From b35ee879403524ea40da09293ef097835a71e538 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Fri, 11 Feb 2022 11:07:48 -0800 Subject: [PATCH 001/656] Update KeepalivePacketData.toString() Test: build Bug: 218569712 Change-Id: I6a146404a285546dbee3923e87236e1627151167 --- .../com/android/internal/telephony/data/KeepaliveTracker.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/KeepaliveTracker.java b/src/java/com/android/internal/telephony/data/KeepaliveTracker.java index bedc77c51a..f9139ec43d 100644 --- a/src/java/com/android/internal/telephony/data/KeepaliveTracker.java +++ b/src/java/com/android/internal/telephony/data/KeepaliveTracker.java @@ -189,9 +189,7 @@ public class KeepaliveTracker extends Handler { private void onStartSocketKeepaliveRequested(int slotIndex, @NonNull Duration interval, @NonNull KeepalivePacketData packet) { log("onStartSocketKeepaliveRequested: slot=" + slotIndex + ", interval=" - + interval.getSeconds() + "s, src=" + packet.getSrcAddress() + ":" - + packet.getSrcPort() + ", dst=" + packet.getDstAddress() + ":" - + packet.getDstPort() + ", packet.length=" + packet.getPacket().length); + + interval.getSeconds() + "s, packet=" + packet); if (packet instanceof NattKeepalivePacketData) { if (mDataNetwork.getTransport() == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { mPhone.mCi.startNattKeepalive(mDataNetwork.getId(), packet, -- GitLab From 9a36e4116f8d6cd5c783cfd49845906282e3ca39 Mon Sep 17 00:00:00 2001 From: Thomas Stuart Date: Mon, 14 Feb 2022 17:39:03 +0000 Subject: [PATCH 002/656] update DSDS call preference logs (2/2) User experienced a bug where the "Ask Every Time" call preference was not working properly. Expected: prompt the user on which SIM they want to use for an outgoing call but Actual: no prompt. There was not enough information in the bug report to determine the issue, nor was the bug reproducible. Hence, some more logging statements have been added to help pinpoint the cause. bug: 198123192 Test: none Change-Id: I55407959def6307940bc23fecfc37d36ccefaa62 --- .../android/internal/telephony/SubscriptionController.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 2652009de6..dfe48cb2cf 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -2839,16 +2839,21 @@ public class SubscriptionController extends ISub.Stub { TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); PhoneAccountHandle currentHandle = telecomManager.getUserSelectedOutgoingPhoneAccount(); + logd("[setDefaultVoiceSubId] current phoneAccountHandle=" + currentHandle); if (!Objects.equals(currentHandle, newHandle)) { telecomManager.setUserSelectedOutgoingPhoneAccount(newHandle); logd("[setDefaultVoiceSubId] change to phoneAccountHandle=" + newHandle); } else { - logd("[setDefaultVoiceSubId] default phone account not changed"); + logd("[setDefaultVoiceSubId] default phoneAccountHandle not changed."); } if (previousDefaultSub != getDefaultSubId()) { sendDefaultChangedBroadcast(getDefaultSubId()); + logd(String.format("[setDefaultVoiceSubId] change to subId=%d", getDefaultSubId())); + } else { + logd(String.format("[setDefaultVoiceSubId] default subId not changed. subId=%d", + previousDefaultSub)); } } -- GitLab From 79b84247071c93aeea60cd3109c2163aa34c4119 Mon Sep 17 00:00:00 2001 From: Brad Ebinger Date: Tue, 15 Feb 2022 11:53:32 -0800 Subject: [PATCH 003/656] Ensure IMS configs are sent properly after IMS service crash We were not sending IMS configs down after ImsService crash, so ensure this happens properly by keeping last cached carrier config. Bug: 219762586 Test: atest ImsPhoneCallTrackerTest Change-Id: I3a601f019df63e8303e552d6c0797ca44a2483c2 --- .../imsphone/ImsPhoneCallTracker.java | 19 ++++---- .../imsphone/ImsPhoneCallTrackerTest.java | 47 +++++++++++++++++++ 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index c759f8832e..527f697632 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -193,9 +193,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // True if there is a carrier config loaded for a specific subscription (and not the default // configuration). private boolean mCarrierConfigLoadedForSubscription = false; - // Cache a carrier config for a subscription that is still pending a connection to the - // ImsService. - private Pair mPendingCarrierConfigForSubId = null; + // Cache the latest carrier config received for a subscription. The configuration will be + // applied to the ImsService when startListeningForCalls is called. + private Pair mCarrierConfigForSubId = null; // The subId of the last ImsService attached to this tracker or empty if there has not been // an attached ImsService yet. private Optional mCurrentlyConnectedSubId = Optional.empty(); @@ -377,16 +377,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { return; } PersistableBundle carrierConfig = getCarrierConfigBundle(subId); + mCarrierConfigForSubId = new Pair<>(subId, carrierConfig); if (!mCurrentlyConnectedSubId.isEmpty() && subId == mCurrentlyConnectedSubId.get()) { log("onReceive: Applying carrier config for subId: " + subId); - // Reset pending config state - mPendingCarrierConfigForSubId = null; updateCarrierConfiguration(subId, carrierConfig); } else { // cache the latest config update until ImsService connects for this subId. - // Once it has connected, startListeningForCalls will apply the pending config. - mPendingCarrierConfigForSubId = new Pair<>(subId, carrierConfig); + // Once it has connected, startListeningForCalls will apply the config. log("onReceive: caching carrier config until ImsService connects for subId: " + subId); } @@ -1107,10 +1105,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { null); } - if (mPendingCarrierConfigForSubId != null && mPendingCarrierConfigForSubId.first == subId) { + if (mCarrierConfigForSubId != null && mCarrierConfigForSubId.first == subId) { // The carrier configuration was received by CarrierConfigManager before the indication - // that the ImsService was connected. - updateCarrierConfiguration(subId, mPendingCarrierConfigForSubId.second); + // that the ImsService was connected or ImsService has restarted and we need to re-apply + // the configuration. + updateCarrierConfiguration(subId, mCarrierConfigForSubId.second); } else { log("startListeningForCalls - waiting for the first carrier config indication for this " + "subscription"); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index a41d95035b..f127127bfa 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -448,6 +448,53 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { verify(mImsManager).updateImsServiceConfig(); } + @Test + @SmallTest + public void testCarrierConfigSentAfterReadyAndCrash() throws Exception { + verify(mImsManager, never()).updateImsServiceConfig(); + + // Receive a subscription loaded and IMS connection ready indication. + doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); + mContextFixture.getCarrierConfigBundle().putBoolean( + CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); + // CarrierConfigLoader has signalled that the carrier config has been applied for a specific + // subscription. This will trigger unavailable -> ready indications. + mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); + mConnectorListener.connectionReady(mImsManager, SUB_0); + processAllMessages(); + // Did not receive carrier config changed yet + verify(mImsManager, never()).updateImsServiceConfig(); + sendCarrierConfigChanged(); + processAllMessages(); + // ImsService crashes and reconnects + mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); + mConnectorListener.connectionReady(mImsManager, SUB_0); + processAllMessages(); + verify(mImsManager, times(2)).updateImsServiceConfig(); + } + + @Test + @SmallTest + public void testCarrierConfigSentBeforeReadyAndCrash() throws Exception { + // move to ImsService unavailable state. + mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); + doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); + mContextFixture.getCarrierConfigBundle().putBoolean( + CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); + + sendCarrierConfigChanged(); + // No ImsService connected, so this will cache the config. + verify(mImsManager, never()).updateImsServiceConfig(); + + // Connect to ImsService and then simulate a crash recovery. We should make sure that the + // configs are sent again after recovery. + mConnectorListener.connectionReady(mImsManager, SUB_0); + mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); + mConnectorListener.connectionReady(mImsManager, SUB_0); + processAllMessages(); + verify(mImsManager, times(2)).updateImsServiceConfig(); + } + @Test @SmallTest public void testImsMTCall() { -- GitLab From c25fd61bc3bfe395aecc34524677deaaa81b63a1 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 16 Feb 2022 15:25:38 -0800 Subject: [PATCH 004/656] Update PhysicalChannelConfig tests Test: atest PhysicalChannelConfigTest Bug: 219586992 Change-Id: Id5e9caf94eb0791b34a0606d1e51e211fcbcc536 --- .../internal/telephony/PhysicalChannelConfigTest.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhysicalChannelConfigTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhysicalChannelConfigTest.java index 853162a03b..4af49b909a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhysicalChannelConfigTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhysicalChannelConfigTest.java @@ -17,8 +17,6 @@ package com.android.internal.telephony; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.fail; - import android.os.Parcel; import android.telephony.AccessNetworkConstants; import android.telephony.PhysicalChannelConfig; @@ -124,12 +122,9 @@ public class PhysicalChannelConfigTest { @Test public void testFrequencyRangeWithoutBand() { - try { - setUpPhysicalChannelConfig(NETWORK_TYPE_UMTS, 0, CHANNEL_NUMBER, CHANNEL_NUMBER, - ServiceState.FREQUENCY_RANGE_UNKNOWN); - fail("Frequency range: 0 is invalid."); - } catch (IllegalArgumentException e) { - } + setUpPhysicalChannelConfig(NETWORK_TYPE_UMTS, 0, CHANNEL_NUMBER, CHANNEL_NUMBER, -1); + assertThat(mPhysicalChannelConfig.getFrequencyRange()) + .isEqualTo(ServiceState.FREQUENCY_RANGE_UNKNOWN); } @Test -- GitLab From b516a8c292fa62d8a205b8639919d3582396b391 Mon Sep 17 00:00:00 2001 From: joonhunshin Date: Thu, 17 Feb 2022 13:00:27 +0000 Subject: [PATCH 005/656] move the responsibility of calling updateImsServiceConfig back to the ImsPhoneCallTracker The ImsProvisioningController has no information as to the current state of the ImsPhonCallTracker and can not wait to send the configs until after the initial set-up from the ImsPhoneCallTracker#startListeningForCalls method. This is causing some conditions where ImsProvisioningController calls ImsManager#updateImsSericeConfig before the ImsPhoneCallTracker is able to set up the interface properly. Bug: 219992992 Test: atest Change-Id: I9694cd7ce58315dce99ac7ae5df12bac34da5c5d --- .../telephony/imsphone/ImsPhoneCallTracker.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index c759f8832e..b9d7247db3 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -4072,10 +4072,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { @Override public void onProvisioningIntChanged(int item, int value) { sendConfigChangedIntent(item, Integer.toString(value)); - - // mImsManager.updateImsServiceConfig() will be called by ImsProvisioningController - // when provisioning status is changed. The implementation is removed to avoid calling - // the updateImsServiceConfig twice. + if ((mImsManager != null) + && (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED + || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED + || item == ImsConfig.ConfigConstants.LVC_SETTING_ENABLED)) { + // Update Ims Service state to make sure updated provisioning values take effect + // immediately. + updateImsServiceConfig(); + } } @Override -- GitLab From 31dcaa81cf1fc10a648a188859be7ac3122afe50 Mon Sep 17 00:00:00 2001 From: Mahesh Telang Date: Fri, 11 Feb 2022 14:50:23 -0800 Subject: [PATCH 006/656] Protecting Null Pointer Exception for Terminated IMS call. Protecting Null Pointer Exception when accessing the call id of a terminated call which does not have an active connection. Bug: 218161502 Change-Id: I6dfcae478737b223576d5eb7310f87aa2c825401 --- .../imsphone/ImsPhoneCallTracker.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index bdd0ee727d..382c1be0ba 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -3225,29 +3225,28 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { cause = DisconnectCause.IMS_MERGED_SUCCESSFULLY; } - String callId = imsCall.getSession().getCallId(); EmergencyNumberTracker emergencyNumberTracker = null; EmergencyNumber num = null; - if (conn != null) { + if (conn != null && imsCall.getSession() != null) { + String callId = imsCall.getSession().getCallId(); emergencyNumberTracker = conn.getEmergencyNumberTracker(); num = conn.getEmergencyNumberInfo(); - } - - mMetrics.writeOnImsCallTerminated(mPhone.getPhoneId(), imsCall.getCallSession(), + mMetrics.writeOnImsCallTerminated(mPhone.getPhoneId(), imsCall.getCallSession(), reasonInfo, mCallQualityMetrics.get(callId), num, getNetworkCountryIso(), emergencyNumberTracker != null - ? emergencyNumberTracker.getEmergencyNumberDbVersion() - : TelephonyManager.INVALID_EMERGENCY_NUMBER_DB_VERSION); - mPhone.getVoiceCallSessionStats().onImsCallTerminated(conn, new ImsReasonInfo( + ? emergencyNumberTracker.getEmergencyNumberDbVersion() + : TelephonyManager.INVALID_EMERGENCY_NUMBER_DB_VERSION); + mPhone.getVoiceCallSessionStats().onImsCallTerminated(conn, new ImsReasonInfo( maybeRemapReasonCode(reasonInfo), reasonInfo.mExtraCode, reasonInfo.mExtraMessage)); - // Remove info for the callId from the current calls and add it to the history - CallQualityMetrics lastCallMetrics = mCallQualityMetrics.remove(callId); - if (lastCallMetrics != null) { - mCallQualityMetricsHistory.add(lastCallMetrics); + // Remove info for the callId from the current calls and add it to the history + CallQualityMetrics lastCallMetrics = mCallQualityMetrics.remove(callId); + if (lastCallMetrics != null) { + mCallQualityMetricsHistory.add(lastCallMetrics); + } + pruneCallQualityMetricsHistory(); } - pruneCallQualityMetricsHistory(); mPhone.notifyImsReason(reasonInfo); if (conn != null) { -- GitLab From c23e4bbd0377a7eb5cd2a3ea0158e3d5642cdf81 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Fri, 4 Mar 2022 00:05:37 +0000 Subject: [PATCH 007/656] Added support for FDN Check. If FDN is available and enabled, then calls and sms to only numbers present in the FDN list are allowed. Bug: 218262162 Test: Manual atest FrameworksTelephonyTests:com.android.internal.telephony.FdnUtilsTest Change-Id: I553977883091069f0d179793d719d3e910428961 --- .../telephony/CallStateException.java | 1 + .../android/internal/telephony/FdnUtils.java | 192 ++++++++++++++++++ .../internal/telephony/GsmCdmaPhone.java | 6 + .../internal/telephony/SmsController.java | 42 +++- .../internal/telephony/FdnUtilsTest.java | 166 +++++++++++++++ 5 files changed, 406 insertions(+), 1 deletion(-) create mode 100644 src/java/com/android/internal/telephony/FdnUtils.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java diff --git a/src/java/com/android/internal/telephony/CallStateException.java b/src/java/com/android/internal/telephony/CallStateException.java index 3fdc4443ab..4de16cb3ce 100644 --- a/src/java/com/android/internal/telephony/CallStateException.java +++ b/src/java/com/android/internal/telephony/CallStateException.java @@ -35,6 +35,7 @@ public class CallStateException extends Exception public static final int ERROR_CALLING_DISABLED = 5; public static final int ERROR_TOO_MANY_CALLS = 6; public static final int ERROR_OTASP_PROVISIONING_IN_PROCESS = 7; + public static final int ERROR_FDN_BLOCKED = 8; public CallStateException() diff --git a/src/java/com/android/internal/telephony/FdnUtils.java b/src/java/com/android/internal/telephony/FdnUtils.java new file mode 100644 index 0000000000..00426f43ec --- /dev/null +++ b/src/java/com/android/internal/telephony/FdnUtils.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2022 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; + +import android.content.Context; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; + +import com.android.i18n.phonenumbers.NumberParseException; +import com.android.i18n.phonenumbers.PhoneNumberUtil; +import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; +import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.uicc.AdnRecord; +import com.android.internal.telephony.uicc.AdnRecordCache; +import com.android.internal.telephony.uicc.IccConstants; +import com.android.internal.telephony.uicc.IccRecords; +import com.android.internal.telephony.uicc.UiccCardApplication; +import com.android.internal.telephony.uicc.UiccController; +import com.android.internal.telephony.uicc.UiccProfile; +import com.android.telephony.Rlog; + +import java.util.ArrayList; +import java.util.Locale; + +/** + * This is a basic utility class for common functions related to Fixed Dialing Numbers + * designed as per 3GPP 22.101. + */ +public class FdnUtils { + private static final boolean VDBG = false; + private static final String LOG_TAG = FdnUtils.class.getSimpleName(); + + /** + * The following function checks if dialed number is blocked due to FDN. + * + * @param phoneId The phone object id for which the FDN check is performed + * @param dialStr dialed phone number + * @param defaultCountryIso country ISO for the subscription associated with this phone + * @return true if dialStr is blocked due to FDN check. + */ + public static boolean isNumberBlockedByFDN(int phoneId, String dialStr, + String defaultCountryIso) { + final UiccCardApplication app = getUiccCardApplication(phoneId); + + if (!isFdnEnabled(app)) { + return false; + } + + final ArrayList fdnList = getFdnList(app); + return !isFDN(dialStr, defaultCountryIso, fdnList); + } + + /** + * The following function checks if destination address or smsc is blocked due to FDN. + * @param context context + * @param subId subscription ID + * @param destAddr destination address of the message + * @param smscAddr smsc address of the subscription + * @return true if either destAddr or smscAddr is blocked due to FDN. + */ + public static boolean isNumberBlockedByFDN(Context context, int subId, String destAddr, + String smscAddr) { + // Skip FDN check for emergency numbers + final TelephonyManager tm = context.getSystemService(TelephonyManager.class); + if(tm.isEmergencyNumber(destAddr)) { + return false; + } + + final int phoneId = SubscriptionManager.getPhoneId(subId); + final String defaultCountryIso = tm.getSimCountryIso().toUpperCase(Locale.ENGLISH); + return (isNumberBlockedByFDN(phoneId, smscAddr, defaultCountryIso) || + isNumberBlockedByFDN(phoneId, destAddr, defaultCountryIso)); + } + + /** + * Checks if dialStr is part of FDN list. + * + * @param fdnList List of all FDN records associated with a sim card + * @param dialStr dialed phone number + * @param defaultCountryIso country ISO for the subscription associated with this phone + * @return true if dialStr is present in the fdnList. + */ + @VisibleForTesting + public static boolean isFDN(String dialStr, String defaultCountryIso, + ArrayList fdnList) { + if (fdnList == null || fdnList.isEmpty() || TextUtils.isEmpty(dialStr)) { + Rlog.w(LOG_TAG, "isFDN: unexpected null value"); + return false; + } + + // Parse the dialStr and convert it to E164 format + String dialStrE164 = null; + String dialStrNational = null; + final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); + try { + final PhoneNumber phoneNumber = phoneNumberUtil.parse(dialStr, defaultCountryIso); + dialStrE164 = phoneNumberUtil.format(phoneNumber, PhoneNumberFormat.E164); + dialStrNational = String.valueOf(phoneNumber.getNationalNumber()); + } catch (NumberParseException ignored) { + Rlog.w(LOG_TAG, "isFDN: could not parse dialStr"); + } + + /** + * Returns true if dialStrE164 or dialStrNational or dialStr starts with fdnNumber + * E.g.1: returns true if fdnNumber="123" and dialStr="12345" + * E.g.2: does not return true if fdnNumber="1123" and dialStr="12345" + */ + for (AdnRecord fdn: fdnList) { + String fdnNumber = fdn.getNumber(); + if (TextUtils.isEmpty(fdnNumber)) { + continue; + } + + if(!TextUtils.isEmpty(dialStrE164)) { + if(dialStrE164.startsWith(fdnNumber)) { + return true; + } + } + + if(!TextUtils.isEmpty(dialStrNational)) { + if (dialStrNational.startsWith(fdnNumber)) { + return true; + } + } + + if (dialStr.startsWith(fdnNumber)) { + return true; + } + } + + if (VDBG) { + Rlog.i(LOG_TAG, "isFDN: dialed number not present in FDN list"); + } + return false; + } + + private static ArrayList getFdnList(UiccCardApplication app) { + if (app == null) { + return null; + } + + final IccRecords iccRecords = app.getIccRecords(); + if (iccRecords == null) { + return null; + } + + final AdnRecordCache adnRecordCache = iccRecords.getAdnCache(); + if(adnRecordCache == null) { + return null; + } + + return adnRecordCache.getRecordsIfLoaded(IccConstants.EF_FDN); + } + + private static boolean isFdnEnabled(UiccCardApplication app) { + if (app == null) { + return false; + } + + if (!app.getIccFdnAvailable()) { + return false; + } + + return app.getIccFdnEnabled(); + } + + private static UiccCardApplication getUiccCardApplication(int phoneId) { + final UiccProfile uiccProfile = UiccController.getInstance() + .getUiccProfileForPhone(phoneId); + if (uiccProfile == null) { + return null; + } + + return uiccProfile.getApplication(UiccController.APP_FAM_3GPP); + } +} \ No newline at end of file diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index a7ac5eee80..edf80c7252 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -1491,6 +1491,12 @@ public class GsmCdmaPhone extends Phone { + ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A")); } + // Perform FDN check for non-emergency calls - shouldn't dial if number is blocked by FDN + if(!isEmergency && FdnUtils.isNumberBlockedByFDN(mPhoneId, dialString, getCountryIso())) { + throw new CallStateException(CallStateException.ERROR_FDN_BLOCKED, + "cannot dial number blocked by FDN"); + } + // Bypass WiFi Only WFC check if this is an emergency call - we should still try to // place over cellular if possible. if (!isEmergency) { diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 9f791619d8..901f116153 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -151,6 +151,14 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } + + // Perform FDN check + if (FdnUtils.isNumberBlockedByFDN(mContext, subId, destAddr, + getSmscAddressFromIccEfForSubscriber(subId, callingPackage))) { + sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); + return; + } + IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendData(callingPackage, callingAttributionTag, destAddr, scAddr, destPort, @@ -201,6 +209,14 @@ public class SmsController extends ISmsImplBase { } finally { Binder.restoreCallingIdentity(token); } + + // Perform FDN check + if (FdnUtils.isNumberBlockedByFDN(mContext, subId, destAddr, + getSmscAddressFromIccEfForSubscriber(subId, callingPackage))) { + sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); + return; + } + if (isBluetoothSubscription(info)) { sendBluetoothText(info, destAddr, text, sentIntent, deliveryIntent); } else { @@ -259,6 +275,14 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } + + // Perform FDN check + if (FdnUtils.isNumberBlockedByFDN(mContext, subId, destAddr, + getSmscAddressFromIccEfForSubscriber(subId, callingPackage))) { + sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); + return; + } + IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendTextWithOptions(callingPackage, callingAttributionTag, destAddr, @@ -281,6 +305,14 @@ public class SmsController extends ISmsImplBase { if (getCallingPackage() != null) { callingPackage = getCallingPackage(); } + + // Perform FDN check + if (FdnUtils.isNumberBlockedByFDN(mContext, subId, destAddr, + getSmscAddressFromIccEfForSubscriber(subId, callingPackage))) { + sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); + return; + } + IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendMultipartText(callingPackage, callingAttributionTag, destAddr, scAddr, @@ -301,6 +333,14 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } + + // Perform FDN check + if (FdnUtils.isNumberBlockedByFDN(mContext, subId, destAddr, + getSmscAddressFromIccEfForSubscriber(subId, callingPackage))) { + sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); + return; + } + IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendMultipartTextWithOptions(callingPackage, callingAttributionTag, @@ -856,4 +896,4 @@ public class SmsController extends ISmsImplBase { public static String formatCrossStackMessageId(long id) { return "{x-message-id:" + id + "}"; } -} +} \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java new file mode 100644 index 0000000000..2c481584e9 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2022 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; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.android.internal.telephony.uicc.AdnRecord; + +import org.junit.Test; + +import java.util.ArrayList; + +public class FdnUtilsTest { + + private ArrayList initializeFdnList() { + ArrayList fdnList = new ArrayList<>(); + AdnRecord adnRecord = new AdnRecord(null, null); + // By default, every sim card holds 15 empty FDN records + int fdnListSize = 15; + for (int i = 0; i < fdnListSize; i++) { + fdnList.add(adnRecord); + } + return fdnList; + } + + @Test + public void fdnListIsNull_returnsFalse() { + assertFalse(FdnUtils.isFDN( "123456789", "US", null)); + } + + @Test + public void fdnListIsEmpty_returnsFalse() { + ArrayList fdnList = new ArrayList<>(); + assertFalse(FdnUtils.isFDN( "123456789", "US", fdnList)); + } + + @Test + public void fdnListHasOnlyDefaultRecords_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + + assertFalse(FdnUtils.isFDN( "123456789", "US", fdnList)); + } + + @Test + public void fdnListHasRecordWithEmptyNumberStr_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, ""); + fdnList.add(1, adnRecord); + + assertFalse(FdnUtils.isFDN( "123456789", "US", fdnList)); + } + + @Test + public void dialStrInFdnList_returnsTrue() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "123456789"); + fdnList.add(2, adnRecord); + + assertTrue(FdnUtils.isFDN( "123456789", "US", fdnList)); + } + + @Test + public void dialStrNotInFdnList_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "111111111"); + fdnList.add(3, adnRecord); + + assertFalse(FdnUtils.isFDN("123456788", "US", fdnList)); + } + + @Test + public void dialStrIsNull_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "111111111"); + fdnList.add(4, adnRecord); + + assertFalse(FdnUtils.isFDN( null, "US", fdnList)); + } + + @Test + public void fdnEntryFirstSubStringOfDialStr_returnsTrue() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "123"); + fdnList.add(5, adnRecord); + + assertTrue(FdnUtils.isFDN( "12345", "US", fdnList)); + } + + @Test + public void fdnEntrySubStringOfDialStr_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "123"); + fdnList.add(5, adnRecord); + + assertFalse(FdnUtils.isFDN("612345", "US", fdnList)); + } + + @Test + public void dialStrFirstSubStringOfFdnEntry_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "12345"); + fdnList.add(5, adnRecord); + + assertFalse(FdnUtils.isFDN("123", "US", fdnList)); + } + + @Test + public void dialStrSubStringOfFdnEntry_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "612345"); + fdnList.add(5, adnRecord); + + assertFalse(FdnUtils.isFDN("123", "US", fdnList)); + } + + @Test + public void dialStrWithoutCountryCode_returnsTrue() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "+16502910000"); + fdnList.add(6, adnRecord); + + assertTrue(FdnUtils.isFDN( "6502910000", "US", fdnList)); + } + + @Test + public void dialStrWithCountryCode_returnsTrue() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "6502910000"); + fdnList.add(6, adnRecord); + + assertTrue(FdnUtils.isFDN("+16502910000", "US", fdnList)); + } + + @Test + public void defaultCountryIsoIsEmpty_returnsTrue() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "650"); + fdnList.add(6, adnRecord); + + assertTrue(FdnUtils.isFDN("+16502910000", "", fdnList)); + } + + @Test + public void defaultCountryIsoIsEmpty_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "+1650"); + fdnList.add(6, adnRecord); + + assertFalse(FdnUtils.isFDN("6502910000", "", fdnList)); + } +} \ No newline at end of file -- GitLab From 053ce5bc628efe9bd933b1b9514495bfd08b01f4 Mon Sep 17 00:00:00 2001 From: Beth Thibodeau Date: Wed, 16 Mar 2022 23:49:57 +0000 Subject: [PATCH 008/656] Revert "Added support for FDN Check." Revert submission 17070464-FDN_CHECK Reason for revert: DroidMonitor: Potential culprit for b/225059967 - verifying through ABTD before revert submission. This is part of the standard investigation process, and does not mean your CL will be reverted Reverted Changes: Iaf5f1c875:Added FDN Check. I553977883:Added support for FDN Check. Change-Id: Ie690ec111ba445b0a4474f2033b249e696400eca --- .../telephony/CallStateException.java | 1 - .../android/internal/telephony/FdnUtils.java | 192 ------------------ .../internal/telephony/GsmCdmaPhone.java | 6 - .../internal/telephony/SmsController.java | 42 +--- .../internal/telephony/FdnUtilsTest.java | 166 --------------- 5 files changed, 1 insertion(+), 406 deletions(-) delete mode 100644 src/java/com/android/internal/telephony/FdnUtils.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java diff --git a/src/java/com/android/internal/telephony/CallStateException.java b/src/java/com/android/internal/telephony/CallStateException.java index 4de16cb3ce..3fdc4443ab 100644 --- a/src/java/com/android/internal/telephony/CallStateException.java +++ b/src/java/com/android/internal/telephony/CallStateException.java @@ -35,7 +35,6 @@ public class CallStateException extends Exception public static final int ERROR_CALLING_DISABLED = 5; public static final int ERROR_TOO_MANY_CALLS = 6; public static final int ERROR_OTASP_PROVISIONING_IN_PROCESS = 7; - public static final int ERROR_FDN_BLOCKED = 8; public CallStateException() diff --git a/src/java/com/android/internal/telephony/FdnUtils.java b/src/java/com/android/internal/telephony/FdnUtils.java deleted file mode 100644 index 00426f43ec..0000000000 --- a/src/java/com/android/internal/telephony/FdnUtils.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import android.content.Context; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.text.TextUtils; - -import com.android.i18n.phonenumbers.NumberParseException; -import com.android.i18n.phonenumbers.PhoneNumberUtil; -import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; -import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.uicc.AdnRecord; -import com.android.internal.telephony.uicc.AdnRecordCache; -import com.android.internal.telephony.uicc.IccConstants; -import com.android.internal.telephony.uicc.IccRecords; -import com.android.internal.telephony.uicc.UiccCardApplication; -import com.android.internal.telephony.uicc.UiccController; -import com.android.internal.telephony.uicc.UiccProfile; -import com.android.telephony.Rlog; - -import java.util.ArrayList; -import java.util.Locale; - -/** - * This is a basic utility class for common functions related to Fixed Dialing Numbers - * designed as per 3GPP 22.101. - */ -public class FdnUtils { - private static final boolean VDBG = false; - private static final String LOG_TAG = FdnUtils.class.getSimpleName(); - - /** - * The following function checks if dialed number is blocked due to FDN. - * - * @param phoneId The phone object id for which the FDN check is performed - * @param dialStr dialed phone number - * @param defaultCountryIso country ISO for the subscription associated with this phone - * @return true if dialStr is blocked due to FDN check. - */ - public static boolean isNumberBlockedByFDN(int phoneId, String dialStr, - String defaultCountryIso) { - final UiccCardApplication app = getUiccCardApplication(phoneId); - - if (!isFdnEnabled(app)) { - return false; - } - - final ArrayList fdnList = getFdnList(app); - return !isFDN(dialStr, defaultCountryIso, fdnList); - } - - /** - * The following function checks if destination address or smsc is blocked due to FDN. - * @param context context - * @param subId subscription ID - * @param destAddr destination address of the message - * @param smscAddr smsc address of the subscription - * @return true if either destAddr or smscAddr is blocked due to FDN. - */ - public static boolean isNumberBlockedByFDN(Context context, int subId, String destAddr, - String smscAddr) { - // Skip FDN check for emergency numbers - final TelephonyManager tm = context.getSystemService(TelephonyManager.class); - if(tm.isEmergencyNumber(destAddr)) { - return false; - } - - final int phoneId = SubscriptionManager.getPhoneId(subId); - final String defaultCountryIso = tm.getSimCountryIso().toUpperCase(Locale.ENGLISH); - return (isNumberBlockedByFDN(phoneId, smscAddr, defaultCountryIso) || - isNumberBlockedByFDN(phoneId, destAddr, defaultCountryIso)); - } - - /** - * Checks if dialStr is part of FDN list. - * - * @param fdnList List of all FDN records associated with a sim card - * @param dialStr dialed phone number - * @param defaultCountryIso country ISO for the subscription associated with this phone - * @return true if dialStr is present in the fdnList. - */ - @VisibleForTesting - public static boolean isFDN(String dialStr, String defaultCountryIso, - ArrayList fdnList) { - if (fdnList == null || fdnList.isEmpty() || TextUtils.isEmpty(dialStr)) { - Rlog.w(LOG_TAG, "isFDN: unexpected null value"); - return false; - } - - // Parse the dialStr and convert it to E164 format - String dialStrE164 = null; - String dialStrNational = null; - final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); - try { - final PhoneNumber phoneNumber = phoneNumberUtil.parse(dialStr, defaultCountryIso); - dialStrE164 = phoneNumberUtil.format(phoneNumber, PhoneNumberFormat.E164); - dialStrNational = String.valueOf(phoneNumber.getNationalNumber()); - } catch (NumberParseException ignored) { - Rlog.w(LOG_TAG, "isFDN: could not parse dialStr"); - } - - /** - * Returns true if dialStrE164 or dialStrNational or dialStr starts with fdnNumber - * E.g.1: returns true if fdnNumber="123" and dialStr="12345" - * E.g.2: does not return true if fdnNumber="1123" and dialStr="12345" - */ - for (AdnRecord fdn: fdnList) { - String fdnNumber = fdn.getNumber(); - if (TextUtils.isEmpty(fdnNumber)) { - continue; - } - - if(!TextUtils.isEmpty(dialStrE164)) { - if(dialStrE164.startsWith(fdnNumber)) { - return true; - } - } - - if(!TextUtils.isEmpty(dialStrNational)) { - if (dialStrNational.startsWith(fdnNumber)) { - return true; - } - } - - if (dialStr.startsWith(fdnNumber)) { - return true; - } - } - - if (VDBG) { - Rlog.i(LOG_TAG, "isFDN: dialed number not present in FDN list"); - } - return false; - } - - private static ArrayList getFdnList(UiccCardApplication app) { - if (app == null) { - return null; - } - - final IccRecords iccRecords = app.getIccRecords(); - if (iccRecords == null) { - return null; - } - - final AdnRecordCache adnRecordCache = iccRecords.getAdnCache(); - if(adnRecordCache == null) { - return null; - } - - return adnRecordCache.getRecordsIfLoaded(IccConstants.EF_FDN); - } - - private static boolean isFdnEnabled(UiccCardApplication app) { - if (app == null) { - return false; - } - - if (!app.getIccFdnAvailable()) { - return false; - } - - return app.getIccFdnEnabled(); - } - - private static UiccCardApplication getUiccCardApplication(int phoneId) { - final UiccProfile uiccProfile = UiccController.getInstance() - .getUiccProfileForPhone(phoneId); - if (uiccProfile == null) { - return null; - } - - return uiccProfile.getApplication(UiccController.APP_FAM_3GPP); - } -} \ No newline at end of file diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index edf80c7252..a7ac5eee80 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -1491,12 +1491,6 @@ public class GsmCdmaPhone extends Phone { + ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A")); } - // Perform FDN check for non-emergency calls - shouldn't dial if number is blocked by FDN - if(!isEmergency && FdnUtils.isNumberBlockedByFDN(mPhoneId, dialString, getCountryIso())) { - throw new CallStateException(CallStateException.ERROR_FDN_BLOCKED, - "cannot dial number blocked by FDN"); - } - // Bypass WiFi Only WFC check if this is an emergency call - we should still try to // place over cellular if possible. if (!isEmergency) { diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 901f116153..9f791619d8 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -151,14 +151,6 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } - - // Perform FDN check - if (FdnUtils.isNumberBlockedByFDN(mContext, subId, destAddr, - getSmscAddressFromIccEfForSubscriber(subId, callingPackage))) { - sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); - return; - } - IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendData(callingPackage, callingAttributionTag, destAddr, scAddr, destPort, @@ -209,14 +201,6 @@ public class SmsController extends ISmsImplBase { } finally { Binder.restoreCallingIdentity(token); } - - // Perform FDN check - if (FdnUtils.isNumberBlockedByFDN(mContext, subId, destAddr, - getSmscAddressFromIccEfForSubscriber(subId, callingPackage))) { - sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); - return; - } - if (isBluetoothSubscription(info)) { sendBluetoothText(info, destAddr, text, sentIntent, deliveryIntent); } else { @@ -275,14 +259,6 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } - - // Perform FDN check - if (FdnUtils.isNumberBlockedByFDN(mContext, subId, destAddr, - getSmscAddressFromIccEfForSubscriber(subId, callingPackage))) { - sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); - return; - } - IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendTextWithOptions(callingPackage, callingAttributionTag, destAddr, @@ -305,14 +281,6 @@ public class SmsController extends ISmsImplBase { if (getCallingPackage() != null) { callingPackage = getCallingPackage(); } - - // Perform FDN check - if (FdnUtils.isNumberBlockedByFDN(mContext, subId, destAddr, - getSmscAddressFromIccEfForSubscriber(subId, callingPackage))) { - sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); - return; - } - IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendMultipartText(callingPackage, callingAttributionTag, destAddr, scAddr, @@ -333,14 +301,6 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } - - // Perform FDN check - if (FdnUtils.isNumberBlockedByFDN(mContext, subId, destAddr, - getSmscAddressFromIccEfForSubscriber(subId, callingPackage))) { - sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); - return; - } - IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendMultipartTextWithOptions(callingPackage, callingAttributionTag, @@ -896,4 +856,4 @@ public class SmsController extends ISmsImplBase { public static String formatCrossStackMessageId(long id) { return "{x-message-id:" + id + "}"; } -} \ No newline at end of file +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java deleted file mode 100644 index 2c481584e9..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.android.internal.telephony.uicc.AdnRecord; - -import org.junit.Test; - -import java.util.ArrayList; - -public class FdnUtilsTest { - - private ArrayList initializeFdnList() { - ArrayList fdnList = new ArrayList<>(); - AdnRecord adnRecord = new AdnRecord(null, null); - // By default, every sim card holds 15 empty FDN records - int fdnListSize = 15; - for (int i = 0; i < fdnListSize; i++) { - fdnList.add(adnRecord); - } - return fdnList; - } - - @Test - public void fdnListIsNull_returnsFalse() { - assertFalse(FdnUtils.isFDN( "123456789", "US", null)); - } - - @Test - public void fdnListIsEmpty_returnsFalse() { - ArrayList fdnList = new ArrayList<>(); - assertFalse(FdnUtils.isFDN( "123456789", "US", fdnList)); - } - - @Test - public void fdnListHasOnlyDefaultRecords_returnsFalse() { - ArrayList fdnList = initializeFdnList(); - - assertFalse(FdnUtils.isFDN( "123456789", "US", fdnList)); - } - - @Test - public void fdnListHasRecordWithEmptyNumberStr_returnsFalse() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, ""); - fdnList.add(1, adnRecord); - - assertFalse(FdnUtils.isFDN( "123456789", "US", fdnList)); - } - - @Test - public void dialStrInFdnList_returnsTrue() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "123456789"); - fdnList.add(2, adnRecord); - - assertTrue(FdnUtils.isFDN( "123456789", "US", fdnList)); - } - - @Test - public void dialStrNotInFdnList_returnsFalse() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "111111111"); - fdnList.add(3, adnRecord); - - assertFalse(FdnUtils.isFDN("123456788", "US", fdnList)); - } - - @Test - public void dialStrIsNull_returnsFalse() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "111111111"); - fdnList.add(4, adnRecord); - - assertFalse(FdnUtils.isFDN( null, "US", fdnList)); - } - - @Test - public void fdnEntryFirstSubStringOfDialStr_returnsTrue() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "123"); - fdnList.add(5, adnRecord); - - assertTrue(FdnUtils.isFDN( "12345", "US", fdnList)); - } - - @Test - public void fdnEntrySubStringOfDialStr_returnsFalse() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "123"); - fdnList.add(5, adnRecord); - - assertFalse(FdnUtils.isFDN("612345", "US", fdnList)); - } - - @Test - public void dialStrFirstSubStringOfFdnEntry_returnsFalse() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "12345"); - fdnList.add(5, adnRecord); - - assertFalse(FdnUtils.isFDN("123", "US", fdnList)); - } - - @Test - public void dialStrSubStringOfFdnEntry_returnsFalse() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "612345"); - fdnList.add(5, adnRecord); - - assertFalse(FdnUtils.isFDN("123", "US", fdnList)); - } - - @Test - public void dialStrWithoutCountryCode_returnsTrue() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "+16502910000"); - fdnList.add(6, adnRecord); - - assertTrue(FdnUtils.isFDN( "6502910000", "US", fdnList)); - } - - @Test - public void dialStrWithCountryCode_returnsTrue() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "6502910000"); - fdnList.add(6, adnRecord); - - assertTrue(FdnUtils.isFDN("+16502910000", "US", fdnList)); - } - - @Test - public void defaultCountryIsoIsEmpty_returnsTrue() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "650"); - fdnList.add(6, adnRecord); - - assertTrue(FdnUtils.isFDN("+16502910000", "", fdnList)); - } - - @Test - public void defaultCountryIsoIsEmpty_returnsFalse() { - ArrayList fdnList = initializeFdnList(); - AdnRecord adnRecord = new AdnRecord(null, "+1650"); - fdnList.add(6, adnRecord); - - assertFalse(FdnUtils.isFDN("6502910000", "", fdnList)); - } -} \ No newline at end of file -- GitLab From 927d040a5c61b91f03b7b21ede1d2b1a5d5cff92 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Fri, 4 Mar 2022 00:05:37 +0000 Subject: [PATCH 009/656] Bring back "Added support for FDN Check." This reverts commit Ie690ec111ba445b0a4474f2033b249e696400eca. If FDN is available and enabled, then calls to only numbers present in the FDN list are allowed. Bug: 218262162 Test: Manual, telephony unit and cts tests atest FrameworksTelephonyTests:com.android.internal.telephony.FdnUtilsTest Change-Id: I8165d5e6785ba42622ee9ca7ad8c1a138bbc4dfb --- .../telephony/CallStateException.java | 1 + .../android/internal/telephony/FdnUtils.java | 192 ++++++++++++++++++ .../internal/telephony/GsmCdmaPhone.java | 6 + .../internal/telephony/FdnUtilsTest.java | 166 +++++++++++++++ 4 files changed, 365 insertions(+) create mode 100644 src/java/com/android/internal/telephony/FdnUtils.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java diff --git a/src/java/com/android/internal/telephony/CallStateException.java b/src/java/com/android/internal/telephony/CallStateException.java index 3fdc4443ab..4de16cb3ce 100644 --- a/src/java/com/android/internal/telephony/CallStateException.java +++ b/src/java/com/android/internal/telephony/CallStateException.java @@ -35,6 +35,7 @@ public class CallStateException extends Exception public static final int ERROR_CALLING_DISABLED = 5; public static final int ERROR_TOO_MANY_CALLS = 6; public static final int ERROR_OTASP_PROVISIONING_IN_PROCESS = 7; + public static final int ERROR_FDN_BLOCKED = 8; public CallStateException() diff --git a/src/java/com/android/internal/telephony/FdnUtils.java b/src/java/com/android/internal/telephony/FdnUtils.java new file mode 100644 index 0000000000..00426f43ec --- /dev/null +++ b/src/java/com/android/internal/telephony/FdnUtils.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2022 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; + +import android.content.Context; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; + +import com.android.i18n.phonenumbers.NumberParseException; +import com.android.i18n.phonenumbers.PhoneNumberUtil; +import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; +import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.uicc.AdnRecord; +import com.android.internal.telephony.uicc.AdnRecordCache; +import com.android.internal.telephony.uicc.IccConstants; +import com.android.internal.telephony.uicc.IccRecords; +import com.android.internal.telephony.uicc.UiccCardApplication; +import com.android.internal.telephony.uicc.UiccController; +import com.android.internal.telephony.uicc.UiccProfile; +import com.android.telephony.Rlog; + +import java.util.ArrayList; +import java.util.Locale; + +/** + * This is a basic utility class for common functions related to Fixed Dialing Numbers + * designed as per 3GPP 22.101. + */ +public class FdnUtils { + private static final boolean VDBG = false; + private static final String LOG_TAG = FdnUtils.class.getSimpleName(); + + /** + * The following function checks if dialed number is blocked due to FDN. + * + * @param phoneId The phone object id for which the FDN check is performed + * @param dialStr dialed phone number + * @param defaultCountryIso country ISO for the subscription associated with this phone + * @return true if dialStr is blocked due to FDN check. + */ + public static boolean isNumberBlockedByFDN(int phoneId, String dialStr, + String defaultCountryIso) { + final UiccCardApplication app = getUiccCardApplication(phoneId); + + if (!isFdnEnabled(app)) { + return false; + } + + final ArrayList fdnList = getFdnList(app); + return !isFDN(dialStr, defaultCountryIso, fdnList); + } + + /** + * The following function checks if destination address or smsc is blocked due to FDN. + * @param context context + * @param subId subscription ID + * @param destAddr destination address of the message + * @param smscAddr smsc address of the subscription + * @return true if either destAddr or smscAddr is blocked due to FDN. + */ + public static boolean isNumberBlockedByFDN(Context context, int subId, String destAddr, + String smscAddr) { + // Skip FDN check for emergency numbers + final TelephonyManager tm = context.getSystemService(TelephonyManager.class); + if(tm.isEmergencyNumber(destAddr)) { + return false; + } + + final int phoneId = SubscriptionManager.getPhoneId(subId); + final String defaultCountryIso = tm.getSimCountryIso().toUpperCase(Locale.ENGLISH); + return (isNumberBlockedByFDN(phoneId, smscAddr, defaultCountryIso) || + isNumberBlockedByFDN(phoneId, destAddr, defaultCountryIso)); + } + + /** + * Checks if dialStr is part of FDN list. + * + * @param fdnList List of all FDN records associated with a sim card + * @param dialStr dialed phone number + * @param defaultCountryIso country ISO for the subscription associated with this phone + * @return true if dialStr is present in the fdnList. + */ + @VisibleForTesting + public static boolean isFDN(String dialStr, String defaultCountryIso, + ArrayList fdnList) { + if (fdnList == null || fdnList.isEmpty() || TextUtils.isEmpty(dialStr)) { + Rlog.w(LOG_TAG, "isFDN: unexpected null value"); + return false; + } + + // Parse the dialStr and convert it to E164 format + String dialStrE164 = null; + String dialStrNational = null; + final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); + try { + final PhoneNumber phoneNumber = phoneNumberUtil.parse(dialStr, defaultCountryIso); + dialStrE164 = phoneNumberUtil.format(phoneNumber, PhoneNumberFormat.E164); + dialStrNational = String.valueOf(phoneNumber.getNationalNumber()); + } catch (NumberParseException ignored) { + Rlog.w(LOG_TAG, "isFDN: could not parse dialStr"); + } + + /** + * Returns true if dialStrE164 or dialStrNational or dialStr starts with fdnNumber + * E.g.1: returns true if fdnNumber="123" and dialStr="12345" + * E.g.2: does not return true if fdnNumber="1123" and dialStr="12345" + */ + for (AdnRecord fdn: fdnList) { + String fdnNumber = fdn.getNumber(); + if (TextUtils.isEmpty(fdnNumber)) { + continue; + } + + if(!TextUtils.isEmpty(dialStrE164)) { + if(dialStrE164.startsWith(fdnNumber)) { + return true; + } + } + + if(!TextUtils.isEmpty(dialStrNational)) { + if (dialStrNational.startsWith(fdnNumber)) { + return true; + } + } + + if (dialStr.startsWith(fdnNumber)) { + return true; + } + } + + if (VDBG) { + Rlog.i(LOG_TAG, "isFDN: dialed number not present in FDN list"); + } + return false; + } + + private static ArrayList getFdnList(UiccCardApplication app) { + if (app == null) { + return null; + } + + final IccRecords iccRecords = app.getIccRecords(); + if (iccRecords == null) { + return null; + } + + final AdnRecordCache adnRecordCache = iccRecords.getAdnCache(); + if(adnRecordCache == null) { + return null; + } + + return adnRecordCache.getRecordsIfLoaded(IccConstants.EF_FDN); + } + + private static boolean isFdnEnabled(UiccCardApplication app) { + if (app == null) { + return false; + } + + if (!app.getIccFdnAvailable()) { + return false; + } + + return app.getIccFdnEnabled(); + } + + private static UiccCardApplication getUiccCardApplication(int phoneId) { + final UiccProfile uiccProfile = UiccController.getInstance() + .getUiccProfileForPhone(phoneId); + if (uiccProfile == null) { + return null; + } + + return uiccProfile.getApplication(UiccController.APP_FAM_3GPP); + } +} \ No newline at end of file diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 85b9b97890..2fca08583f 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -1494,6 +1494,12 @@ public class GsmCdmaPhone extends Phone { + ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A")); } + // Perform FDN check for non-emergency calls - shouldn't dial if number is blocked by FDN + if(!isEmergency && FdnUtils.isNumberBlockedByFDN(mPhoneId, dialString, getCountryIso())) { + throw new CallStateException(CallStateException.ERROR_FDN_BLOCKED, + "cannot dial number blocked by FDN"); + } + // Bypass WiFi Only WFC check if this is an emergency call - we should still try to // place over cellular if possible. if (!isEmergency) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java new file mode 100644 index 0000000000..2c481584e9 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/FdnUtilsTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2022 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; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.android.internal.telephony.uicc.AdnRecord; + +import org.junit.Test; + +import java.util.ArrayList; + +public class FdnUtilsTest { + + private ArrayList initializeFdnList() { + ArrayList fdnList = new ArrayList<>(); + AdnRecord adnRecord = new AdnRecord(null, null); + // By default, every sim card holds 15 empty FDN records + int fdnListSize = 15; + for (int i = 0; i < fdnListSize; i++) { + fdnList.add(adnRecord); + } + return fdnList; + } + + @Test + public void fdnListIsNull_returnsFalse() { + assertFalse(FdnUtils.isFDN( "123456789", "US", null)); + } + + @Test + public void fdnListIsEmpty_returnsFalse() { + ArrayList fdnList = new ArrayList<>(); + assertFalse(FdnUtils.isFDN( "123456789", "US", fdnList)); + } + + @Test + public void fdnListHasOnlyDefaultRecords_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + + assertFalse(FdnUtils.isFDN( "123456789", "US", fdnList)); + } + + @Test + public void fdnListHasRecordWithEmptyNumberStr_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, ""); + fdnList.add(1, adnRecord); + + assertFalse(FdnUtils.isFDN( "123456789", "US", fdnList)); + } + + @Test + public void dialStrInFdnList_returnsTrue() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "123456789"); + fdnList.add(2, adnRecord); + + assertTrue(FdnUtils.isFDN( "123456789", "US", fdnList)); + } + + @Test + public void dialStrNotInFdnList_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "111111111"); + fdnList.add(3, adnRecord); + + assertFalse(FdnUtils.isFDN("123456788", "US", fdnList)); + } + + @Test + public void dialStrIsNull_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "111111111"); + fdnList.add(4, adnRecord); + + assertFalse(FdnUtils.isFDN( null, "US", fdnList)); + } + + @Test + public void fdnEntryFirstSubStringOfDialStr_returnsTrue() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "123"); + fdnList.add(5, adnRecord); + + assertTrue(FdnUtils.isFDN( "12345", "US", fdnList)); + } + + @Test + public void fdnEntrySubStringOfDialStr_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "123"); + fdnList.add(5, adnRecord); + + assertFalse(FdnUtils.isFDN("612345", "US", fdnList)); + } + + @Test + public void dialStrFirstSubStringOfFdnEntry_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "12345"); + fdnList.add(5, adnRecord); + + assertFalse(FdnUtils.isFDN("123", "US", fdnList)); + } + + @Test + public void dialStrSubStringOfFdnEntry_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "612345"); + fdnList.add(5, adnRecord); + + assertFalse(FdnUtils.isFDN("123", "US", fdnList)); + } + + @Test + public void dialStrWithoutCountryCode_returnsTrue() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "+16502910000"); + fdnList.add(6, adnRecord); + + assertTrue(FdnUtils.isFDN( "6502910000", "US", fdnList)); + } + + @Test + public void dialStrWithCountryCode_returnsTrue() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "6502910000"); + fdnList.add(6, adnRecord); + + assertTrue(FdnUtils.isFDN("+16502910000", "US", fdnList)); + } + + @Test + public void defaultCountryIsoIsEmpty_returnsTrue() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "650"); + fdnList.add(6, adnRecord); + + assertTrue(FdnUtils.isFDN("+16502910000", "", fdnList)); + } + + @Test + public void defaultCountryIsoIsEmpty_returnsFalse() { + ArrayList fdnList = initializeFdnList(); + AdnRecord adnRecord = new AdnRecord(null, "+1650"); + fdnList.add(6, adnRecord); + + assertFalse(FdnUtils.isFDN("6502910000", "", fdnList)); + } +} \ No newline at end of file -- GitLab From 4974cf27862f029444ba2a04527cefd1b422f6e2 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 17 Mar 2022 00:00:40 -0700 Subject: [PATCH 010/656] Added network agent auto clean up logic In some rare cases, the netwotk agent would become dangling and make connectivity service thinkgs the network is still alive, hence killing the network brought up later. Added the agent self clean up logic in network agent to auto clean up if onNetworkUnwanted is called for 30 seconds, but without unregistering from connectivity service. Note this is a temporary solution for S QPR. This cannot happen on the new architecture on T because there is no such transferring network agent between data connections. Fix: 221956304 Test: Sanity tests + atest DcNetworkAgentTest Change-Id: Iee219a43d70aca80e5a87b5c22305fbc57768654 --- .../dataconnection/DcNetworkAgent.java | 23 +++- .../dataconnection/DcNetworkAgentTest.java | 118 ++++++++++++++++++ 2 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java diff --git a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java index 796ae94754..ba04a3b299 100644 --- a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java +++ b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java @@ -29,6 +29,7 @@ import android.net.QosFilter; import android.net.QosSessionAttributes; import android.net.SocketKeepalive; import android.net.Uri; +import android.os.Handler; import android.os.Message; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.TransportType; @@ -41,6 +42,7 @@ import android.telephony.data.QosBearerSession; import android.util.LocalLog; import android.util.SparseArray; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RILConstants; @@ -82,6 +84,8 @@ public class DcNetworkAgent extends NetworkAgent implements NotifyQosSessionInte private final Phone mPhone; + private final Handler mHandler; + private int mTransportType; private NetworkCapabilities mNetworkCapabilities; @@ -102,7 +106,10 @@ public class DcNetworkAgent extends NetworkAgent implements NotifyQosSessionInte private static final long NETWORK_UNWANTED_ANOMALY_WINDOW_MS = TimeUnit.MINUTES.toMillis(5); private static final int NETWORK_UNWANTED_ANOMALY_NUM_OCCURRENCES = 12; - DcNetworkAgent(DataConnection dc, Phone phone, int score, NetworkAgentConfig config, + private static final int EVENT_UNWANTED_TIMEOUT = 1; + + @VisibleForTesting + public DcNetworkAgent(DataConnection dc, Phone phone, int score, NetworkAgentConfig config, NetworkProvider networkProvider, int transportType) { super(phone.getContext(), dc.getHandler().getLooper(), "DcNetworkAgent", dc.getNetworkCapabilities(), dc.getLinkProperties(), score, config, @@ -111,6 +118,18 @@ public class DcNetworkAgent extends NetworkAgent implements NotifyQosSessionInte mId = getNetwork().getNetId(); mTag = "DcNetworkAgent" + "-" + mId; mPhone = phone; + mHandler = new Handler(dc.getHandler().getLooper()) { + @Override + public void handleMessage(Message msg) { + if (msg.what == EVENT_UNWANTED_TIMEOUT) { + loge("onNetworkUnwanted timed out. Perform silent de-register."); + logd("Unregister from connectivity service. " + sInterfaceNames.get(mId) + + " removed."); + sInterfaceNames.remove(mId); + DcNetworkAgent.this.unregister(); + } + } + }; mNetworkCapabilities = dc.getNetworkCapabilities(); mTransportType = transportType; mDataConnection = dc; @@ -203,6 +222,7 @@ public class DcNetworkAgent extends NetworkAgent implements NotifyQosSessionInte @Override public synchronized void onNetworkUnwanted() { + mHandler.sendEmptyMessageDelayed(EVENT_UNWANTED_TIMEOUT, TimeUnit.SECONDS.toMillis(30)); trackNetworkUnwanted(); if (mDataConnection == null) { loge("onNetworkUnwanted found called on no-owner DcNetworkAgent!"); @@ -356,6 +376,7 @@ public class DcNetworkAgent extends NetworkAgent implements NotifyQosSessionInte public synchronized void unregister(DataConnection dc) { if (!isOwned(dc, "unregister")) return; + mHandler.removeMessages(EVENT_UNWANTED_TIMEOUT); logd("Unregister from connectivity service. " + sInterfaceNames.get(mId) + " removed."); sInterfaceNames.remove(mId); super.unregister(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java new file mode 100644 index 0000000000..78438e41d9 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 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.dataconnection; + +import static junit.framework.Assert.assertEquals; + +import static org.mockito.Mockito.doReturn; + +import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.NetworkAgent; +import android.net.NetworkAgentConfig; +import android.net.NetworkInfo; +import android.net.NetworkProvider; +import android.os.Looper; +import android.telephony.AccessNetworkConstants; +import android.telephony.TelephonyManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +import java.lang.reflect.Field; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DcNetworkAgentTest extends TelephonyTest { + + private DcNetworkAgent mDcNetworkAgent; + private DataConnection mDc; + private DcController mDcc; + private DcFailBringUp mDcFailBringUp; + + private DataServiceManager mDataServiceManager; + private DcTesterFailBringUpAll mDcTesterFailBringUpAll; + private NetworkProvider mNetworkProvider; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + logd("+Setup!"); + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + doReturn(false).when(mPhone).isUsingNewDataStack(); + mDataServiceManager = Mockito.mock(DataServiceManager.class); + mDcTesterFailBringUpAll = Mockito.mock(DcTesterFailBringUpAll.class); + mNetworkProvider = Mockito.mock(NetworkProvider.class); + + final NetworkAgentConfig.Builder configBuilder = new NetworkAgentConfig.Builder(); + configBuilder.setLegacyType(ConnectivityManager.TYPE_MOBILE); + configBuilder.setLegacyTypeName("MOBILE"); + configBuilder.setLegacySubType(TelephonyManager.NETWORK_TYPE_LTE); + configBuilder.setLegacySubTypeName("LTE"); + configBuilder.setLegacyExtraInfo("apn"); + + doReturn("fake.action_detached").when(mPhone).getActionDetached(); + mDcFailBringUp = new DcFailBringUp(); + mDcFailBringUp.saveParameters(0, 0, -2); + doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp(); + + mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, Looper.myLooper(), + ""); + mDc = DataConnection.makeDataConnection(mPhone, 0, mDcTracker, mDataServiceManager, + mDcTesterFailBringUpAll, mDcc); + + LinkProperties linkProperties = new LinkProperties(); + linkProperties.setInterfaceName("fake_iface"); + Field field = DataConnection.class.getDeclaredField("mLinkProperties"); + field.setAccessible(true); + field.set(mDc, linkProperties); + + mDcNetworkAgent = new DcNetworkAgent(mDc, mPhone, 45, configBuilder.build(), + mNetworkProvider, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + logd("-Setup!"); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + private void verifyDisconnected() throws Exception { + Field field = NetworkAgent.class.getDeclaredField("mNetworkInfo"); + field.setAccessible(true); + NetworkInfo networkInfo = (NetworkInfo) field.get(mDcNetworkAgent); + assertEquals(NetworkInfo.DetailedState.DISCONNECTED, networkInfo.getDetailedState()); + } + + @Test + public void testUnwantedTimeout() throws Exception { + mDcNetworkAgent.markConnected(); + mDcNetworkAgent.onNetworkUnwanted(); + processAllFutureMessages(); + verifyDisconnected(); + } +} -- GitLab From 00f48a969dab57e18f33dac7202133bfbd2df3e6 Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Mon, 21 Mar 2022 17:23:21 -0700 Subject: [PATCH 011/656] Fix resource leak: testOtaEmergencyNumberDatabase Fix leak in file descriptor that showed up after enabling STRICT_MODE Bug: 221641120 Test: acloud & EmergencyNumberTrackerTest Change-Id: I03674fc7d053ebb057d38d7489fc2cc7c64e8307 --- .../emergency/EmergencyNumberTrackerTest.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index 83c0c999ec..a08652d9b8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -41,13 +41,13 @@ import com.android.internal.telephony.TelephonyTest; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import java.io.BufferedInputStream; import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; @@ -93,7 +93,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private static final int VALID_SLOT_INDEX_VALID_1 = 1; private static final int VALID_SLOT_INDEX_VALID_2 = 2; private static final int INVALID_SLOT_INDEX_VALID = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - + private ParcelFileDescriptor mOtaPracelFileDescriptor = null; // Mocked classes private SubscriptionController mSubControllerMock; private Phone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. @@ -150,6 +150,14 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { mEmergencyNumberTrackerMock2 = null; mEmergencyNumberListTestSample.clear(); mEmergencyNumberListTestSample = null; + if (mOtaPracelFileDescriptor != null) { + try { + mOtaPracelFileDescriptor.close(); + mOtaPracelFileDescriptor = null; + } catch (IOException e) { + logd("Failed to close emergency number db file folder for testing " + e.toString()); + } + } super.tearDown(); } @@ -194,11 +202,11 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { File file = new File(Environment.getExternalStorageDirectory(), LOCAL_DOWNLOAD_DIRECTORY + "/" + EMERGENCY_NUMBER_DB_OTA_FILE); try { - final ParcelFileDescriptor otaParcelFileDescriptor = ParcelFileDescriptor.open( + mOtaPracelFileDescriptor = ParcelFileDescriptor.open( file, ParcelFileDescriptor.MODE_READ_ONLY); emergencyNumberTrackerMock.obtainMessage( EmergencyNumberTracker.EVENT_OVERRIDE_OTA_EMERGENCY_NUMBER_DB_FILE_PATH, - otaParcelFileDescriptor).sendToTarget(); + mOtaPracelFileDescriptor).sendToTarget(); logd("Changed emergency number db file folder for testing "); } catch (FileNotFoundException e) { logd("Failed to open emergency number db file folder for testing " + e.toString()); @@ -410,7 +418,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { /** * Test OTA Emergency Number Database Update Status. */ - @Ignore("b/221641120") // TODO: Enable the tests after fixing the resource leak. @Test public void testOtaEmergencyNumberDatabase() { // Set up the Hal version as 1.4 to apply emergency number database -- GitLab From 944761ad46c15f5485177ef52b6e90bbc8407fe6 Mon Sep 17 00:00:00 2001 From: Sooraj Sasindran Date: Tue, 22 Mar 2022 13:57:12 -0700 Subject: [PATCH 012/656] Remove iccid from logging Bug: 220737443 Bug: 220737308 Bug: 220735679 Bug: 220737041 Bug: 220737033 Bug: 220735331 Test: Build Change-Id: I8a971be8032d1d5cb2c4d66e83585e27d9cc3885 --- src/java/com/android/internal/telephony/Phone.java | 2 +- .../android/internal/telephony/SubscriptionController.java | 5 +++-- .../android/internal/telephony/SubscriptionInfoUpdater.java | 2 +- .../com/android/internal/telephony/uicc/IccSimPortInfo.java | 5 +---- src/java/com/android/internal/telephony/uicc/UiccCard.java | 2 +- .../com/android/internal/telephony/uicc/UiccController.java | 2 +- src/java/com/android/internal/telephony/uicc/UiccPort.java | 2 -- src/java/com/android/internal/telephony/uicc/UiccSlot.java | 6 +++--- 8 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index d5175733b5..990797fb5e 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5002,7 +5002,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { pw.println(" isDnsCheckDisabled()=" + isDnsCheckDisabled()); pw.println(" getUnitTestMode()=" + getUnitTestMode()); pw.println(" getState()=" + getState()); - pw.println(" getIccSerialNumber()=" + getIccSerialNumber()); + pw.println(" getIccSerialNumber()=" + Rlog.pii(LOG_TAG, getIccSerialNumber())); pw.println(" getIccRecordsLoaded()=" + getIccRecordsLoaded()); pw.println(" getMessageWaitingIndicator()=" + getMessageWaitingIndicator()); pw.println(" getCallForwardingIndicator()=" + getCallForwardingIndicator()); diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 0110f60bc2..65ca26f0a9 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -834,13 +834,14 @@ public class SubscriptionController extends ISub.Stub { for (SubscriptionInfo si : subList) { if (iccId.equals(si.getIccId())) { if (DBG) - logd("[getActiveSubInfoUsingIccId]+ iccId=" + iccId + " subInfo=" + si); + logd("[getActiveSubInfoUsingIccId]+ iccId=" + + Rlog.pii(LOG_TAG, iccId) + " subInfo=" + si); return si; } } } if (DBG) { - logd("[getActiveSubInfoUsingIccId]+ iccId=" + iccId + logd("[getActiveSubInfoUsingIccId]+ iccId=" + Rlog.pii(LOG_TAG, iccId) + " subList=" + subList + " subInfo=null"); } } finally { diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index 3ab229a9ef..998286647a 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -821,7 +821,7 @@ public class SubscriptionInfoUpdater extends Handler { // If SIM is not absent, insert new record or update existing record. if (!ICCID_STRING_FOR_NO_SIM.equals(sIccId[phoneId]) && sIccId[phoneId] != null) { logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: " - + sIccId[phoneId] + ", phoneId:" + phoneId); + + Rlog.pii(LOG_TAG, sIccId[phoneId]) + ", phoneId:" + phoneId); mSubscriptionManager.addSubscriptionInfoRecord(sIccId[phoneId], phoneId); } diff --git a/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java b/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java index 9a5e10d984..7197fc8f23 100644 --- a/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java +++ b/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java @@ -16,7 +16,6 @@ package com.android.internal.telephony.uicc; -import android.telephony.SubscriptionInfo; import android.text.TextUtils; import java.util.Objects; @@ -50,9 +49,7 @@ public class IccSimPortInfo { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("{").append("iccid=") - .append(SubscriptionInfo.givePrintableIccid(mIccId)).append(",") - .append("logicalSlotIndex=").append(mLogicalSlotIndex).append(",") + sb.append("{").append("logicalSlotIndex=").append(mLogicalSlotIndex).append(",") .append("portActive=").append(mPortActive) .append("}"); return sb.toString(); diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java index 689e4b7be9..03a1257392 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCard.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java @@ -213,7 +213,7 @@ public class UiccCard { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("UiccCard:"); pw.println(" mCardState=" + mCardState); - pw.println(" mCardId=" + mCardId); + pw.println(" mCardId=" + Rlog.pii(LOG_TAG, mCardId)); pw.println(" mNumberOfPorts=" + mUiccPorts.size()); pw.println( "mIsSupportsMultipleEnabledProfiles=" + mIsSupportsMultipleEnabledProfiles); pw.println(); diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 9a6b3efbc7..f5cf80d8b4 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -1443,7 +1443,7 @@ public class UiccController extends Handler { pw.println(" mIsCdmaSupported=" + isCdmaSupported(mContext)); pw.println(" mHasBuiltInEuicc=" + mHasBuiltInEuicc); pw.println(" mHasActiveBuiltInEuicc=" + mHasActiveBuiltInEuicc); - pw.println(" mCardStrings=" + mCardStrings); + pw.println(" mCardStrings=" + Rlog.pii(LOG_TAG, mCardStrings)); pw.println(" mDefaultEuiccCardId=" + mDefaultEuiccCardId); pw.println(" mPhoneIdToSlotId=" + Arrays.toString(mPhoneIdToSlotId)); pw.println(" mUiccSlots: size=" + mUiccSlots.length); diff --git a/src/java/com/android/internal/telephony/uicc/UiccPort.java b/src/java/com/android/internal/telephony/uicc/UiccPort.java index 0152dda088..ab00cab33f 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccPort.java +++ b/src/java/com/android/internal/telephony/uicc/UiccPort.java @@ -21,7 +21,6 @@ import android.content.Context; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; -import android.telephony.SubscriptionInfo; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -363,7 +362,6 @@ public class UiccPort { pw.println(" this=" + this); pw.println(" mPortIdx=" + mPortIdx); pw.println(" mCi=" + mCi); - pw.println(" mIccid=" + SubscriptionInfo.givePrintableIccid(mIccid)); pw.println(" mPhoneId=" + mPhoneId); pw.println(" mPhysicalSlotIndex=" + mPhysicalSlotIndex); synchronized (mOpenChannelRecords) { diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index 1c16738c66..5cd0c58d89 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -44,10 +44,10 @@ import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.euicc.EuiccCard; import com.android.telephony.Rlog; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -608,7 +608,7 @@ public class UiccSlot extends Handler { + isMultipleEnabledProfileSupported()); pw.println(" mIsRemovable=" + mIsRemovable); pw.println(" mLastRadioState=" + mLastRadioState); - pw.println(" mIccIds=" + getPrintableIccIds()); + pw.println(" mIccIds=" + Rlog.pii(TAG, getPrintableIccIds())); pw.println(" mPortIdxToPhoneId=" + mPortIdxToPhoneId); pw.println(" mEid=" + mEid); pw.println(" mCardState=" + mCardState); -- GitLab From d0860452de07ad60fd824994486cf145d79e7a91 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Fri, 4 Mar 2022 00:05:37 +0000 Subject: [PATCH 013/656] Added support for FDN Check in SMS. If FDN is available and enabled, then sms to only numbers present in the FDN list are allowed. Bug: 218262162 Test: Manual atest FrameworksTelephonyTests:com.android.internal.telephony.FdnUtilsTest atest android.app.appops.cts.AppOpsLoggingTest#sendSms Change-Id: I77f873fc34380f0101faf629da6d8ff0ec7a65ae --- .../android/internal/telephony/FdnUtils.java | 59 ++++---------- .../internal/telephony/SmsController.java | 81 +++++++++++++++++++ 2 files changed, 98 insertions(+), 42 deletions(-) diff --git a/src/java/com/android/internal/telephony/FdnUtils.java b/src/java/com/android/internal/telephony/FdnUtils.java index 00426f43ec..5ad6ce488c 100644 --- a/src/java/com/android/internal/telephony/FdnUtils.java +++ b/src/java/com/android/internal/telephony/FdnUtils.java @@ -16,9 +16,6 @@ package com.android.internal.telephony; -import android.content.Context; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; import android.text.TextUtils; import com.android.i18n.phonenumbers.NumberParseException; @@ -36,7 +33,6 @@ import com.android.internal.telephony.uicc.UiccProfile; import com.android.telephony.Rlog; import java.util.ArrayList; -import java.util.Locale; /** * This is a basic utility class for common functions related to Fixed Dialing Numbers @@ -52,40 +48,30 @@ public class FdnUtils { * @param phoneId The phone object id for which the FDN check is performed * @param dialStr dialed phone number * @param defaultCountryIso country ISO for the subscription associated with this phone - * @return true if dialStr is blocked due to FDN check. + * @return {@code true} if dialStr is blocked due to FDN check. */ public static boolean isNumberBlockedByFDN(int phoneId, String dialStr, String defaultCountryIso) { - final UiccCardApplication app = getUiccCardApplication(phoneId); - - if (!isFdnEnabled(app)) { + if (!isFdnEnabled(phoneId)) { return false; } - final ArrayList fdnList = getFdnList(app); + ArrayList fdnList = getFdnList(phoneId); return !isFDN(dialStr, defaultCountryIso, fdnList); } /** - * The following function checks if destination address or smsc is blocked due to FDN. - * @param context context - * @param subId subscription ID - * @param destAddr destination address of the message - * @param smscAddr smsc address of the subscription - * @return true if either destAddr or smscAddr is blocked due to FDN. + * Checks if FDN is enabled + * @param phoneId The phone object id for which the FDN check is performed + * @return {@code true} if FDN is enabled */ - public static boolean isNumberBlockedByFDN(Context context, int subId, String destAddr, - String smscAddr) { - // Skip FDN check for emergency numbers - final TelephonyManager tm = context.getSystemService(TelephonyManager.class); - if(tm.isEmergencyNumber(destAddr)) { + public static boolean isFdnEnabled(int phoneId) { + UiccCardApplication app = getUiccCardApplication(phoneId); + if (app == null || (!app.getIccFdnAvailable())) { return false; } - final int phoneId = SubscriptionManager.getPhoneId(subId); - final String defaultCountryIso = tm.getSimCountryIso().toUpperCase(Locale.ENGLISH); - return (isNumberBlockedByFDN(phoneId, smscAddr, defaultCountryIso) || - isNumberBlockedByFDN(phoneId, destAddr, defaultCountryIso)); + return app.getIccFdnEnabled(); } /** @@ -94,7 +80,7 @@ public class FdnUtils { * @param fdnList List of all FDN records associated with a sim card * @param dialStr dialed phone number * @param defaultCountryIso country ISO for the subscription associated with this phone - * @return true if dialStr is present in the fdnList. + * @return {@code true} if dialStr is present in the fdnList. */ @VisibleForTesting public static boolean isFDN(String dialStr, String defaultCountryIso, @@ -109,7 +95,7 @@ public class FdnUtils { String dialStrNational = null; final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance(); try { - final PhoneNumber phoneNumber = phoneNumberUtil.parse(dialStr, defaultCountryIso); + PhoneNumber phoneNumber = phoneNumberUtil.parse(dialStr, defaultCountryIso); dialStrE164 = phoneNumberUtil.format(phoneNumber, PhoneNumberFormat.E164); dialStrNational = String.valueOf(phoneNumber.getNationalNumber()); } catch (NumberParseException ignored) { @@ -150,17 +136,18 @@ public class FdnUtils { return false; } - private static ArrayList getFdnList(UiccCardApplication app) { + private static ArrayList getFdnList(int phoneId) { + UiccCardApplication app = getUiccCardApplication(phoneId); if (app == null) { return null; } - final IccRecords iccRecords = app.getIccRecords(); + IccRecords iccRecords = app.getIccRecords(); if (iccRecords == null) { return null; } - final AdnRecordCache adnRecordCache = iccRecords.getAdnCache(); + AdnRecordCache adnRecordCache = iccRecords.getAdnCache(); if(adnRecordCache == null) { return null; } @@ -168,20 +155,8 @@ public class FdnUtils { return adnRecordCache.getRecordsIfLoaded(IccConstants.EF_FDN); } - private static boolean isFdnEnabled(UiccCardApplication app) { - if (app == null) { - return false; - } - - if (!app.getIccFdnAvailable()) { - return false; - } - - return app.getIccFdnEnabled(); - } - private static UiccCardApplication getUiccCardApplication(int phoneId) { - final UiccProfile uiccProfile = UiccController.getInstance() + UiccProfile uiccProfile = UiccController.getInstance() .getUiccProfileForPhone(phoneId); if (uiccProfile == null) { return null; diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 9f791619d8..0cd7d29bed 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -47,6 +47,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Locale; /** * Implements the ISmsImplBase interface used in the SmsManager API. @@ -151,6 +152,13 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } + + // Perform FDN check + if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { + sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); + return; + } + IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendData(callingPackage, callingAttributionTag, destAddr, scAddr, destPort, @@ -194,6 +202,13 @@ public class SmsController extends ISmsImplBase { sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_GENERIC_FAILURE); return; } + + // Perform FDN check + if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { + sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); + return; + } + long token = Binder.clearCallingIdentity(); SubscriptionInfo info; try { @@ -201,6 +216,7 @@ public class SmsController extends ISmsImplBase { } finally { Binder.restoreCallingIdentity(token); } + if (isBluetoothSubscription(info)) { sendBluetoothText(info, destAddr, text, sentIntent, deliveryIntent); } else { @@ -259,6 +275,13 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } + + // Perform FDN check + if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { + sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); + return; + } + IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendTextWithOptions(callingPackage, callingAttributionTag, destAddr, @@ -281,6 +304,13 @@ public class SmsController extends ISmsImplBase { if (getCallingPackage() != null) { callingPackage = getCallingPackage(); } + + // Perform FDN check + if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { + sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); + return; + } + IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendMultipartText(callingPackage, callingAttributionTag, destAddr, scAddr, @@ -301,6 +331,13 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } + + // Perform FDN check + if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { + sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); + return; + } + IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendMultipartTextWithOptions(callingPackage, callingAttributionTag, @@ -856,4 +893,48 @@ public class SmsController extends ISmsImplBase { public static String formatCrossStackMessageId(long id) { return "{x-message-id:" + id + "}"; } + + /** + * The following function checks if destination address or smsc is blocked due to FDN. + * @param subId subscription ID + * @param destAddr destination address of the message + * @return true if either destAddr or smscAddr is blocked due to FDN. + */ + private boolean isNumberBlockedByFDN(int subId, String destAddr, String callingPackage) { + int phoneId = SubscriptionManager.getPhoneId(subId); + if (!FdnUtils.isFdnEnabled(subId)) { + return false; + } + + // Skip FDN check for emergency numbers + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + if (tm.isEmergencyNumber(destAddr)) { + return false; + } + + // Check if destAddr is present in FDN list + String defaultCountryIso = tm.getSimCountryIso().toUpperCase(Locale.ENGLISH); + if (FdnUtils.isNumberBlockedByFDN(phoneId, destAddr, defaultCountryIso)) { + return true; + } + + // Get SMSC address for this subscription + IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); + String smscAddr; + if (iccSmsIntMgr != null) { + long identity = Binder.clearCallingIdentity(); + try { + smscAddr = iccSmsIntMgr.getSmscAddressFromIccEf(callingPackage); + } finally { + Binder.restoreCallingIdentity(identity); + } + } else { + Rlog.e(LOG_TAG, "getSmscAddressFromIccEfForSubscriber iccSmsIntMgr is null" + + " for Subscription: " + subId); + return true; + } + + // Check if smscAddr is present in FDN list + return FdnUtils.isNumberBlockedByFDN(phoneId, smscAddr, defaultCountryIso); + } } -- GitLab From 0f07e475a4db6398453b8f40ad799bf2cd03c0ee Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Tue, 8 Mar 2022 01:08:02 +0000 Subject: [PATCH 014/656] Add permission to sendBroadcast intent for ACTION_IMS_CONFIG_CHANGED for limit only apps which have READ_PRIVILEGED_PHONE_STATE permission can reach it Bug: b/175040141 Test: live network test with sanity scenario and bug scenario on VZW/TMO/AT&T carrier Change-Id: Ie8662e7e20260f03240413bba492af3da0983bca --- .../internal/telephony/imsphone/ImsPhoneCallTracker.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index ec1314f9f4..eda5f48409 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -22,6 +22,7 @@ import static android.telephony.CarrierConfigManager.USSD_OVER_IMS_ONLY; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import static com.android.internal.telephony.Phone.CS_FALLBACK; +import android.Manifest; import android.annotation.NonNull; import android.app.usage.NetworkStatsManager; import android.compat.annotation.UnsupportedAppUsage; @@ -4098,7 +4099,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { configChangedIntent.putExtra(ImsConfig.EXTRA_CHANGED_ITEM, item); configChangedIntent.putExtra(ImsConfig.EXTRA_NEW_VALUE, value); if (mPhone != null && mPhone.getContext() != null) { - mPhone.getContext().sendBroadcast(configChangedIntent); + mPhone.getContext().sendBroadcast( + configChangedIntent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); } } }; -- GitLab From 73e2edf9f3fd6c8026e721627b3b7cf86a6e24b3 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 15 Apr 2022 21:51:35 +0000 Subject: [PATCH 015/656] InboundSmsHandler: stop using IPackageManager::isOnlyCoreApps() Due to the removal of support for Full Disk Encryption, this method always returns false. In preparation for removing it, stop calling it from InboundSmsHandler. Bug: 208476087 Change-Id: I154386eaba2d44b18895d89e874fa64012b13ca2 --- .../internal/telephony/InboundSmsHandler.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java index eeda1f9e3e..1f0b5425f2 100644 --- a/src/java/com/android/internal/telephony/InboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java @@ -45,7 +45,6 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.database.Cursor; import android.database.SQLException; @@ -56,8 +55,6 @@ import android.os.Bundle; import android.os.Message; import android.os.PowerManager; import android.os.PowerWhitelistManager; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; @@ -745,19 +742,6 @@ public abstract class InboundSmsHandler extends StateMachine { return Intents.RESULT_SMS_HANDLED; } - // onlyCore indicates if the device is in cryptkeeper - boolean onlyCore = false; - try { - onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService("package")) - .isOnlyCoreApps(); - } catch (RemoteException e) { - } - if (onlyCore) { - // Device is unable to receive SMS in encrypted state - log("Received a short message in encrypted state. Rejecting."); - return Intents.RESULT_SMS_RECEIVED_WHILE_ENCRYPTED; - } - int result = dispatchMessageRadioSpecific(smsb, smsSource); // In case of error, add to metrics. This is not required in case of success, as the @@ -880,7 +864,6 @@ public abstract class InboundSmsHandler extends StateMachine { * RESULT_SMS_DISPATCH_FAILURE
* RESULT_SMS_NULL_PDU
* RESULT_SMS_NULL_MESSAGE
- * RESULT_SMS_RECEIVED_WHILE_ENCRYPTED
* RESULT_SMS_DATABASE_ERROR
* RESULT_SMS_INVALID_URI
*/ -- GitLab From 519d5abb8b0df709efc5417bed76b69138d307e9 Mon Sep 17 00:00:00 2001 From: ckishan Date: Thu, 14 Apr 2022 09:52:23 +0000 Subject: [PATCH 016/656] Telephony GBA_U Authentication Extend getIccAuthentication() API to support GBA-U bootstrapping parameters and NAF key from SIM for both USIM and ISIM Bug: 229200773 Test: `atest android.telephony.cts.TelephonyManagerTest#testTelephonyManager` pass on crosshatch Change-Id: Iba9cc182dd7e383cb14c14b6c5980fd6152f5f1d --- .../android/internal/telephony/PhoneSubInfoController.java | 4 +++- .../android/internal/telephony/uicc/UiccCardApplication.java | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java index b1dfa5fb93..abbd696d0f 100644 --- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java +++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java @@ -438,7 +438,9 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { } if (authType != UiccCardApplication.AUTH_CONTEXT_EAP_SIM - && authType != UiccCardApplication.AUTH_CONTEXT_EAP_AKA) { + && authType != UiccCardApplication.AUTH_CONTEXT_EAP_AKA + && authType != UiccCardApplication.AUTH_CONTEXT_GBA_BOOTSTRAP + && authType != UiccCardApplication.AUTHTYPE_GBA_NAF_KEY_EXTERNAL) { loge("getIccSimChallengeResponse() unsupported authType: " + authType); return null; } diff --git a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java index 3839610183..9454adef0a 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java @@ -59,6 +59,9 @@ public class UiccCardApplication { */ public static final int AUTH_CONTEXT_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM; public static final int AUTH_CONTEXT_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA; + public static final int AUTH_CONTEXT_GBA_BOOTSTRAP = PhoneConstants.AUTH_CONTEXT_GBA_BOOTSTRAP; + public static final int AUTHTYPE_GBA_NAF_KEY_EXTERNAL = + PhoneConstants.AUTHTYPE_GBA_NAF_KEY_EXTERNAL; public static final int AUTH_CONTEXT_UNDEFINED = PhoneConstants.AUTH_CONTEXT_UNDEFINED; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) -- GitLab From e3e9ede2cf28ece1d22ff1456ae2c54cc21b5ef3 Mon Sep 17 00:00:00 2001 From: Michele Berionne Date: Fri, 22 Apr 2022 22:44:51 +0000 Subject: [PATCH 017/656] Prioritize metrics for emergency calls Bug: 230137612 Test: unittest Change-Id: I931ba6ff1a80e23803003bbccb16c5c3522f7e16 --- .../metrics/PersistAtomsStorage.java | 17 ++++++++++++++ .../metrics/PersistAtomsStorageTest.java | 22 +++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java index 349736e262..46d9e947bf 100644 --- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java +++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java @@ -1589,6 +1589,7 @@ public class PersistAtomsStorage { /** Returns index of the item suitable for eviction when the array is full. */ private static int findItemToEvict(T[] array) { if (array instanceof CellularServiceState[]) { + // Evict the item that was used least recently CellularServiceState[] arr = (CellularServiceState[]) array; return IntStream.range(0, arr.length) .reduce((i, j) -> arr[i].lastUsedMillis < arr[j].lastUsedMillis ? i : j) @@ -1596,6 +1597,7 @@ public class PersistAtomsStorage { } if (array instanceof CellularDataServiceSwitch[]) { + // Evict the item that was used least recently CellularDataServiceSwitch[] arr = (CellularDataServiceSwitch[]) array; return IntStream.range(0, arr.length) .reduce((i, j) -> arr[i].lastUsedMillis < arr[j].lastUsedMillis ? i : j) @@ -1603,6 +1605,7 @@ public class PersistAtomsStorage { } if (array instanceof ImsRegistrationStats[]) { + // Evict the item that was used least recently ImsRegistrationStats[] arr = (ImsRegistrationStats[]) array; return IntStream.range(0, arr.length) .reduce((i, j) -> arr[i].lastUsedMillis < arr[j].lastUsedMillis ? i : j) @@ -1610,12 +1613,26 @@ public class PersistAtomsStorage { } if (array instanceof ImsRegistrationTermination[]) { + // Evict the item that was used least recently ImsRegistrationTermination[] arr = (ImsRegistrationTermination[]) array; return IntStream.range(0, arr.length) .reduce((i, j) -> arr[i].lastUsedMillis < arr[j].lastUsedMillis ? i : j) .getAsInt(); } + if (array instanceof VoiceCallSession[]) { + // For voice calls, try to keep emergency calls over regular calls. + VoiceCallSession[] arr = (VoiceCallSession[]) array; + int[] nonEmergencyCallIndexes = IntStream.range(0, arr.length) + .filter(i -> !arr[i].isEmergency) + .toArray(); + if (nonEmergencyCallIndexes.length > 0) { + return nonEmergencyCallIndexes[sRandom.nextInt(nonEmergencyCallIndexes.length)]; + } + // If all calls in the storage are emergency calls, proceed with default case + // even if the new call is not an emergency call. + } + return sRandom.nextInt(array.length); } 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 3300b3cddc..ea1d2d1a0f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java @@ -310,7 +310,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mCall3Proto.isEmergency = false; mCall3Proto.isRoaming = false; - // CS MO call while camped on LTE + // CS MO emergency call while camped on LTE mCall4Proto = new VoiceCallSession(); mCall4Proto.bearerAtStart = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS; mCall4Proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS; @@ -335,7 +335,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mCall4Proto.srvccFailureCount = 0L; mCall4Proto.srvccCancellationCount = 0L; mCall4Proto.rttEnabled = false; - mCall4Proto.isEmergency = false; + mCall4Proto.isEmergency = true; mCall4Proto.isRoaming = true; mCarrier1LteUsageProto = new VoiceCallRatUsage(); @@ -1130,6 +1130,24 @@ public class PersistAtomsStorageTest extends TelephonyTest { assertHasCall(calls, mCall2Proto, /* expectedCount= */ 1); } + @Test + @SmallTest + public void addVoiceCallSession_tooManyCalls_withEmergencyCalls() throws Exception { + createEmptyTestFile(); + // We initially have storage full of emergency calls except one. + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + addRepeatedCalls(mPersistAtomsStorage, mCall4Proto, 49); + mPersistAtomsStorage.addVoiceCallSession(mCall1Proto); + + mPersistAtomsStorage.addVoiceCallSession(mCall4Proto); + mPersistAtomsStorage.incTimeMillis(100L); + + // after adding one more emergency call, the previous non-emergency call should be evicted + verifyCurrentStateSavedToFileOnce(); + VoiceCallSession[] calls = mPersistAtomsStorage.getVoiceCallSessions(0L); + assertHasCall(calls, mCall4Proto, /* expectedCount= */ 50); + } + @Test @SmallTest public void addVoiceCallRatUsage_emptyProto() throws Exception { -- GitLab From d7860668995568cf3ba654235b5c549cf8fe38f9 Mon Sep 17 00:00:00 2001 From: virkumar Date: Thu, 21 Apr 2022 12:18:31 +0000 Subject: [PATCH 018/656] (ImsResolverTest Fix) Inject Looper to ImsResolver. Inject the Looper to ImsResolver so same can be used in handler. Test: atest ImsResolverTest Bug: 229861000 Change-Id: Id1646d2f72baf38d4705666259e6bbe109bdae80 --- .../internal/telephony/ims/ImsResolver.java | 163 ++++++++++-------- .../telephony/ims/ImsResolverTest.java | 84 +++------ 2 files changed, 114 insertions(+), 133 deletions(-) diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java index 7958204829..45f1fa3377 100644 --- a/src/java/com/android/internal/telephony/ims/ImsResolver.java +++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java @@ -138,8 +138,9 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal public static void make(Context context, String defaultMmTelPackageName, String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo) { if (sInstance == null) { + Looper looper = Looper.getMainLooper(); sInstance = new ImsResolver(context, defaultMmTelPackageName, defaultRcsPackageName, - numSlots, repo); + numSlots, repo, looper); } } @@ -444,88 +445,97 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal // Synchronize all events on a handler to ensure that the cache includes the most recent // version of the installed ImsServices. - private final Handler mHandler = new Handler(Looper.getMainLooper(), (msg) -> { - switch (msg.what) { - case HANDLER_ADD_PACKAGE: { - String packageName = (String) msg.obj; - maybeAddedImsService(packageName); - break; - } - case HANDLER_REMOVE_PACKAGE: { - String packageName = (String) msg.obj; - maybeRemovedImsService(packageName); - break; - } - case HANDLER_BOOT_COMPLETE: { - if (!mBootCompletedHandlerRan) { - mBootCompletedHandlerRan = true; - mEventLog.log("handling BOOT_COMPLETE"); - if (mCarrierConfigReceived) { - mEventLog.log("boot complete - reeval"); - // Re-evaluate bound services for all slots after requerying packagemanager - maybeAddedImsService(null /*packageName*/); + private final Handler mHandler; + private class ResolverHandler extends Handler { + + ResolverHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case HANDLER_ADD_PACKAGE: { + String packageName = (String) msg.obj; + maybeAddedImsService(packageName); + break; + } + case HANDLER_REMOVE_PACKAGE: { + String packageName = (String) msg.obj; + maybeRemovedImsService(packageName); + break; + } + case HANDLER_BOOT_COMPLETE: { + if (!mBootCompletedHandlerRan) { + mBootCompletedHandlerRan = true; + mEventLog.log("handling BOOT_COMPLETE"); + if (mCarrierConfigReceived) { + mEventLog.log("boot complete - reeval"); + // Re-evaluate bound services for all slots after requerying + //packagemanager + maybeAddedImsService(null /*packageName*/); + } else { + mEventLog.log("boot complete - update cache"); + // Do not bind any ImsServices yet, just update the cache to include new + // services. All will be re-evaluated after first carrier config changed + updateInstalledServicesCache(); + } + } + break; + } + case HANDLER_CONFIG_CHANGED: { + int slotId = msg.arg1; + int subId = msg.arg2; + // If the msim config has changed and there is a residual event for an invalid + // slot,ignore. + if (slotId >= mNumSlots) { + Log.w(TAG, "HANDLER_CONFIG_CHANGED for invalid slotid=" + slotId); + break; + } + mCarrierConfigReceived = true; + carrierConfigChanged(slotId, subId); + break; + } + case HANDLER_START_DYNAMIC_FEATURE_QUERY: { + ImsServiceInfo info = (ImsServiceInfo) msg.obj; + startDynamicQuery(info); + break; + } + case HANDLER_DYNAMIC_FEATURE_CHANGE: { + SomeArgs args = (SomeArgs) msg.obj; + ComponentName name = (ComponentName) args.arg1; + Set features = + (Set) args.arg2; + args.recycle(); + dynamicQueryComplete(name, features); + break; + } + case HANDLER_OVERRIDE_IMS_SERVICE_CONFIG: { + OverrideConfig config = (OverrideConfig) msg.obj; + if (config.isCarrierService) { + overrideCarrierService(config.slotId, + config.featureTypeToPackageMap); } else { - mEventLog.log("boot complete - update cache"); - // Do not bind any ImsServices yet, just update the cache to include new - // services. All will be re-evaluated after first carrier config changed. - updateInstalledServicesCache(); + overrideDeviceService(config.featureTypeToPackageMap); } + break; } - break; - } - case HANDLER_CONFIG_CHANGED: { - int slotId = msg.arg1; - int subId = msg.arg2; - // If the msim config has changed and there is a residual event for an invalid slot, - // ignore. - if (slotId >= mNumSlots) { - Log.w(TAG, "HANDLER_CONFIG_CHANGED for invalid slotid=" + slotId); + case HANDLER_MSIM_CONFIGURATION_CHANGE: { + AsyncResult result = (AsyncResult) msg.obj; + handleMsimConfigChange((Integer) result.result); break; } - mCarrierConfigReceived = true; - carrierConfigChanged(slotId, subId); - break; - } - case HANDLER_START_DYNAMIC_FEATURE_QUERY: { - ImsServiceInfo info = (ImsServiceInfo) msg.obj; - startDynamicQuery(info); - break; - } - case HANDLER_DYNAMIC_FEATURE_CHANGE: { - SomeArgs args = (SomeArgs) msg.obj; - ComponentName name = (ComponentName) args.arg1; - Set features = - (Set) args.arg2; - args.recycle(); - dynamicQueryComplete(name, features); - break; - } - case HANDLER_OVERRIDE_IMS_SERVICE_CONFIG: { - OverrideConfig config = (OverrideConfig) msg.obj; - if (config.isCarrierService) { - overrideCarrierService(config.slotId, - config.featureTypeToPackageMap); - } else { - overrideDeviceService(config.featureTypeToPackageMap); + case HANDLER_CLEAR_CARRIER_IMS_SERVICE_CONFIG: { + clearCarrierServiceOverrides(msg.arg1); + break; } - break; - } - case HANDLER_MSIM_CONFIGURATION_CHANGE: { - AsyncResult result = (AsyncResult) msg.obj; - handleMsimConfigChange((Integer) result.result); - break; - } - case HANDLER_CLEAR_CARRIER_IMS_SERVICE_CONFIG: { - clearCarrierServiceOverrides(msg.arg1); - break; + default: + break; } - default: - return false; } - return true; - }); + } - private final HandlerExecutor mRunnableExecutor = new HandlerExecutor(mHandler); + private final HandlerExecutor mRunnableExecutor; // Results from dynamic queries to ImsService regarding the features they support. private final ImsServiceFeatureQueryManager.Listener mDynamicQueryListener = @@ -571,7 +581,8 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal private final SparseIntArray mSlotIdToSubIdMap; public ImsResolver(Context context, String defaultMmTelPackageName, - String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo) { + String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo, + Looper looper) { Log.i(TAG, "device MMTEL package: " + defaultMmTelPackageName + ", device RCS package:" + defaultRcsPackageName); mContext = context; @@ -579,6 +590,8 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal mRepo = repo; mReceiverContext = context.createContextAsUser(UserHandle.ALL, 0 /*flags*/); + mHandler = new ResolverHandler(looper); + mRunnableExecutor = new HandlerExecutor(mHandler); mCarrierServices = new SparseArray<>(mNumSlots); setDeviceConfiguration(defaultMmTelPackageName, ImsFeature.FEATURE_EMERGENCY_MMTEL); setDeviceConfiguration(defaultMmTelPackageName, ImsFeature.FEATURE_MMTEL); 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 bfef44539f..cf93e21e4b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java @@ -20,7 +20,6 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.fail; import static junit.framework.TestCase.assertFalse; import static org.mockito.ArgumentMatchers.argThat; @@ -44,6 +43,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.net.Uri; import android.os.Bundle; +import android.os.Looper; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.UserManager; @@ -112,7 +112,6 @@ public class ImsResolverTest extends ImsTestBase { private BroadcastReceiver mTestBootCompleteReceiver; private ImsServiceFeatureQueryManager.Listener mDynamicQueryListener; private PersistableBundle[] mCarrierConfigs; - private TestableLooper mLooper; @Before @Override @@ -134,7 +133,6 @@ public class ImsResolverTest extends ImsTestBase { public void tearDown() throws Exception { mTestImsResolver.destroy(); mTestImsResolver = null; - mLooper = null; mTestPackageBroadcastReceiver = null; mTestCarrierConfigReceiver = null; mTestBootCompleteReceiver = null; @@ -220,15 +218,11 @@ public class ImsResolverTest extends ImsTestBase { // device package name should be returned for both features. final Boolean[] isConfigured = new Boolean[1]; - // Calling this method will block us until the looper processes the command, so use - // runWithLooper to allow the message to be processed. - mLooper.runWithLooper(() -> - isConfigured[0] = mTestImsResolver.isImsServiceConfiguredForFeature(0, - ImsFeature.FEATURE_MMTEL)); + isConfigured[0] = mTestImsResolver.isImsServiceConfiguredForFeature(0, + ImsFeature.FEATURE_MMTEL); assertTrue(isConfigured[0]); - mLooper.runWithLooper(() -> - isConfigured[0] = mTestImsResolver.isImsServiceConfiguredForFeature(0, - ImsFeature.FEATURE_RCS)); + isConfigured[0] = mTestImsResolver.isImsServiceConfiguredForFeature(0, + ImsFeature.FEATURE_RCS); assertTrue(isConfigured[0]); } @@ -253,15 +247,11 @@ public class ImsResolverTest extends ImsTestBase { // device package name should be returned for both features. final String[] packageName = new String[1]; - // Calling this method will block us until the looper processes the command, so use - // runWithLooper to allow the message to be processed. - mLooper.runWithLooper(() -> - packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, - ImsFeature.FEATURE_MMTEL)); + packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, + ImsFeature.FEATURE_MMTEL); assertEquals(TEST_DEVICE_DEFAULT_NAME.getPackageName(), packageName[0]); - mLooper.runWithLooper(() -> - packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, - ImsFeature.FEATURE_RCS)); + packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, + ImsFeature.FEATURE_RCS); assertEquals(TEST_DEVICE_DEFAULT_NAME.getPackageName(), packageName[0]); } @@ -281,15 +271,11 @@ public class ImsResolverTest extends ImsTestBase { // device package name should be returned for both features. final String[] packageName = new String[1]; - // Calling this method will block us until the looper processes the command, so use - // runWithLooper to allow the message to be processed. - mLooper.runWithLooper(() -> - packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, - ImsFeature.FEATURE_MMTEL)); + packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, + ImsFeature.FEATURE_MMTEL); assertNull(packageName[0]); - mLooper.runWithLooper(() -> - packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, - ImsFeature.FEATURE_RCS)); + packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, + ImsFeature.FEATURE_RCS); assertNull(packageName[0]); } @@ -314,15 +300,11 @@ public class ImsResolverTest extends ImsTestBase { // device package name should be returned for both features. final String[] packageName = new String[1]; - // Calling this method will block us until the looper processes the command, so use - // runWithLooper to allow the message to be processed. - mLooper.runWithLooper(() -> - packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, - ImsFeature.FEATURE_MMTEL)); + packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, + ImsFeature.FEATURE_MMTEL); assertNull(packageName[0]); - mLooper.runWithLooper(() -> - packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, - ImsFeature.FEATURE_RCS)); + packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, + ImsFeature.FEATURE_RCS); assertNull(packageName[0]); } @@ -358,15 +340,11 @@ public class ImsResolverTest extends ImsTestBase { // carrier package name should be returned for both features. final String[] packageName = new String[1]; - // Calling this method will block us until the looper processes the command, so use - // runWithLooper to allow the message to be processed. - mLooper.runWithLooper(() -> - packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, - ImsFeature.FEATURE_MMTEL)); + packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, + ImsFeature.FEATURE_MMTEL); assertEquals(TEST_CARRIER_DEFAULT_NAME.getPackageName(), packageName[0]); - mLooper.runWithLooper(() -> - packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, - ImsFeature.FEATURE_RCS)); + packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, + ImsFeature.FEATURE_RCS); assertEquals(TEST_CARRIER_DEFAULT_NAME.getPackageName(), packageName[0]); } @@ -396,15 +374,11 @@ public class ImsResolverTest extends ImsTestBase { startBindCarrierConfigAlreadySet(); final String[] packageName = new String[1]; - // Calling this method will block us until the looper processes the command, so use - // runWithLooper to allow the message to be processed. - mLooper.runWithLooper(() -> - packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, - ImsFeature.FEATURE_MMTEL)); + packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, + ImsFeature.FEATURE_MMTEL); assertEquals(TEST_DEVICE_DEFAULT_NAME.getPackageName(), packageName[0]); - mLooper.runWithLooper(() -> - packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, - ImsFeature.FEATURE_RCS)); + packageName[0] = mTestImsResolver.getConfiguredImsServicePackageName(0, + ImsFeature.FEATURE_RCS); assertEquals(TEST_DEVICE_DEFAULT_NAME.getPackageName(), packageName[0]); } @@ -1946,13 +1920,7 @@ public class ImsResolverTest extends ImsTestBase { } mTestImsResolver = new ImsResolver(mMockContext, deviceMmTelPkgName, deviceRcsPkgName, - numSlots, mMockRepo); - try { - mLooper = new TestableLooper(mTestImsResolver.getHandler().getLooper()); - monitorTestableLooper(mLooper); - } catch (Exception e) { - fail("Unable to create looper from handler."); - } + numSlots, mMockRepo, Looper.myLooper()); mTestImsResolver.setSubscriptionManagerProxy(mTestSubscriptionManagerProxy); mTestImsResolver.setTelephonyManagerProxy(mTestTelephonyManagerProxy); -- GitLab From 6f38aca593eb6402e8e3055d9a4c63d8331a6407 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 5 May 2022 16:05:58 -0700 Subject: [PATCH 019/656] Release PDU session id when setup data call fails When setup data call fails on IWLAN, we should release the PDU session id. Fix: 230283098 Test: Manual Change-Id: I0687d0f9c3b2b4bcd39e92a1dca6a1bbcaf3c712 --- .../internal/telephony/dataconnection/DataConnection.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java index 348908a85c..255972af01 100644 --- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java +++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java @@ -2703,6 +2703,12 @@ public class DataConnection extends StateMachine { } ApnContext.requestLog( cp.mApnContext, "onSetupConnectionCompleted result=" + result); + + if (result != SetupResult.SUCCESS) { + releasePduSessionId(() -> DataConnection.this + .setPduSessionId(PDU_SESSION_ID_NOT_SET)); + } + switch (result) { case SUCCESS: // All is well -- GitLab From 28e7b234fd7571879c65d0e4917f31d8a6f4fcf6 Mon Sep 17 00:00:00 2001 From: Chi Zhang Date: Wed, 27 Apr 2022 16:17:40 -0700 Subject: [PATCH 020/656] Exclude limited service from RAT durations. Bug: 124332646 Test: build, unit tests, manual test with voice call/SMS/MMS Change-Id: Ibd7723a05260450c1a946c4bcc0ab4634c22e839 (cherry picked from commit dff5c2a9e050e33699ecb3482e9b3aa8c392f878) --- .../telephony/metrics/ServiceStateStats.java | 18 ++- .../telephony/metrics/ImsStatsTest.java | 1 + .../metrics/ServiceStateStatsTest.java | 116 +++++++++++++++--- .../metrics/VoiceCallSessionStatsTest.java | 18 ++- 4 files changed, 133 insertions(+), 20 deletions(-) diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java index 6698e5b4ed..6765a4cf20 100644 --- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java +++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java @@ -238,10 +238,22 @@ public class ServiceStateStats { if (imsPhone != null) { @NetworkType int imsVoiceRat = imsPhone.getImsStats().getImsVoiceRadioTech(); if (imsVoiceRat != TelephonyManager.NETWORK_TYPE_UNKNOWN) { - return imsVoiceRat; + // If IMS is over WWAN but WWAN PS is not in-service, then IMS RAT is invalid + boolean isImsVoiceRatValid = + (imsVoiceRat == TelephonyManager.NETWORK_TYPE_IWLAN + || getDataRat(state) != TelephonyManager.NETWORK_TYPE_UNKNOWN); + return isImsVoiceRatValid ? imsVoiceRat : TelephonyManager.NETWORK_TYPE_UNKNOWN; } } - return state.getVoiceNetworkType(); + + // If WWAN CS is not in-service, we should return NETWORK_TYPE_UNKNOWN + final NetworkRegistrationInfo wwanRegInfo = + state.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + return wwanRegInfo != null && wwanRegInfo.isInService() + ? wwanRegInfo.getAccessNetworkTechnology() + : TelephonyManager.NETWORK_TYPE_UNKNOWN; } /** @@ -263,7 +275,7 @@ public class ServiceStateStats { state.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - return wwanRegInfo != null + return wwanRegInfo != null && wwanRegInfo.isInService() ? wwanRegInfo.getAccessNetworkTechnology() : TelephonyManager.NETWORK_TYPE_UNKNOWN; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java index ef2a2f499c..8b2fe92f17 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java @@ -123,6 +123,7 @@ public class ImsStatsTest extends TelephonyTest { // WWAN PS RAT is LTE doReturn(new NetworkRegistrationInfo.Builder() .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) .build()) .when(mServiceState).getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN); diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java index bddaad18b7..1296b9707e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java @@ -103,6 +103,7 @@ public class ServiceStateStatsTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getVoiceNetworkType(); doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); mockWwanPsRat(TelephonyManager.NETWORK_TYPE_LTE); + doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mImsStats).getImsVoiceRadioTech(); mServiceStateStats = new TestableServiceStateStats(mPhone); } @@ -313,7 +314,52 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest - public void update_sameRats() throws Exception { + public void onImsVoiceRegistrationChanged_wifiCallingWhileOos() throws Exception { + doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getVoiceNetworkType(); + doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getDataNetworkType(); + doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mImsStats).getImsVoiceRadioTech(); + mockWwanCsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); + mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); + mServiceStateStats.onServiceStateChanged(mServiceState); + doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mImsStats).getImsVoiceRadioTech(); + + mServiceStateStats.incTimeMillis(100L); + mServiceStateStats.onImsVoiceRegistrationChanged(); + mServiceStateStats.incTimeMillis(200L); + mServiceStateStats.conclude(); + + // There should be 2 separate service state updates, which should be different objects + ArgumentCaptor captor = + ArgumentCaptor.forClass(CellularServiceState.class); + verify(mPersistAtomsStorage, times(2)) + .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null)); + assertNotSame(captor.getAllValues().get(0), captor.getAllValues().get(1)); + CellularServiceState state = captor.getAllValues().get(0); + assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.voiceRat); + assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat); + assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.voiceRoamingType); + assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.dataRoamingType); + assertFalse(state.isEndc); + assertEquals(0, state.simSlotIndex); + assertFalse(state.isMultiSim); + assertEquals(CARRIER1_ID, state.carrierId); + assertEquals(100L, state.totalTimeMillis); + state = captor.getAllValues().get(1); + assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, state.voiceRat); + assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat); + assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.voiceRoamingType); + assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.dataRoamingType); + assertFalse(state.isEndc); + assertEquals(0, state.simSlotIndex); + assertFalse(state.isMultiSim); + assertEquals(CARRIER1_ID, state.carrierId); + assertEquals(200L, state.totalTimeMillis); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + @SmallTest + public void onServiceStateChanged_sameRats() throws Exception { // Using default service state for LTE mServiceStateStats.onServiceStateChanged(mServiceState); @@ -340,7 +386,7 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest - public void update_differentDataRats() throws Exception { + public void onServiceStateChanged_differentDataRats() throws Exception { doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getDataNetworkType(); mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); @@ -361,7 +407,7 @@ public class ServiceStateStatsTest extends TelephonyTest { .addCellularServiceStateAndCellularDataServiceSwitch( serviceStateCaptor.capture(), serviceSwitchCaptor.capture()); CellularServiceState state = serviceStateCaptor.getAllValues().get(0); - assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); + assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat); assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.voiceRoamingType); assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.dataRoamingType); @@ -393,7 +439,7 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest - public void update_differentVoiceRats() throws Exception { + public void onServiceStateChanged_differentVoiceRats() throws Exception { // Using default service state for LTE mServiceStateStats.onServiceStateChanged(mServiceState); @@ -435,7 +481,7 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest - public void update_iwlanButNotWifiCalling() throws Exception { + public void onServiceStateChanged_iwlanButNotWifiCalling() throws Exception { // Using default service state for LTE as WWAN PS RAT doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mServiceState).getDataNetworkType(); @@ -462,7 +508,7 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest - public void update_endc() throws Exception { + public void onServiceStateChanged_endc() throws Exception { // Using default service state for LTE without ENDC mServiceStateStats.onServiceStateChanged(mServiceState); @@ -531,7 +577,7 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest - public void update_simSwapSameRat() throws Exception { + public void onServiceStateChanged_simSwapSameRat() throws Exception { // Using default service state for LTE mServiceStateStats.onServiceStateChanged(mServiceState); @@ -541,6 +587,17 @@ public class ServiceStateStatsTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_UMTS).when(mServiceState).getVoiceNetworkType(); doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getDataNetworkType(); mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); + doReturn( + new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) + .setRegistrationState( + NetworkRegistrationInfo.REGISTRATION_STATE_DENIED) + .setEmergencyOnly(true) + .build()) + .when(mServiceState) + .getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); doReturn(-1).when(mPhone).getCarrierId(); mServiceStateStats.onServiceStateChanged(mServiceState); mServiceStateStats.incTimeMillis(5000L); @@ -549,6 +606,8 @@ public class ServiceStateStatsTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getVoiceNetworkType(); doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); mockWwanPsRat(TelephonyManager.NETWORK_TYPE_LTE); + mockWwanCsRat(TelephonyManager.NETWORK_TYPE_LTE); + doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mImsStats).getImsVoiceRadioTech(); doReturn(CARRIER2_ID).when(mPhone).getCarrierId(); mServiceStateStats.onServiceStateChanged(mServiceState); mServiceStateStats.incTimeMillis(200L); @@ -570,7 +629,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); state = captor.getAllValues().get(1); - assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat); + assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat); assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.voiceRoamingType); assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.dataRoamingType); @@ -594,7 +653,7 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest - public void update_roaming() throws Exception { + public void onServiceStateChanged_roaming() throws Exception { // Using default service state for LTE mServiceStateStats.onServiceStateChanged(mServiceState); @@ -603,6 +662,8 @@ public class ServiceStateStatsTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_UMTS).when(mServiceState).getVoiceNetworkType(); doReturn(TelephonyManager.NETWORK_TYPE_UMTS).when(mServiceState).getDataNetworkType(); mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UMTS); + mockWwanCsRat(TelephonyManager.NETWORK_TYPE_UMTS); + doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mImsStats).getImsVoiceRadioTech(); doReturn(ServiceState.ROAMING_TYPE_INTERNATIONAL).when(mServiceState).getVoiceRoamingType(); mServiceStateStats.onServiceStateChanged(mServiceState); mServiceStateStats.incTimeMillis(200L); @@ -664,7 +725,7 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest - public void update_dualSim() throws Exception { + public void onServiceStateChanged_dualSim() throws Exception { // Using default service state for LTE // Only difference between the 2 slots is slot index mockDualSim(CARRIER1_ID); @@ -677,7 +738,9 @@ public class ServiceStateStatsTest extends TelephonyTest { mSecondServiceStateStats.incTimeMillis(100L); doReturn(TelephonyManager.NETWORK_TYPE_UMTS).when(mServiceState).getVoiceNetworkType(); doReturn(TelephonyManager.NETWORK_TYPE_UMTS).when(mServiceState).getDataNetworkType(); + doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mImsStats).getImsVoiceRadioTech(); mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UMTS); + mockWwanCsRat(TelephonyManager.NETWORK_TYPE_UMTS); mServiceStateStats.onServiceStateChanged(mServiceState); mServiceStateStats.incTimeMillis(200L); mSecondServiceStateStats.onServiceStateChanged(mServiceState); @@ -754,7 +817,7 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest - public void update_airplaneMode() throws Exception { + public void onServiceStateChanged_airplaneMode() throws Exception { // Using default service state for LTE mServiceStateStats.onServiceStateChanged(mServiceState); @@ -806,11 +869,34 @@ public class ServiceStateStatsTest extends TelephonyTest { } private void mockWwanPsRat(@NetworkType int rat) { - doReturn(new NetworkRegistrationInfo.Builder().setAccessNetworkTechnology(rat).build()) + mockWwanRat( + NetworkRegistrationInfo.DOMAIN_PS, + rat, + rat == TelephonyManager.NETWORK_TYPE_UNKNOWN + ? NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING + : NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + } + + private void mockWwanCsRat(@NetworkType int rat) { + mockWwanRat( + NetworkRegistrationInfo.DOMAIN_CS, + rat, + rat == TelephonyManager.NETWORK_TYPE_UNKNOWN + ? NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING + : NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + } + + private void mockWwanRat( + @NetworkRegistrationInfo.Domain int domain, + @NetworkType int rat, + @NetworkRegistrationInfo.RegistrationState int regState) { + doReturn( + new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(rat) + .setRegistrationState(regState) + .build()) .when(mServiceState) - .getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + .getNetworkRegistrationInfo(domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); } private void mockDualSim(int carrierId) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java index fc49fe6b49..5ae6d394c0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/VoiceCallSessionStatsTest.java @@ -2072,7 +2072,14 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { doReturn(rat).when(mock).getVoiceNetworkType(); doReturn(rat).when(mock).getDataNetworkType(); NetworkRegistrationInfo regInfo = - new NetworkRegistrationInfo.Builder().setAccessNetworkTechnology(rat).build(); + new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(rat) + .setRegistrationState( + rat == TelephonyManager.NETWORK_TYPE_UNKNOWN + ? NetworkRegistrationInfo + .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING + : NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); doReturn(regInfo).when(mock) .getNetworkRegistrationInfo( anyInt(), eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); @@ -2082,7 +2089,14 @@ public class VoiceCallSessionStatsTest extends TelephonyTest { doReturn(rat).when(mock).getVoiceNetworkType(); doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mock).getDataNetworkType(); NetworkRegistrationInfo wwanRegInfo = - new NetworkRegistrationInfo.Builder().setAccessNetworkTechnology(rat).build(); + new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(rat) + .setRegistrationState( + rat == TelephonyManager.NETWORK_TYPE_UNKNOWN + ? NetworkRegistrationInfo + .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING + : NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); doReturn(wwanRegInfo).when(mock) .getNetworkRegistrationInfo( anyInt(), eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); -- GitLab From 007c621166e49e22606af5ca41cd2d6131078b35 Mon Sep 17 00:00:00 2001 From: Chi Zhang Date: Thu, 5 May 2022 11:52:40 -0700 Subject: [PATCH 021/656] Add is_emergency_only to CellularServiceState. Test: build, unit test, manua test with voice call/SMS/MMS/data, statsd_testdrive Fixes: 124332646 Change-Id: Ib2191de72bc5c41d0d892402e4c0539be76186cd (cherry picked from commit bee35b0cfaec198d56f7e2c44d48126ea9c37739) --- proto/src/persist_atoms.proto | 3 +- .../telephony/metrics/MetricsCollector.java | 3 +- .../metrics/PersistAtomsStorage.java | 3 +- .../telephony/metrics/ServiceStateStats.java | 10 +++ .../metrics/PersistAtomsStorageTest.java | 28 +++++++- .../metrics/ServiceStateStatsTest.java | 68 +++++++++++++------ 6 files changed, 90 insertions(+), 25 deletions(-) diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index 3201f7cde1..28f1c2d69c 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -303,6 +303,7 @@ message CellularServiceState { optional bool is_multi_sim = 7; optional int32 carrier_id = 8; optional int64 total_time_millis = 9; // Duration needs to be rounded when pulled + optional bool is_emergency_only = 10; // Internal use only optional int64 last_used_millis = 10001; @@ -495,4 +496,4 @@ message GbaEvent { optional bool successful = 3; optional int32 failed_reason = 4; optional int32 count = 5; -} \ No newline at end of file +} diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 46e1d9478d..f3224a9192 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -718,7 +718,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { state.simSlotIndex, state.isMultiSim, state.carrierId, - roundAndConvertMillisToSeconds(state.totalTimeMillis)); + roundAndConvertMillisToSeconds(state.totalTimeMillis), + state.isEmergencyOnly); } private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) { diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java index 46d9e947bf..25544635fc 100644 --- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java +++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java @@ -1258,7 +1258,8 @@ public class PersistAtomsStorage { && state.isEndc == key.isEndc && state.simSlotIndex == key.simSlotIndex && state.isMultiSim == key.isMultiSim - && state.carrierId == key.carrierId) { + && state.carrierId == key.carrierId + && state.isEmergencyOnly == key.isEmergencyOnly) { return state; } } diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java index 6765a4cf20..df4db73290 100644 --- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java +++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java @@ -92,6 +92,7 @@ public class ServiceStateStats { newState.simSlotIndex = mPhone.getPhoneId(); newState.isMultiSim = SimSlotState.isMultiSim(); newState.carrierId = mPhone.getCarrierId(); + newState.isEmergencyOnly = isEmergencyOnly(serviceState); TimestampedServiceState prevState = mLastState.getAndSet(new TimestampedServiceState(newState, now)); @@ -212,6 +213,7 @@ public class ServiceStateStats { copy.isMultiSim = state.isMultiSim; copy.carrierId = state.carrierId; copy.totalTimeMillis = state.totalTimeMillis; + copy.isEmergencyOnly = state.isEmergencyOnly; return copy; } @@ -280,6 +282,14 @@ public class ServiceStateStats { : TelephonyManager.NETWORK_TYPE_UNKNOWN; } + private static boolean isEmergencyOnly(ServiceState state) { + NetworkRegistrationInfo regInfo = + state.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + return regInfo != null && !regInfo.isInService() && regInfo.isEmergencyEnabled(); + } + private static boolean isEndc(ServiceState state) { if (getDataRat(state) != TelephonyManager.NETWORK_TYPE_LTE) { return false; 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 ea1d2d1a0f..d2e30dbaaa 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java @@ -144,6 +144,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { private CellularServiceState mServiceState2Proto; private CellularServiceState mServiceState3Proto; private CellularServiceState mServiceState4Proto; + private CellularServiceState mServiceState5Proto; private CellularDataServiceSwitch[] mServiceSwitches; private CellularServiceState[] mServiceStates; @@ -408,6 +409,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mServiceState1Proto.isMultiSim = true; mServiceState1Proto.carrierId = CARRIER1_ID; mServiceState1Proto.totalTimeMillis = 5000L; + mServiceState1Proto.isEmergencyOnly = false; // LTE with ENDC on slot 0 mServiceState2Proto = new CellularServiceState(); @@ -420,6 +422,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mServiceState2Proto.isMultiSim = true; mServiceState2Proto.carrierId = CARRIER1_ID; mServiceState2Proto.totalTimeMillis = 15000L; + mServiceState2Proto.isEmergencyOnly = false; // LTE with WFC and roaming on slot 1 mServiceState3Proto = new CellularServiceState(); @@ -432,6 +435,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mServiceState3Proto.isMultiSim = true; mServiceState3Proto.carrierId = CARRIER2_ID; mServiceState3Proto.totalTimeMillis = 10000L; + mServiceState3Proto.isEmergencyOnly = false; // UMTS with roaming on slot 1 mServiceState4Proto = new CellularServiceState(); @@ -444,6 +448,20 @@ public class PersistAtomsStorageTest extends TelephonyTest { mServiceState4Proto.isMultiSim = true; mServiceState4Proto.carrierId = CARRIER2_ID; mServiceState4Proto.totalTimeMillis = 10000L; + mServiceState4Proto.isEmergencyOnly = false; + + // Limited service on slot 0 + mServiceState5Proto = new CellularServiceState(); + mServiceState5Proto.voiceRat = TelephonyManager.NETWORK_TYPE_UNKNOWN; + mServiceState5Proto.dataRat = TelephonyManager.NETWORK_TYPE_UNKNOWN; + mServiceState5Proto.voiceRoamingType = ServiceState.ROAMING_TYPE_NOT_ROAMING; + mServiceState5Proto.dataRoamingType = ServiceState.ROAMING_TYPE_NOT_ROAMING; + mServiceState5Proto.isEndc = false; + mServiceState5Proto.simSlotIndex = 0; + mServiceState5Proto.isMultiSim = true; + mServiceState5Proto.carrierId = CARRIER1_ID; + mServiceState5Proto.totalTimeMillis = 15000L; + mServiceState5Proto.isEmergencyOnly = true; mServiceSwitches = new CellularDataServiceSwitch[] {mServiceSwitch1Proto, mServiceSwitch2Proto}; @@ -452,7 +470,8 @@ public class PersistAtomsStorageTest extends TelephonyTest { mServiceState1Proto, mServiceState2Proto, mServiceState3Proto, - mServiceState4Proto + mServiceState4Proto, + mServiceState5Proto }; // IMS over LTE on slot 0, registered for 5 seconds @@ -931,6 +950,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mServiceState2Proto = null; mServiceState3Proto = null; mServiceState4Proto = null; + mServiceState5Proto = null; mServiceSwitches = null; mServiceStates = null; mImsRegistrationStatsLte0 = null; @@ -1368,7 +1388,8 @@ public class PersistAtomsStorageTest extends TelephonyTest { newServiceState1Proto, mServiceState2Proto, mServiceState3Proto, - mServiceState4Proto + mServiceState4Proto, + mServiceState5Proto }, serviceStates); CellularDataServiceSwitch[] serviceSwitches = @@ -1493,7 +1514,8 @@ public class PersistAtomsStorageTest extends TelephonyTest { mServiceState1Proto, mServiceState2Proto, mServiceState3Proto, - mServiceState4Proto + mServiceState4Proto, + mServiceState5Proto }, serviceStates1); assertProtoArrayEquals(new CellularServiceState[0], serviceStates2); diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java index 1296b9707e..96db966e02 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java @@ -138,6 +138,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -169,6 +170,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -211,10 +213,8 @@ public class ServiceStateStatsTest extends TelephonyTest { @Test @SmallTest public void conclude_noSimCardEmergencyOnly() throws Exception { - // Using default service state for LTE doReturn(CardState.CARDSTATE_ABSENT).when(mPhysicalSlot0).getCardState(); - doReturn(ServiceState.STATE_EMERGENCY_ONLY).when(mServiceState).getVoiceRegState(); - doReturn(ServiceState.STATE_EMERGENCY_ONLY).when(mServiceState).getDataRegState(); + mockLimitedService(TelephonyManager.NETWORK_TYPE_UMTS); doReturn(-1).when(mPhone).getCarrierId(); mServiceStateStats.onServiceStateChanged(mServiceState); @@ -227,8 +227,8 @@ public class ServiceStateStatsTest extends TelephonyTest { verify(mPersistAtomsStorage) .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null)); CellularServiceState state = captor.getValue(); - assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); - assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); + assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.voiceRat); + assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat); assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.voiceRoamingType); assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.dataRoamingType); assertFalse(state.isEndc); @@ -236,6 +236,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(-1, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(true, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -269,6 +270,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(-1, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -299,6 +301,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -309,6 +312,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -344,6 +348,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat); @@ -354,6 +359,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -381,6 +387,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -416,6 +423,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = serviceStateCaptor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -426,6 +434,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); CellularDataServiceSwitch serviceSwitch = serviceSwitchCaptor.getAllValues().get(0); assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, serviceSwitch.ratFrom); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, serviceSwitch.ratTo); @@ -503,6 +512,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(0L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -542,6 +552,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -552,6 +563,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = captor.getAllValues().get(2); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -562,6 +574,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(400L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = captor.getAllValues().get(3); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -572,6 +585,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(800L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -584,20 +598,7 @@ public class ServiceStateStatsTest extends TelephonyTest { mServiceStateStats.incTimeMillis(100L); // SIM removed, emergency call only doReturn(CardState.CARDSTATE_ABSENT).when(mPhysicalSlot0).getCardState(); - doReturn(TelephonyManager.NETWORK_TYPE_UMTS).when(mServiceState).getVoiceNetworkType(); - doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getDataNetworkType(); - mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); - doReturn( - new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) - .setRegistrationState( - NetworkRegistrationInfo.REGISTRATION_STATE_DENIED) - .setEmergencyOnly(true) - .build()) - .when(mServiceState) - .getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_CS, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + mockLimitedService(TelephonyManager.NETWORK_TYPE_UMTS); doReturn(-1).when(mPhone).getCarrierId(); mServiceStateStats.onServiceStateChanged(mServiceState); mServiceStateStats.incTimeMillis(5000L); @@ -628,6 +629,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat); @@ -638,6 +640,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(-1, state.carrierId); assertEquals(5000L, state.totalTimeMillis); + assertEquals(true, state.isEmergencyOnly); state = captor.getAllValues().get(2); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -648,6 +651,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER2_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -691,6 +695,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = serviceStateCaptor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat); @@ -701,6 +706,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = serviceStateCaptor.getAllValues().get(2); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat); @@ -711,6 +717,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(400L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); CellularDataServiceSwitch serviceSwitch = serviceSwitchCaptor.getAllValues().get(0); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, serviceSwitch.ratFrom); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, serviceSwitch.ratTo); @@ -766,6 +773,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertTrue(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = serviceStateCaptor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -776,6 +784,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertTrue(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = serviceStateCaptor.getAllValues().get(2); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat); @@ -786,6 +795,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertTrue(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = serviceStateCaptor.getAllValues().get(3); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat); @@ -796,6 +806,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertTrue(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); CellularDataServiceSwitch serviceSwitch = serviceSwitchCaptor.getAllValues().get(0); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, serviceSwitch.ratFrom); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, serviceSwitch.ratTo); @@ -855,6 +866,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -865,6 +877,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -899,6 +912,23 @@ public class ServiceStateStatsTest extends TelephonyTest { .getNetworkRegistrationInfo(domain, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); } + private void mockLimitedService(@NetworkType int rat) { + doReturn(rat).when(mServiceState).getVoiceNetworkType(); + doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getDataNetworkType(); + mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); + doReturn( + new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(rat) + .setRegistrationState( + NetworkRegistrationInfo.REGISTRATION_STATE_DENIED) + .setEmergencyOnly(true) + .build()) + .when(mServiceState) + .getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + } + private void mockDualSim(int carrierId) { doReturn(1).when(mSecondPhone).getPhoneId(); doReturn(1).when(mUiccController).getSlotIdFromPhoneId(1); -- GitLab From 423d57396dae1072a91f22acb1ff465b21fdb70c Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Mon, 4 Apr 2022 18:09:57 +0000 Subject: [PATCH 022/656] Added support for FDN Check in Supplementary Services(SS). If FDN is available and enabled, then only SS whose control strings are present in FDN list are allowed. Bug: 218262162 Test: Manual atest com.android.internal.telephony.GsmCdmaPhoneTest atest com.android.internal.telephony.gsm.GsmMmiCodeTest atest com.android.internal.telephony.FdnUtilsTest Change-Id: Ifde290a188e002b5d05e210c34a50a6bf2551863 --- .../android/internal/telephony/FdnUtils.java | 23 ++ .../internal/telephony/GsmCdmaPhone.java | 116 ++++++- .../internal/telephony/SmsController.java | 2 +- .../internal/telephony/gsm/GsmMmiCode.java | 185 ++++++++++- .../internal/telephony/GsmCdmaPhoneTest.java | 305 ++++++++++++++++++ .../telephony/gsm/GsmMmiCodeTest.java | 206 ++++++++++++ 6 files changed, 834 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/FdnUtils.java b/src/java/com/android/internal/telephony/FdnUtils.java index 5ad6ce488c..aa2bcfd128 100644 --- a/src/java/com/android/internal/telephony/FdnUtils.java +++ b/src/java/com/android/internal/telephony/FdnUtils.java @@ -74,6 +74,29 @@ public class FdnUtils { return app.getIccFdnEnabled(); } + /** + * If FDN is enabled, check to see if the given supplementary service control strings are + * blocked due to FDN. + * @param phoneId The phone object id for which the FDN check is performed + * @param controlStrings control strings associated with the supplementary service request + * @param defaultCountryIso country ISO for the subscription associated with this phone + * @return {@code true} if the FDN list does not contain any of the control strings. + */ + public static boolean isSuppServiceRequestBlockedByFdn(int phoneId, + ArrayList controlStrings, String defaultCountryIso) { + if (!isFdnEnabled(phoneId)) { + return false; + } + + ArrayList fdnList = getFdnList(phoneId); + for(String controlString : controlStrings) { + if(isFDN(controlString, defaultCountryIso, fdnList)) { + return false; + } + } + return true; + } + /** * Checks if dialStr is part of FDN list. * diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 1d3c3e5aed..892f336d3c 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -99,6 +99,7 @@ import com.android.internal.telephony.dataconnection.DcTracker; import com.android.internal.telephony.dataconnection.TransportManager; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.gsm.GsmMmiCode; +import com.android.internal.telephony.gsm.SsData; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; @@ -1697,6 +1698,13 @@ public class GsmCdmaPhone extends Phone { return true; } + // Perform FDN check + if(FdnUtils.isNumberBlockedByFDN(mPhoneId, ussdRequest, getCountryIso())) { + sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE, + wrappedCallback ); + return true; + } + // Try over IMS if possible. Phone imsPhone = mImsPhone; if ((imsPhone != null) @@ -2340,6 +2348,15 @@ public class GsmCdmaPhone extends Phone { @Override public void getCallForwardingOption(int commandInterfaceCFReason, int serviceClass, Message onComplete) { + // Perform FDN check + SsData.ServiceType serviceType = GsmMmiCode.cfReasonToServiceType(commandInterfaceCFReason); + if(isRequestBlockedByFDN(SsData.RequestType.SS_INTERROGATION, serviceType)) { + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.FDN_CHECK_FAILURE)); + onComplete.sendToTarget(); + return; + } + Phone imsPhone = mImsPhone; if (useSsOverIms(onComplete)) { imsPhone.getCallForwardingOption(commandInterfaceCFReason, serviceClass, onComplete); @@ -2389,6 +2406,16 @@ public class GsmCdmaPhone extends Phone { int serviceClass, int timerSeconds, Message onComplete) { + // Perform FDN check + SsData.RequestType requestType = GsmMmiCode.cfActionToRequestType(commandInterfaceCFAction); + SsData.ServiceType serviceType = GsmMmiCode.cfReasonToServiceType(commandInterfaceCFReason); + if(isRequestBlockedByFDN(requestType, serviceType)) { + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.FDN_CHECK_FAILURE)); + onComplete.sendToTarget(); + return; + } + Phone imsPhone = mImsPhone; if (useSsOverIms(onComplete)) { imsPhone.setCallForwardingOption(commandInterfaceCFAction, commandInterfaceCFReason, @@ -2442,6 +2469,15 @@ public class GsmCdmaPhone extends Phone { @Override public void getCallBarring(String facility, String password, Message onComplete, int serviceClass) { + // Perform FDN check + SsData.ServiceType serviceType = GsmMmiCode.cbFacilityToServiceType(facility); + if (isRequestBlockedByFDN(SsData.RequestType.SS_INTERROGATION, serviceType)) { + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.FDN_CHECK_FAILURE)); + onComplete.sendToTarget(); + return; + } + Phone imsPhone = mImsPhone; if (useSsOverIms(onComplete)) { imsPhone.getCallBarring(facility, password, onComplete, serviceClass); @@ -2458,6 +2494,17 @@ public class GsmCdmaPhone extends Phone { @Override public void setCallBarring(String facility, boolean lockState, String password, Message onComplete, int serviceClass) { + // Perform FDN check + SsData.RequestType requestType = lockState ? SsData.RequestType.SS_ACTIVATION : + SsData.RequestType.SS_DEACTIVATION; + SsData.ServiceType serviceType = GsmMmiCode.cbFacilityToServiceType(facility); + if (isRequestBlockedByFDN(requestType, serviceType)) { + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.FDN_CHECK_FAILURE)); + onComplete.sendToTarget(); + return; + } + Phone imsPhone = mImsPhone; if (useSsOverIms(onComplete)) { imsPhone.setCallBarring(facility, lockState, password, onComplete, serviceClass); @@ -2481,6 +2528,18 @@ public class GsmCdmaPhone extends Phone { */ public void changeCallBarringPassword(String facility, String oldPwd, String newPwd, Message onComplete) { + // Perform FDN check + SsData.ServiceType serviceType = GsmMmiCode.cbFacilityToServiceType(facility); + ArrayList controlStrings = GsmMmiCode.getControlStringsForPwd( + SsData.RequestType.SS_REGISTRATION, + serviceType); + if(FdnUtils.isSuppServiceRequestBlockedByFdn(mPhoneId, controlStrings, getCountryIso())) { + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.FDN_CHECK_FAILURE)); + onComplete.sendToTarget(); + return; + } + if (isPhoneTypeGsm()) { mCi.changeBarringPassword(facility, oldPwd, newPwd, onComplete); } else { @@ -2490,6 +2549,14 @@ public class GsmCdmaPhone extends Phone { @Override public void getOutgoingCallerIdDisplay(Message onComplete) { + // Perform FDN check + if(isRequestBlockedByFDN(SsData.RequestType.SS_INTERROGATION, SsData.ServiceType.SS_CLIR)){ + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.FDN_CHECK_FAILURE)); + onComplete.sendToTarget(); + return; + } + Phone imsPhone = mImsPhone; if (useSsOverIms(onComplete)) { imsPhone.getOutgoingCallerIdDisplay(onComplete); @@ -2508,6 +2575,15 @@ public class GsmCdmaPhone extends Phone { @Override public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { + // Perform FDN check + SsData.RequestType requestType = GsmMmiCode.clirModeToRequestType(commandInterfaceCLIRMode); + if (isRequestBlockedByFDN(requestType, SsData.ServiceType.SS_CLIR)) { + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.FDN_CHECK_FAILURE)); + onComplete.sendToTarget(); + return; + } + Phone imsPhone = mImsPhone; if (useSsOverIms(onComplete)) { imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete); @@ -2530,6 +2606,14 @@ public class GsmCdmaPhone extends Phone { @Override public void queryCLIP(Message onComplete) { + // Perform FDN check + if(isRequestBlockedByFDN(SsData.RequestType.SS_INTERROGATION, SsData.ServiceType.SS_CLIP)){ + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.FDN_CHECK_FAILURE)); + onComplete.sendToTarget(); + return; + } + Phone imsPhone = mImsPhone; if (useSsOverIms(onComplete)) { imsPhone.queryCLIP(onComplete); @@ -2548,6 +2632,14 @@ public class GsmCdmaPhone extends Phone { @Override public void getCallWaiting(Message onComplete) { + // Perform FDN check + if(isRequestBlockedByFDN(SsData.RequestType.SS_INTERROGATION, SsData.ServiceType.SS_WAIT)){ + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.FDN_CHECK_FAILURE)); + onComplete.sendToTarget(); + return; + } + Phone imsPhone = mImsPhone; if (useSsOverIms(onComplete)) { imsPhone.getCallWaiting(onComplete); @@ -2589,6 +2681,16 @@ public class GsmCdmaPhone extends Phone { @Override public void setCallWaiting(boolean enable, int serviceClass, Message onComplete) { + // Perform FDN check + SsData.RequestType requestType = enable ? SsData.RequestType.SS_ACTIVATION : + SsData.RequestType.SS_DEACTIVATION; + if (isRequestBlockedByFDN(requestType, SsData.ServiceType.SS_WAIT)) { + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.FDN_CHECK_FAILURE)); + onComplete.sendToTarget(); + return; + } + Phone imsPhone = mImsPhone; if (useSsOverIms(onComplete)) { imsPhone.setCallWaiting(enable, onComplete); @@ -4921,4 +5023,16 @@ public class GsmCdmaPhone extends Phone { public InboundSmsHandler getInboundSmsHandler(boolean is3gpp2) { return mIccSmsInterfaceManager.getInboundSmsHandler(is3gpp2); } -} + + /** + * The following function checks if supplementary service request is blocked due to FDN. + * @param requestType request type associated with the supplementary service + * @param serviceType supplementary service type + * @return {@code true} if request is blocked due to FDN. + */ + private boolean isRequestBlockedByFDN(SsData.RequestType requestType, + SsData.ServiceType serviceType) { + ArrayList controlStrings = GsmMmiCode.getControlStrings(requestType, serviceType); + return FdnUtils.isSuppServiceRequestBlockedByFdn(mPhoneId, controlStrings, getCountryIso()); + } +} \ No newline at end of file diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 0cd7d29bed..589a0d75a2 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -902,7 +902,7 @@ public class SmsController extends ISmsImplBase { */ private boolean isNumberBlockedByFDN(int subId, String destAddr, String callingPackage) { int phoneId = SubscriptionManager.getPhoneId(subId); - if (!FdnUtils.isFdnEnabled(subId)) { + if (!FdnUtils.isFdnEnabled(phoneId)) { return false; } diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java index dec246836c..1353511c4d 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -61,6 +61,7 @@ import com.android.internal.telephony.uicc.UiccCardApplication; import com.android.internal.telephony.util.ArrayUtils; import com.android.telephony.Rlog; +import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -455,7 +456,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { return ""; } - private String getActionStringFromReqType(SsData.RequestType rType) { + private static String getActionStringFromReqType(SsData.RequestType rType) { switch (rType) { case SS_ACTIVATION: return ACTION_ACTIVATE; @@ -520,6 +521,40 @@ public final class GsmMmiCode extends Handler implements MmiCode { } } + public static SsData.ServiceType cfReasonToServiceType(int commandInterfaceCFReason) { + switch (commandInterfaceCFReason) { + case CommandsInterface.CF_REASON_UNCONDITIONAL: + return SsData.ServiceType.SS_CFU; + case CommandsInterface.CF_REASON_BUSY: + return SsData.ServiceType.SS_CF_BUSY; + case CommandsInterface.CF_REASON_NO_REPLY: + return SsData.ServiceType.SS_CF_NO_REPLY; + case CommandsInterface.CF_REASON_NOT_REACHABLE: + return SsData.ServiceType.SS_CF_NOT_REACHABLE; + case CommandsInterface.CF_REASON_ALL: + return SsData.ServiceType.SS_CF_ALL; + case CommandsInterface.CF_REASON_ALL_CONDITIONAL: + return SsData.ServiceType.SS_CF_ALL_CONDITIONAL; + default: + return null; + } + } + + public static SsData.RequestType cfActionToRequestType(int commandInterfaceCFAction) { + switch (commandInterfaceCFAction) { + case CommandsInterface.CF_ACTION_DISABLE: + return SsData.RequestType.SS_DEACTIVATION; + case CommandsInterface.CF_ACTION_ENABLE: + return SsData.RequestType.SS_ACTIVATION; + case CommandsInterface.CF_ACTION_REGISTRATION: + return SsData.RequestType.SS_REGISTRATION; + case CommandsInterface.CF_ACTION_ERASURE: + return SsData.RequestType.SS_ERASURE; + default: + return null; + } + } + @UnsupportedAppUsage private static int siToServiceClass(String si) { @@ -623,6 +658,29 @@ public final class GsmMmiCode extends Handler implements MmiCode { } } + public static SsData.ServiceType cbFacilityToServiceType(String commandInterfaceCBFacility) { + switch(commandInterfaceCBFacility) { + case CommandsInterface.CB_FACILITY_BAOC: + return SsData.ServiceType.SS_BAOC; + case CommandsInterface.CB_FACILITY_BAOIC: + return SsData.ServiceType.SS_BAOIC; + case CommandsInterface.CB_FACILITY_BAOICxH: + return SsData.ServiceType.SS_BAOIC_EXC_HOME; + case CommandsInterface.CB_FACILITY_BAIC: + return SsData.ServiceType.SS_BAIC; + case CommandsInterface.CB_FACILITY_BAICr: + return SsData.ServiceType.SS_BAIC_ROAMING; + case CommandsInterface.CB_FACILITY_BA_ALL: + return SsData.ServiceType.SS_ALL_BARRING; + case CommandsInterface.CB_FACILITY_BA_MO: + return SsData.ServiceType.SS_OUTGOING_BARRING; + case CommandsInterface.CB_FACILITY_BA_MT: + return SsData.ServiceType.SS_INCOMING_BARRING; + default: + return null; + } + } + //***** Constructor @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -892,6 +950,17 @@ public final class GsmMmiCode extends Handler implements MmiCode { return CommandsInterface.CLIR_DEFAULT; } + public static SsData.RequestType clirModeToRequestType(int commandInterfaceCLIRMode) { + switch (commandInterfaceCLIRMode) { + case CommandsInterface.CLIR_SUPPRESSION: + return SsData.RequestType.SS_ACTIVATION; + case CommandsInterface.CLIR_INVOCATION: + return SsData.RequestType.SS_DEACTIVATION; + default: + return null; + } + } + /** * Returns true if the Service Code is FAC to dial as a normal call. * @@ -1827,6 +1896,120 @@ public final class GsmMmiCode extends Handler implements MmiCode { return this.mCallbackReceiver; } + /** + * Returns list of control strings for a supplementary service request + * as defined in TS 22.030 6.5 + * @param requestType request type associated with the supplementary service + * @param serviceType supplementary service type + * @return list of control strings associated with the supplementary service. + */ + public static ArrayList getControlStrings(SsData.RequestType requestType, + SsData.ServiceType serviceType) { + ArrayList controlStrings = new ArrayList<>(); + if (requestType == null || serviceType == null) { + return controlStrings; + } + + String actionStr = getActionStringFromReqType(requestType); + switch (serviceType) { + case SS_CFU: + controlStrings.add(actionStr + SC_CFU); + controlStrings.add(actionStr + SC_CF_All); + break; + case SS_CF_BUSY: + controlStrings.add(actionStr + SC_CFB); + controlStrings.add(actionStr + SC_CF_All_Conditional); + controlStrings.add(actionStr + SC_CF_All); + break; + case SS_CF_NO_REPLY: + controlStrings.add(actionStr + SC_CFNRy); + controlStrings.add(actionStr + SC_CF_All_Conditional); + controlStrings.add(actionStr + SC_CF_All); + break; + case SS_CF_NOT_REACHABLE: + controlStrings.add(actionStr + SC_CFNR); + controlStrings.add(actionStr + SC_CF_All_Conditional); + controlStrings.add(actionStr + SC_CF_All); + break; + case SS_CF_ALL: + controlStrings.add(actionStr + SC_CF_All); + break; + case SS_CF_ALL_CONDITIONAL: + controlStrings.add(actionStr + SC_CF_All_Conditional); + controlStrings.add(actionStr + SC_CF_All); + break; + case SS_CLIP: + controlStrings.add(actionStr + SC_CLIP); + break; + case SS_CLIR: + controlStrings.add(actionStr + SC_CLIR); + break; + case SS_WAIT: + controlStrings.add(actionStr + SC_WAIT); + break; + case SS_BAOC: + controlStrings.add(actionStr + SC_BAOC); + controlStrings.add(actionStr + SC_BA_MO); + controlStrings.add(actionStr + SC_BA_ALL); + break; + case SS_BAOIC: + controlStrings.add(actionStr + SC_BAOIC); + controlStrings.add(actionStr + SC_BA_MO); + controlStrings.add(actionStr + SC_BA_ALL); + break; + case SS_BAOIC_EXC_HOME: + controlStrings.add(actionStr + SC_BAOICxH); + controlStrings.add(actionStr + SC_BA_MO); + controlStrings.add(actionStr + SC_BA_ALL); + break; + case SS_BAIC: + controlStrings.add(actionStr + SC_BAIC); + controlStrings.add(actionStr + SC_BA_MT); + controlStrings.add(actionStr + SC_BA_ALL); + break; + case SS_BAIC_ROAMING: + controlStrings.add(actionStr + SC_BAICr); + controlStrings.add(actionStr + SC_BA_MT); + controlStrings.add(actionStr + SC_BA_ALL); + break; + case SS_ALL_BARRING: + controlStrings.add(actionStr + SC_BA_ALL); + break; + case SS_OUTGOING_BARRING: + controlStrings.add(actionStr + SC_BA_MO); + controlStrings.add(actionStr + SC_BA_ALL); + break; + case SS_INCOMING_BARRING: + controlStrings.add(actionStr + SC_BA_MT); + controlStrings.add(actionStr + SC_BA_ALL); + break; + } + return controlStrings; + } + + /** + * Returns control strings for registration of new password as per TS 22.030 6.5.4 + * @param requestType request type associated with the supplementary service + * @param serviceType supplementary service type + * @return list of control strings for new password registration. + */ + public static ArrayList getControlStringsForPwd(SsData.RequestType requestType, + SsData.ServiceType serviceType) { + ArrayList controlStrings = new ArrayList<>(); + if (requestType == null || serviceType == null) { + return controlStrings; + } + + controlStrings = getControlStrings(SsData.RequestType.SS_ACTIVATION, serviceType); + String actionStr = getActionStringFromReqType(requestType); + ArrayList controlStringsPwd = new ArrayList<>(); + for(String controlString : controlStrings) { + // Prepend each control string with **SC_PWD + controlStringsPwd.add(actionStr + SC_PWD + controlString); + } + return controlStringsPwd; + } + /*** * TODO: It would be nice to have a method here that can take in a dialstring and * figure out if there is an MMI code embedded within it. This code would replace diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 54b9a1d12d..e5a1fe14a3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -78,8 +78,11 @@ import androidx.test.filters.FlakyTest; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.test.SimulatedCommandsVerifier; +import com.android.internal.telephony.uicc.AdnRecord; +import com.android.internal.telephony.uicc.AdnRecordCache; import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccCardStatus; +import com.android.internal.telephony.uicc.IccConstants; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.IccVmNotSupportedException; import com.android.internal.telephony.uicc.UiccController; @@ -109,6 +112,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { private UiccSlot mUiccSlot; private UiccPort mUiccPort; private CommandsInterface mMockCi; + private AdnRecordCache adnRecordCache; //mPhoneUnderTest private GsmCdmaPhone mPhoneUT; @@ -140,6 +144,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mUiccSlot = Mockito.mock(UiccSlot.class); mUiccPort = Mockito.mock(UiccPort.class); mMockCi = Mockito.mock(CommandsInterface.class); + adnRecordCache = Mockito.mock(AdnRecordCache.class); doReturn(false).when(mSST).isDeviceShuttingDown(); doReturn(true).when(mImsManager).isVolteEnabledByPlatform(); @@ -1875,4 +1880,304 @@ public class GsmCdmaPhoneTest extends TelephonyTest { processAllMessages(); verify(mMockCi, never()).setUsageSetting(any(), anyInt()); } + + public void fdnCheckSetup() { + // FDN check setup + mPhoneUT.mCi = mMockCi; + doReturn(adnRecordCache).when(mSimRecords).getAdnCache(); + doReturn(mUiccProfile).when(mUiccController).getUiccProfileForPhone(anyInt()); + doReturn(true).when(mUiccCardApplication3gpp).getIccFdnAvailable(); + doReturn(true).when(mUiccCardApplication3gpp).getIccFdnEnabled(); + } + + @Test + public void testGetCallForwardingOption_FdnCheck() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + Message message = Message.obtain(mTestHandler); + + // FDN check success - no exception is returned + AdnRecord adnRecord = new AdnRecord(null, "*#21"); + fdnList.add(0, adnRecord); + mPhoneUT.getCallForwardingOption(CommandsInterface.CF_REASON_UNCONDITIONAL, message); + processAllMessages(); + verify(mMockCi).queryCallForwardStatus(eq(CommandsInterface.CF_REASON_UNCONDITIONAL), + eq(CommandsInterface.SERVICE_CLASS_VOICE), any(), any()); + // FDN check failure - returns CommandException in onComplete + fdnList.remove(0); + mPhoneUT.getCallForwardingOption(CommandsInterface.CF_REASON_UNCONDITIONAL, message); + processAllMessages(); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertEquals(((CommandException) ar.exception).getCommandError(), + CommandException.Error.FDN_CHECK_FAILURE); + + // clean up + fdnCheckCleanup(); + } + + @Test + public void testSetCallForwardingOption_FdnCheck() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + Message message = Message.obtain(mTestHandler); + + // FDN check success - no exception is returned + AdnRecord adnRecord = new AdnRecord(null, "**21"); + fdnList.add(0, adnRecord); + mPhoneUT.setCallForwardingOption(CommandsInterface.CF_ACTION_REGISTRATION, + CommandsInterface.CF_REASON_UNCONDITIONAL, "123", 0, + message); + processAllMessages(); + verify(mMockCi).setCallForward(eq(CommandsInterface.CF_ACTION_REGISTRATION), + eq(CommandsInterface.CF_REASON_UNCONDITIONAL), + eq(CommandsInterface.SERVICE_CLASS_VOICE), eq("123"), eq(0), any()); + // FDN check failure - returns CommandException in onComplete + fdnList.remove(0); + mPhoneUT.setCallForwardingOption(CommandsInterface.CF_ACTION_REGISTRATION, + CommandsInterface.CF_REASON_UNCONDITIONAL, "", 0, message); + processAllMessages(); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertEquals(((CommandException) ar.exception).getCommandError(), + CommandException.Error.FDN_CHECK_FAILURE); + + // clean up + fdnCheckCleanup(); + } + + @Test + public void testGetCallBarring_FdnCheck() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + Message message = Message.obtain(mTestHandler); + + // FDN check success - no exception is returned + AdnRecord adnRecord = new AdnRecord(null, "*#330"); + fdnList.add(0, adnRecord); + mPhoneUT.getCallBarring(CommandsInterface.CB_FACILITY_BA_ALL, "", message, + CommandsInterface.SERVICE_CLASS_VOICE); + processAllMessages(); + verify(mMockCi).queryFacilityLock(eq(CommandsInterface.CB_FACILITY_BA_ALL), any(), + eq(CommandsInterface.SERVICE_CLASS_VOICE), any()); + // FDN check failure - returns CommandException in onComplete + fdnList.remove(0); + mPhoneUT.getCallBarring(CommandsInterface.CB_FACILITY_BA_ALL, "", message, + CommandsInterface.SERVICE_CLASS_VOICE); + processAllMessages(); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertEquals(((CommandException) ar.exception).getCommandError(), + CommandException.Error.FDN_CHECK_FAILURE); + + // clean up + fdnCheckCleanup(); + } + + @Test + public void testSetCallBarring_FdnCheck() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + Message message = Message.obtain(mTestHandler); + + // FDN check success - no exception is returned + AdnRecord adnRecord = new AdnRecord(null, "*330"); + fdnList.add(0, adnRecord); + mPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BA_ALL, true, "", + message, CommandsInterface.SERVICE_CLASS_VOICE); + processAllMessages(); + verify(mMockCi).setFacilityLock(eq(CommandsInterface.CB_FACILITY_BA_ALL), + eq(true), any(), eq(CommandsInterface.SERVICE_CLASS_VOICE), any()); + // FDN check failure - returns CommandException in onComplete + fdnList.remove(0); + mPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BA_ALL, true, "", + message, CommandsInterface.SERVICE_CLASS_VOICE); + processAllMessages(); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertEquals(((CommandException) ar.exception).getCommandError(), + CommandException.Error.FDN_CHECK_FAILURE); + + // clean up + fdnCheckCleanup(); + } + + @Test + public void testChangeCallBarringPassword_FdnCheck() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + Message message = Message.obtain(mTestHandler); + + // FDN check success - no exception is returned + AdnRecord adnRecord = new AdnRecord(null, "**03*330"); + fdnList.add(0, adnRecord); + mPhoneUT.changeCallBarringPassword(CommandsInterface.CB_FACILITY_BA_ALL, "", + "", message); + processAllMessages(); + verify(mMockCi).changeBarringPassword(eq(CommandsInterface.CB_FACILITY_BA_ALL), any(), + any(), any()); + // FDN check failure - returns CommandException in onComplete + fdnList.remove(0); + mPhoneUT.changeCallBarringPassword(CommandsInterface.CB_FACILITY_BA_ALL, "", + "", message); + processAllMessages(); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertEquals(((CommandException) ar.exception).getCommandError(), + CommandException.Error.FDN_CHECK_FAILURE); + + // clean up + fdnCheckCleanup(); + } + + @Test + public void testGetOutgoingCallerIdDisplay_FdnCheck() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + Message message = Message.obtain(mTestHandler); + + // FDN check success - no exception is returned + AdnRecord adnRecord = new AdnRecord(null, "*#31"); + fdnList.add(0, adnRecord); + mPhoneUT.getOutgoingCallerIdDisplay(message); + processAllMessages(); + verify(mMockCi).getCLIR(any()); + // FDN check failure - returns CommandException in onComplete + fdnList.remove(0); + mPhoneUT.getOutgoingCallerIdDisplay(message); + processAllMessages(); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertEquals(((CommandException) ar.exception).getCommandError(), + CommandException.Error.FDN_CHECK_FAILURE); + + // clean up + fdnCheckCleanup(); + } + + @Test + public void testSetOutgoingCallerIdDisplay_FdnCheck() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + Message message = Message.obtain(mTestHandler); + + // FDN check success - no exception is returned + AdnRecord adnRecord = new AdnRecord(null, "*31"); + fdnList.add(0, adnRecord); + mPhoneUT.setOutgoingCallerIdDisplay(CommandsInterface.CLIR_SUPPRESSION, message); + processAllMessages(); + verify(mMockCi).setCLIR(eq(CommandsInterface.CLIR_SUPPRESSION), any()); + // FDN check failure - returns CommandException in onComplete + fdnList.remove(0); + mPhoneUT.setOutgoingCallerIdDisplay(CommandsInterface.CLIR_SUPPRESSION, message); + processAllMessages(); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertEquals(((CommandException) ar.exception).getCommandError(), + CommandException.Error.FDN_CHECK_FAILURE); + + // clean up + fdnCheckCleanup(); + } + + @Test + public void testQueryCLIP_FdnCheck() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + Message message = Message.obtain(mTestHandler); + + // FDN check success - no exception is returned + AdnRecord adnRecord = new AdnRecord(null, "*#30"); + fdnList.add(0, adnRecord); + mPhoneUT.queryCLIP(message); + processAllMessages(); + verify(mMockCi).queryCLIP(any()); + // FDN check failure - returns CommandException in onComplete + fdnList.remove(0); + mPhoneUT.queryCLIP(message); + processAllMessages(); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertEquals(((CommandException) ar.exception).getCommandError(), + CommandException.Error.FDN_CHECK_FAILURE); + + // clean up + fdnCheckCleanup(); + } + + @Test + public void testGetCallWaiting_FdnCheck() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + Message message = Message.obtain(mTestHandler); + + // FDN check success - no exception is returned + AdnRecord adnRecord = new AdnRecord(null, "*#43"); + fdnList.add(0, adnRecord); + mPhoneUT.getCallWaiting(message); + processAllMessages(); + verify(mMockCi).queryCallWaiting(eq(CommandsInterface.SERVICE_CLASS_NONE), any()); + // FDN check failure - returns CommandException in onComplete + fdnList.remove(0); + mPhoneUT.getCallWaiting(message); + processAllMessages(); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertEquals(((CommandException) ar.exception).getCommandError(), + CommandException.Error.FDN_CHECK_FAILURE); + + // clean up + fdnCheckCleanup(); + } + + @Test + public void testSetCallWaiting_FdnCheck() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + Message message = Message.obtain(mTestHandler); + + // FDN check success - no exception is returned + AdnRecord adnRecord = new AdnRecord(null, "*43"); + fdnList.add(0, adnRecord); + mPhoneUT.setCallWaiting(true, CommandsInterface.SERVICE_CLASS_VOICE, message); + processAllMessages(); + verify(mMockCi).setCallWaiting(eq(true), eq(CommandsInterface.SERVICE_CLASS_VOICE), + any()); + // FDN check failure - returns CommandException in onComplete + fdnList.remove(0); + mPhoneUT.setCallWaiting(true, CommandsInterface.SERVICE_CLASS_VOICE, message); + processAllMessages(); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertEquals(((CommandException) ar.exception).getCommandError(), + CommandException.Error.FDN_CHECK_FAILURE); + + // clean up + fdnCheckCleanup(); + } + + public void fdnCheckCleanup() { + doReturn(false).when(mUiccCardApplication3gpp).getIccFdnAvailable(); + doReturn(false).when(mUiccCardApplication3gpp).getIccFdnEnabled(); + } } 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 8c1caa5a4d..70df8aa70f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.gsm; +import static com.google.common.truth.Truth.assertThat; + import static junit.framework.Assert.fail; import static org.junit.Assert.assertTrue; @@ -36,6 +38,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; import java.util.concurrent.Executor; /** @@ -102,6 +105,209 @@ public class GsmMmiCodeTest extends TelephonyTest { } } + // The main purpose of this test is to list all the valid use cases of getControlStrings(). + @Test + public void testGetControlStrings() { + // Test if controlStrings list is empty when inputs are null + ArrayList controlStrings = GsmMmiCode.getControlStrings(null, + null); + assertThat(controlStrings).isEmpty(); + + // Test control strings of Call Forwarding Unconditional + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_CFU); + assertThat(controlStrings).containsExactly("*#21", "*#002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_REGISTRATION, + SsData.ServiceType.SS_CFU); + assertThat(controlStrings).containsExactly("**21", "**002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_CFU); + assertThat(controlStrings).containsExactly("#21", "#002"); + + // Test control strings of Call Forwarding Busy + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_CF_BUSY); + assertThat(controlStrings).containsExactly("*#67", "*#004", "*#002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_REGISTRATION, + SsData.ServiceType.SS_CF_BUSY); + assertThat(controlStrings).containsExactly("**67", "**004", "**002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_CF_BUSY); + assertThat(controlStrings).containsExactly("#67", "#004", "#002"); + + // Test control strings of Call Forwarding No Reply + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_CF_NO_REPLY); + assertThat(controlStrings).containsExactly("*#61", "*#004", "*#002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_REGISTRATION, + SsData.ServiceType.SS_CF_NO_REPLY); + assertThat(controlStrings).containsExactly("**61", "**004", "**002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_CF_NO_REPLY); + assertThat(controlStrings).containsExactly("#61", "#004", "#002"); + + // Test control strings of Call Forwarding Not Reachable + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_CF_NOT_REACHABLE); + assertThat(controlStrings).containsExactly("*#62", "*#004", "*#002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_REGISTRATION, + SsData.ServiceType.SS_CF_NOT_REACHABLE); + assertThat(controlStrings).containsExactly("**62", "**004", "**002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_CF_NOT_REACHABLE); + assertThat(controlStrings).containsExactly("#62", "#004", "#002"); + + // Test control strings of Call Forwarding All + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_CF_ALL); + assertThat(controlStrings).containsExactly("*#002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_REGISTRATION, + SsData.ServiceType.SS_CF_ALL); + assertThat(controlStrings).containsExactly("**002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_CF_ALL); + assertThat(controlStrings).containsExactly("#002"); + + // Test control strings of Call Forwarding ALl Conditional + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_CF_ALL_CONDITIONAL); + assertThat(controlStrings).containsExactly("*#004", "*#002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_REGISTRATION, + SsData.ServiceType.SS_CF_ALL_CONDITIONAL); + assertThat(controlStrings).containsExactly("**004", "**002"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_CF_ALL_CONDITIONAL); + assertThat(controlStrings).containsExactly("#004", "#002"); + + // Test control strings of CLIP + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_CLIP); + assertThat(controlStrings).containsExactly("*#30"); + + // Test control strings of CLIR + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_CLIR); + assertThat(controlStrings).containsExactly("*#31"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_ACTIVATION, + SsData.ServiceType.SS_CLIR); + assertThat(controlStrings).containsExactly("*31"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_CLIR); + assertThat(controlStrings).containsExactly("#31"); + + // Test control strings of Call Waiting + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_WAIT); + assertThat(controlStrings).containsExactly("*#43"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_ACTIVATION, + SsData.ServiceType.SS_WAIT); + assertThat(controlStrings).containsExactly("*43"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_WAIT); + assertThat(controlStrings).containsExactly("#43"); + + // Test control strings of BAOC + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_BAOC); + assertThat(controlStrings).containsExactly("*#33", "*#330", "*#333"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_ACTIVATION, + SsData.ServiceType.SS_BAOC); + assertThat(controlStrings).containsExactly("*33", "*330", "*333"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_BAOC); + assertThat(controlStrings).containsExactly("#33", "#330", "#333"); + + // Test control strings of BAOIC + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_BAOIC); + assertThat(controlStrings).containsExactly("*#331", "*#330", "*#333"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_ACTIVATION, + SsData.ServiceType.SS_BAOIC); + assertThat(controlStrings).containsExactly("*331", "*330", "*333"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_BAOIC); + assertThat(controlStrings).containsExactly("#331", "#330", "#333"); + + // Test control strings of BAOICxH + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_BAOIC_EXC_HOME); + assertThat(controlStrings).containsExactly("*#332", "*#330", "*#333"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_ACTIVATION, + SsData.ServiceType.SS_BAOIC_EXC_HOME); + assertThat(controlStrings).containsExactly("*332", "*330", "*333"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_BAOIC_EXC_HOME); + assertThat(controlStrings).containsExactly("#332", "#330", "#333"); + + // Test control strings of BAIC + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_BAIC); + assertThat(controlStrings).containsExactly("*#35", "*#330", "*#353"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_ACTIVATION, + SsData.ServiceType.SS_BAIC); + assertThat(controlStrings).containsExactly("*35", "*330", "*353"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_BAIC); + assertThat(controlStrings).containsExactly("#35", "#330", "#353"); + + // Test control strings of BAICr + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_BAIC_ROAMING); + assertThat(controlStrings).containsExactly("*#351", "*#330", "*#353"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_ACTIVATION, + SsData.ServiceType.SS_BAIC_ROAMING); + assertThat(controlStrings).containsExactly("*351", "*330", "*353"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_BAIC_ROAMING); + assertThat(controlStrings).containsExactly("#351", "#330", "#353"); + + // Test control strings of BA_ALL + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_ALL_BARRING); + assertThat(controlStrings).containsExactly("*#330"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_ACTIVATION, + SsData.ServiceType.SS_ALL_BARRING); + assertThat(controlStrings).containsExactly("*330"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_ALL_BARRING); + assertThat(controlStrings).containsExactly( "#330"); + + // Test control strings of BA_MO + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_OUTGOING_BARRING); + assertThat(controlStrings).containsExactly("*#333", "*#330"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_ACTIVATION, + SsData.ServiceType.SS_OUTGOING_BARRING); + assertThat(controlStrings).containsExactly("*333", "*330"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_OUTGOING_BARRING); + assertThat(controlStrings).containsExactly( "#333", "#330"); + + // Test control strings of BA_MT + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_INTERROGATION, + SsData.ServiceType.SS_INCOMING_BARRING); + assertThat(controlStrings).containsExactly("*#353", "*#330"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_ACTIVATION, + SsData.ServiceType.SS_INCOMING_BARRING); + assertThat(controlStrings).containsExactly("*353", "*330"); + controlStrings = GsmMmiCode.getControlStrings(SsData.RequestType.SS_DEACTIVATION, + SsData.ServiceType.SS_INCOMING_BARRING); + assertThat(controlStrings).containsExactly( "#353", "#330"); + } + + @Test + public void testGetControlStringsForPwd() { + // Test if controlStrings list is empty when inputs are null + ArrayList controlStrings = GsmMmiCode.getControlStringsForPwd(null, + null); + assertThat(controlStrings).isEmpty(); + + // Test control strings of Call Barring Change Password + controlStrings = GsmMmiCode.getControlStringsForPwd( + SsData.RequestType.SS_REGISTRATION, SsData.ServiceType.SS_ALL_BARRING); + assertThat(controlStrings).containsExactly("**03*330"); + } + private void setCarrierSupportsCallerIdVerticalServiceCodesCarrierConfig() { final PersistableBundle bundle = new PersistableBundle(); bundle.putBoolean(CarrierConfigManager -- GitLab From 86187e3001de5b953a24a8ec5963b78c22218959 Mon Sep 17 00:00:00 2001 From: Ramya Manoharan Date: Mon, 16 May 2022 14:44:42 +0000 Subject: [PATCH 023/656] TP - Message reference for SMS SUBMIT type Addition of the TP - Message reference in pdu for SMS-SUBMIT type Test: Build Bug: 228299168 Change-Id: I421db7ca022977ed5d76ce6f7cf0fb36b53482bb --- .../internal/telephony/ImsSmsDispatcher.java | 15 +++ .../internal/telephony/SMSDispatcher.java | 8 ++ .../telephony/cdma/CdmaSMSDispatcher.java | 15 +++ .../telephony/gsm/GsmSMSDispatcher.java | 15 +++ .../telephony/util/SMSDispatcherUtil.java | 108 +++++++++++++++++- 5 files changed, 157 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java index a9eac5797b..cdd55c5350 100644 --- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java +++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java @@ -414,6 +414,21 @@ public class ImsSmsDispatcher extends SMSDispatcher { statusReportRequested); } + @Override + protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, + String message, boolean statusReportRequested, SmsHeader smsHeader, int priority, + int validityPeriod, int messageRef) { + return SMSDispatcherUtil.getSubmitPdu(isCdmaMo(), scAddr, destAddr, message, + statusReportRequested, smsHeader, priority, validityPeriod, messageRef); + } + + @Override + protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, + int destPort, byte[] message, boolean statusReportRequested, int messageRef) { + return SMSDispatcherUtil.getSubmitPdu(isCdmaMo(), scAddr, destAddr, destPort, message, + statusReportRequested, messageRef); + } + @Override protected TextEncodingDetails calculateLength(CharSequence messageBody, boolean use7bitOnly) { return SMSDispatcherUtil.calculateLength(isCdmaMo(), messageBody, use7bitOnly); diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index b6bc9e0836..a1616939da 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -1314,6 +1314,14 @@ public abstract class SMSDispatcher extends Handler { protected abstract SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, int destPort, byte[] message, boolean statusReportRequested); + protected abstract SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, + String message, boolean statusReportRequested, SmsHeader smsHeader, + int priority, int validityPeriod, int messageRef); + + + protected abstract SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, + int destPort, byte[] message, boolean statusReportRequested, int messageRef); + /** * Calculate the number of septets needed to encode the message. This function should only be * called for individual segments of multipart message. diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index 5a830a88ae..ebc634258b 100644 --- a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -92,6 +92,21 @@ public class CdmaSMSDispatcher extends SMSDispatcher { statusReportRequested); } + @Override + protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, + String message, boolean statusReportRequested, SmsHeader smsHeader, int priority, + int validityPeriod, int messageRef) { + return SMSDispatcherUtil.getSubmitPduCdma(scAddr, destAddr, message, + statusReportRequested, smsHeader, priority); + } + + @Override + protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, + int destPort, byte[] message, boolean statusReportRequested, int messageRef) { + return SMSDispatcherUtil.getSubmitPduCdma(scAddr, destAddr, destPort, message, + statusReportRequested); + } + @Override protected TextEncodingDetails calculateLength(CharSequence messageBody, boolean use7bitOnly) { return SMSDispatcherUtil.calculateLengthCdma(messageBody, use7bitOnly); diff --git a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java index 1f237b2300..5b1f36d961 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java +++ b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -119,6 +119,21 @@ public final class GsmSMSDispatcher extends SMSDispatcher { statusReportRequested); } + @Override + protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, + String message, boolean statusReportRequested, SmsHeader smsHeader, int priority, + int validityPeriod, int messageRef) { + return SMSDispatcherUtil.getSubmitPduGsm(scAddr, destAddr, message, statusReportRequested, + validityPeriod, messageRef); + } + + @Override + protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr, + int destPort, byte[] message, boolean statusReportRequested, int messageRef) { + return SMSDispatcherUtil.getSubmitPduGsm(scAddr, destAddr, destPort, message, + statusReportRequested, messageRef); + } + @Override protected TextEncodingDetails calculateLength(CharSequence messageBody, boolean use7bitOnly) { return SMSDispatcherUtil.calculateLengthGsm(messageBody, use7bitOnly); diff --git a/src/java/com/android/internal/telephony/util/SMSDispatcherUtil.java b/src/java/com/android/internal/telephony/util/SMSDispatcherUtil.java index 17f26115f3..da429b7365 100644 --- a/src/java/com/android/internal/telephony/util/SMSDispatcherUtil.java +++ b/src/java/com/android/internal/telephony/util/SMSDispatcherUtil.java @@ -16,12 +16,11 @@ package com.android.internal.telephony.util; -import com.android.internal.telephony.ImsSmsDispatcher; -import com.android.internal.telephony.cdma.CdmaSMSDispatcher; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.ImsSmsDispatcher; import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.cdma.CdmaSMSDispatcher; import com.android.internal.telephony.gsm.GsmSMSDispatcher; /** @@ -94,6 +93,46 @@ public final class SMSDispatcherUtil { } } + /** + * Trigger the proper implementation for getting submit pdu for text sms based on format. + * + * @param isCdma true if cdma format should be used. + * @param scAddr is the service center address or null to use the current default SMSC + * @param destAddr the address to send the message to + * @param message the body of the message. + * @param statusReportRequested whether or not a status report is requested. + * @param smsHeader message header. + * @param priority Priority level of the message + * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 + * --------------------------------- + * PRIORITY | Level of Priority + * --------------------------------- + * '00' | Normal + * '01' | Interactive + * '10' | Urgent + * '11' | Emergency + * ---------------------------------- + * Any Other values included Negative considered as Invalid Priority Indicator of the message. + * @param validityPeriod Validity Period of the message in mins. + * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. + * Validity Period(Minimum) -> 5 mins + * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). + * Any Other values included Negative considered as Invalid Validity Period of the message. + * @param messageRef TP Message Reference number + * @return the submit pdu. + */ + public static SmsMessageBase.SubmitPduBase getSubmitPdu(boolean isCdma, String scAddr, + String destAddr, String message, boolean statusReportRequested, SmsHeader smsHeader, + int priority, int validityPeriod, int messageRef) { + if (isCdma) { + return getSubmitPduCdma(scAddr, destAddr, message, statusReportRequested, smsHeader, + priority); + } else { + return getSubmitPduGsm(scAddr, destAddr, message, statusReportRequested, + validityPeriod, messageRef); + } + } + /** * Gsm implementation for * {@link #getSubmitPdu(boolean, String, String, String, boolean)} @@ -131,6 +170,28 @@ public final class SMSDispatcherUtil { statusReportRequested, validityPeriod); } + /** + * Gsm implementation for + * {@link #getSubmitPdu(boolean, String, String, String, boolean, int)} + * + * @param scAddr is the service center address or null to use the current default SMSC + * @param destAddr the address to send the message to + * @param message the body of the message. + * @param statusReportRequested whether or not a status report is requested. + * @param validityPeriod Validity Period of the message in mins. + * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. + * Validity Period(Minimum) -> 5 mins + * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). + * Any Other values included Negative considered as Invalid Validity Period of the message. + * @param messageRef TP Message Reference number + * @return the submit pdu. + */ + public static SmsMessageBase.SubmitPduBase getSubmitPduGsm(String scAddr, String destAddr, + String message, boolean statusReportRequested, int validityPeriod, int messageRef) { + return com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddr, destAddr, message, + statusReportRequested, null, 0, 0, 0, validityPeriod, messageRef); + } + /** * Cdma implementation for * {@link #getSubmitPdu(boolean, String, String, String, boolean, SmsHeader)} @@ -196,6 +257,29 @@ public final class SMSDispatcherUtil { } } + /** + * Trigger the proper implementation for getting submit pdu for data sms based on format. + * + * @param isCdma true if cdma format should be used. + * @param destAddr the address to send the message to + * @param scAddr is the service center address or null to use the current default SMSC + * @param destPort the port to deliver the message to + * @param message the body of the message to send + * @param statusReportRequested whether or not a status report is requested. + * @param messageRef TP Message Reference number + * @return the submit pdu. + */ + public static SmsMessageBase.SubmitPduBase getSubmitPdu(boolean isCdma, String scAddr, + String destAddr, int destPort, byte[] message, boolean statusReportRequested, + int messageRef) { + if (isCdma) { + return getSubmitPduCdma(scAddr, destAddr, destPort, message, statusReportRequested); + } else { + return getSubmitPduGsm(scAddr, destAddr, destPort, message, statusReportRequested, + messageRef); + } + } + /** * Cdma implementation of {@link #getSubmitPdu(boolean, String, String, int, byte[], boolean)} @@ -229,6 +313,22 @@ public final class SMSDispatcherUtil { } + /** + * Gsm implementation of {@link #getSubmitPdu(boolean, String, String, int, byte[], boolean)} + * + * @param destAddr the address to send the message to + * @param scAddr is the service center address or null to use the current default SMSC + * @param destPort the port to deliver the message to + * @param message the body of the message to send + * @param statusReportRequested whether or not a status report is requested. + * @return the submit pdu. + */ + public static SmsMessageBase.SubmitPduBase getSubmitPduGsm(String scAddr, String destAddr, + int destPort, byte[] message, boolean statusReportRequested, int messageRef) { + return com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddr, destAddr, + destPort, message, statusReportRequested, messageRef); + } + /** * Calculate the number of septets needed to encode the message. This function should only be * called for individual segments of multipart message. -- GitLab From 100351d4f451343aa69e2465c2baaf6130fc95af Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Tue, 10 May 2022 11:02:45 -0700 Subject: [PATCH 024/656] change logic for determining emergency number shortnumber xml will be the last resort in case there are no SIMs (i.e. we have a list from atleast one sub) Bug: 230284078 Change-Id: Ib0979f58c5e20f1f1edf6eba65db91e1818ab5af --- .../emergency/EmergencyNumberTracker.java | 127 ++++++++++-------- tests/telephonytests/Android.bp | 1 + .../emergency/EmergencyNumberTrackerTest.java | 95 +++++++++++++ 3 files changed, 166 insertions(+), 57 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 4645d9ade7..276d82a527 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -272,7 +272,8 @@ public class EmergencyNumberTracker extends Handler { int slotId = SubscriptionController.getInstance().getSlotIndex(phone.getSubId()); // If slot id is invalid, it means that there is no sim card. if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - // If there is at least one sim active, sim is not absent; it returns false. + // If there is at least one sim active, sim is not absent; it returns false + logd("found sim in slotId: " + slotId + " subid: " + phone.getSubId()); return false; } } @@ -737,18 +738,25 @@ public class EmergencyNumberTracker extends Handler { } if (exactMatch) { if (num.getNumber().equals(number)) { + logd("Found in mEmergencyNumberList [exact match] "); return true; } } else { if (number.startsWith(num.getNumber())) { + logd("Found in mEmergencyNumberList [not exact match] "); return true; } } } return false; } else { - return isEmergencyNumberFromEccList(number, exactMatch) - || isEmergencyNumberFromDatabase(number) || isEmergencyNumberForTest(number); + boolean inEccList = isEmergencyNumberFromEccList(number, exactMatch); + boolean inEmergencyNumberDb = isEmergencyNumberFromDatabase(number); + boolean inEmergencyNumberTestList = isEmergencyNumberForTest(number); + logd("Search results - inRilEccList:" + inEccList + + " inEmergencyNumberDb:" + inEmergencyNumberDb + " inEmergencyNumberTestList: " + + inEmergencyNumberTestList); + return inEccList || inEmergencyNumberDb || inEmergencyNumberTestList; } } @@ -970,53 +978,56 @@ public class EmergencyNumberTracker extends Handler { String emergencyNumbers = ""; int slotId = SubscriptionController.getInstance().getSlotIndex(mPhone.getSubId()); - // retrieve the list of emergency numbers - // check read-write ecclist property first - String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); + String ecclist = null; + String countryIso = getLastKnownEmergencyCountryIso(); - emergencyNumbers = SystemProperties.get(ecclist, ""); + if (!mPhone.getHalVersion().greaterOrEqual(new HalVersion(1, 4))) { + //only use ril ecc list for older devices with HAL < 1.4 + // check read-write ecclist property first + ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); + emergencyNumbers = SystemProperties.get(ecclist, ""); - String countryIso = getLastKnownEmergencyCountryIso(); - logd("slotId:" + slotId + " country:" + countryIso + " emergencyNumbers: " - + emergencyNumbers); + logd("slotId:" + slotId + " country:" + countryIso + " emergencyNumbers: " + + emergencyNumbers); - if (TextUtils.isEmpty(emergencyNumbers)) { - // then read-only ecclist property since old RIL only uses this - emergencyNumbers = SystemProperties.get("ro.ril.ecclist"); - } + if (TextUtils.isEmpty(emergencyNumbers)) { + // then read-only ecclist property since old RIL only uses this + emergencyNumbers = SystemProperties.get("ro.ril.ecclist"); + } - if (!TextUtils.isEmpty(emergencyNumbers)) { - // searches through the comma-separated list for a match, - // return true if one is found. - for (String emergencyNum : emergencyNumbers.split(",")) { - // According to com.android.i18n.phonenumbers.ShortNumberInfo, in - // these countries, if extra digits are added to an emergency number, - // it no longer connects to the emergency service. - if (useExactMatch || countryIso.equals("br") || countryIso.equals("cl") + if (!TextUtils.isEmpty(emergencyNumbers)) { + // searches through the comma-separated list for a match, + // return true if one is found. + for (String emergencyNum : emergencyNumbers.split(",")) { + // According to com.android.i18n.phonenumbers.ShortNumberInfo, in + // these countries, if extra digits are added to an emergency number, + // it no longer connects to the emergency service. + if (useExactMatch || countryIso.equals("br") || countryIso.equals("cl") || countryIso.equals("ni")) { - if (number.equals(emergencyNum)) { - return true; - } else { - for (String prefix : mEmergencyNumberPrefix) { - if (number.equals(prefix + emergencyNum)) { - return true; + if (number.equals(emergencyNum)) { + return true; + } else { + for (String prefix : mEmergencyNumberPrefix) { + if (number.equals(prefix + emergencyNum)) { + return true; + } } } - } - } else { - if (number.startsWith(emergencyNum)) { - return true; } else { - for (String prefix : mEmergencyNumberPrefix) { - if (number.startsWith(prefix + emergencyNum)) { - return true; + if (number.startsWith(emergencyNum)) { + return true; + } else { + for (String prefix : mEmergencyNumberPrefix) { + if (number.startsWith(prefix + emergencyNum)) { + return true; + } } } } } + // no matches found against the list! + return false; } - // no matches found against the list! - return false; } logd("System property doesn't provide any emergency numbers." @@ -1050,32 +1061,34 @@ public class EmergencyNumberTracker extends Handler { } } - // No ecclist system property, so use our own list. - if (countryIso != null) { - ShortNumberInfo info = ShortNumberInfo.getInstance(); - if (useExactMatch) { - if (info.isEmergencyNumber(number, countryIso.toUpperCase())) { - return true; - } else { - for (String prefix : mEmergencyNumberPrefix) { - if (info.isEmergencyNumber(prefix + number, countryIso.toUpperCase())) { - return true; + if(isSimAbsent()) { + // No ecclist system property, so use our own list. + if (countryIso != null) { + ShortNumberInfo info = ShortNumberInfo.getInstance(); + if (useExactMatch) { + if (info.isEmergencyNumber(number, countryIso.toUpperCase())) { + return true; + } else { + for (String prefix : mEmergencyNumberPrefix) { + if (info.isEmergencyNumber(prefix + number, countryIso.toUpperCase())) { + return true; + } } } - } - return false; - } else { - if (info.connectsToEmergencyNumber(number, countryIso.toUpperCase())) { - return true; + return false; } else { - for (String prefix : mEmergencyNumberPrefix) { - if (info.connectsToEmergencyNumber(prefix + number, - countryIso.toUpperCase())) { - return true; + if (info.connectsToEmergencyNumber(number, countryIso.toUpperCase())) { + return true; + } else { + for (String prefix : mEmergencyNumberPrefix) { + if (info.connectsToEmergencyNumber(prefix + number, + countryIso.toUpperCase())) { + return true; + } } } + return false; } - return false; } } diff --git a/tests/telephonytests/Android.bp b/tests/telephonytests/Android.bp index c1fe0e60cc..f197101486 100644 --- a/tests/telephonytests/Android.bp +++ b/tests/telephonytests/Android.bp @@ -32,6 +32,7 @@ android_test { "androidx.test.rules", "frameworks-base-testutils", "guava", + "libphonenumber-nogeocoder", "mockito-target-minus-junit4", "net-tests-utils", "platform-test-annotations", diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index a08652d9b8..39ff133320 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -19,9 +19,12 @@ package com.android.internal.telephony.emergency; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import android.os.AsyncResult; import android.os.Environment; @@ -39,6 +42,8 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyTest; +import com.google.i18n.phonenumbers.ShortNumberInfo; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -70,6 +75,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private static final String CONFIG_EMERGENCY_NUMBER_ADDRESS = "54321"; private static final String CONFIG_EMERGENCY_NUMBER_COUNTRY = "us"; private static final String CONFIG_EMERGENCY_NUMBER_MNC = ""; + private static final String NON_3GPP_EMERGENCY_TEST_NUMBER = "9876543"; private static final int CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES = EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE | EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE @@ -108,11 +114,13 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private String[] mEmergencyNumberPrefixTestSample = {"123", "456"}; private File mLocalDownloadDirectory; + private ShortNumberInfo mShortNumberInfo; @Before public void setUp() throws Exception { logd("EmergencyNumberTrackerTest +Setup!"); super.setUp(getClass().getSimpleName()); + mShortNumberInfo = mock(ShortNumberInfo.class); mSubControllerMock = mock(SubscriptionController.class); mPhone2 = mock(Phone.class); mContext = InstrumentationRegistry.getTargetContext(); @@ -184,6 +192,15 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { processAllMessages(); } + private void sendEmptyEmergencyNumberListFromRadio( + EmergencyNumberTracker emergencyNumberTrackerMock) { + emergencyNumberTrackerMock.sendMessage( + emergencyNumberTrackerMock.obtainMessage( + 1 /* EVENT_UNSOL_EMERGENCY_NUMBER_LIST */, + new AsyncResult(null, new ArrayList<>(), null))); + processAllMessages(); + } + private void cacheEmergencyNumberListFromDatabaseByCountry(String countryIso) { mEmergencyNumberTrackerMock.updateEmergencyNumberDatabaseCountryChange(countryIso); processAllMessages(); @@ -348,6 +365,84 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { assertTrue(mEmergencyNumberTrackerMock2.getLastKnownEmergencyCountryIso().equals("jp")); } + @Test + public void testIsEmergencyNumber_FallbackToShortNumberXml_NoSims() throws Exception { + // Set up the Hal version as 1.4 + doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(); + doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(); + + setDsdsPhones(); + replaceInstance(SubscriptionController.class, "sInstance", null, mSubControllerMock); + + // Both sim slots are not active + doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( + eq(SUB_ID_PHONE_1)); + doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( + eq(SUB_ID_PHONE_2)); + assertTrue(mEmergencyNumberTrackerMock.isSimAbsent()); + + sendEmptyEmergencyNumberListFromRadio(mEmergencyNumberTrackerMock); + sendEmptyEmergencyNumberListFromRadio(mEmergencyNumberTrackerMock2); + + mEmergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("JP"); + processAllMessages(); + + replaceInstance(ShortNumberInfo.class, "INSTANCE", null, mShortNumberInfo); + mEmergencyNumberTrackerMock.isEmergencyNumber(NON_3GPP_EMERGENCY_TEST_NUMBER, true); + + //verify that we fall back to shortnumber xml when there are no SIMs + verify(mShortNumberInfo).isEmergencyNumber(NON_3GPP_EMERGENCY_TEST_NUMBER, "JP"); + } + + @Test + public void testIsEmergencyNumber_NoFallbackToShortNumberXml_OneSimActive() throws Exception { + testIsEmergencyNumber_NoFallbackToShortNumberXml(1); + } + + @Test + public void testIsEmergencyNumber_NoFallbackToShortNumberXml_TwoSimsActive() throws Exception { + testIsEmergencyNumber_NoFallbackToShortNumberXml(2); + } + + private void testIsEmergencyNumber_NoFallbackToShortNumberXml(int numSims) throws Exception { + // Set up the Hal version as 1.4 + doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(); + doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(); + + assertTrue((numSims > 0 && numSims < 3)); + setDsdsPhones(); + replaceInstance(SubscriptionController.class, "sInstance", null, mSubControllerMock); + + if (numSims == 1) { + // One sim slot is active; the other one is not active + doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubControllerMock).getSlotIndex( + eq(SUB_ID_PHONE_1)); + doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( + eq(SUB_ID_PHONE_2)); + } else { + //both slots active + doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubControllerMock).getSlotIndex( + eq(SUB_ID_PHONE_1)); + doReturn(VALID_SLOT_INDEX_VALID_2).when(mSubControllerMock).getSlotIndex( + eq(SUB_ID_PHONE_2)); + } + assertFalse(mEmergencyNumberTrackerMock.isSimAbsent()); + + //still send empty list from modem for both sims, else we always end up using that + sendEmptyEmergencyNumberListFromRadio(mEmergencyNumberTrackerMock); + sendEmptyEmergencyNumberListFromRadio(mEmergencyNumberTrackerMock2); + + mEmergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("JP"); + processAllMessages(); + + replaceInstance(ShortNumberInfo.class, "INSTANCE", null, mShortNumberInfo); + mEmergencyNumberTrackerMock.isEmergencyNumber(NON_3GPP_EMERGENCY_TEST_NUMBER, true); + + //verify we do not use ShortNumber xml + verify(mShortNumberInfo, never()).isEmergencyNumber(anyString(), anyString()); + + } + @Test public void testUpdateEmergencyCountryIsoFromAnotherSimOrNot() throws Exception { setDsdsPhones(); -- GitLab From c1fe8a1253333f0542ac6357e7e25d7a3579a8bf Mon Sep 17 00:00:00 2001 From: Rafael Higuera Silva Date: Wed, 25 May 2022 19:07:11 +0000 Subject: [PATCH 025/656] Add NR bands to service state. Bug: 231523547 Test: make Change-Id: I493e574e588da17dc8cd26e3cc04498775cbaeff --- .../android/internal/telephony/metrics/ServiceStateStats.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java index 6698e5b4ed..59937504ce 100644 --- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java +++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java @@ -187,6 +187,9 @@ public class ServiceStateStats { case TelephonyManager.NETWORK_TYPE_LTE_CA: band = AccessNetworkUtils.getOperatingBandForEarfcn(chNumber); break; + case TelephonyManager.NETWORK_TYPE_NR: + band = AccessNetworkUtils.getOperatingBandForNrarfcn(chNumber); + break; default: Rlog.w(TAG, "getBand: unknown WWAN RAT " + rat); band = 0; -- GitLab From 1db4d12a249f901d7f96ce7228bc052721c670b5 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Mon, 18 Apr 2022 10:19:12 +0000 Subject: [PATCH 026/656] Fetches smsc value from the EF_PSISMSC elementary file of the sim Bug: 229066443 Test: aTest verification completed Change-Id: I5e3cd32022803982b15cb06d79549bbdf809415d --- .../internal/telephony/uicc/IccConstants.java | 2 +- .../telephony/uicc/IccFileHandler.java | 2 +- .../internal/telephony/uicc/IccRecords.java | 36 ++++++++++ .../telephony/uicc/IsimUiccRecords.java | 35 +++++++++- .../internal/telephony/uicc/SIMRecords.java | 24 ++++++- .../telephony/uicc/IsimUiccRecordsTest.java | 68 +++++++++++++++++++ .../telephony/uicc/SIMRecordsTest.java | 68 +++++++++++++++++++ 7 files changed, 229 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/IccConstants.java b/src/java/com/android/internal/telephony/uicc/IccConstants.java index 5eae070eb4..5349f3999f 100644 --- a/src/java/com/android/internal/telephony/uicc/IccConstants.java +++ b/src/java/com/android/internal/telephony/uicc/IccConstants.java @@ -45,6 +45,7 @@ public interface IccConstants { static final int EF_SST = 0x6F38; static final int EF_CFIS = 0x6FCB; static final int EF_IMG = 0x4F20; + static final int EF_PSISMSC = 0x6FE5; // USIM SIM file ids from TS 131.102 public static final int EF_PBR = 0x4F30; @@ -84,7 +85,6 @@ public interface IccConstants { static final int EF_DOMAIN = 0x6F03; static final int EF_IST = 0x6F07; static final int EF_PCSCF = 0x6F09; - static final int EF_PSI = 0x6FE5; //PLMN Selection Information w/ Access Technology TS 131.102 static final int EF_PLMN_W_ACT = 0x6F60; diff --git a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java index f3b1d0bbf7..6c4ac699b1 100644 --- a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java @@ -693,7 +693,7 @@ public abstract class IccFileHandler extends Handler implements IccConstants { case EF_EXT1: case EF_EXT2: case EF_EXT3: - case EF_PSI: + case EF_PSISMSC: return MF_SIM + DF_TELECOM; case EF_ICCID: diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java index 3a7db7fa7e..a35bb6bb1e 100644 --- a/src/java/com/android/internal/telephony/uicc/IccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java @@ -35,6 +35,7 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.MccTable; +import com.android.internal.telephony.gsm.SimTlv; import com.android.internal.telephony.util.ArrayUtils; import com.android.telephony.Rlog; @@ -43,6 +44,7 @@ import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.nio.charset.Charset; import java.util.Arrays; import java.util.HashMap; import java.util.Objects; @@ -173,6 +175,10 @@ public abstract class IccRecords extends Handler implements IccConstants { protected String[] mEhplmns; protected String[] mFplmns; + // SIP or TEL URI [ Public Service Identity of the SM-SC] + // Reference: TS 31.102 section 4.5.9 + protected String mPsiSmsc; + CarrierTestOverride mCarrierTestOverride; //Arbitrary offset for the Handler @@ -232,6 +238,8 @@ public abstract class IccRecords extends Handler implements IccConstants { // arrive and returning null to the callers. private static final long ICC_SIM_CHALLENGE_TIMEOUT_MILLIS = 2500; + // TAG value to retrieve EF_PSISMSC from parsed SimTlv object + private static final int TAG_TLV_USIM_VALUE_80 = 0x80; /** * There are two purposes for this class. First, each instance of AuthAsyncResponse acts as a * lock to for calling thead to wait in getIccSimChallengeResponse(). Second, pass the IMS @@ -1306,6 +1314,34 @@ public abstract class IccRecords extends Handler implements IccConstants { return mSmsCountOnIcc; } + /** + * parse EF PSISMSC value [3GPP TS 31.102 Section 4.5.9] + * + * @param data read from EF PSISMSC field of type byte[] + * @return SIP URI or tel URI of type string + */ + protected String parseEfPsiSmsc(byte[] data) { + SimTlv tlv = new SimTlv(data, 0, data.length); + if (tlv.isValidObject() && tlv.getData() != null) { + if (tlv.getTag() == TAG_TLV_USIM_VALUE_80) { + return new String(tlv.getData(), Charset.forName("UTF-8")); + } + } + if (VDBG) { + log("Can't find EF PSISMSC field in SIM = " + IccUtils.bytesToHexString(data)); + } + return null; + } + + /** + * SMSC address read from the elementary file EF_PSISMSC + * + * @return SIP URI or tel URI of type string + */ + public String getSmscIdentity() { + return mPsiSmsc; + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("IccRecords: " + this); pw.println(" mDestroyed=" + mDestroyed); diff --git a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java index 1fe62232d9..1919f69f47 100644 --- a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java @@ -24,6 +24,7 @@ import android.os.Build; import android.os.Message; import android.telephony.SubscriptionManager; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.gsm.SimTlv; import com.android.telephony.Rlog; @@ -69,7 +70,8 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { + " mIsimDomain=" + mIsimDomain + " mIsimImpu=" + mIsimImpu + " mIsimIst=" + mIsimIst - + " mIsimPcscf=" + mIsimPcscf) : ""); + + " mIsimPcscf=" + mIsimPcscf + + " mPsiSmsc=" + mPsiSmsc) : ""); } public IsimUiccRecords(UiccCardApplication app, Context c, CommandsInterface ci) { @@ -144,6 +146,10 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimPcscfLoaded())); mRecordsToLoad++; + mFh.loadEFLinearFixed(EF_PSISMSC, 1, obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimPsiSmscLoaded())); + mRecordsToLoad++; + if (DBG) log("fetchIsimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested); } @@ -229,6 +235,29 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { } } + private class EfIsimPsiSmscLoaded implements IccRecords.IccRecordLoaded { + + @Override + public String getEfName() { + return "EF_ISIM_PSISMSC"; + } + + @Override + public void onRecordLoaded(AsyncResult ar) { + byte[] data = (byte[]) ar.result; + if (data != null && data.length > 0) { + mPsiSmsc = parseEfPsiSmsc(data); + if (VDBG) { + log("IsimUiccRecords - EF_PSISMSC value = " + mPsiSmsc); + } + } + } + } + + @VisibleForTesting + public EfIsimPsiSmscLoaded getPsiSmscObject() { + return new EfIsimPsiSmscLoaded(); + } /** * ISIM records for IMS are stored inside a Tag-Length-Value record as a UTF-8 string * with tag value 0x80. @@ -438,6 +467,7 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { pw.println(" mIsimImpu[]=" + Arrays.toString(mIsimImpu)); pw.println(" mIsimIst" + mIsimIst); pw.println(" mIsimPcscf" + mIsimPcscf); + pw.println(" mPsismsc=" + mPsiSmsc); } pw.flush(); } @@ -446,5 +476,4 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { public int getVoiceMessageCount() { return 0; // Not applicable to Isim } - -} +} \ No newline at end of file diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index 9958bfb7a6..59629c372c 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -108,7 +108,8 @@ public class SIMRecords extends IccRecords { + " efCPHS_MWI=" + mEfCPHS_MWI + " mEfCff=" + mEfCff + " mEfCfis=" + mEfCfis - + " getOperatorNumeric=" + getOperatorNumeric(); + + " getOperatorNumeric=" + getOperatorNumeric() + + " mPsiSmsc=" + mPsiSmsc; } // ***** Constants @@ -184,6 +185,7 @@ public class SIMRecords extends IccRecords { private static final int EVENT_GET_FPLMN_DONE = 41 + SIM_RECORD_EVENT_BASE; private static final int EVENT_GET_FPLMN_SIZE_DONE = 42 + SIM_RECORD_EVENT_BASE; private static final int EVENT_SET_FPLMN_DONE = 43 + SIM_RECORD_EVENT_BASE; + protected static final int EVENT_GET_PSISMSC_DONE = 47 + SIM_RECORD_EVENT_BASE; // ***** Constructor public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) { @@ -1291,6 +1293,22 @@ public class SIMRecords extends IccRecords { } break; + case EVENT_GET_PSISMSC_DONE: + isRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + loge("Failed to read USIM EF_SMSS field error=" + ar.exception); + } else { + data = (byte[]) ar.result; + if (data != null && data.length > 0) { + mPsiSmsc = parseEfPsiSmsc(data); + if (VDBG) { + log("SIMRecords - EF_PSISMSC value = " + mPsiSmsc); + } + } + } + break; + default: super.handleMessage(msg); // IccRecords handles generic record load responses } @@ -1680,6 +1698,9 @@ public class SIMRecords extends IccRecords { mFh.getEFLinearRecordSize(EF_SMS, obtainMessage(EVENT_GET_SMS_RECORD_SIZE_DONE)); mRecordsToLoad++; + mFh.loadEFLinearFixed(EF_PSISMSC, 1, obtainMessage(EVENT_GET_PSISMSC_DONE)); + mRecordsToLoad++; + // XXX should seek instead of examining them all if (false) { // XXX mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE)); @@ -2144,6 +2165,7 @@ public class SIMRecords extends IccRecords { pw.println(" mHplmnActRecords[]=" + Arrays.toString(mHplmnActRecords)); pw.println(" mFplmns[]=" + Arrays.toString(mFplmns)); pw.println(" mEhplmns[]=" + Arrays.toString(mEhplmns)); + pw.println(" mPsismsc=" + mPsiSmsc); pw.flush(); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java index b97ae1f5bc..445a5baaf5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java @@ -30,6 +30,7 @@ package com.android.internal.telephony.uicc; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; import android.content.Intent; @@ -37,6 +38,8 @@ import android.os.AsyncResult; import android.os.HandlerThread; import android.os.Message; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.TelephonyTest; import org.junit.After; @@ -87,4 +90,69 @@ public class IsimUiccRecordsTest extends TelephonyTest { ((Intent) intentCapture.getValue()).getAction(), IsimUiccRecords.INTENT_ISIM_REFRESH); } + @Test + public void testPsiSmscTelValue() { + // Testing smsc successfully reading case + String smscTest = "tel:+13123149810"; + String hexSmsc = + "801074656C3A2B3133313233313439383130FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + byte[] smscBytes = getStringToByte(hexSmsc); + Message message = mIsimUiccRecords.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecords.getPsiSmscObject()); + AsyncResult ar = AsyncResult.forMessage(message, smscBytes, null); + mIsimUiccRecords.handleMessage(message); + assertEquals(smscTest, mIsimUiccRecords.getSmscIdentity()); + } + + private byte[] getStringToByte(String hexSmsc) { + byte[] smscBytes = IccUtils.hexStringToBytes(hexSmsc); + return smscBytes; + } + + @Test + public void testGetPsiSmscSipValue() { + // Testing smsc successfully reading case + String smscTest = "sip:+12063130004@msg.pc.t-mobile.com;user=phone"; + byte[] smscBytes = getStringToByte( + "802F7369703A2B3132303633313330303034406D73672E70632E742D6D6F62696C6" + + "52E636F6D3B757365723D70686F6E65FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + Message message = mIsimUiccRecords.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecords.getPsiSmscObject()); + AsyncResult ar = AsyncResult.forMessage(message, smscBytes, null); + mIsimUiccRecords.handleMessage(message); + assertEquals(smscTest, mIsimUiccRecords.getSmscIdentity()); + } + + @Test + public void testGetPsiSmscValueException() { + // Testing smsc exception handling case + String hexSmsc = + "801074656C3A2B3133313233313439383130FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + byte[] smscBytes = getStringToByte(hexSmsc); + Message message = mIsimUiccRecords.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecords.getPsiSmscObject()); + AsyncResult ar = AsyncResult.forMessage(message, smscBytes, + new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + mIsimUiccRecords.handleMessage(message); + assertEquals(null, mIsimUiccRecords.getSmscIdentity()); + } + + @Test + public void testGetPsiSmscValueInvalidObject() { + // Testing smsc invalid data handling case + String smscTest = "tel:+13123149810"; + byte[] smscBytes = GsmAlphabet.stringToGsm8BitPacked(smscTest); + Message message = mIsimUiccRecords.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecords.getPsiSmscObject()); + AsyncResult ar = AsyncResult.forMessage(message, smscBytes, + new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + mIsimUiccRecords.handleMessage(message); + assertEquals(null, mIsimUiccRecords.getSmscIdentity()); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java index 9183235941..b6b8d9887d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java @@ -408,4 +408,72 @@ public class SIMRecordsTest extends TelephonyTest { return data; } + + @Test + public void testGetPsiSmscTelValue() { + // Testing smsc successfully reading case + String smscTest = "tel:+13123149810"; + String hexSmsc = + "801074656C3A2B3133313233313439383130FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + byte[] smscBytes = getStringToByte(hexSmsc); + Message message = mSIMRecordsUT.obtainMessage( + SIMRecords.EVENT_GET_PSISMSC_DONE, smscBytes); + AsyncResult ar = AsyncResult.forMessage(message, smscBytes, null); + mSIMRecordsUT.handleMessage(message); + assertEquals(smscTest, mSIMRecordsUT.getSmscIdentity()); + } + + private byte[] getStringToByte(String hexSmsc) { + byte[] smscBytes = IccUtils.hexStringToBytes(hexSmsc); + return smscBytes; + } + + @Test + public void testGetPsiSmscSipValue() { + // Testing smsc successfully reading case + String smscTest = "sip:+12063130004@msg.pc.t-mobile.com;user=phone"; + byte[] smscBytes = getStringToByte( + "802F7369703A2B3132303633313330303034406D73672E70632E742D6D6F62696C6" + + "52E636F6D3B757365723D70686F6E65FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + Message message = mSIMRecordsUT.obtainMessage( + SIMRecords.EVENT_GET_PSISMSC_DONE, smscBytes); + AsyncResult ar = AsyncResult.forMessage(message, smscBytes, null); + mSIMRecordsUT.handleMessage(message); + assertEquals(smscTest, mSIMRecordsUT.getSmscIdentity()); + } + + @Test + public void testGetPsiSmscException() { + // Testing smsc exception handling case + String hexSmsc = + "801074656C3A2B3133313233313439383130FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + byte[] smscBytes = getStringToByte(hexSmsc); + Message message = mSIMRecordsUT.obtainMessage( + SIMRecords.EVENT_GET_PSISMSC_DONE, smscBytes); + AsyncResult ar = AsyncResult.forMessage(message, smscBytes, + new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + mSIMRecordsUT.handleMessage(message); + assertTrue(ar.exception instanceof CommandException); + assertEquals(null, mSIMRecordsUT.getSmscIdentity()); + } + + @Test + public void testGetPsiSmscValueInvalidObject() { + // Testing smsc invalid data handling case + String smscTest = "tel:+13123149810"; + byte[] smscBytes = GsmAlphabet.stringToGsm8BitPacked(smscTest); + Message message = mSIMRecordsUT.obtainMessage( + SIMRecords.EVENT_GET_PSISMSC_DONE, smscBytes); + AsyncResult ar = AsyncResult.forMessage(message, smscBytes, + new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + mSIMRecordsUT.handleMessage(message); + assertEquals(null, mSIMRecordsUT.getSmscIdentity()); + assertTrue(ar.exception instanceof CommandException); + } } -- GitLab From 6d520e2c3a34d3beea50b4ca4b1557d12d27ef88 Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Tue, 7 Jun 2022 15:38:39 -0700 Subject: [PATCH 027/656] add phoneId to EmergencyCallTracker logs Change-Id: I293ed3578aeb9a47f975685cde2b02f56cd483a7 Tests: manual log verification Bug: 235278331 --- .../emergency/EmergencyNumberTracker.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 276d82a527..7a25fd56d0 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -95,6 +95,7 @@ public class EmergencyNumberTracker extends Handler { private final CommandsInterface mCi; private final Phone mPhone; + private int mPhoneId; private String mCountryIso; private String mLastKnownEmergencyCountryIso = ""; private int mCurrentDatabaseVersion = INVALID_DATABASE_VERSION; @@ -166,6 +167,7 @@ public class EmergencyNumberTracker extends Handler { mCi = ci; if (mPhone != null) { + mPhoneId = phone.getPhoneId(); CarrierConfigManager configMgr = (CarrierConfigManager) mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); if (configMgr != null) { @@ -1158,16 +1160,16 @@ public class EmergencyNumberTracker extends Handler { return new ArrayList<>(mEmergencyNumberListFromRadio); } - private static void logd(String str) { - Rlog.d(TAG, str); + private void logd(String str) { + Rlog.d(TAG, "[" + mPhoneId + "]" + str); } - private static void logw(String str) { - Rlog.w(TAG, str); + private void logw(String str) { + Rlog.w(TAG, "[" + mPhoneId + "]" + str); } - private static void loge(String str) { - Rlog.e(TAG, str); + private void loge(String str) { + Rlog.e(TAG, "[" + mPhoneId + "]" + str); } private void writeUpdatedEmergencyNumberListMetrics( -- GitLab From 1945b0b9468f67ec296a872cd7b3ad64977b8dfc Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 10 Jun 2022 22:22:11 +0000 Subject: [PATCH 028/656] Use isFileEncrypted() instead of isFileEncryptedNativeOrEmulated() Since emulated FBE is no longer supported, isFileEncryptedNativeOrEmulated() is the same as the new method isFileEncrypted(). Use isFileEncrypted() instead. Bug: 232458753 Change-Id: Icd2c30420044d449b1a50e55c37e5d32936e3a80 --- src/java/com/android/internal/telephony/InboundSmsHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java index 1f0b5425f2..d5b716bb17 100644 --- a/src/java/com/android/internal/telephony/InboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java @@ -1147,7 +1147,7 @@ public abstract class InboundSmsHandler extends StateMachine { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private void showNewMessageNotification() { // Do not show the notification on non-FBE devices. - if (!StorageManager.isFileEncryptedNativeOrEmulated()) { + if (!StorageManager.isFileEncrypted()) { return; } log("Show new message notification."); -- GitLab From 7375175521bfb83da56709794cfb9fa30f22bcfa Mon Sep 17 00:00:00 2001 From: Rafael Higuera Silva Date: Tue, 14 Jun 2022 15:15:43 +0000 Subject: [PATCH 029/656] Revert "Add NR bands to service state." Revert submission 18603176-nrBands Reason for revert: Wrong conversions. Reverted Changes: I25ec415e6:Add NR bands to service state. I493e574e5:Add NR bands to service state. Change-Id: I049d31301418e0bfeeb8e09decce50c02de08a76 --- .../android/internal/telephony/metrics/ServiceStateStats.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java index 59937504ce..6698e5b4ed 100644 --- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java +++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java @@ -187,9 +187,6 @@ public class ServiceStateStats { case TelephonyManager.NETWORK_TYPE_LTE_CA: band = AccessNetworkUtils.getOperatingBandForEarfcn(chNumber); break; - case TelephonyManager.NETWORK_TYPE_NR: - band = AccessNetworkUtils.getOperatingBandForNrarfcn(chNumber); - break; default: Rlog.w(TAG, "getBand: unknown WWAN RAT " + rat); band = 0; -- GitLab From db1b3221592d771c861bf91db121d3083f1c7ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CChrista?= Date: Tue, 14 Jun 2022 18:49:36 +0000 Subject: [PATCH 030/656] Fixed the formatting issue of SmsController on x-message-id. Bug: 232087545 Test: fixing formatting issue. Change-Id: I9c6cb6a33251c238d421c9ae54a00e2fb0668941 --- src/java/com/android/internal/telephony/SmsController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 589a0d75a2..d157246a62 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -240,14 +240,14 @@ public class SmsController extends ISmsImplBase { String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, long messageId) { Rlog.d(LOG_TAG, "sendTextForSubscriber iccSmsIntMgr" - + " Subscription: " + subId + " id: " + messageId); + + " Subscription: " + subId + " " + formatCrossStackMessageId(messageId)); IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendText(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent, persistMessageForNonDefaultSmsApp, messageId); } else { Rlog.e(LOG_TAG, "sendTextForSubscriber iccSmsIntMgr is null for" - + " Subscription: " + subId + " id: " + messageId); + + " Subscription: " + subId + " " + formatCrossStackMessageId(messageId)); sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_GENERIC_FAILURE); } } @@ -318,7 +318,7 @@ public class SmsController extends ISmsImplBase { messageId); } else { Rlog.e(LOG_TAG, "sendMultipartTextForSubscriber iccSmsIntMgr is null for" - + " Subscription: " + subId + " id: " + messageId); + + " Subscription: " + subId + " " + formatCrossStackMessageId(messageId)); sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_GENERIC_FAILURE); } } -- GitLab From 43d6c2de3ed88c488be73be7999aa514e0c601b9 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Wed, 23 Mar 2022 14:56:17 +0000 Subject: [PATCH 031/656] Get and Set the TPMR value to EF_SMSS field in ISIM/USIM Bug: 226337641 Test: Atest verified Change-Id: I7fa09707595877f3edd6619ed875020e4e39f263 --- .../internal/telephony/uicc/IccConstants.java | 1 + .../internal/telephony/uicc/IccRecords.java | 108 +++++- .../telephony/uicc/IsimFileHandler.java | 1 + .../telephony/uicc/IsimUiccRecords.java | 32 +- .../internal/telephony/uicc/SIMRecords.java | 31 +- .../telephony/uicc/UsimFileHandler.java | 1 + .../telephony/uicc/IsimUiccRecordsTest.java | 226 +++++++++--- .../telephony/uicc/SIMRecordsTest.java | 328 ++++++++++++++---- 8 files changed, 611 insertions(+), 117 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/IccConstants.java b/src/java/com/android/internal/telephony/uicc/IccConstants.java index 5349f3999f..a9275bedd0 100644 --- a/src/java/com/android/internal/telephony/uicc/IccConstants.java +++ b/src/java/com/android/internal/telephony/uicc/IccConstants.java @@ -46,6 +46,7 @@ public interface IccConstants { static final int EF_CFIS = 0x6FCB; static final int EF_IMG = 0x4F20; static final int EF_PSISMSC = 0x6FE5; + static final int EF_SMSS = 0x6F43; // USIM SIM file ids from TS 131.102 public static final int EF_PBR = 0x4F30; diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java index a35bb6bb1e..da112b166e 100644 --- a/src/java/com/android/internal/telephony/uicc/IccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java @@ -30,6 +30,7 @@ import android.telephony.CellIdentity; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; @@ -40,6 +41,7 @@ import com.android.internal.telephony.util.ArrayUtils; import com.android.telephony.Rlog; import java.io.FileDescriptor; +import java.io.FileNotFoundException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.lang.annotation.Retention; @@ -55,8 +57,11 @@ import java.util.concurrent.atomic.AtomicInteger; * {@hide} */ public abstract class IccRecords extends Handler implements IccConstants { + private static final String LOG_TAG = "IccRecords"; protected static final boolean DBG = true; - protected static final boolean VDBG = false; // STOPSHIP if true + private static final boolean FORCE_VERBOSE_STATE_LOGGING = false; /* stopship if true */ + protected static final boolean VDBG = FORCE_VERBOSE_STATE_LOGGING || + Rlog.isLoggable(LOG_TAG, Log.VERBOSE); public static final int PLMN_MIN_LENGTH = CellIdentity.MCC_LENGTH + CellIdentity.MNC_MIN_LENGTH; @@ -121,6 +126,10 @@ public abstract class IccRecords extends Handler implements IccConstants { protected boolean mRecordsRequested = false; // true if we've made requests for the sim records protected int mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE; + // EF_SMSS fields tpmr invalid, min and max declarations + protected static final int SMSS_INVALID_TPMR = -1; + private static final int TPMR_MIN = 0x00; + private static final int TPMR_MAX = 0xFF; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) public String mIccId; // Includes only decimals (no hex) @@ -179,6 +188,10 @@ public abstract class IccRecords extends Handler implements IccConstants { // Reference: TS 31.102 section 4.5.9 protected String mPsiSmsc; + // EF_SMSS value which is combination of TPMR and Memory exceed flag + // Reference: TS 31.102 section 4.2.9 + protected byte[] mSmssValues; + CarrierTestOverride mCarrierTestOverride; //Arbitrary offset for the Handler @@ -240,6 +253,10 @@ public abstract class IccRecords extends Handler implements IccConstants { // TAG value to retrieve EF_PSISMSC from parsed SimTlv object private static final int TAG_TLV_USIM_VALUE_80 = 0x80; + + // call back received on this upon EF_SMSS record update. + public static final int EVENT_SET_SMSS_RECORD_DONE = 201; + /** * There are two purposes for this class. First, each instance of AuthAsyncResponse acts as a * lock to for calling thead to wait in getIccSimChallengeResponse(). Second, pass the IMS @@ -962,6 +979,26 @@ public abstract class IccRecords extends Handler implements IccConstants { } break; + case EVENT_SET_SMSS_RECORD_DONE: + ar = (AsyncResult) msg.obj; + SmssRecord smssRecord = null; + if (ar.userObj != null) { + smssRecord = (SmssRecord) ar.userObj; + } + if (ar.exception == null && smssRecord.getSmssValue() != null) { + mSmssValues = smssRecord.getSmssValue().clone(); + } else { + loge("SIM EF_SMSS field updating error=" + ar.exception); + } + if (smssRecord != null && smssRecord.getMessage() != null) { + Message message = smssRecord.getMessage(); + AsyncResult.forMessage(message, ar.result, ar.exception); + message.sendToTarget(); + } else { + loge("smssRecord or smssRecord.getMessage() object is null"); + } + break; + default: super.handleMessage(msg); } @@ -1568,4 +1605,73 @@ public abstract class IccRecords extends Handler implements IccConstants { return "{fullName = " + fullName + ", shortName = " + shortName + "}"; } } + + /** + * Sets the elementary (EF_SMSS) field with latest last used TP-Message reference value. + * First byte of EF_SMSS represents the TPMR value as per the spec + * (Section 4.2.9 of 3GPP TS 31.102) + * + * @param tpmr: Last used TP-Message reference parameter of type int + * @param onComplete: android.os.Message to be notified upon completion + */ + public void setSmssTpmrValue(int tpmr, Message onComplete) { + if(VDBG) log("setSmssTpmrValue()"); + if (mSmssValues != null && mSmssValues.length > 0 && tpmr >= TPMR_MIN && tpmr <= TPMR_MAX) { + byte[] tempSmss = mSmssValues.clone(); + tempSmss[0] = (byte) (tpmr & 0xFF); + SmssRecord smssRecord = createSmssRecord(onComplete, tempSmss); + mFh.updateEFTransparent(IccConstants.EF_SMSS, tempSmss, + obtainMessage(EVENT_SET_SMSS_RECORD_DONE, smssRecord)); + } else if (onComplete != null) { + loge("Failed to set EF_SMSS [TPMR] field to SIM"); + if (mSmssValues == null || mSmssValues.length <= 0) { + AsyncResult.forMessage((onComplete)).exception = + new FileNotFoundException("EF_SMSS file not found"); + } else if (tpmr < TPMR_MIN || tpmr > TPMR_MAX) { + AsyncResult.forMessage((onComplete)).exception = + new IllegalArgumentException("TPMR value is not in allowed range"); + } + onComplete.sendToTarget(); + } + } + + /** + * Fetches the last used TPMR value from elementary (EF_SMSS) field. First byte of EF_SMSS + * represents the TPMR value as per the spec (Section 4.2.9 of 3GPP TS 31.102) + * + * @return TP-Message reference parameter of type int, -1 in case if it fails to read the + * EF_SMSS field from the sim. + */ + public int getSmssTpmrValue() { + if (mSmssValues != null && mSmssValues.length > 0) { + return (mSmssValues[0] & 0xFF); + } + loge("IccRecords - EF_SMSS is null"); + return SMSS_INVALID_TPMR; + } + + @VisibleForTesting + public SmssRecord createSmssRecord(Message msg, byte[] smss) { + return new SmssRecord(msg, smss); + } + + + static class SmssRecord { + + private Message mMsg; + private byte[] mSmss; + + SmssRecord (Message msg, byte[] smss) { + mMsg = msg; + mSmss = smss; + } + + private byte[] getSmssValue() { + return mSmss; + } + + private Message getMessage() { + return mMsg; + } + } } diff --git a/src/java/com/android/internal/telephony/uicc/IsimFileHandler.java b/src/java/com/android/internal/telephony/uicc/IsimFileHandler.java index fe900cb387..4d5f8d156f 100644 --- a/src/java/com/android/internal/telephony/uicc/IsimFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/IsimFileHandler.java @@ -38,6 +38,7 @@ public final class IsimFileHandler extends IccFileHandler implements IccConstant case EF_DOMAIN: case EF_IST: case EF_PCSCF: + case EF_SMSS: return MF_SIM + DF_ADF; } String path = getCommonIccEFPath(efid); diff --git a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java index 1919f69f47..7cd59c74ea 100644 --- a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java @@ -23,6 +23,7 @@ import android.os.AsyncResult; import android.os.Build; import android.os.Message; import android.telephony.SubscriptionManager; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; @@ -42,7 +43,9 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { protected static final String LOG_TAG = "IsimUiccRecords"; private static final boolean DBG = true; - private static final boolean VDBG = false; // STOPSHIP if true + private static final boolean FORCE_VERBOSE_STATE_LOGGING = false; /* stopship if true */ + private static final boolean VDBG = FORCE_VERBOSE_STATE_LOGGING || + Rlog.isLoggable(LOG_TAG, Log.VERBOSE); private static final boolean DUMP_RECORDS = false; // Note: PII is logged when this is true // STOPSHIP if true public static final String INTENT_ISIM_REFRESH = "com.android.intent.isim_refresh"; @@ -70,8 +73,9 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { + " mIsimDomain=" + mIsimDomain + " mIsimImpu=" + mIsimImpu + " mIsimIst=" + mIsimIst - + " mIsimPcscf=" + mIsimPcscf - + " mPsiSmsc=" + mPsiSmsc) : ""); + + " mIsimPcscf=" + Arrays.toString(mIsimPcscf) + + " mPsiSmsc=" + mPsiSmsc + + " mSmss TPMR=" + getSmssTpmrValue()) : ""); } public IsimUiccRecords(UiccCardApplication app, Context c, CommandsInterface ci) { @@ -113,7 +117,6 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { broadcastRefresh(); super.handleMessage(msg); break; - default: super.handleMessage(msg); // IccRecords handles generic record load responses @@ -145,6 +148,9 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { mFh.loadEFLinearFixedAll(EF_PCSCF, obtainMessage( IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimPcscfLoaded())); mRecordsToLoad++; + mFh.loadEFTransparent(EF_SMSS, obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimSmssLoaded())); + mRecordsToLoad++; mFh.loadEFLinearFixed(EF_PSISMSC, 1, obtainMessage( IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimPsiSmscLoaded())); @@ -218,6 +224,23 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { if (DUMP_RECORDS) log("EF_IST=" + mIsimIst); } } + + private class EfIsimSmssLoaded implements IccRecords.IccRecordLoaded { + + @Override + public String getEfName() { + return "EF_ISIM_SMSS"; + } + + @Override + public void onRecordLoaded(AsyncResult ar) { + mSmssValues = (byte[]) ar.result; + if (VDBG) { + log("IsimUiccRecords - EF_SMSS TPMR value = " + getSmssTpmrValue()); + } + } + } + private class EfIsimPcscfLoaded implements IccRecords.IccRecordLoaded { public String getEfName() { return "EF_ISIM_PCSCF"; @@ -468,6 +491,7 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { pw.println(" mIsimIst" + mIsimIst); pw.println(" mIsimPcscf" + mIsimPcscf); pw.println(" mPsismsc=" + mPsiSmsc); + pw.println(" mSmss TPMR=" + getSmssTpmrValue()); } pw.flush(); } diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index 59629c372c..f84cf8a8bc 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -31,6 +31,7 @@ import android.telephony.PhoneNumberUtils; import android.telephony.SmsMessage; import android.telephony.SubscriptionInfo; import android.text.TextUtils; +import android.util.Log; import android.util.Pair; import com.android.internal.telephony.CommandsInterface; @@ -54,8 +55,9 @@ public class SIMRecords extends IccRecords { protected static final String LOG_TAG = "SIMRecords"; private static final boolean CRASH_RIL = false; - - private static final boolean VDBG = false; + private static final boolean FORCE_VERBOSE_STATE_LOGGING = false; /* stopship if true */ + private static final boolean VDBG = FORCE_VERBOSE_STATE_LOGGING || + Rlog.isLoggable(LOG_TAG, Log.VERBOSE); // ***** Instance Variables @@ -109,7 +111,8 @@ public class SIMRecords extends IccRecords { + " mEfCff=" + mEfCff + " mEfCfis=" + mEfCfis + " getOperatorNumeric=" + getOperatorNumeric() - + " mPsiSmsc=" + mPsiSmsc; + + " mPsiSmsc=" + mPsiSmsc + + " TPMR=" + getSmssTpmrValue(); } // ***** Constants @@ -185,7 +188,9 @@ public class SIMRecords extends IccRecords { private static final int EVENT_GET_FPLMN_DONE = 41 + SIM_RECORD_EVENT_BASE; private static final int EVENT_GET_FPLMN_SIZE_DONE = 42 + SIM_RECORD_EVENT_BASE; private static final int EVENT_SET_FPLMN_DONE = 43 + SIM_RECORD_EVENT_BASE; + protected static final int EVENT_GET_SMSS_RECORD_DONE = 46 + SIM_RECORD_EVENT_BASE; protected static final int EVENT_GET_PSISMSC_DONE = 47 + SIM_RECORD_EVENT_BASE; + // ***** Constructor public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) { @@ -641,7 +646,6 @@ public class SIMRecords extends IccRecords { " while being destroyed. Ignoring."); return; } - try { switch (msg.what) { /* IO events */ @@ -1297,7 +1301,7 @@ public class SIMRecords extends IccRecords { isRecordLoadResponse = true; ar = (AsyncResult) msg.obj; if (ar.exception != null) { - loge("Failed to read USIM EF_SMSS field error=" + ar.exception); + loge("Failed to read USIM EF_PSISMSC field error=" + ar.exception); } else { data = (byte[]) ar.result; if (data != null && data.length > 0) { @@ -1309,6 +1313,19 @@ public class SIMRecords extends IccRecords { } break; + case EVENT_GET_SMSS_RECORD_DONE: + isRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + loge("Failed to read USIM EF_SMSS field error=" + ar.exception); + } else { + mSmssValues = (byte[]) ar.result; + if (VDBG) { + log("SIMRecords - EF_SMSS TPMR value = " + getSmssTpmrValue()); + } + } + break; + default: super.handleMessage(msg); // IccRecords handles generic record load responses } @@ -1707,6 +1724,9 @@ public class SIMRecords extends IccRecords { mRecordsToLoad++; } + mFh.loadEFTransparent(EF_SMSS, obtainMessage(EVENT_GET_SMSS_RECORD_DONE)); + mRecordsToLoad++; + if (CRASH_RIL) { String sms = "0107912160130310f20404d0110041007030208054832b0120" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" @@ -2166,6 +2186,7 @@ public class SIMRecords extends IccRecords { pw.println(" mFplmns[]=" + Arrays.toString(mFplmns)); pw.println(" mEhplmns[]=" + Arrays.toString(mEhplmns)); pw.println(" mPsismsc=" + mPsiSmsc); + pw.println(" TPMR=" + getSmssTpmrValue()); pw.flush(); } } diff --git a/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java b/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java index ff8d63d5c1..bc46f800a2 100755 --- a/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java @@ -68,6 +68,7 @@ public final class UsimFileHandler extends IccFileHandler implements IccConstant case EF_FPLMN: case EF_LRPLMNSI: case EF_HPPLMN: + case EF_SMSS: return MF_SIM + DF_ADF; case EF_PBR: diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java index 445a5baaf5..8324a5b274 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java @@ -31,14 +31,21 @@ package com.android.internal.telephony.uicc; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import android.content.Context; import android.content.Intent; import android.os.AsyncResult; -import android.os.HandlerThread; +import android.os.Handler; import android.os.Message; +import android.os.test.TestLooper; import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.TelephonyTest; @@ -49,31 +56,48 @@ import org.mockito.ArgumentCaptor; public class IsimUiccRecordsTest extends TelephonyTest { - private IsimUiccRecords mIsimUiccRecords; + // Mocked classes + private IccFileHandler mFhMock; + private TestLooper mTestLooper; + private Handler mTestHandler; + private IsimUiccRecordsUT mIsimUiccRecordsUT; - private class IsimUiccRecordsTestHandler extends HandlerThread { - private IsimUiccRecordsTestHandler(String name) { - super(name); - } - - @Override - public void onLooperPrepared() { - mIsimUiccRecords = new IsimUiccRecords(mUiccCardApplication3gpp, mContext, mSimulatedCommands); - setReady(true); + @SuppressWarnings("ClassCanBeStatic") + private class IsimUiccRecordsUT extends IsimUiccRecords { + IsimUiccRecordsUT(UiccCardApplication app, Context c, + CommandsInterface ci, IccFileHandler mFhMock) { + super(app, c, ci); + mFh = mFhMock; } } @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); - new IsimUiccRecordsTestHandler(TAG).start(); - waitUntilReady(); + mFhMock = mock(IccFileHandler.class); + mTestLooper = new TestLooper(); + mTestHandler = new Handler(mTestLooper.getLooper()); + mTestHandler.post( + () -> { + mIsimUiccRecordsUT = + new IsimUiccRecordsUT( + mUiccCardApplication3gpp, + mContext, + mSimulatedCommands, + mFhMock); + }); + mTestLooper.dispatchAll(); } @After public void tearDown() throws Exception { - mIsimUiccRecords.dispose(); - mIsimUiccRecords = null; + if (mTestLooper != null) { + mTestLooper.dispatchAll(); + mTestLooper = null; + } + mTestHandler.removeCallbacksAndMessages(null); + mTestHandler = null; + mIsimUiccRecordsUT = null; super.tearDown(); } @@ -82,12 +106,12 @@ public class IsimUiccRecordsTest extends TelephonyTest { Message msg = new Message(); msg.what = IccRecords.EVENT_REFRESH; msg.obj = new AsyncResult(null, null, null); - mIsimUiccRecords.handleMessage(msg); + mIsimUiccRecordsUT.handleMessage(msg); ArgumentCaptor intentCapture = ArgumentCaptor.forClass(Intent.class); verify(mContext).sendBroadcast(intentCapture.capture()); - assertEquals( - ((Intent) intentCapture.getValue()).getAction(), IsimUiccRecords.INTENT_ISIM_REFRESH); + ((Intent) intentCapture.getValue()).getAction(), + IsimUiccRecords.INTENT_ISIM_REFRESH); } @Test @@ -98,11 +122,11 @@ public class IsimUiccRecordsTest extends TelephonyTest { "801074656C3A2B3133313233313439383130FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; byte[] smscBytes = getStringToByte(hexSmsc); - Message message = mIsimUiccRecords.obtainMessage( - IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecords.getPsiSmscObject()); - AsyncResult ar = AsyncResult.forMessage(message, smscBytes, null); - mIsimUiccRecords.handleMessage(message); - assertEquals(smscTest, mIsimUiccRecords.getSmscIdentity()); + Message message = mIsimUiccRecordsUT.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecordsUT.getPsiSmscObject()); + AsyncResult.forMessage(message, smscBytes, null); + mIsimUiccRecordsUT.handleMessage(message); + assertEquals(smscTest, mIsimUiccRecordsUT.getSmscIdentity()); } private byte[] getStringToByte(String hexSmsc) { @@ -119,11 +143,11 @@ public class IsimUiccRecordsTest extends TelephonyTest { + "52E636F6D3B757365723D70686F6E65FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); - Message message = mIsimUiccRecords.obtainMessage( - IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecords.getPsiSmscObject()); - AsyncResult ar = AsyncResult.forMessage(message, smscBytes, null); - mIsimUiccRecords.handleMessage(message); - assertEquals(smscTest, mIsimUiccRecords.getSmscIdentity()); + Message message = mIsimUiccRecordsUT.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecordsUT.getPsiSmscObject()); + AsyncResult.forMessage(message, smscBytes, null); + mIsimUiccRecordsUT.handleMessage(message); + assertEquals(smscTest, mIsimUiccRecordsUT.getSmscIdentity()); } @Test @@ -133,13 +157,13 @@ public class IsimUiccRecordsTest extends TelephonyTest { "801074656C3A2B3133313233313439383130FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; byte[] smscBytes = getStringToByte(hexSmsc); - Message message = mIsimUiccRecords.obtainMessage( - IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecords.getPsiSmscObject()); - AsyncResult ar = AsyncResult.forMessage(message, smscBytes, + Message message = mIsimUiccRecordsUT.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecordsUT.getPsiSmscObject()); + AsyncResult.forMessage(message, smscBytes, new CommandException( CommandException.Error.OPERATION_NOT_ALLOWED)); - mIsimUiccRecords.handleMessage(message); - assertEquals(null, mIsimUiccRecords.getSmscIdentity()); + mIsimUiccRecordsUT.handleMessage(message); + assertEquals(null, mIsimUiccRecordsUT.getSmscIdentity()); } @Test @@ -147,12 +171,136 @@ public class IsimUiccRecordsTest extends TelephonyTest { // Testing smsc invalid data handling case String smscTest = "tel:+13123149810"; byte[] smscBytes = GsmAlphabet.stringToGsm8BitPacked(smscTest); - Message message = mIsimUiccRecords.obtainMessage( - IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecords.getPsiSmscObject()); - AsyncResult ar = AsyncResult.forMessage(message, smscBytes, + Message message = mIsimUiccRecordsUT.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecordsUT.getPsiSmscObject()); + AsyncResult.forMessage(message, smscBytes, new CommandException( CommandException.Error.OPERATION_NOT_ALLOWED)); - mIsimUiccRecords.handleMessage(message); - assertEquals(null, mIsimUiccRecords.getSmscIdentity()); + mIsimUiccRecordsUT.handleMessage(message); + assertEquals(null, mIsimUiccRecordsUT.getSmscIdentity()); + } + + @Test + public void testGetSmssTpmrValue() { + // Testing tpmr successfully reading case + byte[] smss = new byte[2]; + int tpmr = 10; + smss[0] = (byte) (tpmr & 0xFF); + IccRecords.SmssRecord smssRecord = mIsimUiccRecordsUT.createSmssRecord(null, smss); + Message message = mIsimUiccRecordsUT.obtainMessage( + IsimUiccRecords.EVENT_SET_SMSS_RECORD_DONE, smssRecord); + AsyncResult.forMessage(message, null, null); + mIsimUiccRecordsUT.handleMessage(message); + assertEquals(tpmr, mIsimUiccRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testGetSmssTpmrValueException() { + // Testing tpmr reading fail case [ exception case ] + byte[] smss = new byte[2]; + int tpmr = 10; + smss[0] = (byte) (tpmr & 0xFF); + IccRecords.SmssRecord smssRecord = mIsimUiccRecordsUT.createSmssRecord(null, smss); + Message message = mIsimUiccRecordsUT.obtainMessage( + IsimUiccRecords.EVENT_SET_SMSS_RECORD_DONE, smssRecord); + AsyncResult.forMessage(message, null, + new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + mIsimUiccRecordsUT.handleMessage(message); + assertEquals(-1, mIsimUiccRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testGetSmssTpmrValueExtreme() { + // Testing extreme tpmr value case [ fails ] + byte[] smss = new byte[2]; + int tpmr = 400; + smss[0] = (byte) (tpmr & 0xFF); + IccRecords.SmssRecord smssRecord = mIsimUiccRecordsUT.createSmssRecord(null, smss); + Message message = mIsimUiccRecordsUT.obtainMessage( + IsimUiccRecords.EVENT_SET_SMSS_RECORD_DONE, smssRecord); + AsyncResult.forMessage(message, null, null); + mIsimUiccRecordsUT.handleMessage(message); + assertEquals(144, mIsimUiccRecordsUT.getSmssTpmrValue()); + } + + private void setValidSmssValue() { + // preset/ initialize smssvalue + byte[] smss = new byte[2]; + int tpmr = 10; + smss[0] = (byte) (tpmr & 0xFF); + IccRecords.SmssRecord smssRecord = mIsimUiccRecordsUT.createSmssRecord(null, smss); + Message message = mIsimUiccRecordsUT.obtainMessage( + IsimUiccRecords.EVENT_SET_SMSS_RECORD_DONE, smssRecord); + AsyncResult.forMessage(message, null, null); + mIsimUiccRecordsUT.handleMessage(message); + assertEquals(tpmr, mIsimUiccRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testSetSmssTpmrValue() { + // Testing tpmr successfully setting case + setValidSmssValue(); + int updateTpmr = 30; + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, true, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIsimUiccRecordsUT.setSmssTpmrValue(updateTpmr, message); + mTestLooper.dispatchAll(); + assertEquals(updateTpmr, mIsimUiccRecordsUT.getSmssTpmrValue()); + } + + + @Test + public void testSetSmssTpmrValueException() { + // Testing exception while setting TPMR [ with out setting initial value] + int updateTpmr = 30; + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, true, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + Message message = Message.obtain(mTestHandler); + mIsimUiccRecordsUT.setSmssTpmrValue(updateTpmr, message); + mTestLooper.dispatchAll(); + assertEquals(-1, mIsimUiccRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testSetSmssTpmrValueException2() { + // Testing exception while setting TPMR + setValidSmssValue(); + int updateTpmr = 30; + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + + AsyncResult.forMessage(response, true, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + Message message = Message.obtain(mTestHandler); + mIsimUiccRecordsUT.setSmssTpmrValue(updateTpmr, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertTrue(((CommandException) ar.exception).getCommandError() == + CommandException.Error.OPERATION_NOT_ALLOWED); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java index b6b8d9887d..3d6f7700d6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java @@ -169,37 +169,37 @@ public class SIMRecordsTest extends TelephonyTest { private void setUpSetForbiddenPlmnsTests() { doAnswer( - invocation -> { - Message response = invocation.getArgument(1); - AsyncResult.forMessage(response, EF_SIZE, null); - response.sendToTarget(); - return null; - }) - .when(mFhMock) - .getEFTransparentRecordSize(anyInt(), any(Message.class)); + invocation -> { + Message response = invocation.getArgument(1); + AsyncResult.forMessage(response, EF_SIZE, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .getEFTransparentRecordSize(anyInt(), any(Message.class)); doAnswer( - invocation -> { - Message response = invocation.getArgument(2); - AsyncResult.forMessage(response, true, null); - response.sendToTarget(); - return null; - }) - .when(mFhMock) - .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, true, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); } @Test public void testGetForbiddenPlmns() { doAnswer( - invocation -> { - Message response = invocation.getArgument(1); - byte[] encodedFplmn = IccUtils.encodeFplmns(SHORT_FPLMNS_LIST, EF_SIZE); - AsyncResult.forMessage(response, encodedFplmn, null); - response.sendToTarget(); - return null; - }) - .when(mFhMock) - .loadEFTransparent(eq(SIMRecords.EF_FPLMN), any(Message.class)); + invocation -> { + Message response = invocation.getArgument(1); + byte[] encodedFplmn = IccUtils.encodeFplmns(SHORT_FPLMNS_LIST, EF_SIZE); + AsyncResult.forMessage(response, encodedFplmn, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .loadEFTransparent(eq(SIMRecords.EF_FPLMN), any(Message.class)); Message message = Message.obtain(mTestHandler); mSIMRecordsUT.getForbiddenPlmns(message); @@ -214,15 +214,15 @@ public class SIMRecordsTest extends TelephonyTest { @Test public void testGetForbiddenPlmnsException() { doAnswer( - invocation -> { - Message response = invocation.getArgument(1); - AsyncResult.forMessage(response, null, new CommandException( - CommandException.Error.OPERATION_NOT_ALLOWED)); - response.sendToTarget(); - return null; - }) - .when(mFhMock) - .loadEFTransparent(eq(SIMRecords.EF_FPLMN), any(Message.class)); + invocation -> { + Message response = invocation.getArgument(1); + AsyncResult.forMessage(response, null, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .loadEFTransparent(eq(SIMRecords.EF_FPLMN), any(Message.class)); Message message = Message.obtain(mTestHandler); mSIMRecordsUT.getForbiddenPlmns(message); @@ -238,14 +238,14 @@ public class SIMRecordsTest extends TelephonyTest { @Test public void testGetForbiddenPlmnsNull() { doAnswer( - invocation -> { - Message response = invocation.getArgument(1); - AsyncResult.forMessage(response); - response.sendToTarget(); - return null; - }) - .when(mFhMock) - .loadEFTransparent(eq(SIMRecords.EF_FPLMN), any(Message.class)); + invocation -> { + Message response = invocation.getArgument(1); + AsyncResult.forMessage(response); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .loadEFTransparent(eq(SIMRecords.EF_FPLMN), any(Message.class)); Message message = Message.obtain(mTestHandler); mSIMRecordsUT.getForbiddenPlmns(message); @@ -259,15 +259,15 @@ public class SIMRecordsTest extends TelephonyTest { @Test public void testGetForbiddenPlmnsEmptyList() { doAnswer( - invocation -> { - Message response = invocation.getArgument(1); - byte[] encodedFplmn = IccUtils.encodeFplmns(EMPTY_FPLMN_LIST, EF_SIZE); - AsyncResult.forMessage(response, encodedFplmn, null); - response.sendToTarget(); - return null; - }) - .when(mFhMock) - .loadEFTransparent(eq(SIMRecords.EF_FPLMN), any(Message.class)); + invocation -> { + Message response = invocation.getArgument(1); + byte[] encodedFplmn = IccUtils.encodeFplmns(EMPTY_FPLMN_LIST, EF_SIZE); + AsyncResult.forMessage(response, encodedFplmn, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .loadEFTransparent(eq(SIMRecords.EF_FPLMN), any(Message.class)); Message message = Message.obtain(mTestHandler); mSIMRecordsUT.getForbiddenPlmns(message); @@ -282,14 +282,14 @@ public class SIMRecordsTest extends TelephonyTest { @Test public void testGetForbiddenPlmnsInvalidLength() { doAnswer( - invocation -> { - Message response = invocation.getArgument(1); - AsyncResult.forMessage(response, new byte[] { (byte) 0xFF, (byte) 0xFF }, null); - response.sendToTarget(); - return null; - }) - .when(mFhMock) - .loadEFTransparent(eq(SIMRecords.EF_FPLMN), any(Message.class)); + invocation -> { + Message response = invocation.getArgument(1); + AsyncResult.forMessage(response, new byte[]{(byte) 0xFF, (byte) 0xFF}, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .loadEFTransparent(eq(SIMRecords.EF_FPLMN), any(Message.class)); Message message = Message.obtain(mTestHandler); mSIMRecordsUT.getForbiddenPlmns(message); @@ -313,7 +313,7 @@ public class SIMRecordsTest extends TelephonyTest { targetPnns.add(new PlmnNetworkName(name, null)); Message message = mSIMRecordsUT.obtainMessage(SIMRecords.EVENT_GET_PNN_DONE); - AsyncResult ar = AsyncResult.forMessage(message, rawPnns, null); + AsyncResult.forMessage(message, rawPnns, null); mSIMRecordsUT.handleMessage(message); List parsedPnns = Arrays.asList(mSIMRecordsUT.getPnns()); @@ -321,22 +321,214 @@ public class SIMRecordsTest extends TelephonyTest { } private static byte[] encodePnn(String name) { - byte[] gsm7BitName = new byte[] {}; + byte[] gsm7BitName = new byte[]{}; try { gsm7BitName = GsmAlphabet.stringToGsm7BitPacked(name); gsm7BitName[0] = (byte) (name.length() % 8 | 0x80); } catch (Exception ex) { fail("SimRecordsTest: GsmAlphabet.stringToGsm7BitPacked() exception:" + ex); } - byte[] encodedName = new byte[gsm7BitName.length + 2]; encodedName[0] = 0x43; encodedName[1] = (byte) gsm7BitName.length; System.arraycopy(gsm7BitName, 0, encodedName, 2, gsm7BitName.length); - return encodedName; } + @Test + public void testGetSmssTpmrValue() { + // Testing tpmr successfully reading case + byte[] smss = new byte[2]; + int tpmr = 10; + smss[0] = (byte) tpmr; + Message message = mSIMRecordsUT.obtainMessage( + SIMRecords.EVENT_GET_SMSS_RECORD_DONE, smss); + AsyncResult.forMessage(message, smss, null); + mSIMRecordsUT.handleMessage(message); + assertEquals(tpmr, mSIMRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testGetSmssTpmrValueException() { + // Testing tpmr exception case + byte[] smss = new byte[2]; + int tpmr = 10; + smss[0] = (byte) tpmr; + Message message = mSIMRecordsUT.obtainMessage( + SIMRecords.EVENT_GET_SMSS_RECORD_DONE, smss); + AsyncResult.forMessage(message, smss, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + mSIMRecordsUT.handleMessage(message); + assertEquals(-1, mSIMRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testSetSmssTpmrValue() { + // Testing tpmr successfully updating case + setValidSmssValue(); + int updateTpmr = 30; + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, true, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setSmssTpmrValue(updateTpmr, message); + mTestLooper.dispatchAll(); + assertEquals(updateTpmr, mSIMRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testSetSmssTpmrNegativevalue() { + // Testing tpmr successfully updating case + setValidSmssValue(); + int updateTpmr = -2; + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, true, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setSmssTpmrValue(updateTpmr, message); + mTestLooper.dispatchAll(); + // 10 is previous set value + assertEquals(10, mSIMRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testSetSmssTpmrHighvalue() { + // Testing tpmr successfully updating case + setValidSmssValue(); + int updateTpmr = 256; + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, true, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setSmssTpmrValue(updateTpmr, message); + mTestLooper.dispatchAll(); + // 10 is previous set value + assertEquals(10, mSIMRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testSetSmssTpmrMaxValue() { + // Testing tpmr successfully updating case + setValidSmssValue(); + int updateTpmr = 255; + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, true, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setSmssTpmrValue(updateTpmr, message); + mTestLooper.dispatchAll(); + assertEquals(updateTpmr, mSIMRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testSetSmssTpmrValueException() { + // Testing exception while setting TPMR [ with out setting initial value] + int updateTpmr = 30; + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, true, null); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setSmssTpmrValue(updateTpmr, message); + mTestLooper.dispatchAll(); + assertEquals(-1, mSIMRecordsUT.getSmssTpmrValue()); + } + + @Test + public void testSetSmssTpmrValueException2() { + // Testing exception while setting TPMR + setValidSmssValue(); + int updateTpmr = 30; + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + + AsyncResult.forMessage(response, true, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setSmssTpmrValue(updateTpmr, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertTrue(((CommandException) ar.exception).getCommandError() == + CommandException.Error.OPERATION_NOT_ALLOWED); + } + + @Test + public void testSetSmssTpmrLargeValue() { + // Testing Large TPMR value setting + setValidSmssValue(); + int updateTpmr = 300; + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, true, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + response.sendToTarget(); + return null; + }) + .when(mFhMock) + .updateEFTransparent(anyInt(), any(byte[].class), any(Message.class)); + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setSmssTpmrValue(updateTpmr, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof IllegalArgumentException); + } + + private void setValidSmssValue() { + // preset/ initialize smssvalue + byte[] smss = new byte[2]; + int tpmr = 10; + smss[0] = (byte) (tpmr & 0xFF); + IccRecords.SmssRecord smssRecord = mSIMRecordsUT.createSmssRecord(null, smss); + Message message = mSIMRecordsUT.obtainMessage( + IsimUiccRecords.EVENT_SET_SMSS_RECORD_DONE, smssRecord); + AsyncResult.forMessage(message, null, null); + mSIMRecordsUT.handleMessage(message); + assertEquals(tpmr, mSIMRecordsUT.getSmssTpmrValue()); + } + @Test public void testGetEfOpl() { ArrayList rawOpl = new ArrayList(); @@ -352,7 +544,7 @@ public class SIMRecordsTest extends TelephonyTest { targetOpl.add(new OperatorPlmnInfo(plmn, lacTacStart, lacTacEnd, pnnIndex)); Message message = mSIMRecordsUT.obtainMessage(SIMRecords.EVENT_GET_OPL_DONE); - AsyncResult ar = AsyncResult.forMessage(message, rawOpl, null); + AsyncResult.forMessage(message, rawOpl, null); mSIMRecordsUT.handleMessage(message); List parsedOpl = Arrays.asList(mSIMRecordsUT.getOpl()); @@ -368,7 +560,7 @@ public class SIMRecordsTest extends TelephonyTest { targetOpl.add(new OperatorPlmnInfo(plmn, lacTacStart, lacTacEnd, pnnIndex)); message = mSIMRecordsUT.obtainMessage(SIMRecords.EVENT_GET_OPL_DONE); - ar = AsyncResult.forMessage(message, rawOpl, null); + AsyncResult.forMessage(message, rawOpl, null); mSIMRecordsUT.handleMessage(message); parsedOpl = Arrays.asList(mSIMRecordsUT.getOpl()); @@ -383,7 +575,7 @@ public class SIMRecordsTest extends TelephonyTest { rawOpl.add(encodeOpl(plmn, lacTacStart, lacTacEnd, pnnIndex)); message = mSIMRecordsUT.obtainMessage(SIMRecords.EVENT_GET_OPL_DONE); - ar = AsyncResult.forMessage(message, rawOpl, null); + AsyncResult.forMessage(message, rawOpl, null); mSIMRecordsUT.handleMessage(message); parsedOpl = Arrays.asList(mSIMRecordsUT.getOpl()); @@ -419,7 +611,7 @@ public class SIMRecordsTest extends TelephonyTest { byte[] smscBytes = getStringToByte(hexSmsc); Message message = mSIMRecordsUT.obtainMessage( SIMRecords.EVENT_GET_PSISMSC_DONE, smscBytes); - AsyncResult ar = AsyncResult.forMessage(message, smscBytes, null); + AsyncResult.forMessage(message, smscBytes, null); mSIMRecordsUT.handleMessage(message); assertEquals(smscTest, mSIMRecordsUT.getSmscIdentity()); } @@ -440,7 +632,7 @@ public class SIMRecordsTest extends TelephonyTest { + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); Message message = mSIMRecordsUT.obtainMessage( SIMRecords.EVENT_GET_PSISMSC_DONE, smscBytes); - AsyncResult ar = AsyncResult.forMessage(message, smscBytes, null); + AsyncResult.forMessage(message, smscBytes, null); mSIMRecordsUT.handleMessage(message); assertEquals(smscTest, mSIMRecordsUT.getSmscIdentity()); } -- GitLab From e6a2e2987e526bcdde9b0e7e435f8fca21978eb5 Mon Sep 17 00:00:00 2001 From: Ramya Manoharan Date: Mon, 16 May 2022 17:32:32 +0000 Subject: [PATCH 032/656] Incrementing of TP - Message reference for every SMS sent. Telephony will start managing TP MR, which includes incrementing and updating pdu. TPMR values will be persisted in telephony db. Test: Sequential sms case for CS and IMS , UT Bug: 228299168 Change-Id: I543b13d05a460c698d2f37c11bdd507c135b2493 --- .../internal/telephony/ImsSmsDispatcher.java | 1 + .../internal/telephony/SMSDispatcher.java | 274 ++++++++++++------ .../telephony/SmsDispatchersController.java | 5 +- .../telephony/SubscriptionController.java | 57 ++++ .../telephony/FakeTelephonyProvider.java | 2 + .../telephony/ImsSmsDispatcherTest.java | 71 +++++ .../telephony/SubscriptionControllerTest.java | 12 + .../telephony/gsm/GsmSmsDispatcherTest.java | 74 +++++ 8 files changed, 411 insertions(+), 85 deletions(-) diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java index 17490d73c4..b9f896c155 100644 --- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java +++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java @@ -504,6 +504,7 @@ public class ImsSmsDispatcher extends SMSDispatcher { @VisibleForTesting public void fallbackToPstn(SmsTracker tracker) { + tracker.mMessageRef = nextMessageRef(); mSmsDispatchersController.sendRetrySms(tracker); } diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index d9664b0c8b..885925a194 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -28,11 +28,13 @@ import android.app.AlertDialog; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.compat.annotation.UnsupportedAppUsage; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -80,6 +82,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; import com.android.internal.telephony.cdma.sms.UserData; +import com.android.internal.telephony.uicc.IccRecords; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -144,6 +147,12 @@ public abstract class SMSDispatcher extends Handler { protected static final int EVENT_ICC_CHANGED = 15; protected static final int EVENT_GET_IMS_SERVICE = 16; + /** Last TP - Message Reference value update to SIM */ + private static final int EVENT_TPMR_SIM_UPDATE_RESPONSE = 17; + + /** Handle SIM loaded */ + private static final int EVENT_SIM_LOADED = 18; + @UnsupportedAppUsage protected Phone mPhone; @UnsupportedAppUsage @@ -190,6 +199,9 @@ public abstract class SMSDispatcher extends Handler { @VisibleForTesting public int mCarrierMessagingTimeout = 10 * 60 * 1000; //10 minutes + /** Used for storing last TP - Message Reference used*/ + private int mMessageRef = -1; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected static int getNextConcatenatedRef() { sConcatenatedRef += 1; @@ -215,10 +227,33 @@ public abstract class SMSDispatcher extends Handler { com.android.internal.R.bool.config_sms_capable); mSmsSendDisabled = !mTelephonyManager.getSmsSendCapableForPhone( mPhone.getPhoneId(), mSmsCapable); + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_SIM_STATE_CHANGED); + mContext.registerReceiver(mBroadcastReceiver, intentFilter); Rlog.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat() + " mSmsSendDisabled=" + mSmsSendDisabled); } + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, Intent intent) { + Rlog.d(TAG, "Received broadcast " + intent.getAction()); + if (Intent.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) { + if (!intent.hasExtra(Intent.EXTRA_SIM_STATE)) { + Rlog.d(TAG, "Extra not found in intent."); + } else { + String simState = intent.getStringExtra(Intent.EXTRA_SIM_STATE); + if (simState.equals(Intent.SIM_STATE_LOADED)) { + Rlog.d(TAG, "SIM_STATE_CHANGED : SIM_LOADED"); + Message msg = obtainMessage(EVENT_SIM_LOADED); + msg.arg1 = getSubId(); + sendMessage(msg); + } + } + } + } + }; + /** * Observe the secure setting for updated premium sms determination rules */ @@ -280,85 +315,153 @@ public abstract class SMSDispatcher extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { - case EVENT_SEND_SMS_COMPLETE: - // An outbound SMS has been successfully transferred, or failed. - handleSendComplete((AsyncResult) msg.obj); - break; - - case EVENT_SEND_RETRY: - Rlog.d(TAG, "SMS retry.."); - sendRetrySms((SmsTracker) msg.obj); - break; - - case EVENT_SEND_LIMIT_REACHED_CONFIRMATION: - handleReachSentLimit((SmsTracker[]) (msg.obj)); - break; - - case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE: - handleConfirmShortCode(false, (SmsTracker[]) (msg.obj)); - break; - - case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE: - handleConfirmShortCode(true, (SmsTracker[]) (msg.obj)); - break; - - case EVENT_SEND_CONFIRMED_SMS: - { - SmsTracker[] trackers = (SmsTracker[]) msg.obj; - for (SmsTracker tracker : trackers) { - sendSms(tracker); + case EVENT_SEND_SMS_COMPLETE: + // An outbound SMS has been successfully transferred, or failed. + handleSendComplete((AsyncResult) msg.obj); + break; + + case EVENT_SEND_RETRY: + Rlog.d(TAG, "SMS retry.."); + sendRetrySms((SmsTracker) msg.obj); + break; + + case EVENT_SEND_LIMIT_REACHED_CONFIRMATION: + handleReachSentLimit((SmsTracker[]) (msg.obj)); + break; + + case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE: + handleConfirmShortCode(false, (SmsTracker[]) (msg.obj)); + break; + + case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE: + handleConfirmShortCode(true, (SmsTracker[]) (msg.obj)); + break; + + case EVENT_SEND_CONFIRMED_SMS: { + SmsTracker[] trackers = (SmsTracker[]) msg.obj; + for (SmsTracker tracker : trackers) { + sendSms(tracker); + } + mPendingTrackerCount--; + break; } - mPendingTrackerCount--; - break; - } - case EVENT_SENDING_NOT_ALLOWED: - { - SmsTracker[] trackers = (SmsTracker[]) msg.obj; - Rlog.d(TAG, "SMSDispatcher: EVENT_SENDING_NOT_ALLOWED - " - + "sending SHORT_CODE_NEVER_ALLOWED error code."); - handleSmsTrackersFailure( - trackers, SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, NO_ERROR_CODE); - break; - } + case EVENT_SENDING_NOT_ALLOWED: { + SmsTracker[] trackers = (SmsTracker[]) msg.obj; + Rlog.d(TAG, "SMSDispatcher: EVENT_SENDING_NOT_ALLOWED - " + + "sending SHORT_CODE_NEVER_ALLOWED error code."); + handleSmsTrackersFailure( + trackers, SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, NO_ERROR_CODE); + break; + } - case EVENT_STOP_SENDING: - { - SmsTracker[] trackers = (SmsTracker[]) msg.obj; - int error; - if (msg.arg1 == ConfirmDialogListener.SHORT_CODE_MSG) { - if (msg.arg2 == ConfirmDialogListener.NEVER_ALLOW) { - error = SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED; + case EVENT_STOP_SENDING: { + SmsTracker[] trackers = (SmsTracker[]) msg.obj; + int error; + if (msg.arg1 == ConfirmDialogListener.SHORT_CODE_MSG) { + if (msg.arg2 == ConfirmDialogListener.NEVER_ALLOW) { + error = SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED; + Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - " + + "sending SHORT_CODE_NEVER_ALLOWED error code."); + } else { + error = SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED; + Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - " + + "sending SHORT_CODE_NOT_ALLOWED error code."); + } + } else if (msg.arg1 == ConfirmDialogListener.RATE_LIMIT) { + error = SmsManager.RESULT_ERROR_LIMIT_EXCEEDED; Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - " - + "sending SHORT_CODE_NEVER_ALLOWED error code."); + + "sending LIMIT_EXCEEDED error code."); } else { - error = SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED; - Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - " - + "sending SHORT_CODE_NOT_ALLOWED error code."); + error = SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING; + Rlog.e(TAG, "SMSDispatcher: EVENT_STOP_SENDING - unexpected cases."); } - } else if (msg.arg1 == ConfirmDialogListener.RATE_LIMIT) { - error = SmsManager.RESULT_ERROR_LIMIT_EXCEEDED; - Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - " - + "sending LIMIT_EXCEEDED error code."); - } else { - error = SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING; - Rlog.e(TAG, "SMSDispatcher: EVENT_STOP_SENDING - unexpected cases."); + + handleSmsTrackersFailure(trackers, error, NO_ERROR_CODE); + mPendingTrackerCount--; + break; } - handleSmsTrackersFailure(trackers, error, NO_ERROR_CODE); - mPendingTrackerCount--; - break; + case EVENT_NEW_SMS_STATUS_REPORT: + handleStatusReport(msg.obj); + break; + case EVENT_TPMR_SIM_UPDATE_RESPONSE: + handleMessageRefStatus(msg); + break; + + case EVENT_SIM_LOADED: + /* sim TPMR value is given higher priority if both are non-negative number. + Use case: + if sim was used on another device and inserted in a new device, + that device will start sending the next TPMR after reading from the SIM. + */ + mMessageRef = getTpmrValueFromSIM(); + if (mMessageRef == -1) { + mMessageRef = SubscriptionController.getInstance().getMessageRef(msg.arg1); + } + break; + + default: + Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what); } + } - case EVENT_NEW_SMS_STATUS_REPORT: - handleStatusReport(msg.obj); - break; + private void handleMessageRefStatus(Message msg) { + AsyncResult ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + Rlog.e(TAG, "Failed to update TP - Message reference value to SIM " + ar.exception); + } else { + Rlog.d(TAG, "TP - Message reference updated to SIM Successfully"); + } + } - default: - Rlog.e(TAG, "handleMessage() ignoring message of unexpected type " + msg.what); + private void updateTPMessageReference() { + updateSIMLastTPMRValue(mMessageRef); + final long identity = Binder.clearCallingIdentity(); + try { + SubscriptionController.getInstance().updateMessageRef(getSubId(), mMessageRef); + } catch (SecurityException e) { + Rlog.e(TAG, "Security Exception caused on messageRef updation to DB " + e.getMessage()); + } finally { + Binder.restoreCallingIdentity(identity); } } + private void updateSIMLastTPMRValue(int messageRef) { + Message msg = obtainMessage(EVENT_TPMR_SIM_UPDATE_RESPONSE); + IccRecords iccRecords = getIccRecords(); + if (iccRecords != null) { + iccRecords.setSmssTpmrValue(messageRef, msg); + } + } + + private int getTpmrValueFromSIM() { + IccRecords iccRecords = getIccRecords(); + if (iccRecords != null) { + return iccRecords.getSmssTpmrValue(); + } + return -1; + } + + private IccRecords getIccRecords() { + if (mPhone != null && mPhone.getIccRecords() != null) { + return mPhone.getIccRecords(); + } + return null; + } + + /** + * Returns the next TP message Reference value incremented by 1 for every sms sent . + * once a max of 255 is reached TP message Reference is reset to 0. + * + * @return messageRef TP message Reference value + */ + public int nextMessageRef() { + mMessageRef = (mMessageRef + 1) % 256; + updateTPMessageReference(); + return mMessageRef; + } + /** * Use the carrier messaging service to send a data or text SMS. */ @@ -1133,14 +1236,15 @@ public abstract class SMSDispatcher extends Handler { @UnsupportedAppUsage protected void sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm) { + int messageRef = nextMessageRef(); SmsMessageBase.SubmitPduBase pdu = getSubmitPdu( - scAddr, destAddr, destPort, data, (deliveryIntent != null)); + scAddr, destAddr, destPort, data, (deliveryIntent != null), messageRef); if (pdu != null) { HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu); SmsTracker tracker = getSmsTracker(callingPackage, map, sentIntent, deliveryIntent, getFormat(), null /*messageUri*/, false /*expectMore*/, null /*fullMessageText*/, false /*isText*/, - true /*persistMessage*/, isForVvm, 0L /* messageId */); + true /*persistMessage*/, isForVvm, 0L /* messageId */, messageRef); if (!sendSmsByCarrierApp(true /* isDataSms */, tracker)) { sendSubmitPdu(tracker); @@ -1257,13 +1361,15 @@ public abstract class SMSDispatcher extends Handler { boolean expectMore, int validityPeriod, boolean isForVvm, long messageId) { Rlog.d(TAG, "sendText id: " + SmsController.formatCrossStackMessageId(messageId)); + int messageRef = nextMessageRef(); SmsMessageBase.SubmitPduBase pdu = getSubmitPdu( - scAddr, destAddr, text, (deliveryIntent != null), null, priority, validityPeriod); + scAddr, destAddr, text, (deliveryIntent != null), null, priority, validityPeriod, + messageRef); if (pdu != null) { HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu); SmsTracker tracker = getSmsTracker(callingPkg, map, sentIntent, deliveryIntent, getFormat(), messageUri, expectMore, text, true /*isText*/, - persistMessage, priority, validityPeriod, isForVvm, messageId); + persistMessage, priority, validityPeriod, isForVvm, messageId, messageRef); if (!sendSmsByCarrierApp(false /* isDataSms */, tracker)) { sendSubmitPdu(tracker); @@ -1502,12 +1608,13 @@ public abstract class SMSDispatcher extends Handler { if (deliveryIntents != null && deliveryIntents.size() > i) { deliveryIntent = deliveryIntents.get(i); } - + int messageRef = nextMessageRef(); trackers[i] = getNewSubmitPduTracker(callingPkg, destAddr, scAddr, parts.get(i), smsHeader, encoding, sentIntent, deliveryIntent, (i == (msgCount - 1)), unsentPartCount, anyPartFailed, messageUri, - fullMessageText, priority, expectMore, validityPeriod, messageId); + fullMessageText, priority, expectMore, validityPeriod, messageId, + messageRef); if (trackers[i] == null) { triggerSentIntentForFailure(sentIntents); return; @@ -1545,7 +1652,7 @@ public abstract class SMSDispatcher extends Handler { PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart, AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, String fullMessageText, int priority, boolean expectMore, int validityPeriod, - long messageId) { + long messageId, int messageRef) { if (isCdmaMo()) { UserData uData = new UserData(); uData.payloadStr = message; @@ -1575,7 +1682,7 @@ public abstract class SMSDispatcher extends Handler { getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader, (!lastPart || expectMore), fullMessageText, true /*isText*/, true /*persistMessage*/, priority, validityPeriod, false /* isForVvm */, - messageId); + messageId, messageRef); } else { Rlog.e(TAG, "CdmaSMSDispatcher.getNewSubmitPduTracker(): getSubmitPdu() returned " + "null " + SmsController.formatCrossStackMessageId(messageId)); @@ -1586,7 +1693,7 @@ public abstract class SMSDispatcher extends Handler { com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader), encoding, smsHeader.languageTable, - smsHeader.languageShiftTable, validityPeriod); + smsHeader.languageShiftTable, validityPeriod, messageRef); if (pdu != null) { HashMap map = getSmsTrackerMap(destinationAddress, scAddress, message, pdu); @@ -1594,7 +1701,7 @@ public abstract class SMSDispatcher extends Handler { deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader, (!lastPart || expectMore), fullMessageText, true /*isText*/, false /*persistMessage*/, priority, validityPeriod, false /* isForVvm */, - messageId); + messageId, messageRef); } else { Rlog.e(TAG, "GsmSMSDispatcher.getNewSubmitPduTracker(): getSubmitPdu() returned " + "null " + SmsController.formatCrossStackMessageId(messageId)); @@ -2099,7 +2206,8 @@ public abstract class SMSDispatcher extends Handler { AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader, boolean expectMore, String fullMessageText, int subId, boolean isText, boolean persistMessage, int userId, int priority, - int validityPeriod, boolean isForVvm, long messageId, int carrierId) { + int validityPeriod, boolean isForVvm, long messageId, int carrierId, + int messageRef) { mData = data; mSentIntent = sentIntent; mDeliveryIntent = deliveryIntent; @@ -2110,7 +2218,7 @@ public abstract class SMSDispatcher extends Handler { mExpectMore = expectMore; mImsRetry = 0; mUsesImsServiceForIms = false; - mMessageRef = 0; + mMessageRef = messageRef; mUnsentPartCount = unsentPartCount; mAnyPartFailed = anyPartFailed; mMessageUri = messageUri; @@ -2392,7 +2500,7 @@ public abstract class SMSDispatcher extends Handler { AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader, boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage, int priority, int validityPeriod, boolean isForVvm, - long messageId) { + long messageId, int messageRef) { // Get package info via packagemanager UserHandle callingUser = UserHandle.getUserHandleForUid(Binder.getCallingUid()); final int userId = callingUser.getIdentifier(); @@ -2409,28 +2517,28 @@ public abstract class SMSDispatcher extends Handler { return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format, unsentPartCount, anyPartFailed, messageUri, smsHeader, expectMore, fullMessageText, getSubId(), isText, persistMessage, userId, priority, - validityPeriod, isForVvm, messageId, mPhone.getCarrierId()); + validityPeriod, isForVvm, messageId, mPhone.getCarrierId(), messageRef); } protected SmsTracker getSmsTracker(String callingPackage, HashMap data, PendingIntent sentIntent, PendingIntent deliveryIntent, String format, Uri messageUri, boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage, - boolean isForVvm, long messageId) { + boolean isForVvm, long messageId, int messageRef) { return getSmsTracker(callingPackage, data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/, null/*anyPartFailed*/, messageUri, null/*smsHeader*/, expectMore, fullMessageText, isText, persistMessage, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, SMS_MESSAGE_PERIOD_NOT_SPECIFIED, isForVvm, - messageId); + messageId, messageRef); } protected SmsTracker getSmsTracker(String callingPackage, HashMap data, PendingIntent sentIntent, PendingIntent deliveryIntent, String format, Uri messageUri, boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage, - int priority, int validityPeriod, boolean isForVvm, long messageId) { + int priority, int validityPeriod, boolean isForVvm, long messageId, int messageRef) { return getSmsTracker(callingPackage, data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/, null/*anyPartFailed*/, messageUri, null/*smsHeader*/, expectMore, fullMessageText, isText, persistMessage, priority, validityPeriod, - isForVvm, messageId); + isForVvm, messageId, messageRef); } protected HashMap getSmsTrackerMap(String destAddr, String scAddr, diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java index 53556ac9f7..04927edd90 100644 --- a/src/java/com/android/internal/telephony/SmsDispatchersController.java +++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java @@ -503,7 +503,8 @@ public class SmsDispatchersController extends Handler { scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null); } else { pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu( - scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null); + scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null, + 0, 0, 0, -1, tracker.mMessageRef); } } else if (map.containsKey("data")) { byte[] data = (byte[]) map.get("data"); @@ -518,7 +519,7 @@ public class SmsDispatchersController extends Handler { } else { pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu( scAddr, destAddr, destPort.intValue(), data, - (tracker.mDeliveryIntent != null)); + (tracker.mDeliveryIntent != null), tracker.mMessageRef); } } diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 2dbda5a623..e868df0c8f 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -4740,6 +4740,63 @@ public class SubscriptionController extends ISub.Stub { return ret; } + /** + * Querying last used TP - MessageRef for particular subId from SIMInfo table. + * @return messageRef + */ + public int getMessageRef(int subId) { + try (Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, + new String[]{SubscriptionManager.TP_MESSAGE_REF}, + SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=\"" + subId + + "\"", null, null)) { + try { + if (cursor != null && cursor.moveToFirst()) { + do { + return cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.TP_MESSAGE_REF)); + } while (cursor.moveToNext()); + } else { + if (DBG) logd("Valid row not present in db"); + } + } catch (Exception e) { + if (DBG) logd("Query failed " + e.getMessage()); + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + return -1; + } + + /** + * Update the TP - Message Reference value for every SMS Sent + * @param messageRef + * @param subId + */ + public void updateMessageRef(int subId, int messageRef) { + TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege( + mContext, subId, mContext.getOpPackageName()); + + if (mContext == null) { + logel("[updateMessageRef] mContext is null"); + return; + } + try { + if (SubscriptionManager.CONTENT_URI != null) { + ContentValues values = new ContentValues(1); + values.put(SubscriptionManager.TP_MESSAGE_REF, messageRef); + mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, values, + SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=\"" + subId + + "\"", null); + } else { + if (DBG) logd("TP - Message reference value not updated to DB"); + } + } finally { + if (DBG) logd("TP - Message reference updated to DB Successfully :" + messageRef); + } + } + /** * @hide */ diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java index 782f78e19e..16e1c7a6e9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java +++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java @@ -123,6 +123,8 @@ public class FakeTelephonyProvider extends MockContentProvider { + Telephony.SimInfo.COLUMN_PORT_INDEX + " INTEGER DEFAULT -1," + Telephony.SimInfo.COLUMN_USAGE_SETTING + " INTEGER DEFAULT " + SubscriptionManager.USAGE_SETTING_UNKNOWN + + "," + Telephony.SimInfo.COLUMN_TP_MESSAGE_REF + + " INTEGER DEFAULT -1" + ");"; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java index 62515607aa..fd1c5e0007 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java @@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -225,4 +226,74 @@ public class ImsSmsDispatcherTest extends TelephonyTest { ImsSmsImplBase.SEND_STATUS_ERROR, 0, 41); verify(mSmsTracker).onFailed(any(Context.class), anyInt(), eq(41)); } + + @Test + public void testSendSmswithMessageRef() throws Exception { + int token = mImsSmsDispatcher.mNextToken.get(); + int messageRef = mImsSmsDispatcher.nextMessageRef() + 1; + + when(mImsManager.getSmsFormat()).thenReturn(SmsMessage.FORMAT_3GPP); + when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM); + doReturn(mSmsUsageMonitor).when(mSmsDispatchersController).getUsageMonitor(); + + mImsSmsDispatcher.sendText("+15555551212", null, "MessageRef test", + null, null, null, null, false, + -1, false, -1, false, 0); + verify(mImsManager).sendSms(eq(token + 1), eq(messageRef), eq(SmsMessage.FORMAT_3GPP), + nullable(String.class), eq(false), (byte[]) any()); + } + + @Test + public void testFallbackGsmRetrywithMessageRef() throws Exception { + int token = mImsSmsDispatcher.mNextToken.get(); + int messageRef = mImsSmsDispatcher.nextMessageRef() + 1; + + when(mImsManager.getSmsFormat()).thenReturn(SmsMessage.FORMAT_3GPP); + when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM); + doReturn(mSmsUsageMonitor).when(mSmsDispatchersController).getUsageMonitor(); + + mImsSmsDispatcher.sendText("+15555551212", null, "MessageRef test", + null, null, null, null, false, + -1, false, -1, false, 0); + verify(mImsManager).sendSms(eq(token + 1), eq(messageRef), eq(SmsMessage.FORMAT_3GPP), + nullable(String.class), eq(false), (byte[]) any()); + + mImsSmsDispatcher.getSmsListener().onSendSmsResult(token + 1, messageRef, + ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK, 0, SmsResponse.NO_ERROR_CODE); + processAllMessages(); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(SMSDispatcher.SmsTracker.class); + verify(mSmsDispatchersController).sendRetrySms(captor.capture()); + assertTrue(messageRef + 1 == captor.getValue().mMessageRef); + } + + @Test + public void testErrorImsRetrywithMessageRef() throws Exception { + int token = mImsSmsDispatcher.mNextToken.get(); + int messageRef = mImsSmsDispatcher.nextMessageRef() + 1; + when(mImsManager.getSmsFormat()).thenReturn(SmsMessage.FORMAT_3GPP); + when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM); + doReturn(mSmsUsageMonitor).when(mSmsDispatchersController).getUsageMonitor(); + + mImsSmsDispatcher.sendText("+15555551212", null, "MessageRef test", + null, null, null, null, false, + -1, false, -1, false, 0); + verify(mImsManager).sendSms(eq(token + 1), eq(messageRef), eq(SmsMessage.FORMAT_3GPP), + nullable(String.class), eq(false), (byte[]) any()); + + // Retry over IMS + mImsSmsDispatcher.getSmsListener().onSendSmsResult(token + 1, messageRef, + ImsSmsImplBase.SEND_STATUS_ERROR_RETRY, 0, SmsResponse.NO_ERROR_CODE); + waitForMs(SMSDispatcher.SEND_RETRY_DELAY + 200); + processAllMessages(); + + // Make sure tpmr value is same and retry bit set + ArgumentCaptor byteCaptor = ArgumentCaptor.forClass(byte[].class); + verify(mImsManager).sendSms(eq(token + 2), eq(messageRef), eq(SmsMessage.FORMAT_3GPP), + nullable(String.class), eq(true), byteCaptor.capture()); + byte[] pdu = byteCaptor.getValue(); + assertEquals(pdu[1], messageRef); + assertEquals(0x04, (pdu[0] & 0x04)); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index 6a4c9c2010..54feef2469 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -2054,4 +2054,16 @@ public class SubscriptionControllerTest extends TelephonyTest { assertTrue(mSubscriptionControllerUT.checkPhoneIdAndIccIdMatch(0, "test2")); assertFalse(mSubscriptionControllerUT.checkPhoneIdAndIccIdMatch(0, "test3")); } + + @Test + @SmallTest + public void testMessageRefDBFetchAndUpdate() throws Exception { + testInsertSim(); + int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); + assertTrue(subIds != null && subIds.length != 0); + final int subId = subIds[0]; + SubscriptionController.getInstance().updateMessageRef(subId, 201); + int messageRef = SubscriptionController.getInstance().getMessageRef(subId); + assertTrue("201 :", messageRef == 201); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java index 19cacf06f8..23aa083f1d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java @@ -66,9 +66,12 @@ import com.android.internal.telephony.ContextFixture; import com.android.internal.telephony.ISub; import com.android.internal.telephony.SMSDispatcher; import com.android.internal.telephony.SmsDispatchersController; +import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.TelephonyTestUtils; import com.android.internal.telephony.TestApplication; +import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.uicc.IsimUiccRecords; import org.junit.After; import org.junit.Before; @@ -503,4 +506,75 @@ public class GsmSmsDispatcherTest extends TelephonyTest { verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class)); } + + + @Test + public void testSendTextWithMessageRef() throws Exception { + int messageRef = mGsmSmsDispatcher.nextMessageRef() + 1; + mGsmSmsDispatcher.sendText("111", "222" /*scAddr*/, TAG, + null, null, null, null, false, -1, false, -1, false, 0L); + + ArgumentCaptor pduCaptor = ArgumentCaptor.forClass(String.class); + verify(mSimulatedCommandsVerifier).sendSMS(anyString(), pduCaptor.capture(), + any(Message.class)); + byte[] pdu = IccUtils.hexStringToBytes(pduCaptor.getValue()); + assertEquals(pdu[1], messageRef); + } + + @Test + public void testSendMultipartWithMessageRef() throws Exception { + ArrayList parts = new ArrayList<>(); + parts.add("segment1"); + parts.add("segment2"); + parts.add("segment3"); + int messageRef = mGsmSmsDispatcher.nextMessageRef() + parts.size(); + mGsmSmsDispatcher.sendMultipartText("6501002000" /*destAddr*/, "222" /*scAddr*/, parts, + null, null, null, null, false, -1, false, -1, 0L); + waitForMs(150); + ArgumentCaptor pduCaptor = ArgumentCaptor.forClass(String.class); + + verify(mSimulatedCommandsVerifier, times(parts.size() - 1)).sendSMSExpectMore(anyString(), + anyString(), + any(Message.class)); + verify(mSimulatedCommandsVerifier).sendSMS(anyString(), pduCaptor.capture(), + any(Message.class)); + byte[] pdu = IccUtils.hexStringToBytes(pduCaptor.getValue()); + assertEquals(pdu[1], messageRef); + } + + @Test + public void testSendTextWithMessageRefNegativeBoundaryCondition() throws Exception { + mIsimUiccRecords = new IsimUiccRecords(mUiccCardApplication3gpp, mContext, + mSimulatedCommands); + doReturn(mIsimUiccRecords).when(mPhone).getIccRecords(); + Message msg = mGsmSmsDispatcher.obtainMessage(17); + mPhone.getIccRecords().setSmssTpmrValue(-1, msg); + SubscriptionController.getInstance().updateMessageRef(mPhone.getSubId(), -1); + mGsmSmsDispatcher.sendText("111", "222" /*scAddr*/, TAG, + null, null, null, null, false, -1, false, -1, false, 0L); + + ArgumentCaptor pduCaptor1 = ArgumentCaptor.forClass(String.class); + verify(mSimulatedCommandsVerifier).sendSMS(anyString(), pduCaptor1.capture(), + any(Message.class)); + byte[] pdu1 = IccUtils.hexStringToBytes(pduCaptor1.getValue()); + assertEquals(pdu1[1], 0); + } + + @Test + public void testSendTextWithMessageRefMaxBoundaryCondition() throws Exception { + mIsimUiccRecords = new IsimUiccRecords(mUiccCardApplication3gpp, mContext, + mSimulatedCommands); + doReturn(mIsimUiccRecords).when(mPhone).getIccRecords(); + Message msg = mGsmSmsDispatcher.obtainMessage(17); + + mPhone.getIccRecords().setSmssTpmrValue(255, null); + mGsmSmsDispatcher.sendText("111", "222" /*scAddr*/, TAG, + null, null, null, null, false, -1, false, -1, false, 0L); + + ArgumentCaptor pduCaptor2 = ArgumentCaptor.forClass(String.class); + verify(mSimulatedCommandsVerifier).sendSMS(anyString(), pduCaptor2.capture(), + any(Message.class)); + byte[] pdu2 = IccUtils.hexStringToBytes(pduCaptor2.getValue()); + assertEquals(pdu2[1], 0); + } } -- GitLab From b45853e3db2c9cf33ff53821f8566a5144c2741b Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 26 Jan 2022 14:39:51 +0000 Subject: [PATCH 033/656] Implement the domain selection of supplementary services over Ut The keys of Carrier config and the state of transport layer are used to determine the UT capability. The following keys are used: - KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL - ImsSs.KEY_UT_REQUIRES_IMS_REGISTRATION_BOOL - ImsSs.KEY_UT_SERVER_BASED_SERVICES_INT_ARRAY - ImsSs.KEY_UT_SUPPORTED_WHEN_PS_DATA_OFF_BOOL - ImsSs.KEY_UT_SUPPORTED_WHEN_ROAMING_BOOL - ImsSs.KEY_USE_CSFB_ON_XCAP_OVER_UT_FAILURE_BOOL - ImsSs.KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY Bug: 202463163 Test: atest Change-Id: Ice627a3c8dd4ec9d69e18ad426cb703096834bd5 (cherry picked from commit 7addc57c93951af3651492706bcb13339d479ba4) Merged-In: Ice627a3c8dd4ec9d69e18ad426cb703096834bd5 --- .../internal/telephony/GsmCdmaPhone.java | 187 ++++-- .../com/android/internal/telephony/Phone.java | 12 +- .../telephony/SsDomainController.java | 566 ++++++++++++++++++ .../internal/telephony/gsm/GsmMmiCode.java | 15 + .../telephony/imsphone/ImsPhoneMmiCode.java | 74 ++- .../internal/telephony/GsmCdmaPhoneTest.java | 147 +++++ .../telephony/SsDomainControllerTest.java | 475 +++++++++++++++ .../internal/telephony/TelephonyTest.java | 2 + .../imsphone/ImsPhoneMmiCodeTest.java | 32 + 9 files changed, 1439 insertions(+), 71 deletions(-) create mode 100644 src/java/com/android/internal/telephony/SsDomainController.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 67ec97276a..0c56c4027a 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -29,6 +29,9 @@ import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REA import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; +import static com.android.internal.telephony.SsDomainController.SS_CLIP; +import static com.android.internal.telephony.SsDomainController.SS_CLIR; +import static com.android.internal.telephony.SsDomainController.SS_CW; import android.annotation.NonNull; import android.annotation.Nullable; @@ -264,6 +267,8 @@ public class GsmCdmaPhone extends Phone { private boolean mResetModemOnRadioTechnologyChange = false; private boolean mSsOverCdmaSupported = false; + private SsDomainController mSsDomainController; + private int mRilVersion; private boolean mBroadcastEmergencyCallStateChanges = false; private @ServiceState.RegState int mTelecomVoiceServiceStateOverride = @@ -399,6 +404,8 @@ public class GsmCdmaPhone extends Phone { subMan.addOnSubscriptionsChangedListener( new HandlerExecutor(this), mSubscriptionsChangedListener); + mSsDomainController = new SsDomainController(this); + logd("GsmCdmaPhone: constructor: sub = " + mPhoneId); } @@ -1464,9 +1471,10 @@ public class GsmCdmaPhone extends Phone { stripSeparators(dialString)); boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#")) && dialPart.endsWith("#"); - boolean isSuppServiceCode = ImsPhoneMmiCode.isSuppServiceCodes(dialPart, this); - boolean isPotentialUssdCode = isMmiCode && !isSuppServiceCode; - boolean useImsForUt = imsPhone != null && imsPhone.isUtEnabled(); + SsDomainController.SuppServiceRoutingInfo ssInfo = + ImsPhoneMmiCode.getSuppServiceRoutingInfo(dialPart, this); + boolean isPotentialUssdCode = isMmiCode && (ssInfo == null); + boolean useImsForUt = ssInfo != null && ssInfo.useSsOverUt(); boolean useImsForCall = useImsForCall(dialArgs) && (isWpsCall ? allowWpsOverIms : true); @@ -1477,7 +1485,8 @@ public class GsmCdmaPhone extends Phone { + ", useImsForEmergency=" + useImsForEmergency + ", useImsForUt=" + useImsForUt + ", isUt=" + isMmiCode - + ", isSuppServiceCode=" + isSuppServiceCode + + ", isSuppServiceCode=" + (ssInfo != null) + + ", useSsOverUt=" + (ssInfo != null && ssInfo.useSsOverUt()) + ", isPotentialUssdCode=" + isPotentialUssdCode + ", isWpsCall=" + isWpsCall + ", allowWpsOverIms=" + allowWpsOverIms @@ -1533,6 +1542,10 @@ public class GsmCdmaPhone extends Phone { } } + if (ssInfo != null && !ssInfo.supportsCsfb()) { + throw new CallStateException("not support csfb for supplementary services"); + } + if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE && mSST.mSS.getDataRegistrationState() != ServiceState.STATE_IN_SERVICE && !isEmergency) { @@ -2323,12 +2336,36 @@ public class GsmCdmaPhone extends Phone { mSsOverCdmaSupported = b.getBoolean(CarrierConfigManager.KEY_SUPPORT_SS_OVER_CDMA_BOOL); } + private void updateSsOverUtConfig(PersistableBundle b) { + mSsDomainController.updateSsOverUtConfig(b); + } + @Override - public boolean useSsOverIms(Message onComplete) { + public SsDomainController getSsDomainController() { + return mSsDomainController; + } + + /** Checks the static configuration for the given Call Barring service. */ + public boolean useCbOverUt(String facility) { + return mSsDomainController.useCbOverUt(facility); + } + + /** Checks the static configuration for the given Call Forwarding service. */ + public boolean useCfOverUt(int reason) { + return mSsDomainController.useCfOverUt(reason); + } + + /** Checks the static configuration for the given supplementary service. */ + public boolean useSsOverUt(String service) { + return mSsDomainController.useSsOverUt(service); + } + + @Override + public boolean useSsOverUt(Message onComplete) { boolean isUtEnabled = isUtEnabled(); - Rlog.d(LOG_TAG, "useSsOverIms: isUtEnabled()= " + isUtEnabled + - " isCsRetry(onComplete))= " + isCsRetry(onComplete)); + Rlog.d(LOG_TAG, "useSsOverUt: isUtEnabled()= " + isUtEnabled + + " isCsRetry(onComplete))= " + isCsRetry(onComplete)); if (isUtEnabled && !isCsRetry(onComplete)) { return true; @@ -2336,6 +2373,24 @@ public class GsmCdmaPhone extends Phone { return false; } + /** + * Returns whether CSFB is supported for supplementary services. + */ + public boolean supportCsfbForSs() { + return mSsDomainController.supportCsfb(); + } + + /** + * Sends response indicating no nework is available for supplementary services. + */ + private void responseInvalidState(Message onComplete) { + if (onComplete == null) return; + AsyncResult.forMessage(onComplete, null, + new CommandException(CommandException.Error.INVALID_STATE, + "No network available for supplementary services")); + onComplete.sendToTarget(); + } + @Override public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { getCallForwardingOption(commandInterfaceCFReason, @@ -2355,9 +2410,15 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverIms(onComplete)) { - imsPhone.getCallForwardingOption(commandInterfaceCFReason, serviceClass, onComplete); - return; + if (useCfOverUt(commandInterfaceCFReason)) { + if (useSsOverUt(onComplete)) { + imsPhone.getCallForwardingOption(commandInterfaceCFReason, + serviceClass, onComplete); + return; + } else if (!supportCsfbForSs()) { + responseInvalidState(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2414,10 +2475,15 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverIms(onComplete)) { - imsPhone.setCallForwardingOption(commandInterfaceCFAction, commandInterfaceCFReason, - dialingNumber, serviceClass, timerSeconds, onComplete); - return; + if (useCfOverUt(commandInterfaceCFReason)) { + if (useSsOverUt(onComplete)) { + imsPhone.setCallForwardingOption(commandInterfaceCFAction, commandInterfaceCFReason, + dialingNumber, serviceClass, timerSeconds, onComplete); + return; + } else if (!supportCsfbForSs()) { + responseInvalidState(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2476,9 +2542,14 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverIms(onComplete)) { - imsPhone.getCallBarring(facility, password, onComplete, serviceClass); - return; + if (useCbOverUt(facility)) { + if (useSsOverUt(onComplete)) { + imsPhone.getCallBarring(facility, password, onComplete, serviceClass); + return; + } else if (!supportCsfbForSs()) { + responseInvalidState(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2503,9 +2574,14 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverIms(onComplete)) { - imsPhone.setCallBarring(facility, lockState, password, onComplete, serviceClass); - return; + if (useCbOverUt(facility)) { + if (useSsOverUt(onComplete)) { + imsPhone.setCallBarring(facility, lockState, password, onComplete, serviceClass); + return; + } else if (!supportCsfbForSs()) { + responseInvalidState(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2555,9 +2631,14 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverIms(onComplete)) { - imsPhone.getOutgoingCallerIdDisplay(onComplete); - return; + if (useSsOverUt(SS_CLIR)) { + if (useSsOverUt(onComplete)) { + imsPhone.getOutgoingCallerIdDisplay(onComplete); + return; + } else if (!supportCsfbForSs()) { + responseInvalidState(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2582,9 +2663,14 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverIms(onComplete)) { - imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete); - return; + if (useSsOverUt(SS_CLIR)) { + if (useSsOverUt(onComplete)) { + imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete); + return; + } else if (!supportCsfbForSs()) { + responseInvalidState(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2612,9 +2698,14 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverIms(onComplete)) { - imsPhone.queryCLIP(onComplete); - return; + if (useSsOverUt(SS_CLIP)) { + if (useSsOverUt(onComplete)) { + imsPhone.queryCLIP(onComplete); + return; + } else if (!supportCsfbForSs()) { + responseInvalidState(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2638,9 +2729,14 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverIms(onComplete)) { - imsPhone.getCallWaiting(onComplete); - return; + if (useSsOverUt(SS_CW)) { + if (useSsOverUt(onComplete)) { + imsPhone.getCallWaiting(onComplete); + return; + } else if (!supportCsfbForSs()) { + responseInvalidState(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2689,9 +2785,14 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverIms(onComplete)) { - imsPhone.setCallWaiting(enable, onComplete); - return; + if (useSsOverUt(SS_CW)) { + if (useSsOverUt(onComplete)) { + imsPhone.setCallWaiting(enable, onComplete); + return; + } else if (!supportCsfbForSs()) { + responseInvalidState(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -3176,6 +3277,7 @@ public class GsmCdmaPhone extends Phone { updateVoNrSettings(b); updateSsOverCdmaSupported(b); loadAllowedNetworksFromSubscriptionDatabase(); + updateSsOverUtConfig(b); // Obtain new radio capabilities from the modem, since some are SIM-dependent mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY)); break; @@ -4399,6 +4501,13 @@ public class GsmCdmaPhone extends Phone { + ServiceState.rilServiceStateToString(mTelecomVoiceServiceStateOverride) + ")"); pw.flush(); + + try { + mSsDomainController.dump(pw); + } catch (Exception e) { + e.printStackTrace(); + } + pw.flush(); } @Override @@ -4695,13 +4804,7 @@ public class GsmCdmaPhone extends Phone { @Override public boolean isUtEnabled() { - Phone imsPhone = mImsPhone; - if (imsPhone != null) { - return imsPhone.isUtEnabled(); - } else { - logd("isUtEnabled: called for GsmCdma"); - return false; - } + return mSsDomainController.isUtEnabled(); } public String getDtmfToneDelayKey() { diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 2be5bc84e9..d00c8f5044 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -4865,7 +4865,17 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } - public boolean useSsOverIms(Message onComplete) { + /** + * Returns the instance of SsDomainController + */ + public SsDomainController getSsDomainController() { + return null; + } + + /** + * Returns whether it will be served with Ut or not. + */ + public boolean useSsOverUt(Message onComplete) { return false; } diff --git a/src/java/com/android/internal/telephony/SsDomainController.java b/src/java/com/android/internal/telephony/SsDomainController.java new file mode 100644 index 0000000000..4fb75e4b48 --- /dev/null +++ b/src/java/com/android/internal/telephony/SsDomainController.java @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2022 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; + +import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.GERAN; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.IWLAN; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_ACR; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_ALL; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BAIC; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BAOC; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BIC_ROAM; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BIL; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BOIC; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BOIC_EXHC; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_IBS; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_OBS; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_ALL; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_ALL_CONDITONAL_FORWARDING; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFB; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFNRC; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFNRY; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFU; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CW; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIP; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIP; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIR; + +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOIC; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOICxH; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.PersistableBundle; +import android.os.SystemProperties; +import android.provider.Settings; +import android.telephony.AccessNetworkConstants; +import android.telephony.CarrierConfigManager; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; +import com.android.telephony.Rlog; + +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * The cache of the carrier configuration + */ +public class SsDomainController { + private static final String LOG_TAG = "SsDomainController"; + + /** + * A Helper class to carry the information indicating Ut is available or not. + */ + public static class SuppServiceRoutingInfo { + private final boolean mUseSsOverUt; + private final boolean mSupportsCsfb; + + public SuppServiceRoutingInfo(boolean useSsOverUt, + boolean isUtEnabled, boolean supportsCsfb) { + if (useSsOverUt) { + mUseSsOverUt = isUtEnabled; + mSupportsCsfb = supportsCsfb; + } else { + mUseSsOverUt = false; + mSupportsCsfb = true; + } + } + + /** + * Returns whether Ut is available. + */ + public boolean useSsOverUt() { + return mUseSsOverUt; + } + + /** + * Returns whether CSFB is allowed. + */ + public boolean supportsCsfb() { + return mSupportsCsfb; + } + } + + public static final String SS_CW = "CW"; + public static final String SS_CLIP = "CLIP"; + public static final String SS_CLIR = "CLIR"; + public static final String SS_COLP = "COLP"; + public static final String SS_COLR = "COLR"; + + // Common instance indicating that Ut is available. + public static final SuppServiceRoutingInfo SS_ROUTING_OVER_UT = + new SuppServiceRoutingInfo(true, true, true); + + // Barring list of incoming numbers + public static final String CB_FACILITY_BIL = "BIL"; + // Barring of all anonymous incoming number + public static final String CB_FACILITY_ACR = "ACR"; + + /** + * Network callback used to determine whether Wi-Fi is connected or not. + */ + private ConnectivityManager.NetworkCallback mNetworkCallback = + new ConnectivityManager.NetworkCallback() { + @Override + public void onAvailable(Network network) { + Rlog.i(LOG_TAG, "Network available: " + network); + updateWifiForUt(true); + } + + @Override + public void onLost(Network network) { + Rlog.i(LOG_TAG, "Network lost: " + network); + updateWifiForUt(false); + } + + @Override + public void onUnavailable() { + Rlog.i(LOG_TAG, "Network unavailable"); + updateWifiForUt(false); + } + }; + + private final GsmCdmaPhone mPhone; + + private final HashSet mCbOverUtSupported = new HashSet<>(); + private final HashSet mCfOverUtSupported = new HashSet<>(); + private final HashSet mSsOverUtSupported = new HashSet<>(); + private boolean mUtSupported = false; + private boolean mCsfbSupported = true; + + private boolean mUtRequiresImsRegistration = false; + private boolean mUtAvailableWhenPsDataOff = false; + private boolean mUtAvailableWhenRoaming = false; + private Set mUtAvailableRats = new HashSet<>(); + private boolean mWiFiAvailable = false; + private boolean mIsMonitoringConnectivity = false; + + public SsDomainController(GsmCdmaPhone phone) { + mPhone = phone; + } + + /** + * Cache the configurations + */ + public void updateSsOverUtConfig(PersistableBundle b) { + if (b == null) { + b = CarrierConfigManager.getDefaultConfig(); + } + + boolean supportsCsfb = b.getBoolean( + CarrierConfigManager.ImsSs.KEY_USE_CSFB_ON_XCAP_OVER_UT_FAILURE_BOOL); + boolean requiresImsRegistration = b.getBoolean( + CarrierConfigManager.ImsSs.KEY_UT_REQUIRES_IMS_REGISTRATION_BOOL); + boolean availableWhenPsDataOff = b.getBoolean( + CarrierConfigManager.ImsSs.KEY_UT_SUPPORTED_WHEN_PS_DATA_OFF_BOOL); + boolean availableWhenRoaming = b.getBoolean( + CarrierConfigManager.ImsSs.KEY_UT_SUPPORTED_WHEN_ROAMING_BOOL); + + boolean supportsUt = b.getBoolean( + CarrierConfigManager.KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL); + int[] services = b.getIntArray( + CarrierConfigManager.ImsSs.KEY_UT_SERVER_BASED_SERVICES_INT_ARRAY); + + int[] utRats = b.getIntArray( + CarrierConfigManager.ImsSs.KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY); + + updateSsOverUtConfig(supportsUt, supportsCsfb, requiresImsRegistration, + availableWhenPsDataOff, availableWhenRoaming, services, utRats); + } + + private void updateSsOverUtConfig(boolean supportsUt, boolean supportsCsfb, + boolean requiresImsRegistration, boolean availableWhenPsDataOff, + boolean availableWhenRoaming, int[] services, int[] utRats) { + + mUtSupported = supportsUt; + mCsfbSupported = supportsCsfb; + mUtRequiresImsRegistration = requiresImsRegistration; + mUtAvailableWhenPsDataOff = availableWhenPsDataOff; + mUtAvailableWhenRoaming = availableWhenRoaming; + + mCbOverUtSupported.clear(); + mCfOverUtSupported.clear(); + mSsOverUtSupported.clear(); + mUtAvailableRats.clear(); + + if (!mUtSupported) { + Rlog.d(LOG_TAG, "updateSsOverUtConfig Ut is not supported"); + unregisterForConnectivityChanges(); + return; + } + + if (services != null) { + for (int service : services) { + updateConfig(service); + } + } + + if (utRats != null) { + mUtAvailableRats = Arrays.stream(utRats).boxed().collect(Collectors.toSet()); + } + + if (mUtAvailableRats.contains(IWLAN)) { + registerForConnectivityChanges(); + } else { + unregisterForConnectivityChanges(); + } + + Rlog.i(LOG_TAG, "updateSsOverUtConfig supportsUt=" + mUtSupported + + ", csfb=" + mCsfbSupported + + ", regRequire=" + mUtRequiresImsRegistration + + ", whenPsDataOff=" + mUtAvailableWhenPsDataOff + + ", whenRoaming=" + mUtAvailableWhenRoaming + + ", cbOverUtSupported=" + mCbOverUtSupported + + ", cfOverUtSupported=" + mCfOverUtSupported + + ", ssOverUtSupported=" + mSsOverUtSupported + + ", utAvailableRats=" + mUtAvailableRats + + ", including IWLAN=" + mUtAvailableRats.contains(IWLAN)); + } + + private void updateConfig(int service) { + switch(service) { + case SUPPLEMENTARY_SERVICE_CW: mSsOverUtSupported.add(SS_CW); return; + + case SUPPLEMENTARY_SERVICE_CF_ALL: mCfOverUtSupported.add(CF_REASON_ALL); return; + case SUPPLEMENTARY_SERVICE_CF_CFU: + mCfOverUtSupported.add(CF_REASON_UNCONDITIONAL); + return; + case SUPPLEMENTARY_SERVICE_CF_ALL_CONDITONAL_FORWARDING: + mCfOverUtSupported.add(CF_REASON_ALL_CONDITIONAL); + return; + case SUPPLEMENTARY_SERVICE_CF_CFB: mCfOverUtSupported.add(CF_REASON_BUSY); return; + case SUPPLEMENTARY_SERVICE_CF_CFNRY: mCfOverUtSupported.add(CF_REASON_NO_REPLY); return; + case SUPPLEMENTARY_SERVICE_CF_CFNRC: + mCfOverUtSupported.add(CF_REASON_NOT_REACHABLE); + return; + + case SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIP: mSsOverUtSupported.add(SS_CLIP); return; + case SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIP: mSsOverUtSupported.add(SS_COLP); return; + case SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR: mSsOverUtSupported.add(SS_CLIR); return; + case SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIR: mSsOverUtSupported.add(SS_COLR); return; + + case SUPPLEMENTARY_SERVICE_CB_BAOC: mCbOverUtSupported.add(CB_FACILITY_BAOC); return; + case SUPPLEMENTARY_SERVICE_CB_BOIC: mCbOverUtSupported.add(CB_FACILITY_BAOIC); return; + case SUPPLEMENTARY_SERVICE_CB_BOIC_EXHC: + mCbOverUtSupported.add(CB_FACILITY_BAOICxH); + return; + case SUPPLEMENTARY_SERVICE_CB_BAIC: mCbOverUtSupported.add(CB_FACILITY_BAIC); return; + case SUPPLEMENTARY_SERVICE_CB_BIC_ROAM: + mCbOverUtSupported.add(CB_FACILITY_BAICr); + return; + case SUPPLEMENTARY_SERVICE_CB_ACR: mCbOverUtSupported.add(CB_FACILITY_ACR); return; + case SUPPLEMENTARY_SERVICE_CB_BIL: mCbOverUtSupported.add(CB_FACILITY_BIL); return; + case SUPPLEMENTARY_SERVICE_CB_ALL: mCbOverUtSupported.add(CB_FACILITY_BA_ALL); return; + case SUPPLEMENTARY_SERVICE_CB_OBS: mCbOverUtSupported.add(CB_FACILITY_BA_MO); return; + case SUPPLEMENTARY_SERVICE_CB_IBS: mCbOverUtSupported.add(CB_FACILITY_BA_MT); return; + + default: + break; + } + } + + /** + * Determines whether Ut service is available or not. + * + * @return {@code true} if Ut service is available + */ + @VisibleForTesting + public boolean isUtEnabled() { + Phone imsPhone = mPhone.getImsPhone(); + if (imsPhone == null) { + Rlog.d(LOG_TAG, "isUtEnabled: called for GsmCdma"); + return false; + } + + if (!mUtSupported) { + Rlog.d(LOG_TAG, "isUtEnabled: not supported"); + return false; + } + + if (mUtRequiresImsRegistration + && imsPhone.getServiceState().getState() != ServiceState.STATE_IN_SERVICE) { + Rlog.d(LOG_TAG, "isUtEnabled: not registered"); + return false; + } + + if (isUtAvailableOnAnyTransport()) { + return imsPhone.isUtEnabled(); + } + + return false; + } + + private boolean isMobileDataEnabled() { + boolean enabled; + int state = Settings.Global.getInt(mPhone.getContext().getContentResolver(), + Settings.Global.MOBILE_DATA, -1); + if (state == -1) { + Rlog.i(LOG_TAG, "isMobileDataEnabled MOBILE_DATA not found"); + enabled = "true".equalsIgnoreCase( + SystemProperties.get("ro.com.android.mobiledata", "true")); + } else { + enabled = (state != 0); + } + Rlog.i(LOG_TAG, "isMobileDataEnabled enabled=" + enabled); + return enabled; + } + + private boolean isUtAvailableOnAnyTransport() { + if (mUtAvailableWhenPsDataOff || isMobileDataEnabled()) { + if (isUtAvailableOverCellular()) { + Rlog.i(LOG_TAG, "isUtAvailableOnAnyTransport found cellular"); + return true; + } + } + + Rlog.i(LOG_TAG, "isUtAvailableOnAnyTransport wifiConnected=" + mWiFiAvailable); + if (mWiFiAvailable) { + if (mUtAvailableRats.contains(IWLAN)) { + Rlog.i(LOG_TAG, "isUtAvailableOnAnyTransport found wifi"); + return true; + } + Rlog.i(LOG_TAG, "isUtAvailableOnAnyTransport wifi not support Ut"); + } + + Rlog.i(LOG_TAG, "isUtAvailableOnAnyTransport no transport"); + return false; + } + + private boolean isUtAvailableOverCellular() { + NetworkRegistrationInfo nri = mPhone.getServiceState().getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (nri != null && nri.isRegistered()) { + if (!mUtAvailableWhenRoaming && nri.isRoaming()) { + Rlog.i(LOG_TAG, "isUtAvailableOverCellular not available in roaming"); + return false; + } + + int networkType = nri.getAccessNetworkTechnology(); + switch (networkType) { + case TelephonyManager.NETWORK_TYPE_NR: + if (mUtAvailableRats.contains(NGRAN)) return true; + break; + case TelephonyManager.NETWORK_TYPE_LTE: + if (mUtAvailableRats.contains(EUTRAN)) return true; + break; + + case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + case TelephonyManager.NETWORK_TYPE_HSPAP: + if (mUtAvailableRats.contains(UTRAN)) return true; + break; + case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_GSM: + if (mUtAvailableRats.contains(GERAN)) return true; + break; + default: + break; + } + } + + Rlog.i(LOG_TAG, "isUtAvailableOverCellular no cellular"); + return false; + } + + /** + * Updates the Wi-Fi connection state. + */ + @VisibleForTesting + public void updateWifiForUt(boolean available) { + mWiFiAvailable = available; + } + + /** + * Registers for changes to network connectivity. + */ + private void registerForConnectivityChanges() { + if (mIsMonitoringConnectivity) { + return; + } + + ConnectivityManager cm = (ConnectivityManager) mPhone.getContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + if (cm != null) { + Rlog.i(LOG_TAG, "registerForConnectivityChanges"); + NetworkRequest.Builder builder = new NetworkRequest.Builder(); + builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + cm.registerNetworkCallback(builder.build(), mNetworkCallback); + mIsMonitoringConnectivity = true; + } + } + + /** + * Unregisters for connectivity changes. + */ + private void unregisterForConnectivityChanges() { + if (!mIsMonitoringConnectivity) { + return; + } + + ConnectivityManager cm = (ConnectivityManager) mPhone.getContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + if (cm != null) { + Rlog.i(LOG_TAG, "unregisterForConnectivityChanges"); + cm.unregisterNetworkCallback(mNetworkCallback); + mIsMonitoringConnectivity = false; + } + } + + /** + * Returns whether Ut is available for the given Call Barring service. + */ + @VisibleForTesting + public boolean useCbOverUt(String facility) { + if (!mUtSupported) { + Rlog.d(LOG_TAG, "useCbOverUt: Ut not supported"); + return false; + } + + return mCbOverUtSupported.contains(facility); + } + + /** + * Returns whether Ut is available for the given Call Forwarding service. + */ + @VisibleForTesting + public boolean useCfOverUt(int reason) { + if (!mUtSupported) { + Rlog.d(LOG_TAG, "useCfOverUt: Ut not supported"); + return false; + } + + return mCfOverUtSupported.contains(reason); + } + + /** + * Returns whether Ut is available for the given supplementary service. + */ + @VisibleForTesting + public boolean useSsOverUt(String service) { + if (!mUtSupported) { + Rlog.d(LOG_TAG, "useSsOverUt: Ut not supported"); + return false; + } + + return mSsOverUtSupported.contains(service); + } + + /** + * Returns whether CSFB is supported for supplementary services. + */ + public boolean supportCsfb() { + if (!mUtSupported) { + Rlog.d(LOG_TAG, "supportsCsfb: Ut not supported"); + return true; + } + + return mCsfbSupported; + } + + /** + * Returns SuppServiceRoutingInfo instance for the given Call Barring service. + * Only for ImsPhoneMmiCode. + */ + public SuppServiceRoutingInfo getSuppServiceRoutingInfoForCb(String facility) { + return new SuppServiceRoutingInfo(useCbOverUt(facility), isUtEnabled(), supportCsfb()); + } + + /** + * Returns SuppServiceRoutingInfo instance for the given Call Forwarding service. + * Only for ImsPhoneMmiCode. + */ + public SuppServiceRoutingInfo getSuppServiceRoutingInfoForCf(int reason) { + return new SuppServiceRoutingInfo(useCfOverUt(reason), isUtEnabled(), supportCsfb()); + } + + /** + * Returns SuppServiceRoutingInfo instance for the given supplementary service. + * Only for ImsPhoneMmiCode. + */ + public SuppServiceRoutingInfo getSuppServiceRoutingInfoForSs(String service) { + return new SuppServiceRoutingInfo(useSsOverUt(service), isUtEnabled(), supportCsfb()); + } + + /** + * Set the carrier configuration for test. + * Test purpose only. + */ + @VisibleForTesting + public void updateCarrierConfigForTest(boolean supportsUt, boolean supportsCsfb, + boolean requiresImsRegistration, boolean availableWhenPsDataOff, + boolean availableWhenRoaming, int[] services, int[] utRats) { + Rlog.i(LOG_TAG, "updateCarrierConfigForTest supportsUt=" + supportsUt + + ", csfb=" + supportsCsfb + + ", reg=" + requiresImsRegistration + + ", whenPsDataOff=" + availableWhenPsDataOff + + ", whenRoaming=" + availableWhenRoaming + + ", services=" + Arrays.toString(services) + + ", rats=" + Arrays.toString(utRats)); + + updateSsOverUtConfig(supportsUt, supportsCsfb, requiresImsRegistration, + availableWhenPsDataOff, availableWhenRoaming, services, utRats); + } + + /** + * Dump this instance into a readable format for dumpsys usage. + */ + public void dump(PrintWriter printWriter) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.increaseIndent(); + pw.println("SsDomainController:"); + pw.println(" mUtSupported=" + mUtSupported); + pw.println(" mCsfbSupported=" + mCsfbSupported); + pw.println(" mCbOverUtSupported=" + mCbOverUtSupported); + pw.println(" mCfOverUtSupported=" + mCfOverUtSupported); + pw.println(" mSsOverUtSupported=" + mSsOverUtSupported); + pw.println(" mUtRequiresImsRegistration=" + mUtRequiresImsRegistration); + pw.println(" mUtAvailableWhenPsDataOff=" + mUtAvailableWhenPsDataOff); + pw.println(" mUtAvailableWhenRoaming=" + mUtAvailableWhenRoaming); + pw.println(" mUtAvailableRats=" + mUtAvailableRats); + pw.println(" mWiFiAvailable=" + mWiFiAvailable); + pw.decreaseIndent(); + } +} diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 1353511c4d..42d869510d 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -1048,6 +1048,9 @@ public final class GsmMmiCode extends Handler implements MmiCode { throw new RuntimeException ("Invalid or Unsupported MMI Code"); } else if (mSc != null && mSc.equals(SC_CLIP)) { Rlog.d(LOG_TAG, "processCode: is CLIP"); + if (!mPhone.supportCsfbForSs()) { + throw new RuntimeException("No network to support supplementary services"); + } if (isInterrogate()) { mPhone.mCi.queryCLIP( obtainMessage(EVENT_QUERY_COMPLETE, this)); @@ -1056,6 +1059,9 @@ public final class GsmMmiCode extends Handler implements MmiCode { } } else if (mSc != null && mSc.equals(SC_CLIR)) { Rlog.d(LOG_TAG, "processCode: is CLIR"); + if (!mPhone.supportCsfbForSs()) { + throw new RuntimeException("No network to support supplementary services"); + } if (isActivate() && !mPhone.isClirActivationAndDeactivationPrevented()) { mPhone.mCi.setCLIR(CommandsInterface.CLIR_INVOCATION, obtainMessage(EVENT_SET_COMPLETE, this)); @@ -1070,6 +1076,9 @@ public final class GsmMmiCode extends Handler implements MmiCode { } } else if (isServiceCodeCallForwarding(mSc)) { Rlog.d(LOG_TAG, "processCode: is CF"); + if (!mPhone.supportCsfbForSs()) { + throw new RuntimeException("No network to support supplementary services"); + } String dialingNumber = mSia; int serviceClass = siToServiceClass(mSib); @@ -1117,6 +1126,9 @@ public final class GsmMmiCode extends Handler implements MmiCode { isEnableDesired, this)); } } else if (isServiceCodeCallBarring(mSc)) { + if (!mPhone.supportCsfbForSs()) { + throw new RuntimeException("No network to support supplementary services"); + } // sia = password // sib = basic service group @@ -1164,6 +1176,9 @@ public final class GsmMmiCode extends Handler implements MmiCode { } } else if (mSc != null && mSc.equals(SC_WAIT)) { + if (!mPhone.supportCsfbForSs()) { + throw new RuntimeException("No network to support supplementary services"); + } // sia = basic service group int serviceClass = siToServiceClass(mSia); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java index 359079d560..ee251fbc78 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java @@ -32,10 +32,14 @@ import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_PAC import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_PAD; import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_SMS; import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; +import static com.android.internal.telephony.SsDomainController.SS_CLIP; +import static com.android.internal.telephony.SsDomainController.SS_CLIR; +import static com.android.internal.telephony.SsDomainController.SS_COLP; +import static com.android.internal.telephony.SsDomainController.SS_COLR; +import static com.android.internal.telephony.SsDomainController.SS_CW; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.content.res.Resources; import android.os.AsyncResult; import android.os.Build; import android.os.Handler; @@ -62,6 +66,7 @@ import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.MmiCode; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SsDomainController; import com.android.internal.telephony.gsm.GsmMmiCode; import com.android.internal.telephony.uicc.IccRecords; import com.android.telephony.Rlog; @@ -487,17 +492,12 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { static boolean isServiceCodeCallBarring(String sc) { - Resources resource = Resources.getSystem(); - if (sc != null) { - String[] barringMMI = resource.getStringArray( - com.android.internal.R.array.config_callBarringMMI_for_ims); - if (barringMMI != null) { - for (String match : barringMMI) { - if (sc.equals(match)) return true; - } - } - } - return false; + return sc != null + && (sc.equals(SC_BAOC) + || sc.equals(SC_BAOIC) || sc.equals(SC_BAOICxH) + || sc.equals(SC_BAIC) || sc.equals(SC_BAICr) + || sc.equals(SC_BA_ALL) || sc.equals(SC_BA_MO) + || sc.equals(SC_BA_MT)); } static boolean isPinPukCommand(String sc) { @@ -509,9 +509,11 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { * Whether the dial string is supplementary service code. * * @param dialString The dial string. - * @return true if the dial string is supplementary service code, and {@code false} otherwise. + * @return an instance of SsDomainController.SuppServiceRoutingInfo if the dial string + * is supplementary service code, and null otherwise. */ - public static boolean isSuppServiceCodes(String dialString, Phone phone) { + public static SsDomainController.SuppServiceRoutingInfo getSuppServiceRoutingInfo( + String dialString, Phone phone) { if (phone != null && phone.getServiceState().getVoiceRoaming() && phone.getDefaultPhone().supportsConversionOfCdmaCallerIdMmiCodesWhileRoaming()) { /* The CDMA MMI coded dialString will be converted to a 3GPP MMI Coded dialString @@ -520,38 +522,54 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { dialString = convertCdmaMmiCodesTo3gppMmiCodes(dialString); } + if (phone == null) return null; + return getSuppServiceRoutingInfo(dialString, phone.getSsDomainController()); + } + + /** + * Whether the dial string is supplementary service code. + */ + @VisibleForTesting + public static SsDomainController.SuppServiceRoutingInfo getSuppServiceRoutingInfo( + String dialString, SsDomainController controller) { Matcher m = sPatternSuppService.matcher(dialString); if (m.matches()) { String sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE)); if (isServiceCodeCallForwarding(sc)) { - return true; + return controller.getSuppServiceRoutingInfoForCf(scToCallForwardReason(sc)); } else if (isServiceCodeCallBarring(sc)) { - return true; + return controller.getSuppServiceRoutingInfoForCb(scToBarringFacility(sc)); } else if (sc != null && sc.equals(SC_CFUT)) { - return true; + // for backward compatibility, not specified by CarrierConfig + return SsDomainController.SS_ROUTING_OVER_UT; } else if (sc != null && sc.equals(SC_CLIP)) { - return true; + return controller.getSuppServiceRoutingInfoForSs(SS_CLIP); } else if (sc != null && sc.equals(SC_CLIR)) { - return true; + return controller.getSuppServiceRoutingInfoForSs(SS_CLIR); } else if (sc != null && sc.equals(SC_COLP)) { - return true; + return controller.getSuppServiceRoutingInfoForSs(SS_COLP); } else if (sc != null && sc.equals(SC_COLR)) { - return true; + return controller.getSuppServiceRoutingInfoForSs(SS_COLR); } else if (sc != null && sc.equals(SC_CNAP)) { - return true; + // for backward compatibility, not specified by CarrierConfig + return SsDomainController.SS_ROUTING_OVER_UT; } else if (sc != null && sc.equals(SC_BS_MT)) { - return true; + return controller.getSuppServiceRoutingInfoForCb( + SsDomainController.CB_FACILITY_BIL); } else if (sc != null && sc.equals(SC_BAICa)) { - return true; + return controller.getSuppServiceRoutingInfoForCb( + SsDomainController.CB_FACILITY_ACR); } else if (sc != null && sc.equals(SC_PWD)) { - return true; + // for backward compatibility, not specified by CarrierConfig + return SsDomainController.SS_ROUTING_OVER_UT; } else if (sc != null && sc.equals(SC_WAIT)) { - return true; + return controller.getSuppServiceRoutingInfoForSs(SS_CW); } else if (isPinPukCommand(sc)) { - return true; + // for backward compatibility, not specified by CarrierConfig + return SsDomainController.SS_ROUTING_OVER_UT; } } - return false; + return null; } static String diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 3610861ca1..43fddc034d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -2031,4 +2031,151 @@ public class GsmCdmaPhoneTest extends TelephonyTest { doReturn(false).when(mUiccCardApplication3gpp).getIccFdnAvailable(); doReturn(false).when(mUiccCardApplication3gpp).getIccFdnEnabled(); } + + @Test + @SmallTest + public void testUpdateSsOverUtSupported() throws Exception { + doReturn(true).when(mImsPhone).isUtEnabled(); + replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); + + // Ut is disabled in config + doReturn(false).when(mSsDomainController).useCfOverUt(anyInt()); + doReturn(false).when(mSsDomainController).useCbOverUt(anyString()); + doReturn(false).when(mSsDomainController).useSsOverUt(anyString()); + replaceInstance(GsmCdmaPhone.class, "mSsDomainController", mPhoneUT, mSsDomainController); + + mPhoneUT.getCallForwardingOption(0, 0, null); + verify(mImsPhone, times(0)).getCallForwardingOption(eq(0), eq(0), any()); + + mPhoneUT.setCallForwardingOption(0, 0, null, 0, 0, null); + verify(mImsPhone, times(0)).setCallForwardingOption( + eq(0), eq(0), any(), eq(0), eq(0), any()); + + mPhoneUT.getCallBarring(CommandsInterface.CB_FACILITY_BAIC, null, null, 0); + verify(mImsPhone, times(0)).getCallBarring( + eq(CommandsInterface.CB_FACILITY_BAIC), any(), any(), eq(0)); + + mPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BAOC, false, null, null, 0); + verify(mImsPhone, times(0)).setCallBarring( + eq(CommandsInterface.CB_FACILITY_BAOC), eq(false), any(), any(), eq(0)); + + mPhoneUT.getOutgoingCallerIdDisplay(null); + verify(mImsPhone, times(0)).getOutgoingCallerIdDisplay(any()); + + mPhoneUT.setOutgoingCallerIdDisplay(0, null); + verify(mImsPhone, times(0)).setOutgoingCallerIdDisplay(eq(0), any()); + + mPhoneUT.queryCLIP(null); + verify(mImsPhone, times(0)).queryCLIP(any()); + + mPhoneUT.getCallWaiting(null); + verify(mImsPhone, times(0)).getCallWaiting(any()); + + mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); + verify(mImsPhone, times(0)).setCallWaiting(eq(false), any()); + + // config changed but isUtEnabled still returns false + doReturn(true).when(mSsDomainController).useCfOverUt(anyInt()); + doReturn(true).when(mSsDomainController).useCbOverUt(anyString()); + doReturn(true).when(mSsDomainController).useSsOverUt(anyString()); + + mPhoneUT.getCallForwardingOption(0, 0, null); + verify(mImsPhone, times(0)).getCallForwardingOption(eq(0), eq(0), any()); + + mPhoneUT.setCallForwardingOption(0, 0, null, 0, 0, null); + verify(mImsPhone, times(0)).setCallForwardingOption( + eq(0), eq(0), any(), eq(0), eq(0), any()); + + mPhoneUT.getCallBarring(CommandsInterface.CB_FACILITY_BAIC, null, null, 0); + verify(mImsPhone, times(0)).getCallBarring( + eq(CommandsInterface.CB_FACILITY_BAIC), any(), any(), eq(0)); + + mPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BAOC, false, null, null, 0); + verify(mImsPhone, times(0)).setCallBarring( + eq(CommandsInterface.CB_FACILITY_BAOC), eq(false), any(), any(), eq(0)); + + mPhoneUT.getOutgoingCallerIdDisplay(null); + verify(mImsPhone, times(0)).getOutgoingCallerIdDisplay(any()); + + mPhoneUT.setOutgoingCallerIdDisplay(0, null); + verify(mImsPhone, times(0)).setOutgoingCallerIdDisplay(eq(0), any()); + + mPhoneUT.queryCLIP(null); + verify(mImsPhone, times(0)).queryCLIP(any()); + + mPhoneUT.getCallWaiting(null); + verify(mImsPhone, times(0)).getCallWaiting(any()); + + mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); + verify(mImsPhone, times(0)).setCallWaiting(eq(false), any()); + + // isUtEnabled returns true + doReturn(true).when(mSsDomainController).isUtEnabled(); + + mPhoneUT.getCallForwardingOption(0, 0, null); + verify(mImsPhone, times(1)).getCallForwardingOption(eq(0), eq(0), any()); + + mPhoneUT.setCallForwardingOption(0, 0, null, 0, 0, null); + verify(mImsPhone, times(1)).setCallForwardingOption( + eq(0), eq(0), any(), eq(0), eq(0), any()); + + mPhoneUT.getCallBarring(CommandsInterface.CB_FACILITY_BAIC, null, null, 0); + verify(mImsPhone, times(1)).getCallBarring( + eq(CommandsInterface.CB_FACILITY_BAIC), any(), any(), eq(0)); + + mPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BAOC, false, null, null, 0); + verify(mImsPhone, times(1)).setCallBarring( + eq(CommandsInterface.CB_FACILITY_BAOC), eq(false), any(), any(), eq(0)); + + mPhoneUT.getOutgoingCallerIdDisplay(null); + verify(mImsPhone, times(1)).getOutgoingCallerIdDisplay(any()); + + mPhoneUT.setOutgoingCallerIdDisplay(0, null); + verify(mImsPhone, times(1)).setOutgoingCallerIdDisplay(eq(0), any()); + + mPhoneUT.queryCLIP(null); + verify(mImsPhone, times(1)).queryCLIP(any()); + + mPhoneUT.getCallWaiting(null); + verify(mImsPhone, times(1)).getCallWaiting(any()); + + mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); + verify(mImsPhone, times(1)).setCallWaiting(eq(false), any()); + + // configure changed, not support Ut + doReturn(false).when(mSsDomainController).useCfOverUt(anyInt()); + doReturn(false).when(mSsDomainController).useCbOverUt(anyString()); + doReturn(false).when(mSsDomainController).useSsOverUt(anyString()); + + // no change in interfactiion counts + mPhoneUT.getCallForwardingOption(0, 0, null); + verify(mImsPhone, times(1)).getCallForwardingOption(eq(0), eq(0), any()); + + mPhoneUT.setCallForwardingOption(0, 0, null, 0, 0, null); + verify(mImsPhone, times(1)).setCallForwardingOption( + eq(0), eq(0), any(), eq(0), eq(0), any()); + + mPhoneUT.getCallBarring(CommandsInterface.CB_FACILITY_BAIC, null, null, 0); + verify(mImsPhone, times(1)).getCallBarring( + eq(CommandsInterface.CB_FACILITY_BAIC), any(), any(), eq(0)); + + mPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BAOC, false, null, null, 0); + verify(mImsPhone, times(1)).setCallBarring( + eq(CommandsInterface.CB_FACILITY_BAOC), eq(false), any(), any(), eq(0)); + + mPhoneUT.getOutgoingCallerIdDisplay(null); + verify(mImsPhone, times(1)).getOutgoingCallerIdDisplay(any()); + + mPhoneUT.setOutgoingCallerIdDisplay(0, null); + verify(mImsPhone, times(1)).setOutgoingCallerIdDisplay(eq(0), any()); + + mPhoneUT.queryCLIP(null); + verify(mImsPhone, times(1)).queryCLIP(any()); + + mPhoneUT.getCallWaiting(null); + verify(mImsPhone, times(1)).getCallWaiting(any()); + + mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); + verify(mImsPhone, times(1)).setCallWaiting(eq(false), any()); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java new file mode 100644 index 0000000000..53679e0dbe --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java @@ -0,0 +1,475 @@ +/* + * Copyright (C) 2021 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; + +import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.GERAN; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.IWLAN; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_ACR; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_ALL; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BAIC; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BAOC; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BIC_ROAM; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BIL; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BOIC; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BOIC_EXHC; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_IBS; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_OBS; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_ALL; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_ALL_CONDITONAL_FORWARDING; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFB; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFNRC; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFNRY; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFU; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CW; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIP; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIP; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIR; + +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOIC; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOICxH; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO; +import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; +import static com.android.internal.telephony.SsDomainController.CB_FACILITY_ACR; +import static com.android.internal.telephony.SsDomainController.CB_FACILITY_BIL; +import static com.android.internal.telephony.SsDomainController.SS_CLIP; +import static com.android.internal.telephony.SsDomainController.SS_CLIR; +import static com.android.internal.telephony.SsDomainController.SS_COLP; +import static com.android.internal.telephony.SsDomainController.SS_COLR; +import static com.android.internal.telephony.SsDomainController.SS_CW; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; + +import android.telephony.AccessNetworkConstants; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.text.TextUtils; + +import com.android.internal.telephony.imsphone.ImsPhoneMmiCode; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.HashMap; +import java.util.Map; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class SsDomainControllerTest extends TelephonyTest { + private static final int[] UT_OVER_ALL = new int[] { + NGRAN, + EUTRAN, + IWLAN, + UTRAN, + GERAN + }; + + private static final int[] UT_OVER_LTE_WIFI = new int[] { + EUTRAN, + IWLAN + }; + + private Map mFacilities = new HashMap() {{ + put(CB_FACILITY_BAOC, "33"); + put(CB_FACILITY_BAOIC, "331"); + put(CB_FACILITY_BAOICxH, "332"); + put(CB_FACILITY_BAIC, "35"); + put(CB_FACILITY_BAICr, "351"); + put(CB_FACILITY_BA_ALL, "330"); + put(CB_FACILITY_BA_MO, "333"); + put(CB_FACILITY_BA_MT, "353"); + put(CB_FACILITY_BIL, "156"); + put(CB_FACILITY_ACR, "157"); + }}; + + private Map mReasons = new HashMap() {{ + put(CF_REASON_ALL, "002"); + put(CF_REASON_UNCONDITIONAL, "21"); + put(CF_REASON_BUSY, "67"); + put(CF_REASON_NOT_REACHABLE, "62"); + put(CF_REASON_NO_REPLY, "61"); + put(CF_REASON_ALL_CONDITIONAL, "004"); + }}; + + private Map mServices = new HashMap() {{ + put(SS_CW, "43"); + put(SS_CLIP, "30"); + put(SS_CLIR, "31"); + put(SS_COLP, "76"); + put(SS_COLR, "77"); + }}; + + private SsDomainController mSdc; + + @Before + public void setUp() throws Exception { + super.setUp(this.getClass().getSimpleName()); + + mSdc = new SsDomainController(mPhone); + } + + @After + public void tearDown() throws Exception { + mSdc = null; + super.tearDown(); + } + + private void verifyCb(String facility) { + for (String f : mFacilities.keySet()) { + String sc = mFacilities.get(f); + + SsDomainController.SuppServiceRoutingInfo ssCode = + ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); + assertNotNull(f + ", only " + facility + " available", ssCode); + if (TextUtils.equals(f, facility)) { + assertTrue(f + ", only " + facility + " available", mSdc.useCbOverUt(f)); + assertTrue(f + ", only " + facility + " available", ssCode.useSsOverUt()); + } else { + assertFalse(f + ", only " + facility + " available", mSdc.useCbOverUt(f)); + assertFalse(f + ", only " + facility + " available", ssCode.useSsOverUt()); + } + } + } + + @Test + @SmallTest + public void testUseCbOverUt() { + setUtEnabled(); + updateCarrierConfig(new int[] {}); + + verifyCb(""); + + /** barring_of_all_outgoing_calls (BAOC) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BAOC }); + + verifyCb(CB_FACILITY_BAOC); + + /** barring_of_outgoing_international_calls (BOIC) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BOIC }); + + verifyCb(CB_FACILITY_BAOIC); + + /** barring_of_outgoing_international_calls_except_to_home_plmn (BoICExHC) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BOIC_EXHC }); + + verifyCb(CB_FACILITY_BAOICxH); + + /** barring of all incoming calls (BAIC) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BAIC }); + + verifyCb(CB_FACILITY_BAIC); + + /** barring of incoming calls when roaming outside home PLMN Country (BICRoam) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BIC_ROAM }); + + verifyCb(CB_FACILITY_BAICr); + + /** barring list of incoming numbers (bil) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BIL }); + + verifyCb(CB_FACILITY_BIL); + + /** barring of all anonymous incoming number (acr) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_ACR }); + + verifyCb(CB_FACILITY_ACR); + + /** all barring services(BA_ALL) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_ALL }); + + verifyCb(CB_FACILITY_BA_ALL); + + /** outgoing barring services(BA_MO) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_OBS }); + + verifyCb(CB_FACILITY_BA_MO); + + /** incoming barring services(BA_MT) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_IBS }); + + verifyCb(CB_FACILITY_BA_MT); + } + + private void verifyCf(int reason) { + for (Integer r : mReasons.keySet()) { + String sc = mReasons.get(r); + + SsDomainController.SuppServiceRoutingInfo ssCode = + ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); + assertNotNull(r + ", only " + reason + " available", ssCode); + if (r == reason) { + assertTrue(r + ", only " + reason + " available", mSdc.useCfOverUt(r)); + assertTrue(r + ", only " + reason + " available", ssCode.useSsOverUt()); + } else { + assertFalse(r + ", only " + reason + " available", mSdc.useCfOverUt(r)); + assertFalse(r + ", only " + reason + " available", ssCode.useSsOverUt()); + } + } + } + + @Test + @SmallTest + public void testUseCfOverUt() { + setUtEnabled(); + updateCarrierConfig(new int[] {}); + + verifyCf(-1); + + /** all_call_forwarding (CFAll) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_ALL }); + + verifyCf(CF_REASON_ALL); + + /** all_forwarding_unconditional (CFU) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_CFU }); + + verifyCf(CF_REASON_UNCONDITIONAL); + + /** all_call_conditional_forwarding (allCondForwarding) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_ALL_CONDITONAL_FORWARDING }); + + verifyCf(CF_REASON_ALL_CONDITIONAL); + + /** call_forwarding_on_mobile_subscriber_busy (CFB) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_CFB }); + + verifyCf(CF_REASON_BUSY); + + /** call_forwarding_on_no_reply (CFNRY) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_CFNRY }); + + verifyCf(CF_REASON_NO_REPLY); + + /** call_forwarding_on_mobile_subscriber_unreachable (CFNRC) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_CFNRC }); + + verifyCf(CF_REASON_NOT_REACHABLE); + } + + private void verifySs(String service) { + for (String s : mServices.keySet()) { + String sc = mServices.get(s); + + SsDomainController.SuppServiceRoutingInfo ssCode = + ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); + assertNotNull(s + ", only " + service + " available", ssCode); + if (TextUtils.equals(s, service)) { + assertTrue(s + ", only " + service + " available", mSdc.useSsOverUt(s)); + assertTrue(s + ", only " + service + " available", ssCode.useSsOverUt()); + } else { + assertFalse(s + ", only " + service + " available", mSdc.useSsOverUt(s)); + assertFalse(s + ", only " + service + " available", ssCode.useSsOverUt()); + } + } + } + + @Test + @SmallTest + public void testUseSsOverUt() { + setUtEnabled(); + updateCarrierConfig(new int[] {}); + verifySs(""); + + /** call waiting (CW) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CW }); + + verifySs(SS_CW); + + /** OIP (clip) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIP }); + + verifySs(SS_CLIP); + + /** TIP (colp) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIP }); + + verifySs(SS_COLP); + + /** TIR (colr) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIR }); + + verifySs(SS_COLR); + + /** OIR (clir) */ + updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR }); + + verifySs(SS_CLIR); + } + + @Test + @SmallTest + public void testUtEnabled() { + doReturn(0).when(mImsPhone).getSubId(); + mSdc.updateWifiForUt(false); + + ServiceState imsSs = new ServiceState(); + // IMS is not registered + imsSs.setState(ServiceState.STATE_OUT_OF_SERVICE); + doReturn(imsSs).when(mImsPhone).getServiceState(); + + doReturn(true).when(mImsPhone).isUtEnabled(); + doReturn(mImsPhone).when(mPhone).getImsPhone(); + + ServiceState ss = new ServiceState(); + // IMS is not registered + ss.setState(ServiceState.STATE_OUT_OF_SERVICE); + doReturn(ss).when(mPhone).getServiceState(); + + // WWAN_LEGACY is registered + NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) + .build(); + + ss.addNetworkRegistrationInfo(nri); + + // IMS Registration is NOT required, enabled when roaming, transport = ALL + updateCarrierConfig(false, true, UT_OVER_ALL); + + assertTrue(mSdc.isUtEnabled()); + + // IMS Registration is NOT required, enabled when roaming, transport = LTE | WiFi + updateCarrierConfig(false, true, UT_OVER_LTE_WIFI); + + // Ut is not available over 3G and 2G. + assertFalse(mSdc.isUtEnabled()); + + // Wi-Fi is connected + mSdc.updateWifiForUt(true); + + // Ut is available over WiFi. + assertTrue(mSdc.isUtEnabled()); + + // IMS Registration is REQUIRED, enabled when roaming, transport = LTE | WiFi + updateCarrierConfig(true, true, UT_OVER_LTE_WIFI); + + // IMS is not registered. + assertFalse(mSdc.isUtEnabled()); + + // IMS is registered + imsSs.setState(ServiceState.STATE_IN_SERVICE); + + assertTrue(mSdc.isUtEnabled()); + } + + @Test + @SmallTest + public void testUtWhenRoaming() { + doReturn(0).when(mImsPhone).getSubId(); + mSdc.updateWifiForUt(false); + + ServiceState imsSs = new ServiceState(); + // IMS is not registered + imsSs.setState(ServiceState.STATE_OUT_OF_SERVICE); + doReturn(imsSs).when(mImsPhone).getServiceState(); + + doReturn(true).when(mImsPhone).isUtEnabled(); + doReturn(mImsPhone).when(mPhone).getImsPhone(); + + ServiceState ss = new ServiceState(); + // IMS is not registered + ss.setState(ServiceState.STATE_OUT_OF_SERVICE); + doReturn(ss).when(mPhone).getServiceState(); + + // WWAN_LEGACY is registered + NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) + .build(); + + ss.addNetworkRegistrationInfo(nri); + + // IMS Registration is NOT required, enabled when roaming, transport = ALL + updateCarrierConfig(false, true, UT_OVER_ALL); + + assertTrue(mSdc.isUtEnabled()); + + // IMS Registration is NOT required, disabled when roaming, transport = ALL + updateCarrierConfig(false, false, UT_OVER_ALL); + + // Ut is not available when roaming + assertFalse(mSdc.isUtEnabled()); + } + + private void setUtEnabled() { + doReturn(0).when(mImsPhone).getSubId(); + mSdc.updateWifiForUt(false); + + ServiceState imsSs = new ServiceState(); + // IMS is not registered + imsSs.setState(ServiceState.STATE_OUT_OF_SERVICE); + doReturn(imsSs).when(mImsPhone).getServiceState(); + + doReturn(true).when(mImsPhone).isUtEnabled(); + doReturn(mImsPhone).when(mPhone).getImsPhone(); + + ServiceState ss = new ServiceState(); + // IMS is not registered + ss.setState(ServiceState.STATE_OUT_OF_SERVICE); + doReturn(ss).when(mPhone).getServiceState(); + + // WWAN_LEGACY is registered + NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) + .build(); + + ss.addNetworkRegistrationInfo(nri); + } + + private void updateCarrierConfig(boolean requiresImsRegistration, + boolean availableWhenRoaming, int[] utRats) { + updateCarrierConfig(true, requiresImsRegistration, true, availableWhenRoaming, utRats); + } + + private void updateCarrierConfig(boolean supportsCsfb, boolean requiresImsRegistration, + boolean availableWhenPsDataOff, boolean availableWhenRoaming, int[] utRats) { + mSdc.updateCarrierConfigForTest(true, supportsCsfb, requiresImsRegistration, + availableWhenPsDataOff, availableWhenRoaming, null, utRats); + } + + private void updateCarrierConfig(int[] services) { + mSdc.updateCarrierConfigForTest(true, true, false, true, true, services, UT_OVER_ALL); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 9b54b19995..6cc87813b9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -266,6 +266,7 @@ public abstract class TelephonyTest { protected CellLocation mCellLocation; protected DataServiceManager mMockedWwanDataServiceManager; protected DataServiceManager mMockedWlanDataServiceManager; + protected SsDomainController mSsDomainController; // Initialized classes protected ActivityManager mActivityManager; @@ -499,6 +500,7 @@ public abstract class TelephonyTest { mCellLocation = Mockito.mock(CellLocation.class); mMockedWwanDataServiceManager = Mockito.mock(DataServiceManager.class); mMockedWlanDataServiceManager = Mockito.mock(DataServiceManager.class); + mSsDomainController = Mockito.mock(SsDomainController.class); TelephonyManager.disableServiceHandleCaching(); SubscriptionController.disableCaching(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java index 23b6bb96aa..2defe3c43d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony.imsphone; import static junit.framework.Assert.fail; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; @@ -26,9 +27,11 @@ import static org.mockito.Mockito.mock; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; +import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import com.android.internal.telephony.SsDomainController; import com.android.internal.telephony.TelephonyTest; import org.junit.After; @@ -117,4 +120,33 @@ public class ImsPhoneMmiCodeTest extends TelephonyTest { .KEY_CARRIER_SUPPORTS_CALLER_ID_VERTICAL_SERVICE_CODES_BOOL, true); doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); } + + @Test + @SmallTest + public void testGetSuppServiceRoutingInfo() { + // Tests for valid service codes are done in SsDomainControllerTest. + + // verifies that null returns when invalid service code is given + // emergency number + SsDomainController.SuppServiceRoutingInfo ssInfo = + ImsPhoneMmiCode.getSuppServiceRoutingInfo("911", + (SsDomainController) null); + assertNull(ssInfo); + + // normal number + ssInfo = ImsPhoneMmiCode.getSuppServiceRoutingInfo("0123456789", + (SsDomainController) null); + assertNull(ssInfo); + ssInfo = ImsPhoneMmiCode.getSuppServiceRoutingInfo("+1234567890", + (SsDomainController) null); + assertNull(ssInfo); + + // USSD + ssInfo = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*0123456789#", + (SsDomainController) null); + assertNull(ssInfo); + ssInfo = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*1234#56789#", + (SsDomainController) null); + assertNull(ssInfo); + } } -- GitLab From 287f3059967cc7e1c3094bdd5c395f8e7ebc0861 Mon Sep 17 00:00:00 2001 From: Android Culprit Assistant Date: Fri, 3 Jun 2022 02:41:06 +0000 Subject: [PATCH 034/656] Revert "Report an Anomaly for missing RegDenied Reason" This is an Android Culprit Assistant revert, created as part of an culprit search session. It will not be committed, and can be ignored. Change-Id: I4f84753bf6edb1cfebc33bdba3882566652cf893 BUG: 234761984 --- .../telephony/CellularNetworkService.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java index 4253905205..19a585d319 100644 --- a/src/java/com/android/internal/telephony/CellularNetworkService.java +++ b/src/java/com/android/internal/telephony/CellularNetworkService.java @@ -500,14 +500,6 @@ public class CellularNetworkService extends NetworkService { final String rplmn = regResult.registeredPlmn; final int reasonForDenial = regResult.reasonForDenial; - if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_DENIED - && reasonForDenial - == android.hardware.radio.network.RegistrationFailCause.NONE) { - AnomalyReporter.reportAnomaly( - UUID.fromString("62ed270f-e139-418a-a427-8bcc1bca8f20"), - "RIL Missing Reg Fail Reason", mPhone.getCarrierId()); - } - int networkType = ServiceState.rilRadioTechnologyToNetworkType(regResult.rat); if (networkType == TelephonyManager.NETWORK_TYPE_LTE_CA) { networkType = TelephonyManager.NETWORK_TYPE_LTE; @@ -590,14 +582,6 @@ public class CellularNetworkService extends NetworkService { networkType = getNetworkTypeForCellIdentity(networkType, cellIdentity, mPhone.getCarrierId()); - if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_DENIED - && reasonForDenial - == android.hardware.radio.network.RegistrationFailCause.NONE) { - AnomalyReporter.reportAnomaly( - UUID.fromString("62ed270f-e139-418a-a427-8bcc1bca8f20"), - "RIL Missing Reg Fail Reason", mPhone.getCarrierId()); - } - // Conditional parameters for specific RANs boolean cssSupported = false; int roamingIndicator = 0; -- GitLab From 3cfbf59efa120b42d157d1b9cd08900f6d2d416d Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 7 Dec 2021 18:52:59 +0000 Subject: [PATCH 035/656] Implement the terminal-based call waiting Terminal-based call waiting can be enabled with the configuration items following: - From CarrierConfigManager.ImsSs: KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY The waiting voice calls over CS and PS are controlled by the terminal per the user's setting not by the network. Bug: 202463005 Test: atest Change-Id: I89d4363146d7ba446f0785e368419c0b8c9f89e0 (cherry picked from commit 6c8755a243a3e6a9b30ae2f489826f730a36c201) Merged-In: I89d4363146d7ba446f0785e368419c0b8c9f89e0 --- .../telephony/CallWaitingController.java | 335 ++++++++++++++++++ .../telephony/GsmCdmaCallTracker.java | 5 + .../internal/telephony/GsmCdmaPhone.java | 26 +- .../com/android/internal/telephony/Phone.java | 20 ++ .../internal/telephony/gsm/GsmMmiCode.java | 19 +- .../internal/telephony/imsphone/ImsPhone.java | 5 + .../telephony/imsphone/ImsPhoneBase.java | 10 + .../imsphone/ImsPhoneCallTracker.java | 35 ++ .../telephony/imsphone/ImsPhoneMmiCode.java | 18 +- .../telephony/CallWaitingControllerTest.java | 252 +++++++++++++ 10 files changed, 721 insertions(+), 4 deletions(-) create mode 100644 src/java/com/android/internal/telephony/CallWaitingController.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java new file mode 100644 index 0000000000..a9d51a0820 --- /dev/null +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2021 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; + +import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_NONE; +import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL; +import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT; +import static android.telephony.CarrierConfigManager.ImsSs.KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CW; + +import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE; +import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; + +import android.annotation.Nullable; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.os.AsyncResult; +import android.os.Bundle; +import android.os.Message; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.telephony.Rlog; + +/** + * Controls the change of the user setting of the call waiting service + * + * {@hide} + */ +public class CallWaitingController { + + public static final String LOG_TAG = "CallWaiting"; + private static final boolean DBG = false; /* STOPSHIP if true */ + + // Terminal-based call waiting is not supported. */ + public static final int TERMINAL_BASED_NOT_SUPPORTED = -1; + // Terminal-based call waiting is supported but not activated. */ + public static final int TERMINAL_BASED_NOT_ACTIVATED = 0; + // Terminal-based call waiting is supported and activated. */ + public static final int TERMINAL_BASED_ACTIVATED = 1; + + @VisibleForTesting + public static final String PREFERENCE_TBCW = "terminal_based_call_waiting"; + @VisibleForTesting + public static final String KEY_SUB_ID = "subId"; + @VisibleForTesting + public static final String KEY_STATE = "state"; + @VisibleForTesting + public static final String KEY_CS_SYNC = "cs_sync"; + + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null) { + return; + } + if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { + Bundle bundle = intent.getExtras(); + if (bundle == null) { + return; + } + int slotId = bundle.getInt(CarrierConfigManager.EXTRA_SLOT_INDEX, + SubscriptionManager.INVALID_PHONE_INDEX); + + if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) { + Rlog.e(LOG_TAG, "onReceive ACTION_CARRIER_CONFIG_CHANGED invalid slotId " + + slotId); + return; + } + + if (slotId == mPhone.getPhoneId()) { + onCarrierConfigChanged(); + } + } + } + }; + + private boolean mSupportedByImsService = false; + private boolean mValidSubscription = false; + + // The user's last setting of terminal-based call waiting + private int mCallWaitingState = TERMINAL_BASED_NOT_SUPPORTED; + + private int mSyncPreference = CALL_WAITING_SYNC_NONE; + private int mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + + private GsmCdmaPhone mPhone; + private Context mContext; + + // Constructors + public CallWaitingController(GsmCdmaPhone phone) { + mPhone = phone; + mContext = phone.getContext(); + } + + private void initialize() { + mContext.registerReceiver(mReceiver, new IntentFilter( + CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + + int phoneId = mPhone.getPhoneId(); + int subId = mPhone.getSubId(); + SharedPreferences sp = + mContext.getSharedPreferences(PREFERENCE_TBCW, Context.MODE_PRIVATE); + mLastSubId = sp.getInt(KEY_SUB_ID + phoneId, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mCallWaitingState = sp.getInt(KEY_STATE + subId, TERMINAL_BASED_NOT_SUPPORTED); + mSyncPreference = sp.getInt(KEY_CS_SYNC + phoneId, CALL_WAITING_SYNC_NONE); + + Rlog.i(LOG_TAG, "initialize phoneId=" + phoneId + + ", lastSubId=" + mLastSubId + ", subId=" + subId + + ", state=" + mCallWaitingState + ", sync=" + mSyncPreference); + } + + /** + * Returns the cached user setting. + * + * Possible values are + * {@link #TERMINAL_BASED_NOT_SUPPORTED}, + * {@link #TERMINAL_BASED_NOT_ACTIVATED}, and + * {@link #TERMINAL_BASED_ACTIVATED}. + */ + @VisibleForTesting + public int getTerminalBasedCallWaitingState() { + if (!mValidSubscription) return TERMINAL_BASED_NOT_SUPPORTED; + return mCallWaitingState; + } + + /** + * Serves the user's requests to interrogate the call waiting service + * + * @return true when terminal-based call waiting is supported, otherwise false + */ + @VisibleForTesting + public boolean getCallWaiting(@Nullable Message onComplete) { + if (mCallWaitingState == TERMINAL_BASED_NOT_SUPPORTED) return false; + + Rlog.i(LOG_TAG, "getCallWaiting " + mCallWaitingState); + + if (mSyncPreference == CALL_WAITING_SYNC_NONE) { + sendGetCallWaitingResponse(onComplete); + return true; + } + + return false; + } + + /** + * Serves the user's requests to set the call waiting service + * + * @param serviceClass the target service class. Values are CommandsInterface.SERVICE_CLASS_*. + * @return true when terminal-based call waiting is supported, otherwise false + */ + @VisibleForTesting + public boolean setCallWaiting(boolean enable, int serviceClass, @Nullable Message onComplete) { + if (mCallWaitingState == TERMINAL_BASED_NOT_SUPPORTED) return false; + + if ((serviceClass & SERVICE_CLASS_VOICE) != SERVICE_CLASS_VOICE) return false; + + Rlog.i(LOG_TAG, "setCallWaiting enable=" + enable + ", service=" + serviceClass); + + if (mSyncPreference == CALL_WAITING_SYNC_NONE) { + updateState( + enable ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); + + sendToTarget(onComplete, null, null); + return true; + } + + return false; + } + + private void sendToTarget(Message onComplete, Object result, Throwable exception) { + if (onComplete != null) { + AsyncResult.forMessage(onComplete, result, exception); + onComplete.sendToTarget(); + } + } + + private void sendGetCallWaitingResponse(Message onComplete) { + if (onComplete != null) { + int serviceClass = SERVICE_CLASS_NONE; + if (mCallWaitingState == TERMINAL_BASED_ACTIVATED) { + serviceClass = SERVICE_CLASS_VOICE; + } + sendToTarget(onComplete, new int[] { mCallWaitingState, serviceClass }, null); + } + } + + private void onCarrierConfigChanged() { + int subId = mPhone.getSubId(); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + Rlog.i(LOG_TAG, "onCarrierConfigChanged invalid subId=" + subId); + + mValidSubscription = false; + return; + } + + CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class); + PersistableBundle b = configManager.getConfigForSubId(subId); + + updateCarrierConfig(subId, b, false); + } + + /** + * @param enforced only used for test + */ + @VisibleForTesting + public void updateCarrierConfig(int subId, PersistableBundle b, boolean enforced) { + mValidSubscription = true; + + if (b == null) return; + + boolean supportsTerminalBased = false; + int[] services = b.getIntArray(KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY); + if (services != null) { + for (int service : services) { + if (service == SUPPLEMENTARY_SERVICE_CW) { + supportsTerminalBased = true; + } + } + } + int syncPreference = b.getInt(KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT, + CALL_WAITING_SYNC_NONE); + boolean activated = b.getBoolean(KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL); + int defaultState = supportsTerminalBased + ? (activated ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED) + : TERMINAL_BASED_NOT_SUPPORTED; + int savedState = getSavedState(subId); + + if (DBG) { + Rlog.d(LOG_TAG, "updateCarrierConfig phoneId=" + mPhone.getPhoneId() + + ", subId=" + subId + ", support=" + supportsTerminalBased + + ", sync=" + syncPreference + ", default=" + defaultState + + ", savedState=" + savedState); + } + + int desiredState = savedState; + + if (enforced) { + desiredState = defaultState; + } else { + if (defaultState == TERMINAL_BASED_NOT_SUPPORTED) { + desiredState = TERMINAL_BASED_NOT_SUPPORTED; + } else if (savedState == TERMINAL_BASED_NOT_SUPPORTED) { + desiredState = defaultState; + } + } + + updateState(desiredState, syncPreference, enforced); + } + + private void updateState(int state) { + updateState(state, mSyncPreference, false); + } + + private void updateState(int state, int syncPreference, boolean enforced) { + int subId = mPhone.getSubId(); + + if (mLastSubId == subId + && mCallWaitingState == state + && mSyncPreference == syncPreference + && (!enforced)) { + return; + } + + int phoneId = mPhone.getPhoneId(); + + Rlog.i(LOG_TAG, "updateState phoneId=" + phoneId + + ", subId=" + subId + ", state=" + state + + ", sync=" + syncPreference + ", enforced=" + enforced); + + SharedPreferences sp = + mContext.getSharedPreferences(PREFERENCE_TBCW, Context.MODE_PRIVATE); + + SharedPreferences.Editor editor = sp.edit(); + editor.putInt(KEY_SUB_ID + phoneId, subId); + editor.putInt(KEY_STATE + subId, state); + editor.putInt(KEY_CS_SYNC + phoneId, syncPreference); + editor.apply(); + + mCallWaitingState = state; + mLastSubId = subId; + mSyncPreference = syncPreference; + + mPhone.setTerminalBasedCallWaitingStatus(mCallWaitingState); + } + + private int getSavedState(int subId) { + SharedPreferences sp = + mContext.getSharedPreferences(PREFERENCE_TBCW, Context.MODE_PRIVATE); + int state = sp.getInt(KEY_STATE + subId, TERMINAL_BASED_NOT_SUPPORTED); + + Rlog.i(LOG_TAG, "getSavedState subId=" + subId + ", state=" + state); + + return state; + } + /** + * Sets whether the device supports the terminal-based call waiting. + * Only for test + */ + @VisibleForTesting + public void setTerminalBasedCallWaitingSupported(boolean supported) { + if (mSupportedByImsService == supported) return; + + Rlog.i(LOG_TAG, "setTerminalBasedCallWaitingSupported " + supported); + + mSupportedByImsService = supported; + + if (supported) { + initialize(); + onCarrierConfigChanged(); + } else { + mContext.unregisterReceiver(mReceiver); + updateState(TERMINAL_BASED_NOT_SUPPORTED); + } + } +} diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java index 3293558bd2..517037eccf 100755 --- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java +++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java @@ -967,6 +967,11 @@ public class GsmCdmaCallTracker extends CallTracker { } else { newUnknownConnectionCdma = mConnections[i]; } + } else if (mPhone.getTerminalBasedCallWaitingState() + == CallWaitingController.TERMINAL_BASED_NOT_ACTIVATED + && newRinging.getState() == Call.State.WAITING) { + mCi.hangupWaitingOrBackground(obtainCompleteMessage()); + return; } } } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 0c56c4027a..b62a5d2c02 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -283,6 +283,7 @@ public class GsmCdmaPhone extends Phone { private final CarrierPrivilegesTracker mCarrierPrivilegesTracker; private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener; + private final CallWaitingController mCallWaitingController; // Constructors @@ -388,6 +389,8 @@ public class GsmCdmaPhone extends Phone { .inject(LinkBandwidthEstimator.class.getName()) .makeLinkBandwidthEstimator(this); + mCallWaitingController = new CallWaitingController(this); + loadTtyMode(); CallManager.getInstance().registerPhone(this); @@ -2728,6 +2731,8 @@ public class GsmCdmaPhone extends Phone { return; } + if (mCallWaitingController.getCallWaiting(onComplete)) return; + Phone imsPhone = mImsPhone; if (useSsOverUt(SS_CW)) { if (useSsOverUt(onComplete)) { @@ -2784,6 +2789,8 @@ public class GsmCdmaPhone extends Phone { return; } + if (mCallWaitingController.setCallWaiting(enable, serviceClass, onComplete)) return; + Phone imsPhone = mImsPhone; if (useSsOverUt(SS_CW)) { if (useSsOverUt(onComplete)) { @@ -2818,6 +2825,23 @@ public class GsmCdmaPhone extends Phone { } } + @Override + public int getTerminalBasedCallWaitingState() { + return mCallWaitingController.getTerminalBasedCallWaitingState(); + } + + @Override + public void setTerminalBasedCallWaitingStatus(int state) { + if (mImsPhone != null) { + mImsPhone.setTerminalBasedCallWaitingStatus(state); + } + } + + @Override + public void setTerminalBasedCallWaitingSupported(boolean supported) { + mCallWaitingController.setTerminalBasedCallWaitingSupported(supported); + } + @Override public void getAvailableNetworks(Message response) { if (isPhoneTypeGsm() || isPhoneTypeCdmaLte()) { @@ -5110,4 +5134,4 @@ public class GsmCdmaPhone extends Phone { ArrayList controlStrings = GsmMmiCode.getControlStrings(requestType, serviceType); return FdnUtils.isSuppServiceRequestBlockedByFdn(mPhoneId, controlStrings, getCountryIso()); } -} \ No newline at end of file +} diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index d00c8f5044..4523031cf0 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -4984,6 +4984,26 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return mNewDataStackEnabled; } + /** + * Returns the user's last setting for terminal-based call waiting + */ + public int getTerminalBasedCallWaitingState() { + return CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED; + } + + /** + * Notifies the change of the user setting of the terminal-based call waiting service + * to IMS service. + */ + public void setTerminalBasedCallWaitingStatus(int state) { + } + + /** + * Notifies that the IMS service connected supports the terminal-based call waiting service + */ + public void setTerminalBasedCallWaitingSupported(boolean supported) { + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 42d869510d..7d7b7ba908 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -49,6 +49,7 @@ import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CallForwardInfo; import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CallWaitingController; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.GsmCdmaPhone; @@ -1183,11 +1184,25 @@ public final class GsmMmiCode extends Handler implements MmiCode { int serviceClass = siToServiceClass(mSia); if (isActivate() || isDeactivate()) { + if (serviceClass == SERVICE_CLASS_NONE + || (serviceClass & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE) { + if (mPhone.getTerminalBasedCallWaitingState() + != CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED) { + mPhone.setCallWaiting(isActivate(), serviceClass, + obtainMessage(EVENT_SET_COMPLETE, this)); + return; + } + } mPhone.mCi.setCallWaiting(isActivate(), serviceClass, obtainMessage(EVENT_SET_COMPLETE, this)); } else if (isInterrogate()) { - mPhone.mCi.queryCallWaiting(serviceClass, - obtainMessage(EVENT_QUERY_COMPLETE, this)); + if (mPhone.getTerminalBasedCallWaitingState() + != CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED) { + mPhone.getCallWaiting(obtainMessage(EVENT_QUERY_COMPLETE, this)); + } else { + mPhone.mCi.queryCallWaiting(serviceClass, + obtainMessage(EVENT_QUERY_COMPLETE, this)); + } } else { throw new RuntimeException ("Invalid or Unsupported MMI Code"); } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 71e85f35b1..090cd27db7 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -2616,6 +2616,11 @@ public class ImsPhone extends ImsPhoneBase { return mLastKnownRoamingState; } + @Override + public void setTerminalBasedCallWaitingStatus(int state) { + mCT.setTerminalBasedCallWaitingStatus(state); + } + @Override public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index d19b8d35fa..e83ef5333d 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -540,4 +540,14 @@ abstract class ImsPhoneBase extends Phone { notifyPhoneStateChanged(); } } + + @Override + public int getTerminalBasedCallWaitingState() { + return getDefaultPhone().getTerminalBasedCallWaitingState(); + } + + @Override + public void setTerminalBasedCallWaitingSupported(boolean supported) { + getDefaultPhone().setTerminalBasedCallWaitingSupported(supported); + } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 7b8316907e..b26c7d2303 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -18,8 +18,11 @@ package com.android.internal.telephony.imsphone; import static android.telephony.CarrierConfigManager.USSD_OVER_CS_PREFERRED; import static android.telephony.CarrierConfigManager.USSD_OVER_IMS_ONLY; +import static android.telephony.ims.ImsService.CAPABILITY_TERMINAL_BASED_CALL_WAITING; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; +import static com.android.internal.telephony.CallWaitingController.TERMINAL_BASED_ACTIVATED; +import static com.android.internal.telephony.CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED; import static com.android.internal.telephony.Phone.CS_FALLBACK; import android.Manifest; @@ -1151,6 +1154,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // For compatibility with apps that still use deprecated intent sendImsServiceStateIntent(ImsManager.ACTION_IMS_SERVICE_UP); mCurrentlyConnectedSubId = Optional.of(subId); + + initializeTerminalBasedCallWaiting(); } /** @@ -5448,4 +5453,34 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } return false; } + + private void initializeTerminalBasedCallWaiting() { + boolean capable = false; + if (mImsManager != null) { + try { + capable = mImsManager.isCapable(CAPABILITY_TERMINAL_BASED_CALL_WAITING); + } catch (ImsException e) { + loge("initializeTerminalBasedCallWaiting : exception " + e); + } + } + mPhone.setTerminalBasedCallWaitingSupported(capable); + + setTerminalBasedCallWaitingStatus(mPhone.getTerminalBasedCallWaitingState()); + } + + /** + * Notifies the change of the user setting of the terminal-based call waiting service + * to IMS service. + */ + public void setTerminalBasedCallWaitingStatus(int state) { + if (state == TERMINAL_BASED_NOT_SUPPORTED) return; + if (mImsManager != null) { + try { + mImsManager.setTerminalBasedCallWaitingStatus( + state == TERMINAL_BASED_ACTIVATED); + } catch (ImsException e) { + loge("setTerminalBasedCallWaitingStatus : exception " + e); + } + } + } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java index ee251fbc78..63fa1cb056 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java @@ -62,6 +62,7 @@ import com.android.ims.ImsException; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CallForwardInfo; import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CallWaitingController; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.MmiCode; @@ -1114,10 +1115,25 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { int serviceClass = siToServiceClass(mSia); if (isActivate() || isDeactivate()) { + if (serviceClass == SERVICE_CLASS_NONE + || (serviceClass & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE) { + if (mPhone.getTerminalBasedCallWaitingState() + != CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED) { + mPhone.getDefaultPhone().setCallWaiting(isActivate(), serviceClass, + obtainMessage(EVENT_SET_COMPLETE, this)); + return; + } + } mPhone.setCallWaiting(isActivate(), serviceClass, obtainMessage(EVENT_SET_COMPLETE, this)); } else if (isInterrogate()) { - mPhone.getCallWaiting(obtainMessage(EVENT_QUERY_COMPLETE, this)); + if (mPhone.getTerminalBasedCallWaitingState() + != CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED) { + mPhone.getDefaultPhone() + .getCallWaiting(obtainMessage(EVENT_QUERY_COMPLETE, this)); + } else { + mPhone.getCallWaiting(obtainMessage(EVENT_QUERY_COMPLETE, this)); + } } else { throw new RuntimeException ("Invalid or Unsupported MMI Code"); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java new file mode 100644 index 0000000000..544902e4e7 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2021 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; + +import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_NONE; +import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL; +import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT; +import static android.telephony.CarrierConfigManager.ImsSs.KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY; +import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CW; + +import static com.android.internal.telephony.CallWaitingController.KEY_CS_SYNC; +import static com.android.internal.telephony.CallWaitingController.KEY_STATE; +import static com.android.internal.telephony.CallWaitingController.KEY_SUB_ID; +import static com.android.internal.telephony.CallWaitingController.PREFERENCE_TBCW; +import static com.android.internal.telephony.CallWaitingController.TERMINAL_BASED_ACTIVATED; +import static com.android.internal.telephony.CallWaitingController.TERMINAL_BASED_NOT_ACTIVATED; +import static com.android.internal.telephony.CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED; +import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_DATA; +import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE; +import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.PersistableBundle; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class CallWaitingControllerTest extends TelephonyTest { + private static final int FAKE_SUB_ID = 1; + + private static final int GET_DONE = 1; + + private CallWaitingController mCWC; + private GetTestHandler mHandler; + + @Before + public void setUp() throws Exception { + super.setUp(this.getClass().getSimpleName()); + mSimulatedCommands.setRadioPower(true, null); + mPhone.mCi = this.mSimulatedCommands; + doReturn(FAKE_SUB_ID).when(mPhone).getSubId(); + + mCWC = new CallWaitingController(mPhone); + logd("CallWaitingController initiated, waiting for Power on"); + /* Make sure radio state is power on before dial. + * When radio state changed from off to on, CallTracker + * will poll result from RIL. Avoid dialing triggered at the same*/ + processAllMessages(); + } + + @After + public void tearDown() throws Exception { + mCWC = null; + super.tearDown(); + } + + @Test + @SmallTest + public void testSetTerminalBasedCallWaitingSupported() { + mCWC.setTerminalBasedCallWaitingSupported(true); + PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_NONE, true); + mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + + mCWC.setTerminalBasedCallWaitingSupported(false); + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_SUPPORTED); + } + + @Test + @SmallTest + public void testInitialize() { + mCWC.setTerminalBasedCallWaitingSupported(false); + setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, + TERMINAL_BASED_ACTIVATED, CALL_WAITING_SYNC_NONE); + PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_NONE, true); + doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); + mCWC.setTerminalBasedCallWaitingSupported(true); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + + mCWC.setTerminalBasedCallWaitingSupported(false); + setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, + TERMINAL_BASED_NOT_ACTIVATED, CALL_WAITING_SYNC_NONE); + mCWC.setTerminalBasedCallWaitingSupported(true); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + + mCWC.setTerminalBasedCallWaitingSupported(false); + bundle = getBundle(false, CALL_WAITING_SYNC_NONE, false); + doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); + mCWC.setTerminalBasedCallWaitingSupported(true); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_SUPPORTED); + } + + @Test + @SmallTest + public void testCarrierConfigChanged() { + mCWC.setTerminalBasedCallWaitingSupported(true); + PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_NONE, true); + mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + + bundle = getBundle(false, CALL_WAITING_SYNC_NONE, true); + mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, false); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_SUPPORTED); + } + + + private static class GetTestHandler extends Handler { + public int[] resp; + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case GET_DONE: + AsyncResult ar = (AsyncResult) msg.obj; + resp = (int[]) ar.result; + break; + default: + } + } + + public void reset() { + resp = null; + } + } + + @Test + @SmallTest + public void testGetCallWaitingSyncNone() { + mCWC.setTerminalBasedCallWaitingSupported(false); + assertFalse(mCWC.getCallWaiting(null)); + + mCWC.setTerminalBasedCallWaitingSupported(true); + PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_NONE, true); + mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + + mHandler = new GetTestHandler(); + + assertTrue(mCWC.setCallWaiting(true, SERVICE_CLASS_VOICE, null)); + mTestableLooper.processAllMessages(); + + assertTrue(mCWC.getCallWaiting(mHandler.obtainMessage(GET_DONE))); + mTestableLooper.processAllMessages(); + + assertNotNull(mHandler.resp); + assertEquals(2, mHandler.resp.length); + assertEquals(TERMINAL_BASED_ACTIVATED, mHandler.resp[0]); + assertEquals(SERVICE_CLASS_VOICE, mHandler.resp[1]); + + mHandler.reset(); + + assertTrue(mCWC.setCallWaiting(false, SERVICE_CLASS_VOICE, null)); + mTestableLooper.processAllMessages(); + + assertTrue(mCWC.getCallWaiting(mHandler.obtainMessage(GET_DONE))); + mTestableLooper.processAllMessages(); + + assertNotNull(mHandler.resp); + assertEquals(2, mHandler.resp.length); + assertEquals(TERMINAL_BASED_NOT_ACTIVATED, mHandler.resp[0]); + assertEquals(SERVICE_CLASS_NONE, mHandler.resp[1]); + } + + @Test + @SmallTest + public void testSetCallWaitingSyncNone() { + mCWC.setTerminalBasedCallWaitingSupported(false); + assertFalse(mCWC.setCallWaiting(true, SERVICE_CLASS_VOICE, null)); + + mCWC.setTerminalBasedCallWaitingSupported(true); + PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_NONE, true); + mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + + assertTrue(mCWC.setCallWaiting(true, SERVICE_CLASS_VOICE, null)); + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_ACTIVATED); + + assertTrue(mCWC.setCallWaiting(false, SERVICE_CLASS_VOICE | SERVICE_CLASS_DATA, null)); + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); + + assertFalse(mCWC.setCallWaiting(true, SERVICE_CLASS_DATA, null)); + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); + + assertFalse(mCWC.setCallWaiting(true, SERVICE_CLASS_NONE, null)); + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); + } + + private PersistableBundle getBundle(boolean provisioned, int preference, boolean defaultState) { + PersistableBundle bundle = new PersistableBundle(); + bundle.putIntArray(KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY, + provisioned ? new int[] { SUPPLEMENTARY_SERVICE_CW } : new int[] { }); + bundle.putInt(KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT, preference); + bundle.putBoolean(KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL, defaultState); + return bundle; + } + + private int retrieveStatePreference(int subId) { + SharedPreferences sp = + mContext.getSharedPreferences(PREFERENCE_TBCW, Context.MODE_PRIVATE); + return sp.getInt(KEY_STATE + subId, TERMINAL_BASED_NOT_SUPPORTED); + } + + private void setPreference(int phoneId, int subId, int state, int syncPreference) { + SharedPreferences sp = + mContext.getSharedPreferences(PREFERENCE_TBCW, Context.MODE_PRIVATE); + + SharedPreferences.Editor editor = sp.edit(); + editor.putInt(KEY_SUB_ID + phoneId, subId); + editor.putInt(KEY_STATE + subId, state); + editor.putInt(KEY_CS_SYNC + phoneId, syncPreference); + editor.apply(); + } +} -- GitLab From 5a295f5cb39c60066c473f397bc646ec1185a713 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 7 Dec 2021 21:28:44 +0000 Subject: [PATCH 036/656] Update CallWaitingController, SYNC_USER_CHANGE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the configuration, CALL_WAITING_SYNC_USER_CHANGE The change of user’s setting is always passed to the CS network. Bug: 202463005 Test: atest Change-Id: I1f21bb0f3f6b5f21ed9eb08527a05eb9595a52b7 (cherry picked from commit 9f80747d451e02c5f68deb182e227e3349f1d052) Merged-In: I1f21bb0f3f6b5f21ed9eb08527a05eb9595a52b7 --- .../telephony/CallWaitingController.java | 68 ++++++++++++++++++- .../telephony/CallWaitingControllerTest.java | 53 +++++++++++++++ .../internal/telephony/SimulatedCommands.java | 18 ++++- 3 files changed, 136 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java index a9d51a0820..15b5d24b4a 100644 --- a/src/java/com/android/internal/telephony/CallWaitingController.java +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_NONE; +import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_USER_CHANGE; import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL; import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT; import static android.telephony.CarrierConfigManager.ImsSs.KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY; @@ -33,6 +34,7 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.AsyncResult; import android.os.Bundle; +import android.os.Handler; import android.os.Message; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -46,7 +48,7 @@ import com.android.telephony.Rlog; * * {@hide} */ -public class CallWaitingController { +public class CallWaitingController extends Handler { public static final String LOG_TAG = "CallWaiting"; private static final boolean DBG = false; /* STOPSHIP if true */ @@ -58,6 +60,20 @@ public class CallWaitingController { // Terminal-based call waiting is supported and activated. */ public static final int TERMINAL_BASED_ACTIVATED = 1; + private static final int EVENT_SET_CALL_WAITING_DONE = 1; + private static final int EVENT_GET_CALL_WAITING_DONE = 2; + + // Class to pack mOnComplete object passed by the caller + private static class Cw { + final boolean mEnable; + final Message mOnComplete; + + Cw(boolean enable, Message onComplete) { + mEnable = enable; + mOnComplete = onComplete; + } + } + @VisibleForTesting public static final String PREFERENCE_TBCW = "terminal_based_call_waiting"; @VisibleForTesting @@ -157,6 +173,11 @@ public class CallWaitingController { if (mSyncPreference == CALL_WAITING_SYNC_NONE) { sendGetCallWaitingResponse(onComplete); return true; + } else if (mSyncPreference == CALL_WAITING_SYNC_USER_CHANGE) { + Cw cw = new Cw(false, onComplete); + Message resp = obtainMessage(EVENT_GET_CALL_WAITING_DONE, 0, 0, cw); + mPhone.mCi.queryCallWaiting(SERVICE_CLASS_NONE, resp); + return true; } return false; @@ -182,11 +203,56 @@ public class CallWaitingController { sendToTarget(onComplete, null, null); return true; + } else if (mSyncPreference == CALL_WAITING_SYNC_USER_CHANGE) { + Cw cw = new Cw(enable, onComplete); + Message resp = obtainMessage(EVENT_SET_CALL_WAITING_DONE, 0, 0, cw); + mPhone.mCi.setCallWaiting(enable, serviceClass, resp); + return true; } return false; } + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_SET_CALL_WAITING_DONE: + onSetCallWaitingDone((AsyncResult) msg.obj); + break; + case EVENT_GET_CALL_WAITING_DONE: + onGetCallWaitingDone((AsyncResult) msg.obj); + break; + } + } + + private void onSetCallWaitingDone(AsyncResult ar) { + if (ar.userObj != null && ar.userObj instanceof Cw) { + if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone"); + Cw cw = (Cw) ar.userObj; + if (ar.exception == null) { + updateState( + cw.mEnable ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); + } + sendToTarget(cw.mOnComplete, ar.result, ar.exception); + } + } + + private void onGetCallWaitingDone(AsyncResult ar) { + if (ar.userObj != null && ar.userObj instanceof Cw) { + if (DBG) Rlog.d(LOG_TAG, "onGetCallWaitingDone"); + Cw cw = (Cw) ar.userObj; + if (ar.exception == null) { + int[] resp = (int[]) ar.result; + if (resp != null && resp.length > 1) { + boolean enabled = + resp[0] == 1 && (resp[1] & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE; + updateState(enabled ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); + } + } + sendToTarget(cw.mOnComplete, ar.result, ar.exception); + } + } + private void sendToTarget(Message onComplete, Object result, Throwable exception) { if (onComplete != null) { AsyncResult.forMessage(onComplete, result, exception); diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java index 544902e4e7..8aa4a05f5f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_NONE; +import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_USER_CHANGE; import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL; import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT; import static android.telephony.CarrierConfigManager.ImsSs.KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY; @@ -224,6 +225,58 @@ public class CallWaitingControllerTest extends TelephonyTest { assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); } + @Test + @SmallTest + public void testSyncUserChange() { + mCWC.setTerminalBasedCallWaitingSupported(false); + setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, + TERMINAL_BASED_ACTIVATED, CALL_WAITING_SYNC_USER_CHANGE); + mCWC.setTerminalBasedCallWaitingSupported(true); + PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_USER_CHANGE, true); + mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_ACTIVATED); + + mHandler = new GetTestHandler(); + + mSimulatedCommands.setCallWaiting(false, SERVICE_CLASS_VOICE, null); + + assertTrue(mCWC.getCallWaiting(mHandler.obtainMessage(GET_DONE))); + mTestableLooper.processAllMessages(); + + assertNotNull(mHandler.resp); + assertEquals(2, mHandler.resp.length); + assertEquals(TERMINAL_BASED_NOT_ACTIVATED, mHandler.resp[0]); + assertEquals(SERVICE_CLASS_NONE, mHandler.resp[1]); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); + + mHandler.reset(); + + mSimulatedCommands.setCallWaiting(true, SERVICE_CLASS_VOICE, null); + + assertTrue(mCWC.getCallWaiting(mHandler.obtainMessage(GET_DONE))); + mTestableLooper.processAllMessages(); + + assertNotNull(mHandler.resp); + assertEquals(2, mHandler.resp.length); + assertEquals(TERMINAL_BASED_ACTIVATED, mHandler.resp[0]); + assertEquals(SERVICE_CLASS_VOICE, mHandler.resp[1]); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_ACTIVATED); + + mHandler.reset(); + + assertTrue(mCWC.setCallWaiting(false, SERVICE_CLASS_VOICE, null)); + mTestableLooper.processAllMessages(); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); + } + private PersistableBundle getBundle(boolean provisioned, int preference, boolean defaultState) { PersistableBundle bundle = new PersistableBundle(); bundle.putIntArray(KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY, diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index 92d163d1bd..986047cd3d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -186,6 +186,8 @@ public class SimulatedCommands extends BaseCommands public boolean mSetRadioPowerForEmergencyCall; public boolean mSetRadioPowerAsSelectedPhoneForEmergencyCall; + public boolean mCallWaitActivated = false; + // mode for Icc Sim Authentication private int mAuthenticationMode; //***** Constructor @@ -1432,6 +1434,14 @@ public class SimulatedCommands extends BaseCommands @Override public void queryCallWaiting(int serviceClass, Message response) { + if (response != null && serviceClass == SERVICE_CLASS_NONE) { + int[] r = new int[2]; + r[0] = (mCallWaitActivated ? 1 : 0); + r[1] = (mCallWaitActivated ? SERVICE_CLASS_VOICE : SERVICE_CLASS_NONE); + resultSuccess(response, r); + return; + } + unimplemented(response); } @@ -1440,11 +1450,15 @@ public class SimulatedCommands extends BaseCommands * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - @Override public void setCallWaiting(boolean enable, int serviceClass, Message response) { - unimplemented(response); + if ((serviceClass & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE) { + mCallWaitActivated = enable; + } + if (response != null) { + resultSuccess(response, null); + } } /** -- GitLab From bdba7d8732ab6c93086938e21130145e8b0e724a Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 10 Dec 2021 19:15:47 +0000 Subject: [PATCH 037/656] Update CallWaitingController, SYNC_FIRST_POWER_UP Implement the configuration CALL_WAITING_SYNC_FIRST_POWER_UP The configuration is same with CALL_WAITING_SYNC_NONE, except that UE enables call waiting in the CS network when the SIM gets changed or the device boots. Bug: 202463005 Test: atest Change-Id: I34d341748743d7d9a400ae730b7647b81284f786 (cherry picked from commit ce2a584f3aab80b4b4e9d2a72bc184b3401f7b4d) Merged-In: I34d341748743d7d9a400ae730b7647b81284f786 --- .../telephony/CallWaitingController.java | 161 ++++++++++++++++-- .../telephony/CallWaitingControllerTest.java | 18 ++ 2 files changed, 163 insertions(+), 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java index 15b5d24b4a..7d140a8d19 100644 --- a/src/java/com/android/internal/telephony/CallWaitingController.java +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_FIRST_POWER_UP; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_NONE; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_USER_CHANGE; import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL; @@ -62,6 +63,7 @@ public class CallWaitingController extends Handler { private static final int EVENT_SET_CALL_WAITING_DONE = 1; private static final int EVENT_GET_CALL_WAITING_DONE = 2; + private static final int EVENT_REGISTERED_TO_NETWORK = 3; // Class to pack mOnComplete object passed by the caller private static class Cw { @@ -119,12 +121,17 @@ public class CallWaitingController extends Handler { private int mSyncPreference = CALL_WAITING_SYNC_NONE; private int mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + private boolean mCsEnabled = false; + private boolean mRegisteredForNetworkAttach = false; + private GsmCdmaPhone mPhone; + private ServiceStateTracker mSST; private Context mContext; // Constructors public CallWaitingController(GsmCdmaPhone phone) { mPhone = phone; + mSST = phone.getServiceStateTracker(); mContext = phone.getContext(); } @@ -142,7 +149,8 @@ public class CallWaitingController extends Handler { Rlog.i(LOG_TAG, "initialize phoneId=" + phoneId + ", lastSubId=" + mLastSubId + ", subId=" + subId - + ", state=" + mCallWaitingState + ", sync=" + mSyncPreference); + + ", state=" + mCallWaitingState + ", sync=" + mSyncPreference + + ", csEnabled=" + mCsEnabled); } /** @@ -170,7 +178,8 @@ public class CallWaitingController extends Handler { Rlog.i(LOG_TAG, "getCallWaiting " + mCallWaitingState); - if (mSyncPreference == CALL_WAITING_SYNC_NONE) { + if (mSyncPreference == CALL_WAITING_SYNC_NONE + || mSyncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP) { sendGetCallWaitingResponse(onComplete); return true; } else if (mSyncPreference == CALL_WAITING_SYNC_USER_CHANGE) { @@ -197,7 +206,8 @@ public class CallWaitingController extends Handler { Rlog.i(LOG_TAG, "setCallWaiting enable=" + enable + ", service=" + serviceClass); - if (mSyncPreference == CALL_WAITING_SYNC_NONE) { + if (mSyncPreference == CALL_WAITING_SYNC_NONE + || mSyncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP) { updateState( enable ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); @@ -222,35 +232,87 @@ public class CallWaitingController extends Handler { case EVENT_GET_CALL_WAITING_DONE: onGetCallWaitingDone((AsyncResult) msg.obj); break; + case EVENT_REGISTERED_TO_NETWORK: + onRegisteredToNetwork(); + break; } } private void onSetCallWaitingDone(AsyncResult ar) { - if (ar.userObj != null && ar.userObj instanceof Cw) { - if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone"); - Cw cw = (Cw) ar.userObj; + if (ar.userObj == null) { + // For the case, CALL_WAITING_SYNC_FIRST_POWER_UP + if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone to sync on network attached"); if (ar.exception == null) { - updateState( - cw.mEnable ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); + updateSyncState(true); + } else { + Rlog.e(LOG_TAG, "onSetCallWaitingDone e=" + ar.exception); } - sendToTarget(cw.mOnComplete, ar.result, ar.exception); + return; } + + if (!(ar.userObj instanceof Cw)) { + // Unexpected state + if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone unexpected result"); + return; + } + + if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone"); + Cw cw = (Cw) ar.userObj; + if (ar.exception == null) { + updateState( + cw.mEnable ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); + } + sendToTarget(cw.mOnComplete, ar.result, ar.exception); } private void onGetCallWaitingDone(AsyncResult ar) { - if (ar.userObj != null && ar.userObj instanceof Cw) { - if (DBG) Rlog.d(LOG_TAG, "onGetCallWaitingDone"); - Cw cw = (Cw) ar.userObj; + if (ar.userObj == null) { + // For the case, CALL_WAITING_SYNC_FIRST_POWER_UP + if (DBG) Rlog.d(LOG_TAG, "onGetCallWaitingDone to sync on network attached"); + boolean enabled = false; if (ar.exception == null) { + //resp[0]: 1 if enabled, 0 otherwise + //resp[1]: bitwise ORs of SERVICE_CLASS_* constants int[] resp = (int[]) ar.result; if (resp != null && resp.length > 1) { - boolean enabled = - resp[0] == 1 && (resp[1] & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE; - updateState(enabled ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); + enabled = (resp[0] == 1) + && (resp[1] & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE; + } else { + Rlog.e(LOG_TAG, "onGetCallWaitingDone unexpected response"); } + } else { + Rlog.e(LOG_TAG, "onGetCallWaitingDone e=" + ar.exception); + } + if (enabled) { + updateSyncState(true); + } else { + Rlog.i(LOG_TAG, "onGetCallWaitingDone enabling CW service in CS network"); + mPhone.mCi.setCallWaiting(true, SERVICE_CLASS_VOICE, + obtainMessage(EVENT_SET_CALL_WAITING_DONE)); } - sendToTarget(cw.mOnComplete, ar.result, ar.exception); + unregisterForNetworkAttached(); + return; } + + if (!(ar.userObj instanceof Cw)) { + // Unexpected state + if (DBG) Rlog.d(LOG_TAG, "onGetCallWaitingDone unexpected result"); + return; + } + + if (DBG) Rlog.d(LOG_TAG, "onGetCallWaitingDone"); + Cw cw = (Cw) ar.userObj; + if (ar.exception == null) { + int[] resp = (int[]) ar.result; + //resp[0]: 1 if enabled, 0 otherwise + //resp[1]: bitwise ORs of SERVICE_CLASS_ + if (resp != null && resp.length > 1) { + boolean enabled = + resp[0] == 1 && (resp[1] & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE; + updateState(enabled ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); + } + } + sendToTarget(cw.mOnComplete, ar.result, ar.exception); } private void sendToTarget(Message onComplete, Object result, Throwable exception) { @@ -270,12 +332,22 @@ public class CallWaitingController extends Handler { } } + private void onRegisteredToNetwork() { + if (mCsEnabled) return; + + if (DBG) Rlog.d(LOG_TAG, "onRegisteredToNetwork"); + + mPhone.mCi.queryCallWaiting(SERVICE_CLASS_NONE, + obtainMessage(EVENT_GET_CALL_WAITING_DONE)); + } + private void onCarrierConfigChanged() { int subId = mPhone.getSubId(); if (!SubscriptionManager.isValidSubscriptionId(subId)) { Rlog.i(LOG_TAG, "onCarrierConfigChanged invalid subId=" + subId); mValidSubscription = false; + unregisterForNetworkAttached(); return; } @@ -283,6 +355,14 @@ public class CallWaitingController extends Handler { PersistableBundle b = configManager.getConfigForSubId(subId); updateCarrierConfig(subId, b, false); + + Rlog.i(LOG_TAG, "onCarrierConfigChanged cs_enabled=" + mCsEnabled); + + if (mSyncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP) { + if (!mCsEnabled) { + registerForNetworkAttached(); + } + } } /** @@ -322,6 +402,9 @@ public class CallWaitingController extends Handler { if (enforced) { desiredState = defaultState; + } else if ((mLastSubId != subId) + && (syncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP)) { + desiredState = defaultState; } else { if (defaultState == TERMINAL_BASED_NOT_SUPPORTED) { desiredState = TERMINAL_BASED_NOT_SUPPORTED; @@ -365,6 +448,9 @@ public class CallWaitingController extends Handler { mCallWaitingState = state; mLastSubId = subId; mSyncPreference = syncPreference; + if (mLastSubId != subId) { + mCsEnabled = false; + } mPhone.setTerminalBasedCallWaitingStatus(mCallWaitingState); } @@ -378,6 +464,40 @@ public class CallWaitingController extends Handler { return state; } + + private void updateSyncState(boolean enabled) { + int phoneId = mPhone.getPhoneId(); + + Rlog.i(LOG_TAG, "updateSyncState phoneId=" + phoneId + ", enabled=" + enabled); + + mCsEnabled = enabled; + } + + /** + * @return whether the service is enabled in the CS network + */ + @VisibleForTesting + public boolean getSyncState() { + return mCsEnabled; + } + + private void registerForNetworkAttached() { + Rlog.i(LOG_TAG, "registerForNetworkAttached"); + if (mRegisteredForNetworkAttach) return; + + mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); + mRegisteredForNetworkAttach = true; + } + + private void unregisterForNetworkAttached() { + Rlog.i(LOG_TAG, "unregisterForNetworkAttached"); + if (!mRegisteredForNetworkAttach) return; + + mSST.unregisterForNetworkAttached(this); + removeMessages(EVENT_REGISTERED_TO_NETWORK); + mRegisteredForNetworkAttach = false; + } + /** * Sets whether the device supports the terminal-based call waiting. * Only for test @@ -398,4 +518,13 @@ public class CallWaitingController extends Handler { updateState(TERMINAL_BASED_NOT_SUPPORTED); } } + + /** + * Notifies that the UE has attached to the network + * Only for test + */ + @VisibleForTesting + public void notifyRegisteredToNetwork() { + sendEmptyMessage(EVENT_REGISTERED_TO_NETWORK); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java index 8aa4a05f5f..4c9e072965 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java @@ -15,6 +15,7 @@ */ package com.android.internal.telephony; +import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_FIRST_POWER_UP; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_NONE; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_USER_CHANGE; import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL; @@ -277,6 +278,23 @@ public class CallWaitingControllerTest extends TelephonyTest { assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); } + @Test + @SmallTest + public void testSyncFirstPowerUp() { + mCWC.setTerminalBasedCallWaitingSupported(false); + setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, + TERMINAL_BASED_NOT_ACTIVATED, CALL_WAITING_SYNC_FIRST_POWER_UP); + mCWC.setTerminalBasedCallWaitingSupported(true); + PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_FIRST_POWER_UP, true); + mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + assertFalse(mCWC.getSyncState()); + + mCWC.notifyRegisteredToNetwork(); + mTestableLooper.processAllMessages(); + + assertTrue(mCWC.getSyncState()); + } + private PersistableBundle getBundle(boolean provisioned, int preference, boolean defaultState) { PersistableBundle bundle = new PersistableBundle(); bundle.putIntArray(KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY, -- GitLab From d08067b2ff18f527be8dc1b1f3dc70a310694f56 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Sat, 11 Dec 2021 13:11:44 +0000 Subject: [PATCH 038/656] Update CallWaitingController, SYNC_FIRST_CHANGE Implement the configuration CALL_WAITING_SYNC_FIRST_CHANGE The configuration is same with CALL_WAITING_SYNC_NONE, except that UE enables call waiting in the CS network when user enables the service for the first time in a power cycle. Bug: 202463005 Test: atest Change-Id: I1f388e334e6d691fca2767f3f3b7e493ac7abf0c (cherry picked from commit 18a1eeff85c96b88603d69a07c1dd73d27161291) Merged-In: I1f388e334e6d691fca2767f3f3b7e493ac7abf0c --- .../telephony/CallWaitingController.java | 119 ++++++++++++++++-- .../internal/telephony/GsmCdmaPhone.java | 1 + .../telephony/CallWaitingControllerTest.java | 40 ++++++ 3 files changed, 151 insertions(+), 9 deletions(-) diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java index 7d140a8d19..d3e5850d2e 100644 --- a/src/java/com/android/internal/telephony/CallWaitingController.java +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_FIRST_CHANGE; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_FIRST_POWER_UP; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_NONE; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_USER_CHANGE; @@ -39,6 +40,7 @@ import android.os.Handler; import android.os.Message; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; +import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import com.android.internal.annotations.VisibleForTesting; @@ -69,10 +71,12 @@ public class CallWaitingController extends Handler { private static class Cw { final boolean mEnable; final Message mOnComplete; + final boolean mImsRegistered; - Cw(boolean enable, Message onComplete) { + Cw(boolean enable, boolean imsRegistered, Message onComplete) { mEnable = enable; mOnComplete = onComplete; + mImsRegistered = imsRegistered; } } @@ -123,6 +127,7 @@ public class CallWaitingController extends Handler { private boolean mCsEnabled = false; private boolean mRegisteredForNetworkAttach = false; + private boolean mImsRegistered = false; private GsmCdmaPhone mPhone; private ServiceStateTracker mSST; @@ -178,12 +183,26 @@ public class CallWaitingController extends Handler { Rlog.i(LOG_TAG, "getCallWaiting " + mCallWaitingState); + if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { + // Interrogate CW in CS network + if (!mCsEnabled) { + // skip interrogation if CS is not available and IMS is registered + if (isCircuitSwitchedNetworkAvailable() || !isImsRegistered()) { + Cw cw = new Cw(false, isImsRegistered(), onComplete); + Message resp = obtainMessage(EVENT_GET_CALL_WAITING_DONE, 0, 0, cw); + mPhone.mCi.queryCallWaiting(SERVICE_CLASS_NONE, resp); + return true; + } + } + } + if (mSyncPreference == CALL_WAITING_SYNC_NONE + || mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE || mSyncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP) { sendGetCallWaitingResponse(onComplete); return true; } else if (mSyncPreference == CALL_WAITING_SYNC_USER_CHANGE) { - Cw cw = new Cw(false, onComplete); + Cw cw = new Cw(false, isImsRegistered(), onComplete); Message resp = obtainMessage(EVENT_GET_CALL_WAITING_DONE, 0, 0, cw); mPhone.mCi.queryCallWaiting(SERVICE_CLASS_NONE, resp); return true; @@ -206,7 +225,24 @@ public class CallWaitingController extends Handler { Rlog.i(LOG_TAG, "setCallWaiting enable=" + enable + ", service=" + serviceClass); + if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { + // Enable CW in the CS network + if (!mCsEnabled && enable) { + if (isCircuitSwitchedNetworkAvailable() || !isImsRegistered()) { + Cw cw = new Cw(true, isImsRegistered(), onComplete); + Message resp = obtainMessage(EVENT_SET_CALL_WAITING_DONE, 0, 0, cw); + mPhone.mCi.setCallWaiting(true, serviceClass, resp); + return true; + } else { + // CS network is not available, however, IMS is registered. + // Enabling the service in the CS network will be delayed. + registerForNetworkAttached(); + } + } + } + if (mSyncPreference == CALL_WAITING_SYNC_NONE + || mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE || mSyncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP) { updateState( enable ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); @@ -214,7 +250,7 @@ public class CallWaitingController extends Handler { sendToTarget(onComplete, null, null); return true; } else if (mSyncPreference == CALL_WAITING_SYNC_USER_CHANGE) { - Cw cw = new Cw(enable, onComplete); + Cw cw = new Cw(enable, isImsRegistered(), onComplete); Message resp = obtainMessage(EVENT_SET_CALL_WAITING_DONE, 0, 0, cw); mPhone.mCi.setCallWaiting(enable, serviceClass, resp); return true; @@ -259,8 +295,20 @@ public class CallWaitingController extends Handler { if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone"); Cw cw = (Cw) ar.userObj; if (ar.exception == null) { + if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { + // SYNC_FIRST_CHANGE implies cw.mEnable is true. + updateSyncState(true); + } updateState( cw.mEnable ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); + } else if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { + if (cw.mImsRegistered) { + // IMS is registered. Do not notify error. + // SYNC_FIRST_CHANGE implies cw.mEnable is true. + updateState(TERMINAL_BASED_ACTIVATED); + sendToTarget(cw.mOnComplete, null, null); + return; + } } sendToTarget(cw.mOnComplete, ar.result, ar.exception); } @@ -306,10 +354,42 @@ public class CallWaitingController extends Handler { int[] resp = (int[]) ar.result; //resp[0]: 1 if enabled, 0 otherwise //resp[1]: bitwise ORs of SERVICE_CLASS_ - if (resp != null && resp.length > 1) { - boolean enabled = - resp[0] == 1 && (resp[1] & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE; - updateState(enabled ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); + if (resp == null || resp.length < 2) { + Rlog.i(LOG_TAG, "onGetCallWaitingDone unexpected response"); + if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { + // no exception but unexpected response, local setting is preferred. + sendGetCallWaitingResponse(cw.mOnComplete); + } else { + sendToTarget(cw.mOnComplete, ar.result, ar.exception); + } + return; + } + + boolean enabled = resp[0] == 1 + && (resp[1] & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE; + + if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { + updateSyncState(enabled); + + if (!enabled && !cw.mImsRegistered) { + // IMS is not registered, change the local setting + Rlog.i(LOG_TAG, "onGetCallWaitingDone CW in CS network is disabled."); + updateState(TERMINAL_BASED_NOT_ACTIVATED); + } + + // return the user setting saved + sendGetCallWaitingResponse(cw.mOnComplete); + return; + } + updateState(enabled ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); + } else if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { + // Got an exception + if (cw.mImsRegistered) { + // queryCallWaiting failed. However, IMS is registered. Do not notify error. + // return the user setting saved + Rlog.i(LOG_TAG, "onGetCallWaitingDone get an exception, but IMS is registered"); + sendGetCallWaitingResponse(cw.mOnComplete); + return; } } sendToTarget(cw.mOnComplete, ar.result, ar.exception); @@ -384,7 +464,7 @@ public class CallWaitingController extends Handler { } } int syncPreference = b.getInt(KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT, - CALL_WAITING_SYNC_NONE); + CALL_WAITING_SYNC_FIRST_CHANGE); boolean activated = b.getBoolean(KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL); int defaultState = supportsTerminalBased ? (activated ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED) @@ -403,7 +483,8 @@ public class CallWaitingController extends Handler { if (enforced) { desiredState = defaultState; } else if ((mLastSubId != subId) - && (syncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP)) { + && (syncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP + || syncPreference == CALL_WAITING_SYNC_FIRST_CHANGE)) { desiredState = defaultState; } else { if (defaultState == TERMINAL_BASED_NOT_SUPPORTED) { @@ -481,6 +562,26 @@ public class CallWaitingController extends Handler { return mCsEnabled; } + private boolean isCircuitSwitchedNetworkAvailable() { + Rlog.i(LOG_TAG, "isCircuitSwitchedNetworkAvailable=" + + (mSST.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)); + return mSST.getServiceState().getState() == ServiceState.STATE_IN_SERVICE; + } + + private boolean isImsRegistered() { + Rlog.i(LOG_TAG, "isImsRegistered " + mImsRegistered); + return mImsRegistered; + } + + /** + * Sets the registration state of IMS service. + */ + public void setImsRegistrationState(boolean registered) { + Rlog.i(LOG_TAG, "setImsRegistrationState prev=" + mImsRegistered + + ", new=" + registered); + mImsRegistered = registered; + } + private void registerForNetworkAttached() { Rlog.i(LOG_TAG, "registerForNetworkAttached"); if (mRegisteredForNetworkAttach) return; diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index b62a5d2c02..e638339182 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -4463,6 +4463,7 @@ public class GsmCdmaPhone extends Phone { @Override public void setImsRegistrationState(boolean registered) { mSST.setImsRegistrationState(registered); + mCallWaitingController.setImsRegistrationState(registered); } @Override diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java index 4c9e072965..c71059e764 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java @@ -15,6 +15,7 @@ */ package com.android.internal.telephony; +import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_FIRST_CHANGE; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_FIRST_POWER_UP; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_NONE; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_USER_CHANGE; @@ -295,6 +296,45 @@ public class CallWaitingControllerTest extends TelephonyTest { assertTrue(mCWC.getSyncState()); } + @Test + @SmallTest + public void testSyncFirstChange() { + mCWC.setTerminalBasedCallWaitingSupported(false); + setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, + TERMINAL_BASED_NOT_ACTIVATED, CALL_WAITING_SYNC_FIRST_CHANGE); + mCWC.setTerminalBasedCallWaitingSupported(true); + PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_FIRST_CHANGE, true); + mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + mCWC.setImsRegistrationState(false); + + assertFalse(mCWC.getSyncState()); + + mSimulatedCommands.setCallWaiting(false, SERVICE_CLASS_VOICE, null); + mCWC.getCallWaiting(null); + mTestableLooper.processAllMessages(); + + assertFalse(mCWC.getSyncState()); + + mSimulatedCommands.setCallWaiting(true, SERVICE_CLASS_VOICE, null); + mCWC.getCallWaiting(null); + mTestableLooper.processAllMessages(); + + assertTrue(mCWC.getSyncState()); + + assertTrue(mCWC.setCallWaiting(true, SERVICE_CLASS_VOICE, null)); + mTestableLooper.processAllMessages(); + + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(mSimulatedCommands.mCallWaitActivated); + + assertTrue(mCWC.setCallWaiting(false, SERVICE_CLASS_VOICE, null)); + mTestableLooper.processAllMessages(); + + // Local setting changed, but no change in CS network. + assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mSimulatedCommands.mCallWaitActivated); + } + private PersistableBundle getBundle(boolean provisioned, int preference, boolean defaultState) { PersistableBundle bundle = new PersistableBundle(); bundle.putIntArray(KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY, -- GitLab From d337dba008cccf01ced5bd28f62c4732e82c90db Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 27 Jan 2022 13:37:29 +0000 Subject: [PATCH 039/656] Add dump to CallWaitingController Bug: 202463005 Test: atest Change-Id: Ic9f4a9ee0e5d96c7355b770c2554c7716fedc743 (cherry picked from commit e1af04b87317ec26931b9b2b8e0701b00c14af36) Merged-In: Ic9f4a9ee0e5d96c7355b770c2554c7716fedc743 --- .../telephony/CallWaitingController.java | 29 +++++++++++++++---- .../internal/telephony/GsmCdmaPhone.java | 7 +++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java index d3e5850d2e..9ac58f1152 100644 --- a/src/java/com/android/internal/telephony/CallWaitingController.java +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -44,12 +44,13 @@ import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; +import java.io.PrintWriter; + /** * Controls the change of the user setting of the call waiting service - * - * {@hide} */ public class CallWaitingController extends Handler { @@ -129,9 +130,9 @@ public class CallWaitingController extends Handler { private boolean mRegisteredForNetworkAttach = false; private boolean mImsRegistered = false; - private GsmCdmaPhone mPhone; - private ServiceStateTracker mSST; - private Context mContext; + private final GsmCdmaPhone mPhone; + private final ServiceStateTracker mSST; + private final Context mContext; // Constructors public CallWaitingController(GsmCdmaPhone phone) { @@ -628,4 +629,22 @@ public class CallWaitingController extends Handler { public void notifyRegisteredToNetwork() { sendEmptyMessage(EVENT_REGISTERED_TO_NETWORK); } + + /** + * Dump this instance into a readable format for dumpsys usage. + */ + public void dump(PrintWriter printWriter) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.increaseIndent(); + pw.println("CallWaitingController:"); + pw.println(" mSupportedByImsService=" + mSupportedByImsService); + pw.println(" mValidSubscription=" + mValidSubscription); + pw.println(" mCallWaitingState=" + mCallWaitingState); + pw.println(" mSyncPreference=" + mSyncPreference); + pw.println(" mLastSubId=" + mLastSubId); + pw.println(" mCsEnabled=" + mCsEnabled); + pw.println(" mRegisteredForNetworkAttach=" + mRegisteredForNetworkAttach); + pw.println(" mImsRegistered=" + mImsRegistered); + pw.decreaseIndent(); + } } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index e638339182..a268e54005 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -4533,6 +4533,13 @@ public class GsmCdmaPhone extends Phone { e.printStackTrace(); } pw.flush(); + + try { + mCallWaitingController.dump(pw); + } catch (Exception e) { + e.printStackTrace(); + } + pw.flush(); } @Override -- GitLab From d08c72137336556e34ea61c54d246bb4ee395f68 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 24 Feb 2022 14:44:14 +0000 Subject: [PATCH 040/656] Hangup CS waiting calls when call waiting is disabled Bug: 202463005 Test: atest Change-Id: I3106919844bd4d8aa6528423f4948b6e3412f8e7 (cherry picked from commit ca2c7d4ec0bbd3e4470b69e604b845b7a054fb43) Merged-In: I3106919844bd4d8aa6528423f4948b6e3412f8e7 --- .../telephony/GsmCdmaCallTracker.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java index 517037eccf..925e31dbe9 100755 --- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java +++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java @@ -967,10 +967,7 @@ public class GsmCdmaCallTracker extends CallTracker { } else { newUnknownConnectionCdma = mConnections[i]; } - } else if (mPhone.getTerminalBasedCallWaitingState() - == CallWaitingController.TERMINAL_BASED_NOT_ACTIVATED - && newRinging.getState() == Call.State.WAITING) { - mCi.hangupWaitingOrBackground(obtainCompleteMessage()); + } else if (hangupWaitingCallSilently(i)) { return; } } @@ -1023,6 +1020,9 @@ public class GsmCdmaCallTracker extends CallTracker { if (mConnections[i].getCall() == mRingingCall) { newRinging = mConnections[i]; + if (hangupWaitingCallSilently(i)) { + return; + } } // else something strange happened hasNonHangupStateChanged = true; } else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */ @@ -1914,4 +1914,22 @@ public class GsmCdmaCallTracker extends CallTracker { public void cleanupCalls() { pollCallsWhenSafe(); } + + private boolean hangupWaitingCallSilently(int index) { + if (index < 0 || index >= mConnections.length) return false; + + GsmCdmaConnection newRinging = mConnections[index]; + if (newRinging == null) return false; + + if ((mPhone.getTerminalBasedCallWaitingState() + == CallWaitingController.TERMINAL_BASED_NOT_ACTIVATED) + && (newRinging.getState() == Call.State.WAITING)) { + Rlog.d(LOG_TAG, "hangupWaitingCallSilently"); + newRinging.dispose(); + mConnections[index] = null; + mCi.hangupWaitingOrBackground(obtainCompleteMessage()); + return true; + } + return false; + } } -- GitLab From ff0ee996c6023ebd763fb6794409f2508d0406bc Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 23 Mar 2022 22:15:34 +0000 Subject: [PATCH 041/656] Add EVENT_CARRIER_CONFIG_CHANGED to CallWaitingController Bug: 202463005 Test: atest Change-Id: I4b96c17fdba46ca04eb35d868f96903cbdf090a0 (cherry picked from commit 4b106dcfeaeff5731291c82eaec11548aef9e40c) Merged-In: I4b96c17fdba46ca04eb35d868f96903cbdf090a0 --- .../telephony/CallWaitingController.java | 45 +++++++++++-------- .../imsphone/ImsPhoneCallTracker.java | 1 + .../telephony/CallWaitingControllerTest.java | 23 +++++----- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java index 9ac58f1152..8eec967b3f 100644 --- a/src/java/com/android/internal/telephony/CallWaitingController.java +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -67,6 +67,7 @@ public class CallWaitingController extends Handler { private static final int EVENT_SET_CALL_WAITING_DONE = 1; private static final int EVENT_GET_CALL_WAITING_DONE = 2; private static final int EVENT_REGISTERED_TO_NETWORK = 3; + private static final int EVENT_CARRIER_CONFIG_CHANGED = 4; // Class to pack mOnComplete object passed by the caller private static class Cw { @@ -90,7 +91,7 @@ public class CallWaitingController extends Handler { @VisibleForTesting public static final String KEY_CS_SYNC = "cs_sync"; - private BroadcastReceiver mReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent == null) { @@ -111,7 +112,7 @@ public class CallWaitingController extends Handler { } if (slotId == mPhone.getPhoneId()) { - onCarrierConfigChanged(); + sendEmptyMessage(EVENT_CARRIER_CONFIG_CHANGED); } } } @@ -168,7 +169,7 @@ public class CallWaitingController extends Handler { * {@link #TERMINAL_BASED_ACTIVATED}. */ @VisibleForTesting - public int getTerminalBasedCallWaitingState() { + public synchronized int getTerminalBasedCallWaitingState() { if (!mValidSubscription) return TERMINAL_BASED_NOT_SUPPORTED; return mCallWaitingState; } @@ -179,7 +180,7 @@ public class CallWaitingController extends Handler { * @return true when terminal-based call waiting is supported, otherwise false */ @VisibleForTesting - public boolean getCallWaiting(@Nullable Message onComplete) { + public synchronized boolean getCallWaiting(@Nullable Message onComplete) { if (mCallWaitingState == TERMINAL_BASED_NOT_SUPPORTED) return false; Rlog.i(LOG_TAG, "getCallWaiting " + mCallWaitingState); @@ -219,7 +220,8 @@ public class CallWaitingController extends Handler { * @return true when terminal-based call waiting is supported, otherwise false */ @VisibleForTesting - public boolean setCallWaiting(boolean enable, int serviceClass, @Nullable Message onComplete) { + public synchronized boolean setCallWaiting(boolean enable, + int serviceClass, @Nullable Message onComplete) { if (mCallWaitingState == TERMINAL_BASED_NOT_SUPPORTED) return false; if ((serviceClass & SERVICE_CLASS_VOICE) != SERVICE_CLASS_VOICE) return false; @@ -272,10 +274,15 @@ public class CallWaitingController extends Handler { case EVENT_REGISTERED_TO_NETWORK: onRegisteredToNetwork(); break; + case EVENT_CARRIER_CONFIG_CHANGED: + onCarrierConfigChanged(); + break; + default: + break; } } - private void onSetCallWaitingDone(AsyncResult ar) { + private synchronized void onSetCallWaitingDone(AsyncResult ar) { if (ar.userObj == null) { // For the case, CALL_WAITING_SYNC_FIRST_POWER_UP if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone to sync on network attached"); @@ -314,7 +321,7 @@ public class CallWaitingController extends Handler { sendToTarget(cw.mOnComplete, ar.result, ar.exception); } - private void onGetCallWaitingDone(AsyncResult ar) { + private synchronized void onGetCallWaitingDone(AsyncResult ar) { if (ar.userObj == null) { // For the case, CALL_WAITING_SYNC_FIRST_POWER_UP if (DBG) Rlog.d(LOG_TAG, "onGetCallWaitingDone to sync on network attached"); @@ -413,7 +420,7 @@ public class CallWaitingController extends Handler { } } - private void onRegisteredToNetwork() { + private synchronized void onRegisteredToNetwork() { if (mCsEnabled) return; if (DBG) Rlog.d(LOG_TAG, "onRegisteredToNetwork"); @@ -422,7 +429,7 @@ public class CallWaitingController extends Handler { obtainMessage(EVENT_GET_CALL_WAITING_DONE)); } - private void onCarrierConfigChanged() { + private synchronized void onCarrierConfigChanged() { int subId = mPhone.getSubId(); if (!SubscriptionManager.isValidSubscriptionId(subId)) { Rlog.i(LOG_TAG, "onCarrierConfigChanged invalid subId=" + subId); @@ -447,10 +454,10 @@ public class CallWaitingController extends Handler { } /** - * @param enforced only used for test + * @param ignoreSavedState only used for test */ @VisibleForTesting - public void updateCarrierConfig(int subId, PersistableBundle b, boolean enforced) { + public void updateCarrierConfig(int subId, PersistableBundle b, boolean ignoreSavedState) { mValidSubscription = true; if (b == null) return; @@ -481,7 +488,7 @@ public class CallWaitingController extends Handler { int desiredState = savedState; - if (enforced) { + if (ignoreSavedState) { desiredState = defaultState; } else if ((mLastSubId != subId) && (syncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP @@ -495,20 +502,20 @@ public class CallWaitingController extends Handler { } } - updateState(desiredState, syncPreference, enforced); + updateState(desiredState, syncPreference, ignoreSavedState); } private void updateState(int state) { updateState(state, mSyncPreference, false); } - private void updateState(int state, int syncPreference, boolean enforced) { + private void updateState(int state, int syncPreference, boolean ignoreSavedState) { int subId = mPhone.getSubId(); if (mLastSubId == subId && mCallWaitingState == state && mSyncPreference == syncPreference - && (!enforced)) { + && (!ignoreSavedState)) { return; } @@ -516,7 +523,7 @@ public class CallWaitingController extends Handler { Rlog.i(LOG_TAG, "updateState phoneId=" + phoneId + ", subId=" + subId + ", state=" + state - + ", sync=" + syncPreference + ", enforced=" + enforced); + + ", sync=" + syncPreference + ", ignoreSavedState=" + ignoreSavedState); SharedPreferences sp = mContext.getSharedPreferences(PREFERENCE_TBCW, Context.MODE_PRIVATE); @@ -577,7 +584,7 @@ public class CallWaitingController extends Handler { /** * Sets the registration state of IMS service. */ - public void setImsRegistrationState(boolean registered) { + public synchronized void setImsRegistrationState(boolean registered) { Rlog.i(LOG_TAG, "setImsRegistrationState prev=" + mImsRegistered + ", new=" + registered); mImsRegistered = registered; @@ -605,7 +612,7 @@ public class CallWaitingController extends Handler { * Only for test */ @VisibleForTesting - public void setTerminalBasedCallWaitingSupported(boolean supported) { + public synchronized void setTerminalBasedCallWaitingSupported(boolean supported) { if (mSupportedByImsService == supported) return; Rlog.i(LOG_TAG, "setTerminalBasedCallWaitingSupported " + supported); @@ -633,7 +640,7 @@ public class CallWaitingController extends Handler { /** * Dump this instance into a readable format for dumpsys usage. */ - public void dump(PrintWriter printWriter) { + public synchronized void dump(PrintWriter printWriter) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.increaseIndent(); pw.println("CallWaitingController:"); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index b26c7d2303..ef79939215 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -5476,6 +5476,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { if (state == TERMINAL_BASED_NOT_SUPPORTED) return; if (mImsManager != null) { try { + log("setTerminalBasedCallWaitingStatus state=" + state); mImsManager.setTerminalBasedCallWaitingStatus( state == TERMINAL_BASED_ACTIVATED); } catch (ImsException e) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java index c71059e764..94a6fff00b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java @@ -92,7 +92,7 @@ public class CallWaitingControllerTest extends TelephonyTest { @SmallTest public void testSetTerminalBasedCallWaitingSupported() { mCWC.setTerminalBasedCallWaitingSupported(true); - PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_NONE, true); + PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); @@ -107,7 +107,7 @@ public class CallWaitingControllerTest extends TelephonyTest { mCWC.setTerminalBasedCallWaitingSupported(false); setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, TERMINAL_BASED_ACTIVATED, CALL_WAITING_SYNC_NONE); - PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_NONE, true); + PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); mCWC.setTerminalBasedCallWaitingSupported(true); @@ -121,7 +121,7 @@ public class CallWaitingControllerTest extends TelephonyTest { assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); mCWC.setTerminalBasedCallWaitingSupported(false); - bundle = getBundle(false, CALL_WAITING_SYNC_NONE, false); + bundle = getConfigBundle(false, CALL_WAITING_SYNC_NONE, false); doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); mCWC.setTerminalBasedCallWaitingSupported(true); @@ -132,12 +132,12 @@ public class CallWaitingControllerTest extends TelephonyTest { @SmallTest public void testCarrierConfigChanged() { mCWC.setTerminalBasedCallWaitingSupported(true); - PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_NONE, true); + PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); - bundle = getBundle(false, CALL_WAITING_SYNC_NONE, true); + bundle = getConfigBundle(false, CALL_WAITING_SYNC_NONE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, false); assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_SUPPORTED); @@ -170,7 +170,7 @@ public class CallWaitingControllerTest extends TelephonyTest { assertFalse(mCWC.getCallWaiting(null)); mCWC.setTerminalBasedCallWaitingSupported(true); - PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_NONE, true); + PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); mHandler = new GetTestHandler(); @@ -207,7 +207,7 @@ public class CallWaitingControllerTest extends TelephonyTest { assertFalse(mCWC.setCallWaiting(true, SERVICE_CLASS_VOICE, null)); mCWC.setTerminalBasedCallWaitingSupported(true); - PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_NONE, true); + PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); assertTrue(mCWC.setCallWaiting(true, SERVICE_CLASS_VOICE, null)); @@ -234,7 +234,7 @@ public class CallWaitingControllerTest extends TelephonyTest { setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, TERMINAL_BASED_ACTIVATED, CALL_WAITING_SYNC_USER_CHANGE); mCWC.setTerminalBasedCallWaitingSupported(true); - PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_USER_CHANGE, true); + PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_USER_CHANGE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); @@ -286,7 +286,7 @@ public class CallWaitingControllerTest extends TelephonyTest { setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, TERMINAL_BASED_NOT_ACTIVATED, CALL_WAITING_SYNC_FIRST_POWER_UP); mCWC.setTerminalBasedCallWaitingSupported(true); - PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_FIRST_POWER_UP, true); + PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_FIRST_POWER_UP, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); assertFalse(mCWC.getSyncState()); @@ -303,7 +303,7 @@ public class CallWaitingControllerTest extends TelephonyTest { setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, TERMINAL_BASED_NOT_ACTIVATED, CALL_WAITING_SYNC_FIRST_CHANGE); mCWC.setTerminalBasedCallWaitingSupported(true); - PersistableBundle bundle = getBundle(true, CALL_WAITING_SYNC_FIRST_CHANGE, true); + PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_FIRST_CHANGE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); mCWC.setImsRegistrationState(false); @@ -335,7 +335,8 @@ public class CallWaitingControllerTest extends TelephonyTest { assertTrue(mSimulatedCommands.mCallWaitActivated); } - private PersistableBundle getBundle(boolean provisioned, int preference, boolean defaultState) { + private PersistableBundle getConfigBundle(boolean provisioned, + int preference, boolean defaultState) { PersistableBundle bundle = new PersistableBundle(); bundle.putIntArray(KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY, provisioned ? new int[] { SUPPLEMENTARY_SERVICE_CW } : new int[] { }); -- GitLab From 7ead8b901036756f4b12ad5cbdf4a1e49622b6bd Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Sat, 9 Apr 2022 06:44:40 +0000 Subject: [PATCH 042/656] Update CallWaitingController, SYNC_IMS_ONLY Implement the configuration CALL_WAITING_SYNC_IMS_ONLY Do not synchronize the service state between CS newtwork and IMS service. If IMS service is registered, the change of user setting shall be handled at the device without any communication with the network. Otherwise, the device tries to communicate with the CS network to handle user's request. Bug: 202463005 Test: atest Change-Id: Ic8f5433e403ff3cc45e02d29d0aaeda24a1ba348 (cherry picked from commit 6acb43cdd8e993b6f977febacbdccc037737d1ac) Merged-In: Ic8f5433e403ff3cc45e02d29d0aaeda24a1ba348 --- .../telephony/CallWaitingController.java | 38 ++++- .../telephony/GsmCdmaCallTracker.java | 2 +- .../internal/telephony/GsmCdmaPhone.java | 4 +- .../com/android/internal/telephony/Phone.java | 3 +- .../internal/telephony/gsm/GsmMmiCode.java | 4 +- .../telephony/imsphone/ImsPhoneBase.java | 4 +- .../imsphone/ImsPhoneCallTracker.java | 5 +- .../telephony/imsphone/ImsPhoneMmiCode.java | 4 +- .../telephony/CallWaitingControllerTest.java | 138 +++++++++++++++--- 9 files changed, 168 insertions(+), 34 deletions(-) diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java index 8eec967b3f..41d54d82bc 100644 --- a/src/java/com/android/internal/telephony/CallWaitingController.java +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_FIRST_CHANGE; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_FIRST_POWER_UP; +import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_IMS_ONLY; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_NONE; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_USER_CHANGE; import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL; @@ -167,9 +168,14 @@ public class CallWaitingController extends Handler { * {@link #TERMINAL_BASED_NOT_SUPPORTED}, * {@link #TERMINAL_BASED_NOT_ACTIVATED}, and * {@link #TERMINAL_BASED_ACTIVATED}. + * + * @param forCsOnly indicates the caller expects the result for CS calls only */ @VisibleForTesting - public synchronized int getTerminalBasedCallWaitingState() { + public synchronized int getTerminalBasedCallWaitingState(boolean forCsOnly) { + if (forCsOnly && (!mImsRegistered) && mSyncPreference == CALL_WAITING_SYNC_IMS_ONLY) { + return TERMINAL_BASED_NOT_SUPPORTED; + } if (!mValidSubscription) return TERMINAL_BASED_NOT_SUPPORTED; return mCallWaitingState; } @@ -200,10 +206,12 @@ public class CallWaitingController extends Handler { if (mSyncPreference == CALL_WAITING_SYNC_NONE || mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE - || mSyncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP) { + || mSyncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP + || isSyncImsOnly()) { sendGetCallWaitingResponse(onComplete); return true; - } else if (mSyncPreference == CALL_WAITING_SYNC_USER_CHANGE) { + } else if (mSyncPreference == CALL_WAITING_SYNC_USER_CHANGE + || mSyncPreference == CALL_WAITING_SYNC_IMS_ONLY) { Cw cw = new Cw(false, isImsRegistered(), onComplete); Message resp = obtainMessage(EVENT_GET_CALL_WAITING_DONE, 0, 0, cw); mPhone.mCi.queryCallWaiting(SERVICE_CLASS_NONE, resp); @@ -246,13 +254,15 @@ public class CallWaitingController extends Handler { if (mSyncPreference == CALL_WAITING_SYNC_NONE || mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE - || mSyncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP) { + || mSyncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP + || isSyncImsOnly()) { updateState( enable ? TERMINAL_BASED_ACTIVATED : TERMINAL_BASED_NOT_ACTIVATED); sendToTarget(onComplete, null, null); return true; - } else if (mSyncPreference == CALL_WAITING_SYNC_USER_CHANGE) { + } else if (mSyncPreference == CALL_WAITING_SYNC_USER_CHANGE + || mSyncPreference == CALL_WAITING_SYNC_IMS_ONLY) { Cw cw = new Cw(enable, isImsRegistered(), onComplete); Message resp = obtainMessage(EVENT_SET_CALL_WAITING_DONE, 0, 0, cw); mPhone.mCi.setCallWaiting(enable, serviceClass, resp); @@ -302,6 +312,13 @@ public class CallWaitingController extends Handler { if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone"); Cw cw = (Cw) ar.userObj; + + if (mSyncPreference == CALL_WAITING_SYNC_IMS_ONLY) { + // do not synchronize service state between CS and IMS + sendToTarget(cw.mOnComplete, ar.result, ar.exception); + return; + } + if (ar.exception == null) { if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { // SYNC_FIRST_CHANGE implies cw.mEnable is true. @@ -358,6 +375,13 @@ public class CallWaitingController extends Handler { if (DBG) Rlog.d(LOG_TAG, "onGetCallWaitingDone"); Cw cw = (Cw) ar.userObj; + + if (mSyncPreference == CALL_WAITING_SYNC_IMS_ONLY) { + // do not synchronize service state between CS and IMS + sendToTarget(cw.mOnComplete, ar.result, ar.exception); + return; + } + if (ar.exception == null) { int[] resp = (int[]) ar.result; //resp[0]: 1 if enabled, 0 otherwise @@ -637,6 +661,10 @@ public class CallWaitingController extends Handler { sendEmptyMessage(EVENT_REGISTERED_TO_NETWORK); } + private boolean isSyncImsOnly() { + return (mSyncPreference == CALL_WAITING_SYNC_IMS_ONLY && mImsRegistered); + } + /** * Dump this instance into a readable format for dumpsys usage. */ diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java index 925e31dbe9..07be4e51fb 100755 --- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java +++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java @@ -1921,7 +1921,7 @@ public class GsmCdmaCallTracker extends CallTracker { GsmCdmaConnection newRinging = mConnections[index]; if (newRinging == null) return false; - if ((mPhone.getTerminalBasedCallWaitingState() + if ((mPhone.getTerminalBasedCallWaitingState(true) == CallWaitingController.TERMINAL_BASED_NOT_ACTIVATED) && (newRinging.getState() == Call.State.WAITING)) { Rlog.d(LOG_TAG, "hangupWaitingCallSilently"); diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index a268e54005..07de88afab 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -2826,8 +2826,8 @@ public class GsmCdmaPhone extends Phone { } @Override - public int getTerminalBasedCallWaitingState() { - return mCallWaitingController.getTerminalBasedCallWaitingState(); + public int getTerminalBasedCallWaitingState(boolean forCsOnly) { + return mCallWaitingController.getTerminalBasedCallWaitingState(forCsOnly); } @Override diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 4523031cf0..99bd3c5358 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -4986,8 +4986,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Returns the user's last setting for terminal-based call waiting + * @param forCsOnly indicates the caller expects the result for CS calls only */ - public int getTerminalBasedCallWaitingState() { + public int getTerminalBasedCallWaitingState(boolean forCsOnly) { return CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED; } diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 7d7b7ba908..114a7d8793 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -1186,7 +1186,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { if (isActivate() || isDeactivate()) { if (serviceClass == SERVICE_CLASS_NONE || (serviceClass & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE) { - if (mPhone.getTerminalBasedCallWaitingState() + if (mPhone.getTerminalBasedCallWaitingState(true) != CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED) { mPhone.setCallWaiting(isActivate(), serviceClass, obtainMessage(EVENT_SET_COMPLETE, this)); @@ -1196,7 +1196,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { mPhone.mCi.setCallWaiting(isActivate(), serviceClass, obtainMessage(EVENT_SET_COMPLETE, this)); } else if (isInterrogate()) { - if (mPhone.getTerminalBasedCallWaitingState() + if (mPhone.getTerminalBasedCallWaitingState(true) != CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED) { mPhone.getCallWaiting(obtainMessage(EVENT_QUERY_COMPLETE, this)); } else { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index e83ef5333d..322dd55f7c 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -542,8 +542,8 @@ abstract class ImsPhoneBase extends Phone { } @Override - public int getTerminalBasedCallWaitingState() { - return getDefaultPhone().getTerminalBasedCallWaitingState(); + public int getTerminalBasedCallWaitingState(boolean forCsOnly) { + return getDefaultPhone().getTerminalBasedCallWaitingState(forCsOnly); } @Override diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index ef79939215..3dc1c4c0f7 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -5463,9 +5463,12 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { loge("initializeTerminalBasedCallWaiting : exception " + e); } } + logi("initializeTerminalBasedCallWaiting capable=" + capable); mPhone.setTerminalBasedCallWaitingSupported(capable); - setTerminalBasedCallWaitingStatus(mPhone.getTerminalBasedCallWaitingState()); + if (capable) { + setTerminalBasedCallWaitingStatus(mPhone.getTerminalBasedCallWaitingState(false)); + } } /** diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java index 63fa1cb056..d26d45e29b 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java @@ -1117,7 +1117,7 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { if (isActivate() || isDeactivate()) { if (serviceClass == SERVICE_CLASS_NONE || (serviceClass & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE) { - if (mPhone.getTerminalBasedCallWaitingState() + if (mPhone.getTerminalBasedCallWaitingState(false) != CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED) { mPhone.getDefaultPhone().setCallWaiting(isActivate(), serviceClass, obtainMessage(EVENT_SET_COMPLETE, this)); @@ -1127,7 +1127,7 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { mPhone.setCallWaiting(isActivate(), serviceClass, obtainMessage(EVENT_SET_COMPLETE, this)); } else if (isInterrogate()) { - if (mPhone.getTerminalBasedCallWaitingState() + if (mPhone.getTerminalBasedCallWaitingState(false) != CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED) { mPhone.getDefaultPhone() .getCallWaiting(obtainMessage(EVENT_QUERY_COMPLETE, this)); diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java index 94a6fff00b..18d054d2dc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 The Android Open Source Project + * Copyright (C) 2022 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. @@ -17,6 +17,7 @@ package com.android.internal.telephony; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_FIRST_CHANGE; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_FIRST_POWER_UP; +import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_IMS_ONLY; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_NONE; import static android.telephony.CarrierConfigManager.ImsSs.CALL_WAITING_SYNC_USER_CHANGE; import static android.telephony.CarrierConfigManager.ImsSs.KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL; @@ -95,10 +96,12 @@ public class CallWaitingControllerTest extends TelephonyTest { PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); mCWC.setTerminalBasedCallWaitingSupported(false); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_SUPPORTED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_SUPPORTED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_SUPPORTED); } @Test @@ -111,21 +114,24 @@ public class CallWaitingControllerTest extends TelephonyTest { doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); mCWC.setTerminalBasedCallWaitingSupported(true); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); mCWC.setTerminalBasedCallWaitingSupported(false); setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, TERMINAL_BASED_NOT_ACTIVATED, CALL_WAITING_SYNC_NONE); mCWC.setTerminalBasedCallWaitingSupported(true); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_ACTIVATED); mCWC.setTerminalBasedCallWaitingSupported(false); bundle = getConfigBundle(false, CALL_WAITING_SYNC_NONE, false); doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); mCWC.setTerminalBasedCallWaitingSupported(true); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_SUPPORTED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_SUPPORTED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_SUPPORTED); } @Test @@ -135,12 +141,14 @@ public class CallWaitingControllerTest extends TelephonyTest { PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); bundle = getConfigBundle(false, CALL_WAITING_SYNC_NONE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, false); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_SUPPORTED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_SUPPORTED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_SUPPORTED); } @@ -211,19 +219,23 @@ public class CallWaitingControllerTest extends TelephonyTest { mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); assertTrue(mCWC.setCallWaiting(true, SERVICE_CLASS_VOICE, null)); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_ACTIVATED); assertTrue(mCWC.setCallWaiting(false, SERVICE_CLASS_VOICE | SERVICE_CLASS_DATA, null)); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_ACTIVATED); assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); assertFalse(mCWC.setCallWaiting(true, SERVICE_CLASS_DATA, null)); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_ACTIVATED); assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); assertFalse(mCWC.setCallWaiting(true, SERVICE_CLASS_NONE, null)); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_ACTIVATED); assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); } @@ -237,7 +249,8 @@ public class CallWaitingControllerTest extends TelephonyTest { PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_USER_CHANGE, true); mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_ACTIVATED); mHandler = new GetTestHandler(); @@ -252,7 +265,8 @@ public class CallWaitingControllerTest extends TelephonyTest { assertEquals(TERMINAL_BASED_NOT_ACTIVATED, mHandler.resp[0]); assertEquals(SERVICE_CLASS_NONE, mHandler.resp[1]); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_ACTIVATED); assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); mHandler.reset(); @@ -267,7 +281,8 @@ public class CallWaitingControllerTest extends TelephonyTest { assertEquals(TERMINAL_BASED_ACTIVATED, mHandler.resp[0]); assertEquals(SERVICE_CLASS_VOICE, mHandler.resp[1]); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_ACTIVATED); mHandler.reset(); @@ -275,7 +290,8 @@ public class CallWaitingControllerTest extends TelephonyTest { assertTrue(mCWC.setCallWaiting(false, SERVICE_CLASS_VOICE, null)); mTestableLooper.processAllMessages(); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_ACTIVATED); assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); } @@ -324,17 +340,103 @@ public class CallWaitingControllerTest extends TelephonyTest { assertTrue(mCWC.setCallWaiting(true, SERVICE_CLASS_VOICE, null)); mTestableLooper.processAllMessages(); - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); assertTrue(mSimulatedCommands.mCallWaitActivated); assertTrue(mCWC.setCallWaiting(false, SERVICE_CLASS_VOICE, null)); mTestableLooper.processAllMessages(); // Local setting changed, but no change in CS network. - assertTrue(mCWC.getTerminalBasedCallWaitingState() == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_ACTIVATED); assertTrue(mSimulatedCommands.mCallWaitActivated); } + @Test + @SmallTest + public void testSyncImsOnly() { + mCWC.setTerminalBasedCallWaitingSupported(false); + setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, + TERMINAL_BASED_ACTIVATED, CALL_WAITING_SYNC_IMS_ONLY); + mCWC.setTerminalBasedCallWaitingSupported(true); + PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_IMS_ONLY, true); + mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + + mSimulatedCommands.setCallWaiting(false, SERVICE_CLASS_VOICE, null); + + // IMS is registered + mCWC.setImsRegistrationState(true); + + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_ACTIVATED); + + mHandler = new GetTestHandler(); + + assertTrue(mCWC.getCallWaiting(mHandler.obtainMessage(GET_DONE))); + mTestableLooper.processAllMessages(); + + // result carries the service state from IMS service + assertNotNull(mHandler.resp); + assertEquals(2, mHandler.resp.length); + assertEquals(TERMINAL_BASED_ACTIVATED, mHandler.resp[0]); + assertEquals(SERVICE_CLASS_VOICE, mHandler.resp[1]); + + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_ACTIVATED); + + mHandler.reset(); + + // IMS is not registered + mCWC.setImsRegistrationState(false); + + assertTrue(mCWC.getCallWaiting(mHandler.obtainMessage(GET_DONE))); + mTestableLooper.processAllMessages(); + + // result carries the service state from CS + assertNotNull(mHandler.resp); + assertEquals(2, mHandler.resp.length); + assertEquals(TERMINAL_BASED_NOT_ACTIVATED, mHandler.resp[0]); + assertEquals(SERVICE_CLASS_NONE, mHandler.resp[1]); + + // service state not synchronized between CS and IMS + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_SUPPORTED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_ACTIVATED); + + mHandler.reset(); + + // IMS is registered + mCWC.setImsRegistrationState(true); + + assertTrue(mCWC.setCallWaiting(false, SERVICE_CLASS_VOICE, null)); + mTestableLooper.processAllMessages(); + + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); + + // IMS is not registered + mCWC.setImsRegistrationState(false); + + assertTrue(mCWC.setCallWaiting(true, SERVICE_CLASS_VOICE, null)); + mTestableLooper.processAllMessages(); + + assertTrue(mCWC.getCallWaiting(mHandler.obtainMessage(GET_DONE))); + mTestableLooper.processAllMessages(); + + // result carries the service state from CS + assertNotNull(mHandler.resp); + assertEquals(2, mHandler.resp.length); + assertEquals(TERMINAL_BASED_ACTIVATED, mHandler.resp[0]); + assertEquals(SERVICE_CLASS_VOICE, mHandler.resp[1]); + + // service state not synchronized between CS and IMS + assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_ACTIVATED); + assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_SUPPORTED); + assertTrue(retrieveStatePreference(mPhone.getSubId()) == TERMINAL_BASED_NOT_ACTIVATED); + } + private PersistableBundle getConfigBundle(boolean provisioned, int preference, boolean defaultState) { PersistableBundle bundle = new PersistableBundle(); -- GitLab From b91f7a2f8b807d67e51a6e674f834ac247afec4e Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 21 Apr 2022 15:19:42 +0000 Subject: [PATCH 043/656] Interworking between CallWaitingController and SsDomainController If vendor Ims service handles the terminal based call waiting service by itself, we should forward the request to Ims service as legacy implementation when Ut is available. And SS_ROUTING_OVER_UT is replaced with getSsRoutingOverUt() to check isUtEnabled(). Bug: 202463005 Bug: 202463163 Test: atest Change-Id: I2d49916da09c733f949807577ac1dc55947cc31d (cherry picked from commit 344d04ba6b5f529aa2405557a41b2184a2932c45) Merged-In: I2d49916da09c733f949807577ac1dc55947cc31d --- .../internal/telephony/GsmCdmaPhone.java | 41 +++++++++++ .../telephony/SsDomainController.java | 69 ++++++++++++++++--- .../telephony/imsphone/ImsPhoneMmiCode.java | 8 +-- .../internal/telephony/GsmCdmaPhoneTest.java | 28 ++++++++ .../telephony/SsDomainControllerTest.java | 27 +++++++- 5 files changed, 158 insertions(+), 15 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 07de88afab..b437bbd83b 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -2376,6 +2376,24 @@ public class GsmCdmaPhone extends Phone { return false; } + /** + * Checks the availability of Ut directly without SsDomainController. + * This is only applicable for the case that the terminal-based call waiting service + * is handled by the IMS service alone without interworking with CallWaitingController. + */ + private boolean useCallWaitingOverUt(Message onComplete) { + Phone imsPhone = mImsPhone; + if (imsPhone == null) { + logd("useCallWaitingOverUt: called for GsmCdma"); + return false; + } + + boolean isUtEnabled = imsPhone.isUtEnabled(); + Rlog.d(LOG_TAG, "useCallWaitingOverUt isUtEnabled= " + isUtEnabled + + " isCsRetry(onComplete))= " + isCsRetry(onComplete)); + return isUtEnabled && !isCsRetry(onComplete); + } + /** * Returns whether CSFB is supported for supplementary services. */ @@ -2383,6 +2401,14 @@ public class GsmCdmaPhone extends Phone { return mSsDomainController.supportCsfb(); } + /** + * Returns whether the carrier supports the terminal-based call waiting service + * and Ims service handles it by itself. + */ + private boolean getOemHandlesTerminalBasedCallWaiting() { + return mSsDomainController.getOemHandlesTerminalBasedCallWaiting(); + } + /** * Sends response indicating no nework is available for supplementary services. */ @@ -2742,6 +2768,13 @@ public class GsmCdmaPhone extends Phone { responseInvalidState(onComplete); return; } + } else if (getOemHandlesTerminalBasedCallWaiting()) { + // Ims service handles the terminal-based call waiting service by itself. + // Use legacy implementation. Forward the request to Ims service if Ut is available. + if (useCallWaitingOverUt(onComplete)) { + imsPhone.getCallWaiting(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2800,6 +2833,13 @@ public class GsmCdmaPhone extends Phone { responseInvalidState(onComplete); return; } + } else if (getOemHandlesTerminalBasedCallWaiting()) { + // Ims service handles the terminal-based call waiting service by itself. + // Use legacy implementation. Forward the request to Ims service if Ut is available. + if (useCallWaitingOverUt(onComplete)) { + imsPhone.setCallWaiting(enable, onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2840,6 +2880,7 @@ public class GsmCdmaPhone extends Phone { @Override public void setTerminalBasedCallWaitingSupported(boolean supported) { mCallWaitingController.setTerminalBasedCallWaitingSupported(supported); + mSsDomainController.setOemHandlesTerminalBasedCallWaiting(!supported); } @Override diff --git a/src/java/com/android/internal/telephony/SsDomainController.java b/src/java/com/android/internal/telephony/SsDomainController.java index 4fb75e4b48..85ca44d94f 100644 --- a/src/java/com/android/internal/telephony/SsDomainController.java +++ b/src/java/com/android/internal/telephony/SsDomainController.java @@ -127,10 +127,6 @@ public class SsDomainController { public static final String SS_COLP = "COLP"; public static final String SS_COLR = "COLR"; - // Common instance indicating that Ut is available. - public static final SuppServiceRoutingInfo SS_ROUTING_OVER_UT = - new SuppServiceRoutingInfo(true, true, true); - // Barring list of incoming numbers public static final String CB_FACILITY_BIL = "BIL"; // Barring of all anonymous incoming number @@ -174,6 +170,9 @@ public class SsDomainController { private Set mUtAvailableRats = new HashSet<>(); private boolean mWiFiAvailable = false; private boolean mIsMonitoringConnectivity = false; + /** true if Ims service handles the terminal-based call waiting service by itself. */ + private boolean mOemHandlesTerminalBasedCallWaiting = false; + private boolean mSupportsTerminalBasedCallWaiting = false; public SsDomainController(GsmCdmaPhone phone) { mPhone = phone; @@ -204,13 +203,16 @@ public class SsDomainController { int[] utRats = b.getIntArray( CarrierConfigManager.ImsSs.KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY); + int[] tbServices = b.getIntArray( + CarrierConfigManager.ImsSs.KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY); + updateSsOverUtConfig(supportsUt, supportsCsfb, requiresImsRegistration, - availableWhenPsDataOff, availableWhenRoaming, services, utRats); + availableWhenPsDataOff, availableWhenRoaming, services, utRats, tbServices); } private void updateSsOverUtConfig(boolean supportsUt, boolean supportsCsfb, boolean requiresImsRegistration, boolean availableWhenPsDataOff, - boolean availableWhenRoaming, int[] services, int[] utRats) { + boolean availableWhenRoaming, int[] services, int[] utRats, int[] tbServices) { mUtSupported = supportsUt; mCsfbSupported = supportsCsfb; @@ -218,6 +220,18 @@ public class SsDomainController { mUtAvailableWhenPsDataOff = availableWhenPsDataOff; mUtAvailableWhenRoaming = availableWhenRoaming; + mSupportsTerminalBasedCallWaiting = false; + if (tbServices != null) { + for (int tbService : tbServices) { + if (tbService == SUPPLEMENTARY_SERVICE_CW) { + mSupportsTerminalBasedCallWaiting = true; + break; + } + } + } + Rlog.i(LOG_TAG, "updateSsOverUtConfig terminal-based cw " + + mSupportsTerminalBasedCallWaiting); + mCbOverUtSupported.clear(); mCfOverUtSupported.clear(); mSsOverUtSupported.clear(); @@ -521,9 +535,24 @@ public class SsDomainController { * Only for ImsPhoneMmiCode. */ public SuppServiceRoutingInfo getSuppServiceRoutingInfoForSs(String service) { + if (SS_CW.equals(service) && getOemHandlesTerminalBasedCallWaiting()) { + // Ims service handles the terminal based call waiting service by itself. + // Use legacy implementation. Forward the request to Ims service if Ut is available. + Phone imsPhone = mPhone.getImsPhone(); + boolean isUtEnabled = (imsPhone != null) && imsPhone.isUtEnabled(); + return new SuppServiceRoutingInfo(true, isUtEnabled, true); + } return new SuppServiceRoutingInfo(useSsOverUt(service), isUtEnabled(), supportCsfb()); } + /** + * Returns SuppServiceRoutingInfo instance for a service will be served by Ut interface. + * Only for ImsPhoneMmiCode. + */ + public SuppServiceRoutingInfo getSsRoutingOverUt() { + return new SuppServiceRoutingInfo(true, isUtEnabled(), true); + } + /** * Set the carrier configuration for test. * Test purpose only. @@ -531,17 +560,37 @@ public class SsDomainController { @VisibleForTesting public void updateCarrierConfigForTest(boolean supportsUt, boolean supportsCsfb, boolean requiresImsRegistration, boolean availableWhenPsDataOff, - boolean availableWhenRoaming, int[] services, int[] utRats) { + boolean availableWhenRoaming, int[] services, int[] utRats, int[] tbServices) { Rlog.i(LOG_TAG, "updateCarrierConfigForTest supportsUt=" + supportsUt + ", csfb=" + supportsCsfb + ", reg=" + requiresImsRegistration + ", whenPsDataOff=" + availableWhenPsDataOff + ", whenRoaming=" + availableWhenRoaming + ", services=" + Arrays.toString(services) - + ", rats=" + Arrays.toString(utRats)); + + ", rats=" + Arrays.toString(utRats) + + ", tbServices=" + Arrays.toString(tbServices)); updateSsOverUtConfig(supportsUt, supportsCsfb, requiresImsRegistration, - availableWhenPsDataOff, availableWhenRoaming, services, utRats); + availableWhenPsDataOff, availableWhenRoaming, services, utRats, tbServices); + } + + /** + * @param state true if Ims service handles the terminal-based call waiting service by itself. + * Otherwise, false. + */ + public void setOemHandlesTerminalBasedCallWaiting(boolean state) { + Rlog.i(LOG_TAG, "setOemHandlesTerminalBasedCallWaiting " + state); + mOemHandlesTerminalBasedCallWaiting = state; + } + + /** + * Returns whether the carrier supports the terminal-based call waiting service + * and Ims service handles it by itself. + */ + public boolean getOemHandlesTerminalBasedCallWaiting() { + Rlog.i(LOG_TAG, "getOemHandlesTerminalBasedCallWaiting " + + mSupportsTerminalBasedCallWaiting + ", " + mOemHandlesTerminalBasedCallWaiting); + return mSupportsTerminalBasedCallWaiting && mOemHandlesTerminalBasedCallWaiting; } /** @@ -561,6 +610,8 @@ public class SsDomainController { pw.println(" mUtAvailableWhenRoaming=" + mUtAvailableWhenRoaming); pw.println(" mUtAvailableRats=" + mUtAvailableRats); pw.println(" mWiFiAvailable=" + mWiFiAvailable); + pw.println(" mOemHandlesTerminalBasedCallWaiting=" + mOemHandlesTerminalBasedCallWaiting); + pw.println(" mSupportsTerminalBasedCallWaiting=" + mSupportsTerminalBasedCallWaiting); pw.decreaseIndent(); } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java index d26d45e29b..3dadd23f44 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java @@ -542,7 +542,7 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { return controller.getSuppServiceRoutingInfoForCb(scToBarringFacility(sc)); } else if (sc != null && sc.equals(SC_CFUT)) { // for backward compatibility, not specified by CarrierConfig - return SsDomainController.SS_ROUTING_OVER_UT; + return controller.getSsRoutingOverUt(); } else if (sc != null && sc.equals(SC_CLIP)) { return controller.getSuppServiceRoutingInfoForSs(SS_CLIP); } else if (sc != null && sc.equals(SC_CLIR)) { @@ -553,7 +553,7 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { return controller.getSuppServiceRoutingInfoForSs(SS_COLR); } else if (sc != null && sc.equals(SC_CNAP)) { // for backward compatibility, not specified by CarrierConfig - return SsDomainController.SS_ROUTING_OVER_UT; + return controller.getSsRoutingOverUt(); } else if (sc != null && sc.equals(SC_BS_MT)) { return controller.getSuppServiceRoutingInfoForCb( SsDomainController.CB_FACILITY_BIL); @@ -562,12 +562,12 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { SsDomainController.CB_FACILITY_ACR); } else if (sc != null && sc.equals(SC_PWD)) { // for backward compatibility, not specified by CarrierConfig - return SsDomainController.SS_ROUTING_OVER_UT; + return controller.getSsRoutingOverUt(); } else if (sc != null && sc.equals(SC_WAIT)) { return controller.getSuppServiceRoutingInfoForSs(SS_CW); } else if (isPinPukCommand(sc)) { // for backward compatibility, not specified by CarrierConfig - return SsDomainController.SS_ROUTING_OVER_UT; + return controller.getSsRoutingOverUt(); } } return null; diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 43fddc034d..074c6237d8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -2178,4 +2178,32 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); verify(mImsPhone, times(1)).setCallWaiting(eq(false), any()); } + + @Test + @SmallTest + public void testOemHandlesTerminalBasedCallWaiting() throws Exception { + doReturn(true).when(mImsPhone).isUtEnabled(); + replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); + + // Ut is disabled in config + doReturn(false).when(mSsDomainController).useSsOverUt(anyString()); + doReturn(false).when(mSsDomainController).getOemHandlesTerminalBasedCallWaiting(); + + replaceInstance(GsmCdmaPhone.class, "mSsDomainController", mPhoneUT, mSsDomainController); + + mPhoneUT.getCallWaiting(null); + verify(mImsPhone, times(0)).getCallWaiting(any()); + + mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); + verify(mImsPhone, times(0)).setCallWaiting(eq(false), any()); + + // OEM handles the terminal-based call waiting service by itself. + doReturn(true).when(mSsDomainController).getOemHandlesTerminalBasedCallWaiting(); + + mPhoneUT.getCallWaiting(null); + verify(mImsPhone, times(1)).getCallWaiting(any()); + + mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); + verify(mImsPhone, times(1)).setCallWaiting(eq(false), any()); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java index 53679e0dbe..a0867fd4f7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java @@ -430,6 +430,29 @@ public class SsDomainControllerTest extends TelephonyTest { assertFalse(mSdc.isUtEnabled()); } + @Test + @SmallTest + public void testOemHandlesTerminalBasedCallWaiting() { + setUtEnabled(); + + // Enable terminal-based call waiting + mSdc.updateCarrierConfigForTest(true, true, false, true, true, + new int[] {}, UT_OVER_ALL, new int[] { SUPPLEMENTARY_SERVICE_CW }); + String sc = mServices.get(SS_CW); + + mSdc.setOemHandlesTerminalBasedCallWaiting(false); + SsDomainController.SuppServiceRoutingInfo ssCode = + ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); + assertNotNull(ssCode); + assertFalse(ssCode.useSsOverUt()); + + mSdc.setOemHandlesTerminalBasedCallWaiting(true); + ssCode = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); + + assertNotNull(ssCode); + assertTrue(ssCode.useSsOverUt()); + } + private void setUtEnabled() { doReturn(0).when(mImsPhone).getSubId(); mSdc.updateWifiForUt(false); @@ -466,10 +489,10 @@ public class SsDomainControllerTest extends TelephonyTest { private void updateCarrierConfig(boolean supportsCsfb, boolean requiresImsRegistration, boolean availableWhenPsDataOff, boolean availableWhenRoaming, int[] utRats) { mSdc.updateCarrierConfigForTest(true, supportsCsfb, requiresImsRegistration, - availableWhenPsDataOff, availableWhenRoaming, null, utRats); + availableWhenPsDataOff, availableWhenRoaming, null, utRats, null); } private void updateCarrierConfig(int[] services) { - mSdc.updateCarrierConfigForTest(true, true, false, true, true, services, UT_OVER_ALL); + mSdc.updateCarrierConfigForTest(true, true, false, true, true, services, UT_OVER_ALL, null); } } -- GitLab From 8329adf5baf302319816332919bf1872d5f92b26 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 22 Apr 2022 12:16:40 +0000 Subject: [PATCH 044/656] Add phone Id to debug messages Add phone Id to debug messages in SsDomainController and CallWaitingController to make it easy analyzing logs of multi-sim devices. Bug: 202463005 Bug: 202463163 Test: build & flash Change-Id: I93d55e60f486b30b9e75a82f6e99de89c440b83f (cherry picked from commit 9457d7b69682b4742267b32238a0c57a32cfd1a7) Merged-In: I93d55e60f486b30b9e75a82f6e99de89c440b83f --- .../telephony/CallWaitingController.java | 76 +++++++++++-------- .../telephony/SsDomainController.java | 62 ++++++++------- 2 files changed, 79 insertions(+), 59 deletions(-) diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java index 41d54d82bc..4940eb62b2 100644 --- a/src/java/com/android/internal/telephony/CallWaitingController.java +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -55,7 +55,7 @@ import java.io.PrintWriter; */ public class CallWaitingController extends Handler { - public static final String LOG_TAG = "CallWaiting"; + public static final String LOG_TAG = "CallWaitingCtrl"; private static final boolean DBG = false; /* STOPSHIP if true */ // Terminal-based call waiting is not supported. */ @@ -107,7 +107,7 @@ public class CallWaitingController extends Handler { SubscriptionManager.INVALID_PHONE_INDEX); if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - Rlog.e(LOG_TAG, "onReceive ACTION_CARRIER_CONFIG_CHANGED invalid slotId " + loge("onReceive ACTION_CARRIER_CONFIG_CHANGED invalid slotId " + slotId); return; } @@ -155,7 +155,7 @@ public class CallWaitingController extends Handler { mCallWaitingState = sp.getInt(KEY_STATE + subId, TERMINAL_BASED_NOT_SUPPORTED); mSyncPreference = sp.getInt(KEY_CS_SYNC + phoneId, CALL_WAITING_SYNC_NONE); - Rlog.i(LOG_TAG, "initialize phoneId=" + phoneId + logi("initialize phoneId=" + phoneId + ", lastSubId=" + mLastSubId + ", subId=" + subId + ", state=" + mCallWaitingState + ", sync=" + mSyncPreference + ", csEnabled=" + mCsEnabled); @@ -189,7 +189,7 @@ public class CallWaitingController extends Handler { public synchronized boolean getCallWaiting(@Nullable Message onComplete) { if (mCallWaitingState == TERMINAL_BASED_NOT_SUPPORTED) return false; - Rlog.i(LOG_TAG, "getCallWaiting " + mCallWaitingState); + logi("getCallWaiting " + mCallWaitingState); if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { // Interrogate CW in CS network @@ -234,7 +234,7 @@ public class CallWaitingController extends Handler { if ((serviceClass & SERVICE_CLASS_VOICE) != SERVICE_CLASS_VOICE) return false; - Rlog.i(LOG_TAG, "setCallWaiting enable=" + enable + ", service=" + serviceClass); + logi("setCallWaiting enable=" + enable + ", service=" + serviceClass); if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { // Enable CW in the CS network @@ -295,22 +295,22 @@ public class CallWaitingController extends Handler { private synchronized void onSetCallWaitingDone(AsyncResult ar) { if (ar.userObj == null) { // For the case, CALL_WAITING_SYNC_FIRST_POWER_UP - if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone to sync on network attached"); + if (DBG) logd("onSetCallWaitingDone to sync on network attached"); if (ar.exception == null) { updateSyncState(true); } else { - Rlog.e(LOG_TAG, "onSetCallWaitingDone e=" + ar.exception); + loge("onSetCallWaitingDone e=" + ar.exception); } return; } if (!(ar.userObj instanceof Cw)) { // Unexpected state - if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone unexpected result"); + if (DBG) logd("onSetCallWaitingDone unexpected result"); return; } - if (DBG) Rlog.d(LOG_TAG, "onSetCallWaitingDone"); + if (DBG) logd("onSetCallWaitingDone"); Cw cw = (Cw) ar.userObj; if (mSyncPreference == CALL_WAITING_SYNC_IMS_ONLY) { @@ -341,7 +341,7 @@ public class CallWaitingController extends Handler { private synchronized void onGetCallWaitingDone(AsyncResult ar) { if (ar.userObj == null) { // For the case, CALL_WAITING_SYNC_FIRST_POWER_UP - if (DBG) Rlog.d(LOG_TAG, "onGetCallWaitingDone to sync on network attached"); + if (DBG) logd("onGetCallWaitingDone to sync on network attached"); boolean enabled = false; if (ar.exception == null) { //resp[0]: 1 if enabled, 0 otherwise @@ -351,15 +351,15 @@ public class CallWaitingController extends Handler { enabled = (resp[0] == 1) && (resp[1] & SERVICE_CLASS_VOICE) == SERVICE_CLASS_VOICE; } else { - Rlog.e(LOG_TAG, "onGetCallWaitingDone unexpected response"); + loge("onGetCallWaitingDone unexpected response"); } } else { - Rlog.e(LOG_TAG, "onGetCallWaitingDone e=" + ar.exception); + loge("onGetCallWaitingDone e=" + ar.exception); } if (enabled) { updateSyncState(true); } else { - Rlog.i(LOG_TAG, "onGetCallWaitingDone enabling CW service in CS network"); + logi("onGetCallWaitingDone enabling CW service in CS network"); mPhone.mCi.setCallWaiting(true, SERVICE_CLASS_VOICE, obtainMessage(EVENT_SET_CALL_WAITING_DONE)); } @@ -369,11 +369,11 @@ public class CallWaitingController extends Handler { if (!(ar.userObj instanceof Cw)) { // Unexpected state - if (DBG) Rlog.d(LOG_TAG, "onGetCallWaitingDone unexpected result"); + if (DBG) logd("onGetCallWaitingDone unexpected result"); return; } - if (DBG) Rlog.d(LOG_TAG, "onGetCallWaitingDone"); + if (DBG) logd("onGetCallWaitingDone"); Cw cw = (Cw) ar.userObj; if (mSyncPreference == CALL_WAITING_SYNC_IMS_ONLY) { @@ -387,7 +387,7 @@ public class CallWaitingController extends Handler { //resp[0]: 1 if enabled, 0 otherwise //resp[1]: bitwise ORs of SERVICE_CLASS_ if (resp == null || resp.length < 2) { - Rlog.i(LOG_TAG, "onGetCallWaitingDone unexpected response"); + logi("onGetCallWaitingDone unexpected response"); if (mSyncPreference == CALL_WAITING_SYNC_FIRST_CHANGE) { // no exception but unexpected response, local setting is preferred. sendGetCallWaitingResponse(cw.mOnComplete); @@ -405,7 +405,7 @@ public class CallWaitingController extends Handler { if (!enabled && !cw.mImsRegistered) { // IMS is not registered, change the local setting - Rlog.i(LOG_TAG, "onGetCallWaitingDone CW in CS network is disabled."); + logi("onGetCallWaitingDone CW in CS network is disabled."); updateState(TERMINAL_BASED_NOT_ACTIVATED); } @@ -419,7 +419,7 @@ public class CallWaitingController extends Handler { if (cw.mImsRegistered) { // queryCallWaiting failed. However, IMS is registered. Do not notify error. // return the user setting saved - Rlog.i(LOG_TAG, "onGetCallWaitingDone get an exception, but IMS is registered"); + logi("onGetCallWaitingDone get an exception, but IMS is registered"); sendGetCallWaitingResponse(cw.mOnComplete); return; } @@ -447,7 +447,7 @@ public class CallWaitingController extends Handler { private synchronized void onRegisteredToNetwork() { if (mCsEnabled) return; - if (DBG) Rlog.d(LOG_TAG, "onRegisteredToNetwork"); + if (DBG) logd("onRegisteredToNetwork"); mPhone.mCi.queryCallWaiting(SERVICE_CLASS_NONE, obtainMessage(EVENT_GET_CALL_WAITING_DONE)); @@ -456,7 +456,7 @@ public class CallWaitingController extends Handler { private synchronized void onCarrierConfigChanged() { int subId = mPhone.getSubId(); if (!SubscriptionManager.isValidSubscriptionId(subId)) { - Rlog.i(LOG_TAG, "onCarrierConfigChanged invalid subId=" + subId); + logi("onCarrierConfigChanged invalid subId=" + subId); mValidSubscription = false; unregisterForNetworkAttached(); @@ -468,7 +468,7 @@ public class CallWaitingController extends Handler { updateCarrierConfig(subId, b, false); - Rlog.i(LOG_TAG, "onCarrierConfigChanged cs_enabled=" + mCsEnabled); + logi("onCarrierConfigChanged cs_enabled=" + mCsEnabled); if (mSyncPreference == CALL_WAITING_SYNC_FIRST_POWER_UP) { if (!mCsEnabled) { @@ -504,7 +504,7 @@ public class CallWaitingController extends Handler { int savedState = getSavedState(subId); if (DBG) { - Rlog.d(LOG_TAG, "updateCarrierConfig phoneId=" + mPhone.getPhoneId() + logd("updateCarrierConfig phoneId=" + mPhone.getPhoneId() + ", subId=" + subId + ", support=" + supportsTerminalBased + ", sync=" + syncPreference + ", default=" + defaultState + ", savedState=" + savedState); @@ -545,7 +545,7 @@ public class CallWaitingController extends Handler { int phoneId = mPhone.getPhoneId(); - Rlog.i(LOG_TAG, "updateState phoneId=" + phoneId + logi("updateState phoneId=" + phoneId + ", subId=" + subId + ", state=" + state + ", sync=" + syncPreference + ", ignoreSavedState=" + ignoreSavedState); @@ -573,7 +573,7 @@ public class CallWaitingController extends Handler { mContext.getSharedPreferences(PREFERENCE_TBCW, Context.MODE_PRIVATE); int state = sp.getInt(KEY_STATE + subId, TERMINAL_BASED_NOT_SUPPORTED); - Rlog.i(LOG_TAG, "getSavedState subId=" + subId + ", state=" + state); + logi("getSavedState subId=" + subId + ", state=" + state); return state; } @@ -581,7 +581,7 @@ public class CallWaitingController extends Handler { private void updateSyncState(boolean enabled) { int phoneId = mPhone.getPhoneId(); - Rlog.i(LOG_TAG, "updateSyncState phoneId=" + phoneId + ", enabled=" + enabled); + logi("updateSyncState phoneId=" + phoneId + ", enabled=" + enabled); mCsEnabled = enabled; } @@ -595,13 +595,13 @@ public class CallWaitingController extends Handler { } private boolean isCircuitSwitchedNetworkAvailable() { - Rlog.i(LOG_TAG, "isCircuitSwitchedNetworkAvailable=" + logi("isCircuitSwitchedNetworkAvailable=" + (mSST.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)); return mSST.getServiceState().getState() == ServiceState.STATE_IN_SERVICE; } private boolean isImsRegistered() { - Rlog.i(LOG_TAG, "isImsRegistered " + mImsRegistered); + logi("isImsRegistered " + mImsRegistered); return mImsRegistered; } @@ -609,13 +609,13 @@ public class CallWaitingController extends Handler { * Sets the registration state of IMS service. */ public synchronized void setImsRegistrationState(boolean registered) { - Rlog.i(LOG_TAG, "setImsRegistrationState prev=" + mImsRegistered + logi("setImsRegistrationState prev=" + mImsRegistered + ", new=" + registered); mImsRegistered = registered; } private void registerForNetworkAttached() { - Rlog.i(LOG_TAG, "registerForNetworkAttached"); + logi("registerForNetworkAttached"); if (mRegisteredForNetworkAttach) return; mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); @@ -623,7 +623,7 @@ public class CallWaitingController extends Handler { } private void unregisterForNetworkAttached() { - Rlog.i(LOG_TAG, "unregisterForNetworkAttached"); + logi("unregisterForNetworkAttached"); if (!mRegisteredForNetworkAttach) return; mSST.unregisterForNetworkAttached(this); @@ -639,7 +639,7 @@ public class CallWaitingController extends Handler { public synchronized void setTerminalBasedCallWaitingSupported(boolean supported) { if (mSupportedByImsService == supported) return; - Rlog.i(LOG_TAG, "setTerminalBasedCallWaitingSupported " + supported); + logi("setTerminalBasedCallWaitingSupported " + supported); mSupportedByImsService = supported; @@ -668,7 +668,7 @@ public class CallWaitingController extends Handler { /** * Dump this instance into a readable format for dumpsys usage. */ - public synchronized void dump(PrintWriter printWriter) { + public void dump(PrintWriter printWriter) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.increaseIndent(); pw.println("CallWaitingController:"); @@ -682,4 +682,16 @@ public class CallWaitingController extends Handler { pw.println(" mImsRegistered=" + mImsRegistered); pw.decreaseIndent(); } + + private void loge(String msg) { + Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "] " + msg); + } + + private void logi(String msg) { + Rlog.i(LOG_TAG, "[" + mPhone.getPhoneId() + "] " + msg); + } + + private void logd(String msg) { + Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "] " + msg); + } } diff --git a/src/java/com/android/internal/telephony/SsDomainController.java b/src/java/com/android/internal/telephony/SsDomainController.java index 85ca44d94f..eef9b68fea 100644 --- a/src/java/com/android/internal/telephony/SsDomainController.java +++ b/src/java/com/android/internal/telephony/SsDomainController.java @@ -139,19 +139,19 @@ public class SsDomainController { new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { - Rlog.i(LOG_TAG, "Network available: " + network); + logi("Network available: " + network); updateWifiForUt(true); } @Override public void onLost(Network network) { - Rlog.i(LOG_TAG, "Network lost: " + network); + logi("Network lost: " + network); updateWifiForUt(false); } @Override public void onUnavailable() { - Rlog.i(LOG_TAG, "Network unavailable"); + logi("Network unavailable"); updateWifiForUt(false); } }; @@ -229,7 +229,7 @@ public class SsDomainController { } } } - Rlog.i(LOG_TAG, "updateSsOverUtConfig terminal-based cw " + logi("updateSsOverUtConfig terminal-based cw " + mSupportsTerminalBasedCallWaiting); mCbOverUtSupported.clear(); @@ -238,7 +238,7 @@ public class SsDomainController { mUtAvailableRats.clear(); if (!mUtSupported) { - Rlog.d(LOG_TAG, "updateSsOverUtConfig Ut is not supported"); + logd("updateSsOverUtConfig Ut is not supported"); unregisterForConnectivityChanges(); return; } @@ -259,7 +259,7 @@ public class SsDomainController { unregisterForConnectivityChanges(); } - Rlog.i(LOG_TAG, "updateSsOverUtConfig supportsUt=" + mUtSupported + logi("updateSsOverUtConfig supportsUt=" + mUtSupported + ", csfb=" + mCsfbSupported + ", regRequire=" + mUtRequiresImsRegistration + ", whenPsDataOff=" + mUtAvailableWhenPsDataOff @@ -322,18 +322,18 @@ public class SsDomainController { public boolean isUtEnabled() { Phone imsPhone = mPhone.getImsPhone(); if (imsPhone == null) { - Rlog.d(LOG_TAG, "isUtEnabled: called for GsmCdma"); + logd("isUtEnabled: called for GsmCdma"); return false; } if (!mUtSupported) { - Rlog.d(LOG_TAG, "isUtEnabled: not supported"); + logd("isUtEnabled: not supported"); return false; } if (mUtRequiresImsRegistration && imsPhone.getServiceState().getState() != ServiceState.STATE_IN_SERVICE) { - Rlog.d(LOG_TAG, "isUtEnabled: not registered"); + logd("isUtEnabled: not registered"); return false; } @@ -349,34 +349,34 @@ public class SsDomainController { int state = Settings.Global.getInt(mPhone.getContext().getContentResolver(), Settings.Global.MOBILE_DATA, -1); if (state == -1) { - Rlog.i(LOG_TAG, "isMobileDataEnabled MOBILE_DATA not found"); + logi("isMobileDataEnabled MOBILE_DATA not found"); enabled = "true".equalsIgnoreCase( SystemProperties.get("ro.com.android.mobiledata", "true")); } else { enabled = (state != 0); } - Rlog.i(LOG_TAG, "isMobileDataEnabled enabled=" + enabled); + logi("isMobileDataEnabled enabled=" + enabled); return enabled; } private boolean isUtAvailableOnAnyTransport() { if (mUtAvailableWhenPsDataOff || isMobileDataEnabled()) { if (isUtAvailableOverCellular()) { - Rlog.i(LOG_TAG, "isUtAvailableOnAnyTransport found cellular"); + logi("isUtAvailableOnAnyTransport found cellular"); return true; } } - Rlog.i(LOG_TAG, "isUtAvailableOnAnyTransport wifiConnected=" + mWiFiAvailable); + logi("isUtAvailableOnAnyTransport wifiConnected=" + mWiFiAvailable); if (mWiFiAvailable) { if (mUtAvailableRats.contains(IWLAN)) { - Rlog.i(LOG_TAG, "isUtAvailableOnAnyTransport found wifi"); + logi("isUtAvailableOnAnyTransport found wifi"); return true; } - Rlog.i(LOG_TAG, "isUtAvailableOnAnyTransport wifi not support Ut"); + logi("isUtAvailableOnAnyTransport wifi not support Ut"); } - Rlog.i(LOG_TAG, "isUtAvailableOnAnyTransport no transport"); + logi("isUtAvailableOnAnyTransport no transport"); return false; } @@ -385,7 +385,7 @@ public class SsDomainController { NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); if (nri != null && nri.isRegistered()) { if (!mUtAvailableWhenRoaming && nri.isRoaming()) { - Rlog.i(LOG_TAG, "isUtAvailableOverCellular not available in roaming"); + logi("isUtAvailableOverCellular not available in roaming"); return false; } @@ -415,7 +415,7 @@ public class SsDomainController { } } - Rlog.i(LOG_TAG, "isUtAvailableOverCellular no cellular"); + logi("isUtAvailableOverCellular no cellular"); return false; } @@ -438,7 +438,7 @@ public class SsDomainController { ConnectivityManager cm = (ConnectivityManager) mPhone.getContext() .getSystemService(Context.CONNECTIVITY_SERVICE); if (cm != null) { - Rlog.i(LOG_TAG, "registerForConnectivityChanges"); + logi("registerForConnectivityChanges"); NetworkRequest.Builder builder = new NetworkRequest.Builder(); builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); cm.registerNetworkCallback(builder.build(), mNetworkCallback); @@ -457,7 +457,7 @@ public class SsDomainController { ConnectivityManager cm = (ConnectivityManager) mPhone.getContext() .getSystemService(Context.CONNECTIVITY_SERVICE); if (cm != null) { - Rlog.i(LOG_TAG, "unregisterForConnectivityChanges"); + logi("unregisterForConnectivityChanges"); cm.unregisterNetworkCallback(mNetworkCallback); mIsMonitoringConnectivity = false; } @@ -469,7 +469,7 @@ public class SsDomainController { @VisibleForTesting public boolean useCbOverUt(String facility) { if (!mUtSupported) { - Rlog.d(LOG_TAG, "useCbOverUt: Ut not supported"); + logd("useCbOverUt: Ut not supported"); return false; } @@ -482,7 +482,7 @@ public class SsDomainController { @VisibleForTesting public boolean useCfOverUt(int reason) { if (!mUtSupported) { - Rlog.d(LOG_TAG, "useCfOverUt: Ut not supported"); + logd("useCfOverUt: Ut not supported"); return false; } @@ -495,7 +495,7 @@ public class SsDomainController { @VisibleForTesting public boolean useSsOverUt(String service) { if (!mUtSupported) { - Rlog.d(LOG_TAG, "useSsOverUt: Ut not supported"); + logd("useSsOverUt: Ut not supported"); return false; } @@ -507,7 +507,7 @@ public class SsDomainController { */ public boolean supportCsfb() { if (!mUtSupported) { - Rlog.d(LOG_TAG, "supportsCsfb: Ut not supported"); + logd("supportsCsfb: Ut not supported"); return true; } @@ -561,7 +561,7 @@ public class SsDomainController { public void updateCarrierConfigForTest(boolean supportsUt, boolean supportsCsfb, boolean requiresImsRegistration, boolean availableWhenPsDataOff, boolean availableWhenRoaming, int[] services, int[] utRats, int[] tbServices) { - Rlog.i(LOG_TAG, "updateCarrierConfigForTest supportsUt=" + supportsUt + logi("updateCarrierConfigForTest supportsUt=" + supportsUt + ", csfb=" + supportsCsfb + ", reg=" + requiresImsRegistration + ", whenPsDataOff=" + availableWhenPsDataOff @@ -579,7 +579,7 @@ public class SsDomainController { * Otherwise, false. */ public void setOemHandlesTerminalBasedCallWaiting(boolean state) { - Rlog.i(LOG_TAG, "setOemHandlesTerminalBasedCallWaiting " + state); + logi("setOemHandlesTerminalBasedCallWaiting " + state); mOemHandlesTerminalBasedCallWaiting = state; } @@ -588,7 +588,7 @@ public class SsDomainController { * and Ims service handles it by itself. */ public boolean getOemHandlesTerminalBasedCallWaiting() { - Rlog.i(LOG_TAG, "getOemHandlesTerminalBasedCallWaiting " + logi("getOemHandlesTerminalBasedCallWaiting " + mSupportsTerminalBasedCallWaiting + ", " + mOemHandlesTerminalBasedCallWaiting); return mSupportsTerminalBasedCallWaiting && mOemHandlesTerminalBasedCallWaiting; } @@ -614,4 +614,12 @@ public class SsDomainController { pw.println(" mSupportsTerminalBasedCallWaiting=" + mSupportsTerminalBasedCallWaiting); pw.decreaseIndent(); } + + private void logi(String msg) { + Rlog.i(LOG_TAG, "[" + mPhone.getPhoneId() + "] " + msg); + } + + private void logd(String msg) { + Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "] " + msg); + } } -- GitLab From f8096e8b760fd516bfc0a82a9c56b1e6f3be137c Mon Sep 17 00:00:00 2001 From: Thomas Stuart Date: Wed, 22 Jun 2022 09:29:46 -0700 Subject: [PATCH 045/656] fix Telecom out of sync w/ Telephony#defaultVoiceSubId bug: 204226202 Test: manual Change-Id: Ia1134daf40edf454bd59f4c4b8585bf5247f3233 --- .../internal/telephony/SubscriptionController.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index d9b9bd4eff..6478a54117 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -2860,15 +2860,9 @@ public class SubscriptionController extends ISub.Stub { subId); TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); - PhoneAccountHandle currentHandle = telecomManager.getUserSelectedOutgoingPhoneAccount(); - logd("[setDefaultVoiceSubId] current phoneAccountHandle=" + currentHandle); - if (!Objects.equals(currentHandle, newHandle)) { - telecomManager.setUserSelectedOutgoingPhoneAccount(newHandle); - logd("[setDefaultVoiceSubId] change to phoneAccountHandle=" + newHandle); - } else { - logd("[setDefaultVoiceSubId] default phoneAccountHandle not changed."); - } + telecomManager.setUserSelectedOutgoingPhoneAccount(newHandle); + logd("[setDefaultVoiceSubId] requesting change to phoneAccountHandle=" + newHandle); if (previousDefaultSub != getDefaultSubId()) { sendDefaultChangedBroadcast(getDefaultSubId()); -- GitLab From 91aef910340fc74ae04ab80ebebd654311403c0d Mon Sep 17 00:00:00 2001 From: Ramya Manoharan Date: Wed, 11 May 2022 03:50:42 +0000 Subject: [PATCH 046/656] Fetching smsc value from Usim/Isim Apis for every SMS sent. smsc is the service center address. Test: UT Bug: 231112947 Change-Id: I1c8388fca6796cae89e5db419e0113339542aa97 --- .../telephony/SmsDispatchersController.java | 25 +++++++++++++++++++ .../telephony/ImsSmsDispatcherTest.java | 2 +- .../SmsDispatchersControllerTest.java | 22 ++++++++++++++++ .../telephony/gsm/GsmSmsDispatcherTest.java | 23 ++++++++--------- 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java index 04927edd90..29ec7d8cad 100644 --- a/src/java/com/android/internal/telephony/SmsDispatchersController.java +++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java @@ -29,6 +29,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.AsyncResult; +import android.os.Binder; import android.os.Handler; import android.os.Message; import android.os.UserManager; @@ -242,6 +243,21 @@ public class SmsDispatchersController extends Handler { } } + private String getSmscAddressFromUSIM(String callingPkg) { + IccSmsInterfaceManager iccSmsIntMgr = mPhone.getIccSmsInterfaceManager(); + if (iccSmsIntMgr != null) { + long identity = Binder.clearCallingIdentity(); + try { + return iccSmsIntMgr.getSmscAddressFromIccEf(callingPkg); + } finally { + Binder.restoreCallingIdentity(identity); + } + } else { + Rlog.d(TAG, "getSmscAddressFromIccEf iccSmsIntMgr is null"); + } + return null; + } + private void reevaluateTimerStatus() { long currentTime = System.currentTimeMillis(); @@ -671,6 +687,9 @@ public class SmsDispatchersController extends Handler { */ protected void sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm) { + if (scAddr == null) { + scAddr = getSmscAddressFromUSIM(callingPackage); + } if (mImsSmsDispatcher.isAvailable()) { mImsSmsDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent, deliveryIntent, isForVvm); @@ -784,6 +803,9 @@ public class SmsDispatchersController extends Handler { PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId) { + if (scAddr == null) { + scAddr = getSmscAddressFromUSIM(callingPkg); + } if (mImsSmsDispatcher.isAvailable() || mImsSmsDispatcher.isEmergencySmsSupport(destAddr)) { mImsSmsDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage, priority, false /*expectMore*/, @@ -910,6 +932,9 @@ public class SmsDispatchersController extends Handler { ArrayList deliveryIntents, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, long messageId) { + if (scAddr == null) { + scAddr = getSmscAddressFromUSIM(callingPkg); + } if (mImsSmsDispatcher.isAvailable()) { mImsSmsDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri, callingPkg, persistMessage, priority, diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java index fd1c5e0007..3bbba0b9d2 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java @@ -293,7 +293,7 @@ public class ImsSmsDispatcherTest extends TelephonyTest { verify(mImsManager).sendSms(eq(token + 2), eq(messageRef), eq(SmsMessage.FORMAT_3GPP), nullable(String.class), eq(true), byteCaptor.capture()); byte[] pdu = byteCaptor.getValue(); - assertEquals(pdu[1], messageRef); + assertEquals(messageRef, pdu[1]); assertEquals(0x04, (pdu[0] & 0x04)); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java index 6ef8508edf..64c21542b7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.os.Message; import android.provider.Telephony.Sms.Intents; +import android.telephony.PhoneNumberUtils; import android.telephony.SmsManager; import android.test.FlakyTest; import android.test.suitebuilder.annotation.SmallTest; @@ -42,11 +43,14 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Singleton; +import com.android.internal.telephony.uicc.IccUtils; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import java.util.HashMap; @@ -179,6 +183,24 @@ public class SmsDispatchersControllerTest extends TelephonyTest { assertEquals(true, mInjectionCallbackTriggered); } + @Test @SmallTest + public void testSendImsGmsTestWithSmsc() { + IccSmsInterfaceManager iccSmsInterfaceManager = Mockito.mock(IccSmsInterfaceManager.class); + when(mPhone.getIccSmsInterfaceManager()).thenReturn(iccSmsInterfaceManager); + when(iccSmsInterfaceManager.getSmscAddressFromIccEf("com.android.messaging")) + .thenReturn("222"); + switchImsSmsFormat(PhoneConstants.PHONE_TYPE_GSM); + + mSmsDispatchersController.sendText("111", null /*scAddr*/, TAG, + null, null, null, "com.android.messaging", + false, -1, false, -1, false, 0L); + byte[] smscbyte = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( + "222"); + String smsc = IccUtils.bytesToHexString(smscbyte); + verify(mSimulatedCommandsVerifier).sendImsGsmSms(eq(smsc), anyString(), + anyInt(), anyInt(), any(Message.class)); + } + private void switchImsSmsFormat(int phoneType) { mSimulatedCommands.setImsRegistrationState(new int[]{1, phoneType}); mSimulatedCommands.notifyImsNetworkStateChanged(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java index 23aa083f1d..5f4671b918 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java @@ -518,7 +518,7 @@ public class GsmSmsDispatcherTest extends TelephonyTest { verify(mSimulatedCommandsVerifier).sendSMS(anyString(), pduCaptor.capture(), any(Message.class)); byte[] pdu = IccUtils.hexStringToBytes(pduCaptor.getValue()); - assertEquals(pdu[1], messageRef); + assertEquals(messageRef, pdu[1]); } @Test @@ -539,7 +539,7 @@ public class GsmSmsDispatcherTest extends TelephonyTest { verify(mSimulatedCommandsVerifier).sendSMS(anyString(), pduCaptor.capture(), any(Message.class)); byte[] pdu = IccUtils.hexStringToBytes(pduCaptor.getValue()); - assertEquals(pdu[1], messageRef); + assertEquals(messageRef, pdu[1]); } @Test @@ -553,11 +553,11 @@ public class GsmSmsDispatcherTest extends TelephonyTest { mGsmSmsDispatcher.sendText("111", "222" /*scAddr*/, TAG, null, null, null, null, false, -1, false, -1, false, 0L); - ArgumentCaptor pduCaptor1 = ArgumentCaptor.forClass(String.class); - verify(mSimulatedCommandsVerifier).sendSMS(anyString(), pduCaptor1.capture(), + ArgumentCaptor pduCaptor = ArgumentCaptor.forClass(String.class); + verify(mSimulatedCommandsVerifier).sendSMS(anyString(), pduCaptor.capture(), any(Message.class)); - byte[] pdu1 = IccUtils.hexStringToBytes(pduCaptor1.getValue()); - assertEquals(pdu1[1], 0); + byte[] pdu = IccUtils.hexStringToBytes(pduCaptor.getValue()); + assertEquals(0, pdu[1]); } @Test @@ -566,15 +566,14 @@ public class GsmSmsDispatcherTest extends TelephonyTest { mSimulatedCommands); doReturn(mIsimUiccRecords).when(mPhone).getIccRecords(); Message msg = mGsmSmsDispatcher.obtainMessage(17); - - mPhone.getIccRecords().setSmssTpmrValue(255, null); + mPhone.getIccRecords().setSmssTpmrValue(255, msg); mGsmSmsDispatcher.sendText("111", "222" /*scAddr*/, TAG, null, null, null, null, false, -1, false, -1, false, 0L); - ArgumentCaptor pduCaptor2 = ArgumentCaptor.forClass(String.class); - verify(mSimulatedCommandsVerifier).sendSMS(anyString(), pduCaptor2.capture(), + ArgumentCaptor pduCaptor = ArgumentCaptor.forClass(String.class); + verify(mSimulatedCommandsVerifier).sendSMS(anyString(), pduCaptor.capture(), any(Message.class)); - byte[] pdu2 = IccUtils.hexStringToBytes(pduCaptor2.getValue()); - assertEquals(pdu2[1], 0); + byte[] pdu = IccUtils.hexStringToBytes(pduCaptor.getValue()); + assertEquals(0, pdu[1]); } } -- GitLab From 50461264f6a416860457dd1c39f7a45b1ff0756a Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Fri, 17 Jun 2022 11:43:33 +0000 Subject: [PATCH 047/656] Interface for PSI-SMSC value from UICC Bug: 236680361 Test: Done with manual and atest verification Change-Id: I3359d274322a981bf2353a771fc37626f4309d6b --- .../telephony/PhoneSubInfoController.java | 24 +++ .../telephony/PhoneSubInfoControllerTest.java | 150 ++++++++++++++++++ 2 files changed, 174 insertions(+) diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java index abbd696d0f..b4c3379575 100644 --- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java +++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java @@ -583,6 +583,30 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { } } + /** + * Returns SIP URI or tel URI of the Public Service Identity of the SM-SC that fetched from + * EFPSISMSC elementary field that are loaded based on the ISIM/USIM appType. + */ + public String getSmscIdentity(int subId, int appType) + throws RemoteException { + return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getSmscIdentity", + (phone) -> { + UiccPort uiccPort = phone.getUiccPort(); + if (uiccPort == null || uiccPort.getUiccProfile() == null) { + loge("getSmscIdentity(): uiccPort or uiccProfile is null"); + return null; + } + UiccCardApplication uiccApp = uiccPort.getUiccProfile().getApplicationByType( + appType); + if (uiccApp == null) { + loge("getSmscIdentity(): no app with specified type = " + + appType); + return null; + } + return uiccApp.getIccRecords().getSmscIdentity(); + }); + } + private void log(String s) { Rlog.d(TAG, s); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java index 606bcec321..a9b4ae7ba8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; import static android.Manifest.permission.READ_PHONE_STATE; +import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -33,15 +34,27 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; import android.os.Build; +import android.os.RemoteException; import android.test.suitebuilder.annotation.SmallTest; +import com.android.internal.telephony.uicc.IsimUiccRecords; +import com.android.internal.telephony.uicc.SIMRecords; +import com.android.internal.telephony.uicc.UiccCardApplication; +import com.android.internal.telephony.uicc.UiccPort; +import com.android.internal.telephony.uicc.UiccProfile; + import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; public class PhoneSubInfoControllerTest extends TelephonyTest { private static final String FEATURE_ID = "myfeatureId"; + private static final String PSI_SMSC_TEL1 = "tel:+91123456789"; + private static final String PSI_SMSC_SIP1 = "sip:+1234567890@msg.pc.t-mobile.com;user=phone"; + private static final String PSI_SMSC_TEL2 = "tel:+91987654321"; + private static final String PSI_SMSC_SIP2 = "sip:+19876543210@msg.pc.t-mobile.com;user=phone"; private PhoneSubInfoController mPhoneSubInfoControllerUT; private AppOpsManager mAppOsMgr; @@ -922,4 +935,141 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { assertEquals("VM_SIM_1", mPhoneSubInfoControllerUT .getVoiceMailAlphaTagForSubscriber(1, TAG, FEATURE_ID)); } + + private void setUpInitials() { + UiccPort uiccPort1 = Mockito.mock(UiccPort.class); + UiccProfile uiccProfile1 = Mockito.mock(UiccProfile.class); + UiccCardApplication uiccCardApplication1 = Mockito.mock(UiccCardApplication.class); + SIMRecords simRecords1 = Mockito.mock(SIMRecords.class); + IsimUiccRecords isimUiccRecords1 = Mockito.mock(IsimUiccRecords.class); + + doReturn(uiccPort1).when(mPhone).getUiccPort(); + doReturn(uiccProfile1).when(uiccPort1).getUiccProfile(); + doReturn(uiccCardApplication1).when(uiccProfile1).getApplicationByType(anyInt()); + doReturn(simRecords1).when(uiccCardApplication1).getIccRecords(); + doReturn(isimUiccRecords1).when(uiccCardApplication1).getIccRecords(); + doReturn(PSI_SMSC_TEL1).when(simRecords1).getSmscIdentity(); + doReturn(PSI_SMSC_TEL1).when(isimUiccRecords1).getSmscIdentity(); + + doReturn(mUiccPort).when(mSecondPhone).getUiccPort(); + doReturn(mUiccProfile).when(mUiccPort).getUiccProfile(); + doReturn(mUiccCardApplicationIms).when(mUiccProfile).getApplicationByType(anyInt()); + doReturn(mSimRecords).when(mUiccCardApplicationIms).getIccRecords(); + doReturn(mIsimUiccRecords).when(mUiccCardApplicationIms).getIccRecords(); + doReturn(PSI_SMSC_TEL2).when(mSimRecords).getSmscIdentity(); + doReturn(PSI_SMSC_TEL2).when(mIsimUiccRecords).getSmscIdentity(); + } + + @Test + public void testGetSmscIdentityForTelUri() { + try { + setUpInitials(); + assertEquals(PSI_SMSC_TEL1, mPhoneSubInfoControllerUT + .getSmscIdentity(0, 5)); + assertEquals(PSI_SMSC_TEL1, mPhoneSubInfoControllerUT + .getSmscIdentity(0, 3)); + assertEquals(PSI_SMSC_TEL2, mPhoneSubInfoControllerUT + .getSmscIdentity(1, 5)); + assertEquals(PSI_SMSC_TEL2, mPhoneSubInfoControllerUT + .getSmscIdentity(1, 5)); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Test + public void testGetSmscIdentityForSipUri() { + try { + UiccPort uiccPort1 = Mockito.mock(UiccPort.class); + UiccProfile uiccProfile1 = Mockito.mock(UiccProfile.class); + UiccCardApplication uiccCardApplication1 = Mockito.mock(UiccCardApplication.class); + SIMRecords simRecords1 = Mockito.mock(SIMRecords.class); + IsimUiccRecords isimUiccRecords1 = Mockito.mock(IsimUiccRecords.class); + + doReturn(uiccPort1).when(mPhone).getUiccPort(); + doReturn(uiccProfile1).when(uiccPort1).getUiccProfile(); + doReturn(uiccCardApplication1).when(uiccProfile1).getApplicationByType(anyInt()); + doReturn(simRecords1).when(uiccCardApplication1).getIccRecords(); + doReturn(isimUiccRecords1).when(uiccCardApplication1).getIccRecords(); + doReturn(PSI_SMSC_SIP1).when(simRecords1).getSmscIdentity(); + doReturn(PSI_SMSC_SIP1).when(isimUiccRecords1).getSmscIdentity(); + + doReturn(mUiccPort).when(mSecondPhone).getUiccPort(); + doReturn(mUiccProfile).when(mUiccPort).getUiccProfile(); + doReturn(mUiccCardApplicationIms).when(mUiccProfile).getApplicationByType(anyInt()); + doReturn(mSimRecords).when(mUiccCardApplicationIms).getIccRecords(); + doReturn(mIsimUiccRecords).when(mUiccCardApplicationIms).getIccRecords(); + doReturn(PSI_SMSC_SIP2).when(mSimRecords).getSmscIdentity(); + doReturn(PSI_SMSC_SIP2).when(mIsimUiccRecords).getSmscIdentity(); + + assertEquals(PSI_SMSC_SIP1, mPhoneSubInfoControllerUT + .getSmscIdentity(0, 5)); + assertEquals(PSI_SMSC_SIP1, mPhoneSubInfoControllerUT + .getSmscIdentity(0, 3)); + assertEquals(PSI_SMSC_SIP2, mPhoneSubInfoControllerUT + .getSmscIdentity(1, 5)); + assertEquals(PSI_SMSC_SIP2, mPhoneSubInfoControllerUT + .getSmscIdentity(1, 5)); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Test + public void testGetSmscIdentityWithOutPermissions() { + setUpInitials(); + + //case 1: no READ_PRIVILEGED_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); + try { + mPhoneSubInfoControllerUT.getSmscIdentity(0, 5); + Assert.fail("expected Security Exception Thrown"); + } catch (Exception ex) { + assertTrue(ex instanceof SecurityException); + assertTrue(ex.getMessage().contains("getSmscIdentity")); + } + + try { + mPhoneSubInfoControllerUT.getSmscIdentity(1, 5); + Assert.fail("expected Security Exception Thrown"); + } catch (Exception ex) { + assertTrue(ex instanceof SecurityException); + assertTrue(ex.getMessage().contains("getSmscIdentity")); + } + + try { + mPhoneSubInfoControllerUT.getSmscIdentity(0, 3); + Assert.fail("expected Security Exception Thrown"); + } catch (Exception ex) { + assertTrue(ex instanceof SecurityException); + assertTrue(ex.getMessage().contains("getSmscIdentity")); + } + + try { + mPhoneSubInfoControllerUT.getSmscIdentity(1, 3); + Assert.fail("expected Security Exception Thrown"); + } catch (Exception ex) { + assertTrue(ex instanceof SecurityException); + assertTrue(ex.getMessage().contains("getSmscIdentity")); + } + + //case 2: no READ_PRIVILEGED_PHONE_STATE + mContextFixture.addCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE); + doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOp( + eq(AppOpsManager.OPSTR_READ_PHONE_STATE), anyInt(), eq(TAG), eq(FEATURE_ID), + nullable(String.class)); + + try { + assertEquals(PSI_SMSC_TEL1, mPhoneSubInfoControllerUT + .getSmscIdentity(0, 5)); + assertEquals(PSI_SMSC_TEL1, mPhoneSubInfoControllerUT + .getSmscIdentity(0, 3)); + assertEquals(PSI_SMSC_TEL2, mPhoneSubInfoControllerUT + .getSmscIdentity(1, 5)); + assertEquals(PSI_SMSC_TEL2, mPhoneSubInfoControllerUT + .getSmscIdentity(1, 5)); + } catch (RemoteException e) { + e.printStackTrace(); + } + } } -- GitLab From 02f3fed27eb2a6d0300b4a7bad3642549207dd75 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 24 Jun 2022 10:39:21 +0000 Subject: [PATCH 048/656] Fix SsDomainController to support terminal-based CLIR with vendor IMS If vendor Ims service handles the terminal based call waiting service by itself, we should forward the request to Ims service as legacy implementation when Ut is available. Bug: 237030511 Test: atest Change-Id: I701cf010da26a7fd4b93e06e99f9dcdcaf0d0e81 --- .../internal/telephony/GsmCdmaPhone.java | 38 ++++++++++++---- .../telephony/SsDomainController.java | 44 +++++++++++++------ .../internal/telephony/GsmCdmaPhoneTest.java | 29 ++++++++++++ .../telephony/SsDomainControllerTest.java | 39 +++++++++++++++- 4 files changed, 126 insertions(+), 24 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index b437bbd83b..6d16fe072a 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -2378,18 +2378,18 @@ public class GsmCdmaPhone extends Phone { /** * Checks the availability of Ut directly without SsDomainController. - * This is only applicable for the case that the terminal-based call waiting service - * is handled by the IMS service alone without interworking with CallWaitingController. + * This is only applicable for the case that the terminal-based service + * is handled by the IMS service alone without interworking with framework. */ - private boolean useCallWaitingOverUt(Message onComplete) { + private boolean useTerminalBasedServiceOverIms(Message onComplete) { Phone imsPhone = mImsPhone; if (imsPhone == null) { - logd("useCallWaitingOverUt: called for GsmCdma"); + logd("useTerminalBasedServiceOverIms: called for GsmCdma"); return false; } boolean isUtEnabled = imsPhone.isUtEnabled(); - Rlog.d(LOG_TAG, "useCallWaitingOverUt isUtEnabled= " + isUtEnabled + Rlog.d(LOG_TAG, "useTerminalBasedServiceOverIms isUtEnabled= " + isUtEnabled + " isCsRetry(onComplete))= " + isCsRetry(onComplete)); return isUtEnabled && !isCsRetry(onComplete); } @@ -2409,6 +2409,14 @@ public class GsmCdmaPhone extends Phone { return mSsDomainController.getOemHandlesTerminalBasedCallWaiting(); } + /** + * Returns whether the carrier supports the terminal-based CLIR + * and Ims service handles it by itself. + */ + private boolean getOemHandlesTerminalBasedClir() { + return mSsDomainController.getOemHandlesTerminalBasedClir(); + } + /** * Sends response indicating no nework is available for supplementary services. */ @@ -2668,6 +2676,13 @@ public class GsmCdmaPhone extends Phone { responseInvalidState(onComplete); return; } + } else if (getOemHandlesTerminalBasedClir()) { + // Ims service handles the terminal-based CLIR by itself. + // Use legacy implementation. Forward the request to Ims service if Ut is available. + if (useTerminalBasedServiceOverIms(onComplete)) { + imsPhone.getOutgoingCallerIdDisplay(onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2700,6 +2715,13 @@ public class GsmCdmaPhone extends Phone { responseInvalidState(onComplete); return; } + } else if (getOemHandlesTerminalBasedClir()) { + // Ims service handles the terminal-based CLIR by itself. + // Use legacy implementation. Forward the request to Ims service if Ut is available. + if (useTerminalBasedServiceOverIms(onComplete)) { + imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete); + return; + } } if (isPhoneTypeGsm()) { @@ -2771,7 +2793,7 @@ public class GsmCdmaPhone extends Phone { } else if (getOemHandlesTerminalBasedCallWaiting()) { // Ims service handles the terminal-based call waiting service by itself. // Use legacy implementation. Forward the request to Ims service if Ut is available. - if (useCallWaitingOverUt(onComplete)) { + if (useTerminalBasedServiceOverIms(onComplete)) { imsPhone.getCallWaiting(onComplete); return; } @@ -2836,7 +2858,7 @@ public class GsmCdmaPhone extends Phone { } else if (getOemHandlesTerminalBasedCallWaiting()) { // Ims service handles the terminal-based call waiting service by itself. // Use legacy implementation. Forward the request to Ims service if Ut is available. - if (useCallWaitingOverUt(onComplete)) { + if (useTerminalBasedServiceOverIms(onComplete)) { imsPhone.setCallWaiting(enable, onComplete); return; } @@ -2880,7 +2902,7 @@ public class GsmCdmaPhone extends Phone { @Override public void setTerminalBasedCallWaitingSupported(boolean supported) { mCallWaitingController.setTerminalBasedCallWaitingSupported(supported); - mSsDomainController.setOemHandlesTerminalBasedCallWaiting(!supported); + mSsDomainController.setOemHandlesTerminalBasedService(!supported); } @Override diff --git a/src/java/com/android/internal/telephony/SsDomainController.java b/src/java/com/android/internal/telephony/SsDomainController.java index eef9b68fea..b0c7dfd7ae 100644 --- a/src/java/com/android/internal/telephony/SsDomainController.java +++ b/src/java/com/android/internal/telephony/SsDomainController.java @@ -170,9 +170,10 @@ public class SsDomainController { private Set mUtAvailableRats = new HashSet<>(); private boolean mWiFiAvailable = false; private boolean mIsMonitoringConnectivity = false; - /** true if Ims service handles the terminal-based call waiting service by itself. */ - private boolean mOemHandlesTerminalBasedCallWaiting = false; + /** true if Ims service handles the terminal-based service by itself. */ + private boolean mOemHandlesTerminalBasedService = false; private boolean mSupportsTerminalBasedCallWaiting = false; + private boolean mSupportsTerminalBasedClir = false; public SsDomainController(GsmCdmaPhone phone) { mPhone = phone; @@ -221,16 +222,19 @@ public class SsDomainController { mUtAvailableWhenRoaming = availableWhenRoaming; mSupportsTerminalBasedCallWaiting = false; + mSupportsTerminalBasedClir = false; if (tbServices != null) { for (int tbService : tbServices) { if (tbService == SUPPLEMENTARY_SERVICE_CW) { mSupportsTerminalBasedCallWaiting = true; - break; + } + if (tbService == SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR) { + mSupportsTerminalBasedClir = true; } } } - logi("updateSsOverUtConfig terminal-based cw " - + mSupportsTerminalBasedCallWaiting); + logi("updateSsOverUtConfig terminal-based cw=" + mSupportsTerminalBasedCallWaiting + + ", clir=" + mSupportsTerminalBasedClir); mCbOverUtSupported.clear(); mCfOverUtSupported.clear(); @@ -535,8 +539,9 @@ public class SsDomainController { * Only for ImsPhoneMmiCode. */ public SuppServiceRoutingInfo getSuppServiceRoutingInfoForSs(String service) { - if (SS_CW.equals(service) && getOemHandlesTerminalBasedCallWaiting()) { - // Ims service handles the terminal based call waiting service by itself. + if ((SS_CW.equals(service) && getOemHandlesTerminalBasedCallWaiting()) + || (SS_CLIR.equals(service) && getOemHandlesTerminalBasedClir())) { + // Ims service handles the terminal based service by itself. // Use legacy implementation. Forward the request to Ims service if Ut is available. Phone imsPhone = mPhone.getImsPhone(); boolean isUtEnabled = (imsPhone != null) && imsPhone.isUtEnabled(); @@ -575,12 +580,12 @@ public class SsDomainController { } /** - * @param state true if Ims service handles the terminal-based call waiting service by itself. + * @param state true if Ims service handles the terminal-based service by itself. * Otherwise, false. */ - public void setOemHandlesTerminalBasedCallWaiting(boolean state) { - logi("setOemHandlesTerminalBasedCallWaiting " + state); - mOemHandlesTerminalBasedCallWaiting = state; + public void setOemHandlesTerminalBasedService(boolean state) { + logi("setOemHandlesTerminalBasedService " + state); + mOemHandlesTerminalBasedService = state; } /** @@ -589,8 +594,18 @@ public class SsDomainController { */ public boolean getOemHandlesTerminalBasedCallWaiting() { logi("getOemHandlesTerminalBasedCallWaiting " - + mSupportsTerminalBasedCallWaiting + ", " + mOemHandlesTerminalBasedCallWaiting); - return mSupportsTerminalBasedCallWaiting && mOemHandlesTerminalBasedCallWaiting; + + mSupportsTerminalBasedCallWaiting + ", " + mOemHandlesTerminalBasedService); + return mSupportsTerminalBasedCallWaiting && mOemHandlesTerminalBasedService; + } + + /** + * Returns whether the carrier supports the terminal-based CLIR + * and Ims service handles it by itself. + */ + public boolean getOemHandlesTerminalBasedClir() { + logi("getOemHandlesTerminalBasedClir " + + mSupportsTerminalBasedClir + ", " + mOemHandlesTerminalBasedService); + return mSupportsTerminalBasedClir && mOemHandlesTerminalBasedService; } /** @@ -610,8 +625,9 @@ public class SsDomainController { pw.println(" mUtAvailableWhenRoaming=" + mUtAvailableWhenRoaming); pw.println(" mUtAvailableRats=" + mUtAvailableRats); pw.println(" mWiFiAvailable=" + mWiFiAvailable); - pw.println(" mOemHandlesTerminalBasedCallWaiting=" + mOemHandlesTerminalBasedCallWaiting); + pw.println(" mOemHandlesTerminalBasedService=" + mOemHandlesTerminalBasedService); pw.println(" mSupportsTerminalBasedCallWaiting=" + mSupportsTerminalBasedCallWaiting); + pw.println(" mSupportsTerminalBasedClir=" + mSupportsTerminalBasedClir); pw.decreaseIndent(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 074c6237d8..02ef15ca84 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.CLIR_SUPPRESSION; import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED; import static com.android.internal.telephony.Phone.EVENT_SRVCC_STATE_CHANGED; import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED; @@ -2206,4 +2207,32 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); verify(mImsPhone, times(1)).setCallWaiting(eq(false), any()); } + + @Test + @SmallTest + public void testOemHandlesTerminalBasedClir() throws Exception { + doReturn(true).when(mImsPhone).isUtEnabled(); + replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); + + // Ut is disabled in config + doReturn(false).when(mSsDomainController).useSsOverUt(anyString()); + doReturn(false).when(mSsDomainController).getOemHandlesTerminalBasedClir(); + + replaceInstance(GsmCdmaPhone.class, "mSsDomainController", mPhoneUT, mSsDomainController); + + mPhoneUT.getOutgoingCallerIdDisplay(null); + verify(mImsPhone, times(0)).getOutgoingCallerIdDisplay(any()); + + mPhoneUT.setOutgoingCallerIdDisplay(CLIR_SUPPRESSION, null); + verify(mImsPhone, times(0)).setOutgoingCallerIdDisplay(anyInt(), any()); + + // OEM handles the terminal-based CLIR by itself. + doReturn(true).when(mSsDomainController).getOemHandlesTerminalBasedClir(); + + mPhoneUT.getOutgoingCallerIdDisplay(null); + verify(mImsPhone, times(1)).getOutgoingCallerIdDisplay(any()); + + mPhoneUT.setOutgoingCallerIdDisplay(CLIR_SUPPRESSION, null); + verify(mImsPhone, times(1)).setOutgoingCallerIdDisplay(eq(CLIR_SUPPRESSION), any()); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java index a0867fd4f7..82dba86379 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java @@ -440,19 +440,54 @@ public class SsDomainControllerTest extends TelephonyTest { new int[] {}, UT_OVER_ALL, new int[] { SUPPLEMENTARY_SERVICE_CW }); String sc = mServices.get(SS_CW); - mSdc.setOemHandlesTerminalBasedCallWaiting(false); + mSdc.setOemHandlesTerminalBasedService(false); SsDomainController.SuppServiceRoutingInfo ssCode = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); assertNotNull(ssCode); assertFalse(ssCode.useSsOverUt()); - mSdc.setOemHandlesTerminalBasedCallWaiting(true); + mSdc.setOemHandlesTerminalBasedService(true); ssCode = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); assertNotNull(ssCode); assertTrue(ssCode.useSsOverUt()); } + @Test + @SmallTest + public void testOemHandlesTerminalBasedClir() { + setUtEnabled(); + + // Enable terminal-based CLIR + mSdc.updateCarrierConfigForTest(true, true, false, true, true, + new int[] {}, UT_OVER_ALL, new int[] { SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR }); + String sc = mServices.get(SS_CLIR); + + mSdc.setOemHandlesTerminalBasedService(false); + SsDomainController.SuppServiceRoutingInfo ssCode = + ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); + + assertNotNull(ssCode); + assertFalse(ssCode.useSsOverUt()); + assertFalse(mSdc.getOemHandlesTerminalBasedClir()); + + mSdc.setOemHandlesTerminalBasedService(true); + ssCode = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); + + assertNotNull(ssCode); + assertTrue(ssCode.useSsOverUt()); + assertTrue(mSdc.getOemHandlesTerminalBasedClir()); + + // Disable terminal-based CLIR + mSdc.updateCarrierConfigForTest(true, true, false, true, true, + new int[] {}, UT_OVER_ALL, new int[] {}); + ssCode = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); + + assertNotNull(ssCode); + assertFalse(ssCode.useSsOverUt()); + assertFalse(mSdc.getOemHandlesTerminalBasedClir()); + } + private void setUtEnabled() { doReturn(0).when(mImsPhone).getSubId(); mSdc.updateWifiForUt(false); -- GitLab From 6a5c8687ba2e68325ccf49d8a6915714b641a9f8 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Tue, 28 Jun 2022 07:50:04 +0000 Subject: [PATCH 049/656] preventing least priority error log to print repeatedly Bug: 188387699 Test: Manual Verification done Change-Id: I18d437ff0daf6d7a5bc21ff4bda729b2c18c8be0 --- .../com/android/internal/telephony/PhoneSubInfoController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java index b4c3379575..5228ad5e7e 100644 --- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java +++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java @@ -493,7 +493,7 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { if (phone != null) { return callMethodHelper.callMethod(phone); } else { - loge(message + " phone is null for Subscription:" + subId); + if (VDBG) loge(message + " phone is null for Subscription:" + subId); return null; } } finally { -- GitLab From 30a88dcca806cf4594b7e142e21745ac6e5d21d3 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Fri, 8 Jul 2022 04:40:18 +0000 Subject: [PATCH 050/656] Added string token to CARD support multiple languages Bug: 138549076 Test: Manual Verification done Change-Id: Ic3639c181b09562492e16e6c3dd04ab40a6f740b --- .../internal/telephony/SubscriptionController.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 46684624f9..83beb04dee 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -34,6 +34,7 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; @@ -71,6 +72,7 @@ import android.util.LocalLog; import android.util.Log; import com.android.ims.ImsManager; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.data.DataEnabledOverride; @@ -1547,9 +1549,9 @@ public class SubscriptionController extends ISub.Stub { if (!TextUtils.isEmpty(simCarrierName)) { nameToSet = simCarrierName; } else { - nameToSet = "CARD " + Integer.toString(slotIndex + 1); + Resources r = Resources.getSystem(); + nameToSet = r.getString(R.string.default_card_name, (slotIndex + 1)); } - ContentValues value = new ContentValues(); value.put(SubscriptionManager.DISPLAY_NAME, nameToSet); resolver.update(SubscriptionManager.getUriForSubscriptionId(subId), value, @@ -2019,7 +2021,9 @@ public class SubscriptionController extends ISub.Stub { if (TextUtils.isEmpty(nameToSet)) { if (nameSource == SubscriptionManager.NAME_SOURCE_USER_INPUT && SubscriptionManager.isValidSlotIndex(getSlotIndex(subId))) { - nameToSet = "CARD " + (getSlotIndex(subId) + 1); + Resources r = Resources.getSystem(); + nameToSet = r.getString(R.string.default_card_name, + (getSlotIndex(subId) + 1)); } else { nameToSet = mContext.getString(SubscriptionManager.DEFAULT_NAME_RES); } -- GitLab From 7223a12a2faf791c0357184c6f4ef7d23b835fd4 Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Fri, 8 Jul 2022 09:20:37 -0700 Subject: [PATCH 051/656] UT update for PhoneNumberWatcher add assert checks to make sure multiple tts spans are not added Bug: 237511525 Test: atest Change-Id: Ibf1aced144d42cb19e71065c51be3dd3e45812d1 --- .../telephony/PhoneNumberWatcherTest.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java index 8f9757109b..c10dea904e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java @@ -23,7 +23,7 @@ import android.text.Editable; import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.TextWatcher; - +import android.text.style.TtsSpan; import org.junit.Ignore; import org.junit.Test; @@ -42,6 +42,8 @@ public class PhoneNumberWatcherTest { textWatcher.afterTextChanged(number); assertEquals(formatted1, number.toString()); assertEquals(formatted1.length(), Selection.getSelectionEnd(number)); + assertSingleTtsSpan(number); + // Append one chars final char appendChar = '6'; final String formatted2 = "(650) 123-456"; @@ -53,6 +55,13 @@ public class PhoneNumberWatcherTest { textWatcher.afterTextChanged(number); assertEquals(formatted2, number.toString()); assertEquals(formatted2.length(), Selection.getSelectionEnd(number)); + assertSingleTtsSpan(number); + } + + private void assertSingleTtsSpan(Editable s) + { + int numTtsSpans = (s.getSpans(0, s.length(), TtsSpan.class)).length; + assertEquals(1, numTtsSpans); } @Test @SmallTest @@ -70,6 +79,8 @@ public class PhoneNumberWatcherTest { textWatcher.afterTextChanged(number); assertEquals(result1, number.toString()); assertEquals(result1.length(), Selection.getSelectionEnd(number)); + assertSingleTtsSpan(number); + // Remove last 5 chars final String result2 = "650-123"; textWatcher.beforeTextChanged(number, number.length() - 4, 4, 0); @@ -79,6 +90,7 @@ public class PhoneNumberWatcherTest { textWatcher.afterTextChanged(number); assertEquals(result2, number.toString()); assertEquals(result2.length(), Selection.getSelectionEnd(number)); + assertSingleTtsSpan(number); } @Test @SmallTest @@ -97,6 +109,7 @@ public class PhoneNumberWatcherTest { assertEquals(expected1, number.toString()); // the cursor should still at the right of '1' assertEquals(5, Selection.getSelectionEnd(number)); + assertSingleTtsSpan(number); // Insert multiple chars final String expected2 = "(650) 145-6723"; @@ -108,6 +121,7 @@ public class PhoneNumberWatcherTest { assertEquals(expected2, number.toString()); // the cursor should be still at the right of '7' assertEquals(12, Selection.getSelectionEnd(number)); + assertSingleTtsSpan(number); } @Test @SmallTest @@ -188,6 +202,7 @@ public class PhoneNumberWatcherTest { assertEquals(expected2, number.toString()); // the cursor should still at the right of '4' assertEquals(expected2.length(), Selection.getSelectionEnd(number)); + assertSingleTtsSpan(number); } @Test @SmallTest -- GitLab From 83c2ecbd706b854d6ac59a2f9e1b58459baf27c8 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Sun, 20 Mar 2022 02:18:22 +0000 Subject: [PATCH 052/656] Fetches sim service table from the EF_SST elementary file of the sim Bug: 217794026 Test: Atest Verification completed Change-Id: I2445a8a419cc5abf9c602e1cd25536cc681604a6 --- .../telephony/PhoneSubInfoController.java | 24 +++++ .../telephony/uicc/IsimServiceTable.java | 56 +++++++++++ .../telephony/uicc/IsimUiccRecords.java | 15 ++- .../internal/telephony/uicc/SIMRecords.java | 14 ++- .../telephony/uicc/UsimServiceTable.java | 4 + .../telephony/PhoneSubInfoControllerTest.java | 95 ++++++++++++++++++- .../telephony/uicc/IsimUiccRecordsTest.java | 75 ++++++++++++++- .../telephony/uicc/SIMRecordsTest.java | 50 +++++++++- 8 files changed, 328 insertions(+), 5 deletions(-) create mode 100644 src/java/com/android/internal/telephony/uicc/IsimServiceTable.java diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java index b4c3379575..d58d77c63f 100644 --- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java +++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java @@ -39,6 +39,7 @@ import android.telephony.TelephonyFrameworkInitializer; import android.util.EventLog; import com.android.internal.telephony.uicc.IsimRecords; +import com.android.internal.telephony.uicc.SIMRecords; import com.android.internal.telephony.uicc.UiccCardApplication; import com.android.internal.telephony.uicc.UiccPort; import com.android.telephony.Rlog; @@ -418,6 +419,29 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { }); } + /** + * Returns the USIM service table that fetched from EFUST elementary field that are loaded + * based on the appType. + */ + public String getSimServiceTable(int subId, int appType) throws RemoteException { + return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getSimServiceTable", + (phone) -> { + UiccPort uiccPort = phone.getUiccPort(); + if (uiccPort == null || uiccPort.getUiccProfile() == null) { + loge("getSimServiceTable(): uiccPort or uiccProfile is null"); + return null; + } + UiccCardApplication uiccApp = uiccPort.getUiccProfile().getApplicationByType( + appType); + if (uiccApp == null) { + loge("getSimServiceTable(): no app with specified apptype=" + + appType); + return null; + } + return ((SIMRecords)uiccApp.getIccRecords()).getSimServiceTable(); + }); + } + @Override public String getIccSimChallengeResponse(int subId, int appType, int authType, String data, String callingPackage, String callingFeatureId) throws RemoteException { diff --git a/src/java/com/android/internal/telephony/uicc/IsimServiceTable.java b/src/java/com/android/internal/telephony/uicc/IsimServiceTable.java new file mode 100644 index 0000000000..289229cc90 --- /dev/null +++ b/src/java/com/android/internal/telephony/uicc/IsimServiceTable.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 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.uicc; + +public final class IsimServiceTable extends IccServiceTable { + private static final String TAG = "IsimServiceTable"; + public enum IsimService { + PCSCF_ADDRESS, + GBA, // Generic Bootstrapping Architecture (GBA) + HTTP_DIGEST, + GBA_LOCALKEY_ESTABLISHMENT, // GBA-based Local Key Establishment Mechanism + PCSCF_DISCOVERY_FOR_IMS, // Support of P-CSCF discovery for IMS Local Break Out + SMS, + SMSR, // Short Message Status Reports + SM_OVERIP_AND_DATA_DL_VIA_SMS_PP, // Support for SM-over-IP including data download via + // SMS-PP + COMMUNICATION_CONTROL_FOR_IMS_BY_ISIM, + UICC_ACCESS_TO_IMS + } + + public IsimServiceTable(byte[] table) { + super(table); + } + + public boolean isAvailable(IsimService service) { + return super.isAvailable(service.ordinal()); + } + + @Override + protected String getTag() { + return TAG; + } + + @Override + protected Object[] getValues() { + return IsimService.values(); + } + + public byte[] getISIMServiceTable() { + return mServiceTable; + } +} diff --git a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java index 7cd59c74ea..b2206efe13 100644 --- a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java @@ -225,6 +225,11 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { } } + @VisibleForTesting + public EfIsimIstLoaded getIsimIstObject() { + return new EfIsimIstLoaded(); + } + private class EfIsimSmssLoaded implements IccRecords.IccRecordLoaded { @Override @@ -484,11 +489,11 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { pw.println("IsimRecords: " + this); pw.println(" extends:"); super.dump(fd, pw, args); + pw.println(" mIsimServiceTable=" + getIsimServiceTable()); if (DUMP_RECORDS) { pw.println(" mIsimImpi=" + mIsimImpi); pw.println(" mIsimDomain=" + mIsimDomain); pw.println(" mIsimImpu[]=" + Arrays.toString(mIsimImpu)); - pw.println(" mIsimIst" + mIsimIst); pw.println(" mIsimPcscf" + mIsimPcscf); pw.println(" mPsismsc=" + mPsiSmsc); pw.println(" mSmss TPMR=" + getSmssTpmrValue()); @@ -496,6 +501,14 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { pw.flush(); } + // Just to return the Enums of service table to print in DUMP + private IsimServiceTable getIsimServiceTable() { + if (mIsimIst != null) { + byte[] istTable = IccUtils.hexStringToBytes(mIsimIst); + return new IsimServiceTable(istTable); + } + return null; + } @Override public int getVoiceMessageCount() { return 0; // Not applicable to Isim diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index f84cf8a8bc..39336c6c0c 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -167,7 +167,7 @@ public class SIMRecords extends IccRecords { private static final int EVENT_UPDATE_DONE = 14 + SIM_RECORD_EVENT_BASE; protected static final int EVENT_GET_PNN_DONE = 15 + SIM_RECORD_EVENT_BASE; protected static final int EVENT_GET_OPL_DONE = 16 + SIM_RECORD_EVENT_BASE; - private static final int EVENT_GET_SST_DONE = 17 + SIM_RECORD_EVENT_BASE; + protected static final int EVENT_GET_SST_DONE = 17 + SIM_RECORD_EVENT_BASE; private static final int EVENT_GET_ALL_SMS_DONE = 18 + SIM_RECORD_EVENT_BASE; private static final int EVENT_MARK_SMS_READ_DONE = 19 + SIM_RECORD_EVENT_BASE; private static final int EVENT_SET_MBDN_DONE = 20 + SIM_RECORD_EVENT_BASE; @@ -279,6 +279,18 @@ public class SIMRecords extends IccRecords { return mUsimServiceTable; } + /** + * Fetches the USIM service table from UsimServiceTable + * + * @return HexString representation of USIM service table + */ + public String getSimServiceTable() { + if (mUsimServiceTable != null) { + return IccUtils.bytesToHexString(mUsimServiceTable.getUSIMServiceTable()); + } + return null; + } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int getExtFromEf(int ef) { int ext; diff --git a/src/java/com/android/internal/telephony/uicc/UsimServiceTable.java b/src/java/com/android/internal/telephony/uicc/UsimServiceTable.java index fc58d3cec3..ea2bf42dce 100644 --- a/src/java/com/android/internal/telephony/uicc/UsimServiceTable.java +++ b/src/java/com/android/internal/telephony/uicc/UsimServiceTable.java @@ -157,4 +157,8 @@ public final class UsimServiceTable extends IccServiceTable { protected Object[] getValues() { return UsimService.values(); } + + public byte[] getUSIMServiceTable() { + return mServiceTable; + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java index a9b4ae7ba8..5eaead53ff 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java @@ -1072,4 +1072,97 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { e.printStackTrace(); } } -} + + @Test + public void testGetSimServiceTable() throws RemoteException { + String refSst = "1234567"; + doReturn(mUiccPort).when(mPhone).getUiccPort(); + doReturn(mUiccProfile).when(mUiccPort).getUiccProfile(); + doReturn(mUiccCardApplicationIms).when(mUiccProfile).getApplicationByType(anyInt()); + doReturn(mSimRecords).when(mUiccCardApplicationIms).getIccRecords(); + + doReturn(refSst).when(mSimRecords).getSimServiceTable(); + + String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt()); + assertEquals(refSst, resultSst); + } + + @Test + public void testGetSimServiceTableEmpty() throws RemoteException { + String refSst = null; + doReturn(mUiccPort).when(mPhone).getUiccPort(); + doReturn(mUiccProfile).when(mUiccPort).getUiccProfile(); + doReturn(mUiccCardApplicationIms).when(mUiccProfile).getApplicationByType(anyInt()); + doReturn(mSimRecords).when(mUiccCardApplicationIms).getIccRecords(); + + doReturn(refSst).when(mSimRecords).getSimServiceTable(); + + String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt()); + assertEquals(refSst, resultSst); + } + + @Test + public void testGetSstWhenNoUiccPort() throws RemoteException { + String refSst = "1234567"; + doReturn(null).when(mPhone).getUiccPort(); + doReturn(mUiccProfile).when(mUiccPort).getUiccProfile(); + doReturn(mUiccCardApplicationIms).when(mUiccProfile).getApplicationByType(anyInt()); + doReturn(mSimRecords).when(mUiccCardApplicationIms).getIccRecords(); + + doReturn(refSst).when(mSimRecords).getSimServiceTable(); + + String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt()); + assertEquals(null, resultSst); + } + + @Test + public void testGetSstWhenNoUiccProfile() throws RemoteException { + String refSst = "1234567"; + doReturn(mUiccPort).when(mPhone).getUiccPort(); + doReturn(null).when(mUiccPort).getUiccProfile(); + doReturn(mUiccCardApplicationIms).when(mUiccProfile).getApplicationByType(anyInt()); + doReturn(mSimRecords).when(mUiccCardApplicationIms).getIccRecords(); + + doReturn(refSst).when(mSimRecords).getSimServiceTable(); + + String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt()); + assertEquals(null, resultSst); + } + + @Test + public void testGetSstWhenNoUiccApplication() throws RemoteException { + String refSst = "1234567"; + doReturn(mUiccPort).when(mPhone).getUiccPort(); + doReturn(mUiccProfile).when(mUiccPort).getUiccProfile(); + doReturn(null).when(mUiccProfile).getApplicationByType(anyInt()); + doReturn(mSimRecords).when(mUiccCardApplicationIms).getIccRecords(); + + doReturn(refSst).when(mSimRecords).getSimServiceTable(); + + String resultSst = mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt()); + assertEquals(null, resultSst); + } + + @Test + public void testGetSimServiceTableWithOutPermissions() throws RemoteException { + String refSst = "1234567"; + doReturn(mUiccPort).when(mPhone).getUiccPort(); + doReturn(mUiccProfile).when(mUiccPort).getUiccProfile(); + doReturn(mUiccCardApplicationIms).when(mUiccProfile).getApplicationByType(anyInt()); + doReturn(mSimRecords).when(mUiccCardApplicationIms).getIccRecords(); + + doReturn(refSst).when(mSimRecords).getSimServiceTable(); + + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); + try { + mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt()); + Assert.fail("expected Security Exception Thrown"); + } catch (Exception ex) { + assertTrue(ex instanceof SecurityException); + assertTrue(ex.getMessage().contains("getSimServiceTable")); + } + + mContextFixture.addCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE); + assertEquals(refSst, mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt())); + } +} \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java index 8324a5b274..6f4666ccf1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IsimUiccRecordsTest.java @@ -303,4 +303,77 @@ public class IsimUiccRecordsTest extends TelephonyTest { assertTrue(((CommandException) ar.exception).getCommandError() == CommandException.Error.OPERATION_NOT_ALLOWED); } -} + + @Test + public void testGetSimServiceTable() { + // reading sim service table successfully case + byte[] sst = new byte[9]; + for (int i = 0; i < sst.length; i++) { + if (i % 2 == 0) { + sst[i] = 0; + } else { + sst[i] = 1; + } + } + Message message = mIsimUiccRecordsUT.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecordsUT.getIsimIstObject()); + AsyncResult ar = AsyncResult.forMessage(message, sst, null); + mIsimUiccRecordsUT.handleMessage(message); + String mockSst = IccUtils.bytesToHexString(sst); + String resultSst = mIsimUiccRecordsUT.getIsimIst(); + assertEquals(mockSst, resultSst); + } + + @Test + public void testGetSimServiceTableException() { + // sim service table exception handling case + Message message = mIsimUiccRecordsUT.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecordsUT.getIsimIstObject()); + AsyncResult ar = AsyncResult.forMessage(message, null, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + mIsimUiccRecordsUT.handleMessage(message); + String resultSst = mIsimUiccRecordsUT.getIsimIst(); + assertEquals(null, resultSst); + } + + @Test + public void testGetSsimServiceTableLessTableSize() { + // The less IST table size will not give any problem + byte[] sst = new byte[5]; + for (int i = 0; i < sst.length; i++) { + if (i % 2 == 0) { + sst[i] = 0; + } else { + sst[i] = 1; + } + } + Message message = mIsimUiccRecordsUT.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecordsUT.getIsimIstObject()); + AsyncResult ar = AsyncResult.forMessage(message, sst, null); + mIsimUiccRecordsUT.handleMessage(message); + String mockSst = IccUtils.bytesToHexString(sst); + String resultSst = mIsimUiccRecordsUT.getIsimIst(); + assertEquals(mockSst, resultSst); + } + + @Test + public void testGetSsimServiceTableLargeTableSize() { + // The Big IST table size will not give any problem [ in feature the table may grows] + byte[] sst = new byte[99]; + for (int i = 0; i < sst.length; i++) { + if (i % 2 == 0) { + sst[i] = 0; + } else { + sst[i] = 1; + } + } + Message message = mIsimUiccRecordsUT.obtainMessage( + IccRecords.EVENT_GET_ICC_RECORD_DONE, mIsimUiccRecordsUT.getIsimIstObject()); + AsyncResult ar = AsyncResult.forMessage(message, sst, null); + mIsimUiccRecordsUT.handleMessage(message); + String mockSst = IccUtils.bytesToHexString(sst); + String resultSst = mIsimUiccRecordsUT.getIsimIst(); + assertEquals(mockSst, resultSst); + } + +} \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java index 3d6f7700d6..90349dad05 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java @@ -597,7 +597,6 @@ public class SIMRecordsTest extends TelephonyTest { data[5] = (byte) (lacTacEnd >>> 8); data[6] = (byte) lacTacEnd; data[7] = (byte) pnnIndex; - return data; } @@ -668,4 +667,53 @@ public class SIMRecordsTest extends TelephonyTest { assertEquals(null, mSIMRecordsUT.getSmscIdentity()); assertTrue(ar.exception instanceof CommandException); } + + @Test + public void testGetSimServiceTable() { + // reading sim service table successfully case + byte[] sst = new byte[111]; + for (int i = 0; i < sst.length; i++) { + if (i % 2 == 0) { + sst[i] = 0; + } else { + sst[i] = 1; + } + } + Message message = mSIMRecordsUT.obtainMessage(SIMRecords.EVENT_GET_SST_DONE); + AsyncResult ar = AsyncResult.forMessage(message, sst, null); + mSIMRecordsUT.handleMessage(message); + String mockSst = IccUtils.bytesToHexString(sst); + String resultSst = mSIMRecordsUT.getSimServiceTable(); + assertEquals(mockSst, resultSst); + } + + @Test + public void testGetSimServiceTableException() { + // sim service table exception handling case + Message message = mSIMRecordsUT.obtainMessage(SIMRecords.EVENT_GET_SST_DONE); + AsyncResult ar = AsyncResult.forMessage(message, null, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + mSIMRecordsUT.handleMessage(message); + String resultSst = mSIMRecordsUT.getSimServiceTable(); + assertEquals(null, resultSst); + } + + @Test + public void testGetSsimServiceTableLessTableSize() { + // sim service table reading case + byte[] sst = new byte[12]; + for (int i = 0; i < sst.length; i++) { + if (i % 2 == 0) { + sst[i] = 0; + } else { + sst[i] = 1; + } + } + Message message = mSIMRecordsUT.obtainMessage(SIMRecords.EVENT_GET_SST_DONE); + AsyncResult ar = AsyncResult.forMessage(message, sst, null); + mSIMRecordsUT.handleMessage(message); + String mockSst = IccUtils.bytesToHexString(sst); + String resultSst = mSIMRecordsUT.getSimServiceTable(); + assertEquals(mockSst, resultSst); + } } -- GitLab From 11bcde08570ca8b158ba1e784f3efa4356def776 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Mon, 11 Jul 2022 22:15:01 +0000 Subject: [PATCH 053/656] Added unit tests for FDN changes. Bug: 218262162 Test: Manual atest com.android.internal.telephony.SmsControllerTest atest com.android.internal.telephony.GsmCdmaPhoneTest Change-Id: I678d5d8b1287e1fdeab88294eb093ea571865632 --- .../internal/telephony/SmsController.java | 7 +- .../internal/telephony/GsmCdmaPhoneTest.java | 37 ++++ .../internal/telephony/SmsControllerTest.java | 168 ++++++++++++++++++ 3 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index d157246a62..8d58895411 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -40,6 +40,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -57,7 +58,8 @@ public class SmsController extends ISmsImplBase { private final Context mContext; - protected SmsController(Context context) { + @VisibleForTesting + public SmsController(Context context) { mContext = context; ServiceRegisterer smsServiceRegisterer = TelephonyFrameworkInitializer .getTelephonyServiceManager() @@ -900,7 +902,8 @@ public class SmsController extends ISmsImplBase { * @param destAddr destination address of the message * @return true if either destAddr or smscAddr is blocked due to FDN. */ - private boolean isNumberBlockedByFDN(int subId, String destAddr, String callingPackage) { + @VisibleForTesting + public boolean isNumberBlockedByFDN(int subId, String destAddr, String callingPackage) { int phoneId = SubscriptionManager.getPhoneId(subId); if (!FdnUtils.isFdnEnabled(phoneId)) { return false; diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 02ef15ca84..091df19528 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -2028,6 +2028,43 @@ public class GsmCdmaPhoneTest extends TelephonyTest { fdnCheckCleanup(); } + @Test + public void testDial_fdnCheck() throws Exception{ + // dial setup + mSST.mSS = mServiceState; + doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState(); + mCT.mForegroundCall = mGsmCdmaCall; + mCT.mBackgroundCall = mGsmCdmaCall; + mCT.mRingingCall = mGsmCdmaCall; + doReturn(GsmCdmaCall.State.IDLE).when(mGsmCdmaCall).getState(); + replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); + + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(adnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + + // FDN check success - no exception is returned + AdnRecord dialRecord = new AdnRecord(null, "1234567890"); + fdnList.add(0, dialRecord); + Connection connection = mPhoneUT.dial("1234567890", + new PhoneInternalInterface.DialArgs.Builder().build()); + verify(mCT).dialGsm(eq("1234567890"), any(PhoneInternalInterface.DialArgs.class)); + + // FDN check failure - returns CallStateException + fdnList.remove(0); + try { + connection = mPhoneUT.dial("1234567890", + new PhoneInternalInterface.DialArgs.Builder().build()); + fail("Expected CallStateException with ERROR_FDN_BLOCKED thrown."); + } catch(CallStateException e) { + assertEquals(CallStateException.ERROR_FDN_BLOCKED, e.getError()); + } + + // clean up + fdnCheckCleanup(); + } + public void fdnCheckCleanup() { doReturn(false).when(mUiccCardApplication3gpp).getIccFdnAvailable(); doReturn(false).when(mUiccCardApplication3gpp).getIccFdnEnabled(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java new file mode 100644 index 0000000000..9d7079454d --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2022 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; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.uicc.AdnRecord; +import com.android.internal.telephony.uicc.AdnRecordCache; +import com.android.internal.telephony.uicc.IccConstants; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doReturn; + +import java.util.ArrayList; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class SmsControllerTest extends TelephonyTest { + + // Mocked classes + private AdnRecordCache mAdnRecordCache; + + // SmsController under test + private SmsController mSmsControllerUT; + private final String smscAddrStr = "+1206313004"; + private String mCallingPackage; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + mAdnRecordCache = Mockito.mock(AdnRecordCache.class); + mSmsControllerUT = new SmsController(mContext); + mCallingPackage = mContext.getOpPackageName(); + } + + @After + public void tearDown() throws Exception { + mAdnRecordCache = null; + super.tearDown(); + } + + private void fdnCheckSetup() { + // FDN check setup + doReturn(mAdnRecordCache).when(mSimRecords).getAdnCache(); + doReturn(mUiccProfile).when(mUiccController).getUiccProfileForPhone(anyInt()); + doReturn(true).when(mUiccCardApplication3gpp).getIccFdnAvailable(); + doReturn(true).when(mUiccCardApplication3gpp).getIccFdnEnabled(); + doReturn(false).when(mTelephonyManager).isEmergencyNumber(anyString()); + doReturn("us").when(mTelephonyManager).getSimCountryIso(); + doReturn(smscAddrStr).when(mIccSmsInterfaceManager).getSmscAddressFromIccEf(anyString()); + } + + private void fdnCheckCleanup() { + doReturn(false).when(mUiccCardApplication3gpp).getIccFdnAvailable(); + doReturn(false).when(mUiccCardApplication3gpp).getIccFdnEnabled(); + } + + @Test + public void isNumberBlockedByFdn_fdnListHasBothDestAddrAndSmscAddr() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(mAdnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + + // FDN list has both destination addr and smsc addr + AdnRecord smscAddrRecord = new AdnRecord(null, smscAddrStr); + AdnRecord destAddrRecord = new AdnRecord(null, "1234"); + fdnList.add(0, smscAddrRecord); + fdnList.add(1, destAddrRecord); + + // Returns false as list contains both dest addr and smsc addr + assertFalse(mSmsControllerUT.isNumberBlockedByFDN(1, "1234", + mCallingPackage)); + + // Clean up + fdnCheckCleanup(); + } + + @Test + public void isNumberBlockedByFdn_fdnListHasDestAddr() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(mAdnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + + // FDN list has only destination addr + AdnRecord destAddrRecord = new AdnRecord(null, "1234"); + fdnList.add(0, destAddrRecord); + + // Returns true as list does not contain smsc addr + assertTrue(mSmsControllerUT.isNumberBlockedByFDN(1, "1234", mCallingPackage)); + + // Clean up + fdnCheckCleanup(); + } + + @Test + public void isNumberBlockedByFdn_fdnListHasSmscAddr() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(mAdnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + + // FDN list has both destination addr and smsc addr + AdnRecord smscAddrRecord = new AdnRecord(null, smscAddrStr); + fdnList.add(0, smscAddrRecord); + + // Returns true as list does not contain dest addr + assertTrue(mSmsControllerUT.isNumberBlockedByFDN(1, "1234", mCallingPackage)); + + // Clean up + fdnCheckCleanup(); + } + + @Test + public void isNumberBlockedByFdn_destAddrIsEmergencyNumber() { + // FDN check setup + fdnCheckSetup(); + ArrayList fdnList = new ArrayList<>(); + doReturn(fdnList).when(mAdnRecordCache).getRecordsIfLoaded(IccConstants.EF_FDN); + + doReturn(true).when(mTelephonyManager).isEmergencyNumber(anyString()); + // Returns false as dest addr is emergency number + assertFalse(mSmsControllerUT.isNumberBlockedByFDN(1, "1234", + mCallingPackage)); + + // Clean up + fdnCheckCleanup(); + } + + @Test + public void isNumberBlockedByFdn_fdnDisabled() { + // FDN check setup + fdnCheckSetup(); + + doReturn(false).when(mUiccCardApplication3gpp).getIccFdnEnabled(); + // Returns false as fdn is not enabled + assertFalse(mSmsControllerUT.isNumberBlockedByFDN(1, "1234", + mCallingPackage)); + + // Clean up + fdnCheckCleanup(); + } +} \ No newline at end of file -- GitLab From 4aebb67154bfe0ff8c6513718f24d82f88b8d70c Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Mon, 23 May 2022 17:37:32 +0000 Subject: [PATCH 054/656] Prevent VVM from sending SMS in ECBM Sending non-emergency SMS would exit ECBM mode. Visual voice mail internally uses SMS for activation, deactivation, status check etc. So, these actions are silently blocked when phone in in ECBM. Bug: 177439988 Test: Sanity, atest com.android.internal.telephony.SmsControllerTest Change-Id: Icfb050d8ba7daf9f4f37b51705fcab769f4c8823 --- .../internal/telephony/SmsController.java | 7 +++++ .../internal/telephony/SmsControllerTest.java | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 8d58895411..774d549058 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -753,6 +753,13 @@ public class SmsController extends ISmsImplBase { public void sendVisualVoicemailSmsForSubscriber(String callingPackage, String callingAttributionTag, int subId, String number, int port, String text, PendingIntent sentIntent) { + // Do not send non-emergency SMS in ECBM as it forces device to exit ECBM. + if(getPhone(subId).isInEcm()) { + Rlog.d(LOG_TAG, "sendVisualVoicemailSmsForSubscriber: Do not send non-emergency " + + "SMS in ECBM as it forces device to exit ECBM."); + return; + } + if (port == 0) { sendTextForSubscriberWithSelfPermissionsInternal(subId, callingPackage, callingAttributionTag, number, null, text, sentIntent, null, false, diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java index 9d7079454d..54d34d4755 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java @@ -31,9 +31,14 @@ import org.mockito.Mockito; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + import java.util.ArrayList; @@ -165,4 +170,26 @@ public class SmsControllerTest extends TelephonyTest { // Clean up fdnCheckCleanup(); } + + @Test + public void sendVisualVoicemailSmsForSubscriber_phoneIsNotInEcm() { + assertFalse(mPhone.isInEcm()); + + mSmsControllerUT.sendVisualVoicemailSmsForSubscriber(mCallingPackage,null , + 1, null, 0, null, null); + verify(mIccSmsInterfaceManager).sendTextWithSelfPermissions(any(), + any(), any(), any(), any(), any(), any(), eq(false), eq(true)); + } + + @Test + public void sendVisualVoicemailSmsForSubscriber_phoneIsInEcm() { + doReturn(true).when(mPhone).isInEcm(); + + mSmsControllerUT.sendVisualVoicemailSmsForSubscriber(mCallingPackage,null , + 1, null, 0, null, null); + verify(mIccSmsInterfaceManager, never()).sendTextWithSelfPermissions(any(), + any(), any(), any(), any(), any(), any(), eq(false), eq(true)); + + doReturn(false).when(mPhone).isInEcm(); + } } \ No newline at end of file -- GitLab From 42f399bf8c2de06be88088e0d6615da36ae9265d Mon Sep 17 00:00:00 2001 From: Amit Mahajan Date: Thu, 19 Mar 2020 16:52:33 -0700 Subject: [PATCH 055/656] Delete unused intents. ACTION_SUBINFO_RECORD_UPDATED and ACTION_SUBINFO_CONTENT_CHANGE Test: atest Bug: 132734069 Change-Id: I1ada569d495234501fb8ad580c84af189e5f5105 --- .../internal/telephony/CarrierResolver.java | 2 +- .../telephony/SubscriptionController.java | 14 ----------- .../telephony/SubscriptionInfoUpdater.java | 3 ++- .../telephony/SubscriptionControllerTest.java | 25 ------------------- 4 files changed, 3 insertions(+), 41 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierResolver.java b/src/java/com/android/internal/telephony/CarrierResolver.java index ec6a5a094c..37c45956bb 100644 --- a/src/java/com/android/internal/telephony/CarrierResolver.java +++ b/src/java/com/android/internal/telephony/CarrierResolver.java @@ -193,7 +193,7 @@ public class CarrierResolver extends Handler { /** * This is triggered from SubscriptionInfoUpdater after sim state change. * The sequence of sim loading would be - * 1. ACTION_SUBINFO_CONTENT_CHANGE + * 1. OnSubscriptionsChangedListener * 2. ACTION_SIM_STATE_CHANGED/ACTION_SIM_CARD_STATE_CHANGED * /ACTION_SIM_APPLICATION_STATE_CHANGED * 3. ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index b75ed86c95..0dc7012c1f 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -492,17 +492,6 @@ public class SubscriptionController extends ISub.Stub { } } - /** - * Broadcast when SubscriptionInfo has changed - * FIXME: Hopefully removed if the API council accepts SubscriptionInfoListener - */ - private void broadcastSimInfoContentChanged() { - Intent intent = new Intent(TelephonyIntents.ACTION_SUBINFO_CONTENT_CHANGE); - mContext.sendBroadcast(intent); - intent = new Intent(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED); - mContext.sendBroadcast(intent); - } - /** * Notify the changed of subscription info. */ @@ -514,9 +503,6 @@ public class SubscriptionController extends ISub.Stub { if (DBG) logd("notifySubscriptionInfoChanged:"); trm.notifySubscriptionInfoChanged(); - // FIXME: Remove if listener technique accepted. - broadcastSimInfoContentChanged(); - MultiSimSettingController.getInstance().notifySubscriptionInfoChanged(); TelephonyMetrics metrics = TelephonyMetrics.getInstance(); List subInfos; diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index 998286647a..be33499fa8 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -612,7 +612,8 @@ public class SubscriptionInfoUpdater extends Handler { /** * The sim loading sequence will be - * 1. ACTION_SUBINFO_CONTENT_CHANGE happens through updateSubscriptionInfoByIccId() above. + * 1. OnSubscriptionsChangedListener is called through updateSubscriptionInfoByIccId() + * above. * 2. ACTION_SIM_STATE_CHANGED/ACTION_SIM_CARD_STATE_CHANGED * /ACTION_SIM_APPLICATION_STATE_CHANGED * 3. ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index 54feef2469..cd1bc395cb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -273,12 +273,6 @@ public class SubscriptionControllerTest extends TelephonyTest { assertEquals(iconTint, subInfo.getIconTint()); assertEquals(disNum, subInfo.getNumber()); assertEquals(isOpportunistic, subInfo.isOpportunistic()); - - /* verify broadcast intent */ - ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); - verify(mContext, atLeast(1)).sendBroadcast(captorIntent.capture()); - assertEquals(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED, - captorIntent.getValue().getAction()); } @Test @SmallTest @@ -299,13 +293,6 @@ public class SubscriptionControllerTest extends TelephonyTest { assertNotNull(subInfo); assertEquals(disName, subInfo.getDisplayName()); assertEquals(nameSource, subInfo.getNameSource()); - - /* verify broadcast intent */ - ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); - verify(mContext, atLeast(1)).sendBroadcast(captorIntent.capture()); - assertEquals(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED, - captorIntent.getValue().getAction()); - } private void setSimEmbedded(boolean isEmbedded) throws Exception { @@ -584,12 +571,6 @@ public class SubscriptionControllerTest extends TelephonyTest { assertNotNull(subInfo); assertEquals(Integer.parseInt(mCcMncVERIZON.substring(0, 3)), subInfo.getMcc()); assertEquals(Integer.parseInt(mCcMncVERIZON.substring(3)), subInfo.getMnc()); - - /* verify broadcast intent */ - ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); - verify(mContext, atLeast(1)).sendBroadcast(captorIntent.capture()); - assertEquals(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED, - captorIntent.getValue().getAction()); } @Test @SmallTest @@ -602,12 +583,6 @@ public class SubscriptionControllerTest extends TelephonyTest { .getActiveSubscriptionInfo(1, mCallingPackage, mCallingFeature); assertNotNull(subInfo); assertEquals(carrierId, subInfo.getCarrierId()); - - /* verify broadcast intent */ - ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); - verify(mContext, atLeast(1)).sendBroadcast(captorIntent.capture()); - assertEquals(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED, - captorIntent.getValue().getAction()); } @Test -- GitLab From 43066e18f5659376dc4c062df838982c4f8a6f26 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Fri, 15 Jul 2022 21:46:11 +0000 Subject: [PATCH 056/656] Revert "Fix APM race conditions in ServiceStateTracker" This reverts commit 7e376251f9657aa0517a5a5d22a8a5be0b7a05dc. Reason for revert: b/238844735, b/238373619 Change-Id: I101b015d1b6e5bd9cda497d302ee809985be70a9 (cherry picked from commit 3e963c46e27abd7e36c8e16f007ed6c44cd6e7cf) --- .../telephony/ServiceStateTracker.java | 40 ++++---------- .../telephony/ServiceStateTrackerTest.java | 53 +------------------ 2 files changed, 12 insertions(+), 81 deletions(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 1a04cb4153..99ee96bc24 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -1094,7 +1094,7 @@ public class ServiceStateTracker extends Handler { /** * Turn on or off radio power with option to specify whether it's for emergency call and specify * a reason for setting the power state. - * More details check {@link PhoneInternalInterface#setRadioPowerForReason( + * More details check {@link PhoneInternalInterface#setRadioPower( * boolean, boolean, boolean, boolean, int)}. */ public void setRadioPowerForReason(boolean power, boolean forEmergencyCall, @@ -1196,10 +1196,10 @@ public class ServiceStateTracker extends Handler { if (VDBG) log("received event " + msg.what); switch (msg.what) { case EVENT_SET_RADIO_POWER_OFF: - synchronized (this) { + synchronized(this) { if (mPhone.isUsingNewDataStack()) { + mPendingRadioPowerOffAfterDataOff = false; log("Wait for all data networks torn down timed out. Power off now."); - cancelPendingRadioPowerOff(); hangupAndPowerOff(); return; } @@ -1495,18 +1495,17 @@ public class ServiceStateTracker extends Handler { areAllDataDisconnectedOnAllPhones = false; } } - synchronized (this) { - if (areAllDataDisconnectedOnAllPhones) { - if (DBG) log("Data disconnected for all phones, turn radio off now."); - cancelPendingRadioPowerOff(); - hangupAndPowerOff(); - } + if (areAllDataDisconnectedOnAllPhones) { + mPendingRadioPowerOffAfterDataOff = false; + removeMessages(EVENT_SET_RADIO_POWER_OFF); + if (DBG) log("Data disconnected for all phones, turn radio off now."); + hangupAndPowerOff(); } return; } int dds = SubscriptionManager.getDefaultDataSubscriptionId(); ProxyController.getInstance().unregisterForAllDataDisconnected(dds, this); - synchronized (this) { + synchronized(this) { if (mPendingRadioPowerOffAfterDataOff) { if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now."); hangupAndPowerOff(); @@ -3141,12 +3140,12 @@ public class ServiceStateTracker extends Handler { && getRadioPowerOffDelayTimeoutForImsRegistration() > 0) { if (DBG) log("setPowerStateToDesired: delaying power off until IMS dereg."); startDelayRadioOffWaitingForImsDeregTimeout(); + // Return early here as we do not want to hit the cancel timeout code below. + return; } else { if (DBG) log("setPowerStateToDesired: powerOffRadioSafely()"); powerOffRadioSafely(); } - // Return early here as we do not want to hit the cancel timeout code below. - return; } else if (mDeviceShuttingDown && (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE)) { // !mDesiredPowerState condition above will happen first if the radio is on, so we will @@ -3156,23 +3155,6 @@ public class ServiceStateTracker extends Handler { } // Cancel any pending timeouts because the state has been re-evaluated. cancelDelayRadioOffWaitingForImsDeregTimeout(); - cancelPendingRadioPowerOff(); - } - - /** - * Cancel the pending radio power off request that was sent to force the radio to power off - * if waiting for all data to disconnect times out. - */ - private synchronized void cancelPendingRadioPowerOff() { - if (mPhone.isUsingNewDataStack() && mPendingRadioPowerOffAfterDataOff) { - if (DBG) log("cancelPendingRadioPowerOff: cancelling."); - mPendingRadioPowerOffAfterDataOff = false; - for (Phone phone : PhoneFactory.getPhones()) { - phone.getDataNetworkController().unregisterDataNetworkControllerCallback( - mDataDisconnectedCallback); - } - removeMessages(EVENT_SET_RADIO_POWER_OFF); - } } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index f34b9e5644..072f2190e0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -417,7 +417,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { callback1.capture()); verify(dataNetworkController_phone2, times(1)).registerDataNetworkControllerCallback( callback2.capture()); - assertTrue(sst.hasMessages(38 /* EVENT_SET_RADIO_POWER_OFF */)); // Data disconnected on sub 2, still waiting for data disconnected on sub 1 doReturn(true).when(dataNetworkController_phone2).areAllDataDisconnected(); @@ -431,58 +430,8 @@ public class ServiceStateTrackerTest extends TelephonyTest { doReturn(true).when(mDataNetworkController).areAllDataDisconnected(); callback1.getValue().onAnyDataNetworkExistingChanged(false); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - verify(mDataNetworkController, times(2)).unregisterDataNetworkControllerCallback(any()); - assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); - } - - @Test - public void testSetRadioPowerCancelWaitForAllDataDisconnected() throws Exception { - // Set up DSDS environment - GsmCdmaPhone phone2 = Mockito.mock(GsmCdmaPhone.class); - DataNetworkController dataNetworkController_phone2 = - Mockito.mock(DataNetworkController.class); - mPhones = new Phone[] {mPhone, phone2}; - replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); - doReturn(dataNetworkController_phone2).when(phone2).getDataNetworkController(); - doReturn(mSST).when(phone2).getServiceStateTracker(); - doReturn(true).when(phone2).isUsingNewDataStack(); - doReturn(false).when(mDataNetworkController).areAllDataDisconnected(); - doReturn(false).when(dataNetworkController_phone2).areAllDataDisconnected(); - doReturn(1).when(mPhone).getSubId(); - doReturn(2).when(phone2).getSubId(); - - // Start with radio on - sst.setRadioPower(true); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); - - // Turn on APM and verify that both subs are waiting for all data disconnected - sst.setRadioPower(false); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); - verify(mDataNetworkController).tearDownAllDataNetworks( - eq(3 /* TEAR_DOWN_REASON_AIRPLANE_MODE_ON */)); - verify(dataNetworkController_phone2, never()).tearDownAllDataNetworks(anyInt()); - ArgumentCaptor callback1 = - ArgumentCaptor.forClass(DataNetworkController.DataNetworkControllerCallback.class); - ArgumentCaptor callback2 = - ArgumentCaptor.forClass(DataNetworkController.DataNetworkControllerCallback.class); - verify(mDataNetworkController, times(1)).registerDataNetworkControllerCallback( - callback1.capture()); - verify(dataNetworkController_phone2, times(1)).registerDataNetworkControllerCallback( - callback2.capture()); - assertTrue(sst.hasMessages(38 /* EVENT_SET_RADIO_POWER_OFF */)); - - // Turn off APM while waiting for data to disconnect - sst.setRadioPower(true); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - - // Check that radio is on and pending power off messages were cleared - assertFalse(sst.hasMessages(38 /* EVENT_SET_RADIO_POWER_OFF */)); verify(mDataNetworkController, times(1)).unregisterDataNetworkControllerCallback(any()); - verify(dataNetworkController_phone2, times(1)).unregisterDataNetworkControllerCallback( - any()); - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); } @Test -- GitLab From c9658ad178493094364f695190acddc59cb1b37c Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 31 Jul 2022 00:44:26 -0700 Subject: [PATCH 057/656] Removed old data stack Fix: 201830726 Test: Manual Change-Id: I4f58626b0693bd95fc06dbd63ae2f680d7c8ee84 --- .../telephony/GsmCdmaCallTracker.java | 11 - .../internal/telephony/GsmCdmaPhone.java | 199 +- .../telephony/MultiSimSettingController.java | 27 +- .../telephony/NetworkTypeController.java | 108 +- .../com/android/internal/telephony/Phone.java | 153 +- .../internal/telephony/ProxyController.java | 29 - .../internal/telephony/RetryManager.java | 723 --- .../telephony/ServiceStateTracker.java | 230 +- .../telephony/TelephonyComponentFactory.java | 16 - .../telephony/data/AccessNetworksManager.java | 194 +- .../telephony/data/DataConfigManager.java | 12 +- .../data/LinkBandwidthEstimator.java | 33 - .../data/NotifyQosSessionInterface.java | 54 - .../telephony/data/PhoneSwitcher.java | 179 +- .../telephony/data/QosCallbackTracker.java | 72 +- .../telephony/data/TelephonyNetworkAgent.java | 36 +- .../data/TelephonyNetworkFactory.java | 253 +- .../data/TelephonyNetworkRequest.java | 14 +- .../dataconnection/ApnConfigType.java | 50 - .../ApnConfigTypeRepository.java | 128 - .../telephony/dataconnection/ApnContext.java | 675 -- .../dataconnection/ApnSettingUtils.java | 129 - .../dataconnection/DataConnection.java | 4094 ------------ .../dataconnection/DataConnectionReasons.java | 176 - .../dataconnection/DataEnabledSettings.java | 566 -- .../dataconnection/DataServiceManager.java | 978 --- .../dataconnection/DataThrottler.java | 366 -- .../dataconnection/DcController.java | 487 -- .../dataconnection/DcFailBringUp.java | 85 - .../dataconnection/DcNetworkAgent.java | 617 -- .../telephony/dataconnection/DcRequest.java | 102 - .../dataconnection/DcTesterDeactivateAll.java | 95 - .../DcTesterFailBringUpAll.java | 110 - .../telephony/dataconnection/DcTracker.java | 5665 ----------------- .../telephony/dataconnection/README.txt | 71 - .../dataconnection/TransportManager.java | 279 - .../telephony/imsphone/ImsPhoneBase.java | 10 - .../imsphone/ImsPhoneCallTracker.java | 74 +- .../metrics/DataStallRecoveryStats.java | 37 - .../telephony/metrics/MetricsCollector.java | 3 +- .../MultiSimSettingControllerTest.java | 98 +- .../telephony/NetworkTypeControllerTest.java | 106 +- .../telephony/SMSDispatcherTest.java.broken | 107 - .../telephony/ServiceStateTrackerTest.java | 53 - .../internal/telephony/TelephonyTest.java | 23 - .../telephony/TestPhoneNotifier.java.broken | 69 - .../ApnSettingTest.java | 214 +- .../telephony/data/DataCallResponseTest.java | 17 +- .../telephony/data/DataNetworkTest.java | 2 - .../data/LinkBandwidthEstimatorTest.java | 23 +- .../telephony/data/PhoneSwitcherTest.java | 22 +- .../data/QosCallbackTrackerTest.java | 97 +- .../data/TelephonyNetworkFactoryTest.java | 94 +- .../ApnConfigTypeRepositoryTest.java | 109 - .../dataconnection/ApnContextTest.java | 240 - .../dataconnection/DataConnectionTest.java | 1479 ----- .../DataEnabledSettingsTest.java | 147 - .../dataconnection/DataThrottlerTest.java | 222 - .../dataconnection/DcControllerTest.java | 272 - .../dataconnection/DcNetworkAgentTest.java | 118 - .../dataconnection/DcRequestTest.java | 125 - .../dataconnection/DcTrackerTest.java | 2983 --------- .../dataconnection/RetryManagerTest.java | 996 --- .../telephony/gsm/GSMPhoneTest.java.broken | 1935 ------ .../telephony/gsm/GSMTestHandler.java.broken | 118 - .../gsm/UsimDataDownloadCommands.java.broken | 694 -- .../gsm/UsimDataDownloadTest.java.broken | 144 - .../metrics/TelephonyMetricsTest.java | 10 +- tools/tdi | 48 - 69 files changed, 411 insertions(+), 27294 deletions(-) delete mode 100644 src/java/com/android/internal/telephony/RetryManager.java delete mode 100644 src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnContext.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DataConnection.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DataThrottler.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcController.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcRequest.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java delete mode 100755 src/java/com/android/internal/telephony/dataconnection/DcTracker.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/README.txt delete mode 100644 src/java/com/android/internal/telephony/dataconnection/TransportManager.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken rename tests/telephonytests/src/com/android/internal/telephony/{dataconnection => data}/ApnSettingTest.java (62%) delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken delete mode 100755 tools/tdi diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java index 07be4e51fb..263bfebc15 100755 --- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java +++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java @@ -182,11 +182,6 @@ public class GsmCdmaCallTracker extends CallTracker { mCi.unregisterForCallWaitingInfo(this); // Prior to phone switch to GSM, if CDMA has any emergency call // data will be in disabled state, after switching to GSM enable data. - if (mIsInEmergencyCall) { - if (!mPhone.isUsingNewDataStack()) { - mPhone.getDataEnabledSettings().setInternalDataEnabled(true); - } - } } else { mConnections = new GsmCdmaConnection[MAX_CONNECTIONS_CDMA]; mPendingCallInEcm = false; @@ -400,9 +395,6 @@ public class GsmCdmaCallTracker extends CallTracker { //CDMA public void setIsInEmergencyCall() { mIsInEmergencyCall = true; - if (!mPhone.isUsingNewDataStack()) { - mPhone.getDataEnabledSettings().setInternalDataEnabled(false); - } mPhone.notifyEmergencyCallRegistrants(true); mPhone.sendEmergencyCallStateChange(true); } @@ -1759,9 +1751,6 @@ public class GsmCdmaCallTracker extends CallTracker { } if (!inEcm) { // Re-initiate data connection - if (!mPhone.isUsingNewDataStack()) { - mPhone.getDataEnabledSettings().setInternalDataEnabled(true); - } mPhone.notifyEmergencyCallRegistrants(false); } mPhone.sendEmergencyCallStateChange(false); diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 6d16fe072a..94d437fa00 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -67,7 +67,6 @@ import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telecom.VideoProfile; -import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.DataActivityType; import android.telephony.Annotation.RadioPowerState; import android.telephony.BarringInfo; @@ -85,7 +84,6 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.UiccAccessRule; import android.telephony.UssdResponse; -import android.telephony.data.ApnSetting; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -97,9 +95,6 @@ import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.LinkBandwidthEstimator; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; -import com.android.internal.telephony.dataconnection.DcTracker; -import com.android.internal.telephony.dataconnection.TransportManager; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.gsm.GsmMmiCode; import com.android.internal.telephony.gsm.SsData; @@ -277,8 +272,6 @@ public class GsmCdmaPhone extends Phone { private CarrierKeyDownloadManager mCDM; private CarrierInfoManager mCIM; - private final SettingsObserver mSettingsObserver; - private final ImsManagerFactory mImsManagerFactory; private final CarrierPrivilegesTracker mCarrierPrivilegesTracker; @@ -323,10 +316,6 @@ public class GsmCdmaPhone extends Phone { mAccessNetworksManager = mTelephonyComponentFactory .inject(AccessNetworksManager.class.getName()) .makeAccessNetworksManager(this, getLooper()); - if (!isUsingNewDataStack()) { - mTransportManager = mTelephonyComponentFactory.inject(TransportManager.class.getName()) - .makeTransportManager(this); - } // SST/DSM depends on SSC, so SSC is instanced before SST/DSM mSignalStrengthController = mTelephonyComponentFactory.inject( SignalStrengthController.class.getName()).makeSignalStrengthController(this); @@ -335,10 +324,6 @@ public class GsmCdmaPhone extends Phone { mEmergencyNumberTracker = mTelephonyComponentFactory .inject(EmergencyNumberTracker.class.getName()).makeEmergencyNumberTracker( this, this.mCi); - if (!isUsingNewDataStack()) { - mDataEnabledSettings = mTelephonyComponentFactory - .inject(DataEnabledSettings.class.getName()).makeDataEnabledSettings(this); - } mDeviceStateMonitor = mTelephonyComponentFactory.inject(DeviceStateMonitor.class.getName()) .makeDeviceStateMonitor(this); @@ -347,20 +332,9 @@ public class GsmCdmaPhone extends Phone { mDisplayInfoController = mTelephonyComponentFactory.inject( DisplayInfoController.class.getName()).makeDisplayInfoController(this); - if (isUsingNewDataStack()) { - mDataNetworkController = mTelephonyComponentFactory.inject( - DataNetworkController.class.getName()) - .makeDataNetworkController(this, getLooper()); - } else { - // DcTracker uses ServiceStateTracker and DisplayInfoController so needs to be created - // after they are instantiated - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - DcTracker dcTracker = mTelephonyComponentFactory.inject(DcTracker.class.getName()) - .makeDcTracker(this, transport); - mDcTrackers.put(transport, dcTracker); - mAccessNetworksManager.registerDataThrottler(dcTracker.getDataThrottler()); - } - } + mDataNetworkController = mTelephonyComponentFactory.inject( + DataNetworkController.class.getName()) + .makeDataNetworkController(this, getLooper()); mCarrierResolver = mTelephonyComponentFactory.inject(CarrierResolver.class.getName()) .makeCarrierResolver(this); @@ -373,15 +347,6 @@ public class GsmCdmaPhone extends Phone { mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, null); - // TODO: Remove SettingsObserver and provisioning events when DataEnabledSettings is removed - mSettingsObserver = new SettingsObserver(context, this); - mSettingsObserver.observe( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), - EVENT_DEVICE_PROVISIONED_CHANGE); - mSettingsObserver.observe( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED), - EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE); - SubscriptionController.getInstance().registerForUiccAppsEnabled(this, EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false); @@ -690,11 +655,6 @@ public class GsmCdmaPhone extends Phone { return mCT; } - @Override - public TransportManager getTransportManager() { - return mTransportManager; - } - @Override public AccessNetworksManager getAccessNetworksManager() { return mAccessNetworksManager; @@ -746,84 +706,9 @@ public class GsmCdmaPhone extends Phone { return mCT.mState != PhoneConstants.State.IDLE && !mSST.isConcurrentVoiceAndDataAllowed(); } - @Override - public PhoneConstants.DataState getDataConnectionState(String apnType) { - PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED; - - if (mSST == null) { - // Radio Technology Change is ongoing, dispose() and removeReferences() have - // already been called - - ret = PhoneConstants.DataState.DISCONNECTED; - } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE - && (isPhoneTypeCdma() || isPhoneTypeCdmaLte() || - (isPhoneTypeGsm() && !apnType.equals(ApnSetting.TYPE_EMERGENCY_STRING)))) { - // If we're out of service, open TCP sockets may still work - // but no data will flow - - // Emergency APN is available even in Out Of Service - // Pass the actual State of EPDN - - ret = PhoneConstants.DataState.DISCONNECTED; - } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */ - int currentTransport = mAccessNetworksManager.getCurrentTransport( - ApnSetting.getApnTypesBitmaskFromString(apnType)); - if (getDcTracker(currentTransport) != null) { - switch (getDcTracker(currentTransport).getState(apnType)) { - case CONNECTED: - case DISCONNECTING: - if (isDataSuspended()) { - ret = PhoneConstants.DataState.SUSPENDED; - } else { - ret = PhoneConstants.DataState.CONNECTED; - } - break; - case CONNECTING: - ret = PhoneConstants.DataState.CONNECTING; - break; - default: - ret = PhoneConstants.DataState.DISCONNECTED; - } - } - } - - logd("getDataConnectionState apnType=" + apnType + " ret=" + ret); - return ret; - } - @Override public @DataActivityType int getDataActivityState() { - if (isUsingNewDataStack()) { - return getDataNetworkController().getDataActivity(); - } - int ret = TelephonyManager.DATA_ACTIVITY_NONE; - - if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE - && getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { - switch (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getActivity()) { - case DATAIN: - ret = TelephonyManager.DATA_ACTIVITY_IN; - break; - - case DATAOUT: - ret = TelephonyManager.DATA_ACTIVITY_OUT; - break; - - case DATAINANDOUT: - ret = TelephonyManager.DATA_ACTIVITY_INOUT; - break; - - case DORMANT: - ret = TelephonyManager.DATA_ACTIVITY_DORMANT; - break; - - default: - ret = TelephonyManager.DATA_ACTIVITY_NONE; - break; - } - } - - return ret; + return getDataNetworkController().getDataActivity(); } /** @@ -2968,25 +2853,12 @@ public class GsmCdmaPhone extends Phone { @Override public boolean getDataRoamingEnabled() { - if (isUsingNewDataStack()) { - return getDataSettingsManager().isDataRoamingEnabled(); - } - if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { - return getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getDataRoamingEnabled(); - } - return false; + return getDataSettingsManager().isDataRoamingEnabled(); } @Override public void setDataRoamingEnabled(boolean enable) { - if (isUsingNewDataStack()) { - getDataSettingsManager().setDataRoamingEnabled(enable); - return; - } - if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { - getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setDataRoamingEnabledByUser(enable); - } + getDataSettingsManager().setDataRoamingEnabled(enable); } @Override @@ -3031,21 +2903,12 @@ public class GsmCdmaPhone extends Phone { } /** - * Whether data is enabled by user. Unlike isDataEnabled, this only - * checks user setting stored in {@link android.provider.Settings.Global#MOBILE_DATA} - * if not provisioning, or isProvisioningDataEnabled if provisioning. + * Whether data is enabled by user. */ @Override public boolean isUserDataEnabled() { - if (isUsingNewDataStack()) { - return getDataSettingsManager().isDataEnabledForReason( - TelephonyManager.DATA_ENABLED_REASON_USER); - } - if (mDataEnabledSettings.isProvisioning()) { - return mDataEnabledSettings.isProvisioningDataEnabled(); - } else { - return mDataEnabledSettings.isUserDataEnabled(); - } + return getDataSettingsManager().isDataEnabledForReason( + TelephonyManager.DATA_ENABLED_REASON_USER); } /** @@ -3580,24 +3443,9 @@ public class GsmCdmaPhone extends Phone { case EVENT_SET_CARRIER_DATA_ENABLED: ar = (AsyncResult) msg.obj; boolean enabled = (boolean) ar.result; - if (isUsingNewDataStack()) { - getDataSettingsManager().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_CARRIER, enabled, - mContext.getOpPackageName()); - return; - } - mDataEnabledSettings.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_CARRIER, - enabled); - break; - case EVENT_DEVICE_PROVISIONED_CHANGE: - if (!isUsingNewDataStack()) { - mDataEnabledSettings.updateProvisionedChanged(); - } - break; - case EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE: - if (!isUsingNewDataStack()) { - mDataEnabledSettings.updateProvisioningDataEnabled(); - } + getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_CARRIER, enabled, + mContext.getOpPackageName()); break; case EVENT_GET_AVAILABLE_NETWORKS_DONE: ar = (AsyncResult) msg.obj; @@ -4092,10 +3940,6 @@ public class GsmCdmaPhone extends Phone { // send an Intent sendEmergencyCallbackModeChange(); - // Re-initiate data connection - if (!isUsingNewDataStack()) { - mDataEnabledSettings.setInternalDataEnabled(true); - } notifyEmergencyCallRegistrants(false); } mIsTestingEmergencyCallbackMode = false; @@ -5051,24 +4895,7 @@ public class GsmCdmaPhone extends Phone { * @return Currently bound data service package names. */ public @NonNull List getDataServicePackages() { - if (isUsingNewDataStack()) { - return getDataNetworkController().getDataServicePackages(); - } - List packages = new ArrayList<>(); - int[] transports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; - - for (int transport : transports) { - DcTracker dct = getDcTracker(transport); - if (dct != null) { - String pkg = dct.getDataServiceManager().getDataServicePackageName(); - if (!TextUtils.isEmpty(pkg)) { - packages.add(pkg); - } - } - } - - return packages; + return getDataNetworkController().getDataServicePackages(); } private void updateBroadcastEmergencyCallStateChangesAfterCarrierConfigChanged( diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index 292046a43b..48dd1e0fd2 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -839,14 +839,9 @@ public class MultiSimSettingController extends Handler { && phone.isUserDataEnabled() && !areSubscriptionsInSameGroup(defaultDataSub, phone.getSubId())) { log("setting data to false on " + phone.getSubId()); - if (phone.isUsingNewDataStack()) { - phone.getDataSettingsManager().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, - mContext.getOpPackageName()); - } else { - phone.getDataEnabledSettings().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); - } + phone.getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, + mContext.getOpPackageName()); } } } @@ -882,13 +877,9 @@ public class MultiSimSettingController extends Handler { // If enable is true and it's not opportunistic subscription, we don't enable it, // as there can't be two if (phone != null) { - if (phone.isUsingNewDataStack()) { - phone.getDataSettingsManager().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, enable, - mContext.getOpPackageName()); - } else { - phone.getDataEnabledSettings().setUserDataEnabled(enable, false); - } + phone.getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, enable, + mContext.getOpPackageName()); } } else { // For inactive subscription, directly write into global settings. @@ -1063,10 +1054,8 @@ public class MultiSimSettingController extends Handler { // existing phone instance. Phone[] phones = PhoneFactory.getPhones(); for (int i = mCallbacksCount; i < phones.length; i++) { - if (phones[i].isUsingNewDataStack()) { - phones[i].getDataSettingsManager().registerCallback( - new DataSettingsControllerCallback(phones[i], this::post)); - } + phones[i].getDataSettingsManager().registerCallback( + new DataSettingsControllerCallback(phones[i], this::post)); } mCallbacksCount = phones.length; } diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 2260d3456a..9cb21945de 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -28,20 +29,16 @@ import android.telephony.AccessNetworkConstants; import android.telephony.Annotation; import android.telephony.CarrierConfigManager; import android.telephony.NetworkRegistrationInfo; -import android.telephony.PcoData; import android.telephony.PhysicalChannelConfig; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataCallResponse.LinkStatus; import android.text.TextUtils; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; -import com.android.internal.telephony.dataconnection.DataConnection; -import com.android.internal.telephony.dataconnection.DcTracker; import com.android.internal.telephony.util.ArrayUtils; import com.android.internal.util.IState; import com.android.internal.util.IndentingPrintWriter; @@ -99,7 +96,6 @@ public class NetworkTypeController extends StateMachine { private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11; private static final int EVENT_INITIALIZE = 12; private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 13; - private static final int EVENT_PCO_DATA_CHANGED = 14; private static final int EVENT_BANDWIDTH_CHANGED = 15; private static final int EVENT_UPDATE_NR_ADVANCED_STATE = 16; private static final int EVENT_DEVICE_IDLE_MODE_CHANGED = 17; @@ -121,7 +117,6 @@ public class NetworkTypeController extends StateMachine { sEvents[EVENT_PREFERRED_NETWORK_MODE_CHANGED] = "EVENT_PREFERRED_NETWORK_MODE_CHANGED"; sEvents[EVENT_INITIALIZE] = "EVENT_INITIALIZE"; sEvents[EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED] = "EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED"; - sEvents[EVENT_PCO_DATA_CHANGED] = "EVENT_PCO_DATA_CHANGED"; sEvents[EVENT_BANDWIDTH_CHANGED] = "EVENT_BANDWIDTH_CHANGED"; sEvents[EVENT_UPDATE_NR_ADVANCED_STATE] = "EVENT_UPDATE_NR_ADVANCED_STATE"; sEvents[EVENT_DEVICE_IDLE_MODE_CHANGED] = "EVENT_DEVICE_IDLE_MODE_CHANGED"; @@ -169,6 +164,9 @@ public class NetworkTypeController extends StateMachine { private boolean mEnableNrAdvancedWhileRoaming = true; private boolean mIsDeviceIdleMode = false; + private @Nullable DataNetworkControllerCallback mNrAdvancedCapableByPcoChangedCallback = null; + private @Nullable DataNetworkControllerCallback mNrPhysicalLinkStatusChangedCallback = null; + /** * NetworkTypeController constructor. * @@ -232,9 +230,6 @@ public class NetworkTypeController extends StateMachine { filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); - if (!mPhone.isUsingNewDataStack()) { - mPhone.mCi.registerForPcoData(getHandler(), EVENT_PCO_DATA_CHANGED, null); - } } private void unRegisterForAllEvents() { @@ -246,9 +241,6 @@ public class NetworkTypeController extends StateMachine { mPhone.getServiceStateTracker().unregisterForNrFrequencyChanged(getHandler()); mPhone.getDeviceStateMonitor().unregisterForPhysicalChannelConfigNotifChanged(getHandler()); mPhone.getContext().unregisterReceiver(mIntentReceiver); - if (!mPhone.isUsingNewDataStack()) { - mPhone.mCi.unregisterForPcoData(getHandler()); - } } private void parseCarrierConfigs() { @@ -306,38 +298,47 @@ public class NetworkTypeController extends StateMachine { CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY); mNrAdvancedCapablePcoId = b.getInt( CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT); - if (mNrAdvancedCapablePcoId > 0 && mPhone.isUsingNewDataStack()) { - mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + if (mNrAdvancedCapablePcoId > 0 && mNrAdvancedCapableByPcoChangedCallback == null) { + mNrAdvancedCapableByPcoChangedCallback = new DataNetworkControllerCallback(getHandler()::post) { - @Override - public void onNrAdvancedCapableByPcoChanged( - boolean nrAdvancedCapable) { - log("mIsNrAdvancedAllowedByPco=" + nrAdvancedCapable); - mIsNrAdvancedAllowedByPco = nrAdvancedCapable; - sendMessage(EVENT_UPDATE_NR_ADVANCED_STATE); - } - }); + @Override + public void onNrAdvancedCapableByPcoChanged( + boolean nrAdvancedCapable) { + log("mIsNrAdvancedAllowedByPco=" + nrAdvancedCapable); + mIsNrAdvancedAllowedByPco = nrAdvancedCapable; + sendMessage(EVENT_UPDATE_NR_ADVANCED_STATE); + } + }; + mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + mNrAdvancedCapableByPcoChangedCallback); + } else if (mNrAdvancedCapablePcoId == 0 + && mNrAdvancedCapableByPcoChangedCallback != null) { + mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( + mNrAdvancedCapableByPcoChangedCallback); + mNrAdvancedCapableByPcoChangedCallback = null; } mEnableNrAdvancedWhileRoaming = b.getBoolean( CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL); mIsUsingUserDataForRrcDetection = b.getBoolean( CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL); if (!mIsPhysicalChannelConfig16Supported || mIsUsingUserDataForRrcDetection) { - if (mPhone.isUsingNewDataStack()) { - mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + if (mNrPhysicalLinkStatusChangedCallback == null) { + mNrPhysicalLinkStatusChangedCallback = new DataNetworkControllerCallback(getHandler()::post) { - @Override - public void onPhysicalLinkStatusChanged( - @LinkStatus int status) { - sendMessage(obtainMessage( - EVENT_PHYSICAL_LINK_STATUS_CHANGED, - new AsyncResult(null, status, null))); - }}); - } else { - mPhone.getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .registerForPhysicalLinkStatusChanged(getHandler(), - EVENT_PHYSICAL_LINK_STATUS_CHANGED); + @Override + public void onPhysicalLinkStatusChanged( + @LinkStatus int status) { + sendMessage(obtainMessage( + EVENT_PHYSICAL_LINK_STATUS_CHANGED, + new AsyncResult(null, status, null))); + }}; + mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + mNrPhysicalLinkStatusChangedCallback); } + } else if (mNrPhysicalLinkStatusChangedCallback != null) { + mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( + mNrPhysicalLinkStatusChangedCallback); + mNrPhysicalLinkStatusChangedCallback = null; } } } @@ -555,15 +556,14 @@ public class NetworkTypeController extends StateMachine { break; case EVENT_INITIALIZE: // The reason that we do it here is because some of the works below requires - // other modules (e.g. DcTracker, ServiceStateTracker), which is not created - // yet when NetworkTypeController is created. + // other modules (e.g. DataNetworkController, ServiceStateTracker), which is not + // created yet when NetworkTypeController is created. registerForAllEvents(); parseCarrierConfigs(); break; case EVENT_DATA_RAT_CHANGED: case EVENT_NR_STATE_CHANGED: case EVENT_NR_FREQUENCY_CHANGED: - case EVENT_PCO_DATA_CHANGED: case EVENT_UPDATE_NR_ADVANCED_STATE: // ignored break; @@ -941,9 +941,6 @@ public class NetworkTypeController extends StateMachine { transitionWithTimerTo(mLegacyState); } break; - case EVENT_PCO_DATA_CHANGED: - handlePcoData((AsyncResult) msg.obj); - break; case EVENT_UPDATE_NR_ADVANCED_STATE: updateNrAdvancedState(); break; @@ -980,6 +977,7 @@ public class NetworkTypeController extends StateMachine { } private void updateNrAdvancedState() { + log("updateNrAdvancedState"); if (!isNrConnected()) { log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); sendMessage(EVENT_NR_STATE_CHANGED); @@ -993,33 +991,7 @@ public class NetworkTypeController extends StateMachine { transitionTo(mNrConnectedState); } mIsNrAdvanced = isNrAdvanced(); - } - - private void handlePcoData(AsyncResult ar) { - if (ar.exception != null) { - loge("PCO_DATA exception: " + ar.exception); - return; - } - PcoData pcodata = (PcoData) ar.result; - if (pcodata == null) { - return; - } - log("EVENT_PCO_DATA_CHANGED: pco data: " + pcodata); - DcTracker dcTracker = mPhone.getDcTracker( - AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - DataConnection dc = - dcTracker != null ? dcTracker.getDataConnectionByContextId(pcodata.cid) : null; - ApnSetting apnSettings = dc != null ? dc.getApnSetting() : null; - if (apnSettings != null && apnSettings.canHandleType(ApnSetting.TYPE_DEFAULT) - && mNrAdvancedCapablePcoId > 0 - && pcodata.pcoId == mNrAdvancedCapablePcoId - ) { - log("EVENT_PCO_DATA_CHANGED: NR_ADVANCED is allowed by PCO. length:" - + pcodata.contents.length + ",value: " + Arrays.toString(pcodata.contents)); - mIsNrAdvancedAllowedByPco = pcodata.contents.length > 0 - && pcodata.contents[pcodata.contents.length - 1] == 1; - updateNrAdvancedState(); - } + log("mIsNrAdvanced=" + mIsNrAdvanced); } } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 99bd3c5358..5c5c303c31 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -40,7 +40,6 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telecom.VideoProfile; import android.telephony.AccessNetworkConstants; -import android.telephony.Annotation.ApnType; import android.telephony.CarrierConfigManager; import android.telephony.CarrierRestrictionRules; import android.telephony.CellIdentity; @@ -60,14 +59,12 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RegistrationManager; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; -import android.util.SparseArray; import android.util.Xml; import com.android.ims.ImsCall; @@ -80,10 +77,6 @@ import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; -import com.android.internal.telephony.dataconnection.DataConnectionReasons; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; -import com.android.internal.telephony.dataconnection.DcTracker; -import com.android.internal.telephony.dataconnection.TransportManager; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; @@ -222,11 +215,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // Radio state change protected static final int EVENT_RADIO_STATE_CHANGED = 47; protected static final int EVENT_SET_CARRIER_DATA_ENABLED = 48; - protected static final int EVENT_DEVICE_PROVISIONED_CHANGE = 49; - protected static final int EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE = 50; protected static final int EVENT_GET_AVAILABLE_NETWORKS_DONE = 51; - private static final int EVENT_ALL_DATA_DISCONNECTED = 52; protected static final int EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED = 53; protected static final int EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED = 54; protected static final int EVENT_GET_UICC_APPS_ENABLEMENT_DONE = 55; @@ -303,11 +293,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public CommandsInterface mCi; protected int mVmCount = 0; private boolean mDnsCheckDisabled; - // Data connection trackers. For each transport type (e.g. WWAN, WLAN), there will be a - // corresponding DcTracker. The WWAN DcTracker is for cellular data connections while - // WLAN DcTracker is for IWLAN data connection. For IWLAN legacy mode, only one (WWAN) DcTracker - // will be created. - protected final SparseArray mDcTrackers = new SparseArray<>(); protected DataNetworkController mDataNetworkController; /* Used for dispatching signals to configured carrier apps */ protected CarrierSignalAgent mCarrierSignalAgent; @@ -346,9 +331,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private final String mActionAttached; protected DeviceStateMonitor mDeviceStateMonitor; protected DisplayInfoController mDisplayInfoController; - protected TransportManager mTransportManager; protected AccessNetworksManager mAccessNetworksManager; - protected DataEnabledSettings mDataEnabledSettings; // Used for identify the carrier of current subscription protected CarrierResolver mCarrierResolver; protected SignalStrengthController mSignalStrengthController; @@ -428,8 +411,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected final RegistrantList mEmergencyCallToggledRegistrants = new RegistrantList(); - private final RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList(); - private final RegistrantList mCellInfoRegistrants = new RegistrantList(); private final RegistrantList mRedialRegistrants = new RegistrantList(); @@ -474,10 +455,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected LinkBandwidthEstimator mLinkBandwidthEstimator; - /** The flag indicating using the new data stack or not. */ - // This flag and the old data stack code will be deleted in Android 14. - private final boolean mNewDataStackEnabled; - public IccRecords getIccRecords() { return mIccRecords.get(); } @@ -619,9 +596,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // Initialize SMS stats mSmsStats = new SmsStats(this); - mNewDataStackEnabled = !mContext.getResources().getBoolean( - com.android.internal.R.bool.config_force_disable_telephony_new_data_stack); - if (getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { return; } @@ -814,11 +788,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { break; } - case EVENT_ALL_DATA_DISCONNECTED: - if (areAllDataDisconnected()) { - mAllDataDisconnectedRegistrants.notifyRegistrants(); - } - break; case EVENT_GET_USAGE_SETTING_DONE: ar = (AsyncResult) msg.obj; if (ar.exception == null) { @@ -1950,13 +1919,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } - /** - * @return The instance of transport manager. - */ - public TransportManager getTransportManager() { - return null; - } - /** * @return The instance of access networks manager. */ @@ -3730,18 +3692,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @return true if there is a matching DUN APN. */ public boolean hasMatchedTetherApnSetting() { - if (isUsingNewDataStack()) { - NetworkRegistrationInfo nrs = getServiceState().getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - if (nrs != null) { - return getDataNetworkController().getDataProfileManager() - .isTetheringDataProfileExisting(nrs.getAccessNetworkTechnology()); - } - return false; - } - if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { - return getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .hasMatchedTetherApnSetting(); + NetworkRegistrationInfo nrs = getServiceState().getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (nrs != null) { + return getDataNetworkController().getDataProfileManager() + .isTetheringDataProfileExisting(nrs.getAccessNetworkTechnology()); } return false; } @@ -3752,30 +3707,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @return {@code true} if internet data is allowed to be established. */ public boolean isDataAllowed() { - if (isUsingNewDataStack()) { - return getDataNetworkController().isInternetDataAllowed(); - } - return isDataAllowed(ApnSetting.TYPE_DEFAULT, null); - } - - /** - * Report on whether data connectivity is allowed. - * - * @param apnType APN type - * @param reasons The reasons that data can/can't be established. This is an output param. - * @return True if data is allowed to be established - */ - public boolean isDataAllowed(@ApnType int apnType, DataConnectionReasons reasons) { - if (mAccessNetworksManager != null) { - int transport = mAccessNetworksManager.getCurrentTransport(apnType); - if (getDcTracker(transport) != null) { - return getDcTracker(transport).isDataAllowed(reasons); - } - } - return false; + return getDataNetworkController().isInternetDataAllowed(); } - /** * Action set from carrier signalling broadcast receivers to enable/disable metered apns. */ @@ -3932,16 +3866,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } - /** - * Get the current for the default apn DataState. No change notification - * exists at this interface -- use - * {@link android.telephony.PhoneStateListener} instead. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public PhoneConstants.DataState getDataConnectionState() { - return getDataConnectionState(ApnSetting.TYPE_DEFAULT_STRING); - } - public void notifyCallForwardingIndicator() { } @@ -4621,42 +4545,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return false; } - /** - * @return True if all data connections are disconnected. - */ - public boolean areAllDataDisconnected() { - if (mAccessNetworksManager != null) { - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - if (getDcTracker(transport) != null - && !getDcTracker(transport).areAllDataDisconnected()) { - return false; - } - } - } - return true; - } - - public void registerForAllDataDisconnected(Handler h, int what) { - mAllDataDisconnectedRegistrants.addUnique(h, what, null); - if (mAccessNetworksManager != null) { - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - if (getDcTracker(transport) != null - && !getDcTracker(transport).areAllDataDisconnected()) { - getDcTracker(transport).registerForAllDataDisconnected( - this, EVENT_ALL_DATA_DISCONNECTED); - } - } - } - } - - public void unregisterForAllDataDisconnected(Handler h) { - mAllDataDisconnectedRegistrants.remove(h); - } - - public DataEnabledSettings getDataEnabledSettings() { - return mDataEnabledSettings; - } - @UnsupportedAppUsage public IccSmsInterfaceManager getIccSmsInterfaceManager(){ return null; @@ -4787,16 +4675,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return isEmergencyCallOnly; } - /** - * Get data connection tracker based on the transport type - * - * @param transportType Transport type defined in AccessNetworkConstants.TransportType - * @return The data connection tracker. Null if not found. - */ - public @Nullable DcTracker getDcTracker(int transportType) { - return mDcTrackers.get(transportType); - } - // Return true if either CSIM or RUIM app is present. By default it returns false. public boolean isCdmaSubscriptionAppPresent() { return false; @@ -4976,14 +4854,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return mIsAllowedNetworkTypesLoadedFromDb; } - /** - * @return {@code true} if using the new telephony data stack. - */ - // This flag and the old data stack code will be deleted in Android 14. - public boolean isUsingNewDataStack() { - return mNewDataStackEnabled; - } - /** * Returns the user's last setting for terminal-based call waiting * @param forCsOnly indicates the caller expects the result for CS calls only @@ -5040,7 +4910,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { pw.println(" needsOtaServiceProvisioning=" + needsOtaServiceProvisioning()); pw.println(" isInEmergencySmsMode=" + isInEmergencySmsMode()); pw.println(" isEcmCanceledForEmergency=" + isEcmCanceledForEmergency()); - pw.println(" isUsingNewDataStack=" + isUsingNewDataStack()); pw.println(" service state=" + getServiceState()); pw.flush(); pw.println("++++++++++++++++++++++++++++++++"); @@ -5056,16 +4925,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { pw.println("++++++++++++++++++++++++++++++++"); } - if (mAccessNetworksManager != null) { - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - if (getDcTracker(transport) != null) { - getDcTracker(transport).dump(fd, pw, args); - pw.flush(); - pw.println("++++++++++++++++++++++++++++++++"); - } - } - } - if (mDataNetworkController != null) { try { mDataNetworkController.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/ProxyController.java b/src/java/com/android/internal/telephony/ProxyController.java index 76f0041ee2..498953c6e0 100644 --- a/src/java/com/android/internal/telephony/ProxyController.java +++ b/src/java/com/android/internal/telephony/ProxyController.java @@ -28,7 +28,6 @@ import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.telephony.RadioAccessFamily; -import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; @@ -157,34 +156,6 @@ public class ProxyController { logd("Constructor - Exit"); } - public void registerForAllDataDisconnected(int subId, Handler h, int what) { - int phoneId = SubscriptionController.getInstance().getPhoneId(subId); - - if (SubscriptionManager.isValidPhoneId(phoneId)) { - mPhones[phoneId].registerForAllDataDisconnected(h, what); - } - } - - public void unregisterForAllDataDisconnected(int subId, Handler h) { - int phoneId = SubscriptionController.getInstance().getPhoneId(subId); - - if (SubscriptionManager.isValidPhoneId(phoneId)) { - mPhones[phoneId].unregisterForAllDataDisconnected(h); - } - } - - - public boolean areAllDataDisconnected(int subId) { - int phoneId = SubscriptionController.getInstance().getPhoneId(subId); - - if (SubscriptionManager.isValidPhoneId(phoneId)) { - return mPhones[phoneId].areAllDataDisconnected(); - } else { - // if we can't find a phone for the given subId, it is disconnected. - return true; - } - } - /** * Get phone radio type and access technology. * diff --git a/src/java/com/android/internal/telephony/RetryManager.java b/src/java/com/android/internal/telephony/RetryManager.java deleted file mode 100644 index 83864e46a0..0000000000 --- a/src/java/com/android/internal/telephony/RetryManager.java +++ /dev/null @@ -1,723 +0,0 @@ -/** - * Copyright (C) 2009 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; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.os.Build; -import android.os.PersistableBundle; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.telephony.Annotation.ApnType; -import android.telephony.CarrierConfigManager; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.text.TextUtils; -import android.util.Pair; - -import com.android.internal.telephony.dataconnection.DataThrottler; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.telephony.Rlog; - -import java.util.ArrayList; -import java.util.Random; - -/** - * Retry manager allows a simple way to declare a series of - * retry timeouts. After creating a RetryManager the configure - * method is used to define the sequence. A simple linear series - * may be initialized using configure with three integer parameters - * The other configure method allows a series to be declared using - * a string. - *

- * The format of the configuration string is the apn type followed by a series of parameters - * separated by a comma. There are two name value pair parameters plus a series - * of delay times. The units of of these delay times is unspecified. - * The name value pairs which may be specified are: - *

    - *
  • max_retries= - *
  • default_randomizationTime= - *
- *

- * apn type specifies the APN type that the retry pattern will apply for. "others" is for all other - * APN types not specified in the config. - * - * max_retries is the number of times that incrementRetryCount - * maybe called before isRetryNeeded will return false. if value - * is infinite then isRetryNeeded will always return true. - * - * default_randomizationTime will be used as the randomizationTime - * for delay times which have no supplied randomizationTime. If - * default_randomizationTime is not defined it defaults to 0. - *

- * The other parameters define The series of delay times and each - * may have an optional randomization value separated from the - * delay time by a colon. - *

- * Examples: - *

    - *
  • 3 retries for mms with no randomization value which means its 0: - *
    • "mms:1000, 2000, 3000"
    - * - *
  • 10 retries for default APN with a 500 default randomization value for each and - * the 4..10 retries all using 3000 as the delay: - *
    • "default:max_retries=10, default_randomization=500, 1000, 2000, 3000"
    - * - *
  • 4 retries for supl APN with a 100 as the default randomization value for the first 2 values - * and the other two having specified values of 500: - *
    • "supl:default_randomization=100, 1000, 2000, 4000:500, 5000:500"
    - * - *
  • Infinite number of retries for all other APNs with the first one at 1000, the second at 2000 - * all others will be at 3000. - *
    • "others:max_retries=infinite,1000,2000,3000
    - *
- * - * {@hide} - */ -public class RetryManager { - public static final String LOG_TAG = "RetryManager"; - public static final boolean DBG = true; - public static final boolean VDBG = false; // STOPSHIP if true - - /** - * The default retry configuration for APNs. See above for the syntax. - */ - private static final String DEFAULT_DATA_RETRY_CONFIG = "max_retries=3, 5000, 5000, 5000"; - - /** - * The APN type used for all other APNs retry configuration. - */ - private static final String OTHERS_APN_TYPE = "others"; - - /** - * The default value (in milliseconds) for delay between APN trying (mInterApnDelay) - * within the same round - */ - private static final long DEFAULT_INTER_APN_DELAY = 20000; - - /** - * The default value (in milliseconds) for delay between APN trying (mFailFastInterApnDelay) - * within the same round when we are in fail fast mode - */ - private static final long DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING = 3000; - - /** - * The default value (in milliseconds) for retrying APN after disconnect - */ - private static final long DEFAULT_APN_RETRY_AFTER_DISCONNECT_DELAY = 10000; - - /** - * The value indicating retry should not occur. - */ - public static final long NO_RETRY = Long.MAX_VALUE; - - /** - * The value indicating network did not suggest any retry delay - */ - public static final long NO_SUGGESTED_RETRY_DELAY = DataCallResponse.RETRY_DURATION_UNDEFINED; - - /** - * If the network suggests a retry delay in the data call setup response, we will retry - * the current APN setting again. The maximum retry count is to prevent that network - * keeps asking device to retry data setup forever and causes power consumption issue. - */ - private static final int DEFAULT_MAX_SAME_APN_RETRY = 3; - - /** - * The delay (in milliseconds) between APN trying within the same round - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long mInterApnDelay; - - /** - * The delay (in milliseconds) between APN trying within the same round when we are in - * fail fast mode - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long mFailFastInterApnDelay; - - /** - * The delay (in milliseconds) for APN retrying after disconnect (e.g. Modem suddenly reports - * data call lost) - */ - private long mApnRetryAfterDisconnectDelay; - - /** - * The counter for same APN retrying. See {@link #DEFAULT_MAX_SAME_APN_RETRY} for the details. - */ - private int mSameApnRetryCount = 0; - - /** - * The maximum times that frameworks retries data setup with the same APN. This value could be - * changed via carrier config. See {@link #DEFAULT_MAX_SAME_APN_RETRY} for the details. - */ - private int mMaxSameApnRetry = DEFAULT_MAX_SAME_APN_RETRY; - - /** - * Retry record with times in milli-seconds - */ - private static class RetryRec { - long mDelayTime; - long mRandomizationTime; - - RetryRec(long delayTime, long randomizationTime) { - mDelayTime = delayTime; - mRandomizationTime = randomizationTime; - } - } - - /** - * The array of retry records - */ - private ArrayList mRetryArray = new ArrayList(); - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private Phone mPhone; - - private final DataThrottler mDataThrottler; - - /** - * Flag indicating whether retrying forever regardless the maximum retry count mMaxRetryCount - */ - private boolean mRetryForever = false; - - /** - * The maximum number of retries to attempt - */ - private int mMaxRetryCount; - - /** - * The current number of retries - */ - private int mRetryCount = 0; - - /** - * Random number generator. The random delay will be added into retry timer to avoid all devices - * around retrying the APN at the same time. - */ - private Random mRng = new Random(); - - /** - * Retry manager configuration string. See top of the detailed explanation. - */ - private String mConfig; - - /** - * The list to store APN setting candidates for data call setup. Most of the carriers only have - * one APN, but few carriers have more than one. - */ - private ArrayList mWaitingApns = new ArrayList<>(); - - /** - * Index pointing to the current trying APN from mWaitingApns - */ - private int mCurrentApnIndex = -1; - - /** - * Apn context type. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private String mApnType; - - private final @ApnType int apnType; - - /** - * Retry manager constructor - * @param phone Phone object - * @param dataThrottler Data throttler - * @param apnType APN type - */ - public RetryManager(@NonNull Phone phone, @NonNull DataThrottler dataThrottler, - @ApnType int apnType) { - mPhone = phone; - mDataThrottler = dataThrottler; - this.apnType = apnType; - } - - /** - * Configure for using string which allow arbitrary - * sequences of times. See class comments for the - * string format. - * - * @return true if successful - */ - @UnsupportedAppUsage - private boolean configure(String configStr) { - // Strip quotes if present. - if ((configStr.startsWith("\"") && configStr.endsWith("\""))) { - configStr = configStr.substring(1, configStr.length() - 1); - } - - // Reset the retry manager since delay, max retry count, etc...will be reset. - reset(); - - if (DBG) log("configure: '" + configStr + "'"); - mConfig = configStr; - - if (!TextUtils.isEmpty(configStr)) { - long defaultRandomization = 0; - - if (VDBG) log("configure: not empty"); - - String strArray[] = configStr.split(","); - for (int i = 0; i < strArray.length; i++) { - if (VDBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'"); - Pair value; - String splitStr[] = strArray[i].split("=", 2); - splitStr[0] = splitStr[0].trim(); - if (VDBG) log("configure: splitStr[0]='" + splitStr[0] + "'"); - if (splitStr.length > 1) { - splitStr[1] = splitStr[1].trim(); - if (VDBG) log("configure: splitStr[1]='" + splitStr[1] + "'"); - if (TextUtils.equals(splitStr[0], "default_randomization")) { - value = parseNonNegativeInt(splitStr[0], splitStr[1]); - if (!value.first) return false; - defaultRandomization = value.second; - } else if (TextUtils.equals(splitStr[0], "max_retries")) { - if (TextUtils.equals("infinite", splitStr[1])) { - mRetryForever = true; - } else { - value = parseNonNegativeInt(splitStr[0], splitStr[1]); - if (!value.first) return false; - mMaxRetryCount = value.second; - } - } else { - Rlog.e(LOG_TAG, "Unrecognized configuration name value pair: " - + strArray[i]); - return false; - } - } else { - /** - * Assume a retry time with an optional randomization value - * following a ":" - */ - splitStr = strArray[i].split(":", 2); - splitStr[0] = splitStr[0].trim(); - RetryRec rr = new RetryRec(0, 0); - value = parseNonNegativeInt("delayTime", splitStr[0]); - if (!value.first) return false; - rr.mDelayTime = value.second; - - // Check if optional randomization value present - if (splitStr.length > 1) { - splitStr[1] = splitStr[1].trim(); - if (VDBG) log("configure: splitStr[1]='" + splitStr[1] + "'"); - value = parseNonNegativeInt("randomizationTime", splitStr[1]); - if (!value.first) return false; - rr.mRandomizationTime = value.second; - } else { - rr.mRandomizationTime = defaultRandomization; - } - mRetryArray.add(rr); - } - } - if (mRetryArray.size() > mMaxRetryCount) { - mMaxRetryCount = mRetryArray.size(); - if (VDBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount); - } - } else { - log("configure: cleared"); - } - - if (VDBG) log("configure: true"); - return true; - } - - /** - * Configure the retry manager - */ - private void configureRetry() { - String configString = null; - String otherConfigString = null; - - try { - if (TelephonyUtils.IS_DEBUGGABLE) { - // Using system properties is easier for testing from command line. - String config = SystemProperties.get("test.data_retry_config"); - if (!TextUtils.isEmpty(config)) { - configure(config); - return; - } - } - - CarrierConfigManager configManager = (CarrierConfigManager) - mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); - - mInterApnDelay = b.getLong( - CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, - DEFAULT_INTER_APN_DELAY); - mFailFastInterApnDelay = b.getLong( - CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, - DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING); - mApnRetryAfterDisconnectDelay = b.getLong( - CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, - DEFAULT_APN_RETRY_AFTER_DISCONNECT_DELAY); - mMaxSameApnRetry = b.getInt( - CarrierConfigManager - .KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, - DEFAULT_MAX_SAME_APN_RETRY); - - // Load all retry patterns for all different APNs. - String[] allConfigStrings = b.getStringArray( - CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS); - if (allConfigStrings != null) { - for (String s : allConfigStrings) { - if (!TextUtils.isEmpty(s)) { - String splitStr[] = s.split(":", 2); - if (splitStr.length == 2) { - String apnTypeStr = splitStr[0].trim(); - // Check if this retry pattern is for the APN we want. - if (apnTypeStr.equals(ApnSetting.getApnTypeString(apnType))) { - // Extract the config string. Note that an empty string is valid - // here, meaning no retry for the specified APN. - configString = splitStr[1]; - break; - } else if (apnTypeStr.equals(OTHERS_APN_TYPE)) { - // Extract the config string. Note that an empty string is valid - // here, meaning no retry for all other APNs. - otherConfigString = splitStr[1]; - } - } - } - } - } - - if (configString == null) { - if (otherConfigString != null) { - configString = otherConfigString; - } else { - // We should never reach here. If we reach here, it must be a configuration - // error bug. - log("Invalid APN retry configuration!. Use the default one now."); - configString = DEFAULT_DATA_RETRY_CONFIG; - } - } - } catch (NullPointerException ex) { - // We should never reach here unless there is a bug - log("Failed to read configuration! Use the hardcoded default value."); - - mInterApnDelay = DEFAULT_INTER_APN_DELAY; - mFailFastInterApnDelay = DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING; - configString = DEFAULT_DATA_RETRY_CONFIG; - } - - if (VDBG) { - log("mInterApnDelay = " + mInterApnDelay + ", mFailFastInterApnDelay = " + - mFailFastInterApnDelay); - } - - configure(configString); - } - - /** - * Return the timer that should be used to trigger the data reconnection - */ - @UnsupportedAppUsage - private long getRetryTimer() { - int index; - if (mRetryCount < mRetryArray.size()) { - index = mRetryCount; - } else { - index = mRetryArray.size() - 1; - } - - long retVal; - if ((index >= 0) && (index < mRetryArray.size())) { - retVal = mRetryArray.get(index).mDelayTime + nextRandomizationTime(index); - } else { - retVal = 0; - } - - if (DBG) log("getRetryTimer: " + retVal); - return retVal; - } - - /** - * Parse an integer validating the value is not negative. - * @param name Name - * @param stringValue Value - * @return Pair.first == true if stringValue an integer >= 0 - */ - private Pair parseNonNegativeInt(String name, String stringValue) { - int value; - Pair retVal; - try { - value = Integer.parseInt(stringValue); - retVal = new Pair<>(validateNonNegativeInt(name, value), value); - } catch (NumberFormatException e) { - Rlog.e(LOG_TAG, name + " bad value: " + stringValue, e); - retVal = new Pair<>(false, 0); - } - if (VDBG) { - log("parseNonNegativeInt: " + name + ", " + stringValue + ", " - + retVal.first + ", " + retVal.second); - } - return retVal; - } - - /** - * Validate an integer is >= 0 and logs an error if not - * @param name Name - * @param value Value - * @return Pair.first - */ - private boolean validateNonNegativeInt(String name, long value) { - boolean retVal; - if (value < 0) { - Rlog.e(LOG_TAG, name + " bad value: is < 0"); - retVal = false; - } else { - retVal = true; - } - if (VDBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal); - return retVal; - } - - /** - * Return next random number for the index - * @param index Retry index - */ - private long nextRandomizationTime(int index) { - long randomTime = mRetryArray.get(index).mRandomizationTime; - if (randomTime == 0) { - return 0; - } else { - return mRng.nextInt((int) randomTime); - } - } - - private long getNetworkSuggestedRetryDelay() { - long retryElapseTime = mDataThrottler.getRetryTime(apnType); - if (retryElapseTime == NO_RETRY || retryElapseTime == NO_SUGGESTED_RETRY_DELAY) { - return retryElapseTime; - } - - // The time from data throttler is system's elapsed time. We need to return the delta. If - // less than 0, then return 0 (i.e. retry immediately). - return Math.max(0, retryElapseTime - SystemClock.elapsedRealtime()); - } - - /** - * Get the next APN setting for data call setup. - * @return APN setting to try. {@code null} if cannot find any APN, - */ - public @Nullable ApnSetting getNextApnSetting() { - if (mWaitingApns == null || mWaitingApns.size() == 0) { - log("Waiting APN list is null or empty."); - return null; - } - - long networkSuggestedRetryDelay = getNetworkSuggestedRetryDelay(); - if (networkSuggestedRetryDelay == NO_RETRY) { - log("Network suggested no retry."); - return null; - } - - // If the network had suggested a retry delay, we should retry the current APN again - // (up to mMaxSameApnRetry times) instead of getting the next APN setting from - // our own list. If the APN waiting list has been reset before a setup data responses - // arrive (i.e. mCurrentApnIndex=-1), then ignore the network suggested retry. - if (mCurrentApnIndex != -1 && networkSuggestedRetryDelay != NO_SUGGESTED_RETRY_DELAY - && mSameApnRetryCount < mMaxSameApnRetry) { - mSameApnRetryCount++; - return mWaitingApns.get(mCurrentApnIndex); - } - - mSameApnRetryCount = 0; - - int index = mCurrentApnIndex; - // Loop through the APN list to find out the index of next non-permanent failed APN. - while (true) { - if (++index == mWaitingApns.size()) index = 0; - - // Stop if we find the non-failed APN. - if (!mWaitingApns.get(index).getPermanentFailed()) { - break; - } - - // If all APNs have permanently failed, bail out. - if (mWaitingApns.stream().allMatch(ApnSetting::getPermanentFailed)) { - return null; - } - } - - mCurrentApnIndex = index; - return mWaitingApns.get(mCurrentApnIndex); - } - - /** - * Get the delay for trying the next waiting APN from the list. - * @param failFastEnabled True if fail fast mode enabled. In this case we'll use a shorter - * delay. - * @return delay in milliseconds - */ - public long getDelayForNextApn(boolean failFastEnabled) { - - if (mWaitingApns == null || mWaitingApns.size() == 0) { - log("Waiting APN list is null or empty."); - return NO_RETRY; - } - - long networkSuggestedDelay = getNetworkSuggestedRetryDelay(); - log("Network suggested delay=" + networkSuggestedDelay + "ms"); - - if (networkSuggestedDelay == NO_RETRY) { - log("Network suggested not retrying."); - return NO_RETRY; - } - - if (networkSuggestedDelay != NO_SUGGESTED_RETRY_DELAY - && mSameApnRetryCount < mMaxSameApnRetry) { - // If the network explicitly suggests a retry delay, we should use it, even in fail fast - // mode. - log("Network suggested retry in " + networkSuggestedDelay + " ms."); - return networkSuggestedDelay; - } - - // In order to determine the delay to try next APN, we need to peek the next available APN. - // Case 1 - If we will start the next round of APN trying, - // we use the exponential-growth delay. (e.g. 5s, 10s, 30s...etc.) - // Case 2 - If we are still within the same round of APN trying, - // we use the fixed standard delay between APNs. (e.g. 20s) - - int index = mCurrentApnIndex; - while (true) { - if (++index >= mWaitingApns.size()) index = 0; - - // Stop if we find the non-failed APN. - if (!mWaitingApns.get(index).getPermanentFailed()) { - break; - } - - // If all APNs have permanently failed, bail out. - if (mWaitingApns.stream().allMatch(ApnSetting::getPermanentFailed)) { - log("All APNs have permanently failed."); - return NO_RETRY; - } - } - - long delay; - if (index <= mCurrentApnIndex) { - // Case 1, if the next APN is in the next round. - if (!mRetryForever && mRetryCount + 1 > mMaxRetryCount) { - log("Reached maximum retry count " + mMaxRetryCount + "."); - return NO_RETRY; - } - delay = getRetryTimer(); - ++mRetryCount; - } else { - // Case 2, if the next APN is still in the same round. - delay = mInterApnDelay; - } - - if (failFastEnabled && delay > mFailFastInterApnDelay) { - // If we enable fail fast mode, and the delay we got is longer than - // fail-fast delay (mFailFastInterApnDelay), use the fail-fast delay. - // If the delay we calculated is already shorter than fail-fast delay, - // then ignore fail-fast delay. - delay = mFailFastInterApnDelay; - } - - return delay; - } - - /** - * Mark the APN setting permanently failed. - * @param apn APN setting to be marked as permanently failed - * */ - public void markApnPermanentFailed(ApnSetting apn) { - if (apn != null) { - apn.setPermanentFailed(true); - } - } - - /** - * Reset the retry manager. - */ - private void reset() { - mMaxRetryCount = 0; - mRetryCount = 0; - mCurrentApnIndex = -1; - mSameApnRetryCount = 0; - mRetryArray.clear(); - } - - /** - * Set waiting APNs for retrying in case needed. - * @param waitingApns Waiting APN list - */ - public void setWaitingApns(ArrayList waitingApns) { - - if (waitingApns == null) { - log("No waiting APNs provided"); - return; - } - - mWaitingApns = waitingApns; - - // Since we replace the entire waiting APN list, we need to re-config this retry manager. - configureRetry(); - - for (ApnSetting apn : mWaitingApns) { - apn.setPermanentFailed(false); - } - - log("Setting " + mWaitingApns.size() + " waiting APNs."); - - if (VDBG) { - for (int i = 0; i < mWaitingApns.size(); i++) { - log(" [" + i + "]:" + mWaitingApns.get(i)); - } - } - } - - /** - * Get the list of waiting APNs. - * @return the list of waiting APNs - */ - public @NonNull ArrayList getWaitingApns() { - return mWaitingApns; - } - - /** - * Get the delay in milliseconds for APN retry after disconnect - * @return The delay in milliseconds - */ - public long getRetryAfterDisconnectDelay() { - return mApnRetryAfterDisconnectDelay; - } - - public String toString() { - if (mConfig == null) return ""; - return "RetryManager: apnType=" + ApnSetting.getApnTypeString(apnType) - + " mRetryCount=" - + mRetryCount + " mMaxRetryCount=" + mMaxRetryCount + " mCurrentApnIndex=" - + mCurrentApnIndex + " mSameApnRtryCount=" + mSameApnRetryCount - + " networkSuggestedDelay=" + getNetworkSuggestedRetryDelay() + " mRetryForever=" - + mRetryForever + " mInterApnDelay=" + mInterApnDelay - + " mApnRetryAfterDisconnectDelay=" + mApnRetryAfterDisconnectDelay - + " mConfig={" + mConfig + "}"; - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private void log(String s) { - Rlog.d(LOG_TAG, "[" + ApnSetting.getApnTypeString(apnType) + "] " + s); - } -} diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 99ee96bc24..d362a20d07 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -37,7 +37,6 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.res.Resources; import android.hardware.radio.V1_0.CellInfoType; -import android.net.NetworkCapabilities; import android.os.AsyncResult; import android.os.BaseBundle; import android.os.Build; @@ -95,7 +94,6 @@ import com.android.internal.telephony.cdnr.CarrierDisplayNameResolver; import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetwork; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; -import com.android.internal.telephony.dataconnection.DataConnection; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.TelephonyMetrics; @@ -224,7 +222,6 @@ public class ServiceStateTracker extends Handler { /* Radio power off pending flag and tag counter */ private boolean mPendingRadioPowerOffAfterDataOff = false; - private int mPendingRadioPowerOffAfterDataOffTag = 0; /** Waiting period before recheck gprs and voice registration. */ public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; @@ -721,17 +718,15 @@ public class ServiceStateTracker extends Handler { registerForImsCapabilityChanged(mCSST, CarrierServiceStateTracker.CARRIER_EVENT_IMS_CAPABILITIES_CHANGED, null); - if (mPhone.isUsingNewDataStack()) { - mDataDisconnectedCallback = new DataNetworkControllerCallback(this::post) { - @Override - public void onAnyDataNetworkExistingChanged(boolean anyDataExisting) { - log("onAnyDataNetworkExistingChanged: anyDataExisting=" + anyDataExisting); - if (!anyDataExisting) { - sendEmptyMessage(EVENT_ALL_DATA_DISCONNECTED); - } + mDataDisconnectedCallback = new DataNetworkControllerCallback(this::post) { + @Override + public void onAnyDataNetworkExistingChanged(boolean anyDataExisting) { + log("onAnyDataNetworkExistingChanged: anyDataExisting=" + anyDataExisting); + if (!anyDataExisting) { + sendEmptyMessage(EVENT_ALL_DATA_DISCONNECTED); } - }; - } + } + }; } @VisibleForTesting @@ -1197,22 +1192,9 @@ public class ServiceStateTracker extends Handler { switch (msg.what) { case EVENT_SET_RADIO_POWER_OFF: synchronized(this) { - if (mPhone.isUsingNewDataStack()) { - mPendingRadioPowerOffAfterDataOff = false; - log("Wait for all data networks torn down timed out. Power off now."); - hangupAndPowerOff(); - return; - } - if (mPendingRadioPowerOffAfterDataOff && - (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) { - if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now."); - hangupAndPowerOff(); - mPendingRadioPowerOffAfterDataOffTag += 1; - mPendingRadioPowerOffAfterDataOff = false; - } else { - log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 + - "!= tag=" + mPendingRadioPowerOffAfterDataOffTag); - } + mPendingRadioPowerOffAfterDataOff = false; + log("Wait for all data networks torn down timed out. Power off now."); + hangupAndPowerOff(); } break; @@ -1480,41 +1462,26 @@ public class ServiceStateTracker extends Handler { break; case EVENT_ALL_DATA_DISCONNECTED: - if (mPhone.isUsingNewDataStack()) { - log("EVENT_ALL_DATA_DISCONNECTED"); - if (!mPendingRadioPowerOffAfterDataOff) return; - boolean areAllDataDisconnectedOnAllPhones = true; - for (Phone phone : PhoneFactory.getPhones()) { - if (phone.getDataNetworkController().areAllDataDisconnected()) { - phone.getDataNetworkController() - .unregisterDataNetworkControllerCallback( - mDataDisconnectedCallback); - } else { - log("Still waiting for all data disconnected on phone: " - + phone.getSubId()); - areAllDataDisconnectedOnAllPhones = false; - } - } - if (areAllDataDisconnectedOnAllPhones) { - mPendingRadioPowerOffAfterDataOff = false; - removeMessages(EVENT_SET_RADIO_POWER_OFF); - if (DBG) log("Data disconnected for all phones, turn radio off now."); - hangupAndPowerOff(); - } - return; - } - int dds = SubscriptionManager.getDefaultDataSubscriptionId(); - ProxyController.getInstance().unregisterForAllDataDisconnected(dds, this); - synchronized(this) { - if (mPendingRadioPowerOffAfterDataOff) { - if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now."); - hangupAndPowerOff(); - mPendingRadioPowerOffAfterDataOffTag += 1; - mPendingRadioPowerOffAfterDataOff = false; + log("EVENT_ALL_DATA_DISCONNECTED"); + if (!mPendingRadioPowerOffAfterDataOff) return; + boolean areAllDataDisconnectedOnAllPhones = true; + for (Phone phone : PhoneFactory.getPhones()) { + if (phone.getDataNetworkController().areAllDataDisconnected()) { + phone.getDataNetworkController() + .unregisterDataNetworkControllerCallback( + mDataDisconnectedCallback); } else { - log("EVENT_ALL_DATA_DISCONNECTED is stale"); + log("Still waiting for all data disconnected on phone: " + + phone.getSubId()); + areAllDataDisconnectedOnAllPhones = false; } } + if (areAllDataDisconnectedOnAllPhones) { + mPendingRadioPowerOffAfterDataOff = false; + removeMessages(EVENT_SET_RADIO_POWER_OFF); + if (DBG) log("Data disconnected for all phones, turn radio off now."); + hangupAndPowerOff(); + } break; case EVENT_CHANGE_IMS_STATE: @@ -2165,18 +2132,8 @@ public class ServiceStateTracker extends Handler { private boolean isInternetPhysicalChannelConfig(PhysicalChannelConfig config) { for (int cid : config.getContextIds()) { - if (mPhone.isUsingNewDataStack()) { - if (mPhone.getDataNetworkController().isInternetNetwork(cid)) { - return true; - } - } else { - DataConnection dc = mPhone.getDcTracker( - AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .getDataConnectionByContextId(cid); - if (dc != null && dc.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_INTERNET)) { - return true; - } + if (mPhone.getDataNetworkController().isInternetNetwork(cid)) { + return true; } } return false; @@ -3135,17 +3092,8 @@ public class ServiceStateTracker extends Handler { mCi.setRadioPower(true, forEmergencyCall, isSelectedPhoneForEmergencyCall, null); } else if ((!mDesiredPowerState || mRadioDisabledByCarrier) && mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) { - // If it's on and available and we want it off gracefully - if (!mPhone.isUsingNewDataStack() && mImsRegistrationOnOff - && getRadioPowerOffDelayTimeoutForImsRegistration() > 0) { - if (DBG) log("setPowerStateToDesired: delaying power off until IMS dereg."); - startDelayRadioOffWaitingForImsDeregTimeout(); - // Return early here as we do not want to hit the cancel timeout code below. - return; - } else { - if (DBG) log("setPowerStateToDesired: powerOffRadioSafely()"); - powerOffRadioSafely(); - } + if (DBG) log("setPowerStateToDesired: powerOffRadioSafely()"); + powerOffRadioSafely(); } else if (mDeviceShuttingDown && (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE)) { // !mDesiredPowerState condition above will happen first if the radio is on, so we will @@ -3519,11 +3467,6 @@ public class ServiceStateTracker extends Handler { NetworkRegistrationInfo newNrs = mNewSS.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, transport); - // If the previously it was not in service, and now it's in service, trigger the - // attached event. Also if airplane mode was just turned on, and data is already in - // service, we need to trigger the attached event again so that DcTracker can setup - // data on all connectable APNs again (because we've already torn down all data - // connections just before airplane mode turned on) boolean changed = (oldNrs == null || !oldNrs.isInService() || hasAirplaneModeOnChanged) && (newNrs != null && newNrs.isInService()); hasDataAttached.put(transport, changed); @@ -5022,96 +4965,33 @@ public class ServiceStateTracker extends Handler { public void powerOffRadioSafely() { synchronized (this) { if (!mPendingRadioPowerOffAfterDataOff) { - if (mPhone.isUsingNewDataStack()) { - // hang up all active voice calls first - if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) { - mPhone.mCT.mRingingCall.hangupIfAlive(); - mPhone.mCT.mBackgroundCall.hangupIfAlive(); - mPhone.mCT.mForegroundCall.hangupIfAlive(); - } + // hang up all active voice calls first + if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) { + mPhone.mCT.mRingingCall.hangupIfAlive(); + mPhone.mCT.mBackgroundCall.hangupIfAlive(); + mPhone.mCT.mForegroundCall.hangupIfAlive(); + } - for (Phone phone : PhoneFactory.getPhones()) { - if (!phone.getDataNetworkController().areAllDataDisconnected()) { - log("powerOffRadioSafely: Data is active on phone " + phone.getSubId() - + ". Wait for all data disconnect."); - mPendingRadioPowerOffAfterDataOff = true; - phone.getDataNetworkController().registerDataNetworkControllerCallback( - mDataDisconnectedCallback); - } + for (Phone phone : PhoneFactory.getPhones()) { + if (!phone.getDataNetworkController().areAllDataDisconnected()) { + log("powerOffRadioSafely: Data is active on phone " + phone.getSubId() + + ". Wait for all data disconnect."); + mPendingRadioPowerOffAfterDataOff = true; + phone.getDataNetworkController().registerDataNetworkControllerCallback( + mDataDisconnectedCallback); } + } - // Tear down outside of the disconnected check to prevent race conditions. - mPhone.getDataNetworkController().tearDownAllDataNetworks( - DataNetwork.TEAR_DOWN_REASON_AIRPLANE_MODE_ON); + // Tear down outside of the disconnected check to prevent race conditions. + mPhone.getDataNetworkController().tearDownAllDataNetworks( + DataNetwork.TEAR_DOWN_REASON_AIRPLANE_MODE_ON); - if (mPendingRadioPowerOffAfterDataOff) { - sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, - POWER_OFF_ALL_DATA_NETWORKS_DISCONNECTED_TIMEOUT); - } else { - log("powerOffRadioSafely: No data is connected, turn off radio now."); - hangupAndPowerOff(); - } - return; - } - int dds = SubscriptionManager.getDefaultDataSubscriptionId(); - // To minimize race conditions we call cleanUpAllConnections on - // both if else paths instead of before this isDisconnected test. - if (mPhone.areAllDataDisconnected() - && (dds == mPhone.getSubId() - || (dds != mPhone.getSubId() - && ProxyController.getInstance().areAllDataDisconnected(dds)))) { - // To minimize race conditions we do this after isDisconnected - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - if (mPhone.getDcTracker(transport) != null) { - mPhone.getDcTracker(transport).cleanUpAllConnections( - Phone.REASON_RADIO_TURNED_OFF); - } - } - if (DBG) { - log("powerOffRadioSafely: Data disconnected, turn off radio now."); - } - hangupAndPowerOff(); + if (mPendingRadioPowerOffAfterDataOff) { + sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, + POWER_OFF_ALL_DATA_NETWORKS_DISCONNECTED_TIMEOUT); } else { - // hang up all active voice calls first - if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) { - mPhone.mCT.mRingingCall.hangupIfAlive(); - mPhone.mCT.mBackgroundCall.hangupIfAlive(); - mPhone.mCT.mForegroundCall.hangupIfAlive(); - } - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - if (mPhone.getDcTracker(transport) != null) { - mPhone.getDcTracker(transport).cleanUpAllConnections( - Phone.REASON_RADIO_TURNED_OFF); - } - } - - if (dds != mPhone.getSubId() - && !ProxyController.getInstance().areAllDataDisconnected(dds)) { - if (DBG) { - log(String.format("powerOffRadioSafely: Data is active on DDS (%d)." - + " Wait for all data disconnect", dds)); - } - // Data is not disconnected on DDS. Wait for the data disconnect complete - // before sending the RADIO_POWER off. - ProxyController.getInstance().registerForAllDataDisconnected(dds, this, - EVENT_ALL_DATA_DISCONNECTED); - mPendingRadioPowerOffAfterDataOff = true; - } - Message msg = Message.obtain(this); - msg.what = EVENT_SET_RADIO_POWER_OFF; - msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag; - if (sendMessageDelayed(msg, 30000)) { - if (DBG) { - log("powerOffRadioSafely: Wait up to 30s for data to disconnect, " - + "then turn off radio."); - } - mPendingRadioPowerOffAfterDataOff = true; - } else { - log("powerOffRadioSafely: Cannot send delayed Msg, turn off radio right" - + " away."); - hangupAndPowerOff(); - mPendingRadioPowerOffAfterDataOff = false; - } + log("powerOffRadioSafely: No data is connected, turn off radio now."); + hangupAndPowerOff(); } } } @@ -5127,7 +5007,6 @@ public class ServiceStateTracker extends Handler { if (mPendingRadioPowerOffAfterDataOff) { if (DBG) log("Process pending request to turn radio off."); hangupAndPowerOff(); - mPendingRadioPowerOffAfterDataOffTag += 1; mPendingRadioPowerOffAfterDataOff = false; return true; } @@ -5361,7 +5240,6 @@ public class ServiceStateTracker extends Handler { pw.println(" mDesiredPowerState=" + mDesiredPowerState); pw.println(" mRestrictedState=" + mRestrictedState); pw.println(" mPendingRadioPowerOffAfterDataOff=" + mPendingRadioPowerOffAfterDataOff); - pw.println(" mPendingRadioPowerOffAfterDataOffTag=" + mPendingRadioPowerOffAfterDataOffTag); pw.println(" mCellIdentity=" + Rlog.pii(VDBG, mCellIdentity)); pw.println(" mLastCellInfoReqTime=" + mLastCellInfoReqTime); dumpCellInfoList(pw); diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java index dcbd2d5a95..08c02e2ea9 100644 --- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java +++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java @@ -27,7 +27,6 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.system.StructStatVfs; -import android.telephony.AccessNetworkConstants.TransportType; import android.text.TextUtils; import com.android.ims.ImsManager; @@ -40,9 +39,6 @@ import com.android.internal.telephony.data.DataServiceManager; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; -import com.android.internal.telephony.dataconnection.DcTracker; -import com.android.internal.telephony.dataconnection.TransportManager; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; @@ -313,10 +309,6 @@ public class TelephonyComponentFactory { return new SimActivationTracker(phone); } - public DcTracker makeDcTracker(Phone phone, @TransportType int transportType) { - return new DcTracker(phone, transportType); - } - public CarrierSignalAgent makeCarrierSignalAgent(Phone phone) { return new CarrierSignalAgent(phone); } @@ -404,10 +396,6 @@ public class TelephonyComponentFactory { return new DeviceStateMonitor(phone); } - public TransportManager makeTransportManager(Phone phone) { - return new TransportManager(phone); - } - /** * Make access networks manager * @@ -430,10 +418,6 @@ public class TelephonyComponentFactory { return new LocaleTracker(phone, nitzStateMachine, looper); } - public DataEnabledSettings makeDataEnabledSettings(Phone phone) { - return new DataEnabledSettings(phone); - } - public Phone makePhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory) { diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index e7734d5954..57b36022fc 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -58,7 +58,6 @@ import android.util.SparseArray; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RIL; import com.android.internal.telephony.SlidingWindowEventCounter; -import com.android.internal.telephony.dataconnection.DataThrottler; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -67,7 +66,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -155,8 +153,6 @@ public class AccessNetworksManager extends Handler { private final RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList(); - private final Set mDataThrottlers = new HashSet<>(); - private final BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -173,20 +169,10 @@ public class AccessNetworksManager extends Handler { } }; - /** - * The current transport of the APN type. The key is the APN type, and the value is the - * transport. - */ - private final Map mCurrentTransports = new ConcurrentHashMap<>(); - /** * The preferred transport of the APN type. The key is the APN type, and the value is the - * transport. The preferred transports are updated as soon as QNS changes the preference, while - * the current transports are updated after handover complete. + * transport. The preferred transports are updated as soon as QNS changes the preference. */ - // TODO: Deprecate mPreferredTransports. Should expose mAvailableNetworks to - // DataNetworkController after we support multi preferred access networks (i.e. - // DataNetworkController might select 2nd preferred access network in some scenarios.) private final Map mPreferredTransports = new ConcurrentHashMap<>(); /** @@ -195,21 +181,6 @@ public class AccessNetworksManager extends Handler { private final @NonNull Set mAccessNetworksManagerCallbacks = new ArraySet<>(); - /** - * Registers the data throttler in order to receive APN status changes. - * - * @param dataThrottler the data throttler to register - */ - public void registerDataThrottler(DataThrottler dataThrottler) { - this.post(() -> { - QualifiedNetworksServiceConnection serviceConnection = mServiceConnection; - this.mDataThrottlers.add(dataThrottler); - if (serviceConnection != null) { - serviceConnection.registerDataThrottler(dataThrottler); - } - }); - } - /** * Represents qualified network types list on a specific APN type. */ @@ -251,18 +222,6 @@ public class AccessNetworksManager extends Handler { } private final class QualifiedNetworksServiceConnection implements ServiceConnection { - - /** - * The APN throttle status callback is attached to the service connection so that they have - * the same life cycle. - */ - @NonNull - private final ThrottleStatusChangedCallback mThrottleStatusCallback; - - QualifiedNetworksServiceConnection() { - mThrottleStatusCallback = new ThrottleStatusChangedCallback(); - } - @Override public void onServiceConnected(ComponentName name, IBinder service) { if (DBG) log("onServiceConnected " + name); @@ -274,9 +233,6 @@ public class AccessNetworksManager extends Handler { service.linkToDeath(mDeathRecipient, 0 /* flags */); mIQualifiedNetworksService.createNetworkAvailabilityProvider(mPhone.getPhoneId(), new QualifiedNetworksServiceCallback()); - - registerDataThrottlersFirstTime(); - } catch (RemoteException e) { loge("Remote exception. " + e); } @@ -285,55 +241,9 @@ public class AccessNetworksManager extends Handler { @Override public void onServiceDisconnected(ComponentName name) { if (DBG) log("onServiceDisconnected " + name); - unregisterForThrottleCallbacks(); mTargetBindingPackageName = null; } - /** - * Runs on all of the data throttlers when the service is connected - */ - private void registerDataThrottlersFirstTime() { - post(() -> { - for (DataThrottler dataThrottler : mDataThrottlers) { - dataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); - } - }); - } - - private void registerDataThrottler(DataThrottler dataThrottler) { - post(() -> { - dataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); - }); - } - - private void unregisterForThrottleCallbacks() { - post(() -> { - for (DataThrottler dataThrottler : mDataThrottlers) { - dataThrottler.unregisterForThrottleStatusChanges(mThrottleStatusCallback); - } - }); - } - } - - private class ThrottleStatusChangedCallback implements DataThrottler.Callback { - @Override - public void onThrottleStatusChanged(List throttleStatuses) { - post(() -> { - try { - List throttleStatusesBySlot = - throttleStatuses - .stream() - .filter(x -> x.getSlotIndex() == mPhone.getPhoneId()) - .collect(Collectors.toList()); - if (mIQualifiedNetworksService != null) { - mIQualifiedNetworksService.reportThrottleStatusChanged(mPhone.getPhoneId(), - throttleStatusesBySlot); - } - } catch (Exception ex) { - loge("onThrottleStatusChanged", ex); - } - }); - } } private final class QualifiedNetworksServiceCallback extends @@ -505,11 +415,10 @@ public class AccessNetworksManager extends Handler { bindQualifiedNetworksService(); } - if (phone.isUsingNewDataStack()) { - // Using post to delay the registering because data retry manager and data config - // manager instances are created later than access networks manager. - post(() -> { - mPhone.getDataNetworkController().getDataRetryManager().registerCallback( + // Using post to delay the registering because data retry manager and data config + // manager instances are created later than access networks manager. + post(() -> { + mPhone.getDataNetworkController().getDataRetryManager().registerCallback( new DataRetryManager.DataRetryManagerCallback(this::post) { @Override public void onThrottleStatusChanged(List throttleStatuses) { @@ -524,16 +433,15 @@ public class AccessNetworksManager extends Handler { } } }); - mDataConfigManager = mPhone.getDataNetworkController().getDataConfigManager(); - mDataConfigManager.registerCallback( - new DataConfigManager.DataConfigManagerCallback(this::post) { - @Override - public void onDeviceConfigChanged() { - mApnTypeToQnsChangeNetworkCounter.clear(); - } - }); - }); - } + mDataConfigManager = mPhone.getDataNetworkController().getDataConfigManager(); + mDataConfigManager.registerCallback( + new DataConfigManager.DataConfigManagerCallback(this::post) { + @Override + public void onDeviceConfigChanged() { + mApnTypeToQnsChangeNetworkCounter.clear(); + } + }); + }); } /** @@ -713,60 +621,6 @@ public class AccessNetworksManager extends Handler { return mAvailableTransports; } - /** - * Get the transport based on the network capability. - * - * @param netCap The network capability. - * @return The transport type. - */ - public @TransportType int getCurrentTransportByNetworkCapability(@NetCapability int netCap) { - return getCurrentTransport(DataUtils.networkCapabilityToApnType(netCap)); - } - - /** - * Get the transport based on the APN type. - * - * @param apnType APN type - * @return The transport type - */ - // TODO: Remove this after TransportManager is removed. - public @TransportType int getCurrentTransport(@ApnType int apnType) { - // In legacy mode, always route to cellular. - if (isInLegacyMode()) { - return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - } - - // If we can't find the corresponding transport, always route to cellular. - return mCurrentTransports.get(apnType) == null - ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mCurrentTransports.get(apnType); - } - - /** - * Set the current transport of a network capability. - * - * @param netCap The network capability. - * @param transport The transport. - */ - public void setCurrentTransportByNetworkCapability(@NetCapability int netCap, - @TransportType int transport) { - setCurrentTransport(DataUtils.networkCapabilityToApnType(netCap), transport); - } - - /** - * Set the current transport of apn type. - * - * @param apnType The APN type - * @param transport The transport. - */ - // TODO: Remove this after TransportManager is removed. - public void setCurrentTransport(@ApnType int apnType, @TransportType int transport) { - Integer previousTransport = mCurrentTransports.put(apnType, transport); - if (previousTransport == null || previousTransport != transport) { - logl("setCurrentTransport: apnType=" + ApnSetting.getApnTypeString(apnType) - + ", transport=" + AccessNetworkConstants.transportTypeToString(transport)); - } - } - private static @TransportType int getTransportFromAccessNetwork(int accessNetwork) { return accessNetwork == AccessNetworkType.IWLAN ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN @@ -825,20 +679,14 @@ public class AccessNetworksManager extends Handler { } /** - * Check if there is any APN type's current transport is on IWLAN. + * Check if there is any APN type preferred on IWLAN. * * @return {@code true} if there is any APN is on IWLAN, otherwise {@code false}. */ public boolean isAnyApnOnIwlan() { for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { - if (mPhone.isUsingNewDataStack()) { - if (getPreferredTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - return true; - } - } else { - if (getCurrentTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - return true; - } + if (getPreferredTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { + return true; } } return false; @@ -902,14 +750,6 @@ public class AccessNetworksManager extends Handler { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println(AccessNetworksManager.class.getSimpleName() + "-" + mPhone.getPhoneId() + ":"); pw.increaseIndent(); - pw.println("current transports="); - pw.increaseIndent(); - for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { - pw.println(ApnSetting.getApnTypeString(apnType) - + ": " + AccessNetworkConstants.transportTypeToString( - getCurrentTransport(apnType))); - } - pw.decreaseIndent(); pw.println("preferred transports="); pw.increaseIndent(); for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index b71db48eae..cc03fd478c 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -134,8 +134,7 @@ public class DataConfigManager extends Handler { private static final String DATA_CONFIG_NETWORK_TYPE_IDEN = "iDEN"; /** Network type LTE. Should not be used outside of DataConfigManager. */ - // TODO: Public only for use by DcTracker. This should be private once DcTracker is removed. - public static final String DATA_CONFIG_NETWORK_TYPE_LTE = "LTE"; + private static final String DATA_CONFIG_NETWORK_TYPE_LTE = "LTE"; /** Network type HSPA+. Should not be used outside of DataConfigManager. */ private static final String DATA_CONFIG_NETWORK_TYPE_HSPAP = "HSPA+"; @@ -153,12 +152,10 @@ public class DataConfigManager extends Handler { private static final String DATA_CONFIG_NETWORK_TYPE_LTE_CA = "LTE_CA"; /** Network type NR_NSA. Should not be used outside of DataConfigManager. */ - // TODO: Public only for use by DcTracker. This should be private once DcTracker is removed. - public static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA = "NR_NSA"; + private static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA = "NR_NSA"; /** Network type NR_NSA_MMWAVE. Should not be used outside of DataConfigManager. */ - // TODO: Public only for use by DcTracker. This should be private once DcTracker is removed. - public static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE = "NR_NSA_MMWAVE"; + private static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE = "NR_NSA_MMWAVE"; /** Network type NR_SA. Should not be used outside of DataConfigManager. */ private static final String DATA_CONFIG_NETWORK_TYPE_NR_SA = "NR_SA"; @@ -985,9 +982,8 @@ public class DataConfigManager extends Handler { * @param displayInfo The {@link TelephonyDisplayInfo} used to determine the type. * @return The equivalent {@link DataConfigNetworkType}. */ - public static @NonNull @DataConfigNetworkType String getDataConfigNetworkType( + private static @NonNull @DataConfigNetworkType String getDataConfigNetworkType( @NonNull TelephonyDisplayInfo displayInfo) { - // TODO: Make method private once DataConnection is removed int networkType = displayInfo.getNetworkType(); switch (displayInfo.getOverrideNetworkType()) { case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED: diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index c225b3f2ad..fbeabc1d7b 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -32,8 +32,6 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Message; import android.os.OutcomeReceiver; -import android.os.Registrant; -import android.os.RegistrantList; import android.preference.PreferenceManager; import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.DataActivityType; @@ -191,7 +189,6 @@ public class LinkBandwidthEstimator extends Handler { private String mBandwidthUpdatePlmn = UNKNOWN_PLMN; private BandwidthState mTxState = new BandwidthState(LINK_TX); private BandwidthState mRxState = new BandwidthState(LINK_RX); - private RegistrantList mBandwidthChangedRegistrants = new RegistrantList(); private long mLastPlmnOrRatChangeTimeMs; private long mLastDrsOrRatChangeTimeMs; @@ -350,33 +347,6 @@ public class LinkBandwidthEstimator extends Handler { } } - /** - * Registers for bandwidth estimation change. The bandwidth will be returned - * * {@link AsyncResult#result} as a {@link Pair} Object. - * * The {@link AsyncResult} will be in the notification {@link Message#obj}. - * @param h handler to notify - * @param what what code of message when delivered - * @param obj placed in Message.obj - * - * @deprecated Use {@link #registerCallback(LinkBandwidthEstimatorCallback)}. - */ - @Deprecated //TODO: Remove once old data stack is removed. - public void registerForBandwidthChanged(Handler h, int what, Object obj) { - Registrant r = new Registrant(h, what, obj); - mBandwidthChangedRegistrants.add(r); - } - - /** - * Unregisters for bandwidth estimation change. - * @param h handler to notify - * - * @deprecated Use {@link #unregisterCallback(LinkBandwidthEstimatorCallback)}. - */ - @Deprecated //TODO: Remove once old data stack is removed. - public void unregisterForBandwidthChanged(Handler h) { - mBandwidthChangedRegistrants.remove(h); - } - /** * Register the callback for receiving information from {@link LinkBandwidthEstimator}. * @@ -930,9 +900,6 @@ public class LinkBandwidthEstimator extends Handler { private void sendLinkBandwidthToDataConnection(int linkBandwidthTxKps, int linkBandwidthRxKps) { logv("send to DC tx " + linkBandwidthTxKps + " rx " + linkBandwidthRxKps); - Pair bandwidthInfo = - new Pair(linkBandwidthTxKps, linkBandwidthRxKps); - mBandwidthChangedRegistrants.notifyRegistrants(new AsyncResult(null, bandwidthInfo, null)); mLinkBandwidthEstimatorCallbacks.forEach(callback -> callback.invokeFromExecutor( () -> callback.onBandwidthChanged(linkBandwidthTxKps, linkBandwidthRxKps))); } diff --git a/src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java b/src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java deleted file mode 100644 index 554177ad2c..0000000000 --- a/src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2021 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.data; - -import android.annotation.NonNull; -import android.net.NetworkAgent; -import android.net.QosSessionAttributes; - -/** - * The temporary interface that is shared by - * {@link com.android.internal.telephony.dataconnection.DcNetworkAgent} and - * {@link com.android.internal.telephony.data.TelephonyNetworkAgent} so they can both interact - * with {@link QosCallbackTracker}. - */ -// TODO: Remove after DcNetworkAgent is removed. -public interface NotifyQosSessionInterface { - /** - * Sends the attributes of Qos Session back to the Application. This method is create for - * Mockito to mock since - * {@link NetworkAgent#sendQosSessionAvailable(int, int, QosSessionAttributes)} is - * {@code final} that can't be mocked. - * - * @param qosCallbackId the callback id that the session belongs to. - * @param sessionId the unique session id across all Qos Sessions. - * @param attributes the attributes of the Qos Session. - */ - void notifyQosSessionAvailable(int qosCallbackId, int sessionId, - @NonNull QosSessionAttributes attributes); - - /** - * Sends event that the Qos Session was lost. This method is create for Mockito to mock - * since {@link NetworkAgent#sendQosSessionLost(int, int, int)} is {@code final} that can't be - * mocked.. - * - * @param qosCallbackId the callback id that the session belongs to. - * @param sessionId the unique session id across all Qos Sessions. - * @param qosSessionType the session type {@code QosSession#QosSessionType}. - */ - void notifyQosSessionLost(int qosCallbackId, int sessionId, int qosSessionType); -} diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index cc5f44738b..47ae22503a 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -83,8 +83,6 @@ import com.android.internal.telephony.SubscriptionController.WatchedInt; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; -import com.android.internal.telephony.dataconnection.ApnConfigTypeRepository; -import com.android.internal.telephony.dataconnection.DcRequest; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch; @@ -96,7 +94,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -182,7 +179,6 @@ public class PhoneSwitcher extends Handler { } } - protected final List mPrioritizedDcRequests = new ArrayList<>(); private final @NonNull NetworkRequestList mNetworkRequestList = new NetworkRequestList(); protected final RegistrantList mActivePhoneRegistrants; protected final SubscriptionController mSubscriptionController; @@ -507,21 +503,16 @@ public class PhoneSwitcher extends Handler { phone.getImsPhone().registerForPreciseCallStateChanged( this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } - if (phone.isUsingNewDataStack()) { - mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), - v -> new DataSettingsManagerCallback(this::post) { - @Override - public void onDataEnabledChanged(boolean enabled, - @TelephonyManager.DataEnabledChangedReason int reason, - @NonNull String callingPackage) { - evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); - }}); - phone.getDataSettingsManager().registerCallback( - mDataSettingsManagerCallbacks.get(phone.getPhoneId())); - } else { - phone.getDataEnabledSettings().registerForDataEnabledChanged( - this, EVENT_DATA_ENABLED_CHANGED, null); - } + mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), + v -> new DataSettingsManagerCallback(this::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @TelephonyManager.DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); + }}); + phone.getDataSettingsManager().registerCallback( + mDataSettingsManagerCallbacks.get(phone.getPhoneId())); registerForImsRadioTechChange(context, i); } @@ -880,22 +871,17 @@ public class PhoneSwitcher extends Handler { this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } - if (phone.isUsingNewDataStack()) { - mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), - v -> new DataSettingsManagerCallback(this::post) { - @Override - public void onDataEnabledChanged(boolean enabled, - @TelephonyManager.DataEnabledChangedReason int reason, - @NonNull String callingPackage) { - evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); - } - }); - phone.getDataSettingsManager().registerCallback( - mDataSettingsManagerCallbacks.get(phone.getPhoneId())); - } else { - phone.getDataEnabledSettings().registerForDataEnabledChanged( - this, EVENT_DATA_ENABLED_CHANGED, null); - } + mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), + v -> new DataSettingsManagerCallback(this::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @TelephonyManager.DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); + } + }); + phone.getDataSettingsManager().registerCallback( + mDataSettingsManagerCallbacks.get(phone.getPhoneId())); Set ddsFailure = new HashSet(); mCurrentDdsSwitchFailure.add(ddsFailure); @@ -941,62 +927,21 @@ public class PhoneSwitcher extends Handler { } private void onRequestNetwork(NetworkRequest networkRequest) { - if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { - TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( - networkRequest, PhoneFactory.getDefaultPhone()); - if (!mNetworkRequestList.contains(telephonyNetworkRequest)) { - mNetworkRequestList.add(telephonyNetworkRequest); - onEvaluate(REQUESTS_CHANGED, "netRequest"); - } - return; - } - final DcRequest dcRequest = - DcRequest.create(networkRequest, createApnRepository(networkRequest)); - if (dcRequest != null) { - if (!mPrioritizedDcRequests.contains(dcRequest)) { - collectRequestNetworkMetrics(networkRequest); - mPrioritizedDcRequests.add(dcRequest); - Collections.sort(mPrioritizedDcRequests); - onEvaluate(REQUESTS_CHANGED, "netRequest"); - if (VDBG) log("Added DcRequest, size: " + mPrioritizedDcRequests.size()); - } + TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( + networkRequest, PhoneFactory.getDefaultPhone()); + if (!mNetworkRequestList.contains(telephonyNetworkRequest)) { + mNetworkRequestList.add(telephonyNetworkRequest); + onEvaluate(REQUESTS_CHANGED, "netRequest"); } } private void onReleaseNetwork(NetworkRequest networkRequest) { - if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { - TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( - networkRequest, PhoneFactory.getDefaultPhone()); - if (mNetworkRequestList.remove(telephonyNetworkRequest)) { - onEvaluate(REQUESTS_CHANGED, "netReleased"); - collectReleaseNetworkMetrics(networkRequest); - } - return; - } - final DcRequest dcRequest = - DcRequest.create(networkRequest, createApnRepository(networkRequest)); - if (dcRequest != null) { - if (mPrioritizedDcRequests.remove(dcRequest)) { - onEvaluate(REQUESTS_CHANGED, "netReleased"); - collectReleaseNetworkMetrics(networkRequest); - if (VDBG) log("Removed DcRequest, size: " + mPrioritizedDcRequests.size()); - } - } - } - - private ApnConfigTypeRepository createApnRepository(NetworkRequest networkRequest) { - int phoneIdForRequest = phoneIdForRequest(networkRequest); - int subId = mSubscriptionController.getSubIdUsingPhoneId(phoneIdForRequest); - CarrierConfigManager configManager = (CarrierConfigManager) mContext - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - - PersistableBundle carrierConfig; - if (configManager != null) { - carrierConfig = configManager.getConfigForSubId(subId); - } else { - carrierConfig = null; + TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( + networkRequest, PhoneFactory.getDefaultPhone()); + if (mNetworkRequestList.remove(telephonyNetworkRequest)) { + onEvaluate(REQUESTS_CHANGED, "netReleased"); + collectReleaseNetworkMetrics(networkRequest); } - return new ApnConfigTypeRepository(carrierConfig); } private void removeDefaultNetworkChangeCallback() { @@ -1147,22 +1092,12 @@ public class PhoneSwitcher extends Handler { } if (newActivePhones.size() < mMaxDataAttachModemCount) { - if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { - for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { - int phoneIdForRequest = phoneIdForRequest(networkRequest); - if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; - if (newActivePhones.contains(phoneIdForRequest)) continue; - newActivePhones.add(phoneIdForRequest); - if (newActivePhones.size() >= mMaxDataAttachModemCount) break; - } - } else { - for (DcRequest dcRequest : mPrioritizedDcRequests) { - int phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); - if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; - if (newActivePhones.contains(phoneIdForRequest)) continue; - newActivePhones.add(phoneIdForRequest); - if (newActivePhones.size() >= mMaxDataAttachModemCount) break; - } + for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { + int phoneIdForRequest = phoneIdForRequest(networkRequest); + if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; + if (newActivePhones.contains(phoneIdForRequest)) continue; + newActivePhones.add(phoneIdForRequest); + if (newActivePhones.size() >= mMaxDataAttachModemCount) break; } } @@ -1291,13 +1226,8 @@ public class PhoneSwitcher extends Handler { } } - // Merge phoneIdForRequest(NetworkRequest netRequest) after Phone.isUsingNewDataStack() is - // cleaned up. private int phoneIdForRequest(TelephonyNetworkRequest networkRequest) { - return phoneIdForRequest(networkRequest.getNativeNetworkRequest()); - } - - private int phoneIdForRequest(NetworkRequest netRequest) { + NetworkRequest netRequest = networkRequest.getNativeNetworkRequest(); int subId = getSubIdFromNetworkSpecifier(netRequest.getNetworkSpecifier()); if (subId == DEFAULT_SUBSCRIPTION_ID) return mPreferredDataPhoneId; @@ -1355,13 +1285,8 @@ public class PhoneSwitcher extends Handler { Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); boolean isDataEnabled = false; if (voicePhone != null) { - if (voicePhone.isUsingNewDataStack()) { - isDataEnabled = voicePhone.getDataSettingsManager() - .isDataEnabled(ApnSetting.TYPE_DEFAULT); - } else { - isDataEnabled = voicePhone.getDataEnabledSettings() - .isDataEnabled(ApnSetting.TYPE_DEFAULT); - } + isDataEnabled = voicePhone.getDataSettingsManager() + .isDataEnabled(ApnSetting.TYPE_DEFAULT); } if (mEmergencyOverride != null && findPhoneById(mEmergencyOverride.mPhoneId) != null) { @@ -1832,25 +1757,11 @@ public class PhoneSwitcher extends Handler { if (ddsPhoneId != INVALID_PHONE_INDEX && ddsPhoneId == phoneId) { return true; } else { - if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { - if (mNetworkRequestList.isEmpty()) return false; - for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { - phoneIdForRequest = phoneIdForRequest(networkRequest); - if (phoneIdForRequest == phoneId) { - return true; - } - } - } else { - if (mPrioritizedDcRequests.size() == 0) { - return false; - } - for (DcRequest dcRequest : mPrioritizedDcRequests) { - if (dcRequest != null) { - phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); - if (phoneIdForRequest == phoneId) { - return true; - } - } + if (mNetworkRequestList.isEmpty()) return false; + for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { + phoneIdForRequest = phoneIdForRequest(networkRequest); + if (phoneIdForRequest == phoneId) { + return true; } } } diff --git a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java index b7cecbdbdb..c3d5cb6a3a 100644 --- a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java +++ b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java @@ -53,8 +53,7 @@ public class QosCallbackTracker extends Handler { private static final int DEDICATED_BEARER_EVENT_STATE_DELETED = 3; private final @NonNull String mLogTag; - // TODO: Change this to TelephonyNetworkAgent - private final @NonNull NotifyQosSessionInterface mNetworkAgent; + private final @NonNull TelephonyNetworkAgent mNetworkAgent; private final @NonNull Map mQosBearerSessions; private final @NonNull RcsStats mRcsStats; @@ -94,8 +93,7 @@ public class QosCallbackTracker extends Handler { * @param networkAgent The network agent to send events to. * @param phone The phone instance. */ - public QosCallbackTracker(@NonNull NotifyQosSessionInterface networkAgent, - @NonNull Phone phone) { + public QosCallbackTracker(@NonNull TelephonyNetworkAgent networkAgent, @NonNull Phone phone) { mQosBearerSessions = new HashMap<>(); mCallbacksToFilter = new HashMap<>(); mNetworkAgent = networkAgent; @@ -103,40 +101,36 @@ public class QosCallbackTracker extends Handler { mRcsStats = RcsStats.getInstance(); mLogTag = "QOSCT" + "-" + ((NetworkAgent) mNetworkAgent).getNetwork().getNetId(); - if (phone.isUsingNewDataStack()) { - //TODO: Replace the NetworkAgent in the constructor with TelephonyNetworkAgent - // after mPhone.isUsingNewDataStack() check is removed. - ((TelephonyNetworkAgent) networkAgent).registerCallback( - new TelephonyNetworkAgent.TelephonyNetworkAgentCallback(this::post) { - @Override - public void onQosCallbackRegistered(int qosCallbackId, - @NonNull QosFilter filter) { - addFilter(qosCallbackId, - new QosCallbackTracker.IFilter() { - @Override - public boolean matchesLocalAddress( - @NonNull InetAddress address, int startPort, - int endPort) { - return filter.matchesLocalAddress(address, startPort, - endPort); - } - - @Override - public boolean matchesRemoteAddress( - @NonNull InetAddress address, int startPort, - int endPort) { - return filter.matchesRemoteAddress(address, startPort, - endPort); - } - }); - } + networkAgent.registerCallback( + new TelephonyNetworkAgent.TelephonyNetworkAgentCallback(this::post) { + @Override + public void onQosCallbackRegistered(int qosCallbackId, + @NonNull QosFilter filter) { + addFilter(qosCallbackId, + new QosCallbackTracker.IFilter() { + @Override + public boolean matchesLocalAddress( + @NonNull InetAddress address, int startPort, + int endPort) { + return filter.matchesLocalAddress(address, startPort, + endPort); + } + + @Override + public boolean matchesRemoteAddress( + @NonNull InetAddress address, int startPort, + int endPort) { + return filter.matchesRemoteAddress(address, startPort, + endPort); + } + }); + } - @Override - public void onQosCallbackUnregistered(int qosCallbackId) { + @Override + public void onQosCallbackUnregistered(int qosCallbackId) { - } - }); - } + } + }); } /** @@ -375,7 +369,7 @@ public class QosCallbackTracker extends Handler { qos.getDownlinkBandwidth().getGuaranteedBitrateKbps(), qos.getUplinkBandwidth().getGuaranteedBitrateKbps(), remoteAddresses); - mNetworkAgent.notifyQosSessionAvailable( + mNetworkAgent.sendQosSessionAvailable( callbackId, session.getQosBearerSessionId(), epsBearerAttr); } else { NrQos qos = (NrQos) session.getQos(); @@ -386,7 +380,7 @@ public class QosCallbackTracker extends Handler { qos.getDownlinkBandwidth().getGuaranteedBitrateKbps(), qos.getUplinkBandwidth().getGuaranteedBitrateKbps(), qos.getAveragingWindow(), remoteAddresses); - mNetworkAgent.notifyQosSessionAvailable( + mNetworkAgent.sendQosSessionAvailable( callbackId, session.getQosBearerSessionId(), nrQosAttr); } @@ -397,7 +391,7 @@ public class QosCallbackTracker extends Handler { } private void sendSessionLost(int callbackId, @NonNull QosBearerSession session) { - mNetworkAgent.notifyQosSessionLost(callbackId, session.getQosBearerSessionId(), + mNetworkAgent.sendQosSessionLost(callbackId, session.getQosBearerSessionId(), session.getQos() instanceof EpsQos ? QosSession.TYPE_EPS_BEARER : QosSession.TYPE_NR_BEARER); log("sendSessionLost, callbackId=" + callbackId); diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java index 3b1256283e..b8f7e87350 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java @@ -25,7 +25,6 @@ import android.net.NetworkAgentConfig; import android.net.NetworkProvider; import android.net.NetworkScore; import android.net.QosFilter; -import android.net.QosSessionAttributes; import android.net.Uri; import android.os.Looper; import android.util.ArraySet; @@ -46,9 +45,8 @@ import java.util.concurrent.Executor; * for telephony to propagate network related information to the connectivity service. It always * has an associated parent {@link DataNetwork}. */ -public class TelephonyNetworkAgent extends NetworkAgent implements NotifyQosSessionInterface { +public class TelephonyNetworkAgent extends NetworkAgent { private final String mLogTag; - private final Phone mPhone; private final LocalLog mLocalLog = new LocalLog(128); /** The parent data network. */ @@ -159,7 +157,6 @@ public class TelephonyNetworkAgent extends NetworkAgent implements NotifyQosSess mDataNetwork = dataNetwork; mNetworkAgentConfig = config; mTelephonyNetworkAgentCallbacks.add(callback); - mPhone = phone; mId = getNetwork().getNetId(); mLogTag = "TNA-" + mId; @@ -288,37 +285,6 @@ public class TelephonyNetworkAgent extends NetworkAgent implements NotifyQosSess () -> callback.onQosCallbackUnregistered(qosCallbackId))); } - /** - * Sends the attributes of Qos Session back to the Application. This method is create for - * Mockito to mock since - * {@link NetworkAgent#sendQosSessionAvailable(int, int, QosSessionAttributes)} is - * {@code final} that can't be mocked. - * - * @param qosCallbackId the callback id that the session belongs to. - * @param sessionId the unique session id across all Qos Sessions. - * @param attributes the attributes of the Qos Session. - */ - @Override - public void notifyQosSessionAvailable(final int qosCallbackId, final int sessionId, - @NonNull final QosSessionAttributes attributes) { - super.sendQosSessionAvailable(qosCallbackId, sessionId, attributes); - } - - /** - * Sends event that the Qos Session was lost. This method is create for Mockito to mock - * since {@link NetworkAgent#sendQosSessionLost(int, int, int)} is {@code final} that can't be - * mocked.. - * - * @param qosCallbackId the callback id that the session belongs to. - * @param sessionId the unique session id across all Qos Sessions. - * @param qosSessionType the session type {@code QosSession#QosSessionType}. - */ - @Override - public void notifyQosSessionLost(final int qosCallbackId, - final int sessionId, final int qosSessionType) { - super.sendQosSessionLost(qosCallbackId, sessionId, qosSessionType); - } - /** * Abandon the network agent. This is used for telephony to re-create the network agent when * immutable capabilities got changed, where telephony calls {@link NetworkAgent#unregister()} diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java index 85f0ae1f0d..e64dd9b7c0 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java @@ -20,27 +20,16 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; -import android.os.AsyncResult; -import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.telephony.AccessNetworkConstants; -import android.telephony.Annotation.ApnType; import android.telephony.SubscriptionManager; -import android.telephony.data.ApnSetting; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; -import com.android.internal.telephony.dataconnection.ApnContext; -import com.android.internal.telephony.dataconnection.DataConnection; -import com.android.internal.telephony.dataconnection.DcTracker; -import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; -import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; -import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams; import com.android.internal.telephony.metrics.NetworkRequestsStats; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -72,19 +61,15 @@ public class TelephonyNetworkFactory extends NetworkFactory { public static final int EVENT_SUBSCRIPTION_CHANGED = 2; private static final int EVENT_NETWORK_REQUEST = 3; private static final int EVENT_NETWORK_RELEASE = 4; - private static final int EVENT_DATA_HANDOVER_NEEDED = 5; - private static final int EVENT_DATA_HANDOVER_COMPLETED = 6; private final PhoneSwitcher mPhoneSwitcher; private final SubscriptionController mSubscriptionController; private final LocalLog mLocalLog = new LocalLog(REQUEST_LOG_SIZE); - // Key: network request. Value: the transport of DcTracker it applies to, + // Key: network request. Value: the transport of the network request applies to, // AccessNetworkConstants.TRANSPORT_TYPE_INVALID if not applied. private final Map mNetworkRequests = new HashMap<>(); - private final Map mPendingHandovers = new HashMap<>(); - private final Phone mPhone; private AccessNetworksManager mAccessNetworksManager; @@ -112,10 +97,6 @@ public class TelephonyNetworkFactory extends NetworkFactory { mPhoneSwitcher.registerForActivePhoneSwitch(mInternalHandler, EVENT_ACTIVE_PHONE_SWITCH, null); - if (!phone.isUsingNewDataStack()) { - mPhone.getTransportManager().registerForHandoverNeededEvent(mInternalHandler, - EVENT_DATA_HANDOVER_NEEDED); - } mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; SubscriptionManager.from(mPhone.getContext()).addOnSubscriptionsChangedListener( @@ -201,93 +182,18 @@ public class TelephonyNetworkFactory extends NetworkFactory { onReleaseNetworkFor(msg); break; } - case EVENT_DATA_HANDOVER_NEEDED: { - AsyncResult ar = (AsyncResult) msg.obj; - HandoverParams handoverParams = (HandoverParams) ar.result; - onDataHandoverNeeded(handoverParams.apnType, handoverParams.targetTransport, - handoverParams); - break; - } - case EVENT_DATA_HANDOVER_COMPLETED: { - Bundle bundle = msg.getData(); - NetworkRequest nr = bundle.getParcelable( - DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST); - boolean success = bundle.getBoolean( - DcTracker.DATA_COMPLETE_MSG_EXTRA_SUCCESS); - int transport = bundle.getInt( - DcTracker.DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE); - boolean fallback = bundle.getBoolean( - DcTracker.DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK); - HandoverParams handoverParams = mPendingHandovers.remove(msg); - if (handoverParams != null) { - onDataHandoverSetupCompleted(nr, success, transport, fallback, - handoverParams); - } else { - logl("Handover completed but cannot find handover entry!"); - } - break; - } } } } private int getTransportTypeFromNetworkRequest(TelephonyNetworkRequest networkRequest) { - if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { - int transport = AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - int capability = networkRequest.getApnTypeNetworkCapability(); - if (capability >= 0) { - transport = mAccessNetworksManager - .getPreferredTransportByNetworkCapability(capability); - } - return transport; - } else { - int apnType = ApnContext.getApnTypeFromNetworkRequest( - networkRequest.getNativeNetworkRequest()); - return mAccessNetworksManager.getCurrentTransport(apnType); - } - } - - /** - * Request network - * - * @param networkRequest Network request from clients - * @param requestType The request type - * @param transport Transport type - * @param onHandoverCompleteMsg When request type is handover, this message will be sent when - * handover is completed. For normal request, this should be null. - */ - private void requestNetworkInternal(TelephonyNetworkRequest networkRequest, - @RequestNetworkType int requestType, int transport, Message onHandoverCompleteMsg) { - NetworkRequestsStats.addNetworkRequest(networkRequest.getNativeNetworkRequest(), - mSubscriptionId); - - if (mPhone.isUsingNewDataStack()) { - mPhone.getDataNetworkController().addNetworkRequest(networkRequest); - } else { - if (mPhone.getDcTracker(transport) != null) { - mPhone.getDcTracker(transport).requestNetwork( - networkRequest.getNativeNetworkRequest(), requestType, - onHandoverCompleteMsg); - } - } - } - - private void releaseNetworkInternal(TelephonyNetworkRequest networkRequest) { - mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); - } - - // TODO: Clean this up after old data stack removed. - private void releaseNetworkInternal(TelephonyNetworkRequest networkRequest, - @ReleaseNetworkType int releaseType, - int transport) { - if (mPhone.isUsingNewDataStack()) { - mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); - } else { - if (mPhone.getDcTracker(transport) != null) { - mPhone.getDcTracker(transport).releaseNetwork( - networkRequest.getNativeNetworkRequest(), releaseType); - } + int transport = AccessNetworkConstants.TRANSPORT_TYPE_WWAN; + int capability = networkRequest.getApnTypeNetworkCapability(); + if (capability >= 0) { + transport = mAccessNetworksManager + .getPreferredTransportByNetworkCapability(capability); } + return transport; } private static int getAction(boolean wasActive, boolean isActive) { @@ -317,15 +223,11 @@ public class TelephonyNetworkFactory extends NetworkFactory { ? "Requesting" : "Releasing") + " network request " + networkRequest); int transportType = getTransportTypeFromNetworkRequest(networkRequest); if (action == ACTION_REQUEST) { - requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, - getTransportTypeFromNetworkRequest(networkRequest), null); + NetworkRequestsStats.addNetworkRequest(networkRequest.getNativeNetworkRequest(), + mSubscriptionId); + mPhone.getDataNetworkController().addNetworkRequest(networkRequest); } else if (action == ACTION_RELEASE) { - if (mPhone.isUsingNewDataStack()) { - releaseNetworkInternal(networkRequest); - } else { - releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_DETACH, - getTransportTypeFromNetworkRequest(networkRequest)); - } + mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); } mNetworkRequests.put(networkRequest, @@ -365,8 +267,9 @@ public class TelephonyNetworkFactory extends NetworkFactory { logl("onNeedNetworkFor " + networkRequest + " shouldApply " + shouldApply); if (shouldApply) { - requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, - getTransportTypeFromNetworkRequest(networkRequest), null); + NetworkRequestsStats.addNetworkRequest(networkRequest.getNativeNetworkRequest(), + mSubscriptionId); + mPhone.getDataNetworkController().addNetworkRequest(networkRequest); } } @@ -388,134 +291,8 @@ public class TelephonyNetworkFactory extends NetworkFactory { logl("onReleaseNetworkFor " + networkRequest + " applied " + applied); if (applied) { - if (mPhone.isUsingNewDataStack()) { - releaseNetworkInternal(networkRequest); - } else { - // Most of the time, the network request only exists in one of the DcTracker, but in - // the middle of handover, the network request temporarily exists in both - // DcTrackers. If connectivity service releases the network request while handover - // is ongoing, we need to remove network requests from both DcTrackers. - // Note that this part will be refactored in T, where we won't even have DcTracker - // at all. - releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - } - } - } - - private void onDataHandoverNeeded(@ApnType int apnType, int targetTransport, - HandoverParams handoverParams) { - log("onDataHandoverNeeded: apnType=" + ApnSetting.getApnTypeString(apnType) - + ", target transport=" - + AccessNetworkConstants.transportTypeToString(targetTransport)); - if (mAccessNetworksManager.getCurrentTransport(apnType) == targetTransport) { - log("APN type " + ApnSetting.getApnTypeString(apnType) + " is already on " - + AccessNetworkConstants.transportTypeToString(targetTransport)); - return; - } - - boolean handoverPending = false; - for (Map.Entry entry : mNetworkRequests.entrySet()) { - TelephonyNetworkRequest networkRequest = entry.getKey(); - int currentTransport = entry.getValue(); - boolean applied = currentTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID; - if (ApnContext.getApnTypeFromNetworkRequest( - networkRequest.getNativeNetworkRequest()) == apnType - && applied - && currentTransport != targetTransport) { - DcTracker dcTracker = mPhone.getDcTracker(currentTransport); - if (dcTracker != null) { - DataConnection dc = dcTracker.getDataConnectionByApnType( - ApnSetting.getApnTypeString(apnType)); - if (dc != null && (dc.isActive())) { - Message onCompleteMsg = mInternalHandler.obtainMessage( - EVENT_DATA_HANDOVER_COMPLETED); - onCompleteMsg.getData().putParcelable( - DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST, - networkRequest.getNativeNetworkRequest()); - mPendingHandovers.put(onCompleteMsg, handoverParams); - requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_HANDOVER, - targetTransport, onCompleteMsg); - log("Requested handover " + ApnSetting.getApnTypeString(apnType) - + " to " - + AccessNetworkConstants.transportTypeToString(targetTransport) - + ". " + networkRequest); - handoverPending = true; - } else { - // Request is there, but no actual data connection. In this case, just move - // the request to the new transport. - log("The network request is on transport " + AccessNetworkConstants - .transportTypeToString(currentTransport) + ", but no live data " - + "connection. Just move the request to transport " - + AccessNetworkConstants.transportTypeToString(targetTransport) - + ", dc=" + dc); - entry.setValue(targetTransport); - releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, - currentTransport); - requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, - targetTransport, null); - } - } else { - log("DcTracker on " + AccessNetworkConstants.transportTypeToString( - currentTransport) + " is not available."); - } - } - } - - if (!handoverPending) { - log("No handover request pending. Handover process is now completed"); - handoverParams.callback.onCompleted(true, false); - } - } - - private void onDataHandoverSetupCompleted(NetworkRequest request, boolean success, - int targetTransport, boolean fallback, - HandoverParams handoverParams) { - log("onDataHandoverSetupCompleted: " + request + ", success=" + success - + ", targetTransport=" - + AccessNetworkConstants.transportTypeToString(targetTransport) - + ", fallback=" + fallback); - - TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(request, mPhone); - // At this point, handover setup has been completed on the target transport. - // If it succeeded, or it failed without falling back to the original transport, - // we should release the request from the original transport. - if (!fallback) { - int originTransport = DataUtils.getSourceTransport(targetTransport); - int releaseType = success - ? DcTracker.RELEASE_TYPE_HANDOVER - // If handover fails, we need to tear down the existing connection, so the - // new data connection can be re-established on the new transport. If we leave - // the existing data connection in current transport, then DCT and qualified - // network service will be out of sync. Specifying release type to detach - // the transport is moved to the other transport, but network request is still - // there, connectivity service will not call unwanted to tear down the network. - // We need explicitly tear down the data connection here so the new data - // connection can be re-established on the other transport. - : DcTracker.RELEASE_TYPE_DETACH; - releaseNetworkInternal(networkRequest, releaseType, originTransport); - - // Before updating the network request with the target transport, make sure the request - // is still there because it's possible that connectivity service has already released - // the network while handover is ongoing. If connectivity service already released - // the network request, we need to tear down the just-handovered data connection on the - // target transport. - if (mNetworkRequests.containsKey(networkRequest)) { - // Update it with the target transport. - mNetworkRequests.put(networkRequest, targetTransport); - } - } else { - // If handover fails and requires to fallback, the context of target transport needs to - // be released - if (!success) { - releaseNetworkInternal(networkRequest, - DcTracker.RELEASE_TYPE_NORMAL, targetTransport); - } + mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); } - - handoverParams.callback.onCompleted(success, fallback); } protected void log(String s) { diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java index b55304a4a9..b334b89d75 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java @@ -157,8 +157,7 @@ public class TelephonyNetworkRequest { /** * Data config manager for retrieving data config. */ - // TODO: Make this @NonNull after old data stack removed. - private final @Nullable DataConfigManager mDataConfigManager; + private final @NonNull DataConfigManager mDataConfigManager; /** * The attached data network. Note that the data network could be in any state. {@code null} @@ -204,12 +203,8 @@ public class TelephonyNetworkRequest { // to satisfy it. mState = REQUEST_STATE_UNSATISFIED; mCreatedTimeMillis = SystemClock.elapsedRealtime(); - if (phone.isUsingNewDataStack()) { - mDataConfigManager = phone.getDataNetworkController().getDataConfigManager(); - updatePriority(); - } else { - mDataConfigManager = null; - } + mDataConfigManager = phone.getDataNetworkController().getDataConfigManager(); + updatePriority(); } /** @@ -401,8 +396,7 @@ public class TelephonyNetworkRequest { * @return {@code true} if this network request can result in bringing up a metered network. */ public boolean isMeteredRequest() { - // TODO: Remove null check after old data stack removed. - return mDataConfigManager != null && mDataConfigManager.isAnyMeteredCapability( + return mDataConfigManager.isAnyMeteredCapability( getCapabilities(), mPhone.getServiceState().getDataRoaming()); } diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java b/src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java deleted file mode 100644 index 827dbdd5e4..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2020 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.dataconnection; - -import android.telephony.Annotation; - -/** - * Container of network configuration settings relevant for telephony module. - * - */ -public class ApnConfigType { - - private final int mType; - private final int mPriority; - - public ApnConfigType(@Annotation.ApnType int type, int priority) { - mType = type; - mPriority = priority; - } - - /** - * Returns the apn type of this config type - * @return Type of apn. - */ - public int getType() { - return mType; - } - - /** - * Returns the priority of this apn config type. - * @return The priority of this apn. - */ - public int getPriority() { - return mPriority; - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java b/src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java deleted file mode 100644 index 156ac926e5..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2020 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.dataconnection; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.PersistableBundle; -import android.telephony.Annotation; -import android.telephony.CarrierConfigManager; -import android.telephony.Rlog; -import android.telephony.data.ApnSetting; -import android.util.ArrayMap; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * Hard coded configuration of specific network types that the telephony module needs. - * Formerly stored in network attributes within the resources file. - */ -public class ApnConfigTypeRepository { - - private static final String TAG = ApnConfigTypeRepository.class.getSimpleName(); - - private final Map mConfigTypeMap; - - public ApnConfigTypeRepository(PersistableBundle carrierConfig) { - mConfigTypeMap = new HashMap<>(); - setup(carrierConfig); - } - - /** - * Gets list of apn config types. - * @return All apn config types. - */ - public Collection getTypes() { - return mConfigTypeMap.values(); - } - - /** - * Gets the apn config type by apn type. - * @param type The ApnType to search for. - * @return The config type matching the given apn type. - */ - @Nullable - public ApnConfigType getByType(@Annotation.ApnType int type) { - return mConfigTypeMap.get(type); - } - - private void setup(PersistableBundle carrierConfig) { - addApns(getCarrierApnTypeMap(CarrierConfigManager.getDefaultConfig())); - addApns(getCarrierApnTypeMap(carrierConfig)); - } - - private void addApns(Map apnTypeMap) { - add(ApnSetting.TYPE_DEFAULT, apnTypeMap); - add(ApnSetting.TYPE_MMS, apnTypeMap); - add(ApnSetting.TYPE_SUPL, apnTypeMap); - add(ApnSetting.TYPE_DUN, apnTypeMap); - add(ApnSetting.TYPE_HIPRI, apnTypeMap); - add(ApnSetting.TYPE_FOTA, apnTypeMap); - add(ApnSetting.TYPE_IMS, apnTypeMap); - add(ApnSetting.TYPE_CBS, apnTypeMap); - add(ApnSetting.TYPE_IA, apnTypeMap); - add(ApnSetting.TYPE_EMERGENCY, apnTypeMap); - add(ApnSetting.TYPE_MCX, apnTypeMap); - add(ApnSetting.TYPE_XCAP, apnTypeMap); - add(ApnSetting.TYPE_ENTERPRISE, apnTypeMap); - } - - @NonNull - private Map getCarrierApnTypeMap(PersistableBundle carrierConfig) { - if (carrierConfig == null) { - Rlog.w(TAG, "carrier config is null"); - return new ArrayMap<>(); - } - - final String[] apnTypeConfig = - carrierConfig.getStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY); - - final Map apnTypeMap = new ArrayMap<>(); - if (apnTypeConfig != null) { - for (final String entry : apnTypeConfig) { - try { - final String[] keyValue = entry.split(":"); - if (keyValue.length != 2) { - Rlog.e(TAG, "Apn type entry must have exactly one ':'"); - } else if (keyValue[0].contains(",")) { - //getApnTypesBitmaskFromString parses commas to a list, not valid here. - Rlog.e(TAG, "Invalid apn type name, entry: " + entry); - } else { - int apnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(keyValue[0]); - if (apnTypeBitmask > 0) { - apnTypeMap.put(apnTypeBitmask, Integer.parseInt(keyValue[1])); - } else { - Rlog.e(TAG, "Invalid apn type name, entry: " + entry); - } - } - - } catch (Exception ex) { - Rlog.e(TAG, "Exception on apn type entry: " + entry + "\n", ex); - } - } - } - return apnTypeMap; - } - - private void add(@Annotation.ApnType int type, Map apnTypeMap) { - if (apnTypeMap.containsKey(type)) { - mConfigTypeMap.put(type, new ApnConfigType(type, apnTypeMap.get(type))); - } - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java deleted file mode 100644 index 3f487cdf65..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Copyright (C) 2006 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.dataconnection; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.os.Message; -import android.telephony.Annotation.ApnType; -import android.telephony.data.ApnSetting; -import android.text.TextUtils; -import android.util.ArraySet; -import android.util.LocalLog; -import android.util.SparseIntArray; - -import com.android.internal.R; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; -import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; -import com.android.internal.util.IndentingPrintWriter; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Maintain the Apn context - */ -public class ApnContext { - - public final String LOG_TAG; - private final static String SLOG_TAG = "ApnContext"; - - protected static final boolean DBG = false; - - private final Phone mPhone; - - private final String mApnType; - - private DctConstants.State mState; - - private int mPriority; - - private ApnSetting mApnSetting; - - private DataConnection mDataConnection; - - private String mReason; - - /** - * user/app requested connection on this APN - */ - AtomicBoolean mDataEnabled; - - private final Object mRefCountLock = new Object(); - - private final DcTracker mDcTracker; - - - /** - * Remember this as a change in this value to a more permissive state - * should cause us to retry even permanent failures - */ - private boolean mConcurrentVoiceAndDataAllowed; - - /** - * used to track a single connection request so disconnects can get ignored if - * obsolete. - */ - private final AtomicInteger mConnectionGeneration = new AtomicInteger(0); - - /** - * Retry manager that handles the APN retry and delays. - */ - private final RetryManager mRetryManager; - - /** - * ApnContext constructor - * @param phone phone object - * @param typeId APN type Id - * @param logTag Tag for logging - * @param tracker Data call tracker - * @param priority Priority of APN type - */ - public ApnContext(Phone phone, int typeId, String logTag, DcTracker tracker, int priority) { - this(phone, ApnSetting.getApnTypeString(typeId), logTag, tracker, priority); - } - - /** - * ApnContext constructor - * @param phone phone object - * @param apnType APN type (e.g. default, supl, mms, etc...) - * @param logTag Tag for logging - * @param tracker Data call tracker - * @param priority Priority of APN type - */ - public ApnContext(Phone phone, String apnType, String logTag, DcTracker tracker, int priority) { - mPhone = phone; - mApnType = apnType; - mState = DctConstants.State.IDLE; - setReason(Phone.REASON_DATA_ENABLED); - mDataEnabled = new AtomicBoolean(false); - mPriority = priority; - LOG_TAG = logTag; - mDcTracker = tracker; - mRetryManager = new RetryManager(phone, tracker.getDataThrottler(), - ApnSetting.getApnTypesBitmaskFromString(apnType)); - } - - - - /** - * Get the APN type - * @return The APN type - */ - public String getApnType() { - return mApnType; - } - - /** - * Gets the APN type bitmask. - * @return The APN type bitmask - */ - public int getApnTypeBitmask() { - return ApnSetting.getApnTypesBitmaskFromString(mApnType); - } - - /** - * Get the associated data connection - * @return The data connection - */ - public synchronized DataConnection getDataConnection() { - return mDataConnection; - } - - /** - * This priority is taken into account when concurrent data connections are not allowed. The - * APN with the HIGHER priority is given preference. - * @return The priority of the APN type - */ - public int getPriority() { - return mPriority; - } - - /** - * Updates the priority of this context. - * @param priority The priority of the APN type - */ - public void setPriority(int priority) { - mPriority = priority; - } - - /** - * Keeping for backwards compatibility and in case it's needed in the future - * @return true - */ - public boolean isDependencyMet() { - return true; - } - - /** - * Set the associated data connection. - * @param dc data connection - */ - public synchronized void setDataConnection(DataConnection dc) { - log("setDataConnectionAc: old=" + mDataConnection + ",new=" + dc + " this=" + this); - mDataConnection = dc; - } - - /** - * Release data connection. - * @param reason The reason of releasing data connection - */ - public synchronized void releaseDataConnection(String reason) { - if (mDataConnection != null) { - mDataConnection.tearDown(this, reason, null); - mDataConnection = null; - } - setState(DctConstants.State.IDLE); - } - - /** - * Get the current APN setting. - * @return APN setting - */ - public synchronized ApnSetting getApnSetting() { - log("getApnSetting: apnSetting=" + mApnSetting); - return mApnSetting; - } - - /** - * Set the APN setting. - * @param apnSetting APN setting - */ - public synchronized void setApnSetting(ApnSetting apnSetting) { - log("setApnSetting: apnSetting=" + apnSetting); - mApnSetting = apnSetting; - } - - /** - * Set the list of APN candidates which will be used for data call setup later. - * @param waitingApns List of APN candidates - */ - public synchronized void setWaitingApns(ArrayList waitingApns) { - mRetryManager.setWaitingApns(waitingApns); - } - - /** - * Get the next available APN to try. - * @return APN setting which will be used for data call setup.{@code null} if there is no - * APN can be retried. - */ - public @Nullable ApnSetting getNextApnSetting() { - return mRetryManager.getNextApnSetting(); - } - - /** - * Get the delay for trying the next APN setting if the current one failed. - * @param failFastEnabled True if fail fast mode enabled. In this case we'll use a shorter - * delay. - * @return The delay in milliseconds - */ - public long getDelayForNextApn(boolean failFastEnabled) { - return mRetryManager.getDelayForNextApn(failFastEnabled || isFastRetryReason()); - } - - /** - * Mark the current APN setting permanently failed, which means it will not be retried anymore. - * @param apn APN setting - */ - public void markApnPermanentFailed(ApnSetting apn) { - mRetryManager.markApnPermanentFailed(apn); - } - - /** - * Get the list of waiting APNs. - * @return the list of waiting APNs - */ - public @NonNull ArrayList getWaitingApns() { - return mRetryManager.getWaitingApns(); - } - - /** - * Save the state indicating concurrent voice/data allowed. - * @param allowed True if concurrent voice/data is allowed - */ - public synchronized void setConcurrentVoiceAndDataAllowed(boolean allowed) { - mConcurrentVoiceAndDataAllowed = allowed; - } - - /** - * Get the state indicating concurrent voice/data allowed. - * @return True if concurrent voice/data is allowed - */ - public synchronized boolean isConcurrentVoiceAndDataAllowed() { - return mConcurrentVoiceAndDataAllowed; - } - - /** - * Set the current data call state. - * @param s Current data call state - */ - public synchronized void setState(DctConstants.State s) { - log("setState: " + s + ", previous state:" + mState); - - if (mState != s) { - mStateLocalLog.log("State changed from " + mState + " to " + s); - mState = s; - } - - if (mState == DctConstants.State.FAILED) { - // when teardown the connection and set to IDLE - mRetryManager.getWaitingApns().clear(); - } - } - - /** - * Get the current data call state. - * @return The current data call state - */ - public synchronized DctConstants.State getState() { - return mState; - } - - /** - * Check whether the data call is disconnected or not. - * @return True if the data call is disconnected - */ - public boolean isDisconnected() { - DctConstants.State currentState = getState(); - return ((currentState == DctConstants.State.IDLE) || - currentState == DctConstants.State.FAILED); - } - - /** - * Set the reason for data call connection. - * @param reason Reason for data call connection - */ - public synchronized void setReason(String reason) { - log("set reason as " + reason + ",current state " + mState); - mReason = reason; - } - - /** - * Get the reason for data call connection. - * @return The reason for data call connection - */ - public synchronized String getReason() { - return mReason; - } - - /** - * Check if ready for data call connection - * @return True if ready, otherwise false. - */ - public boolean isReady() { - return mDataEnabled.get() && isDependencyMet(); - } - - /** - * Check if the data call is in the state which allow connecting. - * @return True if allowed, otherwise false. - */ - public boolean isConnectable() { - return isReady() && ((mState == DctConstants.State.IDLE) - || (mState == DctConstants.State.RETRYING) - || (mState == DctConstants.State.FAILED)); - } - - /** - * Check if apn reason is fast retry reason which should apply shorter delay between apn re-try. - * @return True if it is fast retry reason, otherwise false. - */ - private boolean isFastRetryReason() { - return Phone.REASON_NW_TYPE_CHANGED.equals(mReason) || - Phone.REASON_APN_CHANGED.equals(mReason); - } - - /** Check if the data call is in connected or connecting state. - * @return True if the data call is in connected or connecting state - */ - public boolean isConnectedOrConnecting() { - return isReady() && ((mState == DctConstants.State.CONNECTED) - || (mState == DctConstants.State.CONNECTING) - || (mState == DctConstants.State.RETRYING)); - } - - /** - * Set data call enabled/disabled state. - * @param enabled True if data call is enabled - */ - public void setEnabled(boolean enabled) { - log("set enabled as " + enabled + ", current state is " + mDataEnabled.get()); - mDataEnabled.set(enabled); - } - - /** - * Check if the data call is enabled or not. - * @return True if enabled - */ - public boolean isEnabled() { - return mDataEnabled.get(); - } - - public boolean isProvisioningApn() { - String provisioningApn = mPhone.getContext().getResources() - .getString(R.string.mobile_provisioning_apn); - if (!TextUtils.isEmpty(provisioningApn) && - (mApnSetting != null) && (mApnSetting.getApnName() != null)) { - return (mApnSetting.getApnName().equals(provisioningApn)); - } else { - return false; - } - } - - private final ArraySet mNetworkRequests = new ArraySet<>(); - private final LocalLog mStateLocalLog = new LocalLog(32); - - private static final LocalLog sLocalLog = new LocalLog(256); - - /** Add a line to the ApnContext local log. */ - public static void requestLog(ApnContext apnContext, String str) { - if (apnContext != null) { - String logString = "[ApnContext:" + apnContext.getApnType() + "] " + str; - if (DBG) { - Rlog.d(SLOG_TAG, logString); - } - synchronized (sLocalLog) { - sLocalLog.log(logString); - } - } - } - - /** - * Request a network - * - * @param networkRequest Network request from clients - * @param type The request type - * @param onHandoverCompleteMsg When request type is handover, this message will be sent when - * handover is completed. For normal request, this should be null. - */ - public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type, - Message onHandoverCompleteMsg) { - synchronized (mRefCountLock) { - mNetworkRequests.add(networkRequest); - requestLog(this, "requestNetwork for " + networkRequest + ", type=" - + DcTracker.requestTypeToString(type)); - mDcTracker.enableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type, - onHandoverCompleteMsg); - if (mDataConnection != null) { - // New network request added. Should re-evaluate properties of - // the data connection. For example, the score may change. - mDataConnection.reevaluateDataConnectionProperties(); - } - } - } - - public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type) { - synchronized (mRefCountLock) { - if (mNetworkRequests.contains(networkRequest)) { - mNetworkRequests.remove(networkRequest); - if (mDataConnection != null) { - // New network request added. Should re-evaluate properties of - // the data connection. For example, the score may change. - mDataConnection.reevaluateDataConnectionProperties(); - } - requestLog(this, "releaseNetwork left with " + mNetworkRequests.size() - + " requests."); - if (mNetworkRequests.size() == 0 - || type == DcTracker.RELEASE_TYPE_DETACH - || type == DcTracker.RELEASE_TYPE_HANDOVER) { - mDcTracker.disableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type); - } - } - } - } - - /** - * @param excludeDun True if excluding requests that have DUN capability - * @return True if the attached network requests contain restricted capability. - */ - public boolean hasRestrictedRequests(boolean excludeDun) { - synchronized (mRefCountLock) { - for (NetworkRequest nr : mNetworkRequests) { - if (excludeDun && - nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) { - continue; - } - if (!nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) { - return true; - } - } - } - return false; - } - - private final SparseIntArray mRetriesLeftPerErrorCode = new SparseIntArray(); - - public void resetErrorCodeRetries() { - requestLog(this, "resetErrorCodeRetries"); - - String[] config = mPhone.getContext().getResources().getStringArray( - com.android.internal.R.array.config_cell_retries_per_error_code); - synchronized (mRetriesLeftPerErrorCode) { - mRetriesLeftPerErrorCode.clear(); - - for (String c : config) { - String errorValue[] = c.split(","); - if (errorValue != null && errorValue.length == 2) { - int count = 0; - int errorCode = 0; - try { - errorCode = Integer.parseInt(errorValue[0]); - count = Integer.parseInt(errorValue[1]); - } catch (NumberFormatException e) { - log("Exception parsing config_retries_per_error_code: " + e); - continue; - } - if (count > 0 && errorCode > 0) { - mRetriesLeftPerErrorCode.put(errorCode, count); - } - } else { - log("Exception parsing config_retries_per_error_code: " + c); - } - } - } - } - - public boolean restartOnError(int errorCode) { - boolean result = false; - int retriesLeft = 0; - synchronized(mRetriesLeftPerErrorCode) { - retriesLeft = mRetriesLeftPerErrorCode.get(errorCode); - switch (retriesLeft) { - case 0: { - // not set, never restart modem - break; - } - case 1: { - resetErrorCodeRetries(); - result = true; - break; - } - default: { - mRetriesLeftPerErrorCode.put(errorCode, retriesLeft - 1); - result = false; - } - } - } - requestLog(this, "restartOnError(" + errorCode + ") found " + retriesLeft - + " and returned " + result); - return result; - } - - public int incAndGetConnectionGeneration() { - return mConnectionGeneration.incrementAndGet(); - } - - public int getConnectionGeneration() { - return mConnectionGeneration.get(); - } - - long getRetryAfterDisconnectDelay() { - return mRetryManager.getRetryAfterDisconnectDelay(); - } - - /** - * Get APN type from the network request. - * - * @param nr The network request. - * @return The APN type. - */ - public static @ApnType int getApnTypeFromNetworkRequest(NetworkRequest nr) { - // For now, ignore the bandwidth stuff - if (nr.getTransportTypes().length > 0 - && !nr.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - return ApnSetting.TYPE_NONE; - } - - // in the near term just do 1-1 matches. - // TODO - actually try to match the set of capabilities - int apnType = ApnSetting.TYPE_NONE; - boolean error = false; - - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { - apnType = ApnSetting.TYPE_DEFAULT; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_MMS; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_SUPL; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_DUN; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_FOTA; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_IMS; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_CBS; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_IA)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_IA; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_EMERGENCY; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_MCX)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_MCX; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_XCAP; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_ENTERPRISE; - } - if (error) { - // TODO: If this error condition is removed, the framework's handling of - // NET_CAPABILITY_NOT_RESTRICTED will need to be updated so requests for - // say FOTA and INTERNET are marked as restricted. This is not how - // NetworkCapabilities.maybeMarkCapabilitiesRestricted currently works. - Rlog.d(SLOG_TAG, "Multiple apn types specified in request - result is unspecified!"); - } - if (apnType == ApnSetting.TYPE_NONE) { - Rlog.d(SLOG_TAG, "Unsupported NetworkRequest in Telephony: nr=" + nr); - } - return apnType; - } - - public List getNetworkRequests() { - synchronized (mRefCountLock) { - return new ArrayList(mNetworkRequests); - } - } - - @Override - public synchronized String toString() { - // We don't print mDataConnection because its recursive. - return "{mApnType=" + mApnType + " mState=" + getState() + " mWaitingApns={" - + mRetryManager.getWaitingApns() + " priority=" + mPriority + "}" - + " mApnSetting={" + mApnSetting - + "} mReason=" + mReason + " mDataEnabled=" + mDataEnabled + "}"; - } - - private void log(String s) { - if (DBG) { - Rlog.d(LOG_TAG, "[ApnContext:" + mApnType + "] " + s); - } - } - - public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { - final IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); - synchronized (mRefCountLock) { - pw.println(toString()); - if (mNetworkRequests.size() > 0) { - pw.println("NetworkRequests:"); - pw.increaseIndent(); - for (NetworkRequest nr : mNetworkRequests) { - pw.println(nr); - } - pw.decreaseIndent(); - } - pw.println("Historical APN state:"); - pw.increaseIndent(); - mStateLocalLog.dump(fd, pw, args); - pw.decreaseIndent(); - pw.println(mRetryManager); - pw.println("--------------------------"); - } - } - - /** Dumps the ApnContext local log. */ - public static void dumpLocalLog(FileDescriptor fd, PrintWriter printWriter, String[] args) { - printWriter.println("Local log:"); - synchronized (sLocalLog) { - sLocalLog.dump(fd, printWriter, args); - } - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java b/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java deleted file mode 100644 index 3c2a6ef251..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import android.content.Context; -import android.os.PersistableBundle; -import android.telephony.Annotation.ApnType; -import android.telephony.CarrierConfigManager; -import android.telephony.data.ApnSetting; - -import com.android.internal.telephony.Phone; -import com.android.telephony.Rlog; - -import java.util.Arrays; -import java.util.HashSet; - -/** - * This class represents a apn setting for create PDP link - */ -public class ApnSettingUtils { - - static final String LOG_TAG = "ApnSetting"; - - private static final boolean DBG = false; - - /** - * Check if this APN type is metered. - * - * @param apnType the APN type - * @param phone the phone object - * @return {@code true} if the APN type is metered, {@code false} otherwise. - */ - public static boolean isMeteredApnType(@ApnType int apnType, Phone phone) { - if (phone == null) { - return true; - } - - boolean isRoaming = phone.getServiceState().getDataRoaming(); - int subId = phone.getSubId(); - - String carrierConfig; - // First check if the device is roaming. If yes, use the roaming metered APN list. - // Otherwise use the normal metered APN list. - if (isRoaming) { - carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS; - } else { - carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS; - } - - if (DBG) { - Rlog.d(LOG_TAG, "isMeteredApnType: isRoaming=" + isRoaming); - } - - CarrierConfigManager configManager = (CarrierConfigManager) - phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager == null) { - Rlog.e(LOG_TAG, "Carrier config service is not available"); - return true; - } - - PersistableBundle b = configManager.getConfigForSubId(subId); - if (b == null) { - Rlog.e(LOG_TAG, "Can't get the config. subId = " + subId); - return true; - } - - String[] meteredApnTypes = b.getStringArray(carrierConfig); - if (meteredApnTypes == null) { - Rlog.e(LOG_TAG, carrierConfig + " is not available. " + "subId = " + subId); - return true; - } - - HashSet meteredApnSet = new HashSet<>(Arrays.asList(meteredApnTypes)); - if (DBG) { - Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " - + Arrays.toString(meteredApnSet.toArray())); - } - - if (meteredApnSet.contains(ApnSetting.getApnTypeString(apnType))) { - if (DBG) Rlog.d(LOG_TAG, ApnSetting.getApnTypeString(apnType) + " is metered."); - return true; - } else if (apnType == ApnSetting.TYPE_ALL) { - // Assuming no configuration error, if at least one APN type is - // metered, then this APN setting is metered. - if (meteredApnSet.size() > 0) { - if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered."); - return true; - } - } - - if (DBG) Rlog.d(LOG_TAG, ApnSetting.getApnTypeString(apnType) + " is not metered."); - return false; - } - - /** - * Check if this APN setting is metered. - * - * @param apn APN setting - * @param phone The phone object - * @return True if this APN setting is metered, otherwise false. - */ - public static boolean isMetered(ApnSetting apn, Phone phone) { - if (phone == null || apn == null) { - return true; - } - - for (int apnType : apn.getApnTypes()) { - // If one of the APN type is metered, then this APN setting is metered. - if (isMeteredApnType(apnType, phone)) { - return true; - } - } - return false; - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java deleted file mode 100644 index 255972af01..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java +++ /dev/null @@ -1,4094 +0,0 @@ -/* - * Copyright (C) 2006 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.dataconnection; - -import static android.telephony.data.DataCallResponse.PDU_SESSION_ID_NOT_SET; - -import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_HANDOVER; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.PendingIntent; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.UserInfo; -import android.net.ConnectivityManager; -import android.net.InetAddresses; -import android.net.KeepalivePacketData; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.NetworkAgentConfig; -import android.net.NetworkCapabilities; -import android.net.NetworkFactory; -import android.net.NetworkProvider; -import android.net.NetworkRequest; -import android.net.ProxyInfo; -import android.net.RouteInfo; -import android.net.SocketKeepalive; -import android.net.TelephonyNetworkSpecifier; -import android.net.vcn.VcnManager; -import android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener; -import android.net.vcn.VcnNetworkPolicyResult; -import android.os.AsyncResult; -import android.os.HandlerExecutor; -import android.os.Message; -import android.os.PersistableBundle; -import android.os.Process; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserManager; -import android.provider.Telephony; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.TransportType; -import android.telephony.Annotation.ApnType; -import android.telephony.Annotation.DataFailureCause; -import android.telephony.Annotation.DataState; -import android.telephony.Annotation.NetworkType; -import android.telephony.CarrierConfigManager; -import android.telephony.DataFailCause; -import android.telephony.LinkCapacityEstimate; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.PreciseDataConnectionState; -import android.telephony.ServiceState; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.telephony.data.DataCallResponse.HandoverFailureMode; -import android.telephony.data.DataProfile; -import android.telephony.data.DataService; -import android.telephony.data.DataServiceCallback; -import android.telephony.data.NetworkSliceInfo; -import android.telephony.data.Qos; -import android.telephony.data.QosBearerSession; -import android.telephony.data.TrafficDescriptor; -import android.text.TextUtils; -import android.util.LocalLog; -import android.util.Pair; -import android.util.TimeUtils; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.CarrierPrivilegesTracker; -import com.android.internal.telephony.CarrierSignalAgent; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.RIL; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.TelephonyStatsLog; -import com.android.internal.telephony.data.DataConfigManager; -import com.android.internal.telephony.data.KeepaliveStatus; -import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; -import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; -import com.android.internal.telephony.metrics.DataCallSessionStats; -import com.android.internal.telephony.metrics.TelephonyMetrics; -import com.android.internal.telephony.nano.TelephonyProto.RilDataCall; -import com.android.internal.telephony.uicc.IccUtils; -import com.android.internal.telephony.util.ArrayUtils; -import com.android.internal.util.AsyncChannel; -import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Protocol; -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; -import com.android.net.module.util.NetworkCapabilitiesUtils; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -/** - * {@hide} - * - * DataConnection StateMachine. - * - * This a class for representing a single data connection, with instances of this - * class representing a connection via the cellular network. There may be multiple - * data connections and all of them are managed by the DataConnectionTracker. - * - * NOTE: All DataConnection objects must be running on the same looper, which is the default - * as the coordinator has members which are used without synchronization. - */ -public class DataConnection extends StateMachine { - private static final boolean DBG = true; - private static final boolean VDBG = true; - - private static final String NETWORK_TYPE = "MOBILE"; - - private static final String RAT_NAME_5G = "nr"; - private static final String RAT_NAME_EVDO = "evdo"; - - /** - * OSId for "Android", using UUID version 5 with namespace ISO OSI. - * Prepended to the OsAppId in TrafficDescriptor to use for URSP matching. - */ - private static final UUID OS_ID = UUID.fromString("97a498e3-fc92-5c94-8986-0333d06e4e47"); - - /** - * The data connection is not being or been handovered. Note this is the state for the source - * data connection, not destination data connection - */ - private static final int HANDOVER_STATE_IDLE = 1; - - /** - * The data connection is being handovered. Note this is the state for the source - * data connection, not destination data connection. - */ - private static final int HANDOVER_STATE_BEING_TRANSFERRED = 2; - - /** - * The data connection is already handovered. Note this is the state for the source - * data connection, not destination data connection. - */ - private static final int HANDOVER_STATE_COMPLETED = 3; - - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"HANDOVER_STATE_"}, value = { - HANDOVER_STATE_IDLE, - HANDOVER_STATE_BEING_TRANSFERRED, - HANDOVER_STATE_COMPLETED}) - public @interface HandoverState {} - - // The data connection providing default Internet connection will have a higher score of 50. - // Other connections will have a slightly lower score of 45. The intention is other connections - // will not cause ConnectivityService to tear down default internet connection. For example, - // to validate Internet connection on non-default data SIM, we'll set up a temporary Internet - // connection on that data SIM. In this case, score of 45 is assigned so ConnectivityService - // will not replace the default Internet connection with it. - private static final int DEFAULT_INTERNET_CONNECTION_SCORE = 50; - private static final int OTHER_CONNECTION_SCORE = 45; - - // The score we report to connectivity service - private int mScore; - - // The subscription id associated with this data connection. - private int mSubId; - - // The data connection controller - private DcController mDcController; - - // The Tester for failing all bringup's - private DcTesterFailBringUpAll mDcTesterFailBringUpAll; - - // Whether or not the data connection should allocate its own pdu session id - private boolean mDoAllocatePduSessionId; - - private static AtomicInteger mInstanceNumber = new AtomicInteger(0); - private AsyncChannel mAc; - - // The DCT that's talking to us, we only support one! - private DcTracker mDct = null; - - private String[] mPcscfAddr; - - private final String mTagSuffix; - - private final LocalLog mHandoverLocalLog = new LocalLog(64); - - private int[] mAdministratorUids = new int[0]; - - // stats per data call - private DataCallSessionStats mDataCallSessionStats; - - /** - * Used internally for saving connecting parameters. - */ - public static class ConnectionParams { - int mTag; - ApnContext mApnContext; - int mProfileId; - int mRilRat; - Message mOnCompletedMsg; - final int mConnectionGeneration; - @RequestNetworkType - final int mRequestType; - final int mSubId; - final boolean mIsPreferredApn; - - ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology, - Message onCompletedMsg, int connectionGeneration, - @RequestNetworkType int requestType, int subId, - boolean isPreferredApn) { - mApnContext = apnContext; - mProfileId = profileId; - mRilRat = rilRadioTechnology; - mOnCompletedMsg = onCompletedMsg; - mConnectionGeneration = connectionGeneration; - mRequestType = requestType; - mSubId = subId; - mIsPreferredApn = isPreferredApn; - } - - @Override - public String toString() { - return "{mTag=" + mTag + " mApnContext=" + mApnContext - + " mProfileId=" + mProfileId - + " mRat=" + mRilRat - + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) - + " mRequestType=" + DcTracker.requestTypeToString(mRequestType) - + " mSubId=" + mSubId - + " mIsPreferredApn=" + mIsPreferredApn - + "}"; - } - } - - /** - * Used internally for saving disconnecting parameters. - */ - public static class DisconnectParams { - int mTag; - public ApnContext mApnContext; - String mReason; - @ReleaseNetworkType - final int mReleaseType; - Message mOnCompletedMsg; - - DisconnectParams(ApnContext apnContext, String reason, @ReleaseNetworkType int releaseType, - Message onCompletedMsg) { - mApnContext = apnContext; - mReason = reason; - mReleaseType = releaseType; - mOnCompletedMsg = onCompletedMsg; - } - - @Override - public String toString() { - return "{mTag=" + mTag + " mApnContext=" + mApnContext - + " mReason=" + mReason - + " mReleaseType=" + DcTracker.releaseTypeToString(mReleaseType) - + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; - } - } - - private volatile ApnSetting mApnSetting; - private ConnectionParams mConnectionParams; - private DisconnectParams mDisconnectParams; - @DataFailureCause - private int mDcFailCause; - - @HandoverFailureMode - private int mHandoverFailureMode; - - private Phone mPhone; - private DataServiceManager mDataServiceManager; - private VcnManager mVcnManager; - private final int mTransportType; - private LinkProperties mLinkProperties = new LinkProperties(); - private int mPduSessionId; - private long mCreateTime; - private long mLastFailTime; - @DataFailureCause - private int mLastFailCause; - private static final String NULL_IP = "0.0.0.0"; - private Object mUserData; - private boolean mCongestedOverride; - private boolean mUnmeteredOverride; - private int mRilRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; - private int mDataRegState = Integer.MAX_VALUE; - // Indicating data connection is suspended due to temporary reasons, for example, out of - // service, concurrency voice/data not supported, etc.. Note this flag is only meaningful when - // data is in active state. When data is in inactive, connecting, or disconnecting, this flag - // is unmeaningful. - private boolean mIsSuspended; - private int mDownlinkBandwidth = 14; - private int mUplinkBandwidth = 14; - private Qos mDefaultQos = null; - private List mQosBearerSessions = new ArrayList<>(); - private NetworkSliceInfo mSliceInfo; - private List mTrafficDescriptors = new ArrayList<>(); - - /** The corresponding network agent for this data connection. */ - private DcNetworkAgent mNetworkAgent; - - /** - * The network agent from handover source data connection. This is the potential network agent - * that will be transferred here after handover completed. - */ - private DcNetworkAgent mHandoverSourceNetworkAgent; - - private int mDisabledApnTypeBitMask = 0; - - int mTag; - - /** Data connection id assigned by the modem. This is unique across transports */ - public int mCid; - - @HandoverState - private int mHandoverState = HANDOVER_STATE_IDLE; - private final Map mApnContexts = new ConcurrentHashMap<>(); - PendingIntent mReconnectIntent = null; - - /** Class used to track VCN-defined Network policies for this DcNetworkAgent. */ - private final VcnNetworkPolicyChangeListener mVcnPolicyChangeListener = - new DataConnectionVcnNetworkPolicyChangeListener(); - - // ***** Event codes for driving the state machine, package visible for Dcc - static final int BASE = Protocol.BASE_DATA_CONNECTION; - static final int EVENT_CONNECT = BASE + 0; - static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1; - static final int EVENT_DEACTIVATE_DONE = BASE + 3; - static final int EVENT_DISCONNECT = BASE + 4; - static final int EVENT_DISCONNECT_ALL = BASE + 6; - static final int EVENT_DATA_STATE_CHANGED = BASE + 7; - static final int EVENT_TEAR_DOWN_NOW = BASE + 8; - static final int EVENT_LOST_CONNECTION = BASE + 9; - static final int EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED = BASE + 11; - static final int EVENT_DATA_CONNECTION_ROAM_ON = BASE + 12; - static final int EVENT_DATA_CONNECTION_ROAM_OFF = BASE + 13; - static final int EVENT_BW_REFRESH_RESPONSE = BASE + 14; - static final int EVENT_DATA_CONNECTION_VOICE_CALL_STARTED = BASE + 15; - static final int EVENT_DATA_CONNECTION_VOICE_CALL_ENDED = BASE + 16; - static final int EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED = BASE + 17; - static final int EVENT_KEEPALIVE_STATUS = BASE + 18; - static final int EVENT_KEEPALIVE_STARTED = BASE + 19; - static final int EVENT_KEEPALIVE_STOPPED = BASE + 20; - static final int EVENT_KEEPALIVE_START_REQUEST = BASE + 21; - static final int EVENT_KEEPALIVE_STOP_REQUEST = BASE + 22; - static final int EVENT_LINK_CAPACITY_CHANGED = BASE + 23; - static final int EVENT_RESET = BASE + 24; - static final int EVENT_REEVALUATE_RESTRICTED_STATE = BASE + 25; - static final int EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES = BASE + 26; - static final int EVENT_NR_STATE_CHANGED = BASE + 27; - static final int EVENT_DATA_CONNECTION_METEREDNESS_CHANGED = BASE + 28; - static final int EVENT_NR_FREQUENCY_CHANGED = BASE + 29; - static final int EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED = BASE + 30; - static final int EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED = BASE + 31; - static final int EVENT_CSS_INDICATOR_CHANGED = BASE + 32; - static final int EVENT_UPDATE_SUSPENDED_STATE = BASE + 33; - static final int EVENT_START_HANDOVER = BASE + 34; - static final int EVENT_CANCEL_HANDOVER = BASE + 35; - static final int EVENT_START_HANDOVER_ON_TARGET = BASE + 36; - static final int EVENT_ALLOCATE_PDU_SESSION_ID = BASE + 37; - static final int EVENT_RELEASE_PDU_SESSION_ID = BASE + 38; - static final int EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE = BASE + 39; - private static final int CMD_TO_STRING_COUNT = EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE - BASE + 1; - - private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; - static { - sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT"; - sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] = - "EVENT_SETUP_DATA_CONNECTION_DONE"; - sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE"; - sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT"; - sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL"; - sCmdToString[EVENT_DATA_STATE_CHANGED - BASE] = "EVENT_DATA_STATE_CHANGED"; - sCmdToString[EVENT_TEAR_DOWN_NOW - BASE] = "EVENT_TEAR_DOWN_NOW"; - sCmdToString[EVENT_LOST_CONNECTION - BASE] = "EVENT_LOST_CONNECTION"; - sCmdToString[EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED - BASE] = - "EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"; - sCmdToString[EVENT_DATA_CONNECTION_ROAM_ON - BASE] = "EVENT_DATA_CONNECTION_ROAM_ON"; - sCmdToString[EVENT_DATA_CONNECTION_ROAM_OFF - BASE] = "EVENT_DATA_CONNECTION_ROAM_OFF"; - sCmdToString[EVENT_BW_REFRESH_RESPONSE - BASE] = "EVENT_BW_REFRESH_RESPONSE"; - sCmdToString[EVENT_DATA_CONNECTION_VOICE_CALL_STARTED - BASE] = - "EVENT_DATA_CONNECTION_VOICE_CALL_STARTED"; - sCmdToString[EVENT_DATA_CONNECTION_VOICE_CALL_ENDED - BASE] = - "EVENT_DATA_CONNECTION_VOICE_CALL_ENDED"; - sCmdToString[EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED - BASE] = - "EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED"; - sCmdToString[EVENT_KEEPALIVE_STATUS - BASE] = "EVENT_KEEPALIVE_STATUS"; - sCmdToString[EVENT_KEEPALIVE_STARTED - BASE] = "EVENT_KEEPALIVE_STARTED"; - sCmdToString[EVENT_KEEPALIVE_STOPPED - BASE] = "EVENT_KEEPALIVE_STOPPED"; - sCmdToString[EVENT_KEEPALIVE_START_REQUEST - BASE] = "EVENT_KEEPALIVE_START_REQUEST"; - sCmdToString[EVENT_KEEPALIVE_STOP_REQUEST - BASE] = "EVENT_KEEPALIVE_STOP_REQUEST"; - sCmdToString[EVENT_LINK_CAPACITY_CHANGED - BASE] = "EVENT_LINK_CAPACITY_CHANGED"; - sCmdToString[EVENT_RESET - BASE] = "EVENT_RESET"; - sCmdToString[EVENT_REEVALUATE_RESTRICTED_STATE - BASE] = - "EVENT_REEVALUATE_RESTRICTED_STATE"; - sCmdToString[EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES - BASE] = - "EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES"; - sCmdToString[EVENT_NR_STATE_CHANGED - BASE] = "EVENT_NR_STATE_CHANGED"; - sCmdToString[EVENT_DATA_CONNECTION_METEREDNESS_CHANGED - BASE] = - "EVENT_DATA_CONNECTION_METEREDNESS_CHANGED"; - sCmdToString[EVENT_NR_FREQUENCY_CHANGED - BASE] = "EVENT_NR_FREQUENCY_CHANGED"; - sCmdToString[EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED - BASE] = - "EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED"; - sCmdToString[EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED - BASE] = - "EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED"; - sCmdToString[EVENT_CSS_INDICATOR_CHANGED - BASE] = "EVENT_CSS_INDICATOR_CHANGED"; - sCmdToString[EVENT_UPDATE_SUSPENDED_STATE - BASE] = "EVENT_UPDATE_SUSPENDED_STATE"; - sCmdToString[EVENT_START_HANDOVER - BASE] = "EVENT_START_HANDOVER"; - sCmdToString[EVENT_CANCEL_HANDOVER - BASE] = "EVENT_CANCEL_HANDOVER"; - sCmdToString[EVENT_START_HANDOVER_ON_TARGET - BASE] = "EVENT_START_HANDOVER_ON_TARGET"; - sCmdToString[EVENT_ALLOCATE_PDU_SESSION_ID - BASE] = "EVENT_ALLOCATE_PDU_SESSION_ID"; - sCmdToString[EVENT_RELEASE_PDU_SESSION_ID - BASE] = "EVENT_RELEASE_PDU_SESSION_ID"; - sCmdToString[EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE - BASE] = - "EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE"; - } - // Convert cmd to string or null if unknown - static String cmdToString(int cmd) { - String value = null; - cmd -= BASE; - if ((cmd >= 0) && (cmd < sCmdToString.length)) { - value = sCmdToString[cmd]; - } - if (value == null) { - value = "0x" + Integer.toHexString(cmd + BASE); - } - return value; - } - - /** - * Create the connection object - * - * @param phone the Phone - * @param id the connection id - * @return DataConnection that was created. - */ - public static DataConnection makeDataConnection(Phone phone, int id, DcTracker dct, - DataServiceManager dataServiceManager, - DcTesterFailBringUpAll failBringUpAll, - DcController dcc) { - String transportType = (dataServiceManager.getTransportType() - == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - ? "C" // Cellular - : "I"; // IWLAN - DataConnection dc = new DataConnection(phone, transportType + "-" - + mInstanceNumber.incrementAndGet(), id, dct, dataServiceManager, failBringUpAll, - dcc); - dc.start(); - if (DBG) dc.log("Made " + dc.getName()); - return dc; - } - - void dispose() { - log("dispose: call quiteNow()"); - quitNow(); - } - - /* Getter functions */ - - LinkProperties getLinkProperties() { - return new LinkProperties(mLinkProperties); - } - - boolean isDisconnecting() { - return getCurrentState() == mDisconnectingState - || getCurrentState() == mDisconnectingErrorCreatingConnection; - } - - @VisibleForTesting - public boolean isActive() { - return getCurrentState() == mActiveState; - } - - @VisibleForTesting - public boolean isInactive() { - return getCurrentState() == mInactiveState; - } - - boolean isActivating() { - return getCurrentState() == mActivatingState; - } - - boolean hasBeenTransferred() { - return mHandoverState == HANDOVER_STATE_COMPLETED; - } - - int getCid() { - return mCid; - } - - /** - * @return DataConnection's ApnSetting. - */ - public ApnSetting getApnSetting() { - return mApnSetting; - } - - /** - * Update http proxy of link properties based on current apn setting - */ - private void updateLinkPropertiesHttpProxy() { - if (mApnSetting == null - || TextUtils.isEmpty(mApnSetting.getProxyAddressAsString())) { - return; - } - try { - int port = mApnSetting.getProxyPort(); - if (port == -1) { - port = 8080; - } - ProxyInfo proxy = ProxyInfo.buildDirectProxy( - mApnSetting.getProxyAddressAsString(), port); - mLinkProperties.setHttpProxy(proxy); - } catch (NumberFormatException e) { - loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" - + mApnSetting.getProxyPort() + "): " + e); - } - } - - public static class UpdateLinkPropertyResult { - public SetupResult setupResult = SetupResult.SUCCESS; - public LinkProperties oldLp; - public LinkProperties newLp; - public UpdateLinkPropertyResult(LinkProperties curLp) { - oldLp = curLp; - newLp = curLp; - } - } - - /** - * Class returned by onSetupConnectionCompleted. - */ - public enum SetupResult { - SUCCESS, - ERROR_RADIO_NOT_AVAILABLE, - ERROR_INVALID_ARG, - ERROR_STALE, - ERROR_DATA_SERVICE_SPECIFIC_ERROR, - ERROR_DUPLICATE_CID, - ERROR_NO_DEFAULT_CONNECTION; - - public int mFailCause; - - SetupResult() { - mFailCause = DataFailCause.getFailCause(0); - } - - @Override - public String toString() { - return name() + " SetupResult.mFailCause=" + DataFailCause.toString(mFailCause); - } - } - - public boolean isIpv4Connected() { - boolean ret = false; - Collection addresses = mLinkProperties.getAddresses(); - - for (InetAddress addr: addresses) { - if (addr instanceof java.net.Inet4Address) { - java.net.Inet4Address i4addr = (java.net.Inet4Address) addr; - if (!i4addr.isAnyLocalAddress() && !i4addr.isLinkLocalAddress() && - !i4addr.isLoopbackAddress() && !i4addr.isMulticastAddress()) { - ret = true; - break; - } - } - } - return ret; - } - - public boolean isIpv6Connected() { - boolean ret = false; - Collection addresses = mLinkProperties.getAddresses(); - - for (InetAddress addr: addresses) { - if (addr instanceof java.net.Inet6Address) { - java.net.Inet6Address i6addr = (java.net.Inet6Address) addr; - if (!i6addr.isAnyLocalAddress() && !i6addr.isLinkLocalAddress() && - !i6addr.isLoopbackAddress() && !i6addr.isMulticastAddress()) { - ret = true; - break; - } - } - } - return ret; - } - - public int getPduSessionId() { - return mPduSessionId; - } - - public NetworkSliceInfo getSliceInfo() { - return mSliceInfo; - } - - public List getTrafficDescriptors() { - return mTrafficDescriptors; - } - - /** - * Update DC fields based on a new DataCallResponse - * @param response the response to use to update DC fields - */ - public void updateResponseFields(DataCallResponse response) { - updateQosParameters(response); - updateSliceInfo(response); - updateTrafficDescriptors(response); - } - - public void updateQosParameters(final @Nullable DataCallResponse response) { - if (response == null) { - mDefaultQos = null; - mQosBearerSessions.clear(); - return; - } - - mDefaultQos = response.getDefaultQos(); - mQosBearerSessions = response.getQosBearerSessions(); - - if (mNetworkAgent != null) { - syncQosToNetworkAgent(); - } - } - - private void syncQosToNetworkAgent() { - final DcNetworkAgent networkAgent = mNetworkAgent; - final List qosBearerSessions = mQosBearerSessions; - if (qosBearerSessions == null) { - networkAgent.updateQosBearerSessions(new ArrayList<>()); - return; - } - networkAgent.updateQosBearerSessions(qosBearerSessions); - } - - /** - * Update the latest slice info on this data connection with - * {@link DataCallResponse#getSliceInfo}. - */ - public void updateSliceInfo(DataCallResponse response) { - mSliceInfo = response.getSliceInfo(); - } - - /** - * Update the latest traffic descriptor on this data connection with - * {@link DataCallResponse#getTrafficDescriptors}. - */ - public void updateTrafficDescriptors(DataCallResponse response) { - mTrafficDescriptors = response.getTrafficDescriptors(); - mDcController.updateTrafficDescriptorsForCid(response.getId(), - response.getTrafficDescriptors()); - } - - @VisibleForTesting - public UpdateLinkPropertyResult updateLinkProperty(DataCallResponse newState) { - UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties); - - if (newState == null) return result; - - result.newLp = new LinkProperties(); - - // set link properties based on data call response - result.setupResult = setLinkProperties(newState, result.newLp); - if (result.setupResult != SetupResult.SUCCESS) { - if (DBG) log("updateLinkProperty failed : " + result.setupResult); - return result; - } - // copy HTTP proxy as it is not part DataCallResponse. - result.newLp.setHttpProxy(mLinkProperties.getHttpProxy()); - - checkSetMtu(mApnSetting, result.newLp); - - mLinkProperties = result.newLp; - - updateTcpBufferSizes(mRilRat); - - if (DBG && (! result.oldLp.equals(result.newLp))) { - log("updateLinkProperty old LP=" + result.oldLp); - log("updateLinkProperty new LP=" + result.newLp); - } - - if (result.newLp.equals(result.oldLp) == false && - mNetworkAgent != null) { - mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); - } - - return result; - } - - /** - * Sets the pdu session id of the data connection - * @param pduSessionId pdu session id to set - */ - @VisibleForTesting - public void setPduSessionId(int pduSessionId) { - if (mPduSessionId != pduSessionId) { - logd("Changing pdu session id from: " + mPduSessionId + " to: " + pduSessionId + ", " - + "Handover state: " + handoverStateToString(this.mHandoverState)); - mPduSessionId = pduSessionId; - } - } - - /** - * Read the MTU value from link properties where it can be set from network. In case - * not set by the network, set it again using the mtu szie value defined in the APN - * database for the connected APN - */ - private void checkSetMtu(ApnSetting apn, LinkProperties lp) { - if (lp == null) return; - - if (apn == null || lp == null) return; - - if (lp.getMtu() != PhoneConstants.UNSET_MTU) { - if (DBG) log("MTU set by call response to: " + lp.getMtu()); - return; - } - - if (apn != null && apn.getMtuV4() != PhoneConstants.UNSET_MTU) { - lp.setMtu(apn.getMtuV4()); - if (DBG) log("MTU set by APN to: " + apn.getMtuV4()); - return; - } - - int mtu = mPhone.getContext().getResources().getInteger( - com.android.internal.R.integer.config_mobile_mtu); - if (mtu != PhoneConstants.UNSET_MTU) { - lp.setMtu(mtu); - if (DBG) log("MTU set by config resource to: " + mtu); - } - } - - //***** Constructor (NOTE: uses dcc.getHandler() as its Handler) - private DataConnection(Phone phone, String tagSuffix, int id, - DcTracker dct, DataServiceManager dataServiceManager, - DcTesterFailBringUpAll failBringUpAll, DcController dcc) { - super("DC-" + tagSuffix, dcc); - mTagSuffix = tagSuffix; - setLogRecSize(300); - setLogOnlyTransitions(true); - if (DBG) log("DataConnection created"); - - mPhone = phone; - mDct = dct; - mDataServiceManager = dataServiceManager; - mVcnManager = mPhone.getContext().getSystemService(VcnManager.class); - mTransportType = dataServiceManager.getTransportType(); - mDcTesterFailBringUpAll = failBringUpAll; - mDcController = dcc; - mId = id; - mCid = -1; - mDataRegState = mPhone.getServiceState().getDataRegistrationState(); - mIsSuspended = false; - mDataCallSessionStats = new DataCallSessionStats(mPhone); - mDoAllocatePduSessionId = false; - - int networkType = getNetworkType(); - mRilRat = ServiceState.networkTypeToRilRadioTechnology(networkType); - updateLinkBandwidthsFromCarrierConfig(mRilRat); - - addState(mDefaultState); - addState(mInactiveState, mDefaultState); - addState(mActivatingState, mDefaultState); - addState(mActiveState, mDefaultState); - addState(mDisconnectingState, mDefaultState); - addState(mDisconnectingErrorCreatingConnection, mDefaultState); - setInitialState(mInactiveState); - } - - private @NetworkType int getNetworkType() { - ServiceState ss = mPhone.getServiceState(); - int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - - NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, mTransportType); - if (nri != null) { - networkType = nri.getAccessNetworkTechnology(); - } - - return networkType; - } - - /** - * Get the source transport for handover. For example, handover from WWAN to WLAN, WWAN is the - * source transport, and vice versa. - */ - private @TransportType int getHandoverSourceTransport() { - return mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN - ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN - : AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - } - - /** - * API to generate the OsAppId for enterprise traffic category. - * @return byte[] representing OsId + length of OsAppId + OsAppId - */ - @VisibleForTesting - public static byte[] getEnterpriseOsAppId() { - byte[] osAppId = NetworkCapabilities.getCapabilityCarrierName( - NetworkCapabilities.NET_CAPABILITY_ENTERPRISE).getBytes(); - // 16 bytes for UUID, 1 byte for length of osAppId, and up to 255 bytes for osAppId - ByteBuffer bb = ByteBuffer.allocate(16 + 1 + osAppId.length); - bb.putLong(OS_ID.getMostSignificantBits()); - bb.putLong(OS_ID.getLeastSignificantBits()); - bb.put((byte) osAppId.length); - bb.put(osAppId); - if (VDBG) { - Rlog.d("DataConnection", "getEnterpriseOsAppId: " - + IccUtils.bytesToHexString(bb.array())); - } - return bb.array(); - } - - /** - * Begin setting up a data connection, calls setupDataCall - * and the ConnectionParams will be returned with the - * EVENT_SETUP_DATA_CONNECTION_DONE - * - * @param cp is the connection parameters - * - * @return Fail cause if failed to setup data connection. {@link DataFailCause#NONE} if success. - */ - private @DataFailureCause int connect(ConnectionParams cp) { - log("connect: carrier='" + mApnSetting.getEntryName() - + "' APN='" + mApnSetting.getApnName() - + "' proxy='" + mApnSetting.getProxyAddressAsString() - + "' port='" + mApnSetting.getProxyPort() + "'"); - ApnContext.requestLog(cp.mApnContext, "DataConnection.connect"); - - // Check if we should fake an error. - if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter > 0) { - DataCallResponse response = new DataCallResponse.Builder() - .setCause(mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause) - .setRetryDurationMillis( - mDcTesterFailBringUpAll.getDcFailBringUp().mSuggestedRetryTime) - .setMtuV4(PhoneConstants.UNSET_MTU) - .setMtuV6(PhoneConstants.UNSET_MTU) - .build(); - - Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp); - AsyncResult.forMessage(msg, response, null); - sendMessage(msg); - if (DBG) { - log("connect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp() - + " send error response=" + response); - } - mDcTesterFailBringUpAll.getDcFailBringUp().mCounter -= 1; - return DataFailCause.NONE; - } - - mCreateTime = -1; - mLastFailTime = -1; - mLastFailCause = DataFailCause.NONE; - - Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp); - msg.obj = cp; - - DataProfile dp = new DataProfile.Builder() - .setApnSetting(mApnSetting) - .setPreferred(cp.mIsPreferredApn) - .build(); - - // We need to use the actual modem roaming state instead of the framework roaming state - // here. This flag is only passed down to ril_service for picking the correct protocol (for - // old modem backward compatibility). - boolean isModemRoaming = mPhone.getServiceState().getDataRoamingFromRegistration(); - - // If the apn is NOT metered, we will allow data roaming regardless of the setting. - boolean isUnmeteredApnType = !ApnSettingUtils.isMeteredApnType( - cp.mApnContext.getApnTypeBitmask(), mPhone); - - // Set this flag to true if the user turns on data roaming. Or if we override the roaming - // state in framework, we should set this flag to true as well so the modem will not reject - // the data call setup (because the modem actually thinks the device is roaming). - boolean allowRoaming = mPhone.getDataRoamingEnabled() - || (isModemRoaming && (!mPhone.getServiceState().getDataRoaming() - || isUnmeteredApnType)); - - String dnn = null; - byte[] osAppId = null; - if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { - osAppId = getEnterpriseOsAppId(); - } else { - dnn = mApnSetting.getApnName(); - } - final TrafficDescriptor td = osAppId == null && dnn == null ? null - : new TrafficDescriptor(dnn, osAppId); - final boolean matchAllRuleAllowed = td == null || td.getOsAppId() == null; - - if (DBG) { - log("allowRoaming=" + allowRoaming - + ", mPhone.getDataRoamingEnabled()=" + mPhone.getDataRoamingEnabled() - + ", isModemRoaming=" + isModemRoaming - + ", mPhone.getServiceState().getDataRoaming()=" - + mPhone.getServiceState().getDataRoaming() - + ", isUnmeteredApnType=" + isUnmeteredApnType - + ", trafficDescriptor=" + td - + ", matchAllRuleAllowed=" + matchAllRuleAllowed - ); - } - - // Check if this data setup is a handover. - LinkProperties linkProperties = null; - int reason = DataService.REQUEST_REASON_NORMAL; - if (cp.mRequestType == REQUEST_TYPE_HANDOVER) { - // If this is a data setup for handover, we need to pass the link properties - // of the existing data connection to the modem. - DcTracker srcDcTracker = mPhone.getDcTracker(getHandoverSourceTransport()); - if (srcDcTracker == null || cp.mApnContext == null) { - loge("connect: Handover failed. dcTracker=" + srcDcTracker + ", apnContext=" - + cp.mApnContext); - return DataFailCause.HANDOVER_FAILED; - } - - - // srcDc is the source data connection while the current instance is the target - DataConnection srcDc = - srcDcTracker.getDataConnectionByApnType(cp.mApnContext.getApnType()); - if (srcDc == null) { - loge("connect: Can't find data connection for handover."); - return DataFailCause.HANDOVER_FAILED; - } - - // Helpful for logging purposes - DataServiceManager srcDsm = srcDc.mDataServiceManager; - String srcDsmTag = (srcDsm == null ? "(null)" : srcDsm.getTag()); - logd("connect: REQUEST_TYPE_HANDOVER - Request handover from " + srcDc.getName() - + ", targetDsm=" + mDataServiceManager.getTag() - + ", sourceDsm=" + srcDsmTag); - - - /* startHandover is called on the source data connection, and if successful, - we ask the target data connection (which is the current instance) to call - #setupDataCall with request type handover. - */ - Consumer onCompleted = (dataServiceCallbackResultCode) -> - /* startHandover is called on the srcDc handler, but the callback needs to - be called on the current (which is the targetDc) handler which is why we - call sendRunnableMessage. */ - sendRunnableMessage(EVENT_START_HANDOVER_ON_TARGET, - (inCorrectState) -> requestHandover(inCorrectState, srcDc, - dataServiceCallbackResultCode, - cp, msg, dp, isModemRoaming, allowRoaming)); - srcDc.startHandover(onCompleted); - return DataFailCause.NONE; - } - - // setup data call for REQUEST_TYPE_NORMAL - mDoAllocatePduSessionId = mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN; - allocatePduSessionId(psi -> { - this.setPduSessionId(psi); - mDataServiceManager.setupDataCall( - ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), - dp, - isModemRoaming, - allowRoaming, - reason, - linkProperties, - psi, - null, //slice info is null since this is not a handover - td, - matchAllRuleAllowed, - msg); - TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat, - dp.getProfileId(), dp.getApn(), dp.getProtocolType()); - }); - return DataFailCause.NONE; - } - - private void allocatePduSessionId(Consumer allocateCallback) { - if (mDoAllocatePduSessionId) { - Message msg = this.obtainMessage(EVENT_ALLOCATE_PDU_SESSION_ID); - msg.obj = allocateCallback; - mPhone.mCi.allocatePduSessionId(msg); - } else { - allocateCallback.accept(PDU_SESSION_ID_NOT_SET); - } - } - - private void onRquestHandoverFailed(ConnectionParams cp) { - sendMessage(obtainMessage(EVENT_CANCEL_HANDOVER)); - notifyConnectCompleted(cp, DataFailCause.UNKNOWN, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); - } - - private void requestHandover(boolean inCorrectState, DataConnection srcDc, - @DataServiceCallback.ResultCode int resultCode, - ConnectionParams cp, Message msg, DataProfile dp, boolean isModemRoaming, - boolean allowRoaming) { - - if (!inCorrectState) { - logd("requestHandover: Not in correct state"); - if (isResultCodeSuccess(resultCode)) { - if (srcDc != null) { - logd("requestHandover: Not in correct state - Success result code"); - // We need to cancel the handover on source if we ended up in the wrong state. - srcDc.cancelHandover(); - } else { - logd("requestHandover: Not in correct state - Success result code - " - + "srcdc = null"); - } - } - onRquestHandoverFailed(cp); - return; - } else if (!isResultCodeSuccess(resultCode)) { - if (DBG) { - logd("requestHandover: Non success result code from DataService, " - + "setupDataCall will not be called, result code = " - + DataServiceCallback.resultCodeToString(resultCode)); - } - onRquestHandoverFailed(cp); - return; - } - - if (srcDc == null) { - loge("requestHandover: Cannot find source data connection."); - onRquestHandoverFailed(cp); - return; - } - - LinkProperties linkProperties; - int reason; - - // Preserve the potential network agent from the source data connection. The ownership - // is not transferred at this moment. - mHandoverSourceNetworkAgent = srcDc.getNetworkAgent(); - if (mHandoverSourceNetworkAgent == null) { - loge("requestHandover: Cannot get network agent from the source dc " + srcDc.getName()); - onRquestHandoverFailed(cp); - return; - } - - linkProperties = srcDc.getLinkProperties(); - if (linkProperties == null || linkProperties.getLinkAddresses().isEmpty()) { - loge("requestHandover: Can't find link properties of handover data connection. dc=" - + srcDc); - onRquestHandoverFailed(cp); - return; - } - - mHandoverLocalLog.log("Handover started. Preserved the agent."); - log("Get the handover source network agent: " + mHandoverSourceNetworkAgent); - - reason = DataService.REQUEST_REASON_HANDOVER; - - TrafficDescriptor td = dp.getApn() == null ? null - : new TrafficDescriptor(dp.getApn(), null); - boolean matchAllRuleAllowed = true; - - mDataServiceManager.setupDataCall( - ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), - dp, - isModemRoaming, - allowRoaming, - reason, - linkProperties, - srcDc.getPduSessionId(), - srcDc.getSliceInfo(), - td, - matchAllRuleAllowed, - msg); - TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat, - dp.getProfileId(), dp.getApn(), dp.getProtocolType()); - } - - /** - * Called on the source data connection from the target data connection. - */ - @VisibleForTesting - public void startHandover(Consumer onTargetDcComplete) { - logd("startHandover: " + toStringSimple()); - // Set the handover state to being transferred on "this" data connection which is the src. - setHandoverState(HANDOVER_STATE_BEING_TRANSFERRED); - - Consumer onSrcDcComplete = - resultCode -> onHandoverStarted(resultCode, onTargetDcComplete); - /* - The flow here is: - srcDc#startHandover -> dataService#startHandover -> (onHandoverStarted) -> - onSrcDcComplete -> onTargetDcComplete - */ - mDataServiceManager.startHandover(mCid, - this.obtainMessage(EVENT_START_HANDOVER, - onSrcDcComplete)); - } - - /** - * Called on the source data connection when the async call to start handover is complete - */ - private void onHandoverStarted(@DataServiceCallback.ResultCode int resultCode, - Consumer onTargetDcComplete) { - logd("onHandoverStarted: " + toStringSimple()); - if (!isResultCodeSuccess(resultCode)) { - setHandoverState(HANDOVER_STATE_IDLE); - } - onTargetDcComplete.accept(resultCode); - } - - private void cancelHandover() { - if (mHandoverState != HANDOVER_STATE_BEING_TRANSFERRED) { - logd("cancelHandover: handover state is " + handoverStateToString(mHandoverState) - + ", expecting HANDOVER_STATE_BEING_TRANSFERRED"); - } - mDataServiceManager.cancelHandover(mCid, this.obtainMessage(EVENT_CANCEL_HANDOVER)); - setHandoverState(HANDOVER_STATE_IDLE); - } - - /** - * Update NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED based on congested override - * @param isCongested whether this DC should be set to congested or not - */ - public void onCongestednessChanged(boolean isCongested) { - sendMessage(obtainMessage(EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED, isCongested)); - } - - /** - * Update NetworkCapabilities.NET_CAPABILITY_NOT_METERED based on metered override - * @param isUnmetered whether this DC should be set to unmetered or not - */ - public void onMeterednessChanged(boolean isUnmetered) { - sendMessage(obtainMessage(EVENT_DATA_CONNECTION_METEREDNESS_CHANGED, isUnmetered)); - } - - /** - * TearDown the data connection when the deactivation is complete a Message with - * msg.what == EVENT_DEACTIVATE_DONE - * - * @param o is the object returned in the AsyncResult.obj. - */ - private void tearDownData(Object o) { - int discReason = DataService.REQUEST_REASON_NORMAL; - ApnContext apnContext = null; - if ((o != null) && (o instanceof DisconnectParams)) { - DisconnectParams dp = (DisconnectParams) o; - apnContext = dp.mApnContext; - if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF) - || TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) { - discReason = DataService.REQUEST_REASON_SHUTDOWN; - } else if (dp.mReleaseType == DcTracker.RELEASE_TYPE_HANDOVER) { - discReason = DataService.REQUEST_REASON_HANDOVER; - } - } - - String str = "tearDownData. mCid=" + mCid + ", reason=" + discReason; - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - - - //Needed to be final to work in a closure - final int fDiscReason = discReason; - releasePduSessionId(() -> { - // This is run after release pdu session id is complete - this.setPduSessionId(PDU_SESSION_ID_NOT_SET); - mDataServiceManager.deactivateDataCall(mCid, fDiscReason, - obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, o)); - mDataCallSessionStats.setDeactivateDataCallReason(fDiscReason); - }); - } - - private void releasePduSessionId(Runnable releaseCallback) { - // If the transport is IWLAN, and there is a valid PDU session id, also the data connection - // is not being handovered, we should release the pdu session id. - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN - && mHandoverState == HANDOVER_STATE_IDLE - && this.getPduSessionId() != PDU_SESSION_ID_NOT_SET) { - Message msg = this.obtainMessage(EVENT_RELEASE_PDU_SESSION_ID); - msg.obj = releaseCallback; - mPhone.mCi.releasePduSessionId(msg, this.getPduSessionId()); - } else { - // Just go and run the callback since we either have no pdu session id to release - // or we are in the middle of a handover - releaseCallback.run(); - } - } - - private void notifyAllWithEvent(ApnContext alreadySent, int event, String reason) { - for (ConnectionParams cp : mApnContexts.values()) { - ApnContext apnContext = cp.mApnContext; - if (apnContext == alreadySent) continue; - if (reason != null) apnContext.setReason(reason); - Pair pair = new Pair<>(apnContext, cp.mConnectionGeneration); - Message msg = mDct.obtainMessage(event, cp.mRequestType, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, pair); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - } - } - - /** - * Send the connectionCompletedMsg. - * - * @param cp is the ConnectionParams - * @param cause and if no error the cause is DataFailCause.NONE - * @param handoverFailureMode The action on handover failure - * @param sendAll is true if all contexts are to be notified - */ - private void notifyConnectCompleted(ConnectionParams cp, @DataFailureCause int cause, - @HandoverFailureMode int handoverFailureMode, boolean sendAll) { - ApnContext alreadySent = null; - - if (cp != null && cp.mOnCompletedMsg != null) { - // Get the completed message but only use it once - Message connectionCompletedMsg = cp.mOnCompletedMsg; - cp.mOnCompletedMsg = null; - alreadySent = cp.mApnContext; - - long timeStamp = System.currentTimeMillis(); - connectionCompletedMsg.arg1 = cp.mRequestType; - connectionCompletedMsg.arg2 = handoverFailureMode; - - if (cause == DataFailCause.NONE) { - mCreateTime = timeStamp; - AsyncResult.forMessage(connectionCompletedMsg); - } else { - mLastFailCause = cause; - mLastFailTime = timeStamp; - - // Return message with a Throwable exception to signify an error. - if (cause == DataFailCause.NONE) cause = DataFailCause.UNKNOWN; - AsyncResult.forMessage(connectionCompletedMsg, cause, - new Throwable(DataFailCause.toString(cause))); - } - if (DBG) { - log("notifyConnectCompleted at " + timeStamp + " cause=" - + DataFailCause.toString(cause) + " connectionCompletedMsg=" - + msgToString(connectionCompletedMsg)); - } - - connectionCompletedMsg.sendToTarget(); - } - if (sendAll) { - log("Send to all. " + alreadySent + " " + DataFailCause.toString(cause)); - notifyAllWithEvent(alreadySent, DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR, - DataFailCause.toString(cause)); - } - } - - /** - * Send ar.userObj if its a message, which is should be back to originator. - * - * @param dp is the DisconnectParams. - */ - private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) { - if (VDBG) log("NotifyDisconnectCompleted"); - - ApnContext alreadySent = null; - String reason = null; - - if (dp != null && dp.mOnCompletedMsg != null) { - // Get the completed message but only use it once - Message msg = dp.mOnCompletedMsg; - dp.mOnCompletedMsg = null; - if (msg.obj instanceof ApnContext) { - alreadySent = (ApnContext)msg.obj; - } - reason = dp.mReason; - if (VDBG) { - log(String.format("msg=%s msg.obj=%s", msg.toString(), - ((msg.obj instanceof String) ? (String) msg.obj : ""))); - } - AsyncResult.forMessage(msg); - msg.sendToTarget(); - } - if (sendAll) { - if (reason == null) { - reason = DataFailCause.toString(DataFailCause.UNKNOWN); - } - notifyAllWithEvent(alreadySent, DctConstants.EVENT_DISCONNECT_DONE, reason); - } - if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp); - } - - private void sendRunnableMessage(int eventCode, @NonNull final Consumer r) { - sendMessage(eventCode, r); - } - - /* - * ************************************************************************** - * Begin Members and methods owned by DataConnectionTracker but stored - * in a DataConnection because there is one per connection. - * ************************************************************************** - */ - - /* - * The id is owned by DataConnectionTracker. - */ - private int mId; - - /** - * Get the DataConnection ID - */ - public int getDataConnectionId() { - return mId; - } - - /* - * ************************************************************************** - * End members owned by DataConnectionTracker - * ************************************************************************** - */ - - /** - * Clear all settings called when entering mInactiveState. - */ - private synchronized void clearSettings() { - if (DBG) log("clearSettings"); - - mCreateTime = -1; - mLastFailTime = -1; - mLastFailCause = DataFailCause.NONE; - mCid = -1; - - mPcscfAddr = new String[5]; - - mLinkProperties = new LinkProperties(); - mApnContexts.clear(); - mApnSetting = null; - mUnmeteredUseOnly = false; - mMmsUseOnly = false; - mEnterpriseUse = false; - mRestrictedNetworkOverride = false; - mDcFailCause = DataFailCause.NONE; - mDisabledApnTypeBitMask = 0; - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - mCongestedOverride = false; - mUnmeteredOverride = false; - mDownlinkBandwidth = 14; - mUplinkBandwidth = 14; - mIsSuspended = false; - mHandoverState = HANDOVER_STATE_IDLE; - mHandoverFailureMode = DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN; - mSliceInfo = null; - mDefaultQos = null; - mDoAllocatePduSessionId = false; - mQosBearerSessions.clear(); - mTrafficDescriptors.clear(); - } - - /** - * Process setup data completion result from data service - * - * @param resultCode The result code returned by data service - * @param response Data call setup response from data service - * @param cp The original connection params used for data call setup - * @return Setup result - */ - private SetupResult onSetupConnectionCompleted(@DataServiceCallback.ResultCode int resultCode, - DataCallResponse response, - ConnectionParams cp) { - SetupResult result; - - log("onSetupConnectionCompleted: resultCode=" + resultCode + ", response=" + response); - if (cp.mTag != mTag) { - if (DBG) { - log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag); - } - result = SetupResult.ERROR_STALE; - } else if (resultCode == DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE) { - result = SetupResult.ERROR_RADIO_NOT_AVAILABLE; - result.mFailCause = DataFailCause.RADIO_NOT_AVAILABLE; - } else if (resultCode == DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE) { - result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; - result.mFailCause = DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE; - } else if (resultCode == DataServiceCallback.RESULT_ERROR_INVALID_ARG) { - result = SetupResult.ERROR_INVALID_ARG; - result.mFailCause = DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER; - } else if (response.getCause() != 0) { - if (response.getCause() == DataFailCause.RADIO_NOT_AVAILABLE) { - result = SetupResult.ERROR_RADIO_NOT_AVAILABLE; - result.mFailCause = DataFailCause.RADIO_NOT_AVAILABLE; - } else { - result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; - result.mFailCause = DataFailCause.getFailCause(response.getCause()); - } - } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE - && mDcController.getActiveDcByCid(response.getId()) != null) { - if (!mDcController.getTrafficDescriptorsForCid(response.getId()) - .equals(response.getTrafficDescriptors())) { - if (DBG) log("Updating traffic descriptors: " + response.getTrafficDescriptors()); - mDcController.getActiveDcByCid(response.getId()).updateTrafficDescriptors(response); - mDct.obtainMessage(DctConstants.EVENT_TRAFFIC_DESCRIPTORS_UPDATED).sendToTarget(); - } - if (DBG) log("DataConnection already exists for cid: " + response.getId()); - result = SetupResult.ERROR_DUPLICATE_CID; - result.mFailCause = DataFailCause.DUPLICATE_CID; - } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE - && !mDcController.isDefaultDataActive()) { - if (DBG) log("No default data connection currently active"); - mCid = response.getId(); - result = SetupResult.ERROR_NO_DEFAULT_CONNECTION; - result.mFailCause = DataFailCause.NO_DEFAULT_DATA; - } else { - if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse"); - mCid = response.getId(); - setPduSessionId(response.getPduSessionId()); - updatePcscfAddr(response); - updateResponseFields(response); - result = updateLinkProperty(response).setupResult; - } - - return result; - } - - private static boolean isResultCodeSuccess(int resultCode) { - return resultCode == DataServiceCallback.RESULT_SUCCESS - || resultCode == DataServiceCallback.RESULT_ERROR_UNSUPPORTED; - } - - private boolean isDnsOk(String[] domainNameServers) { - if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1]) - && !mPhone.isDnsCheckDisabled()) { - // Work around a race condition where QMI does not fill in DNS: - // Deactivate PDP and let DataConnectionTracker retry. - // Do not apply the race condition workaround for MMS APN - // if Proxy is an IP-address. - // Otherwise, the default APN will not be restored anymore. - if (!isIpAddress(mApnSetting.getMmsProxyAddressAsString())) { - log(String.format( - "isDnsOk: return false apn.types=%d APN_TYPE_MMS=%s isIpAddress(%s)=%s", - mApnSetting.getApnTypeBitmask(), ApnSetting.TYPE_MMS_STRING, - mApnSetting.getMmsProxyAddressAsString(), - isIpAddress(mApnSetting.getMmsProxyAddressAsString()))); - return false; - } - } - return true; - } - - /** - * TCP buffer size config based on the ril technology. There are 6 parameters - * read_min, read_default, read_max, write_min, write_default, write_max in the TCP buffer - * config string and they are separated by a comma. The unit of these parameters is byte. - */ - private static final String TCP_BUFFER_SIZES_GPRS = "4092,8760,48000,4096,8760,48000"; - private static final String TCP_BUFFER_SIZES_EDGE = "4093,26280,70800,4096,16384,70800"; - private static final String TCP_BUFFER_SIZES_UMTS = "58254,349525,1048576,58254,349525,1048576"; - private static final String TCP_BUFFER_SIZES_1XRTT = "16384,32768,131072,4096,16384,102400"; - private static final String TCP_BUFFER_SIZES_EVDO = "4094,87380,262144,4096,16384,262144"; - private static final String TCP_BUFFER_SIZES_EHRPD = "131072,262144,1048576,4096,16384,524288"; - private static final String TCP_BUFFER_SIZES_HSDPA = "61167,367002,1101005,8738,52429,262114"; - private static final String TCP_BUFFER_SIZES_HSPA = "40778,244668,734003,16777,100663,301990"; - private static final String TCP_BUFFER_SIZES_LTE = - "524288,1048576,2097152,262144,524288,1048576"; - private static final String TCP_BUFFER_SIZES_HSPAP = - "122334,734003,2202010,32040,192239,576717"; - private static final String TCP_BUFFER_SIZES_NR = - "2097152,6291456,16777216,512000,2097152,8388608"; - private static final String TCP_BUFFER_SIZES_LTE_CA = - "4096,6291456,12582912,4096,1048576,2097152"; - - private void updateTcpBufferSizes(int rilRat) { - String sizes = null; - ServiceState ss = mPhone.getServiceState(); - if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE && - ss.isUsingCarrierAggregation()) { - rilRat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA; - } - String ratName = ServiceState.rilRadioTechnologyToString(rilRat).toLowerCase(Locale.ROOT); - // ServiceState gives slightly different names for EVDO tech ("evdo-rev.0" for ex) - // - patch it up: - if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0 || - rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A || - rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B) { - ratName = RAT_NAME_EVDO; - } - - // NR 5G Non-Standalone use LTE cell as the primary cell, the ril technology is LTE in this - // case. We use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network. - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN - && ((rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE || - rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA) && isNRConnected()) - && mPhone.getServiceStateTracker().getNrContextIds().contains(mCid)) { - ratName = RAT_NAME_5G; - } - - log("updateTcpBufferSizes: " + ratName); - - // in the form: "ratname:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max" - String[] configOverride = mPhone.getContext().getResources().getStringArray( - com.android.internal.R.array.config_mobile_tcp_buffers); - for (int i = 0; i < configOverride.length; i++) { - String[] split = configOverride[i].split(":"); - if (ratName.equals(split[0]) && split.length == 2) { - sizes = split[1]; - break; - } - } - - if (sizes == null) { - // no override - use telephony defaults - // doing it this way allows device or carrier to just override the types they - // care about and inherit the defaults for the others. - switch (rilRat) { - case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS: - sizes = TCP_BUFFER_SIZES_GPRS; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE: - sizes = TCP_BUFFER_SIZES_EDGE; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS: - sizes = TCP_BUFFER_SIZES_UMTS; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT: - sizes = TCP_BUFFER_SIZES_1XRTT; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0: - case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A: - case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B: - sizes = TCP_BUFFER_SIZES_EVDO; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD: - sizes = TCP_BUFFER_SIZES_EHRPD; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA: - sizes = TCP_BUFFER_SIZES_HSDPA; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA: - case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA: - sizes = TCP_BUFFER_SIZES_HSPA; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_LTE: - // Use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network. - if (RAT_NAME_5G.equals(ratName)) { - sizes = TCP_BUFFER_SIZES_NR; - } else { - sizes = TCP_BUFFER_SIZES_LTE; - } - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA: - // Use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network. - if (RAT_NAME_5G.equals(ratName)) { - sizes = TCP_BUFFER_SIZES_NR; - } else { - sizes = TCP_BUFFER_SIZES_LTE_CA; - } - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP: - sizes = TCP_BUFFER_SIZES_HSPAP; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_NR: - sizes = TCP_BUFFER_SIZES_NR; - break; - default: - // Leave empty - this will let ConnectivityService use the system default. - break; - } - } - mLinkProperties.setTcpBufferSizes(sizes); - } - - private void updateLinkBandwidthsFromCarrierConfig(int rilRat) { - String ratName = DataConfigManager.getDataConfigNetworkType( - mPhone.getDisplayInfoController().getTelephonyDisplayInfo()); - - if (DBG) log("updateLinkBandwidthsFromCarrierConfig: " + ratName); - - Pair values = mDct.getLinkBandwidthsFromCarrierConfig(ratName); - if (values == null) { - values = new Pair<>(14, 14); - } - mDownlinkBandwidth = values.first; - mUplinkBandwidth = values.second; - } - - - private void updateLinkBandwidthsFromModem(List lceList) { - if (DBG) log("updateLinkBandwidthsFromModem: lceList=" + lceList); - boolean downlinkUpdated = false; - boolean uplinkUpdated = false; - LinkCapacityEstimate lce = lceList.get(0); - // LCE status deprecated in IRadio 1.2, so only check for IRadio < 1.2 - if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_2) - || mPhone.getLceStatus() == RILConstants.LCE_ACTIVE) { - if (lce.getDownlinkCapacityKbps() != LinkCapacityEstimate.INVALID) { - mDownlinkBandwidth = lce.getDownlinkCapacityKbps(); - downlinkUpdated = true; - } - if (lce.getUplinkCapacityKbps() != LinkCapacityEstimate.INVALID) { - mUplinkBandwidth = lce.getUplinkCapacityKbps(); - uplinkUpdated = true; - } - } - - if (!downlinkUpdated || !uplinkUpdated) { - fallBackToCarrierConfigValues(downlinkUpdated, uplinkUpdated); - } - - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this); - } - } - - private void updateLinkBandwidthsFromBandwidthEstimator(int uplinkBandwidthKbps, - int downlinkBandwidthKbps) { - if (DBG) { - log("updateLinkBandwidthsFromBandwidthEstimator, UL= " - + uplinkBandwidthKbps + " DL= " + downlinkBandwidthKbps); - } - boolean downlinkUpdated = false; - boolean uplinkUpdated = false; - if (downlinkBandwidthKbps > 0) { - mDownlinkBandwidth = downlinkBandwidthKbps; - downlinkUpdated = true; - } - if (uplinkBandwidthKbps > 0) { - mUplinkBandwidth = uplinkBandwidthKbps; - uplinkUpdated = true; - } - - if (!downlinkUpdated || !uplinkUpdated) { - fallBackToCarrierConfigValues(downlinkUpdated, uplinkUpdated); - } - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this); - } - } - - private void fallBackToCarrierConfigValues(boolean downlinkUpdated, boolean uplinkUpdated) { - String ratName = ServiceState.rilRadioTechnologyToString(mRilRat); - if (mRilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE && isNRConnected()) { - ratName = mPhone.getServiceState().getNrFrequencyRange() - == ServiceState.FREQUENCY_RANGE_MMWAVE - ? DctConstants.RAT_NAME_NR_NSA_MMWAVE : DctConstants.RAT_NAME_NR_NSA; - } - Pair values = mDct.getLinkBandwidthsFromCarrierConfig(ratName); - if (values != null) { - if (!downlinkUpdated) { - mDownlinkBandwidth = values.first; - } - if (!uplinkUpdated) { - mUplinkBandwidth = values.second; - } - mUplinkBandwidth = Math.min(mUplinkBandwidth, mDownlinkBandwidth); - } - } - - private boolean isBandwidthSourceKey(String source) { - return source.equals(mPhone.getContext().getResources().getString( - com.android.internal.R.string.config_bandwidthEstimateSource)); - } - - /** - * Indicates if this data connection was established for unmetered use only. Note that this - * flag should be populated when data becomes active. And if it is set to true, it can be set to - * false later when we are reevaluating the data connection. But if it is set to false, it - * can never become true later because setting it to true will cause this data connection - * losing some immutable network capabilities, which can cause issues in connectivity service. - */ - private boolean mUnmeteredUseOnly = false; - - /** - * Indicates if this data connection was established for MMS use only. This is true only when - * mobile data is disabled but the user allows sending and receiving MMS messages. If the data - * enabled settings indicate that MMS data is allowed unconditionally, MMS can be sent when data - * is disabled even if it is a metered APN type. - */ - private boolean mMmsUseOnly = false; - - /** - * Indicates if when this connection was established we had a restricted/privileged - * NetworkRequest and needed it to overcome data-enabled limitations. - * - * This flag overrides the APN-based restriction capability, restricting the network - * based on both having a NetworkRequest with restricted AND needing a restricted - * bit to overcome user-disabled status. This allows us to handle the common case - * of having both restricted requests and unrestricted requests for the same apn: - * if conditions require a restricted network to overcome user-disabled then it must - * be restricted, otherwise it is unrestricted (or restricted based on APN type). - * - * This supports a privileged app bringing up a network without general apps having access - * to it when the network is otherwise unavailable (hipri). The first use case is - * pre-paid SIM reprovisioning over internet, where the carrier insists on no traffic - * other than from the privileged carrier-app. - * - * Note that the data connection cannot go from unrestricted to restricted because the - * connectivity service does not support dynamically closing TCP connections at this point. - */ - private boolean mRestrictedNetworkOverride = false; - - /** - * Indicates if this data connection supports enterprise use. Note that this flag should be - * populated when data becomes active. Once it is set, the value cannot be changed because - * setting it will cause this data connection to lose immutable network capabilities, which can - * cause issues in connectivity service. - */ - private boolean mEnterpriseUse = false; - - /** - * Check if this data connection should be restricted. We should call this when data connection - * becomes active, or when we want to re-evaluate the conditions to decide if we need to - * unstrict the data connection. - * - * @return True if this data connection needs to be restricted. - */ - private boolean shouldRestrictNetwork() { - // first, check if there is any network request that containing restricted capability - // (i.e. Do not have NET_CAPABILITY_NOT_RESTRICTED in the request) - boolean isAnyRestrictedRequest = false; - for (ApnContext apnContext : mApnContexts.keySet()) { - if (apnContext.hasRestrictedRequests(true /* exclude DUN */)) { - isAnyRestrictedRequest = true; - break; - } - } - - // If all of the network requests are non-restricted, then we don't need to restrict - // the network. - if (!isAnyRestrictedRequest) { - return false; - } - - // If the network is unmetered, then we don't need to restrict the network because users - // won't be charged anyway. - if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { - return false; - } - - // If the data is disabled, then we need to restrict the network so only privileged apps can - // use the restricted network while data is disabled. - if (!mPhone.getDataEnabledSettings().isDataEnabled()) { - return true; - } - - // If the device is roaming, and the user does not turn on data roaming, then we need to - // restrict the network so only privileged apps can use it. - if (!mDct.getDataRoamingEnabled() && mPhone.getServiceState().getDataRoaming()) { - return true; - } - - // Otherwise we should not restrict the network so anyone who requests can use it. - return false; - } - - /** - * @return True if this data connection should only be used for unmetered purposes. - */ - private boolean isUnmeteredUseOnly() { - // If this data connection is on IWLAN, then it's unmetered and can be used by everyone. - // Should not be for unmetered used only. - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - return false; - } - - // If data is enabled, this data connection can't be for unmetered used only because - // everyone should be able to use it if: - // 1. Device is not roaming, or - // 2. Device is roaming and data roaming is turned on - if (mPhone.getDataEnabledSettings().isDataEnabled()) { - if (!mPhone.getServiceState().getDataRoaming() || mDct.getDataRoamingEnabled()) { - return false; - } - } - - // The data connection can only be unmetered used only if all attached APN contexts - // attached to this data connection are unmetered. - for (ApnContext apnContext : mApnContexts.keySet()) { - if (ApnSettingUtils.isMeteredApnType(apnContext.getApnTypeBitmask(), mPhone)) { - return false; - } - } - return true; - } - - /** - * @return True if this data connection should only be used for MMS purposes. - */ - private boolean isMmsUseOnly() { - // MMS use only if data is disabled, MMS is allowed unconditionally, and MMS is the only - // APN type for this data connection. - DataEnabledSettings des = mPhone.getDataEnabledSettings(); - boolean mmsAllowedUnconditionally = !des.isDataEnabled() && des.isMmsAlwaysAllowed(); - boolean mmsApnOnly = isApnContextAttached(ApnSetting.TYPE_MMS, true); - return mmsAllowedUnconditionally && mmsApnOnly; - } - - /** - * Check if this data connection supports enterprise use. We call this when the data connection - * becomes active or when we want to reevaluate the conditions to decide if we need to update - * the network agent capabilities. - * - * @return True if this data connection supports enterprise use. - */ - private boolean isEnterpriseUse() { - return mApnContexts.keySet().stream().anyMatch( - ac -> ac.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE); - } - - /** - * Get the network capabilities for this data connection. - * - * @return the {@link NetworkCapabilities} of this data connection. - */ - public NetworkCapabilities getNetworkCapabilities() { - final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); - boolean unmeteredApns = false; - - if (mApnSetting != null && !mEnterpriseUse && !mMmsUseOnly) { - final int[] types = ApnSetting.getApnTypesFromBitmask( - mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask); - for (int type : types) { - if ((!mRestrictedNetworkOverride && mUnmeteredUseOnly) - && ApnSettingUtils.isMeteredApnType(type, mPhone)) { - log("Dropped the metered " + ApnSetting.getApnTypeString(type) - + " type for the unmetered data call."); - continue; - } - switch (type) { - case ApnSetting.TYPE_ALL: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); - break; - } - case ApnSetting.TYPE_DEFAULT: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - break; - } - case ApnSetting.TYPE_MMS: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); - break; - } - case ApnSetting.TYPE_SUPL: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); - break; - } - case ApnSetting.TYPE_DUN: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); - break; - } - case ApnSetting.TYPE_FOTA: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); - break; - } - case ApnSetting.TYPE_IMS: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); - break; - } - case ApnSetting.TYPE_CBS: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); - break; - } - case ApnSetting.TYPE_IA: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); - break; - } - case ApnSetting.TYPE_EMERGENCY: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS); - break; - } - case ApnSetting.TYPE_MCX: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MCX); - break; - } - case ApnSetting.TYPE_XCAP: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP); - break; - } - default: - } - } - - if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { - unmeteredApns = true; - } - } - - // Mark NOT_METERED in the following cases: - // 1. All APNs in the APN settings are unmetered. - // 2. The non-restricted data is intended for unmetered use only. - if (unmeteredApns || (mUnmeteredUseOnly && !mRestrictedNetworkOverride)) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } else { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } - - if (mEnterpriseUse) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - } - - if (NetworkCapabilitiesUtils.inferRestrictedCapability(builder.build())) { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - } - - if (mMmsUseOnly) { - if (ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)) { - log("Adding unmetered capability for the unmetered MMS-only data connection"); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } - log("Adding MMS capability for the MMS-only data connection"); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); - } - - if (mRestrictedNetworkOverride) { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - // don't use dun on restriction-overriden networks. - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_DUN); - } - - builder.setLinkDownstreamBandwidthKbps(mDownlinkBandwidth); - builder.setLinkUpstreamBandwidthKbps(mUplinkBandwidth); - - builder.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() - .setSubscriptionId(mSubId).build()); - builder.setSubscriptionIds(Collections.singleton(mSubId)); - - if (!mPhone.getServiceState().getDataRoaming()) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - } - - if (!mCongestedOverride) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); - } - - if (mUnmeteredOverride) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED); - } - - if (!mIsSuspended) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - } - - final int carrierServicePackageUid = getCarrierServicePackageUid(); - - // TODO(b/205736323): Owner and Admin UIDs currently come from separate data sources. Unify - // them, and remove ArrayUtils.contains() check. - if (carrierServicePackageUid != Process.INVALID_UID - && ArrayUtils.contains(mAdministratorUids, carrierServicePackageUid)) { - builder.setOwnerUid(carrierServicePackageUid); - builder.setAllowedUids(Collections.singleton(carrierServicePackageUid)); - } - builder.setAdministratorUids(mAdministratorUids); - - // Always start with NOT_VCN_MANAGED, then remove if VcnManager indicates this is part of a - // VCN. - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - final VcnNetworkPolicyResult vcnPolicy = getVcnPolicy(builder.build()); - if (!vcnPolicy.getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)) { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - } - if (!vcnPolicy.getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - } - - return builder.build(); - } - - // TODO(b/205736323): Once TelephonyManager#getCarrierServicePackageNameForLogicalSlot() is - // plumbed to CarrierPrivilegesTracker's cache, query the cached UIDs. - private int getFirstUidForPackage(String pkgName) { - if (pkgName == null) { - return Process.INVALID_UID; - } - - List users = mPhone.getContext().getSystemService(UserManager.class).getUsers(); - for (UserInfo user : users) { - int userId = user.getUserHandle().getIdentifier(); - try { - PackageManager pm = mPhone.getContext().getPackageManager(); - - if (pm != null) { - return pm.getPackageUidAsUser(pkgName, userId); - } - } catch (NameNotFoundException exception) { - // Didn't find package. Try other users - Rlog.i( - "DataConnection", - "Unable to find uid for package " + pkgName + " and user " + userId); - } - } - return Process.INVALID_UID; - } - - private int getCarrierServicePackageUid() { - String pkgName = - mPhone.getContext() - .getSystemService(TelephonyManager.class) - .getCarrierServicePackageNameForLogicalSlot(mPhone.getPhoneId()); - - return getFirstUidForPackage(pkgName); - } - - /** - * Check if the this data network is VCN-managed. - * - * @param networkCapabilities The network capabilities of this data network. - * @return The VCN's policy for this DataNetwork. - */ - private VcnNetworkPolicyResult getVcnPolicy(NetworkCapabilities networkCapabilities) { - return mVcnManager.applyVcnNetworkPolicy(networkCapabilities, getLinkProperties()); - } - - /** @return {@code true} if validation is required, {@code false} otherwise. */ - public boolean isValidationRequired() { - final NetworkCapabilities nc = getNetworkCapabilities(); - return nc != null - && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); - } - - /** - * @return {@code True} if 464xlat should be skipped. - */ - @VisibleForTesting - public boolean shouldSkip464Xlat() { - switch (mApnSetting.getSkip464Xlat()) { - case Telephony.Carriers.SKIP_464XLAT_ENABLE: - return true; - case Telephony.Carriers.SKIP_464XLAT_DISABLE: - return false; - case Telephony.Carriers.SKIP_464XLAT_DEFAULT: - default: - break; - } - - // As default, return true if ims and no internet - final NetworkCapabilities nc = getNetworkCapabilities(); - return nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS) - && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - } - - /** - * @return {@code} true iff. {@code address} is a literal IPv4 or IPv6 address. - */ - @VisibleForTesting - public static boolean isIpAddress(String address) { - if (address == null) return false; - - // Accept IPv6 addresses (only) in square brackets for compatibility. - if (address.startsWith("[") && address.endsWith("]") && address.indexOf(':') != -1) { - address = address.substring(1, address.length() - 1); - } - return InetAddresses.isNumericAddress(address); - } - - private SetupResult setLinkProperties(DataCallResponse response, - LinkProperties linkProperties) { - // Check if system property dns usable - String propertyPrefix = "net." + response.getInterfaceName() + "."; - String dnsServers[] = new String[2]; - dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1"); - dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2"); - boolean okToUseSystemPropertyDns = isDnsOk(dnsServers); - - SetupResult result; - - // Start with clean network properties and if we have - // a failure we'll clear again at the bottom of this code. - linkProperties.clear(); - - if (response.getCause() == DataFailCause.NONE) { - try { - // set interface name - linkProperties.setInterfaceName(response.getInterfaceName()); - - // set link addresses - if (response.getAddresses().size() > 0) { - for (LinkAddress la : response.getAddresses()) { - if (!la.getAddress().isAnyLocalAddress()) { - if (DBG) { - log("addr/pl=" + la.getAddress() + "/" - + la.getPrefixLength()); - } - linkProperties.addLinkAddress(la); - } - } - } else { - throw new UnknownHostException("no address for ifname=" - + response.getInterfaceName()); - } - - // set dns servers - if (response.getDnsAddresses().size() > 0) { - for (InetAddress dns : response.getDnsAddresses()) { - if (!dns.isAnyLocalAddress()) { - linkProperties.addDnsServer(dns); - } - } - } else if (okToUseSystemPropertyDns) { - for (String dnsAddr : dnsServers) { - dnsAddr = dnsAddr.trim(); - if (dnsAddr.isEmpty()) continue; - InetAddress ia; - try { - ia = InetAddresses.parseNumericAddress(dnsAddr); - } catch (IllegalArgumentException e) { - throw new UnknownHostException("Non-numeric dns addr=" + dnsAddr); - } - if (!ia.isAnyLocalAddress()) { - linkProperties.addDnsServer(ia); - } - } - } else { - throw new UnknownHostException("Empty dns response and no system default dns"); - } - - // set pcscf - if (response.getPcscfAddresses().size() > 0) { - for (InetAddress pcscf : response.getPcscfAddresses()) { - linkProperties.addPcscfServer(pcscf); - } - } - - for (InetAddress gateway : response.getGatewayAddresses()) { - int mtu = gateway instanceof java.net.Inet6Address ? response.getMtuV6() - : response.getMtuV4(); - // Allow 0.0.0.0 or :: as a gateway; - // this indicates a point-to-point interface. - linkProperties.addRoute(new RouteInfo(null, gateway, null, - RouteInfo.RTN_UNICAST, mtu)); - } - - // set interface MTU - // this may clobber the setting read from the APN db, but that's ok - // TODO: remove once LinkProperties#setMtu is deprecated - linkProperties.setMtu(response.getMtu()); - - result = SetupResult.SUCCESS; - } catch (UnknownHostException e) { - log("setLinkProperties: UnknownHostException " + e); - result = SetupResult.ERROR_INVALID_ARG; - } - } else { - result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; - } - - // An error occurred so clear properties - if (result != SetupResult.SUCCESS) { - if (DBG) { - log("setLinkProperties: error clearing LinkProperties status=" - + response.getCause() + " result=" + result); - } - linkProperties.clear(); - } - - return result; - } - - /** - * Initialize connection, this will fail if the - * apnSettings are not compatible. - * - * @param cp the Connection parameters - * @return true if initialization was successful. - */ - private boolean initConnection(ConnectionParams cp) { - ApnContext apnContext = cp.mApnContext; - if (mApnSetting == null) { - // Only change apn setting if it isn't set, it will - // only NOT be set only if we're in DcInactiveState. - mApnSetting = apnContext.getApnSetting(); - } - if (mApnSetting == null || (!mApnSetting.canHandleType(apnContext.getApnTypeBitmask()) - && apnContext.getApnTypeBitmask() != ApnSetting.TYPE_ENTERPRISE)) { - if (DBG) { - log("initConnection: incompatible apnSetting in ConnectionParams cp=" + cp - + " dc=" + DataConnection.this); - } - return false; - } - mTag += 1; - mConnectionParams = cp; - mConnectionParams.mTag = mTag; - - // always update the ConnectionParams with the latest or the - // connectionGeneration gets stale - mApnContexts.put(apnContext, cp); - - if (DBG) { - log("initConnection: " - + " RefCount=" + mApnContexts.size() - + " mApnList=" + mApnContexts - + " mConnectionParams=" + mConnectionParams); - } - return true; - } - - /** - * The parent state for all other states. - */ - private class DcDefaultState extends State { - @Override - public void enter() { - if (DBG) log("DcDefaultState: enter"); - - // Register for DRS or RAT change - mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged( - mTransportType, getHandler(), - DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, null); - - mPhone.getServiceStateTracker().registerForDataRoamingOn(getHandler(), - DataConnection.EVENT_DATA_CONNECTION_ROAM_ON, null); - mPhone.getServiceStateTracker().registerForDataRoamingOff(getHandler(), - DataConnection.EVENT_DATA_CONNECTION_ROAM_OFF, null, true); - mPhone.getServiceStateTracker().registerForNrStateChanged(getHandler(), - DataConnection.EVENT_NR_STATE_CHANGED, null); - mPhone.getServiceStateTracker().registerForNrFrequencyChanged(getHandler(), - DataConnection.EVENT_NR_FREQUENCY_CHANGED, null); - mPhone.getServiceStateTracker().registerForCssIndicatorChanged(getHandler(), - DataConnection.EVENT_CSS_INDICATOR_CHANGED, null); - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR_KEY)) { - mPhone.getLinkBandwidthEstimator().registerForBandwidthChanged(getHandler(), - DataConnection.EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE, null); - } - - // Add ourselves to the list of data connections - mDcController.addDc(DataConnection.this); - } - @Override - public void exit() { - if (DBG) log("DcDefaultState: exit"); - - // Unregister for DRS or RAT change. - mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged( - mTransportType, getHandler()); - - mPhone.getServiceStateTracker().unregisterForDataRoamingOn(getHandler()); - mPhone.getServiceStateTracker().unregisterForDataRoamingOff(getHandler()); - mPhone.getServiceStateTracker().unregisterForNrStateChanged(getHandler()); - mPhone.getServiceStateTracker().unregisterForNrFrequencyChanged(getHandler()); - mPhone.getServiceStateTracker().unregisterForCssIndicatorChanged(getHandler()); - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR_KEY)) { - mPhone.getLinkBandwidthEstimator().unregisterForBandwidthChanged(getHandler()); - } - - // Remove ourselves from the DC lists - mDcController.removeDc(DataConnection.this); - - if (mAc != null) { - mAc.disconnected(); - mAc = null; - } - mApnContexts.clear(); - mReconnectIntent = null; - mDct = null; - mApnSetting = null; - mPhone = null; - mDataServiceManager = null; - mLinkProperties = null; - mLastFailCause = DataFailCause.NONE; - mUserData = null; - mDcController = null; - mDcTesterFailBringUpAll = null; - } - - @Override - public boolean processMessage(Message msg) { - boolean retVal = HANDLED; - - if (VDBG) { - log("DcDefault msg=" + getWhatToString(msg.what) - + " RefCount=" + mApnContexts.size()); - } - switch (msg.what) { - case EVENT_RESET: - if (VDBG) log("DcDefaultState: msg.what=REQ_RESET"); - transitionTo(mInactiveState); - break; - case EVENT_CONNECT: - if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected"); - ConnectionParams cp = (ConnectionParams) msg.obj; - notifyConnectCompleted(cp, DataFailCause.UNKNOWN, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); - break; - - case EVENT_DISCONNECT: - case EVENT_DISCONNECT_ALL: - case EVENT_REEVALUATE_RESTRICTED_STATE: - if (DBG) { - log("DcDefaultState deferring msg.what=" + getWhatToString(msg.what) - + " RefCount=" + mApnContexts.size()); - } - deferMessage(msg); - break; - case EVENT_TEAR_DOWN_NOW: - if (DBG) log("DcDefaultState EVENT_TEAR_DOWN_NOW"); - mDataServiceManager.deactivateDataCall(mCid, DataService.REQUEST_REASON_NORMAL, - null); - mDataCallSessionStats.setDeactivateDataCallReason( - DataService.REQUEST_REASON_NORMAL); - break; - case EVENT_LOST_CONNECTION: - if (DBG) { - String s = "DcDefaultState ignore EVENT_LOST_CONNECTION" - + " tag=" + msg.arg1 + ":mTag=" + mTag; - logAndAddLogRec(s); - } - break; - case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: - AsyncResult ar = (AsyncResult)msg.obj; - Pair drsRatPair = (Pair)ar.result; - mDataRegState = drsRatPair.first; - updateTcpBufferSizes(drsRatPair.second); - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { - updateLinkBandwidthsFromCarrierConfig(drsRatPair.second); - } - mRilRat = drsRatPair.second; - if (DBG) { - log("DcDefaultState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED" - + " regState=" + ServiceState.rilServiceStateToString(mDataRegState) - + " RAT=" + ServiceState.rilRadioTechnologyToString(mRilRat)); - } - mDataCallSessionStats.onDrsOrRatChanged( - ServiceState.rilRadioTechnologyToNetworkType(mRilRat)); - break; - - case EVENT_START_HANDOVER: //calls startHandover() - if (DBG) { - log("DcDefaultState: EVENT_START_HANDOVER not expected."); - } - Consumer r = (Consumer) msg.obj; - r.accept(DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - break; - case EVENT_START_HANDOVER_ON_TARGET: - if (DBG) { - log("DcDefaultState: EVENT_START_HANDOVER not expected, but will " - + "clean up, result code: " - + DataServiceCallback.resultCodeToString(msg.arg1)); - } - ((Consumer) msg.obj).accept(false /* is in correct state*/); - break; - case EVENT_CANCEL_HANDOVER: - // We don't need to do anything in this case - if (DBG) { - log("DcDefaultState: EVENT_CANCEL_HANDOVER resultCode=" - + DataServiceCallback.resultCodeToString(msg.arg1)); - } - break; - case EVENT_RELEASE_PDU_SESSION_ID: { - // We do the same thing in all state in order to preserve the existing workflow - final AsyncResult asyncResult = (AsyncResult) msg.obj; - if (asyncResult == null) { - loge("EVENT_RELEASE_PDU_SESSION_ID: asyncResult is null!"); - } else { - if (msg.obj != null) { - if (DBG) logd("EVENT_RELEASE_PDU_SESSION_ID: id released"); - Runnable runnable = (Runnable) asyncResult.userObj; - runnable.run(); - } else { - loge("EVENT_RELEASE_PDU_SESSION_ID: no runnable set"); - } - } - retVal = HANDLED; - break; - } - case EVENT_ALLOCATE_PDU_SESSION_ID: { - // We do the same thing in all state in order to preserve the existing workflow - final AsyncResult asyncResult = (AsyncResult) msg.obj; - if (asyncResult == null) { - loge("EVENT_ALLOCATE_PDU_SESSION_ID: asyncResult is null!"); - } else { - Consumer onAllocated = (Consumer) asyncResult.userObj; - if (asyncResult.exception != null) { - loge("EVENT_ALLOCATE_PDU_SESSION_ID: exception", - asyncResult.exception); - onAllocated.accept(PDU_SESSION_ID_NOT_SET); - } else if (asyncResult.result == null) { - loge("EVENT_ALLOCATE_PDU_SESSION_ID: result null, no id"); - onAllocated.accept(PDU_SESSION_ID_NOT_SET); - } else { - int psi = (int) asyncResult.result; - if (DBG) logd("EVENT_ALLOCATE_PDU_SESSION_ID: psi=" + psi); - onAllocated.accept(psi); - } - } - retVal = HANDLED; - break; - } - default: - if (DBG) { - log("DcDefaultState: ignore msg.what=" + getWhatToString(msg.what)); - } - break; - } - - return retVal; - } - } - - private void updateSuspendState() { - if (mNetworkAgent == null) { - Rlog.d(getName(), "Setting suspend state without a NetworkAgent"); - } - - boolean newSuspendedState = false; - // Data can only be (temporarily) suspended while data is in active state - if (getCurrentState() == mActiveState) { - // Never set suspended for emergency apn. Emergency data connection - // can work while device is not in service. - if (mApnSetting != null && mApnSetting.isEmergencyApn()) { - newSuspendedState = false; - // If we are not in service, change to suspended. - } else if (mDataRegState != ServiceState.STATE_IN_SERVICE) { - newSuspendedState = true; - // Check voice/data concurrency. - } else if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { - newSuspendedState = mPhone.getCallTracker().getState() != PhoneConstants.State.IDLE; - } - } - - // Only notify when there is a change. - if (mIsSuspended != newSuspendedState) { - mIsSuspended = newSuspendedState; - - // If data connection is active, we need to notify the new data connection state - // changed event reflecting the latest suspended state. - if (isActive()) { - notifyDataConnectionState(); - } - } - } - - private void notifyDataConnectionState() { - // The receivers of this have no way to differentiate between default and enterprise - // connections. Do not notify for enterprise. - if (!isEnterpriseUse()) { - mPhone.notifyDataConnection(getPreciseDataConnectionState()); - } else { - log("notifyDataConnectionState: Skipping for enterprise; state=" + getState()); - } - } - - private DcDefaultState mDefaultState = new DcDefaultState(); - - private int getApnTypeBitmask() { - return isEnterpriseUse() ? ApnSetting.TYPE_ENTERPRISE : - mApnSetting != null ? mApnSetting.getApnTypeBitmask() : 0; - } - - private boolean canHandleDefault() { - return !isEnterpriseUse() && mApnSetting != null - ? mApnSetting.canHandleType(ApnSetting.TYPE_DEFAULT) : false; - } - - /** - * The state machine is inactive and expects a EVENT_CONNECT. - */ - private class DcInactiveState extends State { - // Inform all contexts we've failed connecting - public void setEnterNotificationParams(ConnectionParams cp, @DataFailureCause int cause, - @HandoverFailureMode int handoverFailureMode) { - if (VDBG) log("DcInactiveState: setEnterNotificationParams cp,cause"); - mConnectionParams = cp; - mDisconnectParams = null; - mDcFailCause = cause; - mHandoverFailureMode = handoverFailureMode; - } - - // Inform all contexts we've failed disconnected - public void setEnterNotificationParams(DisconnectParams dp) { - if (VDBG) log("DcInactiveState: setEnterNotificationParams dp"); - mConnectionParams = null; - mDisconnectParams = dp; - mDcFailCause = DataFailCause.NONE; - } - - // Inform all contexts of the failure cause - public void setEnterNotificationParams(@DataFailureCause int cause) { - mConnectionParams = null; - mDisconnectParams = null; - mDcFailCause = cause; - } - - @Override - public void enter() { - mTag += 1; - if (DBG) log("DcInactiveState: enter() mTag=" + mTag); - TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, - TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__INACTIVE, - mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); - mDataCallSessionStats.onDataCallDisconnected(mDcFailCause); - if (mHandoverState == HANDOVER_STATE_BEING_TRANSFERRED) { - // This is from source data connection to set itself's state - setHandoverState(HANDOVER_STATE_COMPLETED); - } - - // Check for dangling agent. Ideally the handover source agent should be null if - // handover process is smooth. When it's not null, that means handover failed. The - // agent was not successfully transferred to the new data connection. We should - // gracefully notify connectivity service the network was disconnected. - if (mHandoverSourceNetworkAgent != null) { - DataConnection sourceDc = mHandoverSourceNetworkAgent.getDataConnection(); - if (sourceDc != null) { - // If the source data connection still owns this agent, then just reset the - // handover state back to idle because handover is already failed. - mHandoverLocalLog.log( - "Handover failed. Reset the source dc " + sourceDc.getName() - + " state to idle"); - sourceDc.cancelHandover(); - } else { - // The agent is now a dangling agent. No data connection owns this agent. - // Gracefully notify connectivity service disconnected. - mHandoverLocalLog.log( - "Handover failed and dangling agent found."); - mHandoverSourceNetworkAgent.acquireOwnership( - DataConnection.this, mTransportType); - log("Cleared dangling network agent. " + mHandoverSourceNetworkAgent); - mHandoverSourceNetworkAgent.unregister(DataConnection.this); - mHandoverSourceNetworkAgent.releaseOwnership(DataConnection.this); - } - mHandoverSourceNetworkAgent = null; - } - - if (mConnectionParams != null) { - if (DBG) { - log("DcInactiveState: enter notifyConnectCompleted +ALL failCause=" - + DataFailCause.toString(mDcFailCause)); - } - notifyConnectCompleted(mConnectionParams, mDcFailCause, mHandoverFailureMode, - true); - } - if (mDisconnectParams != null) { - if (DBG) { - log("DcInactiveState: enter notifyDisconnectCompleted +ALL failCause=" - + DataFailCause.toString(mDcFailCause)); - } - notifyDisconnectCompleted(mDisconnectParams, true); - } - if (mDisconnectParams == null && mConnectionParams == null - && mDcFailCause != DataFailCause.NONE) { - if (DBG) { - log("DcInactiveState: enter notifyAllDisconnectCompleted failCause=" - + DataFailCause.toString(mDcFailCause)); - } - notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE, - DataFailCause.toString(mDcFailCause)); - } - - // Remove ourselves from cid mapping, before clearSettings - mDcController.removeActiveDcByCid(DataConnection.this); - - // For the first time entering here (idle state before setup), do not notify - // disconnected state. Only notify data connection disconnected for data that is - // actually moving from disconnecting to disconnected, or setup failed. In both cases, - // APN setting will not be null. - if (mApnSetting != null) { - notifyDataConnectionState(); - } - clearSettings(); - } - - @Override - public void exit() { - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case EVENT_RESET: - case EVENT_REEVALUATE_RESTRICTED_STATE: - if (DBG) { - log("DcInactiveState: msg.what=" + getWhatToString(msg.what) - + ", ignore we're already done"); - } - return HANDLED; - case EVENT_CONNECT: - if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT"); - ConnectionParams cp = (ConnectionParams) msg.obj; - - if (!initConnection(cp)) { - log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed"); - notifyConnectCompleted(cp, DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); - transitionTo(mInactiveState); - return HANDLED; - } - - int cause = connect(cp); - if (cause != DataFailCause.NONE) { - log("DcInactiveState: msg.what=EVENT_CONNECT connect failed"); - notifyConnectCompleted(cp, cause, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); - transitionTo(mInactiveState); - return HANDLED; - } - - if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - mSubId = cp.mSubId; - } - - transitionTo(mActivatingState); - return HANDLED; - case EVENT_DISCONNECT: - if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT"); - notifyDisconnectCompleted((DisconnectParams)msg.obj, false); - return HANDLED; - case EVENT_DISCONNECT_ALL: - if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL"); - notifyDisconnectCompleted((DisconnectParams)msg.obj, false); - return HANDLED; - default: - if (VDBG) { - log("DcInactiveState not handled msg.what=" + getWhatToString(msg.what)); - } - return NOT_HANDLED; - } - } - } - private DcInactiveState mInactiveState = new DcInactiveState(); - - /** - * The state machine is activating a connection. - */ - private class DcActivatingState extends State { - @Override - public void enter() { - int apnTypeBitmask = getApnTypeBitmask(); - TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, - TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__ACTIVATING, - mPhone.getPhoneId(), mId, apnTypeBitmask, canHandleDefault()); - setHandoverState(HANDOVER_STATE_IDLE); - // restricted evaluation depends on network requests from apnContext. The evaluation - // should happen once entering connecting state rather than active state because it's - // possible that restricted network request can be released during the connecting window - // and if we wait for connection established, then we might mistakenly - // consider it as un-restricted. ConnectivityService then will immediately - // tear down the connection through networkAgent unwanted callback if all requests for - // this connection are going away. - mRestrictedNetworkOverride = shouldRestrictNetwork(); - - CarrierPrivilegesTracker carrierPrivTracker = mPhone.getCarrierPrivilegesTracker(); - if (carrierPrivTracker != null) { - carrierPrivTracker.registerCarrierPrivilegesListener( - getHandler(), EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED, null); - } - notifyDataConnectionState(); - mDataCallSessionStats.onSetupDataCall(apnTypeBitmask); - } - @Override - public boolean processMessage(Message msg) { - boolean retVal; - AsyncResult ar; - ConnectionParams cp; - - if (DBG) log("DcActivatingState: msg=" + msgToString(msg)); - switch (msg.what) { - case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: - case EVENT_CONNECT: - // Activating can't process until we're done. - deferMessage(msg); - retVal = HANDLED; - break; - - case EVENT_SETUP_DATA_CONNECTION_DONE: - cp = (ConnectionParams) msg.obj; - - DataCallResponse dataCallResponse = - msg.getData().getParcelable(DataServiceManager.DATA_CALL_RESPONSE); - SetupResult result = onSetupConnectionCompleted(msg.arg1, dataCallResponse, cp); - if (result != SetupResult.ERROR_STALE) { - if (mConnectionParams != cp) { - loge("DcActivatingState: WEIRD mConnectionsParams:"+ mConnectionParams - + " != cp:" + cp); - } - } - if (DBG) { - log("DcActivatingState onSetupConnectionCompleted result=" + result - + " dc=" + DataConnection.this); - } - ApnContext.requestLog( - cp.mApnContext, "onSetupConnectionCompleted result=" + result); - - if (result != SetupResult.SUCCESS) { - releasePduSessionId(() -> DataConnection.this - .setPduSessionId(PDU_SESSION_ID_NOT_SET)); - } - - switch (result) { - case SUCCESS: - // All is well - mDcFailCause = DataFailCause.NONE; - transitionTo(mActiveState); - break; - case ERROR_RADIO_NOT_AVAILABLE: - // Vendor ril rejected the command and didn't connect. - // Transition to inactive but send notifications after - // we've entered the mInactive state. - mInactiveState.setEnterNotificationParams(cp, result.mFailCause, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); - transitionTo(mInactiveState); - break; - case ERROR_DUPLICATE_CID: - // TODO (b/180988471): Properly handle the case when an existing cid is - // returned by tearing down the network agent if enterprise changed. - long retry = RetryManager.NO_SUGGESTED_RETRY_DELAY; - if (cp.mApnContext != null) { - retry = RetryManager.NO_RETRY; - mDct.getDataThrottler().setRetryTime( - cp.mApnContext.getApnTypeBitmask(), - retry, DcTracker.REQUEST_TYPE_NORMAL); - } - String logStr = "DcActivatingState: " - + DataFailCause.toString(result.mFailCause) - + " retry=" + retry; - if (DBG) log(logStr); - ApnContext.requestLog(cp.mApnContext, logStr); - mInactiveState.setEnterNotificationParams(cp, result.mFailCause, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); - transitionTo(mInactiveState); - break; - case ERROR_NO_DEFAULT_CONNECTION: - // TODO (b/180988471): Properly handle the case when a default data - // connection doesn't exist (tear down connection and retry). - // Currently, this just tears down the connection without retry. - if (DBG) log("DcActivatingState: NO_DEFAULT_DATA"); - case ERROR_INVALID_ARG: - // The addresses given from the RIL are bad - tearDownData(cp); - transitionTo(mDisconnectingErrorCreatingConnection); - break; - case ERROR_DATA_SERVICE_SPECIFIC_ERROR: - - // Retrieve the suggested retry delay from the modem and save it. - // If the modem want us to retry the current APN again, it will - // suggest a positive delay value (in milliseconds). Otherwise we'll get - // NO_SUGGESTED_RETRY_DELAY here. - - long delay = getSuggestedRetryDelay(dataCallResponse); - long retryTime = RetryManager.NO_SUGGESTED_RETRY_DELAY; - if (delay == RetryManager.NO_RETRY) { - retryTime = RetryManager.NO_RETRY; - } else if (delay >= 0) { - retryTime = SystemClock.elapsedRealtime() + delay; - } - int newRequestType = DcTracker.calculateNewRetryRequestType( - mHandoverFailureMode, cp.mRequestType, mDcFailCause); - mDct.getDataThrottler().setRetryTime(getApnTypeBitmask(), - retryTime, newRequestType); - - String str = "DcActivatingState: ERROR_DATA_SERVICE_SPECIFIC_ERROR " - + " delay=" + delay - + " result=" + result - + " result.isRadioRestartFailure=" - + DataFailCause.isRadioRestartFailure(mPhone.getContext(), - result.mFailCause, mPhone.getSubId()) - + " isPermanentFailure=" + - mDct.isPermanentFailure(result.mFailCause); - if (DBG) log(str); - ApnContext.requestLog(cp.mApnContext, str); - - // Save the cause. DcTracker.onDataSetupComplete will check this - // failure cause and determine if we need to retry this APN later - // or not. - mInactiveState.setEnterNotificationParams(cp, result.mFailCause, - dataCallResponse != null - ? dataCallResponse.getHandoverFailureMode() - : DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); - transitionTo(mInactiveState); - break; - case ERROR_STALE: - loge("DcActivatingState: stale EVENT_SETUP_DATA_CONNECTION_DONE" - + " tag:" + cp.mTag + " != mTag:" + mTag); - break; - default: - throw new RuntimeException("Unknown SetupResult, should not happen"); - } - retVal = HANDLED; - mDataCallSessionStats - .onSetupDataCallResponse(dataCallResponse, - ServiceState.rilRadioTechnologyToNetworkType(cp.mRilRat), - getApnTypeBitmask(), mApnSetting.getProtocol(), - result.mFailCause); - break; - case EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED: - AsyncResult asyncResult = (AsyncResult) msg.obj; - int[] administratorUids = (int[]) asyncResult.result; - mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length); - retVal = HANDLED; - break; - case EVENT_START_HANDOVER_ON_TARGET: - //called after startHandover on target transport - ((Consumer) msg.obj).accept(true /* is in correct state*/); - retVal = HANDLED; - break; - case EVENT_CANCEL_HANDOVER: - transitionTo(mInactiveState); - retVal = HANDLED; - break; - default: - if (VDBG) { - log("DcActivatingState not handled msg.what=" + - getWhatToString(msg.what) + " RefCount=" + mApnContexts.size()); - } - retVal = NOT_HANDLED; - break; - } - return retVal; - } - } - private DcActivatingState mActivatingState = new DcActivatingState(); - - /** - * The state machine is connected, expecting an EVENT_DISCONNECT. - */ - private class DcActiveState extends State { - - @Override public void enter() { - if (DBG) log("DcActiveState: enter dc=" + DataConnection.this); - TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, - TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__ACTIVE, - mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); - // If we were retrying there maybe more than one, otherwise they'll only be one. - notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE, - Phone.REASON_CONNECTED); - - mPhone.getCallTracker().registerForVoiceCallStarted(getHandler(), - DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED, null); - mPhone.getCallTracker().registerForVoiceCallEnded(getHandler(), - DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED, null); - - // If the EVENT_CONNECT set the current max retry restore it here - // if it didn't then this is effectively a NOP. - mDcController.addActiveDcByCid(DataConnection.this); - - updateTcpBufferSizes(mRilRat); - updateLinkBandwidthsFromCarrierConfig(mRilRat); - - final NetworkAgentConfig.Builder configBuilder = new NetworkAgentConfig.Builder(); - configBuilder.setLegacyType(ConnectivityManager.TYPE_MOBILE); - configBuilder.setLegacyTypeName(NETWORK_TYPE); - int networkType = getNetworkType(); - configBuilder.setLegacySubType(networkType); - configBuilder.setLegacySubTypeName(TelephonyManager.getNetworkTypeName(networkType)); - configBuilder.setLegacyExtraInfo(mApnSetting.getApnName()); - final CarrierSignalAgent carrierSignalAgent = mPhone.getCarrierSignalAgent(); - if (carrierSignalAgent.hasRegisteredReceivers(TelephonyManager - .ACTION_CARRIER_SIGNAL_REDIRECTED)) { - // carrierSignal Receivers will place the carrier-specific provisioning notification - configBuilder.setProvisioningNotificationEnabled(false); - } - - final String subscriberId = mPhone.getSubscriberId(); - if (!TextUtils.isEmpty(subscriberId)) { - configBuilder.setSubscriberId(subscriberId); - } - - // set skip464xlat if it is not default otherwise - if (shouldSkip464Xlat()) { - configBuilder.setNat64DetectionEnabled(false); - } - - mUnmeteredUseOnly = isUnmeteredUseOnly(); - mMmsUseOnly = isMmsUseOnly(); - mEnterpriseUse = isEnterpriseUse(); - - if (DBG) { - log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride - + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly - + ", mMmsUseOnly = " + mMmsUseOnly - + ", mEnterpriseUse = " + mEnterpriseUse); - } - - // Always register a VcnNetworkPolicyChangeListener, regardless of whether this is a - // handover - // or new Network. - mVcnManager.addVcnNetworkPolicyChangeListener( - new HandlerExecutor(getHandler()), mVcnPolicyChangeListener); - - if (mConnectionParams != null - && mConnectionParams.mRequestType == REQUEST_TYPE_HANDOVER) { - // If this is a data setup for handover, we need to reuse the existing network agent - // instead of creating a new one. This should be transparent to connectivity - // service. - DcTracker dcTracker = mPhone.getDcTracker(getHandoverSourceTransport()); - DataConnection dc = dcTracker.getDataConnectionByApnType( - mConnectionParams.mApnContext.getApnType()); - // It's possible that the source data connection has been disconnected by the modem - // already. If not, set its handover state to completed. - if (dc != null) { - // Transfer network agent from the original data connection as soon as the - // new handover data connection is connected. - dc.setHandoverState(HANDOVER_STATE_COMPLETED); - } - - if (mHandoverSourceNetworkAgent != null) { - String logStr = "Transfer network agent " + mHandoverSourceNetworkAgent.getTag() - + " successfully."; - log(logStr); - mHandoverLocalLog.log(logStr); - mNetworkAgent = mHandoverSourceNetworkAgent; - mNetworkAgent.acquireOwnership(DataConnection.this, mTransportType); - - // TODO: Should evaluate mDisabledApnTypeBitMask again after handover. We don't - // do it now because connectivity service does not support dynamically removing - // immutable capabilities. - - mNetworkAgent.updateLegacySubtype(DataConnection.this); - // Update the capability after handover - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); - mHandoverSourceNetworkAgent = null; - } else { - String logStr = "Failed to get network agent from original data connection"; - loge(logStr); - mHandoverLocalLog.log(logStr); - return; - } - } else { - mScore = calculateScore(); - final NetworkFactory factory = PhoneFactory.getNetworkFactory( - mPhone.getPhoneId()); - final NetworkProvider provider = (null == factory) ? null : factory.getProvider(); - - mDisabledApnTypeBitMask |= getDisallowedApnTypes(); - updateLinkPropertiesHttpProxy(); - mNetworkAgent = new DcNetworkAgent(DataConnection.this, mPhone, mScore, - configBuilder.build(), provider, mTransportType); - - VcnNetworkPolicyResult policyResult = - mVcnManager.applyVcnNetworkPolicy( - getNetworkCapabilities(), getLinkProperties()); - if (policyResult.isTeardownRequested()) { - tearDownAll( - Phone.REASON_VCN_REQUESTED_TEARDOWN, - DcTracker.RELEASE_TYPE_DETACH, - null /* onCompletedMsg */); - } else { - // All network agents start out in CONNECTING mode, but DcNetworkAgents are - // created when the network is already connected. Hence, send the connected - // notification immediately. - mNetworkAgent.markConnected(); - } - - // The network agent is always created with NOT_SUSPENDED capability, but the - // network might be already out of service (or voice call is ongoing) just right - // before data connection is created. Connectivity service would not allow a network - // created with suspended state, so we create a non-suspended network first, and - // then immediately evaluate the suspended state. - sendMessage(obtainMessage(EVENT_UPDATE_SUSPENDED_STATE)); - } - - // The qos parameters are set when the call is connected - syncQosToNetworkAgent(); - - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.registerForNattKeepaliveStatus( - getHandler(), DataConnection.EVENT_KEEPALIVE_STATUS, null); - mPhone.mCi.registerForLceInfo( - getHandler(), DataConnection.EVENT_LINK_CAPACITY_CHANGED, null); - } - notifyDataConnectionState(); - TelephonyMetrics.getInstance().writeRilDataCallEvent(mPhone.getPhoneId(), - mCid, getApnTypeBitmask(), RilDataCall.State.CONNECTED); - } - - @Override - public void exit() { - if (DBG) log("DcActiveState: exit dc=" + this); - mPhone.getCallTracker().unregisterForVoiceCallStarted(getHandler()); - mPhone.getCallTracker().unregisterForVoiceCallEnded(getHandler()); - - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.unregisterForNattKeepaliveStatus(getHandler()); - mPhone.mCi.unregisterForLceInfo(getHandler()); - } - - // If we are still owning this agent, then we should inform connectivity service the - // data connection is disconnected. There is one exception that we shouldn't unregister, - // which is when IWLAN handover is ongoing. Instead of unregistering, the agent will - // be transferred to the new data connection on the other transport. - if (mNetworkAgent != null) { - syncQosToNetworkAgent(); - if (mHandoverState == HANDOVER_STATE_IDLE) { - mNetworkAgent.unregister(DataConnection.this); - } - mNetworkAgent.releaseOwnership(DataConnection.this); - } - mNetworkAgent = null; - - TelephonyMetrics.getInstance().writeRilDataCallEvent(mPhone.getPhoneId(), - mCid, getApnTypeBitmask(), RilDataCall.State.DISCONNECTED); - - mVcnManager.removeVcnNetworkPolicyChangeListener(mVcnPolicyChangeListener); - - CarrierPrivilegesTracker carrierPrivTracker = mPhone.getCarrierPrivilegesTracker(); - if (carrierPrivTracker != null) { - carrierPrivTracker.unregisterCarrierPrivilegesListener(getHandler()); - } - } - - @Override - public boolean processMessage(Message msg) { - boolean retVal; - - switch (msg.what) { - case EVENT_CONNECT: { - ConnectionParams cp = (ConnectionParams) msg.obj; - // either add this new apn context to our set or - // update the existing cp with the latest connection generation number - mApnContexts.put(cp.mApnContext, cp); - // TODO (b/118347948): evaluate if it's still needed after assigning - // different scores to different Cellular network. - mDisabledApnTypeBitMask &= ~cp.mApnContext.getApnTypeBitmask(); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - if (DBG) { - log("DcActiveState: EVENT_CONNECT cp=" + cp + " dc=" + DataConnection.this); - } - notifyConnectCompleted(cp, DataFailCause.NONE, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); - retVal = HANDLED; - break; - } - case EVENT_DISCONNECT: { - DisconnectParams dp = (DisconnectParams) msg.obj; - if (DBG) { - log("DcActiveState: EVENT_DISCONNECT dp=" + dp - + " dc=" + DataConnection.this); - } - if (mApnContexts.containsKey(dp.mApnContext)) { - if (DBG) { - log("DcActiveState msg.what=EVENT_DISCONNECT RefCount=" - + mApnContexts.size()); - } - - if (mApnContexts.size() == 1) { - mApnContexts.clear(); - mDisconnectParams = dp; - mConnectionParams = null; - dp.mTag = mTag; - tearDownData(dp); - transitionTo(mDisconnectingState); - } else { - mApnContexts.remove(dp.mApnContext); - // TODO (b/118347948): evaluate if it's still needed after assigning - // different scores to different Cellular network. - mDisabledApnTypeBitMask |= dp.mApnContext.getApnTypeBitmask(); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - notifyDisconnectCompleted(dp, false); - } - } else { - log("DcActiveState ERROR no such apnContext=" + dp.mApnContext - + " in this dc=" + DataConnection.this); - notifyDisconnectCompleted(dp, false); - } - retVal = HANDLED; - break; - } - case EVENT_DISCONNECT_ALL: { - if (DBG) { - log("DcActiveState EVENT_DISCONNECT clearing apn contexts," - + " dc=" + DataConnection.this); - } - DisconnectParams dp = (DisconnectParams) msg.obj; - mDisconnectParams = dp; - mConnectionParams = null; - dp.mTag = mTag; - tearDownData(dp); - transitionTo(mDisconnectingState); - retVal = HANDLED; - break; - } - case EVENT_LOST_CONNECTION: { - if (DBG) { - log("DcActiveState EVENT_LOST_CONNECTION dc=" + DataConnection.this); - } - - mInactiveState.setEnterNotificationParams(DataFailCause.LOST_CONNECTION); - transitionTo(mInactiveState); - retVal = HANDLED; - break; - } - case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - Pair drsRatPair = (Pair) ar.result; - mDataRegState = drsRatPair.first; - updateTcpBufferSizes(drsRatPair.second); - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { - updateLinkBandwidthsFromCarrierConfig(drsRatPair.second); - } - mRilRat = drsRatPair.second; - if (DBG) { - log("DcActiveState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED" - + " drs=" + mDataRegState - + " mRilRat=" + mRilRat); - } - updateSuspendState(); - if (mNetworkAgent != null) { - mNetworkAgent.updateLegacySubtype(DataConnection.this); - // The new suspended state will be passed through connectivity service - // through NET_CAPABILITY_NOT_SUSPENDED. - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); - } - retVal = HANDLED; - mDataCallSessionStats.onDrsOrRatChanged( - ServiceState.rilRadioTechnologyToNetworkType(mRilRat)); - break; - } - case EVENT_NR_FREQUENCY_CHANGED: - // fallthrough - case EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED: - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { - updateLinkBandwidthsFromCarrierConfig(mRilRat); - } - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - case EVENT_DATA_CONNECTION_METEREDNESS_CHANGED: - boolean isUnmetered = (boolean) msg.obj; - if (isUnmetered == mUnmeteredOverride) { - retVal = HANDLED; - break; - } - mUnmeteredOverride = isUnmetered; - if (mNetworkAgent != null) { - mNetworkAgent.updateLegacySubtype(DataConnection.this); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - case EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED: - boolean isCongested = (boolean) msg.obj; - if (isCongested == mCongestedOverride) { - retVal = HANDLED; - break; - } - mCongestedOverride = isCongested; - if (mNetworkAgent != null) { - mNetworkAgent.updateLegacySubtype(DataConnection.this); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - case EVENT_DATA_CONNECTION_ROAM_ON: - case EVENT_DATA_CONNECTION_ROAM_OFF: { - if (mNetworkAgent != null) { - mNetworkAgent.updateLegacySubtype(DataConnection.this); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - } - case EVENT_DATA_CONNECTION_VOICE_CALL_STARTED: - case EVENT_DATA_CONNECTION_VOICE_CALL_ENDED: - case EVENT_CSS_INDICATOR_CHANGED: - case EVENT_UPDATE_SUSPENDED_STATE: { - updateSuspendState(); - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - } - case EVENT_BW_REFRESH_RESPONSE: { - AsyncResult ar = (AsyncResult)msg.obj; - if (ar.exception != null) { - log("EVENT_BW_REFRESH_RESPONSE: error ignoring, e=" + ar.exception); - } else { - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_MODEM_KEY)) { - updateLinkBandwidthsFromModem((List) ar.result); - } - } - retVal = HANDLED; - break; - } - case EVENT_KEEPALIVE_START_REQUEST: { - KeepalivePacketData pkt = (KeepalivePacketData) msg.obj; - int slotId = msg.arg1; - int intervalMillis = msg.arg2 * 1000; - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.startNattKeepalive( - DataConnection.this.mCid, pkt, intervalMillis, - DataConnection.this.obtainMessage( - EVENT_KEEPALIVE_STARTED, slotId, 0, null)); - } else { - // We currently do not support NATT Keepalive requests using the - // DataService API, so unless the request is WWAN (always bound via - // the CommandsInterface), the request cannot be honored. - // - // TODO: b/72331356 to add support for Keepalive to the DataService - // so that keepalive requests can be handled (if supported) by the - // underlying transport. - if (mNetworkAgent != null) { - mNetworkAgent.sendSocketKeepaliveEvent( - msg.arg1, SocketKeepalive.ERROR_INVALID_NETWORK); - } - } - retVal = HANDLED; - break; - } - case EVENT_KEEPALIVE_STOP_REQUEST: { - int slotId = msg.arg1; - int handle = mNetworkAgent.keepaliveTracker.getHandleForSlot(slotId); - if (handle < 0) { - loge("No slot found for stopSocketKeepalive! " + slotId); - mNetworkAgent.sendSocketKeepaliveEvent( - slotId, SocketKeepalive.ERROR_NO_SUCH_SLOT); - retVal = HANDLED; - break; - } else { - logd("Stopping keepalive with handle: " + handle); - } - - mPhone.mCi.stopNattKeepalive( - handle, DataConnection.this.obtainMessage( - EVENT_KEEPALIVE_STOPPED, handle, slotId, null)); - retVal = HANDLED; - break; - } - case EVENT_KEEPALIVE_STARTED: { - AsyncResult ar = (AsyncResult) msg.obj; - final int slot = msg.arg1; - if (ar.exception != null || ar.result == null) { - loge("EVENT_KEEPALIVE_STARTED: error starting keepalive, e=" - + ar.exception); - mNetworkAgent.sendSocketKeepaliveEvent( - slot, SocketKeepalive.ERROR_HARDWARE_ERROR); - } else { - KeepaliveStatus ks = (KeepaliveStatus) ar.result; - if (ks == null) { - loge("Null KeepaliveStatus received!"); - } else { - mNetworkAgent.keepaliveTracker.handleKeepaliveStarted(slot, ks); - } - } - retVal = HANDLED; - break; - } - case EVENT_KEEPALIVE_STATUS: { - AsyncResult ar = (AsyncResult) msg.obj; - if (ar.exception != null) { - loge("EVENT_KEEPALIVE_STATUS: error in keepalive, e=" + ar.exception); - // We have no way to notify connectivity in this case. - } - if (ar.result != null) { - KeepaliveStatus ks = (KeepaliveStatus) ar.result; - mNetworkAgent.keepaliveTracker.handleKeepaliveStatus(ks); - } - - retVal = HANDLED; - break; - } - case EVENT_KEEPALIVE_STOPPED: { - AsyncResult ar = (AsyncResult) msg.obj; - final int handle = msg.arg1; - final int slotId = msg.arg2; - - if (ar.exception != null) { - loge("EVENT_KEEPALIVE_STOPPED: error stopping keepalive for handle=" - + handle + " e=" + ar.exception); - mNetworkAgent.keepaliveTracker.handleKeepaliveStatus( - new KeepaliveStatus(KeepaliveStatus.ERROR_UNKNOWN)); - } else { - log("Keepalive Stop Requested for handle=" + handle); - mNetworkAgent.keepaliveTracker.handleKeepaliveStatus( - new KeepaliveStatus( - handle, KeepaliveStatus.STATUS_INACTIVE)); - } - retVal = HANDLED; - break; - } - case EVENT_LINK_CAPACITY_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - if (ar.exception != null) { - loge("EVENT_LINK_CAPACITY_CHANGED e=" + ar.exception); - } else { - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_MODEM_KEY)) { - updateLinkBandwidthsFromModem((List) ar.result); - } - } - retVal = HANDLED; - break; - } - case EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE: { - AsyncResult ar = (AsyncResult) msg.obj; - if (ar.exception != null) { - loge("EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE e=" + ar.exception); - } else { - Pair pair = (Pair) ar.result; - if (isBandwidthSourceKey( - DctConstants.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR_KEY)) { - updateLinkBandwidthsFromBandwidthEstimator(pair.first, pair.second); - } - } - retVal = HANDLED; - break; - } - case EVENT_REEVALUATE_RESTRICTED_STATE: { - // If the network was restricted, and now it does not need to be restricted - // anymore, we should add the NET_CAPABILITY_NOT_RESTRICTED capability. - if (mRestrictedNetworkOverride && !shouldRestrictNetwork()) { - if (DBG) { - log("Data connection becomes not-restricted. dc=" + this); - } - // Note we only do this when network becomes non-restricted. When a - // non-restricted becomes restricted (e.g. users disable data, or turn off - // data roaming), DCT will explicitly tear down the networks (because - // connectivity service does not support force-close TCP connections today). - // Also note that NET_CAPABILITY_NOT_RESTRICTED is an immutable capability - // (see {@link NetworkCapabilities}) once we add it to the network, we can't - // remove it through the entire life cycle of the connection. - mRestrictedNetworkOverride = false; - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - - // If the data does need to be unmetered use only (e.g. users turn on data, or - // device is not roaming anymore assuming data roaming is off), then we can - // dynamically add those metered APN type capabilities back. (But not the - // other way around because most of the APN-type capabilities are immutable - // capabilities.) - if (mUnmeteredUseOnly && !isUnmeteredUseOnly()) { - mUnmeteredUseOnly = false; - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - - mMmsUseOnly = isMmsUseOnly(); - - retVal = HANDLED; - break; - } - case EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES: { - // Update other properties like link properties if needed in future. - updateScore(); - retVal = HANDLED; - break; - } - case EVENT_NR_STATE_CHANGED: { - updateTcpBufferSizes(mRilRat); - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { - updateLinkBandwidthsFromCarrierConfig(mRilRat); - } - if (mNetworkAgent != null) { - mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - } - case EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED: - AsyncResult asyncResult = (AsyncResult) msg.obj; - int[] administratorUids = (int[]) asyncResult.result; - mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length); - - // Administrator UIDs changed, so update NetworkAgent with new - // NetworkCapabilities - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities( - getNetworkCapabilities(), DataConnection.this); - } - retVal = HANDLED; - break; - case EVENT_START_HANDOVER: //calls startHandover() - Consumer r = (Consumer) msg.obj; - r.accept(msg.arg1); - retVal = HANDLED; - break; - - default: - if (VDBG) { - log("DcActiveState not handled msg.what=" + getWhatToString(msg.what)); - } - retVal = NOT_HANDLED; - break; - } - return retVal; - } - } - private DcActiveState mActiveState = new DcActiveState(); - - /** - * The state machine is disconnecting. - */ - private class DcDisconnectingState extends State { - @Override - public void enter() { - TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, - TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__DISCONNECTING, - mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); - notifyDataConnectionState(); - } - @Override - public boolean processMessage(Message msg) { - boolean retVal; - - switch (msg.what) { - case EVENT_CONNECT: - if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = " - + mApnContexts.size()); - deferMessage(msg); - retVal = HANDLED; - break; - - case EVENT_DEACTIVATE_DONE: - DisconnectParams dp = (DisconnectParams) msg.obj; - - String str = "DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount=" - + mApnContexts.size(); - - if (DBG) log(str); - ApnContext.requestLog(dp.mApnContext, str); - - // Clear out existing qos sessions - updateQosParameters(null); - - if (dp.mTag == mTag) { - // Transition to inactive but send notifications after - // we've entered the mInactive state. - mInactiveState.setEnterNotificationParams(dp); - transitionTo(mInactiveState); - } else { - if (DBG) log("DcDisconnectState stale EVENT_DEACTIVATE_DONE" - + " dp.tag=" + dp.mTag + " mTag=" + mTag); - } - retVal = HANDLED; - break; - - default: - if (VDBG) { - log("DcDisconnectingState not handled msg.what=" - + getWhatToString(msg.what)); - } - retVal = NOT_HANDLED; - break; - } - return retVal; - } - } - private DcDisconnectingState mDisconnectingState = new DcDisconnectingState(); - - /** - * The state machine is disconnecting after an creating a connection. - */ - private class DcDisconnectionErrorCreatingConnection extends State { - @Override - public void enter() { - TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, - TelephonyStatsLog - .MOBILE_CONNECTION_STATE_CHANGED__STATE__DISCONNECTION_ERROR_CREATING_CONNECTION, - mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); - notifyDataConnectionState(); - } - @Override - public boolean processMessage(Message msg) { - boolean retVal; - - switch (msg.what) { - case EVENT_DEACTIVATE_DONE: - ConnectionParams cp = (ConnectionParams) msg.obj; - if (cp.mTag == mTag) { - String str = "DcDisconnectionErrorCreatingConnection" + - " msg.what=EVENT_DEACTIVATE_DONE"; - if (DBG) log(str); - ApnContext.requestLog(cp.mApnContext, str); - - // Transition to inactive but send notifications after - // we've entered the mInactive state. - mInactiveState.setEnterNotificationParams(cp, - DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); - transitionTo(mInactiveState); - } else { - if (DBG) { - log("DcDisconnectionErrorCreatingConnection stale EVENT_DEACTIVATE_DONE" - + " dp.tag=" + cp.mTag + ", mTag=" + mTag); - } - } - retVal = HANDLED; - break; - - default: - if (VDBG) { - log("DcDisconnectionErrorCreatingConnection not handled msg.what=" - + getWhatToString(msg.what)); - } - retVal = NOT_HANDLED; - break; - } - return retVal; - } - } - private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection = - new DcDisconnectionErrorCreatingConnection(); - - /** - * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg. - * Used for cellular networks that use Access Point Names (APN) such - * as GSM networks. - * - * @param apnContext is the Access Point Name to bring up a connection to - * @param profileId for the connection - * @param rilRadioTechnology Radio technology for the data connection - * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. - * With AsyncResult.userObj set to the original msg.obj, - * AsyncResult.result = FailCause and AsyncResult.exception = Exception(). - * @param connectionGeneration used to track a single connection request so disconnects can get - * ignored if obsolete. - * @param requestType Data request type - * @param subId the subscription id associated with this data connection. - * @param isApnPreferred whether or not the apn is preferred. - */ - public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology, - Message onCompletedMsg, int connectionGeneration, - @RequestNetworkType int requestType, int subId, boolean isApnPreferred) { - if (DBG) { - log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg); - } - - if (mApnSetting == null) { - mApnSetting = apnContext.getApnSetting(); - } - - sendMessage(DataConnection.EVENT_CONNECT, - new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg, - connectionGeneration, requestType, subId, isApnPreferred)); - } - - /** - * Tear down the connection through the apn on the network. - * - * @param apnContext APN context - * @param reason reason to tear down - * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. - * With AsyncResult.userObj set to the original msg.obj. - */ - public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) { - if (DBG) { - log("tearDown: apnContext=" + apnContext + " reason=" + reason + " onCompletedMsg=" - + onCompletedMsg); - } - sendMessage(DataConnection.EVENT_DISCONNECT, - new DisconnectParams(apnContext, reason, DcTracker.RELEASE_TYPE_DETACH, - onCompletedMsg)); - } - - // ******* "public" interface - - /** - * Used for testing purposes. - */ - void tearDownNow() { - if (DBG) log("tearDownNow()"); - sendMessage(obtainMessage(EVENT_TEAR_DOWN_NOW)); - } - - /** - * Tear down the connection through the apn on the network. Ignores reference count and - * and always tears down. - * - * @param releaseType Data release type - * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. - * With AsyncResult.userObj set to the original msg.obj. - */ - public void tearDownAll(String reason, @ReleaseNetworkType int releaseType, - Message onCompletedMsg) { - if (DBG) { - log("tearDownAll: reason=" + reason + ", releaseType=" - + DcTracker.releaseTypeToString(releaseType)); - } - sendMessage(DataConnection.EVENT_DISCONNECT_ALL, - new DisconnectParams(null, reason, releaseType, onCompletedMsg)); - } - - /** - * Reset the data connection to inactive state. - */ - public void reset() { - sendMessage(EVENT_RESET); - if (DBG) log("reset"); - } - - /** - * Re-evaluate the restricted state. If the restricted data connection does not need to be - * restricted anymore, we need to dynamically change the network's capability. - */ - void reevaluateRestrictedState() { - sendMessage(EVENT_REEVALUATE_RESTRICTED_STATE); - if (DBG) log("reevaluate restricted state"); - } - - /** - * Re-evaluate the data connection properties. For example, it will recalculate data connection - * score and update through network agent it if changed. - */ - void reevaluateDataConnectionProperties() { - sendMessage(EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES); - if (DBG) log("reevaluate data connection properties"); - } - - /** - * @return The parameters used for initiating a data connection. - */ - public ConnectionParams getConnectionParams() { - return mConnectionParams; - } - - /** - * Update PCSCF addresses - * - * @param response - */ - public void updatePcscfAddr(DataCallResponse response) { - mPcscfAddr = response.getPcscfAddresses().stream() - .map(InetAddress::getHostAddress).toArray(String[]::new); - } - - /** - * @return The list of PCSCF addresses - */ - public String[] getPcscfAddresses() { - return mPcscfAddr; - } - - /** - * Using the result of the SETUP_DATA_CALL determine the retry delay. - * - * @param response The response from setup data call - * @return {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} if not suggested. - * {@link RetryManager#NO_RETRY} if retry should not happen. Otherwise the delay in milliseconds - * to the next SETUP_DATA_CALL. - */ - private long getSuggestedRetryDelay(DataCallResponse response) { - /** According to ril.h - * The value < 0 means no value is suggested - * The value 0 means retry should be done ASAP. - * The value of Long.MAX_VALUE(0x7fffffffffffffff) means no retry. - */ - if (response == null) { - return RetryManager.NO_SUGGESTED_RETRY_DELAY; - } - - long suggestedRetryTime = response.getRetryDurationMillis(); - - // The value < 0 means no value is suggested - if (suggestedRetryTime < 0) { - if (DBG) log("No suggested retry delay."); - return RetryManager.NO_SUGGESTED_RETRY_DELAY; - } else if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6) - && suggestedRetryTime == Long.MAX_VALUE) { - if (DBG) log("Network suggested not retrying."); - return RetryManager.NO_RETRY; - } else if (mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_6) - && suggestedRetryTime == Integer.MAX_VALUE) { - if (DBG) log("Network suggested not retrying."); - return RetryManager.NO_RETRY; - } - - return suggestedRetryTime; - } - - public List getApnContexts() { - return new ArrayList<>(mApnContexts.keySet()); - } - - /** - * Return whether there is an ApnContext for the given type in this DataConnection. - * @param type APN type to check - * @param exclusive true if the given APN type should be the only APN type that exists - * @return True if there is an ApnContext for the given type - */ - private boolean isApnContextAttached(@ApnType int type, boolean exclusive) { - boolean attached = mApnContexts.keySet().stream() - .map(ApnContext::getApnTypeBitmask) - .anyMatch(bitmask -> bitmask == type); - if (exclusive) { - attached &= mApnContexts.size() == 1; - } - return attached; - } - - /** Get the network agent of the data connection */ - @Nullable - DcNetworkAgent getNetworkAgent() { - return mNetworkAgent; - } - - void setHandoverState(@HandoverState int state) { - if (mHandoverState != state) { - String logStr = "State changed from " + handoverStateToString(mHandoverState) - + " to " + handoverStateToString(state); - mHandoverLocalLog.log(logStr); - logd(logStr); - mHandoverState = state; - } - } - - /** Sets the {@link DataCallSessionStats} mock for this data connection during unit testing. */ - @VisibleForTesting - public void setDataCallSessionStats(DataCallSessionStats dataCallSessionStats) { - mDataCallSessionStats = dataCallSessionStats; - } - - /** - * @return the string for msg.what as our info. - */ - @Override - protected String getWhatToString(int what) { - return cmdToString(what); - } - - private static String msgToString(Message msg) { - String retVal; - if (msg == null) { - retVal = "null"; - } else { - StringBuilder b = new StringBuilder(); - - b.append("{what="); - b.append(cmdToString(msg.what)); - - b.append(" when="); - TimeUtils.formatDuration(msg.getWhen() - SystemClock.uptimeMillis(), b); - - if (msg.arg1 != 0) { - b.append(" arg1="); - b.append(msg.arg1); - } - - if (msg.arg2 != 0) { - b.append(" arg2="); - b.append(msg.arg2); - } - - if (msg.obj != null) { - b.append(" obj="); - b.append(msg.obj); - } - - b.append(" target="); - b.append(msg.getTarget()); - - b.append(" replyTo="); - b.append(msg.replyTo); - - b.append("}"); - - retVal = b.toString(); - } - return retVal; - } - - static void slog(String s) { - Rlog.d("DC", s); - } - - /** - * Log with debug - * - * @param s is string log - */ - @Override - protected void log(String s) { - Rlog.d(getName(), s); - } - - /** - * Log with debug attribute - * - * @param s is string log - */ - @Override - protected void logd(String s) { - Rlog.d(getName(), s); - } - - /** - * Log with verbose attribute - * - * @param s is string log - */ - @Override - protected void logv(String s) { - Rlog.v(getName(), s); - } - - /** - * Log with info attribute - * - * @param s is string log - */ - @Override - protected void logi(String s) { - Rlog.i(getName(), s); - } - - /** - * Log with warning attribute - * - * @param s is string log - */ - @Override - protected void logw(String s) { - Rlog.w(getName(), s); - } - - /** - * Log with error attribute - * - * @param s is string log - */ - @Override - protected void loge(String s) { - Rlog.e(getName(), s); - } - - /** - * Log with error attribute - * - * @param s is string log - * @param e is a Throwable which logs additional information. - */ - @Override - protected void loge(String s, Throwable e) { - Rlog.e(getName(), s, e); - } - - /** Doesn't print mApnList of ApnContext's which would be recursive */ - public synchronized String toStringSimple() { - return getName() + ": State=" + getCurrentState().getName() - + " mApnSetting=" + mApnSetting + " RefCount=" + mApnContexts.size() - + " mCid=" + mCid + " mCreateTime=" + mCreateTime - + " mLastastFailTime=" + mLastFailTime - + " mLastFailCause=" + DataFailCause.toString(mLastFailCause) - + " mTag=" + mTag - + " mLinkProperties=" + mLinkProperties - + " linkCapabilities=" + getNetworkCapabilities() - + " mRestrictedNetworkOverride=" + mRestrictedNetworkOverride; - } - - @Override - public String toString() { - return "{" + toStringSimple() + " mApnContexts=" + mApnContexts + "}"; - } - - /** Check if the device is connected to NR 5G Non-Standalone network. */ - private boolean isNRConnected() { - return mPhone.getServiceState().getNrState() - == NetworkRegistrationInfo.NR_STATE_CONNECTED; - } - - /** - * @return The disallowed APN types bitmask - */ - private @ApnType int getDisallowedApnTypes() { - CarrierConfigManager configManager = (CarrierConfigManager) - mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - int apnTypesBitmask = 0; - if (configManager != null) { - PersistableBundle bundle = configManager.getConfigForSubId(mSubId); - if (bundle != null) { - String key = (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - ? CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY - : CarrierConfigManager.KEY_CARRIER_WLAN_DISALLOWED_APN_TYPES_STRING_ARRAY; - if (bundle.getStringArray(key) != null) { - String disallowedApnTypesString = - TextUtils.join(",", bundle.getStringArray(key)); - if (!TextUtils.isEmpty(disallowedApnTypesString)) { - apnTypesBitmask = ApnSetting.getApnTypesBitmaskFromString( - disallowedApnTypesString); - } - } - } - } - - return apnTypesBitmask; - } - - private void dumpToLog() { - dump(null, new PrintWriter(new StringWriter(0)) { - @Override - public void println(String s) { - DataConnection.this.logd(s); - } - - @Override - public void flush() { - } - }, null); - } - - /** - * Re-calculate score and update through network agent if it changes. - */ - private void updateScore() { - int oldScore = mScore; - mScore = calculateScore(); - if (oldScore != mScore && mNetworkAgent != null) { - log("Updating score from " + oldScore + " to " + mScore); - mNetworkAgent.sendNetworkScore(mScore, this); - } - } - - private int calculateScore() { - int score = OTHER_CONNECTION_SCORE; - - // If it's serving a network request that asks NET_CAPABILITY_INTERNET and doesn't have - // specify a subId, this dataConnection is considered to be default Internet data - // connection. In this case we assign a slightly higher score of 50. The intention is - // it will not be replaced by other data connections accidentally in DSDS usecase. - for (ApnContext apnContext : mApnContexts.keySet()) { - for (NetworkRequest networkRequest : apnContext.getNetworkRequests()) { - if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - && networkRequest.getNetworkSpecifier() == null) { - score = DEFAULT_INTERNET_CONNECTION_SCORE; - break; - } - } - } - - return score; - } - - private String handoverStateToString(@HandoverState int state) { - switch (state) { - case HANDOVER_STATE_IDLE: return "IDLE"; - case HANDOVER_STATE_BEING_TRANSFERRED: return "BEING_TRANSFERRED"; - case HANDOVER_STATE_COMPLETED: return "COMPLETED"; - default: return "UNKNOWN"; - } - } - - private @DataState int getState() { - if (isInactive()) { - return TelephonyManager.DATA_DISCONNECTED; - } else if (isActivating()) { - return TelephonyManager.DATA_CONNECTING; - } else if (isActive()) { - // The data connection can only be suspended when it's in active state. - if (mIsSuspended) { - return TelephonyManager.DATA_SUSPENDED; - } - return TelephonyManager.DATA_CONNECTED; - } else if (isDisconnecting()) { - return TelephonyManager.DATA_DISCONNECTING; - } - - return TelephonyManager.DATA_UNKNOWN; - } - - /** - * Get precise data connection state - * - * @return The {@link PreciseDataConnectionState} - */ - public PreciseDataConnectionState getPreciseDataConnectionState() { - return new PreciseDataConnectionState.Builder() - .setTransportType(mTransportType) - .setId(mCid) - .setState(getState()) - .setApnSetting(mApnSetting) - .setLinkProperties(mLinkProperties) - .setNetworkType(getNetworkType()) - .setFailCause(mDcFailCause) - .build(); - } - - /** - * Dump the current state. - * - * @param fd - * @param printWriter - * @param args - */ - @Override - public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { - IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); - pw.print("DataConnection "); - super.dump(fd, pw, args); - pw.flush(); - pw.increaseIndent(); - pw.println("transport type=" - + AccessNetworkConstants.transportTypeToString(mTransportType)); - pw.println("mApnContexts.size=" + mApnContexts.size()); - pw.println("mApnContexts=" + mApnContexts); - pw.println("mApnSetting=" + mApnSetting); - pw.println("mTag=" + mTag); - pw.println("mCid=" + mCid); - pw.println("mConnectionParams=" + mConnectionParams); - pw.println("mDisconnectParams=" + mDisconnectParams); - pw.println("mDcFailCause=" + DataFailCause.toString(mDcFailCause)); - pw.println("mPhone=" + mPhone); - pw.println("mSubId=" + mSubId); - pw.println("mLinkProperties=" + mLinkProperties); - pw.flush(); - pw.println("mDataRegState=" + mDataRegState); - pw.println("mHandoverState=" + handoverStateToString(mHandoverState)); - pw.println("mRilRat=" + mRilRat); - pw.println("mNetworkCapabilities=" + getNetworkCapabilities()); - pw.println("mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime)); - pw.println("mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime)); - pw.println("mLastFailCause=" + DataFailCause.toString(mLastFailCause)); - pw.println("mUserData=" + mUserData); - pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); - pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); - pw.println("mMmsUseOnly=" + mMmsUseOnly); - pw.println("mEnterpriseUse=" + mEnterpriseUse); - pw.println("mUnmeteredOverride=" + mUnmeteredOverride); - pw.println("mCongestedOverride=" + mCongestedOverride); - pw.println("mDownlinkBandwidth" + mDownlinkBandwidth); - pw.println("mUplinkBandwidth=" + mUplinkBandwidth); - pw.println("mDefaultQos=" + mDefaultQos); - pw.println("mQosBearerSessions=" + mQosBearerSessions); - pw.println("disallowedApnTypes=" - + ApnSetting.getApnTypesStringFromBitmask(getDisallowedApnTypes())); - pw.println("mInstanceNumber=" + mInstanceNumber); - pw.println("mAc=" + mAc); - pw.println("mScore=" + mScore); - if (mNetworkAgent != null) { - mNetworkAgent.dump(fd, pw, args); - } - pw.println("handover local log:"); - pw.increaseIndent(); - mHandoverLocalLog.dump(fd, pw, args); - pw.decreaseIndent(); - pw.decreaseIndent(); - pw.println(); - pw.flush(); - } - - /** - * Class used to track VCN-defined Network policies for this DataConnection. - * - *

MUST be registered with the associated DataConnection's Handler. - */ - private class DataConnectionVcnNetworkPolicyChangeListener - implements VcnNetworkPolicyChangeListener { - @Override - public void onPolicyChanged() { - // Poll the current underlying Network policy from VcnManager and send to NetworkAgent. - final NetworkCapabilities networkCapabilities = getNetworkCapabilities(); - VcnNetworkPolicyResult policyResult = - mVcnManager.applyVcnNetworkPolicy( - networkCapabilities, getLinkProperties()); - if (policyResult.isTeardownRequested()) { - tearDownAll( - Phone.REASON_VCN_REQUESTED_TEARDOWN, - DcTracker.RELEASE_TYPE_DETACH, - null /* onCompletedMsg */); - } - - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(networkCapabilities, DataConnection.this); - } - } - } -} - diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java b/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java deleted file mode 100644 index 68f2ab38ae..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2017 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.dataconnection; - -import com.android.internal.annotations.VisibleForTesting; - -import java.util.HashSet; - -/** - * The class to describe the reasons of allowing or disallowing to establish a data connection. - */ -public class DataConnectionReasons { - private HashSet mDataDisallowedReasonSet = new HashSet<>(); - private DataAllowedReasonType mDataAllowedReason = DataAllowedReasonType.NONE; - - public DataConnectionReasons() {} - - void add(DataDisallowedReasonType reason) { - // Adding a disallowed reason will clean up the allowed reason because they are - // mutual exclusive. - mDataAllowedReason = DataAllowedReasonType.NONE; - mDataDisallowedReasonSet.add(reason); - } - - void add(DataAllowedReasonType reason) { - // Adding an allowed reason will clean up the disallowed reasons because they are - // mutual exclusive. - mDataDisallowedReasonSet.clear(); - - // Only higher priority allowed reason can overwrite the old one. See - // DataAllowedReasonType for the oder. - if (reason.ordinal() > mDataAllowedReason.ordinal()) { - mDataAllowedReason = reason; - } - } - - @Override - public String toString() { - StringBuilder reasonStr = new StringBuilder(); - if (mDataDisallowedReasonSet.size() > 0) { - reasonStr.append("Data disallowed reasons:"); - for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) { - reasonStr.append(" ").append(reason); - } - } else { - reasonStr.append("Data allowed reason:"); - reasonStr.append(" ").append(mDataAllowedReason); - } - return reasonStr.toString(); - } - - void copyFrom(DataConnectionReasons reasons) { - this.mDataDisallowedReasonSet = reasons.mDataDisallowedReasonSet; - this.mDataAllowedReason = reasons.mDataAllowedReason; - } - - boolean allowed() { - return mDataDisallowedReasonSet.size() == 0; - } - - /** - * Check if it contains a certain disallowed reason. - * - * @param reason The disallowed reason to check. - * @return {@code true} if the provided reason matches one of the disallowed reasons. - */ - @VisibleForTesting - public boolean contains(DataDisallowedReasonType reason) { - return mDataDisallowedReasonSet.contains(reason); - } - - /** - * Check if only one disallowed reason prevent data connection. - * - * @param reason The given reason to check - * @return True if the given reason is the only one that prevents data connection - */ - public boolean containsOnly(DataDisallowedReasonType reason) { - return mDataDisallowedReasonSet.size() == 1 && contains(reason); - } - - boolean contains(DataAllowedReasonType reason) { - return reason == mDataAllowedReason; - } - - boolean containsHardDisallowedReasons() { - for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) { - if (reason.isHardReason()) { - return true; - } - } - return false; - } - - // Disallowed reasons. There could be multiple reasons if data connection is not allowed. - public enum DataDisallowedReasonType { - // Soft failure reasons. Normally the reasons from users or policy settings. - - // Data is disabled by the user or policy. - DATA_DISABLED(false), - // Data roaming is disabled by the user. - ROAMING_DISABLED(false), - // Default data not selected. - DEFAULT_DATA_UNSELECTED(false), - - // Belows are all hard failure reasons. - NOT_ATTACHED(true), - SIM_NOT_READY(true), - INVALID_PHONE_STATE(true), - CONCURRENT_VOICE_DATA_NOT_ALLOWED(true), - PS_RESTRICTED(true), - UNDESIRED_POWER_STATE(true), - INTERNAL_DATA_DISABLED(true), - RADIO_DISABLED_BY_CARRIER(true), - // Not in the right state for data call setup. - APN_NOT_CONNECTABLE(true), - // Data is in connecting state. No need to send another setup request. - DATA_IS_CONNECTING(true), - // Data is being disconnected. Telephony will retry after disconnected. - DATA_IS_DISCONNECTING(true), - // Data is already connected. No need to setup data again. - DATA_ALREADY_CONNECTED(true), - // certain APNs are not allowed on IWLAN in legacy mode. - ON_IWLAN(true), - // certain APNs are only allowed when the device is camped on NR. - NOT_ON_NR(true), - // Data is not allowed while device is in emergency callback mode. - IN_ECBM(true), - // The given APN type's preferred transport has switched. - ON_OTHER_TRANSPORT(true), - // Underlying data service is not bound. - DATA_SERVICE_NOT_READY(true), - // Qualified networks service does not allow certain types of APN brought up on either - // cellular or IWLAN. - DISABLED_BY_QNS(true), - // Data is throttled. The network explicitly requested device not to establish data - // connection for a certain period. - DATA_THROTTLED(true); - - private boolean mIsHardReason; - - boolean isHardReason() { - return mIsHardReason; - } - - DataDisallowedReasonType(boolean isHardReason) { - mIsHardReason = isHardReason; - } - } - - // Data allowed reasons. There will be only one reason if data is allowed. - enum DataAllowedReasonType { - // Note that unlike disallowed reasons, we only have one allowed reason every time - // when we check data is allowed or not. The order of these allowed reasons is very - // important. The lower ones take precedence over the upper ones. - NONE, - NORMAL, - UNMETERED_APN, - RESTRICTED_REQUEST, - EMERGENCY_APN, - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java deleted file mode 100644 index 305b4a8df5..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - - -import static android.telephony.PhoneStateListener.LISTEN_CALL_STATE; -import static android.telephony.PhoneStateListener.LISTEN_NONE; - -import android.annotation.IntDef; -import android.content.ContentResolver; -import android.content.Context; -import android.os.Handler; -import android.os.RegistrantList; -import android.os.SystemProperties; -import android.provider.Settings; -import android.sysprop.TelephonyProperties; -import android.telephony.Annotation.CallState; -import android.telephony.CarrierConfigManager; -import android.telephony.PhoneStateListener; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.util.LocalLog; -import android.util.Pair; - -import com.android.internal.telephony.GlobalSettingsHelper; -import com.android.internal.telephony.MultiSimSettingController; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.SubscriptionController; -import com.android.internal.telephony.data.DataEnabledOverride; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * The class to hold different data enabled/disabled settings. Also it allows clients to register - * for overall data enabled setting changed event. - * @hide - */ -public class DataEnabledSettings { - - private static final String LOG_TAG = "DataEnabledSettings"; - - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"REASON_"}, - value = { - REASON_REGISTERED, - REASON_INTERNAL_DATA_ENABLED, - REASON_USER_DATA_ENABLED, - REASON_POLICY_DATA_ENABLED, - REASON_DATA_ENABLED_BY_CARRIER, - REASON_PROVISIONED_CHANGED, - REASON_PROVISIONING_DATA_ENABLED_CHANGED, - REASON_OVERRIDE_RULE_CHANGED, - REASON_OVERRIDE_CONDITION_CHANGED, - REASON_THERMAL_DATA_ENABLED - }) - public @interface DataEnabledChangedReason {} - - public static final int REASON_REGISTERED = 0; - - public static final int REASON_INTERNAL_DATA_ENABLED = 1; - - public static final int REASON_USER_DATA_ENABLED = 2; - - public static final int REASON_POLICY_DATA_ENABLED = 3; - - public static final int REASON_DATA_ENABLED_BY_CARRIER = 4; - - public static final int REASON_PROVISIONED_CHANGED = 5; - - public static final int REASON_PROVISIONING_DATA_ENABLED_CHANGED = 6; - - public static final int REASON_OVERRIDE_RULE_CHANGED = 7; - - public static final int REASON_OVERRIDE_CONDITION_CHANGED = 8; - - public static final int REASON_THERMAL_DATA_ENABLED = 9; - - /** - * responds to the setInternalDataEnabled call - used internally to turn off data. - * For example during emergency calls - */ - private boolean mInternalDataEnabled = true; - - /** - * Flag indicating data allowed by network policy manager or not. - */ - private boolean mPolicyDataEnabled = true; - - /** - * Indicate if metered APNs are enabled by the carrier. set false to block all the metered APNs - * from continuously sending requests, which causes undesired network load. - */ - private boolean mCarrierDataEnabled = true; - - /** - * Flag indicating data allowed by Thermal service or not. - */ - private boolean mThermalDataEnabled = true; - - /** - * Flag indicating whether data is allowed or not for the device. It can be disabled by - * user, carrier, policy or thermal - */ - private boolean mIsDataEnabled = false; - - private final Phone mPhone; - - private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - - private ContentResolver mResolver = null; - - private final RegistrantList mOverallDataEnabledChangedRegistrants = new RegistrantList(); - - // TODO: Merge this with mOverallDataEnabledChangedRegistrants. In the future, notifying data - // enabled changed with APN types bitmask - private final RegistrantList mOverallDataEnabledOverrideChangedRegistrants = - new RegistrantList(); - - private final LocalLog mSettingChangeLocalLog = new LocalLog(32); - - private DataEnabledOverride mDataEnabledOverride; - - private TelephonyManager mTelephonyManager; - - // for msim, user data enabled setting depends on subId. - private final SubscriptionManager.OnSubscriptionsChangedListener - mOnSubscriptionsChangeListener = - new SubscriptionManager.OnSubscriptionsChangedListener() { - @Override - public void onSubscriptionsChanged() { - synchronized (this) { - if (mSubId != mPhone.getSubId()) { - log("onSubscriptionsChanged subId: " + mSubId + " to: " - + mPhone.getSubId()); - mSubId = mPhone.getSubId(); - mDataEnabledOverride = getDataEnabledOverride(); - updatePhoneStateListener(); - updateDataEnabledAndNotify(REASON_USER_DATA_ENABLED); - mPhone.notifyUserMobileDataStateChanged(isUserDataEnabled()); - } - } - } - }; - - private void updatePhoneStateListener() { - mTelephonyManager.listen(mPhoneStateListener, LISTEN_NONE); - if (SubscriptionManager.isUsableSubscriptionId(mSubId)) { - mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); - } - mTelephonyManager.listen(mPhoneStateListener, LISTEN_CALL_STATE); - } - - private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - @Override - public void onCallStateChanged(@CallState int state, String phoneNumber) { - updateDataEnabledAndNotify(REASON_OVERRIDE_CONDITION_CHANGED); - } - }; - - @Override - public String toString() { - return "[mInternalDataEnabled=" + mInternalDataEnabled - + ", isUserDataEnabled=" + isUserDataEnabled() - + ", isProvisioningDataEnabled=" + isProvisioningDataEnabled() - + ", mPolicyDataEnabled=" + mPolicyDataEnabled - + ", mCarrierDataEnabled=" + mCarrierDataEnabled - + ", mIsDataEnabled=" + mIsDataEnabled - + ", mThermalDataEnabled=" + mThermalDataEnabled - + ", " + mDataEnabledOverride - + "]"; - } - - public DataEnabledSettings(Phone phone) { - mPhone = phone; - mResolver = mPhone.getContext().getContentResolver(); - SubscriptionManager subscriptionManager = (SubscriptionManager) mPhone.getContext() - .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); - subscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); - mTelephonyManager = (TelephonyManager) mPhone.getContext() - .getSystemService(Context.TELEPHONY_SERVICE); - mDataEnabledOverride = getDataEnabledOverride(); - updateDataEnabled(); - } - - private DataEnabledOverride getDataEnabledOverride() { - return new DataEnabledOverride(SubscriptionController.getInstance() - .getDataEnabledOverrideRules(mPhone.getSubId())); - } - - public synchronized void setInternalDataEnabled(boolean enabled) { - if (mInternalDataEnabled != enabled) { - localLog("InternalDataEnabled", enabled); - mInternalDataEnabled = enabled; - updateDataEnabledAndNotify(REASON_INTERNAL_DATA_ENABLED); - } - } - public synchronized boolean isInternalDataEnabled() { - return mInternalDataEnabled; - } - - private synchronized void setUserDataEnabled(boolean enabled) { - // By default the change should propagate to the group. - setUserDataEnabled(enabled, true); - } - - /** - * @param notifyMultiSimSettingController if setUserDataEnabled is already from propagating - * from MultiSimSettingController, don't notify MultiSimSettingController again. - * For example, if sub1 and sub2 are in the same group and user enables data for sub - * 1, sub 2 will also be enabled but with propagateToGroup = false. - */ - public synchronized void setUserDataEnabled(boolean enabled, - boolean notifyMultiSimSettingController) { - // Can't disable data for stand alone opportunistic subscription. - if (isStandAloneOpportunistic(mPhone.getSubId(), mPhone.getContext()) && !enabled) return; - - boolean changed = GlobalSettingsHelper.setInt(mPhone.getContext(), - Settings.Global.MOBILE_DATA, mPhone.getSubId(), (enabled ? 1 : 0)); - if (changed) { - localLog("UserDataEnabled", enabled); - mPhone.notifyUserMobileDataStateChanged(enabled); - updateDataEnabledAndNotify(REASON_USER_DATA_ENABLED); - if (notifyMultiSimSettingController) { - MultiSimSettingController.getInstance().notifyUserDataEnabled( - mPhone.getSubId(), enabled); - } - } - } - - /** - * Policy control of data connection with reason - * @param reason the reason the data enable change is taking place - * @param enabled True if enabling the data, otherwise disabling. - */ - public synchronized void setDataEnabled(@TelephonyManager.DataEnabledReason int reason, - boolean enabled) { - switch (reason) { - case TelephonyManager.DATA_ENABLED_REASON_USER: - setUserDataEnabled(enabled); - break; - case TelephonyManager.DATA_ENABLED_REASON_CARRIER: - setCarrierDataEnabled(enabled); - break; - case TelephonyManager.DATA_ENABLED_REASON_POLICY: - setPolicyDataEnabled(enabled); - break; - case TelephonyManager.DATA_ENABLED_REASON_THERMAL: - setThermalDataEnabled(enabled); - break; - default: - log("Invalid data enable reason " + reason); - break; - } - } - - public synchronized boolean isUserDataEnabled() { - // User data should always be true for opportunistic subscription. - if (isStandAloneOpportunistic(mPhone.getSubId(), mPhone.getContext())) return true; - - boolean defaultVal = TelephonyProperties.mobile_data().orElse(true); - - return GlobalSettingsHelper.getBoolean(mPhone.getContext(), - Settings.Global.MOBILE_DATA, mPhone.getSubId(), defaultVal); - } - - /** - * Set whether always allowing MMS data connection. - * - * @param alwaysAllow {@code true} if MMS data is always allowed. - * - * @return {@code false} if the setting is changed. - */ - public synchronized boolean setAlwaysAllowMmsData(boolean alwaysAllow) { - localLog("setAlwaysAllowMmsData", alwaysAllow); - mDataEnabledOverride.setAlwaysAllowMms(alwaysAllow); - boolean changed = SubscriptionController.getInstance() - .setDataEnabledOverrideRules(mPhone.getSubId(), mDataEnabledOverride.getRules()); - if (changed) { - updateDataEnabledAndNotify(REASON_OVERRIDE_RULE_CHANGED); - notifyDataEnabledOverrideChanged(); - } - - return changed; - } - - /** - * Set allowing mobile data during voice call. This is used for allowing data on the non-default - * data SIM. When a voice call is placed on the non-default data SIM on DSDS devices, users will - * not be able to use mobile data. By calling this API, data will be temporarily enabled on the - * non-default data SIM during the life cycle of the voice call. - * - * @param allow {@code true} if allowing using data during voice call, {@code false} if - * disallowed - * - * @return {@code true} if operation is successful. otherwise {@code false}. - */ - public synchronized boolean setAllowDataDuringVoiceCall(boolean allow) { - localLog("setAllowDataDuringVoiceCall", allow); - if (allow == isDataAllowedInVoiceCall()) { - return true; - } - mDataEnabledOverride.setDataAllowedInVoiceCall(allow); - - boolean changed = SubscriptionController.getInstance() - .setDataEnabledOverrideRules(mPhone.getSubId(), mDataEnabledOverride.getRules()); - if (changed) { - updateDataEnabledAndNotify(REASON_OVERRIDE_RULE_CHANGED); - notifyDataEnabledOverrideChanged(); - } - - return changed; - } - - /** - * Check if data is allowed during voice call. - * - * @return {@code true} if data is allowed during voice call. - */ - public synchronized boolean isDataAllowedInVoiceCall() { - return mDataEnabledOverride.isDataAllowedInVoiceCall(); - } - - public synchronized boolean isMmsAlwaysAllowed() { - return mDataEnabledOverride.isMmsAlwaysAllowed(); - } - - private synchronized void setPolicyDataEnabled(boolean enabled) { - if (mPolicyDataEnabled != enabled) { - localLog("PolicyDataEnabled", enabled); - mPolicyDataEnabled = enabled; - updateDataEnabledAndNotify(REASON_POLICY_DATA_ENABLED); - } - } - - public synchronized boolean isPolicyDataEnabled() { - return mPolicyDataEnabled; - } - - private synchronized void setCarrierDataEnabled(boolean enabled) { - if (mCarrierDataEnabled != enabled) { - localLog("CarrierDataEnabled", enabled); - mCarrierDataEnabled = enabled; - updateDataEnabledAndNotify(REASON_DATA_ENABLED_BY_CARRIER); - } - } - - public synchronized boolean isCarrierDataEnabled() { - return mCarrierDataEnabled; - } - - private synchronized void setThermalDataEnabled(boolean enabled) { - if (mThermalDataEnabled != enabled) { - localLog("ThermalDataEnabled", enabled); - mThermalDataEnabled = enabled; - updateDataEnabledAndNotify(REASON_THERMAL_DATA_ENABLED); - } - } - - public synchronized boolean isThermalDataEnabled() { - return mThermalDataEnabled; - } - - public synchronized void updateProvisionedChanged() { - updateDataEnabledAndNotify(REASON_PROVISIONED_CHANGED); - } - - public synchronized void updateProvisioningDataEnabled() { - updateDataEnabledAndNotify(REASON_PROVISIONING_DATA_ENABLED_CHANGED); - } - - public synchronized boolean isDataEnabled() { - return mIsDataEnabled; - } - - /** - * Check if data is enabled for a specific reason {@@TelephonyManager.DataEnabledReason} - * - * @return {@code true} if the overall data is enabled; {@code false} if not. - */ - public synchronized boolean isDataEnabledForReason( - @TelephonyManager.DataEnabledReason int reason) { - switch (reason) { - case TelephonyManager.DATA_ENABLED_REASON_USER: - return isUserDataEnabled(); - case TelephonyManager.DATA_ENABLED_REASON_CARRIER: - return isCarrierDataEnabled(); - case TelephonyManager.DATA_ENABLED_REASON_POLICY: - return isPolicyDataEnabled(); - case TelephonyManager.DATA_ENABLED_REASON_THERMAL: - return isThermalDataEnabled(); - default: - return false; - } - } - - private synchronized void updateDataEnabledAndNotify(int reason) { - boolean prevDataEnabled = mIsDataEnabled; - - updateDataEnabled(); - - if (prevDataEnabled != mIsDataEnabled) { - notifyDataEnabledChanged(!prevDataEnabled, reason); - } - } - - private synchronized void updateDataEnabled() { - if (isProvisioning()) { - mIsDataEnabled = isProvisioningDataEnabled(); - } else { - mIsDataEnabled = mInternalDataEnabled && (isUserDataEnabled() || mDataEnabledOverride - .shouldOverrideDataEnabledSettings(mPhone, ApnSetting.TYPE_ALL)) - && mPolicyDataEnabled && mCarrierDataEnabled && mThermalDataEnabled; - } - } - - public boolean isProvisioning() { - return Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0; - } - /** - * In provisioning, we might want to have enable mobile data during provisioning. It depends - * on value of Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED which is set by - * setupwizard. It only matters if it's in provisioning stage. - * @return whether we are enabling userData during provisioning stage. - */ - public boolean isProvisioningDataEnabled() { - final String prov_property = SystemProperties.get("ro.com.android.prov_mobiledata", - "false"); - boolean retVal = "true".equalsIgnoreCase(prov_property); - - final int prov_mobile_data = Settings.Global.getInt(mResolver, - Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, - retVal ? 1 : 0); - retVal = prov_mobile_data != 0; - log("getDataEnabled during provisioning retVal=" + retVal + " - (" + prov_property - + ", " + prov_mobile_data + ")"); - - return retVal; - } - - public synchronized void setDataRoamingEnabled(boolean enabled) { - // will trigger handleDataOnRoamingChange() through observer - boolean changed = GlobalSettingsHelper.setBoolean(mPhone.getContext(), - Settings.Global.DATA_ROAMING, mPhone.getSubId(), enabled); - - if (changed) { - localLog("setDataRoamingEnabled", enabled); - MultiSimSettingController.getInstance().notifyRoamingDataEnabled(mPhone.getSubId(), - enabled); - } - } - - /** - * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value. - */ - public synchronized boolean getDataRoamingEnabled() { - return GlobalSettingsHelper.getBoolean(mPhone.getContext(), - Settings.Global.DATA_ROAMING, mPhone.getSubId(), getDefaultDataRoamingEnabled()); - } - - /** - * get default values for {@link Settings.Global#DATA_ROAMING} - * return {@code true} if either - * {@link CarrierConfigManager#KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL} or - * system property ro.com.android.dataroaming is set to true. otherwise return {@code false} - */ - public synchronized boolean getDefaultDataRoamingEnabled() { - final CarrierConfigManager configMgr = (CarrierConfigManager) - mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - boolean isDataRoamingEnabled = "true".equalsIgnoreCase(SystemProperties.get( - "ro.com.android.dataroaming", "false")); - isDataRoamingEnabled |= configMgr.getConfigForSubId(mPhone.getSubId()).getBoolean( - CarrierConfigManager.KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL); - return isDataRoamingEnabled; - } - - private void notifyDataEnabledChanged(boolean enabled, int reason) { - mOverallDataEnabledChangedRegistrants.notifyResult(new Pair<>(enabled, reason)); - mPhone.notifyDataEnabled(enabled, reason); - } - - public void registerForDataEnabledChanged(Handler h, int what, Object obj) { - mOverallDataEnabledChangedRegistrants.addUnique(h, what, obj); - notifyDataEnabledChanged(isDataEnabled(), REASON_REGISTERED); - } - - public void unregisterForDataEnabledChanged(Handler h) { - mOverallDataEnabledChangedRegistrants.remove(h); - } - - private void notifyDataEnabledOverrideChanged() { - mOverallDataEnabledOverrideChangedRegistrants.notifyRegistrants(); - } - - /** - * Register for data enabled override changed event. - * - * @param h The handler - * @param what The event - */ - public void registerForDataEnabledOverrideChanged(Handler h, int what) { - mOverallDataEnabledOverrideChangedRegistrants.addUnique(h, what, null); - notifyDataEnabledOverrideChanged(); - } - - /** - * Unregistered for data enabled override changed event. - * - * @param h The handler - */ - public void unregisterForDataEnabledOverrideChanged(Handler h) { - mOverallDataEnabledOverrideChangedRegistrants.remove(h); - } - - private static boolean isStandAloneOpportunistic(int subId, Context context) { - SubscriptionInfo info = SubscriptionController.getInstance().getActiveSubscriptionInfo( - subId, context.getOpPackageName(), context.getAttributionTag()); - return (info != null) && info.isOpportunistic() && info.getGroupUuid() == null; - } - - public synchronized boolean isDataEnabled(int apnType) { - if (isProvisioning()) { - return isProvisioningDataEnabled(); - } else { - boolean userDataEnabled = isUserDataEnabled(); - // Check if we should temporarily enable data in certain conditions. - boolean isDataEnabledOverridden = mDataEnabledOverride - .shouldOverrideDataEnabledSettings(mPhone, apnType); - - return (mInternalDataEnabled && mPolicyDataEnabled && mCarrierDataEnabled - && mThermalDataEnabled && (userDataEnabled || isDataEnabledOverridden)); - } - } - - private void log(String s) { - Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); - } - - private void localLog(String name, boolean value) { - mSettingChangeLocalLog.log(name + " change to " + value); - } - - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println(" DataEnabledSettings="); - mSettingChangeLocalLog.dump(fd, pw, args); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java deleted file mode 100644 index d00600464b..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java +++ /dev/null @@ -1,978 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import static android.text.format.DateUtils.MINUTE_IN_MILLIS; -import static android.text.format.DateUtils.SECOND_IN_MILLIS; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.AppOpsManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.LinkProperties; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.PersistableBundle; -import android.os.RegistrantList; -import android.os.RemoteException; -import android.os.UserHandle; -import android.permission.LegacyPermissionManager; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.TransportType; -import android.telephony.AnomalyReporter; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionManager; -import android.telephony.data.DataCallResponse; -import android.telephony.data.DataProfile; -import android.telephony.data.DataService; -import android.telephony.data.DataServiceCallback; -import android.telephony.data.IDataService; -import android.telephony.data.IDataServiceCallback; -import android.telephony.data.NetworkSliceInfo; -import android.telephony.data.TrafficDescriptor; -import android.text.TextUtils; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConfigurationManager; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.telephony.Rlog; - -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; - -/** - * Data service manager manages handling data requests and responses on data services (e.g. - * Cellular data service, IWLAN data service). - */ -public class DataServiceManager extends Handler { - private static final boolean DBG = true; - - static final String DATA_CALL_RESPONSE = "data_call_response"; - - 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; - - private final int mTransportType; - - private boolean mBound; - - private IDataService mIDataService; - - private DataServiceManagerDeathRecipient mDeathRecipient; - - private final RegistrantList mServiceBindingChangedRegistrants = new RegistrantList(); - - private final Map mMessageMap = new ConcurrentHashMap<>(); - - private final RegistrantList mDataCallListChangedRegistrants = new RegistrantList(); - - private final RegistrantList mApnUnthrottledRegistrants = new RegistrantList(); - - private String mTargetBindingPackageName; - - private CellularDataServiceConnection mServiceConnection; - - private final UUID mAnomalyUUID = UUID.fromString("fc1956de-c080-45de-8431-a1faab687110"); - private String mLastBoundPackageName; - - /** - * Helpful for logging - * @return the tag name - * - * @hide - */ - public String getTag() { - return mTag; - } - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) - && mPhone.getPhoneId() == intent.getIntExtra( - CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) { - // 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."); - sendEmptyMessage(EVENT_BIND_DATA_SERVICE); - } - } - }; - - private class DataServiceManagerDeathRecipient implements IBinder.DeathRecipient { - @Override - public void binderDied() { - // TODO: try to rebind the service. - String message = "Data service " + mLastBoundPackageName + " for transport type " - + AccessNetworkConstants.transportTypeToString(mTransportType) + " died."; - loge(message); - AnomalyReporter.reportAnomaly(mAnomalyUUID, message, mPhone.getCarrierId()); - } - } - - private void grantPermissionsToService(String packageName) { - final String[] pkgToGrant = {packageName}; - CountDownLatch latch = new CountDownLatch(1); - try { - mPermissionManager.grantDefaultPermissionsToEnabledTelephonyDataServices( - pkgToGrant, UserHandle.of(UserHandle.myUserId()), Runnable::run, - isSuccess -> { - if (isSuccess) { - latch.countDown(); - } else { - loge("Failed to grant permissions to service."); - } - }); - TelephonyUtils.waitUntilReady(latch, CHANGE_PERMISSION_TIMEOUT_MS); - mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, - UserHandle.myUserId(), pkgToGrant[0], AppOpsManager.MODE_ALLOWED); - mAppOps.setMode(AppOpsManager.OPSTR_FINE_LOCATION, - UserHandle.myUserId(), pkgToGrant[0], AppOpsManager.MODE_ALLOWED); - } catch (RuntimeException e) { - loge("Binder to package manager died, permission grant for DataService failed."); - throw e; - } - } - - /** - * Loop through all DataServices installed on the system and revoke permissions from any that - * are not currently the WWAN or WLAN data service. - */ - private void revokePermissionsFromUnusedDataServices() { - // Except the current data services from having their permissions removed. - Set dataServices = getAllDataServicePackageNames(); - for (int transportType : mPhone.getAccessNetworksManager().getAvailableTransports()) { - dataServices.remove(getDataServicePackageName(transportType)); - } - - CountDownLatch latch = new CountDownLatch(1); - try { - String[] dataServicesArray = new String[dataServices.size()]; - dataServices.toArray(dataServicesArray); - mPermissionManager.revokeDefaultPermissionsFromDisabledTelephonyDataServices( - dataServicesArray, UserHandle.of(UserHandle.myUserId()), Runnable::run, - isSuccess -> { - if (isSuccess) { - latch.countDown(); - } else { - loge("Failed to revoke permissions from data services."); - } - }); - TelephonyUtils.waitUntilReady(latch, CHANGE_PERMISSION_TIMEOUT_MS); - for (String pkg : dataServices) { - mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, UserHandle.myUserId(), - pkg, AppOpsManager.MODE_ERRORED); - mAppOps.setMode(AppOpsManager.OPSTR_FINE_LOCATION, UserHandle.myUserId(), - pkg, AppOpsManager.MODE_ERRORED); - } - } catch (RuntimeException e) { - loge("Binder to package manager died; failed to revoke DataService permissions."); - throw e; - } - } - - private final class CellularDataServiceConnection implements ServiceConnection { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - if (DBG) log("onServiceConnected"); - mIDataService = IDataService.Stub.asInterface(service); - mDeathRecipient = new DataServiceManagerDeathRecipient(); - mBound = true; - mLastBoundPackageName = getDataServicePackageName(); - removeMessages(EVENT_WATCHDOG_TIMEOUT); - - try { - service.linkToDeath(mDeathRecipient, 0); - mIDataService.createDataServiceProvider(mPhone.getPhoneId()); - mIDataService.registerForDataCallListChanged(mPhone.getPhoneId(), - new CellularDataServiceCallback("dataCallListChanged")); - mIDataService.registerForUnthrottleApn(mPhone.getPhoneId(), - new CellularDataServiceCallback("unthrottleApn")); - } catch (RemoteException e) { - loge("Remote exception. " + e); - return; - } - mServiceBindingChangedRegistrants.notifyResult(true); - } - @Override - public void onServiceDisconnected(ComponentName name) { - if (DBG) log("onServiceDisconnected"); - removeMessages(EVENT_WATCHDOG_TIMEOUT); - mIDataService = null; - mBound = false; - mServiceBindingChangedRegistrants.notifyResult(false); - mTargetBindingPackageName = null; - } - } - - private final class CellularDataServiceCallback extends IDataServiceCallback.Stub { - - private final String mTag; - - CellularDataServiceCallback(String tag) { - mTag = tag; - } - - public String getTag() { - return mTag; - } - - @Override - public void onSetupDataCallComplete(@DataServiceCallback.ResultCode int resultCode, - DataCallResponse response) { - if (DBG) { - log("onSetupDataCallComplete. resultCode = " + resultCode + ", response = " - + response); - } - removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); - Message msg = mMessageMap.remove(asBinder()); - if (msg != null) { - msg.getData().putParcelable(DATA_CALL_RESPONSE, response); - sendCompleteMessage(msg, resultCode); - } else { - loge("Unable to find the message for setup call response."); - } - } - - @Override - public void onDeactivateDataCallComplete(@DataServiceCallback.ResultCode int resultCode) { - if (DBG) log("onDeactivateDataCallComplete. resultCode = " + resultCode); - removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onSetInitialAttachApnComplete(@DataServiceCallback.ResultCode int resultCode) { - if (DBG) log("onSetInitialAttachApnComplete. resultCode = " + resultCode); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onSetDataProfileComplete(@DataServiceCallback.ResultCode int resultCode) { - if (DBG) log("onSetDataProfileComplete. resultCode = " + resultCode); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onRequestDataCallListComplete(@DataServiceCallback.ResultCode int resultCode, - List dataCallList) { - if (DBG) log("onRequestDataCallListComplete. resultCode = " + resultCode); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onDataCallListChanged(List dataCallList) { - mDataCallListChangedRegistrants.notifyRegistrants( - new AsyncResult(null, dataCallList, null)); - } - - @Override - public void onHandoverStarted(@DataServiceCallback.ResultCode int resultCode) { - if (DBG) log("onHandoverStarted. resultCode = " + resultCode); - removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onHandoverCancelled(@DataServiceCallback.ResultCode int resultCode) { - if (DBG) log("onHandoverCancelled. resultCode = " + resultCode); - removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onApnUnthrottled(String apn) { - if (apn != null) { - mApnUnthrottledRegistrants.notifyRegistrants( - new AsyncResult(null, apn, null)); - } else { - loge("onApnUnthrottled: apn is null"); - } - } - - @Override - public void onDataProfileUnthrottled(DataProfile dataProfile) { - if (dataProfile != null) { - mApnUnthrottledRegistrants.notifyRegistrants( - new AsyncResult(null, dataProfile, null)); - } else { - loge("onDataProfileUnthrottled: dataProfile is null"); - } - } - } - - /** - * Constructor - * - * @param phone The phone object - * @param transportType The transport type - * @param tagSuffix Logging tag suffix - */ - public DataServiceManager(Phone phone, @TransportType int transportType, String tagSuffix) { - mPhone = phone; - mTag = "DSM" + tagSuffix; - mTransportType = transportType; - mBound = false; - mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService( - Context.CARRIER_CONFIG_SERVICE); - // 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 - mPermissionManager = (LegacyPermissionManager) phone.getContext().getSystemService( - Context.LEGACY_PERMISSION_SERVICE); - mAppOps = (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE); - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - try { - Context contextAsUser = phone.getContext().createPackageContextAsUser( - phone.getContext().getPackageName(), 0, UserHandle.ALL); - contextAsUser.registerReceiver(mBroadcastReceiver, intentFilter, - null /* broadcastPermission */, null); - } catch (PackageManager.NameNotFoundException e) { - loge("Package name not found: " + e.getMessage()); - } - - PhoneConfigurationManager.registerForMultiSimConfigChange( - this, EVENT_BIND_DATA_SERVICE, null); - - sendEmptyMessage(EVENT_BIND_DATA_SERVICE); - } - - /** - * Handle message events - * - * @param msg The message to handle - */ - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_BIND_DATA_SERVICE: - rebindDataService(); - break; - case EVENT_WATCHDOG_TIMEOUT: - handleRequestUnresponded((CellularDataServiceCallback) msg.obj); - break; - default: - loge("Unhandled event " + msg.what); - } - } - - private void handleRequestUnresponded(CellularDataServiceCallback 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(); - if (mIDataService != null && mIDataService.asBinder().isBinderAlive()) { - log("unbinding service"); - // Remove the network availability updater and then unbind the service. - try { - mIDataService.removeDataServiceProvider(mPhone.getPhoneId()); - } catch (RemoteException e) { - loge("Cannot remove data service provider. " + e); - } - } - - if (mServiceConnection != null) { - mPhone.getContext().unbindService(mServiceConnection); - } - mIDataService = null; - mServiceConnection = null; - mTargetBindingPackageName = null; - mBound = false; - } - - private void bindDataService(String packageName) { - if (mPhone == null || !SubscriptionManager.isValidPhoneId(mPhone.getPhoneId())) { - loge("can't bindDataService with invalid phone or phoneId."); - return; - } - - if (TextUtils.isEmpty(packageName)) { - loge("Can't find the binding package"); - return; - } - - Intent intent = null; - String className = getDataServiceClassName(); - if (TextUtils.isEmpty(className)) { - intent = new Intent(DataService.SERVICE_INTERFACE); - intent.setPackage(packageName); - } else { - ComponentName cm = new ComponentName(packageName, className); - intent = new Intent(DataService.SERVICE_INTERFACE).setComponent(cm); - } - - // Then pre-emptively grant the permissions to the package we will bind. - grantPermissionsToService(packageName); - - try { - mServiceConnection = new CellularDataServiceConnection(); - if (!mPhone.getContext().bindService( - intent, mServiceConnection, Context.BIND_AUTO_CREATE)) { - loge("Cannot bind to the data service."); - return; - } - mTargetBindingPackageName = packageName; - } catch (Exception e) { - loge("Cannot bind to the data service. Exception: " + e); - } - } - - private void rebindDataService() { - String packageName = getDataServicePackageName(); - // Do nothing if no need to rebind. - if (SubscriptionManager.isValidPhoneId(mPhone.getPhoneId()) - && TextUtils.equals(packageName, mTargetBindingPackageName)) { - if (DBG) log("Service " + packageName + " already bound or being bound."); - return; - } - - unbindDataService(); - bindDataService(packageName); - } - - @NonNull - private Set 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 - // to be updated. - List dataPackages = - mPhone.getContext().getPackageManager().queryIntentServices( - new Intent(DataService.SERVICE_INTERFACE), - PackageManager.MATCH_SYSTEM_ONLY); - HashSet packageNames = new HashSet<>(); - for (ResolveInfo info : dataPackages) { - if (info.serviceInfo == null) continue; - packageNames.add(info.serviceInfo.packageName); - } - return packageNames; - } - - /** - * Get the data service package name for our current transport type. - * - * @return package name of the data service package for the the current transportType. - */ - public String getDataServicePackageName() { - return getDataServicePackageName(mTransportType); - } - - /** - * Get the data service package by transport type. - * - * 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. - * - * @param transportType The transport type - * @return package name of the data service package for the specified transportType. - */ - private String getDataServicePackageName(@TransportType int transportType) { - String packageName; - int resourceId; - String carrierConfig; - - switch (transportType) { - 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: - 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)); - } - - // Read package name from resource overlay - packageName = mPhone.getContext().getResources().getString(resourceId); - - PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { - // If carrier config overrides it, use the one from carrier config - packageName = b.getString(carrierConfig, packageName); - } - - return packageName; - } - - /** - * Get the data service class name for our current transport type. - * - * @return class name of the data service package for the the current transportType. - */ - private String getDataServiceClassName() { - return getDataServiceClassName(mTransportType); - } - - - /** - * Get the data service class by transport type. - * - * @param transportType either WWAN or WLAN - * @return class name of the data service package for the specified transportType. - */ - private String getDataServiceClassName(int transportType) { - String className; - int resourceId; - String carrierConfig; - switch (transportType) { - 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: - 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); - } - - // Read package name from resource overlay - className = mPhone.getContext().getResources().getString(resourceId); - - PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { - // If carrier config overrides it, use the one from carrier config - className = b.getString(carrierConfig, className); - } - - return className; - } - - private void sendCompleteMessage(Message msg, @DataServiceCallback.ResultCode int code) { - if (msg != null) { - msg.arg1 = code; - msg.sendToTarget(); - } - } - - /** - * Setup a data connection. The data service provider must implement this method to support - * establishing a packet data connection. When completed or error, the service must invoke - * the provided callback to notify the platform. - * - * @param accessNetworkType Access network type that the data call will be established on. - * Must be one of {@link AccessNetworkConstants.AccessNetworkType}. - * @param dataProfile Data profile used for data call setup. See {@link DataProfile} - * @param isRoaming True if the device is data roaming. - * @param allowRoaming True if data roaming is allowed by the user. - * @param reason The reason for data setup. Must be {@link DataService#REQUEST_REASON_NORMAL} or - * {@link DataService#REQUEST_REASON_HANDOVER}. - * @param linkProperties If {@code reason} is {@link DataService#REQUEST_REASON_HANDOVER}, this - * is the link properties of the existing data connection, otherwise null. - * @param pduSessionId The pdu session id to be used for this data call. A value of -1 means - * no pdu session id was attached to this call. - * Reference: 3GPP TS 24.007 Section 11.2.3.1b - * @param sliceInfo The slice that represents S-NSSAI. - * Reference: 3GPP TS 24.501 - * @param trafficDescriptor The traffic descriptor for this data call, used for URSP matching. - * Reference: 3GPP TS TS 24.526 Section 5.2 - * @param matchAllRuleAllowed True if using the default match-all URSP rule for this request is - * allowed. - * @param onCompleteMessage The result message for this request. Null if the client does not - * care about the result. - */ - public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, - @Nullable NetworkSliceInfo sliceInfo, @Nullable TrafficDescriptor trafficDescriptor, - boolean matchAllRuleAllowed, Message onCompleteMessage) { - if (DBG) log("setupDataCall"); - if (!mBound) { - loge("setupDataCall: Data service not bound."); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - CellularDataServiceCallback callback = new CellularDataServiceCallback("setupDataCall"); - if (onCompleteMessage != null) { - 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); - } catch (RemoteException e) { - loge("setupDataCall: Cannot invoke setupDataCall on data service."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Deactivate a data connection. The data service provider must implement this method to - * support data connection tear down. When completed or error, the service must invoke the - * provided callback to notify the platform. - * - * @param cid Call id returned in the callback of {@link #setupDataCall(int, DataProfile, - * boolean, boolean, int, LinkProperties, Message)} - * @param reason The reason for data deactivation. Must be - * {@link DataService#REQUEST_REASON_NORMAL}, {@link DataService#REQUEST_REASON_SHUTDOWN} - * or {@link DataService#REQUEST_REASON_HANDOVER}. - * @param onCompleteMessage The result message for this request. Null if the client does not - * care about the result. - */ - public void deactivateDataCall(int cid, int reason, Message onCompleteMessage) { - if (DBG) log("deactivateDataCall"); - if (!mBound) { - loge("Data service not bound."); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - CellularDataServiceCallback callback = - new CellularDataServiceCallback("deactivateDataCall"); - if (onCompleteMessage != null) { - 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."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Indicates that a handover has begun. This is called on the source transport. - * - * Any resources being transferred cannot be released while a - * handover is underway. - * - * If a handover was unsuccessful, then the framework calls DataServiceManager#cancelHandover. - * The target transport retains ownership over any of the resources being transferred. - * - * 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. - * - * @param cid The identifier of the data call which is provided in DataCallResponse - * @param onCompleteMessage The result callback for this request. - */ - public void startHandover(int cid, @NonNull Message onCompleteMessage) { - CellularDataServiceCallback callback = - setupCallbackHelper("startHandover", onCompleteMessage); - if (callback == null) { - loge("startHandover: callback == null"); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - 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."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Indicates that a handover was cancelled after a call to DataServiceManager#startHandover. - * This is called on the source transport. - * - * Since the handover was unsuccessful, the source transport retains ownership over any of - * the resources being transferred and is still responsible for releasing them. - * - * @param cid The identifier of the data call which is provided in DataCallResponse - * @param onCompleteMessage The result callback for this request. - */ - public void cancelHandover(int cid, @NonNull Message onCompleteMessage) { - CellularDataServiceCallback callback = - setupCallbackHelper("cancelHandover", onCompleteMessage); - if (callback == null) { - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - 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."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - @Nullable - private CellularDataServiceCallback setupCallbackHelper( - @NonNull final String operationName, @NonNull final Message onCompleteMessage) { - if (DBG) log(operationName); - if (!mBound) { - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return null; - } - - CellularDataServiceCallback callback = - new CellularDataServiceCallback(operationName); - if (onCompleteMessage != null) { - if (DBG) log(operationName + ": onCompleteMessage set"); - mMessageMap.put(callback.asBinder(), onCompleteMessage); - } else { - if (DBG) log(operationName + ": onCompleteMessage not set"); - } - return callback; - } - - /** - * Set an APN to initial attach network. - * - * @param dataProfile Data profile used for data call setup. See {@link DataProfile}. - * @param isRoaming True if the device is data roaming. - * @param onCompleteMessage The result message for this request. Null if the client does not - * care about the result. - */ - public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, - Message onCompleteMessage) { - if (DBG) log("setInitialAttachApn"); - if (!mBound) { - loge("Data service not bound."); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - CellularDataServiceCallback callback = - new CellularDataServiceCallback("setInitialAttachApn"); - if (onCompleteMessage != null) { - mMessageMap.put(callback.asBinder(), onCompleteMessage); - } - try { - mIDataService.setInitialAttachApn(mPhone.getPhoneId(), dataProfile, isRoaming, - callback); - } catch (RemoteException e) { - loge("Cannot invoke setInitialAttachApn on data service."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Send current carrier's data profiles to the data service for data call setup. This is - * only for CDMA carrier that can change the profile through OTA. The data service should - * always uses the latest data profile sent by the framework. - * - * @param dps A list of data profiles. - * @param isRoaming True if the device is data roaming. - * @param onCompleteMessage The result message for this request. Null if the client does not - * care about the result. - */ - public void setDataProfile(List dps, boolean isRoaming, - Message onCompleteMessage) { - if (DBG) log("setDataProfile"); - if (!mBound) { - loge("Data service not bound."); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - CellularDataServiceCallback callback = new CellularDataServiceCallback("setDataProfile"); - if (onCompleteMessage != null) { - mMessageMap.put(callback.asBinder(), onCompleteMessage); - } - try { - mIDataService.setDataProfile(mPhone.getPhoneId(), dps, isRoaming, callback); - } catch (RemoteException e) { - loge("Cannot invoke setDataProfile on data service."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Get the active data call list. - * - * @param onCompleteMessage The result message for this request. Null if the client does not - * care about the result. - */ - public void requestDataCallList(Message onCompleteMessage) { - if (DBG) log("requestDataCallList"); - if (!mBound) { - loge("Data service not bound."); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - CellularDataServiceCallback callback = - new CellularDataServiceCallback("requestDataCallList"); - if (onCompleteMessage != null) { - mMessageMap.put(callback.asBinder(), onCompleteMessage); - } - try { - mIDataService.requestDataCallList(mPhone.getPhoneId(), callback); - } catch (RemoteException e) { - loge("Cannot invoke requestDataCallList on data service."); - if (callback != null) { - mMessageMap.remove(callback.asBinder()); - } - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Register for data call list changed event. - * - * @param h The target to post the event message to. - * @param what The event. - */ - public void registerForDataCallListChanged(Handler h, int what) { - if (h != null) { - mDataCallListChangedRegistrants.addUnique(h, what, null); - } - } - - /** - * Unregister for data call list changed event. - * - * @param h The handler - */ - public void unregisterForDataCallListChanged(Handler h) { - if (h != null) { - mDataCallListChangedRegistrants.remove(h); - } - } - - /** - * Register apn unthrottled event - * - * @param h The target to post the event message to. - * @param what The event. - */ - public void registerForApnUnthrottled(Handler h, int what) { - if (h != null) { - mApnUnthrottledRegistrants.addUnique(h, what, null); - } - } - - /** - * Unregister for apn unthrottled event - * - * @param h The handler - */ - public void unregisterForApnUnthrottled(Handler h) { - if (h != null) { - mApnUnthrottledRegistrants.remove(h); - } - } - - /** - * Register for data service binding status changed event. - * - * @param h The target to post the event message to. - * @param what The event. - * @param obj The user object. - */ - public void registerForServiceBindingChanged(Handler h, int what, Object obj) { - if (h != null) { - mServiceBindingChangedRegistrants.addUnique(h, what, obj); - } - - } - - /** - * Unregister for data service binding status changed event. - * - * @param h The handler - */ - public void unregisterForServiceBindingChanged(Handler h) { - if (h != null) { - mServiceBindingChangedRegistrants.remove(h); - } - } - - /** - * Get the transport type. Must be a {@link TransportType}. - * - * @return - */ - @TransportType - public int getTransportType() { - return mTransportType; - } - - private void log(String s) { - Rlog.d(mTag, s); - } - - private void loge(String s) { - Rlog.e(mTag, s); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java b/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java deleted file mode 100644 index 4a465d262f..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (C) 2020 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.dataconnection; - -import android.annotation.ElapsedRealtimeLong; -import android.annotation.NonNull; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.os.PersistableBundle; -import android.telephony.AccessNetworkConstants; -import android.telephony.Annotation; -import android.telephony.Annotation.ApnType; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionManager; -import android.telephony.data.ApnSetting; -import android.telephony.data.ThrottleStatus; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.RetryManager; -import com.android.telephony.Rlog; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Data throttler tracks the throttling status of the data network and notifies registrants when - * there are changes. The throttler is per phone and per transport type. - */ -public class DataThrottler extends Handler { - private static final String TAG = DataThrottler.class.getSimpleName(); - - private static final int EVENT_SET_RETRY_TIME = 1; - private static final int EVENT_CARRIER_CONFIG_CHANGED = 2; - private static final int EVENT_RESET = 3; - private static final int EVENT_AIRPLANE_MODE_CHANGED = 4; - private static final int EVENT_TRACING_AREA_CODE_CHANGED = 5; - - private final Phone mPhone; - private final int mSlotIndex; - private final @AccessNetworkConstants.TransportType int mTransportType; - private boolean mResetWhenAreaCodeChanged = false; - - /** - * Callbacks that report the apn throttle status. - */ - private final List mCallbacks = new ArrayList<>(); - - /** - * Keeps track of detailed information of the throttle status that is meant to be - * reported to other components. - */ - private final Map mThrottleStatus = new ConcurrentHashMap<>(); - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - if (mPhone.getPhoneId() == intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { - if (intent.getBooleanExtra( - CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, false)) { - // Ignore the rebroadcast one to prevent multiple carrier config changed - // event during boot up. - return; - } - int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (SubscriptionManager.isValidSubscriptionId(subId)) { - sendEmptyMessage(EVENT_CARRIER_CONFIG_CHANGED); - } - } - } - } - }; - - public DataThrottler(Phone phone, int transportType) { - super(null, false); - mPhone = phone; - mSlotIndex = phone.getPhoneId(); - mTransportType = transportType; - - IntentFilter filter = new IntentFilter(); - filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - mPhone.getContext().registerReceiver(mBroadcastReceiver, filter, null, mPhone); - - mPhone.getServiceStateTracker().registerForAirplaneModeChanged(this, - EVENT_AIRPLANE_MODE_CHANGED, null); - mPhone.getServiceStateTracker().registerForAreaCodeChanged(this, - EVENT_TRACING_AREA_CODE_CHANGED, null); - } - - @Override - public void handleMessage(Message msg) { - AsyncResult ar; - switch (msg.what) { - case EVENT_SET_RETRY_TIME: - int apnTypes = msg.arg1; - int newRequestType = msg.arg2; - long retryElapsedTime = (long) msg.obj; - setRetryTimeInternal(apnTypes, retryElapsedTime, newRequestType); - break; - case EVENT_CARRIER_CONFIG_CHANGED: - onCarrierConfigChanged(); - break; - case EVENT_RESET: - resetInternal(); - break; - case EVENT_AIRPLANE_MODE_CHANGED: - ar = (AsyncResult) msg.obj; - if (!(Boolean) ar.result) { - resetInternal(); - } - break; - case EVENT_TRACING_AREA_CODE_CHANGED: - if (mResetWhenAreaCodeChanged) { - resetInternal(); - } - break; - } - } - - @NonNull - private PersistableBundle getCarrierConfig() { - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - // If an invalid subId is used, this bundle will contain default values. - PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId()); - if (config != null) { - return config; - } - } - // Return static default defined in CarrierConfigManager. - return CarrierConfigManager.getDefaultConfig(); - } - - private void onCarrierConfigChanged() { - PersistableBundle config = getCarrierConfig(); - mResetWhenAreaCodeChanged = config.getBoolean( - CarrierConfigManager.KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false); - } - - /** - * Set the retry time and handover failure mode for the give APN types. - * - * @param apnTypes APN types - * @param retryElapsedTime The elapsed time that data connection for APN types should not be - * retried. {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} indicates throttling does not exist. - * {@link RetryManager#NO_RETRY} indicates retry should never happen. - */ - public void setRetryTime(@ApnType int apnTypes, @ElapsedRealtimeLong long retryElapsedTime, - @DcTracker.RequestNetworkType int newRequestType) { - sendMessage(obtainMessage(EVENT_SET_RETRY_TIME, apnTypes, newRequestType, - retryElapsedTime)); - } - - /** - * Set the retry time and handover failure mode for the give APN types. This is running on the - * handler thread. - * - * @param apnTypes APN types - * @param retryElapsedTime The elapsed time that data connection for APN types should not be - * retried. {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} indicates throttling does not exist. - * {@link RetryManager#NO_RETRY} indicates retry should never happen. - */ - private void setRetryTimeInternal(@ApnType int apnTypes, @ElapsedRealtimeLong - long retryElapsedTime, @DcTracker.RequestNetworkType int newRequestType) { - if (retryElapsedTime < 0) { - retryElapsedTime = RetryManager.NO_SUGGESTED_RETRY_DELAY; - } - - List changedStatuses = new ArrayList<>(); - while (apnTypes != 0) { - int apnType; - // Due to an API mistake of ApnSetting.TYPE_DEFAULT (which combines default and hipri - // bit), we need to do special handling here. - if ((apnTypes & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) { - apnType = ApnSetting.TYPE_DEFAULT; - apnTypes &= ~ApnSetting.TYPE_DEFAULT; - } else { - //Extract the least significant bit. - apnType = apnTypes & -apnTypes; - //Remove the least significant bit. - apnTypes &= apnTypes - 1; - } - - //Update the apn throttle status - ThrottleStatus newStatus = createStatus(apnType, retryElapsedTime, newRequestType); - - ThrottleStatus oldStatus = mThrottleStatus.get(apnType); - - //Check to see if there is a change that needs to be applied - if (!newStatus.equals(oldStatus)) { - //Mark as changed status - changedStatuses.add(newStatus); - - //Put the new status in the temp space - mThrottleStatus.put(apnType, newStatus); - } - } - - if (changedStatuses.size() > 0) { - sendThrottleStatusChanged(changedStatuses); - } - } - - /** - * Get the earliest retry time for the given APN type. The time is the system's elapse time. - * - * Note the DataThrottler is running phone process's main thread, which is most of the telephony - * components running on. Calling this method from other threads might run into race conditions. - * - * @param apnType APN type - * @return The earliest retry time for APN type. The time is the system's elapse time. - * {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} indicates there is no throttling for given APN - * type, {@link RetryManager#NO_RETRY} indicates retry should never happen. - */ - @ElapsedRealtimeLong - public long getRetryTime(@ApnType int apnType) { - ThrottleStatus status = mThrottleStatus.get(apnType); - if (status != null) { - if (status.getThrottleType() == ThrottleStatus.THROTTLE_TYPE_NONE) { - return RetryManager.NO_SUGGESTED_RETRY_DELAY; - } else { - return status.getThrottleExpiryTimeMillis(); - } - } - return RetryManager.NO_SUGGESTED_RETRY_DELAY; - } - - /** - * Resets retry times for all APNs to {@link RetryManager.NO_SUGGESTED_RETRY_DELAY}. - */ - public void reset() { - sendEmptyMessage(EVENT_RESET); - } - - /** - * Resets retry times for all APNs to {@link RetryManager.NO_SUGGESTED_RETRY_DELAY}. - */ - private void resetInternal() { - final List apnTypes = new ArrayList<>(); - for (ThrottleStatus throttleStatus : mThrottleStatus.values()) { - apnTypes.add(throttleStatus.getApnType()); - } - - for (int apnType : apnTypes) { - setRetryTime(apnType, RetryManager.NO_SUGGESTED_RETRY_DELAY, - DcTracker.REQUEST_TYPE_NORMAL); - } - } - - private ThrottleStatus createStatus(@Annotation.ApnType int apnType, long retryElapsedTime, - @DcTracker.RequestNetworkType int newRequestType) { - ThrottleStatus.Builder builder = new ThrottleStatus.Builder(); - - if (retryElapsedTime == RetryManager.NO_SUGGESTED_RETRY_DELAY) { - builder - .setNoThrottle() - .setRetryType(getRetryType(newRequestType)); - } else if (retryElapsedTime == RetryManager.NO_RETRY) { - builder - .setThrottleExpiryTimeMillis(RetryManager.NO_RETRY) - .setRetryType(ThrottleStatus.RETRY_TYPE_NONE); - } else { - builder - .setThrottleExpiryTimeMillis(retryElapsedTime) - .setRetryType(getRetryType(newRequestType)); - } - return builder - .setSlotIndex(mSlotIndex) - .setTransportType(mTransportType) - .setApnType(apnType) - .build(); - } - - private static int getRetryType(@DcTracker.RequestNetworkType int newRequestType) { - if (newRequestType == DcTracker.REQUEST_TYPE_NORMAL) { - return ThrottleStatus.RETRY_TYPE_NEW_CONNECTION; - } - - if (newRequestType == DcTracker.REQUEST_TYPE_HANDOVER) { - return ThrottleStatus.RETRY_TYPE_HANDOVER; - } - - loge("createStatus: Unknown requestType=" + newRequestType); - return ThrottleStatus.RETRY_TYPE_NEW_CONNECTION; - } - - private void sendThrottleStatusChanged(List statuses) { - synchronized (mCallbacks) { - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onThrottleStatusChanged(statuses); - } - } - } - - private static void loge(String s) { - Rlog.e(TAG, s); - } - - /** - * Reports changes to apn throttle statuses. - * - * Note: All statuses are sent when first registered. - * - * @param callback status changes callback - */ - public void registerForThrottleStatusChanges(DataThrottler.Callback callback) { - synchronized (mCallbacks) { - //Only add if it's not there already - if (!mCallbacks.contains(callback)) { - //Report everything the first time - List throttleStatuses = - new ArrayList<>(mThrottleStatus.values()); - callback.onThrottleStatusChanged(throttleStatuses); - mCallbacks.add(callback); - } - } - } - - /** - * Unregister the callback - * @param callback the callback to unregister - */ - public void unregisterForThrottleStatusChanges(DataThrottler.Callback callback) { - synchronized (mCallbacks) { - mCallbacks.remove(callback); - } - } - - /** - * Callback for when throttle statuses change - */ - public interface Callback { - /** - * Called whenever the throttle status of an APN has changed. - * - * Note: Called with all statuses when first registered. - * - * @param throttleStatuses the status changes - */ - void onThrottleStatusChanged(List throttleStatuses); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java deleted file mode 100644 index c34157eb9e..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcController.java +++ /dev/null @@ -1,487 +0,0 @@ -/* - * Copyright (C) 2013 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.dataconnection; - -import android.hardware.radio.V1_4.DataConnActiveStatus; -import android.net.LinkAddress; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.RegistrantList; -import android.telephony.AccessNetworkConstants; -import android.telephony.CarrierConfigManager; -import android.telephony.DataFailCause; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.telephony.data.TrafficDescriptor; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.dataconnection.DataConnection.UpdateLinkPropertyResult; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.net.module.util.LinkPropertiesUtils; -import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; -import com.android.net.module.util.NetUtils; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Objects; - -/** - * Data Connection Controller which is a package visible class and controls - * multiple data connections. For instance listening for unsolicited messages - * and then demultiplexing them to the appropriate DC. - */ -public class DcController extends Handler { - private static final boolean DBG = true; - private static final boolean VDBG = false; - - private final Phone mPhone; - private final DcTracker mDct; - private final String mTag; - private final DataServiceManager mDataServiceManager; - private final DcTesterDeactivateAll mDcTesterDeactivateAll; - - // package as its used by Testing code - // @GuardedBy("mDcListAll") - final ArrayList mDcListAll = new ArrayList<>(); - // @GuardedBy("mDcListAll") - private final HashMap mDcListActiveByCid = new HashMap<>(); - // @GuardedBy("mTrafficDescriptorsByCid") - private final HashMap> mTrafficDescriptorsByCid = - new HashMap<>(); - - /** - * Aggregated physical link status from all data connections. This reflects the device's RRC - * connection state. - * If {@link CarrierConfigManager#KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL} is true, - * then This reflects "internet data connection" instead of RRC state. - */ - private @DataCallResponse.LinkStatus int mPhysicalLinkStatus = - DataCallResponse.LINK_STATUS_UNKNOWN; - - private RegistrantList mPhysicalLinkStatusChangedRegistrants = new RegistrantList(); - - /** - * Constructor. - * - * @param name to be used for the Controller - * @param phone the phone associated with Dcc and Dct - * @param dct the DataConnectionTracker associated with Dcc - * @param dataServiceManager the data service manager that manages data services - * @param looper looper for this handler - */ - private DcController(String name, Phone phone, DcTracker dct, - DataServiceManager dataServiceManager, Looper looper) { - super(looper); - mPhone = phone; - mDct = dct; - mTag = name; - mDataServiceManager = dataServiceManager; - - mDcTesterDeactivateAll = (TelephonyUtils.IS_DEBUGGABLE) - ? new DcTesterDeactivateAll(mPhone, DcController.this, this) - : null; - mDataServiceManager.registerForDataCallListChanged(this, - DataConnection.EVENT_DATA_STATE_CHANGED); - } - - public static DcController makeDcc(Phone phone, DcTracker dct, - DataServiceManager dataServiceManager, Looper looper, - String tagSuffix) { - return new DcController("Dcc" + tagSuffix, phone, dct, dataServiceManager, looper); - } - - void addDc(DataConnection dc) { - synchronized (mDcListAll) { - mDcListAll.add(dc); - } - } - - void removeDc(DataConnection dc) { - synchronized (mDcListAll) { - mDcListActiveByCid.remove(dc.mCid); - mDcListAll.remove(dc); - } - synchronized (mTrafficDescriptorsByCid) { - mTrafficDescriptorsByCid.remove(dc.mCid); - } - } - - public void addActiveDcByCid(DataConnection dc) { - if (DBG && dc.mCid < 0) { - log("addActiveDcByCid dc.mCid < 0 dc=" + dc); - } - synchronized (mDcListAll) { - mDcListActiveByCid.put(dc.mCid, dc); - } - updateTrafficDescriptorsForCid(dc.mCid, dc.getTrafficDescriptors()); - } - - DataConnection getActiveDcByCid(int cid) { - synchronized (mDcListAll) { - return mDcListActiveByCid.get(cid); - } - } - - void removeActiveDcByCid(DataConnection dc) { - synchronized (mDcListAll) { - DataConnection removedDc = mDcListActiveByCid.remove(dc.mCid); - if (DBG && removedDc == null) { - log("removeActiveDcByCid removedDc=null dc=" + dc); - } - } - synchronized (mTrafficDescriptorsByCid) { - mTrafficDescriptorsByCid.remove(dc.mCid); - } - } - - boolean isDefaultDataActive() { - synchronized (mDcListAll) { - return mDcListActiveByCid.values().stream() - .anyMatch(dc -> dc.getApnContexts().stream() - .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT)); - } - } - - List getTrafficDescriptorsForCid(int cid) { - synchronized (mTrafficDescriptorsByCid) { - return mTrafficDescriptorsByCid.get(cid); - } - } - - void updateTrafficDescriptorsForCid(int cid, List tds) { - synchronized (mTrafficDescriptorsByCid) { - mTrafficDescriptorsByCid.put(cid, tds); - } - } - - @Override - public void handleMessage(Message msg) { - AsyncResult ar; - - switch (msg.what) { - case DataConnection.EVENT_DATA_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - if (ar.exception == null) { - onDataStateChanged((ArrayList) ar.result); - } else { - log("EVENT_DATA_STATE_CHANGED: exception; likely radio not available, ignore"); - } - break; - default: - loge("Unexpected event " + msg); - break; - } - } - - /** - * Process the new list of "known" Data Calls - * @param dcsList as sent by RIL_UNSOL_DATA_CALL_LIST_CHANGED - */ - private void onDataStateChanged(ArrayList dcsList) { - final HashMap dcListActiveByCid; - synchronized (mDcListAll) { - dcListActiveByCid = new HashMap<>(mDcListActiveByCid); - } - - if (DBG) { - log("onDataStateChanged: dcsList=" + dcsList - + " dcListActiveByCid=" + dcListActiveByCid); - } - - // Create hashmap of cid to DataCallResponse - HashMap dataCallResponseListByCid = new HashMap<>(); - for (DataCallResponse dcs : dcsList) { - dataCallResponseListByCid.put(dcs.getId(), dcs); - } - - // Add a DC that is active but not in the dcsList to the list of DC's to retry - ArrayList dcsToRetry = new ArrayList<>(); - for (DataConnection dc : dcListActiveByCid.values()) { - DataCallResponse response = dataCallResponseListByCid.get(dc.mCid); - if (response == null) { - if (DBG) log("onDataStateChanged: add to retry dc=" + dc); - dcsToRetry.add(dc); - } else { - List oldTds = getTrafficDescriptorsForCid(dc.mCid); - List newTds = response.getTrafficDescriptors(); - if (!oldTds.equals(newTds)) { - if (DBG) { - log("onDataStateChanged: add to retry due to TD changed dc=" + dc - + ", oldTds=" + oldTds + ", newTds=" + newTds); - } - updateTrafficDescriptorsForCid(dc.mCid, newTds); - dcsToRetry.add(dc); - } - } - } - if (DBG) log("onDataStateChanged: dcsToRetry=" + dcsToRetry); - - // Find which connections have changed state and send a notification or cleanup - // and any that are in active need to be retried. - ArrayList apnsToCleanup = new ArrayList(); - - boolean isAnyDataCallDormant = false; - boolean isAnyDataCallActive = false; - boolean isInternetDataCallActive = false; - - for (DataCallResponse newState : dcsList) { - - DataConnection dc = dcListActiveByCid.get(newState.getId()); - if (dc == null) { - // UNSOL_DATA_CALL_LIST_CHANGED arrived before SETUP_DATA_CALL completed. - loge("onDataStateChanged: no associated DC yet, ignore"); - continue; - } - - List apnContexts = dc.getApnContexts(); - if (apnContexts.size() == 0) { - if (DBG) loge("onDataStateChanged: no connected apns, ignore"); - } else { - // Determine if the connection/apnContext should be cleaned up - // or just a notification should be sent out. - if (DBG) { - log("onDataStateChanged: Found ConnId=" + newState.getId() - + " newState=" + newState.toString()); - } - if (apnContexts.stream().anyMatch( - i -> ApnSetting.TYPE_DEFAULT_STRING.equals(i.getApnType())) - && newState.getLinkStatus() == DataConnActiveStatus.ACTIVE) { - isInternetDataCallActive = true; - } - if (newState.getLinkStatus() == DataConnActiveStatus.INACTIVE) { - if (mDct.isCleanupRequired.get()) { - apnsToCleanup.addAll(apnContexts); - mDct.isCleanupRequired.set(false); - } else { - int failCause = DataFailCause.getFailCause(newState.getCause()); - if (DataFailCause.isRadioRestartFailure(mPhone.getContext(), failCause, - mPhone.getSubId())) { - if (DBG) { - log("onDataStateChanged: X restart radio, failCause=" - + failCause); - } - mDct.sendRestartRadio(); - } else if (mDct.isPermanentFailure(failCause)) { - if (DBG) { - log("onDataStateChanged: inactive, add to cleanup list. " - + "failCause=" + failCause); - } - apnsToCleanup.addAll(apnContexts); - } else { - if (DBG) { - log("onDataStateChanged: inactive, add to retry list. " - + "failCause=" + failCause); - } - dcsToRetry.add(dc); - } - } - } else { - // Update the pdu session id - dc.setPduSessionId(newState.getPduSessionId()); - - dc.updatePcscfAddr(newState); - - // Its active so update the DataConnections link properties - UpdateLinkPropertyResult result = dc.updateLinkProperty(newState); - dc.updateResponseFields(newState); - if (result.oldLp.equals(result.newLp)) { - if (DBG) log("onDataStateChanged: no change"); - } else { - if (LinkPropertiesUtils.isIdenticalInterfaceName( - result.oldLp, result.newLp)) { - if (!LinkPropertiesUtils.isIdenticalDnses( - result.oldLp, result.newLp) - || !LinkPropertiesUtils.isIdenticalRoutes( - result.oldLp, result.newLp) - || !LinkPropertiesUtils.isIdenticalHttpProxy( - result.oldLp, result.newLp) - || !LinkPropertiesUtils.isIdenticalAddresses( - result.oldLp, result.newLp)) { - // If the same address type was removed and - // added we need to cleanup - CompareOrUpdateResult car - = new CompareOrUpdateResult( - result.oldLp != null ? - result.oldLp.getLinkAddresses() : null, - result.newLp != null ? - result.newLp.getLinkAddresses() : null, - (la) -> Objects.hash(((LinkAddress)la).getAddress(), - ((LinkAddress)la).getPrefixLength(), - ((LinkAddress)la).getScope())); - if (DBG) { - log("onDataStateChanged: oldLp=" + result.oldLp - + " newLp=" + result.newLp + " car=" + car); - } - boolean needToClean = false; - for (LinkAddress added : car.added) { - for (LinkAddress removed : car.removed) { - if (NetUtils.addressTypeMatches( - removed.getAddress(), - added.getAddress())) { - needToClean = true; - break; - } - } - } - if (needToClean) { - if (DBG) { - log("onDataStateChanged: addr change," - + " cleanup apns=" + apnContexts - + " oldLp=" + result.oldLp - + " newLp=" + result.newLp); - } - apnsToCleanup.addAll(apnContexts); - } - } else { - if (DBG) { - log("onDataStateChanged: no changes"); - } - } - } else { - apnsToCleanup.addAll(apnContexts); - if (DBG) { - log("onDataStateChanged: interface change, cleanup apns=" - + apnContexts); - } - } - } - } - } - - if (newState.getLinkStatus() == DataConnActiveStatus.ACTIVE) { - isAnyDataCallActive = true; - } - if (newState.getLinkStatus() == DataConnActiveStatus.DORMANT) { - isAnyDataCallDormant = true; - } - } - - if (mDataServiceManager.getTransportType() - == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - boolean isPhysicalLinkStatusFocusingOnInternetData = - mDct.getLteEndcUsingUserDataForIdleDetection(); - int physicalLinkStatus = - (isPhysicalLinkStatusFocusingOnInternetData - ? isInternetDataCallActive : isAnyDataCallActive) - ? DataCallResponse.LINK_STATUS_ACTIVE - : DataCallResponse.LINK_STATUS_DORMANT; - if (mPhysicalLinkStatus != physicalLinkStatus) { - mPhysicalLinkStatus = physicalLinkStatus; - mPhysicalLinkStatusChangedRegistrants.notifyResult(mPhysicalLinkStatus); - } - if (isAnyDataCallDormant && !isAnyDataCallActive) { - // There is no way to indicate link activity per APN right now. So - // Link Activity will be considered dormant only when all data calls - // are dormant. - // If a single data call is in dormant state and none of the data - // calls are active broadcast overall link status as dormant. - if (DBG) { - log("onDataStateChanged: Data activity DORMANT. stopNetStatePoll"); - } - mDct.sendStopNetStatPoll(DctConstants.Activity.DORMANT); - } else { - if (DBG) { - log("onDataStateChanged: Data Activity updated to NONE. " - + "isAnyDataCallActive = " + isAnyDataCallActive - + " isAnyDataCallDormant = " + isAnyDataCallDormant); - } - if (isAnyDataCallActive) { - mDct.sendStartNetStatPoll(DctConstants.Activity.NONE); - } - } - } - - if (DBG) { - log("onDataStateChanged: dcsToRetry=" + dcsToRetry - + " apnsToCleanup=" + apnsToCleanup); - } - - // Cleanup connections that have changed - for (ApnContext apnContext : apnsToCleanup) { - mDct.cleanUpConnection(apnContext); - } - - // Retry connections that have disappeared - for (DataConnection dc : dcsToRetry) { - if (DBG) log("onDataStateChanged: send EVENT_LOST_CONNECTION dc.mTag=" + dc.mTag); - dc.sendMessage(DataConnection.EVENT_LOST_CONNECTION, dc.mTag); - } - - if (VDBG) log("onDataStateChanged: X"); - } - - /** - * Register for physical link status (i.e. RRC state) changed event. - * if {@link CarrierConfigManager#KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL} is true, - * then physical link status is focusing on "internet data connection" instead of RRC state. - * @param h The handler - * @param what The event - */ - @VisibleForTesting - public void registerForPhysicalLinkStatusChanged(Handler h, int what) { - mPhysicalLinkStatusChangedRegistrants.addUnique(h, what, null); - } - - /** - * Unregister from physical link status (i.e. RRC state) changed event. - * - * @param h The previously registered handler - */ - void unregisterForPhysicalLinkStatusChanged(Handler h) { - mPhysicalLinkStatusChangedRegistrants.remove(h); - } - - private void log(String s) { - Rlog.d(mTag, s); - } - - private void loge(String s) { - Rlog.e(mTag, s); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - synchronized (mDcListAll) { - sb.append("mDcListAll=").append(mDcListAll) - .append(" mDcListActiveByCid=").append(mDcListActiveByCid); - } - synchronized (mTrafficDescriptorsByCid) { - sb.append("mTrafficDescriptorsByCid=").append(mTrafficDescriptorsByCid); - } - return sb.toString(); - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println(" mPhone=" + mPhone); - synchronized (mDcListAll) { - pw.println(" mDcListAll=" + mDcListAll); - pw.println(" mDcListActiveByCid=" + mDcListActiveByCid); - } - synchronized (mTrafficDescriptorsByCid) { - pw.println(" mTrafficDescriptorsByCid=" + mTrafficDescriptorsByCid); - } - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java b/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java deleted file mode 100644 index 3cdd2090d5..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2013 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.dataconnection; - -import android.content.Intent; -import android.telephony.Annotation.DataFailureCause; -import android.telephony.DataFailCause; - -import com.android.telephony.Rlog; - -/** - * A package visible class for supporting testing failing bringUp commands. This - * saves the parameters from a action_fail_bringup intent. See - * {@link DataConnection#doOnConnect} and {@see DcTesterFailBringUpAll} for more info. - */ -public class DcFailBringUp { - private static final String LOG_TAG = "DcFailBringUp"; - private static final boolean DBG = true; - - static final String INTENT_BASE = DataConnection.class.getPackage().getName(); - - static final String ACTION_FAIL_BRINGUP = "action_fail_bringup"; - - // counter with its --ei option name and default value - static final String COUNTER = "counter"; - static final int DEFAULT_COUNTER = 2; - int mCounter; - - // failCause with its --ei option name and default value - static final String FAIL_CAUSE = "fail_cause"; - static final int DEFAULT_FAIL_CAUSE = DataFailCause.ERROR_UNSPECIFIED; - @DataFailureCause - int mFailCause; - - // suggestedRetryTime with its --ei option name and default value - static final String SUGGESTED_RETRY_TIME = "suggested_retry_time"; - static final long DEFAULT_SUGGESTED_RETRY_TIME = -1; - long mSuggestedRetryTime; - - // Get the Extra Intent parameters - void saveParameters(Intent intent, String s) { - if (DBG) log(s + ".saveParameters: action=" + intent.getAction()); - mCounter = intent.getIntExtra(COUNTER, DEFAULT_COUNTER); - mFailCause = DataFailCause.getFailCause( - intent.getIntExtra(FAIL_CAUSE, DEFAULT_FAIL_CAUSE)); - mSuggestedRetryTime = - intent.getLongExtra(SUGGESTED_RETRY_TIME, DEFAULT_SUGGESTED_RETRY_TIME); - if (DBG) { - log(s + ".saveParameters: " + this); - } - } - - public void saveParameters(int counter, @DataFailureCause int failCause, - long suggestedRetryTime) { - mCounter = counter; - mFailCause = DataFailCause.getFailCause(failCause); - mSuggestedRetryTime = suggestedRetryTime; - } - - @Override - public String toString() { - return "{mCounter=" + mCounter + - " mFailCause=" + mFailCause + - " mSuggestedRetryTime=" + mSuggestedRetryTime + "}"; - - } - - private static void log(String s) { - Rlog.d(LOG_TAG, s); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java deleted file mode 100644 index c6def34093..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java +++ /dev/null @@ -1,617 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.KeepalivePacketData; -import android.net.LinkProperties; -import android.net.NattKeepalivePacketData; -import android.net.NetworkAgent; -import android.net.NetworkAgentConfig; -import android.net.NetworkCapabilities; -import android.net.NetworkProvider; -import android.net.QosFilter; -import android.net.QosSessionAttributes; -import android.net.SocketKeepalive; -import android.net.Uri; -import android.os.Handler; -import android.os.Message; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.TransportType; -import android.telephony.Annotation.NetworkType; -import android.telephony.AnomalyReporter; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.ServiceState; -import android.telephony.TelephonyManager; -import android.telephony.data.QosBearerSession; -import android.util.LocalLog; -import android.util.SparseArray; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.SlidingWindowEventCounter; -import com.android.internal.telephony.data.KeepaliveStatus; -import com.android.internal.telephony.data.NotifyQosSessionInterface; -import com.android.internal.telephony.data.QosCallbackTracker; -import com.android.internal.telephony.metrics.TelephonyMetrics; -import com.android.internal.util.IndentingPrintWriter; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.time.Duration; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -/** - * This class represents a network agent which is communication channel between - * {@link DataConnection} and {@link com.android.server.ConnectivityService}. The agent is - * created when data connection enters {@link DataConnection.DcActiveState} until it exits that - * state. - * - * Note that in IWLAN handover scenario, this agent could be transferred to the new - * {@link DataConnection} so for a short window of time this object might be accessed by two - * different {@link DataConnection}. Thus each method in this class needs to be synchronized. - */ -public class DcNetworkAgent extends NetworkAgent implements NotifyQosSessionInterface { - private final String mTag; - - private final int mId; - - private final Phone mPhone; - - private final Handler mHandler; - - private int mTransportType; - - private NetworkCapabilities mNetworkCapabilities; - - public final DcKeepaliveTracker keepaliveTracker = new DcKeepaliveTracker(); - - private final QosCallbackTracker mQosCallbackTracker; - - private final Executor mQosCallbackExecutor = Executors.newSingleThreadExecutor(); - - private DataConnection mDataConnection; - - private final LocalLog mNetCapsLocalLog = new LocalLog(32); - - // For interface duplicate detection. Key is the net id, value is the interface name in string. - private static Map sInterfaceNames = new ConcurrentHashMap<>(); - - private static final long NETWORK_UNWANTED_ANOMALY_WINDOW_MS = TimeUnit.MINUTES.toMillis(5); - private static final int NETWORK_UNWANTED_ANOMALY_NUM_OCCURRENCES = 12; - - private static final int EVENT_UNWANTED_TIMEOUT = 1; - - @VisibleForTesting - public DcNetworkAgent(DataConnection dc, Phone phone, int score, NetworkAgentConfig config, - NetworkProvider networkProvider, int transportType) { - super(phone.getContext(), dc.getHandler().getLooper(), "DcNetworkAgent", - dc.getNetworkCapabilities(), dc.getLinkProperties(), score, config, - networkProvider); - register(); - mId = getNetwork().getNetId(); - mTag = "DcNetworkAgent" + "-" + mId; - mPhone = phone; - mHandler = new Handler(dc.getHandler().getLooper()) { - @Override - public void handleMessage(Message msg) { - if (msg.what == EVENT_UNWANTED_TIMEOUT) { - loge("onNetworkUnwanted timed out. Perform silent de-register."); - logd("Unregister from connectivity service. " + sInterfaceNames.get(mId) - + " removed."); - sInterfaceNames.remove(mId); - DcNetworkAgent.this.unregister(); - } - } - }; - mNetworkCapabilities = dc.getNetworkCapabilities(); - mTransportType = transportType; - mDataConnection = dc; - if (dc.getLinkProperties() != null) { - checkDuplicateInterface(mId, dc.getLinkProperties().getInterfaceName()); - logd("created for data connection " + dc.getName() + ", " - + dc.getLinkProperties().getInterfaceName()); - } else { - loge("The connection does not have a valid link properties."); - } - mQosCallbackTracker = new QosCallbackTracker(this, mPhone); - } - - private @NetworkType int getNetworkType() { - ServiceState ss = mPhone.getServiceState(); - int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - - NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, mTransportType); - if (nri != null) { - networkType = nri.getAccessNetworkTechnology(); - } - - return networkType; - } - - private void checkDuplicateInterface(int netId, @Nullable String interfaceName) { - for (Map.Entry entry: sInterfaceNames.entrySet()) { - if (Objects.equals(interfaceName, entry.getValue())) { - String message = "Duplicate interface " + interfaceName - + " is detected. DcNetworkAgent-" + entry.getKey() - + " already used this interface name."; - loge(message); - // Using fixed UUID to avoid duplicate bugreport notification - AnomalyReporter.reportAnomaly( - UUID.fromString("02f3d3f6-4613-4415-b6cb-8d92c8a938a6"), - message, mPhone.getCarrierId()); - return; - } - } - sInterfaceNames.put(netId, interfaceName); - } - - /** - * @return The tag - */ - String getTag() { - return mTag; - } - - /** - * Set the data connection that owns this network agent. - * - * @param dc Data connection owning this network agent. - * @param transportType Transport that this data connection is on. - */ - public synchronized void acquireOwnership(@NonNull DataConnection dc, - @TransportType int transportType) { - mDataConnection = dc; - mTransportType = transportType; - logd(dc.getName() + " acquired the ownership of this agent."); - } - - /** - * Release the ownership of network agent. - */ - public synchronized void releaseOwnership(DataConnection dc) { - if (mDataConnection == null) { - loge("releaseOwnership called on no-owner DcNetworkAgent!"); - return; - } else if (mDataConnection != dc) { - loge("releaseOwnership: This agent belongs to " - + mDataConnection.getName() + ", ignored the request from " + dc.getName()); - return; - } - logd("Data connection " + mDataConnection.getName() + " released the ownership."); - mDataConnection = null; - } - - /** - * @return The data connection that owns this agent - */ - public synchronized DataConnection getDataConnection() { - return mDataConnection; - } - - private static final SlidingWindowEventCounter sNetworkUnwantedCounter = - new SlidingWindowEventCounter(NETWORK_UNWANTED_ANOMALY_WINDOW_MS, - NETWORK_UNWANTED_ANOMALY_NUM_OCCURRENCES); - - @Override - public synchronized void onNetworkUnwanted() { - mHandler.sendEmptyMessageDelayed(EVENT_UNWANTED_TIMEOUT, TimeUnit.SECONDS.toMillis(30)); - trackNetworkUnwanted(); - if (mDataConnection == null) { - loge("onNetworkUnwanted found called on no-owner DcNetworkAgent!"); - return; - } - - logd("onNetworkUnwanted called. Now tear down the data connection " - + mDataConnection.getName()); - mDataConnection.tearDownAll(Phone.REASON_RELEASED_BY_CONNECTIVITY_SERVICE, - DcTracker.RELEASE_TYPE_DETACH, null); - } - - /** - * There have been several bugs where a RECONNECT loop kicks off where a DataConnection - * connects to the Network, ConnectivityService indicates that the Network is unwanted, - * and then the DataConnection reconnects. By the time we get the bug report it's too late - * because there have already been hundreds of RECONNECTS. This is meant to capture the issue - * when it first starts. - * - * The unwanted counter is configured to only take an anomaly report in extreme cases. - * This is to avoid having the anomaly message show up on several devices. - * - * This is directly related to b/175845538. But, there have been several other occurrences of - * this issue. - */ - private void trackNetworkUnwanted() { - if (sNetworkUnwantedCounter.addOccurrence()) { - AnomalyReporter.reportAnomaly( - UUID.fromString("3f578b5c-64e9-11eb-ae93-0242ac130002"), - "Network Unwanted called 12 times in 5 minutes.", mPhone.getCarrierId()); - } - } - - @Override - public synchronized void onBandwidthUpdateRequested() { - if (mDataConnection == null) { - loge("onBandwidthUpdateRequested called on no-owner DcNetworkAgent!"); - return; - } - - if (mPhone.getLceStatus() == RILConstants.LCE_ACTIVE // active LCE service - && mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.pullLceData(mDataConnection.obtainMessage( - DataConnection.EVENT_BW_REFRESH_RESPONSE)); - } - } - - @Override - public synchronized void onValidationStatus(int status, Uri redirectUri) { - if (mDataConnection == null) { - loge("onValidationStatus called on no-owner DcNetworkAgent!"); - return; - } - - logd("validation status: " + status + " with redirection URL: " + redirectUri); - DcTracker dct = mPhone.getDcTracker(mTransportType); - if (dct != null) { - Message msg = dct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - status, mDataConnection.getCid(), redirectUri.toString()); - msg.sendToTarget(); - } - } - - private synchronized boolean isOwned(DataConnection dc, String reason) { - if (mDataConnection == null) { - loge(reason + " called on no-owner DcNetworkAgent!"); - return false; - } else if (mDataConnection != dc) { - loge(reason + ": This agent belongs to " - + mDataConnection.getName() + ", ignored the request from " + dc.getName()); - return false; - } - return true; - } - - /** - * Update the legacy sub type (i.e. data network type). - * - * @param dc The data connection that invokes this method. - */ - public synchronized void updateLegacySubtype(DataConnection dc) { - if (!isOwned(dc, "updateLegacySubtype")) return; - - int networkType = getNetworkType(); - setLegacySubtype(networkType, TelephonyManager.getNetworkTypeName(networkType)); - } - - /** - * Set the network capabilities. - * - * @param networkCapabilities The network capabilities. - * @param dc The data connection that invokes this method. - */ - public synchronized void sendNetworkCapabilities(NetworkCapabilities networkCapabilities, - DataConnection dc) { - if (!isOwned(dc, "sendNetworkCapabilities")) return; - - if (!networkCapabilities.equals(mNetworkCapabilities)) { - String logStr = "Changed from " + mNetworkCapabilities + " to " - + networkCapabilities + ", Data RAT=" - + mPhone.getServiceState().getRilDataRadioTechnology() - + ", dc=" + mDataConnection.getName(); - logd(logStr); - mNetCapsLocalLog.log(logStr); - if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { - // only log metrics for DataConnection with NET_CAPABILITY_INTERNET - if (mNetworkCapabilities == null - || networkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) - != mNetworkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)) { - TelephonyMetrics.getInstance().writeNetworkCapabilitiesChangedEvent( - mPhone.getPhoneId(), networkCapabilities); - } - } - mNetworkCapabilities = networkCapabilities; - } - sendNetworkCapabilities(networkCapabilities); - } - - /** - * Set the link properties - * - * @param linkProperties The link properties - * @param dc The data connection that invokes this method. - */ - public synchronized void sendLinkProperties(@NonNull LinkProperties linkProperties, - DataConnection dc) { - if (!isOwned(dc, "sendLinkProperties")) return; - - sInterfaceNames.put(mId, dc.getLinkProperties().getInterfaceName()); - sendLinkProperties(linkProperties); - } - - /** - * Set the network score. - * - * @param score The network score. - * @param dc The data connection that invokes this method. - */ - public synchronized void sendNetworkScore(int score, DataConnection dc) { - if (!isOwned(dc, "sendNetworkScore")) return; - sendNetworkScore(score); - } - - /** - * Unregister the network agent from connectivity service. - * - * @param dc The data connection that invokes this method. - */ - public synchronized void unregister(DataConnection dc) { - if (!isOwned(dc, "unregister")) return; - - mHandler.removeMessages(EVENT_UNWANTED_TIMEOUT); - logd("Unregister from connectivity service. " + sInterfaceNames.get(mId) + " removed."); - sInterfaceNames.remove(mId); - super.unregister(); - } - - @Override - public synchronized void onStartSocketKeepalive(int slot, @NonNull Duration interval, - @NonNull KeepalivePacketData packet) { - if (mDataConnection == null) { - loge("onStartSocketKeepalive called on no-owner DcNetworkAgent!"); - return; - } - - if (packet instanceof NattKeepalivePacketData) { - mDataConnection.obtainMessage(DataConnection.EVENT_KEEPALIVE_START_REQUEST, - slot, (int) interval.getSeconds(), packet).sendToTarget(); - } else { - sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED); - } - } - - @Override - public synchronized void onStopSocketKeepalive(int slot) { - if (mDataConnection == null) { - loge("onStopSocketKeepalive called on no-owner DcNetworkAgent!"); - return; - } - - mDataConnection.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slot) - .sendToTarget(); - } - - @Override - public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) { - mQosCallbackExecutor.execute(() -> mQosCallbackTracker.addFilter(qosCallbackId, - new QosCallbackTracker.IFilter() { - @Override - public boolean matchesLocalAddress( - InetAddress address, int startPort, int endPort) { - return filter.matchesLocalAddress(address, startPort, endPort); - } - - @Override - public boolean matchesRemoteAddress( - InetAddress address, int startPort, int endPort) { - return filter.matchesRemoteAddress(address, startPort, endPort); - } - })); - } - - @Override - public void onQosCallbackUnregistered(final int qosCallbackId) { - mQosCallbackExecutor.execute(() -> mQosCallbackTracker.removeFilter(qosCallbackId)); - } - - void updateQosBearerSessions(final List qosBearerSessions) { - mQosCallbackExecutor.execute(() -> mQosCallbackTracker.updateSessions(qosBearerSessions)); - } - - @Override - public void notifyQosSessionAvailable(final int qosCallbackId, final int sessionId, - @NonNull final QosSessionAttributes attributes) { - super.sendQosSessionAvailable(qosCallbackId, sessionId, attributes); - } - - @Override - public void notifyQosSessionLost(final int qosCallbackId, - final int sessionId, final int qosSessionType) { - super.sendQosSessionLost(qosCallbackId, sessionId, qosSessionType); - } - - @Override - public String toString() { - return "DcNetworkAgent-" - + mId - + " mDataConnection=" - + ((mDataConnection != null) ? mDataConnection.getName() : null) - + " mTransportType=" - + AccessNetworkConstants.transportTypeToString(mTransportType) - + " " + ((mDataConnection != null) ? mDataConnection.getLinkProperties() : null) - + " mNetworkCapabilities=" + mNetworkCapabilities; - } - - /** - * Dump the state of transport manager - * - * @param fd File descriptor - * @param printWriter Print writer - * @param args Arguments - */ - public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { - IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); - pw.println(toString()); - pw.increaseIndent(); - pw.println("Net caps logs:"); - mNetCapsLocalLog.dump(fd, pw, args); - pw.decreaseIndent(); - } - - /** - * Log with debug level - * - * @param s is string log - */ - private void logd(String s) { - Rlog.d(mTag, s); - } - - /** - * Log with error level - * - * @param s is string log - */ - private void loge(String s) { - Rlog.e(mTag, s); - } - - class DcKeepaliveTracker { - private class KeepaliveRecord { - public int slotId; - public int currentStatus; - - KeepaliveRecord(int slotId, int status) { - this.slotId = slotId; - this.currentStatus = status; - } - } - - private final SparseArray mKeepalives = new SparseArray(); - - int getHandleForSlot(int slotId) { - for (int i = 0; i < mKeepalives.size(); i++) { - KeepaliveRecord kr = mKeepalives.valueAt(i); - if (kr.slotId == slotId) return mKeepalives.keyAt(i); - } - return -1; - } - - 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; - } - } - - void handleKeepaliveStarted(final int slot, KeepaliveStatus ks) { - switch (ks.statusCode) { - case KeepaliveStatus.STATUS_INACTIVE: - DcNetworkAgent.this.sendSocketKeepaliveEvent(slot, - keepaliveStatusErrorToPacketKeepaliveError(ks.errorCode)); - break; - case KeepaliveStatus.STATUS_ACTIVE: - DcNetworkAgent.this.sendSocketKeepaliveEvent( - slot, SocketKeepalive.SUCCESS); - // fall through to add record - case KeepaliveStatus.STATUS_PENDING: - logd("Adding keepalive handle=" - + ks.sessionHandle + " slot = " + slot); - mKeepalives.put(ks.sessionHandle, - new KeepaliveRecord( - slot, ks.statusCode)); - break; - default: - logd("Invalid KeepaliveStatus Code: " + ks.statusCode); - break; - } - } - - void handleKeepaliveStatus(KeepaliveStatus ks) { - final KeepaliveRecord kr; - kr = mKeepalives.get(ks.sessionHandle); - - if (kr == null) { - // If there is no slot for the session handle, we received an event - // for a different data connection. This is not an error because the - // keepalive session events are broadcast to all listeners. - loge("Discarding keepalive event for different data connection:" + ks); - return; - } - // Switch on the current state, to see what we do with the status update - switch (kr.currentStatus) { - case KeepaliveStatus.STATUS_INACTIVE: - logd("Inactive Keepalive received status!"); - DcNetworkAgent.this.sendSocketKeepaliveEvent( - kr.slotId, SocketKeepalive.ERROR_HARDWARE_ERROR); - break; - case KeepaliveStatus.STATUS_PENDING: - switch (ks.statusCode) { - case KeepaliveStatus.STATUS_INACTIVE: - DcNetworkAgent.this.sendSocketKeepaliveEvent(kr.slotId, - keepaliveStatusErrorToPacketKeepaliveError(ks.errorCode)); - kr.currentStatus = KeepaliveStatus.STATUS_INACTIVE; - mKeepalives.remove(ks.sessionHandle); - break; - case KeepaliveStatus.STATUS_ACTIVE: - logd("Pending Keepalive received active status!"); - kr.currentStatus = KeepaliveStatus.STATUS_ACTIVE; - DcNetworkAgent.this.sendSocketKeepaliveEvent( - kr.slotId, SocketKeepalive.SUCCESS); - break; - case KeepaliveStatus.STATUS_PENDING: - loge("Invalid unsolicied Keepalive Pending Status!"); - break; - default: - loge("Invalid Keepalive Status received, " + ks.statusCode); - } - break; - case KeepaliveStatus.STATUS_ACTIVE: - switch (ks.statusCode) { - case KeepaliveStatus.STATUS_INACTIVE: - logd("Keepalive received stopped status!"); - DcNetworkAgent.this.sendSocketKeepaliveEvent( - kr.slotId, SocketKeepalive.SUCCESS); - - kr.currentStatus = KeepaliveStatus.STATUS_INACTIVE; - mKeepalives.remove(ks.sessionHandle); - break; - case KeepaliveStatus.STATUS_PENDING: - case KeepaliveStatus.STATUS_ACTIVE: - loge("Active Keepalive received invalid status!"); - break; - default: - loge("Invalid Keepalive Status received, " + ks.statusCode); - } - break; - default: - loge("Invalid Keepalive Status received, " + kr.currentStatus); - } - } - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcRequest.java b/src/java/com/android/internal/telephony/dataconnection/DcRequest.java deleted file mode 100644 index da775e82f5..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcRequest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2006 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.dataconnection; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.NetworkRequest; -import android.net.NetworkSpecifier; -import android.net.TelephonyNetworkSpecifier; -import android.telephony.Annotation.ApnType; - -import com.android.telephony.Rlog; - -/** - * Wraps cellular network requests to configured apn types. - */ -public class DcRequest implements Comparable { - private static final String LOG_TAG = "DcRequest"; - - @NonNull - public final NetworkRequest networkRequest; - public final int priority; - public final @ApnType int apnType; - - private DcRequest(@NonNull final NetworkRequest nr, @ApnType final int type, - int apnPriority) { - networkRequest = nr; - priority = apnPriority; - apnType = type; - } - - /** - * Create a DcRequest based off of the network request. If the network request is not cellular, - * then null is returned and a warning is generated. - * @param networkRequest sets the type of dc request - * @param apnConfigTypeRepository apn config types to match on the network request - * @return corresponding DcRequest - * - */ - @Nullable - public static DcRequest create(@NonNull final NetworkRequest networkRequest, - @NonNull final ApnConfigTypeRepository apnConfigTypeRepository) { - final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest); - final ApnConfigType apnConfigType = apnConfigTypeRepository.getByType(apnType); - if (apnConfigType == null) { - Rlog.d(LOG_TAG, "Non cellular request ignored: " + networkRequest.toString()); - checkForAnomalousNetworkRequest(networkRequest); - return null; - } else { - Rlog.d(LOG_TAG, "Cellular request confirmed: " + networkRequest.toString()); - return new DcRequest(networkRequest, apnType, apnConfigType.getPriority()); - } - } - - private static void checkForAnomalousNetworkRequest(NetworkRequest networkRequest) { - NetworkSpecifier specifier = networkRequest.getNetworkSpecifier(); - if (specifier != null) { - if (specifier instanceof TelephonyNetworkSpecifier) { - reportAnomalousNetworkRequest(networkRequest); - } - } - } - - private static void reportAnomalousNetworkRequest(NetworkRequest networkRequest) { - //TODO: Report anomaly if this happens - Rlog.w(LOG_TAG, "A TelephonyNetworkSpecifier for a non-cellular request is invalid: " - + networkRequest.toString()); - - } - - public String toString() { - return networkRequest.toString() + ", priority=" + priority + ", apnType=" + apnType; - } - - public int hashCode() { - return networkRequest.hashCode(); - } - - public boolean equals(Object o) { - if (o instanceof DcRequest) { - return networkRequest.equals(((DcRequest)o).networkRequest); - } - return false; - } - - public int compareTo(DcRequest o) { - return o.priority - priority; - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java deleted file mode 100644 index 11a0ae67e0..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2013 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.dataconnection; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.telephony.Rlog; - -/** - * To bring down all DC's send the following intent: - * - * adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_deactivate_all - */ -public class DcTesterDeactivateAll { - private static final String LOG_TAG = "DcTesterDeacativateAll"; - private static final boolean DBG = true; - - private Phone mPhone; - private DcController mDcc; - - public static String sActionDcTesterDeactivateAll = - "com.android.internal.telephony.dataconnection.action_deactivate_all"; - - - // The static intent receiver one for all instances and we assume this - // is running on the same thread as Dcc. - protected BroadcastReceiver sIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (DBG) log("sIntentReceiver.onReceive: action=" + action); - if (action.equals(sActionDcTesterDeactivateAll) - || action.equals(mPhone.getActionDetached())) { - log("Send DEACTIVATE to all Dcc's"); - if (mDcc != null) { - for (DataConnection dc : mDcc.mDcListAll) { - dc.tearDownNow(); - } - } else { - if (DBG) log("onReceive: mDcc is null, ignoring"); - } - } else { - if (DBG) log("onReceive: unknown action=" + action); - } - } - }; - - DcTesterDeactivateAll(Phone phone, DcController dcc, Handler handler) { - mPhone = phone; - mDcc = dcc; - - if (TelephonyUtils.IS_DEBUGGABLE) { - IntentFilter filter = new IntentFilter(); - - filter.addAction(sActionDcTesterDeactivateAll); - log("register for intent action=" + sActionDcTesterDeactivateAll); - - filter.addAction(mPhone.getActionDetached()); - log("register for intent action=" + mPhone.getActionDetached()); - - phone.getContext().registerReceiver(sIntentReceiver, filter, null, handler, - Context.RECEIVER_EXPORTED); - } - } - - void dispose() { - if (TelephonyUtils.IS_DEBUGGABLE) { - mPhone.getContext().unregisterReceiver(sIntentReceiver); - } - } - - private static void log(String s) { - Rlog.d(LOG_TAG, s); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java deleted file mode 100644 index 788da297eb..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2013 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.dataconnection; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import android.telephony.DataFailCause; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.telephony.Rlog; - -/** - * A package level call that causes all DataConnection bringUp calls to fail a specific - * number of times. Here is an example that sets counter to 2 and cause to -3 for all instances: - * adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_fail_bringup \ - * --ei counter 2 --ei fail_cause -3 - * - * Also you can add a suggested retry time if desired: - * --ei suggested_retry_time 5000 - * - * The fail_cause is one of {@link DataFailCause} - */ -public class DcTesterFailBringUpAll { - private static final String LOG_TAG = "DcTesterFailBrinupAll"; - private static final boolean DBG = true; - - private Phone mPhone; - - private String mActionFailBringUp = DcFailBringUp.INTENT_BASE + "." - + DcFailBringUp.ACTION_FAIL_BRINGUP; - - // The saved FailBringUp data from the intent - private DcFailBringUp mFailBringUp = new DcFailBringUp(); - - // The static intent receiver one for all instances. - private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (DBG) log("sIntentReceiver.onReceive: action=" + action); - if (action.equals(mActionFailBringUp)) { - mFailBringUp.saveParameters(intent, "sFailBringUp"); - } else if (action.equals(mPhone.getActionDetached())) { - // Counter is MAX, bringUp/retry will always fail - log("simulate detaching"); - mFailBringUp.saveParameters(Integer.MAX_VALUE, - DataFailCause.LOST_CONNECTION, - DcFailBringUp.DEFAULT_SUGGESTED_RETRY_TIME); - } else if (action.equals(mPhone.getActionAttached())) { - // Counter is 0 next bringUp/retry will succeed - log("simulate attaching"); - mFailBringUp.saveParameters(0, DataFailCause.NONE, - DcFailBringUp.DEFAULT_SUGGESTED_RETRY_TIME); - } else { - if (DBG) log("onReceive: unknown action=" + action); - } - } - }; - - DcTesterFailBringUpAll(Phone phone, Handler handler) { - mPhone = phone; - if (TelephonyUtils.IS_DEBUGGABLE) { - IntentFilter filter = new IntentFilter(); - - filter.addAction(mActionFailBringUp); - log("register for intent action=" + mActionFailBringUp); - - filter.addAction(mPhone.getActionDetached()); - log("register for intent action=" + mPhone.getActionDetached()); - - filter.addAction(mPhone.getActionAttached()); - log("register for intent action=" + mPhone.getActionAttached()); - - phone.getContext().registerReceiver(mIntentReceiver, filter, null, handler, - Context.RECEIVER_EXPORTED); - } - } - - void dispose() { - if (TelephonyUtils.IS_DEBUGGABLE) { - mPhone.getContext().unregisterReceiver(mIntentReceiver); - } - } - - public DcFailBringUp getDcFailBringUp() { - return mFailBringUp; - } - - private void log(String s) { - Rlog.d(LOG_TAG, s); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java deleted file mode 100755 index 28f69dcdc9..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java +++ /dev/null @@ -1,5665 +0,0 @@ -/* - * Copyright (C) 2006 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.dataconnection; - -import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; -import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED; -import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; -import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; -import static android.telephony.TelephonyManager.NETWORK_TYPE_NR; -import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_DO_FALLBACK; -import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY; -import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL; - -import static com.android.internal.telephony.RILConstants.DATA_PROFILE_DEFAULT; -import static com.android.internal.telephony.RILConstants.DATA_PROFILE_INVALID; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.AlarmManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.ProgressDialog; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.database.ContentObserver; -import android.database.Cursor; -import android.net.ConnectivityManager; -import android.net.LinkProperties; -import android.net.NetworkAgent; -import android.net.NetworkCapabilities; -import android.net.NetworkPolicyManager; -import android.net.NetworkRequest; -import android.net.TrafficStats; -import android.net.Uri; -import android.os.AsyncResult; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Message; -import android.os.PersistableBundle; -import android.os.RegistrantList; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.preference.PreferenceManager; -import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; -import android.provider.Telephony; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.TransportType; -import android.telephony.Annotation.ApnType; -import android.telephony.Annotation.DataFailureCause; -import android.telephony.Annotation.NetworkType; -import android.telephony.CarrierConfigManager; -import android.telephony.CellLocation; -import android.telephony.DataFailCause; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.PcoData; -import android.telephony.PreciseDataConnectionState; -import android.telephony.ServiceState; -import android.telephony.ServiceState.RilRadioTechnology; -import android.telephony.SubscriptionManager; -import android.telephony.SubscriptionPlan; -import android.telephony.TelephonyDisplayInfo; -import android.telephony.TelephonyFrameworkInitializer; -import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.SimState; -import android.telephony.cdma.CdmaCellLocation; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.telephony.data.DataCallResponse.HandoverFailureMode; -import android.telephony.data.DataProfile; -import android.telephony.data.ThrottleStatus; -import android.telephony.gsm.GsmCellLocation; -import android.text.TextUtils; -import android.util.EventLog; -import android.util.LocalLog; -import android.util.Log; -import android.util.Pair; -import android.util.SparseArray; -import android.view.WindowManager; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.EventLogTags; -import com.android.internal.telephony.GsmCdmaPhone; -import com.android.internal.telephony.ITelephony; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.SettingsObserver; -import com.android.internal.telephony.SubscriptionInfoUpdater; -import com.android.internal.telephony.data.DataConfigManager; -import com.android.internal.telephony.data.PhoneSwitcher; -import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataAllowedReasonType; -import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType; -import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason; -import com.android.internal.telephony.metrics.DataStallRecoveryStats; -import com.android.internal.telephony.metrics.TelephonyMetrics; -import com.android.internal.telephony.util.ArrayUtils; -import com.android.internal.telephony.util.NotificationChannelController; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.internal.util.AsyncChannel; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -/** - * {@hide} - */ -public class DcTracker extends Handler { - protected static final boolean DBG = true; - private static final boolean VDBG = false; // STOPSHIP if true - private static final boolean VDBG_STALL = false; // STOPSHIP if true - private static final boolean RADIO_TESTS = false; - private static final String NOTIFICATION_TAG = DcTracker.class.getSimpleName(); - - @IntDef(value = { - REQUEST_TYPE_NORMAL, - REQUEST_TYPE_HANDOVER, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface RequestNetworkType {} - - /** - * Normal request for {@link #requestNetwork(NetworkRequest, int, Message)}. For request - * network, this adds the request to the {@link ApnContext}. If there were no network request - * attached to the {@link ApnContext} earlier, this request setups a data connection. - */ - public static final int REQUEST_TYPE_NORMAL = 1; - - /** - * Handover request for {@link #requestNetwork(NetworkRequest, int, Message)} or - * {@link #releaseNetwork(NetworkRequest, int)}. For request network, this - * initiates the handover data setup process. The existing data connection will be seamlessly - * handover to the new network. For release network, this performs a data connection softly - * clean up at the underlying layer (versus normal data release). - */ - public static final int REQUEST_TYPE_HANDOVER = 2; - - @IntDef(value = { - RELEASE_TYPE_NORMAL, - RELEASE_TYPE_DETACH, - RELEASE_TYPE_HANDOVER, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ReleaseNetworkType {} - - /** - * For release network, this is just removing the network request from the {@link ApnContext}. - * Note this does not tear down the physical data connection. Normally the data connection is - * torn down by connectivity service directly calling {@link NetworkAgent#unwanted()}. - */ - public static final int RELEASE_TYPE_NORMAL = 1; - - /** - * Detach request for {@link #releaseNetwork(NetworkRequest, int)} only. This - * forces the APN context detach from the data connection. If this {@link ApnContext} is the - * last one attached to the data connection, the data connection will be torn down, otherwise - * the data connection remains active. - */ - public static final int RELEASE_TYPE_DETACH = 2; - - /** - * Handover request for {@link #releaseNetwork(NetworkRequest, int)}. For release - * network, this performs a data connection softly clean up at the underlying layer (versus - * normal data release). - */ - public static final int RELEASE_TYPE_HANDOVER = 3; - - /** The extras for handover completion message */ - public static final String DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST = "extra_network_request"; - public static final String DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE = "extra_transport_type"; - public static final String DATA_COMPLETE_MSG_EXTRA_SUCCESS = "extra_success"; - /** - * The flag indicates whether after handover failure, the data connection should remain on the - * original transport. - */ - public static final String DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK = - "extra_handover_failure_fallback"; - - private final String mLogTag; - - public AtomicBoolean isCleanupRequired = new AtomicBoolean(false); - - private final TelephonyManager mTelephonyManager; - - private final AlarmManager mAlarmManager; - - /* Currently requested APN type (TODO: This should probably be a parameter not a member) */ - private int mRequestedApnType = ApnSetting.TYPE_DEFAULT; - - // All data enabling/disabling related settings - private final DataEnabledSettings mDataEnabledSettings; - - /** - * After detecting a potential connection problem, this is the max number - * of subsequent polls before attempting recovery. - */ - // 1 sec. default polling interval when screen is on. - private static final int POLL_NETSTAT_MILLIS = 1000; - // 10 min. default polling interval when screen is off. - private static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; - // Default sent packets without ack which triggers initial recovery steps - private static final int NUMBER_SENT_PACKETS_OF_HANG = 10; - - // Default for the data stall alarm while non-aggressive stall detection - private static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6; - // Default for the data stall alarm for aggressive stall detection - private static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60; - - private static final boolean DATA_STALL_SUSPECTED = true; - protected static final boolean DATA_STALL_NOT_SUSPECTED = false; - - private static final String INTENT_DATA_STALL_ALARM = - "com.android.internal.telephony.data-stall"; - // Tag for tracking stale alarms - private static final String INTENT_DATA_STALL_ALARM_EXTRA_TAG = "data_stall_alarm_extra_tag"; - private static final String INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE = - "data_stall_alarm_extra_transport_type"; - - // Unique id for no data notification on setup data permanently failed. - private static final int NO_DATA_NOTIFICATION = 1001; - - /** The higher index has higher priority. */ - private static final DctConstants.State[] DATA_CONNECTION_STATE_PRIORITIES = { - DctConstants.State.IDLE, - DctConstants.State.DISCONNECTING, - DctConstants.State.CONNECTING, - DctConstants.State.CONNECTED, - }; - - private DcTesterFailBringUpAll mDcTesterFailBringUpAll; - private DcController mDcc; - - /** kept in sync with mApnContexts - * Higher numbers are higher priority and sorted so highest priority is first */ - private ArrayList mPrioritySortedApnContexts = new ArrayList<>(); - - /** all APN settings applicable to the current carrier */ - private ArrayList mAllApnSettings = new ArrayList<>(); - - /** preferred apn */ - private ApnSetting mPreferredApn = null; - - /** Is packet service restricted by network */ - private boolean mIsPsRestricted = false; - - /** emergency apn Setting*/ - private ApnSetting mEmergencyApn = null; - - /* Once disposed dont handle any messages */ - private boolean mIsDisposed = false; - - private ContentResolver mResolver; - - /* Set to true with CMD_ENABLE_MOBILE_PROVISIONING */ - private boolean mIsProvisioning = false; - - /* The Url passed as object parameter in CMD_ENABLE_MOBILE_PROVISIONING */ - private String mProvisioningUrl = null; - - /* Indicating data service is bound or not */ - private boolean mDataServiceBound = false; - - /* Intent to hide/show the sign-in error notification for provisioning */ - private static final String INTENT_PROVISION = "com.android.internal.telephony.PROVISION"; - - /** - * Extra containing the phone ID for INTENT_PROVISION - * Must be kept consistent with NetworkNotificationManager#setProvNotificationVisible. - * TODO: refactor the deprecated API to prevent hardcoding values. - */ - private static final String EXTRA_PROVISION_PHONE_ID = "provision.phone.id"; - - /* Intent for the provisioning apn alarm */ - private static final String INTENT_PROVISIONING_APN_ALARM = - "com.android.internal.telephony.provisioning_apn_alarm"; - - /* Tag for tracking stale alarms */ - private static final String PROVISIONING_APN_ALARM_TAG_EXTRA = "provisioning.apn.alarm.tag"; - - /* Debug property for overriding the PROVISIONING_APN_ALARM_DELAY_IN_MS */ - private static final String DEBUG_PROV_APN_ALARM = "persist.debug.prov_apn_alarm"; - - /* Default for the provisioning apn alarm timeout */ - private static final int PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT = 1000 * 60 * 15; - - /* The provision apn alarm intent used to disable the provisioning apn */ - private PendingIntent mProvisioningApnAlarmIntent = null; - - /* Used to track stale provisioning apn alarms */ - private int mProvisioningApnAlarmTag = (int) SystemClock.elapsedRealtime(); - - private AsyncChannel mReplyAc = new AsyncChannel(); - - private final LocalLog mDataRoamingLeakageLog = new LocalLog(32); - private final LocalLog mApnSettingsInitializationLog = new LocalLog(32); - - /* 5G connection reevaluation watchdog alarm constants */ - private long mWatchdogTimeMs = 1000 * 60 * 60; - private boolean mWatchdog = false; - - /* Default for whether 5G frequencies are considered unmetered */ - private boolean mNrNsaAllUnmetered = false; - private boolean mNrNsaMmwaveUnmetered = false; - private boolean mNrNsaSub6Unmetered = false; - private boolean mNrSaAllUnmetered = false; - private boolean mNrSaMmwaveUnmetered = false; - private boolean mNrSaSub6Unmetered = false; - private boolean mNrNsaRoamingUnmetered = false; - - // it effect the PhysicalLinkStatusChanged - private boolean mLteEndcUsingUserDataForRrcDetection = false; - - /* List of SubscriptionPlans, updated when initialized and when plans are changed. */ - private List mSubscriptionPlans = new ArrayList<>(); - /* List of network types an unmetered override applies to, set by onSubscriptionOverride - * and cleared when the device is rebooted or the override expires. */ - private List mUnmeteredNetworkTypes = null; - /* List of network types a congested override applies to, set by onSubscriptionOverride - * and cleared when the device is rebooted or the override expires. */ - private List mCongestedNetworkTypes = null; - /* Whether an unmetered override is currently active. */ - private boolean mUnmeteredOverride = false; - /* Whether a congested override is currently active. */ - private boolean mCongestedOverride = false; - - @SimState - private int mSimState = TelephonyManager.SIM_STATE_UNKNOWN; - - private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver () { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (action.equals(Intent.ACTION_SCREEN_ON)) { - // TODO: Evaluate hooking this up with DeviceStateMonitor - if (DBG) log("screen on"); - mIsScreenOn = true; - stopNetStatPoll(); - startNetStatPoll(); - restartDataStallAlarm(); - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - if (DBG) log("screen off"); - mIsScreenOn = false; - stopNetStatPoll(); - startNetStatPoll(); - restartDataStallAlarm(); - } else if (action.equals(INTENT_DATA_STALL_ALARM)) { - onActionIntentDataStallAlarm(intent); - } else if (action.equals(INTENT_PROVISIONING_APN_ALARM)) { - if (DBG) log("Provisioning apn alarm"); - onActionIntentProvisioningApnAlarm(intent); - } else if (action.equals(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED) - || action.equals(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)) { - if (mPhone.getPhoneId() == intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { - int simState = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE, - TelephonyManager.SIM_STATE_UNKNOWN); - sendMessage(obtainMessage(DctConstants.EVENT_SIM_STATE_UPDATED, simState, 0)); - } - } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - if (mPhone.getPhoneId() == intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { - if (intent.getBooleanExtra( - CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, false)) { - // Ignore the rebroadcast one to prevent multiple carrier config changed - // event during boot up. - return; - } - int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (SubscriptionManager.isValidSubscriptionId(subId)) { - sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); - } - } - } else { - if (DBG) log("onReceive: Unknown action=" + action); - } - } - }; - - private final Runnable mPollNetStat = new Runnable() { - @Override - public void run() { - updateDataActivity(); - - if (mIsScreenOn) { - mNetStatPollPeriod = Settings.Global.getInt(mResolver, - Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); - } else { - mNetStatPollPeriod = Settings.Global.getInt(mResolver, - Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, - POLL_NETSTAT_SCREEN_OFF_MILLIS); - } - - if (mNetStatPollEnabled) { - mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod); - } - } - }; - - private class ThrottleStatusChangedCallback implements DataThrottler.Callback { - @Override - public void onThrottleStatusChanged(List throttleStatuses) { - for (ThrottleStatus status : throttleStatuses) { - if (status.getThrottleType() == ThrottleStatus.THROTTLE_TYPE_NONE) { - setupDataOnConnectableApn(mApnContextsByType.get(status.getApnType()), - Phone.REASON_DATA_UNTHROTTLED, - RetryFailures.ALWAYS); - } - } - } - } - - private NetworkPolicyManager mNetworkPolicyManager; - private final NetworkPolicyManager.SubscriptionCallback mSubscriptionCallback = - new NetworkPolicyManager.SubscriptionCallback() { - @Override - public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, - int[] networkTypes) { - if (mPhone == null || mPhone.getSubId() != subId) return; - - List tempList = new ArrayList<>(); - for (int networkType : networkTypes) { - tempList.add(networkType); - } - - log("Subscription override: overrideMask=" + overrideMask - + ", overrideValue=" + overrideValue + ", networkTypes=" + tempList); - - if (overrideMask == SUBSCRIPTION_OVERRIDE_UNMETERED) { - mUnmeteredNetworkTypes = tempList; - mUnmeteredOverride = overrideValue != 0; - reevaluateUnmeteredConnections(); - } else if (overrideMask == SUBSCRIPTION_OVERRIDE_CONGESTED) { - mCongestedNetworkTypes = tempList; - mCongestedOverride = overrideValue != 0; - reevaluateCongestedConnections(); - } - } - - @Override - public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { - if (mPhone == null || mPhone.getSubId() != subId) return; - - mSubscriptionPlans = Arrays.asList(plans); - if (DBG) log("SubscriptionPlans changed: " + mSubscriptionPlans); - reevaluateUnmeteredConnections(); - } - }; - - private final SettingsObserver mSettingsObserver; - - private void registerSettingsObserver() { - mSettingsObserver.unobserve(); - String simSuffix = ""; - if (TelephonyManager.getDefault().getSimCount() > 1) { - simSuffix = Integer.toString(mPhone.getSubId()); - } - - mSettingsObserver.observe( - Settings.Global.getUriFor(Settings.Global.DATA_ROAMING + simSuffix), - DctConstants.EVENT_ROAMING_SETTING_CHANGE); - mSettingsObserver.observe( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), - DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE); - } - - /** - * Maintain the sum of transmit and receive packets. - * - * The packet counts are initialized and reset to -1 and - * remain -1 until they can be updated. - */ - public static class TxRxSum { - public long txPkts; - public long rxPkts; - - public TxRxSum() { - reset(); - } - - public TxRxSum(long txPkts, long rxPkts) { - this.txPkts = txPkts; - this.rxPkts = rxPkts; - } - - public TxRxSum(TxRxSum sum) { - txPkts = sum.txPkts; - rxPkts = sum.rxPkts; - } - - public void reset() { - txPkts = -1; - rxPkts = -1; - } - - @Override - public String toString() { - return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}"; - } - - /** - * Get total Tx/Rx packet count from TrafficStats - */ - public void updateTotalTxRxSum() { - this.txPkts = TrafficStats.getMobileTxPackets(); - this.rxPkts = TrafficStats.getMobileRxPackets(); - } - } - - private void onDataReconnect(ApnContext apnContextforRetry, int subId, - @RequestNetworkType int requestType) { - int phoneSubId = mPhone.getSubId(); - String apnType = apnContextforRetry.getApnType(); - String reason = apnContextforRetry.getReason(); - - if (!SubscriptionManager.isValidSubscriptionId(subId) || (subId != phoneSubId)) { - log("onDataReconnect: invalid subId"); - return; - } - - ApnContext apnContext = mApnContexts.get(apnType); - - if (DBG) { - log("onDataReconnect: mState=" + mState + " reason=" + reason + " apnType=" + apnType - + " apnContext=" + apnContext); - } - - if ((apnContext != null) && (apnContext.isEnabled())) { - apnContext.setReason(reason); - DctConstants.State apnContextState = apnContext.getState(); - if (DBG) { - log("onDataReconnect: apnContext state=" + apnContextState); - } - if ((apnContextState == DctConstants.State.FAILED) - || (apnContextState == DctConstants.State.IDLE)) { - if (DBG) { - log("onDataReconnect: state is FAILED|IDLE, disassociate"); - } - apnContext.releaseDataConnection(""); - } else { - if (DBG) log("onDataReconnect: keep associated"); - } - // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA??? - sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, requestType, - 0, apnContext)); - } - } - - private void onActionIntentDataStallAlarm(Intent intent) { - if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction()); - - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (!SubscriptionManager.isValidSubscriptionId(subId) || (subId != mPhone.getSubId())) { - return; - } - - int transportType = intent.getIntExtra(INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE, 0); - if (transportType != mTransportType) { - return; - } - - Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM, - intent.getAction()); - msg.arg1 = intent.getIntExtra(INTENT_DATA_STALL_ALARM_EXTRA_TAG, 0); - sendMessage(msg); - } - - private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList(); - - // member variables - protected final Phone mPhone; - private DctConstants.Activity mActivity = DctConstants.Activity.NONE; - private DctConstants.State mState = DctConstants.State.IDLE; - private final Handler mDataConnectionTracker; - - private long mTxPkts; - private long mRxPkts; - private int mNetStatPollPeriod; - private boolean mNetStatPollEnabled = false; - - private TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0); - // Used to track stale data stall alarms. - private int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime(); - // The current data stall alarm intent - private PendingIntent mDataStallAlarmIntent = null; - // Number of packets sent since the last received packet - private long mSentSinceLastRecv; - // Controls when a simple recovery attempt it to be tried - private int mNoRecvPollCount = 0; - // Reference counter for enabling fail fast - private static int sEnableFailFastRefCounter = 0; - // True if data stall detection is enabled - private volatile boolean mDataStallNoRxEnabled = true; - - protected volatile boolean mFailFast = false; - - // True when in voice call - protected boolean mInVoiceCall = false; - - /** Intent sent when the reconnect alarm fires. */ - private PendingIntent mReconnectIntent = null; - - // When false we will not auto attach and manually attaching is required. - protected boolean mAutoAttachOnCreationConfig = false; - private AtomicBoolean mAutoAttachEnabled = new AtomicBoolean(false); - - // State of screen - // (TODO: Reconsider tying directly to screen, maybe this is - // really a lower power mode") - private boolean mIsScreenOn = true; - - /** Allows the generation of unique Id's for DataConnection objects */ - private AtomicInteger mUniqueIdGenerator = new AtomicInteger(0); - - /** The data connections. */ - private HashMap mDataConnections = - new HashMap(); - - /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */ - private HashMap mApnToDataConnectionId = new HashMap(); - - /** Phone.APN_TYPE_* ===> ApnContext */ - protected ConcurrentHashMap mApnContexts = - new ConcurrentHashMap(); - - private SparseArray mApnContextsByType = new SparseArray(); - - private ArrayList mLastDataProfileList = new ArrayList<>(); - - /** RAT name ===> (downstream, upstream) bandwidth values from carrier config. */ - private ConcurrentHashMap> mBandwidths = - new ConcurrentHashMap<>(); - - private boolean mConfigReady = false; - - /** - * Handles changes to the APN db. - */ - private class ApnChangeObserver extends ContentObserver { - public ApnChangeObserver () { - super(mDataConnectionTracker); - } - - @Override - public void onChange(boolean selfChange) { - sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED)); - } - } - - //***** Instance Variables - - private boolean mReregisterOnReconnectFailure = false; - - - //***** Constants - - private static final int PROVISIONING_SPINNER_TIMEOUT_MILLIS = 120 * 1000; - - static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID = - Uri.parse("content://telephony/carriers/preferapn_no_update/subId/"); - static final String APN_ID = "apn_id"; - - private boolean mCanSetPreferApn = false; - - private AtomicBoolean mAttached = new AtomicBoolean(false); - - /** Watches for changes to the APN db. */ - private ApnChangeObserver mApnObserver; - - private BroadcastReceiver mProvisionBroadcastReceiver; - private ProgressDialog mProvisioningSpinner; - - private final DataServiceManager mDataServiceManager; - - @AccessNetworkConstants.TransportType - private final int mTransportType; - - private DataStallRecoveryHandler mDsRecoveryHandler; - private HandlerThread mHandlerThread; - - private final DataThrottler mDataThrottler; - - private final ThrottleStatusChangedCallback mThrottleStatusCallback; - - /** - * Request network completion message map. Key is the APN type, value is the list of completion - * messages to be sent. Using a list because there might be multiple network requests for - * the same APN type. - */ - private final Map> mHandoverCompletionMsgs = new HashMap<>(); - - //***** Constructor - public DcTracker(Phone phone, @TransportType int transportType) { - super(); - mPhone = phone; - if (DBG) log("DCT.constructor"); - mTelephonyManager = TelephonyManager.from(phone.getContext()) - .createForSubscriptionId(phone.getSubId()); - // The 'C' in tag indicates cellular, and 'I' indicates IWLAN. This is to distinguish - // between two DcTrackers, one for each. - String tagSuffix = "-" + ((transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - ? "C" : "I"); - tagSuffix += "-" + mPhone.getPhoneId(); - mLogTag = "DCT" + tagSuffix; - - mTransportType = transportType; - mDataServiceManager = new DataServiceManager(phone, transportType, tagSuffix); - mDataThrottler = new DataThrottler(mPhone, transportType); - - mResolver = mPhone.getContext().getContentResolver(); - mAlarmManager = - (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); - - mDsRecoveryHandler = new DataStallRecoveryHandler(); - - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(INTENT_DATA_STALL_ALARM); - filter.addAction(INTENT_PROVISIONING_APN_ALARM); - filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - filter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); - filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); - - mDataEnabledSettings = mPhone.getDataEnabledSettings(); - - mDataEnabledSettings.registerForDataEnabledChanged(this, - DctConstants.EVENT_DATA_ENABLED_CHANGED, null); - mDataEnabledSettings.registerForDataEnabledOverrideChanged(this, - DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED); - - mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); - - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); - mAutoAttachEnabled.set(sp.getBoolean(Phone.DATA_DISABLED_ON_BOOT_KEY, false)); - - mNetworkPolicyManager = (NetworkPolicyManager) mPhone.getContext() - .getSystemService(Context.NETWORK_POLICY_SERVICE); - mNetworkPolicyManager.registerSubscriptionCallback(mSubscriptionCallback); - - mHandlerThread = new HandlerThread("DcHandlerThread"); - mHandlerThread.start(); - Handler dcHandler = new Handler(mHandlerThread.getLooper()); - mDcc = DcController.makeDcc(mPhone, this, mDataServiceManager, dcHandler.getLooper(), - tagSuffix); - mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler); - - mDataConnectionTracker = this; - registerForAllEvents(); - mApnObserver = new ApnChangeObserver(); - phone.getContext().getContentResolver().registerContentObserver( - Telephony.Carriers.CONTENT_URI, true, mApnObserver); - - initApnContexts(); - - addDefaultApnSettingsAsNeeded(); - - mSettingsObserver = new SettingsObserver(mPhone.getContext(), this); - registerSettingsObserver(); - - mThrottleStatusCallback = new ThrottleStatusChangedCallback(); - mDataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); - } - - @VisibleForTesting - public DcTracker() { - mLogTag = "DCT"; - mTelephonyManager = null; - mAlarmManager = null; - mPhone = null; - mDataConnectionTracker = null; - mSettingsObserver = new SettingsObserver(null, this); - mDataEnabledSettings = null; - mTransportType = 0; - mDataServiceManager = null; - mDataThrottler = null; - mThrottleStatusCallback = null; - } - - public void registerServiceStateTrackerEvents() { - mPhone.getServiceStateTracker().registerForDataConnectionAttached(mTransportType, this, - DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null); - mPhone.getServiceStateTracker().registerForDataConnectionDetached(mTransportType, this, - DctConstants.EVENT_DATA_CONNECTION_DETACHED, null); - mPhone.getServiceStateTracker().registerForDataRoamingOn(this, - DctConstants.EVENT_ROAMING_ON, null); - mPhone.getServiceStateTracker().registerForDataRoamingOff(this, - DctConstants.EVENT_ROAMING_OFF, null, true); - mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this, - DctConstants.EVENT_PS_RESTRICT_ENABLED, null); - mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this, - DctConstants.EVENT_PS_RESTRICT_DISABLED, null); - mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(mTransportType, this, - DctConstants.EVENT_DATA_RAT_CHANGED, null); - } - - public void unregisterServiceStateTrackerEvents() { - mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(mTransportType, this); - mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(mTransportType, this); - mPhone.getServiceStateTracker().unregisterForDataRoamingOn(this); - mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this); - mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this); - mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this); - mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(mTransportType, this); - mPhone.getServiceStateTracker().unregisterForAirplaneModeChanged(this); - } - - private void registerForAllEvents() { - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null); - mPhone.mCi.registerForOffOrNotAvailable(this, - DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - mPhone.mCi.registerForPcoData(this, DctConstants.EVENT_PCO_DATA_RECEIVED, null); - } - - // Note, this is fragile - the Phone is now presenting a merged picture - // of PS (volte) & CS and by diving into its internals you're just seeing - // the CS data. This works well for the purposes this is currently used for - // but that may not always be the case. Should probably be redesigned to - // accurately reflect what we're really interested in (registerForCSVoiceCallEnded). - mPhone.getCallTracker().registerForVoiceCallEnded(this, - DctConstants.EVENT_VOICE_CALL_ENDED, null); - mPhone.getCallTracker().registerForVoiceCallStarted(this, - DctConstants.EVENT_VOICE_CALL_STARTED, null); - mPhone.getDisplayInfoController().registerForTelephonyDisplayInfoChanged(this, - DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED, null); - registerServiceStateTrackerEvents(); - mDataServiceManager.registerForServiceBindingChanged(this, - DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED, null); - mDataServiceManager.registerForApnUnthrottled(this, DctConstants.EVENT_APN_UNTHROTTLED); - } - - public void dispose() { - if (DBG) log("DCT.dispose"); - - if (mProvisionBroadcastReceiver != null) { - mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); - mProvisionBroadcastReceiver = null; - } - if (mProvisioningSpinner != null) { - mProvisioningSpinner.dismiss(); - mProvisioningSpinner = null; - } - - cleanUpAllConnectionsInternal(true, null); - - mIsDisposed = true; - mPhone.getContext().unregisterReceiver(mIntentReceiver); - mSettingsObserver.unobserve(); - - mNetworkPolicyManager.unregisterSubscriptionCallback(mSubscriptionCallback); - mDcTesterFailBringUpAll.dispose(); - - mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver); - mApnContexts.clear(); - mApnContextsByType.clear(); - mPrioritySortedApnContexts.clear(); - unregisterForAllEvents(); - - destroyDataConnections(); - } - - /** - * Stop the internal handler thread - * - * TESTING ONLY - */ - @VisibleForTesting - public void stopHandlerThread() { - mHandlerThread.quit(); - } - - private void unregisterForAllEvents() { - //Unregister for all events - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.unregisterForAvailable(this); - mPhone.mCi.unregisterForOffOrNotAvailable(this); - mPhone.mCi.unregisterForPcoData(this); - } - - mPhone.getCallTracker().unregisterForVoiceCallEnded(this); - mPhone.getCallTracker().unregisterForVoiceCallStarted(this); - mPhone.getDisplayInfoController().unregisterForTelephonyDisplayInfoChanged(this); - unregisterServiceStateTrackerEvents(); - mDataServiceManager.unregisterForServiceBindingChanged(this); - mDataEnabledSettings.unregisterForDataEnabledChanged(this); - mDataEnabledSettings.unregisterForDataEnabledOverrideChanged(this); - mDataServiceManager.unregisterForApnUnthrottled(this); - } - - /** - * Reevaluate existing data connections when conditions change. - * - * For example, handle reverting restricted networks back to unrestricted. If we're changing - * user data to enabled and this makes data truly enabled (not disabled by other factors) we - * need to reevaluate and possibly add NET_CAPABILITY_NOT_RESTRICTED capability to the data - * connection. This allows non-privilege apps to use the network. - * - * Or when we brought up a unmetered data connection while data is off, we only limit this - * data connection for unmetered use only. When data is turned back on, we need to tear that - * down so a full capable data connection can be re-established. - */ - private void reevaluateDataConnections() { - for (DataConnection dataConnection : mDataConnections.values()) { - dataConnection.reevaluateRestrictedState(); - } - } - - public long getSubId() { - return mPhone.getSubId(); - } - - public DctConstants.Activity getActivity() { - return mActivity; - } - - private void setActivity(DctConstants.Activity activity) { - log("setActivity = " + activity); - mActivity = activity; - mPhone.notifyDataActivity(); - } - - /** - * Request a network - * - * @param networkRequest Network request from clients - * @param type The request type - * @param onHandoverCompleteMsg When request type is handover, this message will be sent when - * handover is completed. For normal request, this should be null. - */ - public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type, - Message onHandoverCompleteMsg) { - if (type != REQUEST_TYPE_HANDOVER && onHandoverCompleteMsg != null) { - throw new RuntimeException("request network with normal type request type but passing " - + "handover complete message."); - } - final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest); - final ApnContext apnContext = mApnContextsByType.get(apnType); - if (apnContext != null) { - apnContext.requestNetwork(networkRequest, type, onHandoverCompleteMsg); - } - } - - public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type) { - final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest); - final ApnContext apnContext = mApnContextsByType.get(apnType); - if (apnContext != null) { - apnContext.releaseNetwork(networkRequest, type); - } - } - - // Turn telephony radio on or off. - private void setRadio(boolean on) { - final ITelephony phone = ITelephony.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getTelephonyServiceRegisterer() - .get()); - try { - phone.setRadio(on); - } catch (Exception e) { - // Ignore. - } - } - - // Class to handle Intent dispatched with user selects the "Sign-in to network" - // notification. - private class ProvisionNotificationBroadcastReceiver extends BroadcastReceiver { - private final String mNetworkOperator; - // Mobile provisioning URL. Valid while provisioning notification is up. - // Set prior to notification being posted as URL contains ICCID which - // disappears when radio is off (which is the case when notification is up). - private final String mProvisionUrl; - - public ProvisionNotificationBroadcastReceiver(String provisionUrl, String networkOperator) { - mNetworkOperator = networkOperator; - mProvisionUrl = provisionUrl; - } - - private void setEnableFailFastMobileData(int enabled) { - sendMessage(obtainMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled, 0)); - } - - private void enableMobileProvisioning() { - final Message msg = obtainMessage(DctConstants.CMD_ENABLE_MOBILE_PROVISIONING); - Bundle bundle = new Bundle(1); - bundle.putString(DctConstants.PROVISIONING_URL_KEY, mProvisionUrl); - msg.setData(bundle); - sendMessage(msg); - } - - @Override - public void onReceive(Context context, Intent intent) { - if (mPhone.getPhoneId() != intent.getIntExtra(EXTRA_PROVISION_PHONE_ID, - SubscriptionManager.INVALID_PHONE_INDEX)) { - return; - } - // Turning back on the radio can take time on the order of a minute, so show user a - // spinner so they know something is going on. - log("onReceive : ProvisionNotificationBroadcastReceiver"); - mProvisioningSpinner = new ProgressDialog(context); - mProvisioningSpinner.setTitle(mNetworkOperator); - mProvisioningSpinner.setMessage( - // TODO: Don't borrow "Connecting..." i18n string; give Telephony a version. - context.getText(com.android.internal.R.string.media_route_status_connecting)); - mProvisioningSpinner.setIndeterminate(true); - mProvisioningSpinner.setCancelable(true); - // Allow non-Activity Service Context to create a View. - mProvisioningSpinner.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - mProvisioningSpinner.show(); - // After timeout, hide spinner so user can at least use their device. - // TODO: Indicate to user that it is taking an unusually long time to connect? - sendMessageDelayed(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, - mProvisioningSpinner), PROVISIONING_SPINNER_TIMEOUT_MILLIS); - // This code is almost identical to the old - // ConnectivityService.handleMobileProvisioningAction code. - setRadio(true); - setEnableFailFastMobileData(DctConstants.ENABLED); - enableMobileProvisioning(); - } - } - - @Override - protected void finalize() { - if(DBG && mPhone != null) log("finalize"); - } - - private void initApnContexts() { - PersistableBundle carrierConfig; - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - carrierConfig = configManager.getConfigForSubId(mPhone.getSubId()); - } else { - carrierConfig = null; - } - initApnContexts(carrierConfig); - } - - //Blows away any existing apncontexts that may exist, only use in ctor. - private void initApnContexts(PersistableBundle carrierConfig) { - if (!mTelephonyManager.isDataCapable()) { - log("initApnContexts: isDataCapable == false. No Apn Contexts loaded"); - return; - } - - log("initApnContexts: E"); - // Load device network attributes from resources - final Collection types = - new ApnConfigTypeRepository(carrierConfig).getTypes(); - - for (ApnConfigType apnConfigType : types) { - ApnContext apnContext = new ApnContext(mPhone, apnConfigType.getType(), mLogTag, this, - apnConfigType.getPriority()); - int bitmask = ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType()); - mPrioritySortedApnContexts.add(apnContext); - mApnContexts.put(apnContext.getApnType(), apnContext); - mApnContextsByType.put(bitmask, apnContext); - // Notify listeners that all data is disconnected when DCT is initialized. - // Once connections are established, DC will then notify that data is connected. - // This is to prevent the case where the phone process crashed but we don't notify - // listeners that data was disconnected, so they may be stuck in a connected state. - mPhone.notifyDataConnection(new PreciseDataConnectionState.Builder() - .setTransportType(mTransportType) - .setState(TelephonyManager.DATA_DISCONNECTED) - .setApnSetting(new ApnSetting.Builder() - .setApnTypeBitmask(bitmask).buildWithoutCheck()) - .setNetworkType(getDataRat()) - .build()); - log("initApnContexts: apnContext=" + ApnSetting.getApnTypeString( - apnConfigType.getType())); - } - mPrioritySortedApnContexts.sort((c1, c2) -> c2.getPriority() - c1.getPriority()); - logSortedApnContexts(); - } - - private void sortApnContextByPriority() { - if (!mTelephonyManager.isDataCapable()) { - log("sortApnContextByPriority: isDataCapable == false. No Apn Contexts loaded"); - return; - } - - PersistableBundle carrierConfig; - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - carrierConfig = configManager.getConfigForSubId(mPhone.getSubId()); - } else { - carrierConfig = null; - } - - log("sortApnContextByPriority: E"); - // Load device network attributes from resources - final Collection types = - new ApnConfigTypeRepository(carrierConfig).getTypes(); - for (ApnConfigType apnConfigType : types) { - if (mApnContextsByType.contains(apnConfigType.getType())) { - ApnContext apnContext = mApnContextsByType.get(apnConfigType.getType()); - apnContext.setPriority(apnConfigType.getPriority()); - } - } - - //Doing sorted in a different list to keep thread safety - ArrayList prioritySortedApnContexts = - new ArrayList<>(mPrioritySortedApnContexts); - prioritySortedApnContexts.sort((c1, c2) -> c2.getPriority() - c1.getPriority()); - mPrioritySortedApnContexts = prioritySortedApnContexts; - logSortedApnContexts(); - } - - public LinkProperties getLinkProperties(String apnType) { - ApnContext apnContext = mApnContexts.get(apnType); - if (apnContext != null) { - DataConnection dataConnection = apnContext.getDataConnection(); - if (dataConnection != null) { - if (DBG) log("return link properties for " + apnType); - return dataConnection.getLinkProperties(); - } - } - if (DBG) log("return new LinkProperties"); - return new LinkProperties(); - } - - public NetworkCapabilities getNetworkCapabilities(String apnType) { - ApnContext apnContext = mApnContexts.get(apnType); - if (apnContext!=null) { - DataConnection dataConnection = apnContext.getDataConnection(); - if (dataConnection != null) { - if (DBG) { - log("get active pdp is not null, return NetworkCapabilities for " + apnType); - } - return dataConnection.getNetworkCapabilities(); - } - } - if (DBG) log("return new NetworkCapabilities"); - return new NetworkCapabilities(); - } - - // Return all active apn types - public String[] getActiveApnTypes() { - if (DBG) log("get all active apn types"); - ArrayList result = new ArrayList(); - - for (ApnContext apnContext : mApnContexts.values()) { - if (mAttached.get() && apnContext.isReady()) { - result.add(apnContext.getApnType()); - } - } - - return result.toArray(new String[0]); - } - - /** - * Get ApnTypes with connected data connections. This is different than getActiveApnTypes() - * which returns apn types that with active apn contexts. - * @return apn types - */ - public String[] getConnectedApnTypes() { - return mApnContexts.values().stream() - .filter(ac -> ac.getState() == DctConstants.State.CONNECTED) - .map(ApnContext::getApnType) - .toArray(String[]::new); - } - - @VisibleForTesting - public Collection getApnContexts() { - return mPrioritySortedApnContexts; - } - - /** Return active ApnSetting of a specific apnType */ - public ApnSetting getActiveApnSetting(String apnType) { - if (VDBG) log("get active ApnSetting for type:" + apnType); - ApnContext apnContext = mApnContexts.get(apnType); - return (apnContext != null) ? apnContext.getApnSetting() : null; - } - - // Return active apn of specific apn type - public String getActiveApnString(String apnType) { - if (VDBG) log( "get active apn string for type:" + apnType); - ApnSetting setting = getActiveApnSetting(apnType); - return (setting != null) ? setting.getApnName() : null; - } - - /** - * Returns {@link DctConstants.State} based on the state of the {@link DataConnection} that - * contains a {@link ApnSetting} that supported the given apn type {@code anpType}. - * - *

- * Assumes there is less than one {@link ApnSetting} can support the given apn type. - */ - // TODO: for enterprise this always returns IDLE, which is ok for now since it is never called - // for enterprise - public DctConstants.State getState(String apnType) { - DctConstants.State state = DctConstants.State.IDLE; - final int apnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(apnType); - for (DataConnection dc : mDataConnections.values()) { - ApnSetting apnSetting = dc.getApnSetting(); - if (apnSetting != null && apnSetting.canHandleType(apnTypeBitmask)) { - if (dc.isActive()) { - state = getBetterConnectionState(state, DctConstants.State.CONNECTED); - } else if (dc.isActivating()) { - state = getBetterConnectionState(state, DctConstants.State.CONNECTING); - } else if (dc.isInactive()) { - state = getBetterConnectionState(state, DctConstants.State.IDLE); - } else if (dc.isDisconnecting()) { - state = getBetterConnectionState(state, DctConstants.State.DISCONNECTING); - } - } - } - return state; - } - - /** - * Return a better connection state between {@code stateA} and {@code stateB}. Check - * {@link #DATA_CONNECTION_STATE_PRIORITIES} for the details. - * @return the better connection state between {@code stateA} and {@code stateB}. - */ - private static DctConstants.State getBetterConnectionState( - DctConstants.State stateA, DctConstants.State stateB) { - int idxA = ArrayUtils.indexOf(DATA_CONNECTION_STATE_PRIORITIES, stateA); - int idxB = ArrayUtils.indexOf(DATA_CONNECTION_STATE_PRIORITIES, stateB); - return idxA >= idxB ? stateA : stateB; - } - - // Return if apn type is a provisioning apn. - private boolean isProvisioningApn(String apnType) { - ApnContext apnContext = mApnContexts.get(apnType); - if (apnContext != null) { - return apnContext.isProvisioningApn(); - } - return false; - } - - //****** Called from ServiceStateTracker - /** - * Invoked when ServiceStateTracker observes a transition from GPRS - * attach to detach. - */ - private void onDataConnectionDetached() { - /* - * We presently believe it is unnecessary to tear down the PDP context - * when GPRS detaches, but we should stop the network polling. - */ - if (DBG) log ("onDataConnectionDetached: stop polling and notify detached"); - stopNetStatPoll(); - stopDataStallAlarm(); - mAttached.set(false); - } - - private void onDataConnectionAttached() { - if (DBG) log("onDataConnectionAttached"); - mAttached.set(true); - if (isAnyDataConnected()) { - if (DBG) log("onDataConnectionAttached: start polling notify attached"); - startNetStatPoll(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - } - if (mAutoAttachOnCreationConfig) { - mAutoAttachEnabled.set(true); - } - setupDataOnAllConnectableApns(Phone.REASON_DATA_ATTACHED, RetryFailures.ALWAYS); - } - - /** - * Check if it is allowed to make a data connection (without checking APN context specific - * conditions). - * - * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output - * param. It's okay to pass null here and no reasons will be - * provided. - * @return True if data connection is allowed, otherwise false. - */ - public boolean isDataAllowed(DataConnectionReasons dataConnectionReasons) { - return isDataAllowed(null, REQUEST_TYPE_NORMAL, dataConnectionReasons); - } - - /** - * Check if it is allowed to make a data connection for a given APN type. - * - * @param apnContext APN context. If passing null, then will only check general but not APN - * specific conditions (e.g. APN state, metered/unmetered APN). - * @param requestType Setup data request type. - * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output - * param. It's okay to pass null here and no reasons will be - * provided. - * @return True if data connection is allowed, otherwise false. - */ - public boolean isDataAllowed(ApnContext apnContext, @RequestNetworkType int requestType, - DataConnectionReasons dataConnectionReasons) { - // Step 1: Get all environment conditions. - // Step 2: Special handling for emergency APN. - // Step 3. Build disallowed reasons. - // Step 4: Determine if data should be allowed in some special conditions. - - DataConnectionReasons reasons = new DataConnectionReasons(); - - int requestApnType = 0; - if (apnContext != null) { - requestApnType = apnContext.getApnTypeBitmask(); - } - - // Step 1: Get all environment conditions. - final boolean internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled(); - boolean attachedState = mAttached.get(); - boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState(); - boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier(); - // TODO: Remove this hack added by ag/641832. - int dataRat = getDataRat(); - if (dataRat == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { - desiredPowerState = true; - radioStateFromCarrier = true; - } - - boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId( - SubscriptionManager.getDefaultDataSubscriptionId()); - - boolean isMeteredApnType = apnContext == null - || ApnSettingUtils.isMeteredApnType(requestApnType, mPhone); - - PhoneConstants.State phoneState = PhoneConstants.State.IDLE; - // Note this is explicitly not using mPhone.getState. See b/19090488. - // mPhone.getState reports the merge of CS and PS (volte) voice call state - // but we only care about CS calls here for data/voice concurrency issues. - // Calling getCallTracker currently gives you just the CS side where the - // ImsCallTracker is held internally where applicable. - // This should be redesigned to ask explicitly what we want: - // voiceCallStateAllowDataCall, or dataCallAllowed or something similar. - if (mPhone.getCallTracker() != null) { - phoneState = mPhone.getCallTracker().getState(); - } - - // Step 2: Special handling for emergency APN. - if (apnContext != null - && requestApnType == ApnSetting.TYPE_EMERGENCY - && apnContext.isConnectable()) { - // If this is an emergency APN, as long as the APN is connectable, we - // should allow it. - if (dataConnectionReasons != null) { - dataConnectionReasons.add(DataAllowedReasonType.EMERGENCY_APN); - } - // Bail out without further checks. - return true; - } - - // Step 3. Build disallowed reasons. - if (apnContext != null && !apnContext.isConnectable()) { - DctConstants.State state = apnContext.getState(); - if (state == DctConstants.State.CONNECTED) { - reasons.add(DataDisallowedReasonType.DATA_ALREADY_CONNECTED); - } else if (state == DctConstants.State.DISCONNECTING) { - reasons.add(DataDisallowedReasonType.DATA_IS_DISCONNECTING); - } else if (state == DctConstants.State.CONNECTING) { - reasons.add(DataDisallowedReasonType.DATA_IS_CONNECTING); - } else { - reasons.add(DataDisallowedReasonType.APN_NOT_CONNECTABLE); - } - } - - // In legacy mode, if RAT is IWLAN then don't allow default/IA PDP at all. - // Rest of APN types can be evaluated for remaining conditions. - if ((apnContext != null && requestApnType == ApnSetting.TYPE_DEFAULT - || requestApnType == ApnSetting.TYPE_ENTERPRISE - || requestApnType == ApnSetting.TYPE_IA) - && mPhone.getAccessNetworksManager().isInLegacyMode() - && dataRat == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { - reasons.add(DataDisallowedReasonType.ON_IWLAN); - } - - // If device is not on NR, don't allow enterprise - if (apnContext != null && requestApnType == ApnSetting.TYPE_ENTERPRISE - && dataRat != ServiceState.RIL_RADIO_TECHNOLOGY_NR) { - reasons.add(DataDisallowedReasonType.NOT_ON_NR); - } - - if (shouldRestrictDataForEcbm() || mPhone.isInEmergencyCall()) { - reasons.add(DataDisallowedReasonType.IN_ECBM); - } - - if (!attachedState && !shouldAutoAttach() && requestType != REQUEST_TYPE_HANDOVER) { - reasons.add(DataDisallowedReasonType.NOT_ATTACHED); - } - if (mPhone.getSubId() == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - reasons.add(DataDisallowedReasonType.SIM_NOT_READY); - } - if (phoneState != PhoneConstants.State.IDLE - && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { - reasons.add(DataDisallowedReasonType.INVALID_PHONE_STATE); - reasons.add(DataDisallowedReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED); - } - if (!internalDataEnabled) { - reasons.add(DataDisallowedReasonType.INTERNAL_DATA_DISABLED); - } - if (!defaultDataSelected) { - reasons.add(DataDisallowedReasonType.DEFAULT_DATA_UNSELECTED); - } - if (mPhone.getServiceState().getDataRoaming() && !getDataRoamingEnabled()) { - reasons.add(DataDisallowedReasonType.ROAMING_DISABLED); - } - if (mIsPsRestricted) { - reasons.add(DataDisallowedReasonType.PS_RESTRICTED); - } - if (!desiredPowerState) { - reasons.add(DataDisallowedReasonType.UNDESIRED_POWER_STATE); - } - if (!radioStateFromCarrier) { - reasons.add(DataDisallowedReasonType.RADIO_DISABLED_BY_CARRIER); - } - if (!mDataServiceBound) { - reasons.add(DataDisallowedReasonType.DATA_SERVICE_NOT_READY); - } - - if (apnContext != null) { - if (mPhone.getAccessNetworksManager().getPreferredTransport( - apnContext.getApnTypeBitmask()) - == AccessNetworkConstants.TRANSPORT_TYPE_INVALID) { - // If QNS explicitly specified this APN type is not allowed on either cellular or - // IWLAN, we should not allow data setup. - reasons.add(DataDisallowedReasonType.DISABLED_BY_QNS); - } else if (mTransportType != mPhone.getAccessNetworksManager().getPreferredTransport( - apnContext.getApnTypeBitmask())) { - // If the latest preference has already switched to other transport, we should not - // allow data setup. - reasons.add(DataDisallowedReasonType.ON_OTHER_TRANSPORT); - } - - // If the transport has been already switched to the other transport, we should not - // allow the data setup. The only exception is the handover case, where we setup - // handover data connection before switching the transport. - if (mTransportType != mPhone.getAccessNetworksManager().getCurrentTransport( - apnContext.getApnTypeBitmask()) && requestType != REQUEST_TYPE_HANDOVER) { - reasons.add(DataDisallowedReasonType.ON_OTHER_TRANSPORT); - } - - // Check if the device is under data throttling. - long retryTime = mDataThrottler.getRetryTime(apnContext.getApnTypeBitmask()); - if (retryTime > SystemClock.elapsedRealtime()) { - reasons.add(DataDisallowedReasonType.DATA_THROTTLED); - } - } - - boolean isDataEnabled = apnContext == null ? mDataEnabledSettings.isDataEnabled() - : mDataEnabledSettings.isDataEnabled(requestApnType); - - if (!isDataEnabled) { - reasons.add(DataDisallowedReasonType.DATA_DISABLED); - } - - // If there are hard disallowed reasons, we should not allow data connection no matter what. - if (reasons.containsHardDisallowedReasons()) { - if (dataConnectionReasons != null) { - dataConnectionReasons.copyFrom(reasons); - } - return false; - } - - // Step 4: Determine if data should be allowed in some special conditions. - - // At this point, if data is not allowed, it must be because of the soft reasons. We - // should start to check some special conditions that data will be allowed. - if (!reasons.allowed()) { - // Check if the transport is WLAN ie wifi (for AP-assisted mode devices) - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - reasons.add(DataAllowedReasonType.UNMETERED_APN); - // Or if the data is on cellular, and the APN type is determined unmetered by the - // configuration. - } else if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN - && !isMeteredApnType && requestApnType != ApnSetting.TYPE_DEFAULT - && requestApnType != ApnSetting.TYPE_ENTERPRISE) { - reasons.add(DataAllowedReasonType.UNMETERED_APN); - } - - // If the request is restricted and there are only soft disallowed reasons (e.g. data - // disabled, data roaming disabled) existing, we should allow the data. ENTERPRISE is - // an exception and should not be treated as restricted for this purpose; it should be - // treated same as DEFAULT. - if (apnContext != null - && apnContext.hasRestrictedRequests(true) - && !apnContext.getApnType().equals(ApnSetting.TYPE_ENTERPRISE_STRING) - && !reasons.allowed()) { - reasons.add(DataAllowedReasonType.RESTRICTED_REQUEST); - } - } else { - // If there is no disallowed reasons, then we should allow the data request with - // normal reason. - reasons.add(DataAllowedReasonType.NORMAL); - } - - if (dataConnectionReasons != null) { - dataConnectionReasons.copyFrom(reasons); - } - - return reasons.allowed(); - } - - // arg for setupDataOnAllConnectableApns - protected enum RetryFailures { - // retry failed networks always (the old default) - ALWAYS, - // retry only when a substantial change has occurred. Either: - // 1) we were restricted by voice/data concurrency and aren't anymore - // 2) our apn list has change - ONLY_ON_CHANGE - }; - - protected void setupDataOnAllConnectableApns(String reason, RetryFailures retryFailures) { - if (VDBG) log("setupDataOnAllConnectableApns: " + reason); - - if (DBG && !VDBG) { - StringBuilder sb = new StringBuilder(120); - for (ApnContext apnContext : mPrioritySortedApnContexts) { - sb.append(apnContext.getApnType()); - sb.append(":[state="); - sb.append(apnContext.getState()); - sb.append(",enabled="); - sb.append(apnContext.isEnabled()); - sb.append("] "); - } - log("setupDataOnAllConnectableApns: " + reason + " " + sb); - } - - for (ApnContext apnContext : mPrioritySortedApnContexts) { - setupDataOnConnectableApn(apnContext, reason, retryFailures); - } - } - - protected void setupDataOnConnectableApn(ApnContext apnContext, String reason, - RetryFailures retryFailures) { - if (VDBG) log("setupDataOnAllConnectableApns: apnContext " + apnContext); - - if (apnContext.getState() == DctConstants.State.FAILED - || apnContext.getState() == DctConstants.State.RETRYING) { - if (retryFailures == RetryFailures.ALWAYS) { - apnContext.releaseDataConnection(reason); - } else if (!apnContext.isConcurrentVoiceAndDataAllowed() - && mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { - // RetryFailures.ONLY_ON_CHANGE - check if voice concurrency has changed - apnContext.releaseDataConnection(reason); - } - } - if (apnContext.isConnectable()) { - log("isConnectable() call trySetupData"); - apnContext.setReason(reason); - trySetupData(apnContext, REQUEST_TYPE_NORMAL, null); - } - } - - private boolean shouldRestrictDataForEcbm() { - boolean isInEcm = mPhone.isInEcm(); - boolean isInImsEcm = mPhone.getImsPhone() != null && mPhone.getImsPhone().isInImsEcm(); - log("shouldRestrictDataForEcbm: isInEcm=" + isInEcm + " isInImsEcm=" + isInImsEcm); - return isInEcm && !isInImsEcm; - } - - private boolean isHandoverPending(@ApnType int apnType) { - List messageList = mHandoverCompletionMsgs.get(apnType); - return messageList != null && messageList.size() > 0; - } - - private void trySetupData(ApnContext apnContext, @RequestNetworkType int requestType, - @Nullable Message onHandoverCompleteMsg) { - if (onHandoverCompleteMsg != null) { - addHandoverCompleteMsg(onHandoverCompleteMsg, apnContext.getApnTypeBitmask()); - } - - if (mPhone.getSimulatedRadioControl() != null) { - // Assume data is connected on the simulator - log("trySetupData: X We're on the simulator; assuming connected retValue=true"); - return; - } - - DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); - boolean isDataAllowed = isDataAllowed(apnContext, requestType, dataConnectionReasons); - String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: " - + apnContext.getReason() + ", requestType=" + requestTypeToString(requestType) - + ". " + dataConnectionReasons.toString(); - if (dataConnectionReasons.contains(DataDisallowedReasonType.DISABLED_BY_QNS) - || dataConnectionReasons.contains(DataDisallowedReasonType.ON_OTHER_TRANSPORT)) { - logStr += ", current transport=" + AccessNetworkConstants.transportTypeToString( - mPhone.getAccessNetworksManager().getCurrentTransport( - apnContext.getApnTypeBitmask())); - logStr += ", preferred transport=" + AccessNetworkConstants.transportTypeToString( - mPhone.getAccessNetworksManager().getPreferredTransport( - apnContext.getApnTypeBitmask())); - } - if (DBG) log(logStr); - ApnContext.requestLog(apnContext, logStr); - if (!isDataAllowed) { - StringBuilder str = new StringBuilder(); - - str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType() - + ", mState=" + apnContext.getState() + ", apnEnabled=" - + apnContext.isEnabled() + ", mDependencyMet=" - + apnContext.isDependencyMet() + "] "); - - if (!mDataEnabledSettings.isDataEnabled()) { - str.append("isDataEnabled() = false. " + mDataEnabledSettings); - } - - // Check if it fails because of the existing data is still disconnecting. - if (dataConnectionReasons.contains(DataDisallowedReasonType.DATA_IS_DISCONNECTING) - && isHandoverPending(apnContext.getApnTypeBitmask())) { - // Normally we don't retry when isDataAllow() returns false, because that's consider - // pre-condition not met, for example, data not enabled by the user, or airplane - // mode is on. If we retry in those cases, there will be significant power impact. - // DATA_IS_DISCONNECTING is a special case we want to retry, and for the handover - // case only. - log("Data is disconnecting. Will retry handover later."); - return; - } - - // If this is a data retry, we should set the APN state to FAILED so it won't stay - // in RETRYING forever. - if (apnContext.getState() == DctConstants.State.RETRYING) { - apnContext.setState(DctConstants.State.FAILED); - str.append(" Stop retrying."); - } - - if (DBG) log(str.toString()); - ApnContext.requestLog(apnContext, str.toString()); - if (requestType == REQUEST_TYPE_HANDOVER) { - // If fails due to latest preference already changed back to source transport, then - // just fallback (will not attempt handover anymore, and will not tear down the - // data connection on source transport. - boolean fallback = dataConnectionReasons.contains( - DataDisallowedReasonType.ON_OTHER_TRANSPORT); - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, fallback); - } - return; - } - - if (apnContext.getState() == DctConstants.State.FAILED) { - String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable"; - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - apnContext.setState(DctConstants.State.IDLE); - } - int radioTech = getDataRat(); - if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN && mPhone.getServiceState() - .getState() == ServiceState.STATE_IN_SERVICE) { - radioTech = getVoiceRat(); - } - log("service state=" + mPhone.getServiceState()); - apnContext.setConcurrentVoiceAndDataAllowed(mPhone.getServiceStateTracker() - .isConcurrentVoiceAndDataAllowed()); - if (apnContext.getState() == DctConstants.State.IDLE) { - ArrayList waitingApns = - buildWaitingApns(apnContext.getApnType(), radioTech); - if (waitingApns.isEmpty()) { - String str = "trySetupData: X No APN found retValue=false"; - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - if (requestType == REQUEST_TYPE_HANDOVER) { - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, - false); - } - return; - } else { - apnContext.setWaitingApns(waitingApns); - if (DBG) { - log("trySetupData: Create from mAllApnSettings : " - + apnListToString(mAllApnSettings)); - } - } - } - - if (!setupData(apnContext, radioTech, requestType) - && requestType == REQUEST_TYPE_HANDOVER) { - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, false); - } - } - - /** - * Clean up all data connections. Note this is just detach the APN context from the data - * connection. After all APN contexts are detached from the data connection, the data - * connection will be torn down. - * - * @param reason Reason for the clean up. - */ - public void cleanUpAllConnections(String reason) { - log("cleanUpAllConnections"); - Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS); - msg.obj = reason; - sendMessage(msg); - } - - /** - * Clean up all data connections by detaching the APN contexts from the data connections, which - * eventually tearing down all data connections after all APN contexts are detached from the - * data connections. - * - * @param detach {@code true} if detaching APN context from the underlying data connection (when - * no other APN context is attached to the data connection, the data connection will be torn - * down.) {@code false} to only reset the data connection's state machine. - * - * @param reason reason for the clean up. - * @return boolean - true if we did cleanup any connections, false if they - * were already all disconnected. - */ - private boolean cleanUpAllConnectionsInternal(boolean detach, String reason) { - if (DBG) log("cleanUpAllConnectionsInternal: detach=" + detach + " reason=" + reason); - boolean didDisconnect = false; - boolean disableMeteredOnly = false; - - // reasons that only metered apn will be torn down - if (!TextUtils.isEmpty(reason)) { - disableMeteredOnly = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED) || - reason.equals(Phone.REASON_ROAMING_ON) || - reason.equals(Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN); - } - - for (ApnContext apnContext : mApnContexts.values()) { - // Exclude the IMS APN from single data connection case. - if (reason.equals(Phone.REASON_SINGLE_PDN_ARBITRATION) - && apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) { - continue; - } - - if (shouldCleanUpConnection(apnContext, disableMeteredOnly, - reason.equals(Phone.REASON_SINGLE_PDN_ARBITRATION))) { - // TODO - only do cleanup if not disconnected - if (apnContext.isDisconnected() == false) didDisconnect = true; - apnContext.setReason(reason); - cleanUpConnectionInternal(detach, RELEASE_TYPE_DETACH, apnContext); - } else if (DBG) { - log("cleanUpAllConnectionsInternal: APN type " + apnContext.getApnType() - + " shouldn't be cleaned up."); - } - } - - stopNetStatPoll(); - stopDataStallAlarm(); - - // TODO: Do we need mRequestedApnType? - mRequestedApnType = ApnSetting.TYPE_DEFAULT; - - if (areAllDataDisconnected()) { - notifyAllDataDisconnected(); - } - - return didDisconnect; - } - - boolean shouldCleanUpConnection(ApnContext apnContext, boolean disableMeteredOnly, - boolean singlePdn) { - if (apnContext == null) return false; - - // If APN setting is not null and the reason is single PDN arbitration, clean up connection. - ApnSetting apnSetting = apnContext.getApnSetting(); - if (apnSetting != null && singlePdn) return true; - - // If meteredOnly is false, clean up all connections. - if (!disableMeteredOnly) return true; - - // If meteredOnly is true, and apnSetting is null or it's un-metered, no need to clean up. - if (apnSetting == null || !ApnSettingUtils.isMetered(apnSetting, mPhone)) return false; - - boolean isRoaming = mPhone.getServiceState().getDataRoaming(); - boolean isDataRoamingDisabled = !getDataRoamingEnabled(); - boolean isDataDisabled = !mDataEnabledSettings.isDataEnabled( - apnSetting.getApnTypeBitmask()); - - // Should clean up if its data is disabled, or data roaming is disabled while roaming. - return isDataDisabled || (isRoaming && isDataRoamingDisabled); - } - - /** - * Detach the APN context from the associated data connection. This data connection might be - * torn down if no other APN context is attached to it. - * - * @param apnContext The APN context to be detached - */ - void cleanUpConnection(ApnContext apnContext) { - if (DBG) log("cleanUpConnection: apnContext=" + apnContext); - Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION); - msg.arg2 = 0; - msg.obj = apnContext; - sendMessage(msg); - } - - /** - * Detach the APN context from the associated data connection. This data connection will be - * torn down if no other APN context is attached to it. - * - * @param detach {@code true} if detaching APN context from the underlying data connection (when - * no other APN context is attached to the data connection, the data connection will be torn - * down.) {@code false} to only reset the data connection's state machine. - * @param releaseType Data release type. - * @param apnContext The APN context to be detached. - */ - private void cleanUpConnectionInternal(boolean detach, @ReleaseNetworkType int releaseType, - ApnContext apnContext) { - if (apnContext == null) { - if (DBG) log("cleanUpConnectionInternal: apn context is null"); - return; - } - - DataConnection dataConnection = apnContext.getDataConnection(); - String str = "cleanUpConnectionInternal: detach=" + detach + " reason=" - + apnContext.getReason(); - if (VDBG) log(str + " apnContext=" + apnContext); - ApnContext.requestLog(apnContext, str); - if (detach) { - if (apnContext.isDisconnected()) { - // The request is detach and but ApnContext is not connected. - // If apnContext is not enabled anymore, break the linkage to the data connection. - apnContext.releaseDataConnection(""); - } else { - // Connection is still there. Try to clean up. - if (dataConnection != null) { - if (apnContext.getState() != DctConstants.State.DISCONNECTING) { - boolean disconnectAll = false; - if (ApnSetting.TYPE_DUN_STRING.equals(apnContext.getApnType()) - && ServiceState.isCdma(getDataRat())) { - if (DBG) { - log("cleanUpConnectionInternal: disconnectAll DUN connection"); - } - // For CDMA DUN, we need to tear it down immediately. A new data - // connection will be reestablished with correct profile id. - disconnectAll = true; - } - final int generation = apnContext.getConnectionGeneration(); - str = "cleanUpConnectionInternal: tearing down" - + (disconnectAll ? " all" : "") + " using gen#" + generation; - if (DBG) log(str + "apnContext=" + apnContext); - ApnContext.requestLog(apnContext, str); - Pair pair = new Pair<>(apnContext, generation); - Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair); - - if (disconnectAll || releaseType == RELEASE_TYPE_HANDOVER) { - dataConnection.tearDownAll(apnContext.getReason(), releaseType, msg); - } else { - dataConnection.tearDown(apnContext, apnContext.getReason(), msg); - } - - apnContext.setState(DctConstants.State.DISCONNECTING); - } - } else { - // apn is connected but no reference to the data connection. - // Should not be happen, but reset the state in case. - apnContext.setState(DctConstants.State.IDLE); - ApnContext.requestLog( - apnContext, "cleanUpConnectionInternal: connected, bug no dc"); - } - } - } else { - // force clean up the data connection. - if (dataConnection != null) dataConnection.reset(); - apnContext.setState(DctConstants.State.IDLE); - apnContext.setDataConnection(null); - } - - // If there is any outstanding handover request, we need to respond it. - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, false); - - // Make sure reconnection alarm is cleaned up if there is no ApnContext - // associated to the connection. - if (dataConnection != null) { - cancelReconnect(apnContext); - } - str = "cleanUpConnectionInternal: X detach=" + detach + " reason=" - + apnContext.getReason(); - if (DBG) log(str + " apnContext=" + apnContext + " dc=" + apnContext.getDataConnection()); - } - - private Cursor getPreferredApnCursor(int subId) { - Cursor cursor = null; - if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - cursor = mPhone.getContext().getContentResolver().query( - Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, - String.valueOf(subId)), null, null, null, - Telephony.Carriers.DEFAULT_SORT_ORDER); - } - return cursor; - } - - private ApnSetting getPreferredApnFromDB() { - ApnSetting preferredApn = null; - Cursor cursor = getPreferredApnCursor(mPhone.getSubId()); - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - preferredApn = ApnSetting.makeApnSetting(cursor); - } - cursor.close(); - } - if (VDBG) log("getPreferredApnFromDB: preferredApn=" + preferredApn); - return preferredApn; - } - - private void setDefaultPreferredApnIfNeeded() { - ApnSetting defaultPreferredApn = null; - PersistableBundle bundle = getCarrierConfig(); - String defaultPreferredApnName = bundle.getString(CarrierConfigManager - .KEY_DEFAULT_PREFERRED_APN_NAME_STRING); - - if (TextUtils.isEmpty(defaultPreferredApnName) || getPreferredApnFromDB() != null) { - return; - } - - String selection = Telephony.Carriers.APN + " = \"" + defaultPreferredApnName + "\" AND " - + Telephony.Carriers.EDITED_STATUS + " = " + Telephony.Carriers.UNEDITED; - Cursor cursor = mPhone.getContext().getContentResolver().query( - Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, - "filtered/subId/" + mPhone.getSubId()), - null, selection, null, Telephony.Carriers._ID); - - if (cursor != null) { - if (cursor.getCount() > 0) { - if (cursor.moveToFirst()) { - defaultPreferredApn = ApnSetting.makeApnSetting(cursor); - } - } - cursor.close(); - } - - if (defaultPreferredApn != null - && defaultPreferredApn.canHandleType(mRequestedApnType)) { - log("setDefaultPreferredApnIfNeeded: For APN type " - + ApnSetting.getApnTypeString(mRequestedApnType) - + " found default apnSetting " - + defaultPreferredApn); - - setPreferredApn(defaultPreferredApn.getId(), true); - } - - return; - } - - /** - * Check if preferred apn is allowed to edit by user. - * @return {@code true} if it is allowed to edit. - */ - @VisibleForTesting - public boolean isPreferredApnUserEdited() { - boolean isUserEdited = false; - Cursor cursor = getPreferredApnCursor(mPhone.getSubId()); - if (cursor != null) { - if (cursor.getCount() > 0) { - if (cursor.moveToFirst()) { - isUserEdited = cursor.getInt( - cursor.getColumnIndexOrThrow(Telephony.Carriers.EDITED_STATUS)) - == Telephony.Carriers.USER_EDITED; - } - } - cursor.close(); - } - if (VDBG) log("isPreferredApnUserEdited: isUserEdited=" + isUserEdited); - return isUserEdited; - } - - /** - * Fetch the DUN apns - * @return a list of DUN ApnSetting objects - */ - @VisibleForTesting - public @NonNull ArrayList fetchDunApns() { - if (mPhone.getServiceState().getRoaming() && !isPreferredApnUserEdited() - && getCarrierConfig().getBoolean(CarrierConfigManager - .KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL)) { - if (VDBG) log("fetchDunApns: Dun apn is not used in roaming network"); - return new ArrayList(0); - } - - int bearer = getDataRat(); - ArrayList dunCandidates = new ArrayList(); - ArrayList retDunSettings = new ArrayList(); - - if (dunCandidates.isEmpty()) { - if (!ArrayUtils.isEmpty(mAllApnSettings)) { - for (ApnSetting apn : mAllApnSettings) { - if (apn.canHandleType(ApnSetting.TYPE_DUN)) { - dunCandidates.add(apn); - } - } - if (VDBG) log("fetchDunApns: dunCandidates from database: " + dunCandidates); - } - } - - int preferredApnSetId = getPreferredApnSetId(); - ApnSetting preferredApn = getPreferredApnFromDB(); - for (ApnSetting dunSetting : dunCandidates) { - if (dunSetting.canSupportNetworkType( - ServiceState.rilRadioTechnologyToNetworkType(bearer))) { - if (preferredApnSetId == dunSetting.getApnSetId()) { - if (preferredApn != null && preferredApn.equals(dunSetting)) { - // If there is a preferred APN can handled DUN type, prepend it to list to - // use it preferred. - retDunSettings.add(0, dunSetting); - } else { - retDunSettings.add(dunSetting); - } - } - } - } - - if (VDBG) log("fetchDunApns: dunSettings=" + retDunSettings); - return retDunSettings; - } - - private int getPreferredApnSetId() { - // preferapnset uri returns all APNs for the current carrier which have an apn_set_id - // equal to the preferred APN (if no preferred APN, or if the preferred APN has no set id, - // the query will return null) - Cursor c = mPhone.getContext().getContentResolver() - .query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, - "preferapnset/subId/" + mPhone.getSubId()), - new String[] {Telephony.Carriers.APN_SET_ID}, null, null, null); - if (c == null) { - loge("getPreferredApnSetId: cursor is null"); - return Telephony.Carriers.NO_APN_SET_ID; - } - - int setId; - if (c.getCount() < 1) { - loge("getPreferredApnSetId: no APNs found"); - setId = Telephony.Carriers.NO_APN_SET_ID; - } else { - c.moveToFirst(); - setId = c.getInt(0 /* index of Telephony.Carriers.APN_SET_ID */); - } - - if (!c.isClosed()) { - c.close(); - } - return setId; - } - - public boolean hasMatchedTetherApnSetting() { - ArrayList matches = fetchDunApns(); - log("hasMatchedTetherApnSetting: APNs=" + matches); - return matches.size() > 0; - } - - /** - * @return the {@link DataConnection} with the given context id {@code cid}. - */ - public DataConnection getDataConnectionByContextId(int cid) { - return mDcc.getActiveDcByCid(cid); - } - - /** - * @return the {@link DataConnection} with the given APN context. Null if no data connection - * is found. - */ - public @Nullable DataConnection getDataConnectionByApnType(String apnType) { - // TODO: Clean up all APN type in string usage - ApnContext apnContext = mApnContexts.get(apnType); - if (apnContext != null) { - return apnContext.getDataConnection(); - } - return null; - } - - /** - * Check if the data fail cause is a permanent failure (i.e. Frameworks will not retry data - * setup). - * - * @param dcFailCause The data fail cause - * @return {@code true} if the data fail cause is a permanent failure. - */ - @VisibleForTesting - public boolean isPermanentFailure(@DataFailureCause int dcFailCause) { - return (DataFailCause.isPermanentFailure(mPhone.getContext(), dcFailCause, - mPhone.getSubId()) - && (mAttached.get() == false || dcFailCause != DataFailCause.SIGNAL_LOST)); - } - - private DataConnection findFreeDataConnection() { - for (DataConnection dataConnection : mDataConnections.values()) { - boolean inUse = false; - for (ApnContext apnContext : mApnContexts.values()) { - if (apnContext.getDataConnection() == dataConnection) { - inUse = true; - break; - } - } - if (!inUse) { - if (DBG) { - log("findFreeDataConnection: found free DataConnection=" + dataConnection); - } - return dataConnection; - } - } - log("findFreeDataConnection: NO free DataConnection"); - return null; - } - - /** - * Setup a data connection based on given APN type. - * - * @param apnContext APN context - * @param radioTech RAT of the data connection - * @param requestType Data request type - * @return True if successful, otherwise false. - */ - private boolean setupData(ApnContext apnContext, int radioTech, - @RequestNetworkType int requestType) { - if (DBG) { - log("setupData: apnContext=" + apnContext + ", requestType=" - + requestTypeToString(requestType)); - } - ApnContext.requestLog( - apnContext, "setupData. requestType=" + requestTypeToString(requestType)); - ApnSetting apnSetting; - DataConnection dataConnection = null; - - apnSetting = apnContext.getNextApnSetting(); - - if (apnSetting == null) { - if (DBG) log("setupData: return for no apn found!"); - return false; - } - - // profile id is only meaningful when the profile is persistent on the modem. - int profileId = DATA_PROFILE_INVALID; - if (apnSetting.isPersistent()) { - profileId = apnSetting.getProfileId(); - if (profileId == DATA_PROFILE_DEFAULT) { - profileId = getApnProfileID(apnContext.getApnType()); - } - } - - // On CDMA, if we're explicitly asking for DUN, we need have - // a dun-profiled connection so we can't share an existing one - // On GSM/LTE we can share existing apn connections provided they support - // this type. - // If asking for ENTERPRISE, there are no compatible data connections, so skip this check - if ((apnContext.getApnTypeBitmask() != ApnSetting.TYPE_DUN - || ServiceState.isGsm(getDataRat())) - && apnContext.getApnTypeBitmask() != ApnSetting.TYPE_ENTERPRISE) { - dataConnection = checkForCompatibleDataConnection(apnContext, apnSetting); - if (dataConnection != null) { - // Get the apn setting used by the data connection - ApnSetting dataConnectionApnSetting = dataConnection.getApnSetting(); - if (dataConnectionApnSetting != null) { - // Setting is good, so use it. - apnSetting = dataConnectionApnSetting; - } - } - } - if (dataConnection == null) { - if (isOnlySingleDcAllowed(radioTech)) { - if (isHigherPriorityApnContextActive(apnContext)) { - if (DBG) { - log("setupData: Higher priority ApnContext active. Ignoring call"); - } - return false; - } - - // Should not start cleanUp if the setupData is for IMS APN - // or retry of same APN(State==RETRYING). - if (!apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING) - && (apnContext.getState() != DctConstants.State.RETRYING)) { - // Only lower priority calls left. Disconnect them all in this single PDP case - // so that we can bring up the requested higher priority call (once we receive - // response for deactivate request for the calls we are about to disconnect - if (cleanUpAllConnectionsInternal(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) { - // If any call actually requested to be disconnected, means we can't - // bring up this connection yet as we need to wait for those data calls - // to be disconnected. - if (DBG) log("setupData: Some calls are disconnecting first." - + " Wait and retry"); - return false; - } - } - - // No other calls are active, so proceed - if (DBG) log("setupData: Single pdp. Continue setting up data call."); - } - - dataConnection = findFreeDataConnection(); - - if (dataConnection == null) { - dataConnection = createDataConnection(); - } - - if (dataConnection == null) { - if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD"); - return false; - } - } - final int generation = apnContext.incAndGetConnectionGeneration(); - if (DBG) { - log("setupData: dc=" + dataConnection + " apnSetting=" + apnSetting + " gen#=" - + generation); - } - - apnContext.setDataConnection(dataConnection); - apnContext.setApnSetting(apnSetting); - apnContext.setState(DctConstants.State.CONNECTING); - - Message msg = obtainMessage(); - msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE; - msg.obj = new Pair(apnContext, generation); - - ApnSetting preferredApn = getPreferredApn(); - boolean isPreferredApn = apnSetting.equals(preferredApn); - dataConnection.bringUp(apnContext, profileId, radioTech, msg, generation, requestType, - mPhone.getSubId(), isPreferredApn); - - if (DBG) { - if (isPreferredApn) { - log("setupData: initing! isPreferredApn=" + isPreferredApn - + ", apnSetting={" + apnSetting.toString() + "}"); - } else { - String preferredApnStr = preferredApn == null ? "null" : preferredApn.toString(); - log("setupData: initing! isPreferredApn=" + isPreferredApn - + ", apnSetting={" + apnSetting + "}" - + ", preferredApn={" + preferredApnStr + "}"); - } - } - return true; - } - - // Get the allowed APN types for initial attach. The order in the returned list represent - // the order of APN types that should be used for initial attach. - private @NonNull @ApnType List getAllowedInitialAttachApnTypes() { - PersistableBundle bundle = getCarrierConfig(); - if (bundle != null) { - String[] apnTypesArray = bundle.getStringArray( - CarrierConfigManager.KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY); - if (apnTypesArray != null) { - return Arrays.stream(apnTypesArray) - .map(ApnSetting::getApnTypesBitmaskFromString) - .collect(Collectors.toList()); - } - } - - return Collections.emptyList(); - } - - protected void setInitialAttachApn() { - ApnSetting apnSetting = null; - int preferredApnSetId = getPreferredApnSetId(); - ArrayList allApnSettings = new ArrayList<>(); - if (mPreferredApn != null) { - // Put the preferred apn at the beginning of the list. It's okay to have a duplicate - // when later on mAllApnSettings get added. That would not change the selection result. - allApnSettings.add(mPreferredApn); - } - allApnSettings.addAll(mAllApnSettings); - - // Get the allowed APN types for initial attach. Note that if none of the APNs has the - // allowed APN types, then the initial attach will not be performed. - List allowedApnTypes = getAllowedInitialAttachApnTypes(); - for (int allowedApnType : allowedApnTypes) { - apnSetting = allApnSettings.stream() - .filter(apn -> apn.canHandleType(allowedApnType)) - .filter(apn -> (apn.getApnSetId() == preferredApnSetId - || apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID)) - .findFirst() - .orElse(null); - if (apnSetting != null) break; - } - - if (DBG) { - log("setInitialAttachApn: Allowed APN types=" + allowedApnTypes.stream() - .map(ApnSetting::getApnTypeString) - .collect(Collectors.joining(","))); - } - - if (apnSetting == null) { - if (DBG) log("setInitialAttachApn: X There in no available apn."); - } else { - if (DBG) log("setInitialAttachApn: X selected APN=" + apnSetting); - mDataServiceManager.setInitialAttachApn(new DataProfile.Builder() - .setApnSetting(apnSetting) - .setPreferred(apnSetting.equals(getPreferredApn())) - .build(), - mPhone.getServiceState().getDataRoamingFromRegistration(), null); - } - } - - /** - * Handles changes to the APN database. - */ - private void onApnChanged() { - if (mPhone instanceof GsmCdmaPhone) { - // The "current" may no longer be valid. MMS depends on this to send properly. TBD - ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider(); - } - - // TODO: It'd be nice to only do this if the changed entrie(s) - // match the current operator. - if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections"); - mDataThrottler.reset(); - setDefaultPreferredApnIfNeeded(); - createAllApnList(); - setDataProfilesAsNeeded(); - setInitialAttachApn(); - cleanUpConnectionsOnUpdatedApns(isAnyDataConnected(), Phone.REASON_APN_CHANGED); - - // FIXME: See bug 17426028 maybe no conditional is needed. - if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubscriptionId()) { - setupDataOnAllConnectableApns(Phone.REASON_APN_CHANGED, RetryFailures.ALWAYS); - } - } - - /** - * "Active" here means ApnContext isEnabled() and not in FAILED state - * @param apnContext to compare with - * @return true if higher priority active apn found - */ - private boolean isHigherPriorityApnContextActive(ApnContext apnContext) { - if (apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) { - return false; - } - - for (ApnContext otherContext : mPrioritySortedApnContexts) { - if (otherContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) { - continue; - } - if (apnContext.getApnType().equalsIgnoreCase(otherContext.getApnType())) return false; - if (otherContext.isEnabled() && otherContext.getState() != DctConstants.State.FAILED) { - return true; - } - } - return false; - } - - /** - * Reports if we support multiple connections or not. - * This is a combination of factors, based on carrier and RAT. - * @param rilRadioTech the RIL Radio Tech currently in use - * @return true if only single DataConnection is allowed - */ - private boolean isOnlySingleDcAllowed(int rilRadioTech) { - int networkType = ServiceState.rilRadioTechnologyToNetworkType(rilRadioTech); - // Default single dc rats with no knowledge of carrier - int[] singleDcRats = null; - // get the carrier specific value, if it exists, from CarrierConfigManager. - // generally configManager and bundle should not be null, but if they are it should be okay - // to leave singleDcRats null as well - CarrierConfigManager configManager = (CarrierConfigManager) - mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - PersistableBundle bundle = configManager.getConfigForSubId(mPhone.getSubId()); - if (bundle != null) { - singleDcRats = bundle.getIntArray( - CarrierConfigManager.KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY); - } - } - boolean onlySingleDcAllowed = false; - if (TelephonyUtils.IS_DEBUGGABLE - && SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) { - onlySingleDcAllowed = true; - } - if (singleDcRats != null) { - for (int i = 0; i < singleDcRats.length && !onlySingleDcAllowed; i++) { - if (networkType == singleDcRats[i]) { - onlySingleDcAllowed = true; - } - } - } - - if (DBG) { - log("isOnlySingleDcAllowed(" + TelephonyManager.getNetworkTypeName(networkType) + "): " - + onlySingleDcAllowed); - } - return onlySingleDcAllowed; - } - - void sendRestartRadio() { - if (DBG)log("sendRestartRadio:"); - Message msg = obtainMessage(DctConstants.EVENT_RESTART_RADIO); - sendMessage(msg); - } - - private void restartRadio() { - if (DBG) log("restartRadio: ************TURN OFF RADIO**************"); - cleanUpAllConnectionsInternal(true, Phone.REASON_RADIO_TURNED_OFF); - mPhone.getServiceStateTracker().powerOffRadioSafely(); - /* Note: no need to call setRadioPower(true). Assuming the desired - * radio power state is still ON (as tracked by ServiceStateTracker), - * ServiceStateTracker will call setRadioPower when it receives the - * RADIO_STATE_CHANGED notification for the power off. And if the - * desired power state has changed in the interim, we don't want to - * override it with an unconditional power on. - */ - } - - /** - * Return true if data connection need to be setup after disconnected due to - * reason. - * - * @param apnContext APN context - * @return true if try setup data connection is need for this reason - */ - private boolean retryAfterDisconnected(ApnContext apnContext) { - boolean retry = true; - String reason = apnContext.getReason(); - - if (Phone.REASON_RADIO_TURNED_OFF.equals(reason) || (isOnlySingleDcAllowed(getDataRat()) - && isHigherPriorityApnContextActive(apnContext))) { - retry = false; - } - return retry; - } - - protected void startReconnect(long delay, ApnContext apnContext, - @RequestNetworkType int requestType) { - apnContext.setState(DctConstants.State.RETRYING); - Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT, - mPhone.getSubId(), requestType, apnContext); - cancelReconnect(apnContext); - - // Wait a bit before trying the next APN, so that - // we're not tying up the RIL command channel - sendMessageDelayed(msg, delay); - - if (DBG) { - log("startReconnect: delay=" + delay + ", apn=" - + apnContext + ", reason=" + apnContext.getReason() - + ", subId=" + mPhone.getSubId() + ", request type=" - + requestTypeToString(requestType)); - } - } - - /** - * Cancels the alarm associated with apnContext. - * - * @param apnContext on which the alarm should be stopped. - */ - protected void cancelReconnect(ApnContext apnContext) { - if (apnContext == null) return; - - if (DBG) { - log("cancelReconnect: apn=" + apnContext); - } - removeMessages(DctConstants.EVENT_DATA_RECONNECT, apnContext); - } - - /** - * Read configuration. Note this must be called after carrier config is ready. - */ - private void readConfiguration() { - log("readConfiguration"); - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - // Auto attach is for cellular only. - mAutoAttachOnCreationConfig = mPhone.getContext().getResources() - .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation); - } - - mAutoAttachEnabled.set(false); - setDefaultPreferredApnIfNeeded(); - read5GConfiguration(); - registerSettingsObserver(); - SubscriptionPlan[] plans = mNetworkPolicyManager.getSubscriptionPlans( - mPhone.getSubId(), mPhone.getContext().getOpPackageName()); - mSubscriptionPlans = plans == null ? Collections.emptyList() : Arrays.asList(plans); - if (DBG) log("SubscriptionPlans initialized: " + mSubscriptionPlans); - reevaluateUnmeteredConnections(); - mConfigReady = true; - } - - /** - * @return {@code true} if carrier config has been applied. - */ - private boolean isCarrierConfigApplied() { - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); - if (b != null) { - return CarrierConfigManager.isConfigForIdentifiedCarrier(b); - } - } - return false; - } - - private void onCarrierConfigChanged() { - if (DBG) log("onCarrierConfigChanged"); - - if (!isCarrierConfigApplied()) { - log("onCarrierConfigChanged: Carrier config is not ready yet."); - return; - } - - readConfiguration(); - - if (mSimState == TelephonyManager.SIM_STATE_LOADED) { - setDefaultDataRoamingEnabled(); - createAllApnList(); - setDataProfilesAsNeeded(); - setInitialAttachApn(); - sortApnContextByPriority(); - cleanUpConnectionsOnUpdatedApns(true, Phone.REASON_CARRIER_CHANGE); - setupDataOnAllConnectableApns(Phone.REASON_CARRIER_CHANGE, RetryFailures.ALWAYS); - } else { - log("onCarrierConfigChanged: SIM is not loaded yet."); - } - } - - private void onSimAbsent() { - if (DBG) log("onSimAbsent"); - - mConfigReady = false; - cleanUpAllConnectionsInternal(true, Phone.REASON_SIM_NOT_READY); - mAllApnSettings.clear(); - mAutoAttachOnCreationConfig = false; - // Clear auto attach as modem is expected to do a new attach once SIM is ready - mAutoAttachEnabled.set(false); - // In no-sim case, we should still send the emergency APN to the modem, if there is any. - createAllApnList(); - setDataProfilesAsNeeded(); - } - - private void onSimStateUpdated(@SimState int simState) { - mSimState = simState; - - if (DBG) { - log("onSimStateUpdated: state=" + SubscriptionInfoUpdater.simStateString(mSimState)); - } - - if (mSimState == TelephonyManager.SIM_STATE_ABSENT) { - onSimAbsent(); - } else if (mSimState == TelephonyManager.SIM_STATE_LOADED) { - mDataThrottler.reset(); - if (mConfigReady) { - createAllApnList(); - setDataProfilesAsNeeded(); - setInitialAttachApn(); - setupDataOnAllConnectableApns(Phone.REASON_SIM_LOADED, RetryFailures.ALWAYS); - } else { - log("onSimStateUpdated: config not ready yet."); - } - } - } - - private void onApnUnthrottled(String apn) { - if (apn != null) { - ApnSetting apnSetting = mAllApnSettings.stream() - .filter(as -> apn.equals(as.getApnName())) - .findFirst() - .orElse(null); - if (apnSetting != null) { - @ApnType int apnTypes = apnSetting.getApnTypeBitmask(); - mDataThrottler.setRetryTime(apnTypes, RetryManager.NO_SUGGESTED_RETRY_DELAY, - REQUEST_TYPE_NORMAL); - } else { - loge("EVENT_APN_UNTHROTTLED: Invalid APN passed: " + apn); - } - } else { - loge("EVENT_APN_UNTHROTTLED: apn is null"); - } - } - - private void onTrafficDescriptorsUpdated() { - for (ApnContext apnContext : mPrioritySortedApnContexts) { - if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE - && apnContext.getApnSetting().getPermanentFailed()) { - setupDataOnConnectableApn( - apnContext, Phone.REASON_TRAFFIC_DESCRIPTORS_UPDATED, RetryFailures.ALWAYS); - } - } - } - - private DataConnection checkForCompatibleDataConnection(ApnContext apnContext, - ApnSetting nextApn) { - int apnType = apnContext.getApnTypeBitmask(); - ArrayList dunSettings = null; - - if (ApnSetting.TYPE_DUN == apnType) { - dunSettings = fetchDunApns(); - } - if (DBG) { - log("checkForCompatibleDataConnection: apnContext=" + apnContext); - } - - DataConnection potentialDc = null; - for (DataConnection curDc : mDataConnections.values()) { - if (curDc != null) { - ApnSetting apnSetting = curDc.getApnSetting(); - log("apnSetting: " + apnSetting); - if (dunSettings != null && dunSettings.size() > 0) { - for (ApnSetting dunSetting : dunSettings) { - //This ignore network type as a check which is ok because that's checked - //when calculating dun candidates. - if (areCompatible(dunSetting, apnSetting)) { - if (curDc.isActive()) { - if (DBG) { - log("checkForCompatibleDataConnection:" - + " found dun conn=" + curDc); - } - return curDc; - } else if (curDc.isActivating()) { - potentialDc = curDc; - } - } - } - } else if (isApnSettingCompatible(curDc, apnType)) { - if (curDc.isActive()) { - if (DBG) { - log("checkForCompatibleDataConnection:" - + " found canHandle conn=" + curDc); - } - return curDc; - } else if (curDc.isActivating() - || (apnSetting != null && apnSetting.equals(nextApn))) { - potentialDc = curDc; - } - } - } - } - - if (DBG) { - log("checkForCompatibleDataConnection: potential dc=" + potentialDc); - } - return potentialDc; - } - - private boolean isApnSettingCompatible(DataConnection dc, int apnType) { - ApnSetting apnSetting = dc.getApnSetting(); - if (apnSetting == null) return false; - - // Nothing can be compatible with type ENTERPRISE - for (ApnContext apnContext : dc.getApnContexts()) { - if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { - return false; - } - } - - return apnSetting.canHandleType(apnType); - } - - private void addHandoverCompleteMsg(Message onCompleteMsg, - @ApnType int apnType) { - if (onCompleteMsg != null) { - List messageList = mHandoverCompletionMsgs.get(apnType); - if (messageList == null) messageList = new ArrayList<>(); - messageList.add(onCompleteMsg); - mHandoverCompletionMsgs.put(apnType, messageList); - } - } - - private void sendHandoverCompleteMessages(@ApnType int apnType, boolean success, - boolean fallbackOnFailedHandover) { - List messageList = mHandoverCompletionMsgs.get(apnType); - if (messageList != null) { - for (Message msg : messageList) { - sendHandoverCompleteMsg(msg, success, mTransportType, fallbackOnFailedHandover); - } - messageList.clear(); - } - } - - private void sendHandoverCompleteMsg(Message message, boolean success, - @TransportType int transport, boolean doFallbackOnFailedHandover) { - if (message == null) return; - - Bundle b = message.getData(); - b.putBoolean(DATA_COMPLETE_MSG_EXTRA_SUCCESS, success); - b.putInt(DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE, transport); - b.putBoolean(DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK, doFallbackOnFailedHandover); - message.sendToTarget(); - } - - private static boolean shouldFallbackOnFailedHandover( - @HandoverFailureMode int handoverFailureMode, - @RequestNetworkType int requestType, - @DataFailureCause int cause) { - if (requestType != REQUEST_TYPE_HANDOVER) { - //The fallback is only relevant if the request is a handover - return false; - } else if (handoverFailureMode == HANDOVER_FAILURE_MODE_DO_FALLBACK) { - return true; - } else if (handoverFailureMode == HANDOVER_FAILURE_MODE_LEGACY) { - return cause == DataFailCause.HANDOFF_PREFERENCE_CHANGED; - } else { - return false; - } - } - - /** - * Calculates the new request type that will be used the next time a data connection retries - * after a failed data call attempt. - */ - @RequestNetworkType - public static int calculateNewRetryRequestType(@HandoverFailureMode int handoverFailureMode, - @RequestNetworkType int requestType, - @DataFailureCause int cause) { - boolean fallbackOnFailedHandover = - shouldFallbackOnFailedHandover(handoverFailureMode, requestType, cause); - if (requestType != REQUEST_TYPE_HANDOVER) { - //The fallback is only relevant if the request is a handover - return requestType; - } - - if (fallbackOnFailedHandover) { - // Since fallback is happening, the request type is really "NONE". - return REQUEST_TYPE_NORMAL; - } - - if (handoverFailureMode == HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL) { - return REQUEST_TYPE_NORMAL; - } - - return REQUEST_TYPE_HANDOVER; - } - - public void enableApn(@ApnType int apnType, @RequestNetworkType int requestType, - Message onHandoverCompleteMsg) { - sendMessage(obtainMessage(DctConstants.EVENT_ENABLE_APN, apnType, requestType, - onHandoverCompleteMsg)); - } - - private void onEnableApn(@ApnType int apnType, @RequestNetworkType int requestType, - Message onHandoverCompleteMsg) { - ApnContext apnContext = mApnContextsByType.get(apnType); - if (apnContext == null) { - loge("onEnableApn(" + apnType + "): NO ApnContext"); - if (onHandoverCompleteMsg != null) { - sendHandoverCompleteMsg(onHandoverCompleteMsg, false, mTransportType, false); - } - return; - } - - String str = "onEnableApn: apnType=" + ApnSetting.getApnTypeString(apnType) - + ", request type=" + requestTypeToString(requestType); - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - - if (!apnContext.isDependencyMet()) { - apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET); - apnContext.setEnabled(true); - str = "onEnableApn: dependency is not met."; - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - if (onHandoverCompleteMsg != null) { - sendHandoverCompleteMsg(onHandoverCompleteMsg, false, mTransportType, false); - } - return; - } - - if (apnContext.isReady()) { - DctConstants.State state = apnContext.getState(); - switch(state) { - case CONNECTING: - if (onHandoverCompleteMsg != null) { - if (DBG) { - log("onEnableApn: already in CONNECTING state. Handover request " - + "will be responded after connected."); - } - addHandoverCompleteMsg(onHandoverCompleteMsg, apnType); - } else { - if (DBG) log("onEnableApn: in CONNECTING state. Exit now."); - } - return; - case CONNECTED: - if (onHandoverCompleteMsg != null) { - sendHandoverCompleteMsg(onHandoverCompleteMsg, true, mTransportType, - false); - if (DBG) { - log("onEnableApn: already in CONNECTED state. Consider as handover " - + "succeeded"); - } - } else { - if (DBG) log("onEnableApn: APN in CONNECTED state. Exit now."); - } - return; - case IDLE: - case FAILED: - case RETRYING: - // We're "READY" but not active so disconnect (cleanup = true) and - // connect (trySetup = true) to be sure we retry the connection. - apnContext.setReason(Phone.REASON_DATA_ENABLED); - break; - } - } else { - if (apnContext.isEnabled()) { - apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET); - } else { - apnContext.setReason(Phone.REASON_DATA_ENABLED); - } - if (apnContext.getState() == DctConstants.State.FAILED) { - apnContext.setState(DctConstants.State.IDLE); - } - } - apnContext.setEnabled(true); - apnContext.resetErrorCodeRetries(); - - if (mConfigReady || apnContext.getApnTypeBitmask() == ApnSetting.TYPE_EMERGENCY) { - trySetupData(apnContext, requestType, onHandoverCompleteMsg); - } else { - log("onEnableApn: config not ready yet."); - } - } - - public void disableApn(@ApnType int apnType, @ReleaseNetworkType int releaseType) { - sendMessage(obtainMessage(DctConstants.EVENT_DISABLE_APN, apnType, releaseType)); - } - - private void onDisableApn(@ApnType int apnType, - @ReleaseNetworkType int releaseType) { - ApnContext apnContext = mApnContextsByType.get(apnType); - if (apnContext == null) { - loge("disableApn(" + apnType + "): NO ApnContext"); - return; - } - - boolean cleanup = false; - String str = "onDisableApn: apnType=" + ApnSetting.getApnTypeString(apnType) - + ", release type=" + releaseTypeToString(releaseType); - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - - if (apnContext.isReady()) { - cleanup = (releaseType == RELEASE_TYPE_DETACH - || releaseType == RELEASE_TYPE_HANDOVER); - if (apnContext.isDependencyMet()) { - apnContext.setReason(Phone.REASON_DATA_DISABLED_INTERNAL); - // If ConnectivityService has disabled this network, stop trying to bring - // it up, but do not tear it down - ConnectivityService will do that - // directly by talking with the DataConnection. - // - // This doesn't apply to DUN. When the user disable tethering, we would like to - // detach the APN context from the data connection so the data connection can be - // torn down if no other APN context attached to it. - if (ApnSetting.TYPE_DUN_STRING.equals(apnContext.getApnType()) - || apnContext.getState() != DctConstants.State.CONNECTED) { - str = "Clean up the connection. Apn type = " + apnContext.getApnType() - + ", state = " + apnContext.getState(); - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - cleanup = true; - } - } else { - apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET); - } - } - - apnContext.setEnabled(false); - if (cleanup) { - cleanUpConnectionInternal(true, releaseType, apnContext); - } - - if (isOnlySingleDcAllowed(getDataRat()) && !isHigherPriorityApnContextActive(apnContext)) { - if (DBG) log("disableApn:isOnlySingleDcAllowed true & higher priority APN disabled"); - // If the highest priority APN is disabled and only single - // data call is allowed, try to setup data call on other connectable APN. - setupDataOnAllConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION, - RetryFailures.ALWAYS); - } - } - - /** - * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value for user modification only - */ - public void setDataRoamingEnabledByUser(boolean enabled) { - mDataEnabledSettings.setDataRoamingEnabled(enabled); - setDataRoamingFromUserAction(true); - if (DBG) { - log("setDataRoamingEnabledByUser: set phoneSubId=" + mPhone.getSubId() - + " isRoaming=" + enabled); - } - } - - /** - * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value. - */ - public boolean getDataRoamingEnabled() { - boolean isDataRoamingEnabled = mDataEnabledSettings.getDataRoamingEnabled(); - - if (VDBG) { - log("getDataRoamingEnabled: phoneSubId=" + mPhone.getSubId() - + " isDataRoamingEnabled=" + isDataRoamingEnabled); - } - return isDataRoamingEnabled; - } - - /** - * Set default value for {@link android.provider.Settings.Global#DATA_ROAMING} - * if the setting is not from user actions. default value is based on carrier config and system - * properties. - */ - private void setDefaultDataRoamingEnabled() { - // For single SIM phones, this is a per phone property. - String setting = Settings.Global.DATA_ROAMING; - boolean useCarrierSpecificDefault = false; - if (mTelephonyManager.getSimCount() != 1) { - setting = setting + mPhone.getSubId(); - try { - Settings.Global.getInt(mResolver, setting); - } catch (SettingNotFoundException ex) { - // For msim, update to carrier default if uninitialized. - useCarrierSpecificDefault = true; - } - } else if (!isDataRoamingFromUserAction()) { - // for single sim device, update to carrier default if user action is not set - useCarrierSpecificDefault = true; - } - log("setDefaultDataRoamingEnabled: useCarrierSpecificDefault " - + useCarrierSpecificDefault); - if (useCarrierSpecificDefault) { - boolean defaultVal = mDataEnabledSettings.getDefaultDataRoamingEnabled(); - mDataEnabledSettings.setDataRoamingEnabled(defaultVal); - } - } - - private boolean isDataRoamingFromUserAction() { - final SharedPreferences sp = PreferenceManager - .getDefaultSharedPreferences(mPhone.getContext()); - // since we don't want to unset user preference from system update, pass true as the default - // value if shared pref does not exist and set shared pref to false explicitly from factory - // reset. - if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) { - sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit(); - } - return sp.getBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true); - } - - private void setDataRoamingFromUserAction(boolean isUserAction) { - final SharedPreferences.Editor sp = PreferenceManager - .getDefaultSharedPreferences(mPhone.getContext()).edit(); - sp.putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, isUserAction).commit(); - } - - // When the data roaming status changes from roaming to non-roaming. - private void onDataRoamingOff() { - if (DBG) log("onDataRoamingOff"); - - reevaluateDataConnections(); - - if (!getDataRoamingEnabled()) { - // TODO: Remove this once all old vendor RILs are gone. We don't need to set initial apn - // attach and send the data profile again as the modem should have both roaming and - // non-roaming protocol in place. Modem should choose the right protocol based on the - // roaming condition. - setDataProfilesAsNeeded(); - setInitialAttachApn(); - - // If the user did not enable data roaming, now when we transit from roaming to - // non-roaming, we should try to reestablish the data connection. - - setupDataOnAllConnectableApns(Phone.REASON_ROAMING_OFF, RetryFailures.ALWAYS); - } - } - - // This method is called - // 1. When the data roaming status changes from non-roaming to roaming. - // 2. When allowed data roaming settings is changed by the user. - private void onDataRoamingOnOrSettingsChanged(int messageType) { - if (DBG) log("onDataRoamingOnOrSettingsChanged"); - // Used to differentiate data roaming turned on vs settings changed. - boolean settingChanged = (messageType == DctConstants.EVENT_ROAMING_SETTING_CHANGE); - - // Check if the device is actually data roaming - if (!mPhone.getServiceState().getDataRoaming()) { - if (DBG) log("device is not roaming. ignored the request."); - return; - } - - checkDataRoamingStatus(settingChanged); - - if (getDataRoamingEnabled()) { - // If the restricted data was brought up when data roaming is disabled, and now users - // enable data roaming, we need to re-evaluate the conditions and possibly change the - // network's capability. - if (settingChanged) { - reevaluateDataConnections(); - } - - if (DBG) log("onDataRoamingOnOrSettingsChanged: setup data on roaming"); - - setupDataOnAllConnectableApns(Phone.REASON_ROAMING_ON, RetryFailures.ALWAYS); - } else { - // If the user does not turn on data roaming, when we transit from non-roaming to - // roaming, we need to tear down the data connection otherwise the user might be - // charged for data roaming usage. - if (DBG) log("onDataRoamingOnOrSettingsChanged: Tear down data connection on roaming."); - cleanUpAllConnectionsInternal(true, Phone.REASON_ROAMING_ON); - } - } - - // We want to track possible roaming data leakage. Which is, if roaming setting - // is disabled, yet we still setup a roaming data connection or have a connected ApnContext - // switched to roaming. When this happens, we log it in a local log. - private void checkDataRoamingStatus(boolean settingChanged) { - if (!settingChanged && !getDataRoamingEnabled() - && mPhone.getServiceState().getDataRoaming()) { - for (ApnContext apnContext : mApnContexts.values()) { - if (apnContext.getState() == DctConstants.State.CONNECTED) { - mDataRoamingLeakageLog.log("PossibleRoamingLeakage " - + " connection params: " + (apnContext.getDataConnection() != null - ? apnContext.getDataConnection().getConnectionParams() : "")); - } - } - } - } - - private void onRadioAvailable() { - if (DBG) log("onRadioAvailable"); - if (!areAllDataDisconnected()) { - cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, null); - } - } - - private void onRadioOffOrNotAvailable() { - // Make sure our reconnect delay starts at the initial value - // next time the radio comes on - - mReregisterOnReconnectFailure = false; - - // Clear auto attach as modem is expected to do a new attach - mAutoAttachEnabled.set(false); - - if (mPhone.getSimulatedRadioControl() != null) { - // Assume data is connected on the simulator - // FIXME this can be improved - log("We're on the simulator; assuming radio off is meaningless"); - } else { - if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections"); - cleanUpAllConnectionsInternal(false, Phone.REASON_RADIO_TURNED_OFF); - } - } - - private void completeConnection(ApnContext apnContext, @RequestNetworkType int type) { - - if (DBG) log("completeConnection: successful, notify the world apnContext=" + apnContext); - - if (mIsProvisioning && !TextUtils.isEmpty(mProvisioningUrl)) { - if (DBG) { - log("completeConnection: MOBILE_PROVISIONING_ACTION url=" - + mProvisioningUrl); - } - Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, - Intent.CATEGORY_APP_BROWSER); - newIntent.setData(Uri.parse(mProvisioningUrl)); - newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | - Intent.FLAG_ACTIVITY_NEW_TASK); - try { - mPhone.getContext().startActivity(newIntent); - } catch (ActivityNotFoundException e) { - loge("completeConnection: startActivityAsUser failed" + e); - } - } - mIsProvisioning = false; - mProvisioningUrl = null; - if (mProvisioningSpinner != null) { - sendMessage(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, - mProvisioningSpinner)); - } - - startNetStatPoll(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - - PersistableBundle b = getCarrierConfig(); - if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT - && b.getBoolean(CarrierConfigManager - .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) { - NotificationManager notificationManager = (NotificationManager) - mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.cancel(Integer.toString(mPhone.getSubId()), - NO_DATA_NOTIFICATION); - } - } - - /** - * A SETUP (aka bringUp) has completed, possibly with an error. If - * there is an error this method will call {@link #onDataSetupCompleteError}. - */ - protected void onDataSetupComplete(ApnContext apnContext, boolean success, - @DataFailureCause int cause, @RequestNetworkType int requestType, - @HandoverFailureMode int handoverFailureMode) { - boolean fallbackOnFailedHandover = shouldFallbackOnFailedHandover( - handoverFailureMode, requestType, cause); - - if (success && (handoverFailureMode != DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN - && handoverFailureMode != DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY)) { - Log.wtf(mLogTag, "bad failure mode: " - + DataCallResponse.failureModeToString(handoverFailureMode)); - } else if (handoverFailureMode - != DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER - && cause != DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE) { - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), success, - fallbackOnFailedHandover); - } - - if (success) { - DataConnection dataConnection = apnContext.getDataConnection(); - - if (RADIO_TESTS) { - // Note: To change radio.test.onDSC.null.dcac from command line you need to - // adb root and adb remount and from the command line you can only change the - // value to 1 once. To change it a second time you can reboot or execute - // adb shell stop and then adb shell start. The command line to set the value is: - // adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');" - ContentResolver cr = mPhone.getContext().getContentResolver(); - String radioTestProperty = "radio.test.onDSC.null.dcac"; - if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) { - log("onDataSetupComplete: " + radioTestProperty + - " is true, set dcac to null and reset property to false"); - dataConnection = null; - Settings.System.putInt(cr, radioTestProperty, 0); - log("onDataSetupComplete: " + radioTestProperty + "=" + - Settings.System.getInt(mPhone.getContext().getContentResolver(), - radioTestProperty, -1)); - } - } - if (dataConnection == null) { - log("onDataSetupComplete: no connection to DC, handle as error"); - onDataSetupCompleteError(apnContext, requestType, false); - } else { - ApnSetting apn = apnContext.getApnSetting(); - if (DBG) { - log("onDataSetupComplete: success apn=" + (apn == null ? "unknown" - : apn.getApnName())); - } - - // everything is setup - if (TextUtils.equals(apnContext.getApnType(), ApnSetting.TYPE_DEFAULT_STRING) - && mCanSetPreferApn && mPreferredApn == null) { - if (DBG) log("onDataSetupComplete: PREFERRED APN is null"); - mPreferredApn = apn; - if (mPreferredApn != null) { - setPreferredApn(mPreferredApn.getId()); - } - } - - // A connection is setup - apnContext.setState(DctConstants.State.CONNECTED); - - checkDataRoamingStatus(false); - - boolean isProvApn = apnContext.isProvisioningApn(); - final ConnectivityManager cm = (ConnectivityManager) mPhone.getContext() - .getSystemService(Context.CONNECTIVITY_SERVICE); - if (mProvisionBroadcastReceiver != null) { - mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); - mProvisionBroadcastReceiver = null; - } - - if ((!isProvApn) || mIsProvisioning) { - if (mIsProvisioning) { - // Hide any notification that was showing previously - hideProvisioningNotification(); - } - - // Complete the connection normally notifying the world we're connected. - // We do this if this isn't a special provisioning apn or if we've been - // told its time to provision. - completeConnection(apnContext, requestType); - } else { - // This is a provisioning APN that we're reporting as connected. Later - // when the user desires to upgrade this to a "default" connection, - // mIsProvisioning == true, we'll go through the code path above. - // mIsProvisioning becomes true when CMD_ENABLE_MOBILE_PROVISIONING - // is sent to the DCT. - if (DBG) { - log("onDataSetupComplete: successful, BUT send connected to prov apn as" - + " mIsProvisioning:" + mIsProvisioning + " == false" - + " && (isProvisioningApn:" + isProvApn + " == true"); - } - - // While radio is up, grab provisioning URL. The URL contains ICCID which - // disappears when radio is off. - mProvisionBroadcastReceiver = new ProvisionNotificationBroadcastReceiver( - mPhone.getMobileProvisioningUrl(), - mTelephonyManager.getNetworkOperatorName()); - mPhone.getContext().registerReceiver(mProvisionBroadcastReceiver, - new IntentFilter(INTENT_PROVISION)); - - // Put up user notification that sign-in is required. - showProvisioningNotification(); - - // Turn off radio to save battery and avoid wasting carrier resources. - // The network isn't usable and network validation will just fail anyhow. - setRadio(false); - } - if (DBG) { - log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType()); - } - if (TelephonyUtils.IS_DEBUGGABLE) { - // adb shell setprop persist.radio.test.pco [pco_val] - String radioTestProperty = "persist.radio.test.pco"; - int pcoVal = SystemProperties.getInt(radioTestProperty, -1); - if (pcoVal != -1) { - log("PCO testing: read pco value from persist.radio.test.pco " + pcoVal); - final byte[] value = new byte[1]; - value[0] = (byte) pcoVal; - final Intent intent = - new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE); - intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, ApnSetting.TYPE_DEFAULT); - intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL, - ApnSetting.PROTOCOL_IPV4V6); - intent.putExtra(TelephonyManager.EXTRA_PCO_ID, 0xFF00); - intent.putExtra(TelephonyManager.EXTRA_PCO_VALUE, value); - mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); - } - } - } - } else { - if (DBG) { - ApnSetting apn = apnContext.getApnSetting(); - log("onDataSetupComplete: error apn=" + apn.getApnName() + ", cause=" - + DataFailCause.toString(cause) + ", requestType=" - + requestTypeToString(requestType)); - } - if (DataFailCause.isEventLoggable(cause)) { - // Log this failure to the Event Logs. - int cid = getCellLocationId(); - EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL, - cause, cid, mTelephonyManager.getNetworkType()); - } - ApnSetting apn = apnContext.getApnSetting(); - - // Compose broadcast intent send to the specific carrier signaling receivers - Intent intent = new Intent(TelephonyManager - .ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED); - intent.putExtra(TelephonyManager.EXTRA_DATA_FAIL_CAUSE, cause); - intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, - ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType())); - mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); - - if (DataFailCause.isRadioRestartFailure(mPhone.getContext(), cause, mPhone.getSubId()) - || apnContext.restartOnError(cause)) { - if (DBG) log("Modem restarted."); - sendRestartRadio(); - } - - // If the data call failure cause is a permanent failure, we mark the APN as permanent - // failed. - if (isPermanentFailure(cause)) { - log("cause=" + DataFailCause.toString(cause) - + ", mark apn as permanent failed. apn = " + apn); - apnContext.markApnPermanentFailed(apn); - - PersistableBundle b = getCarrierConfig(); - if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT - && b.getBoolean(CarrierConfigManager - .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) { - NotificationManager notificationManager = (NotificationManager) - mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE); - - CharSequence title = mPhone.getContext().getText( - com.android.internal.R.string.RestrictedOnDataTitle); - CharSequence details = mPhone.getContext().getText( - com.android.internal.R.string.RestrictedStateContent); - - Notification notification = new Notification.Builder(mPhone.getContext(), - NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS) - .setWhen(System.currentTimeMillis()) - .setAutoCancel(true) - .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning) - .setTicker(title) - .setColor(mPhone.getContext().getResources().getColor( - com.android.internal.R.color.system_notification_accent_color)) - .setContentTitle(title) - .setStyle(new Notification.BigTextStyle().bigText(details)) - .setContentText(details) - .build(); - notificationManager.notify(Integer.toString(mPhone.getSubId()), - NO_DATA_NOTIFICATION, notification); - } - } - - int newRequestType = calculateNewRetryRequestType(handoverFailureMode, requestType, - cause); - onDataSetupCompleteError(apnContext, newRequestType, fallbackOnFailedHandover); - } - } - - - - /** - * Error has occurred during the SETUP {aka bringUP} request and the DCT - * should either try the next waiting APN or start over from the - * beginning if the list is empty. Between each SETUP request there will - * be a delay defined by {@link ApnContext#getDelayForNextApn(boolean)}. - */ - protected void onDataSetupCompleteError(ApnContext apnContext, - @RequestNetworkType int requestType, boolean fallbackOnFailedHandover) { - long delay = apnContext.getDelayForNextApn(mFailFast); - // Check if we need to retry or not. - if (delay >= 0 && delay != RetryManager.NO_RETRY && !fallbackOnFailedHandover) { - if (DBG) { - log("onDataSetupCompleteError: APN type=" + apnContext.getApnType() - + ". Request type=" + requestTypeToString(requestType) + ", Retry in " - + delay + "ms."); - } - startReconnect(delay, apnContext, requestType); - } else { - // If we are not going to retry any APN, set this APN context to failed state. - // This would be the final state of a data connection. - apnContext.setState(DctConstants.State.FAILED); - apnContext.setDataConnection(null); - log("onDataSetupCompleteError: Stop retrying APNs. delay=" + delay - + ", requestType=" + requestTypeToString(requestType)); - //send request network complete messages as needed - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, - fallbackOnFailedHandover); - } - } - - /** - * Called when EVENT_NETWORK_STATUS_CHANGED is received. - * - * @param status One of {@code NetworkAgent.VALID_NETWORK} or - * {@code NetworkAgent.INVALID_NETWORK}. - * @param cid context id {@code cid} - * @param redirectUrl If the Internet probe was redirected, this - * is the destination it was redirected to, otherwise {@code null} - */ - private void onNetworkStatusChanged(int status, int cid, String redirectUrl) { - if (!TextUtils.isEmpty(redirectUrl)) { - Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED); - intent.putExtra(TelephonyManager.EXTRA_REDIRECTION_URL, redirectUrl); - mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); - log("Notify carrier signal receivers with redirectUrl: " + redirectUrl); - } else { - final boolean isValid = status == NetworkAgent.VALIDATION_STATUS_VALID; - final DataConnection dc = getDataConnectionByContextId(cid); - if (!mDsRecoveryHandler.isRecoveryOnBadNetworkEnabled()) { - if (DBG) log("Skip data stall recovery on network status change with in threshold"); - return; - } - if (mTransportType != AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - if (DBG) log("Skip data stall recovery on non WWAN"); - return; - } - if (dc != null && dc.isValidationRequired()) { - mDsRecoveryHandler.processNetworkStatusChanged(isValid); - } - } - } - - /** - * Called when EVENT_DISCONNECT_DONE is received. - */ - private void onDisconnectDone(ApnContext apnContext) { - if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext); - apnContext.setState(DctConstants.State.IDLE); - // If all data connection are gone, check whether Airplane mode request was pending. - if (areAllDataDisconnected() - && mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) { - if (DBG) log("onDisconnectDone: radio will be turned off, no retries"); - // Radio will be turned off. No need to retry data setup - apnContext.setApnSetting(null); - apnContext.setDataConnection(null); - - // Need to notify disconnect as well, in the case of switching Airplane mode. - // Otherwise, it would cause 30s delayed to turn on Airplane mode. - notifyAllDataDisconnected(); - return; - } - // If APN is still enabled, try to bring it back up automatically - if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) { - // Wait a bit before trying the next APN, so that - // we're not tying up the RIL command channel. - // This also helps in any external dependency to turn off the context. - if (DBG) log("onDisconnectDone: attached, ready and retry after disconnect"); - - // See if there are still handover request pending that we need to retry handover - // after previous data gets disconnected. - if (isHandoverPending(apnContext.getApnTypeBitmask())) { - if (DBG) log("Handover request pending. Retry handover immediately."); - startReconnect(0, apnContext, REQUEST_TYPE_HANDOVER); - } else { - long delay = apnContext.getRetryAfterDisconnectDelay(); - if (delay > 0) { - // Data connection is in IDLE state, so when we reconnect later, we'll rebuild - // the waiting APN list, which will also reset/reconfigure the retry manager. - startReconnect(delay, apnContext, REQUEST_TYPE_NORMAL); - } - } - } else { - boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean( - com.android.internal.R.bool.config_restartRadioAfterProvisioning); - - if (apnContext.isProvisioningApn() && restartRadioAfterProvisioning) { - log("onDisconnectDone: restartRadio after provisioning"); - restartRadio(); - } - apnContext.setApnSetting(null); - apnContext.setDataConnection(null); - if (isOnlySingleDcAllowed(getDataRat())) { - if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn"); - setupDataOnAllConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION, - RetryFailures.ALWAYS); - } else { - if(DBG) log("onDisconnectDone: not retrying"); - } - } - - if (areAllDataDisconnected()) { - apnContext.setConcurrentVoiceAndDataAllowed( - mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()); - notifyAllDataDisconnected(); - } - - } - - private void onVoiceCallStarted() { - if (DBG) log("onVoiceCallStarted"); - mInVoiceCall = true; - if (isAnyDataConnected() - && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { - if (DBG) log("onVoiceCallStarted stop polling"); - stopNetStatPoll(); - stopDataStallAlarm(); - } - } - - protected void onVoiceCallEnded() { - if (DBG) log("onVoiceCallEnded"); - mInVoiceCall = false; - if (isAnyDataConnected()) { - if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { - startNetStatPoll(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - } else { - // clean slate after call end. - resetPollStats(); - } - } - // reset reconnect timer - setupDataOnAllConnectableApns(Phone.REASON_VOICE_CALL_ENDED, RetryFailures.ALWAYS); - } - /** - * @return {@code true} if there is any data in connected state. - */ - @VisibleForTesting - public boolean isAnyDataConnected() { - for (DataConnection dc : mDataConnections.values()) { - if (dc.isActive()) { - return true; - } - } - return false; - } - - /** - * @return {@code true} if all data connections are in disconnected state. - */ - public boolean areAllDataDisconnected() { - for (DataConnection dc : mDataConnections.values()) { - if (!dc.isInactive()) { - if (DBG) log("areAllDataDisconnected false due to DC: " + dc.getName()); - return false; - } - } - return true; - } - - protected void setDataProfilesAsNeeded() { - if (DBG) log("setDataProfilesAsNeeded"); - - ArrayList dataProfileList = new ArrayList<>(); - - int preferredApnSetId = getPreferredApnSetId(); - for (ApnSetting apn : mAllApnSettings) { - if (apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID - || preferredApnSetId == apn.getApnSetId()) { - DataProfile dp = new DataProfile.Builder() - .setApnSetting(apn) - .setPreferred(apn.equals(getPreferredApn())) - .build(); - if (!dataProfileList.contains(dp)) { - dataProfileList.add(dp); - } - } else { - if (VDBG) { - log("setDataProfilesAsNeeded: APN set id " + apn.getApnSetId() - + " does not match the preferred set id " + preferredApnSetId); - } - } - } - - // Check if the data profiles we are sending are same as we did last time. We don't want to - // send the redundant profiles to the modem. Also if there the list is empty, we don't - // send it to the modem. - if (!dataProfileList.isEmpty() - && (dataProfileList.size() != mLastDataProfileList.size() - || !mLastDataProfileList.containsAll(dataProfileList))) { - mDataServiceManager.setDataProfile(dataProfileList, - mPhone.getServiceState().getDataRoamingFromRegistration(), null); - } - } - - /** - * Based on the sim operator numeric, create a list for all possible - * Data Connections and setup the preferredApn. - */ - protected void createAllApnList() { - mAllApnSettings.clear(); - String operator = mPhone.getOperatorNumeric(); - - // ORDER BY Telephony.Carriers._ID ("_id") - Cursor cursor = mPhone.getContext().getContentResolver().query( - Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, "filtered/subId/" - + mPhone.getSubId()), null, null, null, Telephony.Carriers._ID); - - if (cursor != null) { - while (cursor.moveToNext()) { - ApnSetting apn = ApnSetting.makeApnSetting(cursor); - if (apn == null) { - continue; - } - mAllApnSettings.add(apn); - } - cursor.close(); - } else { - if (DBG) log("createAllApnList: cursor is null"); - mApnSettingsInitializationLog.log("cursor is null for carrier, operator: " - + operator); - } - - dedupeApnSettings(); - - if (mAllApnSettings.isEmpty()) { - log("createAllApnList: No APN found for carrier, operator: " + operator); - mApnSettingsInitializationLog.log("no APN found for carrier, operator: " - + operator); - mPreferredApn = null; - } else { - mPreferredApn = getPreferredApn(); - if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn); - } - - addDefaultApnSettingsAsNeeded(); - if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings); - } - - private void dedupeApnSettings() { - ArrayList resultApns = new ArrayList(); - - // coalesce APNs if they are similar enough to prevent - // us from bringing up two data calls with the same interface - int i = 0; - while (i < mAllApnSettings.size() - 1) { - ApnSetting first = mAllApnSettings.get(i); - ApnSetting second = null; - int j = i + 1; - while (j < mAllApnSettings.size()) { - second = mAllApnSettings.get(j); - if (first.similar(second)) { - ApnSetting newApn = mergeApns(first, second); - mAllApnSettings.set(i, newApn); - first = newApn; - mAllApnSettings.remove(j); - } else { - j++; - } - } - i++; - } - } - - private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) { - int id = dest.getId(); - if ((src.getApnTypeBitmask() & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) { - id = src.getId(); - } - final int resultApnType = src.getApnTypeBitmask() | dest.getApnTypeBitmask(); - Uri mmsc = (dest.getMmsc() == null ? src.getMmsc() : dest.getMmsc()); - String mmsProxy = TextUtils.isEmpty(dest.getMmsProxyAddressAsString()) - ? src.getMmsProxyAddressAsString() : dest.getMmsProxyAddressAsString(); - int mmsPort = dest.getMmsProxyPort() == -1 ? src.getMmsProxyPort() : dest.getMmsProxyPort(); - String proxy = TextUtils.isEmpty(dest.getProxyAddressAsString()) - ? src.getProxyAddressAsString() : dest.getProxyAddressAsString(); - int port = dest.getProxyPort() == -1 ? src.getProxyPort() : dest.getProxyPort(); - int protocol = src.getProtocol() == ApnSetting.PROTOCOL_IPV4V6 ? src.getProtocol() - : dest.getProtocol(); - int roamingProtocol = src.getRoamingProtocol() == ApnSetting.PROTOCOL_IPV4V6 - ? src.getRoamingProtocol() : dest.getRoamingProtocol(); - int networkTypeBitmask = (dest.getNetworkTypeBitmask() == 0 - || src.getNetworkTypeBitmask() == 0) - ? 0 : (dest.getNetworkTypeBitmask() | src.getNetworkTypeBitmask()); - return new ApnSetting.Builder() - .setId(id) - .setOperatorNumeric(dest.getOperatorNumeric()) - .setEntryName(dest.getEntryName()) - .setApnName(dest.getApnName()) - .setProxyAddress(proxy) - .setProxyPort(port) - .setMmsc(mmsc) - .setMmsProxyAddress(mmsProxy) - .setMmsProxyPort(mmsPort) - .setUser(dest.getUser()) - .setPassword(dest.getPassword()) - .setAuthType(dest.getAuthType()) - .setApnTypeBitmask(resultApnType) - .setProtocol(protocol) - .setRoamingProtocol(roamingProtocol) - .setCarrierEnabled(dest.isEnabled()) - .setNetworkTypeBitmask(networkTypeBitmask) - .setProfileId(dest.getProfileId()) - .setModemCognitive(dest.isPersistent() || src.isPersistent()) - .setMaxConns(dest.getMaxConns()) - .setWaitTime(dest.getWaitTime()) - .setMaxConnsTime(dest.getMaxConnsTime()) - .setMtuV4(dest.getMtuV4()) - .setMtuV6(dest.getMtuV6()) - .setMvnoType(dest.getMvnoType()) - .setMvnoMatchData(dest.getMvnoMatchData()) - .setApnSetId(dest.getApnSetId()) - .setCarrierId(dest.getCarrierId()) - .setSkip464Xlat(dest.getSkip464Xlat()) - .build(); - } - - private DataConnection createDataConnection() { - if (DBG) log("createDataConnection E"); - - int id = mUniqueIdGenerator.getAndIncrement(); - DataConnection dataConnection = DataConnection.makeDataConnection(mPhone, id, this, - mDataServiceManager, mDcTesterFailBringUpAll, mDcc); - mDataConnections.put(id, dataConnection); - if (DBG) log("createDataConnection() X id=" + id + " dc=" + dataConnection); - return dataConnection; - } - - private void destroyDataConnections() { - if(mDataConnections != null) { - if (DBG) log("destroyDataConnections: clear mDataConnectionList"); - mDataConnections.clear(); - } else { - if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore"); - } - } - - /** - * Build a list of APNs to be used to create PDP's. - * - * @param requestedApnType - * @return waitingApns list to be used to create PDP - * error when waitingApns.isEmpty() - */ - private @NonNull ArrayList buildWaitingApns(String requestedApnType, - int radioTech) { - if (DBG) log("buildWaitingApns: E requestedApnType=" + requestedApnType); - ArrayList apnList = new ArrayList(); - - int requestedApnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(requestedApnType); - if (requestedApnTypeBitmask == ApnSetting.TYPE_ENTERPRISE) { - requestedApnTypeBitmask = ApnSetting.TYPE_DEFAULT; - } - if (requestedApnTypeBitmask == ApnSetting.TYPE_DUN) { - ArrayList dunApns = fetchDunApns(); - if (dunApns.size() > 0) { - for (ApnSetting dun : dunApns) { - apnList.add(dun); - if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList); - } - return apnList; - } - } - - String operator = mPhone.getOperatorNumeric(); - - // This is a workaround for a bug (7305641) where we don't failover to other - // suitable APNs if our preferred APN fails. On prepaid ATT sims we need to - // failover to a provisioning APN, but once we've used their default data - // connection we are locked to it for life. This change allows ATT devices - // to say they don't want to use preferred at all. - boolean usePreferred = true; - try { - usePreferred = !mPhone.getContext().getResources().getBoolean(com.android - .internal.R.bool.config_dontPreferApn); - } catch (Resources.NotFoundException e) { - if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true"); - usePreferred = true; - } - if (usePreferred) { - mPreferredApn = getPreferredApn(); - } - if (DBG) { - log("buildWaitingApns: usePreferred=" + usePreferred - + " canSetPreferApn=" + mCanSetPreferApn - + " mPreferredApn=" + mPreferredApn - + " operator=" + operator + " radioTech=" + radioTech); - } - - if (usePreferred && mCanSetPreferApn && mPreferredApn != null && - mPreferredApn.canHandleType(requestedApnTypeBitmask)) { - if (DBG) { - log("buildWaitingApns: Preferred APN:" + operator + ":" - + mPreferredApn.getOperatorNumeric() + ":" + mPreferredApn); - } - - if (TextUtils.equals(mPreferredApn.getOperatorNumeric(), operator) - || mPreferredApn.getCarrierId() == mPhone.getCarrierId()) { - if (mPreferredApn.canSupportNetworkType( - ServiceState.rilRadioTechnologyToNetworkType(radioTech))) { - // Create a new instance of ApnSetting for ENTERPRISE because each - // DataConnection should have its own ApnSetting. ENTERPRISE uses the same - // APN as DEFAULT but is a separate DataConnection - if (ApnSetting.getApnTypesBitmaskFromString(requestedApnType) - == ApnSetting.TYPE_ENTERPRISE) { - apnList.add(ApnSetting.makeApnSetting(mPreferredApn)); - } else { - apnList.add(mPreferredApn); - } - if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList); - return apnList; - } - } - if (DBG) log("buildWaitingApns: no preferred APN"); - setPreferredApn(-1); - mPreferredApn = null; - } - - if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings); - int preferredApnSetId = getPreferredApnSetId(); - for (ApnSetting apn : mAllApnSettings) { - if (apn.canHandleType(requestedApnTypeBitmask)) { - if (apn.canSupportNetworkType( - ServiceState.rilRadioTechnologyToNetworkType(radioTech))) { - if (apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID - || preferredApnSetId == apn.getApnSetId()) { - if (VDBG) log("buildWaitingApns: adding apn=" + apn); - // Create a new instance of ApnSetting for ENTERPRISE because each - // DataConnection should have its own ApnSetting. ENTERPRISE uses the same - // APN as DEFAULT but is a separate DataConnection - if (ApnSetting.getApnTypesBitmaskFromString(requestedApnType) - == ApnSetting.TYPE_ENTERPRISE) { - apnList.add(ApnSetting.makeApnSetting(apn)); - } else { - apnList.add(apn); - } - } else { - log("buildWaitingApns: APN set id " + apn.getApnSetId() - + " does not match the preferred set id " + preferredApnSetId); - } - } else { - if (DBG) { - log("buildWaitingApns: networkTypeBitmask:" - + apn.getNetworkTypeBitmask() - + " does not include radioTech:" - + ServiceState.rilRadioTechnologyToString(radioTech)); - } - } - } else if (VDBG) { - log("buildWaitingApns: couldn't handle requested ApnType=" - + requestedApnType); - } - } - - if (DBG) log("buildWaitingApns: " + apnList.size() + " APNs in the list: " + apnList); - return apnList; - } - - private String apnListToString (ArrayList apns) { - StringBuilder result = new StringBuilder(); - for (int i = 0, size = apns.size(); i < size; i++) { - result.append('[') - .append(apns.get(i).toString()) - .append(']'); - } - return result.toString(); - } - - private void setPreferredApn(int pos) { - setPreferredApn(pos, false); - } - - private void setPreferredApn(int pos, boolean force) { - if (!force && !mCanSetPreferApn) { - log("setPreferredApn: X !canSEtPreferApn"); - return; - } - - String subId = Long.toString(mPhone.getSubId()); - Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); - log("setPreferredApn: delete"); - ContentResolver resolver = mPhone.getContext().getContentResolver(); - resolver.delete(uri, null, null); - - if (pos >= 0) { - log("setPreferredApn: insert"); - ContentValues values = new ContentValues(); - values.put(APN_ID, pos); - resolver.insert(uri, values); - } - } - - @Nullable - ApnSetting getPreferredApn() { - //Only call this method from main thread - if (mAllApnSettings == null || mAllApnSettings.isEmpty()) { - log("getPreferredApn: mAllApnSettings is empty"); - return null; - } - - String subId = Long.toString(mPhone.getSubId()); - Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); - Cursor cursor = mPhone.getContext().getContentResolver().query( - uri, new String[] { "_id", "name", "apn" }, - null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); - - if (cursor != null) { - mCanSetPreferApn = true; - } else { - mCanSetPreferApn = false; - } - - if (VDBG) { - log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor - + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0)); - } - - if (mCanSetPreferApn && cursor.getCount() > 0) { - int pos; - cursor.moveToFirst(); - pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); - for(ApnSetting p : mAllApnSettings) { - if (p.getId() == pos && p.canHandleType(mRequestedApnType)) { - log("getPreferredApn: For APN type " - + ApnSetting.getApnTypeString(mRequestedApnType) - + " found apnSetting " + p); - cursor.close(); - return p; - } - } - } - - if (cursor != null) { - cursor.close(); - } - - log("getPreferredApn: X not found"); - return null; - } - - @Override - public void handleMessage (Message msg) { - if (VDBG) log("handleMessage msg=" + msg); - - AsyncResult ar; - Pair pair; - ApnContext apnContext; - int generation; - int requestType; - int handoverFailureMode; - switch (msg.what) { - case DctConstants.EVENT_DATA_CONNECTION_DETACHED: - onDataConnectionDetached(); - break; - - case DctConstants.EVENT_DATA_CONNECTION_ATTACHED: - onDataConnectionAttached(); - break; - - case DctConstants.EVENT_DO_RECOVERY: - mDsRecoveryHandler.doRecovery(); - break; - - case DctConstants.EVENT_APN_CHANGED: - onApnChanged(); - break; - - case DctConstants.EVENT_PS_RESTRICT_ENABLED: - /** - * We don't need to explicitly to tear down the PDP context - * when PS restricted is enabled. The base band will deactive - * PDP context and notify us with PDP_CONTEXT_CHANGED. - * But we should stop the network polling and prevent reset PDP. - */ - if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); - stopNetStatPoll(); - stopDataStallAlarm(); - mIsPsRestricted = true; - break; - - case DctConstants.EVENT_PS_RESTRICT_DISABLED: - /** - * When PS restrict is removed, we need setup PDP connection if - * PDP connection is down. - */ - if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); - mIsPsRestricted = false; - if (isAnyDataConnected()) { - startNetStatPoll(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - } else { - // TODO: Should all PDN states be checked to fail? - if (mState == DctConstants.State.FAILED) { - cleanUpAllConnectionsInternal(false, Phone.REASON_PS_RESTRICT_ENABLED); - mReregisterOnReconnectFailure = false; - } - apnContext = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT); - if (apnContext != null) { - apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED); - trySetupData(apnContext, REQUEST_TYPE_NORMAL, null); - } else { - loge("**** Default ApnContext not found ****"); - if (TelephonyUtils.IS_DEBUGGABLE) { - throw new RuntimeException("Default ApnContext not found"); - } - } - } - break; - - case DctConstants.EVENT_TRY_SETUP_DATA: - apnContext = (ApnContext) msg.obj; - requestType = msg.arg1; - trySetupData(apnContext, requestType, null); - break; - case DctConstants.EVENT_CLEAN_UP_CONNECTION: - if (DBG) log("EVENT_CLEAN_UP_CONNECTION"); - cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, (ApnContext) msg.obj); - break; - case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS: - if ((msg.obj != null) && (msg.obj instanceof String == false)) { - msg.obj = null; - } - cleanUpAllConnectionsInternal(true, (String) msg.obj); - break; - - case DctConstants.EVENT_DATA_RAT_CHANGED: - if (getDataRat() == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) { - // unknown rat is an exception for data rat change. It's only received when out - // of service and is not applicable for apn bearer bitmask. We should bypass the - // check of waiting apn list and keep the data connection on, and no need to - // setup a new one. - break; - } - cleanUpConnectionsOnUpdatedApns(false, Phone.REASON_NW_TYPE_CHANGED); - //May new Network allow setupData, so try it here - setupDataOnAllConnectableApns(Phone.REASON_NW_TYPE_CHANGED, - RetryFailures.ONLY_ON_CHANGE); - break; - - case DctConstants.CMD_CLEAR_PROVISIONING_SPINNER: - // Check message sender intended to clear the current spinner. - if (mProvisioningSpinner == msg.obj) { - mProvisioningSpinner.dismiss(); - mProvisioningSpinner = null; - } - break; - - case DctConstants.EVENT_ENABLE_APN: - onEnableApn(msg.arg1, msg.arg2, (Message) msg.obj); - break; - - case DctConstants.EVENT_DISABLE_APN: - onDisableApn(msg.arg1, msg.arg2); - break; - - case DctConstants.EVENT_DATA_STALL_ALARM: - onDataStallAlarm(msg.arg1); - break; - - case DctConstants.EVENT_ROAMING_OFF: - onDataRoamingOff(); - break; - - case DctConstants.EVENT_ROAMING_ON: - case DctConstants.EVENT_ROAMING_SETTING_CHANGE: - onDataRoamingOnOrSettingsChanged(msg.what); - break; - - case DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE: - // Update sharedPreference to false when exits new device provisioning, indicating - // no users modifications on the settings for new devices. Thus carrier specific - // default roaming settings can be applied for new devices till user modification. - final SharedPreferences sp = PreferenceManager - .getDefaultSharedPreferences(mPhone.getContext()); - if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) { - sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit(); - } - break; - - case DctConstants.EVENT_NETWORK_STATUS_CHANGED: - int status = msg.arg1; - int cid = msg.arg2; - String url = (String) msg.obj; - onNetworkStatusChanged(status, cid, url); - break; - - case DctConstants.EVENT_RADIO_AVAILABLE: - onRadioAvailable(); - break; - - case DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE: - onRadioOffOrNotAvailable(); - break; - - case DctConstants.EVENT_DATA_SETUP_COMPLETE: - ar = (AsyncResult) msg.obj; - pair = (Pair) ar.userObj; - apnContext = pair.first; - generation = pair.second; - requestType = msg.arg1; - handoverFailureMode = msg.arg2; - if (apnContext.getConnectionGeneration() == generation) { - boolean success = true; - int cause = DataFailCause.UNKNOWN; - if (ar.exception != null) { - success = false; - cause = (int) ar.result; - } - onDataSetupComplete(apnContext, success, cause, requestType, - handoverFailureMode); - } else { - loge("EVENT_DATA_SETUP_COMPLETE: Dropped the event because generation " - + "did not match."); - } - break; - - case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR: - ar = (AsyncResult) msg.obj; - pair = (Pair) ar.userObj; - apnContext = pair.first; - generation = pair.second; - handoverFailureMode = msg.arg2; - if (apnContext.getConnectionGeneration() == generation) { - onDataSetupCompleteError(apnContext, handoverFailureMode, false); - } else { - loge("EVENT_DATA_SETUP_COMPLETE_ERROR: Dropped the event because generation " - + "did not match."); - } - break; - - case DctConstants.EVENT_DISCONNECT_DONE: - log("EVENT_DISCONNECT_DONE msg=" + msg); - ar = (AsyncResult) msg.obj; - pair = (Pair) ar.userObj; - apnContext = pair.first; - generation = pair.second; - if (apnContext.getConnectionGeneration() == generation) { - onDisconnectDone(apnContext); - } else { - loge("EVENT_DISCONNECT_DONE: Dropped the event because generation " - + "did not match."); - } - break; - - case DctConstants.EVENT_VOICE_CALL_STARTED: - onVoiceCallStarted(); - break; - - case DctConstants.EVENT_VOICE_CALL_ENDED: - onVoiceCallEnded(); - break; - case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: { - sEnableFailFastRefCounter += (msg.arg1 == DctConstants.ENABLED) ? 1 : -1; - if (DBG) { - log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: " - + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter); - } - if (sEnableFailFastRefCounter < 0) { - final String s = "CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: " - + "sEnableFailFastRefCounter:" + sEnableFailFastRefCounter + " < 0"; - loge(s); - sEnableFailFastRefCounter = 0; - } - final boolean enabled = sEnableFailFastRefCounter > 0; - if (DBG) { - log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled - + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter); - } - if (mFailFast != enabled) { - mFailFast = enabled; - - mDataStallNoRxEnabled = !enabled; - if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled() - && isAnyDataConnected() - && (!mInVoiceCall || - mPhone.getServiceStateTracker() - .isConcurrentVoiceAndDataAllowed())) { - if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall"); - stopDataStallAlarm(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - } else { - if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall"); - stopDataStallAlarm(); - } - } - - break; - } - case DctConstants.CMD_ENABLE_MOBILE_PROVISIONING: { - Bundle bundle = msg.getData(); - if (bundle != null) { - try { - mProvisioningUrl = (String)bundle.get(DctConstants.PROVISIONING_URL_KEY); - } catch(ClassCastException e) { - loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url not a string" + e); - mProvisioningUrl = null; - } - } - if (TextUtils.isEmpty(mProvisioningUrl)) { - loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url is empty, ignoring"); - mIsProvisioning = false; - mProvisioningUrl = null; - } else { - loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioningUrl=" + mProvisioningUrl); - mIsProvisioning = true; - startProvisioningApnAlarm(); - } - break; - } - case DctConstants.EVENT_PROVISIONING_APN_ALARM: { - if (DBG) log("EVENT_PROVISIONING_APN_ALARM"); - ApnContext apnCtx = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT); - if (apnCtx.isProvisioningApn() && apnCtx.isConnectedOrConnecting()) { - if (mProvisioningApnAlarmTag == msg.arg1) { - if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Disconnecting"); - mIsProvisioning = false; - mProvisioningUrl = null; - stopProvisioningApnAlarm(); - cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnCtx); - } else { - if (DBG) { - log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag," - + " mProvisioningApnAlarmTag:" + mProvisioningApnAlarmTag - + " != arg1:" + msg.arg1); - } - } - } else { - if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Not connected ignore"); - } - break; - } - case DctConstants.CMD_IS_PROVISIONING_APN: { - if (DBG) log("CMD_IS_PROVISIONING_APN"); - boolean isProvApn; - try { - String apnType = null; - Bundle bundle = msg.getData(); - if (bundle != null) { - apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY); - } - if (TextUtils.isEmpty(apnType)) { - loge("CMD_IS_PROVISIONING_APN: apnType is empty"); - isProvApn = false; - } else { - isProvApn = isProvisioningApn(apnType); - } - } catch (ClassCastException e) { - loge("CMD_IS_PROVISIONING_APN: NO provisioning url ignoring"); - isProvApn = false; - } - if (DBG) log("CMD_IS_PROVISIONING_APN: ret=" + isProvApn); - mReplyAc.replyToMessage(msg, DctConstants.CMD_IS_PROVISIONING_APN, - isProvApn ? DctConstants.ENABLED : DctConstants.DISABLED); - break; - } - case DctConstants.EVENT_RESTART_RADIO: { - restartRadio(); - break; - } - case DctConstants.CMD_NET_STAT_POLL: { - if (msg.arg1 == DctConstants.ENABLED) { - handleStartNetStatPoll((DctConstants.Activity)msg.obj); - } else if (msg.arg1 == DctConstants.DISABLED) { - handleStopNetStatPoll((DctConstants.Activity)msg.obj); - } - break; - } - case DctConstants.EVENT_PCO_DATA_RECEIVED: { - handlePcoData((AsyncResult)msg.obj); - break; - } - case DctConstants.EVENT_DATA_RECONNECT: - if (DBG) { - log("EVENT_DATA_RECONNECT: subId=" + msg.arg1 + ", type=" - + requestTypeToString(msg.arg2)); - } - onDataReconnect((ApnContext) msg.obj, msg.arg1, msg.arg2); - break; - case DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED: - onDataServiceBindingChanged((Boolean) ((AsyncResult) msg.obj).result); - break; - case DctConstants.EVENT_DATA_ENABLED_CHANGED: - ar = (AsyncResult) msg.obj; - if (ar.result instanceof Pair) { - Pair p = (Pair) ar.result; - boolean enabled = p.first; - int reason = p.second; - onDataEnabledChanged(enabled, reason); - } - break; - case DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED: - onDataEnabledOverrideRulesChanged(); - break; - case DctConstants.EVENT_NR_TIMER_WATCHDOG: - mWatchdog = false; - reevaluateUnmeteredConnections(); - break; - case DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED: - reevaluateCongestedConnections(); - reevaluateUnmeteredConnections(); - break; - case DctConstants.EVENT_CARRIER_CONFIG_CHANGED: - onCarrierConfigChanged(); - break; - case DctConstants.EVENT_SIM_STATE_UPDATED: - int simState = msg.arg1; - onSimStateUpdated(simState); - break; - case DctConstants.EVENT_APN_UNTHROTTLED: - ar = (AsyncResult) msg.obj; - String apn = (String) ar.result; - onApnUnthrottled(apn); - break; - case DctConstants.EVENT_TRAFFIC_DESCRIPTORS_UPDATED: - onTrafficDescriptorsUpdated(); - break; - default: - Rlog.e("DcTracker", "Unhandled event=" + msg); - break; - - } - } - - private int getApnProfileID(String apnType) { - if (TextUtils.equals(apnType, ApnSetting.TYPE_IMS_STRING)) { - return RILConstants.DATA_PROFILE_IMS; - } else if (TextUtils.equals(apnType, ApnSetting.TYPE_FOTA_STRING)) { - return RILConstants.DATA_PROFILE_FOTA; - } else if (TextUtils.equals(apnType, ApnSetting.TYPE_CBS_STRING)) { - return RILConstants.DATA_PROFILE_CBS; - } else if (TextUtils.equals(apnType, ApnSetting.TYPE_IA_STRING)) { - return RILConstants.DATA_PROFILE_DEFAULT; // DEFAULT for now - } else if (TextUtils.equals(apnType, ApnSetting.TYPE_DUN_STRING)) { - return RILConstants.DATA_PROFILE_TETHERED; - } else { - return RILConstants.DATA_PROFILE_DEFAULT; - } - } - - private int getCellLocationId() { - int cid = -1; - CellLocation loc = mPhone.getCurrentCellIdentity().asCellLocation(); - - if (loc != null) { - if (loc instanceof GsmCellLocation) { - cid = ((GsmCellLocation)loc).getCid(); - } else if (loc instanceof CdmaCellLocation) { - cid = ((CdmaCellLocation)loc).getBaseStationId(); - } - } - return cid; - } - - /** - * Update link bandwidth estimate default values from carrier config. - * @param bandwidths String array of "RAT:upstream,downstream" for each RAT - * @param useLte For NR NSA, whether to use LTE value for upstream or not - */ - private void updateLinkBandwidths(String[] bandwidths, boolean useLte) { - ConcurrentHashMap> temp = new ConcurrentHashMap<>(); - for (String config : bandwidths) { - int downstream = 14; - int upstream = 14; - String[] kv = config.split(":"); - if (kv.length == 2) { - String[] split = kv[1].split(","); - if (split.length == 2) { - try { - downstream = Integer.parseInt(split[0]); - upstream = Integer.parseInt(split[1]); - } catch (NumberFormatException ignored) { - } - } - temp.put(kv[0], new Pair<>(downstream, upstream)); - } - } - if (useLte) { - Pair ltePair = - temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_LTE); - if (ltePair != null) { - if (temp.containsKey(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA)) { - temp.put(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA, new Pair<>( - temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA).first, - ltePair.second)); - } - if (temp.containsKey(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE)) { - temp.put(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE, new Pair<>( - temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE) - .first, ltePair.second)); - } - } - } - mBandwidths = temp; - for (DataConnection dc : mDataConnections.values()) { - dc.sendMessage(DataConnection.EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED); - } - } - - /** - * Return the link upstream/downstream values from CarrierConfig for the given RAT name. - * @param ratName RAT name from ServiceState#rilRadioTechnologyToString. - * @return pair of downstream/upstream values (kbps), or null if the config is not defined. - */ - public Pair getLinkBandwidthsFromCarrierConfig(String ratName) { - return mBandwidths.get(ratName); - } - - @VisibleForTesting - public boolean shouldAutoAttach() { - if (mAutoAttachEnabled.get()) return true; - - PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); - ServiceState serviceState = mPhone.getServiceState(); - - if (phoneSwitcher == null || serviceState == null) return false; - - // If voice is also not in service, don't auto attach. - if (serviceState.getState() != ServiceState.STATE_IN_SERVICE) return false; - - // If voice is on LTE or NR, don't auto attach as for LTE / NR data would be attached. - if (serviceState.getVoiceNetworkType() == NETWORK_TYPE_LTE - || serviceState.getVoiceNetworkType() == NETWORK_TYPE_NR) return false; - - // If phone is non default phone, modem may have detached from data for optimization. - // If phone is in voice call, for DSDS case DDS switch may be limited so we do try our - // best to setup data connection and allow auto-attach. - return (mPhone.getPhoneId() != phoneSwitcher.getPreferredDataPhoneId() - || mPhone.getState() != PhoneConstants.State.IDLE); - } - - private void notifyAllDataDisconnected() { - sEnableFailFastRefCounter = 0; - mFailFast = false; - log("notify all data disconnected"); - mAllDataDisconnectedRegistrants.notifyRegistrants(); - } - - public void registerForAllDataDisconnected(Handler h, int what) { - mAllDataDisconnectedRegistrants.addUnique(h, what, null); - - if (areAllDataDisconnected()) { - notifyAllDataDisconnected(); - } - } - - public void unregisterForAllDataDisconnected(Handler h) { - mAllDataDisconnectedRegistrants.remove(h); - } - - private void onDataEnabledChanged(boolean enable, - @DataEnabledChangedReason int enabledChangedReason) { - if (DBG) { - log("onDataEnabledChanged: enable=" + enable + ", enabledChangedReason=" - + enabledChangedReason); - } - - if (enable) { - reevaluateDataConnections(); - setupDataOnAllConnectableApns(Phone.REASON_DATA_ENABLED, RetryFailures.ALWAYS); - } else { - String cleanupReason; - switch (enabledChangedReason) { - case DataEnabledSettings.REASON_INTERNAL_DATA_ENABLED: - cleanupReason = Phone.REASON_DATA_DISABLED_INTERNAL; - break; - case DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER: - cleanupReason = Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN; - break; - case DataEnabledSettings.REASON_USER_DATA_ENABLED: - case DataEnabledSettings.REASON_POLICY_DATA_ENABLED: - case DataEnabledSettings.REASON_PROVISIONED_CHANGED: - case DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED: - default: - cleanupReason = Phone.REASON_DATA_SPECIFIC_DISABLED; - break; - - } - cleanUpAllConnectionsInternal(true, cleanupReason); - } - } - - private void reevaluateCongestedConnections() { - log("reevaluateCongestedConnections"); - int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); - // congested override and either network is specified or unknown and all networks specified - boolean isCongested = mCongestedOverride && (mCongestedNetworkTypes.contains(rat) - || mCongestedNetworkTypes.containsAll(Arrays.stream( - TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet()))); - for (DataConnection dataConnection : mDataConnections.values()) { - dataConnection.onCongestednessChanged(isCongested); - } - } - - private void reevaluateUnmeteredConnections() { - log("reevaluateUnmeteredConnections"); - int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); - if (isNrUnmetered() && (!mPhone.getServiceState().getRoaming() || mNrNsaRoamingUnmetered)) { - setDataConnectionUnmetered(true); - if (!mWatchdog) { - startWatchdogAlarm(); - } - } else { - stopWatchdogAlarm(); - setDataConnectionUnmetered(isNetworkTypeUnmetered(rat)); - } - } - - private void setDataConnectionUnmetered(boolean isUnmetered) { - if (!isUnmetered || isTempNotMeteredSupportedByCarrier()) { - for (DataConnection dataConnection : mDataConnections.values()) { - dataConnection.onMeterednessChanged(isUnmetered); - } - } - } - - private boolean isNetworkTypeUnmetered(@NetworkType int networkType) { - boolean isUnmetered; - if (mUnmeteredNetworkTypes == null || !mUnmeteredOverride) { - // check SubscriptionPlans if override is not defined - isUnmetered = isNetworkTypeUnmeteredViaSubscriptionPlan(networkType); - log("isNetworkTypeUnmeteredViaSubscriptionPlan: networkType=" + networkType - + ", isUnmetered=" + isUnmetered); - return isUnmetered; - } - // unmetered override and either network is specified or unknown and all networks specified - isUnmetered = mUnmeteredNetworkTypes.contains(networkType) - || mUnmeteredNetworkTypes.containsAll(Arrays.stream( - TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet())); - if (DBG) { - log("isNetworkTypeUnmetered: networkType=" + networkType - + ", isUnmetered=" + isUnmetered); - } - return isUnmetered; - } - - private boolean isNetworkTypeUnmeteredViaSubscriptionPlan(@NetworkType int networkType) { - if (mSubscriptionPlans.isEmpty()) { - // safe return false if unable to get subscription plans or plans don't exist - return false; - } - - boolean isGeneralUnmetered = true; - Set allNetworkTypes = Arrays.stream(TelephonyManager.getAllNetworkTypes()) - .boxed().collect(Collectors.toSet()); - for (SubscriptionPlan plan : mSubscriptionPlans) { - // check plan is general (applies to all network types) or specific - if (Arrays.stream(plan.getNetworkTypes()).boxed().collect(Collectors.toSet()) - .containsAll(allNetworkTypes)) { - if (!isPlanUnmetered(plan)) { - // metered takes precedence over unmetered for safety - isGeneralUnmetered = false; - } - } else { - // check plan applies to given network type - if (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN) { - for (int planNetworkType : plan.getNetworkTypes()) { - if (planNetworkType == networkType) { - return isPlanUnmetered(plan); - } - } - } - } - } - return isGeneralUnmetered; - } - - private boolean isPlanUnmetered(SubscriptionPlan plan) { - return plan.getDataLimitBytes() == SubscriptionPlan.BYTES_UNLIMITED; - } - - private boolean isNrUnmetered() { - int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); - int override = mPhone.getDisplayInfoController().getTelephonyDisplayInfo() - .getOverrideNetworkType(); - - if (isNetworkTypeUnmetered(NETWORK_TYPE_NR)) { - if (mNrNsaMmwaveUnmetered) { - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) { - if (DBG) log("NR unmetered for mmwave only"); - return true; - } - return false; - } else if (mNrNsaSub6Unmetered) { - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { - if (DBG) log("NR unmetered for sub6 only"); - return true; - } - return false; - } - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED - || override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA - || rat == NETWORK_TYPE_NR) { - if (DBG) log("NR unmetered for all frequencies"); - return true; - } - return false; - } - - if (mNrNsaAllUnmetered) { - if (mNrNsaMmwaveUnmetered) { - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) { - if (DBG) log("NR NSA unmetered for mmwave only via carrier configs"); - return true; - } - return false; - } else if (mNrNsaSub6Unmetered) { - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { - if (DBG) log("NR NSA unmetered for sub6 only via carrier configs"); - return true; - } - return false; - } - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED - || override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { - if (DBG) log("NR NSA unmetered for all frequencies via carrier configs"); - return true; - } - return false; - } - - if (mNrSaAllUnmetered) { - // TODO: add logic for mNrSaMmwaveUnmetered and mNrSaSub6Unmetered once it's defined - // in TelephonyDisplayInfo - if (rat == NETWORK_TYPE_NR) { - if (DBG) log("NR SA unmetered for all frequencies via carrier configs"); - return true; - } - return false; - } - - return false; - } - - private boolean isTempNotMeteredSupportedByCarrier() { - CarrierConfigManager configManager = - mPhone.getContext().getSystemService(CarrierConfigManager.class); - if (configManager != null) { - PersistableBundle bundle = configManager.getConfigForSubId(mPhone.getSubId()); - if (bundle != null) { - return bundle.getBoolean( - CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL); - } - } - - return false; - } - - protected void log(String s) { - Rlog.d(mLogTag, s); - } - - private void loge(String s) { - Rlog.e(mLogTag, s); - } - - private void logSortedApnContexts() { - if (VDBG) { - log("initApnContexts: X mApnContexts=" + mApnContexts); - - StringBuilder sb = new StringBuilder(); - sb.append("sorted apncontexts -> ["); - for (ApnContext apnContext : mPrioritySortedApnContexts) { - sb.append(apnContext); - sb.append(", "); - - log("sorted list"); - } - sb.append("]"); - log(sb.toString()); - } - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("DcTracker:"); - pw.println(" RADIO_TESTS=" + RADIO_TESTS); - pw.println(" mDataEnabledSettings=" + mDataEnabledSettings); - pw.println(" isDataAllowed=" + isDataAllowed(null)); - pw.flush(); - pw.println(" mRequestedApnType=" + mRequestedApnType); - pw.println(" mPhone=" + mPhone.getPhoneName()); - pw.println(" mConfigReady=" + mConfigReady); - pw.println(" mSimState=" + SubscriptionInfoUpdater.simStateString(mSimState)); - pw.println(" mActivity=" + mActivity); - pw.println(" mState=" + mState); - pw.println(" mTxPkts=" + mTxPkts); - pw.println(" mRxPkts=" + mRxPkts); - pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod); - pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled); - pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum); - pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag); - pw.println(" mDataStallNoRxEnabled=" + mDataStallNoRxEnabled); - pw.println(" mEmergencyApn=" + mEmergencyApn); - pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv); - pw.println(" mNoRecvPollCount=" + mNoRecvPollCount); - pw.println(" mResolver=" + mResolver); - pw.println(" mReconnectIntent=" + mReconnectIntent); - pw.println(" mAutoAttachEnabled=" + mAutoAttachEnabled.get()); - pw.println(" mIsScreenOn=" + mIsScreenOn); - pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator); - pw.println(" mDataServiceBound=" + mDataServiceBound); - pw.println(" mDataRoamingLeakageLog= "); - mDataRoamingLeakageLog.dump(fd, pw, args); - pw.println(" mApnSettingsInitializationLog= "); - mApnSettingsInitializationLog.dump(fd, pw, args); - pw.flush(); - pw.println(" ***************************************"); - DcController dcc = mDcc; - if (dcc != null) { - if (mDataServiceBound) { - dcc.dump(fd, pw, args); - } else { - pw.println(" Can't dump mDcc because data service is not bound."); - } - } else { - pw.println(" mDcc=null"); - } - pw.println(" ***************************************"); - HashMap dcs = mDataConnections; - if (dcs != null) { - Set > mDcSet = mDataConnections.entrySet(); - pw.println(" mDataConnections: count=" + mDcSet.size()); - for (Entry entry : mDcSet) { - pw.printf(" *** mDataConnection[%d] \n", entry.getKey()); - entry.getValue().dump(fd, pw, args); - } - } else { - pw.println("mDataConnections=null"); - } - pw.println(" ***************************************"); - pw.flush(); - HashMap apnToDcId = mApnToDataConnectionId; - if (apnToDcId != null) { - Set> apnToDcIdSet = apnToDcId.entrySet(); - pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size()); - for (Entry entry : apnToDcIdSet) { - pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue()); - } - } else { - pw.println("mApnToDataConnectionId=null"); - } - pw.println(" ***************************************"); - pw.flush(); - ConcurrentHashMap apnCtxs = mApnContexts; - if (apnCtxs != null) { - Set> apnCtxsSet = apnCtxs.entrySet(); - pw.println(" mApnContexts size=" + apnCtxsSet.size()); - for (Entry entry : apnCtxsSet) { - entry.getValue().dump(fd, pw, args); - } - ApnContext.dumpLocalLog(fd, pw, args); - pw.println(" ***************************************"); - } else { - pw.println(" mApnContexts=null"); - } - pw.flush(); - - pw.println(" mAllApnSettings size=" + mAllApnSettings.size()); - for (int i = 0; i < mAllApnSettings.size(); i++) { - pw.printf(" mAllApnSettings[%d]: %s\n", i, mAllApnSettings.get(i)); - } - pw.flush(); - - pw.println(" mPreferredApn=" + mPreferredApn); - pw.println(" mIsPsRestricted=" + mIsPsRestricted); - pw.println(" mIsDisposed=" + mIsDisposed); - pw.println(" mIntentReceiver=" + mIntentReceiver); - pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure); - pw.println(" canSetPreferApn=" + mCanSetPreferApn); - pw.println(" mApnObserver=" + mApnObserver); - pw.println(" isAnyDataConnected=" + isAnyDataConnected()); - pw.println(" mAttached=" + mAttached.get()); - mDataEnabledSettings.dump(fd, pw, args); - pw.flush(); - } - - public String[] getPcscfAddress(String apnType) { - log("getPcscfAddress()"); - ApnContext apnContext = null; - - if(apnType == null){ - log("apnType is null, return null"); - return null; - } - - if (TextUtils.equals(apnType, ApnSetting.TYPE_EMERGENCY_STRING)) { - apnContext = mApnContextsByType.get(ApnSetting.TYPE_EMERGENCY); - } else if (TextUtils.equals(apnType, ApnSetting.TYPE_IMS_STRING)) { - apnContext = mApnContextsByType.get(ApnSetting.TYPE_IMS); - } else { - log("apnType is invalid, return null"); - return null; - } - - if (apnContext == null) { - log("apnContext is null, return null"); - return null; - } - - DataConnection dataConnection = apnContext.getDataConnection(); - String[] result = null; - - if (dataConnection != null) { - result = dataConnection.getPcscfAddresses(); - - if (result != null) { - for (int i = 0; i < result.length; i++) { - log("Pcscf[" + i + "]: " + result[i]); - } - } - return result; - } - return null; - } - - /** - * Create default apn settings for the apn type like emergency, and ims - */ - private ApnSetting buildDefaultApnSetting(@NonNull String entry, - @NonNull String apn, @ApnType int apnTypeBitmask) { - return new ApnSetting.Builder() - .setEntryName(entry) - .setProtocol(ApnSetting.PROTOCOL_IPV4V6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6) - .setApnName(apn) - .setApnTypeBitmask(apnTypeBitmask) - .setCarrierEnabled(true) - .setApnSetId(Telephony.Carriers.MATCH_ALL_APN_SET_ID) - .build(); - } - - /** - * Add default APN settings to APN settings list as needed - */ - private void addDefaultApnSettingsAsNeeded() { - boolean isEmergencyApnConfigured = false; - boolean isImsApnConfigured = false; - - for (ApnSetting apn : mAllApnSettings) { - if (apn.canHandleType(ApnSetting.TYPE_EMERGENCY)) { - isEmergencyApnConfigured = true; - } - if (apn.canHandleType(ApnSetting.TYPE_IMS)) { - isImsApnConfigured = true; - } - if (isEmergencyApnConfigured && isImsApnConfigured) { - log("Both emergency and ims apn setting are already present"); - return; - } - } - - // Add default apn setting for emergency service if it is not present - if (!isEmergencyApnConfigured) { - mAllApnSettings.add(buildDefaultApnSetting( - "DEFAULT EIMS", "sos", ApnSetting.TYPE_EMERGENCY)); - log("default emergency apn is created"); - } - - // Only add default apn setting for ims when it is not present and sim is loaded - if (!isImsApnConfigured && mSimState == TelephonyManager.SIM_STATE_LOADED) { - mAllApnSettings.add(buildDefaultApnSetting( - "DEFAULT IMS", "ims", ApnSetting.TYPE_IMS)); - log("default ims apn is created"); - } - } - - private void cleanUpConnectionsOnUpdatedApns(boolean detach, String reason) { - if (DBG) log("cleanUpConnectionsOnUpdatedApns: detach=" + detach); - if (mAllApnSettings.isEmpty()) { - cleanUpAllConnectionsInternal(detach, Phone.REASON_APN_CHANGED); - } else { - if (getDataRat() == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) { - // unknown rat is an exception for data rat change. Its only received when out of - // service and is not applicable for apn bearer bitmask. We should bypass the check - // of waiting apn list and keep the data connection on. - return; - } - for (ApnContext apnContext : mApnContexts.values()) { - boolean cleanupRequired = true; - if (!apnContext.isDisconnected()) { - ArrayList waitingApns = buildWaitingApns( - apnContext.getApnType(), getDataRat()); - if (apnContext.getWaitingApns().size() != waitingApns.size() - || !apnContext.getWaitingApns().containsAll(waitingApns)) { - apnContext.setWaitingApns(waitingApns); - } - for (ApnSetting apnSetting : waitingApns) { - if (areCompatible(apnSetting, apnContext.getApnSetting())) { - cleanupRequired = false; - break; - } - } - - if (cleanupRequired) { - if (DBG) { - log("cleanUpConnectionsOnUpdatedApns: APN type " - + apnContext.getApnType() + " clean up is required. The new " - + "waiting APN list " + waitingApns + " does not cover " - + apnContext.getApnSetting()); - } - apnContext.setReason(reason); - cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnContext); - } - } - } - } - - if (!isAnyDataConnected()) { - stopNetStatPoll(); - stopDataStallAlarm(); - } - - mRequestedApnType = ApnSetting.TYPE_DEFAULT; - - if (areAllDataDisconnected()) { - notifyAllDataDisconnected(); - } - } - - /** - * Polling stuff - */ - protected void resetPollStats() { - mTxPkts = -1; - mRxPkts = -1; - mNetStatPollPeriod = POLL_NETSTAT_MILLIS; - } - - protected void startNetStatPoll() { - if (isAnyDataConnected() && !mNetStatPollEnabled) { - if (DBG) { - log("startNetStatPoll"); - } - resetPollStats(); - mNetStatPollEnabled = true; - mPollNetStat.run(); - } - if (mPhone != null) { - mPhone.notifyDataActivity(); - } - } - - protected void stopNetStatPoll() { - mNetStatPollEnabled = false; - removeCallbacks(mPollNetStat); - if (DBG) { - log("stopNetStatPoll"); - } - - // To sync data activity icon in the case of switching data connection to send MMS. - if (mPhone != null) { - mPhone.notifyDataActivity(); - } - } - - public void sendStartNetStatPoll(DctConstants.Activity activity) { - Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL); - msg.arg1 = DctConstants.ENABLED; - msg.obj = activity; - sendMessage(msg); - } - - private void handleStartNetStatPoll(DctConstants.Activity activity) { - startNetStatPoll(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - setActivity(activity); - } - - public void sendStopNetStatPoll(DctConstants.Activity activity) { - Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL); - msg.arg1 = DctConstants.DISABLED; - msg.obj = activity; - sendMessage(msg); - } - - private void handleStopNetStatPoll(DctConstants.Activity activity) { - stopNetStatPoll(); - stopDataStallAlarm(); - setActivity(activity); - } - - private void onDataEnabledOverrideRulesChanged() { - if (DBG) { - log("onDataEnabledOverrideRulesChanged"); - } - - for (ApnContext apnContext : mPrioritySortedApnContexts) { - if (isDataAllowed(apnContext, REQUEST_TYPE_NORMAL, null)) { - if (apnContext.getDataConnection() != null) { - apnContext.getDataConnection().reevaluateRestrictedState(); - } - setupDataOnConnectableApn(apnContext, Phone.REASON_DATA_ENABLED_OVERRIDE, - RetryFailures.ALWAYS); - } else if (shouldCleanUpConnection(apnContext, true, false)) { - apnContext.setReason(Phone.REASON_DATA_ENABLED_OVERRIDE); - cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnContext); - } - } - } - - private void updateDataActivity() { - long sent, received; - - DctConstants.Activity newActivity; - - TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts); - TxRxSum curTxRxSum = new TxRxSum(); - curTxRxSum.updateTotalTxRxSum(); - mTxPkts = curTxRxSum.txPkts; - mRxPkts = curTxRxSum.rxPkts; - - if (VDBG) { - log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum); - } - - if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) { - sent = mTxPkts - preTxRxSum.txPkts; - received = mRxPkts - preTxRxSum.rxPkts; - - if (VDBG) - log("updateDataActivity: sent=" + sent + " received=" + received); - if (sent > 0 && received > 0) { - newActivity = DctConstants.Activity.DATAINANDOUT; - } else if (sent > 0 && received == 0) { - newActivity = DctConstants.Activity.DATAOUT; - } else if (sent == 0 && received > 0) { - newActivity = DctConstants.Activity.DATAIN; - } else { - newActivity = (mActivity == DctConstants.Activity.DORMANT) ? - mActivity : DctConstants.Activity.NONE; - } - - if (mActivity != newActivity && mIsScreenOn) { - if (VDBG) - log("updateDataActivity: newActivity=" + newActivity); - mActivity = newActivity; - mPhone.notifyDataActivity(); - } - } - } - - private void handlePcoData(AsyncResult ar) { - if (ar.exception != null) { - loge("PCO_DATA exception: " + ar.exception); - return; - } - PcoData pcoData = (PcoData)(ar.result); - ArrayList dcList = new ArrayList<>(); - DataConnection temp = mDcc.getActiveDcByCid(pcoData.cid); - if (temp != null) { - dcList.add(temp); - } - if (dcList.size() == 0) { - loge("PCO_DATA for unknown cid: " + pcoData.cid + ", inferring"); - for (DataConnection dc : mDataConnections.values()) { - final int cid = dc.getCid(); - if (cid == pcoData.cid) { - if (VDBG) log(" found " + dc); - dcList.clear(); - dcList.add(dc); - break; - } - // check if this dc is still connecting - if (cid == -1) { - for (ApnContext apnContext : dc.getApnContexts()) { - if (apnContext.getState() == DctConstants.State.CONNECTING) { - if (VDBG) log(" found potential " + dc); - dcList.add(dc); - break; - } - } - } - } - } - if (dcList.size() == 0) { - loge("PCO_DATA - couldn't infer cid"); - return; - } - for (DataConnection dc : dcList) { - List apnContextList = dc.getApnContexts(); - if (apnContextList.size() == 0) { - break; - } - // send one out for each apn type in play - for (ApnContext apnContext : apnContextList) { - String apnType = apnContext.getApnType(); - - final Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE); - intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, - ApnSetting.getApnTypesBitmaskFromString(apnType)); - intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL, - ApnSetting.getProtocolIntFromString(pcoData.bearerProto)); - intent.putExtra(TelephonyManager.EXTRA_PCO_ID, pcoData.pcoId); - intent.putExtra(TelephonyManager.EXTRA_PCO_VALUE, pcoData.contents); - mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); - } - } - } - - /** - * Data-Stall - */ - - // Recovery action taken in case of data stall - @IntDef( - value = { - RECOVERY_ACTION_GET_DATA_CALL_LIST, - RECOVERY_ACTION_CLEANUP, - RECOVERY_ACTION_REREGISTER, - RECOVERY_ACTION_RADIO_RESTART - }) - @Retention(RetentionPolicy.SOURCE) - public @interface RecoveryAction {}; - private static final int RECOVERY_ACTION_GET_DATA_CALL_LIST = 0; - private static final int RECOVERY_ACTION_CLEANUP = 1; - private static final int RECOVERY_ACTION_REREGISTER = 2; - private static final int RECOVERY_ACTION_RADIO_RESTART = 3; - - // Recovery handler class for cellular data stall - private class DataStallRecoveryHandler { - // Default minimum duration between each recovery steps - private static final int - DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS = (3 * 60 * 1000); // 3 mins - - // The elapsed real time of last recovery attempted - private long mTimeLastRecoveryStartMs; - // Whether current network good or not - private boolean mIsValidNetwork; - // Whether data stall happened or not. - private boolean mWasDataStall; - // Whether the result of last action(RADIO_RESTART) reported. - private boolean mLastActionReported; - // The real time for data stall start. - private long mDataStallStartMs; - // Last data stall action. - private @RecoveryAction int mLastAction; - - public DataStallRecoveryHandler() { - reset(); - } - - public void reset() { - mTimeLastRecoveryStartMs = 0; - putRecoveryAction(RECOVERY_ACTION_GET_DATA_CALL_LIST); - } - - private void setNetworkValidationState(boolean isValid) { - // Validation status is true and was not data stall. - if (isValid && !mWasDataStall) { - return; - } - - if (!mWasDataStall) { - mWasDataStall = true; - mDataStallStartMs = SystemClock.elapsedRealtime(); - if (DBG) log("data stall: start time = " + mDataStallStartMs); - return; - } - - if (!mLastActionReported) { - int timeDuration = (int) (SystemClock.elapsedRealtime() - mDataStallStartMs); - if (DBG) { - log("data stall: lastaction = " + mLastAction + ", isRecovered = " - + isValid + ", mTimeDuration = " + timeDuration); - } - DataStallRecoveryStats.onDataStallEvent(mLastAction, mPhone, isValid, - timeDuration); - mLastActionReported = true; - } - - if (isValid) { - mLastActionReported = false; - mWasDataStall = false; - } - } - - public boolean isAggressiveRecovery() { - @RecoveryAction int action = getRecoveryAction(); - - return ((action == RECOVERY_ACTION_CLEANUP) - || (action == RECOVERY_ACTION_REREGISTER) - || (action == RECOVERY_ACTION_RADIO_RESTART)); - } - - private long getMinDurationBetweenRecovery() { - return Settings.Global.getLong(mResolver, - Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, - DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS); - } - - private long getElapsedTimeSinceRecoveryMs() { - return (SystemClock.elapsedRealtime() - mTimeLastRecoveryStartMs); - } - - @RecoveryAction - private int getRecoveryAction() { - @RecoveryAction int action = Settings.System.getInt(mResolver, - "radio.data.stall.recovery.action", RECOVERY_ACTION_GET_DATA_CALL_LIST); - if (VDBG_STALL) log("getRecoveryAction: " + action); - return action; - } - - private void putRecoveryAction(@RecoveryAction int action) { - Settings.System.putInt(mResolver, "radio.data.stall.recovery.action", action); - if (VDBG_STALL) log("putRecoveryAction: " + action); - } - - private void broadcastDataStallDetected(@RecoveryAction int recoveryAction) { - Intent intent = new Intent(TelephonyManager.ACTION_DATA_STALL_DETECTED); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); - intent.putExtra(TelephonyManager.EXTRA_RECOVERY_ACTION, recoveryAction); - mPhone.getContext().sendBroadcast(intent, READ_PRIVILEGED_PHONE_STATE); - } - - private boolean isRecoveryAlreadyStarted() { - return getRecoveryAction() != RECOVERY_ACTION_GET_DATA_CALL_LIST; - } - - private boolean checkRecovery() { - // To avoid back to back recovery wait for a grace period - if (getElapsedTimeSinceRecoveryMs() < getMinDurationBetweenRecovery()) { - if (VDBG_STALL) log("skip back to back data stall recovery"); - return false; - } - - // Skip recovery if it can cause a call to drop - if (mPhone.getState() != PhoneConstants.State.IDLE - && getRecoveryAction() > RECOVERY_ACTION_CLEANUP) { - if (VDBG_STALL) log("skip data stall recovery as there is an active call"); - return false; - } - - // Allow recovery if data is expected to work - return mAttached.get() && isDataAllowed(null); - } - - private void triggerRecovery() { - // Updating the recovery start time early to avoid race when - // the message is being processed in the Queue - mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime(); - sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY)); - } - - public void doRecovery() { - if (isAnyDataConnected()) { - // Go through a series of recovery steps, each action transitions to the next action - @RecoveryAction final int recoveryAction = getRecoveryAction(); - final int signalStrength = mPhone.getSignalStrength().getLevel(); - TelephonyMetrics.getInstance().writeSignalStrengthEvent( - mPhone.getPhoneId(), signalStrength); - TelephonyMetrics.getInstance().writeDataStallEvent( - mPhone.getPhoneId(), recoveryAction); - mLastAction = recoveryAction; - mLastActionReported = false; - broadcastDataStallDetected(recoveryAction); - - switch (recoveryAction) { - case RECOVERY_ACTION_GET_DATA_CALL_LIST: - EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST, - mSentSinceLastRecv); - if (DBG) log("doRecovery() get data call list"); - mDataServiceManager.requestDataCallList(obtainMessage()); - putRecoveryAction(RECOVERY_ACTION_CLEANUP); - break; - case RECOVERY_ACTION_CLEANUP: - EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, - mSentSinceLastRecv); - if (DBG) log("doRecovery() cleanup all connections"); - cleanUpConnection(mApnContexts.get(ApnSetting.getApnTypeString( - ApnSetting.TYPE_DEFAULT))); - cleanUpConnection(mApnContexts.get(ApnSetting.getApnTypeString( - ApnSetting.TYPE_ENTERPRISE))); - putRecoveryAction(RECOVERY_ACTION_REREGISTER); - break; - case RECOVERY_ACTION_REREGISTER: - EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER, - mSentSinceLastRecv); - if (DBG) log("doRecovery() re-register"); - mPhone.getServiceStateTracker().reRegisterNetwork(null); - putRecoveryAction(RECOVERY_ACTION_RADIO_RESTART); - break; - case RECOVERY_ACTION_RADIO_RESTART: - EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART, - mSentSinceLastRecv); - if (DBG) log("restarting radio"); - restartRadio(); - reset(); - break; - default: - throw new RuntimeException("doRecovery: Invalid recoveryAction=" - + recoveryAction); - } - mSentSinceLastRecv = 0; - } - } - - public void processNetworkStatusChanged(boolean isValid) { - setNetworkValidationState(isValid); - if (isValid) { - mIsValidNetwork = true; - reset(); - } else { - if (mIsValidNetwork || isRecoveryAlreadyStarted()) { - mIsValidNetwork = false; - // Check and trigger a recovery if network switched from good - // to bad or recovery is already started before. - if (checkRecovery()) { - if (DBG) log("trigger data stall recovery"); - triggerRecovery(); - } - } - } - } - - public boolean isRecoveryOnBadNetworkEnabled() { - return Settings.Global.getInt(mResolver, - Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1) == 1; - } - - public boolean isNoRxDataStallDetectionEnabled() { - return mDataStallNoRxEnabled && !isRecoveryOnBadNetworkEnabled(); - } - } - - private void updateDataStallInfo() { - long sent, received; - - TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum); - mDataStallTxRxSum.updateTotalTxRxSum(); - - if (VDBG_STALL) { - log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum + - " preTxRxSum=" + preTxRxSum); - } - - sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts; - received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts; - - if (RADIO_TESTS) { - if (SystemProperties.getBoolean("radio.test.data.stall", false)) { - log("updateDataStallInfo: radio.test.data.stall true received = 0;"); - received = 0; - } - } - if ( sent > 0 && received > 0 ) { - if (VDBG_STALL) log("updateDataStallInfo: IN/OUT"); - mSentSinceLastRecv = 0; - mDsRecoveryHandler.reset(); - } else if (sent > 0 && received == 0) { - if (isPhoneStateIdle()) { - mSentSinceLastRecv += sent; - } else { - mSentSinceLastRecv = 0; - } - if (DBG) { - log("updateDataStallInfo: OUT sent=" + sent + - " mSentSinceLastRecv=" + mSentSinceLastRecv); - } - } else if (sent == 0 && received > 0) { - if (VDBG_STALL) log("updateDataStallInfo: IN"); - mSentSinceLastRecv = 0; - mDsRecoveryHandler.reset(); - } else { - if (VDBG_STALL) log("updateDataStallInfo: NONE"); - } - } - - private boolean isPhoneStateIdle() { - for (int i = 0; i < mTelephonyManager.getPhoneCount(); i++) { - Phone phone = PhoneFactory.getPhone(i); - if (phone != null && phone.getState() != PhoneConstants.State.IDLE) { - log("isPhoneStateIdle false: Voice call active on phone " + i); - return false; - } - } - return true; - } - - private void onDataStallAlarm(int tag) { - if (mDataStallAlarmTag != tag) { - if (DBG) { - log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag); - } - return; - } - - if (DBG) log("Data stall alarm"); - updateDataStallInfo(); - - int hangWatchdogTrigger = Settings.Global.getInt(mResolver, - Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, - NUMBER_SENT_PACKETS_OF_HANG); - - boolean suspectedStall = DATA_STALL_NOT_SUSPECTED; - if (mSentSinceLastRecv >= hangWatchdogTrigger) { - if (DBG) { - log("onDataStallAlarm: tag=" + tag + " do recovery action=" - + mDsRecoveryHandler.getRecoveryAction()); - } - suspectedStall = DATA_STALL_SUSPECTED; - sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY)); - } else { - if (VDBG_STALL) { - log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) + - " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger); - } - } - startDataStallAlarm(suspectedStall); - } - - protected void startDataStallAlarm(boolean suspectedStall) { - int delayInMs; - - if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled() && isAnyDataConnected()) { - // If screen is on or data stall is currently suspected, set the alarm - // with an aggressive timeout. - if (mIsScreenOn || suspectedStall || mDsRecoveryHandler.isAggressiveRecovery()) { - delayInMs = Settings.Global.getInt(mResolver, - Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS, - DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT); - } else { - delayInMs = Settings.Global.getInt(mResolver, - Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS, - DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT); - } - - mDataStallAlarmTag += 1; - if (VDBG_STALL) { - log("startDataStallAlarm: tag=" + mDataStallAlarmTag + - " delay=" + (delayInMs / 1000) + "s"); - } - Intent intent = new Intent(INTENT_DATA_STALL_ALARM); - intent.putExtra(INTENT_DATA_STALL_ALARM_EXTRA_TAG, mDataStallAlarmTag); - intent.putExtra(INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE, mTransportType); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); - mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, - SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent); - } else { - if (VDBG_STALL) { - log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag); - } - } - } - - private void stopDataStallAlarm() { - if (VDBG_STALL) { - log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag + - " mDataStallAlarmIntent=" + mDataStallAlarmIntent); - } - mDataStallAlarmTag += 1; - if (mDataStallAlarmIntent != null) { - mAlarmManager.cancel(mDataStallAlarmIntent); - mDataStallAlarmIntent = null; - } - } - - private void restartDataStallAlarm() { - if (!isAnyDataConnected()) return; - // To be called on screen status change. - // Do not cancel the alarm if it is set with aggressive timeout. - if (mDsRecoveryHandler.isAggressiveRecovery()) { - if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm."); - return; - } - if (VDBG_STALL) log("restartDataStallAlarm: stop then start."); - stopDataStallAlarm(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - } - - /** - * Provisioning APN - */ - private void onActionIntentProvisioningApnAlarm(Intent intent) { - if (DBG) log("onActionIntentProvisioningApnAlarm: action=" + intent.getAction()); - Message msg = obtainMessage(DctConstants.EVENT_PROVISIONING_APN_ALARM, - intent.getAction()); - msg.arg1 = intent.getIntExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, 0); - sendMessage(msg); - } - - private void startProvisioningApnAlarm() { - int delayInMs = Settings.Global.getInt(mResolver, - Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS, - PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT); - if (TelephonyUtils.IS_DEBUGGABLE) { - // Allow debug code to use a system property to provide another value - String delayInMsStrg = Integer.toString(delayInMs); - delayInMsStrg = System.getProperty(DEBUG_PROV_APN_ALARM, delayInMsStrg); - try { - delayInMs = Integer.parseInt(delayInMsStrg); - } catch (NumberFormatException e) { - loge("startProvisioningApnAlarm: e=" + e); - } - } - mProvisioningApnAlarmTag += 1; - if (DBG) { - log("startProvisioningApnAlarm: tag=" + mProvisioningApnAlarmTag + - " delay=" + (delayInMs / 1000) + "s"); - } - Intent intent = new Intent(INTENT_PROVISIONING_APN_ALARM); - intent.putExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, mProvisioningApnAlarmTag); - mProvisioningApnAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + delayInMs, mProvisioningApnAlarmIntent); - } - - private void stopProvisioningApnAlarm() { - if (DBG) { - log("stopProvisioningApnAlarm: current tag=" + mProvisioningApnAlarmTag + - " mProvsioningApnAlarmIntent=" + mProvisioningApnAlarmIntent); - } - mProvisioningApnAlarmTag += 1; - if (mProvisioningApnAlarmIntent != null) { - mAlarmManager.cancel(mProvisioningApnAlarmIntent); - mProvisioningApnAlarmIntent = null; - } - } - - /** - * 5G connection reevaluation alarm - */ - private void startWatchdogAlarm() { - sendMessageDelayed(obtainMessage(DctConstants.EVENT_NR_TIMER_WATCHDOG), mWatchdogTimeMs); - mWatchdog = true; - } - - private void stopWatchdogAlarm() { - removeMessages(DctConstants.EVENT_NR_TIMER_WATCHDOG); - mWatchdog = false; - } - - private void onDataServiceBindingChanged(boolean bound) { - if (!bound) { - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - boolean connPersistenceOnRestart = mPhone.getContext().getResources() - .getBoolean(com.android - .internal.R.bool.config_wlan_data_service_conn_persistence_on_restart); - if (!connPersistenceOnRestart) { - cleanUpAllConnectionsInternal(false, Phone.REASON_IWLAN_DATA_SERVICE_DIED); - } - } - } else { - //reset throttling after binding to data service - mDataThrottler.reset(); - } - mDataServiceBound = bound; - } - - public static String requestTypeToString(@RequestNetworkType int type) { - switch (type) { - case REQUEST_TYPE_NORMAL: return "NORMAL"; - case REQUEST_TYPE_HANDOVER: return "HANDOVER"; - } - return "UNKNOWN"; - } - - public static String releaseTypeToString(@ReleaseNetworkType int type) { - switch (type) { - case RELEASE_TYPE_NORMAL: return "NORMAL"; - case RELEASE_TYPE_DETACH: return "DETACH"; - case RELEASE_TYPE_HANDOVER: return "HANDOVER"; - } - return "UNKNOWN"; - } - - @RilRadioTechnology - protected int getDataRat() { - ServiceState ss = mPhone.getServiceState(); - NetworkRegistrationInfo nrs = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, mTransportType); - if (nrs != null) { - return ServiceState.networkTypeToRilRadioTechnology(nrs.getAccessNetworkTechnology()); - } - return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; - } - - @RilRadioTechnology - private int getVoiceRat() { - ServiceState ss = mPhone.getServiceState(); - NetworkRegistrationInfo nrs = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_CS, mTransportType); - if (nrs != null) { - return ServiceState.networkTypeToRilRadioTechnology(nrs.getAccessNetworkTechnology()); - } - return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; - } - - private void read5GConfiguration() { - if (DBG) log("read5GConfiguration"); - String[] bandwidths = CarrierConfigManager.getDefaultConfig().getStringArray( - CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY); - boolean useLte = false; - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); - if (b != null) { - if (b.getStringArray(CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY) != null) { - bandwidths = b.getStringArray(CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY); - } - useLte = b.getBoolean(CarrierConfigManager - .KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPLINK_BOOL); - mWatchdogTimeMs = b.getLong(CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG); - mNrNsaAllUnmetered = b.getBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_BOOL); - mNrNsaMmwaveUnmetered = b.getBoolean( - CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL); - mNrNsaSub6Unmetered = b.getBoolean( - CarrierConfigManager.KEY_UNMETERED_NR_NSA_SUB6_BOOL); - mNrSaAllUnmetered = b.getBoolean(CarrierConfigManager.KEY_UNMETERED_NR_SA_BOOL); - mNrSaMmwaveUnmetered = b.getBoolean( - CarrierConfigManager.KEY_UNMETERED_NR_SA_MMWAVE_BOOL); - mNrSaSub6Unmetered = b.getBoolean( - CarrierConfigManager.KEY_UNMETERED_NR_SA_SUB6_BOOL); - mNrNsaRoamingUnmetered = b.getBoolean( - CarrierConfigManager.KEY_UNMETERED_NR_NSA_WHEN_ROAMING_BOOL); - mLteEndcUsingUserDataForRrcDetection = b.getBoolean( - CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL); - } - } - updateLinkBandwidths(bandwidths, useLte); - } - - public boolean getLteEndcUsingUserDataForIdleDetection() { - return mLteEndcUsingUserDataForRrcDetection; - } - - /** - * Register for physical link status (i.e. RRC state) changed event. - * if {@link CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL} is true, - * then physical link state is focusing on "internet data connection" instead of RRC state. - * - * @param h The handler - * @param what The event - */ - public void registerForPhysicalLinkStatusChanged(Handler h, int what) { - mDcc.registerForPhysicalLinkStatusChanged(h, what); - } - - /** - * Unregister from physical link status (i.e. RRC state) changed event. - * - * @param h The previously registered handler - */ - public void unregisterForPhysicalLinkStatusChanged(Handler h) { - mDcc.unregisterForPhysicalLinkStatusChanged(h); - } - - // We use a specialized equals function in Apn setting when checking if an active - // data connection is still legitimate to use against a different apn setting. - // This method is extracted to a function to ensure that any future changes to this check will - // be applied to both cleanUpConnectionsOnUpdatedApns and checkForCompatibleDataConnection. - // Fix for b/158908392. - private boolean areCompatible(ApnSetting apnSetting1, ApnSetting apnSetting2) { - return apnSetting1.equals(apnSetting2, - mPhone.getServiceState().getDataRoamingFromRegistration()); - } - - @NonNull - private PersistableBundle getCarrierConfig() { - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - // If an invalid subId is used, this bundle will contain default values. - PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId()); - if (config != null) { - return config; - } - } - // Return static default defined in CarrierConfigManager. - return CarrierConfigManager.getDefaultConfig(); - } - - /** - * @return The data service manager. - */ - public @NonNull DataServiceManager getDataServiceManager() { - return mDataServiceManager; - } - - /** - * @return The data throttler - */ - public @NonNull DataThrottler getDataThrottler() { - return mDataThrottler; - } - - private void showProvisioningNotification() { - final Intent intent = new Intent(DcTracker.INTENT_PROVISION); - intent.putExtra(DcTracker.EXTRA_PROVISION_PHONE_ID, mPhone.getPhoneId()); - final PendingIntent pendingIntent = PendingIntent.getBroadcast( - mPhone.getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE); - - final Resources r = mPhone.getContext().getResources(); - final String title = r.getString(R.string.network_available_sign_in, 0); - final String details = mTelephonyManager.getNetworkOperator(mPhone.getSubId()); - final Notification.Builder builder = new Notification.Builder(mPhone.getContext()) - .setWhen(System.currentTimeMillis()) - .setSmallIcon(R.drawable.stat_notify_rssi_in_range) - .setChannelId(NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS) - .setAutoCancel(true) - .setTicker(title) - .setColor(mPhone.getContext().getColor( - com.android.internal.R.color.system_notification_accent_color)) - .setContentTitle(title) - .setContentText(details) - .setContentIntent(pendingIntent) - .setLocalOnly(true) - .setOnlyAlertOnce(true); - - final Notification notification = builder.build(); - try { - getNotificationManager().notify(NOTIFICATION_TAG, mPhone.getPhoneId(), notification); - } catch (final NullPointerException npe) { - Log.e(mLogTag, "showProvisioningNotification: error showing notification", npe); - } - } - - private void hideProvisioningNotification() { - try { - getNotificationManager().cancel(NOTIFICATION_TAG, mPhone.getPhoneId()); - } catch (final NullPointerException npe) { - Log.e(mLogTag, "hideProvisioningNotification: error hiding notification", npe); - } - } - - private NotificationManager getNotificationManager() { - return (NotificationManager) mPhone.getContext() - .createContextAsUser(UserHandle.ALL, 0 /* flags */) - .getSystemService(Context.NOTIFICATION_SERVICE); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/README.txt b/src/java/com/android/internal/telephony/dataconnection/README.txt deleted file mode 100644 index e613a00a36..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/README.txt +++ /dev/null @@ -1,71 +0,0 @@ -This package contains classes used to manage a DataConnection. - -A criticial aspect of this class is that most objects in this -package run on the same thread except DataConnectionTracker -This makes processing efficient as it minimizes context -switching and it eliminates issues with multi-threading. - -This can be done because all actions are either asynchronous -or are known to be non-blocking and fast. At this time only -DcTesterDeactivateAll takes specific advantage of this -single threading knowledge by using Dcc#mDcListAll so be -very careful when making changes that break this assumption. - -A related change was in DataConnectionAc I added code that -checks to see if the caller is on a different thread. If -it is then the AsyncChannel#sendMessageSynchronously is -used. If the caller is on the same thread then a getter -is used. This allows the DCAC to be used from any thread -and was required to fix a bug when Dcc called -PhoneBase#notifyDataConnection which calls DCT#getLinkProperties -and DCT#getLinkCapabilities which call Dcc all on the same -thread. Without this change there was a dead lock when -sendMessageSynchronously blocks. - - -== Testing == - -The following are Intents that can be sent for testing pruproses on -DEBUGGABLE builds (userdebug, eng) - -*) Causes bringUp and retry requests to fail for all DC's - - adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_fail_bringup --ei counter 2 --ei fail_cause -3 - -*) Causes all DC's to get torn down, simulating a temporary network outage: - - adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_deactivate_all - -*) To simplify testing we also have detach and attach simulations below where {x} is gsm, cdma or sip - - adb shell am broadcast -a com.android.internal.telephony.{x}.action_detached - adb shell am broadcast -a com.android.internal.telephony.{x}.action_attached - - -== System properties for Testing == - -On debuggable builds (userdebug, eng) you can change additional -settings through system properties. These properties can be set with -"setprop" for the current boot, or added to local.prop to persist -across boots. - -device# setprop key value - -device# echo "key=value" >> /data/local.prop -device# chmod 644 /data/local.prop - - --- Retry configuration -- - -You can replace the connection retry configuration. For example, you -could change it to perform 4 retries at 5 second intervals: - -device# setprop test.data_retry_config "5000,5000,5000" - - --- Roaming -- - -You can force the telephony stack to always assume that it's roaming -to verify higher-level framework functionality: - -device# setprop telephony.test.forceRoaming true diff --git a/src/java/com/android/internal/telephony/dataconnection/TransportManager.java b/src/java/com/android/internal/telephony/dataconnection/TransportManager.java deleted file mode 100644 index 63358f4993..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/TransportManager.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import android.annotation.Nullable; -import android.os.Handler; -import android.os.Message; -import android.os.RegistrantList; -import android.telephony.AccessNetworkConstants; -import android.telephony.Annotation.ApnType; -import android.telephony.CarrierConfigManager; -import android.telephony.data.ApnSetting; -import android.util.LocalLog; -import android.util.SparseIntArray; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.data.AccessNetworksManager; -import com.android.internal.telephony.data.TelephonyNetworkFactory; -import com.android.telephony.Rlog; - -import java.util.concurrent.TimeUnit; - -/** - * This class represents the transport manager which manages available transports (i.e. WWAN or - * WLAN) and determine the correct transport for {@link TelephonyNetworkFactory} to handle the data - * requests. - * - * The device can operate in the following modes, which is stored in the system properties - * ro.telephony.iwlan_operation_mode. If the system properties is missing, then it's tied to - * IRadio version. For 1.4 or above, it's AP-assisted mdoe. For 1.3 or below, it's legacy mode. - * - * Legacy mode: - * Frameworks send all data requests to the default data service, which is the cellular data - * service. IWLAN should be still reported as a RAT on cellular network service. - * - * AP-assisted mode: - * IWLAN is handled by IWLAN data service extending {@link android.telephony.data.DataService}, - * IWLAN network service extending {@link android.telephony.NetworkService}, and qualified - * network service extending {@link android.telephony.data.QualifiedNetworksService}. - * - * The following settings for service package name need to be configured properly for - * frameworks to bind. - * - * Package name of data service: - * The resource overlay 'config_wlan_data_service_package' or, - * the carrier config - * {@link CarrierConfigManager#KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING}. - * The carrier config takes precedence over the resource overlay if both exist. - * - * Package name of network service - * The resource overlay 'config_wlan_network_service_package' or - * the carrier config - * {@link CarrierConfigManager#KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING}. - * The carrier config takes precedence over the resource overlay if both exist. - * - * Package name of qualified network service - * The resource overlay 'config_qualified_networks_service_package' or - * the carrier config - * {@link CarrierConfigManager# - * KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING}. - * The carrier config takes precedence over the resource overlay if both exist. - */ -public class TransportManager extends Handler { - private final String mLogTag; - - private static final int EVENT_QUALIFIED_NETWORKS_CHANGED = 1; - - private static final int EVENT_EVALUATE_TRANSPORT_PREFERENCE = 2; - - // Delay the re-evaluation if transport fall back. QNS will need to quickly change the - // preference back to the original transport to avoid another handover request. - private static final long FALL_BACK_REEVALUATE_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(3); - - private final Phone mPhone; - - private final LocalLog mLocalLog = new LocalLog(64); - - @Nullable - private AccessNetworksManager mAccessNetworksManager; - - /** - * The pending handover list. This is a list of APNs that are being handover to the new - * transport. The entry will be removed once handover is completed. The key - * is the APN type, and the value is the target transport that the APN is handovered to. - */ - private final SparseIntArray mPendingHandoverApns; - - /** - * The registrants for listening data handover needed events. - */ - private final RegistrantList mHandoverNeededEventRegistrants; - - /** - * Handover parameters - */ - @VisibleForTesting - public static final class HandoverParams { - /** - * The callback for handover complete. - */ - public interface HandoverCallback { - /** - * Called when handover is completed. - * - * @param success {@true} if handover succeeded, otherwise failed. - * @param fallback {@true} if handover failed, the data connection fallback to the - * original transport - */ - void onCompleted(boolean success, boolean fallback); - } - - public final @ApnType int apnType; - public final int targetTransport; - public final HandoverCallback callback; - - @VisibleForTesting - public HandoverParams(int apnType, int targetTransport, HandoverCallback callback) { - this.apnType = apnType; - this.targetTransport = targetTransport; - this.callback = callback; - } - } - - public TransportManager(Phone phone) { - mPhone = phone; - mPendingHandoverApns = new SparseIntArray(); - mHandoverNeededEventRegistrants = new RegistrantList(); - mLogTag = TransportManager.class.getSimpleName() + "-" + mPhone.getPhoneId(); - mAccessNetworksManager = mPhone.getAccessNetworksManager(); - mAccessNetworksManager.registerForQualifiedNetworksChanged(this, - EVENT_QUALIFIED_NETWORKS_CHANGED); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_QUALIFIED_NETWORKS_CHANGED: - if (!hasMessages(EVENT_EVALUATE_TRANSPORT_PREFERENCE)) { - sendEmptyMessage(EVENT_EVALUATE_TRANSPORT_PREFERENCE); - } - break; - case EVENT_EVALUATE_TRANSPORT_PREFERENCE: - evaluateTransportPreference(); - break; - default: - loge("Unexpected event " + msg.what); - break; - } - } - - /** - * Set the current transport of apn type. - * - * @param apnType The APN type - * @param transport The transport. Must be WWAN or WLAN. - */ - private synchronized void setCurrentTransport(@ApnType int apnType, int transport) { - mAccessNetworksManager.setCurrentTransport(apnType, transport); - } - - private boolean isHandoverPending() { - return mPendingHandoverApns.size() > 0; - } - - /** - * Evaluate the preferred transport for each APN type to see if handover is needed. - */ - private void evaluateTransportPreference() { - // Simultaneously handover is not supported today. Preference will be re-evaluated after - // handover completed. - if (isHandoverPending()) return; - logl("evaluateTransportPreference"); - for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { - int targetTransport = mAccessNetworksManager.getPreferredTransport(apnType); - if (targetTransport != mAccessNetworksManager.getCurrentTransport(apnType)) { - logl("Handover started for APN type: " - + ApnSetting.getApnTypeString(apnType) - + ", target transport: " - + AccessNetworkConstants.transportTypeToString(targetTransport)); - mPendingHandoverApns.put(apnType, targetTransport); - mHandoverNeededEventRegistrants.notifyResult( - new HandoverParams(apnType, targetTransport, - (success, fallback) -> { - // The callback for handover completed. - if (success) { - logl("Handover succeeded for APN type " - + ApnSetting.getApnTypeString(apnType)); - } else { - logl("APN type " - + ApnSetting.getApnTypeString(apnType) - + " handover to " - + AccessNetworkConstants.transportTypeToString( - targetTransport) + " failed" - + ", fallback=" + fallback); - } - - long delay = 0; - if (fallback) { - // No need to change the preference because we should - // fallback. Re-evaluate after few seconds to give QNS - // some time to change the preference back to the original - // transport. - delay = FALL_BACK_REEVALUATE_DELAY_MILLIS; - } else { - // If handover succeeds or failed without falling back - // to the original transport, we should move to the new - // transport (even if it is failed). - setCurrentTransport(apnType, targetTransport); - } - mPendingHandoverApns.delete(apnType); - sendEmptyMessageDelayed(EVENT_EVALUATE_TRANSPORT_PREFERENCE, - delay); - })); - - // Return here instead of processing the next APN type. The next APN type for - // handover will be evaluate again once current handover is completed. - return; - } - } - } - - /** - * Register for data handover needed event - * - * @param h The handler of the event - * @param what The id of the event - */ - public void registerForHandoverNeededEvent(Handler h, int what) { - if (h != null) { - mHandoverNeededEventRegistrants.addUnique(h, what, null); - } - } - - /** - * Unregister for data handover needed event - * - * @param h The handler - */ - public void unregisterForHandoverNeededEvent(Handler h) { - mHandoverNeededEventRegistrants.remove(h); - } - - /** - * Registers the data throttler with DcTracker. - */ - public void registerDataThrottler(DataThrottler dataThrottler) { - if (mAccessNetworksManager != null) { - mAccessNetworksManager.registerDataThrottler(dataThrottler); - } - } - - private void logl(String s) { - log(s); - mLocalLog.log(s); - } - - private void log(String s) { - Rlog.d(mLogTag, s); - } - - private void loge(String s) { - Rlog.e(mLogTag, s); - } -} diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index 322dd55f7c..f9032bfc83 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -41,7 +41,6 @@ import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneNotifier; -import com.android.internal.telephony.dataconnection.DataConnection; import com.android.internal.telephony.uicc.IccFileHandler; import com.android.telephony.Rlog; @@ -173,11 +172,6 @@ abstract class ImsPhoneBase extends Phone { return new ArrayList(0); } - @Override - public PhoneConstants.DataState getDataConnectionState() { - return PhoneConstants.DataState.DISCONNECTED; - } - @Override public @DataActivityType int getDataActivityState() { return TelephonyManager.DATA_ACTIVITY_NONE; @@ -434,10 +428,6 @@ abstract class ImsPhoneBase extends Phone { Message response) { } - public List getCurrentDataConnectionList () { - return null; - } - @Override public void updateServiceLocation() { } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index e72571e113..1f2b0ea7b2 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -68,6 +68,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyLocalConnection; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.DataEnabledChangedReason; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsCallSession; @@ -119,8 +120,6 @@ import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.d2d.RtpTransport; import com.android.internal.telephony.data.DataSettingsManager; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; -import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.imsphone.ImsPhone.ImsDialArgs; @@ -966,8 +965,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } }; - // TODO: make @NonNull after removing DataEnabledSettings - private DataSettingsManager.DataSettingsManagerCallback mSettingsCallback; + private @NonNull DataSettingsManager.DataSettingsManagerCallback mSettingsCallback; /** * Allows the FeatureConnector used to be swapped for easier testing. @@ -1013,39 +1011,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mPhone.getContext().registerReceiver(mReceiver, intentfilter); updateCarrierConfiguration(mPhone.getSubId(), getCarrierConfigBundle(mPhone.getSubId())); - if (mPhone.getDefaultPhone().isUsingNewDataStack()) { - mSettingsCallback = new DataSettingsManager.DataSettingsManagerCallback(this::post) { - @Override - public void onDataEnabledChanged(boolean enabled, - @TelephonyManager.DataEnabledChangedReason int reason, - @NonNull String callingPackage) { - int internalReason; - switch (reason) { - case TelephonyManager.DATA_ENABLED_REASON_USER: - internalReason = DataEnabledSettings.REASON_USER_DATA_ENABLED; - break; - case TelephonyManager.DATA_ENABLED_REASON_POLICY: - internalReason = DataEnabledSettings.REASON_POLICY_DATA_ENABLED; - break; - case TelephonyManager.DATA_ENABLED_REASON_CARRIER: - internalReason = DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER; - break; - case TelephonyManager.DATA_ENABLED_REASON_THERMAL: - internalReason = DataEnabledSettings.REASON_THERMAL_DATA_ENABLED; - break; - case TelephonyManager.DATA_ENABLED_REASON_OVERRIDE: - internalReason = DataEnabledSettings.REASON_OVERRIDE_RULE_CHANGED; - break; - default: - internalReason = DataEnabledSettings.REASON_INTERNAL_DATA_ENABLED; - } - ImsPhoneCallTracker.this.onDataEnabledChanged(enabled, internalReason); - }}; - mPhone.getDefaultPhone().getDataSettingsManager().registerCallback(mSettingsCallback); - } else { - mPhone.getDefaultPhone().getDataEnabledSettings().registerForDataEnabledChanged( - this, EVENT_DATA_ENABLED_CHANGED, null); - } + mSettingsCallback = new DataSettingsManager.DataSettingsManagerCallback(this::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + ImsPhoneCallTracker.this.onDataEnabledChanged(enabled, reason); + }}; + mPhone.getDefaultPhone().getDataSettingsManager().registerCallback(mSettingsCallback); final TelecomManager telecomManager = (TelecomManager) mPhone.getContext().getSystemService(Context.TELECOM_SERVICE); @@ -1290,11 +1263,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { clearDisconnected(); mPhone.getContext().unregisterReceiver(mReceiver); - if (mPhone.getDefaultPhone().isUsingNewDataStack()) { - mPhone.getDefaultPhone().getDataSettingsManager().unregisterCallback(mSettingsCallback); - } else { - mPhone.getDefaultPhone().getDataEnabledSettings().unregisterForDataEnabledChanged(this); - } + mPhone.getDefaultPhone().getDataSettingsManager().unregisterCallback(mSettingsCallback); mImsManagerConnector.disconnect(); final NetworkStatsManager statsManager = @@ -2810,7 +2779,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private void maybeSetVideoCallProvider(ImsPhoneConnection conn, ImsCall imsCall) { android.telecom.Connection.VideoProvider connVideoProvider = conn.getVideoProvider(); - ImsCallSession callSession = imsCall.getCallSession(); + ImsCallSession callSession = imsCall.getCallSession(); if (connVideoProvider != null || callSession == null || callSession.getVideoCallProvider() == null) { return; @@ -3840,15 +3809,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { @Override public void onCallHandover(ImsCall imsCall, int srcAccessTech, int targetAccessTech, ImsReasonInfo reasonInfo) { - // Check with the DCTracker to see if data is enabled; there may be a case when + // Check if data is enabled; there may be a case when // ImsPhoneCallTracker isn't being informed of the right data enabled state via its // registration, so we'll refresh now. boolean isDataEnabled; - if (mPhone.getDefaultPhone().isUsingNewDataStack()) { - isDataEnabled = mPhone.getDefaultPhone().getDataSettingsManager().isDataEnabled(); - } else { - isDataEnabled = mPhone.getDefaultPhone().getDataEnabledSettings().isDataEnabled(); - } + isDataEnabled = mPhone.getDefaultPhone().getDataSettingsManager().isDataEnabled(); if (DBG) { log("onCallHandover :: srcAccessTech=" + srcAccessTech + ", targetAccessTech=" @@ -5028,10 +4993,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { /** * Handler of data enabled changed event * @param enabled True if data is enabled, otherwise disabled. - * @param reason Reason for data enabled/disabled. See {@link DataEnabledChangedReason}. + * @param reason Reason for data enabled/disabled. */ private void onDataEnabledChanged(boolean enabled, @DataEnabledChangedReason int reason) { - // TODO: TelephonyManager.DataEnabledChangedReason instead once DataEnabledSettings is gone log("onDataEnabledChanged: enabled=" + enabled + ", reason=" + reason); mIsDataEnabled = enabled; @@ -5051,9 +5015,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } int reasonCode; - if (reason == DataEnabledSettings.REASON_POLICY_DATA_ENABLED) { + if (reason == TelephonyManager.DATA_ENABLED_REASON_POLICY) { reasonCode = ImsReasonInfo.CODE_DATA_LIMIT_REACHED; - } else if (reason == DataEnabledSettings.REASON_USER_DATA_ENABLED) { + } else if (reason == TelephonyManager.DATA_ENABLED_REASON_USER) { reasonCode = ImsReasonInfo.CODE_DATA_DISABLED; } else { // Unexpected code, default to data disabled. @@ -5066,10 +5030,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // Handle video state changes required as a result of data being enabled/disabled. handleDataEnabledChange(enabled, reasonCode); - // We do not want to update the ImsConfig for REASON_REGISTERED, since it can happen before + // We do not want to update the ImsConfig for REASON_UNKNOWN, since it can happen before // the carrier config has loaded and will deregister IMS. if (!mShouldUpdateImsConfigOnDisconnect - && reason != DataEnabledSettings.REASON_REGISTERED + && reason != TelephonyManager.DATA_ENABLED_REASON_UNKNOWN && mCarrierConfigLoadedForSubscription) { // This will call into updateVideoCallFeatureValue and eventually all clients will be // asynchronously notified that the availability of VT over LTE has changed. diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java index 5ade0bb000..77e758b6d9 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -26,7 +26,6 @@ import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyStatsLog; import com.android.internal.telephony.data.DataStallRecoveryManager; -import com.android.internal.telephony.dataconnection.DcTracker; /** Generates metrics related to data stall recovery events per phone ID for the pushed atom. */ public class DataStallRecoveryStats { @@ -41,42 +40,6 @@ public class DataStallRecoveryStats { private static final int RECOVERY_ACTION_RADIO_RESTART_MAPPING = 3; private static final int RECOVERY_ACTION_RESET_MODEM_MAPPING = 4; - - /** TODO: b/214044479 : Remove this function when new data design(Android T) start. */ - public static void onDataStallEvent( - @DcTracker.RecoveryAction int recoveryAction, - Phone phone, - boolean isRecovered, - int durationMillis) { - if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { - phone = phone.getDefaultPhone(); - } - - int carrierId = phone.getCarrierId(); - int rat = getRat(phone); - int band = - (rat == TelephonyManager.NETWORK_TYPE_IWLAN) ? 0 : ServiceStateStats.getBand(phone); - // the number returned here matches the SignalStrength enum we have - int signalStrength = phone.getSignalStrength().getLevel(); - boolean isOpportunistic = getIsOpportunistic(phone); - boolean isMultiSim = SimSlotState.getCurrentState().numActiveSims > 1; - - // Not use this field in Android S, so we send RECOVERED_REASON_NONE for default value. - int recoveryReason = 0; - TelephonyStatsLog.write( - TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, - carrierId, - rat, - signalStrength, - recoveryAction, - isOpportunistic, - isMultiSim, - band, - isRecovered, - durationMillis, - recoveryReason); - } - /** * Called when data stall happened. * diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 9805d8b1ac..e1e37a6a3e 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -483,8 +483,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return StatsManager.PULL_SKIP; } - data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, - phones[0].isUsingNewDataStack())); + data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, true)); return StatsManager.PULL_SUCCESS; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index bbb463980f..e1b629d379 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -55,7 +55,7 @@ import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; +import com.android.internal.telephony.data.DataSettingsManager; import org.junit.After; import org.junit.Assert; @@ -75,8 +75,8 @@ import java.util.concurrent.atomic.AtomicBoolean; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class MultiSimSettingControllerTest extends TelephonyTest { - private static final int SINGLE_SIM = 1; private static final int DUAL_SIM = 2; + private static final String PHONE_PACKAGE = "com.android.internal.telephony"; private MultiSimSettingController mMultiSimSettingControllerUT; private Phone[] mPhones; private ParcelUuid mGroupUuid1 = new ParcelUuid(UUID.randomUUID()); @@ -85,8 +85,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { private SubscriptionController mSubControllerMock; private Phone mPhoneMock1; private Phone mPhoneMock2; - private DataEnabledSettings mDataEnabledSettingsMock1; - private DataEnabledSettings mDataEnabledSettingsMock2; + private DataSettingsManager mDataSettingsManagerMock1; + private DataSettingsManager mDataSettingsManagerMock2; private CommandsInterface mMockCi; @@ -118,8 +118,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mSubControllerMock = mock(SubscriptionController.class); mPhoneMock1 = mock(Phone.class); mPhoneMock2 = mock(Phone.class); - mDataEnabledSettingsMock1 = mock(DataEnabledSettings.class); - mDataEnabledSettingsMock2 = mock(DataEnabledSettings.class); + mDataSettingsManagerMock1 = mock(DataSettingsManager.class); + mDataSettingsManagerMock2 = mock(DataSettingsManager.class); mMockCi = mock(CommandsInterface.class); // Default configuration: // DSDS device. @@ -145,8 +145,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new int[]{1, 2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mPhones = new Phone[] {mPhoneMock1, mPhoneMock2}; - doReturn(mDataEnabledSettingsMock1).when(mPhoneMock1).getDataEnabledSettings(); - doReturn(mDataEnabledSettingsMock2).when(mPhoneMock2).getDataEnabledSettings(); + doReturn(mDataSettingsManagerMock1).when(mPhoneMock1).getDataSettingsManager(); + doReturn(mDataSettingsManagerMock2).when(mPhoneMock2).getDataSettingsManager(); doReturn(Arrays.asList(mSubInfo1)).when(mSubControllerMock).getSubInfo( eq(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 1), any()); @@ -385,8 +385,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // Enable on non-default sub should trigger setDefaultDataSubId. mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); @@ -397,8 +397,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); - verify(mDataEnabledSettingsMock1).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock1).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); doReturn(1).when(mSubControllerMock).getDefaultSmsSubId(); @@ -440,10 +440,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataEnabledSettingsMock1).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock1).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // as a result of the above calls, update new values to be returned doReturn(false).when(mPhoneMock1).isUserDataEnabled(); @@ -458,8 +458,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); - verify(mDataEnabledSettingsMock1, times(1)).setDataEnabled(anyInt(), anyBoolean()); - verify(mDataEnabledSettingsMock2, times(1)).setDataEnabled(anyInt(), anyBoolean()); + verify(mDataSettingsManagerMock1, times(1)) + .setDataEnabled(anyInt(), anyBoolean(), anyString()); + verify(mDataSettingsManagerMock2, times(1)) + .setDataEnabled(anyInt(), anyBoolean(), anyString()); } @Test @@ -478,10 +480,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataEnabledSettingsMock1).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock1).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // as a result of the above calls, update new values to be returned doReturn(false).when(mPhoneMock1).isUserDataEnabled(); @@ -529,8 +531,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); mMultiSimSettingControllerUT.notifyUserDataEnabled(2, false); processAllMessages(); assertFalse(GlobalSettingsHelper.getBoolean( @@ -578,13 +580,13 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); verify(mSubControllerMock).setDefaultDataSubId(2); - verify(mDataEnabledSettingsMock1, never()).setDataEnabled( - anyInt(), anyBoolean()); + verify(mDataSettingsManagerMock1, never()).setDataEnabled( + anyInt(), anyBoolean(), anyString()); verifyDismissIntentSent(); clearInvocations(mSubControllerMock); - clearInvocations(mDataEnabledSettingsMock1); - clearInvocations(mDataEnabledSettingsMock2); + clearInvocations(mDataSettingsManagerMock1); + clearInvocations(mDataSettingsManagerMock2); doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); // Toggle data on sub 1 or sub 2. Nothing should happen as they are independent. mMultiSimSettingControllerUT.notifyUserDataEnabled(1, false); @@ -595,10 +597,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); processAllMessages(); verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); - verify(mDataEnabledSettingsMock1, never()).setDataEnabled( - eq(TelephonyManager.DATA_ENABLED_REASON_USER), anyBoolean()); - verify(mDataEnabledSettingsMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock1, never()).setDataEnabled( + eq(TelephonyManager.DATA_ENABLED_REASON_USER), anyBoolean(), anyString()); + verify(mDataSettingsManagerMock2, never()).setDataEnabled( + eq(TelephonyManager.DATA_ENABLED_REASON_USER), eq(false), anyString()); } private void verifyDismissIntentSent() { @@ -636,7 +638,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // This should result in setting sync. - verify(mDataEnabledSettingsMock1).setUserDataEnabled(false, false); + verify(mDataSettingsManagerMock1).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, + false, PHONE_PACKAGE); assertFalse(GlobalSettingsHelper.getBoolean( mContext, Settings.Global.DATA_ROAMING, 1, true)); @@ -645,7 +648,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Turning data on on sub 2. Sub 1 should also be turned on. mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); processAllMessages(); - verify(mDataEnabledSettingsMock1).setUserDataEnabled(true, false); + verify(mDataSettingsManagerMock1).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, + true, PHONE_PACKAGE); verifyDismissIntentSent(); } @@ -715,7 +719,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // This should result in setting sync. - verify(mDataEnabledSettingsMock2).setUserDataEnabled(true, false); + verify(mDataSettingsManagerMock2).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, + true, PHONE_PACKAGE); assertFalse(GlobalSettingsHelper.getBoolean( mContext, Settings.Global.DATA_ROAMING, 2, true)); verify(mSubControllerMock).setDataRoaming(/*enable*/0, /*subId*/1); @@ -724,7 +729,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(false).when(mPhoneMock1).isUserDataEnabled(); mMultiSimSettingControllerUT.notifyUserDataEnabled(1, false); processAllMessages(); - verify(mDataEnabledSettingsMock2).setUserDataEnabled(false, false); + verify(mDataSettingsManagerMock2).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, + false, PHONE_PACKAGE); } @Test @@ -736,16 +742,16 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // loaded on both subscriptions. mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); processAllMessages(); - verify(mDataEnabledSettingsMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2, never()).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); processAllMessages(); - verify(mDataEnabledSettingsMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2, never()).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // Switch from sub 2 to sub 3 in phone[1]. clearInvocations(mSubControllerMock); @@ -827,8 +833,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); // Nothing should happen as carrier config is not ready for sub 2. - verify(mDataEnabledSettingsMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2, never()).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // Still notify carrier config without specifying subId2, but this time subController // and CarrierConfigManager have subId 2 active and ready. @@ -840,8 +846,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); // This time user data should be disabled on phone1. - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index 0230645b59..4b0cc6196c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import android.content.Context; import android.content.Intent; @@ -34,25 +35,25 @@ import android.os.PersistableBundle; import android.os.PowerManager; import android.telephony.CarrierConfigManager; import android.telephony.NetworkRegistrationInfo; -import android.telephony.PcoData; import android.telephony.PhysicalChannelConfig; import android.telephony.RadioAccessFamily; import android.telephony.ServiceState; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import com.android.internal.telephony.dataconnection.DataConnection; +import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; import com.android.internal.util.IState; import com.android.internal.util.StateMachine; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.lang.reflect.Method; import java.util.ArrayList; @@ -60,6 +61,7 @@ import java.util.List; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper +@Ignore("b/240911460") public class NetworkTypeControllerTest extends TelephonyTest { // private constants copied over from NetworkTypeController private static final int EVENT_DATA_RAT_CHANGED = 2; @@ -67,21 +69,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { private static final int EVENT_NR_FREQUENCY_CHANGED = 4; private static final int EVENT_PHYSICAL_LINK_STATUS_CHANGED = 5; private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED = 6; - private static final int EVENT_CARRIER_CONFIG_CHANGED = 7; - private static final int EVENT_PRIMARY_TIMER_EXPIRED = 8; - private static final int EVENT_SECONDARY_TIMER_EXPIRED = 9; private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 10; private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11; - private static final int EVENT_INITIALIZE = 12; private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 13; - private static final int EVENT_PCO_DATA_CHANGED = 14; private NetworkTypeController mNetworkTypeController; private PersistableBundle mBundle; - - // Mocked classes - DataConnection mDataConnection; - ApnSetting mApnSetting; + private DataNetworkControllerCallback mDataNetworkControllerCallback; private IState getCurrentState() throws Exception { Method method = StateMachine.class.getDeclaredMethod("getCurrentState"); @@ -106,23 +100,28 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); - mDataConnection = mock(DataConnection.class); - mApnSetting = mock(ApnSetting.class); mBundle = mContextFixture.getCarrierConfigBundle(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING, "connected_mmwave:5G_Plus,connected:5G,not_restricted_rrc_idle:5G," + "not_restricted_rrc_con:5G"); + mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); replaceInstance(Handler.class, "mLooper", mDisplayInfoController, Looper.myLooper()); doReturn(RadioAccessFamily.getRafFromNetworkType( TelephonyManager.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA)).when( mPhone).getCachedAllowedNetworkTypesBitmask(); - doReturn(false).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( + doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); doReturn(new int[] {0}).when(mServiceState).getCellBandwidths(); mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); processAllMessages(); + + ArgumentCaptor dataNetworkControllerCallbackCaptor = + ArgumentCaptor.forClass(DataNetworkControllerCallback.class); + verify(mDataNetworkController).registerDataNetworkControllerCallback( + dataNetworkControllerCallbackCaptor.capture()); + mDataNetworkControllerCallback = dataNetworkControllerCallbackCaptor.getValue(); } @After @@ -474,42 +473,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); - int cid = 1; - byte[] contents = new byte[]{0}; - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); - doReturn(mApnSetting).when(mDataConnection).getApnSetting(); - doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); - - - mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, - new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); - processAllMessages(); - assertEquals("connected", getCurrentState().getName()); - } - - @Test - public void testTransitionToCurrentStateNrConnectedWithPcoLength4AndNoNrAdvancedCapable() - throws Exception { - assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); - doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); - int cid = 1; - byte[] contents = new byte[]{31, 1, 84, 0}; - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); - doReturn(mApnSetting).when(mDataConnection).getApnSetting(); - doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); - - - mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, - new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); + mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(false); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); processAllMessages(); assertEquals("connected", getCurrentState().getName()); @@ -522,19 +486,10 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); - int cid = 1; - byte[] contents = new byte[]{1}; - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); - doReturn(mApnSetting).when(mDataConnection).getApnSetting(); - doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF00); broadcastCarrierConfigs(); - - mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, - new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); + mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(false); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); processAllMessages(); assertEquals("connected", getCurrentState().getName()); @@ -547,39 +502,12 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - int cid = 1; - byte[] contents = new byte[]{1}; - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); - doReturn(mApnSetting).when(mDataConnection).getApnSetting(); - doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, - new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); processAllMessages(); - assertEquals("connected_mmwave", getCurrentState().getName()); - } - - @Test - public void testTransitionToCurrentStateNrConnectedWithNrAdvancedCapableAndPcoLength4() - throws Exception { - assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); - doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - int cid = 1; - byte[] contents = new byte[]{31, 1, 84, 1}; - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); - doReturn(mApnSetting).when(mDataConnection).getApnSetting(); - doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); - - mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, - new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(true); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken b/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken deleted file mode 100644 index 80cd9f17b5..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import android.test.suitebuilder.annotation.MediumTest; -import com.android.internal.telephony.TestPhoneNotifier; -import com.android.internal.telephony.gsm.SmsMessage; -import com.android.internal.telephony.test.SimulatedCommands; -import com.android.internal.telephony.test.SimulatedRadioControl; -import com.android.internal.telephony.uicc.IccUtils; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.Suppress; - -import java.util.Iterator; - -/** - * {@hide} - */ -public class SMSDispatcherTest extends AndroidTestCase { - @MediumTest - public void testCMT1() throws Exception { - SmsMessage sms; - SmsHeader header; - - String[] lines = new String[2]; - - lines[0] = "+CMT: ,158"; - lines[1] = "07914140279510F6440A8111110301003BF56080426101748A8C0B05040B" - + "8423F000035502010106276170706C69636174696F6E2F766E642E776170" - + "2E6D6D732D6D65737361676500AF848D0185B4848C8298524F347839776F" - + "7547514D4141424C3641414141536741415A4B554141414141008D908918" - + "802B31363530323438363137392F545950453D504C4D4E008A808E028000" - + "88058103093A8083687474703A2F2F36"; - - sms = SmsMessage.newFromCMT(lines); - header = sms.getUserDataHeader(); - assertNotNull(header); - assertNotNull(sms.getUserData()); - assertNotNull(header.concatRef); - assertEquals(header.concatRef.refNumber, 85); - assertEquals(header.concatRef.msgCount, 2); - assertEquals(header.concatRef.seqNumber, 1); - assertEquals(header.concatRef.isEightBits, true); - assertNotNull(header.portAddrs); - assertEquals(header.portAddrs.destPort, 2948); - assertEquals(header.portAddrs.origPort, 9200); - assertEquals(header.portAddrs.areEightBits, false); - } - - @MediumTest - public void testCMT2() throws Exception { - SmsMessage sms; - SmsHeader header; - - String[] lines = new String[2]; - - lines[0] = "+CMT: ,77"; - lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F" - + "00003550202362E3130322E3137312E3135302F524F347839776F7547514D4141" - + "424C3641414141536741415A4B55414141414100"; - - sms = SmsMessage.newFromCMT(lines); - header = sms.getUserDataHeader(); - assertNotNull(header); - assertNotNull(sms.getUserData()); - assertNotNull(header.concatRef); - assertEquals(header.concatRef.refNumber, 85); - assertEquals(header.concatRef.msgCount, 2); - assertEquals(header.concatRef.seqNumber, 2); - assertEquals(header.concatRef.isEightBits, true); - assertNotNull(header.portAddrs); - assertEquals(header.portAddrs.destPort, 2948); - assertEquals(header.portAddrs.origPort, 9200); - assertEquals(header.portAddrs.areEightBits, false); - } - - @MediumTest - public void testEfRecord() throws Exception { - SmsMessage sms; - - String s = "03029111000c9194981492631000f269206190022000a053e4534a05358bd3" - + "69f05804259da0219418a40641536a110a0aea408080604028180e888462c1" - + "50341c0f484432a1542c174c46b3e1743c9f9068442a994ea8946ac56ab95e" - + "b0986c46abd96eb89c6ec7ebf97ec0a070482c1a8fc8a472c96c3a9fd0a874" - + "4aad5aafd8ac76cbed7abfe0b0784c2e9bcfe8b47acd6ebbdff0b87c4eafdb" - + "eff8bc7ecfeffbffffffffffffffffffffffffffff"; - byte[] data = IccUtils.hexStringToBytes(s); - - sms = SmsMessage.createFromEfRecord(1, data); - assertNotNull(sms.getMessageBody()); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 072f2190e0..1dbda5ba7c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -235,7 +235,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { doReturn(mIwlanNetworkServiceStub).when(mIwlanNetworkServiceStub).asBinder(); addNetworkService(); - doReturn(true).when(mDcTracker).areAllDataDisconnected(); doReturn(true).when(mDataNetworkController).areAllDataDisconnected(); doReturn(new ServiceState()).when(mPhone).getServiceState(); @@ -261,7 +260,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { int dds = SubscriptionManager.getDefaultDataSubscriptionId(); doReturn(dds).when(mPhone).getSubId(); - doReturn(true).when(mPhone).areAllDataDisconnected(); doReturn(true).when(mPackageManager) .hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA); @@ -391,7 +389,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); doReturn(dataNetworkController_phone2).when(phone2).getDataNetworkController(); doReturn(mSST).when(phone2).getServiceStateTracker(); - doReturn(true).when(phone2).isUsingNewDataStack(); doReturn(false).when(mDataNetworkController).areAllDataDisconnected(); doReturn(false).when(dataNetworkController_phone2).areAllDataDisconnected(); doReturn(1).when(mPhone).getSubId(); @@ -1771,29 +1768,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { assertEquals(TelephonyManager.RADIO_POWER_UNAVAILABLE, mSimulatedCommands.getRadioState()); } - @Test - @SmallTest - public void testImsRegisteredDelayShutDown() throws Exception { - doReturn(false).when(mPhone).isUsingNewDataStack(); - doReturn(true).when(mPhone).isPhoneTypeGsm(); - mContextFixture.putIntResource( - com.android.internal.R.integer.config_delay_for_ims_dereg_millis, 1000 /*ms*/); - sst.setImsRegistrationState(true); - mSimulatedCommands.setRadioPowerFailResponse(false); - sst.setRadioPower(true); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - - // Turn off the radio and ensure radio power is still on - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); - sst.setRadioPower(false); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); - - // Now set IMS reg state to false and ensure we see the modem move to power off. - sst.setImsRegistrationState(false); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); - } @Test @SmallTest @@ -1812,33 +1786,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); } - @Test - @SmallTest - public void testImsRegisteredDelayShutDownTimeout() throws Exception { - doReturn(false).when(mPhone).isUsingNewDataStack(); - doReturn(true).when(mPhone).isPhoneTypeGsm(); - mContextFixture.putIntResource( - com.android.internal.R.integer.config_delay_for_ims_dereg_millis, 1000 /*ms*/); - sst.setImsRegistrationState(true); - mSimulatedCommands.setRadioPowerFailResponse(false); - sst.setRadioPower(true); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - - // Turn off the radio and ensure radio power is still on - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); - sst.setRadioPower(false); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); - - // Ensure that if we never turn deregister for IMS, we still eventually see radio state - // move to off. - // Timeout for IMS reg + some extra time to remove race conditions - waitForDelayedHandlerAction(mSSTTestHandler.getThreadHandler(), - sst.getRadioPowerOffDelayTimeoutForImsRegistration() + 1000, 1000); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); - } - @Test @SmallTest public void testImsRegisteredAPMOnOffToggle() throws Exception { diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 6cc87813b9..6cb7464ff0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -103,9 +103,6 @@ import com.android.internal.telephony.data.DataRetryManager; import com.android.internal.telephony.data.DataServiceManager; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; -import com.android.internal.telephony.dataconnection.DataThrottler; -import com.android.internal.telephony.dataconnection.DcTracker; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; @@ -192,7 +189,6 @@ public abstract class TelephonyTest { protected RegistrantList mRegistrantList; protected IccPhoneBookInterfaceManager mIccPhoneBookIntManager; protected ImsManager mImsManager; - protected DcTracker mDcTracker; protected DataNetworkController mDataNetworkController; protected DataRetryManager mDataRetryManager; protected DataSettingsManager mDataSettingsManager; @@ -240,7 +236,6 @@ public abstract class TelephonyTest { protected SubscriptionInfoUpdater mSubInfoRecordUpdater; protected LocaleTracker mLocaleTracker; protected RestrictedState mRestrictedState; - protected DataEnabledSettings mDataEnabledSettings; protected DataEnabledOverride mDataEnabledOverride; protected PhoneConfigurationManager mPhoneConfigurationManager; protected CellularNetworkValidator mCellularNetworkValidator; @@ -254,7 +249,6 @@ public abstract class TelephonyTest { protected PersistAtomsStorage mPersistAtomsStorage; protected MetricsCollector mMetricsCollector; protected SmsStats mSmsStats; - protected DataThrottler mDataThrottler; protected SignalStrength mSignalStrength; protected WifiManager mWifiManager; protected WifiInfo mWifiInfo; @@ -426,7 +420,6 @@ public abstract class TelephonyTest { mRegistrantList = Mockito.mock(RegistrantList.class); mIccPhoneBookIntManager = Mockito.mock(IccPhoneBookInterfaceManager.class); mImsManager = Mockito.mock(ImsManager.class); - mDcTracker = Mockito.mock(DcTracker.class); mDataNetworkController = Mockito.mock(DataNetworkController.class); mDataRetryManager = Mockito.mock(DataRetryManager.class); mDataSettingsManager = Mockito.mock(DataSettingsManager.class); @@ -474,7 +467,6 @@ public abstract class TelephonyTest { mSubInfoRecordUpdater = Mockito.mock(SubscriptionInfoUpdater.class); mLocaleTracker = Mockito.mock(LocaleTracker.class); mRestrictedState = Mockito.mock(RestrictedState.class); - mDataEnabledSettings = Mockito.mock(DataEnabledSettings.class); mDataEnabledOverride = Mockito.mock(DataEnabledOverride.class); mPhoneConfigurationManager = Mockito.mock(PhoneConfigurationManager.class); mCellularNetworkValidator = Mockito.mock(CellularNetworkValidator.class); @@ -488,7 +480,6 @@ public abstract class TelephonyTest { mPersistAtomsStorage = Mockito.mock(PersistAtomsStorage.class); mMetricsCollector = Mockito.mock(MetricsCollector.class); mSmsStats = Mockito.mock(SmsStats.class); - mDataThrottler = Mockito.mock(DataThrottler.class); mSignalStrength = Mockito.mock(SignalStrength.class); mWifiManager = Mockito.mock(WifiManager.class); mWifiInfo = Mockito.mock(WifiInfo.class); @@ -569,8 +560,6 @@ public abstract class TelephonyTest { .makeGsmCdmaCallTracker(nullable(GsmCdmaPhone.class)); doReturn(mIccPhoneBookIntManager).when(mTelephonyComponentFactory) .makeIccPhoneBookInterfaceManager(nullable(Phone.class)); - doReturn(mDcTracker).when(mTelephonyComponentFactory) - .makeDcTracker(nullable(Phone.class), anyInt()); doReturn(mDisplayInfoController).when(mTelephonyComponentFactory) .makeDisplayInfoController(nullable(Phone.class)); doReturn(mWspTypeDecoder).when(mTelephonyComponentFactory) @@ -598,8 +587,6 @@ public abstract class TelephonyTest { doReturn(mLocaleTracker).when(mTelephonyComponentFactory) .makeLocaleTracker(nullable(Phone.class), nullable(NitzStateMachine.class), nullable(Looper.class)); - doReturn(mDataEnabledSettings).when(mTelephonyComponentFactory) - .makeDataEnabledSettings(nullable(Phone.class)); doReturn(mEriManager).when(mTelephonyComponentFactory) .makeEriManager(nullable(Phone.class), anyInt()); doReturn(mLinkBandwidthEstimator).when(mTelephonyComponentFactory) @@ -629,8 +616,6 @@ public abstract class TelephonyTest { doReturn(mAppSmsManager).when(mPhone).getAppSmsManager(); doReturn(mIccSmsInterfaceManager).when(mPhone).getIccSmsInterfaceManager(); doReturn(mAccessNetworksManager).when(mPhone).getAccessNetworksManager(); - doReturn(mDataEnabledSettings).when(mPhone).getDataEnabledSettings(); - doReturn(mDcTracker).when(mPhone).getDcTracker(anyInt()); doReturn(mDataSettingsManager).when(mDataNetworkController).getDataSettingsManager(); doReturn(mDataNetworkController).when(mPhone).getDataNetworkController(); doReturn(mDataSettingsManager).when(mPhone).getDataSettingsManager(); @@ -648,7 +633,6 @@ public abstract class TelephonyTest { doReturn(mDataProfileManager).when(mDataNetworkController).getDataProfileManager(); doReturn(mDataRetryManager).when(mDataNetworkController).getDataRetryManager(); doReturn(mCarrierPrivilegesTracker).when(mPhone).getCarrierPrivilegesTracker(); - doReturn(true).when(mPhone).isUsingNewDataStack(); doReturn(0).when(mPhone).getPhoneId(); //mUiccController @@ -739,11 +723,6 @@ public abstract class TelephonyTest { doReturn(new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) .when(mAccessNetworksManager).getAvailableTransports(); - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) - .getCurrentTransport(anyInt()); - doReturn(true).when(mDataEnabledSettings).isDataEnabled(); - doReturn(true).when(mDataEnabledSettings).isDataEnabled(anyInt()); - doReturn(true).when(mDataEnabledSettings).isInternalDataEnabled(); doReturn(true).when(mDataSettingsManager).isDataEnabled(); doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( anyInt(), anyInt()); @@ -779,8 +758,6 @@ public abstract class TelephonyTest { Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 1); Settings.Global.putInt(resolver, Settings.Global.DATA_ROAMING, 0); - doReturn(mDataThrottler).when(mDcTracker).getDataThrottler(); - doReturn(-1L).when(mDataThrottler).getRetryTime(anyInt()); doReturn(90).when(mDataConfigManager).getNetworkCapabilityPriority( eq(NetworkCapabilities.NET_CAPABILITY_EIMS)); diff --git a/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken b/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken deleted file mode 100644 index 761dfc7412..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2006 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; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import android.telephony.CellInfo; - -import java.util.List; - -/** - * Stub class used for unit tests - */ - -public class TestPhoneNotifier implements PhoneNotifier { - public TestPhoneNotifier() { - } - - public void notifyPhoneState(Phone sender) { - } - - public void notifyServiceState(Phone sender) { - } - - public void notifyCellLocation(Phone sender) { - } - - public void notifySignalStrength(Phone sender) { - } - - public void notifyMessageWaitingChanged(Phone sender) { - } - - public void notifyCallForwardingChanged(Phone sender) { - } - - public void notifyDataConnection(Phone sender, String reason, String apnType) { - } - - public void notifyDataConnection(Phone sender, String reason, String apnType, - PhoneConstants.DataState state) { - } - - public void notifyDataConnectionFailed(Phone sender, String reason, String apnType) { - } - - public void notifyDataActivity(Phone sender) { - } - - public void notifyOtaspChanged(Phone sender, int otaspMode) { - } - - public void notifyCellInfo(Phone sender, List cellInfo) { - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java similarity index 62% rename from tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java rename to tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java index 1812fa0770..b6d77e952e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java @@ -14,23 +14,20 @@ * limitations under the License. */ -package com.android.internal.telephony.dataconnection; +package com.android.internal.telephony.data; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.doReturn; import android.net.Uri; import android.os.Parcel; import android.os.PersistableBundle; -import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; -import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.TelephonyTest; @@ -118,213 +115,7 @@ public class ApnSettingTest extends TelephonyTest { } @Test - @SmallTest - public void testIsMetered() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - - doReturn(false).when(mServiceState).getDataRoaming(); - doReturn(1).when(mPhone).getSubId(); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_DEFAULT), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_FOTA), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_IA | ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_SUPL, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_CBS, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DUN, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_IA, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_HIPRI, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_ENTERPRISE, mPhone)); - - // Carrier config settings changes. - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); - } - - @Test - @SmallTest - public void testIsRoamingMetered() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - doReturn(true).when(mServiceState).getDataRoaming(); - doReturn(1).when(mPhone).getSubId(); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_DEFAULT), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_FOTA), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_IA | ApnSetting.TYPE_CBS), mPhone)); - - // Carrier config settings changes. - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_FOTA_STRING}); - - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_ENTERPRISE, mPhone)); - } - - @Test - @SmallTest - public void testIsMeteredAnother() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_CBS_STRING}); - - doReturn(false).when(mServiceState).getDataRoaming(); - doReturn(1).when(mPhone).getSubId(); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_SUPL), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_FOTA | ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_IA), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_IMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); - assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_XCAP), mPhone)); - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_ENTERPRISE), mPhone)); - } - - @Test - @SmallTest - public void testIsRoamingMeteredAnother() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_CBS_STRING}); - doReturn(true).when(mServiceState).getDataRoaming(); - doReturn(2).when(mPhone).getSubId(); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_SUPL), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_FOTA | ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_IA), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_IMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); - - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_SUPL, mPhone)); - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_CBS, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DUN, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_IA, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_HIPRI, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_ENTERPRISE, mPhone)); - } - - @Test - @SmallTest - public void testIsMeteredNothingCharged() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{}); - - doReturn(false).when(mServiceState).getDataRoaming(); - doReturn(3).when(mPhone).getSubId(); - - assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_IMS | ApnSetting.TYPE_MMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_FOTA), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - } - - @Test - @SmallTest - public void testIsRoamingMeteredNothingCharged() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{}); - doReturn(true).when(mServiceState).getDataRoaming(); - doReturn(3).when(mPhone).getSubId(); - - assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_IMS | ApnSetting.TYPE_MMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_FOTA), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - } - - @Test - @SmallTest public void testCanHandleType() { - String types[] = {"mms"}; - assertTrue(createApnSetting(ApnSetting.TYPE_ALL) .canHandleType(ApnSetting.TYPE_MMS)); @@ -402,7 +193,6 @@ public class ApnSettingTest extends TelephonyTest { } @Test - @SmallTest public void testEquals() throws Exception { final int dummyInt = 1; final int dummyLong = 1; @@ -451,7 +241,6 @@ public class ApnSettingTest extends TelephonyTest { } @Test - @SmallTest public void testEqualsRoamingProtocol() { ApnSetting apn1 = new ApnSetting.Builder() .setId(1234) @@ -485,7 +274,6 @@ public class ApnSettingTest extends TelephonyTest { } @Test - @SmallTest public void testCanHandleNetwork() { ApnSetting apn1 = new ApnSetting.Builder() .setId(1234) diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java index 46d1f0a6fe..92cf861b33 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java @@ -16,12 +16,6 @@ package com.android.internal.telephony.data; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; - import android.net.InetAddresses; import android.net.LinkAddress; import android.os.Parcel; @@ -37,15 +31,20 @@ import java.util.ArrayList; import java.util.Arrays; public class DataCallResponseTest extends AndroidTestCase { - public static final String FAKE_DNN = "FAKE_DNN"; + private static final String FAKE_ADDRESS = "99.88.77.66"; + private static final String FAKE_DNS = "55.66.77.88"; + private static final String FAKE_DNN = "FAKE_DNN"; + private static final String FAKE_GATEWAY = "11.22.33.44"; + private static final String FAKE_IFNAME = "FAKE IFNAME"; + private static final String FAKE_PCSCF_ADDRESS = "22.33.44.55"; // 97a498e3fc925c9489860333d06e4e470a454e5445525052495345. // [OsAppId.ANDROID_OS_ID, "ENTERPRISE", 1] - public static final byte[] FAKE_OS_APP_ID = {-105, -92, -104, -29, -4, -110, 92, + private static final byte[] FAKE_OS_APP_ID = {-105, -92, -104, -29, -4, -110, 92, -108, -119, -122, 3, 51, -48, 110, 78, 71, 10, 69, 78, 84, 69, 82, 80, 82, 73, 83, 69}; // 97a498e3fc925c9489860333d06e4e470a454e544552505249534532. // [OsAppId.ANDROID_OS_ID, "ENTERPRISE", 2] - public static final byte[] FAKE_OS_APP_ID_2 = {-105, -92, -104, -29, -4, -110, 92, + private static final byte[] FAKE_OS_APP_ID_2 = {-105, -92, -104, -29, -4, -110, 92, -108, -119, -122, 3, 51, -48, 110, 78, 71, 10, 69, 78, 84, 69, 82, 80, 82, 73, 83, 69, 50}; 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 5c9f4cb446..951a7f38b7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -944,8 +944,6 @@ public class DataNetworkTest extends TelephonyTest { verify(mDataNetworkCallback).onHandoverFailed(eq(mDataNetworkUT), eq(DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE), eq(-1L), eq(DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN)); - verify(mLinkBandwidthEstimator, never()).unregisterForBandwidthChanged( - eq(mDataNetworkUT.getHandler())); assertThat(mDataNetworkUT.getTransport()) .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); assertThat(mDataNetworkUT.getId()).isEqualTo(123); 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 ba001f2bfb..d41be7d7a5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/LinkBandwidthEstimatorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/LinkBandwidthEstimatorTest.java @@ -32,7 +32,6 @@ import static com.android.internal.telephony.data.LinkBandwidthEstimator.UNKNOWN import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; @@ -43,9 +42,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.net.NetworkCapabilities; -import android.os.AsyncResult; import android.os.Handler; -import android.os.Message; import android.telephony.CellIdentityLte; import android.telephony.ModemActivityInfo; import android.telephony.NetworkRegistrationInfo; @@ -63,7 +60,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @RunWith(AndroidTestingRunner.class) @@ -80,7 +76,6 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { new ModemActivityInfo(100L, 0, 0, TX_TIME_2_MS, RX_TIME_2_MS); private static final ModemActivityInfo MAI_RX_TIME_HIGH = new ModemActivityInfo(100L, 0, 0, TX_TIME_1_MS, RX_TIME_2_MS); - private static final int EVENT_BANDWIDTH_ESTIMATOR_UPDATE = 1; private NetworkCapabilities mNetworkCapabilities; private CellIdentityLte mCellIdentity; private long mElapsedTimeMs = 0; @@ -89,14 +84,20 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { private NetworkRegistrationInfo mNri; // Mocked classes - TelephonyFacade mTelephonyFacade; + private TelephonyFacade mTelephonyFacade; private Handler mTestHandler; + private LinkBandwidthEstimatorCallback mLinkBandwidthEstimatorCallback; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mTelephonyFacade = mock(TelephonyFacade.class); mTestHandler = mock(Handler.class); + mLinkBandwidthEstimatorCallback = Mockito.mock(LinkBandwidthEstimatorCallback.class); + doAnswer(invocation -> { + ((Runnable) invocation.getArguments()[0]).run(); + return null; + }).when(mLinkBandwidthEstimatorCallback).invokeFromExecutor(any(Runnable.class)); mNetworkCapabilities = new NetworkCapabilities.Builder() .addTransportType(TRANSPORT_CELLULAR) .build(); @@ -116,10 +117,10 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { when(mSignalStrength.getDbm()).thenReturn(-100); when(mSignalStrength.getLevel()).thenReturn(1); mLBE = new LinkBandwidthEstimator(mPhone, mTelephonyFacade); - mLBE.registerForBandwidthChanged(mTestHandler, EVENT_BANDWIDTH_ESTIMATOR_UPDATE, null); mLBE.obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, mNetworkCapabilities).sendToTarget(); mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, false).sendToTarget(); mLBE.obtainMessage(MSG_ACTIVE_PHONE_CHANGED, 1).sendToTarget(); + mLBE.registerCallback(mLinkBandwidthEstimatorCallback); processAllMessages(); } @@ -184,12 +185,8 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { } private void verifyUpdateBandwidth(int txKbps, int rxKbps) { - ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); - verify(mTestHandler, atLeast(1)) - .sendMessageAtTime(messageArgumentCaptor.capture(), anyLong()); - assertEquals(EVENT_BANDWIDTH_ESTIMATOR_UPDATE, messageArgumentCaptor.getValue().what); - assertEquals(new Pair(txKbps, rxKbps), - ((AsyncResult) messageArgumentCaptor.getValue().obj).result); + verify(mLinkBandwidthEstimatorCallback, atLeast(1)) + .onBandwidthChanged(eq(txKbps), eq(rxKbps)); } @Test 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 d50cb720c4..487f7e33f2 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -79,7 +79,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; import org.junit.After; import org.junit.Before; @@ -104,7 +103,7 @@ public class PhoneSwitcherTest extends TelephonyTest { private Phone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. private Phone mImsPhone; // TODO: Add logic for DataSettingsManager - private DataEnabledSettings mDataEnabledSettings2; + private DataSettingsManager mDataSettingsManager2; private Handler mActivePhoneSwitchHandler; private GsmCdmaCall mActiveCall; private GsmCdmaCall mHoldingCall; @@ -136,7 +135,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mCommandsInterface1 = mock(CommandsInterface.class); mPhone2 = mock(Phone.class); // mPhone as phone 1 is already defined in TelephonyTest. mImsPhone = mock(Phone.class); - mDataEnabledSettings2 = mock(DataEnabledSettings.class); + mDataSettingsManager2 = mock(DataSettingsManager.class); mActivePhoneSwitchHandler = mock(Handler.class); mActiveCall = mock(GsmCdmaCall.class); mHoldingCall = mock(GsmCdmaCall.class); @@ -648,7 +647,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInCall(mImsPhone); @@ -677,7 +676,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInDial(mImsPhone); @@ -705,7 +704,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInIncomingCall(mImsPhone); @@ -732,7 +731,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active call, but data is turned off. So no data switching should happen. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_IWLAN); notifyPhoneAsInCall(mImsPhone); @@ -760,7 +759,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone 1 has active IMS call on CROSS_SIM. And data of DEFAULT apn is enabled. This should // not trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_CROSS_SIM); notifyPhoneAsInCall(mImsPhone); @@ -1193,7 +1192,6 @@ public class PhoneSwitcherTest extends TelephonyTest { verify(mPhone2).registerForEmergencyCallToggle(any(), anyInt(), any()); verify(mPhone2).registerForPreciseCallStateChanged(any(), anyInt(), any()); - verify(mDataEnabledSettings2).registerForDataEnabledChanged(any(), anyInt(), any()); clearInvocations(mMockRadioConfig); setSlotIndexToSubId(1, 2); @@ -1375,8 +1373,8 @@ public class PhoneSwitcherTest extends TelephonyTest { } private void notifyDataEnabled(boolean dataEnabled) { - doReturn(dataEnabled).when(mDataEnabledSettings).isDataEnabled(anyInt()); - doReturn(dataEnabled).when(mDataEnabledSettings2).isDataEnabled(anyInt()); + doReturn(dataEnabled).when(mDataSettingsManager).isDataEnabled(anyInt()); + doReturn(dataEnabled).when(mDataSettingsManager2).isDataEnabled(anyInt()); mPhoneSwitcher.sendEmptyMessage(EVENT_DATA_ENABLED_CHANGED); processAllMessages(); } @@ -1470,7 +1468,7 @@ public class PhoneSwitcherTest extends TelephonyTest { doReturn(0).when(mPhone).getPhoneId(); doReturn(1).when(mPhone2).getPhoneId(); doReturn(true).when(mPhone2).isUserDataEnabled(); - doReturn(mDataEnabledSettings2).when(mPhone2).getDataEnabledSettings(); + doReturn(mDataSettingsManager2).when(mPhone2).getDataSettingsManager(); for (int i = 0; i < supportedModemCount; i++) { mSlotIndexToSubId[i] = new int[1]; mSlotIndexToSubId[i][0] = SubscriptionManager.INVALID_SUBSCRIPTION_ID; diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java index 00bca4d0af..2ab65333ee 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java @@ -27,15 +27,17 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.annotation.NonNull; +import android.net.INetworkAgentRegistry; import android.net.InetAddresses; import android.net.LinkAddress; import android.net.Network; +import android.net.NetworkAgent; +import android.net.QosSession; import android.telephony.data.EpsBearerQosSessionAttributes; import android.telephony.data.EpsQos; import android.telephony.data.Qos; import android.telephony.data.QosBearerFilter; import android.telephony.data.QosBearerSession; -import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -91,6 +93,7 @@ public class QosCallbackTrackerTest extends TelephonyTest { // Mocked classes private Phone mPhone; private TelephonyNetworkAgent mNetworkAgent; + private INetworkAgentRegistry mINetworkAgentRegistry; private Network mNetwork; private RcsStats mRcsStats; @@ -101,6 +104,9 @@ public class QosCallbackTrackerTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mPhone = mock(Phone.class); mNetworkAgent = mock(TelephonyNetworkAgent.class); + mINetworkAgentRegistry = mock(INetworkAgentRegistry.class); + replaceInstance(NetworkAgent.class, "mRegistry", mNetworkAgent, mINetworkAgentRegistry); + replaceInstance(NetworkAgent.class, "mPreConnectedQueue", mNetworkAgent, new ArrayList()); mNetwork = mock(Network.class); mRcsStats = mock(RcsStats.class); doReturn(mNetwork).when(mNetworkAgent).getNetwork(); @@ -153,7 +159,6 @@ public class QosCallbackTrackerTest extends TelephonyTest { } @Test - @SmallTest public void testAddFilterBeforeUpdateSessions() throws Exception { Filter filter = new Filter(new InetSocketAddress( InetAddresses.parseNumericAddress("122.22.22.22"), 2222)); @@ -170,8 +175,8 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), - eq(1234), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); // Matching QosBearerFilter ArrayList qosFilters2 = new ArrayList<>(); @@ -182,14 +187,12 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); - + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testAddFilterAfterUpdateSessions() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -213,13 +216,11 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); - + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testRemoveFilter() throws Exception { // Add filter Filter filter = new Filter(new InetSocketAddress( @@ -237,8 +238,8 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), - eq(1234), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); // Remove the filter mQosCallbackTracker.removeFilter(1); @@ -253,13 +254,11 @@ public class QosCallbackTrackerTest extends TelephonyTest { processAllMessages(); // Verify that notifyQosSessionAvailable is not invoked as the filter is already removed - verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); - + verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testSessionLost() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -287,19 +286,18 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); // Remove the matching QosBearerFilter qosSessions.remove(1); mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1235), eq(1)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); } @Test - @SmallTest public void testModifiedQos() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -326,10 +324,10 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); - reset(mNetworkAgent); + reset(mINetworkAgentRegistry); // Update the QOS qosSessions.remove(1); @@ -337,12 +335,11 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testUnmodifiedQos() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -369,8 +366,8 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); reset(mNetworkAgent); @@ -380,12 +377,11 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testEmptyQosSessions() throws Exception { // Add filter Filter filter = new Filter(new InetSocketAddress( @@ -418,21 +414,21 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(2, filter2); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1234), any(EpsBearerQosSessionAttributes.class)); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(2), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(2), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + // Update empty QOS sessions list mQosCallbackTracker.updateSessions(new ArrayList<>()); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234), eq(1)); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(2), eq(1235), eq(1)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(2), any(QosSession.class)); } @Test - @SmallTest public void testMultipleQosSessions() throws Exception { // Add filter 1 Filter filter1 = new Filter(new InetSocketAddress( @@ -465,21 +461,20 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1234), any(EpsBearerQosSessionAttributes.class)); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(2), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(2), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); // Update empty QOS sessions list mQosCallbackTracker.updateSessions(new ArrayList<>()); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234), eq(1)); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(2), eq(1235), eq(1)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(2), any(QosSession.class)); } @Test - @SmallTest public void testQosSessionWithInvalidPortRange() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -503,14 +498,12 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); - + verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest - public void testQosMetrics() throws Exception { + public void testQosMetrics() { final int callbackId = 1; final int slotId = mPhone.getPhoneId(); // Add filter before update session diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java index d109ee929e..7d323aa4b4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java @@ -22,24 +22,18 @@ import static com.android.internal.telephony.NetworkFactory.CMD_REQUEST_NETWORK; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.net.NetworkCapabilities; import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; -import android.os.AsyncResult; -import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.telephony.AccessNetworkConstants; -import android.telephony.data.ApnSetting; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -49,9 +43,6 @@ import androidx.test.filters.FlakyTest; import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.dataconnection.DataConnection; -import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams; -import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams.HandoverCallback; import com.android.telephony.Rlog; import org.junit.After; @@ -59,9 +50,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -74,13 +63,12 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { // Mocked classes PhoneSwitcher mPhoneSwitcher; private RadioConfig mMockRadioConfig; - private DataConnection mDataConnection; private String mTestName = ""; // List of all requests filed by a test private final ArraySet mAllNetworkRequestSet = new ArraySet<>(); - // List of requests active in DcTracker + // List of requests active private final ArrayList mNetworkRequestList = new ArrayList<>(); // List of complete messages associated with the network requests private final Map mNetworkRequestMessageMap = new HashMap<>(); @@ -156,7 +144,6 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mPhoneSwitcher = mock(PhoneSwitcher.class); mMockRadioConfig = mock(RadioConfig.class); - mDataConnection = mock(DataConnection.class); replaceInstance(RadioConfig.class, "sRadioConfig", null, mMockRadioConfig); mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes, @@ -230,7 +217,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { } /** - * Test that phone active changes cause the DcTracker to get poked. + * Test that phone active changes */ @FlakyTest @Test @@ -301,7 +288,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { } /** - * Test that network request changes cause the DcTracker to get poked. + * Test that network request changes */ @Test @SmallTest @@ -364,79 +351,4 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { processAllMessages(); assertEquals(3, mNetworkRequestList.size()); } - - /** - * Test handover when there is no live data connection - */ - @Test - @SmallTest - public void testHandoverNoLiveData() throws Exception { - createMockedTelephonyComponents(); - doReturn(0).when(mSubscriptionController).getSubIdUsingPhoneId(0); - mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( - TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); - - activatePhoneInPhoneSwitcher(0, true); - makeDefaultInternetRequest(); - - makeSubSpecificMmsRequest(0); - processAllMessages(); - - Field f = TelephonyNetworkFactory.class.getDeclaredField("mInternalHandler"); - f.setAccessible(true); - Handler h = (Handler) f.get(mTelephonyNetworkFactoryUT); - - HandoverCallback handoverCallback = mock(HandoverCallback.class); - - HandoverParams hp = new HandoverParams(ApnSetting.TYPE_MMS, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN, handoverCallback); - AsyncResult ar = new AsyncResult(null, hp, null); - h.sendMessage(h.obtainMessage(5, ar)); - processAllMessages(); - - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) - .getCurrentTransport(anyInt()); - - hp = new HandoverParams(ApnSetting.TYPE_MMS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - handoverCallback); - ar = new AsyncResult(null, hp, null); - h.sendMessage(h.obtainMessage(5, ar)); - processAllMessages(); - } - - /** - * Test handover when the data connection is being connected. - */ - @Test - @SmallTest - public void testHandoverActivatingData() throws Exception { - createMockedTelephonyComponents(); - doReturn(0).when(mSubscriptionController).getSubIdUsingPhoneId(0); - mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( - TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); - - activatePhoneInPhoneSwitcher(0, true); - makeDefaultInternetRequest(); - - makeSubSpecificMmsRequest(0); - processAllMessages(); - - Field f = TelephonyNetworkFactory.class.getDeclaredField("mInternalHandler"); - f.setAccessible(true); - Handler h = (Handler) f.get(mTelephonyNetworkFactoryUT); - - HandoverCallback handoverCallback = mock(HandoverCallback.class); - Mockito.reset(mDataNetworkController); - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByApnType(anyString()); - doReturn(false).when(mDataConnection).isActive(); - - HandoverParams hp = new HandoverParams(ApnSetting.TYPE_MMS, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN, handoverCallback); - AsyncResult ar = new AsyncResult(null, hp, null); - h.sendMessage(h.obtainMessage(5, ar)); - processAllMessages(); - - verify(mDataNetworkController, times(1)).removeNetworkRequest(any()); - verify(mDataNetworkController, times(1)).addNetworkRequest(any()); - } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java deleted file mode 100644 index f2d694fb6b..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2020 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.dataconnection; - -import static junit.framework.Assert.assertEquals; - -import android.os.PersistableBundle; -import android.telephony.CarrierConfigManager; -import android.telephony.data.ApnSetting; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -public class ApnConfigTypeRepositoryTest { - - PersistableBundle mCarrierConfig; - - @Before - public void setUp() throws Exception { - mCarrierConfig = new PersistableBundle(); - } - - @After - public void tearDown() { - mCarrierConfig = null; - } - - @Test - public void testReturnsDefaultsWhenCarrierConfigNull() { - ApnConfigTypeRepository repository = new ApnConfigTypeRepository(null); - checkDefaults(repository); - } - - @Test - public void testReturnsDefaultsWhenCarrierConfigApnContextKeyReturnsNull() { - mCarrierConfig.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, - null); - - ApnConfigTypeRepository repository = new ApnConfigTypeRepository(mCarrierConfig); - checkDefaults(repository); - } - - @Test - public void testReturnsDefaultsWhenCarrierConfigHasInvalidTypes() { - - List apnConfigStringArray = new ArrayList<>(); - apnConfigStringArray.add("xcap,cbs:3"); - apnConfigStringArray.add("default:0a"); - - mCarrierConfig.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, - apnConfigStringArray.toArray(new String[0])); - - ApnConfigTypeRepository repository = new ApnConfigTypeRepository(mCarrierConfig); - checkDefaults(repository); - } - - @Test - public void testReturnsCarrierConfigOverride() { - List apnConfigStringArray = new ArrayList<>(); - //Shouldn't match or override any keys - apnConfigStringArray.add("xcap,cbs:3"); - - //Priorities must be integers - apnConfigStringArray.add("default:10a"); - - //Key isn't case sensitive, which means that this priority should be taken - apnConfigStringArray.add("fotA:10"); - - mCarrierConfig.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, - apnConfigStringArray.toArray(new String[0])); - - ApnConfigTypeRepository repository = new ApnConfigTypeRepository(mCarrierConfig); - assertEquals(10, repository.getByType(ApnSetting.TYPE_FOTA).getPriority()); - checkDefaults(repository); - } - - private void checkDefaults(ApnConfigTypeRepository repository) { - assertEquals(0, repository.getByType(ApnSetting.TYPE_ENTERPRISE).getPriority()); - assertEquals(1, repository.getByType(ApnSetting.TYPE_DEFAULT).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_MMS).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_SUPL).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_DUN).getPriority()); - assertEquals(3, repository.getByType(ApnSetting.TYPE_HIPRI).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_IMS).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_CBS).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_IA).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_EMERGENCY).getPriority()); - assertEquals(3, repository.getByType(ApnSetting.TYPE_MCX).getPriority()); - assertEquals(3, repository.getByType(ApnSetting.TYPE_XCAP).getPriority()); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java deleted file mode 100644 index b27054875a..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2010 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.dataconnection; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; - -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.telephony.data.ApnSetting; -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.internal.R; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class ApnContextTest extends TelephonyTest { - // Mocked classes - ApnSetting mApnSetting; - - private ApnContext mApnContext; - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - mApnSetting = mock(ApnSetting.class); - mApnContext = new ApnContext(mPhone, ApnSetting.TYPE_DEFAULT, TAG, mDcTracker, 1); - } - - @After - public void tearDown() throws Exception { - mApnContext = null; - super.tearDown(); - } - - @Test - @SmallTest - public void testSetGetApnSetting() throws Exception { - mApnContext.setApnSetting(mApnSetting); - assertEquals(mApnSetting, mApnContext.getApnSetting()); - } - - @Test - @SmallTest - public void testGetApnType() { - assertEquals(ApnSetting.TYPE_DEFAULT_STRING, mApnContext.getApnType()); - } - - @Test - @SmallTest - public void testConnectionGeneration() throws Exception { - for (int i = 0; i < 100; i++) { - mApnContext.incAndGetConnectionGeneration(); - assertEquals(i + 1, mApnContext.getConnectionGeneration()); - } - } - - @Test - @SmallTest - public void testReason() throws Exception { - mApnContext.setReason("dataEnabled"); - assertEquals("dataEnabled", mApnContext.getReason()); - mApnContext.setReason("simLoaded"); - assertEquals("simLoaded", mApnContext.getReason()); - } - - @Test - @SmallTest - public void testState() throws Exception { - mApnContext.setState(DctConstants.State.DISCONNECTING); - assertEquals(DctConstants.State.DISCONNECTING, mApnContext.getState()); - mApnContext.setEnabled(true); - assertFalse(mApnContext.isConnectable()); - - mApnContext.setState(DctConstants.State.RETRYING); - assertTrue(mApnContext.isConnectable()); - assertTrue(mApnContext.isConnectedOrConnecting()); - - mApnContext.setState(DctConstants.State.FAILED); - assertTrue(mApnContext.isDisconnected()); - mApnContext.setState(DctConstants.State.IDLE); - assertTrue(mApnContext.isDisconnected()); - } - - @Test - @SmallTest - public void testNetworkRequestNormal() throws Exception { - NetworkRequest nr1 = new NetworkRequest.Builder().build(); - mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, null); - - verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); - - NetworkRequest nr2 = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .build(); - - mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, null); - verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); - - mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_NORMAL); - verify(mDcTracker, never()).disableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.RELEASE_TYPE_NORMAL)); - - mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL); - verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.RELEASE_TYPE_NORMAL)); - } - - @Test - @SmallTest - public void testNetworkRequestDetach() throws Exception { - NetworkRequest nr1 = new NetworkRequest.Builder().build(); - mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, null); - verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); - - NetworkRequest nr2 = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .build(); - - mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, null); - verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); - - mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_DETACH); - verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.RELEASE_TYPE_DETACH)); - - mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL); - verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.RELEASE_TYPE_NORMAL)); - } - - @Test - @SmallTest - public void testNetworkRequestHandover() throws Exception { - NetworkRequest nr1 = new NetworkRequest.Builder().build(); - mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_HANDOVER, null); - verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.REQUEST_TYPE_HANDOVER), eq(null)); - - mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_HANDOVER); - verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.RELEASE_TYPE_HANDOVER)); - } - - @Test - @SmallTest - public void testConcurrentVoiceAndDataAllowed() throws Exception { - mApnContext.setConcurrentVoiceAndDataAllowed(true); - assertTrue(mApnContext.isConcurrentVoiceAndDataAllowed()); - mApnContext.setConcurrentVoiceAndDataAllowed(false); - assertFalse(mApnContext.isConcurrentVoiceAndDataAllowed()); - } - - @Test - @SmallTest - public void testEnableDisable() throws Exception { - mApnContext.setEnabled(true); - assertTrue(mApnContext.isEnabled()); - mApnContext.setEnabled(false); - assertFalse(mApnContext.isEnabled()); - } - - @Test - @SmallTest - public void testProvisionApn() throws Exception { - mContextFixture.putResource(R.string.mobile_provisioning_apn, "fake_apn"); - - ApnSetting myApn = new ApnSetting.Builder() - .setId(2163) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("fake_apn") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - mApnContext.setApnSetting(myApn); - assertTrue(mApnContext.isProvisioningApn()); - mApnContext.setApnSetting(mApnSetting); - assertFalse(mApnContext.isProvisioningApn()); - } - - @Test - @SmallTest - public void testIsReady() throws Exception { - mApnContext.setEnabled(true); - assertTrue(mApnContext.isReady()); - - mApnContext.setEnabled(false); - assertFalse(mApnContext.isReady()); - } - - @Test - @SmallTest - public void testErrorCodeRetry() throws Exception { - mContextFixture.putStringArrayResource( - com.android.internal.R.array.config_cell_retries_per_error_code, - new String[]{"36,2"}); - mApnContext.resetErrorCodeRetries(); - - assertFalse(mApnContext.restartOnError(36)); - assertTrue(mApnContext.restartOnError(36)); - assertFalse(mApnContext.restartOnError(37)); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java deleted file mode 100644 index dcaa2a0269..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java +++ /dev/null @@ -1,1479 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; - -import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Matchers.argThat; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.UserInfo; -import android.net.InetAddresses; -import android.net.KeepalivePacketData; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.NattKeepalivePacketData; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.vcn.VcnNetworkPolicyResult; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Message; -import android.os.UserManager; -import android.provider.Telephony; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.AccessNetworkType; -import android.telephony.CarrierConfigManager; -import android.telephony.ServiceState; -import android.telephony.ServiceState.RegState; -import android.telephony.ServiceState.RilRadioTechnology; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.telephony.data.DataProfile; -import android.telephony.data.DataService; -import android.telephony.data.DataServiceCallback; -import android.telephony.data.TrafficDescriptor; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.Pair; - -import com.android.internal.R; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.data.KeepaliveStatus; -import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams; -import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams; -import com.android.internal.telephony.dataconnection.DataConnection.SetupResult; -import com.android.internal.telephony.metrics.DataCallSessionStats; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.function.Consumer; - -public class DataConnectionTest extends TelephonyTest { - private static final int DEFAULT_DC_CID = 10; - private static final ArrayList DEFAULT_TD_LIST = new ArrayList<>(); - - // Mocked classes - DcTesterFailBringUpAll mDcTesterFailBringUpAll; - ConnectionParams mCp; - DisconnectParams mDcp; - ApnContext mApnContext; - ApnContext mEnterpriseApnContext; - DcFailBringUp mDcFailBringUp; - DataCallSessionStats mDataCallSessionStats; - DataConnection mDefaultDc; - DataServiceManager mDataServiceManager; - - private DataConnection mDc; - private DataConnectionTestHandler mDataConnectionTestHandler; - private DcController mDcc; - - private final ApnSetting mApn1 = new ApnSetting.Builder() - .setId(2163) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private final ApnSetting mApn2 = new ApnSetting.Builder() - .setId(2164) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private final ApnSetting mApn3 = new ApnSetting.Builder() - .setId(2165) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setNetworkTypeBitmask(0) - .setCarrierEnabled(true) - .setCarrierId(1) - .setSkip464Xlat(1) - .build(); - - private final ApnSetting mApn4 = new ApnSetting.Builder() - .setId(2166) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_IMS) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private final ApnSetting mApn5 = new ApnSetting.Builder() - .setId(2167) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_IMS) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .setSkip464Xlat(Telephony.Carriers.SKIP_464XLAT_DISABLE) - .build(); - - private final ApnSetting mApn6 = new ApnSetting.Builder() - .setId(2168) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_EMERGENCY) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private class DataConnectionTestHandler extends HandlerThread { - - private DataConnectionTestHandler(String name) { - super(name); - } - - @Override - public void onLooperPrepared() { - Handler h = new Handler(); - mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, h.getLooper(), ""); - mDc = DataConnection.makeDataConnection(mPhone, 0, mDcTracker, mDataServiceManager, - mDcTesterFailBringUpAll, mDcc); - } - } - - private void setSuccessfulSetupDataResponse(int cid, ArrayList tds) { - doAnswer(invocation -> { - final Message msg = (Message) invocation.getArguments()[10]; - - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1L) - .setId(cid) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) - .setInterfaceName("ifname") - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress("10.0.2.15"), 32), - new LinkAddress("2607:fb90:a620:651d:eabe:f8da:c107:44be/64"))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), - InetAddresses.parseNumericAddress("fd00:976a::9"))) - .setGatewayAddresses(Arrays.asList( - InetAddresses.parseNumericAddress("10.0.2.15"), - InetAddresses.parseNumericAddress("fe80::2"))) - .setPcscfAddresses(Arrays.asList( - InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), - InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), - InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) - .setMtu(1500) - .setMtuV4(1500) - .setMtuV6(1500) - .setPduSessionId(1) - .setQosBearerSessions(new ArrayList<>()) - .setTrafficDescriptors(tds) - .build(); - msg.getData().putParcelable("data_call_response", response); - msg.arg1 = DataServiceCallback.RESULT_SUCCESS; - msg.sendToTarget(); - return null; - }).when(mDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), - anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), - any(Message.class)); - } - - private void setFailedSetupDataResponse(@DataServiceCallback.ResultCode int resultCode) { - doAnswer(invocation -> { - final Message msg = (Message) invocation.getArguments()[10]; - msg.arg1 = resultCode; - msg.sendToTarget(); - return null; - }).when(mDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), - anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), - any(Message.class)); - } - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - mDcTesterFailBringUpAll = mock(DcTesterFailBringUpAll.class); - mCp = mock(ConnectionParams.class); - mDcp = mock(DisconnectParams.class); - mApnContext = mock(ApnContext.class); - mEnterpriseApnContext = mock(ApnContext.class); - mDcFailBringUp = mock(DcFailBringUp.class); - mDataCallSessionStats = mock(DataCallSessionStats.class); - mDefaultDc = mock(DataConnection.class); - mDataServiceManager = mock(DataServiceManager.class); - logd("+Setup!"); - doReturn("fake.action_detached").when(mPhone).getActionDetached(); - doReturn(false).when(mPhone).isUsingNewDataStack(); - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext); - replaceInstance(ConnectionParams.class, "mRilRat", mCp, - ServiceState.RIL_RADIO_TECHNOLOGY_UMTS); - doReturn(mApn1).when(mApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_DEFAULT_STRING).when(mApnContext).getApnType(); - doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); - - mDcFailBringUp.saveParameters(0, 0, -2); - doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp(); - - mContextFixture.putStringArrayResource(com.android.internal.R.array - .config_mobile_tcp_buffers, new String[]{ - "umts:131072,262144,1452032,4096,16384,399360", - "hspa:131072,262144,2441216,4096,16384,399360", - "hsupa:131072,262144,2441216,4096,16384,399360", - "hsdpa:131072,262144,2441216,4096,16384,399360", - "hspap:131072,262144,2441216,4096,16384,399360", - "edge:16384,32768,131072,4096,16384,65536", - "gprs:4096,8192,24576,4096,8192,24576", - "1xrtt:16384,32768,131070,4096,16384,102400", - "evdo:131072,262144,1048576,4096,16384,524288", - "lte:524288,1048576,8388608,262144,524288,4194304"}); - - mContextFixture.putResource(R.string.config_wwan_data_service_package, - "com.android.phone"); - - mDcp.mApnContext = mApnContext; - - setSuccessfulSetupDataResponse(DEFAULT_DC_CID, DEFAULT_TD_LIST); - - doAnswer(invocation -> { - final Message msg = (Message) invocation.getArguments()[2]; - msg.arg1 = DataServiceCallback.RESULT_SUCCESS; - msg.sendToTarget(); - return null; - }).when(mDataServiceManager).deactivateDataCall(anyInt(), anyInt(), any(Message.class)); - - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mDataServiceManager) - .getTransportType(); - - mDataConnectionTestHandler = new DataConnectionTestHandler(getClass().getSimpleName()); - mDataConnectionTestHandler.start(); - - waitForMs(200); - mDc.setDataCallSessionStats(mDataCallSessionStats); - - logd("-Setup!"); - } - - @After - public void tearDown() throws Exception { - logd("tearDown"); - mDc.quitNow(); - mDc = null; - mDataConnectionTestHandler.quit(); - mDataConnectionTestHandler.join(); - mDataConnectionTestHandler = null; - mDcc.removeCallbacksAndMessages(null); - mDcc = null; - DEFAULT_TD_LIST.clear(); - waitForMs(100); - super.tearDown(); - } - - private long getSuggestedRetryDelay(DataCallResponse response) throws Exception { - Class[] cArgs = new Class[1]; - cArgs[0] = DataCallResponse.class; - Method method = DataConnection.class.getDeclaredMethod("getSuggestedRetryDelay", cArgs); - method.setAccessible(true); - return (long) method.invoke(mDc, response); - } - - private boolean isUnmeteredUseOnly() throws Exception { - Method method = DataConnection.class.getDeclaredMethod("isUnmeteredUseOnly"); - method.setAccessible(true); - return (boolean) method.invoke(mDc); - } - - private boolean isEnterpriseUse() throws Exception { - Method method = DataConnection.class.getDeclaredMethod("isEnterpriseUse"); - method.setAccessible(true); - return (boolean) method.invoke(mDc); - } - - private boolean isSuspended() throws Exception { - Field field = DataConnection.class.getDeclaredField("mIsSuspended"); - field.setAccessible(true); - return field.getBoolean(mDc); - } - - private SetupResult setLinkProperties(DataCallResponse response, LinkProperties linkProperties) - throws Exception { - Class[] cArgs = new Class[2]; - cArgs[0] = DataCallResponse.class; - cArgs[1] = LinkProperties.class; - Method method = DataConnection.class.getDeclaredMethod("setLinkProperties", cArgs); - method.setAccessible(true); - return (SetupResult) method.invoke(mDc, response, linkProperties); - } - - @Test - @SmallTest - public void testConnectEvent() { - assertTrue(mDc.isInactive()); - connectEvent(true); - - verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class), - eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null)); - verify(mCT, times(1)).registerForVoiceCallEnded(any(Handler.class), - eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED), eq(null)); - verify(mSimulatedCommandsVerifier, times(1)) - .registerForNattKeepaliveStatus(any(Handler.class), - eq(DataConnection.EVENT_KEEPALIVE_STATUS), eq(null)); - verify(mSimulatedCommandsVerifier, times(1)) - .registerForLceInfo(any(Handler.class), - eq(DataConnection.EVENT_LINK_CAPACITY_CHANGED), eq(null)); - verify(mVcnManager, atLeastOnce()) - .applyVcnNetworkPolicy( - argThat(caps -> - caps.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)), - any()); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mDataServiceManager, times(1)).setupDataCall( - eq(AccessNetworkType.UTRAN), dpCaptor.capture(), eq(false), - eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), tdCaptor.capture(), anyBoolean(), any(Message.class)); - - verify(mSimulatedCommandsVerifier, times(0)) - .allocatePduSessionId(any()); - - assertEquals("spmode.ne.jp", dpCaptor.getValue().getApn()); - if (tdCaptor.getValue() != null) { - if (mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - } else { - assertEquals("spmode.ne.jp", tdCaptor.getValue().getDataNetworkName()); - assertEquals(null, tdCaptor.getValue().getOsAppId()); - } - } - assertTrue(mDc.isActive()); - - assertEquals(1, mDc.getPduSessionId()); - assertEquals(3, mDc.getPcscfAddresses().length); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::8"::equals)); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c202:1d::7"::equals)); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::5"::equals)); - } - - @Test - @SmallTest - public void testConnectOnIwlan() throws Exception { - assertTrue(mDc.isInactive()); - Field field = DataConnection.class.getDeclaredField("mTransportType"); - field.setAccessible(true); - field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - connectEvent(true); - - verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class), - eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null)); - verify(mCT, times(1)).registerForVoiceCallEnded(any(Handler.class), - eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED), eq(null)); - verify(mSimulatedCommandsVerifier, times(0)) - .registerForNattKeepaliveStatus(any(Handler.class), - eq(DataConnection.EVENT_KEEPALIVE_STATUS), eq(null)); - verify(mSimulatedCommandsVerifier, times(0)) - .registerForLceInfo(any(Handler.class), - eq(DataConnection.EVENT_LINK_CAPACITY_CHANGED), eq(null)); - verify(mVcnManager, atLeastOnce()) - .applyVcnNetworkPolicy( - argThat(caps -> - caps.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)), - any()); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mDataServiceManager, times(1)).setupDataCall( - eq(AccessNetworkType.UTRAN), dpCaptor.capture(), eq(false), - eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), tdCaptor.capture(), anyBoolean(), any(Message.class)); - - verify(mSimulatedCommandsVerifier, times(1)) - .allocatePduSessionId(any()); - - assertEquals("spmode.ne.jp", dpCaptor.getValue().getApn()); - if (tdCaptor.getValue() != null) { - if (mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - } else { - assertEquals("spmode.ne.jp", tdCaptor.getValue().getDataNetworkName()); - assertEquals(null, tdCaptor.getValue().getOsAppId()); - } - } - assertTrue(mDc.isActive()); - - assertEquals(1, mDc.getPduSessionId()); - assertEquals(3, mDc.getPcscfAddresses().length); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::8"::equals)); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c202:1d::7"::equals)); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::5"::equals)); - } - - @Test - public void testConnectEventDuplicateContextIds() throws Exception { - setUpDefaultData(DEFAULT_DC_CID); - - // Try to connect ENTERPRISE with the same CID as default - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); - doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); - - // Verify that ENTERPRISE wasn't set up - connectEvent(false); - assertTrue(mDc.isInactive()); - - // Change the CID - setSuccessfulSetupDataResponse(DEFAULT_DC_CID + 1, DEFAULT_TD_LIST); - - // Verify that ENTERPRISE was set up - connectEvent(true); - assertTrue(mDc.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - } - - @Test - public void testConnectEventDuplicateContextIdsDifferentTDs() throws Exception { - setUpDefaultData(DEFAULT_DC_CID); - - // Try to connect ENTERPRISE with the same CID as default but different TrafficDescriptors - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); - doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); - ArrayList tdList = new ArrayList<>(); - tdList.add(new TrafficDescriptor("dnn", DataConnection.getEnterpriseOsAppId())); - setSuccessfulSetupDataResponse(DEFAULT_DC_CID, tdList); - - // Verify that ENTERPRISE wasn't set up but the TD list was updated - connectEvent(false); - assertTrue(mDc.isInactive()); - ArgumentCaptor captor = ArgumentCaptor.forClass(DataCallResponse.class); - verify(mDefaultDc).updateTrafficDescriptors(captor.capture()); - assertEquals(tdList, captor.getValue().getTrafficDescriptors()); - } - - @Test - public void testConnectEventNoDefaultData() throws Exception { - assertFalse(mDefaultDc.isActive()); - - // Try to connect ENTERPRISE when default data doesn't exist - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); - doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); - - // Verify that ENTERPRISE wasn't set up - connectEvent(false); - assertTrue(mDc.isInactive()); - - // Set up default data - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext); - setUpDefaultData(1); - - // Verify that ENTERPRISE was set up - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - connectEvent(true); - assertTrue(mDc.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - } - - private void setUpDefaultData(int cid) throws Exception { - replaceInstance(DataConnection.class, "mCid", mDefaultDc, cid); - doReturn(true).when(mDefaultDc).isActive(); - doReturn(Arrays.asList(mApnContext)).when(mDefaultDc).getApnContexts(); - mDcc.addActiveDcByCid(mDefaultDc); - assertTrue(mDefaultDc.getApnContexts().stream() - .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT)); - } - - @Test - @SmallTest - public void testDisconnectEvent() { - testConnectEvent(); - - mDc.setPduSessionId(5); - disconnectEvent(); - - verify(mSimulatedCommandsVerifier, times(1)).unregisterForLceInfo(any(Handler.class)); - verify(mSimulatedCommandsVerifier, times(1)) - .unregisterForNattKeepaliveStatus(any(Handler.class)); - verify(mDataServiceManager, times(1)).deactivateDataCall(eq(DEFAULT_DC_CID), - eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); - verify(mSimulatedCommandsVerifier, times(0)) - .releasePduSessionId(any(), eq(5)); - - assertTrue(mDc.isInactive()); - } - - @Test - @SmallTest - public void testDisconnectOnIwlan() throws Exception { - testConnectEvent(); - - Field field = DataConnection.class.getDeclaredField("mTransportType"); - field.setAccessible(true); - field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - mDc.setPduSessionId(5); - disconnectEvent(); - - verify(mSimulatedCommandsVerifier, times(0)).unregisterForLceInfo(any(Handler.class)); - verify(mSimulatedCommandsVerifier, times(0)) - .unregisterForNattKeepaliveStatus(any(Handler.class)); - verify(mDataServiceManager, times(1)).deactivateDataCall(eq(DEFAULT_DC_CID), - eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); - verify(mSimulatedCommandsVerifier, times(1)) - .releasePduSessionId(any(), eq(5)); - - assertTrue(mDc.isInactive()); - } - - @Test - @SmallTest - public void testModemSuggestRetry() throws Exception { - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(0) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response)); - - response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(1000) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response)); - - response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(9999) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response)); - } - - @Test - @SmallTest - public void testModemNotSuggestRetry() throws Exception { - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response)); - - response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-5) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response)); - - response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(Long.MIN_VALUE) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response)); - } - - @Test - @SmallTest - public void testModemSuggestNoRetry() throws Exception { - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(Long.MAX_VALUE) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(RetryManager.NO_RETRY, getSuggestedRetryDelay(response)); - } - - private NetworkCapabilities getNetworkCapabilities() throws Exception { - Method method = DataConnection.class.getDeclaredMethod("getNetworkCapabilities"); - method.setAccessible(true); - return (NetworkCapabilities) method.invoke(mDc); - } - - private int getDisallowedApnTypes() throws Exception { - Method method = DataConnection.class.getDeclaredMethod("getDisallowedApnTypes"); - method.setAccessible(true); - return (int) method.invoke(mDc); - } - - @Test - @SmallTest - public void testNetworkCapability() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - doReturn(mApn2).when(mApnContext).getApnSetting(); - testConnectEvent(); - - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY, - new String[] {"supl"}); - - disconnectEvent(); - doReturn(mApn1).when(mApnContext).getApnSetting(); - connectEvent(true); - - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - } - - @Test - @SmallTest - public void testVcnNetworkCapability() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - doReturn(mApn2).when(mApnContext).getApnSetting(); - - doAnswer(invocation -> { - NetworkCapabilities nc = invocation.getArgument(0); - NetworkCapabilities policyNc = new NetworkCapabilities.Builder(nc) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .build(); - - return new VcnNetworkPolicyResult( - false /* isTearDownRequested */, policyNc); - }).when(mVcnManager).applyVcnNetworkPolicy(any(), any()); - connectEvent(true); - - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)); - - disconnectEvent(); - - doAnswer(invocation -> { - NetworkCapabilities nc = invocation.getArgument(0); - NetworkCapabilities policyNc = new NetworkCapabilities.Builder(nc) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .build(); - - return new VcnNetworkPolicyResult( - false /* isTearDownRequested */, policyNc); - }).when(mVcnManager).applyVcnNetworkPolicy(any(), any()); - connectEvent(true); - - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)); - } - - @Test - @SmallTest - public void testEnterpriseNetworkCapability() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - doReturn(mApn2).when(mApnContext).getApnSetting(); - testConnectEvent(); - - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - - disconnectEvent(); - setUpDefaultData(1); - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); - doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); - connectEvent(true); - - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - } - - @Test - @SmallTest - public void testMeteredCapability() throws Exception { - - mContextFixture.getCarrierConfigBundle(). - putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] {"default"}); - - testConnectEvent(); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - } - - @Test - @SmallTest - public void testNonMeteredCapability() throws Exception { - - doReturn(2819).when(mPhone).getSubId(); - mContextFixture.getCarrierConfigBundle(). - putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] {"mms"}); - - testConnectEvent(); - - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - } - - @Test - public void testOverrideUnmetered() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - testConnectEvent(); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - - mDc.onMeterednessChanged(true); - waitForMs(100); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - - mDc.onMeterednessChanged(false); - waitForMs(100); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - } - - @Test - public void testOverrideCongested() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - testConnectEvent(); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - - mDc.onCongestednessChanged(true); - waitForMs(100); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - - mDc.onCongestednessChanged(false); - waitForMs(100); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - } - - @Test - public void testOwnerUid() throws Exception { - Context mockContext = mContextFixture.getTestDouble(); - doReturn(mockContext).when(mPhone).getContext(); - - String testPkg = "com.android.telephony.test"; - TelephonyManager telMgr = mockContext.getSystemService(TelephonyManager.class); - doReturn(testPkg).when(telMgr).getCarrierServicePackageNameForLogicalSlot(anyInt()); - - UserInfo info = new UserInfo(0 /* id */, "TEST_USER", 0 /* flags */); - UserManager userMgr = mockContext.getSystemService(UserManager.class); - doReturn(Collections.singletonList(info)).when(userMgr).getUsers(); - - int carrierConfigPkgUid = 12345; - PackageManager pkgMgr = mockContext.getPackageManager(); - doReturn(carrierConfigPkgUid).when(pkgMgr).getPackageUidAsUser(eq(testPkg), anyInt()); - - mContextFixture - .getCarrierConfigBundle() - .putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] {"default"}); - testConnectEvent(); - AsyncResult adminUidsResult = new AsyncResult(null, new int[] {carrierConfigPkgUid}, null); - mDc.sendMessage(DataConnection.EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED, adminUidsResult); - // Wait for carirer privilege UIDs to be updated - waitForMs(100); - - assertEquals(carrierConfigPkgUid, getNetworkCapabilities().getOwnerUid()); - assertEquals( - Collections.singleton(carrierConfigPkgUid), - getNetworkCapabilities().getAllowedUids()); - } - - @Test - public void testSubscriptionIds() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - testConnectEvent(); - - assertEquals(Collections.singleton(0), getNetworkCapabilities().getSubscriptionIds()); - } - - @Test - public void testShouldSkip464Xlat() throws Exception { - assertFalse(testShouldSkip464XlatEvent(mApn1)); - disconnectEvent(); - - assertTrue(testShouldSkip464XlatEvent(mApn3)); - disconnectEvent(); - - assertTrue(testShouldSkip464XlatEvent(mApn4)); - disconnectEvent(); - - assertFalse(testShouldSkip464XlatEvent(mApn5)); - disconnectEvent(); - } - - private boolean testShouldSkip464XlatEvent(ApnSetting apn) throws Exception { - Method method = DataConnection.class.getDeclaredMethod("shouldSkip464Xlat"); - method.setAccessible(true); - - doReturn(apn).when(mApnContext).getApnSetting(); - doReturn(apn.getApnTypeBitmask()).when(mApnContext).getApnTypeBitmask(); - connectEvent(true); - logd(getNetworkCapabilities().toString()); - - return (Boolean) method.invoke(mDc); - } - - private void connectEvent(boolean validate) { - mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp); - waitForMs(200); - if (validate) { - assertTrue(mDc.isActive()); - } - } - - private void disconnectEvent() { - mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp); - waitForMs(100); - assertTrue(mDc.isInactive()); - } - - private void serviceStateChangedEvent(@RegState int dataRegState, @RilRadioTechnology int rat) { - mDc.obtainMessage(DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, - new AsyncResult(null, new Pair<>(dataRegState, rat), null)).sendToTarget(); - waitForMs(100); - } - - @Test - @SmallTest - public void testIsIpAddress() { - // IPv4 - assertTrue(DataConnection.isIpAddress("1.2.3.4")); - assertTrue(DataConnection.isIpAddress("127.0.0.1")); - - // IPv6 - assertTrue(DataConnection.isIpAddress("::1")); - assertTrue(DataConnection.isIpAddress("2001:4860:800d::68")); - } - - @Test - @SmallTest - public void testSetLinkProperties() throws Exception { - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - - LinkProperties linkProperties = new LinkProperties(); - assertEquals(SetupResult.SUCCESS, setLinkProperties(response, linkProperties)); - logd(linkProperties.toString()); - assertEquals(response.getInterfaceName(), linkProperties.getInterfaceName()); - assertEquals(response.getAddresses().size(), linkProperties.getAddresses().size()); - for (int i = 0; i < response.getAddresses().size(); ++i) { - assertEquals(response.getAddresses().get(i).getAddress(), - InetAddresses.parseNumericAddress(linkProperties.getLinkAddresses().get(i) - .getAddress().getHostAddress())); - } - - assertEquals(response.getDnsAddresses().size(), linkProperties.getDnsServers().size()); - for (int i = 0; i < response.getDnsAddresses().size(); ++i) { - assertEquals("i = " + i, response.getDnsAddresses().get(i), - InetAddresses.parseNumericAddress( - linkProperties.getDnsServers().get(i).getHostAddress())); - } - - assertEquals(response.getGatewayAddresses().size(), linkProperties.getRoutes().size()); - for (int i = 0; i < response.getGatewayAddresses().size(); ++i) { - assertEquals("i = " + i, response.getGatewayAddresses().get(i), - InetAddresses.parseNumericAddress(linkProperties.getRoutes().get(i) - .getGateway().getHostAddress())); - } - - assertEquals(response.getPcscfAddresses().size(), linkProperties.getPcscfServers().size()); - for (int i = 0; i < response.getPcscfAddresses().size(); ++i) { - assertEquals("i = " + i, response.getPcscfAddresses().get(i), - InetAddresses.parseNumericAddress(linkProperties.getPcscfServers().get(i) - .getHostAddress())); - } - - assertEquals(response.getMtu(), linkProperties.getMtu()); - } - - @Test - @SmallTest - public void testSetLinkPropertiesEmptyAddress() throws Exception { - // 224.224.224.224 is an invalid address. - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - - LinkProperties linkProperties = new LinkProperties(); - assertEquals(SetupResult.ERROR_INVALID_ARG, setLinkProperties(response, linkProperties)); - } - - @Test - @SmallTest - public void testSetLinkPropertiesEmptyDns() throws Exception { - // Empty dns entry. - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - - // Make sure no exception was thrown - LinkProperties linkProperties = new LinkProperties(); - assertEquals(SetupResult.SUCCESS, setLinkProperties(response, linkProperties)); - } - - @Test - @SmallTest - public void testStartKeepaliveWLAN() throws Exception { - testConnectEvent(); - waitForMs(200); - - Field field = DataConnection.class.getDeclaredField("mTransportType"); - field.setAccessible(true); - field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - - final int sessionHandle = 0xF00; - final int slotId = 3; - final int interval = 10; // seconds - // Construct a new KeepalivePacketData request as we would receive from a Network Agent, - // and check that the packet is sent to the RIL. - KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket( - InetAddresses.parseNumericAddress("1.2.3.4"), - 1234, - InetAddresses.parseNumericAddress("8.8.8.8"), - 4500); - mDc.obtainMessage( - DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget(); - waitForMs(100); - // testStartStopNattKeepalive() verifies that this request is passed with WWAN. - // Thus, even though we can't see the response in NetworkAgent, we can verify that the - // CommandsInterface never receives a request and infer that it was dropped due to WLAN. - verify(mSimulatedCommandsVerifier, times(0)) - .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class)); - } - - public void checkStartStopNattKeepalive(boolean useCondensedFlow) throws Exception { - testConnectEvent(); - waitForMs(200); - - final int sessionHandle = 0xF00; - final int slotId = 3; - final int interval = 10; // seconds - // Construct a new KeepalivePacketData request as we would receive from a Network Agent, - // and check that the packet is sent to the RIL. - KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket( - InetAddresses.parseNumericAddress("1.2.3.4"), - 1234, - InetAddresses.parseNumericAddress("8.8.8.8"), - 4500); - mDc.obtainMessage( - DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget(); - waitForMs(100); - verify(mSimulatedCommandsVerifier, times(1)) - .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class)); - - Message kaStarted = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STARTED, slotId, 0); - if (useCondensedFlow) { - // Send a singled condensed response that a keepalive have been requested and the - // activation is completed. This flow should be used if the keepalive offload request - // is handled by a high-priority signalling path. - AsyncResult.forMessage( - kaStarted, new KeepaliveStatus( - sessionHandle, KeepaliveStatus.STATUS_ACTIVE), null); - kaStarted.sendToTarget(); - } else { - // Send the sequential responses indicating first that the request was received and - // then that the keepalive is running. This should create an active record of the - // keepalive in DataConnection while permitting the status from a low priority or other - // high-latency handler to activate the keepalive without blocking a request. - AsyncResult.forMessage( - kaStarted, new KeepaliveStatus( - sessionHandle, KeepaliveStatus.STATUS_PENDING), null); - kaStarted.sendToTarget(); - Message kaRunning = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STATUS); - AsyncResult.forMessage( - kaRunning, new KeepaliveStatus( - sessionHandle, KeepaliveStatus.STATUS_ACTIVE), null); - kaRunning.sendToTarget(); - } - waitForMs(100); - - // Verify that we can stop the connection, which checks that the record in DataConnection - // has a valid mapping between slotId (from network agent) to sessionHandle (from Radio). - mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget(); - waitForMs(100); - verify(mSimulatedCommandsVerifier, times(1)) - .stopNattKeepalive(eq(sessionHandle), any(Message.class)); - - Message kaStopped = mDc.obtainMessage( - DataConnection.EVENT_KEEPALIVE_STOPPED, sessionHandle, slotId); - AsyncResult.forMessage(kaStopped); - kaStopped.sendToTarget(); - // Verify that after the connection is stopped, the mapping for a Keepalive Session is - // removed. Thus, subsequent calls to stop the same keepalive are ignored. - mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget(); - waitForMs(100); - // Check that the mock has not been called subsequent to the previous invocation - // while avoiding the use of reset() - verify(mSimulatedCommandsVerifier, times(1)) - .stopNattKeepalive(anyInt(), any(Message.class)); - } - - @Test - @MediumTest - public void testStartStopNattKeepalive() throws Exception { - checkStartStopNattKeepalive(false); - } - - @Test - @MediumTest - public void testStartStopNattKeepaliveCondensed() throws Exception { - checkStartStopNattKeepalive(true); - } - - public void checkStartNattKeepaliveFail(boolean useCondensedFlow) throws Exception { - testConnectEvent(); - waitForMs(200); - - final int sessionHandle = 0xF00; - final int slotId = 3; - final int interval = 10; // seconds - // Construct a new KeepalivePacketData request as we would receive from a Network Agent, - // and check that the packet is sent to the RIL. - KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket( - InetAddresses.parseNumericAddress("1.2.3.4"), - 1234, - InetAddresses.parseNumericAddress("8.8.8.8"), - 4500); - mDc.obtainMessage( - DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget(); - waitForMs(100); - verify(mSimulatedCommandsVerifier, times(1)) - .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class)); - - Message kaStarted = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STARTED, slotId, 0); - if (useCondensedFlow) { - // Indicate in the response that the keepalive has failed. - AsyncResult.forMessage( - kaStarted, new KeepaliveStatus(KeepaliveStatus.ERROR_UNSUPPORTED), - null); - kaStarted.sendToTarget(); - } else { - // Indicate that the keepalive is queued, and then signal a failure from the modem - // such that a pending keepalive fails to activate. - AsyncResult.forMessage( - kaStarted, new KeepaliveStatus( - sessionHandle, KeepaliveStatus.STATUS_PENDING), null); - kaStarted.sendToTarget(); - Message kaRunning = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STATUS); - AsyncResult.forMessage( - kaRunning, new KeepaliveStatus( - sessionHandle, KeepaliveStatus.STATUS_INACTIVE), null); - kaRunning.sendToTarget(); - } - waitForMs(100); - // Verify that a failed connection request cannot be stopped due to no record in - // the DataConnection. - mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget(); - waitForMs(100); - verify(mSimulatedCommandsVerifier, times(0)) - .stopNattKeepalive(anyInt(), any(Message.class)); - } - - @Test - @SmallTest - public void testStartNattKeepaliveFail() throws Exception { - checkStartNattKeepaliveFail(false); - } - - @Test - @SmallTest - public void testStartNattKeepaliveFailCondensed() throws Exception { - checkStartNattKeepaliveFail(true); - } - - @Test - @SmallTest - public void testIsUnmeteredUseOnly() throws Exception { - Field field = DataConnection.class.getDeclaredField("mTransportType"); - field.setAccessible(true); - field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - - assertFalse(isUnmeteredUseOnly()); - - field = DataConnection.class.getDeclaredField("mTransportType"); - field.setAccessible(true); - field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mServiceState).getDataRoaming(); - doReturn(ApnSetting.TYPE_MMS).when(mApnContext).getApnTypeBitmask(); - - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - - assertTrue(isUnmeteredUseOnly()); - } - - @Test - public void testIsEnterpriseUse() throws Exception { - assertFalse(isEnterpriseUse()); - assertFalse(mDc.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - - setUpDefaultData(1); - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); - doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); - connectEvent(true); - - assertTrue(isEnterpriseUse()); - assertTrue(mDc.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - } - - @Test - @SmallTest - public void testGetDisallowedApnTypes() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY, - new String[] { "mms", "supl", "fota" }); - testConnectEvent(); - - assertEquals(ApnSetting.TYPE_MMS | ApnSetting.TYPE_SUPL | ApnSetting.TYPE_FOTA, - getDisallowedApnTypes()); - } - - @Test - public void testIsSuspended() throws Exception { - // Return false if not active state - assertTrue(mDc.isInactive()); - assertFalse(isSuspended()); - - // Return false for emergency APN - doReturn(mApn6).when(mApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_EMERGENCY).when(mApnContext).getApnTypeBitmask(); - connectEvent(true); - assertFalse(isSuspended()); - - // Back to DEFAULT APN - disconnectEvent(); - assertTrue(mDc.isInactive()); - doReturn(mApn1).when(mApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); - doReturn(true).when(mSST).isConcurrentVoiceAndDataAllowed(); - connectEvent(true); - - // Before getting any service state event, the connection should not be suspended. - assertFalse(isSuspended()); - - // Return true if combined reg state is not in service - serviceStateChangedEvent(ServiceState.STATE_OUT_OF_SERVICE, - ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN); - assertTrue(isSuspended()); - - // Return false if in service and concurrent voice and data is allowed - serviceStateChangedEvent(ServiceState.STATE_IN_SERVICE, - ServiceState.RIL_RADIO_TECHNOLOGY_LTE); - assertFalse(isSuspended()); - - // Return false if in service and concurrent voice/data not allowed but call state is idle - doReturn(false).when(mSST).isConcurrentVoiceAndDataAllowed(); - doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); - mDc.sendMessage(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED); - waitForMs(100); - assertFalse(isSuspended()); - - // Return true if in service, concurrent voice/data not allowed, and call state not idle - doReturn(PhoneConstants.State.RINGING).when(mCT).getState(); - mDc.sendMessage(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED); - waitForMs(100); - assertTrue(isSuspended()); - } - - @Test - public void testDataCreatedWhenOutOfService() throws Exception { - serviceStateChangedEvent(ServiceState.STATE_OUT_OF_SERVICE, - ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN); - ArgumentCaptor ncCaptor = - ArgumentCaptor.forClass(NetworkCapabilities.class); - doReturn(mock(Network.class)).when(mConnectivityManager).registerNetworkAgent( - any(), any(), any(), ncCaptor.capture(), any(), any(), anyInt()); - - doReturn(mApn1).when(mApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); - doReturn(true).when(mSST).isConcurrentVoiceAndDataAllowed(); - connectEvent(true); - waitForMs(100); - - NetworkCapabilities nc = ncCaptor.getValue(); - // The network must be created with NOT_SUSPENDED capability. - assertTrue(nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)); - - // But it's final state must be suspended. - assertTrue(isSuspended()); - } - - @Test - public void testDataServiceTempUnavailable() throws Exception { - setFailedSetupDataResponse(DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE); - replaceInstance(ConnectionParams.class, "mRequestType", mCp, - DcTracker.REQUEST_TYPE_NORMAL); - // Verify that no data was setup - connectEvent(false); - assertTrue(mDc.isInactive()); - - // Verify that data service did not suggest any retry (i.e. Frameworks uses configured - // retry timer). - verify(mDataThrottler).setRetryTime(eq(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL), - eq(RetryManager.NO_SUGGESTED_RETRY_DELAY), eq(DcTracker.REQUEST_TYPE_NORMAL)); - } - - @Test - public void testDataHandoverFailed() throws Exception { - doReturn(mDefaultDc).when(mDcTracker).getDataConnectionByApnType(anyString()); - - doAnswer(invocation -> { - final Consumer consumer = (Consumer) invocation.getArguments()[0]; - consumer.accept(DataServiceCallback.RESULT_SUCCESS); - return null; - }).when(mDefaultDc).startHandover(any(Consumer.class)); - - replaceInstance(ConnectionParams.class, "mRequestType", mCp, - DcTracker.REQUEST_TYPE_HANDOVER); - assertTrue(mDc.isInactive()); - connectEvent(false); - - // Make sure the data connection is still in inactive state - assertTrue(mDc.isInactive()); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java deleted file mode 100644 index ffe4542b75..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; - -import android.os.HandlerThread; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import java.util.Objects; - -public class DataEnabledSettingsTest extends TelephonyTest { - - private DataEnabledSettings mDataEnabledSettingsUT; - - private DataEnabledSettingsTestHandler mDataEnabledSettingsTestHandler; - - private String mRules = ""; - - private class DataEnabledSettingsTestHandler extends HandlerThread { - - private DataEnabledSettingsTestHandler(String name) { - super(name); - } - - @Override - public void onLooperPrepared() { - mDataEnabledSettingsUT = new DataEnabledSettings(mPhone); - setReady(true); - } - } - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - doReturn(false).when(mPhone).isUsingNewDataStack(); - doReturn(mRules).when(mSubscriptionController).getDataEnabledOverrideRules(anyInt()); - - doAnswer(invocation -> { - String rules = (String) invocation.getArguments()[1]; - boolean changed = !Objects.equals(mRules, rules); - mRules = rules; - return changed; - }).when(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), anyString()); - - mDataEnabledSettingsTestHandler = new DataEnabledSettingsTestHandler( - getClass().getSimpleName()); - mDataEnabledSettingsTestHandler.start(); - waitUntilReady(); - } - - @After - public void tearDown() throws Exception { - mDataEnabledSettingsTestHandler.quit(); - mDataEnabledSettingsTestHandler.join(); - mDataEnabledSettingsTestHandler = null; - mDataEnabledSettingsUT = null; - super.tearDown(); - } - - @Test - @SmallTest - public void testSetDataAllowedInVoiceCall() throws Exception { - mDataEnabledSettingsUT.setAllowDataDuringVoiceCall(true); - ArgumentCaptor stringCaptor = ArgumentCaptor.forClass(String.class); - verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), - stringCaptor.capture()); - assertEquals("*=nonDefault&inVoiceCall&DefaultDataOn&dsdsEnabled", stringCaptor.getValue()); - - clearInvocations(mSubscriptionController); - - mDataEnabledSettingsUT.setAllowDataDuringVoiceCall(false); - verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), - stringCaptor.capture()); - assertEquals("", stringCaptor.getValue()); - } - - @Test - @SmallTest - public void testSetAlwaysAllowMmsData() throws Exception { - mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, false); - assertTrue(mDataEnabledSettingsUT.setAlwaysAllowMmsData(true)); - ArgumentCaptor stringCaptor = ArgumentCaptor.forClass(String.class); - verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), - stringCaptor.capture()); - assertEquals("mms=unconditionally", stringCaptor.getValue()); - assertTrue(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS)); - - clearInvocations(mSubscriptionController); - - assertTrue(mDataEnabledSettingsUT.setAlwaysAllowMmsData(false)); - verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), - stringCaptor.capture()); - assertEquals("", stringCaptor.getValue()); - assertFalse(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS)); - - mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, true); - assertTrue(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS)); - } - - @Test - @SmallTest - public void testSetThermalDataEnabled() throws Exception { - mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_THERMAL, - false); - assertFalse(mDataEnabledSettingsUT.isDataEnabledForReason( - TelephonyManager.DATA_ENABLED_REASON_THERMAL)); - assertFalse(mDataEnabledSettingsUT.isDataEnabled()); - - mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_THERMAL, - true); - assertTrue(mDataEnabledSettingsUT.isDataEnabledForReason( - TelephonyManager.DATA_ENABLED_REASON_THERMAL)); - assertTrue(mDataEnabledSettingsUT.isDataEnabled()); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java deleted file mode 100644 index d03bc8ca5c..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java +++ /dev/null @@ -1,222 +0,0 @@ -/** - * Copyright (C) 2020 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.dataconnection; - -import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_HANDOVER; -import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_NORMAL; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.telephony.AccessNetworkConstants; -import android.telephony.data.ApnSetting; -import android.telephony.data.ThrottleStatus; -import android.test.suitebuilder.annotation.SmallTest; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -/** - * Data throttler tests - */ -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class DataThrottlerTest extends TelephonyTest { - - private static final boolean DBG = true; - private DataThrottler mDataThrottler; - - // Mocked classes - private DataThrottler.Callback mMockChangedCallback1; - private DataThrottler.Callback mMockChangedCallback2; - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - mMockChangedCallback1 = mock(DataThrottler.Callback.class); - mMockChangedCallback2 = mock(DataThrottler.Callback.class); - mDataThrottler = new DataThrottler(mPhone, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - mDataThrottler.registerForThrottleStatusChanges(mMockChangedCallback1); - doReturn(false).when(mPhone).isUsingNewDataStack(); - } - - @After - public void tearDown() throws Exception { - mDataThrottler = null; - super.tearDown(); - } - - /** - * Test the behavior of a retry manager with no waiting APNs set. - */ - @Test - @SmallTest - public void testSetRetryTime() throws Exception { - final ArgumentCaptor> statusCaptor = - ArgumentCaptor.forClass((Class) List.class); - - List> expectedStatuses = new ArrayList<>(); - processAllMessages(); - expectedStatuses.add(List.of()); - - mDataThrottler.setRetryTime(ApnSetting.TYPE_DEFAULT, 1234567890L, - REQUEST_TYPE_NORMAL); - processAllMessages(); - assertEquals(1234567890L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, - mDataThrottler.getRetryTime(ApnSetting.TYPE_MMS)); - - processAllMessages(); - expectedStatuses.add(List.of( - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setApnType(ApnSetting.TYPE_DEFAULT) - .setThrottleExpiryTimeMillis(1234567890L) - .setRetryType(ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) - .build()) - ); - - - mDataThrottler.setRetryTime(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN, 13579L, - REQUEST_TYPE_HANDOVER); - processAllMessages(); - assertEquals(13579L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); - assertEquals(13579L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DUN)); - - processAllMessages(); - expectedStatuses.add(List.of( - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setApnType(ApnSetting.TYPE_DUN) - .setThrottleExpiryTimeMillis(13579L) - .setRetryType(ThrottleStatus.RETRY_TYPE_HANDOVER) - .build(), - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setApnType(ApnSetting.TYPE_DEFAULT) - .setThrottleExpiryTimeMillis(13579L) - .setRetryType(ThrottleStatus.RETRY_TYPE_HANDOVER) - .build()) - ); - - - mDataThrottler.setRetryTime(ApnSetting.TYPE_MMS, -10, - REQUEST_TYPE_NORMAL); - processAllMessages(); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, - mDataThrottler.getRetryTime(ApnSetting.TYPE_MMS)); - processAllMessages(); - expectedStatuses.add(List.of( - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setNoThrottle() - .setApnType(ApnSetting.TYPE_MMS) - .setRetryType(ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) - .build() - )); - - mDataThrottler.setRetryTime(ApnSetting.TYPE_FOTA | ApnSetting.TYPE_EMERGENCY, - RetryManager.NO_RETRY, REQUEST_TYPE_HANDOVER); - - processAllMessages(); - expectedStatuses.add(List.of( - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setApnType(ApnSetting.TYPE_EMERGENCY) - .setThrottleExpiryTimeMillis(RetryManager.NO_RETRY) - .setRetryType(ThrottleStatus.RETRY_TYPE_NONE) - .build(), - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setApnType(ApnSetting.TYPE_FOTA) - .setThrottleExpiryTimeMillis(RetryManager.NO_RETRY) - .setRetryType(ThrottleStatus.RETRY_TYPE_NONE) - .build() - )); - - assertEquals(RetryManager.NO_RETRY, mDataThrottler.getRetryTime(ApnSetting.TYPE_FOTA)); - assertEquals(RetryManager.NO_RETRY, mDataThrottler.getRetryTime(ApnSetting.TYPE_EMERGENCY)); - - - // Loop through statuses and test everything - verify(mMockChangedCallback1, times(expectedStatuses.size())) - .onThrottleStatusChanged(statusCaptor.capture()); - - // Check actual statuses - List> actualStatuses = - (List>) statusCaptor.getAllValues(); - assertEquals(expectedStatuses.size(), actualStatuses.size()); - - if (DBG) { - logd("expectedStatuses.size() = " + expectedStatuses.size()); - logd("actualStatuses.size() = " + actualStatuses.size()); - } - - Comparator comparator = (o1, o2) -> - Integer.compare(o1.getApnType(), o2.getApnType()); - - for (int i = 0; i < expectedStatuses.size(); i++) { - List atsExpected = new ArrayList<>(expectedStatuses.get(i)); - List atsActual = new ArrayList<>(actualStatuses.get(i)); - - atsExpected.sort(comparator); - atsActual.sort(comparator); - assertEquals("Lists at index " + i + " don't match", - atsExpected, atsActual); - } - - this.mDataThrottler.registerForThrottleStatusChanges(mMockChangedCallback2); - } - - /** - * Test the behavior of a retry manager with no waiting APNs set. - */ - @Test - @SmallTest - public void testUnthrottle() throws Exception { - mDataThrottler.setRetryTime(ApnSetting.TYPE_DEFAULT, 1234567890L, - REQUEST_TYPE_NORMAL); - processAllMessages(); - assertEquals(1234567890L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); - - mDataThrottler.reset(); - processAllMessages(); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, - mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java deleted file mode 100644 index bddfdb4fa5..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.net.InetAddresses; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.telephony.AccessNetworkConstants; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.test.suitebuilder.annotation.SmallTest; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.dataconnection.DataConnection.UpdateLinkPropertyResult; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class DcControllerTest extends TelephonyTest { - - private static final int DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT = 1; - private static final int DATA_CONNECTION_ACTIVE_PH_LINK_ACTIVE = 2; - - private static final int EVENT_DATA_STATE_CHANGED = 0x00040007; - private static final int EVENT_PHYSICAL_LINK_STATUS_CHANGED = 1; - - // Mocked classes - private List mApnContexts; - private DataConnection mDc; - private DataServiceManager mDataServiceManager; - private Handler mTestHandler; - - UpdateLinkPropertyResult mResult; - - private DcController mDcc; - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - mApnContexts = mock(List.class); - mDc = mock(DataConnection.class); - mDataServiceManager = mock(DataServiceManager.class); - mTestHandler = mock(Handler.class); - - doReturn("fake.action_detached").when(mPhone).getActionDetached(); - doReturn(1).when(mApnContexts).size(); - doReturn(mApnContexts).when(mDc).getApnContexts(); - doReturn(false).when(mPhone).isUsingNewDataStack(); - - LinkProperties lp = new LinkProperties(); - mResult = new UpdateLinkPropertyResult(lp); - doReturn(mResult).when(mDc).updateLinkProperty(any(DataCallResponse.class)); - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .when(mDataServiceManager).getTransportType(); - - mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, Looper.myLooper(), - ""); - processAllMessages(); - } - - @After - public void tearDown() throws Exception { - mDcc.removeCallbacksAndMessages(null); - mDcc = null; - mResult = null; - super.tearDown(); - } - - @Test - @SmallTest - public void testDataDormant() throws Exception { - ArrayList l = new ArrayList<>(); - DataCallResponse dcResponse = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - l.add(dcResponse); - - mDc.mCid = 1; - mDcc.addActiveDcByCid(mDc); - - mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, - new AsyncResult(null, l, null))); - processAllMessages(); - - verify(mDcTracker, times(1)).sendStopNetStatPoll(eq(DctConstants.Activity.DORMANT)); - } - - @Test - @SmallTest - public void testPhysicalLinkStatusChanged_defaultApnTypeAndDormant_registrantNotifyResult() - throws Exception { - ArrayList l = new ArrayList<>(); - DataCallResponse dcResponse = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - l.add(dcResponse); - mDc.mCid = 1; - mDcc.addActiveDcByCid(mDc); - ApnContext apnContext = new ApnContext(mPhone, ApnSetting.TYPE_DEFAULT, TAG, mDcTracker, 1); - List apnContextList = new ArrayList<>(); - apnContextList.add(apnContext); - doReturn(apnContextList).when(mDc).getApnContexts(); - doReturn(true).when(mDcTracker).getLteEndcUsingUserDataForIdleDetection(); - mDcc.registerForPhysicalLinkStatusChanged(mTestHandler, EVENT_PHYSICAL_LINK_STATUS_CHANGED); - - mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, - new AsyncResult(null, l, null))); - processAllMessages(); - - ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); - verify(mTestHandler, times(1)).sendMessageDelayed(messageCaptor.capture(), anyLong()); - Message message = messageCaptor.getValue(); - assertEquals(EVENT_PHYSICAL_LINK_STATUS_CHANGED, message.what); - AsyncResult ar = (AsyncResult) message.obj; - assertEquals(DataCallResponse.LINK_STATUS_DORMANT, (int) ar.result); - } - - @Test - @SmallTest - public void testPhysicalLinkStatusChanged_imsApnTypeAndDormant_NoNotifyResult() - throws Exception { - testPhysicalLinkStatusChanged_defaultApnTypeAndDormant_registrantNotifyResult(); - - ArrayList l = new ArrayList<>(); - DataCallResponse dcResponse = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_ACTIVE) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - l.add(dcResponse); - mDc.mCid = 1; - mDcc.addActiveDcByCid(mDc); - ApnContext apnContext = new ApnContext(mPhone, ApnSetting.TYPE_IMS, TAG, mDcTracker, 1); - List apnContextList = new ArrayList<>(); - apnContextList.add(apnContext); - doReturn(apnContextList).when(mDc).getApnContexts(); - doReturn(true).when(mDcTracker).getLteEndcUsingUserDataForIdleDetection(); - - mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, - new AsyncResult(null, l, null))); - processAllMessages(); - - ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); - verify(mTestHandler, times(1)).sendMessageDelayed(messageCaptor.capture(), anyLong()); - } - - @Test - @SmallTest - public void testPhysicalLinkStatusChanged_defaultApnTypeAndStateChanged_registrantNotifyResult() - throws Exception { - testPhysicalLinkStatusChanged_imsApnTypeAndDormant_NoNotifyResult(); - - ArrayList l = new ArrayList<>(); - DataCallResponse dcResponse = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_ACTIVE) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - l.add(dcResponse); - mDc.mCid = 1; - mDcc.addActiveDcByCid(mDc); - ApnContext apnContext = new ApnContext(mPhone, ApnSetting.TYPE_DEFAULT, TAG, mDcTracker, 1); - List apnContextList = new ArrayList<>(); - apnContextList.add(apnContext); - doReturn(apnContextList).when(mDc).getApnContexts(); - doReturn(true).when(mDcTracker).getLteEndcUsingUserDataForIdleDetection(); - - mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, - new AsyncResult(null, l, null))); - processAllMessages(); - - ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); - verify(mTestHandler, times(2)).sendMessageDelayed(messageCaptor.capture(), anyLong()); - Message message = messageCaptor.getValue(); - assertEquals(EVENT_PHYSICAL_LINK_STATUS_CHANGED, message.what); - AsyncResult ar = (AsyncResult) message.obj; - assertEquals(DataCallResponse.LINK_STATUS_ACTIVE, (int) ar.result); - } -} \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java deleted file mode 100644 index 78438e41d9..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2022 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.dataconnection; - -import static junit.framework.Assert.assertEquals; - -import static org.mockito.Mockito.doReturn; - -import android.net.ConnectivityManager; -import android.net.LinkProperties; -import android.net.NetworkAgent; -import android.net.NetworkAgentConfig; -import android.net.NetworkInfo; -import android.net.NetworkProvider; -import android.os.Looper; -import android.telephony.AccessNetworkConstants; -import android.telephony.TelephonyManager; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; - -import java.lang.reflect.Field; - -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class DcNetworkAgentTest extends TelephonyTest { - - private DcNetworkAgent mDcNetworkAgent; - private DataConnection mDc; - private DcController mDcc; - private DcFailBringUp mDcFailBringUp; - - private DataServiceManager mDataServiceManager; - private DcTesterFailBringUpAll mDcTesterFailBringUpAll; - private NetworkProvider mNetworkProvider; - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - logd("+Setup!"); - if (Looper.myLooper() == null) { - Looper.prepare(); - } - - doReturn(false).when(mPhone).isUsingNewDataStack(); - mDataServiceManager = Mockito.mock(DataServiceManager.class); - mDcTesterFailBringUpAll = Mockito.mock(DcTesterFailBringUpAll.class); - mNetworkProvider = Mockito.mock(NetworkProvider.class); - - final NetworkAgentConfig.Builder configBuilder = new NetworkAgentConfig.Builder(); - configBuilder.setLegacyType(ConnectivityManager.TYPE_MOBILE); - configBuilder.setLegacyTypeName("MOBILE"); - configBuilder.setLegacySubType(TelephonyManager.NETWORK_TYPE_LTE); - configBuilder.setLegacySubTypeName("LTE"); - configBuilder.setLegacyExtraInfo("apn"); - - doReturn("fake.action_detached").when(mPhone).getActionDetached(); - mDcFailBringUp = new DcFailBringUp(); - mDcFailBringUp.saveParameters(0, 0, -2); - doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp(); - - mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, Looper.myLooper(), - ""); - mDc = DataConnection.makeDataConnection(mPhone, 0, mDcTracker, mDataServiceManager, - mDcTesterFailBringUpAll, mDcc); - - LinkProperties linkProperties = new LinkProperties(); - linkProperties.setInterfaceName("fake_iface"); - Field field = DataConnection.class.getDeclaredField("mLinkProperties"); - field.setAccessible(true); - field.set(mDc, linkProperties); - - mDcNetworkAgent = new DcNetworkAgent(mDc, mPhone, 45, configBuilder.build(), - mNetworkProvider, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - logd("-Setup!"); - } - - @After - public void tearDown() throws Exception { - super.tearDown(); - } - - private void verifyDisconnected() throws Exception { - Field field = NetworkAgent.class.getDeclaredField("mNetworkInfo"); - field.setAccessible(true); - NetworkInfo networkInfo = (NetworkInfo) field.get(mDcNetworkAgent); - assertEquals(NetworkInfo.DetailedState.DISCONNECTED, networkInfo.getDetailedState()); - } - - @Test - public void testUnwantedTimeout() throws Exception { - mDcNetworkAgent.markConnected(); - mDcNetworkAgent.onNetworkUnwanted(); - processAllFutureMessages(); - verifyDisconnected(); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java deleted file mode 100644 index b08a6803d0..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2020 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.dataconnection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.net.TelephonyNetworkSpecifier; -import android.telephony.data.ApnSetting; - -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class DcRequestTest extends TelephonyTest { - NetworkRequest mNetworkRequest; - - // Mocked classes - ApnConfigTypeRepository mApnConfigTypeRepo; - - @Before - public void setUp() throws Exception { - mApnConfigTypeRepo = mock(ApnConfigTypeRepository.class); - super.setUp(getClass().getSimpleName()); - doReturn(false).when(mPhone).isUsingNewDataStack(); - } - - @After - public void tearDown() throws Exception { - mNetworkRequest = null; - super.tearDown(); - } - - @Test - public void whenNetworkRequestInternetThenPriorityZero() { - mNetworkRequest = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); - - when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_DEFAULT)) - .thenReturn(new ApnConfigType(ApnSetting.TYPE_DEFAULT, 0)); - DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); - - assertEquals(0, dcRequest.priority); - } - - @Test - public void whenNetworkRequestMcxThenApnConfigTypeMcxPriorityReturned() { - mNetworkRequest = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - //Testing out multiple transport types here - .addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH) - .addCapability(NetworkCapabilities.NET_CAPABILITY_MCX) - .build(); - - when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_MCX)) - .thenReturn(new ApnConfigType(ApnSetting.TYPE_MCX, 21)); - DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); - assertEquals(21, dcRequest.priority); - } - - @Test - public void whenNetworkRequestNotCellularThenDcRequestIsNull() { - mNetworkRequest = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .addCapability(NetworkCapabilities.NET_CAPABILITY_MCX) - .build(); - when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_NONE)).thenReturn(null); - DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); - assertNull(dcRequest); - } - - @Test - public void whenNetworkRequestHasNoTransportThenPriorityStays() { - //This seems like an invalid case that should be handled differently. - mNetworkRequest = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_MCX) - .build(); - - when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_MCX)) - .thenReturn(new ApnConfigType(ApnSetting.TYPE_MCX, 11)); - DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); - assertEquals(11, dcRequest.priority); - } - - @Test - public void whenNetworkRequestNotCellularWithTelephonySpecifierThenDcRequestIsNull() { - TelephonyNetworkSpecifier telephonyNetworkSpecifier = - new TelephonyNetworkSpecifier.Builder().setSubscriptionId(5).build(); - - //This seems like an invalid case that should be handled differently. - mNetworkRequest = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH) - .setNetworkSpecifier(telephonyNetworkSpecifier) - .build(); - - when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_NONE)).thenReturn(null); - - DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); - - assertNull(dcRequest); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java deleted file mode 100644 index 549c587549..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +++ /dev/null @@ -1,2983 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; -import static com.android.internal.telephony.dataconnection.ApnSettingTest.createApnSetting; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ServiceInfo; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.hardware.radio.V1_0.SetupDataCallResult; -import android.net.LinkProperties; -import android.net.NetworkAgent; -import android.net.NetworkCapabilities; -import android.net.NetworkPolicyManager; -import android.net.NetworkRequest; -import android.net.Uri; -import android.os.AsyncResult; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Message; -import android.os.PersistableBundle; -import android.os.SystemClock; -import android.provider.Settings; -import android.provider.Telephony; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.AccessNetworkType; -import android.telephony.Annotation; -import android.telephony.CarrierConfigManager; -import android.telephony.DataFailCause; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.PreciseDataConnectionState; -import android.telephony.ServiceState; -import android.telephony.SignalStrength; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.SubscriptionPlan; -import android.telephony.TelephonyDisplayInfo; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.telephony.data.DataProfile; -import android.telephony.data.DataService; -import android.telephony.data.TrafficDescriptor; -import android.test.mock.MockContentProvider; -import android.test.mock.MockContentResolver; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; -import android.text.TextUtils; -import android.util.Pair; -import android.util.SparseArray; - -import androidx.test.filters.FlakyTest; - -import com.android.internal.R; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.ISub; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.data.CellularDataService; -import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType; - -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.mockito.stubbing.Answer; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.time.Period; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -public class DcTrackerTest extends TelephonyTest { - public static final String FAKE_APN1 = "FAKE APN 1"; - public static final String FAKE_APN2 = "FAKE APN 2"; - public static final String FAKE_APN3 = "FAKE APN 3"; - public static final String FAKE_APN4 = "FAKE APN 4"; - public static final String FAKE_APN5 = "FAKE APN 5"; - public static final String FAKE_APN6 = "FAKE APN 6"; - public static final String FAKE_APN7 = "FAKE APN 7"; - public static final String FAKE_APN8 = "FAKE APN 8"; - public static final String FAKE_APN9 = "FAKE APN 9"; - public static final String FAKE_IFNAME = "FAKE IFNAME"; - public static final String FAKE_PCSCF_ADDRESS = "22.33.44.55"; - public static final String FAKE_GATEWAY = "11.22.33.44"; - public static final String FAKE_DNS = "55.66.77.88"; - public static final String FAKE_ADDRESS = "99.88.77.66"; - private static final int NETWORK_TYPE_NR_BITMASK = - 1 << (TelephonyManager.NETWORK_TYPE_NR - 1); - private static final int NETWORK_TYPE_LTE_BITMASK = - 1 << (TelephonyManager.NETWORK_TYPE_LTE - 1); - private static final int NETWORK_TYPE_EHRPD_BITMASK = - 1 << (TelephonyManager.NETWORK_TYPE_EHRPD - 1); - private static final Uri PREFERAPN_URI = Uri.parse( - Telephony.Carriers.CONTENT_URI + "/preferapn"); - private static final int DATA_ENABLED_CHANGED = 0; - private static final String FAKE_PLMN = "44010"; - private static final long TEST_TIMEOUT = 1000; - - // Mocked classes - ISub mIsub; - IBinder mBinder; - SubscriptionInfo mSubscriptionInfo; - ApnContext mApnContext; - DataConnection mDataConnection; - Handler mHandler; - NetworkPolicyManager mNetworkPolicyManager; - - private DcTracker mDct; - private DcTrackerTestHandler mDcTrackerTestHandler; - - private AlarmManager mAlarmManager; - - private PersistableBundle mBundle; - - private SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener; - - private final ApnSettingContentProvider mApnSettingContentProvider = - new ApnSettingContentProvider(); - - private Message mMessage; - - private CellularDataService mCellularDataService; - - private void addDataService() { - mCellularDataService = new CellularDataService(); - ServiceInfo serviceInfo = new ServiceInfo(); - serviceInfo.packageName = "com.android.phone"; - serviceInfo.permission = "android.permission.BIND_TELEPHONY_DATA_SERVICE"; - IntentFilter filter = new IntentFilter(); - mContextFixture.addService( - DataService.SERVICE_INTERFACE, - null, - "com.android.phone", - mCellularDataService.mBinder, - serviceInfo, - filter); - } - - private class DcTrackerTestHandler extends HandlerThread { - - private DcTrackerTestHandler(String name) { - super(name); - } - - @Override - public void onLooperPrepared() { - mDct = new DcTracker(mPhone, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - setReady(true); - } - } - - private class ApnSettingContentProvider extends MockContentProvider { - public final String[] FAKE_APN_COLUMNS = new String[]{ - Telephony.Carriers._ID, Telephony.Carriers.NUMERIC, - Telephony.Carriers.NAME, Telephony.Carriers.APN, - Telephony.Carriers.PROXY, Telephony.Carriers.PORT, - Telephony.Carriers.MMSC, Telephony.Carriers.MMSPROXY, - Telephony.Carriers.MMSPORT, Telephony.Carriers.USER, - Telephony.Carriers.PASSWORD, Telephony.Carriers.AUTH_TYPE, - Telephony.Carriers.TYPE, - Telephony.Carriers.PROTOCOL, - Telephony.Carriers.ROAMING_PROTOCOL, - Telephony.Carriers.CARRIER_ENABLED, Telephony.Carriers.BEARER, - Telephony.Carriers.BEARER_BITMASK, - Telephony.Carriers.PROFILE_ID, - Telephony.Carriers.MODEM_PERSIST, - Telephony.Carriers.MAX_CONNECTIONS, - Telephony.Carriers.WAIT_TIME_RETRY, - Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS, - Telephony.Carriers.MTU, - Telephony.Carriers.MTU_V4, - Telephony.Carriers.MTU_V6, - Telephony.Carriers.MVNO_TYPE, - Telephony.Carriers.MVNO_MATCH_DATA, - Telephony.Carriers.NETWORK_TYPE_BITMASK, - Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK, - Telephony.Carriers.APN_SET_ID, - Telephony.Carriers.CARRIER_ID, - Telephony.Carriers.SKIP_464XLAT, - Telephony.Carriers.ALWAYS_ON - }; - - private int mPreferredApnSet = 0; - - private Object[] mPreferredApn = null; - - private String mFakeApn1Types = "default,supl"; - - private String mFakeApn5Types = "dun"; - - private int mFakeApn1Bitmask = NETWORK_TYPE_LTE_BITMASK; - - private int mRowIdOffset = 0; - - public void setFakeApn1Types(String apnTypes) { - mFakeApn1Types = apnTypes; - } - - public void setFakeApn5Types(String apnTypes) { - mFakeApn5Types = apnTypes; - } - - public void setFakeApn1NetworkTypeBitmask(int bitmask) { - mFakeApn1Bitmask = bitmask; - } - - public void setRowIdOffset(int rowIdOffset) { - mRowIdOffset = rowIdOffset; - } - - public void setFakePreferredApn(Object[] fakeApn) { - mPreferredApn = fakeApn; - } - - public Object[] getFakeApn1() { - return new Object[]{ - 2163 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "sp-mode", // name - FAKE_APN1, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - mFakeApn1Types, // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - mFakeApn1Bitmask, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn2() { - return new Object[]{ - 2164 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "mopera U", // name - FAKE_APN2, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "default,supl", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer, - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn3() { - return new Object[]{ - 2165 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "b-mobile for Nexus", // name - FAKE_APN3, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "ims", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - 0, // bearer - 0, // bearer_bitmask - 2, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - 0, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn4() { - return new Object[]{ - 2166 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "sp-mode ehrpd", // name - FAKE_APN4, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "default,supl", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_EHRPD_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn5() { - return new Object[]{ - 2167 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "b-mobile for Nexus", // name - FAKE_APN5, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - mFakeApn5Types, // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - 0, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - 0, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn6() { - return new Object[]{ - 2168 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "sp-mode", // name - FAKE_APN6, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "mms,xcap", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn7() { - return new Object[]{ - 2169 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "sp-mode", // name - FAKE_APN7, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "default", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - 1, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn8() { - return new Object[]{ - 2170 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "IMS", // name - FAKE_APN8, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "ims", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer - 0, // bearer_bitmask - 2, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - -1, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn9() { - return new Object[]{ - 2171 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "sp-mode nr", // name - FAKE_APN9, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "default,enterprise", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_NR_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - logd("ApnSettingContentProvider: query"); - logd(" uri = " + uri); - logd(" projection = " + Arrays.toString(projection)); - logd(" selection = " + selection); - logd(" selectionArgs = " + Arrays.toString(selectionArgs)); - logd(" sortOrder = " + sortOrder); - - if (uri.compareTo(Telephony.Carriers.CONTENT_URI) == 0 - || uri.toString().startsWith(Uri.withAppendedPath( - Telephony.Carriers.CONTENT_URI, "filtered").toString()) - || uri.toString().startsWith(Uri.withAppendedPath( - Telephony.Carriers.SIM_APN_URI, "filtered").toString())) { - if (projection == null) { - - logd("Query '" + FAKE_PLMN + "' APN settings"); - MatrixCursor mc = new MatrixCursor(FAKE_APN_COLUMNS); - mc.addRow(getFakeApn1()); - mc.addRow(getFakeApn2()); - mc.addRow(getFakeApn3()); - mc.addRow(getFakeApn4()); - mc.addRow(getFakeApn5()); - mc.addRow(getFakeApn6()); - mc.addRow(getFakeApn7()); - mc.addRow(getFakeApn8()); - mc.addRow(getFakeApn9()); - - return mc; - } - } else if (isPathPrefixMatch(uri, - Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapnset"))) { - MatrixCursor mc = new MatrixCursor( - new String[]{Telephony.Carriers.APN_SET_ID}); - // apn_set_id is the only field used with this URL - mc.addRow(new Object[]{ mPreferredApnSet }); - mc.addRow(new Object[]{ 0 }); - return mc; - } else if (isPathPrefixMatch(uri, - Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapn_no_update"))) { - if (mPreferredApn == null) { - return null; - } else { - MatrixCursor mc = new MatrixCursor(FAKE_APN_COLUMNS); - mc.addRow(mPreferredApn); - return mc; - } - } - - return null; - } - - @Override - public int update(Uri url, ContentValues values, String where, String[] whereArgs) { - mPreferredApnSet = values.getAsInteger(Telephony.Carriers.APN_SET_ID); - return 1; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - } - - @Before - public void setUp() throws Exception { - logd("DcTrackerTest +Setup!"); - super.setUp(getClass().getSimpleName()); - mIsub = Mockito.mock(ISub.class); - mBinder = Mockito.mock(IBinder.class); - mSubscriptionInfo = Mockito.mock(SubscriptionInfo.class); - mApnContext = Mockito.mock(ApnContext.class); - mDataConnection = Mockito.mock(DataConnection.class); - mHandler = Mockito.mock(Handler.class); - mNetworkPolicyManager = Mockito.mock(NetworkPolicyManager.class); - - doReturn("fake.action_detached").when(mPhone).getActionDetached(); - doReturn("fake.action_attached").when(mPhone).getActionAttached(); - doReturn(false).when(mPhone).isUsingNewDataStack(); - doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState) - .getRilDataRadioTechnology(); - - mContextFixture.putStringArrayResource(com.android.internal.R.array - .config_mobile_tcp_buffers, new String[]{ - "umts:131072,262144,1452032,4096,16384,399360", - "hspa:131072,262144,2441216,4096,16384,399360", - "hsupa:131072,262144,2441216,4096,16384,399360", - "hsdpa:131072,262144,2441216,4096,16384,399360", - "hspap:131072,262144,2441216,4096,16384,399360", - "edge:16384,32768,131072,4096,16384,65536", - "gprs:4096,8192,24576,4096,8192,24576", - "1xrtt:16384,32768,131070,4096,16384,102400", - "evdo:131072,262144,1048576,4096,16384,524288", - "lte:524288,1048576,8388608,262144,524288,4194304"}); - - mContextFixture.putResource(R.string.config_wwan_data_service_package, - "com.android.phone"); - - ((MockContentResolver) mContext.getContentResolver()).addProvider( - Telephony.Carriers.CONTENT_URI.getAuthority(), mApnSettingContentProvider); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0); - - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) - .getPreferredTransport(anyInt()); - doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); - doReturn(true).when(mSST).getDesiredPowerState(); - doReturn(true).when(mSST).getPowerStateFromCarrier(); - doAnswer( - (Answer) invocation -> { - mOnSubscriptionsChangedListener = - (SubscriptionManager.OnSubscriptionsChangedListener) - invocation.getArguments()[0]; - return null; - } - ).when(mSubscriptionManager).addOnSubscriptionsChangedListener(any()); - doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt()); - doReturn(mNetworkPolicyManager).when(mContext) - .getSystemService(Context.NETWORK_POLICY_SERVICE); - doReturn(1).when(mIsub).getDefaultDataSubId(); - doReturn(mIsub).when(mBinder).queryLocalInterface(anyString()); - mServiceManagerMockedServices.put("isub", mBinder); - - mContextFixture.putStringArrayResource( - com.android.internal.R.array.config_cell_retries_per_error_code, - new String[]{"36,2"}); - - mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); - mBundle = mContextFixture.getCarrierConfigBundle(); - - mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); - - mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult()); - addDataService(); - - mDcTrackerTestHandler = new DcTrackerTestHandler(getClass().getSimpleName()); - mDcTrackerTestHandler.start(); - waitUntilReady(); - - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - - waitForMs(600); - logd("DcTrackerTest -Setup!"); - } - - @After - public void tearDown() throws Exception { - logd("DcTrackerTest -tearDown"); - mDct.removeCallbacksAndMessages(null); - mDct.stopHandlerThread(); - mDct = null; - mDcTrackerTestHandler.quit(); - mDcTrackerTestHandler.join(); - mDcTrackerTestHandler = null; - mCellularDataService.onDestroy(); - mCellularDataService = null; - mAlarmManager = null; - mBundle = null; - mCellularDataService = null; - waitForMs(100); - super.tearDown(); - } - - // Create a successful data response - private static SetupDataCallResult createSetupDataCallResult() { - SetupDataCallResult result = new SetupDataCallResult(); - result.status = 0; - result.suggestedRetryTime = -1; - result.cid = 1; - result.active = 2; - result.type = "IP"; - result.ifname = FAKE_IFNAME; - result.addresses = FAKE_ADDRESS; - result.dnses = FAKE_DNS; - result.gateways = FAKE_GATEWAY; - result.pcscf = FAKE_PCSCF_ADDRESS; - result.mtu = 1440; - return result; - } - - private void verifyDataProfile(DataProfile dp, String apn, int profileId, - int supportedApnTypesBitmap, int type, int bearerBitmask) { - assertEquals(profileId, dp.getProfileId()); - assertEquals(apn, dp.getApn()); - assertEquals(ApnSetting.PROTOCOL_IP, dp.getProtocolType()); - assertEquals(0, dp.getAuthType()); - assertEquals("", dp.getUserName()); - assertEquals("", dp.getPassword()); - assertEquals(type, dp.getType()); - assertEquals(0, dp.getWaitTime()); - assertTrue(dp.isEnabled()); - assertEquals(supportedApnTypesBitmap, dp.getSupportedApnTypesBitmask()); - assertEquals(ApnSetting.PROTOCOL_IP, dp.getRoamingProtocolType()); - assertEquals(bearerBitmask, dp.getBearerBitmask()); - assertEquals(0, dp.getMtu()); - assertTrue(dp.isPersistent()); - assertFalse(dp.isPreferred()); - } - - private void verifyDataConnected(final String apnSetting) { - verify(mAlarmManager, times(1)).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), - any(PendingIntent.class)); - - assertEquals(apnSetting, mDct.getActiveApnString(ApnSetting.TYPE_DEFAULT_STRING)); - assertArrayEquals(new String[]{ApnSetting.TYPE_DEFAULT_STRING}, mDct.getActiveApnTypes()); - - assertTrue(mDct.isAnyDataConnected()); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - - LinkProperties linkProperties = mDct.getLinkProperties(ApnSetting.TYPE_DEFAULT_STRING); - assertEquals(FAKE_IFNAME, linkProperties.getInterfaceName()); - assertEquals(1, linkProperties.getAddresses().size()); - assertEquals(FAKE_ADDRESS, linkProperties.getAddresses().get(0).getHostAddress()); - assertEquals(1, linkProperties.getDnsServers().size()); - assertEquals(FAKE_DNS, linkProperties.getDnsServers().get(0).getHostAddress()); - assertEquals(FAKE_GATEWAY, linkProperties.getRoutes().get(0).getGateway().getHostAddress()); - } - - private boolean isHandoverPending(int apnType) { - try { - Method method = DcTracker.class.getDeclaredMethod("isHandoverPending", - int.class); - method.setAccessible(true); - return (boolean) method.invoke(mDct, apnType); - } catch (Exception e) { - fail(e.toString()); - return false; - } - } - - private void addHandoverCompleteMsg(Message onCompleteMsg, - @Annotation.ApnType int apnType) { - try { - Method method = DcTracker.class.getDeclaredMethod("addHandoverCompleteMsg", - Message.class, int.class); - method.setAccessible(true); - method.invoke(mDct, onCompleteMsg, apnType); - } catch (Exception e) { - fail(e.toString()); - } - } - - private void sendInitializationEvents() { - sendCarrierConfigChanged(""); - - sendSimStateUpdated(""); - - sendEventDataConnectionAttached(""); - - waitForMs(200); - } - - private void sendCarrierConfigChanged(String messagePrefix) { - logd(messagePrefix + "Sending EVENT_CARRIER_CONFIG_CHANGED"); - mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - private void sendSimStateUpdated(String messagePrefix) { - logd(messagePrefix + "Sending EVENT_SIM_STATE_UPDATED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SIM_STATE_UPDATED, - TelephonyManager.SIM_STATE_LOADED, 0)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - private void sendEventDataConnectionAttached(String messagePrefix) { - logd(messagePrefix + "Sending EVENT_DATA_CONNECTION_ATTACHED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - // Test the unmetered APN setup when data is disabled. - @Test - @SmallTest - public void testTrySetupDataUnmeteredDefaultNotSelected() throws Exception { - initApns(ApnSetting.TYPE_XCAP_STRING, new String[]{ApnSetting.TYPE_XCAP_STRING}); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mIsub).getDefaultDataSubId(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - sendInitializationEvents(); - - mDct.enableApn(ApnSetting.TYPE_XCAP, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the normal data call setup scenario. - @Test - @MediumTest - public void testDataSetup() throws Exception { - DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); - boolean allowed = mDct.isDataAllowed(dataConnectionReasons); - assertFalse(dataConnectionReasons.toString(), allowed); - - logd("Sending EVENT_ENABLE_APN"); - // APN id 0 is APN_TYPE_DEFAULT - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - sendInitializationEvents(); - - dataConnectionReasons = new DataConnectionReasons(); - allowed = mDct.isDataAllowed(dataConnectionReasons); - assertTrue(dataConnectionReasons.toString(), allowed); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - verifyDataConnected(FAKE_APN1); - } - - // Test the scenario where the first data call setup is failed, and then retry the setup later. - @Test - @MediumTest - public void testDataRetry() throws Exception { - AsyncResult ar = new AsyncResult(null, - new Pair<>(true, DataEnabledSettings.REASON_USER_DATA_ENABLED), null); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // LOST_CONNECTION(0x10004) is a non-permanent failure, so we'll retry data setup later. - SetupDataCallResult result = createSetupDataCallResult(); - result.status = 0x10004; - - // Simulate RIL fails the data call setup - mSimulatedCommands.setDataCallResult(true, result); - - DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); - boolean allowed = mDct.isDataAllowed(dataConnectionReasons); - assertFalse(dataConnectionReasons.toString(), allowed); - - logd("Sending EVENT_ENABLE_APN"); - // APN id 0 is APN_TYPE_DEFAULT - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - sendInitializationEvents(); - - dataConnectionReasons = new DataConnectionReasons(); - allowed = mDct.isDataAllowed(dataConnectionReasons); - assertTrue(dataConnectionReasons.toString(), allowed); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - // This time we'll let RIL command succeed. - mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult()); - - //Send event for reconnecting data - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RECONNECT, - mPhone.getPhoneId(), DcTracker.REQUEST_TYPE_NORMAL, mApnContext)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN2, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - // Verify connected with APN2 setting. - verifyDataConnected(FAKE_APN2); - } - - @Test - @MediumTest - @Ignore - @FlakyTest - public void testUserDisableData() { - //step 1: setup two DataCalls one for Metered: default, another one for Non-metered: IMS - //set Default and MMS to be metered in the CarrierConfigManager - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending DATA_DISABLED_CMD"); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - AsyncResult ar = new AsyncResult(null, - new Pair<>(false, DataEnabledSettings.REASON_USER_DATA_ENABLED), null); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // expected tear down all metered DataConnections - verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - assertTrue(mDct.isAnyDataConnected()); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING)); - } - - @Test - @MediumTest - public void testTrySetupDataMmsAllowedDataDisabled() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_MMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - - List dataProfiles = dpCaptor.getAllValues(); - assertEquals(2, dataProfiles.size()); - - //Verify FAKE_APN1 - Optional fakeApn1 = dataProfiles.stream() - .filter(dp -> dp.getApn().equals(FAKE_APN1)) - .findFirst(); - assertTrue(fakeApn1.isPresent()); - verifyDataProfile(fakeApn1.get(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - //Verify FAKE_APN6 - Optional fakeApn6 = dataProfiles.stream() - .filter(dp -> dp.getApn().equals(FAKE_APN6)) - .findFirst(); - assertTrue(fakeApn6.isPresent()); - verifyDataProfile(fakeApn6.get(), FAKE_APN6, 0, ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP, - 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending DATA_DISABLED_CMD for default data"); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // expected tear down all metered DataConnections - verify(mSimulatedCommandsVerifier, times(2)).deactivateDataCall( - anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING)); - - clearInvocations(mSimulatedCommandsVerifier); - doReturn(true).when(mDataEnabledSettings).isDataEnabled(ApnSetting.TYPE_MMS); - mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); - } - - @Test - @MediumTest - public void testTrySetupDataMmsAlwaysAllowedDataDisabled() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mApnSettingContentProvider.setFakeApn1Types("mms,xcap,default"); - mDct.enableApn(ApnSetting.TYPE_MMS, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - - // Verify MMS was set up and is connected - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, - ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP | ApnSetting.TYPE_DEFAULT, - 1, NETWORK_TYPE_LTE_BITMASK); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); - - // Verify DC has all capabilities specified in fakeApn1Types - Map apnContexts = mDct.getApnContexts().stream().collect( - Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); - assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)); - assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_INTERNET)); - - // Disable mobile data - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - doReturn(false).when(mDataEnabledSettings).isMmsAlwaysAllowed(); - mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Expected tear down all metered DataConnections - waitForMs(200); - verify(mSimulatedCommandsVerifier).deactivateDataCall( - anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING)); - - // Allow MMS unconditionally - clearInvocations(mSimulatedCommandsVerifier); - doReturn(true).when(mDataEnabledSettings).isMmsAlwaysAllowed(); - doReturn(true).when(mDataEnabledSettings).isDataEnabled(ApnSetting.TYPE_MMS); - mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Verify MMS was set up and is connected - waitForMs(200); - verify(mSimulatedCommandsVerifier).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); - - // Ensure MMS data connection has the MMS capability only. - apnContexts = mDct.getApnContexts().stream().collect( - Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); - assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)); - assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_INTERNET)); - } - - @Test - @MediumTest - public void testUserDisableRoaming() { - //step 1: setup two DataCalls one for Metered: default, another one for Non-metered: IMS - //step 2: set roaming disabled, data is enabled - //step 3: under roaming service - //step 4: only tear down metered data connections. - - //set Default and MMS to be metered in the CarrierConfigManager - boolean roamingEnabled = mDct.getDataRoamingEnabled(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForHandlerAction(mDct, 1000); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForHandlerAction(mDct, 1000); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - //user is in roaming - doReturn(true).when(mServiceState).getDataRoaming(); - logd("Sending DISABLE_ROAMING_CMD"); - mDct.setDataRoamingEnabledByUser(false); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_ROAMING_ON)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // expected tear down all metered DataConnections - verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - assertTrue(mDct.isAnyDataConnected()); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING)); - - // reset roaming settings / data enabled settings at end of this test - mDct.setDataRoamingEnabledByUser(roamingEnabled); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - @Test - @MediumTest - public void testDataCallOnUserDisableRoaming() { - //step 1: mock under roaming service and user disabled roaming from settings. - //step 2: user toggled data settings on - //step 3: only non-metered data call is established - - boolean roamingEnabled = mDct.getDataRoamingEnabled(); - doReturn(true).when(mServiceState).getDataRoaming(); - - //set Default and MMS to be metered in the CarrierConfigManager - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - logd("Sending DISABLE_ROAMING_CMD"); - mDct.setDataRoamingEnabledByUser(false); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN3, 2, 64, 0, 0); - - assertTrue(mDct.isAnyDataConnected()); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING)); - - // reset roaming settings / data enabled settings at end of this test - mDct.setDataRoamingEnabledByUser(roamingEnabled); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - // Test the default data switch scenario. - @FlakyTest /* flakes 1.57% of the time */ - @Test - @MediumTest - public void testDDSResetAutoAttach() throws Exception { - mContextFixture.putBooleanResource( - com.android.internal.R.bool.config_auto_attach_data_on_creation, true); - testDataSetup(); - assertTrue(mDct.shouldAutoAttach()); - mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - // The auto attach flag should be reset after update - assertFalse(mDct.shouldAutoAttach()); - } - - // Test for API carrierActionSetMeteredApnsEnabled. - @FlakyTest - @Ignore - @Test - @MediumTest - public void testCarrierActionSetMeteredApnsEnabled() { - //step 1: setup two DataCalls one for Internet and IMS - //step 2: set data is enabled - //step 3: cold sim is detected - //step 4: all data connection is torn down - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK); - assertTrue(mDct.isAnyDataConnected()); - - AsyncResult ar = new AsyncResult(null, - new Pair<>(false, DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER), null); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // Validate all metered data connections have been torn down - verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - assertTrue(mDct.isAnyDataConnected()); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - } - - private void initApns(String targetApn, String[] canHandleTypes) { - doReturn(targetApn).when(mApnContext).getApnType(); - doReturn(ApnSetting.getApnTypesBitmaskFromString(mApnContext.getApnType())) - .when(mApnContext).getApnTypeBitmask(); - doReturn(true).when(mApnContext).isConnectable(); - ApnSetting apnSetting = createApnSetting(ApnSetting.getApnTypesBitmaskFromString( - TextUtils.join(",", canHandleTypes))); - doReturn(apnSetting).when(mApnContext).getNextApnSetting(); - doReturn(apnSetting).when(mApnContext).getApnSetting(); - doReturn(mDataConnection).when(mApnContext).getDataConnection(); - doReturn(true).when(mApnContext).isEnabled(); - doReturn(true).when(mApnContext).isDependencyMet(); - doReturn(true).when(mApnContext).isReady(); - doReturn(false).when(mApnContext).hasRestrictedRequests(eq(true)); - } - - // Test the emergency APN setup. - @Test - @SmallTest - public void testTrySetupDataEmergencyApn() { - initApns(ApnSetting.TYPE_EMERGENCY_STRING, - new String[]{ApnSetting.TYPE_EMERGENCY_STRING}); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - waitForMs(200); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), - anyBoolean(), any(Message.class)); - } - - // Test the XCAP APN setup. - @Test - @SmallTest - public void testTrySetupDataXcapApn() { - initApns(ApnSetting.TYPE_XCAP_STRING, new String[]{ApnSetting.TYPE_XCAP_STRING}); - mDct.enableApn(ApnSetting.TYPE_XCAP, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), - anyBoolean(), any(Message.class)); - } - - // Test the ENTERPRISE APN setup. - @Test - public void testTrySetupDataEnterpriseApn() { - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName()); - assertEquals(null, tdCaptor.getValue().getOsAppId()); - - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - SetupDataCallResult result = createSetupDataCallResult(); - result.cid = 10; - mSimulatedCommands.setDataCallResult(true, result); - mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForMs(200); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - } - - // Test the ENTERPRISE APN setup when default data is not set up yet. - @Test - public void testTrySetupDataEnterpriseApnNoDefaultData() { - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - - // Check APN contexts with no DEFAULT set up - Map apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertEquals(DctConstants.State.IDLE, apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); - assertEquals(DctConstants.State.FAILED, - apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); - - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - waitForMs(200); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName()); - assertEquals(null, tdCaptor.getValue().getOsAppId()); - - // Check APN contexts after DEFAULT is set up (and ENTERPRISE failure) - apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertEquals(DctConstants.State.CONNECTED, - apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); - assertEquals(DctConstants.State.FAILED, - apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); - - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - SetupDataCallResult result = createSetupDataCallResult(); - result.cid = 10; - mSimulatedCommands.setDataCallResult(true, result); - mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - waitForMs(200); - - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - - // Check APN contexts after DEFAULT is set up (and ENTERPRISE reenabled) - apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertEquals(DctConstants.State.CONNECTED, - apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); - assertEquals(DctConstants.State.CONNECTED, - apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); - } - - // Test the ENTERPRISE APN setup when the same CID is returned. - @Test - public void testTrySetupDataEnterpriseApnDuplicateCid() { - mApnSettingContentProvider.setFakeApn1NetworkTypeBitmask( - NETWORK_TYPE_LTE_BITMASK | NETWORK_TYPE_NR_BITMASK); - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - // mSimulatedCommandsVerifier will return the same CID in SetupDataCallResult - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - waitForMs(200); - - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - List tds = tdCaptor.getAllValues(); - // [0] is default and [1] is enterprise, since default should be set up first - assertEquals(FAKE_APN1, tds.get(0).getDataNetworkName()); - assertEquals(null, tds.get(0).getOsAppId()); - assertEquals(null, tds.get(1).getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), tds.get(1).getOsAppId())); - - // Check APN contexts after DEFAULT and ENTERPRISE set up - Map apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertEquals(DctConstants.State.CONNECTED, - apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); - assertEquals(DctConstants.State.FAILED, - apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); - } - - @Test - @SmallTest - public void testGetDataConnectionState() { - initApns(ApnSetting.TYPE_SUPL_STRING, - new String[]{ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_DEFAULT_STRING}); - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_SUPL, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - // Assert that both APN_TYPE_SUPL & APN_TYPE_DEFAULT are connected even we only setup data - // for APN_TYPE_SUPL - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_SUPL_STRING)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - } - - // Test the unmetered APN setup when data is disabled. - @Test - @SmallTest - public void testTrySetupDataUnmeteredDataDisabled() { - initApns(ApnSetting.TYPE_SUPL_STRING, new String[]{ApnSetting.TYPE_SUPL_STRING}); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_FOTA_STRING}); - - mDct.enableApn(ApnSetting.TYPE_SUPL, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the unmetered default APN setup when data is disabled. Default APN should always honor - // the users's setting. - @Test - @SmallTest - public void testTrySetupDataUnmeteredDefaultDataDisabled() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_MMS_STRING}); - - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, never()).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - - // Test the metered APN setup when data is disabled. - @Test - @SmallTest - public void testTrySetupMeteredDataDisabled() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the restricted data request when data is disabled. - @Test - @SmallTest - public void testTrySetupRestrictedDataDisabled() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - sendInitializationEvents(); - - NetworkRequest nr = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .build(); - mDct.requestNetwork(nr, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the restricted data request when roaming is disabled. - @Test - @SmallTest - public void testTrySetupRestrictedRoamingDisabled() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - mDct.setDataRoamingEnabledByUser(false); - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - //user is in roaming - doReturn(true).when(mServiceState).getDataRoaming(); - - sendInitializationEvents(); - - NetworkRequest nr = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .build(); - mDct.requestNetwork(nr, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the default data when data is not connectable. - @Test - @SmallTest - public void testTrySetupNotConnectable() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - doReturn(false).when(mApnContext).isConnectable(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the default data on IWLAN. - @Test - @SmallTest - public void testTrySetupDefaultOnIWLAN() { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the default data when the phone is in ECBM. - @Test - @SmallTest - public void testTrySetupDefaultInECBM() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - doReturn(true).when(mPhone).isInEcm(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test update waiting apn list when on data rat change - @FlakyTest /* flakes 0.86% of the time */ - @Ignore - @Test - @SmallTest - public void testUpdateWaitingApnListOnDataRatChange() { - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier).setupDataCall( - eq(AccessNetworkType.CDMA2000), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK); - assertTrue(mDct.isAnyDataConnected()); - - //data rat change from ehrpd to lte - logd("Sending EVENT_DATA_RAT_CHANGED"); - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // Verify the disconnected data call due to rat change and retry manger schedule another - // data call setup - verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - verify(mAlarmManager, times(1)).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), - anyLong(), any(PendingIntent.class)); - - //Send event for reconnecting data - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RECONNECT, - mPhone.getPhoneId(), DcTracker.RELEASE_TYPE_NORMAL, mApnContext)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - assertTrue(mDct.isAnyDataConnected()); - } - - /** - * Test that fetchDunApns() returns list that prioritize the preferred APN when the preferred - * APN including DUN type. - */ - @Test - public void testFetchDunApnWithPreferredApn() { - // Set support APN types of FAKE_APN1 and FAKE_APN5 - mApnSettingContentProvider.setFakeApn1Types("default,dun"); - mApnSettingContentProvider.setFakeApn5Types("default,dun"); - - // Set prefer apn set id. - ContentResolver cr = mContext.getContentResolver(); - ContentValues values = new ContentValues(); - values.put(Telephony.Carriers.APN_SET_ID, 0); - cr.update(PREFERAPN_URI, values, null, null); - // Set FAKE_APN5 as the preferred APN. - mApnSettingContentProvider.setFakePreferredApn(mApnSettingContentProvider.getFakeApn5()); - - sendInitializationEvents(); - - // Return the APN list that set the preferred APN at the top. - ArrayList dunApns = mDct.fetchDunApns(); - assertEquals(2, dunApns.size()); - assertEquals(FAKE_APN5, dunApns.get(0).getApnName()); - assertEquals(FAKE_APN1, dunApns.get(1).getApnName()); - } - - // This tests simulates the race case where the sim status change event is triggered, the - // default data connection is attached, and then the carrier config gets changed which bumps - // the database id which we want to ignore when cleaning up connections and matching against - // the dun APN. Tests b/158908392. - @Test - @SmallTest - public void testCheckForCompatibleDataConnectionWithDunWhenIdsChange() { - //Set dun as a support apn type of FAKE_APN1 - mApnSettingContentProvider.setFakeApn1Types("default,supl,dun"); - - // Enable the default apn - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - //Load the sim and attach the data connection without firing the carrier changed event - final String logMsgPrefix = "testCheckForCompatibleDataConnectionWithDunWhenIdsChange: "; - sendSimStateUpdated(logMsgPrefix); - sendEventDataConnectionAttached(logMsgPrefix); - waitForMs(200); - - // Confirm that FAKE_APN1 comes up as a dun candidate - ApnSetting dunApn = mDct.fetchDunApns().get(0); - assertEquals(dunApn.getApnName(), FAKE_APN1); - Map apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - - //Double check that the default apn content is connected while the dun apn context is not - assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getState(), - DctConstants.State.CONNECTED); - assertNotEquals(apnContexts.get(ApnSetting.TYPE_DUN).getState(), - DctConstants.State.CONNECTED); - - - //Change the row ids the same way as what happens when we have old apn values in the - //carrier table - mApnSettingContentProvider.setRowIdOffset(100); - sendCarrierConfigChanged(logMsgPrefix); - waitForMs(200); - - mDct.enableApn(ApnSetting.TYPE_DUN, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - Map apnContextsAfterRowIdsChanged = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - - //Make sure that the data connection used earlier wasn't cleaned up and still in use. - assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), - apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DEFAULT).getDataConnection()); - - //Check that the DUN is using the same active data connection - assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), - apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DUN).getDataConnection()); - } - - @Test - @SmallTest - public void testCheckForCompatibleDataConnectionWithEnterprise() { - // Allow both DEFAULT and ENTERPRISE to use APN 1 - mApnSettingContentProvider.setFakeApn1NetworkTypeBitmask( - NETWORK_TYPE_LTE_BITMASK | NETWORK_TYPE_NR_BITMASK); - - // Enable the DEFAULT APN - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - sendInitializationEvents(); - - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName()); - assertEquals(null, tdCaptor.getValue().getOsAppId()); - - // Check APN contexts after DEFAULT is set up - Map apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getState(), - DctConstants.State.CONNECTED); - assertNotEquals(apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState(), - DctConstants.State.CONNECTED); - - // Enable the ENTERPRISE APN - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - SetupDataCallResult result = createSetupDataCallResult(); - result.cid = 10; - mSimulatedCommands.setDataCallResult(true, result); - mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForMs(200); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - - // Check APN contexts after ENTERPRISE is set up - Map apnContextsAfterRowIdsChanged = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - - // Make sure that the data connection used earlier wasn't cleaned up and still in use. - assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), - apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DEFAULT).getDataConnection()); - - // Check that ENTERPRISE isn't using the same data connection as DEFAULT - assertNotEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), - apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_ENTERPRISE).getDataConnection()); - } - - // Test for Data setup with APN Set ID - @Test - @SmallTest - public void testDataSetupWithApnSetId() throws Exception { - // Set the prefer apn set id to "1" - ContentResolver cr = mContext.getContentResolver(); - ContentValues values = new ContentValues(); - values.put(Telephony.Carriers.APN_SET_ID, 1); - cr.update(PREFERAPN_URI, values, null, null); - - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - - List dataProfiles = dpCaptor.getAllValues(); - assertEquals(2, dataProfiles.size()); - - // Verify to use FAKE APN7 which is Default APN with apnSetId=1(Same as the pereferred - // APN's set id). - Optional fakeApn7 = dataProfiles.stream() - .filter(dp -> dp.getApn().equals(FAKE_APN7)).findFirst(); - assertTrue(fakeApn7.isPresent()); - verifyDataProfile(fakeApn7.get(), FAKE_APN7, 0, 17, 1, NETWORK_TYPE_LTE_BITMASK); - - // Verify to use FAKE APN8 which is IMS APN with apnSetId=-1 - // (Telephony.Carriers.MATCH_ALL_APN_SET_ID). - Optional fakeApn8 = dataProfiles.stream() - .filter(dp -> dp.getApn().equals(FAKE_APN8)).findFirst(); - assertTrue(fakeApn8.isPresent()); - verifyDataProfile(fakeApn8.get(), FAKE_APN8, 2, 64, 1, NETWORK_TYPE_LTE_BITMASK); - } - - // Test oos - @Test - @SmallTest - public void testDataRatChangeOOS() { - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier).setupDataCall( - eq(AccessNetworkType.CDMA2000), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK); - assertTrue(mDct.isAnyDataConnected()); - - // Data rat change from ehrpd to unknown due to OOS - logd("Sending EVENT_DATA_RAT_CHANGED"); - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UNKNOWN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // Verify data connection is on - verify(mSimulatedCommandsVerifier, times(0)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - - // Data rat resume from unknown to ehrpd - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Verify the same data connection - assertEquals(FAKE_APN4, mDct.getActiveApnString(ApnSetting.TYPE_DEFAULT_STRING)); - assertTrue(mDct.isAnyDataConnected()); - } - - // Test provisioning - /*@Test - @SmallTest - public void testDataEnableInProvisioning() throws Exception { - ContentResolver resolver = mContext.getContentResolver(); - - assertEquals(1, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA)); - assertTrue(mDct.isDataEnabled()); - assertTrue(mDct.isUserDataEnabled()); - - mDct.setUserDataEnabled(false); - waitForMs(200); - - assertEquals(0, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA)); - assertFalse(mDct.isDataEnabled()); - assertFalse(mDct.isUserDataEnabled()); - - // Changing provisioned to 0. - Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null)); - waitForMs(200); - - assertTrue(mDct.isDataEnabled()); - assertTrue(mDct.isUserDataEnabled()); - - // Enable user data during provisioning. It should write to - // Settings.Global.MOBILE_DATA and keep data enabled when provisioned. - mDct.setUserDataEnabled(true); - Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 1); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null)); - waitForMs(200); - - assertTrue(mDct.isDataEnabled()); - assertTrue(mDct.isUserDataEnabled()); - assertEquals(1, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA)); - }*/ - - /* - @Test - @SmallTest - public void testNotifyDataEnabledChanged() throws Exception { - doAnswer(invocation -> { - mMessage = (Message) invocation.getArguments()[0]; - return true; - }).when(mHandler).sendMessageDelayed(any(), anyLong()); - - // Test registration. - mDct.registerForDataEnabledChanged(mHandler, DATA_ENABLED_CHANGED, null); - verifyDataEnabledChangedMessage(true, DataEnabledSettings.REASON_REGISTERED); - - // Disable user data. Should receive data enabled change to false. - mDct.setUserDataEnabled(false); - waitForMs(200); - verifyDataEnabledChangedMessage(false, DataEnabledSettings.REASON_USER_DATA_ENABLED); - - // Changing provisioned to 0. Shouldn't receive any message, as data enabled remains false. - ContentResolver resolver = mContext.getContentResolver(); - Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0); - Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, - 0); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null)); - waitForMs(200); - assertFalse(mDct.isDataEnabled()); - verify(mHandler, never()).sendMessageDelayed(any(), anyLong()); - - // Changing provisioningDataEnabled to 1. It should trigger data enabled change to true. - Settings.Global.putInt(resolver, - Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 1); - mDct.sendMessage(mDct.obtainMessage( - DctConstants.EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE, null)); - waitForMs(200); - verifyDataEnabledChangedMessage( - true, DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED); - }*/ - - @Test - @SmallTest - public void testNetworkStatusChangedRecoveryOFF() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.VALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.INVALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - waitForMs(200); - - // Verify that its no-op when the new data stall detection feature is disabled - verify(mSimulatedCommandsVerifier, times(0)).getDataCallList(any(Message.class)); - } - - @FlakyTest - @Test - @SmallTest - public void testNetworkStatusChangedRecoveryON() { - ContentResolver resolver = mContext.getContentResolver(); - Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); - Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 0); - doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.VALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.INVALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mSimulatedCommandsVerifier, times(1)).getDataCallList(any(Message.class)); - } - - @FlakyTest - @Test - @SmallTest - public void testRecoveryStepPDPReset() { - ContentResolver resolver = mContext.getContentResolver(); - Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); - Settings.Global.putLong(resolver, - Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); - Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 1); - doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED false"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.INVALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - waitForMs(200); - - // expected tear down all DataConnections - verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - } - - - @Test - @SmallTest - public void testRecoveryStepReRegister() { - ContentResolver resolver = mContext.getContentResolver(); - Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); - Settings.Global.putLong(resolver, - Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); - Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 2); - doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); - doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED false"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.INVALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // expected to get preferred network type - verify(mSST, times(1)).reRegisterNetwork(eq(null)); - } - - @Test - @SmallTest - public void testRecoveryStepRestartRadio() { - ContentResolver resolver = mContext.getContentResolver(); - Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); - Settings.Global.putLong(resolver, - Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); - Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 3); - doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); - doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED false"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.INVALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // expected to get preferred network type - verify(mSST, times(1)).powerOffRadioSafely(); - } - - private void verifyDataEnabledChangedMessage(boolean enabled, int reason) { - verify(mHandler, times(1)).sendMessageDelayed(any(), anyLong()); - Pair result = (Pair) ((AsyncResult) mMessage.obj).result; - assertEquals(DATA_ENABLED_CHANGED, mMessage.what); - assertEquals(enabled, result.first); - assertEquals(reason, (int) result.second); - clearInvocations(mHandler); - } - - private void setUpSubscriptionPlans(boolean isNrUnmetered) throws Exception { - List plans = new ArrayList<>(); - if (isNrUnmetered) { - plans.add(SubscriptionPlan.Builder - .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), - Period.ofMonths(1)) - .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED, - SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED) - .setNetworkTypes(new int[] {TelephonyManager.NETWORK_TYPE_NR}) - .build()); - } - plans.add(SubscriptionPlan.Builder - .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), - Period.ofMonths(1)) - .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) - .setDataUsage(500_000_000, System.currentTimeMillis()) - .build()); - replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, plans); - doReturn(plans.toArray(new SubscriptionPlan[0])).when(mNetworkPolicyManager) - .getSubscriptionPlans(anyInt(), any()); - } - - private void resetSubscriptionPlans() throws Exception { - replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, null); - } - - private void setUpSubscriptionOverride(int[] networkTypes, boolean isUnmetered) - throws Exception { - List networkTypesList = null; - if (networkTypes != null) { - networkTypesList = new ArrayList<>(); - for (int networkType : networkTypes) { - networkTypesList.add(networkType); - } - } - replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, networkTypesList); - replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, isUnmetered); - } - - private void resetSubscriptionOverride() throws Exception { - replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, null); - replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, false); - } - - private boolean isNetworkTypeUnmetered(int networkType) throws Exception { - Method method = DcTracker.class.getDeclaredMethod( - "isNetworkTypeUnmetered", int.class); - method.setAccessible(true); - return (boolean) method.invoke(mDct, networkType); - } - - private int setUpDataConnection() throws Exception { - Field dc = DcTracker.class.getDeclaredField("mDataConnections"); - dc.setAccessible(true); - Field uig = DcTracker.class.getDeclaredField("mUniqueIdGenerator"); - uig.setAccessible(true); - int id = ((AtomicInteger) uig.get(mDct)).getAndIncrement(); - ((HashMap) dc.get(mDct)).put(id, mDataConnection); - return id; - } - - private void resetDataConnection(int id) throws Exception { - Field dc = DcTracker.class.getDeclaredField("mDataConnections"); - dc.setAccessible(true); - ((HashMap) dc.get(mDct)).remove(id); - } - - private void setUpWatchdogTimer() { - // Watchdog active for 10s - mBundle.putLong(CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG, 10000); - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - private boolean getWatchdogStatus() throws Exception { - Field field = DcTracker.class.getDeclaredField(("mWatchdog")); - field.setAccessible(true); - return (boolean) field.get(mDct); - } - - private Map> getHandoverCompletionMessages() throws Exception { - Field field = DcTracker.class.getDeclaredField(("mHandoverCompletionMsgs")); - field.setAccessible(true); - return (Map>) field.get(mDct); - } - - private void setUpTempNotMetered() { - doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR) - .when(mPhone).getRadioAccessFamily(); - doReturn(1).when(mPhone).getSubId(); - mBundle.putBoolean(CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, true); - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - @Test - public void testIsNetworkTypeUnmetered() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - - // only 5G unmetered - setUpSubscriptionOverride(new int[]{TelephonyManager.NETWORK_TYPE_NR}, true); - - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - // all network types metered - setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), false); - - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - // all network types unmetered - setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), true); - - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - resetSubscriptionOverride(); - } - - @Test - public void testIsNetworkTypeUnmeteredViaSubscriptionPlans() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - - // only 5G unmetered - setUpSubscriptionPlans(true); - - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - // all network types metered - setUpSubscriptionPlans(false); - - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - // all network types unmetered - List plans = new ArrayList<>(); - plans.add(SubscriptionPlan.Builder - .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), - Period.ofMonths(1)) - .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED, - SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED) - .build()); - replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, plans); - - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - resetSubscriptionPlans(); - } - - @Test - public void testIsNrUnmeteredSubscriptionPlans() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - int id = setUpDataConnection(); - setUpSubscriptionPlans(false); - setUpWatchdogTimer(); - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - setUpTempNotMetered(); - clearInvocations(mDataConnection); - - // NetCapability should be metered when connected to 5G with no unmetered plan or frequency - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(false); - - // Set SubscriptionPlans unmetered - setUpSubscriptionPlans(true); - - // NetCapability should switch to unmetered with an unmetered plan - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(true); - - // Set MMWAVE frequency to unmetered - mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, true); - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - clearInvocations(mDataConnection); - - // NetCapability should switch to metered without fr=MMWAVE - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(false); - - // NetCapability should switch to unmetered with fr=MMWAVE - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(true); - - resetDataConnection(id); - resetSubscriptionPlans(); - } - - @Test - public void testIsNrUnmeteredCarrierConfigs() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - int id = setUpDataConnection(); - setUpSubscriptionPlans(false); - setUpWatchdogTimer(); - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - setUpTempNotMetered(); - clearInvocations(mDataConnection); - - // NetCapability should be metered when connected to 5G with no unmetered plan or frequency - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(false); - - // Set MMWAVE frequency to unmetered - mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_BOOL, true); - mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, true); - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - clearInvocations(mDataConnection); - - // NetCapability should switch to unmetered when fr=MMWAVE and MMWAVE unmetered - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(true); - - // NetCapability should switch to metered when fr=SUB6 and MMWAVE unmetered - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(false); - - // Set SUB6 frequency to unmetered - doReturn(2).when(mPhone).getSubId(); - mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false); - mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_SUB6_BOOL, true); - intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - clearInvocations(mDataConnection); - - // NetCapability should switch to unmetered when fr=SUB6 and SUB6 unmetered - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mDataConnection, times(1)).onMeterednessChanged(true); - - resetDataConnection(id); - resetSubscriptionPlans(); - } - - @Test - public void testReevaluateUnmeteredConnectionsOnNetworkChange() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - int id = setUpDataConnection(); - setUpSubscriptionPlans(true); - setUpWatchdogTimer(); - setUpTempNotMetered(); - clearInvocations(mDataConnection); - - // NetCapability should be unmetered when connected to 5G - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(true); - - // NetCapability should be metered when disconnected from 5G - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mDataConnection, times(1)).onMeterednessChanged(false); - - resetDataConnection(id); - resetSubscriptionPlans(); - } - - @Test - public void testReevaluateUnmeteredConnectionsOnWatchdog() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - int id = setUpDataConnection(); - setUpSubscriptionPlans(true); - setUpWatchdogTimer(); - - // Watchdog inactive when unmetered and not connected to 5G - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NR_TIMER_WATCHDOG)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - assertFalse(getWatchdogStatus()); - - // Watchdog active when unmetered and connected to 5G - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - assertTrue(getWatchdogStatus()); - - // Watchdog inactive when metered - setUpSubscriptionPlans(false); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - assertFalse(getWatchdogStatus()); - - resetDataConnection(id); - resetSubscriptionPlans(); - } - - /** - * Test if this is a path prefix match against the given Uri. Verifies that - * scheme, authority, and atomic path segments match. - * - * Copied from frameworks/base/core/java/android/net/Uri.java - */ - private boolean isPathPrefixMatch(Uri uriA, Uri uriB) { - if (!Objects.equals(uriA.getScheme(), uriB.getScheme())) return false; - if (!Objects.equals(uriA.getAuthority(), uriB.getAuthority())) return false; - - List segA = uriA.getPathSegments(); - List segB = uriB.getPathSegments(); - - final int size = segB.size(); - if (segA.size() < size) return false; - - for (int i = 0; i < size; i++) { - if (!Objects.equals(segA.get(i), segB.get(i))) { - return false; - } - } - - return true; - } - - @Test - public void testNoApnContextsWhenDataIsDisabled() throws java.lang.InterruptedException { - //Check that apn contexts are loaded. - assertTrue(mDct.getApnContexts().size() > 0); - - //Do work normally done in teardown. - mDct.removeCallbacksAndMessages(null); - mDcTrackerTestHandler.quit(); - mDcTrackerTestHandler.join(); - - //Set isDataCapable to false for the new DcTracker being created in DcTrackerTestHandler. - doReturn(false).when(mTelephonyManager).isDataCapable(); - mDcTrackerTestHandler = new DcTrackerTestHandler(getClass().getSimpleName()); - setReady(false); - - mDcTrackerTestHandler.start(); - waitUntilReady(); - assertEquals(0, mDct.getApnContexts().size()); - - //No need to clean up handler because that work is done in teardown. - } - - @Test - public void testRatChanged() throws Exception { - DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); - boolean allowed = mDct.isDataAllowed(dataConnectionReasons); - assertFalse(dataConnectionReasons.toString(), allowed); - - logd("Sending EVENT_ENABLE_APN"); - // APN id 0 is APN_TYPE_DEFAULT - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - dataConnectionReasons = new DataConnectionReasons(); - allowed = mDct.isDataAllowed(dataConnectionReasons); - assertTrue(dataConnectionReasons.toString(), allowed); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - verifyDataConnected(FAKE_APN1); - - doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS).when(mServiceState) - .getRilDataRadioTechnology(); - - logd("Sending EVENT_DATA_RAT_CHANGED"); - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // expected tear down all metered DataConnections - verify(mSimulatedCommandsVerifier).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - } - - @Test - public void testApnConfigRepositoryUpdatedOnCarrierConfigChange() { - assertPriority(ApnSetting.TYPE_CBS_STRING, 2); - assertPriority(ApnSetting.TYPE_MMS_STRING, 2); - - mBundle.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, - new String[] { - ApnSetting.TYPE_CBS_STRING + ":11", - ApnSetting.TYPE_MMS_STRING + ":19", - }); - - sendInitializationEvents(); - - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - assertPriority(ApnSetting.TYPE_CBS_STRING, 11); - assertPriority(ApnSetting.TYPE_MMS_STRING, 19); - - //Ensure apns are in sorted order. - ApnContext lastApnContext = null; - for (ApnContext apnContext : mDct.getApnContexts()) { - if (lastApnContext != null) { - assertTrue(apnContext.getPriority() <= lastApnContext.getPriority()); - } - lastApnContext = apnContext; - } - } - - private void assertPriority(String type, int priority) { - assertEquals(priority, mDct.getApnContexts().stream() - .filter(x -> x.getApnType().equals(type)) - .findFirst().get().getPriority()); - } - - @Test - public void testProvisionBroadcastReceiver() { - Intent intent = new Intent("com.android.internal.telephony.PROVISION"); - intent.putExtra("provision.phone.id", mPhone.getPhoneId()); - try { - mContext.sendBroadcast(intent); - } catch (SecurityException e) { - fail(); - } - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - @Test - public void testRetryHandoverWhenDisconnecting() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - setUpDataConnection(); - SparseArray apnContextsByType = Mockito.mock(SparseArray.class); - ConcurrentHashMap apnContexts = Mockito.mock(ConcurrentHashMap.class); - doReturn(mApnContext).when(apnContextsByType).get(eq(ApnSetting.TYPE_IMS)); - doReturn(mApnContext).when(apnContexts).get(eq(ApnSetting.TYPE_IMS_STRING)); - doReturn(false).when(mApnContext).isConnectable(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - doReturn(DctConstants.State.DISCONNECTING).when(mApnContext).getState(); - replaceInstance(DcTracker.class, "mApnContextsByType", mDct, apnContextsByType); - replaceInstance(DcTracker.class, "mApnContexts", mDct, apnContexts); - - sendInitializationEvents(); - - logd("Sending EVENT_ENABLE_APN"); - // APN id 0 is APN_TYPE_DEFAULT - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER, - mDct.obtainMessage(12345)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - assertTrue(isHandoverPending(ApnSetting.TYPE_IMS)); - - // Verify no handover request was sent - verify(mDataConnection, never()).bringUp(any(ApnContext.class), anyInt(), anyInt(), - any(Message.class), anyInt(), anyInt(), anyInt(), anyBoolean()); - - doReturn(DctConstants.State.RETRYING).when(mApnContext).getState(); - // Data now is disconnected - doReturn(true).when(mApnContext).isConnectable(); - doReturn(true).when(mDataEnabledSettings).isDataEnabled(anyInt()); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, - new AsyncResult(Pair.create(mApnContext, 0), null, null))); - - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - verify(mDataConnection).bringUp(any(ApnContext.class), anyInt(), anyInt(), - any(Message.class), anyInt(), eq(DcTracker.REQUEST_TYPE_HANDOVER), anyInt(), - anyBoolean()); - } - - @Test - public void testDataUnthrottled() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_APN_UNTHROTTLED, - new AsyncResult(null, FAKE_APN3, null))); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - verify(mDataThrottler).setRetryTime( - eq(ApnSetting.TYPE_IMS), - eq(RetryManager.NO_SUGGESTED_RETRY_DELAY), - eq(DcTracker.REQUEST_TYPE_NORMAL)); - } - - @Test - public void testDataUnthrottledAfterAPNChanged() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); - - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_APN_CHANGED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Verify unthrottling - verify(mDataThrottler, times(2)).reset(); - } - - @Test - public void testDataUnthrottledOnSimStateChanged() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); - - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - sendSimStateUpdated("testDataUnthrottledOnSimStateChanged"); - - // Verify unthrottling - verify(mDataThrottler, times(2)).reset(); - } - - @Test - public void testHandlingSecondHandoverRequest() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - setUpDataConnection(); - SparseArray apnContextsByType = Mockito.mock(SparseArray.class); - ConcurrentHashMap apnContexts = Mockito.mock(ConcurrentHashMap.class); - doReturn(mApnContext).when(apnContextsByType).get(eq(ApnSetting.TYPE_IMS)); - doReturn(mApnContext).when(apnContexts).get(eq(ApnSetting.TYPE_IMS_STRING)); - doReturn(false).when(mApnContext).isConnectable(); - doReturn(DctConstants.State.CONNECTING).when(mApnContext).getState(); - replaceInstance(DcTracker.class, "mApnContextsByType", mDct, apnContextsByType); - replaceInstance(DcTracker.class, "mApnContexts", mDct, apnContexts); - - sendInitializationEvents(); - - logd("Sending EVENT_ENABLE_APN"); - // APN id 0 is APN_TYPE_DEFAULT - Message msg = mDct.obtainMessage(12345); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER, msg); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - Map> msgs = getHandoverCompletionMessages(); - // Make sure the messages was queued properly instead of fired right away. - assertTrue(msgs.get(ApnSetting.TYPE_IMS).contains(msg)); - } - - @Test - public void testDataThrottledNotAllowData() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); - doReturn(SystemClock.elapsedRealtime() + 100000).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_IMS); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - - DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); - boolean allowed = mDct.isDataAllowed(mApnContext, DcTracker.REQUEST_TYPE_NORMAL, - dataConnectionReasons); - assertFalse(dataConnectionReasons.toString(), allowed); - assertTrue(dataConnectionReasons.contains(DataDisallowedReasonType.DATA_THROTTLED)); - - // Makre sure no data setup request - verify(mSimulatedCommandsVerifier, never()).setupDataCall( - anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - @Test - public void testNotifyDataDisconnected() { - // Verify notify data disconnected on DCT constructor, initialized in setUp() - ArgumentCaptor captor = - ArgumentCaptor.forClass(PreciseDataConnectionState.class); - verify(mPhone, times(13)).notifyDataConnection(captor.capture()); - for (PreciseDataConnectionState state : captor.getAllValues()) { - assertEquals(TelephonyManager.DATA_DISCONNECTED, state.getState()); - } - } - - /** - * There is a corresponding test {@link DataConnectionTest#testDataServiceTempUnavailable()} to - * test DataConnection behavior. - */ - @Test - public void testDataServiceTempUnavailable() { - Handler handler = Mockito.mock(Handler.class); - Message handoverCompleteMessage = Message.obtain(handler); - addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS); - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_SETUP_COMPLETE, - DcTracker.REQUEST_TYPE_HANDOVER, DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, - new AsyncResult(Pair.create(mApnContext, 0), - DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE, new Exception()))); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - // Ensure handover is not completed yet - verify(handler, never()).sendMessageDelayed(any(), anyLong()); - } - - @Test - public void testNormalRequestDoesNotFailHandoverRequest() { - Handler handler = Mockito.mock(Handler.class); - Message handoverCompleteMessage = Message.obtain(handler); - addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS); - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - // Ensure handover is not completed yet - verify(handler, never()).sendMessageDelayed(any(), anyLong()); - } - - @Test - public void testPreferenceChangedFallback() { - Handler handler = Mockito.mock(Handler.class); - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) - .getPreferredTransport(anyInt()); - Message handoverCompleteMessage = Message.obtain(handler); - addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS); - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER, - handoverCompleteMessage); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - Bundle bundle = handoverCompleteMessage.getData(); - assertTrue(bundle.getBoolean("extra_handover_failure_fallback")); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java deleted file mode 100644 index 4acfefb2a9..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java +++ /dev/null @@ -1,996 +0,0 @@ -/** - * Copyright (C) 2015 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.dataconnection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; - -import android.os.PersistableBundle; -import android.os.SystemClock; -import android.telephony.CarrierConfigManager; -import android.telephony.data.ApnSetting; -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.SubscriptionController; -import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.uicc.UiccController; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; - -/** - * APN retry manager tests - */ -public class RetryManagerTest extends TelephonyTest { - - // This is the real APN data for the Japanese carrier NTT Docomo. - private final ApnSetting mApn1 = new ApnSetting.Builder() - .setId(2163) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private final ApnSetting mApn2 = new ApnSetting.Builder() - .setId(2164) - .setOperatorNumeric("44010") - .setEntryName("mopera U") - .setApnName("mopera.net") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private final ApnSetting mApn3 = new ApnSetting.Builder() - .setId(2165) - .setOperatorNumeric("44010") - .setEntryName("b-mobile for Nexus") - .setApnName("bmobile.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private PersistableBundle mBundle; - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - mBundle = mContextFixture.getCarrierConfigBundle(); - doReturn(false).when(mPhone).isUsingNewDataStack(); - replaceInstance(SubscriptionController.class, "sInstance", null, mSubscriptionController); - replaceInstance(UiccController.class, "mInstance", null, mUiccController); - } - - @After - public void tearDown() throws Exception { - mBundle = null; - super.tearDown(); - } - - /** - * Test the behavior of a retry manager with no waiting APNs set. - */ - @Test - @SmallTest - public void testRetryManagerEmpty() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:2000"}); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - - long delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the basic retry scenario where only one APN and no retry configured. - */ - @Test - @SmallTest - public void testRetryManagerOneApnNoRetry() throws Exception { - - mBundle.putStringArray( - CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the basic retry scenario where only one APN with two retries configured. - */ - @Test - @SmallTest - public void testRetryManagerOneApnTwoRetries() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"supl:2000,3000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_SUPL); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(3000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - // No matter how many times we call getNextApnSetting, it should always return the next APN - // with NO_RETRY because we've already reached the maximum retry count. - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the basic retry scenario where two waiting APNs with one retry configured. - */ - @Test - @SmallTest - public void testRetryManagerTwoApnsOneRetry() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"others:2000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the basic retry scenario where two waiting APNs with two retries configured. - */ - @Test - @SmallTest - public void testRetryManagerTwoApnsTwoRetries() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"dun:2000,5000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DUN); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(5000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the basic retry scenario where two mms APNs with two retries configured. - */ - @Test - @SmallTest - public void testRetryManagerTwoMmsApnsTwoRetries() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"mms: 3000,6000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_MMS); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(3000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(6000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the permanent fail scenario with one APN configured. - */ - @Test - @SmallTest - public void testRetryManagerApnPermanentFailed() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"fota:1000,4000,7000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting apn = ApnSetting.makeApnSetting(mApn1); - waitingApns.add(apn); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_FOTA); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - - rm.markApnPermanentFailed(apn); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - } - - /** - * Test the permanent fail scenario with two APNs configured. - */ - @Test - @SmallTest - public void testRetryManagerApnPermanentFailedWithTwoApns() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"mms : 1000,4000,7000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_MMS); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - rm.markApnPermanentFailed(myApn1); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(7000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the permanent fail scenario with three APNs configured. - */ - @Test - @SmallTest - public void testRetryManagerApnPermanentFailedWithThreeApns() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:2000:2000,3000:3000", "ims:1000,4000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - ApnSetting myApn3 = ApnSetting.makeApnSetting(mApn3); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - waitingApns.add(myApn3); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_IMS); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - rm.markApnPermanentFailed(myApn2); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the permanent fail scenario with two APN all failed - */ - @Test - @SmallTest - public void testRetryManagerApnPermanentFailedAll() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:1000,4000,7000,9000", "mms:1234,4123"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - rm.markApnPermanentFailed(myApn1); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(7000, delay); - - rm.markApnPermanentFailed(myApn2); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - } - - /** - * Test the randomized delay scenario. - */ - @Test - @SmallTest - public void testRetryManagerDelayWithRandomization() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:default_randomization=1000,3000:2000,6000:3000,10000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertTrue(delay >= 3000 && delay < 5000); // 3s + 2s rand - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertTrue(delay >= 6000 && delay < 9000); // 6s + 3s rand - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertTrue(delay >= 10000 && delay < 11000); // 10s + 1s default rand - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the retry forever scenario - */ - @Test - @SmallTest - public void testRetryManagerRetryForever() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:max_retries=infinite,1000,2000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - } - - /** - * Test the explicit max retry scenario. - */ - @Test - @SmallTest - public void testRetryManagerExplicitMaxRetry() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"hipri: max_retries=4,1000,2000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_HIPRI); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the fail fast scenario. - */ - @Test - @SmallTest - public void testRetryManagerFailFast() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:1000,5000"}); - - mBundle.putLong(CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 2000); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(true); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(true); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(true); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(true); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(true); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the permanent fail scenario with two APN all failed and then reset - */ - @Test - @SmallTest - public void testRetryManagerApnPermanentFailedAllAndThenReset() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"dun:1000,4000,7000,9000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DUN); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - rm.markApnPermanentFailed(myApn1); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(7000, delay); - - rm.markApnPermanentFailed(myApn2); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - - // reset the retry manager - - ApnSetting myApn3 = ApnSetting.makeApnSetting(mApn3); - waitingApns.clear(); - waitingApns.add(myApn3); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"dun:3000,8000"}); - - rm.setWaitingApns(waitingApns); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(3000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(8000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - private void assertRange(long low, long high, long value) { - if (value >= low && value <= high) return; - fail("Not in range[" + low + "," + high + "], value=" + value); - } - - /** - * Test the scenario where modem suggests retry the current APN once - */ - @Test - @SmallTest - public void testRetryManagerModemSuggestedRetryOnce() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"others:1000,4000,7000,9000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_MMS); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - // Network suggests retrying the current APN - doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_MMS); - delay = rm.getDelayForNextApn(false); - assertRange(2450, 2500, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - doReturn(RetryManager.NO_SUGGESTED_RETRY_DELAY).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_MMS); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - // Modem suggests retrying the current APN - //rm.setModemSuggestedDelay(30000); - doReturn(30000 + SystemClock.elapsedRealtime()).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_MMS); - delay = rm.getDelayForNextApn(false); - assertRange(29950, 30000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - doReturn(RetryManager.NO_SUGGESTED_RETRY_DELAY).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_MMS); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - } - - /** - * Test the scenario where modem suggests not retrying - */ - @Test - @SmallTest - public void testRetryManagerModemSuggestedNoRetry() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:1000,4000,7000,9000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - // Modem suggests retrying the current APN - doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_DEFAULT); - delay = rm.getDelayForNextApn(false); - assertRange(2450, 2500, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - doReturn(RetryManager.NO_RETRY).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_DEFAULT); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the scenario that network suggests the same retry for too many times - */ - @Test - @SmallTest - public void testRetryNetworkSuggestedRetryTooManyTimes() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"mms:2000,3000", "default:1000,4000,7000,9000"}); - - int maxRetryCount = 10; - - mBundle.putInt(CarrierConfigManager - .KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, - maxRetryCount); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - for (int i = 0; i < maxRetryCount; i++) { - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_DEFAULT); - delay = rm.getDelayForNextApn(false); - assertRange(2450, 2500, delay); - } - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_DEFAULT); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - doReturn(RetryManager.NO_SUGGESTED_RETRY_DELAY).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_DEFAULT); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken deleted file mode 100644 index 2e9b88cbd6..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken +++ /dev/null @@ -1,1935 +0,0 @@ -/* - * Copyright (C) 2007 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 GSMTestHandler.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.gsm; - -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.telephony.ServiceState; -import android.test.AndroidTestCase; -import android.test.PerformanceTestCase; - -import android.telephony.DisconnectCause; - -import com.android.internal.telephony.Call; -import com.android.internal.telephony.CallStateException; -import com.android.internal.telephony.Connection; -import com.android.internal.telephony.MmiCode; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.gsm.CallFailCause; -import com.android.internal.telephony.gsm.GSMPhone; -import com.android.internal.telephony.gsm.GSMTestHandler; -import com.android.internal.telephony.gsm.GsmMmiCode; -import com.android.internal.telephony.gsm.SuppServiceNotification; -import com.android.internal.telephony.test.SimulatedRadioControl; - -import java.util.List; - - -public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase { - private SimulatedRadioControl mRadioControl; - private GSMPhone mGSMPhone; - private GSMTestHandler mGSMTestHandler; - private Handler mHandler; - - private static final int EVENT_PHONE_STATE_CHANGED = 1; - private static final int EVENT_DISCONNECT = 2; - private static final int EVENT_RINGING = 3; - private static final int EVENT_CHANNEL_OPENED = 4; - private static final int EVENT_POST_DIAL = 5; - private static final int EVENT_DONE = 6; - private static final int EVENT_SSN = 7; - private static final int EVENT_MMI_INITIATE = 8; - private static final int EVENT_MMI_COMPLETE = 9; - private static final int EVENT_IN_SERVICE = 10; - private static final int SUPP_SERVICE_FAILED = 11; - private static final int SERVICE_STATE_CHANGED = 12; - private static final int EVENT_OEM_RIL_MESSAGE = 13; - public static final int ANY_MESSAGE = -1; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mGSMTestHandler = new GSMTestHandler(mContext); - - mGSMTestHandler.start(); - synchronized (mGSMTestHandler) { - do { - mGSMTestHandler.wait(); - } while (mGSMTestHandler.getGSMPhone() == null); - } - - mGSMPhone = mGSMTestHandler.getGSMPhone(); - mRadioControl = mGSMTestHandler.getSimulatedCommands(); - - mHandler = mGSMTestHandler.getHandler(); - mGSMPhone.registerForPreciseCallStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null); - mGSMPhone.registerForNewRingingConnection(mHandler, EVENT_RINGING, null); - mGSMPhone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null); - - mGSMPhone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL, null); - - mGSMPhone.registerForSuppServiceNotification(mHandler, EVENT_SSN, null); - mGSMPhone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null); - mGSMPhone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null); - mGSMPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null); - - mGSMPhone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null); - - // wait until we get phone in both voice and data service - Message msg; - ServiceState state; - - do { - msg = mGSMTestHandler.waitForMessage(SERVICE_STATE_CHANGED); - assertNotNull("Message Time Out", msg); - state = (ServiceState) ((AsyncResult) msg.obj).result; - } while (state.getState() != ServiceState.STATE_IN_SERVICE); - } - - @Override - protected void tearDown() throws Exception { - mRadioControl.shutdown(); - - mGSMPhone.unregisterForPreciseCallStateChanged(mHandler); - mGSMPhone.unregisterForNewRingingConnection(mHandler); - mGSMPhone.unregisterForDisconnect(mHandler); - mGSMPhone.setOnPostDialCharacter(mHandler, 0, null); - mGSMPhone.unregisterForSuppServiceNotification(mHandler); - mGSMPhone.unregisterForMmiInitiate(mHandler); - mGSMPhone.unregisterForMmiComplete(mHandler); - - mGSMPhone = null; - mRadioControl = null; - mHandler = null; - mGSMTestHandler.cleanup(); - - super.tearDown(); - } - - // These test can only be run once. - public int startPerformance(Intermediates intermediates) { - return 1; - } - - public boolean isPerformanceOnly() { - return false; - } - - - //This test is causing the emulator screen to turn off. I don't understand - //why, but I'm removing it until we can figure it out. - public void brokenTestGeneral() throws Exception { - Connection cn; - Message msg; - AsyncResult ar; - - // IDLE state - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - assertFalse(mGSMPhone.canConference()); - - // One DIALING connection - - mRadioControl.setAutoProgressConnectingCall(false); - - mGSMPhone.dial("+13125551212"); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - - msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertEquals(Call.State.DIALING, mGSMPhone.getForegroundCall().getState()); - assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - /*do { - mGSMTestHandler.waitForMessage(ANY_MESSAGE); - } while (mGSMPhone.getForegroundCall().getConnections().size() == 0);*/ - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DIALING, - mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - cn = mGSMPhone.getForegroundCall().getConnections().get(0); - assertTrue(!cn.isIncoming()); - assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); - - assertEquals(DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); - - assertFalse(mGSMPhone.canConference()); - - // One ALERTING connection - - mRadioControl.progressConnectingCallState(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } - while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ALERTING, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - cn = mGSMPhone.getForegroundCall().getConnections().get(0); - assertTrue(!cn.isIncoming()); - assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); - assertFalse(mGSMPhone.canConference()); - - // One ACTIVE connection - - mRadioControl.progressConnectingCallState(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); - - cn = mGSMPhone.getForegroundCall().getConnections().get(0); - assertTrue(!cn.isIncoming()); - assertEquals(Connection.PostDialState.COMPLETE, cn.getPostDialState()); - assertFalse(mGSMPhone.canConference()); - - // One disconnected connection - mGSMPhone.getForegroundCall().hangup(); - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); - - assertFalse(mGSMPhone.canConference()); - - cn = mGSMPhone.getForegroundCall().getEarliestConnection(); - - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - // Back to idle state - - mGSMPhone.clearDisconnected(); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - assertFalse(mGSMPhone.canConference()); - - // cn left over from before phone.clearDisconnected(); - - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - // One ringing (INCOMING) call - - mRadioControl.triggerRing("18005551212"); - - msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - ar = (AsyncResult) msg.obj; - cn = (Connection) ar.result; - assertTrue(cn.isRinging()); - assertEquals(mGSMPhone.getRingingCall(), cn.getCall()); - - assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - cn = mGSMPhone.getRingingCall().getConnections().get(0); - assertTrue(cn.isIncoming()); - assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); - - assertFalse(mGSMPhone.canConference()); - - // One mobile terminated active call - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getConnections().size() == 1); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, - mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); - - cn = mGSMPhone.getForegroundCall().getConnections().get(0); - assertTrue(cn.isIncoming()); - assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); - - assertFalse(mGSMPhone.canConference()); - - // One disconnected (local hangup) call - - try { - Connection conn; - conn = mGSMPhone.getForegroundCall().getConnections().get(0); - conn.hangup(); - } catch (CallStateException ex) { - ex.printStackTrace(); - fail("unexpected ex"); - } - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, - mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); - - cn = mGSMPhone.getForegroundCall().getEarliestConnection(); - - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); - - assertFalse(mGSMPhone.canConference()); - - // Back to idle state - - mGSMPhone.clearDisconnected(); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - assertFalse(mGSMPhone.canConference()); - - // cn left over from before phone.clearDisconnected(); - - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - // One ringing call - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - assertFalse(mGSMPhone.canConference()); - - // One rejected call - mGSMPhone.rejectCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - cn = mGSMPhone.getRingingCall().getEarliestConnection(); - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); - - assertFalse(mGSMPhone.canConference()); - - // Back to idle state - - mGSMPhone.clearDisconnected(); - - assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - assertFalse(mGSMPhone.canConference()); - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - // One ringing call - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - cn = mGSMPhone.getRingingCall().getEarliestConnection(); - - // Ringing call disconnects - - mRadioControl.triggerHangupForeground(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); - - assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); - - // One Ringing Call - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); - - - cn = mGSMPhone.getRingingCall().getEarliestConnection(); - - // One answered call - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // one holding call - mGSMPhone.switchHoldingAndActive(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); - - - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // one active call - mGSMPhone.switchHoldingAndActive(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } - while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // One disconnected call in the foreground slot - - mRadioControl.triggerHangupAll(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(DisconnectCause.NORMAL, cn.getDisconnectCause()); - - // Test missed calls - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); - - mGSMPhone.rejectCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (msg.what != EVENT_DISCONNECT); - - ar = (AsyncResult) msg.obj; - cn = (Connection) ar.result; - - assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); - - // Test incoming not missed calls - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); - - cn = mGSMPhone.getRingingCall().getEarliestConnection(); - - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - assertEquals(DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - - try { - mGSMPhone.getForegroundCall().hangup(); - } catch (CallStateException ex) { - ex.printStackTrace(); - fail("unexpected ex"); - } - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() - != Call.State.DISCONNECTED); - - assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); - - // - // Test held and hangup held calls - // - - // One ALERTING call - mGSMPhone.dial("+13125551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - mRadioControl.progressConnectingCallState(); - mRadioControl.progressConnectingCallState(); - - // One ACTIVE call - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - // One ACTIVE call, one ringing call - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - // One HOLDING call, one ACTIVE call - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertTrue(mGSMPhone.canConference()); - - // Conference the two - mGSMPhone.conference(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertTrue(mGSMPhone.getForegroundCall().isMultiparty()); - assertFalse(mGSMPhone.canConference()); - - // Hold the multiparty call - mGSMPhone.switchHoldingAndActive(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } - while (mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); - assertFalse(mGSMPhone.canConference()); - - // Multiparty call on hold, call waiting added - - mRadioControl.triggerRing("18005558355"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertFalse(mGSMPhone.canConference()); - - // Hangup conference call, ringing call still around - mGSMPhone.getBackgroundCall().hangup(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.DISCONNECTED); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - // Reject waiting call - mGSMPhone.rejectCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - } - - public void testOutgoingCallFailImmediately() throws Exception { - Message msg; - - // Test outgoing call fail-immediately edge case - // This happens when a call terminated before ever appearing in a - // call list - // This should land the immediately-failing call in the - // ForegroundCall list as an IDLE call - mRadioControl.setNextDialFailImmediately(true); - - Connection cn = mGSMPhone.dial("+13125551212"); - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(DisconnectCause.NORMAL, cn.getDisconnectCause()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - } - - public void testHangupOnOutgoing() throws Exception { - Connection cn; - Message msg; - - mRadioControl.setAutoProgressConnectingCall(false); - - // Test 1: local hangup in "DIALING" state - mGSMPhone.dial("+13125551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } - while (mGSMPhone.getForegroundCall().getState() != Call.State.DIALING); - - cn = mGSMPhone.getForegroundCall().getEarliestConnection(); - - mGSMPhone.getForegroundCall().hangup(); - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); - - // Test 2: local hangup in "ALERTING" state - mGSMPhone.dial("+13125551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - mRadioControl.progressConnectingCallState(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } - while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); - - cn = mGSMPhone.getForegroundCall().getEarliestConnection(); - - mGSMPhone.getForegroundCall().hangup(); - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); - - // Test 3: local immediate hangup before GSM index is - // assigned (CallTracker.hangupPendingMO case) - - mRadioControl.pauseResponses(); - - cn = mGSMPhone.dial("+13125551212"); - - cn.hangup(); - - mRadioControl.resumeResponses(); - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - - assertEquals(DisconnectCause.LOCAL, - mGSMPhone.getForegroundCall().getEarliestConnection().getDisconnectCause()); - } - - public void testHangupOnChannelClose() throws Exception { - mGSMPhone.dial("+13125551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getConnections().isEmpty()); - - mRadioControl.shutdown(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - mGSMPhone.clearDisconnected(); - } while (!mGSMPhone.getForegroundCall().getConnections().isEmpty()); - } - - public void testIncallMmiCallDeflection() throws Exception { - Message msg; - - // establish an active call - mGSMPhone.dial("+13125551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // establish a ringing (WAITING) call - - mRadioControl.triggerRing("18005551212"); - - msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering 0 followed by SEND: release all held calls - // or sets UDUB for a waiting call. - mGSMPhone.handleInCallMmiCommands("0"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // change the active call to holding call - mGSMPhone.switchHoldingAndActive(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); - - - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering 0 followed by SEND: release all held calls - // or sets UDUB for a waiting call. - mGSMPhone.handleInCallMmiCommands("0"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); - } - - public void testIncallMmiCallWaiting() throws Exception { - Message msg; - - // establish an active call - mGSMPhone.dial("+13125551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // establish a ringing (WAITING) call - - mRadioControl.triggerRing("18005551212"); - - do { - msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); - assertNotNull("Message Time Out", msg); - } while (msg.what != EVENT_RINGING); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering 1 followed by SEND: release all active calls - // (if any exist) and accepts the other (held or waiting) call. - - mGSMPhone.handleInCallMmiCommands("1"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - - // change the active call to holding call - mGSMPhone.switchHoldingAndActive(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); - - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering 1 followed by SEND: release all active calls - // (if any exist) and accepts the other (held or waiting) call. - mGSMPhone.handleInCallMmiCommands("1"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - - // at this point, the active call with number==18005551212 should - // have the gsm index of 2 - - mRadioControl.triggerRing("16505550100"); - - msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering "12" followed by SEND: release the call with - // gsm index equals to 2. - mGSMPhone.handleInCallMmiCommands("12"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // at this point, the call with number==16505550100 should - // have the gsm index of 1 - mGSMPhone.dial("+13125551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE || - mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // at this point, the active call with number==13125551212 should - // have the gsm index of 2 - - // Simulate entering "11" followed by SEND: release the call with - // gsm index equals to 1. This should not be allowed, and a - // Supplementary Service notification must be received. - mGSMPhone.handleInCallMmiCommands("11"); - - msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED); - assertNotNull("Message Time Out", msg); - assertFalse("IncallMmiCallWaiting: command should not work on holding call", msg == null); - - // Simulate entering "12" followed by SEND: release the call with - // gsm index equals to 2. - mGSMPhone.handleInCallMmiCommands("12"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering 1 followed by SEND: release all active calls - // (if any exist) and accepts the other (held or waiting) call. - mGSMPhone.handleInCallMmiCommands("1"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - assertEquals("16505550100", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - - // Simulate entering "11" followed by SEND: release the call with - // gsm index equals to 1. - mGSMPhone.handleInCallMmiCommands("11"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - } - - public void testIncallMmiCallHold() throws Exception { - Message msg; - - // establish an active call - mGSMPhone.dial("13125551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // establish a ringing (WAITING) call - - mRadioControl.triggerRing("18005551212"); - - msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // simulate entering 2 followed by SEND: place all active calls - // (if any exist) on hold and accepts the other (held or waiting) - // call - - mGSMPhone.handleInCallMmiCommands("2"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); - - - assertFalse(mGSMPhone.getRingingCall().isRinging()); - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, - mGSMPhone.getForegroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertEquals("13125551212", - mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); - - // swap the active and holding calls - mGSMPhone.handleInCallMmiCommands("2"); - - msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED); - assertNotNull("Message Time Out", msg); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("13125551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); - - // merge the calls - mGSMPhone.conference(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - assertEquals(2, mGSMPhone.getForegroundCall().getConnections().size()); - - // at this point, we have an active conference call, with - // call(1) = 13125551212 and call(2) = 18005551212 - - // Simulate entering "23" followed by SEND: places all active call - // on hold except call 3. This should fail and a supplementary service - // failed notification should be received. - - mGSMPhone.handleInCallMmiCommands("23"); - - msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED); - assertNotNull("Message Time Out", msg); - assertFalse("IncallMmiCallHold: separate should have failed!", msg == null); - - // Simulate entering "21" followed by SEND: places all active call - // on hold except call 1. - mGSMPhone.handleInCallMmiCommands("21"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("13125551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); - } - - public void testIncallMmiMultipartyServices() throws Exception { - // establish an active call - mGSMPhone.dial("13125551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // dial another call - mGSMPhone.dial("18005551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - mGSMPhone.handleInCallMmiCommands("3"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals("13125551212", - mGSMPhone.getForegroundCall().getConnections().get(1).getAddress()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - } - - public void testCallIndex() throws Exception { - Message msg; - - // establish the first call - mGSMPhone.dial("16505550100"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - String baseNumber = "1650555010"; - - for (int i = 1; i < 6; i++) { - String number = baseNumber + i; - - mGSMPhone.dial(number); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - if (mGSMPhone.getBackgroundCall().getConnections().size() >= 5) { - break; - } - - mGSMPhone.conference(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - } - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("16505550105", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // create an incoming call, this call should have the call index - // of 7 - mRadioControl.triggerRing("18005551212"); - - msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // hangup the background call and accept the ringing call - mGSMPhone.getBackgroundCall().hangup(); - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getState() != Call.State.IDLE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertEquals("16505550105", - mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); - - mGSMPhone.handleInCallMmiCommands("17"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertEquals("16505550105", - mGSMPhone.getBackgroundCall().getConnections().get(0). - getAddress()); - - mGSMPhone.handleInCallMmiCommands("1"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - mGSMPhone.handleInCallMmiCommands("16"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - } - - public void testPostDialSequences() throws Exception { - Message msg; - AsyncResult ar; - Connection cn; - - mGSMPhone.dial("+13125551212,1234;5N8xx"); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(',', msg.arg1); - assertEquals("1234;5N8", cn.getRemainingPostDialString()); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('1', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('2', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('3', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('4', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals(';', msg.arg1); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); - assertEquals(Connection.PostDialState.WAIT, ar.userObj); - cn.proceedAfterWaitChar(); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('5', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertEquals('N', msg.arg1); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); - assertEquals(Connection.PostDialState.WILD, ar.userObj); - cn.proceedAfterWildChar(",6;7"); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(',', msg.arg1); - assertEquals("6;78", cn.getRemainingPostDialString()); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('6', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals(';', msg.arg1); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); - assertEquals(Connection.PostDialState.WAIT, ar.userObj); - cn.proceedAfterWaitChar(); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('7', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('8', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - // Bogus chars at end should be ignored - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals(0, msg.arg1); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(Connection.PostDialState.COMPLETE, - cn.getPostDialState()); - assertEquals(Connection.PostDialState.COMPLETE, ar.userObj); - } - - public void testPostDialCancel() throws Exception { - Message msg; - AsyncResult ar; - Connection cn; - - mGSMPhone.dial("+13125551212,N"); - mRadioControl.progressConnectingToActive(); - - mRadioControl.progressConnectingToActive(); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals(',', msg.arg1); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertEquals('N', msg.arg1); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); - cn.cancelPostDial(); - - assertEquals(Connection.PostDialState.CANCELLED, cn.getPostDialState()); - } - - public void testOutgoingCallFail() throws Exception { - Message msg; - /* - * normal clearing - */ - - mRadioControl.setNextCallFailCause(CallFailCause.NORMAL_CLEARING); - mRadioControl.setAutoProgressConnectingCall(false); - - Connection cn = mGSMPhone.dial("+13125551212"); - - mRadioControl.progressConnectingCallState(); - - // I'm just progressing the call state to - // ensure getCurrentCalls() gets processed... - // Normally these failure conditions would happen in DIALING - // not ALERTING - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (cn.getState() == Call.State.DIALING); - - - mRadioControl.triggerHangupAll(); - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(DisconnectCause.NORMAL, cn.getDisconnectCause()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - /* - * busy - */ - - mRadioControl.setNextCallFailCause(CallFailCause.USER_BUSY); - mRadioControl.setAutoProgressConnectingCall(false); - - cn = mGSMPhone.dial("+13125551212"); - - mRadioControl.progressConnectingCallState(); - - // I'm just progressing the call state to - // ensure getCurrentCalls() gets processed... - // Normally these failure conditions would happen in DIALING - // not ALERTING - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (cn.getState() == Call.State.DIALING); - - - mRadioControl.triggerHangupAll(); - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(DisconnectCause.BUSY, cn.getDisconnectCause()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, - mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - /* - * congestion - */ - - mRadioControl.setNextCallFailCause(CallFailCause.NO_CIRCUIT_AVAIL); - mRadioControl.setAutoProgressConnectingCall(false); - - cn = mGSMPhone.dial("+13125551212"); - - mRadioControl.progressConnectingCallState(); - - // I'm just progressing the call state to - // ensure getCurrentCalls() gets processed... - // Normally these failure conditions would happen in DIALING - // not ALERTING - do { - msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); - assertNotNull("Message Time Out", msg); - } while (cn.getState() == Call.State.DIALING); - - - mRadioControl.triggerHangupAll(); - - // Unlike the while loops above, this one waits - // for a "phone state changed" message back to "idle" - do { - msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); - assertNotNull("Message Time Out", msg); - } while (!(msg.what == EVENT_PHONE_STATE_CHANGED - && mGSMPhone.getState() == PhoneConstants.State.IDLE)); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(DisconnectCause.CONGESTION, cn.getDisconnectCause()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - } - - public void testSSNotification() throws Exception { - // MO - runTest(0, SuppServiceNotification.MO_CODE_UNCONDITIONAL_CF_ACTIVE); - runTest(0, SuppServiceNotification.MO_CODE_CALL_IS_WAITING); - runTest(0, SuppServiceNotification.MO_CODE_CALL_DEFLECTED); - - // MT - runTest(1, SuppServiceNotification.MT_CODE_FORWARDED_CALL); - runTest(1, SuppServiceNotification.MT_CODE_CALL_CONNECTED_ECT); - runTest(1, SuppServiceNotification.MT_CODE_ADDITIONAL_CALL_FORWARDED); - } - - private void runTest(int type, int code) { - Message msg; - - mRadioControl.triggerSsn(type, code); - - msg = mGSMTestHandler.waitForMessage(EVENT_SSN); - assertNotNull("Message Time Out", msg); - AsyncResult ar = (AsyncResult) msg.obj; - - assertNull(ar.exception); - - SuppServiceNotification notification = - (SuppServiceNotification) ar.result; - - assertEquals(type, notification.notificationType); - assertEquals(code, notification.code); - } - - public void testUssd() throws Exception { - // Quick hack to work around a race condition in this test: - // We may initiate a USSD MMI before GSMPhone receives its initial - // GSMTestHandler.EVENT_RADIO_OFF_OR_NOT_AVAILABLE event. When the phone sees this - // event, it will cancel the just issued USSD MMI, which we don't - // want. So sleep a little first. - try { - Thread.sleep(1000); - } catch (InterruptedException ex) { - // do nothing - } - - verifyNormal(); - verifyCancel(); - varifyNetworkInitiated(); - } - - private void varifyNetworkInitiated() { - Message msg; - AsyncResult ar; - MmiCode mmi; - - // Receive an incoming NOTIFY - mRadioControl.triggerIncomingUssd("0", "NOTIFY message"); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertFalse(mmi.isUssdRequest()); - - // Receive a REQUEST and send response - mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertTrue(mmi.isUssdRequest()); - - mGSMPhone.sendUssdResponse("## TEST: TEST_GSMPhone responding..."); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - GsmMmiCode gsmMmi = (GsmMmiCode) mmi; - assertTrue(gsmMmi.isPendingUSSD()); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertNull(ar.exception); - assertFalse(mmi.isUssdRequest()); - - // Receive a REQUEST and cancel - mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertTrue(mmi.isUssdRequest()); - - mmi.cancel(); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertNull(ar.exception); - assertEquals(MmiCode.State.CANCELLED, mmi.getState()); - - List mmiList = mGSMPhone.getPendingMmiCodes(); - assertEquals(0, mmiList.size()); - } - - private void verifyNormal() throws CallStateException { - Message msg; - AsyncResult ar; - MmiCode mmi; - - mGSMPhone.dial("#646#"); - - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); - assertNotNull("Message Time Out", msg); - - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - assertEquals(MmiCode.State.COMPLETE, mmi.getState()); - } - - - private void verifyCancel() throws CallStateException { - /** - * This case makes an assumption that dial() will add the USSD - * to the "pending MMI codes" list before it returns. This seems - * like reasonable semantics. It also assumes that the USSD - * request in question won't complete until we get back to the - * event loop, thus cancel() is safe. - */ - Message msg; - - mGSMPhone.dial("#646#"); - - List pendingMmis = mGSMPhone.getPendingMmiCodes(); - - assertEquals(1, pendingMmis.size()); - - MmiCode mmi = pendingMmis.get(0); - assertTrue(mmi.isCancelable()); - mmi.cancel(); - - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); - assertNotNull("Message Time Out", msg); - - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - - AsyncResult ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertEquals(MmiCode.State.CANCELLED, mmi.getState()); - } - - public void testRilHooks() throws Exception { - // - // These test cases all assume the RIL OEM hooks - // just echo back their input - // - - Message msg; - AsyncResult ar; - - // null byte array - - mGSMPhone.invokeOemRilRequestRaw(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertNull(ar.result); - assertNull(ar.exception); - - // empty byte array - - mGSMPhone.invokeOemRilRequestRaw(new byte[0], mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertEquals(0, ((byte[]) (ar.result)).length); - assertNull(ar.exception); - - // byte array with data - - mGSMPhone.invokeOemRilRequestRaw("Hello".getBytes("utf-8"), - mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertEquals("Hello", new String(((byte[]) (ar.result)), "utf-8")); - assertNull(ar.exception); - - // null strings - - mGSMPhone.invokeOemRilRequestStrings(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertNull(ar.result); - assertNull(ar.exception); - - // empty byte array - - mGSMPhone.invokeOemRilRequestStrings(new String[0], - mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertEquals(0, ((String[]) (ar.result)).length); - assertNull(ar.exception); - - // Strings with data - - String s[] = new String[1]; - - s[0] = "Hello"; - - mGSMPhone.invokeOemRilRequestStrings(s, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertEquals("Hello", ((String[]) (ar.result))[0]); - assertEquals(1, ((String[]) (ar.result)).length); - assertNull(ar.exception); - } - - public void testMmi() throws Exception { - mRadioControl.setAutoProgressConnectingCall(false); - - // "valid" MMI sequences - runValidMmi("*#67#", false); - runValidMmi("##43*11#", false); - runValidMmi("#33*1234*11#", false); - runValidMmi("*21*6505551234**5#", false); - runValidMmi("**03**1234*4321*4321#", false); - // pound string - runValidMmi("5308234092307540923#", true); - // short code - runValidMmi("22", true); - // as part of call setup - runValidMmiWithConnect("*31#6505551234"); - - // invalid MMI sequences - runNotMmi("6505551234"); - runNotMmi("1234#*12#34566654"); - runNotMmi("*#*#12#*"); - } - - private void runValidMmi(String dialString, boolean cancelable) throws CallStateException { - Connection c = mGSMPhone.dial(dialString); - assertNull(c); - Message msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); - assertNotNull("Message Time Out", msg); - // Should not be cancelable. - AsyncResult ar = (AsyncResult) msg.obj; - MmiCode mmi = (MmiCode) ar.result; - assertEquals(cancelable, mmi.isCancelable()); - - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - } - - private void runValidMmiWithConnect(String dialString) throws CallStateException { - mRadioControl.pauseResponses(); - - Connection c = mGSMPhone.dial(dialString); - assertNotNull(c); - - hangup(c); - } - - private void hangup(Connection cn) throws CallStateException { - cn.hangup(); - - mRadioControl.resumeResponses(); - assertNotNull(mGSMTestHandler.waitForMessage(EVENT_DISCONNECT)); - - } - - private void runNotMmi(String dialString) throws CallStateException { - mRadioControl.pauseResponses(); - - Connection c = mGSMPhone.dial(dialString); - assertNotNull(c); - - hangup(c); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken deleted file mode 100644 index 16861fac7f..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2009 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.gsm; - -import android.content.Context; - -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import com.android.telephony.Rlog; - -import com.android.internal.telephony.gsm.GSMPhone; -import com.android.internal.telephony.test.SimulatedCommands; -import com.android.internal.telephony.TestPhoneNotifier; - -/** - * This class creates a HandlerThread which waits for the various messages. - */ -public class GSMTestHandler extends HandlerThread implements Handler.Callback { - - private Handler mHandler; - private Message mCurrentMessage; - - private Boolean mMsgConsumed; - private SimulatedCommands sc; - private GSMPhone mGSMPhone; - private Context mContext; - - private static final int FAIL_TIMEOUT_MILLIS = 5 * 1000; - - public GSMTestHandler(Context context) { - super("GSMPhoneTest"); - mMsgConsumed = false; - mContext = context; - } - - @Override - protected void onLooperPrepared() { - sc = new SimulatedCommands(); - mGSMPhone = new GSMPhone(mContext, sc, new TestPhoneNotifier(), true); - mHandler = new Handler(getLooper(), this); - synchronized (this) { - notifyAll(); - } - } - - public boolean handleMessage(Message msg) { - synchronized (this) { - mCurrentMessage = msg; - this.notifyAll(); - while(!mMsgConsumed) { - try { - this.wait(); - } catch (InterruptedException e) {} - } - mMsgConsumed = false; - } - return true; - } - - - public void cleanup() { - Looper looper = getLooper(); - if (looper != null) looper.quit(); - mHandler = null; - } - - public Handler getHandler() { - return mHandler; - } - - public SimulatedCommands getSimulatedCommands() { - return sc; - } - - public GSMPhone getGSMPhone() { - return mGSMPhone; - } - - public Message waitForMessage(int code) { - Message msg; - while(true) { - msg = null; - synchronized (this) { - try { - this.wait(FAIL_TIMEOUT_MILLIS); - } catch (InterruptedException e) { - } - - // Check if timeout has occurred. - if (mCurrentMessage != null) { - // Consume the message - msg = Message.obtain(); - msg.copyFrom(mCurrentMessage); - mCurrentMessage = null; - mMsgConsumed = true; - this.notifyAll(); - } - } - if (msg == null || code == GSMPhoneTest.ANY_MESSAGE || msg.what == code) return msg; - } - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken deleted file mode 100644 index a9d869c4cb..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Copyright (C) 2011 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.gsm; - -import android.content.Context; -import android.os.AsyncResult; -import android.os.Message; -import android.os.SystemClock; -import com.android.telephony.Rlog; - -import com.android.internal.telephony.BaseCommands; -import com.android.internal.telephony.UUSInfo; -import com.android.internal.telephony.uicc.IccIoResult; -import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; - -import junit.framework.Assert; - -/** - * Dummy BaseCommands for UsimDataDownloadTest. Only implements UICC envelope and - * SMS acknowledgement commands. - */ -class UsimDataDownloadCommands extends BaseCommands { - private static final String TAG = "UsimDataDownloadCommands"; - - private boolean mExpectingAcknowledgeGsmSms; // true if expecting ack GSM SMS - private boolean mExpectingAcknowledgeGsmSmsSuccess; // true if expecting ack SMS success - private int mExpectingAcknowledgeGsmSmsFailureCause; // expecting ack SMS failure cause - private String mExpectingAcknowledgeGsmSmsPdu; // expecting ack SMS PDU - - private boolean mExpectingSendEnvelope; // true to expect a send envelope command - private String mExpectingSendEnvelopeContents; // expected string for send envelope - private int mExpectingSendEnvelopeResponseSw1; // SW1/SW2 response status - private int mExpectingSendEnvelopeResponseSw2; // SW1/SW2 response status - private String mExpectingSendEnvelopeResponse; // Response string for Send Envelope - - UsimDataDownloadCommands(Context context) { - super(context); - } - - /** - * Expect a call to acknowledgeLastIncomingGsmSms with success flag and failure cause. - * @param success true if expecting success; false if expecting failure - * @param cause the failure cause, if success is false - */ - synchronized void expectAcknowledgeGsmSms(boolean success, int cause) { - Assert.assertFalse("expectAcknowledgeGsmSms called twice", mExpectingAcknowledgeGsmSms); - mExpectingAcknowledgeGsmSms = true; - mExpectingAcknowledgeGsmSmsSuccess = success; - mExpectingAcknowledgeGsmSmsFailureCause = cause; - } - - /** - * Expect a call to acknowledgeLastIncomingGsmSmsWithPdu with success flag and PDU. - * @param success true if expecting success; false if expecting failure - * @param ackPdu the acknowledgement PDU to expect - */ - synchronized void expectAcknowledgeGsmSmsWithPdu(boolean success, String ackPdu) { - Assert.assertFalse("expectAcknowledgeGsmSms called twice", mExpectingAcknowledgeGsmSms); - mExpectingAcknowledgeGsmSms = true; - mExpectingAcknowledgeGsmSmsSuccess = success; - mExpectingAcknowledgeGsmSmsPdu = ackPdu; - } - - /** - * Expect a call to sendEnvelopeWithStatus(). - * @param contents expected envelope contents to send - * @param sw1 simulated SW1 status to return - * @param sw2 simulated SW2 status to return - * @param response simulated envelope response to return - */ - synchronized void expectSendEnvelope(String contents, int sw1, int sw2, String response) { - Assert.assertFalse("expectSendEnvelope called twice", mExpectingSendEnvelope); - mExpectingSendEnvelope = true; - mExpectingSendEnvelopeContents = contents; - mExpectingSendEnvelopeResponseSw1 = sw1; - mExpectingSendEnvelopeResponseSw2 = sw2; - mExpectingSendEnvelopeResponse = response; - } - - synchronized void assertExpectedMethodsCalled() { - long stopTime = SystemClock.elapsedRealtime() + 5000; - while ((mExpectingAcknowledgeGsmSms || mExpectingSendEnvelope) - && SystemClock.elapsedRealtime() < stopTime) { - try { - wait(); - } catch (InterruptedException ignored) {} - } - Assert.assertFalse("expecting SMS acknowledge call", mExpectingAcknowledgeGsmSms); - Assert.assertFalse("expecting send envelope call", mExpectingSendEnvelope); - } - - @Override - public synchronized void acknowledgeLastIncomingGsmSms(boolean success, int cause, - Message response) { - Rlog.d(TAG, "acknowledgeLastIncomingGsmSms: success=" + success + ", cause=" + cause); - Assert.assertTrue("unexpected call to acknowledge SMS", mExpectingAcknowledgeGsmSms); - Assert.assertEquals(mExpectingAcknowledgeGsmSmsSuccess, success); - Assert.assertEquals(mExpectingAcknowledgeGsmSmsFailureCause, cause); - mExpectingAcknowledgeGsmSms = false; - if (response != null) { - AsyncResult.forMessage(response); - response.sendToTarget(); - } - notifyAll(); // wake up assertExpectedMethodsCalled() - } - - @Override - public synchronized void acknowledgeIncomingGsmSmsWithPdu(boolean success, String ackPdu, - Message response) { - Rlog.d(TAG, "acknowledgeLastIncomingGsmSmsWithPdu: success=" + success - + ", ackPDU= " + ackPdu); - Assert.assertTrue("unexpected call to acknowledge SMS", mExpectingAcknowledgeGsmSms); - Assert.assertEquals(mExpectingAcknowledgeGsmSmsSuccess, success); - Assert.assertEquals(mExpectingAcknowledgeGsmSmsPdu, ackPdu); - mExpectingAcknowledgeGsmSms = false; - if (response != null) { - AsyncResult.forMessage(response); - response.sendToTarget(); - } - notifyAll(); // wake up assertExpectedMethodsCalled() - } - - @Override - public synchronized void sendEnvelopeWithStatus(String contents, Message response) { - // Add spaces between hex bytes for readability - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < contents.length(); i += 2) { - builder.append(contents.charAt(i)).append(contents.charAt(i+1)).append(' '); - } - Rlog.d(TAG, "sendEnvelopeWithStatus: " + builder.toString()); - - Assert.assertTrue("unexpected call to send envelope", mExpectingSendEnvelope); - Assert.assertEquals(mExpectingSendEnvelopeContents, contents); - mExpectingSendEnvelope = false; - - IccIoResult result = new IccIoResult(mExpectingSendEnvelopeResponseSw1, - mExpectingSendEnvelopeResponseSw2, mExpectingSendEnvelopeResponse); - - if (response != null) { - AsyncResult.forMessage(response, result, null); - response.sendToTarget(); - } - notifyAll(); // wake up assertExpectedMethodsCalled() - } - - @Override - public void setSuppServiceNotifications(boolean enable, Message result) { - } - - @Override - public void supplyIccPin(String pin, Message result) { - } - - @Override - public void supplyIccPinForApp(String pin, String aid, Message result) { - } - - @Override - public void supplyIccPuk(String puk, String newPin, Message result) { - } - - @Override - public void supplyIccPukForApp(String puk, String newPin, String aid, Message result) { - } - - @Override - public void supplyIccPin2(String pin2, Message result) { - } - - @Override - public void supplyIccPin2ForApp(String pin2, String aid, Message result) { - } - - @Override - public void supplyIccPuk2(String puk2, String newPin2, Message result) { - } - - @Override - public void supplyIccPuk2ForApp(String puk2, String newPin2, String aid, Message result) { - } - - @Override - public void changeIccPin(String oldPin, String newPin, Message result) { - } - - @Override - public void changeIccPinForApp(String oldPin, String newPin, String aidPtr, Message result) { - } - - @Override - public void changeIccPin2(String oldPin2, String newPin2, Message result) { - } - - @Override - public void changeIccPin2ForApp(String oldPin2, String newPin2, String aidPtr, Message result) { - } - - @Override - public void changeBarringPassword(String facility, String oldPwd, String newPwd, - Message result) { - } - - @Override - public void supplyNetworkDepersonalization(String netpin, Message result) { - } - - @Override - public void getCurrentCalls(Message result) { - } - - @Override - public void getPDPContextList(Message result) { - } - - @Override - public void getDataCallList(Message result) { - } - - @Override - public void dial(String address, int clirMode, Message result) { - } - - @Override - public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) { - } - - @Override - public void getIMSI(Message result) { - } - - @Override - public void getIMEI(Message result) { - } - - @Override - public void getIMEISV(Message result) { - } - - @Override - public void hangupConnection(int gsmIndex, Message result) { - } - - @Override - public void hangupWaitingOrBackground(Message result) { - } - - @Override - public void hangupForegroundResumeBackground(Message result) { - } - - @Override - public void switchWaitingOrHoldingAndActive(Message result) { - } - - @Override - public void conference(Message result) { - } - - @Override - public void setPreferredVoicePrivacy(boolean enable, Message result) { - } - - @Override - public void getPreferredVoicePrivacy(Message result) { - } - - @Override - public void separateConnection(int gsmIndex, Message result) { - } - - @Override - public void acceptCall(Message result) { - } - - @Override - public void rejectCall(Message result) { - } - - @Override - public void explicitCallTransfer(Message result) { - } - - @Override - public void getLastCallFailCause(Message result) { - } - - @Override - public void getLastPdpFailCause(Message result) { - } - - @Override - public void getLastDataCallFailCause(Message result) { - } - - @Override - public void setMute(boolean enableMute, Message response) { - } - - @Override - public void getMute(Message response) { - } - - @Override - public void getSignalStrength(Message response) { - } - - @Override - public void getVoiceRegistrationState(Message response) { - } - - @Override - public void getDataRegistrationState(Message response) { - } - - @Override - public void getOperator(Message response) { - } - - @Override - public void sendDtmf(char c, Message result) { - } - - @Override - public void startDtmf(char c, Message result) { - } - - @Override - public void stopDtmf(Message result) { - } - - @Override - public void sendBurstDtmf(String dtmfString, int on, int off, Message result) { - } - - @Override - public void sendSMS(String smscPDU, String pdu, Message response) { - } - - @Override - public void sendSMSExpectMore(String smscPDU, String pdu, Message response) { - } - - @Override - public void sendCdmaSms(byte[] pdu, Message response) { - } - - @Override - public void sendImsGsmSms (String smscPDU, String pdu, - int retry, int messageRef, Message response) { - } - - @Override - public void sendImsCdmaSms(byte[] pdu, int retry, int messageRef, - Message response) { - } - - @Override - public void deleteSmsOnSim(int index, Message response) { - } - - @Override - public void deleteSmsOnRuim(int index, Message response) { - } - - @Override - public void writeSmsToSim(int status, String smsc, String pdu, Message response) { - } - - @Override - public void writeSmsToRuim(int status, byte[] pdu, Message response) { - } - - @Override - public void setRadioPower(boolean on, Message response) { - } - - @Override - public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message response) { - } - - @Override - public void iccIO(int command, int fileid, String path, int p1, int p2, int p3, String data, - String pin2, Message response) { - } - - @Override - public void queryCLIP(Message response) { - } - - @Override - public void getCLIR(Message response) { - } - - @Override - public void setCLIR(int clirMode, Message response) { - } - - @Override - public void queryCallWaiting(int serviceClass, Message response) { - } - - @Override - public void setCallWaiting(boolean enable, int serviceClass, Message response) { - } - - @Override - public void setCallForward(int action, int cfReason, int serviceClass, String number, - int timeSeconds, Message response) { - } - - @Override - public void queryCallForwardStatus(int cfReason, int serviceClass, String number, - Message response) { - } - - @Override - public void setNetworkSelectionModeAutomatic(Message response) { - } - - @Override - public void setNetworkSelectionModeManual(String operatorNumeric, Message response) { - } - - @Override - public void getNetworkSelectionMode(Message response) { - } - - @Override - public void getAvailableNetworks(Message response) { - } - - @Override - public void getBasebandVersion(Message response) { - } - - @Override - public void queryFacilityLock(String facility, String password, int serviceClass, - Message response) { - } - - @Override - public void queryFacilityLockForApp(String facility, String password, int serviceClass, - String appId, Message response) { - } - - @Override - public void setFacilityLock(String facility, boolean lockState, String password, - int serviceClass, Message response) { - } - - @Override - public void setFacilityLockForApp(String facility, boolean lockState, String password, - int serviceClass, String appId, Message response) { - } - - @Override - public void sendUSSD(String ussdString, Message response) { - } - - @Override - public void cancelPendingUssd(Message response) { - } - - @Override - public void resetRadio(Message result) { - } - - @Override - public void setBandMode(int bandMode, Message response) { - } - - @Override - public void queryAvailableBandMode(Message response) { - } - - @Override - public void setPreferredNetworkType(int networkType, Message response) { - } - - @Override - public void getPreferredNetworkType(Message response) { - } - - @Override - public void setLocationUpdates(boolean enable, Message response) { - } - - @Override - public void getSmscAddress(Message result) { - } - - @Override - public void setSmscAddress(String address, Message result) { - } - - @Override - public void reportSmsMemoryStatus(boolean available, Message result) { - } - - @Override - public void reportStkServiceIsRunning(Message result) { - } - - @Override - public void invokeOemRilRequestRaw(byte[] data, Message response) { - } - - @Override - public void invokeOemRilRequestStrings(String[] strings, Message response) { - } - - @Override - public void sendTerminalResponse(String contents, Message response) { - } - - @Override - public void sendEnvelope(String contents, Message response) { - } - - @Override - public void handleCallSetupRequestFromSim(boolean accept, Message response) { - } - - @Override - public void setGsmBroadcastActivation(boolean activate, Message result) { - } - - @Override - public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) { - } - - @Override - public void getGsmBroadcastConfig(Message response) { - } - - @Override - public void getDeviceIdentity(Message response) { - } - - @Override - public void getCDMASubscription(Message response) { - } - - @Override - public void getImsRegistrationState (Message result) { - } - - @Override - public void sendCDMAFeatureCode(String FeatureCode, Message response) { - } - - @Override - public void setPhoneType(int phoneType) { - } - - @Override - public void queryCdmaRoamingPreference(Message response) { - } - - @Override - public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { - } - - @Override - public void setCdmaSubscriptionSource(int cdmaSubscriptionType, Message response) { - } - - @Override - public void getCdmaSubscriptionSource(Message response) { - } - - @Override - public void setTTYMode(int ttyMode, Message response) { - } - - @Override - public void queryTTYMode(Message response) { - } - - @Override - public void setupDataCall(String radioTechnology, String profile, String apn, String user, - String password, String authType, String protocol, Message result) { - } - - @Override - public void deactivateDataCall(int cid, int reason, Message result) { - } - - @Override - public void setCdmaBroadcastActivation(boolean activate, Message result) { - } - - @Override - public void setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs, Message response) { - } - - @Override - public void getCdmaBroadcastConfig(Message result) { - } - - @Override - public void exitEmergencyCallbackMode(Message response) { - } - - @Override - public void getIccCardStatus(Message result) { - } - - @Override - public void requestIsimAuthentication(String nonce, Message response) { - } - - @Override - public void requestIccSimAuthentication(String data, Message response) { - } - - @Override - public void getVoiceRadioTechnology(Message response) { - } - - @Override - public void getCellInfoList(Message result) { - } - - @Override - public void setCellInfoListRate(int rateInMillis, Message response) { - } - - @Override - public void setInitialAttachApn(String apn, String protocol, int authType, String username, - String password, Message result) { - } - - @Override - public void setDataProfile(DataProfile[] dps, Message result) { - } - - @Override - public void getIMSIForApp(String aid, Message result) { - } - - @Override - public void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3, - String data, String pin2, String aid, Message response) { - } - - @Override - public void iccOpenLogicalChannel(String AID, Message response) { - } - - @Override - public void iccCloseLogicalChannel(int channel, Message response) { - } - - @Override - public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, - int p1, int p2, int p3, String data, Message response) { - } - - @Override - public void iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, - int p3, String data, Message response) { - } - - @Override - public void nvReadItem(int itemID, Message response) { - } - - @Override - public void nvWriteItem(int itemID, String itemValue, Message response) { - } - - @Override - public void nvWriteCdmaPrl(byte[] preferredRoamingList, Message response) { - } - - @Override - public void nvResetConfig(int resetType, Message response) { - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken deleted file mode 100644 index 9fbb86c264..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2011 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.gsm; - -import android.os.HandlerThread; -import android.test.AndroidTestCase; -import com.android.telephony.Rlog; - -import java.nio.charset.Charset; - -/** - * Test SMS-PP data download to UICC. - * Uses test messages from 3GPP TS 31.124 section 27.22.5. - */ -public class UsimDataDownloadTest extends AndroidTestCase { - private static final String TAG = "UsimDataDownloadTest"; - - class TestHandlerThread extends HandlerThread { - private UsimDataDownloadHandler mHandler; - - TestHandlerThread() { - super("TestHandlerThread"); - } - - @Override - protected void onLooperPrepared() { - synchronized (this) { - mHandler = new UsimDataDownloadHandler(mCi, 0); - notifyAll(); - } - } - - UsimDataDownloadHandler getHandler() { - synchronized (this) { - while (mHandler == null) { - try { - wait(); - } catch (InterruptedException ignored) {} - } - return mHandler; - } - } - } - - private UsimDataDownloadCommands mCi; - private TestHandlerThread mHandlerThread; - UsimDataDownloadHandler mHandler; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mCi = new UsimDataDownloadCommands(mContext); - mHandlerThread = new TestHandlerThread(); - mHandlerThread.start(); - mHandler = mHandlerThread.getHandler(); - Rlog.d(TAG, "mHandler is constructed"); - } - - @Override - protected void tearDown() throws Exception { - mHandlerThread.quit(); - super.tearDown(); - } - - // SMS-PP Message 3.1.1 - private static final byte[] SMS_PP_MESSAGE_3_1_1 = { - // Service center address - 0x09, (byte) 0x91, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0xf8, - - 0x04, 0x04, (byte) 0x91, 0x21, 0x43, 0x7f, 0x16, (byte) 0x89, 0x10, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x0d, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x20, 0x31 - }; - - // SMS-PP Download Envelope 3.1.1 - private static final String SMS_PP_ENVELOPE_3_1_1 = "d12d8202838106099111223344556677f88b1c04" - + "049121437f16891010000000000d546573744d6573736167652031"; - - // SMS-PP Message 3.1.5 - private static final byte[] SMS_PP_MESSAGE_3_1_5 = { - // Service center address - 0x09, (byte) 0x91, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0xf8, - - 0x44, 0x04, (byte) 0x91, 0x21, 0x43, 0x7f, (byte) 0xf6, (byte) 0x89, 0x10, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x1e, 0x02, 0x70, 0x00, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x00, - 0x00, 0x00, (byte) 0xbf, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, - (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc - }; - - // SMS-PP Download Envelope 3.1.5 - private static final String SMS_PP_ENVELOPE_3_1_5 = "d13e8202838106099111223344556677f88b2d44" - + "049121437ff6891010000000001e0270000019000d00000000bfff00000000000100" - + "dcdcdcdcdcdcdcdcdcdc"; - - public void testDataDownloadMessage1() { - SmsMessage message = SmsMessage.createFromPdu(SMS_PP_MESSAGE_3_1_1); - assertTrue("message is SMS-PP data download", message.isUsimDataDownload()); - - mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x90, 0x00, ""); - mCi.expectAcknowledgeGsmSms(true, 0); - mHandler.startDataDownload(message); - mCi.assertExpectedMethodsCalled(); - - mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x90, 0x00, "0123456789"); - mCi.expectAcknowledgeGsmSmsWithPdu(true, "00077f16050123456789"); - mHandler.startDataDownload(message); - mCi.assertExpectedMethodsCalled(); - - mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x62, 0xff, "0123456789abcdef"); - mCi.expectAcknowledgeGsmSmsWithPdu(false, "00d5077f16080123456789abcdef"); - mHandler.startDataDownload(message); - mCi.assertExpectedMethodsCalled(); - } - - public void testDataDownloadMessage5() { - SmsMessage message = SmsMessage.createFromPdu(SMS_PP_MESSAGE_3_1_5); - assertTrue("message is SMS-PP data download", message.isUsimDataDownload()); - - mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_5, 0x90, 0x00, "9876543210"); - mCi.expectAcknowledgeGsmSmsWithPdu(true, "00077ff6059876543210"); - mHandler.startDataDownload(message); - mCi.assertExpectedMethodsCalled(); - - mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_5, 0x93, 0x00, ""); - mCi.expectAcknowledgeGsmSms(false, 0xd4); // SIM toolkit busy - mHandler.startDataDownload(message); - mCi.assertExpectedMethodsCalled(); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java index 111e5d2c5f..c26dd22842 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java @@ -25,11 +25,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL; import static com.android.internal.telephony.data.LinkBandwidthEstimator.NUM_SIGNAL_LEVEL; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6; import static org.junit.Assert.assertArrayEquals; @@ -89,6 +84,11 @@ import java.util.ArrayList; import java.util.Arrays; public class TelephonyMetricsTest extends TelephonyTest { + private static final String FAKE_ADDRESS = "99.88.77.66"; + private static final String FAKE_DNS = "55.66.77.88"; + private static final String FAKE_GATEWAY = "11.22.33.44"; + private static final String FAKE_IFNAME = "FAKE IFNAME"; + private static final String FAKE_PCSCF_ADDRESS = "22.33.44.55"; // Mocked classes private ImsCallSession mImsCallSession; private ServiceState mServiceState; diff --git a/tools/tdi b/tools/tdi deleted file mode 100755 index 940a83bccc..0000000000 --- a/tools/tdi +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -# Telephony Debug Intents -#set -x - -file_name='tdi' - -# Get the command as the first parameter -cmd=$1 -shift - -function dc_errors() -{ - if [ "$1" == "" ]; then - echo "Usage: $file_name $cmd " - echo " must specifiy the DataConnection such as DC or GsmDC-1" - echo " := number of times to retry" - echo " := From DataConnection.FailCause; such as -3 for SIGNAL_LOST" - echo " := suggested retry time in milli-seconds" - exit - fi - the_DC=$1 - echo "the_DC=$the_DC" - - if [ "$2" != "" ]; then - counter="--ei counter $2"; - fi - echo "counter=$counter" - - if [ "$3" != "" ]; then - fail_cause="--ei fail_cause $3"; - fi - echo "fail_cause=$fail_cause" - - if [ "$4" != "" ]; then - suggested_retry_time="--ei suggested_retry_time $4"; - fi - echo "suggested_retry_time=$suggested_retry_time" - - - adb shell am broadcast -a com.android.internal.telephony.$the_DC.action_fail_bringup $counter $fail_cause $suggested_retry_time -} - - -case ${cmd} in - dce) dc_errors "$@";; - # Add more commands in the future - *) echo 'Broadcast telephony debug intents'; echo 'usage: tdi [dce]'; echo ' dce=DC errors';; -esac -- GitLab From 4cf76bb387905d811fefc4f208198a110f3b8ad2 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Fri, 29 Jul 2022 10:55:03 -0700 Subject: [PATCH 058/656] Cancel pending retry upon data profile unthrottle Test: manual + atest DataRetryManagerTest.java Bug: 239187012 Change-Id: I0a66ef345e678ac3435f00bf1c94c0a17181b502 --- .../telephony/data/DataRetryManager.java | 69 +++++++++++--- .../telephony/data/DataRetryManagerTest.java | 95 ++++++++++++++++++- 2 files changed, 151 insertions(+), 13 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index ec5ba1b42e..e8e694d121 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -969,18 +969,16 @@ public class DataRetryManager extends Handler { switch (msg.what) { case EVENT_DATA_SETUP_RETRY: DataSetupRetryEntry dataSetupRetryEntry = (DataSetupRetryEntry) msg.obj; - Objects.requireNonNull(dataSetupRetryEntry); - mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( - () -> callback.onDataNetworkSetupRetry(dataSetupRetryEntry))); + if (!isRetryCancelled(dataSetupRetryEntry)) { + mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( + () -> callback.onDataNetworkSetupRetry(dataSetupRetryEntry))); + } break; case EVENT_DATA_HANDOVER_RETRY: DataHandoverRetryEntry dataHandoverRetryEntry = (DataHandoverRetryEntry) msg.obj; - Objects.requireNonNull(dataHandoverRetryEntry); - if (mDataRetryEntries.contains(dataHandoverRetryEntry)) { + if (!isRetryCancelled(dataHandoverRetryEntry)) { mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( () -> callback.onDataNetworkHandoverRetry(dataHandoverRetryEntry))); - } else { - log("Handover was cancelled earlier. " + dataHandoverRetryEntry); } break; case EVENT_RADIO_ON: @@ -1013,6 +1011,18 @@ public class DataRetryManager extends Handler { } } + /** + * @param retryEntry The retry entry to check. + * @return {@code true} if the retry is null or not in RETRY_STATE_NOT_RETRIED state. + */ + private boolean isRetryCancelled(@Nullable DataRetryEntry retryEntry) { + if (retryEntry != null && retryEntry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED) { + return false; + } + log("Retry was removed earlier. " + retryEntry); + return true; + } + /** * Called when carrier config is updated. */ @@ -1385,7 +1395,7 @@ public class DataRetryManager extends Handler { * @param remove Whether to remove unthrottled entries from the list of entries. */ private void onDataProfileUnthrottled(@Nullable DataProfile dataProfile, @Nullable String apn, - int transport, boolean remove) { + @TransportType int transport, boolean remove) { log("onDataProfileUnthrottled: data profile=" + dataProfile + ", apn=" + apn + ", transport=" + AccessNetworkConstants.transportTypeToString(transport) + ", remove=" + remove); @@ -1456,11 +1466,16 @@ public class DataRetryManager extends Handler { mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( () -> callback.onThrottleStatusChanged(throttleStatusList))); + if (unthrottledProfile != null) { + // cancel pending retries since we will soon schedule an immediate retry + cancelRetriesForDataProfile(unthrottledProfile, transport); + } + logl("onDataProfileUnthrottled: Removing the following throttling entries. " + dataUnthrottlingEntries); for (DataThrottlingEntry entry : dataUnthrottlingEntries) { + // Immediately retry after unthrottling. if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) { - // Immediately retry after unthrottling. schedule(new DataSetupRetryEntry.Builder<>() .setDataProfile(entry.dataProfile) .setTransport(entry.transport) @@ -1480,6 +1495,34 @@ public class DataRetryManager extends Handler { } } + /** + * Cancel pending retries that uses the specified data profile, with specified target transport. + * + * @param dataProfile The data profile to cancel. + * @param transport The target {@link TransportType} on which the retry to cancel. + */ + private void cancelRetriesForDataProfile(@NonNull DataProfile dataProfile, + @TransportType int transport) { + logl("cancelRetriesForDataProfile: Canceling pending retries for " + dataProfile); + mDataRetryEntries.stream() + .filter(entry -> { + if (entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED) { + if (entry instanceof DataSetupRetryEntry) { + DataSetupRetryEntry retryEntry = (DataSetupRetryEntry) entry; + return dataProfile.equals(retryEntry.dataProfile) + && transport == retryEntry.transport; + } else if (entry instanceof DataHandoverRetryEntry) { + DataHandoverRetryEntry retryEntry = (DataHandoverRetryEntry) entry; + return dataProfile.equals(retryEntry.dataNetwork.getDataProfile()); + } + } + return false; + }) + .forEach(entry -> entry.setState(DataRetryEntry.RETRY_STATE_CANCELLED)); + } + + + /** * Check if there is any similar network request scheduled to retry. The definition of similar * is that network requests have same APN capability and on the same transport. @@ -1564,14 +1607,18 @@ public class DataRetryManager extends Handler { * @param dataNetwork The data network that was originally scheduled for handover retry. */ private void onCancelPendingHandoverRetry(@NonNull DataNetwork dataNetwork) { - mDataRetryEntries.removeIf(entry -> entry instanceof DataHandoverRetryEntry - && ((DataHandoverRetryEntry) entry).dataNetwork == dataNetwork); + mDataRetryEntries.stream() + .filter(entry -> entry instanceof DataHandoverRetryEntry + && ((DataHandoverRetryEntry) entry).dataNetwork == dataNetwork + && entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED) + .forEach(entry -> entry.setState(DataRetryEntry.RETRY_STATE_CANCELLED)); mDataThrottlingEntries.removeIf(entry -> entry.dataNetwork == dataNetwork); } /** * Check if there is any data handover retry scheduled. * + * * @param dataNetwork The network network to retry handover. * @return {@code true} if there is retry scheduled for this network capability. */ 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 4fbc31c9c5..15eb0eae35 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.data; +import static com.android.internal.telephony.data.DataRetryManager.DataHandoverRetryEntry; +import static com.android.internal.telephony.data.DataRetryManager.DataRetryEntry; import static com.android.internal.telephony.data.DataRetryManager.DataSetupRetryEntry; import static com.google.common.truth.Truth.assertThat; @@ -25,6 +27,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.net.NetworkCapabilities; @@ -54,6 +57,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import java.lang.reflect.Field; import java.util.Collections; import java.util.List; @@ -323,15 +327,38 @@ public class DataRetryManagerTest extends TelephonyTest { } @Test - public void testDataSetupUnthrottling() { + public void testDataSetupUnthrottling() throws Exception { testDataSetupRetryNetworkSuggestedNeverRetry(); Mockito.clearInvocations(mDataRetryManagerCallbackMock); + DataNetworkController.NetworkRequestList mockNrl = Mockito.mock( + DataNetworkController.NetworkRequestList.class); + Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries"); + field.setAccessible(true); + List mDataRetryEntries = + (List) field.get(mDataRetryManagerUT); + + // schedule 2 setup retries + DataSetupRetryEntry scheduledRetry1 = new DataSetupRetryEntry.Builder<>() + .setDataProfile(mDataProfile3) + .setNetworkRequestList(mockNrl) + .setTransport(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setSetupRetryType(1) + .build(); + DataSetupRetryEntry scheduledRetry2 = new DataSetupRetryEntry.Builder<>() + .setNetworkRequestList(mockNrl) + .setDataProfile(mDataProfile3) + .setTransport(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + .setSetupRetryType(1) + .build(); + mDataRetryEntries.addAll(List.of(scheduledRetry1, scheduledRetry2)); + // unthrottle the data profile, expect previous retries of the same transport is cancelled mDataRetryManagerUT.obtainMessage(6/*EVENT_DATA_PROFILE_UNTHROTTLED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, mDataProfile3, null)) .sendToTarget(); processAllMessages(); + // check unthrottle ArgumentCaptor> throttleStatusCaptor = ArgumentCaptor.forClass(List.class); verify(mDataRetryManagerCallbackMock).onThrottleStatusChanged( @@ -353,6 +380,10 @@ public class DataRetryManagerTest extends TelephonyTest { assertThat(entry.dataProfile).isEqualTo(mDataProfile3); assertThat(entry.retryDelayMillis).isEqualTo(0); assertThat(entry.transport).isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + + // check mDataProfile3-WWAN retry is cancelled, but not the WLAN + assertThat(scheduledRetry1.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_CANCELLED); + assertThat(scheduledRetry2.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_NOT_RETRIED); } @Test @@ -390,6 +421,66 @@ public class DataRetryManagerTest extends TelephonyTest { assertThat(entry.transport).isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); } + @Test + public void testCancellingRetries() throws Exception { + DataNetworkController.NetworkRequestList mockNrl = Mockito.mock( + DataNetworkController.NetworkRequestList.class); + + // Test: setup retry + DataRetryEntry retry = new DataSetupRetryEntry.Builder<>() + .setSetupRetryType(1) + .setNetworkRequestList(mockNrl) + .setTransport(1) + .build(); + retry.setState(DataRetryEntry.RETRY_STATE_CANCELLED); + + mDataRetryManagerUT.obtainMessage(3/*EVENT_DATA_SETUP_RETRY*/, retry).sendToTarget(); + processAllMessages(); + verify(mDataRetryManagerCallbackMock, never()).onDataNetworkSetupRetry(any()); + + mDataRetryManagerUT.obtainMessage(3/*EVENT_DATA_SETUP_RETRY*/, null).sendToTarget(); + processAllMessages(); + verify(mDataRetryManagerCallbackMock, never()).onDataNetworkSetupRetry(any()); + + retry.setState(DataRetryEntry.RETRY_STATE_NOT_RETRIED); + mDataRetryManagerUT.obtainMessage(3/*EVENT_DATA_SETUP_RETRY*/, retry).sendToTarget(); + processAllMessages(); + verify(mDataRetryManagerCallbackMock, times(1)).onDataNetworkSetupRetry(any()); + + // Test: handover retry + retry = new DataHandoverRetryEntry.Builder<>().build(); + retry.setState(DataRetryEntry.RETRY_STATE_CANCELLED); + mDataRetryManagerUT.obtainMessage(4/*EVENT_DATA_HANDOVER_RETRY*/, retry).sendToTarget(); + processAllMessages(); + verify(mDataRetryManagerCallbackMock, never()).onDataNetworkHandoverRetry(any()); + + mDataRetryManagerUT.obtainMessage(4/*EVENT_DATA_HANDOVER_RETRY*/, null).sendToTarget(); + processAllMessages(); + verify(mDataRetryManagerCallbackMock, never()).onDataNetworkHandoverRetry(any()); + + retry.setState(DataRetryEntry.RETRY_STATE_NOT_RETRIED); + mDataRetryManagerUT.obtainMessage(4/*EVENT_DATA_HANDOVER_RETRY*/, retry).sendToTarget(); + processAllMessages(); + verify(mDataRetryManagerCallbackMock, times(1)) + .onDataNetworkHandoverRetry(any()); + + // Test: cancelPendingHandoverRetry + DataNetwork mockDn = Mockito.mock(DataNetwork.class); + Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries"); + field.setAccessible(true); + List mDataRetryEntries = + (List) field.get(mDataRetryManagerUT); + retry = new DataHandoverRetryEntry.Builder<>() + .setDataNetwork(mockDn) + .build(); + mDataRetryEntries.add(retry); + mDataRetryManagerUT.cancelPendingHandoverRetry(mockDn); + processAllMessages(); + + assertThat(mDataRetryManagerUT.isAnyHandoverRetryScheduled(mockDn)).isFalse(); + assertThat(retry.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_CANCELLED); + } + @Test public void testDataSetupRetryPermanentFailure() { DataSetupRetryRule retryRule = new DataSetupRetryRule( @@ -584,7 +675,7 @@ public class DataRetryManagerTest extends TelephonyTest { assertThat(entry.networkRequestList).isEqualTo(networkRequestList); assertThat(entry.appliedDataRetryRule).isEqualTo(retryRule3); - entry.setState(DataRetryManager.DataRetryEntry.RETRY_STATE_FAILED); + entry.setState(DataRetryEntry.RETRY_STATE_FAILED); } // The last fail should not trigger any retry. -- GitLab From 8c82993ebca22ced40d44e352a0595399f4e7d6c Mon Sep 17 00:00:00 2001 From: sandeepjs Date: Fri, 22 Jul 2022 09:00:19 +0000 Subject: [PATCH 059/656] Replace HashMap with LinkedHashMap to guarantee the order We are using HashMap in UiccCard to map portIndex <-> UiccPort. During download process, we expect card.getUiccPortList()[0] inside getFirstActiveEuiccPort API to always return the same UiccPort for each call. mUiccPorts.values() returns collection of unordered so the order is not guaranteed which causes card.getUiccPortList()[0] problem. So we have replaced HashMap with LinkedHashMap to guarantee the order. Test: Manual, added debug logs in getFirstActiveEuiccPort and verified it always returns same port in E+E mode Bug: 237560274 Change-Id: I722a222d2b122da873e8bb9e9d604e09a6793c7f --- src/java/com/android/internal/telephony/uicc/UiccCard.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java index 03a1257392..54324b98c5 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCard.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java @@ -31,6 +31,7 @@ import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; +import java.util.LinkedHashMap; /** * {@hide} @@ -51,7 +52,7 @@ public class UiccCard { protected String mCardId; protected boolean mIsSupportsMultipleEnabledProfiles; - protected HashMap mUiccPorts = new HashMap<>(); + protected LinkedHashMap mUiccPorts = new LinkedHashMap<>(); private HashMap mPhoneIdToPortIdx = new HashMap<>(); public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, -- GitLab From 4890940667700edb96c14aa6d709f382f64739b6 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Mon, 8 Aug 2022 22:49:36 +0000 Subject: [PATCH 060/656] Removed extra/duplicate logs Bug: 161827748 Test: Atest Verification done Change-Id: Ib971b0ad9c4dbbbe27cad825d3c3dfb46ca4428d --- .../com/android/internal/telephony/uicc/UiccController.java | 4 ++-- src/java/com/android/internal/telephony/uicc/UiccSlot.java | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 86cd278191..4743bce77d 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -760,10 +760,10 @@ public class UiccController extends Handler { IccCardStatus status = (IccCardStatus)ar.result; - logWithLocalLog("onGetIccCardStatusDone: phoneId " + index + " IccCardStatus: " + status); + logWithLocalLog("onGetIccCardStatusDone: phoneId-" + index + " IccCardStatus: " + status); int slotId = status.mSlotPortMapping.mPhysicalSlotIndex; - if (VDBG) log("onGetIccCardStatusDone: phoneId " + index + " physicalSlotIndex " + slotId); + if (VDBG) log("onGetIccCardStatusDone: phoneId-" + index + " physicalSlotIndex " + slotId); if (slotId == INVALID_SLOT_ID) { slotId = index; } diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index 20730fabe1..8de7e0108a 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -108,7 +108,6 @@ public class UiccSlot extends Handler { * Update slot. The main trigger for this is a change in the ICC Card status. */ public void update(CommandsInterface ci, IccCardStatus ics, int phoneId, int slotIndex) { - if (DBG) log("cardStatus update: " + ics.toString()); synchronized (mLock) { mPortIdxToPhoneId.put(ics.mSlotPortMapping.mPortIndex, phoneId); CardState oldState = mCardState; @@ -172,7 +171,6 @@ public class UiccSlot extends Handler { * Update slot based on IccSlotStatus. */ public void update(CommandsInterface[] ci, IccSlotStatus iss, int slotIndex) { - if (DBG) log("slotStatus update: " + iss.toString()); synchronized (mLock) { IccSimPortInfo[] simPortInfos = iss.mSimPortInfos; CardState oldState = mCardState; -- GitLab From 7ad9f93b15b83fed179c3a39cd23a0a83cb86685 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 5 Aug 2022 09:12:03 -0700 Subject: [PATCH 061/656] Removed IWLAN legacy mode support Fix: 241716913 Test: Manual Change-Id: I81fce3558ba9901858abcee43e57ba74a08e520c --- .../telephony/ServiceStateTracker.java | 65 ++--------- .../telephony/data/AccessNetworksManager.java | 103 +++--------------- .../internal/telephony/data/DataNetwork.java | 5 +- .../telephony/data/DataNetworkController.java | 20 ++-- .../telephony/data/DataRetryManager.java | 7 +- .../internal/telephony/imsphone/ImsPhone.java | 42 +------ .../internal/telephony/TelephonyTest.java | 3 - .../data/AccessNetworksManagerTest.java | 3 +- .../telephony/imsphone/ImsPhoneTest.java | 79 -------------- 9 files changed, 45 insertions(+), 282 deletions(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index d362a20d07..880d230a93 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -660,7 +660,7 @@ public class ServiceStateTracker extends Handler { mAccessNetworksManager = mPhone.getAccessNetworksManager(); mOutOfServiceSS = new ServiceState(); - mOutOfServiceSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); + mOutOfServiceSS.setOutOfService(false); for (int transportType : mAccessNetworksManager.getAvailableTransports()) { mRegStateManagers.append(transportType, new NetworkRegistrationManager( @@ -762,9 +762,9 @@ public class ServiceStateTracker extends Handler { } mSS = new ServiceState(); - mSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); + mSS.setOutOfService(false); mNewSS = new ServiceState(); - mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); + mNewSS.setOutOfService(false); mLastCellInfoReqTime = 0; mLastCellInfoList = null; mStartedGprsRegCheck = false; @@ -3302,7 +3302,7 @@ public class ServiceStateTracker extends Handler { nri = mNewSS.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); + mNewSS.setOutOfService(false); // Add the IWLAN registration info back to service state. if (nri != null) { mNewSS.addNetworkRegistrationInfo(nri); @@ -3319,7 +3319,7 @@ public class ServiceStateTracker extends Handler { nri = mNewSS.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), true); + mNewSS.setOutOfService(true); // Add the IWLAN registration info back to service state. if (nri != null) { mNewSS.addNetworkRegistrationInfo(nri); @@ -3446,14 +3446,10 @@ public class ServiceStateTracker extends Handler { mSS.getState() == ServiceState.STATE_POWER_OFF && mNewSS.getState() != ServiceState.STATE_POWER_OFF; - SparseBooleanArray hasDataAttached = new SparseBooleanArray( - mAccessNetworksManager.getAvailableTransports().length); - SparseBooleanArray hasDataDetached = new SparseBooleanArray( - mAccessNetworksManager.getAvailableTransports().length); - SparseBooleanArray hasRilDataRadioTechnologyChanged = new SparseBooleanArray( - mAccessNetworksManager.getAvailableTransports().length); - SparseBooleanArray hasDataRegStateChanged = new SparseBooleanArray( - mAccessNetworksManager.getAvailableTransports().length); + SparseBooleanArray hasDataAttached = new SparseBooleanArray(); + SparseBooleanArray hasDataDetached = new SparseBooleanArray(); + SparseBooleanArray hasRilDataRadioTechnologyChanged = new SparseBooleanArray(); + SparseBooleanArray hasDataRegStateChanged = new SparseBooleanArray(); boolean anyDataRegChanged = false; boolean anyDataRatChanged = false; boolean hasAlphaRawChanged = @@ -3642,7 +3638,7 @@ public class ServiceStateTracker extends Handler { ServiceState oldMergedSS = new ServiceState(mPhone.getServiceState()); mSS = new ServiceState(mNewSS); - mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); + mNewSS.setOutOfService(false); mCellIdentity = primaryCellIdentity; if (mSS.getState() == ServiceState.STATE_IN_SERVICE && primaryCellIdentity != null) { @@ -5518,8 +5514,7 @@ public class ServiceStateTracker extends Handler { /** - * This method adds IWLAN registration info for legacy mode devices camped on IWLAN. It also - * makes some adjustments when the device camps on IWLAN in airplane mode. + * This method makes some adjustments when the device camps on IWLAN in airplane mode. */ private void processIwlanRegistrationInfo() { if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF) { @@ -5533,7 +5528,7 @@ public class ServiceStateTracker extends Handler { } // operator info should be kept in SS String operator = mNewSS.getOperatorAlphaLong(); - mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), true); + mNewSS.setOutOfService(true); if (resetIwlanRatVal) { mNewSS.setDataRegState(ServiceState.STATE_IN_SERVICE); NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() @@ -5543,17 +5538,6 @@ public class ServiceStateTracker extends Handler { .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) .build(); mNewSS.addNetworkRegistrationInfo(nri); - if (mAccessNetworksManager.isInLegacyMode()) { - // If in legacy mode, simulate the behavior that IWLAN registration info - // is reported through WWAN transport. - nri = new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - mNewSS.addNetworkRegistrationInfo(nri); - } mNewSS.setOperatorAlphaLong(operator); // Since it's in airplane mode, cellular must be out of service. The only possible // transport for data to go through is the IWLAN transport. Setting this to true @@ -5563,31 +5547,6 @@ public class ServiceStateTracker extends Handler { } return; } - - // If the device operates in legacy mode and camps on IWLAN, modem reports IWLAN as a RAT - // through WWAN registration info. To be consistent with the behavior with AP-assisted mode, - // we manually make a WLAN registration info for clients to consume. In this scenario, - // both WWAN and WLAN registration info are the IWLAN registration info and that's the - // unfortunate limitation we have when the device operates in legacy mode. In AP-assisted - // mode, the WWAN registration will correctly report the actual cellular registration info - // when the device camps on IWLAN. - if (mAccessNetworksManager.isInLegacyMode()) { - NetworkRegistrationInfo wwanNri = mNewSS.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - if (wwanNri != null && wwanNri.getAccessNetworkTechnology() - == TelephonyManager.NETWORK_TYPE_IWLAN) { - NetworkRegistrationInfo wlanNri = new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setRegistrationState(wwanNri.getInitialRegistrationState()) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRejectCause(wwanNri.getRejectCause()) - .setEmergencyOnly(wwanNri.isEmergencyEnabled()) - .setAvailableServices(wwanNri.getAvailableServices()) - .build(); - mNewSS.addNetworkRegistrationInfo(wlanNri); - } - } } /** diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index 57b36022fc..e17b419e4a 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -19,7 +19,6 @@ package com.android.internal.telephony.data; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.StringDef; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -34,7 +33,6 @@ import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; -import android.os.SystemProperties; import android.os.UserHandle; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; @@ -56,14 +54,11 @@ import android.util.LocalLog; import android.util.SparseArray; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.RIL; import com.android.internal.telephony.SlidingWindowEventCounter; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -81,35 +76,6 @@ import java.util.stream.Collectors; */ public class AccessNetworksManager extends Handler { private static final boolean DBG = false; - public static final String SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE = - "ro.telephony.iwlan_operation_mode"; - - @Retention(RetentionPolicy.SOURCE) - @StringDef(prefix = {"IWLAN_OPERATION_MODE_"}, - value = { - IWLAN_OPERATION_MODE_DEFAULT, - IWLAN_OPERATION_MODE_LEGACY, - IWLAN_OPERATION_MODE_AP_ASSISTED}) - public @interface IwlanOperationMode {} - - /** - * IWLAN default mode. On device that has IRadio 1.4 or above, it means - * {@link #IWLAN_OPERATION_MODE_AP_ASSISTED}. On device that has IRadio 1.3 or below, it means - * {@link #IWLAN_OPERATION_MODE_LEGACY}. - */ - public static final String IWLAN_OPERATION_MODE_DEFAULT = "default"; - - /** - * IWLAN legacy mode. IWLAN is completely handled by the modem, and when the device is on - * IWLAN, modem reports IWLAN as a RAT. - */ - public static final String IWLAN_OPERATION_MODE_LEGACY = "legacy"; - - /** - * IWLAN application processor assisted mode. IWLAN is handled by the bound IWLAN data service - * and network service separately. - */ - public static final String IWLAN_OPERATION_MODE_AP_ASSISTED = "AP-assisted"; /** * The counters to detect frequent QNS attempt to change preferred network transport by ApnType. @@ -392,28 +358,19 @@ public class AccessNetworksManager extends Handler { Context.CARRIER_CONFIG_SERVICE); mLogTag = "ANM-" + mPhone.getPhoneId(); mApnTypeToQnsChangeNetworkCounter = new SparseArray<>(); - - if (isInLegacyMode()) { - log("operates in legacy mode."); - // For legacy mode, WWAN is the only transport to handle all data connections, even - // the IWLAN ones. - mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN}; - } else { - log("operates in AP-assisted mode."); - mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - try { - Context contextAsUser = phone.getContext().createPackageContextAsUser( - phone.getContext().getPackageName(), 0, UserHandle.ALL); - contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter, - null /* broadcastPermission */, null); - } catch (PackageManager.NameNotFoundException e) { - loge("Package name not found: ", e); - } - bindQualifiedNetworksService(); + mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + try { + Context contextAsUser = phone.getContext().createPackageContextAsUser( + phone.getContext().getPackageName(), 0, UserHandle.ALL); + contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter, + null /* broadcastPermission */, null); + } catch (PackageManager.NameNotFoundException e) { + loge("Package name not found: ", e); } + bindQualifiedNetworksService(); // Using post to delay the registering because data retry manager and data config // manager instances are created later than access networks manager. @@ -516,8 +473,7 @@ public class AccessNetworksManager extends Handler { /** * Get the qualified network service package. * - * @return package name of the qualified networks service package. Return empty string when in - * legacy mode (i.e. Dedicated IWLAN data/network service is not supported). + * @return package name of the qualified networks service package. */ private String getQualifiedNetworksServicePackageName() { // Read package name from the resource @@ -594,30 +550,9 @@ public class AccessNetworksManager extends Handler { } /** - * @return {@code true} if the device operates in legacy mode, otherwise {@code false}. + * @return The available transports. */ - public boolean isInLegacyMode() { - // Get IWLAN operation mode from the system property. If the system property is configured - // to default or not configured, the mode is tied to IRadio version. For 1.4 or above, it's - // AP-assisted mode, for 1.3 or below, it's legacy mode. - String mode = SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE); - - if (mode.equals(IWLAN_OPERATION_MODE_AP_ASSISTED)) { - return false; - } else if (mode.equals(IWLAN_OPERATION_MODE_LEGACY)) { - return true; - } - - return mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_4); - } - - /** - * @return The available transports. Note that on legacy devices, the only available transport - * would be WWAN only. If the device is configured as AP-assisted mode, the available transport - * will always be WWAN and WLAN (even if the device is not camped on IWLAN). - * See {@link #isInLegacyMode()} for mode details. - */ - public synchronized @NonNull int[] getAvailableTransports() { + public @NonNull int[] getAvailableTransports() { return mAvailableTransports; } @@ -652,11 +587,6 @@ public class AccessNetworksManager extends Handler { * @return The preferred transport. */ public @TransportType int getPreferredTransport(@ApnType int apnType) { - // In legacy mode, always preferred on cellular. - if (isInLegacyMode()) { - return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - } - return mPreferredTransports.get(apnType) == null ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mPreferredTransports.get(apnType); } @@ -759,9 +689,6 @@ public class AccessNetworksManager extends Handler { } pw.decreaseIndent(); - pw.println("isInLegacy=" + isInLegacyMode()); - pw.println("IWLAN operation mode=" - + SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE)); pw.println("Local logs="); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 5b6b8bc355..8d26f50d88 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -890,8 +890,9 @@ public class DataNetwork extends StateMachine { mDataAllowedReason = dataAllowedReason; dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); mAttachedNetworkRequestList.addAll(networkRequestList); - mCid.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, INVALID_CID); - mCid.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, INVALID_CID); + for (int transportType : mAccessNetworksManager.getAvailableTransports()) { + mCid.put(transportType, INVALID_CID); + } mTcpBufferSizes = mDataConfigManager.getDefaultTcpConfigString(); mTelephonyDisplayInfo = mPhone.getDisplayInfoController().getTelephonyDisplayInfo(); diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 1cdbdfdb78..6d2970267e 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -769,13 +769,11 @@ public class DataNetworkController extends Handler { log("DataNetworkController created."); mAccessNetworksManager = phone.getAccessNetworksManager(); - mDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - new DataServiceManager(mPhone, looper, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); - if (!mAccessNetworksManager.isInLegacyMode()) { - mDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, - new DataServiceManager(mPhone, looper, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN)); + for (int transport : mAccessNetworksManager.getAvailableTransports()) { + mDataServiceManagers.put(transport, new DataServiceManager(mPhone, looper, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); } + mDataConfigManager = new DataConfigManager(mPhone, looper); // ========== Anomaly counters ========== @@ -978,12 +976,10 @@ public class DataNetworkController extends Handler { mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) .registerForServiceBindingChanged(this, EVENT_DATA_SERVICE_BINDING_CHANGED); - if (!mAccessNetworksManager.isInLegacyMode()) { - mPhone.getServiceStateTracker().registerForServiceStateChanged(this, - EVENT_SERVICE_STATE_CHANGED); - mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .registerForServiceBindingChanged(this, EVENT_DATA_SERVICE_BINDING_CHANGED); - } + mPhone.getServiceStateTracker().registerForServiceStateChanged(this, + EVENT_SERVICE_STATE_CHANGED); + mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + .registerForServiceBindingChanged(this, EVENT_DATA_SERVICE_BINDING_CHANGED); mPhone.getContext().getSystemService(TelephonyRegistryManager.class) .addOnSubscriptionsChangedListener(new OnSubscriptionsChangedListener() { diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index e8e694d121..8eff1573ea 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -935,10 +935,9 @@ public class DataRetryManager extends Handler { DataRetryManager.this.onCarrierConfigUpdated(); } }); - mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .registerForApnUnthrottled(this, EVENT_DATA_PROFILE_UNTHROTTLED); - if (!mPhone.getAccessNetworksManager().isInLegacyMode()) { - mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + + for (int transport : mPhone.getAccessNetworksManager().getAvailableTransports()) { + mDataServiceManagers.get(transport) .registerForApnUnthrottled(this, EVENT_DATA_PROFILE_UNTHROTTLED); } mDataProfileManager.registerCallback(new DataProfileManagerCallback(this::post) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 090cd27db7..e46ef85bb8 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -457,11 +457,7 @@ public class ImsPhone extends ImsPhoneBase { mCT.registerPhoneStateListener(mExternalCallTracker); mExternalCallTracker.setCallPuller(mCT); - boolean legacyMode = true; - if (mDefaultPhone.getAccessNetworksManager() != null) { - legacyMode = mDefaultPhone.getAccessNetworksManager().isInLegacyMode(); - } - mSS.setOutOfService(legacyMode, false); + mSS.setOutOfService(false); mPhoneId = mDefaultPhone.getPhoneId(); @@ -2370,7 +2366,7 @@ public class ImsPhone extends ImsPhoneBase { /** * Update roaming state and WFC mode in the following situations: * 1) voice is in service. - * 2) data is in service and it is not IWLAN (if in legacy mode). + * 2) data is in service. * @param ss non-null ServiceState */ private void updateRoamingState(ServiceState ss) { @@ -2391,15 +2387,7 @@ public class ImsPhone extends ImsPhoneBase { logi("updateRoamingState: we are not IN_SERVICE, ignoring roaming change."); return; } - // We ignore roaming changes when moving to IWLAN because it always sets the roaming - // mode to home and masks the actual cellular roaming status if voice is not registered. If - // we just moved to IWLAN because WFC roaming mode is IWLAN preferred and WFC home mode is - // cell preferred, we can get into a condition where the modem keeps bouncing between - // IWLAN->cell->IWLAN->cell... - if (isCsNotInServiceAndPsWwanReportingWlan(ss)) { - logi("updateRoamingState: IWLAN masking roaming, ignore roaming change."); - return; - } + if (mCT.getState() == PhoneConstants.State.IDLE) { if (DBG) logd("updateRoamingState now: " + newRoamingState); mLastKnownRoamingState = newRoamingState; @@ -2418,30 +2406,6 @@ public class ImsPhone extends ImsPhoneBase { } } - /** - * In legacy mode, data registration will report IWLAN when we are using WLAN for data, - * effectively masking the true roaming state of the device if voice is not registered. - * - * @return true if we are reporting not in service for CS domain over WWAN transport and WLAN - * for PS domain over WWAN transport. - */ - private boolean isCsNotInServiceAndPsWwanReportingWlan(ServiceState ss) { - // We can not get into this condition if we are in AP-Assisted mode. - if (mDefaultPhone.getAccessNetworksManager() == null - || !mDefaultPhone.getAccessNetworksManager().isInLegacyMode()) { - return false; - } - NetworkRegistrationInfo csInfo = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - NetworkRegistrationInfo psInfo = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - // We will return roaming state correctly if the CS domain is in service because - // ss.getRoaming() returns isVoiceRoaming||isDataRoaming result and isDataRoaming==false - // when the modem reports IWLAN RAT. - return psInfo != null && csInfo != null && !csInfo.isInService() - && psInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN; - } - public RegistrationManager.RegistrationCallback getImsMmTelRegistrationCallback() { return mImsMmTelRegistrationHelper.getCallback(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 6cb7464ff0..ac11705181 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -717,9 +717,6 @@ public abstract class TelephonyTest { mServiceManagerMockedServices.put("package", mMockPackageManager); mServiceManagerMockedServices.put("legacy_permission", mMockLegacyPermissionManager); logd("mMockLegacyPermissionManager replaced"); - doReturn(new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) - .when(mAccessNetworksManager).getAvailableTransports(); doReturn(new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) .when(mAccessNetworksManager).getAvailableTransports(); 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 a66d4ab157..5f72e636e5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java @@ -18,7 +18,6 @@ package com.android.internal.telephony.data; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -115,7 +114,7 @@ public class AccessNetworksManagerTest extends TelephonyTest { processAllMessages(); replaceInstance(AccessNetworksManager.class, "mDataConfigManager", mAccessNetworksManager, mMockedDataConfigManager); - assumeFalse(mAccessNetworksManager.isInLegacyMode()); + logd("-setUp"); } 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 17a63ddfce..bee3739e2b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -734,7 +734,6 @@ public class ImsPhoneTest extends TelephonyTest { @Test @SmallTest public void testRoamingToAirplanModeIwlanInService() throws Exception { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); doReturn(true).when(mPhone).isRadioOn(); @@ -762,7 +761,6 @@ public class ImsPhoneTest extends TelephonyTest { @Test @SmallTest public void testRoamingToOutOfService() throws Exception { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); doReturn(true).when(mPhone).isRadioOn(); @@ -785,83 +783,6 @@ public class ImsPhoneTest extends TelephonyTest { verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean()); } - @Test - @SmallTest - public void testRoamingChangeForLteInLegacyMode() throws Exception { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); - doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); - doReturn(true).when(mPhone).isRadioOn(); - - //roaming - data registration only on LTE - Message m = getServiceStateChangedMessage(getServiceStateDataOnly( - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true)); - // Inject the message synchronously instead of waiting for the thread to do it. - mImsPhoneUT.handleMessage(m); - m.recycle(); - - verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true)); - - // not roaming - data registration on LTE - m = getServiceStateChangedMessage(getServiceStateDataOnly( - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, false)); - mImsPhoneUT.handleMessage(m); - m.recycle(); - - verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(false)); - } - - @Test - @SmallTest - public void testDataOnlyRoamingCellToIWlanInLegacyMode() throws Exception { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); - doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); - doReturn(true).when(mPhone).isRadioOn(); - - //roaming - data registration only on LTE - Message m = getServiceStateChangedMessage(getServiceStateDataOnly( - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true)); - // Inject the message synchronously instead of waiting for the thread to do it. - mImsPhoneUT.handleMessage(m); - m.recycle(); - - verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true)); - - // not roaming - data registration onto IWLAN - m = getServiceStateChangedMessage(getServiceStateDataOnly( - ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, ServiceState.STATE_IN_SERVICE, false)); - mImsPhoneUT.handleMessage(m); - m.recycle(); - - // Verify that it hasn't been called again. - verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean()); - } - - @Test - @SmallTest - public void testCellVoiceDataChangeToWlanInLegacyMode() throws Exception { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); - doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); - doReturn(true).when(mPhone).isRadioOn(); - - //roaming - voice/data registration on LTE - ServiceState ss = getServiceStateDataAndVoice( - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true); - Message m = getServiceStateChangedMessage(ss); - // Inject the message synchronously instead of waiting for the thread to do it. - mImsPhoneUT.handleMessage(m); - - verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true)); - - // roaming - voice LTE, data registration onto IWLAN - modifyServiceStateData(ss, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, - ServiceState.STATE_IN_SERVICE, false); - mImsPhoneUT.handleMessage(m); - m.recycle(); - - // Verify that it hasn't been called again. - verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean()); - } - @Test public void testNonNullTrackersInImsPhone() throws Exception { assertNotNull(mImsPhoneUT.getEmergencyNumberTracker()); -- GitLab From 17780de20abed1ccb84126c858c226da92ef591d Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 10 Aug 2022 07:33:25 +0000 Subject: [PATCH 062/656] Revert "Removed IWLAN legacy mode support" Revert submission 19536179-iwlan_legacy_removal Reason for revert: b/241947400 Reverted Changes: Ie0efe54c5:Removed IWLAN legacy mode support Id899b53ac:Removed IWLAN legacy mode support I81fce3558:Removed IWLAN legacy mode support Change-Id: I9cf7ff35bc5cc9d1cd394f96b7ba576dc96a5624 --- .../telephony/ServiceStateTracker.java | 65 +++++++++-- .../telephony/data/AccessNetworksManager.java | 103 +++++++++++++++--- .../internal/telephony/data/DataNetwork.java | 5 +- .../telephony/data/DataNetworkController.java | 20 ++-- .../telephony/data/DataRetryManager.java | 7 +- .../internal/telephony/imsphone/ImsPhone.java | 42 ++++++- .../internal/telephony/TelephonyTest.java | 3 + .../data/AccessNetworksManagerTest.java | 3 +- .../telephony/imsphone/ImsPhoneTest.java | 79 ++++++++++++++ 9 files changed, 282 insertions(+), 45 deletions(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 880d230a93..d362a20d07 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -660,7 +660,7 @@ public class ServiceStateTracker extends Handler { mAccessNetworksManager = mPhone.getAccessNetworksManager(); mOutOfServiceSS = new ServiceState(); - mOutOfServiceSS.setOutOfService(false); + mOutOfServiceSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); for (int transportType : mAccessNetworksManager.getAvailableTransports()) { mRegStateManagers.append(transportType, new NetworkRegistrationManager( @@ -762,9 +762,9 @@ public class ServiceStateTracker extends Handler { } mSS = new ServiceState(); - mSS.setOutOfService(false); + mSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); mNewSS = new ServiceState(); - mNewSS.setOutOfService(false); + mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); mLastCellInfoReqTime = 0; mLastCellInfoList = null; mStartedGprsRegCheck = false; @@ -3302,7 +3302,7 @@ public class ServiceStateTracker extends Handler { nri = mNewSS.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - mNewSS.setOutOfService(false); + mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); // Add the IWLAN registration info back to service state. if (nri != null) { mNewSS.addNetworkRegistrationInfo(nri); @@ -3319,7 +3319,7 @@ public class ServiceStateTracker extends Handler { nri = mNewSS.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - mNewSS.setOutOfService(true); + mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), true); // Add the IWLAN registration info back to service state. if (nri != null) { mNewSS.addNetworkRegistrationInfo(nri); @@ -3446,10 +3446,14 @@ public class ServiceStateTracker extends Handler { mSS.getState() == ServiceState.STATE_POWER_OFF && mNewSS.getState() != ServiceState.STATE_POWER_OFF; - SparseBooleanArray hasDataAttached = new SparseBooleanArray(); - SparseBooleanArray hasDataDetached = new SparseBooleanArray(); - SparseBooleanArray hasRilDataRadioTechnologyChanged = new SparseBooleanArray(); - SparseBooleanArray hasDataRegStateChanged = new SparseBooleanArray(); + SparseBooleanArray hasDataAttached = new SparseBooleanArray( + mAccessNetworksManager.getAvailableTransports().length); + SparseBooleanArray hasDataDetached = new SparseBooleanArray( + mAccessNetworksManager.getAvailableTransports().length); + SparseBooleanArray hasRilDataRadioTechnologyChanged = new SparseBooleanArray( + mAccessNetworksManager.getAvailableTransports().length); + SparseBooleanArray hasDataRegStateChanged = new SparseBooleanArray( + mAccessNetworksManager.getAvailableTransports().length); boolean anyDataRegChanged = false; boolean anyDataRatChanged = false; boolean hasAlphaRawChanged = @@ -3638,7 +3642,7 @@ public class ServiceStateTracker extends Handler { ServiceState oldMergedSS = new ServiceState(mPhone.getServiceState()); mSS = new ServiceState(mNewSS); - mNewSS.setOutOfService(false); + mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); mCellIdentity = primaryCellIdentity; if (mSS.getState() == ServiceState.STATE_IN_SERVICE && primaryCellIdentity != null) { @@ -5514,7 +5518,8 @@ public class ServiceStateTracker extends Handler { /** - * This method makes some adjustments when the device camps on IWLAN in airplane mode. + * This method adds IWLAN registration info for legacy mode devices camped on IWLAN. It also + * makes some adjustments when the device camps on IWLAN in airplane mode. */ private void processIwlanRegistrationInfo() { if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF) { @@ -5528,7 +5533,7 @@ public class ServiceStateTracker extends Handler { } // operator info should be kept in SS String operator = mNewSS.getOperatorAlphaLong(); - mNewSS.setOutOfService(true); + mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), true); if (resetIwlanRatVal) { mNewSS.setDataRegState(ServiceState.STATE_IN_SERVICE); NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() @@ -5538,6 +5543,17 @@ public class ServiceStateTracker extends Handler { .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) .build(); mNewSS.addNetworkRegistrationInfo(nri); + if (mAccessNetworksManager.isInLegacyMode()) { + // If in legacy mode, simulate the behavior that IWLAN registration info + // is reported through WWAN transport. + nri = new NetworkRegistrationInfo.Builder() + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + mNewSS.addNetworkRegistrationInfo(nri); + } mNewSS.setOperatorAlphaLong(operator); // Since it's in airplane mode, cellular must be out of service. The only possible // transport for data to go through is the IWLAN transport. Setting this to true @@ -5547,6 +5563,31 @@ public class ServiceStateTracker extends Handler { } return; } + + // If the device operates in legacy mode and camps on IWLAN, modem reports IWLAN as a RAT + // through WWAN registration info. To be consistent with the behavior with AP-assisted mode, + // we manually make a WLAN registration info for clients to consume. In this scenario, + // both WWAN and WLAN registration info are the IWLAN registration info and that's the + // unfortunate limitation we have when the device operates in legacy mode. In AP-assisted + // mode, the WWAN registration will correctly report the actual cellular registration info + // when the device camps on IWLAN. + if (mAccessNetworksManager.isInLegacyMode()) { + NetworkRegistrationInfo wwanNri = mNewSS.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (wwanNri != null && wwanNri.getAccessNetworkTechnology() + == TelephonyManager.NETWORK_TYPE_IWLAN) { + NetworkRegistrationInfo wlanNri = new NetworkRegistrationInfo.Builder() + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setRegistrationState(wwanNri.getInitialRegistrationState()) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) + .setRejectCause(wwanNri.getRejectCause()) + .setEmergencyOnly(wwanNri.isEmergencyEnabled()) + .setAvailableServices(wwanNri.getAvailableServices()) + .build(); + mNewSS.addNetworkRegistrationInfo(wlanNri); + } + } } /** diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index e17b419e4a..57b36022fc 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -19,6 +19,7 @@ package com.android.internal.telephony.data; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.StringDef; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -33,6 +34,7 @@ import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; +import android.os.SystemProperties; import android.os.UserHandle; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; @@ -54,11 +56,14 @@ import android.util.LocalLog; import android.util.SparseArray; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.RIL; import com.android.internal.telephony.SlidingWindowEventCounter; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -76,6 +81,35 @@ import java.util.stream.Collectors; */ public class AccessNetworksManager extends Handler { private static final boolean DBG = false; + public static final String SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE = + "ro.telephony.iwlan_operation_mode"; + + @Retention(RetentionPolicy.SOURCE) + @StringDef(prefix = {"IWLAN_OPERATION_MODE_"}, + value = { + IWLAN_OPERATION_MODE_DEFAULT, + IWLAN_OPERATION_MODE_LEGACY, + IWLAN_OPERATION_MODE_AP_ASSISTED}) + public @interface IwlanOperationMode {} + + /** + * IWLAN default mode. On device that has IRadio 1.4 or above, it means + * {@link #IWLAN_OPERATION_MODE_AP_ASSISTED}. On device that has IRadio 1.3 or below, it means + * {@link #IWLAN_OPERATION_MODE_LEGACY}. + */ + public static final String IWLAN_OPERATION_MODE_DEFAULT = "default"; + + /** + * IWLAN legacy mode. IWLAN is completely handled by the modem, and when the device is on + * IWLAN, modem reports IWLAN as a RAT. + */ + public static final String IWLAN_OPERATION_MODE_LEGACY = "legacy"; + + /** + * IWLAN application processor assisted mode. IWLAN is handled by the bound IWLAN data service + * and network service separately. + */ + public static final String IWLAN_OPERATION_MODE_AP_ASSISTED = "AP-assisted"; /** * The counters to detect frequent QNS attempt to change preferred network transport by ApnType. @@ -358,19 +392,28 @@ public class AccessNetworksManager extends Handler { Context.CARRIER_CONFIG_SERVICE); mLogTag = "ANM-" + mPhone.getPhoneId(); mApnTypeToQnsChangeNetworkCounter = new SparseArray<>(); - mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - try { - Context contextAsUser = phone.getContext().createPackageContextAsUser( - phone.getContext().getPackageName(), 0, UserHandle.ALL); - contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter, - null /* broadcastPermission */, null); - } catch (PackageManager.NameNotFoundException e) { - loge("Package name not found: ", e); + + if (isInLegacyMode()) { + log("operates in legacy mode."); + // For legacy mode, WWAN is the only transport to handle all data connections, even + // the IWLAN ones. + mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN}; + } else { + log("operates in AP-assisted mode."); + mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + try { + Context contextAsUser = phone.getContext().createPackageContextAsUser( + phone.getContext().getPackageName(), 0, UserHandle.ALL); + contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter, + null /* broadcastPermission */, null); + } catch (PackageManager.NameNotFoundException e) { + loge("Package name not found: ", e); + } + bindQualifiedNetworksService(); } - bindQualifiedNetworksService(); // Using post to delay the registering because data retry manager and data config // manager instances are created later than access networks manager. @@ -473,7 +516,8 @@ public class AccessNetworksManager extends Handler { /** * Get the qualified network service package. * - * @return package name of the qualified networks service package. + * @return package name of the qualified networks service package. Return empty string when in + * legacy mode (i.e. Dedicated IWLAN data/network service is not supported). */ private String getQualifiedNetworksServicePackageName() { // Read package name from the resource @@ -550,9 +594,30 @@ public class AccessNetworksManager extends Handler { } /** - * @return The available transports. + * @return {@code true} if the device operates in legacy mode, otherwise {@code false}. */ - public @NonNull int[] getAvailableTransports() { + public boolean isInLegacyMode() { + // Get IWLAN operation mode from the system property. If the system property is configured + // to default or not configured, the mode is tied to IRadio version. For 1.4 or above, it's + // AP-assisted mode, for 1.3 or below, it's legacy mode. + String mode = SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE); + + if (mode.equals(IWLAN_OPERATION_MODE_AP_ASSISTED)) { + return false; + } else if (mode.equals(IWLAN_OPERATION_MODE_LEGACY)) { + return true; + } + + return mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_4); + } + + /** + * @return The available transports. Note that on legacy devices, the only available transport + * would be WWAN only. If the device is configured as AP-assisted mode, the available transport + * will always be WWAN and WLAN (even if the device is not camped on IWLAN). + * See {@link #isInLegacyMode()} for mode details. + */ + public synchronized @NonNull int[] getAvailableTransports() { return mAvailableTransports; } @@ -587,6 +652,11 @@ public class AccessNetworksManager extends Handler { * @return The preferred transport. */ public @TransportType int getPreferredTransport(@ApnType int apnType) { + // In legacy mode, always preferred on cellular. + if (isInLegacyMode()) { + return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; + } + return mPreferredTransports.get(apnType) == null ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mPreferredTransports.get(apnType); } @@ -689,6 +759,9 @@ public class AccessNetworksManager extends Handler { } pw.decreaseIndent(); + pw.println("isInLegacy=" + isInLegacyMode()); + pw.println("IWLAN operation mode=" + + SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE)); pw.println("Local logs="); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 8d26f50d88..5b6b8bc355 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -890,9 +890,8 @@ public class DataNetwork extends StateMachine { mDataAllowedReason = dataAllowedReason; dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); mAttachedNetworkRequestList.addAll(networkRequestList); - for (int transportType : mAccessNetworksManager.getAvailableTransports()) { - mCid.put(transportType, INVALID_CID); - } + mCid.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, INVALID_CID); + mCid.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, INVALID_CID); mTcpBufferSizes = mDataConfigManager.getDefaultTcpConfigString(); mTelephonyDisplayInfo = mPhone.getDisplayInfoController().getTelephonyDisplayInfo(); diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 6d2970267e..1cdbdfdb78 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -769,11 +769,13 @@ public class DataNetworkController extends Handler { log("DataNetworkController created."); mAccessNetworksManager = phone.getAccessNetworksManager(); - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - mDataServiceManagers.put(transport, new DataServiceManager(mPhone, looper, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + mDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + new DataServiceManager(mPhone, looper, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + if (!mAccessNetworksManager.isInLegacyMode()) { + mDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, + new DataServiceManager(mPhone, looper, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN)); } - mDataConfigManager = new DataConfigManager(mPhone, looper); // ========== Anomaly counters ========== @@ -976,10 +978,12 @@ public class DataNetworkController extends Handler { mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) .registerForServiceBindingChanged(this, EVENT_DATA_SERVICE_BINDING_CHANGED); - mPhone.getServiceStateTracker().registerForServiceStateChanged(this, - EVENT_SERVICE_STATE_CHANGED); - mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .registerForServiceBindingChanged(this, EVENT_DATA_SERVICE_BINDING_CHANGED); + if (!mAccessNetworksManager.isInLegacyMode()) { + mPhone.getServiceStateTracker().registerForServiceStateChanged(this, + EVENT_SERVICE_STATE_CHANGED); + mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + .registerForServiceBindingChanged(this, EVENT_DATA_SERVICE_BINDING_CHANGED); + } mPhone.getContext().getSystemService(TelephonyRegistryManager.class) .addOnSubscriptionsChangedListener(new OnSubscriptionsChangedListener() { diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index 8eff1573ea..e8e694d121 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -935,9 +935,10 @@ public class DataRetryManager extends Handler { DataRetryManager.this.onCarrierConfigUpdated(); } }); - - for (int transport : mPhone.getAccessNetworksManager().getAvailableTransports()) { - mDataServiceManagers.get(transport) + mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .registerForApnUnthrottled(this, EVENT_DATA_PROFILE_UNTHROTTLED); + if (!mPhone.getAccessNetworksManager().isInLegacyMode()) { + mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) .registerForApnUnthrottled(this, EVENT_DATA_PROFILE_UNTHROTTLED); } mDataProfileManager.registerCallback(new DataProfileManagerCallback(this::post) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index e46ef85bb8..090cd27db7 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -457,7 +457,11 @@ public class ImsPhone extends ImsPhoneBase { mCT.registerPhoneStateListener(mExternalCallTracker); mExternalCallTracker.setCallPuller(mCT); - mSS.setOutOfService(false); + boolean legacyMode = true; + if (mDefaultPhone.getAccessNetworksManager() != null) { + legacyMode = mDefaultPhone.getAccessNetworksManager().isInLegacyMode(); + } + mSS.setOutOfService(legacyMode, false); mPhoneId = mDefaultPhone.getPhoneId(); @@ -2366,7 +2370,7 @@ public class ImsPhone extends ImsPhoneBase { /** * Update roaming state and WFC mode in the following situations: * 1) voice is in service. - * 2) data is in service. + * 2) data is in service and it is not IWLAN (if in legacy mode). * @param ss non-null ServiceState */ private void updateRoamingState(ServiceState ss) { @@ -2387,7 +2391,15 @@ public class ImsPhone extends ImsPhoneBase { logi("updateRoamingState: we are not IN_SERVICE, ignoring roaming change."); return; } - + // We ignore roaming changes when moving to IWLAN because it always sets the roaming + // mode to home and masks the actual cellular roaming status if voice is not registered. If + // we just moved to IWLAN because WFC roaming mode is IWLAN preferred and WFC home mode is + // cell preferred, we can get into a condition where the modem keeps bouncing between + // IWLAN->cell->IWLAN->cell... + if (isCsNotInServiceAndPsWwanReportingWlan(ss)) { + logi("updateRoamingState: IWLAN masking roaming, ignore roaming change."); + return; + } if (mCT.getState() == PhoneConstants.State.IDLE) { if (DBG) logd("updateRoamingState now: " + newRoamingState); mLastKnownRoamingState = newRoamingState; @@ -2406,6 +2418,30 @@ public class ImsPhone extends ImsPhoneBase { } } + /** + * In legacy mode, data registration will report IWLAN when we are using WLAN for data, + * effectively masking the true roaming state of the device if voice is not registered. + * + * @return true if we are reporting not in service for CS domain over WWAN transport and WLAN + * for PS domain over WWAN transport. + */ + private boolean isCsNotInServiceAndPsWwanReportingWlan(ServiceState ss) { + // We can not get into this condition if we are in AP-Assisted mode. + if (mDefaultPhone.getAccessNetworksManager() == null + || !mDefaultPhone.getAccessNetworksManager().isInLegacyMode()) { + return false; + } + NetworkRegistrationInfo csInfo = ss.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + NetworkRegistrationInfo psInfo = ss.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + // We will return roaming state correctly if the CS domain is in service because + // ss.getRoaming() returns isVoiceRoaming||isDataRoaming result and isDataRoaming==false + // when the modem reports IWLAN RAT. + return psInfo != null && csInfo != null && !csInfo.isInService() + && psInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN; + } + public RegistrationManager.RegistrationCallback getImsMmTelRegistrationCallback() { return mImsMmTelRegistrationHelper.getCallback(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index ac11705181..6cb7464ff0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -717,6 +717,9 @@ public abstract class TelephonyTest { mServiceManagerMockedServices.put("package", mMockPackageManager); mServiceManagerMockedServices.put("legacy_permission", mMockLegacyPermissionManager); logd("mMockLegacyPermissionManager replaced"); + doReturn(new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) + .when(mAccessNetworksManager).getAvailableTransports(); doReturn(new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) .when(mAccessNetworksManager).getAvailableTransports(); 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 5f72e636e5..a66d4ab157 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony.data; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -114,7 +115,7 @@ public class AccessNetworksManagerTest extends TelephonyTest { processAllMessages(); replaceInstance(AccessNetworksManager.class, "mDataConfigManager", mAccessNetworksManager, mMockedDataConfigManager); - + assumeFalse(mAccessNetworksManager.isInLegacyMode()); logd("-setUp"); } 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 bee3739e2b..17a63ddfce 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -734,6 +734,7 @@ public class ImsPhoneTest extends TelephonyTest { @Test @SmallTest public void testRoamingToAirplanModeIwlanInService() throws Exception { + doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); doReturn(true).when(mPhone).isRadioOn(); @@ -761,6 +762,7 @@ public class ImsPhoneTest extends TelephonyTest { @Test @SmallTest public void testRoamingToOutOfService() throws Exception { + doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); doReturn(true).when(mPhone).isRadioOn(); @@ -783,6 +785,83 @@ public class ImsPhoneTest extends TelephonyTest { verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean()); } + @Test + @SmallTest + public void testRoamingChangeForLteInLegacyMode() throws Exception { + doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); + doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); + doReturn(true).when(mPhone).isRadioOn(); + + //roaming - data registration only on LTE + Message m = getServiceStateChangedMessage(getServiceStateDataOnly( + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true)); + // Inject the message synchronously instead of waiting for the thread to do it. + mImsPhoneUT.handleMessage(m); + m.recycle(); + + verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true)); + + // not roaming - data registration on LTE + m = getServiceStateChangedMessage(getServiceStateDataOnly( + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, false)); + mImsPhoneUT.handleMessage(m); + m.recycle(); + + verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(false)); + } + + @Test + @SmallTest + public void testDataOnlyRoamingCellToIWlanInLegacyMode() throws Exception { + doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); + doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); + doReturn(true).when(mPhone).isRadioOn(); + + //roaming - data registration only on LTE + Message m = getServiceStateChangedMessage(getServiceStateDataOnly( + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true)); + // Inject the message synchronously instead of waiting for the thread to do it. + mImsPhoneUT.handleMessage(m); + m.recycle(); + + verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true)); + + // not roaming - data registration onto IWLAN + m = getServiceStateChangedMessage(getServiceStateDataOnly( + ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, ServiceState.STATE_IN_SERVICE, false)); + mImsPhoneUT.handleMessage(m); + m.recycle(); + + // Verify that it hasn't been called again. + verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean()); + } + + @Test + @SmallTest + public void testCellVoiceDataChangeToWlanInLegacyMode() throws Exception { + doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); + doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); + doReturn(true).when(mPhone).isRadioOn(); + + //roaming - voice/data registration on LTE + ServiceState ss = getServiceStateDataAndVoice( + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true); + Message m = getServiceStateChangedMessage(ss); + // Inject the message synchronously instead of waiting for the thread to do it. + mImsPhoneUT.handleMessage(m); + + verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true)); + + // roaming - voice LTE, data registration onto IWLAN + modifyServiceStateData(ss, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, + ServiceState.STATE_IN_SERVICE, false); + mImsPhoneUT.handleMessage(m); + m.recycle(); + + // Verify that it hasn't been called again. + verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean()); + } + @Test public void testNonNullTrackersInImsPhone() throws Exception { assertNotNull(mImsPhoneUT.getEmergencyNumberTracker()); -- GitLab From eabdb4b4c37d676d6e42f008fff505a5d8bab9bb Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 7 Aug 2022 20:01:57 -0700 Subject: [PATCH 063/656] Better support for handover from OOS When handover from OOS to target transport, use the last known RAT to match the rule. Fix: 238599636 Test: atest DataNetworkControllerTest Change-Id: I5e720dad4486d893d561b461c08da9da728421dd --- .../internal/telephony/data/DataNetwork.java | 24 ++++++++++++-- .../telephony/data/DataNetworkController.java | 12 ++++++- .../data/DataNetworkControllerTest.java | 32 +++++++++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 9ecbf06518..db069741f9 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -643,6 +643,11 @@ public class DataNetwork extends StateMachine { */ private @TransportType int mTransport; + /** + * The last known data network type. + */ + private @NetworkType int mLastKnownDataNetworkType; + /** The reason that why setting up this data network is allowed. */ private @NonNull DataAllowedReason mDataAllowedReason; @@ -887,6 +892,7 @@ public class DataNetwork extends StateMachine { mTrafficDescriptors.add(dataProfile.getTrafficDescriptor()); } mTransport = transport; + mLastKnownDataNetworkType = getDataNetworkType(); mDataAllowedReason = dataAllowedReason; dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); mAttachedNetworkRequestList.addAll(networkRequestList); @@ -1077,7 +1083,11 @@ public class DataNetwork extends StateMachine { onCarrierConfigUpdated(); break; case EVENT_SERVICE_STATE_CHANGED: { - mDataCallSessionStats.onDrsOrRatChanged(getDataNetworkType()); + int networkType = getDataNetworkType(); + mDataCallSessionStats.onDrsOrRatChanged(networkType); + if (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN) { + mLastKnownDataNetworkType = networkType; + } updateSuspendState(); updateNetworkCapabilities(); break; @@ -3289,8 +3299,14 @@ public class DataNetwork extends StateMachine { } /** - * @return The PCO data map of the network. The key is the PCO id, the value is the PCO data. - * An empty map if PCO data is not available. + * @return The last known data network type of the data network. + */ + public @NetworkType int getLastKnownDataNetworkType() { + return mLastKnownDataNetworkType; + } + + /** + * @return The PCO data received from the network. */ public @NonNull Map getPcoData() { if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WLAN @@ -3528,6 +3544,8 @@ public class DataNetwork extends StateMachine { pw.increaseIndent(); pw.println("mSubId=" + mSubId); pw.println("mTransport=" + AccessNetworkConstants.transportTypeToString(mTransport)); + pw.println("mLastKnownDataNetworkType=" + TelephonyManager + .getNetworkTypeName(mLastKnownDataNetworkType)); pw.println("WWAN cid=" + mCid.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); pw.println("WLAN cid=" + mCid.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)); pw.println("mNetworkScore=" + mNetworkScore); diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 9b8e5986f7..73a4b17150 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -1879,8 +1879,18 @@ public class DataNetworkController extends Handler { if (mDataConfigManager.isIwlanHandoverPolicyEnabled()) { List handoverRules = mDataConfigManager.getHandoverRules(); + int sourceNetworkType = getDataNetworkType(dataNetwork.getTransport()); + if (sourceNetworkType == TelephonyManager.NETWORK_TYPE_UNKNOWN) { + // Using the data network type stored in the data network. We + // cache the last known network type in data network controller + // because data network has much shorter life cycle. It can prevent + // the obsolete last known network type cached in data network + // type controller. + sourceNetworkType = dataNetwork.getLastKnownDataNetworkType(); + } int sourceAccessNetwork = DataUtils.networkTypeToAccessNetworkType( - getDataNetworkType(dataNetwork.getTransport())); + sourceNetworkType); + int targetAccessNetwork = DataUtils.networkTypeToAccessNetworkType( getDataNetworkType(DataUtils.getTargetTransport(dataNetwork.getTransport()))); NetworkCapabilities capabilities = dataNetwork.getNetworkCapabilities(); 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 79debbeee0..ae863949ee 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -3036,6 +3036,38 @@ public class DataNetworkControllerTest extends TelephonyTest { AccessNetworkConstants.TRANSPORT_TYPE_WLAN); } + @Test + public void testHandoverDataNetworkSourceOosNoUnknownRule() throws Exception { + testSetupImsDataNetwork(); + // Configured handover is allowed from OOS to 4G/5G/IWLAN. + mCarrierConfig.putStringArray( + CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, + new String[]{ + "source=EUTRAN|NGRAN|IWLAN, target=EUTRAN|NGRAN|IWLAN, " + + "type=disallowed, capabilities=IMS|EIMS|MMS|XCAP|CBS" + }); + carrierConfigChanged(); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); + + updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + + // Verify IMS network was torn down on source first. + verify(mMockedWwanDataServiceManager).deactivateDataCall(anyInt(), + eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); + + // Verify that IWLAN is brought up again on IWLAN. + verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), + any(DataProfile.class), anyBoolean(), anyBoolean(), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), + any(Message.class)); + + DataNetwork dataNetwork = getDataNetworks().get(0); + assertThat(dataNetwork.getTransport()).isEqualTo( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + } + @Test public void testHandoverDataNetworkNonVops() throws Exception { ServiceState ss = new ServiceState(); -- GitLab From 2c0fbda1d36e1147f420eb3cc9ad410d237a7553 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Wed, 3 Aug 2022 16:37:52 +0000 Subject: [PATCH 064/656] Combine SmsSenderCallback and MultipartSmsSenderCallback into a single class Bug: 189149331 Test: Run the following tests - atest com.android.internal.telephony.gsm.GsmSmsDispatcherTest - atest com.android.internal.telephony.ImsSmsDispatcherTest - atest com.android.internal.telephony.cdma.CdmaSmsDispatcherTest Change-Id: I65adf8a6e209cf5932a9265c3b3feaa63ff8c838 --- .../internal/telephony/SMSDispatcher.java | 112 ++++++------------ 1 file changed, 35 insertions(+), 77 deletions(-) diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 885925a194..cb492ae09b 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -672,26 +672,50 @@ public abstract class SMSDispatcher extends Handler { @Override public void onSendSmsComplete(int result, int messageRef) { Rlog.d(TAG, "onSendSmsComplete: result=" + result + " messageRef=" + messageRef); - if (mCallbackCalled) { - logWithLocalLog("onSendSmsComplete: unexpected call"); - AnomalyReporter.reportAnomaly(sAnomalyUnexpectedCallback, - "Unexpected onSendSmsComplete", mPhone.getCarrierId()); + if (cleanupOnSendSmsComplete("onSendSmsComplete")) { return; } - mCallbackCalled = true; + final long identity = Binder.clearCallingIdentity(); try { - mSmsSender.mCarrierMessagingServiceWrapper.disconnect(); processSendSmsResponse(mSmsSender.getSmsTracker(), result, messageRef); - mSmsSender.removeTimeout(); } finally { Binder.restoreCallingIdentity(identity); } } + /** + * This method should be called only once. + */ @Override public void onSendMultipartSmsComplete(int result, int[] messageRefs) { - Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with result: " + result); + Rlog.d(TAG, "onSendMultipartSmsComplete: result=" + result + " messageRefs=" + + Arrays.toString(messageRefs)); + if (cleanupOnSendSmsComplete("onSendMultipartSmsComplete")) { + return; + } + + final long identity = Binder.clearCallingIdentity(); + try { + processSendMultipartSmsResponse(mSmsSender.getSmsTrackers(), result, messageRefs); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + private boolean cleanupOnSendSmsComplete(String callingFunction) { + if (mCallbackCalled) { + logWithLocalLog(callingFunction + ": unexpected call"); + AnomalyReporter.reportAnomaly(sAnomalyUnexpectedCallback, + "Unexpected " + callingFunction, mPhone.getCarrierId()); + return true; + } + + mCallbackCalled = true; + mSmsSender.removeTimeout(); + mSmsSender.mCarrierMessagingServiceWrapper.disconnect(); + + return false; } @Override @@ -766,8 +790,7 @@ public abstract class SMSDispatcher extends Handler { } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - void sendSmsByCarrierApp(String carrierPackageName, - MultipartSmsSenderCallback senderCallback) { + void sendSmsByCarrierApp(String carrierPackageName, SmsSenderCallback senderCallback) { super.sendSmsByCarrierApp(carrierPackageName, senderCallback); } @@ -815,69 +838,6 @@ public abstract class SMSDispatcher extends Handler { } } - /** - * Callback for MultipartSmsSender from the carrier messaging service. - * Once the result is ready, the carrier messaging service connection is disposed. - */ - private final class MultipartSmsSenderCallback implements CarrierMessagingCallback { - private final MultipartSmsSender mSmsSender; - private boolean mCallbackCalled = false; - - MultipartSmsSenderCallback(MultipartSmsSender smsSender) { - mSmsSender = smsSender; - } - - @Override - public void onSendSmsComplete(int result, int messageRef) { - Rlog.e(TAG, "Unexpected onSendSmsComplete call with result: " + result); - } - - /** - * This method should be called only once. - */ - @Override - public void onSendMultipartSmsComplete(int result, int[] messageRefs) { - Rlog.d(TAG, "onSendMultipartSmsComplete: result=" + result + " messageRefs=" - + Arrays.toString(messageRefs)); - if (mCallbackCalled) { - logWithLocalLog("onSendMultipartSmsComplete: unexpected call"); - AnomalyReporter.reportAnomaly(sAnomalyUnexpectedCallback, - "Unexpected onSendMultipartSmsComplete", mPhone.getCarrierId()); - return; - } - mCallbackCalled = true; - mSmsSender.removeTimeout(); - mSmsSender.mCarrierMessagingServiceWrapper.disconnect(); - - if (mSmsSender.mTrackers == null) { - Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with null trackers."); - return; - } - - final long identity = Binder.clearCallingIdentity(); - try { - processSendMultipartSmsResponse(mSmsSender.mTrackers, result, messageRefs); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void onReceiveSmsComplete(int result) { - Rlog.e(TAG, "Unexpected onReceiveSmsComplete call with result: " + result); - } - - @Override - public void onSendMmsComplete(int result, byte[] sendConfPdu) { - Rlog.e(TAG, "Unexpected onSendMmsComplete call with result: " + result); - } - - @Override - public void onDownloadMmsComplete(int result) { - Rlog.e(TAG, "Unexpected onDownloadMmsComplete call with result: " + result); - } - } - private void processSendMultipartSmsResponse( SmsTracker[] trackers, int result, int[] messageRefs) { if (trackers == null) { @@ -1624,12 +1584,10 @@ public abstract class SMSDispatcher extends Handler { String carrierPackage = getCarrierAppPackageName(); if (carrierPackage != null) { - Rlog.d(TAG, "Found carrier package " + carrierPackage - + " " + Rlog.d(TAG, "Found carrier package " + carrierPackage + " " + SmsController.formatCrossStackMessageId(getMultiTrackermessageId(trackers))); MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers); - smsSender.sendSmsByCarrierApp(carrierPackage, - new MultipartSmsSenderCallback(smsSender)); + smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender)); } else { Rlog.v(TAG, "No carrier package. " + SmsController.formatCrossStackMessageId(getMultiTrackermessageId(trackers))); -- GitLab From 1c3e793629dffada9087543e1db0c1db0b258a11 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Fri, 15 Jul 2022 18:03:17 +0000 Subject: [PATCH 065/656] Add internal implementation to support the new APIs used by owner groups to vote on radio power state Bug: 228777724 Design doc: go/voting-radio-power-state Test: Run the following tests - atest android.telephony.cts.TelephonyManagerTest - atest com.android.internal.telephony.ServiceStateTrackerTest - atest com.android.internal.telephony.data.DataNetworkControllerTest - atest com.android.internal.telephony.dataconnection.DcTrackerTest - atest com.android.internal.telephony.GsmCdmaPhoneTest Change-Id: I3b193f92e5ad2c14080de8596c8933cbcac43a5d Change-Id: I7b543a86aaca3523a0aa427a48ef876ae962e17b --- .../internal/telephony/GsmCdmaPhone.java | 8 +- .../com/android/internal/telephony/Phone.java | 2 +- .../telephony/PhoneInternalInterface.java | 39 +++++---- .../telephony/ServiceStateTracker.java | 51 ++++-------- .../internal/telephony/GsmCdmaPhoneTest.java | 9 +- .../telephony/ServiceStateTrackerTest.java | 83 ++++++++++++++++--- 6 files changed, 120 insertions(+), 72 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 94d437fa00..2bc4b8988f 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -130,6 +130,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1702,7 +1703,7 @@ public class GsmCdmaPhone extends Phone { public void setRadioPower(boolean power, boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, boolean forceApply) { setRadioPowerForReason(power, forEmergencyCall, isSelectedPhoneForEmergencyCall, forceApply, - Phone.RADIO_POWER_REASON_USER); + TelephonyManager.RADIO_POWER_REASON_USER); } @Override @@ -1712,6 +1713,11 @@ public class GsmCdmaPhone extends Phone { forceApply, reason); } + @Override + public Set getRadioPowerOffReasons() { + return mSST.getRadioPowerOffReasons(); + } + private void storeVoiceMailNumber(String number) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = sp.edit(); diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 5c5c303c31..7c69609acc 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -1901,7 +1901,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public boolean isRadioOffForThermalMitigation() { ServiceStateTracker sst = getServiceStateTracker(); return sst != null && sst.getRadioPowerOffReasons() - .contains(Phone.RADIO_POWER_REASON_THERMAL); + .contains(TelephonyManager.RADIO_POWER_REASON_THERMAL); } /** diff --git a/src/java/com/android/internal/telephony/PhoneInternalInterface.java b/src/java/com/android/internal/telephony/PhoneInternalInterface.java index 5b4d5e513f..f25de35a69 100644 --- a/src/java/com/android/internal/telephony/PhoneInternalInterface.java +++ b/src/java/com/android/internal/telephony/PhoneInternalInterface.java @@ -16,7 +16,6 @@ package com.android.internal.telephony; -import android.annotation.IntDef; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; @@ -36,9 +35,9 @@ import android.telephony.emergency.EmergencyNumber; import com.android.internal.telephony.PhoneConstants.DataState; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Consumer; /** @@ -211,16 +210,6 @@ public interface PhoneInternalInterface { static final String REASON_DATA_UNTHROTTLED = "dataUnthrottled"; static final String REASON_TRAFFIC_DESCRIPTORS_UPDATED = "trafficDescriptorsUpdated"; - // Reasons for Radio being powered off - int RADIO_POWER_REASON_USER = 0; - int RADIO_POWER_REASON_THERMAL = 1; - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"RADIO_POWER_REASON_"}, - value = { - RADIO_POWER_REASON_USER, - RADIO_POWER_REASON_THERMAL}) - public @interface RadioPowerReason {} - // Used for band mode selection methods static final int BM_UNSPECIFIED = RILConstants.BAND_MODE_UNSPECIFIED; // automatic static final int BM_EURO_BAND = RILConstants.BAND_MODE_EURO; @@ -593,8 +582,9 @@ public interface PhoneInternalInterface { * getServiceState().getState() will not change immediately after this call. * registerForServiceStateChanged() to find out when the * request is complete. This will set the reason for radio power state as {@link - * #RADIO_POWER_REASON_USER}. This will not guarantee that the requested radio power state will - * actually be set. See {@link #setRadioPowerForReason(boolean, boolean, boolean, boolean, int)} + * android.telephony.TelephonyManager#RADIO_POWER_REASON_USER}. This will not guarantee that the + * requested radio power state will actually be set. + * See {@link #setRadioPowerForReason(boolean, boolean, boolean, boolean, int)} * for details. * * @param power true means "on", false means "off". @@ -620,8 +610,9 @@ public interface PhoneInternalInterface { * getServiceState().getState() will not change immediately after this call. * registerForServiceStateChanged() to find out when the * request is complete. This will set the reason for radio power state as {@link - * #RADIO_POWER_REASON_USER}. This will not guarantee that the requested radio power state will - * actually be set. See {@link #setRadioPowerForReason(boolean, boolean, boolean, boolean, int)} + * android.telephony.TelephonyManager#RADIO_POWER_REASON_USER}. This will not guarantee that the + * requested radio power state will actually be set. + * See {@link #setRadioPowerForReason(boolean, boolean, boolean, boolean, int)} * for details. * * @param power true means "on", false means "off". @@ -638,7 +629,7 @@ public interface PhoneInternalInterface { default void setRadioPower(boolean power, boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, boolean forceApply) { setRadioPowerForReason(power, forEmergencyCall, isSelectedPhoneForEmergencyCall, forceApply, - RADIO_POWER_REASON_USER); + TelephonyManager.RADIO_POWER_REASON_USER); } /** @@ -656,10 +647,18 @@ public interface PhoneInternalInterface { * @param power true means "on", false means "off". * @param reason RadioPowerReason constant defining the reason why the radio power was set. */ - default void setRadioPowerForReason(boolean power, @RadioPowerReason int reason) { + default void setRadioPowerForReason(boolean power, + @TelephonyManager.RadioPowerReason int reason) { setRadioPowerForReason(power, false, false, false, reason); } + /** + * @return reasons for powering off radio. + */ + default Set getRadioPowerOffReasons() { + return new HashSet<>(); + } + /** * Sets the radio power on/off state with option to specify whether it's for emergency call * (off is sometimes called "airplane mode") and option to set the reason for setting the power @@ -686,7 +685,7 @@ public interface PhoneInternalInterface { */ default void setRadioPowerForReason(boolean power, boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, boolean forceApply, - @RadioPowerReason int reason) {} + @TelephonyManager.RadioPowerReason int reason) {} /** * Get the line 1 phone number (MSISDN). For CDMA phones, the MDN is returned diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index d362a20d07..3f7f5caae0 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -320,8 +320,6 @@ public class ServiceStateTracker extends Handler { private CarrierDisplayNameResolver mCdnr; private boolean mImsRegistrationOnOff = false; - /** Radio is disabled by carrier. Radio power will not be override if this field is set */ - private boolean mRadioDisabledByCarrier = false; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private boolean mDeviceShuttingDown = false; /** Keep track of SPN display rules, so we only broadcast intent if something changes. */ @@ -683,7 +681,7 @@ public class ServiceStateTracker extends Handler { Settings.Global.ENABLE_CELLULAR_ON_BOOT, 1); mDesiredPowerState = (enableCellularOnBoot > 0) && ! (airplaneMode > 0); if (!mDesiredPowerState) { - mRadioPowerOffReasons.add(Phone.RADIO_POWER_REASON_USER); + mRadioPowerOffReasons.add(TelephonyManager.RADIO_POWER_REASON_USER); } mRadioPowerLog.log("init : airplane mode = " + airplaneMode + " enableCellularOnBoot = " + enableCellularOnBoot); @@ -867,7 +865,10 @@ public class ServiceStateTracker extends Handler { public boolean getDesiredPowerState() { return mDesiredPowerState; } - public boolean getPowerStateFromCarrier() { return !mRadioDisabledByCarrier; } + + public boolean getPowerStateFromCarrier() { + return !mRadioPowerOffReasons.contains(TelephonyManager.RADIO_POWER_REASON_CARRIER); + } public List getPhysicalChannelConfigList() { return mLastPhysicalChannelConfigList; @@ -1057,7 +1058,7 @@ public class ServiceStateTracker extends Handler { * @return the current reasons for which the radio is off. */ public Set getRadioPowerOffReasons() { - return mRadioPowerOffReasons; + return Set.copyOf(mRadioPowerOffReasons); } /** @@ -1083,7 +1084,7 @@ public class ServiceStateTracker extends Handler { public void setRadioPower(boolean power, boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, boolean forceApply) { setRadioPowerForReason(power, forEmergencyCall, isSelectedPhoneForEmergencyCall, forceApply, - Phone.RADIO_POWER_REASON_USER); + TelephonyManager.RADIO_POWER_REASON_USER); } /** @@ -1123,23 +1124,6 @@ public class ServiceStateTracker extends Handler { setPowerStateToDesired(forEmergencyCall, isSelectedPhoneForEmergencyCall, forceApply); } - /** - * Radio power set from carrier action. if set to false means carrier desire to turn radio off - * and radio wont be re-enabled unless carrier explicitly turn it back on. - * @param enable indicate if radio power is enabled or disabled from carrier action. - */ - public void setRadioPowerFromCarrier(boolean enable) { - boolean disableByCarrier = !enable; - if (mRadioDisabledByCarrier == disableByCarrier) { - log("setRadioPowerFromCarrier mRadioDisabledByCarrier is already " - + disableByCarrier + " Do nothing."); - return; - } - - mRadioDisabledByCarrier = disableByCarrier; - setPowerStateToDesired(); - } - /** * These two flags manage the behavior of the cell lock -- the * lock should be held if either flag is true. The intention is @@ -1637,7 +1621,8 @@ public class ServiceStateTracker extends Handler { if (ar.exception == null) { boolean enable = (boolean) ar.result; if (DBG) log("EVENT_RADIO_POWER_FROM_CARRIER: " + enable); - setRadioPowerFromCarrier(enable); + setRadioPowerForReason(enable, false, false, false, + TelephonyManager.RADIO_POWER_REASON_CARRIER); } break; @@ -3070,12 +3055,12 @@ public class ServiceStateTracker extends Handler { protected void setPowerStateToDesired(boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, boolean forceApply) { if (DBG) { - String tmpLog = "setPowerStateToDesired: mDeviceShuttingDown=" + mDeviceShuttingDown + - ", mDesiredPowerState=" + mDesiredPowerState + - ", getRadioState=" + mCi.getRadioState() + - ", mRadioDisabledByCarrier=" + mRadioDisabledByCarrier + - ", IMS reg state=" + mImsRegistrationOnOff + - ", pending radio off=" + hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT); + String tmpLog = "setPowerStateToDesired: mDeviceShuttingDown=" + mDeviceShuttingDown + + ", mDesiredPowerState=" + mDesiredPowerState + + ", getRadioState=" + mCi.getRadioState() + + ", mRadioPowerOffReasons=" + mRadioPowerOffReasons + + ", IMS reg state=" + mImsRegistrationOnOff + + ", pending radio off=" + hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT); log(tmpLog); mRadioPowerLog.log(tmpLog); } @@ -3087,10 +3072,10 @@ public class ServiceStateTracker extends Handler { } // If we want it on and it's off, turn it on - if (mDesiredPowerState && !mRadioDisabledByCarrier + if (mDesiredPowerState && mRadioPowerOffReasons.isEmpty() && (forceApply || mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF)) { mCi.setRadioPower(true, forEmergencyCall, isSelectedPhoneForEmergencyCall, null); - } else if ((!mDesiredPowerState || mRadioDisabledByCarrier) && mCi.getRadioState() + } else if ((!mDesiredPowerState || !mRadioPowerOffReasons.isEmpty()) && mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) { if (DBG) log("setPowerStateToDesired: powerOffRadioSafely()"); powerOffRadioSafely(); @@ -5288,7 +5273,7 @@ public class ServiceStateTracker extends Handler { pw.println(" mImsRegistrationOnOff=" + mImsRegistrationOnOff); pw.println(" pending radio off event=" + hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT)); - pw.println(" mRadioDisabledByCarrier" + mRadioDisabledByCarrier); + pw.println(" mRadioPowerOffReasons=" + mRadioPowerOffReasons); pw.println(" mDeviceShuttingDown=" + mDeviceShuttingDown); pw.println(" mSpnUpdatePending=" + mSpnUpdatePending); pw.println(" mCellInfoMinIntervalMs=" + mCellInfoMinIntervalMs); diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 091df19528..79e16b5fac 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -1297,11 +1297,12 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void testSetRadioPower() throws Exception { mPhoneUT.setRadioPower(false); verify(mSST).setRadioPowerForReason(false, false, false, false, - Phone.RADIO_POWER_REASON_USER); + TelephonyManager.RADIO_POWER_REASON_USER); // Turn on radio for emergency call. mPhoneUT.setRadioPower(true, true, false, true); - verify(mSST).setRadioPowerForReason(true, true, false, true, Phone.RADIO_POWER_REASON_USER); + verify(mSST).setRadioPowerForReason(true, true, false, true, + TelephonyManager.RADIO_POWER_REASON_USER); } @Test @@ -1309,12 +1310,12 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void testSetRadioPowerOnForTestEmergencyCall() { mPhoneUT.setRadioPower(false); verify(mSST).setRadioPowerForReason(false, false, false, false, - Phone.RADIO_POWER_REASON_USER); + TelephonyManager.RADIO_POWER_REASON_USER); mPhoneUT.setRadioPowerOnForTestEmergencyCall(false); verify(mSST).clearAllRadioOffReasons(); verify(mSST).setRadioPowerForReason(eq(true), eq(false), anyBoolean(), eq(false), - eq(Phone.RADIO_POWER_REASON_USER)); + eq(TelephonyManager.RADIO_POWER_REASON_USER)); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 1dbda5ba7c..4eec0ced4b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -464,30 +464,37 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @MediumTest public void testSetRadioPowerForReason() { + testSetRadioPowerForReason(TelephonyManager.RADIO_POWER_REASON_THERMAL); + testSetRadioPowerForReason(TelephonyManager.RADIO_POWER_REASON_NEARBY_DEVICE); + testSetRadioPowerForReason(TelephonyManager.RADIO_POWER_REASON_CARRIER); + } + + private void testSetRadioPowerForReason(int reason) { // Radio does not turn on if off for other reason and not emergency call. assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_ON); assertTrue(sst.getRadioPowerOffReasons().isEmpty()); - sst.setRadioPowerForReason(false, false, false, false, Phone.RADIO_POWER_REASON_THERMAL); - assertTrue(sst.getRadioPowerOffReasons().contains(Phone.RADIO_POWER_REASON_THERMAL)); + sst.setRadioPowerForReason(false, false, false, false, reason); + assertTrue(sst.getRadioPowerOffReasons().contains(reason)); assertTrue(sst.getRadioPowerOffReasons().size() == 1); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_OFF); - sst.setRadioPowerForReason(true, false, false, false, Phone.RADIO_POWER_REASON_USER); - assertTrue(sst.getRadioPowerOffReasons().contains(Phone.RADIO_POWER_REASON_THERMAL)); + sst.setRadioPowerForReason(true, false, false, false, + TelephonyManager.RADIO_POWER_REASON_USER); + assertTrue(sst.getRadioPowerOffReasons().contains(reason)); assertTrue(sst.getRadioPowerOffReasons().size() == 1); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_OFF); // Radio power state reason is removed and radio turns on if turned on for same reason it // had been turned off for. - sst.setRadioPowerForReason(true, false, false, false, Phone.RADIO_POWER_REASON_THERMAL); + sst.setRadioPowerForReason(true, false, false, false, reason); assertTrue(sst.getRadioPowerOffReasons().isEmpty()); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_ON); // Turn radio off, then successfully turn radio on for emergency call. - sst.setRadioPowerForReason(false, false, false, false, Phone.RADIO_POWER_REASON_THERMAL); - assertTrue(sst.getRadioPowerOffReasons().contains(Phone.RADIO_POWER_REASON_THERMAL)); + sst.setRadioPowerForReason(false, false, false, false, reason); + assertTrue(sst.getRadioPowerOffReasons().contains(reason)); assertTrue(sst.getRadioPowerOffReasons().size() == 1); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_OFF); @@ -499,33 +506,83 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @MediumTest - public void testSetRadioPowerFromCarrier() { + public void testSetRadioPowerForMultipleReasons() { + assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_ON); + assertTrue(sst.getRadioPowerOffReasons().isEmpty()); + + // Turn off radio + turnRadioOffForReason(TelephonyManager.RADIO_POWER_REASON_USER, 1); + turnRadioOffForReason(TelephonyManager.RADIO_POWER_REASON_THERMAL, 2); + turnRadioOffForReason(TelephonyManager.RADIO_POWER_REASON_CARRIER, 3); + turnRadioOffForReason(TelephonyManager.RADIO_POWER_REASON_NEARBY_DEVICE, 4); + + // Turn on radio + turnRadioOnForReason(TelephonyManager.RADIO_POWER_REASON_NEARBY_DEVICE, 3, + TelephonyManager.RADIO_POWER_OFF); + turnRadioOnForReason(TelephonyManager.RADIO_POWER_REASON_THERMAL, 2, + TelephonyManager.RADIO_POWER_OFF); + turnRadioOnForReason(TelephonyManager.RADIO_POWER_REASON_CARRIER, 1, + TelephonyManager.RADIO_POWER_OFF); + turnRadioOnForReason(TelephonyManager.RADIO_POWER_REASON_USER, 0, + TelephonyManager.RADIO_POWER_ON); + } + + private void turnRadioOffForReason(int reason, int powerOffReasonSize) { + sst.setRadioPowerForReason(false, false, false, false, reason); + assertTrue(sst.getRadioPowerOffReasons().contains(reason)); + assertTrue(sst.getRadioPowerOffReasons().size() == powerOffReasonSize); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_OFF); + } + + private void turnRadioOnForReason(int reason, int powerOffReasonSize, + int expectedRadioPowerState) { + sst.setRadioPowerForReason(true, false, false, false, reason); + assertFalse(sst.getRadioPowerOffReasons().contains(reason)); + assertTrue(sst.getRadioPowerOffReasons().size() == powerOffReasonSize); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertTrue(mSimulatedCommands.getRadioState() == expectedRadioPowerState); + } + + @Test + @MediumTest + public void testSetRadioPowerForReasonCarrier() { // Carrier disable radio power - sst.setRadioPowerFromCarrier(false); + sst.setRadioPowerForReason(false, false, false, false, + TelephonyManager.RADIO_POWER_REASON_CARRIER); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertFalse(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_ON); - assertTrue(sst.getDesiredPowerState()); + assertFalse(sst.getDesiredPowerState()); assertFalse(sst.getPowerStateFromCarrier()); + assertTrue(sst.getRadioPowerOffReasons().contains( + TelephonyManager.RADIO_POWER_REASON_CARRIER)); + assertTrue(sst.getRadioPowerOffReasons().size() == 1); // User toggle radio power will not overrides carrier settings sst.setRadioPower(true); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertFalse(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_ON); - assertTrue(sst.getDesiredPowerState()); + assertFalse(sst.getDesiredPowerState()); assertFalse(sst.getPowerStateFromCarrier()); + assertTrue(sst.getRadioPowerOffReasons().contains( + TelephonyManager.RADIO_POWER_REASON_CARRIER)); + assertTrue(sst.getRadioPowerOffReasons().size() == 1); // Carrier re-enable radio power - sst.setRadioPowerFromCarrier(true); + sst.setRadioPowerForReason(true, false, false, false, + TelephonyManager.RADIO_POWER_REASON_CARRIER); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertTrue(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_ON); assertTrue(sst.getDesiredPowerState()); assertTrue(sst.getPowerStateFromCarrier()); + assertTrue(sst.getRadioPowerOffReasons().isEmpty()); // User toggle radio power off (airplane mode) and set carrier on sst.setRadioPower(false); - sst.setRadioPowerFromCarrier(true); + sst.setRadioPowerForReason(true, false, false, false, + TelephonyManager.RADIO_POWER_REASON_CARRIER); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); assertFalse(mSimulatedCommands.getRadioState() == TelephonyManager.RADIO_POWER_ON); -- GitLab From 8376dfbff7de685135a75ac355e31882fa8b1c3e Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 15 Aug 2022 19:53:50 +0000 Subject: [PATCH 066/656] Revert "Removed old data stack" Revert submission 19477826-remove_old_data Reason for revert: Pixel 4a needs it Reverted Changes: I4f58626b0:Removed old data stack I798b17a59:Removed old data stack I523b924c2:Removed old data stack Change-Id: Ibfddc660d0c94d691983bc1b1f51c6158091863e --- .../telephony/GsmCdmaCallTracker.java | 11 + .../internal/telephony/GsmCdmaPhone.java | 199 +- .../telephony/MultiSimSettingController.java | 27 +- .../telephony/NetworkTypeController.java | 108 +- .../com/android/internal/telephony/Phone.java | 153 +- .../internal/telephony/ProxyController.java | 29 + .../internal/telephony/RetryManager.java | 723 +++ .../telephony/ServiceStateTracker.java | 230 +- .../telephony/TelephonyComponentFactory.java | 16 + .../telephony/data/AccessNetworksManager.java | 194 +- .../telephony/data/DataConfigManager.java | 12 +- .../data/LinkBandwidthEstimator.java | 33 + .../data/NotifyQosSessionInterface.java | 54 + .../telephony/data/PhoneSwitcher.java | 179 +- .../telephony/data/QosCallbackTracker.java | 72 +- .../telephony/data/TelephonyNetworkAgent.java | 36 +- .../data/TelephonyNetworkFactory.java | 253 +- .../data/TelephonyNetworkRequest.java | 14 +- .../dataconnection/ApnConfigType.java | 50 + .../ApnConfigTypeRepository.java | 128 + .../telephony/dataconnection/ApnContext.java | 675 ++ .../dataconnection/ApnSettingUtils.java | 129 + .../dataconnection/DataConnection.java | 4094 ++++++++++++ .../dataconnection/DataConnectionReasons.java | 176 + .../dataconnection/DataEnabledSettings.java | 566 ++ .../dataconnection/DataServiceManager.java | 978 +++ .../dataconnection/DataThrottler.java | 366 ++ .../dataconnection/DcController.java | 487 ++ .../dataconnection/DcFailBringUp.java | 85 + .../dataconnection/DcNetworkAgent.java | 617 ++ .../telephony/dataconnection/DcRequest.java | 102 + .../dataconnection/DcTesterDeactivateAll.java | 95 + .../DcTesterFailBringUpAll.java | 110 + .../telephony/dataconnection/DcTracker.java | 5665 +++++++++++++++++ .../telephony/dataconnection/README.txt | 71 + .../dataconnection/TransportManager.java | 279 + .../telephony/imsphone/ImsPhoneBase.java | 10 + .../imsphone/ImsPhoneCallTracker.java | 74 +- .../metrics/DataStallRecoveryStats.java | 37 + .../telephony/metrics/MetricsCollector.java | 3 +- .../MultiSimSettingControllerTest.java | 98 +- .../telephony/NetworkTypeControllerTest.java | 106 +- .../telephony/SMSDispatcherTest.java.broken | 107 + .../telephony/ServiceStateTrackerTest.java | 53 + .../internal/telephony/TelephonyTest.java | 23 + .../telephony/TestPhoneNotifier.java.broken | 69 + .../telephony/data/DataCallResponseTest.java | 17 +- .../telephony/data/DataNetworkTest.java | 2 + .../data/LinkBandwidthEstimatorTest.java | 23 +- .../telephony/data/PhoneSwitcherTest.java | 22 +- .../data/QosCallbackTrackerTest.java | 97 +- .../data/TelephonyNetworkFactoryTest.java | 94 +- .../ApnConfigTypeRepositoryTest.java | 109 + .../dataconnection/ApnContextTest.java | 240 + .../ApnSettingTest.java | 214 +- .../dataconnection/DataConnectionTest.java | 1479 +++++ .../DataEnabledSettingsTest.java | 147 + .../dataconnection/DataThrottlerTest.java | 222 + .../dataconnection/DcControllerTest.java | 272 + .../dataconnection/DcNetworkAgentTest.java | 118 + .../dataconnection/DcRequestTest.java | 125 + .../dataconnection/DcTrackerTest.java | 2983 +++++++++ .../dataconnection/RetryManagerTest.java | 996 +++ .../telephony/gsm/GSMPhoneTest.java.broken | 1935 ++++++ .../telephony/gsm/GSMTestHandler.java.broken | 118 + .../gsm/UsimDataDownloadCommands.java.broken | 694 ++ .../gsm/UsimDataDownloadTest.java.broken | 144 + .../metrics/TelephonyMetricsTest.java | 10 +- tools/tdi | 48 + 69 files changed, 27294 insertions(+), 411 deletions(-) create mode 100644 src/java/com/android/internal/telephony/RetryManager.java create mode 100644 src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnContext.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DataConnection.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DataThrottler.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DcController.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DcRequest.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java create mode 100755 src/java/com/android/internal/telephony/dataconnection/DcTracker.java create mode 100644 src/java/com/android/internal/telephony/dataconnection/README.txt create mode 100644 src/java/com/android/internal/telephony/dataconnection/TransportManager.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken create mode 100644 tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java rename tests/telephonytests/src/com/android/internal/telephony/{data => dataconnection}/ApnSettingTest.java (62%) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken create mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken create mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken create mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken create mode 100755 tools/tdi diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java index 263bfebc15..07be4e51fb 100755 --- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java +++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java @@ -182,6 +182,11 @@ public class GsmCdmaCallTracker extends CallTracker { mCi.unregisterForCallWaitingInfo(this); // Prior to phone switch to GSM, if CDMA has any emergency call // data will be in disabled state, after switching to GSM enable data. + if (mIsInEmergencyCall) { + if (!mPhone.isUsingNewDataStack()) { + mPhone.getDataEnabledSettings().setInternalDataEnabled(true); + } + } } else { mConnections = new GsmCdmaConnection[MAX_CONNECTIONS_CDMA]; mPendingCallInEcm = false; @@ -395,6 +400,9 @@ public class GsmCdmaCallTracker extends CallTracker { //CDMA public void setIsInEmergencyCall() { mIsInEmergencyCall = true; + if (!mPhone.isUsingNewDataStack()) { + mPhone.getDataEnabledSettings().setInternalDataEnabled(false); + } mPhone.notifyEmergencyCallRegistrants(true); mPhone.sendEmergencyCallStateChange(true); } @@ -1751,6 +1759,9 @@ public class GsmCdmaCallTracker extends CallTracker { } if (!inEcm) { // Re-initiate data connection + if (!mPhone.isUsingNewDataStack()) { + mPhone.getDataEnabledSettings().setInternalDataEnabled(true); + } mPhone.notifyEmergencyCallRegistrants(false); } mPhone.sendEmergencyCallStateChange(false); diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 94d437fa00..6d16fe072a 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -67,6 +67,7 @@ import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telecom.VideoProfile; +import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.DataActivityType; import android.telephony.Annotation.RadioPowerState; import android.telephony.BarringInfo; @@ -84,6 +85,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.UiccAccessRule; import android.telephony.UssdResponse; +import android.telephony.data.ApnSetting; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -95,6 +97,9 @@ import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.LinkBandwidthEstimator; +import com.android.internal.telephony.dataconnection.DataEnabledSettings; +import com.android.internal.telephony.dataconnection.DcTracker; +import com.android.internal.telephony.dataconnection.TransportManager; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.gsm.GsmMmiCode; import com.android.internal.telephony.gsm.SsData; @@ -272,6 +277,8 @@ public class GsmCdmaPhone extends Phone { private CarrierKeyDownloadManager mCDM; private CarrierInfoManager mCIM; + private final SettingsObserver mSettingsObserver; + private final ImsManagerFactory mImsManagerFactory; private final CarrierPrivilegesTracker mCarrierPrivilegesTracker; @@ -316,6 +323,10 @@ public class GsmCdmaPhone extends Phone { mAccessNetworksManager = mTelephonyComponentFactory .inject(AccessNetworksManager.class.getName()) .makeAccessNetworksManager(this, getLooper()); + if (!isUsingNewDataStack()) { + mTransportManager = mTelephonyComponentFactory.inject(TransportManager.class.getName()) + .makeTransportManager(this); + } // SST/DSM depends on SSC, so SSC is instanced before SST/DSM mSignalStrengthController = mTelephonyComponentFactory.inject( SignalStrengthController.class.getName()).makeSignalStrengthController(this); @@ -324,6 +335,10 @@ public class GsmCdmaPhone extends Phone { mEmergencyNumberTracker = mTelephonyComponentFactory .inject(EmergencyNumberTracker.class.getName()).makeEmergencyNumberTracker( this, this.mCi); + if (!isUsingNewDataStack()) { + mDataEnabledSettings = mTelephonyComponentFactory + .inject(DataEnabledSettings.class.getName()).makeDataEnabledSettings(this); + } mDeviceStateMonitor = mTelephonyComponentFactory.inject(DeviceStateMonitor.class.getName()) .makeDeviceStateMonitor(this); @@ -332,9 +347,20 @@ public class GsmCdmaPhone extends Phone { mDisplayInfoController = mTelephonyComponentFactory.inject( DisplayInfoController.class.getName()).makeDisplayInfoController(this); - mDataNetworkController = mTelephonyComponentFactory.inject( - DataNetworkController.class.getName()) - .makeDataNetworkController(this, getLooper()); + if (isUsingNewDataStack()) { + mDataNetworkController = mTelephonyComponentFactory.inject( + DataNetworkController.class.getName()) + .makeDataNetworkController(this, getLooper()); + } else { + // DcTracker uses ServiceStateTracker and DisplayInfoController so needs to be created + // after they are instantiated + for (int transport : mAccessNetworksManager.getAvailableTransports()) { + DcTracker dcTracker = mTelephonyComponentFactory.inject(DcTracker.class.getName()) + .makeDcTracker(this, transport); + mDcTrackers.put(transport, dcTracker); + mAccessNetworksManager.registerDataThrottler(dcTracker.getDataThrottler()); + } + } mCarrierResolver = mTelephonyComponentFactory.inject(CarrierResolver.class.getName()) .makeCarrierResolver(this); @@ -347,6 +373,15 @@ public class GsmCdmaPhone extends Phone { mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, null); + // TODO: Remove SettingsObserver and provisioning events when DataEnabledSettings is removed + mSettingsObserver = new SettingsObserver(context, this); + mSettingsObserver.observe( + Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), + EVENT_DEVICE_PROVISIONED_CHANGE); + mSettingsObserver.observe( + Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED), + EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE); + SubscriptionController.getInstance().registerForUiccAppsEnabled(this, EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false); @@ -655,6 +690,11 @@ public class GsmCdmaPhone extends Phone { return mCT; } + @Override + public TransportManager getTransportManager() { + return mTransportManager; + } + @Override public AccessNetworksManager getAccessNetworksManager() { return mAccessNetworksManager; @@ -706,9 +746,84 @@ public class GsmCdmaPhone extends Phone { return mCT.mState != PhoneConstants.State.IDLE && !mSST.isConcurrentVoiceAndDataAllowed(); } + @Override + public PhoneConstants.DataState getDataConnectionState(String apnType) { + PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED; + + if (mSST == null) { + // Radio Technology Change is ongoing, dispose() and removeReferences() have + // already been called + + ret = PhoneConstants.DataState.DISCONNECTED; + } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE + && (isPhoneTypeCdma() || isPhoneTypeCdmaLte() || + (isPhoneTypeGsm() && !apnType.equals(ApnSetting.TYPE_EMERGENCY_STRING)))) { + // If we're out of service, open TCP sockets may still work + // but no data will flow + + // Emergency APN is available even in Out Of Service + // Pass the actual State of EPDN + + ret = PhoneConstants.DataState.DISCONNECTED; + } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */ + int currentTransport = mAccessNetworksManager.getCurrentTransport( + ApnSetting.getApnTypesBitmaskFromString(apnType)); + if (getDcTracker(currentTransport) != null) { + switch (getDcTracker(currentTransport).getState(apnType)) { + case CONNECTED: + case DISCONNECTING: + if (isDataSuspended()) { + ret = PhoneConstants.DataState.SUSPENDED; + } else { + ret = PhoneConstants.DataState.CONNECTED; + } + break; + case CONNECTING: + ret = PhoneConstants.DataState.CONNECTING; + break; + default: + ret = PhoneConstants.DataState.DISCONNECTED; + } + } + } + + logd("getDataConnectionState apnType=" + apnType + " ret=" + ret); + return ret; + } + @Override public @DataActivityType int getDataActivityState() { - return getDataNetworkController().getDataActivity(); + if (isUsingNewDataStack()) { + return getDataNetworkController().getDataActivity(); + } + int ret = TelephonyManager.DATA_ACTIVITY_NONE; + + if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE + && getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { + switch (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getActivity()) { + case DATAIN: + ret = TelephonyManager.DATA_ACTIVITY_IN; + break; + + case DATAOUT: + ret = TelephonyManager.DATA_ACTIVITY_OUT; + break; + + case DATAINANDOUT: + ret = TelephonyManager.DATA_ACTIVITY_INOUT; + break; + + case DORMANT: + ret = TelephonyManager.DATA_ACTIVITY_DORMANT; + break; + + default: + ret = TelephonyManager.DATA_ACTIVITY_NONE; + break; + } + } + + return ret; } /** @@ -2853,12 +2968,25 @@ public class GsmCdmaPhone extends Phone { @Override public boolean getDataRoamingEnabled() { - return getDataSettingsManager().isDataRoamingEnabled(); + if (isUsingNewDataStack()) { + return getDataSettingsManager().isDataRoamingEnabled(); + } + if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { + return getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getDataRoamingEnabled(); + } + return false; } @Override public void setDataRoamingEnabled(boolean enable) { - getDataSettingsManager().setDataRoamingEnabled(enable); + if (isUsingNewDataStack()) { + getDataSettingsManager().setDataRoamingEnabled(enable); + return; + } + if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { + getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setDataRoamingEnabledByUser(enable); + } } @Override @@ -2903,12 +3031,21 @@ public class GsmCdmaPhone extends Phone { } /** - * Whether data is enabled by user. + * Whether data is enabled by user. Unlike isDataEnabled, this only + * checks user setting stored in {@link android.provider.Settings.Global#MOBILE_DATA} + * if not provisioning, or isProvisioningDataEnabled if provisioning. */ @Override public boolean isUserDataEnabled() { - return getDataSettingsManager().isDataEnabledForReason( - TelephonyManager.DATA_ENABLED_REASON_USER); + if (isUsingNewDataStack()) { + return getDataSettingsManager().isDataEnabledForReason( + TelephonyManager.DATA_ENABLED_REASON_USER); + } + if (mDataEnabledSettings.isProvisioning()) { + return mDataEnabledSettings.isProvisioningDataEnabled(); + } else { + return mDataEnabledSettings.isUserDataEnabled(); + } } /** @@ -3443,9 +3580,24 @@ public class GsmCdmaPhone extends Phone { case EVENT_SET_CARRIER_DATA_ENABLED: ar = (AsyncResult) msg.obj; boolean enabled = (boolean) ar.result; - getDataSettingsManager().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_CARRIER, enabled, - mContext.getOpPackageName()); + if (isUsingNewDataStack()) { + getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_CARRIER, enabled, + mContext.getOpPackageName()); + return; + } + mDataEnabledSettings.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_CARRIER, + enabled); + break; + case EVENT_DEVICE_PROVISIONED_CHANGE: + if (!isUsingNewDataStack()) { + mDataEnabledSettings.updateProvisionedChanged(); + } + break; + case EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE: + if (!isUsingNewDataStack()) { + mDataEnabledSettings.updateProvisioningDataEnabled(); + } break; case EVENT_GET_AVAILABLE_NETWORKS_DONE: ar = (AsyncResult) msg.obj; @@ -3940,6 +4092,10 @@ public class GsmCdmaPhone extends Phone { // send an Intent sendEmergencyCallbackModeChange(); + // Re-initiate data connection + if (!isUsingNewDataStack()) { + mDataEnabledSettings.setInternalDataEnabled(true); + } notifyEmergencyCallRegistrants(false); } mIsTestingEmergencyCallbackMode = false; @@ -4895,7 +5051,24 @@ public class GsmCdmaPhone extends Phone { * @return Currently bound data service package names. */ public @NonNull List getDataServicePackages() { - return getDataNetworkController().getDataServicePackages(); + if (isUsingNewDataStack()) { + return getDataNetworkController().getDataServicePackages(); + } + List packages = new ArrayList<>(); + int[] transports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; + + for (int transport : transports) { + DcTracker dct = getDcTracker(transport); + if (dct != null) { + String pkg = dct.getDataServiceManager().getDataServicePackageName(); + if (!TextUtils.isEmpty(pkg)) { + packages.add(pkg); + } + } + } + + return packages; } private void updateBroadcastEmergencyCallStateChangesAfterCarrierConfigChanged( diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index 48dd1e0fd2..292046a43b 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -839,9 +839,14 @@ public class MultiSimSettingController extends Handler { && phone.isUserDataEnabled() && !areSubscriptionsInSameGroup(defaultDataSub, phone.getSubId())) { log("setting data to false on " + phone.getSubId()); - phone.getDataSettingsManager().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, - mContext.getOpPackageName()); + if (phone.isUsingNewDataStack()) { + phone.getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, + mContext.getOpPackageName()); + } else { + phone.getDataEnabledSettings().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); + } } } } @@ -877,9 +882,13 @@ public class MultiSimSettingController extends Handler { // If enable is true and it's not opportunistic subscription, we don't enable it, // as there can't be two if (phone != null) { - phone.getDataSettingsManager().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, enable, - mContext.getOpPackageName()); + if (phone.isUsingNewDataStack()) { + phone.getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, enable, + mContext.getOpPackageName()); + } else { + phone.getDataEnabledSettings().setUserDataEnabled(enable, false); + } } } else { // For inactive subscription, directly write into global settings. @@ -1054,8 +1063,10 @@ public class MultiSimSettingController extends Handler { // existing phone instance. Phone[] phones = PhoneFactory.getPhones(); for (int i = mCallbacksCount; i < phones.length; i++) { - phones[i].getDataSettingsManager().registerCallback( - new DataSettingsControllerCallback(phones[i], this::post)); + if (phones[i].isUsingNewDataStack()) { + phones[i].getDataSettingsManager().registerCallback( + new DataSettingsControllerCallback(phones[i], this::post)); + } } mCallbacksCount = phones.length; } diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 9cb21945de..2260d3456a 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -16,7 +16,6 @@ package com.android.internal.telephony; -import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -29,16 +28,20 @@ import android.telephony.AccessNetworkConstants; import android.telephony.Annotation; import android.telephony.CarrierConfigManager; import android.telephony.NetworkRegistrationInfo; +import android.telephony.PcoData; import android.telephony.PhysicalChannelConfig; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataCallResponse.LinkStatus; import android.text.TextUtils; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; +import com.android.internal.telephony.dataconnection.DataConnection; +import com.android.internal.telephony.dataconnection.DcTracker; import com.android.internal.telephony.util.ArrayUtils; import com.android.internal.util.IState; import com.android.internal.util.IndentingPrintWriter; @@ -96,6 +99,7 @@ public class NetworkTypeController extends StateMachine { private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11; private static final int EVENT_INITIALIZE = 12; private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 13; + private static final int EVENT_PCO_DATA_CHANGED = 14; private static final int EVENT_BANDWIDTH_CHANGED = 15; private static final int EVENT_UPDATE_NR_ADVANCED_STATE = 16; private static final int EVENT_DEVICE_IDLE_MODE_CHANGED = 17; @@ -117,6 +121,7 @@ public class NetworkTypeController extends StateMachine { sEvents[EVENT_PREFERRED_NETWORK_MODE_CHANGED] = "EVENT_PREFERRED_NETWORK_MODE_CHANGED"; sEvents[EVENT_INITIALIZE] = "EVENT_INITIALIZE"; sEvents[EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED] = "EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED"; + sEvents[EVENT_PCO_DATA_CHANGED] = "EVENT_PCO_DATA_CHANGED"; sEvents[EVENT_BANDWIDTH_CHANGED] = "EVENT_BANDWIDTH_CHANGED"; sEvents[EVENT_UPDATE_NR_ADVANCED_STATE] = "EVENT_UPDATE_NR_ADVANCED_STATE"; sEvents[EVENT_DEVICE_IDLE_MODE_CHANGED] = "EVENT_DEVICE_IDLE_MODE_CHANGED"; @@ -164,9 +169,6 @@ public class NetworkTypeController extends StateMachine { private boolean mEnableNrAdvancedWhileRoaming = true; private boolean mIsDeviceIdleMode = false; - private @Nullable DataNetworkControllerCallback mNrAdvancedCapableByPcoChangedCallback = null; - private @Nullable DataNetworkControllerCallback mNrPhysicalLinkStatusChangedCallback = null; - /** * NetworkTypeController constructor. * @@ -230,6 +232,9 @@ public class NetworkTypeController extends StateMachine { filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); + if (!mPhone.isUsingNewDataStack()) { + mPhone.mCi.registerForPcoData(getHandler(), EVENT_PCO_DATA_CHANGED, null); + } } private void unRegisterForAllEvents() { @@ -241,6 +246,9 @@ public class NetworkTypeController extends StateMachine { mPhone.getServiceStateTracker().unregisterForNrFrequencyChanged(getHandler()); mPhone.getDeviceStateMonitor().unregisterForPhysicalChannelConfigNotifChanged(getHandler()); mPhone.getContext().unregisterReceiver(mIntentReceiver); + if (!mPhone.isUsingNewDataStack()) { + mPhone.mCi.unregisterForPcoData(getHandler()); + } } private void parseCarrierConfigs() { @@ -298,47 +306,38 @@ public class NetworkTypeController extends StateMachine { CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY); mNrAdvancedCapablePcoId = b.getInt( CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT); - if (mNrAdvancedCapablePcoId > 0 && mNrAdvancedCapableByPcoChangedCallback == null) { - mNrAdvancedCapableByPcoChangedCallback = - new DataNetworkControllerCallback(getHandler()::post) { - @Override - public void onNrAdvancedCapableByPcoChanged( - boolean nrAdvancedCapable) { - log("mIsNrAdvancedAllowedByPco=" + nrAdvancedCapable); - mIsNrAdvancedAllowedByPco = nrAdvancedCapable; - sendMessage(EVENT_UPDATE_NR_ADVANCED_STATE); - } - }; + if (mNrAdvancedCapablePcoId > 0 && mPhone.isUsingNewDataStack()) { mPhone.getDataNetworkController().registerDataNetworkControllerCallback( - mNrAdvancedCapableByPcoChangedCallback); - } else if (mNrAdvancedCapablePcoId == 0 - && mNrAdvancedCapableByPcoChangedCallback != null) { - mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( - mNrAdvancedCapableByPcoChangedCallback); - mNrAdvancedCapableByPcoChangedCallback = null; + new DataNetworkControllerCallback(getHandler()::post) { + @Override + public void onNrAdvancedCapableByPcoChanged( + boolean nrAdvancedCapable) { + log("mIsNrAdvancedAllowedByPco=" + nrAdvancedCapable); + mIsNrAdvancedAllowedByPco = nrAdvancedCapable; + sendMessage(EVENT_UPDATE_NR_ADVANCED_STATE); + } + }); } mEnableNrAdvancedWhileRoaming = b.getBoolean( CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL); mIsUsingUserDataForRrcDetection = b.getBoolean( CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL); if (!mIsPhysicalChannelConfig16Supported || mIsUsingUserDataForRrcDetection) { - if (mNrPhysicalLinkStatusChangedCallback == null) { - mNrPhysicalLinkStatusChangedCallback = - new DataNetworkControllerCallback(getHandler()::post) { - @Override - public void onPhysicalLinkStatusChanged( - @LinkStatus int status) { - sendMessage(obtainMessage( - EVENT_PHYSICAL_LINK_STATUS_CHANGED, - new AsyncResult(null, status, null))); - }}; + if (mPhone.isUsingNewDataStack()) { mPhone.getDataNetworkController().registerDataNetworkControllerCallback( - mNrPhysicalLinkStatusChangedCallback); + new DataNetworkControllerCallback(getHandler()::post) { + @Override + public void onPhysicalLinkStatusChanged( + @LinkStatus int status) { + sendMessage(obtainMessage( + EVENT_PHYSICAL_LINK_STATUS_CHANGED, + new AsyncResult(null, status, null))); + }}); + } else { + mPhone.getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .registerForPhysicalLinkStatusChanged(getHandler(), + EVENT_PHYSICAL_LINK_STATUS_CHANGED); } - } else if (mNrPhysicalLinkStatusChangedCallback != null) { - mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( - mNrPhysicalLinkStatusChangedCallback); - mNrPhysicalLinkStatusChangedCallback = null; } } } @@ -556,14 +555,15 @@ public class NetworkTypeController extends StateMachine { break; case EVENT_INITIALIZE: // The reason that we do it here is because some of the works below requires - // other modules (e.g. DataNetworkController, ServiceStateTracker), which is not - // created yet when NetworkTypeController is created. + // other modules (e.g. DcTracker, ServiceStateTracker), which is not created + // yet when NetworkTypeController is created. registerForAllEvents(); parseCarrierConfigs(); break; case EVENT_DATA_RAT_CHANGED: case EVENT_NR_STATE_CHANGED: case EVENT_NR_FREQUENCY_CHANGED: + case EVENT_PCO_DATA_CHANGED: case EVENT_UPDATE_NR_ADVANCED_STATE: // ignored break; @@ -941,6 +941,9 @@ public class NetworkTypeController extends StateMachine { transitionWithTimerTo(mLegacyState); } break; + case EVENT_PCO_DATA_CHANGED: + handlePcoData((AsyncResult) msg.obj); + break; case EVENT_UPDATE_NR_ADVANCED_STATE: updateNrAdvancedState(); break; @@ -977,7 +980,6 @@ public class NetworkTypeController extends StateMachine { } private void updateNrAdvancedState() { - log("updateNrAdvancedState"); if (!isNrConnected()) { log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); sendMessage(EVENT_NR_STATE_CHANGED); @@ -991,7 +993,33 @@ public class NetworkTypeController extends StateMachine { transitionTo(mNrConnectedState); } mIsNrAdvanced = isNrAdvanced(); - log("mIsNrAdvanced=" + mIsNrAdvanced); + } + + private void handlePcoData(AsyncResult ar) { + if (ar.exception != null) { + loge("PCO_DATA exception: " + ar.exception); + return; + } + PcoData pcodata = (PcoData) ar.result; + if (pcodata == null) { + return; + } + log("EVENT_PCO_DATA_CHANGED: pco data: " + pcodata); + DcTracker dcTracker = mPhone.getDcTracker( + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + DataConnection dc = + dcTracker != null ? dcTracker.getDataConnectionByContextId(pcodata.cid) : null; + ApnSetting apnSettings = dc != null ? dc.getApnSetting() : null; + if (apnSettings != null && apnSettings.canHandleType(ApnSetting.TYPE_DEFAULT) + && mNrAdvancedCapablePcoId > 0 + && pcodata.pcoId == mNrAdvancedCapablePcoId + ) { + log("EVENT_PCO_DATA_CHANGED: NR_ADVANCED is allowed by PCO. length:" + + pcodata.contents.length + ",value: " + Arrays.toString(pcodata.contents)); + mIsNrAdvancedAllowedByPco = pcodata.contents.length > 0 + && pcodata.contents[pcodata.contents.length - 1] == 1; + updateNrAdvancedState(); + } } } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 5c5c303c31..99bd3c5358 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -40,6 +40,7 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telecom.VideoProfile; import android.telephony.AccessNetworkConstants; +import android.telephony.Annotation.ApnType; import android.telephony.CarrierConfigManager; import android.telephony.CarrierRestrictionRules; import android.telephony.CellIdentity; @@ -59,12 +60,14 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RegistrationManager; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; +import android.util.SparseArray; import android.util.Xml; import com.android.ims.ImsCall; @@ -77,6 +80,10 @@ import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; +import com.android.internal.telephony.dataconnection.DataConnectionReasons; +import com.android.internal.telephony.dataconnection.DataEnabledSettings; +import com.android.internal.telephony.dataconnection.DcTracker; +import com.android.internal.telephony.dataconnection.TransportManager; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; @@ -215,8 +222,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // Radio state change protected static final int EVENT_RADIO_STATE_CHANGED = 47; protected static final int EVENT_SET_CARRIER_DATA_ENABLED = 48; + protected static final int EVENT_DEVICE_PROVISIONED_CHANGE = 49; + protected static final int EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE = 50; protected static final int EVENT_GET_AVAILABLE_NETWORKS_DONE = 51; + private static final int EVENT_ALL_DATA_DISCONNECTED = 52; protected static final int EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED = 53; protected static final int EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED = 54; protected static final int EVENT_GET_UICC_APPS_ENABLEMENT_DONE = 55; @@ -293,6 +303,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public CommandsInterface mCi; protected int mVmCount = 0; private boolean mDnsCheckDisabled; + // Data connection trackers. For each transport type (e.g. WWAN, WLAN), there will be a + // corresponding DcTracker. The WWAN DcTracker is for cellular data connections while + // WLAN DcTracker is for IWLAN data connection. For IWLAN legacy mode, only one (WWAN) DcTracker + // will be created. + protected final SparseArray mDcTrackers = new SparseArray<>(); protected DataNetworkController mDataNetworkController; /* Used for dispatching signals to configured carrier apps */ protected CarrierSignalAgent mCarrierSignalAgent; @@ -331,7 +346,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private final String mActionAttached; protected DeviceStateMonitor mDeviceStateMonitor; protected DisplayInfoController mDisplayInfoController; + protected TransportManager mTransportManager; protected AccessNetworksManager mAccessNetworksManager; + protected DataEnabledSettings mDataEnabledSettings; // Used for identify the carrier of current subscription protected CarrierResolver mCarrierResolver; protected SignalStrengthController mSignalStrengthController; @@ -411,6 +428,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected final RegistrantList mEmergencyCallToggledRegistrants = new RegistrantList(); + private final RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList(); + private final RegistrantList mCellInfoRegistrants = new RegistrantList(); private final RegistrantList mRedialRegistrants = new RegistrantList(); @@ -455,6 +474,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected LinkBandwidthEstimator mLinkBandwidthEstimator; + /** The flag indicating using the new data stack or not. */ + // This flag and the old data stack code will be deleted in Android 14. + private final boolean mNewDataStackEnabled; + public IccRecords getIccRecords() { return mIccRecords.get(); } @@ -596,6 +619,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // Initialize SMS stats mSmsStats = new SmsStats(this); + mNewDataStackEnabled = !mContext.getResources().getBoolean( + com.android.internal.R.bool.config_force_disable_telephony_new_data_stack); + if (getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { return; } @@ -788,6 +814,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { break; } + case EVENT_ALL_DATA_DISCONNECTED: + if (areAllDataDisconnected()) { + mAllDataDisconnectedRegistrants.notifyRegistrants(); + } + break; case EVENT_GET_USAGE_SETTING_DONE: ar = (AsyncResult) msg.obj; if (ar.exception == null) { @@ -1919,6 +1950,13 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } + /** + * @return The instance of transport manager. + */ + public TransportManager getTransportManager() { + return null; + } + /** * @return The instance of access networks manager. */ @@ -3692,11 +3730,18 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @return true if there is a matching DUN APN. */ public boolean hasMatchedTetherApnSetting() { - NetworkRegistrationInfo nrs = getServiceState().getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - if (nrs != null) { - return getDataNetworkController().getDataProfileManager() - .isTetheringDataProfileExisting(nrs.getAccessNetworkTechnology()); + if (isUsingNewDataStack()) { + NetworkRegistrationInfo nrs = getServiceState().getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (nrs != null) { + return getDataNetworkController().getDataProfileManager() + .isTetheringDataProfileExisting(nrs.getAccessNetworkTechnology()); + } + return false; + } + if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { + return getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .hasMatchedTetherApnSetting(); } return false; } @@ -3707,9 +3752,30 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @return {@code true} if internet data is allowed to be established. */ public boolean isDataAllowed() { - return getDataNetworkController().isInternetDataAllowed(); + if (isUsingNewDataStack()) { + return getDataNetworkController().isInternetDataAllowed(); + } + return isDataAllowed(ApnSetting.TYPE_DEFAULT, null); + } + + /** + * Report on whether data connectivity is allowed. + * + * @param apnType APN type + * @param reasons The reasons that data can/can't be established. This is an output param. + * @return True if data is allowed to be established + */ + public boolean isDataAllowed(@ApnType int apnType, DataConnectionReasons reasons) { + if (mAccessNetworksManager != null) { + int transport = mAccessNetworksManager.getCurrentTransport(apnType); + if (getDcTracker(transport) != null) { + return getDcTracker(transport).isDataAllowed(reasons); + } + } + return false; } + /** * Action set from carrier signalling broadcast receivers to enable/disable metered apns. */ @@ -3866,6 +3932,16 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } + /** + * Get the current for the default apn DataState. No change notification + * exists at this interface -- use + * {@link android.telephony.PhoneStateListener} instead. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public PhoneConstants.DataState getDataConnectionState() { + return getDataConnectionState(ApnSetting.TYPE_DEFAULT_STRING); + } + public void notifyCallForwardingIndicator() { } @@ -4545,6 +4621,42 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return false; } + /** + * @return True if all data connections are disconnected. + */ + public boolean areAllDataDisconnected() { + if (mAccessNetworksManager != null) { + for (int transport : mAccessNetworksManager.getAvailableTransports()) { + if (getDcTracker(transport) != null + && !getDcTracker(transport).areAllDataDisconnected()) { + return false; + } + } + } + return true; + } + + public void registerForAllDataDisconnected(Handler h, int what) { + mAllDataDisconnectedRegistrants.addUnique(h, what, null); + if (mAccessNetworksManager != null) { + for (int transport : mAccessNetworksManager.getAvailableTransports()) { + if (getDcTracker(transport) != null + && !getDcTracker(transport).areAllDataDisconnected()) { + getDcTracker(transport).registerForAllDataDisconnected( + this, EVENT_ALL_DATA_DISCONNECTED); + } + } + } + } + + public void unregisterForAllDataDisconnected(Handler h) { + mAllDataDisconnectedRegistrants.remove(h); + } + + public DataEnabledSettings getDataEnabledSettings() { + return mDataEnabledSettings; + } + @UnsupportedAppUsage public IccSmsInterfaceManager getIccSmsInterfaceManager(){ return null; @@ -4675,6 +4787,16 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return isEmergencyCallOnly; } + /** + * Get data connection tracker based on the transport type + * + * @param transportType Transport type defined in AccessNetworkConstants.TransportType + * @return The data connection tracker. Null if not found. + */ + public @Nullable DcTracker getDcTracker(int transportType) { + return mDcTrackers.get(transportType); + } + // Return true if either CSIM or RUIM app is present. By default it returns false. public boolean isCdmaSubscriptionAppPresent() { return false; @@ -4854,6 +4976,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return mIsAllowedNetworkTypesLoadedFromDb; } + /** + * @return {@code true} if using the new telephony data stack. + */ + // This flag and the old data stack code will be deleted in Android 14. + public boolean isUsingNewDataStack() { + return mNewDataStackEnabled; + } + /** * Returns the user's last setting for terminal-based call waiting * @param forCsOnly indicates the caller expects the result for CS calls only @@ -4910,6 +5040,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { pw.println(" needsOtaServiceProvisioning=" + needsOtaServiceProvisioning()); pw.println(" isInEmergencySmsMode=" + isInEmergencySmsMode()); pw.println(" isEcmCanceledForEmergency=" + isEcmCanceledForEmergency()); + pw.println(" isUsingNewDataStack=" + isUsingNewDataStack()); pw.println(" service state=" + getServiceState()); pw.flush(); pw.println("++++++++++++++++++++++++++++++++"); @@ -4925,6 +5056,16 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { pw.println("++++++++++++++++++++++++++++++++"); } + if (mAccessNetworksManager != null) { + for (int transport : mAccessNetworksManager.getAvailableTransports()) { + if (getDcTracker(transport) != null) { + getDcTracker(transport).dump(fd, pw, args); + pw.flush(); + pw.println("++++++++++++++++++++++++++++++++"); + } + } + } + if (mDataNetworkController != null) { try { mDataNetworkController.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/ProxyController.java b/src/java/com/android/internal/telephony/ProxyController.java index 498953c6e0..76f0041ee2 100644 --- a/src/java/com/android/internal/telephony/ProxyController.java +++ b/src/java/com/android/internal/telephony/ProxyController.java @@ -28,6 +28,7 @@ import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.telephony.RadioAccessFamily; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; @@ -156,6 +157,34 @@ public class ProxyController { logd("Constructor - Exit"); } + public void registerForAllDataDisconnected(int subId, Handler h, int what) { + int phoneId = SubscriptionController.getInstance().getPhoneId(subId); + + if (SubscriptionManager.isValidPhoneId(phoneId)) { + mPhones[phoneId].registerForAllDataDisconnected(h, what); + } + } + + public void unregisterForAllDataDisconnected(int subId, Handler h) { + int phoneId = SubscriptionController.getInstance().getPhoneId(subId); + + if (SubscriptionManager.isValidPhoneId(phoneId)) { + mPhones[phoneId].unregisterForAllDataDisconnected(h); + } + } + + + public boolean areAllDataDisconnected(int subId) { + int phoneId = SubscriptionController.getInstance().getPhoneId(subId); + + if (SubscriptionManager.isValidPhoneId(phoneId)) { + return mPhones[phoneId].areAllDataDisconnected(); + } else { + // if we can't find a phone for the given subId, it is disconnected. + return true; + } + } + /** * Get phone radio type and access technology. * diff --git a/src/java/com/android/internal/telephony/RetryManager.java b/src/java/com/android/internal/telephony/RetryManager.java new file mode 100644 index 0000000000..83864e46a0 --- /dev/null +++ b/src/java/com/android/internal/telephony/RetryManager.java @@ -0,0 +1,723 @@ +/** + * Copyright (C) 2009 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; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.Context; +import android.os.Build; +import android.os.PersistableBundle; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.telephony.Annotation.ApnType; +import android.telephony.CarrierConfigManager; +import android.telephony.data.ApnSetting; +import android.telephony.data.DataCallResponse; +import android.text.TextUtils; +import android.util.Pair; + +import com.android.internal.telephony.dataconnection.DataThrottler; +import com.android.internal.telephony.util.TelephonyUtils; +import com.android.telephony.Rlog; + +import java.util.ArrayList; +import java.util.Random; + +/** + * Retry manager allows a simple way to declare a series of + * retry timeouts. After creating a RetryManager the configure + * method is used to define the sequence. A simple linear series + * may be initialized using configure with three integer parameters + * The other configure method allows a series to be declared using + * a string. + *

+ * The format of the configuration string is the apn type followed by a series of parameters + * separated by a comma. There are two name value pair parameters plus a series + * of delay times. The units of of these delay times is unspecified. + * The name value pairs which may be specified are: + *

    + *
  • max_retries= + *
  • default_randomizationTime= + *
+ *

+ * apn type specifies the APN type that the retry pattern will apply for. "others" is for all other + * APN types not specified in the config. + * + * max_retries is the number of times that incrementRetryCount + * maybe called before isRetryNeeded will return false. if value + * is infinite then isRetryNeeded will always return true. + * + * default_randomizationTime will be used as the randomizationTime + * for delay times which have no supplied randomizationTime. If + * default_randomizationTime is not defined it defaults to 0. + *

+ * The other parameters define The series of delay times and each + * may have an optional randomization value separated from the + * delay time by a colon. + *

+ * Examples: + *

    + *
  • 3 retries for mms with no randomization value which means its 0: + *
    • "mms:1000, 2000, 3000"
    + * + *
  • 10 retries for default APN with a 500 default randomization value for each and + * the 4..10 retries all using 3000 as the delay: + *
    • "default:max_retries=10, default_randomization=500, 1000, 2000, 3000"
    + * + *
  • 4 retries for supl APN with a 100 as the default randomization value for the first 2 values + * and the other two having specified values of 500: + *
    • "supl:default_randomization=100, 1000, 2000, 4000:500, 5000:500"
    + * + *
  • Infinite number of retries for all other APNs with the first one at 1000, the second at 2000 + * all others will be at 3000. + *
    • "others:max_retries=infinite,1000,2000,3000
    + *
+ * + * {@hide} + */ +public class RetryManager { + public static final String LOG_TAG = "RetryManager"; + public static final boolean DBG = true; + public static final boolean VDBG = false; // STOPSHIP if true + + /** + * The default retry configuration for APNs. See above for the syntax. + */ + private static final String DEFAULT_DATA_RETRY_CONFIG = "max_retries=3, 5000, 5000, 5000"; + + /** + * The APN type used for all other APNs retry configuration. + */ + private static final String OTHERS_APN_TYPE = "others"; + + /** + * The default value (in milliseconds) for delay between APN trying (mInterApnDelay) + * within the same round + */ + private static final long DEFAULT_INTER_APN_DELAY = 20000; + + /** + * The default value (in milliseconds) for delay between APN trying (mFailFastInterApnDelay) + * within the same round when we are in fail fast mode + */ + private static final long DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING = 3000; + + /** + * The default value (in milliseconds) for retrying APN after disconnect + */ + private static final long DEFAULT_APN_RETRY_AFTER_DISCONNECT_DELAY = 10000; + + /** + * The value indicating retry should not occur. + */ + public static final long NO_RETRY = Long.MAX_VALUE; + + /** + * The value indicating network did not suggest any retry delay + */ + public static final long NO_SUGGESTED_RETRY_DELAY = DataCallResponse.RETRY_DURATION_UNDEFINED; + + /** + * If the network suggests a retry delay in the data call setup response, we will retry + * the current APN setting again. The maximum retry count is to prevent that network + * keeps asking device to retry data setup forever and causes power consumption issue. + */ + private static final int DEFAULT_MAX_SAME_APN_RETRY = 3; + + /** + * The delay (in milliseconds) between APN trying within the same round + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private long mInterApnDelay; + + /** + * The delay (in milliseconds) between APN trying within the same round when we are in + * fail fast mode + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private long mFailFastInterApnDelay; + + /** + * The delay (in milliseconds) for APN retrying after disconnect (e.g. Modem suddenly reports + * data call lost) + */ + private long mApnRetryAfterDisconnectDelay; + + /** + * The counter for same APN retrying. See {@link #DEFAULT_MAX_SAME_APN_RETRY} for the details. + */ + private int mSameApnRetryCount = 0; + + /** + * The maximum times that frameworks retries data setup with the same APN. This value could be + * changed via carrier config. See {@link #DEFAULT_MAX_SAME_APN_RETRY} for the details. + */ + private int mMaxSameApnRetry = DEFAULT_MAX_SAME_APN_RETRY; + + /** + * Retry record with times in milli-seconds + */ + private static class RetryRec { + long mDelayTime; + long mRandomizationTime; + + RetryRec(long delayTime, long randomizationTime) { + mDelayTime = delayTime; + mRandomizationTime = randomizationTime; + } + } + + /** + * The array of retry records + */ + private ArrayList mRetryArray = new ArrayList(); + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private Phone mPhone; + + private final DataThrottler mDataThrottler; + + /** + * Flag indicating whether retrying forever regardless the maximum retry count mMaxRetryCount + */ + private boolean mRetryForever = false; + + /** + * The maximum number of retries to attempt + */ + private int mMaxRetryCount; + + /** + * The current number of retries + */ + private int mRetryCount = 0; + + /** + * Random number generator. The random delay will be added into retry timer to avoid all devices + * around retrying the APN at the same time. + */ + private Random mRng = new Random(); + + /** + * Retry manager configuration string. See top of the detailed explanation. + */ + private String mConfig; + + /** + * The list to store APN setting candidates for data call setup. Most of the carriers only have + * one APN, but few carriers have more than one. + */ + private ArrayList mWaitingApns = new ArrayList<>(); + + /** + * Index pointing to the current trying APN from mWaitingApns + */ + private int mCurrentApnIndex = -1; + + /** + * Apn context type. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private String mApnType; + + private final @ApnType int apnType; + + /** + * Retry manager constructor + * @param phone Phone object + * @param dataThrottler Data throttler + * @param apnType APN type + */ + public RetryManager(@NonNull Phone phone, @NonNull DataThrottler dataThrottler, + @ApnType int apnType) { + mPhone = phone; + mDataThrottler = dataThrottler; + this.apnType = apnType; + } + + /** + * Configure for using string which allow arbitrary + * sequences of times. See class comments for the + * string format. + * + * @return true if successful + */ + @UnsupportedAppUsage + private boolean configure(String configStr) { + // Strip quotes if present. + if ((configStr.startsWith("\"") && configStr.endsWith("\""))) { + configStr = configStr.substring(1, configStr.length() - 1); + } + + // Reset the retry manager since delay, max retry count, etc...will be reset. + reset(); + + if (DBG) log("configure: '" + configStr + "'"); + mConfig = configStr; + + if (!TextUtils.isEmpty(configStr)) { + long defaultRandomization = 0; + + if (VDBG) log("configure: not empty"); + + String strArray[] = configStr.split(","); + for (int i = 0; i < strArray.length; i++) { + if (VDBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'"); + Pair value; + String splitStr[] = strArray[i].split("=", 2); + splitStr[0] = splitStr[0].trim(); + if (VDBG) log("configure: splitStr[0]='" + splitStr[0] + "'"); + if (splitStr.length > 1) { + splitStr[1] = splitStr[1].trim(); + if (VDBG) log("configure: splitStr[1]='" + splitStr[1] + "'"); + if (TextUtils.equals(splitStr[0], "default_randomization")) { + value = parseNonNegativeInt(splitStr[0], splitStr[1]); + if (!value.first) return false; + defaultRandomization = value.second; + } else if (TextUtils.equals(splitStr[0], "max_retries")) { + if (TextUtils.equals("infinite", splitStr[1])) { + mRetryForever = true; + } else { + value = parseNonNegativeInt(splitStr[0], splitStr[1]); + if (!value.first) return false; + mMaxRetryCount = value.second; + } + } else { + Rlog.e(LOG_TAG, "Unrecognized configuration name value pair: " + + strArray[i]); + return false; + } + } else { + /** + * Assume a retry time with an optional randomization value + * following a ":" + */ + splitStr = strArray[i].split(":", 2); + splitStr[0] = splitStr[0].trim(); + RetryRec rr = new RetryRec(0, 0); + value = parseNonNegativeInt("delayTime", splitStr[0]); + if (!value.first) return false; + rr.mDelayTime = value.second; + + // Check if optional randomization value present + if (splitStr.length > 1) { + splitStr[1] = splitStr[1].trim(); + if (VDBG) log("configure: splitStr[1]='" + splitStr[1] + "'"); + value = parseNonNegativeInt("randomizationTime", splitStr[1]); + if (!value.first) return false; + rr.mRandomizationTime = value.second; + } else { + rr.mRandomizationTime = defaultRandomization; + } + mRetryArray.add(rr); + } + } + if (mRetryArray.size() > mMaxRetryCount) { + mMaxRetryCount = mRetryArray.size(); + if (VDBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount); + } + } else { + log("configure: cleared"); + } + + if (VDBG) log("configure: true"); + return true; + } + + /** + * Configure the retry manager + */ + private void configureRetry() { + String configString = null; + String otherConfigString = null; + + try { + if (TelephonyUtils.IS_DEBUGGABLE) { + // Using system properties is easier for testing from command line. + String config = SystemProperties.get("test.data_retry_config"); + if (!TextUtils.isEmpty(config)) { + configure(config); + return; + } + } + + CarrierConfigManager configManager = (CarrierConfigManager) + mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); + PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); + + mInterApnDelay = b.getLong( + CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, + DEFAULT_INTER_APN_DELAY); + mFailFastInterApnDelay = b.getLong( + CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, + DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING); + mApnRetryAfterDisconnectDelay = b.getLong( + CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, + DEFAULT_APN_RETRY_AFTER_DISCONNECT_DELAY); + mMaxSameApnRetry = b.getInt( + CarrierConfigManager + .KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, + DEFAULT_MAX_SAME_APN_RETRY); + + // Load all retry patterns for all different APNs. + String[] allConfigStrings = b.getStringArray( + CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS); + if (allConfigStrings != null) { + for (String s : allConfigStrings) { + if (!TextUtils.isEmpty(s)) { + String splitStr[] = s.split(":", 2); + if (splitStr.length == 2) { + String apnTypeStr = splitStr[0].trim(); + // Check if this retry pattern is for the APN we want. + if (apnTypeStr.equals(ApnSetting.getApnTypeString(apnType))) { + // Extract the config string. Note that an empty string is valid + // here, meaning no retry for the specified APN. + configString = splitStr[1]; + break; + } else if (apnTypeStr.equals(OTHERS_APN_TYPE)) { + // Extract the config string. Note that an empty string is valid + // here, meaning no retry for all other APNs. + otherConfigString = splitStr[1]; + } + } + } + } + } + + if (configString == null) { + if (otherConfigString != null) { + configString = otherConfigString; + } else { + // We should never reach here. If we reach here, it must be a configuration + // error bug. + log("Invalid APN retry configuration!. Use the default one now."); + configString = DEFAULT_DATA_RETRY_CONFIG; + } + } + } catch (NullPointerException ex) { + // We should never reach here unless there is a bug + log("Failed to read configuration! Use the hardcoded default value."); + + mInterApnDelay = DEFAULT_INTER_APN_DELAY; + mFailFastInterApnDelay = DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING; + configString = DEFAULT_DATA_RETRY_CONFIG; + } + + if (VDBG) { + log("mInterApnDelay = " + mInterApnDelay + ", mFailFastInterApnDelay = " + + mFailFastInterApnDelay); + } + + configure(configString); + } + + /** + * Return the timer that should be used to trigger the data reconnection + */ + @UnsupportedAppUsage + private long getRetryTimer() { + int index; + if (mRetryCount < mRetryArray.size()) { + index = mRetryCount; + } else { + index = mRetryArray.size() - 1; + } + + long retVal; + if ((index >= 0) && (index < mRetryArray.size())) { + retVal = mRetryArray.get(index).mDelayTime + nextRandomizationTime(index); + } else { + retVal = 0; + } + + if (DBG) log("getRetryTimer: " + retVal); + return retVal; + } + + /** + * Parse an integer validating the value is not negative. + * @param name Name + * @param stringValue Value + * @return Pair.first == true if stringValue an integer >= 0 + */ + private Pair parseNonNegativeInt(String name, String stringValue) { + int value; + Pair retVal; + try { + value = Integer.parseInt(stringValue); + retVal = new Pair<>(validateNonNegativeInt(name, value), value); + } catch (NumberFormatException e) { + Rlog.e(LOG_TAG, name + " bad value: " + stringValue, e); + retVal = new Pair<>(false, 0); + } + if (VDBG) { + log("parseNonNegativeInt: " + name + ", " + stringValue + ", " + + retVal.first + ", " + retVal.second); + } + return retVal; + } + + /** + * Validate an integer is >= 0 and logs an error if not + * @param name Name + * @param value Value + * @return Pair.first + */ + private boolean validateNonNegativeInt(String name, long value) { + boolean retVal; + if (value < 0) { + Rlog.e(LOG_TAG, name + " bad value: is < 0"); + retVal = false; + } else { + retVal = true; + } + if (VDBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal); + return retVal; + } + + /** + * Return next random number for the index + * @param index Retry index + */ + private long nextRandomizationTime(int index) { + long randomTime = mRetryArray.get(index).mRandomizationTime; + if (randomTime == 0) { + return 0; + } else { + return mRng.nextInt((int) randomTime); + } + } + + private long getNetworkSuggestedRetryDelay() { + long retryElapseTime = mDataThrottler.getRetryTime(apnType); + if (retryElapseTime == NO_RETRY || retryElapseTime == NO_SUGGESTED_RETRY_DELAY) { + return retryElapseTime; + } + + // The time from data throttler is system's elapsed time. We need to return the delta. If + // less than 0, then return 0 (i.e. retry immediately). + return Math.max(0, retryElapseTime - SystemClock.elapsedRealtime()); + } + + /** + * Get the next APN setting for data call setup. + * @return APN setting to try. {@code null} if cannot find any APN, + */ + public @Nullable ApnSetting getNextApnSetting() { + if (mWaitingApns == null || mWaitingApns.size() == 0) { + log("Waiting APN list is null or empty."); + return null; + } + + long networkSuggestedRetryDelay = getNetworkSuggestedRetryDelay(); + if (networkSuggestedRetryDelay == NO_RETRY) { + log("Network suggested no retry."); + return null; + } + + // If the network had suggested a retry delay, we should retry the current APN again + // (up to mMaxSameApnRetry times) instead of getting the next APN setting from + // our own list. If the APN waiting list has been reset before a setup data responses + // arrive (i.e. mCurrentApnIndex=-1), then ignore the network suggested retry. + if (mCurrentApnIndex != -1 && networkSuggestedRetryDelay != NO_SUGGESTED_RETRY_DELAY + && mSameApnRetryCount < mMaxSameApnRetry) { + mSameApnRetryCount++; + return mWaitingApns.get(mCurrentApnIndex); + } + + mSameApnRetryCount = 0; + + int index = mCurrentApnIndex; + // Loop through the APN list to find out the index of next non-permanent failed APN. + while (true) { + if (++index == mWaitingApns.size()) index = 0; + + // Stop if we find the non-failed APN. + if (!mWaitingApns.get(index).getPermanentFailed()) { + break; + } + + // If all APNs have permanently failed, bail out. + if (mWaitingApns.stream().allMatch(ApnSetting::getPermanentFailed)) { + return null; + } + } + + mCurrentApnIndex = index; + return mWaitingApns.get(mCurrentApnIndex); + } + + /** + * Get the delay for trying the next waiting APN from the list. + * @param failFastEnabled True if fail fast mode enabled. In this case we'll use a shorter + * delay. + * @return delay in milliseconds + */ + public long getDelayForNextApn(boolean failFastEnabled) { + + if (mWaitingApns == null || mWaitingApns.size() == 0) { + log("Waiting APN list is null or empty."); + return NO_RETRY; + } + + long networkSuggestedDelay = getNetworkSuggestedRetryDelay(); + log("Network suggested delay=" + networkSuggestedDelay + "ms"); + + if (networkSuggestedDelay == NO_RETRY) { + log("Network suggested not retrying."); + return NO_RETRY; + } + + if (networkSuggestedDelay != NO_SUGGESTED_RETRY_DELAY + && mSameApnRetryCount < mMaxSameApnRetry) { + // If the network explicitly suggests a retry delay, we should use it, even in fail fast + // mode. + log("Network suggested retry in " + networkSuggestedDelay + " ms."); + return networkSuggestedDelay; + } + + // In order to determine the delay to try next APN, we need to peek the next available APN. + // Case 1 - If we will start the next round of APN trying, + // we use the exponential-growth delay. (e.g. 5s, 10s, 30s...etc.) + // Case 2 - If we are still within the same round of APN trying, + // we use the fixed standard delay between APNs. (e.g. 20s) + + int index = mCurrentApnIndex; + while (true) { + if (++index >= mWaitingApns.size()) index = 0; + + // Stop if we find the non-failed APN. + if (!mWaitingApns.get(index).getPermanentFailed()) { + break; + } + + // If all APNs have permanently failed, bail out. + if (mWaitingApns.stream().allMatch(ApnSetting::getPermanentFailed)) { + log("All APNs have permanently failed."); + return NO_RETRY; + } + } + + long delay; + if (index <= mCurrentApnIndex) { + // Case 1, if the next APN is in the next round. + if (!mRetryForever && mRetryCount + 1 > mMaxRetryCount) { + log("Reached maximum retry count " + mMaxRetryCount + "."); + return NO_RETRY; + } + delay = getRetryTimer(); + ++mRetryCount; + } else { + // Case 2, if the next APN is still in the same round. + delay = mInterApnDelay; + } + + if (failFastEnabled && delay > mFailFastInterApnDelay) { + // If we enable fail fast mode, and the delay we got is longer than + // fail-fast delay (mFailFastInterApnDelay), use the fail-fast delay. + // If the delay we calculated is already shorter than fail-fast delay, + // then ignore fail-fast delay. + delay = mFailFastInterApnDelay; + } + + return delay; + } + + /** + * Mark the APN setting permanently failed. + * @param apn APN setting to be marked as permanently failed + * */ + public void markApnPermanentFailed(ApnSetting apn) { + if (apn != null) { + apn.setPermanentFailed(true); + } + } + + /** + * Reset the retry manager. + */ + private void reset() { + mMaxRetryCount = 0; + mRetryCount = 0; + mCurrentApnIndex = -1; + mSameApnRetryCount = 0; + mRetryArray.clear(); + } + + /** + * Set waiting APNs for retrying in case needed. + * @param waitingApns Waiting APN list + */ + public void setWaitingApns(ArrayList waitingApns) { + + if (waitingApns == null) { + log("No waiting APNs provided"); + return; + } + + mWaitingApns = waitingApns; + + // Since we replace the entire waiting APN list, we need to re-config this retry manager. + configureRetry(); + + for (ApnSetting apn : mWaitingApns) { + apn.setPermanentFailed(false); + } + + log("Setting " + mWaitingApns.size() + " waiting APNs."); + + if (VDBG) { + for (int i = 0; i < mWaitingApns.size(); i++) { + log(" [" + i + "]:" + mWaitingApns.get(i)); + } + } + } + + /** + * Get the list of waiting APNs. + * @return the list of waiting APNs + */ + public @NonNull ArrayList getWaitingApns() { + return mWaitingApns; + } + + /** + * Get the delay in milliseconds for APN retry after disconnect + * @return The delay in milliseconds + */ + public long getRetryAfterDisconnectDelay() { + return mApnRetryAfterDisconnectDelay; + } + + public String toString() { + if (mConfig == null) return ""; + return "RetryManager: apnType=" + ApnSetting.getApnTypeString(apnType) + + " mRetryCount=" + + mRetryCount + " mMaxRetryCount=" + mMaxRetryCount + " mCurrentApnIndex=" + + mCurrentApnIndex + " mSameApnRtryCount=" + mSameApnRetryCount + + " networkSuggestedDelay=" + getNetworkSuggestedRetryDelay() + " mRetryForever=" + + mRetryForever + " mInterApnDelay=" + mInterApnDelay + + " mApnRetryAfterDisconnectDelay=" + mApnRetryAfterDisconnectDelay + + " mConfig={" + mConfig + "}"; + } + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private void log(String s) { + Rlog.d(LOG_TAG, "[" + ApnSetting.getApnTypeString(apnType) + "] " + s); + } +} diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index d362a20d07..99ee96bc24 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -37,6 +37,7 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.res.Resources; import android.hardware.radio.V1_0.CellInfoType; +import android.net.NetworkCapabilities; import android.os.AsyncResult; import android.os.BaseBundle; import android.os.Build; @@ -94,6 +95,7 @@ import com.android.internal.telephony.cdnr.CarrierDisplayNameResolver; import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetwork; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; +import com.android.internal.telephony.dataconnection.DataConnection; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.TelephonyMetrics; @@ -222,6 +224,7 @@ public class ServiceStateTracker extends Handler { /* Radio power off pending flag and tag counter */ private boolean mPendingRadioPowerOffAfterDataOff = false; + private int mPendingRadioPowerOffAfterDataOffTag = 0; /** Waiting period before recheck gprs and voice registration. */ public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; @@ -718,15 +721,17 @@ public class ServiceStateTracker extends Handler { registerForImsCapabilityChanged(mCSST, CarrierServiceStateTracker.CARRIER_EVENT_IMS_CAPABILITIES_CHANGED, null); - mDataDisconnectedCallback = new DataNetworkControllerCallback(this::post) { - @Override - public void onAnyDataNetworkExistingChanged(boolean anyDataExisting) { - log("onAnyDataNetworkExistingChanged: anyDataExisting=" + anyDataExisting); - if (!anyDataExisting) { - sendEmptyMessage(EVENT_ALL_DATA_DISCONNECTED); + if (mPhone.isUsingNewDataStack()) { + mDataDisconnectedCallback = new DataNetworkControllerCallback(this::post) { + @Override + public void onAnyDataNetworkExistingChanged(boolean anyDataExisting) { + log("onAnyDataNetworkExistingChanged: anyDataExisting=" + anyDataExisting); + if (!anyDataExisting) { + sendEmptyMessage(EVENT_ALL_DATA_DISCONNECTED); + } } - } - }; + }; + } } @VisibleForTesting @@ -1192,9 +1197,22 @@ public class ServiceStateTracker extends Handler { switch (msg.what) { case EVENT_SET_RADIO_POWER_OFF: synchronized(this) { - mPendingRadioPowerOffAfterDataOff = false; - log("Wait for all data networks torn down timed out. Power off now."); - hangupAndPowerOff(); + if (mPhone.isUsingNewDataStack()) { + mPendingRadioPowerOffAfterDataOff = false; + log("Wait for all data networks torn down timed out. Power off now."); + hangupAndPowerOff(); + return; + } + if (mPendingRadioPowerOffAfterDataOff && + (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) { + if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now."); + hangupAndPowerOff(); + mPendingRadioPowerOffAfterDataOffTag += 1; + mPendingRadioPowerOffAfterDataOff = false; + } else { + log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 + + "!= tag=" + mPendingRadioPowerOffAfterDataOffTag); + } } break; @@ -1462,25 +1480,40 @@ public class ServiceStateTracker extends Handler { break; case EVENT_ALL_DATA_DISCONNECTED: - log("EVENT_ALL_DATA_DISCONNECTED"); - if (!mPendingRadioPowerOffAfterDataOff) return; - boolean areAllDataDisconnectedOnAllPhones = true; - for (Phone phone : PhoneFactory.getPhones()) { - if (phone.getDataNetworkController().areAllDataDisconnected()) { - phone.getDataNetworkController() - .unregisterDataNetworkControllerCallback( - mDataDisconnectedCallback); - } else { - log("Still waiting for all data disconnected on phone: " - + phone.getSubId()); - areAllDataDisconnectedOnAllPhones = false; + if (mPhone.isUsingNewDataStack()) { + log("EVENT_ALL_DATA_DISCONNECTED"); + if (!mPendingRadioPowerOffAfterDataOff) return; + boolean areAllDataDisconnectedOnAllPhones = true; + for (Phone phone : PhoneFactory.getPhones()) { + if (phone.getDataNetworkController().areAllDataDisconnected()) { + phone.getDataNetworkController() + .unregisterDataNetworkControllerCallback( + mDataDisconnectedCallback); + } else { + log("Still waiting for all data disconnected on phone: " + + phone.getSubId()); + areAllDataDisconnectedOnAllPhones = false; + } + } + if (areAllDataDisconnectedOnAllPhones) { + mPendingRadioPowerOffAfterDataOff = false; + removeMessages(EVENT_SET_RADIO_POWER_OFF); + if (DBG) log("Data disconnected for all phones, turn radio off now."); + hangupAndPowerOff(); } + return; } - if (areAllDataDisconnectedOnAllPhones) { - mPendingRadioPowerOffAfterDataOff = false; - removeMessages(EVENT_SET_RADIO_POWER_OFF); - if (DBG) log("Data disconnected for all phones, turn radio off now."); - hangupAndPowerOff(); + int dds = SubscriptionManager.getDefaultDataSubscriptionId(); + ProxyController.getInstance().unregisterForAllDataDisconnected(dds, this); + synchronized(this) { + if (mPendingRadioPowerOffAfterDataOff) { + if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now."); + hangupAndPowerOff(); + mPendingRadioPowerOffAfterDataOffTag += 1; + mPendingRadioPowerOffAfterDataOff = false; + } else { + log("EVENT_ALL_DATA_DISCONNECTED is stale"); + } } break; @@ -2132,8 +2165,18 @@ public class ServiceStateTracker extends Handler { private boolean isInternetPhysicalChannelConfig(PhysicalChannelConfig config) { for (int cid : config.getContextIds()) { - if (mPhone.getDataNetworkController().isInternetNetwork(cid)) { - return true; + if (mPhone.isUsingNewDataStack()) { + if (mPhone.getDataNetworkController().isInternetNetwork(cid)) { + return true; + } + } else { + DataConnection dc = mPhone.getDcTracker( + AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .getDataConnectionByContextId(cid); + if (dc != null && dc.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + return true; + } } } return false; @@ -3092,8 +3135,17 @@ public class ServiceStateTracker extends Handler { mCi.setRadioPower(true, forEmergencyCall, isSelectedPhoneForEmergencyCall, null); } else if ((!mDesiredPowerState || mRadioDisabledByCarrier) && mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) { - if (DBG) log("setPowerStateToDesired: powerOffRadioSafely()"); - powerOffRadioSafely(); + // If it's on and available and we want it off gracefully + if (!mPhone.isUsingNewDataStack() && mImsRegistrationOnOff + && getRadioPowerOffDelayTimeoutForImsRegistration() > 0) { + if (DBG) log("setPowerStateToDesired: delaying power off until IMS dereg."); + startDelayRadioOffWaitingForImsDeregTimeout(); + // Return early here as we do not want to hit the cancel timeout code below. + return; + } else { + if (DBG) log("setPowerStateToDesired: powerOffRadioSafely()"); + powerOffRadioSafely(); + } } else if (mDeviceShuttingDown && (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE)) { // !mDesiredPowerState condition above will happen first if the radio is on, so we will @@ -3467,6 +3519,11 @@ public class ServiceStateTracker extends Handler { NetworkRegistrationInfo newNrs = mNewSS.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, transport); + // If the previously it was not in service, and now it's in service, trigger the + // attached event. Also if airplane mode was just turned on, and data is already in + // service, we need to trigger the attached event again so that DcTracker can setup + // data on all connectable APNs again (because we've already torn down all data + // connections just before airplane mode turned on) boolean changed = (oldNrs == null || !oldNrs.isInService() || hasAirplaneModeOnChanged) && (newNrs != null && newNrs.isInService()); hasDataAttached.put(transport, changed); @@ -4965,33 +5022,96 @@ public class ServiceStateTracker extends Handler { public void powerOffRadioSafely() { synchronized (this) { if (!mPendingRadioPowerOffAfterDataOff) { - // hang up all active voice calls first - if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) { - mPhone.mCT.mRingingCall.hangupIfAlive(); - mPhone.mCT.mBackgroundCall.hangupIfAlive(); - mPhone.mCT.mForegroundCall.hangupIfAlive(); - } + if (mPhone.isUsingNewDataStack()) { + // hang up all active voice calls first + if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) { + mPhone.mCT.mRingingCall.hangupIfAlive(); + mPhone.mCT.mBackgroundCall.hangupIfAlive(); + mPhone.mCT.mForegroundCall.hangupIfAlive(); + } - for (Phone phone : PhoneFactory.getPhones()) { - if (!phone.getDataNetworkController().areAllDataDisconnected()) { - log("powerOffRadioSafely: Data is active on phone " + phone.getSubId() - + ". Wait for all data disconnect."); - mPendingRadioPowerOffAfterDataOff = true; - phone.getDataNetworkController().registerDataNetworkControllerCallback( - mDataDisconnectedCallback); + for (Phone phone : PhoneFactory.getPhones()) { + if (!phone.getDataNetworkController().areAllDataDisconnected()) { + log("powerOffRadioSafely: Data is active on phone " + phone.getSubId() + + ". Wait for all data disconnect."); + mPendingRadioPowerOffAfterDataOff = true; + phone.getDataNetworkController().registerDataNetworkControllerCallback( + mDataDisconnectedCallback); + } } - } - // Tear down outside of the disconnected check to prevent race conditions. - mPhone.getDataNetworkController().tearDownAllDataNetworks( - DataNetwork.TEAR_DOWN_REASON_AIRPLANE_MODE_ON); + // Tear down outside of the disconnected check to prevent race conditions. + mPhone.getDataNetworkController().tearDownAllDataNetworks( + DataNetwork.TEAR_DOWN_REASON_AIRPLANE_MODE_ON); - if (mPendingRadioPowerOffAfterDataOff) { - sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, - POWER_OFF_ALL_DATA_NETWORKS_DISCONNECTED_TIMEOUT); - } else { - log("powerOffRadioSafely: No data is connected, turn off radio now."); + if (mPendingRadioPowerOffAfterDataOff) { + sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, + POWER_OFF_ALL_DATA_NETWORKS_DISCONNECTED_TIMEOUT); + } else { + log("powerOffRadioSafely: No data is connected, turn off radio now."); + hangupAndPowerOff(); + } + return; + } + int dds = SubscriptionManager.getDefaultDataSubscriptionId(); + // To minimize race conditions we call cleanUpAllConnections on + // both if else paths instead of before this isDisconnected test. + if (mPhone.areAllDataDisconnected() + && (dds == mPhone.getSubId() + || (dds != mPhone.getSubId() + && ProxyController.getInstance().areAllDataDisconnected(dds)))) { + // To minimize race conditions we do this after isDisconnected + for (int transport : mAccessNetworksManager.getAvailableTransports()) { + if (mPhone.getDcTracker(transport) != null) { + mPhone.getDcTracker(transport).cleanUpAllConnections( + Phone.REASON_RADIO_TURNED_OFF); + } + } + if (DBG) { + log("powerOffRadioSafely: Data disconnected, turn off radio now."); + } hangupAndPowerOff(); + } else { + // hang up all active voice calls first + if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) { + mPhone.mCT.mRingingCall.hangupIfAlive(); + mPhone.mCT.mBackgroundCall.hangupIfAlive(); + mPhone.mCT.mForegroundCall.hangupIfAlive(); + } + for (int transport : mAccessNetworksManager.getAvailableTransports()) { + if (mPhone.getDcTracker(transport) != null) { + mPhone.getDcTracker(transport).cleanUpAllConnections( + Phone.REASON_RADIO_TURNED_OFF); + } + } + + if (dds != mPhone.getSubId() + && !ProxyController.getInstance().areAllDataDisconnected(dds)) { + if (DBG) { + log(String.format("powerOffRadioSafely: Data is active on DDS (%d)." + + " Wait for all data disconnect", dds)); + } + // Data is not disconnected on DDS. Wait for the data disconnect complete + // before sending the RADIO_POWER off. + ProxyController.getInstance().registerForAllDataDisconnected(dds, this, + EVENT_ALL_DATA_DISCONNECTED); + mPendingRadioPowerOffAfterDataOff = true; + } + Message msg = Message.obtain(this); + msg.what = EVENT_SET_RADIO_POWER_OFF; + msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag; + if (sendMessageDelayed(msg, 30000)) { + if (DBG) { + log("powerOffRadioSafely: Wait up to 30s for data to disconnect, " + + "then turn off radio."); + } + mPendingRadioPowerOffAfterDataOff = true; + } else { + log("powerOffRadioSafely: Cannot send delayed Msg, turn off radio right" + + " away."); + hangupAndPowerOff(); + mPendingRadioPowerOffAfterDataOff = false; + } } } } @@ -5007,6 +5127,7 @@ public class ServiceStateTracker extends Handler { if (mPendingRadioPowerOffAfterDataOff) { if (DBG) log("Process pending request to turn radio off."); hangupAndPowerOff(); + mPendingRadioPowerOffAfterDataOffTag += 1; mPendingRadioPowerOffAfterDataOff = false; return true; } @@ -5240,6 +5361,7 @@ public class ServiceStateTracker extends Handler { pw.println(" mDesiredPowerState=" + mDesiredPowerState); pw.println(" mRestrictedState=" + mRestrictedState); pw.println(" mPendingRadioPowerOffAfterDataOff=" + mPendingRadioPowerOffAfterDataOff); + pw.println(" mPendingRadioPowerOffAfterDataOffTag=" + mPendingRadioPowerOffAfterDataOffTag); pw.println(" mCellIdentity=" + Rlog.pii(VDBG, mCellIdentity)); pw.println(" mLastCellInfoReqTime=" + mLastCellInfoReqTime); dumpCellInfoList(pw); diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java index 08c02e2ea9..dcbd2d5a95 100644 --- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java +++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java @@ -27,6 +27,7 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.system.StructStatVfs; +import android.telephony.AccessNetworkConstants.TransportType; import android.text.TextUtils; import com.android.ims.ImsManager; @@ -39,6 +40,9 @@ import com.android.internal.telephony.data.DataServiceManager; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; +import com.android.internal.telephony.dataconnection.DataEnabledSettings; +import com.android.internal.telephony.dataconnection.DcTracker; +import com.android.internal.telephony.dataconnection.TransportManager; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; @@ -309,6 +313,10 @@ public class TelephonyComponentFactory { return new SimActivationTracker(phone); } + public DcTracker makeDcTracker(Phone phone, @TransportType int transportType) { + return new DcTracker(phone, transportType); + } + public CarrierSignalAgent makeCarrierSignalAgent(Phone phone) { return new CarrierSignalAgent(phone); } @@ -396,6 +404,10 @@ public class TelephonyComponentFactory { return new DeviceStateMonitor(phone); } + public TransportManager makeTransportManager(Phone phone) { + return new TransportManager(phone); + } + /** * Make access networks manager * @@ -418,6 +430,10 @@ public class TelephonyComponentFactory { return new LocaleTracker(phone, nitzStateMachine, looper); } + public DataEnabledSettings makeDataEnabledSettings(Phone phone) { + return new DataEnabledSettings(phone); + } + public Phone makePhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory) { diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index 57b36022fc..e7734d5954 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -58,6 +58,7 @@ import android.util.SparseArray; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RIL; import com.android.internal.telephony.SlidingWindowEventCounter; +import com.android.internal.telephony.dataconnection.DataThrottler; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -66,6 +67,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -153,6 +155,8 @@ public class AccessNetworksManager extends Handler { private final RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList(); + private final Set mDataThrottlers = new HashSet<>(); + private final BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -169,10 +173,20 @@ public class AccessNetworksManager extends Handler { } }; + /** + * The current transport of the APN type. The key is the APN type, and the value is the + * transport. + */ + private final Map mCurrentTransports = new ConcurrentHashMap<>(); + /** * The preferred transport of the APN type. The key is the APN type, and the value is the - * transport. The preferred transports are updated as soon as QNS changes the preference. + * transport. The preferred transports are updated as soon as QNS changes the preference, while + * the current transports are updated after handover complete. */ + // TODO: Deprecate mPreferredTransports. Should expose mAvailableNetworks to + // DataNetworkController after we support multi preferred access networks (i.e. + // DataNetworkController might select 2nd preferred access network in some scenarios.) private final Map mPreferredTransports = new ConcurrentHashMap<>(); /** @@ -181,6 +195,21 @@ public class AccessNetworksManager extends Handler { private final @NonNull Set mAccessNetworksManagerCallbacks = new ArraySet<>(); + /** + * Registers the data throttler in order to receive APN status changes. + * + * @param dataThrottler the data throttler to register + */ + public void registerDataThrottler(DataThrottler dataThrottler) { + this.post(() -> { + QualifiedNetworksServiceConnection serviceConnection = mServiceConnection; + this.mDataThrottlers.add(dataThrottler); + if (serviceConnection != null) { + serviceConnection.registerDataThrottler(dataThrottler); + } + }); + } + /** * Represents qualified network types list on a specific APN type. */ @@ -222,6 +251,18 @@ public class AccessNetworksManager extends Handler { } private final class QualifiedNetworksServiceConnection implements ServiceConnection { + + /** + * The APN throttle status callback is attached to the service connection so that they have + * the same life cycle. + */ + @NonNull + private final ThrottleStatusChangedCallback mThrottleStatusCallback; + + QualifiedNetworksServiceConnection() { + mThrottleStatusCallback = new ThrottleStatusChangedCallback(); + } + @Override public void onServiceConnected(ComponentName name, IBinder service) { if (DBG) log("onServiceConnected " + name); @@ -233,6 +274,9 @@ public class AccessNetworksManager extends Handler { service.linkToDeath(mDeathRecipient, 0 /* flags */); mIQualifiedNetworksService.createNetworkAvailabilityProvider(mPhone.getPhoneId(), new QualifiedNetworksServiceCallback()); + + registerDataThrottlersFirstTime(); + } catch (RemoteException e) { loge("Remote exception. " + e); } @@ -241,9 +285,55 @@ public class AccessNetworksManager extends Handler { @Override public void onServiceDisconnected(ComponentName name) { if (DBG) log("onServiceDisconnected " + name); + unregisterForThrottleCallbacks(); mTargetBindingPackageName = null; } + /** + * Runs on all of the data throttlers when the service is connected + */ + private void registerDataThrottlersFirstTime() { + post(() -> { + for (DataThrottler dataThrottler : mDataThrottlers) { + dataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); + } + }); + } + + private void registerDataThrottler(DataThrottler dataThrottler) { + post(() -> { + dataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); + }); + } + + private void unregisterForThrottleCallbacks() { + post(() -> { + for (DataThrottler dataThrottler : mDataThrottlers) { + dataThrottler.unregisterForThrottleStatusChanges(mThrottleStatusCallback); + } + }); + } + } + + private class ThrottleStatusChangedCallback implements DataThrottler.Callback { + @Override + public void onThrottleStatusChanged(List throttleStatuses) { + post(() -> { + try { + List throttleStatusesBySlot = + throttleStatuses + .stream() + .filter(x -> x.getSlotIndex() == mPhone.getPhoneId()) + .collect(Collectors.toList()); + if (mIQualifiedNetworksService != null) { + mIQualifiedNetworksService.reportThrottleStatusChanged(mPhone.getPhoneId(), + throttleStatusesBySlot); + } + } catch (Exception ex) { + loge("onThrottleStatusChanged", ex); + } + }); + } } private final class QualifiedNetworksServiceCallback extends @@ -415,10 +505,11 @@ public class AccessNetworksManager extends Handler { bindQualifiedNetworksService(); } - // Using post to delay the registering because data retry manager and data config - // manager instances are created later than access networks manager. - post(() -> { - mPhone.getDataNetworkController().getDataRetryManager().registerCallback( + if (phone.isUsingNewDataStack()) { + // Using post to delay the registering because data retry manager and data config + // manager instances are created later than access networks manager. + post(() -> { + mPhone.getDataNetworkController().getDataRetryManager().registerCallback( new DataRetryManager.DataRetryManagerCallback(this::post) { @Override public void onThrottleStatusChanged(List throttleStatuses) { @@ -433,15 +524,16 @@ public class AccessNetworksManager extends Handler { } } }); - mDataConfigManager = mPhone.getDataNetworkController().getDataConfigManager(); - mDataConfigManager.registerCallback( - new DataConfigManager.DataConfigManagerCallback(this::post) { - @Override - public void onDeviceConfigChanged() { - mApnTypeToQnsChangeNetworkCounter.clear(); - } - }); - }); + mDataConfigManager = mPhone.getDataNetworkController().getDataConfigManager(); + mDataConfigManager.registerCallback( + new DataConfigManager.DataConfigManagerCallback(this::post) { + @Override + public void onDeviceConfigChanged() { + mApnTypeToQnsChangeNetworkCounter.clear(); + } + }); + }); + } } /** @@ -621,6 +713,60 @@ public class AccessNetworksManager extends Handler { return mAvailableTransports; } + /** + * Get the transport based on the network capability. + * + * @param netCap The network capability. + * @return The transport type. + */ + public @TransportType int getCurrentTransportByNetworkCapability(@NetCapability int netCap) { + return getCurrentTransport(DataUtils.networkCapabilityToApnType(netCap)); + } + + /** + * Get the transport based on the APN type. + * + * @param apnType APN type + * @return The transport type + */ + // TODO: Remove this after TransportManager is removed. + public @TransportType int getCurrentTransport(@ApnType int apnType) { + // In legacy mode, always route to cellular. + if (isInLegacyMode()) { + return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; + } + + // If we can't find the corresponding transport, always route to cellular. + return mCurrentTransports.get(apnType) == null + ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mCurrentTransports.get(apnType); + } + + /** + * Set the current transport of a network capability. + * + * @param netCap The network capability. + * @param transport The transport. + */ + public void setCurrentTransportByNetworkCapability(@NetCapability int netCap, + @TransportType int transport) { + setCurrentTransport(DataUtils.networkCapabilityToApnType(netCap), transport); + } + + /** + * Set the current transport of apn type. + * + * @param apnType The APN type + * @param transport The transport. + */ + // TODO: Remove this after TransportManager is removed. + public void setCurrentTransport(@ApnType int apnType, @TransportType int transport) { + Integer previousTransport = mCurrentTransports.put(apnType, transport); + if (previousTransport == null || previousTransport != transport) { + logl("setCurrentTransport: apnType=" + ApnSetting.getApnTypeString(apnType) + + ", transport=" + AccessNetworkConstants.transportTypeToString(transport)); + } + } + private static @TransportType int getTransportFromAccessNetwork(int accessNetwork) { return accessNetwork == AccessNetworkType.IWLAN ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN @@ -679,14 +825,20 @@ public class AccessNetworksManager extends Handler { } /** - * Check if there is any APN type preferred on IWLAN. + * Check if there is any APN type's current transport is on IWLAN. * * @return {@code true} if there is any APN is on IWLAN, otherwise {@code false}. */ public boolean isAnyApnOnIwlan() { for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { - if (getPreferredTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - return true; + if (mPhone.isUsingNewDataStack()) { + if (getPreferredTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { + return true; + } + } else { + if (getCurrentTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { + return true; + } } } return false; @@ -750,6 +902,14 @@ public class AccessNetworksManager extends Handler { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println(AccessNetworksManager.class.getSimpleName() + "-" + mPhone.getPhoneId() + ":"); pw.increaseIndent(); + pw.println("current transports="); + pw.increaseIndent(); + for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { + pw.println(ApnSetting.getApnTypeString(apnType) + + ": " + AccessNetworkConstants.transportTypeToString( + getCurrentTransport(apnType))); + } + pw.decreaseIndent(); pw.println("preferred transports="); pw.increaseIndent(); for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index cc03fd478c..b71db48eae 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -134,7 +134,8 @@ public class DataConfigManager extends Handler { private static final String DATA_CONFIG_NETWORK_TYPE_IDEN = "iDEN"; /** Network type LTE. Should not be used outside of DataConfigManager. */ - private static final String DATA_CONFIG_NETWORK_TYPE_LTE = "LTE"; + // TODO: Public only for use by DcTracker. This should be private once DcTracker is removed. + public static final String DATA_CONFIG_NETWORK_TYPE_LTE = "LTE"; /** Network type HSPA+. Should not be used outside of DataConfigManager. */ private static final String DATA_CONFIG_NETWORK_TYPE_HSPAP = "HSPA+"; @@ -152,10 +153,12 @@ public class DataConfigManager extends Handler { private static final String DATA_CONFIG_NETWORK_TYPE_LTE_CA = "LTE_CA"; /** Network type NR_NSA. Should not be used outside of DataConfigManager. */ - private static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA = "NR_NSA"; + // TODO: Public only for use by DcTracker. This should be private once DcTracker is removed. + public static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA = "NR_NSA"; /** Network type NR_NSA_MMWAVE. Should not be used outside of DataConfigManager. */ - private static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE = "NR_NSA_MMWAVE"; + // TODO: Public only for use by DcTracker. This should be private once DcTracker is removed. + public static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE = "NR_NSA_MMWAVE"; /** Network type NR_SA. Should not be used outside of DataConfigManager. */ private static final String DATA_CONFIG_NETWORK_TYPE_NR_SA = "NR_SA"; @@ -982,8 +985,9 @@ public class DataConfigManager extends Handler { * @param displayInfo The {@link TelephonyDisplayInfo} used to determine the type. * @return The equivalent {@link DataConfigNetworkType}. */ - private static @NonNull @DataConfigNetworkType String getDataConfigNetworkType( + public static @NonNull @DataConfigNetworkType String getDataConfigNetworkType( @NonNull TelephonyDisplayInfo displayInfo) { + // TODO: Make method private once DataConnection is removed int networkType = displayInfo.getNetworkType(); switch (displayInfo.getOverrideNetworkType()) { case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED: diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index fbeabc1d7b..c225b3f2ad 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -32,6 +32,8 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Message; import android.os.OutcomeReceiver; +import android.os.Registrant; +import android.os.RegistrantList; import android.preference.PreferenceManager; import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.DataActivityType; @@ -189,6 +191,7 @@ public class LinkBandwidthEstimator extends Handler { private String mBandwidthUpdatePlmn = UNKNOWN_PLMN; private BandwidthState mTxState = new BandwidthState(LINK_TX); private BandwidthState mRxState = new BandwidthState(LINK_RX); + private RegistrantList mBandwidthChangedRegistrants = new RegistrantList(); private long mLastPlmnOrRatChangeTimeMs; private long mLastDrsOrRatChangeTimeMs; @@ -347,6 +350,33 @@ public class LinkBandwidthEstimator extends Handler { } } + /** + * Registers for bandwidth estimation change. The bandwidth will be returned + * * {@link AsyncResult#result} as a {@link Pair} Object. + * * The {@link AsyncResult} will be in the notification {@link Message#obj}. + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + * + * @deprecated Use {@link #registerCallback(LinkBandwidthEstimatorCallback)}. + */ + @Deprecated //TODO: Remove once old data stack is removed. + public void registerForBandwidthChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + mBandwidthChangedRegistrants.add(r); + } + + /** + * Unregisters for bandwidth estimation change. + * @param h handler to notify + * + * @deprecated Use {@link #unregisterCallback(LinkBandwidthEstimatorCallback)}. + */ + @Deprecated //TODO: Remove once old data stack is removed. + public void unregisterForBandwidthChanged(Handler h) { + mBandwidthChangedRegistrants.remove(h); + } + /** * Register the callback for receiving information from {@link LinkBandwidthEstimator}. * @@ -900,6 +930,9 @@ public class LinkBandwidthEstimator extends Handler { private void sendLinkBandwidthToDataConnection(int linkBandwidthTxKps, int linkBandwidthRxKps) { logv("send to DC tx " + linkBandwidthTxKps + " rx " + linkBandwidthRxKps); + Pair bandwidthInfo = + new Pair(linkBandwidthTxKps, linkBandwidthRxKps); + mBandwidthChangedRegistrants.notifyRegistrants(new AsyncResult(null, bandwidthInfo, null)); mLinkBandwidthEstimatorCallbacks.forEach(callback -> callback.invokeFromExecutor( () -> callback.onBandwidthChanged(linkBandwidthTxKps, linkBandwidthRxKps))); } diff --git a/src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java b/src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java new file mode 100644 index 0000000000..554177ad2c --- /dev/null +++ b/src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2021 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.data; + +import android.annotation.NonNull; +import android.net.NetworkAgent; +import android.net.QosSessionAttributes; + +/** + * The temporary interface that is shared by + * {@link com.android.internal.telephony.dataconnection.DcNetworkAgent} and + * {@link com.android.internal.telephony.data.TelephonyNetworkAgent} so they can both interact + * with {@link QosCallbackTracker}. + */ +// TODO: Remove after DcNetworkAgent is removed. +public interface NotifyQosSessionInterface { + /** + * Sends the attributes of Qos Session back to the Application. This method is create for + * Mockito to mock since + * {@link NetworkAgent#sendQosSessionAvailable(int, int, QosSessionAttributes)} is + * {@code final} that can't be mocked. + * + * @param qosCallbackId the callback id that the session belongs to. + * @param sessionId the unique session id across all Qos Sessions. + * @param attributes the attributes of the Qos Session. + */ + void notifyQosSessionAvailable(int qosCallbackId, int sessionId, + @NonNull QosSessionAttributes attributes); + + /** + * Sends event that the Qos Session was lost. This method is create for Mockito to mock + * since {@link NetworkAgent#sendQosSessionLost(int, int, int)} is {@code final} that can't be + * mocked.. + * + * @param qosCallbackId the callback id that the session belongs to. + * @param sessionId the unique session id across all Qos Sessions. + * @param qosSessionType the session type {@code QosSession#QosSessionType}. + */ + void notifyQosSessionLost(int qosCallbackId, int sessionId, int qosSessionType); +} diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 47ae22503a..cc5f44738b 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -83,6 +83,8 @@ import com.android.internal.telephony.SubscriptionController.WatchedInt; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; +import com.android.internal.telephony.dataconnection.ApnConfigTypeRepository; +import com.android.internal.telephony.dataconnection.DcRequest; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch; @@ -94,6 +96,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -179,6 +182,7 @@ public class PhoneSwitcher extends Handler { } } + protected final List mPrioritizedDcRequests = new ArrayList<>(); private final @NonNull NetworkRequestList mNetworkRequestList = new NetworkRequestList(); protected final RegistrantList mActivePhoneRegistrants; protected final SubscriptionController mSubscriptionController; @@ -503,16 +507,21 @@ public class PhoneSwitcher extends Handler { phone.getImsPhone().registerForPreciseCallStateChanged( this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } - mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), - v -> new DataSettingsManagerCallback(this::post) { - @Override - public void onDataEnabledChanged(boolean enabled, - @TelephonyManager.DataEnabledChangedReason int reason, - @NonNull String callingPackage) { - evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); - }}); - phone.getDataSettingsManager().registerCallback( - mDataSettingsManagerCallbacks.get(phone.getPhoneId())); + if (phone.isUsingNewDataStack()) { + mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), + v -> new DataSettingsManagerCallback(this::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @TelephonyManager.DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); + }}); + phone.getDataSettingsManager().registerCallback( + mDataSettingsManagerCallbacks.get(phone.getPhoneId())); + } else { + phone.getDataEnabledSettings().registerForDataEnabledChanged( + this, EVENT_DATA_ENABLED_CHANGED, null); + } registerForImsRadioTechChange(context, i); } @@ -871,17 +880,22 @@ public class PhoneSwitcher extends Handler { this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } - mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), - v -> new DataSettingsManagerCallback(this::post) { - @Override - public void onDataEnabledChanged(boolean enabled, - @TelephonyManager.DataEnabledChangedReason int reason, - @NonNull String callingPackage) { - evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); - } - }); - phone.getDataSettingsManager().registerCallback( - mDataSettingsManagerCallbacks.get(phone.getPhoneId())); + if (phone.isUsingNewDataStack()) { + mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), + v -> new DataSettingsManagerCallback(this::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @TelephonyManager.DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); + } + }); + phone.getDataSettingsManager().registerCallback( + mDataSettingsManagerCallbacks.get(phone.getPhoneId())); + } else { + phone.getDataEnabledSettings().registerForDataEnabledChanged( + this, EVENT_DATA_ENABLED_CHANGED, null); + } Set ddsFailure = new HashSet(); mCurrentDdsSwitchFailure.add(ddsFailure); @@ -927,21 +941,62 @@ public class PhoneSwitcher extends Handler { } private void onRequestNetwork(NetworkRequest networkRequest) { - TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( - networkRequest, PhoneFactory.getDefaultPhone()); - if (!mNetworkRequestList.contains(telephonyNetworkRequest)) { - mNetworkRequestList.add(telephonyNetworkRequest); - onEvaluate(REQUESTS_CHANGED, "netRequest"); + if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { + TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( + networkRequest, PhoneFactory.getDefaultPhone()); + if (!mNetworkRequestList.contains(telephonyNetworkRequest)) { + mNetworkRequestList.add(telephonyNetworkRequest); + onEvaluate(REQUESTS_CHANGED, "netRequest"); + } + return; + } + final DcRequest dcRequest = + DcRequest.create(networkRequest, createApnRepository(networkRequest)); + if (dcRequest != null) { + if (!mPrioritizedDcRequests.contains(dcRequest)) { + collectRequestNetworkMetrics(networkRequest); + mPrioritizedDcRequests.add(dcRequest); + Collections.sort(mPrioritizedDcRequests); + onEvaluate(REQUESTS_CHANGED, "netRequest"); + if (VDBG) log("Added DcRequest, size: " + mPrioritizedDcRequests.size()); + } } } private void onReleaseNetwork(NetworkRequest networkRequest) { - TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( - networkRequest, PhoneFactory.getDefaultPhone()); - if (mNetworkRequestList.remove(telephonyNetworkRequest)) { - onEvaluate(REQUESTS_CHANGED, "netReleased"); - collectReleaseNetworkMetrics(networkRequest); + if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { + TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( + networkRequest, PhoneFactory.getDefaultPhone()); + if (mNetworkRequestList.remove(telephonyNetworkRequest)) { + onEvaluate(REQUESTS_CHANGED, "netReleased"); + collectReleaseNetworkMetrics(networkRequest); + } + return; + } + final DcRequest dcRequest = + DcRequest.create(networkRequest, createApnRepository(networkRequest)); + if (dcRequest != null) { + if (mPrioritizedDcRequests.remove(dcRequest)) { + onEvaluate(REQUESTS_CHANGED, "netReleased"); + collectReleaseNetworkMetrics(networkRequest); + if (VDBG) log("Removed DcRequest, size: " + mPrioritizedDcRequests.size()); + } + } + } + + private ApnConfigTypeRepository createApnRepository(NetworkRequest networkRequest) { + int phoneIdForRequest = phoneIdForRequest(networkRequest); + int subId = mSubscriptionController.getSubIdUsingPhoneId(phoneIdForRequest); + CarrierConfigManager configManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + + PersistableBundle carrierConfig; + if (configManager != null) { + carrierConfig = configManager.getConfigForSubId(subId); + } else { + carrierConfig = null; } + return new ApnConfigTypeRepository(carrierConfig); } private void removeDefaultNetworkChangeCallback() { @@ -1092,12 +1147,22 @@ public class PhoneSwitcher extends Handler { } if (newActivePhones.size() < mMaxDataAttachModemCount) { - for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { - int phoneIdForRequest = phoneIdForRequest(networkRequest); - if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; - if (newActivePhones.contains(phoneIdForRequest)) continue; - newActivePhones.add(phoneIdForRequest); - if (newActivePhones.size() >= mMaxDataAttachModemCount) break; + if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { + for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { + int phoneIdForRequest = phoneIdForRequest(networkRequest); + if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; + if (newActivePhones.contains(phoneIdForRequest)) continue; + newActivePhones.add(phoneIdForRequest); + if (newActivePhones.size() >= mMaxDataAttachModemCount) break; + } + } else { + for (DcRequest dcRequest : mPrioritizedDcRequests) { + int phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); + if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; + if (newActivePhones.contains(phoneIdForRequest)) continue; + newActivePhones.add(phoneIdForRequest); + if (newActivePhones.size() >= mMaxDataAttachModemCount) break; + } } } @@ -1226,8 +1291,13 @@ public class PhoneSwitcher extends Handler { } } + // Merge phoneIdForRequest(NetworkRequest netRequest) after Phone.isUsingNewDataStack() is + // cleaned up. private int phoneIdForRequest(TelephonyNetworkRequest networkRequest) { - NetworkRequest netRequest = networkRequest.getNativeNetworkRequest(); + return phoneIdForRequest(networkRequest.getNativeNetworkRequest()); + } + + private int phoneIdForRequest(NetworkRequest netRequest) { int subId = getSubIdFromNetworkSpecifier(netRequest.getNetworkSpecifier()); if (subId == DEFAULT_SUBSCRIPTION_ID) return mPreferredDataPhoneId; @@ -1285,8 +1355,13 @@ public class PhoneSwitcher extends Handler { Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); boolean isDataEnabled = false; if (voicePhone != null) { - isDataEnabled = voicePhone.getDataSettingsManager() - .isDataEnabled(ApnSetting.TYPE_DEFAULT); + if (voicePhone.isUsingNewDataStack()) { + isDataEnabled = voicePhone.getDataSettingsManager() + .isDataEnabled(ApnSetting.TYPE_DEFAULT); + } else { + isDataEnabled = voicePhone.getDataEnabledSettings() + .isDataEnabled(ApnSetting.TYPE_DEFAULT); + } } if (mEmergencyOverride != null && findPhoneById(mEmergencyOverride.mPhoneId) != null) { @@ -1757,11 +1832,25 @@ public class PhoneSwitcher extends Handler { if (ddsPhoneId != INVALID_PHONE_INDEX && ddsPhoneId == phoneId) { return true; } else { - if (mNetworkRequestList.isEmpty()) return false; - for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { - phoneIdForRequest = phoneIdForRequest(networkRequest); - if (phoneIdForRequest == phoneId) { - return true; + if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { + if (mNetworkRequestList.isEmpty()) return false; + for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { + phoneIdForRequest = phoneIdForRequest(networkRequest); + if (phoneIdForRequest == phoneId) { + return true; + } + } + } else { + if (mPrioritizedDcRequests.size() == 0) { + return false; + } + for (DcRequest dcRequest : mPrioritizedDcRequests) { + if (dcRequest != null) { + phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); + if (phoneIdForRequest == phoneId) { + return true; + } + } } } } diff --git a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java index c3d5cb6a3a..b7cecbdbdb 100644 --- a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java +++ b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java @@ -53,7 +53,8 @@ public class QosCallbackTracker extends Handler { private static final int DEDICATED_BEARER_EVENT_STATE_DELETED = 3; private final @NonNull String mLogTag; - private final @NonNull TelephonyNetworkAgent mNetworkAgent; + // TODO: Change this to TelephonyNetworkAgent + private final @NonNull NotifyQosSessionInterface mNetworkAgent; private final @NonNull Map mQosBearerSessions; private final @NonNull RcsStats mRcsStats; @@ -93,7 +94,8 @@ public class QosCallbackTracker extends Handler { * @param networkAgent The network agent to send events to. * @param phone The phone instance. */ - public QosCallbackTracker(@NonNull TelephonyNetworkAgent networkAgent, @NonNull Phone phone) { + public QosCallbackTracker(@NonNull NotifyQosSessionInterface networkAgent, + @NonNull Phone phone) { mQosBearerSessions = new HashMap<>(); mCallbacksToFilter = new HashMap<>(); mNetworkAgent = networkAgent; @@ -101,36 +103,40 @@ public class QosCallbackTracker extends Handler { mRcsStats = RcsStats.getInstance(); mLogTag = "QOSCT" + "-" + ((NetworkAgent) mNetworkAgent).getNetwork().getNetId(); - networkAgent.registerCallback( - new TelephonyNetworkAgent.TelephonyNetworkAgentCallback(this::post) { - @Override - public void onQosCallbackRegistered(int qosCallbackId, - @NonNull QosFilter filter) { - addFilter(qosCallbackId, - new QosCallbackTracker.IFilter() { - @Override - public boolean matchesLocalAddress( - @NonNull InetAddress address, int startPort, - int endPort) { - return filter.matchesLocalAddress(address, startPort, - endPort); - } - - @Override - public boolean matchesRemoteAddress( - @NonNull InetAddress address, int startPort, - int endPort) { - return filter.matchesRemoteAddress(address, startPort, - endPort); - } - }); - } + if (phone.isUsingNewDataStack()) { + //TODO: Replace the NetworkAgent in the constructor with TelephonyNetworkAgent + // after mPhone.isUsingNewDataStack() check is removed. + ((TelephonyNetworkAgent) networkAgent).registerCallback( + new TelephonyNetworkAgent.TelephonyNetworkAgentCallback(this::post) { + @Override + public void onQosCallbackRegistered(int qosCallbackId, + @NonNull QosFilter filter) { + addFilter(qosCallbackId, + new QosCallbackTracker.IFilter() { + @Override + public boolean matchesLocalAddress( + @NonNull InetAddress address, int startPort, + int endPort) { + return filter.matchesLocalAddress(address, startPort, + endPort); + } + + @Override + public boolean matchesRemoteAddress( + @NonNull InetAddress address, int startPort, + int endPort) { + return filter.matchesRemoteAddress(address, startPort, + endPort); + } + }); + } - @Override - public void onQosCallbackUnregistered(int qosCallbackId) { + @Override + public void onQosCallbackUnregistered(int qosCallbackId) { - } - }); + } + }); + } } /** @@ -369,7 +375,7 @@ public class QosCallbackTracker extends Handler { qos.getDownlinkBandwidth().getGuaranteedBitrateKbps(), qos.getUplinkBandwidth().getGuaranteedBitrateKbps(), remoteAddresses); - mNetworkAgent.sendQosSessionAvailable( + mNetworkAgent.notifyQosSessionAvailable( callbackId, session.getQosBearerSessionId(), epsBearerAttr); } else { NrQos qos = (NrQos) session.getQos(); @@ -380,7 +386,7 @@ public class QosCallbackTracker extends Handler { qos.getDownlinkBandwidth().getGuaranteedBitrateKbps(), qos.getUplinkBandwidth().getGuaranteedBitrateKbps(), qos.getAveragingWindow(), remoteAddresses); - mNetworkAgent.sendQosSessionAvailable( + mNetworkAgent.notifyQosSessionAvailable( callbackId, session.getQosBearerSessionId(), nrQosAttr); } @@ -391,7 +397,7 @@ public class QosCallbackTracker extends Handler { } private void sendSessionLost(int callbackId, @NonNull QosBearerSession session) { - mNetworkAgent.sendQosSessionLost(callbackId, session.getQosBearerSessionId(), + mNetworkAgent.notifyQosSessionLost(callbackId, session.getQosBearerSessionId(), session.getQos() instanceof EpsQos ? QosSession.TYPE_EPS_BEARER : QosSession.TYPE_NR_BEARER); log("sendSessionLost, callbackId=" + callbackId); diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java index b8f7e87350..3b1256283e 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java @@ -25,6 +25,7 @@ import android.net.NetworkAgentConfig; import android.net.NetworkProvider; import android.net.NetworkScore; import android.net.QosFilter; +import android.net.QosSessionAttributes; import android.net.Uri; import android.os.Looper; import android.util.ArraySet; @@ -45,8 +46,9 @@ import java.util.concurrent.Executor; * for telephony to propagate network related information to the connectivity service. It always * has an associated parent {@link DataNetwork}. */ -public class TelephonyNetworkAgent extends NetworkAgent { +public class TelephonyNetworkAgent extends NetworkAgent implements NotifyQosSessionInterface { private final String mLogTag; + private final Phone mPhone; private final LocalLog mLocalLog = new LocalLog(128); /** The parent data network. */ @@ -157,6 +159,7 @@ public class TelephonyNetworkAgent extends NetworkAgent { mDataNetwork = dataNetwork; mNetworkAgentConfig = config; mTelephonyNetworkAgentCallbacks.add(callback); + mPhone = phone; mId = getNetwork().getNetId(); mLogTag = "TNA-" + mId; @@ -285,6 +288,37 @@ public class TelephonyNetworkAgent extends NetworkAgent { () -> callback.onQosCallbackUnregistered(qosCallbackId))); } + /** + * Sends the attributes of Qos Session back to the Application. This method is create for + * Mockito to mock since + * {@link NetworkAgent#sendQosSessionAvailable(int, int, QosSessionAttributes)} is + * {@code final} that can't be mocked. + * + * @param qosCallbackId the callback id that the session belongs to. + * @param sessionId the unique session id across all Qos Sessions. + * @param attributes the attributes of the Qos Session. + */ + @Override + public void notifyQosSessionAvailable(final int qosCallbackId, final int sessionId, + @NonNull final QosSessionAttributes attributes) { + super.sendQosSessionAvailable(qosCallbackId, sessionId, attributes); + } + + /** + * Sends event that the Qos Session was lost. This method is create for Mockito to mock + * since {@link NetworkAgent#sendQosSessionLost(int, int, int)} is {@code final} that can't be + * mocked.. + * + * @param qosCallbackId the callback id that the session belongs to. + * @param sessionId the unique session id across all Qos Sessions. + * @param qosSessionType the session type {@code QosSession#QosSessionType}. + */ + @Override + public void notifyQosSessionLost(final int qosCallbackId, + final int sessionId, final int qosSessionType) { + super.sendQosSessionLost(qosCallbackId, sessionId, qosSessionType); + } + /** * Abandon the network agent. This is used for telephony to re-create the network agent when * immutable capabilities got changed, where telephony calls {@link NetworkAgent#unregister()} diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java index e64dd9b7c0..85f0ae1f0d 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java @@ -20,16 +20,27 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.os.AsyncResult; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.telephony.AccessNetworkConstants; +import android.telephony.Annotation.ApnType; import android.telephony.SubscriptionManager; +import android.telephony.data.ApnSetting; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.dataconnection.ApnContext; +import com.android.internal.telephony.dataconnection.DataConnection; +import com.android.internal.telephony.dataconnection.DcTracker; +import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; +import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; +import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams; import com.android.internal.telephony.metrics.NetworkRequestsStats; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -61,15 +72,19 @@ public class TelephonyNetworkFactory extends NetworkFactory { public static final int EVENT_SUBSCRIPTION_CHANGED = 2; private static final int EVENT_NETWORK_REQUEST = 3; private static final int EVENT_NETWORK_RELEASE = 4; + private static final int EVENT_DATA_HANDOVER_NEEDED = 5; + private static final int EVENT_DATA_HANDOVER_COMPLETED = 6; private final PhoneSwitcher mPhoneSwitcher; private final SubscriptionController mSubscriptionController; private final LocalLog mLocalLog = new LocalLog(REQUEST_LOG_SIZE); - // Key: network request. Value: the transport of the network request applies to, + // Key: network request. Value: the transport of DcTracker it applies to, // AccessNetworkConstants.TRANSPORT_TYPE_INVALID if not applied. private final Map mNetworkRequests = new HashMap<>(); + private final Map mPendingHandovers = new HashMap<>(); + private final Phone mPhone; private AccessNetworksManager mAccessNetworksManager; @@ -97,6 +112,10 @@ public class TelephonyNetworkFactory extends NetworkFactory { mPhoneSwitcher.registerForActivePhoneSwitch(mInternalHandler, EVENT_ACTIVE_PHONE_SWITCH, null); + if (!phone.isUsingNewDataStack()) { + mPhone.getTransportManager().registerForHandoverNeededEvent(mInternalHandler, + EVENT_DATA_HANDOVER_NEEDED); + } mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; SubscriptionManager.from(mPhone.getContext()).addOnSubscriptionsChangedListener( @@ -182,18 +201,93 @@ public class TelephonyNetworkFactory extends NetworkFactory { onReleaseNetworkFor(msg); break; } + case EVENT_DATA_HANDOVER_NEEDED: { + AsyncResult ar = (AsyncResult) msg.obj; + HandoverParams handoverParams = (HandoverParams) ar.result; + onDataHandoverNeeded(handoverParams.apnType, handoverParams.targetTransport, + handoverParams); + break; + } + case EVENT_DATA_HANDOVER_COMPLETED: { + Bundle bundle = msg.getData(); + NetworkRequest nr = bundle.getParcelable( + DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST); + boolean success = bundle.getBoolean( + DcTracker.DATA_COMPLETE_MSG_EXTRA_SUCCESS); + int transport = bundle.getInt( + DcTracker.DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE); + boolean fallback = bundle.getBoolean( + DcTracker.DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK); + HandoverParams handoverParams = mPendingHandovers.remove(msg); + if (handoverParams != null) { + onDataHandoverSetupCompleted(nr, success, transport, fallback, + handoverParams); + } else { + logl("Handover completed but cannot find handover entry!"); + } + break; + } } } } private int getTransportTypeFromNetworkRequest(TelephonyNetworkRequest networkRequest) { - int transport = AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - int capability = networkRequest.getApnTypeNetworkCapability(); - if (capability >= 0) { - transport = mAccessNetworksManager - .getPreferredTransportByNetworkCapability(capability); + if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { + int transport = AccessNetworkConstants.TRANSPORT_TYPE_WWAN; + int capability = networkRequest.getApnTypeNetworkCapability(); + if (capability >= 0) { + transport = mAccessNetworksManager + .getPreferredTransportByNetworkCapability(capability); + } + return transport; + } else { + int apnType = ApnContext.getApnTypeFromNetworkRequest( + networkRequest.getNativeNetworkRequest()); + return mAccessNetworksManager.getCurrentTransport(apnType); + } + } + + /** + * Request network + * + * @param networkRequest Network request from clients + * @param requestType The request type + * @param transport Transport type + * @param onHandoverCompleteMsg When request type is handover, this message will be sent when + * handover is completed. For normal request, this should be null. + */ + private void requestNetworkInternal(TelephonyNetworkRequest networkRequest, + @RequestNetworkType int requestType, int transport, Message onHandoverCompleteMsg) { + NetworkRequestsStats.addNetworkRequest(networkRequest.getNativeNetworkRequest(), + mSubscriptionId); + + if (mPhone.isUsingNewDataStack()) { + mPhone.getDataNetworkController().addNetworkRequest(networkRequest); + } else { + if (mPhone.getDcTracker(transport) != null) { + mPhone.getDcTracker(transport).requestNetwork( + networkRequest.getNativeNetworkRequest(), requestType, + onHandoverCompleteMsg); + } + } + } + + private void releaseNetworkInternal(TelephonyNetworkRequest networkRequest) { + mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); + } + + // TODO: Clean this up after old data stack removed. + private void releaseNetworkInternal(TelephonyNetworkRequest networkRequest, + @ReleaseNetworkType int releaseType, + int transport) { + if (mPhone.isUsingNewDataStack()) { + mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); + } else { + if (mPhone.getDcTracker(transport) != null) { + mPhone.getDcTracker(transport).releaseNetwork( + networkRequest.getNativeNetworkRequest(), releaseType); + } } - return transport; } private static int getAction(boolean wasActive, boolean isActive) { @@ -223,11 +317,15 @@ public class TelephonyNetworkFactory extends NetworkFactory { ? "Requesting" : "Releasing") + " network request " + networkRequest); int transportType = getTransportTypeFromNetworkRequest(networkRequest); if (action == ACTION_REQUEST) { - NetworkRequestsStats.addNetworkRequest(networkRequest.getNativeNetworkRequest(), - mSubscriptionId); - mPhone.getDataNetworkController().addNetworkRequest(networkRequest); + requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, + getTransportTypeFromNetworkRequest(networkRequest), null); } else if (action == ACTION_RELEASE) { - mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); + if (mPhone.isUsingNewDataStack()) { + releaseNetworkInternal(networkRequest); + } else { + releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_DETACH, + getTransportTypeFromNetworkRequest(networkRequest)); + } } mNetworkRequests.put(networkRequest, @@ -267,9 +365,8 @@ public class TelephonyNetworkFactory extends NetworkFactory { logl("onNeedNetworkFor " + networkRequest + " shouldApply " + shouldApply); if (shouldApply) { - NetworkRequestsStats.addNetworkRequest(networkRequest.getNativeNetworkRequest(), - mSubscriptionId); - mPhone.getDataNetworkController().addNetworkRequest(networkRequest); + requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, + getTransportTypeFromNetworkRequest(networkRequest), null); } } @@ -291,8 +388,134 @@ public class TelephonyNetworkFactory extends NetworkFactory { logl("onReleaseNetworkFor " + networkRequest + " applied " + applied); if (applied) { - mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); + if (mPhone.isUsingNewDataStack()) { + releaseNetworkInternal(networkRequest); + } else { + // Most of the time, the network request only exists in one of the DcTracker, but in + // the middle of handover, the network request temporarily exists in both + // DcTrackers. If connectivity service releases the network request while handover + // is ongoing, we need to remove network requests from both DcTrackers. + // Note that this part will be refactored in T, where we won't even have DcTracker + // at all. + releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + } + } + } + + private void onDataHandoverNeeded(@ApnType int apnType, int targetTransport, + HandoverParams handoverParams) { + log("onDataHandoverNeeded: apnType=" + ApnSetting.getApnTypeString(apnType) + + ", target transport=" + + AccessNetworkConstants.transportTypeToString(targetTransport)); + if (mAccessNetworksManager.getCurrentTransport(apnType) == targetTransport) { + log("APN type " + ApnSetting.getApnTypeString(apnType) + " is already on " + + AccessNetworkConstants.transportTypeToString(targetTransport)); + return; + } + + boolean handoverPending = false; + for (Map.Entry entry : mNetworkRequests.entrySet()) { + TelephonyNetworkRequest networkRequest = entry.getKey(); + int currentTransport = entry.getValue(); + boolean applied = currentTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID; + if (ApnContext.getApnTypeFromNetworkRequest( + networkRequest.getNativeNetworkRequest()) == apnType + && applied + && currentTransport != targetTransport) { + DcTracker dcTracker = mPhone.getDcTracker(currentTransport); + if (dcTracker != null) { + DataConnection dc = dcTracker.getDataConnectionByApnType( + ApnSetting.getApnTypeString(apnType)); + if (dc != null && (dc.isActive())) { + Message onCompleteMsg = mInternalHandler.obtainMessage( + EVENT_DATA_HANDOVER_COMPLETED); + onCompleteMsg.getData().putParcelable( + DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST, + networkRequest.getNativeNetworkRequest()); + mPendingHandovers.put(onCompleteMsg, handoverParams); + requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_HANDOVER, + targetTransport, onCompleteMsg); + log("Requested handover " + ApnSetting.getApnTypeString(apnType) + + " to " + + AccessNetworkConstants.transportTypeToString(targetTransport) + + ". " + networkRequest); + handoverPending = true; + } else { + // Request is there, but no actual data connection. In this case, just move + // the request to the new transport. + log("The network request is on transport " + AccessNetworkConstants + .transportTypeToString(currentTransport) + ", but no live data " + + "connection. Just move the request to transport " + + AccessNetworkConstants.transportTypeToString(targetTransport) + + ", dc=" + dc); + entry.setValue(targetTransport); + releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, + currentTransport); + requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, + targetTransport, null); + } + } else { + log("DcTracker on " + AccessNetworkConstants.transportTypeToString( + currentTransport) + " is not available."); + } + } + } + + if (!handoverPending) { + log("No handover request pending. Handover process is now completed"); + handoverParams.callback.onCompleted(true, false); + } + } + + private void onDataHandoverSetupCompleted(NetworkRequest request, boolean success, + int targetTransport, boolean fallback, + HandoverParams handoverParams) { + log("onDataHandoverSetupCompleted: " + request + ", success=" + success + + ", targetTransport=" + + AccessNetworkConstants.transportTypeToString(targetTransport) + + ", fallback=" + fallback); + + TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(request, mPhone); + // At this point, handover setup has been completed on the target transport. + // If it succeeded, or it failed without falling back to the original transport, + // we should release the request from the original transport. + if (!fallback) { + int originTransport = DataUtils.getSourceTransport(targetTransport); + int releaseType = success + ? DcTracker.RELEASE_TYPE_HANDOVER + // If handover fails, we need to tear down the existing connection, so the + // new data connection can be re-established on the new transport. If we leave + // the existing data connection in current transport, then DCT and qualified + // network service will be out of sync. Specifying release type to detach + // the transport is moved to the other transport, but network request is still + // there, connectivity service will not call unwanted to tear down the network. + // We need explicitly tear down the data connection here so the new data + // connection can be re-established on the other transport. + : DcTracker.RELEASE_TYPE_DETACH; + releaseNetworkInternal(networkRequest, releaseType, originTransport); + + // Before updating the network request with the target transport, make sure the request + // is still there because it's possible that connectivity service has already released + // the network while handover is ongoing. If connectivity service already released + // the network request, we need to tear down the just-handovered data connection on the + // target transport. + if (mNetworkRequests.containsKey(networkRequest)) { + // Update it with the target transport. + mNetworkRequests.put(networkRequest, targetTransport); + } + } else { + // If handover fails and requires to fallback, the context of target transport needs to + // be released + if (!success) { + releaseNetworkInternal(networkRequest, + DcTracker.RELEASE_TYPE_NORMAL, targetTransport); + } } + + handoverParams.callback.onCompleted(success, fallback); } protected void log(String s) { diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java index b334b89d75..b55304a4a9 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java @@ -157,7 +157,8 @@ public class TelephonyNetworkRequest { /** * Data config manager for retrieving data config. */ - private final @NonNull DataConfigManager mDataConfigManager; + // TODO: Make this @NonNull after old data stack removed. + private final @Nullable DataConfigManager mDataConfigManager; /** * The attached data network. Note that the data network could be in any state. {@code null} @@ -203,8 +204,12 @@ public class TelephonyNetworkRequest { // to satisfy it. mState = REQUEST_STATE_UNSATISFIED; mCreatedTimeMillis = SystemClock.elapsedRealtime(); - mDataConfigManager = phone.getDataNetworkController().getDataConfigManager(); - updatePriority(); + if (phone.isUsingNewDataStack()) { + mDataConfigManager = phone.getDataNetworkController().getDataConfigManager(); + updatePriority(); + } else { + mDataConfigManager = null; + } } /** @@ -396,7 +401,8 @@ public class TelephonyNetworkRequest { * @return {@code true} if this network request can result in bringing up a metered network. */ public boolean isMeteredRequest() { - return mDataConfigManager.isAnyMeteredCapability( + // TODO: Remove null check after old data stack removed. + return mDataConfigManager != null && mDataConfigManager.isAnyMeteredCapability( getCapabilities(), mPhone.getServiceState().getDataRoaming()); } diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java b/src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java new file mode 100644 index 0000000000..827dbdd5e4 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 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.dataconnection; + +import android.telephony.Annotation; + +/** + * Container of network configuration settings relevant for telephony module. + * + */ +public class ApnConfigType { + + private final int mType; + private final int mPriority; + + public ApnConfigType(@Annotation.ApnType int type, int priority) { + mType = type; + mPriority = priority; + } + + /** + * Returns the apn type of this config type + * @return Type of apn. + */ + public int getType() { + return mType; + } + + /** + * Returns the priority of this apn config type. + * @return The priority of this apn. + */ + public int getPriority() { + return mPriority; + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java b/src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java new file mode 100644 index 0000000000..156ac926e5 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2020 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.dataconnection; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.PersistableBundle; +import android.telephony.Annotation; +import android.telephony.CarrierConfigManager; +import android.telephony.Rlog; +import android.telephony.data.ApnSetting; +import android.util.ArrayMap; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Hard coded configuration of specific network types that the telephony module needs. + * Formerly stored in network attributes within the resources file. + */ +public class ApnConfigTypeRepository { + + private static final String TAG = ApnConfigTypeRepository.class.getSimpleName(); + + private final Map mConfigTypeMap; + + public ApnConfigTypeRepository(PersistableBundle carrierConfig) { + mConfigTypeMap = new HashMap<>(); + setup(carrierConfig); + } + + /** + * Gets list of apn config types. + * @return All apn config types. + */ + public Collection getTypes() { + return mConfigTypeMap.values(); + } + + /** + * Gets the apn config type by apn type. + * @param type The ApnType to search for. + * @return The config type matching the given apn type. + */ + @Nullable + public ApnConfigType getByType(@Annotation.ApnType int type) { + return mConfigTypeMap.get(type); + } + + private void setup(PersistableBundle carrierConfig) { + addApns(getCarrierApnTypeMap(CarrierConfigManager.getDefaultConfig())); + addApns(getCarrierApnTypeMap(carrierConfig)); + } + + private void addApns(Map apnTypeMap) { + add(ApnSetting.TYPE_DEFAULT, apnTypeMap); + add(ApnSetting.TYPE_MMS, apnTypeMap); + add(ApnSetting.TYPE_SUPL, apnTypeMap); + add(ApnSetting.TYPE_DUN, apnTypeMap); + add(ApnSetting.TYPE_HIPRI, apnTypeMap); + add(ApnSetting.TYPE_FOTA, apnTypeMap); + add(ApnSetting.TYPE_IMS, apnTypeMap); + add(ApnSetting.TYPE_CBS, apnTypeMap); + add(ApnSetting.TYPE_IA, apnTypeMap); + add(ApnSetting.TYPE_EMERGENCY, apnTypeMap); + add(ApnSetting.TYPE_MCX, apnTypeMap); + add(ApnSetting.TYPE_XCAP, apnTypeMap); + add(ApnSetting.TYPE_ENTERPRISE, apnTypeMap); + } + + @NonNull + private Map getCarrierApnTypeMap(PersistableBundle carrierConfig) { + if (carrierConfig == null) { + Rlog.w(TAG, "carrier config is null"); + return new ArrayMap<>(); + } + + final String[] apnTypeConfig = + carrierConfig.getStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY); + + final Map apnTypeMap = new ArrayMap<>(); + if (apnTypeConfig != null) { + for (final String entry : apnTypeConfig) { + try { + final String[] keyValue = entry.split(":"); + if (keyValue.length != 2) { + Rlog.e(TAG, "Apn type entry must have exactly one ':'"); + } else if (keyValue[0].contains(",")) { + //getApnTypesBitmaskFromString parses commas to a list, not valid here. + Rlog.e(TAG, "Invalid apn type name, entry: " + entry); + } else { + int apnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(keyValue[0]); + if (apnTypeBitmask > 0) { + apnTypeMap.put(apnTypeBitmask, Integer.parseInt(keyValue[1])); + } else { + Rlog.e(TAG, "Invalid apn type name, entry: " + entry); + } + } + + } catch (Exception ex) { + Rlog.e(TAG, "Exception on apn type entry: " + entry + "\n", ex); + } + } + } + return apnTypeMap; + } + + private void add(@Annotation.ApnType int type, Map apnTypeMap) { + if (apnTypeMap.containsKey(type)) { + mConfigTypeMap.put(type, new ApnConfigType(type, apnTypeMap.get(type))); + } + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java new file mode 100644 index 0000000000..3f487cdf65 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java @@ -0,0 +1,675 @@ +/* + * Copyright (C) 2006 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.dataconnection; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Message; +import android.telephony.Annotation.ApnType; +import android.telephony.data.ApnSetting; +import android.text.TextUtils; +import android.util.ArraySet; +import android.util.LocalLog; +import android.util.SparseIntArray; + +import com.android.internal.R; +import com.android.internal.telephony.DctConstants; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.RetryManager; +import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; +import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; +import com.android.internal.util.IndentingPrintWriter; +import com.android.telephony.Rlog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Maintain the Apn context + */ +public class ApnContext { + + public final String LOG_TAG; + private final static String SLOG_TAG = "ApnContext"; + + protected static final boolean DBG = false; + + private final Phone mPhone; + + private final String mApnType; + + private DctConstants.State mState; + + private int mPriority; + + private ApnSetting mApnSetting; + + private DataConnection mDataConnection; + + private String mReason; + + /** + * user/app requested connection on this APN + */ + AtomicBoolean mDataEnabled; + + private final Object mRefCountLock = new Object(); + + private final DcTracker mDcTracker; + + + /** + * Remember this as a change in this value to a more permissive state + * should cause us to retry even permanent failures + */ + private boolean mConcurrentVoiceAndDataAllowed; + + /** + * used to track a single connection request so disconnects can get ignored if + * obsolete. + */ + private final AtomicInteger mConnectionGeneration = new AtomicInteger(0); + + /** + * Retry manager that handles the APN retry and delays. + */ + private final RetryManager mRetryManager; + + /** + * ApnContext constructor + * @param phone phone object + * @param typeId APN type Id + * @param logTag Tag for logging + * @param tracker Data call tracker + * @param priority Priority of APN type + */ + public ApnContext(Phone phone, int typeId, String logTag, DcTracker tracker, int priority) { + this(phone, ApnSetting.getApnTypeString(typeId), logTag, tracker, priority); + } + + /** + * ApnContext constructor + * @param phone phone object + * @param apnType APN type (e.g. default, supl, mms, etc...) + * @param logTag Tag for logging + * @param tracker Data call tracker + * @param priority Priority of APN type + */ + public ApnContext(Phone phone, String apnType, String logTag, DcTracker tracker, int priority) { + mPhone = phone; + mApnType = apnType; + mState = DctConstants.State.IDLE; + setReason(Phone.REASON_DATA_ENABLED); + mDataEnabled = new AtomicBoolean(false); + mPriority = priority; + LOG_TAG = logTag; + mDcTracker = tracker; + mRetryManager = new RetryManager(phone, tracker.getDataThrottler(), + ApnSetting.getApnTypesBitmaskFromString(apnType)); + } + + + + /** + * Get the APN type + * @return The APN type + */ + public String getApnType() { + return mApnType; + } + + /** + * Gets the APN type bitmask. + * @return The APN type bitmask + */ + public int getApnTypeBitmask() { + return ApnSetting.getApnTypesBitmaskFromString(mApnType); + } + + /** + * Get the associated data connection + * @return The data connection + */ + public synchronized DataConnection getDataConnection() { + return mDataConnection; + } + + /** + * This priority is taken into account when concurrent data connections are not allowed. The + * APN with the HIGHER priority is given preference. + * @return The priority of the APN type + */ + public int getPriority() { + return mPriority; + } + + /** + * Updates the priority of this context. + * @param priority The priority of the APN type + */ + public void setPriority(int priority) { + mPriority = priority; + } + + /** + * Keeping for backwards compatibility and in case it's needed in the future + * @return true + */ + public boolean isDependencyMet() { + return true; + } + + /** + * Set the associated data connection. + * @param dc data connection + */ + public synchronized void setDataConnection(DataConnection dc) { + log("setDataConnectionAc: old=" + mDataConnection + ",new=" + dc + " this=" + this); + mDataConnection = dc; + } + + /** + * Release data connection. + * @param reason The reason of releasing data connection + */ + public synchronized void releaseDataConnection(String reason) { + if (mDataConnection != null) { + mDataConnection.tearDown(this, reason, null); + mDataConnection = null; + } + setState(DctConstants.State.IDLE); + } + + /** + * Get the current APN setting. + * @return APN setting + */ + public synchronized ApnSetting getApnSetting() { + log("getApnSetting: apnSetting=" + mApnSetting); + return mApnSetting; + } + + /** + * Set the APN setting. + * @param apnSetting APN setting + */ + public synchronized void setApnSetting(ApnSetting apnSetting) { + log("setApnSetting: apnSetting=" + apnSetting); + mApnSetting = apnSetting; + } + + /** + * Set the list of APN candidates which will be used for data call setup later. + * @param waitingApns List of APN candidates + */ + public synchronized void setWaitingApns(ArrayList waitingApns) { + mRetryManager.setWaitingApns(waitingApns); + } + + /** + * Get the next available APN to try. + * @return APN setting which will be used for data call setup.{@code null} if there is no + * APN can be retried. + */ + public @Nullable ApnSetting getNextApnSetting() { + return mRetryManager.getNextApnSetting(); + } + + /** + * Get the delay for trying the next APN setting if the current one failed. + * @param failFastEnabled True if fail fast mode enabled. In this case we'll use a shorter + * delay. + * @return The delay in milliseconds + */ + public long getDelayForNextApn(boolean failFastEnabled) { + return mRetryManager.getDelayForNextApn(failFastEnabled || isFastRetryReason()); + } + + /** + * Mark the current APN setting permanently failed, which means it will not be retried anymore. + * @param apn APN setting + */ + public void markApnPermanentFailed(ApnSetting apn) { + mRetryManager.markApnPermanentFailed(apn); + } + + /** + * Get the list of waiting APNs. + * @return the list of waiting APNs + */ + public @NonNull ArrayList getWaitingApns() { + return mRetryManager.getWaitingApns(); + } + + /** + * Save the state indicating concurrent voice/data allowed. + * @param allowed True if concurrent voice/data is allowed + */ + public synchronized void setConcurrentVoiceAndDataAllowed(boolean allowed) { + mConcurrentVoiceAndDataAllowed = allowed; + } + + /** + * Get the state indicating concurrent voice/data allowed. + * @return True if concurrent voice/data is allowed + */ + public synchronized boolean isConcurrentVoiceAndDataAllowed() { + return mConcurrentVoiceAndDataAllowed; + } + + /** + * Set the current data call state. + * @param s Current data call state + */ + public synchronized void setState(DctConstants.State s) { + log("setState: " + s + ", previous state:" + mState); + + if (mState != s) { + mStateLocalLog.log("State changed from " + mState + " to " + s); + mState = s; + } + + if (mState == DctConstants.State.FAILED) { + // when teardown the connection and set to IDLE + mRetryManager.getWaitingApns().clear(); + } + } + + /** + * Get the current data call state. + * @return The current data call state + */ + public synchronized DctConstants.State getState() { + return mState; + } + + /** + * Check whether the data call is disconnected or not. + * @return True if the data call is disconnected + */ + public boolean isDisconnected() { + DctConstants.State currentState = getState(); + return ((currentState == DctConstants.State.IDLE) || + currentState == DctConstants.State.FAILED); + } + + /** + * Set the reason for data call connection. + * @param reason Reason for data call connection + */ + public synchronized void setReason(String reason) { + log("set reason as " + reason + ",current state " + mState); + mReason = reason; + } + + /** + * Get the reason for data call connection. + * @return The reason for data call connection + */ + public synchronized String getReason() { + return mReason; + } + + /** + * Check if ready for data call connection + * @return True if ready, otherwise false. + */ + public boolean isReady() { + return mDataEnabled.get() && isDependencyMet(); + } + + /** + * Check if the data call is in the state which allow connecting. + * @return True if allowed, otherwise false. + */ + public boolean isConnectable() { + return isReady() && ((mState == DctConstants.State.IDLE) + || (mState == DctConstants.State.RETRYING) + || (mState == DctConstants.State.FAILED)); + } + + /** + * Check if apn reason is fast retry reason which should apply shorter delay between apn re-try. + * @return True if it is fast retry reason, otherwise false. + */ + private boolean isFastRetryReason() { + return Phone.REASON_NW_TYPE_CHANGED.equals(mReason) || + Phone.REASON_APN_CHANGED.equals(mReason); + } + + /** Check if the data call is in connected or connecting state. + * @return True if the data call is in connected or connecting state + */ + public boolean isConnectedOrConnecting() { + return isReady() && ((mState == DctConstants.State.CONNECTED) + || (mState == DctConstants.State.CONNECTING) + || (mState == DctConstants.State.RETRYING)); + } + + /** + * Set data call enabled/disabled state. + * @param enabled True if data call is enabled + */ + public void setEnabled(boolean enabled) { + log("set enabled as " + enabled + ", current state is " + mDataEnabled.get()); + mDataEnabled.set(enabled); + } + + /** + * Check if the data call is enabled or not. + * @return True if enabled + */ + public boolean isEnabled() { + return mDataEnabled.get(); + } + + public boolean isProvisioningApn() { + String provisioningApn = mPhone.getContext().getResources() + .getString(R.string.mobile_provisioning_apn); + if (!TextUtils.isEmpty(provisioningApn) && + (mApnSetting != null) && (mApnSetting.getApnName() != null)) { + return (mApnSetting.getApnName().equals(provisioningApn)); + } else { + return false; + } + } + + private final ArraySet mNetworkRequests = new ArraySet<>(); + private final LocalLog mStateLocalLog = new LocalLog(32); + + private static final LocalLog sLocalLog = new LocalLog(256); + + /** Add a line to the ApnContext local log. */ + public static void requestLog(ApnContext apnContext, String str) { + if (apnContext != null) { + String logString = "[ApnContext:" + apnContext.getApnType() + "] " + str; + if (DBG) { + Rlog.d(SLOG_TAG, logString); + } + synchronized (sLocalLog) { + sLocalLog.log(logString); + } + } + } + + /** + * Request a network + * + * @param networkRequest Network request from clients + * @param type The request type + * @param onHandoverCompleteMsg When request type is handover, this message will be sent when + * handover is completed. For normal request, this should be null. + */ + public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type, + Message onHandoverCompleteMsg) { + synchronized (mRefCountLock) { + mNetworkRequests.add(networkRequest); + requestLog(this, "requestNetwork for " + networkRequest + ", type=" + + DcTracker.requestTypeToString(type)); + mDcTracker.enableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type, + onHandoverCompleteMsg); + if (mDataConnection != null) { + // New network request added. Should re-evaluate properties of + // the data connection. For example, the score may change. + mDataConnection.reevaluateDataConnectionProperties(); + } + } + } + + public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type) { + synchronized (mRefCountLock) { + if (mNetworkRequests.contains(networkRequest)) { + mNetworkRequests.remove(networkRequest); + if (mDataConnection != null) { + // New network request added. Should re-evaluate properties of + // the data connection. For example, the score may change. + mDataConnection.reevaluateDataConnectionProperties(); + } + requestLog(this, "releaseNetwork left with " + mNetworkRequests.size() + + " requests."); + if (mNetworkRequests.size() == 0 + || type == DcTracker.RELEASE_TYPE_DETACH + || type == DcTracker.RELEASE_TYPE_HANDOVER) { + mDcTracker.disableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type); + } + } + } + } + + /** + * @param excludeDun True if excluding requests that have DUN capability + * @return True if the attached network requests contain restricted capability. + */ + public boolean hasRestrictedRequests(boolean excludeDun) { + synchronized (mRefCountLock) { + for (NetworkRequest nr : mNetworkRequests) { + if (excludeDun && + nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) { + continue; + } + if (!nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) { + return true; + } + } + } + return false; + } + + private final SparseIntArray mRetriesLeftPerErrorCode = new SparseIntArray(); + + public void resetErrorCodeRetries() { + requestLog(this, "resetErrorCodeRetries"); + + String[] config = mPhone.getContext().getResources().getStringArray( + com.android.internal.R.array.config_cell_retries_per_error_code); + synchronized (mRetriesLeftPerErrorCode) { + mRetriesLeftPerErrorCode.clear(); + + for (String c : config) { + String errorValue[] = c.split(","); + if (errorValue != null && errorValue.length == 2) { + int count = 0; + int errorCode = 0; + try { + errorCode = Integer.parseInt(errorValue[0]); + count = Integer.parseInt(errorValue[1]); + } catch (NumberFormatException e) { + log("Exception parsing config_retries_per_error_code: " + e); + continue; + } + if (count > 0 && errorCode > 0) { + mRetriesLeftPerErrorCode.put(errorCode, count); + } + } else { + log("Exception parsing config_retries_per_error_code: " + c); + } + } + } + } + + public boolean restartOnError(int errorCode) { + boolean result = false; + int retriesLeft = 0; + synchronized(mRetriesLeftPerErrorCode) { + retriesLeft = mRetriesLeftPerErrorCode.get(errorCode); + switch (retriesLeft) { + case 0: { + // not set, never restart modem + break; + } + case 1: { + resetErrorCodeRetries(); + result = true; + break; + } + default: { + mRetriesLeftPerErrorCode.put(errorCode, retriesLeft - 1); + result = false; + } + } + } + requestLog(this, "restartOnError(" + errorCode + ") found " + retriesLeft + + " and returned " + result); + return result; + } + + public int incAndGetConnectionGeneration() { + return mConnectionGeneration.incrementAndGet(); + } + + public int getConnectionGeneration() { + return mConnectionGeneration.get(); + } + + long getRetryAfterDisconnectDelay() { + return mRetryManager.getRetryAfterDisconnectDelay(); + } + + /** + * Get APN type from the network request. + * + * @param nr The network request. + * @return The APN type. + */ + public static @ApnType int getApnTypeFromNetworkRequest(NetworkRequest nr) { + // For now, ignore the bandwidth stuff + if (nr.getTransportTypes().length > 0 + && !nr.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + return ApnSetting.TYPE_NONE; + } + + // in the near term just do 1-1 matches. + // TODO - actually try to match the set of capabilities + int apnType = ApnSetting.TYPE_NONE; + boolean error = false; + + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + apnType = ApnSetting.TYPE_DEFAULT; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_MMS; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_SUPL; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_DUN; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_FOTA; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_IMS; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_CBS; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_IA)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_IA; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_EMERGENCY; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_MCX)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_MCX; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_XCAP; + } + if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)) { + if (apnType != ApnSetting.TYPE_NONE) error = true; + apnType = ApnSetting.TYPE_ENTERPRISE; + } + if (error) { + // TODO: If this error condition is removed, the framework's handling of + // NET_CAPABILITY_NOT_RESTRICTED will need to be updated so requests for + // say FOTA and INTERNET are marked as restricted. This is not how + // NetworkCapabilities.maybeMarkCapabilitiesRestricted currently works. + Rlog.d(SLOG_TAG, "Multiple apn types specified in request - result is unspecified!"); + } + if (apnType == ApnSetting.TYPE_NONE) { + Rlog.d(SLOG_TAG, "Unsupported NetworkRequest in Telephony: nr=" + nr); + } + return apnType; + } + + public List getNetworkRequests() { + synchronized (mRefCountLock) { + return new ArrayList(mNetworkRequests); + } + } + + @Override + public synchronized String toString() { + // We don't print mDataConnection because its recursive. + return "{mApnType=" + mApnType + " mState=" + getState() + " mWaitingApns={" + + mRetryManager.getWaitingApns() + " priority=" + mPriority + "}" + + " mApnSetting={" + mApnSetting + + "} mReason=" + mReason + " mDataEnabled=" + mDataEnabled + "}"; + } + + private void log(String s) { + if (DBG) { + Rlog.d(LOG_TAG, "[ApnContext:" + mApnType + "] " + s); + } + } + + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + final IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + synchronized (mRefCountLock) { + pw.println(toString()); + if (mNetworkRequests.size() > 0) { + pw.println("NetworkRequests:"); + pw.increaseIndent(); + for (NetworkRequest nr : mNetworkRequests) { + pw.println(nr); + } + pw.decreaseIndent(); + } + pw.println("Historical APN state:"); + pw.increaseIndent(); + mStateLocalLog.dump(fd, pw, args); + pw.decreaseIndent(); + pw.println(mRetryManager); + pw.println("--------------------------"); + } + } + + /** Dumps the ApnContext local log. */ + public static void dumpLocalLog(FileDescriptor fd, PrintWriter printWriter, String[] args) { + printWriter.println("Local log:"); + synchronized (sLocalLog) { + sLocalLog.dump(fd, printWriter, args); + } + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java b/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java new file mode 100644 index 0000000000..3c2a6ef251 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.dataconnection; + +import android.content.Context; +import android.os.PersistableBundle; +import android.telephony.Annotation.ApnType; +import android.telephony.CarrierConfigManager; +import android.telephony.data.ApnSetting; + +import com.android.internal.telephony.Phone; +import com.android.telephony.Rlog; + +import java.util.Arrays; +import java.util.HashSet; + +/** + * This class represents a apn setting for create PDP link + */ +public class ApnSettingUtils { + + static final String LOG_TAG = "ApnSetting"; + + private static final boolean DBG = false; + + /** + * Check if this APN type is metered. + * + * @param apnType the APN type + * @param phone the phone object + * @return {@code true} if the APN type is metered, {@code false} otherwise. + */ + public static boolean isMeteredApnType(@ApnType int apnType, Phone phone) { + if (phone == null) { + return true; + } + + boolean isRoaming = phone.getServiceState().getDataRoaming(); + int subId = phone.getSubId(); + + String carrierConfig; + // First check if the device is roaming. If yes, use the roaming metered APN list. + // Otherwise use the normal metered APN list. + if (isRoaming) { + carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS; + } else { + carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS; + } + + if (DBG) { + Rlog.d(LOG_TAG, "isMeteredApnType: isRoaming=" + isRoaming); + } + + CarrierConfigManager configManager = (CarrierConfigManager) + phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager == null) { + Rlog.e(LOG_TAG, "Carrier config service is not available"); + return true; + } + + PersistableBundle b = configManager.getConfigForSubId(subId); + if (b == null) { + Rlog.e(LOG_TAG, "Can't get the config. subId = " + subId); + return true; + } + + String[] meteredApnTypes = b.getStringArray(carrierConfig); + if (meteredApnTypes == null) { + Rlog.e(LOG_TAG, carrierConfig + " is not available. " + "subId = " + subId); + return true; + } + + HashSet meteredApnSet = new HashSet<>(Arrays.asList(meteredApnTypes)); + if (DBG) { + Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " + + Arrays.toString(meteredApnSet.toArray())); + } + + if (meteredApnSet.contains(ApnSetting.getApnTypeString(apnType))) { + if (DBG) Rlog.d(LOG_TAG, ApnSetting.getApnTypeString(apnType) + " is metered."); + return true; + } else if (apnType == ApnSetting.TYPE_ALL) { + // Assuming no configuration error, if at least one APN type is + // metered, then this APN setting is metered. + if (meteredApnSet.size() > 0) { + if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered."); + return true; + } + } + + if (DBG) Rlog.d(LOG_TAG, ApnSetting.getApnTypeString(apnType) + " is not metered."); + return false; + } + + /** + * Check if this APN setting is metered. + * + * @param apn APN setting + * @param phone The phone object + * @return True if this APN setting is metered, otherwise false. + */ + public static boolean isMetered(ApnSetting apn, Phone phone) { + if (phone == null || apn == null) { + return true; + } + + for (int apnType : apn.getApnTypes()) { + // If one of the APN type is metered, then this APN setting is metered. + if (isMeteredApnType(apnType, phone)) { + return true; + } + } + return false; + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java new file mode 100644 index 0000000000..255972af01 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java @@ -0,0 +1,4094 @@ +/* + * Copyright (C) 2006 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.dataconnection; + +import static android.telephony.data.DataCallResponse.PDU_SESSION_ID_NOT_SET; + +import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_HANDOVER; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.PendingIntent; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.UserInfo; +import android.net.ConnectivityManager; +import android.net.InetAddresses; +import android.net.KeepalivePacketData; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.NetworkAgentConfig; +import android.net.NetworkCapabilities; +import android.net.NetworkFactory; +import android.net.NetworkProvider; +import android.net.NetworkRequest; +import android.net.ProxyInfo; +import android.net.RouteInfo; +import android.net.SocketKeepalive; +import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.VcnManager; +import android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener; +import android.net.vcn.VcnNetworkPolicyResult; +import android.os.AsyncResult; +import android.os.HandlerExecutor; +import android.os.Message; +import android.os.PersistableBundle; +import android.os.Process; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.os.UserManager; +import android.provider.Telephony; +import android.telephony.AccessNetworkConstants; +import android.telephony.AccessNetworkConstants.TransportType; +import android.telephony.Annotation.ApnType; +import android.telephony.Annotation.DataFailureCause; +import android.telephony.Annotation.DataState; +import android.telephony.Annotation.NetworkType; +import android.telephony.CarrierConfigManager; +import android.telephony.DataFailCause; +import android.telephony.LinkCapacityEstimate; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.PreciseDataConnectionState; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; +import android.telephony.data.DataCallResponse; +import android.telephony.data.DataCallResponse.HandoverFailureMode; +import android.telephony.data.DataProfile; +import android.telephony.data.DataService; +import android.telephony.data.DataServiceCallback; +import android.telephony.data.NetworkSliceInfo; +import android.telephony.data.Qos; +import android.telephony.data.QosBearerSession; +import android.telephony.data.TrafficDescriptor; +import android.text.TextUtils; +import android.util.LocalLog; +import android.util.Pair; +import android.util.TimeUtils; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.CarrierPrivilegesTracker; +import com.android.internal.telephony.CarrierSignalAgent; +import com.android.internal.telephony.DctConstants; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.RIL; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.RetryManager; +import com.android.internal.telephony.TelephonyStatsLog; +import com.android.internal.telephony.data.DataConfigManager; +import com.android.internal.telephony.data.KeepaliveStatus; +import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; +import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; +import com.android.internal.telephony.metrics.DataCallSessionStats; +import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.nano.TelephonyProto.RilDataCall; +import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.util.ArrayUtils; +import com.android.internal.util.AsyncChannel; +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Protocol; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; +import com.android.net.module.util.NetworkCapabilitiesUtils; +import com.android.telephony.Rlog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; + +/** + * {@hide} + * + * DataConnection StateMachine. + * + * This a class for representing a single data connection, with instances of this + * class representing a connection via the cellular network. There may be multiple + * data connections and all of them are managed by the DataConnectionTracker. + * + * NOTE: All DataConnection objects must be running on the same looper, which is the default + * as the coordinator has members which are used without synchronization. + */ +public class DataConnection extends StateMachine { + private static final boolean DBG = true; + private static final boolean VDBG = true; + + private static final String NETWORK_TYPE = "MOBILE"; + + private static final String RAT_NAME_5G = "nr"; + private static final String RAT_NAME_EVDO = "evdo"; + + /** + * OSId for "Android", using UUID version 5 with namespace ISO OSI. + * Prepended to the OsAppId in TrafficDescriptor to use for URSP matching. + */ + private static final UUID OS_ID = UUID.fromString("97a498e3-fc92-5c94-8986-0333d06e4e47"); + + /** + * The data connection is not being or been handovered. Note this is the state for the source + * data connection, not destination data connection + */ + private static final int HANDOVER_STATE_IDLE = 1; + + /** + * The data connection is being handovered. Note this is the state for the source + * data connection, not destination data connection. + */ + private static final int HANDOVER_STATE_BEING_TRANSFERRED = 2; + + /** + * The data connection is already handovered. Note this is the state for the source + * data connection, not destination data connection. + */ + private static final int HANDOVER_STATE_COMPLETED = 3; + + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"HANDOVER_STATE_"}, value = { + HANDOVER_STATE_IDLE, + HANDOVER_STATE_BEING_TRANSFERRED, + HANDOVER_STATE_COMPLETED}) + public @interface HandoverState {} + + // The data connection providing default Internet connection will have a higher score of 50. + // Other connections will have a slightly lower score of 45. The intention is other connections + // will not cause ConnectivityService to tear down default internet connection. For example, + // to validate Internet connection on non-default data SIM, we'll set up a temporary Internet + // connection on that data SIM. In this case, score of 45 is assigned so ConnectivityService + // will not replace the default Internet connection with it. + private static final int DEFAULT_INTERNET_CONNECTION_SCORE = 50; + private static final int OTHER_CONNECTION_SCORE = 45; + + // The score we report to connectivity service + private int mScore; + + // The subscription id associated with this data connection. + private int mSubId; + + // The data connection controller + private DcController mDcController; + + // The Tester for failing all bringup's + private DcTesterFailBringUpAll mDcTesterFailBringUpAll; + + // Whether or not the data connection should allocate its own pdu session id + private boolean mDoAllocatePduSessionId; + + private static AtomicInteger mInstanceNumber = new AtomicInteger(0); + private AsyncChannel mAc; + + // The DCT that's talking to us, we only support one! + private DcTracker mDct = null; + + private String[] mPcscfAddr; + + private final String mTagSuffix; + + private final LocalLog mHandoverLocalLog = new LocalLog(64); + + private int[] mAdministratorUids = new int[0]; + + // stats per data call + private DataCallSessionStats mDataCallSessionStats; + + /** + * Used internally for saving connecting parameters. + */ + public static class ConnectionParams { + int mTag; + ApnContext mApnContext; + int mProfileId; + int mRilRat; + Message mOnCompletedMsg; + final int mConnectionGeneration; + @RequestNetworkType + final int mRequestType; + final int mSubId; + final boolean mIsPreferredApn; + + ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology, + Message onCompletedMsg, int connectionGeneration, + @RequestNetworkType int requestType, int subId, + boolean isPreferredApn) { + mApnContext = apnContext; + mProfileId = profileId; + mRilRat = rilRadioTechnology; + mOnCompletedMsg = onCompletedMsg; + mConnectionGeneration = connectionGeneration; + mRequestType = requestType; + mSubId = subId; + mIsPreferredApn = isPreferredApn; + } + + @Override + public String toString() { + return "{mTag=" + mTag + " mApnContext=" + mApnContext + + " mProfileId=" + mProfileId + + " mRat=" + mRilRat + + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + + " mRequestType=" + DcTracker.requestTypeToString(mRequestType) + + " mSubId=" + mSubId + + " mIsPreferredApn=" + mIsPreferredApn + + "}"; + } + } + + /** + * Used internally for saving disconnecting parameters. + */ + public static class DisconnectParams { + int mTag; + public ApnContext mApnContext; + String mReason; + @ReleaseNetworkType + final int mReleaseType; + Message mOnCompletedMsg; + + DisconnectParams(ApnContext apnContext, String reason, @ReleaseNetworkType int releaseType, + Message onCompletedMsg) { + mApnContext = apnContext; + mReason = reason; + mReleaseType = releaseType; + mOnCompletedMsg = onCompletedMsg; + } + + @Override + public String toString() { + return "{mTag=" + mTag + " mApnContext=" + mApnContext + + " mReason=" + mReason + + " mReleaseType=" + DcTracker.releaseTypeToString(mReleaseType) + + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; + } + } + + private volatile ApnSetting mApnSetting; + private ConnectionParams mConnectionParams; + private DisconnectParams mDisconnectParams; + @DataFailureCause + private int mDcFailCause; + + @HandoverFailureMode + private int mHandoverFailureMode; + + private Phone mPhone; + private DataServiceManager mDataServiceManager; + private VcnManager mVcnManager; + private final int mTransportType; + private LinkProperties mLinkProperties = new LinkProperties(); + private int mPduSessionId; + private long mCreateTime; + private long mLastFailTime; + @DataFailureCause + private int mLastFailCause; + private static final String NULL_IP = "0.0.0.0"; + private Object mUserData; + private boolean mCongestedOverride; + private boolean mUnmeteredOverride; + private int mRilRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; + private int mDataRegState = Integer.MAX_VALUE; + // Indicating data connection is suspended due to temporary reasons, for example, out of + // service, concurrency voice/data not supported, etc.. Note this flag is only meaningful when + // data is in active state. When data is in inactive, connecting, or disconnecting, this flag + // is unmeaningful. + private boolean mIsSuspended; + private int mDownlinkBandwidth = 14; + private int mUplinkBandwidth = 14; + private Qos mDefaultQos = null; + private List mQosBearerSessions = new ArrayList<>(); + private NetworkSliceInfo mSliceInfo; + private List mTrafficDescriptors = new ArrayList<>(); + + /** The corresponding network agent for this data connection. */ + private DcNetworkAgent mNetworkAgent; + + /** + * The network agent from handover source data connection. This is the potential network agent + * that will be transferred here after handover completed. + */ + private DcNetworkAgent mHandoverSourceNetworkAgent; + + private int mDisabledApnTypeBitMask = 0; + + int mTag; + + /** Data connection id assigned by the modem. This is unique across transports */ + public int mCid; + + @HandoverState + private int mHandoverState = HANDOVER_STATE_IDLE; + private final Map mApnContexts = new ConcurrentHashMap<>(); + PendingIntent mReconnectIntent = null; + + /** Class used to track VCN-defined Network policies for this DcNetworkAgent. */ + private final VcnNetworkPolicyChangeListener mVcnPolicyChangeListener = + new DataConnectionVcnNetworkPolicyChangeListener(); + + // ***** Event codes for driving the state machine, package visible for Dcc + static final int BASE = Protocol.BASE_DATA_CONNECTION; + static final int EVENT_CONNECT = BASE + 0; + static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1; + static final int EVENT_DEACTIVATE_DONE = BASE + 3; + static final int EVENT_DISCONNECT = BASE + 4; + static final int EVENT_DISCONNECT_ALL = BASE + 6; + static final int EVENT_DATA_STATE_CHANGED = BASE + 7; + static final int EVENT_TEAR_DOWN_NOW = BASE + 8; + static final int EVENT_LOST_CONNECTION = BASE + 9; + static final int EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED = BASE + 11; + static final int EVENT_DATA_CONNECTION_ROAM_ON = BASE + 12; + static final int EVENT_DATA_CONNECTION_ROAM_OFF = BASE + 13; + static final int EVENT_BW_REFRESH_RESPONSE = BASE + 14; + static final int EVENT_DATA_CONNECTION_VOICE_CALL_STARTED = BASE + 15; + static final int EVENT_DATA_CONNECTION_VOICE_CALL_ENDED = BASE + 16; + static final int EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED = BASE + 17; + static final int EVENT_KEEPALIVE_STATUS = BASE + 18; + static final int EVENT_KEEPALIVE_STARTED = BASE + 19; + static final int EVENT_KEEPALIVE_STOPPED = BASE + 20; + static final int EVENT_KEEPALIVE_START_REQUEST = BASE + 21; + static final int EVENT_KEEPALIVE_STOP_REQUEST = BASE + 22; + static final int EVENT_LINK_CAPACITY_CHANGED = BASE + 23; + static final int EVENT_RESET = BASE + 24; + static final int EVENT_REEVALUATE_RESTRICTED_STATE = BASE + 25; + static final int EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES = BASE + 26; + static final int EVENT_NR_STATE_CHANGED = BASE + 27; + static final int EVENT_DATA_CONNECTION_METEREDNESS_CHANGED = BASE + 28; + static final int EVENT_NR_FREQUENCY_CHANGED = BASE + 29; + static final int EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED = BASE + 30; + static final int EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED = BASE + 31; + static final int EVENT_CSS_INDICATOR_CHANGED = BASE + 32; + static final int EVENT_UPDATE_SUSPENDED_STATE = BASE + 33; + static final int EVENT_START_HANDOVER = BASE + 34; + static final int EVENT_CANCEL_HANDOVER = BASE + 35; + static final int EVENT_START_HANDOVER_ON_TARGET = BASE + 36; + static final int EVENT_ALLOCATE_PDU_SESSION_ID = BASE + 37; + static final int EVENT_RELEASE_PDU_SESSION_ID = BASE + 38; + static final int EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE = BASE + 39; + private static final int CMD_TO_STRING_COUNT = EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE - BASE + 1; + + private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; + static { + sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT"; + sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] = + "EVENT_SETUP_DATA_CONNECTION_DONE"; + sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE"; + sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT"; + sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL"; + sCmdToString[EVENT_DATA_STATE_CHANGED - BASE] = "EVENT_DATA_STATE_CHANGED"; + sCmdToString[EVENT_TEAR_DOWN_NOW - BASE] = "EVENT_TEAR_DOWN_NOW"; + sCmdToString[EVENT_LOST_CONNECTION - BASE] = "EVENT_LOST_CONNECTION"; + sCmdToString[EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED - BASE] = + "EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"; + sCmdToString[EVENT_DATA_CONNECTION_ROAM_ON - BASE] = "EVENT_DATA_CONNECTION_ROAM_ON"; + sCmdToString[EVENT_DATA_CONNECTION_ROAM_OFF - BASE] = "EVENT_DATA_CONNECTION_ROAM_OFF"; + sCmdToString[EVENT_BW_REFRESH_RESPONSE - BASE] = "EVENT_BW_REFRESH_RESPONSE"; + sCmdToString[EVENT_DATA_CONNECTION_VOICE_CALL_STARTED - BASE] = + "EVENT_DATA_CONNECTION_VOICE_CALL_STARTED"; + sCmdToString[EVENT_DATA_CONNECTION_VOICE_CALL_ENDED - BASE] = + "EVENT_DATA_CONNECTION_VOICE_CALL_ENDED"; + sCmdToString[EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED - BASE] = + "EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED"; + sCmdToString[EVENT_KEEPALIVE_STATUS - BASE] = "EVENT_KEEPALIVE_STATUS"; + sCmdToString[EVENT_KEEPALIVE_STARTED - BASE] = "EVENT_KEEPALIVE_STARTED"; + sCmdToString[EVENT_KEEPALIVE_STOPPED - BASE] = "EVENT_KEEPALIVE_STOPPED"; + sCmdToString[EVENT_KEEPALIVE_START_REQUEST - BASE] = "EVENT_KEEPALIVE_START_REQUEST"; + sCmdToString[EVENT_KEEPALIVE_STOP_REQUEST - BASE] = "EVENT_KEEPALIVE_STOP_REQUEST"; + sCmdToString[EVENT_LINK_CAPACITY_CHANGED - BASE] = "EVENT_LINK_CAPACITY_CHANGED"; + sCmdToString[EVENT_RESET - BASE] = "EVENT_RESET"; + sCmdToString[EVENT_REEVALUATE_RESTRICTED_STATE - BASE] = + "EVENT_REEVALUATE_RESTRICTED_STATE"; + sCmdToString[EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES - BASE] = + "EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES"; + sCmdToString[EVENT_NR_STATE_CHANGED - BASE] = "EVENT_NR_STATE_CHANGED"; + sCmdToString[EVENT_DATA_CONNECTION_METEREDNESS_CHANGED - BASE] = + "EVENT_DATA_CONNECTION_METEREDNESS_CHANGED"; + sCmdToString[EVENT_NR_FREQUENCY_CHANGED - BASE] = "EVENT_NR_FREQUENCY_CHANGED"; + sCmdToString[EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED - BASE] = + "EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED"; + sCmdToString[EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED - BASE] = + "EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED"; + sCmdToString[EVENT_CSS_INDICATOR_CHANGED - BASE] = "EVENT_CSS_INDICATOR_CHANGED"; + sCmdToString[EVENT_UPDATE_SUSPENDED_STATE - BASE] = "EVENT_UPDATE_SUSPENDED_STATE"; + sCmdToString[EVENT_START_HANDOVER - BASE] = "EVENT_START_HANDOVER"; + sCmdToString[EVENT_CANCEL_HANDOVER - BASE] = "EVENT_CANCEL_HANDOVER"; + sCmdToString[EVENT_START_HANDOVER_ON_TARGET - BASE] = "EVENT_START_HANDOVER_ON_TARGET"; + sCmdToString[EVENT_ALLOCATE_PDU_SESSION_ID - BASE] = "EVENT_ALLOCATE_PDU_SESSION_ID"; + sCmdToString[EVENT_RELEASE_PDU_SESSION_ID - BASE] = "EVENT_RELEASE_PDU_SESSION_ID"; + sCmdToString[EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE - BASE] = + "EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE"; + } + // Convert cmd to string or null if unknown + static String cmdToString(int cmd) { + String value = null; + cmd -= BASE; + if ((cmd >= 0) && (cmd < sCmdToString.length)) { + value = sCmdToString[cmd]; + } + if (value == null) { + value = "0x" + Integer.toHexString(cmd + BASE); + } + return value; + } + + /** + * Create the connection object + * + * @param phone the Phone + * @param id the connection id + * @return DataConnection that was created. + */ + public static DataConnection makeDataConnection(Phone phone, int id, DcTracker dct, + DataServiceManager dataServiceManager, + DcTesterFailBringUpAll failBringUpAll, + DcController dcc) { + String transportType = (dataServiceManager.getTransportType() + == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + ? "C" // Cellular + : "I"; // IWLAN + DataConnection dc = new DataConnection(phone, transportType + "-" + + mInstanceNumber.incrementAndGet(), id, dct, dataServiceManager, failBringUpAll, + dcc); + dc.start(); + if (DBG) dc.log("Made " + dc.getName()); + return dc; + } + + void dispose() { + log("dispose: call quiteNow()"); + quitNow(); + } + + /* Getter functions */ + + LinkProperties getLinkProperties() { + return new LinkProperties(mLinkProperties); + } + + boolean isDisconnecting() { + return getCurrentState() == mDisconnectingState + || getCurrentState() == mDisconnectingErrorCreatingConnection; + } + + @VisibleForTesting + public boolean isActive() { + return getCurrentState() == mActiveState; + } + + @VisibleForTesting + public boolean isInactive() { + return getCurrentState() == mInactiveState; + } + + boolean isActivating() { + return getCurrentState() == mActivatingState; + } + + boolean hasBeenTransferred() { + return mHandoverState == HANDOVER_STATE_COMPLETED; + } + + int getCid() { + return mCid; + } + + /** + * @return DataConnection's ApnSetting. + */ + public ApnSetting getApnSetting() { + return mApnSetting; + } + + /** + * Update http proxy of link properties based on current apn setting + */ + private void updateLinkPropertiesHttpProxy() { + if (mApnSetting == null + || TextUtils.isEmpty(mApnSetting.getProxyAddressAsString())) { + return; + } + try { + int port = mApnSetting.getProxyPort(); + if (port == -1) { + port = 8080; + } + ProxyInfo proxy = ProxyInfo.buildDirectProxy( + mApnSetting.getProxyAddressAsString(), port); + mLinkProperties.setHttpProxy(proxy); + } catch (NumberFormatException e) { + loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" + + mApnSetting.getProxyPort() + "): " + e); + } + } + + public static class UpdateLinkPropertyResult { + public SetupResult setupResult = SetupResult.SUCCESS; + public LinkProperties oldLp; + public LinkProperties newLp; + public UpdateLinkPropertyResult(LinkProperties curLp) { + oldLp = curLp; + newLp = curLp; + } + } + + /** + * Class returned by onSetupConnectionCompleted. + */ + public enum SetupResult { + SUCCESS, + ERROR_RADIO_NOT_AVAILABLE, + ERROR_INVALID_ARG, + ERROR_STALE, + ERROR_DATA_SERVICE_SPECIFIC_ERROR, + ERROR_DUPLICATE_CID, + ERROR_NO_DEFAULT_CONNECTION; + + public int mFailCause; + + SetupResult() { + mFailCause = DataFailCause.getFailCause(0); + } + + @Override + public String toString() { + return name() + " SetupResult.mFailCause=" + DataFailCause.toString(mFailCause); + } + } + + public boolean isIpv4Connected() { + boolean ret = false; + Collection addresses = mLinkProperties.getAddresses(); + + for (InetAddress addr: addresses) { + if (addr instanceof java.net.Inet4Address) { + java.net.Inet4Address i4addr = (java.net.Inet4Address) addr; + if (!i4addr.isAnyLocalAddress() && !i4addr.isLinkLocalAddress() && + !i4addr.isLoopbackAddress() && !i4addr.isMulticastAddress()) { + ret = true; + break; + } + } + } + return ret; + } + + public boolean isIpv6Connected() { + boolean ret = false; + Collection addresses = mLinkProperties.getAddresses(); + + for (InetAddress addr: addresses) { + if (addr instanceof java.net.Inet6Address) { + java.net.Inet6Address i6addr = (java.net.Inet6Address) addr; + if (!i6addr.isAnyLocalAddress() && !i6addr.isLinkLocalAddress() && + !i6addr.isLoopbackAddress() && !i6addr.isMulticastAddress()) { + ret = true; + break; + } + } + } + return ret; + } + + public int getPduSessionId() { + return mPduSessionId; + } + + public NetworkSliceInfo getSliceInfo() { + return mSliceInfo; + } + + public List getTrafficDescriptors() { + return mTrafficDescriptors; + } + + /** + * Update DC fields based on a new DataCallResponse + * @param response the response to use to update DC fields + */ + public void updateResponseFields(DataCallResponse response) { + updateQosParameters(response); + updateSliceInfo(response); + updateTrafficDescriptors(response); + } + + public void updateQosParameters(final @Nullable DataCallResponse response) { + if (response == null) { + mDefaultQos = null; + mQosBearerSessions.clear(); + return; + } + + mDefaultQos = response.getDefaultQos(); + mQosBearerSessions = response.getQosBearerSessions(); + + if (mNetworkAgent != null) { + syncQosToNetworkAgent(); + } + } + + private void syncQosToNetworkAgent() { + final DcNetworkAgent networkAgent = mNetworkAgent; + final List qosBearerSessions = mQosBearerSessions; + if (qosBearerSessions == null) { + networkAgent.updateQosBearerSessions(new ArrayList<>()); + return; + } + networkAgent.updateQosBearerSessions(qosBearerSessions); + } + + /** + * Update the latest slice info on this data connection with + * {@link DataCallResponse#getSliceInfo}. + */ + public void updateSliceInfo(DataCallResponse response) { + mSliceInfo = response.getSliceInfo(); + } + + /** + * Update the latest traffic descriptor on this data connection with + * {@link DataCallResponse#getTrafficDescriptors}. + */ + public void updateTrafficDescriptors(DataCallResponse response) { + mTrafficDescriptors = response.getTrafficDescriptors(); + mDcController.updateTrafficDescriptorsForCid(response.getId(), + response.getTrafficDescriptors()); + } + + @VisibleForTesting + public UpdateLinkPropertyResult updateLinkProperty(DataCallResponse newState) { + UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties); + + if (newState == null) return result; + + result.newLp = new LinkProperties(); + + // set link properties based on data call response + result.setupResult = setLinkProperties(newState, result.newLp); + if (result.setupResult != SetupResult.SUCCESS) { + if (DBG) log("updateLinkProperty failed : " + result.setupResult); + return result; + } + // copy HTTP proxy as it is not part DataCallResponse. + result.newLp.setHttpProxy(mLinkProperties.getHttpProxy()); + + checkSetMtu(mApnSetting, result.newLp); + + mLinkProperties = result.newLp; + + updateTcpBufferSizes(mRilRat); + + if (DBG && (! result.oldLp.equals(result.newLp))) { + log("updateLinkProperty old LP=" + result.oldLp); + log("updateLinkProperty new LP=" + result.newLp); + } + + if (result.newLp.equals(result.oldLp) == false && + mNetworkAgent != null) { + mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); + } + + return result; + } + + /** + * Sets the pdu session id of the data connection + * @param pduSessionId pdu session id to set + */ + @VisibleForTesting + public void setPduSessionId(int pduSessionId) { + if (mPduSessionId != pduSessionId) { + logd("Changing pdu session id from: " + mPduSessionId + " to: " + pduSessionId + ", " + + "Handover state: " + handoverStateToString(this.mHandoverState)); + mPduSessionId = pduSessionId; + } + } + + /** + * Read the MTU value from link properties where it can be set from network. In case + * not set by the network, set it again using the mtu szie value defined in the APN + * database for the connected APN + */ + private void checkSetMtu(ApnSetting apn, LinkProperties lp) { + if (lp == null) return; + + if (apn == null || lp == null) return; + + if (lp.getMtu() != PhoneConstants.UNSET_MTU) { + if (DBG) log("MTU set by call response to: " + lp.getMtu()); + return; + } + + if (apn != null && apn.getMtuV4() != PhoneConstants.UNSET_MTU) { + lp.setMtu(apn.getMtuV4()); + if (DBG) log("MTU set by APN to: " + apn.getMtuV4()); + return; + } + + int mtu = mPhone.getContext().getResources().getInteger( + com.android.internal.R.integer.config_mobile_mtu); + if (mtu != PhoneConstants.UNSET_MTU) { + lp.setMtu(mtu); + if (DBG) log("MTU set by config resource to: " + mtu); + } + } + + //***** Constructor (NOTE: uses dcc.getHandler() as its Handler) + private DataConnection(Phone phone, String tagSuffix, int id, + DcTracker dct, DataServiceManager dataServiceManager, + DcTesterFailBringUpAll failBringUpAll, DcController dcc) { + super("DC-" + tagSuffix, dcc); + mTagSuffix = tagSuffix; + setLogRecSize(300); + setLogOnlyTransitions(true); + if (DBG) log("DataConnection created"); + + mPhone = phone; + mDct = dct; + mDataServiceManager = dataServiceManager; + mVcnManager = mPhone.getContext().getSystemService(VcnManager.class); + mTransportType = dataServiceManager.getTransportType(); + mDcTesterFailBringUpAll = failBringUpAll; + mDcController = dcc; + mId = id; + mCid = -1; + mDataRegState = mPhone.getServiceState().getDataRegistrationState(); + mIsSuspended = false; + mDataCallSessionStats = new DataCallSessionStats(mPhone); + mDoAllocatePduSessionId = false; + + int networkType = getNetworkType(); + mRilRat = ServiceState.networkTypeToRilRadioTechnology(networkType); + updateLinkBandwidthsFromCarrierConfig(mRilRat); + + addState(mDefaultState); + addState(mInactiveState, mDefaultState); + addState(mActivatingState, mDefaultState); + addState(mActiveState, mDefaultState); + addState(mDisconnectingState, mDefaultState); + addState(mDisconnectingErrorCreatingConnection, mDefaultState); + setInitialState(mInactiveState); + } + + private @NetworkType int getNetworkType() { + ServiceState ss = mPhone.getServiceState(); + int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + + NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, mTransportType); + if (nri != null) { + networkType = nri.getAccessNetworkTechnology(); + } + + return networkType; + } + + /** + * Get the source transport for handover. For example, handover from WWAN to WLAN, WWAN is the + * source transport, and vice versa. + */ + private @TransportType int getHandoverSourceTransport() { + return mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN + ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN + : AccessNetworkConstants.TRANSPORT_TYPE_WWAN; + } + + /** + * API to generate the OsAppId for enterprise traffic category. + * @return byte[] representing OsId + length of OsAppId + OsAppId + */ + @VisibleForTesting + public static byte[] getEnterpriseOsAppId() { + byte[] osAppId = NetworkCapabilities.getCapabilityCarrierName( + NetworkCapabilities.NET_CAPABILITY_ENTERPRISE).getBytes(); + // 16 bytes for UUID, 1 byte for length of osAppId, and up to 255 bytes for osAppId + ByteBuffer bb = ByteBuffer.allocate(16 + 1 + osAppId.length); + bb.putLong(OS_ID.getMostSignificantBits()); + bb.putLong(OS_ID.getLeastSignificantBits()); + bb.put((byte) osAppId.length); + bb.put(osAppId); + if (VDBG) { + Rlog.d("DataConnection", "getEnterpriseOsAppId: " + + IccUtils.bytesToHexString(bb.array())); + } + return bb.array(); + } + + /** + * Begin setting up a data connection, calls setupDataCall + * and the ConnectionParams will be returned with the + * EVENT_SETUP_DATA_CONNECTION_DONE + * + * @param cp is the connection parameters + * + * @return Fail cause if failed to setup data connection. {@link DataFailCause#NONE} if success. + */ + private @DataFailureCause int connect(ConnectionParams cp) { + log("connect: carrier='" + mApnSetting.getEntryName() + + "' APN='" + mApnSetting.getApnName() + + "' proxy='" + mApnSetting.getProxyAddressAsString() + + "' port='" + mApnSetting.getProxyPort() + "'"); + ApnContext.requestLog(cp.mApnContext, "DataConnection.connect"); + + // Check if we should fake an error. + if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter > 0) { + DataCallResponse response = new DataCallResponse.Builder() + .setCause(mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause) + .setRetryDurationMillis( + mDcTesterFailBringUpAll.getDcFailBringUp().mSuggestedRetryTime) + .setMtuV4(PhoneConstants.UNSET_MTU) + .setMtuV6(PhoneConstants.UNSET_MTU) + .build(); + + Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp); + AsyncResult.forMessage(msg, response, null); + sendMessage(msg); + if (DBG) { + log("connect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp() + + " send error response=" + response); + } + mDcTesterFailBringUpAll.getDcFailBringUp().mCounter -= 1; + return DataFailCause.NONE; + } + + mCreateTime = -1; + mLastFailTime = -1; + mLastFailCause = DataFailCause.NONE; + + Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp); + msg.obj = cp; + + DataProfile dp = new DataProfile.Builder() + .setApnSetting(mApnSetting) + .setPreferred(cp.mIsPreferredApn) + .build(); + + // We need to use the actual modem roaming state instead of the framework roaming state + // here. This flag is only passed down to ril_service for picking the correct protocol (for + // old modem backward compatibility). + boolean isModemRoaming = mPhone.getServiceState().getDataRoamingFromRegistration(); + + // If the apn is NOT metered, we will allow data roaming regardless of the setting. + boolean isUnmeteredApnType = !ApnSettingUtils.isMeteredApnType( + cp.mApnContext.getApnTypeBitmask(), mPhone); + + // Set this flag to true if the user turns on data roaming. Or if we override the roaming + // state in framework, we should set this flag to true as well so the modem will not reject + // the data call setup (because the modem actually thinks the device is roaming). + boolean allowRoaming = mPhone.getDataRoamingEnabled() + || (isModemRoaming && (!mPhone.getServiceState().getDataRoaming() + || isUnmeteredApnType)); + + String dnn = null; + byte[] osAppId = null; + if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { + osAppId = getEnterpriseOsAppId(); + } else { + dnn = mApnSetting.getApnName(); + } + final TrafficDescriptor td = osAppId == null && dnn == null ? null + : new TrafficDescriptor(dnn, osAppId); + final boolean matchAllRuleAllowed = td == null || td.getOsAppId() == null; + + if (DBG) { + log("allowRoaming=" + allowRoaming + + ", mPhone.getDataRoamingEnabled()=" + mPhone.getDataRoamingEnabled() + + ", isModemRoaming=" + isModemRoaming + + ", mPhone.getServiceState().getDataRoaming()=" + + mPhone.getServiceState().getDataRoaming() + + ", isUnmeteredApnType=" + isUnmeteredApnType + + ", trafficDescriptor=" + td + + ", matchAllRuleAllowed=" + matchAllRuleAllowed + ); + } + + // Check if this data setup is a handover. + LinkProperties linkProperties = null; + int reason = DataService.REQUEST_REASON_NORMAL; + if (cp.mRequestType == REQUEST_TYPE_HANDOVER) { + // If this is a data setup for handover, we need to pass the link properties + // of the existing data connection to the modem. + DcTracker srcDcTracker = mPhone.getDcTracker(getHandoverSourceTransport()); + if (srcDcTracker == null || cp.mApnContext == null) { + loge("connect: Handover failed. dcTracker=" + srcDcTracker + ", apnContext=" + + cp.mApnContext); + return DataFailCause.HANDOVER_FAILED; + } + + + // srcDc is the source data connection while the current instance is the target + DataConnection srcDc = + srcDcTracker.getDataConnectionByApnType(cp.mApnContext.getApnType()); + if (srcDc == null) { + loge("connect: Can't find data connection for handover."); + return DataFailCause.HANDOVER_FAILED; + } + + // Helpful for logging purposes + DataServiceManager srcDsm = srcDc.mDataServiceManager; + String srcDsmTag = (srcDsm == null ? "(null)" : srcDsm.getTag()); + logd("connect: REQUEST_TYPE_HANDOVER - Request handover from " + srcDc.getName() + + ", targetDsm=" + mDataServiceManager.getTag() + + ", sourceDsm=" + srcDsmTag); + + + /* startHandover is called on the source data connection, and if successful, + we ask the target data connection (which is the current instance) to call + #setupDataCall with request type handover. + */ + Consumer onCompleted = (dataServiceCallbackResultCode) -> + /* startHandover is called on the srcDc handler, but the callback needs to + be called on the current (which is the targetDc) handler which is why we + call sendRunnableMessage. */ + sendRunnableMessage(EVENT_START_HANDOVER_ON_TARGET, + (inCorrectState) -> requestHandover(inCorrectState, srcDc, + dataServiceCallbackResultCode, + cp, msg, dp, isModemRoaming, allowRoaming)); + srcDc.startHandover(onCompleted); + return DataFailCause.NONE; + } + + // setup data call for REQUEST_TYPE_NORMAL + mDoAllocatePduSessionId = mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN; + allocatePduSessionId(psi -> { + this.setPduSessionId(psi); + mDataServiceManager.setupDataCall( + ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), + dp, + isModemRoaming, + allowRoaming, + reason, + linkProperties, + psi, + null, //slice info is null since this is not a handover + td, + matchAllRuleAllowed, + msg); + TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat, + dp.getProfileId(), dp.getApn(), dp.getProtocolType()); + }); + return DataFailCause.NONE; + } + + private void allocatePduSessionId(Consumer allocateCallback) { + if (mDoAllocatePduSessionId) { + Message msg = this.obtainMessage(EVENT_ALLOCATE_PDU_SESSION_ID); + msg.obj = allocateCallback; + mPhone.mCi.allocatePduSessionId(msg); + } else { + allocateCallback.accept(PDU_SESSION_ID_NOT_SET); + } + } + + private void onRquestHandoverFailed(ConnectionParams cp) { + sendMessage(obtainMessage(EVENT_CANCEL_HANDOVER)); + notifyConnectCompleted(cp, DataFailCause.UNKNOWN, + DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); + } + + private void requestHandover(boolean inCorrectState, DataConnection srcDc, + @DataServiceCallback.ResultCode int resultCode, + ConnectionParams cp, Message msg, DataProfile dp, boolean isModemRoaming, + boolean allowRoaming) { + + if (!inCorrectState) { + logd("requestHandover: Not in correct state"); + if (isResultCodeSuccess(resultCode)) { + if (srcDc != null) { + logd("requestHandover: Not in correct state - Success result code"); + // We need to cancel the handover on source if we ended up in the wrong state. + srcDc.cancelHandover(); + } else { + logd("requestHandover: Not in correct state - Success result code - " + + "srcdc = null"); + } + } + onRquestHandoverFailed(cp); + return; + } else if (!isResultCodeSuccess(resultCode)) { + if (DBG) { + logd("requestHandover: Non success result code from DataService, " + + "setupDataCall will not be called, result code = " + + DataServiceCallback.resultCodeToString(resultCode)); + } + onRquestHandoverFailed(cp); + return; + } + + if (srcDc == null) { + loge("requestHandover: Cannot find source data connection."); + onRquestHandoverFailed(cp); + return; + } + + LinkProperties linkProperties; + int reason; + + // Preserve the potential network agent from the source data connection. The ownership + // is not transferred at this moment. + mHandoverSourceNetworkAgent = srcDc.getNetworkAgent(); + if (mHandoverSourceNetworkAgent == null) { + loge("requestHandover: Cannot get network agent from the source dc " + srcDc.getName()); + onRquestHandoverFailed(cp); + return; + } + + linkProperties = srcDc.getLinkProperties(); + if (linkProperties == null || linkProperties.getLinkAddresses().isEmpty()) { + loge("requestHandover: Can't find link properties of handover data connection. dc=" + + srcDc); + onRquestHandoverFailed(cp); + return; + } + + mHandoverLocalLog.log("Handover started. Preserved the agent."); + log("Get the handover source network agent: " + mHandoverSourceNetworkAgent); + + reason = DataService.REQUEST_REASON_HANDOVER; + + TrafficDescriptor td = dp.getApn() == null ? null + : new TrafficDescriptor(dp.getApn(), null); + boolean matchAllRuleAllowed = true; + + mDataServiceManager.setupDataCall( + ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), + dp, + isModemRoaming, + allowRoaming, + reason, + linkProperties, + srcDc.getPduSessionId(), + srcDc.getSliceInfo(), + td, + matchAllRuleAllowed, + msg); + TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat, + dp.getProfileId(), dp.getApn(), dp.getProtocolType()); + } + + /** + * Called on the source data connection from the target data connection. + */ + @VisibleForTesting + public void startHandover(Consumer onTargetDcComplete) { + logd("startHandover: " + toStringSimple()); + // Set the handover state to being transferred on "this" data connection which is the src. + setHandoverState(HANDOVER_STATE_BEING_TRANSFERRED); + + Consumer onSrcDcComplete = + resultCode -> onHandoverStarted(resultCode, onTargetDcComplete); + /* + The flow here is: + srcDc#startHandover -> dataService#startHandover -> (onHandoverStarted) -> + onSrcDcComplete -> onTargetDcComplete + */ + mDataServiceManager.startHandover(mCid, + this.obtainMessage(EVENT_START_HANDOVER, + onSrcDcComplete)); + } + + /** + * Called on the source data connection when the async call to start handover is complete + */ + private void onHandoverStarted(@DataServiceCallback.ResultCode int resultCode, + Consumer onTargetDcComplete) { + logd("onHandoverStarted: " + toStringSimple()); + if (!isResultCodeSuccess(resultCode)) { + setHandoverState(HANDOVER_STATE_IDLE); + } + onTargetDcComplete.accept(resultCode); + } + + private void cancelHandover() { + if (mHandoverState != HANDOVER_STATE_BEING_TRANSFERRED) { + logd("cancelHandover: handover state is " + handoverStateToString(mHandoverState) + + ", expecting HANDOVER_STATE_BEING_TRANSFERRED"); + } + mDataServiceManager.cancelHandover(mCid, this.obtainMessage(EVENT_CANCEL_HANDOVER)); + setHandoverState(HANDOVER_STATE_IDLE); + } + + /** + * Update NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED based on congested override + * @param isCongested whether this DC should be set to congested or not + */ + public void onCongestednessChanged(boolean isCongested) { + sendMessage(obtainMessage(EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED, isCongested)); + } + + /** + * Update NetworkCapabilities.NET_CAPABILITY_NOT_METERED based on metered override + * @param isUnmetered whether this DC should be set to unmetered or not + */ + public void onMeterednessChanged(boolean isUnmetered) { + sendMessage(obtainMessage(EVENT_DATA_CONNECTION_METEREDNESS_CHANGED, isUnmetered)); + } + + /** + * TearDown the data connection when the deactivation is complete a Message with + * msg.what == EVENT_DEACTIVATE_DONE + * + * @param o is the object returned in the AsyncResult.obj. + */ + private void tearDownData(Object o) { + int discReason = DataService.REQUEST_REASON_NORMAL; + ApnContext apnContext = null; + if ((o != null) && (o instanceof DisconnectParams)) { + DisconnectParams dp = (DisconnectParams) o; + apnContext = dp.mApnContext; + if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF) + || TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) { + discReason = DataService.REQUEST_REASON_SHUTDOWN; + } else if (dp.mReleaseType == DcTracker.RELEASE_TYPE_HANDOVER) { + discReason = DataService.REQUEST_REASON_HANDOVER; + } + } + + String str = "tearDownData. mCid=" + mCid + ", reason=" + discReason; + if (DBG) log(str); + ApnContext.requestLog(apnContext, str); + + + //Needed to be final to work in a closure + final int fDiscReason = discReason; + releasePduSessionId(() -> { + // This is run after release pdu session id is complete + this.setPduSessionId(PDU_SESSION_ID_NOT_SET); + mDataServiceManager.deactivateDataCall(mCid, fDiscReason, + obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, o)); + mDataCallSessionStats.setDeactivateDataCallReason(fDiscReason); + }); + } + + private void releasePduSessionId(Runnable releaseCallback) { + // If the transport is IWLAN, and there is a valid PDU session id, also the data connection + // is not being handovered, we should release the pdu session id. + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN + && mHandoverState == HANDOVER_STATE_IDLE + && this.getPduSessionId() != PDU_SESSION_ID_NOT_SET) { + Message msg = this.obtainMessage(EVENT_RELEASE_PDU_SESSION_ID); + msg.obj = releaseCallback; + mPhone.mCi.releasePduSessionId(msg, this.getPduSessionId()); + } else { + // Just go and run the callback since we either have no pdu session id to release + // or we are in the middle of a handover + releaseCallback.run(); + } + } + + private void notifyAllWithEvent(ApnContext alreadySent, int event, String reason) { + for (ConnectionParams cp : mApnContexts.values()) { + ApnContext apnContext = cp.mApnContext; + if (apnContext == alreadySent) continue; + if (reason != null) apnContext.setReason(reason); + Pair pair = new Pair<>(apnContext, cp.mConnectionGeneration); + Message msg = mDct.obtainMessage(event, cp.mRequestType, + DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, pair); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + } + } + + /** + * Send the connectionCompletedMsg. + * + * @param cp is the ConnectionParams + * @param cause and if no error the cause is DataFailCause.NONE + * @param handoverFailureMode The action on handover failure + * @param sendAll is true if all contexts are to be notified + */ + private void notifyConnectCompleted(ConnectionParams cp, @DataFailureCause int cause, + @HandoverFailureMode int handoverFailureMode, boolean sendAll) { + ApnContext alreadySent = null; + + if (cp != null && cp.mOnCompletedMsg != null) { + // Get the completed message but only use it once + Message connectionCompletedMsg = cp.mOnCompletedMsg; + cp.mOnCompletedMsg = null; + alreadySent = cp.mApnContext; + + long timeStamp = System.currentTimeMillis(); + connectionCompletedMsg.arg1 = cp.mRequestType; + connectionCompletedMsg.arg2 = handoverFailureMode; + + if (cause == DataFailCause.NONE) { + mCreateTime = timeStamp; + AsyncResult.forMessage(connectionCompletedMsg); + } else { + mLastFailCause = cause; + mLastFailTime = timeStamp; + + // Return message with a Throwable exception to signify an error. + if (cause == DataFailCause.NONE) cause = DataFailCause.UNKNOWN; + AsyncResult.forMessage(connectionCompletedMsg, cause, + new Throwable(DataFailCause.toString(cause))); + } + if (DBG) { + log("notifyConnectCompleted at " + timeStamp + " cause=" + + DataFailCause.toString(cause) + " connectionCompletedMsg=" + + msgToString(connectionCompletedMsg)); + } + + connectionCompletedMsg.sendToTarget(); + } + if (sendAll) { + log("Send to all. " + alreadySent + " " + DataFailCause.toString(cause)); + notifyAllWithEvent(alreadySent, DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR, + DataFailCause.toString(cause)); + } + } + + /** + * Send ar.userObj if its a message, which is should be back to originator. + * + * @param dp is the DisconnectParams. + */ + private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) { + if (VDBG) log("NotifyDisconnectCompleted"); + + ApnContext alreadySent = null; + String reason = null; + + if (dp != null && dp.mOnCompletedMsg != null) { + // Get the completed message but only use it once + Message msg = dp.mOnCompletedMsg; + dp.mOnCompletedMsg = null; + if (msg.obj instanceof ApnContext) { + alreadySent = (ApnContext)msg.obj; + } + reason = dp.mReason; + if (VDBG) { + log(String.format("msg=%s msg.obj=%s", msg.toString(), + ((msg.obj instanceof String) ? (String) msg.obj : ""))); + } + AsyncResult.forMessage(msg); + msg.sendToTarget(); + } + if (sendAll) { + if (reason == null) { + reason = DataFailCause.toString(DataFailCause.UNKNOWN); + } + notifyAllWithEvent(alreadySent, DctConstants.EVENT_DISCONNECT_DONE, reason); + } + if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp); + } + + private void sendRunnableMessage(int eventCode, @NonNull final Consumer r) { + sendMessage(eventCode, r); + } + + /* + * ************************************************************************** + * Begin Members and methods owned by DataConnectionTracker but stored + * in a DataConnection because there is one per connection. + * ************************************************************************** + */ + + /* + * The id is owned by DataConnectionTracker. + */ + private int mId; + + /** + * Get the DataConnection ID + */ + public int getDataConnectionId() { + return mId; + } + + /* + * ************************************************************************** + * End members owned by DataConnectionTracker + * ************************************************************************** + */ + + /** + * Clear all settings called when entering mInactiveState. + */ + private synchronized void clearSettings() { + if (DBG) log("clearSettings"); + + mCreateTime = -1; + mLastFailTime = -1; + mLastFailCause = DataFailCause.NONE; + mCid = -1; + + mPcscfAddr = new String[5]; + + mLinkProperties = new LinkProperties(); + mApnContexts.clear(); + mApnSetting = null; + mUnmeteredUseOnly = false; + mMmsUseOnly = false; + mEnterpriseUse = false; + mRestrictedNetworkOverride = false; + mDcFailCause = DataFailCause.NONE; + mDisabledApnTypeBitMask = 0; + mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + mCongestedOverride = false; + mUnmeteredOverride = false; + mDownlinkBandwidth = 14; + mUplinkBandwidth = 14; + mIsSuspended = false; + mHandoverState = HANDOVER_STATE_IDLE; + mHandoverFailureMode = DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN; + mSliceInfo = null; + mDefaultQos = null; + mDoAllocatePduSessionId = false; + mQosBearerSessions.clear(); + mTrafficDescriptors.clear(); + } + + /** + * Process setup data completion result from data service + * + * @param resultCode The result code returned by data service + * @param response Data call setup response from data service + * @param cp The original connection params used for data call setup + * @return Setup result + */ + private SetupResult onSetupConnectionCompleted(@DataServiceCallback.ResultCode int resultCode, + DataCallResponse response, + ConnectionParams cp) { + SetupResult result; + + log("onSetupConnectionCompleted: resultCode=" + resultCode + ", response=" + response); + if (cp.mTag != mTag) { + if (DBG) { + log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag); + } + result = SetupResult.ERROR_STALE; + } else if (resultCode == DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE) { + result = SetupResult.ERROR_RADIO_NOT_AVAILABLE; + result.mFailCause = DataFailCause.RADIO_NOT_AVAILABLE; + } else if (resultCode == DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE) { + result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; + result.mFailCause = DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE; + } else if (resultCode == DataServiceCallback.RESULT_ERROR_INVALID_ARG) { + result = SetupResult.ERROR_INVALID_ARG; + result.mFailCause = DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER; + } else if (response.getCause() != 0) { + if (response.getCause() == DataFailCause.RADIO_NOT_AVAILABLE) { + result = SetupResult.ERROR_RADIO_NOT_AVAILABLE; + result.mFailCause = DataFailCause.RADIO_NOT_AVAILABLE; + } else { + result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; + result.mFailCause = DataFailCause.getFailCause(response.getCause()); + } + } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE + && mDcController.getActiveDcByCid(response.getId()) != null) { + if (!mDcController.getTrafficDescriptorsForCid(response.getId()) + .equals(response.getTrafficDescriptors())) { + if (DBG) log("Updating traffic descriptors: " + response.getTrafficDescriptors()); + mDcController.getActiveDcByCid(response.getId()).updateTrafficDescriptors(response); + mDct.obtainMessage(DctConstants.EVENT_TRAFFIC_DESCRIPTORS_UPDATED).sendToTarget(); + } + if (DBG) log("DataConnection already exists for cid: " + response.getId()); + result = SetupResult.ERROR_DUPLICATE_CID; + result.mFailCause = DataFailCause.DUPLICATE_CID; + } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE + && !mDcController.isDefaultDataActive()) { + if (DBG) log("No default data connection currently active"); + mCid = response.getId(); + result = SetupResult.ERROR_NO_DEFAULT_CONNECTION; + result.mFailCause = DataFailCause.NO_DEFAULT_DATA; + } else { + if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse"); + mCid = response.getId(); + setPduSessionId(response.getPduSessionId()); + updatePcscfAddr(response); + updateResponseFields(response); + result = updateLinkProperty(response).setupResult; + } + + return result; + } + + private static boolean isResultCodeSuccess(int resultCode) { + return resultCode == DataServiceCallback.RESULT_SUCCESS + || resultCode == DataServiceCallback.RESULT_ERROR_UNSUPPORTED; + } + + private boolean isDnsOk(String[] domainNameServers) { + if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1]) + && !mPhone.isDnsCheckDisabled()) { + // Work around a race condition where QMI does not fill in DNS: + // Deactivate PDP and let DataConnectionTracker retry. + // Do not apply the race condition workaround for MMS APN + // if Proxy is an IP-address. + // Otherwise, the default APN will not be restored anymore. + if (!isIpAddress(mApnSetting.getMmsProxyAddressAsString())) { + log(String.format( + "isDnsOk: return false apn.types=%d APN_TYPE_MMS=%s isIpAddress(%s)=%s", + mApnSetting.getApnTypeBitmask(), ApnSetting.TYPE_MMS_STRING, + mApnSetting.getMmsProxyAddressAsString(), + isIpAddress(mApnSetting.getMmsProxyAddressAsString()))); + return false; + } + } + return true; + } + + /** + * TCP buffer size config based on the ril technology. There are 6 parameters + * read_min, read_default, read_max, write_min, write_default, write_max in the TCP buffer + * config string and they are separated by a comma. The unit of these parameters is byte. + */ + private static final String TCP_BUFFER_SIZES_GPRS = "4092,8760,48000,4096,8760,48000"; + private static final String TCP_BUFFER_SIZES_EDGE = "4093,26280,70800,4096,16384,70800"; + private static final String TCP_BUFFER_SIZES_UMTS = "58254,349525,1048576,58254,349525,1048576"; + private static final String TCP_BUFFER_SIZES_1XRTT = "16384,32768,131072,4096,16384,102400"; + private static final String TCP_BUFFER_SIZES_EVDO = "4094,87380,262144,4096,16384,262144"; + private static final String TCP_BUFFER_SIZES_EHRPD = "131072,262144,1048576,4096,16384,524288"; + private static final String TCP_BUFFER_SIZES_HSDPA = "61167,367002,1101005,8738,52429,262114"; + private static final String TCP_BUFFER_SIZES_HSPA = "40778,244668,734003,16777,100663,301990"; + private static final String TCP_BUFFER_SIZES_LTE = + "524288,1048576,2097152,262144,524288,1048576"; + private static final String TCP_BUFFER_SIZES_HSPAP = + "122334,734003,2202010,32040,192239,576717"; + private static final String TCP_BUFFER_SIZES_NR = + "2097152,6291456,16777216,512000,2097152,8388608"; + private static final String TCP_BUFFER_SIZES_LTE_CA = + "4096,6291456,12582912,4096,1048576,2097152"; + + private void updateTcpBufferSizes(int rilRat) { + String sizes = null; + ServiceState ss = mPhone.getServiceState(); + if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE && + ss.isUsingCarrierAggregation()) { + rilRat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA; + } + String ratName = ServiceState.rilRadioTechnologyToString(rilRat).toLowerCase(Locale.ROOT); + // ServiceState gives slightly different names for EVDO tech ("evdo-rev.0" for ex) + // - patch it up: + if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0 || + rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A || + rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B) { + ratName = RAT_NAME_EVDO; + } + + // NR 5G Non-Standalone use LTE cell as the primary cell, the ril technology is LTE in this + // case. We use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network. + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN + && ((rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE || + rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA) && isNRConnected()) + && mPhone.getServiceStateTracker().getNrContextIds().contains(mCid)) { + ratName = RAT_NAME_5G; + } + + log("updateTcpBufferSizes: " + ratName); + + // in the form: "ratname:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max" + String[] configOverride = mPhone.getContext().getResources().getStringArray( + com.android.internal.R.array.config_mobile_tcp_buffers); + for (int i = 0; i < configOverride.length; i++) { + String[] split = configOverride[i].split(":"); + if (ratName.equals(split[0]) && split.length == 2) { + sizes = split[1]; + break; + } + } + + if (sizes == null) { + // no override - use telephony defaults + // doing it this way allows device or carrier to just override the types they + // care about and inherit the defaults for the others. + switch (rilRat) { + case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS: + sizes = TCP_BUFFER_SIZES_GPRS; + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE: + sizes = TCP_BUFFER_SIZES_EDGE; + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS: + sizes = TCP_BUFFER_SIZES_UMTS; + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT: + sizes = TCP_BUFFER_SIZES_1XRTT; + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0: + case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A: + case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B: + sizes = TCP_BUFFER_SIZES_EVDO; + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD: + sizes = TCP_BUFFER_SIZES_EHRPD; + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA: + sizes = TCP_BUFFER_SIZES_HSDPA; + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA: + case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA: + sizes = TCP_BUFFER_SIZES_HSPA; + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_LTE: + // Use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network. + if (RAT_NAME_5G.equals(ratName)) { + sizes = TCP_BUFFER_SIZES_NR; + } else { + sizes = TCP_BUFFER_SIZES_LTE; + } + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA: + // Use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network. + if (RAT_NAME_5G.equals(ratName)) { + sizes = TCP_BUFFER_SIZES_NR; + } else { + sizes = TCP_BUFFER_SIZES_LTE_CA; + } + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP: + sizes = TCP_BUFFER_SIZES_HSPAP; + break; + case ServiceState.RIL_RADIO_TECHNOLOGY_NR: + sizes = TCP_BUFFER_SIZES_NR; + break; + default: + // Leave empty - this will let ConnectivityService use the system default. + break; + } + } + mLinkProperties.setTcpBufferSizes(sizes); + } + + private void updateLinkBandwidthsFromCarrierConfig(int rilRat) { + String ratName = DataConfigManager.getDataConfigNetworkType( + mPhone.getDisplayInfoController().getTelephonyDisplayInfo()); + + if (DBG) log("updateLinkBandwidthsFromCarrierConfig: " + ratName); + + Pair values = mDct.getLinkBandwidthsFromCarrierConfig(ratName); + if (values == null) { + values = new Pair<>(14, 14); + } + mDownlinkBandwidth = values.first; + mUplinkBandwidth = values.second; + } + + + private void updateLinkBandwidthsFromModem(List lceList) { + if (DBG) log("updateLinkBandwidthsFromModem: lceList=" + lceList); + boolean downlinkUpdated = false; + boolean uplinkUpdated = false; + LinkCapacityEstimate lce = lceList.get(0); + // LCE status deprecated in IRadio 1.2, so only check for IRadio < 1.2 + if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_2) + || mPhone.getLceStatus() == RILConstants.LCE_ACTIVE) { + if (lce.getDownlinkCapacityKbps() != LinkCapacityEstimate.INVALID) { + mDownlinkBandwidth = lce.getDownlinkCapacityKbps(); + downlinkUpdated = true; + } + if (lce.getUplinkCapacityKbps() != LinkCapacityEstimate.INVALID) { + mUplinkBandwidth = lce.getUplinkCapacityKbps(); + uplinkUpdated = true; + } + } + + if (!downlinkUpdated || !uplinkUpdated) { + fallBackToCarrierConfigValues(downlinkUpdated, uplinkUpdated); + } + + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this); + } + } + + private void updateLinkBandwidthsFromBandwidthEstimator(int uplinkBandwidthKbps, + int downlinkBandwidthKbps) { + if (DBG) { + log("updateLinkBandwidthsFromBandwidthEstimator, UL= " + + uplinkBandwidthKbps + " DL= " + downlinkBandwidthKbps); + } + boolean downlinkUpdated = false; + boolean uplinkUpdated = false; + if (downlinkBandwidthKbps > 0) { + mDownlinkBandwidth = downlinkBandwidthKbps; + downlinkUpdated = true; + } + if (uplinkBandwidthKbps > 0) { + mUplinkBandwidth = uplinkBandwidthKbps; + uplinkUpdated = true; + } + + if (!downlinkUpdated || !uplinkUpdated) { + fallBackToCarrierConfigValues(downlinkUpdated, uplinkUpdated); + } + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this); + } + } + + private void fallBackToCarrierConfigValues(boolean downlinkUpdated, boolean uplinkUpdated) { + String ratName = ServiceState.rilRadioTechnologyToString(mRilRat); + if (mRilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE && isNRConnected()) { + ratName = mPhone.getServiceState().getNrFrequencyRange() + == ServiceState.FREQUENCY_RANGE_MMWAVE + ? DctConstants.RAT_NAME_NR_NSA_MMWAVE : DctConstants.RAT_NAME_NR_NSA; + } + Pair values = mDct.getLinkBandwidthsFromCarrierConfig(ratName); + if (values != null) { + if (!downlinkUpdated) { + mDownlinkBandwidth = values.first; + } + if (!uplinkUpdated) { + mUplinkBandwidth = values.second; + } + mUplinkBandwidth = Math.min(mUplinkBandwidth, mDownlinkBandwidth); + } + } + + private boolean isBandwidthSourceKey(String source) { + return source.equals(mPhone.getContext().getResources().getString( + com.android.internal.R.string.config_bandwidthEstimateSource)); + } + + /** + * Indicates if this data connection was established for unmetered use only. Note that this + * flag should be populated when data becomes active. And if it is set to true, it can be set to + * false later when we are reevaluating the data connection. But if it is set to false, it + * can never become true later because setting it to true will cause this data connection + * losing some immutable network capabilities, which can cause issues in connectivity service. + */ + private boolean mUnmeteredUseOnly = false; + + /** + * Indicates if this data connection was established for MMS use only. This is true only when + * mobile data is disabled but the user allows sending and receiving MMS messages. If the data + * enabled settings indicate that MMS data is allowed unconditionally, MMS can be sent when data + * is disabled even if it is a metered APN type. + */ + private boolean mMmsUseOnly = false; + + /** + * Indicates if when this connection was established we had a restricted/privileged + * NetworkRequest and needed it to overcome data-enabled limitations. + * + * This flag overrides the APN-based restriction capability, restricting the network + * based on both having a NetworkRequest with restricted AND needing a restricted + * bit to overcome user-disabled status. This allows us to handle the common case + * of having both restricted requests and unrestricted requests for the same apn: + * if conditions require a restricted network to overcome user-disabled then it must + * be restricted, otherwise it is unrestricted (or restricted based on APN type). + * + * This supports a privileged app bringing up a network without general apps having access + * to it when the network is otherwise unavailable (hipri). The first use case is + * pre-paid SIM reprovisioning over internet, where the carrier insists on no traffic + * other than from the privileged carrier-app. + * + * Note that the data connection cannot go from unrestricted to restricted because the + * connectivity service does not support dynamically closing TCP connections at this point. + */ + private boolean mRestrictedNetworkOverride = false; + + /** + * Indicates if this data connection supports enterprise use. Note that this flag should be + * populated when data becomes active. Once it is set, the value cannot be changed because + * setting it will cause this data connection to lose immutable network capabilities, which can + * cause issues in connectivity service. + */ + private boolean mEnterpriseUse = false; + + /** + * Check if this data connection should be restricted. We should call this when data connection + * becomes active, or when we want to re-evaluate the conditions to decide if we need to + * unstrict the data connection. + * + * @return True if this data connection needs to be restricted. + */ + private boolean shouldRestrictNetwork() { + // first, check if there is any network request that containing restricted capability + // (i.e. Do not have NET_CAPABILITY_NOT_RESTRICTED in the request) + boolean isAnyRestrictedRequest = false; + for (ApnContext apnContext : mApnContexts.keySet()) { + if (apnContext.hasRestrictedRequests(true /* exclude DUN */)) { + isAnyRestrictedRequest = true; + break; + } + } + + // If all of the network requests are non-restricted, then we don't need to restrict + // the network. + if (!isAnyRestrictedRequest) { + return false; + } + + // If the network is unmetered, then we don't need to restrict the network because users + // won't be charged anyway. + if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { + return false; + } + + // If the data is disabled, then we need to restrict the network so only privileged apps can + // use the restricted network while data is disabled. + if (!mPhone.getDataEnabledSettings().isDataEnabled()) { + return true; + } + + // If the device is roaming, and the user does not turn on data roaming, then we need to + // restrict the network so only privileged apps can use it. + if (!mDct.getDataRoamingEnabled() && mPhone.getServiceState().getDataRoaming()) { + return true; + } + + // Otherwise we should not restrict the network so anyone who requests can use it. + return false; + } + + /** + * @return True if this data connection should only be used for unmetered purposes. + */ + private boolean isUnmeteredUseOnly() { + // If this data connection is on IWLAN, then it's unmetered and can be used by everyone. + // Should not be for unmetered used only. + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { + return false; + } + + // If data is enabled, this data connection can't be for unmetered used only because + // everyone should be able to use it if: + // 1. Device is not roaming, or + // 2. Device is roaming and data roaming is turned on + if (mPhone.getDataEnabledSettings().isDataEnabled()) { + if (!mPhone.getServiceState().getDataRoaming() || mDct.getDataRoamingEnabled()) { + return false; + } + } + + // The data connection can only be unmetered used only if all attached APN contexts + // attached to this data connection are unmetered. + for (ApnContext apnContext : mApnContexts.keySet()) { + if (ApnSettingUtils.isMeteredApnType(apnContext.getApnTypeBitmask(), mPhone)) { + return false; + } + } + return true; + } + + /** + * @return True if this data connection should only be used for MMS purposes. + */ + private boolean isMmsUseOnly() { + // MMS use only if data is disabled, MMS is allowed unconditionally, and MMS is the only + // APN type for this data connection. + DataEnabledSettings des = mPhone.getDataEnabledSettings(); + boolean mmsAllowedUnconditionally = !des.isDataEnabled() && des.isMmsAlwaysAllowed(); + boolean mmsApnOnly = isApnContextAttached(ApnSetting.TYPE_MMS, true); + return mmsAllowedUnconditionally && mmsApnOnly; + } + + /** + * Check if this data connection supports enterprise use. We call this when the data connection + * becomes active or when we want to reevaluate the conditions to decide if we need to update + * the network agent capabilities. + * + * @return True if this data connection supports enterprise use. + */ + private boolean isEnterpriseUse() { + return mApnContexts.keySet().stream().anyMatch( + ac -> ac.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE); + } + + /** + * Get the network capabilities for this data connection. + * + * @return the {@link NetworkCapabilities} of this data connection. + */ + public NetworkCapabilities getNetworkCapabilities() { + final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); + boolean unmeteredApns = false; + + if (mApnSetting != null && !mEnterpriseUse && !mMmsUseOnly) { + final int[] types = ApnSetting.getApnTypesFromBitmask( + mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask); + for (int type : types) { + if ((!mRestrictedNetworkOverride && mUnmeteredUseOnly) + && ApnSettingUtils.isMeteredApnType(type, mPhone)) { + log("Dropped the metered " + ApnSetting.getApnTypeString(type) + + " type for the unmetered data call."); + continue; + } + switch (type) { + case ApnSetting.TYPE_ALL: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); + break; + } + case ApnSetting.TYPE_DEFAULT: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + break; + } + case ApnSetting.TYPE_MMS: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); + break; + } + case ApnSetting.TYPE_SUPL: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); + break; + } + case ApnSetting.TYPE_DUN: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); + break; + } + case ApnSetting.TYPE_FOTA: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); + break; + } + case ApnSetting.TYPE_IMS: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + break; + } + case ApnSetting.TYPE_CBS: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); + break; + } + case ApnSetting.TYPE_IA: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); + break; + } + case ApnSetting.TYPE_EMERGENCY: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS); + break; + } + case ApnSetting.TYPE_MCX: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MCX); + break; + } + case ApnSetting.TYPE_XCAP: { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP); + break; + } + default: + } + } + + if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { + unmeteredApns = true; + } + } + + // Mark NOT_METERED in the following cases: + // 1. All APNs in the APN settings are unmetered. + // 2. The non-restricted data is intended for unmetered use only. + if (unmeteredApns || (mUnmeteredUseOnly && !mRestrictedNetworkOverride)) { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } else { + builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } + + if (mEnterpriseUse) { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + } + + if (NetworkCapabilitiesUtils.inferRestrictedCapability(builder.build())) { + builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + } + + if (mMmsUseOnly) { + if (ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)) { + log("Adding unmetered capability for the unmetered MMS-only data connection"); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } + log("Adding MMS capability for the MMS-only data connection"); + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); + } + + if (mRestrictedNetworkOverride) { + builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + // don't use dun on restriction-overriden networks. + builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_DUN); + } + + builder.setLinkDownstreamBandwidthKbps(mDownlinkBandwidth); + builder.setLinkUpstreamBandwidthKbps(mUplinkBandwidth); + + builder.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(mSubId).build()); + builder.setSubscriptionIds(Collections.singleton(mSubId)); + + if (!mPhone.getServiceState().getDataRoaming()) { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); + } + + if (!mCongestedOverride) { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); + } + + if (mUnmeteredOverride) { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED); + } + + if (!mIsSuspended) { + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); + } + + final int carrierServicePackageUid = getCarrierServicePackageUid(); + + // TODO(b/205736323): Owner and Admin UIDs currently come from separate data sources. Unify + // them, and remove ArrayUtils.contains() check. + if (carrierServicePackageUid != Process.INVALID_UID + && ArrayUtils.contains(mAdministratorUids, carrierServicePackageUid)) { + builder.setOwnerUid(carrierServicePackageUid); + builder.setAllowedUids(Collections.singleton(carrierServicePackageUid)); + } + builder.setAdministratorUids(mAdministratorUids); + + // Always start with NOT_VCN_MANAGED, then remove if VcnManager indicates this is part of a + // VCN. + builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + final VcnNetworkPolicyResult vcnPolicy = getVcnPolicy(builder.build()); + if (!vcnPolicy.getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)) { + builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); + } + if (!vcnPolicy.getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) { + builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + } + + return builder.build(); + } + + // TODO(b/205736323): Once TelephonyManager#getCarrierServicePackageNameForLogicalSlot() is + // plumbed to CarrierPrivilegesTracker's cache, query the cached UIDs. + private int getFirstUidForPackage(String pkgName) { + if (pkgName == null) { + return Process.INVALID_UID; + } + + List users = mPhone.getContext().getSystemService(UserManager.class).getUsers(); + for (UserInfo user : users) { + int userId = user.getUserHandle().getIdentifier(); + try { + PackageManager pm = mPhone.getContext().getPackageManager(); + + if (pm != null) { + return pm.getPackageUidAsUser(pkgName, userId); + } + } catch (NameNotFoundException exception) { + // Didn't find package. Try other users + Rlog.i( + "DataConnection", + "Unable to find uid for package " + pkgName + " and user " + userId); + } + } + return Process.INVALID_UID; + } + + private int getCarrierServicePackageUid() { + String pkgName = + mPhone.getContext() + .getSystemService(TelephonyManager.class) + .getCarrierServicePackageNameForLogicalSlot(mPhone.getPhoneId()); + + return getFirstUidForPackage(pkgName); + } + + /** + * Check if the this data network is VCN-managed. + * + * @param networkCapabilities The network capabilities of this data network. + * @return The VCN's policy for this DataNetwork. + */ + private VcnNetworkPolicyResult getVcnPolicy(NetworkCapabilities networkCapabilities) { + return mVcnManager.applyVcnNetworkPolicy(networkCapabilities, getLinkProperties()); + } + + /** @return {@code true} if validation is required, {@code false} otherwise. */ + public boolean isValidationRequired() { + final NetworkCapabilities nc = getNetworkCapabilities(); + return nc != null + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); + } + + /** + * @return {@code True} if 464xlat should be skipped. + */ + @VisibleForTesting + public boolean shouldSkip464Xlat() { + switch (mApnSetting.getSkip464Xlat()) { + case Telephony.Carriers.SKIP_464XLAT_ENABLE: + return true; + case Telephony.Carriers.SKIP_464XLAT_DISABLE: + return false; + case Telephony.Carriers.SKIP_464XLAT_DEFAULT: + default: + break; + } + + // As default, return true if ims and no internet + final NetworkCapabilities nc = getNetworkCapabilities(); + return nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS) + && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + } + + /** + * @return {@code} true iff. {@code address} is a literal IPv4 or IPv6 address. + */ + @VisibleForTesting + public static boolean isIpAddress(String address) { + if (address == null) return false; + + // Accept IPv6 addresses (only) in square brackets for compatibility. + if (address.startsWith("[") && address.endsWith("]") && address.indexOf(':') != -1) { + address = address.substring(1, address.length() - 1); + } + return InetAddresses.isNumericAddress(address); + } + + private SetupResult setLinkProperties(DataCallResponse response, + LinkProperties linkProperties) { + // Check if system property dns usable + String propertyPrefix = "net." + response.getInterfaceName() + "."; + String dnsServers[] = new String[2]; + dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1"); + dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2"); + boolean okToUseSystemPropertyDns = isDnsOk(dnsServers); + + SetupResult result; + + // Start with clean network properties and if we have + // a failure we'll clear again at the bottom of this code. + linkProperties.clear(); + + if (response.getCause() == DataFailCause.NONE) { + try { + // set interface name + linkProperties.setInterfaceName(response.getInterfaceName()); + + // set link addresses + if (response.getAddresses().size() > 0) { + for (LinkAddress la : response.getAddresses()) { + if (!la.getAddress().isAnyLocalAddress()) { + if (DBG) { + log("addr/pl=" + la.getAddress() + "/" + + la.getPrefixLength()); + } + linkProperties.addLinkAddress(la); + } + } + } else { + throw new UnknownHostException("no address for ifname=" + + response.getInterfaceName()); + } + + // set dns servers + if (response.getDnsAddresses().size() > 0) { + for (InetAddress dns : response.getDnsAddresses()) { + if (!dns.isAnyLocalAddress()) { + linkProperties.addDnsServer(dns); + } + } + } else if (okToUseSystemPropertyDns) { + for (String dnsAddr : dnsServers) { + dnsAddr = dnsAddr.trim(); + if (dnsAddr.isEmpty()) continue; + InetAddress ia; + try { + ia = InetAddresses.parseNumericAddress(dnsAddr); + } catch (IllegalArgumentException e) { + throw new UnknownHostException("Non-numeric dns addr=" + dnsAddr); + } + if (!ia.isAnyLocalAddress()) { + linkProperties.addDnsServer(ia); + } + } + } else { + throw new UnknownHostException("Empty dns response and no system default dns"); + } + + // set pcscf + if (response.getPcscfAddresses().size() > 0) { + for (InetAddress pcscf : response.getPcscfAddresses()) { + linkProperties.addPcscfServer(pcscf); + } + } + + for (InetAddress gateway : response.getGatewayAddresses()) { + int mtu = gateway instanceof java.net.Inet6Address ? response.getMtuV6() + : response.getMtuV4(); + // Allow 0.0.0.0 or :: as a gateway; + // this indicates a point-to-point interface. + linkProperties.addRoute(new RouteInfo(null, gateway, null, + RouteInfo.RTN_UNICAST, mtu)); + } + + // set interface MTU + // this may clobber the setting read from the APN db, but that's ok + // TODO: remove once LinkProperties#setMtu is deprecated + linkProperties.setMtu(response.getMtu()); + + result = SetupResult.SUCCESS; + } catch (UnknownHostException e) { + log("setLinkProperties: UnknownHostException " + e); + result = SetupResult.ERROR_INVALID_ARG; + } + } else { + result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; + } + + // An error occurred so clear properties + if (result != SetupResult.SUCCESS) { + if (DBG) { + log("setLinkProperties: error clearing LinkProperties status=" + + response.getCause() + " result=" + result); + } + linkProperties.clear(); + } + + return result; + } + + /** + * Initialize connection, this will fail if the + * apnSettings are not compatible. + * + * @param cp the Connection parameters + * @return true if initialization was successful. + */ + private boolean initConnection(ConnectionParams cp) { + ApnContext apnContext = cp.mApnContext; + if (mApnSetting == null) { + // Only change apn setting if it isn't set, it will + // only NOT be set only if we're in DcInactiveState. + mApnSetting = apnContext.getApnSetting(); + } + if (mApnSetting == null || (!mApnSetting.canHandleType(apnContext.getApnTypeBitmask()) + && apnContext.getApnTypeBitmask() != ApnSetting.TYPE_ENTERPRISE)) { + if (DBG) { + log("initConnection: incompatible apnSetting in ConnectionParams cp=" + cp + + " dc=" + DataConnection.this); + } + return false; + } + mTag += 1; + mConnectionParams = cp; + mConnectionParams.mTag = mTag; + + // always update the ConnectionParams with the latest or the + // connectionGeneration gets stale + mApnContexts.put(apnContext, cp); + + if (DBG) { + log("initConnection: " + + " RefCount=" + mApnContexts.size() + + " mApnList=" + mApnContexts + + " mConnectionParams=" + mConnectionParams); + } + return true; + } + + /** + * The parent state for all other states. + */ + private class DcDefaultState extends State { + @Override + public void enter() { + if (DBG) log("DcDefaultState: enter"); + + // Register for DRS or RAT change + mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged( + mTransportType, getHandler(), + DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, null); + + mPhone.getServiceStateTracker().registerForDataRoamingOn(getHandler(), + DataConnection.EVENT_DATA_CONNECTION_ROAM_ON, null); + mPhone.getServiceStateTracker().registerForDataRoamingOff(getHandler(), + DataConnection.EVENT_DATA_CONNECTION_ROAM_OFF, null, true); + mPhone.getServiceStateTracker().registerForNrStateChanged(getHandler(), + DataConnection.EVENT_NR_STATE_CHANGED, null); + mPhone.getServiceStateTracker().registerForNrFrequencyChanged(getHandler(), + DataConnection.EVENT_NR_FREQUENCY_CHANGED, null); + mPhone.getServiceStateTracker().registerForCssIndicatorChanged(getHandler(), + DataConnection.EVENT_CSS_INDICATOR_CHANGED, null); + if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR_KEY)) { + mPhone.getLinkBandwidthEstimator().registerForBandwidthChanged(getHandler(), + DataConnection.EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE, null); + } + + // Add ourselves to the list of data connections + mDcController.addDc(DataConnection.this); + } + @Override + public void exit() { + if (DBG) log("DcDefaultState: exit"); + + // Unregister for DRS or RAT change. + mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged( + mTransportType, getHandler()); + + mPhone.getServiceStateTracker().unregisterForDataRoamingOn(getHandler()); + mPhone.getServiceStateTracker().unregisterForDataRoamingOff(getHandler()); + mPhone.getServiceStateTracker().unregisterForNrStateChanged(getHandler()); + mPhone.getServiceStateTracker().unregisterForNrFrequencyChanged(getHandler()); + mPhone.getServiceStateTracker().unregisterForCssIndicatorChanged(getHandler()); + if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR_KEY)) { + mPhone.getLinkBandwidthEstimator().unregisterForBandwidthChanged(getHandler()); + } + + // Remove ourselves from the DC lists + mDcController.removeDc(DataConnection.this); + + if (mAc != null) { + mAc.disconnected(); + mAc = null; + } + mApnContexts.clear(); + mReconnectIntent = null; + mDct = null; + mApnSetting = null; + mPhone = null; + mDataServiceManager = null; + mLinkProperties = null; + mLastFailCause = DataFailCause.NONE; + mUserData = null; + mDcController = null; + mDcTesterFailBringUpAll = null; + } + + @Override + public boolean processMessage(Message msg) { + boolean retVal = HANDLED; + + if (VDBG) { + log("DcDefault msg=" + getWhatToString(msg.what) + + " RefCount=" + mApnContexts.size()); + } + switch (msg.what) { + case EVENT_RESET: + if (VDBG) log("DcDefaultState: msg.what=REQ_RESET"); + transitionTo(mInactiveState); + break; + case EVENT_CONNECT: + if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected"); + ConnectionParams cp = (ConnectionParams) msg.obj; + notifyConnectCompleted(cp, DataFailCause.UNKNOWN, + DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); + break; + + case EVENT_DISCONNECT: + case EVENT_DISCONNECT_ALL: + case EVENT_REEVALUATE_RESTRICTED_STATE: + if (DBG) { + log("DcDefaultState deferring msg.what=" + getWhatToString(msg.what) + + " RefCount=" + mApnContexts.size()); + } + deferMessage(msg); + break; + case EVENT_TEAR_DOWN_NOW: + if (DBG) log("DcDefaultState EVENT_TEAR_DOWN_NOW"); + mDataServiceManager.deactivateDataCall(mCid, DataService.REQUEST_REASON_NORMAL, + null); + mDataCallSessionStats.setDeactivateDataCallReason( + DataService.REQUEST_REASON_NORMAL); + break; + case EVENT_LOST_CONNECTION: + if (DBG) { + String s = "DcDefaultState ignore EVENT_LOST_CONNECTION" + + " tag=" + msg.arg1 + ":mTag=" + mTag; + logAndAddLogRec(s); + } + break; + case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: + AsyncResult ar = (AsyncResult)msg.obj; + Pair drsRatPair = (Pair)ar.result; + mDataRegState = drsRatPair.first; + updateTcpBufferSizes(drsRatPair.second); + if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { + updateLinkBandwidthsFromCarrierConfig(drsRatPair.second); + } + mRilRat = drsRatPair.second; + if (DBG) { + log("DcDefaultState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED" + + " regState=" + ServiceState.rilServiceStateToString(mDataRegState) + + " RAT=" + ServiceState.rilRadioTechnologyToString(mRilRat)); + } + mDataCallSessionStats.onDrsOrRatChanged( + ServiceState.rilRadioTechnologyToNetworkType(mRilRat)); + break; + + case EVENT_START_HANDOVER: //calls startHandover() + if (DBG) { + log("DcDefaultState: EVENT_START_HANDOVER not expected."); + } + Consumer r = (Consumer) msg.obj; + r.accept(DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + break; + case EVENT_START_HANDOVER_ON_TARGET: + if (DBG) { + log("DcDefaultState: EVENT_START_HANDOVER not expected, but will " + + "clean up, result code: " + + DataServiceCallback.resultCodeToString(msg.arg1)); + } + ((Consumer) msg.obj).accept(false /* is in correct state*/); + break; + case EVENT_CANCEL_HANDOVER: + // We don't need to do anything in this case + if (DBG) { + log("DcDefaultState: EVENT_CANCEL_HANDOVER resultCode=" + + DataServiceCallback.resultCodeToString(msg.arg1)); + } + break; + case EVENT_RELEASE_PDU_SESSION_ID: { + // We do the same thing in all state in order to preserve the existing workflow + final AsyncResult asyncResult = (AsyncResult) msg.obj; + if (asyncResult == null) { + loge("EVENT_RELEASE_PDU_SESSION_ID: asyncResult is null!"); + } else { + if (msg.obj != null) { + if (DBG) logd("EVENT_RELEASE_PDU_SESSION_ID: id released"); + Runnable runnable = (Runnable) asyncResult.userObj; + runnable.run(); + } else { + loge("EVENT_RELEASE_PDU_SESSION_ID: no runnable set"); + } + } + retVal = HANDLED; + break; + } + case EVENT_ALLOCATE_PDU_SESSION_ID: { + // We do the same thing in all state in order to preserve the existing workflow + final AsyncResult asyncResult = (AsyncResult) msg.obj; + if (asyncResult == null) { + loge("EVENT_ALLOCATE_PDU_SESSION_ID: asyncResult is null!"); + } else { + Consumer onAllocated = (Consumer) asyncResult.userObj; + if (asyncResult.exception != null) { + loge("EVENT_ALLOCATE_PDU_SESSION_ID: exception", + asyncResult.exception); + onAllocated.accept(PDU_SESSION_ID_NOT_SET); + } else if (asyncResult.result == null) { + loge("EVENT_ALLOCATE_PDU_SESSION_ID: result null, no id"); + onAllocated.accept(PDU_SESSION_ID_NOT_SET); + } else { + int psi = (int) asyncResult.result; + if (DBG) logd("EVENT_ALLOCATE_PDU_SESSION_ID: psi=" + psi); + onAllocated.accept(psi); + } + } + retVal = HANDLED; + break; + } + default: + if (DBG) { + log("DcDefaultState: ignore msg.what=" + getWhatToString(msg.what)); + } + break; + } + + return retVal; + } + } + + private void updateSuspendState() { + if (mNetworkAgent == null) { + Rlog.d(getName(), "Setting suspend state without a NetworkAgent"); + } + + boolean newSuspendedState = false; + // Data can only be (temporarily) suspended while data is in active state + if (getCurrentState() == mActiveState) { + // Never set suspended for emergency apn. Emergency data connection + // can work while device is not in service. + if (mApnSetting != null && mApnSetting.isEmergencyApn()) { + newSuspendedState = false; + // If we are not in service, change to suspended. + } else if (mDataRegState != ServiceState.STATE_IN_SERVICE) { + newSuspendedState = true; + // Check voice/data concurrency. + } else if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { + newSuspendedState = mPhone.getCallTracker().getState() != PhoneConstants.State.IDLE; + } + } + + // Only notify when there is a change. + if (mIsSuspended != newSuspendedState) { + mIsSuspended = newSuspendedState; + + // If data connection is active, we need to notify the new data connection state + // changed event reflecting the latest suspended state. + if (isActive()) { + notifyDataConnectionState(); + } + } + } + + private void notifyDataConnectionState() { + // The receivers of this have no way to differentiate between default and enterprise + // connections. Do not notify for enterprise. + if (!isEnterpriseUse()) { + mPhone.notifyDataConnection(getPreciseDataConnectionState()); + } else { + log("notifyDataConnectionState: Skipping for enterprise; state=" + getState()); + } + } + + private DcDefaultState mDefaultState = new DcDefaultState(); + + private int getApnTypeBitmask() { + return isEnterpriseUse() ? ApnSetting.TYPE_ENTERPRISE : + mApnSetting != null ? mApnSetting.getApnTypeBitmask() : 0; + } + + private boolean canHandleDefault() { + return !isEnterpriseUse() && mApnSetting != null + ? mApnSetting.canHandleType(ApnSetting.TYPE_DEFAULT) : false; + } + + /** + * The state machine is inactive and expects a EVENT_CONNECT. + */ + private class DcInactiveState extends State { + // Inform all contexts we've failed connecting + public void setEnterNotificationParams(ConnectionParams cp, @DataFailureCause int cause, + @HandoverFailureMode int handoverFailureMode) { + if (VDBG) log("DcInactiveState: setEnterNotificationParams cp,cause"); + mConnectionParams = cp; + mDisconnectParams = null; + mDcFailCause = cause; + mHandoverFailureMode = handoverFailureMode; + } + + // Inform all contexts we've failed disconnected + public void setEnterNotificationParams(DisconnectParams dp) { + if (VDBG) log("DcInactiveState: setEnterNotificationParams dp"); + mConnectionParams = null; + mDisconnectParams = dp; + mDcFailCause = DataFailCause.NONE; + } + + // Inform all contexts of the failure cause + public void setEnterNotificationParams(@DataFailureCause int cause) { + mConnectionParams = null; + mDisconnectParams = null; + mDcFailCause = cause; + } + + @Override + public void enter() { + mTag += 1; + if (DBG) log("DcInactiveState: enter() mTag=" + mTag); + TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, + TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__INACTIVE, + mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); + mDataCallSessionStats.onDataCallDisconnected(mDcFailCause); + if (mHandoverState == HANDOVER_STATE_BEING_TRANSFERRED) { + // This is from source data connection to set itself's state + setHandoverState(HANDOVER_STATE_COMPLETED); + } + + // Check for dangling agent. Ideally the handover source agent should be null if + // handover process is smooth. When it's not null, that means handover failed. The + // agent was not successfully transferred to the new data connection. We should + // gracefully notify connectivity service the network was disconnected. + if (mHandoverSourceNetworkAgent != null) { + DataConnection sourceDc = mHandoverSourceNetworkAgent.getDataConnection(); + if (sourceDc != null) { + // If the source data connection still owns this agent, then just reset the + // handover state back to idle because handover is already failed. + mHandoverLocalLog.log( + "Handover failed. Reset the source dc " + sourceDc.getName() + + " state to idle"); + sourceDc.cancelHandover(); + } else { + // The agent is now a dangling agent. No data connection owns this agent. + // Gracefully notify connectivity service disconnected. + mHandoverLocalLog.log( + "Handover failed and dangling agent found."); + mHandoverSourceNetworkAgent.acquireOwnership( + DataConnection.this, mTransportType); + log("Cleared dangling network agent. " + mHandoverSourceNetworkAgent); + mHandoverSourceNetworkAgent.unregister(DataConnection.this); + mHandoverSourceNetworkAgent.releaseOwnership(DataConnection.this); + } + mHandoverSourceNetworkAgent = null; + } + + if (mConnectionParams != null) { + if (DBG) { + log("DcInactiveState: enter notifyConnectCompleted +ALL failCause=" + + DataFailCause.toString(mDcFailCause)); + } + notifyConnectCompleted(mConnectionParams, mDcFailCause, mHandoverFailureMode, + true); + } + if (mDisconnectParams != null) { + if (DBG) { + log("DcInactiveState: enter notifyDisconnectCompleted +ALL failCause=" + + DataFailCause.toString(mDcFailCause)); + } + notifyDisconnectCompleted(mDisconnectParams, true); + } + if (mDisconnectParams == null && mConnectionParams == null + && mDcFailCause != DataFailCause.NONE) { + if (DBG) { + log("DcInactiveState: enter notifyAllDisconnectCompleted failCause=" + + DataFailCause.toString(mDcFailCause)); + } + notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE, + DataFailCause.toString(mDcFailCause)); + } + + // Remove ourselves from cid mapping, before clearSettings + mDcController.removeActiveDcByCid(DataConnection.this); + + // For the first time entering here (idle state before setup), do not notify + // disconnected state. Only notify data connection disconnected for data that is + // actually moving from disconnecting to disconnected, or setup failed. In both cases, + // APN setting will not be null. + if (mApnSetting != null) { + notifyDataConnectionState(); + } + clearSettings(); + } + + @Override + public void exit() { + } + + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case EVENT_RESET: + case EVENT_REEVALUATE_RESTRICTED_STATE: + if (DBG) { + log("DcInactiveState: msg.what=" + getWhatToString(msg.what) + + ", ignore we're already done"); + } + return HANDLED; + case EVENT_CONNECT: + if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT"); + ConnectionParams cp = (ConnectionParams) msg.obj; + + if (!initConnection(cp)) { + log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed"); + notifyConnectCompleted(cp, DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER, + DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); + transitionTo(mInactiveState); + return HANDLED; + } + + int cause = connect(cp); + if (cause != DataFailCause.NONE) { + log("DcInactiveState: msg.what=EVENT_CONNECT connect failed"); + notifyConnectCompleted(cp, cause, + DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); + transitionTo(mInactiveState); + return HANDLED; + } + + if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + mSubId = cp.mSubId; + } + + transitionTo(mActivatingState); + return HANDLED; + case EVENT_DISCONNECT: + if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT"); + notifyDisconnectCompleted((DisconnectParams)msg.obj, false); + return HANDLED; + case EVENT_DISCONNECT_ALL: + if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL"); + notifyDisconnectCompleted((DisconnectParams)msg.obj, false); + return HANDLED; + default: + if (VDBG) { + log("DcInactiveState not handled msg.what=" + getWhatToString(msg.what)); + } + return NOT_HANDLED; + } + } + } + private DcInactiveState mInactiveState = new DcInactiveState(); + + /** + * The state machine is activating a connection. + */ + private class DcActivatingState extends State { + @Override + public void enter() { + int apnTypeBitmask = getApnTypeBitmask(); + TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, + TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__ACTIVATING, + mPhone.getPhoneId(), mId, apnTypeBitmask, canHandleDefault()); + setHandoverState(HANDOVER_STATE_IDLE); + // restricted evaluation depends on network requests from apnContext. The evaluation + // should happen once entering connecting state rather than active state because it's + // possible that restricted network request can be released during the connecting window + // and if we wait for connection established, then we might mistakenly + // consider it as un-restricted. ConnectivityService then will immediately + // tear down the connection through networkAgent unwanted callback if all requests for + // this connection are going away. + mRestrictedNetworkOverride = shouldRestrictNetwork(); + + CarrierPrivilegesTracker carrierPrivTracker = mPhone.getCarrierPrivilegesTracker(); + if (carrierPrivTracker != null) { + carrierPrivTracker.registerCarrierPrivilegesListener( + getHandler(), EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED, null); + } + notifyDataConnectionState(); + mDataCallSessionStats.onSetupDataCall(apnTypeBitmask); + } + @Override + public boolean processMessage(Message msg) { + boolean retVal; + AsyncResult ar; + ConnectionParams cp; + + if (DBG) log("DcActivatingState: msg=" + msgToString(msg)); + switch (msg.what) { + case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: + case EVENT_CONNECT: + // Activating can't process until we're done. + deferMessage(msg); + retVal = HANDLED; + break; + + case EVENT_SETUP_DATA_CONNECTION_DONE: + cp = (ConnectionParams) msg.obj; + + DataCallResponse dataCallResponse = + msg.getData().getParcelable(DataServiceManager.DATA_CALL_RESPONSE); + SetupResult result = onSetupConnectionCompleted(msg.arg1, dataCallResponse, cp); + if (result != SetupResult.ERROR_STALE) { + if (mConnectionParams != cp) { + loge("DcActivatingState: WEIRD mConnectionsParams:"+ mConnectionParams + + " != cp:" + cp); + } + } + if (DBG) { + log("DcActivatingState onSetupConnectionCompleted result=" + result + + " dc=" + DataConnection.this); + } + ApnContext.requestLog( + cp.mApnContext, "onSetupConnectionCompleted result=" + result); + + if (result != SetupResult.SUCCESS) { + releasePduSessionId(() -> DataConnection.this + .setPduSessionId(PDU_SESSION_ID_NOT_SET)); + } + + switch (result) { + case SUCCESS: + // All is well + mDcFailCause = DataFailCause.NONE; + transitionTo(mActiveState); + break; + case ERROR_RADIO_NOT_AVAILABLE: + // Vendor ril rejected the command and didn't connect. + // Transition to inactive but send notifications after + // we've entered the mInactive state. + mInactiveState.setEnterNotificationParams(cp, result.mFailCause, + DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); + transitionTo(mInactiveState); + break; + case ERROR_DUPLICATE_CID: + // TODO (b/180988471): Properly handle the case when an existing cid is + // returned by tearing down the network agent if enterprise changed. + long retry = RetryManager.NO_SUGGESTED_RETRY_DELAY; + if (cp.mApnContext != null) { + retry = RetryManager.NO_RETRY; + mDct.getDataThrottler().setRetryTime( + cp.mApnContext.getApnTypeBitmask(), + retry, DcTracker.REQUEST_TYPE_NORMAL); + } + String logStr = "DcActivatingState: " + + DataFailCause.toString(result.mFailCause) + + " retry=" + retry; + if (DBG) log(logStr); + ApnContext.requestLog(cp.mApnContext, logStr); + mInactiveState.setEnterNotificationParams(cp, result.mFailCause, + DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); + transitionTo(mInactiveState); + break; + case ERROR_NO_DEFAULT_CONNECTION: + // TODO (b/180988471): Properly handle the case when a default data + // connection doesn't exist (tear down connection and retry). + // Currently, this just tears down the connection without retry. + if (DBG) log("DcActivatingState: NO_DEFAULT_DATA"); + case ERROR_INVALID_ARG: + // The addresses given from the RIL are bad + tearDownData(cp); + transitionTo(mDisconnectingErrorCreatingConnection); + break; + case ERROR_DATA_SERVICE_SPECIFIC_ERROR: + + // Retrieve the suggested retry delay from the modem and save it. + // If the modem want us to retry the current APN again, it will + // suggest a positive delay value (in milliseconds). Otherwise we'll get + // NO_SUGGESTED_RETRY_DELAY here. + + long delay = getSuggestedRetryDelay(dataCallResponse); + long retryTime = RetryManager.NO_SUGGESTED_RETRY_DELAY; + if (delay == RetryManager.NO_RETRY) { + retryTime = RetryManager.NO_RETRY; + } else if (delay >= 0) { + retryTime = SystemClock.elapsedRealtime() + delay; + } + int newRequestType = DcTracker.calculateNewRetryRequestType( + mHandoverFailureMode, cp.mRequestType, mDcFailCause); + mDct.getDataThrottler().setRetryTime(getApnTypeBitmask(), + retryTime, newRequestType); + + String str = "DcActivatingState: ERROR_DATA_SERVICE_SPECIFIC_ERROR " + + " delay=" + delay + + " result=" + result + + " result.isRadioRestartFailure=" + + DataFailCause.isRadioRestartFailure(mPhone.getContext(), + result.mFailCause, mPhone.getSubId()) + + " isPermanentFailure=" + + mDct.isPermanentFailure(result.mFailCause); + if (DBG) log(str); + ApnContext.requestLog(cp.mApnContext, str); + + // Save the cause. DcTracker.onDataSetupComplete will check this + // failure cause and determine if we need to retry this APN later + // or not. + mInactiveState.setEnterNotificationParams(cp, result.mFailCause, + dataCallResponse != null + ? dataCallResponse.getHandoverFailureMode() + : DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); + transitionTo(mInactiveState); + break; + case ERROR_STALE: + loge("DcActivatingState: stale EVENT_SETUP_DATA_CONNECTION_DONE" + + " tag:" + cp.mTag + " != mTag:" + mTag); + break; + default: + throw new RuntimeException("Unknown SetupResult, should not happen"); + } + retVal = HANDLED; + mDataCallSessionStats + .onSetupDataCallResponse(dataCallResponse, + ServiceState.rilRadioTechnologyToNetworkType(cp.mRilRat), + getApnTypeBitmask(), mApnSetting.getProtocol(), + result.mFailCause); + break; + case EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED: + AsyncResult asyncResult = (AsyncResult) msg.obj; + int[] administratorUids = (int[]) asyncResult.result; + mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length); + retVal = HANDLED; + break; + case EVENT_START_HANDOVER_ON_TARGET: + //called after startHandover on target transport + ((Consumer) msg.obj).accept(true /* is in correct state*/); + retVal = HANDLED; + break; + case EVENT_CANCEL_HANDOVER: + transitionTo(mInactiveState); + retVal = HANDLED; + break; + default: + if (VDBG) { + log("DcActivatingState not handled msg.what=" + + getWhatToString(msg.what) + " RefCount=" + mApnContexts.size()); + } + retVal = NOT_HANDLED; + break; + } + return retVal; + } + } + private DcActivatingState mActivatingState = new DcActivatingState(); + + /** + * The state machine is connected, expecting an EVENT_DISCONNECT. + */ + private class DcActiveState extends State { + + @Override public void enter() { + if (DBG) log("DcActiveState: enter dc=" + DataConnection.this); + TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, + TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__ACTIVE, + mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); + // If we were retrying there maybe more than one, otherwise they'll only be one. + notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE, + Phone.REASON_CONNECTED); + + mPhone.getCallTracker().registerForVoiceCallStarted(getHandler(), + DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED, null); + mPhone.getCallTracker().registerForVoiceCallEnded(getHandler(), + DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED, null); + + // If the EVENT_CONNECT set the current max retry restore it here + // if it didn't then this is effectively a NOP. + mDcController.addActiveDcByCid(DataConnection.this); + + updateTcpBufferSizes(mRilRat); + updateLinkBandwidthsFromCarrierConfig(mRilRat); + + final NetworkAgentConfig.Builder configBuilder = new NetworkAgentConfig.Builder(); + configBuilder.setLegacyType(ConnectivityManager.TYPE_MOBILE); + configBuilder.setLegacyTypeName(NETWORK_TYPE); + int networkType = getNetworkType(); + configBuilder.setLegacySubType(networkType); + configBuilder.setLegacySubTypeName(TelephonyManager.getNetworkTypeName(networkType)); + configBuilder.setLegacyExtraInfo(mApnSetting.getApnName()); + final CarrierSignalAgent carrierSignalAgent = mPhone.getCarrierSignalAgent(); + if (carrierSignalAgent.hasRegisteredReceivers(TelephonyManager + .ACTION_CARRIER_SIGNAL_REDIRECTED)) { + // carrierSignal Receivers will place the carrier-specific provisioning notification + configBuilder.setProvisioningNotificationEnabled(false); + } + + final String subscriberId = mPhone.getSubscriberId(); + if (!TextUtils.isEmpty(subscriberId)) { + configBuilder.setSubscriberId(subscriberId); + } + + // set skip464xlat if it is not default otherwise + if (shouldSkip464Xlat()) { + configBuilder.setNat64DetectionEnabled(false); + } + + mUnmeteredUseOnly = isUnmeteredUseOnly(); + mMmsUseOnly = isMmsUseOnly(); + mEnterpriseUse = isEnterpriseUse(); + + if (DBG) { + log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride + + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly + + ", mMmsUseOnly = " + mMmsUseOnly + + ", mEnterpriseUse = " + mEnterpriseUse); + } + + // Always register a VcnNetworkPolicyChangeListener, regardless of whether this is a + // handover + // or new Network. + mVcnManager.addVcnNetworkPolicyChangeListener( + new HandlerExecutor(getHandler()), mVcnPolicyChangeListener); + + if (mConnectionParams != null + && mConnectionParams.mRequestType == REQUEST_TYPE_HANDOVER) { + // If this is a data setup for handover, we need to reuse the existing network agent + // instead of creating a new one. This should be transparent to connectivity + // service. + DcTracker dcTracker = mPhone.getDcTracker(getHandoverSourceTransport()); + DataConnection dc = dcTracker.getDataConnectionByApnType( + mConnectionParams.mApnContext.getApnType()); + // It's possible that the source data connection has been disconnected by the modem + // already. If not, set its handover state to completed. + if (dc != null) { + // Transfer network agent from the original data connection as soon as the + // new handover data connection is connected. + dc.setHandoverState(HANDOVER_STATE_COMPLETED); + } + + if (mHandoverSourceNetworkAgent != null) { + String logStr = "Transfer network agent " + mHandoverSourceNetworkAgent.getTag() + + " successfully."; + log(logStr); + mHandoverLocalLog.log(logStr); + mNetworkAgent = mHandoverSourceNetworkAgent; + mNetworkAgent.acquireOwnership(DataConnection.this, mTransportType); + + // TODO: Should evaluate mDisabledApnTypeBitMask again after handover. We don't + // do it now because connectivity service does not support dynamically removing + // immutable capabilities. + + mNetworkAgent.updateLegacySubtype(DataConnection.this); + // Update the capability after handover + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); + mHandoverSourceNetworkAgent = null; + } else { + String logStr = "Failed to get network agent from original data connection"; + loge(logStr); + mHandoverLocalLog.log(logStr); + return; + } + } else { + mScore = calculateScore(); + final NetworkFactory factory = PhoneFactory.getNetworkFactory( + mPhone.getPhoneId()); + final NetworkProvider provider = (null == factory) ? null : factory.getProvider(); + + mDisabledApnTypeBitMask |= getDisallowedApnTypes(); + updateLinkPropertiesHttpProxy(); + mNetworkAgent = new DcNetworkAgent(DataConnection.this, mPhone, mScore, + configBuilder.build(), provider, mTransportType); + + VcnNetworkPolicyResult policyResult = + mVcnManager.applyVcnNetworkPolicy( + getNetworkCapabilities(), getLinkProperties()); + if (policyResult.isTeardownRequested()) { + tearDownAll( + Phone.REASON_VCN_REQUESTED_TEARDOWN, + DcTracker.RELEASE_TYPE_DETACH, + null /* onCompletedMsg */); + } else { + // All network agents start out in CONNECTING mode, but DcNetworkAgents are + // created when the network is already connected. Hence, send the connected + // notification immediately. + mNetworkAgent.markConnected(); + } + + // The network agent is always created with NOT_SUSPENDED capability, but the + // network might be already out of service (or voice call is ongoing) just right + // before data connection is created. Connectivity service would not allow a network + // created with suspended state, so we create a non-suspended network first, and + // then immediately evaluate the suspended state. + sendMessage(obtainMessage(EVENT_UPDATE_SUSPENDED_STATE)); + } + + // The qos parameters are set when the call is connected + syncQosToNetworkAgent(); + + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + mPhone.mCi.registerForNattKeepaliveStatus( + getHandler(), DataConnection.EVENT_KEEPALIVE_STATUS, null); + mPhone.mCi.registerForLceInfo( + getHandler(), DataConnection.EVENT_LINK_CAPACITY_CHANGED, null); + } + notifyDataConnectionState(); + TelephonyMetrics.getInstance().writeRilDataCallEvent(mPhone.getPhoneId(), + mCid, getApnTypeBitmask(), RilDataCall.State.CONNECTED); + } + + @Override + public void exit() { + if (DBG) log("DcActiveState: exit dc=" + this); + mPhone.getCallTracker().unregisterForVoiceCallStarted(getHandler()); + mPhone.getCallTracker().unregisterForVoiceCallEnded(getHandler()); + + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + mPhone.mCi.unregisterForNattKeepaliveStatus(getHandler()); + mPhone.mCi.unregisterForLceInfo(getHandler()); + } + + // If we are still owning this agent, then we should inform connectivity service the + // data connection is disconnected. There is one exception that we shouldn't unregister, + // which is when IWLAN handover is ongoing. Instead of unregistering, the agent will + // be transferred to the new data connection on the other transport. + if (mNetworkAgent != null) { + syncQosToNetworkAgent(); + if (mHandoverState == HANDOVER_STATE_IDLE) { + mNetworkAgent.unregister(DataConnection.this); + } + mNetworkAgent.releaseOwnership(DataConnection.this); + } + mNetworkAgent = null; + + TelephonyMetrics.getInstance().writeRilDataCallEvent(mPhone.getPhoneId(), + mCid, getApnTypeBitmask(), RilDataCall.State.DISCONNECTED); + + mVcnManager.removeVcnNetworkPolicyChangeListener(mVcnPolicyChangeListener); + + CarrierPrivilegesTracker carrierPrivTracker = mPhone.getCarrierPrivilegesTracker(); + if (carrierPrivTracker != null) { + carrierPrivTracker.unregisterCarrierPrivilegesListener(getHandler()); + } + } + + @Override + public boolean processMessage(Message msg) { + boolean retVal; + + switch (msg.what) { + case EVENT_CONNECT: { + ConnectionParams cp = (ConnectionParams) msg.obj; + // either add this new apn context to our set or + // update the existing cp with the latest connection generation number + mApnContexts.put(cp.mApnContext, cp); + // TODO (b/118347948): evaluate if it's still needed after assigning + // different scores to different Cellular network. + mDisabledApnTypeBitMask &= ~cp.mApnContext.getApnTypeBitmask(); + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + if (DBG) { + log("DcActiveState: EVENT_CONNECT cp=" + cp + " dc=" + DataConnection.this); + } + notifyConnectCompleted(cp, DataFailCause.NONE, + DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); + retVal = HANDLED; + break; + } + case EVENT_DISCONNECT: { + DisconnectParams dp = (DisconnectParams) msg.obj; + if (DBG) { + log("DcActiveState: EVENT_DISCONNECT dp=" + dp + + " dc=" + DataConnection.this); + } + if (mApnContexts.containsKey(dp.mApnContext)) { + if (DBG) { + log("DcActiveState msg.what=EVENT_DISCONNECT RefCount=" + + mApnContexts.size()); + } + + if (mApnContexts.size() == 1) { + mApnContexts.clear(); + mDisconnectParams = dp; + mConnectionParams = null; + dp.mTag = mTag; + tearDownData(dp); + transitionTo(mDisconnectingState); + } else { + mApnContexts.remove(dp.mApnContext); + // TODO (b/118347948): evaluate if it's still needed after assigning + // different scores to different Cellular network. + mDisabledApnTypeBitMask |= dp.mApnContext.getApnTypeBitmask(); + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + notifyDisconnectCompleted(dp, false); + } + } else { + log("DcActiveState ERROR no such apnContext=" + dp.mApnContext + + " in this dc=" + DataConnection.this); + notifyDisconnectCompleted(dp, false); + } + retVal = HANDLED; + break; + } + case EVENT_DISCONNECT_ALL: { + if (DBG) { + log("DcActiveState EVENT_DISCONNECT clearing apn contexts," + + " dc=" + DataConnection.this); + } + DisconnectParams dp = (DisconnectParams) msg.obj; + mDisconnectParams = dp; + mConnectionParams = null; + dp.mTag = mTag; + tearDownData(dp); + transitionTo(mDisconnectingState); + retVal = HANDLED; + break; + } + case EVENT_LOST_CONNECTION: { + if (DBG) { + log("DcActiveState EVENT_LOST_CONNECTION dc=" + DataConnection.this); + } + + mInactiveState.setEnterNotificationParams(DataFailCause.LOST_CONNECTION); + transitionTo(mInactiveState); + retVal = HANDLED; + break; + } + case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + Pair drsRatPair = (Pair) ar.result; + mDataRegState = drsRatPair.first; + updateTcpBufferSizes(drsRatPair.second); + if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { + updateLinkBandwidthsFromCarrierConfig(drsRatPair.second); + } + mRilRat = drsRatPair.second; + if (DBG) { + log("DcActiveState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED" + + " drs=" + mDataRegState + + " mRilRat=" + mRilRat); + } + updateSuspendState(); + if (mNetworkAgent != null) { + mNetworkAgent.updateLegacySubtype(DataConnection.this); + // The new suspended state will be passed through connectivity service + // through NET_CAPABILITY_NOT_SUSPENDED. + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); + } + retVal = HANDLED; + mDataCallSessionStats.onDrsOrRatChanged( + ServiceState.rilRadioTechnologyToNetworkType(mRilRat)); + break; + } + case EVENT_NR_FREQUENCY_CHANGED: + // fallthrough + case EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED: + if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { + updateLinkBandwidthsFromCarrierConfig(mRilRat); + } + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + } + retVal = HANDLED; + break; + case EVENT_DATA_CONNECTION_METEREDNESS_CHANGED: + boolean isUnmetered = (boolean) msg.obj; + if (isUnmetered == mUnmeteredOverride) { + retVal = HANDLED; + break; + } + mUnmeteredOverride = isUnmetered; + if (mNetworkAgent != null) { + mNetworkAgent.updateLegacySubtype(DataConnection.this); + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + } + retVal = HANDLED; + break; + case EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED: + boolean isCongested = (boolean) msg.obj; + if (isCongested == mCongestedOverride) { + retVal = HANDLED; + break; + } + mCongestedOverride = isCongested; + if (mNetworkAgent != null) { + mNetworkAgent.updateLegacySubtype(DataConnection.this); + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + } + retVal = HANDLED; + break; + case EVENT_DATA_CONNECTION_ROAM_ON: + case EVENT_DATA_CONNECTION_ROAM_OFF: { + if (mNetworkAgent != null) { + mNetworkAgent.updateLegacySubtype(DataConnection.this); + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + } + retVal = HANDLED; + break; + } + case EVENT_DATA_CONNECTION_VOICE_CALL_STARTED: + case EVENT_DATA_CONNECTION_VOICE_CALL_ENDED: + case EVENT_CSS_INDICATOR_CHANGED: + case EVENT_UPDATE_SUSPENDED_STATE: { + updateSuspendState(); + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + } + retVal = HANDLED; + break; + } + case EVENT_BW_REFRESH_RESPONSE: { + AsyncResult ar = (AsyncResult)msg.obj; + if (ar.exception != null) { + log("EVENT_BW_REFRESH_RESPONSE: error ignoring, e=" + ar.exception); + } else { + if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_MODEM_KEY)) { + updateLinkBandwidthsFromModem((List) ar.result); + } + } + retVal = HANDLED; + break; + } + case EVENT_KEEPALIVE_START_REQUEST: { + KeepalivePacketData pkt = (KeepalivePacketData) msg.obj; + int slotId = msg.arg1; + int intervalMillis = msg.arg2 * 1000; + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + mPhone.mCi.startNattKeepalive( + DataConnection.this.mCid, pkt, intervalMillis, + DataConnection.this.obtainMessage( + EVENT_KEEPALIVE_STARTED, slotId, 0, null)); + } else { + // We currently do not support NATT Keepalive requests using the + // DataService API, so unless the request is WWAN (always bound via + // the CommandsInterface), the request cannot be honored. + // + // TODO: b/72331356 to add support for Keepalive to the DataService + // so that keepalive requests can be handled (if supported) by the + // underlying transport. + if (mNetworkAgent != null) { + mNetworkAgent.sendSocketKeepaliveEvent( + msg.arg1, SocketKeepalive.ERROR_INVALID_NETWORK); + } + } + retVal = HANDLED; + break; + } + case EVENT_KEEPALIVE_STOP_REQUEST: { + int slotId = msg.arg1; + int handle = mNetworkAgent.keepaliveTracker.getHandleForSlot(slotId); + if (handle < 0) { + loge("No slot found for stopSocketKeepalive! " + slotId); + mNetworkAgent.sendSocketKeepaliveEvent( + slotId, SocketKeepalive.ERROR_NO_SUCH_SLOT); + retVal = HANDLED; + break; + } else { + logd("Stopping keepalive with handle: " + handle); + } + + mPhone.mCi.stopNattKeepalive( + handle, DataConnection.this.obtainMessage( + EVENT_KEEPALIVE_STOPPED, handle, slotId, null)); + retVal = HANDLED; + break; + } + case EVENT_KEEPALIVE_STARTED: { + AsyncResult ar = (AsyncResult) msg.obj; + final int slot = msg.arg1; + if (ar.exception != null || ar.result == null) { + loge("EVENT_KEEPALIVE_STARTED: error starting keepalive, e=" + + ar.exception); + mNetworkAgent.sendSocketKeepaliveEvent( + slot, SocketKeepalive.ERROR_HARDWARE_ERROR); + } else { + KeepaliveStatus ks = (KeepaliveStatus) ar.result; + if (ks == null) { + loge("Null KeepaliveStatus received!"); + } else { + mNetworkAgent.keepaliveTracker.handleKeepaliveStarted(slot, ks); + } + } + retVal = HANDLED; + break; + } + case EVENT_KEEPALIVE_STATUS: { + AsyncResult ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + loge("EVENT_KEEPALIVE_STATUS: error in keepalive, e=" + ar.exception); + // We have no way to notify connectivity in this case. + } + if (ar.result != null) { + KeepaliveStatus ks = (KeepaliveStatus) ar.result; + mNetworkAgent.keepaliveTracker.handleKeepaliveStatus(ks); + } + + retVal = HANDLED; + break; + } + case EVENT_KEEPALIVE_STOPPED: { + AsyncResult ar = (AsyncResult) msg.obj; + final int handle = msg.arg1; + final int slotId = msg.arg2; + + if (ar.exception != null) { + loge("EVENT_KEEPALIVE_STOPPED: error stopping keepalive for handle=" + + handle + " e=" + ar.exception); + mNetworkAgent.keepaliveTracker.handleKeepaliveStatus( + new KeepaliveStatus(KeepaliveStatus.ERROR_UNKNOWN)); + } else { + log("Keepalive Stop Requested for handle=" + handle); + mNetworkAgent.keepaliveTracker.handleKeepaliveStatus( + new KeepaliveStatus( + handle, KeepaliveStatus.STATUS_INACTIVE)); + } + retVal = HANDLED; + break; + } + case EVENT_LINK_CAPACITY_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + loge("EVENT_LINK_CAPACITY_CHANGED e=" + ar.exception); + } else { + if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_MODEM_KEY)) { + updateLinkBandwidthsFromModem((List) ar.result); + } + } + retVal = HANDLED; + break; + } + case EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE: { + AsyncResult ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + loge("EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE e=" + ar.exception); + } else { + Pair pair = (Pair) ar.result; + if (isBandwidthSourceKey( + DctConstants.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR_KEY)) { + updateLinkBandwidthsFromBandwidthEstimator(pair.first, pair.second); + } + } + retVal = HANDLED; + break; + } + case EVENT_REEVALUATE_RESTRICTED_STATE: { + // If the network was restricted, and now it does not need to be restricted + // anymore, we should add the NET_CAPABILITY_NOT_RESTRICTED capability. + if (mRestrictedNetworkOverride && !shouldRestrictNetwork()) { + if (DBG) { + log("Data connection becomes not-restricted. dc=" + this); + } + // Note we only do this when network becomes non-restricted. When a + // non-restricted becomes restricted (e.g. users disable data, or turn off + // data roaming), DCT will explicitly tear down the networks (because + // connectivity service does not support force-close TCP connections today). + // Also note that NET_CAPABILITY_NOT_RESTRICTED is an immutable capability + // (see {@link NetworkCapabilities}) once we add it to the network, we can't + // remove it through the entire life cycle of the connection. + mRestrictedNetworkOverride = false; + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + } + + // If the data does need to be unmetered use only (e.g. users turn on data, or + // device is not roaming anymore assuming data roaming is off), then we can + // dynamically add those metered APN type capabilities back. (But not the + // other way around because most of the APN-type capabilities are immutable + // capabilities.) + if (mUnmeteredUseOnly && !isUnmeteredUseOnly()) { + mUnmeteredUseOnly = false; + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + } + + mMmsUseOnly = isMmsUseOnly(); + + retVal = HANDLED; + break; + } + case EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES: { + // Update other properties like link properties if needed in future. + updateScore(); + retVal = HANDLED; + break; + } + case EVENT_NR_STATE_CHANGED: { + updateTcpBufferSizes(mRilRat); + if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { + updateLinkBandwidthsFromCarrierConfig(mRilRat); + } + if (mNetworkAgent != null) { + mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); + mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), + DataConnection.this); + } + retVal = HANDLED; + break; + } + case EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED: + AsyncResult asyncResult = (AsyncResult) msg.obj; + int[] administratorUids = (int[]) asyncResult.result; + mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length); + + // Administrator UIDs changed, so update NetworkAgent with new + // NetworkCapabilities + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkCapabilities( + getNetworkCapabilities(), DataConnection.this); + } + retVal = HANDLED; + break; + case EVENT_START_HANDOVER: //calls startHandover() + Consumer r = (Consumer) msg.obj; + r.accept(msg.arg1); + retVal = HANDLED; + break; + + default: + if (VDBG) { + log("DcActiveState not handled msg.what=" + getWhatToString(msg.what)); + } + retVal = NOT_HANDLED; + break; + } + return retVal; + } + } + private DcActiveState mActiveState = new DcActiveState(); + + /** + * The state machine is disconnecting. + */ + private class DcDisconnectingState extends State { + @Override + public void enter() { + TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, + TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__DISCONNECTING, + mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); + notifyDataConnectionState(); + } + @Override + public boolean processMessage(Message msg) { + boolean retVal; + + switch (msg.what) { + case EVENT_CONNECT: + if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = " + + mApnContexts.size()); + deferMessage(msg); + retVal = HANDLED; + break; + + case EVENT_DEACTIVATE_DONE: + DisconnectParams dp = (DisconnectParams) msg.obj; + + String str = "DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount=" + + mApnContexts.size(); + + if (DBG) log(str); + ApnContext.requestLog(dp.mApnContext, str); + + // Clear out existing qos sessions + updateQosParameters(null); + + if (dp.mTag == mTag) { + // Transition to inactive but send notifications after + // we've entered the mInactive state. + mInactiveState.setEnterNotificationParams(dp); + transitionTo(mInactiveState); + } else { + if (DBG) log("DcDisconnectState stale EVENT_DEACTIVATE_DONE" + + " dp.tag=" + dp.mTag + " mTag=" + mTag); + } + retVal = HANDLED; + break; + + default: + if (VDBG) { + log("DcDisconnectingState not handled msg.what=" + + getWhatToString(msg.what)); + } + retVal = NOT_HANDLED; + break; + } + return retVal; + } + } + private DcDisconnectingState mDisconnectingState = new DcDisconnectingState(); + + /** + * The state machine is disconnecting after an creating a connection. + */ + private class DcDisconnectionErrorCreatingConnection extends State { + @Override + public void enter() { + TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, + TelephonyStatsLog + .MOBILE_CONNECTION_STATE_CHANGED__STATE__DISCONNECTION_ERROR_CREATING_CONNECTION, + mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); + notifyDataConnectionState(); + } + @Override + public boolean processMessage(Message msg) { + boolean retVal; + + switch (msg.what) { + case EVENT_DEACTIVATE_DONE: + ConnectionParams cp = (ConnectionParams) msg.obj; + if (cp.mTag == mTag) { + String str = "DcDisconnectionErrorCreatingConnection" + + " msg.what=EVENT_DEACTIVATE_DONE"; + if (DBG) log(str); + ApnContext.requestLog(cp.mApnContext, str); + + // Transition to inactive but send notifications after + // we've entered the mInactive state. + mInactiveState.setEnterNotificationParams(cp, + DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER, + DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); + transitionTo(mInactiveState); + } else { + if (DBG) { + log("DcDisconnectionErrorCreatingConnection stale EVENT_DEACTIVATE_DONE" + + " dp.tag=" + cp.mTag + ", mTag=" + mTag); + } + } + retVal = HANDLED; + break; + + default: + if (VDBG) { + log("DcDisconnectionErrorCreatingConnection not handled msg.what=" + + getWhatToString(msg.what)); + } + retVal = NOT_HANDLED; + break; + } + return retVal; + } + } + private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection = + new DcDisconnectionErrorCreatingConnection(); + + /** + * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg. + * Used for cellular networks that use Access Point Names (APN) such + * as GSM networks. + * + * @param apnContext is the Access Point Name to bring up a connection to + * @param profileId for the connection + * @param rilRadioTechnology Radio technology for the data connection + * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. + * With AsyncResult.userObj set to the original msg.obj, + * AsyncResult.result = FailCause and AsyncResult.exception = Exception(). + * @param connectionGeneration used to track a single connection request so disconnects can get + * ignored if obsolete. + * @param requestType Data request type + * @param subId the subscription id associated with this data connection. + * @param isApnPreferred whether or not the apn is preferred. + */ + public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology, + Message onCompletedMsg, int connectionGeneration, + @RequestNetworkType int requestType, int subId, boolean isApnPreferred) { + if (DBG) { + log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg); + } + + if (mApnSetting == null) { + mApnSetting = apnContext.getApnSetting(); + } + + sendMessage(DataConnection.EVENT_CONNECT, + new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg, + connectionGeneration, requestType, subId, isApnPreferred)); + } + + /** + * Tear down the connection through the apn on the network. + * + * @param apnContext APN context + * @param reason reason to tear down + * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. + * With AsyncResult.userObj set to the original msg.obj. + */ + public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) { + if (DBG) { + log("tearDown: apnContext=" + apnContext + " reason=" + reason + " onCompletedMsg=" + + onCompletedMsg); + } + sendMessage(DataConnection.EVENT_DISCONNECT, + new DisconnectParams(apnContext, reason, DcTracker.RELEASE_TYPE_DETACH, + onCompletedMsg)); + } + + // ******* "public" interface + + /** + * Used for testing purposes. + */ + void tearDownNow() { + if (DBG) log("tearDownNow()"); + sendMessage(obtainMessage(EVENT_TEAR_DOWN_NOW)); + } + + /** + * Tear down the connection through the apn on the network. Ignores reference count and + * and always tears down. + * + * @param releaseType Data release type + * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. + * With AsyncResult.userObj set to the original msg.obj. + */ + public void tearDownAll(String reason, @ReleaseNetworkType int releaseType, + Message onCompletedMsg) { + if (DBG) { + log("tearDownAll: reason=" + reason + ", releaseType=" + + DcTracker.releaseTypeToString(releaseType)); + } + sendMessage(DataConnection.EVENT_DISCONNECT_ALL, + new DisconnectParams(null, reason, releaseType, onCompletedMsg)); + } + + /** + * Reset the data connection to inactive state. + */ + public void reset() { + sendMessage(EVENT_RESET); + if (DBG) log("reset"); + } + + /** + * Re-evaluate the restricted state. If the restricted data connection does not need to be + * restricted anymore, we need to dynamically change the network's capability. + */ + void reevaluateRestrictedState() { + sendMessage(EVENT_REEVALUATE_RESTRICTED_STATE); + if (DBG) log("reevaluate restricted state"); + } + + /** + * Re-evaluate the data connection properties. For example, it will recalculate data connection + * score and update through network agent it if changed. + */ + void reevaluateDataConnectionProperties() { + sendMessage(EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES); + if (DBG) log("reevaluate data connection properties"); + } + + /** + * @return The parameters used for initiating a data connection. + */ + public ConnectionParams getConnectionParams() { + return mConnectionParams; + } + + /** + * Update PCSCF addresses + * + * @param response + */ + public void updatePcscfAddr(DataCallResponse response) { + mPcscfAddr = response.getPcscfAddresses().stream() + .map(InetAddress::getHostAddress).toArray(String[]::new); + } + + /** + * @return The list of PCSCF addresses + */ + public String[] getPcscfAddresses() { + return mPcscfAddr; + } + + /** + * Using the result of the SETUP_DATA_CALL determine the retry delay. + * + * @param response The response from setup data call + * @return {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} if not suggested. + * {@link RetryManager#NO_RETRY} if retry should not happen. Otherwise the delay in milliseconds + * to the next SETUP_DATA_CALL. + */ + private long getSuggestedRetryDelay(DataCallResponse response) { + /** According to ril.h + * The value < 0 means no value is suggested + * The value 0 means retry should be done ASAP. + * The value of Long.MAX_VALUE(0x7fffffffffffffff) means no retry. + */ + if (response == null) { + return RetryManager.NO_SUGGESTED_RETRY_DELAY; + } + + long suggestedRetryTime = response.getRetryDurationMillis(); + + // The value < 0 means no value is suggested + if (suggestedRetryTime < 0) { + if (DBG) log("No suggested retry delay."); + return RetryManager.NO_SUGGESTED_RETRY_DELAY; + } else if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6) + && suggestedRetryTime == Long.MAX_VALUE) { + if (DBG) log("Network suggested not retrying."); + return RetryManager.NO_RETRY; + } else if (mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_6) + && suggestedRetryTime == Integer.MAX_VALUE) { + if (DBG) log("Network suggested not retrying."); + return RetryManager.NO_RETRY; + } + + return suggestedRetryTime; + } + + public List getApnContexts() { + return new ArrayList<>(mApnContexts.keySet()); + } + + /** + * Return whether there is an ApnContext for the given type in this DataConnection. + * @param type APN type to check + * @param exclusive true if the given APN type should be the only APN type that exists + * @return True if there is an ApnContext for the given type + */ + private boolean isApnContextAttached(@ApnType int type, boolean exclusive) { + boolean attached = mApnContexts.keySet().stream() + .map(ApnContext::getApnTypeBitmask) + .anyMatch(bitmask -> bitmask == type); + if (exclusive) { + attached &= mApnContexts.size() == 1; + } + return attached; + } + + /** Get the network agent of the data connection */ + @Nullable + DcNetworkAgent getNetworkAgent() { + return mNetworkAgent; + } + + void setHandoverState(@HandoverState int state) { + if (mHandoverState != state) { + String logStr = "State changed from " + handoverStateToString(mHandoverState) + + " to " + handoverStateToString(state); + mHandoverLocalLog.log(logStr); + logd(logStr); + mHandoverState = state; + } + } + + /** Sets the {@link DataCallSessionStats} mock for this data connection during unit testing. */ + @VisibleForTesting + public void setDataCallSessionStats(DataCallSessionStats dataCallSessionStats) { + mDataCallSessionStats = dataCallSessionStats; + } + + /** + * @return the string for msg.what as our info. + */ + @Override + protected String getWhatToString(int what) { + return cmdToString(what); + } + + private static String msgToString(Message msg) { + String retVal; + if (msg == null) { + retVal = "null"; + } else { + StringBuilder b = new StringBuilder(); + + b.append("{what="); + b.append(cmdToString(msg.what)); + + b.append(" when="); + TimeUtils.formatDuration(msg.getWhen() - SystemClock.uptimeMillis(), b); + + if (msg.arg1 != 0) { + b.append(" arg1="); + b.append(msg.arg1); + } + + if (msg.arg2 != 0) { + b.append(" arg2="); + b.append(msg.arg2); + } + + if (msg.obj != null) { + b.append(" obj="); + b.append(msg.obj); + } + + b.append(" target="); + b.append(msg.getTarget()); + + b.append(" replyTo="); + b.append(msg.replyTo); + + b.append("}"); + + retVal = b.toString(); + } + return retVal; + } + + static void slog(String s) { + Rlog.d("DC", s); + } + + /** + * Log with debug + * + * @param s is string log + */ + @Override + protected void log(String s) { + Rlog.d(getName(), s); + } + + /** + * Log with debug attribute + * + * @param s is string log + */ + @Override + protected void logd(String s) { + Rlog.d(getName(), s); + } + + /** + * Log with verbose attribute + * + * @param s is string log + */ + @Override + protected void logv(String s) { + Rlog.v(getName(), s); + } + + /** + * Log with info attribute + * + * @param s is string log + */ + @Override + protected void logi(String s) { + Rlog.i(getName(), s); + } + + /** + * Log with warning attribute + * + * @param s is string log + */ + @Override + protected void logw(String s) { + Rlog.w(getName(), s); + } + + /** + * Log with error attribute + * + * @param s is string log + */ + @Override + protected void loge(String s) { + Rlog.e(getName(), s); + } + + /** + * Log with error attribute + * + * @param s is string log + * @param e is a Throwable which logs additional information. + */ + @Override + protected void loge(String s, Throwable e) { + Rlog.e(getName(), s, e); + } + + /** Doesn't print mApnList of ApnContext's which would be recursive */ + public synchronized String toStringSimple() { + return getName() + ": State=" + getCurrentState().getName() + + " mApnSetting=" + mApnSetting + " RefCount=" + mApnContexts.size() + + " mCid=" + mCid + " mCreateTime=" + mCreateTime + + " mLastastFailTime=" + mLastFailTime + + " mLastFailCause=" + DataFailCause.toString(mLastFailCause) + + " mTag=" + mTag + + " mLinkProperties=" + mLinkProperties + + " linkCapabilities=" + getNetworkCapabilities() + + " mRestrictedNetworkOverride=" + mRestrictedNetworkOverride; + } + + @Override + public String toString() { + return "{" + toStringSimple() + " mApnContexts=" + mApnContexts + "}"; + } + + /** Check if the device is connected to NR 5G Non-Standalone network. */ + private boolean isNRConnected() { + return mPhone.getServiceState().getNrState() + == NetworkRegistrationInfo.NR_STATE_CONNECTED; + } + + /** + * @return The disallowed APN types bitmask + */ + private @ApnType int getDisallowedApnTypes() { + CarrierConfigManager configManager = (CarrierConfigManager) + mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); + int apnTypesBitmask = 0; + if (configManager != null) { + PersistableBundle bundle = configManager.getConfigForSubId(mSubId); + if (bundle != null) { + String key = (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + ? CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY + : CarrierConfigManager.KEY_CARRIER_WLAN_DISALLOWED_APN_TYPES_STRING_ARRAY; + if (bundle.getStringArray(key) != null) { + String disallowedApnTypesString = + TextUtils.join(",", bundle.getStringArray(key)); + if (!TextUtils.isEmpty(disallowedApnTypesString)) { + apnTypesBitmask = ApnSetting.getApnTypesBitmaskFromString( + disallowedApnTypesString); + } + } + } + } + + return apnTypesBitmask; + } + + private void dumpToLog() { + dump(null, new PrintWriter(new StringWriter(0)) { + @Override + public void println(String s) { + DataConnection.this.logd(s); + } + + @Override + public void flush() { + } + }, null); + } + + /** + * Re-calculate score and update through network agent if it changes. + */ + private void updateScore() { + int oldScore = mScore; + mScore = calculateScore(); + if (oldScore != mScore && mNetworkAgent != null) { + log("Updating score from " + oldScore + " to " + mScore); + mNetworkAgent.sendNetworkScore(mScore, this); + } + } + + private int calculateScore() { + int score = OTHER_CONNECTION_SCORE; + + // If it's serving a network request that asks NET_CAPABILITY_INTERNET and doesn't have + // specify a subId, this dataConnection is considered to be default Internet data + // connection. In this case we assign a slightly higher score of 50. The intention is + // it will not be replaced by other data connections accidentally in DSDS usecase. + for (ApnContext apnContext : mApnContexts.keySet()) { + for (NetworkRequest networkRequest : apnContext.getNetworkRequests()) { + if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + && networkRequest.getNetworkSpecifier() == null) { + score = DEFAULT_INTERNET_CONNECTION_SCORE; + break; + } + } + } + + return score; + } + + private String handoverStateToString(@HandoverState int state) { + switch (state) { + case HANDOVER_STATE_IDLE: return "IDLE"; + case HANDOVER_STATE_BEING_TRANSFERRED: return "BEING_TRANSFERRED"; + case HANDOVER_STATE_COMPLETED: return "COMPLETED"; + default: return "UNKNOWN"; + } + } + + private @DataState int getState() { + if (isInactive()) { + return TelephonyManager.DATA_DISCONNECTED; + } else if (isActivating()) { + return TelephonyManager.DATA_CONNECTING; + } else if (isActive()) { + // The data connection can only be suspended when it's in active state. + if (mIsSuspended) { + return TelephonyManager.DATA_SUSPENDED; + } + return TelephonyManager.DATA_CONNECTED; + } else if (isDisconnecting()) { + return TelephonyManager.DATA_DISCONNECTING; + } + + return TelephonyManager.DATA_UNKNOWN; + } + + /** + * Get precise data connection state + * + * @return The {@link PreciseDataConnectionState} + */ + public PreciseDataConnectionState getPreciseDataConnectionState() { + return new PreciseDataConnectionState.Builder() + .setTransportType(mTransportType) + .setId(mCid) + .setState(getState()) + .setApnSetting(mApnSetting) + .setLinkProperties(mLinkProperties) + .setNetworkType(getNetworkType()) + .setFailCause(mDcFailCause) + .build(); + } + + /** + * Dump the current state. + * + * @param fd + * @param printWriter + * @param args + */ + @Override + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.print("DataConnection "); + super.dump(fd, pw, args); + pw.flush(); + pw.increaseIndent(); + pw.println("transport type=" + + AccessNetworkConstants.transportTypeToString(mTransportType)); + pw.println("mApnContexts.size=" + mApnContexts.size()); + pw.println("mApnContexts=" + mApnContexts); + pw.println("mApnSetting=" + mApnSetting); + pw.println("mTag=" + mTag); + pw.println("mCid=" + mCid); + pw.println("mConnectionParams=" + mConnectionParams); + pw.println("mDisconnectParams=" + mDisconnectParams); + pw.println("mDcFailCause=" + DataFailCause.toString(mDcFailCause)); + pw.println("mPhone=" + mPhone); + pw.println("mSubId=" + mSubId); + pw.println("mLinkProperties=" + mLinkProperties); + pw.flush(); + pw.println("mDataRegState=" + mDataRegState); + pw.println("mHandoverState=" + handoverStateToString(mHandoverState)); + pw.println("mRilRat=" + mRilRat); + pw.println("mNetworkCapabilities=" + getNetworkCapabilities()); + pw.println("mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime)); + pw.println("mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime)); + pw.println("mLastFailCause=" + DataFailCause.toString(mLastFailCause)); + pw.println("mUserData=" + mUserData); + pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); + pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); + pw.println("mMmsUseOnly=" + mMmsUseOnly); + pw.println("mEnterpriseUse=" + mEnterpriseUse); + pw.println("mUnmeteredOverride=" + mUnmeteredOverride); + pw.println("mCongestedOverride=" + mCongestedOverride); + pw.println("mDownlinkBandwidth" + mDownlinkBandwidth); + pw.println("mUplinkBandwidth=" + mUplinkBandwidth); + pw.println("mDefaultQos=" + mDefaultQos); + pw.println("mQosBearerSessions=" + mQosBearerSessions); + pw.println("disallowedApnTypes=" + + ApnSetting.getApnTypesStringFromBitmask(getDisallowedApnTypes())); + pw.println("mInstanceNumber=" + mInstanceNumber); + pw.println("mAc=" + mAc); + pw.println("mScore=" + mScore); + if (mNetworkAgent != null) { + mNetworkAgent.dump(fd, pw, args); + } + pw.println("handover local log:"); + pw.increaseIndent(); + mHandoverLocalLog.dump(fd, pw, args); + pw.decreaseIndent(); + pw.decreaseIndent(); + pw.println(); + pw.flush(); + } + + /** + * Class used to track VCN-defined Network policies for this DataConnection. + * + *

MUST be registered with the associated DataConnection's Handler. + */ + private class DataConnectionVcnNetworkPolicyChangeListener + implements VcnNetworkPolicyChangeListener { + @Override + public void onPolicyChanged() { + // Poll the current underlying Network policy from VcnManager and send to NetworkAgent. + final NetworkCapabilities networkCapabilities = getNetworkCapabilities(); + VcnNetworkPolicyResult policyResult = + mVcnManager.applyVcnNetworkPolicy( + networkCapabilities, getLinkProperties()); + if (policyResult.isTeardownRequested()) { + tearDownAll( + Phone.REASON_VCN_REQUESTED_TEARDOWN, + DcTracker.RELEASE_TYPE_DETACH, + null /* onCompletedMsg */); + } + + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkCapabilities(networkCapabilities, DataConnection.this); + } + } + } +} + diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java b/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java new file mode 100644 index 0000000000..68f2ab38ae --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2017 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.dataconnection; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.HashSet; + +/** + * The class to describe the reasons of allowing or disallowing to establish a data connection. + */ +public class DataConnectionReasons { + private HashSet mDataDisallowedReasonSet = new HashSet<>(); + private DataAllowedReasonType mDataAllowedReason = DataAllowedReasonType.NONE; + + public DataConnectionReasons() {} + + void add(DataDisallowedReasonType reason) { + // Adding a disallowed reason will clean up the allowed reason because they are + // mutual exclusive. + mDataAllowedReason = DataAllowedReasonType.NONE; + mDataDisallowedReasonSet.add(reason); + } + + void add(DataAllowedReasonType reason) { + // Adding an allowed reason will clean up the disallowed reasons because they are + // mutual exclusive. + mDataDisallowedReasonSet.clear(); + + // Only higher priority allowed reason can overwrite the old one. See + // DataAllowedReasonType for the oder. + if (reason.ordinal() > mDataAllowedReason.ordinal()) { + mDataAllowedReason = reason; + } + } + + @Override + public String toString() { + StringBuilder reasonStr = new StringBuilder(); + if (mDataDisallowedReasonSet.size() > 0) { + reasonStr.append("Data disallowed reasons:"); + for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) { + reasonStr.append(" ").append(reason); + } + } else { + reasonStr.append("Data allowed reason:"); + reasonStr.append(" ").append(mDataAllowedReason); + } + return reasonStr.toString(); + } + + void copyFrom(DataConnectionReasons reasons) { + this.mDataDisallowedReasonSet = reasons.mDataDisallowedReasonSet; + this.mDataAllowedReason = reasons.mDataAllowedReason; + } + + boolean allowed() { + return mDataDisallowedReasonSet.size() == 0; + } + + /** + * Check if it contains a certain disallowed reason. + * + * @param reason The disallowed reason to check. + * @return {@code true} if the provided reason matches one of the disallowed reasons. + */ + @VisibleForTesting + public boolean contains(DataDisallowedReasonType reason) { + return mDataDisallowedReasonSet.contains(reason); + } + + /** + * Check if only one disallowed reason prevent data connection. + * + * @param reason The given reason to check + * @return True if the given reason is the only one that prevents data connection + */ + public boolean containsOnly(DataDisallowedReasonType reason) { + return mDataDisallowedReasonSet.size() == 1 && contains(reason); + } + + boolean contains(DataAllowedReasonType reason) { + return reason == mDataAllowedReason; + } + + boolean containsHardDisallowedReasons() { + for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) { + if (reason.isHardReason()) { + return true; + } + } + return false; + } + + // Disallowed reasons. There could be multiple reasons if data connection is not allowed. + public enum DataDisallowedReasonType { + // Soft failure reasons. Normally the reasons from users or policy settings. + + // Data is disabled by the user or policy. + DATA_DISABLED(false), + // Data roaming is disabled by the user. + ROAMING_DISABLED(false), + // Default data not selected. + DEFAULT_DATA_UNSELECTED(false), + + // Belows are all hard failure reasons. + NOT_ATTACHED(true), + SIM_NOT_READY(true), + INVALID_PHONE_STATE(true), + CONCURRENT_VOICE_DATA_NOT_ALLOWED(true), + PS_RESTRICTED(true), + UNDESIRED_POWER_STATE(true), + INTERNAL_DATA_DISABLED(true), + RADIO_DISABLED_BY_CARRIER(true), + // Not in the right state for data call setup. + APN_NOT_CONNECTABLE(true), + // Data is in connecting state. No need to send another setup request. + DATA_IS_CONNECTING(true), + // Data is being disconnected. Telephony will retry after disconnected. + DATA_IS_DISCONNECTING(true), + // Data is already connected. No need to setup data again. + DATA_ALREADY_CONNECTED(true), + // certain APNs are not allowed on IWLAN in legacy mode. + ON_IWLAN(true), + // certain APNs are only allowed when the device is camped on NR. + NOT_ON_NR(true), + // Data is not allowed while device is in emergency callback mode. + IN_ECBM(true), + // The given APN type's preferred transport has switched. + ON_OTHER_TRANSPORT(true), + // Underlying data service is not bound. + DATA_SERVICE_NOT_READY(true), + // Qualified networks service does not allow certain types of APN brought up on either + // cellular or IWLAN. + DISABLED_BY_QNS(true), + // Data is throttled. The network explicitly requested device not to establish data + // connection for a certain period. + DATA_THROTTLED(true); + + private boolean mIsHardReason; + + boolean isHardReason() { + return mIsHardReason; + } + + DataDisallowedReasonType(boolean isHardReason) { + mIsHardReason = isHardReason; + } + } + + // Data allowed reasons. There will be only one reason if data is allowed. + enum DataAllowedReasonType { + // Note that unlike disallowed reasons, we only have one allowed reason every time + // when we check data is allowed or not. The order of these allowed reasons is very + // important. The lower ones take precedence over the upper ones. + NONE, + NORMAL, + UNMETERED_APN, + RESTRICTED_REQUEST, + EMERGENCY_APN, + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java new file mode 100644 index 0000000000..305b4a8df5 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.dataconnection; + + +import static android.telephony.PhoneStateListener.LISTEN_CALL_STATE; +import static android.telephony.PhoneStateListener.LISTEN_NONE; + +import android.annotation.IntDef; +import android.content.ContentResolver; +import android.content.Context; +import android.os.Handler; +import android.os.RegistrantList; +import android.os.SystemProperties; +import android.provider.Settings; +import android.sysprop.TelephonyProperties; +import android.telephony.Annotation.CallState; +import android.telephony.CarrierConfigManager; +import android.telephony.PhoneStateListener; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; +import android.util.LocalLog; +import android.util.Pair; + +import com.android.internal.telephony.GlobalSettingsHelper; +import com.android.internal.telephony.MultiSimSettingController; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.data.DataEnabledOverride; +import com.android.telephony.Rlog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * The class to hold different data enabled/disabled settings. Also it allows clients to register + * for overall data enabled setting changed event. + * @hide + */ +public class DataEnabledSettings { + + private static final String LOG_TAG = "DataEnabledSettings"; + + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"REASON_"}, + value = { + REASON_REGISTERED, + REASON_INTERNAL_DATA_ENABLED, + REASON_USER_DATA_ENABLED, + REASON_POLICY_DATA_ENABLED, + REASON_DATA_ENABLED_BY_CARRIER, + REASON_PROVISIONED_CHANGED, + REASON_PROVISIONING_DATA_ENABLED_CHANGED, + REASON_OVERRIDE_RULE_CHANGED, + REASON_OVERRIDE_CONDITION_CHANGED, + REASON_THERMAL_DATA_ENABLED + }) + public @interface DataEnabledChangedReason {} + + public static final int REASON_REGISTERED = 0; + + public static final int REASON_INTERNAL_DATA_ENABLED = 1; + + public static final int REASON_USER_DATA_ENABLED = 2; + + public static final int REASON_POLICY_DATA_ENABLED = 3; + + public static final int REASON_DATA_ENABLED_BY_CARRIER = 4; + + public static final int REASON_PROVISIONED_CHANGED = 5; + + public static final int REASON_PROVISIONING_DATA_ENABLED_CHANGED = 6; + + public static final int REASON_OVERRIDE_RULE_CHANGED = 7; + + public static final int REASON_OVERRIDE_CONDITION_CHANGED = 8; + + public static final int REASON_THERMAL_DATA_ENABLED = 9; + + /** + * responds to the setInternalDataEnabled call - used internally to turn off data. + * For example during emergency calls + */ + private boolean mInternalDataEnabled = true; + + /** + * Flag indicating data allowed by network policy manager or not. + */ + private boolean mPolicyDataEnabled = true; + + /** + * Indicate if metered APNs are enabled by the carrier. set false to block all the metered APNs + * from continuously sending requests, which causes undesired network load. + */ + private boolean mCarrierDataEnabled = true; + + /** + * Flag indicating data allowed by Thermal service or not. + */ + private boolean mThermalDataEnabled = true; + + /** + * Flag indicating whether data is allowed or not for the device. It can be disabled by + * user, carrier, policy or thermal + */ + private boolean mIsDataEnabled = false; + + private final Phone mPhone; + + private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + + private ContentResolver mResolver = null; + + private final RegistrantList mOverallDataEnabledChangedRegistrants = new RegistrantList(); + + // TODO: Merge this with mOverallDataEnabledChangedRegistrants. In the future, notifying data + // enabled changed with APN types bitmask + private final RegistrantList mOverallDataEnabledOverrideChangedRegistrants = + new RegistrantList(); + + private final LocalLog mSettingChangeLocalLog = new LocalLog(32); + + private DataEnabledOverride mDataEnabledOverride; + + private TelephonyManager mTelephonyManager; + + // for msim, user data enabled setting depends on subId. + private final SubscriptionManager.OnSubscriptionsChangedListener + mOnSubscriptionsChangeListener = + new SubscriptionManager.OnSubscriptionsChangedListener() { + @Override + public void onSubscriptionsChanged() { + synchronized (this) { + if (mSubId != mPhone.getSubId()) { + log("onSubscriptionsChanged subId: " + mSubId + " to: " + + mPhone.getSubId()); + mSubId = mPhone.getSubId(); + mDataEnabledOverride = getDataEnabledOverride(); + updatePhoneStateListener(); + updateDataEnabledAndNotify(REASON_USER_DATA_ENABLED); + mPhone.notifyUserMobileDataStateChanged(isUserDataEnabled()); + } + } + } + }; + + private void updatePhoneStateListener() { + mTelephonyManager.listen(mPhoneStateListener, LISTEN_NONE); + if (SubscriptionManager.isUsableSubscriptionId(mSubId)) { + mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); + } + mTelephonyManager.listen(mPhoneStateListener, LISTEN_CALL_STATE); + } + + private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onCallStateChanged(@CallState int state, String phoneNumber) { + updateDataEnabledAndNotify(REASON_OVERRIDE_CONDITION_CHANGED); + } + }; + + @Override + public String toString() { + return "[mInternalDataEnabled=" + mInternalDataEnabled + + ", isUserDataEnabled=" + isUserDataEnabled() + + ", isProvisioningDataEnabled=" + isProvisioningDataEnabled() + + ", mPolicyDataEnabled=" + mPolicyDataEnabled + + ", mCarrierDataEnabled=" + mCarrierDataEnabled + + ", mIsDataEnabled=" + mIsDataEnabled + + ", mThermalDataEnabled=" + mThermalDataEnabled + + ", " + mDataEnabledOverride + + "]"; + } + + public DataEnabledSettings(Phone phone) { + mPhone = phone; + mResolver = mPhone.getContext().getContentResolver(); + SubscriptionManager subscriptionManager = (SubscriptionManager) mPhone.getContext() + .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); + subscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); + mTelephonyManager = (TelephonyManager) mPhone.getContext() + .getSystemService(Context.TELEPHONY_SERVICE); + mDataEnabledOverride = getDataEnabledOverride(); + updateDataEnabled(); + } + + private DataEnabledOverride getDataEnabledOverride() { + return new DataEnabledOverride(SubscriptionController.getInstance() + .getDataEnabledOverrideRules(mPhone.getSubId())); + } + + public synchronized void setInternalDataEnabled(boolean enabled) { + if (mInternalDataEnabled != enabled) { + localLog("InternalDataEnabled", enabled); + mInternalDataEnabled = enabled; + updateDataEnabledAndNotify(REASON_INTERNAL_DATA_ENABLED); + } + } + public synchronized boolean isInternalDataEnabled() { + return mInternalDataEnabled; + } + + private synchronized void setUserDataEnabled(boolean enabled) { + // By default the change should propagate to the group. + setUserDataEnabled(enabled, true); + } + + /** + * @param notifyMultiSimSettingController if setUserDataEnabled is already from propagating + * from MultiSimSettingController, don't notify MultiSimSettingController again. + * For example, if sub1 and sub2 are in the same group and user enables data for sub + * 1, sub 2 will also be enabled but with propagateToGroup = false. + */ + public synchronized void setUserDataEnabled(boolean enabled, + boolean notifyMultiSimSettingController) { + // Can't disable data for stand alone opportunistic subscription. + if (isStandAloneOpportunistic(mPhone.getSubId(), mPhone.getContext()) && !enabled) return; + + boolean changed = GlobalSettingsHelper.setInt(mPhone.getContext(), + Settings.Global.MOBILE_DATA, mPhone.getSubId(), (enabled ? 1 : 0)); + if (changed) { + localLog("UserDataEnabled", enabled); + mPhone.notifyUserMobileDataStateChanged(enabled); + updateDataEnabledAndNotify(REASON_USER_DATA_ENABLED); + if (notifyMultiSimSettingController) { + MultiSimSettingController.getInstance().notifyUserDataEnabled( + mPhone.getSubId(), enabled); + } + } + } + + /** + * Policy control of data connection with reason + * @param reason the reason the data enable change is taking place + * @param enabled True if enabling the data, otherwise disabling. + */ + public synchronized void setDataEnabled(@TelephonyManager.DataEnabledReason int reason, + boolean enabled) { + switch (reason) { + case TelephonyManager.DATA_ENABLED_REASON_USER: + setUserDataEnabled(enabled); + break; + case TelephonyManager.DATA_ENABLED_REASON_CARRIER: + setCarrierDataEnabled(enabled); + break; + case TelephonyManager.DATA_ENABLED_REASON_POLICY: + setPolicyDataEnabled(enabled); + break; + case TelephonyManager.DATA_ENABLED_REASON_THERMAL: + setThermalDataEnabled(enabled); + break; + default: + log("Invalid data enable reason " + reason); + break; + } + } + + public synchronized boolean isUserDataEnabled() { + // User data should always be true for opportunistic subscription. + if (isStandAloneOpportunistic(mPhone.getSubId(), mPhone.getContext())) return true; + + boolean defaultVal = TelephonyProperties.mobile_data().orElse(true); + + return GlobalSettingsHelper.getBoolean(mPhone.getContext(), + Settings.Global.MOBILE_DATA, mPhone.getSubId(), defaultVal); + } + + /** + * Set whether always allowing MMS data connection. + * + * @param alwaysAllow {@code true} if MMS data is always allowed. + * + * @return {@code false} if the setting is changed. + */ + public synchronized boolean setAlwaysAllowMmsData(boolean alwaysAllow) { + localLog("setAlwaysAllowMmsData", alwaysAllow); + mDataEnabledOverride.setAlwaysAllowMms(alwaysAllow); + boolean changed = SubscriptionController.getInstance() + .setDataEnabledOverrideRules(mPhone.getSubId(), mDataEnabledOverride.getRules()); + if (changed) { + updateDataEnabledAndNotify(REASON_OVERRIDE_RULE_CHANGED); + notifyDataEnabledOverrideChanged(); + } + + return changed; + } + + /** + * Set allowing mobile data during voice call. This is used for allowing data on the non-default + * data SIM. When a voice call is placed on the non-default data SIM on DSDS devices, users will + * not be able to use mobile data. By calling this API, data will be temporarily enabled on the + * non-default data SIM during the life cycle of the voice call. + * + * @param allow {@code true} if allowing using data during voice call, {@code false} if + * disallowed + * + * @return {@code true} if operation is successful. otherwise {@code false}. + */ + public synchronized boolean setAllowDataDuringVoiceCall(boolean allow) { + localLog("setAllowDataDuringVoiceCall", allow); + if (allow == isDataAllowedInVoiceCall()) { + return true; + } + mDataEnabledOverride.setDataAllowedInVoiceCall(allow); + + boolean changed = SubscriptionController.getInstance() + .setDataEnabledOverrideRules(mPhone.getSubId(), mDataEnabledOverride.getRules()); + if (changed) { + updateDataEnabledAndNotify(REASON_OVERRIDE_RULE_CHANGED); + notifyDataEnabledOverrideChanged(); + } + + return changed; + } + + /** + * Check if data is allowed during voice call. + * + * @return {@code true} if data is allowed during voice call. + */ + public synchronized boolean isDataAllowedInVoiceCall() { + return mDataEnabledOverride.isDataAllowedInVoiceCall(); + } + + public synchronized boolean isMmsAlwaysAllowed() { + return mDataEnabledOverride.isMmsAlwaysAllowed(); + } + + private synchronized void setPolicyDataEnabled(boolean enabled) { + if (mPolicyDataEnabled != enabled) { + localLog("PolicyDataEnabled", enabled); + mPolicyDataEnabled = enabled; + updateDataEnabledAndNotify(REASON_POLICY_DATA_ENABLED); + } + } + + public synchronized boolean isPolicyDataEnabled() { + return mPolicyDataEnabled; + } + + private synchronized void setCarrierDataEnabled(boolean enabled) { + if (mCarrierDataEnabled != enabled) { + localLog("CarrierDataEnabled", enabled); + mCarrierDataEnabled = enabled; + updateDataEnabledAndNotify(REASON_DATA_ENABLED_BY_CARRIER); + } + } + + public synchronized boolean isCarrierDataEnabled() { + return mCarrierDataEnabled; + } + + private synchronized void setThermalDataEnabled(boolean enabled) { + if (mThermalDataEnabled != enabled) { + localLog("ThermalDataEnabled", enabled); + mThermalDataEnabled = enabled; + updateDataEnabledAndNotify(REASON_THERMAL_DATA_ENABLED); + } + } + + public synchronized boolean isThermalDataEnabled() { + return mThermalDataEnabled; + } + + public synchronized void updateProvisionedChanged() { + updateDataEnabledAndNotify(REASON_PROVISIONED_CHANGED); + } + + public synchronized void updateProvisioningDataEnabled() { + updateDataEnabledAndNotify(REASON_PROVISIONING_DATA_ENABLED_CHANGED); + } + + public synchronized boolean isDataEnabled() { + return mIsDataEnabled; + } + + /** + * Check if data is enabled for a specific reason {@@TelephonyManager.DataEnabledReason} + * + * @return {@code true} if the overall data is enabled; {@code false} if not. + */ + public synchronized boolean isDataEnabledForReason( + @TelephonyManager.DataEnabledReason int reason) { + switch (reason) { + case TelephonyManager.DATA_ENABLED_REASON_USER: + return isUserDataEnabled(); + case TelephonyManager.DATA_ENABLED_REASON_CARRIER: + return isCarrierDataEnabled(); + case TelephonyManager.DATA_ENABLED_REASON_POLICY: + return isPolicyDataEnabled(); + case TelephonyManager.DATA_ENABLED_REASON_THERMAL: + return isThermalDataEnabled(); + default: + return false; + } + } + + private synchronized void updateDataEnabledAndNotify(int reason) { + boolean prevDataEnabled = mIsDataEnabled; + + updateDataEnabled(); + + if (prevDataEnabled != mIsDataEnabled) { + notifyDataEnabledChanged(!prevDataEnabled, reason); + } + } + + private synchronized void updateDataEnabled() { + if (isProvisioning()) { + mIsDataEnabled = isProvisioningDataEnabled(); + } else { + mIsDataEnabled = mInternalDataEnabled && (isUserDataEnabled() || mDataEnabledOverride + .shouldOverrideDataEnabledSettings(mPhone, ApnSetting.TYPE_ALL)) + && mPolicyDataEnabled && mCarrierDataEnabled && mThermalDataEnabled; + } + } + + public boolean isProvisioning() { + return Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0; + } + /** + * In provisioning, we might want to have enable mobile data during provisioning. It depends + * on value of Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED which is set by + * setupwizard. It only matters if it's in provisioning stage. + * @return whether we are enabling userData during provisioning stage. + */ + public boolean isProvisioningDataEnabled() { + final String prov_property = SystemProperties.get("ro.com.android.prov_mobiledata", + "false"); + boolean retVal = "true".equalsIgnoreCase(prov_property); + + final int prov_mobile_data = Settings.Global.getInt(mResolver, + Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, + retVal ? 1 : 0); + retVal = prov_mobile_data != 0; + log("getDataEnabled during provisioning retVal=" + retVal + " - (" + prov_property + + ", " + prov_mobile_data + ")"); + + return retVal; + } + + public synchronized void setDataRoamingEnabled(boolean enabled) { + // will trigger handleDataOnRoamingChange() through observer + boolean changed = GlobalSettingsHelper.setBoolean(mPhone.getContext(), + Settings.Global.DATA_ROAMING, mPhone.getSubId(), enabled); + + if (changed) { + localLog("setDataRoamingEnabled", enabled); + MultiSimSettingController.getInstance().notifyRoamingDataEnabled(mPhone.getSubId(), + enabled); + } + } + + /** + * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value. + */ + public synchronized boolean getDataRoamingEnabled() { + return GlobalSettingsHelper.getBoolean(mPhone.getContext(), + Settings.Global.DATA_ROAMING, mPhone.getSubId(), getDefaultDataRoamingEnabled()); + } + + /** + * get default values for {@link Settings.Global#DATA_ROAMING} + * return {@code true} if either + * {@link CarrierConfigManager#KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL} or + * system property ro.com.android.dataroaming is set to true. otherwise return {@code false} + */ + public synchronized boolean getDefaultDataRoamingEnabled() { + final CarrierConfigManager configMgr = (CarrierConfigManager) + mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); + boolean isDataRoamingEnabled = "true".equalsIgnoreCase(SystemProperties.get( + "ro.com.android.dataroaming", "false")); + isDataRoamingEnabled |= configMgr.getConfigForSubId(mPhone.getSubId()).getBoolean( + CarrierConfigManager.KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL); + return isDataRoamingEnabled; + } + + private void notifyDataEnabledChanged(boolean enabled, int reason) { + mOverallDataEnabledChangedRegistrants.notifyResult(new Pair<>(enabled, reason)); + mPhone.notifyDataEnabled(enabled, reason); + } + + public void registerForDataEnabledChanged(Handler h, int what, Object obj) { + mOverallDataEnabledChangedRegistrants.addUnique(h, what, obj); + notifyDataEnabledChanged(isDataEnabled(), REASON_REGISTERED); + } + + public void unregisterForDataEnabledChanged(Handler h) { + mOverallDataEnabledChangedRegistrants.remove(h); + } + + private void notifyDataEnabledOverrideChanged() { + mOverallDataEnabledOverrideChangedRegistrants.notifyRegistrants(); + } + + /** + * Register for data enabled override changed event. + * + * @param h The handler + * @param what The event + */ + public void registerForDataEnabledOverrideChanged(Handler h, int what) { + mOverallDataEnabledOverrideChangedRegistrants.addUnique(h, what, null); + notifyDataEnabledOverrideChanged(); + } + + /** + * Unregistered for data enabled override changed event. + * + * @param h The handler + */ + public void unregisterForDataEnabledOverrideChanged(Handler h) { + mOverallDataEnabledOverrideChangedRegistrants.remove(h); + } + + private static boolean isStandAloneOpportunistic(int subId, Context context) { + SubscriptionInfo info = SubscriptionController.getInstance().getActiveSubscriptionInfo( + subId, context.getOpPackageName(), context.getAttributionTag()); + return (info != null) && info.isOpportunistic() && info.getGroupUuid() == null; + } + + public synchronized boolean isDataEnabled(int apnType) { + if (isProvisioning()) { + return isProvisioningDataEnabled(); + } else { + boolean userDataEnabled = isUserDataEnabled(); + // Check if we should temporarily enable data in certain conditions. + boolean isDataEnabledOverridden = mDataEnabledOverride + .shouldOverrideDataEnabledSettings(mPhone, apnType); + + return (mInternalDataEnabled && mPolicyDataEnabled && mCarrierDataEnabled + && mThermalDataEnabled && (userDataEnabled || isDataEnabledOverridden)); + } + } + + private void log(String s) { + Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); + } + + private void localLog(String name, boolean value) { + mSettingChangeLocalLog.log(name + " change to " + value); + } + + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(" DataEnabledSettings="); + mSettingChangeLocalLog.dump(fd, pw, args); + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java new file mode 100644 index 0000000000..d00600464b --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java @@ -0,0 +1,978 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.dataconnection; + +import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AppOpsManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.LinkProperties; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.PersistableBundle; +import android.os.RegistrantList; +import android.os.RemoteException; +import android.os.UserHandle; +import android.permission.LegacyPermissionManager; +import android.telephony.AccessNetworkConstants; +import android.telephony.AccessNetworkConstants.TransportType; +import android.telephony.AnomalyReporter; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.data.DataCallResponse; +import android.telephony.data.DataProfile; +import android.telephony.data.DataService; +import android.telephony.data.DataServiceCallback; +import android.telephony.data.IDataService; +import android.telephony.data.IDataServiceCallback; +import android.telephony.data.NetworkSliceInfo; +import android.telephony.data.TrafficDescriptor; +import android.text.TextUtils; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConfigurationManager; +import com.android.internal.telephony.util.TelephonyUtils; +import com.android.telephony.Rlog; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; + +/** + * Data service manager manages handling data requests and responses on data services (e.g. + * Cellular data service, IWLAN data service). + */ +public class DataServiceManager extends Handler { + private static final boolean DBG = true; + + static final String DATA_CALL_RESPONSE = "data_call_response"; + + 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; + + private final int mTransportType; + + private boolean mBound; + + private IDataService mIDataService; + + private DataServiceManagerDeathRecipient mDeathRecipient; + + private final RegistrantList mServiceBindingChangedRegistrants = new RegistrantList(); + + private final Map mMessageMap = new ConcurrentHashMap<>(); + + private final RegistrantList mDataCallListChangedRegistrants = new RegistrantList(); + + private final RegistrantList mApnUnthrottledRegistrants = new RegistrantList(); + + private String mTargetBindingPackageName; + + private CellularDataServiceConnection mServiceConnection; + + private final UUID mAnomalyUUID = UUID.fromString("fc1956de-c080-45de-8431-a1faab687110"); + private String mLastBoundPackageName; + + /** + * Helpful for logging + * @return the tag name + * + * @hide + */ + public String getTag() { + return mTag; + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) + && mPhone.getPhoneId() == intent.getIntExtra( + CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) { + // 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."); + sendEmptyMessage(EVENT_BIND_DATA_SERVICE); + } + } + }; + + private class DataServiceManagerDeathRecipient implements IBinder.DeathRecipient { + @Override + public void binderDied() { + // TODO: try to rebind the service. + String message = "Data service " + mLastBoundPackageName + " for transport type " + + AccessNetworkConstants.transportTypeToString(mTransportType) + " died."; + loge(message); + AnomalyReporter.reportAnomaly(mAnomalyUUID, message, mPhone.getCarrierId()); + } + } + + private void grantPermissionsToService(String packageName) { + final String[] pkgToGrant = {packageName}; + CountDownLatch latch = new CountDownLatch(1); + try { + mPermissionManager.grantDefaultPermissionsToEnabledTelephonyDataServices( + pkgToGrant, UserHandle.of(UserHandle.myUserId()), Runnable::run, + isSuccess -> { + if (isSuccess) { + latch.countDown(); + } else { + loge("Failed to grant permissions to service."); + } + }); + TelephonyUtils.waitUntilReady(latch, CHANGE_PERMISSION_TIMEOUT_MS); + mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, + UserHandle.myUserId(), pkgToGrant[0], AppOpsManager.MODE_ALLOWED); + mAppOps.setMode(AppOpsManager.OPSTR_FINE_LOCATION, + UserHandle.myUserId(), pkgToGrant[0], AppOpsManager.MODE_ALLOWED); + } catch (RuntimeException e) { + loge("Binder to package manager died, permission grant for DataService failed."); + throw e; + } + } + + /** + * Loop through all DataServices installed on the system and revoke permissions from any that + * are not currently the WWAN or WLAN data service. + */ + private void revokePermissionsFromUnusedDataServices() { + // Except the current data services from having their permissions removed. + Set dataServices = getAllDataServicePackageNames(); + for (int transportType : mPhone.getAccessNetworksManager().getAvailableTransports()) { + dataServices.remove(getDataServicePackageName(transportType)); + } + + CountDownLatch latch = new CountDownLatch(1); + try { + String[] dataServicesArray = new String[dataServices.size()]; + dataServices.toArray(dataServicesArray); + mPermissionManager.revokeDefaultPermissionsFromDisabledTelephonyDataServices( + dataServicesArray, UserHandle.of(UserHandle.myUserId()), Runnable::run, + isSuccess -> { + if (isSuccess) { + latch.countDown(); + } else { + loge("Failed to revoke permissions from data services."); + } + }); + TelephonyUtils.waitUntilReady(latch, CHANGE_PERMISSION_TIMEOUT_MS); + for (String pkg : dataServices) { + mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, UserHandle.myUserId(), + pkg, AppOpsManager.MODE_ERRORED); + mAppOps.setMode(AppOpsManager.OPSTR_FINE_LOCATION, UserHandle.myUserId(), + pkg, AppOpsManager.MODE_ERRORED); + } + } catch (RuntimeException e) { + loge("Binder to package manager died; failed to revoke DataService permissions."); + throw e; + } + } + + private final class CellularDataServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (DBG) log("onServiceConnected"); + mIDataService = IDataService.Stub.asInterface(service); + mDeathRecipient = new DataServiceManagerDeathRecipient(); + mBound = true; + mLastBoundPackageName = getDataServicePackageName(); + removeMessages(EVENT_WATCHDOG_TIMEOUT); + + try { + service.linkToDeath(mDeathRecipient, 0); + mIDataService.createDataServiceProvider(mPhone.getPhoneId()); + mIDataService.registerForDataCallListChanged(mPhone.getPhoneId(), + new CellularDataServiceCallback("dataCallListChanged")); + mIDataService.registerForUnthrottleApn(mPhone.getPhoneId(), + new CellularDataServiceCallback("unthrottleApn")); + } catch (RemoteException e) { + loge("Remote exception. " + e); + return; + } + mServiceBindingChangedRegistrants.notifyResult(true); + } + @Override + public void onServiceDisconnected(ComponentName name) { + if (DBG) log("onServiceDisconnected"); + removeMessages(EVENT_WATCHDOG_TIMEOUT); + mIDataService = null; + mBound = false; + mServiceBindingChangedRegistrants.notifyResult(false); + mTargetBindingPackageName = null; + } + } + + private final class CellularDataServiceCallback extends IDataServiceCallback.Stub { + + private final String mTag; + + CellularDataServiceCallback(String tag) { + mTag = tag; + } + + public String getTag() { + return mTag; + } + + @Override + public void onSetupDataCallComplete(@DataServiceCallback.ResultCode int resultCode, + DataCallResponse response) { + if (DBG) { + log("onSetupDataCallComplete. resultCode = " + resultCode + ", response = " + + response); + } + removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); + Message msg = mMessageMap.remove(asBinder()); + if (msg != null) { + msg.getData().putParcelable(DATA_CALL_RESPONSE, response); + sendCompleteMessage(msg, resultCode); + } else { + loge("Unable to find the message for setup call response."); + } + } + + @Override + public void onDeactivateDataCallComplete(@DataServiceCallback.ResultCode int resultCode) { + if (DBG) log("onDeactivateDataCallComplete. resultCode = " + resultCode); + removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); + Message msg = mMessageMap.remove(asBinder()); + sendCompleteMessage(msg, resultCode); + } + + @Override + public void onSetInitialAttachApnComplete(@DataServiceCallback.ResultCode int resultCode) { + if (DBG) log("onSetInitialAttachApnComplete. resultCode = " + resultCode); + Message msg = mMessageMap.remove(asBinder()); + sendCompleteMessage(msg, resultCode); + } + + @Override + public void onSetDataProfileComplete(@DataServiceCallback.ResultCode int resultCode) { + if (DBG) log("onSetDataProfileComplete. resultCode = " + resultCode); + Message msg = mMessageMap.remove(asBinder()); + sendCompleteMessage(msg, resultCode); + } + + @Override + public void onRequestDataCallListComplete(@DataServiceCallback.ResultCode int resultCode, + List dataCallList) { + if (DBG) log("onRequestDataCallListComplete. resultCode = " + resultCode); + Message msg = mMessageMap.remove(asBinder()); + sendCompleteMessage(msg, resultCode); + } + + @Override + public void onDataCallListChanged(List dataCallList) { + mDataCallListChangedRegistrants.notifyRegistrants( + new AsyncResult(null, dataCallList, null)); + } + + @Override + public void onHandoverStarted(@DataServiceCallback.ResultCode int resultCode) { + if (DBG) log("onHandoverStarted. resultCode = " + resultCode); + removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); + Message msg = mMessageMap.remove(asBinder()); + sendCompleteMessage(msg, resultCode); + } + + @Override + public void onHandoverCancelled(@DataServiceCallback.ResultCode int resultCode) { + if (DBG) log("onHandoverCancelled. resultCode = " + resultCode); + removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); + Message msg = mMessageMap.remove(asBinder()); + sendCompleteMessage(msg, resultCode); + } + + @Override + public void onApnUnthrottled(String apn) { + if (apn != null) { + mApnUnthrottledRegistrants.notifyRegistrants( + new AsyncResult(null, apn, null)); + } else { + loge("onApnUnthrottled: apn is null"); + } + } + + @Override + public void onDataProfileUnthrottled(DataProfile dataProfile) { + if (dataProfile != null) { + mApnUnthrottledRegistrants.notifyRegistrants( + new AsyncResult(null, dataProfile, null)); + } else { + loge("onDataProfileUnthrottled: dataProfile is null"); + } + } + } + + /** + * Constructor + * + * @param phone The phone object + * @param transportType The transport type + * @param tagSuffix Logging tag suffix + */ + public DataServiceManager(Phone phone, @TransportType int transportType, String tagSuffix) { + mPhone = phone; + mTag = "DSM" + tagSuffix; + mTransportType = transportType; + mBound = false; + mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService( + Context.CARRIER_CONFIG_SERVICE); + // 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 + mPermissionManager = (LegacyPermissionManager) phone.getContext().getSystemService( + Context.LEGACY_PERMISSION_SERVICE); + mAppOps = (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE); + + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + try { + Context contextAsUser = phone.getContext().createPackageContextAsUser( + phone.getContext().getPackageName(), 0, UserHandle.ALL); + contextAsUser.registerReceiver(mBroadcastReceiver, intentFilter, + null /* broadcastPermission */, null); + } catch (PackageManager.NameNotFoundException e) { + loge("Package name not found: " + e.getMessage()); + } + + PhoneConfigurationManager.registerForMultiSimConfigChange( + this, EVENT_BIND_DATA_SERVICE, null); + + sendEmptyMessage(EVENT_BIND_DATA_SERVICE); + } + + /** + * Handle message events + * + * @param msg The message to handle + */ + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_BIND_DATA_SERVICE: + rebindDataService(); + break; + case EVENT_WATCHDOG_TIMEOUT: + handleRequestUnresponded((CellularDataServiceCallback) msg.obj); + break; + default: + loge("Unhandled event " + msg.what); + } + } + + private void handleRequestUnresponded(CellularDataServiceCallback 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(); + if (mIDataService != null && mIDataService.asBinder().isBinderAlive()) { + log("unbinding service"); + // Remove the network availability updater and then unbind the service. + try { + mIDataService.removeDataServiceProvider(mPhone.getPhoneId()); + } catch (RemoteException e) { + loge("Cannot remove data service provider. " + e); + } + } + + if (mServiceConnection != null) { + mPhone.getContext().unbindService(mServiceConnection); + } + mIDataService = null; + mServiceConnection = null; + mTargetBindingPackageName = null; + mBound = false; + } + + private void bindDataService(String packageName) { + if (mPhone == null || !SubscriptionManager.isValidPhoneId(mPhone.getPhoneId())) { + loge("can't bindDataService with invalid phone or phoneId."); + return; + } + + if (TextUtils.isEmpty(packageName)) { + loge("Can't find the binding package"); + return; + } + + Intent intent = null; + String className = getDataServiceClassName(); + if (TextUtils.isEmpty(className)) { + intent = new Intent(DataService.SERVICE_INTERFACE); + intent.setPackage(packageName); + } else { + ComponentName cm = new ComponentName(packageName, className); + intent = new Intent(DataService.SERVICE_INTERFACE).setComponent(cm); + } + + // Then pre-emptively grant the permissions to the package we will bind. + grantPermissionsToService(packageName); + + try { + mServiceConnection = new CellularDataServiceConnection(); + if (!mPhone.getContext().bindService( + intent, mServiceConnection, Context.BIND_AUTO_CREATE)) { + loge("Cannot bind to the data service."); + return; + } + mTargetBindingPackageName = packageName; + } catch (Exception e) { + loge("Cannot bind to the data service. Exception: " + e); + } + } + + private void rebindDataService() { + String packageName = getDataServicePackageName(); + // Do nothing if no need to rebind. + if (SubscriptionManager.isValidPhoneId(mPhone.getPhoneId()) + && TextUtils.equals(packageName, mTargetBindingPackageName)) { + if (DBG) log("Service " + packageName + " already bound or being bound."); + return; + } + + unbindDataService(); + bindDataService(packageName); + } + + @NonNull + private Set 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 + // to be updated. + List dataPackages = + mPhone.getContext().getPackageManager().queryIntentServices( + new Intent(DataService.SERVICE_INTERFACE), + PackageManager.MATCH_SYSTEM_ONLY); + HashSet packageNames = new HashSet<>(); + for (ResolveInfo info : dataPackages) { + if (info.serviceInfo == null) continue; + packageNames.add(info.serviceInfo.packageName); + } + return packageNames; + } + + /** + * Get the data service package name for our current transport type. + * + * @return package name of the data service package for the the current transportType. + */ + public String getDataServicePackageName() { + return getDataServicePackageName(mTransportType); + } + + /** + * Get the data service package by transport type. + * + * 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. + * + * @param transportType The transport type + * @return package name of the data service package for the specified transportType. + */ + private String getDataServicePackageName(@TransportType int transportType) { + String packageName; + int resourceId; + String carrierConfig; + + switch (transportType) { + 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: + 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)); + } + + // Read package name from resource overlay + packageName = mPhone.getContext().getResources().getString(resourceId); + + PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); + + if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { + // If carrier config overrides it, use the one from carrier config + packageName = b.getString(carrierConfig, packageName); + } + + return packageName; + } + + /** + * Get the data service class name for our current transport type. + * + * @return class name of the data service package for the the current transportType. + */ + private String getDataServiceClassName() { + return getDataServiceClassName(mTransportType); + } + + + /** + * Get the data service class by transport type. + * + * @param transportType either WWAN or WLAN + * @return class name of the data service package for the specified transportType. + */ + private String getDataServiceClassName(int transportType) { + String className; + int resourceId; + String carrierConfig; + switch (transportType) { + 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: + 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); + } + + // Read package name from resource overlay + className = mPhone.getContext().getResources().getString(resourceId); + + PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); + + if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { + // If carrier config overrides it, use the one from carrier config + className = b.getString(carrierConfig, className); + } + + return className; + } + + private void sendCompleteMessage(Message msg, @DataServiceCallback.ResultCode int code) { + if (msg != null) { + msg.arg1 = code; + msg.sendToTarget(); + } + } + + /** + * Setup a data connection. The data service provider must implement this method to support + * establishing a packet data connection. When completed or error, the service must invoke + * the provided callback to notify the platform. + * + * @param accessNetworkType Access network type that the data call will be established on. + * Must be one of {@link AccessNetworkConstants.AccessNetworkType}. + * @param dataProfile Data profile used for data call setup. See {@link DataProfile} + * @param isRoaming True if the device is data roaming. + * @param allowRoaming True if data roaming is allowed by the user. + * @param reason The reason for data setup. Must be {@link DataService#REQUEST_REASON_NORMAL} or + * {@link DataService#REQUEST_REASON_HANDOVER}. + * @param linkProperties If {@code reason} is {@link DataService#REQUEST_REASON_HANDOVER}, this + * is the link properties of the existing data connection, otherwise null. + * @param pduSessionId The pdu session id to be used for this data call. A value of -1 means + * no pdu session id was attached to this call. + * Reference: 3GPP TS 24.007 Section 11.2.3.1b + * @param sliceInfo The slice that represents S-NSSAI. + * Reference: 3GPP TS 24.501 + * @param trafficDescriptor The traffic descriptor for this data call, used for URSP matching. + * Reference: 3GPP TS TS 24.526 Section 5.2 + * @param matchAllRuleAllowed True if using the default match-all URSP rule for this request is + * allowed. + * @param onCompleteMessage The result message for this request. Null if the client does not + * care about the result. + */ + public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, + boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, + @Nullable NetworkSliceInfo sliceInfo, @Nullable TrafficDescriptor trafficDescriptor, + boolean matchAllRuleAllowed, Message onCompleteMessage) { + if (DBG) log("setupDataCall"); + if (!mBound) { + loge("setupDataCall: Data service not bound."); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + return; + } + + CellularDataServiceCallback callback = new CellularDataServiceCallback("setupDataCall"); + if (onCompleteMessage != null) { + 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); + } catch (RemoteException e) { + loge("setupDataCall: Cannot invoke setupDataCall on data service."); + mMessageMap.remove(callback.asBinder()); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + } + + /** + * Deactivate a data connection. The data service provider must implement this method to + * support data connection tear down. When completed or error, the service must invoke the + * provided callback to notify the platform. + * + * @param cid Call id returned in the callback of {@link #setupDataCall(int, DataProfile, + * boolean, boolean, int, LinkProperties, Message)} + * @param reason The reason for data deactivation. Must be + * {@link DataService#REQUEST_REASON_NORMAL}, {@link DataService#REQUEST_REASON_SHUTDOWN} + * or {@link DataService#REQUEST_REASON_HANDOVER}. + * @param onCompleteMessage The result message for this request. Null if the client does not + * care about the result. + */ + public void deactivateDataCall(int cid, int reason, Message onCompleteMessage) { + if (DBG) log("deactivateDataCall"); + if (!mBound) { + loge("Data service not bound."); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + return; + } + + CellularDataServiceCallback callback = + new CellularDataServiceCallback("deactivateDataCall"); + if (onCompleteMessage != null) { + 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."); + mMessageMap.remove(callback.asBinder()); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + } + + /** + * Indicates that a handover has begun. This is called on the source transport. + * + * Any resources being transferred cannot be released while a + * handover is underway. + * + * If a handover was unsuccessful, then the framework calls DataServiceManager#cancelHandover. + * The target transport retains ownership over any of the resources being transferred. + * + * 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. + * + * @param cid The identifier of the data call which is provided in DataCallResponse + * @param onCompleteMessage The result callback for this request. + */ + public void startHandover(int cid, @NonNull Message onCompleteMessage) { + CellularDataServiceCallback callback = + setupCallbackHelper("startHandover", onCompleteMessage); + if (callback == null) { + loge("startHandover: callback == null"); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + return; + } + + 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."); + mMessageMap.remove(callback.asBinder()); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + } + + /** + * Indicates that a handover was cancelled after a call to DataServiceManager#startHandover. + * This is called on the source transport. + * + * Since the handover was unsuccessful, the source transport retains ownership over any of + * the resources being transferred and is still responsible for releasing them. + * + * @param cid The identifier of the data call which is provided in DataCallResponse + * @param onCompleteMessage The result callback for this request. + */ + public void cancelHandover(int cid, @NonNull Message onCompleteMessage) { + CellularDataServiceCallback callback = + setupCallbackHelper("cancelHandover", onCompleteMessage); + if (callback == null) { + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + return; + } + + 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."); + mMessageMap.remove(callback.asBinder()); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + } + + @Nullable + private CellularDataServiceCallback setupCallbackHelper( + @NonNull final String operationName, @NonNull final Message onCompleteMessage) { + if (DBG) log(operationName); + if (!mBound) { + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + return null; + } + + CellularDataServiceCallback callback = + new CellularDataServiceCallback(operationName); + if (onCompleteMessage != null) { + if (DBG) log(operationName + ": onCompleteMessage set"); + mMessageMap.put(callback.asBinder(), onCompleteMessage); + } else { + if (DBG) log(operationName + ": onCompleteMessage not set"); + } + return callback; + } + + /** + * Set an APN to initial attach network. + * + * @param dataProfile Data profile used for data call setup. See {@link DataProfile}. + * @param isRoaming True if the device is data roaming. + * @param onCompleteMessage The result message for this request. Null if the client does not + * care about the result. + */ + public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, + Message onCompleteMessage) { + if (DBG) log("setInitialAttachApn"); + if (!mBound) { + loge("Data service not bound."); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + return; + } + + CellularDataServiceCallback callback = + new CellularDataServiceCallback("setInitialAttachApn"); + if (onCompleteMessage != null) { + mMessageMap.put(callback.asBinder(), onCompleteMessage); + } + try { + mIDataService.setInitialAttachApn(mPhone.getPhoneId(), dataProfile, isRoaming, + callback); + } catch (RemoteException e) { + loge("Cannot invoke setInitialAttachApn on data service."); + mMessageMap.remove(callback.asBinder()); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + } + + /** + * Send current carrier's data profiles to the data service for data call setup. This is + * only for CDMA carrier that can change the profile through OTA. The data service should + * always uses the latest data profile sent by the framework. + * + * @param dps A list of data profiles. + * @param isRoaming True if the device is data roaming. + * @param onCompleteMessage The result message for this request. Null if the client does not + * care about the result. + */ + public void setDataProfile(List dps, boolean isRoaming, + Message onCompleteMessage) { + if (DBG) log("setDataProfile"); + if (!mBound) { + loge("Data service not bound."); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + return; + } + + CellularDataServiceCallback callback = new CellularDataServiceCallback("setDataProfile"); + if (onCompleteMessage != null) { + mMessageMap.put(callback.asBinder(), onCompleteMessage); + } + try { + mIDataService.setDataProfile(mPhone.getPhoneId(), dps, isRoaming, callback); + } catch (RemoteException e) { + loge("Cannot invoke setDataProfile on data service."); + mMessageMap.remove(callback.asBinder()); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + } + + /** + * Get the active data call list. + * + * @param onCompleteMessage The result message for this request. Null if the client does not + * care about the result. + */ + public void requestDataCallList(Message onCompleteMessage) { + if (DBG) log("requestDataCallList"); + if (!mBound) { + loge("Data service not bound."); + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + return; + } + + CellularDataServiceCallback callback = + new CellularDataServiceCallback("requestDataCallList"); + if (onCompleteMessage != null) { + mMessageMap.put(callback.asBinder(), onCompleteMessage); + } + try { + mIDataService.requestDataCallList(mPhone.getPhoneId(), callback); + } catch (RemoteException e) { + loge("Cannot invoke requestDataCallList on data service."); + if (callback != null) { + mMessageMap.remove(callback.asBinder()); + } + sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); + } + } + + /** + * Register for data call list changed event. + * + * @param h The target to post the event message to. + * @param what The event. + */ + public void registerForDataCallListChanged(Handler h, int what) { + if (h != null) { + mDataCallListChangedRegistrants.addUnique(h, what, null); + } + } + + /** + * Unregister for data call list changed event. + * + * @param h The handler + */ + public void unregisterForDataCallListChanged(Handler h) { + if (h != null) { + mDataCallListChangedRegistrants.remove(h); + } + } + + /** + * Register apn unthrottled event + * + * @param h The target to post the event message to. + * @param what The event. + */ + public void registerForApnUnthrottled(Handler h, int what) { + if (h != null) { + mApnUnthrottledRegistrants.addUnique(h, what, null); + } + } + + /** + * Unregister for apn unthrottled event + * + * @param h The handler + */ + public void unregisterForApnUnthrottled(Handler h) { + if (h != null) { + mApnUnthrottledRegistrants.remove(h); + } + } + + /** + * Register for data service binding status changed event. + * + * @param h The target to post the event message to. + * @param what The event. + * @param obj The user object. + */ + public void registerForServiceBindingChanged(Handler h, int what, Object obj) { + if (h != null) { + mServiceBindingChangedRegistrants.addUnique(h, what, obj); + } + + } + + /** + * Unregister for data service binding status changed event. + * + * @param h The handler + */ + public void unregisterForServiceBindingChanged(Handler h) { + if (h != null) { + mServiceBindingChangedRegistrants.remove(h); + } + } + + /** + * Get the transport type. Must be a {@link TransportType}. + * + * @return + */ + @TransportType + public int getTransportType() { + return mTransportType; + } + + private void log(String s) { + Rlog.d(mTag, s); + } + + private void loge(String s) { + Rlog.e(mTag, s); + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java b/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java new file mode 100644 index 0000000000..4a465d262f --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2020 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.dataconnection; + +import android.annotation.ElapsedRealtimeLong; +import android.annotation.NonNull; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.PersistableBundle; +import android.telephony.AccessNetworkConstants; +import android.telephony.Annotation; +import android.telephony.Annotation.ApnType; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.data.ApnSetting; +import android.telephony.data.ThrottleStatus; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.RetryManager; +import com.android.telephony.Rlog; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Data throttler tracks the throttling status of the data network and notifies registrants when + * there are changes. The throttler is per phone and per transport type. + */ +public class DataThrottler extends Handler { + private static final String TAG = DataThrottler.class.getSimpleName(); + + private static final int EVENT_SET_RETRY_TIME = 1; + private static final int EVENT_CARRIER_CONFIG_CHANGED = 2; + private static final int EVENT_RESET = 3; + private static final int EVENT_AIRPLANE_MODE_CHANGED = 4; + private static final int EVENT_TRACING_AREA_CODE_CHANGED = 5; + + private final Phone mPhone; + private final int mSlotIndex; + private final @AccessNetworkConstants.TransportType int mTransportType; + private boolean mResetWhenAreaCodeChanged = false; + + /** + * Callbacks that report the apn throttle status. + */ + private final List mCallbacks = new ArrayList<>(); + + /** + * Keeps track of detailed information of the throttle status that is meant to be + * reported to other components. + */ + private final Map mThrottleStatus = new ConcurrentHashMap<>(); + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { + if (mPhone.getPhoneId() == intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, + SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { + if (intent.getBooleanExtra( + CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, false)) { + // Ignore the rebroadcast one to prevent multiple carrier config changed + // event during boot up. + return; + } + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (SubscriptionManager.isValidSubscriptionId(subId)) { + sendEmptyMessage(EVENT_CARRIER_CONFIG_CHANGED); + } + } + } + } + }; + + public DataThrottler(Phone phone, int transportType) { + super(null, false); + mPhone = phone; + mSlotIndex = phone.getPhoneId(); + mTransportType = transportType; + + IntentFilter filter = new IntentFilter(); + filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + mPhone.getContext().registerReceiver(mBroadcastReceiver, filter, null, mPhone); + + mPhone.getServiceStateTracker().registerForAirplaneModeChanged(this, + EVENT_AIRPLANE_MODE_CHANGED, null); + mPhone.getServiceStateTracker().registerForAreaCodeChanged(this, + EVENT_TRACING_AREA_CODE_CHANGED, null); + } + + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + switch (msg.what) { + case EVENT_SET_RETRY_TIME: + int apnTypes = msg.arg1; + int newRequestType = msg.arg2; + long retryElapsedTime = (long) msg.obj; + setRetryTimeInternal(apnTypes, retryElapsedTime, newRequestType); + break; + case EVENT_CARRIER_CONFIG_CHANGED: + onCarrierConfigChanged(); + break; + case EVENT_RESET: + resetInternal(); + break; + case EVENT_AIRPLANE_MODE_CHANGED: + ar = (AsyncResult) msg.obj; + if (!(Boolean) ar.result) { + resetInternal(); + } + break; + case EVENT_TRACING_AREA_CODE_CHANGED: + if (mResetWhenAreaCodeChanged) { + resetInternal(); + } + break; + } + } + + @NonNull + private PersistableBundle getCarrierConfig() { + CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager != null) { + // If an invalid subId is used, this bundle will contain default values. + PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId()); + if (config != null) { + return config; + } + } + // Return static default defined in CarrierConfigManager. + return CarrierConfigManager.getDefaultConfig(); + } + + private void onCarrierConfigChanged() { + PersistableBundle config = getCarrierConfig(); + mResetWhenAreaCodeChanged = config.getBoolean( + CarrierConfigManager.KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false); + } + + /** + * Set the retry time and handover failure mode for the give APN types. + * + * @param apnTypes APN types + * @param retryElapsedTime The elapsed time that data connection for APN types should not be + * retried. {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} indicates throttling does not exist. + * {@link RetryManager#NO_RETRY} indicates retry should never happen. + */ + public void setRetryTime(@ApnType int apnTypes, @ElapsedRealtimeLong long retryElapsedTime, + @DcTracker.RequestNetworkType int newRequestType) { + sendMessage(obtainMessage(EVENT_SET_RETRY_TIME, apnTypes, newRequestType, + retryElapsedTime)); + } + + /** + * Set the retry time and handover failure mode for the give APN types. This is running on the + * handler thread. + * + * @param apnTypes APN types + * @param retryElapsedTime The elapsed time that data connection for APN types should not be + * retried. {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} indicates throttling does not exist. + * {@link RetryManager#NO_RETRY} indicates retry should never happen. + */ + private void setRetryTimeInternal(@ApnType int apnTypes, @ElapsedRealtimeLong + long retryElapsedTime, @DcTracker.RequestNetworkType int newRequestType) { + if (retryElapsedTime < 0) { + retryElapsedTime = RetryManager.NO_SUGGESTED_RETRY_DELAY; + } + + List changedStatuses = new ArrayList<>(); + while (apnTypes != 0) { + int apnType; + // Due to an API mistake of ApnSetting.TYPE_DEFAULT (which combines default and hipri + // bit), we need to do special handling here. + if ((apnTypes & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) { + apnType = ApnSetting.TYPE_DEFAULT; + apnTypes &= ~ApnSetting.TYPE_DEFAULT; + } else { + //Extract the least significant bit. + apnType = apnTypes & -apnTypes; + //Remove the least significant bit. + apnTypes &= apnTypes - 1; + } + + //Update the apn throttle status + ThrottleStatus newStatus = createStatus(apnType, retryElapsedTime, newRequestType); + + ThrottleStatus oldStatus = mThrottleStatus.get(apnType); + + //Check to see if there is a change that needs to be applied + if (!newStatus.equals(oldStatus)) { + //Mark as changed status + changedStatuses.add(newStatus); + + //Put the new status in the temp space + mThrottleStatus.put(apnType, newStatus); + } + } + + if (changedStatuses.size() > 0) { + sendThrottleStatusChanged(changedStatuses); + } + } + + /** + * Get the earliest retry time for the given APN type. The time is the system's elapse time. + * + * Note the DataThrottler is running phone process's main thread, which is most of the telephony + * components running on. Calling this method from other threads might run into race conditions. + * + * @param apnType APN type + * @return The earliest retry time for APN type. The time is the system's elapse time. + * {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} indicates there is no throttling for given APN + * type, {@link RetryManager#NO_RETRY} indicates retry should never happen. + */ + @ElapsedRealtimeLong + public long getRetryTime(@ApnType int apnType) { + ThrottleStatus status = mThrottleStatus.get(apnType); + if (status != null) { + if (status.getThrottleType() == ThrottleStatus.THROTTLE_TYPE_NONE) { + return RetryManager.NO_SUGGESTED_RETRY_DELAY; + } else { + return status.getThrottleExpiryTimeMillis(); + } + } + return RetryManager.NO_SUGGESTED_RETRY_DELAY; + } + + /** + * Resets retry times for all APNs to {@link RetryManager.NO_SUGGESTED_RETRY_DELAY}. + */ + public void reset() { + sendEmptyMessage(EVENT_RESET); + } + + /** + * Resets retry times for all APNs to {@link RetryManager.NO_SUGGESTED_RETRY_DELAY}. + */ + private void resetInternal() { + final List apnTypes = new ArrayList<>(); + for (ThrottleStatus throttleStatus : mThrottleStatus.values()) { + apnTypes.add(throttleStatus.getApnType()); + } + + for (int apnType : apnTypes) { + setRetryTime(apnType, RetryManager.NO_SUGGESTED_RETRY_DELAY, + DcTracker.REQUEST_TYPE_NORMAL); + } + } + + private ThrottleStatus createStatus(@Annotation.ApnType int apnType, long retryElapsedTime, + @DcTracker.RequestNetworkType int newRequestType) { + ThrottleStatus.Builder builder = new ThrottleStatus.Builder(); + + if (retryElapsedTime == RetryManager.NO_SUGGESTED_RETRY_DELAY) { + builder + .setNoThrottle() + .setRetryType(getRetryType(newRequestType)); + } else if (retryElapsedTime == RetryManager.NO_RETRY) { + builder + .setThrottleExpiryTimeMillis(RetryManager.NO_RETRY) + .setRetryType(ThrottleStatus.RETRY_TYPE_NONE); + } else { + builder + .setThrottleExpiryTimeMillis(retryElapsedTime) + .setRetryType(getRetryType(newRequestType)); + } + return builder + .setSlotIndex(mSlotIndex) + .setTransportType(mTransportType) + .setApnType(apnType) + .build(); + } + + private static int getRetryType(@DcTracker.RequestNetworkType int newRequestType) { + if (newRequestType == DcTracker.REQUEST_TYPE_NORMAL) { + return ThrottleStatus.RETRY_TYPE_NEW_CONNECTION; + } + + if (newRequestType == DcTracker.REQUEST_TYPE_HANDOVER) { + return ThrottleStatus.RETRY_TYPE_HANDOVER; + } + + loge("createStatus: Unknown requestType=" + newRequestType); + return ThrottleStatus.RETRY_TYPE_NEW_CONNECTION; + } + + private void sendThrottleStatusChanged(List statuses) { + synchronized (mCallbacks) { + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).onThrottleStatusChanged(statuses); + } + } + } + + private static void loge(String s) { + Rlog.e(TAG, s); + } + + /** + * Reports changes to apn throttle statuses. + * + * Note: All statuses are sent when first registered. + * + * @param callback status changes callback + */ + public void registerForThrottleStatusChanges(DataThrottler.Callback callback) { + synchronized (mCallbacks) { + //Only add if it's not there already + if (!mCallbacks.contains(callback)) { + //Report everything the first time + List throttleStatuses = + new ArrayList<>(mThrottleStatus.values()); + callback.onThrottleStatusChanged(throttleStatuses); + mCallbacks.add(callback); + } + } + } + + /** + * Unregister the callback + * @param callback the callback to unregister + */ + public void unregisterForThrottleStatusChanges(DataThrottler.Callback callback) { + synchronized (mCallbacks) { + mCallbacks.remove(callback); + } + } + + /** + * Callback for when throttle statuses change + */ + public interface Callback { + /** + * Called whenever the throttle status of an APN has changed. + * + * Note: Called with all statuses when first registered. + * + * @param throttleStatuses the status changes + */ + void onThrottleStatusChanged(List throttleStatuses); + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java new file mode 100644 index 0000000000..c34157eb9e --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java @@ -0,0 +1,487 @@ +/* + * Copyright (C) 2013 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.dataconnection; + +import android.hardware.radio.V1_4.DataConnActiveStatus; +import android.net.LinkAddress; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.RegistrantList; +import android.telephony.AccessNetworkConstants; +import android.telephony.CarrierConfigManager; +import android.telephony.DataFailCause; +import android.telephony.data.ApnSetting; +import android.telephony.data.DataCallResponse; +import android.telephony.data.TrafficDescriptor; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.DctConstants; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.dataconnection.DataConnection.UpdateLinkPropertyResult; +import com.android.internal.telephony.util.TelephonyUtils; +import com.android.net.module.util.LinkPropertiesUtils; +import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; +import com.android.net.module.util.NetUtils; +import com.android.telephony.Rlog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; + +/** + * Data Connection Controller which is a package visible class and controls + * multiple data connections. For instance listening for unsolicited messages + * and then demultiplexing them to the appropriate DC. + */ +public class DcController extends Handler { + private static final boolean DBG = true; + private static final boolean VDBG = false; + + private final Phone mPhone; + private final DcTracker mDct; + private final String mTag; + private final DataServiceManager mDataServiceManager; + private final DcTesterDeactivateAll mDcTesterDeactivateAll; + + // package as its used by Testing code + // @GuardedBy("mDcListAll") + final ArrayList mDcListAll = new ArrayList<>(); + // @GuardedBy("mDcListAll") + private final HashMap mDcListActiveByCid = new HashMap<>(); + // @GuardedBy("mTrafficDescriptorsByCid") + private final HashMap> mTrafficDescriptorsByCid = + new HashMap<>(); + + /** + * Aggregated physical link status from all data connections. This reflects the device's RRC + * connection state. + * If {@link CarrierConfigManager#KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL} is true, + * then This reflects "internet data connection" instead of RRC state. + */ + private @DataCallResponse.LinkStatus int mPhysicalLinkStatus = + DataCallResponse.LINK_STATUS_UNKNOWN; + + private RegistrantList mPhysicalLinkStatusChangedRegistrants = new RegistrantList(); + + /** + * Constructor. + * + * @param name to be used for the Controller + * @param phone the phone associated with Dcc and Dct + * @param dct the DataConnectionTracker associated with Dcc + * @param dataServiceManager the data service manager that manages data services + * @param looper looper for this handler + */ + private DcController(String name, Phone phone, DcTracker dct, + DataServiceManager dataServiceManager, Looper looper) { + super(looper); + mPhone = phone; + mDct = dct; + mTag = name; + mDataServiceManager = dataServiceManager; + + mDcTesterDeactivateAll = (TelephonyUtils.IS_DEBUGGABLE) + ? new DcTesterDeactivateAll(mPhone, DcController.this, this) + : null; + mDataServiceManager.registerForDataCallListChanged(this, + DataConnection.EVENT_DATA_STATE_CHANGED); + } + + public static DcController makeDcc(Phone phone, DcTracker dct, + DataServiceManager dataServiceManager, Looper looper, + String tagSuffix) { + return new DcController("Dcc" + tagSuffix, phone, dct, dataServiceManager, looper); + } + + void addDc(DataConnection dc) { + synchronized (mDcListAll) { + mDcListAll.add(dc); + } + } + + void removeDc(DataConnection dc) { + synchronized (mDcListAll) { + mDcListActiveByCid.remove(dc.mCid); + mDcListAll.remove(dc); + } + synchronized (mTrafficDescriptorsByCid) { + mTrafficDescriptorsByCid.remove(dc.mCid); + } + } + + public void addActiveDcByCid(DataConnection dc) { + if (DBG && dc.mCid < 0) { + log("addActiveDcByCid dc.mCid < 0 dc=" + dc); + } + synchronized (mDcListAll) { + mDcListActiveByCid.put(dc.mCid, dc); + } + updateTrafficDescriptorsForCid(dc.mCid, dc.getTrafficDescriptors()); + } + + DataConnection getActiveDcByCid(int cid) { + synchronized (mDcListAll) { + return mDcListActiveByCid.get(cid); + } + } + + void removeActiveDcByCid(DataConnection dc) { + synchronized (mDcListAll) { + DataConnection removedDc = mDcListActiveByCid.remove(dc.mCid); + if (DBG && removedDc == null) { + log("removeActiveDcByCid removedDc=null dc=" + dc); + } + } + synchronized (mTrafficDescriptorsByCid) { + mTrafficDescriptorsByCid.remove(dc.mCid); + } + } + + boolean isDefaultDataActive() { + synchronized (mDcListAll) { + return mDcListActiveByCid.values().stream() + .anyMatch(dc -> dc.getApnContexts().stream() + .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT)); + } + } + + List getTrafficDescriptorsForCid(int cid) { + synchronized (mTrafficDescriptorsByCid) { + return mTrafficDescriptorsByCid.get(cid); + } + } + + void updateTrafficDescriptorsForCid(int cid, List tds) { + synchronized (mTrafficDescriptorsByCid) { + mTrafficDescriptorsByCid.put(cid, tds); + } + } + + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch (msg.what) { + case DataConnection.EVENT_DATA_STATE_CHANGED: + ar = (AsyncResult) msg.obj; + if (ar.exception == null) { + onDataStateChanged((ArrayList) ar.result); + } else { + log("EVENT_DATA_STATE_CHANGED: exception; likely radio not available, ignore"); + } + break; + default: + loge("Unexpected event " + msg); + break; + } + } + + /** + * Process the new list of "known" Data Calls + * @param dcsList as sent by RIL_UNSOL_DATA_CALL_LIST_CHANGED + */ + private void onDataStateChanged(ArrayList dcsList) { + final HashMap dcListActiveByCid; + synchronized (mDcListAll) { + dcListActiveByCid = new HashMap<>(mDcListActiveByCid); + } + + if (DBG) { + log("onDataStateChanged: dcsList=" + dcsList + + " dcListActiveByCid=" + dcListActiveByCid); + } + + // Create hashmap of cid to DataCallResponse + HashMap dataCallResponseListByCid = new HashMap<>(); + for (DataCallResponse dcs : dcsList) { + dataCallResponseListByCid.put(dcs.getId(), dcs); + } + + // Add a DC that is active but not in the dcsList to the list of DC's to retry + ArrayList dcsToRetry = new ArrayList<>(); + for (DataConnection dc : dcListActiveByCid.values()) { + DataCallResponse response = dataCallResponseListByCid.get(dc.mCid); + if (response == null) { + if (DBG) log("onDataStateChanged: add to retry dc=" + dc); + dcsToRetry.add(dc); + } else { + List oldTds = getTrafficDescriptorsForCid(dc.mCid); + List newTds = response.getTrafficDescriptors(); + if (!oldTds.equals(newTds)) { + if (DBG) { + log("onDataStateChanged: add to retry due to TD changed dc=" + dc + + ", oldTds=" + oldTds + ", newTds=" + newTds); + } + updateTrafficDescriptorsForCid(dc.mCid, newTds); + dcsToRetry.add(dc); + } + } + } + if (DBG) log("onDataStateChanged: dcsToRetry=" + dcsToRetry); + + // Find which connections have changed state and send a notification or cleanup + // and any that are in active need to be retried. + ArrayList apnsToCleanup = new ArrayList(); + + boolean isAnyDataCallDormant = false; + boolean isAnyDataCallActive = false; + boolean isInternetDataCallActive = false; + + for (DataCallResponse newState : dcsList) { + + DataConnection dc = dcListActiveByCid.get(newState.getId()); + if (dc == null) { + // UNSOL_DATA_CALL_LIST_CHANGED arrived before SETUP_DATA_CALL completed. + loge("onDataStateChanged: no associated DC yet, ignore"); + continue; + } + + List apnContexts = dc.getApnContexts(); + if (apnContexts.size() == 0) { + if (DBG) loge("onDataStateChanged: no connected apns, ignore"); + } else { + // Determine if the connection/apnContext should be cleaned up + // or just a notification should be sent out. + if (DBG) { + log("onDataStateChanged: Found ConnId=" + newState.getId() + + " newState=" + newState.toString()); + } + if (apnContexts.stream().anyMatch( + i -> ApnSetting.TYPE_DEFAULT_STRING.equals(i.getApnType())) + && newState.getLinkStatus() == DataConnActiveStatus.ACTIVE) { + isInternetDataCallActive = true; + } + if (newState.getLinkStatus() == DataConnActiveStatus.INACTIVE) { + if (mDct.isCleanupRequired.get()) { + apnsToCleanup.addAll(apnContexts); + mDct.isCleanupRequired.set(false); + } else { + int failCause = DataFailCause.getFailCause(newState.getCause()); + if (DataFailCause.isRadioRestartFailure(mPhone.getContext(), failCause, + mPhone.getSubId())) { + if (DBG) { + log("onDataStateChanged: X restart radio, failCause=" + + failCause); + } + mDct.sendRestartRadio(); + } else if (mDct.isPermanentFailure(failCause)) { + if (DBG) { + log("onDataStateChanged: inactive, add to cleanup list. " + + "failCause=" + failCause); + } + apnsToCleanup.addAll(apnContexts); + } else { + if (DBG) { + log("onDataStateChanged: inactive, add to retry list. " + + "failCause=" + failCause); + } + dcsToRetry.add(dc); + } + } + } else { + // Update the pdu session id + dc.setPduSessionId(newState.getPduSessionId()); + + dc.updatePcscfAddr(newState); + + // Its active so update the DataConnections link properties + UpdateLinkPropertyResult result = dc.updateLinkProperty(newState); + dc.updateResponseFields(newState); + if (result.oldLp.equals(result.newLp)) { + if (DBG) log("onDataStateChanged: no change"); + } else { + if (LinkPropertiesUtils.isIdenticalInterfaceName( + result.oldLp, result.newLp)) { + if (!LinkPropertiesUtils.isIdenticalDnses( + result.oldLp, result.newLp) + || !LinkPropertiesUtils.isIdenticalRoutes( + result.oldLp, result.newLp) + || !LinkPropertiesUtils.isIdenticalHttpProxy( + result.oldLp, result.newLp) + || !LinkPropertiesUtils.isIdenticalAddresses( + result.oldLp, result.newLp)) { + // If the same address type was removed and + // added we need to cleanup + CompareOrUpdateResult car + = new CompareOrUpdateResult( + result.oldLp != null ? + result.oldLp.getLinkAddresses() : null, + result.newLp != null ? + result.newLp.getLinkAddresses() : null, + (la) -> Objects.hash(((LinkAddress)la).getAddress(), + ((LinkAddress)la).getPrefixLength(), + ((LinkAddress)la).getScope())); + if (DBG) { + log("onDataStateChanged: oldLp=" + result.oldLp + + " newLp=" + result.newLp + " car=" + car); + } + boolean needToClean = false; + for (LinkAddress added : car.added) { + for (LinkAddress removed : car.removed) { + if (NetUtils.addressTypeMatches( + removed.getAddress(), + added.getAddress())) { + needToClean = true; + break; + } + } + } + if (needToClean) { + if (DBG) { + log("onDataStateChanged: addr change," + + " cleanup apns=" + apnContexts + + " oldLp=" + result.oldLp + + " newLp=" + result.newLp); + } + apnsToCleanup.addAll(apnContexts); + } + } else { + if (DBG) { + log("onDataStateChanged: no changes"); + } + } + } else { + apnsToCleanup.addAll(apnContexts); + if (DBG) { + log("onDataStateChanged: interface change, cleanup apns=" + + apnContexts); + } + } + } + } + } + + if (newState.getLinkStatus() == DataConnActiveStatus.ACTIVE) { + isAnyDataCallActive = true; + } + if (newState.getLinkStatus() == DataConnActiveStatus.DORMANT) { + isAnyDataCallDormant = true; + } + } + + if (mDataServiceManager.getTransportType() + == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + boolean isPhysicalLinkStatusFocusingOnInternetData = + mDct.getLteEndcUsingUserDataForIdleDetection(); + int physicalLinkStatus = + (isPhysicalLinkStatusFocusingOnInternetData + ? isInternetDataCallActive : isAnyDataCallActive) + ? DataCallResponse.LINK_STATUS_ACTIVE + : DataCallResponse.LINK_STATUS_DORMANT; + if (mPhysicalLinkStatus != physicalLinkStatus) { + mPhysicalLinkStatus = physicalLinkStatus; + mPhysicalLinkStatusChangedRegistrants.notifyResult(mPhysicalLinkStatus); + } + if (isAnyDataCallDormant && !isAnyDataCallActive) { + // There is no way to indicate link activity per APN right now. So + // Link Activity will be considered dormant only when all data calls + // are dormant. + // If a single data call is in dormant state and none of the data + // calls are active broadcast overall link status as dormant. + if (DBG) { + log("onDataStateChanged: Data activity DORMANT. stopNetStatePoll"); + } + mDct.sendStopNetStatPoll(DctConstants.Activity.DORMANT); + } else { + if (DBG) { + log("onDataStateChanged: Data Activity updated to NONE. " + + "isAnyDataCallActive = " + isAnyDataCallActive + + " isAnyDataCallDormant = " + isAnyDataCallDormant); + } + if (isAnyDataCallActive) { + mDct.sendStartNetStatPoll(DctConstants.Activity.NONE); + } + } + } + + if (DBG) { + log("onDataStateChanged: dcsToRetry=" + dcsToRetry + + " apnsToCleanup=" + apnsToCleanup); + } + + // Cleanup connections that have changed + for (ApnContext apnContext : apnsToCleanup) { + mDct.cleanUpConnection(apnContext); + } + + // Retry connections that have disappeared + for (DataConnection dc : dcsToRetry) { + if (DBG) log("onDataStateChanged: send EVENT_LOST_CONNECTION dc.mTag=" + dc.mTag); + dc.sendMessage(DataConnection.EVENT_LOST_CONNECTION, dc.mTag); + } + + if (VDBG) log("onDataStateChanged: X"); + } + + /** + * Register for physical link status (i.e. RRC state) changed event. + * if {@link CarrierConfigManager#KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL} is true, + * then physical link status is focusing on "internet data connection" instead of RRC state. + * @param h The handler + * @param what The event + */ + @VisibleForTesting + public void registerForPhysicalLinkStatusChanged(Handler h, int what) { + mPhysicalLinkStatusChangedRegistrants.addUnique(h, what, null); + } + + /** + * Unregister from physical link status (i.e. RRC state) changed event. + * + * @param h The previously registered handler + */ + void unregisterForPhysicalLinkStatusChanged(Handler h) { + mPhysicalLinkStatusChangedRegistrants.remove(h); + } + + private void log(String s) { + Rlog.d(mTag, s); + } + + private void loge(String s) { + Rlog.e(mTag, s); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + synchronized (mDcListAll) { + sb.append("mDcListAll=").append(mDcListAll) + .append(" mDcListActiveByCid=").append(mDcListActiveByCid); + } + synchronized (mTrafficDescriptorsByCid) { + sb.append("mTrafficDescriptorsByCid=").append(mTrafficDescriptorsByCid); + } + return sb.toString(); + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(" mPhone=" + mPhone); + synchronized (mDcListAll) { + pw.println(" mDcListAll=" + mDcListAll); + pw.println(" mDcListActiveByCid=" + mDcListActiveByCid); + } + synchronized (mTrafficDescriptorsByCid) { + pw.println(" mTrafficDescriptorsByCid=" + mTrafficDescriptorsByCid); + } + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java b/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java new file mode 100644 index 0000000000..3cdd2090d5 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2013 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.dataconnection; + +import android.content.Intent; +import android.telephony.Annotation.DataFailureCause; +import android.telephony.DataFailCause; + +import com.android.telephony.Rlog; + +/** + * A package visible class for supporting testing failing bringUp commands. This + * saves the parameters from a action_fail_bringup intent. See + * {@link DataConnection#doOnConnect} and {@see DcTesterFailBringUpAll} for more info. + */ +public class DcFailBringUp { + private static final String LOG_TAG = "DcFailBringUp"; + private static final boolean DBG = true; + + static final String INTENT_BASE = DataConnection.class.getPackage().getName(); + + static final String ACTION_FAIL_BRINGUP = "action_fail_bringup"; + + // counter with its --ei option name and default value + static final String COUNTER = "counter"; + static final int DEFAULT_COUNTER = 2; + int mCounter; + + // failCause with its --ei option name and default value + static final String FAIL_CAUSE = "fail_cause"; + static final int DEFAULT_FAIL_CAUSE = DataFailCause.ERROR_UNSPECIFIED; + @DataFailureCause + int mFailCause; + + // suggestedRetryTime with its --ei option name and default value + static final String SUGGESTED_RETRY_TIME = "suggested_retry_time"; + static final long DEFAULT_SUGGESTED_RETRY_TIME = -1; + long mSuggestedRetryTime; + + // Get the Extra Intent parameters + void saveParameters(Intent intent, String s) { + if (DBG) log(s + ".saveParameters: action=" + intent.getAction()); + mCounter = intent.getIntExtra(COUNTER, DEFAULT_COUNTER); + mFailCause = DataFailCause.getFailCause( + intent.getIntExtra(FAIL_CAUSE, DEFAULT_FAIL_CAUSE)); + mSuggestedRetryTime = + intent.getLongExtra(SUGGESTED_RETRY_TIME, DEFAULT_SUGGESTED_RETRY_TIME); + if (DBG) { + log(s + ".saveParameters: " + this); + } + } + + public void saveParameters(int counter, @DataFailureCause int failCause, + long suggestedRetryTime) { + mCounter = counter; + mFailCause = DataFailCause.getFailCause(failCause); + mSuggestedRetryTime = suggestedRetryTime; + } + + @Override + public String toString() { + return "{mCounter=" + mCounter + + " mFailCause=" + mFailCause + + " mSuggestedRetryTime=" + mSuggestedRetryTime + "}"; + + } + + private static void log(String s) { + Rlog.d(LOG_TAG, s); + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java new file mode 100644 index 0000000000..c6def34093 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.dataconnection; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.KeepalivePacketData; +import android.net.LinkProperties; +import android.net.NattKeepalivePacketData; +import android.net.NetworkAgent; +import android.net.NetworkAgentConfig; +import android.net.NetworkCapabilities; +import android.net.NetworkProvider; +import android.net.QosFilter; +import android.net.QosSessionAttributes; +import android.net.SocketKeepalive; +import android.net.Uri; +import android.os.Handler; +import android.os.Message; +import android.telephony.AccessNetworkConstants; +import android.telephony.AccessNetworkConstants.TransportType; +import android.telephony.Annotation.NetworkType; +import android.telephony.AnomalyReporter; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.telephony.data.QosBearerSession; +import android.util.LocalLog; +import android.util.SparseArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.DctConstants; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.SlidingWindowEventCounter; +import com.android.internal.telephony.data.KeepaliveStatus; +import com.android.internal.telephony.data.NotifyQosSessionInterface; +import com.android.internal.telephony.data.QosCallbackTracker; +import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.util.IndentingPrintWriter; +import com.android.telephony.Rlog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.net.InetAddress; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * This class represents a network agent which is communication channel between + * {@link DataConnection} and {@link com.android.server.ConnectivityService}. The agent is + * created when data connection enters {@link DataConnection.DcActiveState} until it exits that + * state. + * + * Note that in IWLAN handover scenario, this agent could be transferred to the new + * {@link DataConnection} so for a short window of time this object might be accessed by two + * different {@link DataConnection}. Thus each method in this class needs to be synchronized. + */ +public class DcNetworkAgent extends NetworkAgent implements NotifyQosSessionInterface { + private final String mTag; + + private final int mId; + + private final Phone mPhone; + + private final Handler mHandler; + + private int mTransportType; + + private NetworkCapabilities mNetworkCapabilities; + + public final DcKeepaliveTracker keepaliveTracker = new DcKeepaliveTracker(); + + private final QosCallbackTracker mQosCallbackTracker; + + private final Executor mQosCallbackExecutor = Executors.newSingleThreadExecutor(); + + private DataConnection mDataConnection; + + private final LocalLog mNetCapsLocalLog = new LocalLog(32); + + // For interface duplicate detection. Key is the net id, value is the interface name in string. + private static Map sInterfaceNames = new ConcurrentHashMap<>(); + + private static final long NETWORK_UNWANTED_ANOMALY_WINDOW_MS = TimeUnit.MINUTES.toMillis(5); + private static final int NETWORK_UNWANTED_ANOMALY_NUM_OCCURRENCES = 12; + + private static final int EVENT_UNWANTED_TIMEOUT = 1; + + @VisibleForTesting + public DcNetworkAgent(DataConnection dc, Phone phone, int score, NetworkAgentConfig config, + NetworkProvider networkProvider, int transportType) { + super(phone.getContext(), dc.getHandler().getLooper(), "DcNetworkAgent", + dc.getNetworkCapabilities(), dc.getLinkProperties(), score, config, + networkProvider); + register(); + mId = getNetwork().getNetId(); + mTag = "DcNetworkAgent" + "-" + mId; + mPhone = phone; + mHandler = new Handler(dc.getHandler().getLooper()) { + @Override + public void handleMessage(Message msg) { + if (msg.what == EVENT_UNWANTED_TIMEOUT) { + loge("onNetworkUnwanted timed out. Perform silent de-register."); + logd("Unregister from connectivity service. " + sInterfaceNames.get(mId) + + " removed."); + sInterfaceNames.remove(mId); + DcNetworkAgent.this.unregister(); + } + } + }; + mNetworkCapabilities = dc.getNetworkCapabilities(); + mTransportType = transportType; + mDataConnection = dc; + if (dc.getLinkProperties() != null) { + checkDuplicateInterface(mId, dc.getLinkProperties().getInterfaceName()); + logd("created for data connection " + dc.getName() + ", " + + dc.getLinkProperties().getInterfaceName()); + } else { + loge("The connection does not have a valid link properties."); + } + mQosCallbackTracker = new QosCallbackTracker(this, mPhone); + } + + private @NetworkType int getNetworkType() { + ServiceState ss = mPhone.getServiceState(); + int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + + NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, mTransportType); + if (nri != null) { + networkType = nri.getAccessNetworkTechnology(); + } + + return networkType; + } + + private void checkDuplicateInterface(int netId, @Nullable String interfaceName) { + for (Map.Entry entry: sInterfaceNames.entrySet()) { + if (Objects.equals(interfaceName, entry.getValue())) { + String message = "Duplicate interface " + interfaceName + + " is detected. DcNetworkAgent-" + entry.getKey() + + " already used this interface name."; + loge(message); + // Using fixed UUID to avoid duplicate bugreport notification + AnomalyReporter.reportAnomaly( + UUID.fromString("02f3d3f6-4613-4415-b6cb-8d92c8a938a6"), + message, mPhone.getCarrierId()); + return; + } + } + sInterfaceNames.put(netId, interfaceName); + } + + /** + * @return The tag + */ + String getTag() { + return mTag; + } + + /** + * Set the data connection that owns this network agent. + * + * @param dc Data connection owning this network agent. + * @param transportType Transport that this data connection is on. + */ + public synchronized void acquireOwnership(@NonNull DataConnection dc, + @TransportType int transportType) { + mDataConnection = dc; + mTransportType = transportType; + logd(dc.getName() + " acquired the ownership of this agent."); + } + + /** + * Release the ownership of network agent. + */ + public synchronized void releaseOwnership(DataConnection dc) { + if (mDataConnection == null) { + loge("releaseOwnership called on no-owner DcNetworkAgent!"); + return; + } else if (mDataConnection != dc) { + loge("releaseOwnership: This agent belongs to " + + mDataConnection.getName() + ", ignored the request from " + dc.getName()); + return; + } + logd("Data connection " + mDataConnection.getName() + " released the ownership."); + mDataConnection = null; + } + + /** + * @return The data connection that owns this agent + */ + public synchronized DataConnection getDataConnection() { + return mDataConnection; + } + + private static final SlidingWindowEventCounter sNetworkUnwantedCounter = + new SlidingWindowEventCounter(NETWORK_UNWANTED_ANOMALY_WINDOW_MS, + NETWORK_UNWANTED_ANOMALY_NUM_OCCURRENCES); + + @Override + public synchronized void onNetworkUnwanted() { + mHandler.sendEmptyMessageDelayed(EVENT_UNWANTED_TIMEOUT, TimeUnit.SECONDS.toMillis(30)); + trackNetworkUnwanted(); + if (mDataConnection == null) { + loge("onNetworkUnwanted found called on no-owner DcNetworkAgent!"); + return; + } + + logd("onNetworkUnwanted called. Now tear down the data connection " + + mDataConnection.getName()); + mDataConnection.tearDownAll(Phone.REASON_RELEASED_BY_CONNECTIVITY_SERVICE, + DcTracker.RELEASE_TYPE_DETACH, null); + } + + /** + * There have been several bugs where a RECONNECT loop kicks off where a DataConnection + * connects to the Network, ConnectivityService indicates that the Network is unwanted, + * and then the DataConnection reconnects. By the time we get the bug report it's too late + * because there have already been hundreds of RECONNECTS. This is meant to capture the issue + * when it first starts. + * + * The unwanted counter is configured to only take an anomaly report in extreme cases. + * This is to avoid having the anomaly message show up on several devices. + * + * This is directly related to b/175845538. But, there have been several other occurrences of + * this issue. + */ + private void trackNetworkUnwanted() { + if (sNetworkUnwantedCounter.addOccurrence()) { + AnomalyReporter.reportAnomaly( + UUID.fromString("3f578b5c-64e9-11eb-ae93-0242ac130002"), + "Network Unwanted called 12 times in 5 minutes.", mPhone.getCarrierId()); + } + } + + @Override + public synchronized void onBandwidthUpdateRequested() { + if (mDataConnection == null) { + loge("onBandwidthUpdateRequested called on no-owner DcNetworkAgent!"); + return; + } + + if (mPhone.getLceStatus() == RILConstants.LCE_ACTIVE // active LCE service + && mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + mPhone.mCi.pullLceData(mDataConnection.obtainMessage( + DataConnection.EVENT_BW_REFRESH_RESPONSE)); + } + } + + @Override + public synchronized void onValidationStatus(int status, Uri redirectUri) { + if (mDataConnection == null) { + loge("onValidationStatus called on no-owner DcNetworkAgent!"); + return; + } + + logd("validation status: " + status + " with redirection URL: " + redirectUri); + DcTracker dct = mPhone.getDcTracker(mTransportType); + if (dct != null) { + Message msg = dct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, + status, mDataConnection.getCid(), redirectUri.toString()); + msg.sendToTarget(); + } + } + + private synchronized boolean isOwned(DataConnection dc, String reason) { + if (mDataConnection == null) { + loge(reason + " called on no-owner DcNetworkAgent!"); + return false; + } else if (mDataConnection != dc) { + loge(reason + ": This agent belongs to " + + mDataConnection.getName() + ", ignored the request from " + dc.getName()); + return false; + } + return true; + } + + /** + * Update the legacy sub type (i.e. data network type). + * + * @param dc The data connection that invokes this method. + */ + public synchronized void updateLegacySubtype(DataConnection dc) { + if (!isOwned(dc, "updateLegacySubtype")) return; + + int networkType = getNetworkType(); + setLegacySubtype(networkType, TelephonyManager.getNetworkTypeName(networkType)); + } + + /** + * Set the network capabilities. + * + * @param networkCapabilities The network capabilities. + * @param dc The data connection that invokes this method. + */ + public synchronized void sendNetworkCapabilities(NetworkCapabilities networkCapabilities, + DataConnection dc) { + if (!isOwned(dc, "sendNetworkCapabilities")) return; + + if (!networkCapabilities.equals(mNetworkCapabilities)) { + String logStr = "Changed from " + mNetworkCapabilities + " to " + + networkCapabilities + ", Data RAT=" + + mPhone.getServiceState().getRilDataRadioTechnology() + + ", dc=" + mDataConnection.getName(); + logd(logStr); + mNetCapsLocalLog.log(logStr); + if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + // only log metrics for DataConnection with NET_CAPABILITY_INTERNET + if (mNetworkCapabilities == null + || networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) + != mNetworkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)) { + TelephonyMetrics.getInstance().writeNetworkCapabilitiesChangedEvent( + mPhone.getPhoneId(), networkCapabilities); + } + } + mNetworkCapabilities = networkCapabilities; + } + sendNetworkCapabilities(networkCapabilities); + } + + /** + * Set the link properties + * + * @param linkProperties The link properties + * @param dc The data connection that invokes this method. + */ + public synchronized void sendLinkProperties(@NonNull LinkProperties linkProperties, + DataConnection dc) { + if (!isOwned(dc, "sendLinkProperties")) return; + + sInterfaceNames.put(mId, dc.getLinkProperties().getInterfaceName()); + sendLinkProperties(linkProperties); + } + + /** + * Set the network score. + * + * @param score The network score. + * @param dc The data connection that invokes this method. + */ + public synchronized void sendNetworkScore(int score, DataConnection dc) { + if (!isOwned(dc, "sendNetworkScore")) return; + sendNetworkScore(score); + } + + /** + * Unregister the network agent from connectivity service. + * + * @param dc The data connection that invokes this method. + */ + public synchronized void unregister(DataConnection dc) { + if (!isOwned(dc, "unregister")) return; + + mHandler.removeMessages(EVENT_UNWANTED_TIMEOUT); + logd("Unregister from connectivity service. " + sInterfaceNames.get(mId) + " removed."); + sInterfaceNames.remove(mId); + super.unregister(); + } + + @Override + public synchronized void onStartSocketKeepalive(int slot, @NonNull Duration interval, + @NonNull KeepalivePacketData packet) { + if (mDataConnection == null) { + loge("onStartSocketKeepalive called on no-owner DcNetworkAgent!"); + return; + } + + if (packet instanceof NattKeepalivePacketData) { + mDataConnection.obtainMessage(DataConnection.EVENT_KEEPALIVE_START_REQUEST, + slot, (int) interval.getSeconds(), packet).sendToTarget(); + } else { + sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED); + } + } + + @Override + public synchronized void onStopSocketKeepalive(int slot) { + if (mDataConnection == null) { + loge("onStopSocketKeepalive called on no-owner DcNetworkAgent!"); + return; + } + + mDataConnection.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slot) + .sendToTarget(); + } + + @Override + public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) { + mQosCallbackExecutor.execute(() -> mQosCallbackTracker.addFilter(qosCallbackId, + new QosCallbackTracker.IFilter() { + @Override + public boolean matchesLocalAddress( + InetAddress address, int startPort, int endPort) { + return filter.matchesLocalAddress(address, startPort, endPort); + } + + @Override + public boolean matchesRemoteAddress( + InetAddress address, int startPort, int endPort) { + return filter.matchesRemoteAddress(address, startPort, endPort); + } + })); + } + + @Override + public void onQosCallbackUnregistered(final int qosCallbackId) { + mQosCallbackExecutor.execute(() -> mQosCallbackTracker.removeFilter(qosCallbackId)); + } + + void updateQosBearerSessions(final List qosBearerSessions) { + mQosCallbackExecutor.execute(() -> mQosCallbackTracker.updateSessions(qosBearerSessions)); + } + + @Override + public void notifyQosSessionAvailable(final int qosCallbackId, final int sessionId, + @NonNull final QosSessionAttributes attributes) { + super.sendQosSessionAvailable(qosCallbackId, sessionId, attributes); + } + + @Override + public void notifyQosSessionLost(final int qosCallbackId, + final int sessionId, final int qosSessionType) { + super.sendQosSessionLost(qosCallbackId, sessionId, qosSessionType); + } + + @Override + public String toString() { + return "DcNetworkAgent-" + + mId + + " mDataConnection=" + + ((mDataConnection != null) ? mDataConnection.getName() : null) + + " mTransportType=" + + AccessNetworkConstants.transportTypeToString(mTransportType) + + " " + ((mDataConnection != null) ? mDataConnection.getLinkProperties() : null) + + " mNetworkCapabilities=" + mNetworkCapabilities; + } + + /** + * Dump the state of transport manager + * + * @param fd File descriptor + * @param printWriter Print writer + * @param args Arguments + */ + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.println(toString()); + pw.increaseIndent(); + pw.println("Net caps logs:"); + mNetCapsLocalLog.dump(fd, pw, args); + pw.decreaseIndent(); + } + + /** + * Log with debug level + * + * @param s is string log + */ + private void logd(String s) { + Rlog.d(mTag, s); + } + + /** + * Log with error level + * + * @param s is string log + */ + private void loge(String s) { + Rlog.e(mTag, s); + } + + class DcKeepaliveTracker { + private class KeepaliveRecord { + public int slotId; + public int currentStatus; + + KeepaliveRecord(int slotId, int status) { + this.slotId = slotId; + this.currentStatus = status; + } + } + + private final SparseArray mKeepalives = new SparseArray(); + + int getHandleForSlot(int slotId) { + for (int i = 0; i < mKeepalives.size(); i++) { + KeepaliveRecord kr = mKeepalives.valueAt(i); + if (kr.slotId == slotId) return mKeepalives.keyAt(i); + } + return -1; + } + + 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; + } + } + + void handleKeepaliveStarted(final int slot, KeepaliveStatus ks) { + switch (ks.statusCode) { + case KeepaliveStatus.STATUS_INACTIVE: + DcNetworkAgent.this.sendSocketKeepaliveEvent(slot, + keepaliveStatusErrorToPacketKeepaliveError(ks.errorCode)); + break; + case KeepaliveStatus.STATUS_ACTIVE: + DcNetworkAgent.this.sendSocketKeepaliveEvent( + slot, SocketKeepalive.SUCCESS); + // fall through to add record + case KeepaliveStatus.STATUS_PENDING: + logd("Adding keepalive handle=" + + ks.sessionHandle + " slot = " + slot); + mKeepalives.put(ks.sessionHandle, + new KeepaliveRecord( + slot, ks.statusCode)); + break; + default: + logd("Invalid KeepaliveStatus Code: " + ks.statusCode); + break; + } + } + + void handleKeepaliveStatus(KeepaliveStatus ks) { + final KeepaliveRecord kr; + kr = mKeepalives.get(ks.sessionHandle); + + if (kr == null) { + // If there is no slot for the session handle, we received an event + // for a different data connection. This is not an error because the + // keepalive session events are broadcast to all listeners. + loge("Discarding keepalive event for different data connection:" + ks); + return; + } + // Switch on the current state, to see what we do with the status update + switch (kr.currentStatus) { + case KeepaliveStatus.STATUS_INACTIVE: + logd("Inactive Keepalive received status!"); + DcNetworkAgent.this.sendSocketKeepaliveEvent( + kr.slotId, SocketKeepalive.ERROR_HARDWARE_ERROR); + break; + case KeepaliveStatus.STATUS_PENDING: + switch (ks.statusCode) { + case KeepaliveStatus.STATUS_INACTIVE: + DcNetworkAgent.this.sendSocketKeepaliveEvent(kr.slotId, + keepaliveStatusErrorToPacketKeepaliveError(ks.errorCode)); + kr.currentStatus = KeepaliveStatus.STATUS_INACTIVE; + mKeepalives.remove(ks.sessionHandle); + break; + case KeepaliveStatus.STATUS_ACTIVE: + logd("Pending Keepalive received active status!"); + kr.currentStatus = KeepaliveStatus.STATUS_ACTIVE; + DcNetworkAgent.this.sendSocketKeepaliveEvent( + kr.slotId, SocketKeepalive.SUCCESS); + break; + case KeepaliveStatus.STATUS_PENDING: + loge("Invalid unsolicied Keepalive Pending Status!"); + break; + default: + loge("Invalid Keepalive Status received, " + ks.statusCode); + } + break; + case KeepaliveStatus.STATUS_ACTIVE: + switch (ks.statusCode) { + case KeepaliveStatus.STATUS_INACTIVE: + logd("Keepalive received stopped status!"); + DcNetworkAgent.this.sendSocketKeepaliveEvent( + kr.slotId, SocketKeepalive.SUCCESS); + + kr.currentStatus = KeepaliveStatus.STATUS_INACTIVE; + mKeepalives.remove(ks.sessionHandle); + break; + case KeepaliveStatus.STATUS_PENDING: + case KeepaliveStatus.STATUS_ACTIVE: + loge("Active Keepalive received invalid status!"); + break; + default: + loge("Invalid Keepalive Status received, " + ks.statusCode); + } + break; + default: + loge("Invalid Keepalive Status received, " + kr.currentStatus); + } + } + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcRequest.java b/src/java/com/android/internal/telephony/dataconnection/DcRequest.java new file mode 100644 index 0000000000..da775e82f5 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DcRequest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2006 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.dataconnection; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.NetworkRequest; +import android.net.NetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; +import android.telephony.Annotation.ApnType; + +import com.android.telephony.Rlog; + +/** + * Wraps cellular network requests to configured apn types. + */ +public class DcRequest implements Comparable { + private static final String LOG_TAG = "DcRequest"; + + @NonNull + public final NetworkRequest networkRequest; + public final int priority; + public final @ApnType int apnType; + + private DcRequest(@NonNull final NetworkRequest nr, @ApnType final int type, + int apnPriority) { + networkRequest = nr; + priority = apnPriority; + apnType = type; + } + + /** + * Create a DcRequest based off of the network request. If the network request is not cellular, + * then null is returned and a warning is generated. + * @param networkRequest sets the type of dc request + * @param apnConfigTypeRepository apn config types to match on the network request + * @return corresponding DcRequest + * + */ + @Nullable + public static DcRequest create(@NonNull final NetworkRequest networkRequest, + @NonNull final ApnConfigTypeRepository apnConfigTypeRepository) { + final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest); + final ApnConfigType apnConfigType = apnConfigTypeRepository.getByType(apnType); + if (apnConfigType == null) { + Rlog.d(LOG_TAG, "Non cellular request ignored: " + networkRequest.toString()); + checkForAnomalousNetworkRequest(networkRequest); + return null; + } else { + Rlog.d(LOG_TAG, "Cellular request confirmed: " + networkRequest.toString()); + return new DcRequest(networkRequest, apnType, apnConfigType.getPriority()); + } + } + + private static void checkForAnomalousNetworkRequest(NetworkRequest networkRequest) { + NetworkSpecifier specifier = networkRequest.getNetworkSpecifier(); + if (specifier != null) { + if (specifier instanceof TelephonyNetworkSpecifier) { + reportAnomalousNetworkRequest(networkRequest); + } + } + } + + private static void reportAnomalousNetworkRequest(NetworkRequest networkRequest) { + //TODO: Report anomaly if this happens + Rlog.w(LOG_TAG, "A TelephonyNetworkSpecifier for a non-cellular request is invalid: " + + networkRequest.toString()); + + } + + public String toString() { + return networkRequest.toString() + ", priority=" + priority + ", apnType=" + apnType; + } + + public int hashCode() { + return networkRequest.hashCode(); + } + + public boolean equals(Object o) { + if (o instanceof DcRequest) { + return networkRequest.equals(((DcRequest)o).networkRequest); + } + return false; + } + + public int compareTo(DcRequest o) { + return o.priority - priority; + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java new file mode 100644 index 0000000000..11a0ae67e0 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2013 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.dataconnection; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.util.TelephonyUtils; +import com.android.telephony.Rlog; + +/** + * To bring down all DC's send the following intent: + * + * adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_deactivate_all + */ +public class DcTesterDeactivateAll { + private static final String LOG_TAG = "DcTesterDeacativateAll"; + private static final boolean DBG = true; + + private Phone mPhone; + private DcController mDcc; + + public static String sActionDcTesterDeactivateAll = + "com.android.internal.telephony.dataconnection.action_deactivate_all"; + + + // The static intent receiver one for all instances and we assume this + // is running on the same thread as Dcc. + protected BroadcastReceiver sIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (DBG) log("sIntentReceiver.onReceive: action=" + action); + if (action.equals(sActionDcTesterDeactivateAll) + || action.equals(mPhone.getActionDetached())) { + log("Send DEACTIVATE to all Dcc's"); + if (mDcc != null) { + for (DataConnection dc : mDcc.mDcListAll) { + dc.tearDownNow(); + } + } else { + if (DBG) log("onReceive: mDcc is null, ignoring"); + } + } else { + if (DBG) log("onReceive: unknown action=" + action); + } + } + }; + + DcTesterDeactivateAll(Phone phone, DcController dcc, Handler handler) { + mPhone = phone; + mDcc = dcc; + + if (TelephonyUtils.IS_DEBUGGABLE) { + IntentFilter filter = new IntentFilter(); + + filter.addAction(sActionDcTesterDeactivateAll); + log("register for intent action=" + sActionDcTesterDeactivateAll); + + filter.addAction(mPhone.getActionDetached()); + log("register for intent action=" + mPhone.getActionDetached()); + + phone.getContext().registerReceiver(sIntentReceiver, filter, null, handler, + Context.RECEIVER_EXPORTED); + } + } + + void dispose() { + if (TelephonyUtils.IS_DEBUGGABLE) { + mPhone.getContext().unregisterReceiver(sIntentReceiver); + } + } + + private static void log(String s) { + Rlog.d(LOG_TAG, s); + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java new file mode 100644 index 0000000000..788da297eb --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2013 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.dataconnection; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.telephony.DataFailCause; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.util.TelephonyUtils; +import com.android.telephony.Rlog; + +/** + * A package level call that causes all DataConnection bringUp calls to fail a specific + * number of times. Here is an example that sets counter to 2 and cause to -3 for all instances: + * adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_fail_bringup \ + * --ei counter 2 --ei fail_cause -3 + * + * Also you can add a suggested retry time if desired: + * --ei suggested_retry_time 5000 + * + * The fail_cause is one of {@link DataFailCause} + */ +public class DcTesterFailBringUpAll { + private static final String LOG_TAG = "DcTesterFailBrinupAll"; + private static final boolean DBG = true; + + private Phone mPhone; + + private String mActionFailBringUp = DcFailBringUp.INTENT_BASE + "." + + DcFailBringUp.ACTION_FAIL_BRINGUP; + + // The saved FailBringUp data from the intent + private DcFailBringUp mFailBringUp = new DcFailBringUp(); + + // The static intent receiver one for all instances. + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (DBG) log("sIntentReceiver.onReceive: action=" + action); + if (action.equals(mActionFailBringUp)) { + mFailBringUp.saveParameters(intent, "sFailBringUp"); + } else if (action.equals(mPhone.getActionDetached())) { + // Counter is MAX, bringUp/retry will always fail + log("simulate detaching"); + mFailBringUp.saveParameters(Integer.MAX_VALUE, + DataFailCause.LOST_CONNECTION, + DcFailBringUp.DEFAULT_SUGGESTED_RETRY_TIME); + } else if (action.equals(mPhone.getActionAttached())) { + // Counter is 0 next bringUp/retry will succeed + log("simulate attaching"); + mFailBringUp.saveParameters(0, DataFailCause.NONE, + DcFailBringUp.DEFAULT_SUGGESTED_RETRY_TIME); + } else { + if (DBG) log("onReceive: unknown action=" + action); + } + } + }; + + DcTesterFailBringUpAll(Phone phone, Handler handler) { + mPhone = phone; + if (TelephonyUtils.IS_DEBUGGABLE) { + IntentFilter filter = new IntentFilter(); + + filter.addAction(mActionFailBringUp); + log("register for intent action=" + mActionFailBringUp); + + filter.addAction(mPhone.getActionDetached()); + log("register for intent action=" + mPhone.getActionDetached()); + + filter.addAction(mPhone.getActionAttached()); + log("register for intent action=" + mPhone.getActionAttached()); + + phone.getContext().registerReceiver(mIntentReceiver, filter, null, handler, + Context.RECEIVER_EXPORTED); + } + } + + void dispose() { + if (TelephonyUtils.IS_DEBUGGABLE) { + mPhone.getContext().unregisterReceiver(mIntentReceiver); + } + } + + public DcFailBringUp getDcFailBringUp() { + return mFailBringUp; + } + + private void log(String s) { + Rlog.d(LOG_TAG, s); + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java new file mode 100755 index 0000000000..28f69dcdc9 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java @@ -0,0 +1,5665 @@ +/* + * Copyright (C) 2006 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.dataconnection; + +import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; +import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED; +import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; +import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; +import static android.telephony.TelephonyManager.NETWORK_TYPE_NR; +import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_DO_FALLBACK; +import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY; +import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL; + +import static com.android.internal.telephony.RILConstants.DATA_PROFILE_DEFAULT; +import static com.android.internal.telephony.RILConstants.DATA_PROFILE_INVALID; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AlarmManager; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.ProgressDialog; +import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.database.Cursor; +import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.NetworkAgent; +import android.net.NetworkCapabilities; +import android.net.NetworkPolicyManager; +import android.net.NetworkRequest; +import android.net.TrafficStats; +import android.net.Uri; +import android.os.AsyncResult; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; +import android.os.PersistableBundle; +import android.os.RegistrantList; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.os.UserHandle; +import android.preference.PreferenceManager; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.provider.Telephony; +import android.telephony.AccessNetworkConstants; +import android.telephony.AccessNetworkConstants.TransportType; +import android.telephony.Annotation.ApnType; +import android.telephony.Annotation.DataFailureCause; +import android.telephony.Annotation.NetworkType; +import android.telephony.CarrierConfigManager; +import android.telephony.CellLocation; +import android.telephony.DataFailCause; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.PcoData; +import android.telephony.PreciseDataConnectionState; +import android.telephony.ServiceState; +import android.telephony.ServiceState.RilRadioTechnology; +import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionPlan; +import android.telephony.TelephonyDisplayInfo; +import android.telephony.TelephonyFrameworkInitializer; +import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.SimState; +import android.telephony.cdma.CdmaCellLocation; +import android.telephony.data.ApnSetting; +import android.telephony.data.DataCallResponse; +import android.telephony.data.DataCallResponse.HandoverFailureMode; +import android.telephony.data.DataProfile; +import android.telephony.data.ThrottleStatus; +import android.telephony.gsm.GsmCellLocation; +import android.text.TextUtils; +import android.util.EventLog; +import android.util.LocalLog; +import android.util.Log; +import android.util.Pair; +import android.util.SparseArray; +import android.view.WindowManager; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.DctConstants; +import com.android.internal.telephony.EventLogTags; +import com.android.internal.telephony.GsmCdmaPhone; +import com.android.internal.telephony.ITelephony; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.RetryManager; +import com.android.internal.telephony.SettingsObserver; +import com.android.internal.telephony.SubscriptionInfoUpdater; +import com.android.internal.telephony.data.DataConfigManager; +import com.android.internal.telephony.data.PhoneSwitcher; +import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataAllowedReasonType; +import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType; +import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason; +import com.android.internal.telephony.metrics.DataStallRecoveryStats; +import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.util.ArrayUtils; +import com.android.internal.telephony.util.NotificationChannelController; +import com.android.internal.telephony.util.TelephonyUtils; +import com.android.internal.util.AsyncChannel; +import com.android.telephony.Rlog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * {@hide} + */ +public class DcTracker extends Handler { + protected static final boolean DBG = true; + private static final boolean VDBG = false; // STOPSHIP if true + private static final boolean VDBG_STALL = false; // STOPSHIP if true + private static final boolean RADIO_TESTS = false; + private static final String NOTIFICATION_TAG = DcTracker.class.getSimpleName(); + + @IntDef(value = { + REQUEST_TYPE_NORMAL, + REQUEST_TYPE_HANDOVER, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface RequestNetworkType {} + + /** + * Normal request for {@link #requestNetwork(NetworkRequest, int, Message)}. For request + * network, this adds the request to the {@link ApnContext}. If there were no network request + * attached to the {@link ApnContext} earlier, this request setups a data connection. + */ + public static final int REQUEST_TYPE_NORMAL = 1; + + /** + * Handover request for {@link #requestNetwork(NetworkRequest, int, Message)} or + * {@link #releaseNetwork(NetworkRequest, int)}. For request network, this + * initiates the handover data setup process. The existing data connection will be seamlessly + * handover to the new network. For release network, this performs a data connection softly + * clean up at the underlying layer (versus normal data release). + */ + public static final int REQUEST_TYPE_HANDOVER = 2; + + @IntDef(value = { + RELEASE_TYPE_NORMAL, + RELEASE_TYPE_DETACH, + RELEASE_TYPE_HANDOVER, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ReleaseNetworkType {} + + /** + * For release network, this is just removing the network request from the {@link ApnContext}. + * Note this does not tear down the physical data connection. Normally the data connection is + * torn down by connectivity service directly calling {@link NetworkAgent#unwanted()}. + */ + public static final int RELEASE_TYPE_NORMAL = 1; + + /** + * Detach request for {@link #releaseNetwork(NetworkRequest, int)} only. This + * forces the APN context detach from the data connection. If this {@link ApnContext} is the + * last one attached to the data connection, the data connection will be torn down, otherwise + * the data connection remains active. + */ + public static final int RELEASE_TYPE_DETACH = 2; + + /** + * Handover request for {@link #releaseNetwork(NetworkRequest, int)}. For release + * network, this performs a data connection softly clean up at the underlying layer (versus + * normal data release). + */ + public static final int RELEASE_TYPE_HANDOVER = 3; + + /** The extras for handover completion message */ + public static final String DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST = "extra_network_request"; + public static final String DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE = "extra_transport_type"; + public static final String DATA_COMPLETE_MSG_EXTRA_SUCCESS = "extra_success"; + /** + * The flag indicates whether after handover failure, the data connection should remain on the + * original transport. + */ + public static final String DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK = + "extra_handover_failure_fallback"; + + private final String mLogTag; + + public AtomicBoolean isCleanupRequired = new AtomicBoolean(false); + + private final TelephonyManager mTelephonyManager; + + private final AlarmManager mAlarmManager; + + /* Currently requested APN type (TODO: This should probably be a parameter not a member) */ + private int mRequestedApnType = ApnSetting.TYPE_DEFAULT; + + // All data enabling/disabling related settings + private final DataEnabledSettings mDataEnabledSettings; + + /** + * After detecting a potential connection problem, this is the max number + * of subsequent polls before attempting recovery. + */ + // 1 sec. default polling interval when screen is on. + private static final int POLL_NETSTAT_MILLIS = 1000; + // 10 min. default polling interval when screen is off. + private static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; + // Default sent packets without ack which triggers initial recovery steps + private static final int NUMBER_SENT_PACKETS_OF_HANG = 10; + + // Default for the data stall alarm while non-aggressive stall detection + private static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6; + // Default for the data stall alarm for aggressive stall detection + private static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60; + + private static final boolean DATA_STALL_SUSPECTED = true; + protected static final boolean DATA_STALL_NOT_SUSPECTED = false; + + private static final String INTENT_DATA_STALL_ALARM = + "com.android.internal.telephony.data-stall"; + // Tag for tracking stale alarms + private static final String INTENT_DATA_STALL_ALARM_EXTRA_TAG = "data_stall_alarm_extra_tag"; + private static final String INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE = + "data_stall_alarm_extra_transport_type"; + + // Unique id for no data notification on setup data permanently failed. + private static final int NO_DATA_NOTIFICATION = 1001; + + /** The higher index has higher priority. */ + private static final DctConstants.State[] DATA_CONNECTION_STATE_PRIORITIES = { + DctConstants.State.IDLE, + DctConstants.State.DISCONNECTING, + DctConstants.State.CONNECTING, + DctConstants.State.CONNECTED, + }; + + private DcTesterFailBringUpAll mDcTesterFailBringUpAll; + private DcController mDcc; + + /** kept in sync with mApnContexts + * Higher numbers are higher priority and sorted so highest priority is first */ + private ArrayList mPrioritySortedApnContexts = new ArrayList<>(); + + /** all APN settings applicable to the current carrier */ + private ArrayList mAllApnSettings = new ArrayList<>(); + + /** preferred apn */ + private ApnSetting mPreferredApn = null; + + /** Is packet service restricted by network */ + private boolean mIsPsRestricted = false; + + /** emergency apn Setting*/ + private ApnSetting mEmergencyApn = null; + + /* Once disposed dont handle any messages */ + private boolean mIsDisposed = false; + + private ContentResolver mResolver; + + /* Set to true with CMD_ENABLE_MOBILE_PROVISIONING */ + private boolean mIsProvisioning = false; + + /* The Url passed as object parameter in CMD_ENABLE_MOBILE_PROVISIONING */ + private String mProvisioningUrl = null; + + /* Indicating data service is bound or not */ + private boolean mDataServiceBound = false; + + /* Intent to hide/show the sign-in error notification for provisioning */ + private static final String INTENT_PROVISION = "com.android.internal.telephony.PROVISION"; + + /** + * Extra containing the phone ID for INTENT_PROVISION + * Must be kept consistent with NetworkNotificationManager#setProvNotificationVisible. + * TODO: refactor the deprecated API to prevent hardcoding values. + */ + private static final String EXTRA_PROVISION_PHONE_ID = "provision.phone.id"; + + /* Intent for the provisioning apn alarm */ + private static final String INTENT_PROVISIONING_APN_ALARM = + "com.android.internal.telephony.provisioning_apn_alarm"; + + /* Tag for tracking stale alarms */ + private static final String PROVISIONING_APN_ALARM_TAG_EXTRA = "provisioning.apn.alarm.tag"; + + /* Debug property for overriding the PROVISIONING_APN_ALARM_DELAY_IN_MS */ + private static final String DEBUG_PROV_APN_ALARM = "persist.debug.prov_apn_alarm"; + + /* Default for the provisioning apn alarm timeout */ + private static final int PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT = 1000 * 60 * 15; + + /* The provision apn alarm intent used to disable the provisioning apn */ + private PendingIntent mProvisioningApnAlarmIntent = null; + + /* Used to track stale provisioning apn alarms */ + private int mProvisioningApnAlarmTag = (int) SystemClock.elapsedRealtime(); + + private AsyncChannel mReplyAc = new AsyncChannel(); + + private final LocalLog mDataRoamingLeakageLog = new LocalLog(32); + private final LocalLog mApnSettingsInitializationLog = new LocalLog(32); + + /* 5G connection reevaluation watchdog alarm constants */ + private long mWatchdogTimeMs = 1000 * 60 * 60; + private boolean mWatchdog = false; + + /* Default for whether 5G frequencies are considered unmetered */ + private boolean mNrNsaAllUnmetered = false; + private boolean mNrNsaMmwaveUnmetered = false; + private boolean mNrNsaSub6Unmetered = false; + private boolean mNrSaAllUnmetered = false; + private boolean mNrSaMmwaveUnmetered = false; + private boolean mNrSaSub6Unmetered = false; + private boolean mNrNsaRoamingUnmetered = false; + + // it effect the PhysicalLinkStatusChanged + private boolean mLteEndcUsingUserDataForRrcDetection = false; + + /* List of SubscriptionPlans, updated when initialized and when plans are changed. */ + private List mSubscriptionPlans = new ArrayList<>(); + /* List of network types an unmetered override applies to, set by onSubscriptionOverride + * and cleared when the device is rebooted or the override expires. */ + private List mUnmeteredNetworkTypes = null; + /* List of network types a congested override applies to, set by onSubscriptionOverride + * and cleared when the device is rebooted or the override expires. */ + private List mCongestedNetworkTypes = null; + /* Whether an unmetered override is currently active. */ + private boolean mUnmeteredOverride = false; + /* Whether a congested override is currently active. */ + private boolean mCongestedOverride = false; + + @SimState + private int mSimState = TelephonyManager.SIM_STATE_UNKNOWN; + + private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver () { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + + if (action.equals(Intent.ACTION_SCREEN_ON)) { + // TODO: Evaluate hooking this up with DeviceStateMonitor + if (DBG) log("screen on"); + mIsScreenOn = true; + stopNetStatPoll(); + startNetStatPoll(); + restartDataStallAlarm(); + } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { + if (DBG) log("screen off"); + mIsScreenOn = false; + stopNetStatPoll(); + startNetStatPoll(); + restartDataStallAlarm(); + } else if (action.equals(INTENT_DATA_STALL_ALARM)) { + onActionIntentDataStallAlarm(intent); + } else if (action.equals(INTENT_PROVISIONING_APN_ALARM)) { + if (DBG) log("Provisioning apn alarm"); + onActionIntentProvisioningApnAlarm(intent); + } else if (action.equals(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED) + || action.equals(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)) { + if (mPhone.getPhoneId() == intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, + SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { + int simState = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE, + TelephonyManager.SIM_STATE_UNKNOWN); + sendMessage(obtainMessage(DctConstants.EVENT_SIM_STATE_UPDATED, simState, 0)); + } + } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { + if (mPhone.getPhoneId() == intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, + SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { + if (intent.getBooleanExtra( + CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, false)) { + // Ignore the rebroadcast one to prevent multiple carrier config changed + // event during boot up. + return; + } + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (SubscriptionManager.isValidSubscriptionId(subId)) { + sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); + } + } + } else { + if (DBG) log("onReceive: Unknown action=" + action); + } + } + }; + + private final Runnable mPollNetStat = new Runnable() { + @Override + public void run() { + updateDataActivity(); + + if (mIsScreenOn) { + mNetStatPollPeriod = Settings.Global.getInt(mResolver, + Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); + } else { + mNetStatPollPeriod = Settings.Global.getInt(mResolver, + Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, + POLL_NETSTAT_SCREEN_OFF_MILLIS); + } + + if (mNetStatPollEnabled) { + mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod); + } + } + }; + + private class ThrottleStatusChangedCallback implements DataThrottler.Callback { + @Override + public void onThrottleStatusChanged(List throttleStatuses) { + for (ThrottleStatus status : throttleStatuses) { + if (status.getThrottleType() == ThrottleStatus.THROTTLE_TYPE_NONE) { + setupDataOnConnectableApn(mApnContextsByType.get(status.getApnType()), + Phone.REASON_DATA_UNTHROTTLED, + RetryFailures.ALWAYS); + } + } + } + } + + private NetworkPolicyManager mNetworkPolicyManager; + private final NetworkPolicyManager.SubscriptionCallback mSubscriptionCallback = + new NetworkPolicyManager.SubscriptionCallback() { + @Override + public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, + int[] networkTypes) { + if (mPhone == null || mPhone.getSubId() != subId) return; + + List tempList = new ArrayList<>(); + for (int networkType : networkTypes) { + tempList.add(networkType); + } + + log("Subscription override: overrideMask=" + overrideMask + + ", overrideValue=" + overrideValue + ", networkTypes=" + tempList); + + if (overrideMask == SUBSCRIPTION_OVERRIDE_UNMETERED) { + mUnmeteredNetworkTypes = tempList; + mUnmeteredOverride = overrideValue != 0; + reevaluateUnmeteredConnections(); + } else if (overrideMask == SUBSCRIPTION_OVERRIDE_CONGESTED) { + mCongestedNetworkTypes = tempList; + mCongestedOverride = overrideValue != 0; + reevaluateCongestedConnections(); + } + } + + @Override + public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { + if (mPhone == null || mPhone.getSubId() != subId) return; + + mSubscriptionPlans = Arrays.asList(plans); + if (DBG) log("SubscriptionPlans changed: " + mSubscriptionPlans); + reevaluateUnmeteredConnections(); + } + }; + + private final SettingsObserver mSettingsObserver; + + private void registerSettingsObserver() { + mSettingsObserver.unobserve(); + String simSuffix = ""; + if (TelephonyManager.getDefault().getSimCount() > 1) { + simSuffix = Integer.toString(mPhone.getSubId()); + } + + mSettingsObserver.observe( + Settings.Global.getUriFor(Settings.Global.DATA_ROAMING + simSuffix), + DctConstants.EVENT_ROAMING_SETTING_CHANGE); + mSettingsObserver.observe( + Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), + DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE); + } + + /** + * Maintain the sum of transmit and receive packets. + * + * The packet counts are initialized and reset to -1 and + * remain -1 until they can be updated. + */ + public static class TxRxSum { + public long txPkts; + public long rxPkts; + + public TxRxSum() { + reset(); + } + + public TxRxSum(long txPkts, long rxPkts) { + this.txPkts = txPkts; + this.rxPkts = rxPkts; + } + + public TxRxSum(TxRxSum sum) { + txPkts = sum.txPkts; + rxPkts = sum.rxPkts; + } + + public void reset() { + txPkts = -1; + rxPkts = -1; + } + + @Override + public String toString() { + return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}"; + } + + /** + * Get total Tx/Rx packet count from TrafficStats + */ + public void updateTotalTxRxSum() { + this.txPkts = TrafficStats.getMobileTxPackets(); + this.rxPkts = TrafficStats.getMobileRxPackets(); + } + } + + private void onDataReconnect(ApnContext apnContextforRetry, int subId, + @RequestNetworkType int requestType) { + int phoneSubId = mPhone.getSubId(); + String apnType = apnContextforRetry.getApnType(); + String reason = apnContextforRetry.getReason(); + + if (!SubscriptionManager.isValidSubscriptionId(subId) || (subId != phoneSubId)) { + log("onDataReconnect: invalid subId"); + return; + } + + ApnContext apnContext = mApnContexts.get(apnType); + + if (DBG) { + log("onDataReconnect: mState=" + mState + " reason=" + reason + " apnType=" + apnType + + " apnContext=" + apnContext); + } + + if ((apnContext != null) && (apnContext.isEnabled())) { + apnContext.setReason(reason); + DctConstants.State apnContextState = apnContext.getState(); + if (DBG) { + log("onDataReconnect: apnContext state=" + apnContextState); + } + if ((apnContextState == DctConstants.State.FAILED) + || (apnContextState == DctConstants.State.IDLE)) { + if (DBG) { + log("onDataReconnect: state is FAILED|IDLE, disassociate"); + } + apnContext.releaseDataConnection(""); + } else { + if (DBG) log("onDataReconnect: keep associated"); + } + // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA??? + sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, requestType, + 0, apnContext)); + } + } + + private void onActionIntentDataStallAlarm(Intent intent) { + if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction()); + + int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (!SubscriptionManager.isValidSubscriptionId(subId) || (subId != mPhone.getSubId())) { + return; + } + + int transportType = intent.getIntExtra(INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE, 0); + if (transportType != mTransportType) { + return; + } + + Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM, + intent.getAction()); + msg.arg1 = intent.getIntExtra(INTENT_DATA_STALL_ALARM_EXTRA_TAG, 0); + sendMessage(msg); + } + + private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList(); + + // member variables + protected final Phone mPhone; + private DctConstants.Activity mActivity = DctConstants.Activity.NONE; + private DctConstants.State mState = DctConstants.State.IDLE; + private final Handler mDataConnectionTracker; + + private long mTxPkts; + private long mRxPkts; + private int mNetStatPollPeriod; + private boolean mNetStatPollEnabled = false; + + private TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0); + // Used to track stale data stall alarms. + private int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime(); + // The current data stall alarm intent + private PendingIntent mDataStallAlarmIntent = null; + // Number of packets sent since the last received packet + private long mSentSinceLastRecv; + // Controls when a simple recovery attempt it to be tried + private int mNoRecvPollCount = 0; + // Reference counter for enabling fail fast + private static int sEnableFailFastRefCounter = 0; + // True if data stall detection is enabled + private volatile boolean mDataStallNoRxEnabled = true; + + protected volatile boolean mFailFast = false; + + // True when in voice call + protected boolean mInVoiceCall = false; + + /** Intent sent when the reconnect alarm fires. */ + private PendingIntent mReconnectIntent = null; + + // When false we will not auto attach and manually attaching is required. + protected boolean mAutoAttachOnCreationConfig = false; + private AtomicBoolean mAutoAttachEnabled = new AtomicBoolean(false); + + // State of screen + // (TODO: Reconsider tying directly to screen, maybe this is + // really a lower power mode") + private boolean mIsScreenOn = true; + + /** Allows the generation of unique Id's for DataConnection objects */ + private AtomicInteger mUniqueIdGenerator = new AtomicInteger(0); + + /** The data connections. */ + private HashMap mDataConnections = + new HashMap(); + + /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */ + private HashMap mApnToDataConnectionId = new HashMap(); + + /** Phone.APN_TYPE_* ===> ApnContext */ + protected ConcurrentHashMap mApnContexts = + new ConcurrentHashMap(); + + private SparseArray mApnContextsByType = new SparseArray(); + + private ArrayList mLastDataProfileList = new ArrayList<>(); + + /** RAT name ===> (downstream, upstream) bandwidth values from carrier config. */ + private ConcurrentHashMap> mBandwidths = + new ConcurrentHashMap<>(); + + private boolean mConfigReady = false; + + /** + * Handles changes to the APN db. + */ + private class ApnChangeObserver extends ContentObserver { + public ApnChangeObserver () { + super(mDataConnectionTracker); + } + + @Override + public void onChange(boolean selfChange) { + sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED)); + } + } + + //***** Instance Variables + + private boolean mReregisterOnReconnectFailure = false; + + + //***** Constants + + private static final int PROVISIONING_SPINNER_TIMEOUT_MILLIS = 120 * 1000; + + static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID = + Uri.parse("content://telephony/carriers/preferapn_no_update/subId/"); + static final String APN_ID = "apn_id"; + + private boolean mCanSetPreferApn = false; + + private AtomicBoolean mAttached = new AtomicBoolean(false); + + /** Watches for changes to the APN db. */ + private ApnChangeObserver mApnObserver; + + private BroadcastReceiver mProvisionBroadcastReceiver; + private ProgressDialog mProvisioningSpinner; + + private final DataServiceManager mDataServiceManager; + + @AccessNetworkConstants.TransportType + private final int mTransportType; + + private DataStallRecoveryHandler mDsRecoveryHandler; + private HandlerThread mHandlerThread; + + private final DataThrottler mDataThrottler; + + private final ThrottleStatusChangedCallback mThrottleStatusCallback; + + /** + * Request network completion message map. Key is the APN type, value is the list of completion + * messages to be sent. Using a list because there might be multiple network requests for + * the same APN type. + */ + private final Map> mHandoverCompletionMsgs = new HashMap<>(); + + //***** Constructor + public DcTracker(Phone phone, @TransportType int transportType) { + super(); + mPhone = phone; + if (DBG) log("DCT.constructor"); + mTelephonyManager = TelephonyManager.from(phone.getContext()) + .createForSubscriptionId(phone.getSubId()); + // The 'C' in tag indicates cellular, and 'I' indicates IWLAN. This is to distinguish + // between two DcTrackers, one for each. + String tagSuffix = "-" + ((transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + ? "C" : "I"); + tagSuffix += "-" + mPhone.getPhoneId(); + mLogTag = "DCT" + tagSuffix; + + mTransportType = transportType; + mDataServiceManager = new DataServiceManager(phone, transportType, tagSuffix); + mDataThrottler = new DataThrottler(mPhone, transportType); + + mResolver = mPhone.getContext().getContentResolver(); + mAlarmManager = + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); + + mDsRecoveryHandler = new DataStallRecoveryHandler(); + + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(INTENT_DATA_STALL_ALARM); + filter.addAction(INTENT_PROVISIONING_APN_ALARM); + filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + filter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); + filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); + + mDataEnabledSettings = mPhone.getDataEnabledSettings(); + + mDataEnabledSettings.registerForDataEnabledChanged(this, + DctConstants.EVENT_DATA_ENABLED_CHANGED, null); + mDataEnabledSettings.registerForDataEnabledOverrideChanged(this, + DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED); + + mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); + + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); + mAutoAttachEnabled.set(sp.getBoolean(Phone.DATA_DISABLED_ON_BOOT_KEY, false)); + + mNetworkPolicyManager = (NetworkPolicyManager) mPhone.getContext() + .getSystemService(Context.NETWORK_POLICY_SERVICE); + mNetworkPolicyManager.registerSubscriptionCallback(mSubscriptionCallback); + + mHandlerThread = new HandlerThread("DcHandlerThread"); + mHandlerThread.start(); + Handler dcHandler = new Handler(mHandlerThread.getLooper()); + mDcc = DcController.makeDcc(mPhone, this, mDataServiceManager, dcHandler.getLooper(), + tagSuffix); + mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler); + + mDataConnectionTracker = this; + registerForAllEvents(); + mApnObserver = new ApnChangeObserver(); + phone.getContext().getContentResolver().registerContentObserver( + Telephony.Carriers.CONTENT_URI, true, mApnObserver); + + initApnContexts(); + + addDefaultApnSettingsAsNeeded(); + + mSettingsObserver = new SettingsObserver(mPhone.getContext(), this); + registerSettingsObserver(); + + mThrottleStatusCallback = new ThrottleStatusChangedCallback(); + mDataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); + } + + @VisibleForTesting + public DcTracker() { + mLogTag = "DCT"; + mTelephonyManager = null; + mAlarmManager = null; + mPhone = null; + mDataConnectionTracker = null; + mSettingsObserver = new SettingsObserver(null, this); + mDataEnabledSettings = null; + mTransportType = 0; + mDataServiceManager = null; + mDataThrottler = null; + mThrottleStatusCallback = null; + } + + public void registerServiceStateTrackerEvents() { + mPhone.getServiceStateTracker().registerForDataConnectionAttached(mTransportType, this, + DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null); + mPhone.getServiceStateTracker().registerForDataConnectionDetached(mTransportType, this, + DctConstants.EVENT_DATA_CONNECTION_DETACHED, null); + mPhone.getServiceStateTracker().registerForDataRoamingOn(this, + DctConstants.EVENT_ROAMING_ON, null); + mPhone.getServiceStateTracker().registerForDataRoamingOff(this, + DctConstants.EVENT_ROAMING_OFF, null, true); + mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this, + DctConstants.EVENT_PS_RESTRICT_ENABLED, null); + mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this, + DctConstants.EVENT_PS_RESTRICT_DISABLED, null); + mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(mTransportType, this, + DctConstants.EVENT_DATA_RAT_CHANGED, null); + } + + public void unregisterServiceStateTrackerEvents() { + mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(mTransportType, this); + mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(mTransportType, this); + mPhone.getServiceStateTracker().unregisterForDataRoamingOn(this); + mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this); + mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this); + mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this); + mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(mTransportType, this); + mPhone.getServiceStateTracker().unregisterForAirplaneModeChanged(this); + } + + private void registerForAllEvents() { + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null); + mPhone.mCi.registerForOffOrNotAvailable(this, + DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + mPhone.mCi.registerForPcoData(this, DctConstants.EVENT_PCO_DATA_RECEIVED, null); + } + + // Note, this is fragile - the Phone is now presenting a merged picture + // of PS (volte) & CS and by diving into its internals you're just seeing + // the CS data. This works well for the purposes this is currently used for + // but that may not always be the case. Should probably be redesigned to + // accurately reflect what we're really interested in (registerForCSVoiceCallEnded). + mPhone.getCallTracker().registerForVoiceCallEnded(this, + DctConstants.EVENT_VOICE_CALL_ENDED, null); + mPhone.getCallTracker().registerForVoiceCallStarted(this, + DctConstants.EVENT_VOICE_CALL_STARTED, null); + mPhone.getDisplayInfoController().registerForTelephonyDisplayInfoChanged(this, + DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED, null); + registerServiceStateTrackerEvents(); + mDataServiceManager.registerForServiceBindingChanged(this, + DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED, null); + mDataServiceManager.registerForApnUnthrottled(this, DctConstants.EVENT_APN_UNTHROTTLED); + } + + public void dispose() { + if (DBG) log("DCT.dispose"); + + if (mProvisionBroadcastReceiver != null) { + mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); + mProvisionBroadcastReceiver = null; + } + if (mProvisioningSpinner != null) { + mProvisioningSpinner.dismiss(); + mProvisioningSpinner = null; + } + + cleanUpAllConnectionsInternal(true, null); + + mIsDisposed = true; + mPhone.getContext().unregisterReceiver(mIntentReceiver); + mSettingsObserver.unobserve(); + + mNetworkPolicyManager.unregisterSubscriptionCallback(mSubscriptionCallback); + mDcTesterFailBringUpAll.dispose(); + + mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver); + mApnContexts.clear(); + mApnContextsByType.clear(); + mPrioritySortedApnContexts.clear(); + unregisterForAllEvents(); + + destroyDataConnections(); + } + + /** + * Stop the internal handler thread + * + * TESTING ONLY + */ + @VisibleForTesting + public void stopHandlerThread() { + mHandlerThread.quit(); + } + + private void unregisterForAllEvents() { + //Unregister for all events + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + mPhone.mCi.unregisterForAvailable(this); + mPhone.mCi.unregisterForOffOrNotAvailable(this); + mPhone.mCi.unregisterForPcoData(this); + } + + mPhone.getCallTracker().unregisterForVoiceCallEnded(this); + mPhone.getCallTracker().unregisterForVoiceCallStarted(this); + mPhone.getDisplayInfoController().unregisterForTelephonyDisplayInfoChanged(this); + unregisterServiceStateTrackerEvents(); + mDataServiceManager.unregisterForServiceBindingChanged(this); + mDataEnabledSettings.unregisterForDataEnabledChanged(this); + mDataEnabledSettings.unregisterForDataEnabledOverrideChanged(this); + mDataServiceManager.unregisterForApnUnthrottled(this); + } + + /** + * Reevaluate existing data connections when conditions change. + * + * For example, handle reverting restricted networks back to unrestricted. If we're changing + * user data to enabled and this makes data truly enabled (not disabled by other factors) we + * need to reevaluate and possibly add NET_CAPABILITY_NOT_RESTRICTED capability to the data + * connection. This allows non-privilege apps to use the network. + * + * Or when we brought up a unmetered data connection while data is off, we only limit this + * data connection for unmetered use only. When data is turned back on, we need to tear that + * down so a full capable data connection can be re-established. + */ + private void reevaluateDataConnections() { + for (DataConnection dataConnection : mDataConnections.values()) { + dataConnection.reevaluateRestrictedState(); + } + } + + public long getSubId() { + return mPhone.getSubId(); + } + + public DctConstants.Activity getActivity() { + return mActivity; + } + + private void setActivity(DctConstants.Activity activity) { + log("setActivity = " + activity); + mActivity = activity; + mPhone.notifyDataActivity(); + } + + /** + * Request a network + * + * @param networkRequest Network request from clients + * @param type The request type + * @param onHandoverCompleteMsg When request type is handover, this message will be sent when + * handover is completed. For normal request, this should be null. + */ + public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type, + Message onHandoverCompleteMsg) { + if (type != REQUEST_TYPE_HANDOVER && onHandoverCompleteMsg != null) { + throw new RuntimeException("request network with normal type request type but passing " + + "handover complete message."); + } + final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest); + final ApnContext apnContext = mApnContextsByType.get(apnType); + if (apnContext != null) { + apnContext.requestNetwork(networkRequest, type, onHandoverCompleteMsg); + } + } + + public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type) { + final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest); + final ApnContext apnContext = mApnContextsByType.get(apnType); + if (apnContext != null) { + apnContext.releaseNetwork(networkRequest, type); + } + } + + // Turn telephony radio on or off. + private void setRadio(boolean on) { + final ITelephony phone = ITelephony.Stub.asInterface( + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getTelephonyServiceRegisterer() + .get()); + try { + phone.setRadio(on); + } catch (Exception e) { + // Ignore. + } + } + + // Class to handle Intent dispatched with user selects the "Sign-in to network" + // notification. + private class ProvisionNotificationBroadcastReceiver extends BroadcastReceiver { + private final String mNetworkOperator; + // Mobile provisioning URL. Valid while provisioning notification is up. + // Set prior to notification being posted as URL contains ICCID which + // disappears when radio is off (which is the case when notification is up). + private final String mProvisionUrl; + + public ProvisionNotificationBroadcastReceiver(String provisionUrl, String networkOperator) { + mNetworkOperator = networkOperator; + mProvisionUrl = provisionUrl; + } + + private void setEnableFailFastMobileData(int enabled) { + sendMessage(obtainMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled, 0)); + } + + private void enableMobileProvisioning() { + final Message msg = obtainMessage(DctConstants.CMD_ENABLE_MOBILE_PROVISIONING); + Bundle bundle = new Bundle(1); + bundle.putString(DctConstants.PROVISIONING_URL_KEY, mProvisionUrl); + msg.setData(bundle); + sendMessage(msg); + } + + @Override + public void onReceive(Context context, Intent intent) { + if (mPhone.getPhoneId() != intent.getIntExtra(EXTRA_PROVISION_PHONE_ID, + SubscriptionManager.INVALID_PHONE_INDEX)) { + return; + } + // Turning back on the radio can take time on the order of a minute, so show user a + // spinner so they know something is going on. + log("onReceive : ProvisionNotificationBroadcastReceiver"); + mProvisioningSpinner = new ProgressDialog(context); + mProvisioningSpinner.setTitle(mNetworkOperator); + mProvisioningSpinner.setMessage( + // TODO: Don't borrow "Connecting..." i18n string; give Telephony a version. + context.getText(com.android.internal.R.string.media_route_status_connecting)); + mProvisioningSpinner.setIndeterminate(true); + mProvisioningSpinner.setCancelable(true); + // Allow non-Activity Service Context to create a View. + mProvisioningSpinner.getWindow().setType( + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); + mProvisioningSpinner.show(); + // After timeout, hide spinner so user can at least use their device. + // TODO: Indicate to user that it is taking an unusually long time to connect? + sendMessageDelayed(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, + mProvisioningSpinner), PROVISIONING_SPINNER_TIMEOUT_MILLIS); + // This code is almost identical to the old + // ConnectivityService.handleMobileProvisioningAction code. + setRadio(true); + setEnableFailFastMobileData(DctConstants.ENABLED); + enableMobileProvisioning(); + } + } + + @Override + protected void finalize() { + if(DBG && mPhone != null) log("finalize"); + } + + private void initApnContexts() { + PersistableBundle carrierConfig; + CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager != null) { + carrierConfig = configManager.getConfigForSubId(mPhone.getSubId()); + } else { + carrierConfig = null; + } + initApnContexts(carrierConfig); + } + + //Blows away any existing apncontexts that may exist, only use in ctor. + private void initApnContexts(PersistableBundle carrierConfig) { + if (!mTelephonyManager.isDataCapable()) { + log("initApnContexts: isDataCapable == false. No Apn Contexts loaded"); + return; + } + + log("initApnContexts: E"); + // Load device network attributes from resources + final Collection types = + new ApnConfigTypeRepository(carrierConfig).getTypes(); + + for (ApnConfigType apnConfigType : types) { + ApnContext apnContext = new ApnContext(mPhone, apnConfigType.getType(), mLogTag, this, + apnConfigType.getPriority()); + int bitmask = ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType()); + mPrioritySortedApnContexts.add(apnContext); + mApnContexts.put(apnContext.getApnType(), apnContext); + mApnContextsByType.put(bitmask, apnContext); + // Notify listeners that all data is disconnected when DCT is initialized. + // Once connections are established, DC will then notify that data is connected. + // This is to prevent the case where the phone process crashed but we don't notify + // listeners that data was disconnected, so they may be stuck in a connected state. + mPhone.notifyDataConnection(new PreciseDataConnectionState.Builder() + .setTransportType(mTransportType) + .setState(TelephonyManager.DATA_DISCONNECTED) + .setApnSetting(new ApnSetting.Builder() + .setApnTypeBitmask(bitmask).buildWithoutCheck()) + .setNetworkType(getDataRat()) + .build()); + log("initApnContexts: apnContext=" + ApnSetting.getApnTypeString( + apnConfigType.getType())); + } + mPrioritySortedApnContexts.sort((c1, c2) -> c2.getPriority() - c1.getPriority()); + logSortedApnContexts(); + } + + private void sortApnContextByPriority() { + if (!mTelephonyManager.isDataCapable()) { + log("sortApnContextByPriority: isDataCapable == false. No Apn Contexts loaded"); + return; + } + + PersistableBundle carrierConfig; + CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager != null) { + carrierConfig = configManager.getConfigForSubId(mPhone.getSubId()); + } else { + carrierConfig = null; + } + + log("sortApnContextByPriority: E"); + // Load device network attributes from resources + final Collection types = + new ApnConfigTypeRepository(carrierConfig).getTypes(); + for (ApnConfigType apnConfigType : types) { + if (mApnContextsByType.contains(apnConfigType.getType())) { + ApnContext apnContext = mApnContextsByType.get(apnConfigType.getType()); + apnContext.setPriority(apnConfigType.getPriority()); + } + } + + //Doing sorted in a different list to keep thread safety + ArrayList prioritySortedApnContexts = + new ArrayList<>(mPrioritySortedApnContexts); + prioritySortedApnContexts.sort((c1, c2) -> c2.getPriority() - c1.getPriority()); + mPrioritySortedApnContexts = prioritySortedApnContexts; + logSortedApnContexts(); + } + + public LinkProperties getLinkProperties(String apnType) { + ApnContext apnContext = mApnContexts.get(apnType); + if (apnContext != null) { + DataConnection dataConnection = apnContext.getDataConnection(); + if (dataConnection != null) { + if (DBG) log("return link properties for " + apnType); + return dataConnection.getLinkProperties(); + } + } + if (DBG) log("return new LinkProperties"); + return new LinkProperties(); + } + + public NetworkCapabilities getNetworkCapabilities(String apnType) { + ApnContext apnContext = mApnContexts.get(apnType); + if (apnContext!=null) { + DataConnection dataConnection = apnContext.getDataConnection(); + if (dataConnection != null) { + if (DBG) { + log("get active pdp is not null, return NetworkCapabilities for " + apnType); + } + return dataConnection.getNetworkCapabilities(); + } + } + if (DBG) log("return new NetworkCapabilities"); + return new NetworkCapabilities(); + } + + // Return all active apn types + public String[] getActiveApnTypes() { + if (DBG) log("get all active apn types"); + ArrayList result = new ArrayList(); + + for (ApnContext apnContext : mApnContexts.values()) { + if (mAttached.get() && apnContext.isReady()) { + result.add(apnContext.getApnType()); + } + } + + return result.toArray(new String[0]); + } + + /** + * Get ApnTypes with connected data connections. This is different than getActiveApnTypes() + * which returns apn types that with active apn contexts. + * @return apn types + */ + public String[] getConnectedApnTypes() { + return mApnContexts.values().stream() + .filter(ac -> ac.getState() == DctConstants.State.CONNECTED) + .map(ApnContext::getApnType) + .toArray(String[]::new); + } + + @VisibleForTesting + public Collection getApnContexts() { + return mPrioritySortedApnContexts; + } + + /** Return active ApnSetting of a specific apnType */ + public ApnSetting getActiveApnSetting(String apnType) { + if (VDBG) log("get active ApnSetting for type:" + apnType); + ApnContext apnContext = mApnContexts.get(apnType); + return (apnContext != null) ? apnContext.getApnSetting() : null; + } + + // Return active apn of specific apn type + public String getActiveApnString(String apnType) { + if (VDBG) log( "get active apn string for type:" + apnType); + ApnSetting setting = getActiveApnSetting(apnType); + return (setting != null) ? setting.getApnName() : null; + } + + /** + * Returns {@link DctConstants.State} based on the state of the {@link DataConnection} that + * contains a {@link ApnSetting} that supported the given apn type {@code anpType}. + * + *

+ * Assumes there is less than one {@link ApnSetting} can support the given apn type. + */ + // TODO: for enterprise this always returns IDLE, which is ok for now since it is never called + // for enterprise + public DctConstants.State getState(String apnType) { + DctConstants.State state = DctConstants.State.IDLE; + final int apnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(apnType); + for (DataConnection dc : mDataConnections.values()) { + ApnSetting apnSetting = dc.getApnSetting(); + if (apnSetting != null && apnSetting.canHandleType(apnTypeBitmask)) { + if (dc.isActive()) { + state = getBetterConnectionState(state, DctConstants.State.CONNECTED); + } else if (dc.isActivating()) { + state = getBetterConnectionState(state, DctConstants.State.CONNECTING); + } else if (dc.isInactive()) { + state = getBetterConnectionState(state, DctConstants.State.IDLE); + } else if (dc.isDisconnecting()) { + state = getBetterConnectionState(state, DctConstants.State.DISCONNECTING); + } + } + } + return state; + } + + /** + * Return a better connection state between {@code stateA} and {@code stateB}. Check + * {@link #DATA_CONNECTION_STATE_PRIORITIES} for the details. + * @return the better connection state between {@code stateA} and {@code stateB}. + */ + private static DctConstants.State getBetterConnectionState( + DctConstants.State stateA, DctConstants.State stateB) { + int idxA = ArrayUtils.indexOf(DATA_CONNECTION_STATE_PRIORITIES, stateA); + int idxB = ArrayUtils.indexOf(DATA_CONNECTION_STATE_PRIORITIES, stateB); + return idxA >= idxB ? stateA : stateB; + } + + // Return if apn type is a provisioning apn. + private boolean isProvisioningApn(String apnType) { + ApnContext apnContext = mApnContexts.get(apnType); + if (apnContext != null) { + return apnContext.isProvisioningApn(); + } + return false; + } + + //****** Called from ServiceStateTracker + /** + * Invoked when ServiceStateTracker observes a transition from GPRS + * attach to detach. + */ + private void onDataConnectionDetached() { + /* + * We presently believe it is unnecessary to tear down the PDP context + * when GPRS detaches, but we should stop the network polling. + */ + if (DBG) log ("onDataConnectionDetached: stop polling and notify detached"); + stopNetStatPoll(); + stopDataStallAlarm(); + mAttached.set(false); + } + + private void onDataConnectionAttached() { + if (DBG) log("onDataConnectionAttached"); + mAttached.set(true); + if (isAnyDataConnected()) { + if (DBG) log("onDataConnectionAttached: start polling notify attached"); + startNetStatPoll(); + startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); + } + if (mAutoAttachOnCreationConfig) { + mAutoAttachEnabled.set(true); + } + setupDataOnAllConnectableApns(Phone.REASON_DATA_ATTACHED, RetryFailures.ALWAYS); + } + + /** + * Check if it is allowed to make a data connection (without checking APN context specific + * conditions). + * + * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output + * param. It's okay to pass null here and no reasons will be + * provided. + * @return True if data connection is allowed, otherwise false. + */ + public boolean isDataAllowed(DataConnectionReasons dataConnectionReasons) { + return isDataAllowed(null, REQUEST_TYPE_NORMAL, dataConnectionReasons); + } + + /** + * Check if it is allowed to make a data connection for a given APN type. + * + * @param apnContext APN context. If passing null, then will only check general but not APN + * specific conditions (e.g. APN state, metered/unmetered APN). + * @param requestType Setup data request type. + * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output + * param. It's okay to pass null here and no reasons will be + * provided. + * @return True if data connection is allowed, otherwise false. + */ + public boolean isDataAllowed(ApnContext apnContext, @RequestNetworkType int requestType, + DataConnectionReasons dataConnectionReasons) { + // Step 1: Get all environment conditions. + // Step 2: Special handling for emergency APN. + // Step 3. Build disallowed reasons. + // Step 4: Determine if data should be allowed in some special conditions. + + DataConnectionReasons reasons = new DataConnectionReasons(); + + int requestApnType = 0; + if (apnContext != null) { + requestApnType = apnContext.getApnTypeBitmask(); + } + + // Step 1: Get all environment conditions. + final boolean internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled(); + boolean attachedState = mAttached.get(); + boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState(); + boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier(); + // TODO: Remove this hack added by ag/641832. + int dataRat = getDataRat(); + if (dataRat == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { + desiredPowerState = true; + radioStateFromCarrier = true; + } + + boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId( + SubscriptionManager.getDefaultDataSubscriptionId()); + + boolean isMeteredApnType = apnContext == null + || ApnSettingUtils.isMeteredApnType(requestApnType, mPhone); + + PhoneConstants.State phoneState = PhoneConstants.State.IDLE; + // Note this is explicitly not using mPhone.getState. See b/19090488. + // mPhone.getState reports the merge of CS and PS (volte) voice call state + // but we only care about CS calls here for data/voice concurrency issues. + // Calling getCallTracker currently gives you just the CS side where the + // ImsCallTracker is held internally where applicable. + // This should be redesigned to ask explicitly what we want: + // voiceCallStateAllowDataCall, or dataCallAllowed or something similar. + if (mPhone.getCallTracker() != null) { + phoneState = mPhone.getCallTracker().getState(); + } + + // Step 2: Special handling for emergency APN. + if (apnContext != null + && requestApnType == ApnSetting.TYPE_EMERGENCY + && apnContext.isConnectable()) { + // If this is an emergency APN, as long as the APN is connectable, we + // should allow it. + if (dataConnectionReasons != null) { + dataConnectionReasons.add(DataAllowedReasonType.EMERGENCY_APN); + } + // Bail out without further checks. + return true; + } + + // Step 3. Build disallowed reasons. + if (apnContext != null && !apnContext.isConnectable()) { + DctConstants.State state = apnContext.getState(); + if (state == DctConstants.State.CONNECTED) { + reasons.add(DataDisallowedReasonType.DATA_ALREADY_CONNECTED); + } else if (state == DctConstants.State.DISCONNECTING) { + reasons.add(DataDisallowedReasonType.DATA_IS_DISCONNECTING); + } else if (state == DctConstants.State.CONNECTING) { + reasons.add(DataDisallowedReasonType.DATA_IS_CONNECTING); + } else { + reasons.add(DataDisallowedReasonType.APN_NOT_CONNECTABLE); + } + } + + // In legacy mode, if RAT is IWLAN then don't allow default/IA PDP at all. + // Rest of APN types can be evaluated for remaining conditions. + if ((apnContext != null && requestApnType == ApnSetting.TYPE_DEFAULT + || requestApnType == ApnSetting.TYPE_ENTERPRISE + || requestApnType == ApnSetting.TYPE_IA) + && mPhone.getAccessNetworksManager().isInLegacyMode() + && dataRat == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { + reasons.add(DataDisallowedReasonType.ON_IWLAN); + } + + // If device is not on NR, don't allow enterprise + if (apnContext != null && requestApnType == ApnSetting.TYPE_ENTERPRISE + && dataRat != ServiceState.RIL_RADIO_TECHNOLOGY_NR) { + reasons.add(DataDisallowedReasonType.NOT_ON_NR); + } + + if (shouldRestrictDataForEcbm() || mPhone.isInEmergencyCall()) { + reasons.add(DataDisallowedReasonType.IN_ECBM); + } + + if (!attachedState && !shouldAutoAttach() && requestType != REQUEST_TYPE_HANDOVER) { + reasons.add(DataDisallowedReasonType.NOT_ATTACHED); + } + if (mPhone.getSubId() == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + reasons.add(DataDisallowedReasonType.SIM_NOT_READY); + } + if (phoneState != PhoneConstants.State.IDLE + && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { + reasons.add(DataDisallowedReasonType.INVALID_PHONE_STATE); + reasons.add(DataDisallowedReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED); + } + if (!internalDataEnabled) { + reasons.add(DataDisallowedReasonType.INTERNAL_DATA_DISABLED); + } + if (!defaultDataSelected) { + reasons.add(DataDisallowedReasonType.DEFAULT_DATA_UNSELECTED); + } + if (mPhone.getServiceState().getDataRoaming() && !getDataRoamingEnabled()) { + reasons.add(DataDisallowedReasonType.ROAMING_DISABLED); + } + if (mIsPsRestricted) { + reasons.add(DataDisallowedReasonType.PS_RESTRICTED); + } + if (!desiredPowerState) { + reasons.add(DataDisallowedReasonType.UNDESIRED_POWER_STATE); + } + if (!radioStateFromCarrier) { + reasons.add(DataDisallowedReasonType.RADIO_DISABLED_BY_CARRIER); + } + if (!mDataServiceBound) { + reasons.add(DataDisallowedReasonType.DATA_SERVICE_NOT_READY); + } + + if (apnContext != null) { + if (mPhone.getAccessNetworksManager().getPreferredTransport( + apnContext.getApnTypeBitmask()) + == AccessNetworkConstants.TRANSPORT_TYPE_INVALID) { + // If QNS explicitly specified this APN type is not allowed on either cellular or + // IWLAN, we should not allow data setup. + reasons.add(DataDisallowedReasonType.DISABLED_BY_QNS); + } else if (mTransportType != mPhone.getAccessNetworksManager().getPreferredTransport( + apnContext.getApnTypeBitmask())) { + // If the latest preference has already switched to other transport, we should not + // allow data setup. + reasons.add(DataDisallowedReasonType.ON_OTHER_TRANSPORT); + } + + // If the transport has been already switched to the other transport, we should not + // allow the data setup. The only exception is the handover case, where we setup + // handover data connection before switching the transport. + if (mTransportType != mPhone.getAccessNetworksManager().getCurrentTransport( + apnContext.getApnTypeBitmask()) && requestType != REQUEST_TYPE_HANDOVER) { + reasons.add(DataDisallowedReasonType.ON_OTHER_TRANSPORT); + } + + // Check if the device is under data throttling. + long retryTime = mDataThrottler.getRetryTime(apnContext.getApnTypeBitmask()); + if (retryTime > SystemClock.elapsedRealtime()) { + reasons.add(DataDisallowedReasonType.DATA_THROTTLED); + } + } + + boolean isDataEnabled = apnContext == null ? mDataEnabledSettings.isDataEnabled() + : mDataEnabledSettings.isDataEnabled(requestApnType); + + if (!isDataEnabled) { + reasons.add(DataDisallowedReasonType.DATA_DISABLED); + } + + // If there are hard disallowed reasons, we should not allow data connection no matter what. + if (reasons.containsHardDisallowedReasons()) { + if (dataConnectionReasons != null) { + dataConnectionReasons.copyFrom(reasons); + } + return false; + } + + // Step 4: Determine if data should be allowed in some special conditions. + + // At this point, if data is not allowed, it must be because of the soft reasons. We + // should start to check some special conditions that data will be allowed. + if (!reasons.allowed()) { + // Check if the transport is WLAN ie wifi (for AP-assisted mode devices) + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { + reasons.add(DataAllowedReasonType.UNMETERED_APN); + // Or if the data is on cellular, and the APN type is determined unmetered by the + // configuration. + } else if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN + && !isMeteredApnType && requestApnType != ApnSetting.TYPE_DEFAULT + && requestApnType != ApnSetting.TYPE_ENTERPRISE) { + reasons.add(DataAllowedReasonType.UNMETERED_APN); + } + + // If the request is restricted and there are only soft disallowed reasons (e.g. data + // disabled, data roaming disabled) existing, we should allow the data. ENTERPRISE is + // an exception and should not be treated as restricted for this purpose; it should be + // treated same as DEFAULT. + if (apnContext != null + && apnContext.hasRestrictedRequests(true) + && !apnContext.getApnType().equals(ApnSetting.TYPE_ENTERPRISE_STRING) + && !reasons.allowed()) { + reasons.add(DataAllowedReasonType.RESTRICTED_REQUEST); + } + } else { + // If there is no disallowed reasons, then we should allow the data request with + // normal reason. + reasons.add(DataAllowedReasonType.NORMAL); + } + + if (dataConnectionReasons != null) { + dataConnectionReasons.copyFrom(reasons); + } + + return reasons.allowed(); + } + + // arg for setupDataOnAllConnectableApns + protected enum RetryFailures { + // retry failed networks always (the old default) + ALWAYS, + // retry only when a substantial change has occurred. Either: + // 1) we were restricted by voice/data concurrency and aren't anymore + // 2) our apn list has change + ONLY_ON_CHANGE + }; + + protected void setupDataOnAllConnectableApns(String reason, RetryFailures retryFailures) { + if (VDBG) log("setupDataOnAllConnectableApns: " + reason); + + if (DBG && !VDBG) { + StringBuilder sb = new StringBuilder(120); + for (ApnContext apnContext : mPrioritySortedApnContexts) { + sb.append(apnContext.getApnType()); + sb.append(":[state="); + sb.append(apnContext.getState()); + sb.append(",enabled="); + sb.append(apnContext.isEnabled()); + sb.append("] "); + } + log("setupDataOnAllConnectableApns: " + reason + " " + sb); + } + + for (ApnContext apnContext : mPrioritySortedApnContexts) { + setupDataOnConnectableApn(apnContext, reason, retryFailures); + } + } + + protected void setupDataOnConnectableApn(ApnContext apnContext, String reason, + RetryFailures retryFailures) { + if (VDBG) log("setupDataOnAllConnectableApns: apnContext " + apnContext); + + if (apnContext.getState() == DctConstants.State.FAILED + || apnContext.getState() == DctConstants.State.RETRYING) { + if (retryFailures == RetryFailures.ALWAYS) { + apnContext.releaseDataConnection(reason); + } else if (!apnContext.isConcurrentVoiceAndDataAllowed() + && mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { + // RetryFailures.ONLY_ON_CHANGE - check if voice concurrency has changed + apnContext.releaseDataConnection(reason); + } + } + if (apnContext.isConnectable()) { + log("isConnectable() call trySetupData"); + apnContext.setReason(reason); + trySetupData(apnContext, REQUEST_TYPE_NORMAL, null); + } + } + + private boolean shouldRestrictDataForEcbm() { + boolean isInEcm = mPhone.isInEcm(); + boolean isInImsEcm = mPhone.getImsPhone() != null && mPhone.getImsPhone().isInImsEcm(); + log("shouldRestrictDataForEcbm: isInEcm=" + isInEcm + " isInImsEcm=" + isInImsEcm); + return isInEcm && !isInImsEcm; + } + + private boolean isHandoverPending(@ApnType int apnType) { + List messageList = mHandoverCompletionMsgs.get(apnType); + return messageList != null && messageList.size() > 0; + } + + private void trySetupData(ApnContext apnContext, @RequestNetworkType int requestType, + @Nullable Message onHandoverCompleteMsg) { + if (onHandoverCompleteMsg != null) { + addHandoverCompleteMsg(onHandoverCompleteMsg, apnContext.getApnTypeBitmask()); + } + + if (mPhone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + log("trySetupData: X We're on the simulator; assuming connected retValue=true"); + return; + } + + DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); + boolean isDataAllowed = isDataAllowed(apnContext, requestType, dataConnectionReasons); + String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: " + + apnContext.getReason() + ", requestType=" + requestTypeToString(requestType) + + ". " + dataConnectionReasons.toString(); + if (dataConnectionReasons.contains(DataDisallowedReasonType.DISABLED_BY_QNS) + || dataConnectionReasons.contains(DataDisallowedReasonType.ON_OTHER_TRANSPORT)) { + logStr += ", current transport=" + AccessNetworkConstants.transportTypeToString( + mPhone.getAccessNetworksManager().getCurrentTransport( + apnContext.getApnTypeBitmask())); + logStr += ", preferred transport=" + AccessNetworkConstants.transportTypeToString( + mPhone.getAccessNetworksManager().getPreferredTransport( + apnContext.getApnTypeBitmask())); + } + if (DBG) log(logStr); + ApnContext.requestLog(apnContext, logStr); + if (!isDataAllowed) { + StringBuilder str = new StringBuilder(); + + str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType() + + ", mState=" + apnContext.getState() + ", apnEnabled=" + + apnContext.isEnabled() + ", mDependencyMet=" + + apnContext.isDependencyMet() + "] "); + + if (!mDataEnabledSettings.isDataEnabled()) { + str.append("isDataEnabled() = false. " + mDataEnabledSettings); + } + + // Check if it fails because of the existing data is still disconnecting. + if (dataConnectionReasons.contains(DataDisallowedReasonType.DATA_IS_DISCONNECTING) + && isHandoverPending(apnContext.getApnTypeBitmask())) { + // Normally we don't retry when isDataAllow() returns false, because that's consider + // pre-condition not met, for example, data not enabled by the user, or airplane + // mode is on. If we retry in those cases, there will be significant power impact. + // DATA_IS_DISCONNECTING is a special case we want to retry, and for the handover + // case only. + log("Data is disconnecting. Will retry handover later."); + return; + } + + // If this is a data retry, we should set the APN state to FAILED so it won't stay + // in RETRYING forever. + if (apnContext.getState() == DctConstants.State.RETRYING) { + apnContext.setState(DctConstants.State.FAILED); + str.append(" Stop retrying."); + } + + if (DBG) log(str.toString()); + ApnContext.requestLog(apnContext, str.toString()); + if (requestType == REQUEST_TYPE_HANDOVER) { + // If fails due to latest preference already changed back to source transport, then + // just fallback (will not attempt handover anymore, and will not tear down the + // data connection on source transport. + boolean fallback = dataConnectionReasons.contains( + DataDisallowedReasonType.ON_OTHER_TRANSPORT); + sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, fallback); + } + return; + } + + if (apnContext.getState() == DctConstants.State.FAILED) { + String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable"; + if (DBG) log(str); + ApnContext.requestLog(apnContext, str); + apnContext.setState(DctConstants.State.IDLE); + } + int radioTech = getDataRat(); + if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN && mPhone.getServiceState() + .getState() == ServiceState.STATE_IN_SERVICE) { + radioTech = getVoiceRat(); + } + log("service state=" + mPhone.getServiceState()); + apnContext.setConcurrentVoiceAndDataAllowed(mPhone.getServiceStateTracker() + .isConcurrentVoiceAndDataAllowed()); + if (apnContext.getState() == DctConstants.State.IDLE) { + ArrayList waitingApns = + buildWaitingApns(apnContext.getApnType(), radioTech); + if (waitingApns.isEmpty()) { + String str = "trySetupData: X No APN found retValue=false"; + if (DBG) log(str); + ApnContext.requestLog(apnContext, str); + if (requestType == REQUEST_TYPE_HANDOVER) { + sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, + false); + } + return; + } else { + apnContext.setWaitingApns(waitingApns); + if (DBG) { + log("trySetupData: Create from mAllApnSettings : " + + apnListToString(mAllApnSettings)); + } + } + } + + if (!setupData(apnContext, radioTech, requestType) + && requestType == REQUEST_TYPE_HANDOVER) { + sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, false); + } + } + + /** + * Clean up all data connections. Note this is just detach the APN context from the data + * connection. After all APN contexts are detached from the data connection, the data + * connection will be torn down. + * + * @param reason Reason for the clean up. + */ + public void cleanUpAllConnections(String reason) { + log("cleanUpAllConnections"); + Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS); + msg.obj = reason; + sendMessage(msg); + } + + /** + * Clean up all data connections by detaching the APN contexts from the data connections, which + * eventually tearing down all data connections after all APN contexts are detached from the + * data connections. + * + * @param detach {@code true} if detaching APN context from the underlying data connection (when + * no other APN context is attached to the data connection, the data connection will be torn + * down.) {@code false} to only reset the data connection's state machine. + * + * @param reason reason for the clean up. + * @return boolean - true if we did cleanup any connections, false if they + * were already all disconnected. + */ + private boolean cleanUpAllConnectionsInternal(boolean detach, String reason) { + if (DBG) log("cleanUpAllConnectionsInternal: detach=" + detach + " reason=" + reason); + boolean didDisconnect = false; + boolean disableMeteredOnly = false; + + // reasons that only metered apn will be torn down + if (!TextUtils.isEmpty(reason)) { + disableMeteredOnly = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED) || + reason.equals(Phone.REASON_ROAMING_ON) || + reason.equals(Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN); + } + + for (ApnContext apnContext : mApnContexts.values()) { + // Exclude the IMS APN from single data connection case. + if (reason.equals(Phone.REASON_SINGLE_PDN_ARBITRATION) + && apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) { + continue; + } + + if (shouldCleanUpConnection(apnContext, disableMeteredOnly, + reason.equals(Phone.REASON_SINGLE_PDN_ARBITRATION))) { + // TODO - only do cleanup if not disconnected + if (apnContext.isDisconnected() == false) didDisconnect = true; + apnContext.setReason(reason); + cleanUpConnectionInternal(detach, RELEASE_TYPE_DETACH, apnContext); + } else if (DBG) { + log("cleanUpAllConnectionsInternal: APN type " + apnContext.getApnType() + + " shouldn't be cleaned up."); + } + } + + stopNetStatPoll(); + stopDataStallAlarm(); + + // TODO: Do we need mRequestedApnType? + mRequestedApnType = ApnSetting.TYPE_DEFAULT; + + if (areAllDataDisconnected()) { + notifyAllDataDisconnected(); + } + + return didDisconnect; + } + + boolean shouldCleanUpConnection(ApnContext apnContext, boolean disableMeteredOnly, + boolean singlePdn) { + if (apnContext == null) return false; + + // If APN setting is not null and the reason is single PDN arbitration, clean up connection. + ApnSetting apnSetting = apnContext.getApnSetting(); + if (apnSetting != null && singlePdn) return true; + + // If meteredOnly is false, clean up all connections. + if (!disableMeteredOnly) return true; + + // If meteredOnly is true, and apnSetting is null or it's un-metered, no need to clean up. + if (apnSetting == null || !ApnSettingUtils.isMetered(apnSetting, mPhone)) return false; + + boolean isRoaming = mPhone.getServiceState().getDataRoaming(); + boolean isDataRoamingDisabled = !getDataRoamingEnabled(); + boolean isDataDisabled = !mDataEnabledSettings.isDataEnabled( + apnSetting.getApnTypeBitmask()); + + // Should clean up if its data is disabled, or data roaming is disabled while roaming. + return isDataDisabled || (isRoaming && isDataRoamingDisabled); + } + + /** + * Detach the APN context from the associated data connection. This data connection might be + * torn down if no other APN context is attached to it. + * + * @param apnContext The APN context to be detached + */ + void cleanUpConnection(ApnContext apnContext) { + if (DBG) log("cleanUpConnection: apnContext=" + apnContext); + Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION); + msg.arg2 = 0; + msg.obj = apnContext; + sendMessage(msg); + } + + /** + * Detach the APN context from the associated data connection. This data connection will be + * torn down if no other APN context is attached to it. + * + * @param detach {@code true} if detaching APN context from the underlying data connection (when + * no other APN context is attached to the data connection, the data connection will be torn + * down.) {@code false} to only reset the data connection's state machine. + * @param releaseType Data release type. + * @param apnContext The APN context to be detached. + */ + private void cleanUpConnectionInternal(boolean detach, @ReleaseNetworkType int releaseType, + ApnContext apnContext) { + if (apnContext == null) { + if (DBG) log("cleanUpConnectionInternal: apn context is null"); + return; + } + + DataConnection dataConnection = apnContext.getDataConnection(); + String str = "cleanUpConnectionInternal: detach=" + detach + " reason=" + + apnContext.getReason(); + if (VDBG) log(str + " apnContext=" + apnContext); + ApnContext.requestLog(apnContext, str); + if (detach) { + if (apnContext.isDisconnected()) { + // The request is detach and but ApnContext is not connected. + // If apnContext is not enabled anymore, break the linkage to the data connection. + apnContext.releaseDataConnection(""); + } else { + // Connection is still there. Try to clean up. + if (dataConnection != null) { + if (apnContext.getState() != DctConstants.State.DISCONNECTING) { + boolean disconnectAll = false; + if (ApnSetting.TYPE_DUN_STRING.equals(apnContext.getApnType()) + && ServiceState.isCdma(getDataRat())) { + if (DBG) { + log("cleanUpConnectionInternal: disconnectAll DUN connection"); + } + // For CDMA DUN, we need to tear it down immediately. A new data + // connection will be reestablished with correct profile id. + disconnectAll = true; + } + final int generation = apnContext.getConnectionGeneration(); + str = "cleanUpConnectionInternal: tearing down" + + (disconnectAll ? " all" : "") + " using gen#" + generation; + if (DBG) log(str + "apnContext=" + apnContext); + ApnContext.requestLog(apnContext, str); + Pair pair = new Pair<>(apnContext, generation); + Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair); + + if (disconnectAll || releaseType == RELEASE_TYPE_HANDOVER) { + dataConnection.tearDownAll(apnContext.getReason(), releaseType, msg); + } else { + dataConnection.tearDown(apnContext, apnContext.getReason(), msg); + } + + apnContext.setState(DctConstants.State.DISCONNECTING); + } + } else { + // apn is connected but no reference to the data connection. + // Should not be happen, but reset the state in case. + apnContext.setState(DctConstants.State.IDLE); + ApnContext.requestLog( + apnContext, "cleanUpConnectionInternal: connected, bug no dc"); + } + } + } else { + // force clean up the data connection. + if (dataConnection != null) dataConnection.reset(); + apnContext.setState(DctConstants.State.IDLE); + apnContext.setDataConnection(null); + } + + // If there is any outstanding handover request, we need to respond it. + sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, false); + + // Make sure reconnection alarm is cleaned up if there is no ApnContext + // associated to the connection. + if (dataConnection != null) { + cancelReconnect(apnContext); + } + str = "cleanUpConnectionInternal: X detach=" + detach + " reason=" + + apnContext.getReason(); + if (DBG) log(str + " apnContext=" + apnContext + " dc=" + apnContext.getDataConnection()); + } + + private Cursor getPreferredApnCursor(int subId) { + Cursor cursor = null; + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + cursor = mPhone.getContext().getContentResolver().query( + Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, + String.valueOf(subId)), null, null, null, + Telephony.Carriers.DEFAULT_SORT_ORDER); + } + return cursor; + } + + private ApnSetting getPreferredApnFromDB() { + ApnSetting preferredApn = null; + Cursor cursor = getPreferredApnCursor(mPhone.getSubId()); + if (cursor != null) { + if (cursor.getCount() > 0) { + cursor.moveToFirst(); + preferredApn = ApnSetting.makeApnSetting(cursor); + } + cursor.close(); + } + if (VDBG) log("getPreferredApnFromDB: preferredApn=" + preferredApn); + return preferredApn; + } + + private void setDefaultPreferredApnIfNeeded() { + ApnSetting defaultPreferredApn = null; + PersistableBundle bundle = getCarrierConfig(); + String defaultPreferredApnName = bundle.getString(CarrierConfigManager + .KEY_DEFAULT_PREFERRED_APN_NAME_STRING); + + if (TextUtils.isEmpty(defaultPreferredApnName) || getPreferredApnFromDB() != null) { + return; + } + + String selection = Telephony.Carriers.APN + " = \"" + defaultPreferredApnName + "\" AND " + + Telephony.Carriers.EDITED_STATUS + " = " + Telephony.Carriers.UNEDITED; + Cursor cursor = mPhone.getContext().getContentResolver().query( + Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, + "filtered/subId/" + mPhone.getSubId()), + null, selection, null, Telephony.Carriers._ID); + + if (cursor != null) { + if (cursor.getCount() > 0) { + if (cursor.moveToFirst()) { + defaultPreferredApn = ApnSetting.makeApnSetting(cursor); + } + } + cursor.close(); + } + + if (defaultPreferredApn != null + && defaultPreferredApn.canHandleType(mRequestedApnType)) { + log("setDefaultPreferredApnIfNeeded: For APN type " + + ApnSetting.getApnTypeString(mRequestedApnType) + + " found default apnSetting " + + defaultPreferredApn); + + setPreferredApn(defaultPreferredApn.getId(), true); + } + + return; + } + + /** + * Check if preferred apn is allowed to edit by user. + * @return {@code true} if it is allowed to edit. + */ + @VisibleForTesting + public boolean isPreferredApnUserEdited() { + boolean isUserEdited = false; + Cursor cursor = getPreferredApnCursor(mPhone.getSubId()); + if (cursor != null) { + if (cursor.getCount() > 0) { + if (cursor.moveToFirst()) { + isUserEdited = cursor.getInt( + cursor.getColumnIndexOrThrow(Telephony.Carriers.EDITED_STATUS)) + == Telephony.Carriers.USER_EDITED; + } + } + cursor.close(); + } + if (VDBG) log("isPreferredApnUserEdited: isUserEdited=" + isUserEdited); + return isUserEdited; + } + + /** + * Fetch the DUN apns + * @return a list of DUN ApnSetting objects + */ + @VisibleForTesting + public @NonNull ArrayList fetchDunApns() { + if (mPhone.getServiceState().getRoaming() && !isPreferredApnUserEdited() + && getCarrierConfig().getBoolean(CarrierConfigManager + .KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL)) { + if (VDBG) log("fetchDunApns: Dun apn is not used in roaming network"); + return new ArrayList(0); + } + + int bearer = getDataRat(); + ArrayList dunCandidates = new ArrayList(); + ArrayList retDunSettings = new ArrayList(); + + if (dunCandidates.isEmpty()) { + if (!ArrayUtils.isEmpty(mAllApnSettings)) { + for (ApnSetting apn : mAllApnSettings) { + if (apn.canHandleType(ApnSetting.TYPE_DUN)) { + dunCandidates.add(apn); + } + } + if (VDBG) log("fetchDunApns: dunCandidates from database: " + dunCandidates); + } + } + + int preferredApnSetId = getPreferredApnSetId(); + ApnSetting preferredApn = getPreferredApnFromDB(); + for (ApnSetting dunSetting : dunCandidates) { + if (dunSetting.canSupportNetworkType( + ServiceState.rilRadioTechnologyToNetworkType(bearer))) { + if (preferredApnSetId == dunSetting.getApnSetId()) { + if (preferredApn != null && preferredApn.equals(dunSetting)) { + // If there is a preferred APN can handled DUN type, prepend it to list to + // use it preferred. + retDunSettings.add(0, dunSetting); + } else { + retDunSettings.add(dunSetting); + } + } + } + } + + if (VDBG) log("fetchDunApns: dunSettings=" + retDunSettings); + return retDunSettings; + } + + private int getPreferredApnSetId() { + // preferapnset uri returns all APNs for the current carrier which have an apn_set_id + // equal to the preferred APN (if no preferred APN, or if the preferred APN has no set id, + // the query will return null) + Cursor c = mPhone.getContext().getContentResolver() + .query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, + "preferapnset/subId/" + mPhone.getSubId()), + new String[] {Telephony.Carriers.APN_SET_ID}, null, null, null); + if (c == null) { + loge("getPreferredApnSetId: cursor is null"); + return Telephony.Carriers.NO_APN_SET_ID; + } + + int setId; + if (c.getCount() < 1) { + loge("getPreferredApnSetId: no APNs found"); + setId = Telephony.Carriers.NO_APN_SET_ID; + } else { + c.moveToFirst(); + setId = c.getInt(0 /* index of Telephony.Carriers.APN_SET_ID */); + } + + if (!c.isClosed()) { + c.close(); + } + return setId; + } + + public boolean hasMatchedTetherApnSetting() { + ArrayList matches = fetchDunApns(); + log("hasMatchedTetherApnSetting: APNs=" + matches); + return matches.size() > 0; + } + + /** + * @return the {@link DataConnection} with the given context id {@code cid}. + */ + public DataConnection getDataConnectionByContextId(int cid) { + return mDcc.getActiveDcByCid(cid); + } + + /** + * @return the {@link DataConnection} with the given APN context. Null if no data connection + * is found. + */ + public @Nullable DataConnection getDataConnectionByApnType(String apnType) { + // TODO: Clean up all APN type in string usage + ApnContext apnContext = mApnContexts.get(apnType); + if (apnContext != null) { + return apnContext.getDataConnection(); + } + return null; + } + + /** + * Check if the data fail cause is a permanent failure (i.e. Frameworks will not retry data + * setup). + * + * @param dcFailCause The data fail cause + * @return {@code true} if the data fail cause is a permanent failure. + */ + @VisibleForTesting + public boolean isPermanentFailure(@DataFailureCause int dcFailCause) { + return (DataFailCause.isPermanentFailure(mPhone.getContext(), dcFailCause, + mPhone.getSubId()) + && (mAttached.get() == false || dcFailCause != DataFailCause.SIGNAL_LOST)); + } + + private DataConnection findFreeDataConnection() { + for (DataConnection dataConnection : mDataConnections.values()) { + boolean inUse = false; + for (ApnContext apnContext : mApnContexts.values()) { + if (apnContext.getDataConnection() == dataConnection) { + inUse = true; + break; + } + } + if (!inUse) { + if (DBG) { + log("findFreeDataConnection: found free DataConnection=" + dataConnection); + } + return dataConnection; + } + } + log("findFreeDataConnection: NO free DataConnection"); + return null; + } + + /** + * Setup a data connection based on given APN type. + * + * @param apnContext APN context + * @param radioTech RAT of the data connection + * @param requestType Data request type + * @return True if successful, otherwise false. + */ + private boolean setupData(ApnContext apnContext, int radioTech, + @RequestNetworkType int requestType) { + if (DBG) { + log("setupData: apnContext=" + apnContext + ", requestType=" + + requestTypeToString(requestType)); + } + ApnContext.requestLog( + apnContext, "setupData. requestType=" + requestTypeToString(requestType)); + ApnSetting apnSetting; + DataConnection dataConnection = null; + + apnSetting = apnContext.getNextApnSetting(); + + if (apnSetting == null) { + if (DBG) log("setupData: return for no apn found!"); + return false; + } + + // profile id is only meaningful when the profile is persistent on the modem. + int profileId = DATA_PROFILE_INVALID; + if (apnSetting.isPersistent()) { + profileId = apnSetting.getProfileId(); + if (profileId == DATA_PROFILE_DEFAULT) { + profileId = getApnProfileID(apnContext.getApnType()); + } + } + + // On CDMA, if we're explicitly asking for DUN, we need have + // a dun-profiled connection so we can't share an existing one + // On GSM/LTE we can share existing apn connections provided they support + // this type. + // If asking for ENTERPRISE, there are no compatible data connections, so skip this check + if ((apnContext.getApnTypeBitmask() != ApnSetting.TYPE_DUN + || ServiceState.isGsm(getDataRat())) + && apnContext.getApnTypeBitmask() != ApnSetting.TYPE_ENTERPRISE) { + dataConnection = checkForCompatibleDataConnection(apnContext, apnSetting); + if (dataConnection != null) { + // Get the apn setting used by the data connection + ApnSetting dataConnectionApnSetting = dataConnection.getApnSetting(); + if (dataConnectionApnSetting != null) { + // Setting is good, so use it. + apnSetting = dataConnectionApnSetting; + } + } + } + if (dataConnection == null) { + if (isOnlySingleDcAllowed(radioTech)) { + if (isHigherPriorityApnContextActive(apnContext)) { + if (DBG) { + log("setupData: Higher priority ApnContext active. Ignoring call"); + } + return false; + } + + // Should not start cleanUp if the setupData is for IMS APN + // or retry of same APN(State==RETRYING). + if (!apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING) + && (apnContext.getState() != DctConstants.State.RETRYING)) { + // Only lower priority calls left. Disconnect them all in this single PDP case + // so that we can bring up the requested higher priority call (once we receive + // response for deactivate request for the calls we are about to disconnect + if (cleanUpAllConnectionsInternal(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) { + // If any call actually requested to be disconnected, means we can't + // bring up this connection yet as we need to wait for those data calls + // to be disconnected. + if (DBG) log("setupData: Some calls are disconnecting first." + + " Wait and retry"); + return false; + } + } + + // No other calls are active, so proceed + if (DBG) log("setupData: Single pdp. Continue setting up data call."); + } + + dataConnection = findFreeDataConnection(); + + if (dataConnection == null) { + dataConnection = createDataConnection(); + } + + if (dataConnection == null) { + if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD"); + return false; + } + } + final int generation = apnContext.incAndGetConnectionGeneration(); + if (DBG) { + log("setupData: dc=" + dataConnection + " apnSetting=" + apnSetting + " gen#=" + + generation); + } + + apnContext.setDataConnection(dataConnection); + apnContext.setApnSetting(apnSetting); + apnContext.setState(DctConstants.State.CONNECTING); + + Message msg = obtainMessage(); + msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE; + msg.obj = new Pair(apnContext, generation); + + ApnSetting preferredApn = getPreferredApn(); + boolean isPreferredApn = apnSetting.equals(preferredApn); + dataConnection.bringUp(apnContext, profileId, radioTech, msg, generation, requestType, + mPhone.getSubId(), isPreferredApn); + + if (DBG) { + if (isPreferredApn) { + log("setupData: initing! isPreferredApn=" + isPreferredApn + + ", apnSetting={" + apnSetting.toString() + "}"); + } else { + String preferredApnStr = preferredApn == null ? "null" : preferredApn.toString(); + log("setupData: initing! isPreferredApn=" + isPreferredApn + + ", apnSetting={" + apnSetting + "}" + + ", preferredApn={" + preferredApnStr + "}"); + } + } + return true; + } + + // Get the allowed APN types for initial attach. The order in the returned list represent + // the order of APN types that should be used for initial attach. + private @NonNull @ApnType List getAllowedInitialAttachApnTypes() { + PersistableBundle bundle = getCarrierConfig(); + if (bundle != null) { + String[] apnTypesArray = bundle.getStringArray( + CarrierConfigManager.KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY); + if (apnTypesArray != null) { + return Arrays.stream(apnTypesArray) + .map(ApnSetting::getApnTypesBitmaskFromString) + .collect(Collectors.toList()); + } + } + + return Collections.emptyList(); + } + + protected void setInitialAttachApn() { + ApnSetting apnSetting = null; + int preferredApnSetId = getPreferredApnSetId(); + ArrayList allApnSettings = new ArrayList<>(); + if (mPreferredApn != null) { + // Put the preferred apn at the beginning of the list. It's okay to have a duplicate + // when later on mAllApnSettings get added. That would not change the selection result. + allApnSettings.add(mPreferredApn); + } + allApnSettings.addAll(mAllApnSettings); + + // Get the allowed APN types for initial attach. Note that if none of the APNs has the + // allowed APN types, then the initial attach will not be performed. + List allowedApnTypes = getAllowedInitialAttachApnTypes(); + for (int allowedApnType : allowedApnTypes) { + apnSetting = allApnSettings.stream() + .filter(apn -> apn.canHandleType(allowedApnType)) + .filter(apn -> (apn.getApnSetId() == preferredApnSetId + || apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID)) + .findFirst() + .orElse(null); + if (apnSetting != null) break; + } + + if (DBG) { + log("setInitialAttachApn: Allowed APN types=" + allowedApnTypes.stream() + .map(ApnSetting::getApnTypeString) + .collect(Collectors.joining(","))); + } + + if (apnSetting == null) { + if (DBG) log("setInitialAttachApn: X There in no available apn."); + } else { + if (DBG) log("setInitialAttachApn: X selected APN=" + apnSetting); + mDataServiceManager.setInitialAttachApn(new DataProfile.Builder() + .setApnSetting(apnSetting) + .setPreferred(apnSetting.equals(getPreferredApn())) + .build(), + mPhone.getServiceState().getDataRoamingFromRegistration(), null); + } + } + + /** + * Handles changes to the APN database. + */ + private void onApnChanged() { + if (mPhone instanceof GsmCdmaPhone) { + // The "current" may no longer be valid. MMS depends on this to send properly. TBD + ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider(); + } + + // TODO: It'd be nice to only do this if the changed entrie(s) + // match the current operator. + if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections"); + mDataThrottler.reset(); + setDefaultPreferredApnIfNeeded(); + createAllApnList(); + setDataProfilesAsNeeded(); + setInitialAttachApn(); + cleanUpConnectionsOnUpdatedApns(isAnyDataConnected(), Phone.REASON_APN_CHANGED); + + // FIXME: See bug 17426028 maybe no conditional is needed. + if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubscriptionId()) { + setupDataOnAllConnectableApns(Phone.REASON_APN_CHANGED, RetryFailures.ALWAYS); + } + } + + /** + * "Active" here means ApnContext isEnabled() and not in FAILED state + * @param apnContext to compare with + * @return true if higher priority active apn found + */ + private boolean isHigherPriorityApnContextActive(ApnContext apnContext) { + if (apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) { + return false; + } + + for (ApnContext otherContext : mPrioritySortedApnContexts) { + if (otherContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) { + continue; + } + if (apnContext.getApnType().equalsIgnoreCase(otherContext.getApnType())) return false; + if (otherContext.isEnabled() && otherContext.getState() != DctConstants.State.FAILED) { + return true; + } + } + return false; + } + + /** + * Reports if we support multiple connections or not. + * This is a combination of factors, based on carrier and RAT. + * @param rilRadioTech the RIL Radio Tech currently in use + * @return true if only single DataConnection is allowed + */ + private boolean isOnlySingleDcAllowed(int rilRadioTech) { + int networkType = ServiceState.rilRadioTechnologyToNetworkType(rilRadioTech); + // Default single dc rats with no knowledge of carrier + int[] singleDcRats = null; + // get the carrier specific value, if it exists, from CarrierConfigManager. + // generally configManager and bundle should not be null, but if they are it should be okay + // to leave singleDcRats null as well + CarrierConfigManager configManager = (CarrierConfigManager) + mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager != null) { + PersistableBundle bundle = configManager.getConfigForSubId(mPhone.getSubId()); + if (bundle != null) { + singleDcRats = bundle.getIntArray( + CarrierConfigManager.KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY); + } + } + boolean onlySingleDcAllowed = false; + if (TelephonyUtils.IS_DEBUGGABLE + && SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) { + onlySingleDcAllowed = true; + } + if (singleDcRats != null) { + for (int i = 0; i < singleDcRats.length && !onlySingleDcAllowed; i++) { + if (networkType == singleDcRats[i]) { + onlySingleDcAllowed = true; + } + } + } + + if (DBG) { + log("isOnlySingleDcAllowed(" + TelephonyManager.getNetworkTypeName(networkType) + "): " + + onlySingleDcAllowed); + } + return onlySingleDcAllowed; + } + + void sendRestartRadio() { + if (DBG)log("sendRestartRadio:"); + Message msg = obtainMessage(DctConstants.EVENT_RESTART_RADIO); + sendMessage(msg); + } + + private void restartRadio() { + if (DBG) log("restartRadio: ************TURN OFF RADIO**************"); + cleanUpAllConnectionsInternal(true, Phone.REASON_RADIO_TURNED_OFF); + mPhone.getServiceStateTracker().powerOffRadioSafely(); + /* Note: no need to call setRadioPower(true). Assuming the desired + * radio power state is still ON (as tracked by ServiceStateTracker), + * ServiceStateTracker will call setRadioPower when it receives the + * RADIO_STATE_CHANGED notification for the power off. And if the + * desired power state has changed in the interim, we don't want to + * override it with an unconditional power on. + */ + } + + /** + * Return true if data connection need to be setup after disconnected due to + * reason. + * + * @param apnContext APN context + * @return true if try setup data connection is need for this reason + */ + private boolean retryAfterDisconnected(ApnContext apnContext) { + boolean retry = true; + String reason = apnContext.getReason(); + + if (Phone.REASON_RADIO_TURNED_OFF.equals(reason) || (isOnlySingleDcAllowed(getDataRat()) + && isHigherPriorityApnContextActive(apnContext))) { + retry = false; + } + return retry; + } + + protected void startReconnect(long delay, ApnContext apnContext, + @RequestNetworkType int requestType) { + apnContext.setState(DctConstants.State.RETRYING); + Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT, + mPhone.getSubId(), requestType, apnContext); + cancelReconnect(apnContext); + + // Wait a bit before trying the next APN, so that + // we're not tying up the RIL command channel + sendMessageDelayed(msg, delay); + + if (DBG) { + log("startReconnect: delay=" + delay + ", apn=" + + apnContext + ", reason=" + apnContext.getReason() + + ", subId=" + mPhone.getSubId() + ", request type=" + + requestTypeToString(requestType)); + } + } + + /** + * Cancels the alarm associated with apnContext. + * + * @param apnContext on which the alarm should be stopped. + */ + protected void cancelReconnect(ApnContext apnContext) { + if (apnContext == null) return; + + if (DBG) { + log("cancelReconnect: apn=" + apnContext); + } + removeMessages(DctConstants.EVENT_DATA_RECONNECT, apnContext); + } + + /** + * Read configuration. Note this must be called after carrier config is ready. + */ + private void readConfiguration() { + log("readConfiguration"); + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + // Auto attach is for cellular only. + mAutoAttachOnCreationConfig = mPhone.getContext().getResources() + .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation); + } + + mAutoAttachEnabled.set(false); + setDefaultPreferredApnIfNeeded(); + read5GConfiguration(); + registerSettingsObserver(); + SubscriptionPlan[] plans = mNetworkPolicyManager.getSubscriptionPlans( + mPhone.getSubId(), mPhone.getContext().getOpPackageName()); + mSubscriptionPlans = plans == null ? Collections.emptyList() : Arrays.asList(plans); + if (DBG) log("SubscriptionPlans initialized: " + mSubscriptionPlans); + reevaluateUnmeteredConnections(); + mConfigReady = true; + } + + /** + * @return {@code true} if carrier config has been applied. + */ + private boolean isCarrierConfigApplied() { + CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager != null) { + PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); + if (b != null) { + return CarrierConfigManager.isConfigForIdentifiedCarrier(b); + } + } + return false; + } + + private void onCarrierConfigChanged() { + if (DBG) log("onCarrierConfigChanged"); + + if (!isCarrierConfigApplied()) { + log("onCarrierConfigChanged: Carrier config is not ready yet."); + return; + } + + readConfiguration(); + + if (mSimState == TelephonyManager.SIM_STATE_LOADED) { + setDefaultDataRoamingEnabled(); + createAllApnList(); + setDataProfilesAsNeeded(); + setInitialAttachApn(); + sortApnContextByPriority(); + cleanUpConnectionsOnUpdatedApns(true, Phone.REASON_CARRIER_CHANGE); + setupDataOnAllConnectableApns(Phone.REASON_CARRIER_CHANGE, RetryFailures.ALWAYS); + } else { + log("onCarrierConfigChanged: SIM is not loaded yet."); + } + } + + private void onSimAbsent() { + if (DBG) log("onSimAbsent"); + + mConfigReady = false; + cleanUpAllConnectionsInternal(true, Phone.REASON_SIM_NOT_READY); + mAllApnSettings.clear(); + mAutoAttachOnCreationConfig = false; + // Clear auto attach as modem is expected to do a new attach once SIM is ready + mAutoAttachEnabled.set(false); + // In no-sim case, we should still send the emergency APN to the modem, if there is any. + createAllApnList(); + setDataProfilesAsNeeded(); + } + + private void onSimStateUpdated(@SimState int simState) { + mSimState = simState; + + if (DBG) { + log("onSimStateUpdated: state=" + SubscriptionInfoUpdater.simStateString(mSimState)); + } + + if (mSimState == TelephonyManager.SIM_STATE_ABSENT) { + onSimAbsent(); + } else if (mSimState == TelephonyManager.SIM_STATE_LOADED) { + mDataThrottler.reset(); + if (mConfigReady) { + createAllApnList(); + setDataProfilesAsNeeded(); + setInitialAttachApn(); + setupDataOnAllConnectableApns(Phone.REASON_SIM_LOADED, RetryFailures.ALWAYS); + } else { + log("onSimStateUpdated: config not ready yet."); + } + } + } + + private void onApnUnthrottled(String apn) { + if (apn != null) { + ApnSetting apnSetting = mAllApnSettings.stream() + .filter(as -> apn.equals(as.getApnName())) + .findFirst() + .orElse(null); + if (apnSetting != null) { + @ApnType int apnTypes = apnSetting.getApnTypeBitmask(); + mDataThrottler.setRetryTime(apnTypes, RetryManager.NO_SUGGESTED_RETRY_DELAY, + REQUEST_TYPE_NORMAL); + } else { + loge("EVENT_APN_UNTHROTTLED: Invalid APN passed: " + apn); + } + } else { + loge("EVENT_APN_UNTHROTTLED: apn is null"); + } + } + + private void onTrafficDescriptorsUpdated() { + for (ApnContext apnContext : mPrioritySortedApnContexts) { + if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE + && apnContext.getApnSetting().getPermanentFailed()) { + setupDataOnConnectableApn( + apnContext, Phone.REASON_TRAFFIC_DESCRIPTORS_UPDATED, RetryFailures.ALWAYS); + } + } + } + + private DataConnection checkForCompatibleDataConnection(ApnContext apnContext, + ApnSetting nextApn) { + int apnType = apnContext.getApnTypeBitmask(); + ArrayList dunSettings = null; + + if (ApnSetting.TYPE_DUN == apnType) { + dunSettings = fetchDunApns(); + } + if (DBG) { + log("checkForCompatibleDataConnection: apnContext=" + apnContext); + } + + DataConnection potentialDc = null; + for (DataConnection curDc : mDataConnections.values()) { + if (curDc != null) { + ApnSetting apnSetting = curDc.getApnSetting(); + log("apnSetting: " + apnSetting); + if (dunSettings != null && dunSettings.size() > 0) { + for (ApnSetting dunSetting : dunSettings) { + //This ignore network type as a check which is ok because that's checked + //when calculating dun candidates. + if (areCompatible(dunSetting, apnSetting)) { + if (curDc.isActive()) { + if (DBG) { + log("checkForCompatibleDataConnection:" + + " found dun conn=" + curDc); + } + return curDc; + } else if (curDc.isActivating()) { + potentialDc = curDc; + } + } + } + } else if (isApnSettingCompatible(curDc, apnType)) { + if (curDc.isActive()) { + if (DBG) { + log("checkForCompatibleDataConnection:" + + " found canHandle conn=" + curDc); + } + return curDc; + } else if (curDc.isActivating() + || (apnSetting != null && apnSetting.equals(nextApn))) { + potentialDc = curDc; + } + } + } + } + + if (DBG) { + log("checkForCompatibleDataConnection: potential dc=" + potentialDc); + } + return potentialDc; + } + + private boolean isApnSettingCompatible(DataConnection dc, int apnType) { + ApnSetting apnSetting = dc.getApnSetting(); + if (apnSetting == null) return false; + + // Nothing can be compatible with type ENTERPRISE + for (ApnContext apnContext : dc.getApnContexts()) { + if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { + return false; + } + } + + return apnSetting.canHandleType(apnType); + } + + private void addHandoverCompleteMsg(Message onCompleteMsg, + @ApnType int apnType) { + if (onCompleteMsg != null) { + List messageList = mHandoverCompletionMsgs.get(apnType); + if (messageList == null) messageList = new ArrayList<>(); + messageList.add(onCompleteMsg); + mHandoverCompletionMsgs.put(apnType, messageList); + } + } + + private void sendHandoverCompleteMessages(@ApnType int apnType, boolean success, + boolean fallbackOnFailedHandover) { + List messageList = mHandoverCompletionMsgs.get(apnType); + if (messageList != null) { + for (Message msg : messageList) { + sendHandoverCompleteMsg(msg, success, mTransportType, fallbackOnFailedHandover); + } + messageList.clear(); + } + } + + private void sendHandoverCompleteMsg(Message message, boolean success, + @TransportType int transport, boolean doFallbackOnFailedHandover) { + if (message == null) return; + + Bundle b = message.getData(); + b.putBoolean(DATA_COMPLETE_MSG_EXTRA_SUCCESS, success); + b.putInt(DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE, transport); + b.putBoolean(DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK, doFallbackOnFailedHandover); + message.sendToTarget(); + } + + private static boolean shouldFallbackOnFailedHandover( + @HandoverFailureMode int handoverFailureMode, + @RequestNetworkType int requestType, + @DataFailureCause int cause) { + if (requestType != REQUEST_TYPE_HANDOVER) { + //The fallback is only relevant if the request is a handover + return false; + } else if (handoverFailureMode == HANDOVER_FAILURE_MODE_DO_FALLBACK) { + return true; + } else if (handoverFailureMode == HANDOVER_FAILURE_MODE_LEGACY) { + return cause == DataFailCause.HANDOFF_PREFERENCE_CHANGED; + } else { + return false; + } + } + + /** + * Calculates the new request type that will be used the next time a data connection retries + * after a failed data call attempt. + */ + @RequestNetworkType + public static int calculateNewRetryRequestType(@HandoverFailureMode int handoverFailureMode, + @RequestNetworkType int requestType, + @DataFailureCause int cause) { + boolean fallbackOnFailedHandover = + shouldFallbackOnFailedHandover(handoverFailureMode, requestType, cause); + if (requestType != REQUEST_TYPE_HANDOVER) { + //The fallback is only relevant if the request is a handover + return requestType; + } + + if (fallbackOnFailedHandover) { + // Since fallback is happening, the request type is really "NONE". + return REQUEST_TYPE_NORMAL; + } + + if (handoverFailureMode == HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL) { + return REQUEST_TYPE_NORMAL; + } + + return REQUEST_TYPE_HANDOVER; + } + + public void enableApn(@ApnType int apnType, @RequestNetworkType int requestType, + Message onHandoverCompleteMsg) { + sendMessage(obtainMessage(DctConstants.EVENT_ENABLE_APN, apnType, requestType, + onHandoverCompleteMsg)); + } + + private void onEnableApn(@ApnType int apnType, @RequestNetworkType int requestType, + Message onHandoverCompleteMsg) { + ApnContext apnContext = mApnContextsByType.get(apnType); + if (apnContext == null) { + loge("onEnableApn(" + apnType + "): NO ApnContext"); + if (onHandoverCompleteMsg != null) { + sendHandoverCompleteMsg(onHandoverCompleteMsg, false, mTransportType, false); + } + return; + } + + String str = "onEnableApn: apnType=" + ApnSetting.getApnTypeString(apnType) + + ", request type=" + requestTypeToString(requestType); + if (DBG) log(str); + ApnContext.requestLog(apnContext, str); + + if (!apnContext.isDependencyMet()) { + apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET); + apnContext.setEnabled(true); + str = "onEnableApn: dependency is not met."; + if (DBG) log(str); + ApnContext.requestLog(apnContext, str); + if (onHandoverCompleteMsg != null) { + sendHandoverCompleteMsg(onHandoverCompleteMsg, false, mTransportType, false); + } + return; + } + + if (apnContext.isReady()) { + DctConstants.State state = apnContext.getState(); + switch(state) { + case CONNECTING: + if (onHandoverCompleteMsg != null) { + if (DBG) { + log("onEnableApn: already in CONNECTING state. Handover request " + + "will be responded after connected."); + } + addHandoverCompleteMsg(onHandoverCompleteMsg, apnType); + } else { + if (DBG) log("onEnableApn: in CONNECTING state. Exit now."); + } + return; + case CONNECTED: + if (onHandoverCompleteMsg != null) { + sendHandoverCompleteMsg(onHandoverCompleteMsg, true, mTransportType, + false); + if (DBG) { + log("onEnableApn: already in CONNECTED state. Consider as handover " + + "succeeded"); + } + } else { + if (DBG) log("onEnableApn: APN in CONNECTED state. Exit now."); + } + return; + case IDLE: + case FAILED: + case RETRYING: + // We're "READY" but not active so disconnect (cleanup = true) and + // connect (trySetup = true) to be sure we retry the connection. + apnContext.setReason(Phone.REASON_DATA_ENABLED); + break; + } + } else { + if (apnContext.isEnabled()) { + apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET); + } else { + apnContext.setReason(Phone.REASON_DATA_ENABLED); + } + if (apnContext.getState() == DctConstants.State.FAILED) { + apnContext.setState(DctConstants.State.IDLE); + } + } + apnContext.setEnabled(true); + apnContext.resetErrorCodeRetries(); + + if (mConfigReady || apnContext.getApnTypeBitmask() == ApnSetting.TYPE_EMERGENCY) { + trySetupData(apnContext, requestType, onHandoverCompleteMsg); + } else { + log("onEnableApn: config not ready yet."); + } + } + + public void disableApn(@ApnType int apnType, @ReleaseNetworkType int releaseType) { + sendMessage(obtainMessage(DctConstants.EVENT_DISABLE_APN, apnType, releaseType)); + } + + private void onDisableApn(@ApnType int apnType, + @ReleaseNetworkType int releaseType) { + ApnContext apnContext = mApnContextsByType.get(apnType); + if (apnContext == null) { + loge("disableApn(" + apnType + "): NO ApnContext"); + return; + } + + boolean cleanup = false; + String str = "onDisableApn: apnType=" + ApnSetting.getApnTypeString(apnType) + + ", release type=" + releaseTypeToString(releaseType); + if (DBG) log(str); + ApnContext.requestLog(apnContext, str); + + if (apnContext.isReady()) { + cleanup = (releaseType == RELEASE_TYPE_DETACH + || releaseType == RELEASE_TYPE_HANDOVER); + if (apnContext.isDependencyMet()) { + apnContext.setReason(Phone.REASON_DATA_DISABLED_INTERNAL); + // If ConnectivityService has disabled this network, stop trying to bring + // it up, but do not tear it down - ConnectivityService will do that + // directly by talking with the DataConnection. + // + // This doesn't apply to DUN. When the user disable tethering, we would like to + // detach the APN context from the data connection so the data connection can be + // torn down if no other APN context attached to it. + if (ApnSetting.TYPE_DUN_STRING.equals(apnContext.getApnType()) + || apnContext.getState() != DctConstants.State.CONNECTED) { + str = "Clean up the connection. Apn type = " + apnContext.getApnType() + + ", state = " + apnContext.getState(); + if (DBG) log(str); + ApnContext.requestLog(apnContext, str); + cleanup = true; + } + } else { + apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET); + } + } + + apnContext.setEnabled(false); + if (cleanup) { + cleanUpConnectionInternal(true, releaseType, apnContext); + } + + if (isOnlySingleDcAllowed(getDataRat()) && !isHigherPriorityApnContextActive(apnContext)) { + if (DBG) log("disableApn:isOnlySingleDcAllowed true & higher priority APN disabled"); + // If the highest priority APN is disabled and only single + // data call is allowed, try to setup data call on other connectable APN. + setupDataOnAllConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION, + RetryFailures.ALWAYS); + } + } + + /** + * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value for user modification only + */ + public void setDataRoamingEnabledByUser(boolean enabled) { + mDataEnabledSettings.setDataRoamingEnabled(enabled); + setDataRoamingFromUserAction(true); + if (DBG) { + log("setDataRoamingEnabledByUser: set phoneSubId=" + mPhone.getSubId() + + " isRoaming=" + enabled); + } + } + + /** + * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value. + */ + public boolean getDataRoamingEnabled() { + boolean isDataRoamingEnabled = mDataEnabledSettings.getDataRoamingEnabled(); + + if (VDBG) { + log("getDataRoamingEnabled: phoneSubId=" + mPhone.getSubId() + + " isDataRoamingEnabled=" + isDataRoamingEnabled); + } + return isDataRoamingEnabled; + } + + /** + * Set default value for {@link android.provider.Settings.Global#DATA_ROAMING} + * if the setting is not from user actions. default value is based on carrier config and system + * properties. + */ + private void setDefaultDataRoamingEnabled() { + // For single SIM phones, this is a per phone property. + String setting = Settings.Global.DATA_ROAMING; + boolean useCarrierSpecificDefault = false; + if (mTelephonyManager.getSimCount() != 1) { + setting = setting + mPhone.getSubId(); + try { + Settings.Global.getInt(mResolver, setting); + } catch (SettingNotFoundException ex) { + // For msim, update to carrier default if uninitialized. + useCarrierSpecificDefault = true; + } + } else if (!isDataRoamingFromUserAction()) { + // for single sim device, update to carrier default if user action is not set + useCarrierSpecificDefault = true; + } + log("setDefaultDataRoamingEnabled: useCarrierSpecificDefault " + + useCarrierSpecificDefault); + if (useCarrierSpecificDefault) { + boolean defaultVal = mDataEnabledSettings.getDefaultDataRoamingEnabled(); + mDataEnabledSettings.setDataRoamingEnabled(defaultVal); + } + } + + private boolean isDataRoamingFromUserAction() { + final SharedPreferences sp = PreferenceManager + .getDefaultSharedPreferences(mPhone.getContext()); + // since we don't want to unset user preference from system update, pass true as the default + // value if shared pref does not exist and set shared pref to false explicitly from factory + // reset. + if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) { + sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit(); + } + return sp.getBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true); + } + + private void setDataRoamingFromUserAction(boolean isUserAction) { + final SharedPreferences.Editor sp = PreferenceManager + .getDefaultSharedPreferences(mPhone.getContext()).edit(); + sp.putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, isUserAction).commit(); + } + + // When the data roaming status changes from roaming to non-roaming. + private void onDataRoamingOff() { + if (DBG) log("onDataRoamingOff"); + + reevaluateDataConnections(); + + if (!getDataRoamingEnabled()) { + // TODO: Remove this once all old vendor RILs are gone. We don't need to set initial apn + // attach and send the data profile again as the modem should have both roaming and + // non-roaming protocol in place. Modem should choose the right protocol based on the + // roaming condition. + setDataProfilesAsNeeded(); + setInitialAttachApn(); + + // If the user did not enable data roaming, now when we transit from roaming to + // non-roaming, we should try to reestablish the data connection. + + setupDataOnAllConnectableApns(Phone.REASON_ROAMING_OFF, RetryFailures.ALWAYS); + } + } + + // This method is called + // 1. When the data roaming status changes from non-roaming to roaming. + // 2. When allowed data roaming settings is changed by the user. + private void onDataRoamingOnOrSettingsChanged(int messageType) { + if (DBG) log("onDataRoamingOnOrSettingsChanged"); + // Used to differentiate data roaming turned on vs settings changed. + boolean settingChanged = (messageType == DctConstants.EVENT_ROAMING_SETTING_CHANGE); + + // Check if the device is actually data roaming + if (!mPhone.getServiceState().getDataRoaming()) { + if (DBG) log("device is not roaming. ignored the request."); + return; + } + + checkDataRoamingStatus(settingChanged); + + if (getDataRoamingEnabled()) { + // If the restricted data was brought up when data roaming is disabled, and now users + // enable data roaming, we need to re-evaluate the conditions and possibly change the + // network's capability. + if (settingChanged) { + reevaluateDataConnections(); + } + + if (DBG) log("onDataRoamingOnOrSettingsChanged: setup data on roaming"); + + setupDataOnAllConnectableApns(Phone.REASON_ROAMING_ON, RetryFailures.ALWAYS); + } else { + // If the user does not turn on data roaming, when we transit from non-roaming to + // roaming, we need to tear down the data connection otherwise the user might be + // charged for data roaming usage. + if (DBG) log("onDataRoamingOnOrSettingsChanged: Tear down data connection on roaming."); + cleanUpAllConnectionsInternal(true, Phone.REASON_ROAMING_ON); + } + } + + // We want to track possible roaming data leakage. Which is, if roaming setting + // is disabled, yet we still setup a roaming data connection or have a connected ApnContext + // switched to roaming. When this happens, we log it in a local log. + private void checkDataRoamingStatus(boolean settingChanged) { + if (!settingChanged && !getDataRoamingEnabled() + && mPhone.getServiceState().getDataRoaming()) { + for (ApnContext apnContext : mApnContexts.values()) { + if (apnContext.getState() == DctConstants.State.CONNECTED) { + mDataRoamingLeakageLog.log("PossibleRoamingLeakage " + + " connection params: " + (apnContext.getDataConnection() != null + ? apnContext.getDataConnection().getConnectionParams() : "")); + } + } + } + } + + private void onRadioAvailable() { + if (DBG) log("onRadioAvailable"); + if (!areAllDataDisconnected()) { + cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, null); + } + } + + private void onRadioOffOrNotAvailable() { + // Make sure our reconnect delay starts at the initial value + // next time the radio comes on + + mReregisterOnReconnectFailure = false; + + // Clear auto attach as modem is expected to do a new attach + mAutoAttachEnabled.set(false); + + if (mPhone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + log("We're on the simulator; assuming radio off is meaningless"); + } else { + if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections"); + cleanUpAllConnectionsInternal(false, Phone.REASON_RADIO_TURNED_OFF); + } + } + + private void completeConnection(ApnContext apnContext, @RequestNetworkType int type) { + + if (DBG) log("completeConnection: successful, notify the world apnContext=" + apnContext); + + if (mIsProvisioning && !TextUtils.isEmpty(mProvisioningUrl)) { + if (DBG) { + log("completeConnection: MOBILE_PROVISIONING_ACTION url=" + + mProvisioningUrl); + } + Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, + Intent.CATEGORY_APP_BROWSER); + newIntent.setData(Uri.parse(mProvisioningUrl)); + newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mPhone.getContext().startActivity(newIntent); + } catch (ActivityNotFoundException e) { + loge("completeConnection: startActivityAsUser failed" + e); + } + } + mIsProvisioning = false; + mProvisioningUrl = null; + if (mProvisioningSpinner != null) { + sendMessage(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, + mProvisioningSpinner)); + } + + startNetStatPoll(); + startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); + + PersistableBundle b = getCarrierConfig(); + if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT + && b.getBoolean(CarrierConfigManager + .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) { + NotificationManager notificationManager = (NotificationManager) + mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.cancel(Integer.toString(mPhone.getSubId()), + NO_DATA_NOTIFICATION); + } + } + + /** + * A SETUP (aka bringUp) has completed, possibly with an error. If + * there is an error this method will call {@link #onDataSetupCompleteError}. + */ + protected void onDataSetupComplete(ApnContext apnContext, boolean success, + @DataFailureCause int cause, @RequestNetworkType int requestType, + @HandoverFailureMode int handoverFailureMode) { + boolean fallbackOnFailedHandover = shouldFallbackOnFailedHandover( + handoverFailureMode, requestType, cause); + + if (success && (handoverFailureMode != DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN + && handoverFailureMode != DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY)) { + Log.wtf(mLogTag, "bad failure mode: " + + DataCallResponse.failureModeToString(handoverFailureMode)); + } else if (handoverFailureMode + != DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER + && cause != DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE) { + sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), success, + fallbackOnFailedHandover); + } + + if (success) { + DataConnection dataConnection = apnContext.getDataConnection(); + + if (RADIO_TESTS) { + // Note: To change radio.test.onDSC.null.dcac from command line you need to + // adb root and adb remount and from the command line you can only change the + // value to 1 once. To change it a second time you can reboot or execute + // adb shell stop and then adb shell start. The command line to set the value is: + // adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');" + ContentResolver cr = mPhone.getContext().getContentResolver(); + String radioTestProperty = "radio.test.onDSC.null.dcac"; + if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) { + log("onDataSetupComplete: " + radioTestProperty + + " is true, set dcac to null and reset property to false"); + dataConnection = null; + Settings.System.putInt(cr, radioTestProperty, 0); + log("onDataSetupComplete: " + radioTestProperty + "=" + + Settings.System.getInt(mPhone.getContext().getContentResolver(), + radioTestProperty, -1)); + } + } + if (dataConnection == null) { + log("onDataSetupComplete: no connection to DC, handle as error"); + onDataSetupCompleteError(apnContext, requestType, false); + } else { + ApnSetting apn = apnContext.getApnSetting(); + if (DBG) { + log("onDataSetupComplete: success apn=" + (apn == null ? "unknown" + : apn.getApnName())); + } + + // everything is setup + if (TextUtils.equals(apnContext.getApnType(), ApnSetting.TYPE_DEFAULT_STRING) + && mCanSetPreferApn && mPreferredApn == null) { + if (DBG) log("onDataSetupComplete: PREFERRED APN is null"); + mPreferredApn = apn; + if (mPreferredApn != null) { + setPreferredApn(mPreferredApn.getId()); + } + } + + // A connection is setup + apnContext.setState(DctConstants.State.CONNECTED); + + checkDataRoamingStatus(false); + + boolean isProvApn = apnContext.isProvisioningApn(); + final ConnectivityManager cm = (ConnectivityManager) mPhone.getContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + if (mProvisionBroadcastReceiver != null) { + mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); + mProvisionBroadcastReceiver = null; + } + + if ((!isProvApn) || mIsProvisioning) { + if (mIsProvisioning) { + // Hide any notification that was showing previously + hideProvisioningNotification(); + } + + // Complete the connection normally notifying the world we're connected. + // We do this if this isn't a special provisioning apn or if we've been + // told its time to provision. + completeConnection(apnContext, requestType); + } else { + // This is a provisioning APN that we're reporting as connected. Later + // when the user desires to upgrade this to a "default" connection, + // mIsProvisioning == true, we'll go through the code path above. + // mIsProvisioning becomes true when CMD_ENABLE_MOBILE_PROVISIONING + // is sent to the DCT. + if (DBG) { + log("onDataSetupComplete: successful, BUT send connected to prov apn as" + + " mIsProvisioning:" + mIsProvisioning + " == false" + + " && (isProvisioningApn:" + isProvApn + " == true"); + } + + // While radio is up, grab provisioning URL. The URL contains ICCID which + // disappears when radio is off. + mProvisionBroadcastReceiver = new ProvisionNotificationBroadcastReceiver( + mPhone.getMobileProvisioningUrl(), + mTelephonyManager.getNetworkOperatorName()); + mPhone.getContext().registerReceiver(mProvisionBroadcastReceiver, + new IntentFilter(INTENT_PROVISION)); + + // Put up user notification that sign-in is required. + showProvisioningNotification(); + + // Turn off radio to save battery and avoid wasting carrier resources. + // The network isn't usable and network validation will just fail anyhow. + setRadio(false); + } + if (DBG) { + log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType()); + } + if (TelephonyUtils.IS_DEBUGGABLE) { + // adb shell setprop persist.radio.test.pco [pco_val] + String radioTestProperty = "persist.radio.test.pco"; + int pcoVal = SystemProperties.getInt(radioTestProperty, -1); + if (pcoVal != -1) { + log("PCO testing: read pco value from persist.radio.test.pco " + pcoVal); + final byte[] value = new byte[1]; + value[0] = (byte) pcoVal; + final Intent intent = + new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE); + intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, ApnSetting.TYPE_DEFAULT); + intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL, + ApnSetting.PROTOCOL_IPV4V6); + intent.putExtra(TelephonyManager.EXTRA_PCO_ID, 0xFF00); + intent.putExtra(TelephonyManager.EXTRA_PCO_VALUE, value); + mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); + } + } + } + } else { + if (DBG) { + ApnSetting apn = apnContext.getApnSetting(); + log("onDataSetupComplete: error apn=" + apn.getApnName() + ", cause=" + + DataFailCause.toString(cause) + ", requestType=" + + requestTypeToString(requestType)); + } + if (DataFailCause.isEventLoggable(cause)) { + // Log this failure to the Event Logs. + int cid = getCellLocationId(); + EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL, + cause, cid, mTelephonyManager.getNetworkType()); + } + ApnSetting apn = apnContext.getApnSetting(); + + // Compose broadcast intent send to the specific carrier signaling receivers + Intent intent = new Intent(TelephonyManager + .ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED); + intent.putExtra(TelephonyManager.EXTRA_DATA_FAIL_CAUSE, cause); + intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, + ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType())); + mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); + + if (DataFailCause.isRadioRestartFailure(mPhone.getContext(), cause, mPhone.getSubId()) + || apnContext.restartOnError(cause)) { + if (DBG) log("Modem restarted."); + sendRestartRadio(); + } + + // If the data call failure cause is a permanent failure, we mark the APN as permanent + // failed. + if (isPermanentFailure(cause)) { + log("cause=" + DataFailCause.toString(cause) + + ", mark apn as permanent failed. apn = " + apn); + apnContext.markApnPermanentFailed(apn); + + PersistableBundle b = getCarrierConfig(); + if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT + && b.getBoolean(CarrierConfigManager + .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) { + NotificationManager notificationManager = (NotificationManager) + mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE); + + CharSequence title = mPhone.getContext().getText( + com.android.internal.R.string.RestrictedOnDataTitle); + CharSequence details = mPhone.getContext().getText( + com.android.internal.R.string.RestrictedStateContent); + + Notification notification = new Notification.Builder(mPhone.getContext(), + NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS) + .setWhen(System.currentTimeMillis()) + .setAutoCancel(true) + .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning) + .setTicker(title) + .setColor(mPhone.getContext().getResources().getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setContentTitle(title) + .setStyle(new Notification.BigTextStyle().bigText(details)) + .setContentText(details) + .build(); + notificationManager.notify(Integer.toString(mPhone.getSubId()), + NO_DATA_NOTIFICATION, notification); + } + } + + int newRequestType = calculateNewRetryRequestType(handoverFailureMode, requestType, + cause); + onDataSetupCompleteError(apnContext, newRequestType, fallbackOnFailedHandover); + } + } + + + + /** + * Error has occurred during the SETUP {aka bringUP} request and the DCT + * should either try the next waiting APN or start over from the + * beginning if the list is empty. Between each SETUP request there will + * be a delay defined by {@link ApnContext#getDelayForNextApn(boolean)}. + */ + protected void onDataSetupCompleteError(ApnContext apnContext, + @RequestNetworkType int requestType, boolean fallbackOnFailedHandover) { + long delay = apnContext.getDelayForNextApn(mFailFast); + // Check if we need to retry or not. + if (delay >= 0 && delay != RetryManager.NO_RETRY && !fallbackOnFailedHandover) { + if (DBG) { + log("onDataSetupCompleteError: APN type=" + apnContext.getApnType() + + ". Request type=" + requestTypeToString(requestType) + ", Retry in " + + delay + "ms."); + } + startReconnect(delay, apnContext, requestType); + } else { + // If we are not going to retry any APN, set this APN context to failed state. + // This would be the final state of a data connection. + apnContext.setState(DctConstants.State.FAILED); + apnContext.setDataConnection(null); + log("onDataSetupCompleteError: Stop retrying APNs. delay=" + delay + + ", requestType=" + requestTypeToString(requestType)); + //send request network complete messages as needed + sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, + fallbackOnFailedHandover); + } + } + + /** + * Called when EVENT_NETWORK_STATUS_CHANGED is received. + * + * @param status One of {@code NetworkAgent.VALID_NETWORK} or + * {@code NetworkAgent.INVALID_NETWORK}. + * @param cid context id {@code cid} + * @param redirectUrl If the Internet probe was redirected, this + * is the destination it was redirected to, otherwise {@code null} + */ + private void onNetworkStatusChanged(int status, int cid, String redirectUrl) { + if (!TextUtils.isEmpty(redirectUrl)) { + Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED); + intent.putExtra(TelephonyManager.EXTRA_REDIRECTION_URL, redirectUrl); + mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); + log("Notify carrier signal receivers with redirectUrl: " + redirectUrl); + } else { + final boolean isValid = status == NetworkAgent.VALIDATION_STATUS_VALID; + final DataConnection dc = getDataConnectionByContextId(cid); + if (!mDsRecoveryHandler.isRecoveryOnBadNetworkEnabled()) { + if (DBG) log("Skip data stall recovery on network status change with in threshold"); + return; + } + if (mTransportType != AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + if (DBG) log("Skip data stall recovery on non WWAN"); + return; + } + if (dc != null && dc.isValidationRequired()) { + mDsRecoveryHandler.processNetworkStatusChanged(isValid); + } + } + } + + /** + * Called when EVENT_DISCONNECT_DONE is received. + */ + private void onDisconnectDone(ApnContext apnContext) { + if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext); + apnContext.setState(DctConstants.State.IDLE); + // If all data connection are gone, check whether Airplane mode request was pending. + if (areAllDataDisconnected() + && mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) { + if (DBG) log("onDisconnectDone: radio will be turned off, no retries"); + // Radio will be turned off. No need to retry data setup + apnContext.setApnSetting(null); + apnContext.setDataConnection(null); + + // Need to notify disconnect as well, in the case of switching Airplane mode. + // Otherwise, it would cause 30s delayed to turn on Airplane mode. + notifyAllDataDisconnected(); + return; + } + // If APN is still enabled, try to bring it back up automatically + if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) { + // Wait a bit before trying the next APN, so that + // we're not tying up the RIL command channel. + // This also helps in any external dependency to turn off the context. + if (DBG) log("onDisconnectDone: attached, ready and retry after disconnect"); + + // See if there are still handover request pending that we need to retry handover + // after previous data gets disconnected. + if (isHandoverPending(apnContext.getApnTypeBitmask())) { + if (DBG) log("Handover request pending. Retry handover immediately."); + startReconnect(0, apnContext, REQUEST_TYPE_HANDOVER); + } else { + long delay = apnContext.getRetryAfterDisconnectDelay(); + if (delay > 0) { + // Data connection is in IDLE state, so when we reconnect later, we'll rebuild + // the waiting APN list, which will also reset/reconfigure the retry manager. + startReconnect(delay, apnContext, REQUEST_TYPE_NORMAL); + } + } + } else { + boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean( + com.android.internal.R.bool.config_restartRadioAfterProvisioning); + + if (apnContext.isProvisioningApn() && restartRadioAfterProvisioning) { + log("onDisconnectDone: restartRadio after provisioning"); + restartRadio(); + } + apnContext.setApnSetting(null); + apnContext.setDataConnection(null); + if (isOnlySingleDcAllowed(getDataRat())) { + if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn"); + setupDataOnAllConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION, + RetryFailures.ALWAYS); + } else { + if(DBG) log("onDisconnectDone: not retrying"); + } + } + + if (areAllDataDisconnected()) { + apnContext.setConcurrentVoiceAndDataAllowed( + mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()); + notifyAllDataDisconnected(); + } + + } + + private void onVoiceCallStarted() { + if (DBG) log("onVoiceCallStarted"); + mInVoiceCall = true; + if (isAnyDataConnected() + && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { + if (DBG) log("onVoiceCallStarted stop polling"); + stopNetStatPoll(); + stopDataStallAlarm(); + } + } + + protected void onVoiceCallEnded() { + if (DBG) log("onVoiceCallEnded"); + mInVoiceCall = false; + if (isAnyDataConnected()) { + if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { + startNetStatPoll(); + startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); + } else { + // clean slate after call end. + resetPollStats(); + } + } + // reset reconnect timer + setupDataOnAllConnectableApns(Phone.REASON_VOICE_CALL_ENDED, RetryFailures.ALWAYS); + } + /** + * @return {@code true} if there is any data in connected state. + */ + @VisibleForTesting + public boolean isAnyDataConnected() { + for (DataConnection dc : mDataConnections.values()) { + if (dc.isActive()) { + return true; + } + } + return false; + } + + /** + * @return {@code true} if all data connections are in disconnected state. + */ + public boolean areAllDataDisconnected() { + for (DataConnection dc : mDataConnections.values()) { + if (!dc.isInactive()) { + if (DBG) log("areAllDataDisconnected false due to DC: " + dc.getName()); + return false; + } + } + return true; + } + + protected void setDataProfilesAsNeeded() { + if (DBG) log("setDataProfilesAsNeeded"); + + ArrayList dataProfileList = new ArrayList<>(); + + int preferredApnSetId = getPreferredApnSetId(); + for (ApnSetting apn : mAllApnSettings) { + if (apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID + || preferredApnSetId == apn.getApnSetId()) { + DataProfile dp = new DataProfile.Builder() + .setApnSetting(apn) + .setPreferred(apn.equals(getPreferredApn())) + .build(); + if (!dataProfileList.contains(dp)) { + dataProfileList.add(dp); + } + } else { + if (VDBG) { + log("setDataProfilesAsNeeded: APN set id " + apn.getApnSetId() + + " does not match the preferred set id " + preferredApnSetId); + } + } + } + + // Check if the data profiles we are sending are same as we did last time. We don't want to + // send the redundant profiles to the modem. Also if there the list is empty, we don't + // send it to the modem. + if (!dataProfileList.isEmpty() + && (dataProfileList.size() != mLastDataProfileList.size() + || !mLastDataProfileList.containsAll(dataProfileList))) { + mDataServiceManager.setDataProfile(dataProfileList, + mPhone.getServiceState().getDataRoamingFromRegistration(), null); + } + } + + /** + * Based on the sim operator numeric, create a list for all possible + * Data Connections and setup the preferredApn. + */ + protected void createAllApnList() { + mAllApnSettings.clear(); + String operator = mPhone.getOperatorNumeric(); + + // ORDER BY Telephony.Carriers._ID ("_id") + Cursor cursor = mPhone.getContext().getContentResolver().query( + Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, "filtered/subId/" + + mPhone.getSubId()), null, null, null, Telephony.Carriers._ID); + + if (cursor != null) { + while (cursor.moveToNext()) { + ApnSetting apn = ApnSetting.makeApnSetting(cursor); + if (apn == null) { + continue; + } + mAllApnSettings.add(apn); + } + cursor.close(); + } else { + if (DBG) log("createAllApnList: cursor is null"); + mApnSettingsInitializationLog.log("cursor is null for carrier, operator: " + + operator); + } + + dedupeApnSettings(); + + if (mAllApnSettings.isEmpty()) { + log("createAllApnList: No APN found for carrier, operator: " + operator); + mApnSettingsInitializationLog.log("no APN found for carrier, operator: " + + operator); + mPreferredApn = null; + } else { + mPreferredApn = getPreferredApn(); + if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn); + } + + addDefaultApnSettingsAsNeeded(); + if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings); + } + + private void dedupeApnSettings() { + ArrayList resultApns = new ArrayList(); + + // coalesce APNs if they are similar enough to prevent + // us from bringing up two data calls with the same interface + int i = 0; + while (i < mAllApnSettings.size() - 1) { + ApnSetting first = mAllApnSettings.get(i); + ApnSetting second = null; + int j = i + 1; + while (j < mAllApnSettings.size()) { + second = mAllApnSettings.get(j); + if (first.similar(second)) { + ApnSetting newApn = mergeApns(first, second); + mAllApnSettings.set(i, newApn); + first = newApn; + mAllApnSettings.remove(j); + } else { + j++; + } + } + i++; + } + } + + private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) { + int id = dest.getId(); + if ((src.getApnTypeBitmask() & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) { + id = src.getId(); + } + final int resultApnType = src.getApnTypeBitmask() | dest.getApnTypeBitmask(); + Uri mmsc = (dest.getMmsc() == null ? src.getMmsc() : dest.getMmsc()); + String mmsProxy = TextUtils.isEmpty(dest.getMmsProxyAddressAsString()) + ? src.getMmsProxyAddressAsString() : dest.getMmsProxyAddressAsString(); + int mmsPort = dest.getMmsProxyPort() == -1 ? src.getMmsProxyPort() : dest.getMmsProxyPort(); + String proxy = TextUtils.isEmpty(dest.getProxyAddressAsString()) + ? src.getProxyAddressAsString() : dest.getProxyAddressAsString(); + int port = dest.getProxyPort() == -1 ? src.getProxyPort() : dest.getProxyPort(); + int protocol = src.getProtocol() == ApnSetting.PROTOCOL_IPV4V6 ? src.getProtocol() + : dest.getProtocol(); + int roamingProtocol = src.getRoamingProtocol() == ApnSetting.PROTOCOL_IPV4V6 + ? src.getRoamingProtocol() : dest.getRoamingProtocol(); + int networkTypeBitmask = (dest.getNetworkTypeBitmask() == 0 + || src.getNetworkTypeBitmask() == 0) + ? 0 : (dest.getNetworkTypeBitmask() | src.getNetworkTypeBitmask()); + return new ApnSetting.Builder() + .setId(id) + .setOperatorNumeric(dest.getOperatorNumeric()) + .setEntryName(dest.getEntryName()) + .setApnName(dest.getApnName()) + .setProxyAddress(proxy) + .setProxyPort(port) + .setMmsc(mmsc) + .setMmsProxyAddress(mmsProxy) + .setMmsProxyPort(mmsPort) + .setUser(dest.getUser()) + .setPassword(dest.getPassword()) + .setAuthType(dest.getAuthType()) + .setApnTypeBitmask(resultApnType) + .setProtocol(protocol) + .setRoamingProtocol(roamingProtocol) + .setCarrierEnabled(dest.isEnabled()) + .setNetworkTypeBitmask(networkTypeBitmask) + .setProfileId(dest.getProfileId()) + .setModemCognitive(dest.isPersistent() || src.isPersistent()) + .setMaxConns(dest.getMaxConns()) + .setWaitTime(dest.getWaitTime()) + .setMaxConnsTime(dest.getMaxConnsTime()) + .setMtuV4(dest.getMtuV4()) + .setMtuV6(dest.getMtuV6()) + .setMvnoType(dest.getMvnoType()) + .setMvnoMatchData(dest.getMvnoMatchData()) + .setApnSetId(dest.getApnSetId()) + .setCarrierId(dest.getCarrierId()) + .setSkip464Xlat(dest.getSkip464Xlat()) + .build(); + } + + private DataConnection createDataConnection() { + if (DBG) log("createDataConnection E"); + + int id = mUniqueIdGenerator.getAndIncrement(); + DataConnection dataConnection = DataConnection.makeDataConnection(mPhone, id, this, + mDataServiceManager, mDcTesterFailBringUpAll, mDcc); + mDataConnections.put(id, dataConnection); + if (DBG) log("createDataConnection() X id=" + id + " dc=" + dataConnection); + return dataConnection; + } + + private void destroyDataConnections() { + if(mDataConnections != null) { + if (DBG) log("destroyDataConnections: clear mDataConnectionList"); + mDataConnections.clear(); + } else { + if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore"); + } + } + + /** + * Build a list of APNs to be used to create PDP's. + * + * @param requestedApnType + * @return waitingApns list to be used to create PDP + * error when waitingApns.isEmpty() + */ + private @NonNull ArrayList buildWaitingApns(String requestedApnType, + int radioTech) { + if (DBG) log("buildWaitingApns: E requestedApnType=" + requestedApnType); + ArrayList apnList = new ArrayList(); + + int requestedApnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(requestedApnType); + if (requestedApnTypeBitmask == ApnSetting.TYPE_ENTERPRISE) { + requestedApnTypeBitmask = ApnSetting.TYPE_DEFAULT; + } + if (requestedApnTypeBitmask == ApnSetting.TYPE_DUN) { + ArrayList dunApns = fetchDunApns(); + if (dunApns.size() > 0) { + for (ApnSetting dun : dunApns) { + apnList.add(dun); + if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList); + } + return apnList; + } + } + + String operator = mPhone.getOperatorNumeric(); + + // This is a workaround for a bug (7305641) where we don't failover to other + // suitable APNs if our preferred APN fails. On prepaid ATT sims we need to + // failover to a provisioning APN, but once we've used their default data + // connection we are locked to it for life. This change allows ATT devices + // to say they don't want to use preferred at all. + boolean usePreferred = true; + try { + usePreferred = !mPhone.getContext().getResources().getBoolean(com.android + .internal.R.bool.config_dontPreferApn); + } catch (Resources.NotFoundException e) { + if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true"); + usePreferred = true; + } + if (usePreferred) { + mPreferredApn = getPreferredApn(); + } + if (DBG) { + log("buildWaitingApns: usePreferred=" + usePreferred + + " canSetPreferApn=" + mCanSetPreferApn + + " mPreferredApn=" + mPreferredApn + + " operator=" + operator + " radioTech=" + radioTech); + } + + if (usePreferred && mCanSetPreferApn && mPreferredApn != null && + mPreferredApn.canHandleType(requestedApnTypeBitmask)) { + if (DBG) { + log("buildWaitingApns: Preferred APN:" + operator + ":" + + mPreferredApn.getOperatorNumeric() + ":" + mPreferredApn); + } + + if (TextUtils.equals(mPreferredApn.getOperatorNumeric(), operator) + || mPreferredApn.getCarrierId() == mPhone.getCarrierId()) { + if (mPreferredApn.canSupportNetworkType( + ServiceState.rilRadioTechnologyToNetworkType(radioTech))) { + // Create a new instance of ApnSetting for ENTERPRISE because each + // DataConnection should have its own ApnSetting. ENTERPRISE uses the same + // APN as DEFAULT but is a separate DataConnection + if (ApnSetting.getApnTypesBitmaskFromString(requestedApnType) + == ApnSetting.TYPE_ENTERPRISE) { + apnList.add(ApnSetting.makeApnSetting(mPreferredApn)); + } else { + apnList.add(mPreferredApn); + } + if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList); + return apnList; + } + } + if (DBG) log("buildWaitingApns: no preferred APN"); + setPreferredApn(-1); + mPreferredApn = null; + } + + if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings); + int preferredApnSetId = getPreferredApnSetId(); + for (ApnSetting apn : mAllApnSettings) { + if (apn.canHandleType(requestedApnTypeBitmask)) { + if (apn.canSupportNetworkType( + ServiceState.rilRadioTechnologyToNetworkType(radioTech))) { + if (apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID + || preferredApnSetId == apn.getApnSetId()) { + if (VDBG) log("buildWaitingApns: adding apn=" + apn); + // Create a new instance of ApnSetting for ENTERPRISE because each + // DataConnection should have its own ApnSetting. ENTERPRISE uses the same + // APN as DEFAULT but is a separate DataConnection + if (ApnSetting.getApnTypesBitmaskFromString(requestedApnType) + == ApnSetting.TYPE_ENTERPRISE) { + apnList.add(ApnSetting.makeApnSetting(apn)); + } else { + apnList.add(apn); + } + } else { + log("buildWaitingApns: APN set id " + apn.getApnSetId() + + " does not match the preferred set id " + preferredApnSetId); + } + } else { + if (DBG) { + log("buildWaitingApns: networkTypeBitmask:" + + apn.getNetworkTypeBitmask() + + " does not include radioTech:" + + ServiceState.rilRadioTechnologyToString(radioTech)); + } + } + } else if (VDBG) { + log("buildWaitingApns: couldn't handle requested ApnType=" + + requestedApnType); + } + } + + if (DBG) log("buildWaitingApns: " + apnList.size() + " APNs in the list: " + apnList); + return apnList; + } + + private String apnListToString (ArrayList apns) { + StringBuilder result = new StringBuilder(); + for (int i = 0, size = apns.size(); i < size; i++) { + result.append('[') + .append(apns.get(i).toString()) + .append(']'); + } + return result.toString(); + } + + private void setPreferredApn(int pos) { + setPreferredApn(pos, false); + } + + private void setPreferredApn(int pos, boolean force) { + if (!force && !mCanSetPreferApn) { + log("setPreferredApn: X !canSEtPreferApn"); + return; + } + + String subId = Long.toString(mPhone.getSubId()); + Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); + log("setPreferredApn: delete"); + ContentResolver resolver = mPhone.getContext().getContentResolver(); + resolver.delete(uri, null, null); + + if (pos >= 0) { + log("setPreferredApn: insert"); + ContentValues values = new ContentValues(); + values.put(APN_ID, pos); + resolver.insert(uri, values); + } + } + + @Nullable + ApnSetting getPreferredApn() { + //Only call this method from main thread + if (mAllApnSettings == null || mAllApnSettings.isEmpty()) { + log("getPreferredApn: mAllApnSettings is empty"); + return null; + } + + String subId = Long.toString(mPhone.getSubId()); + Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); + Cursor cursor = mPhone.getContext().getContentResolver().query( + uri, new String[] { "_id", "name", "apn" }, + null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); + + if (cursor != null) { + mCanSetPreferApn = true; + } else { + mCanSetPreferApn = false; + } + + if (VDBG) { + log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor + + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0)); + } + + if (mCanSetPreferApn && cursor.getCount() > 0) { + int pos; + cursor.moveToFirst(); + pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); + for(ApnSetting p : mAllApnSettings) { + if (p.getId() == pos && p.canHandleType(mRequestedApnType)) { + log("getPreferredApn: For APN type " + + ApnSetting.getApnTypeString(mRequestedApnType) + + " found apnSetting " + p); + cursor.close(); + return p; + } + } + } + + if (cursor != null) { + cursor.close(); + } + + log("getPreferredApn: X not found"); + return null; + } + + @Override + public void handleMessage (Message msg) { + if (VDBG) log("handleMessage msg=" + msg); + + AsyncResult ar; + Pair pair; + ApnContext apnContext; + int generation; + int requestType; + int handoverFailureMode; + switch (msg.what) { + case DctConstants.EVENT_DATA_CONNECTION_DETACHED: + onDataConnectionDetached(); + break; + + case DctConstants.EVENT_DATA_CONNECTION_ATTACHED: + onDataConnectionAttached(); + break; + + case DctConstants.EVENT_DO_RECOVERY: + mDsRecoveryHandler.doRecovery(); + break; + + case DctConstants.EVENT_APN_CHANGED: + onApnChanged(); + break; + + case DctConstants.EVENT_PS_RESTRICT_ENABLED: + /** + * We don't need to explicitly to tear down the PDP context + * when PS restricted is enabled. The base band will deactive + * PDP context and notify us with PDP_CONTEXT_CHANGED. + * But we should stop the network polling and prevent reset PDP. + */ + if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); + stopNetStatPoll(); + stopDataStallAlarm(); + mIsPsRestricted = true; + break; + + case DctConstants.EVENT_PS_RESTRICT_DISABLED: + /** + * When PS restrict is removed, we need setup PDP connection if + * PDP connection is down. + */ + if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); + mIsPsRestricted = false; + if (isAnyDataConnected()) { + startNetStatPoll(); + startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); + } else { + // TODO: Should all PDN states be checked to fail? + if (mState == DctConstants.State.FAILED) { + cleanUpAllConnectionsInternal(false, Phone.REASON_PS_RESTRICT_ENABLED); + mReregisterOnReconnectFailure = false; + } + apnContext = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT); + if (apnContext != null) { + apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED); + trySetupData(apnContext, REQUEST_TYPE_NORMAL, null); + } else { + loge("**** Default ApnContext not found ****"); + if (TelephonyUtils.IS_DEBUGGABLE) { + throw new RuntimeException("Default ApnContext not found"); + } + } + } + break; + + case DctConstants.EVENT_TRY_SETUP_DATA: + apnContext = (ApnContext) msg.obj; + requestType = msg.arg1; + trySetupData(apnContext, requestType, null); + break; + case DctConstants.EVENT_CLEAN_UP_CONNECTION: + if (DBG) log("EVENT_CLEAN_UP_CONNECTION"); + cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, (ApnContext) msg.obj); + break; + case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS: + if ((msg.obj != null) && (msg.obj instanceof String == false)) { + msg.obj = null; + } + cleanUpAllConnectionsInternal(true, (String) msg.obj); + break; + + case DctConstants.EVENT_DATA_RAT_CHANGED: + if (getDataRat() == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) { + // unknown rat is an exception for data rat change. It's only received when out + // of service and is not applicable for apn bearer bitmask. We should bypass the + // check of waiting apn list and keep the data connection on, and no need to + // setup a new one. + break; + } + cleanUpConnectionsOnUpdatedApns(false, Phone.REASON_NW_TYPE_CHANGED); + //May new Network allow setupData, so try it here + setupDataOnAllConnectableApns(Phone.REASON_NW_TYPE_CHANGED, + RetryFailures.ONLY_ON_CHANGE); + break; + + case DctConstants.CMD_CLEAR_PROVISIONING_SPINNER: + // Check message sender intended to clear the current spinner. + if (mProvisioningSpinner == msg.obj) { + mProvisioningSpinner.dismiss(); + mProvisioningSpinner = null; + } + break; + + case DctConstants.EVENT_ENABLE_APN: + onEnableApn(msg.arg1, msg.arg2, (Message) msg.obj); + break; + + case DctConstants.EVENT_DISABLE_APN: + onDisableApn(msg.arg1, msg.arg2); + break; + + case DctConstants.EVENT_DATA_STALL_ALARM: + onDataStallAlarm(msg.arg1); + break; + + case DctConstants.EVENT_ROAMING_OFF: + onDataRoamingOff(); + break; + + case DctConstants.EVENT_ROAMING_ON: + case DctConstants.EVENT_ROAMING_SETTING_CHANGE: + onDataRoamingOnOrSettingsChanged(msg.what); + break; + + case DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE: + // Update sharedPreference to false when exits new device provisioning, indicating + // no users modifications on the settings for new devices. Thus carrier specific + // default roaming settings can be applied for new devices till user modification. + final SharedPreferences sp = PreferenceManager + .getDefaultSharedPreferences(mPhone.getContext()); + if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) { + sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit(); + } + break; + + case DctConstants.EVENT_NETWORK_STATUS_CHANGED: + int status = msg.arg1; + int cid = msg.arg2; + String url = (String) msg.obj; + onNetworkStatusChanged(status, cid, url); + break; + + case DctConstants.EVENT_RADIO_AVAILABLE: + onRadioAvailable(); + break; + + case DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + onRadioOffOrNotAvailable(); + break; + + case DctConstants.EVENT_DATA_SETUP_COMPLETE: + ar = (AsyncResult) msg.obj; + pair = (Pair) ar.userObj; + apnContext = pair.first; + generation = pair.second; + requestType = msg.arg1; + handoverFailureMode = msg.arg2; + if (apnContext.getConnectionGeneration() == generation) { + boolean success = true; + int cause = DataFailCause.UNKNOWN; + if (ar.exception != null) { + success = false; + cause = (int) ar.result; + } + onDataSetupComplete(apnContext, success, cause, requestType, + handoverFailureMode); + } else { + loge("EVENT_DATA_SETUP_COMPLETE: Dropped the event because generation " + + "did not match."); + } + break; + + case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR: + ar = (AsyncResult) msg.obj; + pair = (Pair) ar.userObj; + apnContext = pair.first; + generation = pair.second; + handoverFailureMode = msg.arg2; + if (apnContext.getConnectionGeneration() == generation) { + onDataSetupCompleteError(apnContext, handoverFailureMode, false); + } else { + loge("EVENT_DATA_SETUP_COMPLETE_ERROR: Dropped the event because generation " + + "did not match."); + } + break; + + case DctConstants.EVENT_DISCONNECT_DONE: + log("EVENT_DISCONNECT_DONE msg=" + msg); + ar = (AsyncResult) msg.obj; + pair = (Pair) ar.userObj; + apnContext = pair.first; + generation = pair.second; + if (apnContext.getConnectionGeneration() == generation) { + onDisconnectDone(apnContext); + } else { + loge("EVENT_DISCONNECT_DONE: Dropped the event because generation " + + "did not match."); + } + break; + + case DctConstants.EVENT_VOICE_CALL_STARTED: + onVoiceCallStarted(); + break; + + case DctConstants.EVENT_VOICE_CALL_ENDED: + onVoiceCallEnded(); + break; + case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: { + sEnableFailFastRefCounter += (msg.arg1 == DctConstants.ENABLED) ? 1 : -1; + if (DBG) { + log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: " + + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter); + } + if (sEnableFailFastRefCounter < 0) { + final String s = "CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: " + + "sEnableFailFastRefCounter:" + sEnableFailFastRefCounter + " < 0"; + loge(s); + sEnableFailFastRefCounter = 0; + } + final boolean enabled = sEnableFailFastRefCounter > 0; + if (DBG) { + log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled + + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter); + } + if (mFailFast != enabled) { + mFailFast = enabled; + + mDataStallNoRxEnabled = !enabled; + if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled() + && isAnyDataConnected() + && (!mInVoiceCall || + mPhone.getServiceStateTracker() + .isConcurrentVoiceAndDataAllowed())) { + if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall"); + stopDataStallAlarm(); + startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); + } else { + if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall"); + stopDataStallAlarm(); + } + } + + break; + } + case DctConstants.CMD_ENABLE_MOBILE_PROVISIONING: { + Bundle bundle = msg.getData(); + if (bundle != null) { + try { + mProvisioningUrl = (String)bundle.get(DctConstants.PROVISIONING_URL_KEY); + } catch(ClassCastException e) { + loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url not a string" + e); + mProvisioningUrl = null; + } + } + if (TextUtils.isEmpty(mProvisioningUrl)) { + loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url is empty, ignoring"); + mIsProvisioning = false; + mProvisioningUrl = null; + } else { + loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioningUrl=" + mProvisioningUrl); + mIsProvisioning = true; + startProvisioningApnAlarm(); + } + break; + } + case DctConstants.EVENT_PROVISIONING_APN_ALARM: { + if (DBG) log("EVENT_PROVISIONING_APN_ALARM"); + ApnContext apnCtx = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT); + if (apnCtx.isProvisioningApn() && apnCtx.isConnectedOrConnecting()) { + if (mProvisioningApnAlarmTag == msg.arg1) { + if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Disconnecting"); + mIsProvisioning = false; + mProvisioningUrl = null; + stopProvisioningApnAlarm(); + cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnCtx); + } else { + if (DBG) { + log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag," + + " mProvisioningApnAlarmTag:" + mProvisioningApnAlarmTag + + " != arg1:" + msg.arg1); + } + } + } else { + if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Not connected ignore"); + } + break; + } + case DctConstants.CMD_IS_PROVISIONING_APN: { + if (DBG) log("CMD_IS_PROVISIONING_APN"); + boolean isProvApn; + try { + String apnType = null; + Bundle bundle = msg.getData(); + if (bundle != null) { + apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY); + } + if (TextUtils.isEmpty(apnType)) { + loge("CMD_IS_PROVISIONING_APN: apnType is empty"); + isProvApn = false; + } else { + isProvApn = isProvisioningApn(apnType); + } + } catch (ClassCastException e) { + loge("CMD_IS_PROVISIONING_APN: NO provisioning url ignoring"); + isProvApn = false; + } + if (DBG) log("CMD_IS_PROVISIONING_APN: ret=" + isProvApn); + mReplyAc.replyToMessage(msg, DctConstants.CMD_IS_PROVISIONING_APN, + isProvApn ? DctConstants.ENABLED : DctConstants.DISABLED); + break; + } + case DctConstants.EVENT_RESTART_RADIO: { + restartRadio(); + break; + } + case DctConstants.CMD_NET_STAT_POLL: { + if (msg.arg1 == DctConstants.ENABLED) { + handleStartNetStatPoll((DctConstants.Activity)msg.obj); + } else if (msg.arg1 == DctConstants.DISABLED) { + handleStopNetStatPoll((DctConstants.Activity)msg.obj); + } + break; + } + case DctConstants.EVENT_PCO_DATA_RECEIVED: { + handlePcoData((AsyncResult)msg.obj); + break; + } + case DctConstants.EVENT_DATA_RECONNECT: + if (DBG) { + log("EVENT_DATA_RECONNECT: subId=" + msg.arg1 + ", type=" + + requestTypeToString(msg.arg2)); + } + onDataReconnect((ApnContext) msg.obj, msg.arg1, msg.arg2); + break; + case DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED: + onDataServiceBindingChanged((Boolean) ((AsyncResult) msg.obj).result); + break; + case DctConstants.EVENT_DATA_ENABLED_CHANGED: + ar = (AsyncResult) msg.obj; + if (ar.result instanceof Pair) { + Pair p = (Pair) ar.result; + boolean enabled = p.first; + int reason = p.second; + onDataEnabledChanged(enabled, reason); + } + break; + case DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED: + onDataEnabledOverrideRulesChanged(); + break; + case DctConstants.EVENT_NR_TIMER_WATCHDOG: + mWatchdog = false; + reevaluateUnmeteredConnections(); + break; + case DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED: + reevaluateCongestedConnections(); + reevaluateUnmeteredConnections(); + break; + case DctConstants.EVENT_CARRIER_CONFIG_CHANGED: + onCarrierConfigChanged(); + break; + case DctConstants.EVENT_SIM_STATE_UPDATED: + int simState = msg.arg1; + onSimStateUpdated(simState); + break; + case DctConstants.EVENT_APN_UNTHROTTLED: + ar = (AsyncResult) msg.obj; + String apn = (String) ar.result; + onApnUnthrottled(apn); + break; + case DctConstants.EVENT_TRAFFIC_DESCRIPTORS_UPDATED: + onTrafficDescriptorsUpdated(); + break; + default: + Rlog.e("DcTracker", "Unhandled event=" + msg); + break; + + } + } + + private int getApnProfileID(String apnType) { + if (TextUtils.equals(apnType, ApnSetting.TYPE_IMS_STRING)) { + return RILConstants.DATA_PROFILE_IMS; + } else if (TextUtils.equals(apnType, ApnSetting.TYPE_FOTA_STRING)) { + return RILConstants.DATA_PROFILE_FOTA; + } else if (TextUtils.equals(apnType, ApnSetting.TYPE_CBS_STRING)) { + return RILConstants.DATA_PROFILE_CBS; + } else if (TextUtils.equals(apnType, ApnSetting.TYPE_IA_STRING)) { + return RILConstants.DATA_PROFILE_DEFAULT; // DEFAULT for now + } else if (TextUtils.equals(apnType, ApnSetting.TYPE_DUN_STRING)) { + return RILConstants.DATA_PROFILE_TETHERED; + } else { + return RILConstants.DATA_PROFILE_DEFAULT; + } + } + + private int getCellLocationId() { + int cid = -1; + CellLocation loc = mPhone.getCurrentCellIdentity().asCellLocation(); + + if (loc != null) { + if (loc instanceof GsmCellLocation) { + cid = ((GsmCellLocation)loc).getCid(); + } else if (loc instanceof CdmaCellLocation) { + cid = ((CdmaCellLocation)loc).getBaseStationId(); + } + } + return cid; + } + + /** + * Update link bandwidth estimate default values from carrier config. + * @param bandwidths String array of "RAT:upstream,downstream" for each RAT + * @param useLte For NR NSA, whether to use LTE value for upstream or not + */ + private void updateLinkBandwidths(String[] bandwidths, boolean useLte) { + ConcurrentHashMap> temp = new ConcurrentHashMap<>(); + for (String config : bandwidths) { + int downstream = 14; + int upstream = 14; + String[] kv = config.split(":"); + if (kv.length == 2) { + String[] split = kv[1].split(","); + if (split.length == 2) { + try { + downstream = Integer.parseInt(split[0]); + upstream = Integer.parseInt(split[1]); + } catch (NumberFormatException ignored) { + } + } + temp.put(kv[0], new Pair<>(downstream, upstream)); + } + } + if (useLte) { + Pair ltePair = + temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_LTE); + if (ltePair != null) { + if (temp.containsKey(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA)) { + temp.put(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA, new Pair<>( + temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA).first, + ltePair.second)); + } + if (temp.containsKey(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE)) { + temp.put(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE, new Pair<>( + temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE) + .first, ltePair.second)); + } + } + } + mBandwidths = temp; + for (DataConnection dc : mDataConnections.values()) { + dc.sendMessage(DataConnection.EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED); + } + } + + /** + * Return the link upstream/downstream values from CarrierConfig for the given RAT name. + * @param ratName RAT name from ServiceState#rilRadioTechnologyToString. + * @return pair of downstream/upstream values (kbps), or null if the config is not defined. + */ + public Pair getLinkBandwidthsFromCarrierConfig(String ratName) { + return mBandwidths.get(ratName); + } + + @VisibleForTesting + public boolean shouldAutoAttach() { + if (mAutoAttachEnabled.get()) return true; + + PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); + ServiceState serviceState = mPhone.getServiceState(); + + if (phoneSwitcher == null || serviceState == null) return false; + + // If voice is also not in service, don't auto attach. + if (serviceState.getState() != ServiceState.STATE_IN_SERVICE) return false; + + // If voice is on LTE or NR, don't auto attach as for LTE / NR data would be attached. + if (serviceState.getVoiceNetworkType() == NETWORK_TYPE_LTE + || serviceState.getVoiceNetworkType() == NETWORK_TYPE_NR) return false; + + // If phone is non default phone, modem may have detached from data for optimization. + // If phone is in voice call, for DSDS case DDS switch may be limited so we do try our + // best to setup data connection and allow auto-attach. + return (mPhone.getPhoneId() != phoneSwitcher.getPreferredDataPhoneId() + || mPhone.getState() != PhoneConstants.State.IDLE); + } + + private void notifyAllDataDisconnected() { + sEnableFailFastRefCounter = 0; + mFailFast = false; + log("notify all data disconnected"); + mAllDataDisconnectedRegistrants.notifyRegistrants(); + } + + public void registerForAllDataDisconnected(Handler h, int what) { + mAllDataDisconnectedRegistrants.addUnique(h, what, null); + + if (areAllDataDisconnected()) { + notifyAllDataDisconnected(); + } + } + + public void unregisterForAllDataDisconnected(Handler h) { + mAllDataDisconnectedRegistrants.remove(h); + } + + private void onDataEnabledChanged(boolean enable, + @DataEnabledChangedReason int enabledChangedReason) { + if (DBG) { + log("onDataEnabledChanged: enable=" + enable + ", enabledChangedReason=" + + enabledChangedReason); + } + + if (enable) { + reevaluateDataConnections(); + setupDataOnAllConnectableApns(Phone.REASON_DATA_ENABLED, RetryFailures.ALWAYS); + } else { + String cleanupReason; + switch (enabledChangedReason) { + case DataEnabledSettings.REASON_INTERNAL_DATA_ENABLED: + cleanupReason = Phone.REASON_DATA_DISABLED_INTERNAL; + break; + case DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER: + cleanupReason = Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN; + break; + case DataEnabledSettings.REASON_USER_DATA_ENABLED: + case DataEnabledSettings.REASON_POLICY_DATA_ENABLED: + case DataEnabledSettings.REASON_PROVISIONED_CHANGED: + case DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED: + default: + cleanupReason = Phone.REASON_DATA_SPECIFIC_DISABLED; + break; + + } + cleanUpAllConnectionsInternal(true, cleanupReason); + } + } + + private void reevaluateCongestedConnections() { + log("reevaluateCongestedConnections"); + int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); + // congested override and either network is specified or unknown and all networks specified + boolean isCongested = mCongestedOverride && (mCongestedNetworkTypes.contains(rat) + || mCongestedNetworkTypes.containsAll(Arrays.stream( + TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet()))); + for (DataConnection dataConnection : mDataConnections.values()) { + dataConnection.onCongestednessChanged(isCongested); + } + } + + private void reevaluateUnmeteredConnections() { + log("reevaluateUnmeteredConnections"); + int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); + if (isNrUnmetered() && (!mPhone.getServiceState().getRoaming() || mNrNsaRoamingUnmetered)) { + setDataConnectionUnmetered(true); + if (!mWatchdog) { + startWatchdogAlarm(); + } + } else { + stopWatchdogAlarm(); + setDataConnectionUnmetered(isNetworkTypeUnmetered(rat)); + } + } + + private void setDataConnectionUnmetered(boolean isUnmetered) { + if (!isUnmetered || isTempNotMeteredSupportedByCarrier()) { + for (DataConnection dataConnection : mDataConnections.values()) { + dataConnection.onMeterednessChanged(isUnmetered); + } + } + } + + private boolean isNetworkTypeUnmetered(@NetworkType int networkType) { + boolean isUnmetered; + if (mUnmeteredNetworkTypes == null || !mUnmeteredOverride) { + // check SubscriptionPlans if override is not defined + isUnmetered = isNetworkTypeUnmeteredViaSubscriptionPlan(networkType); + log("isNetworkTypeUnmeteredViaSubscriptionPlan: networkType=" + networkType + + ", isUnmetered=" + isUnmetered); + return isUnmetered; + } + // unmetered override and either network is specified or unknown and all networks specified + isUnmetered = mUnmeteredNetworkTypes.contains(networkType) + || mUnmeteredNetworkTypes.containsAll(Arrays.stream( + TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet())); + if (DBG) { + log("isNetworkTypeUnmetered: networkType=" + networkType + + ", isUnmetered=" + isUnmetered); + } + return isUnmetered; + } + + private boolean isNetworkTypeUnmeteredViaSubscriptionPlan(@NetworkType int networkType) { + if (mSubscriptionPlans.isEmpty()) { + // safe return false if unable to get subscription plans or plans don't exist + return false; + } + + boolean isGeneralUnmetered = true; + Set allNetworkTypes = Arrays.stream(TelephonyManager.getAllNetworkTypes()) + .boxed().collect(Collectors.toSet()); + for (SubscriptionPlan plan : mSubscriptionPlans) { + // check plan is general (applies to all network types) or specific + if (Arrays.stream(plan.getNetworkTypes()).boxed().collect(Collectors.toSet()) + .containsAll(allNetworkTypes)) { + if (!isPlanUnmetered(plan)) { + // metered takes precedence over unmetered for safety + isGeneralUnmetered = false; + } + } else { + // check plan applies to given network type + if (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN) { + for (int planNetworkType : plan.getNetworkTypes()) { + if (planNetworkType == networkType) { + return isPlanUnmetered(plan); + } + } + } + } + } + return isGeneralUnmetered; + } + + private boolean isPlanUnmetered(SubscriptionPlan plan) { + return plan.getDataLimitBytes() == SubscriptionPlan.BYTES_UNLIMITED; + } + + private boolean isNrUnmetered() { + int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); + int override = mPhone.getDisplayInfoController().getTelephonyDisplayInfo() + .getOverrideNetworkType(); + + if (isNetworkTypeUnmetered(NETWORK_TYPE_NR)) { + if (mNrNsaMmwaveUnmetered) { + if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) { + if (DBG) log("NR unmetered for mmwave only"); + return true; + } + return false; + } else if (mNrNsaSub6Unmetered) { + if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { + if (DBG) log("NR unmetered for sub6 only"); + return true; + } + return false; + } + if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED + || override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA + || rat == NETWORK_TYPE_NR) { + if (DBG) log("NR unmetered for all frequencies"); + return true; + } + return false; + } + + if (mNrNsaAllUnmetered) { + if (mNrNsaMmwaveUnmetered) { + if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) { + if (DBG) log("NR NSA unmetered for mmwave only via carrier configs"); + return true; + } + return false; + } else if (mNrNsaSub6Unmetered) { + if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { + if (DBG) log("NR NSA unmetered for sub6 only via carrier configs"); + return true; + } + return false; + } + if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED + || override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { + if (DBG) log("NR NSA unmetered for all frequencies via carrier configs"); + return true; + } + return false; + } + + if (mNrSaAllUnmetered) { + // TODO: add logic for mNrSaMmwaveUnmetered and mNrSaSub6Unmetered once it's defined + // in TelephonyDisplayInfo + if (rat == NETWORK_TYPE_NR) { + if (DBG) log("NR SA unmetered for all frequencies via carrier configs"); + return true; + } + return false; + } + + return false; + } + + private boolean isTempNotMeteredSupportedByCarrier() { + CarrierConfigManager configManager = + mPhone.getContext().getSystemService(CarrierConfigManager.class); + if (configManager != null) { + PersistableBundle bundle = configManager.getConfigForSubId(mPhone.getSubId()); + if (bundle != null) { + return bundle.getBoolean( + CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL); + } + } + + return false; + } + + protected void log(String s) { + Rlog.d(mLogTag, s); + } + + private void loge(String s) { + Rlog.e(mLogTag, s); + } + + private void logSortedApnContexts() { + if (VDBG) { + log("initApnContexts: X mApnContexts=" + mApnContexts); + + StringBuilder sb = new StringBuilder(); + sb.append("sorted apncontexts -> ["); + for (ApnContext apnContext : mPrioritySortedApnContexts) { + sb.append(apnContext); + sb.append(", "); + + log("sorted list"); + } + sb.append("]"); + log(sb.toString()); + } + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("DcTracker:"); + pw.println(" RADIO_TESTS=" + RADIO_TESTS); + pw.println(" mDataEnabledSettings=" + mDataEnabledSettings); + pw.println(" isDataAllowed=" + isDataAllowed(null)); + pw.flush(); + pw.println(" mRequestedApnType=" + mRequestedApnType); + pw.println(" mPhone=" + mPhone.getPhoneName()); + pw.println(" mConfigReady=" + mConfigReady); + pw.println(" mSimState=" + SubscriptionInfoUpdater.simStateString(mSimState)); + pw.println(" mActivity=" + mActivity); + pw.println(" mState=" + mState); + pw.println(" mTxPkts=" + mTxPkts); + pw.println(" mRxPkts=" + mRxPkts); + pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod); + pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled); + pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum); + pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag); + pw.println(" mDataStallNoRxEnabled=" + mDataStallNoRxEnabled); + pw.println(" mEmergencyApn=" + mEmergencyApn); + pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv); + pw.println(" mNoRecvPollCount=" + mNoRecvPollCount); + pw.println(" mResolver=" + mResolver); + pw.println(" mReconnectIntent=" + mReconnectIntent); + pw.println(" mAutoAttachEnabled=" + mAutoAttachEnabled.get()); + pw.println(" mIsScreenOn=" + mIsScreenOn); + pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator); + pw.println(" mDataServiceBound=" + mDataServiceBound); + pw.println(" mDataRoamingLeakageLog= "); + mDataRoamingLeakageLog.dump(fd, pw, args); + pw.println(" mApnSettingsInitializationLog= "); + mApnSettingsInitializationLog.dump(fd, pw, args); + pw.flush(); + pw.println(" ***************************************"); + DcController dcc = mDcc; + if (dcc != null) { + if (mDataServiceBound) { + dcc.dump(fd, pw, args); + } else { + pw.println(" Can't dump mDcc because data service is not bound."); + } + } else { + pw.println(" mDcc=null"); + } + pw.println(" ***************************************"); + HashMap dcs = mDataConnections; + if (dcs != null) { + Set > mDcSet = mDataConnections.entrySet(); + pw.println(" mDataConnections: count=" + mDcSet.size()); + for (Entry entry : mDcSet) { + pw.printf(" *** mDataConnection[%d] \n", entry.getKey()); + entry.getValue().dump(fd, pw, args); + } + } else { + pw.println("mDataConnections=null"); + } + pw.println(" ***************************************"); + pw.flush(); + HashMap apnToDcId = mApnToDataConnectionId; + if (apnToDcId != null) { + Set> apnToDcIdSet = apnToDcId.entrySet(); + pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size()); + for (Entry entry : apnToDcIdSet) { + pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue()); + } + } else { + pw.println("mApnToDataConnectionId=null"); + } + pw.println(" ***************************************"); + pw.flush(); + ConcurrentHashMap apnCtxs = mApnContexts; + if (apnCtxs != null) { + Set> apnCtxsSet = apnCtxs.entrySet(); + pw.println(" mApnContexts size=" + apnCtxsSet.size()); + for (Entry entry : apnCtxsSet) { + entry.getValue().dump(fd, pw, args); + } + ApnContext.dumpLocalLog(fd, pw, args); + pw.println(" ***************************************"); + } else { + pw.println(" mApnContexts=null"); + } + pw.flush(); + + pw.println(" mAllApnSettings size=" + mAllApnSettings.size()); + for (int i = 0; i < mAllApnSettings.size(); i++) { + pw.printf(" mAllApnSettings[%d]: %s\n", i, mAllApnSettings.get(i)); + } + pw.flush(); + + pw.println(" mPreferredApn=" + mPreferredApn); + pw.println(" mIsPsRestricted=" + mIsPsRestricted); + pw.println(" mIsDisposed=" + mIsDisposed); + pw.println(" mIntentReceiver=" + mIntentReceiver); + pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure); + pw.println(" canSetPreferApn=" + mCanSetPreferApn); + pw.println(" mApnObserver=" + mApnObserver); + pw.println(" isAnyDataConnected=" + isAnyDataConnected()); + pw.println(" mAttached=" + mAttached.get()); + mDataEnabledSettings.dump(fd, pw, args); + pw.flush(); + } + + public String[] getPcscfAddress(String apnType) { + log("getPcscfAddress()"); + ApnContext apnContext = null; + + if(apnType == null){ + log("apnType is null, return null"); + return null; + } + + if (TextUtils.equals(apnType, ApnSetting.TYPE_EMERGENCY_STRING)) { + apnContext = mApnContextsByType.get(ApnSetting.TYPE_EMERGENCY); + } else if (TextUtils.equals(apnType, ApnSetting.TYPE_IMS_STRING)) { + apnContext = mApnContextsByType.get(ApnSetting.TYPE_IMS); + } else { + log("apnType is invalid, return null"); + return null; + } + + if (apnContext == null) { + log("apnContext is null, return null"); + return null; + } + + DataConnection dataConnection = apnContext.getDataConnection(); + String[] result = null; + + if (dataConnection != null) { + result = dataConnection.getPcscfAddresses(); + + if (result != null) { + for (int i = 0; i < result.length; i++) { + log("Pcscf[" + i + "]: " + result[i]); + } + } + return result; + } + return null; + } + + /** + * Create default apn settings for the apn type like emergency, and ims + */ + private ApnSetting buildDefaultApnSetting(@NonNull String entry, + @NonNull String apn, @ApnType int apnTypeBitmask) { + return new ApnSetting.Builder() + .setEntryName(entry) + .setProtocol(ApnSetting.PROTOCOL_IPV4V6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6) + .setApnName(apn) + .setApnTypeBitmask(apnTypeBitmask) + .setCarrierEnabled(true) + .setApnSetId(Telephony.Carriers.MATCH_ALL_APN_SET_ID) + .build(); + } + + /** + * Add default APN settings to APN settings list as needed + */ + private void addDefaultApnSettingsAsNeeded() { + boolean isEmergencyApnConfigured = false; + boolean isImsApnConfigured = false; + + for (ApnSetting apn : mAllApnSettings) { + if (apn.canHandleType(ApnSetting.TYPE_EMERGENCY)) { + isEmergencyApnConfigured = true; + } + if (apn.canHandleType(ApnSetting.TYPE_IMS)) { + isImsApnConfigured = true; + } + if (isEmergencyApnConfigured && isImsApnConfigured) { + log("Both emergency and ims apn setting are already present"); + return; + } + } + + // Add default apn setting for emergency service if it is not present + if (!isEmergencyApnConfigured) { + mAllApnSettings.add(buildDefaultApnSetting( + "DEFAULT EIMS", "sos", ApnSetting.TYPE_EMERGENCY)); + log("default emergency apn is created"); + } + + // Only add default apn setting for ims when it is not present and sim is loaded + if (!isImsApnConfigured && mSimState == TelephonyManager.SIM_STATE_LOADED) { + mAllApnSettings.add(buildDefaultApnSetting( + "DEFAULT IMS", "ims", ApnSetting.TYPE_IMS)); + log("default ims apn is created"); + } + } + + private void cleanUpConnectionsOnUpdatedApns(boolean detach, String reason) { + if (DBG) log("cleanUpConnectionsOnUpdatedApns: detach=" + detach); + if (mAllApnSettings.isEmpty()) { + cleanUpAllConnectionsInternal(detach, Phone.REASON_APN_CHANGED); + } else { + if (getDataRat() == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) { + // unknown rat is an exception for data rat change. Its only received when out of + // service and is not applicable for apn bearer bitmask. We should bypass the check + // of waiting apn list and keep the data connection on. + return; + } + for (ApnContext apnContext : mApnContexts.values()) { + boolean cleanupRequired = true; + if (!apnContext.isDisconnected()) { + ArrayList waitingApns = buildWaitingApns( + apnContext.getApnType(), getDataRat()); + if (apnContext.getWaitingApns().size() != waitingApns.size() + || !apnContext.getWaitingApns().containsAll(waitingApns)) { + apnContext.setWaitingApns(waitingApns); + } + for (ApnSetting apnSetting : waitingApns) { + if (areCompatible(apnSetting, apnContext.getApnSetting())) { + cleanupRequired = false; + break; + } + } + + if (cleanupRequired) { + if (DBG) { + log("cleanUpConnectionsOnUpdatedApns: APN type " + + apnContext.getApnType() + " clean up is required. The new " + + "waiting APN list " + waitingApns + " does not cover " + + apnContext.getApnSetting()); + } + apnContext.setReason(reason); + cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnContext); + } + } + } + } + + if (!isAnyDataConnected()) { + stopNetStatPoll(); + stopDataStallAlarm(); + } + + mRequestedApnType = ApnSetting.TYPE_DEFAULT; + + if (areAllDataDisconnected()) { + notifyAllDataDisconnected(); + } + } + + /** + * Polling stuff + */ + protected void resetPollStats() { + mTxPkts = -1; + mRxPkts = -1; + mNetStatPollPeriod = POLL_NETSTAT_MILLIS; + } + + protected void startNetStatPoll() { + if (isAnyDataConnected() && !mNetStatPollEnabled) { + if (DBG) { + log("startNetStatPoll"); + } + resetPollStats(); + mNetStatPollEnabled = true; + mPollNetStat.run(); + } + if (mPhone != null) { + mPhone.notifyDataActivity(); + } + } + + protected void stopNetStatPoll() { + mNetStatPollEnabled = false; + removeCallbacks(mPollNetStat); + if (DBG) { + log("stopNetStatPoll"); + } + + // To sync data activity icon in the case of switching data connection to send MMS. + if (mPhone != null) { + mPhone.notifyDataActivity(); + } + } + + public void sendStartNetStatPoll(DctConstants.Activity activity) { + Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL); + msg.arg1 = DctConstants.ENABLED; + msg.obj = activity; + sendMessage(msg); + } + + private void handleStartNetStatPoll(DctConstants.Activity activity) { + startNetStatPoll(); + startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); + setActivity(activity); + } + + public void sendStopNetStatPoll(DctConstants.Activity activity) { + Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL); + msg.arg1 = DctConstants.DISABLED; + msg.obj = activity; + sendMessage(msg); + } + + private void handleStopNetStatPoll(DctConstants.Activity activity) { + stopNetStatPoll(); + stopDataStallAlarm(); + setActivity(activity); + } + + private void onDataEnabledOverrideRulesChanged() { + if (DBG) { + log("onDataEnabledOverrideRulesChanged"); + } + + for (ApnContext apnContext : mPrioritySortedApnContexts) { + if (isDataAllowed(apnContext, REQUEST_TYPE_NORMAL, null)) { + if (apnContext.getDataConnection() != null) { + apnContext.getDataConnection().reevaluateRestrictedState(); + } + setupDataOnConnectableApn(apnContext, Phone.REASON_DATA_ENABLED_OVERRIDE, + RetryFailures.ALWAYS); + } else if (shouldCleanUpConnection(apnContext, true, false)) { + apnContext.setReason(Phone.REASON_DATA_ENABLED_OVERRIDE); + cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnContext); + } + } + } + + private void updateDataActivity() { + long sent, received; + + DctConstants.Activity newActivity; + + TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts); + TxRxSum curTxRxSum = new TxRxSum(); + curTxRxSum.updateTotalTxRxSum(); + mTxPkts = curTxRxSum.txPkts; + mRxPkts = curTxRxSum.rxPkts; + + if (VDBG) { + log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum); + } + + if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) { + sent = mTxPkts - preTxRxSum.txPkts; + received = mRxPkts - preTxRxSum.rxPkts; + + if (VDBG) + log("updateDataActivity: sent=" + sent + " received=" + received); + if (sent > 0 && received > 0) { + newActivity = DctConstants.Activity.DATAINANDOUT; + } else if (sent > 0 && received == 0) { + newActivity = DctConstants.Activity.DATAOUT; + } else if (sent == 0 && received > 0) { + newActivity = DctConstants.Activity.DATAIN; + } else { + newActivity = (mActivity == DctConstants.Activity.DORMANT) ? + mActivity : DctConstants.Activity.NONE; + } + + if (mActivity != newActivity && mIsScreenOn) { + if (VDBG) + log("updateDataActivity: newActivity=" + newActivity); + mActivity = newActivity; + mPhone.notifyDataActivity(); + } + } + } + + private void handlePcoData(AsyncResult ar) { + if (ar.exception != null) { + loge("PCO_DATA exception: " + ar.exception); + return; + } + PcoData pcoData = (PcoData)(ar.result); + ArrayList dcList = new ArrayList<>(); + DataConnection temp = mDcc.getActiveDcByCid(pcoData.cid); + if (temp != null) { + dcList.add(temp); + } + if (dcList.size() == 0) { + loge("PCO_DATA for unknown cid: " + pcoData.cid + ", inferring"); + for (DataConnection dc : mDataConnections.values()) { + final int cid = dc.getCid(); + if (cid == pcoData.cid) { + if (VDBG) log(" found " + dc); + dcList.clear(); + dcList.add(dc); + break; + } + // check if this dc is still connecting + if (cid == -1) { + for (ApnContext apnContext : dc.getApnContexts()) { + if (apnContext.getState() == DctConstants.State.CONNECTING) { + if (VDBG) log(" found potential " + dc); + dcList.add(dc); + break; + } + } + } + } + } + if (dcList.size() == 0) { + loge("PCO_DATA - couldn't infer cid"); + return; + } + for (DataConnection dc : dcList) { + List apnContextList = dc.getApnContexts(); + if (apnContextList.size() == 0) { + break; + } + // send one out for each apn type in play + for (ApnContext apnContext : apnContextList) { + String apnType = apnContext.getApnType(); + + final Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE); + intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, + ApnSetting.getApnTypesBitmaskFromString(apnType)); + intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL, + ApnSetting.getProtocolIntFromString(pcoData.bearerProto)); + intent.putExtra(TelephonyManager.EXTRA_PCO_ID, pcoData.pcoId); + intent.putExtra(TelephonyManager.EXTRA_PCO_VALUE, pcoData.contents); + mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); + } + } + } + + /** + * Data-Stall + */ + + // Recovery action taken in case of data stall + @IntDef( + value = { + RECOVERY_ACTION_GET_DATA_CALL_LIST, + RECOVERY_ACTION_CLEANUP, + RECOVERY_ACTION_REREGISTER, + RECOVERY_ACTION_RADIO_RESTART + }) + @Retention(RetentionPolicy.SOURCE) + public @interface RecoveryAction {}; + private static final int RECOVERY_ACTION_GET_DATA_CALL_LIST = 0; + private static final int RECOVERY_ACTION_CLEANUP = 1; + private static final int RECOVERY_ACTION_REREGISTER = 2; + private static final int RECOVERY_ACTION_RADIO_RESTART = 3; + + // Recovery handler class for cellular data stall + private class DataStallRecoveryHandler { + // Default minimum duration between each recovery steps + private static final int + DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS = (3 * 60 * 1000); // 3 mins + + // The elapsed real time of last recovery attempted + private long mTimeLastRecoveryStartMs; + // Whether current network good or not + private boolean mIsValidNetwork; + // Whether data stall happened or not. + private boolean mWasDataStall; + // Whether the result of last action(RADIO_RESTART) reported. + private boolean mLastActionReported; + // The real time for data stall start. + private long mDataStallStartMs; + // Last data stall action. + private @RecoveryAction int mLastAction; + + public DataStallRecoveryHandler() { + reset(); + } + + public void reset() { + mTimeLastRecoveryStartMs = 0; + putRecoveryAction(RECOVERY_ACTION_GET_DATA_CALL_LIST); + } + + private void setNetworkValidationState(boolean isValid) { + // Validation status is true and was not data stall. + if (isValid && !mWasDataStall) { + return; + } + + if (!mWasDataStall) { + mWasDataStall = true; + mDataStallStartMs = SystemClock.elapsedRealtime(); + if (DBG) log("data stall: start time = " + mDataStallStartMs); + return; + } + + if (!mLastActionReported) { + int timeDuration = (int) (SystemClock.elapsedRealtime() - mDataStallStartMs); + if (DBG) { + log("data stall: lastaction = " + mLastAction + ", isRecovered = " + + isValid + ", mTimeDuration = " + timeDuration); + } + DataStallRecoveryStats.onDataStallEvent(mLastAction, mPhone, isValid, + timeDuration); + mLastActionReported = true; + } + + if (isValid) { + mLastActionReported = false; + mWasDataStall = false; + } + } + + public boolean isAggressiveRecovery() { + @RecoveryAction int action = getRecoveryAction(); + + return ((action == RECOVERY_ACTION_CLEANUP) + || (action == RECOVERY_ACTION_REREGISTER) + || (action == RECOVERY_ACTION_RADIO_RESTART)); + } + + private long getMinDurationBetweenRecovery() { + return Settings.Global.getLong(mResolver, + Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, + DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS); + } + + private long getElapsedTimeSinceRecoveryMs() { + return (SystemClock.elapsedRealtime() - mTimeLastRecoveryStartMs); + } + + @RecoveryAction + private int getRecoveryAction() { + @RecoveryAction int action = Settings.System.getInt(mResolver, + "radio.data.stall.recovery.action", RECOVERY_ACTION_GET_DATA_CALL_LIST); + if (VDBG_STALL) log("getRecoveryAction: " + action); + return action; + } + + private void putRecoveryAction(@RecoveryAction int action) { + Settings.System.putInt(mResolver, "radio.data.stall.recovery.action", action); + if (VDBG_STALL) log("putRecoveryAction: " + action); + } + + private void broadcastDataStallDetected(@RecoveryAction int recoveryAction) { + Intent intent = new Intent(TelephonyManager.ACTION_DATA_STALL_DETECTED); + SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); + intent.putExtra(TelephonyManager.EXTRA_RECOVERY_ACTION, recoveryAction); + mPhone.getContext().sendBroadcast(intent, READ_PRIVILEGED_PHONE_STATE); + } + + private boolean isRecoveryAlreadyStarted() { + return getRecoveryAction() != RECOVERY_ACTION_GET_DATA_CALL_LIST; + } + + private boolean checkRecovery() { + // To avoid back to back recovery wait for a grace period + if (getElapsedTimeSinceRecoveryMs() < getMinDurationBetweenRecovery()) { + if (VDBG_STALL) log("skip back to back data stall recovery"); + return false; + } + + // Skip recovery if it can cause a call to drop + if (mPhone.getState() != PhoneConstants.State.IDLE + && getRecoveryAction() > RECOVERY_ACTION_CLEANUP) { + if (VDBG_STALL) log("skip data stall recovery as there is an active call"); + return false; + } + + // Allow recovery if data is expected to work + return mAttached.get() && isDataAllowed(null); + } + + private void triggerRecovery() { + // Updating the recovery start time early to avoid race when + // the message is being processed in the Queue + mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime(); + sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY)); + } + + public void doRecovery() { + if (isAnyDataConnected()) { + // Go through a series of recovery steps, each action transitions to the next action + @RecoveryAction final int recoveryAction = getRecoveryAction(); + final int signalStrength = mPhone.getSignalStrength().getLevel(); + TelephonyMetrics.getInstance().writeSignalStrengthEvent( + mPhone.getPhoneId(), signalStrength); + TelephonyMetrics.getInstance().writeDataStallEvent( + mPhone.getPhoneId(), recoveryAction); + mLastAction = recoveryAction; + mLastActionReported = false; + broadcastDataStallDetected(recoveryAction); + + switch (recoveryAction) { + case RECOVERY_ACTION_GET_DATA_CALL_LIST: + EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST, + mSentSinceLastRecv); + if (DBG) log("doRecovery() get data call list"); + mDataServiceManager.requestDataCallList(obtainMessage()); + putRecoveryAction(RECOVERY_ACTION_CLEANUP); + break; + case RECOVERY_ACTION_CLEANUP: + EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, + mSentSinceLastRecv); + if (DBG) log("doRecovery() cleanup all connections"); + cleanUpConnection(mApnContexts.get(ApnSetting.getApnTypeString( + ApnSetting.TYPE_DEFAULT))); + cleanUpConnection(mApnContexts.get(ApnSetting.getApnTypeString( + ApnSetting.TYPE_ENTERPRISE))); + putRecoveryAction(RECOVERY_ACTION_REREGISTER); + break; + case RECOVERY_ACTION_REREGISTER: + EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER, + mSentSinceLastRecv); + if (DBG) log("doRecovery() re-register"); + mPhone.getServiceStateTracker().reRegisterNetwork(null); + putRecoveryAction(RECOVERY_ACTION_RADIO_RESTART); + break; + case RECOVERY_ACTION_RADIO_RESTART: + EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART, + mSentSinceLastRecv); + if (DBG) log("restarting radio"); + restartRadio(); + reset(); + break; + default: + throw new RuntimeException("doRecovery: Invalid recoveryAction=" + + recoveryAction); + } + mSentSinceLastRecv = 0; + } + } + + public void processNetworkStatusChanged(boolean isValid) { + setNetworkValidationState(isValid); + if (isValid) { + mIsValidNetwork = true; + reset(); + } else { + if (mIsValidNetwork || isRecoveryAlreadyStarted()) { + mIsValidNetwork = false; + // Check and trigger a recovery if network switched from good + // to bad or recovery is already started before. + if (checkRecovery()) { + if (DBG) log("trigger data stall recovery"); + triggerRecovery(); + } + } + } + } + + public boolean isRecoveryOnBadNetworkEnabled() { + return Settings.Global.getInt(mResolver, + Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1) == 1; + } + + public boolean isNoRxDataStallDetectionEnabled() { + return mDataStallNoRxEnabled && !isRecoveryOnBadNetworkEnabled(); + } + } + + private void updateDataStallInfo() { + long sent, received; + + TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum); + mDataStallTxRxSum.updateTotalTxRxSum(); + + if (VDBG_STALL) { + log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum + + " preTxRxSum=" + preTxRxSum); + } + + sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts; + received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts; + + if (RADIO_TESTS) { + if (SystemProperties.getBoolean("radio.test.data.stall", false)) { + log("updateDataStallInfo: radio.test.data.stall true received = 0;"); + received = 0; + } + } + if ( sent > 0 && received > 0 ) { + if (VDBG_STALL) log("updateDataStallInfo: IN/OUT"); + mSentSinceLastRecv = 0; + mDsRecoveryHandler.reset(); + } else if (sent > 0 && received == 0) { + if (isPhoneStateIdle()) { + mSentSinceLastRecv += sent; + } else { + mSentSinceLastRecv = 0; + } + if (DBG) { + log("updateDataStallInfo: OUT sent=" + sent + + " mSentSinceLastRecv=" + mSentSinceLastRecv); + } + } else if (sent == 0 && received > 0) { + if (VDBG_STALL) log("updateDataStallInfo: IN"); + mSentSinceLastRecv = 0; + mDsRecoveryHandler.reset(); + } else { + if (VDBG_STALL) log("updateDataStallInfo: NONE"); + } + } + + private boolean isPhoneStateIdle() { + for (int i = 0; i < mTelephonyManager.getPhoneCount(); i++) { + Phone phone = PhoneFactory.getPhone(i); + if (phone != null && phone.getState() != PhoneConstants.State.IDLE) { + log("isPhoneStateIdle false: Voice call active on phone " + i); + return false; + } + } + return true; + } + + private void onDataStallAlarm(int tag) { + if (mDataStallAlarmTag != tag) { + if (DBG) { + log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag); + } + return; + } + + if (DBG) log("Data stall alarm"); + updateDataStallInfo(); + + int hangWatchdogTrigger = Settings.Global.getInt(mResolver, + Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, + NUMBER_SENT_PACKETS_OF_HANG); + + boolean suspectedStall = DATA_STALL_NOT_SUSPECTED; + if (mSentSinceLastRecv >= hangWatchdogTrigger) { + if (DBG) { + log("onDataStallAlarm: tag=" + tag + " do recovery action=" + + mDsRecoveryHandler.getRecoveryAction()); + } + suspectedStall = DATA_STALL_SUSPECTED; + sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY)); + } else { + if (VDBG_STALL) { + log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) + + " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger); + } + } + startDataStallAlarm(suspectedStall); + } + + protected void startDataStallAlarm(boolean suspectedStall) { + int delayInMs; + + if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled() && isAnyDataConnected()) { + // If screen is on or data stall is currently suspected, set the alarm + // with an aggressive timeout. + if (mIsScreenOn || suspectedStall || mDsRecoveryHandler.isAggressiveRecovery()) { + delayInMs = Settings.Global.getInt(mResolver, + Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS, + DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT); + } else { + delayInMs = Settings.Global.getInt(mResolver, + Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS, + DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT); + } + + mDataStallAlarmTag += 1; + if (VDBG_STALL) { + log("startDataStallAlarm: tag=" + mDataStallAlarmTag + + " delay=" + (delayInMs / 1000) + "s"); + } + Intent intent = new Intent(INTENT_DATA_STALL_ALARM); + intent.putExtra(INTENT_DATA_STALL_ALARM_EXTRA_TAG, mDataStallAlarmTag); + intent.putExtra(INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE, mTransportType); + SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); + mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, + SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent); + } else { + if (VDBG_STALL) { + log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag); + } + } + } + + private void stopDataStallAlarm() { + if (VDBG_STALL) { + log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag + + " mDataStallAlarmIntent=" + mDataStallAlarmIntent); + } + mDataStallAlarmTag += 1; + if (mDataStallAlarmIntent != null) { + mAlarmManager.cancel(mDataStallAlarmIntent); + mDataStallAlarmIntent = null; + } + } + + private void restartDataStallAlarm() { + if (!isAnyDataConnected()) return; + // To be called on screen status change. + // Do not cancel the alarm if it is set with aggressive timeout. + if (mDsRecoveryHandler.isAggressiveRecovery()) { + if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm."); + return; + } + if (VDBG_STALL) log("restartDataStallAlarm: stop then start."); + stopDataStallAlarm(); + startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); + } + + /** + * Provisioning APN + */ + private void onActionIntentProvisioningApnAlarm(Intent intent) { + if (DBG) log("onActionIntentProvisioningApnAlarm: action=" + intent.getAction()); + Message msg = obtainMessage(DctConstants.EVENT_PROVISIONING_APN_ALARM, + intent.getAction()); + msg.arg1 = intent.getIntExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, 0); + sendMessage(msg); + } + + private void startProvisioningApnAlarm() { + int delayInMs = Settings.Global.getInt(mResolver, + Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS, + PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT); + if (TelephonyUtils.IS_DEBUGGABLE) { + // Allow debug code to use a system property to provide another value + String delayInMsStrg = Integer.toString(delayInMs); + delayInMsStrg = System.getProperty(DEBUG_PROV_APN_ALARM, delayInMsStrg); + try { + delayInMs = Integer.parseInt(delayInMsStrg); + } catch (NumberFormatException e) { + loge("startProvisioningApnAlarm: e=" + e); + } + } + mProvisioningApnAlarmTag += 1; + if (DBG) { + log("startProvisioningApnAlarm: tag=" + mProvisioningApnAlarmTag + + " delay=" + (delayInMs / 1000) + "s"); + } + Intent intent = new Intent(INTENT_PROVISIONING_APN_ALARM); + intent.putExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, mProvisioningApnAlarmTag); + mProvisioningApnAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + delayInMs, mProvisioningApnAlarmIntent); + } + + private void stopProvisioningApnAlarm() { + if (DBG) { + log("stopProvisioningApnAlarm: current tag=" + mProvisioningApnAlarmTag + + " mProvsioningApnAlarmIntent=" + mProvisioningApnAlarmIntent); + } + mProvisioningApnAlarmTag += 1; + if (mProvisioningApnAlarmIntent != null) { + mAlarmManager.cancel(mProvisioningApnAlarmIntent); + mProvisioningApnAlarmIntent = null; + } + } + + /** + * 5G connection reevaluation alarm + */ + private void startWatchdogAlarm() { + sendMessageDelayed(obtainMessage(DctConstants.EVENT_NR_TIMER_WATCHDOG), mWatchdogTimeMs); + mWatchdog = true; + } + + private void stopWatchdogAlarm() { + removeMessages(DctConstants.EVENT_NR_TIMER_WATCHDOG); + mWatchdog = false; + } + + private void onDataServiceBindingChanged(boolean bound) { + if (!bound) { + if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { + boolean connPersistenceOnRestart = mPhone.getContext().getResources() + .getBoolean(com.android + .internal.R.bool.config_wlan_data_service_conn_persistence_on_restart); + if (!connPersistenceOnRestart) { + cleanUpAllConnectionsInternal(false, Phone.REASON_IWLAN_DATA_SERVICE_DIED); + } + } + } else { + //reset throttling after binding to data service + mDataThrottler.reset(); + } + mDataServiceBound = bound; + } + + public static String requestTypeToString(@RequestNetworkType int type) { + switch (type) { + case REQUEST_TYPE_NORMAL: return "NORMAL"; + case REQUEST_TYPE_HANDOVER: return "HANDOVER"; + } + return "UNKNOWN"; + } + + public static String releaseTypeToString(@ReleaseNetworkType int type) { + switch (type) { + case RELEASE_TYPE_NORMAL: return "NORMAL"; + case RELEASE_TYPE_DETACH: return "DETACH"; + case RELEASE_TYPE_HANDOVER: return "HANDOVER"; + } + return "UNKNOWN"; + } + + @RilRadioTechnology + protected int getDataRat() { + ServiceState ss = mPhone.getServiceState(); + NetworkRegistrationInfo nrs = ss.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, mTransportType); + if (nrs != null) { + return ServiceState.networkTypeToRilRadioTechnology(nrs.getAccessNetworkTechnology()); + } + return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; + } + + @RilRadioTechnology + private int getVoiceRat() { + ServiceState ss = mPhone.getServiceState(); + NetworkRegistrationInfo nrs = ss.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, mTransportType); + if (nrs != null) { + return ServiceState.networkTypeToRilRadioTechnology(nrs.getAccessNetworkTechnology()); + } + return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; + } + + private void read5GConfiguration() { + if (DBG) log("read5GConfiguration"); + String[] bandwidths = CarrierConfigManager.getDefaultConfig().getStringArray( + CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY); + boolean useLte = false; + CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager != null) { + PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); + if (b != null) { + if (b.getStringArray(CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY) != null) { + bandwidths = b.getStringArray(CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY); + } + useLte = b.getBoolean(CarrierConfigManager + .KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPLINK_BOOL); + mWatchdogTimeMs = b.getLong(CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG); + mNrNsaAllUnmetered = b.getBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_BOOL); + mNrNsaMmwaveUnmetered = b.getBoolean( + CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL); + mNrNsaSub6Unmetered = b.getBoolean( + CarrierConfigManager.KEY_UNMETERED_NR_NSA_SUB6_BOOL); + mNrSaAllUnmetered = b.getBoolean(CarrierConfigManager.KEY_UNMETERED_NR_SA_BOOL); + mNrSaMmwaveUnmetered = b.getBoolean( + CarrierConfigManager.KEY_UNMETERED_NR_SA_MMWAVE_BOOL); + mNrSaSub6Unmetered = b.getBoolean( + CarrierConfigManager.KEY_UNMETERED_NR_SA_SUB6_BOOL); + mNrNsaRoamingUnmetered = b.getBoolean( + CarrierConfigManager.KEY_UNMETERED_NR_NSA_WHEN_ROAMING_BOOL); + mLteEndcUsingUserDataForRrcDetection = b.getBoolean( + CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL); + } + } + updateLinkBandwidths(bandwidths, useLte); + } + + public boolean getLteEndcUsingUserDataForIdleDetection() { + return mLteEndcUsingUserDataForRrcDetection; + } + + /** + * Register for physical link status (i.e. RRC state) changed event. + * if {@link CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL} is true, + * then physical link state is focusing on "internet data connection" instead of RRC state. + * + * @param h The handler + * @param what The event + */ + public void registerForPhysicalLinkStatusChanged(Handler h, int what) { + mDcc.registerForPhysicalLinkStatusChanged(h, what); + } + + /** + * Unregister from physical link status (i.e. RRC state) changed event. + * + * @param h The previously registered handler + */ + public void unregisterForPhysicalLinkStatusChanged(Handler h) { + mDcc.unregisterForPhysicalLinkStatusChanged(h); + } + + // We use a specialized equals function in Apn setting when checking if an active + // data connection is still legitimate to use against a different apn setting. + // This method is extracted to a function to ensure that any future changes to this check will + // be applied to both cleanUpConnectionsOnUpdatedApns and checkForCompatibleDataConnection. + // Fix for b/158908392. + private boolean areCompatible(ApnSetting apnSetting1, ApnSetting apnSetting2) { + return apnSetting1.equals(apnSetting2, + mPhone.getServiceState().getDataRoamingFromRegistration()); + } + + @NonNull + private PersistableBundle getCarrierConfig() { + CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager != null) { + // If an invalid subId is used, this bundle will contain default values. + PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId()); + if (config != null) { + return config; + } + } + // Return static default defined in CarrierConfigManager. + return CarrierConfigManager.getDefaultConfig(); + } + + /** + * @return The data service manager. + */ + public @NonNull DataServiceManager getDataServiceManager() { + return mDataServiceManager; + } + + /** + * @return The data throttler + */ + public @NonNull DataThrottler getDataThrottler() { + return mDataThrottler; + } + + private void showProvisioningNotification() { + final Intent intent = new Intent(DcTracker.INTENT_PROVISION); + intent.putExtra(DcTracker.EXTRA_PROVISION_PHONE_ID, mPhone.getPhoneId()); + final PendingIntent pendingIntent = PendingIntent.getBroadcast( + mPhone.getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE); + + final Resources r = mPhone.getContext().getResources(); + final String title = r.getString(R.string.network_available_sign_in, 0); + final String details = mTelephonyManager.getNetworkOperator(mPhone.getSubId()); + final Notification.Builder builder = new Notification.Builder(mPhone.getContext()) + .setWhen(System.currentTimeMillis()) + .setSmallIcon(R.drawable.stat_notify_rssi_in_range) + .setChannelId(NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS) + .setAutoCancel(true) + .setTicker(title) + .setColor(mPhone.getContext().getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setContentTitle(title) + .setContentText(details) + .setContentIntent(pendingIntent) + .setLocalOnly(true) + .setOnlyAlertOnce(true); + + final Notification notification = builder.build(); + try { + getNotificationManager().notify(NOTIFICATION_TAG, mPhone.getPhoneId(), notification); + } catch (final NullPointerException npe) { + Log.e(mLogTag, "showProvisioningNotification: error showing notification", npe); + } + } + + private void hideProvisioningNotification() { + try { + getNotificationManager().cancel(NOTIFICATION_TAG, mPhone.getPhoneId()); + } catch (final NullPointerException npe) { + Log.e(mLogTag, "hideProvisioningNotification: error hiding notification", npe); + } + } + + private NotificationManager getNotificationManager() { + return (NotificationManager) mPhone.getContext() + .createContextAsUser(UserHandle.ALL, 0 /* flags */) + .getSystemService(Context.NOTIFICATION_SERVICE); + } +} diff --git a/src/java/com/android/internal/telephony/dataconnection/README.txt b/src/java/com/android/internal/telephony/dataconnection/README.txt new file mode 100644 index 0000000000..e613a00a36 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/README.txt @@ -0,0 +1,71 @@ +This package contains classes used to manage a DataConnection. + +A criticial aspect of this class is that most objects in this +package run on the same thread except DataConnectionTracker +This makes processing efficient as it minimizes context +switching and it eliminates issues with multi-threading. + +This can be done because all actions are either asynchronous +or are known to be non-blocking and fast. At this time only +DcTesterDeactivateAll takes specific advantage of this +single threading knowledge by using Dcc#mDcListAll so be +very careful when making changes that break this assumption. + +A related change was in DataConnectionAc I added code that +checks to see if the caller is on a different thread. If +it is then the AsyncChannel#sendMessageSynchronously is +used. If the caller is on the same thread then a getter +is used. This allows the DCAC to be used from any thread +and was required to fix a bug when Dcc called +PhoneBase#notifyDataConnection which calls DCT#getLinkProperties +and DCT#getLinkCapabilities which call Dcc all on the same +thread. Without this change there was a dead lock when +sendMessageSynchronously blocks. + + +== Testing == + +The following are Intents that can be sent for testing pruproses on +DEBUGGABLE builds (userdebug, eng) + +*) Causes bringUp and retry requests to fail for all DC's + + adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_fail_bringup --ei counter 2 --ei fail_cause -3 + +*) Causes all DC's to get torn down, simulating a temporary network outage: + + adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_deactivate_all + +*) To simplify testing we also have detach and attach simulations below where {x} is gsm, cdma or sip + + adb shell am broadcast -a com.android.internal.telephony.{x}.action_detached + adb shell am broadcast -a com.android.internal.telephony.{x}.action_attached + + +== System properties for Testing == + +On debuggable builds (userdebug, eng) you can change additional +settings through system properties. These properties can be set with +"setprop" for the current boot, or added to local.prop to persist +across boots. + +device# setprop key value + +device# echo "key=value" >> /data/local.prop +device# chmod 644 /data/local.prop + + +-- Retry configuration -- + +You can replace the connection retry configuration. For example, you +could change it to perform 4 retries at 5 second intervals: + +device# setprop test.data_retry_config "5000,5000,5000" + + +-- Roaming -- + +You can force the telephony stack to always assume that it's roaming +to verify higher-level framework functionality: + +device# setprop telephony.test.forceRoaming true diff --git a/src/java/com/android/internal/telephony/dataconnection/TransportManager.java b/src/java/com/android/internal/telephony/dataconnection/TransportManager.java new file mode 100644 index 0000000000..63358f4993 --- /dev/null +++ b/src/java/com/android/internal/telephony/dataconnection/TransportManager.java @@ -0,0 +1,279 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.dataconnection; + +import android.annotation.Nullable; +import android.os.Handler; +import android.os.Message; +import android.os.RegistrantList; +import android.telephony.AccessNetworkConstants; +import android.telephony.Annotation.ApnType; +import android.telephony.CarrierConfigManager; +import android.telephony.data.ApnSetting; +import android.util.LocalLog; +import android.util.SparseIntArray; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.data.TelephonyNetworkFactory; +import com.android.telephony.Rlog; + +import java.util.concurrent.TimeUnit; + +/** + * This class represents the transport manager which manages available transports (i.e. WWAN or + * WLAN) and determine the correct transport for {@link TelephonyNetworkFactory} to handle the data + * requests. + * + * The device can operate in the following modes, which is stored in the system properties + * ro.telephony.iwlan_operation_mode. If the system properties is missing, then it's tied to + * IRadio version. For 1.4 or above, it's AP-assisted mdoe. For 1.3 or below, it's legacy mode. + * + * Legacy mode: + * Frameworks send all data requests to the default data service, which is the cellular data + * service. IWLAN should be still reported as a RAT on cellular network service. + * + * AP-assisted mode: + * IWLAN is handled by IWLAN data service extending {@link android.telephony.data.DataService}, + * IWLAN network service extending {@link android.telephony.NetworkService}, and qualified + * network service extending {@link android.telephony.data.QualifiedNetworksService}. + * + * The following settings for service package name need to be configured properly for + * frameworks to bind. + * + * Package name of data service: + * The resource overlay 'config_wlan_data_service_package' or, + * the carrier config + * {@link CarrierConfigManager#KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING}. + * The carrier config takes precedence over the resource overlay if both exist. + * + * Package name of network service + * The resource overlay 'config_wlan_network_service_package' or + * the carrier config + * {@link CarrierConfigManager#KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING}. + * The carrier config takes precedence over the resource overlay if both exist. + * + * Package name of qualified network service + * The resource overlay 'config_qualified_networks_service_package' or + * the carrier config + * {@link CarrierConfigManager# + * KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING}. + * The carrier config takes precedence over the resource overlay if both exist. + */ +public class TransportManager extends Handler { + private final String mLogTag; + + private static final int EVENT_QUALIFIED_NETWORKS_CHANGED = 1; + + private static final int EVENT_EVALUATE_TRANSPORT_PREFERENCE = 2; + + // Delay the re-evaluation if transport fall back. QNS will need to quickly change the + // preference back to the original transport to avoid another handover request. + private static final long FALL_BACK_REEVALUATE_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(3); + + private final Phone mPhone; + + private final LocalLog mLocalLog = new LocalLog(64); + + @Nullable + private AccessNetworksManager mAccessNetworksManager; + + /** + * The pending handover list. This is a list of APNs that are being handover to the new + * transport. The entry will be removed once handover is completed. The key + * is the APN type, and the value is the target transport that the APN is handovered to. + */ + private final SparseIntArray mPendingHandoverApns; + + /** + * The registrants for listening data handover needed events. + */ + private final RegistrantList mHandoverNeededEventRegistrants; + + /** + * Handover parameters + */ + @VisibleForTesting + public static final class HandoverParams { + /** + * The callback for handover complete. + */ + public interface HandoverCallback { + /** + * Called when handover is completed. + * + * @param success {@true} if handover succeeded, otherwise failed. + * @param fallback {@true} if handover failed, the data connection fallback to the + * original transport + */ + void onCompleted(boolean success, boolean fallback); + } + + public final @ApnType int apnType; + public final int targetTransport; + public final HandoverCallback callback; + + @VisibleForTesting + public HandoverParams(int apnType, int targetTransport, HandoverCallback callback) { + this.apnType = apnType; + this.targetTransport = targetTransport; + this.callback = callback; + } + } + + public TransportManager(Phone phone) { + mPhone = phone; + mPendingHandoverApns = new SparseIntArray(); + mHandoverNeededEventRegistrants = new RegistrantList(); + mLogTag = TransportManager.class.getSimpleName() + "-" + mPhone.getPhoneId(); + mAccessNetworksManager = mPhone.getAccessNetworksManager(); + mAccessNetworksManager.registerForQualifiedNetworksChanged(this, + EVENT_QUALIFIED_NETWORKS_CHANGED); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_QUALIFIED_NETWORKS_CHANGED: + if (!hasMessages(EVENT_EVALUATE_TRANSPORT_PREFERENCE)) { + sendEmptyMessage(EVENT_EVALUATE_TRANSPORT_PREFERENCE); + } + break; + case EVENT_EVALUATE_TRANSPORT_PREFERENCE: + evaluateTransportPreference(); + break; + default: + loge("Unexpected event " + msg.what); + break; + } + } + + /** + * Set the current transport of apn type. + * + * @param apnType The APN type + * @param transport The transport. Must be WWAN or WLAN. + */ + private synchronized void setCurrentTransport(@ApnType int apnType, int transport) { + mAccessNetworksManager.setCurrentTransport(apnType, transport); + } + + private boolean isHandoverPending() { + return mPendingHandoverApns.size() > 0; + } + + /** + * Evaluate the preferred transport for each APN type to see if handover is needed. + */ + private void evaluateTransportPreference() { + // Simultaneously handover is not supported today. Preference will be re-evaluated after + // handover completed. + if (isHandoverPending()) return; + logl("evaluateTransportPreference"); + for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { + int targetTransport = mAccessNetworksManager.getPreferredTransport(apnType); + if (targetTransport != mAccessNetworksManager.getCurrentTransport(apnType)) { + logl("Handover started for APN type: " + + ApnSetting.getApnTypeString(apnType) + + ", target transport: " + + AccessNetworkConstants.transportTypeToString(targetTransport)); + mPendingHandoverApns.put(apnType, targetTransport); + mHandoverNeededEventRegistrants.notifyResult( + new HandoverParams(apnType, targetTransport, + (success, fallback) -> { + // The callback for handover completed. + if (success) { + logl("Handover succeeded for APN type " + + ApnSetting.getApnTypeString(apnType)); + } else { + logl("APN type " + + ApnSetting.getApnTypeString(apnType) + + " handover to " + + AccessNetworkConstants.transportTypeToString( + targetTransport) + " failed" + + ", fallback=" + fallback); + } + + long delay = 0; + if (fallback) { + // No need to change the preference because we should + // fallback. Re-evaluate after few seconds to give QNS + // some time to change the preference back to the original + // transport. + delay = FALL_BACK_REEVALUATE_DELAY_MILLIS; + } else { + // If handover succeeds or failed without falling back + // to the original transport, we should move to the new + // transport (even if it is failed). + setCurrentTransport(apnType, targetTransport); + } + mPendingHandoverApns.delete(apnType); + sendEmptyMessageDelayed(EVENT_EVALUATE_TRANSPORT_PREFERENCE, + delay); + })); + + // Return here instead of processing the next APN type. The next APN type for + // handover will be evaluate again once current handover is completed. + return; + } + } + } + + /** + * Register for data handover needed event + * + * @param h The handler of the event + * @param what The id of the event + */ + public void registerForHandoverNeededEvent(Handler h, int what) { + if (h != null) { + mHandoverNeededEventRegistrants.addUnique(h, what, null); + } + } + + /** + * Unregister for data handover needed event + * + * @param h The handler + */ + public void unregisterForHandoverNeededEvent(Handler h) { + mHandoverNeededEventRegistrants.remove(h); + } + + /** + * Registers the data throttler with DcTracker. + */ + public void registerDataThrottler(DataThrottler dataThrottler) { + if (mAccessNetworksManager != null) { + mAccessNetworksManager.registerDataThrottler(dataThrottler); + } + } + + private void logl(String s) { + log(s); + mLocalLog.log(s); + } + + private void log(String s) { + Rlog.d(mLogTag, s); + } + + private void loge(String s) { + Rlog.e(mLogTag, s); + } +} diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index f9032bfc83..322dd55f7c 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -41,6 +41,7 @@ import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneNotifier; +import com.android.internal.telephony.dataconnection.DataConnection; import com.android.internal.telephony.uicc.IccFileHandler; import com.android.telephony.Rlog; @@ -172,6 +173,11 @@ abstract class ImsPhoneBase extends Phone { return new ArrayList(0); } + @Override + public PhoneConstants.DataState getDataConnectionState() { + return PhoneConstants.DataState.DISCONNECTED; + } + @Override public @DataActivityType int getDataActivityState() { return TelephonyManager.DATA_ACTIVITY_NONE; @@ -428,6 +434,10 @@ abstract class ImsPhoneBase extends Phone { Message response) { } + public List getCurrentDataConnectionList () { + return null; + } + @Override public void updateServiceLocation() { } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 1f2b0ea7b2..e72571e113 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -68,7 +68,6 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyLocalConnection; import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.DataEnabledChangedReason; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsCallSession; @@ -120,6 +119,8 @@ import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.d2d.RtpTransport; import com.android.internal.telephony.data.DataSettingsManager; +import com.android.internal.telephony.dataconnection.DataEnabledSettings; +import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.imsphone.ImsPhone.ImsDialArgs; @@ -965,7 +966,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } }; - private @NonNull DataSettingsManager.DataSettingsManagerCallback mSettingsCallback; + // TODO: make @NonNull after removing DataEnabledSettings + private DataSettingsManager.DataSettingsManagerCallback mSettingsCallback; /** * Allows the FeatureConnector used to be swapped for easier testing. @@ -1011,14 +1013,39 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mPhone.getContext().registerReceiver(mReceiver, intentfilter); updateCarrierConfiguration(mPhone.getSubId(), getCarrierConfigBundle(mPhone.getSubId())); - mSettingsCallback = new DataSettingsManager.DataSettingsManagerCallback(this::post) { - @Override - public void onDataEnabledChanged(boolean enabled, - @DataEnabledChangedReason int reason, - @NonNull String callingPackage) { - ImsPhoneCallTracker.this.onDataEnabledChanged(enabled, reason); - }}; - mPhone.getDefaultPhone().getDataSettingsManager().registerCallback(mSettingsCallback); + if (mPhone.getDefaultPhone().isUsingNewDataStack()) { + mSettingsCallback = new DataSettingsManager.DataSettingsManagerCallback(this::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @TelephonyManager.DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + int internalReason; + switch (reason) { + case TelephonyManager.DATA_ENABLED_REASON_USER: + internalReason = DataEnabledSettings.REASON_USER_DATA_ENABLED; + break; + case TelephonyManager.DATA_ENABLED_REASON_POLICY: + internalReason = DataEnabledSettings.REASON_POLICY_DATA_ENABLED; + break; + case TelephonyManager.DATA_ENABLED_REASON_CARRIER: + internalReason = DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER; + break; + case TelephonyManager.DATA_ENABLED_REASON_THERMAL: + internalReason = DataEnabledSettings.REASON_THERMAL_DATA_ENABLED; + break; + case TelephonyManager.DATA_ENABLED_REASON_OVERRIDE: + internalReason = DataEnabledSettings.REASON_OVERRIDE_RULE_CHANGED; + break; + default: + internalReason = DataEnabledSettings.REASON_INTERNAL_DATA_ENABLED; + } + ImsPhoneCallTracker.this.onDataEnabledChanged(enabled, internalReason); + }}; + mPhone.getDefaultPhone().getDataSettingsManager().registerCallback(mSettingsCallback); + } else { + mPhone.getDefaultPhone().getDataEnabledSettings().registerForDataEnabledChanged( + this, EVENT_DATA_ENABLED_CHANGED, null); + } final TelecomManager telecomManager = (TelecomManager) mPhone.getContext().getSystemService(Context.TELECOM_SERVICE); @@ -1263,7 +1290,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { clearDisconnected(); mPhone.getContext().unregisterReceiver(mReceiver); - mPhone.getDefaultPhone().getDataSettingsManager().unregisterCallback(mSettingsCallback); + if (mPhone.getDefaultPhone().isUsingNewDataStack()) { + mPhone.getDefaultPhone().getDataSettingsManager().unregisterCallback(mSettingsCallback); + } else { + mPhone.getDefaultPhone().getDataEnabledSettings().unregisterForDataEnabledChanged(this); + } mImsManagerConnector.disconnect(); final NetworkStatsManager statsManager = @@ -2779,7 +2810,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private void maybeSetVideoCallProvider(ImsPhoneConnection conn, ImsCall imsCall) { android.telecom.Connection.VideoProvider connVideoProvider = conn.getVideoProvider(); - ImsCallSession callSession = imsCall.getCallSession(); + ImsCallSession callSession = imsCall.getCallSession(); if (connVideoProvider != null || callSession == null || callSession.getVideoCallProvider() == null) { return; @@ -3809,11 +3840,15 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { @Override public void onCallHandover(ImsCall imsCall, int srcAccessTech, int targetAccessTech, ImsReasonInfo reasonInfo) { - // Check if data is enabled; there may be a case when + // Check with the DCTracker to see if data is enabled; there may be a case when // ImsPhoneCallTracker isn't being informed of the right data enabled state via its // registration, so we'll refresh now. boolean isDataEnabled; - isDataEnabled = mPhone.getDefaultPhone().getDataSettingsManager().isDataEnabled(); + if (mPhone.getDefaultPhone().isUsingNewDataStack()) { + isDataEnabled = mPhone.getDefaultPhone().getDataSettingsManager().isDataEnabled(); + } else { + isDataEnabled = mPhone.getDefaultPhone().getDataEnabledSettings().isDataEnabled(); + } if (DBG) { log("onCallHandover :: srcAccessTech=" + srcAccessTech + ", targetAccessTech=" @@ -4993,9 +5028,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { /** * Handler of data enabled changed event * @param enabled True if data is enabled, otherwise disabled. - * @param reason Reason for data enabled/disabled. + * @param reason Reason for data enabled/disabled. See {@link DataEnabledChangedReason}. */ private void onDataEnabledChanged(boolean enabled, @DataEnabledChangedReason int reason) { + // TODO: TelephonyManager.DataEnabledChangedReason instead once DataEnabledSettings is gone log("onDataEnabledChanged: enabled=" + enabled + ", reason=" + reason); mIsDataEnabled = enabled; @@ -5015,9 +5051,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } int reasonCode; - if (reason == TelephonyManager.DATA_ENABLED_REASON_POLICY) { + if (reason == DataEnabledSettings.REASON_POLICY_DATA_ENABLED) { reasonCode = ImsReasonInfo.CODE_DATA_LIMIT_REACHED; - } else if (reason == TelephonyManager.DATA_ENABLED_REASON_USER) { + } else if (reason == DataEnabledSettings.REASON_USER_DATA_ENABLED) { reasonCode = ImsReasonInfo.CODE_DATA_DISABLED; } else { // Unexpected code, default to data disabled. @@ -5030,10 +5066,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // Handle video state changes required as a result of data being enabled/disabled. handleDataEnabledChange(enabled, reasonCode); - // We do not want to update the ImsConfig for REASON_UNKNOWN, since it can happen before + // We do not want to update the ImsConfig for REASON_REGISTERED, since it can happen before // the carrier config has loaded and will deregister IMS. if (!mShouldUpdateImsConfigOnDisconnect - && reason != TelephonyManager.DATA_ENABLED_REASON_UNKNOWN + && reason != DataEnabledSettings.REASON_REGISTERED && mCarrierConfigLoadedForSubscription) { // This will call into updateVideoCallFeatureValue and eventually all clients will be // asynchronously notified that the availability of VT over LTE has changed. diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java index 77e758b6d9..5ade0bb000 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -26,6 +26,7 @@ import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyStatsLog; import com.android.internal.telephony.data.DataStallRecoveryManager; +import com.android.internal.telephony.dataconnection.DcTracker; /** Generates metrics related to data stall recovery events per phone ID for the pushed atom. */ public class DataStallRecoveryStats { @@ -40,6 +41,42 @@ public class DataStallRecoveryStats { private static final int RECOVERY_ACTION_RADIO_RESTART_MAPPING = 3; private static final int RECOVERY_ACTION_RESET_MODEM_MAPPING = 4; + + /** TODO: b/214044479 : Remove this function when new data design(Android T) start. */ + public static void onDataStallEvent( + @DcTracker.RecoveryAction int recoveryAction, + Phone phone, + boolean isRecovered, + int durationMillis) { + if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { + phone = phone.getDefaultPhone(); + } + + int carrierId = phone.getCarrierId(); + int rat = getRat(phone); + int band = + (rat == TelephonyManager.NETWORK_TYPE_IWLAN) ? 0 : ServiceStateStats.getBand(phone); + // the number returned here matches the SignalStrength enum we have + int signalStrength = phone.getSignalStrength().getLevel(); + boolean isOpportunistic = getIsOpportunistic(phone); + boolean isMultiSim = SimSlotState.getCurrentState().numActiveSims > 1; + + // Not use this field in Android S, so we send RECOVERED_REASON_NONE for default value. + int recoveryReason = 0; + TelephonyStatsLog.write( + TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, + carrierId, + rat, + signalStrength, + recoveryAction, + isOpportunistic, + isMultiSim, + band, + isRecovered, + durationMillis, + recoveryReason); + } + /** * Called when data stall happened. * diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index e1e37a6a3e..9805d8b1ac 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -483,7 +483,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return StatsManager.PULL_SKIP; } - data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, true)); + data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, + phones[0].isUsingNewDataStack())); return StatsManager.PULL_SUCCESS; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index e1b629d379..bbb463980f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -55,7 +55,7 @@ import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; -import com.android.internal.telephony.data.DataSettingsManager; +import com.android.internal.telephony.dataconnection.DataEnabledSettings; import org.junit.After; import org.junit.Assert; @@ -75,8 +75,8 @@ import java.util.concurrent.atomic.AtomicBoolean; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class MultiSimSettingControllerTest extends TelephonyTest { + private static final int SINGLE_SIM = 1; private static final int DUAL_SIM = 2; - private static final String PHONE_PACKAGE = "com.android.internal.telephony"; private MultiSimSettingController mMultiSimSettingControllerUT; private Phone[] mPhones; private ParcelUuid mGroupUuid1 = new ParcelUuid(UUID.randomUUID()); @@ -85,8 +85,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { private SubscriptionController mSubControllerMock; private Phone mPhoneMock1; private Phone mPhoneMock2; - private DataSettingsManager mDataSettingsManagerMock1; - private DataSettingsManager mDataSettingsManagerMock2; + private DataEnabledSettings mDataEnabledSettingsMock1; + private DataEnabledSettings mDataEnabledSettingsMock2; private CommandsInterface mMockCi; @@ -118,8 +118,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mSubControllerMock = mock(SubscriptionController.class); mPhoneMock1 = mock(Phone.class); mPhoneMock2 = mock(Phone.class); - mDataSettingsManagerMock1 = mock(DataSettingsManager.class); - mDataSettingsManagerMock2 = mock(DataSettingsManager.class); + mDataEnabledSettingsMock1 = mock(DataEnabledSettings.class); + mDataEnabledSettingsMock2 = mock(DataEnabledSettings.class); mMockCi = mock(CommandsInterface.class); // Default configuration: // DSDS device. @@ -145,8 +145,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new int[]{1, 2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mPhones = new Phone[] {mPhoneMock1, mPhoneMock2}; - doReturn(mDataSettingsManagerMock1).when(mPhoneMock1).getDataSettingsManager(); - doReturn(mDataSettingsManagerMock2).when(mPhoneMock2).getDataSettingsManager(); + doReturn(mDataEnabledSettingsMock1).when(mPhoneMock1).getDataEnabledSettings(); + doReturn(mDataEnabledSettingsMock2).when(mPhoneMock2).getDataEnabledSettings(); doReturn(Arrays.asList(mSubInfo1)).when(mSubControllerMock).getSubInfo( eq(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 1), any()); @@ -385,8 +385,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataSettingsManagerMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); // Enable on non-default sub should trigger setDefaultDataSubId. mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); @@ -397,8 +397,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); - verify(mDataSettingsManagerMock1).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock1).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); doReturn(1).when(mSubControllerMock).getDefaultSmsSubId(); @@ -440,10 +440,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataSettingsManagerMock1).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); - verify(mDataSettingsManagerMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock1).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataEnabledSettingsMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); // as a result of the above calls, update new values to be returned doReturn(false).when(mPhoneMock1).isUserDataEnabled(); @@ -458,10 +458,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); - verify(mDataSettingsManagerMock1, times(1)) - .setDataEnabled(anyInt(), anyBoolean(), anyString()); - verify(mDataSettingsManagerMock2, times(1)) - .setDataEnabled(anyInt(), anyBoolean(), anyString()); + verify(mDataEnabledSettingsMock1, times(1)).setDataEnabled(anyInt(), anyBoolean()); + verify(mDataEnabledSettingsMock2, times(1)).setDataEnabled(anyInt(), anyBoolean()); } @Test @@ -480,10 +478,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataSettingsManagerMock1).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); - verify(mDataSettingsManagerMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock1).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataEnabledSettingsMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); // as a result of the above calls, update new values to be returned doReturn(false).when(mPhoneMock1).isUserDataEnabled(); @@ -531,8 +529,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); - verify(mDataSettingsManagerMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); mMultiSimSettingControllerUT.notifyUserDataEnabled(2, false); processAllMessages(); assertFalse(GlobalSettingsHelper.getBoolean( @@ -580,13 +578,13 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); verify(mSubControllerMock).setDefaultDataSubId(2); - verify(mDataSettingsManagerMock1, never()).setDataEnabled( - anyInt(), anyBoolean(), anyString()); + verify(mDataEnabledSettingsMock1, never()).setDataEnabled( + anyInt(), anyBoolean()); verifyDismissIntentSent(); clearInvocations(mSubControllerMock); - clearInvocations(mDataSettingsManagerMock1); - clearInvocations(mDataSettingsManagerMock2); + clearInvocations(mDataEnabledSettingsMock1); + clearInvocations(mDataEnabledSettingsMock2); doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); // Toggle data on sub 1 or sub 2. Nothing should happen as they are independent. mMultiSimSettingControllerUT.notifyUserDataEnabled(1, false); @@ -597,10 +595,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); processAllMessages(); verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); - verify(mDataSettingsManagerMock1, never()).setDataEnabled( - eq(TelephonyManager.DATA_ENABLED_REASON_USER), anyBoolean(), anyString()); - verify(mDataSettingsManagerMock2, never()).setDataEnabled( - eq(TelephonyManager.DATA_ENABLED_REASON_USER), eq(false), anyString()); + verify(mDataEnabledSettingsMock1, never()).setDataEnabled( + eq(TelephonyManager.DATA_ENABLED_REASON_USER), anyBoolean()); + verify(mDataEnabledSettingsMock2, never()).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); } private void verifyDismissIntentSent() { @@ -638,8 +636,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // This should result in setting sync. - verify(mDataSettingsManagerMock1).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, - false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock1).setUserDataEnabled(false, false); assertFalse(GlobalSettingsHelper.getBoolean( mContext, Settings.Global.DATA_ROAMING, 1, true)); @@ -648,8 +645,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Turning data on on sub 2. Sub 1 should also be turned on. mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); processAllMessages(); - verify(mDataSettingsManagerMock1).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, - true, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock1).setUserDataEnabled(true, false); verifyDismissIntentSent(); } @@ -719,8 +715,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // This should result in setting sync. - verify(mDataSettingsManagerMock2).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, - true, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock2).setUserDataEnabled(true, false); assertFalse(GlobalSettingsHelper.getBoolean( mContext, Settings.Global.DATA_ROAMING, 2, true)); verify(mSubControllerMock).setDataRoaming(/*enable*/0, /*subId*/1); @@ -729,8 +724,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(false).when(mPhoneMock1).isUserDataEnabled(); mMultiSimSettingControllerUT.notifyUserDataEnabled(1, false); processAllMessages(); - verify(mDataSettingsManagerMock2).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, - false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock2).setUserDataEnabled(false, false); } @Test @@ -742,16 +736,16 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // loaded on both subscriptions. mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); processAllMessages(); - verify(mDataSettingsManagerMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock2, never()).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); processAllMessages(); - verify(mDataSettingsManagerMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock2, never()).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataSettingsManagerMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); // Switch from sub 2 to sub 3 in phone[1]. clearInvocations(mSubControllerMock); @@ -833,8 +827,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); // Nothing should happen as carrier config is not ready for sub 2. - verify(mDataSettingsManagerMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock2, never()).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); // Still notify carrier config without specifying subId2, but this time subController // and CarrierConfigManager have subId 2 active and ready. @@ -846,8 +840,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); // This time user data should be disabled on phone1. - verify(mDataSettingsManagerMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataEnabledSettingsMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index 4b0cc6196c..0230645b59 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import android.content.Context; import android.content.Intent; @@ -35,25 +34,25 @@ import android.os.PersistableBundle; import android.os.PowerManager; import android.telephony.CarrierConfigManager; import android.telephony.NetworkRegistrationInfo; +import android.telephony.PcoData; import android.telephony.PhysicalChannelConfig; import android.telephony.RadioAccessFamily; import android.telephony.ServiceState; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; +import com.android.internal.telephony.dataconnection.DataConnection; import com.android.internal.util.IState; import com.android.internal.util.StateMachine; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import java.lang.reflect.Method; import java.util.ArrayList; @@ -61,7 +60,6 @@ import java.util.List; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper -@Ignore("b/240911460") public class NetworkTypeControllerTest extends TelephonyTest { // private constants copied over from NetworkTypeController private static final int EVENT_DATA_RAT_CHANGED = 2; @@ -69,13 +67,21 @@ public class NetworkTypeControllerTest extends TelephonyTest { private static final int EVENT_NR_FREQUENCY_CHANGED = 4; private static final int EVENT_PHYSICAL_LINK_STATUS_CHANGED = 5; private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED = 6; + private static final int EVENT_CARRIER_CONFIG_CHANGED = 7; + private static final int EVENT_PRIMARY_TIMER_EXPIRED = 8; + private static final int EVENT_SECONDARY_TIMER_EXPIRED = 9; private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 10; private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11; + private static final int EVENT_INITIALIZE = 12; private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 13; + private static final int EVENT_PCO_DATA_CHANGED = 14; private NetworkTypeController mNetworkTypeController; private PersistableBundle mBundle; - private DataNetworkControllerCallback mDataNetworkControllerCallback; + + // Mocked classes + DataConnection mDataConnection; + ApnSetting mApnSetting; private IState getCurrentState() throws Exception { Method method = StateMachine.class.getDeclaredMethod("getCurrentState"); @@ -100,28 +106,23 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + mDataConnection = mock(DataConnection.class); + mApnSetting = mock(ApnSetting.class); mBundle = mContextFixture.getCarrierConfigBundle(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING, "connected_mmwave:5G_Plus,connected:5G,not_restricted_rrc_idle:5G," + "not_restricted_rrc_con:5G"); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); replaceInstance(Handler.class, "mLooper", mDisplayInfoController, Looper.myLooper()); doReturn(RadioAccessFamily.getRafFromNetworkType( TelephonyManager.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA)).when( mPhone).getCachedAllowedNetworkTypesBitmask(); - doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( + doReturn(false).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); doReturn(new int[] {0}).when(mServiceState).getCellBandwidths(); mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); processAllMessages(); - - ArgumentCaptor dataNetworkControllerCallbackCaptor = - ArgumentCaptor.forClass(DataNetworkControllerCallback.class); - verify(mDataNetworkController).registerDataNetworkControllerCallback( - dataNetworkControllerCallbackCaptor.capture()); - mDataNetworkControllerCallback = dataNetworkControllerCallbackCaptor.getValue(); } @After @@ -473,7 +474,42 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); - mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(false); + int cid = 1; + byte[] contents = new byte[]{0}; + doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); + doReturn(mApnSetting).when(mDataConnection).getApnSetting(); + doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); + mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); + broadcastCarrierConfigs(); + + + mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, + new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); + mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + processAllMessages(); + assertEquals("connected", getCurrentState().getName()); + } + + @Test + public void testTransitionToCurrentStateNrConnectedWithPcoLength4AndNoNrAdvancedCapable() + throws Exception { + assertEquals("DefaultState", getCurrentState().getName()); + doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); + doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); + doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); + mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); + broadcastCarrierConfigs(); + int cid = 1; + byte[] contents = new byte[]{31, 1, 84, 0}; + doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); + doReturn(mApnSetting).when(mDataConnection).getApnSetting(); + doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); + mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); + broadcastCarrierConfigs(); + + + mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, + new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); processAllMessages(); assertEquals("connected", getCurrentState().getName()); @@ -486,10 +522,19 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); + mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); + broadcastCarrierConfigs(); + int cid = 1; + byte[] contents = new byte[]{1}; + doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); + doReturn(mApnSetting).when(mDataConnection).getApnSetting(); + doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF00); broadcastCarrierConfigs(); - mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(false); + + mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, + new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); processAllMessages(); assertEquals("connected", getCurrentState().getName()); @@ -502,12 +547,39 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); + int cid = 1; + byte[] contents = new byte[]{1}; + doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); + doReturn(mApnSetting).when(mDataConnection).getApnSetting(); + doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); + mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, + new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); processAllMessages(); - mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(true); + assertEquals("connected_mmwave", getCurrentState().getName()); + } + + @Test + public void testTransitionToCurrentStateNrConnectedWithNrAdvancedCapableAndPcoLength4() + throws Exception { + assertEquals("DefaultState", getCurrentState().getName()); + doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); + doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); + doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); + int cid = 1; + byte[] contents = new byte[]{31, 1, 84, 1}; + doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); + doReturn(mApnSetting).when(mDataConnection).getApnSetting(); + doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); + mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); + broadcastCarrierConfigs(); + + mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, + new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); + mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken b/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken new file mode 100644 index 0000000000..80cd9f17b5 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2007 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; + +import android.test.suitebuilder.annotation.MediumTest; +import com.android.internal.telephony.TestPhoneNotifier; +import com.android.internal.telephony.gsm.SmsMessage; +import com.android.internal.telephony.test.SimulatedCommands; +import com.android.internal.telephony.test.SimulatedRadioControl; +import com.android.internal.telephony.uicc.IccUtils; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.Iterator; + +/** + * {@hide} + */ +public class SMSDispatcherTest extends AndroidTestCase { + @MediumTest + public void testCMT1() throws Exception { + SmsMessage sms; + SmsHeader header; + + String[] lines = new String[2]; + + lines[0] = "+CMT: ,158"; + lines[1] = "07914140279510F6440A8111110301003BF56080426101748A8C0B05040B" + + "8423F000035502010106276170706C69636174696F6E2F766E642E776170" + + "2E6D6D732D6D65737361676500AF848D0185B4848C8298524F347839776F" + + "7547514D4141424C3641414141536741415A4B554141414141008D908918" + + "802B31363530323438363137392F545950453D504C4D4E008A808E028000" + + "88058103093A8083687474703A2F2F36"; + + sms = SmsMessage.newFromCMT(lines); + header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(sms.getUserData()); + assertNotNull(header.concatRef); + assertEquals(header.concatRef.refNumber, 85); + assertEquals(header.concatRef.msgCount, 2); + assertEquals(header.concatRef.seqNumber, 1); + assertEquals(header.concatRef.isEightBits, true); + assertNotNull(header.portAddrs); + assertEquals(header.portAddrs.destPort, 2948); + assertEquals(header.portAddrs.origPort, 9200); + assertEquals(header.portAddrs.areEightBits, false); + } + + @MediumTest + public void testCMT2() throws Exception { + SmsMessage sms; + SmsHeader header; + + String[] lines = new String[2]; + + lines[0] = "+CMT: ,77"; + lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F" + + "00003550202362E3130322E3137312E3135302F524F347839776F7547514D4141" + + "424C3641414141536741415A4B55414141414100"; + + sms = SmsMessage.newFromCMT(lines); + header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(sms.getUserData()); + assertNotNull(header.concatRef); + assertEquals(header.concatRef.refNumber, 85); + assertEquals(header.concatRef.msgCount, 2); + assertEquals(header.concatRef.seqNumber, 2); + assertEquals(header.concatRef.isEightBits, true); + assertNotNull(header.portAddrs); + assertEquals(header.portAddrs.destPort, 2948); + assertEquals(header.portAddrs.origPort, 9200); + assertEquals(header.portAddrs.areEightBits, false); + } + + @MediumTest + public void testEfRecord() throws Exception { + SmsMessage sms; + + String s = "03029111000c9194981492631000f269206190022000a053e4534a05358bd3" + + "69f05804259da0219418a40641536a110a0aea408080604028180e888462c1" + + "50341c0f484432a1542c174c46b3e1743c9f9068442a994ea8946ac56ab95e" + + "b0986c46abd96eb89c6ec7ebf97ec0a070482c1a8fc8a472c96c3a9fd0a874" + + "4aad5aafd8ac76cbed7abfe0b0784c2e9bcfe8b47acd6ebbdff0b87c4eafdb" + + "eff8bc7ecfeffbffffffffffffffffffffffffffff"; + byte[] data = IccUtils.hexStringToBytes(s); + + sms = SmsMessage.createFromEfRecord(1, data); + assertNotNull(sms.getMessageBody()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 1dbda5ba7c..072f2190e0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -235,6 +235,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { doReturn(mIwlanNetworkServiceStub).when(mIwlanNetworkServiceStub).asBinder(); addNetworkService(); + doReturn(true).when(mDcTracker).areAllDataDisconnected(); doReturn(true).when(mDataNetworkController).areAllDataDisconnected(); doReturn(new ServiceState()).when(mPhone).getServiceState(); @@ -260,6 +261,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { int dds = SubscriptionManager.getDefaultDataSubscriptionId(); doReturn(dds).when(mPhone).getSubId(); + doReturn(true).when(mPhone).areAllDataDisconnected(); doReturn(true).when(mPackageManager) .hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA); @@ -389,6 +391,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); doReturn(dataNetworkController_phone2).when(phone2).getDataNetworkController(); doReturn(mSST).when(phone2).getServiceStateTracker(); + doReturn(true).when(phone2).isUsingNewDataStack(); doReturn(false).when(mDataNetworkController).areAllDataDisconnected(); doReturn(false).when(dataNetworkController_phone2).areAllDataDisconnected(); doReturn(1).when(mPhone).getSubId(); @@ -1768,6 +1771,29 @@ public class ServiceStateTrackerTest extends TelephonyTest { assertEquals(TelephonyManager.RADIO_POWER_UNAVAILABLE, mSimulatedCommands.getRadioState()); } + @Test + @SmallTest + public void testImsRegisteredDelayShutDown() throws Exception { + doReturn(false).when(mPhone).isUsingNewDataStack(); + doReturn(true).when(mPhone).isPhoneTypeGsm(); + mContextFixture.putIntResource( + com.android.internal.R.integer.config_delay_for_ims_dereg_millis, 1000 /*ms*/); + sst.setImsRegistrationState(true); + mSimulatedCommands.setRadioPowerFailResponse(false); + sst.setRadioPower(true); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + + // Turn off the radio and ensure radio power is still on + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + sst.setRadioPower(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + + // Now set IMS reg state to false and ensure we see the modem move to power off. + sst.setImsRegistrationState(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); + } @Test @SmallTest @@ -1786,6 +1812,33 @@ public class ServiceStateTrackerTest extends TelephonyTest { assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); } + @Test + @SmallTest + public void testImsRegisteredDelayShutDownTimeout() throws Exception { + doReturn(false).when(mPhone).isUsingNewDataStack(); + doReturn(true).when(mPhone).isPhoneTypeGsm(); + mContextFixture.putIntResource( + com.android.internal.R.integer.config_delay_for_ims_dereg_millis, 1000 /*ms*/); + sst.setImsRegistrationState(true); + mSimulatedCommands.setRadioPowerFailResponse(false); + sst.setRadioPower(true); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + + // Turn off the radio and ensure radio power is still on + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + sst.setRadioPower(false); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); + + // Ensure that if we never turn deregister for IMS, we still eventually see radio state + // move to off. + // Timeout for IMS reg + some extra time to remove race conditions + waitForDelayedHandlerAction(mSSTTestHandler.getThreadHandler(), + sst.getRadioPowerOffDelayTimeoutForImsRegistration() + 1000, 1000); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); + } + @Test @SmallTest public void testImsRegisteredAPMOnOffToggle() throws Exception { diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 6cb7464ff0..6cc87813b9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -103,6 +103,9 @@ import com.android.internal.telephony.data.DataRetryManager; import com.android.internal.telephony.data.DataServiceManager; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; +import com.android.internal.telephony.dataconnection.DataEnabledSettings; +import com.android.internal.telephony.dataconnection.DataThrottler; +import com.android.internal.telephony.dataconnection.DcTracker; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; @@ -189,6 +192,7 @@ public abstract class TelephonyTest { protected RegistrantList mRegistrantList; protected IccPhoneBookInterfaceManager mIccPhoneBookIntManager; protected ImsManager mImsManager; + protected DcTracker mDcTracker; protected DataNetworkController mDataNetworkController; protected DataRetryManager mDataRetryManager; protected DataSettingsManager mDataSettingsManager; @@ -236,6 +240,7 @@ public abstract class TelephonyTest { protected SubscriptionInfoUpdater mSubInfoRecordUpdater; protected LocaleTracker mLocaleTracker; protected RestrictedState mRestrictedState; + protected DataEnabledSettings mDataEnabledSettings; protected DataEnabledOverride mDataEnabledOverride; protected PhoneConfigurationManager mPhoneConfigurationManager; protected CellularNetworkValidator mCellularNetworkValidator; @@ -249,6 +254,7 @@ public abstract class TelephonyTest { protected PersistAtomsStorage mPersistAtomsStorage; protected MetricsCollector mMetricsCollector; protected SmsStats mSmsStats; + protected DataThrottler mDataThrottler; protected SignalStrength mSignalStrength; protected WifiManager mWifiManager; protected WifiInfo mWifiInfo; @@ -420,6 +426,7 @@ public abstract class TelephonyTest { mRegistrantList = Mockito.mock(RegistrantList.class); mIccPhoneBookIntManager = Mockito.mock(IccPhoneBookInterfaceManager.class); mImsManager = Mockito.mock(ImsManager.class); + mDcTracker = Mockito.mock(DcTracker.class); mDataNetworkController = Mockito.mock(DataNetworkController.class); mDataRetryManager = Mockito.mock(DataRetryManager.class); mDataSettingsManager = Mockito.mock(DataSettingsManager.class); @@ -467,6 +474,7 @@ public abstract class TelephonyTest { mSubInfoRecordUpdater = Mockito.mock(SubscriptionInfoUpdater.class); mLocaleTracker = Mockito.mock(LocaleTracker.class); mRestrictedState = Mockito.mock(RestrictedState.class); + mDataEnabledSettings = Mockito.mock(DataEnabledSettings.class); mDataEnabledOverride = Mockito.mock(DataEnabledOverride.class); mPhoneConfigurationManager = Mockito.mock(PhoneConfigurationManager.class); mCellularNetworkValidator = Mockito.mock(CellularNetworkValidator.class); @@ -480,6 +488,7 @@ public abstract class TelephonyTest { mPersistAtomsStorage = Mockito.mock(PersistAtomsStorage.class); mMetricsCollector = Mockito.mock(MetricsCollector.class); mSmsStats = Mockito.mock(SmsStats.class); + mDataThrottler = Mockito.mock(DataThrottler.class); mSignalStrength = Mockito.mock(SignalStrength.class); mWifiManager = Mockito.mock(WifiManager.class); mWifiInfo = Mockito.mock(WifiInfo.class); @@ -560,6 +569,8 @@ public abstract class TelephonyTest { .makeGsmCdmaCallTracker(nullable(GsmCdmaPhone.class)); doReturn(mIccPhoneBookIntManager).when(mTelephonyComponentFactory) .makeIccPhoneBookInterfaceManager(nullable(Phone.class)); + doReturn(mDcTracker).when(mTelephonyComponentFactory) + .makeDcTracker(nullable(Phone.class), anyInt()); doReturn(mDisplayInfoController).when(mTelephonyComponentFactory) .makeDisplayInfoController(nullable(Phone.class)); doReturn(mWspTypeDecoder).when(mTelephonyComponentFactory) @@ -587,6 +598,8 @@ public abstract class TelephonyTest { doReturn(mLocaleTracker).when(mTelephonyComponentFactory) .makeLocaleTracker(nullable(Phone.class), nullable(NitzStateMachine.class), nullable(Looper.class)); + doReturn(mDataEnabledSettings).when(mTelephonyComponentFactory) + .makeDataEnabledSettings(nullable(Phone.class)); doReturn(mEriManager).when(mTelephonyComponentFactory) .makeEriManager(nullable(Phone.class), anyInt()); doReturn(mLinkBandwidthEstimator).when(mTelephonyComponentFactory) @@ -616,6 +629,8 @@ public abstract class TelephonyTest { doReturn(mAppSmsManager).when(mPhone).getAppSmsManager(); doReturn(mIccSmsInterfaceManager).when(mPhone).getIccSmsInterfaceManager(); doReturn(mAccessNetworksManager).when(mPhone).getAccessNetworksManager(); + doReturn(mDataEnabledSettings).when(mPhone).getDataEnabledSettings(); + doReturn(mDcTracker).when(mPhone).getDcTracker(anyInt()); doReturn(mDataSettingsManager).when(mDataNetworkController).getDataSettingsManager(); doReturn(mDataNetworkController).when(mPhone).getDataNetworkController(); doReturn(mDataSettingsManager).when(mPhone).getDataSettingsManager(); @@ -633,6 +648,7 @@ public abstract class TelephonyTest { doReturn(mDataProfileManager).when(mDataNetworkController).getDataProfileManager(); doReturn(mDataRetryManager).when(mDataNetworkController).getDataRetryManager(); doReturn(mCarrierPrivilegesTracker).when(mPhone).getCarrierPrivilegesTracker(); + doReturn(true).when(mPhone).isUsingNewDataStack(); doReturn(0).when(mPhone).getPhoneId(); //mUiccController @@ -723,6 +739,11 @@ public abstract class TelephonyTest { doReturn(new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) .when(mAccessNetworksManager).getAvailableTransports(); + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) + .getCurrentTransport(anyInt()); + doReturn(true).when(mDataEnabledSettings).isDataEnabled(); + doReturn(true).when(mDataEnabledSettings).isDataEnabled(anyInt()); + doReturn(true).when(mDataEnabledSettings).isInternalDataEnabled(); doReturn(true).when(mDataSettingsManager).isDataEnabled(); doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( anyInt(), anyInt()); @@ -758,6 +779,8 @@ public abstract class TelephonyTest { Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 1); Settings.Global.putInt(resolver, Settings.Global.DATA_ROAMING, 0); + doReturn(mDataThrottler).when(mDcTracker).getDataThrottler(); + doReturn(-1L).when(mDataThrottler).getRetryTime(anyInt()); doReturn(90).when(mDataConfigManager).getNetworkCapabilityPriority( eq(NetworkCapabilities.NET_CAPABILITY_EIMS)); diff --git a/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken b/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken new file mode 100644 index 0000000000..761dfc7412 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2006 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; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; +import android.telephony.CellInfo; + +import java.util.List; + +/** + * Stub class used for unit tests + */ + +public class TestPhoneNotifier implements PhoneNotifier { + public TestPhoneNotifier() { + } + + public void notifyPhoneState(Phone sender) { + } + + public void notifyServiceState(Phone sender) { + } + + public void notifyCellLocation(Phone sender) { + } + + public void notifySignalStrength(Phone sender) { + } + + public void notifyMessageWaitingChanged(Phone sender) { + } + + public void notifyCallForwardingChanged(Phone sender) { + } + + public void notifyDataConnection(Phone sender, String reason, String apnType) { + } + + public void notifyDataConnection(Phone sender, String reason, String apnType, + PhoneConstants.DataState state) { + } + + public void notifyDataConnectionFailed(Phone sender, String reason, String apnType) { + } + + public void notifyDataActivity(Phone sender) { + } + + public void notifyOtaspChanged(Phone sender, int otaspMode) { + } + + public void notifyCellInfo(Phone sender, List cellInfo) { + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java index 92cf861b33..46d1f0a6fe 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java @@ -16,6 +16,12 @@ package com.android.internal.telephony.data; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; + import android.net.InetAddresses; import android.net.LinkAddress; import android.os.Parcel; @@ -31,20 +37,15 @@ import java.util.ArrayList; import java.util.Arrays; public class DataCallResponseTest extends AndroidTestCase { - private static final String FAKE_ADDRESS = "99.88.77.66"; - private static final String FAKE_DNS = "55.66.77.88"; - private static final String FAKE_DNN = "FAKE_DNN"; - private static final String FAKE_GATEWAY = "11.22.33.44"; - private static final String FAKE_IFNAME = "FAKE IFNAME"; - private static final String FAKE_PCSCF_ADDRESS = "22.33.44.55"; + public static final String FAKE_DNN = "FAKE_DNN"; // 97a498e3fc925c9489860333d06e4e470a454e5445525052495345. // [OsAppId.ANDROID_OS_ID, "ENTERPRISE", 1] - private static final byte[] FAKE_OS_APP_ID = {-105, -92, -104, -29, -4, -110, 92, + public static final byte[] FAKE_OS_APP_ID = {-105, -92, -104, -29, -4, -110, 92, -108, -119, -122, 3, 51, -48, 110, 78, 71, 10, 69, 78, 84, 69, 82, 80, 82, 73, 83, 69}; // 97a498e3fc925c9489860333d06e4e470a454e544552505249534532. // [OsAppId.ANDROID_OS_ID, "ENTERPRISE", 2] - private static final byte[] FAKE_OS_APP_ID_2 = {-105, -92, -104, -29, -4, -110, 92, + public static final byte[] FAKE_OS_APP_ID_2 = {-105, -92, -104, -29, -4, -110, 92, -108, -119, -122, 3, 51, -48, 110, 78, 71, 10, 69, 78, 84, 69, 82, 80, 82, 73, 83, 69, 50}; 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 951a7f38b7..5c9f4cb446 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -944,6 +944,8 @@ public class DataNetworkTest extends TelephonyTest { verify(mDataNetworkCallback).onHandoverFailed(eq(mDataNetworkUT), eq(DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE), eq(-1L), eq(DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN)); + verify(mLinkBandwidthEstimator, never()).unregisterForBandwidthChanged( + eq(mDataNetworkUT.getHandler())); assertThat(mDataNetworkUT.getTransport()) .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); assertThat(mDataNetworkUT.getId()).isEqualTo(123); 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 d41be7d7a5..ba001f2bfb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/LinkBandwidthEstimatorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/LinkBandwidthEstimatorTest.java @@ -32,6 +32,7 @@ import static com.android.internal.telephony.data.LinkBandwidthEstimator.UNKNOWN import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; @@ -42,7 +43,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.net.NetworkCapabilities; +import android.os.AsyncResult; import android.os.Handler; +import android.os.Message; import android.telephony.CellIdentityLte; import android.telephony.ModemActivityInfo; import android.telephony.NetworkRegistrationInfo; @@ -60,6 +63,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @RunWith(AndroidTestingRunner.class) @@ -76,6 +80,7 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { new ModemActivityInfo(100L, 0, 0, TX_TIME_2_MS, RX_TIME_2_MS); private static final ModemActivityInfo MAI_RX_TIME_HIGH = new ModemActivityInfo(100L, 0, 0, TX_TIME_1_MS, RX_TIME_2_MS); + private static final int EVENT_BANDWIDTH_ESTIMATOR_UPDATE = 1; private NetworkCapabilities mNetworkCapabilities; private CellIdentityLte mCellIdentity; private long mElapsedTimeMs = 0; @@ -84,20 +89,14 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { private NetworkRegistrationInfo mNri; // Mocked classes - private TelephonyFacade mTelephonyFacade; + TelephonyFacade mTelephonyFacade; private Handler mTestHandler; - private LinkBandwidthEstimatorCallback mLinkBandwidthEstimatorCallback; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mTelephonyFacade = mock(TelephonyFacade.class); mTestHandler = mock(Handler.class); - mLinkBandwidthEstimatorCallback = Mockito.mock(LinkBandwidthEstimatorCallback.class); - doAnswer(invocation -> { - ((Runnable) invocation.getArguments()[0]).run(); - return null; - }).when(mLinkBandwidthEstimatorCallback).invokeFromExecutor(any(Runnable.class)); mNetworkCapabilities = new NetworkCapabilities.Builder() .addTransportType(TRANSPORT_CELLULAR) .build(); @@ -117,10 +116,10 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { when(mSignalStrength.getDbm()).thenReturn(-100); when(mSignalStrength.getLevel()).thenReturn(1); mLBE = new LinkBandwidthEstimator(mPhone, mTelephonyFacade); + mLBE.registerForBandwidthChanged(mTestHandler, EVENT_BANDWIDTH_ESTIMATOR_UPDATE, null); mLBE.obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, mNetworkCapabilities).sendToTarget(); mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, false).sendToTarget(); mLBE.obtainMessage(MSG_ACTIVE_PHONE_CHANGED, 1).sendToTarget(); - mLBE.registerCallback(mLinkBandwidthEstimatorCallback); processAllMessages(); } @@ -185,8 +184,12 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { } private void verifyUpdateBandwidth(int txKbps, int rxKbps) { - verify(mLinkBandwidthEstimatorCallback, atLeast(1)) - .onBandwidthChanged(eq(txKbps), eq(rxKbps)); + ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); + verify(mTestHandler, atLeast(1)) + .sendMessageAtTime(messageArgumentCaptor.capture(), anyLong()); + assertEquals(EVENT_BANDWIDTH_ESTIMATOR_UPDATE, messageArgumentCaptor.getValue().what); + assertEquals(new Pair(txKbps, rxKbps), + ((AsyncResult) messageArgumentCaptor.getValue().obj).result); } @Test 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 487f7e33f2..d50cb720c4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -79,6 +79,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.dataconnection.DataEnabledSettings; import org.junit.After; import org.junit.Before; @@ -103,7 +104,7 @@ public class PhoneSwitcherTest extends TelephonyTest { private Phone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. private Phone mImsPhone; // TODO: Add logic for DataSettingsManager - private DataSettingsManager mDataSettingsManager2; + private DataEnabledSettings mDataEnabledSettings2; private Handler mActivePhoneSwitchHandler; private GsmCdmaCall mActiveCall; private GsmCdmaCall mHoldingCall; @@ -135,7 +136,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mCommandsInterface1 = mock(CommandsInterface.class); mPhone2 = mock(Phone.class); // mPhone as phone 1 is already defined in TelephonyTest. mImsPhone = mock(Phone.class); - mDataSettingsManager2 = mock(DataSettingsManager.class); + mDataEnabledSettings2 = mock(DataEnabledSettings.class); mActivePhoneSwitchHandler = mock(Handler.class); mActiveCall = mock(GsmCdmaCall.class); mHoldingCall = mock(GsmCdmaCall.class); @@ -647,7 +648,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInCall(mImsPhone); @@ -676,7 +677,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInDial(mImsPhone); @@ -704,7 +705,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInIncomingCall(mImsPhone); @@ -731,7 +732,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active call, but data is turned off. So no data switching should happen. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_IWLAN); notifyPhoneAsInCall(mImsPhone); @@ -759,7 +760,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone 1 has active IMS call on CROSS_SIM. And data of DEFAULT apn is enabled. This should // not trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_CROSS_SIM); notifyPhoneAsInCall(mImsPhone); @@ -1192,6 +1193,7 @@ public class PhoneSwitcherTest extends TelephonyTest { verify(mPhone2).registerForEmergencyCallToggle(any(), anyInt(), any()); verify(mPhone2).registerForPreciseCallStateChanged(any(), anyInt(), any()); + verify(mDataEnabledSettings2).registerForDataEnabledChanged(any(), anyInt(), any()); clearInvocations(mMockRadioConfig); setSlotIndexToSubId(1, 2); @@ -1373,8 +1375,8 @@ public class PhoneSwitcherTest extends TelephonyTest { } private void notifyDataEnabled(boolean dataEnabled) { - doReturn(dataEnabled).when(mDataSettingsManager).isDataEnabled(anyInt()); - doReturn(dataEnabled).when(mDataSettingsManager2).isDataEnabled(anyInt()); + doReturn(dataEnabled).when(mDataEnabledSettings).isDataEnabled(anyInt()); + doReturn(dataEnabled).when(mDataEnabledSettings2).isDataEnabled(anyInt()); mPhoneSwitcher.sendEmptyMessage(EVENT_DATA_ENABLED_CHANGED); processAllMessages(); } @@ -1468,7 +1470,7 @@ public class PhoneSwitcherTest extends TelephonyTest { doReturn(0).when(mPhone).getPhoneId(); doReturn(1).when(mPhone2).getPhoneId(); doReturn(true).when(mPhone2).isUserDataEnabled(); - doReturn(mDataSettingsManager2).when(mPhone2).getDataSettingsManager(); + doReturn(mDataEnabledSettings2).when(mPhone2).getDataEnabledSettings(); for (int i = 0; i < supportedModemCount; i++) { mSlotIndexToSubId[i] = new int[1]; mSlotIndexToSubId[i][0] = SubscriptionManager.INVALID_SUBSCRIPTION_ID; diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java index 2ab65333ee..00bca4d0af 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java @@ -27,17 +27,15 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.annotation.NonNull; -import android.net.INetworkAgentRegistry; import android.net.InetAddresses; import android.net.LinkAddress; import android.net.Network; -import android.net.NetworkAgent; -import android.net.QosSession; import android.telephony.data.EpsBearerQosSessionAttributes; import android.telephony.data.EpsQos; import android.telephony.data.Qos; import android.telephony.data.QosBearerFilter; import android.telephony.data.QosBearerSession; +import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -93,7 +91,6 @@ public class QosCallbackTrackerTest extends TelephonyTest { // Mocked classes private Phone mPhone; private TelephonyNetworkAgent mNetworkAgent; - private INetworkAgentRegistry mINetworkAgentRegistry; private Network mNetwork; private RcsStats mRcsStats; @@ -104,9 +101,6 @@ public class QosCallbackTrackerTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mPhone = mock(Phone.class); mNetworkAgent = mock(TelephonyNetworkAgent.class); - mINetworkAgentRegistry = mock(INetworkAgentRegistry.class); - replaceInstance(NetworkAgent.class, "mRegistry", mNetworkAgent, mINetworkAgentRegistry); - replaceInstance(NetworkAgent.class, "mPreConnectedQueue", mNetworkAgent, new ArrayList()); mNetwork = mock(Network.class); mRcsStats = mock(RcsStats.class); doReturn(mNetwork).when(mNetworkAgent).getNetwork(); @@ -159,6 +153,7 @@ public class QosCallbackTrackerTest extends TelephonyTest { } @Test + @SmallTest public void testAddFilterBeforeUpdateSessions() throws Exception { Filter filter = new Filter(new InetSocketAddress( InetAddresses.parseNumericAddress("122.22.22.22"), 2222)); @@ -175,8 +170,8 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), + eq(1234), any(EpsBearerQosSessionAttributes.class)); // Matching QosBearerFilter ArrayList qosFilters2 = new ArrayList<>(); @@ -187,12 +182,14 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), + eq(1235), any(EpsBearerQosSessionAttributes.class)); + } @Test + @SmallTest public void testAddFilterAfterUpdateSessions() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -216,11 +213,13 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), + eq(1235), any(EpsBearerQosSessionAttributes.class)); + } @Test + @SmallTest public void testRemoveFilter() throws Exception { // Add filter Filter filter = new Filter(new InetSocketAddress( @@ -238,8 +237,8 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), + eq(1234), any(EpsBearerQosSessionAttributes.class)); // Remove the filter mQosCallbackTracker.removeFilter(1); @@ -254,11 +253,13 @@ public class QosCallbackTrackerTest extends TelephonyTest { processAllMessages(); // Verify that notifyQosSessionAvailable is not invoked as the filter is already removed - verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), + eq(1235), any(EpsBearerQosSessionAttributes.class)); + } @Test + @SmallTest public void testSessionLost() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -286,18 +287,19 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), + eq(1235), any(EpsBearerQosSessionAttributes.class)); // Remove the matching QosBearerFilter qosSessions.remove(1); mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1235), eq(1)); } @Test + @SmallTest public void testModifiedQos() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -324,10 +326,10 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), + eq(1235), any(EpsBearerQosSessionAttributes.class)); - reset(mINetworkAgentRegistry); + reset(mNetworkAgent); // Update the QOS qosSessions.remove(1); @@ -335,11 +337,12 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), + eq(1235), any(EpsBearerQosSessionAttributes.class)); } @Test + @SmallTest public void testUnmodifiedQos() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -366,8 +369,8 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), + eq(1235), any(EpsBearerQosSessionAttributes.class)); reset(mNetworkAgent); @@ -377,11 +380,12 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), + eq(1235), any(EpsBearerQosSessionAttributes.class)); } @Test + @SmallTest public void testEmptyQosSessions() throws Exception { // Add filter Filter filter = new Filter(new InetSocketAddress( @@ -414,21 +418,21 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(2, filter2); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(2), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); - + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), + eq(1234), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(2), + eq(1235), any(EpsBearerQosSessionAttributes.class)); // Update empty QOS sessions list mQosCallbackTracker.updateSessions(new ArrayList<>()); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); - verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(2), any(QosSession.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234), eq(1)); + verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(2), eq(1235), eq(1)); } @Test + @SmallTest public void testMultipleQosSessions() throws Exception { // Add filter 1 Filter filter1 = new Filter(new InetSocketAddress( @@ -461,20 +465,21 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); - verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(2), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), + eq(1234), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(2), + eq(1235), any(EpsBearerQosSessionAttributes.class)); // Update empty QOS sessions list mQosCallbackTracker.updateSessions(new ArrayList<>()); processAllMessages(); - verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); - verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(2), any(QosSession.class)); + verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234), eq(1)); + verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(2), eq(1235), eq(1)); } @Test + @SmallTest public void testQosSessionWithInvalidPortRange() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -498,12 +503,14 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), - any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), + eq(1235), any(EpsBearerQosSessionAttributes.class)); + } @Test - public void testQosMetrics() { + @SmallTest + public void testQosMetrics() throws Exception { final int callbackId = 1; final int slotId = mPhone.getPhoneId(); // Add filter before update session diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java index 7d323aa4b4..d109ee929e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java @@ -22,18 +22,24 @@ import static com.android.internal.telephony.NetworkFactory.CMD_REQUEST_NETWORK; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.net.NetworkCapabilities; import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.os.AsyncResult; +import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.telephony.AccessNetworkConstants; +import android.telephony.data.ApnSetting; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -43,6 +49,9 @@ import androidx.test.filters.FlakyTest; import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.dataconnection.DataConnection; +import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams; +import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams.HandoverCallback; import com.android.telephony.Rlog; import org.junit.After; @@ -50,7 +59,9 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -63,12 +74,13 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { // Mocked classes PhoneSwitcher mPhoneSwitcher; private RadioConfig mMockRadioConfig; + private DataConnection mDataConnection; private String mTestName = ""; // List of all requests filed by a test private final ArraySet mAllNetworkRequestSet = new ArraySet<>(); - // List of requests active + // List of requests active in DcTracker private final ArrayList mNetworkRequestList = new ArrayList<>(); // List of complete messages associated with the network requests private final Map mNetworkRequestMessageMap = new HashMap<>(); @@ -144,6 +156,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mPhoneSwitcher = mock(PhoneSwitcher.class); mMockRadioConfig = mock(RadioConfig.class); + mDataConnection = mock(DataConnection.class); replaceInstance(RadioConfig.class, "sRadioConfig", null, mMockRadioConfig); mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes, @@ -217,7 +230,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { } /** - * Test that phone active changes + * Test that phone active changes cause the DcTracker to get poked. */ @FlakyTest @Test @@ -288,7 +301,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { } /** - * Test that network request changes + * Test that network request changes cause the DcTracker to get poked. */ @Test @SmallTest @@ -351,4 +364,79 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { processAllMessages(); assertEquals(3, mNetworkRequestList.size()); } + + /** + * Test handover when there is no live data connection + */ + @Test + @SmallTest + public void testHandoverNoLiveData() throws Exception { + createMockedTelephonyComponents(); + doReturn(0).when(mSubscriptionController).getSubIdUsingPhoneId(0); + mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( + TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); + + activatePhoneInPhoneSwitcher(0, true); + makeDefaultInternetRequest(); + + makeSubSpecificMmsRequest(0); + processAllMessages(); + + Field f = TelephonyNetworkFactory.class.getDeclaredField("mInternalHandler"); + f.setAccessible(true); + Handler h = (Handler) f.get(mTelephonyNetworkFactoryUT); + + HandoverCallback handoverCallback = mock(HandoverCallback.class); + + HandoverParams hp = new HandoverParams(ApnSetting.TYPE_MMS, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, handoverCallback); + AsyncResult ar = new AsyncResult(null, hp, null); + h.sendMessage(h.obtainMessage(5, ar)); + processAllMessages(); + + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) + .getCurrentTransport(anyInt()); + + hp = new HandoverParams(ApnSetting.TYPE_MMS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + handoverCallback); + ar = new AsyncResult(null, hp, null); + h.sendMessage(h.obtainMessage(5, ar)); + processAllMessages(); + } + + /** + * Test handover when the data connection is being connected. + */ + @Test + @SmallTest + public void testHandoverActivatingData() throws Exception { + createMockedTelephonyComponents(); + doReturn(0).when(mSubscriptionController).getSubIdUsingPhoneId(0); + mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( + TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); + + activatePhoneInPhoneSwitcher(0, true); + makeDefaultInternetRequest(); + + makeSubSpecificMmsRequest(0); + processAllMessages(); + + Field f = TelephonyNetworkFactory.class.getDeclaredField("mInternalHandler"); + f.setAccessible(true); + Handler h = (Handler) f.get(mTelephonyNetworkFactoryUT); + + HandoverCallback handoverCallback = mock(HandoverCallback.class); + Mockito.reset(mDataNetworkController); + doReturn(mDataConnection).when(mDcTracker).getDataConnectionByApnType(anyString()); + doReturn(false).when(mDataConnection).isActive(); + + HandoverParams hp = new HandoverParams(ApnSetting.TYPE_MMS, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, handoverCallback); + AsyncResult ar = new AsyncResult(null, hp, null); + h.sendMessage(h.obtainMessage(5, ar)); + processAllMessages(); + + verify(mDataNetworkController, times(1)).removeNetworkRequest(any()); + verify(mDataNetworkController, times(1)).addNetworkRequest(any()); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java new file mode 100644 index 0000000000..f2d694fb6b --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2020 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.dataconnection; + +import static junit.framework.Assert.assertEquals; + +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.data.ApnSetting; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +public class ApnConfigTypeRepositoryTest { + + PersistableBundle mCarrierConfig; + + @Before + public void setUp() throws Exception { + mCarrierConfig = new PersistableBundle(); + } + + @After + public void tearDown() { + mCarrierConfig = null; + } + + @Test + public void testReturnsDefaultsWhenCarrierConfigNull() { + ApnConfigTypeRepository repository = new ApnConfigTypeRepository(null); + checkDefaults(repository); + } + + @Test + public void testReturnsDefaultsWhenCarrierConfigApnContextKeyReturnsNull() { + mCarrierConfig.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, + null); + + ApnConfigTypeRepository repository = new ApnConfigTypeRepository(mCarrierConfig); + checkDefaults(repository); + } + + @Test + public void testReturnsDefaultsWhenCarrierConfigHasInvalidTypes() { + + List apnConfigStringArray = new ArrayList<>(); + apnConfigStringArray.add("xcap,cbs:3"); + apnConfigStringArray.add("default:0a"); + + mCarrierConfig.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, + apnConfigStringArray.toArray(new String[0])); + + ApnConfigTypeRepository repository = new ApnConfigTypeRepository(mCarrierConfig); + checkDefaults(repository); + } + + @Test + public void testReturnsCarrierConfigOverride() { + List apnConfigStringArray = new ArrayList<>(); + //Shouldn't match or override any keys + apnConfigStringArray.add("xcap,cbs:3"); + + //Priorities must be integers + apnConfigStringArray.add("default:10a"); + + //Key isn't case sensitive, which means that this priority should be taken + apnConfigStringArray.add("fotA:10"); + + mCarrierConfig.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, + apnConfigStringArray.toArray(new String[0])); + + ApnConfigTypeRepository repository = new ApnConfigTypeRepository(mCarrierConfig); + assertEquals(10, repository.getByType(ApnSetting.TYPE_FOTA).getPriority()); + checkDefaults(repository); + } + + private void checkDefaults(ApnConfigTypeRepository repository) { + assertEquals(0, repository.getByType(ApnSetting.TYPE_ENTERPRISE).getPriority()); + assertEquals(1, repository.getByType(ApnSetting.TYPE_DEFAULT).getPriority()); + assertEquals(2, repository.getByType(ApnSetting.TYPE_MMS).getPriority()); + assertEquals(2, repository.getByType(ApnSetting.TYPE_SUPL).getPriority()); + assertEquals(2, repository.getByType(ApnSetting.TYPE_DUN).getPriority()); + assertEquals(3, repository.getByType(ApnSetting.TYPE_HIPRI).getPriority()); + assertEquals(2, repository.getByType(ApnSetting.TYPE_IMS).getPriority()); + assertEquals(2, repository.getByType(ApnSetting.TYPE_CBS).getPriority()); + assertEquals(2, repository.getByType(ApnSetting.TYPE_IA).getPriority()); + assertEquals(2, repository.getByType(ApnSetting.TYPE_EMERGENCY).getPriority()); + assertEquals(3, repository.getByType(ApnSetting.TYPE_MCX).getPriority()); + assertEquals(3, repository.getByType(ApnSetting.TYPE_XCAP).getPriority()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java new file mode 100644 index 0000000000..b27054875a --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2010 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.dataconnection; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.telephony.data.ApnSetting; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.internal.R; +import com.android.internal.telephony.DctConstants; +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class ApnContextTest extends TelephonyTest { + // Mocked classes + ApnSetting mApnSetting; + + private ApnContext mApnContext; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + mApnSetting = mock(ApnSetting.class); + mApnContext = new ApnContext(mPhone, ApnSetting.TYPE_DEFAULT, TAG, mDcTracker, 1); + } + + @After + public void tearDown() throws Exception { + mApnContext = null; + super.tearDown(); + } + + @Test + @SmallTest + public void testSetGetApnSetting() throws Exception { + mApnContext.setApnSetting(mApnSetting); + assertEquals(mApnSetting, mApnContext.getApnSetting()); + } + + @Test + @SmallTest + public void testGetApnType() { + assertEquals(ApnSetting.TYPE_DEFAULT_STRING, mApnContext.getApnType()); + } + + @Test + @SmallTest + public void testConnectionGeneration() throws Exception { + for (int i = 0; i < 100; i++) { + mApnContext.incAndGetConnectionGeneration(); + assertEquals(i + 1, mApnContext.getConnectionGeneration()); + } + } + + @Test + @SmallTest + public void testReason() throws Exception { + mApnContext.setReason("dataEnabled"); + assertEquals("dataEnabled", mApnContext.getReason()); + mApnContext.setReason("simLoaded"); + assertEquals("simLoaded", mApnContext.getReason()); + } + + @Test + @SmallTest + public void testState() throws Exception { + mApnContext.setState(DctConstants.State.DISCONNECTING); + assertEquals(DctConstants.State.DISCONNECTING, mApnContext.getState()); + mApnContext.setEnabled(true); + assertFalse(mApnContext.isConnectable()); + + mApnContext.setState(DctConstants.State.RETRYING); + assertTrue(mApnContext.isConnectable()); + assertTrue(mApnContext.isConnectedOrConnecting()); + + mApnContext.setState(DctConstants.State.FAILED); + assertTrue(mApnContext.isDisconnected()); + mApnContext.setState(DctConstants.State.IDLE); + assertTrue(mApnContext.isDisconnected()); + } + + @Test + @SmallTest + public void testNetworkRequestNormal() throws Exception { + NetworkRequest nr1 = new NetworkRequest.Builder().build(); + mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, null); + + verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), + eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); + + NetworkRequest nr2 = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .build(); + + mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, null); + verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT), + eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); + + mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_NORMAL); + verify(mDcTracker, never()).disableApn(eq(ApnSetting.TYPE_DEFAULT), + eq(DcTracker.RELEASE_TYPE_NORMAL)); + + mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL); + verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), + eq(DcTracker.RELEASE_TYPE_NORMAL)); + } + + @Test + @SmallTest + public void testNetworkRequestDetach() throws Exception { + NetworkRequest nr1 = new NetworkRequest.Builder().build(); + mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, null); + verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), + eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); + + NetworkRequest nr2 = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .build(); + + mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, null); + verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT), + eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); + + mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_DETACH); + verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), + eq(DcTracker.RELEASE_TYPE_DETACH)); + + mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL); + verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), + eq(DcTracker.RELEASE_TYPE_NORMAL)); + } + + @Test + @SmallTest + public void testNetworkRequestHandover() throws Exception { + NetworkRequest nr1 = new NetworkRequest.Builder().build(); + mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_HANDOVER, null); + verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), + eq(DcTracker.REQUEST_TYPE_HANDOVER), eq(null)); + + mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_HANDOVER); + verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), + eq(DcTracker.RELEASE_TYPE_HANDOVER)); + } + + @Test + @SmallTest + public void testConcurrentVoiceAndDataAllowed() throws Exception { + mApnContext.setConcurrentVoiceAndDataAllowed(true); + assertTrue(mApnContext.isConcurrentVoiceAndDataAllowed()); + mApnContext.setConcurrentVoiceAndDataAllowed(false); + assertFalse(mApnContext.isConcurrentVoiceAndDataAllowed()); + } + + @Test + @SmallTest + public void testEnableDisable() throws Exception { + mApnContext.setEnabled(true); + assertTrue(mApnContext.isEnabled()); + mApnContext.setEnabled(false); + assertFalse(mApnContext.isEnabled()); + } + + @Test + @SmallTest + public void testProvisionApn() throws Exception { + mContextFixture.putResource(R.string.mobile_provisioning_apn, "fake_apn"); + + ApnSetting myApn = new ApnSetting.Builder() + .setId(2163) + .setOperatorNumeric("44010") + .setEntryName("sp-mode") + .setApnName("fake_apn") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) + .setProtocol(ApnSetting.PROTOCOL_IP) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .build(); + + mApnContext.setApnSetting(myApn); + assertTrue(mApnContext.isProvisioningApn()); + mApnContext.setApnSetting(mApnSetting); + assertFalse(mApnContext.isProvisioningApn()); + } + + @Test + @SmallTest + public void testIsReady() throws Exception { + mApnContext.setEnabled(true); + assertTrue(mApnContext.isReady()); + + mApnContext.setEnabled(false); + assertFalse(mApnContext.isReady()); + } + + @Test + @SmallTest + public void testErrorCodeRetry() throws Exception { + mContextFixture.putStringArrayResource( + com.android.internal.R.array.config_cell_retries_per_error_code, + new String[]{"36,2"}); + mApnContext.resetErrorCodeRetries(); + + assertFalse(mApnContext.restartOnError(36)); + assertTrue(mApnContext.restartOnError(36)); + assertFalse(mApnContext.restartOnError(37)); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java similarity index 62% rename from tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java rename to tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java index b6d77e952e..1812fa0770 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java @@ -14,20 +14,23 @@ * limitations under the License. */ -package com.android.internal.telephony.data; +package com.android.internal.telephony.dataconnection; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doReturn; import android.net.Uri; import android.os.Parcel; import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; +import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.TelephonyTest; @@ -115,7 +118,213 @@ public class ApnSettingTest extends TelephonyTest { } @Test + @SmallTest + public void testIsMetered() { + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + + doReturn(false).when(mServiceState).getDataRoaming(); + doReturn(1).when(mPhone).getSubId(); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_DEFAULT), mPhone)); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_MMS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_MMS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN), mPhone)); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_FOTA), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_IA | ApnSetting.TYPE_CBS), mPhone)); + + assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); + assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_SUPL, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_CBS, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DUN, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_IA, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_HIPRI, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_ENTERPRISE, mPhone)); + + // Carrier config settings changes. + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + + assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); + } + + @Test + @SmallTest + public void testIsRoamingMetered() { + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + doReturn(true).when(mServiceState).getDataRoaming(); + doReturn(1).when(mPhone).getSubId(); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_DEFAULT), mPhone)); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_MMS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_MMS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN), mPhone)); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_FOTA), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_IA | ApnSetting.TYPE_CBS), mPhone)); + + // Carrier config settings changes. + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_FOTA_STRING}); + + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); + assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_ENTERPRISE, mPhone)); + } + + @Test + @SmallTest + public void testIsMeteredAnother() { + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_CBS_STRING}); + + doReturn(false).when(mServiceState).getDataRoaming(); + doReturn(1).when(mPhone).getSubId(); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_CBS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_SUPL), mPhone)); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_CBS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_FOTA | ApnSetting.TYPE_CBS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_IA), mPhone)); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_IMS), mPhone)); + + assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); + assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_XCAP), mPhone)); + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_ENTERPRISE), mPhone)); + } + + @Test + @SmallTest + public void testIsRoamingMeteredAnother() { + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_CBS_STRING}); + doReturn(true).when(mServiceState).getDataRoaming(); + doReturn(2).when(mPhone).getSubId(); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_CBS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_SUPL), mPhone)); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_CBS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_FOTA | ApnSetting.TYPE_CBS), mPhone)); + + assertTrue(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_IA), mPhone)); + + assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_IMS), mPhone)); + + assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); + + assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_SUPL, mPhone)); + assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_CBS, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DUN, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_IA, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_HIPRI, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone)); + assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_ENTERPRISE, mPhone)); + } + + @Test + @SmallTest + public void testIsMeteredNothingCharged() { + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{}); + + doReturn(false).when(mServiceState).getDataRoaming(); + doReturn(3).when(mPhone).getSubId(); + + assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_IMS | ApnSetting.TYPE_MMS), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_FOTA), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_ALL), mPhone)); + } + + @Test + @SmallTest + public void testIsRoamingMeteredNothingCharged() { + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, + new String[]{}); + doReturn(true).when(mServiceState).getDataRoaming(); + doReturn(3).when(mPhone).getSubId(); + + assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_IMS | ApnSetting.TYPE_MMS), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_FOTA), mPhone)); + + assertFalse(ApnSettingUtils.isMetered( + createApnSetting(ApnSetting.TYPE_ALL), mPhone)); + } + + @Test + @SmallTest public void testCanHandleType() { + String types[] = {"mms"}; + assertTrue(createApnSetting(ApnSetting.TYPE_ALL) .canHandleType(ApnSetting.TYPE_MMS)); @@ -193,6 +402,7 @@ public class ApnSettingTest extends TelephonyTest { } @Test + @SmallTest public void testEquals() throws Exception { final int dummyInt = 1; final int dummyLong = 1; @@ -241,6 +451,7 @@ public class ApnSettingTest extends TelephonyTest { } @Test + @SmallTest public void testEqualsRoamingProtocol() { ApnSetting apn1 = new ApnSetting.Builder() .setId(1234) @@ -274,6 +485,7 @@ public class ApnSettingTest extends TelephonyTest { } @Test + @SmallTest public void testCanHandleNetwork() { ApnSetting apn1 = new ApnSetting.Builder() .setId(1234) diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java new file mode 100644 index 0000000000..dcaa2a0269 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java @@ -0,0 +1,1479 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.dataconnection; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; + +import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.net.InetAddresses; +import android.net.KeepalivePacketData; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.NattKeepalivePacketData; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.vcn.VcnNetworkPolicyResult; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; +import android.os.UserManager; +import android.provider.Telephony; +import android.telephony.AccessNetworkConstants; +import android.telephony.AccessNetworkConstants.AccessNetworkType; +import android.telephony.CarrierConfigManager; +import android.telephony.ServiceState; +import android.telephony.ServiceState.RegState; +import android.telephony.ServiceState.RilRadioTechnology; +import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; +import android.telephony.data.DataCallResponse; +import android.telephony.data.DataProfile; +import android.telephony.data.DataService; +import android.telephony.data.DataServiceCallback; +import android.telephony.data.TrafficDescriptor; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Pair; + +import com.android.internal.R; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.RetryManager; +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.data.KeepaliveStatus; +import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams; +import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams; +import com.android.internal.telephony.dataconnection.DataConnection.SetupResult; +import com.android.internal.telephony.metrics.DataCallSessionStats; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.function.Consumer; + +public class DataConnectionTest extends TelephonyTest { + private static final int DEFAULT_DC_CID = 10; + private static final ArrayList DEFAULT_TD_LIST = new ArrayList<>(); + + // Mocked classes + DcTesterFailBringUpAll mDcTesterFailBringUpAll; + ConnectionParams mCp; + DisconnectParams mDcp; + ApnContext mApnContext; + ApnContext mEnterpriseApnContext; + DcFailBringUp mDcFailBringUp; + DataCallSessionStats mDataCallSessionStats; + DataConnection mDefaultDc; + DataServiceManager mDataServiceManager; + + private DataConnection mDc; + private DataConnectionTestHandler mDataConnectionTestHandler; + private DcController mDcc; + + private final ApnSetting mApn1 = new ApnSetting.Builder() + .setId(2163) + .setOperatorNumeric("44010") + .setEntryName("sp-mode") + .setApnName("spmode.ne.jp") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) + .setProtocol(ApnSetting.PROTOCOL_IP) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .build(); + + private final ApnSetting mApn2 = new ApnSetting.Builder() + .setId(2164) + .setOperatorNumeric("44010") + .setEntryName("sp-mode") + .setApnName("spmode.ne.jp") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN) + .setProtocol(ApnSetting.PROTOCOL_IP) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .build(); + + private final ApnSetting mApn3 = new ApnSetting.Builder() + .setId(2165) + .setOperatorNumeric("44010") + .setEntryName("sp-mode") + .setApnName("spmode.ne.jp") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setNetworkTypeBitmask(0) + .setCarrierEnabled(true) + .setCarrierId(1) + .setSkip464Xlat(1) + .build(); + + private final ApnSetting mApn4 = new ApnSetting.Builder() + .setId(2166) + .setOperatorNumeric("44010") + .setEntryName("sp-mode") + .setApnName("spmode.ne.jp") + .setApnTypeBitmask(ApnSetting.TYPE_IMS) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .build(); + + private final ApnSetting mApn5 = new ApnSetting.Builder() + .setId(2167) + .setOperatorNumeric("44010") + .setEntryName("sp-mode") + .setApnName("spmode.ne.jp") + .setApnTypeBitmask(ApnSetting.TYPE_IMS) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .setSkip464Xlat(Telephony.Carriers.SKIP_464XLAT_DISABLE) + .build(); + + private final ApnSetting mApn6 = new ApnSetting.Builder() + .setId(2168) + .setOperatorNumeric("44010") + .setEntryName("sp-mode") + .setApnName("spmode.ne.jp") + .setApnTypeBitmask(ApnSetting.TYPE_EMERGENCY) + .setProtocol(ApnSetting.PROTOCOL_IP) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .build(); + + private class DataConnectionTestHandler extends HandlerThread { + + private DataConnectionTestHandler(String name) { + super(name); + } + + @Override + public void onLooperPrepared() { + Handler h = new Handler(); + mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, h.getLooper(), ""); + mDc = DataConnection.makeDataConnection(mPhone, 0, mDcTracker, mDataServiceManager, + mDcTesterFailBringUpAll, mDcc); + } + } + + private void setSuccessfulSetupDataResponse(int cid, ArrayList tds) { + doAnswer(invocation -> { + final Message msg = (Message) invocation.getArguments()[10]; + + DataCallResponse response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1L) + .setId(cid) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) + .setInterfaceName("ifname") + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress("10.0.2.15"), 32), + new LinkAddress("2607:fb90:a620:651d:eabe:f8da:c107:44be/64"))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), + InetAddresses.parseNumericAddress("fd00:976a::9"))) + .setGatewayAddresses(Arrays.asList( + InetAddresses.parseNumericAddress("10.0.2.15"), + InetAddresses.parseNumericAddress("fe80::2"))) + .setPcscfAddresses(Arrays.asList( + InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), + InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), + InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) + .setMtu(1500) + .setMtuV4(1500) + .setMtuV6(1500) + .setPduSessionId(1) + .setQosBearerSessions(new ArrayList<>()) + .setTrafficDescriptors(tds) + .build(); + msg.getData().putParcelable("data_call_response", response); + msg.arg1 = DataServiceCallback.RESULT_SUCCESS; + msg.sendToTarget(); + return null; + }).when(mDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), + anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), + any(Message.class)); + } + + private void setFailedSetupDataResponse(@DataServiceCallback.ResultCode int resultCode) { + doAnswer(invocation -> { + final Message msg = (Message) invocation.getArguments()[10]; + msg.arg1 = resultCode; + msg.sendToTarget(); + return null; + }).when(mDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), + anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), + any(Message.class)); + } + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + mDcTesterFailBringUpAll = mock(DcTesterFailBringUpAll.class); + mCp = mock(ConnectionParams.class); + mDcp = mock(DisconnectParams.class); + mApnContext = mock(ApnContext.class); + mEnterpriseApnContext = mock(ApnContext.class); + mDcFailBringUp = mock(DcFailBringUp.class); + mDataCallSessionStats = mock(DataCallSessionStats.class); + mDefaultDc = mock(DataConnection.class); + mDataServiceManager = mock(DataServiceManager.class); + logd("+Setup!"); + doReturn("fake.action_detached").when(mPhone).getActionDetached(); + doReturn(false).when(mPhone).isUsingNewDataStack(); + replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext); + replaceInstance(ConnectionParams.class, "mRilRat", mCp, + ServiceState.RIL_RADIO_TECHNOLOGY_UMTS); + doReturn(mApn1).when(mApnContext).getApnSetting(); + doReturn(ApnSetting.TYPE_DEFAULT_STRING).when(mApnContext).getApnType(); + doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); + + mDcFailBringUp.saveParameters(0, 0, -2); + doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp(); + + mContextFixture.putStringArrayResource(com.android.internal.R.array + .config_mobile_tcp_buffers, new String[]{ + "umts:131072,262144,1452032,4096,16384,399360", + "hspa:131072,262144,2441216,4096,16384,399360", + "hsupa:131072,262144,2441216,4096,16384,399360", + "hsdpa:131072,262144,2441216,4096,16384,399360", + "hspap:131072,262144,2441216,4096,16384,399360", + "edge:16384,32768,131072,4096,16384,65536", + "gprs:4096,8192,24576,4096,8192,24576", + "1xrtt:16384,32768,131070,4096,16384,102400", + "evdo:131072,262144,1048576,4096,16384,524288", + "lte:524288,1048576,8388608,262144,524288,4194304"}); + + mContextFixture.putResource(R.string.config_wwan_data_service_package, + "com.android.phone"); + + mDcp.mApnContext = mApnContext; + + setSuccessfulSetupDataResponse(DEFAULT_DC_CID, DEFAULT_TD_LIST); + + doAnswer(invocation -> { + final Message msg = (Message) invocation.getArguments()[2]; + msg.arg1 = DataServiceCallback.RESULT_SUCCESS; + msg.sendToTarget(); + return null; + }).when(mDataServiceManager).deactivateDataCall(anyInt(), anyInt(), any(Message.class)); + + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mDataServiceManager) + .getTransportType(); + + mDataConnectionTestHandler = new DataConnectionTestHandler(getClass().getSimpleName()); + mDataConnectionTestHandler.start(); + + waitForMs(200); + mDc.setDataCallSessionStats(mDataCallSessionStats); + + logd("-Setup!"); + } + + @After + public void tearDown() throws Exception { + logd("tearDown"); + mDc.quitNow(); + mDc = null; + mDataConnectionTestHandler.quit(); + mDataConnectionTestHandler.join(); + mDataConnectionTestHandler = null; + mDcc.removeCallbacksAndMessages(null); + mDcc = null; + DEFAULT_TD_LIST.clear(); + waitForMs(100); + super.tearDown(); + } + + private long getSuggestedRetryDelay(DataCallResponse response) throws Exception { + Class[] cArgs = new Class[1]; + cArgs[0] = DataCallResponse.class; + Method method = DataConnection.class.getDeclaredMethod("getSuggestedRetryDelay", cArgs); + method.setAccessible(true); + return (long) method.invoke(mDc, response); + } + + private boolean isUnmeteredUseOnly() throws Exception { + Method method = DataConnection.class.getDeclaredMethod("isUnmeteredUseOnly"); + method.setAccessible(true); + return (boolean) method.invoke(mDc); + } + + private boolean isEnterpriseUse() throws Exception { + Method method = DataConnection.class.getDeclaredMethod("isEnterpriseUse"); + method.setAccessible(true); + return (boolean) method.invoke(mDc); + } + + private boolean isSuspended() throws Exception { + Field field = DataConnection.class.getDeclaredField("mIsSuspended"); + field.setAccessible(true); + return field.getBoolean(mDc); + } + + private SetupResult setLinkProperties(DataCallResponse response, LinkProperties linkProperties) + throws Exception { + Class[] cArgs = new Class[2]; + cArgs[0] = DataCallResponse.class; + cArgs[1] = LinkProperties.class; + Method method = DataConnection.class.getDeclaredMethod("setLinkProperties", cArgs); + method.setAccessible(true); + return (SetupResult) method.invoke(mDc, response, linkProperties); + } + + @Test + @SmallTest + public void testConnectEvent() { + assertTrue(mDc.isInactive()); + connectEvent(true); + + verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class), + eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null)); + verify(mCT, times(1)).registerForVoiceCallEnded(any(Handler.class), + eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED), eq(null)); + verify(mSimulatedCommandsVerifier, times(1)) + .registerForNattKeepaliveStatus(any(Handler.class), + eq(DataConnection.EVENT_KEEPALIVE_STATUS), eq(null)); + verify(mSimulatedCommandsVerifier, times(1)) + .registerForLceInfo(any(Handler.class), + eq(DataConnection.EVENT_LINK_CAPACITY_CHANGED), eq(null)); + verify(mVcnManager, atLeastOnce()) + .applyVcnNetworkPolicy( + argThat(caps -> + caps.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)), + any()); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + ArgumentCaptor tdCaptor = + ArgumentCaptor.forClass(TrafficDescriptor.class); + verify(mDataServiceManager, times(1)).setupDataCall( + eq(AccessNetworkType.UTRAN), dpCaptor.capture(), eq(false), + eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), tdCaptor.capture(), anyBoolean(), any(Message.class)); + + verify(mSimulatedCommandsVerifier, times(0)) + .allocatePduSessionId(any()); + + assertEquals("spmode.ne.jp", dpCaptor.getValue().getApn()); + if (tdCaptor.getValue() != null) { + if (mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { + assertEquals(null, tdCaptor.getValue().getDataNetworkName()); + assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), + tdCaptor.getValue().getOsAppId())); + } else { + assertEquals("spmode.ne.jp", tdCaptor.getValue().getDataNetworkName()); + assertEquals(null, tdCaptor.getValue().getOsAppId()); + } + } + assertTrue(mDc.isActive()); + + assertEquals(1, mDc.getPduSessionId()); + assertEquals(3, mDc.getPcscfAddresses().length); + assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::8"::equals)); + assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c202:1d::7"::equals)); + assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::5"::equals)); + } + + @Test + @SmallTest + public void testConnectOnIwlan() throws Exception { + assertTrue(mDc.isInactive()); + Field field = DataConnection.class.getDeclaredField("mTransportType"); + field.setAccessible(true); + field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + connectEvent(true); + + verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class), + eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null)); + verify(mCT, times(1)).registerForVoiceCallEnded(any(Handler.class), + eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED), eq(null)); + verify(mSimulatedCommandsVerifier, times(0)) + .registerForNattKeepaliveStatus(any(Handler.class), + eq(DataConnection.EVENT_KEEPALIVE_STATUS), eq(null)); + verify(mSimulatedCommandsVerifier, times(0)) + .registerForLceInfo(any(Handler.class), + eq(DataConnection.EVENT_LINK_CAPACITY_CHANGED), eq(null)); + verify(mVcnManager, atLeastOnce()) + .applyVcnNetworkPolicy( + argThat(caps -> + caps.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)), + any()); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + ArgumentCaptor tdCaptor = + ArgumentCaptor.forClass(TrafficDescriptor.class); + verify(mDataServiceManager, times(1)).setupDataCall( + eq(AccessNetworkType.UTRAN), dpCaptor.capture(), eq(false), + eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), tdCaptor.capture(), anyBoolean(), any(Message.class)); + + verify(mSimulatedCommandsVerifier, times(1)) + .allocatePduSessionId(any()); + + assertEquals("spmode.ne.jp", dpCaptor.getValue().getApn()); + if (tdCaptor.getValue() != null) { + if (mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { + assertEquals(null, tdCaptor.getValue().getDataNetworkName()); + assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), + tdCaptor.getValue().getOsAppId())); + } else { + assertEquals("spmode.ne.jp", tdCaptor.getValue().getDataNetworkName()); + assertEquals(null, tdCaptor.getValue().getOsAppId()); + } + } + assertTrue(mDc.isActive()); + + assertEquals(1, mDc.getPduSessionId()); + assertEquals(3, mDc.getPcscfAddresses().length); + assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::8"::equals)); + assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c202:1d::7"::equals)); + assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::5"::equals)); + } + + @Test + public void testConnectEventDuplicateContextIds() throws Exception { + setUpDefaultData(DEFAULT_DC_CID); + + // Try to connect ENTERPRISE with the same CID as default + replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); + doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); + doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); + doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); + + // Verify that ENTERPRISE wasn't set up + connectEvent(false); + assertTrue(mDc.isInactive()); + + // Change the CID + setSuccessfulSetupDataResponse(DEFAULT_DC_CID + 1, DEFAULT_TD_LIST); + + // Verify that ENTERPRISE was set up + connectEvent(true); + assertTrue(mDc.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); + } + + @Test + public void testConnectEventDuplicateContextIdsDifferentTDs() throws Exception { + setUpDefaultData(DEFAULT_DC_CID); + + // Try to connect ENTERPRISE with the same CID as default but different TrafficDescriptors + replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); + doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); + doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); + doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); + ArrayList tdList = new ArrayList<>(); + tdList.add(new TrafficDescriptor("dnn", DataConnection.getEnterpriseOsAppId())); + setSuccessfulSetupDataResponse(DEFAULT_DC_CID, tdList); + + // Verify that ENTERPRISE wasn't set up but the TD list was updated + connectEvent(false); + assertTrue(mDc.isInactive()); + ArgumentCaptor captor = ArgumentCaptor.forClass(DataCallResponse.class); + verify(mDefaultDc).updateTrafficDescriptors(captor.capture()); + assertEquals(tdList, captor.getValue().getTrafficDescriptors()); + } + + @Test + public void testConnectEventNoDefaultData() throws Exception { + assertFalse(mDefaultDc.isActive()); + + // Try to connect ENTERPRISE when default data doesn't exist + replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); + doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); + doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); + doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); + + // Verify that ENTERPRISE wasn't set up + connectEvent(false); + assertTrue(mDc.isInactive()); + + // Set up default data + replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext); + setUpDefaultData(1); + + // Verify that ENTERPRISE was set up + replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); + connectEvent(true); + assertTrue(mDc.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); + } + + private void setUpDefaultData(int cid) throws Exception { + replaceInstance(DataConnection.class, "mCid", mDefaultDc, cid); + doReturn(true).when(mDefaultDc).isActive(); + doReturn(Arrays.asList(mApnContext)).when(mDefaultDc).getApnContexts(); + mDcc.addActiveDcByCid(mDefaultDc); + assertTrue(mDefaultDc.getApnContexts().stream() + .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT)); + } + + @Test + @SmallTest + public void testDisconnectEvent() { + testConnectEvent(); + + mDc.setPduSessionId(5); + disconnectEvent(); + + verify(mSimulatedCommandsVerifier, times(1)).unregisterForLceInfo(any(Handler.class)); + verify(mSimulatedCommandsVerifier, times(1)) + .unregisterForNattKeepaliveStatus(any(Handler.class)); + verify(mDataServiceManager, times(1)).deactivateDataCall(eq(DEFAULT_DC_CID), + eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); + verify(mSimulatedCommandsVerifier, times(0)) + .releasePduSessionId(any(), eq(5)); + + assertTrue(mDc.isInactive()); + } + + @Test + @SmallTest + public void testDisconnectOnIwlan() throws Exception { + testConnectEvent(); + + Field field = DataConnection.class.getDeclaredField("mTransportType"); + field.setAccessible(true); + field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + mDc.setPduSessionId(5); + disconnectEvent(); + + verify(mSimulatedCommandsVerifier, times(0)).unregisterForLceInfo(any(Handler.class)); + verify(mSimulatedCommandsVerifier, times(0)) + .unregisterForNattKeepaliveStatus(any(Handler.class)); + verify(mDataServiceManager, times(1)).deactivateDataCall(eq(DEFAULT_DC_CID), + eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); + verify(mSimulatedCommandsVerifier, times(1)) + .releasePduSessionId(any(), eq(5)); + + assertTrue(mDc.isInactive()); + } + + @Test + @SmallTest + public void testModemSuggestRetry() throws Exception { + DataCallResponse response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(0) + .setId(1) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response)); + + response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(1000) + .setId(1) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response)); + + response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(9999) + .setId(1) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response)); + } + + @Test + @SmallTest + public void testModemNotSuggestRetry() throws Exception { + DataCallResponse response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1) + .setId(1) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response)); + + response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-5) + .setId(1) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response)); + + response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(Long.MIN_VALUE) + .setId(1) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response)); + } + + @Test + @SmallTest + public void testModemSuggestNoRetry() throws Exception { + DataCallResponse response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(Long.MAX_VALUE) + .setId(1) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + assertEquals(RetryManager.NO_RETRY, getSuggestedRetryDelay(response)); + } + + private NetworkCapabilities getNetworkCapabilities() throws Exception { + Method method = DataConnection.class.getDeclaredMethod("getNetworkCapabilities"); + method.setAccessible(true); + return (NetworkCapabilities) method.invoke(mDc); + } + + private int getDisallowedApnTypes() throws Exception { + Method method = DataConnection.class.getDeclaredMethod("getDisallowedApnTypes"); + method.setAccessible(true); + return (int) method.invoke(mDc); + } + + @Test + @SmallTest + public void testNetworkCapability() throws Exception { + mContextFixture.getCarrierConfigBundle().putStringArray( + CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] { "default" }); + doReturn(mApn2).when(mApnContext).getApnSetting(); + testConnectEvent(); + + assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); + assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); + + mContextFixture.getCarrierConfigBundle().putStringArray( + CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY, + new String[] {"supl"}); + + disconnectEvent(); + doReturn(mApn1).when(mApnContext).getApnSetting(); + connectEvent(true); + + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); + assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)); + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); + } + + @Test + @SmallTest + public void testVcnNetworkCapability() throws Exception { + mContextFixture.getCarrierConfigBundle().putStringArray( + CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] { "default" }); + doReturn(mApn2).when(mApnContext).getApnSetting(); + + doAnswer(invocation -> { + NetworkCapabilities nc = invocation.getArgument(0); + NetworkCapabilities policyNc = new NetworkCapabilities.Builder(nc) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .build(); + + return new VcnNetworkPolicyResult( + false /* isTearDownRequested */, policyNc); + }).when(mVcnManager).applyVcnNetworkPolicy(any(), any()); + connectEvent(true); + + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)); + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)); + + disconnectEvent(); + + doAnswer(invocation -> { + NetworkCapabilities nc = invocation.getArgument(0); + NetworkCapabilities policyNc = new NetworkCapabilities.Builder(nc) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .build(); + + return new VcnNetworkPolicyResult( + false /* isTearDownRequested */, policyNc); + }).when(mVcnManager).applyVcnNetworkPolicy(any(), any()); + connectEvent(true); + + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)); + assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)); + } + + @Test + @SmallTest + public void testEnterpriseNetworkCapability() throws Exception { + mContextFixture.getCarrierConfigBundle().putStringArray( + CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] { "default" }); + doReturn(mApn2).when(mApnContext).getApnSetting(); + testConnectEvent(); + + assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); + assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); + + disconnectEvent(); + setUpDefaultData(1); + replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); + doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); + doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); + doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); + connectEvent(true); + + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); + assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)); + assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); + } + + @Test + @SmallTest + public void testMeteredCapability() throws Exception { + + mContextFixture.getCarrierConfigBundle(). + putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] {"default"}); + + testConnectEvent(); + + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); + } + + @Test + @SmallTest + public void testNonMeteredCapability() throws Exception { + + doReturn(2819).when(mPhone).getSubId(); + mContextFixture.getCarrierConfigBundle(). + putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] {"mms"}); + + testConnectEvent(); + + assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); + } + + @Test + public void testOverrideUnmetered() throws Exception { + mContextFixture.getCarrierConfigBundle().putStringArray( + CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] { "default" }); + testConnectEvent(); + + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); + + mDc.onMeterednessChanged(true); + waitForMs(100); + + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); + assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); + + mDc.onMeterednessChanged(false); + waitForMs(100); + + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); + } + + @Test + public void testOverrideCongested() throws Exception { + mContextFixture.getCarrierConfigBundle().putStringArray( + CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] { "default" }); + testConnectEvent(); + + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); + + mDc.onCongestednessChanged(true); + waitForMs(100); + + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); + + mDc.onCongestednessChanged(false); + waitForMs(100); + + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); + assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); + assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); + } + + @Test + public void testOwnerUid() throws Exception { + Context mockContext = mContextFixture.getTestDouble(); + doReturn(mockContext).when(mPhone).getContext(); + + String testPkg = "com.android.telephony.test"; + TelephonyManager telMgr = mockContext.getSystemService(TelephonyManager.class); + doReturn(testPkg).when(telMgr).getCarrierServicePackageNameForLogicalSlot(anyInt()); + + UserInfo info = new UserInfo(0 /* id */, "TEST_USER", 0 /* flags */); + UserManager userMgr = mockContext.getSystemService(UserManager.class); + doReturn(Collections.singletonList(info)).when(userMgr).getUsers(); + + int carrierConfigPkgUid = 12345; + PackageManager pkgMgr = mockContext.getPackageManager(); + doReturn(carrierConfigPkgUid).when(pkgMgr).getPackageUidAsUser(eq(testPkg), anyInt()); + + mContextFixture + .getCarrierConfigBundle() + .putStringArray( + CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] {"default"}); + testConnectEvent(); + AsyncResult adminUidsResult = new AsyncResult(null, new int[] {carrierConfigPkgUid}, null); + mDc.sendMessage(DataConnection.EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED, adminUidsResult); + // Wait for carirer privilege UIDs to be updated + waitForMs(100); + + assertEquals(carrierConfigPkgUid, getNetworkCapabilities().getOwnerUid()); + assertEquals( + Collections.singleton(carrierConfigPkgUid), + getNetworkCapabilities().getAllowedUids()); + } + + @Test + public void testSubscriptionIds() throws Exception { + mContextFixture.getCarrierConfigBundle().putStringArray( + CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] { "default" }); + testConnectEvent(); + + assertEquals(Collections.singleton(0), getNetworkCapabilities().getSubscriptionIds()); + } + + @Test + public void testShouldSkip464Xlat() throws Exception { + assertFalse(testShouldSkip464XlatEvent(mApn1)); + disconnectEvent(); + + assertTrue(testShouldSkip464XlatEvent(mApn3)); + disconnectEvent(); + + assertTrue(testShouldSkip464XlatEvent(mApn4)); + disconnectEvent(); + + assertFalse(testShouldSkip464XlatEvent(mApn5)); + disconnectEvent(); + } + + private boolean testShouldSkip464XlatEvent(ApnSetting apn) throws Exception { + Method method = DataConnection.class.getDeclaredMethod("shouldSkip464Xlat"); + method.setAccessible(true); + + doReturn(apn).when(mApnContext).getApnSetting(); + doReturn(apn.getApnTypeBitmask()).when(mApnContext).getApnTypeBitmask(); + connectEvent(true); + logd(getNetworkCapabilities().toString()); + + return (Boolean) method.invoke(mDc); + } + + private void connectEvent(boolean validate) { + mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp); + waitForMs(200); + if (validate) { + assertTrue(mDc.isActive()); + } + } + + private void disconnectEvent() { + mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp); + waitForMs(100); + assertTrue(mDc.isInactive()); + } + + private void serviceStateChangedEvent(@RegState int dataRegState, @RilRadioTechnology int rat) { + mDc.obtainMessage(DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, + new AsyncResult(null, new Pair<>(dataRegState, rat), null)).sendToTarget(); + waitForMs(100); + } + + @Test + @SmallTest + public void testIsIpAddress() { + // IPv4 + assertTrue(DataConnection.isIpAddress("1.2.3.4")); + assertTrue(DataConnection.isIpAddress("127.0.0.1")); + + // IPv6 + assertTrue(DataConnection.isIpAddress("::1")); + assertTrue(DataConnection.isIpAddress("2001:4860:800d::68")); + } + + @Test + @SmallTest + public void testSetLinkProperties() throws Exception { + DataCallResponse response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1) + .setId(1) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + + LinkProperties linkProperties = new LinkProperties(); + assertEquals(SetupResult.SUCCESS, setLinkProperties(response, linkProperties)); + logd(linkProperties.toString()); + assertEquals(response.getInterfaceName(), linkProperties.getInterfaceName()); + assertEquals(response.getAddresses().size(), linkProperties.getAddresses().size()); + for (int i = 0; i < response.getAddresses().size(); ++i) { + assertEquals(response.getAddresses().get(i).getAddress(), + InetAddresses.parseNumericAddress(linkProperties.getLinkAddresses().get(i) + .getAddress().getHostAddress())); + } + + assertEquals(response.getDnsAddresses().size(), linkProperties.getDnsServers().size()); + for (int i = 0; i < response.getDnsAddresses().size(); ++i) { + assertEquals("i = " + i, response.getDnsAddresses().get(i), + InetAddresses.parseNumericAddress( + linkProperties.getDnsServers().get(i).getHostAddress())); + } + + assertEquals(response.getGatewayAddresses().size(), linkProperties.getRoutes().size()); + for (int i = 0; i < response.getGatewayAddresses().size(); ++i) { + assertEquals("i = " + i, response.getGatewayAddresses().get(i), + InetAddresses.parseNumericAddress(linkProperties.getRoutes().get(i) + .getGateway().getHostAddress())); + } + + assertEquals(response.getPcscfAddresses().size(), linkProperties.getPcscfServers().size()); + for (int i = 0; i < response.getPcscfAddresses().size(); ++i) { + assertEquals("i = " + i, response.getPcscfAddresses().get(i), + InetAddresses.parseNumericAddress(linkProperties.getPcscfServers().get(i) + .getHostAddress())); + } + + assertEquals(response.getMtu(), linkProperties.getMtu()); + } + + @Test + @SmallTest + public void testSetLinkPropertiesEmptyAddress() throws Exception { + // 224.224.224.224 is an invalid address. + DataCallResponse response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1) + .setId(1) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + + LinkProperties linkProperties = new LinkProperties(); + assertEquals(SetupResult.ERROR_INVALID_ARG, setLinkProperties(response, linkProperties)); + } + + @Test + @SmallTest + public void testSetLinkPropertiesEmptyDns() throws Exception { + // Empty dns entry. + DataCallResponse response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1) + .setId(1) + .setLinkStatus(2) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + + // Make sure no exception was thrown + LinkProperties linkProperties = new LinkProperties(); + assertEquals(SetupResult.SUCCESS, setLinkProperties(response, linkProperties)); + } + + @Test + @SmallTest + public void testStartKeepaliveWLAN() throws Exception { + testConnectEvent(); + waitForMs(200); + + Field field = DataConnection.class.getDeclaredField("mTransportType"); + field.setAccessible(true); + field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + + final int sessionHandle = 0xF00; + final int slotId = 3; + final int interval = 10; // seconds + // Construct a new KeepalivePacketData request as we would receive from a Network Agent, + // and check that the packet is sent to the RIL. + KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket( + InetAddresses.parseNumericAddress("1.2.3.4"), + 1234, + InetAddresses.parseNumericAddress("8.8.8.8"), + 4500); + mDc.obtainMessage( + DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget(); + waitForMs(100); + // testStartStopNattKeepalive() verifies that this request is passed with WWAN. + // Thus, even though we can't see the response in NetworkAgent, we can verify that the + // CommandsInterface never receives a request and infer that it was dropped due to WLAN. + verify(mSimulatedCommandsVerifier, times(0)) + .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class)); + } + + public void checkStartStopNattKeepalive(boolean useCondensedFlow) throws Exception { + testConnectEvent(); + waitForMs(200); + + final int sessionHandle = 0xF00; + final int slotId = 3; + final int interval = 10; // seconds + // Construct a new KeepalivePacketData request as we would receive from a Network Agent, + // and check that the packet is sent to the RIL. + KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket( + InetAddresses.parseNumericAddress("1.2.3.4"), + 1234, + InetAddresses.parseNumericAddress("8.8.8.8"), + 4500); + mDc.obtainMessage( + DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget(); + waitForMs(100); + verify(mSimulatedCommandsVerifier, times(1)) + .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class)); + + Message kaStarted = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STARTED, slotId, 0); + if (useCondensedFlow) { + // Send a singled condensed response that a keepalive have been requested and the + // activation is completed. This flow should be used if the keepalive offload request + // is handled by a high-priority signalling path. + AsyncResult.forMessage( + kaStarted, new KeepaliveStatus( + sessionHandle, KeepaliveStatus.STATUS_ACTIVE), null); + kaStarted.sendToTarget(); + } else { + // Send the sequential responses indicating first that the request was received and + // then that the keepalive is running. This should create an active record of the + // keepalive in DataConnection while permitting the status from a low priority or other + // high-latency handler to activate the keepalive without blocking a request. + AsyncResult.forMessage( + kaStarted, new KeepaliveStatus( + sessionHandle, KeepaliveStatus.STATUS_PENDING), null); + kaStarted.sendToTarget(); + Message kaRunning = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STATUS); + AsyncResult.forMessage( + kaRunning, new KeepaliveStatus( + sessionHandle, KeepaliveStatus.STATUS_ACTIVE), null); + kaRunning.sendToTarget(); + } + waitForMs(100); + + // Verify that we can stop the connection, which checks that the record in DataConnection + // has a valid mapping between slotId (from network agent) to sessionHandle (from Radio). + mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget(); + waitForMs(100); + verify(mSimulatedCommandsVerifier, times(1)) + .stopNattKeepalive(eq(sessionHandle), any(Message.class)); + + Message kaStopped = mDc.obtainMessage( + DataConnection.EVENT_KEEPALIVE_STOPPED, sessionHandle, slotId); + AsyncResult.forMessage(kaStopped); + kaStopped.sendToTarget(); + // Verify that after the connection is stopped, the mapping for a Keepalive Session is + // removed. Thus, subsequent calls to stop the same keepalive are ignored. + mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget(); + waitForMs(100); + // Check that the mock has not been called subsequent to the previous invocation + // while avoiding the use of reset() + verify(mSimulatedCommandsVerifier, times(1)) + .stopNattKeepalive(anyInt(), any(Message.class)); + } + + @Test + @MediumTest + public void testStartStopNattKeepalive() throws Exception { + checkStartStopNattKeepalive(false); + } + + @Test + @MediumTest + public void testStartStopNattKeepaliveCondensed() throws Exception { + checkStartStopNattKeepalive(true); + } + + public void checkStartNattKeepaliveFail(boolean useCondensedFlow) throws Exception { + testConnectEvent(); + waitForMs(200); + + final int sessionHandle = 0xF00; + final int slotId = 3; + final int interval = 10; // seconds + // Construct a new KeepalivePacketData request as we would receive from a Network Agent, + // and check that the packet is sent to the RIL. + KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket( + InetAddresses.parseNumericAddress("1.2.3.4"), + 1234, + InetAddresses.parseNumericAddress("8.8.8.8"), + 4500); + mDc.obtainMessage( + DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget(); + waitForMs(100); + verify(mSimulatedCommandsVerifier, times(1)) + .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class)); + + Message kaStarted = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STARTED, slotId, 0); + if (useCondensedFlow) { + // Indicate in the response that the keepalive has failed. + AsyncResult.forMessage( + kaStarted, new KeepaliveStatus(KeepaliveStatus.ERROR_UNSUPPORTED), + null); + kaStarted.sendToTarget(); + } else { + // Indicate that the keepalive is queued, and then signal a failure from the modem + // such that a pending keepalive fails to activate. + AsyncResult.forMessage( + kaStarted, new KeepaliveStatus( + sessionHandle, KeepaliveStatus.STATUS_PENDING), null); + kaStarted.sendToTarget(); + Message kaRunning = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STATUS); + AsyncResult.forMessage( + kaRunning, new KeepaliveStatus( + sessionHandle, KeepaliveStatus.STATUS_INACTIVE), null); + kaRunning.sendToTarget(); + } + waitForMs(100); + // Verify that a failed connection request cannot be stopped due to no record in + // the DataConnection. + mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget(); + waitForMs(100); + verify(mSimulatedCommandsVerifier, times(0)) + .stopNattKeepalive(anyInt(), any(Message.class)); + } + + @Test + @SmallTest + public void testStartNattKeepaliveFail() throws Exception { + checkStartNattKeepaliveFail(false); + } + + @Test + @SmallTest + public void testStartNattKeepaliveFailCondensed() throws Exception { + checkStartNattKeepaliveFail(true); + } + + @Test + @SmallTest + public void testIsUnmeteredUseOnly() throws Exception { + Field field = DataConnection.class.getDeclaredField("mTransportType"); + field.setAccessible(true); + field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + + assertFalse(isUnmeteredUseOnly()); + + field = DataConnection.class.getDeclaredField("mTransportType"); + field.setAccessible(true); + field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + + doReturn(false).when(mDataEnabledSettings).isDataEnabled(); + doReturn(false).when(mServiceState).getDataRoaming(); + doReturn(ApnSetting.TYPE_MMS).when(mApnContext).getApnTypeBitmask(); + + mContextFixture.getCarrierConfigBundle().putStringArray( + CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[] { "default" }); + + assertTrue(isUnmeteredUseOnly()); + } + + @Test + public void testIsEnterpriseUse() throws Exception { + assertFalse(isEnterpriseUse()); + assertFalse(mDc.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); + + setUpDefaultData(1); + replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); + doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); + doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); + doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); + connectEvent(true); + + assertTrue(isEnterpriseUse()); + assertTrue(mDc.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); + } + + @Test + @SmallTest + public void testGetDisallowedApnTypes() throws Exception { + mContextFixture.getCarrierConfigBundle().putStringArray( + CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY, + new String[] { "mms", "supl", "fota" }); + testConnectEvent(); + + assertEquals(ApnSetting.TYPE_MMS | ApnSetting.TYPE_SUPL | ApnSetting.TYPE_FOTA, + getDisallowedApnTypes()); + } + + @Test + public void testIsSuspended() throws Exception { + // Return false if not active state + assertTrue(mDc.isInactive()); + assertFalse(isSuspended()); + + // Return false for emergency APN + doReturn(mApn6).when(mApnContext).getApnSetting(); + doReturn(ApnSetting.TYPE_EMERGENCY).when(mApnContext).getApnTypeBitmask(); + connectEvent(true); + assertFalse(isSuspended()); + + // Back to DEFAULT APN + disconnectEvent(); + assertTrue(mDc.isInactive()); + doReturn(mApn1).when(mApnContext).getApnSetting(); + doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); + doReturn(true).when(mSST).isConcurrentVoiceAndDataAllowed(); + connectEvent(true); + + // Before getting any service state event, the connection should not be suspended. + assertFalse(isSuspended()); + + // Return true if combined reg state is not in service + serviceStateChangedEvent(ServiceState.STATE_OUT_OF_SERVICE, + ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN); + assertTrue(isSuspended()); + + // Return false if in service and concurrent voice and data is allowed + serviceStateChangedEvent(ServiceState.STATE_IN_SERVICE, + ServiceState.RIL_RADIO_TECHNOLOGY_LTE); + assertFalse(isSuspended()); + + // Return false if in service and concurrent voice/data not allowed but call state is idle + doReturn(false).when(mSST).isConcurrentVoiceAndDataAllowed(); + doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); + mDc.sendMessage(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED); + waitForMs(100); + assertFalse(isSuspended()); + + // Return true if in service, concurrent voice/data not allowed, and call state not idle + doReturn(PhoneConstants.State.RINGING).when(mCT).getState(); + mDc.sendMessage(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED); + waitForMs(100); + assertTrue(isSuspended()); + } + + @Test + public void testDataCreatedWhenOutOfService() throws Exception { + serviceStateChangedEvent(ServiceState.STATE_OUT_OF_SERVICE, + ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN); + ArgumentCaptor ncCaptor = + ArgumentCaptor.forClass(NetworkCapabilities.class); + doReturn(mock(Network.class)).when(mConnectivityManager).registerNetworkAgent( + any(), any(), any(), ncCaptor.capture(), any(), any(), anyInt()); + + doReturn(mApn1).when(mApnContext).getApnSetting(); + doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); + doReturn(true).when(mSST).isConcurrentVoiceAndDataAllowed(); + connectEvent(true); + waitForMs(100); + + NetworkCapabilities nc = ncCaptor.getValue(); + // The network must be created with NOT_SUSPENDED capability. + assertTrue(nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)); + + // But it's final state must be suspended. + assertTrue(isSuspended()); + } + + @Test + public void testDataServiceTempUnavailable() throws Exception { + setFailedSetupDataResponse(DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE); + replaceInstance(ConnectionParams.class, "mRequestType", mCp, + DcTracker.REQUEST_TYPE_NORMAL); + // Verify that no data was setup + connectEvent(false); + assertTrue(mDc.isInactive()); + + // Verify that data service did not suggest any retry (i.e. Frameworks uses configured + // retry timer). + verify(mDataThrottler).setRetryTime(eq(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL), + eq(RetryManager.NO_SUGGESTED_RETRY_DELAY), eq(DcTracker.REQUEST_TYPE_NORMAL)); + } + + @Test + public void testDataHandoverFailed() throws Exception { + doReturn(mDefaultDc).when(mDcTracker).getDataConnectionByApnType(anyString()); + + doAnswer(invocation -> { + final Consumer consumer = (Consumer) invocation.getArguments()[0]; + consumer.accept(DataServiceCallback.RESULT_SUCCESS); + return null; + }).when(mDefaultDc).startHandover(any(Consumer.class)); + + replaceInstance(ConnectionParams.class, "mRequestType", mCp, + DcTracker.REQUEST_TYPE_HANDOVER); + assertTrue(mDc.isInactive()); + connectEvent(false); + + // Make sure the data connection is still in inactive state + assertTrue(mDc.isInactive()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java new file mode 100644 index 0000000000..ffe4542b75 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.dataconnection; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.os.HandlerThread; +import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import java.util.Objects; + +public class DataEnabledSettingsTest extends TelephonyTest { + + private DataEnabledSettings mDataEnabledSettingsUT; + + private DataEnabledSettingsTestHandler mDataEnabledSettingsTestHandler; + + private String mRules = ""; + + private class DataEnabledSettingsTestHandler extends HandlerThread { + + private DataEnabledSettingsTestHandler(String name) { + super(name); + } + + @Override + public void onLooperPrepared() { + mDataEnabledSettingsUT = new DataEnabledSettings(mPhone); + setReady(true); + } + } + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + doReturn(false).when(mPhone).isUsingNewDataStack(); + doReturn(mRules).when(mSubscriptionController).getDataEnabledOverrideRules(anyInt()); + + doAnswer(invocation -> { + String rules = (String) invocation.getArguments()[1]; + boolean changed = !Objects.equals(mRules, rules); + mRules = rules; + return changed; + }).when(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), anyString()); + + mDataEnabledSettingsTestHandler = new DataEnabledSettingsTestHandler( + getClass().getSimpleName()); + mDataEnabledSettingsTestHandler.start(); + waitUntilReady(); + } + + @After + public void tearDown() throws Exception { + mDataEnabledSettingsTestHandler.quit(); + mDataEnabledSettingsTestHandler.join(); + mDataEnabledSettingsTestHandler = null; + mDataEnabledSettingsUT = null; + super.tearDown(); + } + + @Test + @SmallTest + public void testSetDataAllowedInVoiceCall() throws Exception { + mDataEnabledSettingsUT.setAllowDataDuringVoiceCall(true); + ArgumentCaptor stringCaptor = ArgumentCaptor.forClass(String.class); + verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), + stringCaptor.capture()); + assertEquals("*=nonDefault&inVoiceCall&DefaultDataOn&dsdsEnabled", stringCaptor.getValue()); + + clearInvocations(mSubscriptionController); + + mDataEnabledSettingsUT.setAllowDataDuringVoiceCall(false); + verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), + stringCaptor.capture()); + assertEquals("", stringCaptor.getValue()); + } + + @Test + @SmallTest + public void testSetAlwaysAllowMmsData() throws Exception { + mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, false); + assertTrue(mDataEnabledSettingsUT.setAlwaysAllowMmsData(true)); + ArgumentCaptor stringCaptor = ArgumentCaptor.forClass(String.class); + verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), + stringCaptor.capture()); + assertEquals("mms=unconditionally", stringCaptor.getValue()); + assertTrue(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS)); + + clearInvocations(mSubscriptionController); + + assertTrue(mDataEnabledSettingsUT.setAlwaysAllowMmsData(false)); + verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), + stringCaptor.capture()); + assertEquals("", stringCaptor.getValue()); + assertFalse(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS)); + + mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, true); + assertTrue(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS)); + } + + @Test + @SmallTest + public void testSetThermalDataEnabled() throws Exception { + mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_THERMAL, + false); + assertFalse(mDataEnabledSettingsUT.isDataEnabledForReason( + TelephonyManager.DATA_ENABLED_REASON_THERMAL)); + assertFalse(mDataEnabledSettingsUT.isDataEnabled()); + + mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_THERMAL, + true); + assertTrue(mDataEnabledSettingsUT.isDataEnabledForReason( + TelephonyManager.DATA_ENABLED_REASON_THERMAL)); + assertTrue(mDataEnabledSettingsUT.isDataEnabled()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java new file mode 100644 index 0000000000..d03bc8ca5c --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java @@ -0,0 +1,222 @@ +/** + * Copyright (C) 2020 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.dataconnection; + +import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_HANDOVER; +import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_NORMAL; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.telephony.AccessNetworkConstants; +import android.telephony.data.ApnSetting; +import android.telephony.data.ThrottleStatus; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.RetryManager; +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * Data throttler tests + */ +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DataThrottlerTest extends TelephonyTest { + + private static final boolean DBG = true; + private DataThrottler mDataThrottler; + + // Mocked classes + private DataThrottler.Callback mMockChangedCallback1; + private DataThrottler.Callback mMockChangedCallback2; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + mMockChangedCallback1 = mock(DataThrottler.Callback.class); + mMockChangedCallback2 = mock(DataThrottler.Callback.class); + mDataThrottler = new DataThrottler(mPhone, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + mDataThrottler.registerForThrottleStatusChanges(mMockChangedCallback1); + doReturn(false).when(mPhone).isUsingNewDataStack(); + } + + @After + public void tearDown() throws Exception { + mDataThrottler = null; + super.tearDown(); + } + + /** + * Test the behavior of a retry manager with no waiting APNs set. + */ + @Test + @SmallTest + public void testSetRetryTime() throws Exception { + final ArgumentCaptor> statusCaptor = + ArgumentCaptor.forClass((Class) List.class); + + List> expectedStatuses = new ArrayList<>(); + processAllMessages(); + expectedStatuses.add(List.of()); + + mDataThrottler.setRetryTime(ApnSetting.TYPE_DEFAULT, 1234567890L, + REQUEST_TYPE_NORMAL); + processAllMessages(); + assertEquals(1234567890L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); + assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, + mDataThrottler.getRetryTime(ApnSetting.TYPE_MMS)); + + processAllMessages(); + expectedStatuses.add(List.of( + new ThrottleStatus.Builder() + .setSlotIndex(0) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setApnType(ApnSetting.TYPE_DEFAULT) + .setThrottleExpiryTimeMillis(1234567890L) + .setRetryType(ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) + .build()) + ); + + + mDataThrottler.setRetryTime(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN, 13579L, + REQUEST_TYPE_HANDOVER); + processAllMessages(); + assertEquals(13579L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); + assertEquals(13579L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DUN)); + + processAllMessages(); + expectedStatuses.add(List.of( + new ThrottleStatus.Builder() + .setSlotIndex(0) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setApnType(ApnSetting.TYPE_DUN) + .setThrottleExpiryTimeMillis(13579L) + .setRetryType(ThrottleStatus.RETRY_TYPE_HANDOVER) + .build(), + new ThrottleStatus.Builder() + .setSlotIndex(0) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setApnType(ApnSetting.TYPE_DEFAULT) + .setThrottleExpiryTimeMillis(13579L) + .setRetryType(ThrottleStatus.RETRY_TYPE_HANDOVER) + .build()) + ); + + + mDataThrottler.setRetryTime(ApnSetting.TYPE_MMS, -10, + REQUEST_TYPE_NORMAL); + processAllMessages(); + assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, + mDataThrottler.getRetryTime(ApnSetting.TYPE_MMS)); + processAllMessages(); + expectedStatuses.add(List.of( + new ThrottleStatus.Builder() + .setSlotIndex(0) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setNoThrottle() + .setApnType(ApnSetting.TYPE_MMS) + .setRetryType(ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) + .build() + )); + + mDataThrottler.setRetryTime(ApnSetting.TYPE_FOTA | ApnSetting.TYPE_EMERGENCY, + RetryManager.NO_RETRY, REQUEST_TYPE_HANDOVER); + + processAllMessages(); + expectedStatuses.add(List.of( + new ThrottleStatus.Builder() + .setSlotIndex(0) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setApnType(ApnSetting.TYPE_EMERGENCY) + .setThrottleExpiryTimeMillis(RetryManager.NO_RETRY) + .setRetryType(ThrottleStatus.RETRY_TYPE_NONE) + .build(), + new ThrottleStatus.Builder() + .setSlotIndex(0) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setApnType(ApnSetting.TYPE_FOTA) + .setThrottleExpiryTimeMillis(RetryManager.NO_RETRY) + .setRetryType(ThrottleStatus.RETRY_TYPE_NONE) + .build() + )); + + assertEquals(RetryManager.NO_RETRY, mDataThrottler.getRetryTime(ApnSetting.TYPE_FOTA)); + assertEquals(RetryManager.NO_RETRY, mDataThrottler.getRetryTime(ApnSetting.TYPE_EMERGENCY)); + + + // Loop through statuses and test everything + verify(mMockChangedCallback1, times(expectedStatuses.size())) + .onThrottleStatusChanged(statusCaptor.capture()); + + // Check actual statuses + List> actualStatuses = + (List>) statusCaptor.getAllValues(); + assertEquals(expectedStatuses.size(), actualStatuses.size()); + + if (DBG) { + logd("expectedStatuses.size() = " + expectedStatuses.size()); + logd("actualStatuses.size() = " + actualStatuses.size()); + } + + Comparator comparator = (o1, o2) -> + Integer.compare(o1.getApnType(), o2.getApnType()); + + for (int i = 0; i < expectedStatuses.size(); i++) { + List atsExpected = new ArrayList<>(expectedStatuses.get(i)); + List atsActual = new ArrayList<>(actualStatuses.get(i)); + + atsExpected.sort(comparator); + atsActual.sort(comparator); + assertEquals("Lists at index " + i + " don't match", + atsExpected, atsActual); + } + + this.mDataThrottler.registerForThrottleStatusChanges(mMockChangedCallback2); + } + + /** + * Test the behavior of a retry manager with no waiting APNs set. + */ + @Test + @SmallTest + public void testUnthrottle() throws Exception { + mDataThrottler.setRetryTime(ApnSetting.TYPE_DEFAULT, 1234567890L, + REQUEST_TYPE_NORMAL); + processAllMessages(); + assertEquals(1234567890L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); + + mDataThrottler.reset(); + processAllMessages(); + assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, + mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java new file mode 100644 index 0000000000..bddfdb4fa5 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.dataconnection; + +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.net.InetAddresses; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.telephony.AccessNetworkConstants; +import android.telephony.data.ApnSetting; +import android.telephony.data.DataCallResponse; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.DctConstants; +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.dataconnection.DataConnection.UpdateLinkPropertyResult; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DcControllerTest extends TelephonyTest { + + private static final int DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT = 1; + private static final int DATA_CONNECTION_ACTIVE_PH_LINK_ACTIVE = 2; + + private static final int EVENT_DATA_STATE_CHANGED = 0x00040007; + private static final int EVENT_PHYSICAL_LINK_STATUS_CHANGED = 1; + + // Mocked classes + private List mApnContexts; + private DataConnection mDc; + private DataServiceManager mDataServiceManager; + private Handler mTestHandler; + + UpdateLinkPropertyResult mResult; + + private DcController mDcc; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + mApnContexts = mock(List.class); + mDc = mock(DataConnection.class); + mDataServiceManager = mock(DataServiceManager.class); + mTestHandler = mock(Handler.class); + + doReturn("fake.action_detached").when(mPhone).getActionDetached(); + doReturn(1).when(mApnContexts).size(); + doReturn(mApnContexts).when(mDc).getApnContexts(); + doReturn(false).when(mPhone).isUsingNewDataStack(); + + LinkProperties lp = new LinkProperties(); + mResult = new UpdateLinkPropertyResult(lp); + doReturn(mResult).when(mDc).updateLinkProperty(any(DataCallResponse.class)); + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .when(mDataServiceManager).getTransportType(); + + mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, Looper.myLooper(), + ""); + processAllMessages(); + } + + @After + public void tearDown() throws Exception { + mDcc.removeCallbacksAndMessages(null); + mDcc = null; + mResult = null; + super.tearDown(); + } + + @Test + @SmallTest + public void testDataDormant() throws Exception { + ArrayList l = new ArrayList<>(); + DataCallResponse dcResponse = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1) + .setId(1) + .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + l.add(dcResponse); + + mDc.mCid = 1; + mDcc.addActiveDcByCid(mDc); + + mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, + new AsyncResult(null, l, null))); + processAllMessages(); + + verify(mDcTracker, times(1)).sendStopNetStatPoll(eq(DctConstants.Activity.DORMANT)); + } + + @Test + @SmallTest + public void testPhysicalLinkStatusChanged_defaultApnTypeAndDormant_registrantNotifyResult() + throws Exception { + ArrayList l = new ArrayList<>(); + DataCallResponse dcResponse = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1) + .setId(1) + .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + l.add(dcResponse); + mDc.mCid = 1; + mDcc.addActiveDcByCid(mDc); + ApnContext apnContext = new ApnContext(mPhone, ApnSetting.TYPE_DEFAULT, TAG, mDcTracker, 1); + List apnContextList = new ArrayList<>(); + apnContextList.add(apnContext); + doReturn(apnContextList).when(mDc).getApnContexts(); + doReturn(true).when(mDcTracker).getLteEndcUsingUserDataForIdleDetection(); + mDcc.registerForPhysicalLinkStatusChanged(mTestHandler, EVENT_PHYSICAL_LINK_STATUS_CHANGED); + + mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, + new AsyncResult(null, l, null))); + processAllMessages(); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mTestHandler, times(1)).sendMessageDelayed(messageCaptor.capture(), anyLong()); + Message message = messageCaptor.getValue(); + assertEquals(EVENT_PHYSICAL_LINK_STATUS_CHANGED, message.what); + AsyncResult ar = (AsyncResult) message.obj; + assertEquals(DataCallResponse.LINK_STATUS_DORMANT, (int) ar.result); + } + + @Test + @SmallTest + public void testPhysicalLinkStatusChanged_imsApnTypeAndDormant_NoNotifyResult() + throws Exception { + testPhysicalLinkStatusChanged_defaultApnTypeAndDormant_registrantNotifyResult(); + + ArrayList l = new ArrayList<>(); + DataCallResponse dcResponse = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1) + .setId(1) + .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_ACTIVE) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + l.add(dcResponse); + mDc.mCid = 1; + mDcc.addActiveDcByCid(mDc); + ApnContext apnContext = new ApnContext(mPhone, ApnSetting.TYPE_IMS, TAG, mDcTracker, 1); + List apnContextList = new ArrayList<>(); + apnContextList.add(apnContext); + doReturn(apnContextList).when(mDc).getApnContexts(); + doReturn(true).when(mDcTracker).getLteEndcUsingUserDataForIdleDetection(); + + mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, + new AsyncResult(null, l, null))); + processAllMessages(); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mTestHandler, times(1)).sendMessageDelayed(messageCaptor.capture(), anyLong()); + } + + @Test + @SmallTest + public void testPhysicalLinkStatusChanged_defaultApnTypeAndStateChanged_registrantNotifyResult() + throws Exception { + testPhysicalLinkStatusChanged_imsApnTypeAndDormant_NoNotifyResult(); + + ArrayList l = new ArrayList<>(); + DataCallResponse dcResponse = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1) + .setId(1) + .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_ACTIVE) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses( + Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1440) + .setMtuV6(1440) + .build(); + l.add(dcResponse); + mDc.mCid = 1; + mDcc.addActiveDcByCid(mDc); + ApnContext apnContext = new ApnContext(mPhone, ApnSetting.TYPE_DEFAULT, TAG, mDcTracker, 1); + List apnContextList = new ArrayList<>(); + apnContextList.add(apnContext); + doReturn(apnContextList).when(mDc).getApnContexts(); + doReturn(true).when(mDcTracker).getLteEndcUsingUserDataForIdleDetection(); + + mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, + new AsyncResult(null, l, null))); + processAllMessages(); + + ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); + verify(mTestHandler, times(2)).sendMessageDelayed(messageCaptor.capture(), anyLong()); + Message message = messageCaptor.getValue(); + assertEquals(EVENT_PHYSICAL_LINK_STATUS_CHANGED, message.what); + AsyncResult ar = (AsyncResult) message.obj; + assertEquals(DataCallResponse.LINK_STATUS_ACTIVE, (int) ar.result); + } +} \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java new file mode 100644 index 0000000000..78438e41d9 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 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.dataconnection; + +import static junit.framework.Assert.assertEquals; + +import static org.mockito.Mockito.doReturn; + +import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.NetworkAgent; +import android.net.NetworkAgentConfig; +import android.net.NetworkInfo; +import android.net.NetworkProvider; +import android.os.Looper; +import android.telephony.AccessNetworkConstants; +import android.telephony.TelephonyManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +import java.lang.reflect.Field; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DcNetworkAgentTest extends TelephonyTest { + + private DcNetworkAgent mDcNetworkAgent; + private DataConnection mDc; + private DcController mDcc; + private DcFailBringUp mDcFailBringUp; + + private DataServiceManager mDataServiceManager; + private DcTesterFailBringUpAll mDcTesterFailBringUpAll; + private NetworkProvider mNetworkProvider; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + logd("+Setup!"); + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + doReturn(false).when(mPhone).isUsingNewDataStack(); + mDataServiceManager = Mockito.mock(DataServiceManager.class); + mDcTesterFailBringUpAll = Mockito.mock(DcTesterFailBringUpAll.class); + mNetworkProvider = Mockito.mock(NetworkProvider.class); + + final NetworkAgentConfig.Builder configBuilder = new NetworkAgentConfig.Builder(); + configBuilder.setLegacyType(ConnectivityManager.TYPE_MOBILE); + configBuilder.setLegacyTypeName("MOBILE"); + configBuilder.setLegacySubType(TelephonyManager.NETWORK_TYPE_LTE); + configBuilder.setLegacySubTypeName("LTE"); + configBuilder.setLegacyExtraInfo("apn"); + + doReturn("fake.action_detached").when(mPhone).getActionDetached(); + mDcFailBringUp = new DcFailBringUp(); + mDcFailBringUp.saveParameters(0, 0, -2); + doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp(); + + mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, Looper.myLooper(), + ""); + mDc = DataConnection.makeDataConnection(mPhone, 0, mDcTracker, mDataServiceManager, + mDcTesterFailBringUpAll, mDcc); + + LinkProperties linkProperties = new LinkProperties(); + linkProperties.setInterfaceName("fake_iface"); + Field field = DataConnection.class.getDeclaredField("mLinkProperties"); + field.setAccessible(true); + field.set(mDc, linkProperties); + + mDcNetworkAgent = new DcNetworkAgent(mDc, mPhone, 45, configBuilder.build(), + mNetworkProvider, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + logd("-Setup!"); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + private void verifyDisconnected() throws Exception { + Field field = NetworkAgent.class.getDeclaredField("mNetworkInfo"); + field.setAccessible(true); + NetworkInfo networkInfo = (NetworkInfo) field.get(mDcNetworkAgent); + assertEquals(NetworkInfo.DetailedState.DISCONNECTED, networkInfo.getDetailedState()); + } + + @Test + public void testUnwantedTimeout() throws Exception { + mDcNetworkAgent.markConnected(); + mDcNetworkAgent.onNetworkUnwanted(); + processAllFutureMessages(); + verifyDisconnected(); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java new file mode 100644 index 0000000000..b08a6803d0 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2020 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.dataconnection; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.TelephonyNetworkSpecifier; +import android.telephony.data.ApnSetting; + +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class DcRequestTest extends TelephonyTest { + NetworkRequest mNetworkRequest; + + // Mocked classes + ApnConfigTypeRepository mApnConfigTypeRepo; + + @Before + public void setUp() throws Exception { + mApnConfigTypeRepo = mock(ApnConfigTypeRepository.class); + super.setUp(getClass().getSimpleName()); + doReturn(false).when(mPhone).isUsingNewDataStack(); + } + + @After + public void tearDown() throws Exception { + mNetworkRequest = null; + super.tearDown(); + } + + @Test + public void whenNetworkRequestInternetThenPriorityZero() { + mNetworkRequest = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + + when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_DEFAULT)) + .thenReturn(new ApnConfigType(ApnSetting.TYPE_DEFAULT, 0)); + DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); + + assertEquals(0, dcRequest.priority); + } + + @Test + public void whenNetworkRequestMcxThenApnConfigTypeMcxPriorityReturned() { + mNetworkRequest = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + //Testing out multiple transport types here + .addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH) + .addCapability(NetworkCapabilities.NET_CAPABILITY_MCX) + .build(); + + when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_MCX)) + .thenReturn(new ApnConfigType(ApnSetting.TYPE_MCX, 21)); + DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); + assertEquals(21, dcRequest.priority); + } + + @Test + public void whenNetworkRequestNotCellularThenDcRequestIsNull() { + mNetworkRequest = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_MCX) + .build(); + when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_NONE)).thenReturn(null); + DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); + assertNull(dcRequest); + } + + @Test + public void whenNetworkRequestHasNoTransportThenPriorityStays() { + //This seems like an invalid case that should be handled differently. + mNetworkRequest = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_MCX) + .build(); + + when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_MCX)) + .thenReturn(new ApnConfigType(ApnSetting.TYPE_MCX, 11)); + DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); + assertEquals(11, dcRequest.priority); + } + + @Test + public void whenNetworkRequestNotCellularWithTelephonySpecifierThenDcRequestIsNull() { + TelephonyNetworkSpecifier telephonyNetworkSpecifier = + new TelephonyNetworkSpecifier.Builder().setSubscriptionId(5).build(); + + //This seems like an invalid case that should be handled differently. + mNetworkRequest = new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH) + .setNetworkSpecifier(telephonyNetworkSpecifier) + .build(); + + when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_NONE)).thenReturn(null); + + DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); + + assertNull(dcRequest); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java new file mode 100644 index 0000000000..549c587549 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java @@ -0,0 +1,2983 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.dataconnection; + +import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; +import static com.android.internal.telephony.dataconnection.ApnSettingTest.createApnSetting; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ServiceInfo; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.hardware.radio.V1_0.SetupDataCallResult; +import android.net.LinkProperties; +import android.net.NetworkAgent; +import android.net.NetworkCapabilities; +import android.net.NetworkPolicyManager; +import android.net.NetworkRequest; +import android.net.Uri; +import android.os.AsyncResult; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Message; +import android.os.PersistableBundle; +import android.os.SystemClock; +import android.provider.Settings; +import android.provider.Telephony; +import android.telephony.AccessNetworkConstants; +import android.telephony.AccessNetworkConstants.AccessNetworkType; +import android.telephony.Annotation; +import android.telephony.CarrierConfigManager; +import android.telephony.DataFailCause; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.PreciseDataConnectionState; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionPlan; +import android.telephony.TelephonyDisplayInfo; +import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; +import android.telephony.data.DataCallResponse; +import android.telephony.data.DataProfile; +import android.telephony.data.DataService; +import android.telephony.data.TrafficDescriptor; +import android.test.mock.MockContentProvider; +import android.test.mock.MockContentResolver; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.TextUtils; +import android.util.Pair; +import android.util.SparseArray; + +import androidx.test.filters.FlakyTest; + +import com.android.internal.R; +import com.android.internal.telephony.DctConstants; +import com.android.internal.telephony.ISub; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.RetryManager; +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.data.CellularDataService; +import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.time.Period; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +public class DcTrackerTest extends TelephonyTest { + public static final String FAKE_APN1 = "FAKE APN 1"; + public static final String FAKE_APN2 = "FAKE APN 2"; + public static final String FAKE_APN3 = "FAKE APN 3"; + public static final String FAKE_APN4 = "FAKE APN 4"; + public static final String FAKE_APN5 = "FAKE APN 5"; + public static final String FAKE_APN6 = "FAKE APN 6"; + public static final String FAKE_APN7 = "FAKE APN 7"; + public static final String FAKE_APN8 = "FAKE APN 8"; + public static final String FAKE_APN9 = "FAKE APN 9"; + public static final String FAKE_IFNAME = "FAKE IFNAME"; + public static final String FAKE_PCSCF_ADDRESS = "22.33.44.55"; + public static final String FAKE_GATEWAY = "11.22.33.44"; + public static final String FAKE_DNS = "55.66.77.88"; + public static final String FAKE_ADDRESS = "99.88.77.66"; + private static final int NETWORK_TYPE_NR_BITMASK = + 1 << (TelephonyManager.NETWORK_TYPE_NR - 1); + private static final int NETWORK_TYPE_LTE_BITMASK = + 1 << (TelephonyManager.NETWORK_TYPE_LTE - 1); + private static final int NETWORK_TYPE_EHRPD_BITMASK = + 1 << (TelephonyManager.NETWORK_TYPE_EHRPD - 1); + private static final Uri PREFERAPN_URI = Uri.parse( + Telephony.Carriers.CONTENT_URI + "/preferapn"); + private static final int DATA_ENABLED_CHANGED = 0; + private static final String FAKE_PLMN = "44010"; + private static final long TEST_TIMEOUT = 1000; + + // Mocked classes + ISub mIsub; + IBinder mBinder; + SubscriptionInfo mSubscriptionInfo; + ApnContext mApnContext; + DataConnection mDataConnection; + Handler mHandler; + NetworkPolicyManager mNetworkPolicyManager; + + private DcTracker mDct; + private DcTrackerTestHandler mDcTrackerTestHandler; + + private AlarmManager mAlarmManager; + + private PersistableBundle mBundle; + + private SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener; + + private final ApnSettingContentProvider mApnSettingContentProvider = + new ApnSettingContentProvider(); + + private Message mMessage; + + private CellularDataService mCellularDataService; + + private void addDataService() { + mCellularDataService = new CellularDataService(); + ServiceInfo serviceInfo = new ServiceInfo(); + serviceInfo.packageName = "com.android.phone"; + serviceInfo.permission = "android.permission.BIND_TELEPHONY_DATA_SERVICE"; + IntentFilter filter = new IntentFilter(); + mContextFixture.addService( + DataService.SERVICE_INTERFACE, + null, + "com.android.phone", + mCellularDataService.mBinder, + serviceInfo, + filter); + } + + private class DcTrackerTestHandler extends HandlerThread { + + private DcTrackerTestHandler(String name) { + super(name); + } + + @Override + public void onLooperPrepared() { + mDct = new DcTracker(mPhone, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + setReady(true); + } + } + + private class ApnSettingContentProvider extends MockContentProvider { + public final String[] FAKE_APN_COLUMNS = new String[]{ + Telephony.Carriers._ID, Telephony.Carriers.NUMERIC, + Telephony.Carriers.NAME, Telephony.Carriers.APN, + Telephony.Carriers.PROXY, Telephony.Carriers.PORT, + Telephony.Carriers.MMSC, Telephony.Carriers.MMSPROXY, + Telephony.Carriers.MMSPORT, Telephony.Carriers.USER, + Telephony.Carriers.PASSWORD, Telephony.Carriers.AUTH_TYPE, + Telephony.Carriers.TYPE, + Telephony.Carriers.PROTOCOL, + Telephony.Carriers.ROAMING_PROTOCOL, + Telephony.Carriers.CARRIER_ENABLED, Telephony.Carriers.BEARER, + Telephony.Carriers.BEARER_BITMASK, + Telephony.Carriers.PROFILE_ID, + Telephony.Carriers.MODEM_PERSIST, + Telephony.Carriers.MAX_CONNECTIONS, + Telephony.Carriers.WAIT_TIME_RETRY, + Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS, + Telephony.Carriers.MTU, + Telephony.Carriers.MTU_V4, + Telephony.Carriers.MTU_V6, + Telephony.Carriers.MVNO_TYPE, + Telephony.Carriers.MVNO_MATCH_DATA, + Telephony.Carriers.NETWORK_TYPE_BITMASK, + Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK, + Telephony.Carriers.APN_SET_ID, + Telephony.Carriers.CARRIER_ID, + Telephony.Carriers.SKIP_464XLAT, + Telephony.Carriers.ALWAYS_ON + }; + + private int mPreferredApnSet = 0; + + private Object[] mPreferredApn = null; + + private String mFakeApn1Types = "default,supl"; + + private String mFakeApn5Types = "dun"; + + private int mFakeApn1Bitmask = NETWORK_TYPE_LTE_BITMASK; + + private int mRowIdOffset = 0; + + public void setFakeApn1Types(String apnTypes) { + mFakeApn1Types = apnTypes; + } + + public void setFakeApn5Types(String apnTypes) { + mFakeApn5Types = apnTypes; + } + + public void setFakeApn1NetworkTypeBitmask(int bitmask) { + mFakeApn1Bitmask = bitmask; + } + + public void setRowIdOffset(int rowIdOffset) { + mRowIdOffset = rowIdOffset; + } + + public void setFakePreferredApn(Object[] fakeApn) { + mPreferredApn = fakeApn; + } + + public Object[] getFakeApn1() { + return new Object[]{ + 2163 + mRowIdOffset, // id + FAKE_PLMN, // numeric + "sp-mode", // name + FAKE_APN1, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + mFakeApn1Types, // types + "IP", // protocol + "IP", // roaming_protocol + 1, // carrier_enabled + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer + 0, // bearer_bitmask + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 0, // mtu_v4 + 0, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + mFakeApn1Bitmask, // network_type_bitmask + 0, // lingering_network_type_bitmask + 0, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0 // always_on + }; + } + + public Object[] getFakeApn2() { + return new Object[]{ + 2164 + mRowIdOffset, // id + FAKE_PLMN, // numeric + "mopera U", // name + FAKE_APN2, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "default,supl", // types + "IP", // protocol + "IP", // roaming_protocol + 1, // carrier_enabled + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer, + 0, // bearer_bitmask + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 0, // mtu_v4 + 0, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask + 0, // lingering_network_type_bitmask + 0, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0 // always_on + }; + } + + public Object[] getFakeApn3() { + return new Object[]{ + 2165 + mRowIdOffset, // id + FAKE_PLMN, // numeric + "b-mobile for Nexus", // name + FAKE_APN3, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "ims", // types + "IP", // protocol + "IP", // roaming_protocol + 1, // carrier_enabled + 0, // bearer + 0, // bearer_bitmask + 2, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 0, // mtu_v4 + 0, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + 0, // network_type_bitmask + 0, // lingering_network_type_bitmask + 0, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0 // always_on + }; + } + + public Object[] getFakeApn4() { + return new Object[]{ + 2166 + mRowIdOffset, // id + FAKE_PLMN, // numeric + "sp-mode ehrpd", // name + FAKE_APN4, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "default,supl", // types + "IP", // protocol + "IP", // roaming_protocol + 1, // carrier_enabled + ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD, // bearer + 0, // bearer_bitmask + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 0, // mtu_v4 + 0, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + NETWORK_TYPE_EHRPD_BITMASK, // network_type_bitmask + 0, // lingering_network_type_bitmask + 0, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0 // always_on + }; + } + + public Object[] getFakeApn5() { + return new Object[]{ + 2167 + mRowIdOffset, // id + FAKE_PLMN, // numeric + "b-mobile for Nexus", // name + FAKE_APN5, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + mFakeApn5Types, // types + "IP", // protocol + "IP", // roaming_protocol + 1, // carrier_enabled + 0, // bearer + 0, // bearer_bitmask + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 0, // mtu_v4 + 0, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + 0, // network_type_bitmask + 0, // lingering_network_type_bitmask + 0, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0 // always_on + }; + } + + public Object[] getFakeApn6() { + return new Object[]{ + 2168 + mRowIdOffset, // id + FAKE_PLMN, // numeric + "sp-mode", // name + FAKE_APN6, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "mms,xcap", // types + "IP", // protocol + "IP", // roaming_protocol + 1, // carrier_enabled + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer + 0, // bearer_bitmask + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 0, // mtu_v4 + 0, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask + 0, // lingering_network_type_bitmask + 0, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0 // always_on + }; + } + + public Object[] getFakeApn7() { + return new Object[]{ + 2169 + mRowIdOffset, // id + FAKE_PLMN, // numeric + "sp-mode", // name + FAKE_APN7, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "default", // types + "IP", // protocol + "IP", // roaming_protocol + 1, // carrier_enabled + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer + 0, // bearer_bitmask + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 0, // mtu_v4 + 0, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask + 0, // lingering_network_type_bitmask + 1, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0 // always_on + }; + } + + public Object[] getFakeApn8() { + return new Object[]{ + 2170 + mRowIdOffset, // id + FAKE_PLMN, // numeric + "IMS", // name + FAKE_APN8, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "ims", // types + "IP", // protocol + "IP", // roaming_protocol + 1, // carrier_enabled + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer + 0, // bearer_bitmask + 2, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 0, // mtu_v4 + 0, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask + 0, // lingering_network_type_bitmask + -1, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0 // always_on + }; + } + + public Object[] getFakeApn9() { + return new Object[]{ + 2171 + mRowIdOffset, // id + FAKE_PLMN, // numeric + "sp-mode nr", // name + FAKE_APN9, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "default,enterprise", // types + "IP", // protocol + "IP", // roaming_protocol + 1, // carrier_enabled + ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer + 0, // bearer_bitmask + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 0, // mtu_v4 + 0, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + NETWORK_TYPE_NR_BITMASK, // network_type_bitmask + 0, // lingering_network_type_bitmask + 0, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0 // always_on + }; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + logd("ApnSettingContentProvider: query"); + logd(" uri = " + uri); + logd(" projection = " + Arrays.toString(projection)); + logd(" selection = " + selection); + logd(" selectionArgs = " + Arrays.toString(selectionArgs)); + logd(" sortOrder = " + sortOrder); + + if (uri.compareTo(Telephony.Carriers.CONTENT_URI) == 0 + || uri.toString().startsWith(Uri.withAppendedPath( + Telephony.Carriers.CONTENT_URI, "filtered").toString()) + || uri.toString().startsWith(Uri.withAppendedPath( + Telephony.Carriers.SIM_APN_URI, "filtered").toString())) { + if (projection == null) { + + logd("Query '" + FAKE_PLMN + "' APN settings"); + MatrixCursor mc = new MatrixCursor(FAKE_APN_COLUMNS); + mc.addRow(getFakeApn1()); + mc.addRow(getFakeApn2()); + mc.addRow(getFakeApn3()); + mc.addRow(getFakeApn4()); + mc.addRow(getFakeApn5()); + mc.addRow(getFakeApn6()); + mc.addRow(getFakeApn7()); + mc.addRow(getFakeApn8()); + mc.addRow(getFakeApn9()); + + return mc; + } + } else if (isPathPrefixMatch(uri, + Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapnset"))) { + MatrixCursor mc = new MatrixCursor( + new String[]{Telephony.Carriers.APN_SET_ID}); + // apn_set_id is the only field used with this URL + mc.addRow(new Object[]{ mPreferredApnSet }); + mc.addRow(new Object[]{ 0 }); + return mc; + } else if (isPathPrefixMatch(uri, + Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapn_no_update"))) { + if (mPreferredApn == null) { + return null; + } else { + MatrixCursor mc = new MatrixCursor(FAKE_APN_COLUMNS); + mc.addRow(mPreferredApn); + return mc; + } + } + + return null; + } + + @Override + public int update(Uri url, ContentValues values, String where, String[] whereArgs) { + mPreferredApnSet = values.getAsInteger(Telephony.Carriers.APN_SET_ID); + return 1; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + } + + @Before + public void setUp() throws Exception { + logd("DcTrackerTest +Setup!"); + super.setUp(getClass().getSimpleName()); + mIsub = Mockito.mock(ISub.class); + mBinder = Mockito.mock(IBinder.class); + mSubscriptionInfo = Mockito.mock(SubscriptionInfo.class); + mApnContext = Mockito.mock(ApnContext.class); + mDataConnection = Mockito.mock(DataConnection.class); + mHandler = Mockito.mock(Handler.class); + mNetworkPolicyManager = Mockito.mock(NetworkPolicyManager.class); + + doReturn("fake.action_detached").when(mPhone).getActionDetached(); + doReturn("fake.action_attached").when(mPhone).getActionAttached(); + doReturn(false).when(mPhone).isUsingNewDataStack(); + doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState) + .getRilDataRadioTechnology(); + + mContextFixture.putStringArrayResource(com.android.internal.R.array + .config_mobile_tcp_buffers, new String[]{ + "umts:131072,262144,1452032,4096,16384,399360", + "hspa:131072,262144,2441216,4096,16384,399360", + "hsupa:131072,262144,2441216,4096,16384,399360", + "hsdpa:131072,262144,2441216,4096,16384,399360", + "hspap:131072,262144,2441216,4096,16384,399360", + "edge:16384,32768,131072,4096,16384,65536", + "gprs:4096,8192,24576,4096,8192,24576", + "1xrtt:16384,32768,131070,4096,16384,102400", + "evdo:131072,262144,1048576,4096,16384,524288", + "lte:524288,1048576,8388608,262144,524288,4194304"}); + + mContextFixture.putResource(R.string.config_wwan_data_service_package, + "com.android.phone"); + + ((MockContentResolver) mContext.getContentResolver()).addProvider( + Telephony.Carriers.CONTENT_URI.getAuthority(), mApnSettingContentProvider); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0); + + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) + .getPreferredTransport(anyInt()); + doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); + doReturn(true).when(mSST).getDesiredPowerState(); + doReturn(true).when(mSST).getPowerStateFromCarrier(); + doAnswer( + (Answer) invocation -> { + mOnSubscriptionsChangedListener = + (SubscriptionManager.OnSubscriptionsChangedListener) + invocation.getArguments()[0]; + return null; + } + ).when(mSubscriptionManager).addOnSubscriptionsChangedListener(any()); + doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt()); + doReturn(mNetworkPolicyManager).when(mContext) + .getSystemService(Context.NETWORK_POLICY_SERVICE); + doReturn(1).when(mIsub).getDefaultDataSubId(); + doReturn(mIsub).when(mBinder).queryLocalInterface(anyString()); + mServiceManagerMockedServices.put("isub", mBinder); + + mContextFixture.putStringArrayResource( + com.android.internal.R.array.config_cell_retries_per_error_code, + new String[]{"36,2"}); + + mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + mBundle = mContextFixture.getCarrierConfigBundle(); + + mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); + + mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult()); + addDataService(); + + mDcTrackerTestHandler = new DcTrackerTestHandler(getClass().getSimpleName()); + mDcTrackerTestHandler.start(); + waitUntilReady(); + + Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); + mContext.sendBroadcast(intent); + + waitForMs(600); + logd("DcTrackerTest -Setup!"); + } + + @After + public void tearDown() throws Exception { + logd("DcTrackerTest -tearDown"); + mDct.removeCallbacksAndMessages(null); + mDct.stopHandlerThread(); + mDct = null; + mDcTrackerTestHandler.quit(); + mDcTrackerTestHandler.join(); + mDcTrackerTestHandler = null; + mCellularDataService.onDestroy(); + mCellularDataService = null; + mAlarmManager = null; + mBundle = null; + mCellularDataService = null; + waitForMs(100); + super.tearDown(); + } + + // Create a successful data response + private static SetupDataCallResult createSetupDataCallResult() { + SetupDataCallResult result = new SetupDataCallResult(); + result.status = 0; + result.suggestedRetryTime = -1; + result.cid = 1; + result.active = 2; + result.type = "IP"; + result.ifname = FAKE_IFNAME; + result.addresses = FAKE_ADDRESS; + result.dnses = FAKE_DNS; + result.gateways = FAKE_GATEWAY; + result.pcscf = FAKE_PCSCF_ADDRESS; + result.mtu = 1440; + return result; + } + + private void verifyDataProfile(DataProfile dp, String apn, int profileId, + int supportedApnTypesBitmap, int type, int bearerBitmask) { + assertEquals(profileId, dp.getProfileId()); + assertEquals(apn, dp.getApn()); + assertEquals(ApnSetting.PROTOCOL_IP, dp.getProtocolType()); + assertEquals(0, dp.getAuthType()); + assertEquals("", dp.getUserName()); + assertEquals("", dp.getPassword()); + assertEquals(type, dp.getType()); + assertEquals(0, dp.getWaitTime()); + assertTrue(dp.isEnabled()); + assertEquals(supportedApnTypesBitmap, dp.getSupportedApnTypesBitmask()); + assertEquals(ApnSetting.PROTOCOL_IP, dp.getRoamingProtocolType()); + assertEquals(bearerBitmask, dp.getBearerBitmask()); + assertEquals(0, dp.getMtu()); + assertTrue(dp.isPersistent()); + assertFalse(dp.isPreferred()); + } + + private void verifyDataConnected(final String apnSetting) { + verify(mAlarmManager, times(1)).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), + any(PendingIntent.class)); + + assertEquals(apnSetting, mDct.getActiveApnString(ApnSetting.TYPE_DEFAULT_STRING)); + assertArrayEquals(new String[]{ApnSetting.TYPE_DEFAULT_STRING}, mDct.getActiveApnTypes()); + + assertTrue(mDct.isAnyDataConnected()); + assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); + + LinkProperties linkProperties = mDct.getLinkProperties(ApnSetting.TYPE_DEFAULT_STRING); + assertEquals(FAKE_IFNAME, linkProperties.getInterfaceName()); + assertEquals(1, linkProperties.getAddresses().size()); + assertEquals(FAKE_ADDRESS, linkProperties.getAddresses().get(0).getHostAddress()); + assertEquals(1, linkProperties.getDnsServers().size()); + assertEquals(FAKE_DNS, linkProperties.getDnsServers().get(0).getHostAddress()); + assertEquals(FAKE_GATEWAY, linkProperties.getRoutes().get(0).getGateway().getHostAddress()); + } + + private boolean isHandoverPending(int apnType) { + try { + Method method = DcTracker.class.getDeclaredMethod("isHandoverPending", + int.class); + method.setAccessible(true); + return (boolean) method.invoke(mDct, apnType); + } catch (Exception e) { + fail(e.toString()); + return false; + } + } + + private void addHandoverCompleteMsg(Message onCompleteMsg, + @Annotation.ApnType int apnType) { + try { + Method method = DcTracker.class.getDeclaredMethod("addHandoverCompleteMsg", + Message.class, int.class); + method.setAccessible(true); + method.invoke(mDct, onCompleteMsg, apnType); + } catch (Exception e) { + fail(e.toString()); + } + } + + private void sendInitializationEvents() { + sendCarrierConfigChanged(""); + + sendSimStateUpdated(""); + + sendEventDataConnectionAttached(""); + + waitForMs(200); + } + + private void sendCarrierConfigChanged(String messagePrefix) { + logd(messagePrefix + "Sending EVENT_CARRIER_CONFIG_CHANGED"); + mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + } + + private void sendSimStateUpdated(String messagePrefix) { + logd(messagePrefix + "Sending EVENT_SIM_STATE_UPDATED"); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SIM_STATE_UPDATED, + TelephonyManager.SIM_STATE_LOADED, 0)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + } + + private void sendEventDataConnectionAttached(String messagePrefix) { + logd(messagePrefix + "Sending EVENT_DATA_CONNECTION_ATTACHED"); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + } + + // Test the unmetered APN setup when data is disabled. + @Test + @SmallTest + public void testTrySetupDataUnmeteredDefaultNotSelected() throws Exception { + initApns(ApnSetting.TYPE_XCAP_STRING, new String[]{ApnSetting.TYPE_XCAP_STRING}); + doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mIsub).getDefaultDataSubId(); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + + sendInitializationEvents(); + + mDct.enableApn(ApnSetting.TYPE_XCAP, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), any(DataProfile.class), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + } + + // Test the normal data call setup scenario. + @Test + @MediumTest + public void testDataSetup() throws Exception { + DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); + boolean allowed = mDct.isDataAllowed(dataConnectionReasons); + assertFalse(dataConnectionReasons.toString(), allowed); + + logd("Sending EVENT_ENABLE_APN"); + // APN id 0 is APN_TYPE_DEFAULT + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + sendInitializationEvents(); + + dataConnectionReasons = new DataConnectionReasons(); + allowed = mDct.isDataAllowed(dataConnectionReasons); + assertTrue(dataConnectionReasons.toString(), allowed); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + // Verify if RIL command was sent properly. + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + verifyDataConnected(FAKE_APN1); + } + + // Test the scenario where the first data call setup is failed, and then retry the setup later. + @Test + @MediumTest + public void testDataRetry() throws Exception { + AsyncResult ar = new AsyncResult(null, + new Pair<>(true, DataEnabledSettings.REASON_USER_DATA_ENABLED), null); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // LOST_CONNECTION(0x10004) is a non-permanent failure, so we'll retry data setup later. + SetupDataCallResult result = createSetupDataCallResult(); + result.status = 0x10004; + + // Simulate RIL fails the data call setup + mSimulatedCommands.setDataCallResult(true, result); + + DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); + boolean allowed = mDct.isDataAllowed(dataConnectionReasons); + assertFalse(dataConnectionReasons.toString(), allowed); + + logd("Sending EVENT_ENABLE_APN"); + // APN id 0 is APN_TYPE_DEFAULT + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + sendInitializationEvents(); + + dataConnectionReasons = new DataConnectionReasons(); + allowed = mDct.isDataAllowed(dataConnectionReasons); + assertTrue(dataConnectionReasons.toString(), allowed); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + // Verify if RIL command was sent properly. + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + // This time we'll let RIL command succeed. + mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult()); + + //Send event for reconnecting data + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RECONNECT, + mPhone.getPhoneId(), DcTracker.REQUEST_TYPE_NORMAL, mApnContext)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + // Verify if RIL command was sent properly. + verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN2, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + // Verify connected with APN2 setting. + verifyDataConnected(FAKE_APN2); + } + + @Test + @MediumTest + @Ignore + @FlakyTest + public void testUserDisableData() { + //step 1: setup two DataCalls one for Metered: default, another one for Non-metered: IMS + //set Default and MMS to be metered in the CarrierConfigManager + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK); + + logd("Sending DATA_DISABLED_CMD"); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); + AsyncResult ar = new AsyncResult(null, + new Pair<>(false, DataEnabledSettings.REASON_USER_DATA_ENABLED), null); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + // expected tear down all metered DataConnections + verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( + eq(DataService.REQUEST_REASON_NORMAL), anyInt(), + any(Message.class)); + assertTrue(mDct.isAnyDataConnected()); + assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); + assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING)); + } + + @Test + @MediumTest + public void testTrySetupDataMmsAllowedDataDisabled() { + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + mDct.enableApn(ApnSetting.TYPE_MMS, DcTracker.REQUEST_TYPE_NORMAL, null); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + + List dataProfiles = dpCaptor.getAllValues(); + assertEquals(2, dataProfiles.size()); + + //Verify FAKE_APN1 + Optional fakeApn1 = dataProfiles.stream() + .filter(dp -> dp.getApn().equals(FAKE_APN1)) + .findFirst(); + assertTrue(fakeApn1.isPresent()); + verifyDataProfile(fakeApn1.get(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + //Verify FAKE_APN6 + Optional fakeApn6 = dataProfiles.stream() + .filter(dp -> dp.getApn().equals(FAKE_APN6)) + .findFirst(); + assertTrue(fakeApn6.isPresent()); + verifyDataProfile(fakeApn6.get(), FAKE_APN6, 0, ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP, + 1, NETWORK_TYPE_LTE_BITMASK); + + logd("Sending DATA_DISABLED_CMD for default data"); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); + mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + // expected tear down all metered DataConnections + verify(mSimulatedCommandsVerifier, times(2)).deactivateDataCall( + anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); + assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); + assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING)); + + clearInvocations(mSimulatedCommandsVerifier); + doReturn(true).when(mDataEnabledSettings).isDataEnabled(ApnSetting.TYPE_MMS); + mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); + assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); + } + + @Test + @MediumTest + public void testTrySetupDataMmsAlwaysAllowedDataDisabled() { + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + mApnSettingContentProvider.setFakeApn1Types("mms,xcap,default"); + mDct.enableApn(ApnSetting.TYPE_MMS, DcTracker.REQUEST_TYPE_NORMAL, null); + sendInitializationEvents(); + + // Verify MMS was set up and is connected + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, + ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP | ApnSetting.TYPE_DEFAULT, + 1, NETWORK_TYPE_LTE_BITMASK); + assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); + + // Verify DC has all capabilities specified in fakeApn1Types + Map apnContexts = mDct.getApnContexts().stream().collect( + Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); + assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() + .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); + assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() + .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)); + assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() + .getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_INTERNET)); + + // Disable mobile data + doReturn(false).when(mDataEnabledSettings).isDataEnabled(); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); + doReturn(false).when(mDataEnabledSettings).isMmsAlwaysAllowed(); + mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Expected tear down all metered DataConnections + waitForMs(200); + verify(mSimulatedCommandsVerifier).deactivateDataCall( + anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); + assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING)); + + // Allow MMS unconditionally + clearInvocations(mSimulatedCommandsVerifier); + doReturn(true).when(mDataEnabledSettings).isMmsAlwaysAllowed(); + doReturn(true).when(mDataEnabledSettings).isDataEnabled(ApnSetting.TYPE_MMS); + mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Verify MMS was set up and is connected + waitForMs(200); + verify(mSimulatedCommandsVerifier).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); + + // Ensure MMS data connection has the MMS capability only. + apnContexts = mDct.getApnContexts().stream().collect( + Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); + assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() + .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); + assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() + .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)); + assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() + .getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_INTERNET)); + } + + @Test + @MediumTest + public void testUserDisableRoaming() { + //step 1: setup two DataCalls one for Metered: default, another one for Non-metered: IMS + //step 2: set roaming disabled, data is enabled + //step 3: under roaming service + //step 4: only tear down metered data connections. + + //set Default and MMS to be metered in the CarrierConfigManager + boolean roamingEnabled = mDct.getDataRoamingEnabled(); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForHandlerAction(mDct, 1000); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForHandlerAction(mDct, 1000); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + //user is in roaming + doReturn(true).when(mServiceState).getDataRoaming(); + logd("Sending DISABLE_ROAMING_CMD"); + mDct.setDataRoamingEnabledByUser(false); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_ROAMING_ON)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + // expected tear down all metered DataConnections + verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( + eq(DataService.REQUEST_REASON_NORMAL), anyInt(), + any(Message.class)); + assertTrue(mDct.isAnyDataConnected()); + assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); + assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING)); + + // reset roaming settings / data enabled settings at end of this test + mDct.setDataRoamingEnabledByUser(roamingEnabled); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + } + + @Test + @MediumTest + public void testDataCallOnUserDisableRoaming() { + //step 1: mock under roaming service and user disabled roaming from settings. + //step 2: user toggled data settings on + //step 3: only non-metered data call is established + + boolean roamingEnabled = mDct.getDataRoamingEnabled(); + doReturn(true).when(mServiceState).getDataRoaming(); + + //set Default and MMS to be metered in the CarrierConfigManager + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + logd("Sending DISABLE_ROAMING_CMD"); + mDct.setDataRoamingEnabledByUser(false); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN3, 2, 64, 0, 0); + + assertTrue(mDct.isAnyDataConnected()); + assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); + assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING)); + + // reset roaming settings / data enabled settings at end of this test + mDct.setDataRoamingEnabledByUser(roamingEnabled); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + } + + // Test the default data switch scenario. + @FlakyTest /* flakes 1.57% of the time */ + @Test + @MediumTest + public void testDDSResetAutoAttach() throws Exception { + mContextFixture.putBooleanResource( + com.android.internal.R.bool.config_auto_attach_data_on_creation, true); + testDataSetup(); + assertTrue(mDct.shouldAutoAttach()); + mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + // The auto attach flag should be reset after update + assertFalse(mDct.shouldAutoAttach()); + } + + // Test for API carrierActionSetMeteredApnsEnabled. + @FlakyTest + @Ignore + @Test + @MediumTest + public void testCarrierActionSetMeteredApnsEnabled() { + //step 1: setup two DataCalls one for Internet and IMS + //step 2: set data is enabled + //step 3: cold sim is detected + //step 4: all data connection is torn down + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK); + assertTrue(mDct.isAnyDataConnected()); + + AsyncResult ar = new AsyncResult(null, + new Pair<>(false, DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER), null); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + // Validate all metered data connections have been torn down + verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( + eq(DataService.REQUEST_REASON_NORMAL), anyInt(), + any(Message.class)); + assertTrue(mDct.isAnyDataConnected()); + assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); + } + + private void initApns(String targetApn, String[] canHandleTypes) { + doReturn(targetApn).when(mApnContext).getApnType(); + doReturn(ApnSetting.getApnTypesBitmaskFromString(mApnContext.getApnType())) + .when(mApnContext).getApnTypeBitmask(); + doReturn(true).when(mApnContext).isConnectable(); + ApnSetting apnSetting = createApnSetting(ApnSetting.getApnTypesBitmaskFromString( + TextUtils.join(",", canHandleTypes))); + doReturn(apnSetting).when(mApnContext).getNextApnSetting(); + doReturn(apnSetting).when(mApnContext).getApnSetting(); + doReturn(mDataConnection).when(mApnContext).getDataConnection(); + doReturn(true).when(mApnContext).isEnabled(); + doReturn(true).when(mApnContext).isDependencyMet(); + doReturn(true).when(mApnContext).isReady(); + doReturn(false).when(mApnContext).hasRestrictedRequests(eq(true)); + } + + // Test the emergency APN setup. + @Test + @SmallTest + public void testTrySetupDataEmergencyApn() { + initApns(ApnSetting.TYPE_EMERGENCY_STRING, + new String[]{ApnSetting.TYPE_EMERGENCY_STRING}); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + waitForMs(200); + + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), + anyBoolean(), any(Message.class)); + } + + // Test the XCAP APN setup. + @Test + @SmallTest + public void testTrySetupDataXcapApn() { + initApns(ApnSetting.TYPE_XCAP_STRING, new String[]{ApnSetting.TYPE_XCAP_STRING}); + mDct.enableApn(ApnSetting.TYPE_XCAP, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), + anyBoolean(), any(Message.class)); + } + + // Test the ENTERPRISE APN setup. + @Test + public void testTrySetupDataEnterpriseApn() { + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + sendInitializationEvents(); + + ArgumentCaptor tdCaptor = + ArgumentCaptor.forClass(TrafficDescriptor.class); + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), + anyBoolean(), any(Message.class)); + assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName()); + assertEquals(null, tdCaptor.getValue().getOsAppId()); + + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + SetupDataCallResult result = createSetupDataCallResult(); + result.cid = 10; + mSimulatedCommands.setDataCallResult(true, result); + mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForMs(200); + + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), + anyBoolean(), any(Message.class)); + assertEquals(null, tdCaptor.getValue().getDataNetworkName()); + assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), + tdCaptor.getValue().getOsAppId())); + } + + // Test the ENTERPRISE APN setup when default data is not set up yet. + @Test + public void testTrySetupDataEnterpriseApnNoDefaultData() { + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); + sendInitializationEvents(); + + ArgumentCaptor tdCaptor = + ArgumentCaptor.forClass(TrafficDescriptor.class); + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), + anyBoolean(), any(Message.class)); + assertEquals(null, tdCaptor.getValue().getDataNetworkName()); + assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), + tdCaptor.getValue().getOsAppId())); + + // Check APN contexts with no DEFAULT set up + Map apnContexts = mDct.getApnContexts() + .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); + assertEquals(DctConstants.State.IDLE, apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); + assertEquals(DctConstants.State.FAILED, + apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); + + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + waitForMs(200); + + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), + anyBoolean(), any(Message.class)); + assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName()); + assertEquals(null, tdCaptor.getValue().getOsAppId()); + + // Check APN contexts after DEFAULT is set up (and ENTERPRISE failure) + apnContexts = mDct.getApnContexts() + .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); + assertEquals(DctConstants.State.CONNECTED, + apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); + assertEquals(DctConstants.State.FAILED, + apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); + + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + SetupDataCallResult result = createSetupDataCallResult(); + result.cid = 10; + mSimulatedCommands.setDataCallResult(true, result); + mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + waitForMs(200); + + verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( + eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), + anyBoolean(), any(Message.class)); + assertEquals(null, tdCaptor.getValue().getDataNetworkName()); + assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), + tdCaptor.getValue().getOsAppId())); + + // Check APN contexts after DEFAULT is set up (and ENTERPRISE reenabled) + apnContexts = mDct.getApnContexts() + .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); + assertEquals(DctConstants.State.CONNECTED, + apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); + assertEquals(DctConstants.State.CONNECTED, + apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); + } + + // Test the ENTERPRISE APN setup when the same CID is returned. + @Test + public void testTrySetupDataEnterpriseApnDuplicateCid() { + mApnSettingContentProvider.setFakeApn1NetworkTypeBitmask( + NETWORK_TYPE_LTE_BITMASK | NETWORK_TYPE_NR_BITMASK); + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + // mSimulatedCommandsVerifier will return the same CID in SetupDataCallResult + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); + sendInitializationEvents(); + waitForMs(200); + + ArgumentCaptor tdCaptor = + ArgumentCaptor.forClass(TrafficDescriptor.class); + verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( + eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), + anyBoolean(), any(Message.class)); + List tds = tdCaptor.getAllValues(); + // [0] is default and [1] is enterprise, since default should be set up first + assertEquals(FAKE_APN1, tds.get(0).getDataNetworkName()); + assertEquals(null, tds.get(0).getOsAppId()); + assertEquals(null, tds.get(1).getDataNetworkName()); + assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), tds.get(1).getOsAppId())); + + // Check APN contexts after DEFAULT and ENTERPRISE set up + Map apnContexts = mDct.getApnContexts() + .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); + assertEquals(DctConstants.State.CONNECTED, + apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); + assertEquals(DctConstants.State.FAILED, + apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); + } + + @Test + @SmallTest + public void testGetDataConnectionState() { + initApns(ApnSetting.TYPE_SUPL_STRING, + new String[]{ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_DEFAULT_STRING}); + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + mDct.enableApn(ApnSetting.TYPE_SUPL, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + // Assert that both APN_TYPE_SUPL & APN_TYPE_DEFAULT are connected even we only setup data + // for APN_TYPE_SUPL + assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_SUPL_STRING)); + assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); + } + + // Test the unmetered APN setup when data is disabled. + @Test + @SmallTest + public void testTrySetupDataUnmeteredDataDisabled() { + initApns(ApnSetting.TYPE_SUPL_STRING, new String[]{ApnSetting.TYPE_SUPL_STRING}); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_FOTA_STRING}); + + mDct.enableApn(ApnSetting.TYPE_SUPL, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), any(DataProfile.class), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + } + + // Test the unmetered default APN setup when data is disabled. Default APN should always honor + // the users's setting. + @Test + @SmallTest + public void testTrySetupDataUnmeteredDefaultDataDisabled() { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_MMS_STRING}); + + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + verify(mSimulatedCommandsVerifier, never()).setupDataCall( + eq(AccessNetworkType.EUTRAN), any(DataProfile.class), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + } + + + // Test the metered APN setup when data is disabled. + @Test + @SmallTest + public void testTrySetupMeteredDataDisabled() { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + } + + // Test the restricted data request when data is disabled. + @Test + @SmallTest + public void testTrySetupRestrictedDataDisabled() { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + + sendInitializationEvents(); + + NetworkRequest nr = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .build(); + mDct.requestNetwork(nr, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(anyInt(), any(DataProfile.class), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + } + + // Test the restricted data request when roaming is disabled. + @Test + @SmallTest + public void testTrySetupRestrictedRoamingDisabled() { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + + mDct.setDataRoamingEnabledByUser(false); + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + //user is in roaming + doReturn(true).when(mServiceState).getDataRoaming(); + + sendInitializationEvents(); + + NetworkRequest nr = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .build(); + mDct.requestNetwork(nr, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(anyInt(), any(DataProfile.class), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + } + + // Test the default data when data is not connectable. + @Test + @SmallTest + public void testTrySetupNotConnectable() { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + doReturn(false).when(mApnContext).isConnectable(); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + + sendInitializationEvents(); + + verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + } + + // Test the default data on IWLAN. + @Test + @SmallTest + public void testTrySetupDefaultOnIWLAN() { + doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + + sendInitializationEvents(); + + verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + } + + // Test the default data when the phone is in ECBM. + @Test + @SmallTest + public void testTrySetupDefaultInECBM() { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + doReturn(true).when(mPhone).isInEcm(); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + + sendInitializationEvents(); + + verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + } + + // Test update waiting apn list when on data rat change + @FlakyTest /* flakes 0.86% of the time */ + @Ignore + @Test + @SmallTest + public void testUpdateWaitingApnListOnDataRatChange() { + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + // Verify if RIL command was sent properly. + verify(mSimulatedCommandsVerifier).setupDataCall( + eq(AccessNetworkType.CDMA2000), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK); + assertTrue(mDct.isAnyDataConnected()); + + //data rat change from ehrpd to lte + logd("Sending EVENT_DATA_RAT_CHANGED"); + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + // Verify the disconnected data call due to rat change and retry manger schedule another + // data call setup + verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( + eq(DataService.REQUEST_REASON_NORMAL), anyInt(), + any(Message.class)); + verify(mAlarmManager, times(1)).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), + anyLong(), any(PendingIntent.class)); + + //Send event for reconnecting data + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RECONNECT, + mPhone.getPhoneId(), DcTracker.RELEASE_TYPE_NORMAL, mApnContext)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + // Verify if RIL command was sent properly. + verify(mSimulatedCommandsVerifier).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + assertTrue(mDct.isAnyDataConnected()); + } + + /** + * Test that fetchDunApns() returns list that prioritize the preferred APN when the preferred + * APN including DUN type. + */ + @Test + public void testFetchDunApnWithPreferredApn() { + // Set support APN types of FAKE_APN1 and FAKE_APN5 + mApnSettingContentProvider.setFakeApn1Types("default,dun"); + mApnSettingContentProvider.setFakeApn5Types("default,dun"); + + // Set prefer apn set id. + ContentResolver cr = mContext.getContentResolver(); + ContentValues values = new ContentValues(); + values.put(Telephony.Carriers.APN_SET_ID, 0); + cr.update(PREFERAPN_URI, values, null, null); + // Set FAKE_APN5 as the preferred APN. + mApnSettingContentProvider.setFakePreferredApn(mApnSettingContentProvider.getFakeApn5()); + + sendInitializationEvents(); + + // Return the APN list that set the preferred APN at the top. + ArrayList dunApns = mDct.fetchDunApns(); + assertEquals(2, dunApns.size()); + assertEquals(FAKE_APN5, dunApns.get(0).getApnName()); + assertEquals(FAKE_APN1, dunApns.get(1).getApnName()); + } + + // This tests simulates the race case where the sim status change event is triggered, the + // default data connection is attached, and then the carrier config gets changed which bumps + // the database id which we want to ignore when cleaning up connections and matching against + // the dun APN. Tests b/158908392. + @Test + @SmallTest + public void testCheckForCompatibleDataConnectionWithDunWhenIdsChange() { + //Set dun as a support apn type of FAKE_APN1 + mApnSettingContentProvider.setFakeApn1Types("default,supl,dun"); + + // Enable the default apn + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + //Load the sim and attach the data connection without firing the carrier changed event + final String logMsgPrefix = "testCheckForCompatibleDataConnectionWithDunWhenIdsChange: "; + sendSimStateUpdated(logMsgPrefix); + sendEventDataConnectionAttached(logMsgPrefix); + waitForMs(200); + + // Confirm that FAKE_APN1 comes up as a dun candidate + ApnSetting dunApn = mDct.fetchDunApns().get(0); + assertEquals(dunApn.getApnName(), FAKE_APN1); + Map apnContexts = mDct.getApnContexts() + .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); + + //Double check that the default apn content is connected while the dun apn context is not + assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getState(), + DctConstants.State.CONNECTED); + assertNotEquals(apnContexts.get(ApnSetting.TYPE_DUN).getState(), + DctConstants.State.CONNECTED); + + + //Change the row ids the same way as what happens when we have old apn values in the + //carrier table + mApnSettingContentProvider.setRowIdOffset(100); + sendCarrierConfigChanged(logMsgPrefix); + waitForMs(200); + + mDct.enableApn(ApnSetting.TYPE_DUN, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + Map apnContextsAfterRowIdsChanged = mDct.getApnContexts() + .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); + + //Make sure that the data connection used earlier wasn't cleaned up and still in use. + assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), + apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DEFAULT).getDataConnection()); + + //Check that the DUN is using the same active data connection + assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), + apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DUN).getDataConnection()); + } + + @Test + @SmallTest + public void testCheckForCompatibleDataConnectionWithEnterprise() { + // Allow both DEFAULT and ENTERPRISE to use APN 1 + mApnSettingContentProvider.setFakeApn1NetworkTypeBitmask( + NETWORK_TYPE_LTE_BITMASK | NETWORK_TYPE_NR_BITMASK); + + // Enable the DEFAULT APN + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + sendInitializationEvents(); + + ArgumentCaptor tdCaptor = + ArgumentCaptor.forClass(TrafficDescriptor.class); + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), + anyBoolean(), any(Message.class)); + assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName()); + assertEquals(null, tdCaptor.getValue().getOsAppId()); + + // Check APN contexts after DEFAULT is set up + Map apnContexts = mDct.getApnContexts() + .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); + assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getState(), + DctConstants.State.CONNECTED); + assertNotEquals(apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState(), + DctConstants.State.CONNECTED); + + // Enable the ENTERPRISE APN + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + SetupDataCallResult result = createSetupDataCallResult(); + result.cid = 10; + mSimulatedCommands.setDataCallResult(true, result); + mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForMs(200); + + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), + eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), + anyBoolean(), any(Message.class)); + assertEquals(null, tdCaptor.getValue().getDataNetworkName()); + assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), + tdCaptor.getValue().getOsAppId())); + + // Check APN contexts after ENTERPRISE is set up + Map apnContextsAfterRowIdsChanged = mDct.getApnContexts() + .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); + + // Make sure that the data connection used earlier wasn't cleaned up and still in use. + assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), + apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DEFAULT).getDataConnection()); + + // Check that ENTERPRISE isn't using the same data connection as DEFAULT + assertNotEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), + apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_ENTERPRISE).getDataConnection()); + } + + // Test for Data setup with APN Set ID + @Test + @SmallTest + public void testDataSetupWithApnSetId() throws Exception { + // Set the prefer apn set id to "1" + ContentResolver cr = mContext.getContentResolver(); + ContentValues values = new ContentValues(); + values.put(Telephony.Carriers.APN_SET_ID, 1); + cr.update(PREFERAPN_URI, values, null, null); + + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + + List dataProfiles = dpCaptor.getAllValues(); + assertEquals(2, dataProfiles.size()); + + // Verify to use FAKE APN7 which is Default APN with apnSetId=1(Same as the pereferred + // APN's set id). + Optional fakeApn7 = dataProfiles.stream() + .filter(dp -> dp.getApn().equals(FAKE_APN7)).findFirst(); + assertTrue(fakeApn7.isPresent()); + verifyDataProfile(fakeApn7.get(), FAKE_APN7, 0, 17, 1, NETWORK_TYPE_LTE_BITMASK); + + // Verify to use FAKE APN8 which is IMS APN with apnSetId=-1 + // (Telephony.Carriers.MATCH_ALL_APN_SET_ID). + Optional fakeApn8 = dataProfiles.stream() + .filter(dp -> dp.getApn().equals(FAKE_APN8)).findFirst(); + assertTrue(fakeApn8.isPresent()); + verifyDataProfile(fakeApn8.get(), FAKE_APN8, 2, 64, 1, NETWORK_TYPE_LTE_BITMASK); + } + + // Test oos + @Test + @SmallTest + public void testDataRatChangeOOS() { + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING}); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + // Verify if RIL command was sent properly. + verify(mSimulatedCommandsVerifier).setupDataCall( + eq(AccessNetworkType.CDMA2000), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK); + assertTrue(mDct.isAnyDataConnected()); + + // Data rat change from ehrpd to unknown due to OOS + logd("Sending EVENT_DATA_RAT_CHANGED"); + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UNKNOWN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + // Verify data connection is on + verify(mSimulatedCommandsVerifier, times(0)).deactivateDataCall( + eq(DataService.REQUEST_REASON_NORMAL), anyInt(), + any(Message.class)); + + // Data rat resume from unknown to ehrpd + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Verify the same data connection + assertEquals(FAKE_APN4, mDct.getActiveApnString(ApnSetting.TYPE_DEFAULT_STRING)); + assertTrue(mDct.isAnyDataConnected()); + } + + // Test provisioning + /*@Test + @SmallTest + public void testDataEnableInProvisioning() throws Exception { + ContentResolver resolver = mContext.getContentResolver(); + + assertEquals(1, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA)); + assertTrue(mDct.isDataEnabled()); + assertTrue(mDct.isUserDataEnabled()); + + mDct.setUserDataEnabled(false); + waitForMs(200); + + assertEquals(0, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA)); + assertFalse(mDct.isDataEnabled()); + assertFalse(mDct.isUserDataEnabled()); + + // Changing provisioned to 0. + Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null)); + waitForMs(200); + + assertTrue(mDct.isDataEnabled()); + assertTrue(mDct.isUserDataEnabled()); + + // Enable user data during provisioning. It should write to + // Settings.Global.MOBILE_DATA and keep data enabled when provisioned. + mDct.setUserDataEnabled(true); + Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 1); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null)); + waitForMs(200); + + assertTrue(mDct.isDataEnabled()); + assertTrue(mDct.isUserDataEnabled()); + assertEquals(1, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA)); + }*/ + + /* + @Test + @SmallTest + public void testNotifyDataEnabledChanged() throws Exception { + doAnswer(invocation -> { + mMessage = (Message) invocation.getArguments()[0]; + return true; + }).when(mHandler).sendMessageDelayed(any(), anyLong()); + + // Test registration. + mDct.registerForDataEnabledChanged(mHandler, DATA_ENABLED_CHANGED, null); + verifyDataEnabledChangedMessage(true, DataEnabledSettings.REASON_REGISTERED); + + // Disable user data. Should receive data enabled change to false. + mDct.setUserDataEnabled(false); + waitForMs(200); + verifyDataEnabledChangedMessage(false, DataEnabledSettings.REASON_USER_DATA_ENABLED); + + // Changing provisioned to 0. Shouldn't receive any message, as data enabled remains false. + ContentResolver resolver = mContext.getContentResolver(); + Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0); + Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, + 0); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null)); + waitForMs(200); + assertFalse(mDct.isDataEnabled()); + verify(mHandler, never()).sendMessageDelayed(any(), anyLong()); + + // Changing provisioningDataEnabled to 1. It should trigger data enabled change to true. + Settings.Global.putInt(resolver, + Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 1); + mDct.sendMessage(mDct.obtainMessage( + DctConstants.EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE, null)); + waitForMs(200); + verifyDataEnabledChangedMessage( + true, DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED); + }*/ + + @Test + @SmallTest + public void testNetworkStatusChangedRecoveryOFF() { + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + logd("Sending EVENT_NETWORK_STATUS_CHANGED"); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, + NetworkAgent.VALID_NETWORK, 1, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + logd("Sending EVENT_NETWORK_STATUS_CHANGED"); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, + NetworkAgent.INVALID_NETWORK, 1, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + waitForMs(200); + + // Verify that its no-op when the new data stall detection feature is disabled + verify(mSimulatedCommandsVerifier, times(0)).getDataCallList(any(Message.class)); + } + + @FlakyTest + @Test + @SmallTest + public void testNetworkStatusChangedRecoveryON() { + ContentResolver resolver = mContext.getContentResolver(); + Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); + Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 0); + doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + logd("Sending EVENT_NETWORK_STATUS_CHANGED"); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, + NetworkAgent.VALID_NETWORK, 1, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + logd("Sending EVENT_NETWORK_STATUS_CHANGED"); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, + NetworkAgent.INVALID_NETWORK, 1, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + verify(mSimulatedCommandsVerifier, times(1)).getDataCallList(any(Message.class)); + } + + @FlakyTest + @Test + @SmallTest + public void testRecoveryStepPDPReset() { + ContentResolver resolver = mContext.getContentResolver(); + Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); + Settings.Global.putLong(resolver, + Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); + Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 1); + doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + logd("Sending EVENT_NETWORK_STATUS_CHANGED false"); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, + NetworkAgent.INVALID_NETWORK, 1, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + waitForMs(200); + + // expected tear down all DataConnections + verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( + eq(DataService.REQUEST_REASON_NORMAL), anyInt(), + any(Message.class)); + } + + + @Test + @SmallTest + public void testRecoveryStepReRegister() { + ContentResolver resolver = mContext.getContentResolver(); + Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); + Settings.Global.putLong(resolver, + Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); + Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 2); + doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); + doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + logd("Sending EVENT_NETWORK_STATUS_CHANGED false"); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, + NetworkAgent.INVALID_NETWORK, 1, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // expected to get preferred network type + verify(mSST, times(1)).reRegisterNetwork(eq(null)); + } + + @Test + @SmallTest + public void testRecoveryStepRestartRadio() { + ContentResolver resolver = mContext.getContentResolver(); + Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); + Settings.Global.putLong(resolver, + Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); + Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 3); + doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); + doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + logd("Sending EVENT_NETWORK_STATUS_CHANGED false"); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, + NetworkAgent.INVALID_NETWORK, 1, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // expected to get preferred network type + verify(mSST, times(1)).powerOffRadioSafely(); + } + + private void verifyDataEnabledChangedMessage(boolean enabled, int reason) { + verify(mHandler, times(1)).sendMessageDelayed(any(), anyLong()); + Pair result = (Pair) ((AsyncResult) mMessage.obj).result; + assertEquals(DATA_ENABLED_CHANGED, mMessage.what); + assertEquals(enabled, result.first); + assertEquals(reason, (int) result.second); + clearInvocations(mHandler); + } + + private void setUpSubscriptionPlans(boolean isNrUnmetered) throws Exception { + List plans = new ArrayList<>(); + if (isNrUnmetered) { + plans.add(SubscriptionPlan.Builder + .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), + Period.ofMonths(1)) + .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED, + SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED) + .setNetworkTypes(new int[] {TelephonyManager.NETWORK_TYPE_NR}) + .build()); + } + plans.add(SubscriptionPlan.Builder + .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), + Period.ofMonths(1)) + .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) + .setDataUsage(500_000_000, System.currentTimeMillis()) + .build()); + replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, plans); + doReturn(plans.toArray(new SubscriptionPlan[0])).when(mNetworkPolicyManager) + .getSubscriptionPlans(anyInt(), any()); + } + + private void resetSubscriptionPlans() throws Exception { + replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, null); + } + + private void setUpSubscriptionOverride(int[] networkTypes, boolean isUnmetered) + throws Exception { + List networkTypesList = null; + if (networkTypes != null) { + networkTypesList = new ArrayList<>(); + for (int networkType : networkTypes) { + networkTypesList.add(networkType); + } + } + replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, networkTypesList); + replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, isUnmetered); + } + + private void resetSubscriptionOverride() throws Exception { + replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, null); + replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, false); + } + + private boolean isNetworkTypeUnmetered(int networkType) throws Exception { + Method method = DcTracker.class.getDeclaredMethod( + "isNetworkTypeUnmetered", int.class); + method.setAccessible(true); + return (boolean) method.invoke(mDct, networkType); + } + + private int setUpDataConnection() throws Exception { + Field dc = DcTracker.class.getDeclaredField("mDataConnections"); + dc.setAccessible(true); + Field uig = DcTracker.class.getDeclaredField("mUniqueIdGenerator"); + uig.setAccessible(true); + int id = ((AtomicInteger) uig.get(mDct)).getAndIncrement(); + ((HashMap) dc.get(mDct)).put(id, mDataConnection); + return id; + } + + private void resetDataConnection(int id) throws Exception { + Field dc = DcTracker.class.getDeclaredField("mDataConnections"); + dc.setAccessible(true); + ((HashMap) dc.get(mDct)).remove(id); + } + + private void setUpWatchdogTimer() { + // Watchdog active for 10s + mBundle.putLong(CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG, 10000); + Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); + mContext.sendBroadcast(intent); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + } + + private boolean getWatchdogStatus() throws Exception { + Field field = DcTracker.class.getDeclaredField(("mWatchdog")); + field.setAccessible(true); + return (boolean) field.get(mDct); + } + + private Map> getHandoverCompletionMessages() throws Exception { + Field field = DcTracker.class.getDeclaredField(("mHandoverCompletionMsgs")); + field.setAccessible(true); + return (Map>) field.get(mDct); + } + + private void setUpTempNotMetered() { + doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR) + .when(mPhone).getRadioAccessFamily(); + doReturn(1).when(mPhone).getSubId(); + mBundle.putBoolean(CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, true); + Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); + mContext.sendBroadcast(intent); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + } + + @Test + public void testIsNetworkTypeUnmetered() throws Exception { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + + // only 5G unmetered + setUpSubscriptionOverride(new int[]{TelephonyManager.NETWORK_TYPE_NR}, true); + + assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); + assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); + assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); + + // all network types metered + setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), false); + + assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); + assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); + assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); + + // all network types unmetered + setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), true); + + assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); + assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); + assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); + + resetSubscriptionOverride(); + } + + @Test + public void testIsNetworkTypeUnmeteredViaSubscriptionPlans() throws Exception { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + + // only 5G unmetered + setUpSubscriptionPlans(true); + + assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); + assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); + assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); + + // all network types metered + setUpSubscriptionPlans(false); + + assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); + assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); + assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); + + // all network types unmetered + List plans = new ArrayList<>(); + plans.add(SubscriptionPlan.Builder + .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), + Period.ofMonths(1)) + .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED, + SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED) + .build()); + replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, plans); + + assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); + assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); + assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); + + resetSubscriptionPlans(); + } + + @Test + public void testIsNrUnmeteredSubscriptionPlans() throws Exception { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + int id = setUpDataConnection(); + setUpSubscriptionPlans(false); + setUpWatchdogTimer(); + doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) + .when(mDisplayInfoController).getTelephonyDisplayInfo(); + setUpTempNotMetered(); + clearInvocations(mDataConnection); + + // NetCapability should be metered when connected to 5G with no unmetered plan or frequency + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + verify(mDataConnection, times(1)).onMeterednessChanged(false); + + // Set SubscriptionPlans unmetered + setUpSubscriptionPlans(true); + + // NetCapability should switch to unmetered with an unmetered plan + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + verify(mDataConnection, times(1)).onMeterednessChanged(true); + + // Set MMWAVE frequency to unmetered + mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, true); + Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); + mContext.sendBroadcast(intent); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + clearInvocations(mDataConnection); + + // NetCapability should switch to metered without fr=MMWAVE + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + verify(mDataConnection, times(1)).onMeterednessChanged(false); + + // NetCapability should switch to unmetered with fr=MMWAVE + doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED)) + .when(mDisplayInfoController).getTelephonyDisplayInfo(); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + verify(mDataConnection, times(1)).onMeterednessChanged(true); + + resetDataConnection(id); + resetSubscriptionPlans(); + } + + @Test + public void testIsNrUnmeteredCarrierConfigs() throws Exception { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + int id = setUpDataConnection(); + setUpSubscriptionPlans(false); + setUpWatchdogTimer(); + doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) + .when(mDisplayInfoController).getTelephonyDisplayInfo(); + setUpTempNotMetered(); + clearInvocations(mDataConnection); + + // NetCapability should be metered when connected to 5G with no unmetered plan or frequency + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + verify(mDataConnection, times(1)).onMeterednessChanged(false); + + // Set MMWAVE frequency to unmetered + mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_BOOL, true); + mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, true); + Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); + mContext.sendBroadcast(intent); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + clearInvocations(mDataConnection); + + // NetCapability should switch to unmetered when fr=MMWAVE and MMWAVE unmetered + doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED)) + .when(mDisplayInfoController).getTelephonyDisplayInfo(); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + verify(mDataConnection, times(1)).onMeterednessChanged(true); + + // NetCapability should switch to metered when fr=SUB6 and MMWAVE unmetered + doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) + .when(mDisplayInfoController).getTelephonyDisplayInfo(); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + verify(mDataConnection, times(1)).onMeterednessChanged(false); + + // Set SUB6 frequency to unmetered + doReturn(2).when(mPhone).getSubId(); + mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false); + mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_SUB6_BOOL, true); + intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); + mContext.sendBroadcast(intent); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + clearInvocations(mDataConnection); + + // NetCapability should switch to unmetered when fr=SUB6 and SUB6 unmetered + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + verify(mDataConnection, times(1)).onMeterednessChanged(true); + + resetDataConnection(id); + resetSubscriptionPlans(); + } + + @Test + public void testReevaluateUnmeteredConnectionsOnNetworkChange() throws Exception { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + int id = setUpDataConnection(); + setUpSubscriptionPlans(true); + setUpWatchdogTimer(); + setUpTempNotMetered(); + clearInvocations(mDataConnection); + + // NetCapability should be unmetered when connected to 5G + doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) + .when(mDisplayInfoController).getTelephonyDisplayInfo(); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + verify(mDataConnection, times(1)).onMeterednessChanged(true); + + // NetCapability should be metered when disconnected from 5G + doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) + .when(mDisplayInfoController).getTelephonyDisplayInfo(); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + verify(mDataConnection, times(1)).onMeterednessChanged(false); + + resetDataConnection(id); + resetSubscriptionPlans(); + } + + @Test + public void testReevaluateUnmeteredConnectionsOnWatchdog() throws Exception { + initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); + int id = setUpDataConnection(); + setUpSubscriptionPlans(true); + setUpWatchdogTimer(); + + // Watchdog inactive when unmetered and not connected to 5G + doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) + .when(mDisplayInfoController).getTelephonyDisplayInfo(); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NR_TIMER_WATCHDOG)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + assertFalse(getWatchdogStatus()); + + // Watchdog active when unmetered and connected to 5G + doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) + .when(mDisplayInfoController).getTelephonyDisplayInfo(); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + assertTrue(getWatchdogStatus()); + + // Watchdog inactive when metered + setUpSubscriptionPlans(false); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + assertFalse(getWatchdogStatus()); + + resetDataConnection(id); + resetSubscriptionPlans(); + } + + /** + * Test if this is a path prefix match against the given Uri. Verifies that + * scheme, authority, and atomic path segments match. + * + * Copied from frameworks/base/core/java/android/net/Uri.java + */ + private boolean isPathPrefixMatch(Uri uriA, Uri uriB) { + if (!Objects.equals(uriA.getScheme(), uriB.getScheme())) return false; + if (!Objects.equals(uriA.getAuthority(), uriB.getAuthority())) return false; + + List segA = uriA.getPathSegments(); + List segB = uriB.getPathSegments(); + + final int size = segB.size(); + if (segA.size() < size) return false; + + for (int i = 0; i < size; i++) { + if (!Objects.equals(segA.get(i), segB.get(i))) { + return false; + } + } + + return true; + } + + @Test + public void testNoApnContextsWhenDataIsDisabled() throws java.lang.InterruptedException { + //Check that apn contexts are loaded. + assertTrue(mDct.getApnContexts().size() > 0); + + //Do work normally done in teardown. + mDct.removeCallbacksAndMessages(null); + mDcTrackerTestHandler.quit(); + mDcTrackerTestHandler.join(); + + //Set isDataCapable to false for the new DcTracker being created in DcTrackerTestHandler. + doReturn(false).when(mTelephonyManager).isDataCapable(); + mDcTrackerTestHandler = new DcTrackerTestHandler(getClass().getSimpleName()); + setReady(false); + + mDcTrackerTestHandler.start(); + waitUntilReady(); + assertEquals(0, mDct.getApnContexts().size()); + + //No need to clean up handler because that work is done in teardown. + } + + @Test + public void testRatChanged() throws Exception { + DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); + boolean allowed = mDct.isDataAllowed(dataConnectionReasons); + assertFalse(dataConnectionReasons.toString(), allowed); + + logd("Sending EVENT_ENABLE_APN"); + // APN id 0 is APN_TYPE_DEFAULT + mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); + + sendInitializationEvents(); + + dataConnectionReasons = new DataConnectionReasons(); + allowed = mDct.isDataAllowed(dataConnectionReasons); + assertTrue(dataConnectionReasons.toString(), allowed); + + ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); + // Verify if RIL command was sent properly. + verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( + eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), + eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); + + verifyDataConnected(FAKE_APN1); + + doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS).when(mServiceState) + .getRilDataRadioTechnology(); + + logd("Sending EVENT_DATA_RAT_CHANGED"); + mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( + anyInt(), anyInt()); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Data connection is running on a different thread. Have to wait. + waitForMs(200); + // expected tear down all metered DataConnections + verify(mSimulatedCommandsVerifier).deactivateDataCall( + eq(DataService.REQUEST_REASON_NORMAL), anyInt(), + any(Message.class)); + } + + @Test + public void testApnConfigRepositoryUpdatedOnCarrierConfigChange() { + assertPriority(ApnSetting.TYPE_CBS_STRING, 2); + assertPriority(ApnSetting.TYPE_MMS_STRING, 2); + + mBundle.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, + new String[] { + ApnSetting.TYPE_CBS_STRING + ":11", + ApnSetting.TYPE_MMS_STRING + ":19", + }); + + sendInitializationEvents(); + + Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); + mContext.sendBroadcast(intent); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + assertPriority(ApnSetting.TYPE_CBS_STRING, 11); + assertPriority(ApnSetting.TYPE_MMS_STRING, 19); + + //Ensure apns are in sorted order. + ApnContext lastApnContext = null; + for (ApnContext apnContext : mDct.getApnContexts()) { + if (lastApnContext != null) { + assertTrue(apnContext.getPriority() <= lastApnContext.getPriority()); + } + lastApnContext = apnContext; + } + } + + private void assertPriority(String type, int priority) { + assertEquals(priority, mDct.getApnContexts().stream() + .filter(x -> x.getApnType().equals(type)) + .findFirst().get().getPriority()); + } + + @Test + public void testProvisionBroadcastReceiver() { + Intent intent = new Intent("com.android.internal.telephony.PROVISION"); + intent.putExtra("provision.phone.id", mPhone.getPhoneId()); + try { + mContext.sendBroadcast(intent); + } catch (SecurityException e) { + fail(); + } + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + } + + @Test + public void testRetryHandoverWhenDisconnecting() throws Exception { + initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); + setUpDataConnection(); + SparseArray apnContextsByType = Mockito.mock(SparseArray.class); + ConcurrentHashMap apnContexts = Mockito.mock(ConcurrentHashMap.class); + doReturn(mApnContext).when(apnContextsByType).get(eq(ApnSetting.TYPE_IMS)); + doReturn(mApnContext).when(apnContexts).get(eq(ApnSetting.TYPE_IMS_STRING)); + doReturn(false).when(mApnContext).isConnectable(); + doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); + doReturn(DctConstants.State.DISCONNECTING).when(mApnContext).getState(); + replaceInstance(DcTracker.class, "mApnContextsByType", mDct, apnContextsByType); + replaceInstance(DcTracker.class, "mApnContexts", mDct, apnContexts); + + sendInitializationEvents(); + + logd("Sending EVENT_ENABLE_APN"); + // APN id 0 is APN_TYPE_DEFAULT + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER, + mDct.obtainMessage(12345)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + assertTrue(isHandoverPending(ApnSetting.TYPE_IMS)); + + // Verify no handover request was sent + verify(mDataConnection, never()).bringUp(any(ApnContext.class), anyInt(), anyInt(), + any(Message.class), anyInt(), anyInt(), anyInt(), anyBoolean()); + + doReturn(DctConstants.State.RETRYING).when(mApnContext).getState(); + // Data now is disconnected + doReturn(true).when(mApnContext).isConnectable(); + doReturn(true).when(mDataEnabledSettings).isDataEnabled(anyInt()); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, + new AsyncResult(Pair.create(mApnContext, 0), null, null))); + + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + verify(mDataConnection).bringUp(any(ApnContext.class), anyInt(), anyInt(), + any(Message.class), anyInt(), eq(DcTracker.REQUEST_TYPE_HANDOVER), anyInt(), + anyBoolean()); + } + + @Test + public void testDataUnthrottled() throws Exception { + initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); + replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + sendInitializationEvents(); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_APN_UNTHROTTLED, + new AsyncResult(null, FAKE_APN3, null))); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + verify(mDataThrottler).setRetryTime( + eq(ApnSetting.TYPE_IMS), + eq(RetryManager.NO_SUGGESTED_RETRY_DELAY), + eq(DcTracker.REQUEST_TYPE_NORMAL)); + } + + @Test + public void testDataUnthrottledAfterAPNChanged() throws Exception { + initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); + replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); + + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + sendInitializationEvents(); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_APN_CHANGED, null)); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + + // Verify unthrottling + verify(mDataThrottler, times(2)).reset(); + } + + @Test + public void testDataUnthrottledOnSimStateChanged() throws Exception { + initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); + replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); + + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + sendInitializationEvents(); + sendSimStateUpdated("testDataUnthrottledOnSimStateChanged"); + + // Verify unthrottling + verify(mDataThrottler, times(2)).reset(); + } + + @Test + public void testHandlingSecondHandoverRequest() throws Exception { + initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); + setUpDataConnection(); + SparseArray apnContextsByType = Mockito.mock(SparseArray.class); + ConcurrentHashMap apnContexts = Mockito.mock(ConcurrentHashMap.class); + doReturn(mApnContext).when(apnContextsByType).get(eq(ApnSetting.TYPE_IMS)); + doReturn(mApnContext).when(apnContexts).get(eq(ApnSetting.TYPE_IMS_STRING)); + doReturn(false).when(mApnContext).isConnectable(); + doReturn(DctConstants.State.CONNECTING).when(mApnContext).getState(); + replaceInstance(DcTracker.class, "mApnContextsByType", mDct, apnContextsByType); + replaceInstance(DcTracker.class, "mApnContexts", mDct, apnContexts); + + sendInitializationEvents(); + + logd("Sending EVENT_ENABLE_APN"); + // APN id 0 is APN_TYPE_DEFAULT + Message msg = mDct.obtainMessage(12345); + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER, msg); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + Map> msgs = getHandoverCompletionMessages(); + // Make sure the messages was queued properly instead of fired right away. + assertTrue(msgs.get(ApnSetting.TYPE_IMS).contains(msg)); + } + + @Test + public void testDataThrottledNotAllowData() throws Exception { + initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); + replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); + doReturn(SystemClock.elapsedRealtime() + 100000).when(mDataThrottler) + .getRetryTime(ApnSetting.TYPE_IMS); + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + sendInitializationEvents(); + + DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); + boolean allowed = mDct.isDataAllowed(mApnContext, DcTracker.REQUEST_TYPE_NORMAL, + dataConnectionReasons); + assertFalse(dataConnectionReasons.toString(), allowed); + assertTrue(dataConnectionReasons.contains(DataDisallowedReasonType.DATA_THROTTLED)); + + // Makre sure no data setup request + verify(mSimulatedCommandsVerifier, never()).setupDataCall( + anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); + } + + @Test + public void testNotifyDataDisconnected() { + // Verify notify data disconnected on DCT constructor, initialized in setUp() + ArgumentCaptor captor = + ArgumentCaptor.forClass(PreciseDataConnectionState.class); + verify(mPhone, times(13)).notifyDataConnection(captor.capture()); + for (PreciseDataConnectionState state : captor.getAllValues()) { + assertEquals(TelephonyManager.DATA_DISCONNECTED, state.getState()); + } + } + + /** + * There is a corresponding test {@link DataConnectionTest#testDataServiceTempUnavailable()} to + * test DataConnection behavior. + */ + @Test + public void testDataServiceTempUnavailable() { + Handler handler = Mockito.mock(Handler.class); + Message handoverCompleteMessage = Message.obtain(handler); + addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS); + initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); + mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_SETUP_COMPLETE, + DcTracker.REQUEST_TYPE_HANDOVER, DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, + new AsyncResult(Pair.create(mApnContext, 0), + DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE, new Exception()))); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + // Ensure handover is not completed yet + verify(handler, never()).sendMessageDelayed(any(), anyLong()); + } + + @Test + public void testNormalRequestDoesNotFailHandoverRequest() { + Handler handler = Mockito.mock(Handler.class); + Message handoverCompleteMessage = Message.obtain(handler); + addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS); + initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + // Ensure handover is not completed yet + verify(handler, never()).sendMessageDelayed(any(), anyLong()); + } + + @Test + public void testPreferenceChangedFallback() { + Handler handler = Mockito.mock(Handler.class); + doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) + .getPreferredTransport(anyInt()); + Message handoverCompleteMessage = Message.obtain(handler); + addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS); + initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); + mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER, + handoverCompleteMessage); + waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); + Bundle bundle = handoverCompleteMessage.getData(); + assertTrue(bundle.getBoolean("extra_handover_failure_fallback")); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java new file mode 100644 index 0000000000..4acfefb2a9 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java @@ -0,0 +1,996 @@ +/** + * Copyright (C) 2015 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.dataconnection; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; + +import android.os.PersistableBundle; +import android.os.SystemClock; +import android.telephony.CarrierConfigManager; +import android.telephony.data.ApnSetting; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.internal.telephony.RetryManager; +import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.uicc.UiccController; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; + +/** + * APN retry manager tests + */ +public class RetryManagerTest extends TelephonyTest { + + // This is the real APN data for the Japanese carrier NTT Docomo. + private final ApnSetting mApn1 = new ApnSetting.Builder() + .setId(2163) + .setOperatorNumeric("44010") + .setEntryName("sp-mode") + .setApnName("spmode.ne.jp") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) + .setProtocol(ApnSetting.PROTOCOL_IP) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .build(); + + private final ApnSetting mApn2 = new ApnSetting.Builder() + .setId(2164) + .setOperatorNumeric("44010") + .setEntryName("mopera U") + .setApnName("mopera.net") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) + .setProtocol(ApnSetting.PROTOCOL_IP) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .build(); + + private final ApnSetting mApn3 = new ApnSetting.Builder() + .setId(2165) + .setOperatorNumeric("44010") + .setEntryName("b-mobile for Nexus") + .setApnName("bmobile.ne.jp") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) + .setProtocol(ApnSetting.PROTOCOL_IP) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .build(); + + private PersistableBundle mBundle; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + mBundle = mContextFixture.getCarrierConfigBundle(); + doReturn(false).when(mPhone).isUsingNewDataStack(); + replaceInstance(SubscriptionController.class, "sInstance", null, mSubscriptionController); + replaceInstance(UiccController.class, "mInstance", null, mUiccController); + } + + @After + public void tearDown() throws Exception { + mBundle = null; + super.tearDown(); + } + + /** + * Test the behavior of a retry manager with no waiting APNs set. + */ + @Test + @SmallTest + public void testRetryManagerEmpty() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"default:2000"}); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); + + long delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn == null); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the basic retry scenario where only one APN and no retry configured. + */ + @Test + @SmallTest + public void testRetryManagerOneApnNoRetry() throws Exception { + + mBundle.putStringArray( + CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"default:"}); + + ArrayList waitingApns = new ArrayList(); + waitingApns.add(ApnSetting.makeApnSetting(mApn1)); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the basic retry scenario where only one APN with two retries configured. + */ + @Test + @SmallTest + public void testRetryManagerOneApnTwoRetries() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"supl:2000,3000"}); + + ArrayList waitingApns = new ArrayList(); + waitingApns.add(ApnSetting.makeApnSetting(mApn1)); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_SUPL); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(3000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + + // No matter how many times we call getNextApnSetting, it should always return the next APN + // with NO_RETRY because we've already reached the maximum retry count. + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the basic retry scenario where two waiting APNs with one retry configured. + */ + @Test + @SmallTest + public void testRetryManagerTwoApnsOneRetry() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"others:2000"}); + + ArrayList waitingApns = new ArrayList(); + waitingApns.add(ApnSetting.makeApnSetting(mApn1)); + waitingApns.add(ApnSetting.makeApnSetting(mApn2)); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the basic retry scenario where two waiting APNs with two retries configured. + */ + @Test + @SmallTest + public void testRetryManagerTwoApnsTwoRetries() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"dun:2000,5000"}); + + ArrayList waitingApns = new ArrayList(); + waitingApns.add(ApnSetting.makeApnSetting(mApn1)); + waitingApns.add(ApnSetting.makeApnSetting(mApn2)); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DUN); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(5000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the basic retry scenario where two mms APNs with two retries configured. + */ + @Test + @SmallTest + public void testRetryManagerTwoMmsApnsTwoRetries() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"mms: 3000,6000"}); + + ArrayList waitingApns = new ArrayList(); + waitingApns.add(ApnSetting.makeApnSetting(mApn1)); + waitingApns.add(ApnSetting.makeApnSetting(mApn2)); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_MMS); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(3000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(6000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the permanent fail scenario with one APN configured. + */ + @Test + @SmallTest + public void testRetryManagerApnPermanentFailed() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"fota:1000,4000,7000"}); + + ArrayList waitingApns = new ArrayList(); + ApnSetting apn = ApnSetting.makeApnSetting(mApn1); + waitingApns.add(apn); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_FOTA); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(1000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(4000, delay); + + rm.markApnPermanentFailed(apn); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn == null); + } + + /** + * Test the permanent fail scenario with two APNs configured. + */ + @Test + @SmallTest + public void testRetryManagerApnPermanentFailedWithTwoApns() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"mms : 1000,4000,7000"}); + + ArrayList waitingApns = new ArrayList(); + ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); + ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); + waitingApns.add(myApn1); + waitingApns.add(myApn2); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_MMS); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(1000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + rm.markApnPermanentFailed(myApn1); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(4000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(7000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the permanent fail scenario with three APNs configured. + */ + @Test + @SmallTest + public void testRetryManagerApnPermanentFailedWithThreeApns() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"default:2000:2000,3000:3000", "ims:1000,4000"}); + + ArrayList waitingApns = new ArrayList(); + ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); + ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); + ApnSetting myApn3 = ApnSetting.makeApnSetting(mApn3); + waitingApns.add(myApn1); + waitingApns.add(myApn2); + waitingApns.add(myApn3); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_IMS); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + rm.markApnPermanentFailed(myApn2); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn3)); + delay = rm.getDelayForNextApn(false); + assertEquals(1000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn3)); + delay = rm.getDelayForNextApn(false); + assertEquals(4000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn3)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the permanent fail scenario with two APN all failed + */ + @Test + @SmallTest + public void testRetryManagerApnPermanentFailedAll() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"default:1000,4000,7000,9000", "mms:1234,4123"}); + + ArrayList waitingApns = new ArrayList(); + ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); + ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); + waitingApns.add(myApn1); + waitingApns.add(myApn2); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(1000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + rm.markApnPermanentFailed(myApn1); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(4000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(7000, delay); + + rm.markApnPermanentFailed(myApn2); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn == null); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn == null); + } + + /** + * Test the randomized delay scenario. + */ + @Test + @SmallTest + public void testRetryManagerDelayWithRandomization() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"default:default_randomization=1000,3000:2000,6000:3000,10000"}); + + ArrayList waitingApns = new ArrayList(); + waitingApns.add(ApnSetting.makeApnSetting(mApn1)); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertTrue(delay >= 3000 && delay < 5000); // 3s + 2s rand + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertTrue(delay >= 6000 && delay < 9000); // 6s + 3s rand + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertTrue(delay >= 10000 && delay < 11000); // 10s + 1s default rand + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the retry forever scenario + */ + @Test + @SmallTest + public void testRetryManagerRetryForever() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"default:max_retries=infinite,1000,2000"}); + + ArrayList waitingApns = new ArrayList(); + waitingApns.add(ApnSetting.makeApnSetting(mApn1)); + waitingApns.add(ApnSetting.makeApnSetting(mApn2)); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(1000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(2000, delay); + } + + /** + * Test the explicit max retry scenario. + */ + @Test + @SmallTest + public void testRetryManagerExplicitMaxRetry() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"hipri: max_retries=4,1000,2000"}); + + ArrayList waitingApns = new ArrayList(); + waitingApns.add(ApnSetting.makeApnSetting(mApn1)); + waitingApns.add(ApnSetting.makeApnSetting(mApn2)); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_HIPRI); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(1000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the fail fast scenario. + */ + @Test + @SmallTest + public void testRetryManagerFailFast() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"default:1000,5000"}); + + mBundle.putLong(CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 2000); + + ArrayList waitingApns = new ArrayList(); + waitingApns.add(ApnSetting.makeApnSetting(mApn1)); + waitingApns.add(ApnSetting.makeApnSetting(mApn2)); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(true); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(true); + assertEquals(1000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(true); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(true); + assertEquals(2000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(true); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the permanent fail scenario with two APN all failed and then reset + */ + @Test + @SmallTest + public void testRetryManagerApnPermanentFailedAllAndThenReset() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"dun:1000,4000,7000,9000"}); + + ArrayList waitingApns = new ArrayList(); + ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); + ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); + waitingApns.add(myApn1); + waitingApns.add(myApn2); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DUN); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(1000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + rm.markApnPermanentFailed(myApn1); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(4000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(7000, delay); + + rm.markApnPermanentFailed(myApn2); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn == null); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn == null); + + // reset the retry manager + + ApnSetting myApn3 = ApnSetting.makeApnSetting(mApn3); + waitingApns.clear(); + waitingApns.add(myApn3); + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"dun:3000,8000"}); + + rm.setWaitingApns(waitingApns); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn3)); + delay = rm.getDelayForNextApn(false); + assertEquals(3000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn3)); + delay = rm.getDelayForNextApn(false); + assertEquals(8000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn3)); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + private void assertRange(long low, long high, long value) { + if (value >= low && value <= high) return; + fail("Not in range[" + low + "," + high + "], value=" + value); + } + + /** + * Test the scenario where modem suggests retry the current APN once + */ + @Test + @SmallTest + public void testRetryManagerModemSuggestedRetryOnce() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"others:1000,4000,7000,9000"}); + + ArrayList waitingApns = new ArrayList(); + ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); + ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); + waitingApns.add(myApn1); + waitingApns.add(myApn2); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_MMS); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(1000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + // Network suggests retrying the current APN + doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) + .getRetryTime(ApnSetting.TYPE_MMS); + delay = rm.getDelayForNextApn(false); + assertRange(2450, 2500, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + doReturn(RetryManager.NO_SUGGESTED_RETRY_DELAY).when(mDataThrottler) + .getRetryTime(ApnSetting.TYPE_MMS); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + // Modem suggests retrying the current APN + //rm.setModemSuggestedDelay(30000); + doReturn(30000 + SystemClock.elapsedRealtime()).when(mDataThrottler) + .getRetryTime(ApnSetting.TYPE_MMS); + delay = rm.getDelayForNextApn(false); + assertRange(29950, 30000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + doReturn(RetryManager.NO_SUGGESTED_RETRY_DELAY).when(mDataThrottler) + .getRetryTime(ApnSetting.TYPE_MMS); + delay = rm.getDelayForNextApn(false); + assertEquals(4000, delay); + } + + /** + * Test the scenario where modem suggests not retrying + */ + @Test + @SmallTest + public void testRetryManagerModemSuggestedNoRetry() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"default:1000,4000,7000,9000"}); + + ArrayList waitingApns = new ArrayList(); + ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); + ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); + waitingApns.add(myApn1); + waitingApns.add(myApn2); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(1000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + // Modem suggests retrying the current APN + doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) + .getRetryTime(ApnSetting.TYPE_DEFAULT); + delay = rm.getDelayForNextApn(false); + assertRange(2450, 2500, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + doReturn(RetryManager.NO_RETRY).when(mDataThrottler) + .getRetryTime(ApnSetting.TYPE_DEFAULT); + delay = rm.getDelayForNextApn(false); + assertEquals(RetryManager.NO_RETRY, delay); + } + + /** + * Test the scenario that network suggests the same retry for too many times + */ + @Test + @SmallTest + public void testRetryNetworkSuggestedRetryTooManyTimes() throws Exception { + + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, + new String[]{"mms:2000,3000", "default:1000,4000,7000,9000"}); + + int maxRetryCount = 10; + + mBundle.putInt(CarrierConfigManager + .KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, + maxRetryCount); + + ArrayList waitingApns = new ArrayList(); + ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); + ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); + waitingApns.add(myApn1); + waitingApns.add(myApn2); + + RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); + rm.setWaitingApns(waitingApns); + + ApnSetting nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + long delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + delay = rm.getDelayForNextApn(false); + assertEquals(1000, delay); + + for (int i = 0; i < maxRetryCount; i++) { + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) + .getRetryTime(ApnSetting.TYPE_DEFAULT); + delay = rm.getDelayForNextApn(false); + assertRange(2450, 2500, delay); + } + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn1)); + doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) + .getRetryTime(ApnSetting.TYPE_DEFAULT); + delay = rm.getDelayForNextApn(false); + assertEquals(20000, delay); + + nextApn = rm.getNextApnSetting(); + assertTrue(nextApn.equals(mApn2)); + doReturn(RetryManager.NO_SUGGESTED_RETRY_DELAY).when(mDataThrottler) + .getRetryTime(ApnSetting.TYPE_DEFAULT); + delay = rm.getDelayForNextApn(false); + assertEquals(4000, delay); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken new file mode 100644 index 0000000000..2e9b88cbd6 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken @@ -0,0 +1,1935 @@ +/* + * Copyright (C) 2007 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 GSMTestHandler.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.gsm; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.telephony.ServiceState; +import android.test.AndroidTestCase; +import android.test.PerformanceTestCase; + +import android.telephony.DisconnectCause; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.MmiCode; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.gsm.CallFailCause; +import com.android.internal.telephony.gsm.GSMPhone; +import com.android.internal.telephony.gsm.GSMTestHandler; +import com.android.internal.telephony.gsm.GsmMmiCode; +import com.android.internal.telephony.gsm.SuppServiceNotification; +import com.android.internal.telephony.test.SimulatedRadioControl; + +import java.util.List; + + +public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase { + private SimulatedRadioControl mRadioControl; + private GSMPhone mGSMPhone; + private GSMTestHandler mGSMTestHandler; + private Handler mHandler; + + private static final int EVENT_PHONE_STATE_CHANGED = 1; + private static final int EVENT_DISCONNECT = 2; + private static final int EVENT_RINGING = 3; + private static final int EVENT_CHANNEL_OPENED = 4; + private static final int EVENT_POST_DIAL = 5; + private static final int EVENT_DONE = 6; + private static final int EVENT_SSN = 7; + private static final int EVENT_MMI_INITIATE = 8; + private static final int EVENT_MMI_COMPLETE = 9; + private static final int EVENT_IN_SERVICE = 10; + private static final int SUPP_SERVICE_FAILED = 11; + private static final int SERVICE_STATE_CHANGED = 12; + private static final int EVENT_OEM_RIL_MESSAGE = 13; + public static final int ANY_MESSAGE = -1; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mGSMTestHandler = new GSMTestHandler(mContext); + + mGSMTestHandler.start(); + synchronized (mGSMTestHandler) { + do { + mGSMTestHandler.wait(); + } while (mGSMTestHandler.getGSMPhone() == null); + } + + mGSMPhone = mGSMTestHandler.getGSMPhone(); + mRadioControl = mGSMTestHandler.getSimulatedCommands(); + + mHandler = mGSMTestHandler.getHandler(); + mGSMPhone.registerForPreciseCallStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null); + mGSMPhone.registerForNewRingingConnection(mHandler, EVENT_RINGING, null); + mGSMPhone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null); + + mGSMPhone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL, null); + + mGSMPhone.registerForSuppServiceNotification(mHandler, EVENT_SSN, null); + mGSMPhone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null); + mGSMPhone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null); + mGSMPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null); + + mGSMPhone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null); + + // wait until we get phone in both voice and data service + Message msg; + ServiceState state; + + do { + msg = mGSMTestHandler.waitForMessage(SERVICE_STATE_CHANGED); + assertNotNull("Message Time Out", msg); + state = (ServiceState) ((AsyncResult) msg.obj).result; + } while (state.getState() != ServiceState.STATE_IN_SERVICE); + } + + @Override + protected void tearDown() throws Exception { + mRadioControl.shutdown(); + + mGSMPhone.unregisterForPreciseCallStateChanged(mHandler); + mGSMPhone.unregisterForNewRingingConnection(mHandler); + mGSMPhone.unregisterForDisconnect(mHandler); + mGSMPhone.setOnPostDialCharacter(mHandler, 0, null); + mGSMPhone.unregisterForSuppServiceNotification(mHandler); + mGSMPhone.unregisterForMmiInitiate(mHandler); + mGSMPhone.unregisterForMmiComplete(mHandler); + + mGSMPhone = null; + mRadioControl = null; + mHandler = null; + mGSMTestHandler.cleanup(); + + super.tearDown(); + } + + // These test can only be run once. + public int startPerformance(Intermediates intermediates) { + return 1; + } + + public boolean isPerformanceOnly() { + return false; + } + + + //This test is causing the emulator screen to turn off. I don't understand + //why, but I'm removing it until we can figure it out. + public void brokenTestGeneral() throws Exception { + Connection cn; + Message msg; + AsyncResult ar; + + // IDLE state + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + assertFalse(mGSMPhone.canConference()); + + // One DIALING connection + + mRadioControl.setAutoProgressConnectingCall(false); + + mGSMPhone.dial("+13125551212"); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + + msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.DIALING, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + /*do { + mGSMTestHandler.waitForMessage(ANY_MESSAGE); + } while (mGSMPhone.getForegroundCall().getConnections().size() == 0);*/ + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DIALING, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertEquals(DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // One ALERTING connection + + mRadioControl.progressConnectingCallState(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ALERTING, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + assertFalse(mGSMPhone.canConference()); + + // One ACTIVE connection + + mRadioControl.progressConnectingCallState(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.COMPLETE, cn.getPostDialState()); + assertFalse(mGSMPhone.canConference()); + + // One disconnected connection + mGSMPhone.getForegroundCall().hangup(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + assertFalse(mGSMPhone.canConference()); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // cn left over from before phone.clearDisconnected(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing (INCOMING) call + + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + ar = (AsyncResult) msg.obj; + cn = (Connection) ar.result; + assertTrue(cn.isRinging()); + assertEquals(mGSMPhone.getRingingCall(), cn.getCall()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getRingingCall().getConnections().get(0); + assertTrue(cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertFalse(mGSMPhone.canConference()); + + // One mobile terminated active call + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getConnections().size() == 1); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertFalse(mGSMPhone.canConference()); + + // One disconnected (local hangup) call + + try { + Connection conn; + conn = mGSMPhone.getForegroundCall().getConnections().get(0); + conn.hangup(); + } catch (CallStateException ex) { + ex.printStackTrace(); + fail("unexpected ex"); + } + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // cn left over from before phone.clearDisconnected(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // One rejected call + mGSMPhone.rejectCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + // Ringing call disconnects + + mRadioControl.triggerHangupForeground(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); + + assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + + // One Ringing Call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); + + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + // One answered call + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // one holding call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // one active call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // One disconnected call in the foreground slot + + mRadioControl.triggerHangupAll(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(DisconnectCause.NORMAL, cn.getDisconnectCause()); + + // Test missed calls + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); + + mGSMPhone.rejectCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (msg.what != EVENT_DISCONNECT); + + ar = (AsyncResult) msg.obj; + cn = (Connection) ar.result; + + assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + + // Test incoming not missed calls + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + assertEquals(DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + + try { + mGSMPhone.getForegroundCall().hangup(); + } catch (CallStateException ex) { + ex.printStackTrace(); + fail("unexpected ex"); + } + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() + != Call.State.DISCONNECTED); + + assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // + // Test held and hangup held calls + // + + // One ALERTING call + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + mRadioControl.progressConnectingCallState(); + mRadioControl.progressConnectingCallState(); + + // One ACTIVE call + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + // One ACTIVE call, one ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + // One HOLDING call, one ACTIVE call + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertTrue(mGSMPhone.canConference()); + + // Conference the two + mGSMPhone.conference(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getForegroundCall().isMultiparty()); + assertFalse(mGSMPhone.canConference()); + + // Hold the multiparty call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); + assertFalse(mGSMPhone.canConference()); + + // Multiparty call on hold, call waiting added + + mRadioControl.triggerRing("18005558355"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertFalse(mGSMPhone.canConference()); + + // Hangup conference call, ringing call still around + mGSMPhone.getBackgroundCall().hangup(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.DISCONNECTED); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + // Reject waiting call + mGSMPhone.rejectCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + } + + public void testOutgoingCallFailImmediately() throws Exception { + Message msg; + + // Test outgoing call fail-immediately edge case + // This happens when a call terminated before ever appearing in a + // call list + // This should land the immediately-failing call in the + // ForegroundCall list as an IDLE call + mRadioControl.setNextDialFailImmediately(true); + + Connection cn = mGSMPhone.dial("+13125551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(DisconnectCause.NORMAL, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + } + + public void testHangupOnOutgoing() throws Exception { + Connection cn; + Message msg; + + mRadioControl.setAutoProgressConnectingCall(false); + + // Test 1: local hangup in "DIALING" state + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.DIALING); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + mGSMPhone.getForegroundCall().hangup(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // Test 2: local hangup in "ALERTING" state + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + mRadioControl.progressConnectingCallState(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + mGSMPhone.getForegroundCall().hangup(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // Test 3: local immediate hangup before GSM index is + // assigned (CallTracker.hangupPendingMO case) + + mRadioControl.pauseResponses(); + + cn = mGSMPhone.dial("+13125551212"); + + cn.hangup(); + + mRadioControl.resumeResponses(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + + assertEquals(DisconnectCause.LOCAL, + mGSMPhone.getForegroundCall().getEarliestConnection().getDisconnectCause()); + } + + public void testHangupOnChannelClose() throws Exception { + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getConnections().isEmpty()); + + mRadioControl.shutdown(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + mGSMPhone.clearDisconnected(); + } while (!mGSMPhone.getForegroundCall().getConnections().isEmpty()); + } + + public void testIncallMmiCallDeflection() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 0 followed by SEND: release all held calls + // or sets UDUB for a waiting call. + mGSMPhone.handleInCallMmiCommands("0"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // change the active call to holding call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 0 followed by SEND: release all held calls + // or sets UDUB for a waiting call. + mGSMPhone.handleInCallMmiCommands("0"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); + } + + public void testIncallMmiCallWaiting() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + do { + msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); + assertNotNull("Message Time Out", msg); + } while (msg.what != EVENT_RINGING); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // change the active call to holding call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // at this point, the active call with number==18005551212 should + // have the gsm index of 2 + + mRadioControl.triggerRing("16505550100"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering "12" followed by SEND: release the call with + // gsm index equals to 2. + mGSMPhone.handleInCallMmiCommands("12"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // at this point, the call with number==16505550100 should + // have the gsm index of 1 + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE || + mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // at this point, the active call with number==13125551212 should + // have the gsm index of 2 + + // Simulate entering "11" followed by SEND: release the call with + // gsm index equals to 1. This should not be allowed, and a + // Supplementary Service notification must be received. + mGSMPhone.handleInCallMmiCommands("11"); + + msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED); + assertNotNull("Message Time Out", msg); + assertFalse("IncallMmiCallWaiting: command should not work on holding call", msg == null); + + // Simulate entering "12" followed by SEND: release the call with + // gsm index equals to 2. + mGSMPhone.handleInCallMmiCommands("12"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550100", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // Simulate entering "11" followed by SEND: release the call with + // gsm index equals to 1. + mGSMPhone.handleInCallMmiCommands("11"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testIncallMmiCallHold() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // simulate entering 2 followed by SEND: place all active calls + // (if any exist) on hold and accepts the other (held or waiting) + // call + + mGSMPhone.handleInCallMmiCommands("2"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, + mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + // swap the active and holding calls + mGSMPhone.handleInCallMmiCommands("2"); + + msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED); + assertNotNull("Message Time Out", msg); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + // merge the calls + mGSMPhone.conference(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals(2, mGSMPhone.getForegroundCall().getConnections().size()); + + // at this point, we have an active conference call, with + // call(1) = 13125551212 and call(2) = 18005551212 + + // Simulate entering "23" followed by SEND: places all active call + // on hold except call 3. This should fail and a supplementary service + // failed notification should be received. + + mGSMPhone.handleInCallMmiCommands("23"); + + msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED); + assertNotNull("Message Time Out", msg); + assertFalse("IncallMmiCallHold: separate should have failed!", msg == null); + + // Simulate entering "21" followed by SEND: places all active call + // on hold except call 1. + mGSMPhone.handleInCallMmiCommands("21"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + } + + public void testIncallMmiMultipartyServices() throws Exception { + // establish an active call + mGSMPhone.dial("13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // dial another call + mGSMPhone.dial("18005551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.handleInCallMmiCommands("3"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(1).getAddress()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testCallIndex() throws Exception { + Message msg; + + // establish the first call + mGSMPhone.dial("16505550100"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + String baseNumber = "1650555010"; + + for (int i = 1; i < 6; i++) { + String number = baseNumber + i; + + mGSMPhone.dial(number); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + if (mGSMPhone.getBackgroundCall().getConnections().size() >= 5) { + break; + } + + mGSMPhone.conference(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // create an incoming call, this call should have the call index + // of 7 + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // hangup the background call and accept the ringing call + mGSMPhone.getBackgroundCall().hangup(); + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + mGSMPhone.handleInCallMmiCommands("17"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getBackgroundCall().getConnections().get(0). + getAddress()); + + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.handleInCallMmiCommands("16"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testPostDialSequences() throws Exception { + Message msg; + AsyncResult ar; + Connection cn; + + mGSMPhone.dial("+13125551212,1234;5N8xx"); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(',', msg.arg1); + assertEquals("1234;5N8", cn.getRemainingPostDialString()); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('1', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('2', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('3', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('4', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(';', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WAIT, ar.userObj); + cn.proceedAfterWaitChar(); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('5', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertEquals('N', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WILD, ar.userObj); + cn.proceedAfterWildChar(",6;7"); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(',', msg.arg1); + assertEquals("6;78", cn.getRemainingPostDialString()); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('6', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(';', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WAIT, ar.userObj); + cn.proceedAfterWaitChar(); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('7', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('8', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + // Bogus chars at end should be ignored + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(0, msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.COMPLETE, + cn.getPostDialState()); + assertEquals(Connection.PostDialState.COMPLETE, ar.userObj); + } + + public void testPostDialCancel() throws Exception { + Message msg; + AsyncResult ar; + Connection cn; + + mGSMPhone.dial("+13125551212,N"); + mRadioControl.progressConnectingToActive(); + + mRadioControl.progressConnectingToActive(); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(',', msg.arg1); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertEquals('N', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); + cn.cancelPostDial(); + + assertEquals(Connection.PostDialState.CANCELLED, cn.getPostDialState()); + } + + public void testOutgoingCallFail() throws Exception { + Message msg; + /* + * normal clearing + */ + + mRadioControl.setNextCallFailCause(CallFailCause.NORMAL_CLEARING); + mRadioControl.setAutoProgressConnectingCall(false); + + Connection cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(DisconnectCause.NORMAL, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + /* + * busy + */ + + mRadioControl.setNextCallFailCause(CallFailCause.USER_BUSY); + mRadioControl.setAutoProgressConnectingCall(false); + + cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(DisconnectCause.BUSY, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + /* + * congestion + */ + + mRadioControl.setNextCallFailCause(CallFailCause.NO_CIRCUIT_AVAIL); + mRadioControl.setAutoProgressConnectingCall(false); + + cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); + assertNotNull("Message Time Out", msg); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + + // Unlike the while loops above, this one waits + // for a "phone state changed" message back to "idle" + do { + msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); + assertNotNull("Message Time Out", msg); + } while (!(msg.what == EVENT_PHONE_STATE_CHANGED + && mGSMPhone.getState() == PhoneConstants.State.IDLE)); + + assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); + + assertEquals(DisconnectCause.CONGESTION, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + } + + public void testSSNotification() throws Exception { + // MO + runTest(0, SuppServiceNotification.MO_CODE_UNCONDITIONAL_CF_ACTIVE); + runTest(0, SuppServiceNotification.MO_CODE_CALL_IS_WAITING); + runTest(0, SuppServiceNotification.MO_CODE_CALL_DEFLECTED); + + // MT + runTest(1, SuppServiceNotification.MT_CODE_FORWARDED_CALL); + runTest(1, SuppServiceNotification.MT_CODE_CALL_CONNECTED_ECT); + runTest(1, SuppServiceNotification.MT_CODE_ADDITIONAL_CALL_FORWARDED); + } + + private void runTest(int type, int code) { + Message msg; + + mRadioControl.triggerSsn(type, code); + + msg = mGSMTestHandler.waitForMessage(EVENT_SSN); + assertNotNull("Message Time Out", msg); + AsyncResult ar = (AsyncResult) msg.obj; + + assertNull(ar.exception); + + SuppServiceNotification notification = + (SuppServiceNotification) ar.result; + + assertEquals(type, notification.notificationType); + assertEquals(code, notification.code); + } + + public void testUssd() throws Exception { + // Quick hack to work around a race condition in this test: + // We may initiate a USSD MMI before GSMPhone receives its initial + // GSMTestHandler.EVENT_RADIO_OFF_OR_NOT_AVAILABLE event. When the phone sees this + // event, it will cancel the just issued USSD MMI, which we don't + // want. So sleep a little first. + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + // do nothing + } + + verifyNormal(); + verifyCancel(); + varifyNetworkInitiated(); + } + + private void varifyNetworkInitiated() { + Message msg; + AsyncResult ar; + MmiCode mmi; + + // Receive an incoming NOTIFY + mRadioControl.triggerIncomingUssd("0", "NOTIFY message"); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertFalse(mmi.isUssdRequest()); + + // Receive a REQUEST and send response + mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertTrue(mmi.isUssdRequest()); + + mGSMPhone.sendUssdResponse("## TEST: TEST_GSMPhone responding..."); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + GsmMmiCode gsmMmi = (GsmMmiCode) mmi; + assertTrue(gsmMmi.isPendingUSSD()); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertNull(ar.exception); + assertFalse(mmi.isUssdRequest()); + + // Receive a REQUEST and cancel + mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertTrue(mmi.isUssdRequest()); + + mmi.cancel(); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertNull(ar.exception); + assertEquals(MmiCode.State.CANCELLED, mmi.getState()); + + List mmiList = mGSMPhone.getPendingMmiCodes(); + assertEquals(0, mmiList.size()); + } + + private void verifyNormal() throws CallStateException { + Message msg; + AsyncResult ar; + MmiCode mmi; + + mGSMPhone.dial("#646#"); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + assertEquals(MmiCode.State.COMPLETE, mmi.getState()); + } + + + private void verifyCancel() throws CallStateException { + /** + * This case makes an assumption that dial() will add the USSD + * to the "pending MMI codes" list before it returns. This seems + * like reasonable semantics. It also assumes that the USSD + * request in question won't complete until we get back to the + * event loop, thus cancel() is safe. + */ + Message msg; + + mGSMPhone.dial("#646#"); + + List pendingMmis = mGSMPhone.getPendingMmiCodes(); + + assertEquals(1, pendingMmis.size()); + + MmiCode mmi = pendingMmis.get(0); + assertTrue(mmi.isCancelable()); + mmi.cancel(); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + + AsyncResult ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertEquals(MmiCode.State.CANCELLED, mmi.getState()); + } + + public void testRilHooks() throws Exception { + // + // These test cases all assume the RIL OEM hooks + // just echo back their input + // + + Message msg; + AsyncResult ar; + + // null byte array + + mGSMPhone.invokeOemRilRequestRaw(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertNull(ar.result); + assertNull(ar.exception); + + // empty byte array + + mGSMPhone.invokeOemRilRequestRaw(new byte[0], mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals(0, ((byte[]) (ar.result)).length); + assertNull(ar.exception); + + // byte array with data + + mGSMPhone.invokeOemRilRequestRaw("Hello".getBytes("utf-8"), + mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals("Hello", new String(((byte[]) (ar.result)), "utf-8")); + assertNull(ar.exception); + + // null strings + + mGSMPhone.invokeOemRilRequestStrings(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertNull(ar.result); + assertNull(ar.exception); + + // empty byte array + + mGSMPhone.invokeOemRilRequestStrings(new String[0], + mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals(0, ((String[]) (ar.result)).length); + assertNull(ar.exception); + + // Strings with data + + String s[] = new String[1]; + + s[0] = "Hello"; + + mGSMPhone.invokeOemRilRequestStrings(s, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals("Hello", ((String[]) (ar.result))[0]); + assertEquals(1, ((String[]) (ar.result)).length); + assertNull(ar.exception); + } + + public void testMmi() throws Exception { + mRadioControl.setAutoProgressConnectingCall(false); + + // "valid" MMI sequences + runValidMmi("*#67#", false); + runValidMmi("##43*11#", false); + runValidMmi("#33*1234*11#", false); + runValidMmi("*21*6505551234**5#", false); + runValidMmi("**03**1234*4321*4321#", false); + // pound string + runValidMmi("5308234092307540923#", true); + // short code + runValidMmi("22", true); + // as part of call setup + runValidMmiWithConnect("*31#6505551234"); + + // invalid MMI sequences + runNotMmi("6505551234"); + runNotMmi("1234#*12#34566654"); + runNotMmi("*#*#12#*"); + } + + private void runValidMmi(String dialString, boolean cancelable) throws CallStateException { + Connection c = mGSMPhone.dial(dialString); + assertNull(c); + Message msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + // Should not be cancelable. + AsyncResult ar = (AsyncResult) msg.obj; + MmiCode mmi = (MmiCode) ar.result; + assertEquals(cancelable, mmi.isCancelable()); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + } + + private void runValidMmiWithConnect(String dialString) throws CallStateException { + mRadioControl.pauseResponses(); + + Connection c = mGSMPhone.dial(dialString); + assertNotNull(c); + + hangup(c); + } + + private void hangup(Connection cn) throws CallStateException { + cn.hangup(); + + mRadioControl.resumeResponses(); + assertNotNull(mGSMTestHandler.waitForMessage(EVENT_DISCONNECT)); + + } + + private void runNotMmi(String dialString) throws CallStateException { + mRadioControl.pauseResponses(); + + Connection c = mGSMPhone.dial(dialString); + assertNotNull(c); + + hangup(c); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken new file mode 100644 index 0000000000..16861fac7f --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2009 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.gsm; + +import android.content.Context; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import com.android.telephony.Rlog; + +import com.android.internal.telephony.gsm.GSMPhone; +import com.android.internal.telephony.test.SimulatedCommands; +import com.android.internal.telephony.TestPhoneNotifier; + +/** + * This class creates a HandlerThread which waits for the various messages. + */ +public class GSMTestHandler extends HandlerThread implements Handler.Callback { + + private Handler mHandler; + private Message mCurrentMessage; + + private Boolean mMsgConsumed; + private SimulatedCommands sc; + private GSMPhone mGSMPhone; + private Context mContext; + + private static final int FAIL_TIMEOUT_MILLIS = 5 * 1000; + + public GSMTestHandler(Context context) { + super("GSMPhoneTest"); + mMsgConsumed = false; + mContext = context; + } + + @Override + protected void onLooperPrepared() { + sc = new SimulatedCommands(); + mGSMPhone = new GSMPhone(mContext, sc, new TestPhoneNotifier(), true); + mHandler = new Handler(getLooper(), this); + synchronized (this) { + notifyAll(); + } + } + + public boolean handleMessage(Message msg) { + synchronized (this) { + mCurrentMessage = msg; + this.notifyAll(); + while(!mMsgConsumed) { + try { + this.wait(); + } catch (InterruptedException e) {} + } + mMsgConsumed = false; + } + return true; + } + + + public void cleanup() { + Looper looper = getLooper(); + if (looper != null) looper.quit(); + mHandler = null; + } + + public Handler getHandler() { + return mHandler; + } + + public SimulatedCommands getSimulatedCommands() { + return sc; + } + + public GSMPhone getGSMPhone() { + return mGSMPhone; + } + + public Message waitForMessage(int code) { + Message msg; + while(true) { + msg = null; + synchronized (this) { + try { + this.wait(FAIL_TIMEOUT_MILLIS); + } catch (InterruptedException e) { + } + + // Check if timeout has occurred. + if (mCurrentMessage != null) { + // Consume the message + msg = Message.obtain(); + msg.copyFrom(mCurrentMessage); + mCurrentMessage = null; + mMsgConsumed = true; + this.notifyAll(); + } + } + if (msg == null || code == GSMPhoneTest.ANY_MESSAGE || msg.what == code) return msg; + } + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken new file mode 100644 index 0000000000..a9d869c4cb --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken @@ -0,0 +1,694 @@ +/* + * Copyright (C) 2011 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.gsm; + +import android.content.Context; +import android.os.AsyncResult; +import android.os.Message; +import android.os.SystemClock; +import com.android.telephony.Rlog; + +import com.android.internal.telephony.BaseCommands; +import com.android.internal.telephony.UUSInfo; +import com.android.internal.telephony.uicc.IccIoResult; +import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; + +import junit.framework.Assert; + +/** + * Dummy BaseCommands for UsimDataDownloadTest. Only implements UICC envelope and + * SMS acknowledgement commands. + */ +class UsimDataDownloadCommands extends BaseCommands { + private static final String TAG = "UsimDataDownloadCommands"; + + private boolean mExpectingAcknowledgeGsmSms; // true if expecting ack GSM SMS + private boolean mExpectingAcknowledgeGsmSmsSuccess; // true if expecting ack SMS success + private int mExpectingAcknowledgeGsmSmsFailureCause; // expecting ack SMS failure cause + private String mExpectingAcknowledgeGsmSmsPdu; // expecting ack SMS PDU + + private boolean mExpectingSendEnvelope; // true to expect a send envelope command + private String mExpectingSendEnvelopeContents; // expected string for send envelope + private int mExpectingSendEnvelopeResponseSw1; // SW1/SW2 response status + private int mExpectingSendEnvelopeResponseSw2; // SW1/SW2 response status + private String mExpectingSendEnvelopeResponse; // Response string for Send Envelope + + UsimDataDownloadCommands(Context context) { + super(context); + } + + /** + * Expect a call to acknowledgeLastIncomingGsmSms with success flag and failure cause. + * @param success true if expecting success; false if expecting failure + * @param cause the failure cause, if success is false + */ + synchronized void expectAcknowledgeGsmSms(boolean success, int cause) { + Assert.assertFalse("expectAcknowledgeGsmSms called twice", mExpectingAcknowledgeGsmSms); + mExpectingAcknowledgeGsmSms = true; + mExpectingAcknowledgeGsmSmsSuccess = success; + mExpectingAcknowledgeGsmSmsFailureCause = cause; + } + + /** + * Expect a call to acknowledgeLastIncomingGsmSmsWithPdu with success flag and PDU. + * @param success true if expecting success; false if expecting failure + * @param ackPdu the acknowledgement PDU to expect + */ + synchronized void expectAcknowledgeGsmSmsWithPdu(boolean success, String ackPdu) { + Assert.assertFalse("expectAcknowledgeGsmSms called twice", mExpectingAcknowledgeGsmSms); + mExpectingAcknowledgeGsmSms = true; + mExpectingAcknowledgeGsmSmsSuccess = success; + mExpectingAcknowledgeGsmSmsPdu = ackPdu; + } + + /** + * Expect a call to sendEnvelopeWithStatus(). + * @param contents expected envelope contents to send + * @param sw1 simulated SW1 status to return + * @param sw2 simulated SW2 status to return + * @param response simulated envelope response to return + */ + synchronized void expectSendEnvelope(String contents, int sw1, int sw2, String response) { + Assert.assertFalse("expectSendEnvelope called twice", mExpectingSendEnvelope); + mExpectingSendEnvelope = true; + mExpectingSendEnvelopeContents = contents; + mExpectingSendEnvelopeResponseSw1 = sw1; + mExpectingSendEnvelopeResponseSw2 = sw2; + mExpectingSendEnvelopeResponse = response; + } + + synchronized void assertExpectedMethodsCalled() { + long stopTime = SystemClock.elapsedRealtime() + 5000; + while ((mExpectingAcknowledgeGsmSms || mExpectingSendEnvelope) + && SystemClock.elapsedRealtime() < stopTime) { + try { + wait(); + } catch (InterruptedException ignored) {} + } + Assert.assertFalse("expecting SMS acknowledge call", mExpectingAcknowledgeGsmSms); + Assert.assertFalse("expecting send envelope call", mExpectingSendEnvelope); + } + + @Override + public synchronized void acknowledgeLastIncomingGsmSms(boolean success, int cause, + Message response) { + Rlog.d(TAG, "acknowledgeLastIncomingGsmSms: success=" + success + ", cause=" + cause); + Assert.assertTrue("unexpected call to acknowledge SMS", mExpectingAcknowledgeGsmSms); + Assert.assertEquals(mExpectingAcknowledgeGsmSmsSuccess, success); + Assert.assertEquals(mExpectingAcknowledgeGsmSmsFailureCause, cause); + mExpectingAcknowledgeGsmSms = false; + if (response != null) { + AsyncResult.forMessage(response); + response.sendToTarget(); + } + notifyAll(); // wake up assertExpectedMethodsCalled() + } + + @Override + public synchronized void acknowledgeIncomingGsmSmsWithPdu(boolean success, String ackPdu, + Message response) { + Rlog.d(TAG, "acknowledgeLastIncomingGsmSmsWithPdu: success=" + success + + ", ackPDU= " + ackPdu); + Assert.assertTrue("unexpected call to acknowledge SMS", mExpectingAcknowledgeGsmSms); + Assert.assertEquals(mExpectingAcknowledgeGsmSmsSuccess, success); + Assert.assertEquals(mExpectingAcknowledgeGsmSmsPdu, ackPdu); + mExpectingAcknowledgeGsmSms = false; + if (response != null) { + AsyncResult.forMessage(response); + response.sendToTarget(); + } + notifyAll(); // wake up assertExpectedMethodsCalled() + } + + @Override + public synchronized void sendEnvelopeWithStatus(String contents, Message response) { + // Add spaces between hex bytes for readability + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < contents.length(); i += 2) { + builder.append(contents.charAt(i)).append(contents.charAt(i+1)).append(' '); + } + Rlog.d(TAG, "sendEnvelopeWithStatus: " + builder.toString()); + + Assert.assertTrue("unexpected call to send envelope", mExpectingSendEnvelope); + Assert.assertEquals(mExpectingSendEnvelopeContents, contents); + mExpectingSendEnvelope = false; + + IccIoResult result = new IccIoResult(mExpectingSendEnvelopeResponseSw1, + mExpectingSendEnvelopeResponseSw2, mExpectingSendEnvelopeResponse); + + if (response != null) { + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + } + notifyAll(); // wake up assertExpectedMethodsCalled() + } + + @Override + public void setSuppServiceNotifications(boolean enable, Message result) { + } + + @Override + public void supplyIccPin(String pin, Message result) { + } + + @Override + public void supplyIccPinForApp(String pin, String aid, Message result) { + } + + @Override + public void supplyIccPuk(String puk, String newPin, Message result) { + } + + @Override + public void supplyIccPukForApp(String puk, String newPin, String aid, Message result) { + } + + @Override + public void supplyIccPin2(String pin2, Message result) { + } + + @Override + public void supplyIccPin2ForApp(String pin2, String aid, Message result) { + } + + @Override + public void supplyIccPuk2(String puk2, String newPin2, Message result) { + } + + @Override + public void supplyIccPuk2ForApp(String puk2, String newPin2, String aid, Message result) { + } + + @Override + public void changeIccPin(String oldPin, String newPin, Message result) { + } + + @Override + public void changeIccPinForApp(String oldPin, String newPin, String aidPtr, Message result) { + } + + @Override + public void changeIccPin2(String oldPin2, String newPin2, Message result) { + } + + @Override + public void changeIccPin2ForApp(String oldPin2, String newPin2, String aidPtr, Message result) { + } + + @Override + public void changeBarringPassword(String facility, String oldPwd, String newPwd, + Message result) { + } + + @Override + public void supplyNetworkDepersonalization(String netpin, Message result) { + } + + @Override + public void getCurrentCalls(Message result) { + } + + @Override + public void getPDPContextList(Message result) { + } + + @Override + public void getDataCallList(Message result) { + } + + @Override + public void dial(String address, int clirMode, Message result) { + } + + @Override + public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) { + } + + @Override + public void getIMSI(Message result) { + } + + @Override + public void getIMEI(Message result) { + } + + @Override + public void getIMEISV(Message result) { + } + + @Override + public void hangupConnection(int gsmIndex, Message result) { + } + + @Override + public void hangupWaitingOrBackground(Message result) { + } + + @Override + public void hangupForegroundResumeBackground(Message result) { + } + + @Override + public void switchWaitingOrHoldingAndActive(Message result) { + } + + @Override + public void conference(Message result) { + } + + @Override + public void setPreferredVoicePrivacy(boolean enable, Message result) { + } + + @Override + public void getPreferredVoicePrivacy(Message result) { + } + + @Override + public void separateConnection(int gsmIndex, Message result) { + } + + @Override + public void acceptCall(Message result) { + } + + @Override + public void rejectCall(Message result) { + } + + @Override + public void explicitCallTransfer(Message result) { + } + + @Override + public void getLastCallFailCause(Message result) { + } + + @Override + public void getLastPdpFailCause(Message result) { + } + + @Override + public void getLastDataCallFailCause(Message result) { + } + + @Override + public void setMute(boolean enableMute, Message response) { + } + + @Override + public void getMute(Message response) { + } + + @Override + public void getSignalStrength(Message response) { + } + + @Override + public void getVoiceRegistrationState(Message response) { + } + + @Override + public void getDataRegistrationState(Message response) { + } + + @Override + public void getOperator(Message response) { + } + + @Override + public void sendDtmf(char c, Message result) { + } + + @Override + public void startDtmf(char c, Message result) { + } + + @Override + public void stopDtmf(Message result) { + } + + @Override + public void sendBurstDtmf(String dtmfString, int on, int off, Message result) { + } + + @Override + public void sendSMS(String smscPDU, String pdu, Message response) { + } + + @Override + public void sendSMSExpectMore(String smscPDU, String pdu, Message response) { + } + + @Override + public void sendCdmaSms(byte[] pdu, Message response) { + } + + @Override + public void sendImsGsmSms (String smscPDU, String pdu, + int retry, int messageRef, Message response) { + } + + @Override + public void sendImsCdmaSms(byte[] pdu, int retry, int messageRef, + Message response) { + } + + @Override + public void deleteSmsOnSim(int index, Message response) { + } + + @Override + public void deleteSmsOnRuim(int index, Message response) { + } + + @Override + public void writeSmsToSim(int status, String smsc, String pdu, Message response) { + } + + @Override + public void writeSmsToRuim(int status, byte[] pdu, Message response) { + } + + @Override + public void setRadioPower(boolean on, Message response) { + } + + @Override + public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message response) { + } + + @Override + public void iccIO(int command, int fileid, String path, int p1, int p2, int p3, String data, + String pin2, Message response) { + } + + @Override + public void queryCLIP(Message response) { + } + + @Override + public void getCLIR(Message response) { + } + + @Override + public void setCLIR(int clirMode, Message response) { + } + + @Override + public void queryCallWaiting(int serviceClass, Message response) { + } + + @Override + public void setCallWaiting(boolean enable, int serviceClass, Message response) { + } + + @Override + public void setCallForward(int action, int cfReason, int serviceClass, String number, + int timeSeconds, Message response) { + } + + @Override + public void queryCallForwardStatus(int cfReason, int serviceClass, String number, + Message response) { + } + + @Override + public void setNetworkSelectionModeAutomatic(Message response) { + } + + @Override + public void setNetworkSelectionModeManual(String operatorNumeric, Message response) { + } + + @Override + public void getNetworkSelectionMode(Message response) { + } + + @Override + public void getAvailableNetworks(Message response) { + } + + @Override + public void getBasebandVersion(Message response) { + } + + @Override + public void queryFacilityLock(String facility, String password, int serviceClass, + Message response) { + } + + @Override + public void queryFacilityLockForApp(String facility, String password, int serviceClass, + String appId, Message response) { + } + + @Override + public void setFacilityLock(String facility, boolean lockState, String password, + int serviceClass, Message response) { + } + + @Override + public void setFacilityLockForApp(String facility, boolean lockState, String password, + int serviceClass, String appId, Message response) { + } + + @Override + public void sendUSSD(String ussdString, Message response) { + } + + @Override + public void cancelPendingUssd(Message response) { + } + + @Override + public void resetRadio(Message result) { + } + + @Override + public void setBandMode(int bandMode, Message response) { + } + + @Override + public void queryAvailableBandMode(Message response) { + } + + @Override + public void setPreferredNetworkType(int networkType, Message response) { + } + + @Override + public void getPreferredNetworkType(Message response) { + } + + @Override + public void setLocationUpdates(boolean enable, Message response) { + } + + @Override + public void getSmscAddress(Message result) { + } + + @Override + public void setSmscAddress(String address, Message result) { + } + + @Override + public void reportSmsMemoryStatus(boolean available, Message result) { + } + + @Override + public void reportStkServiceIsRunning(Message result) { + } + + @Override + public void invokeOemRilRequestRaw(byte[] data, Message response) { + } + + @Override + public void invokeOemRilRequestStrings(String[] strings, Message response) { + } + + @Override + public void sendTerminalResponse(String contents, Message response) { + } + + @Override + public void sendEnvelope(String contents, Message response) { + } + + @Override + public void handleCallSetupRequestFromSim(boolean accept, Message response) { + } + + @Override + public void setGsmBroadcastActivation(boolean activate, Message result) { + } + + @Override + public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) { + } + + @Override + public void getGsmBroadcastConfig(Message response) { + } + + @Override + public void getDeviceIdentity(Message response) { + } + + @Override + public void getCDMASubscription(Message response) { + } + + @Override + public void getImsRegistrationState (Message result) { + } + + @Override + public void sendCDMAFeatureCode(String FeatureCode, Message response) { + } + + @Override + public void setPhoneType(int phoneType) { + } + + @Override + public void queryCdmaRoamingPreference(Message response) { + } + + @Override + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { + } + + @Override + public void setCdmaSubscriptionSource(int cdmaSubscriptionType, Message response) { + } + + @Override + public void getCdmaSubscriptionSource(Message response) { + } + + @Override + public void setTTYMode(int ttyMode, Message response) { + } + + @Override + public void queryTTYMode(Message response) { + } + + @Override + public void setupDataCall(String radioTechnology, String profile, String apn, String user, + String password, String authType, String protocol, Message result) { + } + + @Override + public void deactivateDataCall(int cid, int reason, Message result) { + } + + @Override + public void setCdmaBroadcastActivation(boolean activate, Message result) { + } + + @Override + public void setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs, Message response) { + } + + @Override + public void getCdmaBroadcastConfig(Message result) { + } + + @Override + public void exitEmergencyCallbackMode(Message response) { + } + + @Override + public void getIccCardStatus(Message result) { + } + + @Override + public void requestIsimAuthentication(String nonce, Message response) { + } + + @Override + public void requestIccSimAuthentication(String data, Message response) { + } + + @Override + public void getVoiceRadioTechnology(Message response) { + } + + @Override + public void getCellInfoList(Message result) { + } + + @Override + public void setCellInfoListRate(int rateInMillis, Message response) { + } + + @Override + public void setInitialAttachApn(String apn, String protocol, int authType, String username, + String password, Message result) { + } + + @Override + public void setDataProfile(DataProfile[] dps, Message result) { + } + + @Override + public void getIMSIForApp(String aid, Message result) { + } + + @Override + public void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3, + String data, String pin2, String aid, Message response) { + } + + @Override + public void iccOpenLogicalChannel(String AID, Message response) { + } + + @Override + public void iccCloseLogicalChannel(int channel, Message response) { + } + + @Override + public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, + int p1, int p2, int p3, String data, Message response) { + } + + @Override + public void iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, + int p3, String data, Message response) { + } + + @Override + public void nvReadItem(int itemID, Message response) { + } + + @Override + public void nvWriteItem(int itemID, String itemValue, Message response) { + } + + @Override + public void nvWriteCdmaPrl(byte[] preferredRoamingList, Message response) { + } + + @Override + public void nvResetConfig(int resetType, Message response) { + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken new file mode 100644 index 0000000000..9fbb86c264 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2011 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.gsm; + +import android.os.HandlerThread; +import android.test.AndroidTestCase; +import com.android.telephony.Rlog; + +import java.nio.charset.Charset; + +/** + * Test SMS-PP data download to UICC. + * Uses test messages from 3GPP TS 31.124 section 27.22.5. + */ +public class UsimDataDownloadTest extends AndroidTestCase { + private static final String TAG = "UsimDataDownloadTest"; + + class TestHandlerThread extends HandlerThread { + private UsimDataDownloadHandler mHandler; + + TestHandlerThread() { + super("TestHandlerThread"); + } + + @Override + protected void onLooperPrepared() { + synchronized (this) { + mHandler = new UsimDataDownloadHandler(mCi, 0); + notifyAll(); + } + } + + UsimDataDownloadHandler getHandler() { + synchronized (this) { + while (mHandler == null) { + try { + wait(); + } catch (InterruptedException ignored) {} + } + return mHandler; + } + } + } + + private UsimDataDownloadCommands mCi; + private TestHandlerThread mHandlerThread; + UsimDataDownloadHandler mHandler; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mCi = new UsimDataDownloadCommands(mContext); + mHandlerThread = new TestHandlerThread(); + mHandlerThread.start(); + mHandler = mHandlerThread.getHandler(); + Rlog.d(TAG, "mHandler is constructed"); + } + + @Override + protected void tearDown() throws Exception { + mHandlerThread.quit(); + super.tearDown(); + } + + // SMS-PP Message 3.1.1 + private static final byte[] SMS_PP_MESSAGE_3_1_1 = { + // Service center address + 0x09, (byte) 0x91, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0xf8, + + 0x04, 0x04, (byte) 0x91, 0x21, 0x43, 0x7f, 0x16, (byte) 0x89, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x0d, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x20, 0x31 + }; + + // SMS-PP Download Envelope 3.1.1 + private static final String SMS_PP_ENVELOPE_3_1_1 = "d12d8202838106099111223344556677f88b1c04" + + "049121437f16891010000000000d546573744d6573736167652031"; + + // SMS-PP Message 3.1.5 + private static final byte[] SMS_PP_MESSAGE_3_1_5 = { + // Service center address + 0x09, (byte) 0x91, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0xf8, + + 0x44, 0x04, (byte) 0x91, 0x21, 0x43, 0x7f, (byte) 0xf6, (byte) 0x89, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x02, 0x70, 0x00, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x00, + 0x00, 0x00, (byte) 0xbf, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, + (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc + }; + + // SMS-PP Download Envelope 3.1.5 + private static final String SMS_PP_ENVELOPE_3_1_5 = "d13e8202838106099111223344556677f88b2d44" + + "049121437ff6891010000000001e0270000019000d00000000bfff00000000000100" + + "dcdcdcdcdcdcdcdcdcdc"; + + public void testDataDownloadMessage1() { + SmsMessage message = SmsMessage.createFromPdu(SMS_PP_MESSAGE_3_1_1); + assertTrue("message is SMS-PP data download", message.isUsimDataDownload()); + + mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x90, 0x00, ""); + mCi.expectAcknowledgeGsmSms(true, 0); + mHandler.startDataDownload(message); + mCi.assertExpectedMethodsCalled(); + + mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x90, 0x00, "0123456789"); + mCi.expectAcknowledgeGsmSmsWithPdu(true, "00077f16050123456789"); + mHandler.startDataDownload(message); + mCi.assertExpectedMethodsCalled(); + + mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x62, 0xff, "0123456789abcdef"); + mCi.expectAcknowledgeGsmSmsWithPdu(false, "00d5077f16080123456789abcdef"); + mHandler.startDataDownload(message); + mCi.assertExpectedMethodsCalled(); + } + + public void testDataDownloadMessage5() { + SmsMessage message = SmsMessage.createFromPdu(SMS_PP_MESSAGE_3_1_5); + assertTrue("message is SMS-PP data download", message.isUsimDataDownload()); + + mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_5, 0x90, 0x00, "9876543210"); + mCi.expectAcknowledgeGsmSmsWithPdu(true, "00077ff6059876543210"); + mHandler.startDataDownload(message); + mCi.assertExpectedMethodsCalled(); + + mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_5, 0x93, 0x00, ""); + mCi.expectAcknowledgeGsmSms(false, 0xd4); // SIM toolkit busy + mHandler.startDataDownload(message); + mCi.assertExpectedMethodsCalled(); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java index c26dd22842..111e5d2c5f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java @@ -25,6 +25,11 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL; import static com.android.internal.telephony.data.LinkBandwidthEstimator.NUM_SIGNAL_LEVEL; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; +import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6; import static org.junit.Assert.assertArrayEquals; @@ -84,11 +89,6 @@ import java.util.ArrayList; import java.util.Arrays; public class TelephonyMetricsTest extends TelephonyTest { - private static final String FAKE_ADDRESS = "99.88.77.66"; - private static final String FAKE_DNS = "55.66.77.88"; - private static final String FAKE_GATEWAY = "11.22.33.44"; - private static final String FAKE_IFNAME = "FAKE IFNAME"; - private static final String FAKE_PCSCF_ADDRESS = "22.33.44.55"; // Mocked classes private ImsCallSession mImsCallSession; private ServiceState mServiceState; diff --git a/tools/tdi b/tools/tdi new file mode 100755 index 0000000000..940a83bccc --- /dev/null +++ b/tools/tdi @@ -0,0 +1,48 @@ +#!/bin/bash +# Telephony Debug Intents +#set -x + +file_name='tdi' + +# Get the command as the first parameter +cmd=$1 +shift + +function dc_errors() +{ + if [ "$1" == "" ]; then + echo "Usage: $file_name $cmd " + echo " must specifiy the DataConnection such as DC or GsmDC-1" + echo " := number of times to retry" + echo " := From DataConnection.FailCause; such as -3 for SIGNAL_LOST" + echo " := suggested retry time in milli-seconds" + exit + fi + the_DC=$1 + echo "the_DC=$the_DC" + + if [ "$2" != "" ]; then + counter="--ei counter $2"; + fi + echo "counter=$counter" + + if [ "$3" != "" ]; then + fail_cause="--ei fail_cause $3"; + fi + echo "fail_cause=$fail_cause" + + if [ "$4" != "" ]; then + suggested_retry_time="--ei suggested_retry_time $4"; + fi + echo "suggested_retry_time=$suggested_retry_time" + + + adb shell am broadcast -a com.android.internal.telephony.$the_DC.action_fail_bringup $counter $fail_cause $suggested_retry_time +} + + +case ${cmd} in + dce) dc_errors "$@";; + # Add more commands in the future + *) echo 'Broadcast telephony debug intents'; echo 'usage: tdi [dce]'; echo ' dce=DC errors';; +esac -- GitLab From 7b90d04785228bd3c7c6309f9c5f8abbff119dbd Mon Sep 17 00:00:00 2001 From: Gary Jian Date: Tue, 16 Aug 2022 00:19:56 +0800 Subject: [PATCH 067/656] Check ro.boot.radio.allow_mock_modem in USER build Provide new ro.boot.radio.allow_mock_modem for emulator to set it, so we have two property one is for developer options (persist.radio.*) another is for emulator (ro.boot.*). The setModemService is allowed in USER build as long as either is true. Bug: 231323121 Test: emulator Change-Id: I2904172265919770d9984605d27189b916d42b5b --- .../internal/telephony/PhoneConfigurationManager.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java index 05c325e46d..426aeb2792 100644 --- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java +++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java @@ -71,6 +71,7 @@ public class PhoneConfigurationManager { private TelephonyManager mTelephonyManager; private static final RegistrantList sMultiSimConfigChangeRegistrants = new RegistrantList(); private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; + private static final String BOOT_ALLOW_MOCK_MODEM_PROPERTY = "ro.boot.radio.allow_mock_modem"; private static final boolean DEBUG = !"user".equals(Build.TYPE); /** * Init method to instantiate the object @@ -473,9 +474,11 @@ public class PhoneConfigurationManager { boolean statusRadioConfig = false; boolean statusRil = false; final boolean isAllowed = SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false); + final boolean isAllowedForBoot = + SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false); - // Check for ALLOW_MOCK_MODEM_PROPERTY on user builds - if (isAllowed || DEBUG) { + // Check for ALLOW_MOCK_MODEM_PROPERTY and BOOT_ALLOW_MOCK_MODEM_PROPERTY on user builds + if (isAllowed || isAllowedForBoot || DEBUG) { if (serviceName != null) { statusRadioConfig = mRadioConfig.setModemService(serviceName); -- GitLab From a7db06d57bce337d77b6a27290fbc19e700b124c Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 17 Aug 2022 16:44:56 -0700 Subject: [PATCH 068/656] Fixed a crash when data network does not have PCO Avoid crash when PCO data arrives, but it's only for certain data networks but not all, it will crash in data network controller when trying get PCO data from each network. Test: Able to repro with unit test. Verified working after fix. Fix: 242768045 Change-Id: I832ddcc80f4e92d487bd0fa93ec63f74e4978de3 --- .../internal/telephony/data/DataNetwork.java | 2 +- .../telephony/data/DataNetworkControllerTest.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 26ed0f451c..c98df0db82 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -3313,7 +3313,7 @@ public class DataNetwork extends StateMachine { || mCid.get(mTransport) == INVALID_CID) { return Collections.emptyMap(); } - return mPcoData.get(mCid.get(mTransport)); + return mPcoData.getOrDefault(mCid.get(mTransport), Collections.emptyMap()); } /** 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 06666b9fed..79114bd406 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -2515,6 +2515,20 @@ public class DataNetworkControllerTest extends TelephonyTest { verify(mMockedDataNetworkControllerCallback).onNrAdvancedCapableByPcoChanged(eq(true)); } + @Test + public void testNrAdvancedByPcoMultipleNetworks() throws Exception { + testSetupDataNetwork(); + setSuccessfulSetupDataResponse(mMockedDataServiceManagers + .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 2); + testSetupImsDataNetwork(); + + verify(mMockedDataNetworkControllerCallback, never()) + .onNrAdvancedCapableByPcoChanged(anyBoolean()); + mSimulatedCommands.triggerPcoData(2, "IPV6", 1234, new byte[]{1}); + processAllMessages(); + verify(mMockedDataNetworkControllerCallback).onNrAdvancedCapableByPcoChanged(eq(true)); + } + @Test public void testNrAdvancedByEarlyUnrelatedPco() { Mockito.reset(mMockedWwanDataServiceManager); -- GitLab From 31309ffa907f4f884d1885fd6f819ac2c741d53a Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 16 Aug 2022 17:58:03 -0700 Subject: [PATCH 069/656] Subscription Manager public method clean up 1. Preliminary step of subscription manager API surface clean up. 2. Simpler way to solve unit test issue. 3. Fixed incorrect string comparison. 4. Moved some static variables into non-static. Bug: 239607619 Test: atest TelephonyFrameworksTests Change-Id: I50c110f53caec4b73708dcf1cb8d52708242d7ea --- .../telephony/SubscriptionController.java | 136 ++++++------------ .../telephony/data/PhoneSwitcher.java | 4 +- .../telephony/SubscriptionControllerTest.java | 2 - .../internal/telephony/TelephonyTest.java | 4 +- 4 files changed, 44 insertions(+), 102 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 0dc7012c1f..47ca5d0e3a 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -166,15 +166,10 @@ public class SubscriptionController extends ISub.Stub { private AppOpsManager mAppOps; - // Allows test mocks to avoid SELinux failures on invalidate calls. - private static boolean sCachingEnabled = true; - // Each slot can have multiple subs. private static class WatchedSlotIndexToSubIds { - private Map> mSlotIndexToSubIds = new ConcurrentHashMap<>(); - - WatchedSlotIndexToSubIds() { - } + private final Map> mSlotIndexToSubIds = + new ConcurrentHashMap<>(); public void clear() { mSlotIndexToSubIds.clear(); @@ -193,7 +188,7 @@ public class SubscriptionController extends ISub.Stub { return null; } - return new ArrayList(subIdList); + return new ArrayList<>(subIdList); } public void put(int slotIndex, ArrayList value) { @@ -275,9 +270,9 @@ public class SubscriptionController extends ISub.Stub { } } - private static WatchedSlotIndexToSubIds sSlotIndexToSubIds = new WatchedSlotIndexToSubIds(); + private final WatchedSlotIndexToSubIds mSlotIndexToSubIds = new WatchedSlotIndexToSubIds(); - protected static WatchedInt sDefaultFallbackSubId = + private final WatchedInt mDefaultFallbackSubId = new WatchedInt(SubscriptionManager.INVALID_SUBSCRIPTION_ID) { @Override public void set(int newValue) { @@ -1469,7 +1464,7 @@ public class SubscriptionController extends ISub.Stub { int defaultSubId = getDefaultSubId(); if (DBG) { logdl("[addSubInfoRecord]" - + " sSlotIndexToSubIds.size=" + sSlotIndexToSubIds.size() + + " mSlotIndexToSubIds.size=" + mSlotIndexToSubIds.size() + " slotIndex=" + slotIndex + " subId=" + subId + " defaultSubId=" + defaultSubId + " simCount=" + subIdCountMax); @@ -1549,7 +1544,7 @@ public class SubscriptionController extends ISub.Stub { if (DBG) logdl("[addSubInfoRecord] sim name = " + nameToSet); } - if (DBG) logdl("[addSubInfoRecord]- info size=" + sSlotIndexToSubIds.size()); + if (DBG) logdl("[addSubInfoRecord]- info size=" + mSlotIndexToSubIds.size()); } } finally { @@ -1653,7 +1648,7 @@ public class SubscriptionController extends ISub.Stub { return -1; } refreshCachedActiveSubscriptionInfoList(); - result = sSlotIndexToSubIds.removeFromSubIdList(slotIndex, subId); + result = mSlotIndexToSubIds.removeFromSubIdList(slotIndex, subId); if (result == NO_ENTRY_FOR_SLOT_INDEX) { loge("sSlotIndexToSubIds has no entry for slotIndex = " + slotIndex); } else if (result == SUB_ID_NOT_IN_SLOT) { @@ -1697,7 +1692,7 @@ public class SubscriptionController extends ISub.Stub { // Refresh the Cache of Active Subscription Info List refreshCachedActiveSubscriptionInfoList(); - sSlotIndexToSubIds.remove(slotIndex); + mSlotIndexToSubIds.remove(slotIndex); } /** @@ -2586,14 +2581,14 @@ public class SubscriptionController extends ISub.Stub { return SubscriptionManager.INVALID_SIM_SLOT_INDEX; } - int size = sSlotIndexToSubIds.size(); + int size = mSlotIndexToSubIds.size(); if (size == 0) { if (DBG) logd("[getSlotIndex]- size == 0, return SIM_NOT_INSERTED instead"); return SubscriptionManager.SIM_NOT_INSERTED; } - for (Entry> entry : sSlotIndexToSubIds.entrySet()) { + for (Entry> entry : mSlotIndexToSubIds.entrySet()) { int sim = entry.getKey(); ArrayList subs = entry.getValue(); @@ -2636,7 +2631,7 @@ public class SubscriptionController extends ISub.Stub { } // Check if we've got any SubscriptionInfo records using slotIndexToSubId as a surrogate. - int size = sSlotIndexToSubIds.size(); + int size = mSlotIndexToSubIds.size(); if (size == 0) { if (VDBG) { logd("[getSubId]- sSlotIndexToSubIds.size == 0, return null slotIndex=" @@ -2646,7 +2641,7 @@ public class SubscriptionController extends ISub.Stub { } // Convert ArrayList to array - ArrayList subIds = sSlotIndexToSubIds.getCopy(slotIndex); + ArrayList subIds = mSlotIndexToSubIds.getCopy(slotIndex); if (subIds != null && subIds.size() > 0) { int[] subIdArr = new int[subIds.size()]; for (int i = 0; i < subIds.size(); i++) { @@ -2679,7 +2674,7 @@ public class SubscriptionController extends ISub.Stub { return SubscriptionManager.INVALID_PHONE_INDEX; } - int size = sSlotIndexToSubIds.size(); + int size = mSlotIndexToSubIds.size(); if (size == 0) { phoneId = mDefaultPhoneId; if (VDBG) logdl("[getPhoneId]- no sims, returning default phoneId=" + phoneId); @@ -2687,7 +2682,7 @@ public class SubscriptionController extends ISub.Stub { } // FIXME: Assumes phoneId == slotIndex - for (Entry> entry: sSlotIndexToSubIds.entrySet()) { + for (Entry> entry: mSlotIndexToSubIds.entrySet()) { int sim = entry.getKey(); ArrayList subs = entry.getValue(); @@ -2715,14 +2710,14 @@ public class SubscriptionController extends ISub.Stub { // Now that all security checks passes, perform the operation as ourselves. final long identity = Binder.clearCallingIdentity(); try { - int size = sSlotIndexToSubIds.size(); + int size = mSlotIndexToSubIds.size(); if (size == 0) { if (DBG) logdl("[clearSubInfo]- no simInfo size=" + size); return 0; } - sSlotIndexToSubIds.clear(); + mSlotIndexToSubIds.clear(); if (DBG) logdl("[clearSubInfo]- clear size=" + size); return size; } finally { @@ -2773,7 +2768,7 @@ public class SubscriptionController extends ISub.Stub { if (VDBG) logdl("[getDefaultSubId] NOT VoiceCapable subId=" + subId); } if (!isActiveSubId(subId)) { - subId = sDefaultFallbackSubId.get(); + subId = mDefaultFallbackSubId.get(); if (VDBG) logdl("[getDefaultSubId] NOT active use fall back subId=" + subId); } if (VDBG) logv("[getDefaultSubId]- value = " + subId); @@ -2960,7 +2955,7 @@ public class SubscriptionController extends ISub.Stub { } int previousDefaultSub = getDefaultSubId(); if (isSubscriptionForRemoteSim(subscriptionType)) { - sDefaultFallbackSubId.set(subId); + mDefaultFallbackSubId.set(subId); return; } if (SubscriptionManager.isValidSubscriptionId(subId)) { @@ -2968,7 +2963,7 @@ public class SubscriptionController extends ISub.Stub { if (phoneId >= 0 && (phoneId < mTelephonyManager.getPhoneCount() || mTelephonyManager.getSimCount() == 1)) { if (DBG) logdl("[setDefaultFallbackSubId] set sDefaultFallbackSubId=" + subId); - sDefaultFallbackSubId.set(subId); + mDefaultFallbackSubId.set(subId); // Update MCC MNC device configuration information String defaultMccMnc = mTelephonyManager.getSimOperatorNumericForPhone(phoneId); MccTable.updateMccMncConfiguration(mContext, defaultMccMnc); @@ -3068,7 +3063,7 @@ public class SubscriptionController extends ISub.Stub { private synchronized ArrayList getActiveSubIdArrayList() { // Clone the sub id list so it can't change out from under us while iterating List>> simInfoList = - new ArrayList<>(sSlotIndexToSubIds.entrySet()); + new ArrayList<>(mSlotIndexToSubIds.entrySet()); // Put the set of sub ids in slot index order Collections.sort(simInfoList, (x, y) -> x.getKey().compareTo(y.getKey())); @@ -3398,7 +3393,7 @@ public class SubscriptionController extends ISub.Stub { .from(mContext).getDefaultSmsPhoneId()); pw.flush(); - for (Entry> entry : sSlotIndexToSubIds.entrySet()) { + for (Entry> entry : mSlotIndexToSubIds.entrySet()) { pw.println(" sSlotIndexToSubId[" + entry.getKey() + "]: subIds=" + entry); } pw.flush(); @@ -4383,10 +4378,10 @@ public class SubscriptionController extends ISub.Stub { } private synchronized boolean addToSubIdList(int slotIndex, int subId, int subscriptionType) { - ArrayList subIdsList = sSlotIndexToSubIds.getCopy(slotIndex); + ArrayList subIdsList = mSlotIndexToSubIds.getCopy(slotIndex); if (subIdsList == null) { subIdsList = new ArrayList<>(); - sSlotIndexToSubIds.put(slotIndex, subIdsList); + mSlotIndexToSubIds.put(slotIndex, subIdsList); } // add the given subId unless it already exists @@ -4396,20 +4391,20 @@ public class SubscriptionController extends ISub.Stub { } if (isSubscriptionForRemoteSim(subscriptionType)) { // For Remote SIM subscriptions, a slot can have multiple subscriptions. - sSlotIndexToSubIds.addToSubIdList(slotIndex, subId); + mSlotIndexToSubIds.addToSubIdList(slotIndex, subId); } else { // for all other types of subscriptions, a slot can have only one subscription at a time - sSlotIndexToSubIds.clearSubIdList(slotIndex); - sSlotIndexToSubIds.addToSubIdList(slotIndex, subId); + mSlotIndexToSubIds.clearSubIdList(slotIndex); + mSlotIndexToSubIds.addToSubIdList(slotIndex, subId); } // Remove the slot from sSlotIndexToSubIds if it has the same sub id with the added slot - for (Entry> entry : sSlotIndexToSubIds.entrySet()) { + for (Entry> entry : mSlotIndexToSubIds.entrySet()) { if (entry.getKey() != slotIndex && entry.getValue() != null && entry.getValue().contains(subId)) { logdl("addToSubIdList - remove " + entry.getKey()); - sSlotIndexToSubIds.remove(entry.getKey()); + mSlotIndexToSubIds.remove(entry.getKey()); } } @@ -4427,17 +4422,7 @@ public class SubscriptionController extends ISub.Stub { */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public Map> getSlotIndexToSubIdsMap() { - return sSlotIndexToSubIds.getMap(); - } - - /** - * This is only for testing - * @hide - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - public void resetStaticMembers() { - sDefaultFallbackSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mDefaultPhoneId = SubscriptionManager.DEFAULT_PHONE_INDEX; + return mSlotIndexToSubIds.getMap(); } private void notifyOpportunisticSubscriptionInfoChanged() { @@ -4786,77 +4771,36 @@ public class SubscriptionController extends ISub.Stub { */ private void setGlobalSetting(String name, int value) { Settings.Global.putInt(mContext.getContentResolver(), name, value); - if (name == Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION) { + if (TextUtils.equals(name, Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION)) { invalidateDefaultDataSubIdCaches(); invalidateActiveDataSubIdCaches(); invalidateDefaultSubIdCaches(); invalidateSlotIndexCaches(); - } else if (name == Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION) { + } else if (TextUtils.equals(name, Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION)) { invalidateDefaultSubIdCaches(); invalidateSlotIndexCaches(); - } else if (name == Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION) { + } else if (TextUtils.equals(name, Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION)) { invalidateDefaultSmsSubIdCaches(); } } - /** - * @hide - */ private static void invalidateDefaultSubIdCaches() { - if (sCachingEnabled) { - SubscriptionManager.invalidateDefaultSubIdCaches(); - } + SubscriptionManager.invalidateDefaultSubIdCaches(); } - /** - * @hide - */ private static void invalidateDefaultDataSubIdCaches() { - if (sCachingEnabled) { - SubscriptionManager.invalidateDefaultDataSubIdCaches(); - } + SubscriptionManager.invalidateDefaultDataSubIdCaches(); } - /** - * @hide - */ private static void invalidateDefaultSmsSubIdCaches() { - if (sCachingEnabled) { - SubscriptionManager.invalidateDefaultSmsSubIdCaches(); - } + SubscriptionManager.invalidateDefaultSmsSubIdCaches(); } - /** - * @hide - */ - public static void invalidateActiveDataSubIdCaches() { - if (sCachingEnabled) { - SubscriptionManager.invalidateActiveDataSubIdCaches(); - } - } - - /** - * @hide - */ - protected static void invalidateSlotIndexCaches() { - if (sCachingEnabled) { - SubscriptionManager.invalidateSlotIndexCaches(); - } + private static void invalidateActiveDataSubIdCaches() { + SubscriptionManager.invalidateActiveDataSubIdCaches(); } - /** - * @hide - */ - @VisibleForTesting - public static void disableCaching() { - sCachingEnabled = false; - } - - /** - * @hide - */ - @VisibleForTesting - public static void enableCaching() { - sCachingEnabled = true; + private static void invalidateSlotIndexCaches() { + SubscriptionManager.invalidateSlotIndexCaches(); } } diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 47ae22503a..6370c21bad 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -245,7 +245,7 @@ public class PhoneSwitcher extends Handler { @Override public void set(int newValue) { super.set(newValue); - SubscriptionController.invalidateActiveDataSubIdCaches(); + SubscriptionManager.invalidateActiveDataSubIdCaches(); } }; @@ -391,7 +391,7 @@ public class PhoneSwitcher extends Handler { public static PhoneSwitcher make(int maxDataAttachModemCount, Context context, Looper looper) { if (sPhoneSwitcher == null) { sPhoneSwitcher = new PhoneSwitcher(maxDataAttachModemCount, context, looper); - SubscriptionController.invalidateActiveDataSubIdCaches(); + SubscriptionManager.invalidateActiveDataSubIdCaches(); } return sPhoneSwitcher; diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index cd1bc395cb..dabc87eac9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -32,7 +32,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -154,7 +153,6 @@ public class SubscriptionControllerTest extends TelephonyTest { * between each test case. */ if (mSubscriptionControllerUT != null) { mSubscriptionControllerUT.clearSubInfo(); - mSubscriptionControllerUT.resetStaticMembers(); mSubscriptionControllerUT = null; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 6cb7464ff0..dc2d00a4f8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -33,6 +33,7 @@ import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.KeyguardManager; +import android.app.PropertyInvalidatedCache; import android.app.usage.NetworkStatsManager; import android.content.ContentProvider; import android.content.ContentResolver; @@ -494,7 +495,7 @@ public abstract class TelephonyTest { mSsDomainController = Mockito.mock(SsDomainController.class); TelephonyManager.disableServiceHandleCaching(); - SubscriptionController.disableCaching(); + PropertyInvalidatedCache.disableForTestMode(); // For testing do not allow Log.WTF as it can cause test process to crash Log.setWtfHandler((tagString, what, system) -> Log.d(TAG, "WTF captured, ignoring. Tag: " + tagString + ", exception: " + what)); @@ -877,7 +878,6 @@ public abstract class TelephonyTest { } restoreInstances(); TelephonyManager.enableServiceHandleCaching(); - SubscriptionController.enableCaching(); mNetworkRegistrationInfo = null; mActivityManager = null; -- GitLab From 6f12c3f917ed48aed9e4e1e279483684ac020688 Mon Sep 17 00:00:00 2001 From: youngtaecha Date: Thu, 18 Aug 2022 09:07:07 +0000 Subject: [PATCH 070/656] Enable adb command for CB test for multi-sim case Bug: 243324749 Test: Manual - send a test message through adb command to phone_id 1 and verify the test message is received. Change-Id: I9f7706aa6de7079ee6d3d0fa992d3b2021956544 --- .../internal/telephony/gsm/GsmInboundSmsHandler.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java index 0abd4ab711..b1f62facdc 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java @@ -43,7 +43,7 @@ import com.android.internal.telephony.uicc.UsimServiceTable; */ public class GsmInboundSmsHandler extends InboundSmsHandler { - private static BroadcastReceiver sTestBroadcastReceiver; + private BroadcastReceiver mTestBroadcastReceiver; /** Handler for SMS-PP data download messages to UICC. */ private final UsimDataDownloadHandler mDataDownloadHandler; @@ -63,11 +63,11 @@ public class GsmInboundSmsHandler extends InboundSmsHandler { mCellBroadcastServiceManager.enable(); if (TEST_MODE) { - if (sTestBroadcastReceiver == null) { - sTestBroadcastReceiver = new GsmCbTestBroadcastReceiver(); + if (mTestBroadcastReceiver == null) { + mTestBroadcastReceiver = new GsmCbTestBroadcastReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(TEST_ACTION); - context.registerReceiver(sTestBroadcastReceiver, filter, + context.registerReceiver(mTestBroadcastReceiver, filter, Context.RECEIVER_EXPORTED); } } -- GitLab From 692599b352d344a755c62c9e2b86140c43952799 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Tue, 23 Aug 2022 04:09:41 +0000 Subject: [PATCH 071/656] Fix resource leakage and re-enable GsmInboundSmsHandler tests Bug: 188073459 Test: atest com.android.internal.telephony.gsm.GsmInboundSmsHandlerTest Change-Id: I4c92c7c1467366cef90bb36460875de048b97423 --- .../gsm/GsmInboundSmsHandlerTest.java | 35 +++++-------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java index a847a24d05..967941c7f1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java @@ -55,7 +55,6 @@ import android.test.mock.MockContentResolver; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import androidx.test.filters.FlakyTest; import androidx.test.filters.MediumTest; import com.android.internal.telephony.FakeSmsContentProvider; @@ -192,9 +191,9 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { InboundSmsHandler.SOURCE_NOT_INJECTED); doReturn(mInboundSmsTracker).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(Context.class), nullable(byte[].class), anyLong(), - anyInt(), anyBoolean(), - anyBoolean(), nullable(String.class), nullable(String.class), - nullable(String.class), anyBoolean(), anyInt(), anyInt()); + anyInt(), anyBoolean(), + anyBoolean(), nullable(String.class), nullable(String.class), + nullable(String.class), anyBoolean(), anyInt(), anyInt()); createInboundSmsTrackerMultiSim(); @@ -310,7 +309,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { processAllMessages(); } - @FlakyTest @Test @MediumTest public void testNewSms() { @@ -330,7 +328,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(times(1)); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testNewSmsFromBlockedNumber_noBroadcastsSent() { @@ -348,7 +345,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(times(1)); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testNewSmsWithUserLocked_notificationShown() { @@ -375,7 +371,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { any(Notification.class)); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testNewSmsFromBlockedNumberWithUserLocked_noNotificationShown() { @@ -405,7 +400,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { any(Notification.class)); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testNewSms_filterInvoked_noBroadcastsSent() { @@ -431,7 +425,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { anyBoolean(), anyBoolean(), Mockito.>any()); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testNewSms_filterChaining_noBroadcastsSent() { @@ -483,7 +476,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { assertEquals("IdleState", getCurrentState().getName()); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testClass0Sms() { @@ -515,7 +507,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(times(1)); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testBroadcastSms() { @@ -556,7 +547,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(times(2)); } - @FlakyTest @Test @MediumTest public void testInjectSms() { @@ -617,7 +607,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { InboundSmsHandler.SOURCE_NOT_INJECTED); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testMultiPartSmsWithIncompleteWAP() { @@ -678,12 +667,13 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { assertEquals("IdleState", getCurrentState().getName()); // verify there are three segments in the db and only one of them is not marked as deleted. assertEquals(3, mContentProvider.getNumRows()); - assertEquals(1, mContentProvider.query(sRawUri, null, "deleted=0", null, null).getCount()); + Cursor c = mContentProvider.query(sRawUri, null, "deleted=0", null, null); + assertEquals(1, c.getCount()); verifySmsFiltersInvoked(times(1)); + c.close(); } - @FlakyTest @Test @MediumTest public void testMultiPartSms() { @@ -757,7 +747,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { assertEquals("IdleState", getCurrentState().getName()); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testMultiPartIncompleteSms() { @@ -820,9 +809,9 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { // State machine should go back to idle assertEquals("IdleState", getCurrentState().getName()); verifySmsFiltersInvoked(never()); + c.close(); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testMultiPartSmsWithInvalidSeqNumber() { @@ -882,7 +871,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(never()); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testMultipartSmsFromBlockedNumber_noBroadcastsSent() { @@ -921,7 +909,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(times(1)); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testMultipartSmsFromBlockedEmail_noBroadcastsSent() { @@ -977,7 +964,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(times(1)); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testMultipartSms_filterInvoked_noBroadcastsSent() { @@ -1027,7 +1013,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { anyBoolean(), anyBoolean(), Mockito.>any()); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testBroadcastUndeliveredUserLocked() throws Exception { @@ -1085,7 +1070,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(times(1)); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testBroadcastUndeliveredUserUnlocked() throws Exception { @@ -1123,7 +1107,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(times(1)); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testBroadcastUndeliveredDeleted() throws Exception { @@ -1164,7 +1147,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(never()); } - @FlakyTest @Test @MediumTest public void testBroadcastUndeliveredMultiPart() throws Exception { @@ -1180,7 +1162,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { //return InboundSmsTracker objects corresponding to the 2 parts doReturn(mInboundSmsTrackerPart1).doReturn(mInboundSmsTrackerPart2). when(mTelephonyComponentFactory).makeInboundSmsTracker(any(Context.class), - any(Cursor.class), anyBoolean()); + any(Cursor.class), anyBoolean()); SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler); // wait for ScanRawTableThread @@ -1191,7 +1173,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsFiltersInvoked(times(1)); } - @FlakyTest // temporarily disabled, see b/182498318 @Test @MediumTest public void testBroadcastUndeliveredMultiSim() throws Exception { -- GitLab From f8de86cfd00af5ec0476a5c81633fbd129f1b8e8 Mon Sep 17 00:00:00 2001 From: Simon MacMullen Date: Fri, 29 Jul 2022 17:58:16 +0000 Subject: [PATCH 072/656] RIL instrumentation Add atrace invocations for each RPC and unsolicited message from the CP, similar to how we already log. Bug: 240667497 Test: Recorded a trace. Change-Id: I552c16e99d72211c36a46e94926e5d67852bed01 --- .../internal/telephony/DataIndication.java | 17 +- .../telephony/MessagingIndication.java | 18 +- .../internal/telephony/ModemIndication.java | 14 +- .../internal/telephony/NetworkIndication.java | 30 ++-- .../com/android/internal/telephony/RIL.java | 52 ++++-- .../internal/telephony/RadioConfig.java | 8 +- .../telephony/RadioConfigIndicationAidl.java | 6 +- .../telephony/RadioConfigIndicationHidl.java | 8 +- .../internal/telephony/RadioIndication.java | 158 ++++++++++-------- .../internal/telephony/SimIndication.java | 31 ++-- .../internal/telephony/VoiceIndication.java | 34 ++-- 11 files changed, 223 insertions(+), 153 deletions(-) diff --git a/src/java/com/android/internal/telephony/DataIndication.java b/src/java/com/android/internal/telephony/DataIndication.java index c16cbaad2d..346795589a 100644 --- a/src/java/com/android/internal/telephony/DataIndication.java +++ b/src/java/com/android/internal/telephony/DataIndication.java @@ -55,7 +55,7 @@ public class DataIndication extends IRadioDataIndication.Stub { android.hardware.radio.data.SetupDataCallResult[] dcList) { mRil.processIndication(RIL.DATA_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_DATA_CALL_LIST_CHANGED, dcList); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_DATA_CALL_LIST_CHANGED, dcList); ArrayList response = RILUtils.convertHalDataCallResultList(dcList); mRil.mDataCallListChangedRegistrants.notifyRegistrants( new AsyncResult(null, response, null)); @@ -70,9 +70,10 @@ public class DataIndication extends IRadioDataIndication.Stub { android.hardware.radio.data.KeepaliveStatus halStatus) { mRil.processIndication(RIL.DATA_SERVICE, indicationType); - if (RIL.RILJ_LOGD) { - mRil.unsljLogRet(RIL_UNSOL_KEEPALIVE_STATUS, "handle=" + halStatus.sessionHandle - + " code=" + halStatus.code); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet( + RIL_UNSOL_KEEPALIVE_STATUS, + "handle=" + halStatus.sessionHandle + " code=" + halStatus.code); } KeepaliveStatus ks = new KeepaliveStatus( @@ -90,7 +91,7 @@ public class DataIndication extends IRadioDataIndication.Stub { PcoData response = new PcoData(pco.cid, pco.bearerProto, pco.pcoId, pco.contents); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_PCO_DATA, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_PCO_DATA, response); mRil.mPcoDataRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } @@ -106,7 +107,7 @@ public class DataIndication extends IRadioDataIndication.Stub { mRil.processIndication(RIL.DATA_SERVICE, indicationType); DataProfile response = RILUtils.convertToDataProfile(dpi); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_UNTHROTTLE_APN, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_UNTHROTTLE_APN, response); mRil.mApnUnthrottledRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } @@ -120,7 +121,9 @@ public class DataIndication extends IRadioDataIndication.Stub { public void slicingConfigChanged(int indicationType, android.hardware.radio.data.SlicingConfig slicingConfig) throws RemoteException { mRil.processIndication(RIL.DATA_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SLICING_CONFIG_CHANGED, slicingConfig); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_SLICING_CONFIG_CHANGED, slicingConfig); + } NetworkSlicingConfig ret = RILUtils.convertHalSlicingConfig(slicingConfig); mRil.mSlicingConfigChangedRegistrants.notifyRegistrants( new AsyncResult(null, ret, null)); diff --git a/src/java/com/android/internal/telephony/MessagingIndication.java b/src/java/com/android/internal/telephony/MessagingIndication.java index 86e30b085c..96e74cc767 100644 --- a/src/java/com/android/internal/telephony/MessagingIndication.java +++ b/src/java/com/android/internal/telephony/MessagingIndication.java @@ -49,7 +49,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { android.hardware.radio.messaging.CdmaSmsMessage msg) { mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CDMA_NEW_SMS); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_CDMA_NEW_SMS); SmsMessage sms = new SmsMessage(RILUtils.convertHalCdmaSmsMessage(msg)); if (mRil.mCdmaSmsRegistrant != null) { @@ -65,7 +65,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { public void cdmaRuimSmsStorageFull(int indicationType) { mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL); if (mRil.mIccSmsFullRegistrant != null) { mRil.mIccSmsFullRegistrant.notifyRegistrant(); @@ -84,9 +84,9 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { public void newBroadcastSms(int indicationType, byte[] data) { mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); - if (RIL.RILJ_LOGD) { - mRil.unsljLogvRet(RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, - IccUtils.bytesToHexString(data)); + if (mRil.isLogOrTrace()) { + mRil.unsljLogvRet( + RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, IccUtils.bytesToHexString(data)); } if (mRil.mGsmBroadcastSmsRegistrant != null) { @@ -102,7 +102,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { */ public void newSms(int indicationType, byte[] pdu) { mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS); SmsMessageBase smsb = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); if (mRil.mGsmSmsRegistrant != null) { @@ -119,7 +119,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { public void newSmsOnSim(int indicationType, int recordNumber) { mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM); if (mRil.mSmsOnSimRegistrant != null) { mRil.mSmsOnSimRegistrant.notifyRegistrant(new AsyncResult(null, recordNumber, null)); @@ -135,7 +135,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { public void newSmsStatusReport(int indicationType, byte[] pdu) { mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT); if (mRil.mSmsStatusRegistrant != null) { mRil.mSmsStatusRegistrant.notifyRegistrant(new AsyncResult(null, pdu, null)); @@ -151,7 +151,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { public void simSmsStorageFull(int indicationType) { mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_SIM_SMS_STORAGE_FULL); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SIM_SMS_STORAGE_FULL); if (mRil.mIccSmsFullRegistrant != null) { mRil.mIccSmsFullRegistrant.notifyRegistrant(); diff --git a/src/java/com/android/internal/telephony/ModemIndication.java b/src/java/com/android/internal/telephony/ModemIndication.java index 8baa5fd957..d05e0f6730 100644 --- a/src/java/com/android/internal/telephony/ModemIndication.java +++ b/src/java/com/android/internal/telephony/ModemIndication.java @@ -48,7 +48,7 @@ public class ModemIndication extends IRadioModemIndication.Stub { ArrayList response = RILUtils.convertHalHardwareConfigList(configs); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, response); mRil.mHardwareConfigChangeRegistrants.notifyRegistrants( new AsyncResult(null, response, null)); @@ -64,7 +64,7 @@ public class ModemIndication extends IRadioModemIndication.Stub { public void modemReset(int indicationType, String reason) { mRil.processIndication(RIL.MODEM_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_MODEM_RESTART, reason); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_MODEM_RESTART, reason); mRil.writeMetricsModemRestartEvent(reason); mRil.mModemResetRegistrants.notifyRegistrants(new AsyncResult(null, reason, null)); @@ -82,7 +82,7 @@ public class ModemIndication extends IRadioModemIndication.Stub { RadioCapability response = RILUtils.convertHalRadioCapability(radioCapability, mRil); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_RADIO_CAPABILITY, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_RADIO_CAPABILITY, response); mRil.mPhoneRadioCapabilityChangedRegistrants.notifyRegistrants( new AsyncResult(null, response, null)); @@ -97,9 +97,9 @@ public class ModemIndication extends IRadioModemIndication.Stub { mRil.processIndication(RIL.MODEM_SERVICE, indicationType); int state = RILUtils.convertHalRadioState(radioState); - if (RIL.RILJ_LOGD) { - mRil.unsljLogMore(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, "radioStateChanged: " - + state); + if (mRil.isLogOrTrace()) { + mRil.unsljLogMore( + RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, "radioStateChanged: " + state); } mRil.setRadioState(state, false /* forceNotifyRegistrants */); @@ -112,7 +112,7 @@ public class ModemIndication extends IRadioModemIndication.Stub { public void rilConnected(int indicationType) { mRil.processIndication(RIL.MODEM_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RIL_CONNECTED); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RIL_CONNECTED); // Initial conditions mRil.setRadioPower(false, null); diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index 17d906e7db..c9ebfd546c 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -97,7 +97,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { int[] response = new int[]{version}; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_PRL_CHANGED, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_CDMA_PRL_CHANGED, response); mRil.mCdmaPrlChangedRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } @@ -111,7 +111,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { android.hardware.radio.network.CellInfo[] records) { mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); ArrayList response = RILUtils.convertHalCellInfoList(records); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CELL_INFO_LIST, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_CELL_INFO_LIST, response); mRil.mRilCellInfoListRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } @@ -126,7 +126,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { List response = RILUtils.convertHalLceData(lce); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); if (mRil.mLceInfoRegistrants != null) { mRil.mLceInfoRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); @@ -178,7 +178,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { mRil.riljLoge("Invalid PhysicalChannelConfig " + iae); return; } - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG, response); mRil.mPhysicalChannelConfigurationRegistrants.notifyRegistrants( new AsyncResult(null, response, null)); @@ -197,7 +197,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { SignalStrength ss = mRil.fixupSignalStrength10(ssInitial); // Note this is set to "verbose" because it happens frequently - if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); + if (mRil.isLogvOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); if (mRil.mSignalStrengthRegistrant != null) { mRil.mSignalStrengthRegistrant.notifyRegistrant(new AsyncResult(null, ss, null)); @@ -211,7 +211,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { public void imsNetworkStateChanged(int indicationType) { mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED); mRil.mImsNetworkStateChangedRegistrants.notifyRegistrants(); } @@ -227,7 +227,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { ArrayList cellInfos = RILUtils.convertHalCellInfoList(result.networkInfos); NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null)); } @@ -238,7 +238,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { public void networkStateChanged(int indicationType) { mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED); mRil.mNetworkStateRegistrants.notifyRegistrants(); } @@ -258,7 +258,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { @ElapsedRealtimeLong long receivedTimeMs, long ageMs) { mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime); // Ignore the NITZ if receivedTimeMs or ageMs is not a valid time. // e.g. receivedTimeMs is non-positive, ageMs is negative or greater than receivedTimeMs. @@ -280,7 +280,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { boolean ignoreNitz = TelephonyProperties.ignore_nitz().orElse(false); if (ignoreNitz) { - if (RIL.RILJ_LOGD) mRil.riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED"); + if (mRil.isLogOrTrace()) mRil.riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED"); } else { if (mRil.mNITZTimeRegistrant != null) { mRil.mNITZTimeRegistrant.notifyRegistrant(new AsyncResult(null, result, null)); @@ -330,7 +330,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { public void restrictedStateChanged(int indicationType, int state) { mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogvRet(RIL_UNSOL_RESTRICTED_STATE_CHANGED, state); + if (mRil.isLogOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_RESTRICTED_STATE_CHANGED, state); if (mRil.mRestrictedStateRegistrant != null) { mRil.mRestrictedStateRegistrant.notifyRegistrant(new AsyncResult(null, state, null)); @@ -353,7 +353,9 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { notification.type = suppSvcNotification.type; notification.number = suppSvcNotification.number; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SUPP_SVC_NOTIFICATION, notification); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_SUPP_SVC_NOTIFICATION, notification); + } if (mRil.mSsnRegistrant != null) { mRil.mSsnRegistrant.notifyRegistrant(new AsyncResult(null, notification, null)); @@ -370,7 +372,9 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { int[] response = new int[] {rat}; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, response); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, response); + } mRil.mVoiceRadioTechChangedRegistrants.notifyRegistrants( new AsyncResult(null, response, null)); diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 49e8297c45..6de66527e1 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -41,6 +41,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.Trace; import android.os.WorkSource; import android.provider.Settings; import android.sysprop.TelephonyProperties; @@ -1162,6 +1163,8 @@ public class RIL extends BaseCommands implements CommandsInterface { private void addRequest(RILRequest rr) { acquireWakeLock(rr, FOR_WAKELOCK); + Trace.asyncTraceForTrackBegin( + Trace.TRACE_TAG_NETWORK, "RIL", RILUtils.requestToString(rr.mRequest), rr.mSerial); synchronized (mRequestList) { rr.mStartTimeMs = SystemClock.elapsedRealtime(); mRequestList.append(rr.mSerial, rr); @@ -5186,6 +5189,7 @@ public class RIL extends BaseCommands implements CommandsInterface { + " ,error: " + error); return null; } + Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_NETWORK, "RIL", "" /* unused */, rr.mSerial); // Time logging for RIL command and storing it in TelephonyHistogram. addToRilHistogram(rr); @@ -5732,43 +5736,43 @@ public class RIL extends BaseCommands implements CommandsInterface { int response = RIL_UNSOL_CDMA_INFO_REC; if (infoRec.record instanceof CdmaInformationRecords.CdmaDisplayInfoRec) { if (mDisplayInfoRegistrants != null) { - if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + if (isLogOrTrace()) unsljLogRet(response, infoRec.record); mDisplayInfoRegistrants.notifyRegistrants( new AsyncResult(null, infoRec.record, null)); } } else if (infoRec.record instanceof CdmaInformationRecords.CdmaSignalInfoRec) { if (mSignalInfoRegistrants != null) { - if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + if (isLogOrTrace()) unsljLogRet(response, infoRec.record); mSignalInfoRegistrants.notifyRegistrants( new AsyncResult(null, infoRec.record, null)); } } else if (infoRec.record instanceof CdmaInformationRecords.CdmaNumberInfoRec) { if (mNumberInfoRegistrants != null) { - if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + if (isLogOrTrace()) unsljLogRet(response, infoRec.record); mNumberInfoRegistrants.notifyRegistrants( new AsyncResult(null, infoRec.record, null)); } } else if (infoRec.record instanceof CdmaInformationRecords.CdmaRedirectingNumberInfoRec) { if (mRedirNumInfoRegistrants != null) { - if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + if (isLogOrTrace()) unsljLogRet(response, infoRec.record); mRedirNumInfoRegistrants.notifyRegistrants( new AsyncResult(null, infoRec.record, null)); } } else if (infoRec.record instanceof CdmaInformationRecords.CdmaLineControlInfoRec) { if (mLineControlInfoRegistrants != null) { - if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + if (isLogOrTrace()) unsljLogRet(response, infoRec.record); mLineControlInfoRegistrants.notifyRegistrants( new AsyncResult(null, infoRec.record, null)); } } else if (infoRec.record instanceof CdmaInformationRecords.CdmaT53ClirInfoRec) { if (mT53ClirInfoRegistrants != null) { - if (RILJ_LOGD) unsljLogRet(response, infoRec.record); + if (isLogOrTrace()) unsljLogRet(response, infoRec.record); mT53ClirInfoRegistrants.notifyRegistrants( new AsyncResult(null, infoRec.record, null)); } } else if (infoRec.record instanceof CdmaInformationRecords.CdmaT53AudioControlInfoRec) { if (mT53AudCntrlInfoRegistrants != null) { - if (RILJ_LOGD) { + if (isLogOrTrace()) { unsljLogRet(response, infoRec.record); } mT53AudCntrlInfoRegistrants.notifyRegistrants( @@ -5790,26 +5794,48 @@ public class RIL extends BaseCommands implements CommandsInterface { Rlog.v(RILJ_LOG_TAG, msg + (" [PHONE" + mPhoneId + "]")); } + boolean isLogOrTrace() { + return RIL.RILJ_LOGD || Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK); + } + + boolean isLogvOrTrace() { + return RIL.RILJ_LOGV || Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK); + } + @UnsupportedAppUsage void unsljLog(int response) { - riljLog("[UNSL]< " + RILUtils.responseToString(response)); + String logStr = RILUtils.responseToString(response); + if (RIL.RILJ_LOGD) { + riljLog("[UNSL]< " + logStr); + } + Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", logStr); } @UnsupportedAppUsage void unsljLogMore(int response, String more) { - riljLog("[UNSL]< " + RILUtils.responseToString(response) + " " + more); + String logStr = RILUtils.responseToString(response) + " " + more; + if (RIL.RILJ_LOGD) { + riljLog("[UNSL]< " + logStr); + } + Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", logStr); } @UnsupportedAppUsage void unsljLogRet(int response, Object ret) { - riljLog("[UNSL]< " + RILUtils.responseToString(response) + " " - + retToString(response, ret)); + String logStr = RILUtils.responseToString(response) + " " + retToString(response, ret); + if (RIL.RILJ_LOGD) { + riljLog("[UNSL]< " + logStr); + } + Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", logStr); } @UnsupportedAppUsage void unsljLogvRet(int response, Object ret) { - riljLogv("[UNSL]< " + RILUtils.responseToString(response) + " " - + retToString(response, ret)); + String logStr = RILUtils.responseToString(response) + " " + retToString(response, ret); + if (RIL.RILJ_LOGV) { + riljLogv("[UNSL]< " + logStr); + } + Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", logStr); } @Override diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java index 9ac03b1cb9..e455ecbe74 100644 --- a/src/java/com/android/internal/telephony/RadioConfig.java +++ b/src/java/com/android/internal/telephony/RadioConfig.java @@ -36,6 +36,7 @@ import android.os.Message; import android.os.Registrant; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.Trace; import android.os.WorkSource; import android.telephony.TelephonyManager; import android.telephony.UiccSlotMapping; @@ -44,7 +45,6 @@ import android.util.SparseArray; import com.android.telephony.Rlog; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.NoSuchElementException; import java.util.concurrent.atomic.AtomicLong; @@ -342,6 +342,9 @@ public class RadioConfig extends Handler { private RILRequest obtainRequest(int request, Message result, WorkSource workSource) { RILRequest rr = RILRequest.obtain(request, result, workSource); + Trace.asyncTraceForTrackBegin( + Trace.TRACE_TAG_NETWORK, "RIL", RILUtils.requestToString(rr.mRequest), rr.mSerial); + synchronized (mRequestList) { mRequestList.append(rr.mSerial, rr); } @@ -352,7 +355,10 @@ public class RadioConfig extends Handler { RILRequest rr; synchronized (mRequestList) { rr = mRequestList.get(serial); + if (rr != null) { + Trace.asyncTraceForTrackEnd( + Trace.TRACE_TAG_NETWORK, "RIL", "" /* unused */, rr.mSerial); mRequestList.remove(serial); } } diff --git a/src/java/com/android/internal/telephony/RadioConfigIndicationAidl.java b/src/java/com/android/internal/telephony/RadioConfigIndicationAidl.java index 851a8ef6f4..76e6d5e4bb 100644 --- a/src/java/com/android/internal/telephony/RadioConfigIndicationAidl.java +++ b/src/java/com/android/internal/telephony/RadioConfigIndicationAidl.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import android.os.AsyncResult; +import android.os.Trace; import com.android.internal.telephony.uicc.IccSlotStatus; import com.android.telephony.Rlog; @@ -43,7 +44,7 @@ public class RadioConfigIndicationAidl extends public void simSlotsStatusChanged( int type, android.hardware.radio.config.SimSlotStatus[] slotStatus) { ArrayList ret = RILUtils.convertHalSlotStatus(slotStatus); - logd("[UNSL]< UNSOL_SIM_SLOT_STATUS_CHANGED " + ret.toString()); + logd("UNSOL_SIM_SLOT_STATUS_CHANGED " + ret.toString()); if (mRadioConfig.mSimSlotStatusRegistrant != null) { mRadioConfig.mSimSlotStatusRegistrant.notifyRegistrant( new AsyncResult(null, ret, null)); @@ -51,7 +52,8 @@ public class RadioConfigIndicationAidl extends } private static void logd(String log) { - Rlog.d(TAG, log); + Rlog.d(TAG, "[UNSL]< " + log); + Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", log); } @Override diff --git a/src/java/com/android/internal/telephony/RadioConfigIndicationHidl.java b/src/java/com/android/internal/telephony/RadioConfigIndicationHidl.java index 23a676b247..3b5330b9e8 100644 --- a/src/java/com/android/internal/telephony/RadioConfigIndicationHidl.java +++ b/src/java/com/android/internal/telephony/RadioConfigIndicationHidl.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import android.os.AsyncResult; +import android.os.Trace; import com.android.internal.telephony.uicc.IccSlotStatus; import com.android.telephony.Rlog; @@ -42,7 +43,7 @@ public class RadioConfigIndicationHidl extends public void simSlotsStatusChanged(int indicationType, ArrayList slotStatus) { ArrayList ret = RILUtils.convertHalSlotStatus(slotStatus); - logd("[UNSL]< UNSOL_SIM_SLOT_STATUS_CHANGED " + ret.toString()); + logd("UNSOL_SIM_SLOT_STATUS_CHANGED " + ret.toString()); if (mRadioConfig.mSimSlotStatusRegistrant != null) { mRadioConfig.mSimSlotStatusRegistrant.notifyRegistrant( new AsyncResult(null, ret, null)); @@ -55,7 +56,7 @@ public class RadioConfigIndicationHidl extends public void simSlotsStatusChanged_1_2(int indicationType, ArrayList slotStatus) { ArrayList ret = RILUtils.convertHalSlotStatus(slotStatus); - logd("[UNSL]< UNSOL_SIM_SLOT_STATUS_CHANGED " + ret.toString()); + logd("UNSOL_SIM_SLOT_STATUS_CHANGED " + ret.toString()); if (mRadioConfig.mSimSlotStatusRegistrant != null) { mRadioConfig.mSimSlotStatusRegistrant.notifyRegistrant( new AsyncResult(null, ret, null)); @@ -63,6 +64,7 @@ public class RadioConfigIndicationHidl extends } private static void logd(String log) { - Rlog.d(TAG, log); + Rlog.d(TAG, "[UNSL]< " + log); + Trace.instantForTrack(Trace.TRACE_TAG_NETWORK, "RIL", log); } } diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java index c7244be82e..d947d53611 100644 --- a/src/java/com/android/internal/telephony/RadioIndication.java +++ b/src/java/com/android/internal/telephony/RadioIndication.java @@ -139,9 +139,9 @@ public class RadioIndication extends IRadioIndication.Stub { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); int state = RILUtils.convertHalRadioState(radioState); - if (RIL.RILJ_LOGD) { - mRil.unsljLogMore(RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, "radioStateChanged: " + - state); + if (mRil.isLogOrTrace()) { + mRil.unsljLogMore( + RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, "radioStateChanged: " + state); } mRil.setRadioState(state, false /* forceNotifyRegistrants */); @@ -150,7 +150,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void callStateChanged(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED); mRil.mCallStateRegistrants.notifyRegistrants(); } @@ -162,7 +162,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void networkStateChanged(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED); mRil.mNetworkStateRegistrants.notifyRegistrants(); } @@ -171,7 +171,7 @@ public class RadioIndication extends IRadioIndication.Stub { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); byte[] pduArray = RILUtils.arrayListToPrimitiveArray(pdu); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS); SmsMessageBase smsb = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pduArray); if (mRil.mGsmSmsRegistrant != null) { @@ -184,7 +184,7 @@ public class RadioIndication extends IRadioIndication.Stub { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); byte[] pduArray = RILUtils.arrayListToPrimitiveArray(pdu); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT); if (mRil.mSmsStatusRegistrant != null) { mRil.mSmsStatusRegistrant.notifyRegistrant(new AsyncResult(null, pduArray, null)); @@ -194,7 +194,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void newSmsOnSim(int indicationType, int recordNumber) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM); if (mRil.mSmsOnSimRegistrant != null) { mRil.mSmsOnSimRegistrant.notifyRegistrant(new AsyncResult(null, recordNumber, null)); @@ -204,7 +204,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void onUssd(int indicationType, int ussdModeType, String msg) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogMore(RIL_UNSOL_ON_USSD, "" + ussdModeType); + if (mRil.isLogOrTrace()) mRil.unsljLogMore(RIL_UNSOL_ON_USSD, "" + ussdModeType); // todo: Clean this up with a parcelable class for better self-documentation String[] resp = new String[2]; @@ -218,7 +218,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void nitzTimeReceived(int indicationType, String nitzTime, long receivedTime) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime); // todo: Clean this up with a parcelable class for better self-documentation Object[] result = new Object[2]; @@ -228,7 +228,7 @@ public class RadioIndication extends IRadioIndication.Stub { boolean ignoreNitz = TelephonyProperties.ignore_nitz().orElse(false); if (ignoreNitz) { - if (RIL.RILJ_LOGD) mRil.riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED"); + if (mRil.isLogOrTrace()) mRil.riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED"); } else { if (mRil.mNITZTimeRegistrant != null) { mRil.mNITZTimeRegistrant.notifyRegistrant(new AsyncResult (null, result, null)); @@ -247,7 +247,7 @@ public class RadioIndication extends IRadioIndication.Stub { SignalStrength ss = mRil.fixupSignalStrength10(ssInitial); // Note this is set to "verbose" because it happens frequently - if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); + if (mRil.isLogvOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); if (mRil.mSignalStrengthRegistrant != null) { mRil.mSignalStrengthRegistrant.notifyRegistrant(new AsyncResult (null, ss, null)); @@ -263,7 +263,7 @@ public class RadioIndication extends IRadioIndication.Stub { List response = RILUtils.convertHalLceData(lce); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); if (mRil.mLceInfoRegistrants != null) { mRil.mLceInfoRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); @@ -279,7 +279,7 @@ public class RadioIndication extends IRadioIndication.Stub { List response = RILUtils.convertHalLceData(lce); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); if (mRil.mLceInfoRegistrants != null) { mRil.mLceInfoRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); @@ -295,7 +295,7 @@ public class RadioIndication extends IRadioIndication.Stub { SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength); // Note this is set to "verbose" because it happens frequently - if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); + if (mRil.isLogvOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); if (mRil.mSignalStrengthRegistrant != null) { mRil.mSignalStrengthRegistrant.notifyRegistrant(new AsyncResult(null, ss, null)); @@ -312,7 +312,7 @@ public class RadioIndication extends IRadioIndication.Stub { SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength); - if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); + if (mRil.isLogvOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); if (mRil.mSignalStrengthRegistrant != null) { mRil.mSignalStrengthRegistrant.notifyRegistrant(new AsyncResult(null, ss, null)); @@ -329,7 +329,7 @@ public class RadioIndication extends IRadioIndication.Stub { SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength); - if (RIL.RILJ_LOGV) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); + if (mRil.isLogvOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_SIGNAL_STRENGTH, ss); if (mRil.mSignalStrengthRegistrant != null) { mRil.mSignalStrengthRegistrant.notifyRegistrant(new AsyncResult(null, ss, null)); @@ -380,7 +380,7 @@ public class RadioIndication extends IRadioIndication.Stub { response.add(emergencyNumber); } - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_EMERGENCY_NUMBER_LIST, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_EMERGENCY_NUMBER_LIST, response); // Cache emergency number list from last indication. mRil.cacheEmergencyNumberListIndication(response); @@ -431,7 +431,9 @@ public class RadioIndication extends IRadioIndication.Stub { notification.type = suppSvcNotification.type; notification.number = suppSvcNotification.number; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SUPP_SVC_NOTIFICATION, notification); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_SUPP_SVC_NOTIFICATION, notification); + } if (mRil.mSsnRegistrant != null) { mRil.mSsnRegistrant.notifyRegistrant(new AsyncResult (null, notification, null)); @@ -441,7 +443,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void stkSessionEnd(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_STK_SESSION_END); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_SESSION_END); if (mRil.mCatSessionEndRegistrant != null) { mRil.mCatSessionEndRegistrant.notifyRegistrant(new AsyncResult (null, null, null)); @@ -451,7 +453,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void stkProactiveCommand(int indicationType, String cmd) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_STK_PROACTIVE_COMMAND); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_PROACTIVE_COMMAND); if (mRil.mCatProCmdRegistrant != null) { mRil.mCatProCmdRegistrant.notifyRegistrant(new AsyncResult (null, cmd, null)); @@ -461,7 +463,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void stkEventNotify(int indicationType, String cmd) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_STK_EVENT_NOTIFY); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_EVENT_NOTIFY); if (mRil.mCatEventRegistrant != null) { mRil.mCatEventRegistrant.notifyRegistrant(new AsyncResult (null, cmd, null)); @@ -471,7 +473,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void stkCallSetup(int indicationType, long timeout) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_STK_CALL_SETUP, timeout); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_STK_CALL_SETUP, timeout); if (mRil.mCatCallSetUpRegistrant != null) { mRil.mCatCallSetUpRegistrant.notifyRegistrant(new AsyncResult (null, timeout, null)); @@ -481,7 +483,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void simSmsStorageFull(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_SIM_SMS_STORAGE_FULL); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SIM_SMS_STORAGE_FULL); if (mRil.mIccSmsFullRegistrant != null) { mRil.mIccSmsFullRegistrant.notifyRegistrant(); @@ -496,7 +498,7 @@ public class RadioIndication extends IRadioIndication.Stub { response.efId = refreshResult.efId; response.aid = refreshResult.aid; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SIM_REFRESH, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_SIM_REFRESH, response); mRil.mIccRefreshRegistrants.notifyRegistrants(new AsyncResult (null, response, null)); } @@ -517,7 +519,7 @@ public class RadioIndication extends IRadioIndication.Stub { mRil.writeMetricsCallRing(response); } - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CALL_RING, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_CALL_RING, response); if (mRil.mRingRegistrant != null) { mRil.mRingRegistrant.notifyRegistrant(new AsyncResult (null, response, null)); @@ -527,7 +529,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void simStatusChanged(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED); mRil.mIccStatusChangedRegistrants.notifyRegistrants(); } @@ -535,7 +537,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void cdmaNewSms(int indicationType, CdmaSmsMessage msg) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CDMA_NEW_SMS); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_CDMA_NEW_SMS); SmsMessage sms = new SmsMessage(RILUtils.convertHalCdmaSmsMessage(msg)); if (mRil.mCdmaSmsRegistrant != null) { @@ -547,9 +549,9 @@ public class RadioIndication extends IRadioIndication.Stub { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); byte[] response = RILUtils.arrayListToPrimitiveArray(data); - if (RIL.RILJ_LOGD) { - mRil.unsljLogvRet(RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, - IccUtils.bytesToHexString(response)); + if (mRil.isLogOrTrace()) { + mRil.unsljLogvRet( + RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS, IccUtils.bytesToHexString(response)); } if (mRil.mGsmBroadcastSmsRegistrant != null) { @@ -560,7 +562,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void cdmaRuimSmsStorageFull(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL); if (mRil.mIccSmsFullRegistrant != null) { mRil.mIccSmsFullRegistrant.notifyRegistrant(); @@ -570,7 +572,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void restrictedStateChanged(int indicationType, int state) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogvRet(RIL_UNSOL_RESTRICTED_STATE_CHANGED, state); + if (mRil.isLogOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_RESTRICTED_STATE_CHANGED, state); if (mRil.mRestrictedStateRegistrant != null) { mRil.mRestrictedStateRegistrant.notifyRegistrant(new AsyncResult (null, state, null)); @@ -580,7 +582,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void enterEmergencyCallbackMode(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE); if (mRil.mEmergencyCallbackModeRegistrant != null) { mRil.mEmergencyCallbackModeRegistrant.notifyRegistrant(); @@ -605,7 +607,7 @@ public class RadioIndication extends IRadioIndication.Stub { notification.numberType = callWaitingRecord.numberType; notification.numberPlan = callWaitingRecord.numberPlan; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_CALL_WAITING, notification); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_CDMA_CALL_WAITING, notification); mRil.mCallWaitingInfoRegistrants.notifyRegistrants( new AsyncResult (null, notification, null)); @@ -617,7 +619,9 @@ public class RadioIndication extends IRadioIndication.Stub { int response[] = new int[1]; response[0] = status; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, response); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, response); + } mRil.mOtaProvisionRegistrants.notifyRegistrants(new AsyncResult (null, response, null)); } @@ -712,7 +716,9 @@ public class RadioIndication extends IRadioIndication.Stub { + CdmaInformationRecords.idToString(id) + " "); } - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_INFO_REC, cdmaInformationRecords); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_CDMA_INFO_REC, cdmaInformationRecords); + } mRil.notifyRegistrantsCdmaInfoRec(cdmaInformationRecords); } } @@ -720,7 +726,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void indicateRingbackTone(int indicationType, boolean start) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogvRet(RIL_UNSOL_RINGBACK_TONE, start); + if (mRil.isLogOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_RINGBACK_TONE, start); mRil.mRingbackToneRegistrants.notifyRegistrants(new AsyncResult(null, start, null)); } @@ -728,7 +734,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void resendIncallMute(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESEND_INCALL_MUTE); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESEND_INCALL_MUTE); mRil.mResendIncallMuteRegistrants.notifyRegistrants(); } @@ -739,7 +745,9 @@ public class RadioIndication extends IRadioIndication.Stub { int response[] = new int[1]; response[0] = cdmaSource; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, response); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, response); + } mRil.mCdmaSubscriptionChangedRegistrants.notifyRegistrants( new AsyncResult (null, response, null)); @@ -751,7 +759,7 @@ public class RadioIndication extends IRadioIndication.Stub { int response[] = new int[1]; response[0] = version; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_PRL_CHANGED, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_CDMA_PRL_CHANGED, response); mRil.mCdmaPrlChangedRegistrants.notifyRegistrants( new AsyncResult (null, response, null)); @@ -760,7 +768,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void exitEmergencyCallbackMode(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE); mRil.mExitEmergencyCallbackModeRegistrants.notifyRegistrants(); } @@ -768,7 +776,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void rilConnected(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RIL_CONNECTED); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RIL_CONNECTED); // Initial conditions mRil.setRadioPower(false, null); @@ -784,7 +792,9 @@ public class RadioIndication extends IRadioIndication.Stub { int response[] = new int[1]; response[0] = rat; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, response); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_VOICE_RADIO_TECH_CHANGED, response); + } mRil.mVoiceRadioTechChangedRegistrants.notifyRegistrants( new AsyncResult (null, response, null)); @@ -827,7 +837,7 @@ public class RadioIndication extends IRadioIndication.Stub { private void responseCellInfoList(ArrayList records) { ArrayList response = RILUtils.convertHalCellInfoList((ArrayList) records); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CELL_INFO_LIST, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_CELL_INFO_LIST, response); mRil.mRilCellInfoListRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } @@ -835,7 +845,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void uiccApplicationsEnablementChanged(int indicationType, boolean enabled) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) { + if (mRil.isLogOrTrace()) { mRil.unsljLogRet(RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED, enabled); } @@ -875,7 +885,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void imsNetworkStateChanged(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED); mRil.mImsNetworkStateChangedRegistrants.notifyRegistrants(); } @@ -886,7 +896,9 @@ public class RadioIndication extends IRadioIndication.Stub { int response[] = new int[1]; response[0] = activate ? 1 : 0; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, response); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, response); + } mRil.mSubscriptionStatusRegistrants.notifyRegistrants( new AsyncResult (null, response, null)); @@ -898,7 +910,7 @@ public class RadioIndication extends IRadioIndication.Stub { int response[] = new int[1]; response[0] = state; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SRVCC_STATE_NOTIFY, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_SRVCC_STATE_NOTIFY, response); mRil.writeMetricsSrvcc(state); @@ -913,7 +925,7 @@ public class RadioIndication extends IRadioIndication.Stub { ArrayList response = RILUtils.convertHalHardwareConfigList(configs); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_HARDWARE_CONFIG_CHANGED, response); mRil.mHardwareConfigChangeRegistrants.notifyRegistrants( new AsyncResult (null, response, null)); @@ -925,7 +937,7 @@ public class RadioIndication extends IRadioIndication.Stub { RadioCapability response = RILUtils.convertHalRadioCapability(rc, mRil); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_RADIO_CAPABILITY, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_RADIO_CAPABILITY, response); mRil.mPhoneRadioCapabilityChangedRegistrants.notifyRegistrants( new AsyncResult (null, response, null)); @@ -972,7 +984,7 @@ public class RadioIndication extends IRadioIndication.Stub { } } - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_ON_SS, ssData); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_ON_SS, ssData); if (mRil.mSsRegistrant != null) { mRil.mSsRegistrant.notifyRegistrant(new AsyncResult(null, ssData, null)); @@ -982,7 +994,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void stkCallControlAlphaNotify(int indicationType, String alpha) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_STK_CC_ALPHA_NOTIFY, alpha); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_STK_CC_ALPHA_NOTIFY, alpha); if (mRil.mCatCcAlphaRegistrant != null) { mRil.mCatCcAlphaRegistrant.notifyRegistrant(new AsyncResult (null, alpha, null)); @@ -994,7 +1006,7 @@ public class RadioIndication extends IRadioIndication.Stub { List response = RILUtils.convertHalLceData(lce); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_LCEDATA_RECV, response); if (mRil.mLceInfoRegistrants != null) { mRil.mLceInfoRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); @@ -1007,7 +1019,7 @@ public class RadioIndication extends IRadioIndication.Stub { PcoData response = new PcoData(pco.cid, pco.bearerProto, pco.pcoId, RILUtils.arrayListToPrimitiveArray(pco.contents)); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_PCO_DATA, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_PCO_DATA, response); mRil.mPcoDataRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } @@ -1015,7 +1027,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void modemReset(int indicationType, String reason) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_MODEM_RESTART, reason); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_MODEM_RESTART, reason); mRil.writeMetricsModemRestartEvent(reason); mRil.mModemResetRegistrants.notifyRegistrants(new AsyncResult(null, reason, null)); @@ -1028,7 +1040,9 @@ public class RadioIndication extends IRadioIndication.Stub { public void carrierInfoForImsiEncryption(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION, null); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION, null); + } mRil.mCarrierInfoForImsiEncryptionRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); @@ -1043,9 +1057,10 @@ public class RadioIndication extends IRadioIndication.Stub { int indicationType, android.hardware.radio.V1_1.KeepaliveStatus halStatus) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) { - mRil.unsljLogRet(RIL_UNSOL_KEEPALIVE_STATUS, - "handle=" + halStatus.sessionHandle + " code=" + halStatus.code); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet( + RIL_UNSOL_KEEPALIVE_STATUS, + "handle=" + halStatus.sessionHandle + " code=" + halStatus.code); } KeepaliveStatus ks = new KeepaliveStatus( @@ -1061,7 +1076,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void simPhonebookChanged(int indicationType) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) { + if (mRil.isLogOrTrace()) { mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_CHANGED); } @@ -1084,8 +1099,9 @@ public class RadioIndication extends IRadioIndication.Stub { simPhonebookRecords.add(RILUtils.convertHalPhonebookRecordInfo(record)); } - if (RIL.RILJ_LOGD) { - mRil.unsljLogRet(RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED, + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet( + RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED, "status = " + status + " received " + records.size() + " records"); } @@ -1246,7 +1262,7 @@ public class RadioIndication extends IRadioIndication.Stub { return; } - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG, response); mRil.mPhysicalChannelConfigurationRegistrants.notifyRegistrants( new AsyncResult(null, response, null)); @@ -1259,7 +1275,7 @@ public class RadioIndication extends IRadioIndication.Stub { ArrayList cellInfos = RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null)); } @@ -1270,7 +1286,7 @@ public class RadioIndication extends IRadioIndication.Stub { ArrayList cellInfos = RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null)); } @@ -1281,7 +1297,7 @@ public class RadioIndication extends IRadioIndication.Stub { ArrayList cellInfos = RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null)); } @@ -1292,7 +1308,7 @@ public class RadioIndication extends IRadioIndication.Stub { ArrayList cellInfos = RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null)); } @@ -1303,14 +1319,14 @@ public class RadioIndication extends IRadioIndication.Stub { ArrayList cellInfos = RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr); mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null)); } private void responseDataCallListChanged(int indicationType, List dcList) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_DATA_CALL_LIST_CHANGED, dcList); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_DATA_CALL_LIST_CHANGED, dcList); ArrayList response = RILUtils.convertHalDataCallResultList(dcList); mRil.mDataCallListChangedRegistrants.notifyRegistrants( @@ -1320,7 +1336,7 @@ public class RadioIndication extends IRadioIndication.Stub { private void responseApnUnthrottled(int indicationType, String apn) { mRil.processIndication(RIL.RADIO_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_UNTHROTTLE_APN, apn); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_UNTHROTTLE_APN, apn); mRil.mApnUnthrottledRegistrants.notifyRegistrants( new AsyncResult(null, apn, null)); diff --git a/src/java/com/android/internal/telephony/SimIndication.java b/src/java/com/android/internal/telephony/SimIndication.java index f3ece16bca..20f89da73f 100644 --- a/src/java/com/android/internal/telephony/SimIndication.java +++ b/src/java/com/android/internal/telephony/SimIndication.java @@ -55,7 +55,9 @@ public class SimIndication extends IRadioSimIndication.Stub { public void carrierInfoForImsiEncryption(int indicationType) { mRil.processIndication(RIL.SIM_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION, null); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION, null); + } mRil.mCarrierInfoForImsiEncryptionRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); @@ -70,7 +72,9 @@ public class SimIndication extends IRadioSimIndication.Stub { mRil.processIndication(RIL.SIM_SERVICE, indicationType); int[] response = new int[]{cdmaSource}; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, response); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, response); + } mRil.mCdmaSubscriptionChangedRegistrants.notifyRegistrants( new AsyncResult(null, response, null)); @@ -83,7 +87,7 @@ public class SimIndication extends IRadioSimIndication.Stub { public void simPhonebookChanged(int indicationType) { mRil.processIndication(RIL.SIM_SERVICE, indicationType); - if (RIL.RILJ_LOGD) { + if (mRil.isLogOrTrace()) { mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_CHANGED); } @@ -106,8 +110,9 @@ public class SimIndication extends IRadioSimIndication.Stub { simPhonebookRecords.add(RILUtils.convertHalPhonebookRecordInfo(record)); } - if (RIL.RILJ_LOGD) { - mRil.unsljLogRet(RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED, + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet( + RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED, "status = " + status + " received " + records.length + " records"); } @@ -129,7 +134,7 @@ public class SimIndication extends IRadioSimIndication.Stub { response.efId = refreshResult.efId; response.aid = refreshResult.aid; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SIM_REFRESH, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_SIM_REFRESH, response); mRil.mIccRefreshRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } @@ -141,7 +146,7 @@ public class SimIndication extends IRadioSimIndication.Stub { public void simStatusChanged(int indicationType) { mRil.processIndication(RIL.SIM_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED); mRil.mIccStatusChangedRegistrants.notifyRegistrants(); } @@ -156,7 +161,7 @@ public class SimIndication extends IRadioSimIndication.Stub { public void stkEventNotify(int indicationType, String cmd) { mRil.processIndication(RIL.SIM_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_STK_EVENT_NOTIFY); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_EVENT_NOTIFY); if (mRil.mCatEventRegistrant != null) { mRil.mCatEventRegistrant.notifyRegistrant(new AsyncResult(null, cmd, null)); @@ -172,7 +177,7 @@ public class SimIndication extends IRadioSimIndication.Stub { public void stkProactiveCommand(int indicationType, String cmd) { mRil.processIndication(RIL.SIM_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_STK_PROACTIVE_COMMAND); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_PROACTIVE_COMMAND); if (mRil.mCatProCmdRegistrant != null) { mRil.mCatProCmdRegistrant.notifyRegistrant(new AsyncResult(null, cmd, null)); @@ -186,7 +191,7 @@ public class SimIndication extends IRadioSimIndication.Stub { public void stkSessionEnd(int indicationType) { mRil.processIndication(RIL.SIM_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_STK_SESSION_END); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_SESSION_END); if (mRil.mCatSessionEndRegistrant != null) { mRil.mCatSessionEndRegistrant.notifyRegistrant(new AsyncResult(null, null, null)); @@ -203,7 +208,9 @@ public class SimIndication extends IRadioSimIndication.Stub { int[] response = new int[]{activate ? 1 : 0}; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, response); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED, response); + } mRil.mSubscriptionStatusRegistrants.notifyRegistrants( new AsyncResult(null, response, null)); @@ -217,7 +224,7 @@ public class SimIndication extends IRadioSimIndication.Stub { public void uiccApplicationsEnablementChanged(int indicationType, boolean enabled) { mRil.processIndication(RIL.SIM_SERVICE, indicationType); - if (RIL.RILJ_LOGD) { + if (mRil.isLogOrTrace()) { mRil.unsljLogRet(RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED, enabled); } diff --git a/src/java/com/android/internal/telephony/VoiceIndication.java b/src/java/com/android/internal/telephony/VoiceIndication.java index 4ed82a60ef..984d2a0aff 100644 --- a/src/java/com/android/internal/telephony/VoiceIndication.java +++ b/src/java/com/android/internal/telephony/VoiceIndication.java @@ -78,7 +78,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { mRil.writeMetricsCallRing(response); } - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CALL_RING, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_CALL_RING, response); if (mRil.mRingRegistrant != null) { mRil.mRingRegistrant.notifyRegistrant(new AsyncResult(null, response, null)); @@ -92,7 +92,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { public void callStateChanged(int indicationType) { mRil.processIndication(RIL.VOICE_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED); mRil.mCallStateRegistrants.notifyRegistrants(); } @@ -121,7 +121,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { notification.numberType = callWaitingRecord.numberType; notification.numberPlan = callWaitingRecord.numberPlan; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_CALL_WAITING, notification); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_CDMA_CALL_WAITING, notification); mRil.mCallWaitingInfoRegistrants.notifyRegistrants( new AsyncResult(null, notification, null)); @@ -220,7 +220,9 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { + CdmaInformationRecords.idToString(id) + " "); } - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_INFO_REC, cdmaInformationRecords); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_CDMA_INFO_REC, cdmaInformationRecords); + } mRil.notifyRegistrantsCdmaInfoRec(cdmaInformationRecords); } } @@ -235,7 +237,9 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { int[] response = new int[] {status}; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, response); + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_CDMA_OTA_PROVISION_STATUS, response); + } mRil.mOtaProvisionRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } @@ -259,7 +263,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { response.add(emergencyNumber); } - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_EMERGENCY_NUMBER_LIST, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_EMERGENCY_NUMBER_LIST, response); // Cache emergency number list from last indication. mRil.cacheEmergencyNumberListIndication(response); @@ -277,7 +281,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { public void enterEmergencyCallbackMode(int indicationType) { mRil.processIndication(RIL.VOICE_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE); if (mRil.mEmergencyCallbackModeRegistrant != null) { mRil.mEmergencyCallbackModeRegistrant.notifyRegistrant(); @@ -292,7 +296,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { public void exitEmergencyCallbackMode(int indicationType) { mRil.processIndication(RIL.VOICE_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE); mRil.mExitEmergencyCallbackModeRegistrants.notifyRegistrants(); } @@ -305,7 +309,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { public void indicateRingbackTone(int indicationType, boolean start) { mRil.processIndication(RIL.VOICE_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogvRet(RIL_UNSOL_RINGBACK_TONE, start); + if (mRil.isLogOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_RINGBACK_TONE, start); mRil.mRingbackToneRegistrants.notifyRegistrants(new AsyncResult(null, start, null)); } @@ -355,7 +359,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { } } - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_ON_SS, ssData); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_ON_SS, ssData); if (mRil.mSsRegistrant != null) { mRil.mSsRegistrant.notifyRegistrant(new AsyncResult(null, ssData, null)); @@ -372,7 +376,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { public void onUssd(int indicationType, int ussdModeType, String msg) { mRil.processIndication(RIL.VOICE_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogMore(RIL_UNSOL_ON_USSD, "" + ussdModeType); + if (mRil.isLogOrTrace()) mRil.unsljLogMore(RIL_UNSOL_ON_USSD, "" + ussdModeType); // TODO: Clean this up with a parcelable class for better self-documentation String[] resp = new String[]{"" + ussdModeType, msg}; @@ -388,7 +392,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { public void resendIncallMute(int indicationType) { mRil.processIndication(RIL.VOICE_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESEND_INCALL_MUTE); + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESEND_INCALL_MUTE); mRil.mResendIncallMuteRegistrants.notifyRegistrants(); } @@ -403,7 +407,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { int[] response = new int[] {state}; - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_SRVCC_STATE_NOTIFY, response); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_SRVCC_STATE_NOTIFY, response); mRil.writeMetricsSrvcc(state); mRil.mSrvccStateRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); @@ -417,7 +421,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { public void stkCallControlAlphaNotify(int indicationType, String alpha) { mRil.processIndication(RIL.VOICE_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_STK_CC_ALPHA_NOTIFY, alpha); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_STK_CC_ALPHA_NOTIFY, alpha); if (mRil.mCatCcAlphaRegistrant != null) { mRil.mCatCcAlphaRegistrant.notifyRegistrant(new AsyncResult(null, alpha, null)); @@ -432,7 +436,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { public void stkCallSetup(int indicationType, long timeout) { mRil.processIndication(RIL.VOICE_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_STK_CALL_SETUP, timeout); + if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_STK_CALL_SETUP, timeout); if (mRil.mCatCallSetUpRegistrant != null) { mRil.mCatCallSetUpRegistrant.notifyRegistrant(new AsyncResult(null, timeout, null)); -- GitLab From c4bf83fe9f83175c0d3f0d9a4ed5087d7a6fe664 Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Tue, 16 Aug 2022 15:47:39 -0700 Subject: [PATCH 073/656] remove in-exact matching for emergency numbers -remove in-exact matching related code from emergencynumtracker -remove api exposed by emergency num tracker -update tests Bug: 238360124 Test: unit tests Change-Id: Ie8c3e7f674c8d430a2afb7024a8d18386fb68717 --- .../internal/telephony/GsmCdmaPhone.java | 3 +- .../emergency/EmergencyNumberTracker.java | 108 ++++-------------- .../internal/telephony/GsmCdmaPhoneTest.java | 2 +- .../telephony/PhoneNumberUtilsTest.java | 44 ++----- .../emergency/EmergencyNumberTrackerTest.java | 4 +- 5 files changed, 37 insertions(+), 124 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index ff8412f1a5..20e8478e11 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -1434,8 +1434,7 @@ public class GsmCdmaPhone extends Phone { // emergency number list on another SIM, but is not on theirs. In this case we will use the // emergency number list for this carrier's SIM only. if (useOnlyDialedSimEccList) { - isEmergency = getEmergencyNumberTracker().isEmergencyNumber(dialString, - true /* exactMatch */); + isEmergency = getEmergencyNumberTracker().isEmergencyNumber(dialString); logi("dial; isEmergency=" + isEmergency + " (based on this phone only); globalIsEmergency=" + tm.isEmergencyNumber(dialString)); diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 276d82a527..2496ca806d 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -710,7 +710,7 @@ public class EmergencyNumberTracker extends Handler { * * @return {@code true} if it is; {@code false} otherwise. */ - public boolean isEmergencyNumber(String number, boolean exactMatch) { + public boolean isEmergencyNumber(String number) { if (number == null) { return false; } @@ -726,31 +726,14 @@ public class EmergencyNumberTracker extends Handler { if (!mEmergencyNumberListFromRadio.isEmpty()) { for (EmergencyNumber num : mEmergencyNumberList) { - // According to com.android.i18n.phonenumbers.ShortNumberInfo, in - // these countries, if extra digits are added to an emergency number, - // it no longer connects to the emergency service. - String countryIso = getLastKnownEmergencyCountryIso(); - if (countryIso.equals("br") || countryIso.equals("cl") - || countryIso.equals("ni")) { - exactMatch = true; - } else { - exactMatch = false || exactMatch; - } - if (exactMatch) { - if (num.getNumber().equals(number)) { - logd("Found in mEmergencyNumberList [exact match] "); - return true; - } - } else { - if (number.startsWith(num.getNumber())) { - logd("Found in mEmergencyNumberList [not exact match] "); - return true; - } + if (num.getNumber().equals(number)) { + logd("Found in mEmergencyNumberList"); + return true; } } return false; } else { - boolean inEccList = isEmergencyNumberFromEccList(number, exactMatch); + boolean inEccList = isEmergencyNumberFromEccList(number); boolean inEmergencyNumberDb = isEmergencyNumberFromDatabase(number); boolean inEmergencyNumberTestList = isEmergencyNumberForTest(number); logd("Search results - inRilEccList:" + inEccList @@ -952,7 +935,7 @@ public class EmergencyNumberTracker extends Handler { * Back-up old logics for {@link PhoneNumberUtils#isEmergencyNumberInternal} for legacy * and deprecate purpose. */ - private boolean isEmergencyNumberFromEccList(String number, boolean useExactMatch) { + private boolean isEmergencyNumberFromEccList(String number) { // If the number passed in is null, just return false: if (number == null) return false; @@ -999,31 +982,16 @@ public class EmergencyNumberTracker extends Handler { // searches through the comma-separated list for a match, // return true if one is found. for (String emergencyNum : emergencyNumbers.split(",")) { - // According to com.android.i18n.phonenumbers.ShortNumberInfo, in - // these countries, if extra digits are added to an emergency number, - // it no longer connects to the emergency service. - if (useExactMatch || countryIso.equals("br") || countryIso.equals("cl") - || countryIso.equals("ni")) { - if (number.equals(emergencyNum)) { - return true; - } else { - for (String prefix : mEmergencyNumberPrefix) { - if (number.equals(prefix + emergencyNum)) { - return true; - } - } - } + if (number.equals(emergencyNum)) { + return true; } else { - if (number.startsWith(emergencyNum)) { - return true; - } else { - for (String prefix : mEmergencyNumberPrefix) { - if (number.startsWith(prefix + emergencyNum)) { - return true; - } + for (String prefix : mEmergencyNumberPrefix) { + if (number.equals(prefix + emergencyNum)) { + return true; } } } + } // no matches found against the list! return false; @@ -1038,57 +1006,31 @@ public class EmergencyNumberTracker extends Handler { emergencyNumbers = ((isSimAbsent()) ? "112,911,000,08,110,118,119,999" : "112,911"); for (String emergencyNum : emergencyNumbers.split(",")) { - if (useExactMatch) { - if (number.equals(emergencyNum)) { - return true; - } else { - for (String prefix : mEmergencyNumberPrefix) { - if (number.equals(prefix + emergencyNum)) { - return true; - } - } - } + if (number.equals(emergencyNum)) { + return true; } else { - if (number.startsWith(emergencyNum)) { - return true; - } else { - for (String prefix : mEmergencyNumberPrefix) { - if (number.equals(prefix + emergencyNum)) { - return true; - } + for (String prefix : mEmergencyNumberPrefix) { + if (number.equals(prefix + emergencyNum)) { + return true; } } } } - if(isSimAbsent()) { + if (isSimAbsent()) { // No ecclist system property, so use our own list. if (countryIso != null) { ShortNumberInfo info = ShortNumberInfo.getInstance(); - if (useExactMatch) { - if (info.isEmergencyNumber(number, countryIso.toUpperCase())) { - return true; - } else { - for (String prefix : mEmergencyNumberPrefix) { - if (info.isEmergencyNumber(prefix + number, countryIso.toUpperCase())) { - return true; - } - } - } - return false; + if (info.isEmergencyNumber(number, countryIso.toUpperCase())) { + return true; } else { - if (info.connectsToEmergencyNumber(number, countryIso.toUpperCase())) { - return true; - } else { - for (String prefix : mEmergencyNumberPrefix) { - if (info.connectsToEmergencyNumber(prefix + number, - countryIso.toUpperCase())) { - return true; - } + for (String prefix : mEmergencyNumberPrefix) { + if (info.isEmergencyNumber(prefix + number, countryIso.toUpperCase())) { + return true; } } - return false; } + return false; } } @@ -1107,7 +1049,7 @@ public class EmergencyNumberTracker extends Handler { */ private void updateEmergencyNumberListTestModeAndNotify(int action, EmergencyNumber num) { if (action == ADD_EMERGENCY_NUMBER_TEST_MODE) { - if (!isEmergencyNumber(num.getNumber(), true)) { + if (!isEmergencyNumber(num.getNumber())) { mEmergencyNumberListFromTestMode.add(num); } } else if (action == RESET_EMERGENCY_NUMBER_TEST_MODE) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 9e45cc3c62..626242508f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -1599,7 +1599,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { doReturn(true).when(mTelephonyManager).isEmergencyNumber(anyString()); doReturn(isEmergencyPerDialedSim).when(mEmergencyNumberTracker).isEmergencyNumber( - anyString(), anyBoolean()); + anyString()); mPhoneUT.setImsPhone(mImsPhone); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java index b7d2913ec5..dd59e28f3e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java @@ -645,55 +645,27 @@ public class PhoneNumberUtilsTest { @Test @Ignore public void testIsEmergencyNumber() { - // There are two parallel sets of tests here: one for the - // regular isEmergencyNumber() method, and the other for - // isPotentialEmergencyNumber(). - // // (The difference is that isEmergencyNumber() will return true // only if the specified number exactly matches an actual - // emergency number, but isPotentialEmergencyNumber() will - // return true if the specified number simply starts with the - // same digits as any actual emergency number.) + // emergency number // Tests for isEmergencyNumber(): - assertTrue(PhoneNumberUtils.isEmergencyNumber("911", "US")); - assertTrue(PhoneNumberUtils.isEmergencyNumber("112", "US")); + assertTrue(PhoneNumberUtils.isEmergencyNumber("911")); + assertTrue(PhoneNumberUtils.isEmergencyNumber("112")); // The next two numbers are not valid phone numbers in the US, // so do not count as emergency numbers (but they *are* "potential" // emergency numbers; see below.) - assertFalse(PhoneNumberUtils.isEmergencyNumber("91112345", "US")); - assertFalse(PhoneNumberUtils.isEmergencyNumber("11212345", "US")); + assertFalse(PhoneNumberUtils.isEmergencyNumber("91112345")); + assertFalse(PhoneNumberUtils.isEmergencyNumber("11212345")); // A valid mobile phone number from Singapore shouldn't be classified as an emergency number // in Singapore, as 911 is not an emergency number there. - assertFalse(PhoneNumberUtils.isEmergencyNumber("91121234", "SG")); - // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number - // in Brazil, as 112 is not an emergency number there. - assertFalse(PhoneNumberUtils.isEmergencyNumber("1121234567", "BR")); - // A valid local phone number from Brazil shouldn't be classified as an emergency number in - // Brazil. - assertFalse(PhoneNumberUtils.isEmergencyNumber("91112345", "BR")); - - // Tests for isPotentialEmergencyNumber(): - // These first two are obviously emergency numbers: - assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("911", "US")); - assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("112", "US")); - // The next two numbers are not valid phone numbers in the US, but can be used to trick the - // system to dial 911 and 112, which are emergency numbers in the US. For the purpose of - // addressing that, they are also classified as "potential" emergency numbers in the US. - assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "US")); - assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("11212345", "US")); - - // A valid mobile phone number from Singapore shouldn't be classified as an emergency number - // in Singapore, as 911 is not an emergency number there. - // This test fails on devices that have ecclist property preloaded with 911. - // assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91121234", "SG")); - + assertFalse(PhoneNumberUtils.isEmergencyNumber("91121234")); // A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number // in Brazil, as 112 is not an emergency number there. - assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("1121234567", "BR")); + assertFalse(PhoneNumberUtils.isEmergencyNumber("1121234567")); // A valid local phone number from Brazil shouldn't be classified as an emergency number in // Brazil. - assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "BR")); + assertFalse(PhoneNumberUtils.isEmergencyNumber("91112345")); } @SmallTest diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index 39ff133320..c97b6e2fcd 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -388,7 +388,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { processAllMessages(); replaceInstance(ShortNumberInfo.class, "INSTANCE", null, mShortNumberInfo); - mEmergencyNumberTrackerMock.isEmergencyNumber(NON_3GPP_EMERGENCY_TEST_NUMBER, true); + mEmergencyNumberTrackerMock.isEmergencyNumber(NON_3GPP_EMERGENCY_TEST_NUMBER); //verify that we fall back to shortnumber xml when there are no SIMs verify(mShortNumberInfo).isEmergencyNumber(NON_3GPP_EMERGENCY_TEST_NUMBER, "JP"); @@ -436,7 +436,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { processAllMessages(); replaceInstance(ShortNumberInfo.class, "INSTANCE", null, mShortNumberInfo); - mEmergencyNumberTrackerMock.isEmergencyNumber(NON_3GPP_EMERGENCY_TEST_NUMBER, true); + mEmergencyNumberTrackerMock.isEmergencyNumber(NON_3GPP_EMERGENCY_TEST_NUMBER); //verify we do not use ShortNumber xml verify(mShortNumberInfo, never()).isEmergencyNumber(anyString(), anyString()); -- GitLab From 559e5b704d9d5a37862d5a612b72f9dbf79765d6 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Thu, 10 Mar 2022 04:59:49 +0000 Subject: [PATCH 074/656] saving null alphaTag if exceeds the uicc allowed limit in voicemailAlphatag case Bug: 143508861 Test: aTest verification passed,Manually verified with testapp Change-Id: Ia28e65337dc341d177996a2f5123f5571979212b --- .../telephony/uicc/AdnRecordLoader.java | 40 +++- .../internal/telephony/uicc/SIMRecords.java | 35 ++- .../telephony/uicc/SIMRecordsTest.java | 220 ++++++++++++++++++ 3 files changed, 283 insertions(+), 12 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/AdnRecordLoader.java b/src/java/com/android/internal/telephony/uicc/AdnRecordLoader.java index a688c6e5d7..5b0a6a3612 100644 --- a/src/java/com/android/internal/telephony/uicc/AdnRecordLoader.java +++ b/src/java/com/android/internal/telephony/uicc/AdnRecordLoader.java @@ -59,6 +59,7 @@ public class AdnRecordLoader extends Handler { static final int EVENT_EF_LINEAR_RECORD_SIZE_DONE = 4; static final int EVENT_UPDATE_RECORD_DONE = 5; + static final int VOICEMAIL_ALPHATAG_ARG = 1; //***** Constructor @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -177,14 +178,34 @@ public class AdnRecordLoader extends Handler { data = adn.buildAdnString(recordSize[0]); if(data == null) { - throw new RuntimeException("wrong ADN format", - ar.exception); + /** + * The voicemail number saving to the SIM is in name(alphaTag) and number + * format. {@link recordSize[0]} indicates the SIM EF memory size that the + * sim can have to save both voicemail name and number. 14 byte of memory + * is reserved to save the voicemail number and remaining memory is reserved + * for the alphaTag. In case if we receive the alphaTag which is more than + * the reserved memory size then SIM will throw the exception and it don't + * save both the voicemail number and alphaTag. To avoid this problem, in + * case alphaTag length is more we nullify the alphaTag and save the same. + */ + if (mUserResponse.arg1 == VOICEMAIL_ALPHATAG_ARG) { + adn.mAlphaTag = null; + data = adn.buildAdnString(recordSize[0]); + } + if (data == null) { + throw new RuntimeException("wrong ADN format", + ar.exception); + } } - - mFh.updateEFLinearFixed(mEf, getEFPath(mEf), mRecordNumber, - data, mPin2, obtainMessage(EVENT_UPDATE_RECORD_DONE)); - + // Send adn record to caller to track the changes made to alphaTag + if (mUserResponse.arg1 == VOICEMAIL_ALPHATAG_ARG) { + mFh.updateEFLinearFixed(mEf, getEFPath(mEf), mRecordNumber, + data, mPin2, obtainMessage(EVENT_UPDATE_RECORD_DONE, adn)); + } else { + mFh.updateEFLinearFixed(mEf, getEFPath(mEf), mRecordNumber, + data, mPin2, obtainMessage(EVENT_UPDATE_RECORD_DONE)); + } mPendingExtLoads = 1; break; @@ -195,7 +216,12 @@ public class AdnRecordLoader extends Handler { ar.exception); } mPendingExtLoads = 0; - mResult = null; + // send the adn record back to caller through the result of AsyncResult + if (mUserResponse.arg1 == VOICEMAIL_ALPHATAG_ARG) { + mResult = ar.userObj; + } else { + mResult = null; + } break; case EVENT_ADN_LOAD_DONE: ar = (AsyncResult)(msg.obj); diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index 39336c6c0c..77b83ccf48 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -34,6 +34,7 @@ import android.text.TextUtils; import android.util.Log; import android.util.Pair; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.MccTable; import com.android.internal.telephony.SmsConstants; @@ -397,18 +398,20 @@ public class SIMRecords extends IccRecords { mNewVoiceMailTag = alphaTag; AdnRecord adn = new AdnRecord(mNewVoiceMailTag, mNewVoiceMailNum); - if (mMailboxIndex != 0 && mMailboxIndex != 0xff) { new AdnRecordLoader(mFh).updateEF(adn, EF_MBDN, EF_EXT6, mMailboxIndex, null, - obtainMessage(EVENT_SET_MBDN_DONE, onComplete)); + obtainMessage(EVENT_SET_MBDN_DONE, AdnRecordLoader.VOICEMAIL_ALPHATAG_ARG, + 0 /* ignored arg2 */, onComplete)); } else if (isCphsMailboxEnabled()) { new AdnRecordLoader(mFh).updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null, - obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onComplete)); + obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, + AdnRecordLoader.VOICEMAIL_ALPHATAG_ARG, + 0 /* ignored arg2 */, onComplete)); } else { AsyncResult.forMessage((onComplete)).exception = @@ -1031,10 +1034,20 @@ public class SIMRecords extends IccRecords { if (DBG) log("EVENT_SET_MBDN_DONE ex:" + ar.exception); if (ar.exception == null) { + /** + * Check for any changes made to voicemail alphaTag while saving to SIM. + * if voicemail alphaTag length is more than allowed limit of SIM EF then + * null alphaTag will be saved to SIM {@code AdnRecordLoader}. + */ + if (ar.result != null) { + AdnRecord adnRecord = (AdnRecord) (ar.result); + if (adnRecord != null) { + mNewVoiceMailTag = adnRecord.mAlphaTag; + } + } mVoiceMailNum = mNewVoiceMailNum; mVoiceMailTag = mNewVoiceMailTag; } - if (isCphsMailboxEnabled()) { adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum); Message onCphsCompleted = (Message) ar.userObj; @@ -1058,7 +1071,8 @@ public class SIMRecords extends IccRecords { new AdnRecordLoader(mFh) .updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null, obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, - onCphsCompleted)); + AdnRecordLoader.VOICEMAIL_ALPHATAG_ARG, + 0 /* ignored arg2 */, onCphsCompleted)); } else { if (ar.userObj != null) { CarrierConfigManager configManager = (CarrierConfigManager) @@ -1090,6 +1104,12 @@ public class SIMRecords extends IccRecords { isRecordLoadResponse = false; ar = (AsyncResult) msg.obj; if (ar.exception == null) { + if (ar.result != null) { + AdnRecord adnRecord = (AdnRecord) (ar.result); + if (adnRecord != null) { + mNewVoiceMailTag = adnRecord.mAlphaTag; + } + } mVoiceMailNum = mNewVoiceMailNum; mVoiceMailTag = mNewVoiceMailTag; } else { @@ -2163,6 +2183,11 @@ public class SIMRecords extends IccRecords { log("[CSP] Value Added Service Group (0xC0), not found!"); } + @VisibleForTesting + public void setMailboxIndex(int mailboxIndex) { + mMailboxIndex = mailboxIndex; + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("SIMRecords: " + this); diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java index 90349dad05..125fb6a150 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java @@ -22,9 +22,11 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; @@ -41,6 +43,7 @@ import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.uicc.IccRecords.OperatorPlmnInfo; import com.android.internal.telephony.uicc.IccRecords.PlmnNetworkName; +import com.android.telephony.Rlog; import org.junit.After; import org.junit.Before; @@ -50,6 +53,8 @@ import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public class SIMRecordsTest extends TelephonyTest { @@ -716,4 +721,219 @@ public class SIMRecordsTest extends TelephonyTest { String resultSst = mSIMRecordsUT.getSimServiceTable(); assertEquals(mockSst, resultSst); } + + @Test + public void testSetVoiceMailNumber() throws InterruptedException { + + String voiceMailNumber = "1234567890"; + String alphaTag = "Voicemail"; + final CountDownLatch latch = new CountDownLatch(2); + doAnswer( + invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the test invocation1"); + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }) + .when(mFhMock) + .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + doAnswer( + invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the test invocation2"); + Message response = invocation.getArgument(5); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }) + .when(mFhMock) + .updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), + eq(null), any(Message.class)); + + + mSIMRecordsUT.setMailboxIndex(1); + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setVoiceMailNumber(alphaTag, voiceMailNumber, message); + latch.await(5, TimeUnit.SECONDS); + mTestLooper.startAutoDispatch(); + verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), + anyInt(), any(byte[].class), eq(null), any(Message.class)); + + assertEquals(voiceMailNumber, mSIMRecordsUT.getVoiceMailNumber()); + assertEquals(alphaTag, mSIMRecordsUT.getVoiceMailAlphaTag()); + } + + @Test + public void testSetVoiceMailNumberBigAlphatag() throws InterruptedException { + + String voiceMailNumber = "1234567890"; + String alphaTag = "VoicemailAlphaTag-VoicemailAlphaTag"; + final CountDownLatch latch = new CountDownLatch(2); + doAnswer( + invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the test invocation1"); + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }) + .when(mFhMock) + .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + doAnswer( + invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the test invocation2"); + Message response = invocation.getArgument(5); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }) + .when(mFhMock) + .updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), + eq(null), any(Message.class)); + + + mSIMRecordsUT.setMailboxIndex(1); + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setVoiceMailNumber(alphaTag, voiceMailNumber, message); + latch.await(8, TimeUnit.SECONDS); + mTestLooper.startAutoDispatch(); + verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), + anyInt(), any(byte[].class), eq(null), any(Message.class)); + + //if attempt to save bugAlphatag which sim don't support so we will make it null + assertEquals(null, mSIMRecordsUT.getVoiceMailAlphaTag()); + assertEquals(voiceMailNumber, mSIMRecordsUT.getVoiceMailNumber()); + } + + @Test + public void testSetVoiceMailNumberUtf16Alphatag() throws InterruptedException { + + String voiceMailNumber = "1234567890"; + String alphaTag = "หมายเลขข้อความเสียง"; // Messagerie vocale + final CountDownLatch latch = new CountDownLatch(2); + doAnswer( + invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the test invocation1"); + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }) + .when(mFhMock) + .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + doAnswer( + invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the test invocation2"); + Message response = invocation.getArgument(5); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }) + .when(mFhMock) + .updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), + eq(null), any(Message.class)); + + + mSIMRecordsUT.setMailboxIndex(1); + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setVoiceMailNumber(alphaTag, voiceMailNumber, message); + latch.await(5, TimeUnit.SECONDS); + mTestLooper.startAutoDispatch(); + verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), + anyInt(), any(byte[].class), eq(null), any(Message.class)); + + assertEquals(voiceMailNumber, mSIMRecordsUT.getVoiceMailNumber()); + //if attempt to save bugAlphatag which sim don't support so we will make it null + assertEquals(null, mSIMRecordsUT.getVoiceMailAlphaTag()); + } + + + @Test + public void testSetVoiceMailNullNumber() throws InterruptedException { + + String voiceMailNumber = null; + String alphaTag = "VoicemailAlphaTag"; // Messagerie vocale + final CountDownLatch latch = new CountDownLatch(2); + doAnswer( + invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the test invocation1"); + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }) + .when(mFhMock) + .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + doAnswer( + invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the test invocation2"); + Message response = invocation.getArgument(5); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }) + .when(mFhMock) + .updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), + eq(null), any(Message.class)); + + + mSIMRecordsUT.setMailboxIndex(1); + Message message = Message.obtain(mTestHandler); + mSIMRecordsUT.setVoiceMailNumber(alphaTag, voiceMailNumber, message); + latch.await(5, TimeUnit.SECONDS); + mTestLooper.startAutoDispatch(); + verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), + anyInt(), any(byte[].class), eq(null), any(Message.class)); + + assertEquals(null, mSIMRecordsUT.getVoiceMailNumber()); + assertEquals(alphaTag, mSIMRecordsUT.getVoiceMailAlphaTag()); + } } -- GitLab From 956b8afb16969a3a69820475ab398a9d7cddabf3 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 25 Aug 2022 16:49:05 -0700 Subject: [PATCH 075/656] Add optional phoneId for SST TelephonyTester override optionally specify phoneId for a SST override. If not specified, the override applies to all phones. Bug: 244064524 Test: adb shell am broadcast -a com.android.internal.telephony.TestServiceState --ei data_reg_state 1 --ei phone_id 1 Change-Id: I0a1ecfce2922d56a2480aba94cf3bc8c606f83c5 --- .../com/android/internal/telephony/Phone.java | 8 ++++---- .../internal/telephony/TelephonyTester.java | 15 +++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 4b0eaec75a..536a365ccc 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -580,10 +580,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { .makeAppSmsManager(context); mLocalLog = new LocalLog(64); - if (TelephonyUtils.IS_DEBUGGABLE) { - mTelephonyTester = new TelephonyTester(this); - } - setUnitTestMode(unitTestMode); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); @@ -626,6 +622,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return; } + if (TelephonyUtils.IS_DEBUGGABLE) { + mTelephonyTester = new TelephonyTester(this); + } + // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers. mTelephonyComponentFactory = telephonyComponentFactory; mSmsStorageMonitor = mTelephonyComponentFactory.inject(SmsStorageMonitor.class.getName()) diff --git a/src/java/com/android/internal/telephony/TelephonyTester.java b/src/java/com/android/internal/telephony/TelephonyTester.java index 40bb212954..c81a4c3ce5 100644 --- a/src/java/com/android/internal/telephony/TelephonyTester.java +++ b/src/java/com/android/internal/telephony/TelephonyTester.java @@ -62,7 +62,6 @@ import java.util.List; * */ public class TelephonyTester { - private static final String LOG_TAG = "TelephonyTester"; private static final boolean DBG = true; /** @@ -144,6 +143,7 @@ public class TelephonyTester { "com.android.internal.telephony.TestServiceState"; private static final String EXTRA_ACTION = "action"; + private static final String EXTRA_PHONE_ID = "phone_id"; private static final String EXTRA_VOICE_RAT = "voice_rat"; private static final String EXTRA_DATA_RAT = "data_rat"; private static final String EXTRA_VOICE_REG_STATE = "voice_reg_state"; @@ -157,6 +157,8 @@ public class TelephonyTester { private static final String ACTION_RESET = "reset"; + private String mLogTag; + private static List mImsExternalCallStates = null; private Intent mServiceStateTestIntent; @@ -216,7 +218,7 @@ public class TelephonyTester { if (DBG) log("onReceive: unknown action=" + action); } } catch (BadParcelableException e) { - Rlog.w(LOG_TAG, e); + Rlog.w(mLogTag, e); } } }; @@ -225,6 +227,7 @@ public class TelephonyTester { mPhone = phone; if (TelephonyUtils.IS_DEBUGGABLE) { + mLogTag = "TelephonyTester-" + mPhone.getPhoneId(); IntentFilter filter = new IntentFilter(); filter.addAction(mPhone.getActionDetached()); @@ -261,8 +264,8 @@ public class TelephonyTester { } } - private static void log(String s) { - Rlog.d(LOG_TAG, s); + private void log(String s) { + Rlog.d(mLogTag, s); } private void handleSuppServiceFailedIntent(Intent intent) { @@ -387,6 +390,10 @@ public class TelephonyTester { 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"); -- GitLab From ab75195b0bc4b08b53164d66613a258d25d993ba Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Mon, 29 Aug 2022 18:49:35 +0000 Subject: [PATCH 076/656] Log last N SMS outgoing error codes Bug: 244196066 Test: run the following tests - atest com.android.internal.telephony.gsm.GsmSmsDispatcherTest - atest com.android.internal.telephony.SmsDispatchersControllerTest Change-Id: I43c928b6fceab49a46a7bb3f6c23c43e8b89171a --- .../android/internal/telephony/SMSDispatcher.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 885925a194..ba5176acc1 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -164,6 +164,7 @@ public abstract class SMSDispatcher extends Handler { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected final TelephonyManager mTelephonyManager; protected final LocalLog mLocalLog = new LocalLog(16); + protected final LocalLog mSmsOutgoingErrorCodes = new LocalLog(10); /** Maximum number of times to retry sending a failed SMS. */ protected static final int MAX_SEND_RETRIES = 3; @@ -1084,8 +1085,10 @@ public abstract class SMSDispatcher extends Handler { } @SmsManager.Result - private static int rilErrorToSmsManagerResult(CommandException.Error rilError, + private int rilErrorToSmsManagerResult(CommandException.Error rilError, SmsTracker tracker) { + mSmsOutgoingErrorCodes.log("rilError: " + rilError + + ", MessageId: " + SmsController.formatCrossStackMessageId(tracker.mMessageId)); switch (rilError) { case RADIO_NOT_AVAILABLE: return SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE; @@ -2757,10 +2760,17 @@ public abstract class SMSDispatcher extends Handler { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println(TAG); pw.increaseIndent(); + pw.println("mLocalLog:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); pw.decreaseIndent(); + + pw.println("mSmsOutgoingErrorCodes:"); + pw.increaseIndent(); + mSmsOutgoingErrorCodes.dump(fd, pw, args); + pw.decreaseIndent(); + pw.decreaseIndent(); } } -- GitLab From b16e6d724d1a74363d901746e539bf008e6b5835 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Wed, 24 Aug 2022 14:08:38 -0700 Subject: [PATCH 077/656] Handle source PDN lost during HO when source PDN is reported lost duing HO, source transport thinks the old interfaceName can be reused by other PDN, but because HO in progress, the current network is still under the old interfaceName. Fix by mark current network SUSPENDED and update the current interfaceName to be "" . Test: atest + basic placing phone call Fix: 243698950 Change-Id: I7650c79ba1a9a69a22f6a0e67cf7932f6fa2dfc3 --- .../internal/telephony/data/DataNetwork.java | 26 +++++++++++++++++++ .../telephony/data/DataNetworkTest.java | 20 +++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index a7b974e3a3..2f17b00a23 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -1417,6 +1417,13 @@ public class DataNetwork extends StateMachine { + AccessNetworkConstants.transportTypeToString(transport) + " data call list changed event. " + responseList); } else { + // If source PDN is reported lost, notify network agent that the PDN is + // temporarily suspended and the old interface name is no longer usable. + boolean currentPdnIsAlive = responseList.stream() + .anyMatch(r -> mCid.get(mTransport) == r.getId()); + if (!currentPdnIsAlive) { + notifyNetworkUnusable(); + } log("Defer message " + eventToString(msg.what) + ":" + responseList); deferMessage(msg); } @@ -1464,6 +1471,25 @@ public class DataNetwork extends StateMachine { } return HANDLED; } + + /** + * Notify network agent that the PDN is temporarily suspended and the old interface name is + * no longer usable. The state will be re-evaluated when the handover ends. + */ + private void notifyNetworkUnusable() { + log(AccessNetworkConstants.transportTypeToString(mTransport) + + " reports current PDN lost, update capability to SUSPENDED," + + " TNA interfaceName to \"\""); + mNetworkCapabilities = new NetworkCapabilities + .Builder(mNetworkCapabilities) + .removeCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) + .build(); + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + + mLinkProperties.setInterfaceName(""); + mNetworkAgent.sendLinkProperties(mLinkProperties); + } } /** 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 7bab74d5a8..6b96d83176 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -989,12 +989,30 @@ public class DataNetworkTest extends TelephonyTest { public void testHandover() throws Exception { setupDataNetwork(); - setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 456); // Now handover to IWLAN mDataNetworkUT.startHandover(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, null); + // the source transport might report PDN lost + mDataNetworkUT.sendMessage(8/*EVENT_DATA_STATE_CHANGED*/, + new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + Collections.emptyList(), null)); processAllMessages(); + // make sure interface name of source PDN is cleared + assertThat(mDataNetworkUT.getLinkProperties().getInterfaceName()).isNotEqualTo("ifname"); + // make sure the capability of source PDN is set to SUSPENDED + assertThat(mDataNetworkUT.getNetworkCapabilities() + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)).isFalse(); verify(mMockedWwanDataServiceManager).startHandover(eq(123), any(Message.class)); + + // continue the HO + setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 456); + Message msg = new Message(); + msg.what = 26/*EVENT_NOTIFY_HANDOVER_STARTED_RESPONSE*/; + msg.arg2 = AccessNetworkConstants.TRANSPORT_TYPE_WLAN; + msg.obj = null; + mDataNetworkUT.sendMessage(msg); + processAllMessages(); + verify(mLinkBandwidthEstimator).unregisterCallback(any( LinkBandwidthEstimatorCallback.class)); assertThat(mDataNetworkUT.getTransport()) -- GitLab From 8afa5f8abc5366a706ef5b0852d88167d2b168ac Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Fri, 19 Aug 2022 16:26:20 +0000 Subject: [PATCH 078/656] Separate QoS filter match check - address & port If there is one of them, only existing filter will be used to check match of QosSocket. - Only check match of Port match when there is no Address info in QosFilter. - Only check match of Address when there is no port info in QosFilter. Bug: 242634602 Bug: 193720581 Test: Carrier TC with Test Equipment Change-Id: Ic2fedae69192aaa3a1aef3322cf32bda3b115431 will be merged Change-Id: Ifc7d0dbc30f2c363d3874916d8f8da73d1129650 will be merged Change-Id: I7db0005826760057c0937685efb778ecbed4eb5f --- .../telephony/data/QosCallbackTracker.java | 108 +++++++++++------- .../data/QosCallbackTrackerTest.java | 64 +++++++++-- 2 files changed, 116 insertions(+), 56 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java index b7cecbdbdb..bde24df4db 100644 --- a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java +++ b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java @@ -37,6 +37,7 @@ import com.android.telephony.Rlog; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -280,41 +281,61 @@ public class QosCallbackTracker extends Handler { private boolean matchesByLocalAddress(final @NonNull QosBearerFilter sessionFilter, final @NonNull IFilter filter) { - if (sessionFilter.getLocalPortRange() == null) return false; - for (final LinkAddress qosAddress : sessionFilter.getLocalAddresses()) { - return filter.matchesLocalAddress(qosAddress.getAddress(), - sessionFilter.getLocalPortRange().getStart(), - sessionFilter.getLocalPortRange().getEnd()); + int portStart; + int portEnd; + if (sessionFilter.getLocalPortRange() == null) { + portStart = QosBearerFilter.QOS_MIN_PORT; + portEnd = QosBearerFilter.QOS_MAX_PORT; + } else if (sessionFilter.getLocalPortRange().isValid()) { + portStart = sessionFilter.getLocalPortRange().getStart(); + portEnd = sessionFilter.getLocalPortRange().getEnd(); + } else { + return false; + } + if (sessionFilter.getLocalAddresses().isEmpty()) { + InetAddress anyAddress; + try { + anyAddress = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); + } catch (UnknownHostException e) { + return false; + } + return filter.matchesLocalAddress(anyAddress, portStart, portEnd); + } else { + for (final LinkAddress qosAddress : sessionFilter.getLocalAddresses()) { + return filter.matchesLocalAddress(qosAddress.getAddress(), portStart, portEnd); + } } return false; } private boolean matchesByRemoteAddress(@NonNull QosBearerFilter sessionFilter, final @NonNull IFilter filter) { - if (sessionFilter.getRemotePortRange() == null) return false; - for (final LinkAddress qosAddress : sessionFilter.getRemoteAddresses()) { - return filter.matchesRemoteAddress(qosAddress.getAddress(), - sessionFilter.getRemotePortRange().getStart(), - sessionFilter.getRemotePortRange().getEnd()); + int portStart; + int portEnd; + boolean result = false; + if (sessionFilter.getRemotePortRange() == null) { + portStart = QosBearerFilter.QOS_MIN_PORT; + portEnd = QosBearerFilter.QOS_MAX_PORT; + } else if (sessionFilter.getRemotePortRange().isValid()) { + portStart = sessionFilter.getRemotePortRange().getStart(); + portEnd = sessionFilter.getRemotePortRange().getEnd(); + } else { + return false; } - return false; - } - - private boolean matchesByRemoteAndLocalAddress(@NonNull QosBearerFilter sessionFilter, - final @NonNull IFilter filter) { - if (sessionFilter.getLocalPortRange() == null - || sessionFilter.getRemotePortRange() == null) return false; - for (final LinkAddress remoteAddress : sessionFilter.getRemoteAddresses()) { - for (final LinkAddress localAddress : sessionFilter.getLocalAddresses()) { - return filter.matchesRemoteAddress(remoteAddress.getAddress(), - sessionFilter.getRemotePortRange().getStart(), - sessionFilter.getRemotePortRange().getEnd()) - && filter.matchesLocalAddress(localAddress.getAddress(), - sessionFilter.getLocalPortRange().getStart(), - sessionFilter.getLocalPortRange().getEnd()); + if (sessionFilter.getRemoteAddresses().isEmpty()) { + InetAddress anyAddress; + try { + anyAddress = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); + } catch (UnknownHostException e) { + return false; + } + result = filter.matchesRemoteAddress(anyAddress, portStart, portEnd); + } else { + for (final LinkAddress qosAddress : sessionFilter.getRemoteAddresses()) { + result = filter.matchesRemoteAddress(qosAddress.getAddress(), portStart, portEnd); } } - return false; + return result; } private QosBearerFilter getFilterByPrecedence( @@ -329,28 +350,27 @@ public class QosCallbackTracker extends Handler { QosBearerFilter qosFilter = null; for (final QosBearerFilter sessionFilter : qosBearerSession.getQosBearerFilterList()) { + boolean unMatched = false; + boolean hasMatchedFilter = false; if (!sessionFilter.getLocalAddresses().isEmpty() - && !sessionFilter.getRemoteAddresses().isEmpty() - && sessionFilter.getLocalPortRange() != null - && sessionFilter.getLocalPortRange().isValid() - && sessionFilter.getRemotePortRange() != null - && sessionFilter.getRemotePortRange().isValid()) { - if (matchesByRemoteAndLocalAddress(sessionFilter, filter)) { - qosFilter = getFilterByPrecedence(qosFilter, sessionFilter); - } - } else if (!sessionFilter.getRemoteAddresses().isEmpty() - && sessionFilter.getRemotePortRange() != null - && sessionFilter.getRemotePortRange().isValid()) { - if (matchesByRemoteAddress(sessionFilter, filter)) { - qosFilter = getFilterByPrecedence(qosFilter, sessionFilter); + || sessionFilter.getLocalPortRange() != null) { + if (!matchesByLocalAddress(sessionFilter, filter)) { + unMatched = true; + } else { + hasMatchedFilter = true; } - } else if (!sessionFilter.getLocalAddresses().isEmpty() - && sessionFilter.getLocalPortRange() != null - && sessionFilter.getLocalPortRange().isValid()) { - if (matchesByLocalAddress(sessionFilter, filter)) { - qosFilter = getFilterByPrecedence(qosFilter, sessionFilter); + } + if (!sessionFilter.getRemoteAddresses().isEmpty() + || sessionFilter.getRemotePortRange() != null) { + if (!matchesByRemoteAddress(sessionFilter, filter)) { + unMatched = true; + } else { + hasMatchedFilter = true; } } + if (!unMatched && hasMatchedFilter) { + qosFilter = getFilterByPrecedence(qosFilter, sessionFilter); + } } return qosFilter; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java index 00bca4d0af..7856564471 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java @@ -51,7 +51,6 @@ import org.junit.runner.RunWith; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.ArrayList; -import java.util.Arrays; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -76,7 +75,7 @@ public class QosCallbackTrackerTest extends TelephonyTest { final int startPort, final int endPort) { return startPort <= mLocalAddress.getPort() && endPort >= mLocalAddress.getPort() - && mLocalAddress.getAddress().equals(address); + && (address.isAnyLocalAddress() || mLocalAddress.getAddress().equals(address)); } public boolean matchesRemoteAddress(final @NonNull InetAddress address, @@ -84,7 +83,7 @@ public class QosCallbackTrackerTest extends TelephonyTest { return mRemoteAddress != null && startPort <= mRemoteAddress.getPort() && endPort >= mRemoteAddress.getPort() - && mRemoteAddress.getAddress().equals(address); + && (address.isAnyLocalAddress() || mRemoteAddress.getAddress().equals(address)); } } @@ -132,22 +131,32 @@ public class QosCallbackTrackerTest extends TelephonyTest { public static QosBearerFilter createIpv4QosFilter(String localAddress, QosBearerFilter.PortRange localPort, int precedence) { + ArrayList localAddresses = new ArrayList<>(); + if (localAddress != null) { + localAddresses.add( + new LinkAddress(InetAddresses.parseNumericAddress(localAddress), 32)); + } return new QosBearerFilter( - Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(localAddress), 32)), - new ArrayList<>(), localPort, null, QosBearerFilter.QOS_PROTOCOL_TCP, - 7, 987, 678, QosBearerFilter.QOS_FILTER_DIRECTION_BIDIRECTIONAL, precedence); + localAddresses, new ArrayList<>(), localPort, null, + QosBearerFilter.QOS_PROTOCOL_TCP, 7, 987, 678, + QosBearerFilter.QOS_FILTER_DIRECTION_BIDIRECTIONAL, precedence); } private static QosBearerFilter createIpv4QosFilter(String localAddress, String remoteAddress, QosBearerFilter.PortRange localPort, QosBearerFilter.PortRange remotePort, int precedence) { + ArrayList localAddresses = new ArrayList<>(); + if (localAddress != null) { + localAddresses.add( + new LinkAddress(InetAddresses.parseNumericAddress(localAddress), 32)); + } + ArrayList remoteAddresses = new ArrayList<>(); + if (localAddress != null) { + remoteAddresses.add( + new LinkAddress(InetAddresses.parseNumericAddress(remoteAddress), 32)); + } return new QosBearerFilter( - Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(localAddress), 32)), - Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(remoteAddress), 32)), - localPort, remotePort, + localAddresses, remoteAddresses, localPort, remotePort, QosBearerFilter.QOS_PROTOCOL_TCP, 7, 987, 678, QosBearerFilter.QOS_FILTER_DIRECTION_BIDIRECTIONAL, precedence); } @@ -508,6 +517,37 @@ public class QosCallbackTrackerTest extends TelephonyTest { } + @Test + @SmallTest + public void testQosSessionFilterPortRangeWithoutAddress() throws Exception { + // QosBearerFilter including remote port range without remote address + ArrayList qosFilters1 = new ArrayList<>(); + qosFilters1.add(createIpv4QosFilter(null, null, null, + new QosBearerFilter.PortRange(3200, 3220), 45)); + + ArrayList qosSessions = new ArrayList<>(); + qosSessions.add(new QosBearerSession(1234, createEpsQos(5, 6, 7, 8), qosFilters1)); + + mQosCallbackTracker.updateSessions(qosSessions); + + // Add filter after updateSessions + Filter filter = new Filter(new InetSocketAddress( + InetAddresses.parseNumericAddress("122.22.22.22"), 1357), + new InetSocketAddress(InetAddresses.parseNumericAddress("177.77.77.77"), 3202)); + mQosCallbackTracker.addFilter(1, filter); + processAllMessages(); + + verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), + eq(1234), any(EpsBearerQosSessionAttributes.class)); + + // Remove the matching QosBearerFilter + qosSessions.remove(0); + mQosCallbackTracker.updateSessions(qosSessions); + processAllMessages(); + + verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234), eq(1)); + } + @Test @SmallTest public void testQosMetrics() throws Exception { -- GitLab From 5d3ec4f9f762aae06247697140f376a63a9f5f7a Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Wed, 31 Aug 2022 11:09:09 -0700 Subject: [PATCH 079/656] Merge similar data profile - ignore gid difference Fix: 240225494 Test: atest Change-Id: I2a8300ad28a70cfd3b570d7ec9e2cafcdc010d2e --- .../android/internal/telephony/data/DataProfileManager.java | 5 +++-- .../internal/telephony/data/DataProfileManagerTest.java | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java index 42e532d183..8e20827c7c 100644 --- a/src/java/com/android/internal/telephony/data/DataProfileManager.java +++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java @@ -917,6 +917,9 @@ public class DataProfileManager extends Handler { ? apn1.getMtuV4() : apn2.getMtuV4()); apnBuilder.setMtuV6(apn2.getMtuV6() <= ApnSetting.UNSET_MTU ? apn1.getMtuV6() : apn2.getMtuV6()); + // legacy properties that don't matter + apnBuilder.setMvnoType(apn1.getMvnoType()); + apnBuilder.setMvnoMatchData(apn1.getMvnoMatchData()); // The following fields in apn1 and apn2 should be the same, otherwise ApnSetting.similar() // should fail earlier. @@ -931,8 +934,6 @@ public class DataProfileManager extends Handler { apnBuilder.setMaxConns(apn1.getMaxConns()); apnBuilder.setWaitTime(apn1.getWaitTime()); apnBuilder.setMaxConnsTime(apn1.getMaxConnsTime()); - apnBuilder.setMvnoType(apn1.getMvnoType()); - apnBuilder.setMvnoMatchData(apn1.getMvnoMatchData()); apnBuilder.setApnSetId(apn1.getApnSetId()); apnBuilder.setCarrierId(apn1.getCarrierId()); apnBuilder.setSkip464Xlat(apn1.getSkip464Xlat()); 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 7c7befaa6a..f3b4dce0bf 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java @@ -795,6 +795,8 @@ public class DataProfileManagerTest extends TelephonyTest { .setProtocol(ApnSetting.PROTOCOL_IPV4V6) .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6) .setCarrierEnabled(true) + .setMvnoMatchData("1") + .setMvnoType(1) .build()) .build(); @@ -809,6 +811,8 @@ public class DataProfileManagerTest extends TelephonyTest { .setProtocol(ApnSetting.PROTOCOL_IPV4V6) .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6) .setCarrierEnabled(true) + .setMvnoMatchData("2") + .setMvnoType(2) .build()) .build(); -- GitLab From 7210d91c36b8229b4b228ae97d598818d6584966 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 30 Aug 2022 19:49:24 -0700 Subject: [PATCH 080/656] Adopt the last data profile that works for internet as preferred After APN reset, if no carrier configured default, and the data profile that was successfully used in the current internet connection still exists, adopt that one as the preferred as the best guess. Test: atest Fix: 242968857 Change-Id: I26a1e7e41f5705d0e30b446fe9bb8d66b13cf0f8 --- .../telephony/data/DataProfileManager.java | 22 ++++++++++++++++--- .../data/DataProfileManagerTest.java | 14 +++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java index 42e532d183..34bed10859 100644 --- a/src/java/com/android/internal/telephony/data/DataProfileManager.java +++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java @@ -106,6 +106,9 @@ public class DataProfileManager extends Handler { /** 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; + /** Preferred data profile set id. */ private int mPreferredDataProfileSetId = Telephony.Carriers.NO_APN_SET_ID; @@ -166,7 +169,12 @@ public class DataProfileManager extends Handler { public void onInternetDataNetworkConnected( @NonNull List dataProfiles) { DataProfileManager.this.onInternetDataNetworkConnected(dataProfiles); - }}); + } + @Override + public void onInternetDataNetworkDisconnected() { + DataProfileManager.this.onInternetDataNetworkDisconnected(); + } + }); mDataConfigManager.registerCallback(new DataConfigManagerCallback(this::post) { @Override public void onCarrierConfigChanged() { @@ -410,11 +418,19 @@ public class DataProfileManager extends Handler { DataProfile dataProfile = dataProfiles.stream() .max(Comparator.comparingLong(DataProfile::getLastSetupTimestamp).reversed()) .orElse(null); + mLastInternetDataProfile = dataProfile; // Save the preferred data profile into database. setPreferredDataProfile(dataProfile); updateDataProfiles(ONLY_UPDATE_IA_IF_CHANGED); } + /** + * Called when internet data is disconnected. + */ + private void onInternetDataNetworkDisconnected() { + mLastInternetDataProfile = null; + } + /** * Get the preferred data profile for internet data. * @@ -498,12 +514,12 @@ public class DataProfileManager extends Handler { setPreferredDataProfile(preferredDataProfile); } else { preferredDataProfile = mAllDataProfiles.stream() - .filter(dp -> areDataProfileSharingApn(dp, mPreferredDataProfile)) + .filter(dp -> areDataProfileSharingApn(dp, mLastInternetDataProfile)) .findFirst() .orElse(null); if (preferredDataProfile != null) { log("updatePreferredDataProfile: preferredDB is empty and no carrier " - + "default configured, setting preferred to be prev preferred DP."); + + "default configured, setting preferred to be prev internet DP."); setPreferredDataProfile(preferredDataProfile); } } 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 7c7befaa6a..58800c61b4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java @@ -938,10 +938,22 @@ public class DataProfileManagerTest extends TelephonyTest { mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget(); processAllMessages(); - // preferred APN should set to be the prev preferred + // preferred APN should set to be the last data profile that succeeded for internet setup assertThat(mDataProfileManagerUT.isAnyPreferredDataProfileExisting()).isTrue(); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); + // no active internet, expect no preferred APN after reset + mDataNetworkControllerCallback.onInternetDataNetworkDisconnected(); + mPreferredApnId = -1; + mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget(); + processAllMessages(); + + assertThat(mDataProfileManagerUT.isAnyPreferredDataProfileExisting()).isFalse(); + assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isFalse(); + + // setup internet again + mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(dataProfile)); + processAllMessages(); //APN reset and removed GENERAL_PURPOSE_APN(as if user created) from APN DB mPreferredApnId = -1; mApnSettingContentProvider.removeApnByApnId(1); -- GitLab From efb166e5dd627390ca1e6a7a6438de79a917ab90 Mon Sep 17 00:00:00 2001 From: hyosun Date: Mon, 29 Aug 2022 09:26:06 +0000 Subject: [PATCH 081/656] To read the group UUID, the calling app either needs carrier privileges or the READ_PHONE_STATE permission and access to device identifiers. If the app has only the READ_PHONE_STATE permission, it can no longer read the group UUID. When SubscriptionManager#getSubscriptionsInGroup is called, If the calling app has carrier permission or READ_PHONE_STATE permission and access to device identifiers, then returns a list. If not, it will throw a SecurityException. Bug: 213902861 Test: atest SubscriptionManagerTest Test: atest SubscriptionControllerTest Test: manual (b/213902861#comment54) Change-Id: Idaa1b97f7ae2d0ce0c0027b0499d4a930fcce981 --- .../telephony/SubscriptionController.java | 43 +++++++- .../telephony/SubscriptionControllerTest.java | 98 ++++++++++++++++--- 2 files changed, 125 insertions(+), 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index f1f650348c..0095c17f59 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -28,6 +28,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.PendingIntent; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentValues; @@ -164,6 +167,15 @@ public class SubscriptionController extends ISub.Stub { protected TelephonyManager mTelephonyManager; protected UiccController mUiccController; + /** + * Apps targeting on Android T and beyond will get exception if there is no access to device + * identifiers nor has carrier privileges when calling + * SubscriptionManager#getSubscriptionsInGroup. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + public static final long REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID = 213902861L; + private AppOpsManager mAppOps; // Each slot can have multiple subs. @@ -3944,10 +3956,20 @@ public class SubscriptionController extends ISub.Stub { * Get subscriptionInfo list of subscriptions that are in the same group of given subId. * See {@link #createSubscriptionGroup(int[], String)} for more details. * - * Caller will either have {@link android.Manifest.permission#READ_PHONE_STATE} - * permission or had carrier privilege permission on the subscription. + * Caller must have {@link android.Manifest.permission#READ_PHONE_STATE} + * or carrier privilege permission on the subscription. * {@link TelephonyManager#hasCarrierPrivileges(int)} * + *

Starting with API level 33, the caller needs READ_PHONE_STATE and access to device + * identifiers to get the list of subscriptions associated with a group UUID. + * This method can be invoked if one of the following requirements is met: + *

    + *
  • If the app has carrier privilege permission. + * {@link TelephonyManager#hasCarrierPrivileges()} + *
  • If the app has {@link android.Manifest.permission#READ_PHONE_STATE} and + * access to device identifiers. + *
+ * * @throws SecurityException if the caller doesn't meet the requirements * outlined above. * @@ -3974,6 +3996,23 @@ public class SubscriptionController extends ISub.Stub { Binder.restoreCallingIdentity(identity); } + // If the calling app neither has carrier privileges nor READ_PHONE_STATE and access to + // device identifiers, it will throw a securityException. + if (CompatChanges.isChangeEnabled( + REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID, Binder.getCallingUid())) { + try { + if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext, + callingPackage, callingFeatureId, "getSubscriptionsInGroup")) { + EventLog.writeEvent(0x534e4554, "213902861", Binder.getCallingUid()); + throw new SecurityException("Need to have carrier privileges or access to " + + "device identifiers to call getSubscriptionsInGroup"); + } + } catch (SecurityException e) { + EventLog.writeEvent(0x534e4554, "213902861", Binder.getCallingUid()); + throw e; + } + } + return subInfoList.stream().filter(info -> { if (!groupUuid.equals(info.getGroupUuid())) return false; int subId = info.getSubscriptionId(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index 2cfd3da04c..f80253e966 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION; +import static com.android.internal.telephony.SubscriptionController.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID; import static com.android.internal.telephony.uicc.IccCardStatus.CardState.CARDSTATE_PRESENT; import static org.junit.Assert.assertEquals; @@ -32,7 +33,9 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -40,6 +43,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.Manifest; +import android.compat.testing.PlatformCompatChangeRule; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; @@ -67,9 +71,14 @@ import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.uicc.UiccSlot; +import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import org.mockito.ArgumentCaptor; import java.util.ArrayList; @@ -107,6 +116,9 @@ public class SubscriptionControllerTest extends TelephonyTest { private static final String DISPLAY_NUMBER = "123456"; private static final String DISPLAY_NAME = "testing_display_name"; + @Rule + public TestRule mCompatChangeRule = new PlatformCompatChangeRule(); + @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); @@ -1072,6 +1084,7 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test @SmallTest + @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testAddSubscriptionIntoGroupWithCarrierPrivilegePermission() throws Exception { testInsertSim(); // Adding a second profile and mark as embedded. @@ -1088,6 +1101,7 @@ public class SubscriptionControllerTest extends TelephonyTest { // Create group for sub 1. int[] subIdList = new int[] {1}; + doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1); ParcelUuid groupId = mSubscriptionControllerUT.createSubscriptionGroup( subIdList, "packageName1"); @@ -1123,6 +1137,7 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test @SmallTest + @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testUpdateSubscriptionGroupWithCarrierPrivilegePermission() throws Exception { testInsertSim(); // Adding a second profile and mark as embedded. @@ -1139,6 +1154,7 @@ public class SubscriptionControllerTest extends TelephonyTest { int[] subIdList = new int[] {1}; + doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1); doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(2); @@ -1244,6 +1260,7 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test @SmallTest + @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testSetSubscriptionGroup() throws Exception { testInsertSim(); // Adding a second profile and mark as embedded. @@ -1266,6 +1283,7 @@ public class SubscriptionControllerTest extends TelephonyTest { assertNotEquals(null, groupUuid); // Sub 1 and sub 2 should be in same group. + doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); List infoList = mSubscriptionControllerUT.getSubscriptionsInGroup( groupUuid, mContext.getOpPackageName(), mContext.getAttributionTag()); assertNotEquals(null, infoList); @@ -1679,42 +1697,91 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void testGetSubscriptionsInGroupWithNoPermission() throws Exception { - // If the calling package does not have the READ_PHONE_STATE permission or carrier - // privileges then getSubscriptionsInGroup should throw a SecurityException when the - // READ_PHONE_STATE permission check is performed. + @DisableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) + public void testGetSubscriptionsInGroupWithReadPhoneState() throws Exception { + // For backward compatibility test ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); + setupReadPhoneNumbersTest(); + setIdentifierAccess(false); + List subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup( + groupUuid, mCallingPackage, mCallingFeature); + + assertTrue(subInfoList.size() > 0); + for (SubscriptionInfo info : subInfoList) { + assertEquals(UNAVAILABLE_ICCID, info.getIccId()); + assertEquals(UNAVAILABLE_ICCID, info.getCardString()); + assertEquals(UNAVAILABLE_NUMBER, info.getNumber()); + } + } + + @Test + @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) + public void testGetSubscriptionsInGroupWithoutAppropriatePermission() throws Exception { + ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); + + // no permission + setNoPermission(); try { mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage, mCallingFeature); fail("getSubscriptionsInGroup should fail when invoked with no permissions"); } catch (SecurityException expected) { } + + // only has the USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permission + setIdentifierAccess(true); + try { + mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage, + mCallingFeature); + fail("getSubscriptionsInGroup should fail when invoked with no" + + "READ_PHONE_STATE permissions"); + } catch (SecurityException expected) { + } + + // only has the READ_PHONE_STATE permission + setIdentifierAccess(false); + setReadPhoneState(); + try { + mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage, + mCallingFeature); + fail("getSubscriptionsInGroup should fail when invoked with no " + + "USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permissions"); + } catch (SecurityException expected) { + } } @Test - public void testGetSubscriptionsInGroupWithReadPhoneState() throws Exception { - // If the calling package only has the READ_PHONE_STATE permission then - // getSubscriptionsInGroup should still return the list of SubscriptionInfo objects - // but the ICC ID should not be available via getIccId or getCardString. + @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) + public void testGetSubscriptionsInGroupWithReadDeviceIdentifier() throws Exception { ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); - setupReadPhoneNumbersTest(); - setIdentifierAccess(false); + setNoPermission(); + setCarrierPrivileges(false); + setIdentifierAccess(true); + setReadPhoneState(); List subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup( groupUuid, mCallingPackage, mCallingFeature); assertTrue(subInfoList.size() > 0); for (SubscriptionInfo info : subInfoList) { - assertEquals(UNAVAILABLE_ICCID, info.getIccId()); - assertEquals(UNAVAILABLE_ICCID, info.getCardString()); - assertEquals(UNAVAILABLE_NUMBER, info.getNumber()); + assertTrue(info.getIccId().length() > 0); + assertTrue(info.getCardString().length() > 0); } } + private void setNoPermission() { + doThrow(new SecurityException()).when(mContext) + .enforcePermission(anyString(), anyInt(), anyInt(), anyString()); + } + + private void setReadPhoneState() { + doNothing().when(mContext).enforcePermission( + eq(android.Manifest.permission.READ_PHONE_STATE), anyInt(), anyInt(), anyString()); + } + @Test + @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testGetSubscriptionInGroupWithPhoneNumberAccess() throws Exception { // If the calling package meets any of the requirements for the // LegacyPermissionManager#checkPhoneNumberAccess test then the number should be available @@ -1732,6 +1799,7 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test + @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testGetSubscriptionsInGroupWithCarrierPrivileges() throws Exception { // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier // privileges the ICC ID should be available in the SubscriptionInfo objects in the List. @@ -1749,6 +1817,7 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test + @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testGetSubscriptionsInGroupWithPrivilegedPermission() throws Exception { // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier // privileges the ICC ID should be available in the SubscriptionInfo objects in the List. @@ -1770,6 +1839,7 @@ public class SubscriptionControllerTest extends TelephonyTest { ParcelUuid groupUuid = mSubscriptionControllerUT.createSubscriptionGroup(subIdList, mCallingPackage); assertNotNull(groupUuid); + doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); return groupUuid; } -- GitLab From 2893e429cb4ce1bf6cf451603633d3d1a2426afb Mon Sep 17 00:00:00 2001 From: Hyunho Date: Tue, 9 Aug 2022 13:13:03 +0000 Subject: [PATCH 082/656] Create an ImsEnablementTraker class to handle the enable, disable, reset Ims commands. Create an ImsEnablementTraker class to handle the enable, disable, reset Ims commands. Input commands are processed by asyncronus with a certain time gap. Bug: b/232846588 Test: atest ImsEnablementTrackerTest Change-Id: I4985fd26f3a444a15c6846077f551f95392b1310 --- .../telephony/ims/ImsEnablementTracker.java | 671 ++++++++++++++++++ .../internal/telephony/ims/ImsResolver.java | 9 + .../telephony/ims/ImsServiceController.java | 33 +- .../ims/ImsEnablementTrackerTest.java | 508 +++++++++++++ 4 files changed, 1202 insertions(+), 19 deletions(-) create mode 100644 src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java diff --git a/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java b/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java new file mode 100644 index 0000000000..dea12bd9d4 --- /dev/null +++ b/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2022 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.ims; + +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.telephony.ims.aidl.IImsServiceController; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; + +/** + * This class will abstract away all the new enablement logic and take the reset/enable/disable + * IMS commands as inputs. + * The IMS commands will call enableIms or disableIms to match the enablement state only when + * it changes. + */ +public class ImsEnablementTracker { + private static final String LOG_TAG = "ImsEnablementTracker"; + private static final long REQUEST_THROTTLE_TIME_MS = 1 * 1000; // 1 seconds + + private static final int COMMAND_NONE_MSG = 0; + // Indicate that the enableIms command has been received. + private static final int COMMAND_ENABLE_MSG = 1; + // Indicate that the disableIms command has been received. + private static final int COMMAND_DISABLE_MSG = 2; + // Indicate that the resetIms command has been received. + private static final int COMMAND_RESET_MSG = 3; + // Indicate that the internal enable message with delay has been received. + @VisibleForTesting + protected static final int COMMAND_ENABLING_DONE = 4; + // Indicate that the internal disable message with delay has been received. + @VisibleForTesting + protected static final int COMMAND_DISABLING_DONE = 5; + // Indicate that the internal reset message with delay has been received. + @VisibleForTesting + protected static final int COMMAND_RESETTING_DONE = 6; + // The ImsServiceController binder is connected. + private static final int COMMAND_CONNECTED_MSG = 7; + // The ImsServiceController binder is disconnected. + private static final int COMMAND_DISCONNECTED_MSG = 8; + + @VisibleForTesting + protected static final int STATE_IMS_DISCONNECTED = 0; + @VisibleForTesting + protected static final int STATE_IMS_DEFAULT = 1; + @VisibleForTesting + protected static final int STATE_IMS_ENABLED = 2; + @VisibleForTesting + protected static final int STATE_IMS_DISABLING = 3; + @VisibleForTesting + protected static final int STATE_IMS_DISABLED = 4; + @VisibleForTesting + protected static final int STATE_IMS_ENABLING = 5; + @VisibleForTesting + protected static final int STATE_IMS_RESETTING = 6; + + protected final Object mLock = new Object(); + private IImsServiceController mIImsServiceController; + private long mLastImsOperationTimeMs = 0L; + + private final ImsEnablementTrackerStateMachine mEnablementStateMachine; + + /** + * Provides Ims Enablement Tracker State Machine responsible for ims enable/disable command + * interactions with Ims service controller binder. + * The enable/disable/reset ims commands have a time interval of at least 1 second between + * processing each command. + * For example, the enableIms command is received and the binder's enableIms is called. + * After that, if the disableIms command is received, the binder's disableIms will be + * called after 1 second. + * A time of 1 second uses {@link Handler#sendMessageDelayed(Message, long)}, + * and the enabled, disabled and reset states are responsible for waiting for + * that delay message. + */ + class ImsEnablementTrackerStateMachine extends StateMachine { + /** + * The initial state of this class and waiting for an ims commands. + */ + @VisibleForTesting + public final Default mDefault; + /** + * Indicates that {@link IImsServiceController#enableIms(int, int)} has been called and + * waiting for an ims commands. + * Common transitions are to + * {@link #mDisabling} state when the disable command is received + * or {@link #mResetting} state when the reset command is received. + * or {@link #mDisconnected} if the binder is disconnected. + */ + @VisibleForTesting + public final Enabled mEnabled; + /** + * Indicates that the state waiting for a disableIms message. + * Common transitions are to + * {@link #mEnabled} when the enable command is received. + * or {@link #mResetting} when the reset command is received. + * or {@link #mDisabled} the previous binder API call has passed 1 second, and if + * {@link IImsServiceController#disableIms(int, int)} called. + * or {@link #mDisabling} received a disableIms message and the previous binder API call + * has not passed 1 second.Then send a disableIms message with delay. + * or {@link #mDisconnected} if the binder is disconnected. + */ + @VisibleForTesting + public final Disabling mDisabling; + /** + * Indicates that {@link IImsServiceController#disableIms(int, int)} has been called and + * waiting for an ims commands. + * Common transitions are to + * {@link #mEnabling} state when the enable command is received. + * or {@link #mDisconnected} if the binder is disconnected. + */ + @VisibleForTesting + public final Disabled mDisabled; + /** + * Indicates that the state waiting for an enableIms message. + * Common transitions are to + * {@link #mEnabled} the previous binder API call has passed 1 second, and + * {@link IImsServiceController#enableIms(int, int)} called. + * or {@link #mDisabled} when the disable command is received. + * or {@link #mEnabling} received an enableIms message and the previous binder API call + * has not passed 1 second.Then send an enableIms message with delay. + * or {@link #mDisconnected} if the binder is disconnected. + */ + @VisibleForTesting + public final Enabling mEnabling; + /** + * Indicates that the state waiting for a resetIms message. + * Common transitions are to + * {@link #mDisabling} state when the disable command is received + * or {@link #mResetting} received a resetIms message and the previous binder API call + * has not passed 1 second.Then send a resetIms message with delay. + * or {@link #mEnabling} when the resetIms message is received and if + * {@link IImsServiceController#disableIms(int, int)} call is successful. And send an enable + * message with delay. + * or {@link #mDisconnected} if the binder is disconnected. + */ + @VisibleForTesting + public final Resetting mResetting; + /** + * Indicates that {@link IImsServiceController} has not been set. + * Common transition is to + * {@link #mDefault} state when the binder is set. + * or {@link #mDisabling} If the disable command is received while the binder is + * disconnected + * or {@link #mEnabling} If the enable command is received while the binder is + * disconnected + */ + @VisibleForTesting + public final Disconnected mDisconnected; + + @VisibleForTesting + public int mSlotId; + @VisibleForTesting + public int mSubId; + + ImsEnablementTrackerStateMachine(String name, Looper looper) { + super(name, looper); + mDefault = new Default(); + mEnabled = new Enabled(); + mDisabling = new Disabling(); + mDisabled = new Disabled(); + mEnabling = new Enabling(); + mResetting = new Resetting(); + mDisconnected = new Disconnected(); + + addState(mDefault); + addState(mEnabled); + addState(mDisabling); + addState(mDisabled); + addState(mEnabling); + addState(mResetting); + addState(mDisconnected); + setInitialState(mDisconnected); + } + + public void clearAllMessage() { + Log.d(LOG_TAG, "clearAllMessage"); + removeMessages(COMMAND_ENABLE_MSG); + removeMessages(COMMAND_DISABLE_MSG); + removeMessages(COMMAND_RESET_MSG); + removeMessages(COMMAND_ENABLING_DONE); + removeMessages(COMMAND_DISABLING_DONE); + removeMessages(COMMAND_RESETTING_DONE); + } + + public void serviceBinderConnected() { + clearAllMessage(); + sendMessage(COMMAND_CONNECTED_MSG); + } + + public void serviceBinderDisconnected() { + clearAllMessage(); + sendMessage(COMMAND_DISCONNECTED_MSG); + } + + @VisibleForTesting + public void setState(int state) { + if (state == mDefault.mStateNo) { + mEnablementStateMachine.transitionTo(mDefault); + } else if (state == mEnabled.mStateNo) { + mEnablementStateMachine.transitionTo(mEnabled); + } else if (state == mDisabling.mStateNo) { + mEnablementStateMachine.transitionTo(mDisabling); + } else if (state == mDisabled.mStateNo) { + mEnablementStateMachine.transitionTo(mDisabled); + } else if (state == mEnabling.mStateNo) { + mEnablementStateMachine.transitionTo(mEnabling); + } else if (state == mResetting.mStateNo) { + mEnablementStateMachine.transitionTo(mResetting); + } + } + + @VisibleForTesting + public boolean isState(int state) { + if (state == mDefault.mStateNo) { + return (mEnablementStateMachine.getCurrentState() == mDefault) ? true : false; + } else if (state == mEnabled.mStateNo) { + return (mEnablementStateMachine.getCurrentState() == mEnabled) ? true : false; + } else if (state == mDisabling.mStateNo) { + return (mEnablementStateMachine.getCurrentState() == mDisabling) ? true : false; + } else if (state == mDisabled.mStateNo) { + return (mEnablementStateMachine.getCurrentState() == mDisabled) ? true : false; + } else if (state == mEnabling.mStateNo) { + return (mEnablementStateMachine.getCurrentState() == mEnabling) ? true : false; + } else if (state == mResetting.mStateNo) { + return (mEnablementStateMachine.getCurrentState() == mResetting) ? true : false; + } + return false; + } + + + class Default extends State { + public int mStateNo = STATE_IMS_DEFAULT; + @Override + public void enter() { + Log.d(LOG_TAG, "Default state:enter"); + } + + @Override + public void exit() { + Log.d(LOG_TAG, "Default state:exit"); + } + + @Override + public boolean processMessage(Message message) { + Log.d(LOG_TAG, "Default state:processMessage. msg.what=" + message.what); + switch(message.what) { + // When enableIms() is called, enableIms of binder is call and the state + // change to the enabled state. + case COMMAND_ENABLE_MSG: + sendEnableIms(message.arg1, message.arg2); + transitionTo(mEnabled); + return HANDLED; + // When disableIms() is called, disableIms of binder is call and the state + // change to the disabled state. + case COMMAND_DISABLE_MSG: + sendDisableIms(message.arg1, message.arg2); + transitionTo(mDisabled); + return HANDLED; + case COMMAND_DISCONNECTED_MSG: + transitionTo(mDisconnected); + return HANDLED; + default: + return NOT_HANDLED; + } + } + } + + class Enabled extends State { + public int mStateNo = STATE_IMS_ENABLED; + @Override + public void enter() { + Log.d(LOG_TAG, "Enabled state:enter"); + } + + @Override + public void exit() { + Log.d(LOG_TAG, "Enabled state:exit"); + } + + @Override + public boolean processMessage(Message message) { + Log.d(LOG_TAG, "Enabled state:processMessage. msg.what=" + message.what); + mSlotId = message.arg1; + mSubId = message.arg2; + switch(message.what) { + // the disableIms() is called. + case COMMAND_DISABLE_MSG: + transitionTo(mDisabling); + return HANDLED; + // the resetIms() is called. + case COMMAND_RESET_MSG: + transitionTo(mResetting); + return HANDLED; + case COMMAND_DISCONNECTED_MSG: + transitionTo(mDisconnected); + return HANDLED; + default: + return NOT_HANDLED; + } + } + } + + class Disabling extends State { + public int mStateNo = STATE_IMS_DISABLING; + @Override + public void enter() { + Log.d(LOG_TAG, "Disabling state:enter"); + sendMessageDelayed(COMMAND_DISABLING_DONE, mSlotId, mSubId, + getRemainThrottleTime()); + } + + @Override + public void exit() { + Log.d(LOG_TAG, "Disabling state:exit"); + } + + @Override + public boolean processMessage(Message message) { + Log.d(LOG_TAG, "Disabling state:processMessage. msg.what=" + message.what); + mSlotId = message.arg1; + mSubId = message.arg2; + switch(message.what) { + // In the enabled state, disableIms() is called, but the throttle timer has + // not expired, so a delay_disable message is sent. + // At this point enableIms() was called, so it cancels the message and just + // changes the state to the enabled. + case COMMAND_ENABLE_MSG: + clearAllMessage(); + transitionTo(mEnabled); + return HANDLED; + case COMMAND_DISABLING_DONE: + // If the disable command is received before disableIms is processed, + // it will be ignored because the disable command processing is in progress. + removeMessages(COMMAND_DISABLE_MSG); + sendDisableIms(mSlotId, mSubId); + transitionTo(mDisabled); + return HANDLED; + case COMMAND_RESET_MSG: + clearAllMessage(); + transitionTo(mResetting); + return HANDLED; + case COMMAND_DISCONNECTED_MSG: + transitionTo(mDisconnected); + return HANDLED; + default: + return NOT_HANDLED; + } + } + } + + class Disabled extends State { + public int mStateNo = STATE_IMS_DISABLED; + @Override + public void enter() { + Log.d(LOG_TAG, "Disabled state:enter"); + } + + @Override + public void exit() { + Log.d(LOG_TAG, "Disabled state:exit"); + } + + @Override + public boolean processMessage(Message message) { + Log.d(LOG_TAG, "Disabled state:processMessage. msg.what=" + message.what); + mSlotId = message.arg1; + mSubId = message.arg2; + switch(message.what) { + case COMMAND_ENABLE_MSG: + transitionTo(mEnabling); + return HANDLED; + case COMMAND_DISCONNECTED_MSG: + transitionTo(mDisconnected); + return HANDLED; + default: + return NOT_HANDLED; + } + } + } + + class Enabling extends State { + public int mStateNo = STATE_IMS_ENABLING; + @Override + public void enter() { + Log.d(LOG_TAG, "Enabling state:enter"); + sendMessageDelayed(COMMAND_ENABLING_DONE, mSlotId, mSubId, getRemainThrottleTime()); + } + + @Override + public void exit() { + Log.d(LOG_TAG, "Enabling state:exit"); + } + + @Override + public boolean processMessage(Message message) { + Log.d(LOG_TAG, "Enabling state:processMessage. msg.what=" + message.what); + mSlotId = message.arg1; + mSubId = message.arg2; + switch(message.what) { + case COMMAND_DISABLE_MSG: + clearAllMessage(); + transitionTo(mDisabled); + return HANDLED; + case COMMAND_ENABLING_DONE: + // If the enable command is received before enableIms is processed, + // it will be ignored because the enable command processing is in progress. + removeMessages(COMMAND_ENABLE_MSG); + sendEnableIms(mSlotId, mSubId); + transitionTo(mEnabled); + return HANDLED; + case COMMAND_DISCONNECTED_MSG: + transitionTo(mDisconnected); + return HANDLED; + default: + return NOT_HANDLED; + } + } + } + + class Resetting extends State { + public int mStateNo = STATE_IMS_RESETTING; + @Override + public void enter() { + Log.d(LOG_TAG, "Resetting state:enter"); + sendMessageDelayed(COMMAND_RESETTING_DONE, mSlotId, mSubId, + getRemainThrottleTime()); + } + + @Override + public void exit() { + Log.d(LOG_TAG, "Resetting state:exit"); + } + + @Override + public boolean processMessage(Message message) { + Log.d(LOG_TAG, "Resetting state:processMessage. msg.what=" + message.what); + mSlotId = message.arg1; + mSubId = message.arg2; + switch(message.what) { + case COMMAND_DISABLE_MSG: + clearAllMessage(); + transitionTo(mDisabling); + return HANDLED; + case COMMAND_RESETTING_DONE: + // If the reset command is received before disableIms is processed, + // it will be ignored because the reset command processing is in progress. + removeMessages(COMMAND_RESET_MSG); + sendDisableIms(mSlotId, mSubId); + transitionTo(mEnabling); + return HANDLED; + case COMMAND_DISCONNECTED_MSG: + transitionTo(mDisconnected); + return HANDLED; + default: + return NOT_HANDLED; + } + } + } + + class Disconnected extends State { + public int mStateNo = STATE_IMS_DISCONNECTED; + private int mLastMsg = COMMAND_NONE_MSG; + @Override + public void enter() { + Log.d(LOG_TAG, "Disconnected state:enter"); + clearAllMessage(); + } + + @Override + public void exit() { + Log.d(LOG_TAG, "Disconnected state:exit"); + mLastMsg = COMMAND_NONE_MSG; + } + + @Override + public boolean processMessage(Message message) { + Log.d(LOG_TAG, "Disconnected state:processMessage. msg.what=" + message.what); + switch(message.what) { + case COMMAND_CONNECTED_MSG: + clearAllMessage(); + transitionTo(mDefault); + if (mLastMsg != COMMAND_NONE_MSG) { + sendMessageDelayed(mLastMsg, mSlotId, mSubId, 0); + } + return HANDLED; + case COMMAND_ENABLE_MSG: + case COMMAND_DISABLE_MSG: + case COMMAND_RESET_MSG: + mLastMsg = message.what; + mSlotId = message.arg1; + mSubId = message.arg2; + return HANDLED; + default: + return NOT_HANDLED; + } + } + } + } + + public ImsEnablementTracker(Looper looper) { + mIImsServiceController = null; + mEnablementStateMachine = new ImsEnablementTrackerStateMachine("ImsEnablementTracker", + looper); + mEnablementStateMachine.start(); + } + + @VisibleForTesting + public ImsEnablementTracker(Looper looper, IImsServiceController controller) { + mIImsServiceController = controller; + mEnablementStateMachine = new ImsEnablementTrackerStateMachine("ImsEnablementTracker", + looper); + mEnablementStateMachine.start(); + mEnablementStateMachine.sendMessage(COMMAND_CONNECTED_MSG); + } + + @VisibleForTesting + public Handler getHandler() { + return mEnablementStateMachine.getHandler(); + } + + /** + * Set the current state as an input state. + * @param state input state. + */ + @VisibleForTesting + public void setState(int state) { + mEnablementStateMachine.setState(state); + } + + /** + * Check that the current state and the input state are the same. + * @param state the input state. + * @return true if the current state and input state are the same or false. + */ + @VisibleForTesting + public boolean isState(int state) { + return mEnablementStateMachine.isState(state); + } + + /** + * Notify ImsService to enable IMS for the framework. This will trigger IMS registration and + * trigger ImsFeature status updates. + * @param slotId slot id + * @param subId subscription id + */ + public void enableIms(int slotId, int subId) { + Log.d(LOG_TAG, "enableIms"); + mEnablementStateMachine.sendMessage(COMMAND_ENABLE_MSG, slotId, subId); + } + + /** + * Notify ImsService to disable IMS for the framework. This will trigger IMS de-registration and + * trigger ImsFeature capability status to become false. + * @param slotId slot id + * @param subId subscription id + */ + public void disableIms(int slotId, int subId) { + Log.d(LOG_TAG, "disableIms"); + mEnablementStateMachine.sendMessage(COMMAND_DISABLE_MSG, slotId, subId); + } + + /** + * Notify ImsService to disable IMS for the framework if current state is enabled. + * And notify ImsService back to enable IMS for the framework. + * @param slotId slot id + * @param subId subscription id + */ + public void resetIms(int slotId, int subId) { + Log.d(LOG_TAG, "resetIms"); + mEnablementStateMachine.sendMessage(COMMAND_RESET_MSG, slotId, subId); + } + + /** + * Sets the IImsServiceController instance. + */ + protected void setServiceController(IBinder serviceController) { + synchronized (mLock) { + mIImsServiceController = IImsServiceController.Stub.asInterface(serviceController); + + if (isServiceControllerAvailable()) { + mEnablementStateMachine.serviceBinderConnected(); + } else { + mEnablementStateMachine.serviceBinderDisconnected(); + } + } + } + + @VisibleForTesting + protected long getLastOperationTimeMillis() { + return mLastImsOperationTimeMs; + } + + /** + * Get remaining throttle time value + * @return remaining throttle time value + */ + @VisibleForTesting + public long getRemainThrottleTime() { + long remainTime = REQUEST_THROTTLE_TIME_MS - (System.currentTimeMillis() + - getLastOperationTimeMillis()); + Log.d(LOG_TAG, "getRemainThrottleTime:" + remainTime); + if (remainTime < 0) { + return 0; + } + return remainTime; + } + + /** + * Send internal Message for testing. + */ + @VisibleForTesting + public void sendInternalMessage(int msg, int slotId, int subId) { + mEnablementStateMachine.sendMessage(msg, slotId, subId); + } + + /** + * Check to see if the service controller is available. + * @return true if available, false otherwise + */ + private boolean isServiceControllerAvailable() { + return mIImsServiceController != null; + } + + private void sendEnableIms(int slotId, int subId) { + Log.d(LOG_TAG, "sendEnableIms"); + try { + synchronized (mLock) { + if (isServiceControllerAvailable()) { + mIImsServiceController.enableIms(slotId, subId); + mLastImsOperationTimeMs = System.currentTimeMillis(); + } + } + } catch (RemoteException e) { + Log.w(LOG_TAG, "Couldn't enable IMS: " + e.getMessage()); + } + } + + private void sendDisableIms(int slotId, int subId) { + Log.d(LOG_TAG, "sendDisableIms"); + try { + synchronized (mLock) { + if (isServiceControllerAvailable()) { + mIImsServiceController.disableIms(slotId, subId); + mLastImsOperationTimeMs = System.currentTimeMillis(); + } + } + } catch (RemoteException e) { + Log.w(LOG_TAG, "Couldn't disable IMS: " + e.getMessage()); + } + } +} diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java index c3331d9c54..d455d60a90 100644 --- a/src/java/com/android/internal/telephony/ims/ImsResolver.java +++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java @@ -741,6 +741,15 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal (controller) -> controller.disableIms(slotId, getSubId(slotId))); } + /** + * Notify ImsService to disable IMS for the framework. + * And notify ImsService back to enable IMS for the framework. + */ + public void resetIms(int slotId) { + getImsServiceControllers(slotId).forEach( + (controller) -> controller.resetIms(slotId, getSubId(slotId))); + } + /** * Returns the ImsRegistration structure associated with the slotId and feature specified. */ diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceController.java b/src/java/com/android/internal/telephony/ims/ImsServiceController.java index 92e7d7117c..72cf472f8f 100644 --- a/src/java/com/android/internal/telephony/ims/ImsServiceController.java +++ b/src/java/com/android/internal/telephony/ims/ImsServiceController.java @@ -241,6 +241,7 @@ public class ImsServiceController { private Set mImsFeatures; private SparseIntArray mSlotIdToSubIdMap; private IImsServiceController mIImsServiceController; + private final ImsEnablementTracker mImsEnablementTracker; // The Capabilities bitmask of the connected ImsService (see ImsService#ImsServiceCapability). private long mServiceCapabilities; private ImsServiceConnection mImsServiceConnection; @@ -332,7 +333,7 @@ public class ImsServiceController { mPermissionManager = (LegacyPermissionManager) mContext.getSystemService( Context.LEGACY_PERMISSION_SERVICE); mRepo = repo; - + mImsEnablementTracker = new ImsEnablementTracker(mHandlerThread.getLooper()); mPackageManager = mContext.getPackageManager(); if (mPackageManager != null) { mChangedPackages = mPackageManager.getChangedPackages(mLastSequenceNumber); @@ -359,6 +360,7 @@ public class ImsServiceController { mRestartImsServiceRunnable); mPermissionManager = null; mRepo = repo; + mImsEnablementTracker = new ImsEnablementTracker(handler.getLooper()); } /** @@ -553,15 +555,7 @@ public class ImsServiceController { * trigger ImsFeature status updates. */ public void enableIms(int slotId, int subId) { - try { - synchronized (mLock) { - if (isServiceControllerAvailable()) { - mIImsServiceController.enableIms(slotId, subId); - } - } - } catch (RemoteException e) { - Log.w(LOG_TAG, "Couldn't enable IMS: " + e.getMessage()); - } + mImsEnablementTracker.enableIms(slotId, subId); } /** @@ -569,15 +563,15 @@ public class ImsServiceController { * trigger ImsFeature capability status to become false. */ public void disableIms(int slotId, int subId) { - try { - synchronized (mLock) { - if (isServiceControllerAvailable()) { - mIImsServiceController.disableIms(slotId, subId); - } - } - } catch (RemoteException e) { - Log.w(LOG_TAG, "Couldn't disable IMS: " + e.getMessage()); - } + mImsEnablementTracker.disableIms(slotId, subId); + } + + /** + * Notify ImsService to disable IMS for the framework. + * And notify ImsService back to enable IMS for the framework + */ + public void resetIms(int slotId, int subId) { + mImsEnablementTracker.resetIms(slotId, subId); } /** @@ -651,6 +645,7 @@ public class ImsServiceController { */ protected void setServiceController(IBinder serviceController) { mIImsServiceController = IImsServiceController.Stub.asInterface(serviceController); + mImsEnablementTracker.setServiceController(serviceController); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java new file mode 100644 index 0000000000..4d731b54eb --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2022 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.ims; + +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; +import android.telephony.ims.aidl.IImsServiceController; +import android.test.suitebuilder.annotation.SmallTest; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +/** + * Unit tests for ImsEnablementTracker + */ +@RunWith(AndroidJUnit4.class) +public class ImsEnablementTrackerTest extends ImsTestBase { + + private static final int SLOT_1 = 1; + private static final int SUB_1 = 11; + + private static final long TEST_REQUEST_THROTTLE_TIME_MS = 1000L; + // Mocked classes + @Mock + IImsServiceController mMockServiceControllerBinder; + + private TestableImsEnablementTracker mImsEnablementTracker; + private Handler mHandler; + + + private static class TestableImsEnablementTracker extends ImsEnablementTracker { + private long mLastImsOperationTimeMs = 0L; + TestableImsEnablementTracker(Looper looper, IImsServiceController controller) { + super(looper, controller); + } + + @Override + protected long getLastOperationTimeMillis() { + return mLastImsOperationTimeMs; + } + + private void setLastOperationTimeMillis(long timeMills) { + mLastImsOperationTimeMs = timeMills; + } + } + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + } + + @After + @Override + public void tearDown() throws Exception { + // Make sure the handler is empty before finishing the test. + waitForHandlerAction(mHandler, TEST_REQUEST_THROTTLE_TIME_MS); + mImsEnablementTracker = null; + super.tearDown(); + } + + @SmallTest + @Test + public void testEnableCommandInDefaultState() throws RemoteException { + // Verify that when the enable command is received in the Default state and enableIms + // is called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DEFAULT); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testDisableCommandInDefaultState() throws RemoteException { + // Verify that when the disable command is received in the Default state and disableIms + // is called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DEFAULT); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + } + + @SmallTest + @Test + public void testResetCommandInDefaultState() throws RemoteException { + // Verify that when reset command is received in the Default state, it should be ignored. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DEFAULT); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verifyZeroInteractions(mMockServiceControllerBinder); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DEFAULT)); + } + + @SmallTest + @Test + public void testEnableCommandInEnabledState() throws RemoteException { + // Verify that received the enable command is not handle in the Enabled state, + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLED); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), + mImsEnablementTracker.getRemainThrottleTime() + 100); + verify(mMockServiceControllerBinder, never()).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testDisableCommandInEnabledState() throws RemoteException { + // Verify that when the disable command is received in the Enabled state and disableIms + // is called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLED); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + } + + @SmallTest + @Test + public void testResetCommandInEnabledState() throws RemoteException { + // Verify that when the reset command is received in the Enabled state and disableIms + // and enableIms are called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLED); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); + // The disableIms was called. So set the last operation time to current. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + waitForHandlerActionDelayed(mHandler, TEST_REQUEST_THROTTLE_TIME_MS, + TEST_REQUEST_THROTTLE_TIME_MS + 100); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testDisableCommandInDisabledState() throws RemoteException { + // Verify that when disable command is received in the Disabled state, it should be ignored. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLED); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verifyZeroInteractions(mMockServiceControllerBinder); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + } + + @SmallTest + @Test + public void testEnableCommandInDisabledState() throws RemoteException { + // Verify that when the enable command is received in the Disabled state and enableIms + // is called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLED); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testEnableCommandWithoutTimeoutInDisableState() throws RemoteException { + // Verify that when the enable command is received in the Disabled state. After throttle + // time expired, the enableIms is called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLED); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + // Set the last operation time to current to verify the message with delay. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + + mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), + mImsEnablementTracker.getRemainThrottleTime() + 100); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testResetCommandInDisabledState() throws RemoteException { + // Verify that the reset command is received in the Disabled state and it`s not handled. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLED); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verifyZeroInteractions(mMockServiceControllerBinder); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + } + + @SmallTest + @Test + public void testEnableCommandInDisablingState() throws RemoteException { + // Verify that when enable command is received in the Disabling state, it should be ignored. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + // Set the last operation time to current so that the throttle time does not expire. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLING); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verifyZeroInteractions(mMockServiceControllerBinder); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testDisablingMessageInDisablingState() throws RemoteException { + // Verify that when the internal disable message is received in the Disabling state and + // disableIms is called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + // Set the last operation time to current to verify the message with delay. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLING); + + waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), + mImsEnablementTracker.getRemainThrottleTime() + 100); + verify(mMockServiceControllerBinder).disableIms(anyInt(), anyInt()); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + } + + @SmallTest + @Test + public void testResetCommandInDisablingState() throws RemoteException { + // Verify when the reset command is received in the Disabling state the disableIms and + // enableIms are called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + // Set the last operation time to current to verify the message with delay. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLING); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), + mImsEnablementTracker.getRemainThrottleTime() + 100); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); + // The disableIms was called. So set the last operation time to current. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), + mImsEnablementTracker.getRemainThrottleTime() + 100); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testEnablingMessageInEnablingState() throws RemoteException { + // Verify that when the internal enable message is received in the Enabling state and + // enableIms is called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLING); + + waitForHandlerActionDelayed(mHandler, 100, 150); + verify(mMockServiceControllerBinder).enableIms(anyInt(), anyInt()); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testDisableCommandInEnablingState() throws RemoteException { + // Verify that when the disable command is received in the Enabling state and + // clear pending message and disableIms is not called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + // Set the last operation time to current to verify the message with delay. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLING); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + } + + @SmallTest + @Test + public void testResetCommandWithEnablingState() throws RemoteException { + // Verify that when reset command is received in the Enabling state, it should be ignored. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + // Set the last operation time to current to verify the message with delay. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLING); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verifyZeroInteractions(mMockServiceControllerBinder); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLING)); + } + + @SmallTest + @Test + public void testEnableCommandInResettingState() throws RemoteException { + // Verify that when the enable command is received in the Resetting state and + // enableIms is not called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + // Set the last operation time to current to verify the message with delay. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_RESETTING); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verifyZeroInteractions(mMockServiceControllerBinder); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_RESETTING)); + } + + @SmallTest + @Test + public void testDisableCommandInResettingState() throws RemoteException { + // Verify that when the disable command is received in the Resetting state and + // disableIms is called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + // Set the last operation time to current to verify the message with delay. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_RESETTING); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), + mImsEnablementTracker.getRemainThrottleTime() + 100); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + } + + @SmallTest + @Test + public void testResettingMessageInResettingState() throws RemoteException { + // Verify that when the internal reset message is received in the Resetting state and + // disableIms and enableIms are called. + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_RESETTING); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + verify(mMockServiceControllerBinder).disableIms(anyInt(), anyInt()); + // Set the last operation time to current to verify the message with delay. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), + mImsEnablementTracker.getRemainThrottleTime() + 100); + verify(mMockServiceControllerBinder).enableIms(anyInt(), anyInt()); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testConsecutiveCommandInEnabledState() throws RemoteException { + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLED); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + + // Set the last operation time to current to verify the message with delay. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLING)); + + mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + + mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLING)); + mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), + mImsEnablementTracker.getRemainThrottleTime() + 100); + verify(mMockServiceControllerBinder, times(1)).disableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + } + + @SmallTest + @Test + public void testConsecutiveCommandInDisabledState() throws RemoteException { + mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mHandler = mImsEnablementTracker.getHandler(); + mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLED); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + // Set the last operation time to current to verify the message with delay. + mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLING)); + + mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + + mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + + mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + + mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), + mImsEnablementTracker.getRemainThrottleTime() + 100); + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + } + + private TestableImsEnablementTracker createTracker(IImsServiceController binder) { + TestableImsEnablementTracker tracker = new TestableImsEnablementTracker( + Looper.getMainLooper(), binder); + return tracker; + } +} -- GitLab From 3d527835dc69eb110efa6d09a8456c4ecd700918 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 7 Sep 2022 03:32:07 +0000 Subject: [PATCH 083/656] Fix the way to detect the Radio Aidl HAL version Test: manual Bug: 243344927 Change-Id: I00242aca87e3112946e4fe3ae8d7278b49767987 --- .../com/android/internal/telephony/RIL.java | 23 ++++++++------- .../internal/telephony/RadioDataProxy.java | 25 +++++++++++++++-- .../telephony/RadioMessagingProxy.java | 25 +++++++++++++++-- .../internal/telephony/RadioModemProxy.java | 25 +++++++++++++++-- .../internal/telephony/RadioNetworkProxy.java | 28 +++++++++++++++++-- .../internal/telephony/RadioSimProxy.java | 25 +++++++++++++++-- .../internal/telephony/RadioVoiceProxy.java | 26 +++++++++++++++-- 7 files changed, 153 insertions(+), 24 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 6de66527e1..caa887daad 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -159,6 +159,9 @@ public class RIL extends BaseCommands implements CommandsInterface { /** @hide */ public static final HalVersion RADIO_HAL_VERSION_2_0 = new HalVersion(2, 0); + /** @hide */ + public static final HalVersion RADIO_HAL_VERSION_2_1 = new HalVersion(2, 1); + // IRadio version private HalVersion mRadioVersion = RADIO_HAL_VERSION_UNKNOWN; @@ -768,8 +771,7 @@ public class RIL extends BaseCommands implements CommandsInterface { binder = mMockModem.getServiceBinder(DATA_SERVICE); } if (binder != null) { - mRadioVersion = RADIO_HAL_VERSION_2_0; - ((RadioDataProxy) serviceProxy).setAidl(mRadioVersion, + mRadioVersion = ((RadioDataProxy) serviceProxy).setAidl(mRadioVersion, android.hardware.radio.data.IRadioData.Stub.asInterface( binder)); } @@ -783,8 +785,8 @@ public class RIL extends BaseCommands implements CommandsInterface { binder = mMockModem.getServiceBinder(MESSAGING_SERVICE); } if (binder != null) { - mRadioVersion = RADIO_HAL_VERSION_2_0; - ((RadioMessagingProxy) serviceProxy).setAidl(mRadioVersion, + mRadioVersion = ((RadioMessagingProxy) serviceProxy).setAidl( + mRadioVersion, android.hardware.radio.messaging.IRadioMessaging.Stub .asInterface(binder)); } @@ -798,8 +800,7 @@ public class RIL extends BaseCommands implements CommandsInterface { binder = mMockModem.getServiceBinder(MODEM_SERVICE); } if (binder != null) { - mRadioVersion = RADIO_HAL_VERSION_2_0; - ((RadioModemProxy) serviceProxy).setAidl(mRadioVersion, + mRadioVersion = ((RadioModemProxy) serviceProxy).setAidl(mRadioVersion, android.hardware.radio.modem.IRadioModem.Stub .asInterface(binder)); } @@ -813,8 +814,8 @@ public class RIL extends BaseCommands implements CommandsInterface { binder = mMockModem.getServiceBinder(NETWORK_SERVICE); } if (binder != null) { - mRadioVersion = RADIO_HAL_VERSION_2_0; - ((RadioNetworkProxy) serviceProxy).setAidl(mRadioVersion, + mRadioVersion = ((RadioNetworkProxy) serviceProxy).setAidl( + mRadioVersion, android.hardware.radio.network.IRadioNetwork.Stub .asInterface(binder)); } @@ -828,8 +829,7 @@ public class RIL extends BaseCommands implements CommandsInterface { binder = mMockModem.getServiceBinder(SIM_SERVICE); } if (binder != null) { - mRadioVersion = RADIO_HAL_VERSION_2_0; - ((RadioSimProxy) serviceProxy).setAidl(mRadioVersion, + mRadioVersion = ((RadioSimProxy) serviceProxy).setAidl(mRadioVersion, android.hardware.radio.sim.IRadioSim.Stub .asInterface(binder)); } @@ -843,8 +843,7 @@ public class RIL extends BaseCommands implements CommandsInterface { binder = mMockModem.getServiceBinder(VOICE_SERVICE); } if (binder != null) { - mRadioVersion = RADIO_HAL_VERSION_2_0; - ((RadioVoiceProxy) serviceProxy).setAidl(mRadioVersion, + mRadioVersion = ((RadioVoiceProxy) serviceProxy).setAidl(mRadioVersion, android.hardware.radio.voice.IRadioVoice.Stub .asInterface(binder)); } diff --git a/src/java/com/android/internal/telephony/RadioDataProxy.java b/src/java/com/android/internal/telephony/RadioDataProxy.java index cbc762a59d..f1105458e1 100644 --- a/src/java/com/android/internal/telephony/RadioDataProxy.java +++ b/src/java/com/android/internal/telephony/RadioDataProxy.java @@ -45,12 +45,33 @@ public class RadioDataProxy extends RadioServiceProxy { * Set IRadioData as the AIDL implementation for RadioServiceProxy * @param halVersion Radio HAL version * @param data IRadioData implementation + * + * @return updated HAL version */ - public void setAidl(HalVersion halVersion, android.hardware.radio.data.IRadioData data) { + public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.data.IRadioData data) { mHalVersion = halVersion; mDataProxy = data; mIsAidl = true; - Rlog.d(TAG, "AIDL initialized"); + + try { + HalVersion newHalVersion; + int version = data.getInterfaceVersion(); + switch(version) { + default: + newHalVersion = RIL.RADIO_HAL_VERSION_2_0; + break; + } + Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); + + if (mHalVersion.less(newHalVersion)) { + mHalVersion = newHalVersion; + } + } catch (RemoteException e) { + Rlog.e(TAG, "setAidl: " + e); + } + + Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); + return mHalVersion; } /** diff --git a/src/java/com/android/internal/telephony/RadioMessagingProxy.java b/src/java/com/android/internal/telephony/RadioMessagingProxy.java index e68e957b7d..4e9bc8c073 100644 --- a/src/java/com/android/internal/telephony/RadioMessagingProxy.java +++ b/src/java/com/android/internal/telephony/RadioMessagingProxy.java @@ -36,13 +36,34 @@ public class RadioMessagingProxy extends RadioServiceProxy { * Set IRadioMessaging as the AIDL implementation for RadioServiceProxy * @param halVersion Radio HAL version * @param messaging IRadioMessaging implementation + * + * @return updated HAL version */ - public void setAidl(HalVersion halVersion, + public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.messaging.IRadioMessaging messaging) { mHalVersion = halVersion; mMessagingProxy = messaging; mIsAidl = true; - Rlog.d(TAG, "AIDL initialized"); + + try { + HalVersion newHalVersion; + int version = messaging.getInterfaceVersion(); + switch(version) { + default: + newHalVersion = RIL.RADIO_HAL_VERSION_2_0; + break; + } + Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); + + if (mHalVersion.less(newHalVersion)) { + mHalVersion = newHalVersion; + } + } catch (RemoteException e) { + Rlog.e(TAG, "setAidl: " + e); + } + + Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); + return mHalVersion; } /** diff --git a/src/java/com/android/internal/telephony/RadioModemProxy.java b/src/java/com/android/internal/telephony/RadioModemProxy.java index 7aaf727b3b..a9558a509a 100644 --- a/src/java/com/android/internal/telephony/RadioModemProxy.java +++ b/src/java/com/android/internal/telephony/RadioModemProxy.java @@ -31,13 +31,34 @@ public class RadioModemProxy extends RadioServiceProxy { * Set IRadioModem as the AIDL implementation for RadioServiceProxy * @param halVersion Radio HAL version * @param modem IRadioModem implementation + * + * @return updated HAL version */ - public void setAidl(HalVersion halVersion, + public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.modem.IRadioModem modem) { mHalVersion = halVersion; mModemProxy = modem; mIsAidl = true; - Rlog.d(TAG, "AIDL initialized"); + + try { + HalVersion newHalVersion; + int version = modem.getInterfaceVersion(); + switch(version) { + default: + newHalVersion = RIL.RADIO_HAL_VERSION_2_0; + break; + } + Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); + + if (mHalVersion.less(newHalVersion)) { + mHalVersion = newHalVersion; + } + } catch (RemoteException e) { + Rlog.e(TAG, "setAidl: " + e); + } + + Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); + return mHalVersion; } /** diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java index b88103510a..31a8691b4f 100644 --- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java +++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java @@ -65,13 +65,37 @@ public class RadioNetworkProxy extends RadioServiceProxy { * Set IRadioNetwork as the AIDL implementation for RadioServiceProxy * @param halVersion Radio HAL version * @param network IRadioNetwork implementation + * + * @return updated HAL version */ - public void setAidl(HalVersion halVersion, + public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.network.IRadioNetwork network) { mHalVersion = halVersion; mNetworkProxy = network; mIsAidl = true; - Rlog.d(TAG, "AIDL initialized"); + + try { + HalVersion newHalVersion; + int version = network.getInterfaceVersion(); + switch(version) { + case 2: + newHalVersion = RIL.RADIO_HAL_VERSION_2_1; + break; + default: + newHalVersion = RIL.RADIO_HAL_VERSION_2_0; + break; + } + Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); + + if (mHalVersion.less(newHalVersion)) { + mHalVersion = newHalVersion; + } + } catch (RemoteException e) { + Rlog.e(TAG, "setAidl: " + e); + } + + Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); + return mHalVersion; } /** diff --git a/src/java/com/android/internal/telephony/RadioSimProxy.java b/src/java/com/android/internal/telephony/RadioSimProxy.java index c7e19c4f32..9e6728a211 100644 --- a/src/java/com/android/internal/telephony/RadioSimProxy.java +++ b/src/java/com/android/internal/telephony/RadioSimProxy.java @@ -41,12 +41,33 @@ public class RadioSimProxy extends RadioServiceProxy { * Set IRadioSim as the AIDL implementation for RadioServiceProxy * @param halVersion Radio HAL version * @param sim IRadioSim implementation + * + * @return updated HAL version */ - public void setAidl(HalVersion halVersion, android.hardware.radio.sim.IRadioSim sim) { + public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.sim.IRadioSim sim) { mHalVersion = halVersion; mSimProxy = sim; mIsAidl = true; - Rlog.d(TAG, "AIDL initialized"); + + try { + HalVersion newHalVersion; + int version = sim.getInterfaceVersion(); + switch(version) { + default: + newHalVersion = RIL.RADIO_HAL_VERSION_2_0; + break; + } + Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); + + if (mHalVersion.less(newHalVersion)) { + mHalVersion = newHalVersion; + } + } catch (RemoteException e) { + Rlog.e(TAG, "setAidl: " + e); + } + + Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); + return mHalVersion; } /** diff --git a/src/java/com/android/internal/telephony/RadioVoiceProxy.java b/src/java/com/android/internal/telephony/RadioVoiceProxy.java index 6ac603ba90..07afaad30e 100644 --- a/src/java/com/android/internal/telephony/RadioVoiceProxy.java +++ b/src/java/com/android/internal/telephony/RadioVoiceProxy.java @@ -35,12 +35,34 @@ public class RadioVoiceProxy extends RadioServiceProxy { * Set IRadioVoice as the AIDL implementation for RadioServiceProxy * @param halVersion Radio HAL version * @param voice IRadioVoice implementation + * + * @return updated HAL version */ - public void setAidl(HalVersion halVersion, android.hardware.radio.voice.IRadioVoice voice) { + public HalVersion setAidl(HalVersion halVersion, + android.hardware.radio.voice.IRadioVoice voice) { mHalVersion = halVersion; mVoiceProxy = voice; mIsAidl = true; - Rlog.d(TAG, "AIDL initialized"); + + try { + HalVersion newHalVersion; + int version = voice.getInterfaceVersion(); + switch(version) { + default: + newHalVersion = RIL.RADIO_HAL_VERSION_2_0; + break; + } + Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); + + if (mHalVersion.less(newHalVersion)) { + mHalVersion = newHalVersion; + } + } catch (RemoteException e) { + Rlog.e(TAG, "setAidl: " + e); + } + + Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); + return mHalVersion; } /** -- GitLab From 5e77304f504ab11e72480c8231a592cdb6f78eca Mon Sep 17 00:00:00 2001 From: Rambo Wang Date: Tue, 17 May 2022 14:22:42 +0000 Subject: [PATCH 084/656] Turn off carrier privileges grace period feature Carrier privileges grace period feature was introduced in T to benefit the switching between the same carrier. On the cases when switching to different carriers, the feature introduce a small time window to allow the previous carrier app to have carrier privileges on upcoming carrier. This has security concern. In bug 229418673, Tycho can set a non-Fi pSIM subscription as the Fi's secondary sub in a sub group, causing confusing behavior for the end user. The feature is turn off by default. When a solution that can fix the security concern has been found, it will be turn on. Bug: 229418673 Test: atest CarrierPrivilegesTrackerTest Test: QA test on SS -> DS switching Test: Telephony sanity(activation, calling, sms, data, switching...) Merged-In: Ib98a6a97cc590a866a50029237da80634cec2ce3 Change-Id: Ib98a6a97cc590a866a50029237da80634cec2ce3 (cherry picked from commit ad8a33249dd7b565efab3f716d5e29f4a55de577) --- .../internal/telephony/CarrierPrivilegesTracker.java | 5 ++++- .../telephony/CarrierPrivilegesTrackerTest.java | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index b91e6bfb3f..31442297b1 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -108,11 +108,14 @@ public class CarrierPrivilegesTracker extends Handler { private static final String SHA_1 = "SHA-1"; private static final String SHA_256 = "SHA-256"; + // TODO(b/232273884): Turn feature on when find solution to handle the inter-carriers switching /** * Time delay to clear UICC rules after UICC is gone. * This introduces the grace period to retain carrier privileges when SIM is removed. + * + * This feature is off by default due to the security concern during inter-carriers switching. */ - private static final long CLEAR_UICC_RULES_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(30); + private static final long CLEAR_UICC_RULES_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(0); /** * PackageManager flags used to query installed packages. diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java index 92faabd1d8..221b2b525e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java @@ -73,6 +73,7 @@ import com.android.internal.telephony.uicc.IccUtils; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; @@ -549,7 +550,8 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } - @Test + // TODO(b/232273884): turn UT case on when grace period is on + @Ignore public void testSimStateChangedSimStateNotReady() throws Exception { // Start with privileges, verify clearing certs clears UIDs setupCarrierPrivilegesTrackerWithSimLoadedUids(); @@ -573,7 +575,8 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { new Pair<>(Set.of(), Set.of()))); } - @Test + // TODO(b/232273884): turn UT case on when grace period is on + @Ignore public void testSimStateChangedSimStateAbsentThenLoadedWithSameRules() throws Exception { // Start with privileges setupCarrierPrivilegesTrackerWithSimLoadedUids(); @@ -642,7 +645,8 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { List.of(new Pair<>(Set.of(), Set.of()))); } - @Test + // TODO(b/232273884): turn UT case on when grace period is on + @Ignore public void testSimStateChangedSimStateAbsentThenLoadedWithUpdatedRules() throws Exception { // Start with privileges setupCarrierPrivilegesTrackerWithSimLoadedUids(); -- GitLab From f7f4b9498bdd2be370375680ec1bfc2489cad18a Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Tue, 13 Sep 2022 04:12:43 +0000 Subject: [PATCH 085/656] Log caller when sending SMS Bug: 245672677 Test: manual - 09-12 21:04:09.078 D SmsController: sendTextForSubscriber caller=com.google.android.apps.messaging Change-Id: I4fbf28783712708d14d2d629229936ded65199a1 --- .../internal/telephony/SmsController.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 774d549058..511ea7a76a 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -154,6 +154,7 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } + Rlog.d(LOG_TAG, "sendDataForSubscriber caller=" + callingPackage); // Perform FDN check if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { @@ -199,6 +200,8 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } + Rlog.d(LOG_TAG, "sendTextForSubscriber caller=" + callingPackage); + if (!getSmsPermissions(subId).checkCallingCanSendText(persistMessageForNonDefaultSmsApp, callingPackage, callingAttributionTag, "Sending SMS message")) { sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_GENERIC_FAILURE); @@ -277,6 +280,7 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } + Rlog.d(LOG_TAG, "sendTextForSubscriberWithOptions caller=" + callingPackage); // Perform FDN check if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { @@ -306,6 +310,7 @@ public class SmsController extends ISmsImplBase { if (getCallingPackage() != null) { callingPackage = getCallingPackage(); } + Rlog.d(LOG_TAG, "sendMultipartTextForSubscriber caller=" + callingPackage); // Perform FDN check if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { @@ -333,6 +338,7 @@ public class SmsController extends ISmsImplBase { if (callingPackage == null) { callingPackage = getCallingPackage(); } + Rlog.d(LOG_TAG, "sendMultipartTextForSubscriberWithOptions caller=" + callingPackage); // Perform FDN check if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { @@ -448,7 +454,7 @@ public class SmsController extends ISmsImplBase { // Don't show the SMS SIM Pick activity if it is not foreground. boolean isCallingProcessForeground = am != null && am.getUidImportance(Binder.getCallingUid()) - == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; + == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; if (!isCallingProcessForeground) { Rlog.d(LOG_TAG, "isSmsSimPickActivityNeeded: calling process not foreground. " + "Suppressing activity."); @@ -558,6 +564,8 @@ public class SmsController extends ISmsImplBase { throw new SecurityException("sendStoredText: Package " + callingPkg + "does not belong to " + Binder.getCallingUid()); } + Rlog.d(LOG_TAG, "sendStoredText caller=" + callingPkg); + if (iccSmsIntMgr != null) { iccSmsIntMgr.sendStoredText(callingPkg, callingAttributionTag, messageUri, scAddress, sentIntent, deliveryIntent); @@ -576,6 +584,8 @@ public class SmsController extends ISmsImplBase { throw new SecurityException("sendStoredMultipartText: Package " + callingPkg + " does not belong to " + Binder.getCallingUid()); } + Rlog.d(LOG_TAG, "sendStoredMultipartText caller=" + callingPkg); + if (iccSmsIntMgr != null) { iccSmsIntMgr.sendStoredMultipartText(callingPkg, callingAttributionTag, messageUri, scAddress, sentIntents, deliveryIntents); @@ -753,10 +763,12 @@ public class SmsController extends ISmsImplBase { public void sendVisualVoicemailSmsForSubscriber(String callingPackage, String callingAttributionTag, int subId, String number, int port, String text, PendingIntent sentIntent) { + Rlog.d(LOG_TAG, "sendVisualVoicemailSmsForSubscriber caller=" + callingPackage); + // Do not send non-emergency SMS in ECBM as it forces device to exit ECBM. if(getPhone(subId).isInEcm()) { Rlog.d(LOG_TAG, "sendVisualVoicemailSmsForSubscriber: Do not send non-emergency " - + "SMS in ECBM as it forces device to exit ECBM."); + + "SMS in ECBM as it forces device to exit ECBM."); return; } @@ -940,7 +952,7 @@ public class SmsController extends ISmsImplBase { } } else { Rlog.e(LOG_TAG, "getSmscAddressFromIccEfForSubscriber iccSmsIntMgr is null" - + " for Subscription: " + subId); + + " for Subscription: " + subId); return true; } -- GitLab From 834e38f45727444ee437714114a62472812370a8 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 30 Aug 2022 18:05:01 -0700 Subject: [PATCH 086/656] Don't add default IMS data profile before SIM loaded Originally, before SIM loaded, or before TelephonyProvider database finds any APN settings, default IMS data profile is added. However, the default IMS data profile is prepared for the case where a SIM/carrier didn't specify IMS. The fix is to add the default IMS profile only when the detabase loaded some data profile; otherwise, it means the SIM hasn't been read properly, in that case we do nothing but wait for SIM to be read. Bug: 241121008 Test: atest Change-Id: Ifbad8359db98dadabc754514f6f8038b1415200f --- .../telephony/data/DataProfileManager.java | 34 +++++++++++-------- .../data/DataProfileManagerTest.java | 4 ++- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java index 2ee325864b..28c321ce10 100644 --- a/src/java/com/android/internal/telephony/data/DataProfileManager.java +++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java @@ -285,9 +285,27 @@ public class DataProfileManager extends Handler { } } + DataProfile dataProfile; + + if (!profiles.isEmpty()) { // APN database has been read successfully after SIM loaded + // Check if any of the profile already supports IMS, if not, add the default one. + dataProfile = profiles.stream() + .filter(dp -> dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) + .findFirst() + .orElse(null); + if (dataProfile == null) { + profiles.add(new DataProfile.Builder() + .setApnSetting(buildDefaultApnSetting("DEFAULT IMS", "ims", + ApnSetting.TYPE_IMS)) + .setTrafficDescriptor(new TrafficDescriptor("ims", null)) + .build()); + log("Added default IMS data profile."); + } + } + // Check if any of the profile already supports ENTERPRISE, if not, check if DPC has // configured one and retrieve the same. - DataProfile dataProfile = profiles.stream() + dataProfile = profiles.stream() .filter(dp -> dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)) .findFirst() .orElse(null); @@ -299,20 +317,6 @@ public class DataProfileManager extends Handler { } } - // Check if any of the profile already supports IMS, if not, add the default one. - dataProfile = profiles.stream() - .filter(dp -> dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_IMS)) - .findFirst() - .orElse(null); - if (dataProfile == null) { - profiles.add(new DataProfile.Builder() - .setApnSetting(buildDefaultApnSetting("DEFAULT IMS", "ims", - ApnSetting.TYPE_IMS)) - .setTrafficDescriptor(new TrafficDescriptor("ims", null)) - .build()); - log("Added default IMS data profile."); - } - // Check if any of the profile already supports EIMS, if not, add the default one. dataProfile = profiles.stream() .filter(dp -> dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_EIMS)) 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 7c7befaa6a..81a4f1c853 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java @@ -718,6 +718,7 @@ public class DataProfileManagerTest extends TelephonyTest { tnr, TelephonyManager.NETWORK_TYPE_LTE); assertThat(dataProfile).isNull(); + // expect default EIMS when SIM absent tnr = new TelephonyNetworkRequest( new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS) @@ -726,13 +727,14 @@ public class DataProfileManagerTest extends TelephonyTest { tnr, TelephonyManager.NETWORK_TYPE_LTE); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos"); + // expect no default IMS when SIM absent tnr = new TelephonyNetworkRequest( new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) .build(), mPhone); dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( tnr, TelephonyManager.NETWORK_TYPE_LTE); - assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("ims"); + assertThat(dataProfile).isEqualTo(null); } @Test -- GitLab From f580de16051ba5952fe46ebc156bfbd4bdf4a3ee Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Wed, 14 Sep 2022 13:24:38 -0700 Subject: [PATCH 087/656] Enabling debug logs for the state change of Euicc Connector. This will help to analyse this bug b239277548. Test: build Bug: 239277548 Change-Id: I9258648cb12f3afc2d1951a9daac0d2e17748083 --- .../com/android/internal/telephony/euicc/EuiccConnector.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/java/com/android/internal/telephony/euicc/EuiccConnector.java b/src/java/com/android/internal/telephony/euicc/EuiccConnector.java index 974acf9a63..96a9328bce 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccConnector.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccConnector.java @@ -389,6 +389,9 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { mSm = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); + // TODO(b/239277548): Disable debug logging after analysing this bug. + setDbg(true); + // Unavailable/Available both monitor for package changes and update mSelectedComponent but // do not need to adjust the binding. mUnavailableState = new UnavailableState(); -- GitLab From 970b2836c96ff5ec15deb07437b2f02531e23c4b Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 31 Jul 2022 00:44:26 -0700 Subject: [PATCH 088/656] Removed old data stack Completely removed the old telephony data. Fix: 201830726 Test: Manual Change-Id: I2845a04bf9f1dd74f574c14bc951467235d1512a --- .../telephony/GsmCdmaCallTracker.java | 11 - .../internal/telephony/GsmCdmaPhone.java | 199 +- .../telephony/MultiSimSettingController.java | 27 +- .../telephony/NetworkTypeController.java | 108 +- .../com/android/internal/telephony/Phone.java | 153 +- .../internal/telephony/ProxyController.java | 29 - .../internal/telephony/RetryManager.java | 723 --- .../telephony/ServiceStateTracker.java | 230 +- .../telephony/TelephonyComponentFactory.java | 16 - .../telephony/data/AccessNetworksManager.java | 194 +- .../telephony/data/DataConfigManager.java | 12 +- .../data/LinkBandwidthEstimator.java | 33 - .../data/NotifyQosSessionInterface.java | 54 - .../telephony/data/PhoneSwitcher.java | 179 +- .../telephony/data/QosCallbackTracker.java | 72 +- .../telephony/data/TelephonyNetworkAgent.java | 36 +- .../data/TelephonyNetworkFactory.java | 253 +- .../data/TelephonyNetworkRequest.java | 14 +- .../dataconnection/ApnConfigType.java | 50 - .../ApnConfigTypeRepository.java | 128 - .../telephony/dataconnection/ApnContext.java | 675 -- .../dataconnection/ApnSettingUtils.java | 129 - .../dataconnection/DataConnection.java | 4094 ------------ .../dataconnection/DataConnectionReasons.java | 176 - .../dataconnection/DataEnabledSettings.java | 566 -- .../dataconnection/DataServiceManager.java | 978 --- .../dataconnection/DataThrottler.java | 366 -- .../dataconnection/DcController.java | 487 -- .../dataconnection/DcFailBringUp.java | 85 - .../dataconnection/DcNetworkAgent.java | 617 -- .../telephony/dataconnection/DcRequest.java | 102 - .../dataconnection/DcTesterDeactivateAll.java | 95 - .../DcTesterFailBringUpAll.java | 110 - .../telephony/dataconnection/DcTracker.java | 5665 ----------------- .../telephony/dataconnection/README.txt | 71 - .../dataconnection/TransportManager.java | 279 - .../telephony/imsphone/ImsPhoneBase.java | 10 - .../imsphone/ImsPhoneCallTracker.java | 74 +- .../metrics/DataStallRecoveryStats.java | 37 - .../telephony/metrics/MetricsCollector.java | 3 +- .../MultiSimSettingControllerTest.java | 98 +- .../telephony/NetworkTypeControllerTest.java | 106 +- .../telephony/SMSDispatcherTest.java.broken | 107 - .../telephony/ServiceStateTrackerTest.java | 53 - .../internal/telephony/TelephonyTest.java | 23 - .../telephony/TestPhoneNotifier.java.broken | 69 - .../ApnSettingTest.java | 214 +- .../telephony/data/DataCallResponseTest.java | 17 +- .../telephony/data/DataNetworkTest.java | 2 - .../data/LinkBandwidthEstimatorTest.java | 23 +- .../telephony/data/PhoneSwitcherTest.java | 22 +- .../data/QosCallbackTrackerTest.java | 104 +- .../data/TelephonyNetworkFactoryTest.java | 94 +- .../ApnConfigTypeRepositoryTest.java | 109 - .../dataconnection/ApnContextTest.java | 240 - .../dataconnection/DataConnectionTest.java | 1479 ----- .../DataEnabledSettingsTest.java | 147 - .../dataconnection/DataThrottlerTest.java | 222 - .../dataconnection/DcControllerTest.java | 272 - .../dataconnection/DcNetworkAgentTest.java | 118 - .../dataconnection/DcRequestTest.java | 125 - .../dataconnection/DcTrackerTest.java | 2983 --------- .../dataconnection/RetryManagerTest.java | 996 --- .../telephony/gsm/GSMPhoneTest.java.broken | 1935 ------ .../telephony/gsm/GSMTestHandler.java.broken | 118 - .../gsm/UsimDataDownloadCommands.java.broken | 694 -- .../gsm/UsimDataDownloadTest.java.broken | 144 - .../metrics/TelephonyMetricsTest.java | 10 +- tools/tdi | 48 - 69 files changed, 414 insertions(+), 27298 deletions(-) delete mode 100644 src/java/com/android/internal/telephony/RetryManager.java delete mode 100644 src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnContext.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DataConnection.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DataThrottler.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcController.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcRequest.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java delete mode 100755 src/java/com/android/internal/telephony/dataconnection/DcTracker.java delete mode 100644 src/java/com/android/internal/telephony/dataconnection/README.txt delete mode 100644 src/java/com/android/internal/telephony/dataconnection/TransportManager.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken rename tests/telephonytests/src/com/android/internal/telephony/{dataconnection => data}/ApnSettingTest.java (62%) delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken delete mode 100755 tools/tdi diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java index 07be4e51fb..263bfebc15 100755 --- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java +++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java @@ -182,11 +182,6 @@ public class GsmCdmaCallTracker extends CallTracker { mCi.unregisterForCallWaitingInfo(this); // Prior to phone switch to GSM, if CDMA has any emergency call // data will be in disabled state, after switching to GSM enable data. - if (mIsInEmergencyCall) { - if (!mPhone.isUsingNewDataStack()) { - mPhone.getDataEnabledSettings().setInternalDataEnabled(true); - } - } } else { mConnections = new GsmCdmaConnection[MAX_CONNECTIONS_CDMA]; mPendingCallInEcm = false; @@ -400,9 +395,6 @@ public class GsmCdmaCallTracker extends CallTracker { //CDMA public void setIsInEmergencyCall() { mIsInEmergencyCall = true; - if (!mPhone.isUsingNewDataStack()) { - mPhone.getDataEnabledSettings().setInternalDataEnabled(false); - } mPhone.notifyEmergencyCallRegistrants(true); mPhone.sendEmergencyCallStateChange(true); } @@ -1759,9 +1751,6 @@ public class GsmCdmaCallTracker extends CallTracker { } if (!inEcm) { // Re-initiate data connection - if (!mPhone.isUsingNewDataStack()) { - mPhone.getDataEnabledSettings().setInternalDataEnabled(true); - } mPhone.notifyEmergencyCallRegistrants(false); } mPhone.sendEmergencyCallStateChange(false); diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 3b18e4f89d..97c857f787 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -67,7 +67,6 @@ import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telecom.VideoProfile; -import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.DataActivityType; import android.telephony.Annotation.RadioPowerState; import android.telephony.BarringInfo; @@ -85,7 +84,6 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.UiccAccessRule; import android.telephony.UssdResponse; -import android.telephony.data.ApnSetting; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -97,9 +95,6 @@ import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.LinkBandwidthEstimator; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; -import com.android.internal.telephony.dataconnection.DcTracker; -import com.android.internal.telephony.dataconnection.TransportManager; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.gsm.GsmMmiCode; import com.android.internal.telephony.gsm.SsData; @@ -278,8 +273,6 @@ public class GsmCdmaPhone extends Phone { private CarrierKeyDownloadManager mCDM; private CarrierInfoManager mCIM; - private final SettingsObserver mSettingsObserver; - private final ImsManagerFactory mImsManagerFactory; private final CarrierPrivilegesTracker mCarrierPrivilegesTracker; @@ -324,10 +317,6 @@ public class GsmCdmaPhone extends Phone { mAccessNetworksManager = mTelephonyComponentFactory .inject(AccessNetworksManager.class.getName()) .makeAccessNetworksManager(this, getLooper()); - if (!isUsingNewDataStack()) { - mTransportManager = mTelephonyComponentFactory.inject(TransportManager.class.getName()) - .makeTransportManager(this); - } // SST/DSM depends on SSC, so SSC is instanced before SST/DSM mSignalStrengthController = mTelephonyComponentFactory.inject( SignalStrengthController.class.getName()).makeSignalStrengthController(this); @@ -336,10 +325,6 @@ public class GsmCdmaPhone extends Phone { mEmergencyNumberTracker = mTelephonyComponentFactory .inject(EmergencyNumberTracker.class.getName()).makeEmergencyNumberTracker( this, this.mCi); - if (!isUsingNewDataStack()) { - mDataEnabledSettings = mTelephonyComponentFactory - .inject(DataEnabledSettings.class.getName()).makeDataEnabledSettings(this); - } mDeviceStateMonitor = mTelephonyComponentFactory.inject(DeviceStateMonitor.class.getName()) .makeDeviceStateMonitor(this); @@ -348,20 +333,9 @@ public class GsmCdmaPhone extends Phone { mDisplayInfoController = mTelephonyComponentFactory.inject( DisplayInfoController.class.getName()).makeDisplayInfoController(this); - if (isUsingNewDataStack()) { - mDataNetworkController = mTelephonyComponentFactory.inject( - DataNetworkController.class.getName()) - .makeDataNetworkController(this, getLooper()); - } else { - // DcTracker uses ServiceStateTracker and DisplayInfoController so needs to be created - // after they are instantiated - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - DcTracker dcTracker = mTelephonyComponentFactory.inject(DcTracker.class.getName()) - .makeDcTracker(this, transport); - mDcTrackers.put(transport, dcTracker); - mAccessNetworksManager.registerDataThrottler(dcTracker.getDataThrottler()); - } - } + mDataNetworkController = mTelephonyComponentFactory.inject( + DataNetworkController.class.getName()) + .makeDataNetworkController(this, getLooper()); mCarrierResolver = mTelephonyComponentFactory.inject(CarrierResolver.class.getName()) .makeCarrierResolver(this); @@ -374,15 +348,6 @@ public class GsmCdmaPhone extends Phone { mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, null); - // TODO: Remove SettingsObserver and provisioning events when DataEnabledSettings is removed - mSettingsObserver = new SettingsObserver(context, this); - mSettingsObserver.observe( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), - EVENT_DEVICE_PROVISIONED_CHANGE); - mSettingsObserver.observe( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED), - EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE); - SubscriptionController.getInstance().registerForUiccAppsEnabled(this, EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false); @@ -691,11 +656,6 @@ public class GsmCdmaPhone extends Phone { return mCT; } - @Override - public TransportManager getTransportManager() { - return mTransportManager; - } - @Override public AccessNetworksManager getAccessNetworksManager() { return mAccessNetworksManager; @@ -747,84 +707,9 @@ public class GsmCdmaPhone extends Phone { return mCT.mState != PhoneConstants.State.IDLE && !mSST.isConcurrentVoiceAndDataAllowed(); } - @Override - public PhoneConstants.DataState getDataConnectionState(String apnType) { - PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED; - - if (mSST == null) { - // Radio Technology Change is ongoing, dispose() and removeReferences() have - // already been called - - ret = PhoneConstants.DataState.DISCONNECTED; - } else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE - && (isPhoneTypeCdma() || isPhoneTypeCdmaLte() || - (isPhoneTypeGsm() && !apnType.equals(ApnSetting.TYPE_EMERGENCY_STRING)))) { - // If we're out of service, open TCP sockets may still work - // but no data will flow - - // Emergency APN is available even in Out Of Service - // Pass the actual State of EPDN - - ret = PhoneConstants.DataState.DISCONNECTED; - } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */ - int currentTransport = mAccessNetworksManager.getCurrentTransport( - ApnSetting.getApnTypesBitmaskFromString(apnType)); - if (getDcTracker(currentTransport) != null) { - switch (getDcTracker(currentTransport).getState(apnType)) { - case CONNECTED: - case DISCONNECTING: - if (isDataSuspended()) { - ret = PhoneConstants.DataState.SUSPENDED; - } else { - ret = PhoneConstants.DataState.CONNECTED; - } - break; - case CONNECTING: - ret = PhoneConstants.DataState.CONNECTING; - break; - default: - ret = PhoneConstants.DataState.DISCONNECTED; - } - } - } - - logd("getDataConnectionState apnType=" + apnType + " ret=" + ret); - return ret; - } - @Override public @DataActivityType int getDataActivityState() { - if (isUsingNewDataStack()) { - return getDataNetworkController().getDataActivity(); - } - int ret = TelephonyManager.DATA_ACTIVITY_NONE; - - if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE - && getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { - switch (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getActivity()) { - case DATAIN: - ret = TelephonyManager.DATA_ACTIVITY_IN; - break; - - case DATAOUT: - ret = TelephonyManager.DATA_ACTIVITY_OUT; - break; - - case DATAINANDOUT: - ret = TelephonyManager.DATA_ACTIVITY_INOUT; - break; - - case DORMANT: - ret = TelephonyManager.DATA_ACTIVITY_DORMANT; - break; - - default: - ret = TelephonyManager.DATA_ACTIVITY_NONE; - break; - } - } - - return ret; + return getDataNetworkController().getDataActivity(); } /** @@ -2973,25 +2858,12 @@ public class GsmCdmaPhone extends Phone { @Override public boolean getDataRoamingEnabled() { - if (isUsingNewDataStack()) { - return getDataSettingsManager().isDataRoamingEnabled(); - } - if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { - return getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).getDataRoamingEnabled(); - } - return false; + return getDataSettingsManager().isDataRoamingEnabled(); } @Override public void setDataRoamingEnabled(boolean enable) { - if (isUsingNewDataStack()) { - getDataSettingsManager().setDataRoamingEnabled(enable); - return; - } - if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { - getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setDataRoamingEnabledByUser(enable); - } + getDataSettingsManager().setDataRoamingEnabled(enable); } @Override @@ -3036,21 +2908,12 @@ public class GsmCdmaPhone extends Phone { } /** - * Whether data is enabled by user. Unlike isDataEnabled, this only - * checks user setting stored in {@link android.provider.Settings.Global#MOBILE_DATA} - * if not provisioning, or isProvisioningDataEnabled if provisioning. + * Whether data is enabled by user. */ @Override public boolean isUserDataEnabled() { - if (isUsingNewDataStack()) { - return getDataSettingsManager().isDataEnabledForReason( - TelephonyManager.DATA_ENABLED_REASON_USER); - } - if (mDataEnabledSettings.isProvisioning()) { - return mDataEnabledSettings.isProvisioningDataEnabled(); - } else { - return mDataEnabledSettings.isUserDataEnabled(); - } + return getDataSettingsManager().isDataEnabledForReason( + TelephonyManager.DATA_ENABLED_REASON_USER); } /** @@ -3585,24 +3448,9 @@ public class GsmCdmaPhone extends Phone { case EVENT_SET_CARRIER_DATA_ENABLED: ar = (AsyncResult) msg.obj; boolean enabled = (boolean) ar.result; - if (isUsingNewDataStack()) { - getDataSettingsManager().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_CARRIER, enabled, - mContext.getOpPackageName()); - return; - } - mDataEnabledSettings.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_CARRIER, - enabled); - break; - case EVENT_DEVICE_PROVISIONED_CHANGE: - if (!isUsingNewDataStack()) { - mDataEnabledSettings.updateProvisionedChanged(); - } - break; - case EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE: - if (!isUsingNewDataStack()) { - mDataEnabledSettings.updateProvisioningDataEnabled(); - } + getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_CARRIER, enabled, + mContext.getOpPackageName()); break; case EVENT_GET_AVAILABLE_NETWORKS_DONE: ar = (AsyncResult) msg.obj; @@ -4097,10 +3945,6 @@ public class GsmCdmaPhone extends Phone { // send an Intent sendEmergencyCallbackModeChange(); - // Re-initiate data connection - if (!isUsingNewDataStack()) { - mDataEnabledSettings.setInternalDataEnabled(true); - } notifyEmergencyCallRegistrants(false); } mIsTestingEmergencyCallbackMode = false; @@ -5056,24 +4900,7 @@ public class GsmCdmaPhone extends Phone { * @return Currently bound data service package names. */ public @NonNull List getDataServicePackages() { - if (isUsingNewDataStack()) { - return getDataNetworkController().getDataServicePackages(); - } - List packages = new ArrayList<>(); - int[] transports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; - - for (int transport : transports) { - DcTracker dct = getDcTracker(transport); - if (dct != null) { - String pkg = dct.getDataServiceManager().getDataServicePackageName(); - if (!TextUtils.isEmpty(pkg)) { - packages.add(pkg); - } - } - } - - return packages; + return getDataNetworkController().getDataServicePackages(); } private void updateBroadcastEmergencyCallStateChangesAfterCarrierConfigChanged( diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index 85053de899..f3b91dfb86 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -850,14 +850,9 @@ public class MultiSimSettingController extends Handler { && phone.isUserDataEnabled() && !areSubscriptionsInSameGroup(defaultDataSub, phone.getSubId())) { log("setting data to false on " + phone.getSubId()); - if (phone.isUsingNewDataStack()) { - phone.getDataSettingsManager().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false, - mContext.getOpPackageName()); - } else { - phone.getDataEnabledSettings().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); - } + phone.getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, + mContext.getOpPackageName()); } } } @@ -893,13 +888,9 @@ public class MultiSimSettingController extends Handler { // If enable is true and it's not opportunistic subscription, we don't enable it, // as there can't be two if (phone != null) { - if (phone.isUsingNewDataStack()) { - phone.getDataSettingsManager().setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, enable, - mContext.getOpPackageName()); - } else { - phone.getDataEnabledSettings().setUserDataEnabled(enable, false); - } + phone.getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, enable, + mContext.getOpPackageName()); } } else { // For inactive subscription, directly write into global settings. @@ -1074,10 +1065,8 @@ public class MultiSimSettingController extends Handler { // existing phone instance. Phone[] phones = PhoneFactory.getPhones(); for (int i = mCallbacksCount; i < phones.length; i++) { - if (phones[i].isUsingNewDataStack()) { - phones[i].getDataSettingsManager().registerCallback( - new DataSettingsControllerCallback(phones[i], this::post)); - } + phones[i].getDataSettingsManager().registerCallback( + new DataSettingsControllerCallback(phones[i], this::post)); } mCallbacksCount = phones.length; } diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 2260d3456a..9cb21945de 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -28,20 +29,16 @@ import android.telephony.AccessNetworkConstants; import android.telephony.Annotation; import android.telephony.CarrierConfigManager; import android.telephony.NetworkRegistrationInfo; -import android.telephony.PcoData; import android.telephony.PhysicalChannelConfig; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataCallResponse.LinkStatus; import android.text.TextUtils; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; -import com.android.internal.telephony.dataconnection.DataConnection; -import com.android.internal.telephony.dataconnection.DcTracker; import com.android.internal.telephony.util.ArrayUtils; import com.android.internal.util.IState; import com.android.internal.util.IndentingPrintWriter; @@ -99,7 +96,6 @@ public class NetworkTypeController extends StateMachine { private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11; private static final int EVENT_INITIALIZE = 12; private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 13; - private static final int EVENT_PCO_DATA_CHANGED = 14; private static final int EVENT_BANDWIDTH_CHANGED = 15; private static final int EVENT_UPDATE_NR_ADVANCED_STATE = 16; private static final int EVENT_DEVICE_IDLE_MODE_CHANGED = 17; @@ -121,7 +117,6 @@ public class NetworkTypeController extends StateMachine { sEvents[EVENT_PREFERRED_NETWORK_MODE_CHANGED] = "EVENT_PREFERRED_NETWORK_MODE_CHANGED"; sEvents[EVENT_INITIALIZE] = "EVENT_INITIALIZE"; sEvents[EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED] = "EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED"; - sEvents[EVENT_PCO_DATA_CHANGED] = "EVENT_PCO_DATA_CHANGED"; sEvents[EVENT_BANDWIDTH_CHANGED] = "EVENT_BANDWIDTH_CHANGED"; sEvents[EVENT_UPDATE_NR_ADVANCED_STATE] = "EVENT_UPDATE_NR_ADVANCED_STATE"; sEvents[EVENT_DEVICE_IDLE_MODE_CHANGED] = "EVENT_DEVICE_IDLE_MODE_CHANGED"; @@ -169,6 +164,9 @@ public class NetworkTypeController extends StateMachine { private boolean mEnableNrAdvancedWhileRoaming = true; private boolean mIsDeviceIdleMode = false; + private @Nullable DataNetworkControllerCallback mNrAdvancedCapableByPcoChangedCallback = null; + private @Nullable DataNetworkControllerCallback mNrPhysicalLinkStatusChangedCallback = null; + /** * NetworkTypeController constructor. * @@ -232,9 +230,6 @@ public class NetworkTypeController extends StateMachine { filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); - if (!mPhone.isUsingNewDataStack()) { - mPhone.mCi.registerForPcoData(getHandler(), EVENT_PCO_DATA_CHANGED, null); - } } private void unRegisterForAllEvents() { @@ -246,9 +241,6 @@ public class NetworkTypeController extends StateMachine { mPhone.getServiceStateTracker().unregisterForNrFrequencyChanged(getHandler()); mPhone.getDeviceStateMonitor().unregisterForPhysicalChannelConfigNotifChanged(getHandler()); mPhone.getContext().unregisterReceiver(mIntentReceiver); - if (!mPhone.isUsingNewDataStack()) { - mPhone.mCi.unregisterForPcoData(getHandler()); - } } private void parseCarrierConfigs() { @@ -306,38 +298,47 @@ public class NetworkTypeController extends StateMachine { CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY); mNrAdvancedCapablePcoId = b.getInt( CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT); - if (mNrAdvancedCapablePcoId > 0 && mPhone.isUsingNewDataStack()) { - mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + if (mNrAdvancedCapablePcoId > 0 && mNrAdvancedCapableByPcoChangedCallback == null) { + mNrAdvancedCapableByPcoChangedCallback = new DataNetworkControllerCallback(getHandler()::post) { - @Override - public void onNrAdvancedCapableByPcoChanged( - boolean nrAdvancedCapable) { - log("mIsNrAdvancedAllowedByPco=" + nrAdvancedCapable); - mIsNrAdvancedAllowedByPco = nrAdvancedCapable; - sendMessage(EVENT_UPDATE_NR_ADVANCED_STATE); - } - }); + @Override + public void onNrAdvancedCapableByPcoChanged( + boolean nrAdvancedCapable) { + log("mIsNrAdvancedAllowedByPco=" + nrAdvancedCapable); + mIsNrAdvancedAllowedByPco = nrAdvancedCapable; + sendMessage(EVENT_UPDATE_NR_ADVANCED_STATE); + } + }; + mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + mNrAdvancedCapableByPcoChangedCallback); + } else if (mNrAdvancedCapablePcoId == 0 + && mNrAdvancedCapableByPcoChangedCallback != null) { + mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( + mNrAdvancedCapableByPcoChangedCallback); + mNrAdvancedCapableByPcoChangedCallback = null; } mEnableNrAdvancedWhileRoaming = b.getBoolean( CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL); mIsUsingUserDataForRrcDetection = b.getBoolean( CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL); if (!mIsPhysicalChannelConfig16Supported || mIsUsingUserDataForRrcDetection) { - if (mPhone.isUsingNewDataStack()) { - mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + if (mNrPhysicalLinkStatusChangedCallback == null) { + mNrPhysicalLinkStatusChangedCallback = new DataNetworkControllerCallback(getHandler()::post) { - @Override - public void onPhysicalLinkStatusChanged( - @LinkStatus int status) { - sendMessage(obtainMessage( - EVENT_PHYSICAL_LINK_STATUS_CHANGED, - new AsyncResult(null, status, null))); - }}); - } else { - mPhone.getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .registerForPhysicalLinkStatusChanged(getHandler(), - EVENT_PHYSICAL_LINK_STATUS_CHANGED); + @Override + public void onPhysicalLinkStatusChanged( + @LinkStatus int status) { + sendMessage(obtainMessage( + EVENT_PHYSICAL_LINK_STATUS_CHANGED, + new AsyncResult(null, status, null))); + }}; + mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + mNrPhysicalLinkStatusChangedCallback); } + } else if (mNrPhysicalLinkStatusChangedCallback != null) { + mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( + mNrPhysicalLinkStatusChangedCallback); + mNrPhysicalLinkStatusChangedCallback = null; } } } @@ -555,15 +556,14 @@ public class NetworkTypeController extends StateMachine { break; case EVENT_INITIALIZE: // The reason that we do it here is because some of the works below requires - // other modules (e.g. DcTracker, ServiceStateTracker), which is not created - // yet when NetworkTypeController is created. + // other modules (e.g. DataNetworkController, ServiceStateTracker), which is not + // created yet when NetworkTypeController is created. registerForAllEvents(); parseCarrierConfigs(); break; case EVENT_DATA_RAT_CHANGED: case EVENT_NR_STATE_CHANGED: case EVENT_NR_FREQUENCY_CHANGED: - case EVENT_PCO_DATA_CHANGED: case EVENT_UPDATE_NR_ADVANCED_STATE: // ignored break; @@ -941,9 +941,6 @@ public class NetworkTypeController extends StateMachine { transitionWithTimerTo(mLegacyState); } break; - case EVENT_PCO_DATA_CHANGED: - handlePcoData((AsyncResult) msg.obj); - break; case EVENT_UPDATE_NR_ADVANCED_STATE: updateNrAdvancedState(); break; @@ -980,6 +977,7 @@ public class NetworkTypeController extends StateMachine { } private void updateNrAdvancedState() { + log("updateNrAdvancedState"); if (!isNrConnected()) { log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); sendMessage(EVENT_NR_STATE_CHANGED); @@ -993,33 +991,7 @@ public class NetworkTypeController extends StateMachine { transitionTo(mNrConnectedState); } mIsNrAdvanced = isNrAdvanced(); - } - - private void handlePcoData(AsyncResult ar) { - if (ar.exception != null) { - loge("PCO_DATA exception: " + ar.exception); - return; - } - PcoData pcodata = (PcoData) ar.result; - if (pcodata == null) { - return; - } - log("EVENT_PCO_DATA_CHANGED: pco data: " + pcodata); - DcTracker dcTracker = mPhone.getDcTracker( - AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - DataConnection dc = - dcTracker != null ? dcTracker.getDataConnectionByContextId(pcodata.cid) : null; - ApnSetting apnSettings = dc != null ? dc.getApnSetting() : null; - if (apnSettings != null && apnSettings.canHandleType(ApnSetting.TYPE_DEFAULT) - && mNrAdvancedCapablePcoId > 0 - && pcodata.pcoId == mNrAdvancedCapablePcoId - ) { - log("EVENT_PCO_DATA_CHANGED: NR_ADVANCED is allowed by PCO. length:" - + pcodata.contents.length + ",value: " + Arrays.toString(pcodata.contents)); - mIsNrAdvancedAllowedByPco = pcodata.contents.length > 0 - && pcodata.contents[pcodata.contents.length - 1] == 1; - updateNrAdvancedState(); - } + log("mIsNrAdvanced=" + mIsNrAdvanced); } } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 536a365ccc..05633642e1 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -40,7 +40,6 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telecom.VideoProfile; import android.telephony.AccessNetworkConstants; -import android.telephony.Annotation.ApnType; import android.telephony.CarrierConfigManager; import android.telephony.CarrierRestrictionRules; import android.telephony.CellIdentity; @@ -60,14 +59,12 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RegistrationManager; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; -import android.util.SparseArray; import android.util.Xml; import com.android.ims.ImsCall; @@ -80,10 +77,6 @@ import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; -import com.android.internal.telephony.dataconnection.DataConnectionReasons; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; -import com.android.internal.telephony.dataconnection.DcTracker; -import com.android.internal.telephony.dataconnection.TransportManager; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; @@ -222,11 +215,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // Radio state change protected static final int EVENT_RADIO_STATE_CHANGED = 47; protected static final int EVENT_SET_CARRIER_DATA_ENABLED = 48; - protected static final int EVENT_DEVICE_PROVISIONED_CHANGE = 49; - protected static final int EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE = 50; protected static final int EVENT_GET_AVAILABLE_NETWORKS_DONE = 51; - private static final int EVENT_ALL_DATA_DISCONNECTED = 52; protected static final int EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED = 53; protected static final int EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED = 54; protected static final int EVENT_GET_UICC_APPS_ENABLEMENT_DONE = 55; @@ -303,11 +293,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public CommandsInterface mCi; protected int mVmCount = 0; private boolean mDnsCheckDisabled; - // Data connection trackers. For each transport type (e.g. WWAN, WLAN), there will be a - // corresponding DcTracker. The WWAN DcTracker is for cellular data connections while - // WLAN DcTracker is for IWLAN data connection. For IWLAN legacy mode, only one (WWAN) DcTracker - // will be created. - protected final SparseArray mDcTrackers = new SparseArray<>(); protected DataNetworkController mDataNetworkController; /* Used for dispatching signals to configured carrier apps */ protected CarrierSignalAgent mCarrierSignalAgent; @@ -346,9 +331,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private final String mActionAttached; protected DeviceStateMonitor mDeviceStateMonitor; protected DisplayInfoController mDisplayInfoController; - protected TransportManager mTransportManager; protected AccessNetworksManager mAccessNetworksManager; - protected DataEnabledSettings mDataEnabledSettings; // Used for identify the carrier of current subscription protected CarrierResolver mCarrierResolver; protected SignalStrengthController mSignalStrengthController; @@ -428,8 +411,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected final RegistrantList mEmergencyCallToggledRegistrants = new RegistrantList(); - private final RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList(); - private final RegistrantList mCellInfoRegistrants = new RegistrantList(); private final RegistrantList mRedialRegistrants = new RegistrantList(); @@ -474,10 +455,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected LinkBandwidthEstimator mLinkBandwidthEstimator; - /** The flag indicating using the new data stack or not. */ - // This flag and the old data stack code will be deleted in Android 14. - private final boolean mNewDataStackEnabled; - public IccRecords getIccRecords() { return mIccRecords.get(); } @@ -615,9 +592,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // Initialize SMS stats mSmsStats = new SmsStats(this); - mNewDataStackEnabled = !mContext.getResources().getBoolean( - com.android.internal.R.bool.config_force_disable_telephony_new_data_stack); - if (getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { return; } @@ -814,11 +788,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { break; } - case EVENT_ALL_DATA_DISCONNECTED: - if (areAllDataDisconnected()) { - mAllDataDisconnectedRegistrants.notifyRegistrants(); - } - break; case EVENT_GET_USAGE_SETTING_DONE: ar = (AsyncResult) msg.obj; if (ar.exception == null) { @@ -1950,13 +1919,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } - /** - * @return The instance of transport manager. - */ - public TransportManager getTransportManager() { - return null; - } - /** * @return The instance of access networks manager. */ @@ -3730,18 +3692,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @return true if there is a matching DUN APN. */ public boolean hasMatchedTetherApnSetting() { - if (isUsingNewDataStack()) { - NetworkRegistrationInfo nrs = getServiceState().getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - if (nrs != null) { - return getDataNetworkController().getDataProfileManager() - .isTetheringDataProfileExisting(nrs.getAccessNetworkTechnology()); - } - return false; - } - if (getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) != null) { - return getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .hasMatchedTetherApnSetting(); + NetworkRegistrationInfo nrs = getServiceState().getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (nrs != null) { + return getDataNetworkController().getDataProfileManager() + .isTetheringDataProfileExisting(nrs.getAccessNetworkTechnology()); } return false; } @@ -3752,30 +3707,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @return {@code true} if internet data is allowed to be established. */ public boolean isDataAllowed() { - if (isUsingNewDataStack()) { - return getDataNetworkController().isInternetDataAllowed(); - } - return isDataAllowed(ApnSetting.TYPE_DEFAULT, null); - } - - /** - * Report on whether data connectivity is allowed. - * - * @param apnType APN type - * @param reasons The reasons that data can/can't be established. This is an output param. - * @return True if data is allowed to be established - */ - public boolean isDataAllowed(@ApnType int apnType, DataConnectionReasons reasons) { - if (mAccessNetworksManager != null) { - int transport = mAccessNetworksManager.getCurrentTransport(apnType); - if (getDcTracker(transport) != null) { - return getDcTracker(transport).isDataAllowed(reasons); - } - } - return false; + return getDataNetworkController().isInternetDataAllowed(); } - /** * Action set from carrier signalling broadcast receivers to enable/disable metered apns. */ @@ -3932,16 +3866,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } - /** - * Get the current for the default apn DataState. No change notification - * exists at this interface -- use - * {@link android.telephony.PhoneStateListener} instead. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public PhoneConstants.DataState getDataConnectionState() { - return getDataConnectionState(ApnSetting.TYPE_DEFAULT_STRING); - } - public void notifyCallForwardingIndicator() { } @@ -4621,42 +4545,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return false; } - /** - * @return True if all data connections are disconnected. - */ - public boolean areAllDataDisconnected() { - if (mAccessNetworksManager != null) { - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - if (getDcTracker(transport) != null - && !getDcTracker(transport).areAllDataDisconnected()) { - return false; - } - } - } - return true; - } - - public void registerForAllDataDisconnected(Handler h, int what) { - mAllDataDisconnectedRegistrants.addUnique(h, what, null); - if (mAccessNetworksManager != null) { - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - if (getDcTracker(transport) != null - && !getDcTracker(transport).areAllDataDisconnected()) { - getDcTracker(transport).registerForAllDataDisconnected( - this, EVENT_ALL_DATA_DISCONNECTED); - } - } - } - } - - public void unregisterForAllDataDisconnected(Handler h) { - mAllDataDisconnectedRegistrants.remove(h); - } - - public DataEnabledSettings getDataEnabledSettings() { - return mDataEnabledSettings; - } - @UnsupportedAppUsage public IccSmsInterfaceManager getIccSmsInterfaceManager(){ return null; @@ -4787,16 +4675,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return isEmergencyCallOnly; } - /** - * Get data connection tracker based on the transport type - * - * @param transportType Transport type defined in AccessNetworkConstants.TransportType - * @return The data connection tracker. Null if not found. - */ - public @Nullable DcTracker getDcTracker(int transportType) { - return mDcTrackers.get(transportType); - } - // Return true if either CSIM or RUIM app is present. By default it returns false. public boolean isCdmaSubscriptionAppPresent() { return false; @@ -4976,14 +4854,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return mIsAllowedNetworkTypesLoadedFromDb; } - /** - * @return {@code true} if using the new telephony data stack. - */ - // This flag and the old data stack code will be deleted in Android 14. - public boolean isUsingNewDataStack() { - return mNewDataStackEnabled; - } - /** * Returns the user's last setting for terminal-based call waiting * @param forCsOnly indicates the caller expects the result for CS calls only @@ -5040,7 +4910,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { pw.println(" needsOtaServiceProvisioning=" + needsOtaServiceProvisioning()); pw.println(" isInEmergencySmsMode=" + isInEmergencySmsMode()); pw.println(" isEcmCanceledForEmergency=" + isEcmCanceledForEmergency()); - pw.println(" isUsingNewDataStack=" + isUsingNewDataStack()); pw.println(" service state=" + getServiceState()); pw.flush(); pw.println("++++++++++++++++++++++++++++++++"); @@ -5056,16 +4925,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { pw.println("++++++++++++++++++++++++++++++++"); } - if (mAccessNetworksManager != null) { - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - if (getDcTracker(transport) != null) { - getDcTracker(transport).dump(fd, pw, args); - pw.flush(); - pw.println("++++++++++++++++++++++++++++++++"); - } - } - } - if (mDataNetworkController != null) { try { mDataNetworkController.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/ProxyController.java b/src/java/com/android/internal/telephony/ProxyController.java index 76f0041ee2..498953c6e0 100644 --- a/src/java/com/android/internal/telephony/ProxyController.java +++ b/src/java/com/android/internal/telephony/ProxyController.java @@ -28,7 +28,6 @@ import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.telephony.RadioAccessFamily; -import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; @@ -157,34 +156,6 @@ public class ProxyController { logd("Constructor - Exit"); } - public void registerForAllDataDisconnected(int subId, Handler h, int what) { - int phoneId = SubscriptionController.getInstance().getPhoneId(subId); - - if (SubscriptionManager.isValidPhoneId(phoneId)) { - mPhones[phoneId].registerForAllDataDisconnected(h, what); - } - } - - public void unregisterForAllDataDisconnected(int subId, Handler h) { - int phoneId = SubscriptionController.getInstance().getPhoneId(subId); - - if (SubscriptionManager.isValidPhoneId(phoneId)) { - mPhones[phoneId].unregisterForAllDataDisconnected(h); - } - } - - - public boolean areAllDataDisconnected(int subId) { - int phoneId = SubscriptionController.getInstance().getPhoneId(subId); - - if (SubscriptionManager.isValidPhoneId(phoneId)) { - return mPhones[phoneId].areAllDataDisconnected(); - } else { - // if we can't find a phone for the given subId, it is disconnected. - return true; - } - } - /** * Get phone radio type and access technology. * diff --git a/src/java/com/android/internal/telephony/RetryManager.java b/src/java/com/android/internal/telephony/RetryManager.java deleted file mode 100644 index 83864e46a0..0000000000 --- a/src/java/com/android/internal/telephony/RetryManager.java +++ /dev/null @@ -1,723 +0,0 @@ -/** - * Copyright (C) 2009 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; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.Context; -import android.os.Build; -import android.os.PersistableBundle; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.telephony.Annotation.ApnType; -import android.telephony.CarrierConfigManager; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.text.TextUtils; -import android.util.Pair; - -import com.android.internal.telephony.dataconnection.DataThrottler; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.telephony.Rlog; - -import java.util.ArrayList; -import java.util.Random; - -/** - * Retry manager allows a simple way to declare a series of - * retry timeouts. After creating a RetryManager the configure - * method is used to define the sequence. A simple linear series - * may be initialized using configure with three integer parameters - * The other configure method allows a series to be declared using - * a string. - *

- * The format of the configuration string is the apn type followed by a series of parameters - * separated by a comma. There are two name value pair parameters plus a series - * of delay times. The units of of these delay times is unspecified. - * The name value pairs which may be specified are: - *

    - *
  • max_retries= - *
  • default_randomizationTime= - *
- *

- * apn type specifies the APN type that the retry pattern will apply for. "others" is for all other - * APN types not specified in the config. - * - * max_retries is the number of times that incrementRetryCount - * maybe called before isRetryNeeded will return false. if value - * is infinite then isRetryNeeded will always return true. - * - * default_randomizationTime will be used as the randomizationTime - * for delay times which have no supplied randomizationTime. If - * default_randomizationTime is not defined it defaults to 0. - *

- * The other parameters define The series of delay times and each - * may have an optional randomization value separated from the - * delay time by a colon. - *

- * Examples: - *

    - *
  • 3 retries for mms with no randomization value which means its 0: - *
    • "mms:1000, 2000, 3000"
    - * - *
  • 10 retries for default APN with a 500 default randomization value for each and - * the 4..10 retries all using 3000 as the delay: - *
    • "default:max_retries=10, default_randomization=500, 1000, 2000, 3000"
    - * - *
  • 4 retries for supl APN with a 100 as the default randomization value for the first 2 values - * and the other two having specified values of 500: - *
    • "supl:default_randomization=100, 1000, 2000, 4000:500, 5000:500"
    - * - *
  • Infinite number of retries for all other APNs with the first one at 1000, the second at 2000 - * all others will be at 3000. - *
    • "others:max_retries=infinite,1000,2000,3000
    - *
- * - * {@hide} - */ -public class RetryManager { - public static final String LOG_TAG = "RetryManager"; - public static final boolean DBG = true; - public static final boolean VDBG = false; // STOPSHIP if true - - /** - * The default retry configuration for APNs. See above for the syntax. - */ - private static final String DEFAULT_DATA_RETRY_CONFIG = "max_retries=3, 5000, 5000, 5000"; - - /** - * The APN type used for all other APNs retry configuration. - */ - private static final String OTHERS_APN_TYPE = "others"; - - /** - * The default value (in milliseconds) for delay between APN trying (mInterApnDelay) - * within the same round - */ - private static final long DEFAULT_INTER_APN_DELAY = 20000; - - /** - * The default value (in milliseconds) for delay between APN trying (mFailFastInterApnDelay) - * within the same round when we are in fail fast mode - */ - private static final long DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING = 3000; - - /** - * The default value (in milliseconds) for retrying APN after disconnect - */ - private static final long DEFAULT_APN_RETRY_AFTER_DISCONNECT_DELAY = 10000; - - /** - * The value indicating retry should not occur. - */ - public static final long NO_RETRY = Long.MAX_VALUE; - - /** - * The value indicating network did not suggest any retry delay - */ - public static final long NO_SUGGESTED_RETRY_DELAY = DataCallResponse.RETRY_DURATION_UNDEFINED; - - /** - * If the network suggests a retry delay in the data call setup response, we will retry - * the current APN setting again. The maximum retry count is to prevent that network - * keeps asking device to retry data setup forever and causes power consumption issue. - */ - private static final int DEFAULT_MAX_SAME_APN_RETRY = 3; - - /** - * The delay (in milliseconds) between APN trying within the same round - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long mInterApnDelay; - - /** - * The delay (in milliseconds) between APN trying within the same round when we are in - * fail fast mode - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private long mFailFastInterApnDelay; - - /** - * The delay (in milliseconds) for APN retrying after disconnect (e.g. Modem suddenly reports - * data call lost) - */ - private long mApnRetryAfterDisconnectDelay; - - /** - * The counter for same APN retrying. See {@link #DEFAULT_MAX_SAME_APN_RETRY} for the details. - */ - private int mSameApnRetryCount = 0; - - /** - * The maximum times that frameworks retries data setup with the same APN. This value could be - * changed via carrier config. See {@link #DEFAULT_MAX_SAME_APN_RETRY} for the details. - */ - private int mMaxSameApnRetry = DEFAULT_MAX_SAME_APN_RETRY; - - /** - * Retry record with times in milli-seconds - */ - private static class RetryRec { - long mDelayTime; - long mRandomizationTime; - - RetryRec(long delayTime, long randomizationTime) { - mDelayTime = delayTime; - mRandomizationTime = randomizationTime; - } - } - - /** - * The array of retry records - */ - private ArrayList mRetryArray = new ArrayList(); - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private Phone mPhone; - - private final DataThrottler mDataThrottler; - - /** - * Flag indicating whether retrying forever regardless the maximum retry count mMaxRetryCount - */ - private boolean mRetryForever = false; - - /** - * The maximum number of retries to attempt - */ - private int mMaxRetryCount; - - /** - * The current number of retries - */ - private int mRetryCount = 0; - - /** - * Random number generator. The random delay will be added into retry timer to avoid all devices - * around retrying the APN at the same time. - */ - private Random mRng = new Random(); - - /** - * Retry manager configuration string. See top of the detailed explanation. - */ - private String mConfig; - - /** - * The list to store APN setting candidates for data call setup. Most of the carriers only have - * one APN, but few carriers have more than one. - */ - private ArrayList mWaitingApns = new ArrayList<>(); - - /** - * Index pointing to the current trying APN from mWaitingApns - */ - private int mCurrentApnIndex = -1; - - /** - * Apn context type. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private String mApnType; - - private final @ApnType int apnType; - - /** - * Retry manager constructor - * @param phone Phone object - * @param dataThrottler Data throttler - * @param apnType APN type - */ - public RetryManager(@NonNull Phone phone, @NonNull DataThrottler dataThrottler, - @ApnType int apnType) { - mPhone = phone; - mDataThrottler = dataThrottler; - this.apnType = apnType; - } - - /** - * Configure for using string which allow arbitrary - * sequences of times. See class comments for the - * string format. - * - * @return true if successful - */ - @UnsupportedAppUsage - private boolean configure(String configStr) { - // Strip quotes if present. - if ((configStr.startsWith("\"") && configStr.endsWith("\""))) { - configStr = configStr.substring(1, configStr.length() - 1); - } - - // Reset the retry manager since delay, max retry count, etc...will be reset. - reset(); - - if (DBG) log("configure: '" + configStr + "'"); - mConfig = configStr; - - if (!TextUtils.isEmpty(configStr)) { - long defaultRandomization = 0; - - if (VDBG) log("configure: not empty"); - - String strArray[] = configStr.split(","); - for (int i = 0; i < strArray.length; i++) { - if (VDBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'"); - Pair value; - String splitStr[] = strArray[i].split("=", 2); - splitStr[0] = splitStr[0].trim(); - if (VDBG) log("configure: splitStr[0]='" + splitStr[0] + "'"); - if (splitStr.length > 1) { - splitStr[1] = splitStr[1].trim(); - if (VDBG) log("configure: splitStr[1]='" + splitStr[1] + "'"); - if (TextUtils.equals(splitStr[0], "default_randomization")) { - value = parseNonNegativeInt(splitStr[0], splitStr[1]); - if (!value.first) return false; - defaultRandomization = value.second; - } else if (TextUtils.equals(splitStr[0], "max_retries")) { - if (TextUtils.equals("infinite", splitStr[1])) { - mRetryForever = true; - } else { - value = parseNonNegativeInt(splitStr[0], splitStr[1]); - if (!value.first) return false; - mMaxRetryCount = value.second; - } - } else { - Rlog.e(LOG_TAG, "Unrecognized configuration name value pair: " - + strArray[i]); - return false; - } - } else { - /** - * Assume a retry time with an optional randomization value - * following a ":" - */ - splitStr = strArray[i].split(":", 2); - splitStr[0] = splitStr[0].trim(); - RetryRec rr = new RetryRec(0, 0); - value = parseNonNegativeInt("delayTime", splitStr[0]); - if (!value.first) return false; - rr.mDelayTime = value.second; - - // Check if optional randomization value present - if (splitStr.length > 1) { - splitStr[1] = splitStr[1].trim(); - if (VDBG) log("configure: splitStr[1]='" + splitStr[1] + "'"); - value = parseNonNegativeInt("randomizationTime", splitStr[1]); - if (!value.first) return false; - rr.mRandomizationTime = value.second; - } else { - rr.mRandomizationTime = defaultRandomization; - } - mRetryArray.add(rr); - } - } - if (mRetryArray.size() > mMaxRetryCount) { - mMaxRetryCount = mRetryArray.size(); - if (VDBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount); - } - } else { - log("configure: cleared"); - } - - if (VDBG) log("configure: true"); - return true; - } - - /** - * Configure the retry manager - */ - private void configureRetry() { - String configString = null; - String otherConfigString = null; - - try { - if (TelephonyUtils.IS_DEBUGGABLE) { - // Using system properties is easier for testing from command line. - String config = SystemProperties.get("test.data_retry_config"); - if (!TextUtils.isEmpty(config)) { - configure(config); - return; - } - } - - CarrierConfigManager configManager = (CarrierConfigManager) - mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); - - mInterApnDelay = b.getLong( - CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, - DEFAULT_INTER_APN_DELAY); - mFailFastInterApnDelay = b.getLong( - CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, - DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING); - mApnRetryAfterDisconnectDelay = b.getLong( - CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, - DEFAULT_APN_RETRY_AFTER_DISCONNECT_DELAY); - mMaxSameApnRetry = b.getInt( - CarrierConfigManager - .KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, - DEFAULT_MAX_SAME_APN_RETRY); - - // Load all retry patterns for all different APNs. - String[] allConfigStrings = b.getStringArray( - CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS); - if (allConfigStrings != null) { - for (String s : allConfigStrings) { - if (!TextUtils.isEmpty(s)) { - String splitStr[] = s.split(":", 2); - if (splitStr.length == 2) { - String apnTypeStr = splitStr[0].trim(); - // Check if this retry pattern is for the APN we want. - if (apnTypeStr.equals(ApnSetting.getApnTypeString(apnType))) { - // Extract the config string. Note that an empty string is valid - // here, meaning no retry for the specified APN. - configString = splitStr[1]; - break; - } else if (apnTypeStr.equals(OTHERS_APN_TYPE)) { - // Extract the config string. Note that an empty string is valid - // here, meaning no retry for all other APNs. - otherConfigString = splitStr[1]; - } - } - } - } - } - - if (configString == null) { - if (otherConfigString != null) { - configString = otherConfigString; - } else { - // We should never reach here. If we reach here, it must be a configuration - // error bug. - log("Invalid APN retry configuration!. Use the default one now."); - configString = DEFAULT_DATA_RETRY_CONFIG; - } - } - } catch (NullPointerException ex) { - // We should never reach here unless there is a bug - log("Failed to read configuration! Use the hardcoded default value."); - - mInterApnDelay = DEFAULT_INTER_APN_DELAY; - mFailFastInterApnDelay = DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING; - configString = DEFAULT_DATA_RETRY_CONFIG; - } - - if (VDBG) { - log("mInterApnDelay = " + mInterApnDelay + ", mFailFastInterApnDelay = " + - mFailFastInterApnDelay); - } - - configure(configString); - } - - /** - * Return the timer that should be used to trigger the data reconnection - */ - @UnsupportedAppUsage - private long getRetryTimer() { - int index; - if (mRetryCount < mRetryArray.size()) { - index = mRetryCount; - } else { - index = mRetryArray.size() - 1; - } - - long retVal; - if ((index >= 0) && (index < mRetryArray.size())) { - retVal = mRetryArray.get(index).mDelayTime + nextRandomizationTime(index); - } else { - retVal = 0; - } - - if (DBG) log("getRetryTimer: " + retVal); - return retVal; - } - - /** - * Parse an integer validating the value is not negative. - * @param name Name - * @param stringValue Value - * @return Pair.first == true if stringValue an integer >= 0 - */ - private Pair parseNonNegativeInt(String name, String stringValue) { - int value; - Pair retVal; - try { - value = Integer.parseInt(stringValue); - retVal = new Pair<>(validateNonNegativeInt(name, value), value); - } catch (NumberFormatException e) { - Rlog.e(LOG_TAG, name + " bad value: " + stringValue, e); - retVal = new Pair<>(false, 0); - } - if (VDBG) { - log("parseNonNegativeInt: " + name + ", " + stringValue + ", " - + retVal.first + ", " + retVal.second); - } - return retVal; - } - - /** - * Validate an integer is >= 0 and logs an error if not - * @param name Name - * @param value Value - * @return Pair.first - */ - private boolean validateNonNegativeInt(String name, long value) { - boolean retVal; - if (value < 0) { - Rlog.e(LOG_TAG, name + " bad value: is < 0"); - retVal = false; - } else { - retVal = true; - } - if (VDBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal); - return retVal; - } - - /** - * Return next random number for the index - * @param index Retry index - */ - private long nextRandomizationTime(int index) { - long randomTime = mRetryArray.get(index).mRandomizationTime; - if (randomTime == 0) { - return 0; - } else { - return mRng.nextInt((int) randomTime); - } - } - - private long getNetworkSuggestedRetryDelay() { - long retryElapseTime = mDataThrottler.getRetryTime(apnType); - if (retryElapseTime == NO_RETRY || retryElapseTime == NO_SUGGESTED_RETRY_DELAY) { - return retryElapseTime; - } - - // The time from data throttler is system's elapsed time. We need to return the delta. If - // less than 0, then return 0 (i.e. retry immediately). - return Math.max(0, retryElapseTime - SystemClock.elapsedRealtime()); - } - - /** - * Get the next APN setting for data call setup. - * @return APN setting to try. {@code null} if cannot find any APN, - */ - public @Nullable ApnSetting getNextApnSetting() { - if (mWaitingApns == null || mWaitingApns.size() == 0) { - log("Waiting APN list is null or empty."); - return null; - } - - long networkSuggestedRetryDelay = getNetworkSuggestedRetryDelay(); - if (networkSuggestedRetryDelay == NO_RETRY) { - log("Network suggested no retry."); - return null; - } - - // If the network had suggested a retry delay, we should retry the current APN again - // (up to mMaxSameApnRetry times) instead of getting the next APN setting from - // our own list. If the APN waiting list has been reset before a setup data responses - // arrive (i.e. mCurrentApnIndex=-1), then ignore the network suggested retry. - if (mCurrentApnIndex != -1 && networkSuggestedRetryDelay != NO_SUGGESTED_RETRY_DELAY - && mSameApnRetryCount < mMaxSameApnRetry) { - mSameApnRetryCount++; - return mWaitingApns.get(mCurrentApnIndex); - } - - mSameApnRetryCount = 0; - - int index = mCurrentApnIndex; - // Loop through the APN list to find out the index of next non-permanent failed APN. - while (true) { - if (++index == mWaitingApns.size()) index = 0; - - // Stop if we find the non-failed APN. - if (!mWaitingApns.get(index).getPermanentFailed()) { - break; - } - - // If all APNs have permanently failed, bail out. - if (mWaitingApns.stream().allMatch(ApnSetting::getPermanentFailed)) { - return null; - } - } - - mCurrentApnIndex = index; - return mWaitingApns.get(mCurrentApnIndex); - } - - /** - * Get the delay for trying the next waiting APN from the list. - * @param failFastEnabled True if fail fast mode enabled. In this case we'll use a shorter - * delay. - * @return delay in milliseconds - */ - public long getDelayForNextApn(boolean failFastEnabled) { - - if (mWaitingApns == null || mWaitingApns.size() == 0) { - log("Waiting APN list is null or empty."); - return NO_RETRY; - } - - long networkSuggestedDelay = getNetworkSuggestedRetryDelay(); - log("Network suggested delay=" + networkSuggestedDelay + "ms"); - - if (networkSuggestedDelay == NO_RETRY) { - log("Network suggested not retrying."); - return NO_RETRY; - } - - if (networkSuggestedDelay != NO_SUGGESTED_RETRY_DELAY - && mSameApnRetryCount < mMaxSameApnRetry) { - // If the network explicitly suggests a retry delay, we should use it, even in fail fast - // mode. - log("Network suggested retry in " + networkSuggestedDelay + " ms."); - return networkSuggestedDelay; - } - - // In order to determine the delay to try next APN, we need to peek the next available APN. - // Case 1 - If we will start the next round of APN trying, - // we use the exponential-growth delay. (e.g. 5s, 10s, 30s...etc.) - // Case 2 - If we are still within the same round of APN trying, - // we use the fixed standard delay between APNs. (e.g. 20s) - - int index = mCurrentApnIndex; - while (true) { - if (++index >= mWaitingApns.size()) index = 0; - - // Stop if we find the non-failed APN. - if (!mWaitingApns.get(index).getPermanentFailed()) { - break; - } - - // If all APNs have permanently failed, bail out. - if (mWaitingApns.stream().allMatch(ApnSetting::getPermanentFailed)) { - log("All APNs have permanently failed."); - return NO_RETRY; - } - } - - long delay; - if (index <= mCurrentApnIndex) { - // Case 1, if the next APN is in the next round. - if (!mRetryForever && mRetryCount + 1 > mMaxRetryCount) { - log("Reached maximum retry count " + mMaxRetryCount + "."); - return NO_RETRY; - } - delay = getRetryTimer(); - ++mRetryCount; - } else { - // Case 2, if the next APN is still in the same round. - delay = mInterApnDelay; - } - - if (failFastEnabled && delay > mFailFastInterApnDelay) { - // If we enable fail fast mode, and the delay we got is longer than - // fail-fast delay (mFailFastInterApnDelay), use the fail-fast delay. - // If the delay we calculated is already shorter than fail-fast delay, - // then ignore fail-fast delay. - delay = mFailFastInterApnDelay; - } - - return delay; - } - - /** - * Mark the APN setting permanently failed. - * @param apn APN setting to be marked as permanently failed - * */ - public void markApnPermanentFailed(ApnSetting apn) { - if (apn != null) { - apn.setPermanentFailed(true); - } - } - - /** - * Reset the retry manager. - */ - private void reset() { - mMaxRetryCount = 0; - mRetryCount = 0; - mCurrentApnIndex = -1; - mSameApnRetryCount = 0; - mRetryArray.clear(); - } - - /** - * Set waiting APNs for retrying in case needed. - * @param waitingApns Waiting APN list - */ - public void setWaitingApns(ArrayList waitingApns) { - - if (waitingApns == null) { - log("No waiting APNs provided"); - return; - } - - mWaitingApns = waitingApns; - - // Since we replace the entire waiting APN list, we need to re-config this retry manager. - configureRetry(); - - for (ApnSetting apn : mWaitingApns) { - apn.setPermanentFailed(false); - } - - log("Setting " + mWaitingApns.size() + " waiting APNs."); - - if (VDBG) { - for (int i = 0; i < mWaitingApns.size(); i++) { - log(" [" + i + "]:" + mWaitingApns.get(i)); - } - } - } - - /** - * Get the list of waiting APNs. - * @return the list of waiting APNs - */ - public @NonNull ArrayList getWaitingApns() { - return mWaitingApns; - } - - /** - * Get the delay in milliseconds for APN retry after disconnect - * @return The delay in milliseconds - */ - public long getRetryAfterDisconnectDelay() { - return mApnRetryAfterDisconnectDelay; - } - - public String toString() { - if (mConfig == null) return ""; - return "RetryManager: apnType=" + ApnSetting.getApnTypeString(apnType) - + " mRetryCount=" - + mRetryCount + " mMaxRetryCount=" + mMaxRetryCount + " mCurrentApnIndex=" - + mCurrentApnIndex + " mSameApnRtryCount=" + mSameApnRetryCount - + " networkSuggestedDelay=" + getNetworkSuggestedRetryDelay() + " mRetryForever=" - + mRetryForever + " mInterApnDelay=" + mInterApnDelay - + " mApnRetryAfterDisconnectDelay=" + mApnRetryAfterDisconnectDelay - + " mConfig={" + mConfig + "}"; - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private void log(String s) { - Rlog.d(LOG_TAG, "[" + ApnSetting.getApnTypeString(apnType) + "] " + s); - } -} diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index f99479243f..08800aeda6 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -37,7 +37,6 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.res.Resources; import android.hardware.radio.V1_0.CellInfoType; -import android.net.NetworkCapabilities; import android.os.AsyncResult; import android.os.BaseBundle; import android.os.Build; @@ -95,7 +94,6 @@ import com.android.internal.telephony.cdnr.CarrierDisplayNameResolver; import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetwork; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; -import com.android.internal.telephony.dataconnection.DataConnection; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.TelephonyMetrics; @@ -224,7 +222,6 @@ public class ServiceStateTracker extends Handler { /* Radio power off pending flag and tag counter */ private boolean mPendingRadioPowerOffAfterDataOff = false; - private int mPendingRadioPowerOffAfterDataOffTag = 0; /** Waiting period before recheck gprs and voice registration. */ public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; @@ -719,17 +716,15 @@ public class ServiceStateTracker extends Handler { registerForImsCapabilityChanged(mCSST, CarrierServiceStateTracker.CARRIER_EVENT_IMS_CAPABILITIES_CHANGED, null); - if (mPhone.isUsingNewDataStack()) { - mDataDisconnectedCallback = new DataNetworkControllerCallback(this::post) { - @Override - public void onAnyDataNetworkExistingChanged(boolean anyDataExisting) { - log("onAnyDataNetworkExistingChanged: anyDataExisting=" + anyDataExisting); - if (!anyDataExisting) { - sendEmptyMessage(EVENT_ALL_DATA_DISCONNECTED); - } + mDataDisconnectedCallback = new DataNetworkControllerCallback(this::post) { + @Override + public void onAnyDataNetworkExistingChanged(boolean anyDataExisting) { + log("onAnyDataNetworkExistingChanged: anyDataExisting=" + anyDataExisting); + if (!anyDataExisting) { + sendEmptyMessage(EVENT_ALL_DATA_DISCONNECTED); } - }; - } + } + }; } @VisibleForTesting @@ -1181,22 +1176,9 @@ public class ServiceStateTracker extends Handler { switch (msg.what) { case EVENT_SET_RADIO_POWER_OFF: synchronized(this) { - if (mPhone.isUsingNewDataStack()) { - mPendingRadioPowerOffAfterDataOff = false; - log("Wait for all data networks torn down timed out. Power off now."); - hangupAndPowerOff(); - return; - } - if (mPendingRadioPowerOffAfterDataOff && - (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) { - if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now."); - hangupAndPowerOff(); - mPendingRadioPowerOffAfterDataOffTag += 1; - mPendingRadioPowerOffAfterDataOff = false; - } else { - log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 + - "!= tag=" + mPendingRadioPowerOffAfterDataOffTag); - } + mPendingRadioPowerOffAfterDataOff = false; + log("Wait for all data networks torn down timed out. Power off now."); + hangupAndPowerOff(); } break; @@ -1464,41 +1446,26 @@ public class ServiceStateTracker extends Handler { break; case EVENT_ALL_DATA_DISCONNECTED: - if (mPhone.isUsingNewDataStack()) { - log("EVENT_ALL_DATA_DISCONNECTED"); - if (!mPendingRadioPowerOffAfterDataOff) return; - boolean areAllDataDisconnectedOnAllPhones = true; - for (Phone phone : PhoneFactory.getPhones()) { - if (phone.getDataNetworkController().areAllDataDisconnected()) { - phone.getDataNetworkController() - .unregisterDataNetworkControllerCallback( - mDataDisconnectedCallback); - } else { - log("Still waiting for all data disconnected on phone: " - + phone.getSubId()); - areAllDataDisconnectedOnAllPhones = false; - } - } - if (areAllDataDisconnectedOnAllPhones) { - mPendingRadioPowerOffAfterDataOff = false; - removeMessages(EVENT_SET_RADIO_POWER_OFF); - if (DBG) log("Data disconnected for all phones, turn radio off now."); - hangupAndPowerOff(); - } - return; - } - int dds = SubscriptionManager.getDefaultDataSubscriptionId(); - ProxyController.getInstance().unregisterForAllDataDisconnected(dds, this); - synchronized(this) { - if (mPendingRadioPowerOffAfterDataOff) { - if (DBG) log("EVENT_ALL_DATA_DISCONNECTED, turn radio off now."); - hangupAndPowerOff(); - mPendingRadioPowerOffAfterDataOffTag += 1; - mPendingRadioPowerOffAfterDataOff = false; + log("EVENT_ALL_DATA_DISCONNECTED"); + if (!mPendingRadioPowerOffAfterDataOff) return; + boolean areAllDataDisconnectedOnAllPhones = true; + for (Phone phone : PhoneFactory.getPhones()) { + if (phone.getDataNetworkController().areAllDataDisconnected()) { + phone.getDataNetworkController() + .unregisterDataNetworkControllerCallback( + mDataDisconnectedCallback); } else { - log("EVENT_ALL_DATA_DISCONNECTED is stale"); + log("Still waiting for all data disconnected on phone: " + + phone.getSubId()); + areAllDataDisconnectedOnAllPhones = false; } } + if (areAllDataDisconnectedOnAllPhones) { + mPendingRadioPowerOffAfterDataOff = false; + removeMessages(EVENT_SET_RADIO_POWER_OFF); + if (DBG) log("Data disconnected for all phones, turn radio off now."); + hangupAndPowerOff(); + } break; case EVENT_CHANGE_IMS_STATE: @@ -2150,18 +2117,8 @@ public class ServiceStateTracker extends Handler { private boolean isInternetPhysicalChannelConfig(PhysicalChannelConfig config) { for (int cid : config.getContextIds()) { - if (mPhone.isUsingNewDataStack()) { - if (mPhone.getDataNetworkController().isInternetNetwork(cid)) { - return true; - } - } else { - DataConnection dc = mPhone.getDcTracker( - AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .getDataConnectionByContextId(cid); - if (dc != null && dc.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_INTERNET)) { - return true; - } + if (mPhone.getDataNetworkController().isInternetNetwork(cid)) { + return true; } } return false; @@ -3121,17 +3078,8 @@ public class ServiceStateTracker extends Handler { mCi.setRadioPower(true, forEmergencyCall, isSelectedPhoneForEmergencyCall, null); } else if ((!mDesiredPowerState || !mRadioPowerOffReasons.isEmpty()) && mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) { - // If it's on and available and we want it off gracefully - if (!mPhone.isUsingNewDataStack() && mImsRegistrationOnOff - && getRadioPowerOffDelayTimeoutForImsRegistration() > 0) { - if (DBG) log("setPowerStateToDesired: delaying power off until IMS dereg."); - startDelayRadioOffWaitingForImsDeregTimeout(); - // Return early here as we do not want to hit the cancel timeout code below. - return; - } else { - if (DBG) log("setPowerStateToDesired: powerOffRadioSafely()"); - powerOffRadioSafely(); - } + if (DBG) log("setPowerStateToDesired: powerOffRadioSafely()"); + powerOffRadioSafely(); } else if (mDeviceShuttingDown && (mCi.getRadioState() != TelephonyManager.RADIO_POWER_UNAVAILABLE)) { // !mDesiredPowerState condition above will happen first if the radio is on, so we will @@ -3505,11 +3453,6 @@ public class ServiceStateTracker extends Handler { NetworkRegistrationInfo newNrs = mNewSS.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, transport); - // If the previously it was not in service, and now it's in service, trigger the - // attached event. Also if airplane mode was just turned on, and data is already in - // service, we need to trigger the attached event again so that DcTracker can setup - // data on all connectable APNs again (because we've already torn down all data - // connections just before airplane mode turned on) boolean changed = (oldNrs == null || !oldNrs.isInService() || hasAirplaneModeOnChanged) && (newNrs != null && newNrs.isInService()); hasDataAttached.put(transport, changed); @@ -5010,96 +4953,33 @@ public class ServiceStateTracker extends Handler { public void powerOffRadioSafely() { synchronized (this) { if (!mPendingRadioPowerOffAfterDataOff) { - if (mPhone.isUsingNewDataStack()) { - // hang up all active voice calls first - if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) { - mPhone.mCT.mRingingCall.hangupIfAlive(); - mPhone.mCT.mBackgroundCall.hangupIfAlive(); - mPhone.mCT.mForegroundCall.hangupIfAlive(); - } + // hang up all active voice calls first + if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) { + mPhone.mCT.mRingingCall.hangupIfAlive(); + mPhone.mCT.mBackgroundCall.hangupIfAlive(); + mPhone.mCT.mForegroundCall.hangupIfAlive(); + } - for (Phone phone : PhoneFactory.getPhones()) { - if (!phone.getDataNetworkController().areAllDataDisconnected()) { - log("powerOffRadioSafely: Data is active on phone " + phone.getSubId() - + ". Wait for all data disconnect."); - mPendingRadioPowerOffAfterDataOff = true; - phone.getDataNetworkController().registerDataNetworkControllerCallback( - mDataDisconnectedCallback); - } + for (Phone phone : PhoneFactory.getPhones()) { + if (!phone.getDataNetworkController().areAllDataDisconnected()) { + log("powerOffRadioSafely: Data is active on phone " + phone.getSubId() + + ". Wait for all data disconnect."); + mPendingRadioPowerOffAfterDataOff = true; + phone.getDataNetworkController().registerDataNetworkControllerCallback( + mDataDisconnectedCallback); } + } - // Tear down outside of the disconnected check to prevent race conditions. - mPhone.getDataNetworkController().tearDownAllDataNetworks( - DataNetwork.TEAR_DOWN_REASON_AIRPLANE_MODE_ON); + // Tear down outside of the disconnected check to prevent race conditions. + mPhone.getDataNetworkController().tearDownAllDataNetworks( + DataNetwork.TEAR_DOWN_REASON_AIRPLANE_MODE_ON); - if (mPendingRadioPowerOffAfterDataOff) { - sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, - POWER_OFF_ALL_DATA_NETWORKS_DISCONNECTED_TIMEOUT); - } else { - log("powerOffRadioSafely: No data is connected, turn off radio now."); - hangupAndPowerOff(); - } - return; - } - int dds = SubscriptionManager.getDefaultDataSubscriptionId(); - // To minimize race conditions we call cleanUpAllConnections on - // both if else paths instead of before this isDisconnected test. - if (mPhone.areAllDataDisconnected() - && (dds == mPhone.getSubId() - || (dds != mPhone.getSubId() - && ProxyController.getInstance().areAllDataDisconnected(dds)))) { - // To minimize race conditions we do this after isDisconnected - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - if (mPhone.getDcTracker(transport) != null) { - mPhone.getDcTracker(transport).cleanUpAllConnections( - Phone.REASON_RADIO_TURNED_OFF); - } - } - if (DBG) { - log("powerOffRadioSafely: Data disconnected, turn off radio now."); - } - hangupAndPowerOff(); + if (mPendingRadioPowerOffAfterDataOff) { + sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, + POWER_OFF_ALL_DATA_NETWORKS_DISCONNECTED_TIMEOUT); } else { - // hang up all active voice calls first - if (mPhone.isPhoneTypeGsm() && mPhone.isInCall()) { - mPhone.mCT.mRingingCall.hangupIfAlive(); - mPhone.mCT.mBackgroundCall.hangupIfAlive(); - mPhone.mCT.mForegroundCall.hangupIfAlive(); - } - for (int transport : mAccessNetworksManager.getAvailableTransports()) { - if (mPhone.getDcTracker(transport) != null) { - mPhone.getDcTracker(transport).cleanUpAllConnections( - Phone.REASON_RADIO_TURNED_OFF); - } - } - - if (dds != mPhone.getSubId() - && !ProxyController.getInstance().areAllDataDisconnected(dds)) { - if (DBG) { - log(String.format("powerOffRadioSafely: Data is active on DDS (%d)." - + " Wait for all data disconnect", dds)); - } - // Data is not disconnected on DDS. Wait for the data disconnect complete - // before sending the RADIO_POWER off. - ProxyController.getInstance().registerForAllDataDisconnected(dds, this, - EVENT_ALL_DATA_DISCONNECTED); - mPendingRadioPowerOffAfterDataOff = true; - } - Message msg = Message.obtain(this); - msg.what = EVENT_SET_RADIO_POWER_OFF; - msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag; - if (sendMessageDelayed(msg, 30000)) { - if (DBG) { - log("powerOffRadioSafely: Wait up to 30s for data to disconnect, " - + "then turn off radio."); - } - mPendingRadioPowerOffAfterDataOff = true; - } else { - log("powerOffRadioSafely: Cannot send delayed Msg, turn off radio right" - + " away."); - hangupAndPowerOff(); - mPendingRadioPowerOffAfterDataOff = false; - } + log("powerOffRadioSafely: No data is connected, turn off radio now."); + hangupAndPowerOff(); } } } @@ -5115,7 +4995,6 @@ public class ServiceStateTracker extends Handler { if (mPendingRadioPowerOffAfterDataOff) { if (DBG) log("Process pending request to turn radio off."); hangupAndPowerOff(); - mPendingRadioPowerOffAfterDataOffTag += 1; mPendingRadioPowerOffAfterDataOff = false; return true; } @@ -5348,7 +5227,6 @@ public class ServiceStateTracker extends Handler { pw.println(" mDesiredPowerState=" + mDesiredPowerState); pw.println(" mRestrictedState=" + mRestrictedState); pw.println(" mPendingRadioPowerOffAfterDataOff=" + mPendingRadioPowerOffAfterDataOff); - pw.println(" mPendingRadioPowerOffAfterDataOffTag=" + mPendingRadioPowerOffAfterDataOffTag); pw.println(" mCellIdentity=" + Rlog.pii(VDBG, mCellIdentity)); pw.println(" mLastCellInfoReqTime=" + mLastCellInfoReqTime); dumpCellInfoList(pw); diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java index dcbd2d5a95..08c02e2ea9 100644 --- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java +++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java @@ -27,7 +27,6 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.system.StructStatVfs; -import android.telephony.AccessNetworkConstants.TransportType; import android.text.TextUtils; import com.android.ims.ImsManager; @@ -40,9 +39,6 @@ import com.android.internal.telephony.data.DataServiceManager; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; -import com.android.internal.telephony.dataconnection.DcTracker; -import com.android.internal.telephony.dataconnection.TransportManager; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; @@ -313,10 +309,6 @@ public class TelephonyComponentFactory { return new SimActivationTracker(phone); } - public DcTracker makeDcTracker(Phone phone, @TransportType int transportType) { - return new DcTracker(phone, transportType); - } - public CarrierSignalAgent makeCarrierSignalAgent(Phone phone) { return new CarrierSignalAgent(phone); } @@ -404,10 +396,6 @@ public class TelephonyComponentFactory { return new DeviceStateMonitor(phone); } - public TransportManager makeTransportManager(Phone phone) { - return new TransportManager(phone); - } - /** * Make access networks manager * @@ -430,10 +418,6 @@ public class TelephonyComponentFactory { return new LocaleTracker(phone, nitzStateMachine, looper); } - public DataEnabledSettings makeDataEnabledSettings(Phone phone) { - return new DataEnabledSettings(phone); - } - public Phone makePhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory) { diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index 40cb6a8ec8..d34a387272 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -58,7 +58,6 @@ import android.util.SparseArray; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RIL; import com.android.internal.telephony.SlidingWindowEventCounter; -import com.android.internal.telephony.dataconnection.DataThrottler; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -67,7 +66,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -156,8 +154,6 @@ public class AccessNetworksManager extends Handler { private final RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList(); - private final Set mDataThrottlers = new HashSet<>(); - private final BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -174,20 +170,10 @@ public class AccessNetworksManager extends Handler { } }; - /** - * The current transport of the APN type. The key is the APN type, and the value is the - * transport. - */ - private final Map mCurrentTransports = new ConcurrentHashMap<>(); - /** * The preferred transport of the APN type. The key is the APN type, and the value is the - * transport. The preferred transports are updated as soon as QNS changes the preference, while - * the current transports are updated after handover complete. + * transport. The preferred transports are updated as soon as QNS changes the preference. */ - // TODO: Deprecate mPreferredTransports. Should expose mAvailableNetworks to - // DataNetworkController after we support multi preferred access networks (i.e. - // DataNetworkController might select 2nd preferred access network in some scenarios.) private final Map mPreferredTransports = new ConcurrentHashMap<>(); /** @@ -196,21 +182,6 @@ public class AccessNetworksManager extends Handler { private final @NonNull Set mAccessNetworksManagerCallbacks = new ArraySet<>(); - /** - * Registers the data throttler in order to receive APN status changes. - * - * @param dataThrottler the data throttler to register - */ - public void registerDataThrottler(DataThrottler dataThrottler) { - this.post(() -> { - QualifiedNetworksServiceConnection serviceConnection = mServiceConnection; - this.mDataThrottlers.add(dataThrottler); - if (serviceConnection != null) { - serviceConnection.registerDataThrottler(dataThrottler); - } - }); - } - /** * Represents qualified network types list on a specific APN type. */ @@ -252,18 +223,6 @@ public class AccessNetworksManager extends Handler { } private final class QualifiedNetworksServiceConnection implements ServiceConnection { - - /** - * The APN throttle status callback is attached to the service connection so that they have - * the same life cycle. - */ - @NonNull - private final ThrottleStatusChangedCallback mThrottleStatusCallback; - - QualifiedNetworksServiceConnection() { - mThrottleStatusCallback = new ThrottleStatusChangedCallback(); - } - @Override public void onServiceConnected(ComponentName name, IBinder service) { if (DBG) log("onServiceConnected " + name); @@ -275,9 +234,6 @@ public class AccessNetworksManager extends Handler { service.linkToDeath(mDeathRecipient, 0 /* flags */); mIQualifiedNetworksService.createNetworkAvailabilityProvider(mPhone.getPhoneId(), new QualifiedNetworksServiceCallback()); - - registerDataThrottlersFirstTime(); - } catch (RemoteException e) { loge("Remote exception. " + e); } @@ -286,55 +242,9 @@ public class AccessNetworksManager extends Handler { @Override public void onServiceDisconnected(ComponentName name) { if (DBG) log("onServiceDisconnected " + name); - unregisterForThrottleCallbacks(); mTargetBindingPackageName = null; } - /** - * Runs on all of the data throttlers when the service is connected - */ - private void registerDataThrottlersFirstTime() { - post(() -> { - for (DataThrottler dataThrottler : mDataThrottlers) { - dataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); - } - }); - } - - private void registerDataThrottler(DataThrottler dataThrottler) { - post(() -> { - dataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); - }); - } - - private void unregisterForThrottleCallbacks() { - post(() -> { - for (DataThrottler dataThrottler : mDataThrottlers) { - dataThrottler.unregisterForThrottleStatusChanges(mThrottleStatusCallback); - } - }); - } - } - - private class ThrottleStatusChangedCallback implements DataThrottler.Callback { - @Override - public void onThrottleStatusChanged(List throttleStatuses) { - post(() -> { - try { - List throttleStatusesBySlot = - throttleStatuses - .stream() - .filter(x -> x.getSlotIndex() == mPhone.getPhoneId()) - .collect(Collectors.toList()); - if (mIQualifiedNetworksService != null) { - mIQualifiedNetworksService.reportThrottleStatusChanged(mPhone.getPhoneId(), - throttleStatusesBySlot); - } - } catch (Exception ex) { - loge("onThrottleStatusChanged", ex); - } - }); - } } private final class QualifiedNetworksServiceCallback extends @@ -509,11 +419,10 @@ public class AccessNetworksManager extends Handler { bindQualifiedNetworksService(); } - if (phone.isUsingNewDataStack()) { - // Using post to delay the registering because data retry manager and data config - // manager instances are created later than access networks manager. - post(() -> { - mPhone.getDataNetworkController().getDataRetryManager().registerCallback( + // Using post to delay the registering because data retry manager and data config + // manager instances are created later than access networks manager. + post(() -> { + mPhone.getDataNetworkController().getDataRetryManager().registerCallback( new DataRetryManager.DataRetryManagerCallback(this::post) { @Override public void onThrottleStatusChanged(List throttleStatuses) { @@ -528,16 +437,15 @@ public class AccessNetworksManager extends Handler { } } }); - mDataConfigManager = mPhone.getDataNetworkController().getDataConfigManager(); - mDataConfigManager.registerCallback( - new DataConfigManager.DataConfigManagerCallback(this::post) { - @Override - public void onDeviceConfigChanged() { - mApnTypeToQnsChangeNetworkCounter.clear(); - } - }); - }); - } + mDataConfigManager = mPhone.getDataNetworkController().getDataConfigManager(); + mDataConfigManager.registerCallback( + new DataConfigManager.DataConfigManagerCallback(this::post) { + @Override + public void onDeviceConfigChanged() { + mApnTypeToQnsChangeNetworkCounter.clear(); + } + }); + }); } /** @@ -717,60 +625,6 @@ public class AccessNetworksManager extends Handler { return mAvailableTransports; } - /** - * Get the transport based on the network capability. - * - * @param netCap The network capability. - * @return The transport type. - */ - public @TransportType int getCurrentTransportByNetworkCapability(@NetCapability int netCap) { - return getCurrentTransport(DataUtils.networkCapabilityToApnType(netCap)); - } - - /** - * Get the transport based on the APN type. - * - * @param apnType APN type - * @return The transport type - */ - // TODO: Remove this after TransportManager is removed. - public @TransportType int getCurrentTransport(@ApnType int apnType) { - // In legacy mode, always route to cellular. - if (isInLegacyMode()) { - return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - } - - // If we can't find the corresponding transport, always route to cellular. - return mCurrentTransports.get(apnType) == null - ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mCurrentTransports.get(apnType); - } - - /** - * Set the current transport of a network capability. - * - * @param netCap The network capability. - * @param transport The transport. - */ - public void setCurrentTransportByNetworkCapability(@NetCapability int netCap, - @TransportType int transport) { - setCurrentTransport(DataUtils.networkCapabilityToApnType(netCap), transport); - } - - /** - * Set the current transport of apn type. - * - * @param apnType The APN type - * @param transport The transport. - */ - // TODO: Remove this after TransportManager is removed. - public void setCurrentTransport(@ApnType int apnType, @TransportType int transport) { - Integer previousTransport = mCurrentTransports.put(apnType, transport); - if (previousTransport == null || previousTransport != transport) { - logl("setCurrentTransport: apnType=" + ApnSetting.getApnTypeString(apnType) - + ", transport=" + AccessNetworkConstants.transportTypeToString(transport)); - } - } - private static @TransportType int getTransportFromAccessNetwork(int accessNetwork) { return accessNetwork == AccessNetworkType.IWLAN ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN @@ -829,20 +683,14 @@ public class AccessNetworksManager extends Handler { } /** - * Check if there is any APN type's current transport is on IWLAN. + * Check if there is any APN type preferred on IWLAN. * * @return {@code true} if there is any APN is on IWLAN, otherwise {@code false}. */ public boolean isAnyApnOnIwlan() { for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { - if (mPhone.isUsingNewDataStack()) { - if (getPreferredTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - return true; - } - } else { - if (getCurrentTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - return true; - } + if (getPreferredTransport(apnType) == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { + return true; } } return false; @@ -906,14 +754,6 @@ public class AccessNetworksManager extends Handler { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println(AccessNetworksManager.class.getSimpleName() + "-" + mPhone.getPhoneId() + ":"); pw.increaseIndent(); - pw.println("current transports="); - pw.increaseIndent(); - for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { - pw.println(ApnSetting.getApnTypeString(apnType) - + ": " + AccessNetworkConstants.transportTypeToString( - getCurrentTransport(apnType))); - } - pw.decreaseIndent(); pw.println("preferred transports="); pw.increaseIndent(); for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index ae069fe227..26dab0ebe2 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -134,8 +134,7 @@ public class DataConfigManager extends Handler { private static final String DATA_CONFIG_NETWORK_TYPE_IDEN = "iDEN"; /** Network type LTE. Should not be used outside of DataConfigManager. */ - // TODO: Public only for use by DcTracker. This should be private once DcTracker is removed. - public static final String DATA_CONFIG_NETWORK_TYPE_LTE = "LTE"; + private static final String DATA_CONFIG_NETWORK_TYPE_LTE = "LTE"; /** Network type HSPA+. Should not be used outside of DataConfigManager. */ private static final String DATA_CONFIG_NETWORK_TYPE_HSPAP = "HSPA+"; @@ -153,12 +152,10 @@ public class DataConfigManager extends Handler { private static final String DATA_CONFIG_NETWORK_TYPE_LTE_CA = "LTE_CA"; /** Network type NR_NSA. Should not be used outside of DataConfigManager. */ - // TODO: Public only for use by DcTracker. This should be private once DcTracker is removed. - public static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA = "NR_NSA"; + private static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA = "NR_NSA"; /** Network type NR_NSA_MMWAVE. Should not be used outside of DataConfigManager. */ - // TODO: Public only for use by DcTracker. This should be private once DcTracker is removed. - public static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE = "NR_NSA_MMWAVE"; + private static final String DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE = "NR_NSA_MMWAVE"; /** Network type NR_SA. Should not be used outside of DataConfigManager. */ private static final String DATA_CONFIG_NETWORK_TYPE_NR_SA = "NR_SA"; @@ -1002,9 +999,8 @@ public class DataConfigManager extends Handler { * @param displayInfo The {@link TelephonyDisplayInfo} used to determine the type. * @return The equivalent {@link DataConfigNetworkType}. */ - public static @NonNull @DataConfigNetworkType String getDataConfigNetworkType( + private static @NonNull @DataConfigNetworkType String getDataConfigNetworkType( @NonNull TelephonyDisplayInfo displayInfo) { - // TODO: Make method private once DataConnection is removed int networkType = displayInfo.getNetworkType(); switch (displayInfo.getOverrideNetworkType()) { case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED: diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index c225b3f2ad..fbeabc1d7b 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -32,8 +32,6 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Message; import android.os.OutcomeReceiver; -import android.os.Registrant; -import android.os.RegistrantList; import android.preference.PreferenceManager; import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.DataActivityType; @@ -191,7 +189,6 @@ public class LinkBandwidthEstimator extends Handler { private String mBandwidthUpdatePlmn = UNKNOWN_PLMN; private BandwidthState mTxState = new BandwidthState(LINK_TX); private BandwidthState mRxState = new BandwidthState(LINK_RX); - private RegistrantList mBandwidthChangedRegistrants = new RegistrantList(); private long mLastPlmnOrRatChangeTimeMs; private long mLastDrsOrRatChangeTimeMs; @@ -350,33 +347,6 @@ public class LinkBandwidthEstimator extends Handler { } } - /** - * Registers for bandwidth estimation change. The bandwidth will be returned - * * {@link AsyncResult#result} as a {@link Pair} Object. - * * The {@link AsyncResult} will be in the notification {@link Message#obj}. - * @param h handler to notify - * @param what what code of message when delivered - * @param obj placed in Message.obj - * - * @deprecated Use {@link #registerCallback(LinkBandwidthEstimatorCallback)}. - */ - @Deprecated //TODO: Remove once old data stack is removed. - public void registerForBandwidthChanged(Handler h, int what, Object obj) { - Registrant r = new Registrant(h, what, obj); - mBandwidthChangedRegistrants.add(r); - } - - /** - * Unregisters for bandwidth estimation change. - * @param h handler to notify - * - * @deprecated Use {@link #unregisterCallback(LinkBandwidthEstimatorCallback)}. - */ - @Deprecated //TODO: Remove once old data stack is removed. - public void unregisterForBandwidthChanged(Handler h) { - mBandwidthChangedRegistrants.remove(h); - } - /** * Register the callback for receiving information from {@link LinkBandwidthEstimator}. * @@ -930,9 +900,6 @@ public class LinkBandwidthEstimator extends Handler { private void sendLinkBandwidthToDataConnection(int linkBandwidthTxKps, int linkBandwidthRxKps) { logv("send to DC tx " + linkBandwidthTxKps + " rx " + linkBandwidthRxKps); - Pair bandwidthInfo = - new Pair(linkBandwidthTxKps, linkBandwidthRxKps); - mBandwidthChangedRegistrants.notifyRegistrants(new AsyncResult(null, bandwidthInfo, null)); mLinkBandwidthEstimatorCallbacks.forEach(callback -> callback.invokeFromExecutor( () -> callback.onBandwidthChanged(linkBandwidthTxKps, linkBandwidthRxKps))); } diff --git a/src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java b/src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java deleted file mode 100644 index 554177ad2c..0000000000 --- a/src/java/com/android/internal/telephony/data/NotifyQosSessionInterface.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2021 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.data; - -import android.annotation.NonNull; -import android.net.NetworkAgent; -import android.net.QosSessionAttributes; - -/** - * The temporary interface that is shared by - * {@link com.android.internal.telephony.dataconnection.DcNetworkAgent} and - * {@link com.android.internal.telephony.data.TelephonyNetworkAgent} so they can both interact - * with {@link QosCallbackTracker}. - */ -// TODO: Remove after DcNetworkAgent is removed. -public interface NotifyQosSessionInterface { - /** - * Sends the attributes of Qos Session back to the Application. This method is create for - * Mockito to mock since - * {@link NetworkAgent#sendQosSessionAvailable(int, int, QosSessionAttributes)} is - * {@code final} that can't be mocked. - * - * @param qosCallbackId the callback id that the session belongs to. - * @param sessionId the unique session id across all Qos Sessions. - * @param attributes the attributes of the Qos Session. - */ - void notifyQosSessionAvailable(int qosCallbackId, int sessionId, - @NonNull QosSessionAttributes attributes); - - /** - * Sends event that the Qos Session was lost. This method is create for Mockito to mock - * since {@link NetworkAgent#sendQosSessionLost(int, int, int)} is {@code final} that can't be - * mocked.. - * - * @param qosCallbackId the callback id that the session belongs to. - * @param sessionId the unique session id across all Qos Sessions. - * @param qosSessionType the session type {@code QosSession#QosSessionType}. - */ - void notifyQosSessionLost(int qosCallbackId, int sessionId, int qosSessionType); -} diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 5bd4de9d44..6370c21bad 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -83,8 +83,6 @@ import com.android.internal.telephony.SubscriptionController.WatchedInt; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; -import com.android.internal.telephony.dataconnection.ApnConfigTypeRepository; -import com.android.internal.telephony.dataconnection.DcRequest; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch; @@ -96,7 +94,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -182,7 +179,6 @@ public class PhoneSwitcher extends Handler { } } - protected final List mPrioritizedDcRequests = new ArrayList<>(); private final @NonNull NetworkRequestList mNetworkRequestList = new NetworkRequestList(); protected final RegistrantList mActivePhoneRegistrants; protected final SubscriptionController mSubscriptionController; @@ -507,21 +503,16 @@ public class PhoneSwitcher extends Handler { phone.getImsPhone().registerForPreciseCallStateChanged( this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } - if (phone.isUsingNewDataStack()) { - mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), - v -> new DataSettingsManagerCallback(this::post) { - @Override - public void onDataEnabledChanged(boolean enabled, - @TelephonyManager.DataEnabledChangedReason int reason, - @NonNull String callingPackage) { - evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); - }}); - phone.getDataSettingsManager().registerCallback( - mDataSettingsManagerCallbacks.get(phone.getPhoneId())); - } else { - phone.getDataEnabledSettings().registerForDataEnabledChanged( - this, EVENT_DATA_ENABLED_CHANGED, null); - } + mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), + v -> new DataSettingsManagerCallback(this::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @TelephonyManager.DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); + }}); + phone.getDataSettingsManager().registerCallback( + mDataSettingsManagerCallbacks.get(phone.getPhoneId())); registerForImsRadioTechChange(context, i); } @@ -880,22 +871,17 @@ public class PhoneSwitcher extends Handler { this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } - if (phone.isUsingNewDataStack()) { - mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), - v -> new DataSettingsManagerCallback(this::post) { - @Override - public void onDataEnabledChanged(boolean enabled, - @TelephonyManager.DataEnabledChangedReason int reason, - @NonNull String callingPackage) { - evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); - } - }); - phone.getDataSettingsManager().registerCallback( - mDataSettingsManagerCallbacks.get(phone.getPhoneId())); - } else { - phone.getDataEnabledSettings().registerForDataEnabledChanged( - this, EVENT_DATA_ENABLED_CHANGED, null); - } + mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), + v -> new DataSettingsManagerCallback(this::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @TelephonyManager.DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); + } + }); + phone.getDataSettingsManager().registerCallback( + mDataSettingsManagerCallbacks.get(phone.getPhoneId())); Set ddsFailure = new HashSet(); mCurrentDdsSwitchFailure.add(ddsFailure); @@ -941,62 +927,21 @@ public class PhoneSwitcher extends Handler { } private void onRequestNetwork(NetworkRequest networkRequest) { - if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { - TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( - networkRequest, PhoneFactory.getDefaultPhone()); - if (!mNetworkRequestList.contains(telephonyNetworkRequest)) { - mNetworkRequestList.add(telephonyNetworkRequest); - onEvaluate(REQUESTS_CHANGED, "netRequest"); - } - return; - } - final DcRequest dcRequest = - DcRequest.create(networkRequest, createApnRepository(networkRequest)); - if (dcRequest != null) { - if (!mPrioritizedDcRequests.contains(dcRequest)) { - collectRequestNetworkMetrics(networkRequest); - mPrioritizedDcRequests.add(dcRequest); - Collections.sort(mPrioritizedDcRequests); - onEvaluate(REQUESTS_CHANGED, "netRequest"); - if (VDBG) log("Added DcRequest, size: " + mPrioritizedDcRequests.size()); - } + TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( + networkRequest, PhoneFactory.getDefaultPhone()); + if (!mNetworkRequestList.contains(telephonyNetworkRequest)) { + mNetworkRequestList.add(telephonyNetworkRequest); + onEvaluate(REQUESTS_CHANGED, "netRequest"); } } private void onReleaseNetwork(NetworkRequest networkRequest) { - if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { - TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( - networkRequest, PhoneFactory.getDefaultPhone()); - if (mNetworkRequestList.remove(telephonyNetworkRequest)) { - onEvaluate(REQUESTS_CHANGED, "netReleased"); - collectReleaseNetworkMetrics(networkRequest); - } - return; - } - final DcRequest dcRequest = - DcRequest.create(networkRequest, createApnRepository(networkRequest)); - if (dcRequest != null) { - if (mPrioritizedDcRequests.remove(dcRequest)) { - onEvaluate(REQUESTS_CHANGED, "netReleased"); - collectReleaseNetworkMetrics(networkRequest); - if (VDBG) log("Removed DcRequest, size: " + mPrioritizedDcRequests.size()); - } - } - } - - private ApnConfigTypeRepository createApnRepository(NetworkRequest networkRequest) { - int phoneIdForRequest = phoneIdForRequest(networkRequest); - int subId = mSubscriptionController.getSubIdUsingPhoneId(phoneIdForRequest); - CarrierConfigManager configManager = (CarrierConfigManager) mContext - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - - PersistableBundle carrierConfig; - if (configManager != null) { - carrierConfig = configManager.getConfigForSubId(subId); - } else { - carrierConfig = null; + TelephonyNetworkRequest telephonyNetworkRequest = new TelephonyNetworkRequest( + networkRequest, PhoneFactory.getDefaultPhone()); + if (mNetworkRequestList.remove(telephonyNetworkRequest)) { + onEvaluate(REQUESTS_CHANGED, "netReleased"); + collectReleaseNetworkMetrics(networkRequest); } - return new ApnConfigTypeRepository(carrierConfig); } private void removeDefaultNetworkChangeCallback() { @@ -1147,22 +1092,12 @@ public class PhoneSwitcher extends Handler { } if (newActivePhones.size() < mMaxDataAttachModemCount) { - if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { - for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { - int phoneIdForRequest = phoneIdForRequest(networkRequest); - if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; - if (newActivePhones.contains(phoneIdForRequest)) continue; - newActivePhones.add(phoneIdForRequest); - if (newActivePhones.size() >= mMaxDataAttachModemCount) break; - } - } else { - for (DcRequest dcRequest : mPrioritizedDcRequests) { - int phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); - if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; - if (newActivePhones.contains(phoneIdForRequest)) continue; - newActivePhones.add(phoneIdForRequest); - if (newActivePhones.size() >= mMaxDataAttachModemCount) break; - } + for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { + int phoneIdForRequest = phoneIdForRequest(networkRequest); + if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; + if (newActivePhones.contains(phoneIdForRequest)) continue; + newActivePhones.add(phoneIdForRequest); + if (newActivePhones.size() >= mMaxDataAttachModemCount) break; } } @@ -1291,13 +1226,8 @@ public class PhoneSwitcher extends Handler { } } - // Merge phoneIdForRequest(NetworkRequest netRequest) after Phone.isUsingNewDataStack() is - // cleaned up. private int phoneIdForRequest(TelephonyNetworkRequest networkRequest) { - return phoneIdForRequest(networkRequest.getNativeNetworkRequest()); - } - - private int phoneIdForRequest(NetworkRequest netRequest) { + NetworkRequest netRequest = networkRequest.getNativeNetworkRequest(); int subId = getSubIdFromNetworkSpecifier(netRequest.getNetworkSpecifier()); if (subId == DEFAULT_SUBSCRIPTION_ID) return mPreferredDataPhoneId; @@ -1355,13 +1285,8 @@ public class PhoneSwitcher extends Handler { Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); boolean isDataEnabled = false; if (voicePhone != null) { - if (voicePhone.isUsingNewDataStack()) { - isDataEnabled = voicePhone.getDataSettingsManager() - .isDataEnabled(ApnSetting.TYPE_DEFAULT); - } else { - isDataEnabled = voicePhone.getDataEnabledSettings() - .isDataEnabled(ApnSetting.TYPE_DEFAULT); - } + isDataEnabled = voicePhone.getDataSettingsManager() + .isDataEnabled(ApnSetting.TYPE_DEFAULT); } if (mEmergencyOverride != null && findPhoneById(mEmergencyOverride.mPhoneId) != null) { @@ -1832,25 +1757,11 @@ public class PhoneSwitcher extends Handler { if (ddsPhoneId != INVALID_PHONE_INDEX && ddsPhoneId == phoneId) { return true; } else { - if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { - if (mNetworkRequestList.isEmpty()) return false; - for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { - phoneIdForRequest = phoneIdForRequest(networkRequest); - if (phoneIdForRequest == phoneId) { - return true; - } - } - } else { - if (mPrioritizedDcRequests.size() == 0) { - return false; - } - for (DcRequest dcRequest : mPrioritizedDcRequests) { - if (dcRequest != null) { - phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); - if (phoneIdForRequest == phoneId) { - return true; - } - } + if (mNetworkRequestList.isEmpty()) return false; + for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { + phoneIdForRequest = phoneIdForRequest(networkRequest); + if (phoneIdForRequest == phoneId) { + return true; } } } diff --git a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java index bde24df4db..b6c2038a4a 100644 --- a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java +++ b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java @@ -54,8 +54,7 @@ public class QosCallbackTracker extends Handler { private static final int DEDICATED_BEARER_EVENT_STATE_DELETED = 3; private final @NonNull String mLogTag; - // TODO: Change this to TelephonyNetworkAgent - private final @NonNull NotifyQosSessionInterface mNetworkAgent; + private final @NonNull TelephonyNetworkAgent mNetworkAgent; private final @NonNull Map mQosBearerSessions; private final @NonNull RcsStats mRcsStats; @@ -95,8 +94,7 @@ public class QosCallbackTracker extends Handler { * @param networkAgent The network agent to send events to. * @param phone The phone instance. */ - public QosCallbackTracker(@NonNull NotifyQosSessionInterface networkAgent, - @NonNull Phone phone) { + public QosCallbackTracker(@NonNull TelephonyNetworkAgent networkAgent, @NonNull Phone phone) { mQosBearerSessions = new HashMap<>(); mCallbacksToFilter = new HashMap<>(); mNetworkAgent = networkAgent; @@ -104,40 +102,36 @@ public class QosCallbackTracker extends Handler { mRcsStats = RcsStats.getInstance(); mLogTag = "QOSCT" + "-" + ((NetworkAgent) mNetworkAgent).getNetwork().getNetId(); - if (phone.isUsingNewDataStack()) { - //TODO: Replace the NetworkAgent in the constructor with TelephonyNetworkAgent - // after mPhone.isUsingNewDataStack() check is removed. - ((TelephonyNetworkAgent) networkAgent).registerCallback( - new TelephonyNetworkAgent.TelephonyNetworkAgentCallback(this::post) { - @Override - public void onQosCallbackRegistered(int qosCallbackId, - @NonNull QosFilter filter) { - addFilter(qosCallbackId, - new QosCallbackTracker.IFilter() { - @Override - public boolean matchesLocalAddress( - @NonNull InetAddress address, int startPort, - int endPort) { - return filter.matchesLocalAddress(address, startPort, - endPort); - } - - @Override - public boolean matchesRemoteAddress( - @NonNull InetAddress address, int startPort, - int endPort) { - return filter.matchesRemoteAddress(address, startPort, - endPort); - } - }); - } + networkAgent.registerCallback( + new TelephonyNetworkAgent.TelephonyNetworkAgentCallback(this::post) { + @Override + public void onQosCallbackRegistered(int qosCallbackId, + @NonNull QosFilter filter) { + addFilter(qosCallbackId, + new QosCallbackTracker.IFilter() { + @Override + public boolean matchesLocalAddress( + @NonNull InetAddress address, int startPort, + int endPort) { + return filter.matchesLocalAddress(address, startPort, + endPort); + } + + @Override + public boolean matchesRemoteAddress( + @NonNull InetAddress address, int startPort, + int endPort) { + return filter.matchesRemoteAddress(address, startPort, + endPort); + } + }); + } - @Override - public void onQosCallbackUnregistered(int qosCallbackId) { + @Override + public void onQosCallbackUnregistered(int qosCallbackId) { - } - }); - } + } + }); } /** @@ -395,7 +389,7 @@ public class QosCallbackTracker extends Handler { qos.getDownlinkBandwidth().getGuaranteedBitrateKbps(), qos.getUplinkBandwidth().getGuaranteedBitrateKbps(), remoteAddresses); - mNetworkAgent.notifyQosSessionAvailable( + mNetworkAgent.sendQosSessionAvailable( callbackId, session.getQosBearerSessionId(), epsBearerAttr); } else { NrQos qos = (NrQos) session.getQos(); @@ -406,7 +400,7 @@ public class QosCallbackTracker extends Handler { qos.getDownlinkBandwidth().getGuaranteedBitrateKbps(), qos.getUplinkBandwidth().getGuaranteedBitrateKbps(), qos.getAveragingWindow(), remoteAddresses); - mNetworkAgent.notifyQosSessionAvailable( + mNetworkAgent.sendQosSessionAvailable( callbackId, session.getQosBearerSessionId(), nrQosAttr); } @@ -417,7 +411,7 @@ public class QosCallbackTracker extends Handler { } private void sendSessionLost(int callbackId, @NonNull QosBearerSession session) { - mNetworkAgent.notifyQosSessionLost(callbackId, session.getQosBearerSessionId(), + mNetworkAgent.sendQosSessionLost(callbackId, session.getQosBearerSessionId(), session.getQos() instanceof EpsQos ? QosSession.TYPE_EPS_BEARER : QosSession.TYPE_NR_BEARER); log("sendSessionLost, callbackId=" + callbackId); diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java index b74396bc58..78c555c4b0 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java @@ -26,7 +26,6 @@ import android.net.NetworkCapabilities; import android.net.NetworkProvider; import android.net.NetworkScore; import android.net.QosFilter; -import android.net.QosSessionAttributes; import android.net.Uri; import android.os.Looper; import android.util.ArraySet; @@ -47,9 +46,8 @@ import java.util.concurrent.Executor; * for telephony to propagate network related information to the connectivity service. It always * has an associated parent {@link DataNetwork}. */ -public class TelephonyNetworkAgent extends NetworkAgent implements NotifyQosSessionInterface { +public class TelephonyNetworkAgent extends NetworkAgent { private final String mLogTag; - private final Phone mPhone; private final LocalLog mLocalLog = new LocalLog(128); /** The parent data network. */ @@ -166,7 +164,6 @@ public class TelephonyNetworkAgent extends NetworkAgent implements NotifyQosSess mDataNetwork = dataNetwork; mNetworkAgentConfig = config; mTelephonyNetworkAgentCallbacks.add(callback); - mPhone = phone; mId = getNetwork().getNetId(); mLogTag = "TNA-" + mId; @@ -297,37 +294,6 @@ public class TelephonyNetworkAgent extends NetworkAgent implements NotifyQosSess () -> callback.onQosCallbackUnregistered(qosCallbackId))); } - /** - * Sends the attributes of Qos Session back to the Application. This method is create for - * Mockito to mock since - * {@link NetworkAgent#sendQosSessionAvailable(int, int, QosSessionAttributes)} is - * {@code final} that can't be mocked. - * - * @param qosCallbackId the callback id that the session belongs to. - * @param sessionId the unique session id across all Qos Sessions. - * @param attributes the attributes of the Qos Session. - */ - @Override - public void notifyQosSessionAvailable(final int qosCallbackId, final int sessionId, - @NonNull final QosSessionAttributes attributes) { - super.sendQosSessionAvailable(qosCallbackId, sessionId, attributes); - } - - /** - * Sends event that the Qos Session was lost. This method is create for Mockito to mock - * since {@link NetworkAgent#sendQosSessionLost(int, int, int)} is {@code final} that can't be - * mocked.. - * - * @param qosCallbackId the callback id that the session belongs to. - * @param sessionId the unique session id across all Qos Sessions. - * @param qosSessionType the session type {@code QosSession#QosSessionType}. - */ - @Override - public void notifyQosSessionLost(final int qosCallbackId, - final int sessionId, final int qosSessionType) { - super.sendQosSessionLost(qosCallbackId, sessionId, qosSessionType); - } - /** * Abandon the network agent. This is used for telephony to re-create the network agent when * immutable capabilities got changed, where telephony calls {@link NetworkAgent#unregister()} diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java index 85f0ae1f0d..e64dd9b7c0 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java @@ -20,27 +20,16 @@ import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; -import android.os.AsyncResult; -import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.telephony.AccessNetworkConstants; -import android.telephony.Annotation.ApnType; import android.telephony.SubscriptionManager; -import android.telephony.data.ApnSetting; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; -import com.android.internal.telephony.dataconnection.ApnContext; -import com.android.internal.telephony.dataconnection.DataConnection; -import com.android.internal.telephony.dataconnection.DcTracker; -import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; -import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; -import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams; import com.android.internal.telephony.metrics.NetworkRequestsStats; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -72,19 +61,15 @@ public class TelephonyNetworkFactory extends NetworkFactory { public static final int EVENT_SUBSCRIPTION_CHANGED = 2; private static final int EVENT_NETWORK_REQUEST = 3; private static final int EVENT_NETWORK_RELEASE = 4; - private static final int EVENT_DATA_HANDOVER_NEEDED = 5; - private static final int EVENT_DATA_HANDOVER_COMPLETED = 6; private final PhoneSwitcher mPhoneSwitcher; private final SubscriptionController mSubscriptionController; private final LocalLog mLocalLog = new LocalLog(REQUEST_LOG_SIZE); - // Key: network request. Value: the transport of DcTracker it applies to, + // Key: network request. Value: the transport of the network request applies to, // AccessNetworkConstants.TRANSPORT_TYPE_INVALID if not applied. private final Map mNetworkRequests = new HashMap<>(); - private final Map mPendingHandovers = new HashMap<>(); - private final Phone mPhone; private AccessNetworksManager mAccessNetworksManager; @@ -112,10 +97,6 @@ public class TelephonyNetworkFactory extends NetworkFactory { mPhoneSwitcher.registerForActivePhoneSwitch(mInternalHandler, EVENT_ACTIVE_PHONE_SWITCH, null); - if (!phone.isUsingNewDataStack()) { - mPhone.getTransportManager().registerForHandoverNeededEvent(mInternalHandler, - EVENT_DATA_HANDOVER_NEEDED); - } mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; SubscriptionManager.from(mPhone.getContext()).addOnSubscriptionsChangedListener( @@ -201,93 +182,18 @@ public class TelephonyNetworkFactory extends NetworkFactory { onReleaseNetworkFor(msg); break; } - case EVENT_DATA_HANDOVER_NEEDED: { - AsyncResult ar = (AsyncResult) msg.obj; - HandoverParams handoverParams = (HandoverParams) ar.result; - onDataHandoverNeeded(handoverParams.apnType, handoverParams.targetTransport, - handoverParams); - break; - } - case EVENT_DATA_HANDOVER_COMPLETED: { - Bundle bundle = msg.getData(); - NetworkRequest nr = bundle.getParcelable( - DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST); - boolean success = bundle.getBoolean( - DcTracker.DATA_COMPLETE_MSG_EXTRA_SUCCESS); - int transport = bundle.getInt( - DcTracker.DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE); - boolean fallback = bundle.getBoolean( - DcTracker.DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK); - HandoverParams handoverParams = mPendingHandovers.remove(msg); - if (handoverParams != null) { - onDataHandoverSetupCompleted(nr, success, transport, fallback, - handoverParams); - } else { - logl("Handover completed but cannot find handover entry!"); - } - break; - } } } } private int getTransportTypeFromNetworkRequest(TelephonyNetworkRequest networkRequest) { - if (PhoneFactory.getDefaultPhone().isUsingNewDataStack()) { - int transport = AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - int capability = networkRequest.getApnTypeNetworkCapability(); - if (capability >= 0) { - transport = mAccessNetworksManager - .getPreferredTransportByNetworkCapability(capability); - } - return transport; - } else { - int apnType = ApnContext.getApnTypeFromNetworkRequest( - networkRequest.getNativeNetworkRequest()); - return mAccessNetworksManager.getCurrentTransport(apnType); - } - } - - /** - * Request network - * - * @param networkRequest Network request from clients - * @param requestType The request type - * @param transport Transport type - * @param onHandoverCompleteMsg When request type is handover, this message will be sent when - * handover is completed. For normal request, this should be null. - */ - private void requestNetworkInternal(TelephonyNetworkRequest networkRequest, - @RequestNetworkType int requestType, int transport, Message onHandoverCompleteMsg) { - NetworkRequestsStats.addNetworkRequest(networkRequest.getNativeNetworkRequest(), - mSubscriptionId); - - if (mPhone.isUsingNewDataStack()) { - mPhone.getDataNetworkController().addNetworkRequest(networkRequest); - } else { - if (mPhone.getDcTracker(transport) != null) { - mPhone.getDcTracker(transport).requestNetwork( - networkRequest.getNativeNetworkRequest(), requestType, - onHandoverCompleteMsg); - } - } - } - - private void releaseNetworkInternal(TelephonyNetworkRequest networkRequest) { - mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); - } - - // TODO: Clean this up after old data stack removed. - private void releaseNetworkInternal(TelephonyNetworkRequest networkRequest, - @ReleaseNetworkType int releaseType, - int transport) { - if (mPhone.isUsingNewDataStack()) { - mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); - } else { - if (mPhone.getDcTracker(transport) != null) { - mPhone.getDcTracker(transport).releaseNetwork( - networkRequest.getNativeNetworkRequest(), releaseType); - } + int transport = AccessNetworkConstants.TRANSPORT_TYPE_WWAN; + int capability = networkRequest.getApnTypeNetworkCapability(); + if (capability >= 0) { + transport = mAccessNetworksManager + .getPreferredTransportByNetworkCapability(capability); } + return transport; } private static int getAction(boolean wasActive, boolean isActive) { @@ -317,15 +223,11 @@ public class TelephonyNetworkFactory extends NetworkFactory { ? "Requesting" : "Releasing") + " network request " + networkRequest); int transportType = getTransportTypeFromNetworkRequest(networkRequest); if (action == ACTION_REQUEST) { - requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, - getTransportTypeFromNetworkRequest(networkRequest), null); + NetworkRequestsStats.addNetworkRequest(networkRequest.getNativeNetworkRequest(), + mSubscriptionId); + mPhone.getDataNetworkController().addNetworkRequest(networkRequest); } else if (action == ACTION_RELEASE) { - if (mPhone.isUsingNewDataStack()) { - releaseNetworkInternal(networkRequest); - } else { - releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_DETACH, - getTransportTypeFromNetworkRequest(networkRequest)); - } + mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); } mNetworkRequests.put(networkRequest, @@ -365,8 +267,9 @@ public class TelephonyNetworkFactory extends NetworkFactory { logl("onNeedNetworkFor " + networkRequest + " shouldApply " + shouldApply); if (shouldApply) { - requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, - getTransportTypeFromNetworkRequest(networkRequest), null); + NetworkRequestsStats.addNetworkRequest(networkRequest.getNativeNetworkRequest(), + mSubscriptionId); + mPhone.getDataNetworkController().addNetworkRequest(networkRequest); } } @@ -388,134 +291,8 @@ public class TelephonyNetworkFactory extends NetworkFactory { logl("onReleaseNetworkFor " + networkRequest + " applied " + applied); if (applied) { - if (mPhone.isUsingNewDataStack()) { - releaseNetworkInternal(networkRequest); - } else { - // Most of the time, the network request only exists in one of the DcTracker, but in - // the middle of handover, the network request temporarily exists in both - // DcTrackers. If connectivity service releases the network request while handover - // is ongoing, we need to remove network requests from both DcTrackers. - // Note that this part will be refactored in T, where we won't even have DcTracker - // at all. - releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - } - } - } - - private void onDataHandoverNeeded(@ApnType int apnType, int targetTransport, - HandoverParams handoverParams) { - log("onDataHandoverNeeded: apnType=" + ApnSetting.getApnTypeString(apnType) - + ", target transport=" - + AccessNetworkConstants.transportTypeToString(targetTransport)); - if (mAccessNetworksManager.getCurrentTransport(apnType) == targetTransport) { - log("APN type " + ApnSetting.getApnTypeString(apnType) + " is already on " - + AccessNetworkConstants.transportTypeToString(targetTransport)); - return; - } - - boolean handoverPending = false; - for (Map.Entry entry : mNetworkRequests.entrySet()) { - TelephonyNetworkRequest networkRequest = entry.getKey(); - int currentTransport = entry.getValue(); - boolean applied = currentTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID; - if (ApnContext.getApnTypeFromNetworkRequest( - networkRequest.getNativeNetworkRequest()) == apnType - && applied - && currentTransport != targetTransport) { - DcTracker dcTracker = mPhone.getDcTracker(currentTransport); - if (dcTracker != null) { - DataConnection dc = dcTracker.getDataConnectionByApnType( - ApnSetting.getApnTypeString(apnType)); - if (dc != null && (dc.isActive())) { - Message onCompleteMsg = mInternalHandler.obtainMessage( - EVENT_DATA_HANDOVER_COMPLETED); - onCompleteMsg.getData().putParcelable( - DcTracker.DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST, - networkRequest.getNativeNetworkRequest()); - mPendingHandovers.put(onCompleteMsg, handoverParams); - requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_HANDOVER, - targetTransport, onCompleteMsg); - log("Requested handover " + ApnSetting.getApnTypeString(apnType) - + " to " - + AccessNetworkConstants.transportTypeToString(targetTransport) - + ". " + networkRequest); - handoverPending = true; - } else { - // Request is there, but no actual data connection. In this case, just move - // the request to the new transport. - log("The network request is on transport " + AccessNetworkConstants - .transportTypeToString(currentTransport) + ", but no live data " - + "connection. Just move the request to transport " - + AccessNetworkConstants.transportTypeToString(targetTransport) - + ", dc=" + dc); - entry.setValue(targetTransport); - releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL, - currentTransport); - requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL, - targetTransport, null); - } - } else { - log("DcTracker on " + AccessNetworkConstants.transportTypeToString( - currentTransport) + " is not available."); - } - } - } - - if (!handoverPending) { - log("No handover request pending. Handover process is now completed"); - handoverParams.callback.onCompleted(true, false); - } - } - - private void onDataHandoverSetupCompleted(NetworkRequest request, boolean success, - int targetTransport, boolean fallback, - HandoverParams handoverParams) { - log("onDataHandoverSetupCompleted: " + request + ", success=" + success - + ", targetTransport=" - + AccessNetworkConstants.transportTypeToString(targetTransport) - + ", fallback=" + fallback); - - TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest(request, mPhone); - // At this point, handover setup has been completed on the target transport. - // If it succeeded, or it failed without falling back to the original transport, - // we should release the request from the original transport. - if (!fallback) { - int originTransport = DataUtils.getSourceTransport(targetTransport); - int releaseType = success - ? DcTracker.RELEASE_TYPE_HANDOVER - // If handover fails, we need to tear down the existing connection, so the - // new data connection can be re-established on the new transport. If we leave - // the existing data connection in current transport, then DCT and qualified - // network service will be out of sync. Specifying release type to detach - // the transport is moved to the other transport, but network request is still - // there, connectivity service will not call unwanted to tear down the network. - // We need explicitly tear down the data connection here so the new data - // connection can be re-established on the other transport. - : DcTracker.RELEASE_TYPE_DETACH; - releaseNetworkInternal(networkRequest, releaseType, originTransport); - - // Before updating the network request with the target transport, make sure the request - // is still there because it's possible that connectivity service has already released - // the network while handover is ongoing. If connectivity service already released - // the network request, we need to tear down the just-handovered data connection on the - // target transport. - if (mNetworkRequests.containsKey(networkRequest)) { - // Update it with the target transport. - mNetworkRequests.put(networkRequest, targetTransport); - } - } else { - // If handover fails and requires to fallback, the context of target transport needs to - // be released - if (!success) { - releaseNetworkInternal(networkRequest, - DcTracker.RELEASE_TYPE_NORMAL, targetTransport); - } + mPhone.getDataNetworkController().removeNetworkRequest(networkRequest); } - - handoverParams.callback.onCompleted(success, fallback); } protected void log(String s) { diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java index b55304a4a9..b334b89d75 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkRequest.java @@ -157,8 +157,7 @@ public class TelephonyNetworkRequest { /** * Data config manager for retrieving data config. */ - // TODO: Make this @NonNull after old data stack removed. - private final @Nullable DataConfigManager mDataConfigManager; + private final @NonNull DataConfigManager mDataConfigManager; /** * The attached data network. Note that the data network could be in any state. {@code null} @@ -204,12 +203,8 @@ public class TelephonyNetworkRequest { // to satisfy it. mState = REQUEST_STATE_UNSATISFIED; mCreatedTimeMillis = SystemClock.elapsedRealtime(); - if (phone.isUsingNewDataStack()) { - mDataConfigManager = phone.getDataNetworkController().getDataConfigManager(); - updatePriority(); - } else { - mDataConfigManager = null; - } + mDataConfigManager = phone.getDataNetworkController().getDataConfigManager(); + updatePriority(); } /** @@ -401,8 +396,7 @@ public class TelephonyNetworkRequest { * @return {@code true} if this network request can result in bringing up a metered network. */ public boolean isMeteredRequest() { - // TODO: Remove null check after old data stack removed. - return mDataConfigManager != null && mDataConfigManager.isAnyMeteredCapability( + return mDataConfigManager.isAnyMeteredCapability( getCapabilities(), mPhone.getServiceState().getDataRoaming()); } diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java b/src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java deleted file mode 100644 index 827dbdd5e4..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/ApnConfigType.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2020 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.dataconnection; - -import android.telephony.Annotation; - -/** - * Container of network configuration settings relevant for telephony module. - * - */ -public class ApnConfigType { - - private final int mType; - private final int mPriority; - - public ApnConfigType(@Annotation.ApnType int type, int priority) { - mType = type; - mPriority = priority; - } - - /** - * Returns the apn type of this config type - * @return Type of apn. - */ - public int getType() { - return mType; - } - - /** - * Returns the priority of this apn config type. - * @return The priority of this apn. - */ - public int getPriority() { - return mPriority; - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java b/src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java deleted file mode 100644 index 156ac926e5..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/ApnConfigTypeRepository.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2020 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.dataconnection; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.PersistableBundle; -import android.telephony.Annotation; -import android.telephony.CarrierConfigManager; -import android.telephony.Rlog; -import android.telephony.data.ApnSetting; -import android.util.ArrayMap; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * Hard coded configuration of specific network types that the telephony module needs. - * Formerly stored in network attributes within the resources file. - */ -public class ApnConfigTypeRepository { - - private static final String TAG = ApnConfigTypeRepository.class.getSimpleName(); - - private final Map mConfigTypeMap; - - public ApnConfigTypeRepository(PersistableBundle carrierConfig) { - mConfigTypeMap = new HashMap<>(); - setup(carrierConfig); - } - - /** - * Gets list of apn config types. - * @return All apn config types. - */ - public Collection getTypes() { - return mConfigTypeMap.values(); - } - - /** - * Gets the apn config type by apn type. - * @param type The ApnType to search for. - * @return The config type matching the given apn type. - */ - @Nullable - public ApnConfigType getByType(@Annotation.ApnType int type) { - return mConfigTypeMap.get(type); - } - - private void setup(PersistableBundle carrierConfig) { - addApns(getCarrierApnTypeMap(CarrierConfigManager.getDefaultConfig())); - addApns(getCarrierApnTypeMap(carrierConfig)); - } - - private void addApns(Map apnTypeMap) { - add(ApnSetting.TYPE_DEFAULT, apnTypeMap); - add(ApnSetting.TYPE_MMS, apnTypeMap); - add(ApnSetting.TYPE_SUPL, apnTypeMap); - add(ApnSetting.TYPE_DUN, apnTypeMap); - add(ApnSetting.TYPE_HIPRI, apnTypeMap); - add(ApnSetting.TYPE_FOTA, apnTypeMap); - add(ApnSetting.TYPE_IMS, apnTypeMap); - add(ApnSetting.TYPE_CBS, apnTypeMap); - add(ApnSetting.TYPE_IA, apnTypeMap); - add(ApnSetting.TYPE_EMERGENCY, apnTypeMap); - add(ApnSetting.TYPE_MCX, apnTypeMap); - add(ApnSetting.TYPE_XCAP, apnTypeMap); - add(ApnSetting.TYPE_ENTERPRISE, apnTypeMap); - } - - @NonNull - private Map getCarrierApnTypeMap(PersistableBundle carrierConfig) { - if (carrierConfig == null) { - Rlog.w(TAG, "carrier config is null"); - return new ArrayMap<>(); - } - - final String[] apnTypeConfig = - carrierConfig.getStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY); - - final Map apnTypeMap = new ArrayMap<>(); - if (apnTypeConfig != null) { - for (final String entry : apnTypeConfig) { - try { - final String[] keyValue = entry.split(":"); - if (keyValue.length != 2) { - Rlog.e(TAG, "Apn type entry must have exactly one ':'"); - } else if (keyValue[0].contains(",")) { - //getApnTypesBitmaskFromString parses commas to a list, not valid here. - Rlog.e(TAG, "Invalid apn type name, entry: " + entry); - } else { - int apnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(keyValue[0]); - if (apnTypeBitmask > 0) { - apnTypeMap.put(apnTypeBitmask, Integer.parseInt(keyValue[1])); - } else { - Rlog.e(TAG, "Invalid apn type name, entry: " + entry); - } - } - - } catch (Exception ex) { - Rlog.e(TAG, "Exception on apn type entry: " + entry + "\n", ex); - } - } - } - return apnTypeMap; - } - - private void add(@Annotation.ApnType int type, Map apnTypeMap) { - if (apnTypeMap.containsKey(type)) { - mConfigTypeMap.put(type, new ApnConfigType(type, apnTypeMap.get(type))); - } - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java deleted file mode 100644 index 3f487cdf65..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Copyright (C) 2006 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.dataconnection; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.os.Message; -import android.telephony.Annotation.ApnType; -import android.telephony.data.ApnSetting; -import android.text.TextUtils; -import android.util.ArraySet; -import android.util.LocalLog; -import android.util.SparseIntArray; - -import com.android.internal.R; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; -import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; -import com.android.internal.util.IndentingPrintWriter; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Maintain the Apn context - */ -public class ApnContext { - - public final String LOG_TAG; - private final static String SLOG_TAG = "ApnContext"; - - protected static final boolean DBG = false; - - private final Phone mPhone; - - private final String mApnType; - - private DctConstants.State mState; - - private int mPriority; - - private ApnSetting mApnSetting; - - private DataConnection mDataConnection; - - private String mReason; - - /** - * user/app requested connection on this APN - */ - AtomicBoolean mDataEnabled; - - private final Object mRefCountLock = new Object(); - - private final DcTracker mDcTracker; - - - /** - * Remember this as a change in this value to a more permissive state - * should cause us to retry even permanent failures - */ - private boolean mConcurrentVoiceAndDataAllowed; - - /** - * used to track a single connection request so disconnects can get ignored if - * obsolete. - */ - private final AtomicInteger mConnectionGeneration = new AtomicInteger(0); - - /** - * Retry manager that handles the APN retry and delays. - */ - private final RetryManager mRetryManager; - - /** - * ApnContext constructor - * @param phone phone object - * @param typeId APN type Id - * @param logTag Tag for logging - * @param tracker Data call tracker - * @param priority Priority of APN type - */ - public ApnContext(Phone phone, int typeId, String logTag, DcTracker tracker, int priority) { - this(phone, ApnSetting.getApnTypeString(typeId), logTag, tracker, priority); - } - - /** - * ApnContext constructor - * @param phone phone object - * @param apnType APN type (e.g. default, supl, mms, etc...) - * @param logTag Tag for logging - * @param tracker Data call tracker - * @param priority Priority of APN type - */ - public ApnContext(Phone phone, String apnType, String logTag, DcTracker tracker, int priority) { - mPhone = phone; - mApnType = apnType; - mState = DctConstants.State.IDLE; - setReason(Phone.REASON_DATA_ENABLED); - mDataEnabled = new AtomicBoolean(false); - mPriority = priority; - LOG_TAG = logTag; - mDcTracker = tracker; - mRetryManager = new RetryManager(phone, tracker.getDataThrottler(), - ApnSetting.getApnTypesBitmaskFromString(apnType)); - } - - - - /** - * Get the APN type - * @return The APN type - */ - public String getApnType() { - return mApnType; - } - - /** - * Gets the APN type bitmask. - * @return The APN type bitmask - */ - public int getApnTypeBitmask() { - return ApnSetting.getApnTypesBitmaskFromString(mApnType); - } - - /** - * Get the associated data connection - * @return The data connection - */ - public synchronized DataConnection getDataConnection() { - return mDataConnection; - } - - /** - * This priority is taken into account when concurrent data connections are not allowed. The - * APN with the HIGHER priority is given preference. - * @return The priority of the APN type - */ - public int getPriority() { - return mPriority; - } - - /** - * Updates the priority of this context. - * @param priority The priority of the APN type - */ - public void setPriority(int priority) { - mPriority = priority; - } - - /** - * Keeping for backwards compatibility and in case it's needed in the future - * @return true - */ - public boolean isDependencyMet() { - return true; - } - - /** - * Set the associated data connection. - * @param dc data connection - */ - public synchronized void setDataConnection(DataConnection dc) { - log("setDataConnectionAc: old=" + mDataConnection + ",new=" + dc + " this=" + this); - mDataConnection = dc; - } - - /** - * Release data connection. - * @param reason The reason of releasing data connection - */ - public synchronized void releaseDataConnection(String reason) { - if (mDataConnection != null) { - mDataConnection.tearDown(this, reason, null); - mDataConnection = null; - } - setState(DctConstants.State.IDLE); - } - - /** - * Get the current APN setting. - * @return APN setting - */ - public synchronized ApnSetting getApnSetting() { - log("getApnSetting: apnSetting=" + mApnSetting); - return mApnSetting; - } - - /** - * Set the APN setting. - * @param apnSetting APN setting - */ - public synchronized void setApnSetting(ApnSetting apnSetting) { - log("setApnSetting: apnSetting=" + apnSetting); - mApnSetting = apnSetting; - } - - /** - * Set the list of APN candidates which will be used for data call setup later. - * @param waitingApns List of APN candidates - */ - public synchronized void setWaitingApns(ArrayList waitingApns) { - mRetryManager.setWaitingApns(waitingApns); - } - - /** - * Get the next available APN to try. - * @return APN setting which will be used for data call setup.{@code null} if there is no - * APN can be retried. - */ - public @Nullable ApnSetting getNextApnSetting() { - return mRetryManager.getNextApnSetting(); - } - - /** - * Get the delay for trying the next APN setting if the current one failed. - * @param failFastEnabled True if fail fast mode enabled. In this case we'll use a shorter - * delay. - * @return The delay in milliseconds - */ - public long getDelayForNextApn(boolean failFastEnabled) { - return mRetryManager.getDelayForNextApn(failFastEnabled || isFastRetryReason()); - } - - /** - * Mark the current APN setting permanently failed, which means it will not be retried anymore. - * @param apn APN setting - */ - public void markApnPermanentFailed(ApnSetting apn) { - mRetryManager.markApnPermanentFailed(apn); - } - - /** - * Get the list of waiting APNs. - * @return the list of waiting APNs - */ - public @NonNull ArrayList getWaitingApns() { - return mRetryManager.getWaitingApns(); - } - - /** - * Save the state indicating concurrent voice/data allowed. - * @param allowed True if concurrent voice/data is allowed - */ - public synchronized void setConcurrentVoiceAndDataAllowed(boolean allowed) { - mConcurrentVoiceAndDataAllowed = allowed; - } - - /** - * Get the state indicating concurrent voice/data allowed. - * @return True if concurrent voice/data is allowed - */ - public synchronized boolean isConcurrentVoiceAndDataAllowed() { - return mConcurrentVoiceAndDataAllowed; - } - - /** - * Set the current data call state. - * @param s Current data call state - */ - public synchronized void setState(DctConstants.State s) { - log("setState: " + s + ", previous state:" + mState); - - if (mState != s) { - mStateLocalLog.log("State changed from " + mState + " to " + s); - mState = s; - } - - if (mState == DctConstants.State.FAILED) { - // when teardown the connection and set to IDLE - mRetryManager.getWaitingApns().clear(); - } - } - - /** - * Get the current data call state. - * @return The current data call state - */ - public synchronized DctConstants.State getState() { - return mState; - } - - /** - * Check whether the data call is disconnected or not. - * @return True if the data call is disconnected - */ - public boolean isDisconnected() { - DctConstants.State currentState = getState(); - return ((currentState == DctConstants.State.IDLE) || - currentState == DctConstants.State.FAILED); - } - - /** - * Set the reason for data call connection. - * @param reason Reason for data call connection - */ - public synchronized void setReason(String reason) { - log("set reason as " + reason + ",current state " + mState); - mReason = reason; - } - - /** - * Get the reason for data call connection. - * @return The reason for data call connection - */ - public synchronized String getReason() { - return mReason; - } - - /** - * Check if ready for data call connection - * @return True if ready, otherwise false. - */ - public boolean isReady() { - return mDataEnabled.get() && isDependencyMet(); - } - - /** - * Check if the data call is in the state which allow connecting. - * @return True if allowed, otherwise false. - */ - public boolean isConnectable() { - return isReady() && ((mState == DctConstants.State.IDLE) - || (mState == DctConstants.State.RETRYING) - || (mState == DctConstants.State.FAILED)); - } - - /** - * Check if apn reason is fast retry reason which should apply shorter delay between apn re-try. - * @return True if it is fast retry reason, otherwise false. - */ - private boolean isFastRetryReason() { - return Phone.REASON_NW_TYPE_CHANGED.equals(mReason) || - Phone.REASON_APN_CHANGED.equals(mReason); - } - - /** Check if the data call is in connected or connecting state. - * @return True if the data call is in connected or connecting state - */ - public boolean isConnectedOrConnecting() { - return isReady() && ((mState == DctConstants.State.CONNECTED) - || (mState == DctConstants.State.CONNECTING) - || (mState == DctConstants.State.RETRYING)); - } - - /** - * Set data call enabled/disabled state. - * @param enabled True if data call is enabled - */ - public void setEnabled(boolean enabled) { - log("set enabled as " + enabled + ", current state is " + mDataEnabled.get()); - mDataEnabled.set(enabled); - } - - /** - * Check if the data call is enabled or not. - * @return True if enabled - */ - public boolean isEnabled() { - return mDataEnabled.get(); - } - - public boolean isProvisioningApn() { - String provisioningApn = mPhone.getContext().getResources() - .getString(R.string.mobile_provisioning_apn); - if (!TextUtils.isEmpty(provisioningApn) && - (mApnSetting != null) && (mApnSetting.getApnName() != null)) { - return (mApnSetting.getApnName().equals(provisioningApn)); - } else { - return false; - } - } - - private final ArraySet mNetworkRequests = new ArraySet<>(); - private final LocalLog mStateLocalLog = new LocalLog(32); - - private static final LocalLog sLocalLog = new LocalLog(256); - - /** Add a line to the ApnContext local log. */ - public static void requestLog(ApnContext apnContext, String str) { - if (apnContext != null) { - String logString = "[ApnContext:" + apnContext.getApnType() + "] " + str; - if (DBG) { - Rlog.d(SLOG_TAG, logString); - } - synchronized (sLocalLog) { - sLocalLog.log(logString); - } - } - } - - /** - * Request a network - * - * @param networkRequest Network request from clients - * @param type The request type - * @param onHandoverCompleteMsg When request type is handover, this message will be sent when - * handover is completed. For normal request, this should be null. - */ - public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type, - Message onHandoverCompleteMsg) { - synchronized (mRefCountLock) { - mNetworkRequests.add(networkRequest); - requestLog(this, "requestNetwork for " + networkRequest + ", type=" - + DcTracker.requestTypeToString(type)); - mDcTracker.enableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type, - onHandoverCompleteMsg); - if (mDataConnection != null) { - // New network request added. Should re-evaluate properties of - // the data connection. For example, the score may change. - mDataConnection.reevaluateDataConnectionProperties(); - } - } - } - - public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type) { - synchronized (mRefCountLock) { - if (mNetworkRequests.contains(networkRequest)) { - mNetworkRequests.remove(networkRequest); - if (mDataConnection != null) { - // New network request added. Should re-evaluate properties of - // the data connection. For example, the score may change. - mDataConnection.reevaluateDataConnectionProperties(); - } - requestLog(this, "releaseNetwork left with " + mNetworkRequests.size() - + " requests."); - if (mNetworkRequests.size() == 0 - || type == DcTracker.RELEASE_TYPE_DETACH - || type == DcTracker.RELEASE_TYPE_HANDOVER) { - mDcTracker.disableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type); - } - } - } - } - - /** - * @param excludeDun True if excluding requests that have DUN capability - * @return True if the attached network requests contain restricted capability. - */ - public boolean hasRestrictedRequests(boolean excludeDun) { - synchronized (mRefCountLock) { - for (NetworkRequest nr : mNetworkRequests) { - if (excludeDun && - nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) { - continue; - } - if (!nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) { - return true; - } - } - } - return false; - } - - private final SparseIntArray mRetriesLeftPerErrorCode = new SparseIntArray(); - - public void resetErrorCodeRetries() { - requestLog(this, "resetErrorCodeRetries"); - - String[] config = mPhone.getContext().getResources().getStringArray( - com.android.internal.R.array.config_cell_retries_per_error_code); - synchronized (mRetriesLeftPerErrorCode) { - mRetriesLeftPerErrorCode.clear(); - - for (String c : config) { - String errorValue[] = c.split(","); - if (errorValue != null && errorValue.length == 2) { - int count = 0; - int errorCode = 0; - try { - errorCode = Integer.parseInt(errorValue[0]); - count = Integer.parseInt(errorValue[1]); - } catch (NumberFormatException e) { - log("Exception parsing config_retries_per_error_code: " + e); - continue; - } - if (count > 0 && errorCode > 0) { - mRetriesLeftPerErrorCode.put(errorCode, count); - } - } else { - log("Exception parsing config_retries_per_error_code: " + c); - } - } - } - } - - public boolean restartOnError(int errorCode) { - boolean result = false; - int retriesLeft = 0; - synchronized(mRetriesLeftPerErrorCode) { - retriesLeft = mRetriesLeftPerErrorCode.get(errorCode); - switch (retriesLeft) { - case 0: { - // not set, never restart modem - break; - } - case 1: { - resetErrorCodeRetries(); - result = true; - break; - } - default: { - mRetriesLeftPerErrorCode.put(errorCode, retriesLeft - 1); - result = false; - } - } - } - requestLog(this, "restartOnError(" + errorCode + ") found " + retriesLeft - + " and returned " + result); - return result; - } - - public int incAndGetConnectionGeneration() { - return mConnectionGeneration.incrementAndGet(); - } - - public int getConnectionGeneration() { - return mConnectionGeneration.get(); - } - - long getRetryAfterDisconnectDelay() { - return mRetryManager.getRetryAfterDisconnectDelay(); - } - - /** - * Get APN type from the network request. - * - * @param nr The network request. - * @return The APN type. - */ - public static @ApnType int getApnTypeFromNetworkRequest(NetworkRequest nr) { - // For now, ignore the bandwidth stuff - if (nr.getTransportTypes().length > 0 - && !nr.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - return ApnSetting.TYPE_NONE; - } - - // in the near term just do 1-1 matches. - // TODO - actually try to match the set of capabilities - int apnType = ApnSetting.TYPE_NONE; - boolean error = false; - - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { - apnType = ApnSetting.TYPE_DEFAULT; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_MMS; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_SUPL; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_DUN; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_FOTA; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_IMS; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_CBS; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_IA)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_IA; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_EMERGENCY; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_MCX)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_MCX; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_XCAP; - } - if (nr.hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)) { - if (apnType != ApnSetting.TYPE_NONE) error = true; - apnType = ApnSetting.TYPE_ENTERPRISE; - } - if (error) { - // TODO: If this error condition is removed, the framework's handling of - // NET_CAPABILITY_NOT_RESTRICTED will need to be updated so requests for - // say FOTA and INTERNET are marked as restricted. This is not how - // NetworkCapabilities.maybeMarkCapabilitiesRestricted currently works. - Rlog.d(SLOG_TAG, "Multiple apn types specified in request - result is unspecified!"); - } - if (apnType == ApnSetting.TYPE_NONE) { - Rlog.d(SLOG_TAG, "Unsupported NetworkRequest in Telephony: nr=" + nr); - } - return apnType; - } - - public List getNetworkRequests() { - synchronized (mRefCountLock) { - return new ArrayList(mNetworkRequests); - } - } - - @Override - public synchronized String toString() { - // We don't print mDataConnection because its recursive. - return "{mApnType=" + mApnType + " mState=" + getState() + " mWaitingApns={" - + mRetryManager.getWaitingApns() + " priority=" + mPriority + "}" - + " mApnSetting={" + mApnSetting - + "} mReason=" + mReason + " mDataEnabled=" + mDataEnabled + "}"; - } - - private void log(String s) { - if (DBG) { - Rlog.d(LOG_TAG, "[ApnContext:" + mApnType + "] " + s); - } - } - - public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { - final IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); - synchronized (mRefCountLock) { - pw.println(toString()); - if (mNetworkRequests.size() > 0) { - pw.println("NetworkRequests:"); - pw.increaseIndent(); - for (NetworkRequest nr : mNetworkRequests) { - pw.println(nr); - } - pw.decreaseIndent(); - } - pw.println("Historical APN state:"); - pw.increaseIndent(); - mStateLocalLog.dump(fd, pw, args); - pw.decreaseIndent(); - pw.println(mRetryManager); - pw.println("--------------------------"); - } - } - - /** Dumps the ApnContext local log. */ - public static void dumpLocalLog(FileDescriptor fd, PrintWriter printWriter, String[] args) { - printWriter.println("Local log:"); - synchronized (sLocalLog) { - sLocalLog.dump(fd, printWriter, args); - } - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java b/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java deleted file mode 100644 index 3c2a6ef251..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/ApnSettingUtils.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import android.content.Context; -import android.os.PersistableBundle; -import android.telephony.Annotation.ApnType; -import android.telephony.CarrierConfigManager; -import android.telephony.data.ApnSetting; - -import com.android.internal.telephony.Phone; -import com.android.telephony.Rlog; - -import java.util.Arrays; -import java.util.HashSet; - -/** - * This class represents a apn setting for create PDP link - */ -public class ApnSettingUtils { - - static final String LOG_TAG = "ApnSetting"; - - private static final boolean DBG = false; - - /** - * Check if this APN type is metered. - * - * @param apnType the APN type - * @param phone the phone object - * @return {@code true} if the APN type is metered, {@code false} otherwise. - */ - public static boolean isMeteredApnType(@ApnType int apnType, Phone phone) { - if (phone == null) { - return true; - } - - boolean isRoaming = phone.getServiceState().getDataRoaming(); - int subId = phone.getSubId(); - - String carrierConfig; - // First check if the device is roaming. If yes, use the roaming metered APN list. - // Otherwise use the normal metered APN list. - if (isRoaming) { - carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS; - } else { - carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS; - } - - if (DBG) { - Rlog.d(LOG_TAG, "isMeteredApnType: isRoaming=" + isRoaming); - } - - CarrierConfigManager configManager = (CarrierConfigManager) - phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager == null) { - Rlog.e(LOG_TAG, "Carrier config service is not available"); - return true; - } - - PersistableBundle b = configManager.getConfigForSubId(subId); - if (b == null) { - Rlog.e(LOG_TAG, "Can't get the config. subId = " + subId); - return true; - } - - String[] meteredApnTypes = b.getStringArray(carrierConfig); - if (meteredApnTypes == null) { - Rlog.e(LOG_TAG, carrierConfig + " is not available. " + "subId = " + subId); - return true; - } - - HashSet meteredApnSet = new HashSet<>(Arrays.asList(meteredApnTypes)); - if (DBG) { - Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " - + Arrays.toString(meteredApnSet.toArray())); - } - - if (meteredApnSet.contains(ApnSetting.getApnTypeString(apnType))) { - if (DBG) Rlog.d(LOG_TAG, ApnSetting.getApnTypeString(apnType) + " is metered."); - return true; - } else if (apnType == ApnSetting.TYPE_ALL) { - // Assuming no configuration error, if at least one APN type is - // metered, then this APN setting is metered. - if (meteredApnSet.size() > 0) { - if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered."); - return true; - } - } - - if (DBG) Rlog.d(LOG_TAG, ApnSetting.getApnTypeString(apnType) + " is not metered."); - return false; - } - - /** - * Check if this APN setting is metered. - * - * @param apn APN setting - * @param phone The phone object - * @return True if this APN setting is metered, otherwise false. - */ - public static boolean isMetered(ApnSetting apn, Phone phone) { - if (phone == null || apn == null) { - return true; - } - - for (int apnType : apn.getApnTypes()) { - // If one of the APN type is metered, then this APN setting is metered. - if (isMeteredApnType(apnType, phone)) { - return true; - } - } - return false; - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java deleted file mode 100644 index 255972af01..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java +++ /dev/null @@ -1,4094 +0,0 @@ -/* - * Copyright (C) 2006 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.dataconnection; - -import static android.telephony.data.DataCallResponse.PDU_SESSION_ID_NOT_SET; - -import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_HANDOVER; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.PendingIntent; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.UserInfo; -import android.net.ConnectivityManager; -import android.net.InetAddresses; -import android.net.KeepalivePacketData; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.NetworkAgentConfig; -import android.net.NetworkCapabilities; -import android.net.NetworkFactory; -import android.net.NetworkProvider; -import android.net.NetworkRequest; -import android.net.ProxyInfo; -import android.net.RouteInfo; -import android.net.SocketKeepalive; -import android.net.TelephonyNetworkSpecifier; -import android.net.vcn.VcnManager; -import android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener; -import android.net.vcn.VcnNetworkPolicyResult; -import android.os.AsyncResult; -import android.os.HandlerExecutor; -import android.os.Message; -import android.os.PersistableBundle; -import android.os.Process; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserManager; -import android.provider.Telephony; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.TransportType; -import android.telephony.Annotation.ApnType; -import android.telephony.Annotation.DataFailureCause; -import android.telephony.Annotation.DataState; -import android.telephony.Annotation.NetworkType; -import android.telephony.CarrierConfigManager; -import android.telephony.DataFailCause; -import android.telephony.LinkCapacityEstimate; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.PreciseDataConnectionState; -import android.telephony.ServiceState; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.telephony.data.DataCallResponse.HandoverFailureMode; -import android.telephony.data.DataProfile; -import android.telephony.data.DataService; -import android.telephony.data.DataServiceCallback; -import android.telephony.data.NetworkSliceInfo; -import android.telephony.data.Qos; -import android.telephony.data.QosBearerSession; -import android.telephony.data.TrafficDescriptor; -import android.text.TextUtils; -import android.util.LocalLog; -import android.util.Pair; -import android.util.TimeUtils; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.CarrierPrivilegesTracker; -import com.android.internal.telephony.CarrierSignalAgent; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.RIL; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.TelephonyStatsLog; -import com.android.internal.telephony.data.DataConfigManager; -import com.android.internal.telephony.data.KeepaliveStatus; -import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType; -import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType; -import com.android.internal.telephony.metrics.DataCallSessionStats; -import com.android.internal.telephony.metrics.TelephonyMetrics; -import com.android.internal.telephony.nano.TelephonyProto.RilDataCall; -import com.android.internal.telephony.uicc.IccUtils; -import com.android.internal.telephony.util.ArrayUtils; -import com.android.internal.util.AsyncChannel; -import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Protocol; -import com.android.internal.util.State; -import com.android.internal.util.StateMachine; -import com.android.net.module.util.NetworkCapabilitiesUtils; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -/** - * {@hide} - * - * DataConnection StateMachine. - * - * This a class for representing a single data connection, with instances of this - * class representing a connection via the cellular network. There may be multiple - * data connections and all of them are managed by the DataConnectionTracker. - * - * NOTE: All DataConnection objects must be running on the same looper, which is the default - * as the coordinator has members which are used without synchronization. - */ -public class DataConnection extends StateMachine { - private static final boolean DBG = true; - private static final boolean VDBG = true; - - private static final String NETWORK_TYPE = "MOBILE"; - - private static final String RAT_NAME_5G = "nr"; - private static final String RAT_NAME_EVDO = "evdo"; - - /** - * OSId for "Android", using UUID version 5 with namespace ISO OSI. - * Prepended to the OsAppId in TrafficDescriptor to use for URSP matching. - */ - private static final UUID OS_ID = UUID.fromString("97a498e3-fc92-5c94-8986-0333d06e4e47"); - - /** - * The data connection is not being or been handovered. Note this is the state for the source - * data connection, not destination data connection - */ - private static final int HANDOVER_STATE_IDLE = 1; - - /** - * The data connection is being handovered. Note this is the state for the source - * data connection, not destination data connection. - */ - private static final int HANDOVER_STATE_BEING_TRANSFERRED = 2; - - /** - * The data connection is already handovered. Note this is the state for the source - * data connection, not destination data connection. - */ - private static final int HANDOVER_STATE_COMPLETED = 3; - - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"HANDOVER_STATE_"}, value = { - HANDOVER_STATE_IDLE, - HANDOVER_STATE_BEING_TRANSFERRED, - HANDOVER_STATE_COMPLETED}) - public @interface HandoverState {} - - // The data connection providing default Internet connection will have a higher score of 50. - // Other connections will have a slightly lower score of 45. The intention is other connections - // will not cause ConnectivityService to tear down default internet connection. For example, - // to validate Internet connection on non-default data SIM, we'll set up a temporary Internet - // connection on that data SIM. In this case, score of 45 is assigned so ConnectivityService - // will not replace the default Internet connection with it. - private static final int DEFAULT_INTERNET_CONNECTION_SCORE = 50; - private static final int OTHER_CONNECTION_SCORE = 45; - - // The score we report to connectivity service - private int mScore; - - // The subscription id associated with this data connection. - private int mSubId; - - // The data connection controller - private DcController mDcController; - - // The Tester for failing all bringup's - private DcTesterFailBringUpAll mDcTesterFailBringUpAll; - - // Whether or not the data connection should allocate its own pdu session id - private boolean mDoAllocatePduSessionId; - - private static AtomicInteger mInstanceNumber = new AtomicInteger(0); - private AsyncChannel mAc; - - // The DCT that's talking to us, we only support one! - private DcTracker mDct = null; - - private String[] mPcscfAddr; - - private final String mTagSuffix; - - private final LocalLog mHandoverLocalLog = new LocalLog(64); - - private int[] mAdministratorUids = new int[0]; - - // stats per data call - private DataCallSessionStats mDataCallSessionStats; - - /** - * Used internally for saving connecting parameters. - */ - public static class ConnectionParams { - int mTag; - ApnContext mApnContext; - int mProfileId; - int mRilRat; - Message mOnCompletedMsg; - final int mConnectionGeneration; - @RequestNetworkType - final int mRequestType; - final int mSubId; - final boolean mIsPreferredApn; - - ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology, - Message onCompletedMsg, int connectionGeneration, - @RequestNetworkType int requestType, int subId, - boolean isPreferredApn) { - mApnContext = apnContext; - mProfileId = profileId; - mRilRat = rilRadioTechnology; - mOnCompletedMsg = onCompletedMsg; - mConnectionGeneration = connectionGeneration; - mRequestType = requestType; - mSubId = subId; - mIsPreferredApn = isPreferredApn; - } - - @Override - public String toString() { - return "{mTag=" + mTag + " mApnContext=" + mApnContext - + " mProfileId=" + mProfileId - + " mRat=" + mRilRat - + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) - + " mRequestType=" + DcTracker.requestTypeToString(mRequestType) - + " mSubId=" + mSubId - + " mIsPreferredApn=" + mIsPreferredApn - + "}"; - } - } - - /** - * Used internally for saving disconnecting parameters. - */ - public static class DisconnectParams { - int mTag; - public ApnContext mApnContext; - String mReason; - @ReleaseNetworkType - final int mReleaseType; - Message mOnCompletedMsg; - - DisconnectParams(ApnContext apnContext, String reason, @ReleaseNetworkType int releaseType, - Message onCompletedMsg) { - mApnContext = apnContext; - mReason = reason; - mReleaseType = releaseType; - mOnCompletedMsg = onCompletedMsg; - } - - @Override - public String toString() { - return "{mTag=" + mTag + " mApnContext=" + mApnContext - + " mReason=" + mReason - + " mReleaseType=" + DcTracker.releaseTypeToString(mReleaseType) - + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}"; - } - } - - private volatile ApnSetting mApnSetting; - private ConnectionParams mConnectionParams; - private DisconnectParams mDisconnectParams; - @DataFailureCause - private int mDcFailCause; - - @HandoverFailureMode - private int mHandoverFailureMode; - - private Phone mPhone; - private DataServiceManager mDataServiceManager; - private VcnManager mVcnManager; - private final int mTransportType; - private LinkProperties mLinkProperties = new LinkProperties(); - private int mPduSessionId; - private long mCreateTime; - private long mLastFailTime; - @DataFailureCause - private int mLastFailCause; - private static final String NULL_IP = "0.0.0.0"; - private Object mUserData; - private boolean mCongestedOverride; - private boolean mUnmeteredOverride; - private int mRilRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; - private int mDataRegState = Integer.MAX_VALUE; - // Indicating data connection is suspended due to temporary reasons, for example, out of - // service, concurrency voice/data not supported, etc.. Note this flag is only meaningful when - // data is in active state. When data is in inactive, connecting, or disconnecting, this flag - // is unmeaningful. - private boolean mIsSuspended; - private int mDownlinkBandwidth = 14; - private int mUplinkBandwidth = 14; - private Qos mDefaultQos = null; - private List mQosBearerSessions = new ArrayList<>(); - private NetworkSliceInfo mSliceInfo; - private List mTrafficDescriptors = new ArrayList<>(); - - /** The corresponding network agent for this data connection. */ - private DcNetworkAgent mNetworkAgent; - - /** - * The network agent from handover source data connection. This is the potential network agent - * that will be transferred here after handover completed. - */ - private DcNetworkAgent mHandoverSourceNetworkAgent; - - private int mDisabledApnTypeBitMask = 0; - - int mTag; - - /** Data connection id assigned by the modem. This is unique across transports */ - public int mCid; - - @HandoverState - private int mHandoverState = HANDOVER_STATE_IDLE; - private final Map mApnContexts = new ConcurrentHashMap<>(); - PendingIntent mReconnectIntent = null; - - /** Class used to track VCN-defined Network policies for this DcNetworkAgent. */ - private final VcnNetworkPolicyChangeListener mVcnPolicyChangeListener = - new DataConnectionVcnNetworkPolicyChangeListener(); - - // ***** Event codes for driving the state machine, package visible for Dcc - static final int BASE = Protocol.BASE_DATA_CONNECTION; - static final int EVENT_CONNECT = BASE + 0; - static final int EVENT_SETUP_DATA_CONNECTION_DONE = BASE + 1; - static final int EVENT_DEACTIVATE_DONE = BASE + 3; - static final int EVENT_DISCONNECT = BASE + 4; - static final int EVENT_DISCONNECT_ALL = BASE + 6; - static final int EVENT_DATA_STATE_CHANGED = BASE + 7; - static final int EVENT_TEAR_DOWN_NOW = BASE + 8; - static final int EVENT_LOST_CONNECTION = BASE + 9; - static final int EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED = BASE + 11; - static final int EVENT_DATA_CONNECTION_ROAM_ON = BASE + 12; - static final int EVENT_DATA_CONNECTION_ROAM_OFF = BASE + 13; - static final int EVENT_BW_REFRESH_RESPONSE = BASE + 14; - static final int EVENT_DATA_CONNECTION_VOICE_CALL_STARTED = BASE + 15; - static final int EVENT_DATA_CONNECTION_VOICE_CALL_ENDED = BASE + 16; - static final int EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED = BASE + 17; - static final int EVENT_KEEPALIVE_STATUS = BASE + 18; - static final int EVENT_KEEPALIVE_STARTED = BASE + 19; - static final int EVENT_KEEPALIVE_STOPPED = BASE + 20; - static final int EVENT_KEEPALIVE_START_REQUEST = BASE + 21; - static final int EVENT_KEEPALIVE_STOP_REQUEST = BASE + 22; - static final int EVENT_LINK_CAPACITY_CHANGED = BASE + 23; - static final int EVENT_RESET = BASE + 24; - static final int EVENT_REEVALUATE_RESTRICTED_STATE = BASE + 25; - static final int EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES = BASE + 26; - static final int EVENT_NR_STATE_CHANGED = BASE + 27; - static final int EVENT_DATA_CONNECTION_METEREDNESS_CHANGED = BASE + 28; - static final int EVENT_NR_FREQUENCY_CHANGED = BASE + 29; - static final int EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED = BASE + 30; - static final int EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED = BASE + 31; - static final int EVENT_CSS_INDICATOR_CHANGED = BASE + 32; - static final int EVENT_UPDATE_SUSPENDED_STATE = BASE + 33; - static final int EVENT_START_HANDOVER = BASE + 34; - static final int EVENT_CANCEL_HANDOVER = BASE + 35; - static final int EVENT_START_HANDOVER_ON_TARGET = BASE + 36; - static final int EVENT_ALLOCATE_PDU_SESSION_ID = BASE + 37; - static final int EVENT_RELEASE_PDU_SESSION_ID = BASE + 38; - static final int EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE = BASE + 39; - private static final int CMD_TO_STRING_COUNT = EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE - BASE + 1; - - private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; - static { - sCmdToString[EVENT_CONNECT - BASE] = "EVENT_CONNECT"; - sCmdToString[EVENT_SETUP_DATA_CONNECTION_DONE - BASE] = - "EVENT_SETUP_DATA_CONNECTION_DONE"; - sCmdToString[EVENT_DEACTIVATE_DONE - BASE] = "EVENT_DEACTIVATE_DONE"; - sCmdToString[EVENT_DISCONNECT - BASE] = "EVENT_DISCONNECT"; - sCmdToString[EVENT_DISCONNECT_ALL - BASE] = "EVENT_DISCONNECT_ALL"; - sCmdToString[EVENT_DATA_STATE_CHANGED - BASE] = "EVENT_DATA_STATE_CHANGED"; - sCmdToString[EVENT_TEAR_DOWN_NOW - BASE] = "EVENT_TEAR_DOWN_NOW"; - sCmdToString[EVENT_LOST_CONNECTION - BASE] = "EVENT_LOST_CONNECTION"; - sCmdToString[EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED - BASE] = - "EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"; - sCmdToString[EVENT_DATA_CONNECTION_ROAM_ON - BASE] = "EVENT_DATA_CONNECTION_ROAM_ON"; - sCmdToString[EVENT_DATA_CONNECTION_ROAM_OFF - BASE] = "EVENT_DATA_CONNECTION_ROAM_OFF"; - sCmdToString[EVENT_BW_REFRESH_RESPONSE - BASE] = "EVENT_BW_REFRESH_RESPONSE"; - sCmdToString[EVENT_DATA_CONNECTION_VOICE_CALL_STARTED - BASE] = - "EVENT_DATA_CONNECTION_VOICE_CALL_STARTED"; - sCmdToString[EVENT_DATA_CONNECTION_VOICE_CALL_ENDED - BASE] = - "EVENT_DATA_CONNECTION_VOICE_CALL_ENDED"; - sCmdToString[EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED - BASE] = - "EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED"; - sCmdToString[EVENT_KEEPALIVE_STATUS - BASE] = "EVENT_KEEPALIVE_STATUS"; - sCmdToString[EVENT_KEEPALIVE_STARTED - BASE] = "EVENT_KEEPALIVE_STARTED"; - sCmdToString[EVENT_KEEPALIVE_STOPPED - BASE] = "EVENT_KEEPALIVE_STOPPED"; - sCmdToString[EVENT_KEEPALIVE_START_REQUEST - BASE] = "EVENT_KEEPALIVE_START_REQUEST"; - sCmdToString[EVENT_KEEPALIVE_STOP_REQUEST - BASE] = "EVENT_KEEPALIVE_STOP_REQUEST"; - sCmdToString[EVENT_LINK_CAPACITY_CHANGED - BASE] = "EVENT_LINK_CAPACITY_CHANGED"; - sCmdToString[EVENT_RESET - BASE] = "EVENT_RESET"; - sCmdToString[EVENT_REEVALUATE_RESTRICTED_STATE - BASE] = - "EVENT_REEVALUATE_RESTRICTED_STATE"; - sCmdToString[EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES - BASE] = - "EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES"; - sCmdToString[EVENT_NR_STATE_CHANGED - BASE] = "EVENT_NR_STATE_CHANGED"; - sCmdToString[EVENT_DATA_CONNECTION_METEREDNESS_CHANGED - BASE] = - "EVENT_DATA_CONNECTION_METEREDNESS_CHANGED"; - sCmdToString[EVENT_NR_FREQUENCY_CHANGED - BASE] = "EVENT_NR_FREQUENCY_CHANGED"; - sCmdToString[EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED - BASE] = - "EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED"; - sCmdToString[EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED - BASE] = - "EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED"; - sCmdToString[EVENT_CSS_INDICATOR_CHANGED - BASE] = "EVENT_CSS_INDICATOR_CHANGED"; - sCmdToString[EVENT_UPDATE_SUSPENDED_STATE - BASE] = "EVENT_UPDATE_SUSPENDED_STATE"; - sCmdToString[EVENT_START_HANDOVER - BASE] = "EVENT_START_HANDOVER"; - sCmdToString[EVENT_CANCEL_HANDOVER - BASE] = "EVENT_CANCEL_HANDOVER"; - sCmdToString[EVENT_START_HANDOVER_ON_TARGET - BASE] = "EVENT_START_HANDOVER_ON_TARGET"; - sCmdToString[EVENT_ALLOCATE_PDU_SESSION_ID - BASE] = "EVENT_ALLOCATE_PDU_SESSION_ID"; - sCmdToString[EVENT_RELEASE_PDU_SESSION_ID - BASE] = "EVENT_RELEASE_PDU_SESSION_ID"; - sCmdToString[EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE - BASE] = - "EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE"; - } - // Convert cmd to string or null if unknown - static String cmdToString(int cmd) { - String value = null; - cmd -= BASE; - if ((cmd >= 0) && (cmd < sCmdToString.length)) { - value = sCmdToString[cmd]; - } - if (value == null) { - value = "0x" + Integer.toHexString(cmd + BASE); - } - return value; - } - - /** - * Create the connection object - * - * @param phone the Phone - * @param id the connection id - * @return DataConnection that was created. - */ - public static DataConnection makeDataConnection(Phone phone, int id, DcTracker dct, - DataServiceManager dataServiceManager, - DcTesterFailBringUpAll failBringUpAll, - DcController dcc) { - String transportType = (dataServiceManager.getTransportType() - == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - ? "C" // Cellular - : "I"; // IWLAN - DataConnection dc = new DataConnection(phone, transportType + "-" - + mInstanceNumber.incrementAndGet(), id, dct, dataServiceManager, failBringUpAll, - dcc); - dc.start(); - if (DBG) dc.log("Made " + dc.getName()); - return dc; - } - - void dispose() { - log("dispose: call quiteNow()"); - quitNow(); - } - - /* Getter functions */ - - LinkProperties getLinkProperties() { - return new LinkProperties(mLinkProperties); - } - - boolean isDisconnecting() { - return getCurrentState() == mDisconnectingState - || getCurrentState() == mDisconnectingErrorCreatingConnection; - } - - @VisibleForTesting - public boolean isActive() { - return getCurrentState() == mActiveState; - } - - @VisibleForTesting - public boolean isInactive() { - return getCurrentState() == mInactiveState; - } - - boolean isActivating() { - return getCurrentState() == mActivatingState; - } - - boolean hasBeenTransferred() { - return mHandoverState == HANDOVER_STATE_COMPLETED; - } - - int getCid() { - return mCid; - } - - /** - * @return DataConnection's ApnSetting. - */ - public ApnSetting getApnSetting() { - return mApnSetting; - } - - /** - * Update http proxy of link properties based on current apn setting - */ - private void updateLinkPropertiesHttpProxy() { - if (mApnSetting == null - || TextUtils.isEmpty(mApnSetting.getProxyAddressAsString())) { - return; - } - try { - int port = mApnSetting.getProxyPort(); - if (port == -1) { - port = 8080; - } - ProxyInfo proxy = ProxyInfo.buildDirectProxy( - mApnSetting.getProxyAddressAsString(), port); - mLinkProperties.setHttpProxy(proxy); - } catch (NumberFormatException e) { - loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" - + mApnSetting.getProxyPort() + "): " + e); - } - } - - public static class UpdateLinkPropertyResult { - public SetupResult setupResult = SetupResult.SUCCESS; - public LinkProperties oldLp; - public LinkProperties newLp; - public UpdateLinkPropertyResult(LinkProperties curLp) { - oldLp = curLp; - newLp = curLp; - } - } - - /** - * Class returned by onSetupConnectionCompleted. - */ - public enum SetupResult { - SUCCESS, - ERROR_RADIO_NOT_AVAILABLE, - ERROR_INVALID_ARG, - ERROR_STALE, - ERROR_DATA_SERVICE_SPECIFIC_ERROR, - ERROR_DUPLICATE_CID, - ERROR_NO_DEFAULT_CONNECTION; - - public int mFailCause; - - SetupResult() { - mFailCause = DataFailCause.getFailCause(0); - } - - @Override - public String toString() { - return name() + " SetupResult.mFailCause=" + DataFailCause.toString(mFailCause); - } - } - - public boolean isIpv4Connected() { - boolean ret = false; - Collection addresses = mLinkProperties.getAddresses(); - - for (InetAddress addr: addresses) { - if (addr instanceof java.net.Inet4Address) { - java.net.Inet4Address i4addr = (java.net.Inet4Address) addr; - if (!i4addr.isAnyLocalAddress() && !i4addr.isLinkLocalAddress() && - !i4addr.isLoopbackAddress() && !i4addr.isMulticastAddress()) { - ret = true; - break; - } - } - } - return ret; - } - - public boolean isIpv6Connected() { - boolean ret = false; - Collection addresses = mLinkProperties.getAddresses(); - - for (InetAddress addr: addresses) { - if (addr instanceof java.net.Inet6Address) { - java.net.Inet6Address i6addr = (java.net.Inet6Address) addr; - if (!i6addr.isAnyLocalAddress() && !i6addr.isLinkLocalAddress() && - !i6addr.isLoopbackAddress() && !i6addr.isMulticastAddress()) { - ret = true; - break; - } - } - } - return ret; - } - - public int getPduSessionId() { - return mPduSessionId; - } - - public NetworkSliceInfo getSliceInfo() { - return mSliceInfo; - } - - public List getTrafficDescriptors() { - return mTrafficDescriptors; - } - - /** - * Update DC fields based on a new DataCallResponse - * @param response the response to use to update DC fields - */ - public void updateResponseFields(DataCallResponse response) { - updateQosParameters(response); - updateSliceInfo(response); - updateTrafficDescriptors(response); - } - - public void updateQosParameters(final @Nullable DataCallResponse response) { - if (response == null) { - mDefaultQos = null; - mQosBearerSessions.clear(); - return; - } - - mDefaultQos = response.getDefaultQos(); - mQosBearerSessions = response.getQosBearerSessions(); - - if (mNetworkAgent != null) { - syncQosToNetworkAgent(); - } - } - - private void syncQosToNetworkAgent() { - final DcNetworkAgent networkAgent = mNetworkAgent; - final List qosBearerSessions = mQosBearerSessions; - if (qosBearerSessions == null) { - networkAgent.updateQosBearerSessions(new ArrayList<>()); - return; - } - networkAgent.updateQosBearerSessions(qosBearerSessions); - } - - /** - * Update the latest slice info on this data connection with - * {@link DataCallResponse#getSliceInfo}. - */ - public void updateSliceInfo(DataCallResponse response) { - mSliceInfo = response.getSliceInfo(); - } - - /** - * Update the latest traffic descriptor on this data connection with - * {@link DataCallResponse#getTrafficDescriptors}. - */ - public void updateTrafficDescriptors(DataCallResponse response) { - mTrafficDescriptors = response.getTrafficDescriptors(); - mDcController.updateTrafficDescriptorsForCid(response.getId(), - response.getTrafficDescriptors()); - } - - @VisibleForTesting - public UpdateLinkPropertyResult updateLinkProperty(DataCallResponse newState) { - UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties); - - if (newState == null) return result; - - result.newLp = new LinkProperties(); - - // set link properties based on data call response - result.setupResult = setLinkProperties(newState, result.newLp); - if (result.setupResult != SetupResult.SUCCESS) { - if (DBG) log("updateLinkProperty failed : " + result.setupResult); - return result; - } - // copy HTTP proxy as it is not part DataCallResponse. - result.newLp.setHttpProxy(mLinkProperties.getHttpProxy()); - - checkSetMtu(mApnSetting, result.newLp); - - mLinkProperties = result.newLp; - - updateTcpBufferSizes(mRilRat); - - if (DBG && (! result.oldLp.equals(result.newLp))) { - log("updateLinkProperty old LP=" + result.oldLp); - log("updateLinkProperty new LP=" + result.newLp); - } - - if (result.newLp.equals(result.oldLp) == false && - mNetworkAgent != null) { - mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); - } - - return result; - } - - /** - * Sets the pdu session id of the data connection - * @param pduSessionId pdu session id to set - */ - @VisibleForTesting - public void setPduSessionId(int pduSessionId) { - if (mPduSessionId != pduSessionId) { - logd("Changing pdu session id from: " + mPduSessionId + " to: " + pduSessionId + ", " - + "Handover state: " + handoverStateToString(this.mHandoverState)); - mPduSessionId = pduSessionId; - } - } - - /** - * Read the MTU value from link properties where it can be set from network. In case - * not set by the network, set it again using the mtu szie value defined in the APN - * database for the connected APN - */ - private void checkSetMtu(ApnSetting apn, LinkProperties lp) { - if (lp == null) return; - - if (apn == null || lp == null) return; - - if (lp.getMtu() != PhoneConstants.UNSET_MTU) { - if (DBG) log("MTU set by call response to: " + lp.getMtu()); - return; - } - - if (apn != null && apn.getMtuV4() != PhoneConstants.UNSET_MTU) { - lp.setMtu(apn.getMtuV4()); - if (DBG) log("MTU set by APN to: " + apn.getMtuV4()); - return; - } - - int mtu = mPhone.getContext().getResources().getInteger( - com.android.internal.R.integer.config_mobile_mtu); - if (mtu != PhoneConstants.UNSET_MTU) { - lp.setMtu(mtu); - if (DBG) log("MTU set by config resource to: " + mtu); - } - } - - //***** Constructor (NOTE: uses dcc.getHandler() as its Handler) - private DataConnection(Phone phone, String tagSuffix, int id, - DcTracker dct, DataServiceManager dataServiceManager, - DcTesterFailBringUpAll failBringUpAll, DcController dcc) { - super("DC-" + tagSuffix, dcc); - mTagSuffix = tagSuffix; - setLogRecSize(300); - setLogOnlyTransitions(true); - if (DBG) log("DataConnection created"); - - mPhone = phone; - mDct = dct; - mDataServiceManager = dataServiceManager; - mVcnManager = mPhone.getContext().getSystemService(VcnManager.class); - mTransportType = dataServiceManager.getTransportType(); - mDcTesterFailBringUpAll = failBringUpAll; - mDcController = dcc; - mId = id; - mCid = -1; - mDataRegState = mPhone.getServiceState().getDataRegistrationState(); - mIsSuspended = false; - mDataCallSessionStats = new DataCallSessionStats(mPhone); - mDoAllocatePduSessionId = false; - - int networkType = getNetworkType(); - mRilRat = ServiceState.networkTypeToRilRadioTechnology(networkType); - updateLinkBandwidthsFromCarrierConfig(mRilRat); - - addState(mDefaultState); - addState(mInactiveState, mDefaultState); - addState(mActivatingState, mDefaultState); - addState(mActiveState, mDefaultState); - addState(mDisconnectingState, mDefaultState); - addState(mDisconnectingErrorCreatingConnection, mDefaultState); - setInitialState(mInactiveState); - } - - private @NetworkType int getNetworkType() { - ServiceState ss = mPhone.getServiceState(); - int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - - NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, mTransportType); - if (nri != null) { - networkType = nri.getAccessNetworkTechnology(); - } - - return networkType; - } - - /** - * Get the source transport for handover. For example, handover from WWAN to WLAN, WWAN is the - * source transport, and vice versa. - */ - private @TransportType int getHandoverSourceTransport() { - return mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN - ? AccessNetworkConstants.TRANSPORT_TYPE_WLAN - : AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - } - - /** - * API to generate the OsAppId for enterprise traffic category. - * @return byte[] representing OsId + length of OsAppId + OsAppId - */ - @VisibleForTesting - public static byte[] getEnterpriseOsAppId() { - byte[] osAppId = NetworkCapabilities.getCapabilityCarrierName( - NetworkCapabilities.NET_CAPABILITY_ENTERPRISE).getBytes(); - // 16 bytes for UUID, 1 byte for length of osAppId, and up to 255 bytes for osAppId - ByteBuffer bb = ByteBuffer.allocate(16 + 1 + osAppId.length); - bb.putLong(OS_ID.getMostSignificantBits()); - bb.putLong(OS_ID.getLeastSignificantBits()); - bb.put((byte) osAppId.length); - bb.put(osAppId); - if (VDBG) { - Rlog.d("DataConnection", "getEnterpriseOsAppId: " - + IccUtils.bytesToHexString(bb.array())); - } - return bb.array(); - } - - /** - * Begin setting up a data connection, calls setupDataCall - * and the ConnectionParams will be returned with the - * EVENT_SETUP_DATA_CONNECTION_DONE - * - * @param cp is the connection parameters - * - * @return Fail cause if failed to setup data connection. {@link DataFailCause#NONE} if success. - */ - private @DataFailureCause int connect(ConnectionParams cp) { - log("connect: carrier='" + mApnSetting.getEntryName() - + "' APN='" + mApnSetting.getApnName() - + "' proxy='" + mApnSetting.getProxyAddressAsString() - + "' port='" + mApnSetting.getProxyPort() + "'"); - ApnContext.requestLog(cp.mApnContext, "DataConnection.connect"); - - // Check if we should fake an error. - if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter > 0) { - DataCallResponse response = new DataCallResponse.Builder() - .setCause(mDcTesterFailBringUpAll.getDcFailBringUp().mFailCause) - .setRetryDurationMillis( - mDcTesterFailBringUpAll.getDcFailBringUp().mSuggestedRetryTime) - .setMtuV4(PhoneConstants.UNSET_MTU) - .setMtuV6(PhoneConstants.UNSET_MTU) - .build(); - - Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp); - AsyncResult.forMessage(msg, response, null); - sendMessage(msg); - if (DBG) { - log("connect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp() - + " send error response=" + response); - } - mDcTesterFailBringUpAll.getDcFailBringUp().mCounter -= 1; - return DataFailCause.NONE; - } - - mCreateTime = -1; - mLastFailTime = -1; - mLastFailCause = DataFailCause.NONE; - - Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp); - msg.obj = cp; - - DataProfile dp = new DataProfile.Builder() - .setApnSetting(mApnSetting) - .setPreferred(cp.mIsPreferredApn) - .build(); - - // We need to use the actual modem roaming state instead of the framework roaming state - // here. This flag is only passed down to ril_service for picking the correct protocol (for - // old modem backward compatibility). - boolean isModemRoaming = mPhone.getServiceState().getDataRoamingFromRegistration(); - - // If the apn is NOT metered, we will allow data roaming regardless of the setting. - boolean isUnmeteredApnType = !ApnSettingUtils.isMeteredApnType( - cp.mApnContext.getApnTypeBitmask(), mPhone); - - // Set this flag to true if the user turns on data roaming. Or if we override the roaming - // state in framework, we should set this flag to true as well so the modem will not reject - // the data call setup (because the modem actually thinks the device is roaming). - boolean allowRoaming = mPhone.getDataRoamingEnabled() - || (isModemRoaming && (!mPhone.getServiceState().getDataRoaming() - || isUnmeteredApnType)); - - String dnn = null; - byte[] osAppId = null; - if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { - osAppId = getEnterpriseOsAppId(); - } else { - dnn = mApnSetting.getApnName(); - } - final TrafficDescriptor td = osAppId == null && dnn == null ? null - : new TrafficDescriptor(dnn, osAppId); - final boolean matchAllRuleAllowed = td == null || td.getOsAppId() == null; - - if (DBG) { - log("allowRoaming=" + allowRoaming - + ", mPhone.getDataRoamingEnabled()=" + mPhone.getDataRoamingEnabled() - + ", isModemRoaming=" + isModemRoaming - + ", mPhone.getServiceState().getDataRoaming()=" - + mPhone.getServiceState().getDataRoaming() - + ", isUnmeteredApnType=" + isUnmeteredApnType - + ", trafficDescriptor=" + td - + ", matchAllRuleAllowed=" + matchAllRuleAllowed - ); - } - - // Check if this data setup is a handover. - LinkProperties linkProperties = null; - int reason = DataService.REQUEST_REASON_NORMAL; - if (cp.mRequestType == REQUEST_TYPE_HANDOVER) { - // If this is a data setup for handover, we need to pass the link properties - // of the existing data connection to the modem. - DcTracker srcDcTracker = mPhone.getDcTracker(getHandoverSourceTransport()); - if (srcDcTracker == null || cp.mApnContext == null) { - loge("connect: Handover failed. dcTracker=" + srcDcTracker + ", apnContext=" - + cp.mApnContext); - return DataFailCause.HANDOVER_FAILED; - } - - - // srcDc is the source data connection while the current instance is the target - DataConnection srcDc = - srcDcTracker.getDataConnectionByApnType(cp.mApnContext.getApnType()); - if (srcDc == null) { - loge("connect: Can't find data connection for handover."); - return DataFailCause.HANDOVER_FAILED; - } - - // Helpful for logging purposes - DataServiceManager srcDsm = srcDc.mDataServiceManager; - String srcDsmTag = (srcDsm == null ? "(null)" : srcDsm.getTag()); - logd("connect: REQUEST_TYPE_HANDOVER - Request handover from " + srcDc.getName() - + ", targetDsm=" + mDataServiceManager.getTag() - + ", sourceDsm=" + srcDsmTag); - - - /* startHandover is called on the source data connection, and if successful, - we ask the target data connection (which is the current instance) to call - #setupDataCall with request type handover. - */ - Consumer onCompleted = (dataServiceCallbackResultCode) -> - /* startHandover is called on the srcDc handler, but the callback needs to - be called on the current (which is the targetDc) handler which is why we - call sendRunnableMessage. */ - sendRunnableMessage(EVENT_START_HANDOVER_ON_TARGET, - (inCorrectState) -> requestHandover(inCorrectState, srcDc, - dataServiceCallbackResultCode, - cp, msg, dp, isModemRoaming, allowRoaming)); - srcDc.startHandover(onCompleted); - return DataFailCause.NONE; - } - - // setup data call for REQUEST_TYPE_NORMAL - mDoAllocatePduSessionId = mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN; - allocatePduSessionId(psi -> { - this.setPduSessionId(psi); - mDataServiceManager.setupDataCall( - ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), - dp, - isModemRoaming, - allowRoaming, - reason, - linkProperties, - psi, - null, //slice info is null since this is not a handover - td, - matchAllRuleAllowed, - msg); - TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat, - dp.getProfileId(), dp.getApn(), dp.getProtocolType()); - }); - return DataFailCause.NONE; - } - - private void allocatePduSessionId(Consumer allocateCallback) { - if (mDoAllocatePduSessionId) { - Message msg = this.obtainMessage(EVENT_ALLOCATE_PDU_SESSION_ID); - msg.obj = allocateCallback; - mPhone.mCi.allocatePduSessionId(msg); - } else { - allocateCallback.accept(PDU_SESSION_ID_NOT_SET); - } - } - - private void onRquestHandoverFailed(ConnectionParams cp) { - sendMessage(obtainMessage(EVENT_CANCEL_HANDOVER)); - notifyConnectCompleted(cp, DataFailCause.UNKNOWN, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); - } - - private void requestHandover(boolean inCorrectState, DataConnection srcDc, - @DataServiceCallback.ResultCode int resultCode, - ConnectionParams cp, Message msg, DataProfile dp, boolean isModemRoaming, - boolean allowRoaming) { - - if (!inCorrectState) { - logd("requestHandover: Not in correct state"); - if (isResultCodeSuccess(resultCode)) { - if (srcDc != null) { - logd("requestHandover: Not in correct state - Success result code"); - // We need to cancel the handover on source if we ended up in the wrong state. - srcDc.cancelHandover(); - } else { - logd("requestHandover: Not in correct state - Success result code - " - + "srcdc = null"); - } - } - onRquestHandoverFailed(cp); - return; - } else if (!isResultCodeSuccess(resultCode)) { - if (DBG) { - logd("requestHandover: Non success result code from DataService, " - + "setupDataCall will not be called, result code = " - + DataServiceCallback.resultCodeToString(resultCode)); - } - onRquestHandoverFailed(cp); - return; - } - - if (srcDc == null) { - loge("requestHandover: Cannot find source data connection."); - onRquestHandoverFailed(cp); - return; - } - - LinkProperties linkProperties; - int reason; - - // Preserve the potential network agent from the source data connection. The ownership - // is not transferred at this moment. - mHandoverSourceNetworkAgent = srcDc.getNetworkAgent(); - if (mHandoverSourceNetworkAgent == null) { - loge("requestHandover: Cannot get network agent from the source dc " + srcDc.getName()); - onRquestHandoverFailed(cp); - return; - } - - linkProperties = srcDc.getLinkProperties(); - if (linkProperties == null || linkProperties.getLinkAddresses().isEmpty()) { - loge("requestHandover: Can't find link properties of handover data connection. dc=" - + srcDc); - onRquestHandoverFailed(cp); - return; - } - - mHandoverLocalLog.log("Handover started. Preserved the agent."); - log("Get the handover source network agent: " + mHandoverSourceNetworkAgent); - - reason = DataService.REQUEST_REASON_HANDOVER; - - TrafficDescriptor td = dp.getApn() == null ? null - : new TrafficDescriptor(dp.getApn(), null); - boolean matchAllRuleAllowed = true; - - mDataServiceManager.setupDataCall( - ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), - dp, - isModemRoaming, - allowRoaming, - reason, - linkProperties, - srcDc.getPduSessionId(), - srcDc.getSliceInfo(), - td, - matchAllRuleAllowed, - msg); - TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat, - dp.getProfileId(), dp.getApn(), dp.getProtocolType()); - } - - /** - * Called on the source data connection from the target data connection. - */ - @VisibleForTesting - public void startHandover(Consumer onTargetDcComplete) { - logd("startHandover: " + toStringSimple()); - // Set the handover state to being transferred on "this" data connection which is the src. - setHandoverState(HANDOVER_STATE_BEING_TRANSFERRED); - - Consumer onSrcDcComplete = - resultCode -> onHandoverStarted(resultCode, onTargetDcComplete); - /* - The flow here is: - srcDc#startHandover -> dataService#startHandover -> (onHandoverStarted) -> - onSrcDcComplete -> onTargetDcComplete - */ - mDataServiceManager.startHandover(mCid, - this.obtainMessage(EVENT_START_HANDOVER, - onSrcDcComplete)); - } - - /** - * Called on the source data connection when the async call to start handover is complete - */ - private void onHandoverStarted(@DataServiceCallback.ResultCode int resultCode, - Consumer onTargetDcComplete) { - logd("onHandoverStarted: " + toStringSimple()); - if (!isResultCodeSuccess(resultCode)) { - setHandoverState(HANDOVER_STATE_IDLE); - } - onTargetDcComplete.accept(resultCode); - } - - private void cancelHandover() { - if (mHandoverState != HANDOVER_STATE_BEING_TRANSFERRED) { - logd("cancelHandover: handover state is " + handoverStateToString(mHandoverState) - + ", expecting HANDOVER_STATE_BEING_TRANSFERRED"); - } - mDataServiceManager.cancelHandover(mCid, this.obtainMessage(EVENT_CANCEL_HANDOVER)); - setHandoverState(HANDOVER_STATE_IDLE); - } - - /** - * Update NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED based on congested override - * @param isCongested whether this DC should be set to congested or not - */ - public void onCongestednessChanged(boolean isCongested) { - sendMessage(obtainMessage(EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED, isCongested)); - } - - /** - * Update NetworkCapabilities.NET_CAPABILITY_NOT_METERED based on metered override - * @param isUnmetered whether this DC should be set to unmetered or not - */ - public void onMeterednessChanged(boolean isUnmetered) { - sendMessage(obtainMessage(EVENT_DATA_CONNECTION_METEREDNESS_CHANGED, isUnmetered)); - } - - /** - * TearDown the data connection when the deactivation is complete a Message with - * msg.what == EVENT_DEACTIVATE_DONE - * - * @param o is the object returned in the AsyncResult.obj. - */ - private void tearDownData(Object o) { - int discReason = DataService.REQUEST_REASON_NORMAL; - ApnContext apnContext = null; - if ((o != null) && (o instanceof DisconnectParams)) { - DisconnectParams dp = (DisconnectParams) o; - apnContext = dp.mApnContext; - if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF) - || TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) { - discReason = DataService.REQUEST_REASON_SHUTDOWN; - } else if (dp.mReleaseType == DcTracker.RELEASE_TYPE_HANDOVER) { - discReason = DataService.REQUEST_REASON_HANDOVER; - } - } - - String str = "tearDownData. mCid=" + mCid + ", reason=" + discReason; - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - - - //Needed to be final to work in a closure - final int fDiscReason = discReason; - releasePduSessionId(() -> { - // This is run after release pdu session id is complete - this.setPduSessionId(PDU_SESSION_ID_NOT_SET); - mDataServiceManager.deactivateDataCall(mCid, fDiscReason, - obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, o)); - mDataCallSessionStats.setDeactivateDataCallReason(fDiscReason); - }); - } - - private void releasePduSessionId(Runnable releaseCallback) { - // If the transport is IWLAN, and there is a valid PDU session id, also the data connection - // is not being handovered, we should release the pdu session id. - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN - && mHandoverState == HANDOVER_STATE_IDLE - && this.getPduSessionId() != PDU_SESSION_ID_NOT_SET) { - Message msg = this.obtainMessage(EVENT_RELEASE_PDU_SESSION_ID); - msg.obj = releaseCallback; - mPhone.mCi.releasePduSessionId(msg, this.getPduSessionId()); - } else { - // Just go and run the callback since we either have no pdu session id to release - // or we are in the middle of a handover - releaseCallback.run(); - } - } - - private void notifyAllWithEvent(ApnContext alreadySent, int event, String reason) { - for (ConnectionParams cp : mApnContexts.values()) { - ApnContext apnContext = cp.mApnContext; - if (apnContext == alreadySent) continue; - if (reason != null) apnContext.setReason(reason); - Pair pair = new Pair<>(apnContext, cp.mConnectionGeneration); - Message msg = mDct.obtainMessage(event, cp.mRequestType, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, pair); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - } - } - - /** - * Send the connectionCompletedMsg. - * - * @param cp is the ConnectionParams - * @param cause and if no error the cause is DataFailCause.NONE - * @param handoverFailureMode The action on handover failure - * @param sendAll is true if all contexts are to be notified - */ - private void notifyConnectCompleted(ConnectionParams cp, @DataFailureCause int cause, - @HandoverFailureMode int handoverFailureMode, boolean sendAll) { - ApnContext alreadySent = null; - - if (cp != null && cp.mOnCompletedMsg != null) { - // Get the completed message but only use it once - Message connectionCompletedMsg = cp.mOnCompletedMsg; - cp.mOnCompletedMsg = null; - alreadySent = cp.mApnContext; - - long timeStamp = System.currentTimeMillis(); - connectionCompletedMsg.arg1 = cp.mRequestType; - connectionCompletedMsg.arg2 = handoverFailureMode; - - if (cause == DataFailCause.NONE) { - mCreateTime = timeStamp; - AsyncResult.forMessage(connectionCompletedMsg); - } else { - mLastFailCause = cause; - mLastFailTime = timeStamp; - - // Return message with a Throwable exception to signify an error. - if (cause == DataFailCause.NONE) cause = DataFailCause.UNKNOWN; - AsyncResult.forMessage(connectionCompletedMsg, cause, - new Throwable(DataFailCause.toString(cause))); - } - if (DBG) { - log("notifyConnectCompleted at " + timeStamp + " cause=" - + DataFailCause.toString(cause) + " connectionCompletedMsg=" - + msgToString(connectionCompletedMsg)); - } - - connectionCompletedMsg.sendToTarget(); - } - if (sendAll) { - log("Send to all. " + alreadySent + " " + DataFailCause.toString(cause)); - notifyAllWithEvent(alreadySent, DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR, - DataFailCause.toString(cause)); - } - } - - /** - * Send ar.userObj if its a message, which is should be back to originator. - * - * @param dp is the DisconnectParams. - */ - private void notifyDisconnectCompleted(DisconnectParams dp, boolean sendAll) { - if (VDBG) log("NotifyDisconnectCompleted"); - - ApnContext alreadySent = null; - String reason = null; - - if (dp != null && dp.mOnCompletedMsg != null) { - // Get the completed message but only use it once - Message msg = dp.mOnCompletedMsg; - dp.mOnCompletedMsg = null; - if (msg.obj instanceof ApnContext) { - alreadySent = (ApnContext)msg.obj; - } - reason = dp.mReason; - if (VDBG) { - log(String.format("msg=%s msg.obj=%s", msg.toString(), - ((msg.obj instanceof String) ? (String) msg.obj : ""))); - } - AsyncResult.forMessage(msg); - msg.sendToTarget(); - } - if (sendAll) { - if (reason == null) { - reason = DataFailCause.toString(DataFailCause.UNKNOWN); - } - notifyAllWithEvent(alreadySent, DctConstants.EVENT_DISCONNECT_DONE, reason); - } - if (DBG) log("NotifyDisconnectCompleted DisconnectParams=" + dp); - } - - private void sendRunnableMessage(int eventCode, @NonNull final Consumer r) { - sendMessage(eventCode, r); - } - - /* - * ************************************************************************** - * Begin Members and methods owned by DataConnectionTracker but stored - * in a DataConnection because there is one per connection. - * ************************************************************************** - */ - - /* - * The id is owned by DataConnectionTracker. - */ - private int mId; - - /** - * Get the DataConnection ID - */ - public int getDataConnectionId() { - return mId; - } - - /* - * ************************************************************************** - * End members owned by DataConnectionTracker - * ************************************************************************** - */ - - /** - * Clear all settings called when entering mInactiveState. - */ - private synchronized void clearSettings() { - if (DBG) log("clearSettings"); - - mCreateTime = -1; - mLastFailTime = -1; - mLastFailCause = DataFailCause.NONE; - mCid = -1; - - mPcscfAddr = new String[5]; - - mLinkProperties = new LinkProperties(); - mApnContexts.clear(); - mApnSetting = null; - mUnmeteredUseOnly = false; - mMmsUseOnly = false; - mEnterpriseUse = false; - mRestrictedNetworkOverride = false; - mDcFailCause = DataFailCause.NONE; - mDisabledApnTypeBitMask = 0; - mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - mCongestedOverride = false; - mUnmeteredOverride = false; - mDownlinkBandwidth = 14; - mUplinkBandwidth = 14; - mIsSuspended = false; - mHandoverState = HANDOVER_STATE_IDLE; - mHandoverFailureMode = DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN; - mSliceInfo = null; - mDefaultQos = null; - mDoAllocatePduSessionId = false; - mQosBearerSessions.clear(); - mTrafficDescriptors.clear(); - } - - /** - * Process setup data completion result from data service - * - * @param resultCode The result code returned by data service - * @param response Data call setup response from data service - * @param cp The original connection params used for data call setup - * @return Setup result - */ - private SetupResult onSetupConnectionCompleted(@DataServiceCallback.ResultCode int resultCode, - DataCallResponse response, - ConnectionParams cp) { - SetupResult result; - - log("onSetupConnectionCompleted: resultCode=" + resultCode + ", response=" + response); - if (cp.mTag != mTag) { - if (DBG) { - log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag); - } - result = SetupResult.ERROR_STALE; - } else if (resultCode == DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE) { - result = SetupResult.ERROR_RADIO_NOT_AVAILABLE; - result.mFailCause = DataFailCause.RADIO_NOT_AVAILABLE; - } else if (resultCode == DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE) { - result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; - result.mFailCause = DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE; - } else if (resultCode == DataServiceCallback.RESULT_ERROR_INVALID_ARG) { - result = SetupResult.ERROR_INVALID_ARG; - result.mFailCause = DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER; - } else if (response.getCause() != 0) { - if (response.getCause() == DataFailCause.RADIO_NOT_AVAILABLE) { - result = SetupResult.ERROR_RADIO_NOT_AVAILABLE; - result.mFailCause = DataFailCause.RADIO_NOT_AVAILABLE; - } else { - result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; - result.mFailCause = DataFailCause.getFailCause(response.getCause()); - } - } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE - && mDcController.getActiveDcByCid(response.getId()) != null) { - if (!mDcController.getTrafficDescriptorsForCid(response.getId()) - .equals(response.getTrafficDescriptors())) { - if (DBG) log("Updating traffic descriptors: " + response.getTrafficDescriptors()); - mDcController.getActiveDcByCid(response.getId()).updateTrafficDescriptors(response); - mDct.obtainMessage(DctConstants.EVENT_TRAFFIC_DESCRIPTORS_UPDATED).sendToTarget(); - } - if (DBG) log("DataConnection already exists for cid: " + response.getId()); - result = SetupResult.ERROR_DUPLICATE_CID; - result.mFailCause = DataFailCause.DUPLICATE_CID; - } else if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE - && !mDcController.isDefaultDataActive()) { - if (DBG) log("No default data connection currently active"); - mCid = response.getId(); - result = SetupResult.ERROR_NO_DEFAULT_CONNECTION; - result.mFailCause = DataFailCause.NO_DEFAULT_DATA; - } else { - if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse"); - mCid = response.getId(); - setPduSessionId(response.getPduSessionId()); - updatePcscfAddr(response); - updateResponseFields(response); - result = updateLinkProperty(response).setupResult; - } - - return result; - } - - private static boolean isResultCodeSuccess(int resultCode) { - return resultCode == DataServiceCallback.RESULT_SUCCESS - || resultCode == DataServiceCallback.RESULT_ERROR_UNSUPPORTED; - } - - private boolean isDnsOk(String[] domainNameServers) { - if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1]) - && !mPhone.isDnsCheckDisabled()) { - // Work around a race condition where QMI does not fill in DNS: - // Deactivate PDP and let DataConnectionTracker retry. - // Do not apply the race condition workaround for MMS APN - // if Proxy is an IP-address. - // Otherwise, the default APN will not be restored anymore. - if (!isIpAddress(mApnSetting.getMmsProxyAddressAsString())) { - log(String.format( - "isDnsOk: return false apn.types=%d APN_TYPE_MMS=%s isIpAddress(%s)=%s", - mApnSetting.getApnTypeBitmask(), ApnSetting.TYPE_MMS_STRING, - mApnSetting.getMmsProxyAddressAsString(), - isIpAddress(mApnSetting.getMmsProxyAddressAsString()))); - return false; - } - } - return true; - } - - /** - * TCP buffer size config based on the ril technology. There are 6 parameters - * read_min, read_default, read_max, write_min, write_default, write_max in the TCP buffer - * config string and they are separated by a comma. The unit of these parameters is byte. - */ - private static final String TCP_BUFFER_SIZES_GPRS = "4092,8760,48000,4096,8760,48000"; - private static final String TCP_BUFFER_SIZES_EDGE = "4093,26280,70800,4096,16384,70800"; - private static final String TCP_BUFFER_SIZES_UMTS = "58254,349525,1048576,58254,349525,1048576"; - private static final String TCP_BUFFER_SIZES_1XRTT = "16384,32768,131072,4096,16384,102400"; - private static final String TCP_BUFFER_SIZES_EVDO = "4094,87380,262144,4096,16384,262144"; - private static final String TCP_BUFFER_SIZES_EHRPD = "131072,262144,1048576,4096,16384,524288"; - private static final String TCP_BUFFER_SIZES_HSDPA = "61167,367002,1101005,8738,52429,262114"; - private static final String TCP_BUFFER_SIZES_HSPA = "40778,244668,734003,16777,100663,301990"; - private static final String TCP_BUFFER_SIZES_LTE = - "524288,1048576,2097152,262144,524288,1048576"; - private static final String TCP_BUFFER_SIZES_HSPAP = - "122334,734003,2202010,32040,192239,576717"; - private static final String TCP_BUFFER_SIZES_NR = - "2097152,6291456,16777216,512000,2097152,8388608"; - private static final String TCP_BUFFER_SIZES_LTE_CA = - "4096,6291456,12582912,4096,1048576,2097152"; - - private void updateTcpBufferSizes(int rilRat) { - String sizes = null; - ServiceState ss = mPhone.getServiceState(); - if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE && - ss.isUsingCarrierAggregation()) { - rilRat = ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA; - } - String ratName = ServiceState.rilRadioTechnologyToString(rilRat).toLowerCase(Locale.ROOT); - // ServiceState gives slightly different names for EVDO tech ("evdo-rev.0" for ex) - // - patch it up: - if (rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0 || - rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A || - rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B) { - ratName = RAT_NAME_EVDO; - } - - // NR 5G Non-Standalone use LTE cell as the primary cell, the ril technology is LTE in this - // case. We use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network. - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN - && ((rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE || - rilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA) && isNRConnected()) - && mPhone.getServiceStateTracker().getNrContextIds().contains(mCid)) { - ratName = RAT_NAME_5G; - } - - log("updateTcpBufferSizes: " + ratName); - - // in the form: "ratname:rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max" - String[] configOverride = mPhone.getContext().getResources().getStringArray( - com.android.internal.R.array.config_mobile_tcp_buffers); - for (int i = 0; i < configOverride.length; i++) { - String[] split = configOverride[i].split(":"); - if (ratName.equals(split[0]) && split.length == 2) { - sizes = split[1]; - break; - } - } - - if (sizes == null) { - // no override - use telephony defaults - // doing it this way allows device or carrier to just override the types they - // care about and inherit the defaults for the others. - switch (rilRat) { - case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS: - sizes = TCP_BUFFER_SIZES_GPRS; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE: - sizes = TCP_BUFFER_SIZES_EDGE; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS: - sizes = TCP_BUFFER_SIZES_UMTS; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT: - sizes = TCP_BUFFER_SIZES_1XRTT; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0: - case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A: - case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B: - sizes = TCP_BUFFER_SIZES_EVDO; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD: - sizes = TCP_BUFFER_SIZES_EHRPD; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA: - sizes = TCP_BUFFER_SIZES_HSDPA; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA: - case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA: - sizes = TCP_BUFFER_SIZES_HSPA; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_LTE: - // Use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network. - if (RAT_NAME_5G.equals(ratName)) { - sizes = TCP_BUFFER_SIZES_NR; - } else { - sizes = TCP_BUFFER_SIZES_LTE; - } - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA: - // Use NR 5G TCP buffer size when connected to NR 5G Non-Standalone network. - if (RAT_NAME_5G.equals(ratName)) { - sizes = TCP_BUFFER_SIZES_NR; - } else { - sizes = TCP_BUFFER_SIZES_LTE_CA; - } - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP: - sizes = TCP_BUFFER_SIZES_HSPAP; - break; - case ServiceState.RIL_RADIO_TECHNOLOGY_NR: - sizes = TCP_BUFFER_SIZES_NR; - break; - default: - // Leave empty - this will let ConnectivityService use the system default. - break; - } - } - mLinkProperties.setTcpBufferSizes(sizes); - } - - private void updateLinkBandwidthsFromCarrierConfig(int rilRat) { - String ratName = DataConfigManager.getDataConfigNetworkType( - mPhone.getDisplayInfoController().getTelephonyDisplayInfo()); - - if (DBG) log("updateLinkBandwidthsFromCarrierConfig: " + ratName); - - Pair values = mDct.getLinkBandwidthsFromCarrierConfig(ratName); - if (values == null) { - values = new Pair<>(14, 14); - } - mDownlinkBandwidth = values.first; - mUplinkBandwidth = values.second; - } - - - private void updateLinkBandwidthsFromModem(List lceList) { - if (DBG) log("updateLinkBandwidthsFromModem: lceList=" + lceList); - boolean downlinkUpdated = false; - boolean uplinkUpdated = false; - LinkCapacityEstimate lce = lceList.get(0); - // LCE status deprecated in IRadio 1.2, so only check for IRadio < 1.2 - if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_2) - || mPhone.getLceStatus() == RILConstants.LCE_ACTIVE) { - if (lce.getDownlinkCapacityKbps() != LinkCapacityEstimate.INVALID) { - mDownlinkBandwidth = lce.getDownlinkCapacityKbps(); - downlinkUpdated = true; - } - if (lce.getUplinkCapacityKbps() != LinkCapacityEstimate.INVALID) { - mUplinkBandwidth = lce.getUplinkCapacityKbps(); - uplinkUpdated = true; - } - } - - if (!downlinkUpdated || !uplinkUpdated) { - fallBackToCarrierConfigValues(downlinkUpdated, uplinkUpdated); - } - - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this); - } - } - - private void updateLinkBandwidthsFromBandwidthEstimator(int uplinkBandwidthKbps, - int downlinkBandwidthKbps) { - if (DBG) { - log("updateLinkBandwidthsFromBandwidthEstimator, UL= " - + uplinkBandwidthKbps + " DL= " + downlinkBandwidthKbps); - } - boolean downlinkUpdated = false; - boolean uplinkUpdated = false; - if (downlinkBandwidthKbps > 0) { - mDownlinkBandwidth = downlinkBandwidthKbps; - downlinkUpdated = true; - } - if (uplinkBandwidthKbps > 0) { - mUplinkBandwidth = uplinkBandwidthKbps; - uplinkUpdated = true; - } - - if (!downlinkUpdated || !uplinkUpdated) { - fallBackToCarrierConfigValues(downlinkUpdated, uplinkUpdated); - } - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this); - } - } - - private void fallBackToCarrierConfigValues(boolean downlinkUpdated, boolean uplinkUpdated) { - String ratName = ServiceState.rilRadioTechnologyToString(mRilRat); - if (mRilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE && isNRConnected()) { - ratName = mPhone.getServiceState().getNrFrequencyRange() - == ServiceState.FREQUENCY_RANGE_MMWAVE - ? DctConstants.RAT_NAME_NR_NSA_MMWAVE : DctConstants.RAT_NAME_NR_NSA; - } - Pair values = mDct.getLinkBandwidthsFromCarrierConfig(ratName); - if (values != null) { - if (!downlinkUpdated) { - mDownlinkBandwidth = values.first; - } - if (!uplinkUpdated) { - mUplinkBandwidth = values.second; - } - mUplinkBandwidth = Math.min(mUplinkBandwidth, mDownlinkBandwidth); - } - } - - private boolean isBandwidthSourceKey(String source) { - return source.equals(mPhone.getContext().getResources().getString( - com.android.internal.R.string.config_bandwidthEstimateSource)); - } - - /** - * Indicates if this data connection was established for unmetered use only. Note that this - * flag should be populated when data becomes active. And if it is set to true, it can be set to - * false later when we are reevaluating the data connection. But if it is set to false, it - * can never become true later because setting it to true will cause this data connection - * losing some immutable network capabilities, which can cause issues in connectivity service. - */ - private boolean mUnmeteredUseOnly = false; - - /** - * Indicates if this data connection was established for MMS use only. This is true only when - * mobile data is disabled but the user allows sending and receiving MMS messages. If the data - * enabled settings indicate that MMS data is allowed unconditionally, MMS can be sent when data - * is disabled even if it is a metered APN type. - */ - private boolean mMmsUseOnly = false; - - /** - * Indicates if when this connection was established we had a restricted/privileged - * NetworkRequest and needed it to overcome data-enabled limitations. - * - * This flag overrides the APN-based restriction capability, restricting the network - * based on both having a NetworkRequest with restricted AND needing a restricted - * bit to overcome user-disabled status. This allows us to handle the common case - * of having both restricted requests and unrestricted requests for the same apn: - * if conditions require a restricted network to overcome user-disabled then it must - * be restricted, otherwise it is unrestricted (or restricted based on APN type). - * - * This supports a privileged app bringing up a network without general apps having access - * to it when the network is otherwise unavailable (hipri). The first use case is - * pre-paid SIM reprovisioning over internet, where the carrier insists on no traffic - * other than from the privileged carrier-app. - * - * Note that the data connection cannot go from unrestricted to restricted because the - * connectivity service does not support dynamically closing TCP connections at this point. - */ - private boolean mRestrictedNetworkOverride = false; - - /** - * Indicates if this data connection supports enterprise use. Note that this flag should be - * populated when data becomes active. Once it is set, the value cannot be changed because - * setting it will cause this data connection to lose immutable network capabilities, which can - * cause issues in connectivity service. - */ - private boolean mEnterpriseUse = false; - - /** - * Check if this data connection should be restricted. We should call this when data connection - * becomes active, or when we want to re-evaluate the conditions to decide if we need to - * unstrict the data connection. - * - * @return True if this data connection needs to be restricted. - */ - private boolean shouldRestrictNetwork() { - // first, check if there is any network request that containing restricted capability - // (i.e. Do not have NET_CAPABILITY_NOT_RESTRICTED in the request) - boolean isAnyRestrictedRequest = false; - for (ApnContext apnContext : mApnContexts.keySet()) { - if (apnContext.hasRestrictedRequests(true /* exclude DUN */)) { - isAnyRestrictedRequest = true; - break; - } - } - - // If all of the network requests are non-restricted, then we don't need to restrict - // the network. - if (!isAnyRestrictedRequest) { - return false; - } - - // If the network is unmetered, then we don't need to restrict the network because users - // won't be charged anyway. - if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { - return false; - } - - // If the data is disabled, then we need to restrict the network so only privileged apps can - // use the restricted network while data is disabled. - if (!mPhone.getDataEnabledSettings().isDataEnabled()) { - return true; - } - - // If the device is roaming, and the user does not turn on data roaming, then we need to - // restrict the network so only privileged apps can use it. - if (!mDct.getDataRoamingEnabled() && mPhone.getServiceState().getDataRoaming()) { - return true; - } - - // Otherwise we should not restrict the network so anyone who requests can use it. - return false; - } - - /** - * @return True if this data connection should only be used for unmetered purposes. - */ - private boolean isUnmeteredUseOnly() { - // If this data connection is on IWLAN, then it's unmetered and can be used by everyone. - // Should not be for unmetered used only. - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - return false; - } - - // If data is enabled, this data connection can't be for unmetered used only because - // everyone should be able to use it if: - // 1. Device is not roaming, or - // 2. Device is roaming and data roaming is turned on - if (mPhone.getDataEnabledSettings().isDataEnabled()) { - if (!mPhone.getServiceState().getDataRoaming() || mDct.getDataRoamingEnabled()) { - return false; - } - } - - // The data connection can only be unmetered used only if all attached APN contexts - // attached to this data connection are unmetered. - for (ApnContext apnContext : mApnContexts.keySet()) { - if (ApnSettingUtils.isMeteredApnType(apnContext.getApnTypeBitmask(), mPhone)) { - return false; - } - } - return true; - } - - /** - * @return True if this data connection should only be used for MMS purposes. - */ - private boolean isMmsUseOnly() { - // MMS use only if data is disabled, MMS is allowed unconditionally, and MMS is the only - // APN type for this data connection. - DataEnabledSettings des = mPhone.getDataEnabledSettings(); - boolean mmsAllowedUnconditionally = !des.isDataEnabled() && des.isMmsAlwaysAllowed(); - boolean mmsApnOnly = isApnContextAttached(ApnSetting.TYPE_MMS, true); - return mmsAllowedUnconditionally && mmsApnOnly; - } - - /** - * Check if this data connection supports enterprise use. We call this when the data connection - * becomes active or when we want to reevaluate the conditions to decide if we need to update - * the network agent capabilities. - * - * @return True if this data connection supports enterprise use. - */ - private boolean isEnterpriseUse() { - return mApnContexts.keySet().stream().anyMatch( - ac -> ac.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE); - } - - /** - * Get the network capabilities for this data connection. - * - * @return the {@link NetworkCapabilities} of this data connection. - */ - public NetworkCapabilities getNetworkCapabilities() { - final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); - boolean unmeteredApns = false; - - if (mApnSetting != null && !mEnterpriseUse && !mMmsUseOnly) { - final int[] types = ApnSetting.getApnTypesFromBitmask( - mApnSetting.getApnTypeBitmask() & ~mDisabledApnTypeBitMask); - for (int type : types) { - if ((!mRestrictedNetworkOverride && mUnmeteredUseOnly) - && ApnSettingUtils.isMeteredApnType(type, mPhone)) { - log("Dropped the metered " + ApnSetting.getApnTypeString(type) - + " type for the unmetered data call."); - continue; - } - switch (type) { - case ApnSetting.TYPE_ALL: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); - break; - } - case ApnSetting.TYPE_DEFAULT: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - break; - } - case ApnSetting.TYPE_MMS: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); - break; - } - case ApnSetting.TYPE_SUPL: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); - break; - } - case ApnSetting.TYPE_DUN: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); - break; - } - case ApnSetting.TYPE_FOTA: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); - break; - } - case ApnSetting.TYPE_IMS: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); - break; - } - case ApnSetting.TYPE_CBS: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); - break; - } - case ApnSetting.TYPE_IA: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); - break; - } - case ApnSetting.TYPE_EMERGENCY: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS); - break; - } - case ApnSetting.TYPE_MCX: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MCX); - break; - } - case ApnSetting.TYPE_XCAP: { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP); - break; - } - default: - } - } - - if (!ApnSettingUtils.isMetered(mApnSetting, mPhone)) { - unmeteredApns = true; - } - } - - // Mark NOT_METERED in the following cases: - // 1. All APNs in the APN settings are unmetered. - // 2. The non-restricted data is intended for unmetered use only. - if (unmeteredApns || (mUnmeteredUseOnly && !mRestrictedNetworkOverride)) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } else { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } - - if (mEnterpriseUse) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - } - - if (NetworkCapabilitiesUtils.inferRestrictedCapability(builder.build())) { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - } - - if (mMmsUseOnly) { - if (ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)) { - log("Adding unmetered capability for the unmetered MMS-only data connection"); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } - log("Adding MMS capability for the MMS-only data connection"); - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); - } - - if (mRestrictedNetworkOverride) { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - // don't use dun on restriction-overriden networks. - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_DUN); - } - - builder.setLinkDownstreamBandwidthKbps(mDownlinkBandwidth); - builder.setLinkUpstreamBandwidthKbps(mUplinkBandwidth); - - builder.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() - .setSubscriptionId(mSubId).build()); - builder.setSubscriptionIds(Collections.singleton(mSubId)); - - if (!mPhone.getServiceState().getDataRoaming()) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - } - - if (!mCongestedOverride) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); - } - - if (mUnmeteredOverride) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED); - } - - if (!mIsSuspended) { - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); - } - - final int carrierServicePackageUid = getCarrierServicePackageUid(); - - // TODO(b/205736323): Owner and Admin UIDs currently come from separate data sources. Unify - // them, and remove ArrayUtils.contains() check. - if (carrierServicePackageUid != Process.INVALID_UID - && ArrayUtils.contains(mAdministratorUids, carrierServicePackageUid)) { - builder.setOwnerUid(carrierServicePackageUid); - builder.setAllowedUids(Collections.singleton(carrierServicePackageUid)); - } - builder.setAdministratorUids(mAdministratorUids); - - // Always start with NOT_VCN_MANAGED, then remove if VcnManager indicates this is part of a - // VCN. - builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - final VcnNetworkPolicyResult vcnPolicy = getVcnPolicy(builder.build()); - if (!vcnPolicy.getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)) { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - } - if (!vcnPolicy.getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)) { - builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - } - - return builder.build(); - } - - // TODO(b/205736323): Once TelephonyManager#getCarrierServicePackageNameForLogicalSlot() is - // plumbed to CarrierPrivilegesTracker's cache, query the cached UIDs. - private int getFirstUidForPackage(String pkgName) { - if (pkgName == null) { - return Process.INVALID_UID; - } - - List users = mPhone.getContext().getSystemService(UserManager.class).getUsers(); - for (UserInfo user : users) { - int userId = user.getUserHandle().getIdentifier(); - try { - PackageManager pm = mPhone.getContext().getPackageManager(); - - if (pm != null) { - return pm.getPackageUidAsUser(pkgName, userId); - } - } catch (NameNotFoundException exception) { - // Didn't find package. Try other users - Rlog.i( - "DataConnection", - "Unable to find uid for package " + pkgName + " and user " + userId); - } - } - return Process.INVALID_UID; - } - - private int getCarrierServicePackageUid() { - String pkgName = - mPhone.getContext() - .getSystemService(TelephonyManager.class) - .getCarrierServicePackageNameForLogicalSlot(mPhone.getPhoneId()); - - return getFirstUidForPackage(pkgName); - } - - /** - * Check if the this data network is VCN-managed. - * - * @param networkCapabilities The network capabilities of this data network. - * @return The VCN's policy for this DataNetwork. - */ - private VcnNetworkPolicyResult getVcnPolicy(NetworkCapabilities networkCapabilities) { - return mVcnManager.applyVcnNetworkPolicy(networkCapabilities, getLinkProperties()); - } - - /** @return {@code true} if validation is required, {@code false} otherwise. */ - public boolean isValidationRequired() { - final NetworkCapabilities nc = getNetworkCapabilities(); - return nc != null - && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); - } - - /** - * @return {@code True} if 464xlat should be skipped. - */ - @VisibleForTesting - public boolean shouldSkip464Xlat() { - switch (mApnSetting.getSkip464Xlat()) { - case Telephony.Carriers.SKIP_464XLAT_ENABLE: - return true; - case Telephony.Carriers.SKIP_464XLAT_DISABLE: - return false; - case Telephony.Carriers.SKIP_464XLAT_DEFAULT: - default: - break; - } - - // As default, return true if ims and no internet - final NetworkCapabilities nc = getNetworkCapabilities(); - return nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS) - && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - } - - /** - * @return {@code} true iff. {@code address} is a literal IPv4 or IPv6 address. - */ - @VisibleForTesting - public static boolean isIpAddress(String address) { - if (address == null) return false; - - // Accept IPv6 addresses (only) in square brackets for compatibility. - if (address.startsWith("[") && address.endsWith("]") && address.indexOf(':') != -1) { - address = address.substring(1, address.length() - 1); - } - return InetAddresses.isNumericAddress(address); - } - - private SetupResult setLinkProperties(DataCallResponse response, - LinkProperties linkProperties) { - // Check if system property dns usable - String propertyPrefix = "net." + response.getInterfaceName() + "."; - String dnsServers[] = new String[2]; - dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1"); - dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2"); - boolean okToUseSystemPropertyDns = isDnsOk(dnsServers); - - SetupResult result; - - // Start with clean network properties and if we have - // a failure we'll clear again at the bottom of this code. - linkProperties.clear(); - - if (response.getCause() == DataFailCause.NONE) { - try { - // set interface name - linkProperties.setInterfaceName(response.getInterfaceName()); - - // set link addresses - if (response.getAddresses().size() > 0) { - for (LinkAddress la : response.getAddresses()) { - if (!la.getAddress().isAnyLocalAddress()) { - if (DBG) { - log("addr/pl=" + la.getAddress() + "/" - + la.getPrefixLength()); - } - linkProperties.addLinkAddress(la); - } - } - } else { - throw new UnknownHostException("no address for ifname=" - + response.getInterfaceName()); - } - - // set dns servers - if (response.getDnsAddresses().size() > 0) { - for (InetAddress dns : response.getDnsAddresses()) { - if (!dns.isAnyLocalAddress()) { - linkProperties.addDnsServer(dns); - } - } - } else if (okToUseSystemPropertyDns) { - for (String dnsAddr : dnsServers) { - dnsAddr = dnsAddr.trim(); - if (dnsAddr.isEmpty()) continue; - InetAddress ia; - try { - ia = InetAddresses.parseNumericAddress(dnsAddr); - } catch (IllegalArgumentException e) { - throw new UnknownHostException("Non-numeric dns addr=" + dnsAddr); - } - if (!ia.isAnyLocalAddress()) { - linkProperties.addDnsServer(ia); - } - } - } else { - throw new UnknownHostException("Empty dns response and no system default dns"); - } - - // set pcscf - if (response.getPcscfAddresses().size() > 0) { - for (InetAddress pcscf : response.getPcscfAddresses()) { - linkProperties.addPcscfServer(pcscf); - } - } - - for (InetAddress gateway : response.getGatewayAddresses()) { - int mtu = gateway instanceof java.net.Inet6Address ? response.getMtuV6() - : response.getMtuV4(); - // Allow 0.0.0.0 or :: as a gateway; - // this indicates a point-to-point interface. - linkProperties.addRoute(new RouteInfo(null, gateway, null, - RouteInfo.RTN_UNICAST, mtu)); - } - - // set interface MTU - // this may clobber the setting read from the APN db, but that's ok - // TODO: remove once LinkProperties#setMtu is deprecated - linkProperties.setMtu(response.getMtu()); - - result = SetupResult.SUCCESS; - } catch (UnknownHostException e) { - log("setLinkProperties: UnknownHostException " + e); - result = SetupResult.ERROR_INVALID_ARG; - } - } else { - result = SetupResult.ERROR_DATA_SERVICE_SPECIFIC_ERROR; - } - - // An error occurred so clear properties - if (result != SetupResult.SUCCESS) { - if (DBG) { - log("setLinkProperties: error clearing LinkProperties status=" - + response.getCause() + " result=" + result); - } - linkProperties.clear(); - } - - return result; - } - - /** - * Initialize connection, this will fail if the - * apnSettings are not compatible. - * - * @param cp the Connection parameters - * @return true if initialization was successful. - */ - private boolean initConnection(ConnectionParams cp) { - ApnContext apnContext = cp.mApnContext; - if (mApnSetting == null) { - // Only change apn setting if it isn't set, it will - // only NOT be set only if we're in DcInactiveState. - mApnSetting = apnContext.getApnSetting(); - } - if (mApnSetting == null || (!mApnSetting.canHandleType(apnContext.getApnTypeBitmask()) - && apnContext.getApnTypeBitmask() != ApnSetting.TYPE_ENTERPRISE)) { - if (DBG) { - log("initConnection: incompatible apnSetting in ConnectionParams cp=" + cp - + " dc=" + DataConnection.this); - } - return false; - } - mTag += 1; - mConnectionParams = cp; - mConnectionParams.mTag = mTag; - - // always update the ConnectionParams with the latest or the - // connectionGeneration gets stale - mApnContexts.put(apnContext, cp); - - if (DBG) { - log("initConnection: " - + " RefCount=" + mApnContexts.size() - + " mApnList=" + mApnContexts - + " mConnectionParams=" + mConnectionParams); - } - return true; - } - - /** - * The parent state for all other states. - */ - private class DcDefaultState extends State { - @Override - public void enter() { - if (DBG) log("DcDefaultState: enter"); - - // Register for DRS or RAT change - mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged( - mTransportType, getHandler(), - DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, null); - - mPhone.getServiceStateTracker().registerForDataRoamingOn(getHandler(), - DataConnection.EVENT_DATA_CONNECTION_ROAM_ON, null); - mPhone.getServiceStateTracker().registerForDataRoamingOff(getHandler(), - DataConnection.EVENT_DATA_CONNECTION_ROAM_OFF, null, true); - mPhone.getServiceStateTracker().registerForNrStateChanged(getHandler(), - DataConnection.EVENT_NR_STATE_CHANGED, null); - mPhone.getServiceStateTracker().registerForNrFrequencyChanged(getHandler(), - DataConnection.EVENT_NR_FREQUENCY_CHANGED, null); - mPhone.getServiceStateTracker().registerForCssIndicatorChanged(getHandler(), - DataConnection.EVENT_CSS_INDICATOR_CHANGED, null); - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR_KEY)) { - mPhone.getLinkBandwidthEstimator().registerForBandwidthChanged(getHandler(), - DataConnection.EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE, null); - } - - // Add ourselves to the list of data connections - mDcController.addDc(DataConnection.this); - } - @Override - public void exit() { - if (DBG) log("DcDefaultState: exit"); - - // Unregister for DRS or RAT change. - mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged( - mTransportType, getHandler()); - - mPhone.getServiceStateTracker().unregisterForDataRoamingOn(getHandler()); - mPhone.getServiceStateTracker().unregisterForDataRoamingOff(getHandler()); - mPhone.getServiceStateTracker().unregisterForNrStateChanged(getHandler()); - mPhone.getServiceStateTracker().unregisterForNrFrequencyChanged(getHandler()); - mPhone.getServiceStateTracker().unregisterForCssIndicatorChanged(getHandler()); - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR_KEY)) { - mPhone.getLinkBandwidthEstimator().unregisterForBandwidthChanged(getHandler()); - } - - // Remove ourselves from the DC lists - mDcController.removeDc(DataConnection.this); - - if (mAc != null) { - mAc.disconnected(); - mAc = null; - } - mApnContexts.clear(); - mReconnectIntent = null; - mDct = null; - mApnSetting = null; - mPhone = null; - mDataServiceManager = null; - mLinkProperties = null; - mLastFailCause = DataFailCause.NONE; - mUserData = null; - mDcController = null; - mDcTesterFailBringUpAll = null; - } - - @Override - public boolean processMessage(Message msg) { - boolean retVal = HANDLED; - - if (VDBG) { - log("DcDefault msg=" + getWhatToString(msg.what) - + " RefCount=" + mApnContexts.size()); - } - switch (msg.what) { - case EVENT_RESET: - if (VDBG) log("DcDefaultState: msg.what=REQ_RESET"); - transitionTo(mInactiveState); - break; - case EVENT_CONNECT: - if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected"); - ConnectionParams cp = (ConnectionParams) msg.obj; - notifyConnectCompleted(cp, DataFailCause.UNKNOWN, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); - break; - - case EVENT_DISCONNECT: - case EVENT_DISCONNECT_ALL: - case EVENT_REEVALUATE_RESTRICTED_STATE: - if (DBG) { - log("DcDefaultState deferring msg.what=" + getWhatToString(msg.what) - + " RefCount=" + mApnContexts.size()); - } - deferMessage(msg); - break; - case EVENT_TEAR_DOWN_NOW: - if (DBG) log("DcDefaultState EVENT_TEAR_DOWN_NOW"); - mDataServiceManager.deactivateDataCall(mCid, DataService.REQUEST_REASON_NORMAL, - null); - mDataCallSessionStats.setDeactivateDataCallReason( - DataService.REQUEST_REASON_NORMAL); - break; - case EVENT_LOST_CONNECTION: - if (DBG) { - String s = "DcDefaultState ignore EVENT_LOST_CONNECTION" - + " tag=" + msg.arg1 + ":mTag=" + mTag; - logAndAddLogRec(s); - } - break; - case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: - AsyncResult ar = (AsyncResult)msg.obj; - Pair drsRatPair = (Pair)ar.result; - mDataRegState = drsRatPair.first; - updateTcpBufferSizes(drsRatPair.second); - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { - updateLinkBandwidthsFromCarrierConfig(drsRatPair.second); - } - mRilRat = drsRatPair.second; - if (DBG) { - log("DcDefaultState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED" - + " regState=" + ServiceState.rilServiceStateToString(mDataRegState) - + " RAT=" + ServiceState.rilRadioTechnologyToString(mRilRat)); - } - mDataCallSessionStats.onDrsOrRatChanged( - ServiceState.rilRadioTechnologyToNetworkType(mRilRat)); - break; - - case EVENT_START_HANDOVER: //calls startHandover() - if (DBG) { - log("DcDefaultState: EVENT_START_HANDOVER not expected."); - } - Consumer r = (Consumer) msg.obj; - r.accept(DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - break; - case EVENT_START_HANDOVER_ON_TARGET: - if (DBG) { - log("DcDefaultState: EVENT_START_HANDOVER not expected, but will " - + "clean up, result code: " - + DataServiceCallback.resultCodeToString(msg.arg1)); - } - ((Consumer) msg.obj).accept(false /* is in correct state*/); - break; - case EVENT_CANCEL_HANDOVER: - // We don't need to do anything in this case - if (DBG) { - log("DcDefaultState: EVENT_CANCEL_HANDOVER resultCode=" - + DataServiceCallback.resultCodeToString(msg.arg1)); - } - break; - case EVENT_RELEASE_PDU_SESSION_ID: { - // We do the same thing in all state in order to preserve the existing workflow - final AsyncResult asyncResult = (AsyncResult) msg.obj; - if (asyncResult == null) { - loge("EVENT_RELEASE_PDU_SESSION_ID: asyncResult is null!"); - } else { - if (msg.obj != null) { - if (DBG) logd("EVENT_RELEASE_PDU_SESSION_ID: id released"); - Runnable runnable = (Runnable) asyncResult.userObj; - runnable.run(); - } else { - loge("EVENT_RELEASE_PDU_SESSION_ID: no runnable set"); - } - } - retVal = HANDLED; - break; - } - case EVENT_ALLOCATE_PDU_SESSION_ID: { - // We do the same thing in all state in order to preserve the existing workflow - final AsyncResult asyncResult = (AsyncResult) msg.obj; - if (asyncResult == null) { - loge("EVENT_ALLOCATE_PDU_SESSION_ID: asyncResult is null!"); - } else { - Consumer onAllocated = (Consumer) asyncResult.userObj; - if (asyncResult.exception != null) { - loge("EVENT_ALLOCATE_PDU_SESSION_ID: exception", - asyncResult.exception); - onAllocated.accept(PDU_SESSION_ID_NOT_SET); - } else if (asyncResult.result == null) { - loge("EVENT_ALLOCATE_PDU_SESSION_ID: result null, no id"); - onAllocated.accept(PDU_SESSION_ID_NOT_SET); - } else { - int psi = (int) asyncResult.result; - if (DBG) logd("EVENT_ALLOCATE_PDU_SESSION_ID: psi=" + psi); - onAllocated.accept(psi); - } - } - retVal = HANDLED; - break; - } - default: - if (DBG) { - log("DcDefaultState: ignore msg.what=" + getWhatToString(msg.what)); - } - break; - } - - return retVal; - } - } - - private void updateSuspendState() { - if (mNetworkAgent == null) { - Rlog.d(getName(), "Setting suspend state without a NetworkAgent"); - } - - boolean newSuspendedState = false; - // Data can only be (temporarily) suspended while data is in active state - if (getCurrentState() == mActiveState) { - // Never set suspended for emergency apn. Emergency data connection - // can work while device is not in service. - if (mApnSetting != null && mApnSetting.isEmergencyApn()) { - newSuspendedState = false; - // If we are not in service, change to suspended. - } else if (mDataRegState != ServiceState.STATE_IN_SERVICE) { - newSuspendedState = true; - // Check voice/data concurrency. - } else if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { - newSuspendedState = mPhone.getCallTracker().getState() != PhoneConstants.State.IDLE; - } - } - - // Only notify when there is a change. - if (mIsSuspended != newSuspendedState) { - mIsSuspended = newSuspendedState; - - // If data connection is active, we need to notify the new data connection state - // changed event reflecting the latest suspended state. - if (isActive()) { - notifyDataConnectionState(); - } - } - } - - private void notifyDataConnectionState() { - // The receivers of this have no way to differentiate between default and enterprise - // connections. Do not notify for enterprise. - if (!isEnterpriseUse()) { - mPhone.notifyDataConnection(getPreciseDataConnectionState()); - } else { - log("notifyDataConnectionState: Skipping for enterprise; state=" + getState()); - } - } - - private DcDefaultState mDefaultState = new DcDefaultState(); - - private int getApnTypeBitmask() { - return isEnterpriseUse() ? ApnSetting.TYPE_ENTERPRISE : - mApnSetting != null ? mApnSetting.getApnTypeBitmask() : 0; - } - - private boolean canHandleDefault() { - return !isEnterpriseUse() && mApnSetting != null - ? mApnSetting.canHandleType(ApnSetting.TYPE_DEFAULT) : false; - } - - /** - * The state machine is inactive and expects a EVENT_CONNECT. - */ - private class DcInactiveState extends State { - // Inform all contexts we've failed connecting - public void setEnterNotificationParams(ConnectionParams cp, @DataFailureCause int cause, - @HandoverFailureMode int handoverFailureMode) { - if (VDBG) log("DcInactiveState: setEnterNotificationParams cp,cause"); - mConnectionParams = cp; - mDisconnectParams = null; - mDcFailCause = cause; - mHandoverFailureMode = handoverFailureMode; - } - - // Inform all contexts we've failed disconnected - public void setEnterNotificationParams(DisconnectParams dp) { - if (VDBG) log("DcInactiveState: setEnterNotificationParams dp"); - mConnectionParams = null; - mDisconnectParams = dp; - mDcFailCause = DataFailCause.NONE; - } - - // Inform all contexts of the failure cause - public void setEnterNotificationParams(@DataFailureCause int cause) { - mConnectionParams = null; - mDisconnectParams = null; - mDcFailCause = cause; - } - - @Override - public void enter() { - mTag += 1; - if (DBG) log("DcInactiveState: enter() mTag=" + mTag); - TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, - TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__INACTIVE, - mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); - mDataCallSessionStats.onDataCallDisconnected(mDcFailCause); - if (mHandoverState == HANDOVER_STATE_BEING_TRANSFERRED) { - // This is from source data connection to set itself's state - setHandoverState(HANDOVER_STATE_COMPLETED); - } - - // Check for dangling agent. Ideally the handover source agent should be null if - // handover process is smooth. When it's not null, that means handover failed. The - // agent was not successfully transferred to the new data connection. We should - // gracefully notify connectivity service the network was disconnected. - if (mHandoverSourceNetworkAgent != null) { - DataConnection sourceDc = mHandoverSourceNetworkAgent.getDataConnection(); - if (sourceDc != null) { - // If the source data connection still owns this agent, then just reset the - // handover state back to idle because handover is already failed. - mHandoverLocalLog.log( - "Handover failed. Reset the source dc " + sourceDc.getName() - + " state to idle"); - sourceDc.cancelHandover(); - } else { - // The agent is now a dangling agent. No data connection owns this agent. - // Gracefully notify connectivity service disconnected. - mHandoverLocalLog.log( - "Handover failed and dangling agent found."); - mHandoverSourceNetworkAgent.acquireOwnership( - DataConnection.this, mTransportType); - log("Cleared dangling network agent. " + mHandoverSourceNetworkAgent); - mHandoverSourceNetworkAgent.unregister(DataConnection.this); - mHandoverSourceNetworkAgent.releaseOwnership(DataConnection.this); - } - mHandoverSourceNetworkAgent = null; - } - - if (mConnectionParams != null) { - if (DBG) { - log("DcInactiveState: enter notifyConnectCompleted +ALL failCause=" - + DataFailCause.toString(mDcFailCause)); - } - notifyConnectCompleted(mConnectionParams, mDcFailCause, mHandoverFailureMode, - true); - } - if (mDisconnectParams != null) { - if (DBG) { - log("DcInactiveState: enter notifyDisconnectCompleted +ALL failCause=" - + DataFailCause.toString(mDcFailCause)); - } - notifyDisconnectCompleted(mDisconnectParams, true); - } - if (mDisconnectParams == null && mConnectionParams == null - && mDcFailCause != DataFailCause.NONE) { - if (DBG) { - log("DcInactiveState: enter notifyAllDisconnectCompleted failCause=" - + DataFailCause.toString(mDcFailCause)); - } - notifyAllWithEvent(null, DctConstants.EVENT_DISCONNECT_DONE, - DataFailCause.toString(mDcFailCause)); - } - - // Remove ourselves from cid mapping, before clearSettings - mDcController.removeActiveDcByCid(DataConnection.this); - - // For the first time entering here (idle state before setup), do not notify - // disconnected state. Only notify data connection disconnected for data that is - // actually moving from disconnecting to disconnected, or setup failed. In both cases, - // APN setting will not be null. - if (mApnSetting != null) { - notifyDataConnectionState(); - } - clearSettings(); - } - - @Override - public void exit() { - } - - @Override - public boolean processMessage(Message msg) { - switch (msg.what) { - case EVENT_RESET: - case EVENT_REEVALUATE_RESTRICTED_STATE: - if (DBG) { - log("DcInactiveState: msg.what=" + getWhatToString(msg.what) - + ", ignore we're already done"); - } - return HANDLED; - case EVENT_CONNECT: - if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT"); - ConnectionParams cp = (ConnectionParams) msg.obj; - - if (!initConnection(cp)) { - log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed"); - notifyConnectCompleted(cp, DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); - transitionTo(mInactiveState); - return HANDLED; - } - - int cause = connect(cp); - if (cause != DataFailCause.NONE) { - log("DcInactiveState: msg.what=EVENT_CONNECT connect failed"); - notifyConnectCompleted(cp, cause, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); - transitionTo(mInactiveState); - return HANDLED; - } - - if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - mSubId = cp.mSubId; - } - - transitionTo(mActivatingState); - return HANDLED; - case EVENT_DISCONNECT: - if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT"); - notifyDisconnectCompleted((DisconnectParams)msg.obj, false); - return HANDLED; - case EVENT_DISCONNECT_ALL: - if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL"); - notifyDisconnectCompleted((DisconnectParams)msg.obj, false); - return HANDLED; - default: - if (VDBG) { - log("DcInactiveState not handled msg.what=" + getWhatToString(msg.what)); - } - return NOT_HANDLED; - } - } - } - private DcInactiveState mInactiveState = new DcInactiveState(); - - /** - * The state machine is activating a connection. - */ - private class DcActivatingState extends State { - @Override - public void enter() { - int apnTypeBitmask = getApnTypeBitmask(); - TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, - TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__ACTIVATING, - mPhone.getPhoneId(), mId, apnTypeBitmask, canHandleDefault()); - setHandoverState(HANDOVER_STATE_IDLE); - // restricted evaluation depends on network requests from apnContext. The evaluation - // should happen once entering connecting state rather than active state because it's - // possible that restricted network request can be released during the connecting window - // and if we wait for connection established, then we might mistakenly - // consider it as un-restricted. ConnectivityService then will immediately - // tear down the connection through networkAgent unwanted callback if all requests for - // this connection are going away. - mRestrictedNetworkOverride = shouldRestrictNetwork(); - - CarrierPrivilegesTracker carrierPrivTracker = mPhone.getCarrierPrivilegesTracker(); - if (carrierPrivTracker != null) { - carrierPrivTracker.registerCarrierPrivilegesListener( - getHandler(), EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED, null); - } - notifyDataConnectionState(); - mDataCallSessionStats.onSetupDataCall(apnTypeBitmask); - } - @Override - public boolean processMessage(Message msg) { - boolean retVal; - AsyncResult ar; - ConnectionParams cp; - - if (DBG) log("DcActivatingState: msg=" + msgToString(msg)); - switch (msg.what) { - case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: - case EVENT_CONNECT: - // Activating can't process until we're done. - deferMessage(msg); - retVal = HANDLED; - break; - - case EVENT_SETUP_DATA_CONNECTION_DONE: - cp = (ConnectionParams) msg.obj; - - DataCallResponse dataCallResponse = - msg.getData().getParcelable(DataServiceManager.DATA_CALL_RESPONSE); - SetupResult result = onSetupConnectionCompleted(msg.arg1, dataCallResponse, cp); - if (result != SetupResult.ERROR_STALE) { - if (mConnectionParams != cp) { - loge("DcActivatingState: WEIRD mConnectionsParams:"+ mConnectionParams - + " != cp:" + cp); - } - } - if (DBG) { - log("DcActivatingState onSetupConnectionCompleted result=" + result - + " dc=" + DataConnection.this); - } - ApnContext.requestLog( - cp.mApnContext, "onSetupConnectionCompleted result=" + result); - - if (result != SetupResult.SUCCESS) { - releasePduSessionId(() -> DataConnection.this - .setPduSessionId(PDU_SESSION_ID_NOT_SET)); - } - - switch (result) { - case SUCCESS: - // All is well - mDcFailCause = DataFailCause.NONE; - transitionTo(mActiveState); - break; - case ERROR_RADIO_NOT_AVAILABLE: - // Vendor ril rejected the command and didn't connect. - // Transition to inactive but send notifications after - // we've entered the mInactive state. - mInactiveState.setEnterNotificationParams(cp, result.mFailCause, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); - transitionTo(mInactiveState); - break; - case ERROR_DUPLICATE_CID: - // TODO (b/180988471): Properly handle the case when an existing cid is - // returned by tearing down the network agent if enterprise changed. - long retry = RetryManager.NO_SUGGESTED_RETRY_DELAY; - if (cp.mApnContext != null) { - retry = RetryManager.NO_RETRY; - mDct.getDataThrottler().setRetryTime( - cp.mApnContext.getApnTypeBitmask(), - retry, DcTracker.REQUEST_TYPE_NORMAL); - } - String logStr = "DcActivatingState: " - + DataFailCause.toString(result.mFailCause) - + " retry=" + retry; - if (DBG) log(logStr); - ApnContext.requestLog(cp.mApnContext, logStr); - mInactiveState.setEnterNotificationParams(cp, result.mFailCause, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); - transitionTo(mInactiveState); - break; - case ERROR_NO_DEFAULT_CONNECTION: - // TODO (b/180988471): Properly handle the case when a default data - // connection doesn't exist (tear down connection and retry). - // Currently, this just tears down the connection without retry. - if (DBG) log("DcActivatingState: NO_DEFAULT_DATA"); - case ERROR_INVALID_ARG: - // The addresses given from the RIL are bad - tearDownData(cp); - transitionTo(mDisconnectingErrorCreatingConnection); - break; - case ERROR_DATA_SERVICE_SPECIFIC_ERROR: - - // Retrieve the suggested retry delay from the modem and save it. - // If the modem want us to retry the current APN again, it will - // suggest a positive delay value (in milliseconds). Otherwise we'll get - // NO_SUGGESTED_RETRY_DELAY here. - - long delay = getSuggestedRetryDelay(dataCallResponse); - long retryTime = RetryManager.NO_SUGGESTED_RETRY_DELAY; - if (delay == RetryManager.NO_RETRY) { - retryTime = RetryManager.NO_RETRY; - } else if (delay >= 0) { - retryTime = SystemClock.elapsedRealtime() + delay; - } - int newRequestType = DcTracker.calculateNewRetryRequestType( - mHandoverFailureMode, cp.mRequestType, mDcFailCause); - mDct.getDataThrottler().setRetryTime(getApnTypeBitmask(), - retryTime, newRequestType); - - String str = "DcActivatingState: ERROR_DATA_SERVICE_SPECIFIC_ERROR " - + " delay=" + delay - + " result=" + result - + " result.isRadioRestartFailure=" - + DataFailCause.isRadioRestartFailure(mPhone.getContext(), - result.mFailCause, mPhone.getSubId()) - + " isPermanentFailure=" + - mDct.isPermanentFailure(result.mFailCause); - if (DBG) log(str); - ApnContext.requestLog(cp.mApnContext, str); - - // Save the cause. DcTracker.onDataSetupComplete will check this - // failure cause and determine if we need to retry this APN later - // or not. - mInactiveState.setEnterNotificationParams(cp, result.mFailCause, - dataCallResponse != null - ? dataCallResponse.getHandoverFailureMode() - : DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); - transitionTo(mInactiveState); - break; - case ERROR_STALE: - loge("DcActivatingState: stale EVENT_SETUP_DATA_CONNECTION_DONE" - + " tag:" + cp.mTag + " != mTag:" + mTag); - break; - default: - throw new RuntimeException("Unknown SetupResult, should not happen"); - } - retVal = HANDLED; - mDataCallSessionStats - .onSetupDataCallResponse(dataCallResponse, - ServiceState.rilRadioTechnologyToNetworkType(cp.mRilRat), - getApnTypeBitmask(), mApnSetting.getProtocol(), - result.mFailCause); - break; - case EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED: - AsyncResult asyncResult = (AsyncResult) msg.obj; - int[] administratorUids = (int[]) asyncResult.result; - mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length); - retVal = HANDLED; - break; - case EVENT_START_HANDOVER_ON_TARGET: - //called after startHandover on target transport - ((Consumer) msg.obj).accept(true /* is in correct state*/); - retVal = HANDLED; - break; - case EVENT_CANCEL_HANDOVER: - transitionTo(mInactiveState); - retVal = HANDLED; - break; - default: - if (VDBG) { - log("DcActivatingState not handled msg.what=" + - getWhatToString(msg.what) + " RefCount=" + mApnContexts.size()); - } - retVal = NOT_HANDLED; - break; - } - return retVal; - } - } - private DcActivatingState mActivatingState = new DcActivatingState(); - - /** - * The state machine is connected, expecting an EVENT_DISCONNECT. - */ - private class DcActiveState extends State { - - @Override public void enter() { - if (DBG) log("DcActiveState: enter dc=" + DataConnection.this); - TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, - TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__ACTIVE, - mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); - // If we were retrying there maybe more than one, otherwise they'll only be one. - notifyAllWithEvent(null, DctConstants.EVENT_DATA_SETUP_COMPLETE, - Phone.REASON_CONNECTED); - - mPhone.getCallTracker().registerForVoiceCallStarted(getHandler(), - DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED, null); - mPhone.getCallTracker().registerForVoiceCallEnded(getHandler(), - DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED, null); - - // If the EVENT_CONNECT set the current max retry restore it here - // if it didn't then this is effectively a NOP. - mDcController.addActiveDcByCid(DataConnection.this); - - updateTcpBufferSizes(mRilRat); - updateLinkBandwidthsFromCarrierConfig(mRilRat); - - final NetworkAgentConfig.Builder configBuilder = new NetworkAgentConfig.Builder(); - configBuilder.setLegacyType(ConnectivityManager.TYPE_MOBILE); - configBuilder.setLegacyTypeName(NETWORK_TYPE); - int networkType = getNetworkType(); - configBuilder.setLegacySubType(networkType); - configBuilder.setLegacySubTypeName(TelephonyManager.getNetworkTypeName(networkType)); - configBuilder.setLegacyExtraInfo(mApnSetting.getApnName()); - final CarrierSignalAgent carrierSignalAgent = mPhone.getCarrierSignalAgent(); - if (carrierSignalAgent.hasRegisteredReceivers(TelephonyManager - .ACTION_CARRIER_SIGNAL_REDIRECTED)) { - // carrierSignal Receivers will place the carrier-specific provisioning notification - configBuilder.setProvisioningNotificationEnabled(false); - } - - final String subscriberId = mPhone.getSubscriberId(); - if (!TextUtils.isEmpty(subscriberId)) { - configBuilder.setSubscriberId(subscriberId); - } - - // set skip464xlat if it is not default otherwise - if (shouldSkip464Xlat()) { - configBuilder.setNat64DetectionEnabled(false); - } - - mUnmeteredUseOnly = isUnmeteredUseOnly(); - mMmsUseOnly = isMmsUseOnly(); - mEnterpriseUse = isEnterpriseUse(); - - if (DBG) { - log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride - + ", mUnmeteredUseOnly = " + mUnmeteredUseOnly - + ", mMmsUseOnly = " + mMmsUseOnly - + ", mEnterpriseUse = " + mEnterpriseUse); - } - - // Always register a VcnNetworkPolicyChangeListener, regardless of whether this is a - // handover - // or new Network. - mVcnManager.addVcnNetworkPolicyChangeListener( - new HandlerExecutor(getHandler()), mVcnPolicyChangeListener); - - if (mConnectionParams != null - && mConnectionParams.mRequestType == REQUEST_TYPE_HANDOVER) { - // If this is a data setup for handover, we need to reuse the existing network agent - // instead of creating a new one. This should be transparent to connectivity - // service. - DcTracker dcTracker = mPhone.getDcTracker(getHandoverSourceTransport()); - DataConnection dc = dcTracker.getDataConnectionByApnType( - mConnectionParams.mApnContext.getApnType()); - // It's possible that the source data connection has been disconnected by the modem - // already. If not, set its handover state to completed. - if (dc != null) { - // Transfer network agent from the original data connection as soon as the - // new handover data connection is connected. - dc.setHandoverState(HANDOVER_STATE_COMPLETED); - } - - if (mHandoverSourceNetworkAgent != null) { - String logStr = "Transfer network agent " + mHandoverSourceNetworkAgent.getTag() - + " successfully."; - log(logStr); - mHandoverLocalLog.log(logStr); - mNetworkAgent = mHandoverSourceNetworkAgent; - mNetworkAgent.acquireOwnership(DataConnection.this, mTransportType); - - // TODO: Should evaluate mDisabledApnTypeBitMask again after handover. We don't - // do it now because connectivity service does not support dynamically removing - // immutable capabilities. - - mNetworkAgent.updateLegacySubtype(DataConnection.this); - // Update the capability after handover - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); - mHandoverSourceNetworkAgent = null; - } else { - String logStr = "Failed to get network agent from original data connection"; - loge(logStr); - mHandoverLocalLog.log(logStr); - return; - } - } else { - mScore = calculateScore(); - final NetworkFactory factory = PhoneFactory.getNetworkFactory( - mPhone.getPhoneId()); - final NetworkProvider provider = (null == factory) ? null : factory.getProvider(); - - mDisabledApnTypeBitMask |= getDisallowedApnTypes(); - updateLinkPropertiesHttpProxy(); - mNetworkAgent = new DcNetworkAgent(DataConnection.this, mPhone, mScore, - configBuilder.build(), provider, mTransportType); - - VcnNetworkPolicyResult policyResult = - mVcnManager.applyVcnNetworkPolicy( - getNetworkCapabilities(), getLinkProperties()); - if (policyResult.isTeardownRequested()) { - tearDownAll( - Phone.REASON_VCN_REQUESTED_TEARDOWN, - DcTracker.RELEASE_TYPE_DETACH, - null /* onCompletedMsg */); - } else { - // All network agents start out in CONNECTING mode, but DcNetworkAgents are - // created when the network is already connected. Hence, send the connected - // notification immediately. - mNetworkAgent.markConnected(); - } - - // The network agent is always created with NOT_SUSPENDED capability, but the - // network might be already out of service (or voice call is ongoing) just right - // before data connection is created. Connectivity service would not allow a network - // created with suspended state, so we create a non-suspended network first, and - // then immediately evaluate the suspended state. - sendMessage(obtainMessage(EVENT_UPDATE_SUSPENDED_STATE)); - } - - // The qos parameters are set when the call is connected - syncQosToNetworkAgent(); - - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.registerForNattKeepaliveStatus( - getHandler(), DataConnection.EVENT_KEEPALIVE_STATUS, null); - mPhone.mCi.registerForLceInfo( - getHandler(), DataConnection.EVENT_LINK_CAPACITY_CHANGED, null); - } - notifyDataConnectionState(); - TelephonyMetrics.getInstance().writeRilDataCallEvent(mPhone.getPhoneId(), - mCid, getApnTypeBitmask(), RilDataCall.State.CONNECTED); - } - - @Override - public void exit() { - if (DBG) log("DcActiveState: exit dc=" + this); - mPhone.getCallTracker().unregisterForVoiceCallStarted(getHandler()); - mPhone.getCallTracker().unregisterForVoiceCallEnded(getHandler()); - - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.unregisterForNattKeepaliveStatus(getHandler()); - mPhone.mCi.unregisterForLceInfo(getHandler()); - } - - // If we are still owning this agent, then we should inform connectivity service the - // data connection is disconnected. There is one exception that we shouldn't unregister, - // which is when IWLAN handover is ongoing. Instead of unregistering, the agent will - // be transferred to the new data connection on the other transport. - if (mNetworkAgent != null) { - syncQosToNetworkAgent(); - if (mHandoverState == HANDOVER_STATE_IDLE) { - mNetworkAgent.unregister(DataConnection.this); - } - mNetworkAgent.releaseOwnership(DataConnection.this); - } - mNetworkAgent = null; - - TelephonyMetrics.getInstance().writeRilDataCallEvent(mPhone.getPhoneId(), - mCid, getApnTypeBitmask(), RilDataCall.State.DISCONNECTED); - - mVcnManager.removeVcnNetworkPolicyChangeListener(mVcnPolicyChangeListener); - - CarrierPrivilegesTracker carrierPrivTracker = mPhone.getCarrierPrivilegesTracker(); - if (carrierPrivTracker != null) { - carrierPrivTracker.unregisterCarrierPrivilegesListener(getHandler()); - } - } - - @Override - public boolean processMessage(Message msg) { - boolean retVal; - - switch (msg.what) { - case EVENT_CONNECT: { - ConnectionParams cp = (ConnectionParams) msg.obj; - // either add this new apn context to our set or - // update the existing cp with the latest connection generation number - mApnContexts.put(cp.mApnContext, cp); - // TODO (b/118347948): evaluate if it's still needed after assigning - // different scores to different Cellular network. - mDisabledApnTypeBitMask &= ~cp.mApnContext.getApnTypeBitmask(); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - if (DBG) { - log("DcActiveState: EVENT_CONNECT cp=" + cp + " dc=" + DataConnection.this); - } - notifyConnectCompleted(cp, DataFailCause.NONE, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, false); - retVal = HANDLED; - break; - } - case EVENT_DISCONNECT: { - DisconnectParams dp = (DisconnectParams) msg.obj; - if (DBG) { - log("DcActiveState: EVENT_DISCONNECT dp=" + dp - + " dc=" + DataConnection.this); - } - if (mApnContexts.containsKey(dp.mApnContext)) { - if (DBG) { - log("DcActiveState msg.what=EVENT_DISCONNECT RefCount=" - + mApnContexts.size()); - } - - if (mApnContexts.size() == 1) { - mApnContexts.clear(); - mDisconnectParams = dp; - mConnectionParams = null; - dp.mTag = mTag; - tearDownData(dp); - transitionTo(mDisconnectingState); - } else { - mApnContexts.remove(dp.mApnContext); - // TODO (b/118347948): evaluate if it's still needed after assigning - // different scores to different Cellular network. - mDisabledApnTypeBitMask |= dp.mApnContext.getApnTypeBitmask(); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - notifyDisconnectCompleted(dp, false); - } - } else { - log("DcActiveState ERROR no such apnContext=" + dp.mApnContext - + " in this dc=" + DataConnection.this); - notifyDisconnectCompleted(dp, false); - } - retVal = HANDLED; - break; - } - case EVENT_DISCONNECT_ALL: { - if (DBG) { - log("DcActiveState EVENT_DISCONNECT clearing apn contexts," - + " dc=" + DataConnection.this); - } - DisconnectParams dp = (DisconnectParams) msg.obj; - mDisconnectParams = dp; - mConnectionParams = null; - dp.mTag = mTag; - tearDownData(dp); - transitionTo(mDisconnectingState); - retVal = HANDLED; - break; - } - case EVENT_LOST_CONNECTION: { - if (DBG) { - log("DcActiveState EVENT_LOST_CONNECTION dc=" + DataConnection.this); - } - - mInactiveState.setEnterNotificationParams(DataFailCause.LOST_CONNECTION); - transitionTo(mInactiveState); - retVal = HANDLED; - break; - } - case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - Pair drsRatPair = (Pair) ar.result; - mDataRegState = drsRatPair.first; - updateTcpBufferSizes(drsRatPair.second); - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { - updateLinkBandwidthsFromCarrierConfig(drsRatPair.second); - } - mRilRat = drsRatPair.second; - if (DBG) { - log("DcActiveState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED" - + " drs=" + mDataRegState - + " mRilRat=" + mRilRat); - } - updateSuspendState(); - if (mNetworkAgent != null) { - mNetworkAgent.updateLegacySubtype(DataConnection.this); - // The new suspended state will be passed through connectivity service - // through NET_CAPABILITY_NOT_SUSPENDED. - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); - } - retVal = HANDLED; - mDataCallSessionStats.onDrsOrRatChanged( - ServiceState.rilRadioTechnologyToNetworkType(mRilRat)); - break; - } - case EVENT_NR_FREQUENCY_CHANGED: - // fallthrough - case EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED: - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { - updateLinkBandwidthsFromCarrierConfig(mRilRat); - } - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - case EVENT_DATA_CONNECTION_METEREDNESS_CHANGED: - boolean isUnmetered = (boolean) msg.obj; - if (isUnmetered == mUnmeteredOverride) { - retVal = HANDLED; - break; - } - mUnmeteredOverride = isUnmetered; - if (mNetworkAgent != null) { - mNetworkAgent.updateLegacySubtype(DataConnection.this); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - case EVENT_DATA_CONNECTION_CONGESTEDNESS_CHANGED: - boolean isCongested = (boolean) msg.obj; - if (isCongested == mCongestedOverride) { - retVal = HANDLED; - break; - } - mCongestedOverride = isCongested; - if (mNetworkAgent != null) { - mNetworkAgent.updateLegacySubtype(DataConnection.this); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - case EVENT_DATA_CONNECTION_ROAM_ON: - case EVENT_DATA_CONNECTION_ROAM_OFF: { - if (mNetworkAgent != null) { - mNetworkAgent.updateLegacySubtype(DataConnection.this); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - } - case EVENT_DATA_CONNECTION_VOICE_CALL_STARTED: - case EVENT_DATA_CONNECTION_VOICE_CALL_ENDED: - case EVENT_CSS_INDICATOR_CHANGED: - case EVENT_UPDATE_SUSPENDED_STATE: { - updateSuspendState(); - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - } - case EVENT_BW_REFRESH_RESPONSE: { - AsyncResult ar = (AsyncResult)msg.obj; - if (ar.exception != null) { - log("EVENT_BW_REFRESH_RESPONSE: error ignoring, e=" + ar.exception); - } else { - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_MODEM_KEY)) { - updateLinkBandwidthsFromModem((List) ar.result); - } - } - retVal = HANDLED; - break; - } - case EVENT_KEEPALIVE_START_REQUEST: { - KeepalivePacketData pkt = (KeepalivePacketData) msg.obj; - int slotId = msg.arg1; - int intervalMillis = msg.arg2 * 1000; - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.startNattKeepalive( - DataConnection.this.mCid, pkt, intervalMillis, - DataConnection.this.obtainMessage( - EVENT_KEEPALIVE_STARTED, slotId, 0, null)); - } else { - // We currently do not support NATT Keepalive requests using the - // DataService API, so unless the request is WWAN (always bound via - // the CommandsInterface), the request cannot be honored. - // - // TODO: b/72331356 to add support for Keepalive to the DataService - // so that keepalive requests can be handled (if supported) by the - // underlying transport. - if (mNetworkAgent != null) { - mNetworkAgent.sendSocketKeepaliveEvent( - msg.arg1, SocketKeepalive.ERROR_INVALID_NETWORK); - } - } - retVal = HANDLED; - break; - } - case EVENT_KEEPALIVE_STOP_REQUEST: { - int slotId = msg.arg1; - int handle = mNetworkAgent.keepaliveTracker.getHandleForSlot(slotId); - if (handle < 0) { - loge("No slot found for stopSocketKeepalive! " + slotId); - mNetworkAgent.sendSocketKeepaliveEvent( - slotId, SocketKeepalive.ERROR_NO_SUCH_SLOT); - retVal = HANDLED; - break; - } else { - logd("Stopping keepalive with handle: " + handle); - } - - mPhone.mCi.stopNattKeepalive( - handle, DataConnection.this.obtainMessage( - EVENT_KEEPALIVE_STOPPED, handle, slotId, null)); - retVal = HANDLED; - break; - } - case EVENT_KEEPALIVE_STARTED: { - AsyncResult ar = (AsyncResult) msg.obj; - final int slot = msg.arg1; - if (ar.exception != null || ar.result == null) { - loge("EVENT_KEEPALIVE_STARTED: error starting keepalive, e=" - + ar.exception); - mNetworkAgent.sendSocketKeepaliveEvent( - slot, SocketKeepalive.ERROR_HARDWARE_ERROR); - } else { - KeepaliveStatus ks = (KeepaliveStatus) ar.result; - if (ks == null) { - loge("Null KeepaliveStatus received!"); - } else { - mNetworkAgent.keepaliveTracker.handleKeepaliveStarted(slot, ks); - } - } - retVal = HANDLED; - break; - } - case EVENT_KEEPALIVE_STATUS: { - AsyncResult ar = (AsyncResult) msg.obj; - if (ar.exception != null) { - loge("EVENT_KEEPALIVE_STATUS: error in keepalive, e=" + ar.exception); - // We have no way to notify connectivity in this case. - } - if (ar.result != null) { - KeepaliveStatus ks = (KeepaliveStatus) ar.result; - mNetworkAgent.keepaliveTracker.handleKeepaliveStatus(ks); - } - - retVal = HANDLED; - break; - } - case EVENT_KEEPALIVE_STOPPED: { - AsyncResult ar = (AsyncResult) msg.obj; - final int handle = msg.arg1; - final int slotId = msg.arg2; - - if (ar.exception != null) { - loge("EVENT_KEEPALIVE_STOPPED: error stopping keepalive for handle=" - + handle + " e=" + ar.exception); - mNetworkAgent.keepaliveTracker.handleKeepaliveStatus( - new KeepaliveStatus(KeepaliveStatus.ERROR_UNKNOWN)); - } else { - log("Keepalive Stop Requested for handle=" + handle); - mNetworkAgent.keepaliveTracker.handleKeepaliveStatus( - new KeepaliveStatus( - handle, KeepaliveStatus.STATUS_INACTIVE)); - } - retVal = HANDLED; - break; - } - case EVENT_LINK_CAPACITY_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - if (ar.exception != null) { - loge("EVENT_LINK_CAPACITY_CHANGED e=" + ar.exception); - } else { - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_MODEM_KEY)) { - updateLinkBandwidthsFromModem((List) ar.result); - } - } - retVal = HANDLED; - break; - } - case EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE: { - AsyncResult ar = (AsyncResult) msg.obj; - if (ar.exception != null) { - loge("EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE e=" + ar.exception); - } else { - Pair pair = (Pair) ar.result; - if (isBandwidthSourceKey( - DctConstants.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR_KEY)) { - updateLinkBandwidthsFromBandwidthEstimator(pair.first, pair.second); - } - } - retVal = HANDLED; - break; - } - case EVENT_REEVALUATE_RESTRICTED_STATE: { - // If the network was restricted, and now it does not need to be restricted - // anymore, we should add the NET_CAPABILITY_NOT_RESTRICTED capability. - if (mRestrictedNetworkOverride && !shouldRestrictNetwork()) { - if (DBG) { - log("Data connection becomes not-restricted. dc=" + this); - } - // Note we only do this when network becomes non-restricted. When a - // non-restricted becomes restricted (e.g. users disable data, or turn off - // data roaming), DCT will explicitly tear down the networks (because - // connectivity service does not support force-close TCP connections today). - // Also note that NET_CAPABILITY_NOT_RESTRICTED is an immutable capability - // (see {@link NetworkCapabilities}) once we add it to the network, we can't - // remove it through the entire life cycle of the connection. - mRestrictedNetworkOverride = false; - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - - // If the data does need to be unmetered use only (e.g. users turn on data, or - // device is not roaming anymore assuming data roaming is off), then we can - // dynamically add those metered APN type capabilities back. (But not the - // other way around because most of the APN-type capabilities are immutable - // capabilities.) - if (mUnmeteredUseOnly && !isUnmeteredUseOnly()) { - mUnmeteredUseOnly = false; - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - - mMmsUseOnly = isMmsUseOnly(); - - retVal = HANDLED; - break; - } - case EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES: { - // Update other properties like link properties if needed in future. - updateScore(); - retVal = HANDLED; - break; - } - case EVENT_NR_STATE_CHANGED: { - updateTcpBufferSizes(mRilRat); - if (isBandwidthSourceKey(DctConstants.BANDWIDTH_SOURCE_CARRIER_CONFIG_KEY)) { - updateLinkBandwidthsFromCarrierConfig(mRilRat); - } - if (mNetworkAgent != null) { - mNetworkAgent.sendLinkProperties(mLinkProperties, DataConnection.this); - mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), - DataConnection.this); - } - retVal = HANDLED; - break; - } - case EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED: - AsyncResult asyncResult = (AsyncResult) msg.obj; - int[] administratorUids = (int[]) asyncResult.result; - mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length); - - // Administrator UIDs changed, so update NetworkAgent with new - // NetworkCapabilities - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities( - getNetworkCapabilities(), DataConnection.this); - } - retVal = HANDLED; - break; - case EVENT_START_HANDOVER: //calls startHandover() - Consumer r = (Consumer) msg.obj; - r.accept(msg.arg1); - retVal = HANDLED; - break; - - default: - if (VDBG) { - log("DcActiveState not handled msg.what=" + getWhatToString(msg.what)); - } - retVal = NOT_HANDLED; - break; - } - return retVal; - } - } - private DcActiveState mActiveState = new DcActiveState(); - - /** - * The state machine is disconnecting. - */ - private class DcDisconnectingState extends State { - @Override - public void enter() { - TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, - TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__DISCONNECTING, - mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); - notifyDataConnectionState(); - } - @Override - public boolean processMessage(Message msg) { - boolean retVal; - - switch (msg.what) { - case EVENT_CONNECT: - if (DBG) log("DcDisconnectingState msg.what=EVENT_CONNECT. Defer. RefCount = " - + mApnContexts.size()); - deferMessage(msg); - retVal = HANDLED; - break; - - case EVENT_DEACTIVATE_DONE: - DisconnectParams dp = (DisconnectParams) msg.obj; - - String str = "DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount=" - + mApnContexts.size(); - - if (DBG) log(str); - ApnContext.requestLog(dp.mApnContext, str); - - // Clear out existing qos sessions - updateQosParameters(null); - - if (dp.mTag == mTag) { - // Transition to inactive but send notifications after - // we've entered the mInactive state. - mInactiveState.setEnterNotificationParams(dp); - transitionTo(mInactiveState); - } else { - if (DBG) log("DcDisconnectState stale EVENT_DEACTIVATE_DONE" - + " dp.tag=" + dp.mTag + " mTag=" + mTag); - } - retVal = HANDLED; - break; - - default: - if (VDBG) { - log("DcDisconnectingState not handled msg.what=" - + getWhatToString(msg.what)); - } - retVal = NOT_HANDLED; - break; - } - return retVal; - } - } - private DcDisconnectingState mDisconnectingState = new DcDisconnectingState(); - - /** - * The state machine is disconnecting after an creating a connection. - */ - private class DcDisconnectionErrorCreatingConnection extends State { - @Override - public void enter() { - TelephonyStatsLog.write(TelephonyStatsLog.MOBILE_CONNECTION_STATE_CHANGED, - TelephonyStatsLog - .MOBILE_CONNECTION_STATE_CHANGED__STATE__DISCONNECTION_ERROR_CREATING_CONNECTION, - mPhone.getPhoneId(), mId, getApnTypeBitmask(), canHandleDefault()); - notifyDataConnectionState(); - } - @Override - public boolean processMessage(Message msg) { - boolean retVal; - - switch (msg.what) { - case EVENT_DEACTIVATE_DONE: - ConnectionParams cp = (ConnectionParams) msg.obj; - if (cp.mTag == mTag) { - String str = "DcDisconnectionErrorCreatingConnection" + - " msg.what=EVENT_DEACTIVATE_DONE"; - if (DBG) log(str); - ApnContext.requestLog(cp.mApnContext, str); - - // Transition to inactive but send notifications after - // we've entered the mInactive state. - mInactiveState.setEnterNotificationParams(cp, - DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER, - DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN); - transitionTo(mInactiveState); - } else { - if (DBG) { - log("DcDisconnectionErrorCreatingConnection stale EVENT_DEACTIVATE_DONE" - + " dp.tag=" + cp.mTag + ", mTag=" + mTag); - } - } - retVal = HANDLED; - break; - - default: - if (VDBG) { - log("DcDisconnectionErrorCreatingConnection not handled msg.what=" - + getWhatToString(msg.what)); - } - retVal = NOT_HANDLED; - break; - } - return retVal; - } - } - private DcDisconnectionErrorCreatingConnection mDisconnectingErrorCreatingConnection = - new DcDisconnectionErrorCreatingConnection(); - - /** - * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg. - * Used for cellular networks that use Access Point Names (APN) such - * as GSM networks. - * - * @param apnContext is the Access Point Name to bring up a connection to - * @param profileId for the connection - * @param rilRadioTechnology Radio technology for the data connection - * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. - * With AsyncResult.userObj set to the original msg.obj, - * AsyncResult.result = FailCause and AsyncResult.exception = Exception(). - * @param connectionGeneration used to track a single connection request so disconnects can get - * ignored if obsolete. - * @param requestType Data request type - * @param subId the subscription id associated with this data connection. - * @param isApnPreferred whether or not the apn is preferred. - */ - public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology, - Message onCompletedMsg, int connectionGeneration, - @RequestNetworkType int requestType, int subId, boolean isApnPreferred) { - if (DBG) { - log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg); - } - - if (mApnSetting == null) { - mApnSetting = apnContext.getApnSetting(); - } - - sendMessage(DataConnection.EVENT_CONNECT, - new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg, - connectionGeneration, requestType, subId, isApnPreferred)); - } - - /** - * Tear down the connection through the apn on the network. - * - * @param apnContext APN context - * @param reason reason to tear down - * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. - * With AsyncResult.userObj set to the original msg.obj. - */ - public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) { - if (DBG) { - log("tearDown: apnContext=" + apnContext + " reason=" + reason + " onCompletedMsg=" - + onCompletedMsg); - } - sendMessage(DataConnection.EVENT_DISCONNECT, - new DisconnectParams(apnContext, reason, DcTracker.RELEASE_TYPE_DETACH, - onCompletedMsg)); - } - - // ******* "public" interface - - /** - * Used for testing purposes. - */ - void tearDownNow() { - if (DBG) log("tearDownNow()"); - sendMessage(obtainMessage(EVENT_TEAR_DOWN_NOW)); - } - - /** - * Tear down the connection through the apn on the network. Ignores reference count and - * and always tears down. - * - * @param releaseType Data release type - * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. - * With AsyncResult.userObj set to the original msg.obj. - */ - public void tearDownAll(String reason, @ReleaseNetworkType int releaseType, - Message onCompletedMsg) { - if (DBG) { - log("tearDownAll: reason=" + reason + ", releaseType=" - + DcTracker.releaseTypeToString(releaseType)); - } - sendMessage(DataConnection.EVENT_DISCONNECT_ALL, - new DisconnectParams(null, reason, releaseType, onCompletedMsg)); - } - - /** - * Reset the data connection to inactive state. - */ - public void reset() { - sendMessage(EVENT_RESET); - if (DBG) log("reset"); - } - - /** - * Re-evaluate the restricted state. If the restricted data connection does not need to be - * restricted anymore, we need to dynamically change the network's capability. - */ - void reevaluateRestrictedState() { - sendMessage(EVENT_REEVALUATE_RESTRICTED_STATE); - if (DBG) log("reevaluate restricted state"); - } - - /** - * Re-evaluate the data connection properties. For example, it will recalculate data connection - * score and update through network agent it if changed. - */ - void reevaluateDataConnectionProperties() { - sendMessage(EVENT_REEVALUATE_DATA_CONNECTION_PROPERTIES); - if (DBG) log("reevaluate data connection properties"); - } - - /** - * @return The parameters used for initiating a data connection. - */ - public ConnectionParams getConnectionParams() { - return mConnectionParams; - } - - /** - * Update PCSCF addresses - * - * @param response - */ - public void updatePcscfAddr(DataCallResponse response) { - mPcscfAddr = response.getPcscfAddresses().stream() - .map(InetAddress::getHostAddress).toArray(String[]::new); - } - - /** - * @return The list of PCSCF addresses - */ - public String[] getPcscfAddresses() { - return mPcscfAddr; - } - - /** - * Using the result of the SETUP_DATA_CALL determine the retry delay. - * - * @param response The response from setup data call - * @return {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} if not suggested. - * {@link RetryManager#NO_RETRY} if retry should not happen. Otherwise the delay in milliseconds - * to the next SETUP_DATA_CALL. - */ - private long getSuggestedRetryDelay(DataCallResponse response) { - /** According to ril.h - * The value < 0 means no value is suggested - * The value 0 means retry should be done ASAP. - * The value of Long.MAX_VALUE(0x7fffffffffffffff) means no retry. - */ - if (response == null) { - return RetryManager.NO_SUGGESTED_RETRY_DELAY; - } - - long suggestedRetryTime = response.getRetryDurationMillis(); - - // The value < 0 means no value is suggested - if (suggestedRetryTime < 0) { - if (DBG) log("No suggested retry delay."); - return RetryManager.NO_SUGGESTED_RETRY_DELAY; - } else if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6) - && suggestedRetryTime == Long.MAX_VALUE) { - if (DBG) log("Network suggested not retrying."); - return RetryManager.NO_RETRY; - } else if (mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_6) - && suggestedRetryTime == Integer.MAX_VALUE) { - if (DBG) log("Network suggested not retrying."); - return RetryManager.NO_RETRY; - } - - return suggestedRetryTime; - } - - public List getApnContexts() { - return new ArrayList<>(mApnContexts.keySet()); - } - - /** - * Return whether there is an ApnContext for the given type in this DataConnection. - * @param type APN type to check - * @param exclusive true if the given APN type should be the only APN type that exists - * @return True if there is an ApnContext for the given type - */ - private boolean isApnContextAttached(@ApnType int type, boolean exclusive) { - boolean attached = mApnContexts.keySet().stream() - .map(ApnContext::getApnTypeBitmask) - .anyMatch(bitmask -> bitmask == type); - if (exclusive) { - attached &= mApnContexts.size() == 1; - } - return attached; - } - - /** Get the network agent of the data connection */ - @Nullable - DcNetworkAgent getNetworkAgent() { - return mNetworkAgent; - } - - void setHandoverState(@HandoverState int state) { - if (mHandoverState != state) { - String logStr = "State changed from " + handoverStateToString(mHandoverState) - + " to " + handoverStateToString(state); - mHandoverLocalLog.log(logStr); - logd(logStr); - mHandoverState = state; - } - } - - /** Sets the {@link DataCallSessionStats} mock for this data connection during unit testing. */ - @VisibleForTesting - public void setDataCallSessionStats(DataCallSessionStats dataCallSessionStats) { - mDataCallSessionStats = dataCallSessionStats; - } - - /** - * @return the string for msg.what as our info. - */ - @Override - protected String getWhatToString(int what) { - return cmdToString(what); - } - - private static String msgToString(Message msg) { - String retVal; - if (msg == null) { - retVal = "null"; - } else { - StringBuilder b = new StringBuilder(); - - b.append("{what="); - b.append(cmdToString(msg.what)); - - b.append(" when="); - TimeUtils.formatDuration(msg.getWhen() - SystemClock.uptimeMillis(), b); - - if (msg.arg1 != 0) { - b.append(" arg1="); - b.append(msg.arg1); - } - - if (msg.arg2 != 0) { - b.append(" arg2="); - b.append(msg.arg2); - } - - if (msg.obj != null) { - b.append(" obj="); - b.append(msg.obj); - } - - b.append(" target="); - b.append(msg.getTarget()); - - b.append(" replyTo="); - b.append(msg.replyTo); - - b.append("}"); - - retVal = b.toString(); - } - return retVal; - } - - static void slog(String s) { - Rlog.d("DC", s); - } - - /** - * Log with debug - * - * @param s is string log - */ - @Override - protected void log(String s) { - Rlog.d(getName(), s); - } - - /** - * Log with debug attribute - * - * @param s is string log - */ - @Override - protected void logd(String s) { - Rlog.d(getName(), s); - } - - /** - * Log with verbose attribute - * - * @param s is string log - */ - @Override - protected void logv(String s) { - Rlog.v(getName(), s); - } - - /** - * Log with info attribute - * - * @param s is string log - */ - @Override - protected void logi(String s) { - Rlog.i(getName(), s); - } - - /** - * Log with warning attribute - * - * @param s is string log - */ - @Override - protected void logw(String s) { - Rlog.w(getName(), s); - } - - /** - * Log with error attribute - * - * @param s is string log - */ - @Override - protected void loge(String s) { - Rlog.e(getName(), s); - } - - /** - * Log with error attribute - * - * @param s is string log - * @param e is a Throwable which logs additional information. - */ - @Override - protected void loge(String s, Throwable e) { - Rlog.e(getName(), s, e); - } - - /** Doesn't print mApnList of ApnContext's which would be recursive */ - public synchronized String toStringSimple() { - return getName() + ": State=" + getCurrentState().getName() - + " mApnSetting=" + mApnSetting + " RefCount=" + mApnContexts.size() - + " mCid=" + mCid + " mCreateTime=" + mCreateTime - + " mLastastFailTime=" + mLastFailTime - + " mLastFailCause=" + DataFailCause.toString(mLastFailCause) - + " mTag=" + mTag - + " mLinkProperties=" + mLinkProperties - + " linkCapabilities=" + getNetworkCapabilities() - + " mRestrictedNetworkOverride=" + mRestrictedNetworkOverride; - } - - @Override - public String toString() { - return "{" + toStringSimple() + " mApnContexts=" + mApnContexts + "}"; - } - - /** Check if the device is connected to NR 5G Non-Standalone network. */ - private boolean isNRConnected() { - return mPhone.getServiceState().getNrState() - == NetworkRegistrationInfo.NR_STATE_CONNECTED; - } - - /** - * @return The disallowed APN types bitmask - */ - private @ApnType int getDisallowedApnTypes() { - CarrierConfigManager configManager = (CarrierConfigManager) - mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - int apnTypesBitmask = 0; - if (configManager != null) { - PersistableBundle bundle = configManager.getConfigForSubId(mSubId); - if (bundle != null) { - String key = (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - ? CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY - : CarrierConfigManager.KEY_CARRIER_WLAN_DISALLOWED_APN_TYPES_STRING_ARRAY; - if (bundle.getStringArray(key) != null) { - String disallowedApnTypesString = - TextUtils.join(",", bundle.getStringArray(key)); - if (!TextUtils.isEmpty(disallowedApnTypesString)) { - apnTypesBitmask = ApnSetting.getApnTypesBitmaskFromString( - disallowedApnTypesString); - } - } - } - } - - return apnTypesBitmask; - } - - private void dumpToLog() { - dump(null, new PrintWriter(new StringWriter(0)) { - @Override - public void println(String s) { - DataConnection.this.logd(s); - } - - @Override - public void flush() { - } - }, null); - } - - /** - * Re-calculate score and update through network agent if it changes. - */ - private void updateScore() { - int oldScore = mScore; - mScore = calculateScore(); - if (oldScore != mScore && mNetworkAgent != null) { - log("Updating score from " + oldScore + " to " + mScore); - mNetworkAgent.sendNetworkScore(mScore, this); - } - } - - private int calculateScore() { - int score = OTHER_CONNECTION_SCORE; - - // If it's serving a network request that asks NET_CAPABILITY_INTERNET and doesn't have - // specify a subId, this dataConnection is considered to be default Internet data - // connection. In this case we assign a slightly higher score of 50. The intention is - // it will not be replaced by other data connections accidentally in DSDS usecase. - for (ApnContext apnContext : mApnContexts.keySet()) { - for (NetworkRequest networkRequest : apnContext.getNetworkRequests()) { - if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - && networkRequest.getNetworkSpecifier() == null) { - score = DEFAULT_INTERNET_CONNECTION_SCORE; - break; - } - } - } - - return score; - } - - private String handoverStateToString(@HandoverState int state) { - switch (state) { - case HANDOVER_STATE_IDLE: return "IDLE"; - case HANDOVER_STATE_BEING_TRANSFERRED: return "BEING_TRANSFERRED"; - case HANDOVER_STATE_COMPLETED: return "COMPLETED"; - default: return "UNKNOWN"; - } - } - - private @DataState int getState() { - if (isInactive()) { - return TelephonyManager.DATA_DISCONNECTED; - } else if (isActivating()) { - return TelephonyManager.DATA_CONNECTING; - } else if (isActive()) { - // The data connection can only be suspended when it's in active state. - if (mIsSuspended) { - return TelephonyManager.DATA_SUSPENDED; - } - return TelephonyManager.DATA_CONNECTED; - } else if (isDisconnecting()) { - return TelephonyManager.DATA_DISCONNECTING; - } - - return TelephonyManager.DATA_UNKNOWN; - } - - /** - * Get precise data connection state - * - * @return The {@link PreciseDataConnectionState} - */ - public PreciseDataConnectionState getPreciseDataConnectionState() { - return new PreciseDataConnectionState.Builder() - .setTransportType(mTransportType) - .setId(mCid) - .setState(getState()) - .setApnSetting(mApnSetting) - .setLinkProperties(mLinkProperties) - .setNetworkType(getNetworkType()) - .setFailCause(mDcFailCause) - .build(); - } - - /** - * Dump the current state. - * - * @param fd - * @param printWriter - * @param args - */ - @Override - public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { - IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); - pw.print("DataConnection "); - super.dump(fd, pw, args); - pw.flush(); - pw.increaseIndent(); - pw.println("transport type=" - + AccessNetworkConstants.transportTypeToString(mTransportType)); - pw.println("mApnContexts.size=" + mApnContexts.size()); - pw.println("mApnContexts=" + mApnContexts); - pw.println("mApnSetting=" + mApnSetting); - pw.println("mTag=" + mTag); - pw.println("mCid=" + mCid); - pw.println("mConnectionParams=" + mConnectionParams); - pw.println("mDisconnectParams=" + mDisconnectParams); - pw.println("mDcFailCause=" + DataFailCause.toString(mDcFailCause)); - pw.println("mPhone=" + mPhone); - pw.println("mSubId=" + mSubId); - pw.println("mLinkProperties=" + mLinkProperties); - pw.flush(); - pw.println("mDataRegState=" + mDataRegState); - pw.println("mHandoverState=" + handoverStateToString(mHandoverState)); - pw.println("mRilRat=" + mRilRat); - pw.println("mNetworkCapabilities=" + getNetworkCapabilities()); - pw.println("mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime)); - pw.println("mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime)); - pw.println("mLastFailCause=" + DataFailCause.toString(mLastFailCause)); - pw.println("mUserData=" + mUserData); - pw.println("mRestrictedNetworkOverride=" + mRestrictedNetworkOverride); - pw.println("mUnmeteredUseOnly=" + mUnmeteredUseOnly); - pw.println("mMmsUseOnly=" + mMmsUseOnly); - pw.println("mEnterpriseUse=" + mEnterpriseUse); - pw.println("mUnmeteredOverride=" + mUnmeteredOverride); - pw.println("mCongestedOverride=" + mCongestedOverride); - pw.println("mDownlinkBandwidth" + mDownlinkBandwidth); - pw.println("mUplinkBandwidth=" + mUplinkBandwidth); - pw.println("mDefaultQos=" + mDefaultQos); - pw.println("mQosBearerSessions=" + mQosBearerSessions); - pw.println("disallowedApnTypes=" - + ApnSetting.getApnTypesStringFromBitmask(getDisallowedApnTypes())); - pw.println("mInstanceNumber=" + mInstanceNumber); - pw.println("mAc=" + mAc); - pw.println("mScore=" + mScore); - if (mNetworkAgent != null) { - mNetworkAgent.dump(fd, pw, args); - } - pw.println("handover local log:"); - pw.increaseIndent(); - mHandoverLocalLog.dump(fd, pw, args); - pw.decreaseIndent(); - pw.decreaseIndent(); - pw.println(); - pw.flush(); - } - - /** - * Class used to track VCN-defined Network policies for this DataConnection. - * - *

MUST be registered with the associated DataConnection's Handler. - */ - private class DataConnectionVcnNetworkPolicyChangeListener - implements VcnNetworkPolicyChangeListener { - @Override - public void onPolicyChanged() { - // Poll the current underlying Network policy from VcnManager and send to NetworkAgent. - final NetworkCapabilities networkCapabilities = getNetworkCapabilities(); - VcnNetworkPolicyResult policyResult = - mVcnManager.applyVcnNetworkPolicy( - networkCapabilities, getLinkProperties()); - if (policyResult.isTeardownRequested()) { - tearDownAll( - Phone.REASON_VCN_REQUESTED_TEARDOWN, - DcTracker.RELEASE_TYPE_DETACH, - null /* onCompletedMsg */); - } - - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(networkCapabilities, DataConnection.this); - } - } - } -} - diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java b/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java deleted file mode 100644 index 68f2ab38ae..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2017 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.dataconnection; - -import com.android.internal.annotations.VisibleForTesting; - -import java.util.HashSet; - -/** - * The class to describe the reasons of allowing or disallowing to establish a data connection. - */ -public class DataConnectionReasons { - private HashSet mDataDisallowedReasonSet = new HashSet<>(); - private DataAllowedReasonType mDataAllowedReason = DataAllowedReasonType.NONE; - - public DataConnectionReasons() {} - - void add(DataDisallowedReasonType reason) { - // Adding a disallowed reason will clean up the allowed reason because they are - // mutual exclusive. - mDataAllowedReason = DataAllowedReasonType.NONE; - mDataDisallowedReasonSet.add(reason); - } - - void add(DataAllowedReasonType reason) { - // Adding an allowed reason will clean up the disallowed reasons because they are - // mutual exclusive. - mDataDisallowedReasonSet.clear(); - - // Only higher priority allowed reason can overwrite the old one. See - // DataAllowedReasonType for the oder. - if (reason.ordinal() > mDataAllowedReason.ordinal()) { - mDataAllowedReason = reason; - } - } - - @Override - public String toString() { - StringBuilder reasonStr = new StringBuilder(); - if (mDataDisallowedReasonSet.size() > 0) { - reasonStr.append("Data disallowed reasons:"); - for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) { - reasonStr.append(" ").append(reason); - } - } else { - reasonStr.append("Data allowed reason:"); - reasonStr.append(" ").append(mDataAllowedReason); - } - return reasonStr.toString(); - } - - void copyFrom(DataConnectionReasons reasons) { - this.mDataDisallowedReasonSet = reasons.mDataDisallowedReasonSet; - this.mDataAllowedReason = reasons.mDataAllowedReason; - } - - boolean allowed() { - return mDataDisallowedReasonSet.size() == 0; - } - - /** - * Check if it contains a certain disallowed reason. - * - * @param reason The disallowed reason to check. - * @return {@code true} if the provided reason matches one of the disallowed reasons. - */ - @VisibleForTesting - public boolean contains(DataDisallowedReasonType reason) { - return mDataDisallowedReasonSet.contains(reason); - } - - /** - * Check if only one disallowed reason prevent data connection. - * - * @param reason The given reason to check - * @return True if the given reason is the only one that prevents data connection - */ - public boolean containsOnly(DataDisallowedReasonType reason) { - return mDataDisallowedReasonSet.size() == 1 && contains(reason); - } - - boolean contains(DataAllowedReasonType reason) { - return reason == mDataAllowedReason; - } - - boolean containsHardDisallowedReasons() { - for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) { - if (reason.isHardReason()) { - return true; - } - } - return false; - } - - // Disallowed reasons. There could be multiple reasons if data connection is not allowed. - public enum DataDisallowedReasonType { - // Soft failure reasons. Normally the reasons from users or policy settings. - - // Data is disabled by the user or policy. - DATA_DISABLED(false), - // Data roaming is disabled by the user. - ROAMING_DISABLED(false), - // Default data not selected. - DEFAULT_DATA_UNSELECTED(false), - - // Belows are all hard failure reasons. - NOT_ATTACHED(true), - SIM_NOT_READY(true), - INVALID_PHONE_STATE(true), - CONCURRENT_VOICE_DATA_NOT_ALLOWED(true), - PS_RESTRICTED(true), - UNDESIRED_POWER_STATE(true), - INTERNAL_DATA_DISABLED(true), - RADIO_DISABLED_BY_CARRIER(true), - // Not in the right state for data call setup. - APN_NOT_CONNECTABLE(true), - // Data is in connecting state. No need to send another setup request. - DATA_IS_CONNECTING(true), - // Data is being disconnected. Telephony will retry after disconnected. - DATA_IS_DISCONNECTING(true), - // Data is already connected. No need to setup data again. - DATA_ALREADY_CONNECTED(true), - // certain APNs are not allowed on IWLAN in legacy mode. - ON_IWLAN(true), - // certain APNs are only allowed when the device is camped on NR. - NOT_ON_NR(true), - // Data is not allowed while device is in emergency callback mode. - IN_ECBM(true), - // The given APN type's preferred transport has switched. - ON_OTHER_TRANSPORT(true), - // Underlying data service is not bound. - DATA_SERVICE_NOT_READY(true), - // Qualified networks service does not allow certain types of APN brought up on either - // cellular or IWLAN. - DISABLED_BY_QNS(true), - // Data is throttled. The network explicitly requested device not to establish data - // connection for a certain period. - DATA_THROTTLED(true); - - private boolean mIsHardReason; - - boolean isHardReason() { - return mIsHardReason; - } - - DataDisallowedReasonType(boolean isHardReason) { - mIsHardReason = isHardReason; - } - } - - // Data allowed reasons. There will be only one reason if data is allowed. - enum DataAllowedReasonType { - // Note that unlike disallowed reasons, we only have one allowed reason every time - // when we check data is allowed or not. The order of these allowed reasons is very - // important. The lower ones take precedence over the upper ones. - NONE, - NORMAL, - UNMETERED_APN, - RESTRICTED_REQUEST, - EMERGENCY_APN, - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java deleted file mode 100644 index 305b4a8df5..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - - -import static android.telephony.PhoneStateListener.LISTEN_CALL_STATE; -import static android.telephony.PhoneStateListener.LISTEN_NONE; - -import android.annotation.IntDef; -import android.content.ContentResolver; -import android.content.Context; -import android.os.Handler; -import android.os.RegistrantList; -import android.os.SystemProperties; -import android.provider.Settings; -import android.sysprop.TelephonyProperties; -import android.telephony.Annotation.CallState; -import android.telephony.CarrierConfigManager; -import android.telephony.PhoneStateListener; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.util.LocalLog; -import android.util.Pair; - -import com.android.internal.telephony.GlobalSettingsHelper; -import com.android.internal.telephony.MultiSimSettingController; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.SubscriptionController; -import com.android.internal.telephony.data.DataEnabledOverride; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * The class to hold different data enabled/disabled settings. Also it allows clients to register - * for overall data enabled setting changed event. - * @hide - */ -public class DataEnabledSettings { - - private static final String LOG_TAG = "DataEnabledSettings"; - - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"REASON_"}, - value = { - REASON_REGISTERED, - REASON_INTERNAL_DATA_ENABLED, - REASON_USER_DATA_ENABLED, - REASON_POLICY_DATA_ENABLED, - REASON_DATA_ENABLED_BY_CARRIER, - REASON_PROVISIONED_CHANGED, - REASON_PROVISIONING_DATA_ENABLED_CHANGED, - REASON_OVERRIDE_RULE_CHANGED, - REASON_OVERRIDE_CONDITION_CHANGED, - REASON_THERMAL_DATA_ENABLED - }) - public @interface DataEnabledChangedReason {} - - public static final int REASON_REGISTERED = 0; - - public static final int REASON_INTERNAL_DATA_ENABLED = 1; - - public static final int REASON_USER_DATA_ENABLED = 2; - - public static final int REASON_POLICY_DATA_ENABLED = 3; - - public static final int REASON_DATA_ENABLED_BY_CARRIER = 4; - - public static final int REASON_PROVISIONED_CHANGED = 5; - - public static final int REASON_PROVISIONING_DATA_ENABLED_CHANGED = 6; - - public static final int REASON_OVERRIDE_RULE_CHANGED = 7; - - public static final int REASON_OVERRIDE_CONDITION_CHANGED = 8; - - public static final int REASON_THERMAL_DATA_ENABLED = 9; - - /** - * responds to the setInternalDataEnabled call - used internally to turn off data. - * For example during emergency calls - */ - private boolean mInternalDataEnabled = true; - - /** - * Flag indicating data allowed by network policy manager or not. - */ - private boolean mPolicyDataEnabled = true; - - /** - * Indicate if metered APNs are enabled by the carrier. set false to block all the metered APNs - * from continuously sending requests, which causes undesired network load. - */ - private boolean mCarrierDataEnabled = true; - - /** - * Flag indicating data allowed by Thermal service or not. - */ - private boolean mThermalDataEnabled = true; - - /** - * Flag indicating whether data is allowed or not for the device. It can be disabled by - * user, carrier, policy or thermal - */ - private boolean mIsDataEnabled = false; - - private final Phone mPhone; - - private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - - private ContentResolver mResolver = null; - - private final RegistrantList mOverallDataEnabledChangedRegistrants = new RegistrantList(); - - // TODO: Merge this with mOverallDataEnabledChangedRegistrants. In the future, notifying data - // enabled changed with APN types bitmask - private final RegistrantList mOverallDataEnabledOverrideChangedRegistrants = - new RegistrantList(); - - private final LocalLog mSettingChangeLocalLog = new LocalLog(32); - - private DataEnabledOverride mDataEnabledOverride; - - private TelephonyManager mTelephonyManager; - - // for msim, user data enabled setting depends on subId. - private final SubscriptionManager.OnSubscriptionsChangedListener - mOnSubscriptionsChangeListener = - new SubscriptionManager.OnSubscriptionsChangedListener() { - @Override - public void onSubscriptionsChanged() { - synchronized (this) { - if (mSubId != mPhone.getSubId()) { - log("onSubscriptionsChanged subId: " + mSubId + " to: " - + mPhone.getSubId()); - mSubId = mPhone.getSubId(); - mDataEnabledOverride = getDataEnabledOverride(); - updatePhoneStateListener(); - updateDataEnabledAndNotify(REASON_USER_DATA_ENABLED); - mPhone.notifyUserMobileDataStateChanged(isUserDataEnabled()); - } - } - } - }; - - private void updatePhoneStateListener() { - mTelephonyManager.listen(mPhoneStateListener, LISTEN_NONE); - if (SubscriptionManager.isUsableSubscriptionId(mSubId)) { - mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId); - } - mTelephonyManager.listen(mPhoneStateListener, LISTEN_CALL_STATE); - } - - private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - @Override - public void onCallStateChanged(@CallState int state, String phoneNumber) { - updateDataEnabledAndNotify(REASON_OVERRIDE_CONDITION_CHANGED); - } - }; - - @Override - public String toString() { - return "[mInternalDataEnabled=" + mInternalDataEnabled - + ", isUserDataEnabled=" + isUserDataEnabled() - + ", isProvisioningDataEnabled=" + isProvisioningDataEnabled() - + ", mPolicyDataEnabled=" + mPolicyDataEnabled - + ", mCarrierDataEnabled=" + mCarrierDataEnabled - + ", mIsDataEnabled=" + mIsDataEnabled - + ", mThermalDataEnabled=" + mThermalDataEnabled - + ", " + mDataEnabledOverride - + "]"; - } - - public DataEnabledSettings(Phone phone) { - mPhone = phone; - mResolver = mPhone.getContext().getContentResolver(); - SubscriptionManager subscriptionManager = (SubscriptionManager) mPhone.getContext() - .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); - subscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); - mTelephonyManager = (TelephonyManager) mPhone.getContext() - .getSystemService(Context.TELEPHONY_SERVICE); - mDataEnabledOverride = getDataEnabledOverride(); - updateDataEnabled(); - } - - private DataEnabledOverride getDataEnabledOverride() { - return new DataEnabledOverride(SubscriptionController.getInstance() - .getDataEnabledOverrideRules(mPhone.getSubId())); - } - - public synchronized void setInternalDataEnabled(boolean enabled) { - if (mInternalDataEnabled != enabled) { - localLog("InternalDataEnabled", enabled); - mInternalDataEnabled = enabled; - updateDataEnabledAndNotify(REASON_INTERNAL_DATA_ENABLED); - } - } - public synchronized boolean isInternalDataEnabled() { - return mInternalDataEnabled; - } - - private synchronized void setUserDataEnabled(boolean enabled) { - // By default the change should propagate to the group. - setUserDataEnabled(enabled, true); - } - - /** - * @param notifyMultiSimSettingController if setUserDataEnabled is already from propagating - * from MultiSimSettingController, don't notify MultiSimSettingController again. - * For example, if sub1 and sub2 are in the same group and user enables data for sub - * 1, sub 2 will also be enabled but with propagateToGroup = false. - */ - public synchronized void setUserDataEnabled(boolean enabled, - boolean notifyMultiSimSettingController) { - // Can't disable data for stand alone opportunistic subscription. - if (isStandAloneOpportunistic(mPhone.getSubId(), mPhone.getContext()) && !enabled) return; - - boolean changed = GlobalSettingsHelper.setInt(mPhone.getContext(), - Settings.Global.MOBILE_DATA, mPhone.getSubId(), (enabled ? 1 : 0)); - if (changed) { - localLog("UserDataEnabled", enabled); - mPhone.notifyUserMobileDataStateChanged(enabled); - updateDataEnabledAndNotify(REASON_USER_DATA_ENABLED); - if (notifyMultiSimSettingController) { - MultiSimSettingController.getInstance().notifyUserDataEnabled( - mPhone.getSubId(), enabled); - } - } - } - - /** - * Policy control of data connection with reason - * @param reason the reason the data enable change is taking place - * @param enabled True if enabling the data, otherwise disabling. - */ - public synchronized void setDataEnabled(@TelephonyManager.DataEnabledReason int reason, - boolean enabled) { - switch (reason) { - case TelephonyManager.DATA_ENABLED_REASON_USER: - setUserDataEnabled(enabled); - break; - case TelephonyManager.DATA_ENABLED_REASON_CARRIER: - setCarrierDataEnabled(enabled); - break; - case TelephonyManager.DATA_ENABLED_REASON_POLICY: - setPolicyDataEnabled(enabled); - break; - case TelephonyManager.DATA_ENABLED_REASON_THERMAL: - setThermalDataEnabled(enabled); - break; - default: - log("Invalid data enable reason " + reason); - break; - } - } - - public synchronized boolean isUserDataEnabled() { - // User data should always be true for opportunistic subscription. - if (isStandAloneOpportunistic(mPhone.getSubId(), mPhone.getContext())) return true; - - boolean defaultVal = TelephonyProperties.mobile_data().orElse(true); - - return GlobalSettingsHelper.getBoolean(mPhone.getContext(), - Settings.Global.MOBILE_DATA, mPhone.getSubId(), defaultVal); - } - - /** - * Set whether always allowing MMS data connection. - * - * @param alwaysAllow {@code true} if MMS data is always allowed. - * - * @return {@code false} if the setting is changed. - */ - public synchronized boolean setAlwaysAllowMmsData(boolean alwaysAllow) { - localLog("setAlwaysAllowMmsData", alwaysAllow); - mDataEnabledOverride.setAlwaysAllowMms(alwaysAllow); - boolean changed = SubscriptionController.getInstance() - .setDataEnabledOverrideRules(mPhone.getSubId(), mDataEnabledOverride.getRules()); - if (changed) { - updateDataEnabledAndNotify(REASON_OVERRIDE_RULE_CHANGED); - notifyDataEnabledOverrideChanged(); - } - - return changed; - } - - /** - * Set allowing mobile data during voice call. This is used for allowing data on the non-default - * data SIM. When a voice call is placed on the non-default data SIM on DSDS devices, users will - * not be able to use mobile data. By calling this API, data will be temporarily enabled on the - * non-default data SIM during the life cycle of the voice call. - * - * @param allow {@code true} if allowing using data during voice call, {@code false} if - * disallowed - * - * @return {@code true} if operation is successful. otherwise {@code false}. - */ - public synchronized boolean setAllowDataDuringVoiceCall(boolean allow) { - localLog("setAllowDataDuringVoiceCall", allow); - if (allow == isDataAllowedInVoiceCall()) { - return true; - } - mDataEnabledOverride.setDataAllowedInVoiceCall(allow); - - boolean changed = SubscriptionController.getInstance() - .setDataEnabledOverrideRules(mPhone.getSubId(), mDataEnabledOverride.getRules()); - if (changed) { - updateDataEnabledAndNotify(REASON_OVERRIDE_RULE_CHANGED); - notifyDataEnabledOverrideChanged(); - } - - return changed; - } - - /** - * Check if data is allowed during voice call. - * - * @return {@code true} if data is allowed during voice call. - */ - public synchronized boolean isDataAllowedInVoiceCall() { - return mDataEnabledOverride.isDataAllowedInVoiceCall(); - } - - public synchronized boolean isMmsAlwaysAllowed() { - return mDataEnabledOverride.isMmsAlwaysAllowed(); - } - - private synchronized void setPolicyDataEnabled(boolean enabled) { - if (mPolicyDataEnabled != enabled) { - localLog("PolicyDataEnabled", enabled); - mPolicyDataEnabled = enabled; - updateDataEnabledAndNotify(REASON_POLICY_DATA_ENABLED); - } - } - - public synchronized boolean isPolicyDataEnabled() { - return mPolicyDataEnabled; - } - - private synchronized void setCarrierDataEnabled(boolean enabled) { - if (mCarrierDataEnabled != enabled) { - localLog("CarrierDataEnabled", enabled); - mCarrierDataEnabled = enabled; - updateDataEnabledAndNotify(REASON_DATA_ENABLED_BY_CARRIER); - } - } - - public synchronized boolean isCarrierDataEnabled() { - return mCarrierDataEnabled; - } - - private synchronized void setThermalDataEnabled(boolean enabled) { - if (mThermalDataEnabled != enabled) { - localLog("ThermalDataEnabled", enabled); - mThermalDataEnabled = enabled; - updateDataEnabledAndNotify(REASON_THERMAL_DATA_ENABLED); - } - } - - public synchronized boolean isThermalDataEnabled() { - return mThermalDataEnabled; - } - - public synchronized void updateProvisionedChanged() { - updateDataEnabledAndNotify(REASON_PROVISIONED_CHANGED); - } - - public synchronized void updateProvisioningDataEnabled() { - updateDataEnabledAndNotify(REASON_PROVISIONING_DATA_ENABLED_CHANGED); - } - - public synchronized boolean isDataEnabled() { - return mIsDataEnabled; - } - - /** - * Check if data is enabled for a specific reason {@@TelephonyManager.DataEnabledReason} - * - * @return {@code true} if the overall data is enabled; {@code false} if not. - */ - public synchronized boolean isDataEnabledForReason( - @TelephonyManager.DataEnabledReason int reason) { - switch (reason) { - case TelephonyManager.DATA_ENABLED_REASON_USER: - return isUserDataEnabled(); - case TelephonyManager.DATA_ENABLED_REASON_CARRIER: - return isCarrierDataEnabled(); - case TelephonyManager.DATA_ENABLED_REASON_POLICY: - return isPolicyDataEnabled(); - case TelephonyManager.DATA_ENABLED_REASON_THERMAL: - return isThermalDataEnabled(); - default: - return false; - } - } - - private synchronized void updateDataEnabledAndNotify(int reason) { - boolean prevDataEnabled = mIsDataEnabled; - - updateDataEnabled(); - - if (prevDataEnabled != mIsDataEnabled) { - notifyDataEnabledChanged(!prevDataEnabled, reason); - } - } - - private synchronized void updateDataEnabled() { - if (isProvisioning()) { - mIsDataEnabled = isProvisioningDataEnabled(); - } else { - mIsDataEnabled = mInternalDataEnabled && (isUserDataEnabled() || mDataEnabledOverride - .shouldOverrideDataEnabledSettings(mPhone, ApnSetting.TYPE_ALL)) - && mPolicyDataEnabled && mCarrierDataEnabled && mThermalDataEnabled; - } - } - - public boolean isProvisioning() { - return Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0; - } - /** - * In provisioning, we might want to have enable mobile data during provisioning. It depends - * on value of Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED which is set by - * setupwizard. It only matters if it's in provisioning stage. - * @return whether we are enabling userData during provisioning stage. - */ - public boolean isProvisioningDataEnabled() { - final String prov_property = SystemProperties.get("ro.com.android.prov_mobiledata", - "false"); - boolean retVal = "true".equalsIgnoreCase(prov_property); - - final int prov_mobile_data = Settings.Global.getInt(mResolver, - Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, - retVal ? 1 : 0); - retVal = prov_mobile_data != 0; - log("getDataEnabled during provisioning retVal=" + retVal + " - (" + prov_property - + ", " + prov_mobile_data + ")"); - - return retVal; - } - - public synchronized void setDataRoamingEnabled(boolean enabled) { - // will trigger handleDataOnRoamingChange() through observer - boolean changed = GlobalSettingsHelper.setBoolean(mPhone.getContext(), - Settings.Global.DATA_ROAMING, mPhone.getSubId(), enabled); - - if (changed) { - localLog("setDataRoamingEnabled", enabled); - MultiSimSettingController.getInstance().notifyRoamingDataEnabled(mPhone.getSubId(), - enabled); - } - } - - /** - * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value. - */ - public synchronized boolean getDataRoamingEnabled() { - return GlobalSettingsHelper.getBoolean(mPhone.getContext(), - Settings.Global.DATA_ROAMING, mPhone.getSubId(), getDefaultDataRoamingEnabled()); - } - - /** - * get default values for {@link Settings.Global#DATA_ROAMING} - * return {@code true} if either - * {@link CarrierConfigManager#KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL} or - * system property ro.com.android.dataroaming is set to true. otherwise return {@code false} - */ - public synchronized boolean getDefaultDataRoamingEnabled() { - final CarrierConfigManager configMgr = (CarrierConfigManager) - mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - boolean isDataRoamingEnabled = "true".equalsIgnoreCase(SystemProperties.get( - "ro.com.android.dataroaming", "false")); - isDataRoamingEnabled |= configMgr.getConfigForSubId(mPhone.getSubId()).getBoolean( - CarrierConfigManager.KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL); - return isDataRoamingEnabled; - } - - private void notifyDataEnabledChanged(boolean enabled, int reason) { - mOverallDataEnabledChangedRegistrants.notifyResult(new Pair<>(enabled, reason)); - mPhone.notifyDataEnabled(enabled, reason); - } - - public void registerForDataEnabledChanged(Handler h, int what, Object obj) { - mOverallDataEnabledChangedRegistrants.addUnique(h, what, obj); - notifyDataEnabledChanged(isDataEnabled(), REASON_REGISTERED); - } - - public void unregisterForDataEnabledChanged(Handler h) { - mOverallDataEnabledChangedRegistrants.remove(h); - } - - private void notifyDataEnabledOverrideChanged() { - mOverallDataEnabledOverrideChangedRegistrants.notifyRegistrants(); - } - - /** - * Register for data enabled override changed event. - * - * @param h The handler - * @param what The event - */ - public void registerForDataEnabledOverrideChanged(Handler h, int what) { - mOverallDataEnabledOverrideChangedRegistrants.addUnique(h, what, null); - notifyDataEnabledOverrideChanged(); - } - - /** - * Unregistered for data enabled override changed event. - * - * @param h The handler - */ - public void unregisterForDataEnabledOverrideChanged(Handler h) { - mOverallDataEnabledOverrideChangedRegistrants.remove(h); - } - - private static boolean isStandAloneOpportunistic(int subId, Context context) { - SubscriptionInfo info = SubscriptionController.getInstance().getActiveSubscriptionInfo( - subId, context.getOpPackageName(), context.getAttributionTag()); - return (info != null) && info.isOpportunistic() && info.getGroupUuid() == null; - } - - public synchronized boolean isDataEnabled(int apnType) { - if (isProvisioning()) { - return isProvisioningDataEnabled(); - } else { - boolean userDataEnabled = isUserDataEnabled(); - // Check if we should temporarily enable data in certain conditions. - boolean isDataEnabledOverridden = mDataEnabledOverride - .shouldOverrideDataEnabledSettings(mPhone, apnType); - - return (mInternalDataEnabled && mPolicyDataEnabled && mCarrierDataEnabled - && mThermalDataEnabled && (userDataEnabled || isDataEnabledOverridden)); - } - } - - private void log(String s) { - Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); - } - - private void localLog(String name, boolean value) { - mSettingChangeLocalLog.log(name + " change to " + value); - } - - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println(" DataEnabledSettings="); - mSettingChangeLocalLog.dump(fd, pw, args); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java deleted file mode 100644 index d00600464b..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java +++ /dev/null @@ -1,978 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import static android.text.format.DateUtils.MINUTE_IN_MILLIS; -import static android.text.format.DateUtils.SECOND_IN_MILLIS; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.AppOpsManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.net.LinkProperties; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.PersistableBundle; -import android.os.RegistrantList; -import android.os.RemoteException; -import android.os.UserHandle; -import android.permission.LegacyPermissionManager; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.TransportType; -import android.telephony.AnomalyReporter; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionManager; -import android.telephony.data.DataCallResponse; -import android.telephony.data.DataProfile; -import android.telephony.data.DataService; -import android.telephony.data.DataServiceCallback; -import android.telephony.data.IDataService; -import android.telephony.data.IDataServiceCallback; -import android.telephony.data.NetworkSliceInfo; -import android.telephony.data.TrafficDescriptor; -import android.text.TextUtils; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConfigurationManager; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.telephony.Rlog; - -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; - -/** - * Data service manager manages handling data requests and responses on data services (e.g. - * Cellular data service, IWLAN data service). - */ -public class DataServiceManager extends Handler { - private static final boolean DBG = true; - - static final String DATA_CALL_RESPONSE = "data_call_response"; - - 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; - - private final int mTransportType; - - private boolean mBound; - - private IDataService mIDataService; - - private DataServiceManagerDeathRecipient mDeathRecipient; - - private final RegistrantList mServiceBindingChangedRegistrants = new RegistrantList(); - - private final Map mMessageMap = new ConcurrentHashMap<>(); - - private final RegistrantList mDataCallListChangedRegistrants = new RegistrantList(); - - private final RegistrantList mApnUnthrottledRegistrants = new RegistrantList(); - - private String mTargetBindingPackageName; - - private CellularDataServiceConnection mServiceConnection; - - private final UUID mAnomalyUUID = UUID.fromString("fc1956de-c080-45de-8431-a1faab687110"); - private String mLastBoundPackageName; - - /** - * Helpful for logging - * @return the tag name - * - * @hide - */ - public String getTag() { - return mTag; - } - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) - && mPhone.getPhoneId() == intent.getIntExtra( - CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) { - // 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."); - sendEmptyMessage(EVENT_BIND_DATA_SERVICE); - } - } - }; - - private class DataServiceManagerDeathRecipient implements IBinder.DeathRecipient { - @Override - public void binderDied() { - // TODO: try to rebind the service. - String message = "Data service " + mLastBoundPackageName + " for transport type " - + AccessNetworkConstants.transportTypeToString(mTransportType) + " died."; - loge(message); - AnomalyReporter.reportAnomaly(mAnomalyUUID, message, mPhone.getCarrierId()); - } - } - - private void grantPermissionsToService(String packageName) { - final String[] pkgToGrant = {packageName}; - CountDownLatch latch = new CountDownLatch(1); - try { - mPermissionManager.grantDefaultPermissionsToEnabledTelephonyDataServices( - pkgToGrant, UserHandle.of(UserHandle.myUserId()), Runnable::run, - isSuccess -> { - if (isSuccess) { - latch.countDown(); - } else { - loge("Failed to grant permissions to service."); - } - }); - TelephonyUtils.waitUntilReady(latch, CHANGE_PERMISSION_TIMEOUT_MS); - mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, - UserHandle.myUserId(), pkgToGrant[0], AppOpsManager.MODE_ALLOWED); - mAppOps.setMode(AppOpsManager.OPSTR_FINE_LOCATION, - UserHandle.myUserId(), pkgToGrant[0], AppOpsManager.MODE_ALLOWED); - } catch (RuntimeException e) { - loge("Binder to package manager died, permission grant for DataService failed."); - throw e; - } - } - - /** - * Loop through all DataServices installed on the system and revoke permissions from any that - * are not currently the WWAN or WLAN data service. - */ - private void revokePermissionsFromUnusedDataServices() { - // Except the current data services from having their permissions removed. - Set dataServices = getAllDataServicePackageNames(); - for (int transportType : mPhone.getAccessNetworksManager().getAvailableTransports()) { - dataServices.remove(getDataServicePackageName(transportType)); - } - - CountDownLatch latch = new CountDownLatch(1); - try { - String[] dataServicesArray = new String[dataServices.size()]; - dataServices.toArray(dataServicesArray); - mPermissionManager.revokeDefaultPermissionsFromDisabledTelephonyDataServices( - dataServicesArray, UserHandle.of(UserHandle.myUserId()), Runnable::run, - isSuccess -> { - if (isSuccess) { - latch.countDown(); - } else { - loge("Failed to revoke permissions from data services."); - } - }); - TelephonyUtils.waitUntilReady(latch, CHANGE_PERMISSION_TIMEOUT_MS); - for (String pkg : dataServices) { - mAppOps.setMode(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, UserHandle.myUserId(), - pkg, AppOpsManager.MODE_ERRORED); - mAppOps.setMode(AppOpsManager.OPSTR_FINE_LOCATION, UserHandle.myUserId(), - pkg, AppOpsManager.MODE_ERRORED); - } - } catch (RuntimeException e) { - loge("Binder to package manager died; failed to revoke DataService permissions."); - throw e; - } - } - - private final class CellularDataServiceConnection implements ServiceConnection { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - if (DBG) log("onServiceConnected"); - mIDataService = IDataService.Stub.asInterface(service); - mDeathRecipient = new DataServiceManagerDeathRecipient(); - mBound = true; - mLastBoundPackageName = getDataServicePackageName(); - removeMessages(EVENT_WATCHDOG_TIMEOUT); - - try { - service.linkToDeath(mDeathRecipient, 0); - mIDataService.createDataServiceProvider(mPhone.getPhoneId()); - mIDataService.registerForDataCallListChanged(mPhone.getPhoneId(), - new CellularDataServiceCallback("dataCallListChanged")); - mIDataService.registerForUnthrottleApn(mPhone.getPhoneId(), - new CellularDataServiceCallback("unthrottleApn")); - } catch (RemoteException e) { - loge("Remote exception. " + e); - return; - } - mServiceBindingChangedRegistrants.notifyResult(true); - } - @Override - public void onServiceDisconnected(ComponentName name) { - if (DBG) log("onServiceDisconnected"); - removeMessages(EVENT_WATCHDOG_TIMEOUT); - mIDataService = null; - mBound = false; - mServiceBindingChangedRegistrants.notifyResult(false); - mTargetBindingPackageName = null; - } - } - - private final class CellularDataServiceCallback extends IDataServiceCallback.Stub { - - private final String mTag; - - CellularDataServiceCallback(String tag) { - mTag = tag; - } - - public String getTag() { - return mTag; - } - - @Override - public void onSetupDataCallComplete(@DataServiceCallback.ResultCode int resultCode, - DataCallResponse response) { - if (DBG) { - log("onSetupDataCallComplete. resultCode = " + resultCode + ", response = " - + response); - } - removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); - Message msg = mMessageMap.remove(asBinder()); - if (msg != null) { - msg.getData().putParcelable(DATA_CALL_RESPONSE, response); - sendCompleteMessage(msg, resultCode); - } else { - loge("Unable to find the message for setup call response."); - } - } - - @Override - public void onDeactivateDataCallComplete(@DataServiceCallback.ResultCode int resultCode) { - if (DBG) log("onDeactivateDataCallComplete. resultCode = " + resultCode); - removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onSetInitialAttachApnComplete(@DataServiceCallback.ResultCode int resultCode) { - if (DBG) log("onSetInitialAttachApnComplete. resultCode = " + resultCode); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onSetDataProfileComplete(@DataServiceCallback.ResultCode int resultCode) { - if (DBG) log("onSetDataProfileComplete. resultCode = " + resultCode); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onRequestDataCallListComplete(@DataServiceCallback.ResultCode int resultCode, - List dataCallList) { - if (DBG) log("onRequestDataCallListComplete. resultCode = " + resultCode); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onDataCallListChanged(List dataCallList) { - mDataCallListChangedRegistrants.notifyRegistrants( - new AsyncResult(null, dataCallList, null)); - } - - @Override - public void onHandoverStarted(@DataServiceCallback.ResultCode int resultCode) { - if (DBG) log("onHandoverStarted. resultCode = " + resultCode); - removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onHandoverCancelled(@DataServiceCallback.ResultCode int resultCode) { - if (DBG) log("onHandoverCancelled. resultCode = " + resultCode); - removeMessages(EVENT_WATCHDOG_TIMEOUT, CellularDataServiceCallback.this); - Message msg = mMessageMap.remove(asBinder()); - sendCompleteMessage(msg, resultCode); - } - - @Override - public void onApnUnthrottled(String apn) { - if (apn != null) { - mApnUnthrottledRegistrants.notifyRegistrants( - new AsyncResult(null, apn, null)); - } else { - loge("onApnUnthrottled: apn is null"); - } - } - - @Override - public void onDataProfileUnthrottled(DataProfile dataProfile) { - if (dataProfile != null) { - mApnUnthrottledRegistrants.notifyRegistrants( - new AsyncResult(null, dataProfile, null)); - } else { - loge("onDataProfileUnthrottled: dataProfile is null"); - } - } - } - - /** - * Constructor - * - * @param phone The phone object - * @param transportType The transport type - * @param tagSuffix Logging tag suffix - */ - public DataServiceManager(Phone phone, @TransportType int transportType, String tagSuffix) { - mPhone = phone; - mTag = "DSM" + tagSuffix; - mTransportType = transportType; - mBound = false; - mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService( - Context.CARRIER_CONFIG_SERVICE); - // 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 - mPermissionManager = (LegacyPermissionManager) phone.getContext().getSystemService( - Context.LEGACY_PERMISSION_SERVICE); - mAppOps = (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE); - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - try { - Context contextAsUser = phone.getContext().createPackageContextAsUser( - phone.getContext().getPackageName(), 0, UserHandle.ALL); - contextAsUser.registerReceiver(mBroadcastReceiver, intentFilter, - null /* broadcastPermission */, null); - } catch (PackageManager.NameNotFoundException e) { - loge("Package name not found: " + e.getMessage()); - } - - PhoneConfigurationManager.registerForMultiSimConfigChange( - this, EVENT_BIND_DATA_SERVICE, null); - - sendEmptyMessage(EVENT_BIND_DATA_SERVICE); - } - - /** - * Handle message events - * - * @param msg The message to handle - */ - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_BIND_DATA_SERVICE: - rebindDataService(); - break; - case EVENT_WATCHDOG_TIMEOUT: - handleRequestUnresponded((CellularDataServiceCallback) msg.obj); - break; - default: - loge("Unhandled event " + msg.what); - } - } - - private void handleRequestUnresponded(CellularDataServiceCallback 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(); - if (mIDataService != null && mIDataService.asBinder().isBinderAlive()) { - log("unbinding service"); - // Remove the network availability updater and then unbind the service. - try { - mIDataService.removeDataServiceProvider(mPhone.getPhoneId()); - } catch (RemoteException e) { - loge("Cannot remove data service provider. " + e); - } - } - - if (mServiceConnection != null) { - mPhone.getContext().unbindService(mServiceConnection); - } - mIDataService = null; - mServiceConnection = null; - mTargetBindingPackageName = null; - mBound = false; - } - - private void bindDataService(String packageName) { - if (mPhone == null || !SubscriptionManager.isValidPhoneId(mPhone.getPhoneId())) { - loge("can't bindDataService with invalid phone or phoneId."); - return; - } - - if (TextUtils.isEmpty(packageName)) { - loge("Can't find the binding package"); - return; - } - - Intent intent = null; - String className = getDataServiceClassName(); - if (TextUtils.isEmpty(className)) { - intent = new Intent(DataService.SERVICE_INTERFACE); - intent.setPackage(packageName); - } else { - ComponentName cm = new ComponentName(packageName, className); - intent = new Intent(DataService.SERVICE_INTERFACE).setComponent(cm); - } - - // Then pre-emptively grant the permissions to the package we will bind. - grantPermissionsToService(packageName); - - try { - mServiceConnection = new CellularDataServiceConnection(); - if (!mPhone.getContext().bindService( - intent, mServiceConnection, Context.BIND_AUTO_CREATE)) { - loge("Cannot bind to the data service."); - return; - } - mTargetBindingPackageName = packageName; - } catch (Exception e) { - loge("Cannot bind to the data service. Exception: " + e); - } - } - - private void rebindDataService() { - String packageName = getDataServicePackageName(); - // Do nothing if no need to rebind. - if (SubscriptionManager.isValidPhoneId(mPhone.getPhoneId()) - && TextUtils.equals(packageName, mTargetBindingPackageName)) { - if (DBG) log("Service " + packageName + " already bound or being bound."); - return; - } - - unbindDataService(); - bindDataService(packageName); - } - - @NonNull - private Set 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 - // to be updated. - List dataPackages = - mPhone.getContext().getPackageManager().queryIntentServices( - new Intent(DataService.SERVICE_INTERFACE), - PackageManager.MATCH_SYSTEM_ONLY); - HashSet packageNames = new HashSet<>(); - for (ResolveInfo info : dataPackages) { - if (info.serviceInfo == null) continue; - packageNames.add(info.serviceInfo.packageName); - } - return packageNames; - } - - /** - * Get the data service package name for our current transport type. - * - * @return package name of the data service package for the the current transportType. - */ - public String getDataServicePackageName() { - return getDataServicePackageName(mTransportType); - } - - /** - * Get the data service package by transport type. - * - * 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. - * - * @param transportType The transport type - * @return package name of the data service package for the specified transportType. - */ - private String getDataServicePackageName(@TransportType int transportType) { - String packageName; - int resourceId; - String carrierConfig; - - switch (transportType) { - 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: - 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)); - } - - // Read package name from resource overlay - packageName = mPhone.getContext().getResources().getString(resourceId); - - PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { - // If carrier config overrides it, use the one from carrier config - packageName = b.getString(carrierConfig, packageName); - } - - return packageName; - } - - /** - * Get the data service class name for our current transport type. - * - * @return class name of the data service package for the the current transportType. - */ - private String getDataServiceClassName() { - return getDataServiceClassName(mTransportType); - } - - - /** - * Get the data service class by transport type. - * - * @param transportType either WWAN or WLAN - * @return class name of the data service package for the specified transportType. - */ - private String getDataServiceClassName(int transportType) { - String className; - int resourceId; - String carrierConfig; - switch (transportType) { - 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: - 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); - } - - // Read package name from resource overlay - className = mPhone.getContext().getResources().getString(resourceId); - - PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { - // If carrier config overrides it, use the one from carrier config - className = b.getString(carrierConfig, className); - } - - return className; - } - - private void sendCompleteMessage(Message msg, @DataServiceCallback.ResultCode int code) { - if (msg != null) { - msg.arg1 = code; - msg.sendToTarget(); - } - } - - /** - * Setup a data connection. The data service provider must implement this method to support - * establishing a packet data connection. When completed or error, the service must invoke - * the provided callback to notify the platform. - * - * @param accessNetworkType Access network type that the data call will be established on. - * Must be one of {@link AccessNetworkConstants.AccessNetworkType}. - * @param dataProfile Data profile used for data call setup. See {@link DataProfile} - * @param isRoaming True if the device is data roaming. - * @param allowRoaming True if data roaming is allowed by the user. - * @param reason The reason for data setup. Must be {@link DataService#REQUEST_REASON_NORMAL} or - * {@link DataService#REQUEST_REASON_HANDOVER}. - * @param linkProperties If {@code reason} is {@link DataService#REQUEST_REASON_HANDOVER}, this - * is the link properties of the existing data connection, otherwise null. - * @param pduSessionId The pdu session id to be used for this data call. A value of -1 means - * no pdu session id was attached to this call. - * Reference: 3GPP TS 24.007 Section 11.2.3.1b - * @param sliceInfo The slice that represents S-NSSAI. - * Reference: 3GPP TS 24.501 - * @param trafficDescriptor The traffic descriptor for this data call, used for URSP matching. - * Reference: 3GPP TS TS 24.526 Section 5.2 - * @param matchAllRuleAllowed True if using the default match-all URSP rule for this request is - * allowed. - * @param onCompleteMessage The result message for this request. Null if the client does not - * care about the result. - */ - public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, - @Nullable NetworkSliceInfo sliceInfo, @Nullable TrafficDescriptor trafficDescriptor, - boolean matchAllRuleAllowed, Message onCompleteMessage) { - if (DBG) log("setupDataCall"); - if (!mBound) { - loge("setupDataCall: Data service not bound."); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - CellularDataServiceCallback callback = new CellularDataServiceCallback("setupDataCall"); - if (onCompleteMessage != null) { - 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); - } catch (RemoteException e) { - loge("setupDataCall: Cannot invoke setupDataCall on data service."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Deactivate a data connection. The data service provider must implement this method to - * support data connection tear down. When completed or error, the service must invoke the - * provided callback to notify the platform. - * - * @param cid Call id returned in the callback of {@link #setupDataCall(int, DataProfile, - * boolean, boolean, int, LinkProperties, Message)} - * @param reason The reason for data deactivation. Must be - * {@link DataService#REQUEST_REASON_NORMAL}, {@link DataService#REQUEST_REASON_SHUTDOWN} - * or {@link DataService#REQUEST_REASON_HANDOVER}. - * @param onCompleteMessage The result message for this request. Null if the client does not - * care about the result. - */ - public void deactivateDataCall(int cid, int reason, Message onCompleteMessage) { - if (DBG) log("deactivateDataCall"); - if (!mBound) { - loge("Data service not bound."); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - CellularDataServiceCallback callback = - new CellularDataServiceCallback("deactivateDataCall"); - if (onCompleteMessage != null) { - 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."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Indicates that a handover has begun. This is called on the source transport. - * - * Any resources being transferred cannot be released while a - * handover is underway. - * - * If a handover was unsuccessful, then the framework calls DataServiceManager#cancelHandover. - * The target transport retains ownership over any of the resources being transferred. - * - * 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. - * - * @param cid The identifier of the data call which is provided in DataCallResponse - * @param onCompleteMessage The result callback for this request. - */ - public void startHandover(int cid, @NonNull Message onCompleteMessage) { - CellularDataServiceCallback callback = - setupCallbackHelper("startHandover", onCompleteMessage); - if (callback == null) { - loge("startHandover: callback == null"); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - 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."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Indicates that a handover was cancelled after a call to DataServiceManager#startHandover. - * This is called on the source transport. - * - * Since the handover was unsuccessful, the source transport retains ownership over any of - * the resources being transferred and is still responsible for releasing them. - * - * @param cid The identifier of the data call which is provided in DataCallResponse - * @param onCompleteMessage The result callback for this request. - */ - public void cancelHandover(int cid, @NonNull Message onCompleteMessage) { - CellularDataServiceCallback callback = - setupCallbackHelper("cancelHandover", onCompleteMessage); - if (callback == null) { - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - 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."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - @Nullable - private CellularDataServiceCallback setupCallbackHelper( - @NonNull final String operationName, @NonNull final Message onCompleteMessage) { - if (DBG) log(operationName); - if (!mBound) { - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return null; - } - - CellularDataServiceCallback callback = - new CellularDataServiceCallback(operationName); - if (onCompleteMessage != null) { - if (DBG) log(operationName + ": onCompleteMessage set"); - mMessageMap.put(callback.asBinder(), onCompleteMessage); - } else { - if (DBG) log(operationName + ": onCompleteMessage not set"); - } - return callback; - } - - /** - * Set an APN to initial attach network. - * - * @param dataProfile Data profile used for data call setup. See {@link DataProfile}. - * @param isRoaming True if the device is data roaming. - * @param onCompleteMessage The result message for this request. Null if the client does not - * care about the result. - */ - public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, - Message onCompleteMessage) { - if (DBG) log("setInitialAttachApn"); - if (!mBound) { - loge("Data service not bound."); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - CellularDataServiceCallback callback = - new CellularDataServiceCallback("setInitialAttachApn"); - if (onCompleteMessage != null) { - mMessageMap.put(callback.asBinder(), onCompleteMessage); - } - try { - mIDataService.setInitialAttachApn(mPhone.getPhoneId(), dataProfile, isRoaming, - callback); - } catch (RemoteException e) { - loge("Cannot invoke setInitialAttachApn on data service."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Send current carrier's data profiles to the data service for data call setup. This is - * only for CDMA carrier that can change the profile through OTA. The data service should - * always uses the latest data profile sent by the framework. - * - * @param dps A list of data profiles. - * @param isRoaming True if the device is data roaming. - * @param onCompleteMessage The result message for this request. Null if the client does not - * care about the result. - */ - public void setDataProfile(List dps, boolean isRoaming, - Message onCompleteMessage) { - if (DBG) log("setDataProfile"); - if (!mBound) { - loge("Data service not bound."); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - CellularDataServiceCallback callback = new CellularDataServiceCallback("setDataProfile"); - if (onCompleteMessage != null) { - mMessageMap.put(callback.asBinder(), onCompleteMessage); - } - try { - mIDataService.setDataProfile(mPhone.getPhoneId(), dps, isRoaming, callback); - } catch (RemoteException e) { - loge("Cannot invoke setDataProfile on data service."); - mMessageMap.remove(callback.asBinder()); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Get the active data call list. - * - * @param onCompleteMessage The result message for this request. Null if the client does not - * care about the result. - */ - public void requestDataCallList(Message onCompleteMessage) { - if (DBG) log("requestDataCallList"); - if (!mBound) { - loge("Data service not bound."); - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - return; - } - - CellularDataServiceCallback callback = - new CellularDataServiceCallback("requestDataCallList"); - if (onCompleteMessage != null) { - mMessageMap.put(callback.asBinder(), onCompleteMessage); - } - try { - mIDataService.requestDataCallList(mPhone.getPhoneId(), callback); - } catch (RemoteException e) { - loge("Cannot invoke requestDataCallList on data service."); - if (callback != null) { - mMessageMap.remove(callback.asBinder()); - } - sendCompleteMessage(onCompleteMessage, DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE); - } - } - - /** - * Register for data call list changed event. - * - * @param h The target to post the event message to. - * @param what The event. - */ - public void registerForDataCallListChanged(Handler h, int what) { - if (h != null) { - mDataCallListChangedRegistrants.addUnique(h, what, null); - } - } - - /** - * Unregister for data call list changed event. - * - * @param h The handler - */ - public void unregisterForDataCallListChanged(Handler h) { - if (h != null) { - mDataCallListChangedRegistrants.remove(h); - } - } - - /** - * Register apn unthrottled event - * - * @param h The target to post the event message to. - * @param what The event. - */ - public void registerForApnUnthrottled(Handler h, int what) { - if (h != null) { - mApnUnthrottledRegistrants.addUnique(h, what, null); - } - } - - /** - * Unregister for apn unthrottled event - * - * @param h The handler - */ - public void unregisterForApnUnthrottled(Handler h) { - if (h != null) { - mApnUnthrottledRegistrants.remove(h); - } - } - - /** - * Register for data service binding status changed event. - * - * @param h The target to post the event message to. - * @param what The event. - * @param obj The user object. - */ - public void registerForServiceBindingChanged(Handler h, int what, Object obj) { - if (h != null) { - mServiceBindingChangedRegistrants.addUnique(h, what, obj); - } - - } - - /** - * Unregister for data service binding status changed event. - * - * @param h The handler - */ - public void unregisterForServiceBindingChanged(Handler h) { - if (h != null) { - mServiceBindingChangedRegistrants.remove(h); - } - } - - /** - * Get the transport type. Must be a {@link TransportType}. - * - * @return - */ - @TransportType - public int getTransportType() { - return mTransportType; - } - - private void log(String s) { - Rlog.d(mTag, s); - } - - private void loge(String s) { - Rlog.e(mTag, s); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java b/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java deleted file mode 100644 index 4a465d262f..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (C) 2020 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.dataconnection; - -import android.annotation.ElapsedRealtimeLong; -import android.annotation.NonNull; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.os.PersistableBundle; -import android.telephony.AccessNetworkConstants; -import android.telephony.Annotation; -import android.telephony.Annotation.ApnType; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionManager; -import android.telephony.data.ApnSetting; -import android.telephony.data.ThrottleStatus; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.RetryManager; -import com.android.telephony.Rlog; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Data throttler tracks the throttling status of the data network and notifies registrants when - * there are changes. The throttler is per phone and per transport type. - */ -public class DataThrottler extends Handler { - private static final String TAG = DataThrottler.class.getSimpleName(); - - private static final int EVENT_SET_RETRY_TIME = 1; - private static final int EVENT_CARRIER_CONFIG_CHANGED = 2; - private static final int EVENT_RESET = 3; - private static final int EVENT_AIRPLANE_MODE_CHANGED = 4; - private static final int EVENT_TRACING_AREA_CODE_CHANGED = 5; - - private final Phone mPhone; - private final int mSlotIndex; - private final @AccessNetworkConstants.TransportType int mTransportType; - private boolean mResetWhenAreaCodeChanged = false; - - /** - * Callbacks that report the apn throttle status. - */ - private final List mCallbacks = new ArrayList<>(); - - /** - * Keeps track of detailed information of the throttle status that is meant to be - * reported to other components. - */ - private final Map mThrottleStatus = new ConcurrentHashMap<>(); - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - if (mPhone.getPhoneId() == intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { - if (intent.getBooleanExtra( - CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, false)) { - // Ignore the rebroadcast one to prevent multiple carrier config changed - // event during boot up. - return; - } - int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (SubscriptionManager.isValidSubscriptionId(subId)) { - sendEmptyMessage(EVENT_CARRIER_CONFIG_CHANGED); - } - } - } - } - }; - - public DataThrottler(Phone phone, int transportType) { - super(null, false); - mPhone = phone; - mSlotIndex = phone.getPhoneId(); - mTransportType = transportType; - - IntentFilter filter = new IntentFilter(); - filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - mPhone.getContext().registerReceiver(mBroadcastReceiver, filter, null, mPhone); - - mPhone.getServiceStateTracker().registerForAirplaneModeChanged(this, - EVENT_AIRPLANE_MODE_CHANGED, null); - mPhone.getServiceStateTracker().registerForAreaCodeChanged(this, - EVENT_TRACING_AREA_CODE_CHANGED, null); - } - - @Override - public void handleMessage(Message msg) { - AsyncResult ar; - switch (msg.what) { - case EVENT_SET_RETRY_TIME: - int apnTypes = msg.arg1; - int newRequestType = msg.arg2; - long retryElapsedTime = (long) msg.obj; - setRetryTimeInternal(apnTypes, retryElapsedTime, newRequestType); - break; - case EVENT_CARRIER_CONFIG_CHANGED: - onCarrierConfigChanged(); - break; - case EVENT_RESET: - resetInternal(); - break; - case EVENT_AIRPLANE_MODE_CHANGED: - ar = (AsyncResult) msg.obj; - if (!(Boolean) ar.result) { - resetInternal(); - } - break; - case EVENT_TRACING_AREA_CODE_CHANGED: - if (mResetWhenAreaCodeChanged) { - resetInternal(); - } - break; - } - } - - @NonNull - private PersistableBundle getCarrierConfig() { - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - // If an invalid subId is used, this bundle will contain default values. - PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId()); - if (config != null) { - return config; - } - } - // Return static default defined in CarrierConfigManager. - return CarrierConfigManager.getDefaultConfig(); - } - - private void onCarrierConfigChanged() { - PersistableBundle config = getCarrierConfig(); - mResetWhenAreaCodeChanged = config.getBoolean( - CarrierConfigManager.KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false); - } - - /** - * Set the retry time and handover failure mode for the give APN types. - * - * @param apnTypes APN types - * @param retryElapsedTime The elapsed time that data connection for APN types should not be - * retried. {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} indicates throttling does not exist. - * {@link RetryManager#NO_RETRY} indicates retry should never happen. - */ - public void setRetryTime(@ApnType int apnTypes, @ElapsedRealtimeLong long retryElapsedTime, - @DcTracker.RequestNetworkType int newRequestType) { - sendMessage(obtainMessage(EVENT_SET_RETRY_TIME, apnTypes, newRequestType, - retryElapsedTime)); - } - - /** - * Set the retry time and handover failure mode for the give APN types. This is running on the - * handler thread. - * - * @param apnTypes APN types - * @param retryElapsedTime The elapsed time that data connection for APN types should not be - * retried. {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} indicates throttling does not exist. - * {@link RetryManager#NO_RETRY} indicates retry should never happen. - */ - private void setRetryTimeInternal(@ApnType int apnTypes, @ElapsedRealtimeLong - long retryElapsedTime, @DcTracker.RequestNetworkType int newRequestType) { - if (retryElapsedTime < 0) { - retryElapsedTime = RetryManager.NO_SUGGESTED_RETRY_DELAY; - } - - List changedStatuses = new ArrayList<>(); - while (apnTypes != 0) { - int apnType; - // Due to an API mistake of ApnSetting.TYPE_DEFAULT (which combines default and hipri - // bit), we need to do special handling here. - if ((apnTypes & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) { - apnType = ApnSetting.TYPE_DEFAULT; - apnTypes &= ~ApnSetting.TYPE_DEFAULT; - } else { - //Extract the least significant bit. - apnType = apnTypes & -apnTypes; - //Remove the least significant bit. - apnTypes &= apnTypes - 1; - } - - //Update the apn throttle status - ThrottleStatus newStatus = createStatus(apnType, retryElapsedTime, newRequestType); - - ThrottleStatus oldStatus = mThrottleStatus.get(apnType); - - //Check to see if there is a change that needs to be applied - if (!newStatus.equals(oldStatus)) { - //Mark as changed status - changedStatuses.add(newStatus); - - //Put the new status in the temp space - mThrottleStatus.put(apnType, newStatus); - } - } - - if (changedStatuses.size() > 0) { - sendThrottleStatusChanged(changedStatuses); - } - } - - /** - * Get the earliest retry time for the given APN type. The time is the system's elapse time. - * - * Note the DataThrottler is running phone process's main thread, which is most of the telephony - * components running on. Calling this method from other threads might run into race conditions. - * - * @param apnType APN type - * @return The earliest retry time for APN type. The time is the system's elapse time. - * {@link RetryManager#NO_SUGGESTED_RETRY_DELAY} indicates there is no throttling for given APN - * type, {@link RetryManager#NO_RETRY} indicates retry should never happen. - */ - @ElapsedRealtimeLong - public long getRetryTime(@ApnType int apnType) { - ThrottleStatus status = mThrottleStatus.get(apnType); - if (status != null) { - if (status.getThrottleType() == ThrottleStatus.THROTTLE_TYPE_NONE) { - return RetryManager.NO_SUGGESTED_RETRY_DELAY; - } else { - return status.getThrottleExpiryTimeMillis(); - } - } - return RetryManager.NO_SUGGESTED_RETRY_DELAY; - } - - /** - * Resets retry times for all APNs to {@link RetryManager.NO_SUGGESTED_RETRY_DELAY}. - */ - public void reset() { - sendEmptyMessage(EVENT_RESET); - } - - /** - * Resets retry times for all APNs to {@link RetryManager.NO_SUGGESTED_RETRY_DELAY}. - */ - private void resetInternal() { - final List apnTypes = new ArrayList<>(); - for (ThrottleStatus throttleStatus : mThrottleStatus.values()) { - apnTypes.add(throttleStatus.getApnType()); - } - - for (int apnType : apnTypes) { - setRetryTime(apnType, RetryManager.NO_SUGGESTED_RETRY_DELAY, - DcTracker.REQUEST_TYPE_NORMAL); - } - } - - private ThrottleStatus createStatus(@Annotation.ApnType int apnType, long retryElapsedTime, - @DcTracker.RequestNetworkType int newRequestType) { - ThrottleStatus.Builder builder = new ThrottleStatus.Builder(); - - if (retryElapsedTime == RetryManager.NO_SUGGESTED_RETRY_DELAY) { - builder - .setNoThrottle() - .setRetryType(getRetryType(newRequestType)); - } else if (retryElapsedTime == RetryManager.NO_RETRY) { - builder - .setThrottleExpiryTimeMillis(RetryManager.NO_RETRY) - .setRetryType(ThrottleStatus.RETRY_TYPE_NONE); - } else { - builder - .setThrottleExpiryTimeMillis(retryElapsedTime) - .setRetryType(getRetryType(newRequestType)); - } - return builder - .setSlotIndex(mSlotIndex) - .setTransportType(mTransportType) - .setApnType(apnType) - .build(); - } - - private static int getRetryType(@DcTracker.RequestNetworkType int newRequestType) { - if (newRequestType == DcTracker.REQUEST_TYPE_NORMAL) { - return ThrottleStatus.RETRY_TYPE_NEW_CONNECTION; - } - - if (newRequestType == DcTracker.REQUEST_TYPE_HANDOVER) { - return ThrottleStatus.RETRY_TYPE_HANDOVER; - } - - loge("createStatus: Unknown requestType=" + newRequestType); - return ThrottleStatus.RETRY_TYPE_NEW_CONNECTION; - } - - private void sendThrottleStatusChanged(List statuses) { - synchronized (mCallbacks) { - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onThrottleStatusChanged(statuses); - } - } - } - - private static void loge(String s) { - Rlog.e(TAG, s); - } - - /** - * Reports changes to apn throttle statuses. - * - * Note: All statuses are sent when first registered. - * - * @param callback status changes callback - */ - public void registerForThrottleStatusChanges(DataThrottler.Callback callback) { - synchronized (mCallbacks) { - //Only add if it's not there already - if (!mCallbacks.contains(callback)) { - //Report everything the first time - List throttleStatuses = - new ArrayList<>(mThrottleStatus.values()); - callback.onThrottleStatusChanged(throttleStatuses); - mCallbacks.add(callback); - } - } - } - - /** - * Unregister the callback - * @param callback the callback to unregister - */ - public void unregisterForThrottleStatusChanges(DataThrottler.Callback callback) { - synchronized (mCallbacks) { - mCallbacks.remove(callback); - } - } - - /** - * Callback for when throttle statuses change - */ - public interface Callback { - /** - * Called whenever the throttle status of an APN has changed. - * - * Note: Called with all statuses when first registered. - * - * @param throttleStatuses the status changes - */ - void onThrottleStatusChanged(List throttleStatuses); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java deleted file mode 100644 index c34157eb9e..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcController.java +++ /dev/null @@ -1,487 +0,0 @@ -/* - * Copyright (C) 2013 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.dataconnection; - -import android.hardware.radio.V1_4.DataConnActiveStatus; -import android.net.LinkAddress; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.RegistrantList; -import android.telephony.AccessNetworkConstants; -import android.telephony.CarrierConfigManager; -import android.telephony.DataFailCause; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.telephony.data.TrafficDescriptor; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.dataconnection.DataConnection.UpdateLinkPropertyResult; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.net.module.util.LinkPropertiesUtils; -import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; -import com.android.net.module.util.NetUtils; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Objects; - -/** - * Data Connection Controller which is a package visible class and controls - * multiple data connections. For instance listening for unsolicited messages - * and then demultiplexing them to the appropriate DC. - */ -public class DcController extends Handler { - private static final boolean DBG = true; - private static final boolean VDBG = false; - - private final Phone mPhone; - private final DcTracker mDct; - private final String mTag; - private final DataServiceManager mDataServiceManager; - private final DcTesterDeactivateAll mDcTesterDeactivateAll; - - // package as its used by Testing code - // @GuardedBy("mDcListAll") - final ArrayList mDcListAll = new ArrayList<>(); - // @GuardedBy("mDcListAll") - private final HashMap mDcListActiveByCid = new HashMap<>(); - // @GuardedBy("mTrafficDescriptorsByCid") - private final HashMap> mTrafficDescriptorsByCid = - new HashMap<>(); - - /** - * Aggregated physical link status from all data connections. This reflects the device's RRC - * connection state. - * If {@link CarrierConfigManager#KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL} is true, - * then This reflects "internet data connection" instead of RRC state. - */ - private @DataCallResponse.LinkStatus int mPhysicalLinkStatus = - DataCallResponse.LINK_STATUS_UNKNOWN; - - private RegistrantList mPhysicalLinkStatusChangedRegistrants = new RegistrantList(); - - /** - * Constructor. - * - * @param name to be used for the Controller - * @param phone the phone associated with Dcc and Dct - * @param dct the DataConnectionTracker associated with Dcc - * @param dataServiceManager the data service manager that manages data services - * @param looper looper for this handler - */ - private DcController(String name, Phone phone, DcTracker dct, - DataServiceManager dataServiceManager, Looper looper) { - super(looper); - mPhone = phone; - mDct = dct; - mTag = name; - mDataServiceManager = dataServiceManager; - - mDcTesterDeactivateAll = (TelephonyUtils.IS_DEBUGGABLE) - ? new DcTesterDeactivateAll(mPhone, DcController.this, this) - : null; - mDataServiceManager.registerForDataCallListChanged(this, - DataConnection.EVENT_DATA_STATE_CHANGED); - } - - public static DcController makeDcc(Phone phone, DcTracker dct, - DataServiceManager dataServiceManager, Looper looper, - String tagSuffix) { - return new DcController("Dcc" + tagSuffix, phone, dct, dataServiceManager, looper); - } - - void addDc(DataConnection dc) { - synchronized (mDcListAll) { - mDcListAll.add(dc); - } - } - - void removeDc(DataConnection dc) { - synchronized (mDcListAll) { - mDcListActiveByCid.remove(dc.mCid); - mDcListAll.remove(dc); - } - synchronized (mTrafficDescriptorsByCid) { - mTrafficDescriptorsByCid.remove(dc.mCid); - } - } - - public void addActiveDcByCid(DataConnection dc) { - if (DBG && dc.mCid < 0) { - log("addActiveDcByCid dc.mCid < 0 dc=" + dc); - } - synchronized (mDcListAll) { - mDcListActiveByCid.put(dc.mCid, dc); - } - updateTrafficDescriptorsForCid(dc.mCid, dc.getTrafficDescriptors()); - } - - DataConnection getActiveDcByCid(int cid) { - synchronized (mDcListAll) { - return mDcListActiveByCid.get(cid); - } - } - - void removeActiveDcByCid(DataConnection dc) { - synchronized (mDcListAll) { - DataConnection removedDc = mDcListActiveByCid.remove(dc.mCid); - if (DBG && removedDc == null) { - log("removeActiveDcByCid removedDc=null dc=" + dc); - } - } - synchronized (mTrafficDescriptorsByCid) { - mTrafficDescriptorsByCid.remove(dc.mCid); - } - } - - boolean isDefaultDataActive() { - synchronized (mDcListAll) { - return mDcListActiveByCid.values().stream() - .anyMatch(dc -> dc.getApnContexts().stream() - .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT)); - } - } - - List getTrafficDescriptorsForCid(int cid) { - synchronized (mTrafficDescriptorsByCid) { - return mTrafficDescriptorsByCid.get(cid); - } - } - - void updateTrafficDescriptorsForCid(int cid, List tds) { - synchronized (mTrafficDescriptorsByCid) { - mTrafficDescriptorsByCid.put(cid, tds); - } - } - - @Override - public void handleMessage(Message msg) { - AsyncResult ar; - - switch (msg.what) { - case DataConnection.EVENT_DATA_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - if (ar.exception == null) { - onDataStateChanged((ArrayList) ar.result); - } else { - log("EVENT_DATA_STATE_CHANGED: exception; likely radio not available, ignore"); - } - break; - default: - loge("Unexpected event " + msg); - break; - } - } - - /** - * Process the new list of "known" Data Calls - * @param dcsList as sent by RIL_UNSOL_DATA_CALL_LIST_CHANGED - */ - private void onDataStateChanged(ArrayList dcsList) { - final HashMap dcListActiveByCid; - synchronized (mDcListAll) { - dcListActiveByCid = new HashMap<>(mDcListActiveByCid); - } - - if (DBG) { - log("onDataStateChanged: dcsList=" + dcsList - + " dcListActiveByCid=" + dcListActiveByCid); - } - - // Create hashmap of cid to DataCallResponse - HashMap dataCallResponseListByCid = new HashMap<>(); - for (DataCallResponse dcs : dcsList) { - dataCallResponseListByCid.put(dcs.getId(), dcs); - } - - // Add a DC that is active but not in the dcsList to the list of DC's to retry - ArrayList dcsToRetry = new ArrayList<>(); - for (DataConnection dc : dcListActiveByCid.values()) { - DataCallResponse response = dataCallResponseListByCid.get(dc.mCid); - if (response == null) { - if (DBG) log("onDataStateChanged: add to retry dc=" + dc); - dcsToRetry.add(dc); - } else { - List oldTds = getTrafficDescriptorsForCid(dc.mCid); - List newTds = response.getTrafficDescriptors(); - if (!oldTds.equals(newTds)) { - if (DBG) { - log("onDataStateChanged: add to retry due to TD changed dc=" + dc - + ", oldTds=" + oldTds + ", newTds=" + newTds); - } - updateTrafficDescriptorsForCid(dc.mCid, newTds); - dcsToRetry.add(dc); - } - } - } - if (DBG) log("onDataStateChanged: dcsToRetry=" + dcsToRetry); - - // Find which connections have changed state and send a notification or cleanup - // and any that are in active need to be retried. - ArrayList apnsToCleanup = new ArrayList(); - - boolean isAnyDataCallDormant = false; - boolean isAnyDataCallActive = false; - boolean isInternetDataCallActive = false; - - for (DataCallResponse newState : dcsList) { - - DataConnection dc = dcListActiveByCid.get(newState.getId()); - if (dc == null) { - // UNSOL_DATA_CALL_LIST_CHANGED arrived before SETUP_DATA_CALL completed. - loge("onDataStateChanged: no associated DC yet, ignore"); - continue; - } - - List apnContexts = dc.getApnContexts(); - if (apnContexts.size() == 0) { - if (DBG) loge("onDataStateChanged: no connected apns, ignore"); - } else { - // Determine if the connection/apnContext should be cleaned up - // or just a notification should be sent out. - if (DBG) { - log("onDataStateChanged: Found ConnId=" + newState.getId() - + " newState=" + newState.toString()); - } - if (apnContexts.stream().anyMatch( - i -> ApnSetting.TYPE_DEFAULT_STRING.equals(i.getApnType())) - && newState.getLinkStatus() == DataConnActiveStatus.ACTIVE) { - isInternetDataCallActive = true; - } - if (newState.getLinkStatus() == DataConnActiveStatus.INACTIVE) { - if (mDct.isCleanupRequired.get()) { - apnsToCleanup.addAll(apnContexts); - mDct.isCleanupRequired.set(false); - } else { - int failCause = DataFailCause.getFailCause(newState.getCause()); - if (DataFailCause.isRadioRestartFailure(mPhone.getContext(), failCause, - mPhone.getSubId())) { - if (DBG) { - log("onDataStateChanged: X restart radio, failCause=" - + failCause); - } - mDct.sendRestartRadio(); - } else if (mDct.isPermanentFailure(failCause)) { - if (DBG) { - log("onDataStateChanged: inactive, add to cleanup list. " - + "failCause=" + failCause); - } - apnsToCleanup.addAll(apnContexts); - } else { - if (DBG) { - log("onDataStateChanged: inactive, add to retry list. " - + "failCause=" + failCause); - } - dcsToRetry.add(dc); - } - } - } else { - // Update the pdu session id - dc.setPduSessionId(newState.getPduSessionId()); - - dc.updatePcscfAddr(newState); - - // Its active so update the DataConnections link properties - UpdateLinkPropertyResult result = dc.updateLinkProperty(newState); - dc.updateResponseFields(newState); - if (result.oldLp.equals(result.newLp)) { - if (DBG) log("onDataStateChanged: no change"); - } else { - if (LinkPropertiesUtils.isIdenticalInterfaceName( - result.oldLp, result.newLp)) { - if (!LinkPropertiesUtils.isIdenticalDnses( - result.oldLp, result.newLp) - || !LinkPropertiesUtils.isIdenticalRoutes( - result.oldLp, result.newLp) - || !LinkPropertiesUtils.isIdenticalHttpProxy( - result.oldLp, result.newLp) - || !LinkPropertiesUtils.isIdenticalAddresses( - result.oldLp, result.newLp)) { - // If the same address type was removed and - // added we need to cleanup - CompareOrUpdateResult car - = new CompareOrUpdateResult( - result.oldLp != null ? - result.oldLp.getLinkAddresses() : null, - result.newLp != null ? - result.newLp.getLinkAddresses() : null, - (la) -> Objects.hash(((LinkAddress)la).getAddress(), - ((LinkAddress)la).getPrefixLength(), - ((LinkAddress)la).getScope())); - if (DBG) { - log("onDataStateChanged: oldLp=" + result.oldLp - + " newLp=" + result.newLp + " car=" + car); - } - boolean needToClean = false; - for (LinkAddress added : car.added) { - for (LinkAddress removed : car.removed) { - if (NetUtils.addressTypeMatches( - removed.getAddress(), - added.getAddress())) { - needToClean = true; - break; - } - } - } - if (needToClean) { - if (DBG) { - log("onDataStateChanged: addr change," - + " cleanup apns=" + apnContexts - + " oldLp=" + result.oldLp - + " newLp=" + result.newLp); - } - apnsToCleanup.addAll(apnContexts); - } - } else { - if (DBG) { - log("onDataStateChanged: no changes"); - } - } - } else { - apnsToCleanup.addAll(apnContexts); - if (DBG) { - log("onDataStateChanged: interface change, cleanup apns=" - + apnContexts); - } - } - } - } - } - - if (newState.getLinkStatus() == DataConnActiveStatus.ACTIVE) { - isAnyDataCallActive = true; - } - if (newState.getLinkStatus() == DataConnActiveStatus.DORMANT) { - isAnyDataCallDormant = true; - } - } - - if (mDataServiceManager.getTransportType() - == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - boolean isPhysicalLinkStatusFocusingOnInternetData = - mDct.getLteEndcUsingUserDataForIdleDetection(); - int physicalLinkStatus = - (isPhysicalLinkStatusFocusingOnInternetData - ? isInternetDataCallActive : isAnyDataCallActive) - ? DataCallResponse.LINK_STATUS_ACTIVE - : DataCallResponse.LINK_STATUS_DORMANT; - if (mPhysicalLinkStatus != physicalLinkStatus) { - mPhysicalLinkStatus = physicalLinkStatus; - mPhysicalLinkStatusChangedRegistrants.notifyResult(mPhysicalLinkStatus); - } - if (isAnyDataCallDormant && !isAnyDataCallActive) { - // There is no way to indicate link activity per APN right now. So - // Link Activity will be considered dormant only when all data calls - // are dormant. - // If a single data call is in dormant state and none of the data - // calls are active broadcast overall link status as dormant. - if (DBG) { - log("onDataStateChanged: Data activity DORMANT. stopNetStatePoll"); - } - mDct.sendStopNetStatPoll(DctConstants.Activity.DORMANT); - } else { - if (DBG) { - log("onDataStateChanged: Data Activity updated to NONE. " - + "isAnyDataCallActive = " + isAnyDataCallActive - + " isAnyDataCallDormant = " + isAnyDataCallDormant); - } - if (isAnyDataCallActive) { - mDct.sendStartNetStatPoll(DctConstants.Activity.NONE); - } - } - } - - if (DBG) { - log("onDataStateChanged: dcsToRetry=" + dcsToRetry - + " apnsToCleanup=" + apnsToCleanup); - } - - // Cleanup connections that have changed - for (ApnContext apnContext : apnsToCleanup) { - mDct.cleanUpConnection(apnContext); - } - - // Retry connections that have disappeared - for (DataConnection dc : dcsToRetry) { - if (DBG) log("onDataStateChanged: send EVENT_LOST_CONNECTION dc.mTag=" + dc.mTag); - dc.sendMessage(DataConnection.EVENT_LOST_CONNECTION, dc.mTag); - } - - if (VDBG) log("onDataStateChanged: X"); - } - - /** - * Register for physical link status (i.e. RRC state) changed event. - * if {@link CarrierConfigManager#KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL} is true, - * then physical link status is focusing on "internet data connection" instead of RRC state. - * @param h The handler - * @param what The event - */ - @VisibleForTesting - public void registerForPhysicalLinkStatusChanged(Handler h, int what) { - mPhysicalLinkStatusChangedRegistrants.addUnique(h, what, null); - } - - /** - * Unregister from physical link status (i.e. RRC state) changed event. - * - * @param h The previously registered handler - */ - void unregisterForPhysicalLinkStatusChanged(Handler h) { - mPhysicalLinkStatusChangedRegistrants.remove(h); - } - - private void log(String s) { - Rlog.d(mTag, s); - } - - private void loge(String s) { - Rlog.e(mTag, s); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - synchronized (mDcListAll) { - sb.append("mDcListAll=").append(mDcListAll) - .append(" mDcListActiveByCid=").append(mDcListActiveByCid); - } - synchronized (mTrafficDescriptorsByCid) { - sb.append("mTrafficDescriptorsByCid=").append(mTrafficDescriptorsByCid); - } - return sb.toString(); - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println(" mPhone=" + mPhone); - synchronized (mDcListAll) { - pw.println(" mDcListAll=" + mDcListAll); - pw.println(" mDcListActiveByCid=" + mDcListActiveByCid); - } - synchronized (mTrafficDescriptorsByCid) { - pw.println(" mTrafficDescriptorsByCid=" + mTrafficDescriptorsByCid); - } - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java b/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java deleted file mode 100644 index 3cdd2090d5..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcFailBringUp.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2013 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.dataconnection; - -import android.content.Intent; -import android.telephony.Annotation.DataFailureCause; -import android.telephony.DataFailCause; - -import com.android.telephony.Rlog; - -/** - * A package visible class for supporting testing failing bringUp commands. This - * saves the parameters from a action_fail_bringup intent. See - * {@link DataConnection#doOnConnect} and {@see DcTesterFailBringUpAll} for more info. - */ -public class DcFailBringUp { - private static final String LOG_TAG = "DcFailBringUp"; - private static final boolean DBG = true; - - static final String INTENT_BASE = DataConnection.class.getPackage().getName(); - - static final String ACTION_FAIL_BRINGUP = "action_fail_bringup"; - - // counter with its --ei option name and default value - static final String COUNTER = "counter"; - static final int DEFAULT_COUNTER = 2; - int mCounter; - - // failCause with its --ei option name and default value - static final String FAIL_CAUSE = "fail_cause"; - static final int DEFAULT_FAIL_CAUSE = DataFailCause.ERROR_UNSPECIFIED; - @DataFailureCause - int mFailCause; - - // suggestedRetryTime with its --ei option name and default value - static final String SUGGESTED_RETRY_TIME = "suggested_retry_time"; - static final long DEFAULT_SUGGESTED_RETRY_TIME = -1; - long mSuggestedRetryTime; - - // Get the Extra Intent parameters - void saveParameters(Intent intent, String s) { - if (DBG) log(s + ".saveParameters: action=" + intent.getAction()); - mCounter = intent.getIntExtra(COUNTER, DEFAULT_COUNTER); - mFailCause = DataFailCause.getFailCause( - intent.getIntExtra(FAIL_CAUSE, DEFAULT_FAIL_CAUSE)); - mSuggestedRetryTime = - intent.getLongExtra(SUGGESTED_RETRY_TIME, DEFAULT_SUGGESTED_RETRY_TIME); - if (DBG) { - log(s + ".saveParameters: " + this); - } - } - - public void saveParameters(int counter, @DataFailureCause int failCause, - long suggestedRetryTime) { - mCounter = counter; - mFailCause = DataFailCause.getFailCause(failCause); - mSuggestedRetryTime = suggestedRetryTime; - } - - @Override - public String toString() { - return "{mCounter=" + mCounter + - " mFailCause=" + mFailCause + - " mSuggestedRetryTime=" + mSuggestedRetryTime + "}"; - - } - - private static void log(String s) { - Rlog.d(LOG_TAG, s); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java b/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java deleted file mode 100644 index c6def34093..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcNetworkAgent.java +++ /dev/null @@ -1,617 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.KeepalivePacketData; -import android.net.LinkProperties; -import android.net.NattKeepalivePacketData; -import android.net.NetworkAgent; -import android.net.NetworkAgentConfig; -import android.net.NetworkCapabilities; -import android.net.NetworkProvider; -import android.net.QosFilter; -import android.net.QosSessionAttributes; -import android.net.SocketKeepalive; -import android.net.Uri; -import android.os.Handler; -import android.os.Message; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.TransportType; -import android.telephony.Annotation.NetworkType; -import android.telephony.AnomalyReporter; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.ServiceState; -import android.telephony.TelephonyManager; -import android.telephony.data.QosBearerSession; -import android.util.LocalLog; -import android.util.SparseArray; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.SlidingWindowEventCounter; -import com.android.internal.telephony.data.KeepaliveStatus; -import com.android.internal.telephony.data.NotifyQosSessionInterface; -import com.android.internal.telephony.data.QosCallbackTracker; -import com.android.internal.telephony.metrics.TelephonyMetrics; -import com.android.internal.util.IndentingPrintWriter; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.time.Duration; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -/** - * This class represents a network agent which is communication channel between - * {@link DataConnection} and {@link com.android.server.ConnectivityService}. The agent is - * created when data connection enters {@link DataConnection.DcActiveState} until it exits that - * state. - * - * Note that in IWLAN handover scenario, this agent could be transferred to the new - * {@link DataConnection} so for a short window of time this object might be accessed by two - * different {@link DataConnection}. Thus each method in this class needs to be synchronized. - */ -public class DcNetworkAgent extends NetworkAgent implements NotifyQosSessionInterface { - private final String mTag; - - private final int mId; - - private final Phone mPhone; - - private final Handler mHandler; - - private int mTransportType; - - private NetworkCapabilities mNetworkCapabilities; - - public final DcKeepaliveTracker keepaliveTracker = new DcKeepaliveTracker(); - - private final QosCallbackTracker mQosCallbackTracker; - - private final Executor mQosCallbackExecutor = Executors.newSingleThreadExecutor(); - - private DataConnection mDataConnection; - - private final LocalLog mNetCapsLocalLog = new LocalLog(32); - - // For interface duplicate detection. Key is the net id, value is the interface name in string. - private static Map sInterfaceNames = new ConcurrentHashMap<>(); - - private static final long NETWORK_UNWANTED_ANOMALY_WINDOW_MS = TimeUnit.MINUTES.toMillis(5); - private static final int NETWORK_UNWANTED_ANOMALY_NUM_OCCURRENCES = 12; - - private static final int EVENT_UNWANTED_TIMEOUT = 1; - - @VisibleForTesting - public DcNetworkAgent(DataConnection dc, Phone phone, int score, NetworkAgentConfig config, - NetworkProvider networkProvider, int transportType) { - super(phone.getContext(), dc.getHandler().getLooper(), "DcNetworkAgent", - dc.getNetworkCapabilities(), dc.getLinkProperties(), score, config, - networkProvider); - register(); - mId = getNetwork().getNetId(); - mTag = "DcNetworkAgent" + "-" + mId; - mPhone = phone; - mHandler = new Handler(dc.getHandler().getLooper()) { - @Override - public void handleMessage(Message msg) { - if (msg.what == EVENT_UNWANTED_TIMEOUT) { - loge("onNetworkUnwanted timed out. Perform silent de-register."); - logd("Unregister from connectivity service. " + sInterfaceNames.get(mId) - + " removed."); - sInterfaceNames.remove(mId); - DcNetworkAgent.this.unregister(); - } - } - }; - mNetworkCapabilities = dc.getNetworkCapabilities(); - mTransportType = transportType; - mDataConnection = dc; - if (dc.getLinkProperties() != null) { - checkDuplicateInterface(mId, dc.getLinkProperties().getInterfaceName()); - logd("created for data connection " + dc.getName() + ", " - + dc.getLinkProperties().getInterfaceName()); - } else { - loge("The connection does not have a valid link properties."); - } - mQosCallbackTracker = new QosCallbackTracker(this, mPhone); - } - - private @NetworkType int getNetworkType() { - ServiceState ss = mPhone.getServiceState(); - int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - - NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, mTransportType); - if (nri != null) { - networkType = nri.getAccessNetworkTechnology(); - } - - return networkType; - } - - private void checkDuplicateInterface(int netId, @Nullable String interfaceName) { - for (Map.Entry entry: sInterfaceNames.entrySet()) { - if (Objects.equals(interfaceName, entry.getValue())) { - String message = "Duplicate interface " + interfaceName - + " is detected. DcNetworkAgent-" + entry.getKey() - + " already used this interface name."; - loge(message); - // Using fixed UUID to avoid duplicate bugreport notification - AnomalyReporter.reportAnomaly( - UUID.fromString("02f3d3f6-4613-4415-b6cb-8d92c8a938a6"), - message, mPhone.getCarrierId()); - return; - } - } - sInterfaceNames.put(netId, interfaceName); - } - - /** - * @return The tag - */ - String getTag() { - return mTag; - } - - /** - * Set the data connection that owns this network agent. - * - * @param dc Data connection owning this network agent. - * @param transportType Transport that this data connection is on. - */ - public synchronized void acquireOwnership(@NonNull DataConnection dc, - @TransportType int transportType) { - mDataConnection = dc; - mTransportType = transportType; - logd(dc.getName() + " acquired the ownership of this agent."); - } - - /** - * Release the ownership of network agent. - */ - public synchronized void releaseOwnership(DataConnection dc) { - if (mDataConnection == null) { - loge("releaseOwnership called on no-owner DcNetworkAgent!"); - return; - } else if (mDataConnection != dc) { - loge("releaseOwnership: This agent belongs to " - + mDataConnection.getName() + ", ignored the request from " + dc.getName()); - return; - } - logd("Data connection " + mDataConnection.getName() + " released the ownership."); - mDataConnection = null; - } - - /** - * @return The data connection that owns this agent - */ - public synchronized DataConnection getDataConnection() { - return mDataConnection; - } - - private static final SlidingWindowEventCounter sNetworkUnwantedCounter = - new SlidingWindowEventCounter(NETWORK_UNWANTED_ANOMALY_WINDOW_MS, - NETWORK_UNWANTED_ANOMALY_NUM_OCCURRENCES); - - @Override - public synchronized void onNetworkUnwanted() { - mHandler.sendEmptyMessageDelayed(EVENT_UNWANTED_TIMEOUT, TimeUnit.SECONDS.toMillis(30)); - trackNetworkUnwanted(); - if (mDataConnection == null) { - loge("onNetworkUnwanted found called on no-owner DcNetworkAgent!"); - return; - } - - logd("onNetworkUnwanted called. Now tear down the data connection " - + mDataConnection.getName()); - mDataConnection.tearDownAll(Phone.REASON_RELEASED_BY_CONNECTIVITY_SERVICE, - DcTracker.RELEASE_TYPE_DETACH, null); - } - - /** - * There have been several bugs where a RECONNECT loop kicks off where a DataConnection - * connects to the Network, ConnectivityService indicates that the Network is unwanted, - * and then the DataConnection reconnects. By the time we get the bug report it's too late - * because there have already been hundreds of RECONNECTS. This is meant to capture the issue - * when it first starts. - * - * The unwanted counter is configured to only take an anomaly report in extreme cases. - * This is to avoid having the anomaly message show up on several devices. - * - * This is directly related to b/175845538. But, there have been several other occurrences of - * this issue. - */ - private void trackNetworkUnwanted() { - if (sNetworkUnwantedCounter.addOccurrence()) { - AnomalyReporter.reportAnomaly( - UUID.fromString("3f578b5c-64e9-11eb-ae93-0242ac130002"), - "Network Unwanted called 12 times in 5 minutes.", mPhone.getCarrierId()); - } - } - - @Override - public synchronized void onBandwidthUpdateRequested() { - if (mDataConnection == null) { - loge("onBandwidthUpdateRequested called on no-owner DcNetworkAgent!"); - return; - } - - if (mPhone.getLceStatus() == RILConstants.LCE_ACTIVE // active LCE service - && mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.pullLceData(mDataConnection.obtainMessage( - DataConnection.EVENT_BW_REFRESH_RESPONSE)); - } - } - - @Override - public synchronized void onValidationStatus(int status, Uri redirectUri) { - if (mDataConnection == null) { - loge("onValidationStatus called on no-owner DcNetworkAgent!"); - return; - } - - logd("validation status: " + status + " with redirection URL: " + redirectUri); - DcTracker dct = mPhone.getDcTracker(mTransportType); - if (dct != null) { - Message msg = dct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - status, mDataConnection.getCid(), redirectUri.toString()); - msg.sendToTarget(); - } - } - - private synchronized boolean isOwned(DataConnection dc, String reason) { - if (mDataConnection == null) { - loge(reason + " called on no-owner DcNetworkAgent!"); - return false; - } else if (mDataConnection != dc) { - loge(reason + ": This agent belongs to " - + mDataConnection.getName() + ", ignored the request from " + dc.getName()); - return false; - } - return true; - } - - /** - * Update the legacy sub type (i.e. data network type). - * - * @param dc The data connection that invokes this method. - */ - public synchronized void updateLegacySubtype(DataConnection dc) { - if (!isOwned(dc, "updateLegacySubtype")) return; - - int networkType = getNetworkType(); - setLegacySubtype(networkType, TelephonyManager.getNetworkTypeName(networkType)); - } - - /** - * Set the network capabilities. - * - * @param networkCapabilities The network capabilities. - * @param dc The data connection that invokes this method. - */ - public synchronized void sendNetworkCapabilities(NetworkCapabilities networkCapabilities, - DataConnection dc) { - if (!isOwned(dc, "sendNetworkCapabilities")) return; - - if (!networkCapabilities.equals(mNetworkCapabilities)) { - String logStr = "Changed from " + mNetworkCapabilities + " to " - + networkCapabilities + ", Data RAT=" - + mPhone.getServiceState().getRilDataRadioTechnology() - + ", dc=" + mDataConnection.getName(); - logd(logStr); - mNetCapsLocalLog.log(logStr); - if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { - // only log metrics for DataConnection with NET_CAPABILITY_INTERNET - if (mNetworkCapabilities == null - || networkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) - != mNetworkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)) { - TelephonyMetrics.getInstance().writeNetworkCapabilitiesChangedEvent( - mPhone.getPhoneId(), networkCapabilities); - } - } - mNetworkCapabilities = networkCapabilities; - } - sendNetworkCapabilities(networkCapabilities); - } - - /** - * Set the link properties - * - * @param linkProperties The link properties - * @param dc The data connection that invokes this method. - */ - public synchronized void sendLinkProperties(@NonNull LinkProperties linkProperties, - DataConnection dc) { - if (!isOwned(dc, "sendLinkProperties")) return; - - sInterfaceNames.put(mId, dc.getLinkProperties().getInterfaceName()); - sendLinkProperties(linkProperties); - } - - /** - * Set the network score. - * - * @param score The network score. - * @param dc The data connection that invokes this method. - */ - public synchronized void sendNetworkScore(int score, DataConnection dc) { - if (!isOwned(dc, "sendNetworkScore")) return; - sendNetworkScore(score); - } - - /** - * Unregister the network agent from connectivity service. - * - * @param dc The data connection that invokes this method. - */ - public synchronized void unregister(DataConnection dc) { - if (!isOwned(dc, "unregister")) return; - - mHandler.removeMessages(EVENT_UNWANTED_TIMEOUT); - logd("Unregister from connectivity service. " + sInterfaceNames.get(mId) + " removed."); - sInterfaceNames.remove(mId); - super.unregister(); - } - - @Override - public synchronized void onStartSocketKeepalive(int slot, @NonNull Duration interval, - @NonNull KeepalivePacketData packet) { - if (mDataConnection == null) { - loge("onStartSocketKeepalive called on no-owner DcNetworkAgent!"); - return; - } - - if (packet instanceof NattKeepalivePacketData) { - mDataConnection.obtainMessage(DataConnection.EVENT_KEEPALIVE_START_REQUEST, - slot, (int) interval.getSeconds(), packet).sendToTarget(); - } else { - sendSocketKeepaliveEvent(slot, SocketKeepalive.ERROR_UNSUPPORTED); - } - } - - @Override - public synchronized void onStopSocketKeepalive(int slot) { - if (mDataConnection == null) { - loge("onStopSocketKeepalive called on no-owner DcNetworkAgent!"); - return; - } - - mDataConnection.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slot) - .sendToTarget(); - } - - @Override - public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) { - mQosCallbackExecutor.execute(() -> mQosCallbackTracker.addFilter(qosCallbackId, - new QosCallbackTracker.IFilter() { - @Override - public boolean matchesLocalAddress( - InetAddress address, int startPort, int endPort) { - return filter.matchesLocalAddress(address, startPort, endPort); - } - - @Override - public boolean matchesRemoteAddress( - InetAddress address, int startPort, int endPort) { - return filter.matchesRemoteAddress(address, startPort, endPort); - } - })); - } - - @Override - public void onQosCallbackUnregistered(final int qosCallbackId) { - mQosCallbackExecutor.execute(() -> mQosCallbackTracker.removeFilter(qosCallbackId)); - } - - void updateQosBearerSessions(final List qosBearerSessions) { - mQosCallbackExecutor.execute(() -> mQosCallbackTracker.updateSessions(qosBearerSessions)); - } - - @Override - public void notifyQosSessionAvailable(final int qosCallbackId, final int sessionId, - @NonNull final QosSessionAttributes attributes) { - super.sendQosSessionAvailable(qosCallbackId, sessionId, attributes); - } - - @Override - public void notifyQosSessionLost(final int qosCallbackId, - final int sessionId, final int qosSessionType) { - super.sendQosSessionLost(qosCallbackId, sessionId, qosSessionType); - } - - @Override - public String toString() { - return "DcNetworkAgent-" - + mId - + " mDataConnection=" - + ((mDataConnection != null) ? mDataConnection.getName() : null) - + " mTransportType=" - + AccessNetworkConstants.transportTypeToString(mTransportType) - + " " + ((mDataConnection != null) ? mDataConnection.getLinkProperties() : null) - + " mNetworkCapabilities=" + mNetworkCapabilities; - } - - /** - * Dump the state of transport manager - * - * @param fd File descriptor - * @param printWriter Print writer - * @param args Arguments - */ - public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { - IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); - pw.println(toString()); - pw.increaseIndent(); - pw.println("Net caps logs:"); - mNetCapsLocalLog.dump(fd, pw, args); - pw.decreaseIndent(); - } - - /** - * Log with debug level - * - * @param s is string log - */ - private void logd(String s) { - Rlog.d(mTag, s); - } - - /** - * Log with error level - * - * @param s is string log - */ - private void loge(String s) { - Rlog.e(mTag, s); - } - - class DcKeepaliveTracker { - private class KeepaliveRecord { - public int slotId; - public int currentStatus; - - KeepaliveRecord(int slotId, int status) { - this.slotId = slotId; - this.currentStatus = status; - } - } - - private final SparseArray mKeepalives = new SparseArray(); - - int getHandleForSlot(int slotId) { - for (int i = 0; i < mKeepalives.size(); i++) { - KeepaliveRecord kr = mKeepalives.valueAt(i); - if (kr.slotId == slotId) return mKeepalives.keyAt(i); - } - return -1; - } - - 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; - } - } - - void handleKeepaliveStarted(final int slot, KeepaliveStatus ks) { - switch (ks.statusCode) { - case KeepaliveStatus.STATUS_INACTIVE: - DcNetworkAgent.this.sendSocketKeepaliveEvent(slot, - keepaliveStatusErrorToPacketKeepaliveError(ks.errorCode)); - break; - case KeepaliveStatus.STATUS_ACTIVE: - DcNetworkAgent.this.sendSocketKeepaliveEvent( - slot, SocketKeepalive.SUCCESS); - // fall through to add record - case KeepaliveStatus.STATUS_PENDING: - logd("Adding keepalive handle=" - + ks.sessionHandle + " slot = " + slot); - mKeepalives.put(ks.sessionHandle, - new KeepaliveRecord( - slot, ks.statusCode)); - break; - default: - logd("Invalid KeepaliveStatus Code: " + ks.statusCode); - break; - } - } - - void handleKeepaliveStatus(KeepaliveStatus ks) { - final KeepaliveRecord kr; - kr = mKeepalives.get(ks.sessionHandle); - - if (kr == null) { - // If there is no slot for the session handle, we received an event - // for a different data connection. This is not an error because the - // keepalive session events are broadcast to all listeners. - loge("Discarding keepalive event for different data connection:" + ks); - return; - } - // Switch on the current state, to see what we do with the status update - switch (kr.currentStatus) { - case KeepaliveStatus.STATUS_INACTIVE: - logd("Inactive Keepalive received status!"); - DcNetworkAgent.this.sendSocketKeepaliveEvent( - kr.slotId, SocketKeepalive.ERROR_HARDWARE_ERROR); - break; - case KeepaliveStatus.STATUS_PENDING: - switch (ks.statusCode) { - case KeepaliveStatus.STATUS_INACTIVE: - DcNetworkAgent.this.sendSocketKeepaliveEvent(kr.slotId, - keepaliveStatusErrorToPacketKeepaliveError(ks.errorCode)); - kr.currentStatus = KeepaliveStatus.STATUS_INACTIVE; - mKeepalives.remove(ks.sessionHandle); - break; - case KeepaliveStatus.STATUS_ACTIVE: - logd("Pending Keepalive received active status!"); - kr.currentStatus = KeepaliveStatus.STATUS_ACTIVE; - DcNetworkAgent.this.sendSocketKeepaliveEvent( - kr.slotId, SocketKeepalive.SUCCESS); - break; - case KeepaliveStatus.STATUS_PENDING: - loge("Invalid unsolicied Keepalive Pending Status!"); - break; - default: - loge("Invalid Keepalive Status received, " + ks.statusCode); - } - break; - case KeepaliveStatus.STATUS_ACTIVE: - switch (ks.statusCode) { - case KeepaliveStatus.STATUS_INACTIVE: - logd("Keepalive received stopped status!"); - DcNetworkAgent.this.sendSocketKeepaliveEvent( - kr.slotId, SocketKeepalive.SUCCESS); - - kr.currentStatus = KeepaliveStatus.STATUS_INACTIVE; - mKeepalives.remove(ks.sessionHandle); - break; - case KeepaliveStatus.STATUS_PENDING: - case KeepaliveStatus.STATUS_ACTIVE: - loge("Active Keepalive received invalid status!"); - break; - default: - loge("Invalid Keepalive Status received, " + ks.statusCode); - } - break; - default: - loge("Invalid Keepalive Status received, " + kr.currentStatus); - } - } - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcRequest.java b/src/java/com/android/internal/telephony/dataconnection/DcRequest.java deleted file mode 100644 index da775e82f5..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcRequest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2006 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.dataconnection; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.NetworkRequest; -import android.net.NetworkSpecifier; -import android.net.TelephonyNetworkSpecifier; -import android.telephony.Annotation.ApnType; - -import com.android.telephony.Rlog; - -/** - * Wraps cellular network requests to configured apn types. - */ -public class DcRequest implements Comparable { - private static final String LOG_TAG = "DcRequest"; - - @NonNull - public final NetworkRequest networkRequest; - public final int priority; - public final @ApnType int apnType; - - private DcRequest(@NonNull final NetworkRequest nr, @ApnType final int type, - int apnPriority) { - networkRequest = nr; - priority = apnPriority; - apnType = type; - } - - /** - * Create a DcRequest based off of the network request. If the network request is not cellular, - * then null is returned and a warning is generated. - * @param networkRequest sets the type of dc request - * @param apnConfigTypeRepository apn config types to match on the network request - * @return corresponding DcRequest - * - */ - @Nullable - public static DcRequest create(@NonNull final NetworkRequest networkRequest, - @NonNull final ApnConfigTypeRepository apnConfigTypeRepository) { - final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest); - final ApnConfigType apnConfigType = apnConfigTypeRepository.getByType(apnType); - if (apnConfigType == null) { - Rlog.d(LOG_TAG, "Non cellular request ignored: " + networkRequest.toString()); - checkForAnomalousNetworkRequest(networkRequest); - return null; - } else { - Rlog.d(LOG_TAG, "Cellular request confirmed: " + networkRequest.toString()); - return new DcRequest(networkRequest, apnType, apnConfigType.getPriority()); - } - } - - private static void checkForAnomalousNetworkRequest(NetworkRequest networkRequest) { - NetworkSpecifier specifier = networkRequest.getNetworkSpecifier(); - if (specifier != null) { - if (specifier instanceof TelephonyNetworkSpecifier) { - reportAnomalousNetworkRequest(networkRequest); - } - } - } - - private static void reportAnomalousNetworkRequest(NetworkRequest networkRequest) { - //TODO: Report anomaly if this happens - Rlog.w(LOG_TAG, "A TelephonyNetworkSpecifier for a non-cellular request is invalid: " - + networkRequest.toString()); - - } - - public String toString() { - return networkRequest.toString() + ", priority=" + priority + ", apnType=" + apnType; - } - - public int hashCode() { - return networkRequest.hashCode(); - } - - public boolean equals(Object o) { - if (o instanceof DcRequest) { - return networkRequest.equals(((DcRequest)o).networkRequest); - } - return false; - } - - public int compareTo(DcRequest o) { - return o.priority - priority; - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java deleted file mode 100644 index 11a0ae67e0..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcTesterDeactivateAll.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2013 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.dataconnection; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.telephony.Rlog; - -/** - * To bring down all DC's send the following intent: - * - * adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_deactivate_all - */ -public class DcTesterDeactivateAll { - private static final String LOG_TAG = "DcTesterDeacativateAll"; - private static final boolean DBG = true; - - private Phone mPhone; - private DcController mDcc; - - public static String sActionDcTesterDeactivateAll = - "com.android.internal.telephony.dataconnection.action_deactivate_all"; - - - // The static intent receiver one for all instances and we assume this - // is running on the same thread as Dcc. - protected BroadcastReceiver sIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (DBG) log("sIntentReceiver.onReceive: action=" + action); - if (action.equals(sActionDcTesterDeactivateAll) - || action.equals(mPhone.getActionDetached())) { - log("Send DEACTIVATE to all Dcc's"); - if (mDcc != null) { - for (DataConnection dc : mDcc.mDcListAll) { - dc.tearDownNow(); - } - } else { - if (DBG) log("onReceive: mDcc is null, ignoring"); - } - } else { - if (DBG) log("onReceive: unknown action=" + action); - } - } - }; - - DcTesterDeactivateAll(Phone phone, DcController dcc, Handler handler) { - mPhone = phone; - mDcc = dcc; - - if (TelephonyUtils.IS_DEBUGGABLE) { - IntentFilter filter = new IntentFilter(); - - filter.addAction(sActionDcTesterDeactivateAll); - log("register for intent action=" + sActionDcTesterDeactivateAll); - - filter.addAction(mPhone.getActionDetached()); - log("register for intent action=" + mPhone.getActionDetached()); - - phone.getContext().registerReceiver(sIntentReceiver, filter, null, handler, - Context.RECEIVER_EXPORTED); - } - } - - void dispose() { - if (TelephonyUtils.IS_DEBUGGABLE) { - mPhone.getContext().unregisterReceiver(sIntentReceiver); - } - } - - private static void log(String s) { - Rlog.d(LOG_TAG, s); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java b/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java deleted file mode 100644 index 788da297eb..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcTesterFailBringUpAll.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2013 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.dataconnection; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import android.telephony.DataFailCause; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.telephony.Rlog; - -/** - * A package level call that causes all DataConnection bringUp calls to fail a specific - * number of times. Here is an example that sets counter to 2 and cause to -3 for all instances: - * adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_fail_bringup \ - * --ei counter 2 --ei fail_cause -3 - * - * Also you can add a suggested retry time if desired: - * --ei suggested_retry_time 5000 - * - * The fail_cause is one of {@link DataFailCause} - */ -public class DcTesterFailBringUpAll { - private static final String LOG_TAG = "DcTesterFailBrinupAll"; - private static final boolean DBG = true; - - private Phone mPhone; - - private String mActionFailBringUp = DcFailBringUp.INTENT_BASE + "." - + DcFailBringUp.ACTION_FAIL_BRINGUP; - - // The saved FailBringUp data from the intent - private DcFailBringUp mFailBringUp = new DcFailBringUp(); - - // The static intent receiver one for all instances. - private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (DBG) log("sIntentReceiver.onReceive: action=" + action); - if (action.equals(mActionFailBringUp)) { - mFailBringUp.saveParameters(intent, "sFailBringUp"); - } else if (action.equals(mPhone.getActionDetached())) { - // Counter is MAX, bringUp/retry will always fail - log("simulate detaching"); - mFailBringUp.saveParameters(Integer.MAX_VALUE, - DataFailCause.LOST_CONNECTION, - DcFailBringUp.DEFAULT_SUGGESTED_RETRY_TIME); - } else if (action.equals(mPhone.getActionAttached())) { - // Counter is 0 next bringUp/retry will succeed - log("simulate attaching"); - mFailBringUp.saveParameters(0, DataFailCause.NONE, - DcFailBringUp.DEFAULT_SUGGESTED_RETRY_TIME); - } else { - if (DBG) log("onReceive: unknown action=" + action); - } - } - }; - - DcTesterFailBringUpAll(Phone phone, Handler handler) { - mPhone = phone; - if (TelephonyUtils.IS_DEBUGGABLE) { - IntentFilter filter = new IntentFilter(); - - filter.addAction(mActionFailBringUp); - log("register for intent action=" + mActionFailBringUp); - - filter.addAction(mPhone.getActionDetached()); - log("register for intent action=" + mPhone.getActionDetached()); - - filter.addAction(mPhone.getActionAttached()); - log("register for intent action=" + mPhone.getActionAttached()); - - phone.getContext().registerReceiver(mIntentReceiver, filter, null, handler, - Context.RECEIVER_EXPORTED); - } - } - - void dispose() { - if (TelephonyUtils.IS_DEBUGGABLE) { - mPhone.getContext().unregisterReceiver(mIntentReceiver); - } - } - - public DcFailBringUp getDcFailBringUp() { - return mFailBringUp; - } - - private void log(String s) { - Rlog.d(LOG_TAG, s); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java deleted file mode 100755 index 28f69dcdc9..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java +++ /dev/null @@ -1,5665 +0,0 @@ -/* - * Copyright (C) 2006 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.dataconnection; - -import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; -import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED; -import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED; -import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; -import static android.telephony.TelephonyManager.NETWORK_TYPE_NR; -import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_DO_FALLBACK; -import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY; -import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL; - -import static com.android.internal.telephony.RILConstants.DATA_PROFILE_DEFAULT; -import static com.android.internal.telephony.RILConstants.DATA_PROFILE_INVALID; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.AlarmManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.ProgressDialog; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.database.ContentObserver; -import android.database.Cursor; -import android.net.ConnectivityManager; -import android.net.LinkProperties; -import android.net.NetworkAgent; -import android.net.NetworkCapabilities; -import android.net.NetworkPolicyManager; -import android.net.NetworkRequest; -import android.net.TrafficStats; -import android.net.Uri; -import android.os.AsyncResult; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Message; -import android.os.PersistableBundle; -import android.os.RegistrantList; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.preference.PreferenceManager; -import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; -import android.provider.Telephony; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.TransportType; -import android.telephony.Annotation.ApnType; -import android.telephony.Annotation.DataFailureCause; -import android.telephony.Annotation.NetworkType; -import android.telephony.CarrierConfigManager; -import android.telephony.CellLocation; -import android.telephony.DataFailCause; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.PcoData; -import android.telephony.PreciseDataConnectionState; -import android.telephony.ServiceState; -import android.telephony.ServiceState.RilRadioTechnology; -import android.telephony.SubscriptionManager; -import android.telephony.SubscriptionPlan; -import android.telephony.TelephonyDisplayInfo; -import android.telephony.TelephonyFrameworkInitializer; -import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.SimState; -import android.telephony.cdma.CdmaCellLocation; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.telephony.data.DataCallResponse.HandoverFailureMode; -import android.telephony.data.DataProfile; -import android.telephony.data.ThrottleStatus; -import android.telephony.gsm.GsmCellLocation; -import android.text.TextUtils; -import android.util.EventLog; -import android.util.LocalLog; -import android.util.Log; -import android.util.Pair; -import android.util.SparseArray; -import android.view.WindowManager; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.EventLogTags; -import com.android.internal.telephony.GsmCdmaPhone; -import com.android.internal.telephony.ITelephony; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.SettingsObserver; -import com.android.internal.telephony.SubscriptionInfoUpdater; -import com.android.internal.telephony.data.DataConfigManager; -import com.android.internal.telephony.data.PhoneSwitcher; -import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataAllowedReasonType; -import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType; -import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason; -import com.android.internal.telephony.metrics.DataStallRecoveryStats; -import com.android.internal.telephony.metrics.TelephonyMetrics; -import com.android.internal.telephony.util.ArrayUtils; -import com.android.internal.telephony.util.NotificationChannelController; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.internal.util.AsyncChannel; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -/** - * {@hide} - */ -public class DcTracker extends Handler { - protected static final boolean DBG = true; - private static final boolean VDBG = false; // STOPSHIP if true - private static final boolean VDBG_STALL = false; // STOPSHIP if true - private static final boolean RADIO_TESTS = false; - private static final String NOTIFICATION_TAG = DcTracker.class.getSimpleName(); - - @IntDef(value = { - REQUEST_TYPE_NORMAL, - REQUEST_TYPE_HANDOVER, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface RequestNetworkType {} - - /** - * Normal request for {@link #requestNetwork(NetworkRequest, int, Message)}. For request - * network, this adds the request to the {@link ApnContext}. If there were no network request - * attached to the {@link ApnContext} earlier, this request setups a data connection. - */ - public static final int REQUEST_TYPE_NORMAL = 1; - - /** - * Handover request for {@link #requestNetwork(NetworkRequest, int, Message)} or - * {@link #releaseNetwork(NetworkRequest, int)}. For request network, this - * initiates the handover data setup process. The existing data connection will be seamlessly - * handover to the new network. For release network, this performs a data connection softly - * clean up at the underlying layer (versus normal data release). - */ - public static final int REQUEST_TYPE_HANDOVER = 2; - - @IntDef(value = { - RELEASE_TYPE_NORMAL, - RELEASE_TYPE_DETACH, - RELEASE_TYPE_HANDOVER, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ReleaseNetworkType {} - - /** - * For release network, this is just removing the network request from the {@link ApnContext}. - * Note this does not tear down the physical data connection. Normally the data connection is - * torn down by connectivity service directly calling {@link NetworkAgent#unwanted()}. - */ - public static final int RELEASE_TYPE_NORMAL = 1; - - /** - * Detach request for {@link #releaseNetwork(NetworkRequest, int)} only. This - * forces the APN context detach from the data connection. If this {@link ApnContext} is the - * last one attached to the data connection, the data connection will be torn down, otherwise - * the data connection remains active. - */ - public static final int RELEASE_TYPE_DETACH = 2; - - /** - * Handover request for {@link #releaseNetwork(NetworkRequest, int)}. For release - * network, this performs a data connection softly clean up at the underlying layer (versus - * normal data release). - */ - public static final int RELEASE_TYPE_HANDOVER = 3; - - /** The extras for handover completion message */ - public static final String DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST = "extra_network_request"; - public static final String DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE = "extra_transport_type"; - public static final String DATA_COMPLETE_MSG_EXTRA_SUCCESS = "extra_success"; - /** - * The flag indicates whether after handover failure, the data connection should remain on the - * original transport. - */ - public static final String DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK = - "extra_handover_failure_fallback"; - - private final String mLogTag; - - public AtomicBoolean isCleanupRequired = new AtomicBoolean(false); - - private final TelephonyManager mTelephonyManager; - - private final AlarmManager mAlarmManager; - - /* Currently requested APN type (TODO: This should probably be a parameter not a member) */ - private int mRequestedApnType = ApnSetting.TYPE_DEFAULT; - - // All data enabling/disabling related settings - private final DataEnabledSettings mDataEnabledSettings; - - /** - * After detecting a potential connection problem, this is the max number - * of subsequent polls before attempting recovery. - */ - // 1 sec. default polling interval when screen is on. - private static final int POLL_NETSTAT_MILLIS = 1000; - // 10 min. default polling interval when screen is off. - private static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; - // Default sent packets without ack which triggers initial recovery steps - private static final int NUMBER_SENT_PACKETS_OF_HANG = 10; - - // Default for the data stall alarm while non-aggressive stall detection - private static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6; - // Default for the data stall alarm for aggressive stall detection - private static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60; - - private static final boolean DATA_STALL_SUSPECTED = true; - protected static final boolean DATA_STALL_NOT_SUSPECTED = false; - - private static final String INTENT_DATA_STALL_ALARM = - "com.android.internal.telephony.data-stall"; - // Tag for tracking stale alarms - private static final String INTENT_DATA_STALL_ALARM_EXTRA_TAG = "data_stall_alarm_extra_tag"; - private static final String INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE = - "data_stall_alarm_extra_transport_type"; - - // Unique id for no data notification on setup data permanently failed. - private static final int NO_DATA_NOTIFICATION = 1001; - - /** The higher index has higher priority. */ - private static final DctConstants.State[] DATA_CONNECTION_STATE_PRIORITIES = { - DctConstants.State.IDLE, - DctConstants.State.DISCONNECTING, - DctConstants.State.CONNECTING, - DctConstants.State.CONNECTED, - }; - - private DcTesterFailBringUpAll mDcTesterFailBringUpAll; - private DcController mDcc; - - /** kept in sync with mApnContexts - * Higher numbers are higher priority and sorted so highest priority is first */ - private ArrayList mPrioritySortedApnContexts = new ArrayList<>(); - - /** all APN settings applicable to the current carrier */ - private ArrayList mAllApnSettings = new ArrayList<>(); - - /** preferred apn */ - private ApnSetting mPreferredApn = null; - - /** Is packet service restricted by network */ - private boolean mIsPsRestricted = false; - - /** emergency apn Setting*/ - private ApnSetting mEmergencyApn = null; - - /* Once disposed dont handle any messages */ - private boolean mIsDisposed = false; - - private ContentResolver mResolver; - - /* Set to true with CMD_ENABLE_MOBILE_PROVISIONING */ - private boolean mIsProvisioning = false; - - /* The Url passed as object parameter in CMD_ENABLE_MOBILE_PROVISIONING */ - private String mProvisioningUrl = null; - - /* Indicating data service is bound or not */ - private boolean mDataServiceBound = false; - - /* Intent to hide/show the sign-in error notification for provisioning */ - private static final String INTENT_PROVISION = "com.android.internal.telephony.PROVISION"; - - /** - * Extra containing the phone ID for INTENT_PROVISION - * Must be kept consistent with NetworkNotificationManager#setProvNotificationVisible. - * TODO: refactor the deprecated API to prevent hardcoding values. - */ - private static final String EXTRA_PROVISION_PHONE_ID = "provision.phone.id"; - - /* Intent for the provisioning apn alarm */ - private static final String INTENT_PROVISIONING_APN_ALARM = - "com.android.internal.telephony.provisioning_apn_alarm"; - - /* Tag for tracking stale alarms */ - private static final String PROVISIONING_APN_ALARM_TAG_EXTRA = "provisioning.apn.alarm.tag"; - - /* Debug property for overriding the PROVISIONING_APN_ALARM_DELAY_IN_MS */ - private static final String DEBUG_PROV_APN_ALARM = "persist.debug.prov_apn_alarm"; - - /* Default for the provisioning apn alarm timeout */ - private static final int PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT = 1000 * 60 * 15; - - /* The provision apn alarm intent used to disable the provisioning apn */ - private PendingIntent mProvisioningApnAlarmIntent = null; - - /* Used to track stale provisioning apn alarms */ - private int mProvisioningApnAlarmTag = (int) SystemClock.elapsedRealtime(); - - private AsyncChannel mReplyAc = new AsyncChannel(); - - private final LocalLog mDataRoamingLeakageLog = new LocalLog(32); - private final LocalLog mApnSettingsInitializationLog = new LocalLog(32); - - /* 5G connection reevaluation watchdog alarm constants */ - private long mWatchdogTimeMs = 1000 * 60 * 60; - private boolean mWatchdog = false; - - /* Default for whether 5G frequencies are considered unmetered */ - private boolean mNrNsaAllUnmetered = false; - private boolean mNrNsaMmwaveUnmetered = false; - private boolean mNrNsaSub6Unmetered = false; - private boolean mNrSaAllUnmetered = false; - private boolean mNrSaMmwaveUnmetered = false; - private boolean mNrSaSub6Unmetered = false; - private boolean mNrNsaRoamingUnmetered = false; - - // it effect the PhysicalLinkStatusChanged - private boolean mLteEndcUsingUserDataForRrcDetection = false; - - /* List of SubscriptionPlans, updated when initialized and when plans are changed. */ - private List mSubscriptionPlans = new ArrayList<>(); - /* List of network types an unmetered override applies to, set by onSubscriptionOverride - * and cleared when the device is rebooted or the override expires. */ - private List mUnmeteredNetworkTypes = null; - /* List of network types a congested override applies to, set by onSubscriptionOverride - * and cleared when the device is rebooted or the override expires. */ - private List mCongestedNetworkTypes = null; - /* Whether an unmetered override is currently active. */ - private boolean mUnmeteredOverride = false; - /* Whether a congested override is currently active. */ - private boolean mCongestedOverride = false; - - @SimState - private int mSimState = TelephonyManager.SIM_STATE_UNKNOWN; - - private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver () { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if (action.equals(Intent.ACTION_SCREEN_ON)) { - // TODO: Evaluate hooking this up with DeviceStateMonitor - if (DBG) log("screen on"); - mIsScreenOn = true; - stopNetStatPoll(); - startNetStatPoll(); - restartDataStallAlarm(); - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - if (DBG) log("screen off"); - mIsScreenOn = false; - stopNetStatPoll(); - startNetStatPoll(); - restartDataStallAlarm(); - } else if (action.equals(INTENT_DATA_STALL_ALARM)) { - onActionIntentDataStallAlarm(intent); - } else if (action.equals(INTENT_PROVISIONING_APN_ALARM)) { - if (DBG) log("Provisioning apn alarm"); - onActionIntentProvisioningApnAlarm(intent); - } else if (action.equals(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED) - || action.equals(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)) { - if (mPhone.getPhoneId() == intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { - int simState = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE, - TelephonyManager.SIM_STATE_UNKNOWN); - sendMessage(obtainMessage(DctConstants.EVENT_SIM_STATE_UPDATED, simState, 0)); - } - } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - if (mPhone.getPhoneId() == intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { - if (intent.getBooleanExtra( - CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, false)) { - // Ignore the rebroadcast one to prevent multiple carrier config changed - // event during boot up. - return; - } - int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (SubscriptionManager.isValidSubscriptionId(subId)) { - sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); - } - } - } else { - if (DBG) log("onReceive: Unknown action=" + action); - } - } - }; - - private final Runnable mPollNetStat = new Runnable() { - @Override - public void run() { - updateDataActivity(); - - if (mIsScreenOn) { - mNetStatPollPeriod = Settings.Global.getInt(mResolver, - Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); - } else { - mNetStatPollPeriod = Settings.Global.getInt(mResolver, - Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, - POLL_NETSTAT_SCREEN_OFF_MILLIS); - } - - if (mNetStatPollEnabled) { - mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod); - } - } - }; - - private class ThrottleStatusChangedCallback implements DataThrottler.Callback { - @Override - public void onThrottleStatusChanged(List throttleStatuses) { - for (ThrottleStatus status : throttleStatuses) { - if (status.getThrottleType() == ThrottleStatus.THROTTLE_TYPE_NONE) { - setupDataOnConnectableApn(mApnContextsByType.get(status.getApnType()), - Phone.REASON_DATA_UNTHROTTLED, - RetryFailures.ALWAYS); - } - } - } - } - - private NetworkPolicyManager mNetworkPolicyManager; - private final NetworkPolicyManager.SubscriptionCallback mSubscriptionCallback = - new NetworkPolicyManager.SubscriptionCallback() { - @Override - public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, - int[] networkTypes) { - if (mPhone == null || mPhone.getSubId() != subId) return; - - List tempList = new ArrayList<>(); - for (int networkType : networkTypes) { - tempList.add(networkType); - } - - log("Subscription override: overrideMask=" + overrideMask - + ", overrideValue=" + overrideValue + ", networkTypes=" + tempList); - - if (overrideMask == SUBSCRIPTION_OVERRIDE_UNMETERED) { - mUnmeteredNetworkTypes = tempList; - mUnmeteredOverride = overrideValue != 0; - reevaluateUnmeteredConnections(); - } else if (overrideMask == SUBSCRIPTION_OVERRIDE_CONGESTED) { - mCongestedNetworkTypes = tempList; - mCongestedOverride = overrideValue != 0; - reevaluateCongestedConnections(); - } - } - - @Override - public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { - if (mPhone == null || mPhone.getSubId() != subId) return; - - mSubscriptionPlans = Arrays.asList(plans); - if (DBG) log("SubscriptionPlans changed: " + mSubscriptionPlans); - reevaluateUnmeteredConnections(); - } - }; - - private final SettingsObserver mSettingsObserver; - - private void registerSettingsObserver() { - mSettingsObserver.unobserve(); - String simSuffix = ""; - if (TelephonyManager.getDefault().getSimCount() > 1) { - simSuffix = Integer.toString(mPhone.getSubId()); - } - - mSettingsObserver.observe( - Settings.Global.getUriFor(Settings.Global.DATA_ROAMING + simSuffix), - DctConstants.EVENT_ROAMING_SETTING_CHANGE); - mSettingsObserver.observe( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), - DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE); - } - - /** - * Maintain the sum of transmit and receive packets. - * - * The packet counts are initialized and reset to -1 and - * remain -1 until they can be updated. - */ - public static class TxRxSum { - public long txPkts; - public long rxPkts; - - public TxRxSum() { - reset(); - } - - public TxRxSum(long txPkts, long rxPkts) { - this.txPkts = txPkts; - this.rxPkts = rxPkts; - } - - public TxRxSum(TxRxSum sum) { - txPkts = sum.txPkts; - rxPkts = sum.rxPkts; - } - - public void reset() { - txPkts = -1; - rxPkts = -1; - } - - @Override - public String toString() { - return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}"; - } - - /** - * Get total Tx/Rx packet count from TrafficStats - */ - public void updateTotalTxRxSum() { - this.txPkts = TrafficStats.getMobileTxPackets(); - this.rxPkts = TrafficStats.getMobileRxPackets(); - } - } - - private void onDataReconnect(ApnContext apnContextforRetry, int subId, - @RequestNetworkType int requestType) { - int phoneSubId = mPhone.getSubId(); - String apnType = apnContextforRetry.getApnType(); - String reason = apnContextforRetry.getReason(); - - if (!SubscriptionManager.isValidSubscriptionId(subId) || (subId != phoneSubId)) { - log("onDataReconnect: invalid subId"); - return; - } - - ApnContext apnContext = mApnContexts.get(apnType); - - if (DBG) { - log("onDataReconnect: mState=" + mState + " reason=" + reason + " apnType=" + apnType - + " apnContext=" + apnContext); - } - - if ((apnContext != null) && (apnContext.isEnabled())) { - apnContext.setReason(reason); - DctConstants.State apnContextState = apnContext.getState(); - if (DBG) { - log("onDataReconnect: apnContext state=" + apnContextState); - } - if ((apnContextState == DctConstants.State.FAILED) - || (apnContextState == DctConstants.State.IDLE)) { - if (DBG) { - log("onDataReconnect: state is FAILED|IDLE, disassociate"); - } - apnContext.releaseDataConnection(""); - } else { - if (DBG) log("onDataReconnect: keep associated"); - } - // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA??? - sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, requestType, - 0, apnContext)); - } - } - - private void onActionIntentDataStallAlarm(Intent intent) { - if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction()); - - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (!SubscriptionManager.isValidSubscriptionId(subId) || (subId != mPhone.getSubId())) { - return; - } - - int transportType = intent.getIntExtra(INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE, 0); - if (transportType != mTransportType) { - return; - } - - Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM, - intent.getAction()); - msg.arg1 = intent.getIntExtra(INTENT_DATA_STALL_ALARM_EXTRA_TAG, 0); - sendMessage(msg); - } - - private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList(); - - // member variables - protected final Phone mPhone; - private DctConstants.Activity mActivity = DctConstants.Activity.NONE; - private DctConstants.State mState = DctConstants.State.IDLE; - private final Handler mDataConnectionTracker; - - private long mTxPkts; - private long mRxPkts; - private int mNetStatPollPeriod; - private boolean mNetStatPollEnabled = false; - - private TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0); - // Used to track stale data stall alarms. - private int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime(); - // The current data stall alarm intent - private PendingIntent mDataStallAlarmIntent = null; - // Number of packets sent since the last received packet - private long mSentSinceLastRecv; - // Controls when a simple recovery attempt it to be tried - private int mNoRecvPollCount = 0; - // Reference counter for enabling fail fast - private static int sEnableFailFastRefCounter = 0; - // True if data stall detection is enabled - private volatile boolean mDataStallNoRxEnabled = true; - - protected volatile boolean mFailFast = false; - - // True when in voice call - protected boolean mInVoiceCall = false; - - /** Intent sent when the reconnect alarm fires. */ - private PendingIntent mReconnectIntent = null; - - // When false we will not auto attach and manually attaching is required. - protected boolean mAutoAttachOnCreationConfig = false; - private AtomicBoolean mAutoAttachEnabled = new AtomicBoolean(false); - - // State of screen - // (TODO: Reconsider tying directly to screen, maybe this is - // really a lower power mode") - private boolean mIsScreenOn = true; - - /** Allows the generation of unique Id's for DataConnection objects */ - private AtomicInteger mUniqueIdGenerator = new AtomicInteger(0); - - /** The data connections. */ - private HashMap mDataConnections = - new HashMap(); - - /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */ - private HashMap mApnToDataConnectionId = new HashMap(); - - /** Phone.APN_TYPE_* ===> ApnContext */ - protected ConcurrentHashMap mApnContexts = - new ConcurrentHashMap(); - - private SparseArray mApnContextsByType = new SparseArray(); - - private ArrayList mLastDataProfileList = new ArrayList<>(); - - /** RAT name ===> (downstream, upstream) bandwidth values from carrier config. */ - private ConcurrentHashMap> mBandwidths = - new ConcurrentHashMap<>(); - - private boolean mConfigReady = false; - - /** - * Handles changes to the APN db. - */ - private class ApnChangeObserver extends ContentObserver { - public ApnChangeObserver () { - super(mDataConnectionTracker); - } - - @Override - public void onChange(boolean selfChange) { - sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED)); - } - } - - //***** Instance Variables - - private boolean mReregisterOnReconnectFailure = false; - - - //***** Constants - - private static final int PROVISIONING_SPINNER_TIMEOUT_MILLIS = 120 * 1000; - - static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID = - Uri.parse("content://telephony/carriers/preferapn_no_update/subId/"); - static final String APN_ID = "apn_id"; - - private boolean mCanSetPreferApn = false; - - private AtomicBoolean mAttached = new AtomicBoolean(false); - - /** Watches for changes to the APN db. */ - private ApnChangeObserver mApnObserver; - - private BroadcastReceiver mProvisionBroadcastReceiver; - private ProgressDialog mProvisioningSpinner; - - private final DataServiceManager mDataServiceManager; - - @AccessNetworkConstants.TransportType - private final int mTransportType; - - private DataStallRecoveryHandler mDsRecoveryHandler; - private HandlerThread mHandlerThread; - - private final DataThrottler mDataThrottler; - - private final ThrottleStatusChangedCallback mThrottleStatusCallback; - - /** - * Request network completion message map. Key is the APN type, value is the list of completion - * messages to be sent. Using a list because there might be multiple network requests for - * the same APN type. - */ - private final Map> mHandoverCompletionMsgs = new HashMap<>(); - - //***** Constructor - public DcTracker(Phone phone, @TransportType int transportType) { - super(); - mPhone = phone; - if (DBG) log("DCT.constructor"); - mTelephonyManager = TelephonyManager.from(phone.getContext()) - .createForSubscriptionId(phone.getSubId()); - // The 'C' in tag indicates cellular, and 'I' indicates IWLAN. This is to distinguish - // between two DcTrackers, one for each. - String tagSuffix = "-" + ((transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - ? "C" : "I"); - tagSuffix += "-" + mPhone.getPhoneId(); - mLogTag = "DCT" + tagSuffix; - - mTransportType = transportType; - mDataServiceManager = new DataServiceManager(phone, transportType, tagSuffix); - mDataThrottler = new DataThrottler(mPhone, transportType); - - mResolver = mPhone.getContext().getContentResolver(); - mAlarmManager = - (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); - - mDsRecoveryHandler = new DataStallRecoveryHandler(); - - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(INTENT_DATA_STALL_ALARM); - filter.addAction(INTENT_PROVISIONING_APN_ALARM); - filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - filter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); - filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); - - mDataEnabledSettings = mPhone.getDataEnabledSettings(); - - mDataEnabledSettings.registerForDataEnabledChanged(this, - DctConstants.EVENT_DATA_ENABLED_CHANGED, null); - mDataEnabledSettings.registerForDataEnabledOverrideChanged(this, - DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED); - - mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); - - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); - mAutoAttachEnabled.set(sp.getBoolean(Phone.DATA_DISABLED_ON_BOOT_KEY, false)); - - mNetworkPolicyManager = (NetworkPolicyManager) mPhone.getContext() - .getSystemService(Context.NETWORK_POLICY_SERVICE); - mNetworkPolicyManager.registerSubscriptionCallback(mSubscriptionCallback); - - mHandlerThread = new HandlerThread("DcHandlerThread"); - mHandlerThread.start(); - Handler dcHandler = new Handler(mHandlerThread.getLooper()); - mDcc = DcController.makeDcc(mPhone, this, mDataServiceManager, dcHandler.getLooper(), - tagSuffix); - mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler); - - mDataConnectionTracker = this; - registerForAllEvents(); - mApnObserver = new ApnChangeObserver(); - phone.getContext().getContentResolver().registerContentObserver( - Telephony.Carriers.CONTENT_URI, true, mApnObserver); - - initApnContexts(); - - addDefaultApnSettingsAsNeeded(); - - mSettingsObserver = new SettingsObserver(mPhone.getContext(), this); - registerSettingsObserver(); - - mThrottleStatusCallback = new ThrottleStatusChangedCallback(); - mDataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback); - } - - @VisibleForTesting - public DcTracker() { - mLogTag = "DCT"; - mTelephonyManager = null; - mAlarmManager = null; - mPhone = null; - mDataConnectionTracker = null; - mSettingsObserver = new SettingsObserver(null, this); - mDataEnabledSettings = null; - mTransportType = 0; - mDataServiceManager = null; - mDataThrottler = null; - mThrottleStatusCallback = null; - } - - public void registerServiceStateTrackerEvents() { - mPhone.getServiceStateTracker().registerForDataConnectionAttached(mTransportType, this, - DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null); - mPhone.getServiceStateTracker().registerForDataConnectionDetached(mTransportType, this, - DctConstants.EVENT_DATA_CONNECTION_DETACHED, null); - mPhone.getServiceStateTracker().registerForDataRoamingOn(this, - DctConstants.EVENT_ROAMING_ON, null); - mPhone.getServiceStateTracker().registerForDataRoamingOff(this, - DctConstants.EVENT_ROAMING_OFF, null, true); - mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this, - DctConstants.EVENT_PS_RESTRICT_ENABLED, null); - mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this, - DctConstants.EVENT_PS_RESTRICT_DISABLED, null); - mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(mTransportType, this, - DctConstants.EVENT_DATA_RAT_CHANGED, null); - } - - public void unregisterServiceStateTrackerEvents() { - mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(mTransportType, this); - mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(mTransportType, this); - mPhone.getServiceStateTracker().unregisterForDataRoamingOn(this); - mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this); - mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this); - mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this); - mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(mTransportType, this); - mPhone.getServiceStateTracker().unregisterForAirplaneModeChanged(this); - } - - private void registerForAllEvents() { - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null); - mPhone.mCi.registerForOffOrNotAvailable(this, - DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - mPhone.mCi.registerForPcoData(this, DctConstants.EVENT_PCO_DATA_RECEIVED, null); - } - - // Note, this is fragile - the Phone is now presenting a merged picture - // of PS (volte) & CS and by diving into its internals you're just seeing - // the CS data. This works well for the purposes this is currently used for - // but that may not always be the case. Should probably be redesigned to - // accurately reflect what we're really interested in (registerForCSVoiceCallEnded). - mPhone.getCallTracker().registerForVoiceCallEnded(this, - DctConstants.EVENT_VOICE_CALL_ENDED, null); - mPhone.getCallTracker().registerForVoiceCallStarted(this, - DctConstants.EVENT_VOICE_CALL_STARTED, null); - mPhone.getDisplayInfoController().registerForTelephonyDisplayInfoChanged(this, - DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED, null); - registerServiceStateTrackerEvents(); - mDataServiceManager.registerForServiceBindingChanged(this, - DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED, null); - mDataServiceManager.registerForApnUnthrottled(this, DctConstants.EVENT_APN_UNTHROTTLED); - } - - public void dispose() { - if (DBG) log("DCT.dispose"); - - if (mProvisionBroadcastReceiver != null) { - mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); - mProvisionBroadcastReceiver = null; - } - if (mProvisioningSpinner != null) { - mProvisioningSpinner.dismiss(); - mProvisioningSpinner = null; - } - - cleanUpAllConnectionsInternal(true, null); - - mIsDisposed = true; - mPhone.getContext().unregisterReceiver(mIntentReceiver); - mSettingsObserver.unobserve(); - - mNetworkPolicyManager.unregisterSubscriptionCallback(mSubscriptionCallback); - mDcTesterFailBringUpAll.dispose(); - - mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver); - mApnContexts.clear(); - mApnContextsByType.clear(); - mPrioritySortedApnContexts.clear(); - unregisterForAllEvents(); - - destroyDataConnections(); - } - - /** - * Stop the internal handler thread - * - * TESTING ONLY - */ - @VisibleForTesting - public void stopHandlerThread() { - mHandlerThread.quit(); - } - - private void unregisterForAllEvents() { - //Unregister for all events - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - mPhone.mCi.unregisterForAvailable(this); - mPhone.mCi.unregisterForOffOrNotAvailable(this); - mPhone.mCi.unregisterForPcoData(this); - } - - mPhone.getCallTracker().unregisterForVoiceCallEnded(this); - mPhone.getCallTracker().unregisterForVoiceCallStarted(this); - mPhone.getDisplayInfoController().unregisterForTelephonyDisplayInfoChanged(this); - unregisterServiceStateTrackerEvents(); - mDataServiceManager.unregisterForServiceBindingChanged(this); - mDataEnabledSettings.unregisterForDataEnabledChanged(this); - mDataEnabledSettings.unregisterForDataEnabledOverrideChanged(this); - mDataServiceManager.unregisterForApnUnthrottled(this); - } - - /** - * Reevaluate existing data connections when conditions change. - * - * For example, handle reverting restricted networks back to unrestricted. If we're changing - * user data to enabled and this makes data truly enabled (not disabled by other factors) we - * need to reevaluate and possibly add NET_CAPABILITY_NOT_RESTRICTED capability to the data - * connection. This allows non-privilege apps to use the network. - * - * Or when we brought up a unmetered data connection while data is off, we only limit this - * data connection for unmetered use only. When data is turned back on, we need to tear that - * down so a full capable data connection can be re-established. - */ - private void reevaluateDataConnections() { - for (DataConnection dataConnection : mDataConnections.values()) { - dataConnection.reevaluateRestrictedState(); - } - } - - public long getSubId() { - return mPhone.getSubId(); - } - - public DctConstants.Activity getActivity() { - return mActivity; - } - - private void setActivity(DctConstants.Activity activity) { - log("setActivity = " + activity); - mActivity = activity; - mPhone.notifyDataActivity(); - } - - /** - * Request a network - * - * @param networkRequest Network request from clients - * @param type The request type - * @param onHandoverCompleteMsg When request type is handover, this message will be sent when - * handover is completed. For normal request, this should be null. - */ - public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type, - Message onHandoverCompleteMsg) { - if (type != REQUEST_TYPE_HANDOVER && onHandoverCompleteMsg != null) { - throw new RuntimeException("request network with normal type request type but passing " - + "handover complete message."); - } - final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest); - final ApnContext apnContext = mApnContextsByType.get(apnType); - if (apnContext != null) { - apnContext.requestNetwork(networkRequest, type, onHandoverCompleteMsg); - } - } - - public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type) { - final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest); - final ApnContext apnContext = mApnContextsByType.get(apnType); - if (apnContext != null) { - apnContext.releaseNetwork(networkRequest, type); - } - } - - // Turn telephony radio on or off. - private void setRadio(boolean on) { - final ITelephony phone = ITelephony.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getTelephonyServiceRegisterer() - .get()); - try { - phone.setRadio(on); - } catch (Exception e) { - // Ignore. - } - } - - // Class to handle Intent dispatched with user selects the "Sign-in to network" - // notification. - private class ProvisionNotificationBroadcastReceiver extends BroadcastReceiver { - private final String mNetworkOperator; - // Mobile provisioning URL. Valid while provisioning notification is up. - // Set prior to notification being posted as URL contains ICCID which - // disappears when radio is off (which is the case when notification is up). - private final String mProvisionUrl; - - public ProvisionNotificationBroadcastReceiver(String provisionUrl, String networkOperator) { - mNetworkOperator = networkOperator; - mProvisionUrl = provisionUrl; - } - - private void setEnableFailFastMobileData(int enabled) { - sendMessage(obtainMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled, 0)); - } - - private void enableMobileProvisioning() { - final Message msg = obtainMessage(DctConstants.CMD_ENABLE_MOBILE_PROVISIONING); - Bundle bundle = new Bundle(1); - bundle.putString(DctConstants.PROVISIONING_URL_KEY, mProvisionUrl); - msg.setData(bundle); - sendMessage(msg); - } - - @Override - public void onReceive(Context context, Intent intent) { - if (mPhone.getPhoneId() != intent.getIntExtra(EXTRA_PROVISION_PHONE_ID, - SubscriptionManager.INVALID_PHONE_INDEX)) { - return; - } - // Turning back on the radio can take time on the order of a minute, so show user a - // spinner so they know something is going on. - log("onReceive : ProvisionNotificationBroadcastReceiver"); - mProvisioningSpinner = new ProgressDialog(context); - mProvisioningSpinner.setTitle(mNetworkOperator); - mProvisioningSpinner.setMessage( - // TODO: Don't borrow "Connecting..." i18n string; give Telephony a version. - context.getText(com.android.internal.R.string.media_route_status_connecting)); - mProvisioningSpinner.setIndeterminate(true); - mProvisioningSpinner.setCancelable(true); - // Allow non-Activity Service Context to create a View. - mProvisioningSpinner.getWindow().setType( - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); - mProvisioningSpinner.show(); - // After timeout, hide spinner so user can at least use their device. - // TODO: Indicate to user that it is taking an unusually long time to connect? - sendMessageDelayed(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, - mProvisioningSpinner), PROVISIONING_SPINNER_TIMEOUT_MILLIS); - // This code is almost identical to the old - // ConnectivityService.handleMobileProvisioningAction code. - setRadio(true); - setEnableFailFastMobileData(DctConstants.ENABLED); - enableMobileProvisioning(); - } - } - - @Override - protected void finalize() { - if(DBG && mPhone != null) log("finalize"); - } - - private void initApnContexts() { - PersistableBundle carrierConfig; - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - carrierConfig = configManager.getConfigForSubId(mPhone.getSubId()); - } else { - carrierConfig = null; - } - initApnContexts(carrierConfig); - } - - //Blows away any existing apncontexts that may exist, only use in ctor. - private void initApnContexts(PersistableBundle carrierConfig) { - if (!mTelephonyManager.isDataCapable()) { - log("initApnContexts: isDataCapable == false. No Apn Contexts loaded"); - return; - } - - log("initApnContexts: E"); - // Load device network attributes from resources - final Collection types = - new ApnConfigTypeRepository(carrierConfig).getTypes(); - - for (ApnConfigType apnConfigType : types) { - ApnContext apnContext = new ApnContext(mPhone, apnConfigType.getType(), mLogTag, this, - apnConfigType.getPriority()); - int bitmask = ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType()); - mPrioritySortedApnContexts.add(apnContext); - mApnContexts.put(apnContext.getApnType(), apnContext); - mApnContextsByType.put(bitmask, apnContext); - // Notify listeners that all data is disconnected when DCT is initialized. - // Once connections are established, DC will then notify that data is connected. - // This is to prevent the case where the phone process crashed but we don't notify - // listeners that data was disconnected, so they may be stuck in a connected state. - mPhone.notifyDataConnection(new PreciseDataConnectionState.Builder() - .setTransportType(mTransportType) - .setState(TelephonyManager.DATA_DISCONNECTED) - .setApnSetting(new ApnSetting.Builder() - .setApnTypeBitmask(bitmask).buildWithoutCheck()) - .setNetworkType(getDataRat()) - .build()); - log("initApnContexts: apnContext=" + ApnSetting.getApnTypeString( - apnConfigType.getType())); - } - mPrioritySortedApnContexts.sort((c1, c2) -> c2.getPriority() - c1.getPriority()); - logSortedApnContexts(); - } - - private void sortApnContextByPriority() { - if (!mTelephonyManager.isDataCapable()) { - log("sortApnContextByPriority: isDataCapable == false. No Apn Contexts loaded"); - return; - } - - PersistableBundle carrierConfig; - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - carrierConfig = configManager.getConfigForSubId(mPhone.getSubId()); - } else { - carrierConfig = null; - } - - log("sortApnContextByPriority: E"); - // Load device network attributes from resources - final Collection types = - new ApnConfigTypeRepository(carrierConfig).getTypes(); - for (ApnConfigType apnConfigType : types) { - if (mApnContextsByType.contains(apnConfigType.getType())) { - ApnContext apnContext = mApnContextsByType.get(apnConfigType.getType()); - apnContext.setPriority(apnConfigType.getPriority()); - } - } - - //Doing sorted in a different list to keep thread safety - ArrayList prioritySortedApnContexts = - new ArrayList<>(mPrioritySortedApnContexts); - prioritySortedApnContexts.sort((c1, c2) -> c2.getPriority() - c1.getPriority()); - mPrioritySortedApnContexts = prioritySortedApnContexts; - logSortedApnContexts(); - } - - public LinkProperties getLinkProperties(String apnType) { - ApnContext apnContext = mApnContexts.get(apnType); - if (apnContext != null) { - DataConnection dataConnection = apnContext.getDataConnection(); - if (dataConnection != null) { - if (DBG) log("return link properties for " + apnType); - return dataConnection.getLinkProperties(); - } - } - if (DBG) log("return new LinkProperties"); - return new LinkProperties(); - } - - public NetworkCapabilities getNetworkCapabilities(String apnType) { - ApnContext apnContext = mApnContexts.get(apnType); - if (apnContext!=null) { - DataConnection dataConnection = apnContext.getDataConnection(); - if (dataConnection != null) { - if (DBG) { - log("get active pdp is not null, return NetworkCapabilities for " + apnType); - } - return dataConnection.getNetworkCapabilities(); - } - } - if (DBG) log("return new NetworkCapabilities"); - return new NetworkCapabilities(); - } - - // Return all active apn types - public String[] getActiveApnTypes() { - if (DBG) log("get all active apn types"); - ArrayList result = new ArrayList(); - - for (ApnContext apnContext : mApnContexts.values()) { - if (mAttached.get() && apnContext.isReady()) { - result.add(apnContext.getApnType()); - } - } - - return result.toArray(new String[0]); - } - - /** - * Get ApnTypes with connected data connections. This is different than getActiveApnTypes() - * which returns apn types that with active apn contexts. - * @return apn types - */ - public String[] getConnectedApnTypes() { - return mApnContexts.values().stream() - .filter(ac -> ac.getState() == DctConstants.State.CONNECTED) - .map(ApnContext::getApnType) - .toArray(String[]::new); - } - - @VisibleForTesting - public Collection getApnContexts() { - return mPrioritySortedApnContexts; - } - - /** Return active ApnSetting of a specific apnType */ - public ApnSetting getActiveApnSetting(String apnType) { - if (VDBG) log("get active ApnSetting for type:" + apnType); - ApnContext apnContext = mApnContexts.get(apnType); - return (apnContext != null) ? apnContext.getApnSetting() : null; - } - - // Return active apn of specific apn type - public String getActiveApnString(String apnType) { - if (VDBG) log( "get active apn string for type:" + apnType); - ApnSetting setting = getActiveApnSetting(apnType); - return (setting != null) ? setting.getApnName() : null; - } - - /** - * Returns {@link DctConstants.State} based on the state of the {@link DataConnection} that - * contains a {@link ApnSetting} that supported the given apn type {@code anpType}. - * - *

- * Assumes there is less than one {@link ApnSetting} can support the given apn type. - */ - // TODO: for enterprise this always returns IDLE, which is ok for now since it is never called - // for enterprise - public DctConstants.State getState(String apnType) { - DctConstants.State state = DctConstants.State.IDLE; - final int apnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(apnType); - for (DataConnection dc : mDataConnections.values()) { - ApnSetting apnSetting = dc.getApnSetting(); - if (apnSetting != null && apnSetting.canHandleType(apnTypeBitmask)) { - if (dc.isActive()) { - state = getBetterConnectionState(state, DctConstants.State.CONNECTED); - } else if (dc.isActivating()) { - state = getBetterConnectionState(state, DctConstants.State.CONNECTING); - } else if (dc.isInactive()) { - state = getBetterConnectionState(state, DctConstants.State.IDLE); - } else if (dc.isDisconnecting()) { - state = getBetterConnectionState(state, DctConstants.State.DISCONNECTING); - } - } - } - return state; - } - - /** - * Return a better connection state between {@code stateA} and {@code stateB}. Check - * {@link #DATA_CONNECTION_STATE_PRIORITIES} for the details. - * @return the better connection state between {@code stateA} and {@code stateB}. - */ - private static DctConstants.State getBetterConnectionState( - DctConstants.State stateA, DctConstants.State stateB) { - int idxA = ArrayUtils.indexOf(DATA_CONNECTION_STATE_PRIORITIES, stateA); - int idxB = ArrayUtils.indexOf(DATA_CONNECTION_STATE_PRIORITIES, stateB); - return idxA >= idxB ? stateA : stateB; - } - - // Return if apn type is a provisioning apn. - private boolean isProvisioningApn(String apnType) { - ApnContext apnContext = mApnContexts.get(apnType); - if (apnContext != null) { - return apnContext.isProvisioningApn(); - } - return false; - } - - //****** Called from ServiceStateTracker - /** - * Invoked when ServiceStateTracker observes a transition from GPRS - * attach to detach. - */ - private void onDataConnectionDetached() { - /* - * We presently believe it is unnecessary to tear down the PDP context - * when GPRS detaches, but we should stop the network polling. - */ - if (DBG) log ("onDataConnectionDetached: stop polling and notify detached"); - stopNetStatPoll(); - stopDataStallAlarm(); - mAttached.set(false); - } - - private void onDataConnectionAttached() { - if (DBG) log("onDataConnectionAttached"); - mAttached.set(true); - if (isAnyDataConnected()) { - if (DBG) log("onDataConnectionAttached: start polling notify attached"); - startNetStatPoll(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - } - if (mAutoAttachOnCreationConfig) { - mAutoAttachEnabled.set(true); - } - setupDataOnAllConnectableApns(Phone.REASON_DATA_ATTACHED, RetryFailures.ALWAYS); - } - - /** - * Check if it is allowed to make a data connection (without checking APN context specific - * conditions). - * - * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output - * param. It's okay to pass null here and no reasons will be - * provided. - * @return True if data connection is allowed, otherwise false. - */ - public boolean isDataAllowed(DataConnectionReasons dataConnectionReasons) { - return isDataAllowed(null, REQUEST_TYPE_NORMAL, dataConnectionReasons); - } - - /** - * Check if it is allowed to make a data connection for a given APN type. - * - * @param apnContext APN context. If passing null, then will only check general but not APN - * specific conditions (e.g. APN state, metered/unmetered APN). - * @param requestType Setup data request type. - * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output - * param. It's okay to pass null here and no reasons will be - * provided. - * @return True if data connection is allowed, otherwise false. - */ - public boolean isDataAllowed(ApnContext apnContext, @RequestNetworkType int requestType, - DataConnectionReasons dataConnectionReasons) { - // Step 1: Get all environment conditions. - // Step 2: Special handling for emergency APN. - // Step 3. Build disallowed reasons. - // Step 4: Determine if data should be allowed in some special conditions. - - DataConnectionReasons reasons = new DataConnectionReasons(); - - int requestApnType = 0; - if (apnContext != null) { - requestApnType = apnContext.getApnTypeBitmask(); - } - - // Step 1: Get all environment conditions. - final boolean internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled(); - boolean attachedState = mAttached.get(); - boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState(); - boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier(); - // TODO: Remove this hack added by ag/641832. - int dataRat = getDataRat(); - if (dataRat == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { - desiredPowerState = true; - radioStateFromCarrier = true; - } - - boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId( - SubscriptionManager.getDefaultDataSubscriptionId()); - - boolean isMeteredApnType = apnContext == null - || ApnSettingUtils.isMeteredApnType(requestApnType, mPhone); - - PhoneConstants.State phoneState = PhoneConstants.State.IDLE; - // Note this is explicitly not using mPhone.getState. See b/19090488. - // mPhone.getState reports the merge of CS and PS (volte) voice call state - // but we only care about CS calls here for data/voice concurrency issues. - // Calling getCallTracker currently gives you just the CS side where the - // ImsCallTracker is held internally where applicable. - // This should be redesigned to ask explicitly what we want: - // voiceCallStateAllowDataCall, or dataCallAllowed or something similar. - if (mPhone.getCallTracker() != null) { - phoneState = mPhone.getCallTracker().getState(); - } - - // Step 2: Special handling for emergency APN. - if (apnContext != null - && requestApnType == ApnSetting.TYPE_EMERGENCY - && apnContext.isConnectable()) { - // If this is an emergency APN, as long as the APN is connectable, we - // should allow it. - if (dataConnectionReasons != null) { - dataConnectionReasons.add(DataAllowedReasonType.EMERGENCY_APN); - } - // Bail out without further checks. - return true; - } - - // Step 3. Build disallowed reasons. - if (apnContext != null && !apnContext.isConnectable()) { - DctConstants.State state = apnContext.getState(); - if (state == DctConstants.State.CONNECTED) { - reasons.add(DataDisallowedReasonType.DATA_ALREADY_CONNECTED); - } else if (state == DctConstants.State.DISCONNECTING) { - reasons.add(DataDisallowedReasonType.DATA_IS_DISCONNECTING); - } else if (state == DctConstants.State.CONNECTING) { - reasons.add(DataDisallowedReasonType.DATA_IS_CONNECTING); - } else { - reasons.add(DataDisallowedReasonType.APN_NOT_CONNECTABLE); - } - } - - // In legacy mode, if RAT is IWLAN then don't allow default/IA PDP at all. - // Rest of APN types can be evaluated for remaining conditions. - if ((apnContext != null && requestApnType == ApnSetting.TYPE_DEFAULT - || requestApnType == ApnSetting.TYPE_ENTERPRISE - || requestApnType == ApnSetting.TYPE_IA) - && mPhone.getAccessNetworksManager().isInLegacyMode() - && dataRat == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) { - reasons.add(DataDisallowedReasonType.ON_IWLAN); - } - - // If device is not on NR, don't allow enterprise - if (apnContext != null && requestApnType == ApnSetting.TYPE_ENTERPRISE - && dataRat != ServiceState.RIL_RADIO_TECHNOLOGY_NR) { - reasons.add(DataDisallowedReasonType.NOT_ON_NR); - } - - if (shouldRestrictDataForEcbm() || mPhone.isInEmergencyCall()) { - reasons.add(DataDisallowedReasonType.IN_ECBM); - } - - if (!attachedState && !shouldAutoAttach() && requestType != REQUEST_TYPE_HANDOVER) { - reasons.add(DataDisallowedReasonType.NOT_ATTACHED); - } - if (mPhone.getSubId() == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - reasons.add(DataDisallowedReasonType.SIM_NOT_READY); - } - if (phoneState != PhoneConstants.State.IDLE - && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { - reasons.add(DataDisallowedReasonType.INVALID_PHONE_STATE); - reasons.add(DataDisallowedReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED); - } - if (!internalDataEnabled) { - reasons.add(DataDisallowedReasonType.INTERNAL_DATA_DISABLED); - } - if (!defaultDataSelected) { - reasons.add(DataDisallowedReasonType.DEFAULT_DATA_UNSELECTED); - } - if (mPhone.getServiceState().getDataRoaming() && !getDataRoamingEnabled()) { - reasons.add(DataDisallowedReasonType.ROAMING_DISABLED); - } - if (mIsPsRestricted) { - reasons.add(DataDisallowedReasonType.PS_RESTRICTED); - } - if (!desiredPowerState) { - reasons.add(DataDisallowedReasonType.UNDESIRED_POWER_STATE); - } - if (!radioStateFromCarrier) { - reasons.add(DataDisallowedReasonType.RADIO_DISABLED_BY_CARRIER); - } - if (!mDataServiceBound) { - reasons.add(DataDisallowedReasonType.DATA_SERVICE_NOT_READY); - } - - if (apnContext != null) { - if (mPhone.getAccessNetworksManager().getPreferredTransport( - apnContext.getApnTypeBitmask()) - == AccessNetworkConstants.TRANSPORT_TYPE_INVALID) { - // If QNS explicitly specified this APN type is not allowed on either cellular or - // IWLAN, we should not allow data setup. - reasons.add(DataDisallowedReasonType.DISABLED_BY_QNS); - } else if (mTransportType != mPhone.getAccessNetworksManager().getPreferredTransport( - apnContext.getApnTypeBitmask())) { - // If the latest preference has already switched to other transport, we should not - // allow data setup. - reasons.add(DataDisallowedReasonType.ON_OTHER_TRANSPORT); - } - - // If the transport has been already switched to the other transport, we should not - // allow the data setup. The only exception is the handover case, where we setup - // handover data connection before switching the transport. - if (mTransportType != mPhone.getAccessNetworksManager().getCurrentTransport( - apnContext.getApnTypeBitmask()) && requestType != REQUEST_TYPE_HANDOVER) { - reasons.add(DataDisallowedReasonType.ON_OTHER_TRANSPORT); - } - - // Check if the device is under data throttling. - long retryTime = mDataThrottler.getRetryTime(apnContext.getApnTypeBitmask()); - if (retryTime > SystemClock.elapsedRealtime()) { - reasons.add(DataDisallowedReasonType.DATA_THROTTLED); - } - } - - boolean isDataEnabled = apnContext == null ? mDataEnabledSettings.isDataEnabled() - : mDataEnabledSettings.isDataEnabled(requestApnType); - - if (!isDataEnabled) { - reasons.add(DataDisallowedReasonType.DATA_DISABLED); - } - - // If there are hard disallowed reasons, we should not allow data connection no matter what. - if (reasons.containsHardDisallowedReasons()) { - if (dataConnectionReasons != null) { - dataConnectionReasons.copyFrom(reasons); - } - return false; - } - - // Step 4: Determine if data should be allowed in some special conditions. - - // At this point, if data is not allowed, it must be because of the soft reasons. We - // should start to check some special conditions that data will be allowed. - if (!reasons.allowed()) { - // Check if the transport is WLAN ie wifi (for AP-assisted mode devices) - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - reasons.add(DataAllowedReasonType.UNMETERED_APN); - // Or if the data is on cellular, and the APN type is determined unmetered by the - // configuration. - } else if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN - && !isMeteredApnType && requestApnType != ApnSetting.TYPE_DEFAULT - && requestApnType != ApnSetting.TYPE_ENTERPRISE) { - reasons.add(DataAllowedReasonType.UNMETERED_APN); - } - - // If the request is restricted and there are only soft disallowed reasons (e.g. data - // disabled, data roaming disabled) existing, we should allow the data. ENTERPRISE is - // an exception and should not be treated as restricted for this purpose; it should be - // treated same as DEFAULT. - if (apnContext != null - && apnContext.hasRestrictedRequests(true) - && !apnContext.getApnType().equals(ApnSetting.TYPE_ENTERPRISE_STRING) - && !reasons.allowed()) { - reasons.add(DataAllowedReasonType.RESTRICTED_REQUEST); - } - } else { - // If there is no disallowed reasons, then we should allow the data request with - // normal reason. - reasons.add(DataAllowedReasonType.NORMAL); - } - - if (dataConnectionReasons != null) { - dataConnectionReasons.copyFrom(reasons); - } - - return reasons.allowed(); - } - - // arg for setupDataOnAllConnectableApns - protected enum RetryFailures { - // retry failed networks always (the old default) - ALWAYS, - // retry only when a substantial change has occurred. Either: - // 1) we were restricted by voice/data concurrency and aren't anymore - // 2) our apn list has change - ONLY_ON_CHANGE - }; - - protected void setupDataOnAllConnectableApns(String reason, RetryFailures retryFailures) { - if (VDBG) log("setupDataOnAllConnectableApns: " + reason); - - if (DBG && !VDBG) { - StringBuilder sb = new StringBuilder(120); - for (ApnContext apnContext : mPrioritySortedApnContexts) { - sb.append(apnContext.getApnType()); - sb.append(":[state="); - sb.append(apnContext.getState()); - sb.append(",enabled="); - sb.append(apnContext.isEnabled()); - sb.append("] "); - } - log("setupDataOnAllConnectableApns: " + reason + " " + sb); - } - - for (ApnContext apnContext : mPrioritySortedApnContexts) { - setupDataOnConnectableApn(apnContext, reason, retryFailures); - } - } - - protected void setupDataOnConnectableApn(ApnContext apnContext, String reason, - RetryFailures retryFailures) { - if (VDBG) log("setupDataOnAllConnectableApns: apnContext " + apnContext); - - if (apnContext.getState() == DctConstants.State.FAILED - || apnContext.getState() == DctConstants.State.RETRYING) { - if (retryFailures == RetryFailures.ALWAYS) { - apnContext.releaseDataConnection(reason); - } else if (!apnContext.isConcurrentVoiceAndDataAllowed() - && mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { - // RetryFailures.ONLY_ON_CHANGE - check if voice concurrency has changed - apnContext.releaseDataConnection(reason); - } - } - if (apnContext.isConnectable()) { - log("isConnectable() call trySetupData"); - apnContext.setReason(reason); - trySetupData(apnContext, REQUEST_TYPE_NORMAL, null); - } - } - - private boolean shouldRestrictDataForEcbm() { - boolean isInEcm = mPhone.isInEcm(); - boolean isInImsEcm = mPhone.getImsPhone() != null && mPhone.getImsPhone().isInImsEcm(); - log("shouldRestrictDataForEcbm: isInEcm=" + isInEcm + " isInImsEcm=" + isInImsEcm); - return isInEcm && !isInImsEcm; - } - - private boolean isHandoverPending(@ApnType int apnType) { - List messageList = mHandoverCompletionMsgs.get(apnType); - return messageList != null && messageList.size() > 0; - } - - private void trySetupData(ApnContext apnContext, @RequestNetworkType int requestType, - @Nullable Message onHandoverCompleteMsg) { - if (onHandoverCompleteMsg != null) { - addHandoverCompleteMsg(onHandoverCompleteMsg, apnContext.getApnTypeBitmask()); - } - - if (mPhone.getSimulatedRadioControl() != null) { - // Assume data is connected on the simulator - log("trySetupData: X We're on the simulator; assuming connected retValue=true"); - return; - } - - DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); - boolean isDataAllowed = isDataAllowed(apnContext, requestType, dataConnectionReasons); - String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: " - + apnContext.getReason() + ", requestType=" + requestTypeToString(requestType) - + ". " + dataConnectionReasons.toString(); - if (dataConnectionReasons.contains(DataDisallowedReasonType.DISABLED_BY_QNS) - || dataConnectionReasons.contains(DataDisallowedReasonType.ON_OTHER_TRANSPORT)) { - logStr += ", current transport=" + AccessNetworkConstants.transportTypeToString( - mPhone.getAccessNetworksManager().getCurrentTransport( - apnContext.getApnTypeBitmask())); - logStr += ", preferred transport=" + AccessNetworkConstants.transportTypeToString( - mPhone.getAccessNetworksManager().getPreferredTransport( - apnContext.getApnTypeBitmask())); - } - if (DBG) log(logStr); - ApnContext.requestLog(apnContext, logStr); - if (!isDataAllowed) { - StringBuilder str = new StringBuilder(); - - str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType() - + ", mState=" + apnContext.getState() + ", apnEnabled=" - + apnContext.isEnabled() + ", mDependencyMet=" - + apnContext.isDependencyMet() + "] "); - - if (!mDataEnabledSettings.isDataEnabled()) { - str.append("isDataEnabled() = false. " + mDataEnabledSettings); - } - - // Check if it fails because of the existing data is still disconnecting. - if (dataConnectionReasons.contains(DataDisallowedReasonType.DATA_IS_DISCONNECTING) - && isHandoverPending(apnContext.getApnTypeBitmask())) { - // Normally we don't retry when isDataAllow() returns false, because that's consider - // pre-condition not met, for example, data not enabled by the user, or airplane - // mode is on. If we retry in those cases, there will be significant power impact. - // DATA_IS_DISCONNECTING is a special case we want to retry, and for the handover - // case only. - log("Data is disconnecting. Will retry handover later."); - return; - } - - // If this is a data retry, we should set the APN state to FAILED so it won't stay - // in RETRYING forever. - if (apnContext.getState() == DctConstants.State.RETRYING) { - apnContext.setState(DctConstants.State.FAILED); - str.append(" Stop retrying."); - } - - if (DBG) log(str.toString()); - ApnContext.requestLog(apnContext, str.toString()); - if (requestType == REQUEST_TYPE_HANDOVER) { - // If fails due to latest preference already changed back to source transport, then - // just fallback (will not attempt handover anymore, and will not tear down the - // data connection on source transport. - boolean fallback = dataConnectionReasons.contains( - DataDisallowedReasonType.ON_OTHER_TRANSPORT); - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, fallback); - } - return; - } - - if (apnContext.getState() == DctConstants.State.FAILED) { - String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable"; - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - apnContext.setState(DctConstants.State.IDLE); - } - int radioTech = getDataRat(); - if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN && mPhone.getServiceState() - .getState() == ServiceState.STATE_IN_SERVICE) { - radioTech = getVoiceRat(); - } - log("service state=" + mPhone.getServiceState()); - apnContext.setConcurrentVoiceAndDataAllowed(mPhone.getServiceStateTracker() - .isConcurrentVoiceAndDataAllowed()); - if (apnContext.getState() == DctConstants.State.IDLE) { - ArrayList waitingApns = - buildWaitingApns(apnContext.getApnType(), radioTech); - if (waitingApns.isEmpty()) { - String str = "trySetupData: X No APN found retValue=false"; - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - if (requestType == REQUEST_TYPE_HANDOVER) { - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, - false); - } - return; - } else { - apnContext.setWaitingApns(waitingApns); - if (DBG) { - log("trySetupData: Create from mAllApnSettings : " - + apnListToString(mAllApnSettings)); - } - } - } - - if (!setupData(apnContext, radioTech, requestType) - && requestType == REQUEST_TYPE_HANDOVER) { - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, false); - } - } - - /** - * Clean up all data connections. Note this is just detach the APN context from the data - * connection. After all APN contexts are detached from the data connection, the data - * connection will be torn down. - * - * @param reason Reason for the clean up. - */ - public void cleanUpAllConnections(String reason) { - log("cleanUpAllConnections"); - Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS); - msg.obj = reason; - sendMessage(msg); - } - - /** - * Clean up all data connections by detaching the APN contexts from the data connections, which - * eventually tearing down all data connections after all APN contexts are detached from the - * data connections. - * - * @param detach {@code true} if detaching APN context from the underlying data connection (when - * no other APN context is attached to the data connection, the data connection will be torn - * down.) {@code false} to only reset the data connection's state machine. - * - * @param reason reason for the clean up. - * @return boolean - true if we did cleanup any connections, false if they - * were already all disconnected. - */ - private boolean cleanUpAllConnectionsInternal(boolean detach, String reason) { - if (DBG) log("cleanUpAllConnectionsInternal: detach=" + detach + " reason=" + reason); - boolean didDisconnect = false; - boolean disableMeteredOnly = false; - - // reasons that only metered apn will be torn down - if (!TextUtils.isEmpty(reason)) { - disableMeteredOnly = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED) || - reason.equals(Phone.REASON_ROAMING_ON) || - reason.equals(Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN); - } - - for (ApnContext apnContext : mApnContexts.values()) { - // Exclude the IMS APN from single data connection case. - if (reason.equals(Phone.REASON_SINGLE_PDN_ARBITRATION) - && apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) { - continue; - } - - if (shouldCleanUpConnection(apnContext, disableMeteredOnly, - reason.equals(Phone.REASON_SINGLE_PDN_ARBITRATION))) { - // TODO - only do cleanup if not disconnected - if (apnContext.isDisconnected() == false) didDisconnect = true; - apnContext.setReason(reason); - cleanUpConnectionInternal(detach, RELEASE_TYPE_DETACH, apnContext); - } else if (DBG) { - log("cleanUpAllConnectionsInternal: APN type " + apnContext.getApnType() - + " shouldn't be cleaned up."); - } - } - - stopNetStatPoll(); - stopDataStallAlarm(); - - // TODO: Do we need mRequestedApnType? - mRequestedApnType = ApnSetting.TYPE_DEFAULT; - - if (areAllDataDisconnected()) { - notifyAllDataDisconnected(); - } - - return didDisconnect; - } - - boolean shouldCleanUpConnection(ApnContext apnContext, boolean disableMeteredOnly, - boolean singlePdn) { - if (apnContext == null) return false; - - // If APN setting is not null and the reason is single PDN arbitration, clean up connection. - ApnSetting apnSetting = apnContext.getApnSetting(); - if (apnSetting != null && singlePdn) return true; - - // If meteredOnly is false, clean up all connections. - if (!disableMeteredOnly) return true; - - // If meteredOnly is true, and apnSetting is null or it's un-metered, no need to clean up. - if (apnSetting == null || !ApnSettingUtils.isMetered(apnSetting, mPhone)) return false; - - boolean isRoaming = mPhone.getServiceState().getDataRoaming(); - boolean isDataRoamingDisabled = !getDataRoamingEnabled(); - boolean isDataDisabled = !mDataEnabledSettings.isDataEnabled( - apnSetting.getApnTypeBitmask()); - - // Should clean up if its data is disabled, or data roaming is disabled while roaming. - return isDataDisabled || (isRoaming && isDataRoamingDisabled); - } - - /** - * Detach the APN context from the associated data connection. This data connection might be - * torn down if no other APN context is attached to it. - * - * @param apnContext The APN context to be detached - */ - void cleanUpConnection(ApnContext apnContext) { - if (DBG) log("cleanUpConnection: apnContext=" + apnContext); - Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION); - msg.arg2 = 0; - msg.obj = apnContext; - sendMessage(msg); - } - - /** - * Detach the APN context from the associated data connection. This data connection will be - * torn down if no other APN context is attached to it. - * - * @param detach {@code true} if detaching APN context from the underlying data connection (when - * no other APN context is attached to the data connection, the data connection will be torn - * down.) {@code false} to only reset the data connection's state machine. - * @param releaseType Data release type. - * @param apnContext The APN context to be detached. - */ - private void cleanUpConnectionInternal(boolean detach, @ReleaseNetworkType int releaseType, - ApnContext apnContext) { - if (apnContext == null) { - if (DBG) log("cleanUpConnectionInternal: apn context is null"); - return; - } - - DataConnection dataConnection = apnContext.getDataConnection(); - String str = "cleanUpConnectionInternal: detach=" + detach + " reason=" - + apnContext.getReason(); - if (VDBG) log(str + " apnContext=" + apnContext); - ApnContext.requestLog(apnContext, str); - if (detach) { - if (apnContext.isDisconnected()) { - // The request is detach and but ApnContext is not connected. - // If apnContext is not enabled anymore, break the linkage to the data connection. - apnContext.releaseDataConnection(""); - } else { - // Connection is still there. Try to clean up. - if (dataConnection != null) { - if (apnContext.getState() != DctConstants.State.DISCONNECTING) { - boolean disconnectAll = false; - if (ApnSetting.TYPE_DUN_STRING.equals(apnContext.getApnType()) - && ServiceState.isCdma(getDataRat())) { - if (DBG) { - log("cleanUpConnectionInternal: disconnectAll DUN connection"); - } - // For CDMA DUN, we need to tear it down immediately. A new data - // connection will be reestablished with correct profile id. - disconnectAll = true; - } - final int generation = apnContext.getConnectionGeneration(); - str = "cleanUpConnectionInternal: tearing down" - + (disconnectAll ? " all" : "") + " using gen#" + generation; - if (DBG) log(str + "apnContext=" + apnContext); - ApnContext.requestLog(apnContext, str); - Pair pair = new Pair<>(apnContext, generation); - Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair); - - if (disconnectAll || releaseType == RELEASE_TYPE_HANDOVER) { - dataConnection.tearDownAll(apnContext.getReason(), releaseType, msg); - } else { - dataConnection.tearDown(apnContext, apnContext.getReason(), msg); - } - - apnContext.setState(DctConstants.State.DISCONNECTING); - } - } else { - // apn is connected but no reference to the data connection. - // Should not be happen, but reset the state in case. - apnContext.setState(DctConstants.State.IDLE); - ApnContext.requestLog( - apnContext, "cleanUpConnectionInternal: connected, bug no dc"); - } - } - } else { - // force clean up the data connection. - if (dataConnection != null) dataConnection.reset(); - apnContext.setState(DctConstants.State.IDLE); - apnContext.setDataConnection(null); - } - - // If there is any outstanding handover request, we need to respond it. - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, false); - - // Make sure reconnection alarm is cleaned up if there is no ApnContext - // associated to the connection. - if (dataConnection != null) { - cancelReconnect(apnContext); - } - str = "cleanUpConnectionInternal: X detach=" + detach + " reason=" - + apnContext.getReason(); - if (DBG) log(str + " apnContext=" + apnContext + " dc=" + apnContext.getDataConnection()); - } - - private Cursor getPreferredApnCursor(int subId) { - Cursor cursor = null; - if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - cursor = mPhone.getContext().getContentResolver().query( - Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, - String.valueOf(subId)), null, null, null, - Telephony.Carriers.DEFAULT_SORT_ORDER); - } - return cursor; - } - - private ApnSetting getPreferredApnFromDB() { - ApnSetting preferredApn = null; - Cursor cursor = getPreferredApnCursor(mPhone.getSubId()); - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - preferredApn = ApnSetting.makeApnSetting(cursor); - } - cursor.close(); - } - if (VDBG) log("getPreferredApnFromDB: preferredApn=" + preferredApn); - return preferredApn; - } - - private void setDefaultPreferredApnIfNeeded() { - ApnSetting defaultPreferredApn = null; - PersistableBundle bundle = getCarrierConfig(); - String defaultPreferredApnName = bundle.getString(CarrierConfigManager - .KEY_DEFAULT_PREFERRED_APN_NAME_STRING); - - if (TextUtils.isEmpty(defaultPreferredApnName) || getPreferredApnFromDB() != null) { - return; - } - - String selection = Telephony.Carriers.APN + " = \"" + defaultPreferredApnName + "\" AND " - + Telephony.Carriers.EDITED_STATUS + " = " + Telephony.Carriers.UNEDITED; - Cursor cursor = mPhone.getContext().getContentResolver().query( - Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, - "filtered/subId/" + mPhone.getSubId()), - null, selection, null, Telephony.Carriers._ID); - - if (cursor != null) { - if (cursor.getCount() > 0) { - if (cursor.moveToFirst()) { - defaultPreferredApn = ApnSetting.makeApnSetting(cursor); - } - } - cursor.close(); - } - - if (defaultPreferredApn != null - && defaultPreferredApn.canHandleType(mRequestedApnType)) { - log("setDefaultPreferredApnIfNeeded: For APN type " - + ApnSetting.getApnTypeString(mRequestedApnType) - + " found default apnSetting " - + defaultPreferredApn); - - setPreferredApn(defaultPreferredApn.getId(), true); - } - - return; - } - - /** - * Check if preferred apn is allowed to edit by user. - * @return {@code true} if it is allowed to edit. - */ - @VisibleForTesting - public boolean isPreferredApnUserEdited() { - boolean isUserEdited = false; - Cursor cursor = getPreferredApnCursor(mPhone.getSubId()); - if (cursor != null) { - if (cursor.getCount() > 0) { - if (cursor.moveToFirst()) { - isUserEdited = cursor.getInt( - cursor.getColumnIndexOrThrow(Telephony.Carriers.EDITED_STATUS)) - == Telephony.Carriers.USER_EDITED; - } - } - cursor.close(); - } - if (VDBG) log("isPreferredApnUserEdited: isUserEdited=" + isUserEdited); - return isUserEdited; - } - - /** - * Fetch the DUN apns - * @return a list of DUN ApnSetting objects - */ - @VisibleForTesting - public @NonNull ArrayList fetchDunApns() { - if (mPhone.getServiceState().getRoaming() && !isPreferredApnUserEdited() - && getCarrierConfig().getBoolean(CarrierConfigManager - .KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL)) { - if (VDBG) log("fetchDunApns: Dun apn is not used in roaming network"); - return new ArrayList(0); - } - - int bearer = getDataRat(); - ArrayList dunCandidates = new ArrayList(); - ArrayList retDunSettings = new ArrayList(); - - if (dunCandidates.isEmpty()) { - if (!ArrayUtils.isEmpty(mAllApnSettings)) { - for (ApnSetting apn : mAllApnSettings) { - if (apn.canHandleType(ApnSetting.TYPE_DUN)) { - dunCandidates.add(apn); - } - } - if (VDBG) log("fetchDunApns: dunCandidates from database: " + dunCandidates); - } - } - - int preferredApnSetId = getPreferredApnSetId(); - ApnSetting preferredApn = getPreferredApnFromDB(); - for (ApnSetting dunSetting : dunCandidates) { - if (dunSetting.canSupportNetworkType( - ServiceState.rilRadioTechnologyToNetworkType(bearer))) { - if (preferredApnSetId == dunSetting.getApnSetId()) { - if (preferredApn != null && preferredApn.equals(dunSetting)) { - // If there is a preferred APN can handled DUN type, prepend it to list to - // use it preferred. - retDunSettings.add(0, dunSetting); - } else { - retDunSettings.add(dunSetting); - } - } - } - } - - if (VDBG) log("fetchDunApns: dunSettings=" + retDunSettings); - return retDunSettings; - } - - private int getPreferredApnSetId() { - // preferapnset uri returns all APNs for the current carrier which have an apn_set_id - // equal to the preferred APN (if no preferred APN, or if the preferred APN has no set id, - // the query will return null) - Cursor c = mPhone.getContext().getContentResolver() - .query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, - "preferapnset/subId/" + mPhone.getSubId()), - new String[] {Telephony.Carriers.APN_SET_ID}, null, null, null); - if (c == null) { - loge("getPreferredApnSetId: cursor is null"); - return Telephony.Carriers.NO_APN_SET_ID; - } - - int setId; - if (c.getCount() < 1) { - loge("getPreferredApnSetId: no APNs found"); - setId = Telephony.Carriers.NO_APN_SET_ID; - } else { - c.moveToFirst(); - setId = c.getInt(0 /* index of Telephony.Carriers.APN_SET_ID */); - } - - if (!c.isClosed()) { - c.close(); - } - return setId; - } - - public boolean hasMatchedTetherApnSetting() { - ArrayList matches = fetchDunApns(); - log("hasMatchedTetherApnSetting: APNs=" + matches); - return matches.size() > 0; - } - - /** - * @return the {@link DataConnection} with the given context id {@code cid}. - */ - public DataConnection getDataConnectionByContextId(int cid) { - return mDcc.getActiveDcByCid(cid); - } - - /** - * @return the {@link DataConnection} with the given APN context. Null if no data connection - * is found. - */ - public @Nullable DataConnection getDataConnectionByApnType(String apnType) { - // TODO: Clean up all APN type in string usage - ApnContext apnContext = mApnContexts.get(apnType); - if (apnContext != null) { - return apnContext.getDataConnection(); - } - return null; - } - - /** - * Check if the data fail cause is a permanent failure (i.e. Frameworks will not retry data - * setup). - * - * @param dcFailCause The data fail cause - * @return {@code true} if the data fail cause is a permanent failure. - */ - @VisibleForTesting - public boolean isPermanentFailure(@DataFailureCause int dcFailCause) { - return (DataFailCause.isPermanentFailure(mPhone.getContext(), dcFailCause, - mPhone.getSubId()) - && (mAttached.get() == false || dcFailCause != DataFailCause.SIGNAL_LOST)); - } - - private DataConnection findFreeDataConnection() { - for (DataConnection dataConnection : mDataConnections.values()) { - boolean inUse = false; - for (ApnContext apnContext : mApnContexts.values()) { - if (apnContext.getDataConnection() == dataConnection) { - inUse = true; - break; - } - } - if (!inUse) { - if (DBG) { - log("findFreeDataConnection: found free DataConnection=" + dataConnection); - } - return dataConnection; - } - } - log("findFreeDataConnection: NO free DataConnection"); - return null; - } - - /** - * Setup a data connection based on given APN type. - * - * @param apnContext APN context - * @param radioTech RAT of the data connection - * @param requestType Data request type - * @return True if successful, otherwise false. - */ - private boolean setupData(ApnContext apnContext, int radioTech, - @RequestNetworkType int requestType) { - if (DBG) { - log("setupData: apnContext=" + apnContext + ", requestType=" - + requestTypeToString(requestType)); - } - ApnContext.requestLog( - apnContext, "setupData. requestType=" + requestTypeToString(requestType)); - ApnSetting apnSetting; - DataConnection dataConnection = null; - - apnSetting = apnContext.getNextApnSetting(); - - if (apnSetting == null) { - if (DBG) log("setupData: return for no apn found!"); - return false; - } - - // profile id is only meaningful when the profile is persistent on the modem. - int profileId = DATA_PROFILE_INVALID; - if (apnSetting.isPersistent()) { - profileId = apnSetting.getProfileId(); - if (profileId == DATA_PROFILE_DEFAULT) { - profileId = getApnProfileID(apnContext.getApnType()); - } - } - - // On CDMA, if we're explicitly asking for DUN, we need have - // a dun-profiled connection so we can't share an existing one - // On GSM/LTE we can share existing apn connections provided they support - // this type. - // If asking for ENTERPRISE, there are no compatible data connections, so skip this check - if ((apnContext.getApnTypeBitmask() != ApnSetting.TYPE_DUN - || ServiceState.isGsm(getDataRat())) - && apnContext.getApnTypeBitmask() != ApnSetting.TYPE_ENTERPRISE) { - dataConnection = checkForCompatibleDataConnection(apnContext, apnSetting); - if (dataConnection != null) { - // Get the apn setting used by the data connection - ApnSetting dataConnectionApnSetting = dataConnection.getApnSetting(); - if (dataConnectionApnSetting != null) { - // Setting is good, so use it. - apnSetting = dataConnectionApnSetting; - } - } - } - if (dataConnection == null) { - if (isOnlySingleDcAllowed(radioTech)) { - if (isHigherPriorityApnContextActive(apnContext)) { - if (DBG) { - log("setupData: Higher priority ApnContext active. Ignoring call"); - } - return false; - } - - // Should not start cleanUp if the setupData is for IMS APN - // or retry of same APN(State==RETRYING). - if (!apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING) - && (apnContext.getState() != DctConstants.State.RETRYING)) { - // Only lower priority calls left. Disconnect them all in this single PDP case - // so that we can bring up the requested higher priority call (once we receive - // response for deactivate request for the calls we are about to disconnect - if (cleanUpAllConnectionsInternal(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) { - // If any call actually requested to be disconnected, means we can't - // bring up this connection yet as we need to wait for those data calls - // to be disconnected. - if (DBG) log("setupData: Some calls are disconnecting first." - + " Wait and retry"); - return false; - } - } - - // No other calls are active, so proceed - if (DBG) log("setupData: Single pdp. Continue setting up data call."); - } - - dataConnection = findFreeDataConnection(); - - if (dataConnection == null) { - dataConnection = createDataConnection(); - } - - if (dataConnection == null) { - if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD"); - return false; - } - } - final int generation = apnContext.incAndGetConnectionGeneration(); - if (DBG) { - log("setupData: dc=" + dataConnection + " apnSetting=" + apnSetting + " gen#=" - + generation); - } - - apnContext.setDataConnection(dataConnection); - apnContext.setApnSetting(apnSetting); - apnContext.setState(DctConstants.State.CONNECTING); - - Message msg = obtainMessage(); - msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE; - msg.obj = new Pair(apnContext, generation); - - ApnSetting preferredApn = getPreferredApn(); - boolean isPreferredApn = apnSetting.equals(preferredApn); - dataConnection.bringUp(apnContext, profileId, radioTech, msg, generation, requestType, - mPhone.getSubId(), isPreferredApn); - - if (DBG) { - if (isPreferredApn) { - log("setupData: initing! isPreferredApn=" + isPreferredApn - + ", apnSetting={" + apnSetting.toString() + "}"); - } else { - String preferredApnStr = preferredApn == null ? "null" : preferredApn.toString(); - log("setupData: initing! isPreferredApn=" + isPreferredApn - + ", apnSetting={" + apnSetting + "}" - + ", preferredApn={" + preferredApnStr + "}"); - } - } - return true; - } - - // Get the allowed APN types for initial attach. The order in the returned list represent - // the order of APN types that should be used for initial attach. - private @NonNull @ApnType List getAllowedInitialAttachApnTypes() { - PersistableBundle bundle = getCarrierConfig(); - if (bundle != null) { - String[] apnTypesArray = bundle.getStringArray( - CarrierConfigManager.KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY); - if (apnTypesArray != null) { - return Arrays.stream(apnTypesArray) - .map(ApnSetting::getApnTypesBitmaskFromString) - .collect(Collectors.toList()); - } - } - - return Collections.emptyList(); - } - - protected void setInitialAttachApn() { - ApnSetting apnSetting = null; - int preferredApnSetId = getPreferredApnSetId(); - ArrayList allApnSettings = new ArrayList<>(); - if (mPreferredApn != null) { - // Put the preferred apn at the beginning of the list. It's okay to have a duplicate - // when later on mAllApnSettings get added. That would not change the selection result. - allApnSettings.add(mPreferredApn); - } - allApnSettings.addAll(mAllApnSettings); - - // Get the allowed APN types for initial attach. Note that if none of the APNs has the - // allowed APN types, then the initial attach will not be performed. - List allowedApnTypes = getAllowedInitialAttachApnTypes(); - for (int allowedApnType : allowedApnTypes) { - apnSetting = allApnSettings.stream() - .filter(apn -> apn.canHandleType(allowedApnType)) - .filter(apn -> (apn.getApnSetId() == preferredApnSetId - || apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID)) - .findFirst() - .orElse(null); - if (apnSetting != null) break; - } - - if (DBG) { - log("setInitialAttachApn: Allowed APN types=" + allowedApnTypes.stream() - .map(ApnSetting::getApnTypeString) - .collect(Collectors.joining(","))); - } - - if (apnSetting == null) { - if (DBG) log("setInitialAttachApn: X There in no available apn."); - } else { - if (DBG) log("setInitialAttachApn: X selected APN=" + apnSetting); - mDataServiceManager.setInitialAttachApn(new DataProfile.Builder() - .setApnSetting(apnSetting) - .setPreferred(apnSetting.equals(getPreferredApn())) - .build(), - mPhone.getServiceState().getDataRoamingFromRegistration(), null); - } - } - - /** - * Handles changes to the APN database. - */ - private void onApnChanged() { - if (mPhone instanceof GsmCdmaPhone) { - // The "current" may no longer be valid. MMS depends on this to send properly. TBD - ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider(); - } - - // TODO: It'd be nice to only do this if the changed entrie(s) - // match the current operator. - if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections"); - mDataThrottler.reset(); - setDefaultPreferredApnIfNeeded(); - createAllApnList(); - setDataProfilesAsNeeded(); - setInitialAttachApn(); - cleanUpConnectionsOnUpdatedApns(isAnyDataConnected(), Phone.REASON_APN_CHANGED); - - // FIXME: See bug 17426028 maybe no conditional is needed. - if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubscriptionId()) { - setupDataOnAllConnectableApns(Phone.REASON_APN_CHANGED, RetryFailures.ALWAYS); - } - } - - /** - * "Active" here means ApnContext isEnabled() and not in FAILED state - * @param apnContext to compare with - * @return true if higher priority active apn found - */ - private boolean isHigherPriorityApnContextActive(ApnContext apnContext) { - if (apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) { - return false; - } - - for (ApnContext otherContext : mPrioritySortedApnContexts) { - if (otherContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) { - continue; - } - if (apnContext.getApnType().equalsIgnoreCase(otherContext.getApnType())) return false; - if (otherContext.isEnabled() && otherContext.getState() != DctConstants.State.FAILED) { - return true; - } - } - return false; - } - - /** - * Reports if we support multiple connections or not. - * This is a combination of factors, based on carrier and RAT. - * @param rilRadioTech the RIL Radio Tech currently in use - * @return true if only single DataConnection is allowed - */ - private boolean isOnlySingleDcAllowed(int rilRadioTech) { - int networkType = ServiceState.rilRadioTechnologyToNetworkType(rilRadioTech); - // Default single dc rats with no knowledge of carrier - int[] singleDcRats = null; - // get the carrier specific value, if it exists, from CarrierConfigManager. - // generally configManager and bundle should not be null, but if they are it should be okay - // to leave singleDcRats null as well - CarrierConfigManager configManager = (CarrierConfigManager) - mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - PersistableBundle bundle = configManager.getConfigForSubId(mPhone.getSubId()); - if (bundle != null) { - singleDcRats = bundle.getIntArray( - CarrierConfigManager.KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY); - } - } - boolean onlySingleDcAllowed = false; - if (TelephonyUtils.IS_DEBUGGABLE - && SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) { - onlySingleDcAllowed = true; - } - if (singleDcRats != null) { - for (int i = 0; i < singleDcRats.length && !onlySingleDcAllowed; i++) { - if (networkType == singleDcRats[i]) { - onlySingleDcAllowed = true; - } - } - } - - if (DBG) { - log("isOnlySingleDcAllowed(" + TelephonyManager.getNetworkTypeName(networkType) + "): " - + onlySingleDcAllowed); - } - return onlySingleDcAllowed; - } - - void sendRestartRadio() { - if (DBG)log("sendRestartRadio:"); - Message msg = obtainMessage(DctConstants.EVENT_RESTART_RADIO); - sendMessage(msg); - } - - private void restartRadio() { - if (DBG) log("restartRadio: ************TURN OFF RADIO**************"); - cleanUpAllConnectionsInternal(true, Phone.REASON_RADIO_TURNED_OFF); - mPhone.getServiceStateTracker().powerOffRadioSafely(); - /* Note: no need to call setRadioPower(true). Assuming the desired - * radio power state is still ON (as tracked by ServiceStateTracker), - * ServiceStateTracker will call setRadioPower when it receives the - * RADIO_STATE_CHANGED notification for the power off. And if the - * desired power state has changed in the interim, we don't want to - * override it with an unconditional power on. - */ - } - - /** - * Return true if data connection need to be setup after disconnected due to - * reason. - * - * @param apnContext APN context - * @return true if try setup data connection is need for this reason - */ - private boolean retryAfterDisconnected(ApnContext apnContext) { - boolean retry = true; - String reason = apnContext.getReason(); - - if (Phone.REASON_RADIO_TURNED_OFF.equals(reason) || (isOnlySingleDcAllowed(getDataRat()) - && isHigherPriorityApnContextActive(apnContext))) { - retry = false; - } - return retry; - } - - protected void startReconnect(long delay, ApnContext apnContext, - @RequestNetworkType int requestType) { - apnContext.setState(DctConstants.State.RETRYING); - Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT, - mPhone.getSubId(), requestType, apnContext); - cancelReconnect(apnContext); - - // Wait a bit before trying the next APN, so that - // we're not tying up the RIL command channel - sendMessageDelayed(msg, delay); - - if (DBG) { - log("startReconnect: delay=" + delay + ", apn=" - + apnContext + ", reason=" + apnContext.getReason() - + ", subId=" + mPhone.getSubId() + ", request type=" - + requestTypeToString(requestType)); - } - } - - /** - * Cancels the alarm associated with apnContext. - * - * @param apnContext on which the alarm should be stopped. - */ - protected void cancelReconnect(ApnContext apnContext) { - if (apnContext == null) return; - - if (DBG) { - log("cancelReconnect: apn=" + apnContext); - } - removeMessages(DctConstants.EVENT_DATA_RECONNECT, apnContext); - } - - /** - * Read configuration. Note this must be called after carrier config is ready. - */ - private void readConfiguration() { - log("readConfiguration"); - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - // Auto attach is for cellular only. - mAutoAttachOnCreationConfig = mPhone.getContext().getResources() - .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation); - } - - mAutoAttachEnabled.set(false); - setDefaultPreferredApnIfNeeded(); - read5GConfiguration(); - registerSettingsObserver(); - SubscriptionPlan[] plans = mNetworkPolicyManager.getSubscriptionPlans( - mPhone.getSubId(), mPhone.getContext().getOpPackageName()); - mSubscriptionPlans = plans == null ? Collections.emptyList() : Arrays.asList(plans); - if (DBG) log("SubscriptionPlans initialized: " + mSubscriptionPlans); - reevaluateUnmeteredConnections(); - mConfigReady = true; - } - - /** - * @return {@code true} if carrier config has been applied. - */ - private boolean isCarrierConfigApplied() { - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); - if (b != null) { - return CarrierConfigManager.isConfigForIdentifiedCarrier(b); - } - } - return false; - } - - private void onCarrierConfigChanged() { - if (DBG) log("onCarrierConfigChanged"); - - if (!isCarrierConfigApplied()) { - log("onCarrierConfigChanged: Carrier config is not ready yet."); - return; - } - - readConfiguration(); - - if (mSimState == TelephonyManager.SIM_STATE_LOADED) { - setDefaultDataRoamingEnabled(); - createAllApnList(); - setDataProfilesAsNeeded(); - setInitialAttachApn(); - sortApnContextByPriority(); - cleanUpConnectionsOnUpdatedApns(true, Phone.REASON_CARRIER_CHANGE); - setupDataOnAllConnectableApns(Phone.REASON_CARRIER_CHANGE, RetryFailures.ALWAYS); - } else { - log("onCarrierConfigChanged: SIM is not loaded yet."); - } - } - - private void onSimAbsent() { - if (DBG) log("onSimAbsent"); - - mConfigReady = false; - cleanUpAllConnectionsInternal(true, Phone.REASON_SIM_NOT_READY); - mAllApnSettings.clear(); - mAutoAttachOnCreationConfig = false; - // Clear auto attach as modem is expected to do a new attach once SIM is ready - mAutoAttachEnabled.set(false); - // In no-sim case, we should still send the emergency APN to the modem, if there is any. - createAllApnList(); - setDataProfilesAsNeeded(); - } - - private void onSimStateUpdated(@SimState int simState) { - mSimState = simState; - - if (DBG) { - log("onSimStateUpdated: state=" + SubscriptionInfoUpdater.simStateString(mSimState)); - } - - if (mSimState == TelephonyManager.SIM_STATE_ABSENT) { - onSimAbsent(); - } else if (mSimState == TelephonyManager.SIM_STATE_LOADED) { - mDataThrottler.reset(); - if (mConfigReady) { - createAllApnList(); - setDataProfilesAsNeeded(); - setInitialAttachApn(); - setupDataOnAllConnectableApns(Phone.REASON_SIM_LOADED, RetryFailures.ALWAYS); - } else { - log("onSimStateUpdated: config not ready yet."); - } - } - } - - private void onApnUnthrottled(String apn) { - if (apn != null) { - ApnSetting apnSetting = mAllApnSettings.stream() - .filter(as -> apn.equals(as.getApnName())) - .findFirst() - .orElse(null); - if (apnSetting != null) { - @ApnType int apnTypes = apnSetting.getApnTypeBitmask(); - mDataThrottler.setRetryTime(apnTypes, RetryManager.NO_SUGGESTED_RETRY_DELAY, - REQUEST_TYPE_NORMAL); - } else { - loge("EVENT_APN_UNTHROTTLED: Invalid APN passed: " + apn); - } - } else { - loge("EVENT_APN_UNTHROTTLED: apn is null"); - } - } - - private void onTrafficDescriptorsUpdated() { - for (ApnContext apnContext : mPrioritySortedApnContexts) { - if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE - && apnContext.getApnSetting().getPermanentFailed()) { - setupDataOnConnectableApn( - apnContext, Phone.REASON_TRAFFIC_DESCRIPTORS_UPDATED, RetryFailures.ALWAYS); - } - } - } - - private DataConnection checkForCompatibleDataConnection(ApnContext apnContext, - ApnSetting nextApn) { - int apnType = apnContext.getApnTypeBitmask(); - ArrayList dunSettings = null; - - if (ApnSetting.TYPE_DUN == apnType) { - dunSettings = fetchDunApns(); - } - if (DBG) { - log("checkForCompatibleDataConnection: apnContext=" + apnContext); - } - - DataConnection potentialDc = null; - for (DataConnection curDc : mDataConnections.values()) { - if (curDc != null) { - ApnSetting apnSetting = curDc.getApnSetting(); - log("apnSetting: " + apnSetting); - if (dunSettings != null && dunSettings.size() > 0) { - for (ApnSetting dunSetting : dunSettings) { - //This ignore network type as a check which is ok because that's checked - //when calculating dun candidates. - if (areCompatible(dunSetting, apnSetting)) { - if (curDc.isActive()) { - if (DBG) { - log("checkForCompatibleDataConnection:" - + " found dun conn=" + curDc); - } - return curDc; - } else if (curDc.isActivating()) { - potentialDc = curDc; - } - } - } - } else if (isApnSettingCompatible(curDc, apnType)) { - if (curDc.isActive()) { - if (DBG) { - log("checkForCompatibleDataConnection:" - + " found canHandle conn=" + curDc); - } - return curDc; - } else if (curDc.isActivating() - || (apnSetting != null && apnSetting.equals(nextApn))) { - potentialDc = curDc; - } - } - } - } - - if (DBG) { - log("checkForCompatibleDataConnection: potential dc=" + potentialDc); - } - return potentialDc; - } - - private boolean isApnSettingCompatible(DataConnection dc, int apnType) { - ApnSetting apnSetting = dc.getApnSetting(); - if (apnSetting == null) return false; - - // Nothing can be compatible with type ENTERPRISE - for (ApnContext apnContext : dc.getApnContexts()) { - if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { - return false; - } - } - - return apnSetting.canHandleType(apnType); - } - - private void addHandoverCompleteMsg(Message onCompleteMsg, - @ApnType int apnType) { - if (onCompleteMsg != null) { - List messageList = mHandoverCompletionMsgs.get(apnType); - if (messageList == null) messageList = new ArrayList<>(); - messageList.add(onCompleteMsg); - mHandoverCompletionMsgs.put(apnType, messageList); - } - } - - private void sendHandoverCompleteMessages(@ApnType int apnType, boolean success, - boolean fallbackOnFailedHandover) { - List messageList = mHandoverCompletionMsgs.get(apnType); - if (messageList != null) { - for (Message msg : messageList) { - sendHandoverCompleteMsg(msg, success, mTransportType, fallbackOnFailedHandover); - } - messageList.clear(); - } - } - - private void sendHandoverCompleteMsg(Message message, boolean success, - @TransportType int transport, boolean doFallbackOnFailedHandover) { - if (message == null) return; - - Bundle b = message.getData(); - b.putBoolean(DATA_COMPLETE_MSG_EXTRA_SUCCESS, success); - b.putInt(DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE, transport); - b.putBoolean(DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK, doFallbackOnFailedHandover); - message.sendToTarget(); - } - - private static boolean shouldFallbackOnFailedHandover( - @HandoverFailureMode int handoverFailureMode, - @RequestNetworkType int requestType, - @DataFailureCause int cause) { - if (requestType != REQUEST_TYPE_HANDOVER) { - //The fallback is only relevant if the request is a handover - return false; - } else if (handoverFailureMode == HANDOVER_FAILURE_MODE_DO_FALLBACK) { - return true; - } else if (handoverFailureMode == HANDOVER_FAILURE_MODE_LEGACY) { - return cause == DataFailCause.HANDOFF_PREFERENCE_CHANGED; - } else { - return false; - } - } - - /** - * Calculates the new request type that will be used the next time a data connection retries - * after a failed data call attempt. - */ - @RequestNetworkType - public static int calculateNewRetryRequestType(@HandoverFailureMode int handoverFailureMode, - @RequestNetworkType int requestType, - @DataFailureCause int cause) { - boolean fallbackOnFailedHandover = - shouldFallbackOnFailedHandover(handoverFailureMode, requestType, cause); - if (requestType != REQUEST_TYPE_HANDOVER) { - //The fallback is only relevant if the request is a handover - return requestType; - } - - if (fallbackOnFailedHandover) { - // Since fallback is happening, the request type is really "NONE". - return REQUEST_TYPE_NORMAL; - } - - if (handoverFailureMode == HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL) { - return REQUEST_TYPE_NORMAL; - } - - return REQUEST_TYPE_HANDOVER; - } - - public void enableApn(@ApnType int apnType, @RequestNetworkType int requestType, - Message onHandoverCompleteMsg) { - sendMessage(obtainMessage(DctConstants.EVENT_ENABLE_APN, apnType, requestType, - onHandoverCompleteMsg)); - } - - private void onEnableApn(@ApnType int apnType, @RequestNetworkType int requestType, - Message onHandoverCompleteMsg) { - ApnContext apnContext = mApnContextsByType.get(apnType); - if (apnContext == null) { - loge("onEnableApn(" + apnType + "): NO ApnContext"); - if (onHandoverCompleteMsg != null) { - sendHandoverCompleteMsg(onHandoverCompleteMsg, false, mTransportType, false); - } - return; - } - - String str = "onEnableApn: apnType=" + ApnSetting.getApnTypeString(apnType) - + ", request type=" + requestTypeToString(requestType); - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - - if (!apnContext.isDependencyMet()) { - apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET); - apnContext.setEnabled(true); - str = "onEnableApn: dependency is not met."; - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - if (onHandoverCompleteMsg != null) { - sendHandoverCompleteMsg(onHandoverCompleteMsg, false, mTransportType, false); - } - return; - } - - if (apnContext.isReady()) { - DctConstants.State state = apnContext.getState(); - switch(state) { - case CONNECTING: - if (onHandoverCompleteMsg != null) { - if (DBG) { - log("onEnableApn: already in CONNECTING state. Handover request " - + "will be responded after connected."); - } - addHandoverCompleteMsg(onHandoverCompleteMsg, apnType); - } else { - if (DBG) log("onEnableApn: in CONNECTING state. Exit now."); - } - return; - case CONNECTED: - if (onHandoverCompleteMsg != null) { - sendHandoverCompleteMsg(onHandoverCompleteMsg, true, mTransportType, - false); - if (DBG) { - log("onEnableApn: already in CONNECTED state. Consider as handover " - + "succeeded"); - } - } else { - if (DBG) log("onEnableApn: APN in CONNECTED state. Exit now."); - } - return; - case IDLE: - case FAILED: - case RETRYING: - // We're "READY" but not active so disconnect (cleanup = true) and - // connect (trySetup = true) to be sure we retry the connection. - apnContext.setReason(Phone.REASON_DATA_ENABLED); - break; - } - } else { - if (apnContext.isEnabled()) { - apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET); - } else { - apnContext.setReason(Phone.REASON_DATA_ENABLED); - } - if (apnContext.getState() == DctConstants.State.FAILED) { - apnContext.setState(DctConstants.State.IDLE); - } - } - apnContext.setEnabled(true); - apnContext.resetErrorCodeRetries(); - - if (mConfigReady || apnContext.getApnTypeBitmask() == ApnSetting.TYPE_EMERGENCY) { - trySetupData(apnContext, requestType, onHandoverCompleteMsg); - } else { - log("onEnableApn: config not ready yet."); - } - } - - public void disableApn(@ApnType int apnType, @ReleaseNetworkType int releaseType) { - sendMessage(obtainMessage(DctConstants.EVENT_DISABLE_APN, apnType, releaseType)); - } - - private void onDisableApn(@ApnType int apnType, - @ReleaseNetworkType int releaseType) { - ApnContext apnContext = mApnContextsByType.get(apnType); - if (apnContext == null) { - loge("disableApn(" + apnType + "): NO ApnContext"); - return; - } - - boolean cleanup = false; - String str = "onDisableApn: apnType=" + ApnSetting.getApnTypeString(apnType) - + ", release type=" + releaseTypeToString(releaseType); - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - - if (apnContext.isReady()) { - cleanup = (releaseType == RELEASE_TYPE_DETACH - || releaseType == RELEASE_TYPE_HANDOVER); - if (apnContext.isDependencyMet()) { - apnContext.setReason(Phone.REASON_DATA_DISABLED_INTERNAL); - // If ConnectivityService has disabled this network, stop trying to bring - // it up, but do not tear it down - ConnectivityService will do that - // directly by talking with the DataConnection. - // - // This doesn't apply to DUN. When the user disable tethering, we would like to - // detach the APN context from the data connection so the data connection can be - // torn down if no other APN context attached to it. - if (ApnSetting.TYPE_DUN_STRING.equals(apnContext.getApnType()) - || apnContext.getState() != DctConstants.State.CONNECTED) { - str = "Clean up the connection. Apn type = " + apnContext.getApnType() - + ", state = " + apnContext.getState(); - if (DBG) log(str); - ApnContext.requestLog(apnContext, str); - cleanup = true; - } - } else { - apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET); - } - } - - apnContext.setEnabled(false); - if (cleanup) { - cleanUpConnectionInternal(true, releaseType, apnContext); - } - - if (isOnlySingleDcAllowed(getDataRat()) && !isHigherPriorityApnContextActive(apnContext)) { - if (DBG) log("disableApn:isOnlySingleDcAllowed true & higher priority APN disabled"); - // If the highest priority APN is disabled and only single - // data call is allowed, try to setup data call on other connectable APN. - setupDataOnAllConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION, - RetryFailures.ALWAYS); - } - } - - /** - * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value for user modification only - */ - public void setDataRoamingEnabledByUser(boolean enabled) { - mDataEnabledSettings.setDataRoamingEnabled(enabled); - setDataRoamingFromUserAction(true); - if (DBG) { - log("setDataRoamingEnabledByUser: set phoneSubId=" + mPhone.getSubId() - + " isRoaming=" + enabled); - } - } - - /** - * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value. - */ - public boolean getDataRoamingEnabled() { - boolean isDataRoamingEnabled = mDataEnabledSettings.getDataRoamingEnabled(); - - if (VDBG) { - log("getDataRoamingEnabled: phoneSubId=" + mPhone.getSubId() - + " isDataRoamingEnabled=" + isDataRoamingEnabled); - } - return isDataRoamingEnabled; - } - - /** - * Set default value for {@link android.provider.Settings.Global#DATA_ROAMING} - * if the setting is not from user actions. default value is based on carrier config and system - * properties. - */ - private void setDefaultDataRoamingEnabled() { - // For single SIM phones, this is a per phone property. - String setting = Settings.Global.DATA_ROAMING; - boolean useCarrierSpecificDefault = false; - if (mTelephonyManager.getSimCount() != 1) { - setting = setting + mPhone.getSubId(); - try { - Settings.Global.getInt(mResolver, setting); - } catch (SettingNotFoundException ex) { - // For msim, update to carrier default if uninitialized. - useCarrierSpecificDefault = true; - } - } else if (!isDataRoamingFromUserAction()) { - // for single sim device, update to carrier default if user action is not set - useCarrierSpecificDefault = true; - } - log("setDefaultDataRoamingEnabled: useCarrierSpecificDefault " - + useCarrierSpecificDefault); - if (useCarrierSpecificDefault) { - boolean defaultVal = mDataEnabledSettings.getDefaultDataRoamingEnabled(); - mDataEnabledSettings.setDataRoamingEnabled(defaultVal); - } - } - - private boolean isDataRoamingFromUserAction() { - final SharedPreferences sp = PreferenceManager - .getDefaultSharedPreferences(mPhone.getContext()); - // since we don't want to unset user preference from system update, pass true as the default - // value if shared pref does not exist and set shared pref to false explicitly from factory - // reset. - if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) { - sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit(); - } - return sp.getBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true); - } - - private void setDataRoamingFromUserAction(boolean isUserAction) { - final SharedPreferences.Editor sp = PreferenceManager - .getDefaultSharedPreferences(mPhone.getContext()).edit(); - sp.putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, isUserAction).commit(); - } - - // When the data roaming status changes from roaming to non-roaming. - private void onDataRoamingOff() { - if (DBG) log("onDataRoamingOff"); - - reevaluateDataConnections(); - - if (!getDataRoamingEnabled()) { - // TODO: Remove this once all old vendor RILs are gone. We don't need to set initial apn - // attach and send the data profile again as the modem should have both roaming and - // non-roaming protocol in place. Modem should choose the right protocol based on the - // roaming condition. - setDataProfilesAsNeeded(); - setInitialAttachApn(); - - // If the user did not enable data roaming, now when we transit from roaming to - // non-roaming, we should try to reestablish the data connection. - - setupDataOnAllConnectableApns(Phone.REASON_ROAMING_OFF, RetryFailures.ALWAYS); - } - } - - // This method is called - // 1. When the data roaming status changes from non-roaming to roaming. - // 2. When allowed data roaming settings is changed by the user. - private void onDataRoamingOnOrSettingsChanged(int messageType) { - if (DBG) log("onDataRoamingOnOrSettingsChanged"); - // Used to differentiate data roaming turned on vs settings changed. - boolean settingChanged = (messageType == DctConstants.EVENT_ROAMING_SETTING_CHANGE); - - // Check if the device is actually data roaming - if (!mPhone.getServiceState().getDataRoaming()) { - if (DBG) log("device is not roaming. ignored the request."); - return; - } - - checkDataRoamingStatus(settingChanged); - - if (getDataRoamingEnabled()) { - // If the restricted data was brought up when data roaming is disabled, and now users - // enable data roaming, we need to re-evaluate the conditions and possibly change the - // network's capability. - if (settingChanged) { - reevaluateDataConnections(); - } - - if (DBG) log("onDataRoamingOnOrSettingsChanged: setup data on roaming"); - - setupDataOnAllConnectableApns(Phone.REASON_ROAMING_ON, RetryFailures.ALWAYS); - } else { - // If the user does not turn on data roaming, when we transit from non-roaming to - // roaming, we need to tear down the data connection otherwise the user might be - // charged for data roaming usage. - if (DBG) log("onDataRoamingOnOrSettingsChanged: Tear down data connection on roaming."); - cleanUpAllConnectionsInternal(true, Phone.REASON_ROAMING_ON); - } - } - - // We want to track possible roaming data leakage. Which is, if roaming setting - // is disabled, yet we still setup a roaming data connection or have a connected ApnContext - // switched to roaming. When this happens, we log it in a local log. - private void checkDataRoamingStatus(boolean settingChanged) { - if (!settingChanged && !getDataRoamingEnabled() - && mPhone.getServiceState().getDataRoaming()) { - for (ApnContext apnContext : mApnContexts.values()) { - if (apnContext.getState() == DctConstants.State.CONNECTED) { - mDataRoamingLeakageLog.log("PossibleRoamingLeakage " - + " connection params: " + (apnContext.getDataConnection() != null - ? apnContext.getDataConnection().getConnectionParams() : "")); - } - } - } - } - - private void onRadioAvailable() { - if (DBG) log("onRadioAvailable"); - if (!areAllDataDisconnected()) { - cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, null); - } - } - - private void onRadioOffOrNotAvailable() { - // Make sure our reconnect delay starts at the initial value - // next time the radio comes on - - mReregisterOnReconnectFailure = false; - - // Clear auto attach as modem is expected to do a new attach - mAutoAttachEnabled.set(false); - - if (mPhone.getSimulatedRadioControl() != null) { - // Assume data is connected on the simulator - // FIXME this can be improved - log("We're on the simulator; assuming radio off is meaningless"); - } else { - if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections"); - cleanUpAllConnectionsInternal(false, Phone.REASON_RADIO_TURNED_OFF); - } - } - - private void completeConnection(ApnContext apnContext, @RequestNetworkType int type) { - - if (DBG) log("completeConnection: successful, notify the world apnContext=" + apnContext); - - if (mIsProvisioning && !TextUtils.isEmpty(mProvisioningUrl)) { - if (DBG) { - log("completeConnection: MOBILE_PROVISIONING_ACTION url=" - + mProvisioningUrl); - } - Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, - Intent.CATEGORY_APP_BROWSER); - newIntent.setData(Uri.parse(mProvisioningUrl)); - newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | - Intent.FLAG_ACTIVITY_NEW_TASK); - try { - mPhone.getContext().startActivity(newIntent); - } catch (ActivityNotFoundException e) { - loge("completeConnection: startActivityAsUser failed" + e); - } - } - mIsProvisioning = false; - mProvisioningUrl = null; - if (mProvisioningSpinner != null) { - sendMessage(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER, - mProvisioningSpinner)); - } - - startNetStatPoll(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - - PersistableBundle b = getCarrierConfig(); - if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT - && b.getBoolean(CarrierConfigManager - .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) { - NotificationManager notificationManager = (NotificationManager) - mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.cancel(Integer.toString(mPhone.getSubId()), - NO_DATA_NOTIFICATION); - } - } - - /** - * A SETUP (aka bringUp) has completed, possibly with an error. If - * there is an error this method will call {@link #onDataSetupCompleteError}. - */ - protected void onDataSetupComplete(ApnContext apnContext, boolean success, - @DataFailureCause int cause, @RequestNetworkType int requestType, - @HandoverFailureMode int handoverFailureMode) { - boolean fallbackOnFailedHandover = shouldFallbackOnFailedHandover( - handoverFailureMode, requestType, cause); - - if (success && (handoverFailureMode != DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN - && handoverFailureMode != DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY)) { - Log.wtf(mLogTag, "bad failure mode: " - + DataCallResponse.failureModeToString(handoverFailureMode)); - } else if (handoverFailureMode - != DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER - && cause != DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE) { - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), success, - fallbackOnFailedHandover); - } - - if (success) { - DataConnection dataConnection = apnContext.getDataConnection(); - - if (RADIO_TESTS) { - // Note: To change radio.test.onDSC.null.dcac from command line you need to - // adb root and adb remount and from the command line you can only change the - // value to 1 once. To change it a second time you can reboot or execute - // adb shell stop and then adb shell start. The command line to set the value is: - // adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');" - ContentResolver cr = mPhone.getContext().getContentResolver(); - String radioTestProperty = "radio.test.onDSC.null.dcac"; - if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) { - log("onDataSetupComplete: " + radioTestProperty + - " is true, set dcac to null and reset property to false"); - dataConnection = null; - Settings.System.putInt(cr, radioTestProperty, 0); - log("onDataSetupComplete: " + radioTestProperty + "=" + - Settings.System.getInt(mPhone.getContext().getContentResolver(), - radioTestProperty, -1)); - } - } - if (dataConnection == null) { - log("onDataSetupComplete: no connection to DC, handle as error"); - onDataSetupCompleteError(apnContext, requestType, false); - } else { - ApnSetting apn = apnContext.getApnSetting(); - if (DBG) { - log("onDataSetupComplete: success apn=" + (apn == null ? "unknown" - : apn.getApnName())); - } - - // everything is setup - if (TextUtils.equals(apnContext.getApnType(), ApnSetting.TYPE_DEFAULT_STRING) - && mCanSetPreferApn && mPreferredApn == null) { - if (DBG) log("onDataSetupComplete: PREFERRED APN is null"); - mPreferredApn = apn; - if (mPreferredApn != null) { - setPreferredApn(mPreferredApn.getId()); - } - } - - // A connection is setup - apnContext.setState(DctConstants.State.CONNECTED); - - checkDataRoamingStatus(false); - - boolean isProvApn = apnContext.isProvisioningApn(); - final ConnectivityManager cm = (ConnectivityManager) mPhone.getContext() - .getSystemService(Context.CONNECTIVITY_SERVICE); - if (mProvisionBroadcastReceiver != null) { - mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver); - mProvisionBroadcastReceiver = null; - } - - if ((!isProvApn) || mIsProvisioning) { - if (mIsProvisioning) { - // Hide any notification that was showing previously - hideProvisioningNotification(); - } - - // Complete the connection normally notifying the world we're connected. - // We do this if this isn't a special provisioning apn or if we've been - // told its time to provision. - completeConnection(apnContext, requestType); - } else { - // This is a provisioning APN that we're reporting as connected. Later - // when the user desires to upgrade this to a "default" connection, - // mIsProvisioning == true, we'll go through the code path above. - // mIsProvisioning becomes true when CMD_ENABLE_MOBILE_PROVISIONING - // is sent to the DCT. - if (DBG) { - log("onDataSetupComplete: successful, BUT send connected to prov apn as" - + " mIsProvisioning:" + mIsProvisioning + " == false" - + " && (isProvisioningApn:" + isProvApn + " == true"); - } - - // While radio is up, grab provisioning URL. The URL contains ICCID which - // disappears when radio is off. - mProvisionBroadcastReceiver = new ProvisionNotificationBroadcastReceiver( - mPhone.getMobileProvisioningUrl(), - mTelephonyManager.getNetworkOperatorName()); - mPhone.getContext().registerReceiver(mProvisionBroadcastReceiver, - new IntentFilter(INTENT_PROVISION)); - - // Put up user notification that sign-in is required. - showProvisioningNotification(); - - // Turn off radio to save battery and avoid wasting carrier resources. - // The network isn't usable and network validation will just fail anyhow. - setRadio(false); - } - if (DBG) { - log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType()); - } - if (TelephonyUtils.IS_DEBUGGABLE) { - // adb shell setprop persist.radio.test.pco [pco_val] - String radioTestProperty = "persist.radio.test.pco"; - int pcoVal = SystemProperties.getInt(radioTestProperty, -1); - if (pcoVal != -1) { - log("PCO testing: read pco value from persist.radio.test.pco " + pcoVal); - final byte[] value = new byte[1]; - value[0] = (byte) pcoVal; - final Intent intent = - new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE); - intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, ApnSetting.TYPE_DEFAULT); - intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL, - ApnSetting.PROTOCOL_IPV4V6); - intent.putExtra(TelephonyManager.EXTRA_PCO_ID, 0xFF00); - intent.putExtra(TelephonyManager.EXTRA_PCO_VALUE, value); - mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); - } - } - } - } else { - if (DBG) { - ApnSetting apn = apnContext.getApnSetting(); - log("onDataSetupComplete: error apn=" + apn.getApnName() + ", cause=" - + DataFailCause.toString(cause) + ", requestType=" - + requestTypeToString(requestType)); - } - if (DataFailCause.isEventLoggable(cause)) { - // Log this failure to the Event Logs. - int cid = getCellLocationId(); - EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL, - cause, cid, mTelephonyManager.getNetworkType()); - } - ApnSetting apn = apnContext.getApnSetting(); - - // Compose broadcast intent send to the specific carrier signaling receivers - Intent intent = new Intent(TelephonyManager - .ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED); - intent.putExtra(TelephonyManager.EXTRA_DATA_FAIL_CAUSE, cause); - intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, - ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType())); - mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); - - if (DataFailCause.isRadioRestartFailure(mPhone.getContext(), cause, mPhone.getSubId()) - || apnContext.restartOnError(cause)) { - if (DBG) log("Modem restarted."); - sendRestartRadio(); - } - - // If the data call failure cause is a permanent failure, we mark the APN as permanent - // failed. - if (isPermanentFailure(cause)) { - log("cause=" + DataFailCause.toString(cause) - + ", mark apn as permanent failed. apn = " + apn); - apnContext.markApnPermanentFailed(apn); - - PersistableBundle b = getCarrierConfig(); - if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT - && b.getBoolean(CarrierConfigManager - .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) { - NotificationManager notificationManager = (NotificationManager) - mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE); - - CharSequence title = mPhone.getContext().getText( - com.android.internal.R.string.RestrictedOnDataTitle); - CharSequence details = mPhone.getContext().getText( - com.android.internal.R.string.RestrictedStateContent); - - Notification notification = new Notification.Builder(mPhone.getContext(), - NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS) - .setWhen(System.currentTimeMillis()) - .setAutoCancel(true) - .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning) - .setTicker(title) - .setColor(mPhone.getContext().getResources().getColor( - com.android.internal.R.color.system_notification_accent_color)) - .setContentTitle(title) - .setStyle(new Notification.BigTextStyle().bigText(details)) - .setContentText(details) - .build(); - notificationManager.notify(Integer.toString(mPhone.getSubId()), - NO_DATA_NOTIFICATION, notification); - } - } - - int newRequestType = calculateNewRetryRequestType(handoverFailureMode, requestType, - cause); - onDataSetupCompleteError(apnContext, newRequestType, fallbackOnFailedHandover); - } - } - - - - /** - * Error has occurred during the SETUP {aka bringUP} request and the DCT - * should either try the next waiting APN or start over from the - * beginning if the list is empty. Between each SETUP request there will - * be a delay defined by {@link ApnContext#getDelayForNextApn(boolean)}. - */ - protected void onDataSetupCompleteError(ApnContext apnContext, - @RequestNetworkType int requestType, boolean fallbackOnFailedHandover) { - long delay = apnContext.getDelayForNextApn(mFailFast); - // Check if we need to retry or not. - if (delay >= 0 && delay != RetryManager.NO_RETRY && !fallbackOnFailedHandover) { - if (DBG) { - log("onDataSetupCompleteError: APN type=" + apnContext.getApnType() - + ". Request type=" + requestTypeToString(requestType) + ", Retry in " - + delay + "ms."); - } - startReconnect(delay, apnContext, requestType); - } else { - // If we are not going to retry any APN, set this APN context to failed state. - // This would be the final state of a data connection. - apnContext.setState(DctConstants.State.FAILED); - apnContext.setDataConnection(null); - log("onDataSetupCompleteError: Stop retrying APNs. delay=" + delay - + ", requestType=" + requestTypeToString(requestType)); - //send request network complete messages as needed - sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, - fallbackOnFailedHandover); - } - } - - /** - * Called when EVENT_NETWORK_STATUS_CHANGED is received. - * - * @param status One of {@code NetworkAgent.VALID_NETWORK} or - * {@code NetworkAgent.INVALID_NETWORK}. - * @param cid context id {@code cid} - * @param redirectUrl If the Internet probe was redirected, this - * is the destination it was redirected to, otherwise {@code null} - */ - private void onNetworkStatusChanged(int status, int cid, String redirectUrl) { - if (!TextUtils.isEmpty(redirectUrl)) { - Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED); - intent.putExtra(TelephonyManager.EXTRA_REDIRECTION_URL, redirectUrl); - mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); - log("Notify carrier signal receivers with redirectUrl: " + redirectUrl); - } else { - final boolean isValid = status == NetworkAgent.VALIDATION_STATUS_VALID; - final DataConnection dc = getDataConnectionByContextId(cid); - if (!mDsRecoveryHandler.isRecoveryOnBadNetworkEnabled()) { - if (DBG) log("Skip data stall recovery on network status change with in threshold"); - return; - } - if (mTransportType != AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { - if (DBG) log("Skip data stall recovery on non WWAN"); - return; - } - if (dc != null && dc.isValidationRequired()) { - mDsRecoveryHandler.processNetworkStatusChanged(isValid); - } - } - } - - /** - * Called when EVENT_DISCONNECT_DONE is received. - */ - private void onDisconnectDone(ApnContext apnContext) { - if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext); - apnContext.setState(DctConstants.State.IDLE); - // If all data connection are gone, check whether Airplane mode request was pending. - if (areAllDataDisconnected() - && mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) { - if (DBG) log("onDisconnectDone: radio will be turned off, no retries"); - // Radio will be turned off. No need to retry data setup - apnContext.setApnSetting(null); - apnContext.setDataConnection(null); - - // Need to notify disconnect as well, in the case of switching Airplane mode. - // Otherwise, it would cause 30s delayed to turn on Airplane mode. - notifyAllDataDisconnected(); - return; - } - // If APN is still enabled, try to bring it back up automatically - if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) { - // Wait a bit before trying the next APN, so that - // we're not tying up the RIL command channel. - // This also helps in any external dependency to turn off the context. - if (DBG) log("onDisconnectDone: attached, ready and retry after disconnect"); - - // See if there are still handover request pending that we need to retry handover - // after previous data gets disconnected. - if (isHandoverPending(apnContext.getApnTypeBitmask())) { - if (DBG) log("Handover request pending. Retry handover immediately."); - startReconnect(0, apnContext, REQUEST_TYPE_HANDOVER); - } else { - long delay = apnContext.getRetryAfterDisconnectDelay(); - if (delay > 0) { - // Data connection is in IDLE state, so when we reconnect later, we'll rebuild - // the waiting APN list, which will also reset/reconfigure the retry manager. - startReconnect(delay, apnContext, REQUEST_TYPE_NORMAL); - } - } - } else { - boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean( - com.android.internal.R.bool.config_restartRadioAfterProvisioning); - - if (apnContext.isProvisioningApn() && restartRadioAfterProvisioning) { - log("onDisconnectDone: restartRadio after provisioning"); - restartRadio(); - } - apnContext.setApnSetting(null); - apnContext.setDataConnection(null); - if (isOnlySingleDcAllowed(getDataRat())) { - if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn"); - setupDataOnAllConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION, - RetryFailures.ALWAYS); - } else { - if(DBG) log("onDisconnectDone: not retrying"); - } - } - - if (areAllDataDisconnected()) { - apnContext.setConcurrentVoiceAndDataAllowed( - mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()); - notifyAllDataDisconnected(); - } - - } - - private void onVoiceCallStarted() { - if (DBG) log("onVoiceCallStarted"); - mInVoiceCall = true; - if (isAnyDataConnected() - && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { - if (DBG) log("onVoiceCallStarted stop polling"); - stopNetStatPoll(); - stopDataStallAlarm(); - } - } - - protected void onVoiceCallEnded() { - if (DBG) log("onVoiceCallEnded"); - mInVoiceCall = false; - if (isAnyDataConnected()) { - if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) { - startNetStatPoll(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - } else { - // clean slate after call end. - resetPollStats(); - } - } - // reset reconnect timer - setupDataOnAllConnectableApns(Phone.REASON_VOICE_CALL_ENDED, RetryFailures.ALWAYS); - } - /** - * @return {@code true} if there is any data in connected state. - */ - @VisibleForTesting - public boolean isAnyDataConnected() { - for (DataConnection dc : mDataConnections.values()) { - if (dc.isActive()) { - return true; - } - } - return false; - } - - /** - * @return {@code true} if all data connections are in disconnected state. - */ - public boolean areAllDataDisconnected() { - for (DataConnection dc : mDataConnections.values()) { - if (!dc.isInactive()) { - if (DBG) log("areAllDataDisconnected false due to DC: " + dc.getName()); - return false; - } - } - return true; - } - - protected void setDataProfilesAsNeeded() { - if (DBG) log("setDataProfilesAsNeeded"); - - ArrayList dataProfileList = new ArrayList<>(); - - int preferredApnSetId = getPreferredApnSetId(); - for (ApnSetting apn : mAllApnSettings) { - if (apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID - || preferredApnSetId == apn.getApnSetId()) { - DataProfile dp = new DataProfile.Builder() - .setApnSetting(apn) - .setPreferred(apn.equals(getPreferredApn())) - .build(); - if (!dataProfileList.contains(dp)) { - dataProfileList.add(dp); - } - } else { - if (VDBG) { - log("setDataProfilesAsNeeded: APN set id " + apn.getApnSetId() - + " does not match the preferred set id " + preferredApnSetId); - } - } - } - - // Check if the data profiles we are sending are same as we did last time. We don't want to - // send the redundant profiles to the modem. Also if there the list is empty, we don't - // send it to the modem. - if (!dataProfileList.isEmpty() - && (dataProfileList.size() != mLastDataProfileList.size() - || !mLastDataProfileList.containsAll(dataProfileList))) { - mDataServiceManager.setDataProfile(dataProfileList, - mPhone.getServiceState().getDataRoamingFromRegistration(), null); - } - } - - /** - * Based on the sim operator numeric, create a list for all possible - * Data Connections and setup the preferredApn. - */ - protected void createAllApnList() { - mAllApnSettings.clear(); - String operator = mPhone.getOperatorNumeric(); - - // ORDER BY Telephony.Carriers._ID ("_id") - Cursor cursor = mPhone.getContext().getContentResolver().query( - Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, "filtered/subId/" - + mPhone.getSubId()), null, null, null, Telephony.Carriers._ID); - - if (cursor != null) { - while (cursor.moveToNext()) { - ApnSetting apn = ApnSetting.makeApnSetting(cursor); - if (apn == null) { - continue; - } - mAllApnSettings.add(apn); - } - cursor.close(); - } else { - if (DBG) log("createAllApnList: cursor is null"); - mApnSettingsInitializationLog.log("cursor is null for carrier, operator: " - + operator); - } - - dedupeApnSettings(); - - if (mAllApnSettings.isEmpty()) { - log("createAllApnList: No APN found for carrier, operator: " + operator); - mApnSettingsInitializationLog.log("no APN found for carrier, operator: " - + operator); - mPreferredApn = null; - } else { - mPreferredApn = getPreferredApn(); - if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn); - } - - addDefaultApnSettingsAsNeeded(); - if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings); - } - - private void dedupeApnSettings() { - ArrayList resultApns = new ArrayList(); - - // coalesce APNs if they are similar enough to prevent - // us from bringing up two data calls with the same interface - int i = 0; - while (i < mAllApnSettings.size() - 1) { - ApnSetting first = mAllApnSettings.get(i); - ApnSetting second = null; - int j = i + 1; - while (j < mAllApnSettings.size()) { - second = mAllApnSettings.get(j); - if (first.similar(second)) { - ApnSetting newApn = mergeApns(first, second); - mAllApnSettings.set(i, newApn); - first = newApn; - mAllApnSettings.remove(j); - } else { - j++; - } - } - i++; - } - } - - private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) { - int id = dest.getId(); - if ((src.getApnTypeBitmask() & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) { - id = src.getId(); - } - final int resultApnType = src.getApnTypeBitmask() | dest.getApnTypeBitmask(); - Uri mmsc = (dest.getMmsc() == null ? src.getMmsc() : dest.getMmsc()); - String mmsProxy = TextUtils.isEmpty(dest.getMmsProxyAddressAsString()) - ? src.getMmsProxyAddressAsString() : dest.getMmsProxyAddressAsString(); - int mmsPort = dest.getMmsProxyPort() == -1 ? src.getMmsProxyPort() : dest.getMmsProxyPort(); - String proxy = TextUtils.isEmpty(dest.getProxyAddressAsString()) - ? src.getProxyAddressAsString() : dest.getProxyAddressAsString(); - int port = dest.getProxyPort() == -1 ? src.getProxyPort() : dest.getProxyPort(); - int protocol = src.getProtocol() == ApnSetting.PROTOCOL_IPV4V6 ? src.getProtocol() - : dest.getProtocol(); - int roamingProtocol = src.getRoamingProtocol() == ApnSetting.PROTOCOL_IPV4V6 - ? src.getRoamingProtocol() : dest.getRoamingProtocol(); - int networkTypeBitmask = (dest.getNetworkTypeBitmask() == 0 - || src.getNetworkTypeBitmask() == 0) - ? 0 : (dest.getNetworkTypeBitmask() | src.getNetworkTypeBitmask()); - return new ApnSetting.Builder() - .setId(id) - .setOperatorNumeric(dest.getOperatorNumeric()) - .setEntryName(dest.getEntryName()) - .setApnName(dest.getApnName()) - .setProxyAddress(proxy) - .setProxyPort(port) - .setMmsc(mmsc) - .setMmsProxyAddress(mmsProxy) - .setMmsProxyPort(mmsPort) - .setUser(dest.getUser()) - .setPassword(dest.getPassword()) - .setAuthType(dest.getAuthType()) - .setApnTypeBitmask(resultApnType) - .setProtocol(protocol) - .setRoamingProtocol(roamingProtocol) - .setCarrierEnabled(dest.isEnabled()) - .setNetworkTypeBitmask(networkTypeBitmask) - .setProfileId(dest.getProfileId()) - .setModemCognitive(dest.isPersistent() || src.isPersistent()) - .setMaxConns(dest.getMaxConns()) - .setWaitTime(dest.getWaitTime()) - .setMaxConnsTime(dest.getMaxConnsTime()) - .setMtuV4(dest.getMtuV4()) - .setMtuV6(dest.getMtuV6()) - .setMvnoType(dest.getMvnoType()) - .setMvnoMatchData(dest.getMvnoMatchData()) - .setApnSetId(dest.getApnSetId()) - .setCarrierId(dest.getCarrierId()) - .setSkip464Xlat(dest.getSkip464Xlat()) - .build(); - } - - private DataConnection createDataConnection() { - if (DBG) log("createDataConnection E"); - - int id = mUniqueIdGenerator.getAndIncrement(); - DataConnection dataConnection = DataConnection.makeDataConnection(mPhone, id, this, - mDataServiceManager, mDcTesterFailBringUpAll, mDcc); - mDataConnections.put(id, dataConnection); - if (DBG) log("createDataConnection() X id=" + id + " dc=" + dataConnection); - return dataConnection; - } - - private void destroyDataConnections() { - if(mDataConnections != null) { - if (DBG) log("destroyDataConnections: clear mDataConnectionList"); - mDataConnections.clear(); - } else { - if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore"); - } - } - - /** - * Build a list of APNs to be used to create PDP's. - * - * @param requestedApnType - * @return waitingApns list to be used to create PDP - * error when waitingApns.isEmpty() - */ - private @NonNull ArrayList buildWaitingApns(String requestedApnType, - int radioTech) { - if (DBG) log("buildWaitingApns: E requestedApnType=" + requestedApnType); - ArrayList apnList = new ArrayList(); - - int requestedApnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(requestedApnType); - if (requestedApnTypeBitmask == ApnSetting.TYPE_ENTERPRISE) { - requestedApnTypeBitmask = ApnSetting.TYPE_DEFAULT; - } - if (requestedApnTypeBitmask == ApnSetting.TYPE_DUN) { - ArrayList dunApns = fetchDunApns(); - if (dunApns.size() > 0) { - for (ApnSetting dun : dunApns) { - apnList.add(dun); - if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList); - } - return apnList; - } - } - - String operator = mPhone.getOperatorNumeric(); - - // This is a workaround for a bug (7305641) where we don't failover to other - // suitable APNs if our preferred APN fails. On prepaid ATT sims we need to - // failover to a provisioning APN, but once we've used their default data - // connection we are locked to it for life. This change allows ATT devices - // to say they don't want to use preferred at all. - boolean usePreferred = true; - try { - usePreferred = !mPhone.getContext().getResources().getBoolean(com.android - .internal.R.bool.config_dontPreferApn); - } catch (Resources.NotFoundException e) { - if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true"); - usePreferred = true; - } - if (usePreferred) { - mPreferredApn = getPreferredApn(); - } - if (DBG) { - log("buildWaitingApns: usePreferred=" + usePreferred - + " canSetPreferApn=" + mCanSetPreferApn - + " mPreferredApn=" + mPreferredApn - + " operator=" + operator + " radioTech=" + radioTech); - } - - if (usePreferred && mCanSetPreferApn && mPreferredApn != null && - mPreferredApn.canHandleType(requestedApnTypeBitmask)) { - if (DBG) { - log("buildWaitingApns: Preferred APN:" + operator + ":" - + mPreferredApn.getOperatorNumeric() + ":" + mPreferredApn); - } - - if (TextUtils.equals(mPreferredApn.getOperatorNumeric(), operator) - || mPreferredApn.getCarrierId() == mPhone.getCarrierId()) { - if (mPreferredApn.canSupportNetworkType( - ServiceState.rilRadioTechnologyToNetworkType(radioTech))) { - // Create a new instance of ApnSetting for ENTERPRISE because each - // DataConnection should have its own ApnSetting. ENTERPRISE uses the same - // APN as DEFAULT but is a separate DataConnection - if (ApnSetting.getApnTypesBitmaskFromString(requestedApnType) - == ApnSetting.TYPE_ENTERPRISE) { - apnList.add(ApnSetting.makeApnSetting(mPreferredApn)); - } else { - apnList.add(mPreferredApn); - } - if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList); - return apnList; - } - } - if (DBG) log("buildWaitingApns: no preferred APN"); - setPreferredApn(-1); - mPreferredApn = null; - } - - if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings); - int preferredApnSetId = getPreferredApnSetId(); - for (ApnSetting apn : mAllApnSettings) { - if (apn.canHandleType(requestedApnTypeBitmask)) { - if (apn.canSupportNetworkType( - ServiceState.rilRadioTechnologyToNetworkType(radioTech))) { - if (apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID - || preferredApnSetId == apn.getApnSetId()) { - if (VDBG) log("buildWaitingApns: adding apn=" + apn); - // Create a new instance of ApnSetting for ENTERPRISE because each - // DataConnection should have its own ApnSetting. ENTERPRISE uses the same - // APN as DEFAULT but is a separate DataConnection - if (ApnSetting.getApnTypesBitmaskFromString(requestedApnType) - == ApnSetting.TYPE_ENTERPRISE) { - apnList.add(ApnSetting.makeApnSetting(apn)); - } else { - apnList.add(apn); - } - } else { - log("buildWaitingApns: APN set id " + apn.getApnSetId() - + " does not match the preferred set id " + preferredApnSetId); - } - } else { - if (DBG) { - log("buildWaitingApns: networkTypeBitmask:" - + apn.getNetworkTypeBitmask() - + " does not include radioTech:" - + ServiceState.rilRadioTechnologyToString(radioTech)); - } - } - } else if (VDBG) { - log("buildWaitingApns: couldn't handle requested ApnType=" - + requestedApnType); - } - } - - if (DBG) log("buildWaitingApns: " + apnList.size() + " APNs in the list: " + apnList); - return apnList; - } - - private String apnListToString (ArrayList apns) { - StringBuilder result = new StringBuilder(); - for (int i = 0, size = apns.size(); i < size; i++) { - result.append('[') - .append(apns.get(i).toString()) - .append(']'); - } - return result.toString(); - } - - private void setPreferredApn(int pos) { - setPreferredApn(pos, false); - } - - private void setPreferredApn(int pos, boolean force) { - if (!force && !mCanSetPreferApn) { - log("setPreferredApn: X !canSEtPreferApn"); - return; - } - - String subId = Long.toString(mPhone.getSubId()); - Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); - log("setPreferredApn: delete"); - ContentResolver resolver = mPhone.getContext().getContentResolver(); - resolver.delete(uri, null, null); - - if (pos >= 0) { - log("setPreferredApn: insert"); - ContentValues values = new ContentValues(); - values.put(APN_ID, pos); - resolver.insert(uri, values); - } - } - - @Nullable - ApnSetting getPreferredApn() { - //Only call this method from main thread - if (mAllApnSettings == null || mAllApnSettings.isEmpty()) { - log("getPreferredApn: mAllApnSettings is empty"); - return null; - } - - String subId = Long.toString(mPhone.getSubId()); - Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId); - Cursor cursor = mPhone.getContext().getContentResolver().query( - uri, new String[] { "_id", "name", "apn" }, - null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); - - if (cursor != null) { - mCanSetPreferApn = true; - } else { - mCanSetPreferApn = false; - } - - if (VDBG) { - log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor - + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0)); - } - - if (mCanSetPreferApn && cursor.getCount() > 0) { - int pos; - cursor.moveToFirst(); - pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); - for(ApnSetting p : mAllApnSettings) { - if (p.getId() == pos && p.canHandleType(mRequestedApnType)) { - log("getPreferredApn: For APN type " - + ApnSetting.getApnTypeString(mRequestedApnType) - + " found apnSetting " + p); - cursor.close(); - return p; - } - } - } - - if (cursor != null) { - cursor.close(); - } - - log("getPreferredApn: X not found"); - return null; - } - - @Override - public void handleMessage (Message msg) { - if (VDBG) log("handleMessage msg=" + msg); - - AsyncResult ar; - Pair pair; - ApnContext apnContext; - int generation; - int requestType; - int handoverFailureMode; - switch (msg.what) { - case DctConstants.EVENT_DATA_CONNECTION_DETACHED: - onDataConnectionDetached(); - break; - - case DctConstants.EVENT_DATA_CONNECTION_ATTACHED: - onDataConnectionAttached(); - break; - - case DctConstants.EVENT_DO_RECOVERY: - mDsRecoveryHandler.doRecovery(); - break; - - case DctConstants.EVENT_APN_CHANGED: - onApnChanged(); - break; - - case DctConstants.EVENT_PS_RESTRICT_ENABLED: - /** - * We don't need to explicitly to tear down the PDP context - * when PS restricted is enabled. The base band will deactive - * PDP context and notify us with PDP_CONTEXT_CHANGED. - * But we should stop the network polling and prevent reset PDP. - */ - if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); - stopNetStatPoll(); - stopDataStallAlarm(); - mIsPsRestricted = true; - break; - - case DctConstants.EVENT_PS_RESTRICT_DISABLED: - /** - * When PS restrict is removed, we need setup PDP connection if - * PDP connection is down. - */ - if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); - mIsPsRestricted = false; - if (isAnyDataConnected()) { - startNetStatPoll(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - } else { - // TODO: Should all PDN states be checked to fail? - if (mState == DctConstants.State.FAILED) { - cleanUpAllConnectionsInternal(false, Phone.REASON_PS_RESTRICT_ENABLED); - mReregisterOnReconnectFailure = false; - } - apnContext = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT); - if (apnContext != null) { - apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED); - trySetupData(apnContext, REQUEST_TYPE_NORMAL, null); - } else { - loge("**** Default ApnContext not found ****"); - if (TelephonyUtils.IS_DEBUGGABLE) { - throw new RuntimeException("Default ApnContext not found"); - } - } - } - break; - - case DctConstants.EVENT_TRY_SETUP_DATA: - apnContext = (ApnContext) msg.obj; - requestType = msg.arg1; - trySetupData(apnContext, requestType, null); - break; - case DctConstants.EVENT_CLEAN_UP_CONNECTION: - if (DBG) log("EVENT_CLEAN_UP_CONNECTION"); - cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, (ApnContext) msg.obj); - break; - case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS: - if ((msg.obj != null) && (msg.obj instanceof String == false)) { - msg.obj = null; - } - cleanUpAllConnectionsInternal(true, (String) msg.obj); - break; - - case DctConstants.EVENT_DATA_RAT_CHANGED: - if (getDataRat() == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) { - // unknown rat is an exception for data rat change. It's only received when out - // of service and is not applicable for apn bearer bitmask. We should bypass the - // check of waiting apn list and keep the data connection on, and no need to - // setup a new one. - break; - } - cleanUpConnectionsOnUpdatedApns(false, Phone.REASON_NW_TYPE_CHANGED); - //May new Network allow setupData, so try it here - setupDataOnAllConnectableApns(Phone.REASON_NW_TYPE_CHANGED, - RetryFailures.ONLY_ON_CHANGE); - break; - - case DctConstants.CMD_CLEAR_PROVISIONING_SPINNER: - // Check message sender intended to clear the current spinner. - if (mProvisioningSpinner == msg.obj) { - mProvisioningSpinner.dismiss(); - mProvisioningSpinner = null; - } - break; - - case DctConstants.EVENT_ENABLE_APN: - onEnableApn(msg.arg1, msg.arg2, (Message) msg.obj); - break; - - case DctConstants.EVENT_DISABLE_APN: - onDisableApn(msg.arg1, msg.arg2); - break; - - case DctConstants.EVENT_DATA_STALL_ALARM: - onDataStallAlarm(msg.arg1); - break; - - case DctConstants.EVENT_ROAMING_OFF: - onDataRoamingOff(); - break; - - case DctConstants.EVENT_ROAMING_ON: - case DctConstants.EVENT_ROAMING_SETTING_CHANGE: - onDataRoamingOnOrSettingsChanged(msg.what); - break; - - case DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE: - // Update sharedPreference to false when exits new device provisioning, indicating - // no users modifications on the settings for new devices. Thus carrier specific - // default roaming settings can be applied for new devices till user modification. - final SharedPreferences sp = PreferenceManager - .getDefaultSharedPreferences(mPhone.getContext()); - if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) { - sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit(); - } - break; - - case DctConstants.EVENT_NETWORK_STATUS_CHANGED: - int status = msg.arg1; - int cid = msg.arg2; - String url = (String) msg.obj; - onNetworkStatusChanged(status, cid, url); - break; - - case DctConstants.EVENT_RADIO_AVAILABLE: - onRadioAvailable(); - break; - - case DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE: - onRadioOffOrNotAvailable(); - break; - - case DctConstants.EVENT_DATA_SETUP_COMPLETE: - ar = (AsyncResult) msg.obj; - pair = (Pair) ar.userObj; - apnContext = pair.first; - generation = pair.second; - requestType = msg.arg1; - handoverFailureMode = msg.arg2; - if (apnContext.getConnectionGeneration() == generation) { - boolean success = true; - int cause = DataFailCause.UNKNOWN; - if (ar.exception != null) { - success = false; - cause = (int) ar.result; - } - onDataSetupComplete(apnContext, success, cause, requestType, - handoverFailureMode); - } else { - loge("EVENT_DATA_SETUP_COMPLETE: Dropped the event because generation " - + "did not match."); - } - break; - - case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR: - ar = (AsyncResult) msg.obj; - pair = (Pair) ar.userObj; - apnContext = pair.first; - generation = pair.second; - handoverFailureMode = msg.arg2; - if (apnContext.getConnectionGeneration() == generation) { - onDataSetupCompleteError(apnContext, handoverFailureMode, false); - } else { - loge("EVENT_DATA_SETUP_COMPLETE_ERROR: Dropped the event because generation " - + "did not match."); - } - break; - - case DctConstants.EVENT_DISCONNECT_DONE: - log("EVENT_DISCONNECT_DONE msg=" + msg); - ar = (AsyncResult) msg.obj; - pair = (Pair) ar.userObj; - apnContext = pair.first; - generation = pair.second; - if (apnContext.getConnectionGeneration() == generation) { - onDisconnectDone(apnContext); - } else { - loge("EVENT_DISCONNECT_DONE: Dropped the event because generation " - + "did not match."); - } - break; - - case DctConstants.EVENT_VOICE_CALL_STARTED: - onVoiceCallStarted(); - break; - - case DctConstants.EVENT_VOICE_CALL_ENDED: - onVoiceCallEnded(); - break; - case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: { - sEnableFailFastRefCounter += (msg.arg1 == DctConstants.ENABLED) ? 1 : -1; - if (DBG) { - log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: " - + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter); - } - if (sEnableFailFastRefCounter < 0) { - final String s = "CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: " - + "sEnableFailFastRefCounter:" + sEnableFailFastRefCounter + " < 0"; - loge(s); - sEnableFailFastRefCounter = 0; - } - final boolean enabled = sEnableFailFastRefCounter > 0; - if (DBG) { - log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled - + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter); - } - if (mFailFast != enabled) { - mFailFast = enabled; - - mDataStallNoRxEnabled = !enabled; - if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled() - && isAnyDataConnected() - && (!mInVoiceCall || - mPhone.getServiceStateTracker() - .isConcurrentVoiceAndDataAllowed())) { - if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall"); - stopDataStallAlarm(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - } else { - if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall"); - stopDataStallAlarm(); - } - } - - break; - } - case DctConstants.CMD_ENABLE_MOBILE_PROVISIONING: { - Bundle bundle = msg.getData(); - if (bundle != null) { - try { - mProvisioningUrl = (String)bundle.get(DctConstants.PROVISIONING_URL_KEY); - } catch(ClassCastException e) { - loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url not a string" + e); - mProvisioningUrl = null; - } - } - if (TextUtils.isEmpty(mProvisioningUrl)) { - loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url is empty, ignoring"); - mIsProvisioning = false; - mProvisioningUrl = null; - } else { - loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioningUrl=" + mProvisioningUrl); - mIsProvisioning = true; - startProvisioningApnAlarm(); - } - break; - } - case DctConstants.EVENT_PROVISIONING_APN_ALARM: { - if (DBG) log("EVENT_PROVISIONING_APN_ALARM"); - ApnContext apnCtx = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT); - if (apnCtx.isProvisioningApn() && apnCtx.isConnectedOrConnecting()) { - if (mProvisioningApnAlarmTag == msg.arg1) { - if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Disconnecting"); - mIsProvisioning = false; - mProvisioningUrl = null; - stopProvisioningApnAlarm(); - cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnCtx); - } else { - if (DBG) { - log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag," - + " mProvisioningApnAlarmTag:" + mProvisioningApnAlarmTag - + " != arg1:" + msg.arg1); - } - } - } else { - if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Not connected ignore"); - } - break; - } - case DctConstants.CMD_IS_PROVISIONING_APN: { - if (DBG) log("CMD_IS_PROVISIONING_APN"); - boolean isProvApn; - try { - String apnType = null; - Bundle bundle = msg.getData(); - if (bundle != null) { - apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY); - } - if (TextUtils.isEmpty(apnType)) { - loge("CMD_IS_PROVISIONING_APN: apnType is empty"); - isProvApn = false; - } else { - isProvApn = isProvisioningApn(apnType); - } - } catch (ClassCastException e) { - loge("CMD_IS_PROVISIONING_APN: NO provisioning url ignoring"); - isProvApn = false; - } - if (DBG) log("CMD_IS_PROVISIONING_APN: ret=" + isProvApn); - mReplyAc.replyToMessage(msg, DctConstants.CMD_IS_PROVISIONING_APN, - isProvApn ? DctConstants.ENABLED : DctConstants.DISABLED); - break; - } - case DctConstants.EVENT_RESTART_RADIO: { - restartRadio(); - break; - } - case DctConstants.CMD_NET_STAT_POLL: { - if (msg.arg1 == DctConstants.ENABLED) { - handleStartNetStatPoll((DctConstants.Activity)msg.obj); - } else if (msg.arg1 == DctConstants.DISABLED) { - handleStopNetStatPoll((DctConstants.Activity)msg.obj); - } - break; - } - case DctConstants.EVENT_PCO_DATA_RECEIVED: { - handlePcoData((AsyncResult)msg.obj); - break; - } - case DctConstants.EVENT_DATA_RECONNECT: - if (DBG) { - log("EVENT_DATA_RECONNECT: subId=" + msg.arg1 + ", type=" - + requestTypeToString(msg.arg2)); - } - onDataReconnect((ApnContext) msg.obj, msg.arg1, msg.arg2); - break; - case DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED: - onDataServiceBindingChanged((Boolean) ((AsyncResult) msg.obj).result); - break; - case DctConstants.EVENT_DATA_ENABLED_CHANGED: - ar = (AsyncResult) msg.obj; - if (ar.result instanceof Pair) { - Pair p = (Pair) ar.result; - boolean enabled = p.first; - int reason = p.second; - onDataEnabledChanged(enabled, reason); - } - break; - case DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED: - onDataEnabledOverrideRulesChanged(); - break; - case DctConstants.EVENT_NR_TIMER_WATCHDOG: - mWatchdog = false; - reevaluateUnmeteredConnections(); - break; - case DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED: - reevaluateCongestedConnections(); - reevaluateUnmeteredConnections(); - break; - case DctConstants.EVENT_CARRIER_CONFIG_CHANGED: - onCarrierConfigChanged(); - break; - case DctConstants.EVENT_SIM_STATE_UPDATED: - int simState = msg.arg1; - onSimStateUpdated(simState); - break; - case DctConstants.EVENT_APN_UNTHROTTLED: - ar = (AsyncResult) msg.obj; - String apn = (String) ar.result; - onApnUnthrottled(apn); - break; - case DctConstants.EVENT_TRAFFIC_DESCRIPTORS_UPDATED: - onTrafficDescriptorsUpdated(); - break; - default: - Rlog.e("DcTracker", "Unhandled event=" + msg); - break; - - } - } - - private int getApnProfileID(String apnType) { - if (TextUtils.equals(apnType, ApnSetting.TYPE_IMS_STRING)) { - return RILConstants.DATA_PROFILE_IMS; - } else if (TextUtils.equals(apnType, ApnSetting.TYPE_FOTA_STRING)) { - return RILConstants.DATA_PROFILE_FOTA; - } else if (TextUtils.equals(apnType, ApnSetting.TYPE_CBS_STRING)) { - return RILConstants.DATA_PROFILE_CBS; - } else if (TextUtils.equals(apnType, ApnSetting.TYPE_IA_STRING)) { - return RILConstants.DATA_PROFILE_DEFAULT; // DEFAULT for now - } else if (TextUtils.equals(apnType, ApnSetting.TYPE_DUN_STRING)) { - return RILConstants.DATA_PROFILE_TETHERED; - } else { - return RILConstants.DATA_PROFILE_DEFAULT; - } - } - - private int getCellLocationId() { - int cid = -1; - CellLocation loc = mPhone.getCurrentCellIdentity().asCellLocation(); - - if (loc != null) { - if (loc instanceof GsmCellLocation) { - cid = ((GsmCellLocation)loc).getCid(); - } else if (loc instanceof CdmaCellLocation) { - cid = ((CdmaCellLocation)loc).getBaseStationId(); - } - } - return cid; - } - - /** - * Update link bandwidth estimate default values from carrier config. - * @param bandwidths String array of "RAT:upstream,downstream" for each RAT - * @param useLte For NR NSA, whether to use LTE value for upstream or not - */ - private void updateLinkBandwidths(String[] bandwidths, boolean useLte) { - ConcurrentHashMap> temp = new ConcurrentHashMap<>(); - for (String config : bandwidths) { - int downstream = 14; - int upstream = 14; - String[] kv = config.split(":"); - if (kv.length == 2) { - String[] split = kv[1].split(","); - if (split.length == 2) { - try { - downstream = Integer.parseInt(split[0]); - upstream = Integer.parseInt(split[1]); - } catch (NumberFormatException ignored) { - } - } - temp.put(kv[0], new Pair<>(downstream, upstream)); - } - } - if (useLte) { - Pair ltePair = - temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_LTE); - if (ltePair != null) { - if (temp.containsKey(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA)) { - temp.put(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA, new Pair<>( - temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA).first, - ltePair.second)); - } - if (temp.containsKey(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE)) { - temp.put(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE, new Pair<>( - temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE) - .first, ltePair.second)); - } - } - } - mBandwidths = temp; - for (DataConnection dc : mDataConnections.values()) { - dc.sendMessage(DataConnection.EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED); - } - } - - /** - * Return the link upstream/downstream values from CarrierConfig for the given RAT name. - * @param ratName RAT name from ServiceState#rilRadioTechnologyToString. - * @return pair of downstream/upstream values (kbps), or null if the config is not defined. - */ - public Pair getLinkBandwidthsFromCarrierConfig(String ratName) { - return mBandwidths.get(ratName); - } - - @VisibleForTesting - public boolean shouldAutoAttach() { - if (mAutoAttachEnabled.get()) return true; - - PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); - ServiceState serviceState = mPhone.getServiceState(); - - if (phoneSwitcher == null || serviceState == null) return false; - - // If voice is also not in service, don't auto attach. - if (serviceState.getState() != ServiceState.STATE_IN_SERVICE) return false; - - // If voice is on LTE or NR, don't auto attach as for LTE / NR data would be attached. - if (serviceState.getVoiceNetworkType() == NETWORK_TYPE_LTE - || serviceState.getVoiceNetworkType() == NETWORK_TYPE_NR) return false; - - // If phone is non default phone, modem may have detached from data for optimization. - // If phone is in voice call, for DSDS case DDS switch may be limited so we do try our - // best to setup data connection and allow auto-attach. - return (mPhone.getPhoneId() != phoneSwitcher.getPreferredDataPhoneId() - || mPhone.getState() != PhoneConstants.State.IDLE); - } - - private void notifyAllDataDisconnected() { - sEnableFailFastRefCounter = 0; - mFailFast = false; - log("notify all data disconnected"); - mAllDataDisconnectedRegistrants.notifyRegistrants(); - } - - public void registerForAllDataDisconnected(Handler h, int what) { - mAllDataDisconnectedRegistrants.addUnique(h, what, null); - - if (areAllDataDisconnected()) { - notifyAllDataDisconnected(); - } - } - - public void unregisterForAllDataDisconnected(Handler h) { - mAllDataDisconnectedRegistrants.remove(h); - } - - private void onDataEnabledChanged(boolean enable, - @DataEnabledChangedReason int enabledChangedReason) { - if (DBG) { - log("onDataEnabledChanged: enable=" + enable + ", enabledChangedReason=" - + enabledChangedReason); - } - - if (enable) { - reevaluateDataConnections(); - setupDataOnAllConnectableApns(Phone.REASON_DATA_ENABLED, RetryFailures.ALWAYS); - } else { - String cleanupReason; - switch (enabledChangedReason) { - case DataEnabledSettings.REASON_INTERNAL_DATA_ENABLED: - cleanupReason = Phone.REASON_DATA_DISABLED_INTERNAL; - break; - case DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER: - cleanupReason = Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN; - break; - case DataEnabledSettings.REASON_USER_DATA_ENABLED: - case DataEnabledSettings.REASON_POLICY_DATA_ENABLED: - case DataEnabledSettings.REASON_PROVISIONED_CHANGED: - case DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED: - default: - cleanupReason = Phone.REASON_DATA_SPECIFIC_DISABLED; - break; - - } - cleanUpAllConnectionsInternal(true, cleanupReason); - } - } - - private void reevaluateCongestedConnections() { - log("reevaluateCongestedConnections"); - int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); - // congested override and either network is specified or unknown and all networks specified - boolean isCongested = mCongestedOverride && (mCongestedNetworkTypes.contains(rat) - || mCongestedNetworkTypes.containsAll(Arrays.stream( - TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet()))); - for (DataConnection dataConnection : mDataConnections.values()) { - dataConnection.onCongestednessChanged(isCongested); - } - } - - private void reevaluateUnmeteredConnections() { - log("reevaluateUnmeteredConnections"); - int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); - if (isNrUnmetered() && (!mPhone.getServiceState().getRoaming() || mNrNsaRoamingUnmetered)) { - setDataConnectionUnmetered(true); - if (!mWatchdog) { - startWatchdogAlarm(); - } - } else { - stopWatchdogAlarm(); - setDataConnectionUnmetered(isNetworkTypeUnmetered(rat)); - } - } - - private void setDataConnectionUnmetered(boolean isUnmetered) { - if (!isUnmetered || isTempNotMeteredSupportedByCarrier()) { - for (DataConnection dataConnection : mDataConnections.values()) { - dataConnection.onMeterednessChanged(isUnmetered); - } - } - } - - private boolean isNetworkTypeUnmetered(@NetworkType int networkType) { - boolean isUnmetered; - if (mUnmeteredNetworkTypes == null || !mUnmeteredOverride) { - // check SubscriptionPlans if override is not defined - isUnmetered = isNetworkTypeUnmeteredViaSubscriptionPlan(networkType); - log("isNetworkTypeUnmeteredViaSubscriptionPlan: networkType=" + networkType - + ", isUnmetered=" + isUnmetered); - return isUnmetered; - } - // unmetered override and either network is specified or unknown and all networks specified - isUnmetered = mUnmeteredNetworkTypes.contains(networkType) - || mUnmeteredNetworkTypes.containsAll(Arrays.stream( - TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet())); - if (DBG) { - log("isNetworkTypeUnmetered: networkType=" + networkType - + ", isUnmetered=" + isUnmetered); - } - return isUnmetered; - } - - private boolean isNetworkTypeUnmeteredViaSubscriptionPlan(@NetworkType int networkType) { - if (mSubscriptionPlans.isEmpty()) { - // safe return false if unable to get subscription plans or plans don't exist - return false; - } - - boolean isGeneralUnmetered = true; - Set allNetworkTypes = Arrays.stream(TelephonyManager.getAllNetworkTypes()) - .boxed().collect(Collectors.toSet()); - for (SubscriptionPlan plan : mSubscriptionPlans) { - // check plan is general (applies to all network types) or specific - if (Arrays.stream(plan.getNetworkTypes()).boxed().collect(Collectors.toSet()) - .containsAll(allNetworkTypes)) { - if (!isPlanUnmetered(plan)) { - // metered takes precedence over unmetered for safety - isGeneralUnmetered = false; - } - } else { - // check plan applies to given network type - if (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN) { - for (int planNetworkType : plan.getNetworkTypes()) { - if (planNetworkType == networkType) { - return isPlanUnmetered(plan); - } - } - } - } - } - return isGeneralUnmetered; - } - - private boolean isPlanUnmetered(SubscriptionPlan plan) { - return plan.getDataLimitBytes() == SubscriptionPlan.BYTES_UNLIMITED; - } - - private boolean isNrUnmetered() { - int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType(); - int override = mPhone.getDisplayInfoController().getTelephonyDisplayInfo() - .getOverrideNetworkType(); - - if (isNetworkTypeUnmetered(NETWORK_TYPE_NR)) { - if (mNrNsaMmwaveUnmetered) { - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) { - if (DBG) log("NR unmetered for mmwave only"); - return true; - } - return false; - } else if (mNrNsaSub6Unmetered) { - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { - if (DBG) log("NR unmetered for sub6 only"); - return true; - } - return false; - } - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED - || override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA - || rat == NETWORK_TYPE_NR) { - if (DBG) log("NR unmetered for all frequencies"); - return true; - } - return false; - } - - if (mNrNsaAllUnmetered) { - if (mNrNsaMmwaveUnmetered) { - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) { - if (DBG) log("NR NSA unmetered for mmwave only via carrier configs"); - return true; - } - return false; - } else if (mNrNsaSub6Unmetered) { - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { - if (DBG) log("NR NSA unmetered for sub6 only via carrier configs"); - return true; - } - return false; - } - if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED - || override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) { - if (DBG) log("NR NSA unmetered for all frequencies via carrier configs"); - return true; - } - return false; - } - - if (mNrSaAllUnmetered) { - // TODO: add logic for mNrSaMmwaveUnmetered and mNrSaSub6Unmetered once it's defined - // in TelephonyDisplayInfo - if (rat == NETWORK_TYPE_NR) { - if (DBG) log("NR SA unmetered for all frequencies via carrier configs"); - return true; - } - return false; - } - - return false; - } - - private boolean isTempNotMeteredSupportedByCarrier() { - CarrierConfigManager configManager = - mPhone.getContext().getSystemService(CarrierConfigManager.class); - if (configManager != null) { - PersistableBundle bundle = configManager.getConfigForSubId(mPhone.getSubId()); - if (bundle != null) { - return bundle.getBoolean( - CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL); - } - } - - return false; - } - - protected void log(String s) { - Rlog.d(mLogTag, s); - } - - private void loge(String s) { - Rlog.e(mLogTag, s); - } - - private void logSortedApnContexts() { - if (VDBG) { - log("initApnContexts: X mApnContexts=" + mApnContexts); - - StringBuilder sb = new StringBuilder(); - sb.append("sorted apncontexts -> ["); - for (ApnContext apnContext : mPrioritySortedApnContexts) { - sb.append(apnContext); - sb.append(", "); - - log("sorted list"); - } - sb.append("]"); - log(sb.toString()); - } - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("DcTracker:"); - pw.println(" RADIO_TESTS=" + RADIO_TESTS); - pw.println(" mDataEnabledSettings=" + mDataEnabledSettings); - pw.println(" isDataAllowed=" + isDataAllowed(null)); - pw.flush(); - pw.println(" mRequestedApnType=" + mRequestedApnType); - pw.println(" mPhone=" + mPhone.getPhoneName()); - pw.println(" mConfigReady=" + mConfigReady); - pw.println(" mSimState=" + SubscriptionInfoUpdater.simStateString(mSimState)); - pw.println(" mActivity=" + mActivity); - pw.println(" mState=" + mState); - pw.println(" mTxPkts=" + mTxPkts); - pw.println(" mRxPkts=" + mRxPkts); - pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod); - pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled); - pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum); - pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag); - pw.println(" mDataStallNoRxEnabled=" + mDataStallNoRxEnabled); - pw.println(" mEmergencyApn=" + mEmergencyApn); - pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv); - pw.println(" mNoRecvPollCount=" + mNoRecvPollCount); - pw.println(" mResolver=" + mResolver); - pw.println(" mReconnectIntent=" + mReconnectIntent); - pw.println(" mAutoAttachEnabled=" + mAutoAttachEnabled.get()); - pw.println(" mIsScreenOn=" + mIsScreenOn); - pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator); - pw.println(" mDataServiceBound=" + mDataServiceBound); - pw.println(" mDataRoamingLeakageLog= "); - mDataRoamingLeakageLog.dump(fd, pw, args); - pw.println(" mApnSettingsInitializationLog= "); - mApnSettingsInitializationLog.dump(fd, pw, args); - pw.flush(); - pw.println(" ***************************************"); - DcController dcc = mDcc; - if (dcc != null) { - if (mDataServiceBound) { - dcc.dump(fd, pw, args); - } else { - pw.println(" Can't dump mDcc because data service is not bound."); - } - } else { - pw.println(" mDcc=null"); - } - pw.println(" ***************************************"); - HashMap dcs = mDataConnections; - if (dcs != null) { - Set > mDcSet = mDataConnections.entrySet(); - pw.println(" mDataConnections: count=" + mDcSet.size()); - for (Entry entry : mDcSet) { - pw.printf(" *** mDataConnection[%d] \n", entry.getKey()); - entry.getValue().dump(fd, pw, args); - } - } else { - pw.println("mDataConnections=null"); - } - pw.println(" ***************************************"); - pw.flush(); - HashMap apnToDcId = mApnToDataConnectionId; - if (apnToDcId != null) { - Set> apnToDcIdSet = apnToDcId.entrySet(); - pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size()); - for (Entry entry : apnToDcIdSet) { - pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue()); - } - } else { - pw.println("mApnToDataConnectionId=null"); - } - pw.println(" ***************************************"); - pw.flush(); - ConcurrentHashMap apnCtxs = mApnContexts; - if (apnCtxs != null) { - Set> apnCtxsSet = apnCtxs.entrySet(); - pw.println(" mApnContexts size=" + apnCtxsSet.size()); - for (Entry entry : apnCtxsSet) { - entry.getValue().dump(fd, pw, args); - } - ApnContext.dumpLocalLog(fd, pw, args); - pw.println(" ***************************************"); - } else { - pw.println(" mApnContexts=null"); - } - pw.flush(); - - pw.println(" mAllApnSettings size=" + mAllApnSettings.size()); - for (int i = 0; i < mAllApnSettings.size(); i++) { - pw.printf(" mAllApnSettings[%d]: %s\n", i, mAllApnSettings.get(i)); - } - pw.flush(); - - pw.println(" mPreferredApn=" + mPreferredApn); - pw.println(" mIsPsRestricted=" + mIsPsRestricted); - pw.println(" mIsDisposed=" + mIsDisposed); - pw.println(" mIntentReceiver=" + mIntentReceiver); - pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure); - pw.println(" canSetPreferApn=" + mCanSetPreferApn); - pw.println(" mApnObserver=" + mApnObserver); - pw.println(" isAnyDataConnected=" + isAnyDataConnected()); - pw.println(" mAttached=" + mAttached.get()); - mDataEnabledSettings.dump(fd, pw, args); - pw.flush(); - } - - public String[] getPcscfAddress(String apnType) { - log("getPcscfAddress()"); - ApnContext apnContext = null; - - if(apnType == null){ - log("apnType is null, return null"); - return null; - } - - if (TextUtils.equals(apnType, ApnSetting.TYPE_EMERGENCY_STRING)) { - apnContext = mApnContextsByType.get(ApnSetting.TYPE_EMERGENCY); - } else if (TextUtils.equals(apnType, ApnSetting.TYPE_IMS_STRING)) { - apnContext = mApnContextsByType.get(ApnSetting.TYPE_IMS); - } else { - log("apnType is invalid, return null"); - return null; - } - - if (apnContext == null) { - log("apnContext is null, return null"); - return null; - } - - DataConnection dataConnection = apnContext.getDataConnection(); - String[] result = null; - - if (dataConnection != null) { - result = dataConnection.getPcscfAddresses(); - - if (result != null) { - for (int i = 0; i < result.length; i++) { - log("Pcscf[" + i + "]: " + result[i]); - } - } - return result; - } - return null; - } - - /** - * Create default apn settings for the apn type like emergency, and ims - */ - private ApnSetting buildDefaultApnSetting(@NonNull String entry, - @NonNull String apn, @ApnType int apnTypeBitmask) { - return new ApnSetting.Builder() - .setEntryName(entry) - .setProtocol(ApnSetting.PROTOCOL_IPV4V6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6) - .setApnName(apn) - .setApnTypeBitmask(apnTypeBitmask) - .setCarrierEnabled(true) - .setApnSetId(Telephony.Carriers.MATCH_ALL_APN_SET_ID) - .build(); - } - - /** - * Add default APN settings to APN settings list as needed - */ - private void addDefaultApnSettingsAsNeeded() { - boolean isEmergencyApnConfigured = false; - boolean isImsApnConfigured = false; - - for (ApnSetting apn : mAllApnSettings) { - if (apn.canHandleType(ApnSetting.TYPE_EMERGENCY)) { - isEmergencyApnConfigured = true; - } - if (apn.canHandleType(ApnSetting.TYPE_IMS)) { - isImsApnConfigured = true; - } - if (isEmergencyApnConfigured && isImsApnConfigured) { - log("Both emergency and ims apn setting are already present"); - return; - } - } - - // Add default apn setting for emergency service if it is not present - if (!isEmergencyApnConfigured) { - mAllApnSettings.add(buildDefaultApnSetting( - "DEFAULT EIMS", "sos", ApnSetting.TYPE_EMERGENCY)); - log("default emergency apn is created"); - } - - // Only add default apn setting for ims when it is not present and sim is loaded - if (!isImsApnConfigured && mSimState == TelephonyManager.SIM_STATE_LOADED) { - mAllApnSettings.add(buildDefaultApnSetting( - "DEFAULT IMS", "ims", ApnSetting.TYPE_IMS)); - log("default ims apn is created"); - } - } - - private void cleanUpConnectionsOnUpdatedApns(boolean detach, String reason) { - if (DBG) log("cleanUpConnectionsOnUpdatedApns: detach=" + detach); - if (mAllApnSettings.isEmpty()) { - cleanUpAllConnectionsInternal(detach, Phone.REASON_APN_CHANGED); - } else { - if (getDataRat() == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) { - // unknown rat is an exception for data rat change. Its only received when out of - // service and is not applicable for apn bearer bitmask. We should bypass the check - // of waiting apn list and keep the data connection on. - return; - } - for (ApnContext apnContext : mApnContexts.values()) { - boolean cleanupRequired = true; - if (!apnContext.isDisconnected()) { - ArrayList waitingApns = buildWaitingApns( - apnContext.getApnType(), getDataRat()); - if (apnContext.getWaitingApns().size() != waitingApns.size() - || !apnContext.getWaitingApns().containsAll(waitingApns)) { - apnContext.setWaitingApns(waitingApns); - } - for (ApnSetting apnSetting : waitingApns) { - if (areCompatible(apnSetting, apnContext.getApnSetting())) { - cleanupRequired = false; - break; - } - } - - if (cleanupRequired) { - if (DBG) { - log("cleanUpConnectionsOnUpdatedApns: APN type " - + apnContext.getApnType() + " clean up is required. The new " - + "waiting APN list " + waitingApns + " does not cover " - + apnContext.getApnSetting()); - } - apnContext.setReason(reason); - cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnContext); - } - } - } - } - - if (!isAnyDataConnected()) { - stopNetStatPoll(); - stopDataStallAlarm(); - } - - mRequestedApnType = ApnSetting.TYPE_DEFAULT; - - if (areAllDataDisconnected()) { - notifyAllDataDisconnected(); - } - } - - /** - * Polling stuff - */ - protected void resetPollStats() { - mTxPkts = -1; - mRxPkts = -1; - mNetStatPollPeriod = POLL_NETSTAT_MILLIS; - } - - protected void startNetStatPoll() { - if (isAnyDataConnected() && !mNetStatPollEnabled) { - if (DBG) { - log("startNetStatPoll"); - } - resetPollStats(); - mNetStatPollEnabled = true; - mPollNetStat.run(); - } - if (mPhone != null) { - mPhone.notifyDataActivity(); - } - } - - protected void stopNetStatPoll() { - mNetStatPollEnabled = false; - removeCallbacks(mPollNetStat); - if (DBG) { - log("stopNetStatPoll"); - } - - // To sync data activity icon in the case of switching data connection to send MMS. - if (mPhone != null) { - mPhone.notifyDataActivity(); - } - } - - public void sendStartNetStatPoll(DctConstants.Activity activity) { - Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL); - msg.arg1 = DctConstants.ENABLED; - msg.obj = activity; - sendMessage(msg); - } - - private void handleStartNetStatPoll(DctConstants.Activity activity) { - startNetStatPoll(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - setActivity(activity); - } - - public void sendStopNetStatPoll(DctConstants.Activity activity) { - Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL); - msg.arg1 = DctConstants.DISABLED; - msg.obj = activity; - sendMessage(msg); - } - - private void handleStopNetStatPoll(DctConstants.Activity activity) { - stopNetStatPoll(); - stopDataStallAlarm(); - setActivity(activity); - } - - private void onDataEnabledOverrideRulesChanged() { - if (DBG) { - log("onDataEnabledOverrideRulesChanged"); - } - - for (ApnContext apnContext : mPrioritySortedApnContexts) { - if (isDataAllowed(apnContext, REQUEST_TYPE_NORMAL, null)) { - if (apnContext.getDataConnection() != null) { - apnContext.getDataConnection().reevaluateRestrictedState(); - } - setupDataOnConnectableApn(apnContext, Phone.REASON_DATA_ENABLED_OVERRIDE, - RetryFailures.ALWAYS); - } else if (shouldCleanUpConnection(apnContext, true, false)) { - apnContext.setReason(Phone.REASON_DATA_ENABLED_OVERRIDE); - cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnContext); - } - } - } - - private void updateDataActivity() { - long sent, received; - - DctConstants.Activity newActivity; - - TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts); - TxRxSum curTxRxSum = new TxRxSum(); - curTxRxSum.updateTotalTxRxSum(); - mTxPkts = curTxRxSum.txPkts; - mRxPkts = curTxRxSum.rxPkts; - - if (VDBG) { - log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum); - } - - if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) { - sent = mTxPkts - preTxRxSum.txPkts; - received = mRxPkts - preTxRxSum.rxPkts; - - if (VDBG) - log("updateDataActivity: sent=" + sent + " received=" + received); - if (sent > 0 && received > 0) { - newActivity = DctConstants.Activity.DATAINANDOUT; - } else if (sent > 0 && received == 0) { - newActivity = DctConstants.Activity.DATAOUT; - } else if (sent == 0 && received > 0) { - newActivity = DctConstants.Activity.DATAIN; - } else { - newActivity = (mActivity == DctConstants.Activity.DORMANT) ? - mActivity : DctConstants.Activity.NONE; - } - - if (mActivity != newActivity && mIsScreenOn) { - if (VDBG) - log("updateDataActivity: newActivity=" + newActivity); - mActivity = newActivity; - mPhone.notifyDataActivity(); - } - } - } - - private void handlePcoData(AsyncResult ar) { - if (ar.exception != null) { - loge("PCO_DATA exception: " + ar.exception); - return; - } - PcoData pcoData = (PcoData)(ar.result); - ArrayList dcList = new ArrayList<>(); - DataConnection temp = mDcc.getActiveDcByCid(pcoData.cid); - if (temp != null) { - dcList.add(temp); - } - if (dcList.size() == 0) { - loge("PCO_DATA for unknown cid: " + pcoData.cid + ", inferring"); - for (DataConnection dc : mDataConnections.values()) { - final int cid = dc.getCid(); - if (cid == pcoData.cid) { - if (VDBG) log(" found " + dc); - dcList.clear(); - dcList.add(dc); - break; - } - // check if this dc is still connecting - if (cid == -1) { - for (ApnContext apnContext : dc.getApnContexts()) { - if (apnContext.getState() == DctConstants.State.CONNECTING) { - if (VDBG) log(" found potential " + dc); - dcList.add(dc); - break; - } - } - } - } - } - if (dcList.size() == 0) { - loge("PCO_DATA - couldn't infer cid"); - return; - } - for (DataConnection dc : dcList) { - List apnContextList = dc.getApnContexts(); - if (apnContextList.size() == 0) { - break; - } - // send one out for each apn type in play - for (ApnContext apnContext : apnContextList) { - String apnType = apnContext.getApnType(); - - final Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE); - intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, - ApnSetting.getApnTypesBitmaskFromString(apnType)); - intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL, - ApnSetting.getProtocolIntFromString(pcoData.bearerProto)); - intent.putExtra(TelephonyManager.EXTRA_PCO_ID, pcoData.pcoId); - intent.putExtra(TelephonyManager.EXTRA_PCO_VALUE, pcoData.contents); - mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent); - } - } - } - - /** - * Data-Stall - */ - - // Recovery action taken in case of data stall - @IntDef( - value = { - RECOVERY_ACTION_GET_DATA_CALL_LIST, - RECOVERY_ACTION_CLEANUP, - RECOVERY_ACTION_REREGISTER, - RECOVERY_ACTION_RADIO_RESTART - }) - @Retention(RetentionPolicy.SOURCE) - public @interface RecoveryAction {}; - private static final int RECOVERY_ACTION_GET_DATA_CALL_LIST = 0; - private static final int RECOVERY_ACTION_CLEANUP = 1; - private static final int RECOVERY_ACTION_REREGISTER = 2; - private static final int RECOVERY_ACTION_RADIO_RESTART = 3; - - // Recovery handler class for cellular data stall - private class DataStallRecoveryHandler { - // Default minimum duration between each recovery steps - private static final int - DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS = (3 * 60 * 1000); // 3 mins - - // The elapsed real time of last recovery attempted - private long mTimeLastRecoveryStartMs; - // Whether current network good or not - private boolean mIsValidNetwork; - // Whether data stall happened or not. - private boolean mWasDataStall; - // Whether the result of last action(RADIO_RESTART) reported. - private boolean mLastActionReported; - // The real time for data stall start. - private long mDataStallStartMs; - // Last data stall action. - private @RecoveryAction int mLastAction; - - public DataStallRecoveryHandler() { - reset(); - } - - public void reset() { - mTimeLastRecoveryStartMs = 0; - putRecoveryAction(RECOVERY_ACTION_GET_DATA_CALL_LIST); - } - - private void setNetworkValidationState(boolean isValid) { - // Validation status is true and was not data stall. - if (isValid && !mWasDataStall) { - return; - } - - if (!mWasDataStall) { - mWasDataStall = true; - mDataStallStartMs = SystemClock.elapsedRealtime(); - if (DBG) log("data stall: start time = " + mDataStallStartMs); - return; - } - - if (!mLastActionReported) { - int timeDuration = (int) (SystemClock.elapsedRealtime() - mDataStallStartMs); - if (DBG) { - log("data stall: lastaction = " + mLastAction + ", isRecovered = " - + isValid + ", mTimeDuration = " + timeDuration); - } - DataStallRecoveryStats.onDataStallEvent(mLastAction, mPhone, isValid, - timeDuration); - mLastActionReported = true; - } - - if (isValid) { - mLastActionReported = false; - mWasDataStall = false; - } - } - - public boolean isAggressiveRecovery() { - @RecoveryAction int action = getRecoveryAction(); - - return ((action == RECOVERY_ACTION_CLEANUP) - || (action == RECOVERY_ACTION_REREGISTER) - || (action == RECOVERY_ACTION_RADIO_RESTART)); - } - - private long getMinDurationBetweenRecovery() { - return Settings.Global.getLong(mResolver, - Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, - DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS); - } - - private long getElapsedTimeSinceRecoveryMs() { - return (SystemClock.elapsedRealtime() - mTimeLastRecoveryStartMs); - } - - @RecoveryAction - private int getRecoveryAction() { - @RecoveryAction int action = Settings.System.getInt(mResolver, - "radio.data.stall.recovery.action", RECOVERY_ACTION_GET_DATA_CALL_LIST); - if (VDBG_STALL) log("getRecoveryAction: " + action); - return action; - } - - private void putRecoveryAction(@RecoveryAction int action) { - Settings.System.putInt(mResolver, "radio.data.stall.recovery.action", action); - if (VDBG_STALL) log("putRecoveryAction: " + action); - } - - private void broadcastDataStallDetected(@RecoveryAction int recoveryAction) { - Intent intent = new Intent(TelephonyManager.ACTION_DATA_STALL_DETECTED); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); - intent.putExtra(TelephonyManager.EXTRA_RECOVERY_ACTION, recoveryAction); - mPhone.getContext().sendBroadcast(intent, READ_PRIVILEGED_PHONE_STATE); - } - - private boolean isRecoveryAlreadyStarted() { - return getRecoveryAction() != RECOVERY_ACTION_GET_DATA_CALL_LIST; - } - - private boolean checkRecovery() { - // To avoid back to back recovery wait for a grace period - if (getElapsedTimeSinceRecoveryMs() < getMinDurationBetweenRecovery()) { - if (VDBG_STALL) log("skip back to back data stall recovery"); - return false; - } - - // Skip recovery if it can cause a call to drop - if (mPhone.getState() != PhoneConstants.State.IDLE - && getRecoveryAction() > RECOVERY_ACTION_CLEANUP) { - if (VDBG_STALL) log("skip data stall recovery as there is an active call"); - return false; - } - - // Allow recovery if data is expected to work - return mAttached.get() && isDataAllowed(null); - } - - private void triggerRecovery() { - // Updating the recovery start time early to avoid race when - // the message is being processed in the Queue - mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime(); - sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY)); - } - - public void doRecovery() { - if (isAnyDataConnected()) { - // Go through a series of recovery steps, each action transitions to the next action - @RecoveryAction final int recoveryAction = getRecoveryAction(); - final int signalStrength = mPhone.getSignalStrength().getLevel(); - TelephonyMetrics.getInstance().writeSignalStrengthEvent( - mPhone.getPhoneId(), signalStrength); - TelephonyMetrics.getInstance().writeDataStallEvent( - mPhone.getPhoneId(), recoveryAction); - mLastAction = recoveryAction; - mLastActionReported = false; - broadcastDataStallDetected(recoveryAction); - - switch (recoveryAction) { - case RECOVERY_ACTION_GET_DATA_CALL_LIST: - EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST, - mSentSinceLastRecv); - if (DBG) log("doRecovery() get data call list"); - mDataServiceManager.requestDataCallList(obtainMessage()); - putRecoveryAction(RECOVERY_ACTION_CLEANUP); - break; - case RECOVERY_ACTION_CLEANUP: - EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, - mSentSinceLastRecv); - if (DBG) log("doRecovery() cleanup all connections"); - cleanUpConnection(mApnContexts.get(ApnSetting.getApnTypeString( - ApnSetting.TYPE_DEFAULT))); - cleanUpConnection(mApnContexts.get(ApnSetting.getApnTypeString( - ApnSetting.TYPE_ENTERPRISE))); - putRecoveryAction(RECOVERY_ACTION_REREGISTER); - break; - case RECOVERY_ACTION_REREGISTER: - EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER, - mSentSinceLastRecv); - if (DBG) log("doRecovery() re-register"); - mPhone.getServiceStateTracker().reRegisterNetwork(null); - putRecoveryAction(RECOVERY_ACTION_RADIO_RESTART); - break; - case RECOVERY_ACTION_RADIO_RESTART: - EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART, - mSentSinceLastRecv); - if (DBG) log("restarting radio"); - restartRadio(); - reset(); - break; - default: - throw new RuntimeException("doRecovery: Invalid recoveryAction=" - + recoveryAction); - } - mSentSinceLastRecv = 0; - } - } - - public void processNetworkStatusChanged(boolean isValid) { - setNetworkValidationState(isValid); - if (isValid) { - mIsValidNetwork = true; - reset(); - } else { - if (mIsValidNetwork || isRecoveryAlreadyStarted()) { - mIsValidNetwork = false; - // Check and trigger a recovery if network switched from good - // to bad or recovery is already started before. - if (checkRecovery()) { - if (DBG) log("trigger data stall recovery"); - triggerRecovery(); - } - } - } - } - - public boolean isRecoveryOnBadNetworkEnabled() { - return Settings.Global.getInt(mResolver, - Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1) == 1; - } - - public boolean isNoRxDataStallDetectionEnabled() { - return mDataStallNoRxEnabled && !isRecoveryOnBadNetworkEnabled(); - } - } - - private void updateDataStallInfo() { - long sent, received; - - TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum); - mDataStallTxRxSum.updateTotalTxRxSum(); - - if (VDBG_STALL) { - log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum + - " preTxRxSum=" + preTxRxSum); - } - - sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts; - received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts; - - if (RADIO_TESTS) { - if (SystemProperties.getBoolean("radio.test.data.stall", false)) { - log("updateDataStallInfo: radio.test.data.stall true received = 0;"); - received = 0; - } - } - if ( sent > 0 && received > 0 ) { - if (VDBG_STALL) log("updateDataStallInfo: IN/OUT"); - mSentSinceLastRecv = 0; - mDsRecoveryHandler.reset(); - } else if (sent > 0 && received == 0) { - if (isPhoneStateIdle()) { - mSentSinceLastRecv += sent; - } else { - mSentSinceLastRecv = 0; - } - if (DBG) { - log("updateDataStallInfo: OUT sent=" + sent + - " mSentSinceLastRecv=" + mSentSinceLastRecv); - } - } else if (sent == 0 && received > 0) { - if (VDBG_STALL) log("updateDataStallInfo: IN"); - mSentSinceLastRecv = 0; - mDsRecoveryHandler.reset(); - } else { - if (VDBG_STALL) log("updateDataStallInfo: NONE"); - } - } - - private boolean isPhoneStateIdle() { - for (int i = 0; i < mTelephonyManager.getPhoneCount(); i++) { - Phone phone = PhoneFactory.getPhone(i); - if (phone != null && phone.getState() != PhoneConstants.State.IDLE) { - log("isPhoneStateIdle false: Voice call active on phone " + i); - return false; - } - } - return true; - } - - private void onDataStallAlarm(int tag) { - if (mDataStallAlarmTag != tag) { - if (DBG) { - log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag); - } - return; - } - - if (DBG) log("Data stall alarm"); - updateDataStallInfo(); - - int hangWatchdogTrigger = Settings.Global.getInt(mResolver, - Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, - NUMBER_SENT_PACKETS_OF_HANG); - - boolean suspectedStall = DATA_STALL_NOT_SUSPECTED; - if (mSentSinceLastRecv >= hangWatchdogTrigger) { - if (DBG) { - log("onDataStallAlarm: tag=" + tag + " do recovery action=" - + mDsRecoveryHandler.getRecoveryAction()); - } - suspectedStall = DATA_STALL_SUSPECTED; - sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY)); - } else { - if (VDBG_STALL) { - log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) + - " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger); - } - } - startDataStallAlarm(suspectedStall); - } - - protected void startDataStallAlarm(boolean suspectedStall) { - int delayInMs; - - if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled() && isAnyDataConnected()) { - // If screen is on or data stall is currently suspected, set the alarm - // with an aggressive timeout. - if (mIsScreenOn || suspectedStall || mDsRecoveryHandler.isAggressiveRecovery()) { - delayInMs = Settings.Global.getInt(mResolver, - Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS, - DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT); - } else { - delayInMs = Settings.Global.getInt(mResolver, - Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS, - DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT); - } - - mDataStallAlarmTag += 1; - if (VDBG_STALL) { - log("startDataStallAlarm: tag=" + mDataStallAlarmTag + - " delay=" + (delayInMs / 1000) + "s"); - } - Intent intent = new Intent(INTENT_DATA_STALL_ALARM); - intent.putExtra(INTENT_DATA_STALL_ALARM_EXTRA_TAG, mDataStallAlarmTag); - intent.putExtra(INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE, mTransportType); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); - mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, - SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent); - } else { - if (VDBG_STALL) { - log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag); - } - } - } - - private void stopDataStallAlarm() { - if (VDBG_STALL) { - log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag + - " mDataStallAlarmIntent=" + mDataStallAlarmIntent); - } - mDataStallAlarmTag += 1; - if (mDataStallAlarmIntent != null) { - mAlarmManager.cancel(mDataStallAlarmIntent); - mDataStallAlarmIntent = null; - } - } - - private void restartDataStallAlarm() { - if (!isAnyDataConnected()) return; - // To be called on screen status change. - // Do not cancel the alarm if it is set with aggressive timeout. - if (mDsRecoveryHandler.isAggressiveRecovery()) { - if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm."); - return; - } - if (VDBG_STALL) log("restartDataStallAlarm: stop then start."); - stopDataStallAlarm(); - startDataStallAlarm(DATA_STALL_NOT_SUSPECTED); - } - - /** - * Provisioning APN - */ - private void onActionIntentProvisioningApnAlarm(Intent intent) { - if (DBG) log("onActionIntentProvisioningApnAlarm: action=" + intent.getAction()); - Message msg = obtainMessage(DctConstants.EVENT_PROVISIONING_APN_ALARM, - intent.getAction()); - msg.arg1 = intent.getIntExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, 0); - sendMessage(msg); - } - - private void startProvisioningApnAlarm() { - int delayInMs = Settings.Global.getInt(mResolver, - Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS, - PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT); - if (TelephonyUtils.IS_DEBUGGABLE) { - // Allow debug code to use a system property to provide another value - String delayInMsStrg = Integer.toString(delayInMs); - delayInMsStrg = System.getProperty(DEBUG_PROV_APN_ALARM, delayInMsStrg); - try { - delayInMs = Integer.parseInt(delayInMsStrg); - } catch (NumberFormatException e) { - loge("startProvisioningApnAlarm: e=" + e); - } - } - mProvisioningApnAlarmTag += 1; - if (DBG) { - log("startProvisioningApnAlarm: tag=" + mProvisioningApnAlarmTag + - " delay=" + (delayInMs / 1000) + "s"); - } - Intent intent = new Intent(INTENT_PROVISIONING_APN_ALARM); - intent.putExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, mProvisioningApnAlarmTag); - mProvisioningApnAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + delayInMs, mProvisioningApnAlarmIntent); - } - - private void stopProvisioningApnAlarm() { - if (DBG) { - log("stopProvisioningApnAlarm: current tag=" + mProvisioningApnAlarmTag + - " mProvsioningApnAlarmIntent=" + mProvisioningApnAlarmIntent); - } - mProvisioningApnAlarmTag += 1; - if (mProvisioningApnAlarmIntent != null) { - mAlarmManager.cancel(mProvisioningApnAlarmIntent); - mProvisioningApnAlarmIntent = null; - } - } - - /** - * 5G connection reevaluation alarm - */ - private void startWatchdogAlarm() { - sendMessageDelayed(obtainMessage(DctConstants.EVENT_NR_TIMER_WATCHDOG), mWatchdogTimeMs); - mWatchdog = true; - } - - private void stopWatchdogAlarm() { - removeMessages(DctConstants.EVENT_NR_TIMER_WATCHDOG); - mWatchdog = false; - } - - private void onDataServiceBindingChanged(boolean bound) { - if (!bound) { - if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - boolean connPersistenceOnRestart = mPhone.getContext().getResources() - .getBoolean(com.android - .internal.R.bool.config_wlan_data_service_conn_persistence_on_restart); - if (!connPersistenceOnRestart) { - cleanUpAllConnectionsInternal(false, Phone.REASON_IWLAN_DATA_SERVICE_DIED); - } - } - } else { - //reset throttling after binding to data service - mDataThrottler.reset(); - } - mDataServiceBound = bound; - } - - public static String requestTypeToString(@RequestNetworkType int type) { - switch (type) { - case REQUEST_TYPE_NORMAL: return "NORMAL"; - case REQUEST_TYPE_HANDOVER: return "HANDOVER"; - } - return "UNKNOWN"; - } - - public static String releaseTypeToString(@ReleaseNetworkType int type) { - switch (type) { - case RELEASE_TYPE_NORMAL: return "NORMAL"; - case RELEASE_TYPE_DETACH: return "DETACH"; - case RELEASE_TYPE_HANDOVER: return "HANDOVER"; - } - return "UNKNOWN"; - } - - @RilRadioTechnology - protected int getDataRat() { - ServiceState ss = mPhone.getServiceState(); - NetworkRegistrationInfo nrs = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, mTransportType); - if (nrs != null) { - return ServiceState.networkTypeToRilRadioTechnology(nrs.getAccessNetworkTechnology()); - } - return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; - } - - @RilRadioTechnology - private int getVoiceRat() { - ServiceState ss = mPhone.getServiceState(); - NetworkRegistrationInfo nrs = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_CS, mTransportType); - if (nrs != null) { - return ServiceState.networkTypeToRilRadioTechnology(nrs.getAccessNetworkTechnology()); - } - return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; - } - - private void read5GConfiguration() { - if (DBG) log("read5GConfiguration"); - String[] bandwidths = CarrierConfigManager.getDefaultConfig().getStringArray( - CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY); - boolean useLte = false; - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); - if (b != null) { - if (b.getStringArray(CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY) != null) { - bandwidths = b.getStringArray(CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY); - } - useLte = b.getBoolean(CarrierConfigManager - .KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPLINK_BOOL); - mWatchdogTimeMs = b.getLong(CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG); - mNrNsaAllUnmetered = b.getBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_BOOL); - mNrNsaMmwaveUnmetered = b.getBoolean( - CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL); - mNrNsaSub6Unmetered = b.getBoolean( - CarrierConfigManager.KEY_UNMETERED_NR_NSA_SUB6_BOOL); - mNrSaAllUnmetered = b.getBoolean(CarrierConfigManager.KEY_UNMETERED_NR_SA_BOOL); - mNrSaMmwaveUnmetered = b.getBoolean( - CarrierConfigManager.KEY_UNMETERED_NR_SA_MMWAVE_BOOL); - mNrSaSub6Unmetered = b.getBoolean( - CarrierConfigManager.KEY_UNMETERED_NR_SA_SUB6_BOOL); - mNrNsaRoamingUnmetered = b.getBoolean( - CarrierConfigManager.KEY_UNMETERED_NR_NSA_WHEN_ROAMING_BOOL); - mLteEndcUsingUserDataForRrcDetection = b.getBoolean( - CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL); - } - } - updateLinkBandwidths(bandwidths, useLte); - } - - public boolean getLteEndcUsingUserDataForIdleDetection() { - return mLteEndcUsingUserDataForRrcDetection; - } - - /** - * Register for physical link status (i.e. RRC state) changed event. - * if {@link CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL} is true, - * then physical link state is focusing on "internet data connection" instead of RRC state. - * - * @param h The handler - * @param what The event - */ - public void registerForPhysicalLinkStatusChanged(Handler h, int what) { - mDcc.registerForPhysicalLinkStatusChanged(h, what); - } - - /** - * Unregister from physical link status (i.e. RRC state) changed event. - * - * @param h The previously registered handler - */ - public void unregisterForPhysicalLinkStatusChanged(Handler h) { - mDcc.unregisterForPhysicalLinkStatusChanged(h); - } - - // We use a specialized equals function in Apn setting when checking if an active - // data connection is still legitimate to use against a different apn setting. - // This method is extracted to a function to ensure that any future changes to this check will - // be applied to both cleanUpConnectionsOnUpdatedApns and checkForCompatibleDataConnection. - // Fix for b/158908392. - private boolean areCompatible(ApnSetting apnSetting1, ApnSetting apnSetting2) { - return apnSetting1.equals(apnSetting2, - mPhone.getServiceState().getDataRoamingFromRegistration()); - } - - @NonNull - private PersistableBundle getCarrierConfig() { - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - // If an invalid subId is used, this bundle will contain default values. - PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId()); - if (config != null) { - return config; - } - } - // Return static default defined in CarrierConfigManager. - return CarrierConfigManager.getDefaultConfig(); - } - - /** - * @return The data service manager. - */ - public @NonNull DataServiceManager getDataServiceManager() { - return mDataServiceManager; - } - - /** - * @return The data throttler - */ - public @NonNull DataThrottler getDataThrottler() { - return mDataThrottler; - } - - private void showProvisioningNotification() { - final Intent intent = new Intent(DcTracker.INTENT_PROVISION); - intent.putExtra(DcTracker.EXTRA_PROVISION_PHONE_ID, mPhone.getPhoneId()); - final PendingIntent pendingIntent = PendingIntent.getBroadcast( - mPhone.getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE); - - final Resources r = mPhone.getContext().getResources(); - final String title = r.getString(R.string.network_available_sign_in, 0); - final String details = mTelephonyManager.getNetworkOperator(mPhone.getSubId()); - final Notification.Builder builder = new Notification.Builder(mPhone.getContext()) - .setWhen(System.currentTimeMillis()) - .setSmallIcon(R.drawable.stat_notify_rssi_in_range) - .setChannelId(NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS) - .setAutoCancel(true) - .setTicker(title) - .setColor(mPhone.getContext().getColor( - com.android.internal.R.color.system_notification_accent_color)) - .setContentTitle(title) - .setContentText(details) - .setContentIntent(pendingIntent) - .setLocalOnly(true) - .setOnlyAlertOnce(true); - - final Notification notification = builder.build(); - try { - getNotificationManager().notify(NOTIFICATION_TAG, mPhone.getPhoneId(), notification); - } catch (final NullPointerException npe) { - Log.e(mLogTag, "showProvisioningNotification: error showing notification", npe); - } - } - - private void hideProvisioningNotification() { - try { - getNotificationManager().cancel(NOTIFICATION_TAG, mPhone.getPhoneId()); - } catch (final NullPointerException npe) { - Log.e(mLogTag, "hideProvisioningNotification: error hiding notification", npe); - } - } - - private NotificationManager getNotificationManager() { - return (NotificationManager) mPhone.getContext() - .createContextAsUser(UserHandle.ALL, 0 /* flags */) - .getSystemService(Context.NOTIFICATION_SERVICE); - } -} diff --git a/src/java/com/android/internal/telephony/dataconnection/README.txt b/src/java/com/android/internal/telephony/dataconnection/README.txt deleted file mode 100644 index e613a00a36..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/README.txt +++ /dev/null @@ -1,71 +0,0 @@ -This package contains classes used to manage a DataConnection. - -A criticial aspect of this class is that most objects in this -package run on the same thread except DataConnectionTracker -This makes processing efficient as it minimizes context -switching and it eliminates issues with multi-threading. - -This can be done because all actions are either asynchronous -or are known to be non-blocking and fast. At this time only -DcTesterDeactivateAll takes specific advantage of this -single threading knowledge by using Dcc#mDcListAll so be -very careful when making changes that break this assumption. - -A related change was in DataConnectionAc I added code that -checks to see if the caller is on a different thread. If -it is then the AsyncChannel#sendMessageSynchronously is -used. If the caller is on the same thread then a getter -is used. This allows the DCAC to be used from any thread -and was required to fix a bug when Dcc called -PhoneBase#notifyDataConnection which calls DCT#getLinkProperties -and DCT#getLinkCapabilities which call Dcc all on the same -thread. Without this change there was a dead lock when -sendMessageSynchronously blocks. - - -== Testing == - -The following are Intents that can be sent for testing pruproses on -DEBUGGABLE builds (userdebug, eng) - -*) Causes bringUp and retry requests to fail for all DC's - - adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_fail_bringup --ei counter 2 --ei fail_cause -3 - -*) Causes all DC's to get torn down, simulating a temporary network outage: - - adb shell am broadcast -a com.android.internal.telephony.dataconnection.action_deactivate_all - -*) To simplify testing we also have detach and attach simulations below where {x} is gsm, cdma or sip - - adb shell am broadcast -a com.android.internal.telephony.{x}.action_detached - adb shell am broadcast -a com.android.internal.telephony.{x}.action_attached - - -== System properties for Testing == - -On debuggable builds (userdebug, eng) you can change additional -settings through system properties. These properties can be set with -"setprop" for the current boot, or added to local.prop to persist -across boots. - -device# setprop key value - -device# echo "key=value" >> /data/local.prop -device# chmod 644 /data/local.prop - - --- Retry configuration -- - -You can replace the connection retry configuration. For example, you -could change it to perform 4 retries at 5 second intervals: - -device# setprop test.data_retry_config "5000,5000,5000" - - --- Roaming -- - -You can force the telephony stack to always assume that it's roaming -to verify higher-level framework functionality: - -device# setprop telephony.test.forceRoaming true diff --git a/src/java/com/android/internal/telephony/dataconnection/TransportManager.java b/src/java/com/android/internal/telephony/dataconnection/TransportManager.java deleted file mode 100644 index 63358f4993..0000000000 --- a/src/java/com/android/internal/telephony/dataconnection/TransportManager.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import android.annotation.Nullable; -import android.os.Handler; -import android.os.Message; -import android.os.RegistrantList; -import android.telephony.AccessNetworkConstants; -import android.telephony.Annotation.ApnType; -import android.telephony.CarrierConfigManager; -import android.telephony.data.ApnSetting; -import android.util.LocalLog; -import android.util.SparseIntArray; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.data.AccessNetworksManager; -import com.android.internal.telephony.data.TelephonyNetworkFactory; -import com.android.telephony.Rlog; - -import java.util.concurrent.TimeUnit; - -/** - * This class represents the transport manager which manages available transports (i.e. WWAN or - * WLAN) and determine the correct transport for {@link TelephonyNetworkFactory} to handle the data - * requests. - * - * The device can operate in the following modes, which is stored in the system properties - * ro.telephony.iwlan_operation_mode. If the system properties is missing, then it's tied to - * IRadio version. For 1.4 or above, it's AP-assisted mdoe. For 1.3 or below, it's legacy mode. - * - * Legacy mode: - * Frameworks send all data requests to the default data service, which is the cellular data - * service. IWLAN should be still reported as a RAT on cellular network service. - * - * AP-assisted mode: - * IWLAN is handled by IWLAN data service extending {@link android.telephony.data.DataService}, - * IWLAN network service extending {@link android.telephony.NetworkService}, and qualified - * network service extending {@link android.telephony.data.QualifiedNetworksService}. - * - * The following settings for service package name need to be configured properly for - * frameworks to bind. - * - * Package name of data service: - * The resource overlay 'config_wlan_data_service_package' or, - * the carrier config - * {@link CarrierConfigManager#KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING}. - * The carrier config takes precedence over the resource overlay if both exist. - * - * Package name of network service - * The resource overlay 'config_wlan_network_service_package' or - * the carrier config - * {@link CarrierConfigManager#KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING}. - * The carrier config takes precedence over the resource overlay if both exist. - * - * Package name of qualified network service - * The resource overlay 'config_qualified_networks_service_package' or - * the carrier config - * {@link CarrierConfigManager# - * KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING}. - * The carrier config takes precedence over the resource overlay if both exist. - */ -public class TransportManager extends Handler { - private final String mLogTag; - - private static final int EVENT_QUALIFIED_NETWORKS_CHANGED = 1; - - private static final int EVENT_EVALUATE_TRANSPORT_PREFERENCE = 2; - - // Delay the re-evaluation if transport fall back. QNS will need to quickly change the - // preference back to the original transport to avoid another handover request. - private static final long FALL_BACK_REEVALUATE_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(3); - - private final Phone mPhone; - - private final LocalLog mLocalLog = new LocalLog(64); - - @Nullable - private AccessNetworksManager mAccessNetworksManager; - - /** - * The pending handover list. This is a list of APNs that are being handover to the new - * transport. The entry will be removed once handover is completed. The key - * is the APN type, and the value is the target transport that the APN is handovered to. - */ - private final SparseIntArray mPendingHandoverApns; - - /** - * The registrants for listening data handover needed events. - */ - private final RegistrantList mHandoverNeededEventRegistrants; - - /** - * Handover parameters - */ - @VisibleForTesting - public static final class HandoverParams { - /** - * The callback for handover complete. - */ - public interface HandoverCallback { - /** - * Called when handover is completed. - * - * @param success {@true} if handover succeeded, otherwise failed. - * @param fallback {@true} if handover failed, the data connection fallback to the - * original transport - */ - void onCompleted(boolean success, boolean fallback); - } - - public final @ApnType int apnType; - public final int targetTransport; - public final HandoverCallback callback; - - @VisibleForTesting - public HandoverParams(int apnType, int targetTransport, HandoverCallback callback) { - this.apnType = apnType; - this.targetTransport = targetTransport; - this.callback = callback; - } - } - - public TransportManager(Phone phone) { - mPhone = phone; - mPendingHandoverApns = new SparseIntArray(); - mHandoverNeededEventRegistrants = new RegistrantList(); - mLogTag = TransportManager.class.getSimpleName() + "-" + mPhone.getPhoneId(); - mAccessNetworksManager = mPhone.getAccessNetworksManager(); - mAccessNetworksManager.registerForQualifiedNetworksChanged(this, - EVENT_QUALIFIED_NETWORKS_CHANGED); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_QUALIFIED_NETWORKS_CHANGED: - if (!hasMessages(EVENT_EVALUATE_TRANSPORT_PREFERENCE)) { - sendEmptyMessage(EVENT_EVALUATE_TRANSPORT_PREFERENCE); - } - break; - case EVENT_EVALUATE_TRANSPORT_PREFERENCE: - evaluateTransportPreference(); - break; - default: - loge("Unexpected event " + msg.what); - break; - } - } - - /** - * Set the current transport of apn type. - * - * @param apnType The APN type - * @param transport The transport. Must be WWAN or WLAN. - */ - private synchronized void setCurrentTransport(@ApnType int apnType, int transport) { - mAccessNetworksManager.setCurrentTransport(apnType, transport); - } - - private boolean isHandoverPending() { - return mPendingHandoverApns.size() > 0; - } - - /** - * Evaluate the preferred transport for each APN type to see if handover is needed. - */ - private void evaluateTransportPreference() { - // Simultaneously handover is not supported today. Preference will be re-evaluated after - // handover completed. - if (isHandoverPending()) return; - logl("evaluateTransportPreference"); - for (int apnType : AccessNetworksManager.SUPPORTED_APN_TYPES) { - int targetTransport = mAccessNetworksManager.getPreferredTransport(apnType); - if (targetTransport != mAccessNetworksManager.getCurrentTransport(apnType)) { - logl("Handover started for APN type: " - + ApnSetting.getApnTypeString(apnType) - + ", target transport: " - + AccessNetworkConstants.transportTypeToString(targetTransport)); - mPendingHandoverApns.put(apnType, targetTransport); - mHandoverNeededEventRegistrants.notifyResult( - new HandoverParams(apnType, targetTransport, - (success, fallback) -> { - // The callback for handover completed. - if (success) { - logl("Handover succeeded for APN type " - + ApnSetting.getApnTypeString(apnType)); - } else { - logl("APN type " - + ApnSetting.getApnTypeString(apnType) - + " handover to " - + AccessNetworkConstants.transportTypeToString( - targetTransport) + " failed" - + ", fallback=" + fallback); - } - - long delay = 0; - if (fallback) { - // No need to change the preference because we should - // fallback. Re-evaluate after few seconds to give QNS - // some time to change the preference back to the original - // transport. - delay = FALL_BACK_REEVALUATE_DELAY_MILLIS; - } else { - // If handover succeeds or failed without falling back - // to the original transport, we should move to the new - // transport (even if it is failed). - setCurrentTransport(apnType, targetTransport); - } - mPendingHandoverApns.delete(apnType); - sendEmptyMessageDelayed(EVENT_EVALUATE_TRANSPORT_PREFERENCE, - delay); - })); - - // Return here instead of processing the next APN type. The next APN type for - // handover will be evaluate again once current handover is completed. - return; - } - } - } - - /** - * Register for data handover needed event - * - * @param h The handler of the event - * @param what The id of the event - */ - public void registerForHandoverNeededEvent(Handler h, int what) { - if (h != null) { - mHandoverNeededEventRegistrants.addUnique(h, what, null); - } - } - - /** - * Unregister for data handover needed event - * - * @param h The handler - */ - public void unregisterForHandoverNeededEvent(Handler h) { - mHandoverNeededEventRegistrants.remove(h); - } - - /** - * Registers the data throttler with DcTracker. - */ - public void registerDataThrottler(DataThrottler dataThrottler) { - if (mAccessNetworksManager != null) { - mAccessNetworksManager.registerDataThrottler(dataThrottler); - } - } - - private void logl(String s) { - log(s); - mLocalLog.log(s); - } - - private void log(String s) { - Rlog.d(mLogTag, s); - } - - private void loge(String s) { - Rlog.e(mLogTag, s); - } -} diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index 322dd55f7c..f9032bfc83 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -41,7 +41,6 @@ import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneNotifier; -import com.android.internal.telephony.dataconnection.DataConnection; import com.android.internal.telephony.uicc.IccFileHandler; import com.android.telephony.Rlog; @@ -173,11 +172,6 @@ abstract class ImsPhoneBase extends Phone { return new ArrayList(0); } - @Override - public PhoneConstants.DataState getDataConnectionState() { - return PhoneConstants.DataState.DISCONNECTED; - } - @Override public @DataActivityType int getDataActivityState() { return TelephonyManager.DATA_ACTIVITY_NONE; @@ -434,10 +428,6 @@ abstract class ImsPhoneBase extends Phone { Message response) { } - public List getCurrentDataConnectionList () { - return null; - } - @Override public void updateServiceLocation() { } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index e72571e113..1f2b0ea7b2 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -68,6 +68,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyLocalConnection; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.DataEnabledChangedReason; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsCallSession; @@ -119,8 +120,6 @@ import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.d2d.RtpTransport; import com.android.internal.telephony.data.DataSettingsManager; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; -import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.imsphone.ImsPhone.ImsDialArgs; @@ -966,8 +965,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } }; - // TODO: make @NonNull after removing DataEnabledSettings - private DataSettingsManager.DataSettingsManagerCallback mSettingsCallback; + private @NonNull DataSettingsManager.DataSettingsManagerCallback mSettingsCallback; /** * Allows the FeatureConnector used to be swapped for easier testing. @@ -1013,39 +1011,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mPhone.getContext().registerReceiver(mReceiver, intentfilter); updateCarrierConfiguration(mPhone.getSubId(), getCarrierConfigBundle(mPhone.getSubId())); - if (mPhone.getDefaultPhone().isUsingNewDataStack()) { - mSettingsCallback = new DataSettingsManager.DataSettingsManagerCallback(this::post) { - @Override - public void onDataEnabledChanged(boolean enabled, - @TelephonyManager.DataEnabledChangedReason int reason, - @NonNull String callingPackage) { - int internalReason; - switch (reason) { - case TelephonyManager.DATA_ENABLED_REASON_USER: - internalReason = DataEnabledSettings.REASON_USER_DATA_ENABLED; - break; - case TelephonyManager.DATA_ENABLED_REASON_POLICY: - internalReason = DataEnabledSettings.REASON_POLICY_DATA_ENABLED; - break; - case TelephonyManager.DATA_ENABLED_REASON_CARRIER: - internalReason = DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER; - break; - case TelephonyManager.DATA_ENABLED_REASON_THERMAL: - internalReason = DataEnabledSettings.REASON_THERMAL_DATA_ENABLED; - break; - case TelephonyManager.DATA_ENABLED_REASON_OVERRIDE: - internalReason = DataEnabledSettings.REASON_OVERRIDE_RULE_CHANGED; - break; - default: - internalReason = DataEnabledSettings.REASON_INTERNAL_DATA_ENABLED; - } - ImsPhoneCallTracker.this.onDataEnabledChanged(enabled, internalReason); - }}; - mPhone.getDefaultPhone().getDataSettingsManager().registerCallback(mSettingsCallback); - } else { - mPhone.getDefaultPhone().getDataEnabledSettings().registerForDataEnabledChanged( - this, EVENT_DATA_ENABLED_CHANGED, null); - } + mSettingsCallback = new DataSettingsManager.DataSettingsManagerCallback(this::post) { + @Override + public void onDataEnabledChanged(boolean enabled, + @DataEnabledChangedReason int reason, + @NonNull String callingPackage) { + ImsPhoneCallTracker.this.onDataEnabledChanged(enabled, reason); + }}; + mPhone.getDefaultPhone().getDataSettingsManager().registerCallback(mSettingsCallback); final TelecomManager telecomManager = (TelecomManager) mPhone.getContext().getSystemService(Context.TELECOM_SERVICE); @@ -1290,11 +1263,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { clearDisconnected(); mPhone.getContext().unregisterReceiver(mReceiver); - if (mPhone.getDefaultPhone().isUsingNewDataStack()) { - mPhone.getDefaultPhone().getDataSettingsManager().unregisterCallback(mSettingsCallback); - } else { - mPhone.getDefaultPhone().getDataEnabledSettings().unregisterForDataEnabledChanged(this); - } + mPhone.getDefaultPhone().getDataSettingsManager().unregisterCallback(mSettingsCallback); mImsManagerConnector.disconnect(); final NetworkStatsManager statsManager = @@ -2810,7 +2779,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private void maybeSetVideoCallProvider(ImsPhoneConnection conn, ImsCall imsCall) { android.telecom.Connection.VideoProvider connVideoProvider = conn.getVideoProvider(); - ImsCallSession callSession = imsCall.getCallSession(); + ImsCallSession callSession = imsCall.getCallSession(); if (connVideoProvider != null || callSession == null || callSession.getVideoCallProvider() == null) { return; @@ -3840,15 +3809,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { @Override public void onCallHandover(ImsCall imsCall, int srcAccessTech, int targetAccessTech, ImsReasonInfo reasonInfo) { - // Check with the DCTracker to see if data is enabled; there may be a case when + // Check if data is enabled; there may be a case when // ImsPhoneCallTracker isn't being informed of the right data enabled state via its // registration, so we'll refresh now. boolean isDataEnabled; - if (mPhone.getDefaultPhone().isUsingNewDataStack()) { - isDataEnabled = mPhone.getDefaultPhone().getDataSettingsManager().isDataEnabled(); - } else { - isDataEnabled = mPhone.getDefaultPhone().getDataEnabledSettings().isDataEnabled(); - } + isDataEnabled = mPhone.getDefaultPhone().getDataSettingsManager().isDataEnabled(); if (DBG) { log("onCallHandover :: srcAccessTech=" + srcAccessTech + ", targetAccessTech=" @@ -5028,10 +4993,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { /** * Handler of data enabled changed event * @param enabled True if data is enabled, otherwise disabled. - * @param reason Reason for data enabled/disabled. See {@link DataEnabledChangedReason}. + * @param reason Reason for data enabled/disabled. */ private void onDataEnabledChanged(boolean enabled, @DataEnabledChangedReason int reason) { - // TODO: TelephonyManager.DataEnabledChangedReason instead once DataEnabledSettings is gone log("onDataEnabledChanged: enabled=" + enabled + ", reason=" + reason); mIsDataEnabled = enabled; @@ -5051,9 +5015,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } int reasonCode; - if (reason == DataEnabledSettings.REASON_POLICY_DATA_ENABLED) { + if (reason == TelephonyManager.DATA_ENABLED_REASON_POLICY) { reasonCode = ImsReasonInfo.CODE_DATA_LIMIT_REACHED; - } else if (reason == DataEnabledSettings.REASON_USER_DATA_ENABLED) { + } else if (reason == TelephonyManager.DATA_ENABLED_REASON_USER) { reasonCode = ImsReasonInfo.CODE_DATA_DISABLED; } else { // Unexpected code, default to data disabled. @@ -5066,10 +5030,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // Handle video state changes required as a result of data being enabled/disabled. handleDataEnabledChange(enabled, reasonCode); - // We do not want to update the ImsConfig for REASON_REGISTERED, since it can happen before + // We do not want to update the ImsConfig for REASON_UNKNOWN, since it can happen before // the carrier config has loaded and will deregister IMS. if (!mShouldUpdateImsConfigOnDisconnect - && reason != DataEnabledSettings.REASON_REGISTERED + && reason != TelephonyManager.DATA_ENABLED_REASON_UNKNOWN && mCarrierConfigLoadedForSubscription) { // This will call into updateVideoCallFeatureValue and eventually all clients will be // asynchronously notified that the availability of VT over LTE has changed. diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java index 5ade0bb000..77e758b6d9 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -26,7 +26,6 @@ import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyStatsLog; import com.android.internal.telephony.data.DataStallRecoveryManager; -import com.android.internal.telephony.dataconnection.DcTracker; /** Generates metrics related to data stall recovery events per phone ID for the pushed atom. */ public class DataStallRecoveryStats { @@ -41,42 +40,6 @@ public class DataStallRecoveryStats { private static final int RECOVERY_ACTION_RADIO_RESTART_MAPPING = 3; private static final int RECOVERY_ACTION_RESET_MODEM_MAPPING = 4; - - /** TODO: b/214044479 : Remove this function when new data design(Android T) start. */ - public static void onDataStallEvent( - @DcTracker.RecoveryAction int recoveryAction, - Phone phone, - boolean isRecovered, - int durationMillis) { - if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { - phone = phone.getDefaultPhone(); - } - - int carrierId = phone.getCarrierId(); - int rat = getRat(phone); - int band = - (rat == TelephonyManager.NETWORK_TYPE_IWLAN) ? 0 : ServiceStateStats.getBand(phone); - // the number returned here matches the SignalStrength enum we have - int signalStrength = phone.getSignalStrength().getLevel(); - boolean isOpportunistic = getIsOpportunistic(phone); - boolean isMultiSim = SimSlotState.getCurrentState().numActiveSims > 1; - - // Not use this field in Android S, so we send RECOVERED_REASON_NONE for default value. - int recoveryReason = 0; - TelephonyStatsLog.write( - TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, - carrierId, - rat, - signalStrength, - recoveryAction, - isOpportunistic, - isMultiSim, - band, - isRecovered, - durationMillis, - recoveryReason); - } - /** * Called when data stall happened. * diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 9805d8b1ac..e1e37a6a3e 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -483,8 +483,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return StatsManager.PULL_SKIP; } - data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, - phones[0].isUsingNewDataStack())); + data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, true)); return StatsManager.PULL_SUCCESS; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index 5af1c1f6de..fb7b64db43 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -55,7 +55,7 @@ import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; +import com.android.internal.telephony.data.DataSettingsManager; import org.junit.After; import org.junit.Assert; @@ -75,8 +75,8 @@ import java.util.concurrent.atomic.AtomicBoolean; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class MultiSimSettingControllerTest extends TelephonyTest { - private static final int SINGLE_SIM = 1; private static final int DUAL_SIM = 2; + private static final String PHONE_PACKAGE = "com.android.internal.telephony"; private MultiSimSettingController mMultiSimSettingControllerUT; private Phone[] mPhones; private ParcelUuid mGroupUuid1 = new ParcelUuid(UUID.randomUUID()); @@ -85,8 +85,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { private SubscriptionController mSubControllerMock; private Phone mPhoneMock1; private Phone mPhoneMock2; - private DataEnabledSettings mDataEnabledSettingsMock1; - private DataEnabledSettings mDataEnabledSettingsMock2; + private DataSettingsManager mDataSettingsManagerMock1; + private DataSettingsManager mDataSettingsManagerMock2; private CommandsInterface mMockCi; @@ -118,8 +118,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mSubControllerMock = mock(SubscriptionController.class); mPhoneMock1 = mock(Phone.class); mPhoneMock2 = mock(Phone.class); - mDataEnabledSettingsMock1 = mock(DataEnabledSettings.class); - mDataEnabledSettingsMock2 = mock(DataEnabledSettings.class); + mDataSettingsManagerMock1 = mock(DataSettingsManager.class); + mDataSettingsManagerMock2 = mock(DataSettingsManager.class); mMockCi = mock(CommandsInterface.class); // Default configuration: // DSDS device. @@ -145,8 +145,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new int[]{1, 2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mPhones = new Phone[] {mPhoneMock1, mPhoneMock2}; - doReturn(mDataEnabledSettingsMock1).when(mPhoneMock1).getDataEnabledSettings(); - doReturn(mDataEnabledSettingsMock2).when(mPhoneMock2).getDataEnabledSettings(); + doReturn(mDataSettingsManagerMock1).when(mPhoneMock1).getDataSettingsManager(); + doReturn(mDataSettingsManagerMock2).when(mPhoneMock2).getDataSettingsManager(); doReturn(Arrays.asList(mSubInfo1)).when(mSubControllerMock).getSubInfo( eq(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 1), any()); @@ -385,8 +385,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // Enable on non-default sub should trigger setDefaultDataSubId. mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); @@ -397,8 +397,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); - verify(mDataEnabledSettingsMock1).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock1).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); doReturn(1).when(mSubControllerMock).getDefaultSmsSubId(); @@ -440,10 +440,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataEnabledSettingsMock1).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock1).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // as a result of the above calls, update new values to be returned doReturn(false).when(mPhoneMock1).isUserDataEnabled(); @@ -458,8 +458,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); - verify(mDataEnabledSettingsMock1, times(1)).setDataEnabled(anyInt(), anyBoolean()); - verify(mDataEnabledSettingsMock2, times(1)).setDataEnabled(anyInt(), anyBoolean()); + verify(mDataSettingsManagerMock1, times(1)) + .setDataEnabled(anyInt(), anyBoolean(), anyString()); + verify(mDataSettingsManagerMock2, times(1)) + .setDataEnabled(anyInt(), anyBoolean(), anyString()); } @Test @@ -478,10 +480,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataEnabledSettingsMock1).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock1).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // as a result of the above calls, update new values to be returned doReturn(false).when(mPhoneMock1).isUserDataEnabled(); @@ -529,8 +531,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); mMultiSimSettingControllerUT.notifyUserDataEnabled(2, false); processAllMessages(); assertFalse(GlobalSettingsHelper.getBoolean( @@ -578,13 +580,13 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); verify(mSubControllerMock).setDefaultDataSubId(2); - verify(mDataEnabledSettingsMock1, never()).setDataEnabled( - anyInt(), anyBoolean()); + verify(mDataSettingsManagerMock1, never()).setDataEnabled( + anyInt(), anyBoolean(), anyString()); verifyDismissIntentSent(); clearInvocations(mSubControllerMock); - clearInvocations(mDataEnabledSettingsMock1); - clearInvocations(mDataEnabledSettingsMock2); + clearInvocations(mDataSettingsManagerMock1); + clearInvocations(mDataSettingsManagerMock2); doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); // Toggle data on sub 1 or sub 2. Nothing should happen as they are independent. mMultiSimSettingControllerUT.notifyUserDataEnabled(1, false); @@ -595,10 +597,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); processAllMessages(); verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); - verify(mDataEnabledSettingsMock1, never()).setDataEnabled( - eq(TelephonyManager.DATA_ENABLED_REASON_USER), anyBoolean()); - verify(mDataEnabledSettingsMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock1, never()).setDataEnabled( + eq(TelephonyManager.DATA_ENABLED_REASON_USER), anyBoolean(), anyString()); + verify(mDataSettingsManagerMock2, never()).setDataEnabled( + eq(TelephonyManager.DATA_ENABLED_REASON_USER), eq(false), anyString()); } private void verifyDismissIntentSent() { @@ -636,7 +638,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // This should result in setting sync. - verify(mDataEnabledSettingsMock1).setUserDataEnabled(false, false); + verify(mDataSettingsManagerMock1).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, + false, PHONE_PACKAGE); assertFalse(GlobalSettingsHelper.getBoolean( mContext, Settings.Global.DATA_ROAMING, 1, true)); @@ -645,7 +648,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Turning data on on sub 2. Sub 1 should also be turned on. mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); processAllMessages(); - verify(mDataEnabledSettingsMock1).setUserDataEnabled(true, false); + verify(mDataSettingsManagerMock1).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, + true, PHONE_PACKAGE); verifyDismissIntentSent(); } @@ -715,7 +719,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // This should result in setting sync. - verify(mDataEnabledSettingsMock2).setUserDataEnabled(true, false); + verify(mDataSettingsManagerMock2).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, + true, PHONE_PACKAGE); assertFalse(GlobalSettingsHelper.getBoolean( mContext, Settings.Global.DATA_ROAMING, 2, true)); verify(mSubControllerMock).setDataRoaming(/*enable*/0, /*subId*/1); @@ -724,7 +729,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(false).when(mPhoneMock1).isUserDataEnabled(); mMultiSimSettingControllerUT.notifyUserDataEnabled(1, false); processAllMessages(); - verify(mDataEnabledSettingsMock2).setUserDataEnabled(false, false); + verify(mDataSettingsManagerMock2).setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, + false, PHONE_PACKAGE); } @Test @@ -736,16 +742,16 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // loaded on both subscriptions. mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); processAllMessages(); - verify(mDataEnabledSettingsMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2, never()).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); processAllMessages(); - verify(mDataEnabledSettingsMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2, never()).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); processAllMessages(); - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // Switch from sub 2 to sub 3 in phone[1]. clearInvocations(mSubControllerMock); @@ -827,8 +833,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); // Nothing should happen as carrier config is not ready for sub 2. - verify(mDataEnabledSettingsMock2, never()).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2, never()).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // Still notify carrier config without specifying subId2, but this time subController // and CarrierConfigManager have subId 2 active and ready. @@ -840,8 +846,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); // This time user data should be disabled on phone1. - verify(mDataEnabledSettingsMock2).setDataEnabled( - TelephonyManager.DATA_ENABLED_REASON_USER, false); + verify(mDataSettingsManagerMock2).setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index 0230645b59..4b0cc6196c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import android.content.Context; import android.content.Intent; @@ -34,25 +35,25 @@ import android.os.PersistableBundle; import android.os.PowerManager; import android.telephony.CarrierConfigManager; import android.telephony.NetworkRegistrationInfo; -import android.telephony.PcoData; import android.telephony.PhysicalChannelConfig; import android.telephony.RadioAccessFamily; import android.telephony.ServiceState; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import com.android.internal.telephony.dataconnection.DataConnection; +import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; import com.android.internal.util.IState; import com.android.internal.util.StateMachine; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.lang.reflect.Method; import java.util.ArrayList; @@ -60,6 +61,7 @@ import java.util.List; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper +@Ignore("b/240911460") public class NetworkTypeControllerTest extends TelephonyTest { // private constants copied over from NetworkTypeController private static final int EVENT_DATA_RAT_CHANGED = 2; @@ -67,21 +69,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { private static final int EVENT_NR_FREQUENCY_CHANGED = 4; private static final int EVENT_PHYSICAL_LINK_STATUS_CHANGED = 5; private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED = 6; - private static final int EVENT_CARRIER_CONFIG_CHANGED = 7; - private static final int EVENT_PRIMARY_TIMER_EXPIRED = 8; - private static final int EVENT_SECONDARY_TIMER_EXPIRED = 9; private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 10; private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11; - private static final int EVENT_INITIALIZE = 12; private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 13; - private static final int EVENT_PCO_DATA_CHANGED = 14; private NetworkTypeController mNetworkTypeController; private PersistableBundle mBundle; - - // Mocked classes - DataConnection mDataConnection; - ApnSetting mApnSetting; + private DataNetworkControllerCallback mDataNetworkControllerCallback; private IState getCurrentState() throws Exception { Method method = StateMachine.class.getDeclaredMethod("getCurrentState"); @@ -106,23 +100,28 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); - mDataConnection = mock(DataConnection.class); - mApnSetting = mock(ApnSetting.class); mBundle = mContextFixture.getCarrierConfigBundle(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING, "connected_mmwave:5G_Plus,connected:5G,not_restricted_rrc_idle:5G," + "not_restricted_rrc_con:5G"); + mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); replaceInstance(Handler.class, "mLooper", mDisplayInfoController, Looper.myLooper()); doReturn(RadioAccessFamily.getRafFromNetworkType( TelephonyManager.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA)).when( mPhone).getCachedAllowedNetworkTypesBitmask(); - doReturn(false).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( + doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); doReturn(new int[] {0}).when(mServiceState).getCellBandwidths(); mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); processAllMessages(); + + ArgumentCaptor dataNetworkControllerCallbackCaptor = + ArgumentCaptor.forClass(DataNetworkControllerCallback.class); + verify(mDataNetworkController).registerDataNetworkControllerCallback( + dataNetworkControllerCallbackCaptor.capture()); + mDataNetworkControllerCallback = dataNetworkControllerCallbackCaptor.getValue(); } @After @@ -474,42 +473,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); - int cid = 1; - byte[] contents = new byte[]{0}; - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); - doReturn(mApnSetting).when(mDataConnection).getApnSetting(); - doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); - - - mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, - new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); - processAllMessages(); - assertEquals("connected", getCurrentState().getName()); - } - - @Test - public void testTransitionToCurrentStateNrConnectedWithPcoLength4AndNoNrAdvancedCapable() - throws Exception { - assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); - doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); - int cid = 1; - byte[] contents = new byte[]{31, 1, 84, 0}; - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); - doReturn(mApnSetting).when(mDataConnection).getApnSetting(); - doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); - - - mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, - new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); + mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(false); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); processAllMessages(); assertEquals("connected", getCurrentState().getName()); @@ -522,19 +486,10 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); - int cid = 1; - byte[] contents = new byte[]{1}; - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); - doReturn(mApnSetting).when(mDataConnection).getApnSetting(); - doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF00); broadcastCarrierConfigs(); - - mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, - new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); + mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(false); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); processAllMessages(); assertEquals("connected", getCurrentState().getName()); @@ -547,39 +502,12 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - int cid = 1; - byte[] contents = new byte[]{1}; - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); - doReturn(mApnSetting).when(mDataConnection).getApnSetting(); - doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, - new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); processAllMessages(); - assertEquals("connected_mmwave", getCurrentState().getName()); - } - - @Test - public void testTransitionToCurrentStateNrConnectedWithNrAdvancedCapableAndPcoLength4() - throws Exception { - assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); - doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - int cid = 1; - byte[] contents = new byte[]{31, 1, 84, 1}; - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid); - doReturn(mApnSetting).when(mDataConnection).getApnSetting(); - doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); - - mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED, - new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null)); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(true); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken b/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken deleted file mode 100644 index 80cd9f17b5..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java.broken +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import android.test.suitebuilder.annotation.MediumTest; -import com.android.internal.telephony.TestPhoneNotifier; -import com.android.internal.telephony.gsm.SmsMessage; -import com.android.internal.telephony.test.SimulatedCommands; -import com.android.internal.telephony.test.SimulatedRadioControl; -import com.android.internal.telephony.uicc.IccUtils; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.Suppress; - -import java.util.Iterator; - -/** - * {@hide} - */ -public class SMSDispatcherTest extends AndroidTestCase { - @MediumTest - public void testCMT1() throws Exception { - SmsMessage sms; - SmsHeader header; - - String[] lines = new String[2]; - - lines[0] = "+CMT: ,158"; - lines[1] = "07914140279510F6440A8111110301003BF56080426101748A8C0B05040B" - + "8423F000035502010106276170706C69636174696F6E2F766E642E776170" - + "2E6D6D732D6D65737361676500AF848D0185B4848C8298524F347839776F" - + "7547514D4141424C3641414141536741415A4B554141414141008D908918" - + "802B31363530323438363137392F545950453D504C4D4E008A808E028000" - + "88058103093A8083687474703A2F2F36"; - - sms = SmsMessage.newFromCMT(lines); - header = sms.getUserDataHeader(); - assertNotNull(header); - assertNotNull(sms.getUserData()); - assertNotNull(header.concatRef); - assertEquals(header.concatRef.refNumber, 85); - assertEquals(header.concatRef.msgCount, 2); - assertEquals(header.concatRef.seqNumber, 1); - assertEquals(header.concatRef.isEightBits, true); - assertNotNull(header.portAddrs); - assertEquals(header.portAddrs.destPort, 2948); - assertEquals(header.portAddrs.origPort, 9200); - assertEquals(header.portAddrs.areEightBits, false); - } - - @MediumTest - public void testCMT2() throws Exception { - SmsMessage sms; - SmsHeader header; - - String[] lines = new String[2]; - - lines[0] = "+CMT: ,77"; - lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F" - + "00003550202362E3130322E3137312E3135302F524F347839776F7547514D4141" - + "424C3641414141536741415A4B55414141414100"; - - sms = SmsMessage.newFromCMT(lines); - header = sms.getUserDataHeader(); - assertNotNull(header); - assertNotNull(sms.getUserData()); - assertNotNull(header.concatRef); - assertEquals(header.concatRef.refNumber, 85); - assertEquals(header.concatRef.msgCount, 2); - assertEquals(header.concatRef.seqNumber, 2); - assertEquals(header.concatRef.isEightBits, true); - assertNotNull(header.portAddrs); - assertEquals(header.portAddrs.destPort, 2948); - assertEquals(header.portAddrs.origPort, 9200); - assertEquals(header.portAddrs.areEightBits, false); - } - - @MediumTest - public void testEfRecord() throws Exception { - SmsMessage sms; - - String s = "03029111000c9194981492631000f269206190022000a053e4534a05358bd3" - + "69f05804259da0219418a40641536a110a0aea408080604028180e888462c1" - + "50341c0f484432a1542c174c46b3e1743c9f9068442a994ea8946ac56ab95e" - + "b0986c46abd96eb89c6ec7ebf97ec0a070482c1a8fc8a472c96c3a9fd0a874" - + "4aad5aafd8ac76cbed7abfe0b0784c2e9bcfe8b47acd6ebbdff0b87c4eafdb" - + "eff8bc7ecfeffbffffffffffffffffffffffffffff"; - byte[] data = IccUtils.hexStringToBytes(s); - - sms = SmsMessage.createFromEfRecord(1, data); - assertNotNull(sms.getMessageBody()); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index b02a2cf145..51f501a2c2 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -235,7 +235,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { doReturn(mIwlanNetworkServiceStub).when(mIwlanNetworkServiceStub).asBinder(); addNetworkService(); - doReturn(true).when(mDcTracker).areAllDataDisconnected(); doReturn(true).when(mDataNetworkController).areAllDataDisconnected(); doReturn(new ServiceState()).when(mPhone).getServiceState(); @@ -261,7 +260,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { int dds = SubscriptionManager.getDefaultDataSubscriptionId(); doReturn(dds).when(mPhone).getSubId(); - doReturn(true).when(mPhone).areAllDataDisconnected(); doReturn(true).when(mPackageManager) .hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA); @@ -391,7 +389,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); doReturn(dataNetworkController_phone2).when(phone2).getDataNetworkController(); doReturn(mSST).when(phone2).getServiceStateTracker(); - doReturn(true).when(phone2).isUsingNewDataStack(); doReturn(false).when(mDataNetworkController).areAllDataDisconnected(); doReturn(false).when(dataNetworkController_phone2).areAllDataDisconnected(); doReturn(1).when(mPhone).getSubId(); @@ -1828,29 +1825,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { assertEquals(TelephonyManager.RADIO_POWER_UNAVAILABLE, mSimulatedCommands.getRadioState()); } - @Test - @SmallTest - public void testImsRegisteredDelayShutDown() throws Exception { - doReturn(false).when(mPhone).isUsingNewDataStack(); - doReturn(true).when(mPhone).isPhoneTypeGsm(); - mContextFixture.putIntResource( - com.android.internal.R.integer.config_delay_for_ims_dereg_millis, 1000 /*ms*/); - sst.setImsRegistrationState(true); - mSimulatedCommands.setRadioPowerFailResponse(false); - sst.setRadioPower(true); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - - // Turn off the radio and ensure radio power is still on - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); - sst.setRadioPower(false); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); - - // Now set IMS reg state to false and ensure we see the modem move to power off. - sst.setImsRegistrationState(false); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); - } @Test @SmallTest @@ -1869,33 +1843,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); } - @Test - @SmallTest - public void testImsRegisteredDelayShutDownTimeout() throws Exception { - doReturn(false).when(mPhone).isUsingNewDataStack(); - doReturn(true).when(mPhone).isPhoneTypeGsm(); - mContextFixture.putIntResource( - com.android.internal.R.integer.config_delay_for_ims_dereg_millis, 1000 /*ms*/); - sst.setImsRegistrationState(true); - mSimulatedCommands.setRadioPowerFailResponse(false); - sst.setRadioPower(true); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - - // Turn off the radio and ensure radio power is still on - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); - sst.setRadioPower(false); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState()); - - // Ensure that if we never turn deregister for IMS, we still eventually see radio state - // move to off. - // Timeout for IMS reg + some extra time to remove race conditions - waitForDelayedHandlerAction(mSSTTestHandler.getThreadHandler(), - sst.getRadioPowerOffDelayTimeoutForImsRegistration() + 1000, 1000); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState()); - } - @Test @SmallTest public void testImsRegisteredAPMOnOffToggle() throws Exception { diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index d27512e10c..dc2d00a4f8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -104,9 +104,6 @@ import com.android.internal.telephony.data.DataRetryManager; import com.android.internal.telephony.data.DataServiceManager; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; -import com.android.internal.telephony.dataconnection.DataThrottler; -import com.android.internal.telephony.dataconnection.DcTracker; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; @@ -193,7 +190,6 @@ public abstract class TelephonyTest { protected RegistrantList mRegistrantList; protected IccPhoneBookInterfaceManager mIccPhoneBookIntManager; protected ImsManager mImsManager; - protected DcTracker mDcTracker; protected DataNetworkController mDataNetworkController; protected DataRetryManager mDataRetryManager; protected DataSettingsManager mDataSettingsManager; @@ -241,7 +237,6 @@ public abstract class TelephonyTest { protected SubscriptionInfoUpdater mSubInfoRecordUpdater; protected LocaleTracker mLocaleTracker; protected RestrictedState mRestrictedState; - protected DataEnabledSettings mDataEnabledSettings; protected DataEnabledOverride mDataEnabledOverride; protected PhoneConfigurationManager mPhoneConfigurationManager; protected CellularNetworkValidator mCellularNetworkValidator; @@ -255,7 +250,6 @@ public abstract class TelephonyTest { protected PersistAtomsStorage mPersistAtomsStorage; protected MetricsCollector mMetricsCollector; protected SmsStats mSmsStats; - protected DataThrottler mDataThrottler; protected SignalStrength mSignalStrength; protected WifiManager mWifiManager; protected WifiInfo mWifiInfo; @@ -427,7 +421,6 @@ public abstract class TelephonyTest { mRegistrantList = Mockito.mock(RegistrantList.class); mIccPhoneBookIntManager = Mockito.mock(IccPhoneBookInterfaceManager.class); mImsManager = Mockito.mock(ImsManager.class); - mDcTracker = Mockito.mock(DcTracker.class); mDataNetworkController = Mockito.mock(DataNetworkController.class); mDataRetryManager = Mockito.mock(DataRetryManager.class); mDataSettingsManager = Mockito.mock(DataSettingsManager.class); @@ -475,7 +468,6 @@ public abstract class TelephonyTest { mSubInfoRecordUpdater = Mockito.mock(SubscriptionInfoUpdater.class); mLocaleTracker = Mockito.mock(LocaleTracker.class); mRestrictedState = Mockito.mock(RestrictedState.class); - mDataEnabledSettings = Mockito.mock(DataEnabledSettings.class); mDataEnabledOverride = Mockito.mock(DataEnabledOverride.class); mPhoneConfigurationManager = Mockito.mock(PhoneConfigurationManager.class); mCellularNetworkValidator = Mockito.mock(CellularNetworkValidator.class); @@ -489,7 +481,6 @@ public abstract class TelephonyTest { mPersistAtomsStorage = Mockito.mock(PersistAtomsStorage.class); mMetricsCollector = Mockito.mock(MetricsCollector.class); mSmsStats = Mockito.mock(SmsStats.class); - mDataThrottler = Mockito.mock(DataThrottler.class); mSignalStrength = Mockito.mock(SignalStrength.class); mWifiManager = Mockito.mock(WifiManager.class); mWifiInfo = Mockito.mock(WifiInfo.class); @@ -570,8 +561,6 @@ public abstract class TelephonyTest { .makeGsmCdmaCallTracker(nullable(GsmCdmaPhone.class)); doReturn(mIccPhoneBookIntManager).when(mTelephonyComponentFactory) .makeIccPhoneBookInterfaceManager(nullable(Phone.class)); - doReturn(mDcTracker).when(mTelephonyComponentFactory) - .makeDcTracker(nullable(Phone.class), anyInt()); doReturn(mDisplayInfoController).when(mTelephonyComponentFactory) .makeDisplayInfoController(nullable(Phone.class)); doReturn(mWspTypeDecoder).when(mTelephonyComponentFactory) @@ -599,8 +588,6 @@ public abstract class TelephonyTest { doReturn(mLocaleTracker).when(mTelephonyComponentFactory) .makeLocaleTracker(nullable(Phone.class), nullable(NitzStateMachine.class), nullable(Looper.class)); - doReturn(mDataEnabledSettings).when(mTelephonyComponentFactory) - .makeDataEnabledSettings(nullable(Phone.class)); doReturn(mEriManager).when(mTelephonyComponentFactory) .makeEriManager(nullable(Phone.class), anyInt()); doReturn(mLinkBandwidthEstimator).when(mTelephonyComponentFactory) @@ -630,8 +617,6 @@ public abstract class TelephonyTest { doReturn(mAppSmsManager).when(mPhone).getAppSmsManager(); doReturn(mIccSmsInterfaceManager).when(mPhone).getIccSmsInterfaceManager(); doReturn(mAccessNetworksManager).when(mPhone).getAccessNetworksManager(); - doReturn(mDataEnabledSettings).when(mPhone).getDataEnabledSettings(); - doReturn(mDcTracker).when(mPhone).getDcTracker(anyInt()); doReturn(mDataSettingsManager).when(mDataNetworkController).getDataSettingsManager(); doReturn(mDataNetworkController).when(mPhone).getDataNetworkController(); doReturn(mDataSettingsManager).when(mPhone).getDataSettingsManager(); @@ -649,7 +634,6 @@ public abstract class TelephonyTest { doReturn(mDataProfileManager).when(mDataNetworkController).getDataProfileManager(); doReturn(mDataRetryManager).when(mDataNetworkController).getDataRetryManager(); doReturn(mCarrierPrivilegesTracker).when(mPhone).getCarrierPrivilegesTracker(); - doReturn(true).when(mPhone).isUsingNewDataStack(); doReturn(0).when(mPhone).getPhoneId(); //mUiccController @@ -740,11 +724,6 @@ public abstract class TelephonyTest { doReturn(new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) .when(mAccessNetworksManager).getAvailableTransports(); - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) - .getCurrentTransport(anyInt()); - doReturn(true).when(mDataEnabledSettings).isDataEnabled(); - doReturn(true).when(mDataEnabledSettings).isDataEnabled(anyInt()); - doReturn(true).when(mDataEnabledSettings).isInternalDataEnabled(); doReturn(true).when(mDataSettingsManager).isDataEnabled(); doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( anyInt(), anyInt()); @@ -780,8 +759,6 @@ public abstract class TelephonyTest { Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 1); Settings.Global.putInt(resolver, Settings.Global.DATA_ROAMING, 0); - doReturn(mDataThrottler).when(mDcTracker).getDataThrottler(); - doReturn(-1L).when(mDataThrottler).getRetryTime(anyInt()); doReturn(90).when(mDataConfigManager).getNetworkCapabilityPriority( eq(NetworkCapabilities.NET_CAPABILITY_EIMS)); diff --git a/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken b/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken deleted file mode 100644 index 761dfc7412..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java.broken +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2006 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; - -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import android.telephony.CellInfo; - -import java.util.List; - -/** - * Stub class used for unit tests - */ - -public class TestPhoneNotifier implements PhoneNotifier { - public TestPhoneNotifier() { - } - - public void notifyPhoneState(Phone sender) { - } - - public void notifyServiceState(Phone sender) { - } - - public void notifyCellLocation(Phone sender) { - } - - public void notifySignalStrength(Phone sender) { - } - - public void notifyMessageWaitingChanged(Phone sender) { - } - - public void notifyCallForwardingChanged(Phone sender) { - } - - public void notifyDataConnection(Phone sender, String reason, String apnType) { - } - - public void notifyDataConnection(Phone sender, String reason, String apnType, - PhoneConstants.DataState state) { - } - - public void notifyDataConnectionFailed(Phone sender, String reason, String apnType) { - } - - public void notifyDataActivity(Phone sender) { - } - - public void notifyOtaspChanged(Phone sender, int otaspMode) { - } - - public void notifyCellInfo(Phone sender, List cellInfo) { - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java similarity index 62% rename from tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java rename to tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java index 1812fa0770..b6d77e952e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java @@ -14,23 +14,20 @@ * limitations under the License. */ -package com.android.internal.telephony.dataconnection; +package com.android.internal.telephony.data; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.doReturn; import android.net.Uri; import android.os.Parcel; import android.os.PersistableBundle; -import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; -import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.TelephonyTest; @@ -118,213 +115,7 @@ public class ApnSettingTest extends TelephonyTest { } @Test - @SmallTest - public void testIsMetered() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - - doReturn(false).when(mServiceState).getDataRoaming(); - doReturn(1).when(mPhone).getSubId(); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_DEFAULT), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_FOTA), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_IA | ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_SUPL, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_CBS, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DUN, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_IA, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_HIPRI, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_ENTERPRISE, mPhone)); - - // Carrier config settings changes. - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); - } - - @Test - @SmallTest - public void testIsRoamingMetered() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - doReturn(true).when(mServiceState).getDataRoaming(); - doReturn(1).when(mPhone).getSubId(); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_DEFAULT), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_MMS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_FOTA), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_IA | ApnSetting.TYPE_CBS), mPhone)); - - // Carrier config settings changes. - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_FOTA_STRING}); - - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_ENTERPRISE, mPhone)); - } - - @Test - @SmallTest - public void testIsMeteredAnother() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_CBS_STRING}); - - doReturn(false).when(mServiceState).getDataRoaming(); - doReturn(1).when(mPhone).getSubId(); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_SUPL), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_FOTA | ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_IA), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_IMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); - assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_XCAP), mPhone)); - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_ENTERPRISE), mPhone)); - } - - @Test - @SmallTest - public void testIsRoamingMeteredAnother() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_CBS_STRING}); - doReturn(true).when(mServiceState).getDataRoaming(); - doReturn(2).when(mPhone).getSubId(); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_SUPL), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_FOTA | ApnSetting.TYPE_CBS), mPhone)); - - assertTrue(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_SUPL | ApnSetting.TYPE_IA), mPhone)); - - assertTrue(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_IMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); - - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_SUPL, mPhone)); - assertTrue(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_CBS, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DEFAULT, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_MMS, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_DUN, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_FOTA, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_IA, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_HIPRI, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_XCAP, mPhone)); - assertFalse(ApnSettingUtils.isMeteredApnType(ApnSetting.TYPE_ENTERPRISE, mPhone)); - } - - @Test - @SmallTest - public void testIsMeteredNothingCharged() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{}); - - doReturn(false).when(mServiceState).getDataRoaming(); - doReturn(3).when(mPhone).getSubId(); - - assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_IMS | ApnSetting.TYPE_MMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_FOTA), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - } - - @Test - @SmallTest - public void testIsRoamingMeteredNothingCharged() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{}); - doReturn(true).when(mServiceState).getDataRoaming(); - doReturn(3).when(mPhone).getSubId(); - - assertFalse(ApnSettingUtils.isMetered(createApnSetting(ApnSetting.TYPE_IMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_IMS | ApnSetting.TYPE_MMS), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_FOTA), mPhone)); - - assertFalse(ApnSettingUtils.isMetered( - createApnSetting(ApnSetting.TYPE_ALL), mPhone)); - } - - @Test - @SmallTest public void testCanHandleType() { - String types[] = {"mms"}; - assertTrue(createApnSetting(ApnSetting.TYPE_ALL) .canHandleType(ApnSetting.TYPE_MMS)); @@ -402,7 +193,6 @@ public class ApnSettingTest extends TelephonyTest { } @Test - @SmallTest public void testEquals() throws Exception { final int dummyInt = 1; final int dummyLong = 1; @@ -451,7 +241,6 @@ public class ApnSettingTest extends TelephonyTest { } @Test - @SmallTest public void testEqualsRoamingProtocol() { ApnSetting apn1 = new ApnSetting.Builder() .setId(1234) @@ -485,7 +274,6 @@ public class ApnSettingTest extends TelephonyTest { } @Test - @SmallTest public void testCanHandleNetwork() { ApnSetting apn1 = new ApnSetting.Builder() .setId(1234) diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java index 46d1f0a6fe..92cf861b33 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java @@ -16,12 +16,6 @@ package com.android.internal.telephony.data; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; - import android.net.InetAddresses; import android.net.LinkAddress; import android.os.Parcel; @@ -37,15 +31,20 @@ import java.util.ArrayList; import java.util.Arrays; public class DataCallResponseTest extends AndroidTestCase { - public static final String FAKE_DNN = "FAKE_DNN"; + private static final String FAKE_ADDRESS = "99.88.77.66"; + private static final String FAKE_DNS = "55.66.77.88"; + private static final String FAKE_DNN = "FAKE_DNN"; + private static final String FAKE_GATEWAY = "11.22.33.44"; + private static final String FAKE_IFNAME = "FAKE IFNAME"; + private static final String FAKE_PCSCF_ADDRESS = "22.33.44.55"; // 97a498e3fc925c9489860333d06e4e470a454e5445525052495345. // [OsAppId.ANDROID_OS_ID, "ENTERPRISE", 1] - public static final byte[] FAKE_OS_APP_ID = {-105, -92, -104, -29, -4, -110, 92, + private static final byte[] FAKE_OS_APP_ID = {-105, -92, -104, -29, -4, -110, 92, -108, -119, -122, 3, 51, -48, 110, 78, 71, 10, 69, 78, 84, 69, 82, 80, 82, 73, 83, 69}; // 97a498e3fc925c9489860333d06e4e470a454e544552505249534532. // [OsAppId.ANDROID_OS_ID, "ENTERPRISE", 2] - public static final byte[] FAKE_OS_APP_ID_2 = {-105, -92, -104, -29, -4, -110, 92, + private static final byte[] FAKE_OS_APP_ID_2 = {-105, -92, -104, -29, -4, -110, 92, -108, -119, -122, 3, 51, -48, 110, 78, 71, 10, 69, 78, 84, 69, 82, 80, 82, 73, 83, 69, 50}; 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 6b96d83176..e36521e60b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -1062,8 +1062,6 @@ public class DataNetworkTest extends TelephonyTest { verify(mDataNetworkCallback).onHandoverFailed(eq(mDataNetworkUT), eq(DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE), eq(-1L), eq(DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN)); - verify(mLinkBandwidthEstimator, never()).unregisterForBandwidthChanged( - eq(mDataNetworkUT.getHandler())); assertThat(mDataNetworkUT.getTransport()) .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); assertThat(mDataNetworkUT.getId()).isEqualTo(123); 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 ba001f2bfb..d41be7d7a5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/LinkBandwidthEstimatorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/LinkBandwidthEstimatorTest.java @@ -32,7 +32,6 @@ import static com.android.internal.telephony.data.LinkBandwidthEstimator.UNKNOWN import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; @@ -43,9 +42,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.net.NetworkCapabilities; -import android.os.AsyncResult; import android.os.Handler; -import android.os.Message; import android.telephony.CellIdentityLte; import android.telephony.ModemActivityInfo; import android.telephony.NetworkRegistrationInfo; @@ -63,7 +60,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @RunWith(AndroidTestingRunner.class) @@ -80,7 +76,6 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { new ModemActivityInfo(100L, 0, 0, TX_TIME_2_MS, RX_TIME_2_MS); private static final ModemActivityInfo MAI_RX_TIME_HIGH = new ModemActivityInfo(100L, 0, 0, TX_TIME_1_MS, RX_TIME_2_MS); - private static final int EVENT_BANDWIDTH_ESTIMATOR_UPDATE = 1; private NetworkCapabilities mNetworkCapabilities; private CellIdentityLte mCellIdentity; private long mElapsedTimeMs = 0; @@ -89,14 +84,20 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { private NetworkRegistrationInfo mNri; // Mocked classes - TelephonyFacade mTelephonyFacade; + private TelephonyFacade mTelephonyFacade; private Handler mTestHandler; + private LinkBandwidthEstimatorCallback mLinkBandwidthEstimatorCallback; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mTelephonyFacade = mock(TelephonyFacade.class); mTestHandler = mock(Handler.class); + mLinkBandwidthEstimatorCallback = Mockito.mock(LinkBandwidthEstimatorCallback.class); + doAnswer(invocation -> { + ((Runnable) invocation.getArguments()[0]).run(); + return null; + }).when(mLinkBandwidthEstimatorCallback).invokeFromExecutor(any(Runnable.class)); mNetworkCapabilities = new NetworkCapabilities.Builder() .addTransportType(TRANSPORT_CELLULAR) .build(); @@ -116,10 +117,10 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { when(mSignalStrength.getDbm()).thenReturn(-100); when(mSignalStrength.getLevel()).thenReturn(1); mLBE = new LinkBandwidthEstimator(mPhone, mTelephonyFacade); - mLBE.registerForBandwidthChanged(mTestHandler, EVENT_BANDWIDTH_ESTIMATOR_UPDATE, null); mLBE.obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, mNetworkCapabilities).sendToTarget(); mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, false).sendToTarget(); mLBE.obtainMessage(MSG_ACTIVE_PHONE_CHANGED, 1).sendToTarget(); + mLBE.registerCallback(mLinkBandwidthEstimatorCallback); processAllMessages(); } @@ -184,12 +185,8 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest { } private void verifyUpdateBandwidth(int txKbps, int rxKbps) { - ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); - verify(mTestHandler, atLeast(1)) - .sendMessageAtTime(messageArgumentCaptor.capture(), anyLong()); - assertEquals(EVENT_BANDWIDTH_ESTIMATOR_UPDATE, messageArgumentCaptor.getValue().what); - assertEquals(new Pair(txKbps, rxKbps), - ((AsyncResult) messageArgumentCaptor.getValue().obj).result); + verify(mLinkBandwidthEstimatorCallback, atLeast(1)) + .onBandwidthChanged(eq(txKbps), eq(rxKbps)); } @Test 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 d50cb720c4..487f7e33f2 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -79,7 +79,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.dataconnection.DataEnabledSettings; import org.junit.After; import org.junit.Before; @@ -104,7 +103,7 @@ public class PhoneSwitcherTest extends TelephonyTest { private Phone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. private Phone mImsPhone; // TODO: Add logic for DataSettingsManager - private DataEnabledSettings mDataEnabledSettings2; + private DataSettingsManager mDataSettingsManager2; private Handler mActivePhoneSwitchHandler; private GsmCdmaCall mActiveCall; private GsmCdmaCall mHoldingCall; @@ -136,7 +135,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mCommandsInterface1 = mock(CommandsInterface.class); mPhone2 = mock(Phone.class); // mPhone as phone 1 is already defined in TelephonyTest. mImsPhone = mock(Phone.class); - mDataEnabledSettings2 = mock(DataEnabledSettings.class); + mDataSettingsManager2 = mock(DataSettingsManager.class); mActivePhoneSwitchHandler = mock(Handler.class); mActiveCall = mock(GsmCdmaCall.class); mHoldingCall = mock(GsmCdmaCall.class); @@ -648,7 +647,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInCall(mImsPhone); @@ -677,7 +676,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInDial(mImsPhone); @@ -705,7 +704,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInIncomingCall(mImsPhone); @@ -732,7 +731,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active call, but data is turned off. So no data switching should happen. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_IWLAN); notifyPhoneAsInCall(mImsPhone); @@ -760,7 +759,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone 1 has active IMS call on CROSS_SIM. And data of DEFAULT apn is enabled. This should // not trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); mockImsRegTech(1, REGISTRATION_TECH_CROSS_SIM); notifyPhoneAsInCall(mImsPhone); @@ -1193,7 +1192,6 @@ public class PhoneSwitcherTest extends TelephonyTest { verify(mPhone2).registerForEmergencyCallToggle(any(), anyInt(), any()); verify(mPhone2).registerForPreciseCallStateChanged(any(), anyInt(), any()); - verify(mDataEnabledSettings2).registerForDataEnabledChanged(any(), anyInt(), any()); clearInvocations(mMockRadioConfig); setSlotIndexToSubId(1, 2); @@ -1375,8 +1373,8 @@ public class PhoneSwitcherTest extends TelephonyTest { } private void notifyDataEnabled(boolean dataEnabled) { - doReturn(dataEnabled).when(mDataEnabledSettings).isDataEnabled(anyInt()); - doReturn(dataEnabled).when(mDataEnabledSettings2).isDataEnabled(anyInt()); + doReturn(dataEnabled).when(mDataSettingsManager).isDataEnabled(anyInt()); + doReturn(dataEnabled).when(mDataSettingsManager2).isDataEnabled(anyInt()); mPhoneSwitcher.sendEmptyMessage(EVENT_DATA_ENABLED_CHANGED); processAllMessages(); } @@ -1470,7 +1468,7 @@ public class PhoneSwitcherTest extends TelephonyTest { doReturn(0).when(mPhone).getPhoneId(); doReturn(1).when(mPhone2).getPhoneId(); doReturn(true).when(mPhone2).isUserDataEnabled(); - doReturn(mDataEnabledSettings2).when(mPhone2).getDataEnabledSettings(); + doReturn(mDataSettingsManager2).when(mPhone2).getDataSettingsManager(); for (int i = 0; i < supportedModemCount; i++) { mSlotIndexToSubId[i] = new int[1]; mSlotIndexToSubId[i][0] = SubscriptionManager.INVALID_SUBSCRIPTION_ID; diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java index 7856564471..4c2ef80d14 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java @@ -27,15 +27,17 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.annotation.NonNull; +import android.net.INetworkAgentRegistry; import android.net.InetAddresses; import android.net.LinkAddress; import android.net.Network; +import android.net.NetworkAgent; +import android.net.QosSession; import android.telephony.data.EpsBearerQosSessionAttributes; import android.telephony.data.EpsQos; import android.telephony.data.Qos; import android.telephony.data.QosBearerFilter; import android.telephony.data.QosBearerSession; -import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -90,6 +92,7 @@ public class QosCallbackTrackerTest extends TelephonyTest { // Mocked classes private Phone mPhone; private TelephonyNetworkAgent mNetworkAgent; + private INetworkAgentRegistry mINetworkAgentRegistry; private Network mNetwork; private RcsStats mRcsStats; @@ -100,6 +103,9 @@ public class QosCallbackTrackerTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mPhone = mock(Phone.class); mNetworkAgent = mock(TelephonyNetworkAgent.class); + mINetworkAgentRegistry = mock(INetworkAgentRegistry.class); + replaceInstance(NetworkAgent.class, "mRegistry", mNetworkAgent, mINetworkAgentRegistry); + replaceInstance(NetworkAgent.class, "mPreConnectedQueue", mNetworkAgent, new ArrayList()); mNetwork = mock(Network.class); mRcsStats = mock(RcsStats.class); doReturn(mNetwork).when(mNetworkAgent).getNetwork(); @@ -162,7 +168,6 @@ public class QosCallbackTrackerTest extends TelephonyTest { } @Test - @SmallTest public void testAddFilterBeforeUpdateSessions() throws Exception { Filter filter = new Filter(new InetSocketAddress( InetAddresses.parseNumericAddress("122.22.22.22"), 2222)); @@ -179,8 +184,8 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), - eq(1234), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); // Matching QosBearerFilter ArrayList qosFilters2 = new ArrayList<>(); @@ -191,14 +196,12 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); - + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testAddFilterAfterUpdateSessions() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -222,13 +225,11 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); - + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testRemoveFilter() throws Exception { // Add filter Filter filter = new Filter(new InetSocketAddress( @@ -246,8 +247,8 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), - eq(1234), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); // Remove the filter mQosCallbackTracker.removeFilter(1); @@ -262,13 +263,11 @@ public class QosCallbackTrackerTest extends TelephonyTest { processAllMessages(); // Verify that notifyQosSessionAvailable is not invoked as the filter is already removed - verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); - + verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testSessionLost() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -296,19 +295,18 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); // Remove the matching QosBearerFilter qosSessions.remove(1); mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1235), eq(1)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); } @Test - @SmallTest public void testModifiedQos() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -335,10 +333,10 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); - reset(mNetworkAgent); + reset(mINetworkAgentRegistry); // Update the QOS qosSessions.remove(1); @@ -346,12 +344,11 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testUnmodifiedQos() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -378,8 +375,8 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); reset(mNetworkAgent); @@ -389,12 +386,11 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testEmptyQosSessions() throws Exception { // Add filter Filter filter = new Filter(new InetSocketAddress( @@ -427,21 +423,21 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(2, filter2); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1234), any(EpsBearerQosSessionAttributes.class)); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(2), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(2), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + // Update empty QOS sessions list mQosCallbackTracker.updateSessions(new ArrayList<>()); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234), eq(1)); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(2), eq(1235), eq(1)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(2), any(QosSession.class)); } @Test - @SmallTest public void testMultipleQosSessions() throws Exception { // Add filter 1 Filter filter1 = new Filter(new InetSocketAddress( @@ -474,21 +470,20 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1234), any(EpsBearerQosSessionAttributes.class)); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(2), - eq(1235), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(2), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); // Update empty QOS sessions list mQosCallbackTracker.updateSessions(new ArrayList<>()); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234), eq(1)); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(2), eq(1235), eq(1)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(2), any(QosSession.class)); } @Test - @SmallTest public void testQosSessionWithInvalidPortRange() throws Exception { // Non-matching QosBearerFilter ArrayList qosFilters1 = new ArrayList<>(); @@ -512,13 +507,11 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, never()).notifyQosSessionAvailable(eq(1), - eq(1235), any(EpsBearerQosSessionAttributes.class)); - + verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); } @Test - @SmallTest public void testQosSessionFilterPortRangeWithoutAddress() throws Exception { // QosBearerFilter including remote port range without remote address ArrayList qosFilters1 = new ArrayList<>(); @@ -537,20 +530,19 @@ public class QosCallbackTrackerTest extends TelephonyTest { mQosCallbackTracker.addFilter(1, filter); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionAvailable(eq(1), - eq(1234), any(EpsBearerQosSessionAttributes.class)); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); // Remove the matching QosBearerFilter qosSessions.remove(0); mQosCallbackTracker.updateSessions(qosSessions); processAllMessages(); - verify(mNetworkAgent, times(1)).notifyQosSessionLost(eq(1), eq(1234), eq(1)); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); } @Test - @SmallTest - public void testQosMetrics() throws Exception { + public void testQosMetrics() { final int callbackId = 1; final int slotId = mPhone.getPhoneId(); // Add filter before update session diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java index d109ee929e..7d323aa4b4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java @@ -22,24 +22,18 @@ import static com.android.internal.telephony.NetworkFactory.CMD_REQUEST_NETWORK; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.net.NetworkCapabilities; import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; -import android.os.AsyncResult; -import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.telephony.AccessNetworkConstants; -import android.telephony.data.ApnSetting; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -49,9 +43,6 @@ import androidx.test.filters.FlakyTest; import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.dataconnection.DataConnection; -import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams; -import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams.HandoverCallback; import com.android.telephony.Rlog; import org.junit.After; @@ -59,9 +50,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -74,13 +63,12 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { // Mocked classes PhoneSwitcher mPhoneSwitcher; private RadioConfig mMockRadioConfig; - private DataConnection mDataConnection; private String mTestName = ""; // List of all requests filed by a test private final ArraySet mAllNetworkRequestSet = new ArraySet<>(); - // List of requests active in DcTracker + // List of requests active private final ArrayList mNetworkRequestList = new ArrayList<>(); // List of complete messages associated with the network requests private final Map mNetworkRequestMessageMap = new HashMap<>(); @@ -156,7 +144,6 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mPhoneSwitcher = mock(PhoneSwitcher.class); mMockRadioConfig = mock(RadioConfig.class); - mDataConnection = mock(DataConnection.class); replaceInstance(RadioConfig.class, "sRadioConfig", null, mMockRadioConfig); mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes, @@ -230,7 +217,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { } /** - * Test that phone active changes cause the DcTracker to get poked. + * Test that phone active changes */ @FlakyTest @Test @@ -301,7 +288,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { } /** - * Test that network request changes cause the DcTracker to get poked. + * Test that network request changes */ @Test @SmallTest @@ -364,79 +351,4 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { processAllMessages(); assertEquals(3, mNetworkRequestList.size()); } - - /** - * Test handover when there is no live data connection - */ - @Test - @SmallTest - public void testHandoverNoLiveData() throws Exception { - createMockedTelephonyComponents(); - doReturn(0).when(mSubscriptionController).getSubIdUsingPhoneId(0); - mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( - TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); - - activatePhoneInPhoneSwitcher(0, true); - makeDefaultInternetRequest(); - - makeSubSpecificMmsRequest(0); - processAllMessages(); - - Field f = TelephonyNetworkFactory.class.getDeclaredField("mInternalHandler"); - f.setAccessible(true); - Handler h = (Handler) f.get(mTelephonyNetworkFactoryUT); - - HandoverCallback handoverCallback = mock(HandoverCallback.class); - - HandoverParams hp = new HandoverParams(ApnSetting.TYPE_MMS, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN, handoverCallback); - AsyncResult ar = new AsyncResult(null, hp, null); - h.sendMessage(h.obtainMessage(5, ar)); - processAllMessages(); - - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) - .getCurrentTransport(anyInt()); - - hp = new HandoverParams(ApnSetting.TYPE_MMS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - handoverCallback); - ar = new AsyncResult(null, hp, null); - h.sendMessage(h.obtainMessage(5, ar)); - processAllMessages(); - } - - /** - * Test handover when the data connection is being connected. - */ - @Test - @SmallTest - public void testHandoverActivatingData() throws Exception { - createMockedTelephonyComponents(); - doReturn(0).when(mSubscriptionController).getSubIdUsingPhoneId(0); - mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( - TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); - - activatePhoneInPhoneSwitcher(0, true); - makeDefaultInternetRequest(); - - makeSubSpecificMmsRequest(0); - processAllMessages(); - - Field f = TelephonyNetworkFactory.class.getDeclaredField("mInternalHandler"); - f.setAccessible(true); - Handler h = (Handler) f.get(mTelephonyNetworkFactoryUT); - - HandoverCallback handoverCallback = mock(HandoverCallback.class); - Mockito.reset(mDataNetworkController); - doReturn(mDataConnection).when(mDcTracker).getDataConnectionByApnType(anyString()); - doReturn(false).when(mDataConnection).isActive(); - - HandoverParams hp = new HandoverParams(ApnSetting.TYPE_MMS, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN, handoverCallback); - AsyncResult ar = new AsyncResult(null, hp, null); - h.sendMessage(h.obtainMessage(5, ar)); - processAllMessages(); - - verify(mDataNetworkController, times(1)).removeNetworkRequest(any()); - verify(mDataNetworkController, times(1)).addNetworkRequest(any()); - } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java deleted file mode 100644 index f2d694fb6b..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnConfigTypeRepositoryTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2020 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.dataconnection; - -import static junit.framework.Assert.assertEquals; - -import android.os.PersistableBundle; -import android.telephony.CarrierConfigManager; -import android.telephony.data.ApnSetting; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -public class ApnConfigTypeRepositoryTest { - - PersistableBundle mCarrierConfig; - - @Before - public void setUp() throws Exception { - mCarrierConfig = new PersistableBundle(); - } - - @After - public void tearDown() { - mCarrierConfig = null; - } - - @Test - public void testReturnsDefaultsWhenCarrierConfigNull() { - ApnConfigTypeRepository repository = new ApnConfigTypeRepository(null); - checkDefaults(repository); - } - - @Test - public void testReturnsDefaultsWhenCarrierConfigApnContextKeyReturnsNull() { - mCarrierConfig.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, - null); - - ApnConfigTypeRepository repository = new ApnConfigTypeRepository(mCarrierConfig); - checkDefaults(repository); - } - - @Test - public void testReturnsDefaultsWhenCarrierConfigHasInvalidTypes() { - - List apnConfigStringArray = new ArrayList<>(); - apnConfigStringArray.add("xcap,cbs:3"); - apnConfigStringArray.add("default:0a"); - - mCarrierConfig.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, - apnConfigStringArray.toArray(new String[0])); - - ApnConfigTypeRepository repository = new ApnConfigTypeRepository(mCarrierConfig); - checkDefaults(repository); - } - - @Test - public void testReturnsCarrierConfigOverride() { - List apnConfigStringArray = new ArrayList<>(); - //Shouldn't match or override any keys - apnConfigStringArray.add("xcap,cbs:3"); - - //Priorities must be integers - apnConfigStringArray.add("default:10a"); - - //Key isn't case sensitive, which means that this priority should be taken - apnConfigStringArray.add("fotA:10"); - - mCarrierConfig.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, - apnConfigStringArray.toArray(new String[0])); - - ApnConfigTypeRepository repository = new ApnConfigTypeRepository(mCarrierConfig); - assertEquals(10, repository.getByType(ApnSetting.TYPE_FOTA).getPriority()); - checkDefaults(repository); - } - - private void checkDefaults(ApnConfigTypeRepository repository) { - assertEquals(0, repository.getByType(ApnSetting.TYPE_ENTERPRISE).getPriority()); - assertEquals(1, repository.getByType(ApnSetting.TYPE_DEFAULT).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_MMS).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_SUPL).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_DUN).getPriority()); - assertEquals(3, repository.getByType(ApnSetting.TYPE_HIPRI).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_IMS).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_CBS).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_IA).getPriority()); - assertEquals(2, repository.getByType(ApnSetting.TYPE_EMERGENCY).getPriority()); - assertEquals(3, repository.getByType(ApnSetting.TYPE_MCX).getPriority()); - assertEquals(3, repository.getByType(ApnSetting.TYPE_XCAP).getPriority()); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java deleted file mode 100644 index b27054875a..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2010 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.dataconnection; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; - -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.telephony.data.ApnSetting; -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.internal.R; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class ApnContextTest extends TelephonyTest { - // Mocked classes - ApnSetting mApnSetting; - - private ApnContext mApnContext; - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - mApnSetting = mock(ApnSetting.class); - mApnContext = new ApnContext(mPhone, ApnSetting.TYPE_DEFAULT, TAG, mDcTracker, 1); - } - - @After - public void tearDown() throws Exception { - mApnContext = null; - super.tearDown(); - } - - @Test - @SmallTest - public void testSetGetApnSetting() throws Exception { - mApnContext.setApnSetting(mApnSetting); - assertEquals(mApnSetting, mApnContext.getApnSetting()); - } - - @Test - @SmallTest - public void testGetApnType() { - assertEquals(ApnSetting.TYPE_DEFAULT_STRING, mApnContext.getApnType()); - } - - @Test - @SmallTest - public void testConnectionGeneration() throws Exception { - for (int i = 0; i < 100; i++) { - mApnContext.incAndGetConnectionGeneration(); - assertEquals(i + 1, mApnContext.getConnectionGeneration()); - } - } - - @Test - @SmallTest - public void testReason() throws Exception { - mApnContext.setReason("dataEnabled"); - assertEquals("dataEnabled", mApnContext.getReason()); - mApnContext.setReason("simLoaded"); - assertEquals("simLoaded", mApnContext.getReason()); - } - - @Test - @SmallTest - public void testState() throws Exception { - mApnContext.setState(DctConstants.State.DISCONNECTING); - assertEquals(DctConstants.State.DISCONNECTING, mApnContext.getState()); - mApnContext.setEnabled(true); - assertFalse(mApnContext.isConnectable()); - - mApnContext.setState(DctConstants.State.RETRYING); - assertTrue(mApnContext.isConnectable()); - assertTrue(mApnContext.isConnectedOrConnecting()); - - mApnContext.setState(DctConstants.State.FAILED); - assertTrue(mApnContext.isDisconnected()); - mApnContext.setState(DctConstants.State.IDLE); - assertTrue(mApnContext.isDisconnected()); - } - - @Test - @SmallTest - public void testNetworkRequestNormal() throws Exception { - NetworkRequest nr1 = new NetworkRequest.Builder().build(); - mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, null); - - verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); - - NetworkRequest nr2 = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .build(); - - mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, null); - verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); - - mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_NORMAL); - verify(mDcTracker, never()).disableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.RELEASE_TYPE_NORMAL)); - - mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL); - verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.RELEASE_TYPE_NORMAL)); - } - - @Test - @SmallTest - public void testNetworkRequestDetach() throws Exception { - NetworkRequest nr1 = new NetworkRequest.Builder().build(); - mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, null); - verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); - - NetworkRequest nr2 = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .build(); - - mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, null); - verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.REQUEST_TYPE_NORMAL), eq(null)); - - mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_DETACH); - verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.RELEASE_TYPE_DETACH)); - - mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL); - verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.RELEASE_TYPE_NORMAL)); - } - - @Test - @SmallTest - public void testNetworkRequestHandover() throws Exception { - NetworkRequest nr1 = new NetworkRequest.Builder().build(); - mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_HANDOVER, null); - verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.REQUEST_TYPE_HANDOVER), eq(null)); - - mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_HANDOVER); - verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT), - eq(DcTracker.RELEASE_TYPE_HANDOVER)); - } - - @Test - @SmallTest - public void testConcurrentVoiceAndDataAllowed() throws Exception { - mApnContext.setConcurrentVoiceAndDataAllowed(true); - assertTrue(mApnContext.isConcurrentVoiceAndDataAllowed()); - mApnContext.setConcurrentVoiceAndDataAllowed(false); - assertFalse(mApnContext.isConcurrentVoiceAndDataAllowed()); - } - - @Test - @SmallTest - public void testEnableDisable() throws Exception { - mApnContext.setEnabled(true); - assertTrue(mApnContext.isEnabled()); - mApnContext.setEnabled(false); - assertFalse(mApnContext.isEnabled()); - } - - @Test - @SmallTest - public void testProvisionApn() throws Exception { - mContextFixture.putResource(R.string.mobile_provisioning_apn, "fake_apn"); - - ApnSetting myApn = new ApnSetting.Builder() - .setId(2163) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("fake_apn") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - mApnContext.setApnSetting(myApn); - assertTrue(mApnContext.isProvisioningApn()); - mApnContext.setApnSetting(mApnSetting); - assertFalse(mApnContext.isProvisioningApn()); - } - - @Test - @SmallTest - public void testIsReady() throws Exception { - mApnContext.setEnabled(true); - assertTrue(mApnContext.isReady()); - - mApnContext.setEnabled(false); - assertFalse(mApnContext.isReady()); - } - - @Test - @SmallTest - public void testErrorCodeRetry() throws Exception { - mContextFixture.putStringArrayResource( - com.android.internal.R.array.config_cell_retries_per_error_code, - new String[]{"36,2"}); - mApnContext.resetErrorCodeRetries(); - - assertFalse(mApnContext.restartOnError(36)); - assertTrue(mApnContext.restartOnError(36)); - assertFalse(mApnContext.restartOnError(37)); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java deleted file mode 100644 index dcaa2a0269..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java +++ /dev/null @@ -1,1479 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; - -import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Matchers.argThat; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.pm.UserInfo; -import android.net.InetAddresses; -import android.net.KeepalivePacketData; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.net.NattKeepalivePacketData; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.vcn.VcnNetworkPolicyResult; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Message; -import android.os.UserManager; -import android.provider.Telephony; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.AccessNetworkType; -import android.telephony.CarrierConfigManager; -import android.telephony.ServiceState; -import android.telephony.ServiceState.RegState; -import android.telephony.ServiceState.RilRadioTechnology; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.telephony.data.DataProfile; -import android.telephony.data.DataService; -import android.telephony.data.DataServiceCallback; -import android.telephony.data.TrafficDescriptor; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; -import android.util.Pair; - -import com.android.internal.R; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.data.KeepaliveStatus; -import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams; -import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams; -import com.android.internal.telephony.dataconnection.DataConnection.SetupResult; -import com.android.internal.telephony.metrics.DataCallSessionStats; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.function.Consumer; - -public class DataConnectionTest extends TelephonyTest { - private static final int DEFAULT_DC_CID = 10; - private static final ArrayList DEFAULT_TD_LIST = new ArrayList<>(); - - // Mocked classes - DcTesterFailBringUpAll mDcTesterFailBringUpAll; - ConnectionParams mCp; - DisconnectParams mDcp; - ApnContext mApnContext; - ApnContext mEnterpriseApnContext; - DcFailBringUp mDcFailBringUp; - DataCallSessionStats mDataCallSessionStats; - DataConnection mDefaultDc; - DataServiceManager mDataServiceManager; - - private DataConnection mDc; - private DataConnectionTestHandler mDataConnectionTestHandler; - private DcController mDcc; - - private final ApnSetting mApn1 = new ApnSetting.Builder() - .setId(2163) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private final ApnSetting mApn2 = new ApnSetting.Builder() - .setId(2164) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private final ApnSetting mApn3 = new ApnSetting.Builder() - .setId(2165) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setNetworkTypeBitmask(0) - .setCarrierEnabled(true) - .setCarrierId(1) - .setSkip464Xlat(1) - .build(); - - private final ApnSetting mApn4 = new ApnSetting.Builder() - .setId(2166) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_IMS) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private final ApnSetting mApn5 = new ApnSetting.Builder() - .setId(2167) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_IMS) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .setSkip464Xlat(Telephony.Carriers.SKIP_464XLAT_DISABLE) - .build(); - - private final ApnSetting mApn6 = new ApnSetting.Builder() - .setId(2168) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_EMERGENCY) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private class DataConnectionTestHandler extends HandlerThread { - - private DataConnectionTestHandler(String name) { - super(name); - } - - @Override - public void onLooperPrepared() { - Handler h = new Handler(); - mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, h.getLooper(), ""); - mDc = DataConnection.makeDataConnection(mPhone, 0, mDcTracker, mDataServiceManager, - mDcTesterFailBringUpAll, mDcc); - } - } - - private void setSuccessfulSetupDataResponse(int cid, ArrayList tds) { - doAnswer(invocation -> { - final Message msg = (Message) invocation.getArguments()[10]; - - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1L) - .setId(cid) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) - .setInterfaceName("ifname") - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress("10.0.2.15"), 32), - new LinkAddress("2607:fb90:a620:651d:eabe:f8da:c107:44be/64"))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), - InetAddresses.parseNumericAddress("fd00:976a::9"))) - .setGatewayAddresses(Arrays.asList( - InetAddresses.parseNumericAddress("10.0.2.15"), - InetAddresses.parseNumericAddress("fe80::2"))) - .setPcscfAddresses(Arrays.asList( - InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), - InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), - InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) - .setMtu(1500) - .setMtuV4(1500) - .setMtuV6(1500) - .setPduSessionId(1) - .setQosBearerSessions(new ArrayList<>()) - .setTrafficDescriptors(tds) - .build(); - msg.getData().putParcelable("data_call_response", response); - msg.arg1 = DataServiceCallback.RESULT_SUCCESS; - msg.sendToTarget(); - return null; - }).when(mDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), - anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), - any(Message.class)); - } - - private void setFailedSetupDataResponse(@DataServiceCallback.ResultCode int resultCode) { - doAnswer(invocation -> { - final Message msg = (Message) invocation.getArguments()[10]; - msg.arg1 = resultCode; - msg.sendToTarget(); - return null; - }).when(mDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), - anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), - any(Message.class)); - } - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - mDcTesterFailBringUpAll = mock(DcTesterFailBringUpAll.class); - mCp = mock(ConnectionParams.class); - mDcp = mock(DisconnectParams.class); - mApnContext = mock(ApnContext.class); - mEnterpriseApnContext = mock(ApnContext.class); - mDcFailBringUp = mock(DcFailBringUp.class); - mDataCallSessionStats = mock(DataCallSessionStats.class); - mDefaultDc = mock(DataConnection.class); - mDataServiceManager = mock(DataServiceManager.class); - logd("+Setup!"); - doReturn("fake.action_detached").when(mPhone).getActionDetached(); - doReturn(false).when(mPhone).isUsingNewDataStack(); - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext); - replaceInstance(ConnectionParams.class, "mRilRat", mCp, - ServiceState.RIL_RADIO_TECHNOLOGY_UMTS); - doReturn(mApn1).when(mApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_DEFAULT_STRING).when(mApnContext).getApnType(); - doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); - - mDcFailBringUp.saveParameters(0, 0, -2); - doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp(); - - mContextFixture.putStringArrayResource(com.android.internal.R.array - .config_mobile_tcp_buffers, new String[]{ - "umts:131072,262144,1452032,4096,16384,399360", - "hspa:131072,262144,2441216,4096,16384,399360", - "hsupa:131072,262144,2441216,4096,16384,399360", - "hsdpa:131072,262144,2441216,4096,16384,399360", - "hspap:131072,262144,2441216,4096,16384,399360", - "edge:16384,32768,131072,4096,16384,65536", - "gprs:4096,8192,24576,4096,8192,24576", - "1xrtt:16384,32768,131070,4096,16384,102400", - "evdo:131072,262144,1048576,4096,16384,524288", - "lte:524288,1048576,8388608,262144,524288,4194304"}); - - mContextFixture.putResource(R.string.config_wwan_data_service_package, - "com.android.phone"); - - mDcp.mApnContext = mApnContext; - - setSuccessfulSetupDataResponse(DEFAULT_DC_CID, DEFAULT_TD_LIST); - - doAnswer(invocation -> { - final Message msg = (Message) invocation.getArguments()[2]; - msg.arg1 = DataServiceCallback.RESULT_SUCCESS; - msg.sendToTarget(); - return null; - }).when(mDataServiceManager).deactivateDataCall(anyInt(), anyInt(), any(Message.class)); - - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mDataServiceManager) - .getTransportType(); - - mDataConnectionTestHandler = new DataConnectionTestHandler(getClass().getSimpleName()); - mDataConnectionTestHandler.start(); - - waitForMs(200); - mDc.setDataCallSessionStats(mDataCallSessionStats); - - logd("-Setup!"); - } - - @After - public void tearDown() throws Exception { - logd("tearDown"); - mDc.quitNow(); - mDc = null; - mDataConnectionTestHandler.quit(); - mDataConnectionTestHandler.join(); - mDataConnectionTestHandler = null; - mDcc.removeCallbacksAndMessages(null); - mDcc = null; - DEFAULT_TD_LIST.clear(); - waitForMs(100); - super.tearDown(); - } - - private long getSuggestedRetryDelay(DataCallResponse response) throws Exception { - Class[] cArgs = new Class[1]; - cArgs[0] = DataCallResponse.class; - Method method = DataConnection.class.getDeclaredMethod("getSuggestedRetryDelay", cArgs); - method.setAccessible(true); - return (long) method.invoke(mDc, response); - } - - private boolean isUnmeteredUseOnly() throws Exception { - Method method = DataConnection.class.getDeclaredMethod("isUnmeteredUseOnly"); - method.setAccessible(true); - return (boolean) method.invoke(mDc); - } - - private boolean isEnterpriseUse() throws Exception { - Method method = DataConnection.class.getDeclaredMethod("isEnterpriseUse"); - method.setAccessible(true); - return (boolean) method.invoke(mDc); - } - - private boolean isSuspended() throws Exception { - Field field = DataConnection.class.getDeclaredField("mIsSuspended"); - field.setAccessible(true); - return field.getBoolean(mDc); - } - - private SetupResult setLinkProperties(DataCallResponse response, LinkProperties linkProperties) - throws Exception { - Class[] cArgs = new Class[2]; - cArgs[0] = DataCallResponse.class; - cArgs[1] = LinkProperties.class; - Method method = DataConnection.class.getDeclaredMethod("setLinkProperties", cArgs); - method.setAccessible(true); - return (SetupResult) method.invoke(mDc, response, linkProperties); - } - - @Test - @SmallTest - public void testConnectEvent() { - assertTrue(mDc.isInactive()); - connectEvent(true); - - verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class), - eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null)); - verify(mCT, times(1)).registerForVoiceCallEnded(any(Handler.class), - eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED), eq(null)); - verify(mSimulatedCommandsVerifier, times(1)) - .registerForNattKeepaliveStatus(any(Handler.class), - eq(DataConnection.EVENT_KEEPALIVE_STATUS), eq(null)); - verify(mSimulatedCommandsVerifier, times(1)) - .registerForLceInfo(any(Handler.class), - eq(DataConnection.EVENT_LINK_CAPACITY_CHANGED), eq(null)); - verify(mVcnManager, atLeastOnce()) - .applyVcnNetworkPolicy( - argThat(caps -> - caps.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)), - any()); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mDataServiceManager, times(1)).setupDataCall( - eq(AccessNetworkType.UTRAN), dpCaptor.capture(), eq(false), - eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), tdCaptor.capture(), anyBoolean(), any(Message.class)); - - verify(mSimulatedCommandsVerifier, times(0)) - .allocatePduSessionId(any()); - - assertEquals("spmode.ne.jp", dpCaptor.getValue().getApn()); - if (tdCaptor.getValue() != null) { - if (mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - } else { - assertEquals("spmode.ne.jp", tdCaptor.getValue().getDataNetworkName()); - assertEquals(null, tdCaptor.getValue().getOsAppId()); - } - } - assertTrue(mDc.isActive()); - - assertEquals(1, mDc.getPduSessionId()); - assertEquals(3, mDc.getPcscfAddresses().length); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::8"::equals)); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c202:1d::7"::equals)); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::5"::equals)); - } - - @Test - @SmallTest - public void testConnectOnIwlan() throws Exception { - assertTrue(mDc.isInactive()); - Field field = DataConnection.class.getDeclaredField("mTransportType"); - field.setAccessible(true); - field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - connectEvent(true); - - verify(mCT, times(1)).registerForVoiceCallStarted(any(Handler.class), - eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED), eq(null)); - verify(mCT, times(1)).registerForVoiceCallEnded(any(Handler.class), - eq(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_ENDED), eq(null)); - verify(mSimulatedCommandsVerifier, times(0)) - .registerForNattKeepaliveStatus(any(Handler.class), - eq(DataConnection.EVENT_KEEPALIVE_STATUS), eq(null)); - verify(mSimulatedCommandsVerifier, times(0)) - .registerForLceInfo(any(Handler.class), - eq(DataConnection.EVENT_LINK_CAPACITY_CHANGED), eq(null)); - verify(mVcnManager, atLeastOnce()) - .applyVcnNetworkPolicy( - argThat(caps -> - caps.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)), - any()); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mDataServiceManager, times(1)).setupDataCall( - eq(AccessNetworkType.UTRAN), dpCaptor.capture(), eq(false), - eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), tdCaptor.capture(), anyBoolean(), any(Message.class)); - - verify(mSimulatedCommandsVerifier, times(1)) - .allocatePduSessionId(any()); - - assertEquals("spmode.ne.jp", dpCaptor.getValue().getApn()); - if (tdCaptor.getValue() != null) { - if (mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) { - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - } else { - assertEquals("spmode.ne.jp", tdCaptor.getValue().getDataNetworkName()); - assertEquals(null, tdCaptor.getValue().getOsAppId()); - } - } - assertTrue(mDc.isActive()); - - assertEquals(1, mDc.getPduSessionId()); - assertEquals(3, mDc.getPcscfAddresses().length); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::8"::equals)); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c202:1d::7"::equals)); - assertTrue(Arrays.stream(mDc.getPcscfAddresses()).anyMatch("fd00:976a:c305:1d::5"::equals)); - } - - @Test - public void testConnectEventDuplicateContextIds() throws Exception { - setUpDefaultData(DEFAULT_DC_CID); - - // Try to connect ENTERPRISE with the same CID as default - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); - doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); - - // Verify that ENTERPRISE wasn't set up - connectEvent(false); - assertTrue(mDc.isInactive()); - - // Change the CID - setSuccessfulSetupDataResponse(DEFAULT_DC_CID + 1, DEFAULT_TD_LIST); - - // Verify that ENTERPRISE was set up - connectEvent(true); - assertTrue(mDc.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - } - - @Test - public void testConnectEventDuplicateContextIdsDifferentTDs() throws Exception { - setUpDefaultData(DEFAULT_DC_CID); - - // Try to connect ENTERPRISE with the same CID as default but different TrafficDescriptors - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); - doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); - ArrayList tdList = new ArrayList<>(); - tdList.add(new TrafficDescriptor("dnn", DataConnection.getEnterpriseOsAppId())); - setSuccessfulSetupDataResponse(DEFAULT_DC_CID, tdList); - - // Verify that ENTERPRISE wasn't set up but the TD list was updated - connectEvent(false); - assertTrue(mDc.isInactive()); - ArgumentCaptor captor = ArgumentCaptor.forClass(DataCallResponse.class); - verify(mDefaultDc).updateTrafficDescriptors(captor.capture()); - assertEquals(tdList, captor.getValue().getTrafficDescriptors()); - } - - @Test - public void testConnectEventNoDefaultData() throws Exception { - assertFalse(mDefaultDc.isActive()); - - // Try to connect ENTERPRISE when default data doesn't exist - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); - doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); - - // Verify that ENTERPRISE wasn't set up - connectEvent(false); - assertTrue(mDc.isInactive()); - - // Set up default data - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext); - setUpDefaultData(1); - - // Verify that ENTERPRISE was set up - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - connectEvent(true); - assertTrue(mDc.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - } - - private void setUpDefaultData(int cid) throws Exception { - replaceInstance(DataConnection.class, "mCid", mDefaultDc, cid); - doReturn(true).when(mDefaultDc).isActive(); - doReturn(Arrays.asList(mApnContext)).when(mDefaultDc).getApnContexts(); - mDcc.addActiveDcByCid(mDefaultDc); - assertTrue(mDefaultDc.getApnContexts().stream() - .anyMatch(apn -> apn.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT)); - } - - @Test - @SmallTest - public void testDisconnectEvent() { - testConnectEvent(); - - mDc.setPduSessionId(5); - disconnectEvent(); - - verify(mSimulatedCommandsVerifier, times(1)).unregisterForLceInfo(any(Handler.class)); - verify(mSimulatedCommandsVerifier, times(1)) - .unregisterForNattKeepaliveStatus(any(Handler.class)); - verify(mDataServiceManager, times(1)).deactivateDataCall(eq(DEFAULT_DC_CID), - eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); - verify(mSimulatedCommandsVerifier, times(0)) - .releasePduSessionId(any(), eq(5)); - - assertTrue(mDc.isInactive()); - } - - @Test - @SmallTest - public void testDisconnectOnIwlan() throws Exception { - testConnectEvent(); - - Field field = DataConnection.class.getDeclaredField("mTransportType"); - field.setAccessible(true); - field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - mDc.setPduSessionId(5); - disconnectEvent(); - - verify(mSimulatedCommandsVerifier, times(0)).unregisterForLceInfo(any(Handler.class)); - verify(mSimulatedCommandsVerifier, times(0)) - .unregisterForNattKeepaliveStatus(any(Handler.class)); - verify(mDataServiceManager, times(1)).deactivateDataCall(eq(DEFAULT_DC_CID), - eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); - verify(mSimulatedCommandsVerifier, times(1)) - .releasePduSessionId(any(), eq(5)); - - assertTrue(mDc.isInactive()); - } - - @Test - @SmallTest - public void testModemSuggestRetry() throws Exception { - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(0) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response)); - - response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(1000) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response)); - - response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(9999) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(response.getSuggestedRetryTime(), getSuggestedRetryDelay(response)); - } - - @Test - @SmallTest - public void testModemNotSuggestRetry() throws Exception { - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response)); - - response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-5) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response)); - - response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(Long.MIN_VALUE) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, getSuggestedRetryDelay(response)); - } - - @Test - @SmallTest - public void testModemSuggestNoRetry() throws Exception { - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(Long.MAX_VALUE) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - assertEquals(RetryManager.NO_RETRY, getSuggestedRetryDelay(response)); - } - - private NetworkCapabilities getNetworkCapabilities() throws Exception { - Method method = DataConnection.class.getDeclaredMethod("getNetworkCapabilities"); - method.setAccessible(true); - return (NetworkCapabilities) method.invoke(mDc); - } - - private int getDisallowedApnTypes() throws Exception { - Method method = DataConnection.class.getDeclaredMethod("getDisallowedApnTypes"); - method.setAccessible(true); - return (int) method.invoke(mDc); - } - - @Test - @SmallTest - public void testNetworkCapability() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - doReturn(mApn2).when(mApnContext).getApnSetting(); - testConnectEvent(); - - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY, - new String[] {"supl"}); - - disconnectEvent(); - doReturn(mApn1).when(mApnContext).getApnSetting(); - connectEvent(true); - - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - } - - @Test - @SmallTest - public void testVcnNetworkCapability() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - doReturn(mApn2).when(mApnContext).getApnSetting(); - - doAnswer(invocation -> { - NetworkCapabilities nc = invocation.getArgument(0); - NetworkCapabilities policyNc = new NetworkCapabilities.Builder(nc) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .build(); - - return new VcnNetworkPolicyResult( - false /* isTearDownRequested */, policyNc); - }).when(mVcnManager).applyVcnNetworkPolicy(any(), any()); - connectEvent(true); - - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)); - - disconnectEvent(); - - doAnswer(invocation -> { - NetworkCapabilities nc = invocation.getArgument(0); - NetworkCapabilities policyNc = new NetworkCapabilities.Builder(nc) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) - .build(); - - return new VcnNetworkPolicyResult( - false /* isTearDownRequested */, policyNc); - }).when(mVcnManager).applyVcnNetworkPolicy(any(), any()); - connectEvent(true); - - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)); - } - - @Test - @SmallTest - public void testEnterpriseNetworkCapability() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - doReturn(mApn2).when(mApnContext).getApnSetting(); - testConnectEvent(); - - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - - disconnectEvent(); - setUpDefaultData(1); - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); - doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); - connectEvent(true); - - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)); - assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)); - assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - } - - @Test - @SmallTest - public void testMeteredCapability() throws Exception { - - mContextFixture.getCarrierConfigBundle(). - putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] {"default"}); - - testConnectEvent(); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - } - - @Test - @SmallTest - public void testNonMeteredCapability() throws Exception { - - doReturn(2819).when(mPhone).getSubId(); - mContextFixture.getCarrierConfigBundle(). - putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] {"mms"}); - - testConnectEvent(); - - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - } - - @Test - public void testOverrideUnmetered() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - testConnectEvent(); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - - mDc.onMeterednessChanged(true); - waitForMs(100); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - - mDc.onMeterednessChanged(false); - waitForMs(100); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - } - - @Test - public void testOverrideCongested() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - testConnectEvent(); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - - mDc.onCongestednessChanged(true); - waitForMs(100); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - - mDc.onCongestednessChanged(false); - waitForMs(100); - - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED)); - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - } - - @Test - public void testOwnerUid() throws Exception { - Context mockContext = mContextFixture.getTestDouble(); - doReturn(mockContext).when(mPhone).getContext(); - - String testPkg = "com.android.telephony.test"; - TelephonyManager telMgr = mockContext.getSystemService(TelephonyManager.class); - doReturn(testPkg).when(telMgr).getCarrierServicePackageNameForLogicalSlot(anyInt()); - - UserInfo info = new UserInfo(0 /* id */, "TEST_USER", 0 /* flags */); - UserManager userMgr = mockContext.getSystemService(UserManager.class); - doReturn(Collections.singletonList(info)).when(userMgr).getUsers(); - - int carrierConfigPkgUid = 12345; - PackageManager pkgMgr = mockContext.getPackageManager(); - doReturn(carrierConfigPkgUid).when(pkgMgr).getPackageUidAsUser(eq(testPkg), anyInt()); - - mContextFixture - .getCarrierConfigBundle() - .putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] {"default"}); - testConnectEvent(); - AsyncResult adminUidsResult = new AsyncResult(null, new int[] {carrierConfigPkgUid}, null); - mDc.sendMessage(DataConnection.EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED, adminUidsResult); - // Wait for carirer privilege UIDs to be updated - waitForMs(100); - - assertEquals(carrierConfigPkgUid, getNetworkCapabilities().getOwnerUid()); - assertEquals( - Collections.singleton(carrierConfigPkgUid), - getNetworkCapabilities().getAllowedUids()); - } - - @Test - public void testSubscriptionIds() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - testConnectEvent(); - - assertEquals(Collections.singleton(0), getNetworkCapabilities().getSubscriptionIds()); - } - - @Test - public void testShouldSkip464Xlat() throws Exception { - assertFalse(testShouldSkip464XlatEvent(mApn1)); - disconnectEvent(); - - assertTrue(testShouldSkip464XlatEvent(mApn3)); - disconnectEvent(); - - assertTrue(testShouldSkip464XlatEvent(mApn4)); - disconnectEvent(); - - assertFalse(testShouldSkip464XlatEvent(mApn5)); - disconnectEvent(); - } - - private boolean testShouldSkip464XlatEvent(ApnSetting apn) throws Exception { - Method method = DataConnection.class.getDeclaredMethod("shouldSkip464Xlat"); - method.setAccessible(true); - - doReturn(apn).when(mApnContext).getApnSetting(); - doReturn(apn.getApnTypeBitmask()).when(mApnContext).getApnTypeBitmask(); - connectEvent(true); - logd(getNetworkCapabilities().toString()); - - return (Boolean) method.invoke(mDc); - } - - private void connectEvent(boolean validate) { - mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp); - waitForMs(200); - if (validate) { - assertTrue(mDc.isActive()); - } - } - - private void disconnectEvent() { - mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp); - waitForMs(100); - assertTrue(mDc.isInactive()); - } - - private void serviceStateChangedEvent(@RegState int dataRegState, @RilRadioTechnology int rat) { - mDc.obtainMessage(DataConnection.EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED, - new AsyncResult(null, new Pair<>(dataRegState, rat), null)).sendToTarget(); - waitForMs(100); - } - - @Test - @SmallTest - public void testIsIpAddress() { - // IPv4 - assertTrue(DataConnection.isIpAddress("1.2.3.4")); - assertTrue(DataConnection.isIpAddress("127.0.0.1")); - - // IPv6 - assertTrue(DataConnection.isIpAddress("::1")); - assertTrue(DataConnection.isIpAddress("2001:4860:800d::68")); - } - - @Test - @SmallTest - public void testSetLinkProperties() throws Exception { - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - - LinkProperties linkProperties = new LinkProperties(); - assertEquals(SetupResult.SUCCESS, setLinkProperties(response, linkProperties)); - logd(linkProperties.toString()); - assertEquals(response.getInterfaceName(), linkProperties.getInterfaceName()); - assertEquals(response.getAddresses().size(), linkProperties.getAddresses().size()); - for (int i = 0; i < response.getAddresses().size(); ++i) { - assertEquals(response.getAddresses().get(i).getAddress(), - InetAddresses.parseNumericAddress(linkProperties.getLinkAddresses().get(i) - .getAddress().getHostAddress())); - } - - assertEquals(response.getDnsAddresses().size(), linkProperties.getDnsServers().size()); - for (int i = 0; i < response.getDnsAddresses().size(); ++i) { - assertEquals("i = " + i, response.getDnsAddresses().get(i), - InetAddresses.parseNumericAddress( - linkProperties.getDnsServers().get(i).getHostAddress())); - } - - assertEquals(response.getGatewayAddresses().size(), linkProperties.getRoutes().size()); - for (int i = 0; i < response.getGatewayAddresses().size(); ++i) { - assertEquals("i = " + i, response.getGatewayAddresses().get(i), - InetAddresses.parseNumericAddress(linkProperties.getRoutes().get(i) - .getGateway().getHostAddress())); - } - - assertEquals(response.getPcscfAddresses().size(), linkProperties.getPcscfServers().size()); - for (int i = 0; i < response.getPcscfAddresses().size(); ++i) { - assertEquals("i = " + i, response.getPcscfAddresses().get(i), - InetAddresses.parseNumericAddress(linkProperties.getPcscfServers().get(i) - .getHostAddress())); - } - - assertEquals(response.getMtu(), linkProperties.getMtu()); - } - - @Test - @SmallTest - public void testSetLinkPropertiesEmptyAddress() throws Exception { - // 224.224.224.224 is an invalid address. - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - - LinkProperties linkProperties = new LinkProperties(); - assertEquals(SetupResult.ERROR_INVALID_ARG, setLinkProperties(response, linkProperties)); - } - - @Test - @SmallTest - public void testSetLinkPropertiesEmptyDns() throws Exception { - // Empty dns entry. - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - - // Make sure no exception was thrown - LinkProperties linkProperties = new LinkProperties(); - assertEquals(SetupResult.SUCCESS, setLinkProperties(response, linkProperties)); - } - - @Test - @SmallTest - public void testStartKeepaliveWLAN() throws Exception { - testConnectEvent(); - waitForMs(200); - - Field field = DataConnection.class.getDeclaredField("mTransportType"); - field.setAccessible(true); - field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - - final int sessionHandle = 0xF00; - final int slotId = 3; - final int interval = 10; // seconds - // Construct a new KeepalivePacketData request as we would receive from a Network Agent, - // and check that the packet is sent to the RIL. - KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket( - InetAddresses.parseNumericAddress("1.2.3.4"), - 1234, - InetAddresses.parseNumericAddress("8.8.8.8"), - 4500); - mDc.obtainMessage( - DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget(); - waitForMs(100); - // testStartStopNattKeepalive() verifies that this request is passed with WWAN. - // Thus, even though we can't see the response in NetworkAgent, we can verify that the - // CommandsInterface never receives a request and infer that it was dropped due to WLAN. - verify(mSimulatedCommandsVerifier, times(0)) - .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class)); - } - - public void checkStartStopNattKeepalive(boolean useCondensedFlow) throws Exception { - testConnectEvent(); - waitForMs(200); - - final int sessionHandle = 0xF00; - final int slotId = 3; - final int interval = 10; // seconds - // Construct a new KeepalivePacketData request as we would receive from a Network Agent, - // and check that the packet is sent to the RIL. - KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket( - InetAddresses.parseNumericAddress("1.2.3.4"), - 1234, - InetAddresses.parseNumericAddress("8.8.8.8"), - 4500); - mDc.obtainMessage( - DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget(); - waitForMs(100); - verify(mSimulatedCommandsVerifier, times(1)) - .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class)); - - Message kaStarted = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STARTED, slotId, 0); - if (useCondensedFlow) { - // Send a singled condensed response that a keepalive have been requested and the - // activation is completed. This flow should be used if the keepalive offload request - // is handled by a high-priority signalling path. - AsyncResult.forMessage( - kaStarted, new KeepaliveStatus( - sessionHandle, KeepaliveStatus.STATUS_ACTIVE), null); - kaStarted.sendToTarget(); - } else { - // Send the sequential responses indicating first that the request was received and - // then that the keepalive is running. This should create an active record of the - // keepalive in DataConnection while permitting the status from a low priority or other - // high-latency handler to activate the keepalive without blocking a request. - AsyncResult.forMessage( - kaStarted, new KeepaliveStatus( - sessionHandle, KeepaliveStatus.STATUS_PENDING), null); - kaStarted.sendToTarget(); - Message kaRunning = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STATUS); - AsyncResult.forMessage( - kaRunning, new KeepaliveStatus( - sessionHandle, KeepaliveStatus.STATUS_ACTIVE), null); - kaRunning.sendToTarget(); - } - waitForMs(100); - - // Verify that we can stop the connection, which checks that the record in DataConnection - // has a valid mapping between slotId (from network agent) to sessionHandle (from Radio). - mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget(); - waitForMs(100); - verify(mSimulatedCommandsVerifier, times(1)) - .stopNattKeepalive(eq(sessionHandle), any(Message.class)); - - Message kaStopped = mDc.obtainMessage( - DataConnection.EVENT_KEEPALIVE_STOPPED, sessionHandle, slotId); - AsyncResult.forMessage(kaStopped); - kaStopped.sendToTarget(); - // Verify that after the connection is stopped, the mapping for a Keepalive Session is - // removed. Thus, subsequent calls to stop the same keepalive are ignored. - mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget(); - waitForMs(100); - // Check that the mock has not been called subsequent to the previous invocation - // while avoiding the use of reset() - verify(mSimulatedCommandsVerifier, times(1)) - .stopNattKeepalive(anyInt(), any(Message.class)); - } - - @Test - @MediumTest - public void testStartStopNattKeepalive() throws Exception { - checkStartStopNattKeepalive(false); - } - - @Test - @MediumTest - public void testStartStopNattKeepaliveCondensed() throws Exception { - checkStartStopNattKeepalive(true); - } - - public void checkStartNattKeepaliveFail(boolean useCondensedFlow) throws Exception { - testConnectEvent(); - waitForMs(200); - - final int sessionHandle = 0xF00; - final int slotId = 3; - final int interval = 10; // seconds - // Construct a new KeepalivePacketData request as we would receive from a Network Agent, - // and check that the packet is sent to the RIL. - KeepalivePacketData kd = NattKeepalivePacketData.nattKeepalivePacket( - InetAddresses.parseNumericAddress("1.2.3.4"), - 1234, - InetAddresses.parseNumericAddress("8.8.8.8"), - 4500); - mDc.obtainMessage( - DataConnection.EVENT_KEEPALIVE_START_REQUEST, slotId, interval, kd).sendToTarget(); - waitForMs(100); - verify(mSimulatedCommandsVerifier, times(1)) - .startNattKeepalive(anyInt(), eq(kd), eq(interval * 1000), any(Message.class)); - - Message kaStarted = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STARTED, slotId, 0); - if (useCondensedFlow) { - // Indicate in the response that the keepalive has failed. - AsyncResult.forMessage( - kaStarted, new KeepaliveStatus(KeepaliveStatus.ERROR_UNSUPPORTED), - null); - kaStarted.sendToTarget(); - } else { - // Indicate that the keepalive is queued, and then signal a failure from the modem - // such that a pending keepalive fails to activate. - AsyncResult.forMessage( - kaStarted, new KeepaliveStatus( - sessionHandle, KeepaliveStatus.STATUS_PENDING), null); - kaStarted.sendToTarget(); - Message kaRunning = mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STATUS); - AsyncResult.forMessage( - kaRunning, new KeepaliveStatus( - sessionHandle, KeepaliveStatus.STATUS_INACTIVE), null); - kaRunning.sendToTarget(); - } - waitForMs(100); - // Verify that a failed connection request cannot be stopped due to no record in - // the DataConnection. - mDc.obtainMessage(DataConnection.EVENT_KEEPALIVE_STOP_REQUEST, slotId).sendToTarget(); - waitForMs(100); - verify(mSimulatedCommandsVerifier, times(0)) - .stopNattKeepalive(anyInt(), any(Message.class)); - } - - @Test - @SmallTest - public void testStartNattKeepaliveFail() throws Exception { - checkStartNattKeepaliveFail(false); - } - - @Test - @SmallTest - public void testStartNattKeepaliveFailCondensed() throws Exception { - checkStartNattKeepaliveFail(true); - } - - @Test - @SmallTest - public void testIsUnmeteredUseOnly() throws Exception { - Field field = DataConnection.class.getDeclaredField("mTransportType"); - field.setAccessible(true); - field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - - assertFalse(isUnmeteredUseOnly()); - - field = DataConnection.class.getDeclaredField("mTransportType"); - field.setAccessible(true); - field.setInt(mDc, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mServiceState).getDataRoaming(); - doReturn(ApnSetting.TYPE_MMS).when(mApnContext).getApnTypeBitmask(); - - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[] { "default" }); - - assertTrue(isUnmeteredUseOnly()); - } - - @Test - public void testIsEnterpriseUse() throws Exception { - assertFalse(isEnterpriseUse()); - assertFalse(mDc.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - - setUpDefaultData(1); - replaceInstance(ConnectionParams.class, "mApnContext", mCp, mEnterpriseApnContext); - doReturn(mApn1).when(mEnterpriseApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_ENTERPRISE_STRING).when(mEnterpriseApnContext).getApnType(); - doReturn(ApnSetting.TYPE_ENTERPRISE).when(mEnterpriseApnContext).getApnTypeBitmask(); - connectEvent(true); - - assertTrue(isEnterpriseUse()); - assertTrue(mDc.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); - } - - @Test - @SmallTest - public void testGetDisallowedApnTypes() throws Exception { - mContextFixture.getCarrierConfigBundle().putStringArray( - CarrierConfigManager.KEY_CARRIER_WWAN_DISALLOWED_APN_TYPES_STRING_ARRAY, - new String[] { "mms", "supl", "fota" }); - testConnectEvent(); - - assertEquals(ApnSetting.TYPE_MMS | ApnSetting.TYPE_SUPL | ApnSetting.TYPE_FOTA, - getDisallowedApnTypes()); - } - - @Test - public void testIsSuspended() throws Exception { - // Return false if not active state - assertTrue(mDc.isInactive()); - assertFalse(isSuspended()); - - // Return false for emergency APN - doReturn(mApn6).when(mApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_EMERGENCY).when(mApnContext).getApnTypeBitmask(); - connectEvent(true); - assertFalse(isSuspended()); - - // Back to DEFAULT APN - disconnectEvent(); - assertTrue(mDc.isInactive()); - doReturn(mApn1).when(mApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); - doReturn(true).when(mSST).isConcurrentVoiceAndDataAllowed(); - connectEvent(true); - - // Before getting any service state event, the connection should not be suspended. - assertFalse(isSuspended()); - - // Return true if combined reg state is not in service - serviceStateChangedEvent(ServiceState.STATE_OUT_OF_SERVICE, - ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN); - assertTrue(isSuspended()); - - // Return false if in service and concurrent voice and data is allowed - serviceStateChangedEvent(ServiceState.STATE_IN_SERVICE, - ServiceState.RIL_RADIO_TECHNOLOGY_LTE); - assertFalse(isSuspended()); - - // Return false if in service and concurrent voice/data not allowed but call state is idle - doReturn(false).when(mSST).isConcurrentVoiceAndDataAllowed(); - doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); - mDc.sendMessage(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED); - waitForMs(100); - assertFalse(isSuspended()); - - // Return true if in service, concurrent voice/data not allowed, and call state not idle - doReturn(PhoneConstants.State.RINGING).when(mCT).getState(); - mDc.sendMessage(DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED); - waitForMs(100); - assertTrue(isSuspended()); - } - - @Test - public void testDataCreatedWhenOutOfService() throws Exception { - serviceStateChangedEvent(ServiceState.STATE_OUT_OF_SERVICE, - ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN); - ArgumentCaptor ncCaptor = - ArgumentCaptor.forClass(NetworkCapabilities.class); - doReturn(mock(Network.class)).when(mConnectivityManager).registerNetworkAgent( - any(), any(), any(), ncCaptor.capture(), any(), any(), anyInt()); - - doReturn(mApn1).when(mApnContext).getApnSetting(); - doReturn(ApnSetting.TYPE_DEFAULT).when(mApnContext).getApnTypeBitmask(); - doReturn(true).when(mSST).isConcurrentVoiceAndDataAllowed(); - connectEvent(true); - waitForMs(100); - - NetworkCapabilities nc = ncCaptor.getValue(); - // The network must be created with NOT_SUSPENDED capability. - assertTrue(nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)); - - // But it's final state must be suspended. - assertTrue(isSuspended()); - } - - @Test - public void testDataServiceTempUnavailable() throws Exception { - setFailedSetupDataResponse(DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE); - replaceInstance(ConnectionParams.class, "mRequestType", mCp, - DcTracker.REQUEST_TYPE_NORMAL); - // Verify that no data was setup - connectEvent(false); - assertTrue(mDc.isInactive()); - - // Verify that data service did not suggest any retry (i.e. Frameworks uses configured - // retry timer). - verify(mDataThrottler).setRetryTime(eq(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL), - eq(RetryManager.NO_SUGGESTED_RETRY_DELAY), eq(DcTracker.REQUEST_TYPE_NORMAL)); - } - - @Test - public void testDataHandoverFailed() throws Exception { - doReturn(mDefaultDc).when(mDcTracker).getDataConnectionByApnType(anyString()); - - doAnswer(invocation -> { - final Consumer consumer = (Consumer) invocation.getArguments()[0]; - consumer.accept(DataServiceCallback.RESULT_SUCCESS); - return null; - }).when(mDefaultDc).startHandover(any(Consumer.class)); - - replaceInstance(ConnectionParams.class, "mRequestType", mCp, - DcTracker.REQUEST_TYPE_HANDOVER); - assertTrue(mDc.isInactive()); - connectEvent(false); - - // Make sure the data connection is still in inactive state - assertTrue(mDc.isInactive()); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java deleted file mode 100644 index ffe4542b75..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataEnabledSettingsTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; - -import android.os.HandlerThread; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import java.util.Objects; - -public class DataEnabledSettingsTest extends TelephonyTest { - - private DataEnabledSettings mDataEnabledSettingsUT; - - private DataEnabledSettingsTestHandler mDataEnabledSettingsTestHandler; - - private String mRules = ""; - - private class DataEnabledSettingsTestHandler extends HandlerThread { - - private DataEnabledSettingsTestHandler(String name) { - super(name); - } - - @Override - public void onLooperPrepared() { - mDataEnabledSettingsUT = new DataEnabledSettings(mPhone); - setReady(true); - } - } - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - doReturn(false).when(mPhone).isUsingNewDataStack(); - doReturn(mRules).when(mSubscriptionController).getDataEnabledOverrideRules(anyInt()); - - doAnswer(invocation -> { - String rules = (String) invocation.getArguments()[1]; - boolean changed = !Objects.equals(mRules, rules); - mRules = rules; - return changed; - }).when(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), anyString()); - - mDataEnabledSettingsTestHandler = new DataEnabledSettingsTestHandler( - getClass().getSimpleName()); - mDataEnabledSettingsTestHandler.start(); - waitUntilReady(); - } - - @After - public void tearDown() throws Exception { - mDataEnabledSettingsTestHandler.quit(); - mDataEnabledSettingsTestHandler.join(); - mDataEnabledSettingsTestHandler = null; - mDataEnabledSettingsUT = null; - super.tearDown(); - } - - @Test - @SmallTest - public void testSetDataAllowedInVoiceCall() throws Exception { - mDataEnabledSettingsUT.setAllowDataDuringVoiceCall(true); - ArgumentCaptor stringCaptor = ArgumentCaptor.forClass(String.class); - verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), - stringCaptor.capture()); - assertEquals("*=nonDefault&inVoiceCall&DefaultDataOn&dsdsEnabled", stringCaptor.getValue()); - - clearInvocations(mSubscriptionController); - - mDataEnabledSettingsUT.setAllowDataDuringVoiceCall(false); - verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), - stringCaptor.capture()); - assertEquals("", stringCaptor.getValue()); - } - - @Test - @SmallTest - public void testSetAlwaysAllowMmsData() throws Exception { - mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, false); - assertTrue(mDataEnabledSettingsUT.setAlwaysAllowMmsData(true)); - ArgumentCaptor stringCaptor = ArgumentCaptor.forClass(String.class); - verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), - stringCaptor.capture()); - assertEquals("mms=unconditionally", stringCaptor.getValue()); - assertTrue(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS)); - - clearInvocations(mSubscriptionController); - - assertTrue(mDataEnabledSettingsUT.setAlwaysAllowMmsData(false)); - verify(mSubscriptionController).setDataEnabledOverrideRules(anyInt(), - stringCaptor.capture()); - assertEquals("", stringCaptor.getValue()); - assertFalse(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS)); - - mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_USER, true); - assertTrue(mDataEnabledSettingsUT.isDataEnabled(ApnSetting.TYPE_MMS)); - } - - @Test - @SmallTest - public void testSetThermalDataEnabled() throws Exception { - mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_THERMAL, - false); - assertFalse(mDataEnabledSettingsUT.isDataEnabledForReason( - TelephonyManager.DATA_ENABLED_REASON_THERMAL)); - assertFalse(mDataEnabledSettingsUT.isDataEnabled()); - - mDataEnabledSettingsUT.setDataEnabled(TelephonyManager.DATA_ENABLED_REASON_THERMAL, - true); - assertTrue(mDataEnabledSettingsUT.isDataEnabledForReason( - TelephonyManager.DATA_ENABLED_REASON_THERMAL)); - assertTrue(mDataEnabledSettingsUT.isDataEnabled()); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java deleted file mode 100644 index d03bc8ca5c..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataThrottlerTest.java +++ /dev/null @@ -1,222 +0,0 @@ -/** - * Copyright (C) 2020 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.dataconnection; - -import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_HANDOVER; -import static com.android.internal.telephony.dataconnection.DcTracker.REQUEST_TYPE_NORMAL; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.telephony.AccessNetworkConstants; -import android.telephony.data.ApnSetting; -import android.telephony.data.ThrottleStatus; -import android.test.suitebuilder.annotation.SmallTest; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; - -/** - * Data throttler tests - */ -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class DataThrottlerTest extends TelephonyTest { - - private static final boolean DBG = true; - private DataThrottler mDataThrottler; - - // Mocked classes - private DataThrottler.Callback mMockChangedCallback1; - private DataThrottler.Callback mMockChangedCallback2; - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - mMockChangedCallback1 = mock(DataThrottler.Callback.class); - mMockChangedCallback2 = mock(DataThrottler.Callback.class); - mDataThrottler = new DataThrottler(mPhone, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - mDataThrottler.registerForThrottleStatusChanges(mMockChangedCallback1); - doReturn(false).when(mPhone).isUsingNewDataStack(); - } - - @After - public void tearDown() throws Exception { - mDataThrottler = null; - super.tearDown(); - } - - /** - * Test the behavior of a retry manager with no waiting APNs set. - */ - @Test - @SmallTest - public void testSetRetryTime() throws Exception { - final ArgumentCaptor> statusCaptor = - ArgumentCaptor.forClass((Class) List.class); - - List> expectedStatuses = new ArrayList<>(); - processAllMessages(); - expectedStatuses.add(List.of()); - - mDataThrottler.setRetryTime(ApnSetting.TYPE_DEFAULT, 1234567890L, - REQUEST_TYPE_NORMAL); - processAllMessages(); - assertEquals(1234567890L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, - mDataThrottler.getRetryTime(ApnSetting.TYPE_MMS)); - - processAllMessages(); - expectedStatuses.add(List.of( - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setApnType(ApnSetting.TYPE_DEFAULT) - .setThrottleExpiryTimeMillis(1234567890L) - .setRetryType(ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) - .build()) - ); - - - mDataThrottler.setRetryTime(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_DUN, 13579L, - REQUEST_TYPE_HANDOVER); - processAllMessages(); - assertEquals(13579L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); - assertEquals(13579L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DUN)); - - processAllMessages(); - expectedStatuses.add(List.of( - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setApnType(ApnSetting.TYPE_DUN) - .setThrottleExpiryTimeMillis(13579L) - .setRetryType(ThrottleStatus.RETRY_TYPE_HANDOVER) - .build(), - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setApnType(ApnSetting.TYPE_DEFAULT) - .setThrottleExpiryTimeMillis(13579L) - .setRetryType(ThrottleStatus.RETRY_TYPE_HANDOVER) - .build()) - ); - - - mDataThrottler.setRetryTime(ApnSetting.TYPE_MMS, -10, - REQUEST_TYPE_NORMAL); - processAllMessages(); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, - mDataThrottler.getRetryTime(ApnSetting.TYPE_MMS)); - processAllMessages(); - expectedStatuses.add(List.of( - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setNoThrottle() - .setApnType(ApnSetting.TYPE_MMS) - .setRetryType(ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) - .build() - )); - - mDataThrottler.setRetryTime(ApnSetting.TYPE_FOTA | ApnSetting.TYPE_EMERGENCY, - RetryManager.NO_RETRY, REQUEST_TYPE_HANDOVER); - - processAllMessages(); - expectedStatuses.add(List.of( - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setApnType(ApnSetting.TYPE_EMERGENCY) - .setThrottleExpiryTimeMillis(RetryManager.NO_RETRY) - .setRetryType(ThrottleStatus.RETRY_TYPE_NONE) - .build(), - new ThrottleStatus.Builder() - .setSlotIndex(0) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setApnType(ApnSetting.TYPE_FOTA) - .setThrottleExpiryTimeMillis(RetryManager.NO_RETRY) - .setRetryType(ThrottleStatus.RETRY_TYPE_NONE) - .build() - )); - - assertEquals(RetryManager.NO_RETRY, mDataThrottler.getRetryTime(ApnSetting.TYPE_FOTA)); - assertEquals(RetryManager.NO_RETRY, mDataThrottler.getRetryTime(ApnSetting.TYPE_EMERGENCY)); - - - // Loop through statuses and test everything - verify(mMockChangedCallback1, times(expectedStatuses.size())) - .onThrottleStatusChanged(statusCaptor.capture()); - - // Check actual statuses - List> actualStatuses = - (List>) statusCaptor.getAllValues(); - assertEquals(expectedStatuses.size(), actualStatuses.size()); - - if (DBG) { - logd("expectedStatuses.size() = " + expectedStatuses.size()); - logd("actualStatuses.size() = " + actualStatuses.size()); - } - - Comparator comparator = (o1, o2) -> - Integer.compare(o1.getApnType(), o2.getApnType()); - - for (int i = 0; i < expectedStatuses.size(); i++) { - List atsExpected = new ArrayList<>(expectedStatuses.get(i)); - List atsActual = new ArrayList<>(actualStatuses.get(i)); - - atsExpected.sort(comparator); - atsActual.sort(comparator); - assertEquals("Lists at index " + i + " don't match", - atsExpected, atsActual); - } - - this.mDataThrottler.registerForThrottleStatusChanges(mMockChangedCallback2); - } - - /** - * Test the behavior of a retry manager with no waiting APNs set. - */ - @Test - @SmallTest - public void testUnthrottle() throws Exception { - mDataThrottler.setRetryTime(ApnSetting.TYPE_DEFAULT, 1234567890L, - REQUEST_TYPE_NORMAL); - processAllMessages(); - assertEquals(1234567890L, mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); - - mDataThrottler.reset(); - processAllMessages(); - assertEquals(RetryManager.NO_SUGGESTED_RETRY_DELAY, - mDataThrottler.getRetryTime(ApnSetting.TYPE_DEFAULT)); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java deleted file mode 100644 index bddfdb4fa5..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.net.InetAddresses; -import android.net.LinkAddress; -import android.net.LinkProperties; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.telephony.AccessNetworkConstants; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.test.suitebuilder.annotation.SmallTest; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.dataconnection.DataConnection.UpdateLinkPropertyResult; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class DcControllerTest extends TelephonyTest { - - private static final int DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT = 1; - private static final int DATA_CONNECTION_ACTIVE_PH_LINK_ACTIVE = 2; - - private static final int EVENT_DATA_STATE_CHANGED = 0x00040007; - private static final int EVENT_PHYSICAL_LINK_STATUS_CHANGED = 1; - - // Mocked classes - private List mApnContexts; - private DataConnection mDc; - private DataServiceManager mDataServiceManager; - private Handler mTestHandler; - - UpdateLinkPropertyResult mResult; - - private DcController mDcc; - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - mApnContexts = mock(List.class); - mDc = mock(DataConnection.class); - mDataServiceManager = mock(DataServiceManager.class); - mTestHandler = mock(Handler.class); - - doReturn("fake.action_detached").when(mPhone).getActionDetached(); - doReturn(1).when(mApnContexts).size(); - doReturn(mApnContexts).when(mDc).getApnContexts(); - doReturn(false).when(mPhone).isUsingNewDataStack(); - - LinkProperties lp = new LinkProperties(); - mResult = new UpdateLinkPropertyResult(lp); - doReturn(mResult).when(mDc).updateLinkProperty(any(DataCallResponse.class)); - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .when(mDataServiceManager).getTransportType(); - - mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, Looper.myLooper(), - ""); - processAllMessages(); - } - - @After - public void tearDown() throws Exception { - mDcc.removeCallbacksAndMessages(null); - mDcc = null; - mResult = null; - super.tearDown(); - } - - @Test - @SmallTest - public void testDataDormant() throws Exception { - ArrayList l = new ArrayList<>(); - DataCallResponse dcResponse = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - l.add(dcResponse); - - mDc.mCid = 1; - mDcc.addActiveDcByCid(mDc); - - mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, - new AsyncResult(null, l, null))); - processAllMessages(); - - verify(mDcTracker, times(1)).sendStopNetStatPoll(eq(DctConstants.Activity.DORMANT)); - } - - @Test - @SmallTest - public void testPhysicalLinkStatusChanged_defaultApnTypeAndDormant_registrantNotifyResult() - throws Exception { - ArrayList l = new ArrayList<>(); - DataCallResponse dcResponse = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - l.add(dcResponse); - mDc.mCid = 1; - mDcc.addActiveDcByCid(mDc); - ApnContext apnContext = new ApnContext(mPhone, ApnSetting.TYPE_DEFAULT, TAG, mDcTracker, 1); - List apnContextList = new ArrayList<>(); - apnContextList.add(apnContext); - doReturn(apnContextList).when(mDc).getApnContexts(); - doReturn(true).when(mDcTracker).getLteEndcUsingUserDataForIdleDetection(); - mDcc.registerForPhysicalLinkStatusChanged(mTestHandler, EVENT_PHYSICAL_LINK_STATUS_CHANGED); - - mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, - new AsyncResult(null, l, null))); - processAllMessages(); - - ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); - verify(mTestHandler, times(1)).sendMessageDelayed(messageCaptor.capture(), anyLong()); - Message message = messageCaptor.getValue(); - assertEquals(EVENT_PHYSICAL_LINK_STATUS_CHANGED, message.what); - AsyncResult ar = (AsyncResult) message.obj; - assertEquals(DataCallResponse.LINK_STATUS_DORMANT, (int) ar.result); - } - - @Test - @SmallTest - public void testPhysicalLinkStatusChanged_imsApnTypeAndDormant_NoNotifyResult() - throws Exception { - testPhysicalLinkStatusChanged_defaultApnTypeAndDormant_registrantNotifyResult(); - - ArrayList l = new ArrayList<>(); - DataCallResponse dcResponse = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_ACTIVE) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - l.add(dcResponse); - mDc.mCid = 1; - mDcc.addActiveDcByCid(mDc); - ApnContext apnContext = new ApnContext(mPhone, ApnSetting.TYPE_IMS, TAG, mDcTracker, 1); - List apnContextList = new ArrayList<>(); - apnContextList.add(apnContext); - doReturn(apnContextList).when(mDc).getApnContexts(); - doReturn(true).when(mDcTracker).getLteEndcUsingUserDataForIdleDetection(); - - mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, - new AsyncResult(null, l, null))); - processAllMessages(); - - ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); - verify(mTestHandler, times(1)).sendMessageDelayed(messageCaptor.capture(), anyLong()); - } - - @Test - @SmallTest - public void testPhysicalLinkStatusChanged_defaultApnTypeAndStateChanged_registrantNotifyResult() - throws Exception { - testPhysicalLinkStatusChanged_imsApnTypeAndDormant_NoNotifyResult(); - - ArrayList l = new ArrayList<>(); - DataCallResponse dcResponse = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1) - .setId(1) - .setLinkStatus(DATA_CONNECTION_ACTIVE_PH_LINK_ACTIVE) - .setProtocolType(ApnSetting.PROTOCOL_IP) - .setInterfaceName(FAKE_IFNAME) - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS))) - .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) - .setPcscfAddresses( - Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) - .setMtuV4(1440) - .setMtuV6(1440) - .build(); - l.add(dcResponse); - mDc.mCid = 1; - mDcc.addActiveDcByCid(mDc); - ApnContext apnContext = new ApnContext(mPhone, ApnSetting.TYPE_DEFAULT, TAG, mDcTracker, 1); - List apnContextList = new ArrayList<>(); - apnContextList.add(apnContext); - doReturn(apnContextList).when(mDc).getApnContexts(); - doReturn(true).when(mDcTracker).getLteEndcUsingUserDataForIdleDetection(); - - mDcc.sendMessage(mDcc.obtainMessage(EVENT_DATA_STATE_CHANGED, - new AsyncResult(null, l, null))); - processAllMessages(); - - ArgumentCaptor messageCaptor = ArgumentCaptor.forClass(Message.class); - verify(mTestHandler, times(2)).sendMessageDelayed(messageCaptor.capture(), anyLong()); - Message message = messageCaptor.getValue(); - assertEquals(EVENT_PHYSICAL_LINK_STATUS_CHANGED, message.what); - AsyncResult ar = (AsyncResult) message.obj; - assertEquals(DataCallResponse.LINK_STATUS_ACTIVE, (int) ar.result); - } -} \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java deleted file mode 100644 index 78438e41d9..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcNetworkAgentTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2022 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.dataconnection; - -import static junit.framework.Assert.assertEquals; - -import static org.mockito.Mockito.doReturn; - -import android.net.ConnectivityManager; -import android.net.LinkProperties; -import android.net.NetworkAgent; -import android.net.NetworkAgentConfig; -import android.net.NetworkInfo; -import android.net.NetworkProvider; -import android.os.Looper; -import android.telephony.AccessNetworkConstants; -import android.telephony.TelephonyManager; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; - -import java.lang.reflect.Field; - -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class DcNetworkAgentTest extends TelephonyTest { - - private DcNetworkAgent mDcNetworkAgent; - private DataConnection mDc; - private DcController mDcc; - private DcFailBringUp mDcFailBringUp; - - private DataServiceManager mDataServiceManager; - private DcTesterFailBringUpAll mDcTesterFailBringUpAll; - private NetworkProvider mNetworkProvider; - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - logd("+Setup!"); - if (Looper.myLooper() == null) { - Looper.prepare(); - } - - doReturn(false).when(mPhone).isUsingNewDataStack(); - mDataServiceManager = Mockito.mock(DataServiceManager.class); - mDcTesterFailBringUpAll = Mockito.mock(DcTesterFailBringUpAll.class); - mNetworkProvider = Mockito.mock(NetworkProvider.class); - - final NetworkAgentConfig.Builder configBuilder = new NetworkAgentConfig.Builder(); - configBuilder.setLegacyType(ConnectivityManager.TYPE_MOBILE); - configBuilder.setLegacyTypeName("MOBILE"); - configBuilder.setLegacySubType(TelephonyManager.NETWORK_TYPE_LTE); - configBuilder.setLegacySubTypeName("LTE"); - configBuilder.setLegacyExtraInfo("apn"); - - doReturn("fake.action_detached").when(mPhone).getActionDetached(); - mDcFailBringUp = new DcFailBringUp(); - mDcFailBringUp.saveParameters(0, 0, -2); - doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp(); - - mDcc = DcController.makeDcc(mPhone, mDcTracker, mDataServiceManager, Looper.myLooper(), - ""); - mDc = DataConnection.makeDataConnection(mPhone, 0, mDcTracker, mDataServiceManager, - mDcTesterFailBringUpAll, mDcc); - - LinkProperties linkProperties = new LinkProperties(); - linkProperties.setInterfaceName("fake_iface"); - Field field = DataConnection.class.getDeclaredField("mLinkProperties"); - field.setAccessible(true); - field.set(mDc, linkProperties); - - mDcNetworkAgent = new DcNetworkAgent(mDc, mPhone, 45, configBuilder.build(), - mNetworkProvider, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - logd("-Setup!"); - } - - @After - public void tearDown() throws Exception { - super.tearDown(); - } - - private void verifyDisconnected() throws Exception { - Field field = NetworkAgent.class.getDeclaredField("mNetworkInfo"); - field.setAccessible(true); - NetworkInfo networkInfo = (NetworkInfo) field.get(mDcNetworkAgent); - assertEquals(NetworkInfo.DetailedState.DISCONNECTED, networkInfo.getDetailedState()); - } - - @Test - public void testUnwantedTimeout() throws Exception { - mDcNetworkAgent.markConnected(); - mDcNetworkAgent.onNetworkUnwanted(); - processAllFutureMessages(); - verifyDisconnected(); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java deleted file mode 100644 index b08a6803d0..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcRequestTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2020 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.dataconnection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.net.TelephonyNetworkSpecifier; -import android.telephony.data.ApnSetting; - -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class DcRequestTest extends TelephonyTest { - NetworkRequest mNetworkRequest; - - // Mocked classes - ApnConfigTypeRepository mApnConfigTypeRepo; - - @Before - public void setUp() throws Exception { - mApnConfigTypeRepo = mock(ApnConfigTypeRepository.class); - super.setUp(getClass().getSimpleName()); - doReturn(false).when(mPhone).isUsingNewDataStack(); - } - - @After - public void tearDown() throws Exception { - mNetworkRequest = null; - super.tearDown(); - } - - @Test - public void whenNetworkRequestInternetThenPriorityZero() { - mNetworkRequest = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(); - - when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_DEFAULT)) - .thenReturn(new ApnConfigType(ApnSetting.TYPE_DEFAULT, 0)); - DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); - - assertEquals(0, dcRequest.priority); - } - - @Test - public void whenNetworkRequestMcxThenApnConfigTypeMcxPriorityReturned() { - mNetworkRequest = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - //Testing out multiple transport types here - .addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH) - .addCapability(NetworkCapabilities.NET_CAPABILITY_MCX) - .build(); - - when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_MCX)) - .thenReturn(new ApnConfigType(ApnSetting.TYPE_MCX, 21)); - DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); - assertEquals(21, dcRequest.priority); - } - - @Test - public void whenNetworkRequestNotCellularThenDcRequestIsNull() { - mNetworkRequest = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .addCapability(NetworkCapabilities.NET_CAPABILITY_MCX) - .build(); - when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_NONE)).thenReturn(null); - DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); - assertNull(dcRequest); - } - - @Test - public void whenNetworkRequestHasNoTransportThenPriorityStays() { - //This seems like an invalid case that should be handled differently. - mNetworkRequest = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_MCX) - .build(); - - when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_MCX)) - .thenReturn(new ApnConfigType(ApnSetting.TYPE_MCX, 11)); - DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); - assertEquals(11, dcRequest.priority); - } - - @Test - public void whenNetworkRequestNotCellularWithTelephonySpecifierThenDcRequestIsNull() { - TelephonyNetworkSpecifier telephonyNetworkSpecifier = - new TelephonyNetworkSpecifier.Builder().setSubscriptionId(5).build(); - - //This seems like an invalid case that should be handled differently. - mNetworkRequest = new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH) - .setNetworkSpecifier(telephonyNetworkSpecifier) - .build(); - - when(mApnConfigTypeRepo.getByType(ApnSetting.TYPE_NONE)).thenReturn(null); - - DcRequest dcRequest = DcRequest.create(mNetworkRequest, mApnConfigTypeRepo); - - assertNull(dcRequest); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java deleted file mode 100644 index 549c587549..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +++ /dev/null @@ -1,2983 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.dataconnection; - -import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; -import static com.android.internal.telephony.dataconnection.ApnSettingTest.createApnSetting; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.timeout; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ServiceInfo; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.hardware.radio.V1_0.SetupDataCallResult; -import android.net.LinkProperties; -import android.net.NetworkAgent; -import android.net.NetworkCapabilities; -import android.net.NetworkPolicyManager; -import android.net.NetworkRequest; -import android.net.Uri; -import android.os.AsyncResult; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Message; -import android.os.PersistableBundle; -import android.os.SystemClock; -import android.provider.Settings; -import android.provider.Telephony; -import android.telephony.AccessNetworkConstants; -import android.telephony.AccessNetworkConstants.AccessNetworkType; -import android.telephony.Annotation; -import android.telephony.CarrierConfigManager; -import android.telephony.DataFailCause; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.PreciseDataConnectionState; -import android.telephony.ServiceState; -import android.telephony.SignalStrength; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.SubscriptionPlan; -import android.telephony.TelephonyDisplayInfo; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.telephony.data.DataCallResponse; -import android.telephony.data.DataProfile; -import android.telephony.data.DataService; -import android.telephony.data.TrafficDescriptor; -import android.test.mock.MockContentProvider; -import android.test.mock.MockContentResolver; -import android.test.suitebuilder.annotation.MediumTest; -import android.test.suitebuilder.annotation.SmallTest; -import android.text.TextUtils; -import android.util.Pair; -import android.util.SparseArray; - -import androidx.test.filters.FlakyTest; - -import com.android.internal.R; -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.ISub; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.data.CellularDataService; -import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType; - -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.mockito.stubbing.Answer; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.time.Period; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -public class DcTrackerTest extends TelephonyTest { - public static final String FAKE_APN1 = "FAKE APN 1"; - public static final String FAKE_APN2 = "FAKE APN 2"; - public static final String FAKE_APN3 = "FAKE APN 3"; - public static final String FAKE_APN4 = "FAKE APN 4"; - public static final String FAKE_APN5 = "FAKE APN 5"; - public static final String FAKE_APN6 = "FAKE APN 6"; - public static final String FAKE_APN7 = "FAKE APN 7"; - public static final String FAKE_APN8 = "FAKE APN 8"; - public static final String FAKE_APN9 = "FAKE APN 9"; - public static final String FAKE_IFNAME = "FAKE IFNAME"; - public static final String FAKE_PCSCF_ADDRESS = "22.33.44.55"; - public static final String FAKE_GATEWAY = "11.22.33.44"; - public static final String FAKE_DNS = "55.66.77.88"; - public static final String FAKE_ADDRESS = "99.88.77.66"; - private static final int NETWORK_TYPE_NR_BITMASK = - 1 << (TelephonyManager.NETWORK_TYPE_NR - 1); - private static final int NETWORK_TYPE_LTE_BITMASK = - 1 << (TelephonyManager.NETWORK_TYPE_LTE - 1); - private static final int NETWORK_TYPE_EHRPD_BITMASK = - 1 << (TelephonyManager.NETWORK_TYPE_EHRPD - 1); - private static final Uri PREFERAPN_URI = Uri.parse( - Telephony.Carriers.CONTENT_URI + "/preferapn"); - private static final int DATA_ENABLED_CHANGED = 0; - private static final String FAKE_PLMN = "44010"; - private static final long TEST_TIMEOUT = 1000; - - // Mocked classes - ISub mIsub; - IBinder mBinder; - SubscriptionInfo mSubscriptionInfo; - ApnContext mApnContext; - DataConnection mDataConnection; - Handler mHandler; - NetworkPolicyManager mNetworkPolicyManager; - - private DcTracker mDct; - private DcTrackerTestHandler mDcTrackerTestHandler; - - private AlarmManager mAlarmManager; - - private PersistableBundle mBundle; - - private SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener; - - private final ApnSettingContentProvider mApnSettingContentProvider = - new ApnSettingContentProvider(); - - private Message mMessage; - - private CellularDataService mCellularDataService; - - private void addDataService() { - mCellularDataService = new CellularDataService(); - ServiceInfo serviceInfo = new ServiceInfo(); - serviceInfo.packageName = "com.android.phone"; - serviceInfo.permission = "android.permission.BIND_TELEPHONY_DATA_SERVICE"; - IntentFilter filter = new IntentFilter(); - mContextFixture.addService( - DataService.SERVICE_INTERFACE, - null, - "com.android.phone", - mCellularDataService.mBinder, - serviceInfo, - filter); - } - - private class DcTrackerTestHandler extends HandlerThread { - - private DcTrackerTestHandler(String name) { - super(name); - } - - @Override - public void onLooperPrepared() { - mDct = new DcTracker(mPhone, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - setReady(true); - } - } - - private class ApnSettingContentProvider extends MockContentProvider { - public final String[] FAKE_APN_COLUMNS = new String[]{ - Telephony.Carriers._ID, Telephony.Carriers.NUMERIC, - Telephony.Carriers.NAME, Telephony.Carriers.APN, - Telephony.Carriers.PROXY, Telephony.Carriers.PORT, - Telephony.Carriers.MMSC, Telephony.Carriers.MMSPROXY, - Telephony.Carriers.MMSPORT, Telephony.Carriers.USER, - Telephony.Carriers.PASSWORD, Telephony.Carriers.AUTH_TYPE, - Telephony.Carriers.TYPE, - Telephony.Carriers.PROTOCOL, - Telephony.Carriers.ROAMING_PROTOCOL, - Telephony.Carriers.CARRIER_ENABLED, Telephony.Carriers.BEARER, - Telephony.Carriers.BEARER_BITMASK, - Telephony.Carriers.PROFILE_ID, - Telephony.Carriers.MODEM_PERSIST, - Telephony.Carriers.MAX_CONNECTIONS, - Telephony.Carriers.WAIT_TIME_RETRY, - Telephony.Carriers.TIME_LIMIT_FOR_MAX_CONNECTIONS, - Telephony.Carriers.MTU, - Telephony.Carriers.MTU_V4, - Telephony.Carriers.MTU_V6, - Telephony.Carriers.MVNO_TYPE, - Telephony.Carriers.MVNO_MATCH_DATA, - Telephony.Carriers.NETWORK_TYPE_BITMASK, - Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK, - Telephony.Carriers.APN_SET_ID, - Telephony.Carriers.CARRIER_ID, - Telephony.Carriers.SKIP_464XLAT, - Telephony.Carriers.ALWAYS_ON - }; - - private int mPreferredApnSet = 0; - - private Object[] mPreferredApn = null; - - private String mFakeApn1Types = "default,supl"; - - private String mFakeApn5Types = "dun"; - - private int mFakeApn1Bitmask = NETWORK_TYPE_LTE_BITMASK; - - private int mRowIdOffset = 0; - - public void setFakeApn1Types(String apnTypes) { - mFakeApn1Types = apnTypes; - } - - public void setFakeApn5Types(String apnTypes) { - mFakeApn5Types = apnTypes; - } - - public void setFakeApn1NetworkTypeBitmask(int bitmask) { - mFakeApn1Bitmask = bitmask; - } - - public void setRowIdOffset(int rowIdOffset) { - mRowIdOffset = rowIdOffset; - } - - public void setFakePreferredApn(Object[] fakeApn) { - mPreferredApn = fakeApn; - } - - public Object[] getFakeApn1() { - return new Object[]{ - 2163 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "sp-mode", // name - FAKE_APN1, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - mFakeApn1Types, // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - mFakeApn1Bitmask, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn2() { - return new Object[]{ - 2164 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "mopera U", // name - FAKE_APN2, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "default,supl", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer, - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn3() { - return new Object[]{ - 2165 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "b-mobile for Nexus", // name - FAKE_APN3, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "ims", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - 0, // bearer - 0, // bearer_bitmask - 2, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - 0, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn4() { - return new Object[]{ - 2166 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "sp-mode ehrpd", // name - FAKE_APN4, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "default,supl", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_EHRPD_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn5() { - return new Object[]{ - 2167 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "b-mobile for Nexus", // name - FAKE_APN5, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - mFakeApn5Types, // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - 0, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - 0, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn6() { - return new Object[]{ - 2168 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "sp-mode", // name - FAKE_APN6, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "mms,xcap", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn7() { - return new Object[]{ - 2169 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "sp-mode", // name - FAKE_APN7, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "default", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - 1, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn8() { - return new Object[]{ - 2170 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "IMS", // name - FAKE_APN8, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "ims", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer - 0, // bearer_bitmask - 2, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - -1, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - public Object[] getFakeApn9() { - return new Object[]{ - 2171 + mRowIdOffset, // id - FAKE_PLMN, // numeric - "sp-mode nr", // name - FAKE_APN9, // apn - "", // proxy - "", // port - "", // mmsc - "", // mmsproxy - "", // mmsport - "", // user - "", // password - -1, // authtype - "default,enterprise", // types - "IP", // protocol - "IP", // roaming_protocol - 1, // carrier_enabled - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer - 0, // bearer_bitmask - 0, // profile_id - 1, // modem_cognitive - 0, // max_conns - 0, // wait_time - 0, // max_conns_time - 0, // mtu - 0, // mtu_v4 - 0, // mtu_v6 - "", // mvno_type - "", // mnvo_match_data - NETWORK_TYPE_NR_BITMASK, // network_type_bitmask - 0, // lingering_network_type_bitmask - 0, // apn_set_id - -1, // carrier_id - -1, // skip_464xlat - 0 // always_on - }; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - logd("ApnSettingContentProvider: query"); - logd(" uri = " + uri); - logd(" projection = " + Arrays.toString(projection)); - logd(" selection = " + selection); - logd(" selectionArgs = " + Arrays.toString(selectionArgs)); - logd(" sortOrder = " + sortOrder); - - if (uri.compareTo(Telephony.Carriers.CONTENT_URI) == 0 - || uri.toString().startsWith(Uri.withAppendedPath( - Telephony.Carriers.CONTENT_URI, "filtered").toString()) - || uri.toString().startsWith(Uri.withAppendedPath( - Telephony.Carriers.SIM_APN_URI, "filtered").toString())) { - if (projection == null) { - - logd("Query '" + FAKE_PLMN + "' APN settings"); - MatrixCursor mc = new MatrixCursor(FAKE_APN_COLUMNS); - mc.addRow(getFakeApn1()); - mc.addRow(getFakeApn2()); - mc.addRow(getFakeApn3()); - mc.addRow(getFakeApn4()); - mc.addRow(getFakeApn5()); - mc.addRow(getFakeApn6()); - mc.addRow(getFakeApn7()); - mc.addRow(getFakeApn8()); - mc.addRow(getFakeApn9()); - - return mc; - } - } else if (isPathPrefixMatch(uri, - Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapnset"))) { - MatrixCursor mc = new MatrixCursor( - new String[]{Telephony.Carriers.APN_SET_ID}); - // apn_set_id is the only field used with this URL - mc.addRow(new Object[]{ mPreferredApnSet }); - mc.addRow(new Object[]{ 0 }); - return mc; - } else if (isPathPrefixMatch(uri, - Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapn_no_update"))) { - if (mPreferredApn == null) { - return null; - } else { - MatrixCursor mc = new MatrixCursor(FAKE_APN_COLUMNS); - mc.addRow(mPreferredApn); - return mc; - } - } - - return null; - } - - @Override - public int update(Uri url, ContentValues values, String where, String[] whereArgs) { - mPreferredApnSet = values.getAsInteger(Telephony.Carriers.APN_SET_ID); - return 1; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - } - - @Before - public void setUp() throws Exception { - logd("DcTrackerTest +Setup!"); - super.setUp(getClass().getSimpleName()); - mIsub = Mockito.mock(ISub.class); - mBinder = Mockito.mock(IBinder.class); - mSubscriptionInfo = Mockito.mock(SubscriptionInfo.class); - mApnContext = Mockito.mock(ApnContext.class); - mDataConnection = Mockito.mock(DataConnection.class); - mHandler = Mockito.mock(Handler.class); - mNetworkPolicyManager = Mockito.mock(NetworkPolicyManager.class); - - doReturn("fake.action_detached").when(mPhone).getActionDetached(); - doReturn("fake.action_attached").when(mPhone).getActionAttached(); - doReturn(false).when(mPhone).isUsingNewDataStack(); - doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState) - .getRilDataRadioTechnology(); - - mContextFixture.putStringArrayResource(com.android.internal.R.array - .config_mobile_tcp_buffers, new String[]{ - "umts:131072,262144,1452032,4096,16384,399360", - "hspa:131072,262144,2441216,4096,16384,399360", - "hsupa:131072,262144,2441216,4096,16384,399360", - "hsdpa:131072,262144,2441216,4096,16384,399360", - "hspap:131072,262144,2441216,4096,16384,399360", - "edge:16384,32768,131072,4096,16384,65536", - "gprs:4096,8192,24576,4096,8192,24576", - "1xrtt:16384,32768,131070,4096,16384,102400", - "evdo:131072,262144,1048576,4096,16384,524288", - "lte:524288,1048576,8388608,262144,524288,4194304"}); - - mContextFixture.putResource(R.string.config_wwan_data_service_package, - "com.android.phone"); - - ((MockContentResolver) mContext.getContentResolver()).addProvider( - Telephony.Carriers.CONTENT_URI.getAuthority(), mApnSettingContentProvider); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0); - - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) - .getPreferredTransport(anyInt()); - doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); - doReturn(true).when(mSST).getDesiredPowerState(); - doReturn(true).when(mSST).getPowerStateFromCarrier(); - doAnswer( - (Answer) invocation -> { - mOnSubscriptionsChangedListener = - (SubscriptionManager.OnSubscriptionsChangedListener) - invocation.getArguments()[0]; - return null; - } - ).when(mSubscriptionManager).addOnSubscriptionsChangedListener(any()); - doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt()); - doReturn(mNetworkPolicyManager).when(mContext) - .getSystemService(Context.NETWORK_POLICY_SERVICE); - doReturn(1).when(mIsub).getDefaultDataSubId(); - doReturn(mIsub).when(mBinder).queryLocalInterface(anyString()); - mServiceManagerMockedServices.put("isub", mBinder); - - mContextFixture.putStringArrayResource( - com.android.internal.R.array.config_cell_retries_per_error_code, - new String[]{"36,2"}); - - mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); - mBundle = mContextFixture.getCarrierConfigBundle(); - - mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); - - mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult()); - addDataService(); - - mDcTrackerTestHandler = new DcTrackerTestHandler(getClass().getSimpleName()); - mDcTrackerTestHandler.start(); - waitUntilReady(); - - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - - waitForMs(600); - logd("DcTrackerTest -Setup!"); - } - - @After - public void tearDown() throws Exception { - logd("DcTrackerTest -tearDown"); - mDct.removeCallbacksAndMessages(null); - mDct.stopHandlerThread(); - mDct = null; - mDcTrackerTestHandler.quit(); - mDcTrackerTestHandler.join(); - mDcTrackerTestHandler = null; - mCellularDataService.onDestroy(); - mCellularDataService = null; - mAlarmManager = null; - mBundle = null; - mCellularDataService = null; - waitForMs(100); - super.tearDown(); - } - - // Create a successful data response - private static SetupDataCallResult createSetupDataCallResult() { - SetupDataCallResult result = new SetupDataCallResult(); - result.status = 0; - result.suggestedRetryTime = -1; - result.cid = 1; - result.active = 2; - result.type = "IP"; - result.ifname = FAKE_IFNAME; - result.addresses = FAKE_ADDRESS; - result.dnses = FAKE_DNS; - result.gateways = FAKE_GATEWAY; - result.pcscf = FAKE_PCSCF_ADDRESS; - result.mtu = 1440; - return result; - } - - private void verifyDataProfile(DataProfile dp, String apn, int profileId, - int supportedApnTypesBitmap, int type, int bearerBitmask) { - assertEquals(profileId, dp.getProfileId()); - assertEquals(apn, dp.getApn()); - assertEquals(ApnSetting.PROTOCOL_IP, dp.getProtocolType()); - assertEquals(0, dp.getAuthType()); - assertEquals("", dp.getUserName()); - assertEquals("", dp.getPassword()); - assertEquals(type, dp.getType()); - assertEquals(0, dp.getWaitTime()); - assertTrue(dp.isEnabled()); - assertEquals(supportedApnTypesBitmap, dp.getSupportedApnTypesBitmask()); - assertEquals(ApnSetting.PROTOCOL_IP, dp.getRoamingProtocolType()); - assertEquals(bearerBitmask, dp.getBearerBitmask()); - assertEquals(0, dp.getMtu()); - assertTrue(dp.isPersistent()); - assertFalse(dp.isPreferred()); - } - - private void verifyDataConnected(final String apnSetting) { - verify(mAlarmManager, times(1)).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), - any(PendingIntent.class)); - - assertEquals(apnSetting, mDct.getActiveApnString(ApnSetting.TYPE_DEFAULT_STRING)); - assertArrayEquals(new String[]{ApnSetting.TYPE_DEFAULT_STRING}, mDct.getActiveApnTypes()); - - assertTrue(mDct.isAnyDataConnected()); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - - LinkProperties linkProperties = mDct.getLinkProperties(ApnSetting.TYPE_DEFAULT_STRING); - assertEquals(FAKE_IFNAME, linkProperties.getInterfaceName()); - assertEquals(1, linkProperties.getAddresses().size()); - assertEquals(FAKE_ADDRESS, linkProperties.getAddresses().get(0).getHostAddress()); - assertEquals(1, linkProperties.getDnsServers().size()); - assertEquals(FAKE_DNS, linkProperties.getDnsServers().get(0).getHostAddress()); - assertEquals(FAKE_GATEWAY, linkProperties.getRoutes().get(0).getGateway().getHostAddress()); - } - - private boolean isHandoverPending(int apnType) { - try { - Method method = DcTracker.class.getDeclaredMethod("isHandoverPending", - int.class); - method.setAccessible(true); - return (boolean) method.invoke(mDct, apnType); - } catch (Exception e) { - fail(e.toString()); - return false; - } - } - - private void addHandoverCompleteMsg(Message onCompleteMsg, - @Annotation.ApnType int apnType) { - try { - Method method = DcTracker.class.getDeclaredMethod("addHandoverCompleteMsg", - Message.class, int.class); - method.setAccessible(true); - method.invoke(mDct, onCompleteMsg, apnType); - } catch (Exception e) { - fail(e.toString()); - } - } - - private void sendInitializationEvents() { - sendCarrierConfigChanged(""); - - sendSimStateUpdated(""); - - sendEventDataConnectionAttached(""); - - waitForMs(200); - } - - private void sendCarrierConfigChanged(String messagePrefix) { - logd(messagePrefix + "Sending EVENT_CARRIER_CONFIG_CHANGED"); - mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - private void sendSimStateUpdated(String messagePrefix) { - logd(messagePrefix + "Sending EVENT_SIM_STATE_UPDATED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_SIM_STATE_UPDATED, - TelephonyManager.SIM_STATE_LOADED, 0)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - private void sendEventDataConnectionAttached(String messagePrefix) { - logd(messagePrefix + "Sending EVENT_DATA_CONNECTION_ATTACHED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - // Test the unmetered APN setup when data is disabled. - @Test - @SmallTest - public void testTrySetupDataUnmeteredDefaultNotSelected() throws Exception { - initApns(ApnSetting.TYPE_XCAP_STRING, new String[]{ApnSetting.TYPE_XCAP_STRING}); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mIsub).getDefaultDataSubId(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - sendInitializationEvents(); - - mDct.enableApn(ApnSetting.TYPE_XCAP, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the normal data call setup scenario. - @Test - @MediumTest - public void testDataSetup() throws Exception { - DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); - boolean allowed = mDct.isDataAllowed(dataConnectionReasons); - assertFalse(dataConnectionReasons.toString(), allowed); - - logd("Sending EVENT_ENABLE_APN"); - // APN id 0 is APN_TYPE_DEFAULT - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - sendInitializationEvents(); - - dataConnectionReasons = new DataConnectionReasons(); - allowed = mDct.isDataAllowed(dataConnectionReasons); - assertTrue(dataConnectionReasons.toString(), allowed); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - verifyDataConnected(FAKE_APN1); - } - - // Test the scenario where the first data call setup is failed, and then retry the setup later. - @Test - @MediumTest - public void testDataRetry() throws Exception { - AsyncResult ar = new AsyncResult(null, - new Pair<>(true, DataEnabledSettings.REASON_USER_DATA_ENABLED), null); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // LOST_CONNECTION(0x10004) is a non-permanent failure, so we'll retry data setup later. - SetupDataCallResult result = createSetupDataCallResult(); - result.status = 0x10004; - - // Simulate RIL fails the data call setup - mSimulatedCommands.setDataCallResult(true, result); - - DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); - boolean allowed = mDct.isDataAllowed(dataConnectionReasons); - assertFalse(dataConnectionReasons.toString(), allowed); - - logd("Sending EVENT_ENABLE_APN"); - // APN id 0 is APN_TYPE_DEFAULT - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - sendInitializationEvents(); - - dataConnectionReasons = new DataConnectionReasons(); - allowed = mDct.isDataAllowed(dataConnectionReasons); - assertTrue(dataConnectionReasons.toString(), allowed); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - // This time we'll let RIL command succeed. - mSimulatedCommands.setDataCallResult(true, createSetupDataCallResult()); - - //Send event for reconnecting data - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RECONNECT, - mPhone.getPhoneId(), DcTracker.REQUEST_TYPE_NORMAL, mApnContext)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN2, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - // Verify connected with APN2 setting. - verifyDataConnected(FAKE_APN2); - } - - @Test - @MediumTest - @Ignore - @FlakyTest - public void testUserDisableData() { - //step 1: setup two DataCalls one for Metered: default, another one for Non-metered: IMS - //set Default and MMS to be metered in the CarrierConfigManager - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending DATA_DISABLED_CMD"); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - AsyncResult ar = new AsyncResult(null, - new Pair<>(false, DataEnabledSettings.REASON_USER_DATA_ENABLED), null); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // expected tear down all metered DataConnections - verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - assertTrue(mDct.isAnyDataConnected()); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING)); - } - - @Test - @MediumTest - public void testTrySetupDataMmsAllowedDataDisabled() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_MMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - - List dataProfiles = dpCaptor.getAllValues(); - assertEquals(2, dataProfiles.size()); - - //Verify FAKE_APN1 - Optional fakeApn1 = dataProfiles.stream() - .filter(dp -> dp.getApn().equals(FAKE_APN1)) - .findFirst(); - assertTrue(fakeApn1.isPresent()); - verifyDataProfile(fakeApn1.get(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - //Verify FAKE_APN6 - Optional fakeApn6 = dataProfiles.stream() - .filter(dp -> dp.getApn().equals(FAKE_APN6)) - .findFirst(); - assertTrue(fakeApn6.isPresent()); - verifyDataProfile(fakeApn6.get(), FAKE_APN6, 0, ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP, - 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending DATA_DISABLED_CMD for default data"); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // expected tear down all metered DataConnections - verify(mSimulatedCommandsVerifier, times(2)).deactivateDataCall( - anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING)); - - clearInvocations(mSimulatedCommandsVerifier); - doReturn(true).when(mDataEnabledSettings).isDataEnabled(ApnSetting.TYPE_MMS); - mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); - } - - @Test - @MediumTest - public void testTrySetupDataMmsAlwaysAllowedDataDisabled() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mApnSettingContentProvider.setFakeApn1Types("mms,xcap,default"); - mDct.enableApn(ApnSetting.TYPE_MMS, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - - // Verify MMS was set up and is connected - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, - ApnSetting.TYPE_MMS | ApnSetting.TYPE_XCAP | ApnSetting.TYPE_DEFAULT, - 1, NETWORK_TYPE_LTE_BITMASK); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); - - // Verify DC has all capabilities specified in fakeApn1Types - Map apnContexts = mDct.getApnContexts().stream().collect( - Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); - assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)); - assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_INTERNET)); - - // Disable mobile data - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - doReturn(false).when(mDataEnabledSettings).isMmsAlwaysAllowed(); - mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Expected tear down all metered DataConnections - waitForMs(200); - verify(mSimulatedCommandsVerifier).deactivateDataCall( - anyInt(), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_MMS_STRING)); - - // Allow MMS unconditionally - clearInvocations(mSimulatedCommandsVerifier); - doReturn(true).when(mDataEnabledSettings).isMmsAlwaysAllowed(); - doReturn(true).when(mDataEnabledSettings).isDataEnabled(ApnSetting.TYPE_MMS); - mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED).sendToTarget(); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Verify MMS was set up and is connected - waitForMs(200); - verify(mSimulatedCommandsVerifier).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_MMS_STRING)); - - // Ensure MMS data connection has the MMS capability only. - apnContexts = mDct.getApnContexts().stream().collect( - Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertTrue(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)); - assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability(NetworkCapabilities.NET_CAPABILITY_XCAP)); - assertFalse(apnContexts.get(ApnSetting.TYPE_MMS).getDataConnection() - .getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_INTERNET)); - } - - @Test - @MediumTest - public void testUserDisableRoaming() { - //step 1: setup two DataCalls one for Metered: default, another one for Non-metered: IMS - //step 2: set roaming disabled, data is enabled - //step 3: under roaming service - //step 4: only tear down metered data connections. - - //set Default and MMS to be metered in the CarrierConfigManager - boolean roamingEnabled = mDct.getDataRoamingEnabled(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForHandlerAction(mDct, 1000); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForHandlerAction(mDct, 1000); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - //user is in roaming - doReturn(true).when(mServiceState).getDataRoaming(); - logd("Sending DISABLE_ROAMING_CMD"); - mDct.setDataRoamingEnabledByUser(false); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_ROAMING_ON)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // expected tear down all metered DataConnections - verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - assertTrue(mDct.isAnyDataConnected()); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING)); - - // reset roaming settings / data enabled settings at end of this test - mDct.setDataRoamingEnabledByUser(roamingEnabled); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - @Test - @MediumTest - public void testDataCallOnUserDisableRoaming() { - //step 1: mock under roaming service and user disabled roaming from settings. - //step 2: user toggled data settings on - //step 3: only non-metered data call is established - - boolean roamingEnabled = mDct.getDataRoamingEnabled(); - doReturn(true).when(mServiceState).getDataRoaming(); - - //set Default and MMS to be metered in the CarrierConfigManager - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - logd("Sending DISABLE_ROAMING_CMD"); - mDct.setDataRoamingEnabledByUser(false); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN3, 2, 64, 0, 0); - - assertTrue(mDct.isAnyDataConnected()); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_IMS_STRING)); - - // reset roaming settings / data enabled settings at end of this test - mDct.setDataRoamingEnabledByUser(roamingEnabled); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - // Test the default data switch scenario. - @FlakyTest /* flakes 1.57% of the time */ - @Test - @MediumTest - public void testDDSResetAutoAttach() throws Exception { - mContextFixture.putBooleanResource( - com.android.internal.R.bool.config_auto_attach_data_on_creation, true); - testDataSetup(); - assertTrue(mDct.shouldAutoAttach()); - mDct.sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - // The auto attach flag should be reset after update - assertFalse(mDct.shouldAutoAttach()); - } - - // Test for API carrierActionSetMeteredApnsEnabled. - @FlakyTest - @Ignore - @Test - @MediumTest - public void testCarrierActionSetMeteredApnsEnabled() { - //step 1: setup two DataCalls one for Internet and IMS - //step 2: set data is enabled - //step 3: cold sim is detected - //step 4: all data connection is torn down - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, NETWORK_TYPE_LTE_BITMASK); - assertTrue(mDct.isAnyDataConnected()); - - AsyncResult ar = new AsyncResult(null, - new Pair<>(false, DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER), null); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_ENABLED_CHANGED, ar)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // Validate all metered data connections have been torn down - verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - assertTrue(mDct.isAnyDataConnected()); - assertEquals(DctConstants.State.IDLE, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - } - - private void initApns(String targetApn, String[] canHandleTypes) { - doReturn(targetApn).when(mApnContext).getApnType(); - doReturn(ApnSetting.getApnTypesBitmaskFromString(mApnContext.getApnType())) - .when(mApnContext).getApnTypeBitmask(); - doReturn(true).when(mApnContext).isConnectable(); - ApnSetting apnSetting = createApnSetting(ApnSetting.getApnTypesBitmaskFromString( - TextUtils.join(",", canHandleTypes))); - doReturn(apnSetting).when(mApnContext).getNextApnSetting(); - doReturn(apnSetting).when(mApnContext).getApnSetting(); - doReturn(mDataConnection).when(mApnContext).getDataConnection(); - doReturn(true).when(mApnContext).isEnabled(); - doReturn(true).when(mApnContext).isDependencyMet(); - doReturn(true).when(mApnContext).isReady(); - doReturn(false).when(mApnContext).hasRestrictedRequests(eq(true)); - } - - // Test the emergency APN setup. - @Test - @SmallTest - public void testTrySetupDataEmergencyApn() { - initApns(ApnSetting.TYPE_EMERGENCY_STRING, - new String[]{ApnSetting.TYPE_EMERGENCY_STRING}); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - waitForMs(200); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), - anyBoolean(), any(Message.class)); - } - - // Test the XCAP APN setup. - @Test - @SmallTest - public void testTrySetupDataXcapApn() { - initApns(ApnSetting.TYPE_XCAP_STRING, new String[]{ApnSetting.TYPE_XCAP_STRING}); - mDct.enableApn(ApnSetting.TYPE_XCAP, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), - anyBoolean(), any(Message.class)); - } - - // Test the ENTERPRISE APN setup. - @Test - public void testTrySetupDataEnterpriseApn() { - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName()); - assertEquals(null, tdCaptor.getValue().getOsAppId()); - - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - SetupDataCallResult result = createSetupDataCallResult(); - result.cid = 10; - mSimulatedCommands.setDataCallResult(true, result); - mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForMs(200); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - } - - // Test the ENTERPRISE APN setup when default data is not set up yet. - @Test - public void testTrySetupDataEnterpriseApnNoDefaultData() { - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - - // Check APN contexts with no DEFAULT set up - Map apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertEquals(DctConstants.State.IDLE, apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); - assertEquals(DctConstants.State.FAILED, - apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); - - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - waitForMs(200); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName()); - assertEquals(null, tdCaptor.getValue().getOsAppId()); - - // Check APN contexts after DEFAULT is set up (and ENTERPRISE failure) - apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertEquals(DctConstants.State.CONNECTED, - apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); - assertEquals(DctConstants.State.FAILED, - apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); - - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - SetupDataCallResult result = createSetupDataCallResult(); - result.cid = 10; - mSimulatedCommands.setDataCallResult(true, result); - mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - waitForMs(200); - - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - - // Check APN contexts after DEFAULT is set up (and ENTERPRISE reenabled) - apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertEquals(DctConstants.State.CONNECTED, - apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); - assertEquals(DctConstants.State.CONNECTED, - apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); - } - - // Test the ENTERPRISE APN setup when the same CID is returned. - @Test - public void testTrySetupDataEnterpriseApnDuplicateCid() { - mApnSettingContentProvider.setFakeApn1NetworkTypeBitmask( - NETWORK_TYPE_LTE_BITMASK | NETWORK_TYPE_NR_BITMASK); - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - // mSimulatedCommandsVerifier will return the same CID in SetupDataCallResult - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - waitForMs(200); - - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - List tds = tdCaptor.getAllValues(); - // [0] is default and [1] is enterprise, since default should be set up first - assertEquals(FAKE_APN1, tds.get(0).getDataNetworkName()); - assertEquals(null, tds.get(0).getOsAppId()); - assertEquals(null, tds.get(1).getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), tds.get(1).getOsAppId())); - - // Check APN contexts after DEFAULT and ENTERPRISE set up - Map apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertEquals(DctConstants.State.CONNECTED, - apnContexts.get(ApnSetting.TYPE_DEFAULT).getState()); - assertEquals(DctConstants.State.FAILED, - apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState()); - } - - @Test - @SmallTest - public void testGetDataConnectionState() { - initApns(ApnSetting.TYPE_SUPL_STRING, - new String[]{ApnSetting.TYPE_SUPL_STRING, ApnSetting.TYPE_DEFAULT_STRING}); - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_SUPL, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - // Assert that both APN_TYPE_SUPL & APN_TYPE_DEFAULT are connected even we only setup data - // for APN_TYPE_SUPL - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_SUPL_STRING)); - assertEquals(DctConstants.State.CONNECTED, mDct.getState(ApnSetting.TYPE_DEFAULT_STRING)); - } - - // Test the unmetered APN setup when data is disabled. - @Test - @SmallTest - public void testTrySetupDataUnmeteredDataDisabled() { - initApns(ApnSetting.TYPE_SUPL_STRING, new String[]{ApnSetting.TYPE_SUPL_STRING}); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_FOTA_STRING}); - - mDct.enableApn(ApnSetting.TYPE_SUPL, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the unmetered default APN setup when data is disabled. Default APN should always honor - // the users's setting. - @Test - @SmallTest - public void testTrySetupDataUnmeteredDefaultDataDisabled() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_MMS_STRING}); - - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, never()).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - - // Test the metered APN setup when data is disabled. - @Test - @SmallTest - public void testTrySetupMeteredDataDisabled() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the restricted data request when data is disabled. - @Test - @SmallTest - public void testTrySetupRestrictedDataDisabled() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - sendInitializationEvents(); - - NetworkRequest nr = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .build(); - mDct.requestNetwork(nr, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the restricted data request when roaming is disabled. - @Test - @SmallTest - public void testTrySetupRestrictedRoamingDisabled() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - mDct.setDataRoamingEnabledByUser(false); - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - //user is in roaming - doReturn(true).when(mServiceState).getDataRoaming(); - - sendInitializationEvents(); - - NetworkRequest nr = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .build(); - mDct.requestNetwork(nr, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the default data when data is not connectable. - @Test - @SmallTest - public void testTrySetupNotConnectable() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - doReturn(false).when(mApnContext).isConnectable(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the default data on IWLAN. - @Test - @SmallTest - public void testTrySetupDefaultOnIWLAN() { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test the default data when the phone is in ECBM. - @Test - @SmallTest - public void testTrySetupDefaultInECBM() { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - doReturn(true).when(mPhone).isInEcm(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - - sendInitializationEvents(); - - verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(anyInt(), any(DataProfile.class), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - // Test update waiting apn list when on data rat change - @FlakyTest /* flakes 0.86% of the time */ - @Ignore - @Test - @SmallTest - public void testUpdateWaitingApnListOnDataRatChange() { - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier).setupDataCall( - eq(AccessNetworkType.CDMA2000), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK); - assertTrue(mDct.isAnyDataConnected()); - - //data rat change from ehrpd to lte - logd("Sending EVENT_DATA_RAT_CHANGED"); - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // Verify the disconnected data call due to rat change and retry manger schedule another - // data call setup - verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - verify(mAlarmManager, times(1)).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), - anyLong(), any(PendingIntent.class)); - - //Send event for reconnecting data - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RECONNECT, - mPhone.getPhoneId(), DcTracker.RELEASE_TYPE_NORMAL, mApnContext)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - assertTrue(mDct.isAnyDataConnected()); - } - - /** - * Test that fetchDunApns() returns list that prioritize the preferred APN when the preferred - * APN including DUN type. - */ - @Test - public void testFetchDunApnWithPreferredApn() { - // Set support APN types of FAKE_APN1 and FAKE_APN5 - mApnSettingContentProvider.setFakeApn1Types("default,dun"); - mApnSettingContentProvider.setFakeApn5Types("default,dun"); - - // Set prefer apn set id. - ContentResolver cr = mContext.getContentResolver(); - ContentValues values = new ContentValues(); - values.put(Telephony.Carriers.APN_SET_ID, 0); - cr.update(PREFERAPN_URI, values, null, null); - // Set FAKE_APN5 as the preferred APN. - mApnSettingContentProvider.setFakePreferredApn(mApnSettingContentProvider.getFakeApn5()); - - sendInitializationEvents(); - - // Return the APN list that set the preferred APN at the top. - ArrayList dunApns = mDct.fetchDunApns(); - assertEquals(2, dunApns.size()); - assertEquals(FAKE_APN5, dunApns.get(0).getApnName()); - assertEquals(FAKE_APN1, dunApns.get(1).getApnName()); - } - - // This tests simulates the race case where the sim status change event is triggered, the - // default data connection is attached, and then the carrier config gets changed which bumps - // the database id which we want to ignore when cleaning up connections and matching against - // the dun APN. Tests b/158908392. - @Test - @SmallTest - public void testCheckForCompatibleDataConnectionWithDunWhenIdsChange() { - //Set dun as a support apn type of FAKE_APN1 - mApnSettingContentProvider.setFakeApn1Types("default,supl,dun"); - - // Enable the default apn - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - //Load the sim and attach the data connection without firing the carrier changed event - final String logMsgPrefix = "testCheckForCompatibleDataConnectionWithDunWhenIdsChange: "; - sendSimStateUpdated(logMsgPrefix); - sendEventDataConnectionAttached(logMsgPrefix); - waitForMs(200); - - // Confirm that FAKE_APN1 comes up as a dun candidate - ApnSetting dunApn = mDct.fetchDunApns().get(0); - assertEquals(dunApn.getApnName(), FAKE_APN1); - Map apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - - //Double check that the default apn content is connected while the dun apn context is not - assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getState(), - DctConstants.State.CONNECTED); - assertNotEquals(apnContexts.get(ApnSetting.TYPE_DUN).getState(), - DctConstants.State.CONNECTED); - - - //Change the row ids the same way as what happens when we have old apn values in the - //carrier table - mApnSettingContentProvider.setRowIdOffset(100); - sendCarrierConfigChanged(logMsgPrefix); - waitForMs(200); - - mDct.enableApn(ApnSetting.TYPE_DUN, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - Map apnContextsAfterRowIdsChanged = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - - //Make sure that the data connection used earlier wasn't cleaned up and still in use. - assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), - apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DEFAULT).getDataConnection()); - - //Check that the DUN is using the same active data connection - assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), - apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DUN).getDataConnection()); - } - - @Test - @SmallTest - public void testCheckForCompatibleDataConnectionWithEnterprise() { - // Allow both DEFAULT and ENTERPRISE to use APN 1 - mApnSettingContentProvider.setFakeApn1NetworkTypeBitmask( - NETWORK_TYPE_LTE_BITMASK | NETWORK_TYPE_NR_BITMASK); - - // Enable the DEFAULT APN - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - sendInitializationEvents(); - - ArgumentCaptor tdCaptor = - ArgumentCaptor.forClass(TrafficDescriptor.class); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(FAKE_APN1, tdCaptor.getValue().getDataNetworkName()); - assertEquals(null, tdCaptor.getValue().getOsAppId()); - - // Check APN contexts after DEFAULT is set up - Map apnContexts = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getState(), - DctConstants.State.CONNECTED); - assertNotEquals(apnContexts.get(ApnSetting.TYPE_ENTERPRISE).getState(), - DctConstants.State.CONNECTED); - - // Enable the ENTERPRISE APN - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - SetupDataCallResult result = createSetupDataCallResult(); - result.cid = 10; - mSimulatedCommands.setDataCallResult(true, result); - mDct.enableApn(ApnSetting.TYPE_ENTERPRISE, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForMs(200); - - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false), - eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(), - anyBoolean(), any(Message.class)); - assertEquals(null, tdCaptor.getValue().getDataNetworkName()); - assertTrue(Arrays.equals(DataConnection.getEnterpriseOsAppId(), - tdCaptor.getValue().getOsAppId())); - - // Check APN contexts after ENTERPRISE is set up - Map apnContextsAfterRowIdsChanged = mDct.getApnContexts() - .stream().collect(Collectors.toMap(ApnContext::getApnTypeBitmask, x -> x)); - - // Make sure that the data connection used earlier wasn't cleaned up and still in use. - assertEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), - apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_DEFAULT).getDataConnection()); - - // Check that ENTERPRISE isn't using the same data connection as DEFAULT - assertNotEquals(apnContexts.get(ApnSetting.TYPE_DEFAULT).getDataConnection(), - apnContextsAfterRowIdsChanged.get(ApnSetting.TYPE_ENTERPRISE).getDataConnection()); - } - - // Test for Data setup with APN Set ID - @Test - @SmallTest - public void testDataSetupWithApnSetId() throws Exception { - // Set the prefer apn set id to "1" - ContentResolver cr = mContext.getContentResolver(); - ContentValues values = new ContentValues(); - values.put(Telephony.Carriers.APN_SET_ID, 1); - cr.update(PREFERAPN_URI, values, null, null); - - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - - List dataProfiles = dpCaptor.getAllValues(); - assertEquals(2, dataProfiles.size()); - - // Verify to use FAKE APN7 which is Default APN with apnSetId=1(Same as the pereferred - // APN's set id). - Optional fakeApn7 = dataProfiles.stream() - .filter(dp -> dp.getApn().equals(FAKE_APN7)).findFirst(); - assertTrue(fakeApn7.isPresent()); - verifyDataProfile(fakeApn7.get(), FAKE_APN7, 0, 17, 1, NETWORK_TYPE_LTE_BITMASK); - - // Verify to use FAKE APN8 which is IMS APN with apnSetId=-1 - // (Telephony.Carriers.MATCH_ALL_APN_SET_ID). - Optional fakeApn8 = dataProfiles.stream() - .filter(dp -> dp.getApn().equals(FAKE_APN8)).findFirst(); - assertTrue(fakeApn8.isPresent()); - verifyDataProfile(fakeApn8.get(), FAKE_APN8, 2, 64, 1, NETWORK_TYPE_LTE_BITMASK); - } - - // Test oos - @Test - @SmallTest - public void testDataRatChangeOOS() { - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING}); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier).setupDataCall( - eq(AccessNetworkType.CDMA2000), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 21, 2, NETWORK_TYPE_EHRPD_BITMASK); - assertTrue(mDct.isAnyDataConnected()); - - // Data rat change from ehrpd to unknown due to OOS - logd("Sending EVENT_DATA_RAT_CHANGED"); - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UNKNOWN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // Verify data connection is on - verify(mSimulatedCommandsVerifier, times(0)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - - // Data rat resume from unknown to ehrpd - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EHRPD) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Verify the same data connection - assertEquals(FAKE_APN4, mDct.getActiveApnString(ApnSetting.TYPE_DEFAULT_STRING)); - assertTrue(mDct.isAnyDataConnected()); - } - - // Test provisioning - /*@Test - @SmallTest - public void testDataEnableInProvisioning() throws Exception { - ContentResolver resolver = mContext.getContentResolver(); - - assertEquals(1, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA)); - assertTrue(mDct.isDataEnabled()); - assertTrue(mDct.isUserDataEnabled()); - - mDct.setUserDataEnabled(false); - waitForMs(200); - - assertEquals(0, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA)); - assertFalse(mDct.isDataEnabled()); - assertFalse(mDct.isUserDataEnabled()); - - // Changing provisioned to 0. - Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null)); - waitForMs(200); - - assertTrue(mDct.isDataEnabled()); - assertTrue(mDct.isUserDataEnabled()); - - // Enable user data during provisioning. It should write to - // Settings.Global.MOBILE_DATA and keep data enabled when provisioned. - mDct.setUserDataEnabled(true); - Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 1); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null)); - waitForMs(200); - - assertTrue(mDct.isDataEnabled()); - assertTrue(mDct.isUserDataEnabled()); - assertEquals(1, Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA)); - }*/ - - /* - @Test - @SmallTest - public void testNotifyDataEnabledChanged() throws Exception { - doAnswer(invocation -> { - mMessage = (Message) invocation.getArguments()[0]; - return true; - }).when(mHandler).sendMessageDelayed(any(), anyLong()); - - // Test registration. - mDct.registerForDataEnabledChanged(mHandler, DATA_ENABLED_CHANGED, null); - verifyDataEnabledChangedMessage(true, DataEnabledSettings.REASON_REGISTERED); - - // Disable user data. Should receive data enabled change to false. - mDct.setUserDataEnabled(false); - waitForMs(200); - verifyDataEnabledChangedMessage(false, DataEnabledSettings.REASON_USER_DATA_ENABLED); - - // Changing provisioned to 0. Shouldn't receive any message, as data enabled remains false. - ContentResolver resolver = mContext.getContentResolver(); - Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONED, 0); - Settings.Global.putInt(resolver, Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, - 0); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE, null)); - waitForMs(200); - assertFalse(mDct.isDataEnabled()); - verify(mHandler, never()).sendMessageDelayed(any(), anyLong()); - - // Changing provisioningDataEnabled to 1. It should trigger data enabled change to true. - Settings.Global.putInt(resolver, - Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, 1); - mDct.sendMessage(mDct.obtainMessage( - DctConstants.EVENT_DEVICE_PROVISIONING_DATA_SETTING_CHANGE, null)); - waitForMs(200); - verifyDataEnabledChangedMessage( - true, DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED); - }*/ - - @Test - @SmallTest - public void testNetworkStatusChangedRecoveryOFF() { - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.VALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.INVALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - waitForMs(200); - - // Verify that its no-op when the new data stall detection feature is disabled - verify(mSimulatedCommandsVerifier, times(0)).getDataCallList(any(Message.class)); - } - - @FlakyTest - @Test - @SmallTest - public void testNetworkStatusChangedRecoveryON() { - ContentResolver resolver = mContext.getContentResolver(); - Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); - Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 0); - doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.VALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.INVALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mSimulatedCommandsVerifier, times(1)).getDataCallList(any(Message.class)); - } - - @FlakyTest - @Test - @SmallTest - public void testRecoveryStepPDPReset() { - ContentResolver resolver = mContext.getContentResolver(); - Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); - Settings.Global.putLong(resolver, - Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); - Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 1); - doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, timeout(TEST_TIMEOUT).times(2)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED false"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.INVALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - waitForMs(200); - - // expected tear down all DataConnections - verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - } - - - @Test - @SmallTest - public void testRecoveryStepReRegister() { - ContentResolver resolver = mContext.getContentResolver(); - Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); - Settings.Global.putLong(resolver, - Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); - Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 2); - doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); - doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED false"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.INVALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // expected to get preferred network type - verify(mSST, times(1)).reRegisterNetwork(eq(null)); - } - - @Test - @SmallTest - public void testRecoveryStepRestartRadio() { - ContentResolver resolver = mContext.getContentResolver(); - Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1); - Settings.Global.putLong(resolver, - Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100); - Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 3); - doReturn(new SignalStrength()).when(mPhone).getSignalStrength(); - doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, - new String[]{ApnSetting.TYPE_DEFAULT_STRING, ApnSetting.TYPE_MMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - logd("Sending EVENT_NETWORK_STATUS_CHANGED false"); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED, - NetworkAgent.INVALID_NETWORK, 1, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // expected to get preferred network type - verify(mSST, times(1)).powerOffRadioSafely(); - } - - private void verifyDataEnabledChangedMessage(boolean enabled, int reason) { - verify(mHandler, times(1)).sendMessageDelayed(any(), anyLong()); - Pair result = (Pair) ((AsyncResult) mMessage.obj).result; - assertEquals(DATA_ENABLED_CHANGED, mMessage.what); - assertEquals(enabled, result.first); - assertEquals(reason, (int) result.second); - clearInvocations(mHandler); - } - - private void setUpSubscriptionPlans(boolean isNrUnmetered) throws Exception { - List plans = new ArrayList<>(); - if (isNrUnmetered) { - plans.add(SubscriptionPlan.Builder - .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), - Period.ofMonths(1)) - .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED, - SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED) - .setNetworkTypes(new int[] {TelephonyManager.NETWORK_TYPE_NR}) - .build()); - } - plans.add(SubscriptionPlan.Builder - .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), - Period.ofMonths(1)) - .setDataLimit(1_000_000_000, SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED) - .setDataUsage(500_000_000, System.currentTimeMillis()) - .build()); - replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, plans); - doReturn(plans.toArray(new SubscriptionPlan[0])).when(mNetworkPolicyManager) - .getSubscriptionPlans(anyInt(), any()); - } - - private void resetSubscriptionPlans() throws Exception { - replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, null); - } - - private void setUpSubscriptionOverride(int[] networkTypes, boolean isUnmetered) - throws Exception { - List networkTypesList = null; - if (networkTypes != null) { - networkTypesList = new ArrayList<>(); - for (int networkType : networkTypes) { - networkTypesList.add(networkType); - } - } - replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, networkTypesList); - replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, isUnmetered); - } - - private void resetSubscriptionOverride() throws Exception { - replaceInstance(DcTracker.class, "mUnmeteredNetworkTypes", mDct, null); - replaceInstance(DcTracker.class, "mUnmeteredOverride", mDct, false); - } - - private boolean isNetworkTypeUnmetered(int networkType) throws Exception { - Method method = DcTracker.class.getDeclaredMethod( - "isNetworkTypeUnmetered", int.class); - method.setAccessible(true); - return (boolean) method.invoke(mDct, networkType); - } - - private int setUpDataConnection() throws Exception { - Field dc = DcTracker.class.getDeclaredField("mDataConnections"); - dc.setAccessible(true); - Field uig = DcTracker.class.getDeclaredField("mUniqueIdGenerator"); - uig.setAccessible(true); - int id = ((AtomicInteger) uig.get(mDct)).getAndIncrement(); - ((HashMap) dc.get(mDct)).put(id, mDataConnection); - return id; - } - - private void resetDataConnection(int id) throws Exception { - Field dc = DcTracker.class.getDeclaredField("mDataConnections"); - dc.setAccessible(true); - ((HashMap) dc.get(mDct)).remove(id); - } - - private void setUpWatchdogTimer() { - // Watchdog active for 10s - mBundle.putLong(CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG, 10000); - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - private boolean getWatchdogStatus() throws Exception { - Field field = DcTracker.class.getDeclaredField(("mWatchdog")); - field.setAccessible(true); - return (boolean) field.get(mDct); - } - - private Map> getHandoverCompletionMessages() throws Exception { - Field field = DcTracker.class.getDeclaredField(("mHandoverCompletionMsgs")); - field.setAccessible(true); - return (Map>) field.get(mDct); - } - - private void setUpTempNotMetered() { - doReturn((int) TelephonyManager.NETWORK_TYPE_BITMASK_NR) - .when(mPhone).getRadioAccessFamily(); - doReturn(1).when(mPhone).getSubId(); - mBundle.putBoolean(CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, true); - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - @Test - public void testIsNetworkTypeUnmetered() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - - // only 5G unmetered - setUpSubscriptionOverride(new int[]{TelephonyManager.NETWORK_TYPE_NR}, true); - - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - // all network types metered - setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), false); - - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - // all network types unmetered - setUpSubscriptionOverride(TelephonyManager.getAllNetworkTypes(), true); - - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - resetSubscriptionOverride(); - } - - @Test - public void testIsNetworkTypeUnmeteredViaSubscriptionPlans() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - - // only 5G unmetered - setUpSubscriptionPlans(true); - - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - // all network types metered - setUpSubscriptionPlans(false); - - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertFalse(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - // all network types unmetered - List plans = new ArrayList<>(); - plans.add(SubscriptionPlan.Builder - .createRecurring(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"), - Period.ofMonths(1)) - .setDataLimit(SubscriptionPlan.BYTES_UNLIMITED, - SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED) - .build()); - replaceInstance(DcTracker.class, "mSubscriptionPlans", mDct, plans); - - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_NR)); - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_LTE)); - assertTrue(isNetworkTypeUnmetered(TelephonyManager.NETWORK_TYPE_UNKNOWN)); - - resetSubscriptionPlans(); - } - - @Test - public void testIsNrUnmeteredSubscriptionPlans() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - int id = setUpDataConnection(); - setUpSubscriptionPlans(false); - setUpWatchdogTimer(); - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - setUpTempNotMetered(); - clearInvocations(mDataConnection); - - // NetCapability should be metered when connected to 5G with no unmetered plan or frequency - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(false); - - // Set SubscriptionPlans unmetered - setUpSubscriptionPlans(true); - - // NetCapability should switch to unmetered with an unmetered plan - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(true); - - // Set MMWAVE frequency to unmetered - mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, true); - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - clearInvocations(mDataConnection); - - // NetCapability should switch to metered without fr=MMWAVE - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(false); - - // NetCapability should switch to unmetered with fr=MMWAVE - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(true); - - resetDataConnection(id); - resetSubscriptionPlans(); - } - - @Test - public void testIsNrUnmeteredCarrierConfigs() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - int id = setUpDataConnection(); - setUpSubscriptionPlans(false); - setUpWatchdogTimer(); - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - setUpTempNotMetered(); - clearInvocations(mDataConnection); - - // NetCapability should be metered when connected to 5G with no unmetered plan or frequency - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(false); - - // Set MMWAVE frequency to unmetered - mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_BOOL, true); - mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, true); - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - clearInvocations(mDataConnection); - - // NetCapability should switch to unmetered when fr=MMWAVE and MMWAVE unmetered - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(true); - - // NetCapability should switch to metered when fr=SUB6 and MMWAVE unmetered - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(false); - - // Set SUB6 frequency to unmetered - doReturn(2).when(mPhone).getSubId(); - mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false); - mBundle.putBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_SUB6_BOOL, true); - intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - clearInvocations(mDataConnection); - - // NetCapability should switch to unmetered when fr=SUB6 and SUB6 unmetered - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mDataConnection, times(1)).onMeterednessChanged(true); - - resetDataConnection(id); - resetSubscriptionPlans(); - } - - @Test - public void testReevaluateUnmeteredConnectionsOnNetworkChange() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - int id = setUpDataConnection(); - setUpSubscriptionPlans(true); - setUpWatchdogTimer(); - setUpTempNotMetered(); - clearInvocations(mDataConnection); - - // NetCapability should be unmetered when connected to 5G - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - verify(mDataConnection, times(1)).onMeterednessChanged(true); - - // NetCapability should be metered when disconnected from 5G - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - verify(mDataConnection, times(1)).onMeterednessChanged(false); - - resetDataConnection(id); - resetSubscriptionPlans(); - } - - @Test - public void testReevaluateUnmeteredConnectionsOnWatchdog() throws Exception { - initApns(ApnSetting.TYPE_DEFAULT_STRING, new String[]{ApnSetting.TYPE_ALL_STRING}); - int id = setUpDataConnection(); - setUpSubscriptionPlans(true); - setUpWatchdogTimer(); - - // Watchdog inactive when unmetered and not connected to 5G - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NR_TIMER_WATCHDOG)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - assertFalse(getWatchdogStatus()); - - // Watchdog active when unmetered and connected to 5G - doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA)) - .when(mDisplayInfoController).getTelephonyDisplayInfo(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - assertTrue(getWatchdogStatus()); - - // Watchdog inactive when metered - setUpSubscriptionPlans(false); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - assertFalse(getWatchdogStatus()); - - resetDataConnection(id); - resetSubscriptionPlans(); - } - - /** - * Test if this is a path prefix match against the given Uri. Verifies that - * scheme, authority, and atomic path segments match. - * - * Copied from frameworks/base/core/java/android/net/Uri.java - */ - private boolean isPathPrefixMatch(Uri uriA, Uri uriB) { - if (!Objects.equals(uriA.getScheme(), uriB.getScheme())) return false; - if (!Objects.equals(uriA.getAuthority(), uriB.getAuthority())) return false; - - List segA = uriA.getPathSegments(); - List segB = uriB.getPathSegments(); - - final int size = segB.size(); - if (segA.size() < size) return false; - - for (int i = 0; i < size; i++) { - if (!Objects.equals(segA.get(i), segB.get(i))) { - return false; - } - } - - return true; - } - - @Test - public void testNoApnContextsWhenDataIsDisabled() throws java.lang.InterruptedException { - //Check that apn contexts are loaded. - assertTrue(mDct.getApnContexts().size() > 0); - - //Do work normally done in teardown. - mDct.removeCallbacksAndMessages(null); - mDcTrackerTestHandler.quit(); - mDcTrackerTestHandler.join(); - - //Set isDataCapable to false for the new DcTracker being created in DcTrackerTestHandler. - doReturn(false).when(mTelephonyManager).isDataCapable(); - mDcTrackerTestHandler = new DcTrackerTestHandler(getClass().getSimpleName()); - setReady(false); - - mDcTrackerTestHandler.start(); - waitUntilReady(); - assertEquals(0, mDct.getApnContexts().size()); - - //No need to clean up handler because that work is done in teardown. - } - - @Test - public void testRatChanged() throws Exception { - DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); - boolean allowed = mDct.isDataAllowed(dataConnectionReasons); - assertFalse(dataConnectionReasons.toString(), allowed); - - logd("Sending EVENT_ENABLE_APN"); - // APN id 0 is APN_TYPE_DEFAULT - mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL, null); - - sendInitializationEvents(); - - dataConnectionReasons = new DataConnectionReasons(); - allowed = mDct.isDataAllowed(dataConnectionReasons); - assertTrue(dataConnectionReasons.toString(), allowed); - - ArgumentCaptor dpCaptor = ArgumentCaptor.forClass(DataProfile.class); - // Verify if RIL command was sent properly. - verify(mSimulatedCommandsVerifier, times(1)).setupDataCall( - eq(AccessNetworkType.EUTRAN), dpCaptor.capture(), - eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, NETWORK_TYPE_LTE_BITMASK); - - verifyDataConnected(FAKE_APN1); - - doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS).when(mServiceState) - .getRilDataRadioTechnology(); - - logd("Sending EVENT_DATA_RAT_CHANGED"); - mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder() - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( - anyInt(), anyInt()); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Data connection is running on a different thread. Have to wait. - waitForMs(200); - // expected tear down all metered DataConnections - verify(mSimulatedCommandsVerifier).deactivateDataCall( - eq(DataService.REQUEST_REASON_NORMAL), anyInt(), - any(Message.class)); - } - - @Test - public void testApnConfigRepositoryUpdatedOnCarrierConfigChange() { - assertPriority(ApnSetting.TYPE_CBS_STRING, 2); - assertPriority(ApnSetting.TYPE_MMS_STRING, 2); - - mBundle.putStringArray(CarrierConfigManager.KEY_APN_PRIORITY_STRING_ARRAY, - new String[] { - ApnSetting.TYPE_CBS_STRING + ":11", - ApnSetting.TYPE_MMS_STRING + ":19", - }); - - sendInitializationEvents(); - - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - mContext.sendBroadcast(intent); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - assertPriority(ApnSetting.TYPE_CBS_STRING, 11); - assertPriority(ApnSetting.TYPE_MMS_STRING, 19); - - //Ensure apns are in sorted order. - ApnContext lastApnContext = null; - for (ApnContext apnContext : mDct.getApnContexts()) { - if (lastApnContext != null) { - assertTrue(apnContext.getPriority() <= lastApnContext.getPriority()); - } - lastApnContext = apnContext; - } - } - - private void assertPriority(String type, int priority) { - assertEquals(priority, mDct.getApnContexts().stream() - .filter(x -> x.getApnType().equals(type)) - .findFirst().get().getPriority()); - } - - @Test - public void testProvisionBroadcastReceiver() { - Intent intent = new Intent("com.android.internal.telephony.PROVISION"); - intent.putExtra("provision.phone.id", mPhone.getPhoneId()); - try { - mContext.sendBroadcast(intent); - } catch (SecurityException e) { - fail(); - } - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - } - - @Test - public void testRetryHandoverWhenDisconnecting() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - setUpDataConnection(); - SparseArray apnContextsByType = Mockito.mock(SparseArray.class); - ConcurrentHashMap apnContexts = Mockito.mock(ConcurrentHashMap.class); - doReturn(mApnContext).when(apnContextsByType).get(eq(ApnSetting.TYPE_IMS)); - doReturn(mApnContext).when(apnContexts).get(eq(ApnSetting.TYPE_IMS_STRING)); - doReturn(false).when(mApnContext).isConnectable(); - doReturn(false).when(mDataEnabledSettings).isDataEnabled(anyInt()); - doReturn(DctConstants.State.DISCONNECTING).when(mApnContext).getState(); - replaceInstance(DcTracker.class, "mApnContextsByType", mDct, apnContextsByType); - replaceInstance(DcTracker.class, "mApnContexts", mDct, apnContexts); - - sendInitializationEvents(); - - logd("Sending EVENT_ENABLE_APN"); - // APN id 0 is APN_TYPE_DEFAULT - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER, - mDct.obtainMessage(12345)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - assertTrue(isHandoverPending(ApnSetting.TYPE_IMS)); - - // Verify no handover request was sent - verify(mDataConnection, never()).bringUp(any(ApnContext.class), anyInt(), anyInt(), - any(Message.class), anyInt(), anyInt(), anyInt(), anyBoolean()); - - doReturn(DctConstants.State.RETRYING).when(mApnContext).getState(); - // Data now is disconnected - doReturn(true).when(mApnContext).isConnectable(); - doReturn(true).when(mDataEnabledSettings).isDataEnabled(anyInt()); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, - new AsyncResult(Pair.create(mApnContext, 0), null, null))); - - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - verify(mDataConnection).bringUp(any(ApnContext.class), anyInt(), anyInt(), - any(Message.class), anyInt(), eq(DcTracker.REQUEST_TYPE_HANDOVER), anyInt(), - anyBoolean()); - } - - @Test - public void testDataUnthrottled() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_APN_UNTHROTTLED, - new AsyncResult(null, FAKE_APN3, null))); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - verify(mDataThrottler).setRetryTime( - eq(ApnSetting.TYPE_IMS), - eq(RetryManager.NO_SUGGESTED_RETRY_DELAY), - eq(DcTracker.REQUEST_TYPE_NORMAL)); - } - - @Test - public void testDataUnthrottledAfterAPNChanged() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); - - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_APN_CHANGED, null)); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - - // Verify unthrottling - verify(mDataThrottler, times(2)).reset(); - } - - @Test - public void testDataUnthrottledOnSimStateChanged() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); - - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - sendSimStateUpdated("testDataUnthrottledOnSimStateChanged"); - - // Verify unthrottling - verify(mDataThrottler, times(2)).reset(); - } - - @Test - public void testHandlingSecondHandoverRequest() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - setUpDataConnection(); - SparseArray apnContextsByType = Mockito.mock(SparseArray.class); - ConcurrentHashMap apnContexts = Mockito.mock(ConcurrentHashMap.class); - doReturn(mApnContext).when(apnContextsByType).get(eq(ApnSetting.TYPE_IMS)); - doReturn(mApnContext).when(apnContexts).get(eq(ApnSetting.TYPE_IMS_STRING)); - doReturn(false).when(mApnContext).isConnectable(); - doReturn(DctConstants.State.CONNECTING).when(mApnContext).getState(); - replaceInstance(DcTracker.class, "mApnContextsByType", mDct, apnContextsByType); - replaceInstance(DcTracker.class, "mApnContexts", mDct, apnContexts); - - sendInitializationEvents(); - - logd("Sending EVENT_ENABLE_APN"); - // APN id 0 is APN_TYPE_DEFAULT - Message msg = mDct.obtainMessage(12345); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER, msg); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - Map> msgs = getHandoverCompletionMessages(); - // Make sure the messages was queued properly instead of fired right away. - assertTrue(msgs.get(ApnSetting.TYPE_IMS).contains(msg)); - } - - @Test - public void testDataThrottledNotAllowData() throws Exception { - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - replaceInstance(DcTracker.class, "mDataThrottler", mDct, mDataThrottler); - doReturn(SystemClock.elapsedRealtime() + 100000).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_IMS); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - sendInitializationEvents(); - - DataConnectionReasons dataConnectionReasons = new DataConnectionReasons(); - boolean allowed = mDct.isDataAllowed(mApnContext, DcTracker.REQUEST_TYPE_NORMAL, - dataConnectionReasons); - assertFalse(dataConnectionReasons.toString(), allowed); - assertTrue(dataConnectionReasons.contains(DataDisallowedReasonType.DATA_THROTTLED)); - - // Makre sure no data setup request - verify(mSimulatedCommandsVerifier, never()).setupDataCall( - anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), - anyInt(), any(), any(), anyBoolean(), any(Message.class)); - } - - @Test - public void testNotifyDataDisconnected() { - // Verify notify data disconnected on DCT constructor, initialized in setUp() - ArgumentCaptor captor = - ArgumentCaptor.forClass(PreciseDataConnectionState.class); - verify(mPhone, times(13)).notifyDataConnection(captor.capture()); - for (PreciseDataConnectionState state : captor.getAllValues()) { - assertEquals(TelephonyManager.DATA_DISCONNECTED, state.getState()); - } - } - - /** - * There is a corresponding test {@link DataConnectionTest#testDataServiceTempUnavailable()} to - * test DataConnection behavior. - */ - @Test - public void testDataServiceTempUnavailable() { - Handler handler = Mockito.mock(Handler.class); - Message handoverCompleteMessage = Message.obtain(handler); - addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS); - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_SETUP_COMPLETE, - DcTracker.REQUEST_TYPE_HANDOVER, DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN, - new AsyncResult(Pair.create(mApnContext, 0), - DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE, new Exception()))); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - // Ensure handover is not completed yet - verify(handler, never()).sendMessageDelayed(any(), anyLong()); - } - - @Test - public void testNormalRequestDoesNotFailHandoverRequest() { - Handler handler = Mockito.mock(Handler.class); - Message handoverCompleteMessage = Message.obtain(handler); - addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS); - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL, null); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - // Ensure handover is not completed yet - verify(handler, never()).sendMessageDelayed(any(), anyLong()); - } - - @Test - public void testPreferenceChangedFallback() { - Handler handler = Mockito.mock(Handler.class); - doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) - .getPreferredTransport(anyInt()); - Message handoverCompleteMessage = Message.obtain(handler); - addHandoverCompleteMsg(handoverCompleteMessage, ApnSetting.TYPE_IMS); - initApns(ApnSetting.TYPE_IMS_STRING, new String[]{ApnSetting.TYPE_IMS_STRING}); - mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_HANDOVER, - handoverCompleteMessage); - waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler()); - Bundle bundle = handoverCompleteMessage.getData(); - assertTrue(bundle.getBoolean("extra_handover_failure_fallback")); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java deleted file mode 100644 index 4acfefb2a9..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/RetryManagerTest.java +++ /dev/null @@ -1,996 +0,0 @@ -/** - * Copyright (C) 2015 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.dataconnection; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; - -import android.os.PersistableBundle; -import android.os.SystemClock; -import android.telephony.CarrierConfigManager; -import android.telephony.data.ApnSetting; -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.SubscriptionController; -import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.uicc.UiccController; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; - -/** - * APN retry manager tests - */ -public class RetryManagerTest extends TelephonyTest { - - // This is the real APN data for the Japanese carrier NTT Docomo. - private final ApnSetting mApn1 = new ApnSetting.Builder() - .setId(2163) - .setOperatorNumeric("44010") - .setEntryName("sp-mode") - .setApnName("spmode.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private final ApnSetting mApn2 = new ApnSetting.Builder() - .setId(2164) - .setOperatorNumeric("44010") - .setEntryName("mopera U") - .setApnName("mopera.net") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private final ApnSetting mApn3 = new ApnSetting.Builder() - .setId(2165) - .setOperatorNumeric("44010") - .setEntryName("b-mobile for Nexus") - .setApnName("bmobile.ne.jp") - .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL) - .setProtocol(ApnSetting.PROTOCOL_IP) - .setRoamingProtocol(ApnSetting.PROTOCOL_IP) - .setCarrierEnabled(true) - .build(); - - private PersistableBundle mBundle; - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - mBundle = mContextFixture.getCarrierConfigBundle(); - doReturn(false).when(mPhone).isUsingNewDataStack(); - replaceInstance(SubscriptionController.class, "sInstance", null, mSubscriptionController); - replaceInstance(UiccController.class, "mInstance", null, mUiccController); - } - - @After - public void tearDown() throws Exception { - mBundle = null; - super.tearDown(); - } - - /** - * Test the behavior of a retry manager with no waiting APNs set. - */ - @Test - @SmallTest - public void testRetryManagerEmpty() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:2000"}); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - - long delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the basic retry scenario where only one APN and no retry configured. - */ - @Test - @SmallTest - public void testRetryManagerOneApnNoRetry() throws Exception { - - mBundle.putStringArray( - CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the basic retry scenario where only one APN with two retries configured. - */ - @Test - @SmallTest - public void testRetryManagerOneApnTwoRetries() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"supl:2000,3000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_SUPL); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(3000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - // No matter how many times we call getNextApnSetting, it should always return the next APN - // with NO_RETRY because we've already reached the maximum retry count. - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the basic retry scenario where two waiting APNs with one retry configured. - */ - @Test - @SmallTest - public void testRetryManagerTwoApnsOneRetry() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"others:2000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the basic retry scenario where two waiting APNs with two retries configured. - */ - @Test - @SmallTest - public void testRetryManagerTwoApnsTwoRetries() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"dun:2000,5000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DUN); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(5000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the basic retry scenario where two mms APNs with two retries configured. - */ - @Test - @SmallTest - public void testRetryManagerTwoMmsApnsTwoRetries() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"mms: 3000,6000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_MMS); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(3000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(6000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the permanent fail scenario with one APN configured. - */ - @Test - @SmallTest - public void testRetryManagerApnPermanentFailed() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"fota:1000,4000,7000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting apn = ApnSetting.makeApnSetting(mApn1); - waitingApns.add(apn); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_FOTA); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - - rm.markApnPermanentFailed(apn); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - } - - /** - * Test the permanent fail scenario with two APNs configured. - */ - @Test - @SmallTest - public void testRetryManagerApnPermanentFailedWithTwoApns() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"mms : 1000,4000,7000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_MMS); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - rm.markApnPermanentFailed(myApn1); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(7000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the permanent fail scenario with three APNs configured. - */ - @Test - @SmallTest - public void testRetryManagerApnPermanentFailedWithThreeApns() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:2000:2000,3000:3000", "ims:1000,4000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - ApnSetting myApn3 = ApnSetting.makeApnSetting(mApn3); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - waitingApns.add(myApn3); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_IMS); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - rm.markApnPermanentFailed(myApn2); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the permanent fail scenario with two APN all failed - */ - @Test - @SmallTest - public void testRetryManagerApnPermanentFailedAll() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:1000,4000,7000,9000", "mms:1234,4123"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - rm.markApnPermanentFailed(myApn1); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(7000, delay); - - rm.markApnPermanentFailed(myApn2); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - } - - /** - * Test the randomized delay scenario. - */ - @Test - @SmallTest - public void testRetryManagerDelayWithRandomization() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:default_randomization=1000,3000:2000,6000:3000,10000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertTrue(delay >= 3000 && delay < 5000); // 3s + 2s rand - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertTrue(delay >= 6000 && delay < 9000); // 6s + 3s rand - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertTrue(delay >= 10000 && delay < 11000); // 10s + 1s default rand - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the retry forever scenario - */ - @Test - @SmallTest - public void testRetryManagerRetryForever() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:max_retries=infinite,1000,2000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - } - - /** - * Test the explicit max retry scenario. - */ - @Test - @SmallTest - public void testRetryManagerExplicitMaxRetry() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"hipri: max_retries=4,1000,2000"}); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_HIPRI); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the fail fast scenario. - */ - @Test - @SmallTest - public void testRetryManagerFailFast() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:1000,5000"}); - - mBundle.putLong(CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 2000); - - ArrayList waitingApns = new ArrayList(); - waitingApns.add(ApnSetting.makeApnSetting(mApn1)); - waitingApns.add(ApnSetting.makeApnSetting(mApn2)); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(true); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(true); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(true); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(true); - assertEquals(2000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(true); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the permanent fail scenario with two APN all failed and then reset - */ - @Test - @SmallTest - public void testRetryManagerApnPermanentFailedAllAndThenReset() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"dun:1000,4000,7000,9000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DUN); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - rm.markApnPermanentFailed(myApn1); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(7000, delay); - - rm.markApnPermanentFailed(myApn2); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn == null); - - // reset the retry manager - - ApnSetting myApn3 = ApnSetting.makeApnSetting(mApn3); - waitingApns.clear(); - waitingApns.add(myApn3); - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"dun:3000,8000"}); - - rm.setWaitingApns(waitingApns); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(3000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(8000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn3)); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - private void assertRange(long low, long high, long value) { - if (value >= low && value <= high) return; - fail("Not in range[" + low + "," + high + "], value=" + value); - } - - /** - * Test the scenario where modem suggests retry the current APN once - */ - @Test - @SmallTest - public void testRetryManagerModemSuggestedRetryOnce() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"others:1000,4000,7000,9000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_MMS); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - // Network suggests retrying the current APN - doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_MMS); - delay = rm.getDelayForNextApn(false); - assertRange(2450, 2500, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - doReturn(RetryManager.NO_SUGGESTED_RETRY_DELAY).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_MMS); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - // Modem suggests retrying the current APN - //rm.setModemSuggestedDelay(30000); - doReturn(30000 + SystemClock.elapsedRealtime()).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_MMS); - delay = rm.getDelayForNextApn(false); - assertRange(29950, 30000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - doReturn(RetryManager.NO_SUGGESTED_RETRY_DELAY).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_MMS); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - } - - /** - * Test the scenario where modem suggests not retrying - */ - @Test - @SmallTest - public void testRetryManagerModemSuggestedNoRetry() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"default:1000,4000,7000,9000"}); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - // Modem suggests retrying the current APN - doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_DEFAULT); - delay = rm.getDelayForNextApn(false); - assertRange(2450, 2500, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - doReturn(RetryManager.NO_RETRY).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_DEFAULT); - delay = rm.getDelayForNextApn(false); - assertEquals(RetryManager.NO_RETRY, delay); - } - - /** - * Test the scenario that network suggests the same retry for too many times - */ - @Test - @SmallTest - public void testRetryNetworkSuggestedRetryTooManyTimes() throws Exception { - - mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS, - new String[]{"mms:2000,3000", "default:1000,4000,7000,9000"}); - - int maxRetryCount = 10; - - mBundle.putInt(CarrierConfigManager - .KEY_CARRIER_DATA_CALL_RETRY_NETWORK_REQUESTED_MAX_COUNT_INT, - maxRetryCount); - - ArrayList waitingApns = new ArrayList(); - ApnSetting myApn1 = ApnSetting.makeApnSetting(mApn1); - ApnSetting myApn2 = ApnSetting.makeApnSetting(mApn2); - waitingApns.add(myApn1); - waitingApns.add(myApn2); - - RetryManager rm = new RetryManager(mPhone, mDataThrottler, ApnSetting.TYPE_DEFAULT); - rm.setWaitingApns(waitingApns); - - ApnSetting nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - long delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - delay = rm.getDelayForNextApn(false); - assertEquals(1000, delay); - - for (int i = 0; i < maxRetryCount; i++) { - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_DEFAULT); - delay = rm.getDelayForNextApn(false); - assertRange(2450, 2500, delay); - } - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn1)); - doReturn(2500 + SystemClock.elapsedRealtime()).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_DEFAULT); - delay = rm.getDelayForNextApn(false); - assertEquals(20000, delay); - - nextApn = rm.getNextApnSetting(); - assertTrue(nextApn.equals(mApn2)); - doReturn(RetryManager.NO_SUGGESTED_RETRY_DELAY).when(mDataThrottler) - .getRetryTime(ApnSetting.TYPE_DEFAULT); - delay = rm.getDelayForNextApn(false); - assertEquals(4000, delay); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken deleted file mode 100644 index 2e9b88cbd6..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java.broken +++ /dev/null @@ -1,1935 +0,0 @@ -/* - * Copyright (C) 2007 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 GSMTestHandler.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.gsm; - -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.telephony.ServiceState; -import android.test.AndroidTestCase; -import android.test.PerformanceTestCase; - -import android.telephony.DisconnectCause; - -import com.android.internal.telephony.Call; -import com.android.internal.telephony.CallStateException; -import com.android.internal.telephony.Connection; -import com.android.internal.telephony.MmiCode; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.gsm.CallFailCause; -import com.android.internal.telephony.gsm.GSMPhone; -import com.android.internal.telephony.gsm.GSMTestHandler; -import com.android.internal.telephony.gsm.GsmMmiCode; -import com.android.internal.telephony.gsm.SuppServiceNotification; -import com.android.internal.telephony.test.SimulatedRadioControl; - -import java.util.List; - - -public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase { - private SimulatedRadioControl mRadioControl; - private GSMPhone mGSMPhone; - private GSMTestHandler mGSMTestHandler; - private Handler mHandler; - - private static final int EVENT_PHONE_STATE_CHANGED = 1; - private static final int EVENT_DISCONNECT = 2; - private static final int EVENT_RINGING = 3; - private static final int EVENT_CHANNEL_OPENED = 4; - private static final int EVENT_POST_DIAL = 5; - private static final int EVENT_DONE = 6; - private static final int EVENT_SSN = 7; - private static final int EVENT_MMI_INITIATE = 8; - private static final int EVENT_MMI_COMPLETE = 9; - private static final int EVENT_IN_SERVICE = 10; - private static final int SUPP_SERVICE_FAILED = 11; - private static final int SERVICE_STATE_CHANGED = 12; - private static final int EVENT_OEM_RIL_MESSAGE = 13; - public static final int ANY_MESSAGE = -1; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mGSMTestHandler = new GSMTestHandler(mContext); - - mGSMTestHandler.start(); - synchronized (mGSMTestHandler) { - do { - mGSMTestHandler.wait(); - } while (mGSMTestHandler.getGSMPhone() == null); - } - - mGSMPhone = mGSMTestHandler.getGSMPhone(); - mRadioControl = mGSMTestHandler.getSimulatedCommands(); - - mHandler = mGSMTestHandler.getHandler(); - mGSMPhone.registerForPreciseCallStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null); - mGSMPhone.registerForNewRingingConnection(mHandler, EVENT_RINGING, null); - mGSMPhone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null); - - mGSMPhone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL, null); - - mGSMPhone.registerForSuppServiceNotification(mHandler, EVENT_SSN, null); - mGSMPhone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null); - mGSMPhone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null); - mGSMPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null); - - mGSMPhone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null); - - // wait until we get phone in both voice and data service - Message msg; - ServiceState state; - - do { - msg = mGSMTestHandler.waitForMessage(SERVICE_STATE_CHANGED); - assertNotNull("Message Time Out", msg); - state = (ServiceState) ((AsyncResult) msg.obj).result; - } while (state.getState() != ServiceState.STATE_IN_SERVICE); - } - - @Override - protected void tearDown() throws Exception { - mRadioControl.shutdown(); - - mGSMPhone.unregisterForPreciseCallStateChanged(mHandler); - mGSMPhone.unregisterForNewRingingConnection(mHandler); - mGSMPhone.unregisterForDisconnect(mHandler); - mGSMPhone.setOnPostDialCharacter(mHandler, 0, null); - mGSMPhone.unregisterForSuppServiceNotification(mHandler); - mGSMPhone.unregisterForMmiInitiate(mHandler); - mGSMPhone.unregisterForMmiComplete(mHandler); - - mGSMPhone = null; - mRadioControl = null; - mHandler = null; - mGSMTestHandler.cleanup(); - - super.tearDown(); - } - - // These test can only be run once. - public int startPerformance(Intermediates intermediates) { - return 1; - } - - public boolean isPerformanceOnly() { - return false; - } - - - //This test is causing the emulator screen to turn off. I don't understand - //why, but I'm removing it until we can figure it out. - public void brokenTestGeneral() throws Exception { - Connection cn; - Message msg; - AsyncResult ar; - - // IDLE state - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - assertFalse(mGSMPhone.canConference()); - - // One DIALING connection - - mRadioControl.setAutoProgressConnectingCall(false); - - mGSMPhone.dial("+13125551212"); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - - msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertEquals(Call.State.DIALING, mGSMPhone.getForegroundCall().getState()); - assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - /*do { - mGSMTestHandler.waitForMessage(ANY_MESSAGE); - } while (mGSMPhone.getForegroundCall().getConnections().size() == 0);*/ - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DIALING, - mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - cn = mGSMPhone.getForegroundCall().getConnections().get(0); - assertTrue(!cn.isIncoming()); - assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); - - assertEquals(DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); - - assertFalse(mGSMPhone.canConference()); - - // One ALERTING connection - - mRadioControl.progressConnectingCallState(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } - while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ALERTING, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - cn = mGSMPhone.getForegroundCall().getConnections().get(0); - assertTrue(!cn.isIncoming()); - assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); - assertFalse(mGSMPhone.canConference()); - - // One ACTIVE connection - - mRadioControl.progressConnectingCallState(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); - - cn = mGSMPhone.getForegroundCall().getConnections().get(0); - assertTrue(!cn.isIncoming()); - assertEquals(Connection.PostDialState.COMPLETE, cn.getPostDialState()); - assertFalse(mGSMPhone.canConference()); - - // One disconnected connection - mGSMPhone.getForegroundCall().hangup(); - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); - - assertFalse(mGSMPhone.canConference()); - - cn = mGSMPhone.getForegroundCall().getEarliestConnection(); - - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - // Back to idle state - - mGSMPhone.clearDisconnected(); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - assertFalse(mGSMPhone.canConference()); - - // cn left over from before phone.clearDisconnected(); - - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - // One ringing (INCOMING) call - - mRadioControl.triggerRing("18005551212"); - - msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - ar = (AsyncResult) msg.obj; - cn = (Connection) ar.result; - assertTrue(cn.isRinging()); - assertEquals(mGSMPhone.getRingingCall(), cn.getCall()); - - assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - cn = mGSMPhone.getRingingCall().getConnections().get(0); - assertTrue(cn.isIncoming()); - assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); - - assertFalse(mGSMPhone.canConference()); - - // One mobile terminated active call - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getConnections().size() == 1); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, - mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); - - cn = mGSMPhone.getForegroundCall().getConnections().get(0); - assertTrue(cn.isIncoming()); - assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); - - assertFalse(mGSMPhone.canConference()); - - // One disconnected (local hangup) call - - try { - Connection conn; - conn = mGSMPhone.getForegroundCall().getConnections().get(0); - conn.hangup(); - } catch (CallStateException ex) { - ex.printStackTrace(); - fail("unexpected ex"); - } - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, - mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); - - cn = mGSMPhone.getForegroundCall().getEarliestConnection(); - - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); - - assertFalse(mGSMPhone.canConference()); - - // Back to idle state - - mGSMPhone.clearDisconnected(); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - assertFalse(mGSMPhone.canConference()); - - // cn left over from before phone.clearDisconnected(); - - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - // One ringing call - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - assertFalse(mGSMPhone.canConference()); - - // One rejected call - mGSMPhone.rejectCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - cn = mGSMPhone.getRingingCall().getEarliestConnection(); - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); - - assertFalse(mGSMPhone.canConference()); - - // Back to idle state - - mGSMPhone.clearDisconnected(); - - assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - assertFalse(mGSMPhone.canConference()); - assertEquals(Call.State.DISCONNECTED, cn.getState()); - - // One ringing call - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - cn = mGSMPhone.getRingingCall().getEarliestConnection(); - - // Ringing call disconnects - - mRadioControl.triggerHangupForeground(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); - - assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); - - // One Ringing Call - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); - - - cn = mGSMPhone.getRingingCall().getEarliestConnection(); - - // One answered call - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // one holding call - mGSMPhone.switchHoldingAndActive(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); - - - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // one active call - mGSMPhone.switchHoldingAndActive(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } - while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // One disconnected call in the foreground slot - - mRadioControl.triggerHangupAll(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(DisconnectCause.NORMAL, cn.getDisconnectCause()); - - // Test missed calls - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); - - mGSMPhone.rejectCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (msg.what != EVENT_DISCONNECT); - - ar = (AsyncResult) msg.obj; - cn = (Connection) ar.result; - - assertEquals(DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); - - // Test incoming not missed calls - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); - - cn = mGSMPhone.getRingingCall().getEarliestConnection(); - - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - assertEquals(DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - - try { - mGSMPhone.getForegroundCall().hangup(); - } catch (CallStateException ex) { - ex.printStackTrace(); - fail("unexpected ex"); - } - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() - != Call.State.DISCONNECTED); - - assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); - - // - // Test held and hangup held calls - // - - // One ALERTING call - mGSMPhone.dial("+13125551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - mRadioControl.progressConnectingCallState(); - mRadioControl.progressConnectingCallState(); - - // One ACTIVE call - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - // One ACTIVE call, one ringing call - - mRadioControl.triggerRing("18005551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - // One HOLDING call, one ACTIVE call - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertTrue(mGSMPhone.canConference()); - - // Conference the two - mGSMPhone.conference(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertTrue(mGSMPhone.getForegroundCall().isMultiparty()); - assertFalse(mGSMPhone.canConference()); - - // Hold the multiparty call - mGSMPhone.switchHoldingAndActive(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } - while (mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); - assertFalse(mGSMPhone.canConference()); - - // Multiparty call on hold, call waiting added - - mRadioControl.triggerRing("18005558355"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.RINGING); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertFalse(mGSMPhone.canConference()); - - // Hangup conference call, ringing call still around - mGSMPhone.getBackgroundCall().hangup(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.DISCONNECTED); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - - // Reject waiting call - mGSMPhone.rejectCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.IDLE); - - assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - } - - public void testOutgoingCallFailImmediately() throws Exception { - Message msg; - - // Test outgoing call fail-immediately edge case - // This happens when a call terminated before ever appearing in a - // call list - // This should land the immediately-failing call in the - // ForegroundCall list as an IDLE call - mRadioControl.setNextDialFailImmediately(true); - - Connection cn = mGSMPhone.dial("+13125551212"); - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(DisconnectCause.NORMAL, cn.getDisconnectCause()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - } - - public void testHangupOnOutgoing() throws Exception { - Connection cn; - Message msg; - - mRadioControl.setAutoProgressConnectingCall(false); - - // Test 1: local hangup in "DIALING" state - mGSMPhone.dial("+13125551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } - while (mGSMPhone.getForegroundCall().getState() != Call.State.DIALING); - - cn = mGSMPhone.getForegroundCall().getEarliestConnection(); - - mGSMPhone.getForegroundCall().hangup(); - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); - - // Test 2: local hangup in "ALERTING" state - mGSMPhone.dial("+13125551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - mRadioControl.progressConnectingCallState(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } - while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); - - cn = mGSMPhone.getForegroundCall().getEarliestConnection(); - - mGSMPhone.getForegroundCall().hangup(); - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(DisconnectCause.LOCAL, cn.getDisconnectCause()); - - // Test 3: local immediate hangup before GSM index is - // assigned (CallTracker.hangupPendingMO case) - - mRadioControl.pauseResponses(); - - cn = mGSMPhone.dial("+13125551212"); - - cn.hangup(); - - mRadioControl.resumeResponses(); - - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - - assertEquals(DisconnectCause.LOCAL, - mGSMPhone.getForegroundCall().getEarliestConnection().getDisconnectCause()); - } - - public void testHangupOnChannelClose() throws Exception { - mGSMPhone.dial("+13125551212"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getConnections().isEmpty()); - - mRadioControl.shutdown(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - mGSMPhone.clearDisconnected(); - } while (!mGSMPhone.getForegroundCall().getConnections().isEmpty()); - } - - public void testIncallMmiCallDeflection() throws Exception { - Message msg; - - // establish an active call - mGSMPhone.dial("+13125551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // establish a ringing (WAITING) call - - mRadioControl.triggerRing("18005551212"); - - msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering 0 followed by SEND: release all held calls - // or sets UDUB for a waiting call. - mGSMPhone.handleInCallMmiCommands("0"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // change the active call to holding call - mGSMPhone.switchHoldingAndActive(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); - - - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering 0 followed by SEND: release all held calls - // or sets UDUB for a waiting call. - mGSMPhone.handleInCallMmiCommands("0"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); - } - - public void testIncallMmiCallWaiting() throws Exception { - Message msg; - - // establish an active call - mGSMPhone.dial("+13125551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // establish a ringing (WAITING) call - - mRadioControl.triggerRing("18005551212"); - - do { - msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); - assertNotNull("Message Time Out", msg); - } while (msg.what != EVENT_RINGING); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering 1 followed by SEND: release all active calls - // (if any exist) and accepts the other (held or waiting) call. - - mGSMPhone.handleInCallMmiCommands("1"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - - // change the active call to holding call - mGSMPhone.switchHoldingAndActive(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); - - assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering 1 followed by SEND: release all active calls - // (if any exist) and accepts the other (held or waiting) call. - mGSMPhone.handleInCallMmiCommands("1"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - - // at this point, the active call with number==18005551212 should - // have the gsm index of 2 - - mRadioControl.triggerRing("16505550100"); - - msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering "12" followed by SEND: release the call with - // gsm index equals to 2. - mGSMPhone.handleInCallMmiCommands("12"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertFalse(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // at this point, the call with number==16505550100 should - // have the gsm index of 1 - mGSMPhone.dial("+13125551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE || - mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // at this point, the active call with number==13125551212 should - // have the gsm index of 2 - - // Simulate entering "11" followed by SEND: release the call with - // gsm index equals to 1. This should not be allowed, and a - // Supplementary Service notification must be received. - mGSMPhone.handleInCallMmiCommands("11"); - - msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED); - assertNotNull("Message Time Out", msg); - assertFalse("IncallMmiCallWaiting: command should not work on holding call", msg == null); - - // Simulate entering "12" followed by SEND: release the call with - // gsm index equals to 2. - mGSMPhone.handleInCallMmiCommands("12"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // Simulate entering 1 followed by SEND: release all active calls - // (if any exist) and accepts the other (held or waiting) call. - mGSMPhone.handleInCallMmiCommands("1"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - assertEquals("16505550100", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - - // Simulate entering "11" followed by SEND: release the call with - // gsm index equals to 1. - mGSMPhone.handleInCallMmiCommands("11"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - } - - public void testIncallMmiCallHold() throws Exception { - Message msg; - - // establish an active call - mGSMPhone.dial("13125551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // establish a ringing (WAITING) call - - mRadioControl.triggerRing("18005551212"); - - msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // simulate entering 2 followed by SEND: place all active calls - // (if any exist) on hold and accepts the other (held or waiting) - // call - - mGSMPhone.handleInCallMmiCommands("2"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); - - - assertFalse(mGSMPhone.getRingingCall().isRinging()); - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, - mGSMPhone.getForegroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertEquals("13125551212", - mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); - - // swap the active and holding calls - mGSMPhone.handleInCallMmiCommands("2"); - - msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED); - assertNotNull("Message Time Out", msg); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("13125551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); - - // merge the calls - mGSMPhone.conference(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - assertEquals(2, mGSMPhone.getForegroundCall().getConnections().size()); - - // at this point, we have an active conference call, with - // call(1) = 13125551212 and call(2) = 18005551212 - - // Simulate entering "23" followed by SEND: places all active call - // on hold except call 3. This should fail and a supplementary service - // failed notification should be received. - - mGSMPhone.handleInCallMmiCommands("23"); - - msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED); - assertNotNull("Message Time Out", msg); - assertFalse("IncallMmiCallHold: separate should have failed!", msg == null); - - // Simulate entering "21" followed by SEND: places all active call - // on hold except call 1. - mGSMPhone.handleInCallMmiCommands("21"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("13125551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); - } - - public void testIncallMmiMultipartyServices() throws Exception { - // establish an active call - mGSMPhone.dial("13125551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - // dial another call - mGSMPhone.dial("18005551212"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - mGSMPhone.handleInCallMmiCommands("3"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertEquals(PhoneConstants.State.OFFHOOK, mGSMPhone.getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals("13125551212", - mGSMPhone.getForegroundCall().getConnections().get(1).getAddress()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - } - - public void testCallIndex() throws Exception { - Message msg; - - // establish the first call - mGSMPhone.dial("16505550100"); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - String baseNumber = "1650555010"; - - for (int i = 1; i < 6; i++) { - String number = baseNumber + i; - - mGSMPhone.dial(number); - - do { - mRadioControl.progressConnectingCallState(); - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - if (mGSMPhone.getBackgroundCall().getConnections().size() >= 5) { - break; - } - - mGSMPhone.conference(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - } - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("16505550105", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // create an incoming call, this call should have the call index - // of 7 - mRadioControl.triggerRing("18005551212"); - - msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); - assertNotNull("Message Time Out", msg); - - assertEquals(PhoneConstants.State.RINGING, mGSMPhone.getState()); - assertTrue(mGSMPhone.getRingingCall().isRinging()); - assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - - // hangup the background call and accept the ringing call - mGSMPhone.getBackgroundCall().hangup(); - mGSMPhone.acceptCall(); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getRingingCall().getState() != Call.State.IDLE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals("18005551212", - mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertEquals("16505550105", - mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); - - mGSMPhone.handleInCallMmiCommands("17"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); - assertEquals("16505550105", - mGSMPhone.getBackgroundCall().getConnections().get(0). - getAddress()); - - mGSMPhone.handleInCallMmiCommands("1"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); - - assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - mGSMPhone.handleInCallMmiCommands("16"); - - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); - - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - } - - public void testPostDialSequences() throws Exception { - Message msg; - AsyncResult ar; - Connection cn; - - mGSMPhone.dial("+13125551212,1234;5N8xx"); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(',', msg.arg1); - assertEquals("1234;5N8", cn.getRemainingPostDialString()); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('1', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('2', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('3', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('4', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals(';', msg.arg1); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); - assertEquals(Connection.PostDialState.WAIT, ar.userObj); - cn.proceedAfterWaitChar(); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('5', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertEquals('N', msg.arg1); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); - assertEquals(Connection.PostDialState.WILD, ar.userObj); - cn.proceedAfterWildChar(",6;7"); - - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(',', msg.arg1); - assertEquals("6;78", cn.getRemainingPostDialString()); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('6', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals(';', msg.arg1); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); - assertEquals(Connection.PostDialState.WAIT, ar.userObj); - cn.proceedAfterWaitChar(); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('7', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals('8', msg.arg1); - ar = (AsyncResult) (msg.obj); - assertEquals(Connection.PostDialState.STARTED, ar.userObj); - - // Bogus chars at end should be ignored - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals(0, msg.arg1); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(Connection.PostDialState.COMPLETE, - cn.getPostDialState()); - assertEquals(Connection.PostDialState.COMPLETE, ar.userObj); - } - - public void testPostDialCancel() throws Exception { - Message msg; - AsyncResult ar; - Connection cn; - - mGSMPhone.dial("+13125551212,N"); - mRadioControl.progressConnectingToActive(); - - mRadioControl.progressConnectingToActive(); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertNotNull("Message Time Out", msg); - assertEquals(',', msg.arg1); - - msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); - assertEquals('N', msg.arg1); - ar = (AsyncResult) (msg.obj); - cn = (Connection) (ar.result); - assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); - cn.cancelPostDial(); - - assertEquals(Connection.PostDialState.CANCELLED, cn.getPostDialState()); - } - - public void testOutgoingCallFail() throws Exception { - Message msg; - /* - * normal clearing - */ - - mRadioControl.setNextCallFailCause(CallFailCause.NORMAL_CLEARING); - mRadioControl.setAutoProgressConnectingCall(false); - - Connection cn = mGSMPhone.dial("+13125551212"); - - mRadioControl.progressConnectingCallState(); - - // I'm just progressing the call state to - // ensure getCurrentCalls() gets processed... - // Normally these failure conditions would happen in DIALING - // not ALERTING - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (cn.getState() == Call.State.DIALING); - - - mRadioControl.triggerHangupAll(); - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(DisconnectCause.NORMAL, cn.getDisconnectCause()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - /* - * busy - */ - - mRadioControl.setNextCallFailCause(CallFailCause.USER_BUSY); - mRadioControl.setAutoProgressConnectingCall(false); - - cn = mGSMPhone.dial("+13125551212"); - - mRadioControl.progressConnectingCallState(); - - // I'm just progressing the call state to - // ensure getCurrentCalls() gets processed... - // Normally these failure conditions would happen in DIALING - // not ALERTING - do { - assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); - } while (cn.getState() == Call.State.DIALING); - - - mRadioControl.triggerHangupAll(); - msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); - assertNotNull("Message Time Out", msg); - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(DisconnectCause.BUSY, cn.getDisconnectCause()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, - mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - - /* - * congestion - */ - - mRadioControl.setNextCallFailCause(CallFailCause.NO_CIRCUIT_AVAIL); - mRadioControl.setAutoProgressConnectingCall(false); - - cn = mGSMPhone.dial("+13125551212"); - - mRadioControl.progressConnectingCallState(); - - // I'm just progressing the call state to - // ensure getCurrentCalls() gets processed... - // Normally these failure conditions would happen in DIALING - // not ALERTING - do { - msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); - assertNotNull("Message Time Out", msg); - } while (cn.getState() == Call.State.DIALING); - - - mRadioControl.triggerHangupAll(); - - // Unlike the while loops above, this one waits - // for a "phone state changed" message back to "idle" - do { - msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); - assertNotNull("Message Time Out", msg); - } while (!(msg.what == EVENT_PHONE_STATE_CHANGED - && mGSMPhone.getState() == PhoneConstants.State.IDLE)); - - assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState()); - - assertEquals(DisconnectCause.CONGESTION, cn.getDisconnectCause()); - - assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); - assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); - assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); - - assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); - assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); - assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); - - assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); - assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); - } - - public void testSSNotification() throws Exception { - // MO - runTest(0, SuppServiceNotification.MO_CODE_UNCONDITIONAL_CF_ACTIVE); - runTest(0, SuppServiceNotification.MO_CODE_CALL_IS_WAITING); - runTest(0, SuppServiceNotification.MO_CODE_CALL_DEFLECTED); - - // MT - runTest(1, SuppServiceNotification.MT_CODE_FORWARDED_CALL); - runTest(1, SuppServiceNotification.MT_CODE_CALL_CONNECTED_ECT); - runTest(1, SuppServiceNotification.MT_CODE_ADDITIONAL_CALL_FORWARDED); - } - - private void runTest(int type, int code) { - Message msg; - - mRadioControl.triggerSsn(type, code); - - msg = mGSMTestHandler.waitForMessage(EVENT_SSN); - assertNotNull("Message Time Out", msg); - AsyncResult ar = (AsyncResult) msg.obj; - - assertNull(ar.exception); - - SuppServiceNotification notification = - (SuppServiceNotification) ar.result; - - assertEquals(type, notification.notificationType); - assertEquals(code, notification.code); - } - - public void testUssd() throws Exception { - // Quick hack to work around a race condition in this test: - // We may initiate a USSD MMI before GSMPhone receives its initial - // GSMTestHandler.EVENT_RADIO_OFF_OR_NOT_AVAILABLE event. When the phone sees this - // event, it will cancel the just issued USSD MMI, which we don't - // want. So sleep a little first. - try { - Thread.sleep(1000); - } catch (InterruptedException ex) { - // do nothing - } - - verifyNormal(); - verifyCancel(); - varifyNetworkInitiated(); - } - - private void varifyNetworkInitiated() { - Message msg; - AsyncResult ar; - MmiCode mmi; - - // Receive an incoming NOTIFY - mRadioControl.triggerIncomingUssd("0", "NOTIFY message"); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertFalse(mmi.isUssdRequest()); - - // Receive a REQUEST and send response - mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertTrue(mmi.isUssdRequest()); - - mGSMPhone.sendUssdResponse("## TEST: TEST_GSMPhone responding..."); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - GsmMmiCode gsmMmi = (GsmMmiCode) mmi; - assertTrue(gsmMmi.isPendingUSSD()); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertNull(ar.exception); - assertFalse(mmi.isUssdRequest()); - - // Receive a REQUEST and cancel - mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertTrue(mmi.isUssdRequest()); - - mmi.cancel(); - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertNull(ar.exception); - assertEquals(MmiCode.State.CANCELLED, mmi.getState()); - - List mmiList = mGSMPhone.getPendingMmiCodes(); - assertEquals(0, mmiList.size()); - } - - private void verifyNormal() throws CallStateException { - Message msg; - AsyncResult ar; - MmiCode mmi; - - mGSMPhone.dial("#646#"); - - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); - assertNotNull("Message Time Out", msg); - - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - - ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - assertEquals(MmiCode.State.COMPLETE, mmi.getState()); - } - - - private void verifyCancel() throws CallStateException { - /** - * This case makes an assumption that dial() will add the USSD - * to the "pending MMI codes" list before it returns. This seems - * like reasonable semantics. It also assumes that the USSD - * request in question won't complete until we get back to the - * event loop, thus cancel() is safe. - */ - Message msg; - - mGSMPhone.dial("#646#"); - - List pendingMmis = mGSMPhone.getPendingMmiCodes(); - - assertEquals(1, pendingMmis.size()); - - MmiCode mmi = pendingMmis.get(0); - assertTrue(mmi.isCancelable()); - mmi.cancel(); - - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); - assertNotNull("Message Time Out", msg); - - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - - AsyncResult ar = (AsyncResult) msg.obj; - mmi = (MmiCode) ar.result; - - assertEquals(MmiCode.State.CANCELLED, mmi.getState()); - } - - public void testRilHooks() throws Exception { - // - // These test cases all assume the RIL OEM hooks - // just echo back their input - // - - Message msg; - AsyncResult ar; - - // null byte array - - mGSMPhone.invokeOemRilRequestRaw(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertNull(ar.result); - assertNull(ar.exception); - - // empty byte array - - mGSMPhone.invokeOemRilRequestRaw(new byte[0], mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertEquals(0, ((byte[]) (ar.result)).length); - assertNull(ar.exception); - - // byte array with data - - mGSMPhone.invokeOemRilRequestRaw("Hello".getBytes("utf-8"), - mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertEquals("Hello", new String(((byte[]) (ar.result)), "utf-8")); - assertNull(ar.exception); - - // null strings - - mGSMPhone.invokeOemRilRequestStrings(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertNull(ar.result); - assertNull(ar.exception); - - // empty byte array - - mGSMPhone.invokeOemRilRequestStrings(new String[0], - mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertEquals(0, ((String[]) (ar.result)).length); - assertNull(ar.exception); - - // Strings with data - - String s[] = new String[1]; - - s[0] = "Hello"; - - mGSMPhone.invokeOemRilRequestStrings(s, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); - - msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); - assertNotNull("Message Time Out", msg); - - ar = ((AsyncResult) msg.obj); - - assertEquals("Hello", ((String[]) (ar.result))[0]); - assertEquals(1, ((String[]) (ar.result)).length); - assertNull(ar.exception); - } - - public void testMmi() throws Exception { - mRadioControl.setAutoProgressConnectingCall(false); - - // "valid" MMI sequences - runValidMmi("*#67#", false); - runValidMmi("##43*11#", false); - runValidMmi("#33*1234*11#", false); - runValidMmi("*21*6505551234**5#", false); - runValidMmi("**03**1234*4321*4321#", false); - // pound string - runValidMmi("5308234092307540923#", true); - // short code - runValidMmi("22", true); - // as part of call setup - runValidMmiWithConnect("*31#6505551234"); - - // invalid MMI sequences - runNotMmi("6505551234"); - runNotMmi("1234#*12#34566654"); - runNotMmi("*#*#12#*"); - } - - private void runValidMmi(String dialString, boolean cancelable) throws CallStateException { - Connection c = mGSMPhone.dial(dialString); - assertNull(c); - Message msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); - assertNotNull("Message Time Out", msg); - // Should not be cancelable. - AsyncResult ar = (AsyncResult) msg.obj; - MmiCode mmi = (MmiCode) ar.result; - assertEquals(cancelable, mmi.isCancelable()); - - msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); - assertNotNull("Message Time Out", msg); - } - - private void runValidMmiWithConnect(String dialString) throws CallStateException { - mRadioControl.pauseResponses(); - - Connection c = mGSMPhone.dial(dialString); - assertNotNull(c); - - hangup(c); - } - - private void hangup(Connection cn) throws CallStateException { - cn.hangup(); - - mRadioControl.resumeResponses(); - assertNotNull(mGSMTestHandler.waitForMessage(EVENT_DISCONNECT)); - - } - - private void runNotMmi(String dialString) throws CallStateException { - mRadioControl.pauseResponses(); - - Connection c = mGSMPhone.dial(dialString); - assertNotNull(c); - - hangup(c); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken deleted file mode 100644 index 16861fac7f..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java.broken +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2009 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.gsm; - -import android.content.Context; - -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import com.android.telephony.Rlog; - -import com.android.internal.telephony.gsm.GSMPhone; -import com.android.internal.telephony.test.SimulatedCommands; -import com.android.internal.telephony.TestPhoneNotifier; - -/** - * This class creates a HandlerThread which waits for the various messages. - */ -public class GSMTestHandler extends HandlerThread implements Handler.Callback { - - private Handler mHandler; - private Message mCurrentMessage; - - private Boolean mMsgConsumed; - private SimulatedCommands sc; - private GSMPhone mGSMPhone; - private Context mContext; - - private static final int FAIL_TIMEOUT_MILLIS = 5 * 1000; - - public GSMTestHandler(Context context) { - super("GSMPhoneTest"); - mMsgConsumed = false; - mContext = context; - } - - @Override - protected void onLooperPrepared() { - sc = new SimulatedCommands(); - mGSMPhone = new GSMPhone(mContext, sc, new TestPhoneNotifier(), true); - mHandler = new Handler(getLooper(), this); - synchronized (this) { - notifyAll(); - } - } - - public boolean handleMessage(Message msg) { - synchronized (this) { - mCurrentMessage = msg; - this.notifyAll(); - while(!mMsgConsumed) { - try { - this.wait(); - } catch (InterruptedException e) {} - } - mMsgConsumed = false; - } - return true; - } - - - public void cleanup() { - Looper looper = getLooper(); - if (looper != null) looper.quit(); - mHandler = null; - } - - public Handler getHandler() { - return mHandler; - } - - public SimulatedCommands getSimulatedCommands() { - return sc; - } - - public GSMPhone getGSMPhone() { - return mGSMPhone; - } - - public Message waitForMessage(int code) { - Message msg; - while(true) { - msg = null; - synchronized (this) { - try { - this.wait(FAIL_TIMEOUT_MILLIS); - } catch (InterruptedException e) { - } - - // Check if timeout has occurred. - if (mCurrentMessage != null) { - // Consume the message - msg = Message.obtain(); - msg.copyFrom(mCurrentMessage); - mCurrentMessage = null; - mMsgConsumed = true; - this.notifyAll(); - } - } - if (msg == null || code == GSMPhoneTest.ANY_MESSAGE || msg.what == code) return msg; - } - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken deleted file mode 100644 index a9d869c4cb..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java.broken +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Copyright (C) 2011 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.gsm; - -import android.content.Context; -import android.os.AsyncResult; -import android.os.Message; -import android.os.SystemClock; -import com.android.telephony.Rlog; - -import com.android.internal.telephony.BaseCommands; -import com.android.internal.telephony.UUSInfo; -import com.android.internal.telephony.uicc.IccIoResult; -import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; - -import junit.framework.Assert; - -/** - * Dummy BaseCommands for UsimDataDownloadTest. Only implements UICC envelope and - * SMS acknowledgement commands. - */ -class UsimDataDownloadCommands extends BaseCommands { - private static final String TAG = "UsimDataDownloadCommands"; - - private boolean mExpectingAcknowledgeGsmSms; // true if expecting ack GSM SMS - private boolean mExpectingAcknowledgeGsmSmsSuccess; // true if expecting ack SMS success - private int mExpectingAcknowledgeGsmSmsFailureCause; // expecting ack SMS failure cause - private String mExpectingAcknowledgeGsmSmsPdu; // expecting ack SMS PDU - - private boolean mExpectingSendEnvelope; // true to expect a send envelope command - private String mExpectingSendEnvelopeContents; // expected string for send envelope - private int mExpectingSendEnvelopeResponseSw1; // SW1/SW2 response status - private int mExpectingSendEnvelopeResponseSw2; // SW1/SW2 response status - private String mExpectingSendEnvelopeResponse; // Response string for Send Envelope - - UsimDataDownloadCommands(Context context) { - super(context); - } - - /** - * Expect a call to acknowledgeLastIncomingGsmSms with success flag and failure cause. - * @param success true if expecting success; false if expecting failure - * @param cause the failure cause, if success is false - */ - synchronized void expectAcknowledgeGsmSms(boolean success, int cause) { - Assert.assertFalse("expectAcknowledgeGsmSms called twice", mExpectingAcknowledgeGsmSms); - mExpectingAcknowledgeGsmSms = true; - mExpectingAcknowledgeGsmSmsSuccess = success; - mExpectingAcknowledgeGsmSmsFailureCause = cause; - } - - /** - * Expect a call to acknowledgeLastIncomingGsmSmsWithPdu with success flag and PDU. - * @param success true if expecting success; false if expecting failure - * @param ackPdu the acknowledgement PDU to expect - */ - synchronized void expectAcknowledgeGsmSmsWithPdu(boolean success, String ackPdu) { - Assert.assertFalse("expectAcknowledgeGsmSms called twice", mExpectingAcknowledgeGsmSms); - mExpectingAcknowledgeGsmSms = true; - mExpectingAcknowledgeGsmSmsSuccess = success; - mExpectingAcknowledgeGsmSmsPdu = ackPdu; - } - - /** - * Expect a call to sendEnvelopeWithStatus(). - * @param contents expected envelope contents to send - * @param sw1 simulated SW1 status to return - * @param sw2 simulated SW2 status to return - * @param response simulated envelope response to return - */ - synchronized void expectSendEnvelope(String contents, int sw1, int sw2, String response) { - Assert.assertFalse("expectSendEnvelope called twice", mExpectingSendEnvelope); - mExpectingSendEnvelope = true; - mExpectingSendEnvelopeContents = contents; - mExpectingSendEnvelopeResponseSw1 = sw1; - mExpectingSendEnvelopeResponseSw2 = sw2; - mExpectingSendEnvelopeResponse = response; - } - - synchronized void assertExpectedMethodsCalled() { - long stopTime = SystemClock.elapsedRealtime() + 5000; - while ((mExpectingAcknowledgeGsmSms || mExpectingSendEnvelope) - && SystemClock.elapsedRealtime() < stopTime) { - try { - wait(); - } catch (InterruptedException ignored) {} - } - Assert.assertFalse("expecting SMS acknowledge call", mExpectingAcknowledgeGsmSms); - Assert.assertFalse("expecting send envelope call", mExpectingSendEnvelope); - } - - @Override - public synchronized void acknowledgeLastIncomingGsmSms(boolean success, int cause, - Message response) { - Rlog.d(TAG, "acknowledgeLastIncomingGsmSms: success=" + success + ", cause=" + cause); - Assert.assertTrue("unexpected call to acknowledge SMS", mExpectingAcknowledgeGsmSms); - Assert.assertEquals(mExpectingAcknowledgeGsmSmsSuccess, success); - Assert.assertEquals(mExpectingAcknowledgeGsmSmsFailureCause, cause); - mExpectingAcknowledgeGsmSms = false; - if (response != null) { - AsyncResult.forMessage(response); - response.sendToTarget(); - } - notifyAll(); // wake up assertExpectedMethodsCalled() - } - - @Override - public synchronized void acknowledgeIncomingGsmSmsWithPdu(boolean success, String ackPdu, - Message response) { - Rlog.d(TAG, "acknowledgeLastIncomingGsmSmsWithPdu: success=" + success - + ", ackPDU= " + ackPdu); - Assert.assertTrue("unexpected call to acknowledge SMS", mExpectingAcknowledgeGsmSms); - Assert.assertEquals(mExpectingAcknowledgeGsmSmsSuccess, success); - Assert.assertEquals(mExpectingAcknowledgeGsmSmsPdu, ackPdu); - mExpectingAcknowledgeGsmSms = false; - if (response != null) { - AsyncResult.forMessage(response); - response.sendToTarget(); - } - notifyAll(); // wake up assertExpectedMethodsCalled() - } - - @Override - public synchronized void sendEnvelopeWithStatus(String contents, Message response) { - // Add spaces between hex bytes for readability - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < contents.length(); i += 2) { - builder.append(contents.charAt(i)).append(contents.charAt(i+1)).append(' '); - } - Rlog.d(TAG, "sendEnvelopeWithStatus: " + builder.toString()); - - Assert.assertTrue("unexpected call to send envelope", mExpectingSendEnvelope); - Assert.assertEquals(mExpectingSendEnvelopeContents, contents); - mExpectingSendEnvelope = false; - - IccIoResult result = new IccIoResult(mExpectingSendEnvelopeResponseSw1, - mExpectingSendEnvelopeResponseSw2, mExpectingSendEnvelopeResponse); - - if (response != null) { - AsyncResult.forMessage(response, result, null); - response.sendToTarget(); - } - notifyAll(); // wake up assertExpectedMethodsCalled() - } - - @Override - public void setSuppServiceNotifications(boolean enable, Message result) { - } - - @Override - public void supplyIccPin(String pin, Message result) { - } - - @Override - public void supplyIccPinForApp(String pin, String aid, Message result) { - } - - @Override - public void supplyIccPuk(String puk, String newPin, Message result) { - } - - @Override - public void supplyIccPukForApp(String puk, String newPin, String aid, Message result) { - } - - @Override - public void supplyIccPin2(String pin2, Message result) { - } - - @Override - public void supplyIccPin2ForApp(String pin2, String aid, Message result) { - } - - @Override - public void supplyIccPuk2(String puk2, String newPin2, Message result) { - } - - @Override - public void supplyIccPuk2ForApp(String puk2, String newPin2, String aid, Message result) { - } - - @Override - public void changeIccPin(String oldPin, String newPin, Message result) { - } - - @Override - public void changeIccPinForApp(String oldPin, String newPin, String aidPtr, Message result) { - } - - @Override - public void changeIccPin2(String oldPin2, String newPin2, Message result) { - } - - @Override - public void changeIccPin2ForApp(String oldPin2, String newPin2, String aidPtr, Message result) { - } - - @Override - public void changeBarringPassword(String facility, String oldPwd, String newPwd, - Message result) { - } - - @Override - public void supplyNetworkDepersonalization(String netpin, Message result) { - } - - @Override - public void getCurrentCalls(Message result) { - } - - @Override - public void getPDPContextList(Message result) { - } - - @Override - public void getDataCallList(Message result) { - } - - @Override - public void dial(String address, int clirMode, Message result) { - } - - @Override - public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) { - } - - @Override - public void getIMSI(Message result) { - } - - @Override - public void getIMEI(Message result) { - } - - @Override - public void getIMEISV(Message result) { - } - - @Override - public void hangupConnection(int gsmIndex, Message result) { - } - - @Override - public void hangupWaitingOrBackground(Message result) { - } - - @Override - public void hangupForegroundResumeBackground(Message result) { - } - - @Override - public void switchWaitingOrHoldingAndActive(Message result) { - } - - @Override - public void conference(Message result) { - } - - @Override - public void setPreferredVoicePrivacy(boolean enable, Message result) { - } - - @Override - public void getPreferredVoicePrivacy(Message result) { - } - - @Override - public void separateConnection(int gsmIndex, Message result) { - } - - @Override - public void acceptCall(Message result) { - } - - @Override - public void rejectCall(Message result) { - } - - @Override - public void explicitCallTransfer(Message result) { - } - - @Override - public void getLastCallFailCause(Message result) { - } - - @Override - public void getLastPdpFailCause(Message result) { - } - - @Override - public void getLastDataCallFailCause(Message result) { - } - - @Override - public void setMute(boolean enableMute, Message response) { - } - - @Override - public void getMute(Message response) { - } - - @Override - public void getSignalStrength(Message response) { - } - - @Override - public void getVoiceRegistrationState(Message response) { - } - - @Override - public void getDataRegistrationState(Message response) { - } - - @Override - public void getOperator(Message response) { - } - - @Override - public void sendDtmf(char c, Message result) { - } - - @Override - public void startDtmf(char c, Message result) { - } - - @Override - public void stopDtmf(Message result) { - } - - @Override - public void sendBurstDtmf(String dtmfString, int on, int off, Message result) { - } - - @Override - public void sendSMS(String smscPDU, String pdu, Message response) { - } - - @Override - public void sendSMSExpectMore(String smscPDU, String pdu, Message response) { - } - - @Override - public void sendCdmaSms(byte[] pdu, Message response) { - } - - @Override - public void sendImsGsmSms (String smscPDU, String pdu, - int retry, int messageRef, Message response) { - } - - @Override - public void sendImsCdmaSms(byte[] pdu, int retry, int messageRef, - Message response) { - } - - @Override - public void deleteSmsOnSim(int index, Message response) { - } - - @Override - public void deleteSmsOnRuim(int index, Message response) { - } - - @Override - public void writeSmsToSim(int status, String smsc, String pdu, Message response) { - } - - @Override - public void writeSmsToRuim(int status, byte[] pdu, Message response) { - } - - @Override - public void setRadioPower(boolean on, Message response) { - } - - @Override - public void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message response) { - } - - @Override - public void iccIO(int command, int fileid, String path, int p1, int p2, int p3, String data, - String pin2, Message response) { - } - - @Override - public void queryCLIP(Message response) { - } - - @Override - public void getCLIR(Message response) { - } - - @Override - public void setCLIR(int clirMode, Message response) { - } - - @Override - public void queryCallWaiting(int serviceClass, Message response) { - } - - @Override - public void setCallWaiting(boolean enable, int serviceClass, Message response) { - } - - @Override - public void setCallForward(int action, int cfReason, int serviceClass, String number, - int timeSeconds, Message response) { - } - - @Override - public void queryCallForwardStatus(int cfReason, int serviceClass, String number, - Message response) { - } - - @Override - public void setNetworkSelectionModeAutomatic(Message response) { - } - - @Override - public void setNetworkSelectionModeManual(String operatorNumeric, Message response) { - } - - @Override - public void getNetworkSelectionMode(Message response) { - } - - @Override - public void getAvailableNetworks(Message response) { - } - - @Override - public void getBasebandVersion(Message response) { - } - - @Override - public void queryFacilityLock(String facility, String password, int serviceClass, - Message response) { - } - - @Override - public void queryFacilityLockForApp(String facility, String password, int serviceClass, - String appId, Message response) { - } - - @Override - public void setFacilityLock(String facility, boolean lockState, String password, - int serviceClass, Message response) { - } - - @Override - public void setFacilityLockForApp(String facility, boolean lockState, String password, - int serviceClass, String appId, Message response) { - } - - @Override - public void sendUSSD(String ussdString, Message response) { - } - - @Override - public void cancelPendingUssd(Message response) { - } - - @Override - public void resetRadio(Message result) { - } - - @Override - public void setBandMode(int bandMode, Message response) { - } - - @Override - public void queryAvailableBandMode(Message response) { - } - - @Override - public void setPreferredNetworkType(int networkType, Message response) { - } - - @Override - public void getPreferredNetworkType(Message response) { - } - - @Override - public void setLocationUpdates(boolean enable, Message response) { - } - - @Override - public void getSmscAddress(Message result) { - } - - @Override - public void setSmscAddress(String address, Message result) { - } - - @Override - public void reportSmsMemoryStatus(boolean available, Message result) { - } - - @Override - public void reportStkServiceIsRunning(Message result) { - } - - @Override - public void invokeOemRilRequestRaw(byte[] data, Message response) { - } - - @Override - public void invokeOemRilRequestStrings(String[] strings, Message response) { - } - - @Override - public void sendTerminalResponse(String contents, Message response) { - } - - @Override - public void sendEnvelope(String contents, Message response) { - } - - @Override - public void handleCallSetupRequestFromSim(boolean accept, Message response) { - } - - @Override - public void setGsmBroadcastActivation(boolean activate, Message result) { - } - - @Override - public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) { - } - - @Override - public void getGsmBroadcastConfig(Message response) { - } - - @Override - public void getDeviceIdentity(Message response) { - } - - @Override - public void getCDMASubscription(Message response) { - } - - @Override - public void getImsRegistrationState (Message result) { - } - - @Override - public void sendCDMAFeatureCode(String FeatureCode, Message response) { - } - - @Override - public void setPhoneType(int phoneType) { - } - - @Override - public void queryCdmaRoamingPreference(Message response) { - } - - @Override - public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { - } - - @Override - public void setCdmaSubscriptionSource(int cdmaSubscriptionType, Message response) { - } - - @Override - public void getCdmaSubscriptionSource(Message response) { - } - - @Override - public void setTTYMode(int ttyMode, Message response) { - } - - @Override - public void queryTTYMode(Message response) { - } - - @Override - public void setupDataCall(String radioTechnology, String profile, String apn, String user, - String password, String authType, String protocol, Message result) { - } - - @Override - public void deactivateDataCall(int cid, int reason, Message result) { - } - - @Override - public void setCdmaBroadcastActivation(boolean activate, Message result) { - } - - @Override - public void setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs, Message response) { - } - - @Override - public void getCdmaBroadcastConfig(Message result) { - } - - @Override - public void exitEmergencyCallbackMode(Message response) { - } - - @Override - public void getIccCardStatus(Message result) { - } - - @Override - public void requestIsimAuthentication(String nonce, Message response) { - } - - @Override - public void requestIccSimAuthentication(String data, Message response) { - } - - @Override - public void getVoiceRadioTechnology(Message response) { - } - - @Override - public void getCellInfoList(Message result) { - } - - @Override - public void setCellInfoListRate(int rateInMillis, Message response) { - } - - @Override - public void setInitialAttachApn(String apn, String protocol, int authType, String username, - String password, Message result) { - } - - @Override - public void setDataProfile(DataProfile[] dps, Message result) { - } - - @Override - public void getIMSIForApp(String aid, Message result) { - } - - @Override - public void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3, - String data, String pin2, String aid, Message response) { - } - - @Override - public void iccOpenLogicalChannel(String AID, Message response) { - } - - @Override - public void iccCloseLogicalChannel(int channel, Message response) { - } - - @Override - public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, - int p1, int p2, int p3, String data, Message response) { - } - - @Override - public void iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, - int p3, String data, Message response) { - } - - @Override - public void nvReadItem(int itemID, Message response) { - } - - @Override - public void nvWriteItem(int itemID, String itemValue, Message response) { - } - - @Override - public void nvWriteCdmaPrl(byte[] preferredRoamingList, Message response) { - } - - @Override - public void nvResetConfig(int resetType, Message response) { - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken deleted file mode 100644 index 9fbb86c264..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadTest.java.broken +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2011 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.gsm; - -import android.os.HandlerThread; -import android.test.AndroidTestCase; -import com.android.telephony.Rlog; - -import java.nio.charset.Charset; - -/** - * Test SMS-PP data download to UICC. - * Uses test messages from 3GPP TS 31.124 section 27.22.5. - */ -public class UsimDataDownloadTest extends AndroidTestCase { - private static final String TAG = "UsimDataDownloadTest"; - - class TestHandlerThread extends HandlerThread { - private UsimDataDownloadHandler mHandler; - - TestHandlerThread() { - super("TestHandlerThread"); - } - - @Override - protected void onLooperPrepared() { - synchronized (this) { - mHandler = new UsimDataDownloadHandler(mCi, 0); - notifyAll(); - } - } - - UsimDataDownloadHandler getHandler() { - synchronized (this) { - while (mHandler == null) { - try { - wait(); - } catch (InterruptedException ignored) {} - } - return mHandler; - } - } - } - - private UsimDataDownloadCommands mCi; - private TestHandlerThread mHandlerThread; - UsimDataDownloadHandler mHandler; - - @Override - protected void setUp() throws Exception { - super.setUp(); - mCi = new UsimDataDownloadCommands(mContext); - mHandlerThread = new TestHandlerThread(); - mHandlerThread.start(); - mHandler = mHandlerThread.getHandler(); - Rlog.d(TAG, "mHandler is constructed"); - } - - @Override - protected void tearDown() throws Exception { - mHandlerThread.quit(); - super.tearDown(); - } - - // SMS-PP Message 3.1.1 - private static final byte[] SMS_PP_MESSAGE_3_1_1 = { - // Service center address - 0x09, (byte) 0x91, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0xf8, - - 0x04, 0x04, (byte) 0x91, 0x21, 0x43, 0x7f, 0x16, (byte) 0x89, 0x10, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x0d, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x20, 0x31 - }; - - // SMS-PP Download Envelope 3.1.1 - private static final String SMS_PP_ENVELOPE_3_1_1 = "d12d8202838106099111223344556677f88b1c04" - + "049121437f16891010000000000d546573744d6573736167652031"; - - // SMS-PP Message 3.1.5 - private static final byte[] SMS_PP_MESSAGE_3_1_5 = { - // Service center address - 0x09, (byte) 0x91, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0xf8, - - 0x44, 0x04, (byte) 0x91, 0x21, 0x43, 0x7f, (byte) 0xf6, (byte) 0x89, 0x10, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x1e, 0x02, 0x70, 0x00, 0x00, 0x19, 0x00, 0x0d, 0x00, 0x00, - 0x00, 0x00, (byte) 0xbf, (byte) 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, - (byte) 0xdc, (byte) 0xdc, (byte) 0xdc, (byte) 0xdc - }; - - // SMS-PP Download Envelope 3.1.5 - private static final String SMS_PP_ENVELOPE_3_1_5 = "d13e8202838106099111223344556677f88b2d44" - + "049121437ff6891010000000001e0270000019000d00000000bfff00000000000100" - + "dcdcdcdcdcdcdcdcdcdc"; - - public void testDataDownloadMessage1() { - SmsMessage message = SmsMessage.createFromPdu(SMS_PP_MESSAGE_3_1_1); - assertTrue("message is SMS-PP data download", message.isUsimDataDownload()); - - mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x90, 0x00, ""); - mCi.expectAcknowledgeGsmSms(true, 0); - mHandler.startDataDownload(message); - mCi.assertExpectedMethodsCalled(); - - mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x90, 0x00, "0123456789"); - mCi.expectAcknowledgeGsmSmsWithPdu(true, "00077f16050123456789"); - mHandler.startDataDownload(message); - mCi.assertExpectedMethodsCalled(); - - mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_1, 0x62, 0xff, "0123456789abcdef"); - mCi.expectAcknowledgeGsmSmsWithPdu(false, "00d5077f16080123456789abcdef"); - mHandler.startDataDownload(message); - mCi.assertExpectedMethodsCalled(); - } - - public void testDataDownloadMessage5() { - SmsMessage message = SmsMessage.createFromPdu(SMS_PP_MESSAGE_3_1_5); - assertTrue("message is SMS-PP data download", message.isUsimDataDownload()); - - mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_5, 0x90, 0x00, "9876543210"); - mCi.expectAcknowledgeGsmSmsWithPdu(true, "00077ff6059876543210"); - mHandler.startDataDownload(message); - mCi.assertExpectedMethodsCalled(); - - mCi.expectSendEnvelope(SMS_PP_ENVELOPE_3_1_5, 0x93, 0x00, ""); - mCi.expectAcknowledgeGsmSms(false, 0xd4); // SIM toolkit busy - mHandler.startDataDownload(message); - mCi.assertExpectedMethodsCalled(); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java index 111e5d2c5f..c26dd22842 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java @@ -25,11 +25,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL; import static com.android.internal.telephony.data.LinkBandwidthEstimator.NUM_SIGNAL_LEVEL; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME; -import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS; import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6; import static org.junit.Assert.assertArrayEquals; @@ -89,6 +84,11 @@ import java.util.ArrayList; import java.util.Arrays; public class TelephonyMetricsTest extends TelephonyTest { + private static final String FAKE_ADDRESS = "99.88.77.66"; + private static final String FAKE_DNS = "55.66.77.88"; + private static final String FAKE_GATEWAY = "11.22.33.44"; + private static final String FAKE_IFNAME = "FAKE IFNAME"; + private static final String FAKE_PCSCF_ADDRESS = "22.33.44.55"; // Mocked classes private ImsCallSession mImsCallSession; private ServiceState mServiceState; diff --git a/tools/tdi b/tools/tdi deleted file mode 100755 index 940a83bccc..0000000000 --- a/tools/tdi +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -# Telephony Debug Intents -#set -x - -file_name='tdi' - -# Get the command as the first parameter -cmd=$1 -shift - -function dc_errors() -{ - if [ "$1" == "" ]; then - echo "Usage: $file_name $cmd " - echo " must specifiy the DataConnection such as DC or GsmDC-1" - echo " := number of times to retry" - echo " := From DataConnection.FailCause; such as -3 for SIGNAL_LOST" - echo " := suggested retry time in milli-seconds" - exit - fi - the_DC=$1 - echo "the_DC=$the_DC" - - if [ "$2" != "" ]; then - counter="--ei counter $2"; - fi - echo "counter=$counter" - - if [ "$3" != "" ]; then - fail_cause="--ei fail_cause $3"; - fi - echo "fail_cause=$fail_cause" - - if [ "$4" != "" ]; then - suggested_retry_time="--ei suggested_retry_time $4"; - fi - echo "suggested_retry_time=$suggested_retry_time" - - - adb shell am broadcast -a com.android.internal.telephony.$the_DC.action_fail_bringup $counter $fail_cause $suggested_retry_time -} - - -case ${cmd} in - dce) dc_errors "$@";; - # Add more commands in the future - *) echo 'Broadcast telephony debug intents'; echo 'usage: tdi [dce]'; echo ' dce=DC errors';; -esac -- GitLab From b902b0ed0fb8c51f00d02077b72dabfcbd0decbd Mon Sep 17 00:00:00 2001 From: Rambo Wang Date: Wed, 14 Sep 2022 16:25:05 +0000 Subject: [PATCH 089/656] Disable signal strength reporting when threshold is empty This change optimizes scenarios that when the signal threshold is empty, the SignalThresholdInfo is disabled before setting signal strength reporting criteria to modem. The issue can reproduce with fulfill of both of the conditions below: - Device is in idle mode - A customized SignalStrengthUpdateRequest was set with shouldReportWhileIdle to true and shouldReportSystemWhileIdle to false. In above scenario, the system signal thresholds which were not set by client may leave with empty threshold and enabled. The optimization here makes sure only the client's non-empty threshold is enabled. Bug: 245658506 Test: atest SignalStrengthControllerTest Test: feature regress test (go/signalstrength-s-ft) Change-Id: I22dceb4a3f34274942ca9a278d657c6d2263160c --- .../telephony/SignalStrengthController.java | 11 ++- .../SignalStrengthControllerTest.java | 98 ++++++++++++++++++- .../internal/telephony/SimulatedCommands.java | 3 + 3 files changed, 106 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/SignalStrengthController.java b/src/java/com/android/internal/telephony/SignalStrengthController.java index a4c92f4801..d950a9df68 100644 --- a/src/java/com/android/internal/telephony/SignalStrengthController.java +++ b/src/java/com/android/internal/telephony/SignalStrengthController.java @@ -558,12 +558,13 @@ public class SignalStrengthController extends Handler { for (SignalThresholdInfo signalThresholdInfo : signalThresholdInfos) { final int ran = signalThresholdInfo.getRadioAccessNetworkType(); final int measurementType = signalThresholdInfo.getSignalMeasurementType(); - final boolean isEnabledForSystem = signalThresholdInfo.isEnabled(); + final boolean isEnabledForSystem = + signalThresholdInfo.isEnabled() && shouldHonorSystemThresholds(); int[] consolidatedThresholds = getConsolidatedSignalThresholds( ran, measurementType, - isEnabledForSystem && shouldHonorSystemThresholds() + isEnabledForSystem ? signalThresholdInfo.getThresholds() : new int[]{}, ALIGNMENT_HYSTERESIS_DB); @@ -737,7 +738,11 @@ public class SignalStrengthController extends Handler { && srr.mRequest.isSystemThresholdReportingRequestedWhileIdle()); } - void onDeviceIdleStateChanged(boolean isDeviceIdle) { + /** + * Get notified when device idle state changed + */ + @VisibleForTesting + public void onDeviceIdleStateChanged(boolean isDeviceIdle) { sendMessage(obtainMessage(EVENT_ON_DEVICE_IDLE_STATE_CHANGED, isDeviceIdle)); localLog("onDeviceIdleStateChanged isDeviceIdle=" + isDeviceIdle); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java index 583c22b2cd..50a1b96c16 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR; @@ -24,6 +25,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -48,10 +51,13 @@ import android.test.suitebuilder.annotation.MediumTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import com.android.internal.util.ArrayUtils; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import java.util.ArrayList; @@ -59,12 +65,11 @@ import java.util.List; import java.util.Map; /** - * Unit test for {@link SignalStrengthUpdateRequest}. + * Unit test for {@link SignalStrengthController}. */ @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class SignalStrengthControllerTest extends TelephonyTest { - private static final String TAG = "SignalStrengthControllerTest"; private static final int ACTIVE_SUB_ID = 0; @@ -91,19 +96,43 @@ public class SignalStrengthControllerTest extends TelephonyTest { public void setUp() throws Exception { super.setUp(this.getClass().getSimpleName()); mHandler = Mockito.mock(Handler.class); + when(mPhone.getSubId()).thenReturn(ACTIVE_SUB_ID); mSsc = new SignalStrengthController(mPhone); replaceInstance(Handler.class, "mLooper", mHandler, mSsc.getLooper()); replaceInstance(Phone.class, "mLooper", mPhone, mSsc.getLooper()); + // Config a fixed supported RAN/MeasurementTypes to make the test more stable mBundle = mContextFixture.getCarrierConfigBundle(); + // Support GERAN with RSSI + mBundle.putIntArray(CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY, + new int[] { + -109, /* SIGNAL_STRENGTH_POOR */ + -103, /* SIGNAL_STRENGTH_MODERATE */ + -97, /* SIGNAL_STRENGTH_GOOD */ + -89, /* SIGNAL_STRENGTH_GREAT */ + }); + // Support EUTRAN with RSRP + mBundle.putInt(CarrierConfigManager.KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT, + 1 /* USE_RSRP */); + mBundle.putIntArray(CarrierConfigManager.KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY, + new int[] { + -115, /* SIGNAL_STRENGTH_POOR */ + -105, /* SIGNAL_STRENGTH_MODERATE */ + -95, /* SIGNAL_STRENGTH_GOOD */ + -85, /* SIGNAL_STRENGTH_GREAT */ + }); + // Support NR with SSRSRP + mBundle.putInt(CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, + 1 /* USE_SSRSRP */); mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY, new int[] { -110, /* SIGNAL_STRENGTH_POOR */ -90, /* SIGNAL_STRENGTH_MODERATE */ -80, /* SIGNAL_STRENGTH_GOOD */ - -65, /* SIGNAL_STRENGTH_GREAT */ + -64, /* SIGNAL_STRENGTH_GREAT */ }); + // By default, NR with SSRSRQ and SSSINR is not supported mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY, new int[] { -31, /* SIGNAL_STRENGTH_POOR */ @@ -119,6 +148,7 @@ public class SignalStrengthControllerTest extends TelephonyTest { 30 /* SIGNAL_STRENGTH_GREAT */ }); processAllMessages(); + reset(mSimulatedCommandsVerifier); } @After @@ -654,6 +684,68 @@ public class SignalStrengthControllerTest extends TelephonyTest { assertEquals(mSsc.getSignalStrength().getLevel(), CellSignalStrength.SIGNAL_STRENGTH_GOOD); } + /** + * Verify on both high-power and idle modes. All SignalThresholdInfo should be disabled if the + * threshold array is empty when calling CI#setSignalStrengthReportingCriteria. + */ + @Test + public void consolidateAndSetReportingCriteria_allEmptyThresholdShouldBeDisabled() { + // Firstly, test on high-power mode + when(mPhone.isDeviceIdle()).thenReturn(false); + SignalThresholdInfo info = new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) + .setSignalMeasurementType(SIGNAL_MEASUREMENT_TYPE_RSRP) + .setThresholds(new int[]{-112}, true /* isSystem */) + .build(); + SignalStrengthUpdateRequest request = createTestSignalStrengthUpdateRequest( + info, + true /* shouldReportWhileIdle*/, + false /* shouldReportSystemWhileIdle */ + ); + + mSsc.setSignalStrengthUpdateRequest(ACTIVE_SUB_ID, CALLING_UID, + request, Message.obtain(mHandler)); + processAllMessages(); + + // Expect 3 non-empty thresholds (GERAN/RSSI, EUTRAN/RSRP, NR/SSRSRP) + // if Radio HAL ver is >= 1.5 + verifyAllEmptyThresholdAreDisabledWhenSetSignalStrengthReportingCriteria( + 3 /*expectedNonEmptyThreshold*/); + + // Then, test when device turns into idle mode in which all system thresholds are emptied + // (shouldReportSystemWhileIdle is false) + reset(mSimulatedCommandsVerifier); + when(mPhone.isDeviceIdle()).thenReturn(true); + mSsc.onDeviceIdleStateChanged(true /* isDeviceIdle */); + processAllMessages(); + + // Expect 1 non-empty threshold left (EUTRAN/RSRP set by the SignalStrengthUpdateRequest) + verifyAllEmptyThresholdAreDisabledWhenSetSignalStrengthReportingCriteria( + 1 /*expectedNonEmptyThreshold*/); + } + + private void verifyAllEmptyThresholdAreDisabledWhenSetSignalStrengthReportingCriteria( + int expectedNonEmptyThreshold) { + ArgumentCaptor> signalThresholdInfoCaptor = + ArgumentCaptor.forClass(List.class); + verify(mSimulatedCommandsVerifier).setSignalStrengthReportingCriteria( + signalThresholdInfoCaptor.capture(), isNull()); + List capturedInfos = signalThresholdInfoCaptor.getAllValues().get(0); + assertThat(capturedInfos).isNotEmpty(); + int actualNonEmptyThreshold = 0; + for (SignalThresholdInfo signalThresholdInfo: capturedInfos) { + if (ArrayUtils.isEmpty(signalThresholdInfo.getThresholds())) { + assertThat(signalThresholdInfo.isEnabled()).isFalse(); + } else { + actualNonEmptyThreshold++; + } + } + // Only check on RADIO hal 1.5 and above to make it less flaky + if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { + assertThat(expectedNonEmptyThreshold).isEqualTo(actualNonEmptyThreshold); + } + } + private void sendCarrierConfigUpdate() { CarrierConfigManager mockConfigManager = Mockito.mock(CarrierConfigManager.class); when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index 0f7e333071..6e6d44e2a1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -2420,6 +2420,9 @@ public class SimulatedCommands extends BaseCommands @Override public void setSignalStrengthReportingCriteria(List signalThresholdInfos, Message result) { + SimulatedCommandsVerifier.getInstance().setSignalStrengthReportingCriteria( + signalThresholdInfos, result); + resultSuccess(result, null); } @Override -- GitLab From ffb9f286a89112cb182ea00a808eeffd6f59e85f Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 13 Sep 2022 14:09:34 -0700 Subject: [PATCH 090/656] Add auto_data_switch_availability_stability_time_threshold to control auto data switch Bug: 244064524 Test: reviewed bugreport to check the flag is loaded on device Change-Id: Id513a509b181ee3e991f2ebc7ddbb5d65375fce7 --- .../telephony/data/PhoneSwitcher.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 6370c21bad..cd81b0cb2e 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -53,6 +53,7 @@ import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; +import android.provider.DeviceConfig; import android.telephony.CarrierConfigManager; import android.telephony.PhoneCapability; import android.telephony.PhoneStateListener; @@ -65,6 +66,7 @@ import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RegistrationManager; import android.telephony.ims.stub.ImsRegistrationImplBase; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.LocalLog; @@ -109,6 +111,9 @@ import java.util.concurrent.CompletableFuture; */ public class PhoneSwitcher extends Handler { private static final String LOG_TAG = "PhoneSwitcher"; + /** DeviceConfig key of the time threshold in ms for defining a network status to be stable. **/ + private static final String KEY_AUTO_DATA_SWITCH_AVAILABILITY_STABILITY_TIME_THRESHOLD = + "auto_data_switch_availability_stability_time_threshold"; protected static final boolean VDBG = false; private static final int DEFAULT_NETWORK_CHANGE_TIMEOUT_MS = 5000; @@ -294,6 +299,7 @@ public class PhoneSwitcher extends Handler { private static final int EVENT_PROCESS_SIM_STATE_CHANGE = 119; @VisibleForTesting public static final int EVENT_IMS_RADIO_TECH_CHANGED = 120; + public static final int EVENT_DEVICE_CONFIG_CHANGED = 121; // List of events triggers re-evaluations private static final String EVALUATION_REASON_RADIO_ON = "EVENT_RADIO_ON"; @@ -320,6 +326,13 @@ public class PhoneSwitcher extends Handler { private List> mCurrentDdsSwitchFailure; + /** + * Time threshold in ms to define a internet connection status to be stable(e.g. out of service, + * in service, wifi is the default active network.etc), while -1 indicates auto switch + * feature disabled. + */ + private long mAutoDataSwitchAvailabilityStabilityTimeThreshold = -1; + /** Data settings manager callback. Key is the phone id. */ private final @NonNull Map mDataSettingsManagerCallbacks = new ArrayMap<>(); @@ -569,6 +582,17 @@ public class PhoneSwitcher extends Handler { // we want to see all requests networkFactory.registerIgnoringScore(); + // Register for device config update + DeviceConfig.addOnPropertiesChangedListener( + DeviceConfig.NAMESPACE_TELEPHONY, this::post, + properties -> { + if (TextUtils.equals(DeviceConfig.NAMESPACE_TELEPHONY, + properties.getNamespace())) { + sendEmptyMessage(EVENT_DEVICE_CONFIG_CHANGED); + } + }); + updateDeviceConfig(); + updateHalCommandToUse(); log("PhoneSwitcher started"); @@ -840,9 +864,23 @@ public class PhoneSwitcher extends Handler { } break; } + case EVENT_DEVICE_CONFIG_CHANGED: { + updateDeviceConfig(); + break; + } } } + /** Update local properties from {@link DeviceConfig} */ + private void updateDeviceConfig() { + DeviceConfig.Properties properties = //read all telephony properties + DeviceConfig.getProperties(DeviceConfig.NAMESPACE_TELEPHONY); + + mAutoDataSwitchAvailabilityStabilityTimeThreshold = properties.getInt( + KEY_AUTO_DATA_SWITCH_AVAILABILITY_STABILITY_TIME_THRESHOLD, -1); + + } + private synchronized void onMultiSimConfigChanged(int activeModemCount) { // No change. if (mActiveModemCount == activeModemCount) return; @@ -1701,6 +1739,8 @@ public class PhoneSwitcher extends Handler { pw.println("mActiveModemCount=" + mActiveModemCount); pw.println("mPhoneIdInVoiceCall=" + mPhoneIdInVoiceCall); pw.println("mCurrentDdsSwitchFailure=" + mCurrentDdsSwitchFailure); + pw.println("mAutoDataSwitchAvailabilityStabilityTimeThreshold=" + + mAutoDataSwitchAvailabilityStabilityTimeThreshold); pw.println("Local logs:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); -- GitLab From 26c630f3c47fff0ef094ad74bef3d4f894f10487 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 14 Sep 2022 00:45:15 -0700 Subject: [PATCH 091/656] Added builder for SubscriptionInfo Added the builder for SubscriptionInfo, and make all members final. This can prevent other clients accidentally modifying the same copy of SubscriptionInfo. Also moved getAllAccessRules into getAccessRules. Bug: 239607619 Bug: 247140269 Test: Manual + atest SubscriptionInfoTest Change-Id: I820d4753811910e6a0561ec99f83e8837ce40054 --- .../telephony/SubscriptionController.java | 181 +++++++++--------- .../telephony/FakeTelephonyProvider.java | 1 + .../internal/telephony/GsmCdmaPhoneTest.java | 21 +- .../MultiSimSettingControllerTest.java | 60 +++--- .../telephony/SubscriptionInfoTest.java | 102 +++++----- .../SubscriptionInfoUpdaterTest.java | 37 ++-- .../telephony/euicc/EuiccControllerTest.java | 43 +++-- 7 files changed, 232 insertions(+), 213 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index f1f650348c..bc5577a639 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -513,33 +513,34 @@ public class SubscriptionController extends ISub.Stub { /** * New SubInfoRecord instance and fill in detail info - * @param cursor + * @param cursor The database cursor * @return the query result of desired SubInfoRecord */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private SubscriptionInfo getSubInfoRecord(Cursor cursor) { + SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder(); int id = cursor.getInt(cursor.getColumnIndexOrThrow( SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID)); - String iccId = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.ICC_ID)); - int simSlotIndex = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.SIM_SLOT_INDEX)); - String displayName = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.DISPLAY_NAME)); - String carrierName = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.CARRIER_NAME)); - int nameSource = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.NAME_SOURCE)); - int iconTint = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.HUE)); - String number = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.NUMBER)); - int dataRoaming = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.DATA_ROAMING)); - String mcc = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.MCC_STRING)); - String mnc = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.MNC_STRING)); + builder.setId(id) + .setIccId(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.ICC_ID))) + .setSimSlotIndex(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.SIM_SLOT_INDEX))) + .setDisplayName(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.DISPLAY_NAME))) + .setCarrierName(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.CARRIER_NAME))) + .setNameSource(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.NAME_SOURCE))) + .setIconTint(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.HUE))) + .setDataRoaming(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.DATA_ROAMING))) + .setMcc(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.MCC_STRING))) + .setMnc(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.MNC_STRING))); + String ehplmnsRaw = cursor.getString(cursor.getColumnIndexOrThrow( SubscriptionManager.EHPLMNS)); String hplmnsRaw = cursor.getString(cursor.getColumnIndexOrThrow( @@ -547,77 +548,63 @@ public class SubscriptionController extends ISub.Stub { String[] ehplmns = ehplmnsRaw == null ? null : ehplmnsRaw.split(","); String[] hplmns = hplmnsRaw == null ? null : hplmnsRaw.split(","); - // cardId is the private ICCID/EID string, also known as the card string - String cardId = cursor.getString(cursor.getColumnIndexOrThrow( + builder.setEhplmns(ehplmns).setHplmns(hplmns); + + + // CARD_ID is the private ICCID/EID string, also known as the card string + String cardString = cursor.getString(cursor.getColumnIndexOrThrow( SubscriptionManager.CARD_ID)); - String countryIso = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.ISO_COUNTRY_CODE)); + builder.setCardString(cardString); // publicCardId is the publicly exposed int card ID - int publicCardId = mUiccController.convertToPublicCardId(cardId); + int publicCardId = mUiccController.convertToPublicCardId(cardString); + builder.setCardId(publicCardId); + + builder.setCountryIso(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.ISO_COUNTRY_CODE))) + .setCarrierId(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.CARRIER_ID))); + boolean isEmbedded = cursor.getInt(cursor.getColumnIndexOrThrow( SubscriptionManager.IS_EMBEDDED)) == 1; - int carrierId = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.CARRIER_ID)); - UiccAccessRule[] accessRules; + builder.setEmbedded(isEmbedded); if (isEmbedded) { - accessRules = UiccAccessRule.decodeRules(cursor.getBlob( - cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES))); - } else { - accessRules = null; - } - UiccAccessRule[] carrierConfigAccessRules = UiccAccessRule.decodeRules(cursor.getBlob( - cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS))); - boolean isOpportunistic = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.IS_OPPORTUNISTIC)) == 1; - String groupUUID = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.GROUP_UUID)); - int profileClass = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.PROFILE_CLASS)); - int portIndex = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.PORT_INDEX)); - int subType = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.SUBSCRIPTION_TYPE)); - String groupOwner = getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER, - /*defaultVal*/ null); - boolean areUiccApplicationsEnabled = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.UICC_APPLICATIONS_ENABLED)) == 1; - - int usageSetting = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.USAGE_SETTING)); - - if (VDBG) { - String iccIdToPrint = SubscriptionInfo.givePrintableIccid(iccId); - String cardIdToPrint = SubscriptionInfo.givePrintableIccid(cardId); - logd("[getSubInfoRecord] id:" + id + " iccid:" + iccIdToPrint + " simSlotIndex:" - + simSlotIndex + " carrierid:" + carrierId + " displayName:" + displayName - + " nameSource:" + nameSource + " iconTint:" + iconTint - + " dataRoaming:" + dataRoaming + " mcc:" + mcc + " mnc:" + mnc - + " countIso:" + countryIso + " isEmbedded:" - + isEmbedded + " accessRules:" + Arrays.toString(accessRules) - + " carrierConfigAccessRules: " + Arrays.toString(carrierConfigAccessRules) - + " cardId:" + cardIdToPrint + " portIndex:" + portIndex - + " publicCardId:" + publicCardId - + " isOpportunistic:" + isOpportunistic + " groupUUID:" + groupUUID - + " profileClass:" + profileClass + " subscriptionType: " + subType - + " areUiccApplicationsEnabled: " + areUiccApplicationsEnabled - + " usageSetting: " + usageSetting); - } + builder.setNativeAccessRules(UiccAccessRule.decodeRules(cursor.getBlob( + cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES)))); + } + + builder.setCarrierConfigAccessRules(UiccAccessRule.decodeRules(cursor.getBlob( + cursor.getColumnIndexOrThrow( + SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS)))) + .setOpportunistic(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.IS_OPPORTUNISTIC)) == 1) + .setGroupUuid(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.GROUP_UUID))) + .setProfileClass(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.PROFILE_CLASS))) + .setPortIndex(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.PORT_INDEX))) + .setType(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.SUBSCRIPTION_TYPE))) + .setGroupOwner(getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER, + /*defaultVal*/ null)) + .setUiccApplicationsEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.UICC_APPLICATIONS_ENABLED)) == 1) + .setUsageSetting(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.USAGE_SETTING))); // If line1number has been set to a different number, use it instead. + String number = cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.NUMBER)); String line1Number = mTelephonyManager.getLine1Number(id); if (!TextUtils.isEmpty(line1Number) && !line1Number.equals(number)) { number = line1Number; } + builder.setNumber(number); + // FIXME(b/210771052): constructing a complete SubscriptionInfo requires a port index, // but the port index isn't available here. Should it actually be part of SubscriptionInfo? - SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName, - carrierName, nameSource, iconTint, number, dataRoaming, /* icon= */ null, - mcc, mnc, countryIso, isEmbedded, accessRules, cardId, publicCardId, - isOpportunistic, groupUUID, /* isGroupDisabled= */ false , carrierId, profileClass, - subType, groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled, - portIndex, usageSetting); - info.setAssociatedPlmns(ehplmns, hplmns); - return info; + + return builder.build(); } private String getOptionalStringFromCursor(Cursor cursor, String column, String defaultVal) { @@ -3149,8 +3136,8 @@ public class SubscriptionController extends ISub.Stub { /** * Get the SIM state for the slot index. - * For Remote-SIMs, this method returns {@link #IccCardConstants.State.UNKNOWN} - * @return SIM state as the ordinal of {@See IccCardConstants.State} + * For Remote-SIMs, this method returns {@link IccCardConstants.State#UNKNOWN} + * @return SIM state as the ordinal of {@link IccCardConstants.State} */ @Override public int getSimStateForSlotIndex(int slotIndex) { @@ -4119,7 +4106,10 @@ public class SubscriptionController extends ISub.Stub { } // Can't find the existing SIM. - if (slotInfo == null) return false; + if (slotInfo == null) { + loge("Can't find the existing SIM."); + return false; + } // this for physical slot which has only one port if (enable && !slotInfo.getPorts().stream().findFirst().get().isActive()) { @@ -4369,16 +4359,16 @@ public class SubscriptionController extends ISub.Stub { if (hasIdentifierAccess && hasPhoneNumberAccess) { return subInfo; } - SubscriptionInfo result = new SubscriptionInfo(subInfo); + SubscriptionInfo.Builder result = new SubscriptionInfo.Builder(subInfo); if (!hasIdentifierAccess) { - result.clearIccId(); - result.clearCardString(); - result.clearGroupUuid(); + result.setIccId(null); + result.setCardString(null); + result.setGroupUuid(null); } if (!hasPhoneNumberAccess) { - result.clearNumber(); + result.setNumber(null); } - return result; + return result.build(); } private synchronized boolean addToSubIdList(int slotIndex, int subId, int subscriptionType) { @@ -4453,20 +4443,23 @@ public class SubscriptionController extends ISub.Stub { mCacheOpportunisticSubInfoList = subList; - for (SubscriptionInfo info : mCacheOpportunisticSubInfoList) { + for (int i = 0; i < mCacheOpportunisticSubInfoList.size(); i++) { + SubscriptionInfo info = mCacheOpportunisticSubInfoList.get(i); if (shouldDisableSubGroup(info.getGroupUuid())) { - info.setGroupDisabled(true); + SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder(info); + builder.setGroupDisabled(true); + mCacheOpportunisticSubInfoList.set(i, builder.build()); } } if (DBG_CACHE) { if (!mCacheOpportunisticSubInfoList.isEmpty()) { for (SubscriptionInfo si : mCacheOpportunisticSubInfoList) { - logd("[refreshCachedOpptSubscriptionInfoList] Setting Cached info=" - + si); + logd("[refreshCachedOpportunisticSubscriptionInfoList] Setting Cached " + + "info=" + si); } } else { - logdl("[refreshCachedOpptSubscriptionInfoList]- no info return"); + logdl("[refreshCachedOpportunisticSubscriptionInfoList]- no info return"); } } @@ -4647,7 +4640,7 @@ public class SubscriptionController extends ISub.Stub { * Sets the phone number for the given {@code subId}. * *

The only accepted {@code source} is {@link - * SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER}. + * SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER}. */ @Override public void setPhoneNumber(int subId, int source, String number, diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java index 16e1c7a6e9..f1bba36a8b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java +++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java @@ -145,6 +145,7 @@ public class FakeTelephonyProvider extends MockContentProvider { @Override public Uri insert(Uri uri, ContentValues values) { + Log.d(TAG, "insert. values=" + values); SQLiteDatabase db = mDbHelper.getWritableDatabase(); long id = db.insert("siminfo", null, values); return ContentUris.withAppendedId(Telephony.SimInfo.CONTENT_URI, id); diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index d8d81a6d22..3b9667b123 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -1658,10 +1658,23 @@ public class GsmCdmaPhoneTest extends TelephonyTest { private SubscriptionInfo makeSubscriptionInfo(boolean isOpportunistic, int usageSetting) { - return new SubscriptionInfo( - 1, "xxxxxxxxx", 1, "Android Test", "Android Test", 0, 0, "8675309", 0, - null, "001", "01", "us", true, null, null, 0, isOpportunistic, null, false, - 1, 1, 0, null, null, true, 0, usageSetting); + return new SubscriptionInfo.Builder() + .setId(1) + .setIccId("xxxxxxxxx") + .setSimSlotIndex(1) + .setDisplayName("Android Test") + .setDisplayName("Android Test") + .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) + .setNumber("8675309") + .setMcc("001") + .setMnc("01") + .setCountryIso("us") + .setEmbedded(true) + .setOpportunistic(isOpportunistic) + .setCarrierId(1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING) + .setUsageSetting(usageSetting) + .build(); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index fb7b64db43..09493a18b0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -89,28 +89,38 @@ public class MultiSimSettingControllerTest extends TelephonyTest { private DataSettingsManager mDataSettingsManagerMock2; private CommandsInterface mMockCi; + private final SubscriptionInfo mSubInfo1 = new SubscriptionInfo.Builder() + .setId(1) + .setIccId("subInfo1 IccId") + .setSimSlotIndex(0) + .setDisplayName("T-mobile") + .setCarrierName("T-mobile") + .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) + .setIconTint(255) + .setNumber("12345") + .setMcc("310") + .setMnc("260") + .setCountryIso("us") + .build(); + + private final SubscriptionInfo mSubInfo2 = new SubscriptionInfo.Builder(mSubInfo1) + .setId(2) + .setIccId("subInfo2 IccId") + .setGroupUuid(mGroupUuid1.toString()) + .build(); + + private final SubscriptionInfo mSubInfo3 = new SubscriptionInfo.Builder(mSubInfo1) + .setId(3) + .setIccId("subInfo3 IccId") + .setGroupUuid(mGroupUuid1.toString()) + .build(); + + private final SubscriptionInfo mSubInfo4 = new SubscriptionInfo.Builder(mSubInfo1) + .setId(4) + .setIccId("subInfo4 IccId") + .setGroupUuid(mGroupUuid1.toString()) + .build(); - private final SubscriptionInfo mSubInfo1 = new SubscriptionInfo(1, "subInfo1 IccId", 0, - "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", - "156", false, null, null); - - private final SubscriptionInfo mSubInfo2 = new SubscriptionInfo(2, "subInfo2 IccId", 1, - "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", - "156", false, null, null, -1, false, mGroupUuid1.toString(), false, - TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true, -1); - - private final SubscriptionInfo mSubInfo3 = new SubscriptionInfo(3, "subInfo3 IccId", -1, - "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", - "156", false, null, null, -1, false, mGroupUuid1.toString(), false, - TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true, -1); - - private final SubscriptionInfo mSubInfo4 = new SubscriptionInfo(4, "subInfo4 IccId", -1, - "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", - "156", false, null, null, -1, false, mGroupUuid1.toString(), false, - TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true, -1); @Before public void setUp() throws Exception { @@ -615,7 +625,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { public void testGroupedCbrs() throws Exception { // Mark sub 1 as opportunistic. replaceInstance(SubscriptionInfo.class, "mIsOpportunistic", mSubInfo1, true); - replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); doReturn(true).when(mSubControllerMock).isOpportunistic(1); // Make opportunistic sub 1 and sub 2 data enabled. doReturn(true).when(mPhoneMock1).isUserDataEnabled(); @@ -657,7 +667,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @SmallTest public void testGroupedPrimaryRemoved() throws Exception { // Create subscription grouping of subs 1 and 2. - replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock) @@ -713,7 +723,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { processAllMessages(); // Create subscription grouping. - replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock) .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); @@ -933,7 +943,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { public void onSubscriptionGroupChanged_allActiveSubArePartOfGroup() throws Exception { doReturn(3).when(mSubControllerMock).getDefaultDataSubId(); // Create subscription grouping of subs 1 and 2. - replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 1, true); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java index 3f8543500f..7b1005998b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java @@ -15,12 +15,11 @@ */ package com.android.internal.telephony; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static com.google.common.truth.Truth.assertThat; import android.os.Parcel; import android.telephony.SubscriptionInfo; -import android.test.suitebuilder.annotation.SmallTest; +import android.telephony.SubscriptionManager; import org.junit.After; import org.junit.Before; @@ -38,78 +37,63 @@ public class SubscriptionInfoTest { @Before public void setUp() throws Exception { - mSubscriptionInfoUT = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, "T-mobile", - "T-mobile", 0, 255, "12345", 0, null, "310", "260", "156", false, null, null); - mSubscriptionInfoUT.setAssociatedPlmns(EHPLMNS, HPLMNS); + mSubscriptionInfoUT = new SubscriptionInfo.Builder() + .setId(1) + .setIccId("890126042XXXXXXXXXXX") + .setSimSlotIndex(0) + .setDisplayName("T-mobile") + .setCarrierName("T-mobile") + .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) + .setIconTint(255) + .setNumber("12345") + .setDataRoaming(SubscriptionManager.DATA_ROAMING_DISABLE) + .setMcc("310") + .setMnc("260") + .setEhplmns(EHPLMNS) + .setHplmns(HPLMNS) + .setCountryIso("us") + .build(); } @Test - @SmallTest public void testSubProperties() { - assertEquals(260, mSubscriptionInfoUT.getMnc()); - assertEquals(310, mSubscriptionInfoUT.getMcc()); - assertEquals("12345", mSubscriptionInfoUT.getNumber()); - assertEquals(0, mSubscriptionInfoUT.getDataRoaming()); - assertEquals("T-mobile", mSubscriptionInfoUT.getDisplayName()); - assertEquals("T-mobile", mSubscriptionInfoUT.getCarrierName()); - assertEquals("156", mSubscriptionInfoUT.getCountryIso()); - assertEquals(255, mSubscriptionInfoUT.getIconTint()); - assertEquals(0, mSubscriptionInfoUT.getNameSource()); - assertEquals(1, mSubscriptionInfoUT.getSubscriptionId()); - assertEquals(0, mSubscriptionInfoUT.getSimSlotIndex()); - assertEquals("890126042XXXXXXXXXXX", mSubscriptionInfoUT.getIccId()); + assertThat(mSubscriptionInfoUT.getMcc()).isEqualTo(310); + assertThat(mSubscriptionInfoUT.getMccString()).isEqualTo("310"); + assertThat(mSubscriptionInfoUT.getMnc()).isEqualTo(260); + assertThat(mSubscriptionInfoUT.getMncString()).isEqualTo("260"); + assertThat(mSubscriptionInfoUT.getNumber()).isEqualTo("12345"); + assertThat(mSubscriptionInfoUT.getDataRoaming()).isEqualTo(0); + assertThat(mSubscriptionInfoUT.getDisplayName().toString()).isEqualTo("T-mobile"); + assertThat(mSubscriptionInfoUT.getCarrierName().toString()).isEqualTo("T-mobile"); + assertThat(mSubscriptionInfoUT.getCountryIso()).isEqualTo("us"); + assertThat(mSubscriptionInfoUT.getIconTint()).isEqualTo(255); + assertThat(mSubscriptionInfoUT.getNameSource()).isEqualTo(0); + assertThat(mSubscriptionInfoUT.getSubscriptionId()).isEqualTo(1); + assertThat(mSubscriptionInfoUT.getSimSlotIndex()).isEqualTo(0); + assertThat(mSubscriptionInfoUT.getIccId()).isEqualTo("890126042XXXXXXXXXXX"); } @Test - @SmallTest - public void testSetGetCarrierName() { - assertEquals("T-mobile", mSubscriptionInfoUT.getCarrierName()); - mSubscriptionInfoUT.setCarrierName("Verizon"); - assertEquals("Verizon", mSubscriptionInfoUT.getCarrierName()); - } - - @Test - @SmallTest - public void testSetGetDisplayName() { - assertEquals("T-mobile", mSubscriptionInfoUT.getDisplayName()); - mSubscriptionInfoUT.setDisplayName("Verizon"); - assertEquals("Verizon", mSubscriptionInfoUT.getDisplayName()); - } - - @Test - @SmallTest - public void testSetGetIconTint() { - assertEquals(255, mSubscriptionInfoUT.getIconTint()); - mSubscriptionInfoUT.setIconTint(0); - assertEquals(0, mSubscriptionInfoUT.getIconTint()); - } - - @Test - @SmallTest public void testParcelUnparcel() { Parcel p = Parcel.obtain(); mSubscriptionInfoUT.writeToParcel(p, 0); p.setDataPosition(0); SubscriptionInfo copy = SubscriptionInfo.CREATOR.createFromParcel(p); - assertEquals(mSubscriptionInfoUT, copy); + assertThat(mSubscriptionInfoUT).isEqualTo(copy); } @Test - @SmallTest public void testEquals() { - SubscriptionInfo copiedInfo = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, - "T-mobile", "T-mobile", 0, 255, "12345", 0, null, - "310", "260", "156", false, null, null); - copiedInfo.setAssociatedPlmns(EHPLMNS, HPLMNS); - SubscriptionInfo differentDisplayName = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, - "AT&T", "T-mobile", 0, 255, "12345", 0, null, - "310", "260", "156", false, null, null); - SubscriptionInfo differentSubId = new SubscriptionInfo(2, "890126042XXXXXXXXXXX", 0, - "AT&T", "T-mobile", 0, 255, "12345", 0, null, - "310", "260", "156", false, null, null); + SubscriptionInfo copiedInfo = new SubscriptionInfo.Builder(mSubscriptionInfoUT).build(); + SubscriptionInfo differentDisplayName = new SubscriptionInfo.Builder(mSubscriptionInfoUT) + .setDisplayName("Different display name") + .build(); + SubscriptionInfo differentSubId = new SubscriptionInfo.Builder(mSubscriptionInfoUT) + .setId(1234) + .build(); - assertEquals(mSubscriptionInfoUT, copiedInfo); - assertNotEquals(mSubscriptionInfoUT, differentDisplayName); - assertNotEquals(mSubscriptionInfoUT, differentSubId); + assertThat(mSubscriptionInfoUT).isEqualTo(copiedInfo); + assertThat(mSubscriptionInfoUT).isNotEqualTo(differentDisplayName); + assertThat(mSubscriptionInfoUT).isNotEqualTo(differentSubId); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java index ea38e2d828..091ec2761c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java @@ -601,13 +601,16 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { List subInfoList = new ArrayList<>(); // 1: not embedded, but has matching iccid with an embedded subscription. - subInfoList.add(new SubscriptionInfo( - 0, "1", 0, "", "", 0, 0, "", 0, null, "0", "0", "", false /* isEmbedded */, - null /* accessRules */, null)); + subInfoList.add(new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setIccId("1") + .build()); // 2: embedded but no longer present. - subInfoList.add(new SubscriptionInfo( - 0, "2", 0, "", "", 0, 0, "", 0, null, "0", "0", "", true /* isEmbedded */, - null /* accessRules */, null)); + subInfoList.add(new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setIccId("2") + .setEmbedded(true) + .build()); when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( new String[] { "1", "3"}, false /* removable */)).thenReturn(subInfoList); @@ -655,13 +658,16 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { List subInfoList = new ArrayList<>(); // 1: not embedded, but has matching iccid with an embedded subscription. - subInfoList.add(new SubscriptionInfo( - 0, "1", 0, "", "", 0, 0, "", 0, null, "0", "0", "", false /* isEmbedded */, - null /* accessRules */, null)); + subInfoList.add(new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setIccId("1") + .build()); // 2: embedded. - subInfoList.add(new SubscriptionInfo( - 0, "2", 0, "", "", 0, 0, "", 0, null, "0", "0", "", true /* isEmbedded */, - null /* accessRules */, null)); + subInfoList.add(new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setIccId("2") + .setEmbedded(true) + .build()); when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( new String[0], false /* removable */)).thenReturn(subInfoList); @@ -689,9 +695,10 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { List subInfoList = new ArrayList<>(); // 1: not embedded. - subInfoList.add(new SubscriptionInfo( - 0, "1", 0, "", "", 0, 0, "", 0, null, "0", "0", "", false /* isEmbedded */, - null /* accessRules */, null)); + subInfoList.add(new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setIccId("1") + .build()); when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( new String[0], false /* removable */)).thenReturn(subInfoList); 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 491c6903b1..6f0759c74d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java @@ -1258,10 +1258,16 @@ public class EuiccControllerTest extends TelephonyTest { private void setHasCarrierPrivilegesOnActiveSubscription(boolean hasPrivileges) throws Exception { - SubscriptionInfo subInfo = new SubscriptionInfo( - 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */, - hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", CARD_ID, - false, null, false, 0, 0, 0, null, null, true, 0); + SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) + .setEmbedded(true); + if (hasPrivileges) { + builder.setNativeAccessRules(new UiccAccessRule[] { ACCESS_RULE }); + } + builder.setCardId(CARD_ID); + SubscriptionInfo subInfo = builder.build(); + when(mSubscriptionManager.canManageSubscription(subInfo, PACKAGE_NAME)).thenReturn( hasPrivileges); when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn( @@ -1287,14 +1293,16 @@ public class EuiccControllerTest extends TelephonyTest { cardInfos.add(cardInfo2); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(cardInfos); - SubscriptionInfo subInfo1 = new SubscriptionInfo( - 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */, - hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", CARD_ID, - false, null, false, 0, 0, 0, null, null, true, 0); - SubscriptionInfo subInfo2 = new SubscriptionInfo( - 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */, - hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", - 1 /* cardId */, false, null, false, 0, 0, 0, null, null, true, 0); + SubscriptionInfo subInfo1 = new SubscriptionInfo.Builder() + .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) + .setEmbedded(true) + .setCardId(CARD_ID) + .build(); + SubscriptionInfo subInfo2 = new SubscriptionInfo.Builder() + .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) + .setEmbedded(true) + .setCardId(2) + .build(); when(mSubscriptionManager.canManageSubscription(subInfo1, PACKAGE_NAME)).thenReturn( hasPrivileges); when(mSubscriptionManager.canManageSubscription(subInfo2, PACKAGE_NAME)).thenReturn( @@ -1304,10 +1312,13 @@ public class EuiccControllerTest extends TelephonyTest { } private void prepareOperationSubscription(boolean hasPrivileges) throws Exception { - SubscriptionInfo subInfo = new SubscriptionInfo( - SUBSCRIPTION_ID, ICC_ID, 0, "", "", 0, 0, "", 0, null, "0", "0", "", - true /* isEmbedded */, hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, - null); + SubscriptionInfo subInfo = new SubscriptionInfo.Builder() + .setId(SUBSCRIPTION_ID) + .setIccId(ICC_ID) + .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) + .setEmbedded(true) + .setCardId(CARD_ID) + .build(); when(mSubscriptionManager.canManageSubscription(subInfo, PACKAGE_NAME)).thenReturn( hasPrivileges); when(mSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn( -- GitLab From db6a07e2ef67c2ee0d1e72bb246c44b068c4de7c Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Thu, 15 Sep 2022 19:47:08 +0000 Subject: [PATCH 092/656] Implementation of premium sms metrics. Bug: 243187341 Test: atest com.android.internal.telephony.metrics.MetricsCollectorTest atest com.android.internal.telephony.metrics.PersistAtomsStorageTest atest CtsTelephonyTestCases Change-Id: Ie8e7c4ecc23f90d3c3b679f6db71065a588a2faa --- proto/src/persist_atoms.proto | 12 ++ .../internal/telephony/SMSDispatcher.java | 6 + .../internal/telephony/SmsUsageMonitor.java | 38 +++++ .../telephony/metrics/MetricsCollector.java | 26 +++ .../metrics/PersistAtomsStorage.java | 58 ++++++- .../internal/telephony/metrics/SmsStats.java | 10 ++ .../metrics/MetricsCollectorTest.java | 45 ++++- .../metrics/PersistAtomsStorageTest.java | 158 ++++++++++++++++++ 8 files changed, 351 insertions(+), 2 deletions(-) diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index fca76355b8..05de4e1944 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -180,6 +180,12 @@ message PersistAtoms { /* Unmetered networks information. */ repeated UnmeteredNetworks unmetered_networks = 52; + + /* Outgoing Short Code SMS statistics and information. */ + repeated OutgoingShortCodeSms outgoing_short_code_sms = 53; + + /* Timestamp of last outgoing_short_code_sms pull. */ + optional int64 outgoing_short_code_sms_pull_timestamp_millis = 54; } // The canonical versions of the following enums live in: @@ -516,3 +522,9 @@ message UnmeteredNetworks { optional int32 carrier_id = 2; optional int64 unmetered_networks_bitmask = 3; } + +message OutgoingShortCodeSms { + optional int32 category = 1; + optional int32 xml_version = 2; + optional int32 short_code_sms_count = 3; +} \ No newline at end of file diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 824c001673..ac0d54f8a9 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -1861,6 +1861,12 @@ public abstract class SMSDispatcher extends Handler { trackers[0].mDestAddress, networkCountryIso)); } + if (smsCategory != SmsManager.SMS_CATEGORY_NOT_SHORT_CODE) { + int xmlVersion = mSmsDispatchersController.getUsageMonitor() + .getShortCodeXmlFileVersion(); + mPhone.getSmsStats().onOutgoingShortCodeSms(smsCategory, xmlVersion); + } + if (smsCategory == SmsManager.SMS_CATEGORY_NOT_SHORT_CODE || smsCategory == SmsManager.SMS_CATEGORY_FREE_SHORT_CODE || smsCategory == SmsManager.SMS_CATEGORY_STANDARD_SHORT_CODE) { diff --git a/src/java/com/android/internal/telephony/SmsUsageMonitor.java b/src/java/com/android/internal/telephony/SmsUsageMonitor.java index 8bcdc07b55..8e4ac60419 100644 --- a/src/java/com/android/internal/telephony/SmsUsageMonitor.java +++ b/src/java/com/android/internal/telephony/SmsUsageMonitor.java @@ -43,6 +43,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -73,6 +74,8 @@ public class SmsUsageMonitor { private static final String SHORT_CODE_PATH = "/data/misc/sms/codes"; + private static final String SHORT_CODE_VERSION_PATH = "/data/misc/sms/metadata/version"; + /** Default checking period for SMS sent without user permission. */ private static final int DEFAULT_SMS_CHECK_PERIOD = 60000; // 1 minute @@ -128,6 +131,8 @@ public class SmsUsageMonitor { /** Last modified time for pattern file */ private long mPatternFileLastModified = 0; + private int mPatternFileVersion = -1; + private RoleManager mRoleManager; /** Directory for per-app SMS permission XML file. */ @@ -415,9 +420,11 @@ public class SmsUsageMonitor { if (mPatternFile.exists()) { if (DBG) Rlog.d(TAG, "Loading SMS Short Code patterns from file"); mCurrentPatternMatcher = getPatternMatcherFromFile(countryIso); + mPatternFileVersion = getPatternFileVersionFromFile(); } else { if (DBG) Rlog.d(TAG, "Loading SMS Short Code patterns from resource"); mCurrentPatternMatcher = getPatternMatcherFromResource(countryIso); + mPatternFileVersion = -1; } mCurrentCountry = countryIso; } @@ -655,6 +662,37 @@ public class SmsUsageMonitor { return false; } + private int getPatternFileVersionFromFile() { + File versionFile = new File(SHORT_CODE_VERSION_PATH); + if (versionFile.exists()) { + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(versionFile)); + String version = reader.readLine(); + if (version != null) { + return Integer.parseInt(version); + } + } catch (IOException e) { + Rlog.e(TAG, "File reader exception reading short code " + + "pattern file version", e); + } finally { + try { + if (reader != null) { + reader.close(); + } + } catch (IOException e) { + Rlog.e(TAG, "File reader exception closing short code " + + "pattern file version reader", e); + } + } + } + return -1; + } + + public int getShortCodeXmlFileVersion() { + return mPatternFileVersion; + } + private static void log(String msg) { Rlog.d(TAG, msg); } diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 9805d8b1ac..2a5376f64d 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -30,6 +30,7 @@ import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_ import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_TERMINATION; import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS; import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS; +import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SHORT_CODE_SMS; import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS; import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT; import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS; @@ -69,6 +70,7 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTerm import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms; import com.android.internal.telephony.nano.PersistAtomsProto.NetworkRequestsV2; import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; +import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms; import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent; import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats; import com.android.internal.telephony.nano.PersistAtomsProto.RcsClientProvisioningStats; @@ -176,6 +178,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { registerAtom(PRESENCE_NOTIFY_EVENT, POLICY_PULL_DAILY); registerAtom(GBA_EVENT, POLICY_PULL_DAILY); registerAtom(PER_SIM_STATUS, null); + registerAtom(OUTGOING_SHORT_CODE_SMS, POLICY_PULL_DAILY); Rlog.d(TAG, "registered"); } else { @@ -251,6 +254,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return pullGbaEvent(data); case PER_SIM_STATUS: return pullPerSimStatus(data); + case OUTGOING_SHORT_CODE_SMS: + return pullOutgoingShortCodeSms(data); default: Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag)); return StatsManager.PULL_SKIP; @@ -693,6 +698,19 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return result; } + private int pullOutgoingShortCodeSms(List data) { + OutgoingShortCodeSms[] outgoingShortCodeSmsList = mStorage + .getOutgoingShortCodeSms(MIN_COOLDOWN_MILLIS); + if (outgoingShortCodeSmsList != null) { + // Outgoing short code SMS list is already shuffled when SMS were inserted + Arrays.stream(outgoingShortCodeSmsList).forEach(sms -> data.add(buildStatsEvent(sms))); + return StatsManager.PULL_SUCCESS; + } else { + Rlog.w(TAG, "OUTGOING_SHORT_CODE_SMS pull too frequent, skipping"); + return StatsManager.PULL_SKIP; + } + } + /** Registers a pulled atom ID {@code atomId} with optional {@code policy} for pulling. */ private void registerAtom(int atomId, @Nullable StatsManager.PullAtomMetadata policy) { mStatsManager.setPullAtomCallback(atomId, policy, ConcurrentUtils.DIRECT_EXECUTOR, this); @@ -1026,6 +1044,14 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { stats.count); } + private static StatsEvent buildStatsEvent(OutgoingShortCodeSms shortCodeSms) { + return TelephonyStatsLog.buildStatsEvent( + OUTGOING_SHORT_CODE_SMS, + shortCodeSms.category, + shortCodeSms.xmlVersion, + shortCodeSms.shortCodeSmsCount); + } + /** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */ private static Phone[] getPhonesIfAny() { try { diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java index eef88d2457..e1b575f709 100644 --- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java +++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java @@ -43,6 +43,7 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTerm import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms; import com.android.internal.telephony.nano.PersistAtomsProto.NetworkRequestsV2; import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; +import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms; import com.android.internal.telephony.nano.PersistAtomsProto.PersistAtoms; import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent; import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats; @@ -159,6 +160,10 @@ public class PersistAtomsStorage { /** Maximum number of GBA Event to store between pulls. */ private final int mMaxNumGbaEventStats; + + /** Maximum number of outgoing short code sms to store between pulls. */ + private final int mMaxOutgoingShortCodeSms; + /** Stores persist atoms and persist states of the puller. */ @VisibleForTesting protected PersistAtoms mAtoms; @@ -207,6 +212,7 @@ public class PersistAtomsStorage { mMaxNumUceEventStats = 5; mMaxNumPresenceNotifyEventStats = 10; mMaxNumGbaEventStats = 5; + mMaxOutgoingShortCodeSms = 5; } else { mMaxNumVoiceCallSessions = 50; mMaxNumSms = 25; @@ -229,6 +235,7 @@ public class PersistAtomsStorage { mMaxNumUceEventStats = 25; mMaxNumPresenceNotifyEventStats = 50; mMaxNumGbaEventStats = 10; + mMaxOutgoingShortCodeSms = 10; } mAtoms = loadAtomsFromFile(); @@ -655,6 +662,18 @@ public class PersistAtomsStorage { } } + /** Adds an outgoing short code sms to the storage. */ + public synchronized void addOutgoingShortCodeSms(OutgoingShortCodeSms shortCodeSms) { + OutgoingShortCodeSms existingOutgoingShortCodeSms = find(shortCodeSms); + if (existingOutgoingShortCodeSms != null) { + existingOutgoingShortCodeSms.shortCodeSmsCount += 1; + } else { + mAtoms.outgoingShortCodeSms = insertAtRandomPlace(mAtoms.outgoingShortCodeSms, + shortCodeSms, mMaxOutgoingShortCodeSms); + } + 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}. @@ -1174,6 +1193,24 @@ public class PersistAtomsStorage { return bitmask; } + /** + * Returns and clears the OutgoingShortCodeSms if last pulled longer than {@code + * minIntervalMillis} ago, otherwise returns {@code null}. + */ + @Nullable + public synchronized OutgoingShortCodeSms[] getOutgoingShortCodeSms(long minIntervalMillis) { + if ((getWallTimeMillis() - mAtoms.outgoingShortCodeSmsPullTimestampMillis) + > minIntervalMillis) { + mAtoms.outgoingShortCodeSmsPullTimestampMillis = getWallTimeMillis(); + OutgoingShortCodeSms[] previousOutgoingShortCodeSms = mAtoms.outgoingShortCodeSms; + mAtoms.outgoingShortCodeSms = new OutgoingShortCodeSms[0]; + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS); + return previousOutgoingShortCodeSms; + } else { + return null; + } + } + /** Saves {@link PersistAtoms} to a file in private storage immediately. */ public synchronized void flushAtoms() { saveAtomsToFile(0); @@ -1309,6 +1346,8 @@ public class PersistAtomsStorage { atoms.unmeteredNetworks, UnmeteredNetworks.class ); + atoms.outgoingShortCodeSms = sanitizeAtoms(atoms.outgoingShortCodeSms, + OutgoingShortCodeSms.class, mMaxOutgoingShortCodeSms); // out of caution, sanitize also the timestamps atoms.voiceCallRatUsagePullTimestampMillis = @@ -1357,6 +1396,8 @@ public class PersistAtomsStorage { sanitizeTimestamp(atoms.presenceNotifyEventPullTimestampMillis); atoms.gbaEventPullTimestampMillis = sanitizeTimestamp(atoms.gbaEventPullTimestampMillis); + atoms.outgoingShortCodeSmsPullTimestampMillis = + sanitizeTimestamp(atoms.outgoingShortCodeSmsPullTimestampMillis); return atoms; } catch (NoSuchFileException e) { @@ -1724,6 +1765,20 @@ public class PersistAtomsStorage { return null; } + /** + * Returns OutgoingShortCodeSms atom that has same category, xmlVersion as the given one, + * or {@code null} if it does not exist. + */ + private @Nullable OutgoingShortCodeSms find(OutgoingShortCodeSms key) { + for (OutgoingShortCodeSms shortCodeSms : mAtoms.outgoingShortCodeSms) { + if (shortCodeSms.category == key.category + && shortCodeSms.xmlVersion == key.xmlVersion) { + return shortCodeSms; + } + } + return null; + } + /** * Inserts a new element in a random position in an array with a maximum size. * @@ -1969,6 +2024,7 @@ public class PersistAtomsStorage { atoms.uceEventStatsPullTimestampMillis = currentTime; atoms.presenceNotifyEventPullTimestampMillis = currentTime; atoms.gbaEventPullTimestampMillis = currentTime; + atoms.outgoingShortCodeSmsPullTimestampMillis = currentTime; Rlog.d(TAG, "created new PersistAtoms"); return atoms; @@ -1979,4 +2035,4 @@ public class PersistAtomsStorage { // Epoch time in UTC, preserved across reboots, but can be adjusted e.g. by the user or NTP return System.currentTimeMillis(); } -} +} \ No newline at end of file diff --git a/src/java/com/android/internal/telephony/metrics/SmsStats.java b/src/java/com/android/internal/telephony/metrics/SmsStats.java index 48826fdd9d..a93604dda4 100644 --- a/src/java/com/android/internal/telephony/metrics/SmsStats.java +++ b/src/java/com/android/internal/telephony/metrics/SmsStats.java @@ -59,6 +59,7 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms; import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; +import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms; import com.android.telephony.Rlog; import java.util.Objects; @@ -195,6 +196,15 @@ public class SmsStats { mAtomsStorage.addOutgoingSms(proto); } + /** Create a new atom when user attempted to send an outgoing short code sms. */ + public void onOutgoingShortCodeSms(int category, int xmlVersion) { + OutgoingShortCodeSms proto = new OutgoingShortCodeSms(); + proto.category = category; + proto.xmlVersion = xmlVersion; + proto.shortCodeSmsCount = 1; + mAtomsStorage.addOutgoingShortCodeSms(proto); + } + /** Creates a proto for a normal single-part {@code IncomingSms} with default values. */ private IncomingSms getIncomingDefaultProto(boolean is3gpp2, @InboundSmsHandler.SmsSource int smsSource) { 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 a4e257476e..58864229e7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony.metrics; 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.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; @@ -43,6 +44,7 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyTest; 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.VoiceCallRatUsage; import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession; import com.android.internal.telephony.uicc.IccCardStatus.CardState; @@ -412,4 +414,45 @@ public class MetricsCollectorTest extends TelephonyTest { assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS); // TODO(b/153196254): verify atom contents } -} + + @Test + public void onPullAtom_outgoingShortCodeSms_empty() { + doReturn(new OutgoingShortCodeSms[0]).when(mPersistAtomsStorage) + .getOutgoingShortCodeSms(anyLong()); + List actualAtoms = new ArrayList<>(); + + int result = mMetricsCollector.onPullAtom(OUTGOING_SHORT_CODE_SMS, actualAtoms); + + assertThat(actualAtoms).hasSize(0); + assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS); + } + + @Test + public void onPullAtom_outgoingShortCodeSms_tooFrequent() { + doReturn(null).when(mPersistAtomsStorage).getOutgoingShortCodeSms(anyLong()); + List actualAtoms = new ArrayList<>(); + + int result = mMetricsCollector.onPullAtom(OUTGOING_SHORT_CODE_SMS, actualAtoms); + + assertThat(actualAtoms).hasSize(0); + assertThat(result).isEqualTo(StatsManager.PULL_SKIP); + verify(mPersistAtomsStorage, times(1)) + .getOutgoingShortCodeSms(eq(MIN_COOLDOWN_MILLIS)); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + public void onPullAtom_outgoingShortCodeSms_multipleSms() { + OutgoingShortCodeSms outgoingShortCodeSms = new OutgoingShortCodeSms(); + doReturn(new OutgoingShortCodeSms[] {outgoingShortCodeSms, outgoingShortCodeSms, + outgoingShortCodeSms, outgoingShortCodeSms}) + .when(mPersistAtomsStorage) + .getOutgoingShortCodeSms(anyLong()); + List actualAtoms = new ArrayList<>(); + + int result = mMetricsCollector.onPullAtom(OUTGOING_SHORT_CODE_SMS, actualAtoms); + + assertThat(actualAtoms).hasSize(4); + assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS); + } +} \ No newline at end of file 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 e46b822bd1..be2257beeb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java @@ -44,6 +44,7 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.annotation.Nullable; import android.content.Context; @@ -68,6 +69,7 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationFeat import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationServiceDescStats; import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationStats; import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination; +import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms; import com.android.internal.telephony.nano.PersistAtomsProto.PersistAtoms; import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent; import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats; @@ -224,6 +226,10 @@ public class PersistAtomsStorageTest extends TelephonyTest { private SipTransportSession mSipTransportSession2; private SipTransportSession[] mSipTransportSession; + private OutgoingShortCodeSms mOutgoingShortCodeSms1; + private OutgoingShortCodeSms mOutgoingShortCodeSms2; + private OutgoingShortCodeSms[] mOutgoingShortCodeSms; + private void makeTestData() { // MO call with SRVCC (LTE to UMTS) mCall1Proto = new VoiceCallSession(); @@ -859,6 +865,19 @@ public class PersistAtomsStorageTest extends TelephonyTest { mSipTransportSession = new SipTransportSession[] {mSipTransportSession1, mSipTransportSession2}; + + mOutgoingShortCodeSms1 = new OutgoingShortCodeSms(); + mOutgoingShortCodeSms1.category = 1; + mOutgoingShortCodeSms1.xmlVersion = 30; + mOutgoingShortCodeSms1.shortCodeSmsCount = 1; + + mOutgoingShortCodeSms2 = new OutgoingShortCodeSms(); + mOutgoingShortCodeSms2.category = 2; + mOutgoingShortCodeSms2.xmlVersion = 31; + mOutgoingShortCodeSms2.shortCodeSmsCount = 1; + + mOutgoingShortCodeSms = new OutgoingShortCodeSms[] {mOutgoingShortCodeSms1, + mOutgoingShortCodeSms2}; } private static class TestablePersistAtomsStorage extends PersistAtomsStorage { @@ -997,6 +1016,9 @@ public class PersistAtomsStorageTest extends TelephonyTest { mSipTransportSession1 = null; mSipTransportSession2 = null; mSipTransportSession = null; + mOutgoingShortCodeSms1 = null; + mOutgoingShortCodeSms2 = null; + mOutgoingShortCodeSms = null; super.tearDown(); } @@ -3398,6 +3420,121 @@ public class PersistAtomsStorageTest extends TelephonyTest { inOrder.verifyNoMoreInteractions(); } + @Test + public void addOutgoingShortCodeSms_emptyProto() throws Exception { + createEmptyTestFile(); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addOutgoingShortCodeSms(mOutgoingShortCodeSms1); + mPersistAtomsStorage.incTimeMillis(100L); + + // OutgoingShortCodeSms should be added successfully, changes should be saved. + verifyCurrentStateSavedToFileOnce(); + OutgoingShortCodeSms[] expectedList = new OutgoingShortCodeSms[] {mOutgoingShortCodeSms1}; + assertProtoArrayEquals(expectedList, + mPersistAtomsStorage.getOutgoingShortCodeSms(0L)); + } + + @Test + public void addOutgoingShortCodeSms_withExistingEntries() throws Exception { + createEmptyTestFile(); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addOutgoingShortCodeSms(mOutgoingShortCodeSms1); + mPersistAtomsStorage.addOutgoingShortCodeSms(mOutgoingShortCodeSms2); + mPersistAtomsStorage.incTimeMillis(100L); + + // OutgoingShortCodeSms should be added successfully. + verifyCurrentStateSavedToFileOnce(); + OutgoingShortCodeSms[] expectedList = new OutgoingShortCodeSms[] {mOutgoingShortCodeSms1, + mOutgoingShortCodeSms2}; + assertProtoArrayEqualsIgnoringOrder(expectedList, + mPersistAtomsStorage.getOutgoingShortCodeSms(0L)); + } + + @Test + public void addOutgoingShortCodeSms_updateExistingEntries() throws Exception { + createTestFile(START_TIME_MILLIS); + + // Add copy of mOutgoingShortCodeSms1. + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addOutgoingShortCodeSms(copyOf(mOutgoingShortCodeSms1)); + mPersistAtomsStorage.incTimeMillis(100L); + + // mOutgoingShortCodeSms1's short code sms count should be increased by 1. + verifyCurrentStateSavedToFileOnce(); + OutgoingShortCodeSms newOutgoingShortCodeSms1 = copyOf(mOutgoingShortCodeSms1); + newOutgoingShortCodeSms1.shortCodeSmsCount = 2; + OutgoingShortCodeSms[] expectedList = new OutgoingShortCodeSms[] {newOutgoingShortCodeSms1, + mOutgoingShortCodeSms2}; + assertProtoArrayEqualsIgnoringOrder(expectedList, + mPersistAtomsStorage.getOutgoingShortCodeSms(0L)); + } + + @Test + public void addOutgoingShortCodeSms_tooManyEntries() throws Exception { + createEmptyTestFile(); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + + // Store mOutgoingShortCodeSms1 11 times. + for (int i = 0; i < 11; i++) { + mPersistAtomsStorage.addOutgoingShortCodeSms(mOutgoingShortCodeSms1); + mPersistAtomsStorage.incTimeMillis(100L); + } + // Store mOutgoingShortCodeSms2 1 time. + mPersistAtomsStorage.addOutgoingShortCodeSms(mOutgoingShortCodeSms2); + + verifyCurrentStateSavedToFileOnce(); + OutgoingShortCodeSms[] result = mPersistAtomsStorage + .getOutgoingShortCodeSms(0L); + assertHasStatsAndCount(result, mOutgoingShortCodeSms1, 11); + assertHasStatsAndCount(result, mOutgoingShortCodeSms2, 1); + } + + @Test + public void getOutgoingShortCodeSms_tooFrequent() throws Exception { + createTestFile(START_TIME_MILLIS); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + // Pull interval less than minimum. + mPersistAtomsStorage.incTimeMillis(50L); + OutgoingShortCodeSms[] outgoingShortCodeSmsList = mPersistAtomsStorage + .getOutgoingShortCodeSms(100L); + // Should be denied. + assertNull(outgoingShortCodeSmsList); + } + + @Test + public void getOutgoingShortCodeSms_withSavedAtoms() throws Exception { + createTestFile(START_TIME_MILLIS); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.incTimeMillis(100L); + OutgoingShortCodeSms[] outgoingShortCodeSmsList1 = mPersistAtomsStorage + .getOutgoingShortCodeSms(50L); + mPersistAtomsStorage.incTimeMillis(100L); + OutgoingShortCodeSms[] outgoingShortCodeSmsList2 = mPersistAtomsStorage + .getOutgoingShortCodeSms(50L); + + // First set of results should be equal to file contents. + OutgoingShortCodeSms[] expectedOutgoingShortCodeSmsList = + new OutgoingShortCodeSms[] {mOutgoingShortCodeSms1, mOutgoingShortCodeSms2}; + assertProtoArrayEqualsIgnoringOrder(expectedOutgoingShortCodeSmsList, + outgoingShortCodeSmsList1); + // Second set of results should be empty. + assertProtoArrayEquals(new OutgoingShortCodeSms[0], outgoingShortCodeSmsList2); + // Corresponding pull timestamp should be updated and saved. + assertEquals(START_TIME_MILLIS + 200L, mPersistAtomsStorage + .getAtomsProto().outgoingShortCodeSmsPullTimestampMillis); + InOrder inOrder = inOrder(mTestFileOutputStream); + assertEquals(START_TIME_MILLIS + 100L, + getAtomsWritten(inOrder).outgoingShortCodeSmsPullTimestampMillis); + assertEquals(START_TIME_MILLIS + 200L, + getAtomsWritten(inOrder).outgoingShortCodeSmsPullTimestampMillis); + inOrder.verifyNoMoreInteractions(); + } + @Test @SmallTest public void clearAtoms() throws Exception { @@ -3469,6 +3606,8 @@ public class PersistAtomsStorageTest extends TelephonyTest { atoms.sipMessageResponse = mSipMessageResponse; atoms.sipTransportSessionPullTimestampMillis = lastPullTimeMillis; atoms.sipTransportSession = mSipTransportSession; + atoms.outgoingShortCodeSms = mOutgoingShortCodeSms; + atoms.outgoingShortCodeSmsPullTimestampMillis = lastPullTimeMillis; FileOutputStream stream = new FileOutputStream(mTestFile); stream.write(PersistAtoms.toByteArray(atoms)); stream.close(); @@ -3587,6 +3726,11 @@ public class PersistAtomsStorageTest extends TelephonyTest { return SipTransportSession.parseFrom(MessageNano.toByteArray(source)); } + private static OutgoingShortCodeSms copyOf(OutgoingShortCodeSms source) + throws Exception { + return OutgoingShortCodeSms.parseFrom(MessageNano.toByteArray(source)); + } + private void assertAllPullTimestampEquals(long timestamp) { assertEquals( timestamp, @@ -3866,4 +4010,18 @@ public class PersistAtomsStorageTest extends TelephonyTest { } assertEquals(expectedCount, actualCount); } + + private static void assertHasStatsAndCount( + OutgoingShortCodeSms[] outgoingShortCodeSmsList, + @Nullable OutgoingShortCodeSms expectedOutgoingShortCodeSms, int expectedCount) { + assertNotNull(outgoingShortCodeSmsList); + int actualCount = -1; + for (OutgoingShortCodeSms outgoingShortCodeSms : outgoingShortCodeSmsList) { + if (outgoingShortCodeSms.category == expectedOutgoingShortCodeSms.category + && outgoingShortCodeSms.xmlVersion == expectedOutgoingShortCodeSms.xmlVersion) { + actualCount = outgoingShortCodeSms.shortCodeSmsCount; + } + } + assertEquals(expectedCount, actualCount); + } } -- GitLab From db658cc4219c021c9445623ea0881ec56e229f10 Mon Sep 17 00:00:00 2001 From: terrycrhuang Date: Tue, 18 Jan 2022 16:04:58 +0800 Subject: [PATCH 093/656] Support DSDS on Mock Modem Bug: 210073692 Test: Switch to Mock Modem and be able to bind the two phones Change-Id: If97411c11d3312c333549c7d1f8f961f824cbe99 --- .../android/internal/telephony/MockModem.java | 52 ++++++++++--------- .../telephony/PhoneConfigurationManager.java | 37 ++++++++----- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/src/java/com/android/internal/telephony/MockModem.java b/src/java/com/android/internal/telephony/MockModem.java index 4266a7518d..f6afe9e3f3 100644 --- a/src/java/com/android/internal/telephony/MockModem.java +++ b/src/java/com/android/internal/telephony/MockModem.java @@ -42,7 +42,7 @@ public class MockModem { static final int RADIOCONFIG_SERVICE = RIL.MAX_SERVICE_IDX + 1; static final int BINDER_RETRY_MILLIS = 3 * 100; - static final int BINDER_MAX_RETRY = 3; + static final int BINDER_MAX_RETRY = 10; private Context mContext; private String mServiceName; @@ -64,6 +64,7 @@ public class MockModem { private ServiceConnection mConfigServiceConnection; private byte mPhoneId; + private String mTag; MockModem(Context context, String serviceName) { this(context, serviceName, 0); @@ -71,6 +72,7 @@ public class MockModem { MockModem(Context context, String serviceName, int phoneId) { mPhoneId = (byte) phoneId; + mTag = TAG + "-" + mPhoneId; mContext = context; String[] componentInfo = serviceName.split("/", 2); mPackageName = componentInfo[0]; @@ -86,7 +88,7 @@ public class MockModem { @Override public void onServiceConnected(ComponentName name, IBinder binder) { - Rlog.d(TAG, "IRadio " + getModuleName(mService) + " - onServiceConnected"); + Rlog.d(mTag, "IRadio " + getModuleName(mService) + " - onServiceConnected"); if (mService == RIL.MODEM_SERVICE) { mModemBinder = binder; @@ -107,7 +109,7 @@ public class MockModem { @Override public void onServiceDisconnected(ComponentName name) { - Rlog.d(TAG, "IRadio " + getModuleName(mService) + " - onServiceDisconnected"); + Rlog.d(mTag, "IRadio " + getModuleName(mService) + " - onServiceDisconnected"); if (mService == RIL.MODEM_SERVICE) { mModemBinder = null; @@ -138,7 +140,7 @@ public class MockModem { Intent intent = new Intent(); intent.setComponent(new ComponentName(mPackageName, mServiceName)); - intent.setAction(actionName); + intent.setAction(actionName + phoneId); intent.putExtra(PHONE_ID, phoneId); status = mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); @@ -183,11 +185,11 @@ public class MockModem { boolean status = bindModuleToMockModemService(BIND_IRADIOCONFIG, mConfigServiceConnection); if (!status) { - Rlog.d(TAG, "IRadio Config bind fail"); + Rlog.d(mTag, "IRadio Config bind fail"); mConfigServiceConnection = null; } } else { - Rlog.d(TAG, "IRadio Config is bound"); + Rlog.d(mTag, "IRadio Config is bound"); } } else if (service == RIL.MODEM_SERVICE) { if (mModemBinder == null) { @@ -197,11 +199,11 @@ public class MockModem { bindModuleToMockModemService( mPhoneId, BIND_IRADIOMODEM, mModemServiceConnection); if (!status) { - Rlog.d(TAG, "IRadio Modem bind fail"); + Rlog.d(mTag, "IRadio Modem bind fail"); mModemServiceConnection = null; } } else { - Rlog.d(TAG, "IRadio Modem is bound"); + Rlog.d(mTag, "IRadio Modem is bound"); } } else if (service == RIL.SIM_SERVICE) { if (mSimBinder == null) { @@ -211,11 +213,11 @@ public class MockModem { bindModuleToMockModemService( mPhoneId, BIND_IRADIOSIM, mSimServiceConnection); if (!status) { - Rlog.d(TAG, "IRadio Sim bind fail"); + Rlog.d(mTag, "IRadio Sim bind fail"); mSimServiceConnection = null; } } else { - Rlog.d(TAG, "IRadio Sim is bound"); + Rlog.d(mTag, "IRadio Sim is bound"); } } else if (service == RIL.MESSAGING_SERVICE) { if (mMessagingBinder == null) { @@ -225,11 +227,11 @@ public class MockModem { bindModuleToMockModemService( mPhoneId, BIND_IRADIOMESSAGING, mMessagingServiceConnection); if (!status) { - Rlog.d(TAG, "IRadio Messaging bind fail"); + Rlog.d(mTag, "IRadio Messaging bind fail"); mMessagingServiceConnection = null; } } else { - Rlog.d(TAG, "IRadio Messaging is bound"); + Rlog.d(mTag, "IRadio Messaging is bound"); } } else if (service == RIL.DATA_SERVICE) { if (mDataBinder == null) { @@ -239,11 +241,11 @@ public class MockModem { bindModuleToMockModemService( mPhoneId, BIND_IRADIODATA, mDataServiceConnection); if (!status) { - Rlog.d(TAG, "IRadio Data bind fail"); + Rlog.d(mTag, "IRadio Data bind fail"); mDataServiceConnection = null; } } else { - Rlog.d(TAG, "IRadio Data is bound"); + Rlog.d(mTag, "IRadio Data is bound"); } } else if (service == RIL.NETWORK_SERVICE) { if (mNetworkBinder == null) { @@ -253,11 +255,11 @@ public class MockModem { bindModuleToMockModemService( mPhoneId, BIND_IRADIONETWORK, mNetworkServiceConnection); if (!status) { - Rlog.d(TAG, "IRadio Network bind fail"); + Rlog.d(mTag, "IRadio Network bind fail"); mNetworkServiceConnection = null; } } else { - Rlog.d(TAG, "IRadio Network is bound"); + Rlog.d(mTag, "IRadio Network is bound"); } } else if (service == RIL.VOICE_SERVICE) { if (mVoiceBinder == null) { @@ -267,11 +269,11 @@ public class MockModem { bindModuleToMockModemService( mPhoneId, BIND_IRADIOVOICE, mVoiceServiceConnection); if (!status) { - Rlog.d(TAG, "IRadio Voice bind fail"); + Rlog.d(mTag, "IRadio Voice bind fail"); mVoiceServiceConnection = null; } } else { - Rlog.d(TAG, "IRadio Voice is bound"); + Rlog.d(mTag, "IRadio Voice is bound"); } } } @@ -284,49 +286,49 @@ public class MockModem { mContext.unbindService(mConfigServiceConnection); mConfigServiceConnection = null; mConfigBinder = null; - Rlog.d(TAG, "unbind IRadio Config"); + Rlog.d(mTag, "unbind IRadio Config"); } } else if (service == RIL.MODEM_SERVICE) { if (mModemServiceConnection != null) { mContext.unbindService(mModemServiceConnection); mModemServiceConnection = null; mModemBinder = null; - Rlog.d(TAG, "unbind IRadio Modem"); + Rlog.d(mTag, "unbind IRadio Modem"); } } else if (service == RIL.SIM_SERVICE) { if (mSimServiceConnection != null) { mContext.unbindService(mSimServiceConnection); mSimServiceConnection = null; mSimBinder = null; - Rlog.d(TAG, "unbind IRadio Sim"); + Rlog.d(mTag, "unbind IRadio Sim"); } } else if (service == RIL.MESSAGING_SERVICE) { if (mMessagingServiceConnection != null) { mContext.unbindService(mMessagingServiceConnection); mMessagingServiceConnection = null; mMessagingBinder = null; - Rlog.d(TAG, "unbind IRadio Messaging"); + Rlog.d(mTag, "unbind IRadio Messaging"); } } else if (service == RIL.DATA_SERVICE) { if (mDataServiceConnection != null) { mContext.unbindService(mDataServiceConnection); mDataServiceConnection = null; mDataBinder = null; - Rlog.d(TAG, "unbind IRadio Data"); + Rlog.d(mTag, "unbind IRadio Data"); } } else if (service == RIL.NETWORK_SERVICE) { if (mNetworkServiceConnection != null) { mContext.unbindService(mNetworkServiceConnection); mNetworkServiceConnection = null; mNetworkBinder = null; - Rlog.d(TAG, "unbind IRadio Network"); + Rlog.d(mTag, "unbind IRadio Network"); } } else if (service == RIL.VOICE_SERVICE) { if (mVoiceServiceConnection != null) { mContext.unbindService(mVoiceServiceConnection); mVoiceServiceConnection = null; mVoiceBinder = null; - Rlog.d(TAG, "unbind IRadio Voice"); + Rlog.d(mTag, "unbind IRadio Voice"); } } } diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java index 426aeb2792..52b2949d6c 100644 --- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java +++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java @@ -466,10 +466,6 @@ public class PhoneConfigurationManager { * @return true if the modem service is set successfully, false otherwise. */ public boolean setModemService(String serviceName) { - if (mRadioConfig == null || mPhones[0] == null) { - return false; - } - log("setModemService: " + serviceName); boolean statusRadioConfig = false; boolean statusRil = false; @@ -479,23 +475,37 @@ public class PhoneConfigurationManager { // Check for ALLOW_MOCK_MODEM_PROPERTY and BOOT_ALLOW_MOCK_MODEM_PROPERTY on user builds if (isAllowed || isAllowedForBoot || DEBUG) { - if (serviceName != null) { + if (mRadioConfig != null) { statusRadioConfig = mRadioConfig.setModemService(serviceName); + } - //TODO: consider multi-sim case (b/210073692) - statusRil = mPhones[0].mCi.setModemService(serviceName); - } else { - statusRadioConfig = mRadioConfig.setModemService(null); - - //TODO: consider multi-sim case - statusRil = mPhones[0].mCi.setModemService(null); + if (!statusRadioConfig) { + loge("setModemService: switching modem service for radioconfig fail"); + return false; } - return statusRadioConfig && statusRil; + for (int i = 0; i < getPhoneCount(); i++) { + if (mPhones[i] != null) { + statusRil = mPhones[i].mCi.setModemService(serviceName); + } + + if (!statusRil) { + loge("setModemService: switch modem for radio " + i + " fail"); + + // Disconnect the switched service + mRadioConfig.setModemService(null); + for (int t = 0; t < i; t++) { + mPhones[t].mCi.setModemService(null); + } + return false; + } + } } else { loge("setModemService is not allowed"); return false; } + + return true; } /** @@ -503,7 +513,6 @@ public class PhoneConfigurationManager { * @return the service name of the connected service. */ public String getModemService() { - //TODO: consider multi-sim case if (mPhones[0] == null) { return ""; } -- GitLab From 2b552219eb9df5aad17587f83a96042e847328a4 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 21 Sep 2022 01:18:20 +0000 Subject: [PATCH 094/656] Revert "Added builder for SubscriptionInfo" Revert submission 19946716-subscription_info_refactoring Reason for revert: crash Reverted Changes: I820d47538:Added builder for SubscriptionInfo I8eb757960:Added builder for SubscriptionInfo Change-Id: I6c8f8650581e4be690a8a3a0c5f43ee451bb3b8a --- .../telephony/SubscriptionController.java | 181 +++++++++--------- .../telephony/FakeTelephonyProvider.java | 1 - .../internal/telephony/GsmCdmaPhoneTest.java | 21 +- .../MultiSimSettingControllerTest.java | 60 +++--- .../telephony/SubscriptionInfoTest.java | 102 +++++----- .../SubscriptionInfoUpdaterTest.java | 37 ++-- .../telephony/euicc/EuiccControllerTest.java | 43 ++--- 7 files changed, 213 insertions(+), 232 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index bc5577a639..f1f650348c 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -513,34 +513,33 @@ public class SubscriptionController extends ISub.Stub { /** * New SubInfoRecord instance and fill in detail info - * @param cursor The database cursor + * @param cursor * @return the query result of desired SubInfoRecord */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private SubscriptionInfo getSubInfoRecord(Cursor cursor) { - SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder(); int id = cursor.getInt(cursor.getColumnIndexOrThrow( SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID)); - builder.setId(id) - .setIccId(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.ICC_ID))) - .setSimSlotIndex(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.SIM_SLOT_INDEX))) - .setDisplayName(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.DISPLAY_NAME))) - .setCarrierName(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.CARRIER_NAME))) - .setNameSource(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.NAME_SOURCE))) - .setIconTint(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.HUE))) - .setDataRoaming(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.DATA_ROAMING))) - .setMcc(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.MCC_STRING))) - .setMnc(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.MNC_STRING))); - + String iccId = cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.ICC_ID)); + int simSlotIndex = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.SIM_SLOT_INDEX)); + String displayName = cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.DISPLAY_NAME)); + String carrierName = cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.CARRIER_NAME)); + int nameSource = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.NAME_SOURCE)); + int iconTint = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.HUE)); + String number = cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.NUMBER)); + int dataRoaming = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.DATA_ROAMING)); + String mcc = cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.MCC_STRING)); + String mnc = cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.MNC_STRING)); String ehplmnsRaw = cursor.getString(cursor.getColumnIndexOrThrow( SubscriptionManager.EHPLMNS)); String hplmnsRaw = cursor.getString(cursor.getColumnIndexOrThrow( @@ -548,63 +547,77 @@ public class SubscriptionController extends ISub.Stub { String[] ehplmns = ehplmnsRaw == null ? null : ehplmnsRaw.split(","); String[] hplmns = hplmnsRaw == null ? null : hplmnsRaw.split(","); - builder.setEhplmns(ehplmns).setHplmns(hplmns); - - - // CARD_ID is the private ICCID/EID string, also known as the card string - String cardString = cursor.getString(cursor.getColumnIndexOrThrow( + // cardId is the private ICCID/EID string, also known as the card string + String cardId = cursor.getString(cursor.getColumnIndexOrThrow( SubscriptionManager.CARD_ID)); - builder.setCardString(cardString); + String countryIso = cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.ISO_COUNTRY_CODE)); // publicCardId is the publicly exposed int card ID - int publicCardId = mUiccController.convertToPublicCardId(cardString); - builder.setCardId(publicCardId); - - builder.setCountryIso(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.ISO_COUNTRY_CODE))) - .setCarrierId(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.CARRIER_ID))); - + int publicCardId = mUiccController.convertToPublicCardId(cardId); boolean isEmbedded = cursor.getInt(cursor.getColumnIndexOrThrow( SubscriptionManager.IS_EMBEDDED)) == 1; - builder.setEmbedded(isEmbedded); + int carrierId = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.CARRIER_ID)); + UiccAccessRule[] accessRules; if (isEmbedded) { - builder.setNativeAccessRules(UiccAccessRule.decodeRules(cursor.getBlob( - cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES)))); - } - - builder.setCarrierConfigAccessRules(UiccAccessRule.decodeRules(cursor.getBlob( - cursor.getColumnIndexOrThrow( - SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS)))) - .setOpportunistic(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.IS_OPPORTUNISTIC)) == 1) - .setGroupUuid(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.GROUP_UUID))) - .setProfileClass(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.PROFILE_CLASS))) - .setPortIndex(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.PORT_INDEX))) - .setType(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.SUBSCRIPTION_TYPE))) - .setGroupOwner(getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER, - /*defaultVal*/ null)) - .setUiccApplicationsEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.UICC_APPLICATIONS_ENABLED)) == 1) - .setUsageSetting(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.USAGE_SETTING))); + accessRules = UiccAccessRule.decodeRules(cursor.getBlob( + cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES))); + } else { + accessRules = null; + } + UiccAccessRule[] carrierConfigAccessRules = UiccAccessRule.decodeRules(cursor.getBlob( + cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS))); + boolean isOpportunistic = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.IS_OPPORTUNISTIC)) == 1; + String groupUUID = cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.GROUP_UUID)); + int profileClass = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.PROFILE_CLASS)); + int portIndex = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.PORT_INDEX)); + int subType = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.SUBSCRIPTION_TYPE)); + String groupOwner = getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER, + /*defaultVal*/ null); + boolean areUiccApplicationsEnabled = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.UICC_APPLICATIONS_ENABLED)) == 1; + + int usageSetting = cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.USAGE_SETTING)); + + if (VDBG) { + String iccIdToPrint = SubscriptionInfo.givePrintableIccid(iccId); + String cardIdToPrint = SubscriptionInfo.givePrintableIccid(cardId); + logd("[getSubInfoRecord] id:" + id + " iccid:" + iccIdToPrint + " simSlotIndex:" + + simSlotIndex + " carrierid:" + carrierId + " displayName:" + displayName + + " nameSource:" + nameSource + " iconTint:" + iconTint + + " dataRoaming:" + dataRoaming + " mcc:" + mcc + " mnc:" + mnc + + " countIso:" + countryIso + " isEmbedded:" + + isEmbedded + " accessRules:" + Arrays.toString(accessRules) + + " carrierConfigAccessRules: " + Arrays.toString(carrierConfigAccessRules) + + " cardId:" + cardIdToPrint + " portIndex:" + portIndex + + " publicCardId:" + publicCardId + + " isOpportunistic:" + isOpportunistic + " groupUUID:" + groupUUID + + " profileClass:" + profileClass + " subscriptionType: " + subType + + " areUiccApplicationsEnabled: " + areUiccApplicationsEnabled + + " usageSetting: " + usageSetting); + } // If line1number has been set to a different number, use it instead. - String number = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.NUMBER)); String line1Number = mTelephonyManager.getLine1Number(id); if (!TextUtils.isEmpty(line1Number) && !line1Number.equals(number)) { number = line1Number; } - builder.setNumber(number); - // FIXME(b/210771052): constructing a complete SubscriptionInfo requires a port index, // but the port index isn't available here. Should it actually be part of SubscriptionInfo? - - return builder.build(); + SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName, + carrierName, nameSource, iconTint, number, dataRoaming, /* icon= */ null, + mcc, mnc, countryIso, isEmbedded, accessRules, cardId, publicCardId, + isOpportunistic, groupUUID, /* isGroupDisabled= */ false , carrierId, profileClass, + subType, groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled, + portIndex, usageSetting); + info.setAssociatedPlmns(ehplmns, hplmns); + return info; } private String getOptionalStringFromCursor(Cursor cursor, String column, String defaultVal) { @@ -3136,8 +3149,8 @@ public class SubscriptionController extends ISub.Stub { /** * Get the SIM state for the slot index. - * For Remote-SIMs, this method returns {@link IccCardConstants.State#UNKNOWN} - * @return SIM state as the ordinal of {@link IccCardConstants.State} + * For Remote-SIMs, this method returns {@link #IccCardConstants.State.UNKNOWN} + * @return SIM state as the ordinal of {@See IccCardConstants.State} */ @Override public int getSimStateForSlotIndex(int slotIndex) { @@ -4106,10 +4119,7 @@ public class SubscriptionController extends ISub.Stub { } // Can't find the existing SIM. - if (slotInfo == null) { - loge("Can't find the existing SIM."); - return false; - } + if (slotInfo == null) return false; // this for physical slot which has only one port if (enable && !slotInfo.getPorts().stream().findFirst().get().isActive()) { @@ -4359,16 +4369,16 @@ public class SubscriptionController extends ISub.Stub { if (hasIdentifierAccess && hasPhoneNumberAccess) { return subInfo; } - SubscriptionInfo.Builder result = new SubscriptionInfo.Builder(subInfo); + SubscriptionInfo result = new SubscriptionInfo(subInfo); if (!hasIdentifierAccess) { - result.setIccId(null); - result.setCardString(null); - result.setGroupUuid(null); + result.clearIccId(); + result.clearCardString(); + result.clearGroupUuid(); } if (!hasPhoneNumberAccess) { - result.setNumber(null); + result.clearNumber(); } - return result.build(); + return result; } private synchronized boolean addToSubIdList(int slotIndex, int subId, int subscriptionType) { @@ -4443,23 +4453,20 @@ public class SubscriptionController extends ISub.Stub { mCacheOpportunisticSubInfoList = subList; - for (int i = 0; i < mCacheOpportunisticSubInfoList.size(); i++) { - SubscriptionInfo info = mCacheOpportunisticSubInfoList.get(i); + for (SubscriptionInfo info : mCacheOpportunisticSubInfoList) { if (shouldDisableSubGroup(info.getGroupUuid())) { - SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder(info); - builder.setGroupDisabled(true); - mCacheOpportunisticSubInfoList.set(i, builder.build()); + info.setGroupDisabled(true); } } if (DBG_CACHE) { if (!mCacheOpportunisticSubInfoList.isEmpty()) { for (SubscriptionInfo si : mCacheOpportunisticSubInfoList) { - logd("[refreshCachedOpportunisticSubscriptionInfoList] Setting Cached " - + "info=" + si); + logd("[refreshCachedOpptSubscriptionInfoList] Setting Cached info=" + + si); } } else { - logdl("[refreshCachedOpportunisticSubscriptionInfoList]- no info return"); + logdl("[refreshCachedOpptSubscriptionInfoList]- no info return"); } } @@ -4640,7 +4647,7 @@ public class SubscriptionController extends ISub.Stub { * Sets the phone number for the given {@code subId}. * *

The only accepted {@code source} is {@link - * SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER}. + * SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER}. */ @Override public void setPhoneNumber(int subId, int source, String number, diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java index f1bba36a8b..16e1c7a6e9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java +++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java @@ -145,7 +145,6 @@ public class FakeTelephonyProvider extends MockContentProvider { @Override public Uri insert(Uri uri, ContentValues values) { - Log.d(TAG, "insert. values=" + values); SQLiteDatabase db = mDbHelper.getWritableDatabase(); long id = db.insert("siminfo", null, values); return ContentUris.withAppendedId(Telephony.SimInfo.CONTENT_URI, id); diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 3b9667b123..d8d81a6d22 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -1658,23 +1658,10 @@ public class GsmCdmaPhoneTest extends TelephonyTest { private SubscriptionInfo makeSubscriptionInfo(boolean isOpportunistic, int usageSetting) { - return new SubscriptionInfo.Builder() - .setId(1) - .setIccId("xxxxxxxxx") - .setSimSlotIndex(1) - .setDisplayName("Android Test") - .setDisplayName("Android Test") - .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) - .setNumber("8675309") - .setMcc("001") - .setMnc("01") - .setCountryIso("us") - .setEmbedded(true) - .setOpportunistic(isOpportunistic) - .setCarrierId(1) - .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING) - .setUsageSetting(usageSetting) - .build(); + return new SubscriptionInfo( + 1, "xxxxxxxxx", 1, "Android Test", "Android Test", 0, 0, "8675309", 0, + null, "001", "01", "us", true, null, null, 0, isOpportunistic, null, false, + 1, 1, 0, null, null, true, 0, usageSetting); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index 09493a18b0..fb7b64db43 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -89,38 +89,28 @@ public class MultiSimSettingControllerTest extends TelephonyTest { private DataSettingsManager mDataSettingsManagerMock2; private CommandsInterface mMockCi; - private final SubscriptionInfo mSubInfo1 = new SubscriptionInfo.Builder() - .setId(1) - .setIccId("subInfo1 IccId") - .setSimSlotIndex(0) - .setDisplayName("T-mobile") - .setCarrierName("T-mobile") - .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) - .setIconTint(255) - .setNumber("12345") - .setMcc("310") - .setMnc("260") - .setCountryIso("us") - .build(); - - private final SubscriptionInfo mSubInfo2 = new SubscriptionInfo.Builder(mSubInfo1) - .setId(2) - .setIccId("subInfo2 IccId") - .setGroupUuid(mGroupUuid1.toString()) - .build(); - - private final SubscriptionInfo mSubInfo3 = new SubscriptionInfo.Builder(mSubInfo1) - .setId(3) - .setIccId("subInfo3 IccId") - .setGroupUuid(mGroupUuid1.toString()) - .build(); - - private final SubscriptionInfo mSubInfo4 = new SubscriptionInfo.Builder(mSubInfo1) - .setId(4) - .setIccId("subInfo4 IccId") - .setGroupUuid(mGroupUuid1.toString()) - .build(); + private final SubscriptionInfo mSubInfo1 = new SubscriptionInfo(1, "subInfo1 IccId", 0, + "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", + "156", false, null, null); + + private final SubscriptionInfo mSubInfo2 = new SubscriptionInfo(2, "subInfo2 IccId", 1, + "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", + "156", false, null, null, -1, false, mGroupUuid1.toString(), false, + TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true, -1); + + private final SubscriptionInfo mSubInfo3 = new SubscriptionInfo(3, "subInfo3 IccId", -1, + "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", + "156", false, null, null, -1, false, mGroupUuid1.toString(), false, + TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true, -1); + + private final SubscriptionInfo mSubInfo4 = new SubscriptionInfo(4, "subInfo4 IccId", -1, + "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", + "156", false, null, null, -1, false, mGroupUuid1.toString(), false, + TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true, -1); @Before public void setUp() throws Exception { @@ -625,7 +615,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { public void testGroupedCbrs() throws Exception { // Mark sub 1 as opportunistic. replaceInstance(SubscriptionInfo.class, "mIsOpportunistic", mSubInfo1, true); - replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); doReturn(true).when(mSubControllerMock).isOpportunistic(1); // Make opportunistic sub 1 and sub 2 data enabled. doReturn(true).when(mPhoneMock1).isUserDataEnabled(); @@ -667,7 +657,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @SmallTest public void testGroupedPrimaryRemoved() throws Exception { // Create subscription grouping of subs 1 and 2. - replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock) @@ -723,7 +713,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { processAllMessages(); // Create subscription grouping. - replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock) .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); @@ -943,7 +933,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { public void onSubscriptionGroupChanged_allActiveSubArePartOfGroup() throws Exception { doReturn(3).when(mSubControllerMock).getDefaultDataSubId(); // Create subscription grouping of subs 1 and 2. - replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 1, true); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java index 7b1005998b..3f8543500f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java @@ -15,11 +15,12 @@ */ package com.android.internal.telephony; -import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import android.os.Parcel; import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; +import android.test.suitebuilder.annotation.SmallTest; import org.junit.After; import org.junit.Before; @@ -37,63 +38,78 @@ public class SubscriptionInfoTest { @Before public void setUp() throws Exception { - mSubscriptionInfoUT = new SubscriptionInfo.Builder() - .setId(1) - .setIccId("890126042XXXXXXXXXXX") - .setSimSlotIndex(0) - .setDisplayName("T-mobile") - .setCarrierName("T-mobile") - .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) - .setIconTint(255) - .setNumber("12345") - .setDataRoaming(SubscriptionManager.DATA_ROAMING_DISABLE) - .setMcc("310") - .setMnc("260") - .setEhplmns(EHPLMNS) - .setHplmns(HPLMNS) - .setCountryIso("us") - .build(); + mSubscriptionInfoUT = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, "T-mobile", + "T-mobile", 0, 255, "12345", 0, null, "310", "260", "156", false, null, null); + mSubscriptionInfoUT.setAssociatedPlmns(EHPLMNS, HPLMNS); } @Test + @SmallTest public void testSubProperties() { - assertThat(mSubscriptionInfoUT.getMcc()).isEqualTo(310); - assertThat(mSubscriptionInfoUT.getMccString()).isEqualTo("310"); - assertThat(mSubscriptionInfoUT.getMnc()).isEqualTo(260); - assertThat(mSubscriptionInfoUT.getMncString()).isEqualTo("260"); - assertThat(mSubscriptionInfoUT.getNumber()).isEqualTo("12345"); - assertThat(mSubscriptionInfoUT.getDataRoaming()).isEqualTo(0); - assertThat(mSubscriptionInfoUT.getDisplayName().toString()).isEqualTo("T-mobile"); - assertThat(mSubscriptionInfoUT.getCarrierName().toString()).isEqualTo("T-mobile"); - assertThat(mSubscriptionInfoUT.getCountryIso()).isEqualTo("us"); - assertThat(mSubscriptionInfoUT.getIconTint()).isEqualTo(255); - assertThat(mSubscriptionInfoUT.getNameSource()).isEqualTo(0); - assertThat(mSubscriptionInfoUT.getSubscriptionId()).isEqualTo(1); - assertThat(mSubscriptionInfoUT.getSimSlotIndex()).isEqualTo(0); - assertThat(mSubscriptionInfoUT.getIccId()).isEqualTo("890126042XXXXXXXXXXX"); + assertEquals(260, mSubscriptionInfoUT.getMnc()); + assertEquals(310, mSubscriptionInfoUT.getMcc()); + assertEquals("12345", mSubscriptionInfoUT.getNumber()); + assertEquals(0, mSubscriptionInfoUT.getDataRoaming()); + assertEquals("T-mobile", mSubscriptionInfoUT.getDisplayName()); + assertEquals("T-mobile", mSubscriptionInfoUT.getCarrierName()); + assertEquals("156", mSubscriptionInfoUT.getCountryIso()); + assertEquals(255, mSubscriptionInfoUT.getIconTint()); + assertEquals(0, mSubscriptionInfoUT.getNameSource()); + assertEquals(1, mSubscriptionInfoUT.getSubscriptionId()); + assertEquals(0, mSubscriptionInfoUT.getSimSlotIndex()); + assertEquals("890126042XXXXXXXXXXX", mSubscriptionInfoUT.getIccId()); } @Test + @SmallTest + public void testSetGetCarrierName() { + assertEquals("T-mobile", mSubscriptionInfoUT.getCarrierName()); + mSubscriptionInfoUT.setCarrierName("Verizon"); + assertEquals("Verizon", mSubscriptionInfoUT.getCarrierName()); + } + + @Test + @SmallTest + public void testSetGetDisplayName() { + assertEquals("T-mobile", mSubscriptionInfoUT.getDisplayName()); + mSubscriptionInfoUT.setDisplayName("Verizon"); + assertEquals("Verizon", mSubscriptionInfoUT.getDisplayName()); + } + + @Test + @SmallTest + public void testSetGetIconTint() { + assertEquals(255, mSubscriptionInfoUT.getIconTint()); + mSubscriptionInfoUT.setIconTint(0); + assertEquals(0, mSubscriptionInfoUT.getIconTint()); + } + + @Test + @SmallTest public void testParcelUnparcel() { Parcel p = Parcel.obtain(); mSubscriptionInfoUT.writeToParcel(p, 0); p.setDataPosition(0); SubscriptionInfo copy = SubscriptionInfo.CREATOR.createFromParcel(p); - assertThat(mSubscriptionInfoUT).isEqualTo(copy); + assertEquals(mSubscriptionInfoUT, copy); } @Test + @SmallTest public void testEquals() { - SubscriptionInfo copiedInfo = new SubscriptionInfo.Builder(mSubscriptionInfoUT).build(); - SubscriptionInfo differentDisplayName = new SubscriptionInfo.Builder(mSubscriptionInfoUT) - .setDisplayName("Different display name") - .build(); - SubscriptionInfo differentSubId = new SubscriptionInfo.Builder(mSubscriptionInfoUT) - .setId(1234) - .build(); + SubscriptionInfo copiedInfo = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, + "T-mobile", "T-mobile", 0, 255, "12345", 0, null, + "310", "260", "156", false, null, null); + copiedInfo.setAssociatedPlmns(EHPLMNS, HPLMNS); + SubscriptionInfo differentDisplayName = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, + "AT&T", "T-mobile", 0, 255, "12345", 0, null, + "310", "260", "156", false, null, null); + SubscriptionInfo differentSubId = new SubscriptionInfo(2, "890126042XXXXXXXXXXX", 0, + "AT&T", "T-mobile", 0, 255, "12345", 0, null, + "310", "260", "156", false, null, null); - assertThat(mSubscriptionInfoUT).isEqualTo(copiedInfo); - assertThat(mSubscriptionInfoUT).isNotEqualTo(differentDisplayName); - assertThat(mSubscriptionInfoUT).isNotEqualTo(differentSubId); + assertEquals(mSubscriptionInfoUT, copiedInfo); + assertNotEquals(mSubscriptionInfoUT, differentDisplayName); + assertNotEquals(mSubscriptionInfoUT, differentSubId); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java index 091ec2761c..ea38e2d828 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java @@ -601,16 +601,13 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { List subInfoList = new ArrayList<>(); // 1: not embedded, but has matching iccid with an embedded subscription. - subInfoList.add(new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setIccId("1") - .build()); + subInfoList.add(new SubscriptionInfo( + 0, "1", 0, "", "", 0, 0, "", 0, null, "0", "0", "", false /* isEmbedded */, + null /* accessRules */, null)); // 2: embedded but no longer present. - subInfoList.add(new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setIccId("2") - .setEmbedded(true) - .build()); + subInfoList.add(new SubscriptionInfo( + 0, "2", 0, "", "", 0, 0, "", 0, null, "0", "0", "", true /* isEmbedded */, + null /* accessRules */, null)); when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( new String[] { "1", "3"}, false /* removable */)).thenReturn(subInfoList); @@ -658,16 +655,13 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { List subInfoList = new ArrayList<>(); // 1: not embedded, but has matching iccid with an embedded subscription. - subInfoList.add(new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setIccId("1") - .build()); + subInfoList.add(new SubscriptionInfo( + 0, "1", 0, "", "", 0, 0, "", 0, null, "0", "0", "", false /* isEmbedded */, + null /* accessRules */, null)); // 2: embedded. - subInfoList.add(new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setIccId("2") - .setEmbedded(true) - .build()); + subInfoList.add(new SubscriptionInfo( + 0, "2", 0, "", "", 0, 0, "", 0, null, "0", "0", "", true /* isEmbedded */, + null /* accessRules */, null)); when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( new String[0], false /* removable */)).thenReturn(subInfoList); @@ -695,10 +689,9 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { List subInfoList = new ArrayList<>(); // 1: not embedded. - subInfoList.add(new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setIccId("1") - .build()); + subInfoList.add(new SubscriptionInfo( + 0, "1", 0, "", "", 0, 0, "", 0, null, "0", "0", "", false /* isEmbedded */, + null /* accessRules */, null)); when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( new String[0], false /* removable */)).thenReturn(subInfoList); 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 6f0759c74d..491c6903b1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java @@ -1258,16 +1258,10 @@ public class EuiccControllerTest extends TelephonyTest { private void setHasCarrierPrivilegesOnActiveSubscription(boolean hasPrivileges) throws Exception { - SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) - .setEmbedded(true); - if (hasPrivileges) { - builder.setNativeAccessRules(new UiccAccessRule[] { ACCESS_RULE }); - } - builder.setCardId(CARD_ID); - SubscriptionInfo subInfo = builder.build(); - + SubscriptionInfo subInfo = new SubscriptionInfo( + 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */, + hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", CARD_ID, + false, null, false, 0, 0, 0, null, null, true, 0); when(mSubscriptionManager.canManageSubscription(subInfo, PACKAGE_NAME)).thenReturn( hasPrivileges); when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn( @@ -1293,16 +1287,14 @@ public class EuiccControllerTest extends TelephonyTest { cardInfos.add(cardInfo2); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(cardInfos); - SubscriptionInfo subInfo1 = new SubscriptionInfo.Builder() - .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) - .setEmbedded(true) - .setCardId(CARD_ID) - .build(); - SubscriptionInfo subInfo2 = new SubscriptionInfo.Builder() - .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) - .setEmbedded(true) - .setCardId(2) - .build(); + SubscriptionInfo subInfo1 = new SubscriptionInfo( + 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */, + hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", CARD_ID, + false, null, false, 0, 0, 0, null, null, true, 0); + SubscriptionInfo subInfo2 = new SubscriptionInfo( + 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */, + hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", + 1 /* cardId */, false, null, false, 0, 0, 0, null, null, true, 0); when(mSubscriptionManager.canManageSubscription(subInfo1, PACKAGE_NAME)).thenReturn( hasPrivileges); when(mSubscriptionManager.canManageSubscription(subInfo2, PACKAGE_NAME)).thenReturn( @@ -1312,13 +1304,10 @@ public class EuiccControllerTest extends TelephonyTest { } private void prepareOperationSubscription(boolean hasPrivileges) throws Exception { - SubscriptionInfo subInfo = new SubscriptionInfo.Builder() - .setId(SUBSCRIPTION_ID) - .setIccId(ICC_ID) - .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) - .setEmbedded(true) - .setCardId(CARD_ID) - .build(); + SubscriptionInfo subInfo = new SubscriptionInfo( + SUBSCRIPTION_ID, ICC_ID, 0, "", "", 0, 0, "", 0, null, "0", "0", "", + true /* isEmbedded */, hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, + null); when(mSubscriptionManager.canManageSubscription(subInfo, PACKAGE_NAME)).thenReturn( hasPrivileges); when(mSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn( -- GitLab From d836a1bf764f800a8bc6369ae1817870a587a5d4 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Sat, 10 Sep 2022 19:46:32 -0700 Subject: [PATCH 095/656] Refactor validation before data switch refactor the validation before data switch flow to be subId generic instead of specific to opportunistic subId. Bug: 244064524 Test: existing cts+atest, manual data during phone call Change-Id: I0cbfaa195d42140426bea533fe83f1d73ac806e2 --- .../telephony/SubscriptionController.java | 2 +- .../telephony/data/PhoneSwitcher.java | 110 +++++++++++------- .../telephony/data/PhoneSwitcherTest.java | 75 ++++++++++++ 3 files changed, 146 insertions(+), 41 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 0095c17f59..d15aeba5d1 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -3600,7 +3600,7 @@ public class SubscriptionController extends ISub.Stub { return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; } - return phoneSwitcher.getOpportunisticDataSubscriptionId(); + return phoneSwitcher.getAutoSelectedDataSubId(); } finally { Binder.restoreCallingIdentity(token); } diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index cd81b0cb2e..ee8d157907 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -31,6 +31,7 @@ import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TE import static java.util.Arrays.copyOf; import android.annotation.NonNull; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; @@ -195,6 +196,7 @@ public class PhoneSwitcher extends Handler { @VisibleForTesting protected final CellularNetworkValidator mValidator; private int mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; + private int mLastAutoSelectedSwitchReason = -1; private boolean mPendingSwitchNeedValidation; @VisibleForTesting public final CellularNetworkValidator.ValidationCallback mValidationCallback = @@ -227,9 +229,12 @@ public class PhoneSwitcher extends Handler { // Internet data if mOpptDataSubId is not set. protected int mPrimaryDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - // mOpptDataSubId must be an active subscription. If it's set, it overrides mPrimaryDataSubId - // to be used for Internet data. - private int mOpptDataSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; + // The automatically suggested preferred data subId (by e.g. CBRS or auto data switch), a + // candidate for preferred data subId, which is eventually presided by + // updatePreferredDataPhoneId(). + // If CBRS/auto switch feature selects the primary data subId as the preferred data subId, + // its value will be DEFAULT_SUBSCRIPTION_ID. + private int mAutoSelectedDataSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; // The phone ID that has an active voice call. If set, and its mobile data setting is on, // it will become the mPreferredDataPhoneId. @@ -1148,7 +1153,7 @@ public class PhoneSwitcher extends Handler { if (VDBG) { log("mPrimaryDataSubId = " + mPrimaryDataSubId); - log("mOpptDataSubId = " + mOpptDataSubId); + log("mAutoSelectedDataSubId = " + mAutoSelectedDataSubId); for (int i = 0; i < mActiveModemCount; i++) { log(" phone[" + i + "] using sub[" + mPhoneSubscriptions[i] + "]"); } @@ -1310,8 +1315,8 @@ public class PhoneSwitcher extends Handler { } private int getSubIdForDefaultNetworkRequests() { - if (mSubscriptionController.isActiveSubId(mOpptDataSubId)) { - return mOpptDataSubId; + if (mSubscriptionController.isActiveSubId(mAutoSelectedDataSubId)) { + return mAutoSelectedDataSubId; } else { return mPrimaryDataSubId; } @@ -1451,22 +1456,35 @@ public class PhoneSwitcher extends Handler { */ private void setOpportunisticDataSubscription(int subId, boolean needValidation, ISetOpportunisticDataCallback callback) { - if (!mSubscriptionController.isActiveSubId(subId) - && subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - log("Can't switch data to inactive subId " + subId); - sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION); - return; - } - - // Remove EVENT_NETWORK_VALIDATION_DONE. Don't handle validation result of previously subId - // if queued. - removeMessages(EVENT_NETWORK_VALIDATION_DONE); - removeMessages(EVENT_NETWORK_AVAILABLE); + validate(subId, needValidation, + DataSwitch.Reason.DATA_SWITCH_REASON_CBRS, callback); + } + /** + * Try setup a new internet connection on the subId that's pending validation. If the validation + * succeeds, this subId will be evaluated for being the preferred data subId; If fails, nothing + * happens. + * Callback will be updated with the validation result. + * + * @param subId Sub Id that's pending switch, awaiting validation. + * @param needValidation {@code false} if switch to the subId even if validation fails. + * @param switchReason The switch reason for this validation + * @param callback Optional - specific for external opportunistic sub validation request. + */ + private void validate(int subId, boolean needValidation, int switchReason, + @Nullable ISetOpportunisticDataCallback callback) { int subIdToValidate = (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) ? mPrimaryDataSubId : subId; - - mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; + if (!mSubscriptionController.isActiveSubId(subIdToValidate)) { + log("Can't switch data to inactive subId " + subIdToValidate); + if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + // the default data sub is not selected yet, store the intent of switching to + // default subId once it becomes available. + mAutoSelectedDataSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; + } + sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION); + return; + } if (mValidator.isValidating()) { mValidator.stopValidation(); @@ -1474,22 +1492,29 @@ public class PhoneSwitcher extends Handler { mSetOpptSubCallback = null; } - if (subId == mOpptDataSubId) { + // Remove EVENT_NETWORK_VALIDATION_DONE. Don't handle validation result of previous subId + // if queued. + removeMessages(EVENT_NETWORK_VALIDATION_DONE); + removeMessages(EVENT_NETWORK_AVAILABLE); + + mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; + + if (subIdToValidate == mPreferredDataSubId.get()) { sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS); return; } - logDataSwitchEvent(subId == DEFAULT_SUBSCRIPTION_ID ? mPrimaryDataSubId : subId, + mLastAutoSelectedSwitchReason = switchReason; + logDataSwitchEvent(subIdToValidate, TelephonyEvent.EventState.EVENT_STATE_START, - DataSwitch.Reason.DATA_SWITCH_REASON_CBRS); - registerDefaultNetworkChangeCallback( - subId == DEFAULT_SUBSCRIPTION_ID ? mPrimaryDataSubId : subId, - DataSwitch.Reason.DATA_SWITCH_REASON_CBRS); + switchReason); + registerDefaultNetworkChangeCallback(subIdToValidate, + switchReason); // If validation feature is not supported, set it directly. Otherwise, // start validation on the subscription first. if (!mValidator.isValidationFeatureSupported()) { - setOpportunisticSubscriptionInternal(subId); + setAutoSelectedDataSubIdInternal(subIdToValidate); sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS); return; } @@ -1531,12 +1556,15 @@ public class PhoneSwitcher extends Handler { } /** - * Set opportunistic data subscription. + * Evaluate whether the specified sub Id can be set to be the preferred data sub Id. + * + * @param subId The subId that we tried to validate: could possibly be unvalidated if validation + * feature is not supported. */ - private void setOpportunisticSubscriptionInternal(int subId) { - if (mOpptDataSubId != subId) { - mOpptDataSubId = subId; - onEvaluate(REQUESTS_UNCHANGED, "oppt data subId changed"); + private void setAutoSelectedDataSubIdInternal(int subId) { + if (mAutoSelectedDataSubId != subId) { + mAutoSelectedDataSubId = subId; + onEvaluate(REQUESTS_UNCHANGED, switchReasonToString(mLastAutoSelectedSwitchReason)); } } @@ -1549,11 +1577,10 @@ public class PhoneSwitcher extends Handler { } else if (!confirm) { resultForCallBack = SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; } else { - if (mSubscriptionController.isOpportunistic(subId)) { - setOpportunisticSubscriptionInternal(subId); + if (subId == mPrimaryDataSubId) { + setAutoSelectedDataSubIdInternal(DEFAULT_SUBSCRIPTION_ID); } else { - // Switching data back to primary subscription. - setOpportunisticSubscriptionInternal(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); + setAutoSelectedDataSubIdInternal(subId); } resultForCallBack = SET_OPPORTUNISTIC_SUB_SUCCESS; } @@ -1623,10 +1650,6 @@ public class PhoneSwitcher extends Handler { ? HAL_COMMAND_PREFERRED_DATA : HAL_COMMAND_ALLOW_DATA; } - public int getOpportunisticDataSubscriptionId() { - return mOpptDataSubId; - } - public int getPreferredDataPhoneId() { return mPreferredDataPhoneId; } @@ -1708,6 +1731,13 @@ public class PhoneSwitcher extends Handler { return mPreferredDataSubId.get(); } + /** + * @return The auto selected data subscription id. + */ + public int getAutoSelectedDataSubId() { + 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) { @@ -1732,7 +1762,7 @@ public class PhoneSwitcher extends Handler { pw.println("DefaultDataPhoneId=" + mSubscriptionController.getPhoneId( mSubscriptionController.getDefaultDataSubId())); pw.println("mPrimaryDataSubId=" + mPrimaryDataSubId); - pw.println("mOpptDataSubId=" + mOpptDataSubId); + pw.println("mAutoSelectedDataSubId=" + mAutoSelectedDataSubId); pw.println("mIsRegisteredForImsRadioTechChange=" + mIsRegisteredForImsRadioTechChange); pw.println("mPendingSwitchNeedValidation=" + mPendingSwitchNeedValidation); pw.println("mMaxDataAttachModemCount=" + mMaxDataAttachModemCount); 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 487f7e33f2..646570557c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -477,6 +477,65 @@ public class PhoneSwitcherTest extends TelephonyTest { assertFalse(mDataAllowed[1]); } + /** + * TestSetPreferredData in the event of different priorities. + * The following events can set preferred data subId with priority in the order of + * 1. Emergency call + * 2. Voice call (when data during call feature is enabled). + * 3. CBRS requests + */ + @Test + @SmallTest + public void testSetPreferredDataCasePriority() 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); + + // Notify phoneSwitcher about default data sub and default network request. + NetworkRequest internetRequest = addInternetNetworkRequest(null, 50); + // Phone 0 (sub 1) should be activated as it has default data sub. + assertEquals(1, mPhoneSwitcher.getActiveDataSubId()); + assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 0)); + assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 1)); + + // Set sub 2 as preferred sub should make phone 1 activated and phone 0 deactivated. + mPhoneSwitcher.trySetOpportunisticDataSubscription(2, false, null); + processAllMessages(); + mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 2); + // A higher priority event occurring E.g. Phone1 has active IMS call on LTE. + doReturn(mImsPhone).when(mPhone).getImsPhone(); + doReturn(true).when(mDataSettingsManager).isDataEnabled(ApnSetting.TYPE_DEFAULT); + mockImsRegTech(1, REGISTRATION_TECH_LTE); + notifyPhoneAsInCall(mPhone); + + // switch shouldn't occur due to the higher priority event + assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 0)); + assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 1)); + assertEquals(1, mPhoneSwitcher.getActiveDataSubId()); + assertEquals(2, mPhoneSwitcher.getAutoSelectedDataSubId()); + + // The higher priority event ends, time to switch to auto selected subId. + notifyPhoneAsInactive(mPhone); + + assertEquals(2, mPhoneSwitcher.getActiveDataSubId()); + assertEquals(2, mPhoneSwitcher.getAutoSelectedDataSubId()); + assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 1)); + assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 0)); + + } + @Test @SmallTest public void testSetPreferredDataModemCommand() throws Exception { @@ -1084,7 +1143,23 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); + // Switch to primary before a primary is selected/inactive. + setDefaultDataSubId(-1); + mPhoneSwitcher.trySetOpportunisticDataSubscription( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, mSetOpptDataCallback1); + processAllMessages(); + + assertEquals(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mPhoneSwitcher.getAutoSelectedDataSubId()); + verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION); + + // once the primary is selected, it becomes the active sub. + setDefaultDataSubId(2); + assertEquals(2, mPhoneSwitcher.getActiveDataSubId()); + + setDefaultDataSubId(1); // Validating on sub 10 which is inactive. + clearInvocations(mSetOpptDataCallback1); mPhoneSwitcher.trySetOpportunisticDataSubscription(10, true, mSetOpptDataCallback1); processAllMessages(); verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION); -- GitLab From e317649a1c4f91ab756f0d93c57eeab9c3d96b16 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 14 Sep 2022 00:45:15 -0700 Subject: [PATCH 096/656] Added builder for SubscriptionInfo Added the builder for SubscriptionInfo, and make all members final. This can prevent other clients accidentally modifying the same copy of SubscriptionInfo. Also moved getAllAccessRules into getAccessRules. Bug: 239607619 Bug: 247140269 Test: Manual + atest SubscriptionInfoTest Change-Id: I14433c8c1d890fb403af255fbdfb9a2407b7baad --- .../telephony/SubscriptionController.java | 181 +++++++++--------- .../telephony/FakeTelephonyProvider.java | 1 + .../internal/telephony/GsmCdmaPhoneTest.java | 21 +- .../MultiSimSettingControllerTest.java | 60 +++--- .../telephony/SubscriptionInfoTest.java | 102 +++++----- .../SubscriptionInfoUpdaterTest.java | 37 ++-- .../telephony/euicc/EuiccControllerTest.java | 43 +++-- 7 files changed, 232 insertions(+), 213 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 0095c17f59..714b92f3cb 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -525,33 +525,34 @@ public class SubscriptionController extends ISub.Stub { /** * New SubInfoRecord instance and fill in detail info - * @param cursor + * @param cursor The database cursor * @return the query result of desired SubInfoRecord */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private SubscriptionInfo getSubInfoRecord(Cursor cursor) { + SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder(); int id = cursor.getInt(cursor.getColumnIndexOrThrow( SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID)); - String iccId = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.ICC_ID)); - int simSlotIndex = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.SIM_SLOT_INDEX)); - String displayName = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.DISPLAY_NAME)); - String carrierName = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.CARRIER_NAME)); - int nameSource = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.NAME_SOURCE)); - int iconTint = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.HUE)); - String number = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.NUMBER)); - int dataRoaming = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.DATA_ROAMING)); - String mcc = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.MCC_STRING)); - String mnc = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.MNC_STRING)); + builder.setId(id) + .setIccId(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.ICC_ID))) + .setSimSlotIndex(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.SIM_SLOT_INDEX))) + .setDisplayName(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.DISPLAY_NAME))) + .setCarrierName(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.CARRIER_NAME))) + .setNameSource(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.NAME_SOURCE))) + .setIconTint(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.HUE))) + .setDataRoaming(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.DATA_ROAMING))) + .setMcc(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.MCC_STRING))) + .setMnc(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.MNC_STRING))); + String ehplmnsRaw = cursor.getString(cursor.getColumnIndexOrThrow( SubscriptionManager.EHPLMNS)); String hplmnsRaw = cursor.getString(cursor.getColumnIndexOrThrow( @@ -559,77 +560,63 @@ public class SubscriptionController extends ISub.Stub { String[] ehplmns = ehplmnsRaw == null ? null : ehplmnsRaw.split(","); String[] hplmns = hplmnsRaw == null ? null : hplmnsRaw.split(","); - // cardId is the private ICCID/EID string, also known as the card string - String cardId = cursor.getString(cursor.getColumnIndexOrThrow( + builder.setEhplmns(ehplmns).setHplmns(hplmns); + + + // CARD_ID is the private ICCID/EID string, also known as the card string + String cardString = cursor.getString(cursor.getColumnIndexOrThrow( SubscriptionManager.CARD_ID)); - String countryIso = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.ISO_COUNTRY_CODE)); + builder.setCardString(cardString); // publicCardId is the publicly exposed int card ID - int publicCardId = mUiccController.convertToPublicCardId(cardId); + int publicCardId = mUiccController.convertToPublicCardId(cardString); + builder.setCardId(publicCardId); + + builder.setCountryIso(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.ISO_COUNTRY_CODE))) + .setCarrierId(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.CARRIER_ID))); + boolean isEmbedded = cursor.getInt(cursor.getColumnIndexOrThrow( SubscriptionManager.IS_EMBEDDED)) == 1; - int carrierId = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.CARRIER_ID)); - UiccAccessRule[] accessRules; + builder.setEmbedded(isEmbedded); if (isEmbedded) { - accessRules = UiccAccessRule.decodeRules(cursor.getBlob( - cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES))); - } else { - accessRules = null; - } - UiccAccessRule[] carrierConfigAccessRules = UiccAccessRule.decodeRules(cursor.getBlob( - cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS))); - boolean isOpportunistic = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.IS_OPPORTUNISTIC)) == 1; - String groupUUID = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.GROUP_UUID)); - int profileClass = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.PROFILE_CLASS)); - int portIndex = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.PORT_INDEX)); - int subType = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.SUBSCRIPTION_TYPE)); - String groupOwner = getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER, - /*defaultVal*/ null); - boolean areUiccApplicationsEnabled = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.UICC_APPLICATIONS_ENABLED)) == 1; - - int usageSetting = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.USAGE_SETTING)); - - if (VDBG) { - String iccIdToPrint = SubscriptionInfo.givePrintableIccid(iccId); - String cardIdToPrint = SubscriptionInfo.givePrintableIccid(cardId); - logd("[getSubInfoRecord] id:" + id + " iccid:" + iccIdToPrint + " simSlotIndex:" - + simSlotIndex + " carrierid:" + carrierId + " displayName:" + displayName - + " nameSource:" + nameSource + " iconTint:" + iconTint - + " dataRoaming:" + dataRoaming + " mcc:" + mcc + " mnc:" + mnc - + " countIso:" + countryIso + " isEmbedded:" - + isEmbedded + " accessRules:" + Arrays.toString(accessRules) - + " carrierConfigAccessRules: " + Arrays.toString(carrierConfigAccessRules) - + " cardId:" + cardIdToPrint + " portIndex:" + portIndex - + " publicCardId:" + publicCardId - + " isOpportunistic:" + isOpportunistic + " groupUUID:" + groupUUID - + " profileClass:" + profileClass + " subscriptionType: " + subType - + " areUiccApplicationsEnabled: " + areUiccApplicationsEnabled - + " usageSetting: " + usageSetting); - } + builder.setNativeAccessRules(UiccAccessRule.decodeRules(cursor.getBlob( + cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES)))); + } + + builder.setCarrierConfigAccessRules(UiccAccessRule.decodeRules(cursor.getBlob( + cursor.getColumnIndexOrThrow( + SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS)))) + .setOpportunistic(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.IS_OPPORTUNISTIC)) == 1) + .setGroupUuid(cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.GROUP_UUID))) + .setProfileClass(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.PROFILE_CLASS))) + .setPortIndex(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.PORT_INDEX))) + .setType(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.SUBSCRIPTION_TYPE))) + .setGroupOwner(getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER, + /*defaultVal*/ null)) + .setUiccApplicationsEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.UICC_APPLICATIONS_ENABLED)) == 1) + .setUsageSetting(cursor.getInt(cursor.getColumnIndexOrThrow( + SubscriptionManager.USAGE_SETTING))); // If line1number has been set to a different number, use it instead. + String number = cursor.getString(cursor.getColumnIndexOrThrow( + SubscriptionManager.NUMBER)); String line1Number = mTelephonyManager.getLine1Number(id); if (!TextUtils.isEmpty(line1Number) && !line1Number.equals(number)) { number = line1Number; } + builder.setNumber(number); + // FIXME(b/210771052): constructing a complete SubscriptionInfo requires a port index, // but the port index isn't available here. Should it actually be part of SubscriptionInfo? - SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName, - carrierName, nameSource, iconTint, number, dataRoaming, /* icon= */ null, - mcc, mnc, countryIso, isEmbedded, accessRules, cardId, publicCardId, - isOpportunistic, groupUUID, /* isGroupDisabled= */ false , carrierId, profileClass, - subType, groupOwner, carrierConfigAccessRules, areUiccApplicationsEnabled, - portIndex, usageSetting); - info.setAssociatedPlmns(ehplmns, hplmns); - return info; + + return builder.build(); } private String getOptionalStringFromCursor(Cursor cursor, String column, String defaultVal) { @@ -3161,8 +3148,8 @@ public class SubscriptionController extends ISub.Stub { /** * Get the SIM state for the slot index. - * For Remote-SIMs, this method returns {@link #IccCardConstants.State.UNKNOWN} - * @return SIM state as the ordinal of {@See IccCardConstants.State} + * For Remote-SIMs, this method returns {@link IccCardConstants.State#UNKNOWN} + * @return SIM state as the ordinal of {@link IccCardConstants.State} */ @Override public int getSimStateForSlotIndex(int slotIndex) { @@ -4158,7 +4145,10 @@ public class SubscriptionController extends ISub.Stub { } // Can't find the existing SIM. - if (slotInfo == null) return false; + if (slotInfo == null) { + loge("Can't find the existing SIM."); + return false; + } // this for physical slot which has only one port if (enable && !slotInfo.getPorts().stream().findFirst().get().isActive()) { @@ -4408,16 +4398,16 @@ public class SubscriptionController extends ISub.Stub { if (hasIdentifierAccess && hasPhoneNumberAccess) { return subInfo; } - SubscriptionInfo result = new SubscriptionInfo(subInfo); + SubscriptionInfo.Builder result = new SubscriptionInfo.Builder(subInfo); if (!hasIdentifierAccess) { - result.clearIccId(); - result.clearCardString(); - result.clearGroupUuid(); + result.setIccId(null); + result.setCardString(null); + result.setGroupUuid(null); } if (!hasPhoneNumberAccess) { - result.clearNumber(); + result.setNumber(null); } - return result; + return result.build(); } private synchronized boolean addToSubIdList(int slotIndex, int subId, int subscriptionType) { @@ -4492,20 +4482,23 @@ public class SubscriptionController extends ISub.Stub { mCacheOpportunisticSubInfoList = subList; - for (SubscriptionInfo info : mCacheOpportunisticSubInfoList) { + for (int i = 0; i < mCacheOpportunisticSubInfoList.size(); i++) { + SubscriptionInfo info = mCacheOpportunisticSubInfoList.get(i); if (shouldDisableSubGroup(info.getGroupUuid())) { - info.setGroupDisabled(true); + SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder(info); + builder.setGroupDisabled(true); + mCacheOpportunisticSubInfoList.set(i, builder.build()); } } if (DBG_CACHE) { if (!mCacheOpportunisticSubInfoList.isEmpty()) { for (SubscriptionInfo si : mCacheOpportunisticSubInfoList) { - logd("[refreshCachedOpptSubscriptionInfoList] Setting Cached info=" - + si); + logd("[refreshCachedOpportunisticSubscriptionInfoList] Setting Cached " + + "info=" + si); } } else { - logdl("[refreshCachedOpptSubscriptionInfoList]- no info return"); + logdl("[refreshCachedOpportunisticSubscriptionInfoList]- no info return"); } } @@ -4686,7 +4679,7 @@ public class SubscriptionController extends ISub.Stub { * Sets the phone number for the given {@code subId}. * *

The only accepted {@code source} is {@link - * SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER}. + * SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER}. */ @Override public void setPhoneNumber(int subId, int source, String number, diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java index 16e1c7a6e9..f1bba36a8b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java +++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java @@ -145,6 +145,7 @@ public class FakeTelephonyProvider extends MockContentProvider { @Override public Uri insert(Uri uri, ContentValues values) { + Log.d(TAG, "insert. values=" + values); SQLiteDatabase db = mDbHelper.getWritableDatabase(); long id = db.insert("siminfo", null, values); return ContentUris.withAppendedId(Telephony.SimInfo.CONTENT_URI, id); diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index d8d81a6d22..3b9667b123 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -1658,10 +1658,23 @@ public class GsmCdmaPhoneTest extends TelephonyTest { private SubscriptionInfo makeSubscriptionInfo(boolean isOpportunistic, int usageSetting) { - return new SubscriptionInfo( - 1, "xxxxxxxxx", 1, "Android Test", "Android Test", 0, 0, "8675309", 0, - null, "001", "01", "us", true, null, null, 0, isOpportunistic, null, false, - 1, 1, 0, null, null, true, 0, usageSetting); + return new SubscriptionInfo.Builder() + .setId(1) + .setIccId("xxxxxxxxx") + .setSimSlotIndex(1) + .setDisplayName("Android Test") + .setDisplayName("Android Test") + .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) + .setNumber("8675309") + .setMcc("001") + .setMnc("01") + .setCountryIso("us") + .setEmbedded(true) + .setOpportunistic(isOpportunistic) + .setCarrierId(1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING) + .setUsageSetting(usageSetting) + .build(); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index fb7b64db43..09493a18b0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -89,28 +89,38 @@ public class MultiSimSettingControllerTest extends TelephonyTest { private DataSettingsManager mDataSettingsManagerMock2; private CommandsInterface mMockCi; + private final SubscriptionInfo mSubInfo1 = new SubscriptionInfo.Builder() + .setId(1) + .setIccId("subInfo1 IccId") + .setSimSlotIndex(0) + .setDisplayName("T-mobile") + .setCarrierName("T-mobile") + .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) + .setIconTint(255) + .setNumber("12345") + .setMcc("310") + .setMnc("260") + .setCountryIso("us") + .build(); + + private final SubscriptionInfo mSubInfo2 = new SubscriptionInfo.Builder(mSubInfo1) + .setId(2) + .setIccId("subInfo2 IccId") + .setGroupUuid(mGroupUuid1.toString()) + .build(); + + private final SubscriptionInfo mSubInfo3 = new SubscriptionInfo.Builder(mSubInfo1) + .setId(3) + .setIccId("subInfo3 IccId") + .setGroupUuid(mGroupUuid1.toString()) + .build(); + + private final SubscriptionInfo mSubInfo4 = new SubscriptionInfo.Builder(mSubInfo1) + .setId(4) + .setIccId("subInfo4 IccId") + .setGroupUuid(mGroupUuid1.toString()) + .build(); - private final SubscriptionInfo mSubInfo1 = new SubscriptionInfo(1, "subInfo1 IccId", 0, - "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", - "156", false, null, null); - - private final SubscriptionInfo mSubInfo2 = new SubscriptionInfo(2, "subInfo2 IccId", 1, - "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", - "156", false, null, null, -1, false, mGroupUuid1.toString(), false, - TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true, -1); - - private final SubscriptionInfo mSubInfo3 = new SubscriptionInfo(3, "subInfo3 IccId", -1, - "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", - "156", false, null, null, -1, false, mGroupUuid1.toString(), false, - TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true, -1); - - private final SubscriptionInfo mSubInfo4 = new SubscriptionInfo(4, "subInfo4 IccId", -1, - "T-mobile", "T-mobile", 0, 255, "12345", 0, null, "310", "260", - "156", false, null, null, -1, false, mGroupUuid1.toString(), false, - TelephonyManager.UNKNOWN_CARRIER_ID, SubscriptionManager.PROFILE_CLASS_DEFAULT, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM, null, null, true, -1); @Before public void setUp() throws Exception { @@ -615,7 +625,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { public void testGroupedCbrs() throws Exception { // Mark sub 1 as opportunistic. replaceInstance(SubscriptionInfo.class, "mIsOpportunistic", mSubInfo1, true); - replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); doReturn(true).when(mSubControllerMock).isOpportunistic(1); // Make opportunistic sub 1 and sub 2 data enabled. doReturn(true).when(mPhoneMock1).isUserDataEnabled(); @@ -657,7 +667,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @SmallTest public void testGroupedPrimaryRemoved() throws Exception { // Create subscription grouping of subs 1 and 2. - replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock) @@ -713,7 +723,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { processAllMessages(); // Create subscription grouping. - replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock) .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); @@ -933,7 +943,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { public void onSubscriptionGroupChanged_allActiveSubArePartOfGroup() throws Exception { doReturn(3).when(mSubControllerMock).getDefaultDataSubId(); // Create subscription grouping of subs 1 and 2. - replaceInstance(SubscriptionInfo.class, "mGroupUUID", mSubInfo1, mGroupUuid1); + replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 1, true); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java index 3f8543500f..7b1005998b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java @@ -15,12 +15,11 @@ */ package com.android.internal.telephony; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static com.google.common.truth.Truth.assertThat; import android.os.Parcel; import android.telephony.SubscriptionInfo; -import android.test.suitebuilder.annotation.SmallTest; +import android.telephony.SubscriptionManager; import org.junit.After; import org.junit.Before; @@ -38,78 +37,63 @@ public class SubscriptionInfoTest { @Before public void setUp() throws Exception { - mSubscriptionInfoUT = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, "T-mobile", - "T-mobile", 0, 255, "12345", 0, null, "310", "260", "156", false, null, null); - mSubscriptionInfoUT.setAssociatedPlmns(EHPLMNS, HPLMNS); + mSubscriptionInfoUT = new SubscriptionInfo.Builder() + .setId(1) + .setIccId("890126042XXXXXXXXXXX") + .setSimSlotIndex(0) + .setDisplayName("T-mobile") + .setCarrierName("T-mobile") + .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) + .setIconTint(255) + .setNumber("12345") + .setDataRoaming(SubscriptionManager.DATA_ROAMING_DISABLE) + .setMcc("310") + .setMnc("260") + .setEhplmns(EHPLMNS) + .setHplmns(HPLMNS) + .setCountryIso("us") + .build(); } @Test - @SmallTest public void testSubProperties() { - assertEquals(260, mSubscriptionInfoUT.getMnc()); - assertEquals(310, mSubscriptionInfoUT.getMcc()); - assertEquals("12345", mSubscriptionInfoUT.getNumber()); - assertEquals(0, mSubscriptionInfoUT.getDataRoaming()); - assertEquals("T-mobile", mSubscriptionInfoUT.getDisplayName()); - assertEquals("T-mobile", mSubscriptionInfoUT.getCarrierName()); - assertEquals("156", mSubscriptionInfoUT.getCountryIso()); - assertEquals(255, mSubscriptionInfoUT.getIconTint()); - assertEquals(0, mSubscriptionInfoUT.getNameSource()); - assertEquals(1, mSubscriptionInfoUT.getSubscriptionId()); - assertEquals(0, mSubscriptionInfoUT.getSimSlotIndex()); - assertEquals("890126042XXXXXXXXXXX", mSubscriptionInfoUT.getIccId()); + assertThat(mSubscriptionInfoUT.getMcc()).isEqualTo(310); + assertThat(mSubscriptionInfoUT.getMccString()).isEqualTo("310"); + assertThat(mSubscriptionInfoUT.getMnc()).isEqualTo(260); + assertThat(mSubscriptionInfoUT.getMncString()).isEqualTo("260"); + assertThat(mSubscriptionInfoUT.getNumber()).isEqualTo("12345"); + assertThat(mSubscriptionInfoUT.getDataRoaming()).isEqualTo(0); + assertThat(mSubscriptionInfoUT.getDisplayName().toString()).isEqualTo("T-mobile"); + assertThat(mSubscriptionInfoUT.getCarrierName().toString()).isEqualTo("T-mobile"); + assertThat(mSubscriptionInfoUT.getCountryIso()).isEqualTo("us"); + assertThat(mSubscriptionInfoUT.getIconTint()).isEqualTo(255); + assertThat(mSubscriptionInfoUT.getNameSource()).isEqualTo(0); + assertThat(mSubscriptionInfoUT.getSubscriptionId()).isEqualTo(1); + assertThat(mSubscriptionInfoUT.getSimSlotIndex()).isEqualTo(0); + assertThat(mSubscriptionInfoUT.getIccId()).isEqualTo("890126042XXXXXXXXXXX"); } @Test - @SmallTest - public void testSetGetCarrierName() { - assertEquals("T-mobile", mSubscriptionInfoUT.getCarrierName()); - mSubscriptionInfoUT.setCarrierName("Verizon"); - assertEquals("Verizon", mSubscriptionInfoUT.getCarrierName()); - } - - @Test - @SmallTest - public void testSetGetDisplayName() { - assertEquals("T-mobile", mSubscriptionInfoUT.getDisplayName()); - mSubscriptionInfoUT.setDisplayName("Verizon"); - assertEquals("Verizon", mSubscriptionInfoUT.getDisplayName()); - } - - @Test - @SmallTest - public void testSetGetIconTint() { - assertEquals(255, mSubscriptionInfoUT.getIconTint()); - mSubscriptionInfoUT.setIconTint(0); - assertEquals(0, mSubscriptionInfoUT.getIconTint()); - } - - @Test - @SmallTest public void testParcelUnparcel() { Parcel p = Parcel.obtain(); mSubscriptionInfoUT.writeToParcel(p, 0); p.setDataPosition(0); SubscriptionInfo copy = SubscriptionInfo.CREATOR.createFromParcel(p); - assertEquals(mSubscriptionInfoUT, copy); + assertThat(mSubscriptionInfoUT).isEqualTo(copy); } @Test - @SmallTest public void testEquals() { - SubscriptionInfo copiedInfo = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, - "T-mobile", "T-mobile", 0, 255, "12345", 0, null, - "310", "260", "156", false, null, null); - copiedInfo.setAssociatedPlmns(EHPLMNS, HPLMNS); - SubscriptionInfo differentDisplayName = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, - "AT&T", "T-mobile", 0, 255, "12345", 0, null, - "310", "260", "156", false, null, null); - SubscriptionInfo differentSubId = new SubscriptionInfo(2, "890126042XXXXXXXXXXX", 0, - "AT&T", "T-mobile", 0, 255, "12345", 0, null, - "310", "260", "156", false, null, null); + SubscriptionInfo copiedInfo = new SubscriptionInfo.Builder(mSubscriptionInfoUT).build(); + SubscriptionInfo differentDisplayName = new SubscriptionInfo.Builder(mSubscriptionInfoUT) + .setDisplayName("Different display name") + .build(); + SubscriptionInfo differentSubId = new SubscriptionInfo.Builder(mSubscriptionInfoUT) + .setId(1234) + .build(); - assertEquals(mSubscriptionInfoUT, copiedInfo); - assertNotEquals(mSubscriptionInfoUT, differentDisplayName); - assertNotEquals(mSubscriptionInfoUT, differentSubId); + assertThat(mSubscriptionInfoUT).isEqualTo(copiedInfo); + assertThat(mSubscriptionInfoUT).isNotEqualTo(differentDisplayName); + assertThat(mSubscriptionInfoUT).isNotEqualTo(differentSubId); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java index ea38e2d828..091ec2761c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java @@ -601,13 +601,16 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { List subInfoList = new ArrayList<>(); // 1: not embedded, but has matching iccid with an embedded subscription. - subInfoList.add(new SubscriptionInfo( - 0, "1", 0, "", "", 0, 0, "", 0, null, "0", "0", "", false /* isEmbedded */, - null /* accessRules */, null)); + subInfoList.add(new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setIccId("1") + .build()); // 2: embedded but no longer present. - subInfoList.add(new SubscriptionInfo( - 0, "2", 0, "", "", 0, 0, "", 0, null, "0", "0", "", true /* isEmbedded */, - null /* accessRules */, null)); + subInfoList.add(new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setIccId("2") + .setEmbedded(true) + .build()); when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( new String[] { "1", "3"}, false /* removable */)).thenReturn(subInfoList); @@ -655,13 +658,16 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { List subInfoList = new ArrayList<>(); // 1: not embedded, but has matching iccid with an embedded subscription. - subInfoList.add(new SubscriptionInfo( - 0, "1", 0, "", "", 0, 0, "", 0, null, "0", "0", "", false /* isEmbedded */, - null /* accessRules */, null)); + subInfoList.add(new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setIccId("1") + .build()); // 2: embedded. - subInfoList.add(new SubscriptionInfo( - 0, "2", 0, "", "", 0, 0, "", 0, null, "0", "0", "", true /* isEmbedded */, - null /* accessRules */, null)); + subInfoList.add(new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setIccId("2") + .setEmbedded(true) + .build()); when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( new String[0], false /* removable */)).thenReturn(subInfoList); @@ -689,9 +695,10 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { List subInfoList = new ArrayList<>(); // 1: not embedded. - subInfoList.add(new SubscriptionInfo( - 0, "1", 0, "", "", 0, 0, "", 0, null, "0", "0", "", false /* isEmbedded */, - null /* accessRules */, null)); + subInfoList.add(new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setIccId("1") + .build()); when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( new String[0], false /* removable */)).thenReturn(subInfoList); 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 491c6903b1..6f0759c74d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java @@ -1258,10 +1258,16 @@ public class EuiccControllerTest extends TelephonyTest { private void setHasCarrierPrivilegesOnActiveSubscription(boolean hasPrivileges) throws Exception { - SubscriptionInfo subInfo = new SubscriptionInfo( - 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */, - hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", CARD_ID, - false, null, false, 0, 0, 0, null, null, true, 0); + SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder() + .setSimSlotIndex(0) + .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) + .setEmbedded(true); + if (hasPrivileges) { + builder.setNativeAccessRules(new UiccAccessRule[] { ACCESS_RULE }); + } + builder.setCardId(CARD_ID); + SubscriptionInfo subInfo = builder.build(); + when(mSubscriptionManager.canManageSubscription(subInfo, PACKAGE_NAME)).thenReturn( hasPrivileges); when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn( @@ -1287,14 +1293,16 @@ public class EuiccControllerTest extends TelephonyTest { cardInfos.add(cardInfo2); when(mTelephonyManager.getUiccCardsInfo()).thenReturn(cardInfos); - SubscriptionInfo subInfo1 = new SubscriptionInfo( - 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */, - hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", CARD_ID, - false, null, false, 0, 0, 0, null, null, true, 0); - SubscriptionInfo subInfo2 = new SubscriptionInfo( - 0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */, - hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", - 1 /* cardId */, false, null, false, 0, 0, 0, null, null, true, 0); + SubscriptionInfo subInfo1 = new SubscriptionInfo.Builder() + .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) + .setEmbedded(true) + .setCardId(CARD_ID) + .build(); + SubscriptionInfo subInfo2 = new SubscriptionInfo.Builder() + .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) + .setEmbedded(true) + .setCardId(2) + .build(); when(mSubscriptionManager.canManageSubscription(subInfo1, PACKAGE_NAME)).thenReturn( hasPrivileges); when(mSubscriptionManager.canManageSubscription(subInfo2, PACKAGE_NAME)).thenReturn( @@ -1304,10 +1312,13 @@ public class EuiccControllerTest extends TelephonyTest { } private void prepareOperationSubscription(boolean hasPrivileges) throws Exception { - SubscriptionInfo subInfo = new SubscriptionInfo( - SUBSCRIPTION_ID, ICC_ID, 0, "", "", 0, 0, "", 0, null, "0", "0", "", - true /* isEmbedded */, hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, - null); + SubscriptionInfo subInfo = new SubscriptionInfo.Builder() + .setId(SUBSCRIPTION_ID) + .setIccId(ICC_ID) + .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) + .setEmbedded(true) + .setCardId(CARD_ID) + .build(); when(mSubscriptionManager.canManageSubscription(subInfo, PACKAGE_NAME)).thenReturn( hasPrivileges); when(mSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn( -- GitLab From 0bc2239e9eace5c8bb46a15dffd6716bb50fd105 Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Thu, 22 Sep 2022 14:09:34 +0000 Subject: [PATCH 097/656] Support Unit test : For 3g ECNO Measurement type Bug: 247985661 Test: atest FrameworksTelephonyTests Change-Id: I76682798dd979c4607f289b3306f0cfd576bfc81 --- .../telephony/SignalThresholdInfoTest.java | 546 +++++++++++------- 1 file changed, 324 insertions(+), 222 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java index b282c55cbf..5f39c0937b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java @@ -42,69 +42,94 @@ import java.util.Set; public class SignalThresholdInfoTest extends TestCase { private static final int HYSTERESIS_DB = 2; private static final int HYSTERESIS_MS = 30; - private static final int[] SSRSRP_THRESHOLDS = new int[]{-120, -100, -80, -60}; + private static final int[] SSRSRP_THRESHOLDS = new int[] {-120, -100, -80, -60}; // Map of SignalMeasurementType to invalid thresholds edge values. // Each invalid value will be constructed with a thresholds array to test separately. - private static final Map> INVALID_THRESHOLDS_MAP = Map.of( - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, - List.of(SignalThresholdInfo.SIGNAL_RSSI_MIN_VALUE - 1, - SignalThresholdInfo.SIGNAL_RSSI_MAX_VALUE + 1), - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP, - List.of(SignalThresholdInfo.SIGNAL_RSCP_MIN_VALUE - 1, - SignalThresholdInfo.SIGNAL_RSCP_MAX_VALUE + 1), - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP, - List.of(SignalThresholdInfo.SIGNAL_RSRP_MIN_VALUE - 1, - SignalThresholdInfo.SIGNAL_RSRP_MAX_VALUE + 1), - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ, - List.of(SignalThresholdInfo.SIGNAL_RSRQ_MIN_VALUE - 1, - SignalThresholdInfo.SIGNAL_RSRQ_MAX_VALUE + 1), - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR, - List.of(SignalThresholdInfo.SIGNAL_RSSNR_MIN_VALUE - 1, - SignalThresholdInfo.SIGNAL_RSSNR_MAX_VALUE + 1), - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP, - List.of(SignalThresholdInfo.SIGNAL_SSRSRP_MIN_VALUE - 1, - SignalThresholdInfo.SIGNAL_SSRSRP_MAX_VALUE + 1), - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ, - List.of(SignalThresholdInfo.SIGNAL_SSRSRQ_MIN_VALUE - 1, - SignalThresholdInfo.SIGNAL_SSRSRQ_MAX_VALUE + 1), - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR, - List.of(SignalThresholdInfo.SIGNAL_SSSINR_MIN_VALUE - 1, - SignalThresholdInfo.SIGNAL_SSSINR_MAX_VALUE + 1) - ); + private static final Map> INVALID_THRESHOLDS_MAP = + Map.of( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, + List.of( + SignalThresholdInfo.SIGNAL_RSSI_MIN_VALUE - 1, + SignalThresholdInfo.SIGNAL_RSSI_MAX_VALUE + 1), + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP, + List.of( + SignalThresholdInfo.SIGNAL_RSCP_MIN_VALUE - 1, + SignalThresholdInfo.SIGNAL_RSCP_MAX_VALUE + 1), + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP, + List.of( + SignalThresholdInfo.SIGNAL_RSRP_MIN_VALUE - 1, + SignalThresholdInfo.SIGNAL_RSRP_MAX_VALUE + 1), + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ, + List.of( + SignalThresholdInfo.SIGNAL_RSRQ_MIN_VALUE - 1, + SignalThresholdInfo.SIGNAL_RSRQ_MAX_VALUE + 1), + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR, + List.of( + SignalThresholdInfo.SIGNAL_RSSNR_MIN_VALUE - 1, + SignalThresholdInfo.SIGNAL_RSSNR_MAX_VALUE + 1), + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP, + List.of( + SignalThresholdInfo.SIGNAL_SSRSRP_MIN_VALUE - 1, + SignalThresholdInfo.SIGNAL_SSRSRP_MAX_VALUE + 1), + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ, + List.of( + SignalThresholdInfo.SIGNAL_SSRSRQ_MIN_VALUE - 1, + SignalThresholdInfo.SIGNAL_SSRSRQ_MAX_VALUE + 1), + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR, + List.of( + SignalThresholdInfo.SIGNAL_SSSINR_MIN_VALUE - 1, + SignalThresholdInfo.SIGNAL_SSSINR_MAX_VALUE + 1), + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO, + List.of( + SignalThresholdInfo.SIGNAL_ECNO_MIN_VALUE - 1, + SignalThresholdInfo.SIGNAL_ECNO_MAX_VALUE + 1)); // Map of RAN to allowed SignalMeasurementType set. // RAN/TYPE pair will be used to verify the validation of the combo - private static final Map> VALID_RAN_TO_MEASUREMENT_TYPE_MAP = Map.of( - AccessNetworkConstants.AccessNetworkType.GERAN, - Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI), - AccessNetworkConstants.AccessNetworkType.CDMA2000, - Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI), - AccessNetworkConstants.AccessNetworkType.UTRAN, - Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP), - AccessNetworkConstants.AccessNetworkType.EUTRAN, - Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP, - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ, - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR), - AccessNetworkConstants.AccessNetworkType.NGRAN, - Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP, - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ, - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR) - ); + private static final Map> VALID_RAN_TO_MEASUREMENT_TYPE_MAP = + Map.of( + AccessNetworkConstants.AccessNetworkType.GERAN, + Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI), + AccessNetworkConstants.AccessNetworkType.CDMA2000, + Set.of(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI), + AccessNetworkConstants.AccessNetworkType.UTRAN, + Set.of( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP, + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO), + AccessNetworkConstants.AccessNetworkType.EUTRAN, + Set.of( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP, + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ, + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR), + AccessNetworkConstants.AccessNetworkType.NGRAN, + Set.of( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP, + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ, + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR)); // Deliberately picking up the max/min value in each range to test the edge cases - private final int[] mRssiThresholds = new int[]{-113, -103, -97, -51}; - private final int[] mRscpThresholds = new int[]{-120, -105, -95, -25}; - private final int[] mRsrpThresholds = new int[]{-140, -118, -108, -44}; - private final int[] mRsrqThresholds = new int[]{-34, -17, -14, 3}; - private final int[] mRssnrThresholds = new int[]{-20, 10, 20, 30}; - private final int[] mSsrsrpThresholds = new int[]{-140, -118, -98, -44}; - private final int[] mSsrsrqThresholds = new int[]{-43, -17, -14, 20}; - private final int[] mSssinrThresholds = new int[]{-23, -16, -10, 40}; - - private final int[][] mThresholds = {mRssiThresholds, mRscpThresholds, mRsrpThresholds, - mRsrqThresholds, mRssnrThresholds, mSsrsrpThresholds, mSsrsrqThresholds, - mSssinrThresholds}; + private final int[] mRssiThresholds = new int[] {-113, -103, -97, -51}; + private final int[] mRscpThresholds = new int[] {-120, -105, -95, -25}; + private final int[] mRsrpThresholds = new int[] {-140, -118, -108, -44}; + private final int[] mRsrqThresholds = new int[] {-34, -17, -14, 3}; + private final int[] mRssnrThresholds = new int[] {-20, 10, 20, 30}; + private final int[] mSsrsrpThresholds = new int[] {-140, -118, -98, -44}; + private final int[] mSsrsrqThresholds = new int[] {-43, -17, -14, 20}; + private final int[] mSssinrThresholds = new int[] {-23, -16, -10, 40}; + private final int[] mEcnoThresholds = new int[] {-24, -16, -8, 1}; + + private final int[][] mThresholds = { + mRssiThresholds, + mRscpThresholds, + mRsrpThresholds, + mRsrqThresholds, + mRssnrThresholds, + mSsrsrpThresholds, + mSsrsrqThresholds, + mSssinrThresholds, + mEcnoThresholds + }; @Test @SmallTest @@ -120,12 +145,14 @@ public class SignalThresholdInfoTest extends TestCase { .setIsEnabled(false) .build(); - assertEquals(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP, + assertEquals( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP, signalThresholdInfo.getSignalMeasurementType()); assertEquals(HYSTERESIS_MS, signalThresholdInfo.getHysteresisMs()); assertEquals(HYSTERESIS_DB, signalThresholdInfo.getHysteresisDb()); - assertEquals(Arrays.toString(SSRSRP_THRESHOLDS), Arrays.toString( - signalThresholdInfo.getThresholds())); + assertEquals( + Arrays.toString(SSRSRP_THRESHOLDS), + Arrays.toString(signalThresholdInfo.getThresholds())); assertFalse(signalThresholdInfo.isEnabled()); } @@ -160,63 +187,90 @@ public class SignalThresholdInfoTest extends TestCase { @SmallTest public void testGetSignalThresholdInfo() { ArrayList stList = new ArrayList<>(); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) - .setHysteresisMs(0) - .setHysteresisDb(0) - .setThresholds(new int[]{}, true /*isSystem*/) - .setIsEnabled(false) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) - .setHysteresisMs(HYSTERESIS_MS).setHysteresisDb(HYSTERESIS_DB) - .setThresholds(mRssiThresholds) - .setIsEnabled(false) - .build()); - - assertThat(stList.get(0).getThresholds()).isEqualTo(new int[]{}); - assertThat(stList.get(1).getSignalMeasurementType()).isEqualTo( - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) + .setHysteresisMs(0) + .setHysteresisDb(0) + .setThresholds(new int[] {}, true /*isSystem*/) + .setIsEnabled(false) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mRssiThresholds) + .setIsEnabled(false) + .build()); + + assertThat(stList.get(0).getThresholds()).isEqualTo(new int[] {}); + assertThat(stList.get(1).getSignalMeasurementType()) + .isEqualTo(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI); assertThat(stList.get(1).getThresholds()).isEqualTo(mRssiThresholds); } @Test @SmallTest public void testEqualsSignalThresholdInfo() { - final int[] dummyThresholds = new int[]{-100, -90, -70, -60}; - final int[] dummyThreholdsDisordered = new int[]{-60, -90, -100, -70}; - SignalThresholdInfo st1 = new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(1).setSignalMeasurementType(1) - .setHysteresisMs(HYSTERESIS_MS).setHysteresisDb(HYSTERESIS_DB) - .setThresholds(mRssiThresholds).setIsEnabled(false) - .build(); - SignalThresholdInfo st2 = new SignalThresholdInfo.Builder().setRadioAccessNetworkType(2) - .setSignalMeasurementType(2).setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB).setThresholds(mRssiThresholds).setIsEnabled(false) - .build(); - SignalThresholdInfo st3 = new SignalThresholdInfo.Builder().setRadioAccessNetworkType(1) - .setSignalMeasurementType(1).setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB).setThresholds(dummyThresholds).setIsEnabled(false) - .build(); - SignalThresholdInfo st4 = new SignalThresholdInfo.Builder().setRadioAccessNetworkType(1) - .setSignalMeasurementType(1).setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB).setThresholds(mRssiThresholds).setIsEnabled(false) - .build(); - SignalThresholdInfo st5 = new SignalThresholdInfo.Builder().setRadioAccessNetworkType(1) - .setSignalMeasurementType(1).setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB).setThresholds(dummyThreholdsDisordered) - .setIsEnabled(false).build(); - - //Return true if all SignalThresholdInfo values match. + final int[] dummyThresholds = new int[] {-100, -90, -70, -60}; + final int[] dummyThreholdsDisordered = new int[] {-60, -90, -100, -70}; + SignalThresholdInfo st1 = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(1) + .setSignalMeasurementType(1) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mRssiThresholds) + .setIsEnabled(false) + .build(); + SignalThresholdInfo st2 = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(2) + .setSignalMeasurementType(2) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mRssiThresholds) + .setIsEnabled(false) + .build(); + SignalThresholdInfo st3 = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(1) + .setSignalMeasurementType(1) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(dummyThresholds) + .setIsEnabled(false) + .build(); + SignalThresholdInfo st4 = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(1) + .setSignalMeasurementType(1) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mRssiThresholds) + .setIsEnabled(false) + .build(); + SignalThresholdInfo st5 = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(1) + .setSignalMeasurementType(1) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(dummyThreholdsDisordered) + .setIsEnabled(false) + .build(); + + // Return true if all SignalThresholdInfo values match. assertTrue(st1.equals(st1)); assertFalse(st1.equals(st2)); assertFalse(st1.equals(st3)); assertTrue(st1.equals(st4)); - //Threshold values ordering doesn't matter + // Threshold values ordering doesn't matter assertTrue(st3.equals(st5)); - //Return false if the object of argument is other than SignalThresholdInfo. + // Return false if the object of argument is other than SignalThresholdInfo. assertFalse(st1.equals(new String("test"))); } @@ -238,33 +292,40 @@ public class SignalThresholdInfoTest extends TestCase { @SmallTest public void testBuilderWithInvalidParameter() { // Invalid signal measurement type - int[] invalidSignalMeasurementTypes = new int[]{-1, 0, 9}; + int[] invalidSignalMeasurementTypes = new int[] {-1, 0, 9}; for (int signalMeasurementType : invalidSignalMeasurementTypes) { buildWithInvalidParameterThrowException( - AccessNetworkConstants.AccessNetworkType.GERAN, signalMeasurementType, - new int[]{-1}); + AccessNetworkConstants.AccessNetworkType.GERAN, + signalMeasurementType, + new int[] {-1}); } // Null thresholds array - buildWithInvalidParameterThrowException(AccessNetworkConstants.AccessNetworkType.GERAN, - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, null); + buildWithInvalidParameterThrowException( + AccessNetworkConstants.AccessNetworkType.GERAN, + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, + null); // Empty thresholds - buildWithInvalidParameterThrowException(AccessNetworkConstants.AccessNetworkType.GERAN, - SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, new int[]{}); - + buildWithInvalidParameterThrowException( + AccessNetworkConstants.AccessNetworkType.GERAN, + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, + new int[] {}); // Too long thresholds array - buildWithInvalidParameterThrowException(AccessNetworkConstants.AccessNetworkType.GERAN, + buildWithInvalidParameterThrowException( + AccessNetworkConstants.AccessNetworkType.GERAN, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, - new int[]{-100, -90, -70, -60, -58}); + new int[] {-100, -90, -70, -60, -58}); // Thresholds value out of range for (int signalMeasurementType : INVALID_THRESHOLDS_MAP.keySet()) { List invalidThresholds = INVALID_THRESHOLDS_MAP.get(signalMeasurementType); for (int threshold : invalidThresholds) { - buildWithInvalidParameterThrowException(getValidRan(signalMeasurementType), - signalMeasurementType, new int[]{threshold}); + buildWithInvalidParameterThrowException( + getValidRan(signalMeasurementType), + signalMeasurementType, + new int[] {threshold}); } } @@ -272,16 +333,17 @@ public class SignalThresholdInfoTest extends TestCase { for (int ran : VALID_RAN_TO_MEASUREMENT_TYPE_MAP.keySet()) { Set validTypes = VALID_RAN_TO_MEASUREMENT_TYPE_MAP.get(ran); for (int type = SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI; - type <= SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR; type++) { + type <= SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO; + type++) { if (!validTypes.contains(type)) { - buildWithInvalidParameterThrowException(ran, type, new int[]{-1}); + buildWithInvalidParameterThrowException(ran, type, new int[] {-1}); } } } } - private void buildWithInvalidParameterThrowException(int ran, int signalMeasurementType, - int[] thresholds) { + private void buildWithInvalidParameterThrowException( + int ran, int signalMeasurementType, int[] thresholds) { try { new SignalThresholdInfo.Builder() .setRadioAccessNetworkType(ran) @@ -296,68 +358,90 @@ public class SignalThresholdInfoTest extends TestCase { private ArrayList buildSignalThresholdInfoWithAllFields() { ArrayList stList = new ArrayList<>(); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) - .setHysteresisMs(HYSTERESIS_MS).setHysteresisDb(HYSTERESIS_DB) - .setThresholds(mRssiThresholds).setIsEnabled(false) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.UTRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP) - .setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB) - .setThresholds(mRscpThresholds) - .setIsEnabled(false) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP) - .setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB) - .setThresholds(mRsrpThresholds) - .setIsEnabled(false) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ) - .setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB) - .setThresholds(mRsrqThresholds) - .setIsEnabled(false) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR) - .setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB) - .setThresholds(mRssnrThresholds) - .setIsEnabled(false) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP) - .setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB) - .setThresholds(mSsrsrpThresholds) - .setIsEnabled(false) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ) - .setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB) - .setThresholds(mSsrsrqThresholds) - .setIsEnabled(false) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR) - .setHysteresisMs(HYSTERESIS_MS) - .setHysteresisDb(HYSTERESIS_DB) - .setThresholds(mSssinrThresholds) - .setIsEnabled(false) - .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mRssiThresholds) + .setIsEnabled(false) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.UTRAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mRscpThresholds) + .setIsEnabled(false) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mRsrpThresholds) + .setIsEnabled(false) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mRsrqThresholds) + .setIsEnabled(false) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mRssnrThresholds) + .setIsEnabled(false) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) + .setSignalMeasurementType( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mSsrsrpThresholds) + .setIsEnabled(false) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) + .setSignalMeasurementType( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mSsrsrqThresholds) + .setIsEnabled(false) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) + .setSignalMeasurementType( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mSssinrThresholds) + .setIsEnabled(false) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.UTRAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO) + .setHysteresisMs(HYSTERESIS_MS) + .setHysteresisDb(HYSTERESIS_DB) + .setThresholds(mEcnoThresholds) + .setIsEnabled(false) + .build()); return stList; } @@ -365,46 +449,63 @@ public class SignalThresholdInfoTest extends TestCase { private ArrayList buildSignalThresholdInfoWithPublicFields() { ArrayList stList = new ArrayList<>(); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) - .setThresholds(mRssiThresholds) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.UTRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP) - .setThresholds(mRscpThresholds) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP) - .setThresholds(mRsrpThresholds) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ) - .setThresholds(mRsrqThresholds) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR) - .setThresholds(mRssnrThresholds) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP) - .setThresholds(mSsrsrpThresholds) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ) - .setThresholds(mSsrsrqThresholds) - .build()); - stList.add(new SignalThresholdInfo.Builder() - .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) - .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR) - .setThresholds(mSssinrThresholds) - .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) + .setThresholds(mRssiThresholds) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.UTRAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP) + .setThresholds(mRscpThresholds) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP) + .setThresholds(mRsrpThresholds) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ) + .setThresholds(mRsrqThresholds) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR) + .setThresholds(mRssnrThresholds) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) + .setSignalMeasurementType( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP) + .setThresholds(mSsrsrpThresholds) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) + .setSignalMeasurementType( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ) + .setThresholds(mSsrsrqThresholds) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) + .setSignalMeasurementType( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR) + .setThresholds(mSssinrThresholds) + .build()); + stList.add( + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.UTRAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO) + .setThresholds(mEcnoThresholds) + .build()); return stList; } @@ -418,6 +519,7 @@ public class SignalThresholdInfoTest extends TestCase { case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI: return AccessNetworkConstants.AccessNetworkType.GERAN; case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP: + case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO: return AccessNetworkConstants.AccessNetworkType.UTRAN; case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP: case SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ: -- GitLab From 8a49acbf54f824bee0ab9eb78c8b6adf8055f08f Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Sun, 4 Sep 2022 13:55:32 -0700 Subject: [PATCH 098/656] Move dataEnabled override rule check to phone switcher Previously, whether an override rule applies to the current condition is decided by each sub. The motive for moving the check to phoneSwitcher is that as the future override rule becomes increasingly dependent on the status of both SIM, phoneSwitcher, which oversees both SIMs in order to route requests, is more suitable. Bug: 244064524 Test: atest + manual toggle dataDuringCall during voice call + toggle always allow MMS for sending MMS. Change-Id: I8ea07a1ed879afd52d960241b40e8a4897f899aa --- .../telephony/SubscriptionController.java | 28 +- .../telephony/data/DataEnabledOverride.java | 460 ------------------ .../telephony/data/DataNetworkController.java | 3 +- .../telephony/data/DataSettingsManager.java | 191 +++++--- .../internal/telephony/data/DataUtils.java | 39 +- .../telephony/data/PhoneSwitcher.java | 11 +- .../internal/telephony/TelephonyTest.java | 3 - .../data/DataEnabledOverrideTest.java | 218 --------- .../data/DataNetworkControllerTest.java | 44 +- .../data/DataSettingsManagerTest.java | 105 ++++ .../data/DataStallRecoveryManagerTest.java | 2 +- .../telephony/data/PhoneSwitcherTest.java | 38 +- 12 files changed, 361 insertions(+), 781 deletions(-) delete mode 100644 src/java/com/android/internal/telephony/data/DataEnabledOverride.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/data/DataEnabledOverrideTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index a1a451aab7..5090fa219f 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -78,7 +78,6 @@ import com.android.ims.ImsManager; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IccCardConstants.State; -import com.android.internal.telephony.data.DataEnabledOverride; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.uicc.IccUtils; @@ -312,7 +311,7 @@ public class SubscriptionController extends ISub.Stub { SubscriptionManager.WFC_IMS_ROAMING_ENABLED, SubscriptionManager.DATA_ROAMING, SubscriptionManager.DISPLAY_NAME, - SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES, + SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES, SubscriptionManager.UICC_APPLICATIONS_ENABLED, SubscriptionManager.IMS_RCS_UCE_ENABLED, SubscriptionManager.CROSS_SIM_CALLING_ENABLED, @@ -2299,7 +2298,7 @@ public class SubscriptionController extends ISub.Stub { values.put(propKey, cursor.getInt(columnIndex)); break; case SubscriptionManager.DISPLAY_NAME: - case SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES: + case SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES: values.put(propKey, cursor.getString(columnIndex)); break; default: @@ -3330,7 +3329,7 @@ public class SubscriptionController extends ISub.Stub { case SubscriptionManager.CROSS_SIM_CALLING_ENABLED: case SubscriptionManager.IS_OPPORTUNISTIC: case SubscriptionManager.GROUP_UUID: - case SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES: + case SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES: case SubscriptionManager.ALLOWED_NETWORK_TYPES: case SubscriptionManager.D2D_STATUS_SHARING: case SubscriptionManager.VOIMS_OPT_IN_STATUS: @@ -4523,19 +4522,19 @@ public class SubscriptionController extends ISub.Stub { } /** - * Set allowing mobile data during voice call. + * Set enabled mobile data policies. * * @param subId Subscription index - * @param rules Data enabled override rules in string format. See {@link DataEnabledOverride} - * for details. + * @param policies Mobile data policies in string format. + * See {@link TelephonyManager.MobileDataPolicy} for details. * @return {@code true} if settings changed, otherwise {@code false}. */ - public boolean setDataEnabledOverrideRules(int subId, @NonNull String rules) { - if (DBG) logd("[setDataEnabledOverrideRules]+ rules:" + rules + " subId:" + subId); + public boolean setEnabledMobileDataPolicies(int subId, @NonNull String policies) { + if (DBG) logd("[setEnabledMobileDataPolicies]+ policies:" + policies + " subId:" + subId); validateSubId(subId); ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES, rules); + value.put(SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES, policies); boolean result = updateDatabase(value, subId, true) > 0; @@ -4549,15 +4548,16 @@ public class SubscriptionController extends ISub.Stub { } /** - * Get data enabled override rules. + * Get enabled mobile data policies. * * @param subId Subscription index - * @return Data enabled override rules in string + * @return Enabled mobile data policies joined by "," (ie. "1,2") or an empty string if no + * policies are enabled. */ @NonNull - public String getDataEnabledOverrideRules(int subId) { + public String getEnabledMobileDataPolicies(int subId) { return TelephonyUtils.emptyIfNull(getSubscriptionProperty(subId, - SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES)); + SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES)); } /** diff --git a/src/java/com/android/internal/telephony/data/DataEnabledOverride.java b/src/java/com/android/internal/telephony/data/DataEnabledOverride.java deleted file mode 100644 index e639ba6fa7..0000000000 --- a/src/java/com/android/internal/telephony/data/DataEnabledOverride.java +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright (C) 2021 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.data; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.telephony.Annotation.ApnType; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.telephony.data.ApnSetting; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionController; -import com.android.internal.telephony.data.DataEnabledOverride.OverrideConditions.Condition; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -/** - * This class represents the rules for overriding data enabled settings in different conditions. - * When data is disabled by the user, data can still be turned on temporarily when conditions - * satisfy any rule here. - */ -public class DataEnabledOverride { - - private final Set mRules = new HashSet<>(); - - /** - * The rule for allowing data during voice call. - */ - private static final OverrideRule OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL = - new OverrideRule(ApnSetting.TYPE_ALL, OverrideConditions.CONDITION_IN_VOICE_CALL - | OverrideConditions.CONDITION_NON_DEFAULT - | OverrideConditions.CONDITION_DEFAULT_DATA_ENABLED - | OverrideConditions.CONDITION_DSDS_ENABLED); - - /** - * The rule for always allowing mms. Without adding any condition to the rule, any condition can - * satisfy this rule for mms. - */ - private static final OverrideRule OVERRIDE_RULE_ALWAYS_ALLOW_MMS = - new OverrideRule(ApnSetting.TYPE_MMS, OverrideConditions.CONDITION_UNCONDITIONALLY); - - /** - * Data enabled override rule - */ - private static class OverrideRule { - /** - * APN type of the rule. The rule is APN type specific. The override is applicable to the - * specified APN type as well. For now we only support one APN type per rule. Can be - * expanded to multiple APN types in the future. - */ - private final @ApnType int mApnType; - - /** The required conditions for overriding */ - private final OverrideConditions mRequiredConditions; - - /** - * Constructor - * - * @param rule The override rule string. For example, {@code mms=nonDefault} or - * {@code default=voiceCall & nonDefault} - */ - OverrideRule(@NonNull String rule) { - String[] tokens = rule.trim().split("\\s*=\\s*"); - if (tokens.length != 2) { - throw new IllegalArgumentException("Invalid data enabled override rule format: " - + rule); - } - - if (TextUtils.isEmpty(tokens[0])) { - throw new IllegalArgumentException("APN type can't be empty"); - } - - mApnType = ApnSetting.getApnTypesBitmaskFromString(tokens[0]); - if (mApnType == ApnSetting.TYPE_NONE) { - throw new IllegalArgumentException("Invalid APN type. Rule=" + rule); - } - - mRequiredConditions = new OverrideConditions(tokens[1]); - } - - /** - * Constructor - * - * @param apnType APN type of the rule - * @param requiredConditions The required conditions for the rule - */ - private OverrideRule(int apnType, int requiredConditions) { - mApnType = apnType; - mRequiredConditions = new OverrideConditions(requiredConditions); - } - - /** - * Check if this rule can be satisfied by the given APN type and provided conditions. - * - * @param apnType APN type to check - * @param providedConditions The provided conditions to check - * @return {@code true} if satisfied - */ - boolean isSatisfiedByConditions(@ApnType int apnType, @Condition int providedConditions) { - return (mApnType == apnType || mApnType == ApnSetting.TYPE_ALL) - && mRequiredConditions.allMet(providedConditions); - } - - @Override - public String toString() { - return ApnSetting.getApnTypeString(mApnType) + "=" + mRequiredConditions; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - OverrideRule that = (OverrideRule) o; - return mApnType == that.mApnType - && Objects.equals(mRequiredConditions, that.mRequiredConditions); - } - - @Override - public int hashCode() { - return Objects.hash(mApnType, mRequiredConditions); - } - } - - /** - * Represent the conditions for overriding data enabled settings - */ - static class OverrideConditions { - // Possible values for data enabled override condition. Note these flags are bitmasks. - /** Unconditionally override enabled settings */ - static final int CONDITION_UNCONDITIONALLY = 0; - - /** Enable data only on subscription that is not user selected default data subscription */ - static final int CONDITION_NON_DEFAULT = 1 << 0; - - /** Enable data only when device has ongoing voice call */ - static final int CONDITION_IN_VOICE_CALL = 1 << 1; - - /** Enable data only when default data is on */ - static final int CONDITION_DEFAULT_DATA_ENABLED = 1 << 2; - - /** Enable data only when device is in DSDS mode */ - static final int CONDITION_DSDS_ENABLED = 1 << 3; - - /** Enable data unconditionally in string format */ - static final String CONDITION_UNCONDITIONALLY_STRING = "unconditionally"; - - /** Enable data only on subscription that is not default in string format */ - static final String CONDITION_NON_DEFAULT_STRING = "nonDefault"; - - /** Enable data only when device has ongoing voice call in string format */ - static final String CONDITION_VOICE_CALL_STRING = "inVoiceCall"; - - /** Enable data only when default data is on in string format */ - static final String CONDITION_DEFAULT_DATA_ENABLED_STRING = "DefaultDataOn"; - - /** Enable data only when device is in DSDS mode in string format */ - static final String CONDITION_DSDS_ENABLED_STRING = "dsdsEnabled"; - - /** @hide */ - @IntDef(flag = true, prefix = { "OVERRIDE_CONDITION_" }, value = { - CONDITION_NON_DEFAULT, - CONDITION_IN_VOICE_CALL, - CONDITION_DEFAULT_DATA_ENABLED, - CONDITION_DSDS_ENABLED - }) - @Retention(RetentionPolicy.SOURCE) - public @interface Condition {} - - private static final Map OVERRIDE_CONDITION_INT_MAP = new ArrayMap<>(); - private static final Map OVERRIDE_CONDITION_STRING_MAP = new ArrayMap<>(); - - static { - OVERRIDE_CONDITION_INT_MAP.put(CONDITION_NON_DEFAULT, - CONDITION_NON_DEFAULT_STRING); - OVERRIDE_CONDITION_INT_MAP.put(CONDITION_IN_VOICE_CALL, - CONDITION_VOICE_CALL_STRING); - OVERRIDE_CONDITION_INT_MAP.put(CONDITION_DEFAULT_DATA_ENABLED, - CONDITION_DEFAULT_DATA_ENABLED_STRING); - OVERRIDE_CONDITION_INT_MAP.put(CONDITION_DSDS_ENABLED, - CONDITION_DSDS_ENABLED_STRING); - - OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_UNCONDITIONALLY_STRING, - CONDITION_UNCONDITIONALLY); - OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_NON_DEFAULT_STRING, - CONDITION_NON_DEFAULT); - OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_VOICE_CALL_STRING, - CONDITION_IN_VOICE_CALL); - OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_DEFAULT_DATA_ENABLED_STRING, - CONDITION_DEFAULT_DATA_ENABLED); - OVERRIDE_CONDITION_STRING_MAP.put(CONDITION_DSDS_ENABLED_STRING, - CONDITION_DSDS_ENABLED); - } - - private final @Condition int mConditions; - - /** - * Conditions for overriding data enabled setting - * - * @param conditions Conditions in string format - */ - OverrideConditions(@NonNull String conditions) { - mConditions = getBitmaskFromString(conditions); - } - - /** - * Conditions for overriding data enabled setting - * - * @param conditions Conditions in bitmask - */ - OverrideConditions(@Condition int conditions) { - mConditions = conditions; - } - - private static String getStringFromBitmask(@Condition int conditions) { - if (conditions == CONDITION_UNCONDITIONALLY) { - return CONDITION_UNCONDITIONALLY_STRING; - } - List conditionsStrings = new ArrayList<>(); - for (Integer condition : OVERRIDE_CONDITION_INT_MAP.keySet()) { - if ((conditions & condition) == condition) { - conditionsStrings.add(OVERRIDE_CONDITION_INT_MAP.get(condition)); - } - } - return TextUtils.join("&", conditionsStrings); - } - - private static @Condition int getBitmaskFromString(@NonNull String str) { - if (TextUtils.isEmpty(str)) { - throw new IllegalArgumentException("Empty rule string"); - } - - String[] conditionStrings = str.trim().split("\\s*&\\s*"); - int bitmask = 0; - - for (String conditionStr : conditionStrings) { - if (!TextUtils.isEmpty(conditionStr)) { - if (!OVERRIDE_CONDITION_STRING_MAP.containsKey(conditionStr)) { - throw new IllegalArgumentException("Invalid conditions: " + str); - } - bitmask |= OVERRIDE_CONDITION_STRING_MAP.get(conditionStr); - } - } - - return bitmask; - } - - /** - * Check if provided conditions can meet all conditions in the rule. - * - * @param providedConditions The provided conditions - * @return {@code true} if all conditions are met. - */ - boolean allMet(@Condition int providedConditions) { - return (providedConditions & mConditions) == mConditions; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - OverrideConditions that = (OverrideConditions) o; - return mConditions == that.mConditions; - } - - @Override - public int hashCode() { - return Objects.hash(mConditions); - } - - @Override - public String toString() { - return getStringFromBitmask(mConditions); - } - } - - /** - * Constructor - * - * @param rules Data enabled override rules - */ - public DataEnabledOverride(@NonNull String rules) { - updateRules(rules); - } - - /** - * Update the data enabled override rules. - * - * @param newRules New override rules - */ - @VisibleForTesting - public void updateRules(@NonNull String newRules) { - mRules.clear(); - String[] rulesString = newRules.trim().split("\\s*,\\s*"); - for (String rule : rulesString) { - if (!TextUtils.isEmpty(rule)) { - mRules.add(new OverrideRule(rule)); - } - } - } - - /** - * Set always allowing MMS - * - * @param allow {@code true} if always allowing, otherwise {@code false}. - */ - public void setAlwaysAllowMms(boolean allow) { - if (allow) { - mRules.add(OVERRIDE_RULE_ALWAYS_ALLOW_MMS); - } else { - mRules.remove(OVERRIDE_RULE_ALWAYS_ALLOW_MMS); - } - } - - /** - * Set allowing mobile data during voice call. This is used for allowing data on the non-default - * data SIM. When a voice call is placed on the non-default data SIM on DSDS devices, users will - * not be able to use mobile data. By calling this API, data will be temporarily enabled on the - * non-default data SIM during the life cycle of the voice call. - * - * @param allow {@code true} if allowing using data during voice call, {@code false} if - * disallowed. - */ - public void setDataAllowedInVoiceCall(boolean allow) { - if (allow) { - mRules.add(OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL); - } else { - mRules.remove(OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL); - } - } - - /** - * Check if data is allowed during voice call. - * - * @return {@code true} if data is allowed during voice call. - */ - public boolean isDataAllowedInVoiceCall() { - return mRules.contains(OVERRIDE_RULE_ALLOW_DATA_DURING_VOICE_CALL); - } - - public boolean isMmsAlwaysAllowed() { - return mRules.contains(OVERRIDE_RULE_ALWAYS_ALLOW_MMS); - } - - private boolean canSatisfyAnyRule(@ApnType int apnType, - @Condition int providedConditions) { - for (OverrideRule rule : mRules) { - if (rule.isSatisfiedByConditions(apnType, providedConditions)) { - return true; - } - } - return false; - } - - private @Condition int getCurrentConditions(Phone phone) { - int conditions = 0; - - if (phone != null) { - // Check if the device is on voice call - if (phone.getState() != PhoneConstants.State.IDLE) { - conditions |= OverrideConditions.CONDITION_IN_VOICE_CALL; - } - - int defaultDataSubId = SubscriptionController.getInstance().getDefaultDataSubId(); - - if (phone.getSubId() != defaultDataSubId) { - conditions |= OverrideConditions.CONDITION_NON_DEFAULT; - } - - if (defaultDataSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - int phoneId = SubscriptionController.getInstance().getPhoneId(defaultDataSubId); - try { - Phone defaultDataPhone = PhoneFactory.getPhone(phoneId); - if (defaultDataPhone != null && defaultDataPhone.isUserDataEnabled()) { - conditions |= OverrideConditions.CONDITION_DEFAULT_DATA_ENABLED; - } - } catch (IllegalStateException e) { - //ignore the exception and do not add the condition - Log.d("DataEnabledOverride", e.getMessage()); - } - } - - if (TelephonyManager.from(phone.getContext()).isMultiSimEnabled()) { - conditions |= OverrideConditions.CONDITION_DSDS_ENABLED; - } - } - - return conditions; - } - - /** - * Check for given APN type if we should enable data. - * - * @param phone Phone object - * @param apnType APN type - * @return {@code true} if data should be enabled for the current condition. - */ - public boolean shouldOverrideDataEnabledSettings(Phone phone, @ApnType int apnType) { - return canSatisfyAnyRule(apnType, getCurrentConditions(phone)); - } - - /** - * Get data enabled override rules. - * - * @return Get data enabled override rules in string format - */ - @NonNull - public String getRules() { - List ruleStrings = new ArrayList<>(); - for (OverrideRule rule : mRules) { - ruleStrings.add(rule.toString()); - } - return TextUtils.join(",", ruleStrings); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - DataEnabledOverride that = (DataEnabledOverride) o; - return mRules.equals(that.mRules); - } - - @Override - public int hashCode() { - return Objects.hash(mRules); - } - - @Override - public String toString() { - return "DataEnabledOverride: [rules=\"" + getRules() + "\"]"; - } -} diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index eee7324007..53e5ccac84 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -1539,7 +1539,8 @@ public class DataNetworkController extends Handler { if (!mDataSettingsManager.isDataEnabled() && networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS) - && mDataSettingsManager.isMmsAlwaysAllowed()) { + && mDataSettingsManager.isMobileDataPolicyEnabled(TelephonyManager + .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED)) { // We reach here when data is disabled, but MMS always-allowed is enabled. // (Note that isDataEnabled(ApnSetting.TYPE_MMS) returns true in this case, so it // would not generate any soft disallowed reason. We need to explicitly handle it.) diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index c593f88471..d68afadfb8 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -32,9 +32,11 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.MobileDataPolicy; import android.telephony.TelephonyRegistryManager; import android.telephony.data.ApnSetting; import android.telephony.data.ApnSetting.ApnType; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; @@ -49,6 +51,7 @@ import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; @@ -59,6 +62,9 @@ import java.util.stream.Collectors; * data roaming settings, etc... */ public class DataSettingsManager extends Handler { + /** Invalid mobile data policy **/ + private static final int INVALID_MOBILE_DATA_POLICY = -1; + /** Event for call state changed. */ private static final int EVENT_CALL_STATE_CHANGED = 2; /** Event for subscriptions updated. */ @@ -67,10 +73,9 @@ public class DataSettingsManager extends Handler { private static final int EVENT_SET_DATA_ENABLED_FOR_REASON = 5; /** Event for set data roaming enabled. */ private static final int EVENT_SET_DATA_ROAMING_ENABLED = 6; - /** Event for set always allow MMS data. */ - private static final int EVENT_SET_ALWAYS_ALLOW_MMS_DATA = 7; - /** Event for set allow data during voice call. */ - private static final int EVENT_SET_ALLOW_DATA_DURING_VOICE_CALL = 8; + /** Event for set mobile data policy. */ + private static final int EVENT_SET_MOBILE_DATA_POLICY = 7; + /** Event for device provisioned changed. */ private static final int EVENT_PROVISIONED_CHANGED = 9; /** Event for provisioning data enabled setting changed. */ @@ -83,8 +88,8 @@ public class DataSettingsManager extends Handler { private final SettingsObserver mSettingsObserver; private final String mLogTag; private final LocalLog mLocalLog = new LocalLog(128); + private Set mEnabledMobileDataPolicy = new HashSet<>(); private int mSubId; - private DataEnabledOverride mDataEnabledOverride; /** Data config manager */ private final @NonNull DataConfigManager mDataConfigManager; @@ -171,7 +176,7 @@ public class DataSettingsManager extends Handler { mResolver = mPhone.getContext().getContentResolver(); registerCallback(callback); mDataConfigManager = dataNetworkController.getDataConfigManager(); - mDataEnabledOverride = getDataEnabledOverride(); + refreshEnabledMobileDataPolicy(); mSettingsObserver = new SettingsObserver(mPhone.getContext(), this); mDataEnabledSettings.put(TelephonyManager.DATA_ENABLED_REASON_POLICY, true); mDataEnabledSettings.put(TelephonyManager.DATA_ENABLED_REASON_CARRIER, true); @@ -191,7 +196,7 @@ public class DataSettingsManager extends Handler { } case EVENT_SUBSCRIPTIONS_CHANGED: { mSubId = (int) msg.obj; - mDataEnabledOverride = getDataEnabledOverride(); + refreshEnabledMobileDataPolicy(); updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_USER); mPhone.notifyUserMobileDataStateChanged(isUserDataEnabled()); break; @@ -225,34 +230,10 @@ public class DataSettingsManager extends Handler { setDataRoamingFromUserAction(); break; } - case EVENT_SET_ALWAYS_ALLOW_MMS_DATA: { - boolean alwaysAllow = (boolean) msg.obj; - if (alwaysAllow == isMmsAlwaysAllowed()) { - break; - } - logl("AlwaysAllowMmsData changed to " + alwaysAllow); - mDataEnabledOverride.setAlwaysAllowMms(alwaysAllow); - if (SubscriptionController.getInstance() - .setDataEnabledOverrideRules(mSubId, mDataEnabledOverride.getRules())) { - updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_OVERRIDE); - notifyDataEnabledOverrideChanged(alwaysAllow, - TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED); - } - break; - } - case EVENT_SET_ALLOW_DATA_DURING_VOICE_CALL: { - boolean allow = (boolean) msg.obj; - if (allow == isDataAllowedInVoiceCall()) { - break; - } - logl("AllowDataDuringVoiceCall changed to " + allow); - mDataEnabledOverride.setDataAllowedInVoiceCall(allow); - if (SubscriptionController.getInstance() - .setDataEnabledOverrideRules(mSubId, mDataEnabledOverride.getRules())) { - updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_OVERRIDE); - notifyDataEnabledOverrideChanged(allow, TelephonyManager - .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL); - } + case EVENT_SET_MOBILE_DATA_POLICY: { + int mobileDataPolicy = msg.arg1; + boolean enable = msg.arg2 == 1; + onSetMobileDataPolicy(mobileDataPolicy, enable); break; } case EVENT_PROVISIONED_CHANGED: @@ -399,9 +380,9 @@ public class DataSettingsManager extends Handler { return isProvisioningDataEnabled(); } else { boolean userDataEnabled = isUserDataEnabled(); - // Check if we should temporarily enable data in certain conditions. - boolean isDataEnabledOverridden = mDataEnabledOverride - .shouldOverrideDataEnabledSettings(mPhone, apnType); + // Check if we should temporarily enable data based on mobile data policy. + boolean isDataEnabledOverridden = isDataEnabledOverriddenForApn(apnType); + return ((userDataEnabled || isDataEnabledOverridden) && mDataEnabledSettings.get(TelephonyManager.DATA_ENABLED_REASON_POLICY) @@ -593,44 +574,56 @@ public class DataSettingsManager extends Handler { sp.putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true).commit(); } - private @NonNull DataEnabledOverride getDataEnabledOverride() { - return new DataEnabledOverride(SubscriptionController.getInstance() - .getDataEnabledOverrideRules(mSubId)); + /** Refresh the enabled mobile data policies from Telephony database */ + private void refreshEnabledMobileDataPolicy() { + mEnabledMobileDataPolicy = getMobileDataPolicyEnabled(SubscriptionController + .getInstance().getEnabledMobileDataPolicies(mSubId)); } /** - * Set whether to always allow the MMS data connection. - * @param alwaysAllow {@code true} if MMS data is always allowed and {@code false} otherwise. + * @return {@code true} If the mobile data policy is enabled */ - public void setAlwaysAllowMmsData(boolean alwaysAllow) { - obtainMessage(EVENT_SET_ALWAYS_ALLOW_MMS_DATA, alwaysAllow).sendToTarget(); + public boolean isMobileDataPolicyEnabled(@MobileDataPolicy int mobileDataPolicy) { + return mEnabledMobileDataPolicy.contains(mobileDataPolicy); } /** - * Check whether MMS is always allowed. - * @return {@code true} if MMS is always allowed and {@code false} otherwise. + * Set mobile data policy enabled status + * @param mobileDataPolicy The mobile data policy to set + * @param enable {@code true} to enable the policy; {@code false} to disable. */ - public boolean isMmsAlwaysAllowed() { - return mDataEnabledOverride.isMmsAlwaysAllowed(); + public void setMobileDataPolicy(@MobileDataPolicy int mobileDataPolicy, boolean enable) { + obtainMessage(EVENT_SET_MOBILE_DATA_POLICY, mobileDataPolicy, enable ? 1 : 0) + .sendToTarget(); } /** - * Set whether to allow mobile data during voice call. This is used for allowing data on the - * non-default data SIM. When a voice call is placed on the non-default data SIM on DSDS - * devices, users will not be able to use mobile data. By calling this API, data will be - * temporarily enabled on the non-default data SIM during the life cycle of the voice call. - * @param allow {@code true} if data is allowed during a voice call and {@code false} otherwise. + * Store data mobile policy to Telephony database. + * + * @param mobileDataPolicy The mobile data policy that overrides user data enabled setting. + * @param enable {@code true} to enable the policy; {@code false} to remove the policy. */ - public void setAllowDataDuringVoiceCall(boolean allow) { - obtainMessage(EVENT_SET_ALLOW_DATA_DURING_VOICE_CALL, allow).sendToTarget(); - } + private void onSetMobileDataPolicy(@MobileDataPolicy int mobileDataPolicy, boolean enable) { + if (enable == isMobileDataPolicyEnabled(mobileDataPolicy)) { + return; + } + if (enable) { + mEnabledMobileDataPolicy.add(mobileDataPolicy); + } else { + mEnabledMobileDataPolicy.remove(mobileDataPolicy); + } - /** - * Check whether data is allowed during a voice call. - * @return {@code true} if data is allowed during voice call and {@code false} otherwise. - */ - public boolean isDataAllowedInVoiceCall() { - return mDataEnabledOverride.isDataAllowedInVoiceCall(); + String enabledMobileDataPolicies = mEnabledMobileDataPolicy.stream().map(String::valueOf) + .collect(Collectors.joining(",")); + if (SubscriptionController.getInstance().setEnabledMobileDataPolicies( + mSubId, enabledMobileDataPolicies)) { + logl(DataUtils.mobileDataPolicyToString(mobileDataPolicy) + " changed to " + + enable); + updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_OVERRIDE); + notifyDataEnabledOverrideChanged(enable, mobileDataPolicy); + } else { + loge("onSetMobileDataPolicy: failed to set " + enabledMobileDataPolicies); + } } /** @@ -658,6 +651,72 @@ public class DataSettingsManager extends Handler { () -> callback.onDataEnabledOverrideChanged(enabled, policy))); } + /** + * Return the parsed mobile data policies. + * + * @param policies New mobile data policies in String format. + * @return A Set of parsed mobile data policies. + */ + public @NonNull @MobileDataPolicy Set getMobileDataPolicyEnabled( + @NonNull String policies) { + Set mobileDataPolicies = new HashSet<>(); + String[] rulesString = policies.trim().split("\\s*,\\s*"); + for (String rule : rulesString) { + if (!TextUtils.isEmpty(rule)) { + int parsedDataPolicy = parsePolicyFrom(rule); + if (parsedDataPolicy != INVALID_MOBILE_DATA_POLICY) { + mobileDataPolicies.add(parsedDataPolicy); + } + } + } + return mobileDataPolicies; + } + + /** + * Parse a mobile data policy retrieved from Telephony db. + * If the policy is in legacy format, convert it into the corresponding mobile data policy. + * + * @param policy Mobile data policy to be parsed from. + * @return Parsed mobile data policy. {@link #INVALID_MOBILE_DATA_POLICY} if string can't be + * parsed into a mobile data policy. + */ + private @MobileDataPolicy int parsePolicyFrom(@NonNull String policy) { + int dataPolicy; + try { + // parse as new override policy + dataPolicy = Integer.parseInt(policy); + } catch (NumberFormatException e) { + dataPolicy = INVALID_MOBILE_DATA_POLICY; + loge("parsePolicyFrom: invalid mobile data policy format: " + policy); + } + return dataPolicy; + } + + /** + * Check if data enabled is temporarily overridden in certain conditions. + * + * @param apnType The APN type to check. + * @return {@code true} if data enabled should be overridden. + */ + private boolean isDataEnabledOverriddenForApn(@ApnType int apnType) { + boolean overridden = false; + + // mobile data policy : MMS always allowed + if (isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED)) { + overridden = apnType == ApnSetting.TYPE_MMS; + } + + boolean isNonDds = mPhone.getSubId() != SubscriptionController.getInstance() + .getDefaultDataSubId(); + + // mobile data policy : data during call + if (isMobileDataPolicyEnabled(TelephonyManager + .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL)) { + overridden = isNonDds; + } + return overridden; + } + /** * Register the callback for receiving information from {@link DataSettingsManager}. * @@ -700,7 +759,8 @@ public class DataSettingsManager extends Handler { + ", isProvisioningDataEnabled=" + isProvisioningDataEnabled() + ", mIsDataEnabled=" + mIsDataEnabled + ", mDataEnabledSettings=" + mDataEnabledSettings - + ", mDataEnabledOverride=" + mDataEnabledOverride + + ", mEnabledMobileDataPolicy=" + mEnabledMobileDataPolicy.stream() + .map(DataUtils::mobileDataPolicyToString).collect(Collectors.joining(",")) + "]"; } @@ -756,7 +816,8 @@ public class DataSettingsManager extends Handler { .map(entry -> dataEnabledChangedReasonToString(entry.getKey()) + "=" + entry.getValue()) .collect(Collectors.joining(", "))); - pw.println("mDataEnabledOverride=" + mDataEnabledOverride); + pw.println("mEnabledMobileDataPolicy=" + mEnabledMobileDataPolicy.stream() + .map(DataUtils::mobileDataPolicyToString).collect(Collectors.joining(","))); pw.println("Local logs:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/data/DataUtils.java b/src/java/com/android/internal/telephony/data/DataUtils.java index 897f412141..ca957ae584 100644 --- a/src/java/com/android/internal/telephony/data/DataUtils.java +++ b/src/java/com/android/internal/telephony/data/DataUtils.java @@ -32,6 +32,7 @@ import android.telephony.Annotation.NetCapability; import android.telephony.Annotation.NetworkType; import android.telephony.Annotation.ValidationStatus; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.MobileDataPolicy; import android.telephony.data.ApnSetting; import android.telephony.data.ApnSetting.ApnType; import android.telephony.data.DataCallResponse; @@ -41,6 +42,7 @@ import android.telephony.ims.feature.ImsFeature; import android.util.ArrayMap; import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; +import com.android.telephony.Rlog; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -61,6 +63,7 @@ public class DataUtils { /** The time format for converting time to readable string. */ private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS", Locale.US); + private static final String TAG = "DataUtils"; /** * Get the network capability from the string. @@ -164,6 +167,7 @@ public class DataUtils { case NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH: return "PRIORITIZE_BANDWIDTH"; default: + loge("Unknown network capability(" + netCap + ")"); return "Unknown(" + netCap + ")"; } } @@ -209,7 +213,9 @@ public class DataUtils { switch (status) { case NetworkAgent.VALIDATION_STATUS_VALID: return "VALID"; case NetworkAgent.VALIDATION_STATUS_NOT_VALID: return "INVALID"; - default: return "UNKNOWN(" + status + ")"; + default: + loge("Unknown validation status(" + status + ")"); + return "UNKNOWN(" + status + ")"; } } @@ -366,6 +372,7 @@ public class DataUtils { case ImsFeature.FEATURE_MMTEL: return "MMTEL"; case ImsFeature.FEATURE_RCS: return "RCS"; default: + loge("Unknown IMS feature(" + imsFeature + ")"); return "Unknown(" + imsFeature + ")"; } } @@ -468,7 +475,9 @@ public class DataUtils { case DataCallResponse.LINK_STATUS_INACTIVE: return "INACTIVE"; case DataCallResponse.LINK_STATUS_ACTIVE: return "ACTIVE"; case DataCallResponse.LINK_STATUS_DORMANT: return "DORMANT"; - default: return "UNKNOWN(" + linkStatus + ")"; + default: + loge("Unknown link status(" + linkStatus + ")"); + return "UNKNOWN(" + linkStatus + ")"; } } @@ -505,7 +514,31 @@ public class DataUtils { case TelephonyManager.DATA_ACTIVITY_OUT: return "OUT"; case TelephonyManager.DATA_ACTIVITY_INOUT: return "INOUT"; case TelephonyManager.DATA_ACTIVITY_DORMANT: return "DORMANT"; - default: return "UNKNOWN(" + dataActivity + ")"; + default: + loge("Unknown data activity(" + dataActivity + ")"); + return "UNKNOWN(" + dataActivity + ")"; + } + } + + /** + * Convert mobile data policy to string. + * + * @param mobileDataPolicy The mobile data policy. + * @return The mobile data policy in string format. + */ + public static @NonNull String mobileDataPolicyToString(@MobileDataPolicy int mobileDataPolicy) { + switch (mobileDataPolicy) { + case TelephonyManager.MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL: + return "DATA_ON_NON_DEFAULT_DURING_VOICE_CALL"; + case TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED: + return "MMS_ALWAYS_ALLOWED"; + default: + loge("Unknown mobile data policy(" + mobileDataPolicy + ")"); + return "UNKNOWN(" + mobileDataPolicy + ")"; } } + + private static void loge(String msg) { + Rlog.e(TAG, msg); + } } diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index ee8d157907..15df182350 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -62,7 +62,6 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; -import android.telephony.data.ApnSetting; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RegistrationManager; @@ -1326,10 +1325,14 @@ public class PhoneSwitcher extends Handler { // requests. protected void updatePreferredDataPhoneId() { Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); + // check user enabled data on the default phone + int defaultDataPhoneId = SubscriptionController.getInstance().getPhoneId(mPrimaryDataSubId); + Phone defaultDataPhone = findPhoneById(defaultDataPhoneId); boolean isDataEnabled = false; - if (voicePhone != null) { - isDataEnabled = voicePhone.getDataSettingsManager() - .isDataEnabled(ApnSetting.TYPE_DEFAULT); + if (voicePhone != null && defaultDataPhone != null + && defaultDataPhone.isUserDataEnabled()) { + // check voice during call feature is enabled + isDataEnabled = voicePhone.getDataSettingsManager().isDataEnabled(); } if (mEmergencyOverride != null && findPhoneById(mEmergencyOverride.mPhoneId) != null) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index dc2d00a4f8..125ac6374c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -97,7 +97,6 @@ import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.CellularNetworkValidator; import com.android.internal.telephony.data.DataConfigManager; -import com.android.internal.telephony.data.DataEnabledOverride; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.DataProfileManager; import com.android.internal.telephony.data.DataRetryManager; @@ -237,7 +236,6 @@ public abstract class TelephonyTest { protected SubscriptionInfoUpdater mSubInfoRecordUpdater; protected LocaleTracker mLocaleTracker; protected RestrictedState mRestrictedState; - protected DataEnabledOverride mDataEnabledOverride; protected PhoneConfigurationManager mPhoneConfigurationManager; protected CellularNetworkValidator mCellularNetworkValidator; protected UiccCard mUiccCard; @@ -468,7 +466,6 @@ public abstract class TelephonyTest { mSubInfoRecordUpdater = Mockito.mock(SubscriptionInfoUpdater.class); mLocaleTracker = Mockito.mock(LocaleTracker.class); mRestrictedState = Mockito.mock(RestrictedState.class); - mDataEnabledOverride = Mockito.mock(DataEnabledOverride.class); mPhoneConfigurationManager = Mockito.mock(PhoneConfigurationManager.class); mCellularNetworkValidator = Mockito.mock(CellularNetworkValidator.class); mUiccCard = Mockito.mock(UiccCard.class); diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataEnabledOverrideTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataEnabledOverrideTest.java deleted file mode 100644 index 252274ceec..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataEnabledOverrideTest.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.data; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; - -import android.telephony.data.ApnSetting; -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.TelephonyTest; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class DataEnabledOverrideTest extends TelephonyTest { - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - } - - @After - public void tearDown() throws Exception { - super.tearDown(); - } - - @Test - @SmallTest - public void testCreateByRules() throws Exception { - DataEnabledOverride deo1 = new DataEnabledOverride( - "mms=nonDefault, default=inVoiceCall&nonDefault"); - DataEnabledOverride deo2 = new DataEnabledOverride( - "mms=nonDefault, default=inVoiceCall"); - DataEnabledOverride deo3 = new DataEnabledOverride( - "default=inVoiceCall&nonDefault, mms=nonDefault"); - assertEquals(deo1, deo3); - assertNotEquals(deo1, deo2); - } - - @Test - @SmallTest - public void testOverrideEnabled() throws Exception { - DataEnabledOverride dataEnabledOverride = new DataEnabledOverride( - "mms=nonDefault, default=inVoiceCall&nonDefault"); - doReturn(1).when(mPhone).getSubId(); - doReturn(2).when(mSubscriptionController).getDefaultSmsSubId(); - assertTrue(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_MMS)); - - doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); - - assertFalse(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_DEFAULT)); - - doReturn(PhoneConstants.State.OFFHOOK).when(mPhone).getState(); - - assertTrue(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_DEFAULT)); - } - - @Test - @SmallTest - public void testGetRules() throws Exception { - DataEnabledOverride dataEnabledOverride = new DataEnabledOverride( - "mms=nonDefault, default=inVoiceCall&nonDefault"); - String rules = dataEnabledOverride.getRules(); - assertEquals(dataEnabledOverride, new DataEnabledOverride(rules)); - } - - @Test - @SmallTest - public void testUpdateRules() throws Exception { - DataEnabledOverride dataEnabledOverride = new DataEnabledOverride( - "mms=nonDefault, default=inVoiceCall&nonDefault"); - doReturn(1).when(mPhone).getSubId(); - doReturn(2).when(mSubscriptionController).getDefaultSmsSubId(); - assertTrue(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_MMS)); - - doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); - - assertFalse(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_DEFAULT)); - - doReturn(PhoneConstants.State.OFFHOOK).when(mPhone).getState(); - - assertTrue(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_DEFAULT)); - - dataEnabledOverride.updateRules(""); - - assertFalse(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_MMS)); - assertFalse(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_DEFAULT)); - } - - @Test - @SmallTest - public void testAlwaysEnabled() throws Exception { - DataEnabledOverride dataEnabledOverride = new DataEnabledOverride( - "mms =unconditionally, default= unconditionally , "); - assertTrue(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_MMS)); - assertTrue(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_DEFAULT)); - - dataEnabledOverride.updateRules(""); - - assertFalse(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_MMS)); - assertFalse(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_DEFAULT)); - } - - @Test - @SmallTest - public void testAllApnTypesInRule() throws Exception { - DataEnabledOverride dataEnabledOverride = new DataEnabledOverride("*=inVoiceCall"); - doReturn(PhoneConstants.State.OFFHOOK).when(mPhone).getState(); - - assertTrue(dataEnabledOverride.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_FOTA)); - } - - @Test - @SmallTest - public void testInvalidRules() throws Exception { - try { - DataEnabledOverride dataEnabledOverride = new DataEnabledOverride( - "default=xyz"); - fail("Invalid conditions but not threw IllegalArgumentException."); - } catch (IllegalArgumentException ex) { - - } - - try { - DataEnabledOverride dataEnabledOverride = new DataEnabledOverride( - "mms="); - fail("Invalid conditions but not threw IllegalArgumentException."); - } catch (IllegalArgumentException ex) { - - } - - try { - DataEnabledOverride dataEnabledOverride = new DataEnabledOverride( - "abc=nonDefault"); - fail("Invalid APN type but not threw IllegalArgumentException."); - } catch (IllegalArgumentException ex) { - - } - - try { - DataEnabledOverride dataEnabledOverride = new DataEnabledOverride( - " =nonDefault"); - fail("Invalid APN type but not threw IllegalArgumentException."); - } catch (IllegalArgumentException ex) { - - } - - try { - DataEnabledOverride dataEnabledOverride = new DataEnabledOverride( - "Invalid rule"); - fail("Invalid rule but not threw IllegalArgumentException."); - } catch (IllegalArgumentException ex) { - - } - } - - @Test - @SmallTest - public void testSetAlwaysAllowMms() throws Exception { - DataEnabledOverride deo = new DataEnabledOverride(""); - deo.setAlwaysAllowMms(true); - assertTrue(deo.shouldOverrideDataEnabledSettings(mPhone, ApnSetting.TYPE_MMS)); - deo.setAlwaysAllowMms(false); - assertFalse(deo.shouldOverrideDataEnabledSettings(mPhone, ApnSetting.TYPE_MMS)); - } - - @Test - @SmallTest - public void testSetDataAllowedInVoiceCall() throws Exception { - DataEnabledOverride deo = new DataEnabledOverride(""); - deo.setDataAllowedInVoiceCall(true); - assertFalse(deo.getRules(), deo.shouldOverrideDataEnabledSettings(mPhone, - ApnSetting.TYPE_DEFAULT)); - assertTrue(deo.isDataAllowedInVoiceCall()); - doReturn(1).when(mPhone).getSubId(); - doReturn(2).when(mSubscriptionController).getDefaultSmsSubId(); - - doReturn(PhoneConstants.State.OFFHOOK).when(mPhone).getState(); - deo.setDataAllowedInVoiceCall(false); - assertFalse(deo.getRules(), deo.shouldOverrideDataEnabledSettings( - mPhone, ApnSetting.TYPE_DEFAULT)); - assertFalse(deo.isDataAllowedInVoiceCall()); - } -} 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 e239408720..7cd6ede82c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -671,8 +671,8 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(true).when(mSST).getPowerStateFromCarrier(); doReturn(true).when(mSST).isConcurrentVoiceAndDataAllowed(); doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); - doReturn("").when(mSubscriptionController).getDataEnabledOverrideRules(anyInt()); - doReturn(true).when(mSubscriptionController).setDataEnabledOverrideRules( + doReturn("").when(mSubscriptionController).getEnabledMobileDataPolicies(anyInt()); + doReturn(true).when(mSubscriptionController).setEnabledMobileDataPolicies( anyInt(), anyString()); List infoList = new ArrayList<>(); @@ -1450,7 +1450,8 @@ public class DataNetworkControllerTest extends TelephonyTest { mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); // Always allow MMS - mDataNetworkControllerUT.getDataSettingsManager().setAlwaysAllowMmsData(true); + mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager + .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, true); processAllMessages(); mDataNetworkControllerUT.addNetworkRequest( createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_MMS)); @@ -1463,7 +1464,8 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); // Remove MMS data enabled override - mDataNetworkControllerUT.getDataSettingsManager().setAlwaysAllowMmsData(false); + mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager + .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, false); processAllMessages(); // Make sure MMS is torn down when the override is disabled. @@ -1481,7 +1483,8 @@ public class DataNetworkControllerTest extends TelephonyTest { serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); // Always allow MMS - mDataNetworkControllerUT.getDataSettingsManager().setAlwaysAllowMmsData(true); + mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager + .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, true); processAllMessages(); mDataNetworkControllerUT.addNetworkRequest( @@ -1493,6 +1496,37 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMS); } + @Test + public void testIsDataEnabledOverriddenForApn_dataDuringCall() throws Exception { + // Note: we don't check phone call status in DSMGR as the check should already been done in + // PhoneSwitcher when routing requests. + doReturn(1).when(mPhone).getSubId(); + doReturn(2).when(mSubscriptionController).getDefaultDataSubId(); + // Data disabled + mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); + + // Enable during data call mobile policy + mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager + .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL, true); + processAllMessages(); + + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + + // Verify internet connection + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); + + // Disable during data call mobile policy + mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager + .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL, false); + processAllMessages(); + + // Verify no internet connection + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + } + @Test public void testUnmeteredRequestPreferredOnIwlan() throws Exception { // Preferred on cellular diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java new file mode 100644 index 0000000000..0014a1b6a1 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2022 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.data; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.os.Looper; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.util.Set; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DataSettingsManagerTest extends TelephonyTest { + + // Mocked + DataSettingsManagerCallback mMockedDataSettingsManagerCallback; + + DataSettingsManager mDataSettingsManagerUT; + + @Before + public void setUp() throws Exception { + logd("DataSettingsManagerTest +Setup!"); + super.setUp(getClass().getSimpleName()); + mMockedDataSettingsManagerCallback = Mockito.mock(DataSettingsManagerCallback.class); + + doReturn("").when(mSubscriptionController).getEnabledMobileDataPolicies(anyInt()); + doReturn(true).when(mSubscriptionController).setEnabledMobileDataPolicies( + anyInt(), anyString()); + + mDataSettingsManagerUT = new DataSettingsManager(mPhone, mDataNetworkController, + Looper.myLooper(), mMockedDataSettingsManagerCallback); + logd("DataSettingsManagerTest -Setup!"); + } + + @After + public void tearDown() throws Exception { + logd("tearDown"); + super.tearDown(); + } + + @Test + public void testMobileDataPolicyParsing() { + //Valid new data policy + Set policies = mDataSettingsManagerUT.getMobileDataPolicyEnabled("1, 2"); + assertThat(policies.size()).isEqualTo(2); + Set policies2 = mDataSettingsManagerUT.getMobileDataPolicyEnabled(",2"); + assertThat(policies2.size()).isEqualTo(1); + Set policies3 = mDataSettingsManagerUT.getMobileDataPolicyEnabled(""); + assertThat(policies3.size()).isEqualTo(0); + + // Invalid + Set invalid = mDataSettingsManagerUT.getMobileDataPolicyEnabled( + "nonExistent, 1, 2"); + assertThat(invalid.size()).isEqualTo(2); + + Set invalid2 = mDataSettingsManagerUT.getMobileDataPolicyEnabled( + "nonExistent ,,"); + assertThat(invalid2.size()).isEqualTo(0); + } + + @Test + public void testGetPolicies() { + mDataSettingsManagerUT.setMobileDataPolicy(1, true); + mDataSettingsManagerUT.setMobileDataPolicy(2, true); + processAllMessages(); + + ArgumentCaptor stringArgumentCaptor = ArgumentCaptor.forClass(String.class); + verify(mSubscriptionController, times(2)) + .setEnabledMobileDataPolicies(anyInt(), stringArgumentCaptor.capture()); + assertEquals("1,2", stringArgumentCaptor.getValue()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java index de0998d27d..a8290affec 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java @@ -78,7 +78,7 @@ public class DataStallRecoveryManagerTest extends TelephonyTest { }) .when(mDataStallRecoveryManagerCallback) .invokeFromExecutor(any(Runnable.class)); - doReturn("").when(mSubscriptionController).getDataEnabledOverrideRules(anyInt()); + doReturn("").when(mSubscriptionController).getEnabledMobileDataPolicies(anyInt()); mDataStallRecoveryManager = new DataStallRecoveryManager( 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 646570557c..ec313d1410 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -65,7 +65,6 @@ import android.os.Messenger; import android.telephony.PhoneCapability; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; -import android.telephony.data.ApnSetting; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -512,7 +511,8 @@ public class PhoneSwitcherTest extends TelephonyTest { mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 2); // A higher priority event occurring E.g. Phone1 has active IMS call on LTE. doReturn(mImsPhone).when(mPhone).getImsPhone(); - doReturn(true).when(mDataSettingsManager).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mPhone).isUserDataEnabled(); + doReturn(true).when(mDataSettingsManager).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInCall(mPhone); @@ -706,10 +706,17 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInCall(mImsPhone); + // Phone 0 should be the default data phoneId. + assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + + // User turns on data on Phone 0 + doReturn(true).when(mPhone).isUserDataEnabled(); + notifyDataEnabled(true); + // Phone 1 should become the default data phone. assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId()); } @@ -735,10 +742,17 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInDial(mImsPhone); + // Phone 0 should be the default data phoneId. + assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + + // User turns on data on Phone 0 + doReturn(true).when(mPhone).isUserDataEnabled(); + notifyDataEnabled(true); + // Phone 1 should become the default data phone. assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId()); } @@ -763,10 +777,17 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInIncomingCall(mImsPhone); + // Phone 0 should be the default data phoneId. + assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + + // User turns on data on Phone 0 + doReturn(true).when(mPhone).isUserDataEnabled(); + notifyDataEnabled(true); + // Phone 1 should become the default data phone. assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId()); } @@ -790,7 +811,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone2 has active call, but data is turned off. So no data switching should happen. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_IWLAN); notifyPhoneAsInCall(mImsPhone); @@ -818,7 +839,8 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone 1 has active IMS call on CROSS_SIM. And data of DEFAULT apn is enabled. This should // not trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(ApnSetting.TYPE_DEFAULT); + doReturn(true).when(mPhone).isUserDataEnabled(); + doReturn(true).when(mDataSettingsManager2).isDataEnabled(); mockImsRegTech(1, REGISTRATION_TECH_CROSS_SIM); notifyPhoneAsInCall(mImsPhone); @@ -864,6 +886,7 @@ public class PhoneSwitcherTest extends TelephonyTest { new TelephonyNetworkRequest(internetRequest, mPhone), 1)); // Phone2 has active call. So data switch to it. + doReturn(true).when(mPhone).isUserDataEnabled(); notifyDataEnabled(true); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( @@ -1450,6 +1473,7 @@ public class PhoneSwitcherTest extends TelephonyTest { private void notifyDataEnabled(boolean dataEnabled) { doReturn(dataEnabled).when(mDataSettingsManager).isDataEnabled(anyInt()); doReturn(dataEnabled).when(mDataSettingsManager2).isDataEnabled(anyInt()); + doReturn(dataEnabled).when(mDataSettingsManager2).isDataEnabled(); mPhoneSwitcher.sendEmptyMessage(EVENT_DATA_ENABLED_CHANGED); processAllMessages(); } -- GitLab From ce41008f7e94c77ddedc479ff6f778e71ea4ef4c Mon Sep 17 00:00:00 2001 From: Grant Menke Date: Tue, 27 Sep 2022 03:38:46 +0000 Subject: [PATCH 099/656] Network identified emergency call metric fix. Update metric code to account for network identified emergency calls Bug: 234632741 Test: manual Change-Id: If460eb2d3ef2bc1300a9ce62d5e0660e50234a2c --- .../internal/telephony/metrics/VoiceCallSessionStats.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java index b4ba9ba56c..d646eb1d4f 100644 --- a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java +++ b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java @@ -442,7 +442,7 @@ public class VoiceCallSessionStats { proto.srvccFailureCount = 0L; proto.srvccCancellationCount = 0L; proto.rttEnabled = false; - proto.isEmergency = conn.isEmergencyCall(); + proto.isEmergency = conn.isEmergencyCall() || conn.isNetworkIdentifiedEmergencyCall(); proto.isRoaming = serviceState != null ? serviceState.getVoiceRoaming() : false; proto.isMultiparty = conn.isMultiparty(); -- GitLab From 39d6cf93f506b180bb792d8efed0b4c9e59ef436 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 27 Sep 2022 20:36:44 -0700 Subject: [PATCH 100/656] Properly support service state override In addition to override the general service state, also override the inner NetworkRegistrationInfo. Bug: 244064524 Test: Manual Change-Id: I7f3e04e4be8bb10d50df2bbfaccd13980b633114 --- .../com/android/internal/telephony/Phone.java | 9 +++- .../telephony/ServiceStateTracker.java | 4 +- .../internal/telephony/TelephonyTester.java | 47 ++++++++++++++++--- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 05633642e1..835a87c802 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -325,7 +325,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected AtomicReference mUiccApplication = new AtomicReference(); - TelephonyTester mTelephonyTester; + private TelephonyTester mTelephonyTester; private String mName; private final String mActionDetached; private final String mActionAttached; @@ -4875,6 +4875,13 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public void setTerminalBasedCallWaitingSupported(boolean supported) { } + /** + * @return Telephony tester instance. + */ + public @Nullable TelephonyTester getTelephonyTester() { + return mTelephonyTester; + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 08800aeda6..77ae9feb95 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -3400,8 +3400,8 @@ public class ServiceStateTracker extends Handler { updateNrFrequencyRangeFromPhysicalChannelConfigs(mLastPhysicalChannelConfigList, mNewSS); updateNrStateFromPhysicalChannelConfigs(mLastPhysicalChannelConfigList, mNewSS); - if (TelephonyUtils.IS_DEBUGGABLE && mPhone.mTelephonyTester != null) { - mPhone.mTelephonyTester.overrideServiceState(mNewSS); + if (TelephonyUtils.IS_DEBUGGABLE && mPhone.getTelephonyTester() != null) { + mPhone.getTelephonyTester().overrideServiceState(mNewSS); } NetworkRegistrationInfo networkRegState = mNewSS.getNetworkRegistrationInfo( diff --git a/src/java/com/android/internal/telephony/TelephonyTester.java b/src/java/com/android/internal/telephony/TelephonyTester.java index c81a4c3ce5..b9e04c8ba3 100644 --- a/src/java/com/android/internal/telephony/TelephonyTester.java +++ b/src/java/com/android/internal/telephony/TelephonyTester.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -200,11 +201,7 @@ public class TelephonyTester { sendTestSuppServiceNotification(intent); } else if (action.equals(ACTION_TEST_SERVICE_STATE)) { log("handle test service state changed intent"); - // Trigger the service state update. The replacement will be done in - // overrideServiceState(). - mServiceStateTestIntent = intent; - mPhone.getServiceStateTracker().sendEmptyMessage( - ServiceStateTracker.EVENT_NETWORK_STATE_CHANGED); + setServiceStateTestIntent(intent); } else if (action.equals(ACTION_TEST_IMS_E_CALL)) { log("handle test IMS ecall intent"); testImsECall(); @@ -388,6 +385,19 @@ public class TelephonyTester { } } + /** + * Set the service state test intent. + * + * @param intent The service state test intent. + */ + public void setServiceStateTestIntent(@NonNull Intent intent) { + mServiceStateTestIntent = intent; + // Trigger the service state update. The replacement will be done in + // overrideServiceState(). + mPhone.getServiceStateTracker().sendEmptyMessage( + ServiceStateTracker.EVENT_NETWORK_STATE_CHANGED); + } + void overrideServiceState(ServiceState ss) { if (mServiceStateTestIntent == null || ss == null) return; if (mPhone.getPhoneId() != mServiceStateTestIntent.getIntExtra( @@ -401,13 +411,36 @@ public class TelephonyTester { } if (mServiceStateTestIntent.hasExtra(EXTRA_VOICE_REG_STATE)) { + int state = mServiceStateTestIntent.getIntExtra(EXTRA_DATA_REG_STATE, + ServiceState.STATE_OUT_OF_SERVICE); ss.setVoiceRegState(mServiceStateTestIntent.getIntExtra(EXTRA_VOICE_REG_STATE, ServiceState.STATE_OUT_OF_SERVICE)); + NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + NetworkRegistrationInfo.Builder builder = new NetworkRegistrationInfo.Builder(nri); + if (state == ServiceState.STATE_IN_SERVICE) { + builder.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + } else { + builder.setRegistrationState( + NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); + } + ss.addNetworkRegistrationInfo(builder.build()); log("Override voice service state with " + ss.getState()); } if (mServiceStateTestIntent.hasExtra(EXTRA_DATA_REG_STATE)) { - ss.setDataRegState(mServiceStateTestIntent.getIntExtra(EXTRA_DATA_REG_STATE, - ServiceState.STATE_OUT_OF_SERVICE)); + int state = mServiceStateTestIntent.getIntExtra(EXTRA_DATA_REG_STATE, + ServiceState.STATE_OUT_OF_SERVICE); + ss.setDataRegState(state); + NetworkRegistrationInfo nri = ss.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + NetworkRegistrationInfo.Builder builder = new NetworkRegistrationInfo.Builder(nri); + if (state == ServiceState.STATE_IN_SERVICE) { + builder.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + } else { + builder.setRegistrationState( + NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); + } + ss.addNetworkRegistrationInfo(builder.build()); log("Override data service state with " + ss.getDataRegistrationState()); } if (mServiceStateTestIntent.hasExtra(EXTRA_OPERATOR)) { -- GitLab From a2ab0269de201f3fda95ecd8d80052fc9ff58628 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 29 Sep 2022 11:05:48 +0000 Subject: [PATCH 101/656] Update IRadioNetwork for Emergency Call domain selection HAL API changes. Bug: 243344927 Test: build and flash Change-Id: Iea7f8c5e8e30befd16637728a0a610c01e2140d3 --- Android.bp | 2 +- .../internal/telephony/BaseCommands.java | 23 +++++++ .../internal/telephony/CommandsInterface.java | 16 +++++ .../internal/telephony/NetworkIndication.java | 18 ++++++ .../internal/telephony/NetworkResponse.java | 37 ++++++++++++ .../internal/telephony/RadioNetworkProxy.java | 60 +++++++++++++++++++ 6 files changed, 155 insertions(+), 1 deletion(-) diff --git a/Android.bp b/Android.bp index fab53d1da6..d784fc8b24 100644 --- a/Android.bp +++ b/Android.bp @@ -87,7 +87,7 @@ java_library { "android.hardware.radio.data-V1-java", "android.hardware.radio.messaging-V1-java", "android.hardware.radio.modem-V1-java", - "android.hardware.radio.network-V1-java", + "android.hardware.radio.network-V2-java", "android.hardware.radio.sim-V1-java", "android.hardware.radio.voice-V1-java", "voip-common", diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java index 972884a77b..764458a7d9 100644 --- a/src/java/com/android/internal/telephony/BaseCommands.java +++ b/src/java/com/android/internal/telephony/BaseCommands.java @@ -114,6 +114,7 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mBarringInfoChangedRegistrants = new RegistrantList(); protected RegistrantList mSimPhonebookChangedRegistrants = new RegistrantList(); protected RegistrantList mSimPhonebookRecordsReceivedRegistrants = new RegistrantList(); + protected RegistrantList mEmergencyNetworkScanRegistrants = new RegistrantList(); @UnsupportedAppUsage protected Registrant mGsmSmsRegistrant; @@ -1132,4 +1133,26 @@ public abstract class BaseCommands implements CommandsInterface { @Override public void updateSimPhonebookRecord(SimPhonebookRecord phonebookRecord, Message result) { } + + /** + * Register for Emergency network scan result. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + @Override + public void registerForEmergencyNetworkScan(Handler h, int what, Object obj) { + mEmergencyNetworkScanRegistrants.add(h, what, obj); + } + + /** + * Unregister for Emergency network scan result. + * + * @param h Handler to be removed from the registrant list. + */ + @Override + public void unregisterForEmergencyNetworkScan(Handler h) { + mEmergencyNetworkScanRegistrants.remove(h); + } } diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 27cedfeeb9..cdde40e24d 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2761,4 +2761,20 @@ public interface CommandsInterface { * @param result Callback message containing the usage setting (or a failure status). */ default void getUsageSetting(Message result) {} + + /** + * Register for Emergency network scan result. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForEmergencyNetworkScan(Handler h, int what, Object obj) {} + + /** + * Unregister for Emergency network scan result. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForEmergencyNetworkScan(Handler h) {} } diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index c9ebfd546c..9c577ba5b9 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -20,6 +20,7 @@ import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_PRL_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CELL_INFO_LIST; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED; @@ -380,6 +381,23 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { new AsyncResult(null, response, null)); } + /** + * Emergency Scan Results. + * @param indicationType Type of radio indication + * @param result the result of the Emergency Network Scan + */ + public void emergencyNetworkScanResult(int indicationType, + android.hardware.radio.network.EmergencyRegResult result) { + mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + + if (mRil.isLogOrTrace()) { + mRil.unsljLogRet(RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT, result); + } + + mRil.mEmergencyNetworkScanRegistrants.notifyRegistrants( + new AsyncResult(null, result, null)); + } + @Override public String getInterfaceHash() { return IRadioNetworkIndication.HASH; diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index d9f70fdca5..5f5895e16c 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -436,6 +436,43 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { RadioResponse.responseInts(RIL.NETWORK_SERVICE, mRil, responseInfo, usageSetting); } + /** + * @param responseInfo Response info struct containing response type, serial no. and error + * @param regState the current registration state of the modem. + */ + public void setEmergencyModeResponse(RadioResponseInfo responseInfo, + android.hardware.radio.network.EmergencyRegResult regState) { + RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + + if (rr != null) { + if (responseInfo.error == RadioError.NONE) { + RadioResponse.sendMessageResponse(rr.mResult, regState); + } + mRil.processResponseDone(rr, responseInfo, regState); + } + } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void triggerEmergencyNetworkScanResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void exitEmergencyModeResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void cancelEmergencyNetworkScanResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + } + @Override public String getInterfaceHash() { return IRadioNetworkResponse.HASH; diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java index 31a8691b4f..d8ad820c62 100644 --- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java +++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java @@ -852,4 +852,64 @@ public class RadioNetworkProxy extends RadioServiceProxy { } // Only supported on AIDL. } + + /** + * Set the Emergency Mode + * + * @param serial Serial number of the request. + * @param emcModeType Defines the radio emergency mode type. + * @throws RemoteException + */ + public void setEmergencyMode(int serial, int emcModeType) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.setEmergencyMode(serial, emcModeType); + } + // Only supported on AIDL. + } + + /** + * Triggers an Emergency network scan. + * + * @param serial Serial number of the request. + * @param scanRequest Contains the preferred networks and type of service to be scanned. + * @throws RemoteException + */ + public void triggerEmergencyNetworkScan(int serial, + android.hardware.radio.network.EmergencyNetworkScanTrigger scanRequest) + throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.triggerEmergencyNetworkScan(serial, scanRequest); + } + // Only supported on AIDL. + } + + /** + * Cancels ongoing Emergency network scan + * + * @param serial Serial number of the request. + * @throws RemoteException + */ + public void cancelEmergencyNetworkScan(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.cancelEmergencyNetworkScan(serial); + } + // Only supported on AIDL. + } + + /** + * Exits ongoing Emergency Mode + * + * @param serial Serial number of the request. + * @throws RemoteException + */ + public void exitEmergencyMode(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.exitEmergencyMode(serial); + } + // Only supported on AIDL. + } } -- GitLab From 85885038a71fa625d2121206560a7f29ac85a91c Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Tue, 27 Sep 2022 19:20:24 +0000 Subject: [PATCH 102/656] Support 3G ECNO thresholds in SignalStrengthController Bug: 248865591 Test: atest FrameworkTelephonyTests Change-Id: Idde503c1f1bae5eefefac1963c087d5e4014b825 --- .../telephony/SignalStrengthController.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/java/com/android/internal/telephony/SignalStrengthController.java b/src/java/com/android/internal/telephony/SignalStrengthController.java index d950a9df68..6e32cf34ee 100644 --- a/src/java/com/android/internal/telephony/SignalStrengthController.java +++ b/src/java/com/android/internal/telephony/SignalStrengthController.java @@ -480,6 +480,18 @@ public class SignalStrengthController extends Handler { AccessNetworkConstants.AccessNetworkType.NGRAN, (nrMeasurementEnabled & CellSignalStrengthNr.USE_SSSINR) != 0)); } + + int[] wcdmaEcnoThresholds = mCarrierConfig.getIntArray( + CarrierConfigManager.KEY_WCDMA_ECNO_THRESHOLDS_INT_ARRAY); + if (wcdmaEcnoThresholds != null) { + signalThresholdInfos.add( + createSignalThresholdsInfo( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO, + wcdmaEcnoThresholds, + AccessNetworkConstants.AccessNetworkType.UTRAN, + false)); + } + } consolidatedAndSetReportingCriteria(signalThresholdInfos); @@ -546,6 +558,12 @@ public class SignalStrengthController extends Handler { AccessNetworkThresholds.NGRAN_SSSINR, AccessNetworkConstants.AccessNetworkType.NGRAN, false)); + signalThresholdInfos.add( + createSignalThresholdsInfo( + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO, + AccessNetworkThresholds.UTRAN_ECNO, + AccessNetworkConstants.AccessNetworkType.UTRAN, + false)); } consolidatedAndSetReportingCriteria(signalThresholdInfos); @@ -1108,6 +1126,16 @@ public class SignalStrengthController extends Handler { 15, /* SIGNAL_STRENGTH_GOOD */ 30 /* SIGNAL_STRENGTH_GREAT */ }; + + /** + * List of dBm thresholds for UTRAN {@link AccessNetworkConstants.AccessNetworkType} ECNO + */ + public static final int[] UTRAN_ECNO = new int[]{ + -24, /* SIGNAL_STRENGTH_POOR */ + -14, /* SIGNAL_STRENGTH_MODERATE */ + -6, /* SIGNAL_STRENGTH_GOOD */ + 1 /* SIGNAL_STRENGTH_GREAT */ + }; } private static void log(String msg) { -- GitLab From cec627e25845c93478f6a9caa244af32caba4c8f Mon Sep 17 00:00:00 2001 From: rambowang Date: Wed, 28 Sep 2022 10:02:36 -0500 Subject: [PATCH 103/656] Update CellularNetworkValidator with new carrier config key Carrier config key KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG has been renamed to KEY_DATA_SWITCH_VALIDATION_MIN_INTERVAL_MILLIS_LONG to follow the canonical naming format when exposing as public. Bug: 181813215 Test: atest CellularNetworkValidatorTest Change-Id: Idfd8d5d32c8bed71fbe91154c2a65cb987a35850 --- .../internal/telephony/data/CellularNetworkValidator.java | 4 ++-- .../internal/telephony/data/CellularNetworkValidatorTest.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java b/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java index c63676f67a..6d020f7c42 100644 --- a/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java +++ b/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java @@ -17,7 +17,7 @@ package com.android.internal.telephony.data; import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; -import static android.telephony.CarrierConfigManager.KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG; +import static android.telephony.CarrierConfigManager.KEY_DATA_SWITCH_VALIDATION_MIN_INTERVAL_MILLIS_LONG; import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; import android.content.Context; @@ -192,7 +192,7 @@ public class CellularNetworkValidator { if (configManager != null) { PersistableBundle b = configManager.getConfigForSubId(subId); if (b != null) { - ttl = b.getLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG); + ttl = b.getLong(KEY_DATA_SWITCH_VALIDATION_MIN_INTERVAL_MILLIS_LONG); } } // Ttl can't be bigger than one day for now. diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java index 511b2dfc51..3773756dcc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java @@ -490,6 +490,7 @@ public class CellularNetworkValidatorTest extends TelephonyTest { CarrierConfigManager carrierConfigManager = (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); PersistableBundle bundle = carrierConfigManager.getConfigForSubId(anyInt()); - bundle.putLong(CarrierConfigManager.KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, ttl); + bundle.putLong(CarrierConfigManager.KEY_DATA_SWITCH_VALIDATION_MIN_INTERVAL_MILLIS_LONG, + ttl); } } -- GitLab From 147eccd7614989c617c30ae796c51f087dd76f5b Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 30 Sep 2022 13:53:42 -0700 Subject: [PATCH 104/656] Fixed potential string conversion issues Replaced all toLowerCase() with toLowerCase(Locale.ROOT). Replaced all toUpperCase() with toUpperCase(Locale.ROOT). Fix: 250048156 Test: atest FrameworksTelephonyTests + Basic testing Change-Id: Icd58ecef7a761f8c6bd0f44ce201d571373dbd22 --- .../telephony/CarrierPrivilegesTracker.java | 5 +- .../internal/telephony/CarrierResolver.java | 4 +- .../internal/telephony/GsmCdmaPhone.java | 3 +- .../IccPhoneBookInterfaceManager.java | 6 +- .../internal/telephony/IccProvider.java | 3 +- .../telephony/NetworkTypeController.java | 7 +- .../com/android/internal/telephony/Phone.java | 2 +- .../android/internal/telephony/RILUtils.java | 5 +- .../emergency/EmergencyNumberTracker.java | 18 +-- .../telephony/gsm/UsimPhoneBookManager.java | 12 +- .../imsphone/ImsPhoneCallTracker.java | 5 +- .../internal/telephony/metrics/RcsStats.java | 114 ++++++++++-------- .../telephony/uicc/AdnRecordCache.java | 13 +- .../uicc/InstallCarrierAppUtils.java | 3 +- .../internal/telephony/uicc/UiccProfile.java | 5 +- 15 files changed, 118 insertions(+), 87 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index 31442297b1..b3afb66102 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -86,6 +86,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -610,10 +611,10 @@ public class CarrierPrivilegesTracker extends Handler { List signatures = UiccAccessRule.getSignatures(pkg); for (Signature signature : signatures) { byte[] sha1 = UiccAccessRule.getCertHash(signature, SHA_1); - certs.add(IccUtils.bytesToHexString(sha1).toUpperCase()); + certs.add(IccUtils.bytesToHexString(sha1).toUpperCase(Locale.ROOT)); byte[] sha256 = UiccAccessRule.getCertHash(signature, SHA_256); - certs.add(IccUtils.bytesToHexString(sha256).toUpperCase()); + certs.add(IccUtils.bytesToHexString(sha256).toUpperCase(Locale.ROOT)); } mInstalledPackageCerts.put(pkg.packageName, certs); diff --git a/src/java/com/android/internal/telephony/CarrierResolver.java b/src/java/com/android/internal/telephony/CarrierResolver.java index 37c45956bb..7f1d349804 100644 --- a/src/java/com/android/internal/telephony/CarrierResolver.java +++ b/src/java/com/android/internal/telephony/CarrierResolver.java @@ -54,6 +54,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; /** * CarrierResolver identifies the subscription carrier and returns a canonical carrier Id @@ -751,7 +752,8 @@ public class CarrierResolver extends Handler { // Ideally we should do full string match. However due to SIM manufacture issues // gid from some SIM might has garbage tail. private boolean gidMatch(String gidFromSim, String gid) { - return (gidFromSim != null) && gidFromSim.toLowerCase().startsWith(gid.toLowerCase()); + return (gidFromSim != null) && gidFromSim.toLowerCase(Locale.ROOT) + .startsWith(gid.toLowerCase(Locale.ROOT)); } private boolean carrierPrivilegeRulesMatch(List certsFromSubscription, diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 97c857f787..77b0909622 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -130,6 +130,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.function.Consumer; import java.util.regex.Matcher; @@ -4570,7 +4571,7 @@ public class GsmCdmaPhone extends Phone { if (subInfo == null || TextUtils.isEmpty(subInfo.getCountryIso())) { return null; } - return subInfo.getCountryIso().toUpperCase(); + return subInfo.getCountryIso().toUpperCase(Locale.ROOT); } public void notifyEcbmTimerReset(Boolean flag) { diff --git a/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java index 742cc900b9..ab62aa4ac1 100644 --- a/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java +++ b/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java @@ -39,6 +39,7 @@ import com.android.internal.telephony.uicc.UiccProfile; import com.android.telephony.Rlog; import java.util.List; +import java.util.Locale; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -337,7 +338,10 @@ public class IccPhoneBookInterfaceManager { } efid = updateEfForIccType(efid); - if (DBG) logd("getAdnRecordsInEF: efid=0x" + Integer.toHexString(efid).toUpperCase()); + if (DBG) { + logd("getAdnRecordsInEF: efid=0x" + Integer.toHexString(efid) + .toUpperCase(Locale.ROOT)); + } checkThread(); Request loadRequest = new Request(); diff --git a/src/java/com/android/internal/telephony/IccProvider.java b/src/java/com/android/internal/telephony/IccProvider.java index 7a128c034d..b7c7e7b538 100644 --- a/src/java/com/android/internal/telephony/IccProvider.java +++ b/src/java/com/android/internal/telephony/IccProvider.java @@ -37,6 +37,7 @@ import com.android.internal.telephony.uicc.IccConstants; import com.android.telephony.Rlog; import java.util.List; +import java.util.Locale; /** * {@hide} @@ -424,7 +425,7 @@ public class IccProvider extends ContentProvider { private MatrixCursor loadFromEf(int efType, int subId) { if (DBG) log("loadFromEf: efType=0x" + - Integer.toHexString(efType).toUpperCase() + ", subscription=" + subId); + Integer.toHexString(efType).toUpperCase(Locale.ROOT) + ", subscription=" + subId); List adnRecords = null; try { diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 9cb21945de..6f6d655378 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -52,6 +52,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -350,7 +351,7 @@ public class NetworkTypeController extends StateMachine { if (!TextUtils.isEmpty(icons)) { // Format: "STATE:ICON,STATE2:ICON2" for (String pair : icons.trim().split(",")) { - String[] kv = (pair.trim().toLowerCase()).split(":"); + String[] kv = (pair.trim().toLowerCase(Locale.ROOT)).split(":"); if (kv.length != 2) { if (DBG) loge("Invalid 5G icon configuration, config = " + pair); continue; @@ -377,7 +378,7 @@ public class NetworkTypeController extends StateMachine { if (!TextUtils.isEmpty(timers)) { // Format: "FROM_STATE,TO_STATE,DURATION;FROM_STATE_2,TO_STATE_2,DURATION_2" for (String triple : timers.trim().split(";")) { - String[] kv = (triple.trim().toLowerCase()).split(","); + String[] kv = (triple.trim().toLowerCase(Locale.ROOT)).split(","); if (kv.length != 3) { if (DBG) loge("Invalid 5G icon timer configuration, config = " + triple); continue; @@ -403,7 +404,7 @@ public class NetworkTypeController extends StateMachine { if (!TextUtils.isEmpty(secondaryTimers)) { // Format: "PRIMARY_STATE,TO_STATE,DURATION;PRIMARY_STATE_2,TO_STATE_2,DURATION_2" for (String triple : secondaryTimers.trim().split(";")) { - String[] kv = (triple.trim().toLowerCase()).split(","); + String[] kv = (triple.trim().toLowerCase(Locale.ROOT)).split(","); if (kv.length != 3) { if (DBG) { loge("Invalid 5G icon secondary timer configuration, config = " + triple); diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 835a87c802..90ba524494 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -2383,7 +2383,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { try { // Format: "REASON=VALUE,REASON2=VALUE2" for (String pair : result.trim().split(",")) { - String[] networkTypesValues = (pair.trim().toLowerCase()).split("="); + String[] networkTypesValues = (pair.trim().toLowerCase(Locale.ROOT)).split("="); if (networkTypesValues.length != 2) { Rlog.e(LOG_TAG, "Invalid ALLOWED_NETWORK_TYPES from DB, value = " + pair); continue; diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 61f1e82a76..2d1107c27c 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -1441,8 +1441,9 @@ public class RILUtils { if (ComprehensionTlvTag.TEXT_STRING.value() == ctlv.getTag()) { byte[] target = Arrays.copyOfRange(ctlv.getRawValue(), from, ctlv.getValueIndex() + ctlv.getLength()); - terminalResponse = terminalResponse.toLowerCase().replace( - IccUtils.bytesToHexString(target).toLowerCase(), "********"); + terminalResponse = terminalResponse.toLowerCase(Locale.ROOT).replace( + IccUtils.bytesToHexString(target).toLowerCase(Locale.ROOT), + "********"); } // The text string tag and the length field should also be hidden. from = ctlv.getValueIndex() + ctlv.getLength(); diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index b8404d9d7e..de6042842f 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -67,6 +67,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.zip.GZIPInputStream; /** @@ -286,7 +287,7 @@ public class EmergencyNumberTracker extends Handler { // If country iso has been cached when listener is set, don't need to cache the initial // country iso and initial database. if (mCountryIso == null) { - String countryForDatabaseCache = getInitialCountryIso().toLowerCase(); + String countryForDatabaseCache = getInitialCountryIso().toLowerCase(Locale.ROOT); updateEmergencyCountryIso(countryForDatabaseCache); // Use the last known country to cache the database in APM if (TextUtils.isEmpty(countryForDatabaseCache) @@ -467,7 +468,7 @@ public class EmergencyNumberTracker extends Handler { logd(countryIso + " asset emergency database is loaded. Ver: " + assetsDatabaseVersion + " Phone Id: " + mPhone.getPhoneId()); for (ProtobufEccData.CountryInfo countryEccInfo : allEccMessages.countries) { - if (countryEccInfo.isoCode.equals(countryIso.toUpperCase())) { + if (countryEccInfo.isoCode.equals(countryIso.toUpperCase(Locale.ROOT))) { for (ProtobufEccData.EccInfo eccInfo : countryEccInfo.eccs) { updatedAssetEmergencyNumberList.add(convertEmergencyNumberFromEccInfo( eccInfo, countryIso)); @@ -527,7 +528,7 @@ public class EmergencyNumberTracker extends Handler { logd(countryIso + " ota emergency database is loaded. Ver: " + otaDatabaseVersion); otaDatabaseVersion = allEccMessages.revision; for (ProtobufEccData.CountryInfo countryEccInfo : allEccMessages.countries) { - if (countryEccInfo.isoCode.equals(countryIso.toUpperCase())) { + if (countryEccInfo.isoCode.equals(countryIso.toUpperCase(Locale.ROOT))) { for (ProtobufEccData.EccInfo eccInfo : countryEccInfo.eccs) { updatedOtaEmergencyNumberList.add(convertEmergencyNumberFromEccInfo( eccInfo, countryIso)); @@ -593,7 +594,7 @@ public class EmergencyNumberTracker extends Handler { private void updateEmergencyNumberListDatabaseAndNotify(String countryIso) { logd("updateEmergencyNumberListDatabaseAndNotify(): receiving countryIso: " + countryIso); - updateEmergencyCountryIso(countryIso.toLowerCase()); + updateEmergencyCountryIso(countryIso.toLowerCase(Locale.ROOT)); // Use cached country iso in APM to load emergency number database. if (TextUtils.isEmpty(countryIso) && isAirplaneModeEnabled()) { countryIso = getCountryIsoForCachingDatabase(); @@ -921,8 +922,8 @@ public class EmergencyNumberTracker extends Handler { number = PhoneNumberUtils.stripSeparators(number); for (EmergencyNumber num : mEmergencyNumberListFromDatabase) { if (num.getNumber().equals(number)) { - return new EmergencyNumber(number, getLastKnownEmergencyCountryIso().toLowerCase(), - "", num.getEmergencyServiceCategoryBitmask(), + return new EmergencyNumber(number, getLastKnownEmergencyCountryIso() + .toLowerCase(Locale.ROOT), "", num.getEmergencyServiceCategoryBitmask(), new ArrayList(), EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); } @@ -1023,11 +1024,12 @@ public class EmergencyNumberTracker extends Handler { // No ecclist system property, so use our own list. if (countryIso != null) { ShortNumberInfo info = ShortNumberInfo.getInstance(); - if (info.isEmergencyNumber(number, countryIso.toUpperCase())) { + if (info.isEmergencyNumber(number, countryIso.toUpperCase(Locale.ROOT))) { return true; } else { for (String prefix : mEmergencyNumberPrefix) { - if (info.isEmergencyNumber(prefix + number, countryIso.toUpperCase())) { + if (info.isEmergencyNumber(prefix + number, + countryIso.toUpperCase(Locale.ROOT))) { return true; } } diff --git a/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java index e594ab6c1f..48be16c3e7 100755 --- a/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java +++ b/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java @@ -32,6 +32,7 @@ import com.android.internal.telephony.uicc.IccUtils; import com.android.telephony.Rlog; import java.util.ArrayList; +import java.util.Locale; /** * This class implements reading and parsing USIM records. @@ -233,7 +234,7 @@ public class UsimPhoneBookManager extends Handler implements IccConstants { int emailEfid = email.getEfid(); log("EF_EMAIL exists in PBR. efid = 0x" + - Integer.toHexString(emailEfid).toUpperCase()); + Integer.toHexString(emailEfid).toUpperCase(Locale.ROOT)); /** * Make sure this EF_EMAIL was never read earlier. Sometimes two PBR record points @@ -348,7 +349,7 @@ public class UsimPhoneBookManager extends Handler implements IccConstants { emailList = new ArrayList(); } log("Adding email #" + i + " list to index 0x" + - Integer.toHexString(index).toUpperCase()); + Integer.toHexString(index).toUpperCase(Locale.ROOT)); emailList.add(email); mEmailsForAdnRec.put(index, emailList); } @@ -402,7 +403,7 @@ public class UsimPhoneBookManager extends Handler implements IccConstants { } emailList.add(email); log("Adding email list to index 0x" + - Integer.toHexString(index).toUpperCase()); + Integer.toHexString(index).toUpperCase(Locale.ROOT)); mEmailsForAdnRec.put(index, emailList); } } @@ -446,8 +447,9 @@ public class UsimPhoneBookManager extends Handler implements IccConstants { System.arraycopy(emailList.toArray(), 0, emails, 0, emailList.size()); rec.setEmails(emails); log("Adding email list to ADN (0x" + - Integer.toHexString(mPhoneBookRecords.get(i).getEfid()).toUpperCase() + - ") record #" + mPhoneBookRecords.get(i).getRecId()); + Integer.toHexString(mPhoneBookRecords.get(i).getEfid()) + .toUpperCase(Locale.ROOT) + ") record #" + + mPhoneBookRecords.get(i).getRecId()); mPhoneBookRecords.set(i, rec); } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 1f2b0ea7b2..f967f909b2 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -136,6 +136,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -2802,7 +2803,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { @VisibleForTesting public void addReasonCodeRemapping(Integer fromCode, String message, Integer toCode) { if (message != null) { - message = message.toLowerCase(); + message = message.toLowerCase(Locale.ROOT); } mImsReasonCodeMap.put(new Pair<>(fromCode, message), toCode); } @@ -2823,7 +2824,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { if (reason == null) { reason = ""; } else { - reason = reason.toLowerCase(); + reason = reason.toLowerCase(Locale.ROOT); } log("maybeRemapReasonCode : fromCode = " + reasonInfo.getCode() + " ; message = " + reason); diff --git a/src/java/com/android/internal/telephony/metrics/RcsStats.java b/src/java/com/android/internal/telephony/metrics/RcsStats.java index 4a1ff0de86..8751d82bb1 100644 --- a/src/java/com/android/internal/telephony/metrics/RcsStats.java +++ b/src/java/com/android/internal/telephony/metrics/RcsStats.java @@ -85,6 +85,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Random; import java.util.Set; @@ -129,48 +130,51 @@ public class RcsStats { private static final Map FEATURE_TAGS = new HashMap<>(); static { - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_STANDALONE_MSG.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_STANDALONE_MSG.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_STANDALONE_MSG); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHAT_IM.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHAT_IM.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_CHAT_IM); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHAT_SESSION.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHAT_SESSION.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_CHAT_SESSION); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_FILE_TRANSFER.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_FILE_TRANSFER.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_FILE_TRANSFER); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_FILE_TRANSFER_VIA_SMS.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_FILE_TRANSFER_VIA_SMS.trim() + .toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_FILE_TRANSFER_VIA_SMS); FEATURE_TAGS.put( - FeatureTags.FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING.trim().toLowerCase(), + FeatureTags.FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING.trim() + .toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING); FEATURE_TAGS.put( - FeatureTags.FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY.trim().toLowerCase(), + FeatureTags.FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_POST_CALL.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_POST_CALL.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_POST_CALL); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_SHARED_MAP.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_SHARED_MAP.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_SHARED_MAP); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_SHARED_SKETCH.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_SHARED_SKETCH.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_SHARED_SKETCH); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_GEO_PUSH.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_GEO_PUSH.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_GEO_PUSH); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_GEO_PUSH_VIA_SMS.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_GEO_PUSH_VIA_SMS.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_GEO_PUSH_VIA_SMS); FEATURE_TAGS.put( - FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION.trim().toLowerCase(), + FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION.trim() + .toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION); String FeatureTag = FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG; - FEATURE_TAGS.put(FeatureTag.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTag.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG); FEATURE_TAGS.put( - FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED.trim().toLowerCase(), + FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_VERSION_SUPPORTED); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHATBOT_ROLE.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHATBOT_ROLE.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_ROLE); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_MMTEL.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_MMTEL.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_MMTEL); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_VIDEO.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_VIDEO.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_VIDEO); - FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_PRESENCE.trim().toLowerCase(), + FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_PRESENCE.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_PRESENCE); } @@ -183,34 +187,42 @@ public class RcsStats { private static final Map SERVICE_IDS = new HashMap<>(); static { - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_MMTEL.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_MMTEL.trim().toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_MMTEL); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHAT_V1.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHAT_V1.trim().toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V1); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHAT_V2.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHAT_V2.trim().toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V2); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_FT.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_FT.trim().toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_FT_OVER_SMS.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_FT_OVER_SMS.trim() + .toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT_OVER_SMS); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH.trim().toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH_VIA_SMS.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH_VIA_SMS.trim() + .toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH_VIA_SMS); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER.trim() + .toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CALL_COMPOSER); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_POST_CALL.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_POST_CALL.trim() + .toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_POST_CALL); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_SHARED_MAP.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_SHARED_MAP.trim() + .toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_MAP); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_SHARED_SKETCH.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_SHARED_SKETCH.trim() + .toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_SKETCH); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT.trim().toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_STANDALONE.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_STANDALONE.trim() + .toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_STANDALONE ); - SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_ROLE.trim().toLowerCase(), + SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_ROLE.trim() + .toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_ROLE); } @@ -221,33 +233,33 @@ public class RcsStats { private static final Map MESSAGE_TYPE = new HashMap<>(); static { - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_INVITE.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_INVITE.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_INVITE); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_ACK.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_ACK.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_ACK); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_OPTIONS.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_OPTIONS.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_OPTIONS); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_BYE.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_BYE.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_BYE); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_CANCEL.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_CANCEL.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_CANCEL); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_REGISTER.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_REGISTER.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_REGISTER); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_PRACK.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_PRACK.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_PRACK); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_SUBSCRIBE.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_SUBSCRIBE.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_SUBSCRIBE); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_NOTIFY.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_NOTIFY.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_NOTIFY); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_PUBLISH.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_PUBLISH.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_PUBLISH); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_INFO.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_INFO.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_INFO); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_REFER.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_REFER.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_REFER); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_MESSAGE.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_MESSAGE.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_MESSAGE); - MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_UPDATE.trim().toLowerCase(), + MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_UPDATE.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_UPDATE); } @@ -1575,28 +1587,28 @@ public class RcsStats { /** Get a enum value from pre-defined feature tag name list */ @VisibleForTesting public int convertTagNameToValue(@NonNull String tagName) { - return FEATURE_TAGS.getOrDefault(tagName.trim().toLowerCase(), + return FEATURE_TAGS.getOrDefault(tagName.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.IMS_FEATURE_TAG_CUSTOM); } /** Get a enum value from pre-defined service id list */ @VisibleForTesting public int convertServiceIdToValue(@NonNull String serviceId) { - return SERVICE_IDS.getOrDefault(serviceId.trim().toLowerCase(), + return SERVICE_IDS.getOrDefault(serviceId.trim().toLowerCase(Locale.ROOT), IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CUSTOM); } /** Get a enum value from pre-defined message type list */ @VisibleForTesting public int convertMessageTypeToValue(@NonNull String messageType) { - return MESSAGE_TYPE.getOrDefault(messageType.trim().toLowerCase(), + return MESSAGE_TYPE.getOrDefault(messageType.trim().toLowerCase(Locale.ROOT), TelephonyProtoEnums.SIP_REQUEST_CUSTOM); } /** Get a enum value from pre-defined reason list */ @VisibleForTesting public int convertPresenceNotifyReason(@NonNull String reason) { - return NOTIFY_REASONS.getOrDefault(reason.trim().toLowerCase(), + return NOTIFY_REASONS.getOrDefault(reason.trim().toLowerCase(Locale.ROOT), PRESENCE_NOTIFY_EVENT__REASON__REASON_CUSTOM); } diff --git a/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java b/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java index 21a6e37981..ba06c5d46c 100644 --- a/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java +++ b/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java @@ -27,6 +27,7 @@ import com.android.internal.telephony.gsm.UsimPhoneBookManager; import java.util.ArrayList; import java.util.Iterator; +import java.util.Locale; /** * {@hide} @@ -156,14 +157,14 @@ public class AdnRecordCache extends Handler implements IccConstants { int extensionEF = extensionEfForEf(efid); if (extensionEF < 0) { sendErrorResponse(response, "EF is not known ADN-like EF:0x" + - Integer.toHexString(efid).toUpperCase()); + Integer.toHexString(efid).toUpperCase(Locale.ROOT)); return; } Message pendingResponse = mUserWriteResponse.get(efid); if (pendingResponse != null) { sendErrorResponse(response, "Have pending update for EF:0x" + - Integer.toHexString(efid).toUpperCase()); + Integer.toHexString(efid).toUpperCase(Locale.ROOT)); return; } @@ -196,7 +197,7 @@ public class AdnRecordCache extends Handler implements IccConstants { if (extensionEF < 0) { sendErrorResponse(response, "EF is not known ADN-like EF:0x" + - Integer.toHexString(efid).toUpperCase()); + Integer.toHexString(efid).toUpperCase(Locale.ROOT)); return; } @@ -210,7 +211,7 @@ public class AdnRecordCache extends Handler implements IccConstants { if (oldAdnList == null) { sendErrorResponse(response, "Adn list not exist for EF:0x" + - Integer.toHexString(efid).toUpperCase()); + Integer.toHexString(efid).toUpperCase(Locale.ROOT)); return; } @@ -244,7 +245,7 @@ public class AdnRecordCache extends Handler implements IccConstants { if (pendingResponse != null) { sendErrorResponse(response, "Have pending update for EF:0x" + - Integer.toHexString(efid).toUpperCase()); + Integer.toHexString(efid).toUpperCase(Locale.ROOT)); return; } @@ -307,7 +308,7 @@ public class AdnRecordCache extends Handler implements IccConstants { if (response != null) { AsyncResult.forMessage(response).exception = new RuntimeException("EF is not known ADN-like EF:0x" + - Integer.toHexString(efid).toUpperCase()); + Integer.toHexString(efid).toUpperCase(Locale.ROOT)); response.sendToTarget(); } diff --git a/src/java/com/android/internal/telephony/uicc/InstallCarrierAppUtils.java b/src/java/com/android/internal/telephony/uicc/InstallCarrierAppUtils.java index 412295dde8..7666f4cb05 100644 --- a/src/java/com/android/internal/telephony/uicc/InstallCarrierAppUtils.java +++ b/src/java/com/android/internal/telephony/uicc/InstallCarrierAppUtils.java @@ -38,6 +38,7 @@ import com.android.internal.telephony.util.NotificationChannelController; import java.util.Arrays; import java.util.List; +import java.util.Locale; /** * Utility methods for installing the carrier app when a SIM is insterted without the carrier app @@ -178,7 +179,7 @@ public class InstallCarrierAppUtils { */ @VisibleForTesting public static String getAppNameFromPackageName(String packageName, String mapString) { - packageName = packageName.toLowerCase(); + packageName = packageName.toLowerCase(Locale.ROOT); final String pairDelim = "\\s*;\\s*"; final String keyValueDelim = "\\s*:\\s*"; diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index 2809895309..5b84c6c066 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -77,6 +77,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -1393,7 +1394,7 @@ public class UiccProfile extends IccCard { Set uninstalledCarrierPackages = new ArraySet<>(); List accessRules = rules.getAccessRules(); for (UiccAccessRule accessRule : accessRules) { - String certHexString = accessRule.getCertificateHexString().toUpperCase(); + String certHexString = accessRule.getCertificateHexString().toUpperCase(Locale.ROOT); String pkgName = certPackageMap.get(certHexString); if (!TextUtils.isEmpty(pkgName) && !isPackageBundled(mContext, pkgName)) { uninstalledCarrierPackages.add(pkgName); @@ -1423,7 +1424,7 @@ public class UiccProfile extends IccCard { String[] keyValue = keyValueString.split(keyValueDelim); if (keyValue.length == 2) { - map.put(keyValue[0].toUpperCase(), keyValue[1]); + map.put(keyValue[0].toUpperCase(Locale.ROOT), keyValue[1]); } else { loge("Incorrect length of key-value pair in carrier app allow list map. " + "Length should be exactly 2"); -- GitLab From 353905bc6e1007095a07d13c11a35d68e789c415 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 12 Sep 2022 17:33:56 -0700 Subject: [PATCH 105/656] Added empty subscription manager service Non-functional skeleton. The methods are added because we can't remove methods in ISub.aidl at this point. Those are still used by the to-be-removed SubscriptionController. Bug: 239607619 Test: Manual Change-Id: Iffc26de09a8da75b052f06399cf033b2df1d3ec8 --- .../com/android/internal/telephony/Phone.java | 18 + .../internal/telephony/PhoneFactory.java | 14 +- .../SubscriptionManagerService.java | 606 ++++++++++++++++++ 3 files changed, 635 insertions(+), 3 deletions(-) create mode 100644 src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 835a87c802..7c17fc7508 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -82,6 +82,7 @@ import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; import com.android.internal.telephony.metrics.SmsStats; import com.android.internal.telephony.metrics.VoiceCallSessionStats; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.test.SimulatedRadioControl; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; import com.android.internal.telephony.uicc.IccFileHandler; @@ -354,6 +355,12 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private int mUsageSettingFromModem = SubscriptionManager.USAGE_SETTING_UNKNOWN; private boolean mIsUsageSettingSupported = true; + /** + * {@code true} if the new SubscriptionManagerService is enabled, otherwise the old + * SubscriptionController is used. + */ + private boolean mIsSubscriptionManagerServiceEnabled = false; + //IMS /** * {@link CallStateException} message text used to indicate that an IMS call has failed because @@ -600,6 +607,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mTelephonyTester = new TelephonyTester(this); } + mIsSubscriptionManagerServiceEnabled = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_using_subscription_manager_service); + // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers. mTelephonyComponentFactory = telephonyComponentFactory; mSmsStorageMonitor = mTelephonyComponentFactory.inject(SmsStorageMonitor.class.getName()) @@ -4882,6 +4892,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return mTelephonyTester; } + /** + * @return {@code true} if the new {@link SubscriptionManagerService} is enabled, otherwise the + * old {@link SubscriptionController} is used. + */ + public boolean isSubscriptionManagerServiceEnabled() { + return mIsSubscriptionManagerServiceEnabled; + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index 3361b74710..eb11b12c81 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -50,6 +50,7 @@ import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneFactory; import com.android.internal.telephony.metrics.MetricsCollector; import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.util.NotificationChannelController; import com.android.internal.util.IndentingPrintWriter; @@ -83,6 +84,7 @@ public class PhoneFactory { private static IntentBroadcaster sIntentBroadcaster; private static @Nullable EuiccController sEuiccController; private static @Nullable EuiccCardController sEuiccCardController; + private static SubscriptionManagerService sSubscriptionManagerService; static private SubscriptionInfoUpdater sSubInfoRecordUpdater = null; @@ -194,9 +196,15 @@ public class PhoneFactory { // call getInstance() sUiccController = UiccController.make(context); - Rlog.i(LOG_TAG, "Creating SubscriptionController"); - TelephonyComponentFactory.getInstance().inject(SubscriptionController.class. - getName()).initSubscriptionController(context); + if (sContext.getResources().getBoolean( + com.android.internal.R.bool.config_using_subscription_manager_service)) { + Rlog.i(LOG_TAG, "Creating SubscriptionManagerService"); + sSubscriptionManagerService = new SubscriptionManagerService(context); + } else { + Rlog.i(LOG_TAG, "Creating SubscriptionController"); + TelephonyComponentFactory.getInstance().inject(SubscriptionController.class + .getName()).initSubscriptionController(context); + } TelephonyComponentFactory.getInstance().inject(MultiSimSettingController.class. getName()).initMultiSimSettingController(context, SubscriptionController.getInstance()); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java new file mode 100644 index 0000000000..e8c932ba77 --- /dev/null +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -0,0 +1,606 @@ +/* + * Copyright 2022 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.subscription; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.ParcelUuid; +import android.os.TelephonyServiceManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.SubscriptionManager.SubscriptionType; +import android.telephony.TelephonyFrameworkInitializer; +import android.util.IndentingPrintWriter; +import android.util.LocalLog; + +import com.android.internal.telephony.ISetOpportunisticDataCallback; +import com.android.internal.telephony.ISub; +import com.android.telephony.Rlog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Collections; +import java.util.List; + +/** + * The subscription manager service is the backend service of {@link SubscriptionManager}. + * The service handles all SIM subscription related requests from clients. + */ +public class SubscriptionManagerService extends ISub.Stub { + private static final String LOG_TAG = "SMSVC"; + + /** Whether enabling verbose debugging message or not. */ + private static final boolean VDBG = false; + + /** The context */ + private final Context mContext; + + /** Local log for most important debug messages. */ + private final LocalLog mLocalLog = new LocalLog(128); + + /** + * The constructor + * + * @param context The context + */ + public SubscriptionManagerService(@NonNull Context context) { + mContext = context; + TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer(); + subscriptionServiceRegisterer.register(this); + } + + /** + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package + * @return a list of all subscriptions in the database, this includes + * all subscriptions that have been seen. + */ + @Override + public List getAllSubInfoList(@NonNull String callingPackage, + @NonNull String callingFeatureId) { + return null; + } + + /** + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package + * + * @return the count of all subscriptions in the database, this includes all subscriptions that + * have been seen. + */ + @Override + public int getAllSubInfoCount(@NonNull String callingPackage, + @NonNull String callingFeatureId) { + return 0; + } + + /** + * Get the active {@link SubscriptionInfo} with the subscription id key. + * + * @param subId The unique {@link SubscriptionInfo} key in database + * @param callingPackage The package making the call + * @param callingFeatureId The feature in the package + * + * @return The subscription info. + */ + @Override + @Nullable + public SubscriptionInfo getActiveSubscriptionInfo(int subId, @NonNull String callingPackage, + @NonNull String callingFeatureId) { + return null; + } + + /** + * Get the active {@link SubscriptionInfo} associated with the iccId. + * + * @param iccId the IccId of SIM card + * @param callingPackage The package making the call + * @param callingFeatureId The feature in the package + * + * @return The subscription info. + */ + @Override + @Nullable + public SubscriptionInfo getActiveSubscriptionInfoForIccId(@NonNull String iccId, + @NonNull String callingPackage, @NonNull String callingFeatureId) { + return null; + } + + /** + * Get the active {@link SubscriptionInfo} associated with the logical SIM slot index. + * + * @param slotIndex the logical SIM slot index which the subscription is inserted + * @param callingPackage The package making the call + * @param callingFeatureId The feature in the package + * + * @return SubscriptionInfo, null for Remote-SIMs or non-active logical SIM slot index. + */ + @Override + public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, + @NonNull String callingPackage, @NonNull String callingFeatureId) { + return null; + } + + /** + * Get the SubscriptionInfo(s) of the active subscriptions. The records will be sorted + * by {@link SubscriptionInfo#getSimSlotIndex} then by + * {@link SubscriptionInfo#getSubscriptionId}. + * + * @param callingPackage The package making the call + * @param callingFeatureId The feature in the package + * @return Sorted list of the currently {@link SubscriptionInfo} records available on the + * device. + *

    + *
  • + * If null is returned the current state is unknown but if a + * {@link OnSubscriptionsChangedListener} has been registered + * {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be invoked in the future. + *
  • + *
  • + * If the list is empty then there are no {@link SubscriptionInfo} records currently available. + *
  • + *
  • + * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} + * then by {@link SubscriptionInfo#getSubscriptionId}. + *
  • + *
+ */ + @Override + public List getActiveSubscriptionInfoList(@NonNull String callingPackage, + @NonNull String callingFeatureId) { + return null; + } + + /** + * Get the number of active {@link SubscriptionInfo}. + * + * @param callingPackage The package making the call + * @param callingFeatureId The feature in the package + * @return the number of active subscriptions + */ + @Override + public int getActiveSubInfoCount(@NonNull String callingPackage, + @NonNull String callingFeatureId) { + return 0; + } + + /** + * @return the maximum number of subscriptions this device will support at any one time. + */ + @Override + public int getActiveSubInfoCountMax() { + return 0; + } + + /** + * @see SubscriptionManager#getAvailableSubscriptionInfoList + */ + @Override + public List getAvailableSubscriptionInfoList(@NonNull String callingPackage, + @NonNull String callingFeatureId) { + return null; + } + + /** + * @see SubscriptionManager#getAccessibleSubscriptionInfoList + */ + @Override + public List getAccessibleSubscriptionInfoList( + @NonNull String callingPackage) { + return null; + } + + /** + * @see SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh + */ + @Override + public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) { + + } + + /** + * Add a new subscription record to subscription database if needed. + * + * @param iccId the IccId of the SIM card + * @param slotIndex the slot which the SIM is inserted + * + * @return 0 if success, negative if failed. + */ + @Override + public int addSubInfoRecord(@NonNull String iccId, int slotIndex) { + return 0; + } + + /** + * Add a new subscription info record, if needed. + * + * @param uniqueId This is the unique identifier for the subscription within the specific + * subscription type + * @param displayName human-readable name of the device the subscription corresponds to + * @param slotIndex the slot assigned to this device + * @param subscriptionType the type of subscription to be added + * + * @return 0 if success, < 0 on error + */ + @Override + public int addSubInfo(@NonNull String uniqueId, @NonNull String displayName, int slotIndex, + @SubscriptionType int subscriptionType) { + return 0; + } + + /** + * Remove subscription info record for the given device. + * + * @param uniqueId This is the unique identifier for the subscription within the specific + * subscription type. + * @param subscriptionType the type of subscription to be removed + * + * @return 0 if success, < 0 on error + */ + @Override + public int removeSubInfo(@NonNull String uniqueId, int subscriptionType) { + return 0; + } + + /** + * Set SIM icon tint color by simInfo index. + * + * @param tint the icon tint color of the SIM + * @param subId the unique subscription index in database + * + * @return the number of records updated + */ + @Override + public int setIconTint(int tint, int subId) { + return 0; + } + + /** + * Set display name by simInfo index with name source. + * + * @param displayName the display name of SIM card + * @param subId the unique SubscriptionInfo index in database + * @param nameSource 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT + * + * @return the number of records updated + */ + @Override + public int setDisplayNameUsingSrc(@NonNull String displayName, int subId, int nameSource) { + return 0; + } + + /** + * Set phone number by subscription id. + * + * @param number the phone number of the SIM + * @param subId the unique SubscriptionInfo index in database + * + * @return the number of records updated + */ + @Override + public int setDisplayNumber(@NonNull String number, int subId) { + return 0; + } + + /** + * Set data roaming by simInfo index + * + * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming + * @param subId the unique SubscriptionInfo index in database + * + * @return the number of records updated + */ + @Override + public int setDataRoaming(int roaming, int subId) { + return 0; + } + + /** + * Switch to a certain subscription. + * + * @param opportunistic whether it’s opportunistic subscription + * @param subId the unique SubscriptionInfo index in database + * @param callingPackage The package making the call + * + * @return the number of records updated + */ + @Override + public int setOpportunistic(boolean opportunistic, int subId, @NonNull String callingPackage) { + return 0; + } + + /** + * Inform SubscriptionManager that subscriptions in the list are bundled as a group. Typically + * it's a primary subscription and an opportunistic subscription. It should only affect + * multi-SIM scenarios where primary and opportunistic subscriptions can be activated together. + * + * Being in the same group means they might be activated or deactivated together, some of them + * may be invisible to the users, etc. + * + * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} permission or + * can manage all subscriptions in the list, according to their access rules. + * + * @param subIdList list of subId that will be in the same group + * @param callingPackage The package making the call + * + * @return groupUUID a UUID assigned to the subscription group. It returns null if fails. + */ + @Override + public ParcelUuid createSubscriptionGroup(int[] subIdList, @NonNull String callingPackage) { + return null; + } + + /** + * Set which subscription is preferred for cellular data. It's designed to overwrite default + * data subscription temporarily. + * + * @param subId which subscription is preferred to for cellular data + * @param needValidation whether validation is needed before switching + * @param callback callback upon request completion + */ + @Override + public void setPreferredDataSubscriptionId(int subId, boolean needValidation, + @Nullable ISetOpportunisticDataCallback callback) { + } + + /** + * @return The subscription id of preferred subscription for cellular data. This reflects + * the active modem which can serve large amount of cellular data. + */ + @Override + public int getPreferredDataSubscriptionId() { + return 0; + } + + /** + * @return The list of opportunistic subscription info that can be accessed by the callers. + */ + @Override + @NonNull + public List getOpportunisticSubscriptions(@NonNull String callingPackage, + @NonNull String callingFeatureId) { + return Collections.emptyList(); + } + + @Override + public void removeSubscriptionsFromGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, + @NonNull String callingPackage) { + } + + @Override + public void addSubscriptionsIntoGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, + @NonNull String callingPackage) { + } + + @Override + public List getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid, + @NonNull String callingPackage, @NonNull String callingFeatureId) { + return null; + } + + @Override + public int getSlotIndex(int subId) { + return 0; + } + + @Override + public int[] getSubId(int slotIndex) { + return null; + } + + @Override + public int getDefaultSubId() { + return 0; + } + + @Override + public int clearSubInfo() { + return 0; + } + + @Override + public int getPhoneId(int subId) { + return 0; + } + + /** + * @return Subscription id of the default cellular data. This reflects the user's default data + * choice, which might be a little bit different than the active one returned by + * {@link #getPreferredDataSubscriptionId()}. + */ + @Override + public int getDefaultDataSubId() { + return 0; + } + + @Override + public void setDefaultDataSubId(int subId) { + } + + @Override + public int getDefaultVoiceSubId() { + return 0; + } + + @Override + public void setDefaultVoiceSubId(int subId) { + } + + @Override + public int getDefaultSmsSubId() { + return 0; + } + + @Override + public void setDefaultSmsSubId(int subId) { + } + + @Override + public int[] getActiveSubIdList(boolean visibleOnly) { + return null; + } + + @Override + public int setSubscriptionProperty(int subId, @NonNull String propKey, + @NonNull String propValue) { + return 0; + } + + @Override + public String getSubscriptionProperty(int subId, @NonNull String propKey, + @NonNull String callingPackage, @NonNull String callingFeatureId) { + return null; + } + + @Override + public boolean setSubscriptionEnabled(boolean enable, int subId) { + return true; + } + + @Override + public boolean isSubscriptionEnabled(int subId) { + return true; + } + + @Override + public int getEnabledSubscriptionId(int slotIndex) { + return 0; + } + + @Override + public int getSimStateForSlotIndex(int slotIndex) { + return 0; + } + + @Override + public boolean isActiveSubId(int subId, @NonNull String callingPackage, + @NonNull String callingFeatureId) { + return true; + } + + @Override + public int getActiveDataSubscriptionId() { + return 0; + } + + @Override + public boolean canDisablePhysicalSubscription() { + return false; + } + + @Override + public int setUiccApplicationsEnabled(boolean enabled, int subscriptionId) { + return 0; + } + + @Override + public int setDeviceToDeviceStatusSharing(int sharing, int subId) { + return 0; + } + + @Override + public int setDeviceToDeviceStatusSharingContacts(@NonNull String contacts, + int subscriptionId) { + return 0; + } + + @Override + public String getPhoneNumber(int subId, int source, + @NonNull String callingPackage, @NonNull String callingFeatureId) { + return null; + } + + @Override + public String getPhoneNumberFromFirstAvailableSource(int subId, + @NonNull String callingPackage, @NonNull String callingFeatureId) { + return null; + } + + @Override + public void setPhoneNumber(int subId, int source, @NonNull String number, + @NonNull String callingPackage, @NonNull String callingFeatureId) { + } + + /** + * Set the Usage Setting for this subscription. + * + * @param usageSetting the usage setting for this subscription + * @param subId the unique SubscriptionInfo index in database + * @param callingPackage The package making the IPC. + * + * @throws SecurityException if doesn't have MODIFY_PHONE_STATE or Carrier Privileges + */ + @Override + public int setUsageSetting(int usageSetting, int subId, @NonNull String callingPackage) { + return 0; + } + + /** + * Log debug messages. + * + * @param s debug messages + */ + private void log(@NonNull String s) { + Rlog.d(LOG_TAG, s); + } + + /** + * Log error messages. + * + * @param s error messages + */ + private void loge(@NonNull String s) { + Rlog.e(LOG_TAG, s); + } + + /** + * Log verbose messages. + * + * @param s debug messages. + */ + private void logv(@NonNull String s) { + if (VDBG) Rlog.v(LOG_TAG, s); + } + + /** + * 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 {@link SubscriptionManagerService}. + * + * @param fd File descriptor + * @param printWriter Print writer + * @param args Arguments + */ + public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter printWriter, + @NonNull String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.println(SubscriptionManagerService.class.getSimpleName() + ":"); + } +} -- GitLab From 7f7dbda17cb91471da2fcff8eb8c4d45a46789f5 Mon Sep 17 00:00:00 2001 From: Ramya Manoharan Date: Mon, 16 May 2022 14:27:14 +0000 Subject: [PATCH 106/656] CATService STK SEND_SMS STK SEND_SMS implementation Test: UT for STK SEND_SMS Bug: 232895860 Change-Id: I8023204ab177359bcbe6dd72dd0c9934432af38b --- .../internal/telephony/SmsController.java | 31 ++- .../internal/telephony/cat/CatCmdMessage.java | 214 ++++++++++-------- .../internal/telephony/cat/CatService.java | 131 ++++++++++- .../internal/telephony/cat/CommandParams.java | 6 +- .../telephony/cat/CommandParamsFactory.java | 86 ++++++- .../telephony/cat/ComprehensionTlv.java | 2 +- .../telephony/cat/RilMessageDecoder.java | 3 +- .../internal/telephony/cat/SendSMSParams.java | 33 +++ .../internal/telephony/cat/ValueParser.java | 48 +++- .../internal/telephony/SmsControllerTest.java | 30 ++- .../telephony/cat/CATServiceTest.java | 192 ++++++++++++++++ 11 files changed, 659 insertions(+), 117 deletions(-) create mode 100644 src/java/com/android/internal/telephony/cat/SendSMSParams.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 511ea7a76a..7c326bf5da 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -197,6 +197,35 @@ public class SmsController extends ISmsImplBase { String callingAttributionTag, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, long messageId) { + sendTextForSubscriber(subId, callingPackage, callingAttributionTag, destAddr, scAddr, + text, sentIntent, deliveryIntent, persistMessageForNonDefaultSmsApp, messageId, + false); + + } + + /** + * @param subId Subscription Id + * @param callingAttributionTag the attribution tag of the caller + * @param destAddr the address to send the message to + * @param scAddr is the service center address or null to use + * the current default SMSC + * @param text the body of the message to send + * @param sentIntent if not NULL this PendingIntent is + * broadcast when the message is successfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, or relevant errors + * the sentIntent may include the extra "errorCode" containing a radio technology specific + * value, generally only useful for troubleshooting. + * @param deliveryIntent if not NULL this PendingIntent is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * @param skipFdnCheck if set to true, FDN check must be skipped .This is set in case of STK sms + * + * @hide + */ + public void sendTextForSubscriber(int subId, String callingPackage, + String callingAttributionTag, String destAddr, String scAddr, String text, + PendingIntent sentIntent, PendingIntent deliveryIntent, + boolean persistMessageForNonDefaultSmsApp, long messageId, boolean skipFdnCheck) { if (callingPackage == null) { callingPackage = getCallingPackage(); } @@ -209,7 +238,7 @@ public class SmsController extends ISmsImplBase { } // Perform FDN check - if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { + if (!skipFdnCheck && isNumberBlockedByFDN(subId, destAddr, callingPackage)) { sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); return; } diff --git a/src/java/com/android/internal/telephony/cat/CatCmdMessage.java b/src/java/com/android/internal/telephony/cat/CatCmdMessage.java index 3d212709d0..4447c0717e 100644 --- a/src/java/com/android/internal/telephony/cat/CatCmdMessage.java +++ b/src/java/com/android/internal/telephony/cat/CatCmdMessage.java @@ -40,6 +40,7 @@ public class CatCmdMessage implements Parcelable { private ToneSettings mToneSettings = null; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private CallSettings mCallSettings = null; + private SMSSettings mSMSSettings = null; private SetupEventListSettings mSetupEventListSettings = null; private boolean mLoadIconFailed = false; @@ -61,6 +62,14 @@ public class CatCmdMessage implements Parcelable { public TextMessage callMsg; } + /** + * Container for SEND SMS command settings. + */ + public class SMSSettings { + public TextMessage smsText; + public TextMessage destAddr; + } + public class SetupEventListSettings { @UnsupportedAppUsage public int[] eventList; @@ -84,57 +93,69 @@ public class CatCmdMessage implements Parcelable { mCmdDet = cmdParams.mCmdDet; mLoadIconFailed = cmdParams.mLoadIconFailed; switch(getCmdType()) { - case SET_UP_MENU: - case SELECT_ITEM: - mMenu = ((SelectItemParams) cmdParams).mMenu; - break; - case DISPLAY_TEXT: - case SET_UP_IDLE_MODE_TEXT: - case SEND_DTMF: - case SEND_SMS: - case REFRESH: - case RUN_AT: - case SEND_SS: - case SEND_USSD: - mTextMsg = ((DisplayTextParams) cmdParams).mTextMsg; - break; - case GET_INPUT: - case GET_INKEY: - mInput = ((GetInputParams) cmdParams).mInput; - break; - case LAUNCH_BROWSER: - mTextMsg = ((LaunchBrowserParams) cmdParams).mConfirmMsg; - mBrowserSettings = new BrowserSettings(); - mBrowserSettings.url = ((LaunchBrowserParams) cmdParams).mUrl; - mBrowserSettings.mode = ((LaunchBrowserParams) cmdParams).mMode; - break; - case PLAY_TONE: - PlayToneParams params = (PlayToneParams) cmdParams; - mToneSettings = params.mSettings; - mTextMsg = params.mTextMsg; - break; - case GET_CHANNEL_STATUS: - mTextMsg = ((CallSetupParams) cmdParams).mConfirmMsg; - break; - case SET_UP_CALL: - mCallSettings = new CallSettings(); - mCallSettings.confirmMsg = ((CallSetupParams) cmdParams).mConfirmMsg; - mCallSettings.callMsg = ((CallSetupParams) cmdParams).mCallMsg; - break; - case OPEN_CHANNEL: - case CLOSE_CHANNEL: - case RECEIVE_DATA: - case SEND_DATA: - BIPClientParams param = (BIPClientParams) cmdParams; - mTextMsg = param.mTextMsg; - break; - case SET_UP_EVENT_LIST: - mSetupEventListSettings = new SetupEventListSettings(); - mSetupEventListSettings.eventList = ((SetEventListParams) cmdParams).mEventInfo; - break; - case PROVIDE_LOCAL_INFORMATION: - default: - break; + case SET_UP_MENU: + case SELECT_ITEM: + mMenu = ((SelectItemParams) cmdParams).mMenu; + break; + case SEND_SMS: + /* If cmdParams is an instanceof SendSMSParams , then it means config value + * config_stk_sms_send_support is true and the SMS should be sent by framework + */ + if (cmdParams instanceof SendSMSParams) { + mSMSSettings = new SMSSettings(); + mSMSSettings.smsText = ((SendSMSParams) cmdParams).mTextSmsMsg; + mSMSSettings.destAddr = ((SendSMSParams) cmdParams).mDestAddress; + mTextMsg = ((SendSMSParams) cmdParams).mDisplayText.mTextMsg; + } else { + mTextMsg = ((DisplayTextParams) cmdParams).mTextMsg; + } + break; + case DISPLAY_TEXT: + case SET_UP_IDLE_MODE_TEXT: + case SEND_DTMF: + case REFRESH: + case RUN_AT: + case SEND_SS: + case SEND_USSD: + mTextMsg = ((DisplayTextParams) cmdParams).mTextMsg; + break; + case GET_INPUT: + case GET_INKEY: + mInput = ((GetInputParams) cmdParams).mInput; + break; + case LAUNCH_BROWSER: + mTextMsg = ((LaunchBrowserParams) cmdParams).mConfirmMsg; + mBrowserSettings = new BrowserSettings(); + mBrowserSettings.url = ((LaunchBrowserParams) cmdParams).mUrl; + mBrowserSettings.mode = ((LaunchBrowserParams) cmdParams).mMode; + break; + case PLAY_TONE: + PlayToneParams params = (PlayToneParams) cmdParams; + mToneSettings = params.mSettings; + mTextMsg = params.mTextMsg; + break; + case GET_CHANNEL_STATUS: + mTextMsg = ((CallSetupParams) cmdParams).mConfirmMsg; + break; + case SET_UP_CALL: + mCallSettings = new CallSettings(); + mCallSettings.confirmMsg = ((CallSetupParams) cmdParams).mConfirmMsg; + mCallSettings.callMsg = ((CallSetupParams) cmdParams).mCallMsg; + break; + case OPEN_CHANNEL: + case CLOSE_CHANNEL: + case RECEIVE_DATA: + case SEND_DATA: + BIPClientParams param = (BIPClientParams) cmdParams; + mTextMsg = param.mTextMsg; + break; + case SET_UP_EVENT_LIST: + mSetupEventListSettings = new SetupEventListSettings(); + mSetupEventListSettings.eventList = ((SetEventListParams) cmdParams).mEventInfo; + break; + case PROVIDE_LOCAL_INFORMATION: + default: + break; } } @@ -145,29 +166,34 @@ public class CatCmdMessage implements Parcelable { mInput = in.readParcelable(Input.class.getClassLoader()); mLoadIconFailed = (in.readByte() == 1); switch (getCmdType()) { - case LAUNCH_BROWSER: - mBrowserSettings = new BrowserSettings(); - mBrowserSettings.url = in.readString(); - mBrowserSettings.mode = LaunchBrowserMode.values()[in.readInt()]; - break; - case PLAY_TONE: - mToneSettings = in.readParcelable(ToneSettings.class.getClassLoader()); - break; - case SET_UP_CALL: - mCallSettings = new CallSettings(); - mCallSettings.confirmMsg = in.readParcelable(TextMessage.class.getClassLoader()); - mCallSettings.callMsg = in.readParcelable(TextMessage.class.getClassLoader()); - break; - case SET_UP_EVENT_LIST: - mSetupEventListSettings = new SetupEventListSettings(); - int length = in.readInt(); - mSetupEventListSettings.eventList = new int[length]; - for (int i = 0; i < length; i++) { - mSetupEventListSettings.eventList[i] = in.readInt(); - } - break; - default: - break; + case LAUNCH_BROWSER: + mBrowserSettings = new BrowserSettings(); + mBrowserSettings.url = in.readString(); + mBrowserSettings.mode = LaunchBrowserMode.values()[in.readInt()]; + break; + case PLAY_TONE: + mToneSettings = in.readParcelable(ToneSettings.class.getClassLoader()); + break; + case SET_UP_CALL: + mCallSettings = new CallSettings(); + mCallSettings.confirmMsg = in.readParcelable(TextMessage.class.getClassLoader()); + mCallSettings.callMsg = in.readParcelable(TextMessage.class.getClassLoader()); + break; + case SET_UP_EVENT_LIST: + mSetupEventListSettings = new SetupEventListSettings(); + int length = in.readInt(); + mSetupEventListSettings.eventList = new int[length]; + for (int i = 0; i < length; i++) { + mSetupEventListSettings.eventList[i] = in.readInt(); + } + break; + case SEND_SMS: + mSMSSettings = new SMSSettings(); + mSMSSettings.smsText = in.readParcelable(SendSMSParams.class.getClassLoader()); + mSMSSettings.destAddr = in.readParcelable(SendSMSParams.class.getClassLoader()); + break; + default: + break; } } @@ -178,23 +204,29 @@ public class CatCmdMessage implements Parcelable { dest.writeParcelable(mMenu, 0); dest.writeParcelable(mInput, 0); dest.writeByte((byte) (mLoadIconFailed ? 1 : 0)); - switch(getCmdType()) { - case LAUNCH_BROWSER: - dest.writeString(mBrowserSettings.url); - dest.writeInt(mBrowserSettings.mode.ordinal()); - break; - case PLAY_TONE: - dest.writeParcelable(mToneSettings, 0); - break; - case SET_UP_CALL: - dest.writeParcelable(mCallSettings.confirmMsg, 0); - dest.writeParcelable(mCallSettings.callMsg, 0); - break; - case SET_UP_EVENT_LIST: - dest.writeIntArray(mSetupEventListSettings.eventList); - break; - default: - break; + switch (getCmdType()) { + case LAUNCH_BROWSER: + dest.writeString(mBrowserSettings.url); + dest.writeInt(mBrowserSettings.mode.ordinal()); + break; + case PLAY_TONE: + dest.writeParcelable(mToneSettings, 0); + break; + case SET_UP_CALL: + dest.writeParcelable(mCallSettings.confirmMsg, 0); + dest.writeParcelable(mCallSettings.callMsg, 0); + break; + case SET_UP_EVENT_LIST: + dest.writeIntArray(mSetupEventListSettings.eventList); + break; + case SEND_SMS: + if (mSMSSettings != null) { + dest.writeParcelable(mSMSSettings.smsText, 0); + dest.writeParcelable(mSMSSettings.destAddr, 0); + } + break; + default: + break; } } diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java index 9ed5eb9d84..2afc63f6db 100644 --- a/src/java/com/android/internal/telephony/cat/CatService.java +++ b/src/java/com/android/internal/telephony/cat/CatService.java @@ -20,24 +20,34 @@ import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListCon import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.LANGUAGE_SELECTION_EVENT; import static com.android.internal.telephony.cat.CatCmdMessage.SetupEventListConstants.USER_ACTIVITY_EVENT; +import android.app.Activity; import android.app.ActivityManager; +import android.app.PendingIntent; import android.app.backup.BackupManager; import android.compat.annotation.UnsupportedAppUsage; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources.NotFoundException; import android.os.AsyncResult; import android.os.Build; import android.os.Handler; +import android.os.HandlerThread; import android.os.LocaleList; +import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.ProxyController; +import com.android.internal.telephony.SmsController; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.IccFileHandler; @@ -138,12 +148,21 @@ public class CatService extends Handler implements AppInterface { static final String STK_DEFAULT = "Default Message"; + private static final String SMS_DELIVERY_ACTION = + "com.android.internal.telephony.cat.SMS_DELIVERY_ACTION"; + private static final String SMS_SENT_ACTION = + "com.android.internal.telephony.cat.SMS_SENT_ACTION"; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int mSlotId; + private static HandlerThread sCatServiceThread; /* For multisim catservice should not be singleton */ private CatService(CommandsInterface ci, UiccCardApplication ca, IccRecords ir, - Context context, IccFileHandler fh, UiccProfile uiccProfile, int slotId) { + Context context, IccFileHandler fh, UiccProfile uiccProfile, int slotId, + Looper looper) { + //creating new thread to avoid deadlock conditions with the framework thread. + super(looper); if (ci == null || ca == null || ir == null || context == null || fh == null || uiccProfile == null) { throw new NullPointerException( @@ -187,6 +206,10 @@ public class CatService extends Handler implements AppInterface { CatLog.d(this, "Running CAT service on Slotid: " + mSlotId + ". STK app installed:" + mStkAppInstalled); + + SmsBroadcastReceiver smsBroadcastReceiver = new SmsBroadcastReceiver(); + mContext.registerReceiver(smsBroadcastReceiver, new IntentFilter(SMS_DELIVERY_ACTION)); + mContext.registerReceiver(smsBroadcastReceiver, new IntentFilter(SMS_SENT_ACTION)); } /** @@ -200,6 +223,10 @@ public class CatService extends Handler implements AppInterface { */ public static CatService getInstance(CommandsInterface ci, Context context, UiccProfile uiccProfile, int slotId) { + if (sCatServiceThread == null) { + sCatServiceThread = new HandlerThread("CatServiceThread"); + sCatServiceThread.start(); + } UiccCardApplication ca = null; IccFileHandler fh = null; IccRecords ir = null; @@ -227,8 +254,8 @@ public class CatService extends Handler implements AppInterface { || uiccProfile == null) { return null; } - - sInstance[slotId] = new CatService(ci, ca, ir, context, fh, uiccProfile, slotId); + sInstance[slotId] = new CatService(ci, ca, ir, context, fh, uiccProfile, slotId, + sCatServiceThread.getLooper()); } else if ((ir != null) && (mIccRecords != ir)) { if (mIccRecords != null) { mIccRecords.unregisterForRecordsLoaded(sInstance[slotId]); @@ -447,8 +474,49 @@ public class CatService extends Handler implements AppInterface { ((DisplayTextParams)cmdParams).mTextMsg.text = null; } break; - case SEND_DTMF: case SEND_SMS: + /* If cmdParams is an instanceof SendSMSParams , then it means config value + * config_stk_sms_send_support is true and the SMS should be sent by framework + */ + if (cmdParams instanceof SendSMSParams) { + String text = null, destAddr = null; + if (((SendSMSParams) cmdParams).mTextSmsMsg != null) { + text = ((SendSMSParams) cmdParams).mTextSmsMsg.text; + } + if (((SendSMSParams) cmdParams).mDestAddress != null) { + destAddr = ((SendSMSParams) cmdParams).mDestAddress.text; + } + if (text != null && destAddr != null) { + ProxyController proxyController = ProxyController.getInstance(mContext); + SubscriptionManager subscriptionManager = (SubscriptionManager) + mContext.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + SubscriptionInfo subInfo = + subscriptionManager.getActiveSubscriptionInfoForSimSlotIndex( + mSlotId); + if (subInfo != null) { + sendStkSms(text, destAddr, subInfo.getSubscriptionId(), cmdParams, + proxyController); + } else { + sendTerminalResponse(cmdParams.mCmdDet, + ResultCode.CMD_DATA_NOT_UNDERSTOOD, false, 0x00, null); + CatLog.d(this, "Subscription info is null"); + } + } else { + sendTerminalResponse(cmdParams.mCmdDet, ResultCode.CMD_DATA_NOT_UNDERSTOOD, + false, 0x00, null); + CatLog.d(this, "Sms text or Destination Address is null"); + } + } else { + if ((((DisplayTextParams) cmdParams).mTextMsg.text != null) + && (((DisplayTextParams) cmdParams).mTextMsg.text.equals( + STK_DEFAULT))) { + message = mContext.getText(com.android.internal.R.string.sending); + ((DisplayTextParams) cmdParams).mTextMsg.text = message.toString(); + } + } + break; + case SEND_DTMF: case SEND_SS: case SEND_USSD: if ((((DisplayTextParams)cmdParams).mTextMsg.text != null) @@ -536,6 +604,61 @@ public class CatService extends Handler implements AppInterface { broadcastCatCmdIntent(cmdMsg); } + /** + * Used to send STK based sms via CATService + * @param text The message body + * @param destAddr The destination Address + * @param subId Subscription Id + * @param cmdParams Send SMS Command Params + * @param proxyController ProxyController + * @hide + */ + public void sendStkSms(String text, String destAddr, int subId, CommandParams cmdParams, + ProxyController proxyController) { + PendingIntent sentPendingIntent = PendingIntent.getBroadcast(mContext, 0, + new Intent(SMS_SENT_ACTION).putExtra("cmdDetails", + cmdParams.mCmdDet), PendingIntent.FLAG_MUTABLE); + PendingIntent deliveryPendingIntent = PendingIntent.getBroadcast(mContext, 0, + new Intent(SMS_DELIVERY_ACTION).putExtra("cmdDetails", + cmdParams.mCmdDet), PendingIntent.FLAG_MUTABLE); + SmsController smsController = proxyController.getSmsController(); + smsController.sendTextForSubscriber(subId, mContext.getOpPackageName(), + mContext.getAttributionTag(), destAddr, null, text, sentPendingIntent, + deliveryPendingIntent, false, 0L, true); + } + + private class SmsBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + CommandDetails commandDetails = (CommandDetails) intent.getExtra("cmdDetails"); + if (intent.getAction().equals(SMS_SENT_ACTION)) { + int resultCode = getResultCode(); + switch (resultCode) { + case Activity.RESULT_OK: + break; + default: + //ToDO handle Error cases bug : b/243123292 + CatLog.d(this, "Error sending STK SMS : " + resultCode); + sendTerminalResponse(commandDetails, ResultCode.SMS_RP_ERROR, true, + ResultCode.NETWORK_CRNTLY_UNABLE_TO_PROCESS.value(), null); + } + } + if (intent.getAction().equals(SMS_DELIVERY_ACTION)) { + int resultCode = getResultCode(); + switch (resultCode) { + case Activity.RESULT_OK: + sendTerminalResponse(commandDetails, ResultCode.OK, false, 0, null); + break; + default: + //ToDO handle Error cases bug: b/243123292 + CatLog.d(this, "Error delivering STK SMS : " + resultCode); + sendTerminalResponse(commandDetails, ResultCode.SMS_RP_ERROR, true, + ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS.value(), null); + } + } + } + } private void broadcastCatCmdIntent(CatCmdMessage cmdMsg) { Intent intent = new Intent(AppInterface.CAT_CMD_ACTION); diff --git a/src/java/com/android/internal/telephony/cat/CommandParams.java b/src/java/com/android/internal/telephony/cat/CommandParams.java index b9de4d1f2d..8530ee2ec7 100755 --- a/src/java/com/android/internal/telephony/cat/CommandParams.java +++ b/src/java/com/android/internal/telephony/cat/CommandParams.java @@ -22,16 +22,16 @@ import android.os.Build; /** * Container class for proactive command parameters. - * + * @hide */ -class CommandParams { +public class CommandParams { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) CommandDetails mCmdDet; // Variable to track if an optional icon load has failed. boolean mLoadIconFailed = false; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - CommandParams(CommandDetails cmdDet) { + public CommandParams(CommandDetails cmdDet) { mCmdDet = cmdDet; } diff --git a/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java b/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java index 7fbebfad8e..65f3c4ac13 100644 --- a/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java +++ b/src/java/com/android/internal/telephony/cat/CommandParamsFactory.java @@ -29,6 +29,7 @@ import android.graphics.Bitmap; import android.os.Build; import android.os.Handler; import android.os.Message; +import android.telephony.SmsMessage; import android.text.TextUtils; import com.android.internal.telephony.GsmAlphabet; @@ -40,9 +41,9 @@ import java.util.Locale; /** * Factory class, used for decoding raw byte arrays, received from baseband, * into a CommandParams object. - * + * @hide */ -class CommandParamsFactory extends Handler { +public class CommandParamsFactory extends Handler { private static CommandParamsFactory sInstance = null; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private IconLoader mIconLoader; @@ -53,6 +54,7 @@ class CommandParamsFactory extends Handler { private String mSavedLanguage; private String mRequestedLanguage; private boolean mNoAlphaUsrCnf = false; + private boolean mStkSmsSendViaTelephony = false; // constants static final int MSG_ID_LOAD_ICON_DONE = 1; @@ -86,7 +88,15 @@ class CommandParamsFactory extends Handler { private static final int MAX_GSM7_DEFAULT_CHARS = 239; private static final int MAX_UCS2_CHARS = 118; - static synchronized CommandParamsFactory getInstance(RilMessageDecoder caller, + /** + * Returns a singleton instance of CommandParamsFactory + * @param caller Class used for queuing raw ril messages, decoding them into + * CommandParams objects and sending the result back to the CAT Service. + * @param fh IccFileHandler Object + * @param context The Context + * @return CommandParamsFactory instance + */ + public static synchronized CommandParamsFactory getInstance(RilMessageDecoder caller, IccFileHandler fh, Context context) { if (sInstance != null) { return sInstance; @@ -106,6 +116,12 @@ class CommandParamsFactory extends Handler { } catch (NotFoundException e) { mNoAlphaUsrCnf = false; } + try { + mStkSmsSendViaTelephony = context.getResources().getBoolean( + com.android.internal.R.bool.config_stk_sms_send_support); + } catch (NotFoundException e) { + mStkSmsSendViaTelephony = false; + } } private CommandDetails processCommandDetails(List ctlvs) { @@ -187,8 +203,14 @@ class CommandParamsFactory extends Handler { case GET_INPUT: cmdPending = processGetInput(cmdDet, ctlvs); break; - case SEND_DTMF: case SEND_SMS: + if (mStkSmsSendViaTelephony) { + cmdPending = processSMSEventNotify(cmdDet, ctlvs); + } else { + cmdPending = processEventNotify(cmdDet, ctlvs); + } + break; + case SEND_DTMF: case REFRESH: case RUN_AT: case SEND_SS: @@ -735,6 +757,62 @@ class CommandParamsFactory extends Handler { return false; } + + /** + * Processes SMS_EVENT_NOTIFY message from baseband. + * + * Method extracts values such as Alpha Id,Icon Id,Sms Tpdu etc from the ComprehensionTlv, + * in order to create the CommandParams i.e. SendSMSParams. + * + * @param cmdDet Command Details container object. + * @param ctlvs List of ComprehensionTlv objects following Command Details + * object and Device Identities object within the proactive command + * @return true if the command is processing is pending and additional + * asynchronous processing is required. + * @hide + */ + public boolean processSMSEventNotify(CommandDetails cmdDet, + List ctlvs) throws ResultException { + CatLog.d(this, "processSMSEventNotify"); + + TextMessage textMsg = new TextMessage(); + IconId iconId = null; + + ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, + ctlvs); + /* Retrieves alpha identifier from an Alpha Identifier COMPREHENSION-TLV object. + * + * String corresponding to the alpha identifier is obtained and saved as part of + * the DisplayTextParams. + */ + textMsg.text = ValueParser.retrieveAlphaId(ctlv, mNoAlphaUsrCnf); + + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); + if (ctlv != null) { + // Retrieves icon id from the Icon Identifier COMPREHENSION-TLV object + iconId = ValueParser.retrieveIconId(ctlv); + textMsg.iconSelfExplanatory = iconId.selfExplanatory; + } + + textMsg.responseNeeded = false; + DisplayTextParams displayTextParams = new DisplayTextParams(cmdDet, textMsg); + ComprehensionTlv ctlvTpdu = searchForTag(ComprehensionTlvTag.SMS_TPDU, + ctlvs); + // Retrieves smsMessage from the SMS TPDU COMPREHENSION-TLV object + SmsMessage smsMessage = ValueParser.retrieveTpduAsSmsMessage(ctlvTpdu); + if (smsMessage != null) { + TextMessage smsText = new TextMessage(); + // Obtains the sms message content. + smsText.text = smsMessage.getMessageBody(); + TextMessage destAddr = new TextMessage(); + // Obtains the destination Address. + destAddr.text = smsMessage.getRecipientAddress(); + mCmdParams = new SendSMSParams(cmdDet, smsText, destAddr, displayTextParams); + return false; + } + return true; + } + /** * Processes SET_UP_EVENT_LIST proactive command from the SIM card. * diff --git a/src/java/com/android/internal/telephony/cat/ComprehensionTlv.java b/src/java/com/android/internal/telephony/cat/ComprehensionTlv.java index 5542b656b3..416c66926a 100644 --- a/src/java/com/android/internal/telephony/cat/ComprehensionTlv.java +++ b/src/java/com/android/internal/telephony/cat/ComprehensionTlv.java @@ -50,7 +50,7 @@ public class ComprehensionTlv { * @param data Byte array containing the value * @param valueIndex Index in data at which the value starts */ - protected ComprehensionTlv(int tag, boolean cr, int length, byte[] data, + public ComprehensionTlv(int tag, boolean cr, int length, byte[] data, int valueIndex) { mTag = tag; mCr = cr; diff --git a/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java b/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java index c25b59edac..4b10cae7e0 100755 --- a/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java +++ b/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java @@ -32,8 +32,9 @@ import com.android.internal.util.StateMachine; /** * Class used for queuing raw ril messages, decoding them into CommanParams * objects and sending the result back to the CAT Service. + * @hide */ -class RilMessageDecoder extends StateMachine { +public class RilMessageDecoder extends StateMachine { // constants private static final int CMD_START = 1; diff --git a/src/java/com/android/internal/telephony/cat/SendSMSParams.java b/src/java/com/android/internal/telephony/cat/SendSMSParams.java new file mode 100644 index 0000000000..f5108f04c8 --- /dev/null +++ b/src/java/com/android/internal/telephony/cat/SendSMSParams.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 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.cat; + +class SendSMSParams extends CommandParams { + + TextMessage mTextSmsMsg; + TextMessage mDestAddress; + DisplayTextParams mDisplayText; + + SendSMSParams(CommandDetails cmdDet, TextMessage textMsg, TextMessage destAddress, + DisplayTextParams displayText) { + super(cmdDet); + mTextSmsMsg = textMsg; + mDestAddress = destAddress; + mDisplayText = displayText; + } + +} diff --git a/src/java/com/android/internal/telephony/cat/ValueParser.java b/src/java/com/android/internal/telephony/cat/ValueParser.java index 7c0913629f..bd17f48fed 100644 --- a/src/java/com/android/internal/telephony/cat/ValueParser.java +++ b/src/java/com/android/internal/telephony/cat/ValueParser.java @@ -18,16 +18,24 @@ package com.android.internal.telephony.cat; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +import android.telephony.SmsMessage; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.cat.Duration.TimeUnit; import com.android.internal.telephony.uicc.IccUtils; +import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -abstract class ValueParser { + +/** + * Util class that parses different entities from the ctlvs ComprehensionTlv List + * @hide + */ +public abstract class ValueParser { /** * Search for a Command Details object from a list. @@ -352,4 +360,42 @@ abstract class ValueParser { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); } } + + /** + * Retrieve's the tpdu from the ctlv and creates the SmsMessage from pdu. + * @param ctlv ComprehensionTlv value + * @return message SmsMessage to retrieve the destAddress and Text + * @throws ResultException + * @hide + */ + public static SmsMessage retrieveTpduAsSmsMessage(ComprehensionTlv ctlv) + throws ResultException { + if (ctlv != null) { + byte[] rawValue = ctlv.getRawValue(); + int valueIndex = ctlv.getValueIndex(); + int length = ctlv.getLength(); + if (length != 0) { + try { + byte[] pdu = Arrays.copyOfRange(rawValue, valueIndex, (valueIndex + length)); + ByteArrayOutputStream bo = new ByteArrayOutputStream(pdu.length + 1); + /* Framework's TPdu Parser expects the TPdu be prepended with SC-Address. + * else the parser will throw an exception. So prepending TPdu with 0, + * which indicates that there is no SC address and its length is 0. + * This way Parser will skip parsing for SC-Address + */ + bo.write(0x00); + bo.write(pdu, 0, pdu.length); + byte[] frameworkPdu = bo.toByteArray(); + //ToDO handle for 3GPP2 format bug: b/243123533 + SmsMessage message = SmsMessage.createFromPdu(frameworkPdu, + SmsMessage.FORMAT_3GPP); + return message; + } catch (IndexOutOfBoundsException e) { + throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); + } + } + } + return null; + } + } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java index 54d34d4755..2c67342678 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java @@ -16,6 +16,16 @@ package com.android.internal.telephony; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -29,17 +39,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertFalse; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - - import java.util.ArrayList; @RunWith(AndroidTestingRunner.class) @@ -192,4 +191,13 @@ public class SmsControllerTest extends TelephonyTest { doReturn(false).when(mPhone).isInEcm(); } + + @Test + public void sendsendTextForSubscriberTest() { + mSmsControllerUT.sendTextForSubscriber(1, mCallingPackage, null, "1234", + null, "text", null, null, false, 0L, true); + verify(mIccSmsInterfaceManager, Mockito.times(1)) + .sendText(mCallingPackage, "1234", null, "text", null, null, false, 0L); + } + } \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java new file mode 100644 index 0000000000..f8fec6a2a2 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2022 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.cat; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.telephony.SmsMessage; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.ProxyController; +import com.android.internal.telephony.SmsController; +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.uicc.IccCardApplicationStatus; +import com.android.internal.telephony.uicc.IccCardStatus; +import com.android.internal.telephony.uicc.IccFileHandler; +import com.android.internal.telephony.uicc.IccIoResult; +import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.uicc.UiccCard; +import com.android.internal.telephony.uicc.UiccProfile; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class CATServiceTest extends TelephonyTest { + + //Mocked Classes + @Mock + private RilMessageDecoder mRilMessageDecoder; + private IccFileHandler mIccFileHandler; + private SmsController mSmsController; + private CommandDetails mCommandDetails; + private CatService mCatService; + private IccCardStatus mIccCardStatus; + private IccIoResult mIccIoResult; + + private String mData = + "D059810301130082028183051353656E64696E672072657175657374202E2E2E0607911989548056780B" + + "3051FF05812143F500F6082502700000201115001500BFFF01BA23C2169EA9B02D7A7FBAA0" + + "DAABFEE8B8DE9DA06DCD234E"; + private byte[] mRawdata = IccUtils.hexStringToBytes(mData); + private List mCtlvs; + + public CATServiceTest() { + super(); + } + + private IccCardApplicationStatus composeUiccApplicationStatus( + IccCardApplicationStatus.AppType appType, + IccCardApplicationStatus.AppState appState, String aid) { + IccCardApplicationStatus mIccCardAppStatus = new IccCardApplicationStatus(); + mIccCardAppStatus.aid = aid; + mIccCardAppStatus.app_type = appType; + mIccCardAppStatus.aid = aid; + mIccCardAppStatus.app_type = appType; + mIccCardAppStatus.app_state = appState; + mIccCardAppStatus.pin1 = mIccCardAppStatus.pin2 = + IccCardStatus.PinState.PINSTATE_ENABLED_VERIFIED; + return mIccCardAppStatus; + } + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + mRilMessageDecoder = mock(RilMessageDecoder.class); + mIccFileHandler = mock(IccFileHandler.class); + mSmsController = mock(SmsController.class); + mIccCardStatus = mock(IccCardStatus.class); + mProxyController = mock(ProxyController.class); + mUiccCard = mock(UiccCard.class); + IccCardApplicationStatus umtsApp = composeUiccApplicationStatus( + IccCardApplicationStatus.AppType.APPTYPE_USIM, + IccCardApplicationStatus.AppState.APPSTATE_UNKNOWN, "0xA2"); + mIccCardStatus.mApplications = new IccCardApplicationStatus[]{umtsApp}; + mIccCardStatus.mCdmaSubscriptionAppIndex = + mIccCardStatus.mImsSubscriptionAppIndex = + mIccCardStatus.mGsmUmtsSubscriptionAppIndex = -1; + mIccIoResult = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes("FF40")); + mSimulatedCommands.setIccIoResultForApduLogicalChannel(mIccIoResult); + mUiccProfile = new UiccProfile(mContext, mSimulatedCommands, mIccCardStatus, + 0 /* phoneId */, mUiccCard, new Object()); + processAllMessages(); + logd("Created UiccProfile"); + processAllMessages(); + mCatService = CatService.getInstance(mSimulatedCommands, mUiccController.mContext, + mUiccProfile, mUiccController.getSlotIdFromPhoneId(0)); + logd("Created CATService"); + createCommandDetails(); + createComprehensionTlvList(); + } + + @After + public void tearDown() throws Exception { + mUiccProfile = null; + mCatService = null; + mCtlvs = null; + mProxyController = null; + mRilMessageDecoder = null; + mCommandDetails = null; + super.tearDown(); + } + + private void createCommandDetails() { + mCommandDetails = mock(CommandDetails.class); + mCommandDetails.compRequired = true; + mCommandDetails.commandNumber = 1; + mCommandDetails.typeOfCommand = 19; + mCommandDetails.commandQualifier = 0; + } + + private void createComprehensionTlvList() { + ComprehensionTlv ctlv1 = new ComprehensionTlv(1, false, 3, mRawdata, 4); + ComprehensionTlv ctlv2 = new ComprehensionTlv(2, false, 2, mRawdata, 9); + ComprehensionTlv ctlv3 = new ComprehensionTlv(5, false, 19, mRawdata, 13); + ComprehensionTlv ctlv4 = new ComprehensionTlv(6, false, 7, mRawdata, 34); + ComprehensionTlv ctlv5 = new ComprehensionTlv(11, false, 48, mRawdata, 43); + mCtlvs = new ArrayList<>(); + mCtlvs.add(ctlv1); + mCtlvs.add(ctlv2); + mCtlvs.add(ctlv3); + mCtlvs.add(ctlv4); + mCtlvs.add(ctlv5); + } + + @Test + public void testSendSmsCommandParams() throws Exception { + ComprehensionTlv ctlv = new ComprehensionTlv(11, false, 48, mRawdata, 43); + SmsMessage smsMessage = ValueParser.retrieveTpduAsSmsMessage(ctlv); + assertNotNull(smsMessage); + assertEquals("12345", smsMessage.getRecipientAddress()); + } + + @Test + public void testSendSTKSmsViaCatService() { + CommandParams cmdPrms = new CommandParams(mCommandDetails); + when(mProxyController.getSmsController()).thenReturn(mSmsController); + mCatService.sendStkSms("test", "12345", 1, cmdPrms, mProxyController); + verify(mSmsController, Mockito.times(1)).sendTextForSubscriber(anyInt(), + anyString(), nullable(String.class), anyString(), nullable(String.class), + anyString(), Mockito.anyObject(), any(), eq(false), anyLong(), eq(true)); + } + + @Test + public void testprocessSMSEventNotify() throws Exception { + CommandParamsFactory cmdPF = CommandParamsFactory.getInstance(mRilMessageDecoder, + mIccFileHandler, mContext); + assertEquals(false, cmdPF.processSMSEventNotify(mCommandDetails, mCtlvs)); + } + + @Test + public void testSkipFdnCheckforSTKSmsViaCatService() { + CommandParams cmdPrms = new CommandParams(mCommandDetails); + when(mProxyController.getSmsController()).thenReturn(mSmsController); + mCatService.sendStkSms("test", "12345", 1, cmdPrms, mProxyController); + verify(mSmsController, Mockito.times(0)).isNumberBlockedByFDN(1, "12345", + "com.android.internal.telephony"); + } + +} -- GitLab From ce6b58ee4a71e3b3d85e5cced53f28c060940765 Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Mon, 3 Oct 2022 22:45:18 +0000 Subject: [PATCH 107/656] N3IWF HAL support: update NetworkResponse Override getRegistrationStateResponse for N3IWF HAL API change to solve build error Bug: 249129495 Test: build and flash Change-Id: Iad6a6cc2e15a8cdd3896545340e55aeecc00da76 --- .../internal/telephony/NetworkResponse.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index 5f5895e16c..43ee2ead84 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -473,6 +473,22 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); } + /** + * @param responseInfo Response info struct containing response type, serial no. and error + * @param regResponse Current registration response as defined by RegStateResult + */ + public void getRegistrationStateResponse(RadioResponseInfo responseInfo, + android.hardware.radio.network.RegStateResult regResponse) { + RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + + if (rr != null) { + if (responseInfo.error == RadioError.NONE) { + RadioResponse.sendMessageResponse(rr.mResult, regResponse); + } + mRil.processResponseDone(rr, responseInfo, regResponse); + } + } + @Override public String getInterfaceHash() { return IRadioNetworkResponse.HASH; -- GitLab From 228b7ea75f8ceceb070333613b28551ac4aceeaa Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 3 Oct 2022 13:37:02 -0700 Subject: [PATCH 108/656] Removed unused methods Removed getAllSubscriptionInfoCount(), getDefaultSmsPhoneId(), and getDefaultDataPhoneId(). Bug: 239607619 Test: Manual Change-Id: I03752b7ccae39290814f894007ebe9e3d32c083e --- .../internal/telephony/SubscriptionController.java | 6 ------ .../subscription/SubscriptionManagerService.java | 13 ------------- 2 files changed, 19 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 5090fa219f..3b580149e2 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -1049,7 +1049,6 @@ public class SubscriptionController extends ISub.Stub { * @param callingFeatureId The feature in the package * @return all SIM count in database, include what was inserted before */ - @Override public int getAllSubInfoCount(String callingPackage, String callingFeatureId) { if (DBG) logd("[getAllSubInfoCount]+"); @@ -3382,12 +3381,7 @@ public class SubscriptionController extends ISub.Stub { pw.println(" defaultDataSubId=" + getDefaultDataSubId()); pw.println(" defaultVoiceSubId=" + getDefaultVoiceSubId()); pw.println(" defaultSmsSubId=" + getDefaultSmsSubId()); - - pw.println(" defaultDataPhoneId=" + SubscriptionManager - .from(mContext).getDefaultDataPhoneId()); pw.println(" defaultVoicePhoneId=" + SubscriptionManager.getDefaultVoicePhoneId()); - pw.println(" defaultSmsPhoneId=" + SubscriptionManager - .from(mContext).getDefaultSmsPhoneId()); pw.flush(); for (Entry> entry : mSlotIndexToSubIds.entrySet()) { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index e8c932ba77..d543e04b61 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -80,19 +80,6 @@ public class SubscriptionManagerService extends ISub.Stub { return null; } - /** - * @param callingPackage The package making the call. - * @param callingFeatureId The feature in the package - * - * @return the count of all subscriptions in the database, this includes all subscriptions that - * have been seen. - */ - @Override - public int getAllSubInfoCount(@NonNull String callingPackage, - @NonNull String callingFeatureId) { - return 0; - } - /** * Get the active {@link SubscriptionInfo} with the subscription id key. * -- GitLab From 5557c28af7a03ee215b11098c2581484186b68bc Mon Sep 17 00:00:00 2001 From: Cole Faust Date: Thu, 1 Sep 2022 13:36:52 -0700 Subject: [PATCH 109/656] Fix array-related errorprone warnings The ArrayEquals, ArrayHashCode, ArrayToString, and ArraysAsListPrimitiveArray errorprone findings were demoted from errors to warnings. Fix existing occurrences of them so they can be made errors again. Bug: 242630963 Test: RUN_ERROR_PRONE=true m javac-check Change-Id: I110410571e92b4ec41682e45692fe0751d685ac2 --- .../internal/telephony/uicc/IsimUiccRecords.java | 4 ++-- .../internal/telephony/uicc/SIMRecords.java | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java index b2206efe13..9591a49800 100644 --- a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java @@ -71,7 +71,7 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { return "IsimUiccRecords: " + super.toString() + (DUMP_RECORDS ? (" mIsimImpi=" + mIsimImpi + " mIsimDomain=" + mIsimDomain - + " mIsimImpu=" + mIsimImpu + + " mIsimImpu=" + Arrays.toString(mIsimImpu) + " mIsimIst=" + mIsimIst + " mIsimPcscf=" + Arrays.toString(mIsimPcscf) + " mPsiSmsc=" + mPsiSmsc @@ -494,7 +494,7 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { pw.println(" mIsimImpi=" + mIsimImpi); pw.println(" mIsimDomain=" + mIsimDomain); pw.println(" mIsimImpu[]=" + Arrays.toString(mIsimImpu)); - pw.println(" mIsimPcscf" + mIsimPcscf); + pw.println(" mIsimPcscf" + Arrays.toString(mIsimPcscf)); pw.println(" mPsismsc=" + mPsiSmsc); pw.println(" mSmss TPMR=" + getSmssTpmrValue()); } diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index 77b83ccf48..f94bcfbe13 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -105,12 +105,12 @@ public class SIMRecords extends IccRecords { + " mVmConfig" + mVmConfig + " callForwardingEnabled=" + mCallForwardingStatus + " spnState=" + mSpnState - + " mCphsInfo=" + mCphsInfo + + " mCphsInfo=" + IccUtils.bytesToHexString(mCphsInfo) + " mCspPlmnEnabled=" + mCspPlmnEnabled - + " efMWIS=" + mEfMWIS - + " efCPHS_MWI=" + mEfCPHS_MWI - + " mEfCff=" + mEfCff - + " mEfCfis=" + mEfCfis + + " efMWIS=" + IccUtils.bytesToHexString(mEfMWIS) + + " efCPHS_MWI=" + IccUtils.bytesToHexString(mEfCPHS_MWI) + + " mEfCff=" + IccUtils.bytesToHexString(mEfCff) + + " mEfCfis=" + IccUtils.bytesToHexString(mEfCfis) + " getOperatorNumeric=" + getOperatorNumeric() + " mPsiSmsc=" + mPsiSmsc + " TPMR=" + getSmssTpmrValue(); @@ -2043,7 +2043,7 @@ public class SIMRecords extends IccRecords { // Byte 5 and 6 are for lacTacEnd. // Byte 7 is for PNN Record Identifier. if (data.length != 8) { - loge("Invalid length for OPL record " + data); + loge("Invalid length for OPL record " + IccUtils.bytesToHexString(data)); continue; } @@ -2196,14 +2196,14 @@ public class SIMRecords extends IccRecords { pw.println(" mVmConfig=" + mVmConfig); pw.println(" mCallForwardingStatus=" + mCallForwardingStatus); pw.println(" mSpnState=" + mSpnState); - pw.println(" mCphsInfo=" + mCphsInfo); + pw.println(" mCphsInfo=" + IccUtils.bytesToHexString(mCphsInfo)); pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled); pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS)); pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI)); pw.println(" mEfCff[]=" + Arrays.toString(mEfCff)); pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis)); pw.println(" mCarrierNameDisplayCondition=" + mCarrierNameDisplayCondition); - pw.println(" mSpdi[]=" + mSpdi); + pw.println(" mSpdi[]=" + Arrays.toString(mSpdi)); pw.println(" mUsimServiceTable=" + mUsimServiceTable); pw.println(" mGid1=" + mGid1); if (mCarrierTestOverride.isInTestMode()) { -- GitLab From 8d1c127023f415c79f82d16376db78e245cb4d77 Mon Sep 17 00:00:00 2001 From: Michael Groover Date: Tue, 4 Oct 2022 16:53:40 -0500 Subject: [PATCH 110/656] Add unaudited exported flag to exposed runtime receivers Android T allows apps to declare a runtime receiver as not exported by invoking registerReceiver with a new RECEIVER_NOT_EXPORTED flag; receivers registered with this flag will only receive broadcasts from the platform and the app itself. However to ensure developers can properly protect their receivers, all apps targeting U or later registering a receiver for non-system broadcasts must specify either the exported or not exported flag when invoking #registerReceiver; if one of these flags is not provided, the platform will throw a SecurityException. This commit updates all the exposed receivers with a new RECEIVER_EXPORTED_UNAUDITED flag to maintain the existing behavior of exporting the receiver while also flagging the receiver for audit before the U release. Bug: 234659204 Test: Build Change-Id: I9806eafcaa0b25f7a2a34c80cbf20eb60c53cda0 --- .../com/android/internal/telephony/CallWaitingController.java | 3 ++- .../android/internal/telephony/CarrierPrivilegesTracker.java | 3 ++- .../android/internal/telephony/MultiSimSettingController.java | 3 ++- .../com/android/internal/telephony/ServiceStateTracker.java | 2 +- src/java/com/android/internal/telephony/ims/ImsResolver.java | 3 ++- src/java/com/android/internal/telephony/uicc/PinStorage.java | 3 ++- src/java/com/android/internal/telephony/uicc/UiccProfile.java | 3 ++- .../android/internal/telephony/gsm/GsmSmsDispatcherTest.java | 3 ++- 8 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java index 4940eb62b2..3b134f6511 100644 --- a/src/java/com/android/internal/telephony/CallWaitingController.java +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -145,7 +145,8 @@ public class CallWaitingController extends Handler { private void initialize() { mContext.registerReceiver(mReceiver, new IntentFilter( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), + Context.RECEIVER_EXPORTED_UNAUDITED); int phoneId = mPhone.getPhoneId(); int subId = mPhone.getSubId(); diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index b91e6bfb3f..4d9d860df6 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -377,7 +377,8 @@ public class CarrierPrivilegesTracker extends Handler { certFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); certFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); certFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); - mContext.registerReceiver(mIntentReceiver, certFilter); + mContext.registerReceiver(mIntentReceiver, certFilter, + Context.RECEIVER_EXPORTED_UNAUDITED); IntentFilter packageFilter = new IntentFilter(); packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index 85053de899..e3dfcb36da 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -246,7 +246,8 @@ public class MultiSimSettingController extends Handler { mIsAskEverytimeSupportedForSms = mContext.getResources() .getBoolean(com.android.internal.R.bool.config_sms_ask_every_time_support); context.registerReceiver(mIntentReceiver, new IntentFilter( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), + Context.RECEIVER_EXPORTED_UNAUDITED); } /** diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index f99479243f..7ee6273ddb 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -699,7 +699,7 @@ public class ServiceStateTracker extends Handler { filter.addAction(Intent.ACTION_LOCALE_CHANGED); filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED); - context.registerReceiver(mIntentReceiver, filter); + context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_EXPORTED_UNAUDITED); mPhone.notifyOtaspChanged(TelephonyManager.OTASP_UNINITIALIZED); diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java index c3331d9c54..0a14fe1428 100644 --- a/src/java/com/android/internal/telephony/ims/ImsResolver.java +++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java @@ -651,7 +651,8 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal appChangedFilter.addDataScheme("package"); mReceiverContext.registerReceiver(mAppChangedReceiver, appChangedFilter); mReceiverContext.registerReceiver(mConfigChangedReceiver, new IntentFilter( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), + Context.RECEIVER_EXPORTED_UNAUDITED); UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); if (userManager.isUserUnlocked()) { diff --git a/src/java/com/android/internal/telephony/uicc/PinStorage.java b/src/java/com/android/internal/telephony/uicc/PinStorage.java index 1154e0f04a..79813140f5 100644 --- a/src/java/com/android/internal/telephony/uicc/PinStorage.java +++ b/src/java/com/android/internal/telephony/uicc/PinStorage.java @@ -193,7 +193,8 @@ public class PinStorage extends Handler { intentFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); intentFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); - mContext.registerReceiver(mCarrierConfigChangedReceiver, intentFilter); + mContext.registerReceiver(mCarrierConfigChangedReceiver, intentFilter, + Context.RECEIVER_EXPORTED_UNAUDITED); // Initialize the long term secret key. This needs to be present in all cases: // - if the device is not secure or is locked: key does not require user authentication diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index 2809895309..c286cadc4e 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -339,7 +339,8 @@ public class UiccProfile extends IccCard { IntentFilter intentfilter = new IntentFilter(); intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - c.registerReceiver(mCarrierConfigChangedReceiver, intentfilter); + c.registerReceiver(mCarrierConfigChangedReceiver, intentfilter, + Context.RECEIVER_EXPORTED_UNAUDITED); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java index 5f4671b918..a093d11744 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java @@ -231,7 +231,8 @@ public class GsmSmsDispatcherTest extends TelephonyTest { restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton); restoreInstance(ActivityManager.class, "IActivityManagerSingleton", null); Context realContext = TestApplication.getAppContext(); - realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT)); + realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT), + Context.RECEIVER_EXPORTED_UNAUDITED); } @Test -- GitLab From b3d4478c169db2e171a6a6b951aacd7f2eb88263 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Mon, 3 Oct 2022 15:41:18 -0700 Subject: [PATCH 111/656] NR advanced state check for NR SA Prevent the early return when NR state is not connected in NR SA mode and update NR advanced state properly. Fix redundant logs for NR Connected <-> NR Advanced transitions. Test: NetworkTypeControllerTest Test: manual test modifying carrier configs Bug: 249173396 Change-Id: I4a16a37233f696e7869427a98b8f385372036bc9 --- .../telephony/NetworkTypeController.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 6f6d655378..173036660a 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -979,17 +979,20 @@ public class NetworkTypeController extends StateMachine { private void updateNrAdvancedState() { log("updateNrAdvancedState"); - if (!isNrConnected()) { + if (!isNrConnected() && getDataNetworkType() != TelephonyManager.NETWORK_TYPE_NR) { log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); sendMessage(EVENT_NR_STATE_CHANGED); return; } - if (!isNrAdvanced()) { - if (DBG) log("updateNrAdvancedState: CONNECTED_NR_ADVANCED -> CONNECTED"); - transitionWithTimerTo(mNrConnectedState); - } else { - if (DBG) log("updateNrAdvancedState: CONNECTED -> CONNECTED_NR_ADVANCED"); - transitionTo(mNrConnectedState); + boolean isNrAdvanced = isNrAdvanced(); + if (isNrAdvanced != mIsNrAdvanced) { + if (!isNrAdvanced) { + if (DBG) log("updateNrAdvancedState: CONNECTED_NR_ADVANCED -> CONNECTED"); + transitionWithTimerTo(mNrConnectedState); + } else { + if (DBG) log("updateNrAdvancedState: CONNECTED -> CONNECTED_NR_ADVANCED"); + transitionTo(mNrConnectedState); + } } mIsNrAdvanced = isNrAdvanced(); log("mIsNrAdvanced=" + mIsNrAdvanced); -- GitLab From db4b18d9672e9c0d012438b6e006746ae58b4e80 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Tue, 4 Oct 2022 11:56:12 +0100 Subject: [PATCH 112/656] Remove usages of TimestampedValue Track changes in frameworks/base/ Remove usages of TimestampedValue now we have UnixEpochTime, which is the same thing but intended to be an SDK API. Bug: 236612872 Test: Build only Change-Id: I6a7b40acfb880af6acdbcb13d8c169098018bc19 --- .../com/android/internal/telephony/NitzSignal.java | 13 ++++++------- .../telephony/nitz/NitzStateMachineImpl.java | 3 ++- .../telephony/nitz/TimeServiceHelperImpl.java | 7 ++++--- .../telephony/nitz/NitzStateMachineImplTest.java | 3 ++- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/java/com/android/internal/telephony/NitzSignal.java b/src/java/com/android/internal/telephony/NitzSignal.java index 889fe95c7c..2619f3da43 100644 --- a/src/java/com/android/internal/telephony/NitzSignal.java +++ b/src/java/com/android/internal/telephony/NitzSignal.java @@ -19,7 +19,7 @@ package com.android.internal.telephony; import android.annotation.DurationMillisLong; import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; -import android.os.TimestampedValue; +import android.app.time.UnixEpochTime; import java.time.Duration; import java.util.Objects; @@ -88,13 +88,12 @@ public final class NitzSignal { } /** - * Creates a {@link android.os.TimestampedValue} containing the UTC time as the number of - * milliseconds since the start of the Unix epoch. The reference time is the time according to - * the elapsed realtime clock when that would have been the time, accounting for receipt time - * and age. + * Creates a {@link UnixEpochTime} containing the UTC time as the number of milliseconds since + * the start of the Unix epoch. The reference time is the time according to the elapsed realtime + * clock when that would have been the time, accounting for receipt time and age. */ - public TimestampedValue createTimeSignal() { - return new TimestampedValue<>( + public UnixEpochTime createTimeSignal() { + return new UnixEpochTime( getAgeAdjustedElapsedRealtimeMillis(), getNitzData().getCurrentTimeInMillis()); } diff --git a/src/java/com/android/internal/telephony/nitz/NitzStateMachineImpl.java b/src/java/com/android/internal/telephony/nitz/NitzStateMachineImpl.java index 81151278b7..8b34933749 100644 --- a/src/java/com/android/internal/telephony/nitz/NitzStateMachineImpl.java +++ b/src/java/com/android/internal/telephony/nitz/NitzStateMachineImpl.java @@ -18,6 +18,7 @@ package com.android.internal.telephony.nitz; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.time.UnixEpochTime; import android.app.timedetector.TelephonyTimeSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.content.Context; @@ -372,7 +373,7 @@ public final class NitzStateMachineImpl implements NitzStateMachine { builder.addDebugInfo("Clearing time suggestion" + " reason=" + reason); } else { - TimestampedValue newNitzTime = nitzSignal.createTimeSignal(); + UnixEpochTime newNitzTime = nitzSignal.createTimeSignal(); builder.setUnixEpochTime(newNitzTime); builder.addDebugInfo("Sending new time suggestion" + " nitzSignal=" + nitzSignal diff --git a/src/java/com/android/internal/telephony/nitz/TimeServiceHelperImpl.java b/src/java/com/android/internal/telephony/nitz/TimeServiceHelperImpl.java index 9c7aac9cfc..74b30f81c8 100644 --- a/src/java/com/android/internal/telephony/nitz/TimeServiceHelperImpl.java +++ b/src/java/com/android/internal/telephony/nitz/TimeServiceHelperImpl.java @@ -18,13 +18,13 @@ package com.android.internal.telephony.nitz; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.time.UnixEpochTime; import android.app.timedetector.TelephonyTimeSuggestion; import android.app.timedetector.TimeDetector; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.app.timezonedetector.TimeZoneDetector; import android.content.Context; import android.os.SystemClock; -import android.os.TimestampedValue; import android.util.LocalLog; import com.android.internal.telephony.Phone; @@ -69,8 +69,9 @@ public final class TimeServiceHelperImpl implements TimeServiceHelper { Objects.requireNonNull(timeSuggestion); if (timeSuggestion.getUnixEpochTime() != null) { - TimestampedValue unixEpochTime = timeSuggestion.getUnixEpochTime(); - TelephonyMetrics.getInstance().writeNITZEvent(mSlotIndex, unixEpochTime.getValue()); + UnixEpochTime unixEpochTime = timeSuggestion.getUnixEpochTime(); + TelephonyMetrics.getInstance().writeNITZEvent( + mSlotIndex, unixEpochTime.getUnixEpochTimeMillis()); } mTimeDetector.suggestTelephonyTime(timeSuggestion); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/nitz/NitzStateMachineImplTest.java b/tests/telephonytests/src/com/android/internal/telephony/nitz/NitzStateMachineImplTest.java index 2ac0c98365..580d533322 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/nitz/NitzStateMachineImplTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/nitz/NitzStateMachineImplTest.java @@ -910,7 +910,8 @@ public class NitzStateMachineImplTest { suggestedTimes.set(timeSuggestion); if (timeSuggestion.getUnixEpochTime() != null) { // The fake time service just uses the latest suggestion. - mFakeDeviceState.currentTimeMillis = timeSuggestion.getUnixEpochTime().getValue(); + mFakeDeviceState.currentTimeMillis = + timeSuggestion.getUnixEpochTime().getUnixEpochTimeMillis(); } } -- GitLab From 72e81a52860e2656cce6ae219342cf1249206796 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 6 Oct 2022 10:21:56 -0700 Subject: [PATCH 113/656] Add logs for AIDL death recipient registration If we do not receive a notification that the AIDL service died, currently we cannot tell if it is due to an error in the registration or the notification. Add logs to help detect an issue if it occurs. Test: atest RILTest Bug: 245674767 Change-Id: I14b41555f19f5ab37dbbe2a83f7c303c5b080aad --- src/java/com/android/internal/telephony/RIL.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index caa887daad..c9cfc4d77f 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -431,8 +431,11 @@ public class RIL extends BaseCommands implements CommandsInterface { public void linkToDeath(IBinder service) throws RemoteException { if (service != null) { + riljLog("Linked to death for service " + serviceToString(mService)); mBinder = service; mBinder.linkToDeath(this, (int) mServiceCookies.get(mService).incrementAndGet()); + } else { + riljLoge("Unable to link to death for service " + serviceToString(mService)); } } -- GitLab From 3d552542c3390746425d7222c639066c10179643 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Fri, 7 Oct 2022 14:35:23 -0700 Subject: [PATCH 114/656] Check phone in call for DataDuringCall Because MMS requests can be routed to non-DDS. Without the change, MMS will be accidentally allowed due to the current dataDuringCall policy check. Bug: 244064524 Test: manual + UT Change-Id: I907bad0d58d5b1814e4e28cd3d56df1db49facf9 --- .../telephony/data/DataSettingsManager.java | 3 ++- .../telephony/data/DataNetworkControllerTest.java | 13 +++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index d68afadfb8..4ab1adbc6c 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -44,6 +44,7 @@ import android.util.LocalLog; import com.android.internal.telephony.GlobalSettingsHelper; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.SettingsObserver; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback; @@ -712,7 +713,7 @@ public class DataSettingsManager extends Handler { // mobile data policy : data during call if (isMobileDataPolicyEnabled(TelephonyManager .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL)) { - overridden = isNonDds; + overridden = isNonDds && mPhone.getState() != PhoneConstants.State.IDLE; } return overridden; } 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 7cd6ede82c..89f7a5be35 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -1498,8 +1498,6 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testIsDataEnabledOverriddenForApn_dataDuringCall() throws Exception { - // Note: we don't check phone call status in DSMGR as the check should already been done in - // PhoneSwitcher when routing requests. doReturn(1).when(mPhone).getSubId(); doReturn(2).when(mSubscriptionController).getDefaultDataSubId(); // Data disabled @@ -1511,6 +1509,17 @@ public class DataNetworkControllerTest extends TelephonyTest { .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL, true); processAllMessages(); + // No active phone call + doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + + // Verify no internet connection due to no active phone call + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + + // Phone ringing + doReturn(PhoneConstants.State.RINGING).when(mPhone).getState(); mDataNetworkControllerUT.addNetworkRequest( createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); processAllMessages(); -- GitLab From 7d4dd3c20b1b185fcd0fbcdaa365ca7f6cef46bb Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 7 Oct 2022 16:38:53 -0700 Subject: [PATCH 115/656] Renamed name source to display name source Bug: 239607619 Test: Build Change-Id: I88c9b07a3e1085109a8612cd7d3e80d1e7965dfd --- .../telephony/SubscriptionController.java | 6 ++--- .../telephony/SubscriptionInfoUpdater.java | 2 +- .../internal/telephony/GsmCdmaPhoneTest.java | 2 +- .../MultiSimSettingControllerTest.java | 2 +- .../telephony/SubscriptionControllerTest.java | 26 +++++++++---------- .../telephony/SubscriptionInfoTest.java | 4 +-- .../telephony/euicc/EuiccControllerTest.java | 2 +- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 3b580149e2..fdc2089175 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -541,7 +541,7 @@ public class SubscriptionController extends ISub.Stub { SubscriptionManager.DISPLAY_NAME))) .setCarrierName(cursor.getString(cursor.getColumnIndexOrThrow( SubscriptionManager.CARRIER_NAME))) - .setNameSource(cursor.getInt(cursor.getColumnIndexOrThrow( + .setDisplayNameSource(cursor.getInt(cursor.getColumnIndexOrThrow( SubscriptionManager.NAME_SOURCE))) .setIconTint(cursor.getInt(cursor.getColumnIndexOrThrow( SubscriptionManager.HUE))) @@ -1908,7 +1908,7 @@ public class SubscriptionController extends ISub.Stub { String spn; - switch (subInfo.getNameSource()) { + switch (subInfo.getDisplayNameSource()) { case SubscriptionManager.NAME_SOURCE_SIM_PNN: String pnn = phone.getPlmn(); return !TextUtils.isEmpty(pnn); @@ -1976,7 +1976,7 @@ public class SubscriptionController extends ISub.Stub { // if there is no sub in the db, return 0 since subId does not exist in db if (allSubInfo == null || allSubInfo.isEmpty()) return 0; for (SubscriptionInfo subInfo : allSubInfo) { - int subInfoNameSource = subInfo.getNameSource(); + int subInfoNameSource = subInfo.getDisplayNameSource(); boolean isHigherPriority = (getNameSourcePriority(subInfoNameSource) > getNameSourcePriority(nameSource)); boolean isEqualPriorityAndName = (getNameSourcePriority(subInfoNameSource) diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index be33499fa8..d81640e5ab 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -1018,7 +1018,7 @@ public class SubscriptionInfoUpdater extends Handler { mSubscriptionController.insertEmptySubInfoRecord( embeddedProfile.getIccid(), SubscriptionManager.SIM_NOT_INSERTED); } else { - nameSource = existingSubscriptions.get(index).getNameSource(); + nameSource = existingSubscriptions.get(index).getDisplayNameSource(); prevCarrierId = existingSubscriptions.get(index).getCarrierId(); existingSubscriptions.remove(index); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 3b9667b123..ba5e15537d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -1664,7 +1664,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { .setSimSlotIndex(1) .setDisplayName("Android Test") .setDisplayName("Android Test") - .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) + .setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) .setNumber("8675309") .setMcc("001") .setMnc("01") diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index 09493a18b0..ac76797a4a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -95,7 +95,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { .setSimSlotIndex(0) .setDisplayName("T-mobile") .setCarrierName("T-mobile") - .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) + .setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) .setIconTint(255) .setNumber("12345") .setMcc("310") diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index f80253e966..15dec83140 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -302,7 +302,7 @@ public class SubscriptionControllerTest extends TelephonyTest { .getActiveSubscriptionInfo(subID, mCallingPackage, mCallingFeature); assertNotNull(subInfo); assertEquals(disName, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getNameSource()); + assertEquals(nameSource, subInfo.getDisplayNameSource()); } private void setSimEmbedded(boolean isEmbedded) throws Exception { @@ -336,7 +336,7 @@ public class SubscriptionControllerTest extends TelephonyTest { assertNotNull(subInfo); assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getNameSource()); + assertEquals(nameSource, subInfo.getDisplayNameSource()); } @Test @SmallTest @@ -363,7 +363,7 @@ public class SubscriptionControllerTest extends TelephonyTest { assertNotNull(subInfo); assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getNameSource()); + assertEquals(nameSource, subInfo.getDisplayNameSource()); } @Test @SmallTest @@ -390,7 +390,7 @@ public class SubscriptionControllerTest extends TelephonyTest { assertNotNull(subInfo); assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getNameSource()); + assertEquals(nameSource, subInfo.getDisplayNameSource()); } @Test @SmallTest @@ -421,7 +421,7 @@ public class SubscriptionControllerTest extends TelephonyTest { assertNotNull(subInfo); assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getNameSource()); + assertEquals(nameSource, subInfo.getDisplayNameSource()); } @Test @SmallTest @@ -447,7 +447,7 @@ public class SubscriptionControllerTest extends TelephonyTest { assertNotNull(subInfo); assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getNameSource()); + assertEquals(nameSource, subInfo.getDisplayNameSource()); } @Test @SmallTest @@ -472,13 +472,13 @@ public class SubscriptionControllerTest extends TelephonyTest { assertNotNull(subInfo); assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getNameSource()); + assertEquals(nameSource, subInfo.getDisplayNameSource()); } @Test @SmallTest public void testIsExistingNameSourceStillValid_pnnIsNotNull_returnTrue() { when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getNameSource()) + when(mMockSubscriptionInfo.getDisplayNameSource()) .thenReturn(SubscriptionManager.NAME_SOURCE_SIM_PNN); when(mPhone.getPlmn()).thenReturn("testing_pnn"); @@ -488,7 +488,7 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test @SmallTest public void testIsExistingNameSourceStillValid_spnIsNotNull_returnTrue() { when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getNameSource()) + when(mMockSubscriptionInfo.getDisplayNameSource()) .thenReturn(SubscriptionManager.NAME_SOURCE_SIM_SPN); when(mUiccController.getUiccProfileForPhone(anyInt())).thenReturn(mUiccProfile); when(mUiccProfile.getServiceProviderName()).thenReturn("testing_spn"); @@ -500,7 +500,7 @@ public class SubscriptionControllerTest extends TelephonyTest { public void testIsExistingNameSourceStillValid_simIsEmbedded_returnTrue() { when(mMockSubscriptionInfo.isEmbedded()).thenReturn(true); when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getNameSource()) + when(mMockSubscriptionInfo.getDisplayNameSource()) .thenReturn(SubscriptionManager.NAME_SOURCE_CARRIER); assertTrue(mSubscriptionControllerUT.isExistingNameSourceStillValid(mMockSubscriptionInfo)); @@ -510,7 +510,7 @@ public class SubscriptionControllerTest extends TelephonyTest { public void testIsExistingNameSourceStillValid_carrierConfigIsNull_returnTrue() { when(mMockSubscriptionInfo.isEmbedded()).thenReturn(false); when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getNameSource()) + when(mMockSubscriptionInfo.getDisplayNameSource()) .thenReturn(SubscriptionManager.NAME_SOURCE_CARRIER); when(mCarrierConfigManager.getConfigForSubId(FAKE_SUBID)).thenReturn(null); @@ -521,7 +521,7 @@ public class SubscriptionControllerTest extends TelephonyTest { public void testIsExistingNameSourceStillValid_carrierNameOverrideIsTrue_returnTrue() { when(mMockSubscriptionInfo.isEmbedded()).thenReturn(false); when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getNameSource()) + when(mMockSubscriptionInfo.getDisplayNameSource()) .thenReturn(SubscriptionManager.NAME_SOURCE_CARRIER); mCarrierConfigs.putBoolean(CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL, true); @@ -532,7 +532,7 @@ public class SubscriptionControllerTest extends TelephonyTest { public void testIsExistingNameSourceStillValid_spnIsNullAndCarrierNameIsNotNull_returnTrue() { when(mMockSubscriptionInfo.isEmbedded()).thenReturn(false); when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getNameSource()) + when(mMockSubscriptionInfo.getDisplayNameSource()) .thenReturn(SubscriptionManager.NAME_SOURCE_CARRIER); when(mUiccController.getUiccProfileForPhone(anyInt())).thenReturn(mUiccProfile); when(mUiccProfile.getServiceProviderName()).thenReturn(null); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java index 7b1005998b..3bafe4d7e9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoTest.java @@ -43,7 +43,7 @@ public class SubscriptionInfoTest { .setSimSlotIndex(0) .setDisplayName("T-mobile") .setCarrierName("T-mobile") - .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) + .setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) .setIconTint(255) .setNumber("12345") .setDataRoaming(SubscriptionManager.DATA_ROAMING_DISABLE) @@ -67,7 +67,7 @@ public class SubscriptionInfoTest { assertThat(mSubscriptionInfoUT.getCarrierName().toString()).isEqualTo("T-mobile"); assertThat(mSubscriptionInfoUT.getCountryIso()).isEqualTo("us"); assertThat(mSubscriptionInfoUT.getIconTint()).isEqualTo(255); - assertThat(mSubscriptionInfoUT.getNameSource()).isEqualTo(0); + assertThat(mSubscriptionInfoUT.getDisplayNameSource()).isEqualTo(0); assertThat(mSubscriptionInfoUT.getSubscriptionId()).isEqualTo(1); assertThat(mSubscriptionInfoUT.getSimSlotIndex()).isEqualTo(0); assertThat(mSubscriptionInfoUT.getIccId()).isEqualTo("890126042XXXXXXXXXXX"); 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 6f0759c74d..15316e6043 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java @@ -1260,7 +1260,7 @@ public class EuiccControllerTest extends TelephonyTest { throws Exception { SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder() .setSimSlotIndex(0) - .setNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) + .setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) .setEmbedded(true); if (hasPrivileges) { builder.setNativeAccessRules(new UiccAccessRule[] { ACCESS_RULE }); -- GitLab From 2a31e7f3c36d4df652c28f01ea488d5798d4ed50 Mon Sep 17 00:00:00 2001 From: sparvathy Date: Tue, 4 Oct 2022 03:28:59 +0000 Subject: [PATCH 116/656] (Emergency Call Improvement) Seperated codes related to hal version below & above 1.4 Rearranged all the code which are dependent on hal version into seperate methods. So that will be easy to deprecate older version. From Hal version 1.4 emergency number are obtained from radio indication. For version less than 1.4 emergency number are obtained from ril.ecclist Test: atest EmergencyNumberTrackerTest Bug: 249107141 Change-Id: I9049595980b451d99e9a31c15cee75ccc8e1a6f5 --- .../emergency/EmergencyNumberTracker.java | 106 ++++++++++-------- .../emergency/EmergencyNumberTrackerTest.java | 18 ++- 2 files changed, 73 insertions(+), 51 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index de6042842f..b346636a92 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.emergency; +import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -100,6 +101,7 @@ public class EmergencyNumberTracker extends Handler { private String mCountryIso; private String mLastKnownEmergencyCountryIso = ""; private int mCurrentDatabaseVersion = INVALID_DATABASE_VERSION; + private boolean mIsHalVersionLessThan1Dot4 = false; /** * Indicates if the country iso is set by another subscription. * @hide @@ -188,6 +190,8 @@ public class EmergencyNumberTracker extends Handler { filter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED); mPhone.getContext().registerReceiver(mIntentReceiver, filter); + + mIsHalVersionLessThan1Dot4 = mPhone.getHalVersion().lessOrEqual(new HalVersion(1, 3)); } else { loge("mPhone is null."); } @@ -841,29 +845,44 @@ public class EmergencyNumberTracker extends Handler { */ private List getEmergencyNumberListFromEccList() { List emergencyNumberList = new ArrayList<>(); + + if (mIsHalVersionLessThan1Dot4) { + emergencyNumberList.addAll(getEmergencyNumberListFromEccListForHalv1_3()); + } + String emergencyNumbers = ((isSimAbsent()) ? "112,911,000,08,110,118,119,999" : "112,911"); + for (String emergencyNum : emergencyNumbers.split(",")) { + emergencyNumberList.add(getLabeledEmergencyNumberForEcclist(emergencyNum)); + } + if (mEmergencyNumberPrefix.length != 0) { + emergencyNumberList.addAll(getEmergencyNumberListWithPrefix(emergencyNumberList)); + } + EmergencyNumber.mergeSameNumbersInEmergencyNumberList(emergencyNumberList); + return emergencyNumberList; + } + + private String getEmergencyNumberListForHalv1_3() { int slotId = SubscriptionController.getInstance().getSlotIndex(mPhone.getSubId()); String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); String emergencyNumbers = SystemProperties.get(ecclist, ""); + if (TextUtils.isEmpty(emergencyNumbers)) { // then read-only ecclist property since old RIL only uses this emergencyNumbers = SystemProperties.get("ro.ril.ecclist"); } + logd(ecclist + " emergencyNumbers: " + emergencyNumbers); + return emergencyNumbers; + } + + private List getEmergencyNumberListFromEccListForHalv1_3() { + List emergencyNumberList = new ArrayList<>(); + String emergencyNumbers = getEmergencyNumberListForHalv1_3(); + if (!TextUtils.isEmpty(emergencyNumbers)) { - // searches through the comma-separated list for a match, - // return true if one is found. for (String emergencyNum : emergencyNumbers.split(",")) { emergencyNumberList.add(getLabeledEmergencyNumberForEcclist(emergencyNum)); } } - emergencyNumbers = ((isSimAbsent()) ? "112,911,000,08,110,118,119,999" : "112,911"); - for (String emergencyNum : emergencyNumbers.split(",")) { - emergencyNumberList.add(getLabeledEmergencyNumberForEcclist(emergencyNum)); - } - if (mEmergencyNumberPrefix.length != 0) { - emergencyNumberList.addAll(getEmergencyNumberListWithPrefix(emergencyNumberList)); - } - EmergencyNumber.mergeSameNumbersInEmergencyNumberList(emergencyNumberList); return emergencyNumberList; } @@ -899,7 +918,7 @@ public class EmergencyNumberTracker extends Handler { } private boolean isEmergencyNumberFromDatabase(String number) { - if (!mPhone.getHalVersion().greaterOrEqual(new HalVersion(1, 4))) { + if (mEmergencyNumberListFromDatabase.isEmpty()) { return false; } number = PhoneNumberUtils.stripSeparators(number); @@ -962,42 +981,14 @@ public class EmergencyNumberTracker extends Handler { /// @} String emergencyNumbers = ""; - int slotId = SubscriptionController.getInstance().getSlotIndex(mPhone.getSubId()); - - String ecclist = null; String countryIso = getLastKnownEmergencyCountryIso(); + logd("country:" + countryIso); - if (!mPhone.getHalVersion().greaterOrEqual(new HalVersion(1, 4))) { - //only use ril ecc list for older devices with HAL < 1.4 - // check read-write ecclist property first - ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); - emergencyNumbers = SystemProperties.get(ecclist, ""); - - logd("slotId:" + slotId + " country:" + countryIso + " emergencyNumbers: " - + emergencyNumbers); - - if (TextUtils.isEmpty(emergencyNumbers)) { - // then read-only ecclist property since old RIL only uses this - emergencyNumbers = SystemProperties.get("ro.ril.ecclist"); - } + if (mIsHalVersionLessThan1Dot4) { + emergencyNumbers = getEmergencyNumberListForHalv1_3(); if (!TextUtils.isEmpty(emergencyNumbers)) { - // searches through the comma-separated list for a match, - // return true if one is found. - for (String emergencyNum : emergencyNumbers.split(",")) { - if (number.equals(emergencyNum)) { - return true; - } else { - for (String prefix : mEmergencyNumberPrefix) { - if (number.equals(prefix + emergencyNum)) { - return true; - } - } - } - - } - // no matches found against the list! - return false; + return isEmergencyNumberFromEccListForHalv1_3(number, emergencyNumbers); } } @@ -1041,6 +1032,25 @@ public class EmergencyNumberTracker extends Handler { return false; } + private boolean isEmergencyNumberFromEccListForHalv1_3(@NonNull String number, + @NonNull String emergencyNumbers) { + // searches through the comma-separated list for a match, + // return true if one is found. + for (String emergencyNum : emergencyNumbers.split(",")) { + if (number.equals(emergencyNum)) { + return true; + } else { + for (String prefix : mEmergencyNumberPrefix) { + if (number.equals(prefix + emergencyNum)) { + return true; + } + } + } + } + // no matches found against the list! + return false; + } + /** * Execute command for updating emergency number for test mode. */ @@ -1080,7 +1090,7 @@ public class EmergencyNumberTracker extends Handler { private List getEmergencyNumberListFromEccListDatabaseAndTest() { List mergedEmergencyNumberList = getEmergencyNumberListFromEccList(); - if (mPhone.getHalVersion().greaterOrEqual(new HalVersion(1, 4))) { + if (!mEmergencyNumberListFromDatabase.isEmpty()) { loge("getEmergencyNumberListFromEccListDatabaseAndTest: radio indication is" + " unavailable in 1.4 HAL."); mergedEmergencyNumberList.addAll(mEmergencyNumberListFromDatabase); @@ -1175,10 +1185,10 @@ public class EmergencyNumberTracker extends Handler { ipw.decreaseIndent(); ipw.println(" ========================================= "); - int slotId = SubscriptionController.getInstance().getSlotIndex(mPhone.getSubId()); - String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); - ipw.println(" ril.ecclist: " + SystemProperties.get(ecclist, "")); - ipw.println(" ========================================= "); + if (mIsHalVersionLessThan1Dot4) { + getEmergencyNumberListForHalv1_3(); + ipw.println(" ========================================= "); + } ipw.println("Emergency Number List for Phone" + "(" + mPhone.getPhoneId() + ")"); ipw.increaseIndent(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index c97b6e2fcd..f49960a59f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -26,6 +26,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.content.Context; +import android.content.res.AssetManager; import android.os.AsyncResult; import android.os.Environment; import android.os.ParcelFileDescriptor; @@ -115,6 +117,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private File mLocalDownloadDirectory; private ShortNumberInfo mShortNumberInfo; + private Context mMockContext; @Before public void setUp() throws Exception { @@ -124,14 +127,17 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { mSubControllerMock = mock(SubscriptionController.class); mPhone2 = mock(Phone.class); mContext = InstrumentationRegistry.getTargetContext(); + mMockContext = mock(Context.class); doReturn(mContext).when(mPhone).getContext(); doReturn(0).when(mPhone).getPhoneId(); doReturn(SUB_ID_PHONE_1).when(mPhone).getSubId(); + doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(); doReturn(mContext).when(mPhone2).getContext(); doReturn(1).when(mPhone2).getPhoneId(); doReturn(SUB_ID_PHONE_2).when(mPhone2).getSubId(); + doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(); initializeEmergencyNumberListTestSamples(); mEmergencyNumberTrackerMock = new EmergencyNumberTracker(mPhone, mSimulatedCommands); @@ -142,6 +148,9 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { // Copy an OTA file to the test directory to similate the OTA mechanism simulateOtaEmergencyNumberDb(mPhone); + AssetManager am = new AssetManager.Builder().build(); + doReturn(am).when(mMockContext).getAssets(); + processAllMessages(); logd("EmergencyNumberTrackerTest -Setup!"); } @@ -481,13 +490,16 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { @Test public void testUsingEmergencyNumberDatabaseWheneverHal_1_3() { doReturn(new HalVersion(1, 3)).when(mPhone).getHalVersion(); + doReturn(mMockContext).when(mPhone).getContext(); + EmergencyNumberTracker emergencyNumberTracker = new EmergencyNumberTracker( + mPhone, mSimulatedCommands); - sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock); - mEmergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("us"); + sendEmergencyNumberPrefix(emergencyNumberTracker); + emergencyNumberTracker.updateEmergencyCountryIsoAllPhones("us"); processAllMessages(); boolean hasDatabaseNumber = false; - for (EmergencyNumber number : mEmergencyNumberTrackerMock.getEmergencyNumberList()) { + for (EmergencyNumber number : emergencyNumberTracker.getEmergencyNumberList()) { if (number.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE)) { hasDatabaseNumber = true; break; -- GitLab From 7b55c1ad3fb9024a458e5dbd26c77753061939fb Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 7 Oct 2022 23:08:41 -0700 Subject: [PATCH 117/656] Added SubscriptionDatabaseManager Added subscription database manager, which is the wrapper on top of the database with a full cache. Bug: 239607619 Test: atest SubscriptionDatabaseManagerTest Change-Id: I2845352f89d71c303ea2d1503fb3d15dcf7730b2 --- .../telephony/data/DataSettingsManager.java | 7 +- .../internal/telephony/data/DataUtils.java | 19 - .../SubscriptionDatabaseManager.java | 1327 ++++++++++ .../SubscriptionInfoInternal.java | 2166 +++++++++++++++++ .../SubscriptionManagerService.java | 11 + .../SubscriptionDatabaseManagerTest.java | 892 +++++++ 6 files changed, 4400 insertions(+), 22 deletions(-) create mode 100644 src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java create mode 100644 src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index 4ab1adbc6c..fcd572c371 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -48,6 +48,7 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.SettingsObserver; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback; +import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -618,7 +619,7 @@ public class DataSettingsManager extends Handler { .collect(Collectors.joining(",")); if (SubscriptionController.getInstance().setEnabledMobileDataPolicies( mSubId, enabledMobileDataPolicies)) { - logl(DataUtils.mobileDataPolicyToString(mobileDataPolicy) + " changed to " + logl(TelephonyUtils.mobileDataPolicyToString(mobileDataPolicy) + " changed to " + enable); updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_OVERRIDE); notifyDataEnabledOverrideChanged(enable, mobileDataPolicy); @@ -761,7 +762,7 @@ public class DataSettingsManager extends Handler { + ", mIsDataEnabled=" + mIsDataEnabled + ", mDataEnabledSettings=" + mDataEnabledSettings + ", mEnabledMobileDataPolicy=" + mEnabledMobileDataPolicy.stream() - .map(DataUtils::mobileDataPolicyToString).collect(Collectors.joining(",")) + .map(TelephonyUtils::mobileDataPolicyToString).collect(Collectors.joining(",")) + "]"; } @@ -818,7 +819,7 @@ public class DataSettingsManager extends Handler { dataEnabledChangedReasonToString(entry.getKey()) + "=" + entry.getValue()) .collect(Collectors.joining(", "))); pw.println("mEnabledMobileDataPolicy=" + mEnabledMobileDataPolicy.stream() - .map(DataUtils::mobileDataPolicyToString).collect(Collectors.joining(","))); + .map(TelephonyUtils::mobileDataPolicyToString).collect(Collectors.joining(","))); pw.println("Local logs:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/data/DataUtils.java b/src/java/com/android/internal/telephony/data/DataUtils.java index ca957ae584..fc0c4f1145 100644 --- a/src/java/com/android/internal/telephony/data/DataUtils.java +++ b/src/java/com/android/internal/telephony/data/DataUtils.java @@ -32,7 +32,6 @@ import android.telephony.Annotation.NetCapability; import android.telephony.Annotation.NetworkType; import android.telephony.Annotation.ValidationStatus; import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.MobileDataPolicy; import android.telephony.data.ApnSetting; import android.telephony.data.ApnSetting.ApnType; import android.telephony.data.DataCallResponse; @@ -520,24 +519,6 @@ public class DataUtils { } } - /** - * Convert mobile data policy to string. - * - * @param mobileDataPolicy The mobile data policy. - * @return The mobile data policy in string format. - */ - public static @NonNull String mobileDataPolicyToString(@MobileDataPolicy int mobileDataPolicy) { - switch (mobileDataPolicy) { - case TelephonyManager.MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL: - return "DATA_ON_NON_DEFAULT_DURING_VOICE_CALL"; - case TelephonyManager.MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED: - return "MMS_ALWAYS_ALLOWED"; - default: - loge("Unknown mobile data policy(" + mobileDataPolicy + ")"); - return "UNKNOWN(" + mobileDataPolicy + ")"; - } - } - private static void loge(String msg) { Rlog.e(TAG, msg); } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java new file mode 100644 index 0000000000..3c6449539a --- /dev/null +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -0,0 +1,1327 @@ +/* + * Copyright 2022 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.subscription; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.provider.Telephony; +import android.provider.Telephony.SimInfo; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionManager.DeviceToDeviceStatusSharingPreference; +import android.telephony.SubscriptionManager.ProfileClass; +import android.telephony.SubscriptionManager.SimDisplayNameSource; +import android.telephony.SubscriptionManager.SubscriptionType; +import android.telephony.SubscriptionManager.UsageSetting; +import android.telephony.TelephonyManager; +import android.telephony.UiccAccessRule; +import android.telephony.ims.ImsMmTelManager; +import android.text.TextUtils; +import android.util.IndentingPrintWriter; +import android.util.LocalLog; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.telephony.uicc.UiccController; +import com.android.telephony.Rlog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * The subscription database manager is the wrapper of {@link SimInfo} + * table. It's a full memory cache of the entire subscription database, and it's intended to run + * on a separate thread to perform asynchronous database update. The database's cache allows + * multi threads to read simultaneously, if no write is ongoing. + * + * Note that from Android 14, directly writing into the subscription database through content + * resolver with {@link SimInfo#CONTENT_URI} will cause cache/db out of sync. All the read/write + * to the database should go through {@link SubscriptionManagerService}. + */ +public class SubscriptionDatabaseManager extends Handler { + private static final String LOG_TAG = "SDM"; + + /** Whether enabling verbose debugging message or not. */ + private static final boolean VDBG = false; + + /** Invalid database row index. */ + private static final int INVALID_ROW_INDEX = -1; + + /** The context */ + @NonNull + private final Context mContext; + + /** Telephony manager */ + private final TelephonyManager mTelephonyManager; + + /** UICC controller */ + private final UiccController mUiccController; + + /** + * The read/write lock to protect the entire database access. Using a Re-entrant read lock as + * much more read requests are expected than the write requests. All the access to + * {@link #mAllSubscriptionInfoInternalCache} needs to be protected by this lock. + */ + @NonNull + private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock(); + + /** Local log for most important debug messages. */ + @NonNull + private final LocalLog mLocalLog = new LocalLog(128); + + /** + * The entire subscription database, including subscriptions from inserted, previously inserted + * SIMs. This is the full memory cache of the subscription database. The key is the subscription + * id. Note all the access to this map needs to be protected by the re-entrant lock + * {@link #mReadWriteLock}. + * + * @see SimInfo + */ + @GuardedBy("mReadWriteLock") + @NonNull + private final Map mAllSubscriptionInfoInternalCache = + new HashMap<>(16); + + /** The mapping from {@link SimInfo} table to {@link SubscriptionInfoInternal} get methods. */ + private static final Map> + SUBSCRIPTION_GET_METHOD_MAP = Map.ofEntries( + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, + SubscriptionInfoInternal::getSubscriptionId), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ICC_ID, + SubscriptionInfoInternal::getIccId), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_SIM_SLOT_INDEX, + SubscriptionInfoInternal::getSimSlotIndex), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_DISPLAY_NAME, + SubscriptionInfoInternal::getDisplayName), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CARRIER_NAME, + SubscriptionInfoInternal::getCarrierName), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_NAME_SOURCE, + SubscriptionInfoInternal::getDisplayNameSource), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_COLOR, + SubscriptionInfoInternal::getIconTint), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_NUMBER, + SubscriptionInfoInternal::getNumber), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_DATA_ROAMING, + SubscriptionInfoInternal::getDataRoaming), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_MCC_STRING, + SubscriptionInfoInternal::getMccString), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_MNC_STRING, + SubscriptionInfoInternal::getMncString), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_EHPLMNS, + SubscriptionInfoInternal::getEhplmns), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_HPLMNS, + SubscriptionInfoInternal::getHplmnsRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_EMBEDDED, + SubscriptionInfoInternal::isEmbeddedRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CARD_ID, + SubscriptionInfoInternal::getCardString), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ACCESS_RULES, + SubscriptionInfoInternal::getNativeAccessRulesRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, + SubscriptionInfoInternal::getCarrierConfigAccessRulesRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_REMOVABLE, + SubscriptionInfoInternal::isRemovableEmbeddedRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, + SubscriptionInfoInternal::isEnhanced4GModeEnabledRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_VT_IMS_ENABLED, + SubscriptionInfoInternal::isVideoTelephonyEnabledRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_ENABLED, + SubscriptionInfoInternal::isWifiCallingEnabledRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_MODE, + SubscriptionInfoInternal::getWifiCallingMode), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, + SubscriptionInfoInternal::getWifiCallingModeForRoaming), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, + SubscriptionInfoInternal::isWifiCallingEnabledForRoamingRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_OPPORTUNISTIC, + SubscriptionInfoInternal::isOpportunisticRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_GROUP_UUID, + SubscriptionInfoInternal::getGroupUuidRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ISO_COUNTRY_CODE, + SubscriptionInfoInternal::getCountryIso), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CARRIER_ID, + SubscriptionInfoInternal::getCarrierId), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PROFILE_CLASS, + SubscriptionInfoInternal::getProfileClass), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_SUBSCRIPTION_TYPE, + SubscriptionInfoInternal::getSubscriptionType), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_GROUP_OWNER, + SubscriptionInfoInternal::getGroupOwner), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, + SubscriptionInfoInternal::getEnabledMobileDataPoliciesRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IMSI, + SubscriptionInfoInternal::getImsi), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED, + SubscriptionInfoInternal::areUiccApplicationsEnabledRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, + SubscriptionInfoInternal::isRcsUceEnabledRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, + SubscriptionInfoInternal::isCrossSimCallingEnabledRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_RCS_CONFIG, + SubscriptionInfoInternal::getRcsConfig), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, + SubscriptionInfoInternal::getAllowedNetworkTypesForReasons), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_D2D_STATUS_SHARING, + SubscriptionInfoInternal::getDeviceToDeviceStatusSharingPreference), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, + SubscriptionInfoInternal::isVoImsOptInEnabledRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + SubscriptionInfoInternal::getDeviceToDeviceStatusSharingContacts), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, + SubscriptionInfoInternal::isNrAdvancedCallingEnabledRaw), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER, + SubscriptionInfoInternal::getNumberFromCarrier), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS, + SubscriptionInfoInternal::getNumberFromIms), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PORT_INDEX, + SubscriptionInfoInternal::getPortIndex), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_USAGE_SETTING, + SubscriptionInfoInternal::getUsageSetting), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_TP_MESSAGE_REF, + SubscriptionInfoInternal::getLastUsedTPMessageReference), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_USER_HANDLE, + SubscriptionInfoInternal::getUserId) + ); + + /** + * The constructor. + * + * @param context The context. + * @param looper Looper for the handler. + */ + public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper) { + super(looper); + mContext = context; + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + mUiccController = UiccController.getInstance(); + loadFromDatabase(); + } + + /** + * Helper method to get specific field from {@link SubscriptionInfoInternal} by the database + * column name. {@link SubscriptionInfoInternal} represent one single record in the + * {@link SimInfo} table. So every column has a corresponding get method in + * {@link SubscriptionInfoInternal} (except for unused or deprecated columns). + * + * @param subInfo The subscription info. + * @param columnName The corresponding database column name. + * + * @return The corresponding value from {@link SubscriptionInfoInternal}. + */ + private Object getSubscriptionInfoFieldByColumnName(@NonNull SubscriptionInfoInternal subInfo, + @NonNull String columnName) { + if (SUBSCRIPTION_GET_METHOD_MAP.containsKey(columnName)) { + return SUBSCRIPTION_GET_METHOD_MAP.get(columnName).apply(subInfo); + } + return null; + } + + /** + * Comparing the old/new {@link SubscriptionInfoInternal} and create content values for database + * update. If any field in the new subscription info is different from the old one, then each + * delta will be added into the {@link ContentValues}. + * + * @param oldSubInfo The old {@link SubscriptionInfoInternal}. + * @param newSubInfo The new {@link SubscriptionInfoInternal}. + * + * @return The delta content values for database update. + */ + @NonNull + private ContentValues createDeltaContentValues(@Nullable SubscriptionInfoInternal oldSubInfo, + @NonNull SubscriptionInfoInternal newSubInfo) { + ContentValues deltaContentValues = new ContentValues(); + + for (String columnName : Telephony.SimInfo.getAllColumns()) { + Object newValue = getSubscriptionInfoFieldByColumnName(newSubInfo, columnName); + if (newValue != null) { + Object oldValue = null; + if (oldSubInfo != null) { + oldValue = getSubscriptionInfoFieldByColumnName(oldSubInfo, columnName); + } + // Some columns need special handling. We need to convert them into a format that + // is accepted by the database. + if (!Objects.equals(oldValue, newValue)) { + deltaContentValues.putObject(columnName, newValue); + } + } + } + return deltaContentValues; + } + + /** + * Synchronously insert a new record into the database. This operation is synchronous because + * we need to convert the inserted row index into the subscription id. + * + * @param contentValues The fields of the subscription to be inserted into the database. + * + * @return The row index of the new record. {@link #INVALID_ROW_INDEX} if insertion failed. + */ + private int insertNewRecordIntoDatabaseSync(@NonNull ContentValues contentValues) { + Objects.requireNonNull(contentValues); + Uri uri = mContext.getContentResolver().insert(SimInfo.CONTENT_URI, contentValues); + if (uri != null && uri.getLastPathSegment() != null) { + logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" + + uri.getLastPathSegment()); + return Integer.parseInt(uri.getLastPathSegment()); + } else { + loge("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " + + "contentValues=" + contentValues); + } + return INVALID_ROW_INDEX; + } + + /** + * Insert a new subscription info. The subscription info must have subscription id + * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}. Note this is a slow method, so be + * cautious to call this method. + * + * @param subInfo The subscription info to update. + * + * @return The new subscription id. {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} (-1) if + * insertion fails. + */ + public int insertSubscriptionInfo(@NonNull SubscriptionInfoInternal subInfo) { + Objects.requireNonNull(subInfo); + // A new subscription to be inserted must have invalid subscription id. + if (SubscriptionManager.isValidSubscriptionId(subInfo.getSubscriptionId())) { + throw new RuntimeException("insertSubscriptionInfo: Not a new subscription to " + + "insert. subInfo=" + subInfo); + } + + int subId; + // Grab the write lock so no other threads can read or write the cache. + mReadWriteLock.writeLock().lock(); + try { + // Synchronously insert into the database. Note this should be the only synchronous + // write operation performed by the subscription database manager. The reason is that + // we need to get the sub id for cache update. + subId = insertNewRecordIntoDatabaseSync(createDeltaContentValues(null, subInfo)); + if (subId > 0) { + mAllSubscriptionInfoInternalCache.put(subId, new SubscriptionInfoInternal + .Builder(subInfo) + .setId(subId).build()); + } else { + loge("insertSubscriptionInfo: Failed to insert a new subscription. subInfo=" + + subInfo); + } + } finally { + mReadWriteLock.writeLock().unlock(); + } + return subId; + } + + /** + * Update a subscription in database asynchronously. + * + * @param subId The subscription id of the subscription to be updated. + * @param contentValues The fields to be update. + */ + private void updateDatabaseAsync(int subId, @NonNull ContentValues contentValues) { + logv("updateDatabaseAsync: prepare to update sub " + subId); + // Perform the update in the handler thread asynchronously. + post(() -> { + int rowsUpdated = mContext.getContentResolver().update(Uri.withAppendedPath( + SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null); + if (rowsUpdated == 1) { + logv("updateDatabaseAsync: Successfully updated subscription in the database. " + + "subId=" + subId + ", contentValues= " + contentValues.getValues()); + } else { + loge("updateDatabaseAsync: Unexpected update result. rowsUpdated=" + rowsUpdated + + ", contentValues=" + contentValues); + } + }); + } + + /** + * Update a certain field of subscription in the database. Also update the subscription cache + * {@link #mAllSubscriptionInfoInternalCache}. + * + * @param subId The subscription id. + * @param columnName The database column name from the database table {@link SimInfo}. + * @param newValue The new value to update the subscription info cache + * {@link #mAllSubscriptionInfoInternalCache}. + * @param builderSetMethod The {@link SubscriptionInfo.Builder} method to set a specific field + * when constructing the new {@link SubscriptionInfo}. This should be one of the + * SubscriptionInfoInternal.Builder.setXxxx method. + * @param The type of newValue for subscription cache update. + */ + private void writeDatabaseAndCacheHelper(int subId, @NonNull String columnName, + @Nullable T newValue, + BiFunction + builderSetMethod) { + ContentValues contentValues = new ContentValues(); + SubscriptionInfoInternal subInfoCache; + + // Grab the write lock so no other threads can read or write the cache. + mReadWriteLock.writeLock().lock(); + try { + subInfoCache = mAllSubscriptionInfoInternalCache.get(subId); + if (subInfoCache != null) { + // Check if the new value is different from the old value in the cache. + if (!Objects.equals(getSubscriptionInfoFieldByColumnName(subInfoCache, columnName), + newValue)) { + // If the value is different, then we need to update the cache. Since all fields + // in SubscriptionInfo is final, so we need to create a new SubscriptionInfo. + SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal + .Builder(subInfoCache); + + // Apply the new value to the builder. This line is equivalent to + // builder.setXxxxxx(newValue); + builder = builderSetMethod.apply(builder, newValue); + + // Update the subscription database cache. + mAllSubscriptionInfoInternalCache.put(subId, builder.build()); + + // Prepare the content value for update. + contentValues.putObject(columnName, newValue); + // Writing into the database is slow. So do this asynchronously. + updateDatabaseAsync(subId, contentValues); + } + } else { + loge("Subscription doesn't exist. subId=" + subId); + } + } finally { + mReadWriteLock.writeLock().unlock(); + } + } + + /** + * Update the database with the {@link SubscriptionInfo}, and also update the cache. + * + * @param subInfo The new {@link SubscriptionInfo}. + */ + public void updateSubscription(@NonNull SubscriptionInfoInternal subInfo) { + Objects.requireNonNull(subInfo); + + // Grab the write lock so no other threads can read or write the cache. + mReadWriteLock.writeLock().lock(); + try { + int subId = subInfo.getSubscriptionId(); + SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get( + subInfo.getSubscriptionId()); + if (subInfoCache == null) { + throw new RuntimeException("updateSubscription: subscription does not exist. subId=" + + subId); + } + mAllSubscriptionInfoInternalCache.put(subId, subInfo); + // Writing into the database is slow. So do this asynchronously. + updateDatabaseAsync(subId, createDeltaContentValues(subInfoCache, subInfo)); + } finally { + mReadWriteLock.writeLock().unlock(); + } + } + + /** + * Set the ICCID of the SIM that is associated with the subscription. + * + * @param subId Subscription id. + * @param iccId The ICCID of the SIM that is associated with this subscription. + */ + public void setIccId(int subId, @NonNull String iccId) { + Objects.requireNonNull(iccId); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ICC_ID, iccId, + SubscriptionInfoInternal.Builder::setIccId); + } + + /** + * Set the SIM index of the slot that currently contains the subscription. Set to + * {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX} if the subscription is inactive. + * + * @param subId Subscription id. + * @param simSlotIndex The SIM slot index. + */ + public void setSimSlotIndex(int subId, int simSlotIndex) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SIM_SLOT_INDEX, simSlotIndex, + SubscriptionInfoInternal.Builder::setSimSlotIndex); + } + + /** + * Set the name displayed to the user that identifies this subscription. This name is used + * in Settings page and can be renamed by the user. + * + * @param subId Subscription id. + * @param displayName The display name. + */ + public void setDisplayName(int subId, @NonNull String displayName) { + Objects.requireNonNull(displayName); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_DISPLAY_NAME, displayName, + SubscriptionInfoInternal.Builder::setDisplayName); + } + + /** + * Set the name displayed to the user that identifies subscription provider name. This name + * is the SPN displayed in status bar and many other places. Can't be renamed by the user. + * + * @param subId Subscription id. + * @param carrierName The carrier name. + */ + public void setCarrierName(int subId, @NonNull String carrierName) { + Objects.requireNonNull(carrierName); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CARRIER_NAME, carrierName, + SubscriptionInfoInternal.Builder::setCarrierName); + } + + /** + * Set the source of the display name. + * + * @param subId Subscription id. + * @param displayNameSource The source of the display name. + * + * @see SubscriptionInfo#getDisplayName() + */ + public void setDisplayNameSource(int subId, @SimDisplayNameSource int displayNameSource) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NAME_SOURCE, displayNameSource, + SubscriptionInfoInternal.Builder::setDisplayNameSource); + } + + /** + * Set the color to be used for tinting the icon when displaying to the user. + * + * @param subId Subscription id. + * @param iconTint The color to be used for tinting the icon when displaying to the user. + */ + public void setIconTint(int subId, int iconTint) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_COLOR, iconTint, + SubscriptionInfoInternal.Builder::setIconTint); + } + + /** + * Set the number presented to the user identify this subscription. + * + * @param subId Subscription id. + * @param number the number presented to the user identify this subscription. + */ + public void setNumber(int subId, @NonNull String number) { + Objects.requireNonNull(number); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NUMBER, number, + SubscriptionInfoInternal.Builder::setNumber); + } + + /** + * Set whether user enables data roaming for this subscription or not. + * + * @param subId Subscription id. + * @param dataRoaming Data roaming mode. Either + * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or + * {@link SubscriptionManager#DATA_ROAMING_DISABLE} + */ + public void setDataRoaming(int subId, int dataRoaming) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_DATA_ROAMING, dataRoaming, + SubscriptionInfoInternal.Builder::setDataRoaming); + } + + /** + * Set the mobile country code. + * + * @param subId Subscription id. + * @param mcc The mobile country code. + */ + public void setMcc(int subId, @NonNull String mcc) { + Objects.requireNonNull(mcc); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_MCC_STRING, mcc, + SubscriptionInfoInternal.Builder::setMcc); + } + + /** + * Set the mobile network code. + * + * @param subId Subscription id. + * @param mnc Mobile network code. + */ + public void setMnc(int subId, @NonNull String mnc) { + Objects.requireNonNull(mnc); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_MNC_STRING, mnc, + SubscriptionInfoInternal.Builder::setMnc); + } + + /** + * Set EHPLMNs associated with the subscription. + * + * @param subId Subscription id. + * @param ehplmns EHPLMNs associated with the subscription. + */ + public void setEhplmns(int subId, @NonNull String[] ehplmns) { + Objects.requireNonNull(ehplmns); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_EHPLMNS, TextUtils.join(",", ehplmns), + SubscriptionInfoInternal.Builder::setEhplmns); + } + + /** + * Set HPLMNs associated with the subscription. + * + * @param subId Subscription id. + * @param hplmns HPLMNs associated with the subscription. + */ + public void setHplmns(int subId, @NonNull String[] hplmns) { + Objects.requireNonNull(hplmns); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_HPLMNS, TextUtils.join(",", hplmns), + SubscriptionInfoInternal.Builder::setHplmns); + } + + /** + * Set whether the subscription is from eSIM or not. + * + * @param subId Subscription id. + * @param isEmbedded {@code true} if the subscription is from eSIM. + */ + public void setEmbedded(int subId, boolean isEmbedded) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_EMBEDDED, isEmbedded ? 1 : 0, + SubscriptionInfoInternal.Builder::setEmbedded); + } + + /** + * Set the card string of the SIM card. This is usually the ICCID or EID. + * + * @param subId Subscription id. + * @param cardString The card string of the SIM card. + * + * @see SubscriptionInfo#getCardString() + */ + public void setCardString(int subId, @NonNull String cardString) { + Objects.requireNonNull(cardString); + // Also update the public card id. + setCardId(subId, mUiccController.convertToPublicCardId(cardString)); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CARD_ID, cardString, + SubscriptionInfoInternal.Builder::setCardString); + } + + /** + * Set the card id. This is the non-PII card id converted from + * {@link SubscriptionInfoInternal#getCardString()}. This field only exists in + * {@link SubscriptionInfo}, but not the database. + * + * @param subId Subscription id. + * @param cardId The card id. + */ + public void setCardId(int subId, int cardId) { + // card id does not have a corresponding SimInfo column. So we only update the cache. + + // Grab the write lock so no other threads can read or write the cache. + mReadWriteLock.writeLock().lock(); + try { + SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get(subId); + mAllSubscriptionInfoInternalCache.put(subId, + new SubscriptionInfoInternal.Builder(subInfoCache) + .setCardId(cardId).build()); + } finally { + mReadWriteLock.writeLock().unlock(); + } + } + + /** + * Set the native access rules for this subscription, if it is embedded and defines any. + * This does not include access rules for non-embedded subscriptions. + * + * @param subId Subscription id. + * @param nativeAccessRules The native access rules for this subscription. + */ + public void setNativeAccessRules(int subId, @NonNull UiccAccessRule[] nativeAccessRules) { + Objects.requireNonNull(nativeAccessRules); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES, + UiccAccessRule.encodeRules(nativeAccessRules), + SubscriptionInfoInternal.Builder::setNativeAccessRules); + } + + /** + * Set the carrier certificates for this subscription that are saved in carrier configs. + * This does not include access rules from the Uicc, whether embedded or non-embedded. + * + * @param subId Subscription id. + * @param carrierConfigAccessRules The carrier certificates for this subscription. + */ + public void setCarrierConfigAccessRules(int subId, + @NonNull UiccAccessRule[] carrierConfigAccessRules) { + Objects.requireNonNull(carrierConfigAccessRules); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, + UiccAccessRule.encodeRules(carrierConfigAccessRules), + SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules); + } + + /** + * Set whether an embedded subscription is on a removable card. Such subscriptions are + * marked inaccessible as soon as the current card is removed. Otherwise, they will remain + * accessible unless explicitly deleted. Only meaningful when for embedded subscription. + * + * @param subId Subscription id. + * @param isRemovableEmbedded {@code true} if the subscription is from the removable + * embedded SIM. + */ + public void setRemovableEmbedded(int subId, boolean isRemovableEmbedded) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_REMOVABLE, isRemovableEmbedded ? 1 : 0, + SubscriptionInfoInternal.Builder::setRemovableEmbedded); + } + + /** + * Set whether enhanced 4G mode is enabled by the user or not. + * + * @param subId Subscription id. + * @param isEnhanced4GModeEnabled whether enhanced 4G mode is enabled by the user or not. + */ + public void setEnhanced4GModeEnabled(int subId, boolean isEnhanced4GModeEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, + isEnhanced4GModeEnabled ? 1 : 0, + SubscriptionInfoInternal.Builder::setEnhanced4GModeEnabled); + } + + /** + * Set whether video telephony is enabled by the user or not. + * + * @param subId Subscription id. + * @param isVideoTelephonyEnabled whether video telephony is enabled by the user or not. + */ + public void setVideoTelephonyEnabled(int subId, boolean isVideoTelephonyEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VT_IMS_ENABLED, + isVideoTelephonyEnabled ? 1 : 0, + SubscriptionInfoInternal.Builder::setVideoTelephonyEnabled); + } + + /** + * Set whether Wi-Fi calling is enabled by the user or not when the device is not roaming. + * + * @param subId Subscription id. + * @param isWifiCallingEnabled whether Wi-Fi calling is enabled by the user or not when the + * device is not roaming. + */ + public void setWifiCallingEnabled(int subId, boolean isWifiCallingEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ENABLED, + isWifiCallingEnabled ? 1 : 0, + SubscriptionInfoInternal.Builder::setWifiCallingEnabled); + } + + /** + * Set Wi-Fi calling mode when the device is not roaming. + * + * @param subId Subscription id. + * @param wifiCallingMode Wi-Fi calling mode when the device is not roaming. + */ + public void setWifiCallingMode(int subId, + @ImsMmTelManager.WiFiCallingMode int wifiCallingMode) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_MODE, wifiCallingMode, + SubscriptionInfoInternal.Builder::setWifiCallingMode); + } + + /** + * Set Wi-Fi calling mode when the device is roaming. + * + * @param subId Subscription id. + * @param wifiCallingModeForRoaming Wi-Fi calling mode when the device is roaming. + */ + public void setWifiCallingModeForRoaming(int subId, + @ImsMmTelManager.WiFiCallingMode int wifiCallingModeForRoaming) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, + wifiCallingModeForRoaming, + SubscriptionInfoInternal.Builder::setWifiCallingModeForRoaming); + } + + /** + * Set whether Wi-Fi calling is enabled by the user or not when the device is roaming. + * + * @param subId Subscription id. + * @param isWifiCallingEnabledForRoaming whether Wi-Fi calling is enabled by the user or not + * when the device is roaming. + */ + public void setWifiCallingEnabledForRoaming(int subId, boolean isWifiCallingEnabledForRoaming) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, + isWifiCallingEnabledForRoaming ? 1 : 0, + SubscriptionInfoInternal.Builder::setWifiCallingEnabledForRoaming); + } + + /** + * Set whether the subscription is opportunistic or not. + * + * @param subId Subscription id. + * @param isOpportunistic {@code true} if the subscription is opportunistic. + */ + public void setOpportunistic(int subId, boolean isOpportunistic) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_OPPORTUNISTIC, isOpportunistic ? 1 : 0, + SubscriptionInfoInternal.Builder::setOpportunistic); + } + + /** + * Set the group UUID of the subscription group. + * + * @param subId Subscription id. + * @param groupUuid The group UUID. + * + * @see SubscriptionInfo#getGroupUuid() + */ + public void setGroupUuid(int subId, @NonNull String groupUuid) { + Objects.requireNonNull(groupUuid); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_GROUP_UUID, groupUuid, + SubscriptionInfoInternal.Builder::setGroupUuid); + } + + /** + * Set the ISO Country code for the subscription's provider. + * + * @param subId Subscription id. + * @param countryIso The ISO country code for the subscription's provider. + */ + public void setCountryIso(int subId, @NonNull String countryIso) { + Objects.requireNonNull(countryIso); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ISO_COUNTRY_CODE, countryIso, + SubscriptionInfoInternal.Builder::setCountryIso); + } + + /** + * Set the subscription carrier id. + * + * @param subId Subscription id. + * @param carrierId The carrier id. + * + * @see TelephonyManager#getSimCarrierId() + */ + public void setCarrierId(int subId, int carrierId) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CARRIER_ID, carrierId, + SubscriptionInfoInternal.Builder::setCarrierId); + } + + /** + * Set the profile class populated from the profile metadata if present. + * + * @param subId Subscription id. + * @param profileClass the profile class populated from the profile metadata if present. + * + * @see SubscriptionInfo#getProfileClass() + */ + public void setProfileClass(int subId, @ProfileClass int profileClass) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PROFILE_CLASS, profileClass, + SubscriptionInfoInternal.Builder::setProfileClass); + } + + /** + * Set the subscription type. + * + * @param subId Subscription id. + * @param type Subscription type. + */ + public void setSubscriptionType(int subId, @SubscriptionType int type) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SUBSCRIPTION_TYPE, type, + SubscriptionInfoInternal.Builder::setType); + } + + /** + * Set the owner package of group the subscription belongs to. + * + * @param subId Subscription id. + * @param groupOwner Owner package of group the subscription belongs to. + */ + public void setGroupOwner(int subId, @NonNull String groupOwner) { + Objects.requireNonNull(groupOwner); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_GROUP_OWNER, groupOwner, + SubscriptionInfoInternal.Builder::setGroupOwner); + } + + /** + * Set the enabled mobile data policies. + * + * @param subId Subscription id. + * @param enabledMobileDataPolicies The enabled mobile data policies. + */ + public void setEnabledMobileDataPolicies(int subId, @NonNull String enabledMobileDataPolicies) { + Objects.requireNonNull(enabledMobileDataPolicies); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, + enabledMobileDataPolicies, + SubscriptionInfoInternal.Builder::setEnabledMobileDataPolicies); + } + + /** + * Set the IMSI (International Mobile Subscriber Identity) of the subscription. + * + * @param subId Subscription id. + * @param imsi The IMSI. + */ + public void setImsi(int subId, @NonNull String imsi) { + Objects.requireNonNull(imsi); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IMSI, imsi, + SubscriptionInfoInternal.Builder::setImsi); + } + + /** + * Set whether Uicc applications are configured to enable or not. + * + * @param subId Subscription id. + * @param areUiccApplicationsEnabled {@code true} if Uicc applications are configured to + * enable. + */ + public void setUiccApplicationsEnabled(int subId, boolean areUiccApplicationsEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED, + areUiccApplicationsEnabled ? 1 : 0, + SubscriptionInfoInternal.Builder::setUiccApplicationsEnabled); + } + + /** + * Set whether the user has enabled IMS RCS User Capability Exchange (UCE) for this + * subscription. + * + * @param subId Subscription id. + * @param isRcsUceEnabled If the user enabled RCS UCE for this subscription. + */ + public void setRcsUceEnabled(int subId, boolean isRcsUceEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, + isRcsUceEnabled ? 1 : 0, SubscriptionInfoInternal.Builder::setRcsUceEnabled); + } + + /** + * Set whether the user has enabled cross SIM calling for this subscription. + * + * @param subId Subscription id. + * @param isCrossSimCallingEnabled If the user enabled cross SIM calling for this + * subscription. + */ + public void setCrossSimCallingEnabled(int subId, boolean isCrossSimCallingEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, + isCrossSimCallingEnabled ? 1 : 0, + SubscriptionInfoInternal.Builder::setCrossSimCallingEnabled); + } + + /** + * Set the RCS config for this subscription. + * + * @param subId Subscription id. + * @param rcsConfig The RCS config for this subscription. + */ + public void setRcsConfig(int subId, @NonNull byte[] rcsConfig) { + Objects.requireNonNull(rcsConfig); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_RCS_CONFIG, rcsConfig, + SubscriptionInfoInternal.Builder::setRcsConfig); + } + + /** + * Set the allowed network types for reasons. + * + * @param subId Subscription id. + * @param allowedNetworkTypesForReasons The allowed network types for reasons in string + * format. The format is + * "[reason]=[network types bitmask], [reason]=[network types bitmask], ..." + * + * For example, "user=1239287394, thermal=298791239, carrier=3456812312". + * + */ + public void setAllowedNetworkTypesForReasons(int subId, + @NonNull String allowedNetworkTypesForReasons) { + Objects.requireNonNull(allowedNetworkTypesForReasons); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, + allowedNetworkTypesForReasons, + SubscriptionInfoInternal.Builder::setAllowedNetworkTypesForReasons); + } + + /** + * Set device to device sharing status. + * + * @param subId Subscription id. + * @param deviceToDeviceStatusSharingPreference Device to device sharing status. + */ + public void setDeviceToDeviceStatusSharingPreference(int subId, + @DeviceToDeviceStatusSharingPreference int deviceToDeviceStatusSharingPreference) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_D2D_STATUS_SHARING, + deviceToDeviceStatusSharingPreference, + SubscriptionInfoInternal.Builder::setDeviceToDeviceStatusSharingPreference); + } + + /** + * Set whether the user has opted-in voice over IMS. + * + * @param subId Subscription id. + * @param isVoImsOptInEnabled Whether the user has opted-in voice over IMS. + */ + public void setVoImsOptInEnabled(int subId, boolean isVoImsOptInEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, + isVoImsOptInEnabled ? 1 : 0, + SubscriptionInfoInternal.Builder::setVoImsOptInEnabled); + } + + /** + * Set contacts information that allow device to device sharing. + * + * @param subId Subscription id. + * @param deviceToDeviceStatusSharingContacts contacts information that allow device to + * device sharing. + */ + public void setDeviceToDeviceStatusSharingContacts(int subId, + @NonNull String deviceToDeviceStatusSharingContacts) { + Objects.requireNonNull(deviceToDeviceStatusSharingContacts); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + deviceToDeviceStatusSharingContacts, + SubscriptionInfoInternal.Builder::setDeviceToDeviceStatusSharingContacts); + } + + /** + * Set whether the user has enabled NR advanced calling. + * + * @param subId Subscription id. + * @param isNrAdvancedCallingEnabled Whether the user has enabled NR advanced calling. + */ + public void setNrAdvancedCallingEnabled(int subId, boolean isNrAdvancedCallingEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, + isNrAdvancedCallingEnabled ? 1 : 0, + SubscriptionInfoInternal.Builder::setNrAdvancedCallingEnabled); + } + + /** + * Set the phone number retrieved from carrier. + * + * @param subId Subscription id. + * @param numberFromCarrier The phone number retrieved from carrier. + */ + public void setNumberFromCarrier(int subId, @NonNull String numberFromCarrier) { + Objects.requireNonNull(numberFromCarrier); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER, + numberFromCarrier, SubscriptionInfoInternal.Builder::setNumberFromCarrier); + } + + /** + * Set the phone number retrieved from IMS. + * + * @param subId Subscription id. + * @param numberFromIms The phone number retrieved from IMS. + */ + public void setNumberFromIms(int subId, @NonNull String numberFromIms) { + Objects.requireNonNull(numberFromIms); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS, + numberFromIms, SubscriptionInfoInternal.Builder::setNumberFromIms); + } + + /** + * Set the port index of the Uicc card. + * + * @param subId Subscription id. + * @param portIndex The port index of the Uicc card. + */ + public void setPortIndex(int subId, int portIndex) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PORT_INDEX, portIndex, + SubscriptionInfoInternal.Builder::setPortIndex); + } + + /** + * Set subscription's preferred usage setting. + * + * @param subId Subscription id. + * @param usageSetting Subscription's preferred usage setting. + */ + public void setUsageSetting(int subId, @UsageSetting int usageSetting) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_USAGE_SETTING, usageSetting, + SubscriptionInfoInternal.Builder::setUsageSetting); + } + + /** + * Set last used TP message reference. + * + * @param subId Subscription id. + * @param lastUsedTPMessageReference Last used TP message reference. + */ + public void setLastUsedTPMessageReference(int subId, int lastUsedTPMessageReference) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_TP_MESSAGE_REF, + lastUsedTPMessageReference, + SubscriptionInfoInternal.Builder::setLastUsedTPMessageReference); + } + + /** + * Set the user id associated with this subscription. + * + * @param subId Subscription id. + * @param userId The user id associated with this subscription. + */ + public void setUserId(int subId, int userId) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_USER_HANDLE, userId, + SubscriptionInfoInternal.Builder::setUserId); + } + + /** + * Load the entire database into the cache. + */ + private void loadFromDatabase() { + // Perform the task in the handler thread. + post(() -> { + try (Cursor cursor = mContext.getContentResolver().query( + SimInfo.CONTENT_URI, null, null, null, null)) { + mReadWriteLock.writeLock().lock(); + try { + mAllSubscriptionInfoInternalCache.clear(); + while (cursor != null && cursor.moveToNext()) { + SubscriptionInfoInternal subInfo = createSubscriptionInfoFromCursor(cursor); + if (subInfo != null) { + mAllSubscriptionInfoInternalCache + .put(subInfo.getSubscriptionId(), subInfo); + } + } + log("Loaded " + mAllSubscriptionInfoInternalCache.size() + + " records from the subscription database."); + } finally { + mReadWriteLock.writeLock().unlock(); + } + } + }); + } + + /** + * Build the {@link SubscriptionInfoInternal} from database. + * + * @param cursor The cursor of the database. + * + * @return The subscription info from a single database record. + */ + @Nullable + private SubscriptionInfoInternal createSubscriptionInfoFromCursor(@NonNull Cursor cursor) { + SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal.Builder(); + int id = cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID)); + builder.setId(id) + .setIccId(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ICC_ID)))) + .setSimSlotIndex(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_SIM_SLOT_INDEX))) + .setDisplayName(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_DISPLAY_NAME)))) + .setCarrierName(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CARRIER_NAME)))) + .setDisplayNameSource(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_NAME_SOURCE))) + .setIconTint(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_COLOR))) + .setNumber(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_NUMBER)))) + .setDataRoaming(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_DATA_ROAMING))) + .setMcc(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_MCC_STRING)))) + .setMnc(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_MNC_STRING)))) + .setEhplmns(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_EHPLMNS)))) + .setHplmns(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_HPLMNS)))) + .setEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_IS_EMBEDDED))); + + String cardString = TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CARD_ID))); + builder.setCardString(cardString); + // publicCardId is the publicly exposed int card ID + int publicCardId = mUiccController.convertToPublicCardId(cardString); + + builder.setCardId(publicCardId) + .setNativeAccessRules(cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ACCESS_RULES))) + .setCarrierConfigAccessRules(cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS))) + .setRemovableEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_IS_REMOVABLE))) + .setEnhanced4GModeEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED))) + .setVideoTelephonyEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_VT_IMS_ENABLED))) + .setWifiCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_WFC_IMS_ENABLED))) + .setWifiCallingMode(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_WFC_IMS_MODE))) + .setWifiCallingModeForRoaming(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE))) + .setWifiCallingEnabledForRoaming(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED))) + .setOpportunistic(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_IS_OPPORTUNISTIC))) + .setGroupUuid(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_GROUP_UUID)))) + .setCountryIso(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ISO_COUNTRY_CODE)))) + .setCarrierId(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CARRIER_ID))) + .setProfileClass(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_PROFILE_CLASS))) + .setType(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_SUBSCRIPTION_TYPE))) + .setGroupOwner(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_GROUP_OWNER)))) + .setEnabledMobileDataPolicies(TextUtils.emptyIfNull( + cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES)))) + .setImsi(TextUtils.emptyIfNull(cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_IMSI)))) + .setUiccApplicationsEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED))) + .setRcsUceEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED))) + .setCrossSimCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED))) + .setRcsConfig(cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_RCS_CONFIG))) + .setAllowedNetworkTypesForReasons(TextUtils.emptyIfNull( + cursor.getString(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS)))) + .setDeviceToDeviceStatusSharingPreference(cursor.getInt( + cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_D2D_STATUS_SHARING))) + .setVoImsOptInEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS))) + .setDeviceToDeviceStatusSharingContacts(TextUtils.emptyIfNull(cursor.getString( + cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS)))) + .setNrAdvancedCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED))) + .setNumberFromCarrier(TextUtils.emptyIfNull(cursor.getString( + cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER)))) + .setNumberFromIms(TextUtils.emptyIfNull(cursor.getString( + cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS)))) + .setPortIndex(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_PORT_INDEX))) + .setUsageSetting(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_USAGE_SETTING))) + .setLastUsedTPMessageReference(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_TP_MESSAGE_REF))) + .setUserId(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_USER_HANDLE))); + + return builder.build(); + } + + /** + * Get the subscription info by subscription id. + * + * @param subId The subscription id + * + * @return The subscription info. {@code null} if not found. + */ + @Nullable + public SubscriptionInfoInternal getSubscriptionInfoInternal(int subId) { + mReadWriteLock.readLock().lock(); + try { + return mAllSubscriptionInfoInternalCache.get(subId); + } finally { + mReadWriteLock.readLock().unlock(); + } + } + + /** + * Log debug messages. + * + * @param s debug messages + */ + private void log(@NonNull String s) { + Rlog.d(LOG_TAG, s); + } + + /** + * Log error messages. + * + * @param s error messages + */ + private void loge(@NonNull String s) { + Rlog.e(LOG_TAG, s); + } + + /** + * Log verbose messages. + * + * @param s debug messages. + */ + private void logv(@NonNull String s) { + if (VDBG) Rlog.v(LOG_TAG, s); + } + + /** + * 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 {@link SubscriptionManagerService}. + * + * @param fd File descriptor + * @param printWriter Print writer + * @param args Arguments + */ + public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter printWriter, + @NonNull String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.println(SubscriptionManagerService.class.getSimpleName() + ":"); + pw.increaseIndent(); + pw.println("All subscriptions:"); + pw.increaseIndent(); + mAllSubscriptionInfoInternalCache.forEach((subId, subInfo) -> pw.println(subInfo)); + pw.decreaseIndent(); + pw.decreaseIndent(); + } +} diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java new file mode 100644 index 0000000000..ae0c1d1347 --- /dev/null +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -0,0 +1,2166 @@ +/* + * Copyright (C) 2022 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. + */ +/* + * Copyright (C) 2022 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.subscription; + +import android.annotation.NonNull; +import android.os.UserHandle; +import android.provider.Telephony.SimInfo; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionManager.DeviceToDeviceStatusSharingPreference; +import android.telephony.SubscriptionManager.ProfileClass; +import android.telephony.SubscriptionManager.SimDisplayNameSource; +import android.telephony.SubscriptionManager.SubscriptionType; +import android.telephony.SubscriptionManager.UsageSetting; +import android.telephony.TelephonyManager; +import android.telephony.ims.ImsMmTelManager; + +import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.util.TelephonyUtils; +import com.android.telephony.Rlog; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +/** + * The class represents a single row of {@link SimInfo} table. All columns (excepts unused columns) + * in the database have a corresponding field in this class. + * + * The difference between {@link SubscriptionInfo} and this class is that {@link SubscriptionInfo} + * is a subset of this class. This is intended to solve the problem that some database fields + * required higher permission like + * {@link android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE} to access while + * {@link SubscriptionManager#getActiveSubscriptionIdList()} only requires + * {@link android.Manifest.permission.READ_PHONE_STATE} to access. Sometimes blanking out fields in + * {@link SubscriptionInfo} creates ambiguity for clients hard to distinguish between insufficient + * permission versus true failure. + * + * Also the fields in this class match the format used in database. For example, boolean values + * are stored as integer, or string arrays are stored as a single comma separated string. + */ +public class SubscriptionInfoInternal { + /** + * Subscription Identifier, this is a device unique number + * and not an index into an array + */ + private final int mId; + + /** + * The ICCID of the SIM that is associated with this subscription, empty if unknown. + */ + @NonNull + private final String mIccId; + + /** + * The index of the SIM slot that currently contains the subscription and not necessarily unique + * and maybe {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX} if unknown or the subscription + * is inactive. + */ + private final int mSimSlotIndex; + + /** + * The name displayed to the user that identifies this subscription. This name is used + * in Settings page and can be renamed by the user. + */ + @NonNull + private final String mDisplayName; + + /** + * The name displayed to the user that identifies subscription provider name. This name is the + * SPN displayed in status bar and many other places. Can't be renamed by the user. + */ + @NonNull + private final String mCarrierName; + + /** + * The source of the {@link #mDisplayName}. + */ + @SimDisplayNameSource + private final int mDisplayNameSource; + + /** + * The color to be used for tinting the icon when displaying to the user. + */ + private final int mIconTint; + + /** + * The number presented to the user identify this subscription. + */ + @NonNull + private final String mNumber; + + /** + * Whether user enables data roaming for this subscription or not. Either + * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or + * {@link SubscriptionManager#DATA_ROAMING_DISABLE}. + */ + private final int mDataRoaming; + + /** + * Mobile Country Code. + */ + @NonNull + private final String mMcc; + + /** + * Mobile Network Code. + */ + @NonNull + private final String mMnc; + + /** + * EHPLMNs associated with the subscription. + */ + @NonNull + private final String mEhplmns; + + /** + * HPLMNs associated with the subscription. + */ + @NonNull + private final String mHplmns; + + /** + * Whether the subscription is from eSIM. It is intended to use integer to fit the database + * format. + */ + private final int mIsEmbedded; + + /** + * The string ID of the SIM card. It is the ICCID of the active profile for a UICC card and the + * EID for an eUICC card. + */ + @NonNull + private final String mCardString; + + /** + * The access rules for this subscription, if it is embedded and defines any. This does not + * include access rules for non-embedded subscriptions. + */ + @NonNull + private final byte[] mNativeAccessRules; + + /** + * The carrier certificates for this subscription that are saved in carrier configs. + * This does not include access rules from the Uicc, whether embedded or non-embedded. + */ + @NonNull + private final byte[] mCarrierConfigAccessRules; + + /** + * Whether an embedded subscription is on a removable card. Such subscriptions are marked + * inaccessible as soon as the current card is removed. Otherwise, they will remain accessible + * unless explicitly deleted. Only meaningful when {@link #isEmbedded()} is {@code true}. It + * is intended to use integer to fit the database format. + */ + private final int mIsRemovableEmbedded; + + /** + * Whether enhanced 4G mode is enabled by the user or not. It is intended to use integer to fit + * the database format. + */ + private final int mIsEnhanced4GModeEnabled; + + /** + * Whether video telephony is enabled by the user or not. It is intended to use integer to fit + * the database format. + */ + private final int mIsVideoTelephonyEnabled; + + /** + * Whether Wi-Fi calling is enabled by the user or not when the device is not roaming. It is + * intended to use integer to fit the database format. + */ + private final int mIsWifiCallingEnabled; + + /** + * Wi-Fi calling mode when the device is not roaming. + */ + @ImsMmTelManager.WiFiCallingMode + private final int mWifiCallingMode; + + /** + * Wi-Fi calling mode when the device is roaming. + */ + @ImsMmTelManager.WiFiCallingMode + private final int mWifiCallingModeForRoaming; + + /** + * Whether Wi-Fi calling is enabled by the user or not when the device is roaming. It is + * intended to use integer to fit the database format. + */ + private final int mIsWifiCallingEnabledForRoaming; + + /** + * Whether the subscription is opportunistic. It is intended to use integer to fit the database + * format. + */ + private final int mIsOpportunistic; + + /** + * A UUID assigned to the subscription group in string format. + * + * @see SubscriptionManager#createSubscriptionGroup(List) + */ + @NonNull + private final String mGroupUuid; + + /** + * ISO Country code for the subscription's provider. + */ + @NonNull + private final String mCountryIso; + + /** + * The subscription carrier id. + * + * @see TelephonyManager#getSimCarrierId() + */ + private final int mCarrierId; + + /** + * The profile class populated from the profile metadata if present. Otherwise, + * the profile class defaults to {@link SubscriptionManager#PROFILE_CLASS_UNSET} if there is no + * profile metadata or the subscription is not on an eUICC ({@link #isEmbedded} returns + * {@code false}). + */ + @ProfileClass + private final int mProfileClass; + + /** + * Type of the subscription. + */ + @SubscriptionType + private final int mType; + + /** + * A package name that specifies who created the group. Empty if not available. + */ + @NonNull + private final String mGroupOwner; + + /** + * The enabled mobile data policies in string format. + */ + @NonNull + private final String mEnabledMobileDataPolicies; + + /** + * The IMSI (International Mobile Subscriber Identity) of the subscription. + */ + @NonNull + private final String mImsi; + + /** + * Whether uicc applications are configured to enable or disable. + * By default it's true. It is intended to use integer to fit the database format. + */ + private final int mAreUiccApplicationsEnabled; + + /** + * Whether the user has enabled IMS RCS User Capability Exchange (UCE) for this subscription. + * It is intended to use integer to fit the database format. + */ + private final int mIsRcsUceEnabled; + + /** + * Whether the user has enabled cross SIM calling for this subscription. It is intended to + * use integer to fit the database format. + */ + private final int mIsCrossSimCallingEnabled; + + /** + * The RCS configuration. + */ + @NonNull + private final byte[] mRcsConfig; + + /** + * The allowed network types for reasons in string format. The format is + * "[reason]=[network types bitmask], [reason]=[network types bitmask], ..." + * + * For example, "user=1239287394, thermal=298791239, carrier=3456812312". + */ + @NonNull + private final String mAllowedNetworkTypesForReasons; + + /** + * Device to device sharing status. + */ + @DeviceToDeviceStatusSharingPreference + private final int mDeviceToDeviceStatusSharingPreference; + + /** + * Whether the user has opted-in voice over IMS. It is intended to use integer to fit the + * database format. + */ + private final int mIsVoImsOptInEnabled; + + /** + * Contacts information that allow device to device sharing. + */ + @NonNull + private final String mDeviceToDeviceStatusSharingContacts; + + /** + * Whether the user has enabled NR advanced calling. It is intended to use integer to fit the + * database format. + */ + private final int mIsNrAdvancedCallingEnabled; + + /** + * The phone number retrieved from carrier. + */ + @NonNull + private final String mNumberFromCarrier; + + /** + * The phone number retrieved from IMS. + */ + @NonNull + private final String mNumberFromIms; + + /** + * The port index of the Uicc card. + */ + private final int mPortIndex; + + /** + * Subscription's preferred usage setting. + */ + @UsageSetting + private final int mUsageSetting; + + /** + * Last used TP message reference. + */ + private final int mLastUsedTPMessageReference; + + /** + * The user id associated with this subscription. + */ + private final int mUserId; + + // Below are the fields that do not exist in the SimInfo table. + /** + * The card ID of the SIM card. This maps uniquely to {@link #mCardString}. + */ + private final int mCardId; + + /** + * Whether group of the subscription is disabled. This is only useful if it's a grouped + * opportunistic subscription. In this case, if all primary (non-opportunistic) subscriptions + * in the group are deactivated (unplugged pSIM or deactivated eSIM profile), we should disable + * this opportunistic subscription. It is intended to use integer to fit the database format. + */ + private final boolean mIsGroupDisabled; + + /** + * Constructor from builder. + * + * @param builder Builder of {@link SubscriptionInfoInternal}. + */ + private SubscriptionInfoInternal(@NonNull Builder builder) { + this.mId = builder.mId; + this.mIccId = builder.mIccId; + this.mSimSlotIndex = builder.mSimSlotIndex; + this.mDisplayName = builder.mDisplayName; + this.mCarrierName = builder.mCarrierName; + this.mDisplayNameSource = builder.mDisplayNameSource; + this.mIconTint = builder.mIconTint; + this.mNumber = builder.mNumber; + this.mDataRoaming = builder.mDataRoaming; + this.mMcc = builder.mMcc; + this.mMnc = builder.mMnc; + this.mEhplmns = builder.mEhplmns; + this.mHplmns = builder.mHplmns; + this.mIsEmbedded = builder.mIsEmbedded; + this.mCardString = builder.mCardString; + this.mNativeAccessRules = builder.mNativeAccessRules; + this.mCarrierConfigAccessRules = builder.mCarrierConfigAccessRules; + this.mIsRemovableEmbedded = builder.mIsRemovableEmbedded; + this.mIsEnhanced4GModeEnabled = builder.mIsEnhanced4GModeEnabled; + this.mIsVideoTelephonyEnabled = builder.mIsVideoTelephonyEnabled; + this.mIsWifiCallingEnabled = builder.mIsWifiCallingEnabled; + this.mWifiCallingMode = builder.mWifiCallingMode; + this.mWifiCallingModeForRoaming = builder.mWifiCallingModeForRoaming; + this.mIsWifiCallingEnabledForRoaming = builder.mIsWifiCallingEnabledForRoaming; + this.mIsOpportunistic = builder.mIsOpportunistic; + this.mGroupUuid = builder.mGroupUuid; + this.mCountryIso = builder.mCountryIso; + this.mCarrierId = builder.mCarrierId; + this.mProfileClass = builder.mProfileClass; + this.mType = builder.mType; + this.mGroupOwner = builder.mGroupOwner; + this.mEnabledMobileDataPolicies = builder.mEnabledMobileDataPolicies; + this.mImsi = builder.mImsi; + this.mAreUiccApplicationsEnabled = builder.mAreUiccApplicationsEnabled; + this.mIsRcsUceEnabled = builder.mIsRcsUceEnabled; + this.mIsCrossSimCallingEnabled = builder.mIsCrossSimCallingEnabled; + this.mRcsConfig = builder.mRcsConfig; + this.mAllowedNetworkTypesForReasons = builder.mAllowedNetworkTypesForReasons; + this.mDeviceToDeviceStatusSharingPreference = + builder.mDeviceToDeviceStatusSharingPreference; + this.mIsVoImsOptInEnabled = builder.mIsVoImsOptInEnabled; + this.mDeviceToDeviceStatusSharingContacts = builder.mDeviceToDeviceStatusSharingContacts; + this.mIsNrAdvancedCallingEnabled = builder.mIsNrAdvancedCallingEnabled; + this.mNumberFromCarrier = builder.mNumberFromCarrier; + this.mNumberFromIms = builder.mNumberFromIms; + this.mPortIndex = builder.mPortIndex; + this.mUsageSetting = builder.mUsageSetting; + this.mLastUsedTPMessageReference = builder.mLastUsedTPMessageReference; + this.mUserId = builder.mUserId; + + // Below are the fields that do not exist in the SimInfo table. + this.mCardId = builder.mCardId; + this.mIsGroupDisabled = builder.mIsGroupDisabled; + } + + /** + * @return The subscription ID. + */ + public int getSubscriptionId() { + return mId; + } + + /** + * Returns the ICC ID. + * + * @return the ICC ID, or an empty string if one of these requirements is not met + */ + @NonNull + public String getIccId() { + return mIccId; + } + + /** + * @return The index of the SIM slot that currently contains the subscription and not + * necessarily unique and maybe {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX} if unknown or + * the subscription is inactive. + */ + public int getSimSlotIndex() { + return mSimSlotIndex; + } + + /** + * @return The name displayed to the user that identifies this subscription. This name is + * used in Settings page and can be renamed by the user. + * + * @see #getCarrierName() + */ + @NonNull + public CharSequence getDisplayName() { + return mDisplayName; + } + + /** + * @return The name displayed to the user that identifies subscription provider name. This name + * is the SPN displayed in status bar and many other places. Can't be renamed by the user. + * + * @see #getDisplayName() + */ + @NonNull + public CharSequence getCarrierName() { + return mCarrierName; + } + + /** + * @return The source of the {@link #getDisplayName()}. + */ + @SimDisplayNameSource + public int getDisplayNameSource() { + return mDisplayNameSource; + } + + /** + * A highlight color to use in displaying information about this {@code PhoneAccount}. + * + * @return A hexadecimal color value. + */ + public int getIconTint() { + return mIconTint; + } + + /** + * @return the number of this subscription. + */ + public String getNumber() { + return mNumber; + } + + /** + * Whether user enables data roaming for this subscription or not. Either + * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or + * {@link SubscriptionManager#DATA_ROAMING_DISABLE}. + */ + public int getDataRoaming() { + return mDataRoaming; + } + + /** + * @return The mobile country code. + */ + @NonNull + public String getMccString() { + return mMcc; + } + + /** + * @return The mobile network code. + */ + @NonNull + public String getMncString() { + return mMnc; + } + + /** + * @return Extended home PLMNs associated with this subscription. + */ + @NonNull + public String getEhplmns() { + return mEhplmns; + } + + /** + * @return Home PLMNs associated with this subscription. + */ + @NonNull + public String getHplmnsRaw() { + return mHplmns; + } + + /** + * @return {@code true} if the subscription is from eSIM. + */ + public boolean isEmbedded() { + return mIsEmbedded != 0; + } + + /** + * @return The raw database value of {@link #isEmbedded()}. + */ + public int isEmbeddedRaw() { + return mIsEmbedded; + } + + /** + * Returns the card string of the SIM card which contains the subscription. + * + * @return The card string of the SIM card which contains the subscription. The card string is + * the ICCID for UICCs or the EID for + * eUICCs. + */ + @NonNull + public String getCardString() { + return mCardString; + } + + /** + * @return The access rules for this subscription, if it is embedded and defines any. This + * does not include access rules for non-embedded subscriptions. This is the raw string + * stored in the database. + */ + @NonNull + public byte[] getNativeAccessRulesRaw() { + return mNativeAccessRules; + } + + /** + * @return The carrier certificates for this subscription that are saved in carrier configs. + * This does not include access rules from the Uicc, whether embedded or non-embedded. This + * is the raw string stored in the database. + */ + public byte[] getCarrierConfigAccessRulesRaw() { + return mCarrierConfigAccessRules; + } + + /** + * Whether an embedded subscription is on a removable card. Such subscriptions are marked + * inaccessible as soon as the current card is removed. Otherwise, they will remain accessible + * unless explicitly deleted. Only meaningful when {@link #isEmbedded()} is {@code true}. + */ + public boolean isRemovableEmbedded() { + return mIsRemovableEmbedded != 0; + } + + /** + * @return The raw database value of {@link #isRemovableEmbedded()}. + */ + public int isRemovableEmbeddedRaw() { + return mIsRemovableEmbedded; + } + + /** + * @return Whether enhanced 4G mode is enabled by the user or not. + */ + public boolean isEnhanced4GModeEnabled() { + return mIsEnhanced4GModeEnabled != 0; + } + + /** + * @return The raw database value of {@link #isEnhanced4GModeEnabled()}. + */ + public int isEnhanced4GModeEnabledRaw() { + return mIsEnhanced4GModeEnabled; + } + + /** + * @return Whether video telephony is enabled by the user or not. + */ + public boolean isVideoTelephonyEnabled() { + return mIsVideoTelephonyEnabled != 0; + } + + /** + * @return The raw database value of {@link #isVideoTelephonyEnabled()}. + */ + public int isVideoTelephonyEnabledRaw() { + return mIsVideoTelephonyEnabled; + } + + /** + * @return Whether Wi-Fi calling is enabled by the user or not when the device is not roaming. + */ + public boolean isWifiCallingEnabled() { + return mIsWifiCallingEnabled != 0; + } + + /** + * @return The raw database value of {@link #isWifiCallingEnabled()}. + */ + public int isWifiCallingEnabledRaw() { + return mIsWifiCallingEnabled; + } + + /** + * @return Wi-Fi calling mode when the device is not roaming. + */ + @ImsMmTelManager.WiFiCallingMode + public int getWifiCallingMode() { + return mWifiCallingMode; + } + + /** + * @return Whether Wi-Fi calling is enabled by the user or not when the device is roaming. + */ + @ImsMmTelManager.WiFiCallingMode + public int getWifiCallingModeForRoaming() { + return mWifiCallingModeForRoaming; + } + + /** + * @return Whether Wi-Fi calling is enabled by the user or not when the device is roaming. + */ + public boolean isWifiCallingEnabledForRoaming() { + return mIsWifiCallingEnabledForRoaming != 0; + } + + /** + * @return The raw database value of {@link #isWifiCallingEnabledForRoaming()}. + */ + public int isWifiCallingEnabledForRoamingRaw() { + return mIsWifiCallingEnabledForRoaming; + } + + /** + * An opportunistic subscription connects to a network that is + * limited in functionality and / or coverage. + * + * @return Whether subscription is opportunistic. + */ + public boolean isOpportunistic() { + return mIsOpportunistic != 0; + } + + /** + * @return The raw database value of {@link #isOpportunistic()}. + */ + public int isOpportunisticRaw() { + return mIsOpportunistic; + } + + /** + * Used in scenarios where different subscriptions are bundled as a group. + * It's typically a primary and an opportunistic subscription. (see {@link #isOpportunistic()}) + * Such that those subscriptions will have some affiliated behaviors such as opportunistic + * subscription may be invisible to the user. + * + * @return Group UUID in string format. + */ + @NonNull + public String getGroupUuidRaw() { + return mGroupUuid; + } + + /** + * @return The ISO country code. Empty if not available. + */ + public String getCountryIso() { + return mCountryIso; + } + + /** + * @return The carrier id of this subscription carrier. + * + * @see TelephonyManager#getSimCarrierId() + */ + public int getCarrierId() { + return mCarrierId; + } + + /** + * @return The profile class populated from the profile metadata if present. Otherwise, + * the profile class defaults to {@link SubscriptionManager#PROFILE_CLASS_UNSET} if there is no + * profile metadata or the subscription is not on an eUICC ({@link #isEmbedded} return + * {@code false}). + */ + @ProfileClass + public int getProfileClass() { + return mProfileClass; + } + + /** + * This method returns the type of a subscription. It can be + * {@link SubscriptionManager#SUBSCRIPTION_TYPE_LOCAL_SIM} or + * {@link SubscriptionManager#SUBSCRIPTION_TYPE_REMOTE_SIM}. + * + * @return The type of the subscription. + */ + @SubscriptionType + public int getSubscriptionType() { + return mType; + } + + /** + * @return The owner package of group the subscription belongs to. + */ + @NonNull + public String getGroupOwner() { + return mGroupOwner; + } + + /** + * @return The enabled mobile data policies in string format. + * + * @see com.android.internal.telephony.data.DataSettingsManager#getMobileDataPolicyEnabled + */ + @NonNull + public String getEnabledMobileDataPoliciesRaw() { + return mEnabledMobileDataPolicies; + } + + /** + * @return The IMSI (International Mobile Subscriber Identity) of the subscription. + */ + @NonNull + public String getImsi() { + return mImsi; + } + + /** + * @return {@code true} if Uicc applications are set to be enabled or disabled. + */ + public boolean areUiccApplicationsEnabled() { + return mAreUiccApplicationsEnabled != 0; + } + + /** + * @return The raw database value of {@link #areUiccApplicationsEnabled()}. + */ + public int areUiccApplicationsEnabledRaw() { + return mAreUiccApplicationsEnabled; + } + + /** + * @return Whether the user has enabled IMS RCS User Capability Exchange (UCE) for this + * subscription. + */ + public boolean isRcsUceEnabled() { + return mIsRcsUceEnabled != 0; + } + + /** + * @return The raw database value of {@link #isRcsUceEnabled()}. + */ + public int isRcsUceEnabledRaw() { + return mIsRcsUceEnabled; + } + + /** + * @return Whether the user has enabled cross SIM calling for this subscription. + */ + public boolean isCrossSimCallingEnabled() { + return mIsCrossSimCallingEnabled != 0; + } + + /** + * @return The raw database value of {@link #isCrossSimCallingEnabled()}. + */ + public int isCrossSimCallingEnabledRaw() { + return mIsCrossSimCallingEnabled; + } + + /** + * @return The RCS configuration. + */ + @NonNull + public byte[] getRcsConfig() { + return mRcsConfig; + } + + /** + * The allowed network types for reasons in string format. The format is + * "[reason]=[network types bitmask], [reason]=[network types bitmask], ..." + * + * For example, "user=1239287394, thermal=298791239, carrier=3456812312". + */ + @NonNull + public String getAllowedNetworkTypesForReasons() { + return mAllowedNetworkTypesForReasons; + } + + /** + * @return Device to device sharing status. + */ + @DeviceToDeviceStatusSharingPreference + public int getDeviceToDeviceStatusSharingPreference() { + return mDeviceToDeviceStatusSharingPreference; + } + + /** + * @return Whether the user has opted-in voice over IMS. + */ + public boolean isVoImsOptInEnabled() { + return mIsVoImsOptInEnabled != 0; + } + + /** + * @return The raw database value of {@link #isVoImsOptInEnabled()}. + */ + public int isVoImsOptInEnabledRaw() { + return mIsVoImsOptInEnabled; + } + + /** + * @return Contacts information that allow device to device sharing. + */ + @NonNull + public String getDeviceToDeviceStatusSharingContacts() { + return mDeviceToDeviceStatusSharingContacts; + } + + /** + * @return Whether the user has enabled NR advanced calling. + */ + public boolean isNrAdvancedCallingEnabled() { + return mIsNrAdvancedCallingEnabled != 0; + } + + /** + * @return The raw database value of {@link #isNrAdvancedCallingEnabled()}. + */ + public int isNrAdvancedCallingEnabledRaw() { + return mIsNrAdvancedCallingEnabled; + } + + /** + * @return Get the phone number retrieved from carrier. + */ + @NonNull + public String getNumberFromCarrier() { + return mNumberFromCarrier; + } + + /** + * @return Get the phone number retrieved from IMS. + */ + @NonNull + public String getNumberFromIms() { + return mNumberFromIms; + } + + /** + * @return The port index of the SIM card which contains the subscription. + */ + public int getPortIndex() { + return mPortIndex; + } + + /** + * Get the usage setting for this subscription. + * + * @return The usage setting used for this subscription. + */ + @UsageSetting + public int getUsageSetting() { + return mUsageSetting; + } + + /** + * @return Last used TP message reference. + */ + public int getLastUsedTPMessageReference() { + return mLastUsedTPMessageReference; + } + + /** + * @return The user id associated with this subscription. + */ + public int getUserId() { + return mUserId; + } + + // Below are the fields that do not exist in SimInfo table. + /** + * @return The card ID of the SIM card which contains the subscription. + * + * @see android.telephony.UiccCardInfo#getCardId(). + */ + public int getCardId() { + return mCardId; + } + + /** + * @return {@code true} if the group of the subscription is disabled. This is only useful if + * it's a grouped opportunistic subscription. In this case, if all primary (non-opportunistic) + * subscriptions in the group are deactivated (unplugged pSIM or deactivated eSIM profile), we + * should disable this opportunistic subscription. + */ + public boolean isGroupDisabled() { + return mIsGroupDisabled; + } + + /** + * Get ID stripped PII information on user build. + * + * @param id The PII id. + * + * @return The stripped string. + */ + public static String givePrintableId(String id) { + String idToPrint = null; + if (id != null) { + int len = id.length(); + if (len > 6 && !TelephonyUtils.IS_DEBUGGABLE) { + idToPrint = id.substring(0, len - 6) + Rlog.pii(false, id.substring(len - 6)); + } else { + idToPrint = id; + } + } + return idToPrint; + } + + @Override + public String toString() { + return "[SubscriptionInfoInternal: id=" + mId + + " iccId=" + givePrintableId(mIccId) + + " simSlotIndex=" + mSimSlotIndex + + " portIndex=" + mPortIndex + + " isEmbedded=" + mIsEmbedded + + " isRemovableEmbedded=" + mIsRemovableEmbedded + + " carrierId=" + mCarrierId + + " displayName=" + mDisplayName + + " carrierName=" + mCarrierName + + " isOpportunistic=" + mIsOpportunistic + + " groupUuid=" + mGroupUuid + + " groupOwner=" + mGroupOwner + + " displayNameSource=" + + SubscriptionManager.displayNameSourceToString(mDisplayNameSource) + + " iconTint=" + mIconTint + + " number=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumber) + + " dataRoaming=" + mDataRoaming + + " mcc=" + mMcc + + " mnc=" + mMnc + + " ehplmns=" + mEhplmns + + " hplmns=" + mHplmns + + " cardString=" + givePrintableId(mCardString) + + " cardId=" + mCardId + + " nativeAccessRules=" + IccUtils.bytesToHexString(mNativeAccessRules) + + " carrierConfigAccessRules=" + IccUtils.bytesToHexString( + mCarrierConfigAccessRules) + + " countryIso=" + mCountryIso + + " profileClass=" + mProfileClass + + " type=" + SubscriptionManager.subscriptionTypeToString(mType) + + " areUiccApplicationsEnabled=" + mAreUiccApplicationsEnabled + + " usageSetting=" + SubscriptionManager.usageSettingToString(mUsageSetting) + + " isEnhanced4GModeEnabled=" + mIsEnhanced4GModeEnabled + + " isVideoTelephonyEnabled=" + mIsVideoTelephonyEnabled + + " isWifiCallingEnabled=" + mIsWifiCallingEnabled + + " isWifiCallingEnabledForRoaming=" + mIsWifiCallingEnabledForRoaming + + " wifiCallingMode=" + ImsMmTelManager.wifiCallingModeToString(mWifiCallingMode) + + " wifiCallingModeForRoaming=" + + ImsMmTelManager.wifiCallingModeToString(mWifiCallingModeForRoaming) + + " enabledMobileDataPolicies=" + mEnabledMobileDataPolicies + + " imsi=" + givePrintableId(mImsi) + + " rcsUceEnabled=" + mIsRcsUceEnabled + + " crossSimCallingEnabled=" + mIsCrossSimCallingEnabled + + " rcsConfig=" + IccUtils.bytesToHexString(mRcsConfig) + + " allowedNetworkTypesForReasons=" + mAllowedNetworkTypesForReasons + + " deviceToDeviceStatusSharingPreference=" + mDeviceToDeviceStatusSharingPreference + + " isVoImsOptInEnabled=" + mIsVoImsOptInEnabled + + " deviceToDeviceStatusSharingContacts=" + mDeviceToDeviceStatusSharingContacts + + " numberFromCarrier=" + mNumberFromCarrier + + " numberFromIms=" + mNumberFromIms + + " userId=" + mUserId + + " isGroupDisabled=" + mIsGroupDisabled + + "]"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SubscriptionInfoInternal that = (SubscriptionInfoInternal) o; + return mId == that.mId && mSimSlotIndex == that.mSimSlotIndex + && mDisplayNameSource == that.mDisplayNameSource && mIconTint == that.mIconTint + && mDataRoaming == that.mDataRoaming && mIsEmbedded == that.mIsEmbedded + && mIsRemovableEmbedded == that.mIsRemovableEmbedded + && mIsEnhanced4GModeEnabled == that.mIsEnhanced4GModeEnabled + && mIsVideoTelephonyEnabled == that.mIsVideoTelephonyEnabled + && mIsWifiCallingEnabled == that.mIsWifiCallingEnabled + && mWifiCallingMode == that.mWifiCallingMode + && mWifiCallingModeForRoaming == that.mWifiCallingModeForRoaming + && mIsWifiCallingEnabledForRoaming == that.mIsWifiCallingEnabledForRoaming + && mIsOpportunistic == that.mIsOpportunistic && mCarrierId == that.mCarrierId + && mProfileClass == that.mProfileClass && mType == that.mType + && mAreUiccApplicationsEnabled == that.mAreUiccApplicationsEnabled + && mIsRcsUceEnabled == that.mIsRcsUceEnabled + && mIsCrossSimCallingEnabled == that.mIsCrossSimCallingEnabled + && mDeviceToDeviceStatusSharingPreference + == that.mDeviceToDeviceStatusSharingPreference + && mIsVoImsOptInEnabled == that.mIsVoImsOptInEnabled + && mIsNrAdvancedCallingEnabled == that.mIsNrAdvancedCallingEnabled + && mPortIndex == that.mPortIndex && mUsageSetting == that.mUsageSetting + && mLastUsedTPMessageReference == that.mLastUsedTPMessageReference + && mUserId == that.mUserId && mCardId == that.mCardId + && mIsGroupDisabled == that.mIsGroupDisabled && mIccId.equals(that.mIccId) + && mDisplayName.equals(that.mDisplayName) && mCarrierName.equals(that.mCarrierName) + && mNumber.equals(that.mNumber) && mMcc.equals(that.mMcc) && mMnc.equals(that.mMnc) + && mEhplmns.equals(that.mEhplmns) && mHplmns.equals(that.mHplmns) + && mCardString.equals( + that.mCardString) && Arrays.equals(mNativeAccessRules, + that.mNativeAccessRules) && Arrays.equals(mCarrierConfigAccessRules, + that.mCarrierConfigAccessRules) && mGroupUuid.equals(that.mGroupUuid) + && mCountryIso.equals(that.mCountryIso) && mGroupOwner.equals(that.mGroupOwner) + && mEnabledMobileDataPolicies.equals(that.mEnabledMobileDataPolicies) + && mImsi.equals( + that.mImsi) && Arrays.equals(mRcsConfig, that.mRcsConfig) + && mAllowedNetworkTypesForReasons.equals(that.mAllowedNetworkTypesForReasons) + && mDeviceToDeviceStatusSharingContacts.equals( + that.mDeviceToDeviceStatusSharingContacts) && mNumberFromCarrier.equals( + that.mNumberFromCarrier) && mNumberFromIms.equals(that.mNumberFromIms); + } + + @Override + public int hashCode() { + int result = Objects.hash(mId, mIccId, mSimSlotIndex, mDisplayName, mCarrierName, + mDisplayNameSource, mIconTint, mNumber, mDataRoaming, mMcc, mMnc, mEhplmns, mHplmns, + mIsEmbedded, mCardString, mIsRemovableEmbedded, mIsEnhanced4GModeEnabled, + mIsVideoTelephonyEnabled, mIsWifiCallingEnabled, mWifiCallingMode, + mWifiCallingModeForRoaming, mIsWifiCallingEnabledForRoaming, mIsOpportunistic, + mGroupUuid, mCountryIso, mCarrierId, mProfileClass, mType, mGroupOwner, + mEnabledMobileDataPolicies, mImsi, mAreUiccApplicationsEnabled, mIsRcsUceEnabled, + mIsCrossSimCallingEnabled, mAllowedNetworkTypesForReasons, + mDeviceToDeviceStatusSharingPreference, mIsVoImsOptInEnabled, + mDeviceToDeviceStatusSharingContacts, mIsNrAdvancedCallingEnabled, + mNumberFromCarrier, + mNumberFromIms, mPortIndex, mUsageSetting, mLastUsedTPMessageReference, mUserId, + mCardId, mIsGroupDisabled); + result = 31 * result + Arrays.hashCode(mNativeAccessRules); + result = 31 * result + Arrays.hashCode(mCarrierConfigAccessRules); + result = 31 * result + Arrays.hashCode(mRcsConfig); + return result; + } + + /** + * The builder class of {@link SubscriptionInfoInternal}. + */ + public static class Builder { + /** + * The subscription id. + */ + private int mId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + + /** + * The ICCID of the SIM that is associated with this subscription, empty if unknown. + */ + @NonNull + private String mIccId = ""; + + /** + * The index of the SIM slot that currently contains the subscription and not necessarily + * unique and maybe {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX} if unknown or the + * subscription is inactive. + */ + private int mSimSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX; + + /** + * The name displayed to the user that identifies this subscription. This name is used + * in Settings page and can be renamed by the user. + */ + @NonNull + private String mDisplayName = ""; + + /** + * The name displayed to the user that identifies subscription provider name. This name + * is the SPN displayed in status bar and many other places. Can't be renamed by the user. + */ + @NonNull + private String mCarrierName = ""; + + /** + * The source of the display name. + */ + @SimDisplayNameSource + private int mDisplayNameSource = SubscriptionManager.NAME_SOURCE_UNKNOWN; + + /** + * The color to be used for tinting the icon when displaying to the user. + */ + private int mIconTint = 0; + + /** + * The number presented to the user identify this subscription. + */ + @NonNull + private String mNumber = ""; + + /** + * Whether user enables data roaming for this subscription or not. Either + * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or + * {@link SubscriptionManager#DATA_ROAMING_DISABLE}. + */ + private int mDataRoaming = SubscriptionManager.DATA_ROAMING_DISABLE; + + /** + * The mobile country code. + */ + @NonNull + private String mMcc = ""; + + /** + * The mobile network code. + */ + @NonNull + private String mMnc = ""; + + /** + * EHPLMNs associated with the subscription. + */ + @NonNull + private String mEhplmns = ""; + + /** + * HPLMNs associated with the subscription. + */ + @NonNull + private String mHplmns = ""; + + /** + * Whether the subscription is from eSIM. + */ + private int mIsEmbedded = 0; + + /** + * The card string of the SIM card. + */ + @NonNull + private String mCardString = ""; + + /** + * The native access rules for this subscription, if it is embedded and defines any. This + * does not include access rules for non-embedded subscriptions. + */ + @NonNull + private byte[] mNativeAccessRules = new byte[0]; + + /** + * The carrier certificates for this subscription that are saved in carrier configs. + * This does not include access rules from the Uicc, whether embedded or non-embedded. + */ + @NonNull + private byte[] mCarrierConfigAccessRules = new byte[0]; + + /** + * Whether an embedded subscription is on a removable card. Such subscriptions are marked + * inaccessible as soon as the current card is removed. Otherwise, they will remain + * accessible unless explicitly deleted. Only meaningful when {@link #isEmbedded()} is + * {@code true}. + */ + private int mIsRemovableEmbedded = 0; + + /** + * Whether enhanced 4G mode is enabled by the user or not. + */ + private int mIsEnhanced4GModeEnabled = 0; + + /** + * Whether video telephony is enabled by the user or not. + */ + private int mIsVideoTelephonyEnabled = 0; + + /** + * Whether Wi-Fi calling is enabled by the user or not when the device is not roaming. + */ + private int mIsWifiCallingEnabled = 0; + + /** + * Wi-Fi calling mode when the device is not roaming. + */ + @ImsMmTelManager.WiFiCallingMode + private int mWifiCallingMode = ImsMmTelManager.WIFI_MODE_UNKNOWN; + + /** + * Wi-Fi calling mode when the device is roaming. + */ + @ImsMmTelManager.WiFiCallingMode + private int mWifiCallingModeForRoaming = ImsMmTelManager.WIFI_MODE_UNKNOWN; + + /** + * Whether Wi-Fi calling is enabled by the user or not when the device is roaming. + */ + private int mIsWifiCallingEnabledForRoaming = 0; + + /** + * Whether the subscription is opportunistic or not. + */ + private int mIsOpportunistic = 0; + + /** + * The group UUID of the subscription group in string format. + */ + @NonNull + private String mGroupUuid = ""; + + /** + * The ISO Country code for the subscription's provider. + */ + @NonNull + private String mCountryIso = ""; + + /** + * The carrier id. + * + * @see TelephonyManager#getSimCarrierId() + */ + private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID; + + /** + * The profile class populated from the profile metadata if present. Otherwise, the profile + * class defaults to {@link SubscriptionManager#PROFILE_CLASS_UNSET} if there is no profile + * metadata or the subscription is not on an eUICC ({@link #isEmbedded} returns + * {@code false}). + */ + @ProfileClass + private int mProfileClass = SubscriptionManager.PROFILE_CLASS_UNSET; + + /** + * The subscription type. + */ + @SubscriptionType + private int mType = SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM; + + /** + * The owner package of group the subscription belongs to. + */ + @NonNull + private String mGroupOwner = ""; + + /** + * The enabled mobile data policies in string format. + */ + @NonNull + private String mEnabledMobileDataPolicies = ""; + + /** + * The IMSI (International Mobile Subscriber Identity) of the subscription. + */ + @NonNull + private String mImsi = ""; + + /** + * Whether Uicc applications are configured to enable or not. + */ + private int mAreUiccApplicationsEnabled = 0; + + /** + * Whether the user has enabled IMS RCS User Capability Exchange (UCE) for this + * subscription. + */ + private int mIsRcsUceEnabled = 0; + + /** + * Whether the user has enabled cross SIM calling for this subscription. + */ + private int mIsCrossSimCallingEnabled = 0; + + /** + * The RCS configuration. + */ + private byte[] mRcsConfig = new byte[0]; + + /** + * The allowed network types for reasons in string format. The format is + * "[reason]=[network types bitmask], [reason]=[network types bitmask], ..." + * + * For example, "user=1239287394, thermal=298791239, carrier=3456812312". + */ + private String mAllowedNetworkTypesForReasons = ""; + + /** + * Device to device sharing status. + */ + @DeviceToDeviceStatusSharingPreference + private int mDeviceToDeviceStatusSharingPreference = + SubscriptionManager.D2D_SHARING_DISABLED; + + /** + * Whether the user has opted-in voice over IMS. + */ + private int mIsVoImsOptInEnabled = 0; + + /** + * Contacts information that allow device to device sharing. + */ + @NonNull + private String mDeviceToDeviceStatusSharingContacts = ""; + + /** + * Whether the user has enabled NR advanced calling. + */ + private int mIsNrAdvancedCallingEnabled = 0; + + /** + * The phone number retrieved from carrier. + */ + @NonNull + private String mNumberFromCarrier = ""; + + /** + * The phone number retrieved from IMS. + */ + @NonNull + private String mNumberFromIms = ""; + + /** + * the port index of the Uicc card. + */ + private int mPortIndex = TelephonyManager.INVALID_PORT_INDEX; + + /** + * Subscription's preferred usage setting. + */ + @UsageSetting + private int mUsageSetting = SubscriptionManager.USAGE_SETTING_UNKNOWN; + + /** + * Last used TP message reference. + */ + private int mLastUsedTPMessageReference = -1; + + /** + * The user id associated with this subscription. + */ + private int mUserId = UserHandle.USER_NULL; + + // The following fields do not exist in the SimInfo table. + /** + * The card ID of the SIM card which contains the subscription. + */ + private int mCardId = TelephonyManager.UNINITIALIZED_CARD_ID; + + /** + * Whether group of the subscription is disabled. This is only useful if it's a grouped + * opportunistic subscription. In this case, if all primary (non-opportunistic) + * subscriptions in the group are deactivated (unplugged pSIM or deactivated eSIM profile), + * we should disable this opportunistic subscription. + */ + private boolean mIsGroupDisabled; + + /** + * Default constructor. + */ + public Builder() { + } + + /** + * Constructor from {@link SubscriptionInfoInternal}. + * + * @param info The subscription info. + */ + public Builder(@NonNull SubscriptionInfoInternal info) { + mId = info.mId; + mIccId = info.mIccId; + mSimSlotIndex = info.mSimSlotIndex; + mDisplayName = info.mDisplayName; + mCarrierName = info.mCarrierName; + mDisplayNameSource = info.mDisplayNameSource; + mIconTint = info.mIconTint; + mNumber = info.mNumber; + mDataRoaming = info.mDataRoaming; + mMcc = info.mMcc; + mMnc = info.mMnc; + mEhplmns = info.mEhplmns; + mHplmns = info.mHplmns; + mIsEmbedded = info.mIsEmbedded; + mCardString = info.mCardString; + mNativeAccessRules = info.mNativeAccessRules; + mCarrierConfigAccessRules = info.mCarrierConfigAccessRules; + mIsRemovableEmbedded = info.mIsRemovableEmbedded; + mIsEnhanced4GModeEnabled = info.mIsEnhanced4GModeEnabled; + mIsVideoTelephonyEnabled = info.mIsVideoTelephonyEnabled; + mIsWifiCallingEnabled = info.mIsWifiCallingEnabled; + mWifiCallingMode = info.mWifiCallingMode; + mWifiCallingModeForRoaming = info.mWifiCallingModeForRoaming; + mIsWifiCallingEnabledForRoaming = info.mIsWifiCallingEnabledForRoaming; + mIsOpportunistic = info.mIsOpportunistic; + mGroupUuid = info.mGroupUuid; + mCountryIso = info.mCountryIso; + mCarrierId = info.mCarrierId; + mProfileClass = info.mProfileClass; + mType = info.mType; + mGroupOwner = info.mGroupOwner; + mEnabledMobileDataPolicies = info.mEnabledMobileDataPolicies; + mImsi = info.mImsi; + mAreUiccApplicationsEnabled = info.mAreUiccApplicationsEnabled; + mIsRcsUceEnabled = info.mIsRcsUceEnabled; + mIsCrossSimCallingEnabled = info.mIsCrossSimCallingEnabled; + mRcsConfig = info.mRcsConfig; + mAllowedNetworkTypesForReasons = info.mAllowedNetworkTypesForReasons; + mDeviceToDeviceStatusSharingPreference = info.mDeviceToDeviceStatusSharingPreference; + mIsVoImsOptInEnabled = info.mIsVoImsOptInEnabled; + mDeviceToDeviceStatusSharingContacts = info.mDeviceToDeviceStatusSharingContacts; + mIsNrAdvancedCallingEnabled = info.mIsNrAdvancedCallingEnabled; + mNumberFromCarrier = info.mNumberFromCarrier; + mNumberFromIms = info.mNumberFromIms; + mPortIndex = info.mPortIndex; + mUsageSetting = info.mUsageSetting; + mLastUsedTPMessageReference = info.getLastUsedTPMessageReference(); + mUserId = info.mUserId; + // Below are the fields that do not exist in the SimInfo table. + mCardId = info.mCardId; + mIsGroupDisabled = info.mIsGroupDisabled; + } + + /** + * Set the subscription id. + * + * @param id The subscription id. + * + * @return The builder. + */ + @NonNull + public Builder setId(int id) { + mId = id; + return this; + } + + /** + * Set the ICCID of the SIM that is associated with this subscription. + * + * @param iccId The ICCID of the SIM that is associated with this subscription. + * + * @return The builder. + */ + @NonNull + public Builder setIccId(@NonNull String iccId) { + Objects.requireNonNull(iccId); + mIccId = iccId; + return this; + } + + /** + * Set the SIM index of the slot that currently contains the subscription. Set to + * {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX} if the subscription is inactive. + * + * @param simSlotIndex The SIM slot index. + * + * @return The builder. + */ + @NonNull + public Builder setSimSlotIndex(int simSlotIndex) { + mSimSlotIndex = simSlotIndex; + return this; + } + + /** + * The name displayed to the user that identifies this subscription. This name is used + * in Settings page and can be renamed by the user. + * + * @param displayName The display name. + * + * @return The builder. + */ + @NonNull + public Builder setDisplayName(@NonNull String displayName) { + Objects.requireNonNull(displayName); + mDisplayName = displayName; + return this; + } + + /** + * The name displayed to the user that identifies subscription provider name. This name + * is the SPN displayed in status bar and many other places. Can't be renamed by the user. + * + * @param carrierName The carrier name. + * + * @return The builder. + */ + @NonNull + public Builder setCarrierName(@NonNull String carrierName) { + Objects.requireNonNull(carrierName); + mCarrierName = carrierName; + return this; + } + + /** + * Set the source of the display name. + * + * @param displayNameSource The source of the display name. + * @return The builder. + * + * @see SubscriptionInfoInternal#getDisplayName() + */ + @NonNull + public Builder setDisplayNameSource(@SimDisplayNameSource int displayNameSource) { + mDisplayNameSource = displayNameSource; + return this; + } + + /** + * Set the color to be used for tinting the icon when displaying to the user. + * + * @param iconTint The color to be used for tinting the icon when displaying to the user. + * + * @return The builder. + */ + @NonNull + public Builder setIconTint(int iconTint) { + mIconTint = iconTint; + return this; + } + + /** + * Set the number presented to the user identify this subscription. + * + * @param number the number presented to the user identify this subscription. + * + * @return The builder. + */ + @NonNull + public Builder setNumber(@NonNull String number) { + Objects.requireNonNull(number); + mNumber = number; + return this; + } + + /** + * Set whether user enables data roaming for this subscription or not. + * + * @param dataRoaming Data roaming mode. Either + * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or + * {@link SubscriptionManager#DATA_ROAMING_DISABLE} + * + * @return The builder. + */ + @NonNull + public Builder setDataRoaming(int dataRoaming) { + mDataRoaming = dataRoaming; + return this; + } + + /** + * Set the mobile country code. + * + * @param mcc The mobile country code. + * + * @return The builder. + */ + @NonNull + public Builder setMcc(@NonNull String mcc) { + Objects.requireNonNull(mcc); + mMcc = mcc; + return this; + } + + /** + * Set the mobile network code. + * + * @param mnc Mobile network code. + * + * @return The builder. + */ + @NonNull + public Builder setMnc(@NonNull String mnc) { + Objects.requireNonNull(mnc); + mMnc = mnc; + return this; + } + + /** + * Set EHPLMNs associated with the subscription. + * + * @param ehplmns EHPLMNs associated with the subscription. + * + * @return The builder. + */ + @NonNull + public Builder setEhplmns(@NonNull String ehplmns) { + Objects.requireNonNull(ehplmns); + mEhplmns = ehplmns; + return this; + } + + /** + * Set HPLMNs associated with the subscription. + * + * @param hplmns HPLMNs associated with the subscription. + * + * @return The builder. + */ + @NonNull + public Builder setHplmns(@NonNull String hplmns) { + Objects.requireNonNull(hplmns); + mHplmns = hplmns; + return this; + } + + /** + * Set whether the subscription is from eSIM or not. + * + * @param isEmbedded {@code true} if the subscription is from eSIM. + * + * @return The builder. + */ + @NonNull + public Builder setEmbedded(int isEmbedded) { + mIsEmbedded = isEmbedded; + return this; + } + + /** + * Set the card string of the SIM card. + * + * @param cardString The card string of the SIM card. + * + * @return The builder. + * + * @see #getCardString() + */ + @NonNull + public Builder setCardString(@NonNull String cardString) { + Objects.requireNonNull(cardString); + mCardString = cardString; + return this; + } + + /** + * Set the native access rules for this subscription, if it is embedded and defines any. + * This does not include access rules for non-embedded subscriptions. + * + * @param nativeAccessRules The native access rules for this subscription. + * + * @return The builder. + */ + @NonNull + public Builder setNativeAccessRules(@NonNull byte[] nativeAccessRules) { + Objects.requireNonNull(nativeAccessRules); + mNativeAccessRules = nativeAccessRules; + return this; + } + + /** + * Set the carrier certificates for this subscription that are saved in carrier configs. + * This does not include access rules from the Uicc, whether embedded or non-embedded. + * + * @param carrierConfigAccessRules The carrier certificates for this subscription. + * + * @return The builder. + */ + @NonNull + public Builder setCarrierConfigAccessRules(@NonNull byte[] carrierConfigAccessRules) { + Objects.requireNonNull(carrierConfigAccessRules); + mCarrierConfigAccessRules = carrierConfigAccessRules; + return this; + } + + /** + * Set whether an embedded subscription is on a removable card. Such subscriptions are + * marked inaccessible as soon as the current card is removed. Otherwise, they will remain + * accessible unless explicitly deleted. Only meaningful when {@link #isEmbedded()} is + * {@code true}. + * + * @param isRemovableEmbedded {@code true} if the subscription is from the removable + * embedded SIM. + * + * @return The builder. + */ + @NonNull + public Builder setRemovableEmbedded(int isRemovableEmbedded) { + mIsRemovableEmbedded = isRemovableEmbedded; + return this; + } + + /** + * Set whether enhanced 4G mode is enabled by the user or not. + * + * @param isEnhanced4GModeEnabled whether enhanced 4G mode is enabled by the user or not. + * + * @return The builder. + */ + @NonNull + public Builder setEnhanced4GModeEnabled(int isEnhanced4GModeEnabled) { + mIsEnhanced4GModeEnabled = isEnhanced4GModeEnabled; + return this; + } + + /** + * Set whether video telephony is enabled by the user or not. + * + * @param isVideoTelephonyEnabled whether video telephony is enabled by the user or not. + * + * @return The builder. + */ + @NonNull + public Builder setVideoTelephonyEnabled(int isVideoTelephonyEnabled) { + mIsVideoTelephonyEnabled = isVideoTelephonyEnabled; + return this; + } + + /** + * Set whether Wi-Fi calling is enabled by the user or not when the device is not roaming. + * + * @param isWifiCallingEnabled whether Wi-Fi calling is enabled by the user or not when + * the device is not roaming. + * + * @return The builder. + */ + @NonNull + public Builder setWifiCallingEnabled(int isWifiCallingEnabled) { + mIsWifiCallingEnabled = isWifiCallingEnabled; + return this; + } + + /** + * Set Wi-Fi calling mode when the device is not roaming. + * + * @param wifiCallingMode Wi-Fi calling mode when the device is not roaming. + * + * @return The builder. + */ + @NonNull + public Builder setWifiCallingMode(@ImsMmTelManager.WiFiCallingMode int wifiCallingMode) { + mWifiCallingMode = wifiCallingMode; + return this; + } + + /** + * Set Wi-Fi calling mode when the device is roaming. + * + * @param wifiCallingModeForRoaming Wi-Fi calling mode when the device is roaming. + * + * @return The builder. + */ + @NonNull + public Builder setWifiCallingModeForRoaming( + @ImsMmTelManager.WiFiCallingMode int wifiCallingModeForRoaming) { + mWifiCallingModeForRoaming = wifiCallingModeForRoaming; + return this; + } + + /** + * Set whether Wi-Fi calling is enabled by the user or not when the device is roaming. + * + * @param wifiCallingEnabledForRoaming whether Wi-Fi calling is enabled by the user or not + * when the device is roaming. + * + * @return The builder. + */ + @NonNull + public Builder setWifiCallingEnabledForRoaming(int wifiCallingEnabledForRoaming) { + mIsWifiCallingEnabledForRoaming = wifiCallingEnabledForRoaming; + return this; + } + + /** + * Set whether the subscription is opportunistic or not. + * + * @param isOpportunistic {@code true} if the subscription is opportunistic. + * @return The builder. + */ + @NonNull + public Builder setOpportunistic(int isOpportunistic) { + mIsOpportunistic = isOpportunistic; + return this; + } + + /** + * Set the group UUID of the subscription group. + * + * @param groupUuid The group UUID. + * @return The builder. + * + */ + @NonNull + public Builder setGroupUuid(@NonNull String groupUuid) { + Objects.requireNonNull(groupUuid); + mGroupUuid = groupUuid; + return this; + } + + /** + * Set the ISO country code for the subscription's provider. + * + * @param countryIso The ISO country code for the subscription's provider. + * @return The builder. + */ + @NonNull + public Builder setCountryIso(@NonNull String countryIso) { + Objects.requireNonNull(countryIso); + mCountryIso = countryIso; + return this; + } + + /** + * Set the subscription carrier id. + * + * @param carrierId The carrier id. + * @return The builder + * + * @see TelephonyManager#getSimCarrierId() + */ + @NonNull + public Builder setCarrierId(int carrierId) { + mCarrierId = carrierId; + return this; + } + + /** + * Set the profile class populated from the profile metadata if present. + * + * @param profileClass the profile class populated from the profile metadata if present. + * @return The builder + * + * @see #getProfileClass() + */ + @NonNull + public Builder setProfileClass(@ProfileClass int profileClass) { + mProfileClass = profileClass; + return this; + } + + /** + * Set the subscription type. + * + * @param type Subscription type. + * @return The builder. + */ + @NonNull + public Builder setType(@SubscriptionType int type) { + mType = type; + return this; + } + + /** + * Set the owner package of group the subscription belongs to. + * + * @param groupOwner Owner package of group the subscription belongs to. + * @return The builder. + */ + @NonNull + public Builder setGroupOwner(@NonNull String groupOwner) { + Objects.requireNonNull(groupOwner); + mGroupOwner = groupOwner; + return this; + } + + /** + * Set the enabled mobile data policies. + * + * @param enabledMobileDataPolicies The enabled mobile data policies. + * @return The builder. + */ + @NonNull + public Builder setEnabledMobileDataPolicies(@NonNull String enabledMobileDataPolicies) { + Objects.requireNonNull(enabledMobileDataPolicies); + mEnabledMobileDataPolicies = enabledMobileDataPolicies; + return this; + } + + /** + * Set the IMSI (International Mobile Subscriber Identity) of the subscription. + * + * @param imsi The IMSI. + * @return The builder. + */ + @NonNull + public Builder setImsi(@NonNull String imsi) { + Objects.requireNonNull(imsi); + mImsi = imsi; + return this; + } + + /** + * Set whether Uicc applications are configured to enable or not. + * + * @param areUiccApplicationsEnabled {@code true} if Uicc applications are configured to + * enable. + * @return The builder. + */ + @NonNull + public Builder setUiccApplicationsEnabled(int areUiccApplicationsEnabled) { + mAreUiccApplicationsEnabled = areUiccApplicationsEnabled; + return this; + } + + /** + * Set whether the user has enabled IMS RCS User Capability Exchange (UCE) for this + * subscription. + * + * @param isRcsUceEnabled If the user enabled RCS UCE for this subscription. + * @return The builder. + */ + @NonNull + public Builder setRcsUceEnabled(int isRcsUceEnabled) { + mIsRcsUceEnabled = isRcsUceEnabled; + return this; + } + + /** + * Set whether the user has enabled cross SIM calling for this subscription. + * + * @param isCrossSimCallingEnabled If the user enabled cross SIM calling for this + * subscription. + * @return The builder. + */ + @NonNull + public Builder setCrossSimCallingEnabled(int isCrossSimCallingEnabled) { + mIsCrossSimCallingEnabled = isCrossSimCallingEnabled; + return this; + } + + /** + * Set the RCS config for this subscription. + * + * @param rcsConfig The RCS config for this subscription. + * @return The builder. + */ + @NonNull + public Builder setRcsConfig(byte[] rcsConfig) { + Objects.requireNonNull(rcsConfig); + mRcsConfig = rcsConfig; + return this; + } + + /** + * Set the allowed network types for reasons. + * + * @param allowedNetworkTypesForReasons The allowed network types for reasons in string + * format. The format is + * "[reason]=[network types bitmask], [reason]=[network types bitmask], ..." + * + * For example, "user=1239287394, thermal=298791239, carrier=3456812312". + * + * @return The builder. + */ + public Builder setAllowedNetworkTypesForReasons( + @NonNull String allowedNetworkTypesForReasons) { + Objects.requireNonNull(allowedNetworkTypesForReasons); + mAllowedNetworkTypesForReasons = allowedNetworkTypesForReasons; + return this; + } + + /** + * Set device to device sharing status. + * + * @param deviceToDeviceStatusSharingPreference Device to device sharing status. + * @return The builder. + */ + public Builder setDeviceToDeviceStatusSharingPreference( + @DeviceToDeviceStatusSharingPreference int deviceToDeviceStatusSharingPreference) { + mDeviceToDeviceStatusSharingPreference = deviceToDeviceStatusSharingPreference; + return this; + } + + /** + * Set whether the user has opted-in voice over IMS. + * + * @param isVoImsOptInEnabled Whether the user has opted-in voice over IMS. + * @return The builder. + */ + @NonNull + public Builder setVoImsOptInEnabled(int isVoImsOptInEnabled) { + mIsVoImsOptInEnabled = isVoImsOptInEnabled; + return this; + } + + /** + * Set contacts information that allow device to device sharing. + * + * @param deviceToDeviceStatusSharingContacts contacts information that allow device to + * device sharing. + * @return The builder. + */ + @NonNull + public Builder setDeviceToDeviceStatusSharingContacts( + @NonNull String deviceToDeviceStatusSharingContacts) { + Objects.requireNonNull(deviceToDeviceStatusSharingContacts); + mDeviceToDeviceStatusSharingContacts = deviceToDeviceStatusSharingContacts; + return this; + } + + /** + * Set whether the user has enabled NR advanced calling. + * + * @param isNrAdvancedCallingEnabled Whether the user has enabled NR advanced calling. + * @return The builder. + */ + @NonNull + public Builder setNrAdvancedCallingEnabled(int isNrAdvancedCallingEnabled) { + mIsNrAdvancedCallingEnabled = isNrAdvancedCallingEnabled; + return this; + } + + /** + * Set the phone number retrieved from carrier. + * + * @param numberFromCarrier The phone number retrieved from carrier. + * @return The builder. + */ + @NonNull + public Builder setNumberFromCarrier(@NonNull String numberFromCarrier) { + Objects.requireNonNull(numberFromCarrier); + mNumberFromCarrier = numberFromCarrier; + return this; + } + + /** + * Set the phone number retrieved from IMS. + * + * @param numberFromIms The phone number retrieved from IMS. + * @return The builder. + */ + @NonNull + public Builder setNumberFromIms(@NonNull String numberFromIms) { + Objects.requireNonNull(numberFromIms); + mNumberFromIms = numberFromIms; + return this; + } + + /** + * Set the port index of the Uicc card. + * + * @param portIndex The port index of the Uicc card. + * @return The builder. + */ + @NonNull + public Builder setPortIndex(int portIndex) { + mPortIndex = portIndex; + return this; + } + + /** + * Set subscription's preferred usage setting. + * + * @param usageSetting Subscription's preferred usage setting. + * @return The builder. + */ + @NonNull + public Builder setUsageSetting(@UsageSetting int usageSetting) { + mUsageSetting = usageSetting; + return this; + } + + /** + * Set last used TP message reference. + * + * @param lastUsedTPMessageReference Last used TP message reference. + * @return The builder. + */ + @NonNull + public Builder setLastUsedTPMessageReference( + int lastUsedTPMessageReference) { + mLastUsedTPMessageReference = lastUsedTPMessageReference; + return this; + } + + /** + * Set the user id associated with this subscription. + * + * @param userId The user id associated with this subscription. + * @return The builder. + */ + @NonNull + public Builder setUserId(int userId) { + mUserId = userId; + return this; + } + + // Below are the fields that do not exist in the SimInfo table. + /** + * Set the card ID of the SIM card which contains the subscription. + * + * @param cardId The card ID of the SIM card which contains the subscription. + * @return The builder. + */ + @NonNull + public Builder setCardId(int cardId) { + mCardId = cardId; + return this; + } + + /** + * Whether group of the subscription is disabled. This is only useful if it's a grouped + * opportunistic subscription. In this case, if all primary (non-opportunistic) + * subscriptions in the group are deactivated (unplugged pSIM or deactivated eSIM profile), + * we should disable this opportunistic subscription. + * + * @param isGroupDisabled {@code true} if group of the subscription is disabled. + * @return The builder. + */ + @NonNull + public Builder setGroupDisabled(boolean isGroupDisabled) { + mIsGroupDisabled = isGroupDisabled; + return this; + } + + /** + * Build the {@link SubscriptionInfoInternal}. + * + * @return The {@link SubscriptionInfoInternal} instance. + */ + public SubscriptionInfoInternal build() { + return new SubscriptionInfoInternal(this); + } + } +} diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index d543e04b61..521b08c3f2 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -19,6 +19,7 @@ package com.android.internal.telephony.subscription; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.os.HandlerThread; import android.os.ParcelUuid; import android.os.TelephonyServiceManager; import android.telephony.SubscriptionInfo; @@ -54,6 +55,9 @@ public class SubscriptionManagerService extends ISub.Stub { /** Local log for most important debug messages. */ private final LocalLog mLocalLog = new LocalLog(128); + /** The subscription database manager. */ + private final SubscriptionDatabaseManager mSubscriptionDatabaseManager; + /** * The constructor * @@ -66,6 +70,13 @@ public class SubscriptionManagerService extends ISub.Stub { .getTelephonyServiceManager() .getSubscriptionServiceRegisterer(); subscriptionServiceRegisterer.register(this); + + // Create a separate thread for subscription database manager. The database will be updated + // from a different thread. + HandlerThread handlerThread = new HandlerThread(LOG_TAG); + handlerThread.start(); + mSubscriptionDatabaseManager = new SubscriptionDatabaseManager(context, + handlerThread.getLooper()); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java new file mode 100644 index 0000000000..f4db542bfe --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -0,0 +1,892 @@ +/* + * Copyright 2022 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.subscription; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; + +import android.annotation.NonNull; +import android.content.ContentUris; +import android.content.ContentValues; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.os.Looper; +import android.provider.Telephony; +import android.telephony.SubscriptionManager; +import android.telephony.UiccAccessRule; +import android.telephony.ims.ImsMmTelManager; +import android.test.mock.MockContentProvider; +import android.test.mock.MockContentResolver; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class SubscriptionDatabaseManagerTest extends TelephonyTest { + private static final String FAKE_ICCID1 = "123456"; + private static final String FAKE_ICCID2 = "456789"; + private static final String FAKE_PHONE_NUMBER1 = "6502530000"; + private static final String FAKE_PHONE_NUMBER2 = "4089961010"; + private static final String FAKE_CARRIER_NAME1 = "A-Mobile"; + private static final String FAKE_CARRIER_NAME2 = "B-Mobile"; + private static final int FAKE_COLOR1 = 1; + private static final int FAKE_COLOR2 = 3; + private static final int FAKE_CARRIER_ID1 = 1234; + private static final int FAKE_CARRIER_ID2 = 5678; + private static final String FAKE_COUNTRY_CODE1 = "TW"; + private static final String FAKE_COUNTRY_CODE2 = "US"; + private static final String FAKE_MCC1 = "466"; + private static final String FAKE_MCC2 = "310"; + private static final String FAKE_MNC1 = "01"; + private static final String FAKE_MNC2 = "410"; + private static final String FAKE_EHPLMNS1 = "46602,46603"; + private static final String FAKE_EHPLMNS2 = "310411,310412"; + private static final String FAKE_HPLMNS1 = "46601,46604"; + private static final String FAKE_HPLMNS2 = "310410,310413"; + private static final byte[] FAKE_NATIVE_ACCESS_RULES1 = UiccAccessRule.encodeRules( + new UiccAccessRule[]{new UiccAccessRule(new byte[] {}, "package1", 12345L)}); + private static final byte[] FAKE_NATIVE_ACCESS_RULES2 = UiccAccessRule.encodeRules( + new UiccAccessRule[]{new UiccAccessRule(new byte[] {}, "package2", 45678L)}); + private static final byte[] FAKE_CARRIER_CONFIG_ACCESS_RULES1 = UiccAccessRule.encodeRules( + new UiccAccessRule[]{new UiccAccessRule(new byte[] {}, "package1", 54321L)}); + private static final byte[] FAKE_CARRIER_CONFIG_ACCESS_RULES2 = UiccAccessRule.encodeRules( + new UiccAccessRule[]{new UiccAccessRule(new byte[] {}, "package2", 84954L)}); + private static final String FAKE_UUID1 = "a684e31a-5998-4670-abdd-0561252c58a5"; + private static final String FAKE_UUID2 = "cf6d7a9d-e712-4b3c-a600-7a2d4961b5b9"; + private static final String FAKE_OWNER1 = "owner1"; + private static final String FAKE_OWNER2 = "owner2"; + private static final String FAKE_MOBILE_DATA_POLICY1 = "1,2"; + private static final String FAKE_MOBILE_DATA_POLICY2 = "1"; + private static final String FAKE_IMSI1 = "1234"; + private static final String FAKE_IMSI2 = "5678"; + private static final byte[] FAKE_RCS_CONFIG1 = new byte[]{0x01, 0x02, 0x03}; + private static final byte[] FAKE_RCS_CONFIG2 = new byte[]{0x04, 0x05, 0x06}; + private static final String FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS1 = "carrier=123456, power=3"; + private static final String FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2 = "user=1256, enable_2g=3"; + private static final String FAKE_CONTACT1 = "John Smith, Tesla Forrest"; + private static final String FAKE_CONTACT2 = "Mary Jane, Teresa Mill"; + private static final int FAKE_TP_MESSAGE_REFERENCE1 = 123; + private static final int FAKE_TP_MESSAGE_REFERENCE2 = 456; + private static final int FAKE_USER_ID1 = 10; + private static final int FAKE_USER_ID2 = 11; + + private static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO1 = + new SubscriptionInfoInternal.Builder() + .setIccId(FAKE_ICCID1) + .setSimSlotIndex(0) + .setDisplayName(FAKE_CARRIER_NAME1) + .setCarrierName(FAKE_CARRIER_NAME1) + .setDisplayNameSource(SubscriptionManager.NAME_SOURCE_SIM_SPN) + .setIconTint(FAKE_COLOR1) + .setNumber(FAKE_PHONE_NUMBER1) + .setDataRoaming(SubscriptionManager.DATA_ROAMING_ENABLE) + .setMcc(FAKE_MCC1) + .setMnc(FAKE_MNC1) + .setEhplmns(FAKE_EHPLMNS1) + .setHplmns(FAKE_HPLMNS1) + .setEmbedded(1) + .setCardString(FAKE_ICCID1) + .setCardId(1) + .setNativeAccessRules(FAKE_NATIVE_ACCESS_RULES1) + .setCarrierConfigAccessRules(FAKE_CARRIER_CONFIG_ACCESS_RULES1) + .setRemovableEmbedded(0) + .setEnhanced4GModeEnabled(1) + .setVideoTelephonyEnabled(1) + .setWifiCallingEnabled(1) + .setWifiCallingMode(ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED) + .setWifiCallingModeForRoaming(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED) + .setWifiCallingModeForRoaming(1) + .setOpportunistic(0) + .setGroupUuid(FAKE_UUID1) + .setCountryIso(FAKE_COUNTRY_CODE1) + .setCarrierId(FAKE_CARRIER_ID1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL) + .setType(SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM) + .setGroupOwner(FAKE_OWNER1) + .setEnabledMobileDataPolicies(FAKE_MOBILE_DATA_POLICY1) + .setImsi(FAKE_IMSI1) + .setUiccApplicationsEnabled(1) + .setRcsUceEnabled(1) + .setCrossSimCallingEnabled(1) + .setRcsConfig(FAKE_RCS_CONFIG1) + .setAllowedNetworkTypesForReasons(FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS1) + .setDeviceToDeviceStatusSharingPreference( + SubscriptionManager.D2D_SHARING_ALL_CONTACTS) + .setVoImsOptInEnabled(1) + .setDeviceToDeviceStatusSharingContacts(FAKE_CONTACT1) + .setNrAdvancedCallingEnabled(1) + .setNumberFromCarrier(FAKE_PHONE_NUMBER1) + .setNumberFromIms(FAKE_PHONE_NUMBER1) + .setPortIndex(0) + .setUsageSetting(SubscriptionManager.USAGE_SETTING_DEFAULT) + .setLastUsedTPMessageReference(FAKE_TP_MESSAGE_REFERENCE1) + .setUserId(FAKE_USER_ID1) + .setGroupDisabled(false) + .build(); + + private static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO2 = + new SubscriptionInfoInternal.Builder() + .setIccId(FAKE_ICCID2) + .setSimSlotIndex(1) + .setDisplayName(FAKE_CARRIER_NAME2) + .setCarrierName(FAKE_CARRIER_NAME2) + .setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) + .setIconTint(FAKE_COLOR2) + .setNumber(FAKE_PHONE_NUMBER2) + .setDataRoaming(SubscriptionManager.DATA_ROAMING_DISABLE) + .setMcc(FAKE_MCC2) + .setMnc(FAKE_MNC2) + .setEhplmns(FAKE_EHPLMNS2) + .setHplmns(FAKE_HPLMNS2) + .setEmbedded(0) + .setCardString(FAKE_ICCID2) + .setCardId(2) + .setNativeAccessRules(FAKE_NATIVE_ACCESS_RULES2) + .setCarrierConfigAccessRules(FAKE_CARRIER_CONFIG_ACCESS_RULES2) + .setRemovableEmbedded(1) + .setEnhanced4GModeEnabled(0) + .setVideoTelephonyEnabled(0) + .setWifiCallingEnabled(0) + .setWifiCallingMode(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED) + .setWifiCallingModeForRoaming(ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED) + .setWifiCallingModeForRoaming(0) + .setOpportunistic(1) + .setGroupUuid(FAKE_UUID2) + .setCountryIso(FAKE_COUNTRY_CODE2) + .setCarrierId(FAKE_CARRIER_ID2) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING) + .setType(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM) + .setGroupOwner(FAKE_OWNER2) + .setEnabledMobileDataPolicies(FAKE_MOBILE_DATA_POLICY2) + .setImsi(FAKE_IMSI2) + .setUiccApplicationsEnabled(0) + .setRcsUceEnabled(0) + .setCrossSimCallingEnabled(0) + .setRcsConfig(FAKE_RCS_CONFIG2) + .setAllowedNetworkTypesForReasons(FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2) + .setDeviceToDeviceStatusSharingPreference( + SubscriptionManager.D2D_SHARING_SELECTED_CONTACTS) + .setVoImsOptInEnabled(0) + .setDeviceToDeviceStatusSharingContacts(FAKE_CONTACT2) + .setNrAdvancedCallingEnabled(0) + .setNumberFromCarrier(FAKE_PHONE_NUMBER2) + .setNumberFromIms(FAKE_PHONE_NUMBER2) + .setPortIndex(1) + .setUsageSetting(SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) + .setLastUsedTPMessageReference(FAKE_TP_MESSAGE_REFERENCE2) + .setUserId(FAKE_USER_ID2) + .setGroupDisabled(false) + .build(); + + private SubscriptionDatabaseManager mDatabaseManagerUT; + + private final SubscriptionProvider mSubscriptionProvider = new SubscriptionProvider(); + + private static class SubscriptionProvider extends MockContentProvider { + private final List mDatabase = new ArrayList<>(); + + private final List mAllColumns; + + SubscriptionProvider() { + mAllColumns = Telephony.SimInfo.getAllColumns(); + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + logd("SubscriptionProvider: query. uri=" + uri); + if (!Telephony.SimInfo.CONTENT_URI.equals(uri)) { + throw new UnsupportedOperationException("Unsupported uri=" + uri); + } + if (projection != null || selection != null || selectionArgs != null) { + throw new UnsupportedOperationException("Only support full database query. " + + "projection=" + Arrays.toString(projection) + ", selection=" + selection + + ", selectionArgs=" + Arrays.toString(selectionArgs)); + } + + MatrixCursor mc = new MatrixCursor(mAllColumns.toArray(new String[0])); + + // Only support full database query + for (int row = 0; row < mDatabase.size(); row++) { + List values = new ArrayList<>(); + for (String column : mAllColumns) { + values.add(mDatabase.get(row).get(column)); + } + mc.addRow(values); + } + + return mc; + } + + @Override + public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { + if (!uri.isPathPrefixMatch(Telephony.SimInfo.CONTENT_URI)) { + throw new UnsupportedOperationException("Unsupported uri=" + uri); + } + + int subId = Integer.parseInt(uri.getLastPathSegment()); + assertThat(mDatabase.size()).isAtLeast(subId); + + ContentValues existingValues = mDatabase.get(subId - 1); + logd("update: subId=" + subId + ", contentValues=" + values); + for (Map.Entry entry : values.valueSet()) { + String column = entry.getKey(); + Object value = entry.getValue(); + if (!mAllColumns.contains(column)) { + throw new IllegalArgumentException("Update with unknown column " + column); + } + existingValues.putObject(column, value); + } + return 1; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("delete is not supported uri=" + uri); + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + logd("SubscriptionProvider: insert. uri=" + uri + ", values=" + values); + if (!Telephony.SimInfo.CONTENT_URI.equals(uri)) { + throw new UnsupportedOperationException("Unsupported uri=" + uri); + } + + for (String column : values.keySet()) { + if (!mAllColumns.contains(column)) { + throw new IllegalArgumentException("Insert with unknown column " + column); + } + } + int subId = mDatabase.size() + 1; + values.put(Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, subId); + mDatabase.add(values); + return ContentUris.withAppendedId(Telephony.SimInfo.CONTENT_URI, subId); + } + } + + private void loadFromDatabase() throws Exception { + Method method = SubscriptionDatabaseManager.class.getDeclaredMethod("loadFromDatabase"); + method.setAccessible(true); + method.invoke(mDatabaseManagerUT); + processAllMessages(); + } + + @Before + public void setUp() throws Exception { + logd("SubscriptionDatabaseManagerTest +Setup!"); + super.setUp(getClass().getSimpleName()); + ((MockContentResolver) mContext.getContentResolver()).addProvider( + Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); + doReturn(1).when(mUiccController).convertToPublicCardId(eq(FAKE_ICCID1)); + doReturn(2).when(mUiccController).convertToPublicCardId(eq(FAKE_ICCID2)); + mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper()); + logd("SubscriptionDatabaseManagerTest -Setup!"); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Verify the subscription from the cache and database is same as the provided one. + * + * @param subInfo The subscription to compare. + */ + private void verifySubscription(@NonNull SubscriptionInfoInternal subInfo) throws Exception { + int subId = subInfo.getSubscriptionId(); + // Verify the cache value is same as the inserted one. + assertWithMessage("Subscription info cache value is different.") + .that(mDatabaseManagerUT.getSubscriptionInfoInternal(subId)).isEqualTo(subInfo); + + // Load subscription info from the database. + loadFromDatabase(); + // Verify the database value is same as the inserted one. + assertWithMessage("Subscription info database value is different.") + .that(mDatabaseManagerUT.getSubscriptionInfoInternal(subId)).isEqualTo(subInfo); + } + + /** + * Insert a subscription info into the database and verify it's in the cache and database. + * + * @param subInfo The subscription info to insert. + * @return The inserted subscription info. + */ + private SubscriptionInfoInternal insertSubscriptionAndVerify( + @NonNull SubscriptionInfoInternal subInfo) throws Exception { + assertThat(subInfo.getSubscriptionId()).isEqualTo( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + int subId = mDatabaseManagerUT.insertSubscriptionInfo(subInfo); + assertThat(SubscriptionManager.isValidSubscriptionId(subId)).isTrue(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setId(subId).build(); + verifySubscription(subInfo); + return subInfo; + } + + @Test + public void testGetAllColumns() throws Exception { + Field[] declaredFields = Telephony.SimInfo.class.getDeclaredFields(); + List columnNames = new ArrayList<>(); + for (Field field : declaredFields) { + if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("COLUMN_")) { + columnNames.add((String) field.get(null)); + } + } + // When you add a new column in Telephony.SimInfo, did you remember to modify + // Telephony.SimInfo.getAllColumns() as well? + assertThat(Telephony.SimInfo.getAllColumns()).containsExactlyElementsIn(columnNames); + } + + @Test + public void testInsertSubscription() throws Exception { + assertThat(insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1).getSubscriptionId()) + .isEqualTo(1); + assertThat(insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO2).getSubscriptionId()) + .isEqualTo(2); + } + + @Test + public void testUpdateSubscription() throws Exception { + assertThat(insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1).getSubscriptionId()) + .isEqualTo(1); + SubscriptionInfoInternal subInfo = new SubscriptionInfoInternal + .Builder(FAKE_SUBSCRIPTION_INFO2) + .setId(1) + .build(); + mDatabaseManagerUT.updateSubscription(subInfo); + processAllMessages(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateIccId() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setIccId(subInfo.getSubscriptionId(), FAKE_ICCID2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setIccId(FAKE_ICCID2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateSimSlotIndex() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setSimSlotIndex(subInfo.getSubscriptionId(), + SubscriptionManager.INVALID_SIM_SLOT_INDEX); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setSimSlotIndex( + SubscriptionManager.INVALID_SIM_SLOT_INDEX).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateDisplayName() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setDisplayName(subInfo.getSubscriptionId(), FAKE_CARRIER_NAME2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setDisplayName( + FAKE_CARRIER_NAME2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateCarrierName() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCarrierName(subInfo.getSubscriptionId(), FAKE_CARRIER_NAME2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setCarrierName( + FAKE_CARRIER_NAME2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateDisplayNameSource() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCarrierName(subInfo.getSubscriptionId(), FAKE_CARRIER_NAME2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setCarrierName( + FAKE_CARRIER_NAME2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateIconTint() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setIconTint(subInfo.getSubscriptionId(), FAKE_COLOR2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setIconTint(FAKE_COLOR2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateNumber() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setNumber(subInfo.getSubscriptionId(), FAKE_PHONE_NUMBER2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setNumber(FAKE_PHONE_NUMBER2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateDataRoaming() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setDataRoaming(subInfo.getSubscriptionId(), + SubscriptionManager.DATA_ROAMING_DISABLE); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setDataRoaming(SubscriptionManager.DATA_ROAMING_DISABLE).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateMcc() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setMcc(subInfo.getSubscriptionId(), FAKE_MCC2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setMcc(FAKE_MCC2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateMnc() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setMnc(subInfo.getSubscriptionId(), FAKE_MNC2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setMnc(FAKE_MNC2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateEhplmns() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setEhplmns(subInfo.getSubscriptionId(), FAKE_EHPLMNS2.split(",")); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setEhplmns(FAKE_EHPLMNS2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateHplmns() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setHplmns(subInfo.getSubscriptionId(), FAKE_HPLMNS2.split(",")); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setHplmns(FAKE_HPLMNS2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateEmbedded() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setEmbedded(subInfo.getSubscriptionId(), false); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setEmbedded(0).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateCardString() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCardString(subInfo.getSubscriptionId(), FAKE_ICCID2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCardString(FAKE_ICCID2) + .setCardId(2) + .build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateNativeAccessRules() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setNativeAccessRules(subInfo.getSubscriptionId(), + UiccAccessRule.decodeRules(FAKE_NATIVE_ACCESS_RULES2)); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setNativeAccessRules(FAKE_NATIVE_ACCESS_RULES2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateCarrierConfigAccessRules() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCarrierConfigAccessRules(subInfo.getSubscriptionId(), + UiccAccessRule.decodeRules(FAKE_CARRIER_CONFIG_ACCESS_RULES2)); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCarrierConfigAccessRules(FAKE_CARRIER_CONFIG_ACCESS_RULES2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateRemovableEmbedded() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setRemovableEmbedded(subInfo.getSubscriptionId(), true); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setRemovableEmbedded(1).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateEnhanced4GModeEnabled() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setEnhanced4GModeEnabled(subInfo.getSubscriptionId(), false); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setEnhanced4GModeEnabled(0).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateVideoTelephonyEnabled() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setVideoTelephonyEnabled(subInfo.getSubscriptionId(), false); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setVideoTelephonyEnabled(0).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateWifiCallingEnabled() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setWifiCallingEnabled(subInfo.getSubscriptionId(), false); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setWifiCallingEnabled(0).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateWifiCallingMode() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setWifiCallingMode(subInfo.getSubscriptionId(), + ImsMmTelManager.WIFI_MODE_WIFI_ONLY); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setWifiCallingMode(ImsMmTelManager.WIFI_MODE_WIFI_ONLY).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateWifiCallingModeForRoaming() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setWifiCallingModeForRoaming(subInfo.getSubscriptionId(), + ImsMmTelManager.WIFI_MODE_WIFI_ONLY); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setWifiCallingModeForRoaming(ImsMmTelManager.WIFI_MODE_WIFI_ONLY).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateWifiCallingEnabledForRoaming() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setWifiCallingEnabledForRoaming(subInfo.getSubscriptionId(), false); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setWifiCallingEnabledForRoaming(0).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateOpportunistic() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setOpportunistic(subInfo.getSubscriptionId(), true); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setOpportunistic(1).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateGroupUuid() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setGroupUuid(subInfo.getSubscriptionId(), FAKE_UUID2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setGroupUuid(FAKE_UUID2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateCountryIso() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCountryIso(subInfo.getSubscriptionId(), FAKE_COUNTRY_CODE2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCountryIso(FAKE_COUNTRY_CODE2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateCarrierId() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCarrierId(subInfo.getSubscriptionId(), FAKE_CARRIER_ID2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCarrierId(FAKE_CARRIER_ID2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateProfileClass() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setProfileClass(subInfo.getSubscriptionId(), + SubscriptionManager.PROFILE_CLASS_TESTING); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_TESTING).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateSubscriptionType() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setSubscriptionType(subInfo.getSubscriptionId(), + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setType(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateGroupOwner() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setGroupOwner(subInfo.getSubscriptionId(), FAKE_OWNER2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setGroupOwner(FAKE_OWNER2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateEnabledMobileDataPolicies() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setEnabledMobileDataPolicies(subInfo.getSubscriptionId(), + FAKE_MOBILE_DATA_POLICY2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setEnabledMobileDataPolicies(FAKE_MOBILE_DATA_POLICY2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateImsi() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setImsi(subInfo.getSubscriptionId(), FAKE_IMSI2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setImsi(FAKE_IMSI2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateUiccApplicationsEnabled() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setUiccApplicationsEnabled(subInfo.getSubscriptionId(), false); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setUiccApplicationsEnabled(0).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateRcsUceEnabled() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setRcsUceEnabled(subInfo.getSubscriptionId(), false); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setRcsUceEnabled(0).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateCrossSimCallingEnabled() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCrossSimCallingEnabled(subInfo.getSubscriptionId(), false); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCrossSimCallingEnabled(0).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateRcsConfig() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setRcsConfig(subInfo.getSubscriptionId(), FAKE_RCS_CONFIG2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setRcsConfig(FAKE_RCS_CONFIG2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateAllowedNetworkTypesForReasons() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setAllowedNetworkTypesForReasons(subInfo.getSubscriptionId(), + FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setAllowedNetworkTypesForReasons(FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateDeviceToDeviceStatusSharingPreference() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setDeviceToDeviceStatusSharingPreference(subInfo.getSubscriptionId(), + SubscriptionManager.D2D_SHARING_DISABLED); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setDeviceToDeviceStatusSharingPreference( + SubscriptionManager.D2D_SHARING_DISABLED).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateNrAdvancedCallingEnabled() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setNrAdvancedCallingEnabled(subInfo.getSubscriptionId(), false); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setNrAdvancedCallingEnabled(0).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateNumberFromCarrier() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setNumberFromCarrier(subInfo.getSubscriptionId(), FAKE_PHONE_NUMBER2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setNumberFromCarrier(FAKE_PHONE_NUMBER2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateNumberFromIms() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setNumberFromIms(subInfo.getSubscriptionId(), FAKE_PHONE_NUMBER2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setNumberFromIms(FAKE_PHONE_NUMBER2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdatePortIndex() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setPortIndex(subInfo.getSubscriptionId(), 1); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setPortIndex(1).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateUsageSetting() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setUsageSetting(subInfo.getSubscriptionId(), + SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setUsageSetting(SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateLastUsedTPMessageReference() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setLastUsedTPMessageReference(subInfo.getSubscriptionId(), + FAKE_TP_MESSAGE_REFERENCE2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setLastUsedTPMessageReference(FAKE_TP_MESSAGE_REFERENCE2).build(); + verifySubscription(subInfo); + } + + @Test + public void testUpdateUserId() throws Exception { + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setUserId(subInfo.getSubscriptionId(), FAKE_USER_ID2); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setUserId(FAKE_USER_ID2).build(); + verifySubscription(subInfo); + } +} -- GitLab From 130a2c16bb30a35115533968140b3f2e682a0008 Mon Sep 17 00:00:00 2001 From: Grant Menke Date: Mon, 17 Oct 2022 22:37:24 +0000 Subject: [PATCH 118/656] Add helper functions for emergency device configs. Added helper functions to check two new demergency number database related device configs. The first new device configs returns a boolean representing whether modem/config sourced emergency numbers should be ignored. The second new device config returns a boolean representing whether emergency number routing defined in the android emergency number database should be ignored. Bug: 247636518 Test: manual Change-Id: I1398f36070799a7b9c8c01ec084853cb26bf610b --- .../emergency/EmergencyNumberTracker.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index b346636a92..f9837df333 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -21,6 +21,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.os.AsyncResult; import android.os.Environment; import android.os.Handler; @@ -102,6 +103,8 @@ public class EmergencyNumberTracker extends Handler { private String mLastKnownEmergencyCountryIso = ""; private int mCurrentDatabaseVersion = INVALID_DATABASE_VERSION; private boolean mIsHalVersionLessThan1Dot4 = false; + private Resources mResources = null; + /** * Indicates if the country iso is set by another subscription. * @hide @@ -168,6 +171,7 @@ public class EmergencyNumberTracker extends Handler { public EmergencyNumberTracker(Phone phone, CommandsInterface ci) { mPhone = phone; mCi = ci; + mResources = mPhone.getContext().getResources(); if (mPhone != null) { mPhoneId = phone.getPhoneId(); @@ -1137,6 +1141,28 @@ public class EmergencyNumberTracker extends Handler { } } + /** + * @return {@code true} if emergency numbers sourced from modem/config should be ignored. + * {@code false} if emergency numbers sourced from modem/config should not be ignored. + */ + @VisibleForTesting + public boolean shouldModemConfigEmergencyNumbersBeIgnored() { + return mResources.getBoolean(com.android.internal.R.bool + .ignore_modem_config_emergency_numbers); + } + + /** + * @return {@code true} if emergency number routing from the android emergency number + * database should be ignored. + * {@code false} if emergency number routing from the android emergency number database + * should not be ignored. + */ + @VisibleForTesting + public boolean shouldEmergencyNumberRoutingFromDbBeIgnored() { + return mResources.getBoolean(com.android.internal.R.bool + .ignore_emergency_number_routing_from_db); + } + /** * Dump Emergency Number List info in the tracking * -- GitLab From 08d6ef5f5e4c65493a8747ddb8413c1f9ac1bc4e Mon Sep 17 00:00:00 2001 From: Diaesh Antony Date: Thu, 29 Sep 2022 16:19:23 +0800 Subject: [PATCH 119/656] [DSRM] Fix for failing to perform data stall recovery soon after skipping data recovery action under poor network signal. Symptom: If a data stall recovery is skipped under poor network signal strength for the very first time. Then in the next iteration, data stall recovery is skipped due to mIsValidNetwork flag remains false always. Solution: Refactor the existing conditions for data stall recovery. Bug: 249687945 Test: Manual test passed. Signed-off-by: Diaesh Antony Change-Id: I16abe882dfc965b7f48b37d79e5e678efbc490b0 --- .../data/DataStallRecoveryManager.java | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index e46781595f..d0120331ba 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -151,6 +151,8 @@ public class DataStallRecoveryManager extends Handler { private @ElapsedRealtimeLong long mTimeLastRecoveryStartMs; /** Whether current network is good or not */ private boolean mIsValidNetwork; + /** Whether data stall recovery is triggered or not */ + private boolean mRecoveryTriggered = false; /** Whether data stall happened or not. */ private boolean mDataStalled; /** Whether the result of last action(RADIO_RESTART) reported. */ @@ -352,6 +354,7 @@ public class DataStallRecoveryManager extends Handler { */ private void reset() { mIsValidNetwork = true; + mRecoveryTriggered = false; mIsAttemptedAllSteps = false; mRadioStateChangedDuringDataStall = false; mIsAirPlaneModeEnableDuringDataStall = false; @@ -373,15 +376,12 @@ public class DataStallRecoveryManager extends Handler { setNetworkValidationState(isValid); if (isValid) { reset(); - } else { - if (mIsValidNetwork || isRecoveryAlreadyStarted()) { - mIsValidNetwork = false; - if (isRecoveryNeeded(true)) { - log("trigger data stall recovery"); - mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime(); - sendMessage(obtainMessage(EVENT_DO_RECOVERY)); - } - } + } else if (isRecoveryNeeded(true)) { + // Set the network as invalid, because recovery is needed + mIsValidNetwork = false; + log("trigger data stall recovery"); + mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime(); + sendMessage(obtainMessage(EVENT_DO_RECOVERY)); } } @@ -455,7 +455,7 @@ public class DataStallRecoveryManager extends Handler { * @return {@code true} if recovery already started, {@code false} recovery not started. */ private boolean isRecoveryAlreadyStarted() { - return getRecoveryAction() != RECOVERY_ACTION_GET_DATA_CALL_LIST; + return getRecoveryAction() != RECOVERY_ACTION_GET_DATA_CALL_LIST || mRecoveryTriggered; } /** @@ -542,6 +542,12 @@ public class DataStallRecoveryManager extends Handler { private boolean isRecoveryNeeded(boolean isNeedToCheckTimer) { logv("enter: isRecoveryNeeded()"); + // Skip if network is invalid and recovery was not started yet + if (!mIsValidNetwork && !isRecoveryAlreadyStarted()) { + logl("skip when network still remains invalid and recovery was not started yet"); + return false; + } + // Skip recovery if we have already attempted all steps. if (mIsAttemptedAllSteps) { logl("skip retrying continue recovery action"); @@ -577,7 +583,6 @@ public class DataStallRecoveryManager extends Handler { logl("skip data stall recovery as data not connected"); return false; } - return true; } @@ -652,6 +657,7 @@ public class DataStallRecoveryManager extends Handler { private void doRecovery() { @RecoveryAction final int recoveryAction = getRecoveryAction(); final int signalStrength = mPhone.getSignalStrength().getLevel(); + mRecoveryTriggered = true; // DSRM used sendMessageDelayed to process the next event EVENT_DO_RECOVERY, so it need // to check the condition if DSRM need to process the recovery action. -- GitLab From aa5ea3df62c6c90f4c894ca9239ac19ad592bf37 Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Fri, 21 Oct 2022 00:43:46 +0000 Subject: [PATCH 120/656] Revert "N3IWF HAL support: update NetworkResponse" Revert submission 20057104-hal_support_n3iwf Reason for revert: Reverted Changes: Ie7784ffa3:Update IRadioNetworkImpl of MockModem Iad6a6cc2e:N3IWF HAL support: update NetworkResponse I2b5506d84:Radio HAL : Support N3IWF cuttlefish work I8b4b055be:Radio HAL : Support N3IWF Change-Id: I948ccf67e41215ac28c0b114b69f12959c867ba0 --- .../internal/telephony/NetworkResponse.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index 43ee2ead84..5f5895e16c 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -473,22 +473,6 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); } - /** - * @param responseInfo Response info struct containing response type, serial no. and error - * @param regResponse Current registration response as defined by RegStateResult - */ - public void getRegistrationStateResponse(RadioResponseInfo responseInfo, - android.hardware.radio.network.RegStateResult regResponse) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); - - if (rr != null) { - if (responseInfo.error == RadioError.NONE) { - RadioResponse.sendMessageResponse(rr.mResult, regResponse); - } - mRil.processResponseDone(rr, responseInfo, regResponse); - } - } - @Override public String getInterfaceHash() { return IRadioNetworkResponse.HASH; -- GitLab From ce5af6720faa41a2ccab930ae697000bf2e6e6ad Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 20 Oct 2022 15:17:08 -0700 Subject: [PATCH 121/656] Use voice RAT to select data profile when data OOS We allow data for nonDDS if voice is in service in some conditions. This change uses voice RAT, instead of data RAT, to select data profile when such condition is met. Bug: 253536472 Test: atest Change-Id: I99e2e6eee5565727cb2fcde76d220f74724664aa --- .../telephony/data/DataNetworkController.java | 11 ++++- .../data/DataNetworkControllerTest.java | 47 ++++++++++++------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 53e5ccac84..d088b3d527 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -1310,7 +1310,7 @@ public class DataNetworkController extends Handler { if (nriRegState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME || nriRegState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING) return true; - // If data is OOS on the non-DDS, + // If data is OOS as this device slot is not modem preferred(i.e. not active for internet), // attempt to attach PS on 2G/3G if CS connection is available. return ss.getVoiceRegState() == ServiceState.STATE_IN_SERVICE && mPhone.getPhoneId() != PhoneSwitcher.getInstance().getPreferredDataPhoneId() @@ -1568,8 +1568,15 @@ public class DataNetworkController extends Handler { } // Check if there is any compatible data profile + int networkType = getDataNetworkType(transport); + if (networkType == TelephonyManager.NETWORK_TYPE_UNKNOWN + && transport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + // reach here when data is OOS but serviceStateAllowsPSAttach == true, so we adopt the + // voice RAT to select data profile + networkType = mServiceState.getVoiceNetworkType(); + } DataProfile dataProfile = mDataProfileManager - .getDataProfileForNetworkRequest(networkRequest, getDataNetworkType(transport)); + .getDataProfileForNetworkRequest(networkRequest, networkType); if (dataProfile == null) { evaluation.addDataDisallowedReason(DataDisallowedReason.NO_SUITABLE_DATA_PROFILE); } else if (reason == DataEvaluationReason.NEW_REQUEST 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 89f7a5be35..af0e56ee19 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -75,7 +75,6 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionPlan; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; -import android.telephony.TelephonyProtoEnums; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataCallResponse.LinkStatus; @@ -492,6 +491,20 @@ public class DataNetworkControllerTest extends TelephonyTest { private void serviceStateChanged(@NetworkType int networkType, @RegistrationState int dataRegState, @RegistrationState int voiceRegState, @RegistrationState int iwlanRegState, DataSpecificRegistrationInfo dsri) { + ServiceState ss = createSS(networkType, networkType, dataRegState, voiceRegState, + iwlanRegState, dsri); + + doReturn(ss).when(mSST).getServiceState(); + doReturn(ss).when(mPhone).getServiceState(); + + mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + processAllMessages(); + } + + private ServiceState createSS(@NetworkType int dataNetworkType, + @NetworkType int voiceNetworkType, + @RegistrationState int dataRegState, @RegistrationState int voiceRegState, + @RegistrationState int iwlanRegState, DataSpecificRegistrationInfo dsri) { if (dsri == null) { dsri = new DataSpecificRegistrationInfo(8, false, true, true, new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, @@ -502,7 +515,7 @@ public class DataNetworkControllerTest extends TelephonyTest { ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(networkType) + .setAccessNetworkTechnology(dataNetworkType) .setRegistrationState(dataRegState) .setDomain(NetworkRegistrationInfo.DOMAIN_PS) .setDataSpecificInfo(dsri) @@ -517,19 +530,15 @@ public class DataNetworkControllerTest extends TelephonyTest { ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(networkType) + .setAccessNetworkTechnology(voiceNetworkType) .setRegistrationState(voiceRegState) .setDomain(NetworkRegistrationInfo.DOMAIN_CS) .build()); + ss.setDataRoamingFromRegistration(dataRegState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); processServiceStateRegStateForTest(ss); - - doReturn(ss).when(mSST).getServiceState(); - doReturn(ss).when(mPhone).getServiceState(); - - mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); - processAllMessages(); + return ss; } // set SS reg state base on SST impl, where WLAN overrides WWAN's data reg. @@ -3583,7 +3592,7 @@ public class DataNetworkControllerTest extends TelephonyTest { mDataNetworkControllerUT.addNetworkRequest(request); processAllMessages(); - // Now DDS temporarily switched to phone 1 + // this slot is 0, modem preferred on slot 1 doReturn(1).when(mMockedPhoneSwitcher).getPreferredDataPhoneId(); // Simulate telephony network factory remove request due to switch. @@ -3596,13 +3605,13 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testSetupDataOnNonDds() throws Exception { - // Now DDS switched to phone 1 + // this slot is 0, modem preferred on slot 1 doReturn(1).when(mMockedPhoneSwitcher).getPreferredDataPhoneId(); TelephonyNetworkRequest request = createNetworkRequest( NetworkCapabilities.NET_CAPABILITY_MMS); // Test Don't allow setup if both data and voice OOS - serviceStateChanged(TelephonyProtoEnums.NETWORK_TYPE_1XRTT, + serviceStateChanged(TelephonyManager.NETWORK_TYPE_1xRTT, // data, voice, Iwlan reg state NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, @@ -3613,18 +3622,24 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyAllDataDisconnected(); // Test Don't allow setup if CS is in service, but current RAT is already PS(e.g. LTE) - serviceStateChanged(TelephonyProtoEnums.NETWORK_TYPE_LTE, + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, null); verifyAllDataDisconnected(); - // Test Allow if voice is in service if RAT is 2g/3g - serviceStateChanged(TelephonyProtoEnums.NETWORK_TYPE_1XRTT, - NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, + // Test Allow if voice is in service if RAT is 2g/3g, use voice RAT to select data profile + ServiceState ss = createSS(TelephonyManager.NETWORK_TYPE_UNKNOWN /* data RAT */, + TelephonyManager.NETWORK_TYPE_1xRTT /* voice RAT */, + NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING , NetworkRegistrationInfo.REGISTRATION_STATE_HOME, NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, null); + doReturn(ss).when(mSST).getServiceState(); + mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); + mDataNetworkControllerUT.removeNetworkRequest(request); + mDataNetworkControllerUT.addNetworkRequest(request); + processAllMessages(); verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); } -- GitLab From 8abebce072c4fa9095159cf4a6a2bcbf4f37c007 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Sun, 28 Aug 2022 13:34:33 -0700 Subject: [PATCH 122/656] Add auto data switch feature The feature is enabled via TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH. The feature only applies to non-DDS. If enabled, we automatically switch to the non-DDS for data traffic when it has better availability than the DDS. Bug: 244064524 Test: cts + UT + manual test in DSDS/single sim/wifi/APM scenario. Change-Id: I0aa793d73f88de022944566d34f889b894f3b24f --- proto/src/telephony.proto | 3 + .../telephony/ServiceStateTracker.java | 5 +- .../telephony/data/DataConfigManager.java | 49 ++ .../internal/telephony/data/DataNetwork.java | 2 +- .../telephony/data/DataNetworkController.java | 4 +- .../telephony/data/DataSettingsManager.java | 17 +- .../telephony/data/PhoneSwitcher.java | 623 ++++++++++++---- .../data/DataNetworkControllerTest.java | 49 +- .../telephony/data/DataNetworkTest.java | 2 +- .../telephony/data/PhoneSwitcherTest.java | 694 +++++++++++++----- 10 files changed, 1132 insertions(+), 316 deletions(-) diff --git a/proto/src/telephony.proto b/proto/src/telephony.proto index 6d3d711fa2..b87728b53a 100644 --- a/proto/src/telephony.proto +++ b/proto/src/telephony.proto @@ -931,6 +931,9 @@ message TelephonyEvent { /** Data switch caused by CBRS switch. */ DATA_SWITCH_REASON_CBRS = 3; + + /** Data switch caused by non-default SIM having better availability(e.g.signal). */ + DATA_SWITCH_REASON_AUTO = 4; } /** The reason for data switch. */ diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 77ae9feb95..ca70d9cbc8 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -4931,9 +4931,10 @@ public class ServiceStateTracker extends Handler { * * @param h handler to notify * @param what what code of message when delivered + * @param userobj the user obj that will be passed back when notify */ - public void registerForServiceStateChanged(Handler h, int what) { - mServiceStateChangedRegistrants.addUnique(h, what, null); + public void registerForServiceStateChanged(Handler h, int what, Object userobj) { + mServiceStateChangedRegistrants.addUnique(h, what, userobj); } /** diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index 951bb18fa4..5df9d295f3 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -76,6 +76,12 @@ public class DataConfigManager extends Handler { /** The default timeout in ms for data network stuck in a transit state. */ private static final int DEFAULT_NETWORK_TRANSIT_STATE_TIMEOUT_MS = 300000; + /** Default time threshold in ms to define a internet connection status to be stable. */ + public static int DEFAULT_AUTO_DATA_SWITCH_STABILITY_TIME_MS = 10000; + + /** The max number of retries when a pre-switching validation fails. */ + public static int DEFAULT_AUTO_DATA_SWITCH_MAX_RETRY = 7; + /** Event for carrier config changed. */ private static final int EVENT_CARRIER_CONFIG_CHANGED = 1; @@ -218,6 +224,12 @@ public class DataConfigManager extends Handler { "anomaly_network_handover_timeout"; /** DeviceConfig key of anomaly report: True for enabling APN config invalidity detection */ private static final String KEY_ANOMALY_APN_CONFIG_ENABLED = "anomaly_apn_config_enabled"; + /** DeviceConfig key of the time threshold in ms for defining a network status to be stable. **/ + private static final String KEY_AUTO_DATA_SWITCH_AVAILABILITY_STABILITY_TIME_THRESHOLD = + "auto_data_switch_availability_stability_time_threshold"; + /** DeviceConfig key of the maximum number of retries when a validation for switching failed.**/ + private static final String KEY_AUTO_DATA_SWITCH_VALIDATION_MAX_RETRY = + "auto_data_switch_validation_max_retry"; /** Anomaly report thresholds for frequent setup data call failure. */ private EventFrequency mSetupDataCallAnomalyReportThreshold; @@ -260,6 +272,18 @@ public class DataConfigManager extends Handler { */ private boolean mIsApnConfigAnomalyReportEnabled; + /** + * Time threshold in ms to define a internet connection status to be stable(e.g. out of service, + * in service, wifi is the default active network.etc), while -1 indicates auto switch feature + * disabled. + */ + private long mAutoDataSwitchAvailabilityStabilityTimeThreshold; + + /** + * The maximum number of retries when a pre-switching validation fails. + */ + private int mAutoDataSwitchValidationMaxRetry; + private @NonNull final Phone mPhone; private @NonNull final String mLogTag; @@ -425,6 +449,12 @@ public class DataConfigManager extends Handler { KEY_ANOMALY_NETWORK_HANDOVER_TIMEOUT, DEFAULT_NETWORK_TRANSIT_STATE_TIMEOUT_MS); mIsApnConfigAnomalyReportEnabled = properties.getBoolean( KEY_ANOMALY_APN_CONFIG_ENABLED, false); + mAutoDataSwitchAvailabilityStabilityTimeThreshold = properties.getInt( + KEY_AUTO_DATA_SWITCH_AVAILABILITY_STABILITY_TIME_THRESHOLD, + DEFAULT_AUTO_DATA_SWITCH_STABILITY_TIME_MS); + mAutoDataSwitchValidationMaxRetry = properties.getInt( + KEY_AUTO_DATA_SWITCH_VALIDATION_MAX_RETRY, + DEFAULT_AUTO_DATA_SWITCH_MAX_RETRY); } /** @@ -900,6 +930,22 @@ public class DataConfigManager extends Handler { return mIsApnConfigAnomalyReportEnabled; } + /** + * @return The maximum number of retries when a validation for switching failed. + */ + public int getAutoDataSwitchValidationMaxRetry() { + return mAutoDataSwitchValidationMaxRetry; + } + + /** + * @return Time threshold in ms to define a internet connection status to be stable + * (e.g. out of service, in service, wifi is the default active network.etc), while -1 indicates + * auto switch feature disabled. + */ + public long getAutoDataSwitchAvailabilityStabilityTimeThreshold() { + return mAutoDataSwitchAvailabilityStabilityTimeThreshold; + } + /** * Get the TCP config string, used by {@link LinkProperties#setTcpBufferSizes(String)}. * The config string will have the following form, with values in bytes: @@ -1280,6 +1326,9 @@ public class DataConfigManager extends Handler { pw.println("mNetworkDisconnectingTimeout=" + mNetworkDisconnectingTimeout); pw.println("mNetworkHandoverTimeout=" + mNetworkHandoverTimeout); pw.println("mIsApnConfigAnomalyReportEnabled=" + mIsApnConfigAnomalyReportEnabled); + pw.println("mAutoDataSwitchAvailabilityStabilityTimeThreshold=" + + mAutoDataSwitchAvailabilityStabilityTimeThreshold); + pw.println("mAutoDataSwitchValidationMaxRetry=" + mAutoDataSwitchValidationMaxRetry); pw.println("Metered APN types=" + mMeteredApnTypes.stream() .map(ApnSetting::getApnTypeString).collect(Collectors.joining(","))); pw.println("Roaming metered APN types=" + mRoamingMeteredApnTypes.stream() diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 4fe276d563..e8d1bd1467 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -1024,7 +1024,7 @@ public class DataNetwork extends StateMachine { mPhone.getDisplayInfoController().registerForTelephonyDisplayInfoChanged( getHandler(), EVENT_DISPLAY_INFO_CHANGED, null); mPhone.getServiceStateTracker().registerForServiceStateChanged(getHandler(), - EVENT_SERVICE_STATE_CHANGED); + EVENT_SERVICE_STATE_CHANGED, null); for (int transport : mAccessNetworksManager.getAvailableTransports()) { mDataServiceManagers.get(transport) .registerForDataCallListChanged(getHandler(), EVENT_DATA_STATE_CHANGED); diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 53e5ccac84..76788699db 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -959,7 +959,7 @@ public class DataNetworkController extends Handler { }); mPhone.getServiceStateTracker().registerForServiceStateChanged(this, - EVENT_SERVICE_STATE_CHANGED); + EVENT_SERVICE_STATE_CHANGED, null); mDataConfigManager.registerCallback(new DataConfigManagerCallback(this::post) { @Override public void onCarrierConfigChanged() { @@ -981,7 +981,7 @@ public class DataNetworkController extends Handler { if (!mAccessNetworksManager.isInLegacyMode()) { mPhone.getServiceStateTracker().registerForServiceStateChanged(this, - EVENT_SERVICE_STATE_CHANGED); + EVENT_SERVICE_STATE_CHANGED, null); mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) .registerForServiceBindingChanged(this, EVENT_DATA_SERVICE_BINDING_CHANGED); } diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index fcd572c371..f710266261 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -45,6 +45,7 @@ import android.util.LocalLog; import com.android.internal.telephony.GlobalSettingsHelper; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SettingsObserver; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback; @@ -708,14 +709,26 @@ public class DataSettingsManager extends Handler { overridden = apnType == ApnSetting.TYPE_MMS; } - boolean isNonDds = mPhone.getSubId() != SubscriptionController.getInstance() - .getDefaultDataSubId(); + SubscriptionController subscriptionController = SubscriptionController.getInstance(); + boolean isNonDds = mPhone.getSubId() != subscriptionController.getDefaultDataSubId(); // mobile data policy : data during call if (isMobileDataPolicyEnabled(TelephonyManager .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL)) { overridden = isNonDds && mPhone.getState() != PhoneConstants.State.IDLE; } + + // mobile data policy : auto data switch + if (isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)) { + // check user enabled data on the default data phone + Phone defaultDataPhone = PhoneFactory.getPhone(subscriptionController.getPhoneId( + subscriptionController.getDefaultDataSubId())); + if (defaultDataPhone == null) { + loge("isDataEnabledOverriddenForApn: unexpected defaultDataPhone is null"); + } else { + overridden = isNonDds && defaultDataPhone.isUserDataEnabled(); + } + } return overridden; } diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 15df182350..e6d0e1cc79 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -32,6 +32,9 @@ import static java.util.Arrays.copyOf; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; @@ -47,6 +50,7 @@ import android.net.NetworkSpecifier; import android.net.TelephonyNetworkSpecifier; import android.os.AsyncResult; import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -54,8 +58,10 @@ import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; -import android.provider.DeviceConfig; +import android.provider.Settings; +import android.telephony.AccessNetworkConstants; import android.telephony.CarrierConfigManager; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneCapability; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionInfo; @@ -66,7 +72,6 @@ import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RegistrationManager; import android.telephony.ims.stub.ImsRegistrationImplBase; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.LocalLog; @@ -89,6 +94,7 @@ import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch; +import com.android.internal.telephony.util.NotificationChannelController; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -111,12 +117,23 @@ import java.util.concurrent.CompletableFuture; */ public class PhoneSwitcher extends Handler { private static final String LOG_TAG = "PhoneSwitcher"; - /** DeviceConfig key of the time threshold in ms for defining a network status to be stable. **/ - private static final String KEY_AUTO_DATA_SWITCH_AVAILABILITY_STABILITY_TIME_THRESHOLD = - "auto_data_switch_availability_stability_time_threshold"; protected static final boolean VDBG = false; - private static final int DEFAULT_NETWORK_CHANGE_TIMEOUT_MS = 5000; + /** Fragment "key" argument passed thru {@link #SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS} */ + private static final String SETTINGS_EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"; + /** + * When starting this activity, this extra can also be specified to supply a Bundle of arguments + * to pass to that fragment when it is instantiated during the initial creation of the activity. + */ + private static final String SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS = + ":settings:show_fragment_args"; + /** The res Id of the auto data switch fragment in settings. **/ + private static final String AUTO_DATA_SWITCH_SETTING_R_ID = "auto_data_switch"; + /** Notification tag **/ + private static final String AUTO_DATA_SWITCH_NOTIFICATION_TAG = "auto_data_switch"; + /** Notification ID **/ + private static final int AUTO_DATA_SWITCH_NOTIFICATION_ID = 1; + private static final int MODEM_COMMAND_RETRY_PERIOD_MS = 5000; // After the emergency call ends, wait for a few seconds to see if we enter ECBM before starting // the countdown to remove the emergency DDS override. @@ -195,7 +212,10 @@ public class PhoneSwitcher extends Handler { @VisibleForTesting protected final CellularNetworkValidator mValidator; private int mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; + /** The last reason for auto switch (e.g. CBRS) **/ private int mLastAutoSelectedSwitchReason = -1; + /** {@code true} if we've displayed the notification the first time auto switch occurs **/ + private boolean mDisplayedAutoSwitchNotification = false; private boolean mPendingSwitchNeedValidation; @VisibleForTesting public final CellularNetworkValidator.ValidationCallback mValidationCallback = @@ -235,6 +255,9 @@ public class PhoneSwitcher extends Handler { // its value will be DEFAULT_SUBSCRIPTION_ID. private int mAutoSelectedDataSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; + /** The count of consecutive auto switch validation failure **/ + private int mAutoSwitchRetryFailedCount = 0; + // The phone ID that has an active voice call. If set, and its mobile data setting is on, // it will become the mPreferredDataPhoneId. protected int mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX; @@ -265,6 +288,16 @@ public class PhoneSwitcher extends Handler { private ISetOpportunisticDataCallback mSetOpptSubCallback; + /** Data config manager callback for updating device config. **/ + private final DataConfigManager.DataConfigManagerCallback mDataConfigManagerCallback = + new DataConfigManager.DataConfigManagerCallback(this::post) { + @Override + public void onDeviceConfigChanged() { + log("onDeviceConfigChanged"); + PhoneSwitcher.this.updateConfig(); + } + }; + private static final int EVENT_PRIMARY_DATA_SUB_CHANGED = 101; protected static final int EVENT_SUBSCRIPTION_CHANGED = 102; private static final int EVENT_REQUEST_NETWORK = 103; @@ -281,14 +314,12 @@ public class PhoneSwitcher extends Handler { // mEmergencyOverride, start the countdown to remove the override using the message // EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE. The only exception to this is if the device moves to // ECBM, which is detected by EVENT_EMERGENCY_TOGGLE. - @VisibleForTesting - public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 109; + private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 109; private static final int EVENT_NETWORK_VALIDATION_DONE = 110; - private static final int EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK = 111; + private static final int EVENT_EVALUATE_AUTO_SWITCH = 111; private static final int EVENT_MODEM_COMMAND_DONE = 112; private static final int EVENT_MODEM_COMMAND_RETRY = 113; - @VisibleForTesting - public static final int EVENT_DATA_ENABLED_CHANGED = 114; + private static final int EVENT_SERVICE_STATE_CHANGED = 114; // An emergency call is about to be originated and requires the DDS to be overridden. // Uses EVENT_PRECISE_CALL_STATE_CHANGED message to start countdown to finish override defined // in mEmergencyOverride. If EVENT_PRECISE_CALL_STATE_CHANGED does not come in @@ -297,13 +328,11 @@ public class PhoneSwitcher extends Handler { // If it exists, remove the current mEmergencyOverride DDS override. private static final int EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE = 116; // If it exists, remove the current mEmergencyOverride DDS override. - @VisibleForTesting - public static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 117; + private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 117; private static final int EVENT_NETWORK_AVAILABLE = 118; private static final int EVENT_PROCESS_SIM_STATE_CHANGE = 119; - @VisibleForTesting - public static final int EVENT_IMS_RADIO_TECH_CHANGED = 120; - public static final int EVENT_DEVICE_CONFIG_CHANGED = 121; + private static final int EVENT_IMS_RADIO_TECH_CHANGED = 120; + private static final int EVENT_MEETS_AUTO_DATA_SWITCH_STATE = 121; // List of events triggers re-evaluations private static final String EVALUATION_REASON_RADIO_ON = "EVENT_RADIO_ON"; @@ -323,8 +352,6 @@ public class PhoneSwitcher extends Handler { // Default timeout value of network validation in millisecond. private final static int DEFAULT_VALIDATION_EXPIRATION_TIME = 2000; - private Boolean mHasRegisteredDefaultNetworkChangeCallback = false; - private ConnectivityManager mConnectivityManager; private int mImsRegistrationTech = REGISTRATION_TECH_NONE; @@ -337,6 +364,12 @@ public class PhoneSwitcher extends Handler { */ private long mAutoDataSwitchAvailabilityStabilityTimeThreshold = -1; + /** + * The maximum number of retries when a validation for switching failed. + */ + private int mAutoDataSwitchValidationMaxRetry = + DataConfigManager.DEFAULT_AUTO_DATA_SWITCH_MAX_RETRY; + /** Data settings manager callback. Key is the phone id. */ private final @NonNull Map mDataSettingsManagerCallbacks = new ArrayMap<>(); @@ -344,20 +377,37 @@ public class PhoneSwitcher extends Handler { private class DefaultNetworkCallback extends ConnectivityManager.NetworkCallback { public int mExpectedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; public int mSwitchReason = TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; + public boolean isDefaultNetworkOnCellular = false; @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { - if (networkCapabilities.hasTransport(TRANSPORT_CELLULAR) - && SubscriptionManager.isValidSubscriptionId(mExpectedSubId) - && mExpectedSubId == getSubIdFromNetworkSpecifier( - networkCapabilities.getNetworkSpecifier())) { - logDataSwitchEvent( - mExpectedSubId, - TelephonyEvent.EventState.EVENT_STATE_END, - mSwitchReason); - removeDefaultNetworkChangeCallback(); + if (networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { + isDefaultNetworkOnCellular = true; + if (SubscriptionManager.isValidSubscriptionId(mExpectedSubId) + && mExpectedSubId == getSubIdFromNetworkSpecifier( + networkCapabilities.getNetworkSpecifier())) { + logDataSwitchEvent( + mExpectedSubId, + TelephonyEvent.EventState.EVENT_STATE_END, + mSwitchReason); + mExpectedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + mSwitchReason = TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; + } + } else { + if (isDefaultNetworkOnCellular) { + // non-cellular transport is active + isDefaultNetworkOnCellular = false; + log("default network is active on non cellular"); + evaluateIfAutoSwitchIsNeeded(); + } } } + + @Override + public void onLost(Network network) { + // try find an active sub to switch to + scheduleAutoSwitchEvaluation(); + } } private RegistrationManager.RegistrationCallback mRegistrationCallback = @@ -430,7 +480,7 @@ public class PhoneSwitcher extends Handler { boolean isOnOriginalNetwork = (imsRegTech != REGISTRATION_TECH_IWLAN) && (imsRegTech != REGISTRATION_TECH_CROSS_SIM); if (!isOnOriginalNetwork) { - log("IMS call on IWLAN or cross SIM. Call will be ignored for DDS switch"); + logl("IMS call on IWLAN or cross SIM. Call will be ignored for DDS switch"); } return isOnOriginalNetwork; } @@ -450,7 +500,7 @@ public class PhoneSwitcher extends Handler { } if (mPhoneIdInVoiceCall != oldPhoneIdInVoiceCall) { - log("isPhoneInVoiceCallChanged from phoneId " + oldPhoneIdInVoiceCall + logl("isPhoneInVoiceCallChanged from phoneId " + oldPhoneIdInVoiceCall + " to phoneId " + mPhoneIdInVoiceCall); return true; } else { @@ -477,13 +527,13 @@ public class PhoneSwitcher extends Handler { } } - private void evaluateIfDataSwitchIsNeeded(String reason) { - if (onEvaluate(REQUESTS_UNCHANGED, reason)) { + private void evaluateIfImmediateDataSwitchIsNeeded(String evaluationReason, int switchReason) { + if (onEvaluate(REQUESTS_UNCHANGED, evaluationReason)) { logDataSwitchEvent(mPreferredDataSubId.get(), TelephonyEvent.EventState.EVENT_STATE_START, - DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); + switchReason); registerDefaultNetworkChangeCallback(mPreferredDataSubId.get(), - DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); + switchReason); } } @@ -507,9 +557,9 @@ public class PhoneSwitcher extends Handler { mContext.registerReceiver(mSimStateIntentReceiver, filter); mActivePhoneRegistrants = new RegistrantList(); - for (int i = 0; i < mActiveModemCount; i++) { - mPhoneStates[i] = new PhoneState(); - Phone phone = PhoneFactory.getPhone(i); + for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { + mPhoneStates[phoneId] = new PhoneState(); + Phone phone = PhoneFactory.getPhone(phoneId); if (phone != null) { phone.registerForEmergencyCallToggle( this, EVENT_EMERGENCY_TOGGLE, null); @@ -520,18 +570,22 @@ public class PhoneSwitcher extends Handler { phone.getImsPhone().registerForPreciseCallStateChanged( this, EVENT_PRECISE_CALL_STATE_CHANGED, null); } - mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), + mDataSettingsManagerCallbacks.computeIfAbsent(phoneId, v -> new DataSettingsManagerCallback(this::post) { @Override public void onDataEnabledChanged(boolean enabled, @TelephonyManager.DataEnabledChangedReason int reason, @NonNull String callingPackage) { - evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); + logl("user changed data settings"); + evaluateIfImmediateDataSwitchIsNeeded("user changed data settings", + DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); + evaluateIfAutoSwitchIsNeeded(); }}); phone.getDataSettingsManager().registerCallback( - mDataSettingsManagerCallbacks.get(phone.getPhoneId())); - - registerForImsRadioTechChange(context, i); + mDataSettingsManagerCallbacks.get(phoneId)); + phone.getServiceStateTracker().registerForServiceStateChanged(this, + EVENT_SERVICE_STATE_CHANGED, phoneId); + registerForImsRadioTechChange(context, phoneId); } Set ddsFailure = new HashSet(); mCurrentDdsSwitchFailure.add(ddsFailure); @@ -555,6 +609,8 @@ public class PhoneSwitcher extends Handler { PhoneConfigurationManager.registerForMultiSimConfigChange( this, EVENT_MULTI_SIM_CONFIG_CHANGED, null); + mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, this); + final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder() .addTransportType(TRANSPORT_CELLULAR) .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS) @@ -586,20 +642,9 @@ public class PhoneSwitcher extends Handler { // we want to see all requests networkFactory.registerIgnoringScore(); - // Register for device config update - DeviceConfig.addOnPropertiesChangedListener( - DeviceConfig.NAMESPACE_TELEPHONY, this::post, - properties -> { - if (TextUtils.equals(DeviceConfig.NAMESPACE_TELEPHONY, - properties.getNamespace())) { - sendEmptyMessage(EVENT_DEVICE_CONFIG_CHANGED); - } - }); - updateDeviceConfig(); - updateHalCommandToUse(); - log("PhoneSwitcher started"); + logl("PhoneSwitcher started"); } private final BroadcastReceiver mDefaultDataChangedReceiver = new BroadcastReceiver() { @@ -619,7 +664,7 @@ public class PhoneSwitcher extends Handler { TelephonyManager.SIM_STATE_UNKNOWN); int slotIndex = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, SubscriptionManager.INVALID_SIM_SLOT_INDEX); - log("mSimStateIntentReceiver: slotIndex = " + slotIndex + " state = " + state); + logl("mSimStateIntentReceiver: slotIndex = " + slotIndex + " state = " + state); obtainMessage(EVENT_PROCESS_SIM_STATE_CHANGE, slotIndex, state).sendToTarget(); } } @@ -637,7 +682,7 @@ public class PhoneSwitcher extends Handler { IccCard iccCard = PhoneFactory.getPhone(slotIndex).getIccCard(); if (!iccCard.isEmptyProfile() && uiccAppsEnabled) { - log("isSimApplicationReady: SIM is ready for slotIndex: " + slotIndex); + logl("isSimApplicationReady: SIM is ready for slotIndex: " + slotIndex); return true; } else { return false; @@ -660,14 +705,22 @@ public class PhoneSwitcher extends Handler { onEvaluate(REQUESTS_UNCHANGED, "subChanged"); break; } + case EVENT_SERVICE_STATE_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + final int phoneId = (int) ar.userObj; + onServiceStateChanged(phoneId); + break; + } + case EVENT_MEETS_AUTO_DATA_SWITCH_STATE: { + final int targetSubId = msg.arg1; + final boolean needValidation = (boolean) msg.obj; + validate(targetSubId, needValidation, + DataSwitch.Reason.DATA_SWITCH_REASON_AUTO, null); + break; + } case EVENT_PRIMARY_DATA_SUB_CHANGED: { - if (onEvaluate(REQUESTS_UNCHANGED, "primary data subId changed")) { - logDataSwitchEvent(mPreferredDataSubId.get(), - TelephonyEvent.EventState.EVENT_STATE_START, - DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL); - registerDefaultNetworkChangeCallback(mPreferredDataSubId.get(), - DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL); - } + evaluateIfImmediateDataSwitchIsNeeded("primary data sub changed", + DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL); break; } case EVENT_REQUEST_NETWORK: { @@ -681,7 +734,7 @@ public class PhoneSwitcher extends Handler { case EVENT_EMERGENCY_TOGGLE: { boolean isInEcm = isInEmergencyCallbackMode(); if (mEmergencyOverride != null) { - log("Emergency override - ecbm status = " + isInEcm); + logl("Emergency override - ecbm status = " + isInEcm); if (isInEcm) { // The device has gone into ECBM. Wait until it's out. removeMessages(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); @@ -695,6 +748,9 @@ public class PhoneSwitcher extends Handler { onEvaluate(REQUESTS_CHANGED, "emergencyToggle"); break; } + case EVENT_EVALUATE_AUTO_SWITCH: + evaluateIfAutoSwitchIsNeeded(); + break; case EVENT_RADIO_CAPABILITY_CHANGED: { final int phoneId = msg.arg1; sendRilCommands(phoneId); @@ -721,7 +777,8 @@ public class PhoneSwitcher extends Handler { if (!isPhoneInVoiceCallChanged()) { break; } - evaluateIfDataSwitchIsNeeded("EVENT_IMS_RADIO_TECH_CHANGED"); + evaluateIfImmediateDataSwitchIsNeeded("Ims radio tech changed", + DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); break; case EVENT_PRECISE_CALL_STATE_CHANGED: { @@ -759,13 +816,10 @@ public class PhoneSwitcher extends Handler { mEmergencyOverride.mPendingOriginatingCall = false; } } - evaluateIfDataSwitchIsNeeded("EVENT_PRECISE_CALL_STATE_CHANGED"); + evaluateIfImmediateDataSwitchIsNeeded("precise call state changed", + DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); break; } - - case EVENT_DATA_ENABLED_CHANGED: - evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); - break; case EVENT_NETWORK_VALIDATION_DONE: { int subId = msg.arg1; boolean passed = (msg.arg2 == 1); @@ -778,10 +832,6 @@ public class PhoneSwitcher extends Handler { onNetworkAvailable(subId, network); break; } - case EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK: { - removeDefaultNetworkChangeCallback(); - break; - } case EVENT_MODEM_COMMAND_DONE: { AsyncResult ar = (AsyncResult) msg.obj; onDdsSwitchResponse(ar); @@ -790,10 +840,10 @@ public class PhoneSwitcher extends Handler { case EVENT_MODEM_COMMAND_RETRY: { int phoneId = (int) msg.obj; if (isPhoneIdValidForRetry(phoneId)) { - log("EVENT_MODEM_COMMAND_RETRY: resend modem command on phone " + phoneId); + logl("EVENT_MODEM_COMMAND_RETRY: resend modem command on phone " + phoneId); sendRilCommands(phoneId); } else { - log("EVENT_MODEM_COMMAND_RETRY: skip retry as DDS sub changed"); + logl("EVENT_MODEM_COMMAND_RETRY: skip retry as DDS sub changed"); mCurrentDdsSwitchFailure.get(phoneId).clear(); } break; @@ -805,7 +855,7 @@ public class PhoneSwitcher extends Handler { // being overridden, ignore. We should not try to switch DDS while already // waiting for SUPL. if (mEmergencyOverride.mPhoneId != req.mPhoneId) { - log("emergency override requested for phone id " + req.mPhoneId + " when " + logl("emergency override requested for phone id " + req.mPhoneId + " when " + "there is already an override in place for phone id " + mEmergencyOverride.mPhoneId + ". Ignoring."); if (req.isCallbackAvailable()) { @@ -825,7 +875,7 @@ public class PhoneSwitcher extends Handler { mEmergencyOverride = req; } - log("new emergency override - " + mEmergencyOverride); + logl("new emergency override - " + mEmergencyOverride); // a new request has been created, remove any previous override complete scheduled. removeMessages(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); Message msg2 = obtainMessage(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); @@ -843,7 +893,7 @@ public class PhoneSwitcher extends Handler { break; } case EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE: { - log("Emergency override removed - " + mEmergencyOverride); + logl("Emergency override removed - " + mEmergencyOverride); mEmergencyOverride = null; onEvaluate(REQUESTS_UNCHANGED, "emer_rm_override_dds"); break; @@ -858,7 +908,7 @@ public class PhoneSwitcher extends Handler { int simState = (int) msg.arg2; if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { - log("EVENT_PROCESS_SIM_STATE_CHANGE: skip processing due to invalid slotId: " + logl("EVENT_PROCESS_SIM_STATE_CHANGE: skip processing due to invalid slotId: " + slotIndex); } else if (mCurrentDdsSwitchFailure.get(slotIndex).contains( CommandException.Error.INVALID_SIM_STATE) @@ -866,23 +916,38 @@ public class PhoneSwitcher extends Handler { && isSimApplicationReady(slotIndex)) { sendRilCommands(slotIndex); } - break; - } - case EVENT_DEVICE_CONFIG_CHANGED: { - updateDeviceConfig(); + + registerConfigChange(); break; } } } - /** Update local properties from {@link DeviceConfig} */ - private void updateDeviceConfig() { - DeviceConfig.Properties properties = //read all telephony properties - DeviceConfig.getProperties(DeviceConfig.NAMESPACE_TELEPHONY); - - mAutoDataSwitchAvailabilityStabilityTimeThreshold = properties.getInt( - KEY_AUTO_DATA_SWITCH_AVAILABILITY_STABILITY_TIME_THRESHOLD, -1); + /** + * Register for device config change on the primary data phone. + */ + private void registerConfigChange() { + Phone phone = findPhoneById(mSubscriptionController.getPhoneId(mPrimaryDataSubId)); + if (phone != null) { + DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); + dataConfig.registerCallback(mDataConfigManagerCallback); + updateConfig(); + sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); + } + } + /** + * Update data config. + */ + private void updateConfig() { + Phone phone = findPhoneById(mSubscriptionController.getPhoneId(mPrimaryDataSubId)); + if (phone != null) { + DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); + mAutoDataSwitchAvailabilityStabilityTimeThreshold = + dataConfig.getAutoDataSwitchAvailabilityStabilityTimeThreshold(); + mAutoDataSwitchValidationMaxRetry = + dataConfig.getAutoDataSwitchValidationMaxRetry(); + } } private synchronized void onMultiSimConfigChanged(int activeModemCount) { @@ -919,11 +984,16 @@ public class PhoneSwitcher extends Handler { public void onDataEnabledChanged(boolean enabled, @TelephonyManager.DataEnabledChangedReason int reason, @NonNull String callingPackage) { - evaluateIfDataSwitchIsNeeded("EVENT_DATA_ENABLED_CHANGED"); + logl("user changed data settings"); + evaluateIfImmediateDataSwitchIsNeeded("user changed data settings", + DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); + evaluateIfAutoSwitchIsNeeded(); } }); phone.getDataSettingsManager().registerCallback( mDataSettingsManagerCallbacks.get(phone.getPhoneId())); + phone.getServiceStateTracker().registerForServiceStateChanged(this, + EVENT_SERVICE_STATE_CHANGED, phoneId); Set ddsFailure = new HashSet(); mCurrentDdsSwitchFailure.add(ddsFailure); @@ -986,21 +1056,9 @@ public class PhoneSwitcher extends Handler { } } - private void removeDefaultNetworkChangeCallback() { - removeMessages(EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK); - mDefaultNetworkCallback.mExpectedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - mDefaultNetworkCallback.mSwitchReason = - TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; - mConnectivityManager.unregisterNetworkCallback(mDefaultNetworkCallback); - } - private void registerDefaultNetworkChangeCallback(int expectedSubId, int reason) { mDefaultNetworkCallback.mExpectedSubId = expectedSubId; mDefaultNetworkCallback.mSwitchReason = reason; - mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, this); - sendMessageDelayed( - obtainMessage(EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK), - DEFAULT_NETWORK_CHANGE_TIMEOUT_MS); } private void collectRequestNetworkMetrics(NetworkRequest networkRequest) { @@ -1027,6 +1085,186 @@ public class PhoneSwitcher extends Handler { } } + /** + * Called when service state changed. + */ + private void onServiceStateChanged(int phoneId) { + Phone phone = findPhoneById(phoneId); + if (phone != null) { + int newRegState = phone.getServiceState() + .getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .getRegistrationState(); + if (newRegState != mPhoneStates[phoneId].dataRegState) { + mPhoneStates[phoneId].dataRegState = newRegState; + logl("onServiceStateChanged:phoneId:" + phoneId + " dataReg-> " + + NetworkRegistrationInfo.registrationStateToString(newRegState)); + evaluateIfAutoSwitchIsNeeded(); + } + } + } + + /** + * Evaluate if auto switch is suitable at the moment. + */ + private void evaluateIfAutoSwitchIsNeeded() { + // auto data switch feature is disabled from server + if (mAutoDataSwitchAvailabilityStabilityTimeThreshold < 0) return; + if (!mSubscriptionController.isActiveSubId(mPrimaryDataSubId) + || mSubscriptionController.getActiveSubIdList(true).length <= 1) { + return; + } + int primaryPhoneId = mSubscriptionController.getPhoneId(mPrimaryDataSubId); + + log("evaluateIfAutoSwitchIsNeeded: primaryPhoneId: " + primaryPhoneId + + " preferredPhoneId: " + mPreferredDataPhoneId); + Phone primaryDataPhone = findPhoneById(primaryPhoneId); + Phone secondaryDataPhone; + if (primaryDataPhone != null) { + + if (mPreferredDataPhoneId == primaryPhoneId) { + // on primary data sub + int candidateSubId = getAutoSwitchTargetSubIdIfExists(); + if (candidateSubId != INVALID_SUBSCRIPTION_ID) { + startAutoDataSwitchStabilityCheck(candidateSubId, true); + } else { + cancelPendingAutoDataSwitch(); + } + } else if ((secondaryDataPhone = findPhoneById(mPreferredDataPhoneId)) != null) { + // on secondary data sub + + if (!primaryDataPhone.isUserDataEnabled() + || !secondaryDataPhone.isDataAllowed()) { + // immediately switch back if user setting changes + mAutoSelectedDataSubId = DEFAULT_SUBSCRIPTION_ID; + evaluateIfImmediateDataSwitchIsNeeded("User disabled data settings", + DataSwitch.Reason.DATA_SWITCH_REASON_AUTO); + return; + } + + NetworkCapabilities defaultNetworkCapabilities = mConnectivityManager + .getNetworkCapabilities(mConnectivityManager.getActiveNetwork()); + if (defaultNetworkCapabilities != null && !defaultNetworkCapabilities + .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + log("evaluateIfAutoSwitchIsNeeded:" + + "Default network is active on non-cellular transport"); + startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, false); + return; + } + + if (mPhoneStates[secondaryDataPhone.getPhoneId()].dataRegState + != NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { + // secondary phone lost its HOME availability + startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, false); + return; + } + + if (isInService(mPhoneStates[primaryPhoneId])) { + // primary becomes available + startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, true); + return; + } + + // cancel any previous attempts of switching back to primary + cancelPendingAutoDataSwitch(); + } + + } + } + + /** + * @param phoneState The phone state to check + * @return {@code true} if the phone state is considered in service. + */ + private boolean isInService(@NonNull PhoneState phoneState) { + return phoneState.dataRegState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME + || phoneState.dataRegState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; + } + + /** + * Called when the current environment suits auto data switch. + * Start pre-switch validation if the current environment suits auto data switch for + * {@link #mAutoDataSwitchAvailabilityStabilityTimeThreshold} MS. + * @param targetSubId the target sub Id. + * @param needValidation {@code true} if validation is needed. + */ + private void startAutoDataSwitchStabilityCheck(int targetSubId, boolean needValidation) { + log("startAutoDataSwitchStabilityCheck: targetSubId=" + targetSubId + + " needValidation=" + needValidation); + if (!hasMessages(EVENT_MEETS_AUTO_DATA_SWITCH_STATE, needValidation)) { + sendMessageDelayed(obtainMessage(EVENT_MEETS_AUTO_DATA_SWITCH_STATE, targetSubId, + 0/*placeholder*/, + needValidation), + mAutoDataSwitchAvailabilityStabilityTimeThreshold); + } + } + + /** + * Cancel any auto switch attempts when the current environment is not suitable for auto switch. + */ + private void cancelPendingAutoDataSwitch() { + mAutoSwitchRetryFailedCount = 0; + removeMessages(EVENT_MEETS_AUTO_DATA_SWITCH_STATE); + if (mValidator.isValidating()) { + mValidator.stopValidation(); + + removeMessages(EVENT_NETWORK_VALIDATION_DONE); + removeMessages(EVENT_NETWORK_AVAILABLE); + mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; + mPendingSwitchNeedValidation = false; + } + } + + /** + * Called when consider switching from primary default data sub to another data sub. + * @return the target subId if a suitable candidate is found, otherwise return + * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} + */ + private int getAutoSwitchTargetSubIdIfExists() { + int primaryPhoneId = mSubscriptionController.getPhoneId(mPrimaryDataSubId); + Phone primaryDataPhone = findPhoneById(primaryPhoneId); + + if (primaryDataPhone == null) { + log("getAutoSwitchTargetSubId: no sim loaded"); + return INVALID_SUBSCRIPTION_ID; + } + + if (!primaryDataPhone.isUserDataEnabled()) { + log("getAutoSwitchTargetSubId: user disabled data"); + return INVALID_SUBSCRIPTION_ID; + } + + NetworkCapabilities defaultNetworkCapabilities = mConnectivityManager + .getNetworkCapabilities(mConnectivityManager.getActiveNetwork()); + if (defaultNetworkCapabilities != null && !defaultNetworkCapabilities + .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + // Exists other active default transport + log("getAutoSwitchTargetSubId: Default network is active on non-cellular transport"); + return INVALID_SUBSCRIPTION_ID; + } + + // check whether primary and secondary signal status worth switching + if (isInService(mPhoneStates[primaryPhoneId])) { + log("getAutoSwitchTargetSubId: primary is in service"); + return INVALID_SUBSCRIPTION_ID; + } + for (int phoneId = 0; phoneId < mPhoneStates.length; phoneId++) { + if (phoneId != primaryPhoneId) { + // the alternative phone must have HOME availability + if (mPhoneStates[phoneId].dataRegState + == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { + Phone secondaryDataPhone = findPhoneById(phoneId); + if (secondaryDataPhone != null && // check auto switch feature enabled + secondaryDataPhone.isDataAllowed()) { + return secondaryDataPhone.getSubId(); + } + } + } + } + return INVALID_SUBSCRIPTION_ID; + } + private TelephonyManager getTm() { return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); } @@ -1068,6 +1306,9 @@ public class PhoneSwitcher extends Handler { if (sub != mPhoneSubscriptions[i]) { sb.append(" phone[").append(i).append("] ").append(mPhoneSubscriptions[i]); sb.append("->").append(sub); + if (mAutoSelectedDataSubId == mPhoneSubscriptions[i]) { + mAutoSelectedDataSubId = DEFAULT_SUBSCRIPTION_ID; + } mPhoneSubscriptions[i] = sub; diffDetected = true; } @@ -1097,7 +1338,7 @@ public class PhoneSwitcher extends Handler { .append("->").append(mPreferredDataPhoneId); diffDetected = true; } else if (oldPreferredDataSubId != mPreferredDataSubId.get()) { - log("SIM refresh, notify dds change"); + logl("SIM refresh, notify dds change"); // Inform connectivity about the active data phone notifyPreferredDataSubIdChanged(); } @@ -1106,7 +1347,7 @@ public class PhoneSwitcher extends Handler { // DDS are out of sync after APM, AP should force DDS when radio on. long term solution // should be having API to query preferred data modem to detect the out-of-sync scenarios. if (diffDetected || EVALUATION_REASON_RADIO_ON.equals(reason)) { - log("evaluating due to " + sb.toString()); + logl("evaluating due to " + sb); if (mHalCommandToUse == HAL_COMMAND_PREFERRED_DATA) { // With HAL_COMMAND_PREFERRED_DATA, all phones are assumed to allow PS attach. // So marking all phone as active, and the phone with mPreferredDataPhoneId @@ -1177,6 +1418,8 @@ public class PhoneSwitcher extends Handler { protected static class PhoneState { public volatile boolean active = false; + public @NetworkRegistrationInfo.RegistrationState int dataRegState = + NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; public long lastRequested = 0; } @@ -1194,7 +1437,7 @@ public class PhoneSwitcher extends Handler { PhoneState state = mPhoneStates[phoneId]; if (state.active == active) return; state.active = active; - log((active ? "activate " : "deactivate ") + phoneId); + logl((active ? "activate " : "deactivate ") + phoneId); state.lastRequested = System.currentTimeMillis(); sendRilCommands(phoneId); } @@ -1241,7 +1484,7 @@ public class PhoneSwitcher extends Handler { protected void sendRilCommands(int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId)) { - log("sendRilCommands: skip dds switch due to invalid phoneId=" + phoneId); + logl("sendRilCommands: skip dds switch due to invalid phoneId=" + phoneId); return; } @@ -1253,7 +1496,7 @@ public class PhoneSwitcher extends Handler { } } else if (phoneId == mPreferredDataPhoneId) { // Only setPreferredDataModem if the phoneId equals to current mPreferredDataPhoneId - log("sendRilCommands: setPreferredDataModem - phoneId: " + phoneId); + logl("sendRilCommands: setPreferredDataModem - phoneId: " + phoneId); mRadioConfig.setPreferredDataModem(mPreferredDataPhoneId, message); } } @@ -1263,7 +1506,7 @@ public class PhoneSwitcher extends Handler { .getNumberOfModemsWithSimultaneousDataConnections(); if (mMaxDataAttachModemCount != newMaxDataAttachModemCount) { mMaxDataAttachModemCount = newMaxDataAttachModemCount; - log("Max active phones changed to " + mMaxDataAttachModemCount); + logl("Max active phones changed to " + mMaxDataAttachModemCount); onEvaluate(REQUESTS_UNCHANGED, "phoneCfgChanged"); } } @@ -1332,7 +1575,7 @@ public class PhoneSwitcher extends Handler { if (voicePhone != null && defaultDataPhone != null && defaultDataPhone.isUserDataEnabled()) { // check voice during call feature is enabled - isDataEnabled = voicePhone.getDataSettingsManager().isDataEnabled(); + isDataEnabled = voicePhone.isDataAllowed(); } if (mEmergencyOverride != null && findPhoneById(mEmergencyOverride.mPhoneId) != null) { @@ -1340,14 +1583,13 @@ public class PhoneSwitcher extends Handler { // emergency. // TODO: Provide a notification to the user that metered data is currently being // used during this period. - log("updatePreferredDataPhoneId: preferred data overridden for emergency." + logl("updatePreferredDataPhoneId: preferred data overridden for emergency." + " phoneId = " + mEmergencyOverride.mPhoneId); mPreferredDataPhoneId = mEmergencyOverride.mPhoneId; } else if (isDataEnabled) { // If a phone is in call and user enabled its mobile data, we // should switch internet connection to it. Because the other modem // will lose data connection anyway. - // TODO: validate network first. mPreferredDataPhoneId = mPhoneIdInVoiceCall; } else { int subId = getSubIdForDefaultNetworkRequests(); @@ -1371,12 +1613,12 @@ public class PhoneSwitcher extends Handler { protected void transitionToEmergencyPhone() { if (mActiveModemCount <= 0) { - log("No phones: unable to reset preferred phone for emergency"); + logl("No phones: unable to reset preferred phone for emergency"); return; } if (mPreferredDataPhoneId != DEFAULT_EMERGENCY_PHONE_ID) { - log("No active subscriptions: resetting preferred phone to 0 for emergency"); + logl("No active subscriptions: resetting preferred phone to 0 for emergency"); mPreferredDataPhoneId = DEFAULT_EMERGENCY_PHONE_ID; } @@ -1476,10 +1718,12 @@ public class PhoneSwitcher extends Handler { */ private void validate(int subId, boolean needValidation, int switchReason, @Nullable ISetOpportunisticDataCallback callback) { + logl("Validate " + subId + " due to " + switchReasonToString(switchReason) + + " needValidation=" + needValidation); int subIdToValidate = (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) ? mPrimaryDataSubId : subId; if (!mSubscriptionController.isActiveSubId(subIdToValidate)) { - log("Can't switch data to inactive subId " + subIdToValidate); + logl("Can't switch data to inactive subId " + subIdToValidate); if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { // the default data sub is not selected yet, store the intent of switching to // default subId once it becomes available. @@ -1554,7 +1798,7 @@ public class PhoneSwitcher extends Handler { try { callback.onComplete(result); } catch (RemoteException exception) { - log("RemoteException " + exception); + logl("RemoteException " + exception); } } @@ -1572,13 +1816,20 @@ public class PhoneSwitcher extends Handler { } private void confirmSwitch(int subId, boolean confirm) { - log("confirmSwitch: subId " + subId + (confirm ? " confirmed." : " cancelled.")); + logl("confirmSwitch: subId " + subId + (confirm ? " confirmed." : " cancelled.")); int resultForCallBack; if (!mSubscriptionController.isActiveSubId(subId)) { - log("confirmSwitch: subId " + subId + " is no longer active"); + logl("confirmSwitch: subId " + subId + " is no longer active"); resultForCallBack = SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION; + mAutoSwitchRetryFailedCount = 0; } else if (!confirm) { resultForCallBack = SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; + + // retry for auto data switch validation failure + if (mLastAutoSelectedSwitchReason == DataSwitch.Reason.DATA_SWITCH_REASON_AUTO) { + scheduleAutoSwitchEvaluation(); + mAutoSwitchRetryFailedCount++; + } } else { if (subId == mPrimaryDataSubId) { setAutoSelectedDataSubIdInternal(DEFAULT_SUBSCRIPTION_ID); @@ -1586,6 +1837,7 @@ public class PhoneSwitcher extends Handler { setAutoSelectedDataSubIdInternal(subId); } resultForCallBack = SET_OPPORTUNISTIC_SUB_SUCCESS; + mAutoSwitchRetryFailedCount = 0; } // Trigger callback if needed @@ -1594,6 +1846,23 @@ public class PhoneSwitcher extends Handler { mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; } + /** + * Schedule auto data switch evaluation retry if haven't reached the max retry count. + */ + private void scheduleAutoSwitchEvaluation() { + if (mAutoSwitchRetryFailedCount < mAutoDataSwitchValidationMaxRetry) { + if (!hasMessages(EVENT_EVALUATE_AUTO_SWITCH)) { + sendMessageDelayed(obtainMessage(EVENT_EVALUATE_AUTO_SWITCH), + mAutoDataSwitchAvailabilityStabilityTimeThreshold + << mAutoSwitchRetryFailedCount); + } + } else { + logl("scheduleAutoSwitchEvaluation: reached max auto switch retry count " + + mAutoDataSwitchValidationMaxRetry); + mAutoSwitchRetryFailedCount = 0; + } + } + private void onNetworkAvailable(int subId, Network network) { log("onNetworkAvailable: on subId " + subId); // Do nothing unless pending switch matches target subId and it doesn't require @@ -1606,7 +1875,7 @@ public class PhoneSwitcher extends Handler { } private void onValidationDone(int subId, boolean passed) { - log("onValidationDone: " + (passed ? "passed" : "failed") + " on subId " + subId); + logl("onValidationDone: " + (passed ? "passed" : "failed") + " on subId " + subId); if (mPendingSwitchSubId == INVALID_SUBSCRIPTION_ID || mPendingSwitchSubId != subId) return; // If validation failed and mPendingSwitch.mNeedValidation is false, we still confirm @@ -1632,7 +1901,7 @@ public class PhoneSwitcher extends Handler { */ public void trySetOpportunisticDataSubscription(int subId, boolean needValidation, ISetOpportunisticDataCallback callback) { - log("Try set opportunistic data subscription to subId " + subId + logl("Try set opportunistic data subscription to subId " + subId + (needValidation ? " with " : " without ") + "validation"); PhoneSwitcher.this.obtainMessage(EVENT_OPPT_DATA_SUB_CHANGED, subId, needValidation ? 1 : 0, callback).sendToTarget(); @@ -1657,12 +1926,33 @@ public class PhoneSwitcher extends Handler { return mPreferredDataPhoneId; } + /** + * Log debug messages and also log into the local log. + * @param l debug messages + */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - protected void log(String l) { - Rlog.d(LOG_TAG, l); + protected void logl(String l) { + log(l); mLocalLog.log(l); } + /** + * Log debug messages. + * @param s debug messages + */ + private void log(@NonNull String s) { + Rlog.d(LOG_TAG, s); + } + + /** + * Log debug error messages. + * @param s debug messages + */ + private void loge(@NonNull String s) { + Rlog.e(LOG_TAG, s); + } + + /** * Convert data switch reason into string. * @@ -1679,6 +1969,8 @@ public class PhoneSwitcher extends Handler { return "IN_CALL"; case TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_CBRS: return "CBRS"; + case TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_AUTO: + return "AUTO"; default: return "UNKNOWN(" + reason + ")"; } } @@ -1709,7 +2001,7 @@ public class PhoneSwitcher extends Handler { * @param reason The switching reason. */ private void logDataSwitchEvent(int subId, int state, int reason) { - log("Data switch event. subId=" + subId + ", state=" + switchStateToString(state) + logl("Data switch event. subId=" + subId + ", state=" + switchStateToString(state) + ", reason=" + switchReasonToString(reason)); DataSwitch dataSwitch = new DataSwitch(); dataSwitch.state = state; @@ -1723,7 +2015,7 @@ public class PhoneSwitcher extends Handler { protected void notifyPreferredDataSubIdChanged() { TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) mContext .getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); - log("notifyPreferredDataSubIdChanged to " + mPreferredDataSubId.get()); + logl("notifyPreferredDataSubIdChanged to " + mPreferredDataSubId.get()); telephonyRegistryManager.notifyActiveDataSubIdChanged(mPreferredDataSubId.get()); } @@ -1755,8 +2047,10 @@ public class PhoneSwitcher extends Handler { for (int i = 0; i < mActiveModemCount; i++) { PhoneState ps = mPhoneStates[i]; c.setTimeInMillis(ps.lastRequested); - pw.println("PhoneId(" + i + ") active=" + ps.active + ", lastRequest=" + - (ps.lastRequested == 0 ? "never" : + pw.println("PhoneId(" + i + ") active=" + ps.active + ", dataRegState=" + + NetworkRegistrationInfo.registrationStateToString(ps.dataRegState) + + ", lastRequest=" + + (ps.lastRequested == 0 ? "never" : String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c))); } pw.println("mPreferredDataPhoneId=" + mPreferredDataPhoneId); @@ -1774,6 +2068,7 @@ public class PhoneSwitcher extends Handler { pw.println("mCurrentDdsSwitchFailure=" + mCurrentDdsSwitchFailure); pw.println("mAutoDataSwitchAvailabilityStabilityTimeThreshold=" + mAutoDataSwitchAvailabilityStabilityTimeThreshold); + pw.println("mAutoDataSwitchValidationMaxRetry=" + mAutoDataSwitchValidationMaxRetry); pw.println("Local logs:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); @@ -1791,36 +2086,100 @@ public class PhoneSwitcher extends Handler { boolean commandSuccess = ar != null && ar.exception == null; int phoneId = (int) ar.userObj; if (mEmergencyOverride != null) { - log("Emergency override result sent = " + commandSuccess); + logl("Emergency override result sent = " + commandSuccess); mEmergencyOverride.sendOverrideCompleteCallbackResultAndClear(commandSuccess); // Do not retry , as we do not allow changes in onEvaluate during an emergency // call. When the call ends, we will start the countdown to remove the override. } else if (!commandSuccess) { - log("onDdsSwitchResponse: DDS switch failed. with exception " + ar.exception); + logl("onDdsSwitchResponse: DDS switch failed. with exception " + ar.exception); if (ar.exception instanceof CommandException) { CommandException.Error error = ((CommandException) (ar.exception)).getCommandError(); mCurrentDdsSwitchFailure.get(phoneId).add(error); if (error == CommandException.Error.OP_NOT_ALLOWED_DURING_VOICE_CALL) { - log("onDdsSwitchResponse: Wait for call end indication"); + logl("onDdsSwitchResponse: Wait for call end indication"); return; } else if (error == CommandException.Error.INVALID_SIM_STATE) { /* If there is a attach failure due to sim not ready then hold the retry until sim gets ready */ - log("onDdsSwitchResponse: Wait for SIM to get READY"); + logl("onDdsSwitchResponse: Wait for SIM to get READY"); return; } } - log("onDdsSwitchResponse: Scheduling DDS switch retry"); + logl("onDdsSwitchResponse: Scheduling DDS switch retry"); sendMessageDelayed(Message.obtain(this, EVENT_MODEM_COMMAND_RETRY, phoneId), MODEM_COMMAND_RETRY_PERIOD_MS); return; } - if (commandSuccess) log("onDdsSwitchResponse: DDS switch success on phoneId = " + phoneId); + if (commandSuccess) logl("onDdsSwitchResponse: DDS switch success on phoneId = " + phoneId); mCurrentDdsSwitchFailure.get(phoneId).clear(); // Notify all registrants mActivePhoneRegistrants.notifyRegistrants(); notifyPreferredDataSubIdChanged(); + displayAutoDataSwitchNotification(); + } + + /** + * Display a notification the first time auto data switch occurs. + */ + private void displayAutoDataSwitchNotification() { + NotificationManager notificationManager = (NotificationManager) + mContext.getSystemService(Context.NOTIFICATION_SERVICE); + + if (mDisplayedAutoSwitchNotification) { + // cancel posted notification if any exist + if (VDBG) { + log("displayAutoDataSwitchNotification: canceling any notifications for subId " + + mAutoSelectedDataSubId); + } + notificationManager.cancel(AUTO_DATA_SWITCH_NOTIFICATION_TAG, + AUTO_DATA_SWITCH_NOTIFICATION_ID); + return; + } + // proceed only the first time auto data switch occurs + if (mLastAutoSelectedSwitchReason != DataSwitch.Reason.DATA_SWITCH_REASON_AUTO) { + if (VDBG) { + log("displayAutoDataSwitchNotification: Ignore DDS switch due to " + + switchReasonToString(mLastAutoSelectedSwitchReason)); + } + return; + } + SubscriptionInfo subInfo = mSubscriptionController.getSubscriptionInfo( + mAutoSelectedDataSubId); + if (subInfo == null || subInfo.isOpportunistic()) { + loge("displayAutoDataSwitchNotification: unexpected " + subInfo); + return; + } + log("displayAutoDataSwitchNotification: displaying for subId=" + mAutoSelectedDataSubId); + // "Mobile network settings" screen / dialog + Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS); + final Bundle fragmentArgs = new Bundle(); + // Special contract for Settings to highlight permission row + fragmentArgs.putString(SETTINGS_EXTRA_FRAGMENT_ARG_KEY, AUTO_DATA_SWITCH_SETTING_R_ID); + fragmentArgs.putInt(Settings.EXTRA_SUB_ID, mAutoSelectedDataSubId); + intent.putExtra(SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs); + PendingIntent contentIntent = PendingIntent.getActivity( + mContext, mAutoSelectedDataSubId, intent, PendingIntent.FLAG_IMMUTABLE); + + CharSequence activeCarrierName = subInfo.getDisplayName(); + CharSequence contentTitle = mContext.getString( + com.android.internal.R.string.auto_data_switch_title, activeCarrierName); + CharSequence contentText = mContext.getText( + com.android.internal.R.string.auto_data_switch_content); + + final Notification notif = new Notification.Builder(mContext) + .setContentTitle(contentTitle) + .setContentText(contentText) + .setSmallIcon(android.R.drawable.stat_sys_warning) + .setColor(mContext.getResources().getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setChannelId(NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS) + .setContentIntent(contentIntent) + .setStyle(new Notification.BigTextStyle().bigText(contentText)) + .build(); + notificationManager.notify(AUTO_DATA_SWITCH_NOTIFICATION_TAG, + AUTO_DATA_SWITCH_NOTIFICATION_ID, notif); + mDisplayedAutoSwitchNotification = true; } private boolean isPhoneIdValidForRetry(int phoneId) { 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 89f7a5be35..6265d08d3d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -103,6 +103,7 @@ import com.android.internal.telephony.ISub; import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RIL; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback; @@ -680,7 +681,8 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(infoList).when(mSubscriptionController).getSubscriptionsInGroup( any(), any(), any()); doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); - doReturn(0).when(mSubscriptionController).getPhoneId(anyInt()); + doReturn(0).when(mSubscriptionController).getPhoneId(1); + doReturn(1).when(mSubscriptionController).getPhoneId(2); for (int transport : new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) { @@ -1497,7 +1499,7 @@ public class DataNetworkControllerTest extends TelephonyTest { } @Test - public void testIsDataEnabledOverriddenForApn_dataDuringCall() throws Exception { + public void testIsDataEnabledOverriddenForApnDataDuringCall() throws Exception { doReturn(1).when(mPhone).getSubId(); doReturn(2).when(mSubscriptionController).getDefaultDataSubId(); // Data disabled @@ -1536,6 +1538,49 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } + @Test + public void testIsDataEnabledOverriddenForApnAutoDataSwitch() throws Exception { + // Assume phone2 is the default data phone + Phone phone2 = Mockito.mock(Phone.class); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, phone2}); + doReturn(2).when(mSubscriptionController).getDefaultDataSubId(); + + // Data disabled on nonDDS + mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( + TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); + + // Enable auto data switch mobile policy + mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager + .MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, true); + processAllMessages(); + + // use disabled data on DDS + doReturn(false).when(phone2).isUserDataEnabled(); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + + // Verify no internet connection + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + + // use enabled data on DDS + doReturn(true).when(phone2).isUserDataEnabled(); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + + // Verify internet connection + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); + + // Disable auto data switch mobile policy + mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager + .MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, false); + processAllMessages(); + + // Verify no internet connection + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + } + @Test public void testUnmeteredRequestPreferredOnIwlan() throws Exception { // Preferred on cellular 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 e36521e60b..9acde6350d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -1149,7 +1149,7 @@ public class DataNetworkTest extends TelephonyTest { verify(mVcnManager).addVcnNetworkPolicyChangeListener(any(Executor.class), any(VcnNetworkPolicyChangeListener.class)); verify(mSST).registerForCssIndicatorChanged(any(Handler.class), anyInt(), eq(null)); - verify(mSST).registerForServiceStateChanged(any(Handler.class), anyInt()); + verify(mSST).registerForServiceStateChanged(any(Handler.class), anyInt(), any()); verify(mCT).registerForVoiceCallStarted(any(Handler.class), anyInt(), eq(null)); verify(mCT).registerForVoiceCallEnded(any(Handler.class), anyInt(), eq(null)); verify(mImsCT).registerForVoiceCallStarted(any(Handler.class), anyInt(), eq(null)); 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 ec313d1410..55ecbaa225 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -28,10 +28,6 @@ import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TE import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; import static com.android.internal.telephony.data.PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS; -import static com.android.internal.telephony.data.PhoneSwitcher.EVENT_DATA_ENABLED_CHANGED; -import static com.android.internal.telephony.data.PhoneSwitcher.EVENT_IMS_RADIO_TECH_CHANGED; -import static com.android.internal.telephony.data.PhoneSwitcher.EVENT_MULTI_SIM_CONFIG_CHANGED; -import static com.android.internal.telephony.data.PhoneSwitcher.EVENT_PRECISE_CALL_STATE_CHANGED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -50,6 +46,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; @@ -62,7 +59,10 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Messenger; +import android.telephony.AccessNetworkConstants; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneCapability; +import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.test.suitebuilder.annotation.SmallTest; @@ -76,6 +76,7 @@ import com.android.internal.telephony.GsmCdmaCall; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; @@ -85,23 +86,31 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import java.lang.reflect.Field; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.LinkedBlockingQueue; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class PhoneSwitcherTest extends TelephonyTest { + private static final int AUTO_DATA_SWITCH_NOTIFICATION = 1; private static final int ACTIVE_PHONE_SWITCH = 1; private static final int EVENT_RADIO_ON = 108; private static final int EVENT_MODEM_COMMAND_DONE = 112; + private static final int EVENT_EVALUATE_AUTO_SWITCH = 111; + private static final int EVENT_IMS_RADIO_TECH_CHANGED = 120; + private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 117; + private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 109; + private static final int EVENT_SERVICE_STATE_CHANGED = 114; // Mocked classes CompletableFuture mFuturePhone; private CommandsInterface mCommandsInterface0; private CommandsInterface mCommandsInterface1; private Phone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. + private ServiceStateTracker mSST2; private Phone mImsPhone; - // TODO: Add logic for DataSettingsManager private DataSettingsManager mDataSettingsManager2; private Handler mActivePhoneSwitchHandler; private GsmCdmaCall mActiveCall; @@ -113,12 +122,15 @@ public class PhoneSwitcherTest extends TelephonyTest { private ISetOpportunisticDataCallback mSetOpptDataCallback2; PhoneSwitcher.ImsRegTechProvider mMockImsRegTechProvider; private SubscriptionInfo mSubscriptionInfo; + private NotificationManager mNotificationManager; - private PhoneSwitcher mPhoneSwitcher; + private PhoneSwitcher mPhoneSwitcherUT; private SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener; private ConnectivityManager mConnectivityManager; // The messenger of PhoneSwitcher used to receive network requests. private Messenger mNetworkProviderMessenger = null; + private Map + mDataSettingsManagerCallbacks; private int mDefaultDataSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private int[][] mSlotIndexToSubId; private boolean[] mDataAllowed; @@ -133,6 +145,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mCommandsInterface0 = mock(CommandsInterface.class); mCommandsInterface1 = mock(CommandsInterface.class); mPhone2 = mock(Phone.class); // mPhone as phone 1 is already defined in TelephonyTest. + mSST2 = mock(ServiceStateTracker.class); mImsPhone = mock(Phone.class); mDataSettingsManager2 = mock(DataSettingsManager.class); mActivePhoneSwitchHandler = mock(Handler.class); @@ -145,6 +158,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mSetOpptDataCallback2 = mock(ISetOpportunisticDataCallback.class); mMockImsRegTechProvider = mock(PhoneSwitcher.ImsRegTechProvider.class); mSubscriptionInfo = mock(SubscriptionInfo.class); + mNotificationManager = mock(NotificationManager.class); PhoneCapability phoneCapability = new PhoneCapability(1, 1, null, false, new int[0]); doReturn(phoneCapability).when(mPhoneConfigurationManager).getCurrentPhoneCapability(); @@ -165,7 +179,7 @@ public class PhoneSwitcherTest extends TelephonyTest { @After public void tearDown() throws Exception { - mPhoneSwitcher = null; + mPhoneSwitcherUT = null; mSubChangedListener = null; mConnectivityManager = null; mNetworkProviderMessenger = null; @@ -186,14 +200,14 @@ public class PhoneSwitcherTest extends TelephonyTest { NetworkRequest internetNetworkRequest = addInternetNetworkRequest(null, 50); - assertFalse("phone active after request", mPhoneSwitcher + assertFalse("phone active after request", mPhoneSwitcherUT .shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetNetworkRequest, mPhone), 0)); // not registered yet - shouldn't inc verify(mActivePhoneSwitchHandler, never()).sendMessageAtTime(any(), anyLong()); - mPhoneSwitcher.registerForActivePhoneSwitch(mActivePhoneSwitchHandler, + mPhoneSwitcherUT.registerForActivePhoneSwitch(mActivePhoneSwitchHandler, ACTIVE_PHONE_SWITCH, null); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); @@ -208,7 +222,7 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); AsyncResult res = new AsyncResult(1, null, null); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); @@ -229,7 +243,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // 1 lose default via default sub change setDefaultDataSubId(1); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); @@ -239,7 +253,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mSubChangedListener.onSubscriptionsChanged(); processAllMessages(); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); @@ -249,7 +263,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // 2 gain default via default sub change setDefaultDataSubId(0); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); @@ -260,7 +274,7 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(0, 2); mSubChangedListener.onSubscriptionsChanged(); processAllMessages(); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); @@ -273,7 +287,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mSubChangedListener.onSubscriptionsChanged(); processAllMessages(); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); @@ -283,7 +297,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // 5 lose default network request releaseNetworkRequest(internetNetworkRequest); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); @@ -293,7 +307,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // 6 gain subscription-specific request NetworkRequest specificInternetRequest = addInternetNetworkRequest(0, 50); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); @@ -305,7 +319,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mSubChangedListener.onSubscriptionsChanged(); processAllMessages(); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); @@ -317,7 +331,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mSubChangedListener.onSubscriptionsChanged(); processAllMessages(); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); @@ -327,7 +341,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // 9 lose subscription-specific request releaseNetworkRequest(specificInternetRequest); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); @@ -355,6 +369,255 @@ public class PhoneSwitcherTest extends TelephonyTest { // if (commandsInterfaces[1].isDataAllowed()) fail("data allowed"); } + /** Test Data Auto Switch **/ + + /** + * Trigger conditions + * 1. service state changes + * 2. data setting changes + * - user toggle data + * - user toggle auto switch feature + * 3. default network changes + * - current network lost + * - network become active on non-cellular network + * 4. subscription changes + * - slot/sub mapping changes + */ + @Test + @SmallTest + public void testAutoDataSwitchCancelScenario_onPrimary() throws Exception { + initialize(); + // Phone 0 has sub 1, phone 1 has sub 2. + // Sub 1 is default data sub. + setSlotIndexToSubId(0, 1); + setSlotIndexToSubId(1, 2); + setDefaultDataSubId(1); + + // 0. When all conditions met + prepareIdealAutoSwitchCondition(); + processAllFutureMessages(); + + // Verify attempting to switch + verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), + eq(mPhoneSwitcherUT.mValidationCallback)); + doReturn(true).when(mCellularNetworkValidator).isValidating(); + + // 1. Service state becomes not ideal - primary is available again + clearInvocations(mCellularNetworkValidator); + serviceStateChanged(0, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + processAllFutureMessages(); + + verify(mCellularNetworkValidator).stopValidation(); + + // 2.1 User data disabled on primary SIM + prepareIdealAutoSwitchCondition(); + processAllFutureMessages(); + clearInvocations(mCellularNetworkValidator); + doReturn(false).when(mPhone).isUserDataEnabled(); + mDataSettingsManagerCallbacks.get(0).onDataEnabledChanged(false, 123 , ""); + processAllFutureMessages(); + + verify(mCellularNetworkValidator).stopValidation(); + + // 2.2 Auto switch feature is disabled + prepareIdealAutoSwitchCondition(); + processAllFutureMessages(); + clearInvocations(mCellularNetworkValidator); + doReturn(false).when(mPhone2).isDataAllowed(); + mDataSettingsManagerCallbacks.get(1).onDataEnabledChanged(false, 123 , ""); + processAllFutureMessages(); + + verify(mCellularNetworkValidator).stopValidation(); + + // 3.1 No default network + prepareIdealAutoSwitchCondition(); + processAllFutureMessages(); + clearInvocations(mCellularNetworkValidator); + doReturn(new NetworkCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)) + .when(mConnectivityManager).getNetworkCapabilities(any()); + mPhoneSwitcherUT.sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); + processAllFutureMessages(); + + verify(mCellularNetworkValidator).stopValidation(); + } + + public void testAutoSwitchToSecondarySucceed() { + prepareIdealAutoSwitchCondition(); + processAllFutureMessages(); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(true, 2); + processAllMessages(); + // Confirm auto switched to secondary sub Id 1/phone 0 + assertEquals(2, mPhoneSwitcherUT.getActiveDataSubId()); + } + + @Test + @SmallTest + public void testAutoDataSwitch_switchBackToPrimary() throws Exception { + initialize(); + // Phone 0 has sub 1, phone 1 has sub 2. + // Sub 1 is default data sub. + setSlotIndexToSubId(0, 1); + setSlotIndexToSubId(1, 2); + setDefaultDataSubId(1); + + testAutoSwitchToSecondarySucceed(); + // 1.1 service state changes - primary becomes available, need validation pass to switch + serviceStateChanged(0, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + processAllFutureMessages(); + verify(mCellularNetworkValidator).validate(eq(1), anyLong(), eq(false), + eq(mPhoneSwitcherUT.mValidationCallback)); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 1); + processAllMessages(); + + assertEquals(2, mPhoneSwitcherUT.getActiveDataSubId()); // since validation failed + + serviceStateChanged(0, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + processAllFutureMessages(); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(true, 1); + processAllMessages(); + + assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId()); // since validation passed + + testAutoSwitchToSecondarySucceed(); + // 1.2 service state changes - secondary becomes unavailable, NO need validation + // The later validation requirement overrides the previous + serviceStateChanged(0, NetworkRegistrationInfo.REGISTRATION_STATE_HOME/*need validate*/); + serviceStateChanged(1, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING/*no need*/); + processAllFutureMessages(); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 1); + processAllMessages(); + + assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId()); // since no need validation + + testAutoSwitchToSecondarySucceed(); + // 2.1 User data disabled on primary SIM + clearInvocations(mCellularNetworkValidator); + doReturn(false).when(mPhone).isUserDataEnabled(); + mDataSettingsManagerCallbacks.get(0).onDataEnabledChanged(false, 123 , ""); + processAllFutureMessages(); + + assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId()); // since no need validation + verify(mCellularNetworkValidator, never()).validate(eq(1), anyLong(), eq(false), + eq(mPhoneSwitcherUT.mValidationCallback)); + + testAutoSwitchToSecondarySucceed(); + // 2.2 Auto switch feature is disabled + clearInvocations(mCellularNetworkValidator); + doReturn(false).when(mPhone2).isDataAllowed(); + mDataSettingsManagerCallbacks.get(0).onDataEnabledChanged(false, 123 , ""); + processAllFutureMessages(); + + assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId()); // since no need validation + verify(mCellularNetworkValidator, never()).validate(eq(1), anyLong(), eq(false), + eq(mPhoneSwitcherUT.mValidationCallback)); + + testAutoSwitchToSecondarySucceed(); + // 3.1 Default network is active on non-cellular transport + clearInvocations(mCellularNetworkValidator); + doReturn(new NetworkCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)) + .when(mConnectivityManager).getNetworkCapabilities(any()); + mPhoneSwitcherUT.sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); + processAllFutureMessages(); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 1); + processAllMessages(); + + assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId()); // since no need validation + } + + @Test + @SmallTest + public void testAutoDataSwitchCancel_onSecondary() throws Exception { + initialize(); + // Phone 0 has sub 1, phone 1 has sub 2. + // Sub 1 is default data sub. + setSlotIndexToSubId(0, 1); + setSlotIndexToSubId(1, 2); + setDefaultDataSubId(1); + + testAutoSwitchToSecondarySucceed(); + clearInvocations(mCellularNetworkValidator); + // attempts the switch back due to secondary becomes ROAMING + serviceStateChanged(1, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + processAllFutureMessages(); + + verify(mCellularNetworkValidator).validate(eq(1), anyLong(), eq(false), + eq(mPhoneSwitcherUT.mValidationCallback)); + doReturn(true).when(mCellularNetworkValidator).isValidating(); + + // cancel the switch back attempt due to secondary back to HOME + serviceStateChanged(1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + processAllMessages(); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(true, 1); + processAllMessages(); + + assertEquals(2, mPhoneSwitcherUT.getActiveDataSubId()); + verify(mCellularNetworkValidator).stopValidation(); + } + + @Test + @SmallTest + public void testAutoDataSwitchRetry() throws Exception { + initialize(); + // Phone 0 has sub 1, phone 1 has sub 2. + // Sub 1 is default data sub. + setSlotIndexToSubId(0, 1); + setSlotIndexToSubId(1, 2); + setDefaultDataSubId(1); + + prepareIdealAutoSwitchCondition(); + processAllFutureMessages(); + + // Verify attempting to switch + verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), + eq(mPhoneSwitcherUT.mValidationCallback)); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 2); + processAllMessages(); + + assertTrue(mPhoneSwitcherUT.hasMessages(EVENT_EVALUATE_AUTO_SWITCH)); + + processAllFutureMessages(); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(true, 2); + processAllFutureMessages(); + + assertEquals(2, mPhoneSwitcherUT.getActiveDataSubId()); + } + + @Test + @SmallTest + public void testAutoDataSwitchSetNotification() throws Exception { + clearInvocations(mNotificationManager); + SubscriptionInfo mockedInfo = mock(SubscriptionInfo.class); + doReturn(false).when(mockedInfo).isOpportunistic(); + doReturn(mockedInfo).when(mSubscriptionController).getSubscriptionInfo(anyInt()); + initialize(); + // Phone 0 has sub 1, phone 1 has sub 2. + // Sub 1 is default data sub. + setSlotIndexToSubId(0, 1); + setSlotIndexToSubId(1, 2); + setDefaultDataSubId(1); + + testAutoSwitchToSecondarySucceed(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(1, null, null)) + .sendToTarget(); + processAllMessages(); + verify(mNotificationManager).notify(eq(null), eq(AUTO_DATA_SWITCH_NOTIFICATION), any()); + + // switch back to primary + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(0, null, null)) + .sendToTarget(); + processAllMessages(); + verify(mNotificationManager).cancel(eq(null), eq(AUTO_DATA_SWITCH_NOTIFICATION)); + + clearInvocations(mNotificationManager); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(1, null, null)) + .sendToTarget(); + processAllMessages(); + verify(mNotificationManager, never()) + .notify(eq(null), eq(AUTO_DATA_SWITCH_NOTIFICATION), any()); + } + /** * Test a multi-sim case with limited active phones: * - lose default via default sub change @@ -380,7 +643,7 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(0, 0); setSlotIndexToSubId(1, 1); setDefaultDataSubId(0); - mPhoneSwitcher.registerForActivePhoneSwitch(mActivePhoneSwitchHandler, + mPhoneSwitcherUT.registerForActivePhoneSwitch(mActivePhoneSwitchHandler, ACTIVE_PHONE_SWITCH, null); processAllMessages(); // verify initial conditions @@ -393,7 +656,7 @@ public class PhoneSwitcherTest extends TelephonyTest { addMmsNetworkRequest(1); AsyncResult res = new AsyncResult(1, null, null); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); // After gain of network request, mActivePhoneSwitchHandler should be notified 2 times. @@ -459,18 +722,18 @@ public class PhoneSwitcherTest extends TelephonyTest { assertTrue(mDataAllowed[0]); // Set sub 2 as preferred sub should make phone 1 activated and phone 0 deactivated. - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, false, null); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, null); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 2); + mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 2); processAllMessages(); assertFalse(mDataAllowed[0]); assertTrue(mDataAllowed[1]); // Unset preferred sub should make default data sub (phone 0 / sub 1) activated again. - mPhoneSwitcher.trySetOpportunisticDataSubscription( + mPhoneSwitcherUT.trySetOpportunisticDataSubscription( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, null); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 1); + mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 1); processAllMessages(); assertTrue(mDataAllowed[0]); assertFalse(mDataAllowed[1]); @@ -482,10 +745,11 @@ public class PhoneSwitcherTest extends TelephonyTest { * 1. Emergency call * 2. Voice call (when data during call feature is enabled). * 3. CBRS requests + * 4. Auto switch requests */ @Test @SmallTest - public void testSetPreferredDataCasePriority() throws Exception { + public void testSetPreferredDataCasePriority_CbrsWaitsForVoiceCall() throws Exception { initialize(); setAllPhonesInactive(); @@ -499,41 +763,63 @@ public class PhoneSwitcherTest extends TelephonyTest { // Notify phoneSwitcher about default data sub and default network request. NetworkRequest internetRequest = addInternetNetworkRequest(null, 50); // Phone 0 (sub 1) should be activated as it has default data sub. - assertEquals(1, mPhoneSwitcher.getActiveDataSubId()); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId()); + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); // Set sub 2 as preferred sub should make phone 1 activated and phone 0 deactivated. - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, false, null); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, null); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 2); + mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 2); // A higher priority event occurring E.g. Phone1 has active IMS call on LTE. doReturn(mImsPhone).when(mPhone).getImsPhone(); doReturn(true).when(mPhone).isUserDataEnabled(); - doReturn(true).when(mDataSettingsManager).isDataEnabled(); - mockImsRegTech(1, REGISTRATION_TECH_LTE); + doReturn(true).when(mPhone).isDataAllowed(); + mockImsRegTech(0, REGISTRATION_TECH_LTE); notifyPhoneAsInCall(mPhone); // switch shouldn't occur due to the higher priority event - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); - assertEquals(1, mPhoneSwitcher.getActiveDataSubId()); - assertEquals(2, mPhoneSwitcher.getAutoSelectedDataSubId()); + assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId()); + assertEquals(2, mPhoneSwitcherUT.getAutoSelectedDataSubId()); // The higher priority event ends, time to switch to auto selected subId. notifyPhoneAsInactive(mPhone); - assertEquals(2, mPhoneSwitcher.getActiveDataSubId()); - assertEquals(2, mPhoneSwitcher.getAutoSelectedDataSubId()); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertEquals(2, mPhoneSwitcherUT.getActiveDataSubId()); + assertEquals(2, mPhoneSwitcherUT.getAutoSelectedDataSubId()); + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); + } + + @Test + @SmallTest + public void testSetPreferredData_NoAutoSwitchWhenCbrs() 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); + + clearInvocations(mCellularNetworkValidator); + doReturn(new int[1]).when(mSubscriptionController).getActiveSubIdList(true); + prepareIdealAutoSwitchCondition(); + processAllFutureMessages(); + verify(mCellularNetworkValidator, never()).validate(eq(2), anyLong(), eq(false), + eq(mPhoneSwitcherUT.mValidationCallback)); + assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId()); } @Test @@ -541,9 +827,9 @@ public class PhoneSwitcherTest extends TelephonyTest { public void testSetPreferredDataModemCommand() throws Exception { doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported(); initialize(); - mPhoneSwitcher.registerForActivePhoneSwitch(mActivePhoneSwitchHandler, + mPhoneSwitcherUT.registerForActivePhoneSwitch(mActivePhoneSwitchHandler, ACTIVE_PHONE_SWITCH, null); - mPhoneSwitcher.registerForActivePhoneSwitch(mActivePhoneSwitchHandler, + mPhoneSwitcherUT.registerForActivePhoneSwitch(mActivePhoneSwitchHandler, ACTIVE_PHONE_SWITCH, null); verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong()); clearInvocations(mMockRadioConfig); @@ -558,7 +844,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Phone 0 (sub 1) should be preferred data phone as it has default data sub. verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); AsyncResult res = new AsyncResult(1, null, null); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong()); clearInvocations(mMockRadioConfig); @@ -570,55 +856,55 @@ public class PhoneSwitcherTest extends TelephonyTest { NetworkRequest mmsRequest = addMmsNetworkRequest(2); verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); verify(mActivePhoneSwitchHandler, never()).sendMessageAtTime(any(), anyLong()); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(mmsRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(mmsRequest, mPhone), 1)); // Set sub 2 as preferred sub should make phone 1 preferredDataModem doReturn(true).when(mSubscriptionController).isOpportunistic(2); - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, false, null); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, null); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 2); + mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 2); processAllMessages(); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong()); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(mmsRequest, mPhone), 0)); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(mmsRequest, mPhone), 1)); clearInvocations(mMockRadioConfig); clearInvocations(mActivePhoneSwitchHandler); // Unset preferred sub should make phone0 preferredDataModem again. - mPhoneSwitcher.trySetOpportunisticDataSubscription( + mPhoneSwitcherUT.trySetOpportunisticDataSubscription( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, null); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 1); + mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 1); processAllMessages(); verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); verify(mActivePhoneSwitchHandler, times(2)).sendMessageAtTime(any(), anyLong()); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(mmsRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(mmsRequest, mPhone), 1)); // SetDataAllowed should never be triggered. @@ -627,7 +913,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // Set preferred data modem should be triggered after radio on or available. clearInvocations(mMockRadioConfig); - Message.obtain(mPhoneSwitcher, EVENT_RADIO_ON, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_RADIO_ON, res).sendToTarget(); processAllMessages(); verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); } @@ -648,42 +934,42 @@ public class PhoneSwitcherTest extends TelephonyTest { setDefaultDataSubId(1); // Phone 0 (sub 1) should be activated as it has default data sub. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // Set sub 2 as preferred sub should make phone 1 activated and phone 0 deactivated. - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, true, null); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, true, null); processAllMessages(); verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), - eq(mPhoneSwitcher.mValidationCallback)); + eq(mPhoneSwitcherUT.mValidationCallback)); // Validation failed. Preferred data sub should remain 1, data phone should remain 0. - mPhoneSwitcher.mValidationCallback.onValidationDone(false, 2); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 2); processAllMessages(); - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // Validation succeeds. Preferred data sub changes to 2, data phone changes to 1. - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, true, null); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, true, null); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onValidationDone(true, 2); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(true, 2); processAllMessages(); - assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(1, mPhoneSwitcherUT.getPreferredDataPhoneId()); // Switching data back to primary (subId 1) with customized validation timeout. long timeout = 1234; mContextFixture.getCarrierConfigBundle().putLong( KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, timeout); - mPhoneSwitcher.trySetOpportunisticDataSubscription( + mPhoneSwitcherUT.trySetOpportunisticDataSubscription( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true, null); processAllMessages(); verify(mCellularNetworkValidator).validate(eq(1), eq(timeout), eq(false), - eq(mPhoneSwitcher.mValidationCallback)); - mPhoneSwitcher.mValidationCallback.onValidationDone(true, 1); + eq(mPhoneSwitcherUT.mValidationCallback)); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(true, 1); processAllMessages(); - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); } private void mockImsRegTech(int phoneId, int regTech) { doReturn(regTech).when(mMockImsRegTechProvider).get(any(), eq(phoneId)); - mPhoneSwitcher.mImsRegTechProvider = mMockImsRegTechProvider; + mPhoneSwitcherUT.mImsRegTechProvider = mMockImsRegTechProvider; } @Test @@ -701,24 +987,24 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(); + doReturn(true).when(mPhone2).isDataAllowed(); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInCall(mImsPhone); // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // User turns on data on Phone 0 doReturn(true).when(mPhone).isUserDataEnabled(); notifyDataEnabled(true); // Phone 1 should become the default data phone. - assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(1, mPhoneSwitcherUT.getPreferredDataPhoneId()); } @Test @@ -737,24 +1023,24 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(); + doReturn(true).when(mPhone2).isDataAllowed(); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInDial(mImsPhone); // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // User turns on data on Phone 0 doReturn(true).when(mPhone).isUserDataEnabled(); notifyDataEnabled(true); // Phone 1 should become the default data phone. - assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(1, mPhoneSwitcherUT.getPreferredDataPhoneId()); } @Test @SmallTest @@ -772,24 +1058,24 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should // trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(); + doReturn(true).when(mPhone2).isDataAllowed(); mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInIncomingCall(mImsPhone); // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // User turns on data on Phone 0 doReturn(true).when(mPhone).isUserDataEnabled(); notifyDataEnabled(true); // Phone 1 should become the default data phone. - assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(1, mPhoneSwitcherUT.getPreferredDataPhoneId()); } @Test @@ -807,16 +1093,16 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // Phone2 has active call, but data is turned off. So no data switching should happen. doReturn(mImsPhone).when(mPhone2).getImsPhone(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(); + doReturn(true).when(mPhone2).isDataAllowed(); mockImsRegTech(1, REGISTRATION_TECH_IWLAN); notifyPhoneAsInCall(mImsPhone); // Phone 0 should remain the default data phone. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); } @Test @@ -834,18 +1120,18 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // Phone 1 has active IMS call on CROSS_SIM. And data of DEFAULT apn is enabled. This should // not trigger data switch. doReturn(mImsPhone).when(mPhone2).getImsPhone(); doReturn(true).when(mPhone).isUserDataEnabled(); - doReturn(true).when(mDataSettingsManager2).isDataEnabled(); + doReturn(true).when(mPhone2).isDataAllowed(); mockImsRegTech(1, REGISTRATION_TECH_CROSS_SIM); notifyPhoneAsInCall(mImsPhone); // Phone 0 should remain the default data phone. - assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); // Phone 1 has has handed over the call to LTE. And data of DEFAULT apn is enabled. // This should trigger data switch. @@ -853,7 +1139,7 @@ public class PhoneSwitcherTest extends TelephonyTest { notifyImsRegistrationTechChange(mPhone2); // Phone 1 should become the default data phone. - assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId()); + assertEquals(1, mPhoneSwitcherUT.getPreferredDataPhoneId()); } @Test @@ -868,9 +1154,9 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); NetworkRequest internetRequest = addInternetNetworkRequest(null, 50); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); clearInvocations(mMockRadioConfig); setAllPhonesInactive(); @@ -880,36 +1166,36 @@ public class PhoneSwitcherTest extends TelephonyTest { notifyDataEnabled(false); notifyPhoneAsInCall(mPhone2); verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); // Phone2 has active call. So data switch to it. doReturn(true).when(mPhone).isUserDataEnabled(); notifyDataEnabled(true); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); clearInvocations(mMockRadioConfig); // Phone2 call ended. So data switch back to default data sub. notifyPhoneAsInactive(mPhone2); verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); clearInvocations(mMockRadioConfig); // Phone2 has holding call, but data is turned off. So no data switching should happen. notifyPhoneAsInHoldingCall(mPhone2); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); } @@ -926,16 +1212,16 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); NetworkRequest internetRequest = addInternetNetworkRequest(2, 50); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); // Restricted network request will should be applied. internetRequest = addInternetNetworkRequest(2, 50, true); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); } @@ -951,7 +1237,7 @@ public class PhoneSwitcherTest extends TelephonyTest { clearInvocations(mMockRadioConfig); // override the phone ID in prep for emergency call - mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, mFuturePhone); + mPhoneSwitcherUT.overrideDefaultDataForEmergency(1, 1, mFuturePhone); sendPreferredDataSuccessResult(1); processAllMessages(); verify(mFuturePhone).complete(true); @@ -972,7 +1258,7 @@ public class PhoneSwitcherTest extends TelephonyTest { clearInvocations(mMockRadioConfig); // override the phone ID in prep for emergency call - mPhoneSwitcher.overrideDefaultDataForEmergency(0, 1, mFuturePhone); + mPhoneSwitcherUT.overrideDefaultDataForEmergency(0, 1, mFuturePhone); processAllMessages(); // The radio command should never be called because the DDS hasn't changed. verify(mMockRadioConfig, never()).setPreferredDataModem(eq(0), any()); @@ -996,7 +1282,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // override the phone ID in prep for emergency call - mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, mFuturePhone); + mPhoneSwitcherUT.overrideDefaultDataForEmergency(1, 1, mFuturePhone); sendPreferredDataSuccessResult(1); processAllMessages(); verify(mFuturePhone).complete(true); @@ -1011,7 +1297,7 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); AsyncResult res = new AsyncResult(1, null, null); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); // Make sure the correct broadcast is sent out for the phone ID @@ -1033,7 +1319,7 @@ public class PhoneSwitcherTest extends TelephonyTest { clearInvocations(mTelephonyRegistryManager); // override the phone ID in prep for emergency call - mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, mFuturePhone); + mPhoneSwitcherUT.overrideDefaultDataForEmergency(1, 1, mFuturePhone); sendPreferredDataSuccessResult(1); processAllMessages(); verify(mFuturePhone).complete(true); @@ -1062,7 +1348,7 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); AsyncResult res = new AsyncResult(1, null, null); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); // Make sure the correct broadcast is sent out for the phone ID verify(mTelephonyRegistryManager).notifyActiveDataSubIdChanged(eq(1)); @@ -1083,7 +1369,7 @@ public class PhoneSwitcherTest extends TelephonyTest { clearInvocations(mTelephonyRegistryManager); // override the phone ID in prep for emergency call - mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, mFuturePhone); + mPhoneSwitcherUT.overrideDefaultDataForEmergency(1, 1, mFuturePhone); sendPreferredDataSuccessResult(1); processAllMessages(); verify(mFuturePhone).complete(true); @@ -1093,7 +1379,7 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); AsyncResult res = new AsyncResult(1, null, null); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); // Make sure the correct broadcast is sent out for the phone ID @@ -1118,7 +1404,7 @@ public class PhoneSwitcherTest extends TelephonyTest { LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); CompletableFuture futurePhone = new CompletableFuture<>(); futurePhone.whenComplete((r, error) -> queue.offer(r)); - mPhoneSwitcher.overrideDefaultDataForEmergency(1, 1, futurePhone); + mPhoneSwitcherUT.overrideDefaultDataForEmergency(1, 1, futurePhone); sendPreferredDataSuccessResult(1); processAllMessages(); Boolean result = queue.poll(); @@ -1128,7 +1414,7 @@ public class PhoneSwitcherTest extends TelephonyTest { // try override the phone ID again while there is an existing override for a different phone futurePhone = new CompletableFuture<>(); futurePhone.whenComplete((r, error) -> queue.offer(r)); - mPhoneSwitcher.overrideDefaultDataForEmergency(0, 1, futurePhone); + mPhoneSwitcherUT.overrideDefaultDataForEmergency(0, 1, futurePhone); processAllMessages(); result = queue.poll(); assertNotNull(result); @@ -1144,7 +1430,7 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); AsyncResult res = new AsyncResult(1, null, null); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); processAllMessages(); // Make sure the correct broadcast is sent out for the phone ID @@ -1164,66 +1450,65 @@ public class PhoneSwitcherTest extends TelephonyTest { // Both are active subscriptions are active sub, as they are in both active slots. setSlotIndexToSubId(0, 1); setSlotIndexToSubId(1, 2); - setDefaultDataSubId(1); // Switch to primary before a primary is selected/inactive. setDefaultDataSubId(-1); - mPhoneSwitcher.trySetOpportunisticDataSubscription( + mPhoneSwitcherUT.trySetOpportunisticDataSubscription( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, mSetOpptDataCallback1); processAllMessages(); assertEquals(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - mPhoneSwitcher.getAutoSelectedDataSubId()); + mPhoneSwitcherUT.getAutoSelectedDataSubId()); verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION); // once the primary is selected, it becomes the active sub. setDefaultDataSubId(2); - assertEquals(2, mPhoneSwitcher.getActiveDataSubId()); + assertEquals(2, mPhoneSwitcherUT.getActiveDataSubId()); setDefaultDataSubId(1); // Validating on sub 10 which is inactive. clearInvocations(mSetOpptDataCallback1); - mPhoneSwitcher.trySetOpportunisticDataSubscription(10, true, mSetOpptDataCallback1); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(10, true, mSetOpptDataCallback1); processAllMessages(); verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION); // Switch to active subId without validating. Should always succeed. - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, false, mSetOpptDataCallback1); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, mSetOpptDataCallback1); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 2); + mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 2); processAllMessages(); verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_SUCCESS); // Validating on sub 1 and fails. clearInvocations(mSetOpptDataCallback1); - mPhoneSwitcher.trySetOpportunisticDataSubscription(1, true, mSetOpptDataCallback1); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(1, true, mSetOpptDataCallback1); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onValidationDone(false, 1); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 1); processAllMessages(); verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED); // Validating on sub 2 and succeeds. - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, true, mSetOpptDataCallback2); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, true, mSetOpptDataCallback2); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onValidationDone(true, 2); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(true, 2); processAllMessages(); verify(mSetOpptDataCallback2).onComplete(SET_OPPORTUNISTIC_SUB_SUCCESS); // Switching data back to primary and validation fails. clearInvocations(mSetOpptDataCallback2); - mPhoneSwitcher.trySetOpportunisticDataSubscription( + mPhoneSwitcherUT.trySetOpportunisticDataSubscription( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true, mSetOpptDataCallback2); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onValidationDone(false, 1); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 1); processAllMessages(); verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED); // Switching data back to primary and succeeds. clearInvocations(mSetOpptDataCallback2); - mPhoneSwitcher.trySetOpportunisticDataSubscription( + mPhoneSwitcherUT.trySetOpportunisticDataSubscription( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true, mSetOpptDataCallback2); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onValidationDone(true, 1); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(true, 1); processAllMessages(); verify(mSetOpptDataCallback2).onComplete(SET_OPPORTUNISTIC_SUB_SUCCESS); @@ -1231,36 +1516,36 @@ public class PhoneSwitcherTest extends TelephonyTest { clearInvocations(mSetOpptDataCallback1); clearInvocations(mSetOpptDataCallback2); clearInvocations(mCellularNetworkValidator); - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, true, mSetOpptDataCallback1); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, true, mSetOpptDataCallback1); processAllMessages(); verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), - eq(mPhoneSwitcher.mValidationCallback)); + eq(mPhoneSwitcherUT.mValidationCallback)); doReturn(true).when(mCellularNetworkValidator).isValidating(); - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, true, mSetOpptDataCallback2); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, true, mSetOpptDataCallback2); processAllMessages(); verify(mSetOpptDataCallback1).onComplete(SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED); verify(mSetOpptDataCallback2, never()).onComplete(anyInt()); // Validation succeeds. doReturn(false).when(mCellularNetworkValidator).isValidating(); - mPhoneSwitcher.mValidationCallback.onValidationDone(true, 2); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(true, 2); processAllMessages(); verify(mSetOpptDataCallback2).onComplete(SET_OPPORTUNISTIC_SUB_SUCCESS); - mPhoneSwitcher.trySetOpportunisticDataSubscription( + mPhoneSwitcherUT.trySetOpportunisticDataSubscription( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, null); processAllMessages(); - mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 1); + mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 1); processAllMessages(); clearInvocations(mSetOpptDataCallback1); clearInvocations(mSetOpptDataCallback2); clearInvocations(mCellularNetworkValidator); // Back to back call, call 1 to switch to subId 2, call 2 to switch back. - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, true, mSetOpptDataCallback1); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, true, mSetOpptDataCallback1); processAllMessages(); verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), - eq(mPhoneSwitcher.mValidationCallback)); + eq(mPhoneSwitcherUT.mValidationCallback)); doReturn(true).when(mCellularNetworkValidator).isValidating(); - mPhoneSwitcher.trySetOpportunisticDataSubscription( + mPhoneSwitcherUT.trySetOpportunisticDataSubscription( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true, mSetOpptDataCallback2); processAllMessages(); // Call 1 should be cancelled and failed. Call 2 return success immediately as there's no @@ -1285,7 +1570,7 @@ public class PhoneSwitcherTest extends TelephonyTest { setNumPhones(2, 2); AsyncResult result = new AsyncResult(null, 2, null); - Message.obtain(mPhoneSwitcher, EVENT_MULTI_SIM_CONFIG_CHANGED, result).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MULTI_SIM_CONFIG_CHANGED, result).sendToTarget(); processAllMessages(); verify(mPhone2).registerForEmergencyCallToggle(any(), anyInt(), any()); @@ -1309,28 +1594,28 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); NetworkRequest internetRequest = addInternetNetworkRequest(null, 50); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); clearInvocations(mMockRadioConfig); setAllPhonesInactive(); // Initialization done. doReturn(true).when(mSubscriptionController).isOpportunistic(2); - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, false, mSetOpptDataCallback1); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, mSetOpptDataCallback1); processAllMessages(); verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), - eq(mPhoneSwitcher.mValidationCallback)); + eq(mPhoneSwitcherUT.mValidationCallback)); doReturn(true).when(mCellularNetworkValidator).isValidating(); // Network available on different sub. Should do nothing. - mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 1); + mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 1); processAllMessages(); verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); // Network available on corresponding sub. Should confirm switch. - mPhoneSwitcher.mValidationCallback.onNetworkAvailable(null, 2); + mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 2); processAllMessages(); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); } @@ -1347,28 +1632,28 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); NetworkRequest internetRequest = addInternetNetworkRequest(null, 50); - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); clearInvocations(mMockRadioConfig); setAllPhonesInactive(); // Initialization done. doReturn(true).when(mSubscriptionController).isOpportunistic(2); - mPhoneSwitcher.trySetOpportunisticDataSubscription(2, false, mSetOpptDataCallback1); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, mSetOpptDataCallback1); processAllMessages(); verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), - eq(mPhoneSwitcher.mValidationCallback)); + eq(mPhoneSwitcherUT.mValidationCallback)); doReturn(true).when(mCellularNetworkValidator).isValidating(); // Validation failed on different sub. Should do nothing. - mPhoneSwitcher.mValidationCallback.onValidationDone(false, 1); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 1); processAllMessages(); verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); // Network available on corresponding sub. Should confirm switch. - mPhoneSwitcher.mValidationCallback.onValidationDone(false, 2); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 2); processAllMessages(); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); } @@ -1386,16 +1671,15 @@ public class PhoneSwitcherTest extends TelephonyTest { // modem retry not invoked. AsyncResult res1 = new AsyncResult(0, null, new CommandException(CommandException.Error.INVALID_SIM_STATE)); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res1).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res1).sendToTarget(); processAllMessages(); moveTimeForward(5000); processAllMessages(); verify(mMockRadioConfig, times(0)).setPreferredDataModem(eq(0), any()); - doReturn(0).when(mSubscriptionController).getPhoneId(anyInt()); AsyncResult res2 = new AsyncResult(0, null, new CommandException(CommandException.Error.NETWORK_NOT_READY)); - Message.obtain(mPhoneSwitcher, EVENT_MODEM_COMMAND_DONE, res2).sendToTarget(); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res2).sendToTarget(); processAllMessages(); moveTimeForward(5000); processAllMessages(); @@ -1428,6 +1712,45 @@ public class PhoneSwitcherTest extends TelephonyTest { /* Private utility methods start here */ + private void prepareIdealAutoSwitchCondition() { + // 1. service state changes + serviceStateChanged(1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + serviceStateChanged(0, NetworkRegistrationInfo + .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); + + // 2.1 User data enabled on primary SIM + doReturn(true).when(mPhone).isUserDataEnabled(); + + // 2.2 Auto switch feature is enabled + doReturn(true).when(mPhone2).isDataAllowed(); + + // 3.1 No default network + doReturn(null).when(mConnectivityManager).getNetworkCapabilities(any()); + + mPhoneSwitcherUT.sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); + } + + private void serviceStateChanged(int phoneId, + @NetworkRegistrationInfo.RegistrationState int dataRegState) { + + ServiceState ss = new ServiceState(); + + ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setRegistrationState(dataRegState) + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .build()); + + ss.setDataRoamingFromRegistration(dataRegState + == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + + doReturn(ss).when(mPhones[phoneId]).getServiceState(); + + Message msg = mPhoneSwitcherUT.obtainMessage(EVENT_SERVICE_STATE_CHANGED); + msg.obj = new AsyncResult(phoneId, null, null); + mPhoneSwitcherUT.sendMessage(msg); + } + private void setAllPhonesInactive() { doReturn(mInactiveCall).when(mPhone).getForegroundCall(); doReturn(mInactiveCall).when(mPhone).getBackgroundCall(); @@ -1442,44 +1765,46 @@ public class PhoneSwitcherTest extends TelephonyTest { private void notifyPhoneAsInCall(Phone phone) { doReturn(mActiveCall).when(phone).getForegroundCall(); - mPhoneSwitcher.sendEmptyMessage(EVENT_PRECISE_CALL_STATE_CHANGED); + mPhoneSwitcherUT.sendEmptyMessage(EVENT_PRECISE_CALL_STATE_CHANGED); processAllMessages(); } private void notifyPhoneAsInDial(Phone phone) { doReturn(mDialCall).when(phone).getForegroundCall(); - mPhoneSwitcher.sendEmptyMessage(EVENT_PRECISE_CALL_STATE_CHANGED); + mPhoneSwitcherUT.sendEmptyMessage(EVENT_PRECISE_CALL_STATE_CHANGED); processAllMessages(); } private void notifyPhoneAsInIncomingCall(Phone phone) { doReturn(mIncomingCall).when(phone).getForegroundCall(); - mPhoneSwitcher.sendEmptyMessage(EVENT_PRECISE_CALL_STATE_CHANGED); + mPhoneSwitcherUT.sendEmptyMessage(EVENT_PRECISE_CALL_STATE_CHANGED); processAllMessages(); } private void notifyPhoneAsInHoldingCall(Phone phone) { doReturn(mHoldingCall).when(phone).getBackgroundCall(); - mPhoneSwitcher.sendEmptyMessage(EVENT_PRECISE_CALL_STATE_CHANGED); + mPhoneSwitcherUT.sendEmptyMessage(EVENT_PRECISE_CALL_STATE_CHANGED); processAllMessages(); } private void notifyPhoneAsInactive(Phone phone) { doReturn(mInactiveCall).when(phone).getForegroundCall(); - mPhoneSwitcher.sendEmptyMessage(EVENT_PRECISE_CALL_STATE_CHANGED); + mPhoneSwitcherUT.sendEmptyMessage(EVENT_PRECISE_CALL_STATE_CHANGED); processAllMessages(); } private void notifyDataEnabled(boolean dataEnabled) { - doReturn(dataEnabled).when(mDataSettingsManager).isDataEnabled(anyInt()); - doReturn(dataEnabled).when(mDataSettingsManager2).isDataEnabled(anyInt()); - doReturn(dataEnabled).when(mDataSettingsManager2).isDataEnabled(); - mPhoneSwitcher.sendEmptyMessage(EVENT_DATA_ENABLED_CHANGED); + doReturn(dataEnabled).when(mDataSettingsManager).isDataEnabled(); + doReturn(dataEnabled).when(mPhone2).isDataAllowed(); + mDataSettingsManagerCallbacks.get(0).onDataEnabledChanged(dataEnabled, 123 , ""); + if (mDataSettingsManagerCallbacks.size() > 1) { + mDataSettingsManagerCallbacks.get(1).onDataEnabledChanged(dataEnabled, 123, ""); + } processAllMessages(); } private void notifyImsRegistrationTechChange(Phone phone) { - mPhoneSwitcher.sendEmptyMessage(EVENT_IMS_RADIO_TECH_CHANGED); + mPhoneSwitcherUT.sendEmptyMessage(EVENT_IMS_RADIO_TECH_CHANGED); processAllMessages(); } @@ -1529,10 +1854,10 @@ public class PhoneSwitcherTest extends TelephonyTest { for (int i = 0; i < mActiveModemCount; i++) { if (defaultDataSub == (i + 1)) { // sub id is always phoneId+1 for testing - assertTrue(mPhoneSwitcher.shouldApplyNetworkRequest( + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), i)); } else { - assertFalse(mPhoneSwitcher.shouldApplyNetworkRequest( + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), i)); } } @@ -1552,8 +1877,22 @@ public class PhoneSwitcherTest extends TelephonyTest { initializeTelRegistryMock(); initializeConnManagerMock(); - mPhoneSwitcher = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper()); + mPhoneSwitcherUT = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper()); processAllMessages(); + replaceInstance(PhoneSwitcher.class, "mNotificationManager", + mPhoneSwitcherUT, mNotificationManager); + + Field field = PhoneSwitcher.class.getDeclaredField("mDataSettingsManagerCallbacks"); + field.setAccessible(true); + mDataSettingsManagerCallbacks = + (Map) + field.get(mPhoneSwitcherUT); + + int deviceConfigValue = 10000; + field = PhoneSwitcher.class.getDeclaredField( + "mAutoDataSwitchAvailabilityStabilityTimeThreshold"); + field.setAccessible(true); + field.setInt(mPhoneSwitcherUT, deviceConfigValue); verify(mTelephonyRegistryManager).addOnSubscriptionsChangedListener(any(), any()); } @@ -1568,6 +1907,7 @@ public class PhoneSwitcherTest extends TelephonyTest { doReturn(1).when(mPhone2).getPhoneId(); doReturn(true).when(mPhone2).isUserDataEnabled(); doReturn(mDataSettingsManager2).when(mPhone2).getDataSettingsManager(); + doReturn(mSST2).when(mPhone2).getServiceStateTracker(); for (int i = 0; i < supportedModemCount; i++) { mSlotIndexToSubId[i] = new int[1]; mSlotIndexToSubId[i][0] = SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -1645,6 +1985,8 @@ public class PhoneSwitcherTest extends TelephonyTest { */ private void initializeSubControllerMock() { doReturn(mDefaultDataSub).when(mSubscriptionController).getDefaultDataSubId(); + doReturn(0).when(mSubscriptionController).getPhoneId(1); + doReturn(1).when(mSubscriptionController).getPhoneId(2); doAnswer(invocation -> { int phoneId = (int) invocation.getArguments()[0]; if (phoneId == SubscriptionManager.INVALID_PHONE_INDEX) { @@ -1666,6 +2008,8 @@ public class PhoneSwitcherTest extends TelephonyTest { } return false; }).when(mSubscriptionController).isActiveSubId(anyInt()); + doReturn(new int[mSlotIndexToSubId.length]).when(mSubscriptionController) + .getActiveSubIdList(true); } private void setDefaultDataSubId(int defaultDataSub) { @@ -1676,6 +2020,8 @@ public class PhoneSwitcherTest extends TelephonyTest { private void setSlotIndexToSubId(int slotId, int subId) { mSlotIndexToSubId[slotId][0] = subId; + Phone phone = slotId == 0 ? mPhone : mPhone2; + doReturn(subId).when(phone).getSubId(); } /** -- GitLab From 1033370bb15aef00df08f5f30489e1db3b309bec Mon Sep 17 00:00:00 2001 From: Aswin Sankar Date: Thu, 20 Oct 2022 16:57:50 -0700 Subject: [PATCH 123/656] PhoneConfigurationManager: query vDSDA capability - PCM will query resource overlay for config_enable_virtual_dsda to determine if static capability for 'max active voice subscriptions' needs to be updated. Bug: 249857869 Test: PhoneConfigurationManagerTest#testConfigureAndGetMaxActiveVoiceSubscriptions() Change-Id: Iffbfafdbc28cba1aec64d4e5d6897968cfd621f6 --- .../telephony/PhoneConfigurationManager.java | 17 +++++++++++++++ .../PhoneConfigurationManagerTest.java | 21 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java index 52b2949d6c..ab0b250969 100644 --- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java +++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java @@ -123,6 +123,21 @@ public class PhoneConfigurationManager { } } + // If virtual DSDA is enabled for this UE, then updates maxActiveVoiceSubscriptions to 2. + private PhoneCapability maybeUpdateMaxActiveVoiceSubscriptions( + final PhoneCapability staticCapability) { + boolean enableVirtualDsda = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_enable_virtual_dsda); + + if (staticCapability.getLogicalModemList().size() > 1 && enableVirtualDsda) { + return new PhoneCapability.Builder(staticCapability) + .setMaxActiveVoiceSubscriptions(2) + .build(); + } else { + return staticCapability; + } + } + /** * Static method to get instance. */ @@ -181,6 +196,8 @@ public class PhoneConfigurationManager { ar = (AsyncResult) msg.obj; if (ar != null && ar.exception == null) { mStaticCapability = (PhoneCapability) ar.result; + mStaticCapability = + maybeUpdateMaxActiveVoiceSubscriptions(mStaticCapability); notifyCapabilityChanged(); } else { log(msg.what + " failure. Not getting phone capability." + ar.exception); diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java index 57713269c5..81b9ff1531 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java @@ -136,6 +136,27 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { assertEquals(PhoneCapability.DEFAULT_DSDS_CAPABILITY, mPcm.getStaticPhoneCapability()); } + @Test + @SmallTest + public void testConfigureAndGetMaxActiveVoiceSubscriptions() throws Exception { + init(2); + assertEquals(1, mPcm.getStaticPhoneCapability().getMaxActiveVoiceSubscriptions()); + + PhoneCapability dualActiveVoiceSubCapability = new PhoneCapability.Builder( + PhoneCapability.DEFAULT_DSDS_CAPABILITY) + .setMaxActiveVoiceSubscriptions(2) + .build(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(Message.class); + verify(mMockRadioConfig).getPhoneCapability(captor.capture()); + Message msg = captor.getValue(); + AsyncResult.forMessage(msg, dualActiveVoiceSubCapability, null); + msg.sendToTarget(); + processAllMessages(); + + assertEquals(2, mPcm.getStaticPhoneCapability().getMaxActiveVoiceSubscriptions()); + } + @Test @SmallTest public void testSwitchMultiSimConfig_notDsdsCapable_shouldFail() throws Exception { -- GitLab From 72bd993fc7f6d7fb48656e30037ace5feb14cd35 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Thu, 22 Sep 2022 22:24:22 +0000 Subject: [PATCH 124/656] Add setUserHandle and getUserHandle apis. Bug: 247166170 Test: Basic testing, unittests Change-Id: I78030b3c92c9a1097747b69c944c69bc8b59abe4 --- .../telephony/SubscriptionController.java | 79 ++++++++++++++++++- .../SubscriptionManagerService.java | 35 ++++++++ .../telephony/FakeTelephonyProvider.java | 5 +- .../telephony/SubscriptionControllerTest.java | 73 ++++++++++++++++- 4 files changed, 189 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index fdc2089175..b4ee52726f 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -315,7 +315,8 @@ public class SubscriptionController extends ISub.Stub { SubscriptionManager.UICC_APPLICATIONS_ENABLED, SubscriptionManager.IMS_RCS_UCE_ENABLED, SubscriptionManager.CROSS_SIM_CALLING_ENABLED, - SubscriptionManager.NR_ADVANCED_CALLING_ENABLED + SubscriptionManager.NR_ADVANCED_CALLING_ENABLED, + SubscriptionManager.USER_HANDLE )); public static SubscriptionController init(Context c) { @@ -466,6 +467,11 @@ public class SubscriptionController extends ISub.Stub { Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message); } + private void enforceManageSubscriptionUserAssociation(String message) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION, message); + } + /** * Returns whether the {@code callingPackage} has access to subscriber identifiers on the * specified {@code subId} using the provided {@code message} in any resulting @@ -2294,6 +2300,7 @@ public class SubscriptionController extends ISub.Stub { case SubscriptionManager.IMS_RCS_UCE_ENABLED: case SubscriptionManager.CROSS_SIM_CALLING_ENABLED: case SubscriptionManager.NR_ADVANCED_CALLING_ENABLED: + case SubscriptionManager.USER_HANDLE: values.put(propKey, cursor.getInt(columnIndex)); break; case SubscriptionManager.DISPLAY_NAME: @@ -3241,6 +3248,7 @@ public class SubscriptionController extends ISub.Stub { case SubscriptionManager.VOIMS_OPT_IN_STATUS: case SubscriptionManager.NR_ADVANCED_CALLING_ENABLED: case SubscriptionManager.USAGE_SETTING: + case SubscriptionManager.USER_HANDLE: value.put(propKey, Integer.parseInt(propValue)); break; case SubscriptionManager.ALLOWED_NETWORK_TYPES: @@ -3337,6 +3345,7 @@ public class SubscriptionController extends ISub.Stub { case SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER: case SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS: case SubscriptionManager.USAGE_SETTING: + case SubscriptionManager.USER_HANDLE: resultValue = cursor.getString(0); break; default: @@ -4796,6 +4805,74 @@ public class SubscriptionController extends ISub.Stub { } } + /** + * Set UserHandle for this subscription + * + * @param userHandle the userHandle associated with the subscription + * Pass {@code null} user handle to clear the association + * @param subId the unique SubscriptionInfo index in database + * @param callingPackage the package making the IPC + * @return the number of records updated. + * + * @throws SecurityException if doesn't have required permission. + * @throws IllegalArgumentException if subId is invalid. + */ + @Override + public int setUserHandle(@Nullable UserHandle userHandle, int subId, + @NonNull String callingPackage) { + enforceManageSubscriptionUserAssociation("setUserHandle"); + + if (userHandle == null) { + userHandle = UserHandle.of(UserHandle.USER_NULL); + } + + long token = Binder.clearCallingIdentity(); + try { + int ret = setSubscriptionProperty(subId, SubscriptionManager.USER_HANDLE, + String.valueOf(userHandle.getIdentifier())); + // ret is the number of records updated in the DB + if (ret != 0) { + notifySubscriptionInfoChanged(); + } else { + throw new IllegalArgumentException("[setUserHandle]: Invalid subId: " + subId); + } + return ret; + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** + * Get UserHandle of this subscription. + * + * @param subId the unique SubscriptionInfo index in database + * @param callingPackage the package making the IPC + * @return userHandle associated with this subscription + * or {@code null} if subscription is not associated with any user. + * + * @throws SecurityException if doesn't have required permission. + * @throws IllegalArgumentException if subId is invalid. + */ + @Override + public UserHandle getUserHandle(int subId, @NonNull String callingPackage) { + enforceManageSubscriptionUserAssociation("getUserHandle"); + + long token = Binder.clearCallingIdentity(); + try { + String userHandleStr = getSubscriptionProperty(subId, SubscriptionManager.USER_HANDLE); + if (userHandleStr == null) { + throw new IllegalArgumentException("[getUserHandle]: Invalid subId: " + subId); + } + UserHandle userHandle = UserHandle.of(Integer.parseInt(userHandleStr)); + if (userHandle.getIdentifier() == UserHandle.USER_NULL) { + return null; + } + return userHandle; + } finally { + Binder.restoreCallingIdentity(token); + } + } + /** * @hide */ diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 521b08c3f2..1762dc892a 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -22,6 +22,7 @@ import android.content.Context; import android.os.HandlerThread; import android.os.ParcelUuid; import android.os.TelephonyServiceManager; +import android.os.UserHandle; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; @@ -552,6 +553,40 @@ public class SubscriptionManagerService extends ISub.Stub { return 0; } + /** + * Set UserHandle for this subscription + * + * @param userHandle the userHandle associated with the subscription + * Pass {@code null} user handle to clear the association + * @param subId the unique SubscriptionInfo index in database + * @param callingPackage the package making the IPC + * @return the number of records updated. + * + * @throws SecurityException if doesn't have required permission. + * @throws IllegalArgumentException if subId is invalid. + */ + @Override + public int setUserHandle(@Nullable UserHandle userHandle, int subId, + @NonNull String callingPackage) { + return 0; + } + + /** + * Get UserHandle of this subscription. + * + * @param subId the unique SubscriptionInfo index in database + * @param callingPackage the package making the IPC + * @return userHandle associated with this subscription + * or {@code null} if subscription is not associated with any user. + * + * @throws SecurityException if doesn't have required permission. + * @throws IllegalArgumentException if subId is invalid. + */ + @Override + public UserHandle getUserHandle(int subId, @NonNull String callingPackage) { + return null; + } + /** * Log debug messages. * diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java index f1bba36a8b..3be850924c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java +++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java @@ -24,6 +24,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; import android.os.Bundle; +import android.os.UserHandle; import android.provider.BaseColumns; import android.provider.Telephony; import android.telephony.SubscriptionManager; @@ -124,7 +125,9 @@ public class FakeTelephonyProvider extends MockContentProvider { + Telephony.SimInfo.COLUMN_USAGE_SETTING + " INTEGER DEFAULT " + SubscriptionManager.USAGE_SETTING_UNKNOWN + "," + Telephony.SimInfo.COLUMN_TP_MESSAGE_REF - + " INTEGER DEFAULT -1" + + " INTEGER DEFAULT -1," + + Telephony.SimInfo.COLUMN_USER_HANDLE + " INTEGER DEFAULT " + + UserHandle.USER_NULL + ");"; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index 15dec83140..35479ba187 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -19,6 +19,7 @@ import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_REMOTE_SE import static com.android.internal.telephony.SubscriptionController.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID; import static com.android.internal.telephony.uicc.IccCardStatus.CardState.CARDSTATE_PRESENT; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -2110,4 +2111,74 @@ public class SubscriptionControllerTest extends TelephonyTest { int messageRef = SubscriptionController.getInstance().getMessageRef(subId); assertTrue("201 :", messageRef == 201); } -} + + @Test + public void setUserHandle_withoutPermission() { + testInsertSim(); + /* Get SUB ID */ + int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); + assertTrue(subIds != null && subIds.length != 0); + final int subId = subIds[0]; + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); + + assertThrows(SecurityException.class, + () -> mSubscriptionControllerUT.setUserHandle(UserHandle.of(UserHandle.USER_SYSTEM), + subId, mCallingPackage)); + } + + @Test + public void setGetUserHandle_userHandleNull() { + testInsertSim(); + /* Get SUB ID */ + int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); + assertTrue(subIds != null && subIds.length != 0); + final int subId = subIds[0]; + + mSubscriptionControllerUT.setUserHandle(null, subId, mCallingPackage); + + assertThat(mSubscriptionControllerUT.getUserHandle(subId, mCallingPackage)) + .isEqualTo(null); + } + + @Test + public void setUserHandle_invalidSubId() { + assertThrows(IllegalArgumentException.class, + () -> mSubscriptionControllerUT.setUserHandle(UserHandle.of(UserHandle.USER_SYSTEM), + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mCallingPackage)); + } + + @Test + public void setGetUserHandle_withValidUserHandleAndSubId() { + testInsertSim(); + /* Get SUB ID */ + int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); + assertTrue(subIds != null && subIds.length != 0); + final int subId = subIds[0]; + + mSubscriptionControllerUT.setUserHandle(UserHandle.of(UserHandle.USER_SYSTEM), subId, + mCallingPackage); + + assertThat(mSubscriptionControllerUT.getUserHandle(subId, mCallingPackage)) + .isEqualTo(UserHandle.of(UserHandle.USER_SYSTEM)); + } + + @Test + public void getUserHandle_withoutPermission() { + testInsertSim(); + /* Get SUB ID */ + int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); + assertTrue(subIds != null && subIds.length != 0); + final int subId = subIds[0]; + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); + + assertThrows(SecurityException.class, + () -> mSubscriptionControllerUT.getUserHandle(subId, mCallingPackage)); + } + + @Test + public void getUserHandle_invalidSubId() { + assertThrows(IllegalArgumentException.class, + () -> mSubscriptionControllerUT.getUserHandle( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mCallingPackage)); + } +} \ No newline at end of file -- GitLab From a5ee92edeb33d0b72dbd03a5a24dc8353da1ad5a Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 25 Oct 2022 15:27:49 -0700 Subject: [PATCH 125/656] Improved the anomaly report Not fixing the issue, but improve the debug message readability by specifically printing the duplicate interface network name to help future debugging. Bug: 255298635 Test: Manual Change-Id: Ic933a355ccdd36daa235e8021e3b3d2d65bb181a --- .../internal/telephony/data/DataNetwork.java | 8 +++++--- .../telephony/data/DataNetworkController.java | 15 +++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 4fe276d563..064c551d4c 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -2398,9 +2398,11 @@ public class DataNetwork extends StateMachine { mFailCause = getFailCauseFromDataCallResponse(resultCode, response); validateDataCallResponse(response); if (mFailCause == DataFailCause.NONE) { - if (mDataNetworkController.isNetworkInterfaceExisting(response.getInterfaceName())) { - logl("Interface " + response.getInterfaceName() + " already existing. Silently " - + "tear down now."); + DataNetwork dataNetwork = mDataNetworkController.getDataNetworkByInterface( + response.getInterfaceName()); + if (dataNetwork != null) { + logl("Interface " + response.getInterfaceName() + " has been already used by " + + dataNetwork + ". Silently tear down now."); // If this is a pre-5G data setup, that means APN database has some problems. For // example, different APN settings have the same APN name. if (response.getTrafficDescriptors().isEmpty()) { diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index d088b3d527..9b9545d7ab 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -2122,16 +2122,19 @@ public class DataNetworkController extends Handler { } /** - * Check if there are existing networks having the same interface name. + * Get data network by interface name. * - * @param interfaceName The interface name to check. - * @return {@code true} if the existing network has the same interface name. + * @param interfaceName The network interface name. + * @return The data network if found. */ - public boolean isNetworkInterfaceExisting(@NonNull String interfaceName) { + @Nullable + DataNetwork getDataNetworkByInterface(@NonNull String interfaceName) { return mDataNetworkList.stream() .filter(dataNetwork -> !dataNetwork.isDisconnecting()) - .anyMatch(dataNetwork -> interfaceName.equals( - dataNetwork.getLinkProperties().getInterfaceName())); + .filter(dataNetwork -> interfaceName.equals( + dataNetwork.getLinkProperties().getInterfaceName())) + .findFirst() + .orElse(null); } /** -- GitLab From 549bd62792e74930d00ef5c9fa637db457caf3b9 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 25 Oct 2022 23:16:08 +0000 Subject: [PATCH 126/656] Add resetScan parameter to cancelEmergencyNetworkScan It indicates the way how the next triggerEmergencyNetworkScan shall work. If true, modem will start the new scan from the beginning. Otherwise, it will proceed as an existing search. Test: build Bug: 243344927 Change-Id: Idaaf637b57b6a1d3fbf479c063277119961fa606 --- .../com/android/internal/telephony/RadioNetworkProxy.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java index d8ad820c62..5e1cc60691 100644 --- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java +++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java @@ -889,12 +889,16 @@ public class RadioNetworkProxy extends RadioServiceProxy { * Cancels ongoing Emergency network scan * * @param serial Serial number of the request. + * @param resetScan Indicates how the next {@link #triggerEmergencyNetworkScan} should work. + * If {@code true}, then the modem shall start the new scan from the beginning, + * otherwise the modem shall resume from the last search. + * * @throws RemoteException */ - public void cancelEmergencyNetworkScan(int serial) throws RemoteException { + public void cancelEmergencyNetworkScan(int serial, boolean resetScan) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mNetworkProxy.cancelEmergencyNetworkScan(serial); + mNetworkProxy.cancelEmergencyNetworkScan(serial, resetScan); } // Only supported on AIDL. } -- GitLab From a3d990d7be04c659ad4c51d4c410644443877e03 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 25 Oct 2022 21:54:02 -0700 Subject: [PATCH 127/656] Fix Telephony Test 1) Remove replaceInstance in phone switcher test 2) Update package visible method to be public to be visible for test 3) temporarily ignore failing tests, created 255697307 to track Bug: 244064524 Test: atest fwk Change-Id: I189577581d16528638ec85fe9801d3baf254bce3 --- .../telephony/data/DataNetworkController.java | 2 +- .../telephony/data/PhoneSwitcherTest.java | 16 +++++----------- .../telephony/euicc/EuiccControllerTest.java | 3 +++ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 33f8d44879..e57f29c0fb 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -2128,7 +2128,7 @@ public class DataNetworkController extends Handler { * @return The data network if found. */ @Nullable - DataNetwork getDataNetworkByInterface(@NonNull String interfaceName) { + public DataNetwork getDataNetworkByInterface(@NonNull String interfaceName) { return mDataNetworkList.stream() .filter(dataNetwork -> !dataNetwork.isDisconnecting()) .filter(dataNetwork -> interfaceName.equals( 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 55ecbaa225..bd4b5f8fa0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -46,7 +46,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; @@ -122,7 +121,6 @@ public class PhoneSwitcherTest extends TelephonyTest { private ISetOpportunisticDataCallback mSetOpptDataCallback2; PhoneSwitcher.ImsRegTechProvider mMockImsRegTechProvider; private SubscriptionInfo mSubscriptionInfo; - private NotificationManager mNotificationManager; private PhoneSwitcher mPhoneSwitcherUT; private SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener; @@ -158,7 +156,6 @@ public class PhoneSwitcherTest extends TelephonyTest { mSetOpptDataCallback2 = mock(ISetOpportunisticDataCallback.class); mMockImsRegTechProvider = mock(PhoneSwitcher.ImsRegTechProvider.class); mSubscriptionInfo = mock(SubscriptionInfo.class); - mNotificationManager = mock(NotificationManager.class); PhoneCapability phoneCapability = new PhoneCapability(1, 1, null, false, new int[0]); doReturn(phoneCapability).when(mPhoneConfigurationManager).getCurrentPhoneCapability(); @@ -587,7 +584,6 @@ public class PhoneSwitcherTest extends TelephonyTest { @Test @SmallTest public void testAutoDataSwitchSetNotification() throws Exception { - clearInvocations(mNotificationManager); SubscriptionInfo mockedInfo = mock(SubscriptionInfo.class); doReturn(false).when(mockedInfo).isOpportunistic(); doReturn(mockedInfo).when(mSubscriptionController).getSubscriptionInfo(anyInt()); @@ -599,23 +595,23 @@ public class PhoneSwitcherTest extends TelephonyTest { setDefaultDataSubId(1); testAutoSwitchToSecondarySucceed(); + clearInvocations(mSubscriptionController); Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(1, null, null)) .sendToTarget(); processAllMessages(); - verify(mNotificationManager).notify(eq(null), eq(AUTO_DATA_SWITCH_NOTIFICATION), any()); + verify(mSubscriptionController).getSubscriptionInfo(2); // switch back to primary + clearInvocations(mSubscriptionController); Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(0, null, null)) .sendToTarget(); processAllMessages(); - verify(mNotificationManager).cancel(eq(null), eq(AUTO_DATA_SWITCH_NOTIFICATION)); + verify(mSubscriptionController, never()).getSubscriptionInfo(1); - clearInvocations(mNotificationManager); Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(1, null, null)) .sendToTarget(); processAllMessages(); - verify(mNotificationManager, never()) - .notify(eq(null), eq(AUTO_DATA_SWITCH_NOTIFICATION), any()); + verify(mSubscriptionController, never()).getSubscriptionInfo(2); } /** @@ -1879,8 +1875,6 @@ public class PhoneSwitcherTest extends TelephonyTest { mPhoneSwitcherUT = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper()); processAllMessages(); - replaceInstance(PhoneSwitcher.class, "mNotificationManager", - mPhoneSwitcherUT, mNotificationManager); Field field = PhoneSwitcher.class.getDeclaredField("mDataSettingsManagerCallbacks"); field.setAccessible(true); 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 15316e6043..85db492203 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java @@ -75,6 +75,7 @@ import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; @@ -611,6 +612,7 @@ public class EuiccControllerTest extends TelephonyTest { assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult); } + @Ignore("b/255697307") @Test @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS}) public void testDownloadSubscription_noPrivileges_hasCarrierPrivileges_multiSim() @@ -887,6 +889,7 @@ public class EuiccControllerTest extends TelephonyTest { anyBoolean(), any(), anyBoolean()); } + @Ignore("b/255697307") @Test @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS}) public void testSwitchToSubscription_emptySubscription_success() throws Exception { -- GitLab From 1c6bc4a3ae31c9d80a4da68efbe02fe863904555 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Tue, 25 Oct 2022 20:43:22 +0000 Subject: [PATCH 128/656] Change get/setUserHandle to get/setSubscriptionUserHandle. Bug: 255592760 Test: Sanity, atest android.telephony.cts.SubscriptionManagerTest, atest com.android.internal.telephony.SubscritpionControllerTest Change-Id: I70f990a9ea0f3b146593fdba675c28cbc0f2564c --- .../telephony/SubscriptionController.java | 17 ++++----- .../SubscriptionManagerService.java | 7 +--- .../telephony/SubscriptionControllerTest.java | 37 ++++++++++--------- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index b4ee52726f..f65ed6fca0 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -4811,16 +4811,14 @@ public class SubscriptionController extends ISub.Stub { * @param userHandle the userHandle associated with the subscription * Pass {@code null} user handle to clear the association * @param subId the unique SubscriptionInfo index in database - * @param callingPackage the package making the IPC * @return the number of records updated. * * @throws SecurityException if doesn't have required permission. * @throws IllegalArgumentException if subId is invalid. */ @Override - public int setUserHandle(@Nullable UserHandle userHandle, int subId, - @NonNull String callingPackage) { - enforceManageSubscriptionUserAssociation("setUserHandle"); + public int setSubscriptionUserHandle(@Nullable UserHandle userHandle, int subId) { + enforceManageSubscriptionUserAssociation("setSubscriptionUserHandle"); if (userHandle == null) { userHandle = UserHandle.of(UserHandle.USER_NULL); @@ -4834,7 +4832,8 @@ public class SubscriptionController extends ISub.Stub { if (ret != 0) { notifySubscriptionInfoChanged(); } else { - throw new IllegalArgumentException("[setUserHandle]: Invalid subId: " + subId); + throw new IllegalArgumentException("[setSubscriptionUserHandle]: Invalid subId: " + + subId); } return ret; } finally { @@ -4846,7 +4845,6 @@ public class SubscriptionController extends ISub.Stub { * Get UserHandle of this subscription. * * @param subId the unique SubscriptionInfo index in database - * @param callingPackage the package making the IPC * @return userHandle associated with this subscription * or {@code null} if subscription is not associated with any user. * @@ -4854,14 +4852,15 @@ public class SubscriptionController extends ISub.Stub { * @throws IllegalArgumentException if subId is invalid. */ @Override - public UserHandle getUserHandle(int subId, @NonNull String callingPackage) { - enforceManageSubscriptionUserAssociation("getUserHandle"); + public UserHandle getSubscriptionUserHandle(int subId) { + enforceManageSubscriptionUserAssociation("getSubscriptionUserHandle"); long token = Binder.clearCallingIdentity(); try { String userHandleStr = getSubscriptionProperty(subId, SubscriptionManager.USER_HANDLE); if (userHandleStr == null) { - throw new IllegalArgumentException("[getUserHandle]: Invalid subId: " + subId); + throw new IllegalArgumentException("[getSubscriptionUserHandle]: Invalid subId: " + + subId); } UserHandle userHandle = UserHandle.of(Integer.parseInt(userHandleStr)); if (userHandle.getIdentifier() == UserHandle.USER_NULL) { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 1762dc892a..e0b55891a4 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -559,15 +559,13 @@ public class SubscriptionManagerService extends ISub.Stub { * @param userHandle the userHandle associated with the subscription * Pass {@code null} user handle to clear the association * @param subId the unique SubscriptionInfo index in database - * @param callingPackage the package making the IPC * @return the number of records updated. * * @throws SecurityException if doesn't have required permission. * @throws IllegalArgumentException if subId is invalid. */ @Override - public int setUserHandle(@Nullable UserHandle userHandle, int subId, - @NonNull String callingPackage) { + public int setSubscriptionUserHandle(@Nullable UserHandle userHandle, int subId) { return 0; } @@ -575,7 +573,6 @@ public class SubscriptionManagerService extends ISub.Stub { * Get UserHandle of this subscription. * * @param subId the unique SubscriptionInfo index in database - * @param callingPackage the package making the IPC * @return userHandle associated with this subscription * or {@code null} if subscription is not associated with any user. * @@ -583,7 +580,7 @@ public class SubscriptionManagerService extends ISub.Stub { * @throws IllegalArgumentException if subId is invalid. */ @Override - public UserHandle getUserHandle(int subId, @NonNull String callingPackage) { + public UserHandle getSubscriptionUserHandle(int subId) { return null; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index 35479ba187..5b8bdaaec9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -2113,7 +2113,7 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void setUserHandle_withoutPermission() { + public void setSubscriptionUserHandle_withoutPermission() { testInsertSim(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); @@ -2122,48 +2122,49 @@ public class SubscriptionControllerTest extends TelephonyTest { mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); assertThrows(SecurityException.class, - () -> mSubscriptionControllerUT.setUserHandle(UserHandle.of(UserHandle.USER_SYSTEM), - subId, mCallingPackage)); + () -> mSubscriptionControllerUT.setSubscriptionUserHandle( + UserHandle.of(UserHandle.USER_SYSTEM), subId)); } @Test - public void setGetUserHandle_userHandleNull() { + public void setGetSubscriptionUserHandle_userHandleNull() { testInsertSim(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); final int subId = subIds[0]; - mSubscriptionControllerUT.setUserHandle(null, subId, mCallingPackage); + mSubscriptionControllerUT.setSubscriptionUserHandle(null, subId); - assertThat(mSubscriptionControllerUT.getUserHandle(subId, mCallingPackage)) + assertThat(mSubscriptionControllerUT.getSubscriptionUserHandle(subId)) .isEqualTo(null); } @Test - public void setUserHandle_invalidSubId() { + public void setSubscriptionUserHandle_invalidSubId() { assertThrows(IllegalArgumentException.class, - () -> mSubscriptionControllerUT.setUserHandle(UserHandle.of(UserHandle.USER_SYSTEM), - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mCallingPackage)); + () -> mSubscriptionControllerUT.setSubscriptionUserHandle( + UserHandle.of(UserHandle.USER_SYSTEM), + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)); } @Test - public void setGetUserHandle_withValidUserHandleAndSubId() { + public void setGetSubscriptionUserHandle_withValidUserHandleAndSubId() { testInsertSim(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); final int subId = subIds[0]; - mSubscriptionControllerUT.setUserHandle(UserHandle.of(UserHandle.USER_SYSTEM), subId, - mCallingPackage); + mSubscriptionControllerUT.setSubscriptionUserHandle( + UserHandle.of(UserHandle.USER_SYSTEM), subId); - assertThat(mSubscriptionControllerUT.getUserHandle(subId, mCallingPackage)) + assertThat(mSubscriptionControllerUT.getSubscriptionUserHandle(subId)) .isEqualTo(UserHandle.of(UserHandle.USER_SYSTEM)); } @Test - public void getUserHandle_withoutPermission() { + public void getSubscriptionUserHandle_withoutPermission() { testInsertSim(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); @@ -2172,13 +2173,13 @@ public class SubscriptionControllerTest extends TelephonyTest { mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); assertThrows(SecurityException.class, - () -> mSubscriptionControllerUT.getUserHandle(subId, mCallingPackage)); + () -> mSubscriptionControllerUT.getSubscriptionUserHandle(subId)); } @Test - public void getUserHandle_invalidSubId() { + public void getSubscriptionUserHandle_invalidSubId() { assertThrows(IllegalArgumentException.class, - () -> mSubscriptionControllerUT.getUserHandle( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mCallingPackage)); + () -> mSubscriptionControllerUT.getSubscriptionUserHandle( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)); } } \ No newline at end of file -- GitLab From dd478f3052a308046d63d2a5124fec50fc538038 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 25 Oct 2022 20:52:24 -0700 Subject: [PATCH 129/656] Don't allow similar data profile for setup data call When setup data call, if a similar data profile(meaning data profiles that only differ by auto-generated id) is already being used by an existing network, don't bring up another network. Bug: 240090826 Test: atest + data browsing + phone call Change-Id: Ie216cf30e0aae8c9fcd524187d96b83e6efbf71d --- .../telephony/data/DataNetworkController.java | 7 +- .../telephony/data/DataProfileManager.java | 8 +- .../data/DataNetworkControllerTest.java | 110 ++++++++++++++++++ 3 files changed, 119 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index e57f29c0fb..bd9bed0408 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -2389,9 +2389,12 @@ public class DataNetworkController extends Handler { + dataSetupRetryEntry + ", allowed reason=" + allowedReason + ", service state=" + mServiceState); for (DataNetwork dataNetwork : mDataNetworkList) { - if (dataNetwork.getDataProfile().equals(dataProfile)) { + DataProfile currentDataProfile = dataNetwork.getDataProfile(); + if (dataProfile.equals(currentDataProfile) + || mDataProfileManager.areDataProfilesSharingApn( + dataProfile, currentDataProfile)) { log("onSetupDataNetwork: Found existing data network " + dataNetwork - + " has the same data profile."); + + " using the same or a similar data profile."); if (dataSetupRetryEntry != null) { dataSetupRetryEntry.setState(DataRetryEntry.RETRY_STATE_CANCELLED); } diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java index 6c14794ada..651eea6626 100644 --- a/src/java/com/android/internal/telephony/data/DataProfileManager.java +++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java @@ -518,7 +518,7 @@ public class DataProfileManager extends Handler { setPreferredDataProfile(preferredDataProfile); } else { preferredDataProfile = mAllDataProfiles.stream() - .filter(dp -> areDataProfileSharingApn(dp, mLastInternetDataProfile)) + .filter(dp -> areDataProfilesSharingApn(dp, mLastInternetDataProfile)) .findFirst() .orElse(null); if (preferredDataProfile != null) { @@ -751,7 +751,7 @@ public class DataProfileManager extends Handler { * @return {@code true} if the data profile is essentially the preferred data profile. */ public boolean isDataProfilePreferred(@NonNull DataProfile dataProfile) { - return areDataProfileSharingApn(dataProfile, mPreferredDataProfile); + return areDataProfilesSharingApn(dataProfile, mPreferredDataProfile); } /** @@ -990,14 +990,14 @@ public class DataProfileManager extends Handler { && (dp.getApnSetting().getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID || dp.getApnSetting().getApnSetId() == mPreferredDataProfileSetId)) - .anyMatch(dp -> areDataProfileSharingApn(dataProfile, dp)); + .anyMatch(dp -> areDataProfilesSharingApn(dataProfile, dp)); } /** * @return {@code true} if both data profiles' APN setting are non-null and essentially the same * (non-essential elements include e.g.APN Id). */ - private boolean areDataProfileSharingApn(@Nullable DataProfile a, @Nullable DataProfile b) { + public boolean areDataProfilesSharingApn(@Nullable DataProfile a, @Nullable DataProfile b) { return a != null && b != null && a.getApnSetting() != null 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 8bac4a5b80..147fe3f80e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -194,6 +194,36 @@ public class DataNetworkControllerTest extends TelephonyTest { .setPreferred(false) .build(); + // The same data profile but with different auto generated ID, should be considered the same as + // mGeneralPurposeDataProfile + private final DataProfile mDuplicatedGeneralPurposeDataProfile = new DataProfile.Builder() + .setApnSetting(new ApnSetting.Builder() + .setId(3612) + .setOperatorNumeric("12345") + .setEntryName("internet_supl_mms_apn") + .setApnName("internet_supl_mms_apn") + .setUser("user") + .setPassword("passwd") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL + | ApnSetting.TYPE_MMS) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN + | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT)) + .setLingeringNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT + | TelephonyManager.NETWORK_TYPE_BITMASK_UMTS + | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) + .setProfileId(1234) + .setMaxConns(321) + .setWaitTime(456) + .setMaxConnsTime(789) + .build()) + .setPreferred(false) + .build(); + private final DataProfile mImsCellularDataProfile = new DataProfile.Builder() .setApnSetting(new ApnSetting.Builder() .setId(2164) @@ -792,6 +822,17 @@ public class DataNetworkControllerTest extends TelephonyTest { return null; }).when(mDataProfileManager).isDataProfileCompatible(any(DataProfile.class)); + doAnswer(invocation -> { + DataProfile a = (DataProfile) invocation.getArguments()[0]; + DataProfile b = (DataProfile) invocation.getArguments()[1]; + return a != null + && b != null + && a.getApnSetting() != null + && a.getApnSetting().equals(b.getApnSetting(), + mPhone.getServiceState().getDataRoamingFromRegistration()); + }).when(mDataProfileManager).areDataProfilesSharingApn(any(DataProfile.class), + any(DataProfile.class)); + doAnswer(invocation -> { TelephonyNetworkRequest networkRequest = (TelephonyNetworkRequest) invocation.getArguments()[0]; @@ -1043,6 +1084,75 @@ public class DataNetworkControllerTest extends TelephonyTest { verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); } + @Test + public void testSetupDataNetworkWithSimilarDataProfile() throws Exception { + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllMessages(); + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); + verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); + + List dataNetworkList = getDataNetworks(); + assertThat(dataNetworkList).hasSize(1); + DataNetwork dataNetwork = dataNetworkList.get(0); + assertThat(dataNetworkList.get(0).getLinkProperties().getAddresses()).containsExactly( + InetAddresses.parseNumericAddress(IPV4_ADDRESS), + InetAddresses.parseNumericAddress(IPV6_ADDRESS)); + + verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); + + // database updated/reloaded, causing data profile id change + List profiles = List.of(mDuplicatedGeneralPurposeDataProfile); + doAnswer(invocation -> { + DataProfile dp = (DataProfile) invocation.getArguments()[0]; + + if (dp.getApnSetting() == null) return true; + + for (DataProfile dataProfile : profiles) { + if (dataProfile.getApnSetting() != null + && dataProfile.getApnSetting().equals(dp.getApnSetting(), false)) { + return true; + } + } + return null; + }).when(mDataProfileManager).isDataProfileCompatible(any(DataProfile.class)); + doAnswer(invocation -> { + TelephonyNetworkRequest networkRequest = + (TelephonyNetworkRequest) invocation.getArguments()[0]; + int networkType = (int) invocation.getArguments()[1]; + + for (DataProfile dataProfile : profiles) { + if (dataProfile.canSatisfy(networkRequest.getCapabilities()) + && (dataProfile.getApnSetting().getNetworkTypeBitmask() == 0 + || (dataProfile.getApnSetting().getNetworkTypeBitmask() + & ServiceState.getBitmaskForTech(networkType)) != 0)) { + return dataProfile; + } + } + logd("Cannot find data profile to satisfy " + networkRequest + ", network type=" + + TelephonyManager.getNetworkTypeName(networkType)); + return null; + }).when(mDataProfileManager).getDataProfileForNetworkRequest( + any(TelephonyNetworkRequest.class), anyInt()); + + // verify the network still connects + verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); + + // A NOT_VCN_MANAGED request cannot be satisfied by the existing network, but will adopt the + // same data profile + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET, + NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)); + + processAllMessages(); + + // verify the network still connects + verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); + // verify we don't try to setup a separate network for the not_vcn_managed request + dataNetworkList = getDataNetworks(); + assertThat(dataNetworkList).hasSize(1); + } + @Test public void testSetupImsDataNetwork() throws Exception { mDataNetworkControllerUT.addNetworkRequest( -- GitLab From 5db220ce91e4e63d8b8162e8727951dd1e495e3d Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Sun, 18 Sep 2022 19:16:37 +0000 Subject: [PATCH 130/656] UT for IccFileHandler file Bug: 244637886 Test: Atest Verification done Change-Id: I2d4cd6ad494d0fc258b0b695afe9e63298e5c738 --- .../telephony/uicc/IccFileHandler.java | 34 +- .../telephony/uicc/IccFileHandlerTest.java | 537 ++++++++++++++++++ 2 files changed, 551 insertions(+), 20 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/uicc/IccFileHandlerTest.java diff --git a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java index 6c4ac699b1..5f8ccb482a 100644 --- a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java @@ -22,6 +22,7 @@ import android.os.Build; import android.os.Handler; import android.os.Message; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import java.util.ArrayList; @@ -108,7 +109,7 @@ public abstract class IccFileHandler extends Handler implements IccConstants { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected final String mAid; - static class LoadLinearFixedContext { + public static class LoadLinearFixedContext { int mEfid; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -145,14 +146,11 @@ public abstract class IccFileHandler extends Handler implements IccConstants { mOnLoaded = onLoaded; mPath = path; } + } - LoadLinearFixedContext(int efid, Message onLoaded) { - mEfid = efid; - mRecordNum = 1; - mLoadAll = true; - mOnLoaded = onLoaded; - mPath = null; - } + @VisibleForTesting + public int getEfid(LoadLinearFixedContext lc) { + return lc.mEfid; } /** @@ -164,6 +162,13 @@ public abstract class IccFileHandler extends Handler implements IccConstants { mCi = ci; } + @VisibleForTesting + public IccFileHandler(CommandsInterface ci) { + mParentApp = null; + mAid = null; + mCi = ci; + } + public void dispose() { } @@ -267,8 +272,7 @@ public abstract class IccFileHandler extends Handler implements IccConstants { * @param path Path of the EF on the card * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the size of data int */ - public void getEFTransparentRecordSize(int fileid, String path, Message onLoaded) { - String efPath = (path == null) ? getEFPath(fileid) : path; + public void getEFTransparentRecordSize(int fileid, Message onLoaded) { Message response = obtainMessage(EVENT_GET_EF_TRANSPARENT_SIZE_DONE, fileid, 0, onLoaded); mCi.iccIOForApp( COMMAND_GET_RESPONSE, @@ -283,16 +287,6 @@ public abstract class IccFileHandler extends Handler implements IccConstants { response); } - /** - * Get record size for a transparent EF - * - * @param fileid EF id - * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the size of the data int - */ - public void getEFTransparentRecordSize(int fileid, Message onLoaded) { - getEFTransparentRecordSize(fileid, getEFPath(fileid), onLoaded); - } - /** * Load all records from a SIM Linear Fixed EF * diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccFileHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccFileHandlerTest.java new file mode 100644 index 0000000000..63e68e2efb --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccFileHandlerTest.java @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2022 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.uicc; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.test.TestLooper; +import android.util.Log; + +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; + +public class IccFileHandlerTest { + CommandsInterface mCi; + IccFileHandler mIccFileHandler; + private TestLooper mTestLooper; + private Handler mTestHandler; + + @Before + public void setUp() throws Exception { + mCi = mock(CommandsInterface.class); + mTestLooper = new TestLooper(); + mTestHandler = new Handler(mTestLooper.getLooper()); + mTestHandler.post( + () -> mIccFileHandler = new IccFileHandler(mCi) { + @Override + protected String getEFPath(int efid) { + switch (efid) { + case 0x4f30: + case 0x4f3a: + return "3F007F105F3A"; + } + return ""; + } + + @Override + protected void logd(String s) { + Log.d("IccFileHandlerTest", s); + } + + @Override + protected void loge(String s) { + Log.d("IccFileHandlerTest", s); + } + }); + + + mTestLooper.dispatchAll(); + } + + @After + public void tearDown() throws Exception { + if (mTestLooper != null) { + mTestLooper.dispatchAll(); + mTestLooper = null; + } + mTestHandler.removeCallbacksAndMessages(null); + mTestHandler = null; + mIccFileHandler = null; + mCi = null; + } + + @Test + public void loadEFLinearFixed_WithNullPath() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFLinearFixed(0, "", 0, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void loadEFLinearFixed() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFLinearFixed(0, 0, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void loadEFImgLinearFixed() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFImgLinearFixed(0, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void getEFLinearRecordSize_WithNullPath() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.getEFLinearRecordSize(0, "", message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void getEFLinearRecordSize() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.getEFLinearRecordSize(0, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void getEFTransparentRecordSize() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.getEFTransparentRecordSize(0, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void loadEFLinearFixedAll_FileNotFoundAtGetRecord() throws InterruptedException { + int efId = 0x4f30; + final CountDownLatch latch = new CountDownLatch(1); + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + IccIoResult iir = new IccIoResult(0x94, 0x00, + IccUtils.hexStringToBytes(null)); + AsyncResult.forMessage(response, iir, null); + mTestHandler.postDelayed(latch::countDown, 100); + response.sendToTarget(); + return null; + }).when(mCi).iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), + anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFLinearFixedAll(efId, null, message); + mTestLooper.startAutoDispatch(); + latch.await(5, java.util.concurrent.TimeUnit.SECONDS); + AsyncResult ar = (AsyncResult) message.obj; + assertNotNull(ar); + assertTrue(ar.exception instanceof IccFileNotFound); + } + + @Test + public void loadEFLinearFixedAll_FileNotFoundAtReadRecord() throws InterruptedException { + int efid = 0x4f30; + final CountDownLatch latch = new CountDownLatch(2); + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + IccIoResult iir = null; + if (response.what == 6) { + iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes( + "000000454F30040000FFFF01020145")); + latch.countDown(); + } else if (response.what == 7) { + iir = new IccIoResult(0x94, 0x00, IccUtils.hexStringToBytes(null)); + mTestHandler.postDelayed(latch::countDown, 100); + } + AsyncResult.forMessage(response, iir, null); + response.sendToTarget(); + return null; + }).when(mCi).iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), + anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFLinearFixedAll(efid, null, message); + mTestLooper.startAutoDispatch(); + latch.await(5, java.util.concurrent.TimeUnit.SECONDS); + AsyncResult ar = (AsyncResult) message.obj; + assertNotNull(ar); + assertTrue(ar.exception instanceof IccFileNotFound); + } + + @Test + public void loadEFLinearFixedAll_ExceptionAtGetRecord() throws InterruptedException { + int efid = 0x4f30; + final CountDownLatch latch = new CountDownLatch(1); + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, null, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + response.sendToTarget(); + mTestHandler.postDelayed(latch::countDown, 100); + return null; + }).when(mCi).iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), + anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFLinearFixedAll(efid, null, message); + mTestLooper.startAutoDispatch(); + latch.await(5, java.util.concurrent.TimeUnit.SECONDS); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertSame(CommandException.Error.OPERATION_NOT_ALLOWED, + ((CommandException) ar.exception).getCommandError()); + assertNull(ar.result); + } + + @Test + public void loadEFLinearFixedAll_ExceptionAtReadRecord() throws InterruptedException { + int efid = 0x4f30; + final CountDownLatch latch = new CountDownLatch(2); + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + String hexString = null; + IccIoResult iir = null; + if (response.what == 6) { + hexString = "000000454F30040000FFFF01020145"; + iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString)); + AsyncResult.forMessage(response, iir, null); + latch.countDown(); + } else if (response.what == 7) { + AsyncResult.forMessage(response, null, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + mTestHandler.postDelayed(latch::countDown, 100); + } + response.sendToTarget(); + mTestHandler.postDelayed(latch::countDown, 100); + return null; + }).when(mCi).iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), + anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFLinearFixedAll(efid, null, message); + mTestLooper.startAutoDispatch(); + latch.await(5, java.util.concurrent.TimeUnit.SECONDS); + AsyncResult ar = (AsyncResult) message.obj; + assertTrue(ar.exception instanceof CommandException); + assertSame(CommandException.Error.OPERATION_NOT_ALLOWED, + ((CommandException) ar.exception).getCommandError()); + assertNull(ar.result); + } + + @Test + public void loadEFLinearFixedAll_FullLoop() throws InterruptedException { + int efid = 0x4f30; + final CountDownLatch latch = new CountDownLatch(2); + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + String hexString = null; + if (response.what == 6) { + hexString = "000000454F30040000FFFF01020145"; + latch.countDown(); + } else if (response.what == 7) { + try { + IccFileHandler.LoadLinearFixedContext lc = + (IccFileHandler.LoadLinearFixedContext) response.obj; + if (mIccFileHandler.getEfid(lc) == efid) { + hexString = + "A814C0034F3A01C1034F3202C5034F0904C9034F2109A90FC3034F611" + + "5C4034F1108CA034F5017AA0FC2034F4A03C7034F4B06CB" + + "034F4F16FFFFFFFFFFFFFFFFFFFFFFFFFF"; + } + mTestHandler.postDelayed(latch::countDown, 100); + + } catch (Exception e) { + e.printStackTrace(); + Log.e("UsimFH", e.getMessage()); + } + + } + IccIoResult iir = new IccIoResult(0x90, 0x00, + IccUtils.hexStringToBytes(hexString)); + AsyncResult.forMessage(response, iir, null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFLinearFixedAll(efid, null, message); + mTestLooper.startAutoDispatch(); + latch.await(5, java.util.concurrent.TimeUnit.SECONDS); + AsyncResult ar = (AsyncResult) message.obj; + assertNotNull(ar); + ArrayList results = (ArrayList) ar.result; + assertEquals( + "A814C0034F3A01C1034F3202C5034F0904C9034F2109A90FC3034F6115C4034F1108CA03" + + "4F5017AA0FC2034F4A03C7034F4B06CB034F4F16FFFFFFFFFFFFFFFFFFFFFFFFFF", + IccUtils.bytesToHexString(results.get(0))); + verify(mCi, times(2)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void loadEFLinearFixedAll_WithNullPath() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFLinearFixedAll(0, "", message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void loadEFLinearFixedAll() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFLinearFixedAll(0, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void loadEFTransparent() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFTransparent(0, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void loadEFTransparent_WithZeroSize() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFTransparent(0, 0, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void loadEFImgTransparent() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + isNull(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.loadEFImgTransparent(0, 0, 0, 0, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), isNull(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void updateEFLinearFixed_WithNullPath() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + anyString(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.updateEFLinearFixed(0, "", 0, new byte[10], null, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), anyString(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void updateEFLinearFixed() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + anyString(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.updateEFLinearFixed(0, 0, new byte[10], null, message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), anyString(), isNull(), isNull(), any(Message.class)); + } + + @Test + public void updateEFTransparent() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(9); + AsyncResult.forMessage(response, "Success", null); + response.sendToTarget(); + return null; + }) + .when(mCi) + .iccIOForApp(anyInt(), anyInt(), anyString(), anyInt(), anyInt(), anyInt(), + anyString(), isNull(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mIccFileHandler.updateEFTransparent(0, new byte[10], message); + verify(mCi, times(1)).iccIOForApp(anyInt(), anyInt(), anyString(), + anyInt(), anyInt(), anyInt(), anyString(), isNull(), isNull(), any(Message.class)); + } +} -- GitLab From f84a391ccf021ec222b9055a607c1dd2e739bd0d Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Sun, 9 Oct 2022 16:43:39 +0000 Subject: [PATCH 131/656] Updating mDefaultFallbackSubId cache in multiple scenarios Bug: 238827346 Test: AtestVerified Change-Id: Idb332661ac285060a4816fae54792b35dcbbb719 --- .../telephony/SubscriptionController.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 3b580149e2..4a32898867 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -1469,7 +1469,9 @@ public class SubscriptionController extends ISub.Stub { // Set the default sub if not set or if single sim device if (!isSubscriptionForRemoteSim(subscriptionType)) { if (!SubscriptionManager.isValidSubscriptionId(defaultSubId) - || subIdCountMax == 1) { + || subIdCountMax == 1 + || mDefaultFallbackSubId.get() == + SubscriptionManager.INVALID_SUBSCRIPTION_ID) { logdl("setting default fallback subid to " + subId); setDefaultFallbackSubId(subId, subscriptionType); } @@ -1688,7 +1690,26 @@ public class SubscriptionController extends ISub.Stub { // Refresh the Cache of Active Subscription Info List refreshCachedActiveSubscriptionInfoList(); + boolean isFallBackRefreshRequired = false; + if (mDefaultFallbackSubId.get() > SubscriptionManager.INVALID_SUBSCRIPTION_ID && + mSlotIndexToSubIds.getCopy(slotIndex) != null && + mSlotIndexToSubIds.getCopy(slotIndex).contains(mDefaultFallbackSubId.get())) { + isFallBackRefreshRequired = true; + } mSlotIndexToSubIds.remove(slotIndex); + // set mDefaultFallbackSubId to invalid in case mSlotIndexToSubIds do not have any entries + if (mSlotIndexToSubIds.size() ==0 ) { + mDefaultFallbackSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } else if (isFallBackRefreshRequired) { + // set mDefaultFallbackSubId to valid subId from mSlotIndexToSubIds + for (int index = 0; index < getActiveSubIdArrayList().size(); index ++) { + int subId = getActiveSubIdArrayList().get(index); + if (subId > SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + mDefaultFallbackSubId.set(subId); + break; + } + } + } } /** -- GitLab From 87f7c851d01f2978be75a8acf18788bb625ee2e6 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 20 Oct 2022 23:14:22 -0700 Subject: [PATCH 132/656] Fixed permananent failure behaviors 1. Non-conditional based evaluations will no longer trigger setup data if the APN was marked as permanent failure earlier. Only environmental changes can result in data setup. 2. Permanent failure can be only applied to the failed APN. When this happens, frameworks retries the next non-permanent-failed APN. Fix: 254752857 Fix: 249908875 Test: Manual (verified on JP carrier) + atest FrameworksTelephonyTests + Basic testing. Change-Id: Ic147c44b0729e8204cb494eb80932ef2c11f9861 --- .../telephony/data/DataEvaluation.java | 66 +++-- .../internal/telephony/data/DataNetwork.java | 2 +- .../telephony/data/DataNetworkController.java | 21 +- .../telephony/data/DataProfileManager.java | 31 ++- .../telephony/data/DataRetryManager.java | 258 ++++++++++++------ .../data/DataNetworkControllerTest.java | 57 +++- .../data/DataProfileManagerTest.java | 46 ++-- .../telephony/data/DataRetryManagerTest.java | 31 ++- 8 files changed, 353 insertions(+), 159 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataEvaluation.java b/src/java/com/android/internal/telephony/data/DataEvaluation.java index c061e169b9..323e8b43b3 100644 --- a/src/java/com/android/internal/telephony/data/DataEvaluation.java +++ b/src/java/com/android/internal/telephony/data/DataEvaluation.java @@ -195,50 +195,74 @@ public class DataEvaluation { @VisibleForTesting public enum DataEvaluationReason { /** New request from the apps. */ - NEW_REQUEST, + NEW_REQUEST(false), /** Data config changed. */ - DATA_CONFIG_CHANGED, + DATA_CONFIG_CHANGED(true), /** SIM is loaded. */ - SIM_LOADED, + SIM_LOADED(true), /** SIM is removed. */ - SIM_REMOVAL, + SIM_REMOVAL(true), /** Data profiles changed. */ - DATA_PROFILES_CHANGED, + DATA_PROFILES_CHANGED(true), /** When service state changes.(For now only considering data RAT and data registration). */ - DATA_SERVICE_STATE_CHANGED, + DATA_SERVICE_STATE_CHANGED(true), /** When data is enabled or disabled (by user, carrier, thermal, etc...) */ - DATA_ENABLED_CHANGED, + DATA_ENABLED_CHANGED(true), /** When data enabled overrides are changed (MMS always allowed, data on non-DDS sub). */ - DATA_ENABLED_OVERRIDE_CHANGED, + DATA_ENABLED_OVERRIDE_CHANGED(true), /** When data roaming is enabled or disabled. */ - ROAMING_ENABLED_CHANGED, + ROAMING_ENABLED_CHANGED(true), /** When voice call ended (for concurrent voice/data not supported RAT). */ - VOICE_CALL_ENDED, + VOICE_CALL_ENDED(true), /** When network restricts or no longer restricts mobile data. */ - DATA_RESTRICTED_CHANGED, + DATA_RESTRICTED_CHANGED(true), /** Network capabilities changed. The unsatisfied requests might have chances to attach. */ - DATA_NETWORK_CAPABILITIES_CHANGED, + DATA_NETWORK_CAPABILITIES_CHANGED(true), /** When emergency call started or ended. */ - EMERGENCY_CALL_CHANGED, + EMERGENCY_CALL_CHANGED(true), /** When data disconnected, re-evaluate later to see if data could be brought up again. */ - RETRY_AFTER_DISCONNECTED, + RETRY_AFTER_DISCONNECTED(true), /** Data setup retry. */ - DATA_RETRY, + DATA_RETRY(false), /** For handover evaluation, or for network tearing down after handover succeeds/fails. */ - DATA_HANDOVER, + DATA_HANDOVER(true), /** Preferred transport changed. */ - PREFERRED_TRANSPORT_CHANGED, + PREFERRED_TRANSPORT_CHANGED(true), /** Slice config changed. */ - SLICE_CONFIG_CHANGED, + SLICE_CONFIG_CHANGED(true), /** * Single data network arbitration. On certain RATs, only one data network is allowed at the * same time. */ - SINGLE_DATA_NETWORK_ARBITRATION, + SINGLE_DATA_NETWORK_ARBITRATION(true), /** Query from {@link TelephonyManager#isDataConnectivityPossible()}. */ - EXTERNAL_QUERY, + EXTERNAL_QUERY(false), /** Tracking area code changed. */ - TAC_CHANGED, + TAC_CHANGED(true); + + /** + * {@code true} if the evaluation is due to environmental changes (i.e. SIM removal, + * registration state changes, etc.... + */ + private final boolean mIsConditionBased; + + /** + * @return {@code true} if the evaluation is due to environmental changes (i.e. SIM removal, + * registration state changes, etc.... + */ + public boolean isConditionBased() { + return mIsConditionBased; + } + + /** + * Constructor + * + * @param isConditionBased {@code true} if the evaluation is due to environmental changes + * (i.e. SIM removal, registration state changes, etc....) + */ + DataEvaluationReason(boolean isConditionBased) { + mIsConditionBased = isConditionBased; + } } /** Disallowed reasons. There could be multiple reasons if it is not allowed. */ diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 321d4273fc..e122591c9a 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -3190,7 +3190,7 @@ public class DataNetwork extends StateMachine { && !mAttachedNetworkRequestList.isEmpty()) { TelephonyNetworkRequest networkRequest = mAttachedNetworkRequestList.get(0); DataProfile dataProfile = mDataNetworkController.getDataProfileManager() - .getDataProfileForNetworkRequest(networkRequest, targetNetworkType); + .getDataProfileForNetworkRequest(networkRequest, targetNetworkType, true); // Some carriers have different profiles between cellular and IWLAN. We need to // dynamically switch profile, but only when those profiles have same APN name. if (dataProfile != null && dataProfile.getApnSetting() != null diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index a2d53ca931..d963bc4966 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -551,6 +551,15 @@ public class DataNetworkController extends Handler { */ public void onInternetDataNetworkConnected(@NonNull List dataProfiles) {} + /** + * Called when data network is connected. + * + * @param transport Transport for the connected network. + * @param dataProfile The data profile of the connected data network. + */ + public void onDataNetworkConnected(@TransportType int transport, + @NonNull DataProfile dataProfile) {} + /** Called when internet data network is disconnected. */ public void onInternetDataNetworkDisconnected() {} @@ -1426,7 +1435,7 @@ public class DataNetworkController extends Handler { if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)) { evaluation.addDataAllowedReason(DataAllowedReason.EMERGENCY_REQUEST); evaluation.setCandidateDataProfile(mDataProfileManager.getDataProfileForNetworkRequest( - networkRequest, getDataNetworkType(transport))); + networkRequest, getDataNetworkType(transport), true)); networkRequest.setEvaluation(evaluation); log(evaluation.toString()); return evaluation; @@ -1576,7 +1585,10 @@ public class DataNetworkController extends Handler { networkType = mServiceState.getVoiceNetworkType(); } DataProfile dataProfile = mDataProfileManager - .getDataProfileForNetworkRequest(networkRequest, networkType); + .getDataProfileForNetworkRequest(networkRequest, networkType, + // If the evaluation is due to environmental changes, then we should ignore + // the permanent failure reached earlier. + reason.isConditionBased()); if (dataProfile == null) { evaluation.addDataDisallowedReason(DataDisallowedReason.NO_SUITABLE_DATA_PROFILE); } else if (reason == DataEvaluationReason.NEW_REQUEST @@ -2608,6 +2620,11 @@ public class DataNetworkController extends Handler { */ private void onDataNetworkConnected(@NonNull DataNetwork dataNetwork) { logl("onDataNetworkConnected: " + dataNetwork); + + mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor( + () -> callback.onDataNetworkConnected(dataNetwork.getTransport(), + dataNetwork.getDataProfile()))); + mPreviousConnectedDataNetworkList.add(0, dataNetwork); // Preserve the connected data networks for debugging purposes. if (mPreviousConnectedDataNetworkList.size() > MAX_HISTORICAL_CONNECTED_DATA_NETWORKS) { diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java index 651eea6626..7360cd0655 100644 --- a/src/java/com/android/internal/telephony/data/DataProfileManager.java +++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java @@ -621,14 +621,18 @@ public class DataProfileManager extends Handler { * * @param networkRequest The network request. * @param networkType The current data network type. + * @param ignorePermanentFailure {@code true} to ignore {@link ApnSetting#getPermanentFailed()}. + * This should be set to true for condition-based retry/setup. * @return The data profile. {@code null} if can't find any satisfiable data profile. */ public @Nullable DataProfile getDataProfileForNetworkRequest( - @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType) { + @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType, + boolean ignorePermanentFailure) { ApnSetting apnSetting = null; if (networkRequest.hasAttribute(TelephonyNetworkRequest .CAPABILITY_ATTRIBUTE_APN_SETTING)) { - apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType); + apnSetting = getApnSettingForNetworkRequest(networkRequest, networkType, + ignorePermanentFailure); } TrafficDescriptor.Builder trafficDescriptorBuilder = new TrafficDescriptor.Builder(); @@ -687,10 +691,13 @@ public class DataProfileManager extends Handler { * * @param networkRequest The network request. * @param networkType The current data network type. + * @param ignorePermanentFailure {@code true} to ignore {@link ApnSetting#getPermanentFailed()}. + * This should be set to true for condition-based retry/setup. * @return The APN setting. {@code null} if can't find any satisfiable data profile. */ private @Nullable ApnSetting getApnSettingForNetworkRequest( - @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType) { + @NonNull TelephonyNetworkRequest networkRequest, @NetworkType int networkType, + boolean ignorePermanentFailure) { if (!networkRequest.hasAttribute( TelephonyNetworkRequest.CAPABILITY_ATTRIBUTE_APN_SETTING)) { loge("Network request does not have APN setting attribute."); @@ -733,6 +740,7 @@ public class DataProfileManager extends Handler { && (dp.getApnSetting().getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID || dp.getApnSetting().getApnSetId() == mPreferredDataProfileSetId)) + .filter(dp -> ignorePermanentFailure || !dp.getApnSetting().getPermanentFailed()) .collect(Collectors.toList()); if (dataProfiles.size() == 0) { log("Can't find any data profile has APN set id matched. mPreferredDataProfileSetId=" @@ -740,6 +748,15 @@ public class DataProfileManager extends Handler { return null; } + // Check if data profiles are permanently failed. + dataProfiles = dataProfiles.stream() + .filter(dp -> ignorePermanentFailure || !dp.getApnSetting().getPermanentFailed()) + .collect(Collectors.toList()); + if (dataProfiles.size() == 0) { + log("The suitable data profiles are all in permanent failed state."); + return null; + } + return dataProfiles.get(0).getApnSetting(); } @@ -772,7 +789,7 @@ public class DataProfileManager extends Handler { new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) .build(), mPhone); - return getDataProfileForNetworkRequest(networkRequest, networkType) != null; + return getDataProfileForNetworkRequest(networkRequest, networkType, true) != null; } /** @@ -1095,6 +1112,12 @@ public class DataProfileManager extends Handler { pw.println("Initial attach data profile=" + mInitialAttachDataProfile); pw.println("isTetheringDataProfileExisting=" + isTetheringDataProfileExisting( TelephonyManager.NETWORK_TYPE_LTE)); + pw.println("Permanent failed profiles="); + pw.increaseIndent(); + mAllDataProfiles.stream() + .filter(dp -> dp.getApnSetting() != null && dp.getApnSetting().getPermanentFailed()) + .forEach(pw::println); + pw.decreaseIndent(); pw.println("Local logs:"); pw.increaseIndent(); diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index e8e694d121..0beea1fdb3 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -56,7 +56,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Objects; @@ -315,10 +314,6 @@ public class DataRetryManager extends Handler { } } - if (mMaxRetries == 0) { - mRetryIntervalsMillis = Collections.emptyList(); - } - if (mMaxRetries < 0) { throw new IllegalArgumentException("Max retries should not be less than 0. " + "mMaxRetries=" + mMaxRetries); @@ -359,39 +354,45 @@ public class DataRetryManager extends Handler { } /** - * Represent a setup data network retry rule. + * Represent a rule for data setup retry. * * The syntax of the retry rule: - * 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network - * capabilities are supported. - * "capabilities=[netCaps1|netCaps2|...], [retry_interval=n1|n2|n3|n4...], - * [maximum_retries=n]" + * 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network capabilities + * are supported. If the capabilities are not specified, then the retry rule only applies + * to the current failed APN used in setup data call request. + * "capabilities=[netCaps1|netCaps2|...], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]" * * 2. Retry based on {@link DataFailCause} - * "fail_causes=[cause1|cause2|cause3|..], [retry_interval=n1|n2|n3|n4...], - * [maximum_retries=n]" + * "fail_causes=[cause1|cause2|cause3|..], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]" * * 3. Retry based on {@link NetworkCapabilities} and {@link DataFailCause}. Note that only * APN-type network capabilities are supported. * "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...], * [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]" * + * 4. Permanent fail causes (no timer-based retry) on the current failed APN. Retry interval + * is specified for retrying the next available APN. + * "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|65543|65547| + * 2252|2253|2254, retry_interval=2500" + * * For example, * "capabilities=eims, retry_interval=1000, maximum_retries=20" means if the attached * network request is emergency, then retry data network setup every 1 second for up to 20 * times. * - * "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|2254 - * , maximum_retries=0" means for those fail causes, never retry with timers. Note that - * when environment changes, retry can still happen. - * * "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|" * "5000|10000|15000|20000|40000|60000|120000|240000|600000|1200000|1800000" - * "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, - * 5s, 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries. + * "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, 5s, + * 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries. + * */ public static class DataSetupRetryRule extends DataRetryRule { + private static final String RULE_TAG_PERMANENT_FAIL_CAUSES = "permanent_fail_causes"; private static final String RULE_TAG_CAPABILITIES = "capabilities"; + + /** {@code true} if this rule is for permanent fail causes. */ + private boolean mIsPermanentFailCauseRule; + /** * Constructor * @@ -410,8 +411,23 @@ public class DataRetryManager extends Handler { } String key = tokens[0].trim(); String value = tokens[1].trim(); - if (key.equals(RULE_TAG_CAPABILITIES)) { - mNetworkCapabilities = DataUtils.getNetworkCapabilitiesFromString(value); + try { + switch (key) { + case RULE_TAG_PERMANENT_FAIL_CAUSES: + mFailCauses = Arrays.stream(value.split("\\s*\\|\\s*")) + .map(String::trim) + .map(Integer::valueOf) + .collect(Collectors.toSet()); + mIsPermanentFailCauseRule = true; + break; + case RULE_TAG_CAPABILITIES: + mNetworkCapabilities = DataUtils + .getNetworkCapabilitiesFromString(value); + break; + } + } catch (Exception e) { + e.printStackTrace(); + throw new IllegalArgumentException("illegal rule " + ruleString + ", e=" + e); } } @@ -433,6 +449,13 @@ public class DataRetryManager extends Handler { return mNetworkCapabilities; } + /** + * @return {@code true} if this rule is for permanent fail causes. + */ + public boolean isPermanentFailCauseRule() { + return mIsPermanentFailCauseRule; + } + /** * Check if this rule can be matched. * @@ -949,10 +972,27 @@ public class DataRetryManager extends Handler { }); dataNetworkController.registerDataNetworkControllerCallback( new DataNetworkControllerCallback(this::post) { + /** + * Called when data service is bound. + * + * @param transport The transport of the data service. + */ @Override public void onDataServiceBound(@TransportType int transport) { onReset(RESET_REASON_DATA_SERVICE_BOUND); } + + /** + * Called when data network is connected. + * + * @param transport Transport for the connected network. + * @param dataProfile The data profile of the connected data network. + */ + @Override + public void onDataNetworkConnected(@TransportType int transport, + @NonNull DataProfile dataProfile) { + DataRetryManager.this.onDataNetworkConnected(transport, dataProfile); + } }); mRil.registerForOn(this, EVENT_RADIO_ON, null); mRil.registerForModemReset(this, EVENT_MODEM_RESET, null); @@ -1001,7 +1041,7 @@ public class DataRetryManager extends Handler { } else if (ar.result instanceof DataProfile) { dataProfile = (DataProfile) ar.result; } - onDataProfileUnthrottled(dataProfile, apn, transport, true); + onDataProfileUnthrottled(dataProfile, apn, transport, true, true); break; case EVENT_CANCEL_PENDING_HANDOVER_RETRY: onCancelPendingHandoverRetry((DataNetwork) msg.obj); @@ -1034,6 +1074,21 @@ public class DataRetryManager extends Handler { + ", mDataHandoverRetryRuleList=" + mDataHandoverRetryRuleList); } + /** + * Called when data network is connected. + * + * @param transport Transport for the connected network. + * @param dataProfile The data profile of the connected data network. + */ + public void onDataNetworkConnected(@TransportType int transport, + @NonNull DataProfile dataProfile) { + if (dataProfile.getApnSetting() != null) { + dataProfile.getApnSetting().setPermanentFailed(false); + } + + onDataProfileUnthrottled(dataProfile, null, transport, true, false); + } + /** * Evaluate if data setup retry is needed or not. If needed, retry will be scheduled * automatically after evaluation. @@ -1072,6 +1127,7 @@ public class DataRetryManager extends Handler { // ThrottleStatus is just for API backwards compatibility reason. updateThrottleStatus(dataProfile, requestList, null, ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport, Long.MAX_VALUE); + return; } else if (retryDelayMillis != DataCallResponse.RETRY_DURATION_UNDEFINED) { // Network specifically asks retry the previous data profile again. DataSetupRetryEntry dataSetupRetryEntry = new DataSetupRetryEntry.Builder<>() @@ -1085,67 +1141,89 @@ public class DataRetryManager extends Handler { ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport, dataSetupRetryEntry.retryElapsedTime); schedule(dataSetupRetryEntry); - } else { - // Network did not suggest any retry. Use the configured rules to perform retry. - logv("mDataSetupRetryRuleList=" + mDataSetupRetryRuleList); + return; + } - // Support the legacy permanent failure configuration - if (DataFailCause.isPermanentFailure(mPhone.getContext(), cause, mPhone.getSubId())) { - log("Stopped timer-based retry. cause=" + DataFailCause.toString(cause)); + // Network did not suggest any retry. Use the configured rules to perform retry. + logv("mDataSetupRetryRuleList=" + mDataSetupRetryRuleList); + + boolean retryScheduled = false; + List groupedNetworkRequestLists = + DataUtils.getGroupedNetworkRequestList(requestList); + for (DataSetupRetryRule retryRule : mDataSetupRetryRuleList) { + if (retryRule.isPermanentFailCauseRule() && retryRule.getFailCauses().contains(cause)) { + if (dataProfile.getApnSetting() != null) { + dataProfile.getApnSetting().setPermanentFailed(true); + + // It seems strange to have retry timer in permanent failure rule, but since + // in this case permanent failure is only applicable to the failed profile, so + // we need to see if other profile can be selected for next data setup. + log("Marked " + dataProfile.getApnSetting().getApnName() + " permanently " + + "failed, but still schedule retry to see if another data profile " + + "can be used for setup data."); + // Schedule a data retry to see if another data profile could be selected. + // If the same data profile is selected again, since it's marked as + // permanent failure, it won't be used for setup data call. + schedule(new DataSetupRetryEntry.Builder<>() + .setRetryDelay(retryRule.getRetryIntervalsMillis().get(0)) + .setAppliedRetryRule(retryRule) + .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS) + .setTransport(transport) + .setNetworkRequestList(requestList) + .build()); + } else { + // For TD-based data profile, do not do anything for now. Should expand this in + // the future if needed. + log("Stopped timer-based retry for TD-based data profile. Will retry only when " + + "environment changes."); + } return; } - - boolean retryScheduled = false; - List groupedNetworkRequestLists = - DataUtils.getGroupedNetworkRequestList(requestList); for (NetworkRequestList networkRequestList : groupedNetworkRequestLists) { int capability = networkRequestList.get(0).getApnTypeNetworkCapability(); + if (retryRule.canBeMatched(capability, cause)) { + // Check if there is already a similar network request retry scheduled. + if (isSimilarNetworkRequestRetryScheduled( + networkRequestList.get(0), transport)) { + log(networkRequestList.get(0) + " already had similar retry " + + "scheduled."); + return; + } - for (DataSetupRetryRule retryRule : mDataSetupRetryRuleList) { - if (retryRule.canBeMatched(capability, cause)) { - // Check if there is already a similar network request retry scheduled. - if (isSimilarNetworkRequestRetryScheduled( - networkRequestList.get(0), transport)) { - log(networkRequestList.get(0) + " already had similar retry " - + "scheduled."); - return; - } + int failedCount = getRetryFailedCount(capability, retryRule); + log("For capability " + DataUtils.networkCapabilityToString(capability) + + ", found matching rule " + retryRule + ", failed count=" + + failedCount); + if (failedCount == retryRule.getMaxRetries()) { + log("Data retry failed for " + failedCount + " times. Stopped " + + "timer-based data retry for " + + DataUtils.networkCapabilityToString(capability) + + ". Condition-based retry will still happen when condition " + + "changes."); + return; + } - int failedCount = getRetryFailedCount(capability, retryRule); - log("For capability " + DataUtils.networkCapabilityToString(capability) - + ", found matching rule " + retryRule + ", failed count=" - + failedCount); - if (failedCount == retryRule.getMaxRetries()) { - log("Data retry failed for " + failedCount + " times. Stopped " - + "timer-based data retry for " - + DataUtils.networkCapabilityToString(capability) - + ". Condition-based retry will still happen when condition " - + "changes."); - return; - } + retryDelayMillis = retryRule.getRetryIntervalsMillis().get( + Math.min(failedCount, retryRule + .getRetryIntervalsMillis().size() - 1)); - retryDelayMillis = retryRule.getRetryIntervalsMillis().get( - Math.min(failedCount, retryRule - .getRetryIntervalsMillis().size() - 1)); - - // Schedule a data retry. - schedule(new DataSetupRetryEntry.Builder<>() - .setRetryDelay(retryDelayMillis) - .setAppliedRetryRule(retryRule) - .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS) - .setTransport(transport) - .setNetworkRequestList(networkRequestList) - .build()); - retryScheduled = true; - break; - } + // Schedule a data retry. + schedule(new DataSetupRetryEntry.Builder<>() + .setRetryDelay(retryDelayMillis) + .setAppliedRetryRule(retryRule) + .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS) + .setTransport(transport) + .setNetworkRequestList(networkRequestList) + .build()); + retryScheduled = true; + break; } } + } - if (!retryScheduled) { - log("onEvaluateDataSetupRetry: Did not match any retry rule. Stop timer-based " - + "retry."); - } + if (!retryScheduled) { + log("onEvaluateDataSetupRetry: Did not match any retry rule. Stop timer-based " + + "retry."); } } @@ -1234,7 +1312,7 @@ public class DataRetryManager extends Handler { DataProfile dataProfile = dataThrottlingEntry.dataProfile; String apn = dataProfile.getApnSetting() != null ? dataProfile.getApnSetting().getApnName() : null; - onDataProfileUnthrottled(dataProfile, apn, dataThrottlingEntry.transport, false); + onDataProfileUnthrottled(dataProfile, apn, dataThrottlingEntry.transport, false, true); } mDataThrottlingEntries.clear(); @@ -1393,9 +1471,10 @@ public class DataRetryManager extends Handler { * When this is set, {@code dataProfile} must be {@code null}. * @param transport The transport that this unthrottling request is on. * @param remove Whether to remove unthrottled entries from the list of entries. + * @param retry Whether schedule data setup retry after unthrottling. */ private void onDataProfileUnthrottled(@Nullable DataProfile dataProfile, @Nullable String apn, - @TransportType int transport, boolean remove) { + @TransportType int transport, boolean remove, boolean retry) { log("onDataProfileUnthrottled: data profile=" + dataProfile + ", apn=" + apn + ", transport=" + AccessNetworkConstants.transportTypeToString(transport) + ", remove=" + remove); @@ -1412,6 +1491,7 @@ public class DataRetryManager extends Handler { Stream stream = mDataThrottlingEntries.stream(); stream = stream.filter(entry -> entry.expirationTimeMillis > now); if (dataProfile.getApnSetting() != null) { + dataProfile.getApnSetting().setPermanentFailed(false); stream = stream .filter(entry -> entry.dataProfile.getApnSetting() != null) .filter(entry -> entry.dataProfile.getApnSetting().getApnName() @@ -1473,21 +1553,23 @@ public class DataRetryManager extends Handler { logl("onDataProfileUnthrottled: Removing the following throttling entries. " + dataUnthrottlingEntries); - for (DataThrottlingEntry entry : dataUnthrottlingEntries) { - // Immediately retry after unthrottling. - if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) { - schedule(new DataSetupRetryEntry.Builder<>() - .setDataProfile(entry.dataProfile) - .setTransport(entry.transport) - .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_DATA_PROFILE) - .setNetworkRequestList(entry.networkRequestList) - .setRetryDelay(0) - .build()); - } else if (entry.retryType == ThrottleStatus.RETRY_TYPE_HANDOVER) { - schedule(new DataHandoverRetryEntry.Builder<>() - .setDataNetwork(entry.dataNetwork) - .setRetryDelay(0) - .build()); + if (retry) { + for (DataThrottlingEntry entry : dataUnthrottlingEntries) { + // Immediately retry after unthrottling. + if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) { + schedule(new DataSetupRetryEntry.Builder<>() + .setDataProfile(entry.dataProfile) + .setTransport(entry.transport) + .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_DATA_PROFILE) + .setNetworkRequestList(entry.networkRequestList) + .setRetryDelay(0) + .build()); + } else if (entry.retryType == ThrottleStatus.RETRY_TYPE_HANDOVER) { + schedule(new DataHandoverRetryEntry.Builder<>() + .setDataNetwork(entry.dataNetwork) + .setRetryDelay(0) + .build()); + } } } if (remove) { 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 7b2f26fa6c..3e74ab4724 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -180,6 +180,7 @@ public class DataNetworkControllerTest extends TelephonyTest { .setRoamingProtocol(ApnSetting.PROTOCOL_IP) .setCarrierEnabled(true) .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | TelephonyManager.NETWORK_TYPE_BITMASK_NR | TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT)) .setLingeringNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE @@ -638,8 +639,8 @@ public class DataNetworkControllerTest extends TelephonyTest { CarrierConfigManager.KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY, new String[]{ "capabilities=eims, retry_interval=1000, maximum_retries=20", - "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|" - + "2254, maximum_retries=0", // No retry for those causes + "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|" + + "-3|65543|65547|2252|2253|2254, retry_interval=2500", "capabilities=mms|supl|cbs, retry_interval=2000", "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|" + "5000|10000|15000|20000|40000|60000|120000|240000|" @@ -803,8 +804,7 @@ public class DataNetworkControllerTest extends TelephonyTest { linkBandwidthEstimatorCallbackCaptor.capture()); mLinkBandwidthEstimatorCallback = linkBandwidthEstimatorCallbackCaptor.getValue(); - List profiles = List.of(mGeneralPurposeDataProfile, - mImsCellularDataProfile, + List profiles = List.of(mGeneralPurposeDataProfile, mImsCellularDataProfile, mImsIwlanDataProfile, mEmergencyDataProfile, mFotaDataProfile, mTetheringDataProfile); @@ -837,12 +837,15 @@ public class DataNetworkControllerTest extends TelephonyTest { TelephonyNetworkRequest networkRequest = (TelephonyNetworkRequest) invocation.getArguments()[0]; int networkType = (int) invocation.getArguments()[1]; + boolean ignorePermanentFailure = (boolean) invocation.getArguments()[2]; for (DataProfile dataProfile : profiles) { if (dataProfile.canSatisfy(networkRequest.getCapabilities()) && (dataProfile.getApnSetting().getNetworkTypeBitmask() == 0 || (dataProfile.getApnSetting().getNetworkTypeBitmask() - & ServiceState.getBitmaskForTech(networkType)) != 0)) { + & ServiceState.getBitmaskForTech(networkType)) != 0) + && (ignorePermanentFailure || (dataProfile.getApnSetting() != null + && !dataProfile.getApnSetting().getPermanentFailed()))) { return dataProfile; } } @@ -850,7 +853,7 @@ public class DataNetworkControllerTest extends TelephonyTest { + TelephonyManager.getNetworkTypeName(networkType)); return null; }).when(mDataProfileManager).getDataProfileForNetworkRequest( - any(TelephonyNetworkRequest.class), anyInt()); + any(TelephonyNetworkRequest.class), anyInt(), anyBoolean()); doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(anyInt()); @@ -1133,7 +1136,7 @@ public class DataNetworkControllerTest extends TelephonyTest { + TelephonyManager.getNetworkTypeName(networkType)); return null; }).when(mDataProfileManager).getDataProfileForNetworkRequest( - any(TelephonyNetworkRequest.class), anyInt()); + any(TelephonyNetworkRequest.class), anyInt(), anyBoolean()); // verify the network still connects verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); @@ -1177,7 +1180,8 @@ public class DataNetworkControllerTest extends TelephonyTest { setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, createDataCallResponse(1, DataCallResponse.LINK_STATUS_ACTIVE, tdList)); doReturn(mEnterpriseDataProfile).when(mDataProfileManager) - .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt()); + .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), + anyBoolean()); mDataNetworkControllerUT.addNetworkRequest( createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); @@ -1368,7 +1372,8 @@ public class DataNetworkControllerTest extends TelephonyTest { // Now RAT changes from UMTS to GSM doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest( - any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_GSM)); + any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_GSM), + anyBoolean()); serviceStateChanged(TelephonyManager.NETWORK_TYPE_GSM, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); verifyAllDataDisconnected(); @@ -1379,13 +1384,15 @@ public class DataNetworkControllerTest extends TelephonyTest { Mockito.clearInvocations(mMockedDataNetworkControllerCallback); // Now RAT changes from GSM to UMTS doReturn(null).when(mDataProfileManager).getDataProfileForNetworkRequest( - any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_UMTS)); + any(TelephonyNetworkRequest.class), eq(TelephonyManager.NETWORK_TYPE_UMTS), + anyBoolean()); serviceStateChanged(TelephonyManager.NETWORK_TYPE_UMTS, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); doReturn(mGeneralPurposeDataProfile).when(mDataProfileManager) - .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt()); + .getDataProfileForNetworkRequest(any(TelephonyNetworkRequest.class), anyInt(), + anyBoolean()); // Now RAT changes from UMTS to LTE serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); @@ -2632,6 +2639,34 @@ public class DataNetworkControllerTest extends TelephonyTest { verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); + + Mockito.clearInvocations(mMockedWwanDataServiceManager); + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + processAllFutureMessages(); + + // Even receiving a new network request, setup data call should not be sent. + verify(mMockedWwanDataServiceManager, never()).setupDataCall(anyInt(), + any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), + any(), any(), anyBoolean(), any(Message.class)); + // APN should be marked as permanent failure. + assertThat(mGeneralPurposeDataProfile.getApnSetting().getPermanentFailed()).isTrue(); + } + + @Test + public void testSetupDataNetworkConditionChangesAfterPermanentFailure() throws Exception { + testSetupDataNetworkPermanentFailure(); + + setSuccessfulSetupDataResponse(mMockedDataServiceManagers + .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), 1); + + // From LTE to NR + serviceStateChanged(TelephonyManager.NETWORK_TYPE_NR, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + + // condition change should trigger setup data, even though previously the APN has been + // marked as permanent failure. + verifyInternetConnected(); } @Test 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 cc27bfe3c1..f8de47510f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java @@ -626,7 +626,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE); + TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue(); assertThat(dp.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); @@ -637,7 +637,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); tnr = new TelephonyNetworkRequest(request, mPhone); dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE); + TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue(); assertThat(dp.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); @@ -647,7 +647,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); tnr = new TelephonyNetworkRequest(request, mPhone); dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE); + TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue(); assertThat(dp.getApnSetting().getApnName()).isEqualTo(IMS_APN); @@ -656,7 +656,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); tnr = new TelephonyNetworkRequest(request, mPhone); dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE); + TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dp).isNull(); doReturn(new NetworkRegistrationInfo.Builder() @@ -669,7 +669,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); tnr = new TelephonyNetworkRequest(request, mPhone); dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_NR); + TelephonyManager.NETWORK_TYPE_NR, false); assertThat(dp.canSatisfy(tnr.getCapabilities())).isTrue(); assertThat(dp.getApnSetting().getApnName()).isEqualTo(TETHERING_APN); } @@ -681,7 +681,7 @@ public class DataProfileManagerTest extends TelephonyTest { .build(); TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_GSM); + TelephonyManager.NETWORK_TYPE_GSM, false); // Should not find data profile due to RAT incompatible. assertThat(dp).isNull(); } @@ -693,14 +693,14 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); logd("Set setLastSetupTimestamp on " + dataProfile); dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); // See if another one can be returned. dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1); } @@ -711,7 +711,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting()).isNull(); OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId()); @@ -724,7 +724,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addEnterpriseId(2), ConnectivityManager.TYPE_NONE, 0, NetworkRequest.Type.REQUEST), mPhone); dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting()).isNull(); osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId()); @@ -740,7 +740,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting()).isNull(); OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId()); @@ -756,7 +756,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting()).isNull(); OsAppId osAppId = new OsAppId(dataProfile.getTrafficDescriptor().getOsAppId()); @@ -773,7 +773,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); dataProfile.setPreferred(true); @@ -782,7 +782,7 @@ public class DataProfileManagerTest extends TelephonyTest { // See if the same one can be returned. dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); } @@ -849,7 +849,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile).isNull(); // expect default EIMS when SIM absent @@ -858,7 +858,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS) .build(), mPhone); dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("sos"); // expect no default IMS when SIM absent @@ -867,7 +867,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) .build(), mPhone); dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile).isEqualTo(null); } @@ -898,7 +898,7 @@ public class DataProfileManagerTest extends TelephonyTest { new TelephonyNetworkRequest(new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) .build(), mPhone), - TelephonyManager.NETWORK_TYPE_LTE); + TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(IMS_APN); } @@ -910,7 +910,7 @@ public class DataProfileManagerTest extends TelephonyTest { TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); // This should get the merged data profile after deduping. DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, - TelephonyManager.NETWORK_TYPE_LTE); + TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue(); } @@ -1045,7 +1045,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApn()).isEqualTo("sos"); assertThat(dataProfile.getTrafficDescriptor().getDataNetworkName()).isEqualTo("sos"); @@ -1062,7 +1062,7 @@ public class DataProfileManagerTest extends TelephonyTest { .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(), mPhone); DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); dataProfile.setPreferred(true); @@ -1122,7 +1122,7 @@ public class DataProfileManagerTest extends TelephonyTest { // The carrier configured data profile should be the preferred APN after APN reset DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); @@ -1135,7 +1135,7 @@ public class DataProfileManagerTest extends TelephonyTest { // The carrier configured data profile should be the preferred APN after APN reset dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - tnr, TelephonyManager.NETWORK_TYPE_LTE); + tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN1); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); } 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 15eb0eae35..769a920620 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java @@ -46,6 +46,7 @@ import android.util.SparseArray; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback; +import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; import com.android.internal.telephony.data.DataRetryManager.DataHandoverRetryRule; import com.android.internal.telephony.data.DataRetryManager.DataRetryManagerCallback; import com.android.internal.telephony.data.DataRetryManager.DataSetupRetryRule; @@ -128,9 +129,6 @@ public class DataRetryManagerTest extends TelephonyTest { .setPreferred(false) .build(); - private final List mAllDataProfileList = List.of(mDataProfile1, mDataProfile2, - mDataProfile3); - // Mocked classes private DataRetryManagerCallback mDataRetryManagerCallbackMock; @@ -138,6 +136,8 @@ public class DataRetryManagerTest extends TelephonyTest { private DataConfigManagerCallback mDataConfigManagerCallback; + private DataNetworkControllerCallback mDataNetworkControllerCallback; + @Before public void setUp() throws Exception { logd("DataRetryManagerTest +Setup!"); @@ -160,6 +160,12 @@ public class DataRetryManagerTest extends TelephonyTest { verify(mDataConfigManager).registerCallback(dataConfigManagerCallbackCaptor.capture()); mDataConfigManagerCallback = dataConfigManagerCallbackCaptor.getValue(); + ArgumentCaptor dataNetworkControllerCallbackCaptor = + ArgumentCaptor.forClass(DataNetworkControllerCallback.class); + verify(mDataNetworkController).registerDataNetworkControllerCallback( + dataNetworkControllerCallbackCaptor.capture()); + mDataNetworkControllerCallback = dataNetworkControllerCallbackCaptor.getValue(); + logd("DataRetryManagerTest -Setup!"); } @@ -187,7 +193,6 @@ public class DataRetryManagerTest extends TelephonyTest { assertThat(rule.getMaxRetries()).isEqualTo(0); assertThat(rule.getFailCauses()).containsExactly(8, 27, 28, 29, 30, 32, 33, 35, 50, 51, 111, -5, -6, 65537, 65538, -3, 2253, 2254); - assertThat(rule.getRetryIntervalsMillis()).isEmpty(); ruleString = "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500| 3000|" + " 5000| 10000 | 15000| 20000|40000|60000| 120000|240000 |" @@ -484,15 +489,15 @@ public class DataRetryManagerTest extends TelephonyTest { @Test public void testDataSetupRetryPermanentFailure() { DataSetupRetryRule retryRule = new DataSetupRetryRule( - "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|" - + "2254, maximum_retries=0"); + "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|65543|" + + "65547|2252|2253|2254, retry_interval=2500"); doReturn(Collections.singletonList(retryRule)).when(mDataConfigManager) .getDataSetupRetryRules(); mDataConfigManagerCallback.onCarrierConfigChanged(); processAllMessages(); - NetworkRequest request = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(); TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); @@ -503,8 +508,17 @@ public class DataRetryManagerTest extends TelephonyTest { DataCallResponse.RETRY_DURATION_UNDEFINED); processAllFutureMessages(); - verify(mDataRetryManagerCallbackMock, never()) + // Permanent failure is only applicable to the failed APN. Retry should still happen if + // there are other APNs. + verify(mDataRetryManagerCallbackMock) .onDataNetworkSetupRetry(any(DataSetupRetryEntry.class)); + assertThat(mDataProfile1.getApnSetting().getPermanentFailed()).isTrue(); + + // When condition changes, data will still be retried. As soon as data network is connected, + // we should clear the previous permanent failure. + mDataNetworkControllerCallback.onDataNetworkConnected( + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, mDataProfile1); + assertThat(mDataProfile1.getApnSetting().getPermanentFailed()).isFalse(); } @Test @@ -698,7 +712,6 @@ public class DataRetryManagerTest extends TelephonyTest { assertThat(rule.getMaxRetries()).isEqualTo(0); assertThat(rule.getFailCauses()).containsExactly(8, 27, 28, 29, 30, 32, 33, 35, 50, 51, 111, -5, -6, 65537, 65538, -3, 2253, 2254); - assertThat(rule.getRetryIntervalsMillis()).isEmpty(); ruleString = "retry_interval=1000|2000|4000|8000|16000, maximum_retries=5"; rule = new DataHandoverRetryRule(ruleString); -- GitLab From ebaffc26a0ceb75a747b79e5acc9f18b7aa37a7a Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Tue, 18 Oct 2022 00:41:32 +0000 Subject: [PATCH 133/656] Enhance SMS error handling - Report SMS send result, internal send error, and network error code in SMS-outgoing metrics - Update the mapping from RIL errors to SmsManager#Result Bug: 250951137 Test: manual Change-Id: I48c3d998a8f9510e444b773d7eb8391d99f376bf --- proto/src/persist_atoms.proto | 2 + .../internal/telephony/ImsSmsDispatcher.java | 1 + .../internal/telephony/SMSDispatcher.java | 71 +++++++++++++++++++ .../telephony/metrics/MetricsCollector.java | 8 ++- .../internal/telephony/metrics/SmsStats.java | 31 ++++---- 5 files changed, 98 insertions(+), 15 deletions(-) diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index ebf97defe6..a4fb816bd2 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -277,6 +277,8 @@ message OutgoingSms { optional int32 retry_id = 13; optional int64 interval_millis = 14; optional int32 count = 15; + optional int32 send_error_code = 16; + optional int32 network_error_code = 17; // Internal use only optional int32 hashCode = 10001; diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java index b9f896c155..324959a00e 100644 --- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java +++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java @@ -193,6 +193,7 @@ public class ImsSmsDispatcher extends SMSDispatcher { SmsConstants.FORMAT_3GPP2.equals(getFormat()), status == ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK, reason, + networkReasonCode, tracker.mMessageId, tracker.isFromDefaultSmsApplication(mContext), tracker.getInterval()); diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index ac0d54f8a9..16922c7868 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -27,6 +27,9 @@ import android.app.Activity; import android.app.AlertDialog; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -153,6 +156,17 @@ public abstract class SMSDispatcher extends Handler { /** Handle SIM loaded */ private static final int EVENT_SIM_LOADED = 18; + /** + * When this change is enabled, more specific values of SMS sending error code + * {@link SmsManager#Result} will be returned to the SMS Apps. + * + * Refer to {@link SMSDispatcher#rilErrorToSmsManagerResult} fore more details of the new values + * of SMS sending error code that will be returned. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + static final long ADD_MORE_SMS_SENDING_ERROR_CODES = 250017070L; + @UnsupportedAppUsage protected Phone mPhone; @UnsupportedAppUsage @@ -1049,6 +1063,27 @@ public abstract class SMSDispatcher extends Handler { SmsTracker tracker) { mSmsOutgoingErrorCodes.log("rilError: " + rilError + ", MessageId: " + SmsController.formatCrossStackMessageId(tracker.mMessageId)); + + ApplicationInfo appInfo = tracker.getAppInfo(); + if (appInfo == null + || !CompatChanges.isChangeEnabled(ADD_MORE_SMS_SENDING_ERROR_CODES, appInfo.uid)) { + if (rilError == CommandException.Error.INVALID_RESPONSE + || rilError == CommandException.Error.SIM_PIN2 + || rilError == CommandException.Error.SIM_PUK2 + || rilError == CommandException.Error.SUBSCRIPTION_NOT_AVAILABLE + || rilError == CommandException.Error.SIM_ERR + || rilError == CommandException.Error.INVALID_SIM_STATE + || rilError == CommandException.Error.NO_SMS_TO_ACK + || rilError == CommandException.Error.SIM_BUSY + || rilError == CommandException.Error.SIM_FULL + || rilError == CommandException.Error.NO_SUBSCRIPTION + || rilError == CommandException.Error.NO_NETWORK_FOUND + || rilError == CommandException.Error.DEVICE_IN_USE + || rilError == CommandException.Error.ABORTED) { + return SmsManager.RESULT_ERROR_GENERIC_FAILURE; + } + } + switch (rilError) { case RADIO_NOT_AVAILABLE: return SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE; @@ -1098,6 +1133,34 @@ public abstract class SMSDispatcher extends Handler { return SmsManager.RESULT_RIL_ACCESS_BARRED; case BLOCKED_DUE_TO_CALL: return SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL; + case INVALID_SMSC_ADDRESS: + return SmsManager.RESULT_INVALID_SMSC_ADDRESS; + case INVALID_RESPONSE: + return SmsManager.RESULT_RIL_INVALID_RESPONSE; + case SIM_PIN2: + return SmsManager.RESULT_RIL_SIM_PIN2; + case SIM_PUK2: + return SmsManager.RESULT_RIL_SIM_PUK2; + case SUBSCRIPTION_NOT_AVAILABLE: + return SmsManager.RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE; + case SIM_ERR: + return SmsManager.RESULT_RIL_SIM_ERROR; + case INVALID_SIM_STATE: + return SmsManager.RESULT_RIL_INVALID_SIM_STATE; + case NO_SMS_TO_ACK: + return SmsManager.RESULT_RIL_NO_SMS_TO_ACK; + case SIM_BUSY: + return SmsManager.RESULT_RIL_SIM_BUSY; + case SIM_FULL: + return SmsManager.RESULT_RIL_SIM_FULL; + case NO_SUBSCRIPTION: + return SmsManager.RESULT_RIL_NO_SUBSCRIPTION; + case NO_NETWORK_FOUND: + return SmsManager.RESULT_RIL_NO_NETWORK_FOUND; + case DEVICE_IN_USE: + return SmsManager.RESULT_RIL_DEVICE_IN_USE; + case ABORTED: + return SmsManager.RESULT_RIL_ABORTED; default: Rlog.d(TAG, "rilErrorToSmsManagerResult: " + rilError + " " + SmsController.formatCrossStackMessageId(tracker.mMessageId)); @@ -2214,6 +2277,14 @@ public abstract class SMSDispatcher extends Handler { return mAppInfo != null ? mAppInfo.packageName : null; } + /** + * Get the calling Application Info + * @return Application Info + */ + public ApplicationInfo getAppInfo() { + return mAppInfo == null ? null : mAppInfo.applicationInfo; + } + /** Return if the SMS was originated from the default SMS application. */ public boolean isFromDefaultSmsApplication(Context context) { if (mIsFromDefaultSmsApplication == null) { diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 5d9d2b50bd..e915e4c226 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -29,8 +29,8 @@ import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_ import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_STATS; import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_TERMINATION; import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS; -import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS; import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SHORT_CODE_SMS; +import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS; import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS; import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT; import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS; @@ -69,8 +69,8 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationStat import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination; import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms; import com.android.internal.telephony.nano.PersistAtomsProto.NetworkRequestsV2; -import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms; +import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent; import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats; import com.android.internal.telephony.nano.PersistAtomsProto.RcsClientProvisioningStats; @@ -829,7 +829,9 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { sms.messageId, sms.retryId, sms.intervalMillis, - sms.count); + sms.count, + sms.sendErrorCode, + sms.networkErrorCode); } private static StatsEvent buildStatsEvent(DataCallSession dataCallSession) { diff --git a/src/java/com/android/internal/telephony/metrics/SmsStats.java b/src/java/com/android/internal/telephony/metrics/SmsStats.java index a93604dda4..5e81282881 100644 --- a/src/java/com/android/internal/telephony/metrics/SmsStats.java +++ b/src/java/com/android/internal/telephony/metrics/SmsStats.java @@ -58,8 +58,8 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms; -import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms; +import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; import com.android.telephony.Rlog; import java.util.Objects; @@ -156,43 +156,50 @@ public class SmsStats { /** Create a new atom when an outgoing SMS is sent. */ public void onOutgoingSms(boolean isOverIms, boolean is3gpp2, boolean fallbackToCs, - @SmsManager.Result int errorCode, long messageId, boolean isFromDefaultApp, + @SmsManager.Result int sendErrorCode, long messageId, boolean isFromDefaultApp, long intervalMillis) { - onOutgoingSms(isOverIms, is3gpp2, fallbackToCs, errorCode, NO_ERROR_CODE, + onOutgoingSms(isOverIms, is3gpp2, fallbackToCs, sendErrorCode, NO_ERROR_CODE, messageId, isFromDefaultApp, intervalMillis); } /** Create a new atom when an outgoing SMS is sent. */ public void onOutgoingSms(boolean isOverIms, boolean is3gpp2, boolean fallbackToCs, - @SmsManager.Result int errorCode, int radioSpecificErrorCode, long messageId, + @SmsManager.Result int sendErrorCode, int networkErrorCode, long messageId, boolean isFromDefaultApp, long intervalMillis) { OutgoingSms proto = getOutgoingDefaultProto(is3gpp2, isOverIms, messageId, isFromDefaultApp, intervalMillis); + // The field errorCode is used for up-to-Android-13 devices. From Android 14, sendErrorCode + // and networkErrorCode will be used. The field errorCode will be deprecated when most + // devices use Android 14 or higher versions. if (isOverIms) { // Populate error code and result for IMS case - proto.errorCode = errorCode; + proto.errorCode = sendErrorCode; if (fallbackToCs) { proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR_FALLBACK; - } else if (errorCode == SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY) { + } else if (sendErrorCode == SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY) { proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR_RETRY; - } else if (errorCode != SmsManager.RESULT_ERROR_NONE) { + } else if (sendErrorCode != SmsManager.RESULT_ERROR_NONE) { proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR; } } else { // Populate error code and result for CS case - if (errorCode == SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY) { + if (sendErrorCode == SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY) { proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR_RETRY; - } else if (errorCode != SmsManager.RESULT_ERROR_NONE) { + } else if (sendErrorCode != SmsManager.RESULT_ERROR_NONE) { proto.sendResult = OUTGOING_SMS__SEND_RESULT__SMS_SEND_RESULT_ERROR; } - proto.errorCode = radioSpecificErrorCode; - if (errorCode == SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE - && radioSpecificErrorCode == NO_ERROR_CODE) { + proto.errorCode = networkErrorCode; + if (sendErrorCode == SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE + && networkErrorCode == NO_ERROR_CODE) { proto.errorCode = is3gpp2 ? NO_NETWORK_ERROR_3GPP2 : NO_NETWORK_ERROR_3GPP; } } + + proto.sendErrorCode = sendErrorCode; + proto.networkErrorCode = networkErrorCode; + mAtomsStorage.addOutgoingSms(proto); } -- GitLab From a754a52613e1b468a322e9718261ddb6acb5d9ee Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Fri, 28 Oct 2022 23:37:02 -0700 Subject: [PATCH 134/656] Temporarily ignore tests with flake rate >20% Temporarily disable tests with flake rate >20% to allow enabling telephony tests in presubmit. Bug: 256282468 Bug: 256282780 Test: atest FrameworksTelephonyTests Change-Id: Idbaf066b03999e0455cafcfa0b13b23d51d7aecf --- .../internal/telephony/gsm/GsmSmsDispatcherTest.java | 2 ++ .../com/android/internal/telephony/uicc/SIMRecordsTest.java | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java index 5f4671b918..435cb574a0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java @@ -376,6 +376,7 @@ public class GsmSmsDispatcherTest extends TelephonyTest { @Test @SmallTest + @Ignore("b/256282780") public void testSendSmsByCarrierApp() throws Exception { mockCarrierApp(); mockCarrierAppStubResults(CarrierMessagingService.SEND_STATUS_OK, @@ -450,6 +451,7 @@ public class GsmSmsDispatcherTest extends TelephonyTest { @Test @SmallTest + @Ignore("b/256282780") public void testSendMultipartSmsByCarrierApp() throws Exception { mockCarrierApp(); mockCarrierAppStubResults(CarrierMessagingService.SEND_STATUS_OK, diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java index 125fb6a150..79cd6a44de 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java @@ -47,6 +47,7 @@ import com.android.telephony.Rlog; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -723,6 +724,7 @@ public class SIMRecordsTest extends TelephonyTest { } @Test + @Ignore("b/256282468") public void testSetVoiceMailNumber() throws InterruptedException { String voiceMailNumber = "1234567890"; @@ -776,6 +778,7 @@ public class SIMRecordsTest extends TelephonyTest { } @Test + @Ignore("b/256282468") public void testSetVoiceMailNumberBigAlphatag() throws InterruptedException { String voiceMailNumber = "1234567890"; @@ -830,6 +833,7 @@ public class SIMRecordsTest extends TelephonyTest { } @Test + @Ignore("b/256282468") public void testSetVoiceMailNumberUtf16Alphatag() throws InterruptedException { String voiceMailNumber = "1234567890"; @@ -883,8 +887,8 @@ public class SIMRecordsTest extends TelephonyTest { assertEquals(null, mSIMRecordsUT.getVoiceMailAlphaTag()); } - @Test + @Ignore("b/256282468") public void testSetVoiceMailNullNumber() throws InterruptedException { String voiceMailNumber = null; -- GitLab From cb4d2fb2be8dfb744a22664579c0b7005a938a31 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 14 Apr 2022 18:59:04 +0000 Subject: [PATCH 135/656] Allow IRadioIms mock modem to be connected in CF Bug: 229274730 Test: atest CtsTelephonyTestCases:TelephonyManagerTestOnMockModem Change-Id: I4d56e8f48a6753eac511e41495ccf5c8db0f57a5 (cherry picked from commit d7882fe544e4c360435aab85a5e5251dc14a6928) --- src/java/com/android/internal/telephony/RIL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index c9cfc4d77f..fbe17de687 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -759,7 +759,7 @@ public class RIL extends BaseCommands implements CommandsInterface { } try { - if (mDisabledRadioServices.get(service).contains(mPhoneId)) { + if (mMockModem == null && mDisabledRadioServices.get(service).contains(mPhoneId)) { riljLoge("getRadioServiceProxy: " + serviceToString(service) + " for " + HIDL_SERVICE_NAME[mPhoneId] + " is disabled"); } else { -- GitLab From b2edbbac3337e3077ccd955d5ab7b4207be58f87 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 21 Dec 2021 20:02:10 +0000 Subject: [PATCH 136/656] Add RadioImaProxy, ImsResponse, and ImsIndication for IRadioIms Bug: 216387835 Test: build & flash Change-Id: I278089c761cc9c5066db084d0169c1607ebe1b62 Merged-In: I278089c761cc9c5066db084d0169c1607ebe1b62 --- Android.bp | 1 + .../internal/telephony/BaseCommands.java | 22 +++ .../internal/telephony/CommandsInterface.java | 67 +++++++ .../internal/telephony/ImsIndication.java | 76 ++++++++ .../internal/telephony/ImsResponse.java | 59 +++++++ .../com/android/internal/telephony/RIL.java | 165 +++++++++++++++++- .../android/internal/telephony/RILUtils.java | 94 ++++++++++ .../internal/telephony/RadioImsProxy.java | 132 ++++++++++++++ .../internal/telephony/SrvccConnection.java | 128 ++++++++++++++ 9 files changed, 741 insertions(+), 3 deletions(-) create mode 100644 src/java/com/android/internal/telephony/ImsIndication.java create mode 100644 src/java/com/android/internal/telephony/ImsResponse.java create mode 100644 src/java/com/android/internal/telephony/RadioImsProxy.java create mode 100644 src/java/com/android/internal/telephony/SrvccConnection.java diff --git a/Android.bp b/Android.bp index d784fc8b24..eb16ba5fba 100644 --- a/Android.bp +++ b/Android.bp @@ -85,6 +85,7 @@ java_library { "android.hardware.radio-V1.6-java", "android.hardware.radio.config-V1-java", "android.hardware.radio.data-V1-java", + "android.hardware.radio.ims-V1-java", "android.hardware.radio.messaging-V1-java", "android.hardware.radio.modem-V1-java", "android.hardware.radio.network-V2-java", diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java index 764458a7d9..25cd6c70d9 100644 --- a/src/java/com/android/internal/telephony/BaseCommands.java +++ b/src/java/com/android/internal/telephony/BaseCommands.java @@ -115,6 +115,8 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mSimPhonebookChangedRegistrants = new RegistrantList(); protected RegistrantList mSimPhonebookRecordsReceivedRegistrants = new RegistrantList(); protected RegistrantList mEmergencyNetworkScanRegistrants = new RegistrantList(); + protected RegistrantList mConnectionSetupFailureRegistrants = new RegistrantList(); + protected RegistrantList mAccessAllowedRegistrants = new RegistrantList(); @UnsupportedAppUsage protected Registrant mGsmSmsRegistrant; @@ -1155,4 +1157,24 @@ public abstract class BaseCommands implements CommandsInterface { public void unregisterForEmergencyNetworkScan(Handler h) { mEmergencyNetworkScanRegistrants.remove(h); } + + @Override + public void registerForConnectionSetupFailure(Handler h, int what, Object obj) { + mConnectionSetupFailureRegistrants.addUnique(h, what, obj); + } + + @Override + public void unregisterForConnectionSetupFailure(Handler h) { + mConnectionSetupFailureRegistrants.remove(h); + } + + @Override + public void registerForAccessAllowed(Handler h, int what, Object obj) { + mAccessAllowedRegistrants.addUnique(h, what, obj); + } + + @Override + public void unregisterForAccessAllowed(Handler h) { + mAccessAllowedRegistrants.remove(h); + } } diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index cdde40e24d..329abee2be 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2746,6 +2746,38 @@ public interface CommandsInterface { */ public void unregisterForSimPhonebookRecordsReceived(Handler h); + /** + * Registers for notifications when connection setup fails. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForConnectionSetupFailure(Handler h, int what, Object obj) {} + + /** + * Unregisters for notifications when connection setup fails. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForConnectionSetupFailure(Handler h) {} + + /** + * Register for notifications when IMS traffic access is allowed + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForAccessAllowed(Handler h, int what, Object obj) {} + + /** + * Unregister for notifications when IMS traffic access is allowed + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForAccessAllowed(Handler h) {} + /** * Set the UE's usage setting. * @@ -2777,4 +2809,39 @@ public interface CommandsInterface { * @param h Handler to be removed from the registrant list. */ default void unregisterForEmergencyNetworkScan(Handler h) {} + + /** + * Provides a list of SRVCC call information to radio + * + * @param srvccConnections the list of connections. + */ + default void setSrvccCallInfo(SrvccConnection[] srvccConnections, Message result) {} + + /** + * Updates the IMS registration information to the radio. + * + * @param state the current IMS registration state. + * @param ipcan the type of IP connectivity access network where IMS features are registered. + * @param reason a failure reason for IMS registration. + * @param features IMS features such as VOICE, VIDEO and SMS. + */ + default void updateImsRegistrationInfo(int state, + int ipcan, int reason, int features, Message result) {} + + /** + * Notifies the NAS and RRC layers of the radio the type of upcoming IMS traffic. + * + * @param token The token of the request. + * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. + * @param isStart true when the traffic flow starts, false when traffic flow stops. + */ + default void notifyImsTraffic(int token, int trafficType, boolean isStart, Message result) {} + + /** + * Checks access class barring checks based on ImsTrafficType. + * + * @param token The token of the request. + * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. + */ + default void performAcbCheck(int token, int trafficType, Message result) {} } diff --git a/src/java/com/android/internal/telephony/ImsIndication.java b/src/java/com/android/internal/telephony/ImsIndication.java new file mode 100644 index 0000000000..5436607808 --- /dev/null +++ b/src/java/com/android/internal/telephony/ImsIndication.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 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; + +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ACCESS_ALLOWED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CONNECTION_SETUP_FAILURE; + +import android.hardware.radio.ims.IRadioImsIndication; +import android.os.AsyncResult; + +/** + * Interface declaring unsolicited radio indications for IMS APIs. + */ +public class ImsIndication extends IRadioImsIndication.Stub { + private final RIL mRil; + + public ImsIndication(RIL ril) { + mRil = ril; + } + + /** + * Fired by radio when any IMS traffic is not sent to network due to any failure + * on cellular networks. + * + * @param indicationType Type of radio indication. + * @param token The token provided by {@link #notifyImsTraffic} or {@link #performACBcheck}. + * @param info Connection failure information. + */ + public void onConnectionSetupFailure(int indicationType, int token, + android.hardware.radio.ims.ConnectionFailureInfo info) { + mRil.processIndication(RIL.IMS_SERVICE, indicationType); + + int[] response = new int[4]; + response[0] = token; + response[1] = info.failureReason; + response[2] = info.causeCode; + response[3] = info.waitTimeMillis; + + if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CONNECTION_SETUP_FAILURE, response); + + mRil.mConnectionSetupFailureRegistrants.notifyRegistrants( + new AsyncResult(null, response, null)); + } + + /** + * Fired by radio in response to {@link #performAcbCheck} + * if the access class check is allowed for the requested traffic type. + * + * @param indicationType Type of radio indication + * @param token The token provided by {@link #performAcbCheck} + */ + public void onAccessAllowed(int indicationType, int token) { + mRil.processIndication(RIL.IMS_SERVICE, indicationType); + + int[] response = new int[1]; + response[0] = token; + + if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_ACCESS_ALLOWED, response); + + mRil.mAccessAllowedRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); + } +} diff --git a/src/java/com/android/internal/telephony/ImsResponse.java b/src/java/com/android/internal/telephony/ImsResponse.java new file mode 100644 index 0000000000..4664c1efc1 --- /dev/null +++ b/src/java/com/android/internal/telephony/ImsResponse.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 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; + +import android.hardware.radio.RadioResponseInfo; +import android.hardware.radio.ims.IRadioImsResponse; + +/** + * Interface declaring response functions to solicited radio requests for IMS APIs. + */ +public class ImsResponse extends IRadioImsResponse.Stub { + private final RIL mRil; + + public ImsResponse(RIL ril) { + mRil = ril; + } + + /** + * @param info Response info struct containing response type, serial no. and error. + */ + public void setSrvccCallInfoResponse(RadioResponseInfo info) { + RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + } + + /** + * @param info Response info struct containing response type, serial no. and error. + */ + public void updateImsRegistrationInfoResponse(RadioResponseInfo info) { + RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + } + + /** + * @param info Response info struct containing response type, serial no. and error. + */ + public void notifyImsTrafficResponse(RadioResponseInfo info) { + RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + } + + /** + * @param info Response info struct containing response type, serial no. and error. + */ + public void performAcbCheckResponse(RadioResponseInfo info) { + RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + } +} diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index c9cfc4d77f..11ba4962d6 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -208,8 +208,9 @@ public class RIL extends BaseCommands implements CommandsInterface { static final int NETWORK_SERVICE = 4; static final int SIM_SERVICE = 5; static final int VOICE_SERVICE = 6; + static final int IMS_SERVICE = 7; static final int MIN_SERVICE_IDX = RADIO_SERVICE; - static final int MAX_SERVICE_IDX = VOICE_SERVICE; + static final int MAX_SERVICE_IDX = IMS_SERVICE; /** * An array of sets that records if services are disabled in the HAL for a specific phone ID @@ -236,6 +237,8 @@ public class RIL extends BaseCommands implements CommandsInterface { private volatile IRadio mRadioProxy = null; private DataResponse mDataResponse; private DataIndication mDataIndication; + private ImsResponse mImsResponse; + private ImsIndication mImsIndication; private MessagingResponse mMessagingResponse; private MessagingIndication mMessagingIndication; private ModemResponse mModemResponse; @@ -707,8 +710,8 @@ public class RIL extends BaseCommands implements CommandsInterface { /** * Returns a {@link RadioDataProxy}, {@link RadioMessagingProxy}, {@link RadioModemProxy}, - * {@link RadioNetworkProxy}, {@link RadioSimProxy}, {@link RadioVoiceProxy}, or an empty {@link RadioServiceProxy} - * if the service is not available. + * {@link RadioNetworkProxy}, {@link RadioSimProxy}, {@link RadioVoiceProxy}, + * {@link RadioImsProxy}, or null if the service is not available. */ @NonNull public T getRadioServiceProxy(Class serviceClass, @@ -731,6 +734,9 @@ public class RIL extends BaseCommands implements CommandsInterface { if (serviceClass == RadioVoiceProxy.class) { return (T) getRadioServiceProxy(VOICE_SERVICE, result); } + if (serviceClass == RadioImsProxy.class) { + return (T) getRadioServiceProxy(IMS_SERVICE, result); + } riljLoge("getRadioServiceProxy: unrecognized " + serviceClass); return null; } @@ -851,6 +857,21 @@ public class RIL extends BaseCommands implements CommandsInterface { .asInterface(binder)); } break; + case IMS_SERVICE: + if (mMockModem == null) { + binder = ServiceManager.waitForDeclaredService( + android.hardware.radio.ims.IRadioIms.DESCRIPTOR + "/" + + HIDL_SERVICE_NAME[mPhoneId]); + } else { + binder = mMockModem.getServiceBinder(IMS_SERVICE); + } + if (binder != null) { + mRadioVersion = RADIO_HAL_VERSION_2_1; + ((RadioImsProxy) serviceProxy).setAidl(mRadioVersion, + android.hardware.radio.ims.IRadioIms.Stub + .asInterface(binder)); + } + break; } if (serviceProxy.isEmpty() && mRadioVersion.less(RADIO_HAL_VERSION_2_0)) { @@ -962,6 +983,12 @@ public class RIL extends BaseCommands implements CommandsInterface { ((RadioVoiceProxy) serviceProxy).getAidl().setResponseFunctions( mVoiceResponse, mVoiceIndication); break; + case IMS_SERVICE: + mDeathRecipients.get(service).linkToDeath( + ((RadioImsProxy) serviceProxy).getAidl().asBinder()); + ((RadioImsProxy) serviceProxy).getAidl().setResponseFunctions( + mImsResponse, mImsIndication); + break; } } else { if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_0)) { @@ -1062,6 +1089,8 @@ public class RIL extends BaseCommands implements CommandsInterface { mRadioIndication = new RadioIndication(this); mDataResponse = new DataResponse(this); mDataIndication = new DataIndication(this); + mImsResponse = new ImsResponse(this); + mImsIndication = new ImsIndication(this); mMessagingResponse = new MessagingResponse(this); mMessagingIndication = new MessagingIndication(this); mModemResponse = new ModemResponse(this); @@ -1088,6 +1117,7 @@ public class RIL extends BaseCommands implements CommandsInterface { mServiceProxies.put(NETWORK_SERVICE, new RadioNetworkProxy()); mServiceProxies.put(SIM_SERVICE, new RadioSimProxy()); mServiceProxies.put(VOICE_SERVICE, new RadioVoiceProxy()); + mServiceProxies.put(IMS_SERVICE, new RadioImsProxy()); } else { mServiceProxies = proxies; } @@ -5089,6 +5119,133 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + @Override + public void setSrvccCallInfo(SrvccConnection[] srvccConnections, Message result) { + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); + if (imsProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_SET_SRVCC_CALL_INFO, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + imsProxy.setSrvccCallInfo(rr.mSerial, + RILUtils.convertToHalSrvccCall(srvccConnections)); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(IMS_SERVICE, "setSrvccCallInfo", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "setSrvccCallInfo: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + @Override + public void updateImsRegistrationInfo(int state, + int ipcan, int reason, int features, Message result) { + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); + if (imsProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + android.hardware.radio.ims.ImsRegistration registrationInfo = + new android.hardware.radio.ims.ImsRegistration(); + registrationInfo.state = state; + registrationInfo.ipcan = ipcan; + registrationInfo.reason = reason; + registrationInfo.features = features; + + try { + imsProxy.updateImsRegistrationInfo(rr.mSerial, registrationInfo); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(IMS_SERVICE, "updateImsRegistrationInfo", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "updateImsRegistrationInfo: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + @Override + public void notifyImsTraffic(int token, int trafficType, boolean isStart, Message result) { + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); + if (imsProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_NOTIFY_IMS_TRAFFIC, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + imsProxy.notifyImsTraffic(rr.mSerial, token, trafficType, isStart); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(IMS_SERVICE, "notifyImsTraffic", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "notifyImsTraffic: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + @Override + public void performAcbCheck(int token, int trafficType, Message result) { + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); + if (imsProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_PERFORM_ACB_CHECK, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + imsProxy.performAcbCheck(rr.mSerial, token, trafficType); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(IMS_SERVICE, "performAcbCheck", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "performAcbCheck: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + //***** Private Methods /** * This is a helper function to be called when an indication callback is called for any radio @@ -5957,6 +6114,8 @@ public class RIL extends BaseCommands implements CommandsInterface { return "SIM"; case VOICE_SERVICE: return "VOICE"; + case IMS_SERVICE: + return "IMS"; default: return "UNKNOWN:" + service; } diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 2d1107c27c..dc13cd47a6 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -116,6 +116,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_NR_DUAL import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_VONR_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_LAST_CALL_FAIL_CAUSE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NOTIFY_IMS_TRAFFIC; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_READ_ITEM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_RESET_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_WRITE_CDMA_PRL; @@ -123,6 +124,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_WRITE_I import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OEM_HOOK_RAW; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OEM_HOOK_STRINGS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OPERATOR; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PERFORM_ACB_CHECK; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PULL_LCEDATA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_AVAILABLE_NETWORKS; @@ -168,6 +170,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_RADIO_ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SIM_CARD_POWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SMSC_ADDRESS; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SRVCC_CALL_INFO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_TTY_MODE; @@ -200,10 +203,12 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_NETWO import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UDUB; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORD; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_VOICE_RADIO_TECH; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_VOICE_REGISTRATION_STATE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_WRITE_SMS_TO_SIM; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ACCESS_ALLOWED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_BARRING_INFO_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CALL_RING; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION; @@ -214,6 +219,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_PRL_CHA import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CELL_INFO_LIST; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CONNECTION_SETUP_FAILURE; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_DATA_CALL_LIST_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_DC_RT_INFO_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EMERGENCY_NUMBER_LIST; @@ -5042,6 +5048,14 @@ public class RILUtils { return "SET_USAGE_SETTING"; case RIL_REQUEST_GET_USAGE_SETTING: return "GET_USAGE_SETTING"; + case RIL_REQUEST_SET_SRVCC_CALL_INFO: + return "SET_SRVCC_CALL_INFO"; + case RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO: + return "UPDATE_IMS_REGISTRATION_INFO"; + case RIL_REQUEST_NOTIFY_IMS_TRAFFIC: + return "NOTIFY_IMS_TRAFFIC"; + case RIL_REQUEST_PERFORM_ACB_CHECK: + return "PERFORM_ACB_CHECK"; default: return ""; } @@ -5174,6 +5188,10 @@ public class RILUtils { return "UNSOL_REGISTRATION_FAILED"; case RIL_UNSOL_BARRING_INFO_CHANGED: return "UNSOL_BARRING_INFO_CHANGED"; + case RIL_UNSOL_ACCESS_ALLOWED: + return "UNSOL_ACCESS_ALLOWED"; + case RIL_UNSOL_CONNECTION_SETUP_FAILURE: + return "UNSOL_CONNECTION_SETUP_FAILURE"; default: return ""; } @@ -5322,6 +5340,82 @@ public class RILUtils { return sb.toString(); } + /** + * Converts the list of call information for Single Radio Voice Call Continuity(SRVCC). + * + * @param srvccConnections The list of call information for SRVCC. + * @return The converted list of call information. + */ + public static android.hardware.radio.ims.SrvccCall[] convertToHalSrvccCall( + SrvccConnection[] srvccConnections) { + if (srvccConnections == null) { + return new android.hardware.radio.ims.SrvccCall[0]; + } + + int length = srvccConnections.length; + android.hardware.radio.ims.SrvccCall[] srvccCalls = + new android.hardware.radio.ims.SrvccCall[length]; + + for (int i = 0; i < length; i++) { + srvccCalls[i] = new android.hardware.radio.ims.SrvccCall(); + srvccCalls[i].index = i + 1; + srvccCalls[i].callType = srvccConnections[i].getType(); + srvccCalls[i].callState = convertCallState(srvccConnections[i].getState()); + srvccCalls[i].callSubstate = srvccConnections[i].getSubState(); + srvccCalls[i].ringbackToneType = srvccConnections[i].getRingbackToneType(); + srvccCalls[i].isMpty = srvccConnections[i].isMultiParty(); + srvccCalls[i].isMT = srvccConnections[i].isIncoming(); + srvccCalls[i].number = TextUtils.emptyIfNull(srvccConnections[i].getNumber()); + srvccCalls[i].numPresentation = + convertPresentation(srvccConnections[i].getNumberPresentation()); + srvccCalls[i].name = TextUtils.emptyIfNull(srvccConnections[i].getName()); + srvccCalls[i].namePresentation = + convertPresentation(srvccConnections[i].getNamePresentation()); + } + + return srvccCalls; + } + + /** + * Converts the call state. + * + * @param state The call state. + * @return The converted call state. + */ + public static int convertCallState(Call.State state) { + switch (state) { + case ACTIVE: return android.hardware.radio.voice.Call.STATE_ACTIVE; + case HOLDING: return android.hardware.radio.voice.Call.STATE_HOLDING; + case DIALING: return android.hardware.radio.voice.Call.STATE_DIALING; + case ALERTING: return android.hardware.radio.voice.Call.STATE_ALERTING; + case INCOMING: return android.hardware.radio.voice.Call.STATE_INCOMING; + case WAITING: return android.hardware.radio.voice.Call.STATE_WAITING; + default: + throw new RuntimeException("illegal state " + state); + } + } + + /** + * Converts the number presentation type for caller id display. + * + * @param presentation The number presentation type. + * @return The converted presentation type. + */ + public static int convertPresentation(int presentation) { + switch (presentation) { + case PhoneConstants.PRESENTATION_ALLOWED: + return android.hardware.radio.voice.Call.PRESENTATION_ALLOWED; + case PhoneConstants.PRESENTATION_RESTRICTED: + return android.hardware.radio.voice.Call.PRESENTATION_RESTRICTED; + case PhoneConstants.PRESENTATION_UNKNOWN: + return android.hardware.radio.voice.Call.PRESENTATION_UNKNOWN; + case PhoneConstants.PRESENTATION_PAYPHONE: + return android.hardware.radio.voice.Call.PRESENTATION_PAYPHONE; + default: + throw new RuntimeException("illegal presentation " + presentation); + } + } + private static void logd(String log) { Rlog.d("RILUtils", log); } diff --git a/src/java/com/android/internal/telephony/RadioImsProxy.java b/src/java/com/android/internal/telephony/RadioImsProxy.java new file mode 100644 index 0000000000..e3f3b1635f --- /dev/null +++ b/src/java/com/android/internal/telephony/RadioImsProxy.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2022 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; + +import android.os.RemoteException; +import android.telephony.Rlog; + +/** + * A holder for IRadioIms. + * Use getAidl to get IRadioIms and call the AIDL implementations of the HAL APIs. + */ +public class RadioImsProxy extends RadioServiceProxy { + private static final String TAG = "RadioImsProxy"; + private volatile android.hardware.radio.ims.IRadioIms mImsProxy = null; + + /** + * Sets IRadioIms as the AIDL implementation for RadioServiceProxy. + * @param halVersion Radio HAL version. + * @param ims IRadioIms implementation. + */ + public void setAidl(HalVersion halVersion, android.hardware.radio.ims.IRadioIms ims) { + mHalVersion = halVersion; + mImsProxy = ims; + mIsAidl = true; + Rlog.d(TAG, "AIDL initialized"); + } + + /** + * Gets the AIDL implementation of RadioImsProxy. + * @return IRadioIms implementation. + */ + public android.hardware.radio.ims.IRadioIms getAidl() { + return mImsProxy; + } + + /** + * Resets RadioImsProxy. + */ + @Override + public void clear() { + super.clear(); + mImsProxy = null; + } + + /** + * Checks whether a RadioIms implementation exists. + * @return true if there is neither a HIDL nor AIDL implementation. + */ + @Override + public boolean isEmpty() { + return mRadioProxy == null && mImsProxy == null; + } + + /** + * No implementation in IRadioIms. + * @throws RemoteException. + */ + @Override + public void responseAcknowledgement() throws RemoteException { + /* Currently, IRadioIms doesn't support the following response types: + * - RadioIndicationType.UNSOLICITED_ACK_EXP + * - RadioResponseType.SOLICITED_ACK_EXP */ + // no-op + } + + /** + * Calls IRadioIms#setSrvccCallInfo. + * @param serial Serial number of request. + * @param srvccCalls The list of call information. + * @throws RemoteException. + */ + public void setSrvccCallInfo(int serial, + android.hardware.radio.ims.SrvccCall[] srvccCalls) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mImsProxy.setSrvccCallInfo(serial, srvccCalls); + } + } + + /** + * Calls IRadioIms#updateImsRegistrationInfo. + * @param serial Serial number of request. + * @param registrationInfo The registration state information. + * @throws RemoteException. + */ + public void updateImsRegistrationInfo(int serial, + android.hardware.radio.ims.ImsRegistration registrationInfo) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mImsProxy.updateImsRegistrationInfo(serial, registrationInfo); + } + } + + /** + * Calls IRadioIms#startImsTraffic. + * @param serial Serial number of request. + * @throws RemoteException. + */ + public void notifyImsTraffic(int serial, int token, int trafficType, boolean isStart) + throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mImsProxy.notifyImsTraffic(serial, token, trafficType, isStart); + } + } + + /** + * Calls IRadioIms#performAcbCheck. + * @param serial Serial number of request. + * @throws RemoteException. + */ + public void performAcbCheck(int serial, int token, int trafficType) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mImsProxy.performAcbCheck(serial, token, trafficType); + } + } +} diff --git a/src/java/com/android/internal/telephony/SrvccConnection.java b/src/java/com/android/internal/telephony/SrvccConnection.java new file mode 100644 index 0000000000..b491b51fc5 --- /dev/null +++ b/src/java/com/android/internal/telephony/SrvccConnection.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2022 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; + +/** + * Connection information for SRVCC + */ +public class SrvccConnection { + private static final String TAG = "SrvccConnection"; + + private static final int CALL_TYPE_NORMAL = 0; + private static final int CALL_TYPE_EMERGENCY = 1; + + public static final int SUBSTATE_NONE = 0; + /** Pre-alerting state. Applicable for MT calls only */ + public static final int SUBSTATE_PREALERTING = 1; + + public static final int TONE_NONE = 0; + public static final int TONE_LOCAL = 1; + public static final int TONE_NETWORK = 2; + + /** Values are CALL_TYPE_ */ + private int mType; + + /** Values are Call.State */ + private Call.State mState; + + /** Values are SUBSTATE_ */ + private int mSubstate; + + /** Values are TONE_ */ + private int mRingbackToneType; + + /** true if it is a multi-party call */ + private boolean mIsMpty; + + /** true if it is a mobile terminated call */ + private boolean mIsMT; + + /** Remote party nummber */ + private String mNumber; + + /** Values are PhoneConstants.PRESENTATION_ */ + private int mNumPresentation; + + /** Remote party name */ + private String mName; + + /** Values are PhoneConstants.PRESENTATION_ */ + private int mNamePresentation; + + public SrvccConnection(Connection c, boolean isEmergency, int ringbackToneType) { + mType = isEmergency ? CALL_TYPE_EMERGENCY : CALL_TYPE_NORMAL; + mState = c.getState(); + mSubstate = SUBSTATE_NONE; + mRingbackToneType = ringbackToneType; + mIsMpty = false; + mIsMT = c.isIncoming(); + mNumber = c.getAddress(); + mNumPresentation = c.getNumberPresentation(); + mName = c.getCnapName(); + mNamePresentation = c.getCnapNamePresentation(); + } + + /** Returns the type of the call */ + public int getType() { + return mType; + } + + /** Returns the state */ + public Call.State getState() { + return mState; + } + + /** Returns the sub state */ + public int getSubState() { + return mSubstate; + } + + /** Returns the ringback tone type */ + public int getRingbackToneType() { + return mRingbackToneType; + } + + /** true if it is a multi-party call */ + public boolean isMultiParty() { + return mIsMpty; + } + + /** true if it is a mobile terminated call */ + public boolean isIncoming() { + return mIsMT; + } + + /** Returns the remote party nummber */ + public String getNumber() { + return mNumber; + } + + /** Returns the number presentation */ + public int getNumberPresentation() { + return mNumPresentation; + } + + /** Returns the remote party name */ + public String getName() { + return mName; + } + + /** Returns the name presentation */ + public int getNamePresentation() { + return mNamePresentation; + } +} -- GitLab From feab74fb2e961aa597f83d438dea50dcbdfdb39f Mon Sep 17 00:00:00 2001 From: Hwayoung Date: Sun, 6 Feb 2022 20:08:16 +0000 Subject: [PATCH 137/656] Add RadioImaProxy, ImsResponse, and ImsIndication for IRadioIms Test: manual Change-Id: Ief602eb3c5abbfbc68394a201f62a9deaa6e20aa Merged-In: Ief602eb3c5abbfbc68394a201f62a9deaa6e20aa --- .../internal/telephony/BaseCommands.java | 13 +++- .../internal/telephony/CommandsInterface.java | 34 +++++++++++ .../internal/telephony/ImsIndication.java | 24 ++++++++ .../internal/telephony/ImsResponse.java | 16 ++++- .../com/android/internal/telephony/RIL.java | 60 +++++++++++++++++++ .../android/internal/telephony/RILUtils.java | 9 +++ .../internal/telephony/RadioImsProxy.java | 29 +++++++++ 7 files changed, 183 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java index 25cd6c70d9..1f1a6c3fe0 100644 --- a/src/java/com/android/internal/telephony/BaseCommands.java +++ b/src/java/com/android/internal/telephony/BaseCommands.java @@ -117,6 +117,7 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mEmergencyNetworkScanRegistrants = new RegistrantList(); protected RegistrantList mConnectionSetupFailureRegistrants = new RegistrantList(); protected RegistrantList mAccessAllowedRegistrants = new RegistrantList(); + protected RegistrantList mNotifyAnbrRegistrants = new RegistrantList(); @UnsupportedAppUsage protected Registrant mGsmSmsRegistrant; @@ -1177,4 +1178,14 @@ public abstract class BaseCommands implements CommandsInterface { public void unregisterForAccessAllowed(Handler h) { mAccessAllowedRegistrants.remove(h); } -} + + @Override + public void registerForNotifyAnbr(Handler h, int what, Object obj) { + mNotifyAnbrRegistrants.addUnique(h, what, obj); + } + + @Override + public void unregisterForNotifyAnbr(Handler h) { + mNotifyAnbrRegistrants.remove(h); + } +} \ No newline at end of file diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 329abee2be..ff46427fa6 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2778,6 +2778,22 @@ public interface CommandsInterface { */ default void unregisterForAccessAllowed(Handler h) {} + /** + * Registers for notifications when ANBR is received form the network. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForNotifyAnbr(Handler h, int what, Object obj) {} + + /** + * Unregisters for notifications when ANBR is received form the network. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForNotifyAnbr(Handler h) {} + /** * Set the UE's usage setting. * @@ -2844,4 +2860,22 @@ public interface CommandsInterface { * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. */ default void performAcbCheck(int token, int trafficType, Message result) {} + + /** + * Enable or disable the ANBR feature + * + * @param qosSessionId QoS session ID is used to identify media stream such as audio or video + * @param isEnabled True if Anbr feature is enabled, false otherwise + */ + default void setAnbrEnabled(int qosSessionId, boolean isEnabled, Message result) {} + + /** + * Triggers radio to send ANBRQ message to the network. + * + * @param qosSessionId QoS session ID is used to identify media stream such as audio or video. + * @param imsdirection Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond The bit rate requested by the opponent UE. + */ + default void sendAnbrQuery(int qosSessionId, int imsdirection, int bitsPerSecond, + Message result) {} } diff --git a/src/java/com/android/internal/telephony/ImsIndication.java b/src/java/com/android/internal/telephony/ImsIndication.java index 5436607808..d403961bb8 100644 --- a/src/java/com/android/internal/telephony/ImsIndication.java +++ b/src/java/com/android/internal/telephony/ImsIndication.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ACCESS_ALLOWED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CONNECTION_SETUP_FAILURE; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NOTIFY_ANBR; import android.hardware.radio.ims.IRadioImsIndication; import android.os.AsyncResult; @@ -73,4 +74,27 @@ public class ImsIndication extends IRadioImsIndication.Stub { mRil.mAccessAllowedRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } + + /** + * Fired by radio when ANBR is received form the network. + * + * @param indicationType Type of radio indication. + * @param qosSessionId QoS session ID is used to identify media stream such as audio or video. + * @param imsdirection Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond The recommended bit rate for the UE + * for a specific logical channel and a specific direction by the network. + */ + public void notifyAnbr(int indicationType, int qosSessionId, int imsdirection, + int bitsPerSecond) { + mRil.processIndication(RIL.IMS_SERVICE, indicationType); + + int[] response = new int[3]; + response[0] = qosSessionId; + response[1] = imsdirection; + response[2] = bitsPerSecond; + + if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NOTIFY_ANBR, response); + + mRil.mNotifyAnbrRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); + } } diff --git a/src/java/com/android/internal/telephony/ImsResponse.java b/src/java/com/android/internal/telephony/ImsResponse.java index 4664c1efc1..299cf6f56a 100644 --- a/src/java/com/android/internal/telephony/ImsResponse.java +++ b/src/java/com/android/internal/telephony/ImsResponse.java @@ -56,4 +56,18 @@ public class ImsResponse extends IRadioImsResponse.Stub { public void performAcbCheckResponse(RadioResponseInfo info) { RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); } -} + + /** + * @param info Response info struct containing response type, serial no. and error. + */ + public void setAnbrEnabledResponse(RadioResponseInfo info) { + RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + } + + /** + * @param info Response info struct containing response type, serial no. and error. + */ + public void sendAnbrQueryResponse(RadioResponseInfo info) { + RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + } +} \ No newline at end of file diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 11ba4962d6..9cfc865bae 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5246,6 +5246,66 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + @Override + public void setAnbrEnabled(int qosSessionId, boolean isEnabled, Message result) { + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); + if (imsProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_SET_ANBR_ENABLED, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + imsProxy.setAnbrEnabled(rr.mSerial, qosSessionId, isEnabled); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(IMS_SERVICE, "setAnbrEnabled", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "setAnbrEnabled: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + @Override + public void sendAnbrQuery(int qosSessionId, int imsdirection, int bitsPerSecond, + Message result) { + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); + if (imsProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_SEND_ANBR_QUERY, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + imsProxy.sendAnbrQuery(rr.mSerial, qosSessionId, imsdirection, bitsPerSecond); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(IMS_SERVICE, "sendAnbrQuery", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "sendAnbrQuery: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + //***** Private Methods /** * This is a helper function to be called when an indication callback is called for any radio diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index dc13cd47a6..5a647331c1 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -140,6 +140,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REPORT_SMS import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RESET_RADIO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SCREEN_STATE; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_ANBR_QUERY; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_DEVICE_STATE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE; @@ -148,6 +149,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEPARATE_C import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_ALLOWED_CARRIERS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_ANBR_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_BAND_MODE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_CALL_FORWARD; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_CALL_WAITING; @@ -232,6 +234,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NOTIFY_ANBR; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_OEM_HOOK_RAW; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_SS; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD; @@ -5056,6 +5059,10 @@ public class RILUtils { return "NOTIFY_IMS_TRAFFIC"; case RIL_REQUEST_PERFORM_ACB_CHECK: return "PERFORM_ACB_CHECK"; + case RIL_REQUEST_SET_ANBR_ENABLED: + return "SET_ANBR_ENABLED"; + case RIL_REQUEST_SEND_ANBR_QUERY: + return "SEND_ANBR_QUERY"; default: return ""; } @@ -5192,6 +5199,8 @@ public class RILUtils { return "UNSOL_ACCESS_ALLOWED"; case RIL_UNSOL_CONNECTION_SETUP_FAILURE: return "UNSOL_CONNECTION_SETUP_FAILURE"; + case RIL_UNSOL_NOTIFY_ANBR: + return "UNSOL_NOTIFY_ANBR"; default: return ""; } diff --git a/src/java/com/android/internal/telephony/RadioImsProxy.java b/src/java/com/android/internal/telephony/RadioImsProxy.java index e3f3b1635f..136cf5071e 100644 --- a/src/java/com/android/internal/telephony/RadioImsProxy.java +++ b/src/java/com/android/internal/telephony/RadioImsProxy.java @@ -129,4 +129,33 @@ public class RadioImsProxy extends RadioServiceProxy { mImsProxy.performAcbCheck(serial, token, trafficType); } } + + /** + * Call IRadioIms#setAnbrEnabled + * @param serial Serial number of request + * @throws RemoteException + */ + public void setAnbrEnabled(int serial, int qosSessionId, boolean isEnabled) + throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mImsProxy.setAnbrEnabled(serial, qosSessionId, isEnabled); + } + } + + /** + * Calls IRadioIms#sendAnbrQuery. + * @param serial Serial number of request. + * @param qosSessionId QoS session ID is used to identify media stream such as audio or video. + * @param imsdirection Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond The bit rate requested by the opponent UE. + * @throws RemoteException. + */ + public void sendAnbrQuery(int serial, int qosSessionId, int imsdirection, int bitsPerSecond) + throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mImsProxy.sendAnbrQuery(serial, qosSessionId, imsdirection, bitsPerSecond); + } + } } -- GitLab From 21f2acd3b2c4b0088e8529378466ffbd72bf3f3b Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 29 Mar 2022 03:06:13 +0000 Subject: [PATCH 138/656] Update RIL for IRadioIms HAL - Replace notifyImsTraffic with startImsTraffic and stopImsTraffic. - Remove performAcbCheck and onAccessAllowed Bug: 216387835 Test: build & flash Change-Id: I8740c2da61c230d25cc453e46332225534a79652 Merged-In: I8740c2da61c230d25cc453e46332225534a79652 --- .../internal/telephony/BaseCommands.java | 11 -- .../internal/telephony/CommandsInterface.java | 52 ++++----- .../internal/telephony/ImsIndication.java | 38 ++---- .../internal/telephony/ImsResponse.java | 28 ++++- .../com/android/internal/telephony/RIL.java | 29 ++--- .../android/internal/telephony/RILUtils.java | 109 ++++++++++++++++-- .../internal/telephony/RadioImsProxy.java | 15 ++- .../internal/telephony/SrvccConnection.java | 4 +- 8 files changed, 182 insertions(+), 104 deletions(-) diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java index 1f1a6c3fe0..c558fa16e2 100644 --- a/src/java/com/android/internal/telephony/BaseCommands.java +++ b/src/java/com/android/internal/telephony/BaseCommands.java @@ -116,7 +116,6 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mSimPhonebookRecordsReceivedRegistrants = new RegistrantList(); protected RegistrantList mEmergencyNetworkScanRegistrants = new RegistrantList(); protected RegistrantList mConnectionSetupFailureRegistrants = new RegistrantList(); - protected RegistrantList mAccessAllowedRegistrants = new RegistrantList(); protected RegistrantList mNotifyAnbrRegistrants = new RegistrantList(); @UnsupportedAppUsage @@ -1169,16 +1168,6 @@ public abstract class BaseCommands implements CommandsInterface { mConnectionSetupFailureRegistrants.remove(h); } - @Override - public void registerForAccessAllowed(Handler h, int what, Object obj) { - mAccessAllowedRegistrants.addUnique(h, what, obj); - } - - @Override - public void unregisterForAccessAllowed(Handler h) { - mAccessAllowedRegistrants.remove(h); - } - @Override public void registerForNotifyAnbr(Handler h, int what, Object obj) { mNotifyAnbrRegistrants.addUnique(h, what, obj); diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index ff46427fa6..12320772b5 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -25,6 +25,7 @@ import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.WorkSource; +import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CarrierRestrictionRules; import android.telephony.ClientRequestStats; @@ -124,6 +125,15 @@ public interface CommandsInterface { static final int CDMA_SMS_FAIL_CAUSE_OTHER_TERMINAL_PROBLEM = 39; static final int CDMA_SMS_FAIL_CAUSE_ENCODING_PROBLEM = 96; + /** IMS voice capability */ + int IMS_MMTEL_CAPABILITY_VOICE = 1 << 0; + /** IMS video capability */ + int IMS_MMTEL_CAPABILITY_VIDEO = 1 << 1; + /** IMS SMS capability */ + int IMS_MMTEL_CAPABILITY_SMS = 1 << 2; + /** IMS RCS capabilities */ + int IMS_RCS_CAPABILITIES = 1 << 3; + //***** Methods /** @@ -2762,22 +2772,6 @@ public interface CommandsInterface { */ default void unregisterForConnectionSetupFailure(Handler h) {} - /** - * Register for notifications when IMS traffic access is allowed - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - default void registerForAccessAllowed(Handler h, int what, Object obj) {} - - /** - * Unregister for notifications when IMS traffic access is allowed - * - * @param h Handler to be removed from the registrant list. - */ - default void unregisterForAccessAllowed(Handler h) {} - /** * Registers for notifications when ANBR is received form the network. * @@ -2836,30 +2830,32 @@ public interface CommandsInterface { /** * Updates the IMS registration information to the radio. * - * @param state the current IMS registration state. - * @param ipcan the type of IP connectivity access network where IMS features are registered. - * @param reason a failure reason for IMS registration. - * @param features IMS features such as VOICE, VIDEO and SMS. + * @param state The current IMS registration state. + * @param accessNetworkType The type of underlying radio access network used. + * @param reason A failure reason for IMS registration. + * @param capabilities IMS capabilities such as VOICE, VIDEO and SMS. */ default void updateImsRegistrationInfo(int state, - int ipcan, int reason, int features, Message result) {} + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, + int reason, int capabilities, Message result) {} /** * Notifies the NAS and RRC layers of the radio the type of upcoming IMS traffic. * - * @param token The token of the request. + * @param token A nonce to identify the request. * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. - * @param isStart true when the traffic flow starts, false when traffic flow stops. + * @param accessNetworkType The type of underlying radio access network used. */ - default void notifyImsTraffic(int token, int trafficType, boolean isStart, Message result) {} + default void startImsTraffic(String token, int trafficType, + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, + Message result) {} /** - * Checks access class barring checks based on ImsTrafficType. + * Notifies IMS traffic has been stopped. * - * @param token The token of the request. - * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. + * @param token The token assigned by startImsTraffic. */ - default void performAcbCheck(int token, int trafficType, Message result) {} + default void stopImsTraffic(String token, Message result) {} /** * Enable or disable the ANBR feature diff --git a/src/java/com/android/internal/telephony/ImsIndication.java b/src/java/com/android/internal/telephony/ImsIndication.java index d403961bb8..19db5b127f 100644 --- a/src/java/com/android/internal/telephony/ImsIndication.java +++ b/src/java/com/android/internal/telephony/ImsIndication.java @@ -16,7 +16,6 @@ package com.android.internal.telephony; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ACCESS_ALLOWED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CONNECTION_SETUP_FAILURE; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NOTIFY_ANBR; @@ -38,18 +37,21 @@ public class ImsIndication extends IRadioImsIndication.Stub { * on cellular networks. * * @param indicationType Type of radio indication. - * @param token The token provided by {@link #notifyImsTraffic} or {@link #performACBcheck}. - * @param info Connection failure information. + * @param token The token provided by {@link #startImsTraffic}. + * @param failureInfo Connection failure information. */ - public void onConnectionSetupFailure(int indicationType, int token, - android.hardware.radio.ims.ConnectionFailureInfo info) { + public void onConnectionSetupFailure(int indicationType, String token, + android.hardware.radio.ims.ConnectionFailureInfo failureInfo) { mRil.processIndication(RIL.IMS_SERVICE, indicationType); - int[] response = new int[4]; + int[] info = new int[3]; + info[0] = failureInfo.failureReason; + info[1] = failureInfo.causeCode; + info[2] = failureInfo.waitTimeMillis; + + Object[] response = new Object[2]; response[0] = token; - response[1] = info.failureReason; - response[2] = info.causeCode; - response[3] = info.waitTimeMillis; + response[1] = info; if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CONNECTION_SETUP_FAILURE, response); @@ -57,24 +59,6 @@ public class ImsIndication extends IRadioImsIndication.Stub { new AsyncResult(null, response, null)); } - /** - * Fired by radio in response to {@link #performAcbCheck} - * if the access class check is allowed for the requested traffic type. - * - * @param indicationType Type of radio indication - * @param token The token provided by {@link #performAcbCheck} - */ - public void onAccessAllowed(int indicationType, int token) { - mRil.processIndication(RIL.IMS_SERVICE, indicationType); - - int[] response = new int[1]; - response[0] = token; - - if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_ACCESS_ALLOWED, response); - - mRil.mAccessAllowedRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); - } - /** * Fired by radio when ANBR is received form the network. * diff --git a/src/java/com/android/internal/telephony/ImsResponse.java b/src/java/com/android/internal/telephony/ImsResponse.java index 299cf6f56a..43a2192a11 100644 --- a/src/java/com/android/internal/telephony/ImsResponse.java +++ b/src/java/com/android/internal/telephony/ImsResponse.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.ims.IRadioImsResponse; @@ -44,16 +45,33 @@ public class ImsResponse extends IRadioImsResponse.Stub { } /** - * @param info Response info struct containing response type, serial no. and error. + * @param responseInfo Response info struct containing response type, serial no. and error. + * @param failureInfo Failure information. */ - public void notifyImsTrafficResponse(RadioResponseInfo info) { - RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + public void startImsTrafficResponse(RadioResponseInfo responseInfo, + android.hardware.radio.ims.ConnectionFailureInfo failureInfo) { + RILRequest rr = mRil.processResponse(RIL.IMS_SERVICE, responseInfo); + + if (rr != null) { + Object[] response = { "", null }; + + if (responseInfo.error == RadioError.NONE) { + int[] info = new int[3]; + info[0] = failureInfo.failureReason; + info[1] = failureInfo.causeCode; + info[2] = failureInfo.waitTimeMillis; + response[1] = info; + + RadioResponse.sendMessageResponse(rr.mResult, response); + } + mRil.processResponseDone(rr, responseInfo, response); + } } /** * @param info Response info struct containing response type, serial no. and error. */ - public void performAcbCheckResponse(RadioResponseInfo info) { + public void stopImsTrafficResponse(RadioResponseInfo info) { RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); } @@ -70,4 +88,4 @@ public class ImsResponse extends IRadioImsResponse.Stub { public void sendAnbrQueryResponse(RadioResponseInfo info) { RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); } -} \ No newline at end of file +} diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 9cfc865bae..0b39eac014 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5152,7 +5152,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void updateImsRegistrationInfo(int state, - int ipcan, int reason, int features, Message result) { + int accessNetworkType, int reason, int capabilities, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { @@ -5166,10 +5166,10 @@ public class RIL extends BaseCommands implements CommandsInterface { android.hardware.radio.ims.ImsRegistration registrationInfo = new android.hardware.radio.ims.ImsRegistration(); - registrationInfo.state = state; - registrationInfo.ipcan = ipcan; + registrationInfo.regState = RILUtils.convertImsRegistrationState(state); + registrationInfo.accessNetworkType = accessNetworkType; registrationInfo.reason = reason; - registrationInfo.features = features; + registrationInfo.capabilities = RILUtils.convertImsCapability(capabilities); try { imsProxy.updateImsRegistrationInfo(rr.mSerial, registrationInfo); @@ -5189,11 +5189,12 @@ public class RIL extends BaseCommands implements CommandsInterface { } @Override - public void notifyImsTraffic(int token, int trafficType, boolean isStart, Message result) { + public void startImsTraffic(String token, + int trafficType, int accessNetworkType, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_NOTIFY_IMS_TRAFFIC, result, + RILRequest rr = obtainRequest(RIL_REQUEST_START_IMS_TRAFFIC, result, mRILDefaultWorkSource); if (RILJ_LOGD) { @@ -5201,13 +5202,13 @@ public class RIL extends BaseCommands implements CommandsInterface { } try { - imsProxy.notifyImsTraffic(rr.mSerial, token, trafficType, isStart); + imsProxy.startImsTraffic(rr.mSerial, token, trafficType, accessNetworkType); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(IMS_SERVICE, "notifyImsTraffic", e); + handleRadioProxyExceptionForRR(IMS_SERVICE, "startImsTraffic", e); } } else { if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "notifyImsTraffic: REQUEST_NOT_SUPPORTED"); + Rlog.d(RILJ_LOG_TAG, "startImsTraffic: REQUEST_NOT_SUPPORTED"); } if (result != null) { AsyncResult.forMessage(result, null, @@ -5218,11 +5219,11 @@ public class RIL extends BaseCommands implements CommandsInterface { } @Override - public void performAcbCheck(int token, int trafficType, Message result) { + public void stopImsTraffic(String token, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_PERFORM_ACB_CHECK, result, + RILRequest rr = obtainRequest(RIL_REQUEST_STOP_IMS_TRAFFIC, result, mRILDefaultWorkSource); if (RILJ_LOGD) { @@ -5230,13 +5231,13 @@ public class RIL extends BaseCommands implements CommandsInterface { } try { - imsProxy.performAcbCheck(rr.mSerial, token, trafficType); + imsProxy.stopImsTraffic(rr.mSerial, token); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(IMS_SERVICE, "performAcbCheck", e); + handleRadioProxyExceptionForRR(IMS_SERVICE, "stopImsTraffic", e); } } else { if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "performAcbCheck: REQUEST_NOT_SUPPORTED"); + Rlog.d(RILJ_LOG_TAG, "stopImsTraffic: REQUEST_NOT_SUPPORTED"); } if (result != null) { AsyncResult.forMessage(result, null, diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 5a647331c1..7dde9c5d0d 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -116,7 +116,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_NR_DUAL import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_VONR_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_LAST_CALL_FAIL_CAUSE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NOTIFY_IMS_TRAFFIC; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_READ_ITEM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_RESET_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_WRITE_CDMA_PRL; @@ -124,7 +123,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_WRITE_I import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OEM_HOOK_RAW; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OEM_HOOK_STRINGS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OPERATOR; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PERFORM_ACB_CHECK; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PULL_LCEDATA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_AVAILABLE_NETWORKS; @@ -190,6 +188,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SIM_TRANSM import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SMS_ACKNOWLEDGE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_HANDOVER; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_IMS_TRAFFIC; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_KEEPALIVE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_LCE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_NETWORK_SCAN; @@ -199,6 +198,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_SEND_E import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_SEND_ENVELOPE_WITH_STATUS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_SET_PROFILE; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_IMS_TRAFFIC; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_KEEPALIVE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_LCE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_NETWORK_SCAN; @@ -210,7 +210,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UPDATE_SIM import static com.android.internal.telephony.RILConstants.RIL_REQUEST_VOICE_RADIO_TECH; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_VOICE_REGISTRATION_STATE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_WRITE_SMS_TO_SIM; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ACCESS_ALLOWED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_BARRING_INFO_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CALL_RING; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION; @@ -335,6 +334,7 @@ import android.telephony.data.QosBearerSession; import android.telephony.data.RouteSelectionDescriptor; import android.telephony.data.TrafficDescriptor; import android.telephony.data.UrspRule; +import android.telephony.ims.RegistrationManager; import android.text.TextUtils; import android.util.ArraySet; import android.util.SparseArray; @@ -5055,10 +5055,10 @@ public class RILUtils { return "SET_SRVCC_CALL_INFO"; case RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO: return "UPDATE_IMS_REGISTRATION_INFO"; - case RIL_REQUEST_NOTIFY_IMS_TRAFFIC: - return "NOTIFY_IMS_TRAFFIC"; - case RIL_REQUEST_PERFORM_ACB_CHECK: - return "PERFORM_ACB_CHECK"; + case RIL_REQUEST_START_IMS_TRAFFIC: + return "START_IMS_TRAFFIC"; + case RIL_REQUEST_STOP_IMS_TRAFFIC: + return "STOP_IMS_TRAFFIC"; case RIL_REQUEST_SET_ANBR_ENABLED: return "SET_ANBR_ENABLED"; case RIL_REQUEST_SEND_ANBR_QUERY: @@ -5195,8 +5195,6 @@ public class RILUtils { return "UNSOL_REGISTRATION_FAILED"; case RIL_UNSOL_BARRING_INFO_CHANGED: return "UNSOL_BARRING_INFO_CHANGED"; - case RIL_UNSOL_ACCESS_ALLOWED: - return "UNSOL_ACCESS_ALLOWED"; case RIL_UNSOL_CONNECTION_SETUP_FAILURE: return "UNSOL_CONNECTION_SETUP_FAILURE"; case RIL_UNSOL_NOTIFY_ANBR: @@ -5368,10 +5366,12 @@ public class RILUtils { for (int i = 0; i < length; i++) { srvccCalls[i] = new android.hardware.radio.ims.SrvccCall(); srvccCalls[i].index = i + 1; - srvccCalls[i].callType = srvccConnections[i].getType(); + srvccCalls[i].callType = convertSrvccCallType(srvccConnections[i].getType()); srvccCalls[i].callState = convertCallState(srvccConnections[i].getState()); - srvccCalls[i].callSubstate = srvccConnections[i].getSubState(); - srvccCalls[i].ringbackToneType = srvccConnections[i].getRingbackToneType(); + srvccCalls[i].callSubstate = + convertSrvccCallSubState(srvccConnections[i].getSubState()); + srvccCalls[i].ringbackToneType = + convertSrvccCallRingbackToneType(srvccConnections[i].getRingbackToneType()); srvccCalls[i].isMpty = srvccConnections[i].isMultiParty(); srvccCalls[i].isMT = srvccConnections[i].isIncoming(); srvccCalls[i].number = TextUtils.emptyIfNull(srvccConnections[i].getNumber()); @@ -5385,6 +5385,23 @@ public class RILUtils { return srvccCalls; } + /** + * Converts the call type. + * + * @param type The call type. + * @return The converted call type. + */ + public static int convertSrvccCallType(int type) { + switch (type) { + case SrvccConnection.CALL_TYPE_NORMAL: + return android.hardware.radio.ims.SrvccCall.CallType.NORMAL; + case SrvccConnection.CALL_TYPE_EMERGENCY: + return android.hardware.radio.ims.SrvccCall.CallType.EMERGENCY; + default: + throw new RuntimeException("illegal call type " + type); + } + } + /** * Converts the call state. * @@ -5404,6 +5421,42 @@ public class RILUtils { } } + /** + * Converts the substate of a call. + * + * @param state The substate of a call. + * @return The converted substate. + */ + public static int convertSrvccCallSubState(int state) { + switch (state) { + case SrvccConnection.SUBSTATE_NONE: + return android.hardware.radio.ims.SrvccCall.CallSubState.NONE; + case SrvccConnection.SUBSTATE_PREALERTING: + return android.hardware.radio.ims.SrvccCall.CallSubState.PREALERTING; + default: + throw new RuntimeException("illegal substate " + state); + } + } + + /** + * Converts the ringback tone type. + * + * @param type The ringback tone type. + * @return The converted ringback tone type. + */ + public static int convertSrvccCallRingbackToneType(int type) { + switch (type) { + case SrvccConnection.TONE_NONE: + return android.hardware.radio.ims.SrvccCall.ToneType.NONE; + case SrvccConnection.TONE_LOCAL: + return android.hardware.radio.ims.SrvccCall.ToneType.LOCAL; + case SrvccConnection.TONE_NETWORK: + return android.hardware.radio.ims.SrvccCall.ToneType.NETWORK; + default: + throw new RuntimeException("illegal ringback tone type " + type); + } + } + /** * Converts the number presentation type for caller id display. * @@ -5425,6 +5478,38 @@ public class RILUtils { } } + /** Convert IMS registration state */ + public static int convertImsRegistrationState(int state) { + switch (state) { + case RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED: + return android.hardware.radio.ims.ImsRegistrationState.NOT_REGISTERED; + case RegistrationManager.REGISTRATION_STATE_REGISTERED: + return android.hardware.radio.ims.ImsRegistrationState.REGISTERED; + default: + throw new RuntimeException("illegal state " + state); + } + } + + /** Convert IMS capability */ + public static int convertImsCapability(int capabilities) { + int halCapabilities = android.hardware.radio.ims.ImsRegistration.IMS_MMTEL_CAPABILITY_NONE; + if ((capabilities & CommandsInterface.IMS_MMTEL_CAPABILITY_VOICE) > 0) { + halCapabilities |= + android.hardware.radio.ims.ImsRegistration.IMS_MMTEL_CAPABILITY_VOICE; + } + if ((capabilities & CommandsInterface.IMS_MMTEL_CAPABILITY_VIDEO) > 0) { + halCapabilities |= + android.hardware.radio.ims.ImsRegistration.IMS_MMTEL_CAPABILITY_VIDEO; + } + if ((capabilities & CommandsInterface.IMS_MMTEL_CAPABILITY_SMS) > 0) { + halCapabilities |= android.hardware.radio.ims.ImsRegistration.IMS_MMTEL_CAPABILITY_SMS; + } + if ((capabilities & CommandsInterface.IMS_RCS_CAPABILITIES) > 0) { + halCapabilities |= android.hardware.radio.ims.ImsRegistration.IMS_RCS_CAPABILITIES; + } + return halCapabilities; + } + private static void logd(String log) { Rlog.d("RILUtils", log); } diff --git a/src/java/com/android/internal/telephony/RadioImsProxy.java b/src/java/com/android/internal/telephony/RadioImsProxy.java index 136cf5071e..aae6684e69 100644 --- a/src/java/com/android/internal/telephony/RadioImsProxy.java +++ b/src/java/com/android/internal/telephony/RadioImsProxy.java @@ -108,25 +108,30 @@ public class RadioImsProxy extends RadioServiceProxy { /** * Calls IRadioIms#startImsTraffic. * @param serial Serial number of request. + * @param token A nonce to identify the request. + * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. + * @param accessNetworkType The type of underlying radio access network used. * @throws RemoteException. */ - public void notifyImsTraffic(int serial, int token, int trafficType, boolean isStart) + public void startImsTraffic(int serial, String token, int trafficType, int accessNetworkType) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mImsProxy.notifyImsTraffic(serial, token, trafficType, isStart); + mImsProxy.startImsTraffic(serial, token, trafficType, accessNetworkType); } } /** - * Calls IRadioIms#performAcbCheck. + * Calls IRadioIms#stopImsTraffic. * @param serial Serial number of request. + * @param token The token assigned by startImsTraffic. * @throws RemoteException. */ - public void performAcbCheck(int serial, int token, int trafficType) throws RemoteException { + public void stopImsTraffic(int serial, String token) + throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mImsProxy.performAcbCheck(serial, token, trafficType); + mImsProxy.stopImsTraffic(serial, token); } } diff --git a/src/java/com/android/internal/telephony/SrvccConnection.java b/src/java/com/android/internal/telephony/SrvccConnection.java index b491b51fc5..57b827002b 100644 --- a/src/java/com/android/internal/telephony/SrvccConnection.java +++ b/src/java/com/android/internal/telephony/SrvccConnection.java @@ -22,8 +22,8 @@ package com.android.internal.telephony; public class SrvccConnection { private static final String TAG = "SrvccConnection"; - private static final int CALL_TYPE_NORMAL = 0; - private static final int CALL_TYPE_EMERGENCY = 1; + public static final int CALL_TYPE_NORMAL = 0; + public static final int CALL_TYPE_EMERGENCY = 1; public static final int SUBSTATE_NONE = 0; /** Pre-alerting state. Applicable for MT calls only */ -- GitLab From 98231dd4abe9b7f3328eb16505b3d9a1ae9c6eab Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 27 May 2022 08:39:45 +0000 Subject: [PATCH 139/656] Fix NPE with startImsTrafficResponse ConnectionFailureInfo is defined as @nullable. Bug: 234095136 Test: manual Change-Id: I739f54c4f4dd1bc7389a53c35986eac2a8810692 Merged-In: I739f54c4f4dd1bc7389a53c35986eac2a8810692 --- .../com/android/internal/telephony/ImsResponse.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/ImsResponse.java b/src/java/com/android/internal/telephony/ImsResponse.java index 43a2192a11..e8a6ad24ed 100644 --- a/src/java/com/android/internal/telephony/ImsResponse.java +++ b/src/java/com/android/internal/telephony/ImsResponse.java @@ -56,11 +56,13 @@ public class ImsResponse extends IRadioImsResponse.Stub { Object[] response = { "", null }; if (responseInfo.error == RadioError.NONE) { - int[] info = new int[3]; - info[0] = failureInfo.failureReason; - info[1] = failureInfo.causeCode; - info[2] = failureInfo.waitTimeMillis; - response[1] = info; + if (failureInfo != null) { + int[] info = new int[3]; + info[0] = failureInfo.failureReason; + info[1] = failureInfo.causeCode; + info[2] = failureInfo.waitTimeMillis; + response[1] = info; + } RadioResponse.sendMessageResponse(rr.mResult, response); } -- GitLab From ac3c58e492ac717bbad5958cd7f6206f2217219b Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 12 Apr 2022 06:29:03 +0000 Subject: [PATCH 140/656] Add triggerImsDeregistration to ImsIndication Bug: 216387835 Test: build & flash Change-Id: I8a770cf81c35e1a5004c2dc2c603d0f7f69c2a6e Merged-In: I8a770cf81c35e1a5004c2dc2c603d0f7f69c2a6e --- .../internal/telephony/BaseCommands.java | 13 ++++++++++++- .../internal/telephony/CommandsInterface.java | 16 ++++++++++++++++ .../internal/telephony/ImsIndication.java | 19 +++++++++++++++++++ .../android/internal/telephony/RILUtils.java | 3 +++ 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java index c558fa16e2..f36161a7d3 100644 --- a/src/java/com/android/internal/telephony/BaseCommands.java +++ b/src/java/com/android/internal/telephony/BaseCommands.java @@ -117,6 +117,7 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mEmergencyNetworkScanRegistrants = new RegistrantList(); protected RegistrantList mConnectionSetupFailureRegistrants = new RegistrantList(); protected RegistrantList mNotifyAnbrRegistrants = new RegistrantList(); + protected RegistrantList mTriggerImsDeregistrationRegistrants = new RegistrantList(); @UnsupportedAppUsage protected Registrant mGsmSmsRegistrant; @@ -1177,4 +1178,14 @@ public abstract class BaseCommands implements CommandsInterface { public void unregisterForNotifyAnbr(Handler h) { mNotifyAnbrRegistrants.remove(h); } -} \ No newline at end of file + + @Override + public void registerForTriggerImsDeregistration(Handler h, int what, Object obj) { + mTriggerImsDeregistrationRegistrants.add(h, what, obj); + } + + @Override + public void unregisterForTriggerImsDeregistration(Handler h) { + mTriggerImsDeregistrationRegistrants.remove(h); + } +} diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 12320772b5..222f152ceb 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2788,6 +2788,22 @@ public interface CommandsInterface { */ default void unregisterForNotifyAnbr(Handler h) {} + /** + * Registers for IMS deregistration trigger from modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForTriggerImsDeregistration(Handler h, int what, Object obj) {} + + /** + * Unregisters for IMS deregistration trigger from modem. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForTriggerImsDeregistration(Handler h) {} + /** * Set the UE's usage setting. * diff --git a/src/java/com/android/internal/telephony/ImsIndication.java b/src/java/com/android/internal/telephony/ImsIndication.java index 19db5b127f..4e5dd8c51b 100644 --- a/src/java/com/android/internal/telephony/ImsIndication.java +++ b/src/java/com/android/internal/telephony/ImsIndication.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CONNECTION_SETUP_FAILURE; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NOTIFY_ANBR; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION; import android.hardware.radio.ims.IRadioImsIndication; import android.os.AsyncResult; @@ -81,4 +82,22 @@ public class ImsIndication extends IRadioImsIndication.Stub { mRil.mNotifyAnbrRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } + + /** + * Fired by radio when a graceful IMS deregistration needs to be performed by telephony + * prior to radio performing network detach. Example scenarios are SIM refresh or user + * mode preference change which would cause network detach. The radio waits for the + * IMS deregistration, which will be notified by telephony via + * {@link IRadioIms#updateImsRegistrationInfo()}, or a certain timeout interval to start + * the network detach procedure. + * + * @param indicationType Type of radio indication + */ + public void triggerImsDeregistration(int indicationType) { + mRil.processIndication(RIL.IMS_SERVICE, indicationType); + + if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION); + + mRil.mTriggerImsDeregistrationRegistrants.notifyRegistrants(); + } } diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 7dde9c5d0d..df00adc2ef 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -268,6 +268,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_EVENT_NO import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_PROACTIVE_COMMAND; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_SESSION_END; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SUPP_SVC_NOTIFICATION; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_UNTHROTTLE_APN; @@ -5199,6 +5200,8 @@ public class RILUtils { return "UNSOL_CONNECTION_SETUP_FAILURE"; case RIL_UNSOL_NOTIFY_ANBR: return "UNSOL_NOTIFY_ANBR"; + case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION: + return "UNSOL_TRIGGER_IMS_DEREGISTRATION"; default: return ""; } -- GitLab From 5fda154e09cd1fce559837757795ea7acbbc7580 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 13 Apr 2022 04:49:59 +0000 Subject: [PATCH 141/656] Add getInterfaceHash and getInterfaceVersion for IRadioIms Bug: 216387835 Test: build & flash Change-Id: I2eb218bdc0aab772a6e175b83e6c7502967dde82 Merged-In: I2eb218bdc0aab772a6e175b83e6c7502967dde82 --- .../com/android/internal/telephony/ImsIndication.java | 10 ++++++++++ .../com/android/internal/telephony/ImsResponse.java | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/java/com/android/internal/telephony/ImsIndication.java b/src/java/com/android/internal/telephony/ImsIndication.java index 4e5dd8c51b..a4be0fcdd9 100644 --- a/src/java/com/android/internal/telephony/ImsIndication.java +++ b/src/java/com/android/internal/telephony/ImsIndication.java @@ -33,6 +33,16 @@ public class ImsIndication extends IRadioImsIndication.Stub { mRil = ril; } + @Override + public String getInterfaceHash() { + return IRadioImsIndication.HASH; + } + + @Override + public int getInterfaceVersion() { + return IRadioImsIndication.VERSION; + } + /** * Fired by radio when any IMS traffic is not sent to network due to any failure * on cellular networks. diff --git a/src/java/com/android/internal/telephony/ImsResponse.java b/src/java/com/android/internal/telephony/ImsResponse.java index e8a6ad24ed..890ade5fdf 100644 --- a/src/java/com/android/internal/telephony/ImsResponse.java +++ b/src/java/com/android/internal/telephony/ImsResponse.java @@ -30,6 +30,16 @@ public class ImsResponse extends IRadioImsResponse.Stub { mRil = ril; } + @Override + public String getInterfaceHash() { + return IRadioImsResponse.HASH; + } + + @Override + public int getInterfaceVersion() { + return IRadioImsResponse.VERSION; + } + /** * @param info Response info struct containing response type, serial no. and error. */ -- GitLab From 79b8fcd1071d75a87a4f0c6649ae20e577bf7600 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 14 Apr 2022 06:36:59 +0000 Subject: [PATCH 142/656] Support IRadio Ims module interface in the mock modem Bug: 229154572 Test: IRadio Ims could be bined in the mock modem Change-Id: Ia564a40d88cf9a066b98f0e94b90f09e07b23a42 Merged-In: Ia564a40d88cf9a066b98f0e94b90f09e07b23a42 --- .../android/internal/telephony/MockModem.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/java/com/android/internal/telephony/MockModem.java b/src/java/com/android/internal/telephony/MockModem.java index f6afe9e3f3..7e638ef27c 100644 --- a/src/java/com/android/internal/telephony/MockModem.java +++ b/src/java/com/android/internal/telephony/MockModem.java @@ -34,6 +34,7 @@ public class MockModem { private static final String BIND_IRADIODATA = "android.telephony.mockmodem.iradiodata"; private static final String BIND_IRADIONETWORK = "android.telephony.mockmodem.iradionetwork"; private static final String BIND_IRADIOVOICE = "android.telephony.mockmodem.iradiovoice"; + private static final String BIND_IRADIOIMS = "android.telephony.mockmodem.iradioims"; private static final String BIND_IRADIOCONFIG = "android.telephony.mockmodem.iradioconfig"; private static final String PHONE_ID = "phone_id"; @@ -54,6 +55,7 @@ public class MockModem { private IBinder mDataBinder; private IBinder mNetworkBinder; private IBinder mVoiceBinder; + private IBinder mImsBinder; private IBinder mConfigBinder; private ServiceConnection mModemServiceConnection; private ServiceConnection mSimServiceConnection; @@ -61,6 +63,7 @@ public class MockModem { private ServiceConnection mDataServiceConnection; private ServiceConnection mNetworkServiceConnection; private ServiceConnection mVoiceServiceConnection; + private ServiceConnection mImsServiceConnection; private ServiceConnection mConfigServiceConnection; private byte mPhoneId; @@ -102,6 +105,8 @@ public class MockModem { mNetworkBinder = binder; } else if (mService == RIL.VOICE_SERVICE) { mVoiceBinder = binder; + } else if (mService == RIL.IMS_SERVICE) { + mImsBinder = binder; } else if (mService == RADIOCONFIG_SERVICE) { mConfigBinder = binder; } @@ -123,6 +128,8 @@ public class MockModem { mNetworkBinder = null; } else if (mService == RIL.VOICE_SERVICE) { mVoiceBinder = null; + } else if (mService == RIL.IMS_SERVICE) { + mImsBinder = null; } else if (mService == RADIOCONFIG_SERVICE) { mConfigBinder = null; } @@ -162,6 +169,8 @@ public class MockModem { return mNetworkBinder; case RIL.VOICE_SERVICE: return mVoiceBinder; + case RIL.IMS_SERVICE: + return mImsBinder; case RADIOCONFIG_SERVICE: return mConfigBinder; default: @@ -275,6 +284,20 @@ public class MockModem { } else { Rlog.d(mTag, "IRadio Voice is bound"); } + } else if (service == RIL.IMS_SERVICE) { + if (mImsBinder == null) { + mImsServiceConnection = new MockModemConnection(RIL.IMS_SERVICE); + + boolean status = + bindModuleToMockModemService( + mPhoneId, BIND_IRADIOIMS, mImsServiceConnection); + if (!status) { + Rlog.d(TAG, "IRadio Ims bind fail"); + mImsServiceConnection = null; + } + } else { + Rlog.d(TAG, "IRadio Ims is bound"); + } } } @@ -330,6 +353,13 @@ public class MockModem { mVoiceBinder = null; Rlog.d(mTag, "unbind IRadio Voice"); } + } else if (service == RIL.IMS_SERVICE) { + if (mImsServiceConnection != null) { + mContext.unbindService(mImsServiceConnection); + mImsServiceConnection = null; + mImsBinder = null; + Rlog.d(TAG, "unbind IRadio Ims"); + } } } @@ -351,6 +381,8 @@ public class MockModem { return "network"; case RIL.VOICE_SERVICE: return "voice"; + case RIL.IMS_SERVICE: + return "ims"; case RADIOCONFIG_SERVICE: return "config"; default: -- GitLab From 00f698bdbafb026a229f76e44a6c5f659cb7dbc4 Mon Sep 17 00:00:00 2001 From: Helen Date: Tue, 26 Apr 2022 05:23:52 +0000 Subject: [PATCH 143/656] Update ANBR apis Bug: 224905346 Test: Build Change-Id: I6db876fa44c72287b6b9a714f11fb0482a30874d Merged-In: I6db876fa44c72287b6b9a714f11fb0482a30874d --- .../internal/telephony/CommandsInterface.java | 15 ++------ .../internal/telephony/ImsResponse.java | 7 ---- .../com/android/internal/telephony/RIL.java | 34 ++----------------- .../android/internal/telephony/RILUtils.java | 3 -- .../internal/telephony/RadioImsProxy.java | 21 +++--------- 5 files changed, 9 insertions(+), 71 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 222f152ceb..e80974f0f1 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2873,21 +2873,12 @@ public interface CommandsInterface { */ default void stopImsTraffic(String token, Message result) {} - /** - * Enable or disable the ANBR feature - * - * @param qosSessionId QoS session ID is used to identify media stream such as audio or video - * @param isEnabled True if Anbr feature is enabled, false otherwise - */ - default void setAnbrEnabled(int qosSessionId, boolean isEnabled, Message result) {} - /** * Triggers radio to send ANBRQ message to the network. * - * @param qosSessionId QoS session ID is used to identify media stream such as audio or video. - * @param imsdirection Direction of this packet stream (e.g. uplink or downlink). + * @param mediaType Media type is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). * @param bitsPerSecond The bit rate requested by the opponent UE. */ - default void sendAnbrQuery(int qosSessionId, int imsdirection, int bitsPerSecond, - Message result) {} + default void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond, Message result) {} } diff --git a/src/java/com/android/internal/telephony/ImsResponse.java b/src/java/com/android/internal/telephony/ImsResponse.java index 890ade5fdf..fa7d38fb8d 100644 --- a/src/java/com/android/internal/telephony/ImsResponse.java +++ b/src/java/com/android/internal/telephony/ImsResponse.java @@ -87,13 +87,6 @@ public class ImsResponse extends IRadioImsResponse.Stub { RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); } - /** - * @param info Response info struct containing response type, serial no. and error. - */ - public void setAnbrEnabledResponse(RadioResponseInfo info) { - RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); - } - /** * @param info Response info struct containing response type, serial no. and error. */ diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 0b39eac014..43f98b5698 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5248,37 +5248,7 @@ public class RIL extends BaseCommands implements CommandsInterface { } @Override - public void setAnbrEnabled(int qosSessionId, boolean isEnabled, Message result) { - RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); - if (imsProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_ANBR_ENABLED, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - imsProxy.setAnbrEnabled(rr.mSerial, qosSessionId, isEnabled); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(IMS_SERVICE, "setAnbrEnabled", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setAnbrEnabled: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } - } - - @Override - public void sendAnbrQuery(int qosSessionId, int imsdirection, int bitsPerSecond, + public void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; @@ -5291,7 +5261,7 @@ public class RIL extends BaseCommands implements CommandsInterface { } try { - imsProxy.sendAnbrQuery(rr.mSerial, qosSessionId, imsdirection, bitsPerSecond); + imsProxy.sendAnbrQuery(rr.mSerial, mediaType, direction, bitsPerSecond); } catch (RemoteException | RuntimeException e) { handleRadioProxyExceptionForRR(IMS_SERVICE, "sendAnbrQuery", e); } diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index df00adc2ef..3f17d6d3d0 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -147,7 +147,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEPARATE_C import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_ALLOWED_CARRIERS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_ANBR_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_BAND_MODE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_CALL_FORWARD; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_CALL_WAITING; @@ -5060,8 +5059,6 @@ public class RILUtils { return "START_IMS_TRAFFIC"; case RIL_REQUEST_STOP_IMS_TRAFFIC: return "STOP_IMS_TRAFFIC"; - case RIL_REQUEST_SET_ANBR_ENABLED: - return "SET_ANBR_ENABLED"; case RIL_REQUEST_SEND_ANBR_QUERY: return "SEND_ANBR_QUERY"; default: diff --git a/src/java/com/android/internal/telephony/RadioImsProxy.java b/src/java/com/android/internal/telephony/RadioImsProxy.java index aae6684e69..5e5492ae03 100644 --- a/src/java/com/android/internal/telephony/RadioImsProxy.java +++ b/src/java/com/android/internal/telephony/RadioImsProxy.java @@ -135,32 +135,19 @@ public class RadioImsProxy extends RadioServiceProxy { } } - /** - * Call IRadioIms#setAnbrEnabled - * @param serial Serial number of request - * @throws RemoteException - */ - public void setAnbrEnabled(int serial, int qosSessionId, boolean isEnabled) - throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mImsProxy.setAnbrEnabled(serial, qosSessionId, isEnabled); - } - } - /** * Calls IRadioIms#sendAnbrQuery. * @param serial Serial number of request. - * @param qosSessionId QoS session ID is used to identify media stream such as audio or video. - * @param imsdirection Direction of this packet stream (e.g. uplink or downlink). + * @param mediaType Media type is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). * @param bitsPerSecond The bit rate requested by the opponent UE. * @throws RemoteException. */ - public void sendAnbrQuery(int serial, int qosSessionId, int imsdirection, int bitsPerSecond) + public void sendAnbrQuery(int serial, int mediaType, int direction, int bitsPerSecond) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mImsProxy.sendAnbrQuery(serial, qosSessionId, imsdirection, bitsPerSecond); + mImsProxy.sendAnbrQuery(serial, mediaType, direction, bitsPerSecond); } } } -- GitLab From 811fa9de530c9efd2ac75a832709d5c2de94a78d Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Mon, 1 Aug 2022 05:44:41 +0000 Subject: [PATCH 144/656] Add triggerEpsFallback to RadioImsProxy Bug: 234803835 Test: build & flash Change-Id: I96cc54dd6633462f412548ad495195fbf2395dff Merged-In: I96cc54dd6633462f412548ad495195fbf2395dff --- .../internal/telephony/CommandsInterface.java | 7 +++++ .../internal/telephony/ImsResponse.java | 7 +++++ .../com/android/internal/telephony/Phone.java | 10 +++++++ .../com/android/internal/telephony/RIL.java | 30 +++++++++++++++++++ .../android/internal/telephony/RILUtils.java | 3 ++ .../internal/telephony/RadioImsProxy.java | 14 +++++++++ .../internal/telephony/imsphone/ImsPhone.java | 5 ++++ 7 files changed, 76 insertions(+) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index e80974f0f1..affcb995a2 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2873,6 +2873,13 @@ public interface CommandsInterface { */ default void stopImsTraffic(String token, Message result) {} + /** + * Triggers the UE initiated EPS fallback procedure. + * + * @param reason Specifies the reason for EPS fallback. + */ + default void triggerEpsFallback(int reason, Message result) {} + /** * Triggers radio to send ANBRQ message to the network. * diff --git a/src/java/com/android/internal/telephony/ImsResponse.java b/src/java/com/android/internal/telephony/ImsResponse.java index fa7d38fb8d..6b84a6e91f 100644 --- a/src/java/com/android/internal/telephony/ImsResponse.java +++ b/src/java/com/android/internal/telephony/ImsResponse.java @@ -87,6 +87,13 @@ public class ImsResponse extends IRadioImsResponse.Stub { RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); } + /** + * @param info Response info struct containing response type, serial no. and error. + */ + public void triggerEpsFallbackResponse(RadioResponseInfo info) { + RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + } + /** * @param info Response info struct containing response type, serial no. and error. */ diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 52a5b615ae..df077eb3ab 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -4885,6 +4885,16 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public void setTerminalBasedCallWaitingSupported(boolean supported) { } + /** + * Triggers the UE initiated EPS fallback procedure. + * + * @param reason specifies the reason for EPS fallback. + * @param response is callback message. + */ + public void triggerEpsFallback(int reason, Message response) { + mCi.triggerEpsFallback(reason, response); + } + /** * @return Telephony tester instance. */ diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 43f98b5698..23a13b7ca2 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5247,6 +5247,36 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + @Override + public void triggerEpsFallback(int reason, Message result) { + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); + if (imsProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_TRIGGER_EPS_FALLBACK, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " reason=" + reason); + } + + try { + imsProxy.triggerEpsFallback(rr.mSerial, reason); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(IMS_SERVICE, "triggerEpsFallback", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "triggerEpsFallback: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + @Override public void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond, Message result) { diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 3f17d6d3d0..a0e5d9de5a 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -203,6 +203,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_LCE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_NETWORK_SCAN; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_TRIGGER_EPS_FALLBACK; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UDUB; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORD; @@ -5061,6 +5062,8 @@ public class RILUtils { return "STOP_IMS_TRAFFIC"; case RIL_REQUEST_SEND_ANBR_QUERY: return "SEND_ANBR_QUERY"; + case RIL_REQUEST_TRIGGER_EPS_FALLBACK: + return "TRIGGER_EPS_FALLBACK"; default: return ""; } diff --git a/src/java/com/android/internal/telephony/RadioImsProxy.java b/src/java/com/android/internal/telephony/RadioImsProxy.java index 5e5492ae03..530fd9e8f7 100644 --- a/src/java/com/android/internal/telephony/RadioImsProxy.java +++ b/src/java/com/android/internal/telephony/RadioImsProxy.java @@ -135,6 +135,20 @@ public class RadioImsProxy extends RadioServiceProxy { } } + /** + * Calls IRadioIms#triggerEpsFallback. + * @param serial Serial number of request. + * @param reason Specifies the reason for EPS fallback. + * @throws RemoteException. + */ + public void triggerEpsFallback(int serial, int reason) + throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mImsProxy.triggerEpsFallback(serial, reason); + } + } + /** * Calls IRadioIms#sendAnbrQuery. * @param serial Serial number of request. diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 090cd27db7..f47f8374c9 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -2621,6 +2621,11 @@ public class ImsPhone extends ImsPhoneBase { mCT.setTerminalBasedCallWaitingStatus(state); } + @Override + public void triggerEpsFallback(int reason, Message response) { + mDefaultPhone.triggerEpsFallback(reason, response); + } + @Override public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); -- GitLab From e124fc4ab9fc83058a53d069edc0264ff31b23b7 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 2 Sep 2022 04:35:35 +0000 Subject: [PATCH 145/656] Update triggerImsDeregistration to specify the reason Bug: 219242993 Test: build & flash Change-Id: I02ef99b6c8a869a2b1cb7f47d8602f9373ebc577 Merged-In: I02ef99b6c8a869a2b1cb7f47d8602f9373ebc577 --- .../internal/telephony/ImsIndication.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/ImsIndication.java b/src/java/com/android/internal/telephony/ImsIndication.java index a4be0fcdd9..04821b415f 100644 --- a/src/java/com/android/internal/telephony/ImsIndication.java +++ b/src/java/com/android/internal/telephony/ImsIndication.java @@ -94,20 +94,24 @@ public class ImsIndication extends IRadioImsIndication.Stub { } /** - * Fired by radio when a graceful IMS deregistration needs to be performed by telephony - * prior to radio performing network detach. Example scenarios are SIM refresh or user - * mode preference change which would cause network detach. The radio waits for the - * IMS deregistration, which will be notified by telephony via + * Requests IMS stack to perform graceful IMS deregistration before radio performing + * network detach in the events of SIM remove, refresh or and so on. The radio waits for + * the IMS deregistration, which will be notified by telephony via * {@link IRadioIms#updateImsRegistrationInfo()}, or a certain timeout interval to start * the network detach procedure. * - * @param indicationType Type of radio indication + * @param indicationType Type of radio indication. + * @param reason the reason why the deregistration is triggered. */ - public void triggerImsDeregistration(int indicationType) { + public void triggerImsDeregistration(int indicationType, int reason) { mRil.processIndication(RIL.IMS_SERVICE, indicationType); - if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION); + if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION, reason); + + int[] response = new int[1]; + response[0] = reason; - mRil.mTriggerImsDeregistrationRegistrants.notifyRegistrants(); + mRil.mTriggerImsDeregistrationRegistrants.notifyRegistrants( + new AsyncResult(null, response, null)); } } -- GitLab From fb02560ba28e099e7fc645f7d9be13262c96c714 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 20 Sep 2022 05:00:52 +0000 Subject: [PATCH 146/656] Fix the way to detect the Radio Aidl HAL version Bug: 219242993 Test: build & flash Change-Id: I50a398affd4b778046a30e355ac51016e18d7e08 Merged-In: I50a398affd4b778046a30e355ac51016e18d7e08 --- .../com/android/internal/telephony/RIL.java | 3 +-- .../internal/telephony/RadioImsProxy.java | 25 +++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 23a13b7ca2..1b21a274d0 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -866,8 +866,7 @@ public class RIL extends BaseCommands implements CommandsInterface { binder = mMockModem.getServiceBinder(IMS_SERVICE); } if (binder != null) { - mRadioVersion = RADIO_HAL_VERSION_2_1; - ((RadioImsProxy) serviceProxy).setAidl(mRadioVersion, + mRadioVersion = ((RadioImsProxy) serviceProxy).setAidl(mRadioVersion, android.hardware.radio.ims.IRadioIms.Stub .asInterface(binder)); } diff --git a/src/java/com/android/internal/telephony/RadioImsProxy.java b/src/java/com/android/internal/telephony/RadioImsProxy.java index 530fd9e8f7..1fb7bd93fd 100644 --- a/src/java/com/android/internal/telephony/RadioImsProxy.java +++ b/src/java/com/android/internal/telephony/RadioImsProxy.java @@ -31,12 +31,33 @@ public class RadioImsProxy extends RadioServiceProxy { * Sets IRadioIms as the AIDL implementation for RadioServiceProxy. * @param halVersion Radio HAL version. * @param ims IRadioIms implementation. + * + * @return updated HAL version. */ - public void setAidl(HalVersion halVersion, android.hardware.radio.ims.IRadioIms ims) { + public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.ims.IRadioIms ims) { mHalVersion = halVersion; mImsProxy = ims; mIsAidl = true; - Rlog.d(TAG, "AIDL initialized"); + + try { + HalVersion newHalVersion; + int version = ims.getInterfaceVersion(); + switch(version) { + default: + newHalVersion = RIL.RADIO_HAL_VERSION_2_1; + break; + } + Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); + + if (mHalVersion.less(newHalVersion)) { + mHalVersion = newHalVersion; + } + } catch (RemoteException e) { + Rlog.e(TAG, "setAidl: " + e); + } + + Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); + return mHalVersion; } /** -- GitLab From 0e65b72766f62f0122b02b60f75c62fb0f6ff30f Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 16 Sep 2022 00:21:40 +0000 Subject: [PATCH 147/656] Replace ImsFailureReason with SuggestedAction Bug: 219242990 Bug: 246678554 Test: atest FrameworksTelephonyTests:ImsPhoneCallTrackerTest#testUpdateImsRegistrationInfo Change-Id: Ib21fae72eeb3fc0bd99ce7fc80c6ba486a79fb7e Merged-In: Ib21fae72eeb3fc0bd99ce7fc80c6ba486a79fb7e --- .../com/android/internal/telephony/CommandsInterface.java | 4 ++-- src/java/com/android/internal/telephony/RIL.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index affcb995a2..6c3e47ab88 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2848,12 +2848,12 @@ public interface CommandsInterface { * * @param state The current IMS registration state. * @param accessNetworkType The type of underlying radio access network used. - * @param reason A failure reason for IMS registration. + * @param suggestedAction The expected action that modem should perform. * @param capabilities IMS capabilities such as VOICE, VIDEO and SMS. */ default void updateImsRegistrationInfo(int state, @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, - int reason, int capabilities, Message result) {} + int suggestedAction, int capabilities, Message result) {} /** * Notifies the NAS and RRC layers of the radio the type of upcoming IMS traffic. diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 1b21a274d0..b01e0b1235 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5151,7 +5151,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void updateImsRegistrationInfo(int state, - int accessNetworkType, int reason, int capabilities, Message result) { + int accessNetworkType, int suggestedAction, int capabilities, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { @@ -5167,7 +5167,7 @@ public class RIL extends BaseCommands implements CommandsInterface { new android.hardware.radio.ims.ImsRegistration(); registrationInfo.regState = RILUtils.convertImsRegistrationState(state); registrationInfo.accessNetworkType = accessNetworkType; - registrationInfo.reason = reason; + registrationInfo.suggestedAction = suggestedAction; registrationInfo.capabilities = RILUtils.convertImsCapability(capabilities); try { -- GitLab From ee3a9ebf1311be6bd9201dae077397689d298273 Mon Sep 17 00:00:00 2001 From: sandeepjs Date: Mon, 31 Oct 2022 13:59:20 +0000 Subject: [PATCH 148/656] Updating portindex in the builder of subscriptionInfo the constructor of the subscriptionInfo is updated to builder, here while building subscriptionInfo getting portIndex as -1 for activeSubsInfo, hence test cases are failing. updating portIndex value to default ie to 0. Bug: 255697307 Test: atest EuiccControllerTest Change-Id: Ia7357b865693634a8ce3b4165a2a4048127babbc --- .../internal/telephony/euicc/EuiccControllerTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 85db492203..f960aff9d3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java @@ -75,7 +75,6 @@ import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; @@ -612,7 +611,6 @@ public class EuiccControllerTest extends TelephonyTest { assertFalse(mController.mCalledRefreshSubscriptionsAndSendResult); } - @Ignore("b/255697307") @Test @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS}) public void testDownloadSubscription_noPrivileges_hasCarrierPrivileges_multiSim() @@ -889,7 +887,6 @@ public class EuiccControllerTest extends TelephonyTest { anyBoolean(), any(), anyBoolean()); } - @Ignore("b/255697307") @Test @DisableCompatChanges({EuiccManager.SHOULD_RESOLVE_PORT_INDEX_FOR_APPS}) public void testSwitchToSubscription_emptySubscription_success() throws Exception { @@ -1263,6 +1260,7 @@ public class EuiccControllerTest extends TelephonyTest { throws Exception { SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder() .setSimSlotIndex(0) + .setPortIndex(mTelephonyManager.DEFAULT_PORT_INDEX) .setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER_ID) .setEmbedded(true); if (hasPrivileges) { @@ -1300,11 +1298,13 @@ public class EuiccControllerTest extends TelephonyTest { .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) .setEmbedded(true) .setCardId(CARD_ID) + .setPortIndex(mTelephonyManager.DEFAULT_PORT_INDEX) .build(); SubscriptionInfo subInfo2 = new SubscriptionInfo.Builder() .setNativeAccessRules(hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null) .setEmbedded(true) .setCardId(2) + .setPortIndex(TelephonyManager.DEFAULT_PORT_INDEX) .build(); when(mSubscriptionManager.canManageSubscription(subInfo1, PACKAGE_NAME)).thenReturn( hasPrivileges); -- GitLab From d62284ae6dead60caca6b3646e90f62f93378615 Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Tue, 1 Nov 2022 00:33:04 +0000 Subject: [PATCH 149/656] Cleanup pending MO call when it disconnects before alerting. Ensure that where a call is in the pending MO state and gets disconnected prior to alerting that it will be cleaned up so that other calls can be placed. Test: Wrote new unit test for this case. Fixes: 250229749 Change-Id: I4daa33915fcc3fa5b128175c19827fc332c05d1d --- .../imsphone/ImsPhoneCallTracker.java | 6 +++++ .../imsphone/ImsPhoneCallTrackerTest.java | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index bb7d69479e..61ec28e165 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -2806,6 +2806,12 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { conn.getCall().detach(conn); removeConnection(conn); + // If the call being disconnected was the pending MO call we should clear it. + if (mPendingMO == conn) { + mPendingMO.finalize(); + mPendingMO = null; + } + // remove conference participants from the cached list when call is disconnected List cpList = imsCall.getConferenceParticipants(); if (cpList != null) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 1a94727d8f..4f1bdac9d5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -1902,6 +1902,30 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { } } + /** + * Tests the case where a dialed call has not yet moved beyond the "pending MO" phase, but the + * user then disconnects. In such a case we need to ensure that the pending MO reference is + * cleared so that another call can be placed. + */ + @Test + @SmallTest + public void testCallDisconnectBeforeActive() { + ImsPhoneConnection connection = placeCall(); + assertEquals(1, mCTUT.getConnections().size()); + // Call is the pending MO right now. + assertEquals(connection, mCTUT.getPendingMO()); + assertEquals(Call.State.DIALING, mCTUT.mForegroundCall.getState()); + assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState()); + + mImsCallListener.onCallTerminated(connection.getImsCall(), + new ImsReasonInfo(ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE, 0)); + // Make sure pending MO got nulled out. + assertNull(mCTUT.getPendingMO()); + + // Try making another call; it should not fail. + ImsPhoneConnection connection2 = placeCall(); + } + private void sendCarrierConfigChanged() { Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); -- GitLab From 3287a50eb843549d82c62436710ee81b10090675 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Sat, 29 Oct 2022 12:02:51 +0000 Subject: [PATCH 150/656] When creating the StateMachine, I set the initial state. A state transition occurs while the state is transitioning from the old state to the new state. The problem occurs because the request is processed without the desired state. Bug: b/256244379 Test: atest FrameworksTelephonyTests:ImsEnablementTrackerTest Change-Id: I59bd7a00e00b8650ee55109e4e5a43489a34fe7c --- .../telephony/ims/ImsEnablementTracker.java | 65 +++++----- .../ims/ImsEnablementTrackerTest.java | 117 +++++++++++------- 2 files changed, 103 insertions(+), 79 deletions(-) diff --git a/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java b/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java index dea12bd9d4..f7412a4f9c 100644 --- a/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java +++ b/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java @@ -172,7 +172,7 @@ public class ImsEnablementTracker { @VisibleForTesting public int mSubId; - ImsEnablementTrackerStateMachine(String name, Looper looper) { + ImsEnablementTrackerStateMachine(String name, Looper looper, int state) { super(name, looper); mDefault = new Default(); mEnabled = new Enabled(); @@ -189,7 +189,8 @@ public class ImsEnablementTracker { addState(mEnabling); addState(mResetting); addState(mDisconnected); - setInitialState(mDisconnected); + + setInitialState(getState(state)); } public void clearAllMessage() { @@ -212,23 +213,6 @@ public class ImsEnablementTracker { sendMessage(COMMAND_DISCONNECTED_MSG); } - @VisibleForTesting - public void setState(int state) { - if (state == mDefault.mStateNo) { - mEnablementStateMachine.transitionTo(mDefault); - } else if (state == mEnabled.mStateNo) { - mEnablementStateMachine.transitionTo(mEnabled); - } else if (state == mDisabling.mStateNo) { - mEnablementStateMachine.transitionTo(mDisabling); - } else if (state == mDisabled.mStateNo) { - mEnablementStateMachine.transitionTo(mDisabled); - } else if (state == mEnabling.mStateNo) { - mEnablementStateMachine.transitionTo(mEnabling); - } else if (state == mResetting.mStateNo) { - mEnablementStateMachine.transitionTo(mResetting); - } - } - @VisibleForTesting public boolean isState(int state) { if (state == mDefault.mStateNo) { @@ -247,6 +231,24 @@ public class ImsEnablementTracker { return false; } + private State getState(int state) { + switch (state) { + case ImsEnablementTracker.STATE_IMS_DEFAULT: + return mDefault; + case ImsEnablementTracker.STATE_IMS_ENABLED: + return mEnabled; + case ImsEnablementTracker.STATE_IMS_DISABLING: + return mDisabling; + case ImsEnablementTracker.STATE_IMS_DISABLED: + return mDisabled; + case ImsEnablementTracker.STATE_IMS_ENABLING: + return mEnabling; + case ImsEnablementTracker.STATE_IMS_RESETTING: + return mResetting; + default: + return mDisconnected; + } + } class Default extends State { public int mStateNo = STATE_IMS_DEFAULT; @@ -520,15 +522,25 @@ public class ImsEnablementTracker { public ImsEnablementTracker(Looper looper) { mIImsServiceController = null; mEnablementStateMachine = new ImsEnablementTrackerStateMachine("ImsEnablementTracker", - looper); + looper, ImsEnablementTracker.STATE_IMS_DISCONNECTED); mEnablementStateMachine.start(); } @VisibleForTesting - public ImsEnablementTracker(Looper looper, IImsServiceController controller) { + public ImsEnablementTracker(Looper looper, IImsServiceController controller, int state) { mIImsServiceController = controller; mEnablementStateMachine = new ImsEnablementTrackerStateMachine("ImsEnablementTracker", - looper); + looper, state); + } + + /** + * This API is for testing purposes only and is used to start a state machine. + */ + @VisibleForTesting + public void startStateMachineAsConnected() { + if (mEnablementStateMachine == null) { + return; + } mEnablementStateMachine.start(); mEnablementStateMachine.sendMessage(COMMAND_CONNECTED_MSG); } @@ -538,15 +550,6 @@ public class ImsEnablementTracker { return mEnablementStateMachine.getHandler(); } - /** - * Set the current state as an input state. - * @param state input state. - */ - @VisibleForTesting - public void setState(int state) { - mEnablementStateMachine.setState(state); - } - /** * Check that the current state and the input state are the same. * @param state the input state. diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java index 4d731b54eb..7c45f24850 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java @@ -59,8 +59,8 @@ public class ImsEnablementTrackerTest extends ImsTestBase { private static class TestableImsEnablementTracker extends ImsEnablementTracker { private long mLastImsOperationTimeMs = 0L; - TestableImsEnablementTracker(Looper looper, IImsServiceController controller) { - super(looper, controller); + TestableImsEnablementTracker(Looper looper, IImsServiceController controller, int state) { + super(looper, controller, state); } @Override @@ -93,10 +93,11 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandInDefaultState() throws RemoteException { // Verify that when the enable command is received in the Default state and enableIms // is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DEFAULT); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DEFAULT); - // Wait for a while for the state machine to be ready. + // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); mImsEnablementTracker.enableIms(SLOT_1, SUB_1); @@ -110,9 +111,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInDefaultState() throws RemoteException { // Verify that when the disable command is received in the Default state and disableIms // is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DEFAULT); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DEFAULT); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -126,9 +128,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @Test public void testResetCommandInDefaultState() throws RemoteException { // Verify that when reset command is received in the Default state, it should be ignored. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DEFAULT); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DEFAULT); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -142,9 +145,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @Test public void testEnableCommandInEnabledState() throws RemoteException { // Verify that received the enable command is not handle in the Enabled state, - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_ENABLED); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLED); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -160,9 +164,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInEnabledState() throws RemoteException { // Verify that when the disable command is received in the Enabled state and disableIms // is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_ENABLED); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLED); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -177,9 +182,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testResetCommandInEnabledState() throws RemoteException { // Verify that when the reset command is received in the Enabled state and disableIms // and enableIms are called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_ENABLED); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLED); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -198,9 +204,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @Test public void testDisableCommandInDisabledState() throws RemoteException { // Verify that when disable command is received in the Disabled state, it should be ignored. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DISABLED); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLED); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -215,9 +222,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandInDisabledState() throws RemoteException { // Verify that when the enable command is received in the Disabled state and enableIms // is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DISABLED); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLED); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -232,9 +240,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandWithoutTimeoutInDisableState() throws RemoteException { // Verify that when the enable command is received in the Disabled state. After throttle // time expired, the enableIms is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DISABLED); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLED); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); // Set the last operation time to current to verify the message with delay. @@ -251,9 +260,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @Test public void testResetCommandInDisabledState() throws RemoteException { // Verify that the reset command is received in the Disabled state and it`s not handled. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DISABLED); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLED); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -267,11 +277,12 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @Test public void testEnableCommandInDisablingState() throws RemoteException { // Verify that when enable command is received in the Disabling state, it should be ignored. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DISABLING); mHandler = mImsEnablementTracker.getHandler(); - // Set the last operation time to current so that the throttle time does not expire. + // Set the last operation time to current to verify the message with delay. mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLING); + mImsEnablementTracker.startStateMachineAsConnected(); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -286,11 +297,12 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisablingMessageInDisablingState() throws RemoteException { // Verify that when the internal disable message is received in the Disabling state and // disableIms is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DISABLING); mHandler = mImsEnablementTracker.getHandler(); // Set the last operation time to current to verify the message with delay. mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLING); + mImsEnablementTracker.startStateMachineAsConnected(); waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), mImsEnablementTracker.getRemainThrottleTime() + 100); @@ -303,11 +315,12 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testResetCommandInDisablingState() throws RemoteException { // Verify when the reset command is received in the Disabling state the disableIms and // enableIms are called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DISABLING); mHandler = mImsEnablementTracker.getHandler(); // Set the last operation time to current to verify the message with delay. mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLING); + mImsEnablementTracker.startStateMachineAsConnected(); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -328,9 +341,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnablingMessageInEnablingState() throws RemoteException { // Verify that when the internal enable message is received in the Enabling state and // enableIms is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_ENABLING); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLING); waitForHandlerActionDelayed(mHandler, 100, 150); verify(mMockServiceControllerBinder).enableIms(anyInt(), anyInt()); @@ -342,11 +356,12 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInEnablingState() throws RemoteException { // Verify that when the disable command is received in the Enabling state and // clear pending message and disableIms is not called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_ENABLING); mHandler = mImsEnablementTracker.getHandler(); // Set the last operation time to current to verify the message with delay. mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLING); + mImsEnablementTracker.startStateMachineAsConnected(); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -360,11 +375,12 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @Test public void testResetCommandWithEnablingState() throws RemoteException { // Verify that when reset command is received in the Enabling state, it should be ignored. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_ENABLING); mHandler = mImsEnablementTracker.getHandler(); // Set the last operation time to current to verify the message with delay. mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLING); + mImsEnablementTracker.startStateMachineAsConnected(); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -379,11 +395,12 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandInResettingState() throws RemoteException { // Verify that when the enable command is received in the Resetting state and // enableIms is not called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_RESETTING); mHandler = mImsEnablementTracker.getHandler(); // Set the last operation time to current to verify the message with delay. mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_RESETTING); + mImsEnablementTracker.startStateMachineAsConnected(); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -398,11 +415,12 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInResettingState() throws RemoteException { // Verify that when the disable command is received in the Resetting state and // disableIms is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_RESETTING); mHandler = mImsEnablementTracker.getHandler(); // Set the last operation time to current to verify the message with delay. mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_RESETTING); + mImsEnablementTracker.startStateMachineAsConnected(); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -418,9 +436,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testResettingMessageInResettingState() throws RemoteException { // Verify that when the internal reset message is received in the Resetting state and // disableIms and enableIms are called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_RESETTING); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_RESETTING); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -436,9 +455,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @SmallTest @Test public void testConsecutiveCommandInEnabledState() throws RemoteException { - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_ENABLED); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_ENABLED); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -469,9 +489,10 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @SmallTest @Test public void testConsecutiveCommandInDisabledState() throws RemoteException { - mImsEnablementTracker = createTracker(mMockServiceControllerBinder); + mImsEnablementTracker = createTracker(mMockServiceControllerBinder, + mImsEnablementTracker.STATE_IMS_DISABLED); + mImsEnablementTracker.startStateMachineAsConnected(); mHandler = mImsEnablementTracker.getHandler(); - mImsEnablementTracker.setState(mImsEnablementTracker.STATE_IMS_DISABLED); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); @@ -500,9 +521,9 @@ public class ImsEnablementTrackerTest extends ImsTestBase { assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); } - private TestableImsEnablementTracker createTracker(IImsServiceController binder) { + private TestableImsEnablementTracker createTracker(IImsServiceController binder, int state) { TestableImsEnablementTracker tracker = new TestableImsEnablementTracker( - Looper.getMainLooper(), binder); + Looper.getMainLooper(), binder, state); return tracker; } } -- GitLab From 49b4f188afa93e59e8a47021f5d238bed6d51283 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 1 Nov 2022 06:30:01 +0000 Subject: [PATCH 151/656] Change the type of token of startImsTraffic from String to int Bug: 219242095 Test: atest Change-Id: I6342e1096e114e0855541cb601ca93e5b13e3ca8 --- .../com/android/internal/telephony/CommandsInterface.java | 4 ++-- src/java/com/android/internal/telephony/ImsIndication.java | 2 +- src/java/com/android/internal/telephony/RIL.java | 5 ++--- src/java/com/android/internal/telephony/RadioImsProxy.java | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 6c3e47ab88..acce23e050 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2862,7 +2862,7 @@ public interface CommandsInterface { * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. * @param accessNetworkType The type of underlying radio access network used. */ - default void startImsTraffic(String token, int trafficType, + default void startImsTraffic(int token, int trafficType, @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, Message result) {} @@ -2871,7 +2871,7 @@ public interface CommandsInterface { * * @param token The token assigned by startImsTraffic. */ - default void stopImsTraffic(String token, Message result) {} + default void stopImsTraffic(int token, Message result) {} /** * Triggers the UE initiated EPS fallback procedure. diff --git a/src/java/com/android/internal/telephony/ImsIndication.java b/src/java/com/android/internal/telephony/ImsIndication.java index 04821b415f..896679ec76 100644 --- a/src/java/com/android/internal/telephony/ImsIndication.java +++ b/src/java/com/android/internal/telephony/ImsIndication.java @@ -51,7 +51,7 @@ public class ImsIndication extends IRadioImsIndication.Stub { * @param token The token provided by {@link #startImsTraffic}. * @param failureInfo Connection failure information. */ - public void onConnectionSetupFailure(int indicationType, String token, + public void onConnectionSetupFailure(int indicationType, int token, android.hardware.radio.ims.ConnectionFailureInfo failureInfo) { mRil.processIndication(RIL.IMS_SERVICE, indicationType); diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 70691104d6..ad5254c66d 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5188,8 +5188,7 @@ public class RIL extends BaseCommands implements CommandsInterface { } @Override - public void startImsTraffic(String token, - int trafficType, int accessNetworkType, Message result) { + public void startImsTraffic(int token, int trafficType, int accessNetworkType, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { @@ -5218,7 +5217,7 @@ public class RIL extends BaseCommands implements CommandsInterface { } @Override - public void stopImsTraffic(String token, Message result) { + public void stopImsTraffic(int token, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { diff --git a/src/java/com/android/internal/telephony/RadioImsProxy.java b/src/java/com/android/internal/telephony/RadioImsProxy.java index 1fb7bd93fd..5cb82aa5f7 100644 --- a/src/java/com/android/internal/telephony/RadioImsProxy.java +++ b/src/java/com/android/internal/telephony/RadioImsProxy.java @@ -134,7 +134,7 @@ public class RadioImsProxy extends RadioServiceProxy { * @param accessNetworkType The type of underlying radio access network used. * @throws RemoteException. */ - public void startImsTraffic(int serial, String token, int trafficType, int accessNetworkType) + public void startImsTraffic(int serial, int token, int trafficType, int accessNetworkType) throws RemoteException { if (isEmpty()) return; if (isAidl()) { @@ -148,7 +148,7 @@ public class RadioImsProxy extends RadioServiceProxy { * @param token The token assigned by startImsTraffic. * @throws RemoteException. */ - public void stopImsTraffic(int serial, String token) + public void stopImsTraffic(int serial, int token) throws RemoteException { if (isEmpty()) return; if (isAidl()) { -- GitLab From 2f236a6aafa86c3f622ec1e5c3c04cc35c2fd188 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 7 Sep 2022 03:11:27 +0000 Subject: [PATCH 152/656] Update RIL for Emergency Call domain selection HAL API changes. Add the following: - setEmergencyMode - triggerEmergencyNetworkScan - cancelEmergencyNetworkScan - default void exitEmergencyMode Test: build and flash Bug: 243344927 Change-Id: I1a0eb89beb886545862b04d9c395278e9f2c7582 --- .../internal/telephony/CommandsInterface.java | 50 ++++++- .../internal/telephony/NetworkIndication.java | 7 +- .../internal/telephony/NetworkResponse.java | 6 +- .../com/android/internal/telephony/Phone.java | 68 +++++++++ .../com/android/internal/telephony/RIL.java | 136 ++++++++++++++++++ .../android/internal/telephony/RILUtils.java | 115 +++++++++++++++ .../emergency/EmergencyConstants.java | 69 +++++++++ 7 files changed, 443 insertions(+), 8 deletions(-) create mode 100644 src/java/com/android/internal/telephony/emergency/EmergencyConstants.java diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 6c3e47ab88..fe7f103b95 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -29,6 +29,7 @@ import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CarrierRestrictionRules; import android.telephony.ClientRequestStats; +import android.telephony.DomainSelectionService; import android.telephony.ImsiEncryptionInfo; import android.telephony.NetworkScanRequest; import android.telephony.RadioAccessSpecifier; @@ -41,6 +42,7 @@ import android.telephony.data.TrafficDescriptor; import android.telephony.emergency.EmergencyNumber; import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; +import com.android.internal.telephony.emergency.EmergencyConstants; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState; import com.android.internal.telephony.uicc.IccCardStatus; @@ -2821,20 +2823,60 @@ public interface CommandsInterface { default void getUsageSetting(Message result) {} /** - * Register for Emergency network scan result. + * Sets the emergency mode. + * + * @param emcMode Defines the radio emergency mode type. + * @param result Callback message containing the success or failure status. + */ + default void setEmergencyMode(@EmergencyConstants.EmergencyMode int emcMode, + @Nullable Message result) {} + + /** + * Triggers an emergency network scan. + * + * @param accessNetwork Contains the list of access network types to be prioritized + * during emergency scan. The 1st entry has the highest priority. + * @param scanType Indicates the type of scans to be performed i.e. limited scan, + * full service scan or both. + * @param result Callback message containing the success or failure status. + */ + default void triggerEmergencyNetworkScan( + @NonNull @AccessNetworkConstants.RadioAccessNetworkType int[] accessNetwork, + @DomainSelectionService.EmergencyScanType int scanType, @Nullable Message result) {} + + /** + * Cancels ongoing emergency network scan. + * + * @param resetScan Indicates how the next {@link #triggerEmergencyNetworkScan} should work. + * If {@code true}, then the modem shall start the new scan from the beginning, + * otherwise the modem shall resume from the last search. + * @param result Callback message containing the success or failure status. + */ + default void cancelEmergencyNetworkScan(boolean resetScan, @Nullable Message result) {} + + /** + * Exits ongoing emergency mode. + * + * @param result Callback message containing the success or failure status. + */ + default void exitEmergencyMode(@Nullable Message result) {} + + /** + * Registers for emergency network scan result. * * @param h Handler for notification message. * @param what User-defined message code. * @param obj User object. */ - default void registerForEmergencyNetworkScan(Handler h, int what, Object obj) {} + default void registerForEmergencyNetworkScan(@NonNull Handler h, + int what, @Nullable Object obj) {} /** - * Unregister for Emergency network scan result. + * Unregisters for emergency network scan result. * * @param h Handler to be removed from the registrant list. */ - default void unregisterForEmergencyNetworkScan(Handler h) {} + default void unregisterForEmergencyNetworkScan(@NonNull Handler h) {} /** * Provides a list of SRVCC call information to radio diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index 9c577ba5b9..d59707e28b 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -40,6 +40,7 @@ import android.telephony.AnomalyReporter; import android.telephony.BarringInfo; import android.telephony.CellIdentity; import android.telephony.CellInfo; +import android.telephony.EmergencyRegResult; import android.telephony.LinkCapacityEstimate; import android.telephony.NetworkRegistrationInfo; import android.telephony.PhysicalChannelConfig; @@ -390,12 +391,14 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { android.hardware.radio.network.EmergencyRegResult result) { mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + EmergencyRegResult response = RILUtils.convertHalEmergencyRegResult(result); + if (mRil.isLogOrTrace()) { - mRil.unsljLogRet(RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT, result); + mRil.unsljLogRet(RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT, response); } mRil.mEmergencyNetworkScanRegistrants.notifyRegistrants( - new AsyncResult(null, result, null)); + new AsyncResult(null, response, null)); } @Override diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index 5f5895e16c..370335a70f 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -22,6 +22,7 @@ import android.hardware.radio.network.IRadioNetworkResponse; import android.os.AsyncResult; import android.telephony.BarringInfo; import android.telephony.CellInfo; +import android.telephony.EmergencyRegResult; import android.telephony.LinkCapacityEstimate; import android.telephony.RadioAccessSpecifier; import android.telephony.SignalStrength; @@ -445,10 +446,11 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); if (rr != null) { + EmergencyRegResult response = RILUtils.convertHalEmergencyRegResult(regState); if (responseInfo.error == RadioError.NONE) { - RadioResponse.sendMessageResponse(rr.mResult, regState); + RadioResponse.sendMessageResponse(rr.mResult, response); } - mRil.processResponseDone(rr, responseInfo, regState); + mRil.processResponseDone(rr, responseInfo, response); } } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index df077eb3ab..396fdfe292 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -45,6 +45,7 @@ import android.telephony.CarrierRestrictionRules; import android.telephony.CellIdentity; import android.telephony.CellInfo; import android.telephony.ClientRequestStats; +import android.telephony.DomainSelectionService; import android.telephony.ImsiEncryptionInfo; import android.telephony.LinkCapacityEstimate; import android.telephony.NetworkRegistrationInfo; @@ -77,6 +78,7 @@ import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; +import com.android.internal.telephony.emergency.EmergencyConstants; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; @@ -4895,6 +4897,72 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.triggerEpsFallback(reason, response); } + /** + * Sets the emergency mode + * + * @param emcMode The radio emergency mode type. + * @param result Callback message. + */ + public void setEmergencyMode(@EmergencyConstants.EmergencyMode int emcMode, + @Nullable Message result) { + mCi.setEmergencyMode(emcMode, result); + } + + /** + * Triggers an emergency network scan. + * + * @param accessNetwork Contains the list of access network types to be prioritized + * during emergency scan. The 1st entry has the highest priority. + * @param scanType Indicates the type of scans to be performed i.e. limited scan, + * full service scan or any scan. + * @param result Callback message. + */ + public void triggerEmergencyNetworkScan( + @NonNull @AccessNetworkConstants.RadioAccessNetworkType int[] accessNetwork, + @DomainSelectionService.EmergencyScanType int scanType, @Nullable Message result) { + mCi.triggerEmergencyNetworkScan(accessNetwork, scanType, result); + } + + /** + * Cancels ongoing emergency network scan + * @param resetScan Indicates how the next {@link #triggerEmergencyNetworkScan} should work. + * If {@code true}, then the modem shall start the new scan from the beginning, + * otherwise the modem shall resume from the last search. + * @param result Callback message. + */ + public void cancelEmergencyNetworkScan(boolean resetScan, @Nullable Message result) { + mCi.cancelEmergencyNetworkScan(resetScan, result); + } + + /** + * Exits ongoing emergency mode + * @param result Callback message. + */ + public void exitEmergencyMode(@Nullable Message result) { + mCi.exitEmergencyMode(result); + } + + /** + * Registers for emergency network scan result. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForEmergencyNetworkScan(@NonNull Handler h, + int what, @Nullable Object obj) { + mCi.registerForEmergencyNetworkScan(h, what, obj); + } + + /** + * Unregisters for emergency network scan result. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForEmergencyNetworkScan(@NonNull Handler h) { + mCi.unregisterForEmergencyNetworkScan(h); + } + /** * @return Telephony tester instance. */ diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 70691104d6..d57284d0b1 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -45,6 +45,7 @@ import android.os.Trace; import android.os.WorkSource; import android.provider.Settings; import android.sysprop.TelephonyProperties; +import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CarrierRestrictionRules; import android.telephony.CellInfo; @@ -55,6 +56,7 @@ import android.telephony.CellSignalStrengthNr; import android.telephony.CellSignalStrengthTdscdma; import android.telephony.CellSignalStrengthWcdma; import android.telephony.ClientRequestStats; +import android.telephony.DomainSelectionService; import android.telephony.ImsiEncryptionInfo; import android.telephony.ModemActivityInfo; import android.telephony.NeighboringCellInfo; @@ -78,6 +80,7 @@ import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; 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.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.metrics.ModemRestartStats; import com.android.internal.telephony.metrics.TelephonyMetrics; @@ -5306,6 +5309,139 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * {@inheritDoc} + */ + @Override + public void setEmergencyMode(int emcMode, Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); + if (networkProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_SET_EMERGENCY_MODE, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " mode=" + EmergencyConstants.emergencyModeToString(emcMode)); + } + + try { + networkProxy.setEmergencyMode(rr.mSerial, emcMode); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setEmergencyMode", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "setEmergencyMode: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void triggerEmergencyNetworkScan( + @NonNull @AccessNetworkConstants.RadioAccessNetworkType int[] accessNetwork, + @DomainSelectionService.EmergencyScanType int scanType, Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); + if (networkProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + networkProxy.triggerEmergencyNetworkScan(rr.mSerial, + RILUtils.convertEmergencyNetworkScanTrigger(accessNetwork, scanType)); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(NETWORK_SERVICE, "triggerEmergencyNetworkScan", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "triggerEmergencyNetworkScan: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void cancelEmergencyNetworkScan(boolean resetScan, Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); + if (networkProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_EMERGENCY_NETWORK_SCAN, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " resetScan=" + resetScan); + } + + try { + networkProxy.cancelEmergencyNetworkScan(rr.mSerial, resetScan); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(NETWORK_SERVICE, "cancelEmergencyNetworkScan", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "cancelEmergencyNetworkScan: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void exitEmergencyMode(Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); + if (networkProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_EXIT_EMERGENCY_MODE, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + networkProxy.exitEmergencyMode(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(NETWORK_SERVICE, "exitEmergencyMode", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "exitEmergencyMode: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + //***** Private Methods /** * This is a helper function to be called when an indication callback is called for any radio diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index a0e5d9de5a..c05b669295 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -29,6 +29,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ALLOCATE_P import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ALLOW_DATA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ANSWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_BASEBAND_VERSION; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CANCEL_EMERGENCY_NETWORK_SCAN; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CANCEL_HANDOVER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CANCEL_USSD; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CDMA_BROADCAST_ACTIVATION; @@ -74,6 +75,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ENTER_SIM_ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ENTER_SIM_PUK; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ENTER_SIM_PUK2; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_EXIT_EMERGENCY_MODE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_EXPLICIT_CALL_TRANSFER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_ACTIVITY_INFO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_ALLOWED_CARRIERS; @@ -155,6 +157,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_CLIR; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_DATA_PROFILE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_DATA_THROTTLING; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_DC_RT_INFO_RATE; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_EMERGENCY_MODE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_FACILITY_LOCK; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_INITIAL_ATTACH_APN; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA; @@ -203,6 +206,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_LCE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_NETWORK_SCAN; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_TRIGGER_EPS_FALLBACK; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UDUB; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO; @@ -223,6 +227,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CELL_INFO_LI import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CONNECTION_SETUP_FAILURE; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_DATA_CALL_LIST_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_DC_RT_INFO_CHANGED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EMERGENCY_NUMBER_LIST; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE; @@ -274,6 +279,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_UICC_SUBSCRI import static com.android.internal.telephony.RILConstants.RIL_UNSOL_UNTHROTTLE_APN; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_VOICE_RADIO_TECH_CHANGED; +import android.annotation.NonNull; import android.annotation.Nullable; import android.net.InetAddresses; import android.net.LinkAddress; @@ -307,8 +313,11 @@ import android.telephony.CellSignalStrengthNr; import android.telephony.CellSignalStrengthTdscdma; import android.telephony.CellSignalStrengthWcdma; import android.telephony.ClosedSubscriberGroupInfo; +import android.telephony.DomainSelectionService; +import android.telephony.EmergencyRegResult; import android.telephony.LinkCapacityEstimate; import android.telephony.ModemInfo; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneCapability; import android.telephony.PhoneNumberUtils; import android.telephony.PhysicalChannelConfig; @@ -4601,6 +4610,102 @@ public class RILUtils { validationBeforeSwitchSupported, deviceNrCapabilities); } + /** + * Convert network scan type + * @param scanType The network scan type + * @return The converted EmergencyScanType + */ + public static int convertEmergencyScanType(int scanType) { + switch (scanType) { + case DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE: + return android.hardware.radio.network.EmergencyScanType.LIMITED_SERVICE; + case DomainSelectionService.SCAN_TYPE_FULL_SERVICE: + return android.hardware.radio.network.EmergencyScanType.FULL_SERVICE; + default: + return android.hardware.radio.network.EmergencyScanType.NO_PREFERENCE; + } + } + + /** + * Convert to EmergencyNetworkScanTrigger + * @param accessNetwork The list of access network types + * @param scanType The network scan type + * @return The converted EmergencyNetworkScanTrigger + */ + public static android.hardware.radio.network.EmergencyNetworkScanTrigger + convertEmergencyNetworkScanTrigger(@NonNull int[] accessNetwork, int scanType) { + int[] halAccessNetwork = new int[accessNetwork.length]; + for (int i = 0; i < accessNetwork.length; i++) { + halAccessNetwork[i] = convertToHalAccessNetworkAidl(accessNetwork[i]); + } + + android.hardware.radio.network.EmergencyNetworkScanTrigger scanRequest = + new android.hardware.radio.network.EmergencyNetworkScanTrigger(); + + scanRequest.accessNetwork = halAccessNetwork; + scanRequest.scanType = convertEmergencyScanType(scanType); + return scanRequest; + } + + /** + * Convert EmergencyRegResult.aidl to EmergencyRegResult. + * @param halResult EmergencyRegResult.aidl in HAL. + * @return Converted EmergencyRegResult. + */ + public static EmergencyRegResult convertHalEmergencyRegResult( + android.hardware.radio.network.EmergencyRegResult halResult) { + return new EmergencyRegResult( + halResult.accessNetwork, + convertHalRegState(halResult.regState), + halResult.emcDomain, + halResult.isVopsSupported, + halResult.isEmcBearerSupported, + halResult.nwProvidedEmc, + halResult.nwProvidedEmf, + halResult.mcc, + halResult.mnc, + getCountryCodeForMccMnc(halResult.mcc, halResult.mnc)); + } + + private static @NonNull String getCountryCodeForMccMnc( + @NonNull String mcc, @NonNull String mnc) { + if (TextUtils.isEmpty(mcc)) return ""; + if (TextUtils.isEmpty(mnc)) mnc = "000"; + String operatorNumeric = TextUtils.concat(mcc, mnc).toString(); + + MccTable.MccMnc mccMnc = MccTable.MccMnc.fromOperatorNumeric(operatorNumeric); + return MccTable.geoCountryCodeForMccMnc(mccMnc); + } + + /** + * Convert RegResult.aidl to RegistrationState. + * @param halRegState RegResult in HAL. + * @return Converted RegistrationState. + */ + public static @NetworkRegistrationInfo.RegistrationState int convertHalRegState( + int halRegState) { + switch (halRegState) { + case android.hardware.radio.network.RegState.NOT_REG_MT_NOT_SEARCHING_OP: + case android.hardware.radio.network.RegState.NOT_REG_MT_NOT_SEARCHING_OP_EM: + return NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; + case android.hardware.radio.network.RegState.REG_HOME: + return NetworkRegistrationInfo.REGISTRATION_STATE_HOME; + case android.hardware.radio.network.RegState.NOT_REG_MT_SEARCHING_OP: + case android.hardware.radio.network.RegState.NOT_REG_MT_SEARCHING_OP_EM: + return NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING; + case android.hardware.radio.network.RegState.REG_DENIED: + case android.hardware.radio.network.RegState.REG_DENIED_EM: + return NetworkRegistrationInfo.REGISTRATION_STATE_DENIED; + case android.hardware.radio.network.RegState.UNKNOWN: + case android.hardware.radio.network.RegState.UNKNOWN_EM: + return NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN; + case android.hardware.radio.network.RegState.REG_ROAMING: + return NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; + default: + return NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; + } + } + /** Append the data to the end of an ArrayList */ public static void appendPrimitiveArrayToArrayList(byte[] src, ArrayList dst) { for (byte b : src) { @@ -5052,6 +5157,14 @@ public class RILUtils { return "SET_USAGE_SETTING"; case RIL_REQUEST_GET_USAGE_SETTING: return "GET_USAGE_SETTING"; + case RIL_REQUEST_SET_EMERGENCY_MODE: + return "SET_EMERGENCY_MODE"; + case RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN: + return "TRIGGER_EMERGENCY_NETWORK_SCAN"; + case RIL_REQUEST_CANCEL_EMERGENCY_NETWORK_SCAN: + return "CANCEL_EMERGENCY_NETWORK_SCAN"; + case RIL_REQUEST_EXIT_EMERGENCY_MODE: + return "EXIT_EMERGENCY_MODE"; case RIL_REQUEST_SET_SRVCC_CALL_INFO: return "SET_SRVCC_CALL_INFO"; case RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO: @@ -5196,6 +5309,8 @@ public class RILUtils { return "UNSOL_REGISTRATION_FAILED"; case RIL_UNSOL_BARRING_INFO_CHANGED: return "UNSOL_BARRING_INFO_CHANGED"; + case RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT: + return "UNSOL_EMERGENCY_NETWORK_SCAN_RESULT"; case RIL_UNSOL_CONNECTION_SETUP_FAILURE: return "UNSOL_CONNECTION_SETUP_FAILURE"; case RIL_UNSOL_NOTIFY_ANBR: diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyConstants.java b/src/java/com/android/internal/telephony/emergency/EmergencyConstants.java new file mode 100644 index 0000000000..6caf5abef7 --- /dev/null +++ b/src/java/com/android/internal/telephony/emergency/EmergencyConstants.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 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.emergency; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Define the constants for emergency call domain selection. + */ +public class EmergencyConstants { + + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"MODE_EMERGENCY_"}, + value = { + MODE_EMERGENCY_NONE, + MODE_EMERGENCY_WWAN, + MODE_EMERGENCY_WLAN, + MODE_EMERGENCY_CALLBACK, + }) + public @interface EmergencyMode {} + + /** + * Default value. + */ + public static final int MODE_EMERGENCY_NONE = 0; + /** + * Mode Type Emergency WWAN, indicates that the current domain selected for the Emergency call + * is cellular. + */ + public static final int MODE_EMERGENCY_WWAN = 1; + /** + * Mode Type Emergency WLAN, indicates that the current domain selected for the Emergency call + * is WLAN/WIFI. + */ + public static final int MODE_EMERGENCY_WLAN = 2; + /** + * Mode Type Emergency Callback, indicates that the current mode set request is for Emergency + * callback. + */ + public static final int MODE_EMERGENCY_CALLBACK = 3; + + /** Converts the {@link EmergencyMode} to String */ + public static String emergencyModeToString(int emcMode) { + switch (emcMode) { + case MODE_EMERGENCY_NONE: return "NONE"; + case MODE_EMERGENCY_WWAN: return "WWAN"; + case MODE_EMERGENCY_WLAN: return "WLAN"; + case MODE_EMERGENCY_CALLBACK: return "CALLBACK"; + default: return "UNKNOWN(" + emcMode + ")"; + } + } +} -- GitLab From c32727fab3df9ee8f2e994b0190609a3467e423f Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Mon, 19 Sep 2022 09:57:23 +0000 Subject: [PATCH 153/656] UT for IccIoResult file Bug: 244637886 Test: Atest Verification done Change-Id: Ie1ec869f7aede2e782d64a19a570fb435d9550a3 --- .../telephony/uicc/IccIoResultTest.java | 452 ++++++++++++++++++ 1 file changed, 452 insertions(+) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/uicc/IccIoResultTest.java diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccIoResultTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccIoResultTest.java new file mode 100644 index 0000000000..b3e0a85cff --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccIoResultTest.java @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2022 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.uicc; + +import org.junit.Assert; +import org.junit.Test; + +public class IccIoResultTest { + + @Test + public void check0x90_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x90, 0x00, new byte[10]); + String resultStr = iccIoResult.toString(); + + Assert.assertTrue(resultStr != null && (!resultStr.contains("Error"))); + } + + @Test + public void check0x91_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x91, 0x00, new byte[10]); + String resultStr = iccIoResult.toString(); + + Assert.assertTrue(resultStr != null && (!resultStr.contains("Error"))); + } + + @Test + public void check0x9E_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x9E, 0x00, new byte[10]); + String resultStr = iccIoResult.toString(); + + Assert.assertTrue(resultStr != null && (!resultStr.contains("Error"))); + } + + @Test + public void check0x9F_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x9F, 0x00, new byte[10]); + String resultStr = iccIoResult.toString(); + + Assert.assertTrue(resultStr != null && (!resultStr.contains("Error"))); + } + + @Test + public void check0x94_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x94, 0x00, new byte[10]); + String resultStr = iccIoResult.toString(); + + Assert.assertTrue(resultStr != null && (resultStr.contains("no EF selected"))); + + iccIoResult = new IccIoResult(0x94, 0x02, new byte[10]); + resultStr = iccIoResult.toString(); + + Assert.assertTrue( + resultStr != null && (resultStr.contains("out f range (invalid address)"))); + + iccIoResult = new IccIoResult(0x94, 0x04, new byte[10]); + resultStr = iccIoResult.toString(); + + Assert.assertTrue( + resultStr != null && (resultStr.contains("file ID not found/pattern not found"))); + + iccIoResult = new IccIoResult(0x94, 0x08, new byte[10]); + resultStr = iccIoResult.toString(); + + Assert.assertTrue( + resultStr != null && (resultStr.contains("file is inconsistent with the command"))); + } + + @Test + public void check0x98_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x98, 0x00, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("unknown"))); + + iccIoResult = new IccIoResult(0x98, 0x02, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("no CHV initialized"))); + + iccIoResult = new IccIoResult(0x98, 0x04, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains("access condition not fulfilled"))); + + iccIoResult = new IccIoResult(0x98, 0x08, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains("in contradiction with CHV status"))); + + iccIoResult = new IccIoResult(0x98, 0x10, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "in contradiction with invalidation status"))); + + iccIoResult = new IccIoResult(0x98, 0x40, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "unsuccessful CHV verification, no attempt left"))); + + iccIoResult = new IccIoResult(0x98, 0x50, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "increase cannot be performed, Max value reached"))); + + iccIoResult = new IccIoResult(0x98, 0x62, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "authentication error, application specific"))); + + iccIoResult = new IccIoResult(0x98, 0x64, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "authentication error, security context not supported"))); + + iccIoResult = new IccIoResult(0x98, 0x65, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("key freshness failure"))); + + iccIoResult = new IccIoResult(0x98, 0x66, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "authentication error, no memory space available"))); + + iccIoResult = new IccIoResult(0x98, 0x67, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "authentication error, no memory space available in EF_MUK"))); + } + + @Test + public void check0x61_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x61, 0x20, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains("more response bytes available"))); + } + + @Test + public void check0x62_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x62, 0x00, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("no information given"))); + + iccIoResult = new IccIoResult(0x62, 0x81, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains( + "part of returned data may be corrupted"))); + + iccIoResult = new IccIoResult(0x62, 0x82, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "end of file/record reached before reading Le bytes"))); + + iccIoResult = new IccIoResult(0x62, 0x83, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("selected file invalidated"))); + + iccIoResult = new IccIoResult(0x62, 0x84, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains("selected file in termination state"))); + + iccIoResult = new IccIoResult(0x62, 0xF1, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("more data available"))); + + iccIoResult = new IccIoResult(0x62, 0xF2, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "more data available and proactive command pending"))); + + iccIoResult = new IccIoResult(0x62, 0xF3, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("response data available"))); + + iccIoResult = new IccIoResult(0x62, 0xF4, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("unknown"))); + } + + @Test + public void check0x63_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x63, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains( + "command successful but after using an internal update retry routine 0 " + + "times"))); + + iccIoResult = new IccIoResult(0x63, 0xF1, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains("more data expected"))); + + iccIoResult = new IccIoResult(0x63, 0xF2, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains( + "more data expected and proactive command pending"))); + + iccIoResult = new IccIoResult(0x63, 0xF3, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains("unknown"))); + } + + @Test + public void check0x64_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x64, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains("unknown"))); + + iccIoResult = new IccIoResult(0x64, 0x00, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains("no information given"))); + } + + @Test + public void check0x65_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x65, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("unknown"))); + + iccIoResult = new IccIoResult(0x65, 0x00, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue((resultStr != null) && (resultStr.contains( + "no information given, state of non-volatile memory changed"))); + + iccIoResult = new IccIoResult(0x65, 0x81, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("memory problem"))); + } + + @Test + public void check0x67_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x67, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "the interpretation of this status word is command dependent"))); + + iccIoResult = new IccIoResult(0x67, 0x00, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "incorrect parameter P3"))); + } + + @Test + public void check0x68_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x68, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("unknown"))); + + iccIoResult = new IccIoResult(0x68, 0x00, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("no information given"))); + + iccIoResult = new IccIoResult(0x68, 0x81, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("logical channel not supported"))); + + iccIoResult = new IccIoResult(0x68, 0x82, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("secure messaging not supported"))); + } + + @Test + public void check0x69_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x69, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("unknown"))); + + iccIoResult = new IccIoResult(0x69, 0x00, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("no information given"))); + + iccIoResult = new IccIoResult(0x69, 0x81, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains( + "command incompatible with file structure"))); + + iccIoResult = new IccIoResult(0x69, 0x82, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("security status not satisfied"))); + + iccIoResult = new IccIoResult(0x69, 0x83, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("authentication/PIN method blocked"))); + + iccIoResult = new IccIoResult(0x69, 0x84, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("referenced data invalidated"))); + + iccIoResult = new IccIoResult(0x69, 0x85, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("conditions of use not satisfied"))); + + iccIoResult = new IccIoResult(0x69, 0x86, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue((resultStr != null) && (resultStr.contains( + "command not allowed (no EF selected)"))); + + iccIoResult = new IccIoResult(0x69, 0x89, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue((resultStr != null) && (resultStr.contains( + "command not allowed - secure channel - security not satisfied"))); + } + + @Test + public void check0x6A_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x6A, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("unknown"))); + + iccIoResult = new IccIoResult(0x6A, 0x80, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "incorrect parameters in the data field"))); + + iccIoResult = new IccIoResult(0x6A, 0x81, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("function not supported"))); + + iccIoResult = new IccIoResult(0x6A, 0x82, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("file not found"))); + + iccIoResult = new IccIoResult(0x6A, 0x83, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("record not found"))); + + iccIoResult = new IccIoResult(0x6A, 0x84, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("not enough memory space"))); + + iccIoResult = new IccIoResult(0x6A, 0x86, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue( + (resultStr != null) && (resultStr.contains("incorrect parameters P1 to P2"))); + + iccIoResult = new IccIoResult(0x6A, 0x87, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue((resultStr != null) && (resultStr.contains( + "lc inconsistent with P1 to P2"))); + + iccIoResult = new IccIoResult(0x6A, 0x88, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue((resultStr != null) && (resultStr.contains( + "referenced data not found"))); + } + + @Test + public void check0x6B_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x6B, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue( + resultStr != null && (resultStr.contains("incorrect parameter P1 or P2"))); + } + + @Test + public void check0x6C_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x6C, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains("wrong length, retry with "))); + } + + @Test + public void check0x6D_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x6D, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "unknown instruction code given in the command"))); + } + + @Test + public void check0x6E_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x6E, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "wrong instruction class given in the command"))); + } + + @Test + public void check0x6F_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x6F, 0xC0, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "the interpretation of this status word is command dependent"))); + + iccIoResult = new IccIoResult(0x6F, 0x00, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "technical problem with no diagnostic given"))); + } + + @Test + public void check0x92_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x92, 0x00, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "command successful but after using an internal update retry routine"))); + + iccIoResult = new IccIoResult(0x92, 0x40, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "memory problem"))); + + iccIoResult = new IccIoResult(0x92, 0x41, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "unknown"))); + } + + @Test + public void check0x93_ErrorCodeParsing() { + IccIoResult iccIoResult = new IccIoResult(0x93, 0x00, new byte[10]); + String resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "SIM Application Toolkit is busy. Command cannot be executed" + + " at present, further normal commands are allowed"))); + + iccIoResult = new IccIoResult(0x93, 0x41, new byte[10]); + resultStr = iccIoResult.toString(); + Assert.assertTrue(resultStr != null && (resultStr.contains( + "unknown"))); + } +} -- GitLab From 16c293a1d499b751635bca30177b222ee4b6f03c Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Sun, 11 Sep 2022 17:36:28 +0000 Subject: [PATCH 154/656] UT for AdnRecordCache file Bug: 244637886 Test: Atest Verification done Change-Id: Id2b8aa7ee512530f9bdcf7599ffc9be427994162 --- .../telephony/uicc/AdnRecordCache.java | 35 +- .../telephony/uicc/AdnRecordCacheTest.java | 340 ++++++++++++++++++ 2 files changed, 366 insertions(+), 9 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/uicc/AdnRecordCacheTest.java diff --git a/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java b/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java index ba06c5d46c..90c94914f8 100644 --- a/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java +++ b/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java @@ -23,6 +23,7 @@ import android.os.Handler; import android.os.Message; import android.util.SparseArray; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.gsm.UsimPhoneBookManager; import java.util.ArrayList; @@ -59,14 +60,16 @@ public class AdnRecordCache extends Handler implements IccConstants { static final int EVENT_UPDATE_ADN_DONE = 2; //***** Constructor - - - AdnRecordCache(IccFileHandler fh) { mFh = fh; mUsimPhoneBookManager = new UsimPhoneBookManager(mFh, this); } + public AdnRecordCache(IccFileHandler fh, UsimPhoneBookManager usimPhoneBookManager) { + mFh = fh; + mUsimPhoneBookManager = usimPhoneBookManager; + } + //***** Called from SIMRecords /** @@ -191,7 +194,6 @@ public class AdnRecordCache extends Handler implements IccConstants { */ public void updateAdnBySearch(int efid, AdnRecord oldAdn, AdnRecord newAdn, String pin2, Message response) { - int extensionEF; extensionEF = extensionEfForEf(efid); @@ -200,7 +202,6 @@ public class AdnRecordCache extends Handler implements IccConstants { Integer.toHexString(efid).toUpperCase(Locale.ROOT)); return; } - ArrayList oldAdnList; if (efid == EF_PBR) { @@ -208,13 +209,11 @@ public class AdnRecordCache extends Handler implements IccConstants { } else { oldAdnList = getRecordsIfLoaded(efid); } - if (oldAdnList == null) { sendErrorResponse(response, "Adn list not exist for EF:0x" + Integer.toHexString(efid).toUpperCase(Locale.ROOT)); return; } - int index = -1; int count = 1; for (Iterator it = oldAdnList.iterator(); it.hasNext(); ) { @@ -224,7 +223,6 @@ public class AdnRecordCache extends Handler implements IccConstants { } count++; } - if (index == -1) { sendErrorResponse(response, "Adn record don't exist for " + oldAdn); return; @@ -343,7 +341,6 @@ public class AdnRecordCache extends Handler implements IccConstants { handleMessage(Message msg) { AsyncResult ar; int efid; - switch(msg.what) { case EVENT_LOAD_ALL_ADN_LIKE_DONE: /* arg1 is efid, obj.result is ArrayList*/ @@ -382,4 +379,24 @@ public class AdnRecordCache extends Handler implements IccConstants { break; } } + + @VisibleForTesting + protected void setAdnLikeWriters(int key, ArrayList waiters) { + mAdnLikeWaiters.put(EF_MBDN, waiters); + } + + @VisibleForTesting + protected void setAdnLikeFiles(int key, ArrayList adnRecordList) { + mAdnLikeFiles.put(EF_MBDN, adnRecordList); + } + + @VisibleForTesting + protected void setUserWriteResponse(int key, Message message) { + mUserWriteResponse.put(EF_MBDN, message); + } + + @VisibleForTesting + protected UsimPhoneBookManager getUsimPhoneBookManager() { + return mUsimPhoneBookManager; + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/AdnRecordCacheTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/AdnRecordCacheTest.java new file mode 100644 index 0000000000..c040b9e9a1 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/AdnRecordCacheTest.java @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2022 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.uicc; + +import static com.android.internal.telephony.uicc.IccConstants.EF_ADN; +import static com.android.internal.telephony.uicc.IccConstants.EF_MBDN; +import static com.android.internal.telephony.uicc.IccConstants.EF_PBR; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.test.TestLooper; + +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.gsm.UsimPhoneBookManager; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; + +public class AdnRecordCacheTest extends TelephonyTest { + + private AdnRecordCacheUT mAdnRecordCache; + private TestLooper mTestLooper; + private Handler mTestHandler; + private IccFileHandler mFhMock; + private UsimPhoneBookManager mUsimPhoneBookManager; + + @SuppressWarnings("ClassCanBeStatic") + private class AdnRecordCacheUT extends AdnRecordCache { + AdnRecordCacheUT(IccFileHandler fh, UsimPhoneBookManager usimPhoneBookManager) { + super(fh, usimPhoneBookManager); + } + + protected void setAdnLikeWriters(int key, ArrayList waiters) { + super.setAdnLikeWriters(key, waiters); + } + + protected void setAdnLikeFiles(int key, ArrayList adnRecordList) { + super.setAdnLikeFiles(key, adnRecordList); + } + + protected void setUserWriteResponse(int key, Message message) { + super.setUserWriteResponse(key, message); + } + + protected UsimPhoneBookManager getUsimPhoneBookManager() { + return super.getUsimPhoneBookManager(); + } + } + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + // Mocked classes + mFhMock = mock(IccFileHandler.class); + mUsimPhoneBookManager = mock(UsimPhoneBookManager.class); + mTestLooper = new TestLooper(); + mTestHandler = new Handler(mTestLooper.getLooper()); + mTestHandler.post( + () -> mAdnRecordCache = new AdnRecordCacheUT(mFhMock, mUsimPhoneBookManager)); + mTestLooper.dispatchAll(); + } + + @After + public void tearDown() throws Exception { + if (mTestLooper != null) { + mTestLooper.dispatchAll(); + mTestLooper = null; + } + mTestHandler.removeCallbacksAndMessages(null); + mTestHandler = null; + mAdnRecordCache = null; + super.tearDown(); + } + + @Test + public void resetTest() { + Message message1 = Message.obtain(mTestHandler); + Message message2 = Message.obtain(mTestHandler); + + // test data to create mAdnLikeWaiters + ArrayList waiters = new ArrayList<>(); + waiters.add(message1); + mAdnRecordCache.setAdnLikeWriters(EF_MBDN, waiters); + + // test data to create mAdnLikeFiles + setAdnLikeFiles(EF_MBDN); + + // test data to create mUserWriteResponse + mAdnRecordCache.setUserWriteResponse(EF_MBDN, message2); + + mAdnRecordCache.reset(); + + mTestLooper.dispatchAll(); + AsyncResult ar1 = (AsyncResult) message1.obj; + AsyncResult ar2 = (AsyncResult) message2.obj; + Assert.assertTrue(ar1.exception.toString().contains("AdnCache reset")); + Assert.assertTrue(ar2.exception.toString().contains("AdnCace reset")); + } + + @Test + public void updateAdnByIndexEfException() { + int efId = 0x6FC5; + Message message = Message.obtain(mTestHandler); + mAdnRecordCache.updateAdnByIndex(efId, null, 0, null, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + Assert.assertNotNull(ar.exception); + assertTrue((ar.exception.toString().contains("EF is not known ADN-like EF:0x6FC5"))); + } + + @Test + public void updateAdnByIndex_WriteResponseException() { + int efId = EF_MBDN; + Message message = Message.obtain(mTestHandler); + Message message2 = Message.obtain(mTestHandler); + AdnRecord adnRecord = new AdnRecord("AlphaTag", "123456789"); + // test data to create mUserWriteResponse + mAdnRecordCache.setUserWriteResponse(efId, message2); + mAdnRecordCache.updateAdnByIndex(efId, adnRecord, 0, null, message); + + AsyncResult ar = (AsyncResult) message.obj; + Assert.assertNotNull(ar.exception); + assertTrue((ar.exception.toString().contains("Have pending update for EF:0x6FC7"))); + } + + @Test + public void updateAdnByIndex() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, "success2", null); + response.sendToTarget(); + return response; + }) + .when(mFhMock) + .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + Assert.assertNotNull(message); + AdnRecord adnRecord = new AdnRecord("AlphaTag", "123456789"); + // test data to create mUserWriteResponse + mAdnRecordCache.updateAdnByIndex(EF_MBDN, adnRecord, 0, null, message); + mTestLooper.startAutoDispatch(); + verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + } + + @Test + public void updateAdnBySearch_EfException() { + int efId = 0x6FC5; + Message message = Message.obtain(mTestHandler); + mAdnRecordCache.updateAdnBySearch(efId, null, null, null, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + Assert.assertNotNull(ar.exception); + assertTrue((ar.exception.toString().contains("EF is not known ADN-like EF:0x6FC5"))); + } + + @Test + public void updateAdnBySearch_Exception() { + Message message = Message.obtain(mTestHandler); + mAdnRecordCache.updateAdnBySearch(EF_MBDN, null, null, null, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + Assert.assertNotNull(ar.exception); + assertTrue((ar.exception.toString().contains("Adn list not exist for EF:0x6FC7"))); + } + + @Test + public void updateAdnBySearch_AdnListError() { + int efId = EF_MBDN; + setAdnLikeFiles(efId); + Message message = Message.obtain(mTestHandler); + AdnRecord oldAdn = new AdnRecord("oldAlphaTag", "123456789"); + mAdnRecordCache.updateAdnBySearch(efId, oldAdn, null, null, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + Assert.assertNotNull(ar.exception); + assertTrue((ar.exception.toString().contains( + "Adn record don't exist for ADN Record 'oldAlphaTag'"))); + } + + @Test + public void updateAdnBySearch_PendingUpdate() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, "success2", null); + response.sendToTarget(); + return response; + }) + .when(mFhMock) + .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + int efId = EF_MBDN; + setAdnLikeFiles(efId); + Message message = Message.obtain(mTestHandler); + AdnRecord oldAdn = new AdnRecord("AlphaTag", "123456789"); + mAdnRecordCache.updateAdnBySearch(efId, oldAdn, null, null, message); + mTestLooper.dispatchAll(); + + verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + } + + @Test + public void updateAdnBySearch() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, "success", null); + response.sendToTarget(); + return response; + }) + .when(mFhMock) + .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + int efId = EF_MBDN; + setAdnLikeFiles(efId); + Message message = Message.obtain(mTestHandler); + AdnRecord oldAdn = new AdnRecord("AlphaTag", "123456789"); + mAdnRecordCache.updateAdnBySearch(efId, oldAdn, null, null, message); + mTestLooper.dispatchAll(); + + verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + } + + + @Test + public void updateAdnBySearch_AdnException() { + doReturn(null).when(mUsimPhoneBookManager).loadEfFilesFromUsim(); + Message message = Message.obtain(mTestHandler); + AdnRecord oldAdn = new AdnRecord("oldAlphaTag", "123456789"); + mAdnRecordCache.updateAdnBySearch(EF_PBR, oldAdn, null, null, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + Assert.assertNotNull(ar.exception); + assertTrue((ar.exception.toString().contains("Adn list not exist for EF:0x4F30"))); + } + + @Test + public void requestLoadAllAdnLike_AlreadyLoadedEf() { + int efId = EF_MBDN; + setAdnLikeFiles(efId); + Message message = Message.obtain(mTestHandler); + mAdnRecordCache.requestLoadAllAdnLike(efId, 0, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + Assert.assertNull(ar.exception); + Assert.assertNotNull(ar.result); + } + + @Test + public void requestLoadAllAdnLike_AlreadyLoadingEf() { + int efId = EF_MBDN; + // test data to create mAdnLikeWaiters + Message message = Message.obtain(mTestHandler); + ArrayList waiters = new ArrayList<>(); + waiters.add(message); + mAdnRecordCache.setAdnLikeWriters(efId, waiters); + mAdnRecordCache.requestLoadAllAdnLike(efId, 0, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + Assert.assertNull(ar); + } + + @Test + public void requestLoadAllAdnLike_NotKnownEf() { + Message message = Message.obtain(mTestHandler); + mAdnRecordCache.requestLoadAllAdnLike(EF_MBDN, -1, message); + mTestLooper.dispatchAll(); + + AsyncResult ar = (AsyncResult) message.obj; + Assert.assertTrue(ar.exception.toString().contains("EF is not known ADN-like EF:0x")); + } + + @Test + public void requestLoadAllAdnLike() { + doAnswer( + invocation -> { + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, null, new CommandException( + CommandException.Error.REQUEST_NOT_SUPPORTED)); + response.sendToTarget(); + return response; + }) + .when(mFhMock) + .loadEFLinearFixedAll(anyInt(), anyString(), any(Message.class)); + + Message message = Message.obtain(mTestHandler); + mAdnRecordCache.requestLoadAllAdnLike(EF_ADN, 0x6FC8, message); + mTestLooper.dispatchAll(); + + verify(mFhMock, times(1)).loadEFLinearFixedAll(anyInt(), anyString(), any(Message.class)); + } + + private void setAdnLikeFiles(int ef) { + // test data to create mAdnLikeFiles + ArrayList adnRecordList = new ArrayList<>(); + AdnRecord adnRecord = new AdnRecord("AlphaTag", "123456789"); + adnRecordList.add(adnRecord); + mAdnRecordCache.setAdnLikeFiles(ef, adnRecordList); + } +} \ No newline at end of file -- GitLab From 0c22cfac19f08750628255d5285911d3570cfa2e Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Wed, 2 Nov 2022 00:06:57 -0700 Subject: [PATCH 155/656] Delay Auto data switch check to allow data reg state to propagate To prevent the race condition of data registration state, send an event to allow data reg state to be processed by datanetworkcontroller Bug: 244064524 Test: manual toggle APM + toggle WIFI Change-Id: I81fcee3c65b72729fadf4216afc5365c464d4abd --- .../internal/telephony/data/PhoneSwitcher.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index e6d0e1cc79..0dda836dac 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -406,7 +406,9 @@ public class PhoneSwitcher extends Handler { @Override public void onLost(Network network) { // try find an active sub to switch to - scheduleAutoSwitchEvaluation(); + if (!hasMessages(EVENT_EVALUATE_AUTO_SWITCH)) { + sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); + } } } @@ -1100,7 +1102,9 @@ public class PhoneSwitcher extends Handler { mPhoneStates[phoneId].dataRegState = newRegState; logl("onServiceStateChanged:phoneId:" + phoneId + " dataReg-> " + NetworkRegistrationInfo.registrationStateToString(newRegState)); - evaluateIfAutoSwitchIsNeeded(); + if (!hasMessages(EVENT_EVALUATE_AUTO_SWITCH)) { + sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); + } } } } @@ -1111,6 +1115,7 @@ public class PhoneSwitcher extends Handler { private void evaluateIfAutoSwitchIsNeeded() { // auto data switch feature is disabled from server if (mAutoDataSwitchAvailabilityStabilityTimeThreshold < 0) return; + // check is valid DSDS if (!mSubscriptionController.isActiveSubId(mPrimaryDataSubId) || mSubscriptionController.getActiveSubIdList(true).length <= 1) { return; @@ -1718,7 +1723,7 @@ public class PhoneSwitcher extends Handler { */ private void validate(int subId, boolean needValidation, int switchReason, @Nullable ISetOpportunisticDataCallback callback) { - logl("Validate " + subId + " due to " + switchReasonToString(switchReason) + logl("Validate subId " + subId + " due to " + switchReasonToString(switchReason) + " needValidation=" + needValidation); int subIdToValidate = (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) ? mPrimaryDataSubId : subId; @@ -1827,7 +1832,7 @@ public class PhoneSwitcher extends Handler { // retry for auto data switch validation failure if (mLastAutoSelectedSwitchReason == DataSwitch.Reason.DATA_SWITCH_REASON_AUTO) { - scheduleAutoSwitchEvaluation(); + scheduleAutoSwitchRetryEvaluation(); mAutoSwitchRetryFailedCount++; } } else { @@ -1849,7 +1854,7 @@ public class PhoneSwitcher extends Handler { /** * Schedule auto data switch evaluation retry if haven't reached the max retry count. */ - private void scheduleAutoSwitchEvaluation() { + private void scheduleAutoSwitchRetryEvaluation() { if (mAutoSwitchRetryFailedCount < mAutoDataSwitchValidationMaxRetry) { if (!hasMessages(EVENT_EVALUATE_AUTO_SWITCH)) { sendMessageDelayed(obtainMessage(EVENT_EVALUATE_AUTO_SWITCH), -- GitLab From 6fe8b2a516b8425d2a0a3e281586f1bb64474c9e Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Wed, 26 Oct 2022 15:56:54 -0700 Subject: [PATCH 156/656] Add metrics field to track auto data switch toggle Bug: 255838492 Test: manual checked log Change-Id: If618dd639b7c48ba24135673202d233fabf0e271 --- proto/src/persist_atoms.proto | 3 ++ .../telephony/data/DataSettingsManager.java | 13 ++++++++ .../DeviceTelephonyPropertiesStats.java | 32 +++++++++++++++++++ .../telephony/metrics/MetricsCollector.java | 17 ++++++++-- .../metrics/PersistAtomsStorage.java | 20 +++++++++++- 5 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 src/java/com/android/internal/telephony/metrics/DeviceTelephonyPropertiesStats.java diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index a4fb816bd2..26427c89b4 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -186,6 +186,9 @@ message PersistAtoms { /* Timestamp of last outgoing_short_code_sms pull. */ optional int64 outgoing_short_code_sms_pull_timestamp_millis = 54; + + /* Number of time the user toggled the data switch feature since the last collection. */ + optional int32 auto_data_switch_toggle_count = 55; } // The canonical versions of the following enums live in: diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index f710266261..15743d77d6 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -49,6 +49,7 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SettingsObserver; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback; +import com.android.internal.telephony.metrics.DeviceTelephonyPropertiesStats; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -610,6 +611,8 @@ public class DataSettingsManager extends Handler { if (enable == isMobileDataPolicyEnabled(mobileDataPolicy)) { return; } + metricsRecordSetMobileDataPolicy(mobileDataPolicy); + if (enable) { mEnabledMobileDataPolicy.add(mobileDataPolicy); } else { @@ -629,6 +632,16 @@ public class DataSettingsManager extends Handler { } } + /** + * Record the number of times a mobile data policy is toggled to metrics. + * @param mobileDataPolicy The mobile data policy that's toggled + */ + private void metricsRecordSetMobileDataPolicy(@MobileDataPolicy int mobileDataPolicy) { + if (mobileDataPolicy == TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH) { + DeviceTelephonyPropertiesStats.recordAutoDataSwitchFeatureToggle(); + } + } + /** * Check whether data stall recovery on bad network is enabled. * @return {@code true} if data stall recovery is enabled and {@code false} otherwise. diff --git a/src/java/com/android/internal/telephony/metrics/DeviceTelephonyPropertiesStats.java b/src/java/com/android/internal/telephony/metrics/DeviceTelephonyPropertiesStats.java new file mode 100644 index 0000000000..51fe20c0de --- /dev/null +++ b/src/java/com/android/internal/telephony/metrics/DeviceTelephonyPropertiesStats.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 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 com.android.internal.telephony.PhoneFactory; + +/** Metrics for the telephony related properties on the device. */ +public class DeviceTelephonyPropertiesStats { + private static final String TAG = DeviceTelephonyPropertiesStats.class.getSimpleName(); + + /** + * Record whenever the auto data switch feature is toggled. + */ + public static void recordAutoDataSwitchFeatureToggle() { + PersistAtomsStorage storage = PhoneFactory.getMetricsCollector().getAtomsStorage(); + storage.recordToggledAutoDataSwitch(); + } +} diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index e915e4c226..be698c16b4 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -50,6 +50,8 @@ import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSIO import android.annotation.Nullable; import android.app.StatsManager; import android.content.Context; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.util.StatsEvent; import com.android.internal.annotations.VisibleForTesting; @@ -482,13 +484,22 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } } - private static int pullDeviceTelephonyProperties(List data) { + private int pullDeviceTelephonyProperties(List data) { Phone[] phones = getPhonesIfAny(); if (phones.length == 0) { return StatsManager.PULL_SKIP; } - - data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, true)); + boolean isAutoDataSwitchOn = false; + for (Phone phone : phones) { + // only applies to non-DDS + if (phone.getSubId() != SubscriptionManager.getDefaultDataSubscriptionId()) { + isAutoDataSwitchOn = phone.getDataSettingsManager().isMobileDataPolicyEnabled( + TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH); + break; + } + } + data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, true, + isAutoDataSwitchOn, mStorage.getAutoDataSwitchToggleCount())); return StatsManager.PULL_SUCCESS; } diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java index e1b575f709..d1a60e8122 100644 --- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java +++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java @@ -42,8 +42,8 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationStat import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination; import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms; import com.android.internal.telephony.nano.PersistAtomsProto.NetworkRequestsV2; -import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms; +import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; import com.android.internal.telephony.nano.PersistAtomsProto.PersistAtoms; import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent; import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats; @@ -438,6 +438,14 @@ public class PersistAtomsStorage { } } + /** + * Store the number of times auto data switch feature is toggled. + */ + public synchronized void recordToggledAutoDataSwitch() { + mAtoms.autoDataSwitchToggleCount++; + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS); + } + /** Adds a new {@link NetworkRequestsV2} to the storage. */ public synchronized void addNetworkRequestsV2(NetworkRequestsV2 networkRequests) { NetworkRequestsV2 existingMetrics = find(networkRequests); @@ -884,6 +892,16 @@ public class PersistAtomsStorage { } } + /** @return the number of times auto data switch mobile data policy is toggled. */ + public synchronized int getAutoDataSwitchToggleCount() { + int count = mAtoms.autoDataSwitchToggleCount; + if (count > 0) { + mAtoms.autoDataSwitchToggleCount = 0; + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS); + } + return count; + } + /** * Returns and clears the ImsRegistrationFeatureTagStats if last pulled longer than * {@code minIntervalMillis} ago, otherwise returns {@code null}. -- GitLab From f30be7ee1e357496f4b237b3d15087e01cad76e9 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 11 Oct 2022 19:29:24 -0700 Subject: [PATCH 157/656] Add metrics for AutoDataSwitch Add DataCallSessionStats.is_non_dds and DataStallRecoveryReported.other_phone_signal_strength to track the effectiveness of auto data switch feature. AMD: https://eldar.corp.google.com/assessments/296451350/drafts/795146072?jsmode=o#sections/999001 PDD: https://eldar.corp.google.com/assessments/653114600/drafts/771765910?jsmode=o#sections/55001 Bug: 253081968 Test: pull and check DataCallSessionStats.is_non_dds on local device + basic data browsing + phone call Change-Id: If8342b9150d56546c85c1a9ad255f4d17c5c04bc --- proto/src/persist_atoms.proto | 3 ++- .../metrics/DataCallSessionStats.java | 14 ++++++++++ .../metrics/DataStallRecoveryStats.java | 27 ++++++++++++++++++- .../telephony/metrics/MetricsCollector.java | 3 ++- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index a4fb816bd2..dd99603a6a 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -313,6 +313,7 @@ message DataCallSession { optional int32 band_at_end = 19; repeated int32 handover_failure_causes = 20; repeated int32 handover_failure_rat = 21; + optional bool is_non_dds = 22; } message CellularServiceState { @@ -530,4 +531,4 @@ message OutgoingShortCodeSms { optional int32 category = 1; optional int32 xml_version = 2; optional int32 short_code_sms_count = 3; -} \ No newline at end of file +} diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java index bfa081becc..cdade427bc 100644 --- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java @@ -29,7 +29,9 @@ import android.telephony.Annotation.DataFailureCause; import android.telephony.Annotation.NetworkType; import android.telephony.DataFailCause; import android.telephony.ServiceState; +import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; +import android.telephony.data.ApnSetting; import android.telephony.data.ApnSetting.ProtocolType; import android.telephony.data.DataCallResponse; import android.telephony.data.DataService; @@ -257,6 +259,16 @@ public class DataCallSessionStats { private void endDataCallSession() { mDataCallSession.oosAtEnd = getIsOos(); mDataCallSession.ongoing = false; + // set if this data call is established for internet on the non-Dds + SubscriptionInfo subInfo = SubscriptionController.getInstance() + .getSubscriptionInfo(mPhone.getSubId()); + if (mPhone.getSubId() != SubscriptionController.getInstance().getDefaultDataSubId() + && ((mDataCallSession.apnTypeBitmask & ApnSetting.TYPE_DEFAULT) + == ApnSetting.TYPE_DEFAULT) + && subInfo != null && !subInfo.isOpportunistic()) { + mDataCallSession.isNonDds = true; + } + // store for the data call list event, after DataCall is disconnected and entered into // inactive mode PhoneFactory.getMetricsCollector().unregisterOngoingDataCallStat(this); @@ -292,6 +304,7 @@ public class DataCallSessionStats { call.handoverFailureCauses.length); copy.handoverFailureRat = Arrays.copyOf(call.handoverFailureRat, call.handoverFailureRat.length); + copy.isNonDds = call.isNonDds; return copy; } @@ -316,6 +329,7 @@ public class DataCallSessionStats { proto.ongoing = true; proto.handoverFailureCauses = new int[0]; proto.handoverFailureRat = new int[0]; + proto.isNonDds = false; return proto; } diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java index 77e758b6d9..ee4e842233 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -16,12 +16,16 @@ package com.android.internal.telephony.metrics; +import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.NetworkType; +import android.telephony.CellSignalStrength; +import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyStatsLog; @@ -74,6 +78,25 @@ public class DataStallRecoveryStats { recoveryAction = RECOVERY_ACTION_RESET_MODEM_MAPPING; } + // collect info of the other device in case of DSDS + int otherSignalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; + // the number returned here matches the NetworkRegistrationState enum we have + int otherNetworkRegState = NetworkRegistrationInfo + .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; + for (Phone otherPhone : PhoneFactory.getPhones()) { + if (otherPhone.getPhoneId() == phone.getPhoneId()) continue; + if (!getIsOpportunistic(otherPhone)) { + otherSignalStrength = otherPhone.getSignalStrength().getLevel(); + NetworkRegistrationInfo regInfo = otherPhone.getServiceState() + .getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (regInfo != null) { + otherNetworkRegState = regInfo.getRegistrationState(); + } + break; + } + } + TelephonyStatsLog.write( TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, carrierId, @@ -85,7 +108,9 @@ public class DataStallRecoveryStats { band, isRecovered, durationMillis, - reason); + reason, + otherSignalStrength, + otherNetworkRegState); } /** Returns the RAT used for data (including IWLAN). */ diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index e915e4c226..b38b4b7937 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -858,7 +858,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { dataCallSession.ongoing, dataCallSession.bandAtEnd, dataCallSession.handoverFailureCauses, - dataCallSession.handoverFailureRat); + dataCallSession.handoverFailureRat, + dataCallSession.isNonDds); } private static StatsEvent buildStatsEvent(ImsRegistrationStats stats) { -- GitLab From d1fa63cf038aac3cc1992d1da78185b2e146afad Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 8 Feb 2022 06:29:07 +0000 Subject: [PATCH 158/656] Sync IMS call info with modem for SRVCC Bug: 217654931 Test: atest ImsPhoneCallTrackerTest Change-Id: If78ba30c12b1bbf4ad27c3c3815729bddb5a3b50 (cherry picked from commit 6f13d9cb6d5a5b7c2868268588660aa91fe2a50e) --- .../com/android/internal/telephony/Phone.java | 15 +- .../internal/telephony/SrvccConnection.java | 91 ++++- .../internal/telephony/imsphone/ImsPhone.java | 2 +- .../imsphone/ImsPhoneCallTracker.java | 188 ++++++++- .../internal/telephony/SimulatedCommands.java | 11 + .../imsphone/ImsPhoneCallTrackerTest.java | 360 +++++++++++++++++- 6 files changed, 634 insertions(+), 33 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 396fdfe292..e4502eac65 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -40,6 +40,7 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telecom.VideoProfile; import android.telephony.AccessNetworkConstants; +import android.telephony.Annotation.SrvccState; import android.telephony.CarrierConfigManager; import android.telephony.CarrierRestrictionRules; import android.telephony.CellIdentity; @@ -852,7 +853,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } - public void notifySrvccState(Call.SrvccState state) { + /** + * Notifies the change of the SRVCC state. + * @param state the new SRVCC state. + */ + public void notifySrvccState(@SrvccState int state) { } public void registerForSilentRedial(Handler h, int what, Object obj) { @@ -875,6 +880,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { Call.SrvccState srvccState = Call.SrvccState.NONE; if (ret != null && ret.length != 0) { int state = ret[0]; + if (imsPhone != null) { + imsPhone.notifySrvccState(state); + } switch(state) { case TelephonyManager.SRVCC_STATE_HANDOVER_STARTED: srvccState = Call.SrvccState.STARTED; @@ -887,11 +895,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { break; case TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED: srvccState = Call.SrvccState.COMPLETED; - if (imsPhone != null) { - imsPhone.notifySrvccState(srvccState); - } else { - Rlog.d(LOG_TAG, "HANDOVER_COMPLETED: mImsPhone null"); - } break; case TelephonyManager.SRVCC_STATE_HANDOVER_FAILED: case TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED: diff --git a/src/java/com/android/internal/telephony/SrvccConnection.java b/src/java/com/android/internal/telephony/SrvccConnection.java index 57b827002b..0ce40d88dc 100644 --- a/src/java/com/android/internal/telephony/SrvccConnection.java +++ b/src/java/com/android/internal/telephony/SrvccConnection.java @@ -16,6 +16,20 @@ package com.android.internal.telephony; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_ACTIVE; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_ALERTING; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_DIALING; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_HOLDING; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_INCOMING; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_INCOMING_SETUP; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_WAITING; + +import android.telephony.Annotation.PreciseCallStates; +import android.telephony.ims.ImsCallProfile; +import android.telephony.ims.ImsStreamMediaProfile; + +import com.android.internal.telephony.imsphone.ImsPhoneConnection; + /** * Connection information for SRVCC */ @@ -34,19 +48,19 @@ public class SrvccConnection { public static final int TONE_NETWORK = 2; /** Values are CALL_TYPE_ */ - private int mType; + private int mType = CALL_TYPE_NORMAL; /** Values are Call.State */ private Call.State mState; /** Values are SUBSTATE_ */ - private int mSubstate; + private int mSubstate = SUBSTATE_NONE; /** Values are TONE_ */ - private int mRingbackToneType; + private int mRingbackToneType = TONE_NONE; /** true if it is a multi-party call */ - private boolean mIsMpty; + private boolean mIsMpty = false; /** true if it is a mobile terminated call */ private boolean mIsMT; @@ -63,12 +77,38 @@ public class SrvccConnection { /** Values are PhoneConstants.PRESENTATION_ */ private int mNamePresentation; - public SrvccConnection(Connection c, boolean isEmergency, int ringbackToneType) { - mType = isEmergency ? CALL_TYPE_EMERGENCY : CALL_TYPE_NORMAL; - mState = c.getState(); - mSubstate = SUBSTATE_NONE; - mRingbackToneType = ringbackToneType; - mIsMpty = false; + public SrvccConnection(ImsCallProfile profile, + ImsPhoneConnection c, @PreciseCallStates int preciseCallState) { + mState = toCallState(preciseCallState); + if (mState == Call.State.ALERTING) { + mRingbackToneType = isLocalTone(profile) ? TONE_LOCAL : TONE_NETWORK; + } + if (preciseCallState == PRECISE_CALL_STATE_INCOMING_SETUP) { + mSubstate = SUBSTATE_PREALERTING; + } + + if (c == null) { + initialize(profile); + } else { + initialize(c); + } + } + + // MT call in alerting or prealerting state + private void initialize(ImsCallProfile profile) { + mIsMT = true; + mNumber = profile.getCallExtra(ImsCallProfile.EXTRA_OI); + mName = profile.getCallExtra(ImsCallProfile.EXTRA_CNA); + mNumPresentation = ImsCallProfile.OIRToPresentation( + profile.getCallExtraInt(ImsCallProfile.EXTRA_OIR)); + mNamePresentation = ImsCallProfile.OIRToPresentation( + profile.getCallExtraInt(ImsCallProfile.EXTRA_CNAP)); + } + + private void initialize(ImsPhoneConnection c) { + if (c.isEmergencyCall()) { + mType = CALL_TYPE_EMERGENCY; + } mIsMT = c.isIncoming(); mNumber = c.getAddress(); mNumPresentation = c.getNumberPresentation(); @@ -76,6 +116,32 @@ public class SrvccConnection { mNamePresentation = c.getCnapNamePresentation(); } + private boolean isLocalTone(ImsCallProfile profile) { + if (profile == null) return false; + + ImsStreamMediaProfile mediaProfile = profile.getMediaProfile(); + if (mediaProfile == null) return false; + + boolean shouldPlayRingback = + (mediaProfile.getAudioDirection() == ImsStreamMediaProfile.DIRECTION_INACTIVE) + ? true : false; + return shouldPlayRingback; + } + + private static Call.State toCallState(int preciseCallState) { + switch (preciseCallState) { + case PRECISE_CALL_STATE_ACTIVE: return Call.State.ACTIVE; + case PRECISE_CALL_STATE_HOLDING: return Call.State.HOLDING; + case PRECISE_CALL_STATE_DIALING: return Call.State.DIALING; + case PRECISE_CALL_STATE_ALERTING: return Call.State.ALERTING; + case PRECISE_CALL_STATE_INCOMING: return Call.State.INCOMING; + case PRECISE_CALL_STATE_WAITING: return Call.State.WAITING; + case PRECISE_CALL_STATE_INCOMING_SETUP: return Call.State.INCOMING; + default: + } + return Call.State.DISCONNECTED; + } + /** Returns the type of the call */ public int getType() { return mType; @@ -86,6 +152,11 @@ public class SrvccConnection { return mState; } + /** Updates the state */ + public void setState(Call.State state) { + mState = state; + } + /** Returns the sub state */ public int getSubState() { return mSubstate; diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index f47f8374c9..b206b861bd 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -1583,7 +1583,7 @@ public class ImsPhone extends ImsPhoneBase { } @Override - public void notifySrvccState(Call.SrvccState state) { + public void notifySrvccState(int state) { mCT.notifySrvccState(state); } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 61ec28e165..748f081e01 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -16,8 +16,19 @@ package com.android.internal.telephony.imsphone; +import static android.telephony.CarrierConfigManager.ImsVoice.ALERTING_SRVCC_SUPPORT; +import static android.telephony.CarrierConfigManager.ImsVoice.BASIC_SRVCC_SUPPORT; +import static android.telephony.CarrierConfigManager.ImsVoice.MIDCALL_SRVCC_SUPPORT; +import static android.telephony.CarrierConfigManager.ImsVoice.PREALERTING_SRVCC_SUPPORT; import static android.telephony.CarrierConfigManager.USSD_OVER_CS_PREFERRED; import static android.telephony.CarrierConfigManager.USSD_OVER_IMS_ONLY; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_ACTIVE; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_ALERTING; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_DIALING; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_HOLDING; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_INCOMING; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_INCOMING_SETUP; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_WAITING; import static android.telephony.ims.ImsService.CAPABILITY_TERMINAL_BASED_CALL_WAITING; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; @@ -81,6 +92,8 @@ import android.telephony.ims.ImsSuppServiceNotification; import android.telephony.ims.ProvisioningManager; import android.telephony.ims.RtpHeaderExtension; import android.telephony.ims.RtpHeaderExtensionType; +import android.telephony.ims.SrvccCall; +import android.telephony.ims.aidl.ISrvccStartedCallback; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; @@ -118,6 +131,7 @@ import com.android.internal.telephony.LocaleTracker; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.SrvccConnection; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.d2d.RtpTransport; import com.android.internal.telephony.data.DataSettingsManager; @@ -135,6 +149,7 @@ import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -153,6 +168,7 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.regex.Pattern; +import java.util.stream.Collectors; /** * {@hide} @@ -558,6 +574,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } } + private class SrvccStartedCallback extends ISrvccStartedCallback.Stub { + @Override + public void onSrvccCallNotified(List profiles) { + handleSrvccConnectionInfo(profiles); + } + } + private volatile NetworkStats mVtDataUsageSnapshot = null; private volatile NetworkStats mVtDataUsageUidSnapshot = null; private final VtDataUsageProvider mVtDataUsageProvider = new VtDataUsageProvider(); @@ -612,6 +635,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private boolean mSupportCepOnPeer = true; private boolean mSupportD2DUsingRtp = false; private boolean mSupportSdpForRtpHeaderExtensions = false; + private final List mSrvccTypeSupported = new ArrayList<>(); + private final SrvccStartedCallback mSrvccStartedCallback = new SrvccStartedCallback(); // Tracks the state of our background/foreground calls while a call hold/swap operation is // in progress. Values listed above. private HoldSwapState mHoldSwitchingState = HoldSwapState.INACTIVE; @@ -1748,6 +1773,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } else { log("No carrier ImsReasonInfo mappings defined."); } + + mSrvccTypeSupported.clear(); + int[] srvccType = + carrierConfig.getIntArray(CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY); + if (srvccType != null && srvccType.length > 0) { + mSrvccTypeSupported.addAll( + Arrays.stream(srvccType).boxed().collect(Collectors.toList())); + } } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -4327,21 +4360,55 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { * Notify of a change to SRVCC state * @param state the new SRVCC state. */ - public void notifySrvccState(Call.SrvccState state) { + public void notifySrvccState(int state) { if (DBG) log("notifySrvccState state=" + state); - mSrvccState = state; + switch(state) { + case TelephonyManager.SRVCC_STATE_HANDOVER_STARTED: + mSrvccState = Call.SrvccState.STARTED; + break; - if (mSrvccState == Call.SrvccState.COMPLETED) { - // If the dialing call had ringback, ensure it stops now, otherwise it'll keep playing - // afer the SRVCC completes. - mForegroundCall.maybeStopRingback(); + case TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED: + mSrvccState = Call.SrvccState.COMPLETED; - resetState(); - transferHandoverConnections(mForegroundCall); - transferHandoverConnections(mBackgroundCall); - transferHandoverConnections(mRingingCall); - updatePhoneState(); + // If the dialing call had ringback, ensure it stops now, + // otherwise it'll keep playing afer the SRVCC completes. + mForegroundCall.maybeStopRingback(); + + resetState(); + transferHandoverConnections(mForegroundCall); + transferHandoverConnections(mBackgroundCall); + transferHandoverConnections(mRingingCall); + updatePhoneState(); + break; + + case TelephonyManager.SRVCC_STATE_HANDOVER_FAILED: + mSrvccState = Call.SrvccState.FAILED; + break; + + case TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED: + mSrvccState = Call.SrvccState.CANCELED; + break; + + default: + //ignore invalid state + return; + } + + if (mImsManager != null) { + try { + if (mSrvccState == Call.SrvccState.STARTED) { + mImsManager.notifySrvccStarted(mSrvccStartedCallback); + } else if (mSrvccState == Call.SrvccState.COMPLETED) { + mImsManager.notifySrvccCompleted(); + } else if (mSrvccState == Call.SrvccState.FAILED) { + mImsManager.notifySrvccFailed(); + } else if (mSrvccState == Call.SrvccState.CANCELED) { + mImsManager.notifySrvccCanceled(); + } + } catch (ImsException e) { + loge("notifySrvccState : exception " + e); + } } } @@ -4728,6 +4795,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { + mSupportSdpForRtpHeaderExtensions); } } + pw.println(" mSrvccTypeSupported=" + mSrvccTypeSupported); pw.println(" Event Log:"); pw.increaseIndent(); mOperationLocalLog.dump(pw); @@ -5533,4 +5601,102 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } } } + + /** Send the list of SrvccConnection instances to the radio */ + public void handleSrvccConnectionInfo(List profileList) { + mPhone.getDefaultPhone().mCi.setSrvccCallInfo( + convertToSrvccConnectionInfo(profileList), null); + } + + /** Converts SrvccCall to SrvccConnection. */ + @VisibleForTesting + public SrvccConnection[] convertToSrvccConnectionInfo(List profileList) { + if (mSrvccTypeSupported.isEmpty() || profileList == null || profileList.isEmpty()) { + return null; + } + + List connList = new ArrayList<>(); + for (SrvccCall profile : profileList) { + if (isCallProfileSupported(profile)) { + addConnection(connList, + profile, findConnection(profile.getCallId())); + } + } + + if (connList.isEmpty()) return null; + return connList.toArray(new SrvccConnection[0]); + } + + private boolean isCallProfileSupported(SrvccCall profile) { + if (profile == null) return false; + + switch(profile.getPreciseCallState()) { + case PRECISE_CALL_STATE_ACTIVE: + return mSrvccTypeSupported.contains(BASIC_SRVCC_SUPPORT); + case PRECISE_CALL_STATE_HOLDING: + return mSrvccTypeSupported.contains(MIDCALL_SRVCC_SUPPORT); + case PRECISE_CALL_STATE_DIALING: + return mSrvccTypeSupported.contains(PREALERTING_SRVCC_SUPPORT); + case PRECISE_CALL_STATE_ALERTING: + return mSrvccTypeSupported.contains(ALERTING_SRVCC_SUPPORT); + case PRECISE_CALL_STATE_INCOMING: + return mSrvccTypeSupported.contains(ALERTING_SRVCC_SUPPORT); + case PRECISE_CALL_STATE_WAITING: + return mSrvccTypeSupported.contains(ALERTING_SRVCC_SUPPORT); + case PRECISE_CALL_STATE_INCOMING_SETUP: + return mSrvccTypeSupported.contains(PREALERTING_SRVCC_SUPPORT); + default: + break; + } + return false; + } + + private synchronized ImsPhoneConnection findConnection(String callId) { + for (ImsPhoneConnection c : mConnections) { + ImsCall imsCall = c.getImsCall(); + if (imsCall == null) continue; + ImsCallSession session = imsCall.getCallSession(); + if (session == null) continue; + + if (TextUtils.equals(session.getCallId(), callId)) { + return c; + } + } + return null; + } + + /** + * Update the list of SrvccConnection with the given SrvccCall and ImsPhoneconnection. + * + * @param destList the list of SrvccConnection the new connection will be added + * @param profile the SrvccCall of the connection to be added + * @param c the ImsPhoneConnection of the connection to be added + */ + private static void addConnection( + List destList, SrvccCall profile, ImsPhoneConnection c) { + if (destList == null) return; + if (profile == null) return; + + int preciseCallState = profile.getPreciseCallState(); + if (!isAlive(preciseCallState)) return; + + SrvccConnection srvccConnection = + new SrvccConnection(profile.getImsCallProfile(), c, preciseCallState); + + destList.add(srvccConnection); + } + + private static boolean isAlive(int preciseCallState) { + switch (preciseCallState) { + case PRECISE_CALL_STATE_ACTIVE: return true; + case PRECISE_CALL_STATE_HOLDING: return true; + case PRECISE_CALL_STATE_DIALING: return true; + case PRECISE_CALL_STATE_ALERTING: return true; + case PRECISE_CALL_STATE_INCOMING: return true; + case PRECISE_CALL_STATE_WAITING: return true; + case PRECISE_CALL_STATE_INCOMING_SETUP: return true; + default: + } + return false; + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index 6e6d44e2a1..e9b644f8ae 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -66,6 +66,7 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.RILUtils; import com.android.internal.telephony.RadioCapability; import com.android.internal.telephony.SmsResponse; +import com.android.internal.telephony.SrvccConnection; import com.android.internal.telephony.UUSInfo; import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; @@ -187,6 +188,7 @@ public class SimulatedCommands extends BaseCommands public boolean mSetRadioPowerAsSelectedPhoneForEmergencyCall; public boolean mCallWaitActivated = false; + private SrvccConnection[] mSrvccConnections; // mode for Icc Sim Authentication private int mAuthenticationMode; @@ -2572,4 +2574,13 @@ public class SimulatedCommands extends BaseCommands PcoData response = new PcoData(cid, bearerProto, pcoId, contents); mPcoDataRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); } + + @Override + public void setSrvccCallInfo(SrvccConnection[] srvccConnections, Message result) { + mSrvccConnections = srvccConnections; + } + + public SrvccConnection[] getSrvccConnections() { + return mSrvccConnections; + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 4f1bdac9d5..853a1924da 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -21,6 +21,19 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; +import static android.telephony.CarrierConfigManager.ImsVoice.ALERTING_SRVCC_SUPPORT; +import static android.telephony.CarrierConfigManager.ImsVoice.BASIC_SRVCC_SUPPORT; +import static android.telephony.CarrierConfigManager.ImsVoice.PREALERTING_SRVCC_SUPPORT; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_ACTIVE; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_ALERTING; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_INCOMING; +import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_INCOMING_SETUP; +import static android.telephony.TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED; +import static android.telephony.TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED; +import static android.telephony.TelephonyManager.SRVCC_STATE_HANDOVER_FAILED; +import static android.telephony.TelephonyManager.SRVCC_STATE_HANDOVER_STARTED; +import static android.telephony.ims.ImsStreamMediaProfile.DIRECTION_INACTIVE; +import static android.telephony.ims.ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE; import static com.android.testutils.NetworkStatsUtilsKt.assertNetworkStatsEquals; @@ -76,6 +89,8 @@ import android.telephony.ims.ImsMmTelManager; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsStreamMediaProfile; import android.telephony.ims.RtpHeaderExtensionType; +import android.telephony.ims.SrvccCall; +import android.telephony.ims.aidl.ISrvccStartedCallback; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; @@ -98,6 +113,7 @@ import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.SrvccConnection; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.d2d.RtpTransport; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker.VtDataUsageProvider; @@ -112,6 +128,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import java.util.ArrayList; +import java.util.List; import java.util.Set; import java.util.concurrent.Executor; @@ -125,6 +143,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { private ImsCall.Listener mImsCallListener; private ImsCall mImsCall; private ImsCall mSecondImsCall; + private ISrvccStartedCallback mSrvccStartedCallback; private BroadcastReceiver mBroadcastReceiver; private Bundle mBundle = new Bundle(); private static final int SUB_0 = 0; @@ -1689,7 +1708,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { assertTrue(mCTUT.mForegroundCall.isRingbackTonePlaying()); // Move the connection to the handover state. - mCTUT.notifySrvccState(Call.SrvccState.COMPLETED); + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_COMPLETED); assertFalse(mCTUT.mForegroundCall.isRingbackTonePlaying()); } @@ -1720,7 +1739,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { } // Move the connection to the handover state. - mCTUT.notifySrvccState(Call.SrvccState.COMPLETED); + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_COMPLETED); // Ensure we are no longer tracking hold. assertFalse(mCTUT.isHoldOrSwapInProgress()); } @@ -1743,7 +1762,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { connection.addListener(mImsPhoneConnectionListener); // Move the connection to the handover state. - mCTUT.notifySrvccState(Call.SrvccState.COMPLETED); + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_COMPLETED); assertEquals(1, mCTUT.mHandoverCall.getConnections().size()); // No need to go through all the rigamarole of the mocked termination we normally do; we @@ -1781,7 +1800,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { connection.addListener(mImsPhoneConnectionListener); // Move the connection to the handover state. - mCTUT.notifySrvccState(Call.SrvccState.COMPLETED); + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_COMPLETED); assertEquals(1, mCTUT.mHandoverCall.getConnections().size()); // Make sure the tracker states it's idle. @@ -1892,7 +1911,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { startOutgoingCall(); // Move the connection to the handover state. - mCTUT.notifySrvccState(Call.SrvccState.COMPLETED); + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_COMPLETED); try { // When trigger CallSessionUpdated after Srvcc completes, checking no exception. @@ -1926,6 +1945,303 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { ImsPhoneConnection connection2 = placeCall(); } + @Test + @SmallTest + public void testConvertToSrvccConnectionInfoNotSupported() throws Exception { + // setup ImsPhoneCallTracker's mConnections + ImsPhoneConnection activeMO = getImsPhoneConnection(Call.State.ACTIVE, "1234", false); + ImsPhoneConnection heldMT = getImsPhoneConnection(Call.State.HOLDING, "5678", true); + + ArrayList connections = new ArrayList(); + replaceInstance(ImsPhoneCallTracker.class, "mConnections", mCTUT, connections); + connections.add(activeMO); + connections.add(heldMT); + + ImsCallProfile activeProfile = getImsCallProfileForSrvccSync("activeCall", activeMO, false); + ImsCallProfile heldProfile = getImsCallProfileForSrvccSync("heldCall", heldMT, false); + + // setup the response of notifySrvccStarted + List profiles = new ArrayList<>(); + + SrvccConnection[] srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNull(srvccConnections); + + // active call + SrvccCall srvccProfile = new SrvccCall( + "activeCall", PRECISE_CALL_STATE_ACTIVE, activeProfile); + profiles.add(srvccProfile); + + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] {}); + mCTUT.updateCarrierConfigCache(bundle); + + srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNull(srvccConnections); + } + + @Test + @SmallTest + public void testConvertToSrvccConnectionInfoBasicSrvcc() throws Exception { + // setup ImsPhoneCallTracker's mConnections + ImsPhoneConnection activeMO = getImsPhoneConnection(Call.State.ACTIVE, "1234", false); + ImsPhoneConnection heldMT = getImsPhoneConnection(Call.State.HOLDING, "5678", true); + + ArrayList connections = new ArrayList(); + replaceInstance(ImsPhoneCallTracker.class, "mConnections", mCTUT, connections); + connections.add(activeMO); + connections.add(heldMT); + + ImsCallProfile activeProfile = getImsCallProfileForSrvccSync("activeCall", activeMO, false); + ImsCallProfile heldProfile = getImsCallProfileForSrvccSync("heldCall", heldMT, false); + + // setup the response of notifySrvccStarted + List profiles = new ArrayList<>(); + + // active call + SrvccCall srvccProfile = new SrvccCall( + "activeCall", PRECISE_CALL_STATE_ACTIVE, activeProfile); + profiles.add(srvccProfile); + + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] { + BASIC_SRVCC_SUPPORT, + }); + mCTUT.updateCarrierConfigCache(bundle); + + SrvccConnection[] srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNotNull(srvccConnections); + assertTrue(srvccConnections.length == 1); + assertTrue(srvccConnections[0].getState() == Call.State.ACTIVE); + assertEquals("1234", srvccConnections[0].getNumber()); + } + + @Test + @SmallTest + public void testConvertToSrvccConnectionInfoMoAlerting() throws Exception { + // setup ImsPhoneCallTracker's mConnections + ImsPhoneConnection alertingMO = getImsPhoneConnection(Call.State.ALERTING, "1234", false); + + ArrayList connections = new ArrayList(); + replaceInstance(ImsPhoneCallTracker.class, "mConnections", mCTUT, connections); + connections.add(alertingMO); + + ImsCallProfile alertingProfile = getImsCallProfileForSrvccSync("alertingCall", null, true); + + // setup the response of notifySrvccStarted + List profiles = new ArrayList<>(); + + // alerting call, with local ringback tone + SrvccCall srvccProfile = new SrvccCall( + "alertingCall", PRECISE_CALL_STATE_ALERTING, alertingProfile); + profiles.add(srvccProfile); + + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] { + BASIC_SRVCC_SUPPORT, + }); + mCTUT.updateCarrierConfigCache(bundle); + + SrvccConnection[] srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNull(srvccConnections); + + bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] { + BASIC_SRVCC_SUPPORT, + ALERTING_SRVCC_SUPPORT, + }); + mCTUT.updateCarrierConfigCache(bundle); + + srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNotNull(srvccConnections); + assertTrue(srvccConnections.length == 1); + assertTrue(srvccConnections[0].getState() == Call.State.ALERTING); + assertTrue(srvccConnections[0].getRingbackToneType() == SrvccConnection.TONE_LOCAL); + + profiles.clear(); + + // alerting call, with network ringback tone + alertingProfile = getImsCallProfileForSrvccSync("alertingCall", null, false); + + srvccProfile = new SrvccCall( + "alertingCall", PRECISE_CALL_STATE_ALERTING, alertingProfile); + profiles.add(srvccProfile); + + srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNotNull(srvccConnections); + assertTrue(srvccConnections.length == 1); + assertTrue(srvccConnections[0].getState() == Call.State.ALERTING); + assertTrue(srvccConnections[0].getRingbackToneType() == SrvccConnection.TONE_NETWORK); + } + + @Test + @SmallTest + public void testConvertToSrvccConnectionInfoMtAlerting() throws Exception { + // setup ImsPhoneCallTracker's mConnections + ImsPhoneConnection alertingMT = getImsPhoneConnection(Call.State.INCOMING, "1234", false); + + ArrayList connections = new ArrayList(); + replaceInstance(ImsPhoneCallTracker.class, "mConnections", mCTUT, connections); + connections.add(alertingMT); + + ImsCallProfile incomingProfile = + getImsCallProfileForSrvccSync("incomingCall", alertingMT, false); + + // setup the response of notifySrvccStarted + List profiles = new ArrayList<>(); + + SrvccCall srvccProfile = new SrvccCall( + "incomingCall", PRECISE_CALL_STATE_INCOMING, incomingProfile); + profiles.add(srvccProfile); + + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] { + BASIC_SRVCC_SUPPORT, + }); + mCTUT.updateCarrierConfigCache(bundle); + + SrvccConnection[] srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNull(srvccConnections); + + bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] { + ALERTING_SRVCC_SUPPORT, + }); + mCTUT.updateCarrierConfigCache(bundle); + + srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNotNull(srvccConnections); + assertTrue(srvccConnections.length == 1); + assertTrue(srvccConnections[0].getState() == Call.State.INCOMING); + } + + @Test + @SmallTest + public void testConvertToSrvccConnectionInfoMtPreAlerting() throws Exception { + // setup the response of notifySrvccStarted + List profiles = new ArrayList<>(); + + ImsCallProfile incomingProfile = getImsCallProfileForSrvccSync("incomingCall", null, false); + + SrvccCall srvccProfile = new SrvccCall( + "incomingCallSetup", PRECISE_CALL_STATE_INCOMING_SETUP, incomingProfile); + profiles.add(srvccProfile); + + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] { + BASIC_SRVCC_SUPPORT, + ALERTING_SRVCC_SUPPORT, + }); + mCTUT.updateCarrierConfigCache(bundle); + + SrvccConnection[] srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNull(srvccConnections); + + bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] { + BASIC_SRVCC_SUPPORT, + ALERTING_SRVCC_SUPPORT, + PREALERTING_SRVCC_SUPPORT, + }); + mCTUT.updateCarrierConfigCache(bundle); + + srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNotNull(srvccConnections); + assertTrue(srvccConnections.length == 1); + assertTrue(srvccConnections[0].getState() == Call.State.INCOMING); + assertTrue(srvccConnections[0].getSubState() == SrvccConnection.SUBSTATE_PREALERTING); + } + + @Test + @SmallTest + public void testNotifySrvccStateStarted() throws Exception { + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] { + BASIC_SRVCC_SUPPORT, + }); + mCTUT.updateCarrierConfigCache(bundle); + + mSrvccStartedCallback = null; + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + mSrvccStartedCallback = (ISrvccStartedCallback) invocation.getArguments()[0]; + return null; + } + }).when(mImsManager).notifySrvccStarted(any(ISrvccStartedCallback.class)); + + verify(mImsManager, times(0)).notifySrvccStarted(any()); + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_STARTED); + verify(mImsManager, times(1)).notifySrvccStarted(any()); + assertNotNull(mSrvccStartedCallback); + + // setup ImsPhoneCallTracker's mConnections + ImsPhoneConnection activeMO = getImsPhoneConnection(Call.State.ACTIVE, "1234", false); + + ArrayList connections = new ArrayList(); + replaceInstance(ImsPhoneCallTracker.class, "mConnections", mCTUT, connections); + connections.add(activeMO); + + ImsCallProfile activeProfile = getImsCallProfileForSrvccSync("activeCall", activeMO, false); + + // setup the response of notifySrvccStarted + List profiles = new ArrayList<>(); + + // active call + SrvccCall srvccProfile = new SrvccCall( + "activeCall", PRECISE_CALL_STATE_ACTIVE, activeProfile); + profiles.add(srvccProfile); + + mSrvccStartedCallback.onSrvccCallNotified(profiles); + SrvccConnection[] srvccConnections = mSimulatedCommands.getSrvccConnections(); + + assertNotNull(srvccConnections); + assertTrue(srvccConnections.length == 1); + assertTrue(srvccConnections[0].getState() == Call.State.ACTIVE); + assertEquals("1234", srvccConnections[0].getNumber()); + } + + @Test + @SmallTest + public void testNotifySrvccStateFailed() throws Exception { + verify(mImsManager, times(0)).notifySrvccFailed(); + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_FAILED); + verify(mImsManager, times(1)).notifySrvccFailed(); + } + + @Test + @SmallTest + public void testNotifySrvccStateCanceled() throws Exception { + verify(mImsManager, times(0)).notifySrvccCanceled(); + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_CANCELED); + verify(mImsManager, times(1)).notifySrvccCanceled(); + } + + @Test + @SmallTest + public void testNotifySrvccStateCompleted() throws Exception { + verify(mImsManager, times(0)).notifySrvccCompleted(); + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_COMPLETED); + verify(mImsManager, times(1)).notifySrvccCompleted(); + } + private void sendCarrierConfigChanged() { Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); @@ -2001,5 +2317,39 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { } return connection; } + + private ImsPhoneConnection getImsPhoneConnection(Call.State state, + String number, boolean isIncoming) { + ImsPhoneCall call = mock(ImsPhoneCall.class); + doReturn(state).when(call).getState(); + + ImsPhoneConnection c = mock(ImsPhoneConnection.class); + doReturn(state).when(c).getState(); + doReturn(isIncoming).when(c).isIncoming(); + doReturn(call).when(c).getCall(); + doReturn(number).when(c).getAddress(); + + return c; + } + + private ImsCallProfile getImsCallProfileForSrvccSync(String callId, + ImsPhoneConnection c, boolean localTone) { + ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile(0, + localTone ? DIRECTION_INACTIVE : DIRECTION_SEND_RECEIVE, 0, 0, 0); + ImsCallProfile profile = new ImsCallProfile(0, 0, null, mediaProfile); + + if (c != null) { + ImsCallSession session = mock(ImsCallSession.class); + doReturn(callId).when(session).getCallId(); + + ImsCall imsCall = mock(ImsCall.class); + doReturn(profile).when(imsCall).getCallProfile(); + doReturn(session).when(imsCall).getCallSession(); + + doReturn(imsCall).when(c).getImsCall(); + } + + return profile; + } } -- GitLab From 52be46a8dacc4e33dd41ec03210e6147ec5db844 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 19 Apr 2022 06:25:47 +0000 Subject: [PATCH 159/656] Support SRVCC of conference participants Bug: 217654931 Test: atest ImsPhoneCallTrackerTest Change-Id: I8ec63bd8e3e4787cab7c0c9ee15e1e1ad35a42d8 --- .../internal/telephony/SrvccConnection.java | 36 +++++++++ .../imsphone/ImsPhoneCallTracker.java | 30 ++++++- .../imsphone/ImsPhoneCallTrackerTest.java | 80 +++++++++++++++++++ 3 files changed, 142 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/SrvccConnection.java b/src/java/com/android/internal/telephony/SrvccConnection.java index 0ce40d88dc..b831a592cb 100644 --- a/src/java/com/android/internal/telephony/SrvccConnection.java +++ b/src/java/com/android/internal/telephony/SrvccConnection.java @@ -24,10 +24,13 @@ import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_INCOMING; import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_INCOMING_SETUP; import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_WAITING; +import android.net.Uri; import android.telephony.Annotation.PreciseCallStates; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsStreamMediaProfile; +import android.text.TextUtils; +import com.android.ims.internal.ConferenceParticipant; import com.android.internal.telephony.imsphone.ImsPhoneConnection; /** @@ -94,6 +97,39 @@ public class SrvccConnection { } } + public SrvccConnection(ConferenceParticipant cp, @PreciseCallStates int preciseCallState) { + mState = toCallState(preciseCallState); + mIsMT = cp.getCallDirection() == android.telecom.Call.Details.DIRECTION_INCOMING; + mNumber = getParticipantAddress(cp.getHandle()); + mNumPresentation = cp.getParticipantPresentation(); + if (mNumPresentation == PhoneConstants.PRESENTATION_RESTRICTED) { + mNumber = ""; + } + mName = cp.getDisplayName(); + if (!TextUtils.isEmpty(mName)) { + mNamePresentation = PhoneConstants.PRESENTATION_ALLOWED; + } else { + mNamePresentation = PhoneConstants.PRESENTATION_UNKNOWN; + } + mIsMpty = true; + } + + private static String getParticipantAddress(Uri address) { + if (address == null) { + return null; + } + + String number = address.getSchemeSpecificPart(); + if (TextUtils.isEmpty(number)) { + return null; + } + + String[] numberParts = number.split("[@;:]"); + if (numberParts.length == 0) return null; + + return numberParts[0]; + } + // MT call in alerting or prealerting state private void initialize(ImsCallProfile profile) { mIsMT = true; diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 748f081e01..1c9ee8877e 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -5672,7 +5672,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { * @param profile the SrvccCall of the connection to be added * @param c the ImsPhoneConnection of the connection to be added */ - private static void addConnection( + private void addConnection( List destList, SrvccCall profile, ImsPhoneConnection c) { if (destList == null) return; if (profile == null) return; @@ -5680,10 +5680,32 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { int preciseCallState = profile.getPreciseCallState(); if (!isAlive(preciseCallState)) return; - SrvccConnection srvccConnection = - new SrvccConnection(profile.getImsCallProfile(), c, preciseCallState); + List participants = getConferenceParticipants(c); + if (participants != null) { + for (ConferenceParticipant cp : participants) { + if (cp.getState() == android.telecom.Connection.STATE_DISCONNECTED) { + Rlog.i(LOG_TAG, "addConnection participant is disconnected"); + continue; + } + SrvccConnection srvccConnection = new SrvccConnection(cp, preciseCallState); + destList.add(srvccConnection); + } + } else { + SrvccConnection srvccConnection = + new SrvccConnection(profile.getImsCallProfile(), c, preciseCallState); + destList.add(srvccConnection); + } + } + + private List getConferenceParticipants(ImsPhoneConnection c) { + if (!mSrvccTypeSupported.contains(MIDCALL_SRVCC_SUPPORT)) return null; + + ImsCall imsCall = c.getImsCall(); + if (imsCall == null) return null; - destList.add(srvccConnection); + List participants = imsCall.getConferenceParticipants(); + if (participants == null || participants.isEmpty()) return null; + return participants; } private static boolean isAlive(int preciseCallState) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 853a1924da..23de7df755 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -23,6 +23,7 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.telephony.CarrierConfigManager.ImsVoice.ALERTING_SRVCC_SUPPORT; import static android.telephony.CarrierConfigManager.ImsVoice.BASIC_SRVCC_SUPPORT; +import static android.telephony.CarrierConfigManager.ImsVoice.MIDCALL_SRVCC_SUPPORT; import static android.telephony.CarrierConfigManager.ImsVoice.PREALERTING_SRVCC_SUPPORT; import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_ACTIVE; import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_ALERTING; @@ -71,6 +72,7 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.NetworkStats; import android.net.NetworkStats.Entry; +import android.net.Uri; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.os.Bundle; import android.os.Message; @@ -106,6 +108,7 @@ import com.android.ims.ImsCall; import com.android.ims.ImsConfig; import com.android.ims.ImsException; import com.android.ims.ImsManager; +import com.android.ims.internal.ConferenceParticipant; import com.android.ims.internal.IImsCallSession; import com.android.internal.telephony.Call; import com.android.internal.telephony.CallStateException; @@ -2242,6 +2245,77 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { verify(mImsManager, times(1)).notifySrvccCompleted(); } + @Test + @SmallTest + public void testConvertToSrvccConnectionInfoConferenceCall() throws Exception { + // setup ImsPhoneCallTracker's mConnections + ImsPhoneConnection activeMO = getImsPhoneConnection(Call.State.ACTIVE, "1234", false); + + ArrayList connections = new ArrayList(); + replaceInstance(ImsPhoneCallTracker.class, "mConnections", mCTUT, connections); + connections.add(activeMO); + + List participants = new ArrayList(); + participants.add(new ConferenceParticipant(Uri.parse("tel:1234"), "", null, + android.telecom.Connection.STATE_ACTIVE, + android.telecom.Call.Details.DIRECTION_INCOMING)); + participants.add(new ConferenceParticipant(Uri.parse("tel:5678"), "", null, + android.telecom.Connection.STATE_ACTIVE, + android.telecom.Call.Details.DIRECTION_OUTGOING)); + + ImsCallProfile activeProfile = getImsCallProfileForSrvccSync("activeCall", + activeMO, false, participants); + + // setup the response of notifySrvccStarted + List profiles = new ArrayList<>(); + + SrvccConnection[] srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNull(srvccConnections); + + // active call + SrvccCall srvccProfile = new SrvccCall( + "activeCall", PRECISE_CALL_STATE_ACTIVE, activeProfile); + profiles.add(srvccProfile); + + PersistableBundle bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] { + BASIC_SRVCC_SUPPORT, + }); + mCTUT.updateCarrierConfigCache(bundle); + + srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNotNull(srvccConnections); + assertTrue(srvccConnections.length == 1); + assertTrue(srvccConnections[0].getState() == Call.State.ACTIVE); + assertFalse(srvccConnections[0].isMultiParty()); + assertEquals("1234", srvccConnections[0].getNumber()); + + bundle = mContextFixture.getCarrierConfigBundle(); + bundle.putIntArray( + CarrierConfigManager.ImsVoice.KEY_SRVCC_TYPE_INT_ARRAY, + new int[] { + BASIC_SRVCC_SUPPORT, + MIDCALL_SRVCC_SUPPORT + }); + mCTUT.updateCarrierConfigCache(bundle); + + srvccConnections = mCTUT.convertToSrvccConnectionInfo(profiles); + assertNotNull(srvccConnections); + assertTrue(srvccConnections.length == 2); + + assertTrue(srvccConnections[0].getState() == Call.State.ACTIVE); + assertTrue(srvccConnections[0].isMultiParty()); + assertTrue(srvccConnections[0].isIncoming()); + assertEquals("1234", srvccConnections[0].getNumber()); + + assertTrue(srvccConnections[1].getState() == Call.State.ACTIVE); + assertTrue(srvccConnections[1].isMultiParty()); + assertFalse(srvccConnections[1].isIncoming()); + assertEquals("5678", srvccConnections[1].getNumber()); + } + private void sendCarrierConfigChanged() { Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); @@ -2334,6 +2408,11 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { private ImsCallProfile getImsCallProfileForSrvccSync(String callId, ImsPhoneConnection c, boolean localTone) { + return getImsCallProfileForSrvccSync(callId, c, localTone, null); + } + + private ImsCallProfile getImsCallProfileForSrvccSync(String callId, + ImsPhoneConnection c, boolean localTone, List participants) { ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile(0, localTone ? DIRECTION_INACTIVE : DIRECTION_SEND_RECEIVE, 0, 0, 0); ImsCallProfile profile = new ImsCallProfile(0, 0, null, mediaProfile); @@ -2345,6 +2424,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { ImsCall imsCall = mock(ImsCall.class); doReturn(profile).when(imsCall).getCallProfile(); doReturn(session).when(imsCall).getCallSession(); + doReturn(participants).when(imsCall).getConferenceParticipants(); doReturn(imsCall).when(c).getImsCall(); } -- GitLab From c46200b32bca42f735c3f3eb9322b982edb00886 Mon Sep 17 00:00:00 2001 From: Ramya Manoharan Date: Fri, 21 Oct 2022 09:07:11 +0000 Subject: [PATCH 160/656] Disabling user confirmation pop up for SEND_SMS_NO_CONFIRMATION permission when sms is sent via framework in CAtService When destination address is a short code , user is prompted with pop up as charges may be incurred. Added boolean variable skipShortCodeCheck to skip the check and disable from pop up appearing Bug: 248405140 Test: refactoring CL.System testing done. Change-Id: Ic6c3055a69c48476a9d4eaf9ca366e7502da1279 --- .../telephony/IccSmsInterfaceManager.java | 19 ++- .../internal/telephony/SMSDispatcher.java | 141 ++++++++++++++++-- .../internal/telephony/SmsController.java | 20 ++- .../telephony/SmsDispatchersController.java | 112 +++++++++++++- .../internal/telephony/cat/CatService.java | 2 +- .../internal/telephony/SmsControllerTest.java | 4 +- .../telephony/cat/CATServiceTest.java | 2 +- 7 files changed, 271 insertions(+), 29 deletions(-) diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java index d3e6a0d728..1a5d5b31cf 100644 --- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java +++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java @@ -457,11 +457,11 @@ public class IccSmsInterfaceManager { */ public void sendText(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, - boolean persistMessageForNonDefaultSmsApp, long messageId) { + boolean persistMessageForNonDefaultSmsApp, long messageId, boolean skipShortCodeCheck) { sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent, persistMessageForNonDefaultSmsApp, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, false /* expectMore */, SMS_MESSAGE_PERIOD_NOT_SPECIFIED, false /* isForVvm */, - messageId); + messageId, skipShortCodeCheck); } /** @@ -481,6 +481,16 @@ public class IccSmsInterfaceManager { SMS_MESSAGE_PERIOD_NOT_SPECIFIED, isForVvm, 0L /* messageId */); } + + private void sendTextInternal(String callingPackage, String destAddr, String scAddr, + String text, PendingIntent sentIntent, PendingIntent deliveryIntent, + boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore, + int validityPeriod, boolean isForVvm, long messageId) { + sendTextInternal(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent, + persistMessageForNonDefaultSmsApp, priority, expectMore, validityPeriod, isForVvm, + messageId, false); + } + /** * Send a text based SMS. * @@ -527,12 +537,13 @@ public class IccSmsInterfaceManager { * Any Other values including negative considered as Invalid Validity Period of the message. * @param messageId An id that uniquely identifies the message requested to be sent. * Used for logging and diagnostics purposes. The id may be 0. + * @param skipShortCodeCheck Skip check for short code type destination address. */ private void sendTextInternal(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessageForNonDefaultSmsApp, int priority, boolean expectMore, - int validityPeriod, boolean isForVvm, long messageId) { + int validityPeriod, boolean isForVvm, long messageId, boolean skipShortCodeCheck) { if (Rlog.isLoggable("SMS", Log.VERBOSE)) { log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr + " text='" + text + "' sentIntent=" + sentIntent + " deliveryIntent=" @@ -544,7 +555,7 @@ public class IccSmsInterfaceManager { destAddr = filterDestAddress(destAddr); mDispatchersController.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp, - priority, expectMore, validityPeriod, isForVvm, messageId); + priority, expectMore, validityPeriod, isForVvm, messageId, skipShortCodeCheck); } /** diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index ac0d54f8a9..7782b6ec04 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -1318,11 +1318,121 @@ public abstract class SMSDispatcher extends Handler { * @param messageId An id that uniquely identifies the message requested to be sent. * Used for logging and diagnostics purposes. The id may be NULL. */ + public void sendText(String destAddr, String scAddr, String text, + PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, + String callingPkg, boolean persistMessage, int priority, + boolean expectMore, int validityPeriod, boolean isForVvm, + long messageId) { + sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, + persistMessage, priority, expectMore, validityPeriod, isForVvm, messageId, false); + } + + /** + * Send a text based SMS. + * + * @param destAddr the address to send the message to + * @param scAddr is the service center address or null to use + * the current default SMSC + * @param text the body of the message to send + * @param sentIntent if not NULL this PendingIntent is + * broadcast when the message is successfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors:
+ * SmsManager.RESULT_ERROR_GENERIC_FAILURE
+ * SmsManager.RESULT_ERROR_RADIO_OFF
+ * SmsManager.RESULT_ERROR_NULL_PDU
+ * SmsManager.RESULT_ERROR_NO_SERVICE
+ * SmsManager.RESULT_ERROR_LIMIT_EXCEEDED
+ * SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE
+ * SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED
+ * SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED
+ * SmsManager.RESULT_RADIO_NOT_AVAILABLE
+ * SmsManager.RESULT_NETWORK_REJECT
+ * SmsManager.RESULT_INVALID_ARGUMENTS
+ * SmsManager.RESULT_INVALID_STATE
+ * SmsManager.RESULT_NO_MEMORY
+ * SmsManager.RESULT_INVALID_SMS_FORMAT
+ * SmsManager.RESULT_SYSTEM_ERROR
+ * SmsManager.RESULT_MODEM_ERROR
+ * SmsManager.RESULT_NETWORK_ERROR
+ * SmsManager.RESULT_ENCODING_ERROR
+ * SmsManager.RESULT_INVALID_SMSC_ADDRESS
+ * SmsManager.RESULT_OPERATION_NOT_ALLOWED
+ * SmsManager.RESULT_INTERNAL_ERROR
+ * SmsManager.RESULT_NO_RESOURCES
+ * SmsManager.RESULT_CANCELLED
+ * SmsManager.RESULT_REQUEST_NOT_SUPPORTED
+ * SmsManager.RESULT_NO_BLUETOOTH_SERVICE
+ * SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS
+ * SmsManager.RESULT_BLUETOOTH_DISCONNECTED
+ * SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING
+ * SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY
+ * SmsManager.RESULT_SMS_SEND_RETRY_FAILED
+ * SmsManager.RESULT_REMOTE_EXCEPTION
+ * SmsManager.RESULT_NO_DEFAULT_SMS_APP
+ * SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE
+ * SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY
+ * SmsManager.RESULT_RIL_NETWORK_REJECT
+ * SmsManager.RESULT_RIL_INVALID_STATE
+ * SmsManager.RESULT_RIL_INVALID_ARGUMENTS
+ * SmsManager.RESULT_RIL_NO_MEMORY
+ * SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED
+ * SmsManager.RESULT_RIL_INVALID_SMS_FORMAT
+ * SmsManager.RESULT_RIL_SYSTEM_ERR
+ * SmsManager.RESULT_RIL_ENCODING_ERR
+ * SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS
+ * SmsManager.RESULT_RIL_MODEM_ERR
+ * SmsManager.RESULT_RIL_NETWORK_ERR
+ * SmsManager.RESULT_RIL_INTERNAL_ERR
+ * SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED
+ * SmsManager.RESULT_RIL_INVALID_MODEM_STATE
+ * SmsManager.RESULT_RIL_NETWORK_NOT_READY
+ * SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED
+ * SmsManager.RESULT_RIL_NO_RESOURCES
+ * SmsManager.RESULT_RIL_CANCELLED
+ * SmsManager.RESULT_RIL_SIM_ABSENT
+ * SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED
+ * SmsManager.RESULT_RIL_ACCESS_BARRED
+ * SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL
+ * For SmsManager.RESULT_ERROR_GENERIC_FAILURE or any of the RESULT_RIL errors, + * the sentIntent may include the extra "errorCode" containing a radio technology specific + * value, generally only useful for troubleshooting.
+ * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this PendingIntent is + * broadcast when the message is delivered to the recipient. The + * @param messageUri optional URI of the message if it is already stored in the system + * @param callingPkg the calling package name + * @param persistMessage whether to save the sent message into SMS DB for a + * non-default SMS app. + * + * @param priority Priority level of the message + * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 + * --------------------------------- + * PRIORITY | Level of Priority + * --------------------------------- + * '00' | Normal + * '01' | Interactive + * '10' | Urgent + * '11' | Emergency + * ---------------------------------- + * Any Other values included Negative considered as Invalid Priority Indicator of the message. + * @param expectMore is a boolean to indicate the sending messages through same link or not. + * @param validityPeriod Validity Period of the message in mins. + * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. + * Validity Period(Minimum) -> 5 mins + * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). + * Any Other values included Negative considered as Invalid Validity Period of the message. + * @param messageId An id that uniquely identifies the message requested to be sent. + * Used for logging and diagnostics purposes. The id may be NULL. + * @param skipShortCodeCheck Skip check for short code type destination address. + */ public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, - long messageId) { + long messageId, boolean skipShortCodeCheck) { Rlog.d(TAG, "sendText id: " + SmsController.formatCrossStackMessageId(messageId)); int messageRef = nextMessageRef(); SmsMessageBase.SubmitPduBase pdu = getSubmitPdu( @@ -1332,7 +1442,8 @@ public abstract class SMSDispatcher extends Handler { HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu); SmsTracker tracker = getSmsTracker(callingPkg, map, sentIntent, deliveryIntent, getFormat(), messageUri, expectMore, text, true /*isText*/, - persistMessage, priority, validityPeriod, isForVvm, messageId, messageRef); + persistMessage, priority, validityPeriod, isForVvm, messageId, messageRef, + skipShortCodeCheck); if (!sendSmsByCarrierApp(false /* isDataSms */, tracker)) { sendSubmitPdu(tracker); @@ -1643,7 +1754,7 @@ public abstract class SMSDispatcher extends Handler { getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader, (!lastPart || expectMore), fullMessageText, true /*isText*/, true /*persistMessage*/, priority, validityPeriod, false /* isForVvm */, - messageId, messageRef); + messageId, messageRef, false); } else { Rlog.e(TAG, "CdmaSMSDispatcher.getNewSubmitPduTracker(): getSubmitPdu() returned " + "null " + SmsController.formatCrossStackMessageId(messageId)); @@ -1656,13 +1767,12 @@ public abstract class SMSDispatcher extends Handler { SmsHeader.toByteArray(smsHeader), encoding, smsHeader.languageTable, smsHeader.languageShiftTable, validityPeriod, messageRef); if (pdu != null) { - HashMap map = getSmsTrackerMap(destinationAddress, scAddress, - message, pdu); + HashMap map = getSmsTrackerMap(destinationAddress, scAddress, message, pdu); return getSmsTracker(callingPackage, map, sentIntent, deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader, (!lastPart || expectMore), fullMessageText, true /*isText*/, false /*persistMessage*/, priority, validityPeriod, false /* isForVvm */, - messageId, messageRef); + messageId, messageRef, false); } else { Rlog.e(TAG, "GsmSMSDispatcher.getNewSubmitPduTracker(): getSubmitPdu() returned " + "null " + SmsController.formatCrossStackMessageId(messageId)); @@ -1820,7 +1930,8 @@ public abstract class SMSDispatcher extends Handler { */ boolean checkDestination(SmsTracker[] trackers) { if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION) - == PackageManager.PERMISSION_GRANTED || trackers[0].mIsForVvm) { + == PackageManager.PERMISSION_GRANTED || trackers[0].mIsForVvm + || trackers[0].mSkipShortCodeDestAddrCheck) { return true; // app is pre-approved to send to short codes } else { int rule = mPremiumSmsRule.get(); @@ -2164,6 +2275,7 @@ public abstract class SMSDispatcher extends Handler { private Boolean mIsFromDefaultSmsApplication; private int mCarrierId; + private boolean mSkipShortCodeDestAddrCheck; // SMS anomaly uuid -- unexpected error from RIL private final UUID mAnomalyUnexpectedErrorFromRilUUID = UUID.fromString("43043600-ea7a-44d2-9ae6-a58567ac7886"); @@ -2174,7 +2286,7 @@ public abstract class SMSDispatcher extends Handler { SmsHeader smsHeader, boolean expectMore, String fullMessageText, int subId, boolean isText, boolean persistMessage, int userId, int priority, int validityPeriod, boolean isForVvm, long messageId, int carrierId, - int messageRef) { + int messageRef, boolean skipShortCodeDestAddrCheck) { mData = data; mSentIntent = sentIntent; mDeliveryIntent = deliveryIntent; @@ -2200,6 +2312,7 @@ public abstract class SMSDispatcher extends Handler { mIsForVvm = isForVvm; mMessageId = messageId; mCarrierId = carrierId; + mSkipShortCodeDestAddrCheck = skipShortCodeDestAddrCheck; } public HashMap getData() { @@ -2467,7 +2580,7 @@ public abstract class SMSDispatcher extends Handler { AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader, boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage, int priority, int validityPeriod, boolean isForVvm, - long messageId, int messageRef) { + long messageId, int messageRef, boolean skipShortCodeCheck) { // Get package info via packagemanager UserHandle callingUser = UserHandle.getUserHandleForUid(Binder.getCallingUid()); final int userId = callingUser.getIdentifier(); @@ -2484,7 +2597,8 @@ public abstract class SMSDispatcher extends Handler { return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format, unsentPartCount, anyPartFailed, messageUri, smsHeader, expectMore, fullMessageText, getSubId(), isText, persistMessage, userId, priority, - validityPeriod, isForVvm, messageId, mPhone.getCarrierId(), messageRef); + validityPeriod, isForVvm, messageId, mPhone.getCarrierId(), messageRef, + skipShortCodeCheck); } protected SmsTracker getSmsTracker(String callingPackage, HashMap data, @@ -2495,17 +2609,18 @@ public abstract class SMSDispatcher extends Handler { null/*unsentPartCount*/, null/*anyPartFailed*/, messageUri, null/*smsHeader*/, expectMore, fullMessageText, isText, persistMessage, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED, SMS_MESSAGE_PERIOD_NOT_SPECIFIED, isForVvm, - messageId, messageRef); + messageId, messageRef, false); } protected SmsTracker getSmsTracker(String callingPackage, HashMap data, PendingIntent sentIntent, PendingIntent deliveryIntent, String format, Uri messageUri, boolean expectMore, String fullMessageText, boolean isText, boolean persistMessage, - int priority, int validityPeriod, boolean isForVvm, long messageId, int messageRef) { + int priority, int validityPeriod, boolean isForVvm, long messageId, int messageRef, + boolean skipShortCodeCheck) { return getSmsTracker(callingPackage, data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/, null/*anyPartFailed*/, messageUri, null/*smsHeader*/, expectMore, fullMessageText, isText, persistMessage, priority, validityPeriod, - isForVvm, messageId, messageRef); + isForVvm, messageId, messageRef, skipShortCodeCheck); } protected HashMap getSmsTrackerMap(String destAddr, String scAddr, diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 7c326bf5da..1e947e50f8 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -26,6 +26,7 @@ import android.app.AppOpsManager; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.BaseBundle; import android.os.Binder; @@ -199,7 +200,7 @@ public class SmsController extends ISmsImplBase { boolean persistMessageForNonDefaultSmsApp, long messageId) { sendTextForSubscriber(subId, callingPackage, callingAttributionTag, destAddr, scAddr, text, sentIntent, deliveryIntent, persistMessageForNonDefaultSmsApp, messageId, - false); + false, false); } @@ -225,12 +226,20 @@ public class SmsController extends ISmsImplBase { public void sendTextForSubscriber(int subId, String callingPackage, String callingAttributionTag, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, - boolean persistMessageForNonDefaultSmsApp, long messageId, boolean skipFdnCheck) { + boolean persistMessageForNonDefaultSmsApp, long messageId, boolean skipFdnCheck, + boolean skipShortCodeCheck) { if (callingPackage == null) { callingPackage = getCallingPackage(); } Rlog.d(LOG_TAG, "sendTextForSubscriber caller=" + callingPackage); + if (skipFdnCheck || skipShortCodeCheck) { + if (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_PHONE_STATE) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires MODIFY_PHONE_STATE permission."); + } + } if (!getSmsPermissions(subId).checkCallingCanSendText(persistMessageForNonDefaultSmsApp, callingPackage, callingAttributionTag, "Sending SMS message")) { sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_GENERIC_FAILURE); @@ -255,7 +264,7 @@ public class SmsController extends ISmsImplBase { sendBluetoothText(info, destAddr, text, sentIntent, deliveryIntent); } else { sendIccText(subId, callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent, - persistMessageForNonDefaultSmsApp, messageId); + persistMessageForNonDefaultSmsApp, messageId, skipShortCodeCheck); } } @@ -272,13 +281,14 @@ public class SmsController extends ISmsImplBase { private void sendIccText(int subId, String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, - boolean persistMessageForNonDefaultSmsApp, long messageId) { + boolean persistMessageForNonDefaultSmsApp, long messageId, boolean skipShortCodeCheck) { Rlog.d(LOG_TAG, "sendTextForSubscriber iccSmsIntMgr" + " Subscription: " + subId + " " + formatCrossStackMessageId(messageId)); IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId); if (iccSmsIntMgr != null) { iccSmsIntMgr.sendText(callingPackage, destAddr, scAddr, text, sentIntent, - deliveryIntent, persistMessageForNonDefaultSmsApp, messageId); + deliveryIntent, persistMessageForNonDefaultSmsApp, messageId, + skipShortCodeCheck); } else { Rlog.e(LOG_TAG, "sendTextForSubscriber iccSmsIntMgr is null for" + " Subscription: " + subId + " " + formatCrossStackMessageId(messageId)); diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java index 29ec7d8cad..1763b5f8a0 100644 --- a/src/java/com/android/internal/telephony/SmsDispatchersController.java +++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java @@ -803,22 +803,128 @@ public class SmsDispatchersController extends Handler { PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId) { + sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, + persistMessage, priority, expectMore, validityPeriod, isForVvm, messageId, false); + } + + /** + * Send a text based SMS. + * + * @param destAddr the address to send the message to + * @param scAddr is the service center address or null to use + * the current default SMSC + * @param text the body of the message to send + * @param sentIntent if not NULL this PendingIntent is + * broadcast when the message is successfully sent, or failed. + * The result code will be Activity.RESULT_OK for success, + * or one of these errors:
+ * SmsManager.RESULT_ERROR_GENERIC_FAILURE
+ * SmsManager.RESULT_ERROR_RADIO_OFF
+ * SmsManager.RESULT_ERROR_NULL_PDU
+ * SmsManager.RESULT_ERROR_NO_SERVICE
+ * SmsManager.RESULT_ERROR_LIMIT_EXCEEDED
+ * SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE
+ * SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED
+ * SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED
+ * SmsManager.RESULT_RADIO_NOT_AVAILABLE
+ * SmsManager.RESULT_NETWORK_REJECT
+ * SmsManager.RESULT_INVALID_ARGUMENTS
+ * SmsManager.RESULT_INVALID_STATE
+ * SmsManager.RESULT_NO_MEMORY
+ * SmsManager.RESULT_INVALID_SMS_FORMAT
+ * SmsManager.RESULT_SYSTEM_ERROR
+ * SmsManager.RESULT_MODEM_ERROR
+ * SmsManager.RESULT_NETWORK_ERROR
+ * SmsManager.RESULT_ENCODING_ERROR
+ * SmsManager.RESULT_INVALID_SMSC_ADDRESS
+ * SmsManager.RESULT_OPERATION_NOT_ALLOWED
+ * SmsManager.RESULT_INTERNAL_ERROR
+ * SmsManager.RESULT_NO_RESOURCES
+ * SmsManager.RESULT_CANCELLED
+ * SmsManager.RESULT_REQUEST_NOT_SUPPORTED
+ * SmsManager.RESULT_NO_BLUETOOTH_SERVICE
+ * SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS
+ * SmsManager.RESULT_BLUETOOTH_DISCONNECTED
+ * SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING
+ * SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY
+ * SmsManager.RESULT_SMS_SEND_RETRY_FAILED
+ * SmsManager.RESULT_REMOTE_EXCEPTION
+ * SmsManager.RESULT_NO_DEFAULT_SMS_APP
+ * SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE
+ * SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY
+ * SmsManager.RESULT_RIL_NETWORK_REJECT
+ * SmsManager.RESULT_RIL_INVALID_STATE
+ * SmsManager.RESULT_RIL_INVALID_ARGUMENTS
+ * SmsManager.RESULT_RIL_NO_MEMORY
+ * SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED
+ * SmsManager.RESULT_RIL_INVALID_SMS_FORMAT
+ * SmsManager.RESULT_RIL_SYSTEM_ERR
+ * SmsManager.RESULT_RIL_ENCODING_ERR
+ * SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS
+ * SmsManager.RESULT_RIL_MODEM_ERR
+ * SmsManager.RESULT_RIL_NETWORK_ERR
+ * SmsManager.RESULT_RIL_INTERNAL_ERR
+ * SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED
+ * SmsManager.RESULT_RIL_INVALID_MODEM_STATE
+ * SmsManager.RESULT_RIL_NETWORK_NOT_READY
+ * SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED
+ * SmsManager.RESULT_RIL_NO_RESOURCES
+ * SmsManager.RESULT_RIL_CANCELLED
+ * SmsManager.RESULT_RIL_SIM_ABSENT
+ * SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED
+ * SmsManager.RESULT_RIL_ACCESS_BARRED
+ * SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL
+ * For SmsManager.RESULT_ERROR_GENERIC_FAILURE or any of the RESULT_RIL errors, + * the sentIntent may include the extra "errorCode" containing a radio technology specific + * value, generally only useful for troubleshooting.
+ * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this PendingIntent is + * broadcast when the message is delivered to the recipient. The + * @param messageUri optional URI of the message if it is already stored in the system + * @param callingPkg the calling package name + * @param persistMessage whether to save the sent message into SMS DB for a + * non-default SMS app. + * @param priority Priority level of the message + * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 + * --------------------------------- + * PRIORITY | Level of Priority + * --------------------------------- + * '00' | Normal + * '01' | Interactive + * '10' | Urgent + * '11' | Emergency + * ---------------------------------- + * Any Other values included Negative considered as Invalid Priority Indicator of the message. + * @param expectMore is a boolean to indicate the sending messages through same link or not. + * @param validityPeriod Validity Period of the message in mins. + * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. + * Validity Period(Minimum) -> 5 mins + * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). + * Any Other values included Negative considered as Invalid Validity Period of the message. + * @param skipShortCodeCheck Skip check for short code type destination address. + */ + public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, + PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, + int priority, boolean expectMore, int validityPeriod, boolean isForVvm, + long messageId, boolean skipShortCodeCheck) { if (scAddr == null) { scAddr = getSmscAddressFromUSIM(callingPkg); } if (mImsSmsDispatcher.isAvailable() || mImsSmsDispatcher.isEmergencySmsSupport(destAddr)) { mImsSmsDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage, priority, false /*expectMore*/, - validityPeriod, isForVvm, messageId); + validityPeriod, isForVvm, messageId, skipShortCodeCheck); } else { if (isCdmaMo()) { mCdmaDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage, priority, expectMore, - validityPeriod, isForVvm, messageId); + validityPeriod, isForVvm, messageId, skipShortCodeCheck); } else { mGsmDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage, priority, expectMore, - validityPeriod, isForVvm, messageId); + validityPeriod, isForVvm, messageId, skipShortCodeCheck); } } } diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java index 2afc63f6db..f0ac9af9ad 100644 --- a/src/java/com/android/internal/telephony/cat/CatService.java +++ b/src/java/com/android/internal/telephony/cat/CatService.java @@ -624,7 +624,7 @@ public class CatService extends Handler implements AppInterface { SmsController smsController = proxyController.getSmsController(); smsController.sendTextForSubscriber(subId, mContext.getOpPackageName(), mContext.getAttributionTag(), destAddr, null, text, sentPendingIntent, - deliveryPendingIntent, false, 0L, true); + deliveryPendingIntent, false, 0L, true, true); } private class SmsBroadcastReceiver extends BroadcastReceiver { diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java index 2c67342678..63f7d00552 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java @@ -195,9 +195,9 @@ public class SmsControllerTest extends TelephonyTest { @Test public void sendsendTextForSubscriberTest() { mSmsControllerUT.sendTextForSubscriber(1, mCallingPackage, null, "1234", - null, "text", null, null, false, 0L, true); + null, "text", null, null, false, 0L, true, true); verify(mIccSmsInterfaceManager, Mockito.times(1)) - .sendText(mCallingPackage, "1234", null, "text", null, null, false, 0L); + .sendText(mCallingPackage, "1234", null, "text", null, null, false, 0L, true); } } \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java index f8fec6a2a2..6bc31da405 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java @@ -170,7 +170,7 @@ public class CATServiceTest extends TelephonyTest { mCatService.sendStkSms("test", "12345", 1, cmdPrms, mProxyController); verify(mSmsController, Mockito.times(1)).sendTextForSubscriber(anyInt(), anyString(), nullable(String.class), anyString(), nullable(String.class), - anyString(), Mockito.anyObject(), any(), eq(false), anyLong(), eq(true)); + anyString(), Mockito.anyObject(), any(), eq(false), anyLong(), eq(true), eq(true)); } @Test -- GitLab From 4721df13b75b6902695a63e875fb8f512d8269d2 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 21 Oct 2022 13:11:38 +0000 Subject: [PATCH 161/656] Update RadioImsProxy for startImsTraffic and updateImsCallStatus Add trafficDirection paramter to startImsTraffic. Add updateImsCallStatus. Bug: 255450284 Test: build Change-Id: Ia6b4a724980f060f9956ca10326e59c52dd14ce7 --- .../internal/telephony/ImsResponse.java | 7 ++++++ .../com/android/internal/telephony/RIL.java | 3 ++- .../internal/telephony/RadioImsProxy.java | 23 ++++++++++++++++--- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/ImsResponse.java b/src/java/com/android/internal/telephony/ImsResponse.java index 6b84a6e91f..257f1da14b 100644 --- a/src/java/com/android/internal/telephony/ImsResponse.java +++ b/src/java/com/android/internal/telephony/ImsResponse.java @@ -100,4 +100,11 @@ public class ImsResponse extends IRadioImsResponse.Stub { public void sendAnbrQueryResponse(RadioResponseInfo info) { RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); } + + /** + * @param info Response info struct containing response type, serial no. and error. + */ + public void updateImsCallStatusResponse(RadioResponseInfo info) { + RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + } } diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 1d08958dfb..69fffe2f0d 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5203,7 +5203,8 @@ public class RIL extends BaseCommands implements CommandsInterface { } try { - imsProxy.startImsTraffic(rr.mSerial, token, trafficType, accessNetworkType); + // TODO(ag/20335448): replace 0 with actual trafficDirection + imsProxy.startImsTraffic(rr.mSerial, token, trafficType, accessNetworkType, 0); } catch (RemoteException | RuntimeException e) { handleRadioProxyExceptionForRR(IMS_SERVICE, "startImsTraffic", e); } diff --git a/src/java/com/android/internal/telephony/RadioImsProxy.java b/src/java/com/android/internal/telephony/RadioImsProxy.java index 5cb82aa5f7..439e350719 100644 --- a/src/java/com/android/internal/telephony/RadioImsProxy.java +++ b/src/java/com/android/internal/telephony/RadioImsProxy.java @@ -132,13 +132,16 @@ public class RadioImsProxy extends RadioServiceProxy { * @param token A nonce to identify the request. * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. * @param accessNetworkType The type of underlying radio access network used. + * @param trafficDirection Indicates whether traffic is originated by mobile originated or + * mobile terminated use case eg. MO/MT call/SMS etc. * @throws RemoteException. */ - public void startImsTraffic(int serial, int token, int trafficType, int accessNetworkType) - throws RemoteException { + public void startImsTraffic(int serial, int token, int trafficType, int accessNetworkType, + int trafficDirection) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mImsProxy.startImsTraffic(serial, token, trafficType, accessNetworkType); + mImsProxy.startImsTraffic(serial, + token, trafficType, accessNetworkType, trafficDirection); } } @@ -185,4 +188,18 @@ public class RadioImsProxy extends RadioServiceProxy { mImsProxy.sendAnbrQuery(serial, mediaType, direction, bitsPerSecond); } } + + /** + * Call IRadioIms#updateImsCallStatus + * @param serial Serial number of request. + * @param imsCalls The list of call status information. + * @throws RemoteException. + */ + public void updateImsCallStatus(int serial, + android.hardware.radio.ims.ImsCall[] imsCalls) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mImsProxy.updateImsCallStatus(serial, imsCalls); + } + } } -- GitLab From a45e7011a6b46d486e71614ecb8a6c4b2537b17e Mon Sep 17 00:00:00 2001 From: sandeepjs Date: Tue, 4 Oct 2022 07:14:08 +0000 Subject: [PATCH 162/656] Updating getEnabledProfile API to return code when no iccid enabled some of the ES10x procedures are returning the error code same as the one defined for EuiccCardManager.RESULT_PROFILE_NOT_FOUND(#1) in the platform(eUICC always returns positive integers as error code), Hence deprecated it and defining new constant with -4 as value to avoid confusion. Test: build and manual Bug: 242288148 Change-Id: Ia6c8fe99b270a5ca0d5bdc12fc7cf0105361dc03 --- .../android/internal/telephony/euicc/EuiccCardController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java index f33714163e..6a0011dfcd 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java @@ -413,7 +413,7 @@ public class EuiccCardController extends IEuiccCardController.Stub { // if there is no iccid enabled on this port, return null. if (TextUtils.isEmpty(iccId)) { try { - callback.onComplete(EuiccCardManager.RESULT_PROFILE_NOT_FOUND, null); + callback.onComplete(EuiccCardManager.RESULT_PROFILE_DOES_NOT_EXIST, null); } catch (RemoteException exception) { loge("getEnabledProfile callback failure.", exception); } -- GitLab From b51212517520641aca5057fc87f19cad8e5d5e5b Mon Sep 17 00:00:00 2001 From: Michael Groover Date: Fri, 4 Nov 2022 23:12:05 +0000 Subject: [PATCH 163/656] Revert "Add unaudited exported flag to exposed runtime receivers" This reverts commit 8d1c127023f415c79f82d16376db78e245cb4d77. Reason for revert: Reverting to resolve test failures in b/257459174 Change-Id: I7d50bff6afa65a9ad3d93d04566aa46f3fa16a95 --- .../com/android/internal/telephony/CallWaitingController.java | 3 +-- .../android/internal/telephony/CarrierPrivilegesTracker.java | 3 +-- .../android/internal/telephony/MultiSimSettingController.java | 3 +-- .../com/android/internal/telephony/ServiceStateTracker.java | 2 +- src/java/com/android/internal/telephony/ims/ImsResolver.java | 3 +-- src/java/com/android/internal/telephony/uicc/PinStorage.java | 3 +-- src/java/com/android/internal/telephony/uicc/UiccProfile.java | 3 +-- .../android/internal/telephony/gsm/GsmSmsDispatcherTest.java | 3 +-- 8 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java index 3b134f6511..4940eb62b2 100644 --- a/src/java/com/android/internal/telephony/CallWaitingController.java +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -145,8 +145,7 @@ public class CallWaitingController extends Handler { private void initialize() { mContext.registerReceiver(mReceiver, new IntentFilter( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), - Context.RECEIVER_EXPORTED_UNAUDITED); + CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); int phoneId = mPhone.getPhoneId(); int subId = mPhone.getSubId(); diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index 4d9d860df6..b91e6bfb3f 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -377,8 +377,7 @@ public class CarrierPrivilegesTracker extends Handler { certFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); certFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); certFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); - mContext.registerReceiver(mIntentReceiver, certFilter, - Context.RECEIVER_EXPORTED_UNAUDITED); + mContext.registerReceiver(mIntentReceiver, certFilter); IntentFilter packageFilter = new IntentFilter(); packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index e3dfcb36da..85053de899 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -246,8 +246,7 @@ public class MultiSimSettingController extends Handler { mIsAskEverytimeSupportedForSms = mContext.getResources() .getBoolean(com.android.internal.R.bool.config_sms_ask_every_time_support); context.registerReceiver(mIntentReceiver, new IntentFilter( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), - Context.RECEIVER_EXPORTED_UNAUDITED); + CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); } /** diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 7ee6273ddb..f99479243f 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -699,7 +699,7 @@ public class ServiceStateTracker extends Handler { filter.addAction(Intent.ACTION_LOCALE_CHANGED); filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED); - context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_EXPORTED_UNAUDITED); + context.registerReceiver(mIntentReceiver, filter); mPhone.notifyOtaspChanged(TelephonyManager.OTASP_UNINITIALIZED); diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java index 0a14fe1428..c3331d9c54 100644 --- a/src/java/com/android/internal/telephony/ims/ImsResolver.java +++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java @@ -651,8 +651,7 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal appChangedFilter.addDataScheme("package"); mReceiverContext.registerReceiver(mAppChangedReceiver, appChangedFilter); mReceiverContext.registerReceiver(mConfigChangedReceiver, new IntentFilter( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), - Context.RECEIVER_EXPORTED_UNAUDITED); + CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); if (userManager.isUserUnlocked()) { diff --git a/src/java/com/android/internal/telephony/uicc/PinStorage.java b/src/java/com/android/internal/telephony/uicc/PinStorage.java index 79813140f5..1154e0f04a 100644 --- a/src/java/com/android/internal/telephony/uicc/PinStorage.java +++ b/src/java/com/android/internal/telephony/uicc/PinStorage.java @@ -193,8 +193,7 @@ public class PinStorage extends Handler { intentFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); intentFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); - mContext.registerReceiver(mCarrierConfigChangedReceiver, intentFilter, - Context.RECEIVER_EXPORTED_UNAUDITED); + mContext.registerReceiver(mCarrierConfigChangedReceiver, intentFilter); // Initialize the long term secret key. This needs to be present in all cases: // - if the device is not secure or is locked: key does not require user authentication diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index c286cadc4e..2809895309 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -339,8 +339,7 @@ public class UiccProfile extends IccCard { IntentFilter intentfilter = new IntentFilter(); intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - c.registerReceiver(mCarrierConfigChangedReceiver, intentfilter, - Context.RECEIVER_EXPORTED_UNAUDITED); + c.registerReceiver(mCarrierConfigChangedReceiver, intentfilter); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java index a093d11744..5f4671b918 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java @@ -231,8 +231,7 @@ public class GsmSmsDispatcherTest extends TelephonyTest { restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton); restoreInstance(ActivityManager.class, "IActivityManagerSingleton", null); Context realContext = TestApplication.getAppContext(); - realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT), - Context.RECEIVER_EXPORTED_UNAUDITED); + realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT)); } @Test -- GitLab From 323eb72f6a9b69b17c6daf07fc2ce968657516fd Mon Sep 17 00:00:00 2001 From: Aswin Sankar Date: Tue, 1 Nov 2022 14:38:51 -0700 Subject: [PATCH 164/656] SST: Update SPN display on IWLAN reg tech change - When IMS registration tech moves from "regular" IWLAN (WiFi AP) to CROSS_SIM, the ServiceState objects do not change, so it does not trigger an update to the carrier alpha tag. - SST will now manually update alpha tag when IMS service updates the IMS registration state. - go/pag/2315643 for the ShannonIMS svc change. Bug:249609782 Test: Live test on P10: connect to WiFi AP when 1 sub is in Backup Calling, observe UI update from ' Backup Calling' to ' WiFi Calling'. Change-Id: If605b8bdb3d44d61b3588a8ce35d4c4d9bc00d8f --- .../com/android/internal/telephony/ServiceStateTracker.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index ca70d9cbc8..d33d00a333 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -3239,7 +3239,6 @@ public class ServiceStateTracker extends Handler { + " mImsRegistrationOnOff=" + mImsRegistrationOnOff + "}"); - if (mImsRegistrationOnOff && !registered) { // moving to deregistered, only send this event if we need to re-evaluate if (getRadioPowerOffDelayTimeoutForImsRegistration() > 0) { @@ -3252,6 +3251,9 @@ public class ServiceStateTracker extends Handler { } } mImsRegistrationOnOff = registered; + + // It's possible ServiceState changes did not trigger SPN display update; we update it here. + updateSpnDisplay(); } public void onImsCapabilityChanged() { -- GitLab From afd20af54fe562dcb7757348e5da140df581cfef Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Mon, 7 Nov 2022 14:44:42 -0800 Subject: [PATCH 165/656] Update auto switch notification intent Put the target subId in intent directly without being wrapped by a bundle. Improved logs. Test: manual Bug: 257991417 Change-Id: I9bec0e35aa2a5eb19f3af7c3cc7ffbe77809faeb --- .../internal/telephony/data/PhoneSwitcher.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index e6d0e1cc79..6c2a2cbcd1 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -1254,6 +1254,7 @@ public class PhoneSwitcher extends Handler { // the alternative phone must have HOME availability if (mPhoneStates[phoneId].dataRegState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { + log("getAutoSwitchTargetSubId: found phone " + phoneId + " in HOME service"); Phone secondaryDataPhone = findPhoneById(phoneId); if (secondaryDataPhone != null && // check auto switch feature enabled secondaryDataPhone.isDataAllowed()) { @@ -2069,6 +2070,7 @@ public class PhoneSwitcher extends Handler { pw.println("mAutoDataSwitchAvailabilityStabilityTimeThreshold=" + mAutoDataSwitchAvailabilityStabilityTimeThreshold); pw.println("mAutoDataSwitchValidationMaxRetry=" + mAutoDataSwitchValidationMaxRetry); + pw.println("mDisplayedAutoSwitchNotification=" + mDisplayedAutoSwitchNotification); pw.println("Local logs:"); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); @@ -2128,20 +2130,16 @@ public class PhoneSwitcher extends Handler { if (mDisplayedAutoSwitchNotification) { // cancel posted notification if any exist - if (VDBG) { - log("displayAutoDataSwitchNotification: canceling any notifications for subId " - + mAutoSelectedDataSubId); - } + log("displayAutoDataSwitchNotification: canceling any notifications for subId " + + mAutoSelectedDataSubId); notificationManager.cancel(AUTO_DATA_SWITCH_NOTIFICATION_TAG, AUTO_DATA_SWITCH_NOTIFICATION_ID); return; } // proceed only the first time auto data switch occurs if (mLastAutoSelectedSwitchReason != DataSwitch.Reason.DATA_SWITCH_REASON_AUTO) { - if (VDBG) { - log("displayAutoDataSwitchNotification: Ignore DDS switch due to " - + switchReasonToString(mLastAutoSelectedSwitchReason)); - } + log("displayAutoDataSwitchNotification: Ignore DDS switch due to " + + switchReasonToString(mLastAutoSelectedSwitchReason)); return; } SubscriptionInfo subInfo = mSubscriptionController.getSubscriptionInfo( @@ -2150,13 +2148,13 @@ public class PhoneSwitcher extends Handler { loge("displayAutoDataSwitchNotification: unexpected " + subInfo); return; } - log("displayAutoDataSwitchNotification: displaying for subId=" + mAutoSelectedDataSubId); + logl("displayAutoDataSwitchNotification: display for subId=" + mAutoSelectedDataSubId); // "Mobile network settings" screen / dialog Intent intent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS); final Bundle fragmentArgs = new Bundle(); // Special contract for Settings to highlight permission row fragmentArgs.putString(SETTINGS_EXTRA_FRAGMENT_ARG_KEY, AUTO_DATA_SWITCH_SETTING_R_ID); - fragmentArgs.putInt(Settings.EXTRA_SUB_ID, mAutoSelectedDataSubId); + intent.putExtra(Settings.EXTRA_SUB_ID, mAutoSelectedDataSubId); intent.putExtra(SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS, fragmentArgs); PendingIntent contentIntent = PendingIntent.getActivity( mContext, mAutoSelectedDataSubId, intent, PendingIntent.FLAG_IMMUTABLE); -- GitLab From 37351879877f871efcf4a3dfd729e9b3c437b356 Mon Sep 17 00:00:00 2001 From: Yomna Nasser Date: Thu, 13 Oct 2022 23:36:35 +0000 Subject: [PATCH 166/656] Add RIL interface for setNullCipherAndIntegrityEnabled Bug: b/237529943 Test: m Change-Id: I53403d9f710ff22fa4ceba679c770e808525e9cc --- .../internal/telephony/CommandsInterface.java | 10 ++++++ .../internal/telephony/NetworkResponse.java | 8 +++++ .../com/android/internal/telephony/Phone.java | 12 +++++++ .../com/android/internal/telephony/RIL.java | 36 +++++++++++++++++++ .../android/internal/telephony/RILUtils.java | 3 ++ .../internal/telephony/RadioNetworkProxy.java | 16 +++++++++ 6 files changed, 85 insertions(+) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 2c6ff087ed..bfcda07304 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2930,4 +2930,14 @@ public interface CommandsInterface { * @param bitsPerSecond The bit rate requested by the opponent UE. */ default void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond, Message result) {} + + /** + * Set the UE's ability to accept/reject null ciphered and/or null integrity-protected + * connections. + * + * @param result Callback message containing the success or failure status. + * @param enabled true to allow null ciphered and/or null integrity-protected connections, + * false to disallow. + */ + default void setNullCipherAndIntegrityEnabled(Message result, boolean enabled) {} } diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index 370335a70f..6d532b24f7 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -484,4 +484,12 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { public int getInterfaceVersion() { return IRadioNetworkResponse.VERSION; } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void setNullCipherAndIntegrityEnabledResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + } + } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index e4502eac65..ec912d398f 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -4966,6 +4966,18 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.unregisterForEmergencyNetworkScan(h); } + /** + * Set the UE's ability to accept/reject null ciphered and/or null integrity-protected + * connections. + * + * @param result Callback message. + * @param enabled true to allow null ciphered and/or null integrity-protected connections, + * false to disallow. + */ + public void setNullCipherAndIntegrityEnabled(@Nullable Message result, boolean enabled) { + mCi.setNullCipherAndIntegrityEnabled(result, enabled); + } + /** * @return Telephony tester instance. */ diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 69fffe2f0d..539e969d1a 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5442,6 +5442,42 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * Set if null ciphering / null integrity modes are permitted. + * + * @param result Callback message containing the success or failure status. + * @param enabled true if null ciphering / null integrity modes are permitted, false otherwise + */ + @Override + public void setNullCipherAndIntegrityEnabled(Message result, boolean enabled) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); + if (networkProxy.isEmpty()) return; + if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + networkProxy.setNullCipherAndIntegrityEnabled(rr.mSerial, enabled); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR( + NETWORK_SERVICE, "setNullCipherAndIntegrityEnabled", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "setNullCipherAndIntegrityEnabled: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + //***** Private Methods /** * This is a helper function to be called when an indication callback is called for any radio diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index c05b669295..d016db8f18 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -166,6 +166,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LOGICA import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_MUTE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_DATA_MODEM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_RADIO_CAPABILITY; @@ -5177,6 +5178,8 @@ public class RILUtils { return "SEND_ANBR_QUERY"; case RIL_REQUEST_TRIGGER_EPS_FALLBACK: return "TRIGGER_EPS_FALLBACK"; + case RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED: + return "SET_NULL_CIPHER_AND_INTEGRITY_ENABLED"; default: return ""; } diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java index 5e1cc60691..c8855cd8b7 100644 --- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java +++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java @@ -916,4 +916,20 @@ public class RadioNetworkProxy extends RadioServiceProxy { } // Only supported on AIDL. } + + /** + * Set if null ciphering / null integrity is permitted. + * + * @param serial Serial number of the request. + * @param enabled true if null modes are allowed, false otherwise + * @throws RemoteException + */ + public void setNullCipherAndIntegrityEnabled(int serial, + boolean enabled) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.setNullCipherAndIntegrityEnabled(serial, enabled); + } + // Only supported on AIDL. + } } -- GitLab From 1ccdb8e44816761c300960ae3da842c55de07839 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Mon, 11 Jul 2022 15:36:35 -0700 Subject: [PATCH 167/656] Remove race conditions in NetworkTypeController 1. Cache physical channel configs and service state to prevent race conditions when determining current state. 2. Combine all events related to ServiceState into a single EVENT_SERVICE_STATE_CHANGED event. This handles changes in NR state, frequency, bandwidth, data rat, etc. 3. Create NrConnectedAdvancedState to better handle transitions between connected and connected_mmwave states. 4. Add additional logging to debug future issues. 5. Update tests. Test: atest NetworkTypeControllerTest Bug: 233048459 Bug: 240911460 Change-Id: Ie45efc7626f898b51b1a0b78c0df64548e93a07e --- .../telephony/NetworkTypeController.java | 487 ++++++++++-------- .../telephony/ServiceStateTracker.java | 42 +- .../telephony/NetworkTypeControllerTest.java | 243 +++++---- 3 files changed, 394 insertions(+), 378 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 173036660a..8cfcaa79df 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; @@ -84,30 +85,35 @@ public class NetworkTypeController extends StateMachine { /** Stop all timers and go to current state. */ public static final int EVENT_UPDATE = 0; /** Quit after processing all existing messages. */ - public static final int EVENT_QUIT = 1; - private static final int EVENT_DATA_RAT_CHANGED = 2; - private static final int EVENT_NR_STATE_CHANGED = 3; - private static final int EVENT_NR_FREQUENCY_CHANGED = 4; - private static final int EVENT_PHYSICAL_LINK_STATUS_CHANGED = 5; - private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED = 6; - private static final int EVENT_CARRIER_CONFIG_CHANGED = 7; - private static final int EVENT_PRIMARY_TIMER_EXPIRED = 8; - private static final int EVENT_SECONDARY_TIMER_EXPIRED = 9; - private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 10; - private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11; - private static final int EVENT_INITIALIZE = 12; - private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 13; - private static final int EVENT_BANDWIDTH_CHANGED = 15; - private static final int EVENT_UPDATE_NR_ADVANCED_STATE = 16; - private static final int EVENT_DEVICE_IDLE_MODE_CHANGED = 17; + private static final int EVENT_QUIT = 1; + /** Initialize all events. */ + private static final int EVENT_INITIALIZE = 2; + /** Event for service state changed (data rat, bandwidth, NR state, NR frequency, etc). */ + private static final int EVENT_SERVICE_STATE_CHANGED = 3; + /** Event for physical link status changed. */ + private static final int EVENT_PHYSICAL_LINK_STATUS_CHANGED = 4; + /** Event for physical channel config indications turned on/off. */ + private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED = 5; + /** Event for carrier configs changed. */ + private static final int EVENT_CARRIER_CONFIG_CHANGED = 6; + /** Event for primary timer expired. If a secondary timer exists, it will begin afterwards. */ + private static final int EVENT_PRIMARY_TIMER_EXPIRED = 7; + /** Event for secondary timer expired. */ + private static final int EVENT_SECONDARY_TIMER_EXPIRED = 8; + /** Event for radio off or unavailable. */ + private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 9; + /** Event for preferred network mode changed. */ + private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 10; + /** Event for physical channel configs changed. */ + private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 11; + /** Event for device idle mode changed, when device goes to deep sleep and pauses all timers. */ + private static final int EVENT_DEVICE_IDLE_MODE_CHANGED = 12; private static final String[] sEvents = new String[EVENT_DEVICE_IDLE_MODE_CHANGED + 1]; static { sEvents[EVENT_UPDATE] = "EVENT_UPDATE"; sEvents[EVENT_QUIT] = "EVENT_QUIT"; - sEvents[EVENT_DATA_RAT_CHANGED] = "EVENT_DATA_RAT_CHANGED"; - sEvents[EVENT_NR_STATE_CHANGED] = "EVENT_NR_STATE_CHANGED"; - sEvents[EVENT_NR_FREQUENCY_CHANGED] = "EVENT_NR_FREQUENCY_CHANGED"; + sEvents[EVENT_SERVICE_STATE_CHANGED] = "EVENT_SERVICE_STATE_CHANGED"; sEvents[EVENT_PHYSICAL_LINK_STATUS_CHANGED] = "EVENT_PHYSICAL_LINK_STATUS_CHANGED"; sEvents[EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED] = "EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED"; @@ -118,14 +124,12 @@ public class NetworkTypeController extends StateMachine { sEvents[EVENT_PREFERRED_NETWORK_MODE_CHANGED] = "EVENT_PREFERRED_NETWORK_MODE_CHANGED"; sEvents[EVENT_INITIALIZE] = "EVENT_INITIALIZE"; sEvents[EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED] = "EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED"; - sEvents[EVENT_BANDWIDTH_CHANGED] = "EVENT_BANDWIDTH_CHANGED"; - sEvents[EVENT_UPDATE_NR_ADVANCED_STATE] = "EVENT_UPDATE_NR_ADVANCED_STATE"; sEvents[EVENT_DEVICE_IDLE_MODE_CHANGED] = "EVENT_DEVICE_IDLE_MODE_CHANGED"; } - private final Phone mPhone; - private final DisplayInfoController mDisplayInfoController; - private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + private final @NonNull Phone mPhone; + private final @NonNull DisplayInfoController mDisplayInfoController; + private final @NonNull BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { @@ -144,19 +148,19 @@ public class NetworkTypeController extends StateMachine { } }; - private Map mOverrideTimerRules = new HashMap<>(); - private String mLteEnhancedPattern = ""; - private int mOverrideNetworkType; + private @NonNull Map mOverrideTimerRules = new HashMap<>(); + private @NonNull String mLteEnhancedPattern = ""; + private @Annotation.OverrideNetworkType int mOverrideNetworkType; private boolean mIsPhysicalChannelConfigOn; private boolean mIsPrimaryTimerActive; private boolean mIsSecondaryTimerActive; private boolean mIsTimerResetEnabledForLegacyStateRRCIdle; private int mLtePlusThresholdBandwidth; private int mNrAdvancedThresholdBandwidth; - private int[] mAdditionalNrAdvancedBandsList; - private String mPrimaryTimerState; - private String mSecondaryTimerState; - private String mPreviousState; + private @NonNull int[] mAdditionalNrAdvancedBandsList; + private @NonNull String mPrimaryTimerState; + private @NonNull String mSecondaryTimerState; + private @NonNull String mPreviousState; private @LinkStatus int mPhysicalLinkStatus; private boolean mIsPhysicalChannelConfig16Supported; private boolean mIsNrAdvancedAllowedByPco = false; @@ -168,6 +172,10 @@ public class NetworkTypeController extends StateMachine { private @Nullable DataNetworkControllerCallback mNrAdvancedCapableByPcoChangedCallback = null; private @Nullable DataNetworkControllerCallback mNrPhysicalLinkStatusChangedCallback = null; + // Cached copies below to prevent race conditions + private @NonNull ServiceState mServiceState; + private @Nullable List mPhysicalChannelConfigs; + /** * NetworkTypeController constructor. * @@ -180,13 +188,21 @@ public class NetworkTypeController extends StateMachine { mDisplayInfoController = displayInfoController; mOverrideNetworkType = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; mIsPhysicalChannelConfigOn = true; + mPrimaryTimerState = ""; + mSecondaryTimerState = ""; + mPreviousState = ""; addState(mDefaultState); addState(mLegacyState, mDefaultState); addState(mIdleState, mDefaultState); addState(mLteConnectedState, mDefaultState); addState(mNrConnectedState, mDefaultState); + addState(mNrConnectedAdvancedState, mDefaultState); setInitialState(mDefaultState); start(); + + mServiceState = mPhone.getServiceStateTracker().getServiceState(); + mPhysicalChannelConfigs = mPhone.getServiceStateTracker().getPhysicalChannelConfigList(); + sendMessage(EVENT_INITIALIZE); } @@ -199,10 +215,10 @@ public class NetworkTypeController extends StateMachine { } /** - * @return True if either the primary or secondary 5G hysteresis timer is active, - * and false if neither are. + * @return {@code true} if either the primary or secondary 5G icon timers are active, + * and {@code false} if neither are. */ - public boolean is5GHysteresisActive() { + public boolean areAnyTimersActive() { return mIsPrimaryTimerActive || mIsSecondaryTimerActive; } @@ -213,18 +229,11 @@ public class NetworkTypeController extends StateMachine { EVENT_PREFERRED_NETWORK_MODE_CHANGED, null); mPhone.registerForPhysicalChannelConfig(getHandler(), EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED, null); - mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged( - AccessNetworkConstants.TRANSPORT_TYPE_WWAN, getHandler(), - EVENT_DATA_RAT_CHANGED, null); - mPhone.getServiceStateTracker().registerForBandwidthChanged( - getHandler(), EVENT_BANDWIDTH_CHANGED, null); + mPhone.getServiceStateTracker().registerForServiceStateChanged(getHandler(), + EVENT_SERVICE_STATE_CHANGED, null); mIsPhysicalChannelConfig16Supported = mPhone.getContext().getSystemService( TelephonyManager.class).isRadioInterfaceCapabilitySupported( TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); - mPhone.getServiceStateTracker().registerForNrStateChanged(getHandler(), - EVENT_NR_STATE_CHANGED, null); - mPhone.getServiceStateTracker().registerForNrFrequencyChanged(getHandler(), - EVENT_NR_FREQUENCY_CHANGED, null); mPhone.getDeviceStateMonitor().registerForPhysicalChannelConfigNotifChanged(getHandler(), EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED, null); IntentFilter filter = new IntentFilter(); @@ -236,10 +245,7 @@ public class NetworkTypeController extends StateMachine { private void unRegisterForAllEvents() { mPhone.unregisterForRadioOffOrNotAvailable(getHandler()); mPhone.unregisterForPreferredNetworkTypeChanged(getHandler()); - mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged( - AccessNetworkConstants.TRANSPORT_TYPE_WWAN, getHandler()); - mPhone.getServiceStateTracker().unregisterForNrStateChanged(getHandler()); - mPhone.getServiceStateTracker().unregisterForNrFrequencyChanged(getHandler()); + mPhone.getServiceStateTracker().unregisterForServiceStateChanged(getHandler()); mPhone.getDeviceStateMonitor().unregisterForPhysicalChannelConfigNotifChanged(getHandler()); mPhone.getContext().unregisterReceiver(mIntentReceiver); } @@ -303,11 +309,10 @@ public class NetworkTypeController extends StateMachine { mNrAdvancedCapableByPcoChangedCallback = new DataNetworkControllerCallback(getHandler()::post) { @Override - public void onNrAdvancedCapableByPcoChanged( - boolean nrAdvancedCapable) { + public void onNrAdvancedCapableByPcoChanged(boolean nrAdvancedCapable) { log("mIsNrAdvancedAllowedByPco=" + nrAdvancedCapable); mIsNrAdvancedAllowedByPco = nrAdvancedCapable; - sendMessage(EVENT_UPDATE_NR_ADVANCED_STATE); + sendMessage(EVENT_UPDATE); } }; mPhone.getDataNetworkController().registerDataNetworkControllerCallback( @@ -446,7 +451,7 @@ public class NetworkTypeController extends StateMachine { int displayNetworkType = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; int dataNetworkType = getDataNetworkType(); boolean nrNsa = isLte(dataNetworkType) - && mPhone.getServiceState().getNrState() != NetworkRegistrationInfo.NR_STATE_NONE; + && mServiceState.getNrState() != NetworkRegistrationInfo.NR_STATE_NONE; boolean nrSa = dataNetworkType == TelephonyManager.NETWORK_TYPE_NR; // NR display is not accurate when physical channel config notifications are off @@ -477,7 +482,7 @@ public class NetworkTypeController extends StateMachine { keys.add(STATE_CONNECTED_NR_ADVANCED); } } else { - switch (mPhone.getServiceState().getNrState()) { + switch (mServiceState.getNrState()) { case NetworkRegistrationInfo.NR_STATE_CONNECTED: if (isNrAdvanced()) { keys.add(STATE_CONNECTED_NR_ADVANCED); @@ -507,9 +512,8 @@ public class NetworkTypeController extends StateMachine { private @Annotation.OverrideNetworkType int getLteDisplayType() { int value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; if ((getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA - || mPhone.getServiceState().isUsingCarrierAggregation()) - && (IntStream.of(mPhone.getServiceState().getCellBandwidths()).sum() - > mLtePlusThresholdBandwidth)) { + || mServiceState.isUsingCarrierAggregation()) + && getBandwidth() > mLtePlusThresholdBandwidth) { value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA; } if (isLteEnhancedAvailable()) { @@ -523,8 +527,8 @@ public class NetworkTypeController extends StateMachine { return false; } Pattern stringPattern = Pattern.compile(mLteEnhancedPattern); - for (String opName : new String[] {mPhone.getServiceState().getOperatorAlphaLongRaw(), - mPhone.getServiceState().getOperatorAlphaShortRaw()}) { + for (String opName : new String[] {mServiceState.getOperatorAlphaLongRaw(), + mServiceState.getOperatorAlphaShortRaw()}) { if (!TextUtils.isEmpty(opName)) { Matcher matcher = stringPattern.matcher(opName); if (matcher.find()) { @@ -544,8 +548,6 @@ public class NetworkTypeController extends StateMachine { if (DBG) log("DefaultState: process " + getEventName(msg.what)); switch (msg.what) { case EVENT_UPDATE: - case EVENT_PREFERRED_NETWORK_MODE_CHANGED: - if (DBG) log("Reset timers since preferred network mode changed."); resetAllTimers(); transitionToCurrentState(); break; @@ -562,20 +564,10 @@ public class NetworkTypeController extends StateMachine { registerForAllEvents(); parseCarrierConfigs(); break; - case EVENT_DATA_RAT_CHANGED: - case EVENT_NR_STATE_CHANGED: - case EVENT_NR_FREQUENCY_CHANGED: - case EVENT_UPDATE_NR_ADVANCED_STATE: - // ignored - break; - case EVENT_BANDWIDTH_CHANGED: - // Update in case of LTE/LTE+ switch - updateOverrideNetworkType(); - break; - case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED: - if (isUsingPhysicalChannelConfigForRrcDetection()) { - mPhysicalLinkStatus = getPhysicalLinkStatusFromPhysicalChannelConfig(); - } + case EVENT_SERVICE_STATE_CHANGED: + mServiceState = mPhone.getServiceStateTracker().getServiceState(); + if (DBG) log("ServiceState updated: " + mServiceState); + transitionToCurrentState(); break; case EVENT_PHYSICAL_LINK_STATUS_CHANGED: AsyncResult ar = (AsyncResult) msg.obj; @@ -617,6 +609,20 @@ public class NetworkTypeController extends StateMachine { resetAllTimers(); transitionTo(mLegacyState); break; + case EVENT_PREFERRED_NETWORK_MODE_CHANGED: + if (DBG) log("Reset timers since preferred network mode changed."); + resetAllTimers(); + transitionToCurrentState(); + break; + case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED: + mPhysicalChannelConfigs = + mPhone.getServiceStateTracker().getPhysicalChannelConfigList(); + if (DBG) log("Physical channel configs updated: " + mPhysicalChannelConfigs); + if (isUsingPhysicalChannelConfigForRrcDetection()) { + mPhysicalLinkStatus = getPhysicalLinkStatusFromPhysicalChannelConfig(); + } + transitionToCurrentState(); + break; case EVENT_DEVICE_IDLE_MODE_CHANGED: PowerManager pm = mPhone.getContext().getSystemService(PowerManager.class); mIsDeviceIdleMode = pm.isDeviceIdleMode(); @@ -665,11 +671,19 @@ public class NetworkTypeController extends StateMachine { public boolean processMessage(Message msg) { if (DBG) log("LegacyState: process " + getEventName(msg.what)); updateTimers(); - int rat = getDataNetworkType(); switch (msg.what) { - case EVENT_DATA_RAT_CHANGED: + case EVENT_SERVICE_STATE_CHANGED: + mServiceState = mPhone.getServiceStateTracker().getServiceState(); + if (DBG) log("ServiceState updated: " + mServiceState); + // fallthrough + case EVENT_UPDATE: + int rat = getDataNetworkType(); if (rat == TelephonyManager.NETWORK_TYPE_NR || isLte(rat) && isNrConnected()) { - transitionTo(mNrConnectedState); + if (isNrAdvanced()) { + transitionTo(mNrConnectedAdvancedState); + } else { + transitionTo(mNrConnectedState); + } } else if (isLte(rat) && isNrNotRestricted()) { transitionWithTimerTo(isPhysicalLinkActive() ? mLteConnectedState : mIdleState); @@ -682,21 +696,10 @@ public class NetworkTypeController extends StateMachine { } mIsNrRestricted = isNrRestricted(); break; - case EVENT_NR_STATE_CHANGED: - if (isNrConnected()) { - transitionTo(mNrConnectedState); - } else if (isLte(rat) && isNrNotRestricted()) { - transitionWithTimerTo(isPhysicalLinkActive() - ? mLteConnectedState : mIdleState); - } else if (isLte(rat) && isNrRestricted()) { - updateOverrideNetworkType(); - } - mIsNrRestricted = isNrRestricted(); - break; - case EVENT_NR_FREQUENCY_CHANGED: - // ignored - break; case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED: + mPhysicalChannelConfigs = + mPhone.getServiceStateTracker().getPhysicalChannelConfigList(); + if (DBG) log("Physical channel configs updated: " + mPhysicalChannelConfigs); if (isUsingPhysicalChannelConfigForRrcDetection()) { mPhysicalLinkStatus = getPhysicalLinkStatusFromPhysicalChannelConfig(); if (mIsTimerResetEnabledForLegacyStateRRCIdle && !isPhysicalLinkActive()) { @@ -704,8 +707,6 @@ public class NetworkTypeController extends StateMachine { resetAllTimers(); } } - // Update in case of LTE/LTE+ switch - updateOverrideNetworkType(); break; case EVENT_PHYSICAL_LINK_STATUS_CHANGED: AsyncResult ar = (AsyncResult) msg.obj; @@ -752,52 +753,51 @@ public class NetworkTypeController extends StateMachine { if (DBG) log("IdleState: process " + getEventName(msg.what)); updateTimers(); switch (msg.what) { - case EVENT_DATA_RAT_CHANGED: + case EVENT_SERVICE_STATE_CHANGED: + mServiceState = mPhone.getServiceStateTracker().getServiceState(); + if (DBG) log("ServiceState updated: " + mServiceState); + // fallthrough + case EVENT_UPDATE: int rat = getDataNetworkType(); - if (rat == TelephonyManager.NETWORK_TYPE_NR) { - transitionTo(mNrConnectedState); + if (rat == TelephonyManager.NETWORK_TYPE_NR || isLte(rat) && isNrConnected()) { + if (isNrAdvanced()) { + transitionTo(mNrConnectedAdvancedState); + } else { + transitionTo(mNrConnectedState); + } } else if (!isLte(rat) || !isNrNotRestricted()) { transitionWithTimerTo(mLegacyState); + } else { + if (isPhysicalLinkActive()) { + transitionWithTimerTo(mLteConnectedState); + } else { + // Update in case of LTE/LTE+ switch + updateOverrideNetworkType(); + } } break; - case EVENT_NR_STATE_CHANGED: - if (isNrConnected()) { - transitionTo(mNrConnectedState); - } else if (!isNrNotRestricted()) { - transitionWithTimerTo(mLegacyState); - } - break; - case EVENT_NR_FREQUENCY_CHANGED: - // ignore - break; case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED: + mPhysicalChannelConfigs = + mPhone.getServiceStateTracker().getPhysicalChannelConfigList(); + if (DBG) log("Physical channel configs updated: " + mPhysicalChannelConfigs); if (isUsingPhysicalChannelConfigForRrcDetection()) { mPhysicalLinkStatus = getPhysicalLinkStatusFromPhysicalChannelConfig(); - if (isNrNotRestricted()) { - // NOT_RESTRICTED_RRC_IDLE -> NOT_RESTRICTED_RRC_CON - if (isPhysicalLinkActive()) { - transitionWithTimerTo(mLteConnectedState); - break; - } + if (isPhysicalLinkActive()) { + transitionWithTimerTo(mLteConnectedState); } else { - log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); - sendMessage(EVENT_NR_STATE_CHANGED); + log("Reevaluating state due to link status changed."); + sendMessage(EVENT_UPDATE); } } - // Update in case of LTE/LTE+ switch - updateOverrideNetworkType(); break; case EVENT_PHYSICAL_LINK_STATUS_CHANGED: AsyncResult ar = (AsyncResult) msg.obj; mPhysicalLinkStatus = (int) ar.result; - if (isNrNotRestricted()) { - // NOT_RESTRICTED_RRC_IDLE -> NOT_RESTRICTED_RRC_CON - if (isPhysicalLinkActive()) { - transitionWithTimerTo(mLteConnectedState); - } + if (isPhysicalLinkActive()) { + transitionWithTimerTo(mLteConnectedState); } else { - log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); - sendMessage(EVENT_NR_STATE_CHANGED); + log("Reevaluating state due to link status changed."); + sendMessage(EVENT_UPDATE); } break; default: @@ -836,52 +836,52 @@ public class NetworkTypeController extends StateMachine { if (DBG) log("LteConnectedState: process " + getEventName(msg.what)); updateTimers(); switch (msg.what) { - case EVENT_DATA_RAT_CHANGED: + case EVENT_SERVICE_STATE_CHANGED: + mServiceState = mPhone.getServiceStateTracker().getServiceState(); + if (DBG) log("ServiceState updated: " + mServiceState); + // fallthrough + case EVENT_UPDATE: int rat = getDataNetworkType(); - if (rat == TelephonyManager.NETWORK_TYPE_NR) { - transitionTo(mNrConnectedState); + if (rat == TelephonyManager.NETWORK_TYPE_NR + || (isLte(rat) && isNrConnected())) { + if (isNrAdvanced()) { + transitionTo(mNrConnectedAdvancedState); + } else { + transitionTo(mNrConnectedState); + } } else if (!isLte(rat) || !isNrNotRestricted()) { transitionWithTimerTo(mLegacyState); + } else { + if (!isPhysicalLinkActive()) { + transitionWithTimerTo(mIdleState); + } else { + // Update in case of LTE/LTE+ switch + updateOverrideNetworkType(); + } } break; - case EVENT_NR_STATE_CHANGED: - if (isNrConnected()) { - transitionTo(mNrConnectedState); - } else if (!isNrNotRestricted()) { - transitionWithTimerTo(mLegacyState); - } - break; - case EVENT_NR_FREQUENCY_CHANGED: - // ignore - break; case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED: + mPhysicalChannelConfigs = + mPhone.getServiceStateTracker().getPhysicalChannelConfigList(); + if (DBG) log("Physical channel configs updated: " + mPhysicalChannelConfigs); if (isUsingPhysicalChannelConfigForRrcDetection()) { mPhysicalLinkStatus = getPhysicalLinkStatusFromPhysicalChannelConfig(); - if (isNrNotRestricted()) { - // NOT_RESTRICTED_RRC_CON -> NOT_RESTRICTED_RRC_IDLE - if (!isPhysicalLinkActive()) { - transitionWithTimerTo(mIdleState); - break; - } + if (!isPhysicalLinkActive()) { + transitionWithTimerTo(mIdleState); } else { - log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); - sendMessage(EVENT_NR_STATE_CHANGED); + log("Reevaluating state due to link status changed."); + sendMessage(EVENT_UPDATE); } } - // Update in case of LTE/LTE+ switch - updateOverrideNetworkType(); break; case EVENT_PHYSICAL_LINK_STATUS_CHANGED: AsyncResult ar = (AsyncResult) msg.obj; mPhysicalLinkStatus = (int) ar.result; - if (isNrNotRestricted()) { - // NOT_RESTRICTED_RRC_CON -> NOT_RESTRICTED_RRC_IDLE - if (!isPhysicalLinkActive()) { - transitionWithTimerTo(mIdleState); - } + if (!isPhysicalLinkActive()) { + transitionWithTimerTo(mIdleState); } else { - log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); - sendMessage(EVENT_NR_STATE_CHANGED); + log("Reevaluating state due to link status changed."); + sendMessage(EVENT_UPDATE); } break; default: @@ -905,28 +905,33 @@ public class NetworkTypeController extends StateMachine { * Device is connected to 5G NR as the primary or secondary cell. */ private final class NrConnectedState extends State { - private boolean mIsNrAdvanced = false; - @Override public void enter() { - if (DBG) log("Entering NrConnectedState(" + getName() + ")"); + if (DBG) log("Entering NrConnectedState"); updateTimers(); updateOverrideNetworkType(); if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { - mIsNrAdvanced = isNrAdvanced(); mPreviousState = getName(); } } @Override public boolean processMessage(Message msg) { - if (DBG) log("NrConnectedState(" + getName() + "): process " + getEventName(msg.what)); + if (DBG) log("NrConnectedState: process " + getEventName(msg.what)); updateTimers(); - int rat = getDataNetworkType(); switch (msg.what) { - case EVENT_DATA_RAT_CHANGED: + case EVENT_SERVICE_STATE_CHANGED: + mServiceState = mPhone.getServiceStateTracker().getServiceState(); + if (DBG) log("ServiceState updated: " + mServiceState); + // fallthrough + case EVENT_UPDATE: + int rat = getDataNetworkType(); if (rat == TelephonyManager.NETWORK_TYPE_NR || isLte(rat) && isNrConnected()) { - updateOverrideNetworkType(); + if (isNrAdvanced()) { + transitionTo(mNrConnectedAdvancedState); + } else { + // Same NR connected state + } } else if (isLte(rat) && isNrNotRestricted()) { transitionWithTimerTo(isPhysicalLinkActive() ? mLteConnectedState : mIdleState); @@ -934,34 +939,94 @@ public class NetworkTypeController extends StateMachine { transitionWithTimerTo(mLegacyState); } break; - case EVENT_NR_STATE_CHANGED: - if (isLte(rat) && isNrNotRestricted()) { + case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED: + mPhysicalChannelConfigs = + mPhone.getServiceStateTracker().getPhysicalChannelConfigList(); + if (DBG) log("Physical channel configs updated: " + mPhysicalChannelConfigs); + if (isUsingPhysicalChannelConfigForRrcDetection()) { + mPhysicalLinkStatus = getPhysicalLinkStatusFromPhysicalChannelConfig(); + } + // Check NR advanced in case NR advanced bands were added + if (isNrAdvanced()) { + transitionTo(mNrConnectedAdvancedState); + } + break; + case EVENT_PHYSICAL_LINK_STATUS_CHANGED: + AsyncResult ar = (AsyncResult) msg.obj; + mPhysicalLinkStatus = (int) ar.result; + break; + default: + return NOT_HANDLED; + } + if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { + mPreviousState = getName(); + } + return HANDLED; + } + + @Override + public String getName() { + return STATE_CONNECTED; + } + } + + private final NrConnectedState mNrConnectedState = new NrConnectedState(); + + /** + * Device is connected to 5G NR as the primary cell and the data rate is higher than + * the generic 5G data rate. + */ + private final class NrConnectedAdvancedState extends State { + @Override + public void enter() { + if (DBG) log("Entering NrConnectedAdvancedState"); + updateTimers(); + updateOverrideNetworkType(); + if (!mIsPrimaryTimerActive && !mIsSecondaryTimerActive) { + mPreviousState = getName(); + } + } + + @Override + public boolean processMessage(Message msg) { + if (DBG) log("NrConnectedAdvancedState: process " + getEventName(msg.what)); + updateTimers(); + switch (msg.what) { + case EVENT_SERVICE_STATE_CHANGED: + mServiceState = mPhone.getServiceStateTracker().getServiceState(); + if (DBG) log("ServiceState updated: " + mServiceState); + // fallthrough + case EVENT_UPDATE: + int rat = getDataNetworkType(); + if (rat == TelephonyManager.NETWORK_TYPE_NR + || (isLte(rat) && isNrConnected())) { + if (isNrAdvanced()) { + // Same NR advanced state + } else { + transitionWithTimerTo(mNrConnectedState); + } + } else if (isLte(rat) && isNrNotRestricted()) { transitionWithTimerTo(isPhysicalLinkActive() ? mLteConnectedState : mIdleState); - } else if (rat != TelephonyManager.NETWORK_TYPE_NR && !isNrConnected()) { + } else { transitionWithTimerTo(mLegacyState); } break; - case EVENT_UPDATE_NR_ADVANCED_STATE: - updateNrAdvancedState(); - break; - case EVENT_NR_FREQUENCY_CHANGED: case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED: + mPhysicalChannelConfigs = + mPhone.getServiceStateTracker().getPhysicalChannelConfigList(); + if (DBG) log("Physical channel configs updated: " + mPhysicalChannelConfigs); if (isUsingPhysicalChannelConfigForRrcDetection()) { mPhysicalLinkStatus = getPhysicalLinkStatusFromPhysicalChannelConfig(); } - updateNrAdvancedState(); + // Check NR advanced in case NR advanced bands were removed + if (!isNrAdvanced()) { + transitionWithTimerTo(mNrConnectedState); + } break; case EVENT_PHYSICAL_LINK_STATUS_CHANGED: AsyncResult ar = (AsyncResult) msg.obj; mPhysicalLinkStatus = (int) ar.result; - if (!isNrConnected()) { - log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); - sendMessage(EVENT_NR_STATE_CHANGED); - } - break; - case EVENT_BANDWIDTH_CHANGED: - updateNrAdvancedState(); break; default: return NOT_HANDLED; @@ -974,32 +1039,12 @@ public class NetworkTypeController extends StateMachine { @Override public String getName() { - return mIsNrAdvanced ? STATE_CONNECTED_NR_ADVANCED : STATE_CONNECTED; - } - - private void updateNrAdvancedState() { - log("updateNrAdvancedState"); - if (!isNrConnected() && getDataNetworkType() != TelephonyManager.NETWORK_TYPE_NR) { - log("NR state changed. Sending EVENT_NR_STATE_CHANGED"); - sendMessage(EVENT_NR_STATE_CHANGED); - return; - } - boolean isNrAdvanced = isNrAdvanced(); - if (isNrAdvanced != mIsNrAdvanced) { - if (!isNrAdvanced) { - if (DBG) log("updateNrAdvancedState: CONNECTED_NR_ADVANCED -> CONNECTED"); - transitionWithTimerTo(mNrConnectedState); - } else { - if (DBG) log("updateNrAdvancedState: CONNECTED -> CONNECTED_NR_ADVANCED"); - transitionTo(mNrConnectedState); - } - } - mIsNrAdvanced = isNrAdvanced(); - log("mIsNrAdvanced=" + mIsNrAdvanced); + return STATE_CONNECTED_NR_ADVANCED; } } - private final NrConnectedState mNrConnectedState = new NrConnectedState(); + private final NrConnectedAdvancedState mNrConnectedAdvancedState = + new NrConnectedAdvancedState(); private void transitionWithTimerTo(IState destState) { String destName = destState.getName(); @@ -1038,22 +1083,23 @@ public class NetworkTypeController extends StateMachine { private void transitionToCurrentState() { int dataRat = getDataNetworkType(); IState transitionState; - if (dataRat == TelephonyManager.NETWORK_TYPE_NR || isNrConnected()) { - transitionState = mNrConnectedState; - mPreviousState = isNrAdvanced() ? STATE_CONNECTED_NR_ADVANCED : STATE_CONNECTED; + if (dataRat == TelephonyManager.NETWORK_TYPE_NR || (isLte(dataRat) && isNrConnected())) { + if (isNrAdvanced()) { + transitionState = mNrConnectedAdvancedState; + } else { + transitionState = mNrConnectedState; + } } else if (isLte(dataRat) && isNrNotRestricted()) { if (isPhysicalLinkActive()) { transitionState = mLteConnectedState; - mPreviousState = STATE_NOT_RESTRICTED_RRC_CON; } else { transitionState = mIdleState; - mPreviousState = STATE_NOT_RESTRICTED_RRC_IDLE; } } else { transitionState = mLegacyState; - mPreviousState = isNrRestricted() ? STATE_RESTRICTED : STATE_LEGACY; } if (!transitionState.equals(getCurrentState())) { + mPreviousState = getCurrentState().getName(); transitionTo(transitionState); } else { updateOverrideNetworkType(); @@ -1198,17 +1244,15 @@ public class NetworkTypeController extends StateMachine { } private boolean isNrConnected() { - return mPhone.getServiceState().getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED; + return mServiceState.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED; } private boolean isNrNotRestricted() { - return mPhone.getServiceState().getNrState() - == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED; + return mServiceState.getNrState() == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED; } private boolean isNrRestricted() { - return mPhone.getServiceState().getNrState() - == NetworkRegistrationInfo.NR_STATE_RESTRICTED; + return mServiceState.getNrState() == NetworkRegistrationInfo.NR_STATE_RESTRICTED; } /** @@ -1223,15 +1267,13 @@ public class NetworkTypeController extends StateMachine { // Check if NR advanced is enabled when the device is roaming. Some carriers disable it // while the device is roaming. - if (mPhone.getServiceState().getDataRoaming() && !mEnableNrAdvancedWhileRoaming) { + if (mServiceState.getDataRoaming() && !mEnableNrAdvancedWhileRoaming) { return false; } // Check if meeting minimum bandwidth requirement. For most carriers, there is no minimum // bandwidth requirement and mNrAdvancedThresholdBandwidth is 0. - if (mNrAdvancedThresholdBandwidth > 0 - && IntStream.of(mPhone.getServiceState().getCellBandwidths()).sum() - < mNrAdvancedThresholdBandwidth) { + if (mNrAdvancedThresholdBandwidth > 0 && getBandwidth() < mNrAdvancedThresholdBandwidth) { return false; } @@ -1241,18 +1283,15 @@ public class NetworkTypeController extends StateMachine { } private boolean isNrMmwave() { - return mPhone.getServiceState().getNrFrequencyRange() - == ServiceState.FREQUENCY_RANGE_MMWAVE; + return mServiceState.getNrFrequencyRange() == ServiceState.FREQUENCY_RANGE_MMWAVE; } private boolean isAdditionalNrAdvancedBand() { - List physicalChannelConfigList = - mPhone.getServiceStateTracker().getPhysicalChannelConfigList(); if (ArrayUtils.isEmpty(mAdditionalNrAdvancedBandsList) - || physicalChannelConfigList == null) { + || mPhysicalChannelConfigs == null) { return false; } - for (PhysicalChannelConfig item : physicalChannelConfigList) { + for (PhysicalChannelConfig item : mPhysicalChannelConfigs) { if (item.getNetworkType() == TelephonyManager.NETWORK_TYPE_NR && ArrayUtils.contains(mAdditionalNrAdvancedBandsList, item.getBand())) { return true; @@ -1271,19 +1310,21 @@ public class NetworkTypeController extends StateMachine { } private int getPhysicalLinkStatusFromPhysicalChannelConfig() { - List physicalChannelConfigList = - mPhone.getServiceStateTracker().getPhysicalChannelConfigList(); - return (physicalChannelConfigList == null || physicalChannelConfigList.isEmpty()) + return (mPhysicalChannelConfigs == null || mPhysicalChannelConfigs.isEmpty()) ? DataCallResponse.LINK_STATUS_DORMANT : DataCallResponse.LINK_STATUS_ACTIVE; } private int getDataNetworkType() { - NetworkRegistrationInfo nri = mPhone.getServiceState().getNetworkRegistrationInfo( + NetworkRegistrationInfo nri = mServiceState.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); return nri == null ? TelephonyManager.NETWORK_TYPE_UNKNOWN : nri.getAccessNetworkTechnology(); } + private int getBandwidth() { + return IntStream.of(mServiceState.getCellBandwidths()).sum(); + } + private String getEventName(int event) { try { return sEvents[event]; diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index d33d00a333..31716ff43b 100755 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -216,7 +216,6 @@ public class ServiceStateTracker extends Handler { private RegistrantList mNrStateChangedRegistrants = new RegistrantList(); private RegistrantList mNrFrequencyChangedRegistrants = new RegistrantList(); private RegistrantList mCssIndicatorChangedRegistrants = new RegistrantList(); - private final RegistrantList mBandwidthChangedRegistrants = new RegistrantList(); private final RegistrantList mAirplaneModeChangedRegistrants = new RegistrantList(); private final RegistrantList mAreaCodeChangedRegistrants = new RegistrantList(); @@ -1651,6 +1650,7 @@ public class ServiceStateTracker extends Handler { // Notify NR frequency, NR connection status or bandwidths changed. if (hasChanged) { mPhone.notifyServiceStateChanged(mPhone.getServiceState()); + mServiceStateChangedRegistrants.notifyRegistrants(); TelephonyMetrics.getInstance().writeServiceStateChanged( mPhone.getPhoneId(), mSS); mPhone.getVoiceCallSessionStats().onServiceStateChanged(mSS); @@ -2066,16 +2066,20 @@ public class ServiceStateTracker extends Handler { if (physicalChannelConfigs != null) { for (PhysicalChannelConfig config : physicalChannelConfigs) { if (isNrPhysicalChannelConfig(config) && isInternetPhysicalChannelConfig(config)) { - // Update the NR frequency range if there is an internet data connection + // Update the NR frequency range if there is an active internet data connection // associated with this NR physical channel channel config. - newFrequencyRange = ServiceState.getBetterNRFrequencyRange( - newFrequencyRange, config.getFrequencyRange()); - break; + // If there are multiple valid configs, use the highest frequency range value. + newFrequencyRange = Math.max(newFrequencyRange, config.getFrequencyRange()); } } } boolean hasChanged = newFrequencyRange != ss.getNrFrequencyRange(); + if (hasChanged) { + log(String.format("NR frequency range changed from %s to %s.", + ServiceState.frequencyRangeToString(ss.getNrFrequencyRange()), + ServiceState.frequencyRangeToString(newFrequencyRange))); + } ss.setNrFrequencyRange(newFrequencyRange); return hasChanged; } @@ -2106,6 +2110,11 @@ public class ServiceStateTracker extends Handler { } boolean hasChanged = newNrState != oldNrState; + if (hasChanged) { + log(String.format("NR state changed from %s to %s.", + NetworkRegistrationInfo.nrStateToString(oldNrState), + NetworkRegistrationInfo.nrStateToString(newNrState))); + } regInfo.setNrState(newNrState); ss.addNetworkRegistrationInfo(regInfo); return hasChanged; @@ -3676,10 +3685,6 @@ public class ServiceStateTracker extends Handler { mCssIndicatorChangedRegistrants.notifyRegistrants(); } - if (hasBandwidthChanged) { - mBandwidthChangedRegistrants.notifyRegistrants(); - } - if (hasRejectCauseChanged) { setNotification(CS_REJECT_CAUSE_ENABLED); } @@ -5834,25 +5839,6 @@ public class ServiceStateTracker extends Handler { mCssIndicatorChangedRegistrants.remove(h); } - /** - * Registers for cell bandwidth changed. - * @param h handler to notify - * @param what what code of message when delivered - * @param obj placed in Message.obj - */ - public void registerForBandwidthChanged(Handler h, int what, Object obj) { - Registrant r = new Registrant(h, what, obj); - mBandwidthChangedRegistrants.add(r); - } - - /** - * Unregisters for cell bandwidth changed. - * @param h handler to notify - */ - public void unregisterForBandwidthChanged(Handler h) { - mBandwidthChangedRegistrants.remove(h); - } - /** * Get the NR data connection context ids. * diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index 4b0cc6196c..91d936d7cf 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -50,7 +50,6 @@ import com.android.internal.util.StateMachine; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -61,21 +60,9 @@ import java.util.List; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper -@Ignore("b/240911460") public class NetworkTypeControllerTest extends TelephonyTest { - // private constants copied over from NetworkTypeController - private static final int EVENT_DATA_RAT_CHANGED = 2; - private static final int EVENT_NR_STATE_CHANGED = 3; - private static final int EVENT_NR_FREQUENCY_CHANGED = 4; - private static final int EVENT_PHYSICAL_LINK_STATUS_CHANGED = 5; - private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED = 6; - private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 10; - private static final int EVENT_PREFERRED_NETWORK_MODE_CHANGED = 11; - private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 13; - private NetworkTypeController mNetworkTypeController; private PersistableBundle mBundle; - private DataNetworkControllerCallback mDataNetworkControllerCallback; private IState getCurrentState() throws Exception { Method method = StateMachine.class.getDeclaredMethod("getCurrentState"); @@ -104,7 +91,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { mBundle.putString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING, "connected_mmwave:5G_Plus,connected:5G,not_restricted_rrc_idle:5G," + "not_restricted_rrc_con:5G"); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); replaceInstance(Handler.class, "mLooper", mDisplayInfoController, Looper.myLooper()); @@ -116,12 +102,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(new int[] {0}).when(mServiceState).getCellBandwidths(); mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); processAllMessages(); - - ArgumentCaptor dataNetworkControllerCallbackCaptor = - ArgumentCaptor.forClass(DataNetworkControllerCallback.class); - verify(mDataNetworkController).registerDataNetworkControllerCallback( - dataNetworkControllerCallbackCaptor.capture()); - mDataNetworkControllerCallback = dataNetworkControllerCallbackCaptor.getValue(); } @After @@ -263,8 +243,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { public void testTransitionToCurrentStateLegacy() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); doReturn(TelephonyManager.NETWORK_TYPE_HSPAP).when(mServiceState).getDataNetworkType(); - - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("legacy", getCurrentState().getName()); } @@ -274,8 +253,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("DefaultState", getCurrentState().getName()); doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(mServiceState).getNrState(); - - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("restricted", getCurrentState().getName()); } @@ -285,9 +263,9 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("DefaultState", getCurrentState().getName()); doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_DORMANT, null)); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("not_restricted_rrc_idle", getCurrentState().getName()); } @@ -299,11 +277,12 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); + doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); setPhysicalLinkStatus(false); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("not_restricted_rrc_idle", getCurrentState().getName()); } @@ -318,14 +297,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { broadcastCarrierConfigs(); processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); + doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_DORMANT, null)); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); - + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals("not_restricted_rrc_idle", getCurrentState().getName()); } @@ -334,9 +312,9 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("DefaultState", getCurrentState().getName()); doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_ACTIVE, null)); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("not_restricted_rrc_con", getCurrentState().getName()); } @@ -350,11 +328,12 @@ public class NetworkTypeControllerTest extends TelephonyTest { broadcastCarrierConfigs(); processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); + doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); setPhysicalLinkStatus(true); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("not_restricted_rrc_con", getCurrentState().getName()); } @@ -370,14 +349,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { broadcastCarrierConfigs(); processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); + doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_ACTIVE, null)); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); - + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals("not_restricted_rrc_con", getCurrentState().getName()); } @@ -387,7 +365,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected", getCurrentState().getName()); } @@ -399,7 +377,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } @@ -422,7 +400,8 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } @@ -445,7 +424,8 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected", getCurrentState().getName()); } @@ -456,10 +436,9 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } @@ -473,8 +452,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); - mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(false); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + + ArgumentCaptor dataNetworkControllerCallbackCaptor = + ArgumentCaptor.forClass(DataNetworkControllerCallback.class); + verify(mDataNetworkController).registerDataNetworkControllerCallback( + dataNetworkControllerCallbackCaptor.capture()); + DataNetworkControllerCallback callback = dataNetworkControllerCallbackCaptor.getValue(); + callback.onNrAdvancedCapableByPcoChanged(false); processAllMessages(); assertEquals("connected", getCurrentState().getName()); } @@ -489,8 +473,12 @@ public class NetworkTypeControllerTest extends TelephonyTest { mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF00); broadcastCarrierConfigs(); - mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(false); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + ArgumentCaptor dataNetworkControllerCallbackCaptor = + ArgumentCaptor.forClass(DataNetworkControllerCallback.class); + verify(mDataNetworkController).registerDataNetworkControllerCallback( + dataNetworkControllerCallbackCaptor.capture()); + DataNetworkControllerCallback callback = dataNetworkControllerCallbackCaptor.getValue(); + callback.onNrAdvancedCapableByPcoChanged(false); processAllMessages(); assertEquals("connected", getCurrentState().getName()); } @@ -505,9 +493,12 @@ public class NetworkTypeControllerTest extends TelephonyTest { mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); - processAllMessages(); - mDataNetworkControllerCallback.onNrAdvancedCapableByPcoChanged(true); + ArgumentCaptor dataNetworkControllerCallbackCaptor = + ArgumentCaptor.forClass(DataNetworkControllerCallback.class); + verify(mDataNetworkController).registerDataNetworkControllerCallback( + dataNetworkControllerCallbackCaptor.capture()); + DataNetworkControllerCallback callback = dataNetworkControllerCallbackCaptor.getValue(); + callback.onNrAdvancedCapableByPcoChanged(true); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } @@ -518,7 +509,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_DATA_RAT_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected", getCurrentState().getName()); } @@ -528,7 +519,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { testTransitionToCurrentStateNrConnected(); doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("restricted", getCurrentState().getName()); } @@ -539,9 +530,8 @@ public class NetworkTypeControllerTest extends TelephonyTest { testTransitionToCurrentStateNrConnectedMmwave(); doReturn(ServiceState.FREQUENCY_RANGE_LOW).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals("connected", getCurrentState().getName()); } @@ -551,9 +541,8 @@ public class NetworkTypeControllerTest extends TelephonyTest { testTransitionToCurrentStateNrConnected(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals("connected_mmwave", getCurrentState().getName()); } @@ -562,12 +551,11 @@ public class NetworkTypeControllerTest extends TelephonyTest { testTransitionToCurrentStateNrConnectedMmwave(); doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_ACTIVE, null)); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals("not_restricted_rrc_con", getCurrentState().getName()); } @@ -582,9 +570,8 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); setPhysicalLinkStatus(true); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); @@ -605,10 +592,9 @@ public class NetworkTypeControllerTest extends TelephonyTest { testTransitionToCurrentStateNrConnectedMmwave(); doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_ACTIVE, null)); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); @@ -625,7 +611,8 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(true).when(mServiceState).isUsingCarrierAggregation(); doReturn(new int[] {30000}).when(mServiceState).getCellBandwidths(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED); + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA, @@ -643,9 +630,9 @@ public class NetworkTypeControllerTest extends TelephonyTest { // Transition to LTE connected state doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_ACTIVE, null)); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("not_restricted_rrc_con", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, @@ -654,7 +641,8 @@ public class NetworkTypeControllerTest extends TelephonyTest { // LTE -> LTE+ doReturn(true).when(mServiceState).isUsingCarrierAggregation(); doReturn(new int[] {30000}).when(mServiceState).getCellBandwidths(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED); + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA, @@ -672,9 +660,9 @@ public class NetworkTypeControllerTest extends TelephonyTest { // Transition to idle state doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_DORMANT, null)); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("not_restricted_rrc_idle", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, @@ -683,7 +671,8 @@ public class NetworkTypeControllerTest extends TelephonyTest { // LTE -> LTE+ doReturn(true).when(mServiceState).isUsingCarrierAggregation(); doReturn(new int[] {30000}).when(mServiceState).getCellBandwidths(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED); + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA, @@ -694,7 +683,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { public void testEventPhysicalLinkStatusChanged() throws Exception { testTransitionToCurrentStateLteConnected(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_DORMANT, null)); processAllMessages(); @@ -712,8 +701,8 @@ public class NetworkTypeControllerTest extends TelephonyTest { testTransitionToCurrentStateLteConnectedSupportPhysicalChannelConfig1_6(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); setPhysicalLinkStatus(false); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED); - + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("not_restricted_rrc_idle", getCurrentState().getName()); @@ -731,7 +720,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { processAllMessages(); testTransitionToCurrentStateLteConnected_usingUserDataForRrcDetection(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_DORMANT, null)); processAllMessages(); @@ -745,7 +734,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - mNetworkTypeController.sendMessage(EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED, + mNetworkTypeController.sendMessage(5 /* EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED */, new AsyncResult(null, false, null)); processAllMessages(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, @@ -761,7 +750,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getDataNetworkType(); - mNetworkTypeController.sendMessage(EVENT_RADIO_OFF_OR_UNAVAILABLE); + mNetworkTypeController.sendMessage(9 /* EVENT_RADIO_OFF_OR_UNAVAILABLE */); processAllMessages(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, mNetworkTypeController.getOverrideNetworkType()); @@ -778,7 +767,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { TelephonyManager.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA)).when( mPhone).getCachedAllowedNetworkTypesBitmask(); - mNetworkTypeController.sendMessage(EVENT_PREFERRED_NETWORK_MODE_CHANGED); + mNetworkTypeController.sendMessage(10 /* EVENT_PREFERRED_NETWORK_MODE_CHANGED */); processAllMessages(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, mNetworkTypeController.getOverrideNetworkType()); @@ -798,13 +787,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { // should trigger 10 second timer doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // timer expires moveTimeForward(10 * 1000); @@ -813,7 +802,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } @Test @@ -829,7 +818,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { new Handler(Looper.myLooper())); doReturn(pm).when(mContext).getSystemService(Context.POWER_SERVICE); doReturn(true).when(powerManager).isDeviceIdleMode(); - mNetworkTypeController.sendMessage(17 /*EVENT_DEVICE_IDLE_MODE_CHANGED*/); + mNetworkTypeController.sendMessage(12 /* EVENT_DEVICE_IDLE_MODE_CHANGED */); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, @@ -837,13 +826,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { // should not trigger timer doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } @Test @@ -860,17 +849,17 @@ public class NetworkTypeControllerTest extends TelephonyTest { // trigger 10 second timer after disconnecting from NR doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // reconnect to NR in the middle of the timer doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); // timer expires moveTimeForward(10 * 1000); @@ -880,7 +869,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } @Test @@ -903,14 +892,14 @@ public class NetworkTypeControllerTest extends TelephonyTest { // trigger 10 second timer after disconnecting from NR, and then it does the timer reset // since the network mode without the NR capability. doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); // timer should be reset. assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } @Test @@ -928,13 +917,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { // should trigger 10 second timer doReturn(ServiceState.FREQUENCY_RANGE_LOW).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // timer expires moveTimeForward(10 * 1000); @@ -943,7 +932,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } @Test @@ -961,17 +950,17 @@ public class NetworkTypeControllerTest extends TelephonyTest { // trigger 10 second timer after disconnecting from NR doReturn(ServiceState.FREQUENCY_RANGE_LOW).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // reconnect to NR in the middle of the timer doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); // timer expires moveTimeForward(10 * 1000); @@ -981,7 +970,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected_mmwave", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } @Test @@ -1000,13 +989,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { // should trigger 10 second primary timer doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // primary timer expires moveTimeForward(10 * 1000); @@ -1016,7 +1005,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // secondary timer expires moveTimeForward(30 * 1000); @@ -1025,7 +1014,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } @Test @@ -1044,13 +1033,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { // should trigger 10 second primary timer doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // primary timer expires moveTimeForward(10 * 1000); @@ -1060,11 +1049,11 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // reconnect to NR in the middle of the timer doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_NR_STATE_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); // secondary timer expires moveTimeForward(30 * 1000); @@ -1074,7 +1063,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } @Test @@ -1094,13 +1083,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { // should trigger 10 second primary timer doReturn(ServiceState.FREQUENCY_RANGE_LOW).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // primary timer expires moveTimeForward(10 * 1000); @@ -1110,7 +1099,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // secondary timer expires moveTimeForward(30 * 1000); @@ -1119,7 +1108,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } @Test @@ -1139,13 +1128,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { // should trigger 10 second primary timer doReturn(ServiceState.FREQUENCY_RANGE_LOW).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // primary timer expires moveTimeForward(10 * 1000); @@ -1155,11 +1144,11 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // reconnect to NR in the middle of the timer doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); // secondary timer expires moveTimeForward(30 * 1000); @@ -1169,7 +1158,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected_mmwave", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } @Test @@ -1189,13 +1178,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { // should trigger 10 second primary timer doReturn(ServiceState.FREQUENCY_RANGE_LOW).when(mServiceState).getNrFrequencyRange(); - mNetworkTypeController.sendMessage(EVENT_NR_FREQUENCY_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); - assertTrue(mNetworkTypeController.is5GHysteresisActive()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); // rat is UMTS, should stop timer NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() @@ -1204,13 +1193,13 @@ public class NetworkTypeControllerTest extends TelephonyTest { .build(); doReturn(nri).when(mServiceState).getNetworkRegistrationInfo(anyInt(), anyInt()); doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); - mNetworkTypeController.sendMessage(EVENT_DATA_RAT_CHANGED); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("legacy", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, mNetworkTypeController.getOverrideNetworkType()); - assertFalse(mNetworkTypeController.is5GHysteresisActive()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); } private void setPhysicalLinkStatus(Boolean state) { @@ -1240,7 +1229,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected", getCurrentState().getName()); } @@ -1255,7 +1244,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } @@ -1270,7 +1259,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { mBundle.putBoolean(CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL, false); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected", getCurrentState().getName()); } -- GitLab From 47ee601faf9d4a393ff974adc51fb38bea9fc525 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 9 Nov 2022 00:33:04 -0800 Subject: [PATCH 168/656] RadioAccessSpecifier converter don't return null Test: atest FrameworksTelephonyTests Bug: 213406795 Change-Id: Id616ce2d755e614a4a0714fc7466d6f1886b49c1 --- src/java/com/android/internal/telephony/RILUtils.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index c05b669295..9d8e487fbb 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -1331,8 +1331,6 @@ public class RILUtils { case AccessNetworkConstants.AccessNetworkType.EUTRAN: rasInHalFormat.eutranBands = bands; break; - default: - return null; } if (ras.getChannels() != null) { @@ -1376,8 +1374,6 @@ public class RILUtils { case AccessNetworkConstants.AccessNetworkType.NGRAN: bandsInHalFormat.ngranBands(bands); break; - default: - return null; } rasInHalFormat.bands = bandsInHalFormat; @@ -1424,8 +1420,6 @@ public class RILUtils { case AccessNetworkConstants.AccessNetworkType.NGRAN: bandsInHalFormat.setNgranBands(bands); break; - default: - return null; } rasInHalFormat.bands = bandsInHalFormat; -- GitLab From ab287e8859104c22766e20d5aeefc10967bab499 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 9 Nov 2022 14:14:38 -0800 Subject: [PATCH 169/656] Update tests for DataCallResponse Test equals and hash code Test: atest DataCallResponseTest Bug: 257975797 Change-Id: Ib23c650473659f57a8f6ae540954c0dc7636d339 --- .../telephony/data/DataCallResponseTest.java | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java index 92cf861b33..4b5189a0a9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataCallResponseTest.java @@ -34,6 +34,7 @@ public class DataCallResponseTest extends AndroidTestCase { private static final String FAKE_ADDRESS = "99.88.77.66"; private static final String FAKE_DNS = "55.66.77.88"; private static final String FAKE_DNN = "FAKE_DNN"; + private static final String FAKE_DNN_2 = "FAKE_DNN_2"; private static final String FAKE_GATEWAY = "11.22.33.44"; private static final String FAKE_IFNAME = "FAKE IFNAME"; private static final String FAKE_PCSCF_ADDRESS = "22.33.44.55"; @@ -81,7 +82,7 @@ public class DataCallResponseTest extends AndroidTestCase { } @SmallTest - public void testEquals() { + public void testEqualsAndHashCode() { DataCallResponse response = new DataCallResponse.Builder() .setCause(0) .setRetryDurationMillis(-1L) @@ -122,6 +123,7 @@ public class DataCallResponseTest extends AndroidTestCase { assertEquals(response, response); assertEquals(response, response1); + assertEquals(response.hashCode(), response1.hashCode()); DataCallResponse response2 = new DataCallResponse.Builder() .setCause(1) @@ -140,12 +142,39 @@ public class DataCallResponseTest extends AndroidTestCase { InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) .setMtuV4(1441) .setMtuV6(1440) - .setTrafficDescriptors( - Arrays.asList(new TrafficDescriptor("FAKE_DNN_2", FAKE_OS_APP_ID_2))) + .setTrafficDescriptors(Arrays.asList( + new TrafficDescriptor(FAKE_DNN, FAKE_OS_APP_ID), + new TrafficDescriptor(FAKE_DNN_2, FAKE_OS_APP_ID_2))) .build(); assertNotSame(response1, response2); assertNotSame(response1, null); assertNotSame(response1, new String[1]); + assertNotSame(response1.hashCode(), response2.hashCode()); + + DataCallResponse response3 = new DataCallResponse.Builder() + .setCause(1) + .setRetryDurationMillis(-1L) + .setId(1) + .setLinkStatus(3) + .setProtocolType(ApnSetting.PROTOCOL_IP) + .setInterfaceName(FAKE_IFNAME) + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS), + InetAddresses.parseNumericAddress(FAKE_DNS))) + .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY))) + .setPcscfAddresses(Arrays.asList( + InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS), + InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS))) + .setMtuV4(1441) + .setMtuV6(1440) + .setTrafficDescriptors(Arrays.asList( + new TrafficDescriptor(FAKE_DNN_2, FAKE_OS_APP_ID_2), + new TrafficDescriptor(FAKE_DNN, FAKE_OS_APP_ID))) + .build(); + + assertEquals(response2, response3); + assertEquals(response2.hashCode(), response3.hashCode()); } } -- GitLab From 44c84a6f506bc44bfc55edc366b8131f2d677749 Mon Sep 17 00:00:00 2001 From: sparvathy Date: Tue, 18 Oct 2022 17:43:27 +0000 Subject: [PATCH 170/656] (Emergency call routing type) Determined routing type for emergency numbers Default set as emergency call. Based on the value of is_normal_routing field from database routing type is modified. If is_normal_routing is true and mnc list is null then normal routing. If list of mnc not null then normal routing only for those mnc's. support to use DB routing while merging of duplicate numbers. Test: atest EmergencyNumberTrackerTest & emergency call test in device Bug: 238359415 Change-Id: I907939de6b0c281c51e457ed4b4400af9384191b --- .../emergency/EmergencyNumberTracker.java | 185 +++++++++++++++-- tests/telephonytests/assets/eccdata | Bin 51 -> 96 bytes tests/telephonytests/assets/eccdata_input.txt | 51 +++++ .../emergency/EmergencyNumberTest.java | 31 ++- .../emergency/EmergencyNumberTrackerTest.java | 195 +++++++++++++++++- 5 files changed, 440 insertions(+), 22 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index f9837df333..fd09f340cf 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -30,6 +30,7 @@ import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.SystemProperties; import android.telephony.CarrierConfigManager; +import android.telephony.CellIdentity; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; @@ -38,6 +39,8 @@ import android.telephony.emergency.EmergencyNumber; import android.telephony.emergency.EmergencyNumber.EmergencyCallRouting; import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories; import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; @@ -70,6 +73,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Set; import java.util.zip.GZIPInputStream; /** @@ -104,6 +109,11 @@ public class EmergencyNumberTracker extends Handler { private int mCurrentDatabaseVersion = INVALID_DATABASE_VERSION; private boolean mIsHalVersionLessThan1Dot4 = false; private Resources mResources = null; + /** + * Used for storing all specific mnc's along with the list of emergency numbers + * for which normal routing should be supported. + */ + private Map> mNormalRoutedNumbers = new ArrayMap<>(); /** * Indicates if the country iso is set by another subscription. @@ -415,7 +425,8 @@ public class EmergencyNumberTracker extends Handler { EVENT_OVERRIDE_OTA_EMERGENCY_NUMBER_DB_FILE_PATH, null).sendToTarget(); } - private EmergencyNumber convertEmergencyNumberFromEccInfo(EccInfo eccInfo, String countryIso) { + private EmergencyNumber convertEmergencyNumberFromEccInfo(EccInfo eccInfo, String countryIso, + int emergencyCallRouting) { String phoneNumber = eccInfo.phoneNumber.trim(); if (phoneNumber.isEmpty()) { loge("EccInfo has empty phone number."); @@ -456,13 +467,54 @@ public class EmergencyNumberTracker extends Handler { // Ignores unknown types. } } - return new EmergencyNumber(phoneNumber, countryIso, "", emergencyServiceCategoryBitmask, - new ArrayList(), EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, - EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + return new EmergencyNumber(phoneNumber, countryIso, "", + emergencyServiceCategoryBitmask, new ArrayList(), + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, emergencyCallRouting); + } + + /** + * Get routing type of emergency numbers from DB. Update mnc's list with numbers that are + * to supported as normal routing type in the respective mnc's. + */ + private int getRoutingInfoFromDB(EccInfo eccInfo, + Map> normalRoutedNumbers) { + int emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY; + String phoneNumber = eccInfo.phoneNumber.trim(); + if (phoneNumber.isEmpty()) { + loge("EccInfo has empty phone number."); + return emergencyCallRouting; + } + + if (eccInfo.isNormalRouted) { + emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL; + + if (((eccInfo.normalRoutingMncs).length != 0) + && (eccInfo.normalRoutingMncs[0].length() > 0)) { + emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY; + + for (String routingMnc : eccInfo.normalRoutingMncs) { + boolean mncExist = normalRoutedNumbers.containsKey(routingMnc); + Set phoneNumberList; + if (!mncExist) { + phoneNumberList = new ArraySet(); + phoneNumberList.add(phoneNumber); + normalRoutedNumbers.put(routingMnc, phoneNumberList); + } else { + phoneNumberList = normalRoutedNumbers.get(routingMnc); + if (!phoneNumberList.contains(phoneNumber)) { + phoneNumberList.add(phoneNumber); + } + } + } + logd("Normal routed mncs with phoneNumbers:" + normalRoutedNumbers); + } + } + return emergencyCallRouting; } private void cacheEmergencyDatabaseByCountry(String countryIso) { int assetsDatabaseVersion; + Map> assetNormalRoutedNumbers = new ArrayMap<>(); // Read the Asset emergency number database List updatedAssetEmergencyNumberList = new ArrayList<>(); @@ -478,8 +530,13 @@ public class EmergencyNumberTracker extends Handler { for (ProtobufEccData.CountryInfo countryEccInfo : allEccMessages.countries) { if (countryEccInfo.isoCode.equals(countryIso.toUpperCase(Locale.ROOT))) { for (ProtobufEccData.EccInfo eccInfo : countryEccInfo.eccs) { + int emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN; + if (!shouldEmergencyNumberRoutingFromDbBeIgnored()) { + emergencyCallRouting = getRoutingInfoFromDB(eccInfo, + assetNormalRoutedNumbers); + } updatedAssetEmergencyNumberList.add(convertEmergencyNumberFromEccInfo( - eccInfo, countryIso)); + eccInfo, countryIso, emergencyCallRouting)); } } } @@ -500,6 +557,8 @@ public class EmergencyNumberTracker extends Handler { logd("Using Asset Emergency database. Version: " + assetsDatabaseVersion); mCurrentDatabaseVersion = assetsDatabaseVersion; mEmergencyNumberListFromDatabase = updatedAssetEmergencyNumberList; + mNormalRoutedNumbers.clear(); + mNormalRoutedNumbers = assetNormalRoutedNumbers; } else { logd("Using Ota Emergency database. Version: " + otaDatabaseVersion); } @@ -508,6 +567,7 @@ public class EmergencyNumberTracker extends Handler { private int cacheOtaEmergencyNumberDatabase() { ProtobufEccData.AllInfo allEccMessages = null; int otaDatabaseVersion = INVALID_DATABASE_VERSION; + Map> otaNormalRoutedNumbers = new ArrayMap<>(); // Read the OTA emergency number database List updatedOtaEmergencyNumberList = new ArrayList<>(); @@ -538,8 +598,13 @@ public class EmergencyNumberTracker extends Handler { for (ProtobufEccData.CountryInfo countryEccInfo : allEccMessages.countries) { if (countryEccInfo.isoCode.equals(countryIso.toUpperCase(Locale.ROOT))) { for (ProtobufEccData.EccInfo eccInfo : countryEccInfo.eccs) { + int emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN; + if (!shouldEmergencyNumberRoutingFromDbBeIgnored()) { + emergencyCallRouting = getRoutingInfoFromDB(eccInfo, + otaNormalRoutedNumbers); + } updatedOtaEmergencyNumberList.add(convertEmergencyNumberFromEccInfo( - eccInfo, countryIso)); + eccInfo, countryIso, emergencyCallRouting)); } } } @@ -554,6 +619,8 @@ public class EmergencyNumberTracker extends Handler { && mCurrentDatabaseVersion < otaDatabaseVersion) { mCurrentDatabaseVersion = otaDatabaseVersion; mEmergencyNumberListFromDatabase = updatedOtaEmergencyNumberList; + mNormalRoutedNumbers.clear(); + mNormalRoutedNumbers = otaNormalRoutedNumbers; } return otaDatabaseVersion; } @@ -709,11 +776,96 @@ public class EmergencyNumberTracker extends Handler { * indication not support from the HAL. */ public List getEmergencyNumberList() { + List completeEmergencyNumberList; if (!mEmergencyNumberListFromRadio.isEmpty()) { - return Collections.unmodifiableList(mEmergencyNumberList); + completeEmergencyNumberList = Collections.unmodifiableList(mEmergencyNumberList); + } else { + completeEmergencyNumberList = getEmergencyNumberListFromEccListDatabaseAndTest(); + } + if (shouldAdjustForRouting()) { + return adjustRoutingForEmergencyNumbers(completeEmergencyNumberList); + } else { + return completeEmergencyNumberList; + } + } + + /** + * Util function to check whether routing type and mnc value in emergency number needs + * to be adjusted for the current network mnc. + */ + private boolean shouldAdjustForRouting() { + if (!shouldEmergencyNumberRoutingFromDbBeIgnored() && !mNormalRoutedNumbers.isEmpty()) { + CellIdentity cellIdentity = mPhone.getCurrentCellIdentity(); + if (cellIdentity != null) { + String networkMnc = cellIdentity.getMncString(); + if (mNormalRoutedNumbers.containsKey(networkMnc)) { + Set phoneNumbers = mNormalRoutedNumbers.get(networkMnc); + if (phoneNumbers != null && !phoneNumbers.isEmpty()) { + return true; + } + } + } + } + return false; + } + + /** + * Adjust emergency numbers with mnc and routing type based on the current network mnc. + */ + private List adjustRoutingForEmergencyNumbers( + List emergencyNumbers) { + CellIdentity cellIdentity = mPhone.getCurrentCellIdentity(); + if (cellIdentity != null) { + String networkMnc = cellIdentity.getMncString(); + + Set normalRoutedPhoneNumbers = mNormalRoutedNumbers.get(networkMnc); + if (normalRoutedPhoneNumbers == null || normalRoutedPhoneNumbers.isEmpty()) { + return emergencyNumbers; + } + Set normalRoutedPhoneNumbersWithPrefix = new ArraySet(); + for (String num : normalRoutedPhoneNumbers) { + Set phoneNumbersWithPrefix = addPrefixToEmergencyNumber(num); + if (phoneNumbersWithPrefix != null && !phoneNumbersWithPrefix.isEmpty()) { + normalRoutedPhoneNumbersWithPrefix.addAll(phoneNumbersWithPrefix); + } + } + List adjustedEmergencyNumberList = new ArrayList<>(); + int routing; + String mnc; + for (EmergencyNumber num : emergencyNumbers) { + routing = num.getEmergencyCallRouting(); + mnc = num.getMnc(); + if (num.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE) + && (normalRoutedPhoneNumbers.contains(num.getNumber()) + || (normalRoutedPhoneNumbersWithPrefix.contains(num.getNumber())))) { + routing = EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL; + mnc = networkMnc; + logd("adjustRoutingForEmergencyNumbers for number" + num.getNumber()); + } + adjustedEmergencyNumberList.add(new EmergencyNumber(num.getNumber(), + num.getCountryIso(), mnc, + num.getEmergencyServiceCategoryBitmask(), + num.getEmergencyUrns(), num.getEmergencyNumberSourceBitmask(), + routing)); + } + return adjustedEmergencyNumberList; } else { - return getEmergencyNumberListFromEccListDatabaseAndTest(); + return emergencyNumbers; + } + } + + + /** + * Util function to add prefix to the given emergency number. + */ + private Set addPrefixToEmergencyNumber(String number) { + Set phoneNumbersWithPrefix = new ArraySet(); + for (String prefix : mEmergencyNumberPrefix) { + if (!number.startsWith(prefix)) { + phoneNumbersWithPrefix.add(prefix + number); + } } + return phoneNumbersWithPrefix; } /** @@ -895,15 +1047,14 @@ public class EmergencyNumberTracker extends Handler { List emergencyNumberListWithPrefix = new ArrayList<>(); if (emergencyNumberList != null) { for (EmergencyNumber num : emergencyNumberList) { - for (String prefix : mEmergencyNumberPrefix) { - // If an emergency number has started with the prefix, - // no need to apply the prefix. - if (!num.getNumber().startsWith(prefix)) { + Set phoneNumbersWithPrefix = addPrefixToEmergencyNumber(num.getNumber()); + if (phoneNumbersWithPrefix != null && !phoneNumbersWithPrefix.isEmpty()) { + for (String numberWithPrefix : phoneNumbersWithPrefix) { emergencyNumberListWithPrefix.add(new EmergencyNumber( - prefix + num.getNumber(), num.getCountryIso(), - num.getMnc(), num.getEmergencyServiceCategoryBitmask(), - num.getEmergencyUrns(), num.getEmergencyNumberSourceBitmask(), - num.getEmergencyCallRouting())); + numberWithPrefix, num.getCountryIso(), + num.getMnc(), num.getEmergencyServiceCategoryBitmask(), + num.getEmergencyUrns(), num.getEmergencyNumberSourceBitmask(), + num.getEmergencyCallRouting())); } } } @@ -948,7 +1099,7 @@ public class EmergencyNumberTracker extends Handler { return new EmergencyNumber(number, getLastKnownEmergencyCountryIso() .toLowerCase(Locale.ROOT), "", num.getEmergencyServiceCategoryBitmask(), new ArrayList(), EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, - EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + num.getEmergencyCallRouting()); } } return new EmergencyNumber(number, "", "", diff --git a/tests/telephonytests/assets/eccdata b/tests/telephonytests/assets/eccdata index 4c5959b4e8f2b16cd9c8191200f9faf678cdec6a..9dcec54f3c0d25e008d89598cd6b32a6dbdb79d7 100644 GIT binary patch literal 96 zcmV-m0H6OKiwFRTV`F0g1LI&6YGmYM3Jn$#<6<>6F*Y(3VrOJxW?^Mxmta(4GB6dA z;bOM1us{(tF$H3Cu&gK-n;Dum1|5urGmu`Ei2Cq-RN7ykbHRl1xnv&5T5n(o>Ss5>u0>Cv7t^VPR-i+2bM4 Hz`y_itX>b0 diff --git a/tests/telephonytests/assets/eccdata_input.txt b/tests/telephonytests/assets/eccdata_input.txt index 8dcfa753b5..d0ff583f3a 100644 --- a/tests/telephonytests/assets/eccdata_input.txt +++ b/tests/telephonytests/assets/eccdata_input.txt @@ -10,6 +10,57 @@ countries { types: MOUNTAIN_RESCUE types: MIEC types: AIEC + is_normal_routed: true + normal_routing_mncs: "05" + } + eccs { + phone_number: "888" + types: POLICE + types: AMBULANCE + types: FIRE + types: MARINE_GUARD + types: MOUNTAIN_RESCUE + types: MIEC + types: AIEC + is_normal_routed: true + normal_routing_mncs: "45" + normal_routing_mncs: "47" + normal_routing_mncs: "05" + } + eccs { + phone_number: "654321" + types: POLICE + types: AMBULANCE + types: FIRE + types: MARINE_GUARD + types: MOUNTAIN_RESCUE + types: MIEC + types: AIEC + is_normal_routed: false + normal_routing_mncs: "" + } + eccs { + phone_number: "7654321" + types: POLICE + types: AMBULANCE + types: FIRE + types: MARINE_GUARD + types: MOUNTAIN_RESCUE + types: MIEC + types: AIEC + is_normal_routed: true + normal_routing_mncs: "" + } + eccs { + phone_number: "4321" + types: POLICE + types: AMBULANCE + types: FIRE + types: MARINE_GUARD + types: MOUNTAIN_RESCUE + types: MIEC + types: AIEC + is_normal_routed: true } ecc_fallback: "911" } diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java index 1273148940..d6aad72b77 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java @@ -379,7 +379,36 @@ public class EmergencyNumberTest extends TestCase { EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); - assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + /* case 1: Check routing is not checked when comparing the same numbers. As routing will + be unknown for all numbers apart from DB. Check merge when both are not from DB then + routing value is merged from first number. */ + assertTrue(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + assertEquals(num1, EmergencyNumber.mergeSameEmergencyNumbers(num1, num2)); + + num2 = new EmergencyNumber( + "911", + "jp", + "30", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, + new ArrayList(), + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + + /* case 1: Check routing is not checked when comparing the same numbers. Check merge when + one of the number is from DB then routing value is merged from DB number. Along with + source value is masked with both*/ + assertTrue(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + + num2 = new EmergencyNumber( + "911", + "jp", + "30", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, + new ArrayList(), + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING + | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + assertEquals(num2, EmergencyNumber.mergeSameEmergencyNumbers(num1, num2)); } public void testSameEmergencyNumberDifferentSource() throws Exception { diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index f49960a59f..9cd11c85d9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.content.res.AssetManager; +import android.content.res.Resources; import android.os.AsyncResult; import android.os.Environment; import android.os.ParcelFileDescriptor; @@ -75,6 +76,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private static final String EMERGENCY_NUMBER_DB_OTA_FILE = "eccdata_ota"; private static final int CONFIG_UNIT_TEST_EMERGENCY_NUMBER_DB_VERSION = 99999; private static final String CONFIG_EMERGENCY_NUMBER_ADDRESS = "54321"; + private static final String CONFIG_EMERGENCY_DUPLICATE_NUMBER = "4321"; private static final String CONFIG_EMERGENCY_NUMBER_COUNTRY = "us"; private static final String CONFIG_EMERGENCY_NUMBER_MNC = ""; private static final String NON_3GPP_EMERGENCY_TEST_NUMBER = "9876543"; @@ -118,6 +120,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private File mLocalDownloadDirectory; private ShortNumberInfo mShortNumberInfo; private Context mMockContext; + private Resources mResources; @Before public void setUp() throws Exception { @@ -128,6 +131,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { mPhone2 = mock(Phone.class); mContext = InstrumentationRegistry.getTargetContext(); mMockContext = mock(Context.class); + mResources = mock(Resources.class); doReturn(mContext).when(mPhone).getContext(); doReturn(0).when(mPhone).getPhoneId(); @@ -191,6 +195,14 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); mEmergencyNumberListTestSample.add(emergencyNumberForTest); + + emergencyNumberForTest = new EmergencyNumber( + CONFIG_EMERGENCY_DUPLICATE_NUMBER, CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + mEmergencyNumberListTestSample.add(emergencyNumberForTest); } private void sendEmergencyNumberListFromRadio() { @@ -277,6 +289,11 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { } } + private boolean hasDbEmergencyNumbers(List subList, + List list) { + return list.containsAll(subList); + } + private boolean hasDbEmergencyNumber(EmergencyNumber number, List list) { return list.contains(number); } @@ -491,6 +508,10 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { public void testUsingEmergencyNumberDatabaseWheneverHal_1_3() { doReturn(new HalVersion(1, 3)).when(mPhone).getHalVersion(); doReturn(mMockContext).when(mPhone).getContext(); + doReturn(mResources).when(mMockContext).getResources(); + doReturn(true).when(mResources).getBoolean( + com.android.internal.R.bool.ignore_emergency_number_routing_from_db); + EmergencyNumberTracker emergencyNumberTracker = new EmergencyNumberTracker( mPhone, mSimulatedCommands); @@ -513,13 +534,179 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { */ @Test public void testUsingEmergencyNumberDatabaseWheneverHal_1_4() { - doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(); + doReturn(mMockContext).when(mPhone).getContext(); + doReturn(mContext.getAssets()).when(mMockContext).getAssets(); + doReturn(mResources).when(mMockContext).getResources(); + doReturn(true).when(mResources).getBoolean( + com.android.internal.R.bool.ignore_emergency_number_routing_from_db); - sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock); - mEmergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("us"); + EmergencyNumberTracker emergencyNumberTrackerMock = new EmergencyNumberTracker( + mPhone, mSimulatedCommands); + emergencyNumberTrackerMock.sendMessage( + emergencyNumberTrackerMock.obtainMessage( + 1 /* EVENT_UNSOL_EMERGENCY_NUMBER_LIST */, + new AsyncResult(null, mEmergencyNumberListTestSample, null))); + sendEmergencyNumberPrefix(emergencyNumberTrackerMock); + emergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("us"); processAllMessages(); + /* case 1: check DB number exist or not */ assertTrue(hasDbEmergencyNumber(CONFIG_EMERGENCY_NUMBER, - mEmergencyNumberTrackerMock.getEmergencyNumberList())); + emergencyNumberTrackerMock.getEmergencyNumberList())); + + /* case 2: since ignore_emergency_routing_from_db is true. check for all DB numbers with + routing value as unknown by ignoring DB value */ + List completeEmergencyNumberList = new ArrayList<>(); + EmergencyNumber emergencyNumber = new EmergencyNumber( + "888", CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + completeEmergencyNumberList.add(emergencyNumber); + + emergencyNumber = new EmergencyNumber( + "54321", CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + completeEmergencyNumberList.add(emergencyNumber); + + emergencyNumber = new EmergencyNumber( + "654321", CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + completeEmergencyNumberList.add(emergencyNumber); + + emergencyNumber = new EmergencyNumber( + "7654321", CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + completeEmergencyNumberList.add(emergencyNumber); + + assertTrue(hasDbEmergencyNumbers(completeEmergencyNumberList, + emergencyNumberTrackerMock.getEmergencyNumberList())); + + /* case 3: check the routing type of merged duplicate numbers + between DB number and radio list. */ + EmergencyNumber duplicateEmergencyNumber = new EmergencyNumber( + CONFIG_EMERGENCY_DUPLICATE_NUMBER, CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE + | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + assertTrue(hasDbEmergencyNumber(duplicateEmergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + } + + @Test + public void testUsingEmergencyNumberDatabaseWithRouting() { + doReturn(mMockContext).when(mPhone).getContext(); + doReturn(mContext.getAssets()).when(mMockContext).getAssets(); + doReturn(mResources).when(mMockContext).getResources(); + doReturn("05").when(mCellIdentity).getMncString(); + doReturn(false).when(mResources).getBoolean( + com.android.internal.R.bool.ignore_emergency_number_routing_from_db); + + EmergencyNumberTracker emergencyNumberTrackerMock = new EmergencyNumberTracker( + mPhone, mSimulatedCommands); + emergencyNumberTrackerMock.sendMessage( + emergencyNumberTrackerMock.obtainMessage( + 1 /* EVENT_UNSOL_EMERGENCY_NUMBER_LIST */, + new AsyncResult(null, mEmergencyNumberListTestSample, null))); + sendEmergencyNumberPrefix(emergencyNumberTrackerMock); + emergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("us"); + processAllMessages(); + + // case 1: check DB number with normal routing true and for mnc 05 + EmergencyNumber emergencyNumber = new EmergencyNumber( + CONFIG_EMERGENCY_NUMBER_ADDRESS, CONFIG_EMERGENCY_NUMBER_COUNTRY, + "05", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + + // case 2: check DB number with normal routing true in multiple mnc 05, 45, 47 + emergencyNumber = new EmergencyNumber( + "888", CONFIG_EMERGENCY_NUMBER_COUNTRY, + "05", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + + doReturn("47").when(mCellIdentity).getMncString(); + emergencyNumber = new EmergencyNumber( + "888", CONFIG_EMERGENCY_NUMBER_COUNTRY, + "47", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + + emergencyNumber = new EmergencyNumber( + CONFIG_EMERGENCY_NUMBER_ADDRESS, CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY); + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + + /* case 3: check DB number with normal routing false and for mnc 05, + but current cell identity is 04 */ + doReturn("04").when(mCellIdentity).getMncString(); + emergencyNumber = new EmergencyNumber( + CONFIG_EMERGENCY_NUMBER_ADDRESS, CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY); + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + + // case 4: check DB number with normal routing false + emergencyNumber = new EmergencyNumber( + "654321", CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY); + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + + // case 5: check DB number with normal routing true & empty mnc + emergencyNumber = new EmergencyNumber( + "7654321", CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + + /* case 6: check DB number with normal routing true & empty mnc. But same number exist + in radio list. In merge DB routing should be used */ + emergencyNumber = new EmergencyNumber( + CONFIG_EMERGENCY_DUPLICATE_NUMBER, CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE + | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); } /** -- GitLab From c52c9d735bfd266ff9426ad3ca45760b8afb3ca5 Mon Sep 17 00:00:00 2001 From: Michael Groover Date: Mon, 7 Nov 2022 23:19:28 +0000 Subject: [PATCH 171/656] Revert "Revert "Add unaudited exported flag to exposed runtime receivers"" This reverts commit b51212517520641aca5057fc87f19cad8e5d5e5b. Reason for revert: Failing tests have been resolved, reverting to restore the other flagged receivers from the original CL. Bug: 234659204 Test: atest ImsResolverTest Test: atest GsmSmsDispatcherTest Change-Id: I63ef1f048881c88cbc775730e8afb1663cfec294 --- .../android/internal/telephony/gsm/GsmSmsDispatcherTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java index 435cb574a0..4bf54155b1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java @@ -231,7 +231,8 @@ public class GsmSmsDispatcherTest extends TelephonyTest { restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton); restoreInstance(ActivityManager.class, "IActivityManagerSingleton", null); Context realContext = TestApplication.getAppContext(); - realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT)); + realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT), + Context.RECEIVER_EXPORTED); } @Test -- GitLab From e2302476363d11865d2a85cfd5f5918c5964d796 Mon Sep 17 00:00:00 2001 From: Neha Jain Date: Fri, 11 Nov 2022 23:27:58 +0000 Subject: [PATCH 172/656] Revert "RadioAccessSpecifier converter don't return null" This reverts commit 47ee601faf9d4a393ff974adc51fb38bea9fc525. Reason for revert: b/258753599 Change-Id: If6b79fb41601873969347b105d84e7b88a0b9cab --- src/java/com/android/internal/telephony/RILUtils.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 9d8e487fbb..c05b669295 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -1331,6 +1331,8 @@ public class RILUtils { case AccessNetworkConstants.AccessNetworkType.EUTRAN: rasInHalFormat.eutranBands = bands; break; + default: + return null; } if (ras.getChannels() != null) { @@ -1374,6 +1376,8 @@ public class RILUtils { case AccessNetworkConstants.AccessNetworkType.NGRAN: bandsInHalFormat.ngranBands(bands); break; + default: + return null; } rasInHalFormat.bands = bandsInHalFormat; @@ -1420,6 +1424,8 @@ public class RILUtils { case AccessNetworkConstants.AccessNetworkType.NGRAN: bandsInHalFormat.setNgranBands(bands); break; + default: + return null; } rasInHalFormat.bands = bandsInHalFormat; -- GitLab From c8bdda428b8aac7a962bd252a8e3fcfdc6b8ea3f Mon Sep 17 00:00:00 2001 From: Neha Jain Date: Fri, 11 Nov 2022 23:27:58 +0000 Subject: [PATCH 173/656] Revert "RadioAccessSpecifier converter don't return null" This reverts commit 47ee601faf9d4a393ff974adc51fb38bea9fc525. Reason for revert: b/258753599 Change-Id: If6b79fb41601873969347b105d84e7b88a0b9cab (cherry picked from commit e2302476363d11865d2a85cfd5f5918c5964d796) Merged-In: If6b79fb41601873969347b105d84e7b88a0b9cab --- src/java/com/android/internal/telephony/RILUtils.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 9d8e487fbb..c05b669295 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -1331,6 +1331,8 @@ public class RILUtils { case AccessNetworkConstants.AccessNetworkType.EUTRAN: rasInHalFormat.eutranBands = bands; break; + default: + return null; } if (ras.getChannels() != null) { @@ -1374,6 +1376,8 @@ public class RILUtils { case AccessNetworkConstants.AccessNetworkType.NGRAN: bandsInHalFormat.ngranBands(bands); break; + default: + return null; } rasInHalFormat.bands = bandsInHalFormat; @@ -1420,6 +1424,8 @@ public class RILUtils { case AccessNetworkConstants.AccessNetworkType.NGRAN: bandsInHalFormat.setNgranBands(bands); break; + default: + return null; } rasInHalFormat.bands = bandsInHalFormat; -- GitLab From a69e10f5020f2e41c429ca476773e141bc846325 Mon Sep 17 00:00:00 2001 From: jimsun Date: Tue, 13 Sep 2022 11:43:42 +0800 Subject: [PATCH 174/656] Create module-specific Hal versions Bug: 243072871 Test: atest RILTest Change-Id: I5b6cd810a0c351f62b54a17f9ef35520463c96f7 --- .../internal/telephony/CommandsInterface.java | 11 + .../internal/telephony/DataIndication.java | 12 +- .../internal/telephony/DataResponse.java | 30 +- .../telephony/DeviceStateMonitor.java | 3 +- .../internal/telephony/HalVersion.java | 3 + .../internal/telephony/ImsIndication.java | 8 +- .../internal/telephony/ImsResponse.java | 16 +- .../telephony/MessagingIndication.java | 16 +- .../internal/telephony/MessagingResponse.java | 36 +- .../android/internal/telephony/MockModem.java | 106 +-- .../internal/telephony/ModemIndication.java | 12 +- .../internal/telephony/ModemResponse.java | 32 +- .../internal/telephony/NetworkIndication.java | 31 +- .../internal/telephony/NetworkResponse.java | 80 +- .../com/android/internal/telephony/Phone.java | 19 +- .../internal/telephony/PhoneFactory.java | 4 +- .../com/android/internal/telephony/RIL.java | 830 ++++++++++-------- .../internal/telephony/RadioIndication.java | 143 +-- .../telephony/SignalStrengthController.java | 6 +- .../internal/telephony/SimIndication.java | 24 +- .../internal/telephony/SimResponse.java | 64 +- .../internal/telephony/VoiceIndication.java | 32 +- .../internal/telephony/VoiceResponse.java | 76 +- .../telephony/data/AccessNetworksManager.java | 4 +- .../internal/telephony/data/DataNetwork.java | 6 +- .../emergency/EmergencyNumberTracker.java | 7 +- .../android/internal/telephony/RILTest.java | 68 +- .../SignalStrengthControllerTest.java | 3 +- .../internal/telephony/TelephonyTest.java | 2 +- .../data/DataNetworkControllerTest.java | 4 +- .../emergency/EmergencyNumberTrackerTest.java | 18 +- 31 files changed, 958 insertions(+), 748 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 2c6ff087ed..e2595c47ec 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -35,6 +35,7 @@ import android.telephony.NetworkScanRequest; import android.telephony.RadioAccessSpecifier; import android.telephony.SignalThresholdInfo; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.HalService; import android.telephony.data.DataCallResponse; import android.telephony.data.DataProfile; import android.telephony.data.NetworkSliceInfo; @@ -2198,11 +2199,21 @@ public interface CommandsInterface { /** * @return the radio hal version + * @deprecated use {@link #getHalVersion(int)} */ + @Deprecated default HalVersion getHalVersion() { return HalVersion.UNKNOWN; } + /** + * @param service indicate the service id to query. + * @return the hal version of a specific service + */ + default HalVersion getHalVersion(@HalService int service) { + return HalVersion.UNKNOWN; + } + /** * Sets user selected subscription at Modem. * diff --git a/src/java/com/android/internal/telephony/DataIndication.java b/src/java/com/android/internal/telephony/DataIndication.java index 346795589a..205c4d8b2c 100644 --- a/src/java/com/android/internal/telephony/DataIndication.java +++ b/src/java/com/android/internal/telephony/DataIndication.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; + import static com.android.internal.telephony.RILConstants.RIL_UNSOL_DATA_CALL_LIST_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_KEEPALIVE_STATUS; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PCO_DATA; @@ -53,7 +55,7 @@ public class DataIndication extends IRadioDataIndication.Stub { */ public void dataCallListChanged(int indicationType, android.hardware.radio.data.SetupDataCallResult[] dcList) { - mRil.processIndication(RIL.DATA_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_DATA, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_DATA_CALL_LIST_CHANGED, dcList); ArrayList response = RILUtils.convertHalDataCallResultList(dcList); @@ -68,7 +70,7 @@ public class DataIndication extends IRadioDataIndication.Stub { */ public void keepaliveStatus(int indicationType, android.hardware.radio.data.KeepaliveStatus halStatus) { - mRil.processIndication(RIL.DATA_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_DATA, indicationType); if (mRil.isLogOrTrace()) { mRil.unsljLogRet( @@ -87,7 +89,7 @@ public class DataIndication extends IRadioDataIndication.Stub { * @param pco New PcoData */ public void pcoData(int indicationType, android.hardware.radio.data.PcoDataInfo pco) { - mRil.processIndication(RIL.DATA_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_DATA, indicationType); PcoData response = new PcoData(pco.cid, pco.bearerProto, pco.pcoId, pco.contents); @@ -104,7 +106,7 @@ public class DataIndication extends IRadioDataIndication.Stub { */ public void unthrottleApn(int indicationType, android.hardware.radio.data.DataProfileInfo dpi) throws RemoteException { - mRil.processIndication(RIL.DATA_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_DATA, indicationType); DataProfile response = RILUtils.convertToDataProfile(dpi); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_UNTHROTTLE_APN, response); @@ -120,7 +122,7 @@ public class DataIndication extends IRadioDataIndication.Stub { */ public void slicingConfigChanged(int indicationType, android.hardware.radio.data.SlicingConfig slicingConfig) throws RemoteException { - mRil.processIndication(RIL.DATA_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_DATA, indicationType); if (mRil.isLogOrTrace()) { mRil.unsljLogRet(RIL_UNSOL_SLICING_CONFIG_CHANGED, slicingConfig); } diff --git a/src/java/com/android/internal/telephony/DataResponse.java b/src/java/com/android/internal/telephony/DataResponse.java index 7cfe13b229..bef1da7317 100644 --- a/src/java/com/android/internal/telephony/DataResponse.java +++ b/src/java/com/android/internal/telephony/DataResponse.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; + import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.data.IRadioDataResponse; @@ -51,7 +53,7 @@ public class DataResponse extends IRadioDataResponse.Stub { * @param id The pdu session id allocated */ public void allocatePduSessionIdResponse(RadioResponseInfo responseInfo, int id) { - RILRequest rr = mRil.processResponse(RIL.DATA_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_DATA, responseInfo); if (rr != null) { if (responseInfo.error == RadioError.NONE) { RadioResponse.sendMessageResponse(rr.mResult, id); @@ -64,14 +66,14 @@ public class DataResponse extends IRadioDataResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void cancelHandoverResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.DATA_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_DATA, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void deactivateDataCallResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.DATA_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_DATA, mRil, responseInfo); } /** @@ -80,7 +82,7 @@ public class DataResponse extends IRadioDataResponse.Stub { */ public void getDataCallListResponse(RadioResponseInfo responseInfo, android.hardware.radio.data.SetupDataCallResult[] dataCallResultList) { - RILRequest rr = mRil.processResponse(RIL.DATA_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_DATA, responseInfo); if (rr != null) { ArrayList response = @@ -98,7 +100,7 @@ public class DataResponse extends IRadioDataResponse.Stub { */ public void getSlicingConfigResponse(RadioResponseInfo responseInfo, android.hardware.radio.data.SlicingConfig slicingConfig) { - RILRequest rr = mRil.processResponse(RIL.DATA_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_DATA, responseInfo); if (rr != null) { NetworkSlicingConfig ret = RILUtils.convertHalSlicingConfig(slicingConfig); @@ -113,35 +115,35 @@ public class DataResponse extends IRadioDataResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void releasePduSessionIdResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.DATA_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_DATA, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setDataAllowedResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.DATA_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_DATA, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setDataProfileResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.DATA_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_DATA, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setDataThrottlingResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.DATA_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_DATA, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setInitialAttachApnResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.DATA_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_DATA, mRil, responseInfo); } /** @@ -150,7 +152,7 @@ public class DataResponse extends IRadioDataResponse.Stub { */ public void setupDataCallResponse(RadioResponseInfo responseInfo, android.hardware.radio.data.SetupDataCallResult setupDataCallResult) { - RILRequest rr = mRil.processResponse(RIL.DATA_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_DATA, responseInfo); if (rr != null) { DataCallResponse response = RILUtils.convertHalDataCallResult(setupDataCallResult); @@ -165,7 +167,7 @@ public class DataResponse extends IRadioDataResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void startHandoverResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.DATA_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_DATA, mRil, responseInfo); } /** @@ -175,7 +177,7 @@ public class DataResponse extends IRadioDataResponse.Stub { public void startKeepaliveResponse(RadioResponseInfo responseInfo, android.hardware.radio.data.KeepaliveStatus keepaliveStatus) { - RILRequest rr = mRil.processResponse(RIL.DATA_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_DATA, responseInfo); if (rr == null) return; KeepaliveStatus ret = null; @@ -214,7 +216,7 @@ public class DataResponse extends IRadioDataResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void stopKeepaliveResponse(RadioResponseInfo responseInfo) { - RILRequest rr = mRil.processResponse(RIL.DATA_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_DATA, responseInfo); if (rr == null) return; try { diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java index 3d63a29f5e..ecc6208192 100644 --- a/src/java/com/android/internal/telephony/DeviceStateMonitor.java +++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java @@ -20,6 +20,7 @@ import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE; import static android.hardware.radio.V1_0.DeviceStateType.CHARGING_STATE; import static android.hardware.radio.V1_0.DeviceStateType.LOW_DATA_EXPECTED; import static android.hardware.radio.V1_0.DeviceStateType.POWER_SAVE_MODE; +import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; import android.app.UiModeManager; import android.content.BroadcastReceiver; @@ -669,7 +670,7 @@ public class DeviceStateMonitor extends Handler { LINK_CAPACITY_UPLINK_THRESHOLDS, AccessNetworkType.EUTRAN); mPhone.setLinkCapacityReportingCriteria(LINK_CAPACITY_DOWNLINK_THRESHOLDS, LINK_CAPACITY_UPLINK_THRESHOLDS, AccessNetworkType.CDMA2000); - if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { + if (mPhone.getHalVersion(HAL_SERVICE_NETWORK).greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { mPhone.setLinkCapacityReportingCriteria(LINK_CAPACITY_DOWNLINK_THRESHOLDS, LINK_CAPACITY_UPLINK_THRESHOLDS, AccessNetworkType.NGRAN); } diff --git a/src/java/com/android/internal/telephony/HalVersion.java b/src/java/com/android/internal/telephony/HalVersion.java index f83d790f20..c05111b256 100644 --- a/src/java/com/android/internal/telephony/HalVersion.java +++ b/src/java/com/android/internal/telephony/HalVersion.java @@ -25,6 +25,9 @@ import java.util.Objects; */ public class HalVersion implements Comparable { + /** The HAL Version indicating that the version is unsupported */ + public static final HalVersion UNSUPPORTED = new HalVersion(-2, -2); + /** The HAL Version indicating that the version is unknown or invalid */ public static final HalVersion UNKNOWN = new HalVersion(-1, -1); diff --git a/src/java/com/android/internal/telephony/ImsIndication.java b/src/java/com/android/internal/telephony/ImsIndication.java index 896679ec76..80d75ce447 100644 --- a/src/java/com/android/internal/telephony/ImsIndication.java +++ b/src/java/com/android/internal/telephony/ImsIndication.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_IMS; + import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CONNECTION_SETUP_FAILURE; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NOTIFY_ANBR; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION; @@ -53,7 +55,7 @@ public class ImsIndication extends IRadioImsIndication.Stub { */ public void onConnectionSetupFailure(int indicationType, int token, android.hardware.radio.ims.ConnectionFailureInfo failureInfo) { - mRil.processIndication(RIL.IMS_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_IMS, indicationType); int[] info = new int[3]; info[0] = failureInfo.failureReason; @@ -81,7 +83,7 @@ public class ImsIndication extends IRadioImsIndication.Stub { */ public void notifyAnbr(int indicationType, int qosSessionId, int imsdirection, int bitsPerSecond) { - mRil.processIndication(RIL.IMS_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_IMS, indicationType); int[] response = new int[3]; response[0] = qosSessionId; @@ -104,7 +106,7 @@ public class ImsIndication extends IRadioImsIndication.Stub { * @param reason the reason why the deregistration is triggered. */ public void triggerImsDeregistration(int indicationType, int reason) { - mRil.processIndication(RIL.IMS_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_IMS, indicationType); if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION, reason); diff --git a/src/java/com/android/internal/telephony/ImsResponse.java b/src/java/com/android/internal/telephony/ImsResponse.java index 257f1da14b..574cf359a7 100644 --- a/src/java/com/android/internal/telephony/ImsResponse.java +++ b/src/java/com/android/internal/telephony/ImsResponse.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_IMS; + import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.ims.IRadioImsResponse; @@ -44,14 +46,14 @@ public class ImsResponse extends IRadioImsResponse.Stub { * @param info Response info struct containing response type, serial no. and error. */ public void setSrvccCallInfoResponse(RadioResponseInfo info) { - RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + RadioResponse.responseVoid(HAL_SERVICE_IMS, mRil, info); } /** * @param info Response info struct containing response type, serial no. and error. */ public void updateImsRegistrationInfoResponse(RadioResponseInfo info) { - RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + RadioResponse.responseVoid(HAL_SERVICE_IMS, mRil, info); } /** @@ -60,7 +62,7 @@ public class ImsResponse extends IRadioImsResponse.Stub { */ public void startImsTrafficResponse(RadioResponseInfo responseInfo, android.hardware.radio.ims.ConnectionFailureInfo failureInfo) { - RILRequest rr = mRil.processResponse(RIL.IMS_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_IMS, responseInfo); if (rr != null) { Object[] response = { "", null }; @@ -84,27 +86,27 @@ public class ImsResponse extends IRadioImsResponse.Stub { * @param info Response info struct containing response type, serial no. and error. */ public void stopImsTrafficResponse(RadioResponseInfo info) { - RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + RadioResponse.responseVoid(HAL_SERVICE_IMS, mRil, info); } /** * @param info Response info struct containing response type, serial no. and error. */ public void triggerEpsFallbackResponse(RadioResponseInfo info) { - RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + RadioResponse.responseVoid(HAL_SERVICE_IMS, mRil, info); } /** * @param info Response info struct containing response type, serial no. and error. */ public void sendAnbrQueryResponse(RadioResponseInfo info) { - RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + RadioResponse.responseVoid(HAL_SERVICE_IMS, mRil, info); } /** * @param info Response info struct containing response type, serial no. and error. */ public void updateImsCallStatusResponse(RadioResponseInfo info) { - RadioResponse.responseVoid(RIL.IMS_SERVICE, mRil, info); + RadioResponse.responseVoid(HAL_SERVICE_IMS, mRil, info); } } diff --git a/src/java/com/android/internal/telephony/MessagingIndication.java b/src/java/com/android/internal/telephony/MessagingIndication.java index 96e74cc767..5814e3db6f 100644 --- a/src/java/com/android/internal/telephony/MessagingIndication.java +++ b/src/java/com/android/internal/telephony/MessagingIndication.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_MESSAGING; + import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_CDMA_NEW_SMS; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS; @@ -47,7 +49,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { */ public void cdmaNewSms(int indicationType, android.hardware.radio.messaging.CdmaSmsMessage msg) { - mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MESSAGING, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_CDMA_NEW_SMS); @@ -63,7 +65,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { * @param indicationType Type of radio indication */ public void cdmaRuimSmsStorageFull(int indicationType) { - mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MESSAGING, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL); @@ -82,7 +84,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { * BTS as coded in 3GPP 23.041 Section 9.4.2.2 */ public void newBroadcastSms(int indicationType, byte[] data) { - mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MESSAGING, indicationType); if (mRil.isLogOrTrace()) { mRil.unsljLogvRet( @@ -101,7 +103,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { * The PDU starts with the SMSC address per TS 27.005 (+CMT:) */ public void newSms(int indicationType, byte[] pdu) { - mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MESSAGING, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS); SmsMessageBase smsb = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); @@ -117,7 +119,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { * @param recordNumber Record number on the SIM */ public void newSmsOnSim(int indicationType, int recordNumber) { - mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MESSAGING, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM); @@ -133,7 +135,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { * The PDU starts with the SMSC address per TS 27.005 (+CMT:) */ public void newSmsStatusReport(int indicationType, byte[] pdu) { - mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MESSAGING, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT); @@ -149,7 +151,7 @@ public class MessagingIndication extends IRadioMessagingIndication.Stub { * @param indicationType Type of radio indication */ public void simSmsStorageFull(int indicationType) { - mRil.processIndication(RIL.MESSAGING_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MESSAGING, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SIM_SMS_STORAGE_FULL); diff --git a/src/java/com/android/internal/telephony/MessagingResponse.java b/src/java/com/android/internal/telephony/MessagingResponse.java index 3dc1d1a965..19211e15f5 100644 --- a/src/java/com/android/internal/telephony/MessagingResponse.java +++ b/src/java/com/android/internal/telephony/MessagingResponse.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_MESSAGING; + import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.messaging.IRadioMessagingResponse; @@ -36,7 +38,7 @@ public class MessagingResponse extends IRadioMessagingResponse.Stub { private void responseSms(RadioResponseInfo responseInfo, android.hardware.radio.messaging.SendSmsResult sms) { - RILRequest rr = mRil.processResponse(RIL.MESSAGING_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_MESSAGING, responseInfo); if (rr != null) { long messageId = RIL.getOutgoingSmsMessageId(rr.mResult); @@ -62,35 +64,35 @@ public class MessagingResponse extends IRadioMessagingResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void acknowledgeIncomingGsmSmsWithPduResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void acknowledgeLastIncomingCdmaSmsResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void acknowledgeLastIncomingGsmSmsResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void deleteSmsOnRuimResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void deleteSmsOnSimResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** @@ -99,7 +101,7 @@ public class MessagingResponse extends IRadioMessagingResponse.Stub { */ public void getCdmaBroadcastConfigResponse(RadioResponseInfo responseInfo, android.hardware.radio.messaging.CdmaBroadcastSmsConfigInfo[] configs) { - RILRequest rr = mRil.processResponse(RIL.MESSAGING_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_MESSAGING, responseInfo); if (rr != null) { int[] ret; @@ -148,7 +150,7 @@ public class MessagingResponse extends IRadioMessagingResponse.Stub { */ public void getGsmBroadcastConfigResponse(RadioResponseInfo responseInfo, android.hardware.radio.messaging.GsmBroadcastSmsConfigInfo[] configs) { - RILRequest rr = mRil.processResponse(RIL.MESSAGING_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_MESSAGING, responseInfo); if (rr != null) { ArrayList ret = new ArrayList<>(); @@ -168,14 +170,14 @@ public class MessagingResponse extends IRadioMessagingResponse.Stub { * @param smsc Short Message Service Center address on the device */ public void getSmscAddressResponse(RadioResponseInfo responseInfo, String smsc) { - RadioResponse.responseString(RIL.MESSAGING_SERVICE, mRil, responseInfo, smsc); + RadioResponse.responseString(HAL_SERVICE_MESSAGING, mRil, responseInfo, smsc); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void reportSmsMemoryStatusResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** @@ -227,35 +229,35 @@ public class MessagingResponse extends IRadioMessagingResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void setCdmaBroadcastActivationResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setCdmaBroadcastConfigResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setGsmBroadcastActivationResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setGsmBroadcastConfigResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setSmscAddressResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MESSAGING_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MESSAGING, mRil, responseInfo); } /** @@ -263,7 +265,7 @@ public class MessagingResponse extends IRadioMessagingResponse.Stub { * @param index record index where the CDMA SMS message is stored */ public void writeSmsToRuimResponse(RadioResponseInfo responseInfo, int index) { - RadioResponse.responseInts(RIL.MESSAGING_SERVICE, mRil, responseInfo, index); + RadioResponse.responseInts(HAL_SERVICE_MESSAGING, mRil, responseInfo, index); } /** @@ -271,7 +273,7 @@ public class MessagingResponse extends IRadioMessagingResponse.Stub { * @param index record index where the message is stored */ public void writeSmsToSimResponse(RadioResponseInfo responseInfo, int index) { - RadioResponse.responseInts(RIL.MESSAGING_SERVICE, mRil, responseInfo, index); + RadioResponse.responseInts(HAL_SERVICE_MESSAGING, mRil, responseInfo, index); } @Override diff --git a/src/java/com/android/internal/telephony/MockModem.java b/src/java/com/android/internal/telephony/MockModem.java index 7e638ef27c..a20e74818f 100644 --- a/src/java/com/android/internal/telephony/MockModem.java +++ b/src/java/com/android/internal/telephony/MockModem.java @@ -16,6 +16,14 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; +import static android.telephony.TelephonyManager.HAL_SERVICE_IMS; +import static android.telephony.TelephonyManager.HAL_SERVICE_MESSAGING; +import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; +import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; +import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; +import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; + import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -93,19 +101,19 @@ public class MockModem { public void onServiceConnected(ComponentName name, IBinder binder) { Rlog.d(mTag, "IRadio " + getModuleName(mService) + " - onServiceConnected"); - if (mService == RIL.MODEM_SERVICE) { + if (mService == HAL_SERVICE_MODEM) { mModemBinder = binder; - } else if (mService == RIL.SIM_SERVICE) { + } else if (mService == HAL_SERVICE_SIM) { mSimBinder = binder; - } else if (mService == RIL.MESSAGING_SERVICE) { + } else if (mService == HAL_SERVICE_MESSAGING) { mMessagingBinder = binder; - } else if (mService == RIL.DATA_SERVICE) { + } else if (mService == HAL_SERVICE_DATA) { mDataBinder = binder; - } else if (mService == RIL.NETWORK_SERVICE) { + } else if (mService == HAL_SERVICE_NETWORK) { mNetworkBinder = binder; - } else if (mService == RIL.VOICE_SERVICE) { + } else if (mService == HAL_SERVICE_VOICE) { mVoiceBinder = binder; - } else if (mService == RIL.IMS_SERVICE) { + } else if (mService == HAL_SERVICE_IMS) { mImsBinder = binder; } else if (mService == RADIOCONFIG_SERVICE) { mConfigBinder = binder; @@ -116,19 +124,19 @@ public class MockModem { public void onServiceDisconnected(ComponentName name) { Rlog.d(mTag, "IRadio " + getModuleName(mService) + " - onServiceDisconnected"); - if (mService == RIL.MODEM_SERVICE) { + if (mService == HAL_SERVICE_MODEM) { mModemBinder = null; - } else if (mService == RIL.SIM_SERVICE) { + } else if (mService == HAL_SERVICE_SIM) { mSimBinder = null; - } else if (mService == RIL.MESSAGING_SERVICE) { + } else if (mService == HAL_SERVICE_MESSAGING) { mMessagingBinder = null; - } else if (mService == RIL.DATA_SERVICE) { + } else if (mService == HAL_SERVICE_DATA) { mDataBinder = null; - } else if (mService == RIL.NETWORK_SERVICE) { + } else if (mService == HAL_SERVICE_NETWORK) { mNetworkBinder = null; - } else if (mService == RIL.VOICE_SERVICE) { + } else if (mService == HAL_SERVICE_VOICE) { mVoiceBinder = null; - } else if (mService == RIL.IMS_SERVICE) { + } else if (mService == HAL_SERVICE_IMS) { mImsBinder = null; } else if (mService == RADIOCONFIG_SERVICE) { mConfigBinder = null; @@ -157,19 +165,19 @@ public class MockModem { /** waitForBinder */ public IBinder getServiceBinder(int service) { switch (service) { - case RIL.MODEM_SERVICE: + case HAL_SERVICE_MODEM: return mModemBinder; - case RIL.SIM_SERVICE: + case HAL_SERVICE_SIM: return mSimBinder; - case RIL.MESSAGING_SERVICE: + case HAL_SERVICE_MESSAGING: return mMessagingBinder; - case RIL.DATA_SERVICE: + case HAL_SERVICE_DATA: return mDataBinder; - case RIL.NETWORK_SERVICE: + case HAL_SERVICE_NETWORK: return mNetworkBinder; - case RIL.VOICE_SERVICE: + case HAL_SERVICE_VOICE: return mVoiceBinder; - case RIL.IMS_SERVICE: + case HAL_SERVICE_IMS: return mImsBinder; case RADIOCONFIG_SERVICE: return mConfigBinder; @@ -200,9 +208,9 @@ public class MockModem { } else { Rlog.d(mTag, "IRadio Config is bound"); } - } else if (service == RIL.MODEM_SERVICE) { + } else if (service == HAL_SERVICE_MODEM) { if (mModemBinder == null) { - mModemServiceConnection = new MockModemConnection(RIL.MODEM_SERVICE); + mModemServiceConnection = new MockModemConnection(HAL_SERVICE_MODEM); boolean status = bindModuleToMockModemService( @@ -214,9 +222,9 @@ public class MockModem { } else { Rlog.d(mTag, "IRadio Modem is bound"); } - } else if (service == RIL.SIM_SERVICE) { + } else if (service == HAL_SERVICE_SIM) { if (mSimBinder == null) { - mSimServiceConnection = new MockModemConnection(RIL.SIM_SERVICE); + mSimServiceConnection = new MockModemConnection(HAL_SERVICE_SIM); boolean status = bindModuleToMockModemService( @@ -228,9 +236,9 @@ public class MockModem { } else { Rlog.d(mTag, "IRadio Sim is bound"); } - } else if (service == RIL.MESSAGING_SERVICE) { + } else if (service == HAL_SERVICE_MESSAGING) { if (mMessagingBinder == null) { - mMessagingServiceConnection = new MockModemConnection(RIL.MESSAGING_SERVICE); + mMessagingServiceConnection = new MockModemConnection(HAL_SERVICE_MESSAGING); boolean status = bindModuleToMockModemService( @@ -242,9 +250,9 @@ public class MockModem { } else { Rlog.d(mTag, "IRadio Messaging is bound"); } - } else if (service == RIL.DATA_SERVICE) { + } else if (service == HAL_SERVICE_DATA) { if (mDataBinder == null) { - mDataServiceConnection = new MockModemConnection(RIL.DATA_SERVICE); + mDataServiceConnection = new MockModemConnection(HAL_SERVICE_DATA); boolean status = bindModuleToMockModemService( @@ -256,9 +264,9 @@ public class MockModem { } else { Rlog.d(mTag, "IRadio Data is bound"); } - } else if (service == RIL.NETWORK_SERVICE) { + } else if (service == HAL_SERVICE_NETWORK) { if (mNetworkBinder == null) { - mNetworkServiceConnection = new MockModemConnection(RIL.NETWORK_SERVICE); + mNetworkServiceConnection = new MockModemConnection(HAL_SERVICE_NETWORK); boolean status = bindModuleToMockModemService( @@ -270,9 +278,9 @@ public class MockModem { } else { Rlog.d(mTag, "IRadio Network is bound"); } - } else if (service == RIL.VOICE_SERVICE) { + } else if (service == HAL_SERVICE_VOICE) { if (mVoiceBinder == null) { - mVoiceServiceConnection = new MockModemConnection(RIL.VOICE_SERVICE); + mVoiceServiceConnection = new MockModemConnection(HAL_SERVICE_VOICE); boolean status = bindModuleToMockModemService( @@ -284,9 +292,9 @@ public class MockModem { } else { Rlog.d(mTag, "IRadio Voice is bound"); } - } else if (service == RIL.IMS_SERVICE) { + } else if (service == HAL_SERVICE_IMS) { if (mImsBinder == null) { - mImsServiceConnection = new MockModemConnection(RIL.IMS_SERVICE); + mImsServiceConnection = new MockModemConnection(HAL_SERVICE_IMS); boolean status = bindModuleToMockModemService( @@ -311,49 +319,49 @@ public class MockModem { mConfigBinder = null; Rlog.d(mTag, "unbind IRadio Config"); } - } else if (service == RIL.MODEM_SERVICE) { + } else if (service == HAL_SERVICE_MODEM) { if (mModemServiceConnection != null) { mContext.unbindService(mModemServiceConnection); mModemServiceConnection = null; mModemBinder = null; Rlog.d(mTag, "unbind IRadio Modem"); } - } else if (service == RIL.SIM_SERVICE) { + } else if (service == HAL_SERVICE_SIM) { if (mSimServiceConnection != null) { mContext.unbindService(mSimServiceConnection); mSimServiceConnection = null; mSimBinder = null; Rlog.d(mTag, "unbind IRadio Sim"); } - } else if (service == RIL.MESSAGING_SERVICE) { + } else if (service == HAL_SERVICE_MESSAGING) { if (mMessagingServiceConnection != null) { mContext.unbindService(mMessagingServiceConnection); mMessagingServiceConnection = null; mMessagingBinder = null; Rlog.d(mTag, "unbind IRadio Messaging"); } - } else if (service == RIL.DATA_SERVICE) { + } else if (service == HAL_SERVICE_DATA) { if (mDataServiceConnection != null) { mContext.unbindService(mDataServiceConnection); mDataServiceConnection = null; mDataBinder = null; Rlog.d(mTag, "unbind IRadio Data"); } - } else if (service == RIL.NETWORK_SERVICE) { + } else if (service == HAL_SERVICE_NETWORK) { if (mNetworkServiceConnection != null) { mContext.unbindService(mNetworkServiceConnection); mNetworkServiceConnection = null; mNetworkBinder = null; Rlog.d(mTag, "unbind IRadio Network"); } - } else if (service == RIL.VOICE_SERVICE) { + } else if (service == HAL_SERVICE_VOICE) { if (mVoiceServiceConnection != null) { mContext.unbindService(mVoiceServiceConnection); mVoiceServiceConnection = null; mVoiceBinder = null; Rlog.d(mTag, "unbind IRadio Voice"); } - } else if (service == RIL.IMS_SERVICE) { + } else if (service == HAL_SERVICE_IMS) { if (mImsServiceConnection != null) { mContext.unbindService(mImsServiceConnection); mImsServiceConnection = null; @@ -369,19 +377,19 @@ public class MockModem { private String getModuleName(int service) { switch (service) { - case RIL.MODEM_SERVICE: + case HAL_SERVICE_MODEM: return "modem"; - case RIL.SIM_SERVICE: + case HAL_SERVICE_SIM: return "sim"; - case RIL.MESSAGING_SERVICE: + case HAL_SERVICE_MESSAGING: return "messaging"; - case RIL.DATA_SERVICE: + case HAL_SERVICE_DATA: return "data"; - case RIL.NETWORK_SERVICE: + case HAL_SERVICE_NETWORK: return "network"; - case RIL.VOICE_SERVICE: + case HAL_SERVICE_VOICE: return "voice"; - case RIL.IMS_SERVICE: + case HAL_SERVICE_IMS: return "ims"; case RADIOCONFIG_SERVICE: return "config"; diff --git a/src/java/com/android/internal/telephony/ModemIndication.java b/src/java/com/android/internal/telephony/ModemIndication.java index d05e0f6730..0ee40bb6ff 100644 --- a/src/java/com/android/internal/telephony/ModemIndication.java +++ b/src/java/com/android/internal/telephony/ModemIndication.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; + import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RADIO_CAPABILITY; @@ -44,7 +46,7 @@ public class ModemIndication extends IRadioModemIndication.Stub { */ public void hardwareConfigChanged(int indicationType, android.hardware.radio.modem.HardwareConfig[] configs) { - mRil.processIndication(RIL.MODEM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MODEM, indicationType); ArrayList response = RILUtils.convertHalHardwareConfigList(configs); @@ -62,7 +64,7 @@ public class ModemIndication extends IRadioModemIndication.Stub { * restart" that explains the cause of the modem restart */ public void modemReset(int indicationType, String reason) { - mRil.processIndication(RIL.MODEM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MODEM, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_MODEM_RESTART, reason); @@ -78,7 +80,7 @@ public class ModemIndication extends IRadioModemIndication.Stub { */ public void radioCapabilityIndication(int indicationType, android.hardware.radio.modem.RadioCapability radioCapability) { - mRil.processIndication(RIL.MODEM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MODEM, indicationType); RadioCapability response = RILUtils.convertHalRadioCapability(radioCapability, mRil); @@ -94,7 +96,7 @@ public class ModemIndication extends IRadioModemIndication.Stub { * @param radioState Current radio state */ public void radioStateChanged(int indicationType, int radioState) { - mRil.processIndication(RIL.MODEM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MODEM, indicationType); int state = RILUtils.convertHalRadioState(radioState); if (mRil.isLogOrTrace()) { @@ -110,7 +112,7 @@ public class ModemIndication extends IRadioModemIndication.Stub { * @param indicationType Type of radio indication */ public void rilConnected(int indicationType) { - mRil.processIndication(RIL.MODEM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_MODEM, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RIL_CONNECTED); diff --git a/src/java/com/android/internal/telephony/ModemResponse.java b/src/java/com/android/internal/telephony/ModemResponse.java index 6e44ddc76e..4589e795c8 100644 --- a/src/java/com/android/internal/telephony/ModemResponse.java +++ b/src/java/com/android/internal/telephony/ModemResponse.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; + import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.modem.IRadioModemResponse; @@ -51,7 +53,7 @@ public class ModemResponse extends IRadioModemResponse.Stub { * @param responseInfo Response info struct containing response type, serial number and error. */ public void enableModemResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MODEM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MODEM, mRil, responseInfo); } /** @@ -59,7 +61,7 @@ public class ModemResponse extends IRadioModemResponse.Stub { * @param version String containing version string for log reporting */ public void getBasebandVersionResponse(RadioResponseInfo responseInfo, String version) { - RadioResponse.responseString(RIL.MODEM_SERVICE, mRil, responseInfo, version); + RadioResponse.responseString(HAL_SERVICE_MODEM, mRil, responseInfo, version); } /** @@ -72,7 +74,7 @@ public class ModemResponse extends IRadioModemResponse.Stub { public void getDeviceIdentityResponse(RadioResponseInfo responseInfo, String imei, String imeisv, String esn, String meid) { RadioResponse.responseStrings( - RIL.MODEM_SERVICE, mRil, responseInfo, imei, imeisv, esn, meid); + HAL_SERVICE_MODEM, mRil, responseInfo, imei, imeisv, esn, meid); } /** @@ -81,7 +83,7 @@ public class ModemResponse extends IRadioModemResponse.Stub { */ public void getHardwareConfigResponse(RadioResponseInfo responseInfo, android.hardware.radio.modem.HardwareConfig[] config) { - RILRequest rr = mRil.processResponse(RIL.MODEM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_MODEM, responseInfo); if (rr != null) { ArrayList ret = RILUtils.convertHalHardwareConfigList(config); @@ -98,7 +100,7 @@ public class ModemResponse extends IRadioModemResponse.Stub { */ public void getModemActivityInfoResponse(RadioResponseInfo responseInfo, android.hardware.radio.modem.ActivityStatsInfo activityInfo) { - RILRequest rr = mRil.processResponse(RIL.MODEM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_MODEM, responseInfo); if (rr != null) { ModemActivityInfo ret = null; @@ -141,7 +143,7 @@ public class ModemResponse extends IRadioModemResponse.Stub { * @param isEnabled whether the modem stack is enabled. */ public void getModemStackStatusResponse(RadioResponseInfo responseInfo, boolean isEnabled) { - RILRequest rr = mRil.processResponse(RIL.MODEM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_MODEM, responseInfo); if (rr != null) { if (responseInfo.error == RadioError.NONE) { @@ -157,7 +159,7 @@ public class ModemResponse extends IRadioModemResponse.Stub { */ public void getRadioCapabilityResponse(RadioResponseInfo responseInfo, android.hardware.radio.modem.RadioCapability radioCapability) { - RILRequest rr = mRil.processResponse(RIL.MODEM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_MODEM, responseInfo); if (rr != null) { RadioCapability ret = RILUtils.convertHalRadioCapability(radioCapability, mRil); @@ -179,42 +181,42 @@ public class ModemResponse extends IRadioModemResponse.Stub { * @param result String containing the contents of the NV item */ public void nvReadItemResponse(RadioResponseInfo responseInfo, String result) { - RadioResponse.responseString(RIL.MODEM_SERVICE, mRil, responseInfo, result); + RadioResponse.responseString(HAL_SERVICE_MODEM, mRil, responseInfo, result); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void nvResetConfigResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MODEM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MODEM, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void nvWriteCdmaPrlResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MODEM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MODEM, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void nvWriteItemResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MODEM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MODEM, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void requestShutdownResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MODEM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MODEM, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void sendDeviceStateResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MODEM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MODEM, mRil, responseInfo); } /** @@ -223,7 +225,7 @@ public class ModemResponse extends IRadioModemResponse.Stub { */ public void setRadioCapabilityResponse(RadioResponseInfo responseInfo, android.hardware.radio.modem.RadioCapability radioCapability) { - RILRequest rr = mRil.processResponse(RIL.MODEM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_MODEM, responseInfo); if (rr != null) { RadioCapability ret = RILUtils.convertHalRadioCapability(radioCapability, mRil); @@ -238,7 +240,7 @@ public class ModemResponse extends IRadioModemResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error. */ public void setRadioPowerResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.MODEM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_MODEM, mRil, responseInfo); mRil.mLastRadioPowerResult = responseInfo.error; if (responseInfo.error == RadioError.RF_HARDWARE_ISSUE) { AnomalyReporter.reportAnomaly( diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index d59707e28b..a19d4df264 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_PRL_CHANGED; @@ -74,7 +75,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { public void barringInfoChanged(int indicationType, android.hardware.radio.network.CellIdentity cellIdentity, android.hardware.radio.network.BarringInfo[] barringInfos) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); if (cellIdentity == null || barringInfos == null) { reportAnomaly(UUID.fromString("645b16bb-c930-4c1c-9c5d-568696542e05"), @@ -95,7 +96,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { * @param version PRL version after PRL changes */ public void cdmaPrlChanged(int indicationType, int version) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); int[] response = new int[]{version}; @@ -111,7 +112,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { */ public void cellInfoList(int indicationType, android.hardware.radio.network.CellInfo[] records) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); ArrayList response = RILUtils.convertHalCellInfoList(records); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_CELL_INFO_LIST, response); mRil.mRilCellInfoListRegistrants.notifyRegistrants(new AsyncResult(null, response, null)); @@ -124,7 +125,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { */ public void currentLinkCapacityEstimate(int indicationType, android.hardware.radio.network.LinkCapacityEstimate lce) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); List response = RILUtils.convertHalLceData(lce); @@ -142,7 +143,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { */ public void currentPhysicalChannelConfigs(int indicationType, android.hardware.radio.network.PhysicalChannelConfig[] configs) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); List response = new ArrayList<>(configs.length); try { for (android.hardware.radio.network.PhysicalChannelConfig config : configs) { @@ -193,7 +194,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { */ public void currentSignalStrength(int indicationType, android.hardware.radio.network.SignalStrength signalStrength) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); SignalStrength ssInitial = RILUtils.convertHalSignalStrength(signalStrength); @@ -211,7 +212,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { * @param indicationType Type of radio indication */ public void imsNetworkStateChanged(int indicationType) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED); @@ -225,7 +226,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { */ public void networkScanResult(int indicationType, android.hardware.radio.network.NetworkScanResult result) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); ArrayList cellInfos = RILUtils.convertHalCellInfoList(result.networkInfos); NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos); @@ -238,7 +239,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { * @param indicationType Type of radio indication */ public void networkStateChanged(int indicationType) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED); @@ -258,7 +259,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { */ public void nitzTimeReceived(int indicationType, String nitzTime, @ElapsedRealtimeLong long receivedTimeMs, long ageMs) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime); @@ -305,7 +306,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { public void registrationFailed(int indicationType, android.hardware.radio.network.CellIdentity cellIdentity, String chosenPlmn, @NetworkRegistrationInfo.Domain int domain, int causeCode, int additionalCauseCode) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); CellIdentity ci = RILUtils.convertHalCellIdentity(cellIdentity); if (ci == null || TextUtils.isEmpty(chosenPlmn) || (domain & NetworkRegistrationInfo.DOMAIN_CS_PS) == 0 @@ -330,7 +331,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { * @param state Bitmask of restricted state as defined by PhoneRestrictedState */ public void restrictedStateChanged(int indicationType, int state) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_RESTRICTED_STATE_CHANGED, state); @@ -346,7 +347,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { */ public void suppSvcNotify(int indicationType, android.hardware.radio.network.SuppSvcNotification suppSvcNotification) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); SuppServiceNotification notification = new SuppServiceNotification(); notification.notificationType = suppSvcNotification.isMT ? 1 : 0; @@ -370,7 +371,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { * @param rat Current new voice rat */ public void voiceRadioTechChanged(int indicationType, int rat) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); int[] response = new int[] {rat}; @@ -389,7 +390,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { */ public void emergencyNetworkScanResult(int indicationType, android.hardware.radio.network.EmergencyRegResult result) { - mRil.processIndication(RIL.NETWORK_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); EmergencyRegResult response = RILUtils.convertHalEmergencyRegResult(result); diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index 370335a70f..755cb75bb9 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; + import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.network.IRadioNetworkResponse; @@ -58,7 +60,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { int halRadioAccessFamilyBitmap) { int networkTypeBitmask = RILUtils.convertHalNetworkTypeBitMask(halRadioAccessFamilyBitmap); mRil.mAllowedNetworkTypesBitmask = networkTypeBitmask; - RadioResponse.responseInts(RIL.NETWORK_SERVICE, mRil, responseInfo, networkTypeBitmask); + RadioResponse.responseInts(HAL_SERVICE_NETWORK, mRil, responseInfo, networkTypeBitmask); } /** @@ -66,7 +68,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { * @param bandModes List of RadioBandMode listing supported modes */ public void getAvailableBandModesResponse(RadioResponseInfo responseInfo, int[] bandModes) { - RadioResponse.responseIntArrayList(RIL.NETWORK_SERVICE, mRil, responseInfo, + RadioResponse.responseIntArrayList(HAL_SERVICE_NETWORK, mRil, responseInfo, RILUtils.primitiveArrayToArrayList(bandModes)); } @@ -76,7 +78,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void getAvailableNetworksResponse(RadioResponseInfo responseInfo, android.hardware.radio.network.OperatorInfo[] networkInfos) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { ArrayList ret = new ArrayList<>(); @@ -99,7 +101,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { public void getBarringInfoResponse(RadioResponseInfo responseInfo, android.hardware.radio.network.CellIdentity cellIdentity, android.hardware.radio.network.BarringInfo[] barringInfos) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { BarringInfo bi = new BarringInfo(RILUtils.convertHalCellIdentity(cellIdentity), @@ -119,7 +121,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { * @param type CdmaRoamingType defined in types.hal */ public void getCdmaRoamingPreferenceResponse(RadioResponseInfo responseInfo, int type) { - RadioResponse.responseInts(RIL.NETWORK_SERVICE, mRil, responseInfo, type); + RadioResponse.responseInts(HAL_SERVICE_NETWORK, mRil, responseInfo, type); } /** @@ -128,7 +130,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void getCellInfoListResponse(RadioResponseInfo responseInfo, android.hardware.radio.network.CellInfo[] cellInfo) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { ArrayList ret = RILUtils.convertHalCellInfoList(cellInfo); @@ -145,7 +147,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void getDataRegistrationStateResponse(RadioResponseInfo responseInfo, android.hardware.radio.network.RegStateResult dataRegResponse) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { if (responseInfo.error == RadioError.NONE) { @@ -162,7 +164,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void getImsRegistrationStateResponse(RadioResponseInfo responseInfo, boolean isRegistered, int ratFamily) { - RadioResponse.responseInts(RIL.NETWORK_SERVICE, mRil, responseInfo, isRegistered ? 1 : 0, + RadioResponse.responseInts(HAL_SERVICE_NETWORK, mRil, responseInfo, isRegistered ? 1 : 0, ratFamily == android.hardware.radio.RadioTechnologyFamily.THREE_GPP ? PhoneConstants.PHONE_TYPE_GSM : PhoneConstants.PHONE_TYPE_CDMA); } @@ -172,7 +174,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { * @param selection false for automatic selection, true for manual selection */ public void getNetworkSelectionModeResponse(RadioResponseInfo responseInfo, boolean selection) { - RadioResponse.responseInts(RIL.NETWORK_SERVICE, mRil, responseInfo, selection ? 1 : 0); + RadioResponse.responseInts(HAL_SERVICE_NETWORK, mRil, responseInfo, selection ? 1 : 0); } /** @@ -184,7 +186,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { public void getOperatorResponse(RadioResponseInfo responseInfo, String longName, String shortName, String numeric) { RadioResponse.responseStrings( - RIL.NETWORK_SERVICE, mRil, responseInfo, longName, shortName, numeric); + HAL_SERVICE_NETWORK, mRil, responseInfo, longName, shortName, numeric); } /** @@ -193,7 +195,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void getSignalStrengthResponse(RadioResponseInfo responseInfo, android.hardware.radio.network.SignalStrength signalStrength) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { SignalStrength ret = RILUtils.convertHalSignalStrength(signalStrength); @@ -210,7 +212,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void getSystemSelectionChannelsResponse(RadioResponseInfo responseInfo, android.hardware.radio.network.RadioAccessSpecifier[] halSpecifiers) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { ArrayList specifiers = new ArrayList<>(); @@ -230,7 +232,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { * @param rat Current voice RAT */ public void getVoiceRadioTechnologyResponse(RadioResponseInfo responseInfo, int rat) { - RadioResponse.responseInts(RIL.NETWORK_SERVICE, mRil, responseInfo, rat); + RadioResponse.responseInts(HAL_SERVICE_NETWORK, mRil, responseInfo, rat); } /** @@ -239,7 +241,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void getVoiceRegistrationStateResponse(RadioResponseInfo responseInfo, android.hardware.radio.network.RegStateResult voiceRegResponse) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { if (responseInfo.error == RadioError.NONE) { RadioResponse.sendMessageResponse(rr.mResult, voiceRegResponse); @@ -255,7 +257,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void isNrDualConnectivityEnabledResponse(RadioResponseInfo responseInfo, boolean isEnabled) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { if (responseInfo.error == RadioError.NONE) { @@ -271,7 +273,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void pullLceDataResponse(RadioResponseInfo responseInfo, android.hardware.radio.network.LceDataInfo lceInfo) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { List ret = RILUtils.convertHalLceData(lceInfo); @@ -286,105 +288,105 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void setAllowedNetworkTypesBitmapResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setBandModeResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setBarringPasswordResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setCdmaRoamingPreferenceResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setCellInfoListRateResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setIndicationFilterResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setLinkCapacityReportingCriteriaResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setLocationUpdatesResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setNetworkSelectionModeAutomaticResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setNetworkSelectionModeManualResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setNrDualConnectivityStateResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setSignalStrengthReportingCriteriaResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setSuppServiceNotificationsResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial number and error. */ public void setSystemSelectionChannelsResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void startNetworkScanResponse(RadioResponseInfo responseInfo) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { NetworkScanResult nsr = null; if (responseInfo.error == RadioError.NONE) { @@ -400,7 +402,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void stopNetworkScanResponse(RadioResponseInfo responseInfo) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { NetworkScanResult nsr = null; if (responseInfo.error == RadioError.NONE) { @@ -418,14 +420,14 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void supplyNetworkDepersonalizationResponse(RadioResponseInfo responseInfo, int retriesRemaining) { - RadioResponse.responseInts(RIL.NETWORK_SERVICE, mRil, responseInfo, retriesRemaining); + RadioResponse.responseInts(HAL_SERVICE_NETWORK, mRil, responseInfo, retriesRemaining); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setUsageSettingResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** @@ -434,7 +436,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void getUsageSettingResponse(RadioResponseInfo responseInfo, /* @TelephonyManager.UsageSetting */ int usageSetting) { - RadioResponse.responseInts(RIL.NETWORK_SERVICE, mRil, responseInfo, usageSetting); + RadioResponse.responseInts(HAL_SERVICE_NETWORK, mRil, responseInfo, usageSetting); } /** @@ -443,7 +445,7 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { */ public void setEmergencyModeResponse(RadioResponseInfo responseInfo, android.hardware.radio.network.EmergencyRegResult regState) { - RILRequest rr = mRil.processResponse(RIL.NETWORK_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); if (rr != null) { EmergencyRegResult response = RILUtils.convertHalEmergencyRegResult(regState); @@ -458,21 +460,21 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void triggerEmergencyNetworkScanResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void exitEmergencyModeResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void cancelEmergencyNetworkScanResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } @Override diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index e4502eac65..445af27190 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_RADIO; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.BroadcastOptions; @@ -61,6 +63,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.HalService; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RegistrationManager; import android.telephony.ims.stub.ImsRegistrationImplBase; @@ -4713,10 +4716,24 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * Get the HAL version. * * @return the current HalVersion + * + * @deprecated Use {@link #getHalVersion(int service)} instead. */ + @Deprecated public HalVersion getHalVersion() { + return getHalVersion(HAL_SERVICE_RADIO); + } + + /** + * Get the HAL version with a specific service. + * + * @param service the service id to query + * @return the current HalVersion for a specific service + * + */ + public HalVersion getHalVersion(@HalService int service) { if (mCi != null && mCi instanceof RIL) { - return ((RIL) mCi).getHalVersion(); + return ((RIL) mCi).getHalVersion(service); } return RIL.RADIO_HAL_VERSION_UNKNOWN; } diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index eb11b12c81..e642314fda 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_RADIO; + import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA; import static com.android.internal.telephony.PhoneConstants.PHONE_TYPE_CDMA_LTE; @@ -181,7 +183,7 @@ public class PhoneFactory { if (numPhones > 0) { final RadioConfig radioConfig = RadioConfig.make(context, - sCommandsInterfaces[0].getHalVersion()); + sCommandsInterfaces[0].getHalVersion(HAL_SERVICE_RADIO)); sRadioHalCapabilities = RadioInterfaceCapabilityController.init(radioConfig, sCommandsInterfaces[0]); } else { diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 69fffe2f0d..36c680a28a 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -16,6 +16,15 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; +import static android.telephony.TelephonyManager.HAL_SERVICE_IMS; +import static android.telephony.TelephonyManager.HAL_SERVICE_MESSAGING; +import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; +import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; +import static android.telephony.TelephonyManager.HAL_SERVICE_RADIO; +import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; +import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; + import static com.android.internal.telephony.RILConstants.*; import android.annotation.NonNull; @@ -69,6 +78,7 @@ import android.telephony.SignalThresholdInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyHistogram; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.HalService; import android.telephony.TelephonyManager.PrefNetworkMode; import android.telephony.data.DataProfile; import android.telephony.data.NetworkSliceInfo; @@ -95,8 +105,10 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; @@ -135,6 +147,9 @@ public class RIL extends BaseCommands implements CommandsInterface { public static final int FOR_ACK_WAKELOCK = 1; private final ClientWakelockTracker mClientWakelockTracker = new ClientWakelockTracker(); + /** @hide */ + public static final HalVersion RADIO_HAL_VERSION_UNSUPPORTED = HalVersion.UNSUPPORTED; + /** @hide */ public static final HalVersion RADIO_HAL_VERSION_UNKNOWN = HalVersion.UNKNOWN; @@ -165,8 +180,8 @@ public class RIL extends BaseCommands implements CommandsInterface { /** @hide */ public static final HalVersion RADIO_HAL_VERSION_2_1 = new HalVersion(2, 1); - // IRadio version - private HalVersion mRadioVersion = RADIO_HAL_VERSION_UNKNOWN; + // Hal version + private Map mHalVersion = new HashMap<>(); //***** Instance Variables @@ -204,16 +219,9 @@ public class RIL extends BaseCommands implements CommandsInterface { private static final String PROPERTY_IS_VONR_ENABLED = "persist.radio.is_vonr_enabled_"; - static final int RADIO_SERVICE = 0; - static final int DATA_SERVICE = 1; - static final int MESSAGING_SERVICE = 2; - static final int MODEM_SERVICE = 3; - static final int NETWORK_SERVICE = 4; - static final int SIM_SERVICE = 5; - static final int VOICE_SERVICE = 6; - static final int IMS_SERVICE = 7; - static final int MIN_SERVICE_IDX = RADIO_SERVICE; - static final int MAX_SERVICE_IDX = IMS_SERVICE; + public static final int MIN_SERVICE_IDX = HAL_SERVICE_RADIO; + + public static final int MAX_SERVICE_IDX = HAL_SERVICE_IMS; /** * An array of sets that records if services are disabled in the HAL for a specific phone ID @@ -422,7 +430,8 @@ public class RIL extends BaseCommands implements CommandsInterface { public void serviceDied(long cookie) { // Deal with service going away riljLog("serviceDied"); - mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD, RADIO_SERVICE, + mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD, + HAL_SERVICE_RADIO, 0 /* ignored arg2 */, cookie)); } } @@ -462,7 +471,7 @@ public class RIL extends BaseCommands implements CommandsInterface { } private synchronized void resetProxyAndRequestList(int service) { - if (service == RADIO_SERVICE) { + if (service == HAL_SERVICE_RADIO) { mRadioProxy = null; } else { mServiceProxies.get(service).clear(); @@ -479,7 +488,7 @@ public class RIL extends BaseCommands implements CommandsInterface { // Clear request list on close clearRequestList(RADIO_NOT_AVAILABLE, false); - if (service == RADIO_SERVICE) { + if (service == HAL_SERVICE_RADIO) { getRadioProxy(null); } else { getRadioServiceProxy(service, null); @@ -508,13 +517,13 @@ public class RIL extends BaseCommands implements CommandsInterface { // Disable HIDL service if (mRadioProxy != null) { riljLog("Disable HIDL service"); - mDisabledRadioServices.get(RADIO_SERVICE).add(mPhoneId); + mDisabledRadioServices.get(HAL_SERVICE_RADIO).add(mPhoneId); } mMockModem.bindAllMockModemService(); for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) { - if (service == RADIO_SERVICE) continue; + if (service == HAL_SERVICE_RADIO) continue; int retryCount = 0; IBinder binder; @@ -549,15 +558,23 @@ public class RIL extends BaseCommands implements CommandsInterface { if ((serviceName == null) || (!serviceBound)) { if (serviceBound) riljLog("Unbinding to MockModemService"); - if (mDisabledRadioServices.get(RADIO_SERVICE).contains(mPhoneId)) { - mDisabledRadioServices.get(RADIO_SERVICE).clear(); + if (mDisabledRadioServices.get(HAL_SERVICE_RADIO).contains(mPhoneId)) { + mDisabledRadioServices.get(HAL_SERVICE_RADIO).clear(); } if (mMockModem != null) { - mRadioVersion = RADIO_HAL_VERSION_UNKNOWN; mMockModem = null; for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) { - resetProxyAndRequestList(service); + if (isRadioServiceSupported(service)) { + resetProxyAndRequestList(service); + if (service == HAL_SERVICE_RADIO && isRadioVersion2_0()) { + mHalVersion.put(service, RADIO_HAL_VERSION_2_0); + } else { + mHalVersion.put(service, RADIO_HAL_VERSION_UNKNOWN); + } + } else { + mHalVersion.put(service, RADIO_HAL_VERSION_UNSUPPORTED); + } } } } @@ -598,7 +615,10 @@ public class RIL extends BaseCommands implements CommandsInterface { /** Returns a {@link IRadio} instance or null if the service is not available. */ @VisibleForTesting public synchronized IRadio getRadioProxy(Message result) { - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_0)) return null; + if (mHalVersion.containsKey(HAL_SERVICE_RADIO) + && mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + return null; + } if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return null; if (!mIsCellularSupported) { if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only"); @@ -615,14 +635,14 @@ public class RIL extends BaseCommands implements CommandsInterface { } try { - if (mDisabledRadioServices.get(RADIO_SERVICE).contains(mPhoneId)) { + if (mDisabledRadioServices.get(HAL_SERVICE_RADIO).contains(mPhoneId)) { riljLoge("getRadioProxy: mRadioProxy for " + HIDL_SERVICE_NAME[mPhoneId] + " is disabled"); } else { try { mRadioProxy = android.hardware.radio.V1_6.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); - mRadioVersion = RADIO_HAL_VERSION_1_6; + mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_6); } catch (NoSuchElementException e) { } @@ -630,7 +650,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { mRadioProxy = android.hardware.radio.V1_5.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); - mRadioVersion = RADIO_HAL_VERSION_1_5; + mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_5); } catch (NoSuchElementException e) { } } @@ -639,7 +659,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { mRadioProxy = android.hardware.radio.V1_4.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); - mRadioVersion = RADIO_HAL_VERSION_1_4; + mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_4); } catch (NoSuchElementException e) { } } @@ -648,7 +668,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { mRadioProxy = android.hardware.radio.V1_3.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); - mRadioVersion = RADIO_HAL_VERSION_1_3; + mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_3); } catch (NoSuchElementException e) { } } @@ -657,7 +677,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { mRadioProxy = android.hardware.radio.V1_2.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); - mRadioVersion = RADIO_HAL_VERSION_1_2; + mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_2); } catch (NoSuchElementException e) { } } @@ -666,7 +686,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { mRadioProxy = android.hardware.radio.V1_1.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); - mRadioVersion = RADIO_HAL_VERSION_1_1; + mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_1); } catch (NoSuchElementException e) { } } @@ -675,7 +695,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { mRadioProxy = android.hardware.radio.V1_0.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); - mRadioVersion = RADIO_HAL_VERSION_1_0; + mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_1_0); } catch (NoSuchElementException e) { } } @@ -684,11 +704,11 @@ public class RIL extends BaseCommands implements CommandsInterface { if (!mIsRadioProxyInitialized) { mIsRadioProxyInitialized = true; mRadioProxy.linkToDeath(mRadioProxyDeathRecipient, - mServiceCookies.get(RADIO_SERVICE).incrementAndGet()); + mServiceCookies.get(HAL_SERVICE_RADIO).incrementAndGet()); mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication); } } else { - mDisabledRadioServices.get(RADIO_SERVICE).add(mPhoneId); + mDisabledRadioServices.get(HAL_SERVICE_RADIO).add(mPhoneId); riljLoge("getRadioProxy: set mRadioProxy for " + HIDL_SERVICE_NAME[mPhoneId] + " as disabled"); } @@ -720,25 +740,25 @@ public class RIL extends BaseCommands implements CommandsInterface { public T getRadioServiceProxy(Class serviceClass, Message result) { if (serviceClass == RadioDataProxy.class) { - return (T) getRadioServiceProxy(DATA_SERVICE, result); + return (T) getRadioServiceProxy(HAL_SERVICE_DATA, result); } if (serviceClass == RadioMessagingProxy.class) { - return (T) getRadioServiceProxy(MESSAGING_SERVICE, result); + return (T) getRadioServiceProxy(HAL_SERVICE_MESSAGING, result); } if (serviceClass == RadioModemProxy.class) { - return (T) getRadioServiceProxy(MODEM_SERVICE, result); + return (T) getRadioServiceProxy(HAL_SERVICE_MODEM, result); } if (serviceClass == RadioNetworkProxy.class) { - return (T) getRadioServiceProxy(NETWORK_SERVICE, result); + return (T) getRadioServiceProxy(HAL_SERVICE_NETWORK, result); } if (serviceClass == RadioSimProxy.class) { - return (T) getRadioServiceProxy(SIM_SERVICE, result); + return (T) getRadioServiceProxy(HAL_SERVICE_SIM, result); } if (serviceClass == RadioVoiceProxy.class) { - return (T) getRadioServiceProxy(VOICE_SERVICE, result); + return (T) getRadioServiceProxy(HAL_SERVICE_VOICE, result); } if (serviceClass == RadioImsProxy.class) { - return (T) getRadioServiceProxy(IMS_SERVICE, result); + return (T) getRadioServiceProxy(HAL_SERVICE_IMS, result); } riljLoge("getRadioServiceProxy: unrecognized " + serviceClass); return null; @@ -746,12 +766,15 @@ public class RIL extends BaseCommands implements CommandsInterface { /** * Returns a {@link RadioServiceProxy}, which is empty if the service is not available. - * For RADIO_SERVICE, use {@link #getRadioProxy} instead, as this will always return null. + * For HAL_SERVICE_RADIO, use {@link #getRadioProxy} instead, as this will always return null. */ @VisibleForTesting @NonNull public synchronized RadioServiceProxy getRadioServiceProxy(int service, Message result) { if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return mServiceProxies.get(service); + if (service == HAL_SERVICE_IMS && !isRadioServiceSupported(service)) { + return mServiceProxies.get(service); + } if (!mIsCellularSupported) { if (RILJ_LOGV) riljLog("getRadioServiceProxy: Not calling getService(): wifi-only"); if (result != null) { @@ -774,172 +797,184 @@ public class RIL extends BaseCommands implements CommandsInterface { } else { IBinder binder; switch (service) { - case DATA_SERVICE: + case HAL_SERVICE_DATA: if (mMockModem == null) { binder = ServiceManager.waitForDeclaredService( android.hardware.radio.data.IRadioData.DESCRIPTOR + "/" + HIDL_SERVICE_NAME[mPhoneId]); } else { - binder = mMockModem.getServiceBinder(DATA_SERVICE); + binder = mMockModem.getServiceBinder(HAL_SERVICE_DATA); } if (binder != null) { - mRadioVersion = ((RadioDataProxy) serviceProxy).setAidl(mRadioVersion, + mHalVersion.put(service, ((RadioDataProxy) serviceProxy).setAidl( + mHalVersion.get(service), android.hardware.radio.data.IRadioData.Stub.asInterface( - binder)); + binder))); } break; - case MESSAGING_SERVICE: + case HAL_SERVICE_MESSAGING: if (mMockModem == null) { binder = ServiceManager.waitForDeclaredService( android.hardware.radio.messaging.IRadioMessaging.DESCRIPTOR + "/" + HIDL_SERVICE_NAME[mPhoneId]); } else { - binder = mMockModem.getServiceBinder(MESSAGING_SERVICE); + binder = mMockModem.getServiceBinder(HAL_SERVICE_MESSAGING); } if (binder != null) { - mRadioVersion = ((RadioMessagingProxy) serviceProxy).setAidl( - mRadioVersion, + mHalVersion.put(service, ((RadioMessagingProxy) serviceProxy).setAidl( + mHalVersion.get(service), android.hardware.radio.messaging.IRadioMessaging.Stub - .asInterface(binder)); + .asInterface(binder))); } break; - case MODEM_SERVICE: + case HAL_SERVICE_MODEM: if (mMockModem == null) { binder = ServiceManager.waitForDeclaredService( android.hardware.radio.modem.IRadioModem.DESCRIPTOR + "/" + HIDL_SERVICE_NAME[mPhoneId]); } else { - binder = mMockModem.getServiceBinder(MODEM_SERVICE); + binder = mMockModem.getServiceBinder(HAL_SERVICE_MODEM); } if (binder != null) { - mRadioVersion = ((RadioModemProxy) serviceProxy).setAidl(mRadioVersion, + mHalVersion.put(service, ((RadioModemProxy) serviceProxy).setAidl( + mHalVersion.get(service), android.hardware.radio.modem.IRadioModem.Stub - .asInterface(binder)); + .asInterface(binder))); } break; - case NETWORK_SERVICE: + case HAL_SERVICE_NETWORK: if (mMockModem == null) { binder = ServiceManager.waitForDeclaredService( android.hardware.radio.network.IRadioNetwork.DESCRIPTOR + "/" + HIDL_SERVICE_NAME[mPhoneId]); } else { - binder = mMockModem.getServiceBinder(NETWORK_SERVICE); + binder = mMockModem.getServiceBinder(HAL_SERVICE_NETWORK); } if (binder != null) { - mRadioVersion = ((RadioNetworkProxy) serviceProxy).setAidl( - mRadioVersion, + mHalVersion.put(service, ((RadioNetworkProxy) serviceProxy).setAidl( + mHalVersion.get(service), android.hardware.radio.network.IRadioNetwork.Stub - .asInterface(binder)); + .asInterface(binder))); } break; - case SIM_SERVICE: + case HAL_SERVICE_SIM: if (mMockModem == null) { binder = ServiceManager.waitForDeclaredService( android.hardware.radio.sim.IRadioSim.DESCRIPTOR + "/" + HIDL_SERVICE_NAME[mPhoneId]); } else { - binder = mMockModem.getServiceBinder(SIM_SERVICE); + binder = mMockModem.getServiceBinder(HAL_SERVICE_SIM); } if (binder != null) { - mRadioVersion = ((RadioSimProxy) serviceProxy).setAidl(mRadioVersion, + mHalVersion.put(service, ((RadioSimProxy) serviceProxy).setAidl( + mHalVersion.get(service), android.hardware.radio.sim.IRadioSim.Stub - .asInterface(binder)); + .asInterface(binder))); } break; - case VOICE_SERVICE: + case HAL_SERVICE_VOICE: if (mMockModem == null) { binder = ServiceManager.waitForDeclaredService( android.hardware.radio.voice.IRadioVoice.DESCRIPTOR + "/" + HIDL_SERVICE_NAME[mPhoneId]); } else { - binder = mMockModem.getServiceBinder(VOICE_SERVICE); + binder = mMockModem.getServiceBinder(HAL_SERVICE_VOICE); } if (binder != null) { - mRadioVersion = ((RadioVoiceProxy) serviceProxy).setAidl(mRadioVersion, + mHalVersion.put(service, ((RadioVoiceProxy) serviceProxy).setAidl( + mHalVersion.get(service), android.hardware.radio.voice.IRadioVoice.Stub - .asInterface(binder)); + .asInterface(binder))); } break; - case IMS_SERVICE: + case HAL_SERVICE_IMS: if (mMockModem == null) { binder = ServiceManager.waitForDeclaredService( android.hardware.radio.ims.IRadioIms.DESCRIPTOR + "/" + HIDL_SERVICE_NAME[mPhoneId]); } else { - binder = mMockModem.getServiceBinder(IMS_SERVICE); + binder = mMockModem.getServiceBinder(HAL_SERVICE_IMS); } if (binder != null) { - mRadioVersion = ((RadioImsProxy) serviceProxy).setAidl(mRadioVersion, + mHalVersion.put(service, ((RadioImsProxy) serviceProxy).setAidl( + mHalVersion.get(service), android.hardware.radio.ims.IRadioIms.Stub - .asInterface(binder)); + .asInterface(binder))); } break; } - if (serviceProxy.isEmpty() && mRadioVersion.less(RADIO_HAL_VERSION_2_0)) { + if (serviceProxy.isEmpty() + && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { try { - mRadioVersion = RADIO_HAL_VERSION_1_6; - serviceProxy.setHidl(mRadioVersion, + mHalVersion.put(service, RADIO_HAL_VERSION_1_6); + serviceProxy.setHidl(mHalVersion.get(service), android.hardware.radio.V1_6.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true)); } catch (NoSuchElementException e) { } } - if (serviceProxy.isEmpty() && mRadioVersion.less(RADIO_HAL_VERSION_2_0)) { + if (serviceProxy.isEmpty() + && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { try { - mRadioVersion = RADIO_HAL_VERSION_1_5; - serviceProxy.setHidl(mRadioVersion, + mHalVersion.put(service, RADIO_HAL_VERSION_1_5); + serviceProxy.setHidl(mHalVersion.get(service), android.hardware.radio.V1_5.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true)); } catch (NoSuchElementException e) { } } - if (serviceProxy.isEmpty() && mRadioVersion.less(RADIO_HAL_VERSION_2_0)) { + if (serviceProxy.isEmpty() + && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { try { - mRadioVersion = RADIO_HAL_VERSION_1_4; - serviceProxy.setHidl(mRadioVersion, + mHalVersion.put(service, RADIO_HAL_VERSION_1_4); + serviceProxy.setHidl(mHalVersion.get(service), android.hardware.radio.V1_4.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true)); } catch (NoSuchElementException e) { } } - if (serviceProxy.isEmpty() && mRadioVersion.less(RADIO_HAL_VERSION_2_0)) { + if (serviceProxy.isEmpty() + && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { try { - mRadioVersion = RADIO_HAL_VERSION_1_3; - serviceProxy.setHidl(mRadioVersion, + mHalVersion.put(service, RADIO_HAL_VERSION_1_3); + serviceProxy.setHidl(mHalVersion.get(service), android.hardware.radio.V1_3.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true)); } catch (NoSuchElementException e) { } } - if (serviceProxy.isEmpty() && mRadioVersion.less(RADIO_HAL_VERSION_2_0)) { + if (serviceProxy.isEmpty() + && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { try { - mRadioVersion = RADIO_HAL_VERSION_1_2; - serviceProxy.setHidl(mRadioVersion, + mHalVersion.put(service, RADIO_HAL_VERSION_1_2); + serviceProxy.setHidl(mHalVersion.get(service), android.hardware.radio.V1_2.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true)); } catch (NoSuchElementException e) { } } - if (serviceProxy.isEmpty() && mRadioVersion.less(RADIO_HAL_VERSION_2_0)) { + if (serviceProxy.isEmpty() + && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { try { - mRadioVersion = RADIO_HAL_VERSION_1_1; - serviceProxy.setHidl(mRadioVersion, + mHalVersion.put(service, RADIO_HAL_VERSION_1_1); + serviceProxy.setHidl(mHalVersion.get(service), android.hardware.radio.V1_1.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true)); } catch (NoSuchElementException e) { } } - if (serviceProxy.isEmpty() && mRadioVersion.less(RADIO_HAL_VERSION_2_0)) { + if (serviceProxy.isEmpty() + && mHalVersion.get(service).less(RADIO_HAL_VERSION_2_0)) { try { - mRadioVersion = RADIO_HAL_VERSION_1_0; - serviceProxy.setHidl(mRadioVersion, + mHalVersion.put(service, RADIO_HAL_VERSION_1_0); + serviceProxy.setHidl(mHalVersion.get(service), android.hardware.radio.V1_0.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true)); } catch (NoSuchElementException e) { @@ -949,43 +984,43 @@ public class RIL extends BaseCommands implements CommandsInterface { if (!serviceProxy.isEmpty()) { if (serviceProxy.isAidl()) { switch (service) { - case DATA_SERVICE: + case HAL_SERVICE_DATA: mDeathRecipients.get(service).linkToDeath( ((RadioDataProxy) serviceProxy).getAidl().asBinder()); ((RadioDataProxy) serviceProxy).getAidl().setResponseFunctions( mDataResponse, mDataIndication); break; - case MESSAGING_SERVICE: + case HAL_SERVICE_MESSAGING: mDeathRecipients.get(service).linkToDeath( ((RadioMessagingProxy) serviceProxy).getAidl().asBinder()); ((RadioMessagingProxy) serviceProxy).getAidl().setResponseFunctions( mMessagingResponse, mMessagingIndication); break; - case MODEM_SERVICE: + case HAL_SERVICE_MODEM: mDeathRecipients.get(service).linkToDeath( ((RadioModemProxy) serviceProxy).getAidl().asBinder()); ((RadioModemProxy) serviceProxy).getAidl().setResponseFunctions( mModemResponse, mModemIndication); break; - case NETWORK_SERVICE: + case HAL_SERVICE_NETWORK: mDeathRecipients.get(service).linkToDeath( ((RadioNetworkProxy) serviceProxy).getAidl().asBinder()); ((RadioNetworkProxy) serviceProxy).getAidl().setResponseFunctions( mNetworkResponse, mNetworkIndication); break; - case SIM_SERVICE: + case HAL_SERVICE_SIM: mDeathRecipients.get(service).linkToDeath( ((RadioSimProxy) serviceProxy).getAidl().asBinder()); ((RadioSimProxy) serviceProxy).getAidl().setResponseFunctions( mSimResponse, mSimIndication); break; - case VOICE_SERVICE: + case HAL_SERVICE_VOICE: mDeathRecipients.get(service).linkToDeath( ((RadioVoiceProxy) serviceProxy).getAidl().asBinder()); ((RadioVoiceProxy) serviceProxy).getAidl().setResponseFunctions( mVoiceResponse, mVoiceIndication); break; - case IMS_SERVICE: + case HAL_SERVICE_IMS: mDeathRecipients.get(service).linkToDeath( ((RadioImsProxy) serviceProxy).getAidl().asBinder()); ((RadioImsProxy) serviceProxy).getAidl().setResponseFunctions( @@ -993,7 +1028,8 @@ public class RIL extends BaseCommands implements CommandsInterface { break; } } else { - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + if (mHalVersion.get(service) + .greaterOrEqual(RADIO_HAL_VERSION_2_0)) { throw new AssertionError("serviceProxy shouldn't be HIDL with HAL 2.0"); } if (!mIsRadioProxyInitialized) { @@ -1006,6 +1042,7 @@ public class RIL extends BaseCommands implements CommandsInterface { } } else { mDisabledRadioServices.get(service).add(mPhoneId); + mHalVersion.put(service, RADIO_HAL_VERSION_UNKNOWN); riljLoge("getRadioServiceProxy: set " + serviceToString(service) + " for " + HIDL_SERVICE_NAME[mPhoneId] + " as disabled"); } @@ -1034,7 +1071,7 @@ public class RIL extends BaseCommands implements CommandsInterface { 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 == RADIO_SERVICE) { + if (service == HAL_SERVICE_RADIO) { getRadioProxy(null); } else { getRadioServiceProxy(service, null); @@ -1075,7 +1112,11 @@ public class RIL extends BaseCommands implements CommandsInterface { mRadioBugDetector = new RadioBugDetector(context, mPhoneId); } try { - if (isRadioVersion2_0()) mRadioVersion = RADIO_HAL_VERSION_2_0; + if (isRadioVersion2_0()) { + mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_2_0); + } else { + mHalVersion.put(HAL_SERVICE_RADIO, RADIO_HAL_VERSION_UNKNOWN); + } } catch (SecurityException ex) { /* TODO(b/211920208): instead of the following workaround (guessing if we're in a test * based on proxies being populated), mock ServiceManager to not throw @@ -1106,20 +1147,33 @@ public class RIL extends BaseCommands implements CommandsInterface { mRilHandler = new RilHandler(); mRadioProxyDeathRecipient = new RadioProxyDeathRecipient(); for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) { - if (service != RADIO_SERVICE) { + if (service != HAL_SERVICE_RADIO) { + try { + if (isRadioServiceSupported(service)) { + mHalVersion.put(service, RADIO_HAL_VERSION_UNKNOWN); + } else { + mHalVersion.put(service, RADIO_HAL_VERSION_UNSUPPORTED); + } + } catch (SecurityException ex) { + /* TODO(b/211920208): instead of the following workaround (guessing if + * we're in a test based on proxies being populated), mock ServiceManager + * to not throw SecurityException and return correct value based on what + * HAL we're testing. */ + if (proxies == null) throw ex; + } mDeathRecipients.put(service, new BinderServiceDeathRecipient(service)); } mDisabledRadioServices.put(service, new HashSet<>()); mServiceCookies.put(service, new AtomicLong(0)); } if (proxies == null) { - mServiceProxies.put(DATA_SERVICE, new RadioDataProxy()); - mServiceProxies.put(MESSAGING_SERVICE, new RadioMessagingProxy()); - mServiceProxies.put(MODEM_SERVICE, new RadioModemProxy()); - mServiceProxies.put(NETWORK_SERVICE, new RadioNetworkProxy()); - mServiceProxies.put(SIM_SERVICE, new RadioSimProxy()); - mServiceProxies.put(VOICE_SERVICE, new RadioVoiceProxy()); - mServiceProxies.put(IMS_SERVICE, new RadioImsProxy()); + mServiceProxies.put(HAL_SERVICE_DATA, new RadioDataProxy()); + mServiceProxies.put(HAL_SERVICE_MESSAGING, new RadioMessagingProxy()); + mServiceProxies.put(HAL_SERVICE_MODEM, new RadioModemProxy()); + mServiceProxies.put(HAL_SERVICE_NETWORK, new RadioNetworkProxy()); + mServiceProxies.put(HAL_SERVICE_SIM, new RadioSimProxy()); + mServiceProxies.put(HAL_SERVICE_VOICE, new RadioVoiceProxy()); + mServiceProxies.put(HAL_SERVICE_IMS, new RadioImsProxy()); } else { mServiceProxies = proxies; } @@ -1148,7 +1202,7 @@ public class RIL extends BaseCommands implements CommandsInterface { // 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 (service == RADIO_SERVICE) { + if (service == HAL_SERVICE_RADIO) { getRadioProxy(null); } else { if (proxies == null) { @@ -1156,30 +1210,62 @@ public class RIL extends BaseCommands implements CommandsInterface { getRadioServiceProxy(service, null); } } - } - if (RILJ_LOGD) { - riljLog("Radio HAL version: " + mRadioVersion); + if (RILJ_LOGD) { + riljLog("HAL version of " + serviceToString(service) + + ": " + mHalVersion.get(service)); + } } } private boolean isRadioVersion2_0() { - final String[] serviceNames = new String[] { - android.hardware.radio.data.IRadioData.DESCRIPTOR, - android.hardware.radio.messaging.IRadioMessaging.DESCRIPTOR, - android.hardware.radio.modem.IRadioModem.DESCRIPTOR, - android.hardware.radio.network.IRadioNetwork.DESCRIPTOR, - android.hardware.radio.sim.IRadioSim.DESCRIPTOR, - android.hardware.radio.voice.IRadioVoice.DESCRIPTOR, - }; - for (String serviceName : serviceNames) { - if (ServiceManager.isDeclared(serviceName + '/' + HIDL_SERVICE_NAME[mPhoneId])) { + for (int service = HAL_SERVICE_DATA; service <= MAX_SERVICE_IDX; service++) { + if (isRadioServiceSupported(service)) { return true; } } return false; } + private boolean isRadioServiceSupported(int service) { + String serviceName = ""; + + if (service == HAL_SERVICE_RADIO) { + return true; + } + + switch (service) { + case HAL_SERVICE_DATA: + serviceName = android.hardware.radio.data.IRadioData.DESCRIPTOR; + break; + case HAL_SERVICE_MESSAGING: + serviceName = android.hardware.radio.messaging.IRadioMessaging.DESCRIPTOR; + break; + case HAL_SERVICE_MODEM: + serviceName = android.hardware.radio.modem.IRadioModem.DESCRIPTOR; + break; + case HAL_SERVICE_NETWORK: + serviceName = android.hardware.radio.network.IRadioNetwork.DESCRIPTOR; + break; + case HAL_SERVICE_SIM: + serviceName = android.hardware.radio.sim.IRadioSim.DESCRIPTOR; + break; + case HAL_SERVICE_VOICE: + serviceName = android.hardware.radio.voice.IRadioVoice.DESCRIPTOR; + break; + case HAL_SERVICE_IMS: + serviceName = android.hardware.radio.ims.IRadioIms.DESCRIPTOR; + break; + } + + if (!serviceName.equals("") + && ServiceManager.isDeclared(serviceName + '/' + HIDL_SERVICE_NAME[mPhoneId])) { + return true; + } + + return false; + } + private boolean isRadioBugDetectionEnabled() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ENABLE_RADIO_BUG_DETECTION, 1) != 0; @@ -1239,7 +1325,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.getIccCardStatus(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "getIccCardStatus", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getIccCardStatus", e); } } } @@ -1286,7 +1372,7 @@ public class RIL extends BaseCommands implements CommandsInterface { simProxy.supplyIccPinForApp(rr.mSerial, RILUtils.convertNullToEmptyString(pin), RILUtils.convertNullToEmptyString(aid)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "supplyIccPinForApp", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "supplyIccPinForApp", e); } } } @@ -1313,7 +1399,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(newPin), RILUtils.convertNullToEmptyString(aid)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "supplyIccPukForApp", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "supplyIccPukForApp", e); } } } @@ -1339,7 +1425,7 @@ public class RIL extends BaseCommands implements CommandsInterface { simProxy.supplyIccPin2ForApp(rr.mSerial, RILUtils.convertNullToEmptyString(pin), RILUtils.convertNullToEmptyString(aid)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "supplyIccPin2ForApp", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "supplyIccPin2ForApp", e); } } } @@ -1366,7 +1452,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(newPin2), RILUtils.convertNullToEmptyString(aid)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "supplyIccPuk2ForApp", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "supplyIccPuk2ForApp", e); } } } @@ -1394,7 +1480,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(newPin), RILUtils.convertNullToEmptyString(aid)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "changeIccPinForApp", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "changeIccPinForApp", e); } } } @@ -1422,7 +1508,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(newPin2), RILUtils.convertNullToEmptyString(aid)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "changeIccPin2ForApp", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "changeIccPin2ForApp", e); } } } @@ -1444,7 +1530,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(netpin)); } catch (RemoteException | RuntimeException e) { handleRadioProxyExceptionForRR( - NETWORK_SERVICE, "supplyNetworkDepersonalization", e); + HAL_SERVICE_NETWORK, "supplyNetworkDepersonalization", e); } } } @@ -1454,7 +1540,7 @@ public class RIL extends BaseCommands implements CommandsInterface { Message result) { RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); if (simProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) { + if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_DEPERSONALIZATION, result, mRILDefaultWorkSource); @@ -1467,7 +1553,7 @@ public class RIL extends BaseCommands implements CommandsInterface { simProxy.supplySimDepersonalization(rr.mSerial, persoType, RILUtils.convertNullToEmptyString(controlKey)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "supplySimDepersonalization", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "supplySimDepersonalization", e); } } else { if (PersoSubState.PERSOSUBSTATE_SIM_NETWORK == persoType) { @@ -1499,7 +1585,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.getCurrentCalls(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "getCurrentCalls", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getCurrentCalls", e); } } } @@ -1515,7 +1601,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void enableModem(boolean enable, Message result) { RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); if (modemProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_3)) { + if (mHalVersion.get(HAL_SERVICE_MODEM).greaterOrEqual(RADIO_HAL_VERSION_1_3)) { RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_MODEM, result, mRILDefaultWorkSource); if (RILJ_LOGD) { @@ -1526,7 +1612,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.enableModem(rr.mSerial, enable); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "enableModem", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, + "enableModem", e); } } else { if (RILJ_LOGV) riljLog("enableModem: not supported."); @@ -1543,7 +1630,7 @@ public class RIL extends BaseCommands implements CommandsInterface { Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_3)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_3)) { RILRequest rr = obtainRequest(RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS, result, mRILDefaultWorkSource); @@ -1555,7 +1642,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setSystemSelectionChannels(rr.mSerial, specifiers); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setSystemSelectionChannels", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, + "setSystemSelectionChannels", e); } } else { if (RILJ_LOGV) riljLog("setSystemSelectionChannels: not supported."); @@ -1571,7 +1659,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void getSystemSelectionChannels(Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS, result, mRILDefaultWorkSource); @@ -1583,7 +1671,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getSystemSelectionChannels(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getSystemSelectionChannels", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, + "getSystemSelectionChannels", e); } } else { if (RILJ_LOGV) riljLog("getSystemSelectionChannels: not supported."); @@ -1599,7 +1688,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void getModemStatus(Message result) { RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); if (modemProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_3)) { + if (mHalVersion.get(HAL_SERVICE_MODEM).greaterOrEqual(RADIO_HAL_VERSION_1_3)) { RILRequest rr = obtainRequest(RIL_REQUEST_GET_MODEM_STATUS, result, mRILDefaultWorkSource); @@ -1610,7 +1699,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.getModemStackStatus(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "getModemStatus", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getModemStatus", e); } } else { if (RILJ_LOGV) riljLog("getModemStatus: not supported."); @@ -1625,7 +1714,8 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void dial(String address, boolean isEmergencyCall, EmergencyNumber emergencyNumberInfo, boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo, Message result) { - if (isEmergencyCall && mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4) + if (isEmergencyCall + && mHalVersion.get(HAL_SERVICE_VOICE).greaterOrEqual(RADIO_HAL_VERSION_1_4) && emergencyNumberInfo != null) { emergencyDial(address, emergencyNumberInfo, hasKnownUserIntentEmergency, clirMode, uusInfo, result); @@ -1643,7 +1733,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.dial(rr.mSerial, address, clirMode, uusInfo); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "dial", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "dial", e); } } } @@ -1652,7 +1742,7 @@ public class RIL extends BaseCommands implements CommandsInterface { boolean hasKnownUserIntentEmergency, int clirMode, UUSInfo uusInfo, Message result) { RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); if (voiceProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) { + if (mHalVersion.get(HAL_SERVICE_VOICE).greaterOrEqual(RADIO_HAL_VERSION_1_4)) { RILRequest rr = obtainRequest(RIL_REQUEST_EMERGENCY_DIAL, result, mRILDefaultWorkSource); @@ -1665,7 +1755,7 @@ public class RIL extends BaseCommands implements CommandsInterface { voiceProxy.emergencyDial(rr.mSerial, RILUtils.convertNullToEmptyString(address), emergencyNumberInfo, hasKnownUserIntentEmergency, clirMode, uusInfo); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "emergencyDial", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "emergencyDial", e); } } else { riljLoge("emergencyDial is not supported with 1.4 below IRadio"); @@ -1690,7 +1780,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.getImsiForApp(rr.mSerial, RILUtils.convertNullToEmptyString(aid)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "getImsiForApp", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getImsiForApp", e); } } } @@ -1709,7 +1799,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.hangup(rr.mSerial, gsmIndex); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "hangup", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "hangup", e); } } } @@ -1729,7 +1819,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.hangupWaitingOrBackground(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "hangupWaitingOrBackground", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "hangupWaitingOrBackground", e); } } } @@ -1750,7 +1840,7 @@ public class RIL extends BaseCommands implements CommandsInterface { voiceProxy.hangupForegroundResumeBackground(rr.mSerial); } catch (RemoteException | RuntimeException e) { handleRadioProxyExceptionForRR( - VOICE_SERVICE, "hangupForegroundResumeBackground", e); + HAL_SERVICE_VOICE, "hangupForegroundResumeBackground", e); } } } @@ -1769,7 +1859,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.switchWaitingOrHoldingAndActive(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "switchWaitingOrHoldingAndActive", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, + "switchWaitingOrHoldingAndActive", e); } } } @@ -1787,7 +1878,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.conference(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "conference", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "conference", e); } } } @@ -1805,7 +1896,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.rejectCall(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "rejectCall", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "rejectCall", e); } } } @@ -1824,7 +1915,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.getLastCallFailCause(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "getLastCallFailCause", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getLastCallFailCause", e); } } } @@ -1843,7 +1934,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getSignalStrength(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getSignalStrength", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getSignalStrength", e); } } } @@ -1867,7 +1958,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getVoiceRegistrationState(rr.mSerial, overrideHalVersion); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getVoiceRegistrationState", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getVoiceRegistrationState", e); } } } @@ -1891,7 +1982,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getDataRegistrationState(rr.mSerial, overrideHalVersion); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getDataRegistrationState", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getDataRegistrationState", e); } } } @@ -1909,7 +2000,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getOperator(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getOperator", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getOperator", e); } } } @@ -1932,7 +2023,7 @@ public class RIL extends BaseCommands implements CommandsInterface { modemProxy.setRadioPower(rr.mSerial, on, forEmergencyCall, preferredForEmergencyCall); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "setRadioPower", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "setRadioPower", e); } } } @@ -1951,7 +2042,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.sendDtmf(rr.mSerial, c + ""); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "sendDtmf", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "sendDtmf", e); } } } @@ -1973,7 +2064,7 @@ public class RIL extends BaseCommands implements CommandsInterface { mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_GSM, SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "sendSMS", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendSMS", e); } } } @@ -2014,7 +2105,7 @@ public class RIL extends BaseCommands implements CommandsInterface { mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_GSM, SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "sendSMSExpectMore", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendSMSExpectMore", e); } } } @@ -2045,7 +2136,7 @@ public class RIL extends BaseCommands implements CommandsInterface { isRoaming, allowRoaming, reason, linkProperties, pduSessionId, sliceInfo, trafficDescriptor, matchAllRuleAllowed); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "setupDataCall", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setupDataCall", e); } } } @@ -2082,7 +2173,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(pin2), RILUtils.convertNullToEmptyString(aid)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "iccIoForApp", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccIoForApp", e); } } } @@ -2104,7 +2195,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.sendUssd(rr.mSerial, RILUtils.convertNullToEmptyString(ussd)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "sendUssd", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "sendUssd", e); } } } @@ -2123,7 +2214,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.cancelPendingUssd(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "cancelPendingUssd", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "cancelPendingUssd", e); } } } @@ -2141,7 +2232,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.getClir(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "getClir", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getClir", e); } } } @@ -2160,7 +2251,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.setClir(rr.mSerial, clirMode); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "setClir", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setClir", e); } } } @@ -2181,7 +2272,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.getCallForwardStatus(rr.mSerial, cfReason, serviceClass, number); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "getCallForwardStatus", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getCallForwardStatus", e); } } } @@ -2204,7 +2295,7 @@ public class RIL extends BaseCommands implements CommandsInterface { voiceProxy.setCallForward( rr.mSerial, action, cfReason, serviceClass, number, timeSeconds); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "setCallForward", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setCallForward", e); } } } @@ -2224,7 +2315,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.getCallWaiting(rr.mSerial, serviceClass); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "getCallWaiting", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getCallWaiting", e); } } } @@ -2244,7 +2335,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.setCallWaiting(rr.mSerial, enable, serviceClass); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "setCallWaiting", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setCallWaiting", e); } } } @@ -2265,7 +2356,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.acknowledgeLastIncomingGsmSms(rr.mSerial, success, cause); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "acknowledgeLastIncomingGsmSms", e); } } @@ -2285,7 +2376,7 @@ public class RIL extends BaseCommands implements CommandsInterface { voiceProxy.acceptCall(rr.mSerial); mMetrics.writeRilAnswer(mPhoneId, rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "acceptCall", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "acceptCall", e); } } } @@ -2307,7 +2398,7 @@ public class RIL extends BaseCommands implements CommandsInterface { dataProxy.deactivateDataCall(rr.mSerial, cid, reason); mMetrics.writeRilDeactivateDataCall(mPhoneId, rr.mSerial, cid, reason); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "deactivateDataCall", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "deactivateDataCall", e); } } } @@ -2338,7 +2429,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(password), serviceClass, RILUtils.convertNullToEmptyString(appId)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "getFacilityLockForApp", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getFacilityLockForApp", e); } } } @@ -2369,7 +2460,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(password), serviceClass, RILUtils.convertNullToEmptyString(appId)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "setFacilityLockForApp", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "setFacilityLockForApp", e); } } } @@ -2394,7 +2485,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(oldPwd), RILUtils.convertNullToEmptyString(newPwd)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "changeBarringPassword", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "changeBarringPassword", e); } } } @@ -2413,7 +2504,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getNetworkSelectionMode(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getNetworkSelectionMode", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getNetworkSelectionMode", e); } } } @@ -2433,7 +2524,7 @@ public class RIL extends BaseCommands implements CommandsInterface { networkProxy.setNetworkSelectionModeAutomatic(rr.mSerial); } catch (RemoteException | RuntimeException e) { handleRadioProxyExceptionForRR( - NETWORK_SERVICE, "setNetworkSelectionModeAutomatic", e); + HAL_SERVICE_NETWORK, "setNetworkSelectionModeAutomatic", e); } } } @@ -2454,7 +2545,8 @@ public class RIL extends BaseCommands implements CommandsInterface { networkProxy.setNetworkSelectionModeManual(rr.mSerial, RILUtils.convertNullToEmptyString(operatorNumeric), ran); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setNetworkSelectionModeManual", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, + "setNetworkSelectionModeManual", e); } } } @@ -2473,7 +2565,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getAvailableNetworks(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getAvailableNetworks", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getAvailableNetworks", e); } } } @@ -2488,7 +2580,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void startNetworkScan(NetworkScanRequest networkScanRequest, Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_1)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_1)) { HalVersion overrideHalVersion = getCompatVersion(RIL_REQUEST_START_NETWORK_SCAN); if (RILJ_LOGD) { riljLog("startNetworkScan: overrideHalVersion=" + overrideHalVersion); @@ -2505,7 +2597,7 @@ public class RIL extends BaseCommands implements CommandsInterface { networkProxy.startNetworkScan(rr.mSerial, networkScanRequest, overrideHalVersion, result); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "startNetworkScan", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "startNetworkScan", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "startNetworkScan: REQUEST_NOT_SUPPORTED"); @@ -2521,7 +2613,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void stopNetworkScan(Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_1)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_STOP_NETWORK_SCAN, result, mRILDefaultWorkSource); @@ -2532,7 +2624,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.stopNetworkScan(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "stopNetworkScan", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "stopNetworkScan", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "stopNetworkScan: REQUEST_NOT_SUPPORTED"); @@ -2558,7 +2650,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.startDtmf(rr.mSerial, c + ""); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "startDtmf", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "startDtmf", e); } } } @@ -2576,7 +2668,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.stopDtmf(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "stopDtmf", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "stopDtmf", e); } } } @@ -2596,7 +2688,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.separateConnection(rr.mSerial, gsmIndex); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "separateConnection", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "separateConnection", e); } } } @@ -2615,7 +2707,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.getBasebandVersion(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "getBasebandVersion", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getBasebandVersion", e); } } } @@ -2634,7 +2726,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.setMute(rr.mSerial, enableMute); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "setMute", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setMute", e); } } } @@ -2652,7 +2744,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.getMute(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "getMute", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getMute", e); } } } @@ -2670,7 +2762,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.getClip(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "getClip", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getClip", e); } } } @@ -2698,7 +2790,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.getDataCallList(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "getDataCallList", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "getDataCallList", e); } } } @@ -2729,7 +2821,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setSuppServiceNotifications(rr.mSerial, enable); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setSuppServiceNotifications", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, + "setSuppServiceNotifications", e); } } } @@ -2752,7 +2845,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(smsc), RILUtils.convertNullToEmptyString(pdu)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "writeSmsToSim", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "writeSmsToSim", e); } } } @@ -2773,7 +2866,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.deleteSmsOnSim(rr.mSerial, index); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "deleteSmsOnSim", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "deleteSmsOnSim", e); } } } @@ -2792,7 +2885,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setBandMode(rr.mSerial, bandMode); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setBandMode", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setBandMode", e); } } } @@ -2811,7 +2904,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getAvailableBandModes(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "queryAvailableBandMode", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "queryAvailableBandMode", e); } } } @@ -2831,7 +2924,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.sendEnvelope(rr.mSerial, RILUtils.convertNullToEmptyString(contents)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "sendEnvelope", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "sendEnvelope", e); } } } @@ -2853,7 +2946,7 @@ public class RIL extends BaseCommands implements CommandsInterface { simProxy.sendTerminalResponseToSim(rr.mSerial, RILUtils.convertNullToEmptyString(contents)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "sendTerminalResponse", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "sendTerminalResponse", e); } } } @@ -2874,7 +2967,7 @@ public class RIL extends BaseCommands implements CommandsInterface { simProxy.sendEnvelopeWithStatus(rr.mSerial, RILUtils.convertNullToEmptyString(contents)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "sendEnvelopeWithStatus", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "sendEnvelopeWithStatus", e); } } } @@ -2893,7 +2986,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.explicitCallTransfer(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "explicitCallTransfer", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "explicitCallTransfer", e); } } } @@ -2915,7 +3008,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setPreferredNetworkTypeBitmap(rr.mSerial, mAllowedNetworkTypesBitmask); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setPreferredNetworkType", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setPreferredNetworkType", e); } } } @@ -2934,7 +3027,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getAllowedNetworkTypesBitmap(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getPreferredNetworkType", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getPreferredNetworkType", e); } } } @@ -2944,7 +3037,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @TelephonyManager.NetworkTypeBitMask int networkTypeBitmask, Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (!networkProxy.isEmpty()) { - if (mRadioVersion.less(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).less(RADIO_HAL_VERSION_1_6)) { // For older HAL, redirects the call to setPreferredNetworkType. setPreferredNetworkType( RadioAccessFamily.getNetworkTypeFromRaf(networkTypeBitmask), result); @@ -2961,7 +3054,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setAllowedNetworkTypesBitmap(rr.mSerial, mAllowedNetworkTypesBitmask); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setAllowedNetworkTypeBitmask", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, + "setAllowedNetworkTypeBitmask", e); } } } @@ -2980,7 +3074,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getAllowedNetworkTypesBitmap(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getAllowedNetworkTypeBitmask", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, + "getAllowedNetworkTypeBitmask", e); } } } @@ -3000,7 +3095,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setLocationUpdates(rr.mSerial, enable); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setLocationUpdates", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setLocationUpdates", e); } } } @@ -3012,7 +3107,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void isNrDualConnectivityEnabled(Message result, WorkSource workSource) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED, result, getDefaultWorkSourceIfInvalid(workSource)); @@ -3023,7 +3118,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.isNrDualConnectivityEnabled(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "isNrDualConnectivityEnabled", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, + "isNrDualConnectivityEnabled", e); } } else { if (RILJ_LOGD) { @@ -3053,7 +3149,7 @@ public class RIL extends BaseCommands implements CommandsInterface { WorkSource workSource) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_NR_DUAL_CONNECTIVITY, result, getDefaultWorkSourceIfInvalid(workSource)); @@ -3065,7 +3161,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setNrDualConnectivityState(rr.mSerial, (byte) nrDualConnectivityState); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "enableNrDualConnectivity", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "enableNrDualConnectivity", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "enableNrDualConnectivity: REQUEST_NOT_SUPPORTED"); @@ -3091,7 +3187,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void isVoNrEnabled(Message result, WorkSource workSource) { - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + if (mHalVersion.get(HAL_SERVICE_VOICE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); if (!voiceProxy.isEmpty()) { RILRequest rr = obtainRequest(RIL_REQUEST_IS_VONR_ENABLED , result, @@ -3104,7 +3200,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.isVoNrEnabled(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "isVoNrEnabled", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "isVoNrEnabled", e); } } } else { @@ -3124,7 +3220,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void setVoNrEnabled(boolean enabled, Message result, WorkSource workSource) { setVoNrEnabled(enabled); - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + if (mHalVersion.get(HAL_SERVICE_VOICE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); if (!voiceProxy.isEmpty()) { RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_VONR, result, @@ -3137,7 +3233,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.setVoNrEnabled(rr.mSerial, enabled); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "setVoNrEnabled", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setVoNrEnabled", e); } } } else { @@ -3169,7 +3265,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.setCdmaSubscriptionSource(rr.mSerial, cdmaSubscription); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "setCdmaSubscriptionSource", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "setCdmaSubscriptionSource", e); } } } @@ -3188,7 +3284,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getCdmaRoamingPreference(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "queryCdmaRoamingPreference", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, + "queryCdmaRoamingPreference", e); } } } @@ -3208,7 +3305,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setCdmaRoamingPreference(rr.mSerial, cdmaRoamingType); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setCdmaRoamingPreference", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setCdmaRoamingPreference", e); } } } @@ -3227,7 +3324,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.getTtyMode(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "getTtyMode", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getTtyMode", e); } } } @@ -3246,7 +3343,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.setTtyMode(rr.mSerial, ttyMode); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "setTtyMode", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setTtyMode", e); } } } @@ -3266,7 +3363,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.setPreferredVoicePrivacy(rr.mSerial, enable); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "setPreferredVoicePrivacy", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "setPreferredVoicePrivacy", e); } } } @@ -3285,7 +3382,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.getPreferredVoicePrivacy(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "getPreferredVoicePrivacy", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "getPreferredVoicePrivacy", e); } } } @@ -3305,7 +3402,7 @@ public class RIL extends BaseCommands implements CommandsInterface { voiceProxy.sendCdmaFeatureCode(rr.mSerial, RILUtils.convertNullToEmptyString(featureCode)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "sendCdmaFeatureCode", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "sendCdmaFeatureCode", e); } } } @@ -3326,7 +3423,7 @@ public class RIL extends BaseCommands implements CommandsInterface { voiceProxy.sendBurstDtmf(rr.mSerial, RILUtils.convertNullToEmptyString(dtmfString), on, off); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "sendBurstDtmf", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "sendBurstDtmf", e); } } } @@ -3346,13 +3443,13 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.sendCdmaSmsExpectMore(rr.mSerial, pdu); - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) { + if (mHalVersion.get(HAL_SERVICE_MESSAGING).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_CDMA, SmsSession.Event.Format.SMS_FORMAT_3GPP2, getOutgoingSmsMessageId(result)); } } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "sendCdmaSMSExpectMore", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendCdmaSMSExpectMore", e); } } } @@ -3374,7 +3471,7 @@ public class RIL extends BaseCommands implements CommandsInterface { mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_CDMA, SmsSession.Event.Format.SMS_FORMAT_3GPP2, getOutgoingSmsMessageId(result)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "sendCdmaSms", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendCdmaSms", e); } } } @@ -3395,7 +3492,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.acknowledgeLastIncomingCdmaSms(rr.mSerial, success, cause); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "acknowledgeLastIncomingCdmaSms", e); } } @@ -3416,7 +3513,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.getGsmBroadcastConfig(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "getGsmBroadcastConfig", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "getGsmBroadcastConfig", e); } } } @@ -3440,7 +3537,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.setGsmBroadcastConfig(rr.mSerial, config); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "setGsmBroadcastConfig", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "setGsmBroadcastConfig", e); } } } @@ -3461,7 +3558,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.setGsmBroadcastActivation(rr.mSerial, activate); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "setGsmBroadcastActivation", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, + "setGsmBroadcastActivation", e); } } } @@ -3481,7 +3579,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.getCdmaBroadcastConfig(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "getCdmaBroadcastConfig", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "getCdmaBroadcastConfig", e); } } } @@ -3505,7 +3603,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.setCdmaBroadcastConfig(rr.mSerial, configs); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "setCdmaBroadcastConfig", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "setCdmaBroadcastConfig", e); } } } @@ -3526,7 +3624,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.setCdmaBroadcastActivation(rr.mSerial, activate); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "setCdmaBroadcastActivation", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, + "setCdmaBroadcastActivation", e); } } } @@ -3545,7 +3644,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.getCdmaSubscription(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "getCdmaSubscription", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getCdmaSubscription", e); } } } @@ -3566,7 +3665,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.writeSmsToRuim(rr.mSerial, status, pdu); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "writeSmsToRuim", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "writeSmsToRuim", e); } } } @@ -3587,7 +3686,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.deleteSmsOnRuim(rr.mSerial, index); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "deleteSmsOnRuim", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "deleteSmsOnRuim", e); } } } @@ -3606,7 +3705,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.getDeviceIdentity(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "getDeviceIdentity", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getDeviceIdentity", e); } } } @@ -3625,7 +3724,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { voiceProxy.exitEmergencyCallbackMode(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(VOICE_SERVICE, "exitEmergencyCallbackMode", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_VOICE, "exitEmergencyCallbackMode", e); } } } @@ -3645,7 +3744,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.getSmscAddress(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "getSmscAddress", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "getSmscAddress", e); } } } @@ -3667,7 +3766,7 @@ public class RIL extends BaseCommands implements CommandsInterface { messagingProxy.setSmscAddress(rr.mSerial, RILUtils.convertNullToEmptyString(address)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "setSmscAddress", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "setSmscAddress", e); } } } @@ -3688,7 +3787,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { messagingProxy.reportSmsMemoryStatus(rr.mSerial, available); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "reportSmsMemoryStatus", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "reportSmsMemoryStatus", e); } } } @@ -3707,7 +3806,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.reportStkServiceIsRunning(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "reportStkServiceIsRunning", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "reportStkServiceIsRunning", e); } } } @@ -3726,7 +3825,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.getCdmaSubscriptionSource(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "getCdmaSubscriptionSource", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getCdmaSubscriptionSource", e); } } } @@ -3748,7 +3847,7 @@ public class RIL extends BaseCommands implements CommandsInterface { messagingProxy.acknowledgeIncomingGsmSmsWithPdu(rr.mSerial, success, RILUtils.convertNullToEmptyString(ackPdu)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "acknowledgeIncomingGsmSmsWithPdu", e); } } @@ -3768,7 +3867,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getVoiceRadioTechnology(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getVoiceRadioTechnology", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getVoiceRadioTechnology", e); } } } @@ -3787,7 +3886,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getCellInfoList(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getCellInfoList", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getCellInfoList", e); } } } @@ -3807,7 +3906,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setCellInfoListRate(rr.mSerial, rateInMillis); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setCellInfoListRate", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setCellInfoListRate", e); } } } @@ -3827,7 +3926,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.setInitialAttachApn(rr.mSerial, dataProfile, isRoaming); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "setInitialAttachApn", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setInitialAttachApn", e); } } } @@ -3846,7 +3945,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getImsRegistrationState(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getImsRegistrationState", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getImsRegistrationState", e); } } } @@ -3869,7 +3968,7 @@ public class RIL extends BaseCommands implements CommandsInterface { mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_IMS, SmsSession.Event.Format.SMS_FORMAT_3GPP, getOutgoingSmsMessageId(result)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "sendImsGsmSms", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendImsGsmSms", e); } } } @@ -3891,7 +3990,7 @@ public class RIL extends BaseCommands implements CommandsInterface { mMetrics.writeRilSendSms(mPhoneId, rr.mSerial, SmsSession.Event.Tech.SMS_IMS, SmsSession.Event.Format.SMS_FORMAT_3GPP2, getOutgoingSmsMessageId(result)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MESSAGING_SERVICE, "sendImsCdmaSms", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MESSAGING, "sendImsCdmaSms", e); } } } @@ -3919,7 +4018,7 @@ public class RIL extends BaseCommands implements CommandsInterface { simProxy.iccTransmitApduBasicChannel( rr.mSerial, cla, instruction, p1, p2, p3, data); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "iccTransmitApduBasicChannel", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccTransmitApduBasicChannel", e); } } } @@ -3944,7 +4043,7 @@ public class RIL extends BaseCommands implements CommandsInterface { simProxy.iccOpenLogicalChannel(rr.mSerial, RILUtils.convertNullToEmptyString(aid), p2); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "iccOpenLogicalChannel", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccOpenLogicalChannel", e); } } } @@ -3964,7 +4063,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.iccCloseLogicalChannel(rr.mSerial, channel); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "iccCloseLogicalChannel", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccCloseLogicalChannel", e); } } } @@ -3998,7 +4097,7 @@ public class RIL extends BaseCommands implements CommandsInterface { simProxy.iccTransmitApduLogicalChannel( rr.mSerial, channel, cla, instruction, p1, p2, p3, data); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "iccTransmitApduLogicalChannel", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccTransmitApduLogicalChannel", e); } } } @@ -4018,7 +4117,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.nvReadItem(rr.mSerial, itemID); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "nvReadItem", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "nvReadItem", e); } } } @@ -4039,7 +4138,7 @@ public class RIL extends BaseCommands implements CommandsInterface { modemProxy.nvWriteItem(rr.mSerial, itemId, RILUtils.convertNullToEmptyString(itemValue)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "nvWriteItem", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "nvWriteItem", e); } } } @@ -4060,7 +4159,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.nvWriteCdmaPrl(rr.mSerial, preferredRoamingList); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "nvWriteCdmaPrl", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "nvWriteCdmaPrl", e); } } } @@ -4080,7 +4179,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.nvResetConfig(rr.mSerial, resetType); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "nvResetConfig", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "nvResetConfig", e); } } } @@ -4102,7 +4201,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.setUiccSubscription(rr.mSerial, slotId, appIndex, subId, subStatus); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "setUiccSubscription", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "setUiccSubscription", e); } } } @@ -4117,7 +4216,7 @@ public class RIL extends BaseCommands implements CommandsInterface { // EID should be supported as long as HAL >= 1.2. // - in HAL 1.2 we have EID through ATR // - in later HAL versions we also have EID through slot / card status. - return mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2); + return mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_1_2); } @Override @@ -4134,7 +4233,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.setDataAllowed(rr.mSerial, allowed); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "setDataAllowed", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setDataAllowed", e); } } } @@ -4154,7 +4253,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.getHardwareConfig(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "getHardwareConfig", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getHardwareConfig", e); } } } @@ -4177,7 +4276,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILUtils.convertNullToEmptyString(data), RILUtils.convertNullToEmptyString(aid)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "requestIccSimAuthentication", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "requestIccSimAuthentication", e); } } } @@ -4200,7 +4299,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.setDataProfile(rr.mSerial, dps, isRoaming); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "setDataProfile", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setDataProfile", e); } } } @@ -4218,7 +4317,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.requestShutdown(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "requestShutdown", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "requestShutdown", e); } } } @@ -4237,7 +4336,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.getRadioCapability(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "getRadioCapability", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getRadioCapability", e); } } } @@ -4257,14 +4356,14 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.setRadioCapability(rr.mSerial, rc); } catch (Exception e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "setRadioCapability", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "setRadioCapability", e); } } } @Override public void startLceService(int reportIntervalMs, boolean pullMode, Message result) { - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2)) { + if (mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_1_2)) { // We have a 1.2 or later radio, so the LCE 1.0 LCE service control path is unused. // Instead the LCE functionality is always-on and provides unsolicited indications. if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "startLceService: REQUEST_NOT_SUPPORTED"); @@ -4288,14 +4387,14 @@ public class RIL extends BaseCommands implements CommandsInterface { try { radioProxy.startLceService(rr.mSerial, reportIntervalMs, pullMode); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(RADIO_SERVICE, "startLceService", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_RADIO, "startLceService", e); } } } @Override public void stopLceService(Message result) { - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2)) { + if (mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_1_2)) { // We have a 1.2 or later radio, so the LCE 1.0 LCE service control is unused. // Instead the LCE functionality is always-on and provides unsolicited indications. if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "stopLceService: REQUEST_NOT_SUPPORTED"); @@ -4318,7 +4417,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { radioProxy.stopLceService(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(RADIO_SERVICE, "stopLceService", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_RADIO, "stopLceService", e); } } } @@ -4337,7 +4436,7 @@ public class RIL extends BaseCommands implements CommandsInterface { long completionWindowMillis) { RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); if (dataProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_SET_DATA_THROTTLING, result, getDefaultWorkSourceIfInvalid(workSource)); @@ -4352,7 +4451,7 @@ public class RIL extends BaseCommands implements CommandsInterface { dataProxy.setDataThrottling(rr.mSerial, (byte) dataThrottlingAction, completionWindowMillis); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "setDataThrottling", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setDataThrottling", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "setDataThrottling: REQUEST_NOT_SUPPORTED"); @@ -4377,7 +4476,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @Deprecated @Override public void pullLceData(Message result) { - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2)) { + if (mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_1_2)) { // We have a 1.2 or later radio, so the LCE 1.0 LCE service control path is unused. // Instead the LCE functionality is always-on and provides unsolicited indications. if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "pullLceData: REQUEST_NOT_SUPPORTED"); @@ -4400,7 +4499,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { radioProxy.pullLceData(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(RADIO_SERVICE, "pullLceData", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_RADIO, "pullLceData", e); } } } @@ -4422,7 +4521,7 @@ public class RIL extends BaseCommands implements CommandsInterface { mRilHandler.obtainMessage(EVENT_BLOCKING_RESPONSE_TIMEOUT, rr.mSerial); mRilHandler.sendMessageDelayed(msg, DEFAULT_BLOCKING_MESSAGE_RESPONSE_TIMEOUT_MS); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "getModemActivityInfo", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getModemActivityInfo", e); } } } @@ -4445,7 +4544,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.setAllowedCarriers(rr.mSerial, carrierRestrictionRules, result); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "setAllowedCarriers", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "setAllowedCarriers", e); } } } @@ -4464,7 +4563,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.getAllowedCarriers(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "getAllowedCarriers", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getAllowedCarriers", e); } } } @@ -4484,7 +4583,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { modemProxy.sendDeviceState(rr.mSerial, stateType, state); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(MODEM_SERVICE, "sendDeviceState", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "sendDeviceState", e); } } } @@ -4504,7 +4603,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setIndicationFilter(rr.mSerial, filter); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setIndicationFilter", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setIndicationFilter", e); } } } @@ -4514,7 +4613,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @NonNull List signalThresholdInfos, @Nullable Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_2)) { RILRequest rr = obtainRequest(RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA, result, mRILDefaultWorkSource); @@ -4525,7 +4624,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setSignalStrengthReportingCriteria(rr.mSerial, signalThresholdInfos); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setSignalStrengthReportingCriteria", e); } } else { @@ -4539,7 +4638,7 @@ public class RIL extends BaseCommands implements CommandsInterface { Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_2)) { RILRequest rr = obtainRequest(RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA, result, mRILDefaultWorkSource); @@ -4553,7 +4652,7 @@ public class RIL extends BaseCommands implements CommandsInterface { ran); } catch (RemoteException | RuntimeException e) { handleRadioProxyExceptionForRR( - NETWORK_SERVICE, "setLinkCapacityReportingCriteria", e); + HAL_SERVICE_NETWORK, "setLinkCapacityReportingCriteria", e); } } else { riljLoge("setLinkCapacityReportingCriteria ignored on IRadio version less than 1.2"); @@ -4575,7 +4674,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.setSimCardPower(rr.mSerial, state, result); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "setSimCardPower", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "setSimCardPower", e); } } } @@ -4586,7 +4685,7 @@ public class RIL extends BaseCommands implements CommandsInterface { Objects.requireNonNull(imsiEncryptionInfo, "ImsiEncryptionInfo cannot be null."); RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); if (simProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_1)) { + if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION, result, mRILDefaultWorkSource); if (RILJ_LOGD) { @@ -4596,7 +4695,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.setCarrierInfoForImsiEncryption(rr.mSerial, imsiEncryptionInfo); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "setCarrierInfoForImsiEncryption", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, + "setCarrierInfoForImsiEncryption", e); } } else { if (RILJ_LOGD) { @@ -4616,7 +4716,7 @@ public class RIL extends BaseCommands implements CommandsInterface { Objects.requireNonNull(packetData, "KeepaliveRequest cannot be null."); RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); if (dataProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_1)) { + if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_START_KEEPALIVE, result, mRILDefaultWorkSource); @@ -4627,7 +4727,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.startKeepalive(rr.mSerial, contextId, packetData, intervalMillis, result); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "startNattKeepalive", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "startNattKeepalive", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "startNattKeepalive: REQUEST_NOT_SUPPORTED"); @@ -4643,7 +4743,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void stopNattKeepalive(int sessionHandle, Message result) { RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); if (dataProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_1)) { + if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_STOP_KEEPALIVE, result, mRILDefaultWorkSource); @@ -4654,7 +4754,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.stopKeepalive(rr.mSerial, sessionHandle); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "stopNattKeepalive", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "stopNattKeepalive", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "stopNattKeepalive: REQUEST_NOT_SUPPORTED"); @@ -4703,7 +4803,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void enableUiccApplications(boolean enable, Message result) { RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); if (simProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) { + if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_UICC_APPLICATIONS, result, mRILDefaultWorkSource); @@ -4714,7 +4814,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.enableUiccApplications(rr.mSerial, enable); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "enableUiccApplications", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "enableUiccApplications", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "enableUiccApplications: REQUEST_NOT_SUPPORTED"); @@ -4735,7 +4835,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void areUiccApplicationsEnabled(Message result) { RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); if (simProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) { + if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { RILRequest rr = obtainRequest(RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT, result, mRILDefaultWorkSource); @@ -4746,7 +4846,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.areUiccApplicationsEnabled(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "areUiccApplicationsEnabled", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "areUiccApplicationsEnabled", e); } } else { if (RILJ_LOGD) { @@ -4766,7 +4866,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public boolean canToggleUiccApplicationsEnablement() { return !getRadioServiceProxy(RadioSimProxy.class, null).isEmpty() - && mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5); + && mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_1_5); } @Override @@ -4792,7 +4892,7 @@ public class RIL extends BaseCommands implements CommandsInterface { voiceProxy.handleStkCallSetupRequestFromSim(rr.mSerial, accept); } catch (RemoteException | RuntimeException e) { handleRadioProxyExceptionForRR( - VOICE_SERVICE, "handleStkCallSetupRequestFromSim", e); + HAL_SERVICE_VOICE, "handleStkCallSetupRequestFromSim", e); } } } @@ -4804,7 +4904,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void getBarringInfo(Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_5)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_1_5)) { RILRequest rr = obtainRequest(RIL_REQUEST_GET_BARRING_INFO, result, mRILDefaultWorkSource); @@ -4815,7 +4915,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getBarringInfo(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getBarringInfo", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getBarringInfo", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "getBarringInfo: REQUEST_NOT_SUPPORTED"); @@ -4834,7 +4934,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void allocatePduSessionId(Message result) { RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); if (dataProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_ALLOCATE_PDU_SESSION_ID, result, mRILDefaultWorkSource); if (RILJ_LOGD) { @@ -4844,7 +4944,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.allocatePduSessionId(rr.mSerial); } catch (RemoteException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "allocatePduSessionId", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "allocatePduSessionId", e); } } else { AsyncResult.forMessage(result, null, @@ -4860,7 +4960,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void releasePduSessionId(Message result, int pduSessionId) { RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); if (dataProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_RELEASE_PDU_SESSION_ID, result, mRILDefaultWorkSource); if (RILJ_LOGD) { @@ -4870,7 +4970,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.releasePduSessionId(rr.mSerial, pduSessionId); } catch (RemoteException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "releasePduSessionId", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "releasePduSessionId", e); } } else { AsyncResult.forMessage(result, null, @@ -4886,7 +4986,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void startHandover(Message result, int callId) { RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); if (dataProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_START_HANDOVER, result, mRILDefaultWorkSource); if (RILJ_LOGD) { @@ -4896,7 +4996,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.startHandover(rr.mSerial, callId); } catch (RemoteException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "startHandover", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "startHandover", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "startHandover: REQUEST_NOT_SUPPORTED"); @@ -4915,7 +5015,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void cancelHandover(Message result, int callId) { RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); if (dataProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_HANDOVER, result, mRILDefaultWorkSource); if (RILJ_LOGD) { @@ -4925,7 +5025,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.cancelHandover(rr.mSerial, callId); } catch (RemoteException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "cancelHandover", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "cancelHandover", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "cancelHandover: REQUEST_NOT_SUPPORTED"); @@ -4942,7 +5042,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void getSlicingConfig(Message result) { RadioDataProxy dataProxy = getRadioServiceProxy(RadioDataProxy.class, result); if (dataProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_DATA).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_GET_SLICING_CONFIG, result, mRILDefaultWorkSource); @@ -4953,7 +5053,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { dataProxy.getSlicingConfig(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(DATA_SERVICE, "getSlicingConfig", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "getSlicingConfig", e); } } else { if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "getSlicingConfig: REQUEST_NOT_SUPPORTED"); @@ -4967,7 +5067,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void getSimPhonebookRecords(Message result) { RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); if (simProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_PHONEBOOK_RECORDS, result, mRILDefaultWorkSource); @@ -4978,7 +5078,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.getSimPhonebookRecords(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "getSimPhonebookRecords", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getSimPhonebookRecords", e); } } else { if (RILJ_LOGD) { @@ -4996,7 +5096,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void getSimPhonebookCapacity(Message result) { RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); if (simProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_PHONEBOOK_CAPACITY, result, mRILDefaultWorkSource); @@ -5007,7 +5107,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.getSimPhonebookCapacity(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "getSimPhonebookCapacity", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "getSimPhonebookCapacity", e); } } else { if (RILJ_LOGD) { @@ -5025,7 +5125,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void updateSimPhonebookRecord(SimPhonebookRecord phonebookRecord, Message result) { RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); if (simProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_6)) { + if (mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_6)) { RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORD, result, mRILDefaultWorkSource); @@ -5037,7 +5137,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.updateSimPhonebookRecords(rr.mSerial, phonebookRecord); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(SIM_SERVICE, "updateSimPhonebookRecords", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "updateSimPhonebookRecords", e); } } else { if (RILJ_LOGD) { @@ -5062,7 +5162,7 @@ public class RIL extends BaseCommands implements CommandsInterface { /* @TelephonyManager.UsageSetting */ int usageSetting) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RILRequest rr = obtainRequest(RIL_REQUEST_SET_USAGE_SETTING, result, mRILDefaultWorkSource); @@ -5073,7 +5173,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setUsageSetting(rr.mSerial, usageSetting); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setUsageSetting", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setUsageSetting", e); } } else { if (RILJ_LOGD) { @@ -5096,7 +5196,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void getUsageSetting(Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RILRequest rr = obtainRequest(RIL_REQUEST_GET_USAGE_SETTING, result, mRILDefaultWorkSource); @@ -5107,7 +5207,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.getUsageSetting(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "getUsageSetting", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "getUsageSetting", e); } } else { if (RILJ_LOGD) { @@ -5125,7 +5225,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void setSrvccCallInfo(SrvccConnection[] srvccConnections, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_SET_SRVCC_CALL_INFO, result, mRILDefaultWorkSource); @@ -5138,7 +5238,7 @@ public class RIL extends BaseCommands implements CommandsInterface { imsProxy.setSrvccCallInfo(rr.mSerial, RILUtils.convertToHalSrvccCall(srvccConnections)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(IMS_SERVICE, "setSrvccCallInfo", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "setSrvccCallInfo", e); } } else { if (RILJ_LOGD) { @@ -5157,7 +5257,7 @@ public class RIL extends BaseCommands implements CommandsInterface { int accessNetworkType, int suggestedAction, int capabilities, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO, result, mRILDefaultWorkSource); @@ -5176,7 +5276,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { imsProxy.updateImsRegistrationInfo(rr.mSerial, registrationInfo); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(IMS_SERVICE, "updateImsRegistrationInfo", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "updateImsRegistrationInfo", e); } } else { if (RILJ_LOGD) { @@ -5194,7 +5294,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void startImsTraffic(int token, int trafficType, int accessNetworkType, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_START_IMS_TRAFFIC, result, mRILDefaultWorkSource); @@ -5206,7 +5306,7 @@ public class RIL extends BaseCommands implements CommandsInterface { // TODO(ag/20335448): replace 0 with actual trafficDirection imsProxy.startImsTraffic(rr.mSerial, token, trafficType, accessNetworkType, 0); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(IMS_SERVICE, "startImsTraffic", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "startImsTraffic", e); } } else { if (RILJ_LOGD) { @@ -5224,7 +5324,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void stopImsTraffic(int token, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_STOP_IMS_TRAFFIC, result, mRILDefaultWorkSource); @@ -5235,7 +5335,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { imsProxy.stopImsTraffic(rr.mSerial, token); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(IMS_SERVICE, "stopImsTraffic", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "stopImsTraffic", e); } } else { if (RILJ_LOGD) { @@ -5253,7 +5353,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void triggerEpsFallback(int reason, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_TRIGGER_EPS_FALLBACK, result, mRILDefaultWorkSource); @@ -5265,7 +5365,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { imsProxy.triggerEpsFallback(rr.mSerial, reason); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(IMS_SERVICE, "triggerEpsFallback", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "triggerEpsFallback", e); } } else { if (RILJ_LOGD) { @@ -5284,7 +5384,7 @@ public class RIL extends BaseCommands implements CommandsInterface { Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_SEND_ANBR_QUERY, result, mRILDefaultWorkSource); @@ -5295,7 +5395,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { imsProxy.sendAnbrQuery(rr.mSerial, mediaType, direction, bitsPerSecond); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(IMS_SERVICE, "sendAnbrQuery", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "sendAnbrQuery", e); } } else { if (RILJ_LOGD) { @@ -5316,7 +5416,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void setEmergencyMode(int emcMode, Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_SET_EMERGENCY_MODE, result, mRILDefaultWorkSource); @@ -5328,7 +5428,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.setEmergencyMode(rr.mSerial, emcMode); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "setEmergencyMode", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setEmergencyMode", e); } } else { if (RILJ_LOGD) { @@ -5351,7 +5451,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @DomainSelectionService.EmergencyScanType int scanType, Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN, result, mRILDefaultWorkSource); @@ -5363,7 +5463,8 @@ public class RIL extends BaseCommands implements CommandsInterface { networkProxy.triggerEmergencyNetworkScan(rr.mSerial, RILUtils.convertEmergencyNetworkScanTrigger(accessNetwork, scanType)); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "triggerEmergencyNetworkScan", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, + "triggerEmergencyNetworkScan", e); } } else { if (RILJ_LOGD) { @@ -5384,7 +5485,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void cancelEmergencyNetworkScan(boolean resetScan, Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_EMERGENCY_NETWORK_SCAN, result, mRILDefaultWorkSource); @@ -5396,7 +5497,8 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.cancelEmergencyNetworkScan(rr.mSerial, resetScan); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "cancelEmergencyNetworkScan", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, + "cancelEmergencyNetworkScan", e); } } else { if (RILJ_LOGD) { @@ -5417,7 +5519,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void exitEmergencyMode(Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_EXIT_EMERGENCY_MODE, result, mRILDefaultWorkSource); @@ -5428,7 +5530,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { networkProxy.exitEmergencyMode(rr.mSerial); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(NETWORK_SERVICE, "exitEmergencyMode", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "exitEmergencyMode", e); } } else { if (RILJ_LOGD) { @@ -5483,7 +5585,7 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @VisibleForTesting public RILRequest processResponse(RadioResponseInfo responseInfo) { - return processResponseInternal(RADIO_SERVICE, responseInfo.serial, responseInfo.error, + return processResponseInternal(HAL_SERVICE_RADIO, responseInfo.serial, responseInfo.error, responseInfo.type); } @@ -5497,7 +5599,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @VisibleForTesting public RILRequest processResponse_1_6( android.hardware.radio.V1_6.RadioResponseInfo responseInfo) { - return processResponseInternal(RADIO_SERVICE, responseInfo.serial, responseInfo.error, + return processResponseInternal(HAL_SERVICE_RADIO, responseInfo.serial, responseInfo.error, responseInfo.type); } @@ -5509,7 +5611,6 @@ public class RIL extends BaseCommands implements CommandsInterface { * @param responseInfo RadioResponseInfo received in response callback * @return RILRequest corresponding to the response */ - @VisibleForTesting public RILRequest processResponse(int service, android.hardware.radio.RadioResponseInfo responseInfo) { return processResponseInternal(service, responseInfo.serial, responseInfo.error, @@ -5709,13 +5810,13 @@ public class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_RESPONSE_ACKNOWLEDGEMENT, null, mRILDefaultWorkSource); acquireWakeLock(rr, FOR_ACK_WAKELOCK); - if (service == RADIO_SERVICE) { + if (service == HAL_SERVICE_RADIO) { IRadio radioProxy = getRadioProxy(null); if (radioProxy != null) { try { radioProxy.responseAcknowledgement(); } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(RADIO_SERVICE, "sendAck", e); + handleRadioProxyExceptionForRR(HAL_SERVICE_RADIO, "sendAck", e); riljLoge("sendAck: " + e); } } else { @@ -6286,31 +6387,40 @@ public class RIL extends BaseCommands implements CommandsInterface { } /** - * Get the HAL version. + * Get the HAL version with a specific service. * + * @param service the hal service id * @return the current HalVersion */ - public HalVersion getHalVersion() { - return mRadioVersion; + public HalVersion getHalVersion(int service) { + HalVersion halVersion = mHalVersion.get(service); + if (halVersion == null) { + if (isRadioServiceSupported(service)) { + halVersion = RADIO_HAL_VERSION_UNKNOWN; + } else { + halVersion = RADIO_HAL_VERSION_UNSUPPORTED; + } + } + return halVersion; } - private static String serviceToString(int service) { + private static String serviceToString(@HalService int service) { switch (service) { - case RADIO_SERVICE: + case HAL_SERVICE_RADIO: return "RADIO"; - case DATA_SERVICE: + case HAL_SERVICE_DATA: return "DATA"; - case MESSAGING_SERVICE: + case HAL_SERVICE_MESSAGING: return "MESSAGING"; - case MODEM_SERVICE: + case HAL_SERVICE_MODEM: return "MODEM"; - case NETWORK_SERVICE: + case HAL_SERVICE_NETWORK: return "NETWORK"; - case SIM_SERVICE: + case HAL_SERVICE_SIM: return "SIM"; - case VOICE_SERVICE: + case HAL_SERVICE_VOICE: return "VOICE"; - case IMS_SERVICE: + case HAL_SERVICE_IMS: return "IMS"; default: return "UNKNOWN:" + service; diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java index d947d53611..800511bc55 100644 --- a/src/java/com/android/internal/telephony/RadioIndication.java +++ b/src/java/com/android/internal/telephony/RadioIndication.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_RADIO; import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CALL_RING; @@ -136,7 +137,7 @@ public class RadioIndication extends IRadioIndication.Stub { * @param radioState android.hardware.radio.V1_0.RadioState */ public void radioStateChanged(int indicationType, int radioState) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); int state = RILUtils.convertHalRadioState(radioState); if (mRil.isLogOrTrace()) { @@ -148,7 +149,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void callStateChanged(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED); @@ -160,7 +161,7 @@ public class RadioIndication extends IRadioIndication.Stub { * @param indicationType RadioIndicationType */ public void networkStateChanged(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED); @@ -168,7 +169,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void newSms(int indicationType, ArrayList pdu) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); byte[] pduArray = RILUtils.arrayListToPrimitiveArray(pdu); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS); @@ -181,7 +182,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void newSmsStatusReport(int indicationType, ArrayList pdu) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); byte[] pduArray = RILUtils.arrayListToPrimitiveArray(pdu); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT); @@ -192,7 +193,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void newSmsOnSim(int indicationType, int recordNumber) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM); @@ -202,7 +203,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void onUssd(int indicationType, int ussdModeType, String msg) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogMore(RIL_UNSOL_ON_USSD, "" + ussdModeType); @@ -216,7 +217,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void nitzTimeReceived(int indicationType, String nitzTime, long receivedTime) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime); @@ -241,7 +242,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void currentSignalStrength(int indicationType, android.hardware.radio.V1_0.SignalStrength signalStrength) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); SignalStrength ssInitial = RILUtils.convertHalSignalStrength(signalStrength); @@ -259,7 +260,7 @@ public class RadioIndication extends IRadioIndication.Stub { */ public void currentLinkCapacityEstimate(int indicationType, android.hardware.radio.V1_2.LinkCapacityEstimate lce) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); List response = RILUtils.convertHalLceData(lce); @@ -275,7 +276,7 @@ public class RadioIndication extends IRadioIndication.Stub { */ public void currentLinkCapacityEstimate_1_6(int indicationType, android.hardware.radio.V1_6.LinkCapacityEstimate lce) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); List response = RILUtils.convertHalLceData(lce); @@ -291,7 +292,7 @@ public class RadioIndication extends IRadioIndication.Stub { */ public void currentSignalStrength_1_2(int indicationType, android.hardware.radio.V1_2.SignalStrength signalStrength) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength); // Note this is set to "verbose" because it happens frequently @@ -308,7 +309,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void currentSignalStrength_1_4(int indicationType, android.hardware.radio.V1_4.SignalStrength signalStrength) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength); @@ -325,7 +326,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void currentSignalStrength_1_6(int indicationType, android.hardware.radio.V1_6.SignalStrength signalStrength) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); SignalStrength ss = RILUtils.convertHalSignalStrength(signalStrength); @@ -341,7 +342,7 @@ public class RadioIndication extends IRadioIndication.Stub { */ public void currentPhysicalChannelConfigs_1_4(int indicationType, ArrayList configs) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); physicalChannelConfigsIndication(configs); } @@ -350,7 +351,7 @@ public class RadioIndication extends IRadioIndication.Stub { */ public void currentPhysicalChannelConfigs_1_6(int indicationType, ArrayList configs) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); physicalChannelConfigsIndication(configs); } @@ -359,7 +360,7 @@ public class RadioIndication extends IRadioIndication.Stub { */ public void currentPhysicalChannelConfigs(int indicationType, ArrayList configs) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); physicalChannelConfigsIndication(configs); } @@ -368,7 +369,7 @@ public class RadioIndication extends IRadioIndication.Stub { */ public void currentEmergencyNumberList(int indicationType, ArrayList emergencyNumberList) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); List response = new ArrayList<>(emergencyNumberList.size()); for (android.hardware.radio.V1_4.EmergencyNumber emergencyNumberHal @@ -422,7 +423,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void suppSvcNotify(int indicationType, SuppSvcNotification suppSvcNotification) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); SuppServiceNotification notification = new SuppServiceNotification(); notification.notificationType = suppSvcNotification.isMT ? 1 : 0; @@ -441,7 +442,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void stkSessionEnd(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_SESSION_END); @@ -451,7 +452,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void stkProactiveCommand(int indicationType, String cmd) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_PROACTIVE_COMMAND); @@ -461,7 +462,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void stkEventNotify(int indicationType, String cmd) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_EVENT_NOTIFY); @@ -471,7 +472,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void stkCallSetup(int indicationType, long timeout) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_STK_CALL_SETUP, timeout); @@ -481,7 +482,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void simSmsStorageFull(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SIM_SMS_STORAGE_FULL); @@ -491,7 +492,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void simRefresh(int indicationType, SimRefreshResult refreshResult) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); IccRefreshResponse response = new IccRefreshResponse(); response.refreshResult = refreshResult.type; @@ -504,7 +505,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void callRing(int indicationType, boolean isGsm, CdmaSignalInfoRecord record) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); char response[] = null; @@ -527,7 +528,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void simStatusChanged(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED); @@ -535,7 +536,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void cdmaNewSms(int indicationType, CdmaSmsMessage msg) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_CDMA_NEW_SMS); @@ -546,7 +547,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void newBroadcastSms(int indicationType, ArrayList data) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); byte[] response = RILUtils.arrayListToPrimitiveArray(data); if (mRil.isLogOrTrace()) { @@ -560,7 +561,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void cdmaRuimSmsStorageFull(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL); @@ -570,7 +571,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void restrictedStateChanged(int indicationType, int state) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_RESTRICTED_STATE_CHANGED, state); @@ -580,7 +581,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void enterEmergencyCallbackMode(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE); @@ -590,7 +591,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void cdmaCallWaiting(int indicationType, CdmaCallWaiting callWaitingRecord) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); // todo: create a CdmaCallWaitingNotification constructor that takes in these fields to make // sure no fields are missing @@ -614,7 +615,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void cdmaOtaProvisionStatus(int indicationType, int status) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); int response[] = new int[1]; response[0] = status; @@ -628,7 +629,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void cdmaInfoRec(int indicationType, android.hardware.radio.V1_0.CdmaInformationRecords records) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); int numberOfInfoRecs = records.infoRec.size(); for (int i = 0; i < numberOfInfoRecs; i++) { @@ -724,7 +725,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void indicateRingbackTone(int indicationType, boolean start) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_RINGBACK_TONE, start); @@ -732,7 +733,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void resendIncallMute(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESEND_INCALL_MUTE); @@ -740,7 +741,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void cdmaSubscriptionSourceChanged(int indicationType, int cdmaSource) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); int response[] = new int[1]; response[0] = cdmaSource; @@ -754,7 +755,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void cdmaPrlChanged(int indicationType, int version) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); int response[] = new int[1]; response[0] = version; @@ -766,7 +767,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void exitEmergencyCallbackMode(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE); @@ -774,7 +775,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void rilConnected(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RIL_CONNECTED); @@ -787,7 +788,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void voiceRadioTechChanged(int indicationType, int rat) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); int response[] = new int[1]; response[0] = rat; @@ -803,35 +804,35 @@ public class RadioIndication extends IRadioIndication.Stub { /** Get unsolicited message for cellInfoList */ public void cellInfoList(int indicationType, ArrayList records) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); responseCellInfoList(records); } /** Get unsolicited message for cellInfoList using HAL V1_2 */ public void cellInfoList_1_2(int indicationType, ArrayList records) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); responseCellInfoList(records); } /** Get unsolicited message for cellInfoList using HAL V1_4 */ public void cellInfoList_1_4(int indicationType, ArrayList records) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); responseCellInfoList(records); } /** Get unsolicited message for cellInfoList using HAL V1_5 */ public void cellInfoList_1_5(int indicationType, ArrayList records) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); responseCellInfoList(records); } /** Get unsolicited message for cellInfoList using HAL V1_5 */ public void cellInfoList_1_6(int indicationType, ArrayList records) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); responseCellInfoList(records); } @@ -843,7 +844,7 @@ public class RadioIndication extends IRadioIndication.Stub { /** Get unsolicited message for uicc applications enablement changes. */ public void uiccApplicationsEnablementChanged(int indicationType, boolean enabled) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) { mRil.unsljLogRet(RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED, enabled); @@ -883,7 +884,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void imsNetworkStateChanged(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED); @@ -891,7 +892,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void subscriptionStatusChanged(int indicationType, boolean activate) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); int response[] = new int[1]; response[0] = activate ? 1 : 0; @@ -905,7 +906,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void srvccStateNotify(int indicationType, int state) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); int response[] = new int[1]; response[0] = state; @@ -921,7 +922,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void hardwareConfigChanged( int indicationType, ArrayList configs) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); ArrayList response = RILUtils.convertHalHardwareConfigList(configs); @@ -933,7 +934,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void radioCapabilityIndication(int indicationType, android.hardware.radio.V1_0.RadioCapability rc) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); RadioCapability response = RILUtils.convertHalRadioCapability(rc, mRil); @@ -944,7 +945,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void onSupplementaryServiceIndication(int indicationType, StkCcUnsolSsResult ss) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); int num; SsData ssData = new SsData(); @@ -992,7 +993,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void stkCallControlAlphaNotify(int indicationType, String alpha) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_STK_CC_ALPHA_NOTIFY, alpha); @@ -1002,7 +1003,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void lceData(int indicationType, LceDataInfo lce) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); List response = RILUtils.convertHalLceData(lce); @@ -1014,7 +1015,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void pcoData(int indicationType, PcoDataInfo pco) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); PcoData response = new PcoData(pco.cid, pco.bearerProto, pco.pcoId, RILUtils.arrayListToPrimitiveArray(pco.contents)); @@ -1025,7 +1026,7 @@ public class RadioIndication extends IRadioIndication.Stub { } public void modemReset(int indicationType, String reason) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_MODEM_RESTART, reason); @@ -1038,7 +1039,7 @@ public class RadioIndication extends IRadioIndication.Stub { * @param indicationType RadioIndicationType */ public void carrierInfoForImsiEncryption(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) { mRil.unsljLogRet(RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION, null); @@ -1055,7 +1056,7 @@ public class RadioIndication extends IRadioIndication.Stub { */ public void keepaliveStatus( int indicationType, android.hardware.radio.V1_1.KeepaliveStatus halStatus) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) { mRil.unsljLogRet( @@ -1074,7 +1075,7 @@ public class RadioIndication extends IRadioIndication.Stub { * @param indicationType RadioIndicationType */ public void simPhonebookChanged(int indicationType) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) { mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_CHANGED); @@ -1091,7 +1092,7 @@ public class RadioIndication extends IRadioIndication.Stub { */ public void simPhonebookRecordsReceived(int indicationType, byte status, ArrayList records) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); List simPhonebookRecords = new ArrayList<>(); @@ -1124,7 +1125,7 @@ public class RadioIndication extends IRadioIndication.Stub { android.hardware.radio.V1_5.CellIdentity cellIdentity, String chosenPlmn, @NetworkRegistrationInfo.Domain int domain, int causeCode, int additionalCauseCode) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); CellIdentity ci = RILUtils.convertHalCellIdentity(cellIdentity); if (ci == null || TextUtils.isEmpty(chosenPlmn) @@ -1155,7 +1156,7 @@ public class RadioIndication extends IRadioIndication.Stub { public void barringInfoChanged(int indicationType, android.hardware.radio.V1_5.CellIdentity cellIdentity, ArrayList barringInfos) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (cellIdentity == null || barringInfos == null) { reportAnomaly( @@ -1270,7 +1271,7 @@ public class RadioIndication extends IRadioIndication.Stub { private void responseNetworkScan(int indicationType, android.hardware.radio.V1_1.NetworkScanResult result) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); ArrayList cellInfos = RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); @@ -1281,7 +1282,7 @@ public class RadioIndication extends IRadioIndication.Stub { private void responseNetworkScan_1_2(int indicationType, android.hardware.radio.V1_2.NetworkScanResult result) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); ArrayList cellInfos = RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); @@ -1292,7 +1293,7 @@ public class RadioIndication extends IRadioIndication.Stub { private void responseNetworkScan_1_4(int indicationType, android.hardware.radio.V1_4.NetworkScanResult result) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); ArrayList cellInfos = RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); @@ -1303,7 +1304,7 @@ public class RadioIndication extends IRadioIndication.Stub { private void responseNetworkScan_1_5(int indicationType, android.hardware.radio.V1_5.NetworkScanResult result) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); ArrayList cellInfos = RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); @@ -1314,7 +1315,7 @@ public class RadioIndication extends IRadioIndication.Stub { private void responseNetworkScan_1_6(int indicationType, android.hardware.radio.V1_6.NetworkScanResult result) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); ArrayList cellInfos = RILUtils.convertHalCellInfoList(new ArrayList<>(result.networkInfos)); @@ -1324,7 +1325,7 @@ public class RadioIndication extends IRadioIndication.Stub { } private void responseDataCallListChanged(int indicationType, List dcList) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_DATA_CALL_LIST_CHANGED, dcList); @@ -1334,7 +1335,7 @@ public class RadioIndication extends IRadioIndication.Stub { } private void responseApnUnthrottled(int indicationType, String apn) { - mRil.processIndication(RIL.RADIO_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_UNTHROTTLE_APN, apn); diff --git a/src/java/com/android/internal/telephony/SignalStrengthController.java b/src/java/com/android/internal/telephony/SignalStrengthController.java index 6e32cf34ee..0c21ebf158 100644 --- a/src/java/com/android/internal/telephony/SignalStrengthController.java +++ b/src/java/com/android/internal/telephony/SignalStrengthController.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.BroadcastReceiver; @@ -423,7 +425,7 @@ public class SignalStrengthController extends Handler { (lteMeasurementEnabled & CellSignalStrengthLte.USE_RSRP) != 0)); } - if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { + if (mPhone.getHalVersion(HAL_SERVICE_NETWORK).greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { int[] lteRsrqThresholds = mCarrierConfig.getIntArray( CarrierConfigManager.KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY); if (lteRsrqThresholds != null) { @@ -525,7 +527,7 @@ public class SignalStrengthController extends Handler { AccessNetworkConstants.AccessNetworkType.CDMA2000, true)); - if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { + if (mPhone.getHalVersion(HAL_SERVICE_NETWORK).greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { signalThresholdInfos.add( createSignalThresholdsInfo( SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ, diff --git a/src/java/com/android/internal/telephony/SimIndication.java b/src/java/com/android/internal/telephony/SimIndication.java index 20f89da73f..d74a9b1194 100644 --- a/src/java/com/android/internal/telephony/SimIndication.java +++ b/src/java/com/android/internal/telephony/SimIndication.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; + import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_CHANGED; @@ -53,7 +55,7 @@ public class SimIndication extends IRadioSimIndication.Stub { * @param indicationType Type of radio indication */ public void carrierInfoForImsiEncryption(int indicationType) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); if (mRil.isLogOrTrace()) { mRil.unsljLogRet(RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION, null); @@ -69,7 +71,7 @@ public class SimIndication extends IRadioSimIndication.Stub { * @param cdmaSource New CdmaSubscriptionSource */ public void cdmaSubscriptionSourceChanged(int indicationType, int cdmaSource) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); int[] response = new int[]{cdmaSource}; if (mRil.isLogOrTrace()) { @@ -85,7 +87,7 @@ public class SimIndication extends IRadioSimIndication.Stub { * @param indicationType Type of radio indication */ public void simPhonebookChanged(int indicationType) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); if (mRil.isLogOrTrace()) { mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_CHANGED); @@ -102,7 +104,7 @@ public class SimIndication extends IRadioSimIndication.Stub { */ public void simPhonebookRecordsReceived(int indicationType, byte status, android.hardware.radio.sim.PhonebookRecordInfo[] records) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); List simPhonebookRecords = new ArrayList<>(); @@ -127,7 +129,7 @@ public class SimIndication extends IRadioSimIndication.Stub { */ public void simRefresh(int indicationType, android.hardware.radio.sim.SimRefreshResult refreshResult) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); IccRefreshResponse response = new IccRefreshResponse(); response.refreshResult = refreshResult.type; @@ -144,7 +146,7 @@ public class SimIndication extends IRadioSimIndication.Stub { * @param indicationType Type of radio indication */ public void simStatusChanged(int indicationType) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED); @@ -159,7 +161,7 @@ public class SimIndication extends IRadioSimIndication.Stub { * Refer to TS 102.223 section 9.4 for command types */ public void stkEventNotify(int indicationType, String cmd) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_EVENT_NOTIFY); @@ -175,7 +177,7 @@ public class SimIndication extends IRadioSimIndication.Stub { * Refer to TS 102.223 section 9.4 for command types */ public void stkProactiveCommand(int indicationType, String cmd) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_PROACTIVE_COMMAND); @@ -189,7 +191,7 @@ public class SimIndication extends IRadioSimIndication.Stub { * @param indicationType Type of radio indication */ public void stkSessionEnd(int indicationType) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_STK_SESSION_END); @@ -204,7 +206,7 @@ public class SimIndication extends IRadioSimIndication.Stub { * @param activate false for subscription deactivated, true for subscription activated */ public void subscriptionStatusChanged(int indicationType, boolean activate) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); int[] response = new int[]{activate ? 1 : 0}; @@ -222,7 +224,7 @@ public class SimIndication extends IRadioSimIndication.Stub { * @param enabled Whether uiccApplications are enabled or disabled */ public void uiccApplicationsEnablementChanged(int indicationType, boolean enabled) { - mRil.processIndication(RIL.SIM_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_SIM, indicationType); if (mRil.isLogOrTrace()) { mRil.unsljLogRet(RIL_UNSOL_UICC_APPLICATIONS_ENABLEMENT_CHANGED, enabled); diff --git a/src/java/com/android/internal/telephony/SimResponse.java b/src/java/com/android/internal/telephony/SimResponse.java index b0099fbf28..5f05c584fc 100644 --- a/src/java/com/android/internal/telephony/SimResponse.java +++ b/src/java/com/android/internal/telephony/SimResponse.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; + import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.sim.IRadioSimResponse; @@ -41,7 +43,7 @@ public class SimResponse extends IRadioSimResponse.Stub { private void responseIccIo(RadioResponseInfo responseInfo, android.hardware.radio.sim.IccIoResult result) { - RILRequest rr = mRil.processResponse(RIL.SIM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_SIM, responseInfo); if (rr != null) { IccIoResult ret = new IccIoResult(result.sw1, result.sw2, result.simResponse); @@ -68,7 +70,7 @@ public class SimResponse extends IRadioSimResponse.Stub { */ public void areUiccApplicationsEnabledResponse(RadioResponseInfo responseInfo, boolean enabled) { - RILRequest rr = mRil.processResponse(RIL.SIM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_SIM, responseInfo); if (rr != null) { if (responseInfo.error == RadioError.NONE) { @@ -83,7 +85,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown. */ public void changeIccPin2ForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) { - RadioResponse.responseInts(RIL.SIM_SERVICE, mRil, responseInfo, remainingAttempts); + RadioResponse.responseInts(HAL_SERVICE_SIM, mRil, responseInfo, remainingAttempts); } /** @@ -91,14 +93,14 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown. */ public void changeIccPinForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) { - RadioResponse.responseInts(RIL.SIM_SERVICE, mRil, responseInfo, remainingAttempts); + RadioResponse.responseInts(HAL_SERVICE_SIM, mRil, responseInfo, remainingAttempts); } /** * @param responseInfo Response info struct containing response type, serial no. and error. */ public void enableUiccApplicationsResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.SIM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); } /** @@ -109,7 +111,7 @@ public class SimResponse extends IRadioSimResponse.Stub { public void getAllowedCarriersResponse(RadioResponseInfo responseInfo, android.hardware.radio.sim.CarrierRestrictions carrierRestrictions, int multiSimPolicy) { - RILRequest rr = mRil.processResponse(RIL.SIM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_SIM, responseInfo); if (rr == null) { return; } @@ -154,7 +156,7 @@ public class SimResponse extends IRadioSimResponse.Stub { public void getCdmaSubscriptionResponse(RadioResponseInfo responseInfo, String mdn, String hSid, String hNid, String min, String prl) { RadioResponse.responseStrings( - RIL.SIM_SERVICE, mRil, responseInfo, mdn, hSid, hNid, min, prl); + HAL_SERVICE_SIM, mRil, responseInfo, mdn, hSid, hNid, min, prl); } /** @@ -162,7 +164,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param source CDMA subscription source */ public void getCdmaSubscriptionSourceResponse(RadioResponseInfo responseInfo, int source) { - RadioResponse.responseInts(RIL.SIM_SERVICE, mRil, responseInfo, source); + RadioResponse.responseInts(HAL_SERVICE_SIM, mRil, responseInfo, source); } /** @@ -171,7 +173,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * specified barring facility is active. "0" means "disabled for all" */ public void getFacilityLockForAppResponse(RadioResponseInfo responseInfo, int response) { - RadioResponse.responseInts(RIL.SIM_SERVICE, mRil, responseInfo, response); + RadioResponse.responseInts(HAL_SERVICE_SIM, mRil, responseInfo, response); } /** @@ -180,7 +182,7 @@ public class SimResponse extends IRadioSimResponse.Stub { */ public void getIccCardStatusResponse(RadioResponseInfo responseInfo, android.hardware.radio.sim.CardStatus cardStatus) { - RILRequest rr = mRil.processResponse(RIL.SIM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_SIM, responseInfo); if (rr != null) { IccCardStatus iccCardStatus = RILUtils.convertHalCardStatus(cardStatus); @@ -197,7 +199,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param imsi String containing the IMSI */ public void getImsiForAppResponse(RadioResponseInfo responseInfo, String imsi) { - RadioResponse.responseString(RIL.SIM_SERVICE, mRil, responseInfo, imsi); + RadioResponse.responseString(HAL_SERVICE_SIM, mRil, responseInfo, imsi); } /** @@ -207,7 +209,7 @@ public class SimResponse extends IRadioSimResponse.Stub { public void getSimPhonebookCapacityResponse(RadioResponseInfo responseInfo, android.hardware.radio.sim.PhonebookCapacity pbCapacity) { AdnCapacity capacity = RILUtils.convertHalPhonebookCapacity(pbCapacity); - RILRequest rr = mRil.processResponse(RIL.SIM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_SIM, responseInfo); if (rr != null) { if (responseInfo.error == RadioError.NONE) { RadioResponse.sendMessageResponse(rr.mResult, capacity); @@ -220,14 +222,14 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error. */ public void getSimPhonebookRecordsResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.SIM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void iccCloseLogicalChannelResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.SIM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); } /** @@ -252,7 +254,7 @@ public class SimResponse extends IRadioSimResponse.Stub { for (int i = 0; i < selectResponse.length; i++) { arr.add((int) selectResponse[i]); } - RadioResponse.responseIntArrayList(RIL.SIM_SERVICE, mRil, responseInfo, arr); + RadioResponse.responseIntArrayList(HAL_SERVICE_SIM, mRil, responseInfo, arr); } /** @@ -277,7 +279,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void reportStkServiceIsRunningResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.SIM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); } /** @@ -286,7 +288,7 @@ public class SimResponse extends IRadioSimResponse.Stub { */ public void requestIccSimAuthenticationResponse(RadioResponseInfo responseInfo, android.hardware.radio.sim.IccIoResult iccIo) { - RILRequest rr = mRil.processResponse(RIL.SIM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_SIM, responseInfo); if (rr != null) { IccIoResult ret = new IccIoResult(iccIo.sw1, iccIo.sw2, @@ -315,7 +317,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * string starting with first byte of response */ public void sendEnvelopeResponse(RadioResponseInfo responseInfo, String commandResponse) { - RadioResponse.responseString(RIL.SIM_SERVICE, mRil, responseInfo, commandResponse); + RadioResponse.responseString(HAL_SERVICE_SIM, mRil, responseInfo, commandResponse); } /** @@ -331,7 +333,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void sendTerminalResponseToSimResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.SIM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); } /** @@ -339,7 +341,7 @@ public class SimResponse extends IRadioSimResponse.Stub { */ public void setAllowedCarriersResponse(RadioResponseInfo responseInfo) { int ret = TelephonyManager.SET_CARRIER_RESTRICTION_ERROR; - RILRequest rr = mRil.processResponse(RIL.SIM_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_SIM, responseInfo); if (rr != null) { mRil.riljLog("setAllowedCarriersResponse - error = " + responseInfo.error); @@ -355,14 +357,14 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void setCarrierInfoForImsiEncryptionResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.SIM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setCdmaSubscriptionSourceResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.SIM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); } /** @@ -370,21 +372,21 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param retry 0 is the number of retries remaining, or -1 if unknown */ public void setFacilityLockForAppResponse(RadioResponseInfo responseInfo, int retry) { - RadioResponse.responseInts(RIL.SIM_SERVICE, mRil, responseInfo, retry); + RadioResponse.responseInts(HAL_SERVICE_SIM, mRil, responseInfo, retry); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setSimCardPowerResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.SIM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setUiccSubscriptionResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.SIM_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); } /** @@ -392,7 +394,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown. */ public void supplyIccPin2ForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) { - RadioResponse.responseInts(RIL.SIM_SERVICE, mRil, responseInfo, remainingAttempts); + RadioResponse.responseInts(HAL_SERVICE_SIM, mRil, responseInfo, remainingAttempts); } /** @@ -400,7 +402,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown. */ public void supplyIccPinForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) { - RadioResponse.responseInts(RIL.SIM_SERVICE, mRil, responseInfo, remainingAttempts); + RadioResponse.responseInts(HAL_SERVICE_SIM, mRil, responseInfo, remainingAttempts); } /** @@ -408,7 +410,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown. */ public void supplyIccPuk2ForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) { - RadioResponse.responseInts(RIL.SIM_SERVICE, mRil, responseInfo, remainingAttempts); + RadioResponse.responseInts(HAL_SERVICE_SIM, mRil, responseInfo, remainingAttempts); } /** @@ -416,7 +418,7 @@ public class SimResponse extends IRadioSimResponse.Stub { * @param remainingAttempts Number of retries remaining, must be equal to -1 if unknown. */ public void supplyIccPukForAppResponse(RadioResponseInfo responseInfo, int remainingAttempts) { - RadioResponse.responseInts(RIL.SIM_SERVICE, mRil, responseInfo, remainingAttempts); + RadioResponse.responseInts(HAL_SERVICE_SIM, mRil, responseInfo, remainingAttempts); } /** @@ -428,7 +430,7 @@ public class SimResponse extends IRadioSimResponse.Stub { public void supplySimDepersonalizationResponse(RadioResponseInfo responseInfo, int persoType, int remainingRetries) { RadioResponse.responseInts( - RIL.SIM_SERVICE, mRil, responseInfo, persoType, remainingRetries); + HAL_SERVICE_SIM, mRil, responseInfo, persoType, remainingRetries); } /** @@ -437,7 +439,7 @@ public class SimResponse extends IRadioSimResponse.Stub { */ public void updateSimPhonebookRecordsResponse(RadioResponseInfo responseInfo, int updatedRecordIndex) { - RadioResponse.responseInts(RIL.SIM_SERVICE, mRil, responseInfo, updatedRecordIndex); + RadioResponse.responseInts(HAL_SERVICE_SIM, mRil, responseInfo, updatedRecordIndex); } @Override diff --git a/src/java/com/android/internal/telephony/VoiceIndication.java b/src/java/com/android/internal/telephony/VoiceIndication.java index 984d2a0aff..9720bb76ab 100644 --- a/src/java/com/android/internal/telephony/VoiceIndication.java +++ b/src/java/com/android/internal/telephony/VoiceIndication.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; + import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CALL_RING; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_CALL_WAITING; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CDMA_INFO_REC; @@ -63,7 +65,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { */ public void callRing(int indicationType, boolean isGsm, android.hardware.radio.voice.CdmaSignalInfoRecord record) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); char[] response = null; @@ -90,7 +92,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { * @param indicationType Type of radio indication */ public void callStateChanged(int indicationType) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED); @@ -104,7 +106,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { */ public void cdmaCallWaiting(int indicationType, android.hardware.radio.voice.CdmaCallWaiting callWaitingRecord) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); // TODO: create a CdmaCallWaitingNotification constructor that takes in these fields to make // sure no fields are missing @@ -134,7 +136,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { */ public void cdmaInfoRec(int indicationType, android.hardware.radio.voice.CdmaInformationRecord[] records) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); for (int i = 0; i < records.length; i++) { android.hardware.radio.voice.CdmaInformationRecord record = records[i]; @@ -233,7 +235,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { * @param status CDMA OTA provision status */ public void cdmaOtaProvisionStatus(int indicationType, int status) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); int[] response = new int[] {status}; @@ -252,7 +254,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { */ public void currentEmergencyNumberList(int indicationType, android.hardware.radio.voice.EmergencyNumber[] emergencyNumberList) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); List response = new ArrayList<>(emergencyNumberList.length); for (android.hardware.radio.voice.EmergencyNumber enHal : emergencyNumberList) { @@ -279,7 +281,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { * @param indicationType Type of radio indication */ public void enterEmergencyCallbackMode(int indicationType) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE); @@ -294,7 +296,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { * @param indicationType Type of radio indication */ public void exitEmergencyCallbackMode(int indicationType) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE); @@ -307,7 +309,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { * @param start true = start play ringback tone, false = stop playing ringback tone */ public void indicateRingbackTone(int indicationType, boolean start) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogvRet(RIL_UNSOL_RINGBACK_TONE, start); @@ -322,7 +324,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { */ public void onSupplementaryServiceIndication(int indicationType, android.hardware.radio.voice.StkCcUnsolSsResult ss) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); int num; SsData ssData = new SsData(); @@ -374,7 +376,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { * @param msg Message string in UTF-8, if applicable */ public void onUssd(int indicationType, int ussdModeType, String msg) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogMore(RIL_UNSOL_ON_USSD, "" + ussdModeType); @@ -390,7 +392,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { * @param indicationType Type of radio indication */ public void resendIncallMute(int indicationType) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_RESEND_INCALL_MUTE); @@ -403,7 +405,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { * @param state New SRVCC State */ public void srvccStateNotify(int indicationType, int state) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); int[] response = new int[] {state}; @@ -419,7 +421,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { * @param alpha ALPHA string from UICC in UTF-8 format */ public void stkCallControlAlphaNotify(int indicationType, String alpha) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_STK_CC_ALPHA_NOTIFY, alpha); @@ -434,7 +436,7 @@ public class VoiceIndication extends IRadioVoiceIndication.Stub { * @param timeout Timeout value in milliseconds for setting up voice call */ public void stkCallSetup(int indicationType, long timeout) { - mRil.processIndication(RIL.VOICE_SERVICE, indicationType); + mRil.processIndication(HAL_SERVICE_VOICE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLogRet(RIL_UNSOL_STK_CALL_SETUP, timeout); diff --git a/src/java/com/android/internal/telephony/VoiceResponse.java b/src/java/com/android/internal/telephony/VoiceResponse.java index b1ba9d98e1..d1e060ee81 100644 --- a/src/java/com/android/internal/telephony/VoiceResponse.java +++ b/src/java/com/android/internal/telephony/VoiceResponse.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; + import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.voice.IRadioVoiceResponse; @@ -47,49 +49,49 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void acceptCallResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void cancelPendingUssdResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void conferenceResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void dialResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void emergencyDialResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void exitEmergencyCallbackModeResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void explicitCallTransferResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** @@ -99,7 +101,7 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { */ public void getCallForwardStatusResponse(RadioResponseInfo responseInfo, android.hardware.radio.voice.CallForwardInfo[] callForwardInfos) { - RILRequest rr = mRil.processResponse(RIL.VOICE_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_VOICE, responseInfo); if (rr != null) { CallForwardInfo[] ret = new CallForwardInfo[callForwardInfos.length]; for (int i = 0; i < callForwardInfos.length; i++) { @@ -129,7 +131,7 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { public void getCallWaitingResponse(RadioResponseInfo responseInfo, boolean enable, int serviceClass) { RadioResponse.responseInts( - RIL.VOICE_SERVICE, mRil, responseInfo, enable ? 1 : 0, serviceClass); + HAL_SERVICE_VOICE, mRil, responseInfo, enable ? 1 : 0, serviceClass); } /** @@ -137,7 +139,7 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { * @param status indicates CLIP status */ public void getClipResponse(RadioResponseInfo responseInfo, int status) { - RadioResponse.responseInts(RIL.VOICE_SERVICE, mRil, responseInfo, status); + RadioResponse.responseInts(HAL_SERVICE_VOICE, mRil, responseInfo, status); } /** @@ -146,7 +148,7 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { * @param m is "m" parameter from TS 27.007 7.7 */ public void getClirResponse(RadioResponseInfo responseInfo, int n, int m) { - RadioResponse.responseInts(RIL.VOICE_SERVICE, mRil, responseInfo, n, m); + RadioResponse.responseInts(HAL_SERVICE_VOICE, mRil, responseInfo, n, m); } /** @@ -155,7 +157,7 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { */ public void getCurrentCallsResponse(RadioResponseInfo responseInfo, android.hardware.radio.voice.Call[] calls) { - RILRequest rr = mRil.processResponse(RIL.VOICE_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_VOICE, responseInfo); if (rr != null) { int num = calls.length; @@ -198,7 +200,7 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { */ public void getLastCallFailCauseResponse(RadioResponseInfo responseInfo, android.hardware.radio.voice.LastCallFailCauseInfo fcInfo) { - RILRequest rr = mRil.processResponse(RIL.VOICE_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_VOICE, responseInfo); if (rr != null) { LastCallFailCause ret = new LastCallFailCause(); @@ -216,7 +218,7 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { * @param enable true for "mute enabled" and false for "mute disabled" */ public void getMuteResponse(RadioResponseInfo responseInfo, boolean enable) { - RadioResponse.responseInts(RIL.VOICE_SERVICE, mRil, responseInfo, enable ? 1 : 0); + RadioResponse.responseInts(HAL_SERVICE_VOICE, mRil, responseInfo, enable ? 1 : 0); } /** @@ -225,7 +227,7 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { * true for Enhanced Privacy Mode (Private Long Code Mask) */ public void getPreferredVoicePrivacyResponse(RadioResponseInfo responseInfo, boolean enable) { - RadioResponse.responseInts(RIL.VOICE_SERVICE, mRil, responseInfo, enable ? 1 : 0); + RadioResponse.responseInts(HAL_SERVICE_VOICE, mRil, responseInfo, enable ? 1 : 0); } /** @@ -233,35 +235,35 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { * @param mode TTY mode */ public void getTtyModeResponse(RadioResponseInfo responseInfo, int mode) { - RadioResponse.responseInts(RIL.VOICE_SERVICE, mRil, responseInfo, mode); + RadioResponse.responseInts(HAL_SERVICE_VOICE, mRil, responseInfo, mode); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void handleStkCallSetupRequestFromSimResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void hangupConnectionResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void hangupForegroundResumeBackgroundResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void hangupWaitingOrBackgroundResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** @@ -269,7 +271,7 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { * @param enable true for "vonr enabled" and false for "vonr disabled" */ public void isVoNrEnabledResponse(RadioResponseInfo responseInfo, boolean enable) { - RILRequest rr = mRil.processResponse(RIL.VOICE_SERVICE, responseInfo); + RILRequest rr = mRil.processResponse(HAL_SERVICE_VOICE, responseInfo); if (rr != null) { if (responseInfo.error == RadioError.NONE) { @@ -283,112 +285,112 @@ public class VoiceResponse extends IRadioVoiceResponse.Stub { * @param responseInfo Response info struct containing response type, serial no. and error */ public void rejectCallResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void sendBurstDtmfResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void sendCdmaFeatureCodeResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void sendDtmfResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void sendUssdResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void separateConnectionResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setCallForwardResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setCallWaitingResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setClirResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setMuteResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setPreferredVoicePrivacyResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setTtyModeResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void setVoNrEnabledResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void startDtmfResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void stopDtmfResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } /** * @param responseInfo Response info struct containing response type, serial no. and error */ public void switchWaitingOrHoldingAndActiveResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.VOICE_SERVICE, mRil, responseInfo); + RadioResponse.responseVoid(HAL_SERVICE_VOICE, mRil, responseInfo); } @Override diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index d034abdf3a..66996f4755 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.data; +import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; + import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; @@ -582,7 +584,7 @@ public class AccessNetworksManager extends Handler { return true; } - return mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_4); + return mPhone.getHalVersion(HAL_SERVICE_DATA).less(RIL.RADIO_HAL_VERSION_1_4); } /** diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index e122591c9a..dabe43fd1c 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.data; +import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; + import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; @@ -2538,9 +2540,9 @@ public class DataNetwork extends StateMachine { log("Remove network since deactivate request returned an error."); mFailCause = DataFailCause.RADIO_NOT_AVAILABLE; transitionTo(mDisconnectedState); - } else if (mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_2_0)) { + } else if (mPhone.getHalVersion(HAL_SERVICE_DATA).less(RIL.RADIO_HAL_VERSION_2_0)) { log("Remove network on deactivate data response on old HAL " - + mPhone.getHalVersion()); + + mPhone.getHalVersion(HAL_SERVICE_DATA)); mFailCause = DataFailCause.LOST_CONNECTION; transitionTo(mDisconnectedState); } diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index fd09f340cf..3e8473355e 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.emergency; +import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; + import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; @@ -205,7 +207,8 @@ public class EmergencyNumberTracker extends Handler { mPhone.getContext().registerReceiver(mIntentReceiver, filter); - mIsHalVersionLessThan1Dot4 = mPhone.getHalVersion().lessOrEqual(new HalVersion(1, 3)); + mIsHalVersionLessThan1Dot4 = mPhone.getHalVersion(HAL_SERVICE_VOICE) + .lessOrEqual(new HalVersion(1, 3)); } else { loge("mPhone is null."); } @@ -1323,7 +1326,7 @@ public class EmergencyNumberTracker extends Handler { */ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); - ipw.println(" Hal Version:" + mPhone.getHalVersion()); + ipw.println(" Hal Version:" + mPhone.getHalVersion(HAL_SERVICE_VOICE)); ipw.println(" ========================================= "); ipw.println(" Country Iso:" + getEmergencyCountryIso()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java index 311fe2043e..8054c203c0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java @@ -16,6 +16,11 @@ package com.android.internal.telephony; +import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; +import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; +import static android.telephony.TelephonyManager.HAL_SERVICE_RADIO; +import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; + import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ALLOW_DATA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE; @@ -183,8 +188,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Consumer; @@ -206,13 +213,13 @@ public class RILTest extends TelephonyTest { private RadioNetworkProxy mNetworkProxy; private RadioSimProxy mSimProxy; - private HalVersion mRadioVersionV10 = new HalVersion(1, 0); - private HalVersion mRadioVersionV11 = new HalVersion(1, 1); - private HalVersion mRadioVersionV12 = new HalVersion(1, 2); - private HalVersion mRadioVersionV13 = new HalVersion(1, 3); - private HalVersion mRadioVersionV14 = new HalVersion(1, 4); - private HalVersion mRadioVersionV15 = new HalVersion(1, 5); - private HalVersion mRadioVersionV16 = new HalVersion(1, 6); + private Map mHalVersionV10 = new HashMap<>(); + private Map mHalVersionV11 = new HashMap<>(); + private Map mHalVersionV12 = new HashMap<>(); + private Map mHalVersionV13 = new HashMap<>(); + private Map mHalVersionV14 = new HashMap<>(); + private Map mHalVersionV15 = new HashMap<>(); + private Map mHalVersionV16 = new HashMap<>(); private RIL mRILInstance; private RIL mRILUnderTest; @@ -316,10 +323,10 @@ public class RILTest extends TelephonyTest { doReturn(powerManager).when(context).getSystemService(Context.POWER_SERVICE); doReturn(new ApplicationInfo()).when(context).getApplicationInfo(); SparseArray proxies = new SparseArray<>(); - proxies.put(RIL.RADIO_SERVICE, null); - proxies.put(RIL.DATA_SERVICE, mDataProxy); - proxies.put(RIL.NETWORK_SERVICE, mNetworkProxy); - proxies.put(RIL.SIM_SERVICE, mSimProxy); + proxies.put(HAL_SERVICE_RADIO, null); + proxies.put(HAL_SERVICE_DATA, mDataProxy); + proxies.put(HAL_SERVICE_NETWORK, mNetworkProxy); + proxies.put(HAL_SERVICE_SIM, mSimProxy); mRILInstance = new RIL(context, RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE), Phone.PREFERRED_CDMA_SUBSCRIPTION, 0, proxies); @@ -335,7 +342,16 @@ public class RILTest extends TelephonyTest { doReturn(false).when(mNetworkProxy).isEmpty(); doReturn(false).when(mSimProxy).isEmpty(); try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV10); + for (int service = RIL.MIN_SERVICE_IDX; service <= RIL.MAX_SERVICE_IDX; service++) { + mHalVersionV10.put(service, new HalVersion(1, 0)); + mHalVersionV11.put(service, new HalVersion(1, 1)); + mHalVersionV12.put(service, new HalVersion(1, 2)); + mHalVersionV13.put(service, new HalVersion(1, 3)); + mHalVersionV14.put(service, new HalVersion(1, 4)); + mHalVersionV15.put(service, new HalVersion(1, 5)); + mHalVersionV16.put(service, new HalVersion(1, 6)); + } + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV10); } catch (Exception e) { } } @@ -493,7 +509,7 @@ public class RILTest extends TelephonyTest { // Make radio version 1.5 to support the operation. try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV15); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV15); } catch (Exception e) { } @@ -531,7 +547,7 @@ public class RILTest extends TelephonyTest { // Make radio version 1.5 to support the operation. try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV15); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV15); } catch (Exception e) { } @@ -711,7 +727,7 @@ public class RILTest extends TelephonyTest { public void testStartNetworkScanWithUnsupportedResponse() throws Exception { // Use Radio HAL v1.5 try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV15); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV15); } catch (Exception e) { } NetworkScanRequest nsr = getNetworkScanRequestForTesting(); @@ -738,7 +754,7 @@ public class RILTest extends TelephonyTest { public void testGetVoiceRegistrationStateWithUnsupportedResponse() throws Exception { // Use Radio HAL v1.5 try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV15); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV15); } catch (Exception e) { } mRILUnderTest.getVoiceRegistrationState(obtainMessage()); @@ -773,7 +789,7 @@ public class RILTest extends TelephonyTest { public void testGetDataRegistrationStateWithUnsupportedResponse() throws Exception { // Use Radio HAL v1.5 try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV15); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV15); } catch (Exception e) { } @@ -818,7 +834,7 @@ public class RILTest extends TelephonyTest { // Use Radio HAL v1.6 try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV16); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV16); } catch (Exception e) { } @@ -861,7 +877,7 @@ public class RILTest extends TelephonyTest { public void testSendSMS_1_6() throws Exception { // Use Radio HAL v1.6 try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV16); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV16); } catch (Exception e) { } String smscPdu = "smscPdu"; @@ -893,7 +909,7 @@ public class RILTest extends TelephonyTest { public void testSendSMSExpectMore_1_6() throws Exception { // Use Radio HAL v1.6 try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV16); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV16); } catch (Exception e) { } String smscPdu = "smscPdu"; @@ -912,7 +928,7 @@ public class RILTest extends TelephonyTest { public void testSendCdmaSMS_1_6() throws Exception { // Use Radio HAL v1.6 try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV16); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV16); } catch (Exception e) { } byte[] pdu = "000010020000000000000000000000000000000000".getBytes(); @@ -928,7 +944,7 @@ public class RILTest extends TelephonyTest { public void testSendCdmaSMSExpectMore_1_6() throws Exception { // Use Radio HAL v1.6 try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV16); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV16); } catch (Exception e) { } byte[] pdu = "000010020000000000000000000000000000000000".getBytes(); @@ -1475,7 +1491,7 @@ public class RILTest extends TelephonyTest { // Make radio version 1.5 to support the operation. try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV15); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV15); } catch (Exception e) { } mRILUnderTest.getBarringInfo(obtainMessage()); @@ -2838,7 +2854,7 @@ public class RILTest extends TelephonyTest { // Make radio version 1.5 to support the operation. try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV15); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV15); } catch (Exception e) { } mRILUnderTest.enableUiccApplications(false, obtainMessage()); @@ -2855,7 +2871,7 @@ public class RILTest extends TelephonyTest { // Make radio version 1.5 to support the operation. try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV15); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV15); } catch (Exception e) { } mRILUnderTest.areUiccApplicationsEnabled(obtainMessage()); @@ -2902,7 +2918,7 @@ public class RILTest extends TelephonyTest { public void testGetSlicingConfig() throws Exception { // Use Radio HAL v1.6 try { - replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV16); + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV16); } catch (Exception e) { } mRILUnderTest.getSlicingConfig(obtainMessage()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java index 50a1b96c16..8b4a2fa431 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java @@ -19,6 +19,7 @@ package com.android.internal.telephony; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR; +import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; import static com.google.common.truth.Truth.assertThat; @@ -741,7 +742,7 @@ public class SignalStrengthControllerTest extends TelephonyTest { } } // Only check on RADIO hal 1.5 and above to make it less flaky - if (mPhone.getHalVersion().greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { + if (mPhone.getHalVersion(HAL_SERVICE_NETWORK).greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { assertThat(expectedNonEmptyThreshold).isEqualTo(actualNonEmptyThreshold); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 125ac6374c..b0b72e41c9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -724,7 +724,7 @@ public abstract class TelephonyTest { doReturn(true).when(mDataSettingsManager).isDataEnabled(); doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo( anyInt(), anyInt()); - doReturn(RIL.RADIO_HAL_VERSION_2_0).when(mPhone).getHalVersion(); + doReturn(RIL.RADIO_HAL_VERSION_2_0).when(mPhone).getHalVersion(anyInt()); doReturn(2).when(mSignalStrength).getLevel(); // WiFi 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 77d3e85f4a..a967539175 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.data; +import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; + import static com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; import static com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; @@ -3839,7 +3841,7 @@ public class DataNetworkControllerTest extends TelephonyTest { }).when(mMockedWwanDataServiceManager).deactivateDataCall( anyInt(), anyInt(), any(Message.class)); // Simulate old devices - doReturn(RIL.RADIO_HAL_VERSION_1_6).when(mPhone).getHalVersion(); + doReturn(RIL.RADIO_HAL_VERSION_1_6).when(mPhone).getHalVersion(HAL_SERVICE_DATA); testSetupDataNetwork(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index 9cd11c85d9..6121127acc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.emergency; +import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -136,12 +138,12 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { doReturn(mContext).when(mPhone).getContext(); doReturn(0).when(mPhone).getPhoneId(); doReturn(SUB_ID_PHONE_1).when(mPhone).getSubId(); - doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(); + doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(HAL_SERVICE_VOICE); doReturn(mContext).when(mPhone2).getContext(); doReturn(1).when(mPhone2).getPhoneId(); doReturn(SUB_ID_PHONE_2).when(mPhone2).getSubId(); - doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(); + doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(HAL_SERVICE_VOICE); initializeEmergencyNumberListTestSamples(); mEmergencyNumberTrackerMock = new EmergencyNumberTracker(mPhone, mSimulatedCommands); @@ -394,8 +396,8 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { @Test public void testIsEmergencyNumber_FallbackToShortNumberXml_NoSims() throws Exception { // Set up the Hal version as 1.4 - doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(); - doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(); + doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(HAL_SERVICE_VOICE); + doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(HAL_SERVICE_VOICE); setDsdsPhones(); replaceInstance(SubscriptionController.class, "sInstance", null, mSubControllerMock); @@ -432,8 +434,8 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private void testIsEmergencyNumber_NoFallbackToShortNumberXml(int numSims) throws Exception { // Set up the Hal version as 1.4 - doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(); - doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(); + doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(HAL_SERVICE_VOICE); + doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(HAL_SERVICE_VOICE); assertTrue((numSims > 0 && numSims < 3)); setDsdsPhones(); @@ -506,7 +508,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { */ @Test public void testUsingEmergencyNumberDatabaseWheneverHal_1_3() { - doReturn(new HalVersion(1, 3)).when(mPhone).getHalVersion(); + doReturn(new HalVersion(1, 3)).when(mPhone).getHalVersion(HAL_SERVICE_VOICE); doReturn(mMockContext).when(mPhone).getContext(); doReturn(mResources).when(mMockContext).getResources(); doReturn(true).when(mResources).getBoolean( @@ -715,7 +717,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { @Test public void testOtaEmergencyNumberDatabase() { // Set up the Hal version as 1.4 to apply emergency number database - doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(); + doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(HAL_SERVICE_VOICE); sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock); mEmergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones(""); -- GitLab From 011b2b419db6987ae6c8144429c114193c53ea12 Mon Sep 17 00:00:00 2001 From: Binyi Wu Date: Tue, 15 Nov 2022 02:18:48 +0000 Subject: [PATCH 175/656] Revert "Add RIL interface for setNullCipherAndIntegrityEnabled" Revert submission 20283075-setNullCipherAndIntegrityEnabled Reason for revert: DroidMonitor: Potential culprit for Bug b/259163733 - verifying through ABTD before revert submission. This is part of the standard investigation process, and does not mean your CL will be reverted. Reverted Changes: Idad17af0a:Add setNullCipherAndIntegrityEnabled CTS to IRadio... Ia72f7bdd6:Add constants for setNullCipherAndIntegrityEnabled... I5ea99cb06:Add setNullCipherAndIntegrityEnabled to IRadioNetw... I53403d9f7:Add RIL interface for setNullCipherAndIntegrityEna... Change-Id: Ie9d339a660f21b0db3cce32fcce218ebb7264aff --- .../internal/telephony/CommandsInterface.java | 10 ------ .../internal/telephony/NetworkResponse.java | 8 ----- .../com/android/internal/telephony/Phone.java | 12 ------- .../com/android/internal/telephony/RIL.java | 36 ------------------- .../android/internal/telephony/RILUtils.java | 3 -- .../internal/telephony/RadioNetworkProxy.java | 16 --------- 6 files changed, 85 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index bfcda07304..2c6ff087ed 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2930,14 +2930,4 @@ public interface CommandsInterface { * @param bitsPerSecond The bit rate requested by the opponent UE. */ default void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond, Message result) {} - - /** - * Set the UE's ability to accept/reject null ciphered and/or null integrity-protected - * connections. - * - * @param result Callback message containing the success or failure status. - * @param enabled true to allow null ciphered and/or null integrity-protected connections, - * false to disallow. - */ - default void setNullCipherAndIntegrityEnabled(Message result, boolean enabled) {} } diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index 6d532b24f7..370335a70f 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -484,12 +484,4 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { public int getInterfaceVersion() { return IRadioNetworkResponse.VERSION; } - - /** - * @param responseInfo Response info struct containing response type, serial no. and error - */ - public void setNullCipherAndIntegrityEnabledResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(RIL.NETWORK_SERVICE, mRil, responseInfo); - } - } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index ec912d398f..e4502eac65 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -4966,18 +4966,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.unregisterForEmergencyNetworkScan(h); } - /** - * Set the UE's ability to accept/reject null ciphered and/or null integrity-protected - * connections. - * - * @param result Callback message. - * @param enabled true to allow null ciphered and/or null integrity-protected connections, - * false to disallow. - */ - public void setNullCipherAndIntegrityEnabled(@Nullable Message result, boolean enabled) { - mCi.setNullCipherAndIntegrityEnabled(result, enabled); - } - /** * @return Telephony tester instance. */ diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 539e969d1a..69fffe2f0d 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5442,42 +5442,6 @@ public class RIL extends BaseCommands implements CommandsInterface { } } - /** - * Set if null ciphering / null integrity modes are permitted. - * - * @param result Callback message containing the success or failure status. - * @param enabled true if null ciphering / null integrity modes are permitted, false otherwise - */ - @Override - public void setNullCipherAndIntegrityEnabled(Message result, boolean enabled) { - RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); - if (networkProxy.isEmpty()) return; - if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_2_1)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - networkProxy.setNullCipherAndIntegrityEnabled(rr.mSerial, enabled); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - NETWORK_SERVICE, "setNullCipherAndIntegrityEnabled", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setNullCipherAndIntegrityEnabled: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } - } - //***** Private Methods /** * This is a helper function to be called when an indication callback is called for any radio diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index d016db8f18..c05b669295 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -166,7 +166,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LOGICA import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_MUTE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_DATA_MODEM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_RADIO_CAPABILITY; @@ -5178,8 +5177,6 @@ public class RILUtils { return "SEND_ANBR_QUERY"; case RIL_REQUEST_TRIGGER_EPS_FALLBACK: return "TRIGGER_EPS_FALLBACK"; - case RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED: - return "SET_NULL_CIPHER_AND_INTEGRITY_ENABLED"; default: return ""; } diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java index c8855cd8b7..5e1cc60691 100644 --- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java +++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java @@ -916,20 +916,4 @@ public class RadioNetworkProxy extends RadioServiceProxy { } // Only supported on AIDL. } - - /** - * Set if null ciphering / null integrity is permitted. - * - * @param serial Serial number of the request. - * @param enabled true if null modes are allowed, false otherwise - * @throws RemoteException - */ - public void setNullCipherAndIntegrityEnabled(int serial, - boolean enabled) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mNetworkProxy.setNullCipherAndIntegrityEnabled(serial, enabled); - } - // Only supported on AIDL. - } } -- GitLab From 79f120e250b05b339241616b2f7224470202851c Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Mon, 14 Nov 2022 16:25:12 -0800 Subject: [PATCH 176/656] Update routing field type to enum in proto Change-Id: I73559c83ec912f1f8c16d7f7d8992428b3e9ba1e Bug: 238359415 Test: atest TeleServiceTests:EccDataTest#testEccDataContent Test: atest EmergencyNumberTrackerTest --- .../emergency/EmergencyNumberTracker.java | 15 +++++++++++++-- tests/telephonytests/assets/eccdata | Bin 96 -> 96 bytes tests/telephonytests/assets/eccdata_input.txt | 10 +++++----- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index fd09f340cf..d2ff50c338 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -478,14 +478,25 @@ public class EmergencyNumberTracker extends Handler { */ private int getRoutingInfoFromDB(EccInfo eccInfo, Map> normalRoutedNumbers) { - int emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY; + int emergencyCallRouting; + switch(eccInfo.routing) + { + case EccInfo.Routing.NORMAL : + emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL; + break; + case EccInfo.Routing.EMERGENCY : + emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY; + break; + default: + emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN; + } String phoneNumber = eccInfo.phoneNumber.trim(); if (phoneNumber.isEmpty()) { loge("EccInfo has empty phone number."); return emergencyCallRouting; } - if (eccInfo.isNormalRouted) { + if (eccInfo.routing == EccInfo.Routing.NORMAL) { emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL; if (((eccInfo.normalRoutingMncs).length != 0) diff --git a/tests/telephonytests/assets/eccdata b/tests/telephonytests/assets/eccdata index 9dcec54f3c0d25e008d89598cd6b32a6dbdb79d7..bd9ff47fb045b70816a28cbf29f838c515cbe388 100644 GIT binary patch delta 71 zcmV-N0J#5PU Date: Fri, 11 Nov 2022 13:50:58 +0000 Subject: [PATCH 177/656] QoS filtering based on Protocol ID Support QoS filter Protocol ID. Find proper callback listener based on protocol ID included in QoS filter from network. Bug: 246227644 Test: atest FrameworksTelephonyTests Change-Id: I11f1ac0c13ba6924a88ec1f5bda165caec1f5d8c --- .../telephony/data/QosCallbackTracker.java | 39 ++++++++- .../data/QosCallbackTrackerTest.java | 82 ++++++++++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java index b6c2038a4a..ac046277a9 100644 --- a/src/java/com/android/internal/telephony/data/QosCallbackTracker.java +++ b/src/java/com/android/internal/telephony/data/QosCallbackTracker.java @@ -80,12 +80,20 @@ public class QosCallbackTracker extends Handler { /** * Filter using the remote address. * - * @param address The local address. + * @param address The remote address. * @param startPort Starting port. * @param endPort Ending port. * @return {@code true} if matches, {@code false} otherwise. */ boolean matchesRemoteAddress(InetAddress address, int startPort, int endPort); + + /** + * Filter using the protocol + * + * @param protocol ID + * @return {@code true} if matches, {@code false} otherwise. + */ + boolean matchesProtocol(int protocol); } /** @@ -124,6 +132,11 @@ public class QosCallbackTracker extends Handler { return filter.matchesRemoteAddress(address, startPort, endPort); } + + @Override + public boolean matchesProtocol(int protocol) { + return filter.matchesProtocol(protocol); + } }); } @@ -332,6 +345,21 @@ public class QosCallbackTracker extends Handler { return result; } + private boolean matchesByProtocol(@NonNull QosBearerFilter sessionFilter, + final @NonNull IFilter filter, boolean hasMatchedFilter) { + boolean result = false; + int protocol = sessionFilter.getProtocol(); + if (protocol == QosBearerFilter.QOS_PROTOCOL_TCP + || protocol == QosBearerFilter.QOS_PROTOCOL_UDP) { + result = filter.matchesProtocol(protocol); + } else { + // FWK currently doesn't support filtering based on protocol ID ESP & AH. We will follow + // match results of other filters. + result = hasMatchedFilter; + } + return result; + } + private QosBearerFilter getFilterByPrecedence( @Nullable QosBearerFilter qosFilter, QosBearerFilter sessionFilter) { // Find for the highest precedence filter, lower the value is the higher the precedence @@ -362,6 +390,15 @@ public class QosCallbackTracker extends Handler { hasMatchedFilter = true; } } + + if (sessionFilter.getProtocol() != QosBearerFilter.QOS_PROTOCOL_UNSPECIFIED) { + if (!matchesByProtocol(sessionFilter, filter, hasMatchedFilter)) { + unMatched = true; + } else { + hasMatchedFilter = true; + } + } + if (!unMatched && hasMatchedFilter) { qosFilter = getFilterByPrecedence(qosFilter, sessionFilter); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java index 4c2ef80d14..d528d8588c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/QosCallbackTrackerTest.java @@ -61,6 +61,7 @@ public class QosCallbackTrackerTest extends TelephonyTest { class Filter implements QosCallbackTracker.IFilter { InetSocketAddress mLocalAddress; InetSocketAddress mRemoteAddress; + int mProtocol = QosBearerFilter.QOS_PROTOCOL_TCP; Filter(@NonNull final InetSocketAddress localAddress) { this.mLocalAddress = localAddress; @@ -87,6 +88,10 @@ public class QosCallbackTrackerTest extends TelephonyTest { && endPort >= mRemoteAddress.getPort() && (address.isAnyLocalAddress() || mRemoteAddress.getAddress().equals(address)); } + + public boolean matchesProtocol(int protocol) { + return mProtocol == protocol; + } } // Mocked classes @@ -151,6 +156,13 @@ public class QosCallbackTrackerTest extends TelephonyTest { private static QosBearerFilter createIpv4QosFilter(String localAddress, String remoteAddress, QosBearerFilter.PortRange localPort, QosBearerFilter.PortRange remotePort, int precedence) { + return createIpv4QosFilter(localAddress, remoteAddress, localPort, remotePort, + QosBearerFilter.QOS_PROTOCOL_TCP, precedence); + } + + private static QosBearerFilter createIpv4QosFilter(String localAddress, String remoteAddress, + QosBearerFilter.PortRange localPort, QosBearerFilter.PortRange remotePort, int protocol, + int precedence) { ArrayList localAddresses = new ArrayList<>(); if (localAddress != null) { localAddresses.add( @@ -163,7 +175,7 @@ public class QosCallbackTrackerTest extends TelephonyTest { } return new QosBearerFilter( localAddresses, remoteAddresses, localPort, remotePort, - QosBearerFilter.QOS_PROTOCOL_TCP, 7, 987, 678, + protocol, 7, 987, 678, QosBearerFilter.QOS_FILTER_DIRECTION_BIDIRECTIONAL, precedence); } @@ -541,6 +553,74 @@ public class QosCallbackTrackerTest extends TelephonyTest { verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); } + @Test + public void testQosSessionFilterProtocol() throws Exception { + // QosBearerFilter including protocol + ArrayList qosFilters1 = new ArrayList<>(); + qosFilters1.add(createIpv4QosFilter(null, null, null, + new QosBearerFilter.PortRange(3200, 3220), QosBearerFilter.QOS_PROTOCOL_UDP, 45)); + ArrayList qosSessions = new ArrayList<>(); + qosSessions.add(new QosBearerSession(1234, createEpsQos(5, 6, 7, 8), qosFilters1)); + + mQosCallbackTracker.updateSessions(qosSessions); + + // Add filter after updateSessions + Filter filter = new Filter(new InetSocketAddress( + InetAddresses.parseNumericAddress("122.22.22.22"), 1357), + new InetSocketAddress(InetAddresses.parseNumericAddress("177.77.77.77"), 3207)); + mQosCallbackTracker.addFilter(1, filter); + processAllMessages(); + verify(mINetworkAgentRegistry, never()).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + + // Remove the matching QosBearerFilter + qosSessions.remove(0); + mQosCallbackTracker.updateSessions(qosSessions); + processAllMessages(); + verify(mINetworkAgentRegistry, never()).sendQosSessionLost(eq(1), any(QosSession.class)); + + qosFilters1.clear(); + qosFilters1.add(createIpv4QosFilter(null, null, null, + new QosBearerFilter.PortRange(3200, 3220), QosBearerFilter.QOS_PROTOCOL_TCP, 45)); + qosSessions.clear(); + qosSessions.add(new QosBearerSession(1234, createEpsQos(5, 6, 7, 8), qosFilters1)); + mQosCallbackTracker.updateSessions(qosSessions); + processAllMessages(); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + qosSessions.remove(0); + mQosCallbackTracker.updateSessions(qosSessions); + processAllMessages(); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); + } + + @Test + public void testQosSessionFilterProtocolEsp() throws Exception { + // QosBearerFilter including protocol + ArrayList qosFilters1 = new ArrayList<>(); + qosFilters1.add(createIpv4QosFilter(null, null, null, + new QosBearerFilter.PortRange(3200, 3220), QosBearerFilter.QOS_PROTOCOL_ESP, 45)); + ArrayList qosSessions = new ArrayList<>(); + qosSessions.add(new QosBearerSession(1234, createEpsQos(5, 6, 7, 8), qosFilters1)); + + mQosCallbackTracker.updateSessions(qosSessions); + + // Add filter after updateSessions + Filter filter = new Filter(new InetSocketAddress( + InetAddresses.parseNumericAddress("122.22.22.22"), 1357), + new InetSocketAddress(InetAddresses.parseNumericAddress("177.77.77.77"), 3211)); + mQosCallbackTracker.addFilter(1, filter); + processAllMessages(); + verify(mINetworkAgentRegistry, times(1)).sendEpsQosSessionAvailable(eq(1), + any(QosSession.class), any(EpsBearerQosSessionAttributes.class)); + + // Remove the matching QosBearerFilter + qosSessions.remove(0); + mQosCallbackTracker.updateSessions(qosSessions); + processAllMessages(); + verify(mINetworkAgentRegistry, times(1)).sendQosSessionLost(eq(1), any(QosSession.class)); + } + @Test public void testQosMetrics() { final int callbackId = 1; -- GitLab From 7b9ba5bd0998e0b6d135072b762bc396b7d280f8 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 15 Nov 2022 23:18:56 +0000 Subject: [PATCH 178/656] Fix the version of IRadioIms HAL Bug: 243344927 Test: build Change-Id: I9e3d09b9e1790e54b48b818dce36df25c797ff2d --- src/java/com/android/internal/telephony/RadioImsProxy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/RadioImsProxy.java b/src/java/com/android/internal/telephony/RadioImsProxy.java index 439e350719..3ad1b946f2 100644 --- a/src/java/com/android/internal/telephony/RadioImsProxy.java +++ b/src/java/com/android/internal/telephony/RadioImsProxy.java @@ -44,7 +44,7 @@ public class RadioImsProxy extends RadioServiceProxy { int version = ims.getInterfaceVersion(); switch(version) { default: - newHalVersion = RIL.RADIO_HAL_VERSION_2_1; + newHalVersion = RIL.RADIO_HAL_VERSION_2_0; break; } Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); -- GitLab From 1165265afc245994fe48dd4d9bc9d1225f720348 Mon Sep 17 00:00:00 2001 From: Yomna Nasser Date: Tue, 15 Nov 2022 23:24:27 +0000 Subject: [PATCH 179/656] Revert "Revert "Add RIL interface for setNullCipherAndIntegrityEnabled"" This reverts commit 011b2b419db6987ae6c8144429c114193c53ea12. A few small fixes are included with this revert commit, namely switching to use HAL_SERVICE_NETWORK in NetworkResponse.java and RIL.java, and mHalVersion in RIL.java. Bug: b/237529943 Test: m Change-Id: If48c55cb4a13b39e0d30d4cdbd9a23b88cb0de45 --- .../internal/telephony/CommandsInterface.java | 10 ++++++ .../internal/telephony/NetworkResponse.java | 8 +++++ .../com/android/internal/telephony/Phone.java | 12 +++++++ .../com/android/internal/telephony/RIL.java | 36 +++++++++++++++++++ .../android/internal/telephony/RILUtils.java | 3 ++ .../internal/telephony/RadioNetworkProxy.java | 16 +++++++++ 6 files changed, 85 insertions(+) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index e2595c47ec..98de4be845 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2941,4 +2941,14 @@ public interface CommandsInterface { * @param bitsPerSecond The bit rate requested by the opponent UE. */ default void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond, Message result) {} + + /** + * Set the UE's ability to accept/reject null ciphered and/or null integrity-protected + * connections. + * + * @param result Callback message containing the success or failure status. + * @param enabled true to allow null ciphered and/or null integrity-protected connections, + * false to disallow. + */ + default void setNullCipherAndIntegrityEnabled(Message result, boolean enabled) {} } diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index 755cb75bb9..d9de8abc4f 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -486,4 +486,12 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { public int getInterfaceVersion() { return IRadioNetworkResponse.VERSION; } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void setNullCipherAndIntegrityEnabledResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); + } + } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 445af27190..3fee2af7d4 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -4983,6 +4983,18 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.unregisterForEmergencyNetworkScan(h); } + /** + * Set the UE's ability to accept/reject null ciphered and/or null integrity-protected + * connections. + * + * @param result Callback message. + * @param enabled true to allow null ciphered and/or null integrity-protected connections, + * false to disallow. + */ + public void setNullCipherAndIntegrityEnabled(@Nullable Message result, boolean enabled) { + mCi.setNullCipherAndIntegrityEnabled(result, enabled); + } + /** * @return Telephony tester instance. */ diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 36c680a28a..45dd06c14b 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5544,6 +5544,42 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * Set if null ciphering / null integrity modes are permitted. + * + * @param result Callback message containing the success or failure status. + * @param enabled true if null ciphering / null integrity modes are permitted, false otherwise + */ + @Override + public void setNullCipherAndIntegrityEnabled(Message result, boolean enabled) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); + if (networkProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + networkProxy.setNullCipherAndIntegrityEnabled(rr.mSerial, enabled); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR( + HAL_SERVICE_NETWORK, "setNullCipherAndIntegrityEnabled", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "setNullCipherAndIntegrityEnabled: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + //***** Private Methods /** * This is a helper function to be called when an indication callback is called for any radio diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index c05b669295..d016db8f18 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -166,6 +166,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LOGICA import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_MUTE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_DATA_MODEM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_RADIO_CAPABILITY; @@ -5177,6 +5178,8 @@ public class RILUtils { return "SEND_ANBR_QUERY"; case RIL_REQUEST_TRIGGER_EPS_FALLBACK: return "TRIGGER_EPS_FALLBACK"; + case RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED: + return "SET_NULL_CIPHER_AND_INTEGRITY_ENABLED"; default: return ""; } diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java index 5e1cc60691..c8855cd8b7 100644 --- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java +++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java @@ -916,4 +916,20 @@ public class RadioNetworkProxy extends RadioServiceProxy { } // Only supported on AIDL. } + + /** + * Set if null ciphering / null integrity is permitted. + * + * @param serial Serial number of the request. + * @param enabled true if null modes are allowed, false otherwise + * @throws RemoteException + */ + public void setNullCipherAndIntegrityEnabled(int serial, + boolean enabled) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.setNullCipherAndIntegrityEnabled(serial, enabled); + } + // Only supported on AIDL. + } } -- GitLab From bbb7c1bdf78559750f048c02d51996b883fa6488 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Mon, 14 Nov 2022 18:36:58 +0000 Subject: [PATCH 180/656] Add isN1ModeEnabled and setN1ModeEnabled to RadioNetworkProxy Bug: 255450196 Test: build Change-Id: I4cda580a8d36ed76ecbc7253743cbe9393564b5d --- .../internal/telephony/NetworkResponse.java | 22 ++++++++++++++ .../internal/telephony/RadioNetworkProxy.java | 29 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index d9de8abc4f..34e3766d36 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -477,6 +477,28 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } + /** + * @param responseInfo Response info struct containing response type, serial no. and error. + * @param isEnabled Indicates whether N1 mode is enabled or not. + */ + public void isN1ModeEnabledResponse(RadioResponseInfo responseInfo, boolean isEnabled) { + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); + + if (rr != null) { + if (responseInfo.error == RadioError.NONE) { + RadioResponse.sendMessageResponse(rr.mResult, isEnabled); + } + mRil.processResponseDone(rr, responseInfo, isEnabled); + } + } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error. + */ + public void setN1ModeEnabledResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); + } + @Override public String getInterfaceHash() { return IRadioNetworkResponse.HASH; diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java index c8855cd8b7..9e16edf408 100644 --- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java +++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java @@ -932,4 +932,33 @@ public class RadioNetworkProxy extends RadioServiceProxy { } // Only supported on AIDL. } + + /** + * Checks whether N1 mode is enabled. + * + * @param serial Serial number of the request. + * @throws RemoteException + */ + public void isN1ModeEnabled(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.isN1ModeEnabled(serial); + } + // Only supported on AIDL. + } + + /** + * Enables or disables N1 mode. + * + * @param serial Serial number of request. + * @param enable Indicates whether to enable N1 mode or not. + * @throws RemoteException + */ + public void setN1ModeEnabled(int serial, boolean enable) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.setN1ModeEnabled(serial, enable); + } + // Only supported on AIDL. + } } -- GitLab From 441f248c902ed902268a42ed6a4620eb30fe833f Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Tue, 4 Oct 2022 17:36:10 +0000 Subject: [PATCH 181/656] Replace callers of SmsApplication with user-aware methods. Bug: 250617029 Test: Sending and receiving SMS, atest FrameworkTelephonyTests, atest CtsTelephonyTestCases Change-Id: I6d360254db1b9b989b28138da74d05b2ad477e1c --- .../android/internal/telephony/InboundSmsHandler.java | 11 ++++++++--- .../com/android/internal/telephony/SMSDispatcher.java | 6 ++++-- .../android/internal/telephony/SmsPermissions.java | 6 +++++- .../android/internal/telephony/SmsStorageMonitor.java | 10 +++++++++- .../android/internal/telephony/WapPushOverSms.java | 11 +++++++++-- 5 files changed, 35 insertions(+), 9 deletions(-) mode change 100755 => 100644 src/java/com/android/internal/telephony/SmsStorageMonitor.java mode change 100755 => 100644 src/java/com/android/internal/telephony/WapPushOverSms.java diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java index a077b2c818..6daf9d90a0 100644 --- a/src/java/com/android/internal/telephony/InboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java @@ -1436,12 +1436,14 @@ public abstract class InboundSmsHandler extends StateMachine { intent.putExtra("messageId", messageId); } + UserHandle userHandle = null; if (destPort == -1) { intent.setAction(Intents.SMS_DELIVER_ACTION); // Direct the intent to only the default SMS app. If we can't find a default SMS app // then sent it to all broadcast receivers. - // We are deliberately delivering to the primary user's default SMS App. - ComponentName componentName = SmsApplication.getDefaultSmsApplication(mContext, true); + userHandle = TelephonyUtils.getSubscriptionUserHandle(mContext, subId); + ComponentName componentName = SmsApplication.getDefaultSmsApplicationAsUser(mContext, + true, userHandle); if (componentName != null) { // Deliver SMS message only to this receiver. intent.setComponent(componentName); @@ -1465,9 +1467,12 @@ public abstract class InboundSmsHandler extends StateMachine { intent.setComponent(null); } + if (userHandle == null) { + userHandle = UserHandle.SYSTEM; + } Bundle options = handleSmsWhitelisting(intent.getComponent(), isClass0); dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS, - AppOpsManager.OPSTR_RECEIVE_SMS, options, resultReceiver, UserHandle.SYSTEM, subId); + AppOpsManager.OPSTR_RECEIVE_SMS, options, resultReceiver, userHandle, subId); } /** diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 1a444ff990..40d779d252 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -86,6 +86,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.telephony.uicc.IccRecords; +import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -2401,9 +2402,10 @@ public abstract class SMSDispatcher extends Handler { /** Return if the SMS was originated from the default SMS application. */ public boolean isFromDefaultSmsApplication(Context context) { if (mIsFromDefaultSmsApplication == null) { + UserHandle userHandle = TelephonyUtils.getSubscriptionUserHandle(context, mSubId); // Perform a lazy initialization, due to the cost of the operation. - mIsFromDefaultSmsApplication = - SmsApplication.isDefaultSmsApplication(context, getAppPackageName()); + mIsFromDefaultSmsApplication = SmsApplication.isDefaultSmsApplicationAsUser(context, + getAppPackageName(), userHandle); } return mIsFromDefaultSmsApplication; } diff --git a/src/java/com/android/internal/telephony/SmsPermissions.java b/src/java/com/android/internal/telephony/SmsPermissions.java index 44751acf9d..e45cee3f7f 100644 --- a/src/java/com/android/internal/telephony/SmsPermissions.java +++ b/src/java/com/android/internal/telephony/SmsPermissions.java @@ -23,9 +23,11 @@ import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.Build; +import android.os.UserHandle; import android.service.carrier.CarrierMessagingService; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; /** @@ -163,7 +165,9 @@ public class SmsPermissions { @VisibleForTesting public boolean isCallerDefaultSmsPackage(String packageName) { if (packageNameMatchesCallingUid(packageName)) { - return SmsApplication.isDefaultSmsApplication(mContext, packageName); + UserHandle userHandle = TelephonyUtils.getSubscriptionUserHandle(mContext, + mPhone.getSubId()); + return SmsApplication.isDefaultSmsApplicationAsUser(mContext, packageName, userHandle); } return false; } diff --git a/src/java/com/android/internal/telephony/SmsStorageMonitor.java b/src/java/com/android/internal/telephony/SmsStorageMonitor.java old mode 100755 new mode 100644 index 2375c732ec..89e35450c3 --- a/src/java/com/android/internal/telephony/SmsStorageMonitor.java +++ b/src/java/com/android/internal/telephony/SmsStorageMonitor.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -26,10 +27,12 @@ import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.PowerManager; +import android.os.UserHandle; import android.provider.Telephony.Sms.Intents; import android.telephony.SubscriptionManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; /** @@ -223,9 +226,14 @@ public class SmsStorageMonitor extends Handler { * that SIM storage for SMS messages is full. */ private void handleIccFull() { + UserHandle userHandle = TelephonyUtils.getSubscriptionUserHandle(mContext, + mPhone.getSubId()); + ComponentName componentName = SmsApplication.getDefaultSimFullApplicationAsUser(mContext, + false, userHandle); + // broadcast SIM_FULL intent Intent intent = new Intent(Intents.SIM_FULL_ACTION); - intent.setComponent(SmsApplication.getDefaultSimFullApplication(mContext, false)); + intent.setComponent(componentName); mWakeLock.acquire(WAKE_LOCK_TIMEOUT); SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); mContext.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS); diff --git a/src/java/com/android/internal/telephony/WapPushOverSms.java b/src/java/com/android/internal/telephony/WapPushOverSms.java old mode 100755 new mode 100644 index d6f69e203e..bff95c645d --- a/src/java/com/android/internal/telephony/WapPushOverSms.java +++ b/src/java/com/android/internal/telephony/WapPushOverSms.java @@ -46,6 +46,7 @@ import android.telephony.SubscriptionManager; import android.text.TextUtils; import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; import com.google.android.mms.pdu.GenericPdu; @@ -391,7 +392,10 @@ public class WapPushOverSms implements ServiceConnection { // Direct the intent to only the default MMS app. If we can't find a default MMS app // then sent it to all broadcast receivers. - ComponentName componentName = SmsApplication.getDefaultMmsApplication(mContext, true); + UserHandle userHandle = TelephonyUtils.getSubscriptionUserHandle(mContext, subId); + ComponentName componentName = SmsApplication.getDefaultMmsApplicationAsUser(mContext, + true, userHandle); + Bundle options = null; if (componentName != null) { // Deliver MMS message only to this receiver @@ -409,9 +413,12 @@ public class WapPushOverSms implements ServiceConnection { options = bopts.toBundle(); } + if (userHandle == null) { + userHandle = UserHandle.SYSTEM; + } handler.dispatchIntent(intent, getPermissionForType(result.mimeType), getAppOpsStringPermissionForIntent(result.mimeType), options, receiver, - UserHandle.SYSTEM, subId); + userHandle, subId); return Activity.RESULT_OK; } -- GitLab From 024cbf122c298e11ea4c0185828391c40c0d99bd Mon Sep 17 00:00:00 2001 From: Hyunho Date: Sat, 12 Nov 2022 10:20:43 +0000 Subject: [PATCH 182/656] Add subIdChangedToInvalid API in ImsEnablementTracker When the ImsEnablementTracker is created, the state machine is created as the number of slots. Added an API to change the state of state machine related to the slotId whose the subId was changed to invalid to Default. Bug: b/257485774 Test: inserted TMO SIM > removed TMO SIM > inserted AT&T SIM > removed AT&T SIM > inserted TMO SIM Test: activate eSIM > inserted TMO SIM > inactivate eSIM > activate eSIM > removed TMO SIM > inserted TMO SIM Test: atest ImsEnablementTrackerTest Change-Id: I738de666907941edc8fda6a33ad783a6c52d6b93 --- .../telephony/ims/ImsEnablementTracker.java | 250 ++++++++--- .../telephony/ims/ImsServiceController.java | 14 +- .../ims/ImsEnablementTrackerTest.java | 406 ++++++++++-------- 3 files changed, 429 insertions(+), 241 deletions(-) diff --git a/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java b/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java index f7412a4f9c..732478de98 100644 --- a/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java +++ b/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.ims; +import android.content.ComponentName; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -23,11 +24,15 @@ import android.os.Message; import android.os.RemoteException; import android.telephony.ims.aidl.IImsServiceController; import android.util.Log; +import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import java.util.HashMap; +import java.util.Map; + /** * This class will abstract away all the new enablement logic and take the reset/enable/disable * IMS commands as inputs. @@ -58,6 +63,22 @@ public class ImsEnablementTracker { private static final int COMMAND_CONNECTED_MSG = 7; // The ImsServiceController binder is disconnected. private static final int COMMAND_DISCONNECTED_MSG = 8; + // The subId is changed to INVALID_SUBSCRIPTION_ID. + private static final int COMMAND_INVALID_SUBID_MSG = 9; + + private static final Map EVENT_DESCRIPTION = new HashMap<>(); + static { + EVENT_DESCRIPTION.put(COMMAND_NONE_MSG, "COMMAND_NONE_MSG"); + EVENT_DESCRIPTION.put(COMMAND_ENABLE_MSG, "COMMAND_ENABLE_MSG"); + EVENT_DESCRIPTION.put(COMMAND_DISABLE_MSG, "COMMAND_DISABLE_MSG"); + EVENT_DESCRIPTION.put(COMMAND_RESET_MSG, "COMMAND_RESET_MSG"); + EVENT_DESCRIPTION.put(COMMAND_ENABLING_DONE, "COMMAND_ENABLING_DONE"); + EVENT_DESCRIPTION.put(COMMAND_DISABLING_DONE, "COMMAND_DISABLING_DONE"); + EVENT_DESCRIPTION.put(COMMAND_RESETTING_DONE, "COMMAND_RESETTING_DONE"); + EVENT_DESCRIPTION.put(COMMAND_CONNECTED_MSG, "COMMAND_CONNECTED_MSG"); + EVENT_DESCRIPTION.put(COMMAND_DISCONNECTED_MSG, "COMMAND_DISCONNECTED_MSG"); + EVENT_DESCRIPTION.put(COMMAND_INVALID_SUBID_MSG, "COMMAND_INVALID_SUBID_MSG"); + } @VisibleForTesting protected static final int STATE_IMS_DISCONNECTED = 0; @@ -77,8 +98,11 @@ public class ImsEnablementTracker { protected final Object mLock = new Object(); private IImsServiceController mIImsServiceController; private long mLastImsOperationTimeMs = 0L; + private final ComponentName mComponentName; + private final SparseArray mStateMachines; - private final ImsEnablementTrackerStateMachine mEnablementStateMachine; + private final Looper mLooper; + private final int mState; /** * Provides Ims Enablement Tracker State Machine responsible for ims enable/disable command @@ -172,8 +196,11 @@ public class ImsEnablementTracker { @VisibleForTesting public int mSubId; - ImsEnablementTrackerStateMachine(String name, Looper looper, int state) { + private final int mPhoneId; + + ImsEnablementTrackerStateMachine(String name, Looper looper, int state, int slotId) { super(name, looper); + mPhoneId = slotId; mDefault = new Default(); mEnabled = new Enabled(); mDisabling = new Disabling(); @@ -216,17 +243,17 @@ public class ImsEnablementTracker { @VisibleForTesting public boolean isState(int state) { if (state == mDefault.mStateNo) { - return (mEnablementStateMachine.getCurrentState() == mDefault) ? true : false; + return (getCurrentState() == mDefault) ? true : false; } else if (state == mEnabled.mStateNo) { - return (mEnablementStateMachine.getCurrentState() == mEnabled) ? true : false; + return (getCurrentState() == mEnabled) ? true : false; } else if (state == mDisabling.mStateNo) { - return (mEnablementStateMachine.getCurrentState() == mDisabling) ? true : false; + return (getCurrentState() == mDisabling) ? true : false; } else if (state == mDisabled.mStateNo) { - return (mEnablementStateMachine.getCurrentState() == mDisabled) ? true : false; + return (getCurrentState() == mDisabled) ? true : false; } else if (state == mEnabling.mStateNo) { - return (mEnablementStateMachine.getCurrentState() == mEnabling) ? true : false; + return (getCurrentState() == mEnabling) ? true : false; } else if (state == mResetting.mStateNo) { - return (mEnablementStateMachine.getCurrentState() == mResetting) ? true : false; + return (getCurrentState() == mResetting) ? true : false; } return false; } @@ -264,8 +291,9 @@ public class ImsEnablementTracker { @Override public boolean processMessage(Message message) { - Log.d(LOG_TAG, "Default state:processMessage. msg.what=" + message.what); - switch(message.what) { + Log.d(LOG_TAG, "[" + mPhoneId + "]Default state:processMessage. msg.what=" + + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); + switch (message.what) { // When enableIms() is called, enableIms of binder is call and the state // change to the enabled state. case COMMAND_ENABLE_MSG: @@ -301,10 +329,11 @@ public class ImsEnablementTracker { @Override public boolean processMessage(Message message) { - Log.d(LOG_TAG, "Enabled state:processMessage. msg.what=" + message.what); + Log.d(LOG_TAG, "[" + mPhoneId + "]Enabled state:processMessage. msg.what=" + + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); mSlotId = message.arg1; mSubId = message.arg2; - switch(message.what) { + switch (message.what) { // the disableIms() is called. case COMMAND_DISABLE_MSG: transitionTo(mDisabling); @@ -316,6 +345,10 @@ public class ImsEnablementTracker { case COMMAND_DISCONNECTED_MSG: transitionTo(mDisconnected); return HANDLED; + case COMMAND_INVALID_SUBID_MSG: + clearAllMessage(); + transitionTo(mDefault); + return HANDLED; default: return NOT_HANDLED; } @@ -338,10 +371,11 @@ public class ImsEnablementTracker { @Override public boolean processMessage(Message message) { - Log.d(LOG_TAG, "Disabling state:processMessage. msg.what=" + message.what); + Log.d(LOG_TAG, "[" + mPhoneId + "]Disabling state:processMessage. msg.what=" + + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); mSlotId = message.arg1; mSubId = message.arg2; - switch(message.what) { + switch (message.what) { // In the enabled state, disableIms() is called, but the throttle timer has // not expired, so a delay_disable message is sent. // At this point enableIms() was called, so it cancels the message and just @@ -364,6 +398,10 @@ public class ImsEnablementTracker { case COMMAND_DISCONNECTED_MSG: transitionTo(mDisconnected); return HANDLED; + case COMMAND_INVALID_SUBID_MSG: + clearAllMessage(); + transitionTo(mDefault); + return HANDLED; default: return NOT_HANDLED; } @@ -384,16 +422,21 @@ public class ImsEnablementTracker { @Override public boolean processMessage(Message message) { - Log.d(LOG_TAG, "Disabled state:processMessage. msg.what=" + message.what); + Log.d(LOG_TAG, "[" + mPhoneId + "]Disabled state:processMessage. msg.what=" + + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); mSlotId = message.arg1; mSubId = message.arg2; - switch(message.what) { + switch (message.what) { case COMMAND_ENABLE_MSG: transitionTo(mEnabling); return HANDLED; case COMMAND_DISCONNECTED_MSG: transitionTo(mDisconnected); return HANDLED; + case COMMAND_INVALID_SUBID_MSG: + clearAllMessage(); + transitionTo(mDefault); + return HANDLED; default: return NOT_HANDLED; } @@ -415,10 +458,11 @@ public class ImsEnablementTracker { @Override public boolean processMessage(Message message) { - Log.d(LOG_TAG, "Enabling state:processMessage. msg.what=" + message.what); + Log.d(LOG_TAG, "[" + mPhoneId + "]Enabling state:processMessage. msg.what=" + + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); mSlotId = message.arg1; mSubId = message.arg2; - switch(message.what) { + switch (message.what) { case COMMAND_DISABLE_MSG: clearAllMessage(); transitionTo(mDisabled); @@ -427,12 +471,16 @@ public class ImsEnablementTracker { // If the enable command is received before enableIms is processed, // it will be ignored because the enable command processing is in progress. removeMessages(COMMAND_ENABLE_MSG); - sendEnableIms(mSlotId, mSubId); + sendEnableIms(message.arg1, message.arg2); transitionTo(mEnabled); return HANDLED; case COMMAND_DISCONNECTED_MSG: transitionTo(mDisconnected); return HANDLED; + case COMMAND_INVALID_SUBID_MSG: + clearAllMessage(); + transitionTo(mDefault); + return HANDLED; default: return NOT_HANDLED; } @@ -455,10 +503,11 @@ public class ImsEnablementTracker { @Override public boolean processMessage(Message message) { - Log.d(LOG_TAG, "Resetting state:processMessage. msg.what=" + message.what); + Log.d(LOG_TAG, "[" + mPhoneId + "]Resetting state:processMessage. msg.what=" + + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); mSlotId = message.arg1; mSubId = message.arg2; - switch(message.what) { + switch (message.what) { case COMMAND_DISABLE_MSG: clearAllMessage(); transitionTo(mDisabling); @@ -473,6 +522,10 @@ public class ImsEnablementTracker { case COMMAND_DISCONNECTED_MSG: transitionTo(mDisconnected); return HANDLED; + case COMMAND_INVALID_SUBID_MSG: + clearAllMessage(); + transitionTo(mDefault); + return HANDLED; default: return NOT_HANDLED; } @@ -496,8 +549,9 @@ public class ImsEnablementTracker { @Override public boolean processMessage(Message message) { - Log.d(LOG_TAG, "Disconnected state:processMessage. msg.what=" + message.what); - switch(message.what) { + Log.d(LOG_TAG, "[" + mPhoneId + "]Disconnected state:processMessage. msg.what=" + + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); + switch (message.what) { case COMMAND_CONNECTED_MSG: clearAllMessage(); transitionTo(mDefault); @@ -519,35 +573,70 @@ public class ImsEnablementTracker { } } - public ImsEnablementTracker(Looper looper) { + public ImsEnablementTracker(Looper looper, ComponentName componentName) { mIImsServiceController = null; - mEnablementStateMachine = new ImsEnablementTrackerStateMachine("ImsEnablementTracker", - looper, ImsEnablementTracker.STATE_IMS_DISCONNECTED); - mEnablementStateMachine.start(); + mStateMachines = new SparseArray<>(); + mLooper = looper; + mState = ImsEnablementTracker.STATE_IMS_DISCONNECTED; + mComponentName = componentName; } @VisibleForTesting - public ImsEnablementTracker(Looper looper, IImsServiceController controller, int state) { + public ImsEnablementTracker(Looper looper, IImsServiceController controller, int state, + int numSlots) { mIImsServiceController = controller; - mEnablementStateMachine = new ImsEnablementTrackerStateMachine("ImsEnablementTracker", - looper, state); + mStateMachines = new SparseArray<>(); + mLooper = looper; + mState = state; + mComponentName = null; + ImsEnablementTrackerStateMachine enablementStateMachine = null; + for (int i = 0; i < numSlots; i++) { + enablementStateMachine = new ImsEnablementTrackerStateMachine("ImsEnablementTracker", + mLooper, mState, i); + mStateMachines.put(i, enablementStateMachine); + } } /** - * This API is for testing purposes only and is used to start a state machine. + * Set the number of SIM slots. + * @param numOfSlots the number of SIM slots. */ - @VisibleForTesting - public void startStateMachineAsConnected() { - if (mEnablementStateMachine == null) { + public void setNumOfSlots(int numOfSlots) { + int oldNumSlots = mStateMachines.size(); + Log.d(LOG_TAG, "set the slots: old[" + oldNumSlots + "], new[" + numOfSlots + "]," + + "component:" + mComponentName); + if (numOfSlots == oldNumSlots) { return; } - mEnablementStateMachine.start(); - mEnablementStateMachine.sendMessage(COMMAND_CONNECTED_MSG); + ImsEnablementTrackerStateMachine enablementStateMachine = null; + if (oldNumSlots < numOfSlots) { + for (int i = oldNumSlots; i < numOfSlots; i++) { + enablementStateMachine = new ImsEnablementTrackerStateMachine( + "ImsEnablementTracker", mLooper, mState, i); + enablementStateMachine.start(); + mStateMachines.put(i, enablementStateMachine); + } + } else if (oldNumSlots > numOfSlots) { + for (int i = (oldNumSlots - 1); i > (numOfSlots - 1); i--) { + enablementStateMachine = mStateMachines.get(i); + mStateMachines.remove(i); + enablementStateMachine.quitNow(); + } + } + } + + /** + * This API is for testing purposes only and is used to start a state machine. + */ + @VisibleForTesting + public void startStateMachineAsConnected(int slotId) { + mStateMachines.get(slotId).start(); + mStateMachines.get(slotId).sendMessage(COMMAND_CONNECTED_MSG); } @VisibleForTesting - public Handler getHandler() { - return mEnablementStateMachine.getHandler(); + public Handler getHandler(int slotId) { + return mStateMachines.get(slotId).getHandler(); } /** @@ -556,8 +645,22 @@ public class ImsEnablementTracker { * @return true if the current state and input state are the same or false. */ @VisibleForTesting - public boolean isState(int state) { - return mEnablementStateMachine.isState(state); + public boolean isState(int slotId, int state) { + return mStateMachines.get(slotId).isState(state); + } + + /** + * Notify the state machine that the subId has changed to invalid. + * @param slotId subscription id + */ + public void subIdChangedToInvalid(int slotId) { + Log.d(LOG_TAG, "[" + slotId + "] subId changed to invalid, component:" + mComponentName); + ImsEnablementTrackerStateMachine stateMachine = mStateMachines.get(slotId); + if (stateMachine != null) { + stateMachine.sendMessage(COMMAND_INVALID_SUBID_MSG, slotId); + } else { + Log.w(LOG_TAG, "There is no state machine associated with this slotId."); + } } /** @@ -567,8 +670,13 @@ public class ImsEnablementTracker { * @param subId subscription id */ public void enableIms(int slotId, int subId) { - Log.d(LOG_TAG, "enableIms"); - mEnablementStateMachine.sendMessage(COMMAND_ENABLE_MSG, slotId, subId); + Log.d(LOG_TAG, "[" + slotId + "][" + subId + "]enableIms, component:" + mComponentName); + ImsEnablementTrackerStateMachine stateMachine = mStateMachines.get(slotId); + if (stateMachine != null) { + stateMachine.sendMessage(COMMAND_ENABLE_MSG, slotId, subId); + } else { + Log.w(LOG_TAG, "There is no state machine associated with this slotId."); + } } /** @@ -578,8 +686,13 @@ public class ImsEnablementTracker { * @param subId subscription id */ public void disableIms(int slotId, int subId) { - Log.d(LOG_TAG, "disableIms"); - mEnablementStateMachine.sendMessage(COMMAND_DISABLE_MSG, slotId, subId); + Log.d(LOG_TAG, "[" + slotId + "][" + subId + "]disableIms, component:" + mComponentName); + ImsEnablementTrackerStateMachine stateMachine = mStateMachines.get(slotId); + if (stateMachine != null) { + stateMachine.sendMessage(COMMAND_DISABLE_MSG, slotId, subId); + } else { + Log.w(LOG_TAG, "There is no state machine associated with this slotId."); + } } /** @@ -589,8 +702,13 @@ public class ImsEnablementTracker { * @param subId subscription id */ public void resetIms(int slotId, int subId) { - Log.d(LOG_TAG, "resetIms"); - mEnablementStateMachine.sendMessage(COMMAND_RESET_MSG, slotId, subId); + Log.d(LOG_TAG, "[" + slotId + "][" + subId + "]resetIms, component:" + mComponentName); + ImsEnablementTrackerStateMachine stateMachine = mStateMachines.get(slotId); + if (stateMachine != null) { + stateMachine.sendMessage(COMMAND_RESET_MSG, slotId, subId); + } else { + Log.w(LOG_TAG, "There is no state machine associated with this slotId."); + } } /** @@ -599,11 +717,21 @@ public class ImsEnablementTracker { protected void setServiceController(IBinder serviceController) { synchronized (mLock) { mIImsServiceController = IImsServiceController.Stub.asInterface(serviceController); - - if (isServiceControllerAvailable()) { - mEnablementStateMachine.serviceBinderConnected(); - } else { - mEnablementStateMachine.serviceBinderDisconnected(); + Log.d(LOG_TAG, "setServiceController with Binder:" + mIImsServiceController + + ", component:" + mComponentName); + ImsEnablementTrackerStateMachine stateMachine = null; + for (int i = 0; i < mStateMachines.size(); i++) { + stateMachine = mStateMachines.get(i); + if (stateMachine == null) { + Log.w(LOG_TAG, "There is no state machine associated with" + + "the slotId[" + i + "]"); + continue; + } + if (isServiceControllerAvailable()) { + stateMachine.serviceBinderConnected(); + } else { + stateMachine.serviceBinderDisconnected(); + } } } } @@ -628,27 +756,24 @@ public class ImsEnablementTracker { return remainTime; } - /** - * Send internal Message for testing. - */ - @VisibleForTesting - public void sendInternalMessage(int msg, int slotId, int subId) { - mEnablementStateMachine.sendMessage(msg, slotId, subId); - } - /** * Check to see if the service controller is available. * @return true if available, false otherwise */ private boolean isServiceControllerAvailable() { - return mIImsServiceController != null; + if (mIImsServiceController != null) { + return true; + } + Log.d(LOG_TAG, "isServiceControllerAvailable : binder is not alive"); + return false; } private void sendEnableIms(int slotId, int subId) { - Log.d(LOG_TAG, "sendEnableIms"); try { synchronized (mLock) { if (isServiceControllerAvailable()) { + Log.d(LOG_TAG, "[" + slotId + "][" + subId + "]sendEnableIms," + + "componentName[" + mComponentName + "]"); mIImsServiceController.enableIms(slotId, subId); mLastImsOperationTimeMs = System.currentTimeMillis(); } @@ -659,10 +784,11 @@ public class ImsEnablementTracker { } private void sendDisableIms(int slotId, int subId) { - Log.d(LOG_TAG, "sendDisableIms"); try { synchronized (mLock) { if (isServiceControllerAvailable()) { + Log.d(LOG_TAG, "[" + slotId + "][" + subId + "]sendDisableIms," + + "componentName[" + mComponentName + "]"); mIImsServiceController.disableIms(slotId, subId); mLastImsOperationTimeMs = System.currentTimeMillis(); } diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceController.java b/src/java/com/android/internal/telephony/ims/ImsServiceController.java index 72cf472f8f..357215884c 100644 --- a/src/java/com/android/internal/telephony/ims/ImsServiceController.java +++ b/src/java/com/android/internal/telephony/ims/ImsServiceController.java @@ -333,7 +333,7 @@ public class ImsServiceController { mPermissionManager = (LegacyPermissionManager) mContext.getSystemService( Context.LEGACY_PERMISSION_SERVICE); mRepo = repo; - mImsEnablementTracker = new ImsEnablementTracker(mHandlerThread.getLooper()); + mImsEnablementTracker = new ImsEnablementTracker(mHandlerThread.getLooper(), componentName); mPackageManager = mContext.getPackageManager(); if (mPackageManager != null) { mChangedPackages = mPackageManager.getChangedPackages(mLastSequenceNumber); @@ -360,7 +360,7 @@ public class ImsServiceController { mRestartImsServiceRunnable); mPermissionManager = null; mRepo = repo; - mImsEnablementTracker = new ImsEnablementTracker(handler.getLooper()); + mImsEnablementTracker = new ImsEnablementTracker(handler.getLooper(), componentName); } /** @@ -380,6 +380,8 @@ public class ImsServiceController { sanitizeFeatureConfig(imsFeatureSet); mImsFeatures = imsFeatureSet; mSlotIdToSubIdMap = slotIdToSubIdMap; + // Set the number of slots that support the feature + mImsEnablementTracker.setNumOfSlots(mSlotIdToSubIdMap.size()); grantPermissionsToService(); Intent imsServiceIntent = new Intent(getServiceInterface()).setComponent( mComponentName); @@ -466,6 +468,14 @@ public class ImsServiceController { + newSubId); Log.i(LOG_TAG, "subId changed for slot: " + slotID + ", " + oldSubId + " -> " + newSubId); + if (newSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + /* An INVALID subId can also be set in bind(), however + the ImsEnablementTracker will move into the DEFAULT state, so we only + need to track changes in subId that result in requiring we move + the state machine back to DEFAULT. + */ + mImsEnablementTracker.subIdChangedToInvalid(slotID); + } } } mSlotIdToSubIdMap = slotIdToSubIdMap; diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java index 7c45f24850..b3b9052281 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java @@ -45,22 +45,24 @@ import org.mockito.Mock; @RunWith(AndroidJUnit4.class) public class ImsEnablementTrackerTest extends ImsTestBase { - private static final int SLOT_1 = 1; + private static final int SLOT_1 = 0; private static final int SUB_1 = 11; + private static final int SLOT_2 = 1; + private static final int SUB_2 = 22; private static final long TEST_REQUEST_THROTTLE_TIME_MS = 1000L; // Mocked classes @Mock IImsServiceController mMockServiceControllerBinder; - private TestableImsEnablementTracker mImsEnablementTracker; + private TestableImsEnablementTracker mTracker; private Handler mHandler; - private static class TestableImsEnablementTracker extends ImsEnablementTracker { private long mLastImsOperationTimeMs = 0L; - TestableImsEnablementTracker(Looper looper, IImsServiceController controller, int state) { - super(looper, controller, state); + TestableImsEnablementTracker(Looper looper, IImsServiceController controller, int state, + int numSlots) { + super(looper, controller, state, numSlots); } @Override @@ -84,7 +86,7 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void tearDown() throws Exception { // Make sure the handler is empty before finishing the test. waitForHandlerAction(mHandler, TEST_REQUEST_THROTTLE_TIME_MS); - mImsEnablementTracker = null; + mTracker = null; super.tearDown(); } @@ -93,17 +95,16 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandInDefaultState() throws RemoteException { // Verify that when the enable command is received in the Default state and enableIms // is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DEFAULT); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @@ -111,52 +112,49 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInDefaultState() throws RemoteException { // Verify that when the disable command is received in the Default state and disableIms // is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DEFAULT); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @SmallTest @Test public void testResetCommandInDefaultState() throws RemoteException { // Verify that when reset command is received in the Default state, it should be ignored. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DEFAULT); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + mTracker.resetIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verifyZeroInteractions(mMockServiceControllerBinder); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DEFAULT)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DEFAULT)); } @SmallTest @Test public void testEnableCommandInEnabledState() throws RemoteException { // Verify that received the enable command is not handle in the Enabled state, - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_ENABLED); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), - mImsEnablementTracker.getRemainThrottleTime() + 100); + mTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + 100); verify(mMockServiceControllerBinder, never()).enableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @@ -164,17 +162,16 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInEnabledState() throws RemoteException { // Verify that when the disable command is received in the Enabled state and disableIms // is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_ENABLED); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @SmallTest @@ -182,39 +179,37 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testResetCommandInEnabledState() throws RemoteException { // Verify that when the reset command is received in the Enabled state and disableIms // and enableIms are called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_ENABLED); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + mTracker.resetIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); // The disableIms was called. So set the last operation time to current. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); waitForHandlerActionDelayed(mHandler, TEST_REQUEST_THROTTLE_TIME_MS, TEST_REQUEST_THROTTLE_TIME_MS + 100); verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @Test public void testDisableCommandInDisabledState() throws RemoteException { // Verify that when disable command is received in the Disabled state, it should be ignored. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DISABLED); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verifyZeroInteractions(mMockServiceControllerBinder); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @SmallTest @@ -222,17 +217,16 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandInDisabledState() throws RemoteException { // Verify that when the enable command is received in the Disabled state and enableIms // is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DISABLED); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @@ -240,56 +234,54 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandWithoutTimeoutInDisableState() throws RemoteException { // Verify that when the enable command is received in the Disabled state. After throttle // time expired, the enableIms is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DISABLED); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); + // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), - mImsEnablementTracker.getRemainThrottleTime() + 100); + mTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + 100); verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @Test public void testResetCommandInDisabledState() throws RemoteException { // Verify that the reset command is received in the Disabled state and it`s not handled. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DISABLED); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + mTracker.resetIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verifyZeroInteractions(mMockServiceControllerBinder); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @SmallTest @Test public void testEnableCommandInDisablingState() throws RemoteException { // Verify that when enable command is received in the Disabling state, it should be ignored. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DISABLING); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLING); + mHandler = mTracker.getHandler(SLOT_1); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.startStateMachineAsConnected(); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verifyZeroInteractions(mMockServiceControllerBinder); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @@ -297,17 +289,16 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisablingMessageInDisablingState() throws RemoteException { // Verify that when the internal disable message is received in the Disabling state and // disableIms is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DISABLING); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLING); + mHandler = mTracker.getHandler(SLOT_1); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.startStateMachineAsConnected(); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.startStateMachineAsConnected(SLOT_1); - waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), - mImsEnablementTracker.getRemainThrottleTime() + 100); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + 100); verify(mMockServiceControllerBinder).disableIms(anyInt(), anyInt()); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @SmallTest @@ -315,25 +306,24 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testResetCommandInDisablingState() throws RemoteException { // Verify when the reset command is received in the Disabling state the disableIms and // enableIms are called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DISABLING); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLING); + mHandler = mTracker.getHandler(SLOT_1); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.startStateMachineAsConnected(); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.resetIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), - mImsEnablementTracker.getRemainThrottleTime() + 100); + mTracker.resetIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + 100); verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); // The disableIms was called. So set the last operation time to current. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), - mImsEnablementTracker.getRemainThrottleTime() + 100); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + 100); verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @@ -341,14 +331,13 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnablingMessageInEnablingState() throws RemoteException { // Verify that when the internal enable message is received in the Enabling state and // enableIms is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_ENABLING); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLING); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); waitForHandlerActionDelayed(mHandler, 100, 150); verify(mMockServiceControllerBinder).enableIms(anyInt(), anyInt()); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @@ -356,38 +345,36 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInEnablingState() throws RemoteException { // Verify that when the disable command is received in the Enabling state and // clear pending message and disableIms is not called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_ENABLING); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLING); + mHandler = mTracker.getHandler(SLOT_1); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.startStateMachineAsConnected(); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @SmallTest @Test public void testResetCommandWithEnablingState() throws RemoteException { // Verify that when reset command is received in the Enabling state, it should be ignored. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_ENABLING); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLING); + mHandler = mTracker.getHandler(SLOT_1); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.startStateMachineAsConnected(); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + mTracker.resetIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verifyZeroInteractions(mMockServiceControllerBinder); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLING)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLING)); } @SmallTest @@ -395,19 +382,18 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandInResettingState() throws RemoteException { // Verify that when the enable command is received in the Resetting state and // enableIms is not called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_RESETTING); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING); + mHandler = mTracker.getHandler(SLOT_1); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.startStateMachineAsConnected(); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); verifyZeroInteractions(mMockServiceControllerBinder); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_RESETTING)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_RESETTING)); } @SmallTest @@ -415,20 +401,19 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInResettingState() throws RemoteException { // Verify that when the disable command is received in the Resetting state and // disableIms is called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_RESETTING); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING); + mHandler = mTracker.getHandler(SLOT_1); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.startStateMachineAsConnected(); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), - mImsEnablementTracker.getRemainThrottleTime() + 100); + mTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + 100); verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @SmallTest @@ -436,94 +421,161 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testResettingMessageInResettingState() throws RemoteException { // Verify that when the internal reset message is received in the Resetting state and // disableIms and enableIms are called. - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_RESETTING); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); verify(mMockServiceControllerBinder).disableIms(anyInt(), anyInt()); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), - mImsEnablementTracker.getRemainThrottleTime() + 100); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + 100); verify(mMockServiceControllerBinder).enableIms(anyInt(), anyInt()); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @Test public void testConsecutiveCommandInEnabledState() throws RemoteException { - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_ENABLED); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); - mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.disableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLING)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLING)); - mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); - mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLING)); - mImsEnablementTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), - mImsEnablementTracker.getRemainThrottleTime() + 100); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLING)); + mTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + 100); verify(mMockServiceControllerBinder, times(1)).disableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @SmallTest @Test public void testConsecutiveCommandInDisabledState() throws RemoteException { - mImsEnablementTracker = createTracker(mMockServiceControllerBinder, - mImsEnablementTracker.STATE_IMS_DISABLED); - mImsEnablementTracker.startStateMachineAsConnected(); - mHandler = mImsEnablementTracker.getHandler(); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. waitForHandlerActionDelayed(mHandler, 100, 150); // Set the last operation time to current to verify the message with delay. - mImsEnablementTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mImsEnablementTracker.enableIms(SLOT_1, SUB_1); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.enableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLING)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLING)); - mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); - mImsEnablementTracker.resetIms(SLOT_1, SUB_1); + mTracker.resetIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); - mImsEnablementTracker.disableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, 100, 150); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); - mImsEnablementTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, mImsEnablementTracker.getRemainThrottleTime(), - mImsEnablementTracker.getRemainThrottleTime() + 100); + mTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + 100); verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mImsEnablementTracker.isState(mImsEnablementTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testSubIdChangeToInvalidAndEnableCommand() throws RemoteException { + // Verify that when the enable command is received in the Default state and enableIms + // is called. + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mTracker.subIdChangedToInvalid(SLOT_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DEFAULT)); + + mTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testEnableCommandWithDifferentSlotId() throws RemoteException { + // Verify that when the enable command is received in the Default state and enableIms + // is called. + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT, 2); + mTracker.startStateMachineAsConnected(SLOT_1); + mHandler = mTracker.getHandler(SLOT_1); + mTracker.startStateMachineAsConnected(SLOT_2); + Handler handlerForSlot2 = mTracker.getHandler(SLOT_2); + // Wait for a while for the state machine to be ready. + waitForHandlerActionDelayed(mHandler, 100, 150); + + mTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, 100, 150); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_2, mTracker.STATE_IMS_DEFAULT)); + + mTracker.enableIms(SLOT_2, SUB_2); + waitForHandlerActionDelayed(handlerForSlot2, 100, 150); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_2), eq(SUB_2)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); + assertTrue(mTracker.isState(SLOT_2, mTracker.STATE_IMS_ENABLED)); + + mTracker.setNumOfSlots(1); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + 100); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); + + mTracker.setNumOfSlots(2); + mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + mTracker.disableIms(SLOT_2, SUB_2); + waitForHandlerActionDelayed(handlerForSlot2, 100, 150); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_2), eq(SUB_2)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); + assertTrue(mTracker.isState(SLOT_2, mTracker.STATE_IMS_DISABLED)); } private TestableImsEnablementTracker createTracker(IImsServiceController binder, int state) { TestableImsEnablementTracker tracker = new TestableImsEnablementTracker( - Looper.getMainLooper(), binder, state); + Looper.getMainLooper(), binder, state, 1); + return tracker; + } + + private TestableImsEnablementTracker createTracker(IImsServiceController binder, int state, + int numSlots) { + TestableImsEnablementTracker tracker = new TestableImsEnablementTracker( + Looper.getMainLooper(), binder, state, numSlots); return tracker; } } -- GitLab From 16bc55ef04875b08e1d754ba975a20f98269bb46 Mon Sep 17 00:00:00 2001 From: sandeepjs Date: Wed, 9 Nov 2022 15:23:42 +0000 Subject: [PATCH 183/656] Updating Unit Test for EuiccContollers methods Updating Unit test cases to verify the behaviour of getResolvedPortIndexForDisableSubscription and getResolvedPortIndexForSubscriptionSwitch Test: atest EuiccControllerTest Bug: 199559633 Change-Id: I3b0f513b39fce7be188f2232e14a2841c560bbed --- .../telephony/euicc/EuiccController.java | 6 +- .../telephony/euicc/EuiccControllerTest.java | 90 ++++++++++++++++++- 2 files changed, 93 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java index 28039b71d7..f109cde7b4 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccController.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java @@ -1147,7 +1147,8 @@ public class EuiccController extends IEuiccController.Stub { * Returns the resolved portIndex or {@link TelephonyManager#INVALID_PORT_INDEX} if calling * cannot manage any active subscription. */ - private int getResolvedPortIndexForDisableSubscription(int cardId, String callingPackage, + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public int getResolvedPortIndexForDisableSubscription(int cardId, String callingPackage, boolean callerCanWriteEmbeddedSubscriptions) { List subInfoList = mSubscriptionManager .getActiveSubscriptionInfoList(/* userVisibleOnly */false); @@ -1175,7 +1176,8 @@ public class EuiccController extends IEuiccController.Stub { * Returns the resolved portIndex or {@link TelephonyManager#INVALID_PORT_INDEX} if no port * is available without user consent. */ - private int getResolvedPortIndexForSubscriptionSwitch(int cardId) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + public int getResolvedPortIndexForSubscriptionSwitch(int cardId) { int slotIndex = getSlotIndexFromCardId(cardId); // Euicc Slot UiccSlot slot = UiccController.getInstance().getUiccSlot(slotIndex); 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 f960aff9d3..600c94a6d3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java @@ -128,7 +128,6 @@ public class EuiccControllerTest extends TelephonyTest { private static final int SUBSCRIPTION_ID = 12345; private static final String ICC_ID = "54321"; private static final int CARD_ID = 25; - private static final int PORT_INDEX = 0; // Mocked classes private EuiccConnector mMockConnector; @@ -786,6 +785,70 @@ public class EuiccControllerTest extends TelephonyTest { assertTrue(mController.mCalledRefreshSubscriptionsAndSendResult); } + @Test + public void testGetResolvedPortIndexForSubscriptionSwitchWithOutMEP() throws Exception { + setUpUiccSlotData(); + assertEquals(TelephonyManager.DEFAULT_PORT_INDEX, + mController.getResolvedPortIndexForSubscriptionSwitch(CARD_ID)); + } + + @Test + public void testGetResolvedPortIndexForSubscriptionSwitchWithMEP() throws Exception { + setUpUiccSlotDataWithMEP(); + when(mUiccSlot.getPortList()).thenReturn(new int[]{0, 1}); + when(mUiccSlot.isPortActive(TelephonyManager.DEFAULT_PORT_INDEX)).thenReturn(false); + when(mUiccSlot.isPortActive(1)).thenReturn(true); + when(mTelephonyManager.getActiveModemCount()).thenReturn(2); + assertEquals(1, mController.getResolvedPortIndexForSubscriptionSwitch(CARD_ID)); + } + + @Test + public void testGetResolvedPortIndexForSubscriptionSwitchWithUiccSlotNull() throws Exception { + assertEquals(TelephonyManager.DEFAULT_PORT_INDEX, + mController.getResolvedPortIndexForSubscriptionSwitch(CARD_ID)); + } + + @Test + public void testGetResolvedPortIndexForSubscriptionSwitchWithPsimActiveAndSS() + throws Exception { + when(mUiccController.getUiccSlot(anyInt())).thenReturn(mUiccSlot); + when(mUiccSlot.isRemovable()).thenReturn(true); + when(mUiccSlot.isEuicc()).thenReturn(false); + when(mUiccSlot.isActive()).thenReturn(true); + when(mTelephonyManager.getActiveModemCount()).thenReturn(1); + assertEquals(TelephonyManager.DEFAULT_PORT_INDEX, + mController.getResolvedPortIndexForSubscriptionSwitch(CARD_ID)); + } + + @Test + public void testGetResolvedPortIndexForSubscriptionSwitchWithPsimInActiveAndSS() + throws Exception { + setUpUiccSlotDataWithMEP(); + when(mUiccSlot.getPortList()).thenReturn(new int[]{0}); + when(mUiccSlot.isPortActive(TelephonyManager.DEFAULT_PORT_INDEX)).thenReturn(true); + when(mTelephonyManager.getActiveModemCount()).thenReturn(1); + assertEquals(TelephonyManager.DEFAULT_PORT_INDEX, + mController.getResolvedPortIndexForSubscriptionSwitch(CARD_ID)); + } + + @Test + public void testgetResolvedPortIndexForDisableSubscriptionForNoActiveSubscription() + throws Exception { + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(null); + assertEquals(-1, + mController.getResolvedPortIndexForDisableSubscription( + CARD_ID, PACKAGE_NAME, true)); + } + + @Test + public void testgetResolvedPortIndexForDisableSubscriptionForActiveSubscriptions() + throws Exception { + setActiveSubscriptionInfoInMEPMode(); + assertEquals(1, + mController.getResolvedPortIndexForDisableSubscription( + CARD_ID, PACKAGE_NAME, false)); + } + @Test public void testDeleteSubscription_noPrivileges() throws Exception { setHasWriteEmbeddedPermission(false); @@ -1233,6 +1296,11 @@ public class EuiccControllerTest extends TelephonyTest { when(mUiccSlot.isMultipleEnabledProfileSupported()).thenReturn(false); } + private void setUpUiccSlotDataWithMEP() { + when(mUiccController.getUiccSlot(anyInt())).thenReturn(mUiccSlot); + when(mUiccSlot.isMultipleEnabledProfileSupported()).thenReturn(true); + } + private void setGetEidPermissions( boolean hasPhoneStatePrivileged, boolean hasCarrierPrivileges) throws Exception { doReturn(hasPhoneStatePrivileged @@ -1314,6 +1382,26 @@ public class EuiccControllerTest extends TelephonyTest { when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(subInfos); } + private void setActiveSubscriptionInfoInMEPMode() + throws Exception { + SubscriptionInfo subInfo1 = new SubscriptionInfo.Builder() + .setEmbedded(true) + .setCardId(CARD_ID) + .setPortIndex(TelephonyManager.DEFAULT_PORT_INDEX) + .build(); + SubscriptionInfo subInfo2 = new SubscriptionInfo.Builder() + .setEmbedded(true) + .setCardId(CARD_ID) + .setPortIndex(1) + .build(); + when(mSubscriptionManager.canManageSubscription(subInfo1, PACKAGE_NAME)).thenReturn( + false); + when(mSubscriptionManager.canManageSubscription(subInfo2, PACKAGE_NAME)).thenReturn( + true); + ArrayList subInfos = new ArrayList<>(Arrays.asList(subInfo1, subInfo2)); + when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(subInfos); + } + private void prepareOperationSubscription(boolean hasPrivileges) throws Exception { SubscriptionInfo subInfo = new SubscriptionInfo.Builder() .setId(SUBSCRIPTION_ID) -- GitLab From 10a7ce1ddf2cb1c3ff856cef5b6f805285072327 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 17 Nov 2022 13:28:08 +0000 Subject: [PATCH 184/656] Fix the version of IRadioIms HAL Bug: 243344927 Test: atest CtsTelephonyTestCases:MmTelFeatureTestOnMockModem Change-Id: I263d02ba60908fe5dcface03d5af7d56f48ae3a2 --- src/java/com/android/internal/telephony/RIL.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 45dd06c14b..0fb6612626 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5225,7 +5225,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void setSrvccCallInfo(SrvccConnection[] srvccConnections, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RILRequest rr = obtainRequest(RIL_REQUEST_SET_SRVCC_CALL_INFO, result, mRILDefaultWorkSource); @@ -5257,7 +5257,7 @@ public class RIL extends BaseCommands implements CommandsInterface { int accessNetworkType, int suggestedAction, int capabilities, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO, result, mRILDefaultWorkSource); @@ -5294,7 +5294,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void startImsTraffic(int token, int trafficType, int accessNetworkType, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RILRequest rr = obtainRequest(RIL_REQUEST_START_IMS_TRAFFIC, result, mRILDefaultWorkSource); @@ -5324,7 +5324,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void stopImsTraffic(int token, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RILRequest rr = obtainRequest(RIL_REQUEST_STOP_IMS_TRAFFIC, result, mRILDefaultWorkSource); @@ -5353,7 +5353,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void triggerEpsFallback(int reason, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RILRequest rr = obtainRequest(RIL_REQUEST_TRIGGER_EPS_FALLBACK, result, mRILDefaultWorkSource); @@ -5384,7 +5384,7 @@ public class RIL extends BaseCommands implements CommandsInterface { Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RILRequest rr = obtainRequest(RIL_REQUEST_SEND_ANBR_QUERY, result, mRILDefaultWorkSource); -- GitLab From dcfd911305431163db31c0ed7971a67b7981696a Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 17 Nov 2022 13:36:34 +0000 Subject: [PATCH 185/656] Fix HAL service from IMS to NETWORK Change following ag/19940048 Bug: 243072871 Bug: 243344927 Test: atest RILTest Change-Id: I13d91b617025d6f36c4648ccab4be4e0366781fd --- src/java/com/android/internal/telephony/RIL.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 45dd06c14b..ab60c64e4b 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5416,7 +5416,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void setEmergencyMode(int emcMode, Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_SET_EMERGENCY_MODE, result, mRILDefaultWorkSource); @@ -5451,7 +5451,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @DomainSelectionService.EmergencyScanType int scanType, Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN, result, mRILDefaultWorkSource); @@ -5485,7 +5485,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void cancelEmergencyNetworkScan(boolean resetScan, Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_CANCEL_EMERGENCY_NETWORK_SCAN, result, mRILDefaultWorkSource); @@ -5519,7 +5519,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void exitEmergencyMode(Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_EXIT_EMERGENCY_MODE, result, mRILDefaultWorkSource); -- GitLab From cd747e564629943ac3371ae9d91e6bb28514c5db Mon Sep 17 00:00:00 2001 From: Pranav Madapurmath Date: Wed, 16 Nov 2022 19:33:29 +0000 Subject: [PATCH 186/656] Add work profile support for registering phone accounts with Telecom When registering a phone account for a user not associated with the phone process, we want to grab the user associated with the phone subscription. Currently, we enable MULTI_USER_CAPABILITY for all phone accounts; we should disable this when registering another user. We will also need the INTERACT_ACROSS_USERS permission to perform actions across users (other than the primary). Bug: 255342474 Test: PhoneUtilsTest.java Change-Id: I5ed05d770846b6e216628d9ce9bcfe90f540e5c8 --- src/java/com/android/internal/telephony/Phone.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 3fee2af7d4..0e237ea9fd 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -37,6 +37,7 @@ import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.UserHandle; import android.os.WorkSource; import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; @@ -5010,6 +5011,17 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return mIsSubscriptionManagerServiceEnabled; } + /** + * @return UserHandle from phone sub id, or null if subscription is invalid. + */ + public UserHandle getUserHandle() { + SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class); + int subId = getSubId(); + return subManager.isValidSubscriptionId(subId) + ? subManager.getSubscriptionUserHandle(subId) + : null; + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); -- GitLab From d7beaac35b726914cb1f6e0d3957cf1882de3dda Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 17 Nov 2022 09:43:32 -0800 Subject: [PATCH 187/656] Remove LTE_CA HAL usages Update IRadio imports to use V2 Test: build Bug: 240997187 Change-Id: I5d329bcd0d33e98d77cd7eff4f000b4eefa9c1e2 --- Android.bp | 12 ++++++------ .../com/android/internal/telephony/RILUtils.java | 6 ++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Android.bp b/Android.bp index eb16ba5fba..4097571eb5 100644 --- a/Android.bp +++ b/Android.bp @@ -83,14 +83,14 @@ java_library { "android.hardware.radio-V1.4-java", "android.hardware.radio-V1.5-java", "android.hardware.radio-V1.6-java", - "android.hardware.radio.config-V1-java", - "android.hardware.radio.data-V1-java", + "android.hardware.radio.config-V2-java", + "android.hardware.radio.data-V2-java", "android.hardware.radio.ims-V1-java", - "android.hardware.radio.messaging-V1-java", - "android.hardware.radio.modem-V1-java", + "android.hardware.radio.messaging-V2-java", + "android.hardware.radio.modem-V2-java", "android.hardware.radio.network-V2-java", - "android.hardware.radio.sim-V1-java", - "android.hardware.radio.voice-V1-java", + "android.hardware.radio.sim-V2-java", + "android.hardware.radio.voice-V2-java", "voip-common", "ims-common", "unsupportedappusage", diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index d016db8f18..52f8974e26 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -1681,12 +1681,10 @@ public class RILUtils { if ((networkTypeBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN) != 0) { raf |= android.hardware.radio.RadioAccessFamily.IWLAN; } - if ((networkTypeBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_LTE) != 0) { + if ((networkTypeBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_LTE) != 0 + || (networkTypeBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA) != 0) { raf |= android.hardware.radio.RadioAccessFamily.LTE; } - if ((networkTypeBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA) != 0) { - raf |= android.hardware.radio.RadioAccessFamily.LTE_CA; - } if ((networkTypeBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_NR) != 0) { raf |= android.hardware.radio.RadioAccessFamily.NR; } -- GitLab From 77d09851397a867ed322f2bc88d6e90a82dc2fa7 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 17 Nov 2022 22:12:25 +0000 Subject: [PATCH 188/656] Revert "Handle source PDN lost during HO" This reverts commit b16e6d724d1a74363d901746e539bf008e6b5835. Reason for revert: Considered the 3 proposals in 249922254#comment15, we adopt proposal 1(keep the original behavior) and relax the anomaly report. Change-Id: Ie1b2344a601ddada46273325df6ada3728109d9e --- .../internal/telephony/data/DataNetwork.java | 26 ------------------- .../telephony/data/DataNetworkTest.java | 20 +------------- 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 2f17b00a23..a7b974e3a3 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -1417,13 +1417,6 @@ public class DataNetwork extends StateMachine { + AccessNetworkConstants.transportTypeToString(transport) + " data call list changed event. " + responseList); } else { - // If source PDN is reported lost, notify network agent that the PDN is - // temporarily suspended and the old interface name is no longer usable. - boolean currentPdnIsAlive = responseList.stream() - .anyMatch(r -> mCid.get(mTransport) == r.getId()); - if (!currentPdnIsAlive) { - notifyNetworkUnusable(); - } log("Defer message " + eventToString(msg.what) + ":" + responseList); deferMessage(msg); } @@ -1471,25 +1464,6 @@ public class DataNetwork extends StateMachine { } return HANDLED; } - - /** - * Notify network agent that the PDN is temporarily suspended and the old interface name is - * no longer usable. The state will be re-evaluated when the handover ends. - */ - private void notifyNetworkUnusable() { - log(AccessNetworkConstants.transportTypeToString(mTransport) - + " reports current PDN lost, update capability to SUSPENDED," - + " TNA interfaceName to \"\""); - mNetworkCapabilities = new NetworkCapabilities - .Builder(mNetworkCapabilities) - .removeCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) - .build(); - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - - mLinkProperties.setInterfaceName(""); - mNetworkAgent.sendLinkProperties(mLinkProperties); - } } /** 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 6b96d83176..7bab74d5a8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -989,30 +989,12 @@ public class DataNetworkTest extends TelephonyTest { public void testHandover() throws Exception { setupDataNetwork(); + setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 456); // Now handover to IWLAN mDataNetworkUT.startHandover(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, null); - // the source transport might report PDN lost - mDataNetworkUT.sendMessage(8/*EVENT_DATA_STATE_CHANGED*/, - new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - Collections.emptyList(), null)); processAllMessages(); - // make sure interface name of source PDN is cleared - assertThat(mDataNetworkUT.getLinkProperties().getInterfaceName()).isNotEqualTo("ifname"); - // make sure the capability of source PDN is set to SUSPENDED - assertThat(mDataNetworkUT.getNetworkCapabilities() - .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)).isFalse(); verify(mMockedWwanDataServiceManager).startHandover(eq(123), any(Message.class)); - - // continue the HO - setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 456); - Message msg = new Message(); - msg.what = 26/*EVENT_NOTIFY_HANDOVER_STARTED_RESPONSE*/; - msg.arg2 = AccessNetworkConstants.TRANSPORT_TYPE_WLAN; - msg.obj = null; - mDataNetworkUT.sendMessage(msg); - processAllMessages(); - verify(mLinkBandwidthEstimator).unregisterCallback(any( LinkBandwidthEstimatorCallback.class)); assertThat(mDataNetworkUT.getTransport()) -- GitLab From 879fae04d03c8657c6cd22d3a6140ba2a3a1e5ef Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 17 Nov 2022 19:46:35 -0800 Subject: [PATCH 189/656] Unregister after replacement for network agent to avoid onLost When immutable properties change, the original behavior will unregister the networkagent, causing apps receiving onLost. Using the new API unregisterAfterReplacement will not cause onLost but being replaced by a equivalent or better network. Test: basic phone call + data browsing Bug: 253219539 Change-Id: I816a1b6e3a7ee77b9158ef9ee2331168076ba2c2 --- .../telephony/data/TelephonyNetworkAgent.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java index 78c555c4b0..5ed09e6b3e 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkAgent.java @@ -50,6 +50,9 @@ public class TelephonyNetworkAgent extends NetworkAgent { private final String mLogTag; private final LocalLog mLocalLog = new LocalLog(128); + /** Max unregister network agent delay. */ + private static final int NETWORK_AGENT_TEARDOWN_DELAY_MS = 5_000; + /** The parent data network. */ private final @NonNull DataNetwork mDataNetwork; @@ -296,14 +299,15 @@ public class TelephonyNetworkAgent extends NetworkAgent { /** * Abandon the network agent. This is used for telephony to re-create the network agent when - * immutable capabilities got changed, where telephony calls {@link NetworkAgent#unregister()} - * and then create another network agent with new capabilities. Abandon this network agent - * allowing it ignore the subsequent {@link #onNetworkUnwanted()} invocation caused by - * {@link NetworkAgent#unregister()}. + * immutable capabilities got changed, where telephony calls + * {@link NetworkAgent#unregisterAfterReplacement} and then create another network agent with + * new capabilities. Abandon this network agent allowing it ignore the subsequent + * {@link #onNetworkUnwanted()} invocation caused by + * {@link NetworkAgent#unregisterAfterReplacement}. */ public void abandon() { mAbandoned = true; - unregister(); + unregisterAfterReplacement(NETWORK_AGENT_TEARDOWN_DELAY_MS); } /** -- GitLab From 48042897b1c89089d7630360efa512c1b134679e Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Mon, 14 Nov 2022 11:22:30 -0800 Subject: [PATCH 190/656] Fix for GSM-8bit decoding error Bug: 253538769 Test: atest android.telephony.cts.VisualVoicemailServiceTest Change-Id: Iad422dbe730ab8d318537d60439210ef8e7d37aa --- .../telephony/VisualVoicemailSmsFilter.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java index 5bbe8b4bc4..1934136fc9 100644 --- a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java +++ b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java @@ -15,6 +15,8 @@ */ package com.android.internal.telephony; +import static com.android.internal.telephony.SmsConstants.ENCODING_8BIT; + import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; @@ -294,7 +296,18 @@ public class VisualVoicemailSmsFilter { result.firstMessage = message; } String body = message.getMessageBody(); - if (body == null && message.getUserData() != null) { + + /* + * For visual voice mail SMS message, UTF-8 is used by default + * {@link com.android.internal.telephony.SmsController#sendVisualVoicemailSmsForSubscriber} + * + * If config_sms_decode_gsm_8bit_data is enabled, GSM-8bit will be used to decode the + * received message. However, the message is most likely encoded with UTF-8. Therefore, + * we need to retry decoding the received message with UTF-8. + */ + if ((body == null || message.getReceivedEncodingType() == ENCODING_8BIT) + && message.getUserData() != null) { + Log.d(TAG, "getFullMessage decode using UTF-8"); // Attempt to interpret the user data as UTF-8. UTF-8 string over data SMS using // 8BIT data coding scheme is our recommended way to send VVM SMS and is used in CTS // Tests. The OMTP visual voicemail specification does not specify the SMS type and @@ -303,7 +316,8 @@ public class VisualVoicemailSmsFilter { try { body = decoder.decode(byteBuffer).toString(); } catch (CharacterCodingException e) { - // User data is not decode-able as UTF-8. Ignoring. + Log.e(TAG, "getFullMessage: got CharacterCodingException" + + " when decoding with UTF-8, e = " + e); return null; } } -- GitLab From bf9ad6d68168332430528675d23a334454d4ff8e Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 17 Nov 2022 22:54:18 -0800 Subject: [PATCH 191/656] Fixed file attributes The java file should not be executable. Changed the file mode from 755 to 644. Test: build Change-Id: I60430860979bda735f5dbbe08e7cb3e4aacb8420 --- src/java/com/android/internal/telephony/GsmCdmaCallTracker.java | 0 src/java/com/android/internal/telephony/LocaleTracker.java | 0 src/java/com/android/internal/telephony/ServiceStateTracker.java | 0 src/java/com/android/internal/telephony/SmsStorageMonitor.java | 0 src/java/com/android/internal/telephony/WapPushOverSms.java | 0 src/java/com/android/internal/telephony/WspTypeDecoder.java | 0 src/java/com/android/internal/telephony/cat/AppInterface.java | 0 src/java/com/android/internal/telephony/cat/CommandParams.java | 0 .../com/android/internal/telephony/cat/RilMessageDecoder.java | 0 .../internal/telephony/cdma/CdmaSmsBroadcastConfigInfo.java | 0 .../com/android/internal/telephony/gsm/UsimPhoneBookManager.java | 0 .../android/internal/telephony/imsphone/ImsPhoneConnection.java | 0 src/java/com/android/internal/telephony/uicc/PlmnActRecord.java | 0 src/java/com/android/internal/telephony/uicc/RuimRecords.java | 0 src/java/com/android/internal/telephony/uicc/UsimFileHandler.java | 0 .../src/com/android/internal/telephony/ConnectionTest.java | 0 .../internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java | 0 .../src/com/android/internal/telephony/uicc/RuimRecordsTest.java | 0 18 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/java/com/android/internal/telephony/GsmCdmaCallTracker.java mode change 100755 => 100644 src/java/com/android/internal/telephony/LocaleTracker.java mode change 100755 => 100644 src/java/com/android/internal/telephony/ServiceStateTracker.java mode change 100755 => 100644 src/java/com/android/internal/telephony/SmsStorageMonitor.java mode change 100755 => 100644 src/java/com/android/internal/telephony/WapPushOverSms.java mode change 100755 => 100644 src/java/com/android/internal/telephony/WspTypeDecoder.java mode change 100755 => 100644 src/java/com/android/internal/telephony/cat/AppInterface.java mode change 100755 => 100644 src/java/com/android/internal/telephony/cat/CommandParams.java mode change 100755 => 100644 src/java/com/android/internal/telephony/cat/RilMessageDecoder.java mode change 100755 => 100644 src/java/com/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo.java mode change 100755 => 100644 src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java mode change 100755 => 100644 src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java mode change 100755 => 100644 src/java/com/android/internal/telephony/uicc/PlmnActRecord.java mode change 100755 => 100644 src/java/com/android/internal/telephony/uicc/RuimRecords.java mode change 100755 => 100644 src/java/com/android/internal/telephony/uicc/UsimFileHandler.java mode change 100755 => 100644 tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java mode change 100755 => 100644 tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java mode change 100755 => 100644 tests/telephonytests/src/com/android/internal/telephony/uicc/RuimRecordsTest.java diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/SmsStorageMonitor.java b/src/java/com/android/internal/telephony/SmsStorageMonitor.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/WapPushOverSms.java b/src/java/com/android/internal/telephony/WapPushOverSms.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/WspTypeDecoder.java b/src/java/com/android/internal/telephony/WspTypeDecoder.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/cat/AppInterface.java b/src/java/com/android/internal/telephony/cat/AppInterface.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/cat/CommandParams.java b/src/java/com/android/internal/telephony/cat/CommandParams.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java b/src/java/com/android/internal/telephony/cat/RilMessageDecoder.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo.java b/src/java/com/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java b/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java old mode 100755 new mode 100644 diff --git a/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java b/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java old mode 100755 new mode 100644 diff --git a/tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java old mode 100755 new mode 100644 diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java old mode 100755 new mode 100644 diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/RuimRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/RuimRecordsTest.java old mode 100755 new mode 100644 -- GitLab From 790f232994b921cb7487a03f5d533dea21675adc Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 17 Nov 2022 22:46:55 -0800 Subject: [PATCH 192/656] Renamed methods for clarification Test: build Bug: 239607619 Change-Id: Iefbf99da50eb7575234d03a36bd65d2e34a76b41 --- .../telephony/MultiSimSettingController.java | 2 +- .../com/android/internal/telephony/Phone.java | 2 +- .../internal/telephony/SMSDispatcher.java | 2 +- .../telephony/SubscriptionController.java | 17 ++++++++--------- .../telephony/SubscriptionInfoUpdater.java | 2 +- .../internal/telephony/data/PhoneSwitcher.java | 6 +++--- .../telephony/data/TelephonyNetworkFactory.java | 4 ++-- .../SubscriptionManagerService.java | 2 +- .../internal/telephony/uicc/RuimRecords.java | 2 +- .../internal/telephony/uicc/SIMRecords.java | 2 +- .../internal/telephony/uicc/UiccProfile.java | 4 ++-- .../internal/telephony/GsmCdmaPhoneTest.java | 12 ++++++------ .../MultiSimSettingControllerTest.java | 2 +- .../telephony/SubscriptionInfoUpdaterTest.java | 16 ++++++++-------- .../telephony/TelephonyRegistryTest.java | 2 +- .../telephony/data/PhoneSwitcherTest.java | 2 +- .../data/TelephonyNetworkFactoryTest.java | 12 ++++++------ 17 files changed, 45 insertions(+), 46 deletions(-) diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index f3b91dfb86..0a0e265b15 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -439,7 +439,7 @@ public class MultiSimSettingController extends Handler { // being specified in it. So here we do additional check to make sur we don't miss the // subId. if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - int[] subIds = mSubController.getSubId(phoneId); + int[] subIds = mSubController.getSubIds(phoneId); if (!ArrayUtils.isEmpty(subIds)) { CarrierConfigManager cm = (CarrierConfigManager) mContext.getSystemService( mContext.CARRIER_CONFIG_SERVICE); diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 0e237ea9fd..b17282be5d 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -4067,7 +4067,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { Rlog.e(LOG_TAG, "SubscriptionController.getInstance = null! Returning default subId"); return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; } - return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhoneId); + return SubscriptionController.getInstance().getSubId(mPhoneId); } /** diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 1a444ff990..0c7aa48de1 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -2860,7 +2860,7 @@ public abstract class SMSDispatcher extends Handler { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected int getSubId() { - return SubscriptionController.getInstance().getSubIdUsingPhoneId(mPhone.getPhoneId()); + return SubscriptionController.getInstance().getSubId(mPhone.getPhoneId()); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index c9929838ce..1b9129a76a 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -1520,7 +1520,7 @@ public class SubscriptionController extends ISub.Stub { notifySubscriptionInfoChanged(); } else { // Handle Local SIM devices // Set Display name after sub id is set above so as to get valid simCarrierName - int subId = getSubIdUsingPhoneId(slotIndex); + int subId = getSubId(slotIndex); if (!SubscriptionManager.isValidSubscriptionId(subId)) { if (DBG) { logdl("[addSubInfoRecord]- getSubId failed invalid subId = " + subId); @@ -1795,7 +1795,7 @@ public class SubscriptionController extends ISub.Stub { public boolean setPlmnSpn(int slotIndex, boolean showPlmn, String plmn, boolean showSpn, String spn) { synchronized (mLock) { - int subId = getSubIdUsingPhoneId(slotIndex); + int subId = getSubId(slotIndex); if (mContext.getPackageManager().resolveContentProvider( SubscriptionManager.CONTENT_URI.getAuthority(), 0) == null || !SubscriptionManager.isValidSubscriptionId(subId)) { @@ -2627,13 +2627,13 @@ public class SubscriptionController extends ISub.Stub { } /** - * Return the subId for specified slot Id. + * Return the subIds for specified slot Id. * @deprecated */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Override @Deprecated - public int[] getSubId(int slotIndex) { + public int[] getSubIds(int slotIndex) { if (VDBG) printStackTrace("[getSubId]+ slotIndex=" + slotIndex); // Map default slotIndex to the current default subId. @@ -3027,9 +3027,8 @@ public class SubscriptionController extends ISub.Stub { // FIXME: We need we should not be assuming phoneId == slotIndex as it will not be true // when there are multiple subscriptions per sim and probably for other reasons. - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int getSubIdUsingPhoneId(int phoneId) { - int[] subIds = getSubId(phoneId); + public int getSubId(int phoneId) { + int[] subIds = getSubIds(phoneId); if (subIds == null || subIds.length == 0) { return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @@ -4043,7 +4042,7 @@ public class SubscriptionController extends ISub.Stub { * @return true if sub/group is the same, false otherwise */ public boolean checkPhoneIdAndIccIdMatch(int phoneId, String iccid) { - int subId = getSubIdUsingPhoneId(phoneId); + int subId = getSubId(phoneId); if (!SubscriptionManager.isUsableSubIdValue(subId)) return false; ParcelUuid groupUuid = getGroupUuid(subId); List subInfoList; @@ -4316,7 +4315,7 @@ public class SubscriptionController extends ISub.Stub { Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT + physicalSlotIndex); } catch (Settings.SettingNotFoundException e) { // Value never set. Return whether it's currently active. - subId = getSubIdUsingPhoneId(logicalSlotIndex); + subId = getSubId(logicalSlotIndex); } return subId; diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index 596589905b..2a9aac6584 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -1166,7 +1166,7 @@ public class SubscriptionInfoUpdater extends Handler { return; } - int currentSubId = mSubscriptionController.getSubIdUsingPhoneId(phoneId); + int currentSubId = mSubscriptionController.getSubId(phoneId); if (!SubscriptionManager.isValidSubscriptionId(currentSubId) || currentSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { if (DBG) logd("No subscription is active for phone being updated"); diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index f3f72f1d1b..b1552cdef0 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -1305,7 +1305,7 @@ public class PhoneSwitcher extends Handler { // Check if phoneId to subId mapping is changed. for (int i = 0; i < mActiveModemCount; i++) { - int sub = mSubscriptionController.getSubIdUsingPhoneId(i); + int sub = mSubscriptionController.getSubId(i); if (SubscriptionManager.isValidSubscriptionId(sub)) hasAnyActiveSubscription = true; @@ -1614,7 +1614,7 @@ public class PhoneSwitcher extends Handler { } mPreferredDataSubId.set( - mSubscriptionController.getSubIdUsingPhoneId(mPreferredDataPhoneId)); + mSubscriptionController.getSubId(mPreferredDataPhoneId)); } protected void transitionToEmergencyPhone() { @@ -1647,7 +1647,7 @@ public class PhoneSwitcher extends Handler { // In any case, if phone state is inactive, don't apply the network request. if (!isPhoneActive(phoneId) || ( - mSubscriptionController.getSubIdUsingPhoneId(phoneId) == INVALID_SUBSCRIPTION_ID + mSubscriptionController.getSubId(phoneId) == INVALID_SUBSCRIPTION_ID && !isEmergencyNetworkRequest(networkRequest))) { return false; } diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java index e64dd9b7c0..3a71055558 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java @@ -115,7 +115,7 @@ public class TelephonyNetworkFactory extends NetworkFactory { private NetworkCapabilities makeNetworkFilter(SubscriptionController subscriptionController, int phoneId) { - final int subscriptionId = subscriptionController.getSubIdUsingPhoneId(phoneId); + final int subscriptionId = subscriptionController.getSubId(phoneId); return makeNetworkFilter(subscriptionId); } @@ -238,7 +238,7 @@ public class TelephonyNetworkFactory extends NetworkFactory { // watch for phone->subId changes, reapply new filter and let // that flow through to apply/revoke of requests private void onSubIdChange() { - final int newSubscriptionId = mSubscriptionController.getSubIdUsingPhoneId( + final int newSubscriptionId = mSubscriptionController.getSubId( mPhone.getPhoneId()); if (mSubscriptionId != newSubscriptionId) { if (DBG) logl("onSubIdChange " + mSubscriptionId + "->" + newSubscriptionId); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index e0b55891a4..39727997ad 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -402,7 +402,7 @@ public class SubscriptionManagerService extends ISub.Stub { } @Override - public int[] getSubId(int slotIndex) { + public int[] getSubIds(int slotIndex) { return null; } diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java index 08c15735b8..e039c55453 100644 --- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java +++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java @@ -821,7 +821,7 @@ public class RuimRecords extends IccRecords { // TODO: The below is hacky since the SubscriptionController may not be ready at this time. if (!TextUtils.isEmpty(mMdn)) { int phoneId = mParentApp.getUiccProfile().getPhoneId(); - int subId = SubscriptionController.getInstance().getSubIdUsingPhoneId(phoneId); + int subId = SubscriptionController.getInstance().getSubId(phoneId); if (SubscriptionManager.isValidSubscriptionId(subId)) { SubscriptionManager.from(mContext).setDisplayNumber(mMdn, subId); } else { diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index f94bcfbe13..b8fb2a6f2c 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -1079,7 +1079,7 @@ public class SIMRecords extends IccRecords { mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); if (ar.exception != null && configManager != null) { PersistableBundle b = configManager.getConfigForSubId( - SubscriptionController.getInstance().getSubIdUsingPhoneId( + SubscriptionController.getInstance().getSubId( mParentApp.getPhoneId())); if (b != null && b.getBoolean( CarrierConfigManager.KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL)) { diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index 5b84c6c066..154e59fc33 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -433,7 +433,7 @@ public class UiccProfile extends IccCard { */ private void handleCarrierNameOverride() { SubscriptionController subCon = SubscriptionController.getInstance(); - final int subId = subCon.getSubIdUsingPhoneId(mPhoneId); + final int subId = subCon.getSubId(mPhoneId); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { loge("subId not valid for Phone " + mPhoneId); return; @@ -498,7 +498,7 @@ public class UiccProfile extends IccCard { */ private void handleSimCountryIsoOverride() { SubscriptionController subCon = SubscriptionController.getInstance(); - final int subId = subCon.getSubIdUsingPhoneId(mPhoneId); + final int subId = subCon.getSubId(mPhoneId); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { loge("subId not valid for Phone " + mPhoneId); return; diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index ba5e15537d..46fe5d32c0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -1057,13 +1057,13 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // invalid subId doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionController). - getSubIdUsingPhoneId(anyInt()); + getSubId(anyInt()); assertEquals(false, mPhoneUT.getCallForwardingIndicator()); // valid subId, sharedPreference not present int subId1 = 0; int subId2 = 1; - doReturn(subId1).when(mSubscriptionController).getSubIdUsingPhoneId(anyInt()); + doReturn(subId1).when(mSubscriptionController).getSubId(anyInt()); assertEquals(false, mPhoneUT.getCallForwardingIndicator()); // old sharedPreference present @@ -1085,7 +1085,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { assertEquals(true, mPhoneUT.getCallForwardingIndicator()); // check for another subId - doReturn(subId2).when(mSubscriptionController).getSubIdUsingPhoneId(anyInt()); + doReturn(subId2).when(mSubscriptionController).getSubId(anyInt()); assertEquals(false, mPhoneUT.getCallForwardingIndicator()); // set value for the new subId in sharedPreference @@ -1094,7 +1094,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { assertEquals(true, mPhoneUT.getCallForwardingIndicator()); // switching back to previous subId, stored value should still be available - doReturn(subId1).when(mSubscriptionController).getSubIdUsingPhoneId(anyInt()); + doReturn(subId1).when(mSubscriptionController).getSubId(anyInt()); assertEquals(true, mPhoneUT.getCallForwardingIndicator()); // cleanup @@ -1501,7 +1501,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @SmallTest public void testLoadAllowedNetworksFromSubscriptionDatabase_loadTheNullValue_isLoadedTrue() { int subId = 1; - doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(anyInt()); + doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); doReturn(null).when(mSubscriptionController).getSubscriptionProperty(anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); @@ -1515,7 +1515,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @SmallTest public void testLoadAllowedNetworksFromSubscriptionDatabase_subIdNotValid_isLoadedFalse() { int subId = -1; - doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(anyInt()); + doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); when(mSubscriptionController.getSubscriptionProperty(anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES))).thenReturn(null); diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index ac76797a4a..4fe748caea 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -848,7 +848,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Still notify carrier config without specifying subId2, but this time subController // and CarrierConfigManager have subId 2 active and ready. - doReturn(new int[] {2}).when(mSubControllerMock).getSubId(1); + doReturn(new int[] {2}).when(mSubControllerMock).getSubIds(1); CarrierConfigManager cm = (CarrierConfigManager) mContext.getSystemService( mContext.CARRIER_CONFIG_SERVICE); doReturn(new PersistableBundle()).when(cm).getConfigForSubId(2); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java index 49375293d9..ff217b0a0c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java @@ -151,7 +151,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { }); doReturn(mUserInfo).when(mIActivityManager).getCurrentUser(); - doReturn(new int[]{FAKE_SUB_ID_1}).when(mSubscriptionController).getSubId(0); + doReturn(new int[]{FAKE_SUB_ID_1}).when(mSubscriptionController).getSubIds(0); doReturn(new int[]{FAKE_SUB_ID_1}).when(mSubscriptionManager).getActiveSubscriptionIdList(); ((MockContentResolver) mContext.getContentResolver()).addProvider( SubscriptionManager.CONTENT_URI.getAuthority(), @@ -750,7 +750,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { final int phoneId = mPhone.getPhoneId(); String carrierPackageName = "FakeCarrierPackageName"; - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); doReturn(carrierPackageName).when(mTelephonyManager) .getCarrierServicePackageNameForLogicalSlot(eq(phoneId)); @@ -775,7 +775,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { true, ""); String carrierPackageName = "FakeCarrierPackageName"; - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); doReturn(false).when(mSubInfo).isOpportunistic(); doReturn(carrierPackageName).when(mTelephonyManager) @@ -807,7 +807,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { String carrierPackageName = "FakeCarrierPackageName"; - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); doReturn(true).when(mSubInfo).isOpportunistic(); doReturn(carrierPackageName).when(mTelephonyManager) @@ -841,7 +841,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { doReturn(true).when(mSubscriptionController).canPackageManageGroup( ParcelUuid.fromString("11111111-2222-3333-4444-555555555555"), carrierPackageName); - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); doReturn(carrierPackageName).when(mTelephonyManager) .getCarrierServicePackageNameForLogicalSlot(eq(phoneId)); @@ -876,7 +876,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { doReturn(true).when(mSubscriptionController).canPackageManageGroup( ParcelUuid.fromString("11111111-2222-3333-4444-555555555555"), carrierPackageName); - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); doReturn(ParcelUuid.fromString("11111111-2222-3333-4444-555555555555")) .when(mSubInfo).getGroupUuid(); @@ -970,7 +970,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { setupUsageSettingResources(); // Setup subscription - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); doReturn(null).when(mSubInfo).getGroupUuid(); doReturn(false).when(mSubInfo).isOpportunistic(); @@ -1017,7 +1017,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { String carrierPackageName = "FakeCarrierPackageName"; - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); doReturn(false).when(mSubInfo).isOpportunistic(); doReturn(carrierPackageName).when(mTelephonyManager) diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java index cf7cadb923..21002e140d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java @@ -1165,7 +1165,7 @@ public class TelephonyRegistryTest extends TelephonyTest { final int subId = 1; // Return a slotIndex / phoneId of 0 for subId 1. - doReturn(new int[] {subId}).when(mSubscriptionController).getSubId(phoneId); + doReturn(new int[] {subId}).when(mSubscriptionController).getSubIds(phoneId); doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(subId); doReturn(phoneId).when(mMockSubInfo).getSimSlotIndex(); mServiceManagerMockedServices.put("isub", mSubscriptionController); 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 bd4b5f8fa0..bcaa056946 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -1990,7 +1990,7 @@ public class PhoneSwitcherTest extends TelephonyTest { } else { return mSlotIndexToSubId[phoneId][0]; } - }).when(mSubscriptionController).getSubIdUsingPhoneId(anyInt()); + }).when(mSubscriptionController).getSubId(anyInt()); doAnswer(invocation -> { int subId = (int) invocation.getArguments()[0]; diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java index 7d323aa4b4..86e508917e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java @@ -205,7 +205,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { doAnswer(invocation -> { final NetworkCapabilities capabilitiesFilter = mTelephonyNetworkFactoryUT.makeNetworkFilter( - mSubscriptionController.getSubIdUsingPhoneId(0)); + mSubscriptionController.getSubId(0)); for (final TelephonyNetworkRequest request : mAllNetworkRequestSet) { final int message = request.canBeSatisfiedBy(capabilitiesFilter) ? CMD_REQUEST_NETWORK : CMD_CANCEL_REQUEST; @@ -230,7 +230,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { createMockedTelephonyComponents(); doReturn(false).when(mPhoneSwitcher).shouldApplyNetworkRequest(any(), anyInt()); - doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(subId).when(mSubscriptionController).getSubId(phoneId); // fake onSubscriptionChangedListener being triggered. mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); @@ -303,7 +303,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { createMockedTelephonyComponents(); - doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(subId).when(mSubscriptionController).getSubId(phoneId); mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); processAllMessages(); @@ -317,7 +317,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { processAllMessages(); assertEquals(1, mNetworkRequestList.size()); - doReturn(altSubId).when(mSubscriptionController).getSubIdUsingPhoneId(altPhoneId); + doReturn(altSubId).when(mSubscriptionController).getSubId(altPhoneId); processAllMessages(); assertEquals(1, mNetworkRequestList.size()); @@ -332,7 +332,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { processAllMessages(); assertEquals(1, mNetworkRequestList.size()); - doReturn(unusedSubId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(unusedSubId).when(mSubscriptionController).getSubId(phoneId); mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); processAllMessages(); @@ -342,7 +342,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { processAllMessages(); assertEquals(0, mNetworkRequestList.size()); - doReturn(subId).when(mSubscriptionController).getSubIdUsingPhoneId(phoneId); + doReturn(subId).when(mSubscriptionController).getSubId(phoneId); mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); processAllMessages(); -- GitLab From a27ae7280b62905ab8b9cca44934232f955942bc Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Wed, 14 Sep 2022 13:59:13 +0000 Subject: [PATCH 193/656] SMS class 2 handling. ImsManager object is stored and async response from SIM card is acknowledged to IMS Test: manual(receive class2 SMS) Change-Id: I1e76e5af8fca2c79a8f556ef89bfae9e974d7bfc --- .../internal/telephony/ImsSmsDispatcher.java | 13 +- .../internal/telephony/InboundSmsHandler.java | 18 +- .../telephony/SmsDispatchersController.java | 19 +- .../telephony/cdma/CdmaInboundSmsHandler.java | 3 +- .../telephony/gsm/GsmInboundSmsHandler.java | 17 +- .../gsm/UsimDataDownloadHandler.java | 166 +++++++++++++++--- 6 files changed, 197 insertions(+), 39 deletions(-) diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java index 324959a00e..91cee51e62 100644 --- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java +++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.app.Activity; import android.content.Context; import android.os.Binder; import android.os.Message; @@ -249,6 +250,10 @@ public class ImsSmsDispatcher extends SMSDispatcher { mappedResult = ImsSmsImplBase.DELIVER_STATUS_ERROR_REQUEST_NOT_SUPPORTED; break; + case Activity.RESULT_OK: + // class2 message saving to SIM operation is in progress, defer ack + // until saving to SIM is success/failure + return; default: mappedResult = ImsSmsImplBase.DELIVER_STATUS_ERROR_GENERIC; break; @@ -264,7 +269,7 @@ public class ImsSmsDispatcher extends SMSDispatcher { } catch (ImsException e) { loge("Failed to acknowledgeSms(). Error: " + e.getMessage()); } - }, true /* ignoreClass */, true /* isOverIms */); + }, true /* ignoreClass */, true /* isOverIms */, token); } finally { Binder.restoreCallingIdentity(identity); } @@ -296,6 +301,9 @@ public class ImsSmsDispatcher extends SMSDispatcher { mImsManager = manager; setListeners(); mIsImsServiceUp = true; + + /* set ImsManager */ + mSmsDispatchersController.setImsManager(mImsManager); } } @@ -310,6 +318,9 @@ public class ImsSmsDispatcher extends SMSDispatcher { synchronized (mLock) { mImsManager = null; mIsImsServiceUp = false; + + /* unset ImsManager */ + mSmsDispatchersController.setImsManager(null); } } }, this::post); diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java index a077b2c818..72cab0fd15 100644 --- a/src/java/com/android/internal/telephony/InboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java @@ -182,6 +182,7 @@ public abstract class InboundSmsHandler extends StateMachine { /** BroadcastReceiver timed out waiting for an intent */ public static final int EVENT_RECEIVER_TIMEOUT = 9; + /** Wakelock release delay when returning to idle state. */ private static final int WAKELOCK_TIMEOUT = 3000; @@ -498,7 +499,6 @@ public abstract class InboundSmsHandler extends StateMachine { case EVENT_RETURN_TO_IDLE: // already in idle state; ignore return HANDLED; - case EVENT_BROADCAST_COMPLETE: case EVENT_START_ACCEPTING_SMS: default: @@ -537,7 +537,8 @@ public abstract class InboundSmsHandler extends StateMachine { case EVENT_INJECT_SMS: // handle new injected SMS - handleInjectSms((AsyncResult) msg.obj, msg.arg1 == 1 /* isOverIms */); + handleInjectSms((AsyncResult) msg.obj, msg.arg1 == 1 /* isOverIms */, + msg.arg2 /* token */); sendMessage(EVENT_RETURN_TO_IDLE); return HANDLED; @@ -660,7 +661,6 @@ public abstract class InboundSmsHandler extends StateMachine { } } } - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private void handleNewSms(AsyncResult ar) { if (ar.exception != null) { @@ -671,7 +671,7 @@ public abstract class InboundSmsHandler extends StateMachine { int result; try { SmsMessage sms = (SmsMessage) ar.result; - result = dispatchMessage(sms.mWrappedSmsMessage, SOURCE_NOT_INJECTED); + result = dispatchMessage(sms.mWrappedSmsMessage, SOURCE_NOT_INJECTED, 0 /*unused*/); } catch (RuntimeException ex) { loge("Exception dispatching message", ex); result = RESULT_SMS_DISPATCH_FAILURE; @@ -690,7 +690,7 @@ public abstract class InboundSmsHandler extends StateMachine { * @param ar is the AsyncResult that has the SMS PDU to be injected. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private void handleInjectSms(AsyncResult ar, boolean isOverIms) { + private void handleInjectSms(AsyncResult ar, boolean isOverIms, int token) { int result; SmsDispatchersController.SmsInjectionCallback callback = null; try { @@ -702,7 +702,7 @@ public abstract class InboundSmsHandler extends StateMachine { } else { @SmsSource int smsSource = isOverIms ? SOURCE_INJECTED_FROM_IMS : SOURCE_INJECTED_FROM_UNKNOWN; - result = dispatchMessage(sms.mWrappedSmsMessage, smsSource); + result = dispatchMessage(sms.mWrappedSmsMessage, smsSource, token); } } catch (RuntimeException ex) { loge("Exception dispatching message", ex); @@ -723,7 +723,7 @@ public abstract class InboundSmsHandler extends StateMachine { * @return a result code from {@link android.provider.Telephony.Sms.Intents}, * or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC */ - private int dispatchMessage(SmsMessageBase smsb, @SmsSource int smsSource) { + private int dispatchMessage(SmsMessageBase smsb, @SmsSource int smsSource, int token) { // If sms is null, there was a parsing error. if (smsb == null) { loge("dispatchSmsMessage: message is null"); @@ -737,7 +737,7 @@ public abstract class InboundSmsHandler extends StateMachine { return Intents.RESULT_SMS_HANDLED; } - int result = dispatchMessageRadioSpecific(smsb, smsSource); + int result = dispatchMessageRadioSpecific(smsb, smsSource, token); // In case of error, add to metrics. This is not required in case of success, as the // data will be tracked when the message is processed (processMessagePart). @@ -759,7 +759,7 @@ public abstract class InboundSmsHandler extends StateMachine { * or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC */ protected abstract int dispatchMessageRadioSpecific(SmsMessageBase smsb, - @SmsSource int smsSource); + @SmsSource int smsSource, int token); /** * Send an acknowledge message to the SMSC. diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java index 1763b5f8a0..a57a68c04c 100644 --- a/src/java/com/android/internal/telephony/SmsDispatchersController.java +++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java @@ -406,7 +406,7 @@ public class SmsDispatchersController extends Handler { // SMS pdus when the phone is camping on CDMA(3gpp2) network and vice versa. android.telephony.SmsMessage msg = android.telephony.SmsMessage.createFromPdu(pdu, format); - injectSmsPdu(msg, format, callback, false /* ignoreClass */, isOverIms); + injectSmsPdu(msg, format, callback, false /* ignoreClass */, isOverIms, 0 /* unused */); } /** @@ -421,7 +421,7 @@ public class SmsDispatchersController extends Handler { */ @VisibleForTesting public void injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback, - boolean ignoreClass, boolean isOverIms) { + boolean ignoreClass, boolean isOverIms, int token) { Rlog.d(TAG, "SmsDispatchersController:injectSmsPdu"); try { if (msg == null) { @@ -443,7 +443,7 @@ public class SmsDispatchersController extends Handler { Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg + ", format=" + format + "to mGsmInboundSmsHandler"); mGsmInboundSmsHandler.sendMessage( - InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, 0, ar); + InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, token, ar); } else if (format.equals(SmsConstants.FORMAT_3GPP2)) { Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg + ", format=" + format + "to mCdmaInboundSmsHandler"); @@ -460,6 +460,19 @@ public class SmsDispatchersController extends Handler { } } + /** + * sets ImsManager object. + * + * @param imsManager holds a valid object or a null for setting + */ + public boolean setImsManager(ImsManager imsManager) { + if (mGsmInboundSmsHandler != null) { + mGsmInboundSmsHandler.setImsManager(imsManager); + return true; + } + return false; + } + /** * Retry the message along to the radio. * diff --git a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java index eb5f866b8e..096dba1419 100644 --- a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java @@ -194,7 +194,8 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler { * @return true if the message was handled here; false to continue processing */ @Override - protected int dispatchMessageRadioSpecific(SmsMessageBase smsb, @SmsSource int smsSource) { + protected int dispatchMessageRadioSpecific(SmsMessageBase smsb, @SmsSource int smsSource, + int token) { SmsMessage sms = (SmsMessage) smsb; boolean isBroadcastType = (SmsEnvelope.MESSAGE_TYPE_BROADCAST == sms.getMessageType()); diff --git a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java index b1f62facdc..98fbcf81be 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java @@ -28,6 +28,7 @@ import android.os.Message; import android.os.SystemProperties; import android.provider.Telephony.Sms.Intents; +import com.android.ims.ImsManager; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.InboundSmsHandler; import com.android.internal.telephony.Phone; @@ -153,7 +154,8 @@ public class GsmInboundSmsHandler extends InboundSmsHandler { * or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC */ @Override - protected int dispatchMessageRadioSpecific(SmsMessageBase smsb, @SmsSource int smsSource) { + protected int dispatchMessageRadioSpecific(SmsMessageBase smsb, @SmsSource int smsSource, + int token) { SmsMessage sms = (SmsMessage) smsb; if (sms.isTypeZero()) { @@ -177,7 +179,7 @@ public class GsmInboundSmsHandler extends InboundSmsHandler { // Send SMS-PP data download messages to UICC. See 3GPP TS 31.111 section 7.1.1. if (sms.isUsimDataDownload()) { UsimServiceTable ust = mPhone.getUsimServiceTable(); - return mDataDownloadHandler.handleUsimDataDownload(ust, sms, smsSource); + return mDataDownloadHandler.handleUsimDataDownload(ust, sms, smsSource, token); } boolean handled = false; @@ -268,4 +270,15 @@ public class GsmInboundSmsHandler extends InboundSmsHandler { android.telephony.SmsMessage.FORMAT_3GPP); mPhone.getSmsStats().onIncomingSmsVoicemail(false /* is3gpp2 */, smsSource); } + + /** + * sets ImsManager object. + */ + public boolean setImsManager(ImsManager imsManager) { + if (mDataDownloadHandler != null) { + mDataDownloadHandler.setImsManager(imsManager); + return true; + } + return false; + } } diff --git a/src/java/com/android/internal/telephony/gsm/UsimDataDownloadHandler.java b/src/java/com/android/internal/telephony/gsm/UsimDataDownloadHandler.java index ed819c1adc..bae56d127c 100644 --- a/src/java/com/android/internal/telephony/gsm/UsimDataDownloadHandler.java +++ b/src/java/com/android/internal/telephony/gsm/UsimDataDownloadHandler.java @@ -17,13 +17,19 @@ package com.android.internal.telephony.gsm; import android.app.Activity; +import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.provider.Telephony.Sms.Intents; import android.telephony.PhoneNumberUtils; import android.telephony.SmsManager; +import android.telephony.ims.stub.ImsSmsImplBase; +import com.android.ims.ImsException; +import com.android.ims.ImsManager; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.InboundSmsHandler; import com.android.internal.telephony.PhoneFactory; @@ -61,10 +67,14 @@ public class UsimDataDownloadHandler extends Handler { private final CommandsInterface mCi; private final int mPhoneId; + private ImsManager mImsManager; + Resources mResource; public UsimDataDownloadHandler(CommandsInterface commandsInterface, int phoneId) { mCi = commandsInterface; mPhoneId = phoneId; + mImsManager = null; // will get initialized when ImsManager connection is ready + mResource = Resources.getSystem(); } /** @@ -79,7 +89,7 @@ public class UsimDataDownloadHandler extends Handler { * @return {@code Activity.RESULT_OK} on success; {@code RESULT_SMS_GENERIC_ERROR} on failure */ int handleUsimDataDownload(UsimServiceTable ust, SmsMessage smsMessage, - @InboundSmsHandler.SmsSource int smsSource) { + @InboundSmsHandler.SmsSource int smsSource, int token) { // If we receive an SMS-PP message before the UsimServiceTable has been loaded, // assume that the data download service is not present. This is very unlikely to // happen because the IMS connection will not be established until after the ISIM @@ -87,7 +97,7 @@ public class UsimDataDownloadHandler extends Handler { if (ust != null && ust.isAvailable( UsimServiceTable.UsimService.DATA_DL_VIA_SMS_PP)) { Rlog.d(TAG, "Received SMS-PP data download, sending to UICC."); - return startDataDownload(smsMessage, smsSource); + return startDataDownload(smsMessage, smsSource, token); } else { Rlog.d(TAG, "DATA_DL_VIA_SMS_PP service not available, storing message to UICC."); String smsc = IccUtils.bytesToHexString( @@ -95,7 +105,8 @@ public class UsimDataDownloadHandler extends Handler { smsMessage.getServiceCenterAddress())); mCi.writeSmsToSim(SmsManager.STATUS_ON_ICC_UNREAD, smsc, IccUtils.bytesToHexString(smsMessage.getPdu()), - obtainMessage(EVENT_WRITE_SMS_COMPLETE)); + obtainMessage(EVENT_WRITE_SMS_COMPLETE, + new int[]{ smsSource, smsMessage.mMessageRef, token })); addUsimDataDownloadToMetrics(false, smsSource); return Activity.RESULT_OK; // acknowledge after response from write to USIM } @@ -111,9 +122,9 @@ public class UsimDataDownloadHandler extends Handler { * @return {@code Activity.RESULT_OK} on success; {@code RESULT_SMS_GENERIC_ERROR} on failure */ public int startDataDownload(SmsMessage smsMessage, - @InboundSmsHandler.SmsSource int smsSource) { + @InboundSmsHandler.SmsSource int smsSource, int token) { if (sendMessage(obtainMessage(EVENT_START_DATA_DOWNLOAD, - smsSource, 0 /* unused */, smsMessage))) { + smsSource, token, smsMessage))) { return Activity.RESULT_OK; // we will send SMS ACK/ERROR based on UICC response } else { Rlog.e(TAG, "startDataDownload failed to send message to start data download."); @@ -122,7 +133,7 @@ public class UsimDataDownloadHandler extends Handler { } private void handleDataDownload(SmsMessage smsMessage, - @InboundSmsHandler.SmsSource int smsSource) { + @InboundSmsHandler.SmsSource int smsSource, int token) { int dcs = smsMessage.getDataCodingScheme(); int pid = smsMessage.getProtocolIdentifier(); byte[] pdu = smsMessage.getPdu(); // includes SC address @@ -139,6 +150,7 @@ public class UsimDataDownloadHandler extends Handler { byte[] envelope = new byte[totalLength]; int index = 0; + Rlog.d(TAG, "smsSource: " + smsSource + "Token: " + token); // SMS-PP download tag and length (assumed to be < 256 bytes). envelope[index++] = (byte) BER_SMS_PP_DOWNLOAD_TAG; @@ -173,14 +185,16 @@ public class UsimDataDownloadHandler extends Handler { // Verify that we calculated the payload size correctly. if (index != envelope.length) { Rlog.e(TAG, "startDataDownload() calculated incorrect envelope length, aborting."); - acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR); + acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR, + smsSource, token, smsMessage.mMessageRef); addUsimDataDownloadToMetrics(false, smsSource); return; } String encodedEnvelope = IccUtils.bytesToHexString(envelope); mCi.sendEnvelopeWithStatus(encodedEnvelope, obtainMessage( - EVENT_SEND_ENVELOPE_RESPONSE, new int[]{ dcs, pid })); + EVENT_SEND_ENVELOPE_RESPONSE, new int[]{ dcs, pid, smsSource, + smsMessage.mMessageRef, token })); addUsimDataDownloadToMetrics(true, smsSource); } @@ -211,7 +225,8 @@ public class UsimDataDownloadHandler extends Handler { * @param response UICC response encoded as hexadecimal digits. First two bytes are the * UICC SW1 and SW2 status bytes. */ - private void sendSmsAckForEnvelopeResponse(IccIoResult response, int dcs, int pid) { + private void sendSmsAckForEnvelopeResponse(IccIoResult response, int dcs, int pid, + int smsSource, int token, int messageRef) { int sw1 = response.sw1; int sw2 = response.sw2; @@ -221,7 +236,8 @@ public class UsimDataDownloadHandler extends Handler { success = true; } else if (sw1 == 0x93 && sw2 == 0x00) { Rlog.e(TAG, "USIM data download failed: Toolkit busy"); - acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY); + acknowledgeSmsWithError(CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY, + smsSource, token, messageRef); return; } else if (sw1 == 0x62 || sw1 == 0x63) { Rlog.e(TAG, "USIM data download failed: " + response.toString()); @@ -234,10 +250,11 @@ public class UsimDataDownloadHandler extends Handler { byte[] responseBytes = response.payload; if (responseBytes == null || responseBytes.length == 0) { if (success) { - mCi.acknowledgeLastIncomingGsmSms(true, 0, null); + acknowledgeSmsWithSuccess(0, smsSource, token, messageRef); } else { acknowledgeSmsWithError( - CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR); + CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR, smsSource, + token, messageRef); } return; } @@ -268,12 +285,32 @@ public class UsimDataDownloadHandler extends Handler { System.arraycopy(responseBytes, 0, smsAckPdu, index, responseBytes.length); - mCi.acknowledgeIncomingGsmSmsWithPdu(success, - IccUtils.bytesToHexString(smsAckPdu), null); + if (smsSource == InboundSmsHandler.SOURCE_INJECTED_FROM_IMS && ackViaIms()) { + acknowledgeImsSms(token, messageRef, true, smsAckPdu); + } else { + mCi.acknowledgeIncomingGsmSmsWithPdu(success, + IccUtils.bytesToHexString(smsAckPdu), null); + } + } + + private void acknowledgeSmsWithSuccess(int cause, int smsSource, int token, int messageRef) { + Rlog.d(TAG, "acknowledgeSmsWithSuccess- cause: " + cause + " smsSource: " + smsSource + + " token: " + token + " messageRef: " + messageRef); + if (smsSource == InboundSmsHandler.SOURCE_INJECTED_FROM_IMS && ackViaIms()) { + acknowledgeImsSms(token, messageRef, true, null); + } else { + mCi.acknowledgeLastIncomingGsmSms(true, cause, null); + } } - private void acknowledgeSmsWithError(int cause) { - mCi.acknowledgeLastIncomingGsmSms(false, cause, null); + private void acknowledgeSmsWithError(int cause, int smsSource, int token, int messageRef) { + Rlog.d(TAG, "acknowledgeSmsWithError- cause: " + cause + " smsSource: " + smsSource + + " token: " + token + " messageRef: " + messageRef); + if (smsSource == InboundSmsHandler.SOURCE_INJECTED_FROM_IMS && ackViaIms()) { + acknowledgeImsSms(token, messageRef, false, null); + } else { + mCi.acknowledgeLastIncomingGsmSms(false, cause, null); + } } /** @@ -299,6 +336,45 @@ public class UsimDataDownloadHandler extends Handler { PhoneFactory.getPhone(mPhoneId).getSmsStats().onIncomingSmsPP(smsSource, result); } + /** + * Route resposes via ImsManager based on config + */ + private boolean ackViaIms() { + boolean isViaIms; + + try { + isViaIms = mResource.getBoolean( + com.android.internal.R.bool.config_smppsim_response_via_ims); + } catch (NotFoundException e) { + isViaIms = false; + } + + Rlog.d(TAG, "ackViaIms : " + isViaIms); + return isViaIms; + } + + /** + * Acknowledges IMS SMS and delivers the result based on the envelope or SIM saving respose + * received from SIM for SMS-PP Data. + */ + private void acknowledgeImsSms(int token, int messageRef, boolean success, byte[] pdu) { + int result = success ? ImsSmsImplBase.DELIVER_STATUS_OK : + ImsSmsImplBase.DELIVER_STATUS_ERROR_GENERIC; + Rlog.d(TAG, "sending result via acknowledgeImsSms: " + result + " token: " + token); + + try { + if (mImsManager != null) { + if (pdu != null && pdu.length > 0) { + mImsManager.acknowledgeSms(token, messageRef, result, pdu); + } else { + mImsManager.acknowledgeSms(token, messageRef, result); + } + } + } catch (ImsException e) { + Rlog.e(TAG, "Failed to acknowledgeSms(). Error: " + e.getMessage()); + } + } + /** * Handle UICC envelope response and send SMS acknowledgement. * @@ -307,35 +383,60 @@ public class UsimDataDownloadHandler extends Handler { @Override public void handleMessage(Message msg) { AsyncResult ar; + int smsSource = InboundSmsHandler.SOURCE_INJECTED_FROM_UNKNOWN; + int token = 0; + int messageRef = 0; + int[] responseInfo; switch (msg.what) { case EVENT_START_DATA_DOWNLOAD: - handleDataDownload((SmsMessage) msg.obj, msg.arg1 /* smsSource */); + Rlog.d(TAG, "EVENT_START_DATA_DOWNLOAD"); + handleDataDownload((SmsMessage) msg.obj, msg.arg1 /* smsSource */, + msg.arg2 /* token */); break; case EVENT_SEND_ENVELOPE_RESPONSE: ar = (AsyncResult) msg.obj; + responseInfo = (int[]) ar.userObj; + smsSource = responseInfo[2]; + messageRef = responseInfo[3]; + token = responseInfo[4]; + + Rlog.d(TAG, "Received EVENT_SEND_ENVELOPE_RESPONSE from source : " + smsSource); + if (ar.exception != null) { Rlog.e(TAG, "UICC Send Envelope failure, exception: " + ar.exception); + acknowledgeSmsWithError( - CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR); + CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR, + smsSource, token, messageRef); return; } - int[] dcsPid = (int[]) ar.userObj; - sendSmsAckForEnvelopeResponse((IccIoResult) ar.result, dcsPid[0], dcsPid[1]); + Rlog.d(TAG, "Successful in sending envelope response"); + sendSmsAckForEnvelopeResponse((IccIoResult) ar.result, responseInfo[0], + responseInfo[1], smsSource, token, messageRef); break; case EVENT_WRITE_SMS_COMPLETE: ar = (AsyncResult) msg.obj; + + responseInfo = (int[]) ar.userObj; + smsSource = responseInfo[0]; + messageRef = responseInfo[1]; + token = responseInfo[2]; + + Rlog.d(TAG, "Received EVENT_WRITE_SMS_COMPLETE from source : " + smsSource); + if (ar.exception == null) { Rlog.d(TAG, "Successfully wrote SMS-PP message to UICC"); - mCi.acknowledgeLastIncomingGsmSms(true, 0, null); + acknowledgeSmsWithSuccess(0, smsSource, token, messageRef); } else { Rlog.d(TAG, "Failed to write SMS-PP message to UICC", ar.exception); - mCi.acknowledgeLastIncomingGsmSms(false, - CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR, null); + acknowledgeSmsWithError( + CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR, + smsSource, token, messageRef); } break; @@ -343,4 +444,23 @@ public class UsimDataDownloadHandler extends Handler { Rlog.e(TAG, "Ignoring unexpected message, what=" + msg.what); } } + + /** + * Called when ImsManager connection is ready. ImsManager object will be used to send ACK to IMS + * which doesn't use RIL interface. + * @param imsManager object + */ + public void setImsManager(ImsManager imsManager) { + mImsManager = imsManager; + } + + /** + * Called to set mocked object of type Resources during unit testing of this file. + * @param resource object + */ + @VisibleForTesting + public void setResourcesForTest(Resources resource) { + mResource = resource; + Rlog.d(TAG, "setResourcesForTest"); + } } -- GitLab From 6cab4ec866a6b3009b0a195e3aae6fc7517d5247 Mon Sep 17 00:00:00 2001 From: Grant Menke Date: Thu, 10 Nov 2022 23:07:59 +0000 Subject: [PATCH 194/656] Refactor use of EmergencyNumberTracker. When EmergencyNumberTracker#getEmergencyNumber() is invoked in Connection.java, only one instance of EmergencyNumberTracker was being used to verify emergency numbers. This caused inaccuracies when multiple SIMs are active. This change refactors that invocation to ensure all instances of EmergencyNumberTracker are used inclusively to verify emergency numbers. Bug: 249116557 Test: atest ConnectionTest Change-Id: Ie01d059c6828a907015c992b51516db225684b9f --- .../internal/telephony/Connection.java | 62 ++++++++++++++++++- .../internal/telephony/ConnectionTest.java | 35 +++++++++++ 2 files changed, 94 insertions(+), 3 deletions(-) mode change 100755 => 100644 tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java diff --git a/src/java/com/android/internal/telephony/Connection.java b/src/java/com/android/internal/telephony/Connection.java index c60e5df900..f51bd2f89e 100644 --- a/src/java/com/android/internal/telephony/Connection.java +++ b/src/java/com/android/internal/telephony/Connection.java @@ -327,6 +327,41 @@ public abstract class Connection { /* Instance Methods */ + /** + * PhoneFactory Dependencies for testing. + */ + @VisibleForTesting + public interface PhoneFactoryProxy { + Phone getPhone(int index); + Phone getDefaultPhone(); + Phone[] getPhones(); + } + + private PhoneFactoryProxy mPhoneFactoryProxy = new PhoneFactoryProxy() { + @Override + public Phone getPhone(int index) { + return PhoneFactory.getPhone(index); + } + + @Override + public Phone getDefaultPhone() { + return PhoneFactory.getDefaultPhone(); + } + + @Override + public Phone[] getPhones() { + return PhoneFactory.getPhones(); + } + }; + + /** + * Overrides PhoneFactory dependencies for testing. + */ + @VisibleForTesting + public void setPhoneFactoryProxy(PhoneFactoryProxy proxy) { + mPhoneFactoryProxy = proxy; + } + /** * @return The telecom internal call ID associated with this connection. Only to be used for * debugging purposes. @@ -590,14 +625,35 @@ public abstract class Connection { */ public void setEmergencyCallInfo(CallTracker ct) { if (ct != null) { - Phone phone = ct.getPhone(); - if (phone != null) { - EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker(); + Phone currentPhone = ct.getPhone(); + if (currentPhone != null) { + EmergencyNumberTracker tracker = currentPhone.getEmergencyNumberTracker(); if (tracker != null) { EmergencyNumber num = tracker.getEmergencyNumber(mAddress); + Phone[] allPhones = mPhoneFactoryProxy.getPhones(); if (num != null) { mIsEmergencyCall = true; mEmergencyNumberInfo = num; + } else if (allPhones.length > 1) { + // If there are multiple active SIMs, check all instances: + boolean found = false; + for (Phone phone : allPhones) { + // If the current iteration was already checked, skip: + if (phone.getPhoneId() == currentPhone.getPhoneId()){ + continue; + } + num = phone.getEmergencyNumberTracker() + .getEmergencyNumber(mAddress); + if (num != null){ + found = true; + mIsEmergencyCall = true; + mEmergencyNumberInfo = num; + break; + } + } + if (!found){ + Rlog.e(TAG, "setEmergencyCallInfo: emergency number is null"); + } } else { Rlog.e(TAG, "setEmergencyCallInfo: emergency number is null"); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java old mode 100755 new mode 100644 index d1e643e2b5..39491613a1 --- a/tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java @@ -20,11 +20,14 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import android.os.Handler; import android.os.Looper; +import com.android.internal.telephony.emergency.EmergencyNumberTracker; import org.junit.After; import org.junit.Before; @@ -39,6 +42,10 @@ public class ConnectionTest extends TelephonyTest { // Mocked classes protected Call mCall; + protected GsmCdmaPhone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. + protected EmergencyNumberTracker mEmergencyNumberTracker2; + protected Connection.PhoneFactoryProxy mPhoneFactoryProxy; + protected Connection mTestConnection; private class TestConnection extends Connection { @@ -117,7 +124,16 @@ public class ConnectionTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mCall = mock(Call.class); doReturn(mPhone).when(mCall).getPhone(); + doReturn(mPhone).when(mCT).getPhone(); replaceInstance(Handler.class, "mLooper", mCT, Looper.getMainLooper()); + + mPhone2 = mock(GsmCdmaPhone.class); + mEmergencyNumberTracker2 = mock(EmergencyNumberTracker.class); + doReturn(mEmergencyNumberTracker2).when(mPhone2).getEmergencyNumberTracker(); + + mTestConnection = new TestConnection(TEST_PHONE_TYPE); + mPhoneFactoryProxy = mock(Connection.PhoneFactoryProxy.class); + mTestConnection.setPhoneFactoryProxy(mPhoneFactoryProxy); } @After @@ -156,5 +172,24 @@ public class ConnectionTest extends TelephonyTest { assertTrue(connection.hasKnownUserIntentEmergency()); } + @Test + public void testSetEmergencyCallInfo() { + //Replicate Dual-SIM: + Phone [] phones = {mPhone, mPhone2}; + when(mPhoneFactoryProxy.getPhones()).thenReturn(phones); + doReturn(1).when(mPhone).getPhoneId(); + doReturn(2).when(mPhone2).getPhoneId(); + + //Replicate behavior when a number is an emergency number + // on the secondary SIM but not on the default SIM: + when(mPhone.getEmergencyNumberTracker().getEmergencyNumber(any())).thenReturn(null); + when(mEmergencyNumberTracker2.getEmergencyNumber(any())) + .thenReturn(getTestEmergencyNumber()); + + //Ensure the connection is considered as an emergency call: + mTestConnection.setEmergencyCallInfo(mCT); + assertTrue(mTestConnection.isEmergencyCall()); + } + // TODO Verify more methods in Connection } -- GitLab From f88aad54feaa6b1135b037d6777aea9bdfcffc20 Mon Sep 17 00:00:00 2001 From: Grant Menke Date: Thu, 17 Nov 2022 00:05:12 +0000 Subject: [PATCH 195/656] Refactor use of ENT in IccSmsInterfaceManager. When EmergencyNumberTracker#getEmergencyNumber() is invoked in IccSmsInterfaceManager.java, only one instance of EmergencyNumberTracker was being used to verify emergency numbers. This caused inaccuracies when multiple SIMs are active. This change refactors that invocation to ensure all instances of EmergencyNumberTracker are used inclusively to verify emergency numbers. Bug: 249116557 Test: atest IccSmsInterfaceManagerTest Change-Id: Ie775d8d1d192e6e5d677722adbd92c23ebaaed10 --- .../telephony/IccSmsInterfaceManager.java | 53 ++++++++++++++++++- .../telephony/IccSmsInterfaceManagerTest.java | 31 +++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java index 1a5d5b31cf..cdcf344223 100644 --- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java +++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java @@ -176,6 +176,41 @@ public class IccSmsInterfaceManager { mSmsPermissions = smsPermissions; } + /** + * PhoneFactory Dependencies for testing. + */ + @VisibleForTesting + public interface PhoneFactoryProxy { + Phone getPhone(int index); + Phone getDefaultPhone(); + Phone[] getPhones(); + } + + private PhoneFactoryProxy mPhoneFactoryProxy = new PhoneFactoryProxy() { + @Override + public Phone getPhone(int index) { + return PhoneFactory.getPhone(index); + } + + @Override + public Phone getDefaultPhone() { + return PhoneFactory.getDefaultPhone(); + } + + @Override + public Phone[] getPhones() { + return PhoneFactory.getPhones(); + } + }; + + /** + * Overrides PhoneFactory dependencies for testing. + */ + @VisibleForTesting + public void setPhoneFactoryProxy(PhoneFactoryProxy proxy) { + mPhoneFactoryProxy = proxy; + } + private void enforceNotOnHandlerThread(String methodName) { if (Looper.myLooper() == mHandler.getLooper()) { throw new RuntimeException("This method " + methodName + " will deadlock if called from" @@ -1463,11 +1498,27 @@ public class IccSmsInterfaceManager { return null; } - private void notifyIfOutgoingEmergencySms(String destAddr) { + @VisibleForTesting + public void notifyIfOutgoingEmergencySms(String destAddr) { + Phone[] allPhones = mPhoneFactoryProxy.getPhones(); EmergencyNumber emergencyNumber = mPhone.getEmergencyNumberTracker().getEmergencyNumber( destAddr); if (emergencyNumber != null) { mPhone.notifyOutgoingEmergencySms(emergencyNumber); + } else if (allPhones.length > 1) { + // If there are multiple active SIMs, check all instances: + for (Phone phone : allPhones) { + // If the current iteration was already checked, skip: + if (phone.getPhoneId() == mPhone.getPhoneId()) { + continue; + } + emergencyNumber = phone.getEmergencyNumberTracker() + .getEmergencyNumber(destAddr); + if (emergencyNumber != null) { + mPhone.notifyOutgoingEmergencySms(emergencyNumber); + break; + } + } } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/IccSmsInterfaceManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/IccSmsInterfaceManagerTest.java index 67d6e5c360..dc24683405 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/IccSmsInterfaceManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/IccSmsInterfaceManagerTest.java @@ -29,10 +29,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.android.internal.telephony.emergency.EmergencyNumberTracker; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -50,6 +53,9 @@ public class IccSmsInterfaceManagerTest extends TelephonyTest { // Mocked classes private SmsPermissions mMockSmsPermissions; + protected GsmCdmaPhone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. + protected EmergencyNumberTracker mEmergencyNumberTracker2; + protected IccSmsInterfaceManager.PhoneFactoryProxy mPhoneFactoryProxy; @Before public void setUp() throws Exception { @@ -57,6 +63,13 @@ public class IccSmsInterfaceManagerTest extends TelephonyTest { mMockSmsPermissions = mock(SmsPermissions.class); mIccSmsInterfaceManager = new IccSmsInterfaceManager(mPhone, mContext, mAppOpsManager, mSmsDispatchersController, mMockSmsPermissions); + + mPhoneFactoryProxy = mock(IccSmsInterfaceManager.PhoneFactoryProxy.class); + mIccSmsInterfaceManager.setPhoneFactoryProxy(mPhoneFactoryProxy); + + mPhone2 = mock(GsmCdmaPhone.class); + mEmergencyNumberTracker2 = mock(EmergencyNumberTracker.class); + doReturn(mEmergencyNumberTracker2).when(mPhone2).getEmergencyNumberTracker(); } @After @@ -144,4 +157,22 @@ public class IccSmsInterfaceManagerTest extends TelephonyTest { fail("getSmscLatch.await interrupted"); } } + + @Test + public void testNotifyIfOutgoingEmergencySmsWithDualSim() { + //Replicate Dual-SIM: + Phone [] phones = {mPhone, mPhone2}; + when(mPhoneFactoryProxy.getPhones()).thenReturn(phones); + doReturn(1).when(mPhone).getPhoneId(); + doReturn(2).when(mPhone2).getPhoneId(); + + //Replicate behavior when a number is an emergency number + // on the secondary SIM but not on the default SIM: + when(mPhone.getEmergencyNumberTracker().getEmergencyNumber(any())).thenReturn(null); + when(mEmergencyNumberTracker2.getEmergencyNumber(any())) + .thenReturn(getTestEmergencyNumber()); + + mIccSmsInterfaceManager.notifyIfOutgoingEmergencySms("1234"); + verify(mEmergencyNumberTracker2).getEmergencyNumber("1234"); + } } -- GitLab From 959c128131cea3b2b011e063d754447ddba8196b Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 19 Nov 2022 22:24:47 -0800 Subject: [PATCH 196/656] Add getSubscriptionId API The old getSubId or getSubscriptionIds return multiple sub ids per slot index, which is not possible in today's implementation because the slot index here refers to the logical slot index, which is also known as phone id, or the logical modem index. In today's telephony, one logical phone can only have one subscription at one time, so does the modem. Bug: 239607619 Test: Manual Change-Id: I6f400f3a520bdeaf72bcb232c0472cd2f6f255a8 --- .../internal/telephony/RadioResponse.java | 7 +- .../internal/telephony/WapPushOverSms.java | 7 +- .../internal/telephony/ims/ImsResolver.java | 10 +- .../internal/telephony/metrics/RcsStats.java | 7 +- .../SubscriptionManagerService.java | 95 ++++++++++++++++++- 5 files changed, 105 insertions(+), 21 deletions(-) diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java index 5265be5ac9..0bc29583fb 100644 --- a/src/java/com/android/internal/telephony/RadioResponse.java +++ b/src/java/com/android/internal/telephony/RadioResponse.java @@ -2532,10 +2532,9 @@ public class RadioResponse extends IRadioResponse.Stub { ArrayList ret = new ArrayList(); NeighboringCellInfo cell; - int[] subId = SubscriptionManager.getSubId(mRil.mPhoneId); - int radioType = - ((TelephonyManager) mRil.mContext.getSystemService( - Context.TELEPHONY_SERVICE)).getDataNetworkType(subId[0]); + int radioType = ((TelephonyManager) mRil.mContext.getSystemService( + Context.TELEPHONY_SERVICE)).getDataNetworkType( + SubscriptionManager.getSubscriptionId(mRil.mPhoneId)); if (radioType != TelephonyManager.NETWORK_TYPE_UNKNOWN) { for (int i = 0; i < cells.size(); i++) { diff --git a/src/java/com/android/internal/telephony/WapPushOverSms.java b/src/java/com/android/internal/telephony/WapPushOverSms.java index d6f69e203e..08c7acdf07 100644 --- a/src/java/com/android/internal/telephony/WapPushOverSms.java +++ b/src/java/com/android/internal/telephony/WapPushOverSms.java @@ -245,9 +245,10 @@ public class WapPushOverSms implements ServiceConnection { System.arraycopy(pdu, dataIndex, intentData, 0, intentData.length); } - int[] subIds = SubscriptionManager.getSubId(phoneId); - int subId = (subIds != null) && (subIds.length > 0) ? subIds[0] - : SmsManager.getDefaultSmsSubscriptionId(); + int subId = SubscriptionManager.getSubscriptionId(phoneId); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + subId = SmsManager.getDefaultSmsSubscriptionId(); + } // Continue if PDU parsing fails: the default messaging app may successfully parse the // same PDU. diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java index d455d60a90..f5f3ce7d33 100644 --- a/src/java/com/android/internal/telephony/ims/ImsResolver.java +++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java @@ -312,7 +312,8 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal @VisibleForTesting public interface SubscriptionManagerProxy { /** - * Mock-able interface for {@link SubscriptionManager#getSubId(int)} used for testing. + * Mock-able interface for {@link SubscriptionManager#getSubscriptionId(int)} used for + * testing. */ int getSubId(int slotId); /** @@ -346,12 +347,7 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal private SubscriptionManagerProxy mSubscriptionManagerProxy = new SubscriptionManagerProxy() { @Override public int getSubId(int slotId) { - int[] subIds = SubscriptionManager.getSubId(slotId); - if (subIds != null) { - // This is done in all other places getSubId is used. - return subIds[0]; - } - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + return SubscriptionManager.getSubscriptionId(slotId); } @Override diff --git a/src/java/com/android/internal/telephony/metrics/RcsStats.java b/src/java/com/android/internal/telephony/metrics/RcsStats.java index 8751d82bb1..8d24defb2b 100644 --- a/src/java/com/android/internal/telephony/metrics/RcsStats.java +++ b/src/java/com/android/internal/telephony/metrics/RcsStats.java @@ -1576,12 +1576,7 @@ public class RcsStats { @VisibleForTesting protected int getSubId(int slotId) { - final int[] subIds = SubscriptionManager.getSubId(slotId); - int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - if (subIds != null && subIds.length >= 1) { - subId = subIds[0]; - } - return subId; + return SubscriptionManager.getSubscriptionId(slotId); } /** Get a enum value from pre-defined feature tag name list */ diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 39727997ad..ac6fe7a9ae 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -39,6 +39,9 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * The subscription manager service is the backend service of {@link SubscriptionManager}. @@ -59,6 +62,80 @@ public class SubscriptionManagerService extends ISub.Stub { /** The subscription database manager. */ private final SubscriptionDatabaseManager mSubscriptionDatabaseManager; + /** + * Watched slot index to sub id map. + */ + private static class WatchedSlotIndexToSubId { + private final Map mSlotIndexToSubId = + new ConcurrentHashMap<>(); + + public void clear() { + mSlotIndexToSubId.clear(); + SubscriptionManager.invalidateDefaultSubIdCaches(); + SubscriptionManager.invalidateSlotIndexCaches(); + } + + public Set> entrySet() { + return mSlotIndexToSubId.entrySet(); + } + + // Force all updates to data structure through wrapper. + public int get(int slotIndex) { + return mSlotIndexToSubId.getOrDefault(slotIndex, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + + public void put(int slotIndex, int value) { + mSlotIndexToSubId.put(slotIndex, value); + SubscriptionManager.invalidateDefaultSubIdCaches(); + SubscriptionManager.invalidateSlotIndexCaches(); + } + + public void remove(int slotIndex) { + mSlotIndexToSubId.remove(slotIndex); + SubscriptionManager.invalidateDefaultSubIdCaches(); + SubscriptionManager.invalidateSlotIndexCaches(); + } + + public int size() { + return mSlotIndexToSubId.size(); + } + } + + /** + * Watched integer. + */ + public static class WatchedInt { + private int mValue; + + /** + * Constructor. + * + * @param initialValue The initial value. + */ + public WatchedInt(int initialValue) { + mValue = initialValue; + } + + /** + * @return The value. + */ + public int get() { + return mValue; + } + + /** + * Set the value. + * + * @param newValue The new value. + */ + public void set(int newValue) { + mValue = newValue; + } + } + + private final WatchedSlotIndexToSubId mSlotIndexToSubId = new WatchedSlotIndexToSubId(); + /** * The constructor * @@ -401,9 +478,25 @@ public class SubscriptionManagerService extends ISub.Stub { return 0; } + @Override + public int getSubId(int slotIndex) { + if (slotIndex == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) { + slotIndex = getSlotIndex(getDefaultSubId()); + } + + // Check that we have a valid slotIndex or the slotIndex is for a remote SIM (remote SIM + // uses special slot index that may be invalid otherwise) + if (!SubscriptionManager.isValidSlotIndex(slotIndex) + && slotIndex != SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB) { + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + return mSlotIndexToSubId.get(slotIndex); + } + @Override public int[] getSubIds(int slotIndex) { - return null; + return new int[]{getSubId(slotIndex)}; } @Override -- GitLab From 74eaf2cc406c6b4e94b8d9b06e533277a10b1531 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 20 Nov 2022 00:17:37 -0800 Subject: [PATCH 197/656] Notify subscription info changed Notify clients when subscription info changes. Bug: 239607619 Test: Manual Change-Id: I7c3e133cb0b00a0118583ca67e5b54239f28ea7d --- .../telephony/MultiSimSettingController.java | 14 ++- .../internal/telephony/PhoneFactory.java | 3 +- .../SubscriptionDatabaseManager.java | 88 +++++++++++++++---- .../SubscriptionManagerService.java | 40 ++++++++- .../MultiSimSettingControllerTest.java | 2 +- .../SubscriptionInfoUpdaterTest.java | 2 +- .../telephony/TelephonyRegistryTest.java | 2 +- .../SubscriptionDatabaseManagerTest.java | 75 +++++++++++++++- 8 files changed, 193 insertions(+), 33 deletions(-) diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index 0a0e265b15..e514055fab 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -439,14 +439,12 @@ public class MultiSimSettingController extends Handler { // being specified in it. So here we do additional check to make sur we don't miss the // subId. if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - int[] subIds = mSubController.getSubIds(phoneId); - if (!ArrayUtils.isEmpty(subIds)) { - CarrierConfigManager cm = (CarrierConfigManager) mContext.getSystemService( - mContext.CARRIER_CONFIG_SERVICE); - if (cm != null && cm.getConfigForSubId(subIds[0]) != null) { - loge("onCarrierConfigChanged with invalid subId while subd " - + subIds[0] + " is active and its config is loaded"); - subId = subIds[0]; + subId = mSubController.getSubId(phoneId); + if (SubscriptionManager.isValidSubscriptionId(subId)) { + CarrierConfigManager cm = mContext.getSystemService(CarrierConfigManager.class); + if (cm != null && cm.getConfigForSubId(subId) != null) { + loge("onCarrierConfigChanged with invalid subId while subId " + + subId + " is active and its config is loaded"); } } } diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index e642314fda..75c4740293 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -201,7 +201,8 @@ public class PhoneFactory { if (sContext.getResources().getBoolean( com.android.internal.R.bool.config_using_subscription_manager_service)) { Rlog.i(LOG_TAG, "Creating SubscriptionManagerService"); - sSubscriptionManagerService = new SubscriptionManagerService(context); + sSubscriptionManagerService = new SubscriptionManagerService(context, + Looper.myLooper()); } else { Rlog.i(LOG_TAG, "Creating SubscriptionController"); TelephonyComponentFactory.getInstance().inject(SubscriptionController.class diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 3c6449539a..3c9ece77e0 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.subscription; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentValues; @@ -41,6 +42,7 @@ import android.util.IndentingPrintWriter; import android.util.LocalLog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.uicc.UiccController; import com.android.telephony.Rlog; @@ -50,6 +52,7 @@ import java.util.AbstractMap; import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.BiFunction; @@ -78,6 +81,10 @@ public class SubscriptionDatabaseManager extends Handler { @NonNull private final Context mContext; + /** The callback used for passing events back to {@link SubscriptionManagerService}. */ + @NonNull + private final SubscriptionDatabaseManagerCallback mCallback; + /** Telephony manager */ private final TelephonyManager mTelephonyManager; @@ -258,15 +265,59 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal::getUserId) ); + /** + * This is the callback used for listening events from {@link SubscriptionDatabaseManager}. + */ + public abstract static class SubscriptionDatabaseManagerCallback { + /** The executor of the callback. */ + private final @NonNull Executor mExecutor; + + /** + * Constructor + * + * @param executor The executor of the callback. + */ + public SubscriptionDatabaseManagerCallback(@NonNull @CallbackExecutor Executor executor) { + mExecutor = executor; + } + + /** + * @return The executor of the callback. + */ + @VisibleForTesting + public @NonNull Executor getExecutor() { + return mExecutor; + } + + /** + * Invoke the callback from executor. + * + * @param runnable The callback method to invoke. + */ + public void invokeFromExecutor(@NonNull Runnable runnable) { + mExecutor.execute(runnable); + } + + /** + * Called when subscription changed. + * + * @param subId The subscription id. + */ + public abstract void onSubscriptionChanged(int subId); + } + /** * The constructor. * * @param context The context. * @param looper Looper for the handler. + * @param callback Subscription database callback. */ - public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper) { + public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper, + @NonNull SubscriptionDatabaseManagerCallback callback) { super(looper); mContext = context; + mCallback = callback; mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mUiccController = UiccController.getInstance(); loadFromDatabase(); @@ -382,6 +433,8 @@ public class SubscriptionDatabaseManager extends Handler { } finally { mReadWriteLock.writeLock().unlock(); } + + mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); return subId; } @@ -425,20 +478,20 @@ public class SubscriptionDatabaseManager extends Handler { BiFunction builderSetMethod) { ContentValues contentValues = new ContentValues(); - SubscriptionInfoInternal subInfoCache; + SubscriptionInfoInternal oldSubInfo; // Grab the write lock so no other threads can read or write the cache. mReadWriteLock.writeLock().lock(); try { - subInfoCache = mAllSubscriptionInfoInternalCache.get(subId); - if (subInfoCache != null) { + oldSubInfo = mAllSubscriptionInfoInternalCache.get(subId); + if (oldSubInfo != null) { // Check if the new value is different from the old value in the cache. - if (!Objects.equals(getSubscriptionInfoFieldByColumnName(subInfoCache, columnName), + if (!Objects.equals(getSubscriptionInfoFieldByColumnName(oldSubInfo, columnName), newValue)) { // If the value is different, then we need to update the cache. Since all fields // in SubscriptionInfo is final, so we need to create a new SubscriptionInfo. SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal - .Builder(subInfoCache); + .Builder(oldSubInfo); // Apply the new value to the builder. This line is equivalent to // builder.setXxxxxx(newValue); @@ -446,6 +499,7 @@ public class SubscriptionDatabaseManager extends Handler { // Update the subscription database cache. mAllSubscriptionInfoInternalCache.put(subId, builder.build()); + mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); // Prepare the content value for update. contentValues.putObject(columnName, newValue); @@ -461,26 +515,28 @@ public class SubscriptionDatabaseManager extends Handler { } /** - * Update the database with the {@link SubscriptionInfo}, and also update the cache. + * Update the database with the {@link SubscriptionInfoInternal}, and also update the cache. * - * @param subInfo The new {@link SubscriptionInfo}. + * @param newSubInfo The new {@link SubscriptionInfoInternal}. */ - public void updateSubscription(@NonNull SubscriptionInfoInternal subInfo) { - Objects.requireNonNull(subInfo); + public void updateSubscription(@NonNull SubscriptionInfoInternal newSubInfo) { + Objects.requireNonNull(newSubInfo); // Grab the write lock so no other threads can read or write the cache. mReadWriteLock.writeLock().lock(); try { - int subId = subInfo.getSubscriptionId(); - SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get( - subInfo.getSubscriptionId()); - if (subInfoCache == null) { + int subId = newSubInfo.getSubscriptionId(); + SubscriptionInfoInternal oldSubInfo = mAllSubscriptionInfoInternalCache.get( + newSubInfo.getSubscriptionId()); + if (oldSubInfo == null) { throw new RuntimeException("updateSubscription: subscription does not exist. subId=" + subId); } - mAllSubscriptionInfoInternalCache.put(subId, subInfo); + if (oldSubInfo.equals(newSubInfo)) return; + mAllSubscriptionInfoInternalCache.put(subId, newSubInfo); + mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); // Writing into the database is slow. So do this asynchronously. - updateDatabaseAsync(subId, createDeltaContentValues(subInfoCache, subInfo)); + updateDatabaseAsync(subId, createDeltaContentValues(oldSubInfo, newSubInfo)); } finally { mReadWriteLock.writeLock().unlock(); } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index ac6fe7a9ae..0131c982ab 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -19,7 +19,9 @@ package com.android.internal.telephony.subscription; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.os.Handler; import android.os.HandlerThread; +import android.os.Looper; import android.os.ParcelUuid; import android.os.TelephonyServiceManager; import android.os.UserHandle; @@ -28,11 +30,14 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.TelephonyFrameworkInitializer; +import android.telephony.TelephonyRegistryManager; import android.util.IndentingPrintWriter; import android.util.LocalLog; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; +import com.android.internal.telephony.MultiSimSettingController; +import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -56,6 +61,9 @@ public class SubscriptionManagerService extends ISub.Stub { /** The context */ private final Context mContext; + /** The main handler of subscription manager service. */ + private final Handler mHandler; + /** Local log for most important debug messages. */ private final LocalLog mLocalLog = new LocalLog(128); @@ -140,9 +148,11 @@ public class SubscriptionManagerService extends ISub.Stub { * The constructor * * @param context The context + * @param looper The looper for the handler. */ - public SubscriptionManagerService(@NonNull Context context) { + public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper) { mContext = context; + mHandler = new Handler(looper); TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = TelephonyFrameworkInitializer .getTelephonyServiceManager() @@ -154,7 +164,33 @@ public class SubscriptionManagerService extends ISub.Stub { HandlerThread handlerThread = new HandlerThread(LOG_TAG); handlerThread.start(); mSubscriptionDatabaseManager = new SubscriptionDatabaseManager(context, - handlerThread.getLooper()); + handlerThread.getLooper(), new SubscriptionDatabaseManagerCallback(mHandler::post) { + /** + * Called when subscription changed. + * + * @param subId The subscription id. + */ + @Override + public void onSubscriptionChanged(int subId) { + MultiSimSettingController.getInstance().notifySubscriptionInfoChanged(); + + TelephonyRegistryManager telephonyRegistryManager = + mContext.getSystemService(TelephonyRegistryManager.class); + if (telephonyRegistryManager != null) { + telephonyRegistryManager.notifySubscriptionInfoChanged(); + } + + SubscriptionInfoInternal subInfo = + mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subId); + if (subInfo != null && subInfo.isOpportunistic() + && telephonyRegistryManager != null) { + telephonyRegistryManager.notifyOpportunisticSubscriptionInfoChanged(); + } + + // TODO: Call TelephonyMetrics.updateActiveSubscriptionInfoList when active + // subscription changes. + } + }); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index 4fe748caea..8a2730938e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -848,7 +848,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Still notify carrier config without specifying subId2, but this time subController // and CarrierConfigManager have subId 2 active and ready. - doReturn(new int[] {2}).when(mSubControllerMock).getSubIds(1); + doReturn(2).when(mSubControllerMock).getSubId(1); CarrierConfigManager cm = (CarrierConfigManager) mContext.getSystemService( mContext.CARRIER_CONFIG_SERVICE); doReturn(new PersistableBundle()).when(cm).getConfigForSubId(2); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java index ff217b0a0c..868b53a8cc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java @@ -151,7 +151,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { }); doReturn(mUserInfo).when(mIActivityManager).getCurrentUser(); - doReturn(new int[]{FAKE_SUB_ID_1}).when(mSubscriptionController).getSubIds(0); + doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(0); doReturn(new int[]{FAKE_SUB_ID_1}).when(mSubscriptionManager).getActiveSubscriptionIdList(); ((MockContentResolver) mContext.getContentResolver()).addProvider( SubscriptionManager.CONTENT_URI.getAuthority(), diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java index 21002e140d..0a5a2ea7b1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java @@ -1165,7 +1165,7 @@ public class TelephonyRegistryTest extends TelephonyTest { final int subId = 1; // Return a slotIndex / phoneId of 0 for subId 1. - doReturn(new int[] {subId}).when(mSubscriptionController).getSubIds(phoneId); + doReturn(subId).when(mSubscriptionController).getSubId(phoneId); doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(subId); doReturn(phoneId).when(mMockSubInfo).getSimSlotIndex(); mServiceManagerMockedServices.put("isub", mSubscriptionController); 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 f4db542bfe..028a6537c5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -19,8 +19,12 @@ package com.android.internal.telephony.subscription; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.annotation.NonNull; import android.content.ContentUris; @@ -39,11 +43,13 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -128,7 +134,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setWifiCallingEnabled(1) .setWifiCallingMode(ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED) .setWifiCallingModeForRoaming(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED) - .setWifiCallingModeForRoaming(1) + .setWifiCallingEnabledForRoaming(1) .setOpportunistic(0) .setGroupUuid(FAKE_UUID1) .setCountryIso(FAKE_COUNTRY_CODE1) @@ -182,7 +188,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setWifiCallingEnabled(0) .setWifiCallingMode(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED) .setWifiCallingModeForRoaming(ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED) - .setWifiCallingModeForRoaming(0) + .setWifiCallingEnabledForRoaming(0) .setOpportunistic(1) .setGroupUuid(FAKE_UUID2) .setCountryIso(FAKE_COUNTRY_CODE2) @@ -215,6 +221,9 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { private final SubscriptionProvider mSubscriptionProvider = new SubscriptionProvider(); + //mock + private SubscriptionDatabaseManagerCallback mSubscriptionDatabaseManagerCallback; + private static class SubscriptionProvider extends MockContentProvider { private final List mDatabase = new ArrayList<>(); @@ -308,11 +317,19 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionDatabaseManagerTest +Setup!"); super.setUp(getClass().getSimpleName()); + mSubscriptionDatabaseManagerCallback = + Mockito.mock(SubscriptionDatabaseManagerCallback.class); + doAnswer(invocation -> { + ((Runnable) invocation.getArguments()[0]).run(); + return null; + }).when(mSubscriptionDatabaseManagerCallback).invokeFromExecutor(any(Runnable.class)); + ((MockContentResolver) mContext.getContentResolver()).addProvider( Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); doReturn(1).when(mUiccController).convertToPublicCardId(eq(FAKE_ICCID1)); doReturn(2).when(mUiccController).convertToPublicCardId(eq(FAKE_ICCID2)); - mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper()); + mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper(), + mSubscriptionDatabaseManagerCallback); logd("SubscriptionDatabaseManagerTest -Setup!"); } @@ -375,8 +392,14 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { public void testInsertSubscription() throws Exception { assertThat(insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1).getSubscriptionId()) .isEqualTo(1); + processAllMessages(); + verify(mSubscriptionDatabaseManagerCallback).onSubscriptionChanged(eq(1)); + Mockito.clearInvocations(mSubscriptionDatabaseManagerCallback); + assertThat(insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO2).getSubscriptionId()) .isEqualTo(2); + processAllMessages(); + verify(mSubscriptionDatabaseManagerCallback).onSubscriptionChanged(eq(2)); } @Test @@ -390,6 +413,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { mDatabaseManagerUT.updateSubscription(subInfo); processAllMessages(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -400,6 +424,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setIccId(FAKE_ICCID2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -412,6 +437,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setSimSlotIndex( SubscriptionManager.INVALID_SIM_SLOT_INDEX).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -423,6 +449,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setDisplayName( FAKE_CARRIER_NAME2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -434,6 +461,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setCarrierName( FAKE_CARRIER_NAME2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -445,6 +473,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setCarrierName( FAKE_CARRIER_NAME2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -455,6 +484,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setIconTint(FAKE_COLOR2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -466,6 +496,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setNumber(FAKE_PHONE_NUMBER2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -478,6 +509,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setDataRoaming(SubscriptionManager.DATA_ROAMING_DISABLE).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -488,6 +520,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setMcc(FAKE_MCC2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -498,6 +531,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setMnc(FAKE_MNC2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -508,6 +542,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setEhplmns(FAKE_EHPLMNS2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -518,6 +553,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setHplmns(FAKE_HPLMNS2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -528,6 +564,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setEmbedded(0).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -541,6 +578,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setCardId(2) .build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -553,6 +591,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setNativeAccessRules(FAKE_NATIVE_ACCESS_RULES2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -565,6 +604,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setCarrierConfigAccessRules(FAKE_CARRIER_CONFIG_ACCESS_RULES2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -575,6 +615,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setRemovableEmbedded(1).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -585,6 +626,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setEnhanced4GModeEnabled(0).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -595,6 +637,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setVideoTelephonyEnabled(0).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -605,6 +648,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setWifiCallingEnabled(0).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -617,6 +661,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setWifiCallingMode(ImsMmTelManager.WIFI_MODE_WIFI_ONLY).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -629,6 +674,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setWifiCallingModeForRoaming(ImsMmTelManager.WIFI_MODE_WIFI_ONLY).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -640,6 +686,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setWifiCallingEnabledForRoaming(0).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -650,6 +697,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setOpportunistic(1).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -660,6 +708,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setGroupUuid(FAKE_UUID2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -671,6 +720,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setCountryIso(FAKE_COUNTRY_CODE2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -682,6 +732,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setCarrierId(FAKE_CARRIER_ID2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -694,6 +745,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setProfileClass(SubscriptionManager.PROFILE_CLASS_TESTING).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -706,6 +758,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setType(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -717,6 +770,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setGroupOwner(FAKE_OWNER2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -729,6 +783,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setEnabledMobileDataPolicies(FAKE_MOBILE_DATA_POLICY2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -740,6 +795,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setImsi(FAKE_IMSI2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -751,6 +807,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setUiccApplicationsEnabled(0).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -762,6 +819,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setRcsUceEnabled(0).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -773,6 +831,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setCrossSimCallingEnabled(0).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -784,6 +843,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setRcsConfig(FAKE_RCS_CONFIG2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -796,6 +856,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setAllowedNetworkTypesForReasons(FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -809,6 +870,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setDeviceToDeviceStatusSharingPreference( SubscriptionManager.D2D_SHARING_DISABLED).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -820,6 +882,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setNrAdvancedCallingEnabled(0).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -831,6 +894,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setNumberFromCarrier(FAKE_PHONE_NUMBER2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -842,6 +906,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setNumberFromIms(FAKE_PHONE_NUMBER2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -853,6 +918,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setPortIndex(1).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -865,6 +931,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setUsageSetting(SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -877,6 +944,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setLastUsedTPMessageReference(FAKE_TP_MESSAGE_REFERENCE2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test @@ -888,5 +956,6 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setUserId(FAKE_USER_ID2).build(); verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } } -- GitLab From ca549020944f35baa8610a0299b17d68267bf693 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 20 Nov 2022 13:56:11 -0800 Subject: [PATCH 198/656] Removed unused method Bug: 239607619 Test: atest FrameworksTelephonyTests Change-Id: I3f250631cebdbce16c8f6fa343b740995aeca1df --- .../telephony/SubscriptionController.java | 11 --- .../SubscriptionManagerService.java | 13 ---- .../telephony/SubscriptionControllerTest.java | 67 +++++++++++++------ 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 1b9129a76a..c11c23acde 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -1306,17 +1306,6 @@ public class SubscriptionController extends ISub.Stub { mTelephonyManager.getCardIdForDefaultEuicc(), callback); } - /** - * Add a new SubInfoRecord to subinfo database if needed - * @param iccId the IccId of the SIM card - * @param slotIndex the slot which the SIM is inserted - * @return 0 if success, < 0 on error. - */ - @Override - public int addSubInfoRecord(String iccId, int slotIndex) { - return addSubInfo(iccId, null, slotIndex, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - } - /** * Add a new subscription info record, if needed. * @param uniqueId This is the unique identifier for the subscription within the specific diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 39727997ad..21b5df1137 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -216,19 +216,6 @@ public class SubscriptionManagerService extends ISub.Stub { } - /** - * Add a new subscription record to subscription database if needed. - * - * @param iccId the IccId of the SIM card - * @param slotIndex the slot which the SIM is inserted - * - * @return 0 if success, negative if failed. - */ - @Override - public int addSubInfoRecord(@NonNull String iccId, int slotIndex) { - return 0; - } - /** * Add a new subscription info record, if needed. * diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index 5b8bdaaec9..0bb6eb243f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -19,6 +19,7 @@ import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_REMOTE_SE import static com.android.internal.telephony.SubscriptionController.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID; import static com.android.internal.telephony.uicc.IccCardStatus.CardState.CARDSTATE_PRESENT; + import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; @@ -196,7 +197,8 @@ public class SubscriptionControllerTest extends TelephonyTest { int slotID = 0; //insert one Subscription Info - mSubscriptionControllerUT.addSubInfoRecord("test", slotID); + mSubscriptionControllerUT.addSubInfo("test", null, slotID, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); //verify there is one sim assertEquals(1, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage, @@ -760,7 +762,8 @@ public class SubscriptionControllerTest extends TelephonyTest { .notifyOpportunisticSubscriptionInfoChanged(); testInsertSim(); - mSubscriptionControllerUT.addSubInfoRecord("test2", 0); + mSubscriptionControllerUT.addSubInfo("test2", null, 0, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // Neither sub1 or sub2 are opportunistic. So getOpportunisticSubscriptions // should return empty list and no callback triggered. @@ -965,7 +968,9 @@ public class SubscriptionControllerTest extends TelephonyTest { @SmallTest public void testSetSubscriptionGroupWithModifyPermission() throws Exception { testInsertSim(); - mSubscriptionControllerUT.addSubInfoRecord("test2", 0); + mSubscriptionControllerUT.addSubInfo("test2", null, 0, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); @@ -1028,7 +1033,9 @@ public class SubscriptionControllerTest extends TelephonyTest { testInsertSim(); // Adding a second profile and mark as embedded. // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfoRecord("test2", 1); + mSubscriptionControllerUT.addSubInfo("test2", null, 1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + ContentValues values = new ContentValues(); values.put(SubscriptionManager.IS_EMBEDDED, 1); mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, @@ -1070,7 +1077,9 @@ public class SubscriptionControllerTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission( android.Manifest.permission.MODIFY_PHONE_STATE); // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfoRecord("test3", 1); + mSubscriptionControllerUT.addSubInfo("test3", null, 1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + mContextFixture.removeCallingOrSelfPermission( android.Manifest.permission.MODIFY_PHONE_STATE); // As sub2 is inactive, it will checks carrier privilege against access rules in the db. @@ -1090,7 +1099,9 @@ public class SubscriptionControllerTest extends TelephonyTest { testInsertSim(); // Adding a second profile and mark as embedded. // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfoRecord("test2", 1); + mSubscriptionControllerUT.addSubInfo("test2", null, 1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + ContentValues values = new ContentValues(); values.put(SubscriptionManager.IS_EMBEDDED, 1); mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, @@ -1143,7 +1154,9 @@ public class SubscriptionControllerTest extends TelephonyTest { testInsertSim(); // Adding a second profile and mark as embedded. // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfoRecord("test2", 1); + mSubscriptionControllerUT.addSubInfo("test2", null, 1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + ContentValues values = new ContentValues(); values.put(SubscriptionManager.IS_EMBEDDED, 1); mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, @@ -1214,7 +1227,8 @@ public class SubscriptionControllerTest extends TelephonyTest { testInsertSim(); // Adding a second profile and mark as embedded. - mSubscriptionControllerUT.addSubInfoRecord("test2", 0); + mSubscriptionControllerUT.addSubInfo("test2", null, 0, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); ContentValues values = new ContentValues(); values.put(SubscriptionManager.IS_EMBEDDED, 1); @@ -1265,7 +1279,9 @@ public class SubscriptionControllerTest extends TelephonyTest { public void testSetSubscriptionGroup() throws Exception { testInsertSim(); // Adding a second profile and mark as embedded. - mSubscriptionControllerUT.addSubInfoRecord("test2", 1); + mSubscriptionControllerUT.addSubInfo("test2", null, 1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + ContentValues values = new ContentValues(); values.put(SubscriptionManager.IS_EMBEDDED, 1); mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, @@ -1353,8 +1369,10 @@ public class SubscriptionControllerTest extends TelephonyTest { @SmallTest public void testGetActiveSubIdList() throws Exception { // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfoRecord("123", 1); // sub 1 - mSubscriptionControllerUT.addSubInfoRecord("456", 0); // sub 2 + mSubscriptionControllerUT.addSubInfo("123", null, 1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 1 + mSubscriptionControllerUT.addSubInfo("456", null, 0, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 2 int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); // Make sure the return sub ids are sorted by slot index @@ -1617,7 +1635,9 @@ public class SubscriptionControllerTest extends TelephonyTest { // the ICC ID and phone number. testInsertSim(); doReturn(2).when(mTelephonyManager).getPhoneCount(); - mSubscriptionControllerUT.addSubInfoRecord("test2", 1); + mSubscriptionControllerUT.addSubInfo("test2", null, 1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + int firstSubId = getFirstSubId(); int secondSubId = getSubIdAtIndex(1); mSubscriptionControllerUT.setDisplayNumber(DISPLAY_NUMBER, secondSubId); @@ -1644,7 +1664,8 @@ public class SubscriptionControllerTest extends TelephonyTest { // the ICC ID and phone number. testInsertSim(); doReturn(2).when(mTelephonyManager).getPhoneCount(); - mSubscriptionControllerUT.addSubInfoRecord("test2", 1); + mSubscriptionControllerUT.addSubInfo("test2", null, 1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); int firstSubId = getFirstSubId(); int secondSubId = getSubIdAtIndex(1); setupIdentifierCarrierPrivilegesTest(); @@ -1971,8 +1992,10 @@ public class SubscriptionControllerTest extends TelephonyTest { @SmallTest public void testGetAvailableSubscriptionList() throws Exception { // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfoRecord("123", 1); // sub 1 - mSubscriptionControllerUT.addSubInfoRecord("456", 0); // sub 2 + mSubscriptionControllerUT.addSubInfo("123", null, 1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 1 + mSubscriptionControllerUT.addSubInfo("456", null, 0, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 2 List infoList = mSubscriptionControllerUT .getAvailableSubscriptionInfoList(mCallingPackage, mCallingFeature); @@ -2006,8 +2029,10 @@ public class SubscriptionControllerTest extends TelephonyTest { @SmallTest public void testGetAvailableSubscriptionList_withTrailingF() throws Exception { // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfoRecord("123", 1); // sub 1 - mSubscriptionControllerUT.addSubInfoRecord("456", 0); // sub 2 + mSubscriptionControllerUT.addSubInfo("123", null, 1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 1 + mSubscriptionControllerUT.addSubInfo("456", null, 0, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 2 // Remove "123" from active sim list but have it inserted. UiccSlot[] uiccSlots = {mUiccSlot}; @@ -2054,7 +2079,8 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test public void testSetSubscriptionEnabled_disableActivePsim_cardIdWithTrailingF() { String iccId = "123F"; - mSubscriptionControllerUT.addSubInfoRecord(iccId, 0); + mSubscriptionControllerUT.addSubInfo(iccId, null, 0, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); mSubscriptionControllerUT.registerForUiccAppsEnabled(mHandler, 0, null, false); UiccSlotInfo slot = getFakeUiccSlotInfo(true, 0, iccId + "FF", iccId); UiccSlotInfo[] uiccSlotInfos = {slot}; @@ -2092,8 +2118,9 @@ public class SubscriptionControllerTest extends TelephonyTest { fail("Unexpected exception: " + e); } - mSubscriptionControllerUT.addSubInfoRecord("test3", - SubscriptionManager.INVALID_SIM_SLOT_INDEX); + mSubscriptionControllerUT.addSubInfo("test3", null, + SubscriptionManager.INVALID_SIM_SLOT_INDEX, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); assertTrue(mSubscriptionControllerUT.checkPhoneIdAndIccIdMatch(0, "test")); assertTrue(mSubscriptionControllerUT.checkPhoneIdAndIccIdMatch(0, "test2")); -- GitLab From f8c523b938733ff531977142757df85a2a04490d Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 20 Nov 2022 17:44:18 -0800 Subject: [PATCH 199/656] Added subscription info conversion method Added the conversion method. Also renamed some methods that have inappropriate prefix. Bug: 239607619 Test: atest SubscriptionInfoInternalTest SubscriptionDatabaseManagerTest Change-Id: Iacf77ff6b930cde934da4dc40085f1680ba6ac21 --- .../SubscriptionDatabaseManager.java | 38 +-- .../SubscriptionInfoInternal.java | 175 +++++++---- .../SubscriptionDatabaseManagerTest.java | 84 +++--- .../SubscriptionInfoInternalTest.java | 272 ++++++++++++++++++ 4 files changed, 445 insertions(+), 124 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 3c9ece77e0..374f9e9b7d 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -148,40 +148,40 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal::getDataRoaming), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_MCC_STRING, - SubscriptionInfoInternal::getMccString), + SubscriptionInfoInternal::getMcc), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_MNC_STRING, - SubscriptionInfoInternal::getMncString), + SubscriptionInfoInternal::getMnc), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_EHPLMNS, SubscriptionInfoInternal::getEhplmns), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_HPLMNS, - SubscriptionInfoInternal::getHplmnsRaw), + SubscriptionInfoInternal::getHplmns), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_IS_EMBEDDED, - SubscriptionInfoInternal::isEmbeddedRaw), + SubscriptionInfoInternal::getEmbedded), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_CARD_ID, SubscriptionInfoInternal::getCardString), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_ACCESS_RULES, - SubscriptionInfoInternal::getNativeAccessRulesRaw), + SubscriptionInfoInternal::getNativeAccessRules), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, - SubscriptionInfoInternal::getCarrierConfigAccessRulesRaw), + SubscriptionInfoInternal::getCarrierConfigAccessRules), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_IS_REMOVABLE, - SubscriptionInfoInternal::isRemovableEmbeddedRaw), + SubscriptionInfoInternal::getRemovableEmbedded), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, - SubscriptionInfoInternal::isEnhanced4GModeEnabledRaw), + SubscriptionInfoInternal::getEnhanced4GModeEnabled), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_VT_IMS_ENABLED, - SubscriptionInfoInternal::isVideoTelephonyEnabledRaw), + SubscriptionInfoInternal::getVideoTelephonyEnabled), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_WFC_IMS_ENABLED, - SubscriptionInfoInternal::isWifiCallingEnabledRaw), + SubscriptionInfoInternal::getWifiCallingEnabled), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_WFC_IMS_MODE, SubscriptionInfoInternal::getWifiCallingMode), @@ -190,13 +190,13 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal::getWifiCallingModeForRoaming), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, - SubscriptionInfoInternal::isWifiCallingEnabledForRoamingRaw), + SubscriptionInfoInternal::getWifiCallingEnabledForRoaming), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_IS_OPPORTUNISTIC, - SubscriptionInfoInternal::isOpportunisticRaw), + SubscriptionInfoInternal::getOpportunistic), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_GROUP_UUID, - SubscriptionInfoInternal::getGroupUuidRaw), + SubscriptionInfoInternal::getGroupUuid), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_ISO_COUNTRY_CODE, SubscriptionInfoInternal::getCountryIso), @@ -214,19 +214,19 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal::getGroupOwner), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, - SubscriptionInfoInternal::getEnabledMobileDataPoliciesRaw), + SubscriptionInfoInternal::getEnabledMobileDataPolicies), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_IMSI, SubscriptionInfoInternal::getImsi), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED, - SubscriptionInfoInternal::areUiccApplicationsEnabledRaw), + SubscriptionInfoInternal::getUiccApplicationsEnabled), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, - SubscriptionInfoInternal::isRcsUceEnabledRaw), + SubscriptionInfoInternal::getRcsUceEnabled), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, - SubscriptionInfoInternal::isCrossSimCallingEnabledRaw), + SubscriptionInfoInternal::getCrossSimCallingEnabled), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_RCS_CONFIG, SubscriptionInfoInternal::getRcsConfig), @@ -238,13 +238,13 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal::getDeviceToDeviceStatusSharingPreference), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, - SubscriptionInfoInternal::isVoImsOptInEnabledRaw), + SubscriptionInfoInternal::getVoImsOptInEnabled), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, SubscriptionInfoInternal::getDeviceToDeviceStatusSharingContacts), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, - SubscriptionInfoInternal::isNrAdvancedCallingEnabledRaw), + SubscriptionInfoInternal::getNrAdvancedCallingEnabled), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER, SubscriptionInfoInternal::getNumberFromCarrier), diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index ae0c1d1347..f692e2c688 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -42,7 +42,9 @@ import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyManager; +import android.telephony.UiccAccessRule; import android.telephony.ims.ImsMmTelManager; +import android.text.TextUtils; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.util.TelephonyUtils; @@ -59,9 +61,9 @@ import java.util.Objects; * The difference between {@link SubscriptionInfo} and this class is that {@link SubscriptionInfo} * is a subset of this class. This is intended to solve the problem that some database fields * required higher permission like - * {@link android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE} to access while + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} to access while * {@link SubscriptionManager#getActiveSubscriptionIdList()} only requires - * {@link android.Manifest.permission.READ_PHONE_STATE} to access. Sometimes blanking out fields in + * {@link android.Manifest.permission#READ_PHONE_STATE} to access. Sometimes blanking out fields in * {@link SubscriptionInfo} creates ambiguity for clients hard to distinguish between insufficient * permission versus true failure. * @@ -180,7 +182,7 @@ public class SubscriptionInfoInternal { /** * Whether an embedded subscription is on a removable card. Such subscriptions are marked * inaccessible as soon as the current card is removed. Otherwise, they will remain accessible - * unless explicitly deleted. Only meaningful when {@link #isEmbedded()} is {@code true}. It + * unless explicitly deleted. Only meaningful when {@link #getEmbedded()} is {@code 1}. It * is intended to use integer to fit the database format. */ private final int mIsRemovableEmbedded; @@ -251,8 +253,8 @@ public class SubscriptionInfoInternal { /** * The profile class populated from the profile metadata if present. Otherwise, * the profile class defaults to {@link SubscriptionManager#PROFILE_CLASS_UNSET} if there is no - * profile metadata or the subscription is not on an eUICC ({@link #isEmbedded} returns - * {@code false}). + * profile metadata or the subscription is not on an eUICC ({@link #getEmbedded} returns + * {@code 0}). */ @ProfileClass private final int mProfileClass; @@ -531,7 +533,7 @@ public class SubscriptionInfoInternal { * @return The mobile country code. */ @NonNull - public String getMccString() { + public String getMcc() { return mMcc; } @@ -539,7 +541,7 @@ public class SubscriptionInfoInternal { * @return The mobile network code. */ @NonNull - public String getMncString() { + public String getMnc() { return mMnc; } @@ -555,7 +557,7 @@ public class SubscriptionInfoInternal { * @return Home PLMNs associated with this subscription. */ @NonNull - public String getHplmnsRaw() { + public String getHplmns() { return mHplmns; } @@ -567,9 +569,9 @@ public class SubscriptionInfoInternal { } /** - * @return The raw database value of {@link #isEmbedded()}. + * @return {@code 1} if the subscription is from eSIM. */ - public int isEmbeddedRaw() { + public int getEmbedded() { return mIsEmbedded; } @@ -591,7 +593,7 @@ public class SubscriptionInfoInternal { * stored in the database. */ @NonNull - public byte[] getNativeAccessRulesRaw() { + public byte[] getNativeAccessRules() { return mNativeAccessRules; } @@ -600,65 +602,69 @@ public class SubscriptionInfoInternal { * This does not include access rules from the Uicc, whether embedded or non-embedded. This * is the raw string stored in the database. */ - public byte[] getCarrierConfigAccessRulesRaw() { + public byte[] getCarrierConfigAccessRules() { return mCarrierConfigAccessRules; } /** - * Whether an embedded subscription is on a removable card. Such subscriptions are marked - * inaccessible as soon as the current card is removed. Otherwise, they will remain accessible - * unless explicitly deleted. Only meaningful when {@link #isEmbedded()} is {@code true}. + * @return {@code 1} if an embedded subscription is on a removable card. Such subscriptions are + * marked inaccessible as soon as the current card is removed. Otherwise, they will remain + * accessible unless explicitly deleted. Only meaningful when {@link #getEmbedded()} is 1. */ public boolean isRemovableEmbedded() { return mIsRemovableEmbedded != 0; } /** - * @return The raw database value of {@link #isRemovableEmbedded()}. + * @return {@code 1} if an embedded subscription is on a removable card. Such subscriptions are + * marked inaccessible as soon as the current card is removed. Otherwise, they will remain + * accessible unless explicitly deleted. Only meaningful when {@link #getEmbedded()} is 1. */ - public int isRemovableEmbeddedRaw() { + public int getRemovableEmbedded() { return mIsRemovableEmbedded; } /** - * @return Whether enhanced 4G mode is enabled by the user or not. + * @return {@code true} if enhanced 4G mode is enabled by the user or not. */ public boolean isEnhanced4GModeEnabled() { return mIsEnhanced4GModeEnabled != 0; } /** - * @return The raw database value of {@link #isEnhanced4GModeEnabled()}. + * @return {@code 1} if enhanced 4G mode is enabled by the user or not. */ - public int isEnhanced4GModeEnabledRaw() { + public int getEnhanced4GModeEnabled() { return mIsEnhanced4GModeEnabled; } /** - * @return Whether video telephony is enabled by the user or not. + * @return {@code true} if video telephony is enabled by the user or not. */ public boolean isVideoTelephonyEnabled() { return mIsVideoTelephonyEnabled != 0; } /** - * @return The raw database value of {@link #isVideoTelephonyEnabled()}. + * @return {@code 1} if video telephony is enabled by the user or not. */ - public int isVideoTelephonyEnabledRaw() { + public int getVideoTelephonyEnabled() { return mIsVideoTelephonyEnabled; } /** - * @return Whether Wi-Fi calling is enabled by the user or not when the device is not roaming. + * @return {@code true} if Wi-Fi calling is enabled by the user or not when the device is not + * roaming. */ public boolean isWifiCallingEnabled() { return mIsWifiCallingEnabled != 0; } /** - * @return The raw database value of {@link #isWifiCallingEnabled()}. + * @return {@code 1} if Wi-Fi calling is enabled by the user or not when the device is not + * roaming. */ - public int isWifiCallingEnabledRaw() { + public int getWifiCallingEnabled() { return mIsWifiCallingEnabled; } @@ -671,7 +677,7 @@ public class SubscriptionInfoInternal { } /** - * @return Whether Wi-Fi calling is enabled by the user or not when the device is roaming. + * @return Wi-Fi calling mode when the device is roaming. */ @ImsMmTelManager.WiFiCallingMode public int getWifiCallingModeForRoaming() { @@ -679,16 +685,17 @@ public class SubscriptionInfoInternal { } /** - * @return Whether Wi-Fi calling is enabled by the user or not when the device is roaming. + * @return {@code true} if Wi-Fi calling is enabled by the user or not when the device is + * roaming. */ public boolean isWifiCallingEnabledForRoaming() { return mIsWifiCallingEnabledForRoaming != 0; } /** - * @return The raw database value of {@link #isWifiCallingEnabledForRoaming()}. + * @return {@code 1} if Wi-Fi calling is enabled by the user or not when the device is roaming. */ - public int isWifiCallingEnabledForRoamingRaw() { + public int getWifiCallingEnabledForRoaming() { return mIsWifiCallingEnabledForRoaming; } @@ -696,29 +703,32 @@ public class SubscriptionInfoInternal { * An opportunistic subscription connects to a network that is * limited in functionality and / or coverage. * - * @return Whether subscription is opportunistic. + * @return {@code true} if subscription is opportunistic. */ public boolean isOpportunistic() { return mIsOpportunistic != 0; } /** - * @return The raw database value of {@link #isOpportunistic()}. + * An opportunistic subscription connects to a network that is + * limited in functionality and / or coverage. + * + * @return {@code 1} if subscription is opportunistic. */ - public int isOpportunisticRaw() { + public int getOpportunistic() { return mIsOpportunistic; } /** * Used in scenarios where different subscriptions are bundled as a group. - * It's typically a primary and an opportunistic subscription. (see {@link #isOpportunistic()}) + * It's typically a primary and an opportunistic subscription. (see {@link #getOpportunistic()}) * Such that those subscriptions will have some affiliated behaviors such as opportunistic * subscription may be invisible to the user. * * @return Group UUID in string format. */ @NonNull - public String getGroupUuidRaw() { + public String getGroupUuid() { return mGroupUuid; } @@ -741,8 +751,8 @@ public class SubscriptionInfoInternal { /** * @return The profile class populated from the profile metadata if present. Otherwise, * the profile class defaults to {@link SubscriptionManager#PROFILE_CLASS_UNSET} if there is no - * profile metadata or the subscription is not on an eUICC ({@link #isEmbedded} return - * {@code false}). + * profile metadata or the subscription is not on an eUICC ({@link #getEmbedded} return + * {@code 0}). */ @ProfileClass public int getProfileClass() { @@ -775,7 +785,7 @@ public class SubscriptionInfoInternal { * @see com.android.internal.telephony.data.DataSettingsManager#getMobileDataPolicyEnabled */ @NonNull - public String getEnabledMobileDataPoliciesRaw() { + public String getEnabledMobileDataPolicies() { return mEnabledMobileDataPolicies; } @@ -795,14 +805,14 @@ public class SubscriptionInfoInternal { } /** - * @return The raw database value of {@link #areUiccApplicationsEnabled()}. + * @return {@code 1} if Uicc applications are set to be enabled or disabled. */ - public int areUiccApplicationsEnabledRaw() { + public int getUiccApplicationsEnabled() { return mAreUiccApplicationsEnabled; } /** - * @return Whether the user has enabled IMS RCS User Capability Exchange (UCE) for this + * @return {@code true} if the user has enabled IMS RCS User Capability Exchange (UCE) for this * subscription. */ public boolean isRcsUceEnabled() { @@ -810,23 +820,24 @@ public class SubscriptionInfoInternal { } /** - * @return The raw database value of {@link #isRcsUceEnabled()}. + * @return {@code 1} if the user has enabled IMS RCS User Capability Exchange (UCE) for this + * subscription. */ - public int isRcsUceEnabledRaw() { + public int getRcsUceEnabled() { return mIsRcsUceEnabled; } /** - * @return Whether the user has enabled cross SIM calling for this subscription. + * @return {@code true} if the user has enabled cross SIM calling for this subscription. */ public boolean isCrossSimCallingEnabled() { return mIsCrossSimCallingEnabled != 0; } /** - * @return The raw database value of {@link #isCrossSimCallingEnabled()}. + * @return {@code 1} if the user has enabled cross SIM calling for this subscription. */ - public int isCrossSimCallingEnabledRaw() { + public int getCrossSimCallingEnabled() { return mIsCrossSimCallingEnabled; } @@ -858,16 +869,16 @@ public class SubscriptionInfoInternal { } /** - * @return Whether the user has opted-in voice over IMS. + * @return {@code true} if the user has opted-in voice over IMS. */ public boolean isVoImsOptInEnabled() { return mIsVoImsOptInEnabled != 0; } /** - * @return The raw database value of {@link #isVoImsOptInEnabled()}. + * @return {@code 1} if the user has opted-in voice over IMS. */ - public int isVoImsOptInEnabledRaw() { + public int getVoImsOptInEnabled() { return mIsVoImsOptInEnabled; } @@ -880,16 +891,16 @@ public class SubscriptionInfoInternal { } /** - * @return Whether the user has enabled NR advanced calling. + * @return {@code true} if the user has enabled NR advanced calling. */ public boolean isNrAdvancedCallingEnabled() { return mIsNrAdvancedCallingEnabled != 0; } /** - * @return The raw database value of {@link #isNrAdvancedCallingEnabled()}. + * @return {@code 1} if the user has enabled NR advanced calling. */ - public int isNrAdvancedCallingEnabledRaw() { + public int getNrAdvancedCallingEnabled() { return mIsNrAdvancedCallingEnabled; } @@ -960,6 +971,44 @@ public class SubscriptionInfoInternal { return mIsGroupDisabled; } + /** @return converted {@link SubscriptionInfo}. */ + @NonNull + public SubscriptionInfo toSubscriptionInfo() { + return new SubscriptionInfo.Builder() + .setId(mId) + .setIccId(mIccId) + .setSimSlotIndex(mSimSlotIndex) + .setDisplayName(mDisplayName) + .setCarrierName(mCarrierName) + .setDisplayNameSource(mDisplayNameSource) + .setIconTint(mIconTint) + .setNumber(mNumber) + .setDataRoaming(mDataRoaming) + .setMcc(mMcc) + .setMnc(mMnc) + .setEhplmns(TextUtils.isEmpty(mEhplmns) ? null : mEhplmns.split(",")) + .setHplmns(TextUtils.isEmpty(mHplmns) ? null : mHplmns.split(",")) + .setCountryIso(mCountryIso) + .setEmbedded(mIsEmbedded != 0) + .setNativeAccessRules(mNativeAccessRules.length == 0 + ? null : UiccAccessRule.decodeRules(mNativeAccessRules)) + .setCardString(mCardString) + .setCardId(mCardId) + .setOpportunistic(mIsOpportunistic != 0) + .setGroupUuid(mGroupUuid) + .setGroupDisabled(mIsGroupDisabled) + .setCarrierId(mCarrierId) + .setProfileClass(mProfileClass) + .setType(mType) + .setGroupOwner(mGroupOwner) + .setCarrierConfigAccessRules(mCarrierConfigAccessRules.length == 0 + ? null : UiccAccessRule.decodeRules(mCarrierConfigAccessRules)) + .setUiccApplicationsEnabled(mAreUiccApplicationsEnabled != 0) + .setPortIndex(mPortIndex) + .setUsageSetting(mUsageSetting) + .build(); + } + /** * Get ID stripped PII information on user build. * @@ -1214,8 +1263,8 @@ public class SubscriptionInfoInternal { /** * Whether an embedded subscription is on a removable card. Such subscriptions are marked * inaccessible as soon as the current card is removed. Otherwise, they will remain - * accessible unless explicitly deleted. Only meaningful when {@link #isEmbedded()} is - * {@code true}. + * accessible unless explicitly deleted. Only meaningful when {@link #getEmbedded()} is + * {@code 1}. */ private int mIsRemovableEmbedded = 0; @@ -1278,8 +1327,8 @@ public class SubscriptionInfoInternal { /** * The profile class populated from the profile metadata if present. Otherwise, the profile * class defaults to {@link SubscriptionManager#PROFILE_CLASS_UNSET} if there is no profile - * metadata or the subscription is not on an eUICC ({@link #isEmbedded} returns - * {@code false}). + * metadata or the subscription is not on an eUICC ({@link #getEmbedded} returns + * {@code 0}). */ @ProfileClass private int mProfileClass = SubscriptionManager.PROFILE_CLASS_UNSET; @@ -1658,7 +1707,7 @@ public class SubscriptionInfoInternal { /** * Set whether the subscription is from eSIM or not. * - * @param isEmbedded {@code true} if the subscription is from eSIM. + * @param isEmbedded {@code 1} if the subscription is from eSIM. * * @return The builder. */ @@ -1717,10 +1766,10 @@ public class SubscriptionInfoInternal { /** * Set whether an embedded subscription is on a removable card. Such subscriptions are * marked inaccessible as soon as the current card is removed. Otherwise, they will remain - * accessible unless explicitly deleted. Only meaningful when {@link #isEmbedded()} is - * {@code true}. + * accessible unless explicitly deleted. Only meaningful when {@link #getEmbedded()} is + * {@code 1}. * - * @param isRemovableEmbedded {@code true} if the subscription is from the removable + * @param isRemovableEmbedded {@code 1} if the subscription is from the removable * embedded SIM. * * @return The builder. @@ -1815,7 +1864,7 @@ public class SubscriptionInfoInternal { /** * Set whether the subscription is opportunistic or not. * - * @param isOpportunistic {@code true} if the subscription is opportunistic. + * @param isOpportunistic {@code 1} if the subscription is opportunistic. * @return The builder. */ @NonNull @@ -1933,7 +1982,7 @@ public class SubscriptionInfoInternal { /** * Set whether Uicc applications are configured to enable or not. * - * @param areUiccApplicationsEnabled {@code true} if Uicc applications are configured to + * @param areUiccApplicationsEnabled {@code 1} if Uicc applications are configured to * enable. * @return The builder. */ @@ -2145,7 +2194,7 @@ public class SubscriptionInfoInternal { * subscriptions in the group are deactivated (unplugged pSIM or deactivated eSIM profile), * we should disable this opportunistic subscription. * - * @param isGroupDisabled {@code true} if group of the subscription is disabled. + * @param isGroupDisabled {@code 1} if group of the subscription is disabled. * @return The builder. */ @NonNull 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 028a6537c5..7dc51937d8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -62,52 +62,52 @@ import java.util.Map; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class SubscriptionDatabaseManagerTest extends TelephonyTest { - private static final String FAKE_ICCID1 = "123456"; - private static final String FAKE_ICCID2 = "456789"; - private static final String FAKE_PHONE_NUMBER1 = "6502530000"; - private static final String FAKE_PHONE_NUMBER2 = "4089961010"; - private static final String FAKE_CARRIER_NAME1 = "A-Mobile"; - private static final String FAKE_CARRIER_NAME2 = "B-Mobile"; - private static final int FAKE_COLOR1 = 1; - private static final int FAKE_COLOR2 = 3; - private static final int FAKE_CARRIER_ID1 = 1234; - private static final int FAKE_CARRIER_ID2 = 5678; - private static final String FAKE_COUNTRY_CODE1 = "TW"; - private static final String FAKE_COUNTRY_CODE2 = "US"; - private static final String FAKE_MCC1 = "466"; - private static final String FAKE_MCC2 = "310"; - private static final String FAKE_MNC1 = "01"; - private static final String FAKE_MNC2 = "410"; - private static final String FAKE_EHPLMNS1 = "46602,46603"; - private static final String FAKE_EHPLMNS2 = "310411,310412"; - private static final String FAKE_HPLMNS1 = "46601,46604"; - private static final String FAKE_HPLMNS2 = "310410,310413"; - private static final byte[] FAKE_NATIVE_ACCESS_RULES1 = UiccAccessRule.encodeRules( + 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_CARRIER_NAME1 = "A-Mobile"; + static final String FAKE_CARRIER_NAME2 = "B-Mobile"; + static final int FAKE_COLOR1 = 1; + static final int FAKE_COLOR2 = 3; + static final int FAKE_CARRIER_ID1 = 1234; + static final int FAKE_CARRIER_ID2 = 5678; + static final String FAKE_COUNTRY_CODE1 = "TW"; + static final String FAKE_COUNTRY_CODE2 = "US"; + static final String FAKE_MCC1 = "466"; + static final String FAKE_MCC2 = "310"; + static final String FAKE_MNC1 = "01"; + static final String FAKE_MNC2 = "410"; + static final String FAKE_EHPLMNS1 = "46602,46603"; + static final String FAKE_EHPLMNS2 = "310411,310412"; + static final String FAKE_HPLMNS1 = "46601,46604"; + static final String FAKE_HPLMNS2 = "310410,310413"; + static final byte[] FAKE_NATIVE_ACCESS_RULES1 = UiccAccessRule.encodeRules( new UiccAccessRule[]{new UiccAccessRule(new byte[] {}, "package1", 12345L)}); - private static final byte[] FAKE_NATIVE_ACCESS_RULES2 = UiccAccessRule.encodeRules( + static final byte[] FAKE_NATIVE_ACCESS_RULES2 = UiccAccessRule.encodeRules( new UiccAccessRule[]{new UiccAccessRule(new byte[] {}, "package2", 45678L)}); - private static final byte[] FAKE_CARRIER_CONFIG_ACCESS_RULES1 = UiccAccessRule.encodeRules( + static final byte[] FAKE_CARRIER_CONFIG_ACCESS_RULES1 = UiccAccessRule.encodeRules( new UiccAccessRule[]{new UiccAccessRule(new byte[] {}, "package1", 54321L)}); - private static final byte[] FAKE_CARRIER_CONFIG_ACCESS_RULES2 = UiccAccessRule.encodeRules( + static final byte[] FAKE_CARRIER_CONFIG_ACCESS_RULES2 = UiccAccessRule.encodeRules( new UiccAccessRule[]{new UiccAccessRule(new byte[] {}, "package2", 84954L)}); - private static final String FAKE_UUID1 = "a684e31a-5998-4670-abdd-0561252c58a5"; - private static final String FAKE_UUID2 = "cf6d7a9d-e712-4b3c-a600-7a2d4961b5b9"; - private static final String FAKE_OWNER1 = "owner1"; - private static final String FAKE_OWNER2 = "owner2"; - private static final String FAKE_MOBILE_DATA_POLICY1 = "1,2"; - private static final String FAKE_MOBILE_DATA_POLICY2 = "1"; - private static final String FAKE_IMSI1 = "1234"; - private static final String FAKE_IMSI2 = "5678"; - private static final byte[] FAKE_RCS_CONFIG1 = new byte[]{0x01, 0x02, 0x03}; - private static final byte[] FAKE_RCS_CONFIG2 = new byte[]{0x04, 0x05, 0x06}; - private static final String FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS1 = "carrier=123456, power=3"; - private static final String FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2 = "user=1256, enable_2g=3"; - private static final String FAKE_CONTACT1 = "John Smith, Tesla Forrest"; - private static final String FAKE_CONTACT2 = "Mary Jane, Teresa Mill"; - private static final int FAKE_TP_MESSAGE_REFERENCE1 = 123; - private static final int FAKE_TP_MESSAGE_REFERENCE2 = 456; - private static final int FAKE_USER_ID1 = 10; - private static final int FAKE_USER_ID2 = 11; + static final String FAKE_UUID1 = "a684e31a-5998-4670-abdd-0561252c58a5"; + static final String FAKE_UUID2 = "cf6d7a9d-e712-4b3c-a600-7a2d4961b5b9"; + static final String FAKE_OWNER1 = "owner1"; + static final String FAKE_OWNER2 = "owner2"; + static final String FAKE_MOBILE_DATA_POLICY1 = "1,2"; + static final String FAKE_MOBILE_DATA_POLICY2 = "1"; + static final String FAKE_IMSI1 = "1234"; + static final String FAKE_IMSI2 = "5678"; + static final byte[] FAKE_RCS_CONFIG1 = new byte[]{0x01, 0x02, 0x03}; + static final byte[] FAKE_RCS_CONFIG2 = new byte[]{0x04, 0x05, 0x06}; + static final String FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS1 = "carrier=123456, power=3"; + static final String FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2 = "user=1256, enable_2g=3"; + static final String FAKE_CONTACT1 = "John Smith, Tesla Forrest"; + static final String FAKE_CONTACT2 = "Mary Jane, Teresa Mill"; + static final int FAKE_TP_MESSAGE_REFERENCE1 = 123; + static final int FAKE_TP_MESSAGE_REFERENCE2 = 456; + static final int FAKE_USER_ID1 = 10; + static final int FAKE_USER_ID2 = 11; private static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO1 = new SubscriptionInfoInternal.Builder() diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java new file mode 100644 index 0000000000..7c78106f3a --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2022 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.subscription; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.ParcelUuid; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.UiccAccessRule; +import android.telephony.ims.ImsMmTelManager; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class SubscriptionInfoInternalTest { + private final SubscriptionInfoInternal mSubInfo = + new SubscriptionInfoInternal.Builder() + .setId(1) + .setIccId(SubscriptionDatabaseManagerTest.FAKE_ICCID1) + .setSimSlotIndex(0) + .setDisplayName(SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1) + .setCarrierName(SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1) + .setDisplayNameSource(SubscriptionManager.NAME_SOURCE_SIM_SPN) + .setIconTint(SubscriptionDatabaseManagerTest.FAKE_COLOR1) + .setNumber(SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER1) + .setDataRoaming(SubscriptionManager.DATA_ROAMING_ENABLE) + .setMcc(SubscriptionDatabaseManagerTest.FAKE_MCC1) + .setMnc(SubscriptionDatabaseManagerTest.FAKE_MNC1) + .setEhplmns(SubscriptionDatabaseManagerTest.FAKE_EHPLMNS1) + .setHplmns(SubscriptionDatabaseManagerTest.FAKE_HPLMNS1) + .setEmbedded(1) + .setCardString(SubscriptionDatabaseManagerTest.FAKE_ICCID1) + .setCardId(1) + .setNativeAccessRules(SubscriptionDatabaseManagerTest + .FAKE_NATIVE_ACCESS_RULES1) + .setCarrierConfigAccessRules(SubscriptionDatabaseManagerTest + .FAKE_CARRIER_CONFIG_ACCESS_RULES1) + .setRemovableEmbedded(0) + .setEnhanced4GModeEnabled(1) + .setVideoTelephonyEnabled(1) + .setWifiCallingEnabled(1) + .setWifiCallingMode(ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED) + .setWifiCallingModeForRoaming(ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED) + .setWifiCallingEnabledForRoaming(1) + .setOpportunistic(0) + .setGroupUuid(SubscriptionDatabaseManagerTest.FAKE_UUID1) + .setCountryIso(SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE1) + .setCarrierId(SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL) + .setType(SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM) + .setGroupOwner(SubscriptionDatabaseManagerTest.FAKE_OWNER1) + .setEnabledMobileDataPolicies(SubscriptionDatabaseManagerTest + .FAKE_MOBILE_DATA_POLICY1) + .setImsi(SubscriptionDatabaseManagerTest.FAKE_IMSI1) + .setUiccApplicationsEnabled(1) + .setRcsUceEnabled(1) + .setCrossSimCallingEnabled(1) + .setRcsConfig(SubscriptionDatabaseManagerTest.FAKE_RCS_CONFIG1) + .setAllowedNetworkTypesForReasons(SubscriptionDatabaseManagerTest + .FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS1) + .setDeviceToDeviceStatusSharingPreference( + SubscriptionManager.D2D_SHARING_ALL_CONTACTS) + .setVoImsOptInEnabled(1) + .setDeviceToDeviceStatusSharingContacts( + SubscriptionDatabaseManagerTest.FAKE_CONTACT1) + .setNrAdvancedCallingEnabled(1) + .setNumberFromCarrier(SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER1) + .setNumberFromIms(SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER1) + .setPortIndex(0) + .setUsageSetting(SubscriptionManager.USAGE_SETTING_DEFAULT) + .setLastUsedTPMessageReference(SubscriptionDatabaseManagerTest + .FAKE_TP_MESSAGE_REFERENCE1) + .setUserId(SubscriptionDatabaseManagerTest.FAKE_USER_ID1) + .setGroupDisabled(false) + .build(); + + private final SubscriptionInfoInternal mSubInfoNull = + new SubscriptionInfoInternal.Builder() + .setId(1) + .setIccId("123") + .setSimSlotIndex(0) + .setDisplayName("") + .setCarrierName("") + .setNumber("") + .setMcc("") + .setMnc("") + .setEhplmns("") + .setHplmns("") + .setEmbedded(1) + .setCardId(1) + .setNativeAccessRules(new byte[0]) + .setCarrierConfigAccessRules(new byte[0]) + .setGroupUuid("") + .setCountryIso("") + .setGroupOwner("") + .setEnabledMobileDataPolicies("") + .setImsi("") + .setRcsConfig(new byte[0]) + .setAllowedNetworkTypesForReasons("") + .setDeviceToDeviceStatusSharingContacts("") + .build(); + + @Test + public void testSubscriptionInfoInternalSetAndGet() { + assertThat(mSubInfo.getSubscriptionId()).isEqualTo(1); + assertThat(mSubInfo.getIccId()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_ICCID1); + assertThat(mSubInfo.getSimSlotIndex()).isEqualTo(0); + assertThat(mSubInfo.getDisplayName()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1); + assertThat(mSubInfo.getCarrierName()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1); + assertThat(mSubInfo.getDisplayNameSource()).isEqualTo( + SubscriptionManager.NAME_SOURCE_SIM_SPN); + assertThat(mSubInfo.getIconTint()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_COLOR1); + assertThat(mSubInfo.getNumber()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER1); + assertThat(mSubInfo.getDataRoaming()).isEqualTo(SubscriptionManager.DATA_ROAMING_ENABLE); + assertThat(mSubInfo.getMcc()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_MCC1); + assertThat(mSubInfo.getMnc()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_MNC1); + assertThat(mSubInfo.getEhplmns()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_EHPLMNS1); + assertThat(mSubInfo.getHplmns()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_HPLMNS1); + assertThat(mSubInfo.getEmbedded()).isEqualTo(1); + assertThat(mSubInfo.getCardString()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_ICCID1); + assertThat(mSubInfo.getCardId()).isEqualTo(1); + assertThat(mSubInfo.getNativeAccessRules()).isEqualTo(SubscriptionDatabaseManagerTest + .FAKE_NATIVE_ACCESS_RULES1); + assertThat(mSubInfo.getCarrierConfigAccessRules()).isEqualTo(SubscriptionDatabaseManagerTest + .FAKE_CARRIER_CONFIG_ACCESS_RULES1); + assertThat(mSubInfo.getRemovableEmbedded()).isEqualTo(0); + assertThat(mSubInfo.getEnhanced4GModeEnabled()).isEqualTo(1); + assertThat(mSubInfo.getVideoTelephonyEnabled()).isEqualTo(1); + assertThat(mSubInfo.getWifiCallingEnabled()).isEqualTo(1); + assertThat(mSubInfo.getWifiCallingMode()).isEqualTo( + ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED); + assertThat(mSubInfo.getWifiCallingModeForRoaming()).isEqualTo( + ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED); + assertThat(mSubInfo.getOpportunistic()).isEqualTo(0); + assertThat(mSubInfo.getGroupUuid()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_UUID1); + assertThat(mSubInfo.getCountryIso()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE1); + assertThat(mSubInfo.getCarrierId()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID1); + assertThat(mSubInfo.getProfileClass()).isEqualTo( + SubscriptionManager.PROFILE_CLASS_OPERATIONAL); + assertThat(mSubInfo.getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + assertThat(mSubInfo.getGroupOwner()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_OWNER1); + assertThat(mSubInfo.getEnabledMobileDataPolicies()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_MOBILE_DATA_POLICY1); + assertThat(mSubInfo.getImsi()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_IMSI1); + assertThat(mSubInfo.getUiccApplicationsEnabled()).isEqualTo(1); + assertThat(mSubInfo.getRcsUceEnabled()).isEqualTo(1); + assertThat(mSubInfo.getCrossSimCallingEnabled()).isEqualTo(1); + assertThat(mSubInfo.getRcsConfig()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_RCS_CONFIG1); + assertThat(mSubInfo.getAllowedNetworkTypesForReasons()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS1); + assertThat(mSubInfo.getVoImsOptInEnabled()).isEqualTo(1); + assertThat(mSubInfo.getDeviceToDeviceStatusSharingContacts()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_CONTACT1); + assertThat(mSubInfo.getNrAdvancedCallingEnabled()).isEqualTo(1); + assertThat(mSubInfo.getNumberFromCarrier()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER1); + assertThat(mSubInfo.getNumberFromIms()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER1); + assertThat(mSubInfo.getPortIndex()).isEqualTo( + SubscriptionManager.USAGE_SETTING_DEFAULT); + assertThat(mSubInfo.getLastUsedTPMessageReference()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_TP_MESSAGE_REFERENCE1); + assertThat(mSubInfo.getUserId()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_USER_ID1); + assertThat(mSubInfo.isGroupDisabled()).isFalse(); + } + + @Test + public void testEquals() { + SubscriptionInfoInternal another = new SubscriptionInfoInternal.Builder(mSubInfo).build(); + assertThat(another).isEqualTo(mSubInfo); + } + + @Test + public void testConvertToSubscriptionInfo() { + SubscriptionInfo subInfo = mSubInfo.toSubscriptionInfo(); + + assertThat(subInfo.getSubscriptionId()).isEqualTo(1); + assertThat(subInfo.getIccId()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_ICCID1); + assertThat(subInfo.getSimSlotIndex()).isEqualTo(0); + assertThat(subInfo.getDisplayName()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1); + assertThat(subInfo.getCarrierName()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1); + assertThat(subInfo.getDisplayNameSource()).isEqualTo( + SubscriptionManager.NAME_SOURCE_SIM_SPN); + assertThat(subInfo.getIconTint()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_COLOR1); + assertThat(subInfo.getNumber()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER1); + assertThat(subInfo.getDataRoaming()).isEqualTo(SubscriptionManager.DATA_ROAMING_ENABLE); + assertThat(subInfo.getMccString()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_MCC1); + assertThat(subInfo.getMncString()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_MNC1); + assertThat(subInfo.getEhplmns()).isEqualTo(Arrays.asList( + SubscriptionDatabaseManagerTest.FAKE_EHPLMNS1.split(","))); + assertThat(subInfo.getHplmns()).isEqualTo(Arrays.asList( + SubscriptionDatabaseManagerTest.FAKE_HPLMNS1.split(","))); + assertThat(subInfo.isEmbedded()).isTrue(); + assertThat(subInfo.getCardString()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_ICCID1); + assertThat(subInfo.getCardId()).isEqualTo(1); + + + List rules = new ArrayList<>(); + + rules.addAll(Arrays.asList(UiccAccessRule.decodeRules( + SubscriptionDatabaseManagerTest.FAKE_NATIVE_ACCESS_RULES1))); + rules.addAll(Arrays.asList(UiccAccessRule.decodeRules( + SubscriptionDatabaseManagerTest.FAKE_CARRIER_CONFIG_ACCESS_RULES1))); + + assertThat(subInfo.getAccessRules()).containsExactlyElementsIn(rules); + + assertThat(subInfo.isOpportunistic()).isFalse(); + assertThat(subInfo.getGroupUuid()).isEqualTo(ParcelUuid.fromString( + SubscriptionDatabaseManagerTest.FAKE_UUID1)); + assertThat(subInfo.getCountryIso()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE1); + assertThat(subInfo.getCarrierId()).isEqualTo( + SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID1); + assertThat(subInfo.getProfileClass()).isEqualTo( + SubscriptionManager.PROFILE_CLASS_OPERATIONAL); + assertThat(subInfo.getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + assertThat(subInfo.getGroupOwner()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_OWNER1); + assertThat(subInfo.areUiccApplicationsEnabled()).isTrue(); + assertThat(subInfo.getPortIndex()).isEqualTo( + SubscriptionManager.USAGE_SETTING_DEFAULT); + assertThat(subInfo.isGroupDisabled()).isFalse(); + } + + @Test + public void testNullability() { + SubscriptionInfo subInfoNull = mSubInfoNull.toSubscriptionInfo(); + assertThat(subInfoNull.getSubscriptionId()).isEqualTo(1); + assertThat(subInfoNull.getIccId()).isEqualTo("123"); + assertThat(subInfoNull.getSimSlotIndex()).isEqualTo(0); + assertThat(subInfoNull.getDisplayName()).isEqualTo(""); + assertThat(subInfoNull.getCarrierName()).isEqualTo(""); + assertThat(subInfoNull.getNumber()).isEqualTo(""); + assertThat(subInfoNull.getMccString()).isEqualTo(""); + assertThat(subInfoNull.getMncString()).isEqualTo(""); + assertThat(subInfoNull.getEhplmns()).isEmpty(); + assertThat(subInfoNull.getHplmns()).isEmpty(); + assertThat(subInfoNull.isEmbedded()).isTrue(); + assertThat(subInfoNull.getCardId()).isEqualTo(1); + assertThat(subInfoNull.getAccessRules()).isNull(); + assertThat(subInfoNull.getGroupUuid()).isNull(); + assertThat(subInfoNull.getCountryIso()).isEqualTo(""); + assertThat(subInfoNull.getGroupOwner()).isEqualTo(""); + } +} -- GitLab From 6b79ab244db36791d60c34c046b018aaaa83898d Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Mon, 21 Nov 2022 00:54:25 -0800 Subject: [PATCH 200/656] Change NrQos qfi from byte to int Deprecate byte qfi and replace with int qosFlowIdentifier Test: build Bug: 247072632 Change-Id: I531d2f59fa7143253ee2b83f249a4c2f96e9b0e0 --- src/java/com/android/internal/telephony/RILUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 52f8974e26..2d43f00456 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -3855,7 +3855,7 @@ public class RILUtils { case android.hardware.radio.data.Qos.nr: android.hardware.radio.data.NrQos nr = qos.getNr(); return new NrQos(convertHalQosBandwidth(nr.downlink), - convertHalQosBandwidth(nr.uplink), nr.qfi, nr.fiveQi, + convertHalQosBandwidth(nr.uplink), nr.qosFlowIdentifier, nr.fiveQi, nr.averagingWindowMs); default: return null; -- GitLab From c9223c7326ff756f16bf39977e27afd05f74fc8d Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Mon, 21 Nov 2022 19:13:41 +0000 Subject: [PATCH 201/656] Display timestamp on network connectivity notifications. Bug: 238784502 Test: Manual - adb shell cmd phone cc set-value -p emergency_notification_delay_int 30000 Change-Id: I62955d64721db00e844708e030924e611f24892d --- .../android/internal/telephony/CarrierServiceStateTracker.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java index 64dc7ecee9..9fa26cca7d 100644 --- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java @@ -376,6 +376,7 @@ public class CarrierServiceStateTracker extends Handler { Notification.Builder builder = getNotificationBuilder(notificationType); // set some common attributes builder.setWhen(System.currentTimeMillis()) + .setShowWhen(true) .setAutoCancel(true) .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning) .setColor(context.getResources().getColor( -- GitLab From b513332cb172a111f81834d19da7fe5be18f67bd Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Mon, 21 Nov 2022 16:21:06 -0800 Subject: [PATCH 202/656] Add "not supported" string for MMI codes not supported by network. When either the GSM or IMS MMI codes result in a "request not supported" or "operation not allowed" result code, report that the operation is not supported. Bug: 230841132 Test: Added new unit tests to verify the correct message is generated when the network reports that a feature is not supported. Change-Id: I30af9525a02880be83c70e66c36b28ec1b72eddf --- .../internal/telephony/gsm/GsmMmiCode.java | 11 ++++++++-- .../telephony/imsphone/ImsPhoneMmiCode.java | 9 ++++++++- .../telephony/gsm/GsmMmiCodeTest.java | 18 +++++++++++++++++ .../imsphone/ImsPhoneMmiCodeTest.java | 20 +++++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 114a7d8793..58e03ae4c3 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -1432,8 +1432,8 @@ public final class GsmMmiCode extends Handler implements MmiCode { } } //***** Private instance methods - - private CharSequence getErrorMessage(AsyncResult ar) { + @VisibleForTesting + public CharSequence getErrorMessage(AsyncResult ar) { if (ar.exception instanceof CommandException) { CommandException.Error err = ((CommandException)(ar.exception)).getCommandError(); @@ -1461,6 +1461,13 @@ public final class GsmMmiCode extends Handler implements MmiCode { } else if (err == CommandException.Error.OEM_ERROR_1) { Rlog.i(LOG_TAG, "OEM_ERROR_1 USSD_MODIFIED_TO_DIAL_VIDEO"); return mContext.getText(com.android.internal.R.string.stk_cc_ussd_to_dial_video); + } else if (err == CommandException.Error.REQUEST_NOT_SUPPORTED + || err == CommandException.Error.OPERATION_NOT_ALLOWED) { + Rlog.i(LOG_TAG, "REQUEST_NOT_SUPPORTED/OPERATION_NOT_ALLOWED"); + // getResources().getText() is the same as getText(), however getText() is final and + // cannot be mocked in tests. + return mContext.getResources().getText( + com.android.internal.R.string.mmiErrorNotSupported); } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java index 3dadd23f44..1f8c8c5b17 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java @@ -1364,7 +1364,8 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { mContext.getText(com.android.internal.R.string.mmiError); } - private CharSequence getMmiErrorMessage(AsyncResult ar) { + @VisibleForTesting + public CharSequence getMmiErrorMessage(AsyncResult ar) { if (ar.exception instanceof ImsException) { switch (((ImsException) ar.exception).getCode()) { case ImsReasonInfo.CODE_FDN_BLOCKED: @@ -1394,6 +1395,12 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { return mContext.getText(com.android.internal.R.string.stk_cc_ss_to_dial_video); } else if (err.getCommandError() == CommandException.Error.INTERNAL_ERR) { return mContext.getText(com.android.internal.R.string.mmiError); + } else if (err.getCommandError() == CommandException.Error.REQUEST_NOT_SUPPORTED + || err.getCommandError() == CommandException.Error.OPERATION_NOT_ALLOWED) { + // getResources().getText() is the same as getText(), however getText() is final and + // cannot be mocked in tests. + return mContext.getResources().getText( + com.android.internal.R.string.mmiErrorNotSupported); } } return null; 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 70df8aa70f..1c1ca0feff 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmMmiCodeTest.java @@ -23,12 +23,16 @@ import static junit.framework.Assert.fail; 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.os.AsyncResult; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import com.android.internal.telephony.CommandException; import com.android.internal.telephony.GsmCdmaPhone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyTest; @@ -308,6 +312,20 @@ public class GsmMmiCodeTest extends TelephonyTest { assertThat(controlStrings).containsExactly("**03*330"); } + @Test + public void testOperationNotSupported() { + // Contrived; this is just to get a simple instance of the class. + mGsmMmiCode = GsmMmiCode.newNetworkInitiatedUssd(null, true, mGsmCdmaPhoneUT, null); + + assertThat(mGsmMmiCode).isNotNull(); + // Emulate request not supported from the network. + AsyncResult ar = new AsyncResult(null, null, + new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED)); + mGsmMmiCode.getErrorMessage(ar); + verify(mContext.getResources()).getText( + eq(com.android.internal.R.string.mmiErrorNotSupported)); + } + private void setCarrierSupportsCallerIdVerticalServiceCodesCarrierConfig() { final PersistableBundle bundle = new PersistableBundle(); bundle.putBoolean(CarrierConfigManager diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java index 2defe3c43d..724f9d48fe 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java @@ -21,9 +21,12 @@ import static junit.framework.Assert.fail; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import android.os.AsyncResult; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; @@ -31,6 +34,7 @@ import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import com.android.internal.telephony.CommandException; import com.android.internal.telephony.SsDomainController; import com.android.internal.telephony.TelephonyTest; @@ -149,4 +153,20 @@ public class ImsPhoneMmiCodeTest extends TelephonyTest { (SsDomainController) null); assertNull(ssInfo); } + + /** + * Ensure that when an operation is not supported that the correct message is returned. + */ + @Test + @SmallTest + public void testOperationNotSupported() { + mImsPhoneMmiCode = ImsPhoneMmiCode.newNetworkInitiatedUssd(null, true, mImsPhoneUT); + + // Emulate request not supported from the network. + AsyncResult ar = new AsyncResult(null, null, + new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED)); + mImsPhoneMmiCode.getMmiErrorMessage(ar); + verify(mContext.getResources()).getText( + eq(com.android.internal.R.string.mmiErrorNotSupported)); + } } -- GitLab From 23be79841e8e5dc603de0a7316db256b06634571 Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Fri, 19 Aug 2022 03:25:30 +0000 Subject: [PATCH 203/656] Adding Ims Call Info to CallAttributes Provide IMS Call type & session ID to CallAttributes. That will be used for QNS handover decision. Bug: 242928210 Test: atest FrameworksTelephonyTests Change-Id: Ic7b5adefdc08d992d2c8d27f9843b91a88245eb9 --- .../telephony/DefaultPhoneNotifier.java | 23 ++- .../internal/telephony/GsmCdmaPhone.java | 5 +- .../com/android/internal/telephony/Phone.java | 13 +- .../internal/telephony/PhoneNotifier.java | 6 +- .../telephony/imsphone/ImsPhoneBase.java | 35 +++- .../telephony/imsphone/ImsPhoneCall.java | 37 ++++ .../internal/telephony/CallStateTest.java | 177 ++++++++++++++++++ .../telephony/DefaultPhoneNotifierTest.java | 161 ++++++++++++---- .../telephony/imsphone/ImsPhoneCallTest.java | 48 +++++ 9 files changed, 452 insertions(+), 53 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java index e4aff4c911..cabceb2fc7 100644 --- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.annotation.NonNull; import android.content.Context; +import android.telephony.Annotation; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SrvccState; import android.telephony.BarringInfo; @@ -34,6 +35,7 @@ import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager.DataEnabledReason; import android.telephony.TelephonyRegistryManager; import android.telephony.emergency.EmergencyNumber; +import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsReasonInfo; import com.android.telephony.Rlog; @@ -142,15 +144,28 @@ public class DefaultPhoneNotifier implements PhoneNotifier { mTelephonyRegistryMgr.notifyCellInfoChanged(subId, cellInfo); } - public void notifyPreciseCallState(Phone sender) { + /** + * Notify precise call state of foreground, background and ringing call states. + * + * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId} for + * ringing, foreground & background calls. + * @param imsCallServiceTypes Array of IMS call service type for ringing, foreground & + * background calls. + * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls. + */ + public void notifyPreciseCallState(Phone sender, String[] imsCallIds, + @Annotation.ImsCallServiceType int[] imsCallServiceTypes, + @Annotation.ImsCallType int[] imsCallTypes) { Call ringingCall = sender.getRingingCall(); Call foregroundCall = sender.getForegroundCall(); Call backgroundCall = sender.getBackgroundCall(); + if (ringingCall != null && foregroundCall != null && backgroundCall != null) { - mTelephonyRegistryMgr.notifyPreciseCallState(sender.getPhoneId(), sender.getSubId(), - convertPreciseCallState(ringingCall.getState()), + int[] callStates = {convertPreciseCallState(ringingCall.getState()), convertPreciseCallState(foregroundCall.getState()), - convertPreciseCallState(backgroundCall.getState())); + convertPreciseCallState(backgroundCall.getState())}; + mTelephonyRegistryMgr.notifyPreciseCallState(sender.getPhoneId(), sender.getSubId(), + callStates, imsCallIds, imsCallServiceTypes, imsCallTypes); } } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 6d16fe072a..ed891b4dac 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -842,7 +842,10 @@ public class GsmCdmaPhone extends Phone { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void notifyPreciseCallStateChanged() { /* we'd love it if this was package-scoped*/ - super.notifyPreciseCallStateChangedP(); + AsyncResult ar = new AsyncResult(null, this, null); + mPreciseCallStateRegistrants.notifyRegistrants(ar); + + mNotifier.notifyPreciseCallState(this, null, null, null); } public void notifyNewRingingConnection(Connection c) { diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 99bd3c5358..b9c1868303 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -399,7 +399,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public static final String EXTRA_KEY_ALERT_SHOW = "alertShow"; public static final String EXTRA_KEY_NOTIFICATION_MESSAGE = "notificationMessage"; - private final RegistrantList mPreciseCallStateRegistrants = new RegistrantList(); + protected final RegistrantList mPreciseCallStateRegistrants = new RegistrantList(); private final RegistrantList mHandoverRegistrants = new RegistrantList(); @@ -984,17 +984,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mPreciseCallStateRegistrants.remove(h); } - /** - * Subclasses of Phone probably want to replace this with a - * version scoped to their packages - */ - protected void notifyPreciseCallStateChangedP() { - AsyncResult ar = new AsyncResult(null, this, null); - mPreciseCallStateRegistrants.notifyRegistrants(ar); - - mNotifier.notifyPreciseCallState(this); - } - /** * Notifies when a Handover happens due to SRVCC or Silent Redial */ diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java index 701a157f98..7617bdf225 100644 --- a/src/java/com/android/internal/telephony/PhoneNotifier.java +++ b/src/java/com/android/internal/telephony/PhoneNotifier.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; +import android.telephony.Annotation; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SrvccState; import android.telephony.BarringInfo; @@ -78,7 +79,10 @@ public interface PhoneNotifier { void notifyCellInfo(Phone sender, List cellInfo); - void notifyPreciseCallState(Phone sender); + /** Send a notification that precise call state changed. */ + void notifyPreciseCallState(Phone sender, String[] imsCallIds, + @Annotation.ImsCallServiceType int[] imsCallServiceTypes, + @Annotation.ImsCallType int[] imsCallTypes); void notifyDisconnectCause(Phone sender, int cause, int preciseCause); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index 322dd55f7c..2ae9dc54ba 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -24,6 +24,7 @@ import android.os.RegistrantList; import android.sysprop.TelephonyProperties; import android.telephony.Annotation.DataActivityType; import android.telephony.CallQuality; +import android.telephony.CallState; import android.telephony.NetworkScanRequest; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -198,7 +199,39 @@ abstract class ImsPhoneBase extends Phone { */ public void notifyPreciseCallStateChanged() { /* we'd love it if this was package-scoped*/ - super.notifyPreciseCallStateChangedP(); + AsyncResult ar = new AsyncResult(null, this, null); + mPreciseCallStateRegistrants.notifyRegistrants(ar); + + ImsPhoneCall ringingCall = (ImsPhoneCall) getRingingCall(); + ImsPhoneCall foregroundCall = (ImsPhoneCall) getForegroundCall(); + ImsPhoneCall backgroundCall = (ImsPhoneCall) getBackgroundCall(); + + if (ringingCall != null && foregroundCall != null && backgroundCall != null) { + //Array for IMS call session ID of RINGING/FOREGROUND/BACKGROUND call + String[] imsCallIds = new String[CallState.CALL_CLASSIFICATION_MAX]; + //Array for IMS call service type of RINGING/FOREGROUND/BACKGROUND call + int[] imsCallServiceTypes = new int[CallState.CALL_CLASSIFICATION_MAX]; + //Array for IMS call type of RINGING/FOREGROUND/BACKGROUND call + int[] imsCallTypes = new int[CallState.CALL_CLASSIFICATION_MAX]; + imsCallIds[CallState.CALL_CLASSIFICATION_RINGING] = + ringingCall.getCallSessionId(); + imsCallIds[CallState.CALL_CLASSIFICATION_FOREGROUND] = + foregroundCall.getCallSessionId(); + imsCallIds[CallState.CALL_CLASSIFICATION_BACKGROUND] = + backgroundCall.getCallSessionId(); + imsCallServiceTypes[CallState.CALL_CLASSIFICATION_RINGING] = + ringingCall.getServiceType(); + imsCallServiceTypes[CallState.CALL_CLASSIFICATION_FOREGROUND] = + foregroundCall.getServiceType(); + imsCallServiceTypes[CallState.CALL_CLASSIFICATION_BACKGROUND] = + backgroundCall.getServiceType(); + imsCallTypes[CallState.CALL_CLASSIFICATION_RINGING] = ringingCall.getCallType(); + imsCallTypes[CallState.CALL_CLASSIFICATION_FOREGROUND] = + foregroundCall.getCallType(); + imsCallTypes[CallState.CALL_CLASSIFICATION_BACKGROUND] = + backgroundCall.getCallType(); + mNotifier.notifyPreciseCallState(this, imsCallIds, imsCallServiceTypes, imsCallTypes); + } } public void notifyDisconnect(Connection cn) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java index 98cc441861..7a6adce8af 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java @@ -19,6 +19,8 @@ package com.android.internal.telephony.imsphone; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.telephony.DisconnectCause; +import android.telephony.ims.ImsCallProfile; +import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsStreamMediaProfile; import android.util.Log; @@ -327,6 +329,41 @@ public class ImsPhoneCall extends Call { return (connection == null) ? null : connection.getImsCall(); } + /** + * Retrieves the {@link ImsCallSession#getCallId()} for the current {@link ImsPhoneCall}. + */ + @VisibleForTesting + public String getCallSessionId() { + return ((getImsCall() == null) ? null : getImsCall().getSession()) == null + ? null : getImsCall().getSession().getCallId(); + } + + /** + * Retrieves the service type in {@link ImsCallProfile} for the current {@link ImsPhoneCall}. + */ + @VisibleForTesting + public int getServiceType() { + if (getFirstConnection() == null) { + return ImsCallProfile.SERVICE_TYPE_NONE; + } else { + return getFirstConnection().isEmergencyCall() + ? ImsCallProfile.SERVICE_TYPE_EMERGENCY : ImsCallProfile.SERVICE_TYPE_NORMAL; + } + } + + /** + * Retrieves the call type in {@link ImsCallProfile} for the current {@link ImsPhoneCall}. + */ + @VisibleForTesting + public int getCallType() { + if (getImsCall() == null) { + return ImsCallProfile.CALL_TYPE_NONE; + } else { + return getImsCall().isVideoCall() + ? ImsCallProfile.CALL_TYPE_VT : ImsCallProfile.CALL_TYPE_VOICE; + } + } + /*package*/ static boolean isLocalTone(ImsCall imsCall) { if ((imsCall == null) || (imsCall.getCallProfile() == null) || (imsCall.getCallProfile().mMediaProfile == null)) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java new file mode 100644 index 0000000000..4e319a12dc --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import static org.junit.Assert.assertEquals; + +import android.os.Parcel; +import android.telephony.CallQuality; +import android.telephony.CallState; +import android.telephony.PreciseCallState; +import android.telephony.TelephonyManager; +import android.telephony.ims.ImsCallProfile; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import org.junit.Test; + +/** + * Simple GTS test verifying the parceling and unparceling of CallAttributes. + */ +public class CallStateTest extends AndroidTestCase { + + + @SmallTest + public void testParcelUnparcelPreciseCallState() { + CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_INCOMING) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(null) + .setCallClassification(CallState.CALL_CLASSIFICATION_RINGING) + .setImsCallSessionId("1") + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) + .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); + + Parcel parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertEquals("PreciseCallState is not equal after parceled/unparceled", + data.getCallState(), + unparceledData.getCallState()); + } + + @SmallTest + public void testParcelUnparcelCallQuality() { + CallQuality quality = new CallQuality(); + CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_IDLE) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(null) + .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId(null) + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) + .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); + + + Parcel parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertNull(unparceledData.getCallQuality()); + + data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_IDLE) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(quality) + .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId(null) + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) + .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); + + + parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertEquals("CallQuality is not equal after parceled/unparceled", + data.getCallQuality(), + unparceledData.getCallQuality()); + } + + @SmallTest + public void testParcelUnparcelNetworkTypeAndClassification() { + CallQuality quality = new CallQuality(); + CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_DIALING) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(null) + .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId("3") + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) + .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); + + Parcel parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertEquals("NetworkType is not equal after parceled/unparceled", + data.getNetworkType(), + unparceledData.getNetworkType()); + assertEquals("Call classification is not equal after parceled/unparceled", + data.getCallClassification(), + unparceledData.getCallClassification()); + } + + @Test + public void testParcelUnparcelImsCallInfo() { + CallQuality quality = new CallQuality(); + CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_DIALING) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(null) + .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId(null) + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NORMAL) + .setImsCallType(ImsCallProfile.CALL_TYPE_VOICE).build(); + + Parcel parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertNull(unparceledData.getImsCallSessionId()); + + assertEquals("Ims call service type is not equal after parceled/unparceled", + data.getImsCallServiceType(), + unparceledData.getImsCallServiceType()); + + assertEquals("Ims call type is not equal after parceled/unparceled", + data.getImsCallType(), + unparceledData.getImsCallType()); + + data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(quality) + .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId("2") + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NORMAL) + .setImsCallType(ImsCallProfile.CALL_TYPE_VT).build(); + + parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertEquals("Ims call session ID is not equal after parceled/unparceled", + data.getImsCallSessionId(), + unparceledData.getImsCallSessionId()); + + assertEquals("Ims call service type is not equal after parceled/unparceled", + data.getImsCallServiceType(), + unparceledData.getImsCallServiceType()); + + assertEquals("Ims call type is not equal after parceled/unparceled", + data.getImsCallType(), + unparceledData.getImsCallType()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java index 6a05d4f4b8..2f4182a993 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; @@ -30,8 +31,11 @@ import android.telephony.PreciseCallState; import android.telephony.PreciseDisconnectCause; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; +import android.telephony.ims.ImsCallProfile; import android.test.suitebuilder.annotation.SmallTest; +import com.android.internal.telephony.imsphone.ImsPhoneCall; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -53,6 +57,9 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { GsmCdmaCall mForeGroundCall; GsmCdmaCall mBackGroundCall; GsmCdmaCall mRingingCall; + ImsPhoneCall mImsForeGroundCall; + ImsPhoneCall mImsBackGroundCall; + ImsPhoneCall mImsRingingCall; @Before public void setUp() throws Exception { @@ -62,6 +69,9 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { mForeGroundCall = mock(GsmCdmaCall.class); mBackGroundCall = mock(GsmCdmaCall.class); mRingingCall = mock(GsmCdmaCall.class); + mImsForeGroundCall = mock(ImsPhoneCall.class); + mImsBackGroundCall = mock(ImsPhoneCall.class); + mImsRingingCall = mock(ImsPhoneCall.class); mDefaultPhoneNotifierUT = new DefaultPhoneNotifier(mContext); } @@ -168,61 +178,144 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { @Test @SmallTest public void testNotifyPreciseCallState() throws Exception { - //mock forground/background/ringing call and call state doReturn(Call.State.IDLE).when(mForeGroundCall).getState(); doReturn(Call.State.IDLE).when(mBackGroundCall).getState(); doReturn(Call.State.IDLE).when(mRingingCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); verify(mTelephonyRegistryManager, times(0)).notifyPreciseCallState( - anyInt(), anyInt(), anyInt(), anyInt(), anyInt()); + anyInt(), anyInt(), any(), any(), any(), any()); doReturn(mForeGroundCall).when(mPhone).getForegroundCall(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); verify(mTelephonyRegistryManager, times(0)).notifyPreciseCallState( - anyInt(), anyInt(), anyInt(), anyInt(), anyInt()); + anyInt(), anyInt(), any(), any(), any(), any()); doReturn(mBackGroundCall).when(mPhone).getBackgroundCall(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); verify(mTelephonyRegistryManager, times(0)).notifyPreciseCallState( - anyInt(), anyInt(), anyInt(), anyInt(), anyInt()); + anyInt(), anyInt(), any(), any(), any(), any()); doReturn(mRingingCall).when(mPhone).getRingingCall(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); - verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( - mPhone.getPhoneId(), - mPhone.getSubId(), - PreciseCallState.PRECISE_CALL_STATE_IDLE, - PreciseCallState.PRECISE_CALL_STATE_IDLE, - PreciseCallState.PRECISE_CALL_STATE_IDLE); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + ArgumentCaptor captor = ArgumentCaptor.forClass(int[].class); + int phoneId = mPhone.getPhoneId(); + int subId = mPhone.getSubId(); + verify(mTelephonyRegistryManager).notifyPreciseCallState( + eq(phoneId), eq(subId), captor.capture(), eq(null), eq(null), eq(null)); + final int[] callStates = captor.getValue(); + assertEquals(3, callStates.length); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates[/*ringing call*/ 0]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates[/*foreground call*/ 1]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates[/*background call*/ 2]); doReturn(Call.State.ACTIVE).when(mForeGroundCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); - verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( - mPhone.getPhoneId(), - mPhone.getSubId(), - PreciseCallState.PRECISE_CALL_STATE_IDLE, - PreciseCallState.PRECISE_CALL_STATE_ACTIVE, - PreciseCallState.PRECISE_CALL_STATE_IDLE); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + ArgumentCaptor captor1 = ArgumentCaptor.forClass(int[].class); + phoneId = mPhone.getPhoneId(); + subId = mPhone.getSubId(); + verify(mTelephonyRegistryManager, times(2)).notifyPreciseCallState( + eq(phoneId), eq(subId), captor1.capture(), eq(null), eq(null), eq(null)); + final int[] callStates1 = captor1.getValue(); + assertEquals(3, callStates1.length); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates1[/*ringing call*/ 0]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + callStates1[/*foreground call*/ 1]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates1[/*background call*/ 2]); doReturn(Call.State.HOLDING).when(mBackGroundCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); - verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( - mPhone.getPhoneId(), - mPhone.getSubId(), - PreciseCallState.PRECISE_CALL_STATE_IDLE, - PreciseCallState.PRECISE_CALL_STATE_ACTIVE, - PreciseCallState.PRECISE_CALL_STATE_HOLDING); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + ArgumentCaptor captor2 = ArgumentCaptor.forClass(int[].class); + verify(mTelephonyRegistryManager, times(3)).notifyPreciseCallState( + eq(phoneId), eq(subId), captor2.capture(), eq(null), eq(null), eq(null)); + final int[] callStates2 = captor2.getValue(); + assertEquals(3, callStates2.length); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates2[/*ringing call*/ 0]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + callStates2[/*foreground call*/ 1]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, + callStates2[/*background call*/ 2]); doReturn(Call.State.ALERTING).when(mRingingCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + ArgumentCaptor captor3 = ArgumentCaptor.forClass(int[].class); + verify(mTelephonyRegistryManager, times(4)).notifyPreciseCallState( + eq(phoneId), eq(subId), captor3.capture(), eq(null), eq(null), eq(null)); + final int[] callStates3 = captor3.getValue(); + assertEquals(3, callStates3.length); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_ALERTING, + callStates3[/*ringing call*/ 0]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + callStates3[/*foreground call*/ 1]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, + callStates3[/*background call*/ 2]); + } + + @Test + public void testNotifyPreciseCallStateImsCallInfo() throws Exception { + //mock forground/background/ringing call and call state + doReturn(Call.State.ACTIVE).when(mImsForeGroundCall).getState(); + doReturn(Call.State.HOLDING).when(mImsBackGroundCall).getState(); + doReturn(Call.State.IDLE).when(mImsRingingCall).getState(); + + doReturn(mImsForeGroundCall).when(mImsPhone).getForegroundCall(); + doReturn(mImsBackGroundCall).when(mImsPhone).getBackgroundCall(); + doReturn(mImsRingingCall).when(mImsPhone).getRingingCall(); + + String[] imsCallIds = {null, "1", "2"}; + int[] imsCallServiceTypes = {ImsCallProfile.SERVICE_TYPE_NONE, + ImsCallProfile.SERVICE_TYPE_NORMAL, ImsCallProfile.SERVICE_TYPE_NORMAL}; + int[] imsCallTypes = {ImsCallProfile.CALL_TYPE_NONE, + ImsCallProfile.CALL_TYPE_VOICE, ImsCallProfile.CALL_TYPE_VT}; + + mDefaultPhoneNotifierUT + .notifyPreciseCallState(mImsPhone, imsCallIds, imsCallServiceTypes, imsCallTypes); + ArgumentCaptor callStateCaptor = ArgumentCaptor.forClass(int[].class); + ArgumentCaptor callIdCaptor = ArgumentCaptor.forClass(String[].class); + ArgumentCaptor callServiceTypeCaptor = ArgumentCaptor.forClass(int[].class); + ArgumentCaptor callTypeCaptor = ArgumentCaptor.forClass(int[].class); + int phoneId = mImsPhone.getPhoneId(); + int subId = mImsPhone.getSubId(); verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( - mPhone.getPhoneId(), - mPhone.getSubId(), - PreciseCallState.PRECISE_CALL_STATE_ALERTING, - PreciseCallState.PRECISE_CALL_STATE_ACTIVE, - PreciseCallState.PRECISE_CALL_STATE_HOLDING); + eq(phoneId), eq(subId), callStateCaptor.capture(), callIdCaptor.capture(), + callServiceTypeCaptor.capture(), callTypeCaptor.capture()); + final int[] callStates = callStateCaptor.getValue(); + final String[] callIds = callIdCaptor.getValue(); + final int[] callServiceTypes = callServiceTypeCaptor.getValue(); + final int[] callTypes = callTypeCaptor.getValue(); + assertEquals(3, callStates.length); + assertEquals(3, callIds.length); + assertEquals(3, callServiceTypes.length); + assertEquals(3, callServiceTypes.length); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates[/*ringing call*/ 0]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + callStates[/*foreground call*/ 1]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, + callStates[/*background call*/ 2]); + + assertEquals("1", callIds[/*foreground call*/ 1]); + assertEquals("2", callIds[/*background call*/ 2]); + assertEquals(null, callIds[/*ringing call*/ 0]); + assertEquals(ImsCallProfile.SERVICE_TYPE_NORMAL, + callServiceTypes[/*foreground call*/ 1]); + assertEquals(ImsCallProfile.SERVICE_TYPE_NORMAL, + callServiceTypes[/*background call*/ 2]); + assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, + callServiceTypes[/*ringing call*/ 0]); + assertEquals(ImsCallProfile.CALL_TYPE_VOICE, + callTypes[/*foreground call*/ 1]); + assertEquals(ImsCallProfile.CALL_TYPE_VT, + callTypes[/*background call*/ 2]); + assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, + callServiceTypes[/*ringing call*/ 0]); } @Test @SmallTest diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java index c2db93ff6c..13748e8ef3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony.imsphone; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; @@ -27,6 +28,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.telephony.ims.ImsCallProfile; +import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsStreamMediaProfile; import android.test.suitebuilder.annotation.SmallTest; @@ -256,6 +259,51 @@ public class ImsPhoneCallTest extends TelephonyTest { assertEquals(mImsCall, imsCall); } + @Test + @SmallTest + public void testGetCallSessionId() { + doReturn(mImsCall).when(mConnection1).getImsCall(); + ImsCallSession imsForegroundCallSession = mock(ImsCallSession.class); + doReturn(imsForegroundCallSession).when(mImsCall).getSession(); + doReturn("1").when(imsForegroundCallSession).getCallId(); + mImsCallUT.attach(mConnection1, Call.State.ACTIVE); + assertEquals("1", mImsCallUT.getCallSessionId()); + doReturn(null).when(mImsCall).getSession(); + assertNull(mImsCallUT.getCallSessionId()); + doReturn(null).when(mConnection1).getImsCall(); + assertNull(mImsCallUT.getCallSessionId()); + mImsCallUT.detach(mConnection1); + assertNull(mImsCallUT.getCallSessionId()); + } + + @Test + @SmallTest + public void testGetServiceType() { + doReturn(mImsCall).when(mConnection1).getImsCall(); + mImsCallUT.attach(mConnection1, Call.State.ACTIVE); + doReturn(false).when(mConnection1).isEmergencyCall(); + assertEquals(ImsCallProfile.SERVICE_TYPE_NORMAL, mImsCallUT.getServiceType()); + doReturn(true).when(mConnection1).isEmergencyCall(); + assertEquals(ImsCallProfile.SERVICE_TYPE_EMERGENCY, mImsCallUT.getServiceType()); + mImsCallUT.detach(mConnection1); + assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, mImsCallUT.getServiceType()); + } + + @Test + @SmallTest + public void testGetCallType() { + doReturn(mImsCall).when(mConnection1).getImsCall(); + mImsCallUT.attach(mConnection1, Call.State.ACTIVE); + doReturn(false).when(mImsCall).isVideoCall(); + assertEquals(ImsCallProfile.CALL_TYPE_VOICE, mImsCallUT.getCallType()); + doReturn(true).when(mImsCall).isVideoCall(); + assertEquals(ImsCallProfile.CALL_TYPE_VT, mImsCallUT.getCallType()); + doReturn(null).when(mConnection1).getImsCall(); + assertEquals(ImsCallProfile.CALL_TYPE_NONE, mImsCallUT.getCallType()); + mImsCallUT.detach(mConnection1); + assertEquals(ImsCallProfile.CALL_TYPE_NONE, mImsCallUT.getCallType()); + } + @Test @SmallTest public void testSetMute() { -- GitLab From 29c27573313edab5e12ef8dfa5279f1936fa68ac Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 22 Nov 2022 01:09:41 -0800 Subject: [PATCH 204/656] Use NR configs for minimum NR advanced bandwidth threshold Test: manual verify Test: atest NetworkTypeControllerTest Bug: 257135958 Bug: 260007418 Change-Id: I164b43d1dd5b491e22277bc7b5b99093f34b6e34 --- .../internal/telephony/NetworkTypeController.java | 15 +++++++++------ .../telephony/NetworkTypeControllerTest.java | 9 +++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index f846fa9441..2ecad3cdc5 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -513,7 +513,8 @@ public class NetworkTypeController extends StateMachine { int value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; if ((getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA || mServiceState.isUsingCarrierAggregation()) - && getBandwidth() > mLtePlusThresholdBandwidth) { + && IntStream.of(mServiceState.getCellBandwidths()).sum() + > mLtePlusThresholdBandwidth) { value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA; } if (isLteEnhancedAvailable()) { @@ -1275,9 +1276,15 @@ public class NetworkTypeController extends StateMachine { return false; } + int bandwidths = mPhone.getServiceStateTracker().getPhysicalChannelConfigList() + .stream() + .filter(config -> config.getNetworkType() == TelephonyManager.NETWORK_TYPE_NR) + .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) + .mapToInt(Integer::intValue) + .sum(); // Check if meeting minimum bandwidth requirement. For most carriers, there is no minimum // bandwidth requirement and mNrAdvancedThresholdBandwidth is 0. - if (mNrAdvancedThresholdBandwidth > 0 && getBandwidth() < mNrAdvancedThresholdBandwidth) { + if (mNrAdvancedThresholdBandwidth > 0 && bandwidths < mNrAdvancedThresholdBandwidth) { return false; } @@ -1325,10 +1332,6 @@ public class NetworkTypeController extends StateMachine { : nri.getAccessNetworkTechnology(); } - private int getBandwidth() { - return IntStream.of(mServiceState.getCellBandwidths()).sum(); - } - private String getEventName(int event) { try { return sEvents[event]; diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index 91d936d7cf..bf6297870e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -1240,11 +1240,16 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - doReturn(new int[] {20001}).when(mServiceState).getCellBandwidths(); + List lastPhysicalChannelConfigList = new ArrayList<>(); + lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() + .setNetworkType(TelephonyManager.NETWORK_TYPE_NR) + .setCellBandwidthDownlinkKhz(20001) + .build()); + doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } -- GitLab From 86156914d04bc5efa5d69ef38e6c353e6831f00e Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 17 Nov 2022 14:25:16 -0800 Subject: [PATCH 205/656] Relax anomaly report for duplicate interface Only report if the existing network is connected. Test: basic voice call + data browsing Bug: 249922254 Change-Id: Iab541d6946cc72ee29a9d1438364b4921bc49e22 --- src/java/com/android/internal/telephony/data/DataNetwork.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index e122591c9a..ce7e72ece9 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -2406,7 +2406,7 @@ public class DataNetwork extends StateMachine { + dataNetwork + ". Silently tear down now."); // If this is a pre-5G data setup, that means APN database has some problems. For // example, different APN settings have the same APN name. - if (response.getTrafficDescriptors().isEmpty()) { + if (response.getTrafficDescriptors().isEmpty() && dataNetwork.isConnected()) { reportAnomaly("Duplicate network interface " + response.getInterfaceName() + " detected.", "62f66e7e-8d71-45de-a57b-dc5c78223fd5"); } -- GitLab From 363f99b518c9e709a2725a8507a82b9970b879a3 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 22 Nov 2022 20:49:37 -0800 Subject: [PATCH 206/656] Added addSubInfo support 1. Added addSubInfo support. 2. Added subscription manager service callback. Bug: 239607619 Test: atest SubscriptionManagerServiceTest Change-Id: I1e494f9229e2b8d0b9e21aa56c69008e13d1ff7b --- .../internal/telephony/CarrierResolver.java | 8 +- .../internal/telephony/GsmCdmaPhone.java | 15 +- .../com/android/internal/telephony/Phone.java | 5 + .../SubscriptionDatabaseManager.java | 370 ++++++++++-------- .../SubscriptionManagerService.java | 249 +++++++++++- .../SubscriptionDatabaseManagerTest.java | 6 +- .../SubscriptionManagerServiceTest.java | 110 ++++++ 7 files changed, 596 insertions(+), 167 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java diff --git a/src/java/com/android/internal/telephony/CarrierResolver.java b/src/java/com/android/internal/telephony/CarrierResolver.java index 7f1d349804..4036cd9aae 100644 --- a/src/java/com/android/internal/telephony/CarrierResolver.java +++ b/src/java/com/android/internal/telephony/CarrierResolver.java @@ -43,6 +43,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.metrics.CarrierIdMatchStats; import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.util.TelephonyUtils; @@ -548,7 +549,12 @@ public class CarrierResolver extends Handler { // subscriptioninfo db to make sure we have correct carrier id set. if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId()) && !isSimOverride) { // only persist carrier id to simInfo db when subId is valid. - SubscriptionController.getInstance().setCarrierId(mCarrierId, mPhone.getSubId()); + if (mPhone.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().setCarrierId(mPhone.getSubId(), + mCarrierId); + } else { + SubscriptionController.getInstance().setCarrierId(mCarrierId, mPhone.getSubId()); + } } } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 175824c219..fe0f328eeb 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -104,6 +104,7 @@ import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.imsphone.ImsPhoneMmiCode; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.metrics.VoiceCallSessionStats; +import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; import com.android.internal.telephony.test.SimulatedRadioControl; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; import com.android.internal.telephony.uicc.IccCardStatus; @@ -349,8 +350,18 @@ public class GsmCdmaPhone extends Phone { mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, null); - SubscriptionController.getInstance().registerForUiccAppsEnabled(this, - EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false); + if (isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService.registerCallback(new SubscriptionManagerServiceCallback( + this::post) { + @Override + public void onUiccApplicationsEnabled(int subId) { + reapplyUiccAppsEnablementIfNeeded(ENABLE_UICC_APPS_MAX_RETRIES); + } + }); + } else { + SubscriptionController.getInstance().registerForUiccAppsEnabled(this, + EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false); + } mLinkBandwidthEstimator = mTelephonyComponentFactory .inject(LinkBandwidthEstimator.class.getName()) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index b17282be5d..9064ddf3cd 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -444,6 +444,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected final Context mContext; + protected SubscriptionManagerService mSubscriptionManagerService; + /** * PhoneNotifier is an abstraction for all system-wide * state change notification. DefaultPhoneNotifier is @@ -616,6 +618,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mIsSubscriptionManagerServiceEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_using_subscription_manager_service); + if (isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); + } // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers. mTelephonyComponentFactory = telephonyComponentFactory; diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 374f9e9b7d..b0f5b87010 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -49,7 +49,9 @@ import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.AbstractMap; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.Executor; @@ -77,6 +79,155 @@ public class SubscriptionDatabaseManager extends Handler { /** Invalid database row index. */ private static final int INVALID_ROW_INDEX = -1; + /** The mapping from {@link SimInfo} table to {@link SubscriptionInfoInternal} get methods. */ + private static final Map> + SUBSCRIPTION_GET_METHOD_MAP = Map.ofEntries( + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, + SubscriptionInfoInternal::getSubscriptionId), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ICC_ID, + SubscriptionInfoInternal::getIccId), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_SIM_SLOT_INDEX, + SubscriptionInfoInternal::getSimSlotIndex), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_DISPLAY_NAME, + SubscriptionInfoInternal::getDisplayName), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CARRIER_NAME, + SubscriptionInfoInternal::getCarrierName), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_NAME_SOURCE, + SubscriptionInfoInternal::getDisplayNameSource), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_COLOR, + SubscriptionInfoInternal::getIconTint), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_NUMBER, + SubscriptionInfoInternal::getNumber), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_DATA_ROAMING, + SubscriptionInfoInternal::getDataRoaming), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_MCC_STRING, + SubscriptionInfoInternal::getMcc), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_MNC_STRING, + SubscriptionInfoInternal::getMnc), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_EHPLMNS, + SubscriptionInfoInternal::getEhplmns), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_HPLMNS, + SubscriptionInfoInternal::getHplmns), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_EMBEDDED, + SubscriptionInfoInternal::getEmbedded), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CARD_ID, + SubscriptionInfoInternal::getCardString), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ACCESS_RULES, + SubscriptionInfoInternal::getNativeAccessRules), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, + SubscriptionInfoInternal::getCarrierConfigAccessRules), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_REMOVABLE, + SubscriptionInfoInternal::getRemovableEmbedded), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, + SubscriptionInfoInternal::getEnhanced4GModeEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_VT_IMS_ENABLED, + SubscriptionInfoInternal::getVideoTelephonyEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_ENABLED, + SubscriptionInfoInternal::getWifiCallingEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_MODE, + SubscriptionInfoInternal::getWifiCallingMode), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, + SubscriptionInfoInternal::getWifiCallingModeForRoaming), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, + SubscriptionInfoInternal::getWifiCallingEnabledForRoaming), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_OPPORTUNISTIC, + SubscriptionInfoInternal::getOpportunistic), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_GROUP_UUID, + SubscriptionInfoInternal::getGroupUuid), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ISO_COUNTRY_CODE, + SubscriptionInfoInternal::getCountryIso), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CARRIER_ID, + SubscriptionInfoInternal::getCarrierId), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PROFILE_CLASS, + SubscriptionInfoInternal::getProfileClass), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_SUBSCRIPTION_TYPE, + SubscriptionInfoInternal::getSubscriptionType), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_GROUP_OWNER, + SubscriptionInfoInternal::getGroupOwner), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, + SubscriptionInfoInternal::getEnabledMobileDataPolicies), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IMSI, + SubscriptionInfoInternal::getImsi), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED, + SubscriptionInfoInternal::getUiccApplicationsEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, + SubscriptionInfoInternal::getRcsUceEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, + SubscriptionInfoInternal::getCrossSimCallingEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_RCS_CONFIG, + SubscriptionInfoInternal::getRcsConfig), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, + SubscriptionInfoInternal::getAllowedNetworkTypesForReasons), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_D2D_STATUS_SHARING, + SubscriptionInfoInternal::getDeviceToDeviceStatusSharingPreference), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, + SubscriptionInfoInternal::getVoImsOptInEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + SubscriptionInfoInternal::getDeviceToDeviceStatusSharingContacts), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, + SubscriptionInfoInternal::getNrAdvancedCallingEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER, + SubscriptionInfoInternal::getNumberFromCarrier), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS, + SubscriptionInfoInternal::getNumberFromIms), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PORT_INDEX, + SubscriptionInfoInternal::getPortIndex), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_USAGE_SETTING, + SubscriptionInfoInternal::getUsageSetting), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_TP_MESSAGE_REF, + SubscriptionInfoInternal::getLastUsedTPMessageReference), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_USER_HANDLE, + SubscriptionInfoInternal::getUserId) + ); + /** The context */ @NonNull private final Context mContext; @@ -85,9 +236,6 @@ public class SubscriptionDatabaseManager extends Handler { @NonNull private final SubscriptionDatabaseManagerCallback mCallback; - /** Telephony manager */ - private final TelephonyManager mTelephonyManager; - /** UICC controller */ private final UiccController mUiccController; @@ -116,154 +264,8 @@ public class SubscriptionDatabaseManager extends Handler { private final Map mAllSubscriptionInfoInternalCache = new HashMap<>(16); - /** The mapping from {@link SimInfo} table to {@link SubscriptionInfoInternal} get methods. */ - private static final Map> - SUBSCRIPTION_GET_METHOD_MAP = Map.ofEntries( - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, - SubscriptionInfoInternal::getSubscriptionId), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_ICC_ID, - SubscriptionInfoInternal::getIccId), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_SIM_SLOT_INDEX, - SubscriptionInfoInternal::getSimSlotIndex), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_DISPLAY_NAME, - SubscriptionInfoInternal::getDisplayName), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_CARRIER_NAME, - SubscriptionInfoInternal::getCarrierName), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_NAME_SOURCE, - SubscriptionInfoInternal::getDisplayNameSource), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_COLOR, - SubscriptionInfoInternal::getIconTint), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_NUMBER, - SubscriptionInfoInternal::getNumber), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_DATA_ROAMING, - SubscriptionInfoInternal::getDataRoaming), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_MCC_STRING, - SubscriptionInfoInternal::getMcc), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_MNC_STRING, - SubscriptionInfoInternal::getMnc), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_EHPLMNS, - SubscriptionInfoInternal::getEhplmns), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_HPLMNS, - SubscriptionInfoInternal::getHplmns), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_IS_EMBEDDED, - SubscriptionInfoInternal::getEmbedded), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_CARD_ID, - SubscriptionInfoInternal::getCardString), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_ACCESS_RULES, - SubscriptionInfoInternal::getNativeAccessRules), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, - SubscriptionInfoInternal::getCarrierConfigAccessRules), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_IS_REMOVABLE, - SubscriptionInfoInternal::getRemovableEmbedded), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, - SubscriptionInfoInternal::getEnhanced4GModeEnabled), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_VT_IMS_ENABLED, - SubscriptionInfoInternal::getVideoTelephonyEnabled), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_WFC_IMS_ENABLED, - SubscriptionInfoInternal::getWifiCallingEnabled), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_WFC_IMS_MODE, - SubscriptionInfoInternal::getWifiCallingMode), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, - SubscriptionInfoInternal::getWifiCallingModeForRoaming), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, - SubscriptionInfoInternal::getWifiCallingEnabledForRoaming), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_IS_OPPORTUNISTIC, - SubscriptionInfoInternal::getOpportunistic), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_GROUP_UUID, - SubscriptionInfoInternal::getGroupUuid), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_ISO_COUNTRY_CODE, - SubscriptionInfoInternal::getCountryIso), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_CARRIER_ID, - SubscriptionInfoInternal::getCarrierId), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_PROFILE_CLASS, - SubscriptionInfoInternal::getProfileClass), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_SUBSCRIPTION_TYPE, - SubscriptionInfoInternal::getSubscriptionType), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_GROUP_OWNER, - SubscriptionInfoInternal::getGroupOwner), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, - SubscriptionInfoInternal::getEnabledMobileDataPolicies), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_IMSI, - SubscriptionInfoInternal::getImsi), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED, - SubscriptionInfoInternal::getUiccApplicationsEnabled), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, - SubscriptionInfoInternal::getRcsUceEnabled), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, - SubscriptionInfoInternal::getCrossSimCallingEnabled), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_RCS_CONFIG, - SubscriptionInfoInternal::getRcsConfig), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, - SubscriptionInfoInternal::getAllowedNetworkTypesForReasons), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_D2D_STATUS_SHARING, - SubscriptionInfoInternal::getDeviceToDeviceStatusSharingPreference), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, - SubscriptionInfoInternal::getVoImsOptInEnabled), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, - SubscriptionInfoInternal::getDeviceToDeviceStatusSharingContacts), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, - SubscriptionInfoInternal::getNrAdvancedCallingEnabled), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER, - SubscriptionInfoInternal::getNumberFromCarrier), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS, - SubscriptionInfoInternal::getNumberFromIms), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_PORT_INDEX, - SubscriptionInfoInternal::getPortIndex), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_USAGE_SETTING, - SubscriptionInfoInternal::getUsageSetting), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_TP_MESSAGE_REF, - SubscriptionInfoInternal::getLastUsedTPMessageReference), - new AbstractMap.SimpleImmutableEntry<>( - SimInfo.COLUMN_USER_HANDLE, - SubscriptionInfoInternal::getUserId) - ); + /** Whether database has been loaded into the cache after boot up. */ + private boolean mDatabaseLoaded = false; /** * This is the callback used for listening events from {@link SubscriptionDatabaseManager}. @@ -298,12 +300,25 @@ public class SubscriptionDatabaseManager extends Handler { mExecutor.execute(runnable); } + /** + * Called when database has been loaded into the cache. + */ + public abstract void onDatabaseLoaded(); + /** * Called when subscription changed. * * @param subId The subscription id. */ public abstract void onSubscriptionChanged(int subId); + + /** + * Called when {@link SubscriptionInfoInternal#areUiccApplicationsEnabled()} + * changed. + * + * @param subId The subscription id. + */ + public abstract void onUiccApplicationsEnabled(int subId); } /** @@ -318,7 +333,6 @@ public class SubscriptionDatabaseManager extends Handler { super(looper); mContext = context; mCallback = callback; - mTelephonyManager = mContext.getSystemService(TelephonyManager.class); mUiccController = UiccController.getInstance(); loadFromDatabase(); } @@ -414,6 +428,11 @@ public class SubscriptionDatabaseManager extends Handler { + "insert. subInfo=" + subInfo); } + if (!mDatabaseLoaded) { + throw new IllegalStateException("Database has not been loaded. Can't insert new " + + "record at this point."); + } + int subId; // Grab the write lock so no other threads can read or write the cache. mReadWriteLock.writeLock().lock(); @@ -447,6 +466,12 @@ public class SubscriptionDatabaseManager extends Handler { private void updateDatabaseAsync(int subId, @NonNull ContentValues contentValues) { logv("updateDatabaseAsync: prepare to update sub " + subId); // Perform the update in the handler thread asynchronously. + + if (!mDatabaseLoaded) { + throw new IllegalStateException("Database has not been loaded. Can't update " + + "database at this point. contentValues=" + contentValues); + } + post(() -> { int rowsUpdated = mContext.getContentResolver().update(Uri.withAppendedPath( SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null); @@ -535,6 +560,10 @@ public class SubscriptionDatabaseManager extends Handler { if (oldSubInfo.equals(newSubInfo)) return; mAllSubscriptionInfoInternalCache.put(subId, newSubInfo); mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); + if (oldSubInfo.areUiccApplicationsEnabled() + != newSubInfo.areUiccApplicationsEnabled()) { + mCallback.invokeFromExecutor(() -> mCallback.onUiccApplicationsEnabled(subId)); + } // Writing into the database is slow. So do this asynchronously. updateDatabaseAsync(subId, createDeltaContentValues(oldSubInfo, newSubInfo)); } finally { @@ -1176,6 +1205,8 @@ public class SubscriptionDatabaseManager extends Handler { .put(subInfo.getSubscriptionId(), subInfo); } } + mDatabaseLoaded = true; + mCallback.invokeFromExecutor(mCallback::onDatabaseLoaded); log("Loaded " + mAllSubscriptionInfoInternalCache.size() + " records from the subscription database."); } finally { @@ -1311,7 +1342,7 @@ public class SubscriptionDatabaseManager extends Handler { /** * Get the subscription info by subscription id. * - * @param subId The subscription id + * @param subId The subscription id. * * @return The subscription info. {@code null} if not found. */ @@ -1325,6 +1356,39 @@ public class SubscriptionDatabaseManager extends Handler { } } + /** + * @return All subscription infos in the database. + */ + @NonNull + public List getAllSubscriptions() { + return new ArrayList<>(mAllSubscriptionInfoInternalCache.values()); + } + + /** + * Get subscription info by ICCID. + * + * @param iccId The ICCID of the SIM card. + * @return The subscription info if found. {@code null} if not found. + */ + @Nullable + public SubscriptionInfoInternal getSubscriptionInfoInternalByIccId(@NonNull String iccId) { + mReadWriteLock.readLock().lock(); + try { + return mAllSubscriptionInfoInternalCache.values().stream() + .filter(subInfo -> subInfo.getIccId().equals(iccId)) + .findFirst() + .orElse(null); + } finally { + mReadWriteLock.readLock().unlock(); + } + } + + /** + * @return {@code true} if the database has been loaded into the cache. + */ + public boolean isDatabaseLoaded() { + return mDatabaseLoaded; + } /** * Log debug messages. * diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index eca1bfdf07..1244c85bf6 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -16,9 +16,13 @@ package com.android.internal.telephony.subscription; +import android.Manifest; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -30,14 +34,19 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.TelephonyFrameworkInitializer; +import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; +import android.text.TextUtils; +import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.LocalLog; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; +import com.android.internal.telephony.uicc.IccUtils; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -47,6 +56,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; /** * The subscription manager service is the backend service of {@link SubscriptionManager}. @@ -58,18 +68,34 @@ public class SubscriptionManagerService extends ISub.Stub { /** Whether enabling verbose debugging message or not. */ private static final boolean VDBG = false; + /** Instance of subscription manager service. */ + @NonNull + private static SubscriptionManagerService sInstance; + /** The context */ + @NonNull private final Context mContext; /** The main handler of subscription manager service. */ + @NonNull private final Handler mHandler; /** Local log for most important debug messages. */ + @NonNull private final LocalLog mLocalLog = new LocalLog(128); /** The subscription database manager. */ + @NonNull private final SubscriptionDatabaseManager mSubscriptionDatabaseManager; + @NonNull + private final WatchedSlotIndexToSubId mSlotIndexToSubId = new WatchedSlotIndexToSubId(); + + /** Subscription manager service callbacks. */ + @NonNull + private final Set mSubscriptionManagerServiceCallbacks = + new ArraySet<>(); + /** * Watched slot index to sub id map. */ @@ -142,7 +168,55 @@ public class SubscriptionManagerService extends ISub.Stub { } } - private final WatchedSlotIndexToSubId mSlotIndexToSubId = new WatchedSlotIndexToSubId(); + /** + * This is the callback used for listening events from {@link SubscriptionManagerService}. + */ + public static class SubscriptionManagerServiceCallback { + /** The executor of the callback. */ + @NonNull + private final Executor mExecutor; + + /** + * Constructor + * + * @param executor The executor of the callback. + */ + public SubscriptionManagerServiceCallback(@NonNull @CallbackExecutor Executor executor) { + mExecutor = executor; + } + + /** + * @return The executor of the callback. + */ + @NonNull + @VisibleForTesting + public Executor getExecutor() { + return mExecutor; + } + + /** + * Invoke the callback from executor. + * + * @param runnable The callback method to invoke. + */ + public void invokeFromExecutor(@NonNull Runnable runnable) { + mExecutor.execute(runnable); + } + + /** + * Called when subscription changed. + * + * @param subId The subscription id. + */ + public void onSubscriptionChanged(int subId) {} + + /** + * Called when {@link SubscriptionInfoInternal#areUiccApplicationsEnabled()} changed. + * + * @param subId The subscription id. + */ + public void onUiccApplicationsEnabled(int subId) {} + } /** * The constructor @@ -151,13 +225,16 @@ public class SubscriptionManagerService extends ISub.Stub { * @param looper The looper for the handler. */ public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper) { + sInstance = this; mContext = context; mHandler = new Handler(looper); TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = TelephonyFrameworkInitializer .getTelephonyServiceManager() .getSubscriptionServiceRegisterer(); - subscriptionServiceRegisterer.register(this); + if (subscriptionServiceRegisterer.get() == null) { + subscriptionServiceRegisterer.register(this); + } // Create a separate thread for subscription database manager. The database will be updated // from a different thread. @@ -165,6 +242,14 @@ public class SubscriptionManagerService extends ISub.Stub { handlerThread.start(); mSubscriptionDatabaseManager = new SubscriptionDatabaseManager(context, handlerThread.getLooper(), new SubscriptionDatabaseManagerCallback(mHandler::post) { + /** + * Called when database has been loaded into the cache. + */ + @Override + public void onDatabaseLoaded() { + log("Subscription database has been loaded."); + } + /** * Called when subscription changed. * @@ -172,6 +257,10 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public void onSubscriptionChanged(int subId) { + mSubscriptionManagerServiceCallbacks.forEach( + callback -> callback.invokeFromExecutor( + () -> callback.onSubscriptionChanged(subId))); + MultiSimSettingController.getInstance().notifySubscriptionInfoChanged(); TelephonyRegistryManager telephonyRegistryManager = @@ -190,9 +279,43 @@ public class SubscriptionManagerService extends ISub.Stub { // TODO: Call TelephonyMetrics.updateActiveSubscriptionInfoList when active // subscription changes. } + + /** + * Called when {@link SubscriptionInfoInternal#areUiccApplicationsEnabled()} + * changed. + * + * @param subId The subscription id. + */ + @Override + public void onUiccApplicationsEnabled(int subId) { + log("onUiccApplicationsEnabled: subId=" + subId); + mSubscriptionManagerServiceCallbacks.forEach( + callback -> callback.invokeFromExecutor( + () -> callback.onUiccApplicationsEnabled(subId))); + } }); } + /** + * @return The singleton instance of {@link SubscriptionManagerService}. + */ + @NonNull + public static SubscriptionManagerService getInstance() { + return sInstance; + } + + /** + * Set the subscription carrier id. + * + * @param subId Subscription id. + * @param carrierId The carrier id. + * + * @see TelephonyManager#getSimCarrierId() + */ + public void setCarrierId(int subId, int carrierId) { + mSubscriptionDatabaseManager.setCarrierId(subId, carrierId); + } + /** * @param callingPackage The package making the call. * @param callingFeatureId The feature in the package @@ -330,20 +453,70 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Add a new subscription info record, if needed. + * Add a new subscription info record, if needed. This should be only used for remote SIM. * - * @param uniqueId This is the unique identifier for the subscription within the specific - * subscription type - * @param displayName human-readable name of the device the subscription corresponds to - * @param slotIndex the slot assigned to this device + * @param iccId ICCID of the SIM card. + * @param displayName human-readable name of the device the subscription corresponds to. + * @param slotIndex the logical SIM slot index assigned to this device. * @param subscriptionType the type of subscription to be added * * @return 0 if success, < 0 on error */ @Override - public int addSubInfo(@NonNull String uniqueId, @NonNull String displayName, int slotIndex, + public int addSubInfo(@NonNull String iccId, @NonNull String displayName, int slotIndex, @SubscriptionType int subscriptionType) { + log("addSubInfo: iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + ", slotIndex=" + + slotIndex + ", displayName=" + displayName + ", type=" + + SubscriptionManager.subscriptionTypeToString(subscriptionType)); + enforceModifyPhoneState("addSubInfo"); + + // Now that all security checks passes, perform the operation as ourselves. + final long identity = Binder.clearCallingIdentity(); + try { + if (TextUtils.isEmpty(iccId)) { + loge("addSubInfo: null or empty iccId"); + return -1; + } + + if (subscriptionType != SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM + || !mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_AUTOMOTIVE)) { + loge("addSubInfo: remote SIM is only supported when FEATURE_AUTOMOTIVE is " + + "enabled."); + return -1; + } + + if (slotIndex != SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB) { + loge("addSubInfo: This API can only be used for remote SIM. slotIndex=" + + slotIndex); + return -1; + } + + iccId = IccUtils.stripTrailingFs(iccId); + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternalByIccId(iccId); + + // Check if the record exists or not. + if (subInfo == null) { + // Record does not exist. + mSubscriptionDatabaseManager.insertSubscriptionInfo( + new SubscriptionInfoInternal.Builder() + .setIccId(iccId) + .setSimSlotIndex(slotIndex) + .setDisplayName(displayName) + .setType(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM) + .build() + ); + } else { + // Record already exists. + loge("Subscription record already existed."); + return -1; + } + } finally { + Binder.restoreCallingIdentity(identity); + } return 0; + } /** @@ -700,6 +873,66 @@ public class SubscriptionManagerService extends ISub.Stub { return null; } + /** + * Register the callback for receiving information from {@link SubscriptionManagerService}. + * + * @param callback The callback. + */ + public void registerCallback(@NonNull SubscriptionManagerServiceCallback callback) { + mSubscriptionManagerServiceCallbacks.add(callback); + } + + /** + * Unregister the previously registered {@link SubscriptionManagerServiceCallback}. + * + * @param callback The callback to unregister. + */ + public void unregisterCallback(@NonNull SubscriptionManagerServiceCallback callback) { + mSubscriptionManagerServiceCallbacks.remove(callback); + } + + /** + * Enforce {@link android.Manifest.permission#MODIFY_PHONE_STATE} permission + * + * @param message Error message included in the exception. + */ + private void enforceModifyPhoneState(String message) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MODIFY_PHONE_STATE, message); + } + + /** + * Enforce {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} permission + * + * @param message Error message included in the exception. + */ + private void enforceReadPrivilegedPhoneState(String message) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message); + } + + /** + * Enforce {@link android.Manifest.permission#MANAGE_SUBSCRIPTION_USER_ASSOCIATION} permission + * + * @param message Error message included in the exception. + */ + private void enforceManageSubscriptionUserAssociation(String message) { + mContext.enforceCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION, message); + } + + /** + * Get the subscription info by subscription id. + * + * @param subId The subscription id. + * + * @return The subscription info. {@code null} if not found. + */ + @Nullable + public SubscriptionInfoInternal getSubscriptionInfoInternal(int subId) { + return mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subId); + } + /** * Log debug messages. * 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 7dc51937d8..c72efd09a3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -109,7 +109,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { static final int FAKE_USER_ID1 = 10; static final int FAKE_USER_ID2 = 11; - private static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO1 = + static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO1 = new SubscriptionInfoInternal.Builder() .setIccId(FAKE_ICCID1) .setSimSlotIndex(0) @@ -163,7 +163,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setGroupDisabled(false) .build(); - private static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO2 = + static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO2 = new SubscriptionInfoInternal.Builder() .setIccId(FAKE_ICCID2) .setSimSlotIndex(1) @@ -224,7 +224,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { //mock private SubscriptionDatabaseManagerCallback mSubscriptionDatabaseManagerCallback; - private static class SubscriptionProvider extends MockContentProvider { + static class SubscriptionProvider extends MockContentProvider { private final List mDatabase = new ArrayList<>(); private final List mAllColumns; diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java new file mode 100644 index 0000000000..ac082c2785 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2022 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.subscription; + +import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID1; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.content.pm.PackageManager; +import android.os.Looper; +import android.provider.Telephony; +import android.telephony.SubscriptionManager; +import android.test.mock.MockContentResolver; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider; +import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class SubscriptionManagerServiceTest extends TelephonyTest { + + private SubscriptionManagerService mSubscriptionManagerServiceUT; + + private final SubscriptionProvider mSubscriptionProvider = new SubscriptionProvider(); + + // mocked + private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback; + + @Before + public void setUp() throws Exception { + logd("SubscriptionManagerServiceTest +Setup!"); + super.setUp(getClass().getSimpleName()); + + mMockedSubscriptionManagerServiceCallback = Mockito.mock( + SubscriptionManagerServiceCallback.class); + ((MockContentResolver) mContext.getContentResolver()).addProvider( + Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); + mSubscriptionManagerServiceUT = new SubscriptionManagerService(mContext, Looper.myLooper()); + + doAnswer(invocation -> { + ((Runnable) invocation.getArguments()[0]).run(); + return null; + }).when(mMockedSubscriptionManagerServiceCallback).invokeFromExecutor(any(Runnable.class)); + + mSubscriptionManagerServiceUT.registerCallback(mMockedSubscriptionManagerServiceCallback); + // Database loading is on a different thread. Need to wait a bit. + waitForMs(100); + processAllFutureMessages(); + + logd("SubscriptionManagerServiceTest -Setup!"); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testAddSubInfo() { + doReturn(true).when(mPackageManager).hasSystemFeature( + PackageManager.FEATURE_AUTOMOTIVE); + + mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, + SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB, + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); + processAllMessages(); + + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID1); + assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); + assertThat(subInfo.getSimSlotIndex()).isEqualTo( + SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB); + assertThat(subInfo.getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); + } +} -- GitLab From f84f58959f907d2c082127b96f78eb02e43bf5a7 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 22 Nov 2022 17:21:01 -0800 Subject: [PATCH 207/656] Improve auto data switch related log Test: manual toggle settings during voice call Change-Id: If05dd11051deea0a70a9aad129bcfa4ef487474a --- .../telephony/data/PhoneSwitcher.java | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index b1552cdef0..4584592938 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -212,8 +212,8 @@ public class PhoneSwitcher extends Handler { @VisibleForTesting protected final CellularNetworkValidator mValidator; private int mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; - /** The last reason for auto switch (e.g. CBRS) **/ - private int mLastAutoSelectedSwitchReason = -1; + /** The reason for the last time changing preferred data sub **/ + private int mLastSwitchPreferredDataReason = -1; /** {@code true} if we've displayed the notification the first time auto switch occurs **/ private boolean mDisplayedAutoSwitchNotification = false; private boolean mPendingSwitchNeedValidation; @@ -579,8 +579,6 @@ public class PhoneSwitcher extends Handler { @TelephonyManager.DataEnabledChangedReason int reason, @NonNull String callingPackage) { logl("user changed data settings"); - evaluateIfImmediateDataSwitchIsNeeded("user changed data settings", - DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); evaluateIfAutoSwitchIsNeeded(); }}); phone.getDataSettingsManager().registerCallback( @@ -1130,6 +1128,15 @@ public class PhoneSwitcher extends Handler { if (mPreferredDataPhoneId == primaryPhoneId) { // on primary data sub + + if (isAnyVoiceCallActiveOnDevice()) { + // if on voice call, switch immediately + evaluateIfImmediateDataSwitchIsNeeded( + "user updates data settings during voice call", + DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); + return; + } + int candidateSubId = getAutoSwitchTargetSubIdIfExists(); if (candidateSubId != INVALID_SUBSCRIPTION_ID) { startAutoDataSwitchStabilityCheck(candidateSubId, true); @@ -1144,7 +1151,7 @@ public class PhoneSwitcher extends Handler { // immediately switch back if user setting changes mAutoSelectedDataSubId = DEFAULT_SUBSCRIPTION_ID; evaluateIfImmediateDataSwitchIsNeeded("User disabled data settings", - DataSwitch.Reason.DATA_SWITCH_REASON_AUTO); + DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL); return; } @@ -1298,6 +1305,7 @@ public class PhoneSwitcher extends Handler { sb.append(" mPrimaryDataSubId ").append(mPrimaryDataSubId).append("->") .append(primaryDataSubId); mPrimaryDataSubId = primaryDataSubId; + mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL; } // Check to see if there is any active subscription on any phone @@ -1592,11 +1600,13 @@ public class PhoneSwitcher extends Handler { logl("updatePreferredDataPhoneId: preferred data overridden for emergency." + " phoneId = " + mEmergencyOverride.mPhoneId); mPreferredDataPhoneId = mEmergencyOverride.mPhoneId; + mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; } else if (isDataEnabled) { // If a phone is in call and user enabled its mobile data, we // should switch internet connection to it. Because the other modem // will lose data connection anyway. mPreferredDataPhoneId = mPhoneIdInVoiceCall; + mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL; } else { int subId = getSubIdForDefaultNetworkRequests(); int phoneId = SubscriptionManager.INVALID_PHONE_INDEX; @@ -1757,7 +1767,7 @@ public class PhoneSwitcher extends Handler { return; } - mLastAutoSelectedSwitchReason = switchReason; + mLastSwitchPreferredDataReason = switchReason; logDataSwitchEvent(subIdToValidate, TelephonyEvent.EventState.EVENT_STATE_START, switchReason); @@ -1817,7 +1827,7 @@ public class PhoneSwitcher extends Handler { private void setAutoSelectedDataSubIdInternal(int subId) { if (mAutoSelectedDataSubId != subId) { mAutoSelectedDataSubId = subId; - onEvaluate(REQUESTS_UNCHANGED, switchReasonToString(mLastAutoSelectedSwitchReason)); + onEvaluate(REQUESTS_UNCHANGED, switchReasonToString(mLastSwitchPreferredDataReason)); } } @@ -1832,7 +1842,7 @@ public class PhoneSwitcher extends Handler { resultForCallBack = SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; // retry for auto data switch validation failure - if (mLastAutoSelectedSwitchReason == DataSwitch.Reason.DATA_SWITCH_REASON_AUTO) { + if (mLastSwitchPreferredDataReason == DataSwitch.Reason.DATA_SWITCH_REASON_AUTO) { scheduleAutoSwitchRetryEvaluation(); mAutoSwitchRetryFailedCount++; } @@ -2075,6 +2085,8 @@ public class PhoneSwitcher extends Handler { pw.println("mAutoDataSwitchAvailabilityStabilityTimeThreshold=" + mAutoDataSwitchAvailabilityStabilityTimeThreshold); pw.println("mAutoDataSwitchValidationMaxRetry=" + mAutoDataSwitchValidationMaxRetry); + pw.println("mLastSwitchPreferredDataReason=" + + switchReasonToString(mLastSwitchPreferredDataReason)); pw.println("mDisplayedAutoSwitchNotification=" + mDisplayedAutoSwitchNotification); pw.println("Local logs:"); pw.increaseIndent(); @@ -2141,16 +2153,17 @@ public class PhoneSwitcher extends Handler { AUTO_DATA_SWITCH_NOTIFICATION_ID); return; } - // proceed only the first time auto data switch occurs - if (mLastAutoSelectedSwitchReason != DataSwitch.Reason.DATA_SWITCH_REASON_AUTO) { + // proceed only the first time auto data switch occurs, which includes data during call + if (mLastSwitchPreferredDataReason != DataSwitch.Reason.DATA_SWITCH_REASON_AUTO) { log("displayAutoDataSwitchNotification: Ignore DDS switch due to " - + switchReasonToString(mLastAutoSelectedSwitchReason)); + + switchReasonToString(mLastSwitchPreferredDataReason)); return; } SubscriptionInfo subInfo = mSubscriptionController.getSubscriptionInfo( mAutoSelectedDataSubId); if (subInfo == null || subInfo.isOpportunistic()) { - loge("displayAutoDataSwitchNotification: unexpected " + subInfo); + loge("displayAutoDataSwitchNotification:mAutoSelectedDataSubId=" + + mAutoSelectedDataSubId + " unexpected subInfo " + subInfo); return; } logl("displayAutoDataSwitchNotification: display for subId=" + mAutoSelectedDataSubId); -- GitLab From f14b9c6f0b65dd8492bebb0969810a49ddd9097c Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 22 Nov 2022 22:19:41 -0800 Subject: [PATCH 208/656] Added set MCC, MNC, country code support Bug: 239607619 Test: atest SubscriptionManagerServiceTest Change-Id: I5b1d5e1a706227bd9e2a7935d0a313b5f0273723 --- .../internal/telephony/GsmCdmaPhone.java | 20 ++--- .../SubscriptionManagerService.java | 38 ++++++---- .../SubscriptionManagerServiceTest.java | 73 ++++++++++++++++--- 3 files changed, 95 insertions(+), 36 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index fe0f328eeb..88bc03719d 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -519,7 +519,11 @@ public class GsmCdmaPhone extends Phone { logd("update icc_operator_numeric=" + operatorNumeric); tm.setSimOperatorNumericForPhone(mPhoneId, operatorNumeric); - SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId()); + if (isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService.setMccMnc(getSubId(), operatorNumeric); + } else { + SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId()); + } // Sets iso country property by retrieving from build-time system property String iso = ""; @@ -531,7 +535,11 @@ public class GsmCdmaPhone extends Phone { logd("init: set 'gsm.sim.operator.iso-country' to iso=" + iso); tm.setSimCountryIsoForPhone(mPhoneId, iso); - SubscriptionController.getInstance().setCountryIso(iso, getSubId()); + if (isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService.setCountryIso(getSubId(), iso); + } else { + SubscriptionController.getInstance().setCountryIso(iso, getSubId()); + } // Updates MCC MNC device configuration information logd("update mccmnc=" + operatorNumeric); @@ -931,14 +939,6 @@ public class GsmCdmaPhone extends Phone { } } - @Override - public void dispose() { - // Note: this API is currently never called. We are defining actions here in case - // we need to dispose GsmCdmaPhone/Phone object. - super.dispose(); - SubscriptionController.getInstance().unregisterForUiccAppsEnabled(this); - } - @Override public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { if (isPhoneTypeGsm()) { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 1244c85bf6..0351d884d6 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -21,7 +21,6 @@ import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.content.pm.PackageManager; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -316,6 +315,27 @@ public class SubscriptionManagerService extends ISub.Stub { mSubscriptionDatabaseManager.setCarrierId(subId, carrierId); } + /** + * Set MCC/MNC by subscription id. + * + * @param mccMnc MCC/MNC associated with the subscription. + * @param subId The subscription id. + */ + public void setMccMnc(int subId, @NonNull String mccMnc) { + mSubscriptionDatabaseManager.setMcc(subId, mccMnc.substring(0, 3)); + mSubscriptionDatabaseManager.setMnc(subId, mccMnc.substring(3)); + } + + /** + * Set ISO country code by subscription id. + * + * @param iso ISO country code associated with the subscription. + * @param subId The subscription id. + */ + public void setCountryIso(int subId, @NonNull String iso) { + mSubscriptionDatabaseManager.setCountryIso(subId, iso); + } + /** * @param callingPackage The package making the call. * @param callingFeatureId The feature in the package @@ -478,20 +498,6 @@ public class SubscriptionManagerService extends ISub.Stub { return -1; } - if (subscriptionType != SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM - || !mContext.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_AUTOMOTIVE)) { - loge("addSubInfo: remote SIM is only supported when FEATURE_AUTOMOTIVE is " - + "enabled."); - return -1; - } - - if (slotIndex != SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB) { - loge("addSubInfo: This API can only be used for remote SIM. slotIndex=" - + slotIndex); - return -1; - } - iccId = IccUtils.stripTrailingFs(iccId); SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager .getSubscriptionInfoInternalByIccId(iccId); @@ -504,7 +510,7 @@ public class SubscriptionManagerService extends ISub.Stub { .setIccId(iccId) .setSimSlotIndex(slotIndex) .setDisplayName(displayName) - .setType(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM) + .setType(subscriptionType) .build() ); } else { 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 ac082c2785..74d6f55ea2 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -17,18 +17,21 @@ package com.android.internal.telephony.subscription; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MCC2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MNC2; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import android.content.pm.PackageManager; import android.os.Looper; import android.provider.Telephony; import android.telephony.SubscriptionManager; @@ -88,12 +91,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testAddSubInfo() { - doReturn(true).when(mPackageManager).hasSystemFeature( - PackageManager.FEATURE_AUTOMOTIVE); - mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, - SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB, - SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); + 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); @@ -102,9 +101,63 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { .getSubscriptionInfoInternal(1); assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID1); assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); - assertThat(subInfo.getSimSlotIndex()).isEqualTo( - SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB); + assertThat(subInfo.getSimSlotIndex()).isEqualTo(0); assertThat(subInfo.getSubscriptionType()).isEqualTo( - SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + } + + @Test + public void testSetMccMnc() { + mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, + 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + processAllMessages(); + + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); + mSubscriptionManagerServiceUT.setMccMnc(1, FAKE_MCC2 + FAKE_MNC2); + processAllMessages(); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getMcc()).isEqualTo(FAKE_MCC2); + assertThat(subInfo.getMnc()).isEqualTo(FAKE_MNC2); + verify(mMockedSubscriptionManagerServiceCallback, times(2)).onSubscriptionChanged(eq(1)); + } + + @Test + public void testSetCountryIso() { + mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, + 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + processAllMessages(); + + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); + mSubscriptionManagerServiceUT.setCountryIso(1, FAKE_COUNTRY_CODE2); + processAllMessages(); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getCountryIso()).isEqualTo(FAKE_COUNTRY_CODE2); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + } + + @Test + public void testSetCarrierId() { + mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, + 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + processAllMessages(); + + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); + mSubscriptionManagerServiceUT.setCarrierId(1, FAKE_CARRIER_ID2); + processAllMessages(); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getCarrierId()).isEqualTo(FAKE_CARRIER_ID2); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); } } -- GitLab From b543caca12d9be71699ed6baeea16be693bbb2fc Mon Sep 17 00:00:00 2001 From: Terry Huang Date: Thu, 17 Nov 2022 19:44:37 +0800 Subject: [PATCH 209/656] [Telephony] Add Location Privacy HAL Bug: 244637957 Test: Build pass Change-Id: Iddce96b53811929dd7b08acbc819a68b278fa801 --- .../internal/telephony/NetworkIndication.java | 15 +++++++++++++++ .../internal/telephony/NetworkResponse.java | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index a19d4df264..8d518f0249 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -25,6 +25,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EMERGENCY_NE import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_NETWORK_INITIATED_LOCATION_RESULT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED; @@ -402,6 +403,20 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { new AsyncResult(null, response, null)); } + /** + * Reports the result of the network initiated location request. + * + * @param locationResponseType result of the network initiated location request. + * Define by LocationResponseType. + */ + public void onNetworkInitiatedLocationResult(int indicationType, int locationResponseType) { + mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); + + if (mRil.isLogOrTrace()) { + mRil.unsljLogvRet(RIL_UNSOL_ON_NETWORK_INITIATED_LOCATION_RESULT, locationResponseType); + } + } + @Override public String getInterfaceHash() { return IRadioNetworkIndication.HASH; diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index 34e3766d36..17c07a2fdf 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -499,6 +499,22 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void setLocationPrivacySettingResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); + } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error. + * @param shareLocation Indicates whether the location sharing is allowed or not. + */ + public void getLocationPrivacySettingResponse( + RadioResponseInfo responseInfo, boolean shareLocation) { + RadioResponse.responseInts(HAL_SERVICE_NETWORK, mRil, responseInfo, shareLocation ? 1 : 0); + } + @Override public String getInterfaceHash() { return IRadioNetworkResponse.HASH; -- GitLab From c301eb05cf9509c6275f1785a64082644a8cd46d Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 23 Nov 2022 01:36:24 -0800 Subject: [PATCH 210/656] TelephonyDisplayInfo get network type from NetworkTypeController Prevent network type and override network type mismatch in the race condition where the override network type is updated and the data rat changes as we're updating the TelephonyDisplayInfo. Get the network type from the cached ServiceState value in NetworkTypeController instead. Test: atest NetworkTypeControllerTest Bug: 239184651 Change-Id: I62244d8dc99d742dff284f6a9e14b06527da4cf0 --- .../telephony/DisplayInfoController.java | 11 ++--------- .../telephony/NetworkTypeController.java | 18 +++++++++++------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/DisplayInfoController.java b/src/java/com/android/internal/telephony/DisplayInfoController.java index 886a899129..67dcef1ffd 100644 --- a/src/java/com/android/internal/telephony/DisplayInfoController.java +++ b/src/java/com/android/internal/telephony/DisplayInfoController.java @@ -20,9 +20,7 @@ import android.annotation.NonNull; import android.os.Handler; import android.os.Registrant; import android.os.RegistrantList; -import android.telephony.AccessNetworkConstants; import android.telephony.AnomalyReporter; -import android.telephony.NetworkRegistrationInfo; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.util.IndentingPrintWriter; @@ -45,8 +43,6 @@ import javax.sip.InvalidArgumentException; * TelephonyDisplayInfo via {@link #getTelephonyDisplayInfo}. */ public class DisplayInfoController extends Handler { - private static final String TAG = "DisplayInfoController"; - private final String mLogTag; private final LocalLog mLocalLog = new LocalLog(128); @@ -90,11 +86,8 @@ public class DisplayInfoController extends Handler { * NetworkTypeController. */ public void updateTelephonyDisplayInfo() { - NetworkRegistrationInfo nri = mPhone.getServiceState().getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - int dataNetworkType = nri == null ? TelephonyManager.NETWORK_TYPE_UNKNOWN - : nri.getAccessNetworkTechnology(); - TelephonyDisplayInfo newDisplayInfo = new TelephonyDisplayInfo(dataNetworkType, + TelephonyDisplayInfo newDisplayInfo = new TelephonyDisplayInfo( + mNetworkTypeController.getDataNetworkType(), mNetworkTypeController.getOverrideNetworkType()); if (!newDisplayInfo.equals(mTelephonyDisplayInfo)) { logl("TelephonyDisplayInfo changed from " + mTelephonyDisplayInfo + " to " diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 2ecad3cdc5..e03605d340 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -214,6 +214,17 @@ public class NetworkTypeController extends StateMachine { return mOverrideNetworkType; } + /** + * @return The current data network type, used to create TelephonyDisplayInfo in + * DisplayInfoController. + */ + public @Annotation.NetworkType int getDataNetworkType() { + NetworkRegistrationInfo nri = mServiceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + return nri == null ? TelephonyManager.NETWORK_TYPE_UNKNOWN + : nri.getAccessNetworkTechnology(); + } + /** * @return {@code true} if either the primary or secondary 5G icon timers are active, * and {@code false} if neither are. @@ -1325,13 +1336,6 @@ public class NetworkTypeController extends StateMachine { ? DataCallResponse.LINK_STATUS_DORMANT : DataCallResponse.LINK_STATUS_ACTIVE; } - private int getDataNetworkType() { - NetworkRegistrationInfo nri = mServiceState.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - return nri == null ? TelephonyManager.NETWORK_TYPE_UNKNOWN - : nri.getAccessNetworkTechnology(); - } - private String getEventName(int event) { try { return sEvents[event]; -- GitLab From 1f6f51b6fd817f5ecfb8ee5190066d5f22e15588 Mon Sep 17 00:00:00 2001 From: jimsun Date: Wed, 23 Nov 2022 21:39:29 +0800 Subject: [PATCH 211/656] Remove reseting Hal version after switching mock modem Bug: 260136363 Test: atest CtsTelephonyTestCases Change-Id: Idc40f2459a7604f93751b1c0f08b8cb4ac8f8bf0 --- src/java/com/android/internal/telephony/RIL.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index f459d0b014..200d35842a 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -567,13 +567,6 @@ public class RIL extends BaseCommands implements CommandsInterface { for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) { if (isRadioServiceSupported(service)) { resetProxyAndRequestList(service); - if (service == HAL_SERVICE_RADIO && isRadioVersion2_0()) { - mHalVersion.put(service, RADIO_HAL_VERSION_2_0); - } else { - mHalVersion.put(service, RADIO_HAL_VERSION_UNKNOWN); - } - } else { - mHalVersion.put(service, RADIO_HAL_VERSION_UNSUPPORTED); } } } -- GitLab From 7475a643113f87ffd2c470627ced2400864b1d82 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 22 Nov 2022 15:09:29 -0800 Subject: [PATCH 212/656] Combine data roaming from user action into one preference Instead of using DATA_ROAMING_IS_USER_SETTING_KEY for SSSS and DATA_ROAMING + subId for DSDS, combine both into DATA_ROAMING_IS_USER_SETTING_KEY + subId. Test: verify data roaming settings persisted across reboots Test: verify data roaming settings persisted across upgrades Test: verify data roaming settings correct based on carrier configs Test: atest DataSettingsManagerTest Bug: 259604889 Change-Id: Id73e66b2fd96a367ff469b464bf01bedddf6fdd3 --- .../telephony/data/DataSettingsManager.java | 59 +++++++++---------- .../data/DataSettingsManagerTest.java | 30 ++++++++++ 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index 15743d77d6..1a5d6c5f00 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -529,42 +529,37 @@ public class DataSettingsManager extends Handler { * has not manually set the value. The default value is {@link #isDefaultDataRoamingEnabled()}. */ public void setDefaultDataRoamingEnabled() { - // For SSSS, this is a per-phone property from DATA_ROAMING_IS_USER_SETTING_KEY. - // For DSDS, this is a per-sub property from Settings.Global.DATA_ROAMING + subId. // If the user has not manually set the value, use the default value. - boolean useCarrierSpecificDefault = false; - if (mPhone.getContext().getSystemService(TelephonyManager.class).getSimCount() != 1) { - String setting = Settings.Global.DATA_ROAMING + mPhone.getSubId(); - try { - Settings.Global.getInt(mResolver, setting); - } catch (Settings.SettingNotFoundException ex) { - // For multi-SIM phones, use the default value if uninitialized. - useCarrierSpecificDefault = true; - } - } else if (!isDataRoamingFromUserAction()) { - // For single-SIM phones, use the default value if user action is not set. - useCarrierSpecificDefault = true; - } - log("setDefaultDataRoamingEnabled: useCarrierSpecificDefault=" + useCarrierSpecificDefault); - if (useCarrierSpecificDefault) { - boolean defaultVal = isDefaultDataRoamingEnabled(); - setDataRoamingEnabledInternal(defaultVal); + if (!isDataRoamingFromUserAction()) { + setDataRoamingEnabledInternal(isDefaultDataRoamingEnabled()); } } /** - * Get whether the user has manually enabled or disabled data roaming from settings. - * @return {@code true} if the user has enabled data roaming and {@code false} if they have not. + * Get whether the user has manually enabled or disabled data roaming from settings for the + * current subscription. + * @return {@code true} if the user has manually enabled data roaming for the current + * subscription and {@code false} if they have not. */ private boolean isDataRoamingFromUserAction() { - final SharedPreferences sp = PreferenceManager - .getDefaultSharedPreferences(mPhone.getContext()); - // Since we don't want to unset user preferences after a system update, default to true if - // the preference does not exist and set it to false explicitly from factory reset. - if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) { - sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit(); + String key = Phone.DATA_ROAMING_IS_USER_SETTING_KEY + mPhone.getSubId(); + final SharedPreferences sp = + PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); + + // Set the default roaming from user action value if the preference doesn't exist + if (!sp.contains(key)) { + if (sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) { + log("Reusing previous roaming from user action value for backwards compatibility."); + sp.edit().putBoolean(key, true).commit(); + } else { + log("Clearing roaming from user action value for new or upgrading devices."); + sp.edit().putBoolean(key, false).commit(); + } } - return sp.getBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true); + + boolean isUserSetting = sp.getBoolean(key, true); + log("isDataRoamingFromUserAction: key=" + key + ", isUserSetting=" + isUserSetting); + return isUserSetting; } /** @@ -573,9 +568,11 @@ public class DataSettingsManager extends Handler { * {@link #isDefaultDataRoamingEnabled()} will continue to be used. */ private void setDataRoamingFromUserAction() { - final SharedPreferences.Editor sp = PreferenceManager - .getDefaultSharedPreferences(mPhone.getContext()).edit(); - sp.putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true).commit(); + String key = Phone.DATA_ROAMING_IS_USER_SETTING_KEY + mPhone.getSubId(); + log("setDataRoamingFromUserAction: key=" + key); + final SharedPreferences.Editor sp = + PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()).edit(); + sp.putBoolean(key, true).commit(); } /** Refresh the enabled mobile data policies from Telephony database */ diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java index 0014a1b6a1..4984879752 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java @@ -19,6 +19,8 @@ package com.android.internal.telephony.data; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; @@ -26,6 +28,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.os.Looper; +import android.os.PersistableBundle; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -44,17 +47,21 @@ import java.util.Set; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class DataSettingsManagerTest extends TelephonyTest { + private static final String DATA_ROAMING_IS_USER_SETTING = "data_roaming_is_user_setting_key0"; // Mocked DataSettingsManagerCallback mMockedDataSettingsManagerCallback; DataSettingsManager mDataSettingsManagerUT; + PersistableBundle mBundle; @Before public void setUp() throws Exception { logd("DataSettingsManagerTest +Setup!"); super.setUp(getClass().getSimpleName()); mMockedDataSettingsManagerCallback = Mockito.mock(DataSettingsManagerCallback.class); + mBundle = mContextFixture.getCarrierConfigBundle(); + doReturn(true).when(mDataConfigManager).isConfigCarrierSpecific(); doReturn("").when(mSubscriptionController).getEnabledMobileDataPolicies(anyInt()); doReturn(true).when(mSubscriptionController).setEnabledMobileDataPolicies( @@ -102,4 +109,27 @@ public class DataSettingsManagerTest extends TelephonyTest { .setEnabledMobileDataPolicies(anyInt(), stringArgumentCaptor.capture()); assertEquals("1,2", stringArgumentCaptor.getValue()); } + + @Test + public void testDefaultDataRoamingEnabled() { + doReturn(true).when(mDataConfigManager).isDataRoamingEnabledByDefault(); + mDataSettingsManagerUT.setDefaultDataRoamingEnabled(); + assertTrue(mDataSettingsManagerUT.isDataRoamingEnabled()); + + mDataSettingsManagerUT.setDataRoamingEnabled(false); + processAllMessages(); + assertFalse(mDataSettingsManagerUT.isDataRoamingEnabled()); + + mDataSettingsManagerUT.setDefaultDataRoamingEnabled(); + assertFalse(mDataSettingsManagerUT.isDataRoamingEnabled()); + } + + @Test + public void testDefaultDataRoamingEnabledFromUpgrade() { + doReturn(true).when(mDataConfigManager).isDataRoamingEnabledByDefault(); + mContext.getSharedPreferences("", 0).edit() + .putBoolean(DATA_ROAMING_IS_USER_SETTING, true).commit(); + mDataSettingsManagerUT.setDefaultDataRoamingEnabled(); + assertFalse(mDataSettingsManagerUT.isDataRoamingEnabled()); + } } -- GitLab From c647440839509e90693e181461937166983bfd58 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 23 Nov 2022 14:56:15 -0800 Subject: [PATCH 213/656] Added few more APIs support Added getAllSubscriptionInfoList and setPhoneNumber support. Allowed carrier privilege apps to get full subscription info on their associated subscriptions. Bug: 239607619 Test: atest SubscriptionManagerServiceTest Change-Id: I784c5aaa8fcfc84d3f6abac451fd52105893198a --- .../internal/telephony/GsmCdmaPhone.java | 18 +- .../SubscriptionManagerService.java | 199 ++++++++++++++++-- .../SubscriptionManagerServiceTest.java | 144 ++++++++++++- 3 files changed, 335 insertions(+), 26 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 88bc03719d..f189bc0fb8 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -4854,18 +4854,28 @@ public class GsmCdmaPhone extends Phone { return; } - SubscriptionInfo info = SubscriptionController.getInstance().getSubInfoForIccId( - IccUtils.stripTrailingFs(iccId)); + SubscriptionInfo info; + if (isSubscriptionManagerServiceEnabled()) { + info = mSubscriptionManagerService + .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) + .stream() + .filter(subInfo -> subInfo.getIccId().equals(IccUtils.stripTrailingFs(iccId))) + .findFirst() + .orElse(null); + } else { + info = SubscriptionController.getInstance().getSubInfoForIccId( + IccUtils.stripTrailingFs(iccId)); + } // If info is null, it could be a new subscription. By default we enable it. - boolean expectedValue = info == null ? true : info.areUiccApplicationsEnabled(); + boolean expectedValue = info == null || info.areUiccApplicationsEnabled(); // If for any reason current state is different from configured state, re-apply the // configured state. if (expectedValue != mUiccApplicationsEnabled) { mCi.enableUiccApplications(expectedValue, Message.obtain( this, EVENT_REAPPLY_UICC_APPS_ENABLEMENT_DONE, - new Pair(expectedValue, retries))); + new Pair<>(expectedValue, retries))); } } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 0351d884d6..88236b1188 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -31,6 +31,7 @@ import android.os.UserHandle; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; +import android.telephony.SubscriptionManager.PhoneNumberSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; @@ -44,6 +45,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; import com.android.internal.telephony.MultiSimSettingController; +import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; import com.android.telephony.Rlog; @@ -51,11 +53,13 @@ import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; +import java.util.stream.Collectors; /** * The subscription manager service is the backend service of {@link SubscriptionManager}. @@ -75,6 +79,9 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull private final Context mContext; + /** Telephony manager instance. */ + private final TelephonyManager mTelephonyManager; + /** The main handler of subscription manager service. */ @NonNull private final Handler mHandler; @@ -226,6 +233,7 @@ public class SubscriptionManagerService extends ISub.Stub { public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper) { sInstance = this; mContext = context; + mTelephonyManager = context.getSystemService(TelephonyManager.class); mHandler = new Handler(looper); TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = TelephonyFrameworkInitializer @@ -303,6 +311,98 @@ public class SubscriptionManagerService extends ISub.Stub { return sInstance; } + /** + * Check whether the {@code callingPackage} has access to the phone number on the specified + * {@code subId} or not. + * + * @param subId The subscription id. + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * @param message Message to include in the exception or NoteOp. + * + * @return {@code true} if the caller has phone number access. + */ + private boolean hasPhoneNumberAccess(int subId, @NonNull String callingPackage, + @Nullable String callingFeatureId, @Nullable String message) { + try { + return TelephonyPermissions.checkCallingOrSelfReadPhoneNumber(mContext, subId, + callingPackage, callingFeatureId, message); + } catch (SecurityException e) { + return false; + } + } + + /** + * Check whether the {@code callingPackage} has access to subscriber identifiers on the + * specified {@code subId} or not. + * + * @param subId The subscription id. + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * @param message Message to include in the exception or NoteOp. + * @param reportFailure Indicates if failure should be reported. + * + * @return {@code true} if the caller has identifier access. + */ + private boolean hasSubscriberIdentifierAccess(int subId, String callingPackage, + String callingFeatureId, String message, boolean reportFailure) { + try { + return TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(mContext, subId, + callingPackage, callingFeatureId, message, reportFailure); + } catch (SecurityException e) { + // A SecurityException indicates that the calling package is targeting at least the + // minimum level that enforces identifier access restrictions and the new access + // requirements are not met. + return false; + } + } + + /** + * Conditionally removes identifiers from the provided {@link SubscriptionInfo} if the {@code + * callingPackage} does not meet the access requirements for identifiers and returns the + * potentially modified object.. + * + *

+ * If the caller does not have {@link Manifest.permission#READ_PHONE_NUMBERS} permission, + * {@link SubscriptionInfo#getNumber()} will return empty string. + * If the caller does not have {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER}, + * {@link SubscriptionInfo#getIccId()} and {@link SubscriptionInfo#getCardString()} will return + * empty string, and {@link SubscriptionInfo#getGroupUuid()} will return {@code null}. + * + * @param subInfo The subscription info. + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * @param message Message to include in the exception or NoteOp. + * + * @return The modified {@link SubscriptionInfo} depending on caller's permission. + */ + @NonNull + private SubscriptionInfo conditionallyRemoveIdentifiers(@NonNull SubscriptionInfo subInfo, + @NonNull String callingPackage, @Nullable String callingFeatureId, + @Nullable String message) { + int subId = subInfo.getSubscriptionId(); + boolean hasIdentifierAccess = hasSubscriberIdentifierAccess(subId, callingPackage, + callingFeatureId, message, true); + boolean hasPhoneNumberAccess = hasPhoneNumberAccess(subId, callingPackage, + callingFeatureId, message); + + if (hasIdentifierAccess && hasPhoneNumberAccess) { + return subInfo; + } + + SubscriptionInfo.Builder result = new SubscriptionInfo.Builder(subInfo); + if (!hasIdentifierAccess) { + result.setIccId(null); + result.setCardString(null); + result.setGroupUuid(null); + } + + if (!hasPhoneNumberAccess) { + result.setNumber(null); + } + return result.build(); + } + /** * Set the subscription carrier id. * @@ -337,30 +437,70 @@ public class SubscriptionManagerService extends ISub.Stub { } /** + * Get all subscription info records from SIMs that are inserted now or were inserted before. + * + *

+ * If the caller does not have {@link Manifest.permission#READ_PHONE_NUMBERS} permission, + * {@link SubscriptionInfo#getNumber()} will return empty string. + * If the caller does not have {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER}, + * {@link SubscriptionInfo#getIccId()} and {@link SubscriptionInfo#getCardString()} will return + * empty string, and {@link SubscriptionInfo#getGroupUuid()} will return {@code null}. + * + *

+ * The carrier app will always have full {@link SubscriptionInfo} for the subscriptions + * that it has carrier privilege. + * + * @return List of all {@link SubscriptionInfo} records from SIMs that are inserted or + * inserted before. Sorted by {@link SubscriptionInfo#getSimSlotIndex()}, then + * {@link SubscriptionInfo#getSubscriptionId()}. + * * @param callingPackage The package making the call. - * @param callingFeatureId The feature in the package - * @return a list of all subscriptions in the database, this includes - * all subscriptions that have been seen. + * @param callingFeatureId The feature in the package. + * */ @Override public List getAllSubInfoList(@NonNull String callingPackage, - @NonNull String callingFeatureId) { - return null; + @Nullable String callingFeatureId) { + // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier + // privilege on any active subscription. The carrier app will get full subscription infos + // on the subs it has carrier privilege. + if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, + Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, + "getAllSubInfoList")) { + throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + + "carrier privilege to call getAllSubInfoList"); + } + + final long identity = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getAllSubInfoList")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); + + } finally { + Binder.restoreCallingIdentity(identity); + } } /** * Get the active {@link SubscriptionInfo} with the subscription id key. * * @param subId The unique {@link SubscriptionInfo} key in database - * @param callingPackage The package making the call - * @param callingFeatureId The feature in the package + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * * @return The subscription info. */ @Override @Nullable public SubscriptionInfo getActiveSubscriptionInfo(int subId, @NonNull String callingPackage, - @NonNull String callingFeatureId) { + @Nullable String callingFeatureId) { return null; } @@ -376,7 +516,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override @Nullable public SubscriptionInfo getActiveSubscriptionInfoForIccId(@NonNull String iccId, - @NonNull String callingPackage, @NonNull String callingFeatureId) { + @NonNull String callingPackage, @Nullable String callingFeatureId) { return null; } @@ -391,7 +531,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, - @NonNull String callingPackage, @NonNull String callingFeatureId) { + @NonNull String callingPackage, @Nullable String callingFeatureId) { return null; } @@ -421,7 +561,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public List getActiveSubscriptionInfoList(@NonNull String callingPackage, - @NonNull String callingFeatureId) { + @Nullable String callingFeatureId) { return null; } @@ -434,7 +574,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int getActiveSubInfoCount(@NonNull String callingPackage, - @NonNull String callingFeatureId) { + @Nullable String callingFeatureId) { return 0; } @@ -451,7 +591,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public List getAvailableSubscriptionInfoList(@NonNull String callingPackage, - @NonNull String callingFeatureId) { + @Nullable String callingFeatureId) { return null; } @@ -655,7 +795,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override @NonNull public List getOpportunisticSubscriptions(@NonNull String callingPackage, - @NonNull String callingFeatureId) { + @Nullable String callingFeatureId) { return Collections.emptyList(); } @@ -671,7 +811,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public List getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid, - @NonNull String callingPackage, @NonNull String callingFeatureId) { + @NonNull String callingPackage, @Nullable String callingFeatureId) { return null; } @@ -761,7 +901,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public String getSubscriptionProperty(int subId, @NonNull String propKey, - @NonNull String callingPackage, @NonNull String callingFeatureId) { + @NonNull String callingPackage, @Nullable String callingFeatureId) { return null; } @@ -787,7 +927,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public boolean isActiveSubId(int subId, @NonNull String callingPackage, - @NonNull String callingFeatureId) { + @Nullable String callingFeatureId) { return true; } @@ -819,19 +959,36 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public String getPhoneNumber(int subId, int source, - @NonNull String callingPackage, @NonNull String callingFeatureId) { + @NonNull String callingPackage, @Nullable String callingFeatureId) { return null; } @Override public String getPhoneNumberFromFirstAvailableSource(int subId, - @NonNull String callingPackage, @NonNull String callingFeatureId) { + @NonNull String callingPackage, @Nullable String callingFeatureId) { return null; } @Override - public void setPhoneNumber(int subId, int source, @NonNull String number, - @NonNull String callingPackage, @NonNull String callingFeatureId) { + public void setPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String number, + @NonNull String callingPackage, @Nullable String callingFeatureId) { + if (source != SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER) { + throw new IllegalArgumentException("setPhoneNumber doesn't accept source " + + SubscriptionManager.phoneNumberSourceToString(source)); + } + if (!TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext, subId)) { + throw new SecurityException("setPhoneNumber for CARRIER needs carrier privilege."); + } + if (number == null) { + throw new NullPointerException("invalid number null"); + } + + final long identity = Binder.clearCallingIdentity(); + try { + mSubscriptionDatabaseManager.setNumberFromCarrier(subId, number); + } finally { + Binder.restoreCallingIdentity(identity); + } } /** 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 74d6f55ea2..9b6ff14c2d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -16,29 +16,44 @@ package com.android.internal.telephony.subscription; +import static android.Manifest.permission.READ_PHONE_STATE; + import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MCC2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MNC2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER2; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.app.AppOpsManager; +import android.content.pm.PackageManager; +import android.os.Build; import android.os.Looper; import android.provider.Telephony; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.test.mock.MockContentResolver; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import com.android.internal.telephony.ContextFixture; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; @@ -49,10 +64,16 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; +import java.util.List; + @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class SubscriptionManagerServiceTest extends TelephonyTest { + private static final String CALLING_PACKAGE = "calling_package"; + + private static final String CALLING_FEATURE = "calling_feature"; + private SubscriptionManagerService mSubscriptionManagerServiceUT; private final SubscriptionProvider mSubscriptionProvider = new SubscriptionProvider(); @@ -64,7 +85,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionManagerServiceTest +Setup!"); super.setUp(getClass().getSimpleName()); - + setupMocksForTelephonyPermissions(Build.VERSION_CODES.UPSIDE_DOWN_CAKE); mMockedSubscriptionManagerServiceCallback = Mockito.mock( SubscriptionManagerServiceCallback.class); ((MockContentResolver) mContext.getContentResolver()).addProvider( @@ -160,4 +181,125 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfo.getCarrierId()).isEqualTo(FAKE_CARRIER_ID2); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); } + + @Test + public void testSetPhoneNumber() { + mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, + 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + processAllMessages(); + + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); + + // Source IMS is not acceptable + assertThrows(IllegalArgumentException.class, + () -> mSubscriptionManagerServiceUT.setPhoneNumber(1, + SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, FAKE_PHONE_NUMBER2, + CALLING_PACKAGE, CALLING_FEATURE)); + + // Caller does not have carrier privilege + assertThrows(SecurityException.class, + () -> mSubscriptionManagerServiceUT.setPhoneNumber(1, + SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, FAKE_PHONE_NUMBER2, + CALLING_PACKAGE, CALLING_FEATURE)); + + // Grant carrier privilege + setCarrierPrivilegesForSubId(true, 1); + + mSubscriptionManagerServiceUT.setPhoneNumber(1, + SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, FAKE_PHONE_NUMBER2, + CALLING_PACKAGE, CALLING_FEATURE); + processAllMessages(); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getNumberFromCarrier()).isEqualTo(FAKE_PHONE_NUMBER2); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + } + + @Test + public void testGetAllSubInfoList() { + doReturn(new int[]{1, 2}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); + mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, + 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID2, FAKE_CARRIER_NAME2, + 1, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + processAllMessages(); + + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(2)); + + // Revoke all permissions. + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); + doReturn(AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).noteOpNoThrow(anyString(), + anyInt(), nullable(String.class), nullable(String.class), nullable(String.class)); + setIdentifierAccess(false); + setPhoneNumberAccess(PackageManager.PERMISSION_DENIED); + + // Should throw security exception if the caller does not have permission. + assertThrows(SecurityException.class, + () -> mSubscriptionManagerServiceUT.getAllSubInfoList("", null)); + + // Grant carrier privilege for sub 1 + setCarrierPrivilegesForSubId(true, 1); + // Grant carrier privilege for sub 2 + setCarrierPrivilegesForSubId(true, 2); + + List subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList("", null); + assertThat(subInfos).hasSize(2); + + assertThat(subInfos.get(0).getIccId()).isEqualTo(FAKE_ICCID1); + assertThat(subInfos.get(0).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); + assertThat(subInfos.get(0).getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + assertThat(subInfos.get(0).getSimSlotIndex()).isEqualTo(0); + + assertThat(subInfos.get(1).getIccId()).isEqualTo(FAKE_ICCID2); + assertThat(subInfos.get(1).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME2); + assertThat(subInfos.get(1).getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + assertThat(subInfos.get(1).getSimSlotIndex()).isEqualTo(1); + + // Revoke carrier privilege for sub 2 + setCarrierPrivilegesForSubId(false, 2); + + subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList("", null); + assertThat(subInfos).hasSize(2); + + assertThat(subInfos.get(0).getIccId()).isEqualTo(FAKE_ICCID1); + assertThat(subInfos.get(0).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); + assertThat(subInfos.get(0).getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + assertThat(subInfos.get(0).getSimSlotIndex()).isEqualTo(0); + + // ICCID should be empty due to insufficient permission. + assertThat(subInfos.get(1).getIccId()).isEmpty(); + assertThat(subInfos.get(1).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME2); + assertThat(subInfos.get(1).getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + assertThat(subInfos.get(1).getSimSlotIndex()).isEqualTo(1); + + // Grant READ_PHONE_STATE permission + mContextFixture.addCallingOrSelfPermission(READ_PHONE_STATE); + // Grant identifier access + setIdentifierAccess(true); + // Revoke carrier privileges. + setCarrierPrivilegesForSubId(false, 1); + setCarrierPrivilegesForSubId(false, 2); + + subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList("", null); + assertThat(subInfos).hasSize(2); + + assertThat(subInfos.get(0).getIccId()).isEqualTo(FAKE_ICCID1); + assertThat(subInfos.get(0).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); + assertThat(subInfos.get(0).getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + assertThat(subInfos.get(0).getSimSlotIndex()).isEqualTo(0); + + assertThat(subInfos.get(1).getIccId()).isEqualTo(FAKE_ICCID2); + assertThat(subInfos.get(1).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME2); + assertThat(subInfos.get(1).getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + assertThat(subInfos.get(1).getSimSlotIndex()).isEqualTo(1); + } } -- GitLab From 3a45d5969f187b4b1a2cc661474e4bd7db25aab0 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 24 Nov 2022 07:47:35 +0000 Subject: [PATCH 214/656] Revert "Use NR configs for minimum NR advanced bandwidth threshold" This reverts commit 29c27573313edab5e12ef8dfa5279f1936fa68ac. Reason for revert: b/260301879 Change-Id: Iec58ef365d7d60a7a93d7fd95968e5c2c105f09e --- .../internal/telephony/NetworkTypeController.java | 15 ++++++--------- .../telephony/NetworkTypeControllerTest.java | 9 ++------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index e03605d340..2091effcdb 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -524,8 +524,7 @@ public class NetworkTypeController extends StateMachine { int value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; if ((getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA || mServiceState.isUsingCarrierAggregation()) - && IntStream.of(mServiceState.getCellBandwidths()).sum() - > mLtePlusThresholdBandwidth) { + && getBandwidth() > mLtePlusThresholdBandwidth) { value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA; } if (isLteEnhancedAvailable()) { @@ -1287,15 +1286,9 @@ public class NetworkTypeController extends StateMachine { return false; } - int bandwidths = mPhone.getServiceStateTracker().getPhysicalChannelConfigList() - .stream() - .filter(config -> config.getNetworkType() == TelephonyManager.NETWORK_TYPE_NR) - .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) - .mapToInt(Integer::intValue) - .sum(); // Check if meeting minimum bandwidth requirement. For most carriers, there is no minimum // bandwidth requirement and mNrAdvancedThresholdBandwidth is 0. - if (mNrAdvancedThresholdBandwidth > 0 && bandwidths < mNrAdvancedThresholdBandwidth) { + if (mNrAdvancedThresholdBandwidth > 0 && getBandwidth() < mNrAdvancedThresholdBandwidth) { return false; } @@ -1336,6 +1329,10 @@ public class NetworkTypeController extends StateMachine { ? DataCallResponse.LINK_STATUS_DORMANT : DataCallResponse.LINK_STATUS_ACTIVE; } + private int getBandwidth() { + return IntStream.of(mServiceState.getCellBandwidths()).sum(); + } + private String getEventName(int event) { try { return sEvents[event]; diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index bf6297870e..91d936d7cf 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -1240,16 +1240,11 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - List lastPhysicalChannelConfigList = new ArrayList<>(); - lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() - .setNetworkType(TelephonyManager.NETWORK_TYPE_NR) - .setCellBandwidthDownlinkKhz(20001) - .build()); - doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); + doReturn(new int[] {20001}).when(mServiceState).getCellBandwidths(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } -- GitLab From eda64281872c98bd795cf2d3b8b22dc2ee0535ac Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 23 Nov 2022 21:48:36 -0800 Subject: [PATCH 215/656] Added getSubscriptionsInGroup support Bug: 239607619 Test: atest SubscriptionManagerServiceTest Change-Id: Iac3731c63bfece061c3b8f99fa795b98e27d0e4d --- .../internal/telephony/GsmCdmaPhone.java | 31 +-- .../telephony/MultiSimSettingController.java | 16 +- .../SubscriptionInfoInternal.java | 20 +- .../SubscriptionManagerService.java | 80 ++++++- .../SubscriptionManagerServiceTest.java | 199 +++++++++++++----- 5 files changed, 265 insertions(+), 81 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index f189bc0fb8..ab4d9b1ba8 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -104,6 +104,7 @@ import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.imsphone.ImsPhoneMmiCode; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.metrics.VoiceCallSessionStats; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; import com.android.internal.telephony.test.SimulatedRadioControl; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; @@ -4967,13 +4968,19 @@ public class GsmCdmaPhone extends Phone { boolean mDefaultVonr = config.getBoolean(CarrierConfigManager.KEY_VONR_ON_BY_DEFAULT_BOOL); - String result = SubscriptionController.getInstance().getSubscriptionProperty( - getSubId(), - SubscriptionManager.NR_ADVANCED_CALLING_ENABLED); - int setting = -1; - if (result != null) { - setting = Integer.parseInt(result); + if (isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(getSubId()); + if (subInfo != null) { + setting = subInfo.getNrAdvancedCallingEnabled(); + } + } else { + String result = SubscriptionController.getInstance().getSubscriptionProperty( + getSubId(), SubscriptionManager.NR_ADVANCED_CALLING_ENABLED); + if (result != null) { + setting = Integer.parseInt(result); + } } logd("VoNR setting from telephony.db:" @@ -4983,15 +4990,9 @@ public class GsmCdmaPhone extends Phone { + " ,vonr_on_by_default_bool:" + mDefaultVonr); - if (!mIsVonrEnabledByCarrier) { - mCi.setVoNrEnabled(false, obtainMessage(EVENT_SET_VONR_ENABLED_DONE), null); - } else if (setting == -1) { - mCi.setVoNrEnabled(mDefaultVonr, obtainMessage(EVENT_SET_VONR_ENABLED_DONE), null); - } else if (setting == 1) { - mCi.setVoNrEnabled(true, obtainMessage(EVENT_SET_VONR_ENABLED_DONE), null); - } else if (setting == 0) { - mCi.setVoNrEnabled(false, obtainMessage(EVENT_SET_VONR_ENABLED_DONE), null); - } + boolean enbleVonr = mIsVonrEnabledByCarrier + && (setting == 1 || (setting == -1 && mDefaultVonr)); + mCi.setVoNrEnabled(enbleVonr, obtainMessage(EVENT_SET_VONR_ENABLED_DONE), null); } private void updateCdmaRoamingSettingsAfterCarrierConfigChanged(PersistableBundle config) { diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index e514055fab..298e3b8614 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -54,6 +54,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.util.ArrayUtils; import java.lang.annotation.Retention; @@ -903,11 +904,16 @@ public class MultiSimSettingController extends Handler { * are synced. */ private void setRoamingDataEnabledForGroup(int subId, boolean enable) { - SubscriptionController subController = SubscriptionController.getInstance(); - List infoList = subController.getSubscriptionsInGroup( - mSubController.getGroupUuid(subId), mContext.getOpPackageName(), - mContext.getAttributionTag()); - + List infoList; + if (PhoneFactory.getDefaultPhone().isSubscriptionManagerServiceEnabled()) { + infoList = SubscriptionManagerService.getInstance().getSubscriptionsInGroup( + mSubController.getGroupUuid(subId), mContext.getOpPackageName(), + mContext.getAttributionTag()); + } else { + infoList = SubscriptionController.getInstance().getSubscriptionsInGroup( + mSubController.getGroupUuid(subId), mContext.getOpPackageName(), + mContext.getAttributionTag()); + } if (infoList == null) return; for (SubscriptionInfo info : infoList) { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index f692e2c688..c9f2ab47ea 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -628,11 +628,12 @@ public class SubscriptionInfoInternal { * @return {@code true} if enhanced 4G mode is enabled by the user or not. */ public boolean isEnhanced4GModeEnabled() { - return mIsEnhanced4GModeEnabled != 0; + return mIsEnhanced4GModeEnabled == 1; } /** - * @return {@code 1} if enhanced 4G mode is enabled by the user or not. + * @return {@code 1} if enhanced 4G mode is enabled by the user or not. {@code 0} if disabled. + * {@code -1} if the user did not change any setting. */ public int getEnhanced4GModeEnabled() { return mIsEnhanced4GModeEnabled; @@ -657,12 +658,12 @@ public class SubscriptionInfoInternal { * roaming. */ public boolean isWifiCallingEnabled() { - return mIsWifiCallingEnabled != 0; + return mIsWifiCallingEnabled == 1; } /** * @return {@code 1} if Wi-Fi calling is enabled by the user or not when the device is not - * roaming. + * roaming. {@code 0} if disabled. {@code -1} if the user did not change any setting. */ public int getWifiCallingEnabled() { return mIsWifiCallingEnabled; @@ -686,10 +687,10 @@ public class SubscriptionInfoInternal { /** * @return {@code true} if Wi-Fi calling is enabled by the user or not when the device is - * roaming. + * roaming. {@code 0} if disabled. {@code -1} if the user did not change any setting. */ public boolean isWifiCallingEnabledForRoaming() { - return mIsWifiCallingEnabledForRoaming != 0; + return mIsWifiCallingEnabledForRoaming == 1; } /** @@ -894,11 +895,12 @@ public class SubscriptionInfoInternal { * @return {@code true} if the user has enabled NR advanced calling. */ public boolean isNrAdvancedCallingEnabled() { - return mIsNrAdvancedCallingEnabled != 0; + return mIsNrAdvancedCallingEnabled == 1; } /** - * @return {@code 1} if the user has enabled NR advanced calling. + * @return {@code 1} if the user has enabled NR advanced calling. {code 0} if disabled. + * {code -1} if the user did not change any setting. */ public int getNrAdvancedCallingEnabled() { return mIsNrAdvancedCallingEnabled; @@ -1407,7 +1409,7 @@ public class SubscriptionInfoInternal { /** * Whether the user has enabled NR advanced calling. */ - private int mIsNrAdvancedCallingEnabled = 0; + private int mIsNrAdvancedCallingEnabled = -1; /** * The phone number retrieved from carrier. diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 88236b1188..4ec0f4cb4a 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -20,8 +20,12 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.content.Context; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -38,6 +42,7 @@ import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; import android.text.TextUtils; import android.util.ArraySet; +import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.LocalLog; @@ -71,6 +76,15 @@ public class SubscriptionManagerService extends ISub.Stub { /** Whether enabling verbose debugging message or not. */ private static final boolean VDBG = false; + /** + * Apps targeting on Android T and beyond will get exception if there is no access to device + * identifiers nor has carrier privileges when calling + * {@link SubscriptionManager#getSubscriptionsInGroup}. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) + public static final long REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID = 213902861L; + /** Instance of subscription manager service. */ @NonNull private static SubscriptionManagerService sInstance; @@ -82,6 +96,9 @@ public class SubscriptionManagerService extends ISub.Stub { /** Telephony manager instance. */ private final TelephonyManager mTelephonyManager; + /** Subscription manager instance. */ + private final SubscriptionManager mSubscriptionManager; + /** The main handler of subscription manager service. */ @NonNull private final Handler mHandler; @@ -234,6 +251,7 @@ public class SubscriptionManagerService extends ISub.Stub { sInstance = this; mContext = context; mTelephonyManager = context.getSystemService(TelephonyManager.class); + mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mHandler = new Handler(looper); TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = TelephonyFrameworkInitializer @@ -344,8 +362,8 @@ public class SubscriptionManagerService extends ISub.Stub { * * @return {@code true} if the caller has identifier access. */ - private boolean hasSubscriberIdentifierAccess(int subId, String callingPackage, - String callingFeatureId, String message, boolean reportFailure) { + private boolean hasSubscriberIdentifierAccess(int subId, @NonNull String callingPackage, + @Nullable String callingFeatureId, @Nullable String message, boolean reportFailure) { try { return TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(mContext, subId, callingPackage, callingFeatureId, message, reportFailure); @@ -360,7 +378,7 @@ public class SubscriptionManagerService extends ISub.Stub { /** * Conditionally removes identifiers from the provided {@link SubscriptionInfo} if the {@code * callingPackage} does not meet the access requirements for identifiers and returns the - * potentially modified object.. + * potentially modified object. * *

* If the caller does not have {@link Manifest.permission#READ_PHONE_NUMBERS} permission, @@ -809,10 +827,64 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull String callingPackage) { } + /** + * Get subscriptionInfo list of subscriptions that are in the same group of given subId. + * See {@link #createSubscriptionGroup(int[], String)} for more details. + * + * Caller must have {@link android.Manifest.permission#READ_PHONE_STATE} + * or carrier privilege permission on the subscription. + * + *

Starting with API level 33, the caller also needs permission to access device identifiers + * to get the list of subscriptions associated with a group UUID. + * This method can be invoked if one of the following requirements is met: + *

    + *
  • If the app has carrier privilege permission. + * {@link TelephonyManager#hasCarrierPrivileges()} + *
  • If the app has {@link android.Manifest.permission#READ_PHONE_STATE} permission and + * access to device identifiers. + *
+ * + * @param groupUuid of which list of subInfo will be returned. + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * + * @return List of {@link SubscriptionInfo} that belong to the same group, including the given + * subscription itself. It will return an empty list if no subscription belongs to the group. + * + * @throws SecurityException if the caller doesn't meet the requirements outlined above. + * + */ @Override + @NonNull public List getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid, @NonNull String callingPackage, @Nullable String callingFeatureId) { - return null; + // If the calling app neither has carrier privileges nor READ_PHONE_STATE and access to + // device identifiers, it will throw a SecurityException. + if (CompatChanges.isChangeEnabled(REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID, + Binder.getCallingUid())) { + try { + if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext, + callingPackage, callingFeatureId, "getSubscriptionsInGroup")) { + EventLog.writeEvent(0x534e4554, "213902861", Binder.getCallingUid()); + throw new SecurityException("Need to have carrier privileges or access to " + + "device identifiers to call getSubscriptionsInGroup"); + } + } catch (SecurityException e) { + EventLog.writeEvent(0x534e4554, "213902861", Binder.getCallingUid()); + throw e; + } + } + + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .map(SubscriptionInfoInternal::toSubscriptionInfo) + .filter(info -> groupUuid.equals(info.getGroupUuid()) + && (mSubscriptionManager.canManageSubscription(info, callingPackage) + || TelephonyPermissions.checkCallingOrSelfReadPhoneState( + mContext, info.getSubscriptionId(), callingPackage, + callingFeatureId, "getSubscriptionsInGroup"))) + .map(subscriptionInfo -> conditionallyRemoveIdentifiers(subscriptionInfo, + callingPackage, callingFeatureId, "getSubscriptionsInGroup")) + .collect(Collectors.toList()); } @Override 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 9b6ff14c2d..632f9956d5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -16,36 +16,44 @@ package com.android.internal.telephony.subscription; -import static android.Manifest.permission.READ_PHONE_STATE; - import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1; -import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MCC2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MNC2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER2; +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; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.Manifest; +import android.annotation.NonNull; import android.app.AppOpsManager; +import android.app.PropertyInvalidatedCache; +import android.compat.testing.PlatformCompatChangeRule; import android.content.pm.PackageManager; import android.os.Build; import android.os.Looper; +import android.os.ParcelUuid; import android.provider.Telephony; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -58,12 +66,18 @@ import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.Mockito; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.List; @RunWith(AndroidTestingRunner.class) @@ -81,11 +95,16 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // mocked private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback; + @Rule + public TestRule compatChangeRule = new PlatformCompatChangeRule(); + @Before public void setUp() throws Exception { logd("SubscriptionManagerServiceTest +Setup!"); super.setUp(getClass().getSimpleName()); setupMocksForTelephonyPermissions(Build.VERSION_CODES.UPSIDE_DOWN_CAKE); + PropertyInvalidatedCache.disableForCurrentProcess("cache_key.is_compat_change_enabled"); + mMockedSubscriptionManagerServiceCallback = Mockito.mock( SubscriptionManagerServiceCallback.class); ((MockContentResolver) mContext.getContentResolver()).addProvider( @@ -102,6 +121,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { waitForMs(100); processAllFutureMessages(); + // Revoke all permissions. + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); + doReturn(AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).noteOpNoThrow(anyString(), + anyInt(), nullable(String.class), nullable(String.class), nullable(String.class)); + setIdentifierAccess(false); + setPhoneNumberAccess(PackageManager.PERMISSION_DENIED); + logd("SubscriptionManagerServiceTest -Setup!"); } @@ -110,8 +136,28 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { super.tearDown(); } + private void insertSubscription(@NonNull SubscriptionInfoInternal subInfo) { + try { + Field field = SubscriptionManagerService.class.getDeclaredField( + "mSubscriptionDatabaseManager"); + field.setAccessible(true); + SubscriptionDatabaseManager sdbm = + (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT); + + Class[] cArgs = new Class[1]; + cArgs[0] = SubscriptionInfoInternal.class; + Method method = SubscriptionDatabaseManager.class.getDeclaredMethod( + "insertSubscriptionInfo", cArgs); + method.setAccessible(true); + method.invoke(sdbm, subInfo); + } catch (Exception e) { + fail("Failed to insert subscription. e=" + e); + } + } + @Test public void testAddSubInfo() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); processAllMessages(); @@ -129,6 +175,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetMccMnc() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); processAllMessages(); @@ -148,6 +195,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetCountryIso() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); processAllMessages(); @@ -166,6 +214,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetCarrierId() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); processAllMessages(); @@ -184,6 +233,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetPhoneNumber() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); processAllMessages(); @@ -220,86 +270,139 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testGetAllSubInfoList() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); doReturn(new int[]{1, 2}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); - mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID1, FAKE_CARRIER_NAME1, - 0, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - mSubscriptionManagerServiceUT.addSubInfo(FAKE_ICCID2, FAKE_CARRIER_NAME2, - 1, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(2)); - // Revoke all permissions. - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - doReturn(AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).noteOpNoThrow(anyString(), - anyInt(), nullable(String.class), nullable(String.class), nullable(String.class)); - setIdentifierAccess(false); - setPhoneNumberAccess(PackageManager.PERMISSION_DENIED); - // Should throw security exception if the caller does not have permission. assertThrows(SecurityException.class, - () -> mSubscriptionManagerServiceUT.getAllSubInfoList("", null)); + () -> mSubscriptionManagerServiceUT.getAllSubInfoList( + CALLING_PACKAGE, CALLING_FEATURE)); // Grant carrier privilege for sub 1 setCarrierPrivilegesForSubId(true, 1); // Grant carrier privilege for sub 2 setCarrierPrivilegesForSubId(true, 2); - List subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList("", null); + List subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList( + CALLING_PACKAGE, CALLING_FEATURE); assertThat(subInfos).hasSize(2); - assertThat(subInfos.get(0).getIccId()).isEqualTo(FAKE_ICCID1); - assertThat(subInfos.get(0).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); - assertThat(subInfos.get(0).getSubscriptionType()).isEqualTo( - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - assertThat(subInfos.get(0).getSimSlotIndex()).isEqualTo(0); + assertThat(subInfos.get(0)).isEqualTo(new SubscriptionInfoInternal + .Builder(FAKE_SUBSCRIPTION_INFO1) + .setId(1).build().toSubscriptionInfo()); - assertThat(subInfos.get(1).getIccId()).isEqualTo(FAKE_ICCID2); - assertThat(subInfos.get(1).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME2); - assertThat(subInfos.get(1).getSubscriptionType()).isEqualTo( - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - assertThat(subInfos.get(1).getSimSlotIndex()).isEqualTo(1); + assertThat(subInfos.get(1)).isEqualTo(new SubscriptionInfoInternal + .Builder(FAKE_SUBSCRIPTION_INFO2) + .setId(2).build().toSubscriptionInfo()); // Revoke carrier privilege for sub 2 setCarrierPrivilegesForSubId(false, 2); - subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList("", null); + subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList( + CALLING_PACKAGE, CALLING_FEATURE); assertThat(subInfos).hasSize(2); assertThat(subInfos.get(0).getIccId()).isEqualTo(FAKE_ICCID1); - assertThat(subInfos.get(0).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); - assertThat(subInfos.get(0).getSubscriptionType()).isEqualTo( - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - assertThat(subInfos.get(0).getSimSlotIndex()).isEqualTo(0); - - // ICCID should be empty due to insufficient permission. + assertThat(subInfos.get(0).getCardString()).isEqualTo(FAKE_ICCID1); + assertThat(subInfos.get(0).getNumber()).isEqualTo(FAKE_PHONE_NUMBER1); + // identifiers should be empty due to insufficient permission. assertThat(subInfos.get(1).getIccId()).isEmpty(); - assertThat(subInfos.get(1).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME2); - assertThat(subInfos.get(1).getSubscriptionType()).isEqualTo( - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - assertThat(subInfos.get(1).getSimSlotIndex()).isEqualTo(1); + assertThat(subInfos.get(1).getCardString()).isEmpty(); + assertThat(subInfos.get(1).getNumber()).isEmpty(); // Grant READ_PHONE_STATE permission - mContextFixture.addCallingOrSelfPermission(READ_PHONE_STATE); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); // Grant identifier access setIdentifierAccess(true); // Revoke carrier privileges. setCarrierPrivilegesForSubId(false, 1); setCarrierPrivilegesForSubId(false, 2); - subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList("", null); + subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList( + CALLING_PACKAGE, CALLING_FEATURE); assertThat(subInfos).hasSize(2); assertThat(subInfos.get(0).getIccId()).isEqualTo(FAKE_ICCID1); - assertThat(subInfos.get(0).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); - assertThat(subInfos.get(0).getSubscriptionType()).isEqualTo( - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - assertThat(subInfos.get(0).getSimSlotIndex()).isEqualTo(0); - + assertThat(subInfos.get(0).getCardString()).isEqualTo(FAKE_ICCID1); + // Phone number should be empty + assertThat(subInfos.get(0).getNumber()).isEmpty(); assertThat(subInfos.get(1).getIccId()).isEqualTo(FAKE_ICCID2); - assertThat(subInfos.get(1).getDisplayName()).isEqualTo(FAKE_CARRIER_NAME2); - assertThat(subInfos.get(1).getSubscriptionType()).isEqualTo( - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - assertThat(subInfos.get(1).getSimSlotIndex()).isEqualTo(1); + assertThat(subInfos.get(1).getCardString()).isEqualTo(FAKE_ICCID2); + // Phone number should be empty + assertThat(subInfos.get(1).getNumber()).isEmpty(); + + // Grant phone number access + doReturn(PackageManager.PERMISSION_GRANTED).when(mMockLegacyPermissionManager) + .checkPhoneNumberAccess(anyString(), anyString(), anyString(), anyInt(), anyInt()); + + subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList( + CALLING_PACKAGE, CALLING_FEATURE); + assertThat(subInfos).hasSize(2); + assertThat(subInfos.get(0).getNumber()).isEqualTo(FAKE_PHONE_NUMBER1); + assertThat(subInfos.get(1).getNumber()).isEqualTo(FAKE_PHONE_NUMBER2); + } + + @Test + @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) + public void testGetSubscriptionsInGroup() { + doReturn(new int[]{1, 2}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); + + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + SubscriptionInfoInternal anotherSubInfo = + new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO2) + .setGroupUuid(FAKE_UUID1) + .build(); + insertSubscription(anotherSubInfo); + + // Throw exception is the new behavior. + assertThrows(SecurityException.class, + () -> mSubscriptionManagerServiceUT.getSubscriptionsInGroup( + ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE)); + + // Grant carrier privilege on sub 1 and 2 + setCarrierPrivilegesForSubId(true, 1); + setCarrierPrivilegesForSubId(true, 2); + List subInfos = mSubscriptionManagerServiceUT.getSubscriptionsInGroup( + ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE); + + assertThat(subInfos).hasSize(2); + assertThat(subInfos.get(0)).isEqualTo(new SubscriptionInfoInternal.Builder( + FAKE_SUBSCRIPTION_INFO1).setId(1).build().toSubscriptionInfo()); + assertThat(subInfos.get(1)).isEqualTo(new SubscriptionInfoInternal.Builder(anotherSubInfo) + .setId(2).build().toSubscriptionInfo()); + + // Grant READ_PHONE_STATE permission + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); + setIdentifierAccess(false); + setCarrierPrivilegesForSubId(false, 1); + setCarrierPrivilegesForSubId(false, 2); + doNothing().when(mContext).enforcePermission( + eq(android.Manifest.permission.READ_PHONE_STATE), anyInt(), anyInt(), anyString()); + + // Throw exception is the new behavior. Only has READ_PHONE_STATE is not enough. Need + // identifier access as well. + assertThrows(SecurityException.class, + () -> mSubscriptionManagerServiceUT.getSubscriptionsInGroup( + ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE)); + + // Grant identifier access + setIdentifierAccess(true); + // Grant phone number access + setPhoneNumberAccess(PackageManager.PERMISSION_GRANTED); + + subInfos = mSubscriptionManagerServiceUT.getSubscriptionsInGroup( + ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE); + + assertThat(subInfos).hasSize(2); + assertThat(subInfos).containsExactlyElementsIn( + List.of(new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO1) + .setId(1).build().toSubscriptionInfo(), + new SubscriptionInfoInternal.Builder(anotherSubInfo) + .setId(2).build().toSubscriptionInfo())); } } -- GitLab From cb1e57c050020957a02ba0aa96eb25619c1d56f8 Mon Sep 17 00:00:00 2001 From: Tairu Wang Date: Wed, 23 Nov 2022 18:32:25 +0000 Subject: [PATCH 216/656] Initialize maxActiveVoiceSubscriptions to a reasonable value Initialize maxActiveVoiceCalls as maxActiveData Bug: 254926322 Test: make build completed successfully Change-Id: I5ed93f868fcab06c06961f7fe147a95b7c9c893e --- src/java/com/android/internal/telephony/RILUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 2d43f00456..85783ca17b 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -4605,6 +4605,7 @@ public class RILUtils { logicalModemList.add(new ModemInfo(modemInfo.modemId)); } } + maxActiveVoiceCalls = maxActiveData; return new PhoneCapability(maxActiveVoiceCalls, maxActiveData, logicalModemList, validationBeforeSwitchSupported, deviceNrCapabilities); } -- GitLab From e1f8bab088af385ff5b25f1dd98ee536ac12766a Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 22 Nov 2022 01:09:41 -0800 Subject: [PATCH 217/656] Use NR configs for minimum NR advanced bandwidth threshold Test: manual verify Test: atest NetworkTypeControllerTest Bug: 257135958 Bug: 260007418 Change-Id: I41eb1a08e9c04820e4ec188eb6dfd2c7f73ff591 --- .../telephony/NetworkTypeController.java | 19 +++++++++++++------ .../telephony/NetworkTypeControllerTest.java | 9 +++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 2091effcdb..2e6da82268 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -524,7 +524,8 @@ public class NetworkTypeController extends StateMachine { int value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; if ((getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA || mServiceState.isUsingCarrierAggregation()) - && getBandwidth() > mLtePlusThresholdBandwidth) { + && IntStream.of(mServiceState.getCellBandwidths()).sum() + > mLtePlusThresholdBandwidth) { value = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA; } if (isLteEnhancedAvailable()) { @@ -1286,9 +1287,19 @@ public class NetworkTypeController extends StateMachine { return false; } + int bandwidths = 0; + if (mPhone.getServiceStateTracker().getPhysicalChannelConfigList() != null) { + bandwidths = mPhone.getServiceStateTracker().getPhysicalChannelConfigList() + .stream() + .filter(config -> config.getNetworkType() == TelephonyManager.NETWORK_TYPE_NR) + .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) + .mapToInt(Integer::intValue) + .sum(); + } + // Check if meeting minimum bandwidth requirement. For most carriers, there is no minimum // bandwidth requirement and mNrAdvancedThresholdBandwidth is 0. - if (mNrAdvancedThresholdBandwidth > 0 && getBandwidth() < mNrAdvancedThresholdBandwidth) { + if (mNrAdvancedThresholdBandwidth > 0 && bandwidths < mNrAdvancedThresholdBandwidth) { return false; } @@ -1329,10 +1340,6 @@ public class NetworkTypeController extends StateMachine { ? DataCallResponse.LINK_STATUS_DORMANT : DataCallResponse.LINK_STATUS_ACTIVE; } - private int getBandwidth() { - return IntStream.of(mServiceState.getCellBandwidths()).sum(); - } - private String getEventName(int event) { try { return sEvents[event]; diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index 91d936d7cf..bf6297870e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -1240,11 +1240,16 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - doReturn(new int[] {20001}).when(mServiceState).getCellBandwidths(); + List lastPhysicalChannelConfigList = new ArrayList<>(); + lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() + .setNetworkType(TelephonyManager.NETWORK_TYPE_NR) + .setCellBandwidthDownlinkKhz(20001) + .build()); + doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); broadcastCarrierConfigs(); - mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); + mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); processAllMessages(); assertEquals("connected_mmwave", getCurrentState().getName()); } -- GitLab From 51c5890af0926b65a09b566678e70faae95082b6 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 23 Nov 2022 14:46:09 -0800 Subject: [PATCH 218/656] Add carrier config to use both NR and LTE bands for NR advanced threshold Test: atest NetworkTypeControllerTest Bug: 260052715 Change-Id: If797df389455f7ccbf0befd2d205962f4fea8060 --- .../telephony/NetworkTypeController.java | 10 ++++++- .../telephony/NetworkTypeControllerTest.java | 28 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 2e6da82268..1c4b9b55c8 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -157,6 +157,7 @@ public class NetworkTypeController extends StateMachine { private boolean mIsTimerResetEnabledForLegacyStateRRCIdle; private int mLtePlusThresholdBandwidth; private int mNrAdvancedThresholdBandwidth; + private boolean mIncludeLteForNrAdvancedThresholdBandwidth; private @NonNull int[] mAdditionalNrAdvancedBandsList; private @NonNull String mPrimaryTimerState; private @NonNull String mSecondaryTimerState; @@ -277,6 +278,9 @@ public class NetworkTypeController extends StateMachine { CarrierConfigManager.KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT); mNrAdvancedThresholdBandwidth = CarrierConfigManager.getDefaultConfig().getInt( CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT); + mIncludeLteForNrAdvancedThresholdBandwidth = CarrierConfigManager.getDefaultConfig() + .getBoolean(CarrierConfigManager + .KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); mEnableNrAdvancedWhileRoaming = CarrierConfigManager.getDefaultConfig().getBoolean( CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL); @@ -312,6 +316,9 @@ public class NetworkTypeController extends StateMachine { mNrAdvancedThresholdBandwidth = b.getInt( CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, mNrAdvancedThresholdBandwidth); + mIncludeLteForNrAdvancedThresholdBandwidth = b.getBoolean(CarrierConfigManager + .KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, + mIncludeLteForNrAdvancedThresholdBandwidth); mAdditionalNrAdvancedBandsList = b.getIntArray( CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY); mNrAdvancedCapablePcoId = b.getInt( @@ -1291,7 +1298,8 @@ public class NetworkTypeController extends StateMachine { if (mPhone.getServiceStateTracker().getPhysicalChannelConfigList() != null) { bandwidths = mPhone.getServiceStateTracker().getPhysicalChannelConfigList() .stream() - .filter(config -> config.getNetworkType() == TelephonyManager.NETWORK_TYPE_NR) + .filter(config -> mIncludeLteForNrAdvancedThresholdBandwidth + || config.getNetworkType() == TelephonyManager.NETWORK_TYPE_NR) .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) .mapToInt(Integer::intValue) .sum(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index bf6297870e..d95e5bc158 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -1254,6 +1254,34 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected_mmwave", getCurrentState().getName()); } + @Test + public void testTransitionToCurrentStateNrConnectedWithHighBandwidthIncludingLte() + throws Exception { + assertEquals("DefaultState", getCurrentState().getName()); + doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); + doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); + doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); + List lastPhysicalChannelConfigList = new ArrayList<>(); + lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() + .setNetworkType(TelephonyManager.NETWORK_TYPE_NR) + .setCellBandwidthDownlinkKhz(20000) + .build()); + lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCellBandwidthDownlinkKhz(10000) + .build()); + doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); + mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); + mBundle.putBoolean( + CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, + true); + broadcastCarrierConfigs(); + + mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + processAllMessages(); + assertEquals("connected_mmwave", getCurrentState().getName()); + } + @Test public void testNrAdvancedDisabledWhileRoaming() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); -- GitLab From 275bb210969d6ef2e5764b11afa4ee8d4c9af0fd Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Mon, 28 Nov 2022 21:45:53 +0000 Subject: [PATCH 219/656] Revert "Adding Ims Call Info to CallAttributes" Revert submission 19673329-IMSCallInfo_In_CallAttributes Reason for revert: Reverted Changes: Id5c4ba0b6:Add CTS for CallAttributesListener Ic7b5adefd:Adding Ims Call Info to CallAttributes I1584524ce:Notify IMS Call info via CallAttributesListener Change-Id: I158c48822b0fdbcaad9303b3035d32aad0c5f048 --- .../telephony/DefaultPhoneNotifier.java | 23 +-- .../internal/telephony/GsmCdmaPhone.java | 5 +- .../com/android/internal/telephony/Phone.java | 13 +- .../internal/telephony/PhoneNotifier.java | 6 +- .../telephony/imsphone/ImsPhoneBase.java | 35 +--- .../telephony/imsphone/ImsPhoneCall.java | 37 ---- .../internal/telephony/CallStateTest.java | 177 ------------------ .../telephony/DefaultPhoneNotifierTest.java | 161 ++++------------ .../telephony/imsphone/ImsPhoneCallTest.java | 48 ----- 9 files changed, 53 insertions(+), 452 deletions(-) delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java index cabceb2fc7..e4aff4c911 100644 --- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -18,7 +18,6 @@ package com.android.internal.telephony; import android.annotation.NonNull; import android.content.Context; -import android.telephony.Annotation; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SrvccState; import android.telephony.BarringInfo; @@ -35,7 +34,6 @@ import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager.DataEnabledReason; import android.telephony.TelephonyRegistryManager; import android.telephony.emergency.EmergencyNumber; -import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsReasonInfo; import com.android.telephony.Rlog; @@ -144,28 +142,15 @@ public class DefaultPhoneNotifier implements PhoneNotifier { mTelephonyRegistryMgr.notifyCellInfoChanged(subId, cellInfo); } - /** - * Notify precise call state of foreground, background and ringing call states. - * - * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId} for - * ringing, foreground & background calls. - * @param imsCallServiceTypes Array of IMS call service type for ringing, foreground & - * background calls. - * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls. - */ - public void notifyPreciseCallState(Phone sender, String[] imsCallIds, - @Annotation.ImsCallServiceType int[] imsCallServiceTypes, - @Annotation.ImsCallType int[] imsCallTypes) { + public void notifyPreciseCallState(Phone sender) { Call ringingCall = sender.getRingingCall(); Call foregroundCall = sender.getForegroundCall(); Call backgroundCall = sender.getBackgroundCall(); - if (ringingCall != null && foregroundCall != null && backgroundCall != null) { - int[] callStates = {convertPreciseCallState(ringingCall.getState()), - convertPreciseCallState(foregroundCall.getState()), - convertPreciseCallState(backgroundCall.getState())}; mTelephonyRegistryMgr.notifyPreciseCallState(sender.getPhoneId(), sender.getSubId(), - callStates, imsCallIds, imsCallServiceTypes, imsCallTypes); + convertPreciseCallState(ringingCall.getState()), + convertPreciseCallState(foregroundCall.getState()), + convertPreciseCallState(backgroundCall.getState())); } } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index ed891b4dac..6d16fe072a 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -842,10 +842,7 @@ public class GsmCdmaPhone extends Phone { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void notifyPreciseCallStateChanged() { /* we'd love it if this was package-scoped*/ - AsyncResult ar = new AsyncResult(null, this, null); - mPreciseCallStateRegistrants.notifyRegistrants(ar); - - mNotifier.notifyPreciseCallState(this, null, null, null); + super.notifyPreciseCallStateChangedP(); } public void notifyNewRingingConnection(Connection c) { diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index b9c1868303..99bd3c5358 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -399,7 +399,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public static final String EXTRA_KEY_ALERT_SHOW = "alertShow"; public static final String EXTRA_KEY_NOTIFICATION_MESSAGE = "notificationMessage"; - protected final RegistrantList mPreciseCallStateRegistrants = new RegistrantList(); + private final RegistrantList mPreciseCallStateRegistrants = new RegistrantList(); private final RegistrantList mHandoverRegistrants = new RegistrantList(); @@ -984,6 +984,17 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mPreciseCallStateRegistrants.remove(h); } + /** + * Subclasses of Phone probably want to replace this with a + * version scoped to their packages + */ + protected void notifyPreciseCallStateChangedP() { + AsyncResult ar = new AsyncResult(null, this, null); + mPreciseCallStateRegistrants.notifyRegistrants(ar); + + mNotifier.notifyPreciseCallState(this); + } + /** * Notifies when a Handover happens due to SRVCC or Silent Redial */ diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java index 7617bdf225..701a157f98 100644 --- a/src/java/com/android/internal/telephony/PhoneNotifier.java +++ b/src/java/com/android/internal/telephony/PhoneNotifier.java @@ -18,7 +18,6 @@ package com.android.internal.telephony; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; -import android.telephony.Annotation; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SrvccState; import android.telephony.BarringInfo; @@ -79,10 +78,7 @@ public interface PhoneNotifier { void notifyCellInfo(Phone sender, List cellInfo); - /** Send a notification that precise call state changed. */ - void notifyPreciseCallState(Phone sender, String[] imsCallIds, - @Annotation.ImsCallServiceType int[] imsCallServiceTypes, - @Annotation.ImsCallType int[] imsCallTypes); + void notifyPreciseCallState(Phone sender); void notifyDisconnectCause(Phone sender, int cause, int preciseCause); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index 2ae9dc54ba..322dd55f7c 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -24,7 +24,6 @@ import android.os.RegistrantList; import android.sysprop.TelephonyProperties; import android.telephony.Annotation.DataActivityType; import android.telephony.CallQuality; -import android.telephony.CallState; import android.telephony.NetworkScanRequest; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -199,39 +198,7 @@ abstract class ImsPhoneBase extends Phone { */ public void notifyPreciseCallStateChanged() { /* we'd love it if this was package-scoped*/ - AsyncResult ar = new AsyncResult(null, this, null); - mPreciseCallStateRegistrants.notifyRegistrants(ar); - - ImsPhoneCall ringingCall = (ImsPhoneCall) getRingingCall(); - ImsPhoneCall foregroundCall = (ImsPhoneCall) getForegroundCall(); - ImsPhoneCall backgroundCall = (ImsPhoneCall) getBackgroundCall(); - - if (ringingCall != null && foregroundCall != null && backgroundCall != null) { - //Array for IMS call session ID of RINGING/FOREGROUND/BACKGROUND call - String[] imsCallIds = new String[CallState.CALL_CLASSIFICATION_MAX]; - //Array for IMS call service type of RINGING/FOREGROUND/BACKGROUND call - int[] imsCallServiceTypes = new int[CallState.CALL_CLASSIFICATION_MAX]; - //Array for IMS call type of RINGING/FOREGROUND/BACKGROUND call - int[] imsCallTypes = new int[CallState.CALL_CLASSIFICATION_MAX]; - imsCallIds[CallState.CALL_CLASSIFICATION_RINGING] = - ringingCall.getCallSessionId(); - imsCallIds[CallState.CALL_CLASSIFICATION_FOREGROUND] = - foregroundCall.getCallSessionId(); - imsCallIds[CallState.CALL_CLASSIFICATION_BACKGROUND] = - backgroundCall.getCallSessionId(); - imsCallServiceTypes[CallState.CALL_CLASSIFICATION_RINGING] = - ringingCall.getServiceType(); - imsCallServiceTypes[CallState.CALL_CLASSIFICATION_FOREGROUND] = - foregroundCall.getServiceType(); - imsCallServiceTypes[CallState.CALL_CLASSIFICATION_BACKGROUND] = - backgroundCall.getServiceType(); - imsCallTypes[CallState.CALL_CLASSIFICATION_RINGING] = ringingCall.getCallType(); - imsCallTypes[CallState.CALL_CLASSIFICATION_FOREGROUND] = - foregroundCall.getCallType(); - imsCallTypes[CallState.CALL_CLASSIFICATION_BACKGROUND] = - backgroundCall.getCallType(); - mNotifier.notifyPreciseCallState(this, imsCallIds, imsCallServiceTypes, imsCallTypes); - } + super.notifyPreciseCallStateChangedP(); } public void notifyDisconnect(Connection cn) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java index 7a6adce8af..98cc441861 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java @@ -19,8 +19,6 @@ package com.android.internal.telephony.imsphone; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.telephony.DisconnectCause; -import android.telephony.ims.ImsCallProfile; -import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsStreamMediaProfile; import android.util.Log; @@ -329,41 +327,6 @@ public class ImsPhoneCall extends Call { return (connection == null) ? null : connection.getImsCall(); } - /** - * Retrieves the {@link ImsCallSession#getCallId()} for the current {@link ImsPhoneCall}. - */ - @VisibleForTesting - public String getCallSessionId() { - return ((getImsCall() == null) ? null : getImsCall().getSession()) == null - ? null : getImsCall().getSession().getCallId(); - } - - /** - * Retrieves the service type in {@link ImsCallProfile} for the current {@link ImsPhoneCall}. - */ - @VisibleForTesting - public int getServiceType() { - if (getFirstConnection() == null) { - return ImsCallProfile.SERVICE_TYPE_NONE; - } else { - return getFirstConnection().isEmergencyCall() - ? ImsCallProfile.SERVICE_TYPE_EMERGENCY : ImsCallProfile.SERVICE_TYPE_NORMAL; - } - } - - /** - * Retrieves the call type in {@link ImsCallProfile} for the current {@link ImsPhoneCall}. - */ - @VisibleForTesting - public int getCallType() { - if (getImsCall() == null) { - return ImsCallProfile.CALL_TYPE_NONE; - } else { - return getImsCall().isVideoCall() - ? ImsCallProfile.CALL_TYPE_VT : ImsCallProfile.CALL_TYPE_VOICE; - } - } - /*package*/ static boolean isLocalTone(ImsCall imsCall) { if ((imsCall == null) || (imsCall.getCallProfile() == null) || (imsCall.getCallProfile().mMediaProfile == null)) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java deleted file mode 100644 index 4e319a12dc..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony; - -import static org.junit.Assert.assertEquals; - -import android.os.Parcel; -import android.telephony.CallQuality; -import android.telephony.CallState; -import android.telephony.PreciseCallState; -import android.telephony.TelephonyManager; -import android.telephony.ims.ImsCallProfile; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -import org.junit.Test; - -/** - * Simple GTS test verifying the parceling and unparceling of CallAttributes. - */ -public class CallStateTest extends AndroidTestCase { - - - @SmallTest - public void testParcelUnparcelPreciseCallState() { - CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_INCOMING) - .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) - .setCallQuality(null) - .setCallClassification(CallState.CALL_CLASSIFICATION_RINGING) - .setImsCallSessionId("1") - .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) - .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); - - Parcel parcel = Parcel.obtain(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); - parcel.recycle(); - - assertEquals("PreciseCallState is not equal after parceled/unparceled", - data.getCallState(), - unparceledData.getCallState()); - } - - @SmallTest - public void testParcelUnparcelCallQuality() { - CallQuality quality = new CallQuality(); - CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_IDLE) - .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) - .setCallQuality(null) - .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) - .setImsCallSessionId(null) - .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) - .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); - - - Parcel parcel = Parcel.obtain(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); - parcel.recycle(); - - assertNull(unparceledData.getCallQuality()); - - data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_IDLE) - .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) - .setCallQuality(quality) - .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) - .setImsCallSessionId(null) - .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) - .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); - - - parcel = Parcel.obtain(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - unparceledData = CallState.CREATOR.createFromParcel(parcel); - parcel.recycle(); - - assertEquals("CallQuality is not equal after parceled/unparceled", - data.getCallQuality(), - unparceledData.getCallQuality()); - } - - @SmallTest - public void testParcelUnparcelNetworkTypeAndClassification() { - CallQuality quality = new CallQuality(); - CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_DIALING) - .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) - .setCallQuality(null) - .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) - .setImsCallSessionId("3") - .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) - .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); - - Parcel parcel = Parcel.obtain(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); - parcel.recycle(); - - assertEquals("NetworkType is not equal after parceled/unparceled", - data.getNetworkType(), - unparceledData.getNetworkType()); - assertEquals("Call classification is not equal after parceled/unparceled", - data.getCallClassification(), - unparceledData.getCallClassification()); - } - - @Test - public void testParcelUnparcelImsCallInfo() { - CallQuality quality = new CallQuality(); - CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_DIALING) - .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) - .setCallQuality(null) - .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) - .setImsCallSessionId(null) - .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NORMAL) - .setImsCallType(ImsCallProfile.CALL_TYPE_VOICE).build(); - - Parcel parcel = Parcel.obtain(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); - parcel.recycle(); - - assertNull(unparceledData.getImsCallSessionId()); - - assertEquals("Ims call service type is not equal after parceled/unparceled", - data.getImsCallServiceType(), - unparceledData.getImsCallServiceType()); - - assertEquals("Ims call type is not equal after parceled/unparceled", - data.getImsCallType(), - unparceledData.getImsCallType()); - - data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE) - .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) - .setCallQuality(quality) - .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) - .setImsCallSessionId("2") - .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NORMAL) - .setImsCallType(ImsCallProfile.CALL_TYPE_VT).build(); - - parcel = Parcel.obtain(); - data.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - unparceledData = CallState.CREATOR.createFromParcel(parcel); - parcel.recycle(); - - assertEquals("Ims call session ID is not equal after parceled/unparceled", - data.getImsCallSessionId(), - unparceledData.getImsCallSessionId()); - - assertEquals("Ims call service type is not equal after parceled/unparceled", - data.getImsCallServiceType(), - unparceledData.getImsCallServiceType()); - - assertEquals("Ims call type is not equal after parceled/unparceled", - data.getImsCallType(), - unparceledData.getImsCallType()); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java index 2f4182a993..6a05d4f4b8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java @@ -16,7 +16,6 @@ package com.android.internal.telephony; import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; @@ -31,11 +30,8 @@ import android.telephony.PreciseCallState; import android.telephony.PreciseDisconnectCause; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; -import android.telephony.ims.ImsCallProfile; import android.test.suitebuilder.annotation.SmallTest; -import com.android.internal.telephony.imsphone.ImsPhoneCall; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -57,9 +53,6 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { GsmCdmaCall mForeGroundCall; GsmCdmaCall mBackGroundCall; GsmCdmaCall mRingingCall; - ImsPhoneCall mImsForeGroundCall; - ImsPhoneCall mImsBackGroundCall; - ImsPhoneCall mImsRingingCall; @Before public void setUp() throws Exception { @@ -69,9 +62,6 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { mForeGroundCall = mock(GsmCdmaCall.class); mBackGroundCall = mock(GsmCdmaCall.class); mRingingCall = mock(GsmCdmaCall.class); - mImsForeGroundCall = mock(ImsPhoneCall.class); - mImsBackGroundCall = mock(ImsPhoneCall.class); - mImsRingingCall = mock(ImsPhoneCall.class); mDefaultPhoneNotifierUT = new DefaultPhoneNotifier(mContext); } @@ -178,144 +168,61 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { @Test @SmallTest public void testNotifyPreciseCallState() throws Exception { + //mock forground/background/ringing call and call state doReturn(Call.State.IDLE).when(mForeGroundCall).getState(); doReturn(Call.State.IDLE).when(mBackGroundCall).getState(); doReturn(Call.State.IDLE).when(mRingingCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); verify(mTelephonyRegistryManager, times(0)).notifyPreciseCallState( - anyInt(), anyInt(), any(), any(), any(), any()); + anyInt(), anyInt(), anyInt(), anyInt(), anyInt()); doReturn(mForeGroundCall).when(mPhone).getForegroundCall(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); verify(mTelephonyRegistryManager, times(0)).notifyPreciseCallState( - anyInt(), anyInt(), any(), any(), any(), any()); + anyInt(), anyInt(), anyInt(), anyInt(), anyInt()); doReturn(mBackGroundCall).when(mPhone).getBackgroundCall(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); verify(mTelephonyRegistryManager, times(0)).notifyPreciseCallState( - anyInt(), anyInt(), any(), any(), any(), any()); + anyInt(), anyInt(), anyInt(), anyInt(), anyInt()); doReturn(mRingingCall).when(mPhone).getRingingCall(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); - ArgumentCaptor captor = ArgumentCaptor.forClass(int[].class); - int phoneId = mPhone.getPhoneId(); - int subId = mPhone.getSubId(); - verify(mTelephonyRegistryManager).notifyPreciseCallState( - eq(phoneId), eq(subId), captor.capture(), eq(null), eq(null), eq(null)); - final int[] callStates = captor.getValue(); - assertEquals(3, callStates.length); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, - callStates[/*ringing call*/ 0]); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, - callStates[/*foreground call*/ 1]); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, - callStates[/*background call*/ 2]); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( + mPhone.getPhoneId(), + mPhone.getSubId(), + PreciseCallState.PRECISE_CALL_STATE_IDLE, + PreciseCallState.PRECISE_CALL_STATE_IDLE, + PreciseCallState.PRECISE_CALL_STATE_IDLE); doReturn(Call.State.ACTIVE).when(mForeGroundCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); - ArgumentCaptor captor1 = ArgumentCaptor.forClass(int[].class); - phoneId = mPhone.getPhoneId(); - subId = mPhone.getSubId(); - verify(mTelephonyRegistryManager, times(2)).notifyPreciseCallState( - eq(phoneId), eq(subId), captor1.capture(), eq(null), eq(null), eq(null)); - final int[] callStates1 = captor1.getValue(); - assertEquals(3, callStates1.length); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, - callStates1[/*ringing call*/ 0]); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, - callStates1[/*foreground call*/ 1]); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, - callStates1[/*background call*/ 2]); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( + mPhone.getPhoneId(), + mPhone.getSubId(), + PreciseCallState.PRECISE_CALL_STATE_IDLE, + PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + PreciseCallState.PRECISE_CALL_STATE_IDLE); doReturn(Call.State.HOLDING).when(mBackGroundCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); - ArgumentCaptor captor2 = ArgumentCaptor.forClass(int[].class); - verify(mTelephonyRegistryManager, times(3)).notifyPreciseCallState( - eq(phoneId), eq(subId), captor2.capture(), eq(null), eq(null), eq(null)); - final int[] callStates2 = captor2.getValue(); - assertEquals(3, callStates2.length); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, - callStates2[/*ringing call*/ 0]); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, - callStates2[/*foreground call*/ 1]); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, - callStates2[/*background call*/ 2]); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( + mPhone.getPhoneId(), + mPhone.getSubId(), + PreciseCallState.PRECISE_CALL_STATE_IDLE, + PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + PreciseCallState.PRECISE_CALL_STATE_HOLDING); doReturn(Call.State.ALERTING).when(mRingingCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); - ArgumentCaptor captor3 = ArgumentCaptor.forClass(int[].class); - verify(mTelephonyRegistryManager, times(4)).notifyPreciseCallState( - eq(phoneId), eq(subId), captor3.capture(), eq(null), eq(null), eq(null)); - final int[] callStates3 = captor3.getValue(); - assertEquals(3, callStates3.length); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_ALERTING, - callStates3[/*ringing call*/ 0]); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, - callStates3[/*foreground call*/ 1]); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, - callStates3[/*background call*/ 2]); - } - - @Test - public void testNotifyPreciseCallStateImsCallInfo() throws Exception { - //mock forground/background/ringing call and call state - doReturn(Call.State.ACTIVE).when(mImsForeGroundCall).getState(); - doReturn(Call.State.HOLDING).when(mImsBackGroundCall).getState(); - doReturn(Call.State.IDLE).when(mImsRingingCall).getState(); - - doReturn(mImsForeGroundCall).when(mImsPhone).getForegroundCall(); - doReturn(mImsBackGroundCall).when(mImsPhone).getBackgroundCall(); - doReturn(mImsRingingCall).when(mImsPhone).getRingingCall(); - - String[] imsCallIds = {null, "1", "2"}; - int[] imsCallServiceTypes = {ImsCallProfile.SERVICE_TYPE_NONE, - ImsCallProfile.SERVICE_TYPE_NORMAL, ImsCallProfile.SERVICE_TYPE_NORMAL}; - int[] imsCallTypes = {ImsCallProfile.CALL_TYPE_NONE, - ImsCallProfile.CALL_TYPE_VOICE, ImsCallProfile.CALL_TYPE_VT}; - - mDefaultPhoneNotifierUT - .notifyPreciseCallState(mImsPhone, imsCallIds, imsCallServiceTypes, imsCallTypes); - ArgumentCaptor callStateCaptor = ArgumentCaptor.forClass(int[].class); - ArgumentCaptor callIdCaptor = ArgumentCaptor.forClass(String[].class); - ArgumentCaptor callServiceTypeCaptor = ArgumentCaptor.forClass(int[].class); - ArgumentCaptor callTypeCaptor = ArgumentCaptor.forClass(int[].class); - int phoneId = mImsPhone.getPhoneId(); - int subId = mImsPhone.getSubId(); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( - eq(phoneId), eq(subId), callStateCaptor.capture(), callIdCaptor.capture(), - callServiceTypeCaptor.capture(), callTypeCaptor.capture()); - final int[] callStates = callStateCaptor.getValue(); - final String[] callIds = callIdCaptor.getValue(); - final int[] callServiceTypes = callServiceTypeCaptor.getValue(); - final int[] callTypes = callTypeCaptor.getValue(); - assertEquals(3, callStates.length); - assertEquals(3, callIds.length); - assertEquals(3, callServiceTypes.length); - assertEquals(3, callServiceTypes.length); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, - callStates[/*ringing call*/ 0]); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, - callStates[/*foreground call*/ 1]); - assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, - callStates[/*background call*/ 2]); - - assertEquals("1", callIds[/*foreground call*/ 1]); - assertEquals("2", callIds[/*background call*/ 2]); - assertEquals(null, callIds[/*ringing call*/ 0]); - assertEquals(ImsCallProfile.SERVICE_TYPE_NORMAL, - callServiceTypes[/*foreground call*/ 1]); - assertEquals(ImsCallProfile.SERVICE_TYPE_NORMAL, - callServiceTypes[/*background call*/ 2]); - assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, - callServiceTypes[/*ringing call*/ 0]); - assertEquals(ImsCallProfile.CALL_TYPE_VOICE, - callTypes[/*foreground call*/ 1]); - assertEquals(ImsCallProfile.CALL_TYPE_VT, - callTypes[/*background call*/ 2]); - assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, - callServiceTypes[/*ringing call*/ 0]); + mPhone.getPhoneId(), + mPhone.getSubId(), + PreciseCallState.PRECISE_CALL_STATE_ALERTING, + PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + PreciseCallState.PRECISE_CALL_STATE_HOLDING); } @Test @SmallTest diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java index 13748e8ef3..c2db93ff6c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java @@ -18,7 +18,6 @@ package com.android.internal.telephony.imsphone; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; @@ -28,8 +27,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.telephony.ims.ImsCallProfile; -import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsStreamMediaProfile; import android.test.suitebuilder.annotation.SmallTest; @@ -259,51 +256,6 @@ public class ImsPhoneCallTest extends TelephonyTest { assertEquals(mImsCall, imsCall); } - @Test - @SmallTest - public void testGetCallSessionId() { - doReturn(mImsCall).when(mConnection1).getImsCall(); - ImsCallSession imsForegroundCallSession = mock(ImsCallSession.class); - doReturn(imsForegroundCallSession).when(mImsCall).getSession(); - doReturn("1").when(imsForegroundCallSession).getCallId(); - mImsCallUT.attach(mConnection1, Call.State.ACTIVE); - assertEquals("1", mImsCallUT.getCallSessionId()); - doReturn(null).when(mImsCall).getSession(); - assertNull(mImsCallUT.getCallSessionId()); - doReturn(null).when(mConnection1).getImsCall(); - assertNull(mImsCallUT.getCallSessionId()); - mImsCallUT.detach(mConnection1); - assertNull(mImsCallUT.getCallSessionId()); - } - - @Test - @SmallTest - public void testGetServiceType() { - doReturn(mImsCall).when(mConnection1).getImsCall(); - mImsCallUT.attach(mConnection1, Call.State.ACTIVE); - doReturn(false).when(mConnection1).isEmergencyCall(); - assertEquals(ImsCallProfile.SERVICE_TYPE_NORMAL, mImsCallUT.getServiceType()); - doReturn(true).when(mConnection1).isEmergencyCall(); - assertEquals(ImsCallProfile.SERVICE_TYPE_EMERGENCY, mImsCallUT.getServiceType()); - mImsCallUT.detach(mConnection1); - assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, mImsCallUT.getServiceType()); - } - - @Test - @SmallTest - public void testGetCallType() { - doReturn(mImsCall).when(mConnection1).getImsCall(); - mImsCallUT.attach(mConnection1, Call.State.ACTIVE); - doReturn(false).when(mImsCall).isVideoCall(); - assertEquals(ImsCallProfile.CALL_TYPE_VOICE, mImsCallUT.getCallType()); - doReturn(true).when(mImsCall).isVideoCall(); - assertEquals(ImsCallProfile.CALL_TYPE_VT, mImsCallUT.getCallType()); - doReturn(null).when(mConnection1).getImsCall(); - assertEquals(ImsCallProfile.CALL_TYPE_NONE, mImsCallUT.getCallType()); - mImsCallUT.detach(mConnection1); - assertEquals(ImsCallProfile.CALL_TYPE_NONE, mImsCallUT.getCallType()); - } - @Test @SmallTest public void testSetMute() { -- GitLab From 3a819be3e1c080eaba9bec204e8d7368ccf2bf55 Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Fri, 19 Aug 2022 03:25:30 +0000 Subject: [PATCH 220/656] Adding Ims Call Info to CallAttributes Provide IMS Call type & session ID to CallAttributes. That will be used for QNS handover decision. Bug: 242928210 Test: atest FrameworksTelephonyTests Change-Id: Ic7b5adefdc08d992d2c8d27f9843b91a88245eaa --- .../telephony/DefaultPhoneNotifier.java | 23 ++- .../internal/telephony/GsmCdmaPhone.java | 5 +- .../com/android/internal/telephony/Phone.java | 13 +- .../internal/telephony/PhoneNotifier.java | 6 +- .../telephony/imsphone/ImsPhoneBase.java | 35 +++- .../telephony/imsphone/ImsPhoneCall.java | 37 ++++ .../internal/telephony/CallStateTest.java | 177 ++++++++++++++++++ .../telephony/DefaultPhoneNotifierTest.java | 161 ++++++++++++---- .../telephony/imsphone/ImsPhoneCallTest.java | 48 +++++ 9 files changed, 452 insertions(+), 53 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java index e4aff4c911..cabceb2fc7 100644 --- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.annotation.NonNull; import android.content.Context; +import android.telephony.Annotation; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SrvccState; import android.telephony.BarringInfo; @@ -34,6 +35,7 @@ import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager.DataEnabledReason; import android.telephony.TelephonyRegistryManager; import android.telephony.emergency.EmergencyNumber; +import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsReasonInfo; import com.android.telephony.Rlog; @@ -142,15 +144,28 @@ public class DefaultPhoneNotifier implements PhoneNotifier { mTelephonyRegistryMgr.notifyCellInfoChanged(subId, cellInfo); } - public void notifyPreciseCallState(Phone sender) { + /** + * Notify precise call state of foreground, background and ringing call states. + * + * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId} for + * ringing, foreground & background calls. + * @param imsCallServiceTypes Array of IMS call service type for ringing, foreground & + * background calls. + * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls. + */ + public void notifyPreciseCallState(Phone sender, String[] imsCallIds, + @Annotation.ImsCallServiceType int[] imsCallServiceTypes, + @Annotation.ImsCallType int[] imsCallTypes) { Call ringingCall = sender.getRingingCall(); Call foregroundCall = sender.getForegroundCall(); Call backgroundCall = sender.getBackgroundCall(); + if (ringingCall != null && foregroundCall != null && backgroundCall != null) { - mTelephonyRegistryMgr.notifyPreciseCallState(sender.getPhoneId(), sender.getSubId(), - convertPreciseCallState(ringingCall.getState()), + int[] callStates = {convertPreciseCallState(ringingCall.getState()), convertPreciseCallState(foregroundCall.getState()), - convertPreciseCallState(backgroundCall.getState())); + convertPreciseCallState(backgroundCall.getState())}; + mTelephonyRegistryMgr.notifyPreciseCallState(sender.getPhoneId(), sender.getSubId(), + callStates, imsCallIds, imsCallServiceTypes, imsCallTypes); } } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 88bc03719d..6ca9d5cbf9 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -748,7 +748,10 @@ public class GsmCdmaPhone extends Phone { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void notifyPreciseCallStateChanged() { /* we'd love it if this was package-scoped*/ - super.notifyPreciseCallStateChangedP(); + AsyncResult ar = new AsyncResult(null, this, null); + mPreciseCallStateRegistrants.notifyRegistrants(ar); + + mNotifier.notifyPreciseCallState(this, null, null, null); } public void notifyNewRingingConnection(Connection c) { diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 9064ddf3cd..3bf0a4f7de 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -396,7 +396,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public static final String EXTRA_KEY_ALERT_SHOW = "alertShow"; public static final String EXTRA_KEY_NOTIFICATION_MESSAGE = "notificationMessage"; - private final RegistrantList mPreciseCallStateRegistrants = new RegistrantList(); + protected final RegistrantList mPreciseCallStateRegistrants = new RegistrantList(); private final RegistrantList mHandoverRegistrants = new RegistrantList(); @@ -977,17 +977,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mPreciseCallStateRegistrants.remove(h); } - /** - * Subclasses of Phone probably want to replace this with a - * version scoped to their packages - */ - protected void notifyPreciseCallStateChangedP() { - AsyncResult ar = new AsyncResult(null, this, null); - mPreciseCallStateRegistrants.notifyRegistrants(ar); - - mNotifier.notifyPreciseCallState(this); - } - /** * Notifies when a Handover happens due to SRVCC or Silent Redial */ diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java index 701a157f98..7617bdf225 100644 --- a/src/java/com/android/internal/telephony/PhoneNotifier.java +++ b/src/java/com/android/internal/telephony/PhoneNotifier.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; +import android.telephony.Annotation; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SrvccState; import android.telephony.BarringInfo; @@ -78,7 +79,10 @@ public interface PhoneNotifier { void notifyCellInfo(Phone sender, List cellInfo); - void notifyPreciseCallState(Phone sender); + /** Send a notification that precise call state changed. */ + void notifyPreciseCallState(Phone sender, String[] imsCallIds, + @Annotation.ImsCallServiceType int[] imsCallServiceTypes, + @Annotation.ImsCallType int[] imsCallTypes); void notifyDisconnectCause(Phone sender, int cause, int preciseCause); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index f9032bfc83..1d8a88c025 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -24,6 +24,7 @@ import android.os.RegistrantList; import android.sysprop.TelephonyProperties; import android.telephony.Annotation.DataActivityType; import android.telephony.CallQuality; +import android.telephony.CallState; import android.telephony.NetworkScanRequest; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -192,7 +193,39 @@ abstract class ImsPhoneBase extends Phone { */ public void notifyPreciseCallStateChanged() { /* we'd love it if this was package-scoped*/ - super.notifyPreciseCallStateChangedP(); + AsyncResult ar = new AsyncResult(null, this, null); + mPreciseCallStateRegistrants.notifyRegistrants(ar); + + ImsPhoneCall ringingCall = (ImsPhoneCall) getRingingCall(); + ImsPhoneCall foregroundCall = (ImsPhoneCall) getForegroundCall(); + ImsPhoneCall backgroundCall = (ImsPhoneCall) getBackgroundCall(); + + if (ringingCall != null && foregroundCall != null && backgroundCall != null) { + //Array for IMS call session ID of RINGING/FOREGROUND/BACKGROUND call + String[] imsCallIds = new String[CallState.CALL_CLASSIFICATION_MAX]; + //Array for IMS call service type of RINGING/FOREGROUND/BACKGROUND call + int[] imsCallServiceTypes = new int[CallState.CALL_CLASSIFICATION_MAX]; + //Array for IMS call type of RINGING/FOREGROUND/BACKGROUND call + int[] imsCallTypes = new int[CallState.CALL_CLASSIFICATION_MAX]; + imsCallIds[CallState.CALL_CLASSIFICATION_RINGING] = + ringingCall.getCallSessionId(); + imsCallIds[CallState.CALL_CLASSIFICATION_FOREGROUND] = + foregroundCall.getCallSessionId(); + imsCallIds[CallState.CALL_CLASSIFICATION_BACKGROUND] = + backgroundCall.getCallSessionId(); + imsCallServiceTypes[CallState.CALL_CLASSIFICATION_RINGING] = + ringingCall.getServiceType(); + imsCallServiceTypes[CallState.CALL_CLASSIFICATION_FOREGROUND] = + foregroundCall.getServiceType(); + imsCallServiceTypes[CallState.CALL_CLASSIFICATION_BACKGROUND] = + backgroundCall.getServiceType(); + imsCallTypes[CallState.CALL_CLASSIFICATION_RINGING] = ringingCall.getCallType(); + imsCallTypes[CallState.CALL_CLASSIFICATION_FOREGROUND] = + foregroundCall.getCallType(); + imsCallTypes[CallState.CALL_CLASSIFICATION_BACKGROUND] = + backgroundCall.getCallType(); + mNotifier.notifyPreciseCallState(this, imsCallIds, imsCallServiceTypes, imsCallTypes); + } } public void notifyDisconnect(Connection cn) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java index 98cc441861..7a6adce8af 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java @@ -19,6 +19,8 @@ package com.android.internal.telephony.imsphone; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.telephony.DisconnectCause; +import android.telephony.ims.ImsCallProfile; +import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsStreamMediaProfile; import android.util.Log; @@ -327,6 +329,41 @@ public class ImsPhoneCall extends Call { return (connection == null) ? null : connection.getImsCall(); } + /** + * Retrieves the {@link ImsCallSession#getCallId()} for the current {@link ImsPhoneCall}. + */ + @VisibleForTesting + public String getCallSessionId() { + return ((getImsCall() == null) ? null : getImsCall().getSession()) == null + ? null : getImsCall().getSession().getCallId(); + } + + /** + * Retrieves the service type in {@link ImsCallProfile} for the current {@link ImsPhoneCall}. + */ + @VisibleForTesting + public int getServiceType() { + if (getFirstConnection() == null) { + return ImsCallProfile.SERVICE_TYPE_NONE; + } else { + return getFirstConnection().isEmergencyCall() + ? ImsCallProfile.SERVICE_TYPE_EMERGENCY : ImsCallProfile.SERVICE_TYPE_NORMAL; + } + } + + /** + * Retrieves the call type in {@link ImsCallProfile} for the current {@link ImsPhoneCall}. + */ + @VisibleForTesting + public int getCallType() { + if (getImsCall() == null) { + return ImsCallProfile.CALL_TYPE_NONE; + } else { + return getImsCall().isVideoCall() + ? ImsCallProfile.CALL_TYPE_VT : ImsCallProfile.CALL_TYPE_VOICE; + } + } + /*package*/ static boolean isLocalTone(ImsCall imsCall) { if ((imsCall == null) || (imsCall.getCallProfile() == null) || (imsCall.getCallProfile().mMediaProfile == null)) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java new file mode 100644 index 0000000000..4e319a12dc --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/CallStateTest.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import static org.junit.Assert.assertEquals; + +import android.os.Parcel; +import android.telephony.CallQuality; +import android.telephony.CallState; +import android.telephony.PreciseCallState; +import android.telephony.TelephonyManager; +import android.telephony.ims.ImsCallProfile; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import org.junit.Test; + +/** + * Simple GTS test verifying the parceling and unparceling of CallAttributes. + */ +public class CallStateTest extends AndroidTestCase { + + + @SmallTest + public void testParcelUnparcelPreciseCallState() { + CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_INCOMING) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(null) + .setCallClassification(CallState.CALL_CLASSIFICATION_RINGING) + .setImsCallSessionId("1") + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) + .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); + + Parcel parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertEquals("PreciseCallState is not equal after parceled/unparceled", + data.getCallState(), + unparceledData.getCallState()); + } + + @SmallTest + public void testParcelUnparcelCallQuality() { + CallQuality quality = new CallQuality(); + CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_IDLE) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(null) + .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId(null) + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) + .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); + + + Parcel parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertNull(unparceledData.getCallQuality()); + + data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_IDLE) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(quality) + .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId(null) + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) + .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); + + + parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertEquals("CallQuality is not equal after parceled/unparceled", + data.getCallQuality(), + unparceledData.getCallQuality()); + } + + @SmallTest + public void testParcelUnparcelNetworkTypeAndClassification() { + CallQuality quality = new CallQuality(); + CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_DIALING) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(null) + .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId("3") + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NONE) + .setImsCallType(ImsCallProfile.CALL_TYPE_NONE).build(); + + Parcel parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertEquals("NetworkType is not equal after parceled/unparceled", + data.getNetworkType(), + unparceledData.getNetworkType()); + assertEquals("Call classification is not equal after parceled/unparceled", + data.getCallClassification(), + unparceledData.getCallClassification()); + } + + @Test + public void testParcelUnparcelImsCallInfo() { + CallQuality quality = new CallQuality(); + CallState data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_DIALING) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(null) + .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId(null) + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NORMAL) + .setImsCallType(ImsCallProfile.CALL_TYPE_VOICE).build(); + + Parcel parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + CallState unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertNull(unparceledData.getImsCallSessionId()); + + assertEquals("Ims call service type is not equal after parceled/unparceled", + data.getImsCallServiceType(), + unparceledData.getImsCallServiceType()); + + assertEquals("Ims call type is not equal after parceled/unparceled", + data.getImsCallType(), + unparceledData.getImsCallType()); + + data = new CallState.Builder(PreciseCallState.PRECISE_CALL_STATE_ACTIVE) + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCallQuality(quality) + .setCallClassification(CallState.CALL_CLASSIFICATION_FOREGROUND) + .setImsCallSessionId("2") + .setImsCallServiceType(ImsCallProfile.SERVICE_TYPE_NORMAL) + .setImsCallType(ImsCallProfile.CALL_TYPE_VT).build(); + + parcel = Parcel.obtain(); + data.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + unparceledData = CallState.CREATOR.createFromParcel(parcel); + parcel.recycle(); + + assertEquals("Ims call session ID is not equal after parceled/unparceled", + data.getImsCallSessionId(), + unparceledData.getImsCallSessionId()); + + assertEquals("Ims call service type is not equal after parceled/unparceled", + data.getImsCallServiceType(), + unparceledData.getImsCallServiceType()); + + assertEquals("Ims call type is not equal after parceled/unparceled", + data.getImsCallType(), + unparceledData.getImsCallType()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java index 6a05d4f4b8..2f4182a993 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; @@ -30,8 +31,11 @@ import android.telephony.PreciseCallState; import android.telephony.PreciseDisconnectCause; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; +import android.telephony.ims.ImsCallProfile; import android.test.suitebuilder.annotation.SmallTest; +import com.android.internal.telephony.imsphone.ImsPhoneCall; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -53,6 +57,9 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { GsmCdmaCall mForeGroundCall; GsmCdmaCall mBackGroundCall; GsmCdmaCall mRingingCall; + ImsPhoneCall mImsForeGroundCall; + ImsPhoneCall mImsBackGroundCall; + ImsPhoneCall mImsRingingCall; @Before public void setUp() throws Exception { @@ -62,6 +69,9 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { mForeGroundCall = mock(GsmCdmaCall.class); mBackGroundCall = mock(GsmCdmaCall.class); mRingingCall = mock(GsmCdmaCall.class); + mImsForeGroundCall = mock(ImsPhoneCall.class); + mImsBackGroundCall = mock(ImsPhoneCall.class); + mImsRingingCall = mock(ImsPhoneCall.class); mDefaultPhoneNotifierUT = new DefaultPhoneNotifier(mContext); } @@ -168,61 +178,144 @@ public class DefaultPhoneNotifierTest extends TelephonyTest { @Test @SmallTest public void testNotifyPreciseCallState() throws Exception { - //mock forground/background/ringing call and call state doReturn(Call.State.IDLE).when(mForeGroundCall).getState(); doReturn(Call.State.IDLE).when(mBackGroundCall).getState(); doReturn(Call.State.IDLE).when(mRingingCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); verify(mTelephonyRegistryManager, times(0)).notifyPreciseCallState( - anyInt(), anyInt(), anyInt(), anyInt(), anyInt()); + anyInt(), anyInt(), any(), any(), any(), any()); doReturn(mForeGroundCall).when(mPhone).getForegroundCall(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); verify(mTelephonyRegistryManager, times(0)).notifyPreciseCallState( - anyInt(), anyInt(), anyInt(), anyInt(), anyInt()); + anyInt(), anyInt(), any(), any(), any(), any()); doReturn(mBackGroundCall).when(mPhone).getBackgroundCall(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); verify(mTelephonyRegistryManager, times(0)).notifyPreciseCallState( - anyInt(), anyInt(), anyInt(), anyInt(), anyInt()); + anyInt(), anyInt(), any(), any(), any(), any()); doReturn(mRingingCall).when(mPhone).getRingingCall(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); - verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( - mPhone.getPhoneId(), - mPhone.getSubId(), - PreciseCallState.PRECISE_CALL_STATE_IDLE, - PreciseCallState.PRECISE_CALL_STATE_IDLE, - PreciseCallState.PRECISE_CALL_STATE_IDLE); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + ArgumentCaptor captor = ArgumentCaptor.forClass(int[].class); + int phoneId = mPhone.getPhoneId(); + int subId = mPhone.getSubId(); + verify(mTelephonyRegistryManager).notifyPreciseCallState( + eq(phoneId), eq(subId), captor.capture(), eq(null), eq(null), eq(null)); + final int[] callStates = captor.getValue(); + assertEquals(3, callStates.length); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates[/*ringing call*/ 0]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates[/*foreground call*/ 1]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates[/*background call*/ 2]); doReturn(Call.State.ACTIVE).when(mForeGroundCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); - verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( - mPhone.getPhoneId(), - mPhone.getSubId(), - PreciseCallState.PRECISE_CALL_STATE_IDLE, - PreciseCallState.PRECISE_CALL_STATE_ACTIVE, - PreciseCallState.PRECISE_CALL_STATE_IDLE); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + ArgumentCaptor captor1 = ArgumentCaptor.forClass(int[].class); + phoneId = mPhone.getPhoneId(); + subId = mPhone.getSubId(); + verify(mTelephonyRegistryManager, times(2)).notifyPreciseCallState( + eq(phoneId), eq(subId), captor1.capture(), eq(null), eq(null), eq(null)); + final int[] callStates1 = captor1.getValue(); + assertEquals(3, callStates1.length); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates1[/*ringing call*/ 0]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + callStates1[/*foreground call*/ 1]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates1[/*background call*/ 2]); doReturn(Call.State.HOLDING).when(mBackGroundCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); - verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( - mPhone.getPhoneId(), - mPhone.getSubId(), - PreciseCallState.PRECISE_CALL_STATE_IDLE, - PreciseCallState.PRECISE_CALL_STATE_ACTIVE, - PreciseCallState.PRECISE_CALL_STATE_HOLDING); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + ArgumentCaptor captor2 = ArgumentCaptor.forClass(int[].class); + verify(mTelephonyRegistryManager, times(3)).notifyPreciseCallState( + eq(phoneId), eq(subId), captor2.capture(), eq(null), eq(null), eq(null)); + final int[] callStates2 = captor2.getValue(); + assertEquals(3, callStates2.length); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates2[/*ringing call*/ 0]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + callStates2[/*foreground call*/ 1]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, + callStates2[/*background call*/ 2]); doReturn(Call.State.ALERTING).when(mRingingCall).getState(); - mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone); + mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone, null, null, null); + ArgumentCaptor captor3 = ArgumentCaptor.forClass(int[].class); + verify(mTelephonyRegistryManager, times(4)).notifyPreciseCallState( + eq(phoneId), eq(subId), captor3.capture(), eq(null), eq(null), eq(null)); + final int[] callStates3 = captor3.getValue(); + assertEquals(3, callStates3.length); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_ALERTING, + callStates3[/*ringing call*/ 0]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + callStates3[/*foreground call*/ 1]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, + callStates3[/*background call*/ 2]); + } + + @Test + public void testNotifyPreciseCallStateImsCallInfo() throws Exception { + //mock forground/background/ringing call and call state + doReturn(Call.State.ACTIVE).when(mImsForeGroundCall).getState(); + doReturn(Call.State.HOLDING).when(mImsBackGroundCall).getState(); + doReturn(Call.State.IDLE).when(mImsRingingCall).getState(); + + doReturn(mImsForeGroundCall).when(mImsPhone).getForegroundCall(); + doReturn(mImsBackGroundCall).when(mImsPhone).getBackgroundCall(); + doReturn(mImsRingingCall).when(mImsPhone).getRingingCall(); + + String[] imsCallIds = {null, "1", "2"}; + int[] imsCallServiceTypes = {ImsCallProfile.SERVICE_TYPE_NONE, + ImsCallProfile.SERVICE_TYPE_NORMAL, ImsCallProfile.SERVICE_TYPE_NORMAL}; + int[] imsCallTypes = {ImsCallProfile.CALL_TYPE_NONE, + ImsCallProfile.CALL_TYPE_VOICE, ImsCallProfile.CALL_TYPE_VT}; + + mDefaultPhoneNotifierUT + .notifyPreciseCallState(mImsPhone, imsCallIds, imsCallServiceTypes, imsCallTypes); + ArgumentCaptor callStateCaptor = ArgumentCaptor.forClass(int[].class); + ArgumentCaptor callIdCaptor = ArgumentCaptor.forClass(String[].class); + ArgumentCaptor callServiceTypeCaptor = ArgumentCaptor.forClass(int[].class); + ArgumentCaptor callTypeCaptor = ArgumentCaptor.forClass(int[].class); + int phoneId = mImsPhone.getPhoneId(); + int subId = mImsPhone.getSubId(); verify(mTelephonyRegistryManager, times(1)).notifyPreciseCallState( - mPhone.getPhoneId(), - mPhone.getSubId(), - PreciseCallState.PRECISE_CALL_STATE_ALERTING, - PreciseCallState.PRECISE_CALL_STATE_ACTIVE, - PreciseCallState.PRECISE_CALL_STATE_HOLDING); + eq(phoneId), eq(subId), callStateCaptor.capture(), callIdCaptor.capture(), + callServiceTypeCaptor.capture(), callTypeCaptor.capture()); + final int[] callStates = callStateCaptor.getValue(); + final String[] callIds = callIdCaptor.getValue(); + final int[] callServiceTypes = callServiceTypeCaptor.getValue(); + final int[] callTypes = callTypeCaptor.getValue(); + assertEquals(3, callStates.length); + assertEquals(3, callIds.length); + assertEquals(3, callServiceTypes.length); + assertEquals(3, callServiceTypes.length); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_IDLE, + callStates[/*ringing call*/ 0]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_ACTIVE, + callStates[/*foreground call*/ 1]); + assertEquals(PreciseCallState.PRECISE_CALL_STATE_HOLDING, + callStates[/*background call*/ 2]); + + assertEquals("1", callIds[/*foreground call*/ 1]); + assertEquals("2", callIds[/*background call*/ 2]); + assertEquals(null, callIds[/*ringing call*/ 0]); + assertEquals(ImsCallProfile.SERVICE_TYPE_NORMAL, + callServiceTypes[/*foreground call*/ 1]); + assertEquals(ImsCallProfile.SERVICE_TYPE_NORMAL, + callServiceTypes[/*background call*/ 2]); + assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, + callServiceTypes[/*ringing call*/ 0]); + assertEquals(ImsCallProfile.CALL_TYPE_VOICE, + callTypes[/*foreground call*/ 1]); + assertEquals(ImsCallProfile.CALL_TYPE_VT, + callTypes[/*background call*/ 2]); + assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, + callServiceTypes[/*ringing call*/ 0]); } @Test @SmallTest diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java index c2db93ff6c..13748e8ef3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony.imsphone; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; @@ -27,6 +28,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.telephony.ims.ImsCallProfile; +import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsStreamMediaProfile; import android.test.suitebuilder.annotation.SmallTest; @@ -256,6 +259,51 @@ public class ImsPhoneCallTest extends TelephonyTest { assertEquals(mImsCall, imsCall); } + @Test + @SmallTest + public void testGetCallSessionId() { + doReturn(mImsCall).when(mConnection1).getImsCall(); + ImsCallSession imsForegroundCallSession = mock(ImsCallSession.class); + doReturn(imsForegroundCallSession).when(mImsCall).getSession(); + doReturn("1").when(imsForegroundCallSession).getCallId(); + mImsCallUT.attach(mConnection1, Call.State.ACTIVE); + assertEquals("1", mImsCallUT.getCallSessionId()); + doReturn(null).when(mImsCall).getSession(); + assertNull(mImsCallUT.getCallSessionId()); + doReturn(null).when(mConnection1).getImsCall(); + assertNull(mImsCallUT.getCallSessionId()); + mImsCallUT.detach(mConnection1); + assertNull(mImsCallUT.getCallSessionId()); + } + + @Test + @SmallTest + public void testGetServiceType() { + doReturn(mImsCall).when(mConnection1).getImsCall(); + mImsCallUT.attach(mConnection1, Call.State.ACTIVE); + doReturn(false).when(mConnection1).isEmergencyCall(); + assertEquals(ImsCallProfile.SERVICE_TYPE_NORMAL, mImsCallUT.getServiceType()); + doReturn(true).when(mConnection1).isEmergencyCall(); + assertEquals(ImsCallProfile.SERVICE_TYPE_EMERGENCY, mImsCallUT.getServiceType()); + mImsCallUT.detach(mConnection1); + assertEquals(ImsCallProfile.SERVICE_TYPE_NONE, mImsCallUT.getServiceType()); + } + + @Test + @SmallTest + public void testGetCallType() { + doReturn(mImsCall).when(mConnection1).getImsCall(); + mImsCallUT.attach(mConnection1, Call.State.ACTIVE); + doReturn(false).when(mImsCall).isVideoCall(); + assertEquals(ImsCallProfile.CALL_TYPE_VOICE, mImsCallUT.getCallType()); + doReturn(true).when(mImsCall).isVideoCall(); + assertEquals(ImsCallProfile.CALL_TYPE_VT, mImsCallUT.getCallType()); + doReturn(null).when(mConnection1).getImsCall(); + assertEquals(ImsCallProfile.CALL_TYPE_NONE, mImsCallUT.getCallType()); + mImsCallUT.detach(mConnection1); + assertEquals(ImsCallProfile.CALL_TYPE_NONE, mImsCallUT.getCallType()); + } + @Test @SmallTest public void testSetMute() { -- GitLab From 4d18f048015cd0e016822136c27017f12e16daf9 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 24 Nov 2022 12:53:31 -0800 Subject: [PATCH 221/656] Added getAvailableSubscriptionInfoList Bug: 239607619 Test: atest SubscriptionManagerServiceTest Change-Id: Ic9c5b1a582f7d872388c9caa5fe58e68508c945b --- .../telephony/NetworkScanRequestTracker.java | 9 ++ .../SubscriptionInfoInternal.java | 7 ++ .../SubscriptionManagerService.java | 115 ++++++++++++++---- .../internal/telephony/ContextFixture.java | 2 + .../SubscriptionDatabaseManagerTest.java | 16 ++- .../SubscriptionManagerServiceTest.java | 69 ++++++++--- 6 files changed, 172 insertions(+), 46 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java index ea68cbae41..d576a09719 100644 --- a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java +++ b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java @@ -42,6 +42,8 @@ import android.telephony.SubscriptionInfo; import android.telephony.TelephonyScanManager; import android.util.Log; +import com.android.internal.telephony.subscription.SubscriptionManagerService; + import java.util.Collection; import java.util.List; import java.util.Set; @@ -195,6 +197,13 @@ public final class NetworkScanRequestTracker { public static Set getAllowedMccMncsForLocationRestrictedScan(Context context) { final long token = Binder.clearCallingIdentity(); try { + if (PhoneFactory.getDefaultPhone().isSubscriptionManagerServiceEnabled()) { + return SubscriptionManagerService.getInstance() + .getAvailableSubscriptionInfoList(context.getOpPackageName(), + context.getAttributionTag()).stream() + .flatMap(NetworkScanRequestTracker::getAllowableMccMncsFromSubscriptionInfo) + .collect(Collectors.toSet()); + } return SubscriptionController.getInstance() .getAvailableSubscriptionInfoList(context.getOpPackageName(), context.getAttributionTag()).stream() diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index c9f2ab47ea..8076242824 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -973,6 +973,13 @@ public class SubscriptionInfoInternal { return mIsGroupDisabled; } + /** + * @return {@code true} if the subscription is from the actively used SIM. + */ + public boolean isActive() { + return mSimSlotIndex >= 0 || mType == SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM; + } + /** @return converted {@link SubscriptionInfo}. */ @NonNull public SubscriptionInfo toSubscriptionInfo() { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 4ec0f4cb4a..311006deca 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -20,10 +20,12 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.AppOpsManager; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -40,6 +42,7 @@ import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; +import android.telephony.euicc.EuiccManager; import android.text.TextUtils; import android.util.ArraySet; import android.util.EventLog; @@ -53,10 +56,14 @@ import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.uicc.UiccController; +import com.android.internal.telephony.uicc.UiccSlot; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -99,6 +106,12 @@ public class SubscriptionManagerService extends ISub.Stub { /** Subscription manager instance. */ private final SubscriptionManager mSubscriptionManager; + /** Euicc manager instance. */ + private final EuiccManager mEuiccManager; + + /** Uicc controller instance. */ + private final UiccController mUiccController; + /** The main handler of subscription manager service. */ @NonNull private final Handler mHandler; @@ -252,6 +265,8 @@ public class SubscriptionManagerService extends ISub.Stub { mContext = context; mTelephonyManager = context.getSystemService(TelephonyManager.class); mSubscriptionManager = context.getSystemService(SubscriptionManager.class); + mEuiccManager = context.getSystemService(EuiccManager.class); + mUiccController = UiccController.getInstance(); mHandler = new Handler(looper); TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = TelephonyFrameworkInitializer @@ -421,6 +436,29 @@ public class SubscriptionManagerService extends ISub.Stub { return result.build(); } + /** + * @return The list of ICCIDs from the inserted physical SIMs. + */ + @NonNull + private List getIccIdsOfInsertedPhysicalSims() { + List iccidList = new ArrayList<>(); + UiccSlot[] uiccSlots = mUiccController.getUiccSlots(); + if (uiccSlots == null) return iccidList; + + for (UiccSlot uiccSlot : uiccSlots) { + if (uiccSlot != null && uiccSlot.getCardState() != null + && uiccSlot.getCardState().isCardPresent() && !uiccSlot.isEuicc()) { + // Non euicc slots will have single port, so use default port index. + String iccId = uiccSlot.getIccId(TelephonyManager.DEFAULT_PORT_INDEX); + if (!TextUtils.isEmpty(iccId)) { + iccidList.add(IccUtils.stripTrailingFs(iccId)); + } + } + } + + return iccidList; + } + /** * Set the subscription carrier id. * @@ -477,8 +515,13 @@ public class SubscriptionManagerService extends ISub.Stub { * */ @Override + @NonNull public List getAllSubInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos // on the subs it has carrier privilege. @@ -605,12 +648,41 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * @see SubscriptionManager#getAvailableSubscriptionInfoList + * Gets the SubscriptionInfo(s) of all available subscriptions, if any. + * + * Available subscriptions include active ones (those with a non-negative + * {@link SubscriptionInfo#getSimSlotIndex()}) as well as inactive but installed embedded + * subscriptions. */ @Override + @NonNull public List getAvailableSubscriptionInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { - return null; + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + enforcePermissions("getAvailableSubscriptionInfoList", + Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + // Now that all security checks pass, perform the operation as ourselves. + final long identity = Binder.clearCallingIdentity(); + try { + // Available eSIM profiles are reported by EuiccManager. However for physical SIMs if + // they are in inactive slot or programmatically disabled, they are still considered + // available. In this case we get their iccid from slot info and include their + // subscriptionInfos. + List iccIds = getIccIdsOfInsertedPhysicalSims(); + + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(subInfo -> subInfo.isActive() || iccIds.contains(subInfo.getIccId()) + || (mEuiccManager.isEnabled() && subInfo.isEmbedded())) + .map(SubscriptionInfoInternal::toSubscriptionInfo) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -646,7 +718,7 @@ public class SubscriptionManagerService extends ISub.Stub { log("addSubInfo: iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + ", slotIndex=" + slotIndex + ", displayName=" + displayName + ", type=" + SubscriptionManager.subscriptionTypeToString(subscriptionType)); - enforceModifyPhoneState("addSubInfo"); + enforcePermissions("addSubInfo", Manifest.permission.MODIFY_PHONE_STATE); // Now that all security checks passes, perform the operation as ourselves. final long identity = Binder.clearCallingIdentity(); @@ -1127,33 +1199,22 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Enforce {@link android.Manifest.permission#MODIFY_PHONE_STATE} permission + * Enforce callers have any of the provided permissions. * - * @param message Error message included in the exception. - */ - private void enforceModifyPhoneState(String message) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE, message); - } - - /** - * Enforce {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} permission + * @param message Message to include in the exception. + * @param permissions The permissions to enforce. * - * @param message Error message included in the exception. + * @throws SecurityException if the caller does not have any permissions. */ - private void enforceReadPrivilegedPhoneState(String message) { - mContext.enforceCallingOrSelfPermission( - Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message); - } - - /** - * Enforce {@link android.Manifest.permission#MANAGE_SUBSCRIPTION_USER_ASSOCIATION} permission - * - * @param message Error message included in the exception. - */ - private void enforceManageSubscriptionUserAssociation(String message) { - mContext.enforceCallingOrSelfPermission( - Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION, message); + private void enforcePermissions(@Nullable String message, @NonNull String ...permissions) { + for (String permission : permissions) { + if (mContext.checkCallingOrSelfPermission(permission) + == PackageManager.PERMISSION_GRANTED) { + return; + } + } + throw new SecurityException(message + ". Does not have any of the following permissions. " + + Arrays.toString(permissions)); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java index b8c10a5c7a..82ade7388e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java @@ -349,6 +349,8 @@ public class ContextFixture implements TestFixture { return Context.NETWORK_POLICY_SERVICE; } else if (serviceClass == PowerManager.class) { return Context.POWER_SERVICE; + } else if (serviceClass == EuiccManager.class) { + return Context.EUICC_SERVICE; } return super.getSystemServiceName(serviceClass); } 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 c72efd09a3..6ca922de35 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -20,9 +20,11 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -111,6 +113,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO1 = new SubscriptionInfoInternal.Builder() + .setId(1) .setIccId(FAKE_ICCID1) .setSimSlotIndex(0) .setDisplayName(FAKE_CARRIER_NAME1) @@ -165,6 +168,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO2 = new SubscriptionInfoInternal.Builder() + .setId(2) .setIccId(FAKE_ICCID2) .setSimSlotIndex(1) .setDisplayName(FAKE_CARRIER_NAME2) @@ -364,9 +368,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { */ private SubscriptionInfoInternal insertSubscriptionAndVerify( @NonNull SubscriptionInfoInternal subInfo) throws Exception { - assertThat(subInfo.getSubscriptionId()).isEqualTo( - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - int subId = mDatabaseManagerUT.insertSubscriptionInfo(subInfo); + int subId = mDatabaseManagerUT.insertSubscriptionInfo( + new SubscriptionInfoInternal.Builder(subInfo) + .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID) + .build()); assertThat(SubscriptionManager.isValidSubscriptionId(subId)).isTrue(); subInfo = new SubscriptionInfoInternal.Builder(subInfo).setId(subId).build(); @@ -414,6 +419,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { processAllMessages(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + Mockito.clearInvocations(mSubscriptionDatabaseManagerCallback); + + // Same sub info again. Should not trigger callback + mDatabaseManagerUT.updateSubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, never()).onSubscriptionChanged(anyInt()); } @Test 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 632f9956d5..2ff3f8bf73 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -136,8 +136,17 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { super.tearDown(); } - private void insertSubscription(@NonNull SubscriptionInfoInternal subInfo) { + /** + * Insert the subscrtipion info to the database. + * + * @param subInfo The subscription to be inserted. + * @return The new sub id. + */ + private int insertSubscription(@NonNull SubscriptionInfoInternal subInfo) { try { + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID).build(); + Field field = SubscriptionManagerService.class.getDeclaredField( "mSubscriptionDatabaseManager"); field.setAccessible(true); @@ -149,10 +158,11 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { Method method = SubscriptionDatabaseManager.class.getDeclaredMethod( "insertSubscriptionInfo", cArgs); method.setAccessible(true); - method.invoke(sdbm, subInfo); + return (int) method.invoke(sdbm, subInfo); } catch (Exception e) { fail("Failed to insert subscription. e=" + e); } + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @Test @@ -292,13 +302,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { CALLING_PACKAGE, CALLING_FEATURE); assertThat(subInfos).hasSize(2); - assertThat(subInfos.get(0)).isEqualTo(new SubscriptionInfoInternal - .Builder(FAKE_SUBSCRIPTION_INFO1) - .setId(1).build().toSubscriptionInfo()); + assertThat(subInfos.get(0)).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); - assertThat(subInfos.get(1)).isEqualTo(new SubscriptionInfoInternal - .Builder(FAKE_SUBSCRIPTION_INFO2) - .setId(2).build().toSubscriptionInfo()); + assertThat(subInfos.get(1)).isEqualTo(FAKE_SUBSCRIPTION_INFO2.toSubscriptionInfo()); // Revoke carrier privilege for sub 2 setCarrierPrivilegesForSubId(false, 2); @@ -371,10 +377,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { ParcelUuid.fromString(FAKE_UUID1), CALLING_PACKAGE, CALLING_FEATURE); assertThat(subInfos).hasSize(2); - assertThat(subInfos.get(0)).isEqualTo(new SubscriptionInfoInternal.Builder( - FAKE_SUBSCRIPTION_INFO1).setId(1).build().toSubscriptionInfo()); - assertThat(subInfos.get(1)).isEqualTo(new SubscriptionInfoInternal.Builder(anotherSubInfo) - .setId(2).build().toSubscriptionInfo()); + assertThat(subInfos.get(0)).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); + assertThat(subInfos.get(1)).isEqualTo(anotherSubInfo.toSubscriptionInfo()); // Grant READ_PHONE_STATE permission mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); @@ -400,9 +404,42 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfos).hasSize(2); assertThat(subInfos).containsExactlyElementsIn( - List.of(new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO1) - .setId(1).build().toSubscriptionInfo(), - new SubscriptionInfoInternal.Builder(anotherSubInfo) - .setId(2).build().toSubscriptionInfo())); + List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo(), + anotherSubInfo.toSubscriptionInfo())); + } + + @Test + public void testGetAvailableSubscriptionInfoList() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + SubscriptionInfoInternal anotherSubInfo = + new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO2) + .setSimSlotIndex(SubscriptionManager.INVALID_SIM_SLOT_INDEX) + .setType(SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM) + .build(); + insertSubscription(anotherSubInfo); + + assertThrows(SecurityException.class, + () -> mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE)); + // Grant carrier privilege for sub 1 + setCarrierPrivilegesForSubId(true, 1); + + // Not yet planned for carrier apps to access this API. + assertThrows(SecurityException.class, + () -> mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE)); + + // Grant READ_PHONE_STATE permission, which is not enough for this API. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); + assertThrows(SecurityException.class, + () -> mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE)); + + // Grant READ_PRIVILEGED_PHONE_STATE permission + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + List subInfos = mSubscriptionManagerServiceUT + .getAvailableSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE); + assertThat(subInfos).hasSize(1); + assertThat(subInfos.get(0)).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); } } -- GitLab From 6bc52d7718008b7e889e3d90fc6a6177c25dd0d8 Mon Sep 17 00:00:00 2001 From: Saloni Date: Wed, 26 Oct 2022 06:29:17 +0000 Subject: [PATCH 222/656] Unit test for SMS class 2 handling. Test case added for Class2 Bug: b/238250839 Test: atest ImsSmsDispatcherTest Test: atest SmsDispatchersControllerTest Test: atest GsmInboundSmsHandlerTest Test: atest UsimDataDownloadHandlerTest Test: mm build Change-Id: I5d70c3fe2eccb530b384516567e00d9f4aafc42a --- .../telephony/ImsSmsDispatcherTest.java | 1 + .../SmsDispatchersControllerTest.java | 7 + .../gsm/GsmInboundSmsHandlerTest.java | 9 + .../gsm/UsimDataDownloadHandlerTest.java | 403 ++++++++++++++++++ 4 files changed, 420 insertions(+) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadHandlerTest.java diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java index 3bbba0b9d2..b9c83d312b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java @@ -87,6 +87,7 @@ public class ImsSmsDispatcherTest extends TelephonyTest { when(mSmsDispatchersController.isIms()).thenReturn(true); mTrackerData = new HashMap<>(1); when(mSmsTracker.getData()).thenReturn(mTrackerData); + verify(mSmsDispatchersController).setImsManager(mImsManager); } @After diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java index 64c21542b7..fecfc88d0a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java @@ -43,6 +43,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Singleton; +import com.android.ims.ImsManager; import com.android.internal.telephony.uicc.IccUtils; import org.junit.After; @@ -208,4 +209,10 @@ public class SmsDispatchersControllerTest extends TelephonyTest { processAllMessages(); assertTrue(mSmsDispatchersController.isIms()); } + + @Test + public void testSetImsManager() { + ImsManager imsManager = mock(ImsManager.class); + assertTrue(mSmsDispatchersController.setImsManager(imsManager)); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java index 967941c7f1..1df90f8139 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java @@ -57,6 +57,7 @@ import android.testing.TestableLooper; import androidx.test.filters.MediumTest; +import com.android.ims.ImsManager; import com.android.internal.telephony.FakeSmsContentProvider; import com.android.internal.telephony.InboundSmsHandler; import com.android.internal.telephony.InboundSmsTracker; @@ -1232,4 +1233,12 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { assertEquals("IdleState", getCurrentState().getName()); } + + @Test + public void testSetImsManager() { + ImsManager imsManager = Mockito.mock(ImsManager.class); + transitionFromStartupToIdle(); + assertTrue(mGsmInboundSmsHandler.setImsManager(imsManager)); + } } + diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadHandlerTest.java new file mode 100644 index 0000000000..c6041c8dd6 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadHandlerTest.java @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2022 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.gsm; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.content.res.Resources; +import android.os.AsyncResult; +import android.os.Message; +import android.telephony.ims.stub.ImsSmsImplBase; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.ims.ImsManager; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.GsmCdmaPhone; +import com.android.internal.telephony.InboundSmsHandler; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.uicc.IccIoResult; +import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.util.HexDump; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class UsimDataDownloadHandlerTest extends TelephonyTest { + // Mocked classes + private CommandsInterface mMockCi; + protected GsmCdmaPhone mMockPhone; + private ImsManager mMockImsManager; + private Resources mMockResources; + + private UsimDataDownloadHandler mUsimDataDownloadHandler; + private Phone mPhoneObj; + private Phone[] mPhoneslist; + private int mPhoneId; + private int mSlotId = 0; + private int mToken = 0; + private int mSmsSource = 1; + private byte[] mTpdu; + private byte[] mSmsAckPdu; + //Envelope is created as per TS.131.111 for SMS-PP data downwnload operation + private String mEnvelope = "D11502028281060591896745F306068199201269231300"; + //SMS TPDU for Class2 according to TS.123.040 + private String mPdu = "07914151551512f221110A81785634121000000666B2996C2603"; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + mMockCi = Mockito.mock(CommandsInterface.class); + mMockPhone = Mockito.mock(GsmCdmaPhone.class); + mMockImsManager = Mockito.mock(ImsManager.class); + mMockResources = Mockito.mock(Resources.class); + + mPhoneslist = new Phone[] {mMockPhone}; + mTpdu = HexDump.hexStringToByteArray(mPdu); + + //Use reflection to mock + replaceInstance(PhoneFactory.class, "sPhones", null, mPhoneslist); + replaceInstance(PhoneFactory.class, "sPhone", null, mMockPhone); + + mPhoneObj = PhoneFactory.getPhone(mSlotId); + assertNotNull(mPhoneObj); + mPhoneId = mPhoneObj.getPhoneId(); + doReturn(mSmsStats).when(mPhoneObj).getSmsStats(); + + //new UsimDataDownloadHandlerThread(TAG).start(); + //waitUntilReady(); + mUsimDataDownloadHandler = new UsimDataDownloadHandler(mMockCi, mPhoneId); + mUsimDataDownloadHandler.setImsManager(mMockImsManager); + } + + @After + public void tearDown() throws Exception { + mUsimDataDownloadHandler = null; + mPhoneslist = null; + super.tearDown(); + } + + @Test + public void sendEnvelopeForException() throws Exception { + setSmsPPSimConfig(false); + com.android.internal.telephony.gsm.SmsMessage sms = + com.android.internal.telephony.gsm.SmsMessage.createFromPdu(mTpdu); + + doAnswer( + invocation -> { + Message response = invocation.getArgument(1); + AsyncResult.forMessage(response, null, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + response.sendToTarget(); + return null; + }) + .when(mMockCi) + .sendEnvelopeWithStatus(anyString(), any(Message.class)); + + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + verify(mMockCi).acknowledgeLastIncomingGsmSms(false, + CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR, null); + + setSmsPPSimConfig(true); + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + //mTpdu[9] holds messageReference value + verify(mMockImsManager).acknowledgeSms(mToken, mTpdu[9], + ImsSmsImplBase.DELIVER_STATUS_ERROR_GENERIC); + } + + @Test + public void sendEnvelopeDataDownloadSuccess() throws Exception { + setSmsPPSimConfig(true); + com.android.internal.telephony.gsm.SmsMessage sms = + com.android.internal.telephony.gsm.SmsMessage.createFromPdu(mTpdu); + mSmsAckPdu = createSmsAckPdu(true, mEnvelope, sms); + + doAnswer( + invocation -> { + Message response = invocation.getArgument(1); + IccIoResult iir = new IccIoResult(0x90, 0x00, + IccUtils.hexStringToBytes(mEnvelope)); + AsyncResult.forMessage(response, iir, null); + response.sendToTarget(); + return null; + }) + .when(mMockCi) + .sendEnvelopeWithStatus(anyString(), any(Message.class)); + + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + //mTpdu[9] holds messageReference value + verify(mMockImsManager).acknowledgeSms(mToken, mTpdu[9], + ImsSmsImplBase.DELIVER_STATUS_OK, mSmsAckPdu); + + setSmsPPSimConfig(false); + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + verify(mMockCi).acknowledgeIncomingGsmSmsWithPdu(true, + IccUtils.bytesToHexString(mSmsAckPdu), null); + } + + @Test + public void sendEnvelopeDataDownloadFailed() throws Exception { + setSmsPPSimConfig(false); + com.android.internal.telephony.gsm.SmsMessage sms = + com.android.internal.telephony.gsm.SmsMessage.createFromPdu(mTpdu); + + doAnswer( + invocation -> { + Message response = invocation.getArgument(1); + IccIoResult iir = new IccIoResult(0x93, 0x00, + IccUtils.hexStringToBytes(mEnvelope)); + AsyncResult.forMessage(response, iir, null); + response.sendToTarget(); + return null; + }) + .when(mMockCi) + .sendEnvelopeWithStatus(anyString(), any(Message.class)); + + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + verify(mMockCi).acknowledgeLastIncomingGsmSms(false, + CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY, null); + + setSmsPPSimConfig(true); + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + //mTpdu[9] holds messageReference value + verify(mMockImsManager).acknowledgeSms(mToken, mTpdu[9], + ImsSmsImplBase.DELIVER_STATUS_ERROR_GENERIC); + } + + @Test + public void sendEnvelopeForSw1_62() throws Exception { + setSmsPPSimConfig(false); + com.android.internal.telephony.gsm.SmsMessage sms = + com.android.internal.telephony.gsm.SmsMessage.createFromPdu(mTpdu); + mSmsAckPdu = createSmsAckPdu(false, mEnvelope, sms); + + doAnswer( + invocation -> { + Message response = invocation.getArgument(1); + IccIoResult iir = new IccIoResult(0x62, 0x63, + IccUtils.hexStringToBytes(mEnvelope)); + AsyncResult.forMessage(response, iir, null); + response.sendToTarget(); + return null; + }) + .when(mMockCi) + .sendEnvelopeWithStatus(anyString(), any(Message.class)); + + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + verify(mMockCi).acknowledgeIncomingGsmSmsWithPdu(false, + IccUtils.bytesToHexString(mSmsAckPdu), null); + + setSmsPPSimConfig(true); + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + //mTpdu[9] holds messageReference value + verify(mMockImsManager).acknowledgeSms(mToken, mTpdu[9], + ImsSmsImplBase.DELIVER_STATUS_OK, mSmsAckPdu); + } + + @Test + public void smsCompleteForException() throws Exception { + setSmsPPSimConfig(false); + + doAnswer( + invocation -> { + Message response = invocation.getArgument(3); + AsyncResult.forMessage(response, null, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + response.sendToTarget(); + return null; + }) + .when(mMockCi) + .writeSmsToSim(anyInt(), anyString(), anyString(), any(Message.class)); + + int[] responseInfo = {mSmsSource, mTpdu[9], mToken}; + Message msg = mUsimDataDownloadHandler.obtainMessage(3 /* EVENT_WRITE_SMS_COMPLETE */, + responseInfo); + AsyncResult.forMessage(msg, null, new CommandException( + CommandException.Error.OPERATION_NOT_ALLOWED)); + mUsimDataDownloadHandler.handleMessage(msg); + verify(mMockCi).acknowledgeLastIncomingGsmSms(false, + CommandsInterface.GSM_SMS_FAIL_CAUSE_UNSPECIFIED_ERROR, null); + + setSmsPPSimConfig(true); + mUsimDataDownloadHandler.handleMessage(msg); + //mTpdu[9] holds messageReference value + verify(mMockImsManager).acknowledgeSms(mToken, mTpdu[9], + ImsSmsImplBase.DELIVER_STATUS_ERROR_GENERIC); + } + + @Test + public void smsComplete() throws Exception { + setSmsPPSimConfig(true); + + doAnswer( + invocation -> { + Message response = invocation.getArgument(3); + IccIoResult iir = new IccIoResult(0x90, 0x00, + IccUtils.hexStringToBytes(mEnvelope)); + AsyncResult.forMessage(response, iir, null); + response.sendToTarget(); + return null; + }) + .when(mMockCi) + .writeSmsToSim(anyInt(), anyString(), anyString(), any(Message.class)); + + int[] responseInfo = {mSmsSource, mTpdu[9], mToken}; + Message msg = mUsimDataDownloadHandler.obtainMessage(3 /* EVENT_WRITE_SMS_COMPLETE */, + responseInfo); + AsyncResult.forMessage(msg, null, null); + mUsimDataDownloadHandler.handleMessage(msg); + //mTpdu[9] holds messageReference value + verify(mMockImsManager).acknowledgeSms(mToken, mTpdu[9], ImsSmsImplBase.DELIVER_STATUS_OK); + + setSmsPPSimConfig(false); + mUsimDataDownloadHandler.handleMessage(msg); + verify(mMockCi).acknowledgeLastIncomingGsmSms(true, 0, null); + } + + @Test + public void failureEnvelopeResponse() throws Exception { + setSmsPPSimConfig(false); + com.android.internal.telephony.gsm.SmsMessage sms = + com.android.internal.telephony.gsm.SmsMessage.createFromPdu(mTpdu); + + doAnswer( + invocation -> { + Message response = invocation.getArgument(1); + IccIoResult iir = new IccIoResult(0x62, 0x63, + IccUtils.hexStringToBytes(null)); //ForNullResponseBytes + AsyncResult.forMessage(response, iir, null); + response.sendToTarget(); + return null; + }) + .when(mMockCi) + .sendEnvelopeWithStatus(anyString(), any(Message.class)); + + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + verify(mMockCi).acknowledgeLastIncomingGsmSms(false, + CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR, null); + + setSmsPPSimConfig(true); + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + //mTpdu[9] holds messageReference value + verify(mMockImsManager).acknowledgeSms(mToken, mTpdu[9], + ImsSmsImplBase.DELIVER_STATUS_ERROR_GENERIC); + } + + @Test + public void successEnvelopeResponse() throws Exception { + setSmsPPSimConfig(false); + com.android.internal.telephony.gsm.SmsMessage sms = + com.android.internal.telephony.gsm.SmsMessage.createFromPdu(mTpdu); + + doAnswer( + invocation -> { + Message response = invocation.getArgument(1); + IccIoResult iir = new IccIoResult(0x90, 0x00, + IccUtils.hexStringToBytes(null)); //ForNullResponseBytes + AsyncResult.forMessage(response, iir, null); + response.sendToTarget(); + return null; + }) + .when(mMockCi) + .sendEnvelopeWithStatus(anyString(), any(Message.class)); + + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + verify(mMockCi).acknowledgeLastIncomingGsmSms(true, 0, null); + + setSmsPPSimConfig(true); + mUsimDataDownloadHandler.startDataDownload(sms, + InboundSmsHandler.SOURCE_INJECTED_FROM_IMS, mToken); + processAllMessages(); + //mTpdu[9] holds messageReference value + verify(mMockImsManager).acknowledgeSms(mToken, mTpdu[9], ImsSmsImplBase.DELIVER_STATUS_OK); + } + + //To set "config_smppsim_response_via_ims" for testing purpose + private void setSmsPPSimConfig(boolean config) { + mUsimDataDownloadHandler.setResourcesForTest(mMockResources); + doReturn(config).when(mMockResources).getBoolean( + com.android.internal.R.bool.config_smppsim_response_via_ims); + } + + private byte[] createSmsAckPdu(boolean success, String envelope, SmsMessage smsMessage) { + byte[] responseBytes = IccUtils.hexStringToBytes(envelope); + int dcs = 0x00; + int pid = smsMessage.getProtocolIdentifier(); + byte[] smsAckPdu; + int index = 0; + if (success) { + smsAckPdu = new byte[responseBytes.length + 5]; + smsAckPdu[index++] = 0x00; + smsAckPdu[index++] = 0x07; + } else { + smsAckPdu = new byte[responseBytes.length + 6]; + smsAckPdu[index++] = 0x00; + smsAckPdu[index++] = (byte) + CommandsInterface.GSM_SMS_FAIL_CAUSE_USIM_DATA_DOWNLOAD_ERROR; + smsAckPdu[index++] = 0x07; + } + + smsAckPdu[index++] = (byte) pid; + smsAckPdu[index++] = (byte) dcs; + + if (((dcs & 0x8C) == 0x00) || ((dcs & 0xF4) == 0xF0)) { + int septetCount = responseBytes.length * 8 / 7; + smsAckPdu[index++] = (byte) septetCount; + } else { + smsAckPdu[index++] = (byte) responseBytes.length; + } + + System.arraycopy(responseBytes, 0, smsAckPdu, index, responseBytes.length); + return smsAckPdu; + } +} -- GitLab From 23b3574cfdc554d82118eb12a3326e22d116084b Mon Sep 17 00:00:00 2001 From: Lalit Maganti Date: Thu, 1 Dec 2022 16:59:44 +0000 Subject: [PATCH 223/656] frameworks: migrate use of deprecated asyncTraceForTrackEnd function This function was deprecated and is going to be removed in a followup so migrate to the replacement function which no longer takes a trace name. Bug: 259535570 Change-Id: I2d48e226cf4b918e3196282df09a1c61d80b6596 --- src/java/com/android/internal/telephony/RIL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 200d35842a..b5f5da180a 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5674,7 +5674,7 @@ public class RIL extends BaseCommands implements CommandsInterface { + " ,error: " + error); return null; } - Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_NETWORK, "RIL", "" /* unused */, rr.mSerial); + Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_NETWORK, "RIL", rr.mSerial); // Time logging for RIL command and storing it in TelephonyHistogram. addToRilHistogram(rr); -- GitLab From 475ca590008ced0be1b3f0402c0404745787f412 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 1 Dec 2022 10:17:15 -0800 Subject: [PATCH 224/656] Dump radio halversion Bug: 258597835 Test: verified bugreport Change-Id: I35dd99ac85cbf05db2b125a0e75e337fb8dadd2b --- .../com/android/internal/telephony/PhoneFactory.java | 11 +++++++++++ src/java/com/android/internal/telephony/RIL.java | 7 +++++++ .../com/android/internal/telephony/RadioConfig.java | 5 +++++ .../android/internal/telephony/RadioConfigProxy.java | 7 +++++++ .../telephony/RadioInterfaceCapabilityController.java | 9 +++++++++ .../android/internal/telephony/RadioServiceProxy.java | 5 +++++ .../internal/telephony/data/PhoneSwitcher.java | 2 +- .../internal/telephony/data/PhoneSwitcherTest.java | 6 +++--- 8 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index 75c4740293..21a3afccff 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -609,6 +609,17 @@ public class PhoneFactory { pw.decreaseIndent(); pw.println("++++++++++++++++++++++++++++++++"); + pw.println("sRadioHalCapabilities:"); + pw.increaseIndent(); + try { + sRadioHalCapabilities.dump(fd, pw, args); + } catch (Exception e) { + e.printStackTrace(); + } + pw.flush(); + pw.decreaseIndent(); + pw.println("++++++++++++++++++++++++++++++++"); + pw.println("LocalLogs:"); pw.increaseIndent(); synchronized (sLocalLogs) { diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 200d35842a..0bdcbaca9e 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -6340,6 +6340,13 @@ public class RIL extends BaseCommands implements CommandsInterface { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("RIL: " + this); + pw.println(" " + mServiceProxies.get(HAL_SERVICE_DATA)); + pw.println(" " + mServiceProxies.get(HAL_SERVICE_MESSAGING)); + pw.println(" " + mServiceProxies.get(HAL_SERVICE_MODEM)); + pw.println(" " + mServiceProxies.get(HAL_SERVICE_NETWORK)); + pw.println(" " + mServiceProxies.get(HAL_SERVICE_SIM)); + pw.println(" " + mServiceProxies.get(HAL_SERVICE_VOICE)); + pw.println(" " + mServiceProxies.get(HAL_SERVICE_IMS)); pw.println(" mWakeLock=" + mWakeLock); pw.println(" mWakeLockTimeout=" + mWakeLockTimeout); synchronized (mRequestList) { diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java index e455ecbe74..f9dd3b5fc0 100644 --- a/src/java/com/android/internal/telephony/RadioConfig.java +++ b/src/java/com/android/internal/telephony/RadioConfig.java @@ -642,4 +642,9 @@ public class RadioConfig extends Handler { private static void loge(String log) { Rlog.e(TAG, log); } + + @Override + public String toString() { + return "RadioConfig[" + "mRadioConfigProxy=" + mRadioConfigProxy + ']'; + } } diff --git a/src/java/com/android/internal/telephony/RadioConfigProxy.java b/src/java/com/android/internal/telephony/RadioConfigProxy.java index a8601f1c60..edeb558b5d 100644 --- a/src/java/com/android/internal/telephony/RadioConfigProxy.java +++ b/src/java/com/android/internal/telephony/RadioConfigProxy.java @@ -336,4 +336,11 @@ public class RadioConfigProxy { mRadioConfig.obtainMessage(RadioConfig.EVENT_AIDL_SERVICE_DEAD)); } } + + @Override + public String toString() { + return "RadioConfigProxy[" + + "mRadioHalVersion=" + mRadioHalVersion + + ", mRadioConfigHalVersion=" + mRadioConfigHalVersion + ']'; + } } diff --git a/src/java/com/android/internal/telephony/RadioInterfaceCapabilityController.java b/src/java/com/android/internal/telephony/RadioInterfaceCapabilityController.java index 04c6b541de..bab4d12185 100644 --- a/src/java/com/android/internal/telephony/RadioInterfaceCapabilityController.java +++ b/src/java/com/android/internal/telephony/RadioInterfaceCapabilityController.java @@ -28,6 +28,8 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.telephony.Rlog; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.Collections; import java.util.Set; @@ -164,6 +166,13 @@ public class RadioInterfaceCapabilityController extends Handler { } } + /** + * Dump the fields of the instance + */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("mRadioConfig=" + mRadioConfig); + } + private static void log(final String s) { Rlog.d(LOG_TAG, s); } diff --git a/src/java/com/android/internal/telephony/RadioServiceProxy.java b/src/java/com/android/internal/telephony/RadioServiceProxy.java index 8650dd006b..4257327330 100644 --- a/src/java/com/android/internal/telephony/RadioServiceProxy.java +++ b/src/java/com/android/internal/telephony/RadioServiceProxy.java @@ -78,4 +78,9 @@ public abstract class RadioServiceProxy { if (isEmpty()) return; if (!isAidl()) mRadioProxy.responseAcknowledgement(); } + + @Override + public String toString() { + return getClass().getSimpleName() + "[mHalVersion=" + mHalVersion + ']'; + } } diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 4584592938..44e40ad6b4 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -1399,7 +1399,7 @@ public class PhoneSwitcher extends Handler { } if (newActivePhones.size() < mMaxDataAttachModemCount - && newActivePhones.contains(mPreferredDataPhoneId) + && !newActivePhones.contains(mPreferredDataPhoneId) && SubscriptionManager.isUsableSubIdValue(mPreferredDataPhoneId)) { newActivePhones.add(mPreferredDataPhoneId); } 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 bcaa056946..45a312bfe5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -192,7 +192,7 @@ public class PhoneSwitcherTest extends TelephonyTest { initialize(); // verify nothing has been done while there are no inputs - assertFalse("data allowed initially", mDataAllowed[0]); + assertTrue("data should be always allowed for emergency", mDataAllowed[0]); assertFalse("data allowed initially", mDataAllowed[1]); NetworkRequest internetNetworkRequest = addInternetNetworkRequest(null, 50); @@ -298,7 +298,7 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); - assertFalse("data allowed", mDataAllowed[0]); + assertTrue("data not allowed", mDataAllowed[0]); assertFalse("data allowed", mDataAllowed[1]); // 6 gain subscription-specific request @@ -342,7 +342,7 @@ public class PhoneSwitcherTest extends TelephonyTest { processAllMessages(); verify(mActivePhoneSwitchHandler, times(1)).sendMessageAtTime(any(), anyLong()); clearInvocations(mActivePhoneSwitchHandler); - assertFalse("data allowed", mDataAllowed[0]); + assertTrue("data not allowed", mDataAllowed[0]); assertFalse("data allowed", mDataAllowed[1]); // 10 don't switch phones when in emergency mode -- GitLab From 171c02b19fa84a86480b61ef6f5ccf34896b8b2e Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Tue, 22 Nov 2022 12:09:21 +0000 Subject: [PATCH 225/656] HAL changes to PrimaryImei feature Bug: 184001777 Test: Build successfully Change-Id: Ifae4ce5debdb02c0f2418f871ae933a2568c85e4 --- .../com/android/internal/telephony/ModemResponse.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/java/com/android/internal/telephony/ModemResponse.java b/src/java/com/android/internal/telephony/ModemResponse.java index 4589e795c8..47eb6856c5 100644 --- a/src/java/com/android/internal/telephony/ModemResponse.java +++ b/src/java/com/android/internal/telephony/ModemResponse.java @@ -21,6 +21,7 @@ import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.modem.IRadioModemResponse; +import android.hardware.radio.modem.ImeiInfo; import android.os.SystemClock; import android.telephony.ActivityStatsTechSpecificInfo; import android.telephony.AnomalyReporter; @@ -77,6 +78,14 @@ public class ModemResponse extends IRadioModemResponse.Stub { HAL_SERVICE_MODEM, mRil, responseInfo, imei, imeisv, esn, meid); } + /** + * + * @param responseInfo Response info struct containing response type, serial no. and error + * @param imeiInfo imeiInfo object containing ImeiType, device IMEI and IMEISV + */ + public void getImeiResponse(RadioResponseInfo responseInfo, ImeiInfo imeiInfo) { + // TODO as part of the framework coding + } /** * @param responseInfo Response info struct containing response type, serial no. and error * @param config Array of HardwareConfig of the radio -- GitLab From 00baa890c37a76376cabe233d99f64d2dacd09ac Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 25 Nov 2022 17:17:58 -0800 Subject: [PATCH 226/656] Added default voice/data/sms subscription support Bug: 239607619 Test: atest SubscriptionManagerServiceTest Change-Id: Ib4a902c73685367edde1a24811c367b0871db683 --- .../SubscriptionManagerService.java | 345 +++++++++++++++--- .../SubscriptionManagerServiceTest.java | 140 ++++++- 2 files changed, 430 insertions(+), 55 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 311006deca..985a135ef7 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -20,11 +20,13 @@ import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.app.AppOpsManager; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.os.Binder; import android.os.Build; @@ -34,9 +36,11 @@ import android.os.Looper; import android.os.ParcelUuid; import android.os.TelephonyServiceManager; import android.os.UserHandle; +import android.provider.Settings; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; -import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.SubscriptionManager.PhoneNumberSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.TelephonyFrameworkInitializer; @@ -53,6 +57,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; import com.android.internal.telephony.MultiSimSettingController; +import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; @@ -68,6 +73,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; @@ -124,8 +130,9 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull private final SubscriptionDatabaseManager mSubscriptionDatabaseManager; + /** The slot index subscription id map. Key is the slot index, and the value is sub id. */ @NonNull - private final WatchedSlotIndexToSubId mSlotIndexToSubId = new WatchedSlotIndexToSubId(); + private final WatchedMap mSlotIndexToSubId = new WatchedMap<>(); /** Subscription manager service callbacks. */ @NonNull @@ -133,42 +140,50 @@ public class SubscriptionManagerService extends ISub.Stub { new ArraySet<>(); /** - * Watched slot index to sub id map. + * Default sub id. Derived from {@link #mDefaultVoiceSubId} and {@link #mDefaultDataSubId}, + * depending on device capability. */ - private static class WatchedSlotIndexToSubId { - private final Map mSlotIndexToSubId = - new ConcurrentHashMap<>(); + @NonNull + private final WatchedInt mDefaultSubId; - public void clear() { - mSlotIndexToSubId.clear(); - SubscriptionManager.invalidateDefaultSubIdCaches(); - SubscriptionManager.invalidateSlotIndexCaches(); - } + /** Default voice subscription id. */ + @NonNull + private final WatchedInt mDefaultVoiceSubId; - public Set> entrySet() { - return mSlotIndexToSubId.entrySet(); - } + /** Default data subscription id. */ + @NonNull + private final WatchedInt mDefaultDataSubId; - // Force all updates to data structure through wrapper. - public int get(int slotIndex) { - return mSlotIndexToSubId.getOrDefault(slotIndex, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - } + /** Default sms subscription id. */ + @NonNull + private final WatchedInt mDefaultSmsSubId; - public void put(int slotIndex, int value) { - mSlotIndexToSubId.put(slotIndex, value); - SubscriptionManager.invalidateDefaultSubIdCaches(); - SubscriptionManager.invalidateSlotIndexCaches(); + /** + * Watched map that automatically invalidate cache in {@link SubscriptionManager}. + */ + private static class WatchedMap extends ConcurrentHashMap { + @Override + public void clear() { + super.clear(); + SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); } - public void remove(int slotIndex) { - mSlotIndexToSubId.remove(slotIndex); - SubscriptionManager.invalidateDefaultSubIdCaches(); - SubscriptionManager.invalidateSlotIndexCaches(); + @Override + public V put(K key, V value) { + V oldValue = super.put(key, value); + if (!Objects.equals(oldValue, value)) { + SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); + } + return oldValue; } - public int size() { - return mSlotIndexToSubId.size(); + @Override + public V remove(Object key) { + V oldValue = super.remove(key); + if (oldValue != null) { + SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); + } + return oldValue; } } @@ -198,9 +213,16 @@ public class SubscriptionManagerService extends ISub.Stub { * Set the value. * * @param newValue The new value. + * + * @return {@code true} if {@code newValue} is different from the existing value. */ - public void set(int newValue) { - mValue = newValue; + public boolean set(int newValue) { + if (mValue != newValue) { + mValue = newValue; + SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); + return true; + } + return false; } } @@ -276,6 +298,50 @@ public class SubscriptionManagerService extends ISub.Stub { subscriptionServiceRegisterer.register(this); } + mDefaultVoiceSubId = new WatchedInt(Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, + SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { + @Override + public boolean set(int newValue) { + if (super.set(newValue)) { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, newValue); + return true; + } + return false; + } + }; + + mDefaultDataSubId = new WatchedInt(Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, + SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { + @Override + public boolean set(int newValue) { + if (super.set(newValue)) { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, newValue); + return true; + } + return false; + } + }; + + mDefaultSmsSubId = new WatchedInt(Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, + SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { + @Override + public boolean set(int newValue) { + if (super.set(newValue)) { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, newValue); + return true; + } + return false; + } + }; + + mDefaultSubId = new WatchedInt(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + // Create a separate thread for subscription database manager. The database will be updated // from a different thread. HandlerThread handlerThread = new HandlerThread(LOG_TAG); @@ -334,6 +400,8 @@ public class SubscriptionManagerService extends ISub.Stub { () -> callback.onUiccApplicationsEnabled(subId))); } }); + + updateDefaultSubId(); } /** @@ -601,24 +669,11 @@ public class SubscriptionManagerService extends ISub.Stub { * by {@link SubscriptionInfo#getSimSlotIndex} then by * {@link SubscriptionInfo#getSubscriptionId}. * - * @param callingPackage The package making the call - * @param callingFeatureId The feature in the package + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * * @return Sorted list of the currently {@link SubscriptionInfo} records available on the * device. - *
    - *
  • - * If null is returned the current state is unknown but if a - * {@link OnSubscriptionsChangedListener} has been registered - * {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be invoked in the future. - *
  • - *
  • - * If the list is empty then there are no {@link SubscriptionInfo} records currently available. - *
  • - *
  • - * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} - * then by {@link SubscriptionInfo#getSubscriptionId}. - *
  • - *
*/ @Override public List getActiveSubscriptionInfoList(@NonNull String callingPackage, @@ -959,11 +1014,35 @@ public class SubscriptionManagerService extends ISub.Stub { .collect(Collectors.toList()); } + /** + * Get slot index associated with the subscription. + * + * @param subId The subscription id. + * + * @return Logical slot indexx (i.e. phone id) as a positive integer or + * {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX} if the supplied {@code subId} doesn't have + * an associated slot index. + */ @Override public int getSlotIndex(int subId) { - return 0; + if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + subId = getDefaultSubId(); + } + + for (Map.Entry entry : mSlotIndexToSubId.entrySet()) { + if (entry.getValue() == subId) return entry.getKey(); + } + + return SubscriptionManager.INVALID_SIM_SLOT_INDEX; } + /** + * Get the subscription id for specified slot index. + * + * @param slotIndex Logical SIM slot index. + * @return The subscription id. {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if SIM is + * absent. + */ @Override public int getSubId(int slotIndex) { if (slotIndex == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) { @@ -977,7 +1056,8 @@ public class SubscriptionManagerService extends ISub.Stub { return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } - return mSlotIndexToSubId.get(slotIndex); + return mSlotIndexToSubId.getOrDefault(slotIndex, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); } @Override @@ -985,9 +1065,46 @@ public class SubscriptionManagerService extends ISub.Stub { return new int[]{getSubId(slotIndex)}; } + /** + * Update default sub id. + */ + private void updateDefaultSubId() { + int subId; + boolean isVoiceCapable = mTelephonyManager.isVoiceCapable(); + + if (isVoiceCapable) { + subId = getDefaultVoiceSubId(); + } else { + subId = getDefaultDataSubId(); + } + + // If the subId is not active, use the fist active subscription's subId. + if (!mSlotIndexToSubId.containsValue(subId)) { + int[] activeSubIds = getActiveSubIdList(true); + if (activeSubIds.length > 0) { + subId = activeSubIds[0]; + log("updateDefaultSubId: First available active sub = " + subId); + } else { + subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + } + + if (mDefaultSubId.get() != subId) { + int phoneId = getPhoneId(subId); + logl("updateDefaultSubId: Default sub id updated from " + mDefaultSubId.get() + " to " + + subId + ", phoneId=" + phoneId); + mDefaultSubId.set(subId); + + Intent intent = new Intent(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId, subId); + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + } + } + @Override public int getDefaultSubId() { - return 0; + return mDefaultSubId.get(); } @Override @@ -996,6 +1113,7 @@ public class SubscriptionManagerService extends ISub.Stub { } @Override + public int getPhoneId(int subId) { return 0; } @@ -1007,34 +1125,153 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int getDefaultDataSubId() { - return 0; + return mDefaultDataSubId.get(); } + /** + * Set the default data subscription id. + * + * @param subId The default data subscription id. + */ @Override + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultDataSubId(int subId) { + enforcePermissions("setDefaultDataSubId", Manifest.permission.MODIFY_PHONE_STATE); + + if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + throw new RuntimeException("setDefaultDataSubId called with DEFAULT_SUBSCRIPTION_ID"); + } + + final long token = Binder.clearCallingIdentity(); + try { + int oldDefaultDataSubId = mDefaultDataSubId.get(); + if (mDefaultDataSubId.set(subId)) { + SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); + logl("Default data subId changed from " + oldDefaultDataSubId + " to " + subId); + + MultiSimSettingController.getInstance().notifyDefaultDataSubChanged(); + + Intent intent = new Intent( + TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + SubscriptionManager.putSubscriptionIdExtra(intent, subId); + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + + updateDefaultSubId(); + } + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public int getDefaultVoiceSubId() { - return 0; + return mDefaultVoiceSubId.get(); } + /** + * Set the default voice subscription id. + * + * @param subId The default SMS subscription id. + */ @Override + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultVoiceSubId(int subId) { + enforcePermissions("setDefaultVoiceSubId", Manifest.permission.MODIFY_PHONE_STATE); + + if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + throw new RuntimeException("setDefaultVoiceSubId called with DEFAULT_SUB_ID"); + } + + final long token = Binder.clearCallingIdentity(); + try { + int oldDefaultVoiceSubId = mDefaultVoiceSubId.get(); + if (mDefaultVoiceSubId.set(subId)) { + SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); + logl("Default voice subId changed from " + oldDefaultVoiceSubId + " to " + subId); + + Intent intent = new Intent( + TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + SubscriptionManager.putSubscriptionIdExtra(intent, subId); + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + + PhoneAccountHandle newHandle = subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID + ? null : mTelephonyManager.getPhoneAccountHandleForSubscriptionId(subId); + + TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); + if (telecomManager != null) { + telecomManager.setUserSelectedOutgoingPhoneAccount(newHandle); + } + + updateDefaultSubId(); + } + + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public int getDefaultSmsSubId() { - return 0; + return mDefaultSmsSubId.get(); } + /** + * Set the default SMS subscription id. + * + * @param subId The default SMS subscription id. + */ @Override + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultSmsSubId(int subId) { + enforcePermissions("setDefaultSmsSubId", Manifest.permission.MODIFY_PHONE_STATE); + + if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + throw new RuntimeException("setDefaultSmsSubId called with DEFAULT_SUB_ID"); + } + + final long token = Binder.clearCallingIdentity(); + try { + int oldDefaultSmsSubId = mDefaultSmsSubId.get(); + if (mDefaultSmsSubId.set(subId)) { + SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); + logl("Default SMS subId changed from " + oldDefaultSmsSubId + " to " + subId); + + Intent intent = new Intent( + SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + SubscriptionManager.putSubscriptionIdExtra(intent, subId); + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + } + + } finally { + Binder.restoreCallingIdentity(token); + } } + /** + * Get the active subscription id list. + * + * @param visibleOnly {@code true} if only includes user visible subscription's sub id. + * + * @return List of the active subscription id. + */ @Override + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int[] getActiveSubIdList(boolean visibleOnly) { - return null; + enforcePermissions("getActiveSubIdList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + final long token = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(subInfo -> subInfo.isActive() && (!visibleOnly + || (subInfo.getGroupUuid().isEmpty() || !subInfo.isOpportunistic()))) + .mapToInt(SubscriptionInfoInternal::getSubscriptionId) + .toArray(); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override 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 2ff3f8bf73..775bd83baf 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -50,10 +50,14 @@ import android.annotation.NonNull; import android.app.AppOpsManager; import android.app.PropertyInvalidatedCache; import android.compat.testing.PlatformCompatChangeRule; +import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; +import android.os.Bundle; import android.os.Looper; import android.os.ParcelUuid; +import android.os.UserHandle; +import android.provider.Settings; import android.provider.Telephony; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -62,6 +66,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.ContextFixture; +import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; @@ -74,6 +79,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import java.lang.reflect.Field; @@ -105,6 +111,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { setupMocksForTelephonyPermissions(Build.VERSION_CODES.UPSIDE_DOWN_CAKE); PropertyInvalidatedCache.disableForCurrentProcess("cache_key.is_compat_change_enabled"); + doReturn(true).when(mTelephonyManager).isVoiceCapable(); mMockedSubscriptionManagerServiceCallback = Mockito.mock( SubscriptionManagerServiceCallback.class); ((MockContentResolver) mContext.getContentResolver()).addProvider( @@ -133,11 +140,20 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @After public void tearDown() throws Exception { + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); super.tearDown(); } /** - * Insert the subscrtipion info to the database. + * Insert the subscription info to the database. * * @param subInfo The subscription to be inserted. * @return The new sub id. @@ -442,4 +458,126 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfos).hasSize(1); assertThat(subInfos.get(0)).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); } + + @Test + public void testSetDefaultVoiceSubId() throws Exception { + // Grant MODIFY_PHONE_STATE permission for insertion. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + // Remove MODIFY_PHONE_STATE + mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, + () -> mSubscriptionManagerServiceUT.setDefaultVoiceSubId(1)); + + // Grant MODIFY_PHONE_STATE permission + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + mSubscriptionManagerServiceUT.setDefaultVoiceSubId(1); + + assertThat(Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION)).isEqualTo(1); + ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); + verify(mContext, times(2)).sendStickyBroadcastAsUser( + captorIntent.capture(), eq(UserHandle.ALL)); + + Intent intent = captorIntent.getAllValues().get(0); + assertThat(intent.getAction()).isEqualTo( + TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); + + Bundle b = intent.getExtras(); + + assertThat(b.containsKey(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isTrue(); + assertThat(b.getInt(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isEqualTo(1); + + intent = captorIntent.getAllValues().get(1); + assertThat(intent.getAction()).isEqualTo( + SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED); + + b = intent.getExtras(); + + assertThat(b.containsKey(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isTrue(); + assertThat(b.getInt(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isEqualTo(1); + } + + @Test + public void testSetDefaultDataSubId() throws Exception { + doReturn(false).when(mTelephonyManager).isVoiceCapable(); + // Grant MODIFY_PHONE_STATE permission for insertion. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + // Remove MODIFY_PHONE_STATE + mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, + () -> mSubscriptionManagerServiceUT.setDefaultDataSubId(1)); + + // Grant MODIFY_PHONE_STATE permission + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + mSubscriptionManagerServiceUT.setDefaultDataSubId(1); + + assertThat(Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION)).isEqualTo(1); + ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); + verify(mContext, times(2)).sendStickyBroadcastAsUser( + captorIntent.capture(), eq(UserHandle.ALL)); + + Intent intent = captorIntent.getAllValues().get(0); + assertThat(intent.getAction()).isEqualTo( + TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); + + Bundle b = intent.getExtras(); + + assertThat(b.containsKey(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isTrue(); + assertThat(b.getInt(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isEqualTo(1); + + intent = captorIntent.getAllValues().get(1); + assertThat(intent.getAction()).isEqualTo( + SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED); + + b = intent.getExtras(); + + assertThat(b.containsKey(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isTrue(); + assertThat(b.getInt(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isEqualTo(1); + } + + @Test + public void testSetDefaultSmsSubId() throws Exception { + // Grant MODIFY_PHONE_STATE permission for insertion. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + // Remove MODIFY_PHONE_STATE + mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, + () -> mSubscriptionManagerServiceUT.setDefaultSmsSubId(1)); + + // Grant MODIFY_PHONE_STATE permission + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + mSubscriptionManagerServiceUT.setDefaultSmsSubId(1); + + assertThat(Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION)).isEqualTo(1); + ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); + verify(mContext).sendStickyBroadcastAsUser(captorIntent.capture(), eq(UserHandle.ALL)); + + Intent intent = captorIntent.getValue(); + assertThat(intent.getAction()).isEqualTo( + SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED); + + Bundle b = intent.getExtras(); + + assertThat(b.containsKey(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isTrue(); + assertThat(b.getInt(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isEqualTo(1); + } } -- GitLab From 009cd96ecfe7004ff90d179ebbde32333d4f302b Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 26 Nov 2022 17:28:24 -0800 Subject: [PATCH 227/656] Added isActiveSubId support Also replaced several instance of using the legacy SubscriptionController. Test: atest SubscriptionManagerServiceTest Bug: 239607619 Change-Id: I369dd7a0f60952d9fef5265f4779a98df97f7da3 --- .../telephony/MultiSimSettingController.java | 2 +- .../telephony/NetworkScanRequestTracker.java | 2 +- .../com/android/internal/telephony/Phone.java | 12 ++- .../telephony/PhoneConfigurationManager.java | 16 +++- .../internal/telephony/PhoneFactory.java | 73 ++++++++++++------- .../telephony/PhoneSubInfoController.java | 20 ++++- .../telephony/ServiceStateTracker.java | 68 ++++++++++++++--- .../SubscriptionDatabaseManager.java | 22 ++++-- .../SubscriptionInfoInternal.java | 7 ++ .../SubscriptionManagerService.java | 62 +++++++++++++++- .../SubscriptionDatabaseManagerTest.java | 2 +- .../SubscriptionManagerServiceTest.java | 22 ++++++ 12 files changed, 253 insertions(+), 55 deletions(-) diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index 298e3b8614..f2b33ddd5e 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -905,7 +905,7 @@ public class MultiSimSettingController extends Handler { */ private void setRoamingDataEnabledForGroup(int subId, boolean enable) { List infoList; - if (PhoneFactory.getDefaultPhone().isSubscriptionManagerServiceEnabled()) { + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { infoList = SubscriptionManagerService.getInstance().getSubscriptionsInGroup( mSubController.getGroupUuid(subId), mContext.getOpPackageName(), mContext.getAttributionTag()); diff --git a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java index d576a09719..b15dc594b3 100644 --- a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java +++ b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java @@ -197,7 +197,7 @@ public final class NetworkScanRequestTracker { public static Set getAllowedMccMncsForLocationRestrictedScan(Context context) { final long token = Binder.clearCallingIdentity(); try { - if (PhoneFactory.getDefaultPhone().isSubscriptionManagerServiceEnabled()) { + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { return SubscriptionManagerService.getInstance() .getAvailableSubscriptionInfoList(context.getOpPackageName(), context.getAttributionTag()).stream() diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 9064ddf3cd..1c496b5cab 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -89,6 +89,7 @@ import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; import com.android.internal.telephony.metrics.SmsStats; import com.android.internal.telephony.metrics.VoiceCallSessionStats; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.test.SimulatedRadioControl; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; @@ -4386,7 +4387,16 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } private int getResolvedUsageSetting(int subId) { - SubscriptionInfo subInfo = SubscriptionController.getInstance().getSubscriptionInfo(subId); + SubscriptionInfo subInfo = null; + if (isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfoInternal = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + if (subInfoInternal != null) { + subInfo = subInfoInternal.toSubscriptionInfo(); + } + } else { + subInfo = SubscriptionController.getInstance().getSubscriptionInfo(subId); + } if (subInfo == null || subInfo.getUsageSetting() == SubscriptionManager.USAGE_SETTING_UNKNOWN) { diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java index ab0b250969..6f428724c1 100644 --- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java +++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java @@ -35,6 +35,7 @@ import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.telephony.Rlog; import java.util.HashMap; @@ -384,7 +385,11 @@ public class PhoneConfigurationManager { // eg if we are going from 2 phones to 1 phone, we need to deregister RIL for the // second phone. This loop does nothing if numOfActiveModems is increasing. for (int phoneId = numOfActiveModems; phoneId < oldNumOfActiveModems; phoneId++) { - SubscriptionController.getInstance().clearSubInfoRecord(phoneId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().markSubscriptionsInactive(phoneId); + } else { + SubscriptionController.getInstance().clearSubInfoRecord(phoneId); + } subInfoCleared = true; mPhones[phoneId].mCi.onSlotActiveStatusChange( SubscriptionManager.isValidPhoneId(phoneId)); @@ -418,8 +423,13 @@ public class PhoneConfigurationManager { + "setting VOICE & SMS subId to -1 (No Preference)"); //Set the default VOICE subId to -1 ("No Preference") - SubscriptionController.getInstance().setDefaultVoiceSubId( - SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().setDefaultVoiceSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } else { + SubscriptionController.getInstance().setDefaultVoiceSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } //TODO:: Set the default SMS sub to "No Preference". Tracking this bug (b/227386042) } else { diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index 75c4740293..dcb9edf819 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -106,6 +106,8 @@ public class PhoneFactory { private static MetricsCollector sMetricsCollector; private static RadioInterfaceCapabilityController sRadioHalCapabilities; + private static boolean sSubscriptionManagerServiceEnabled = false; + //***** Class Methods public static void makeDefaultPhones(Context context) { @@ -121,6 +123,10 @@ public class PhoneFactory { synchronized (sLockProxyPhones) { if (!sMadeDefaults) { sContext = context; + + sSubscriptionManagerServiceEnabled = context.getResources().getBoolean( + com.android.internal.R.bool.config_using_subscription_manager_service); + // create the telephony device controller. TelephonyDevController.create(); @@ -198,8 +204,8 @@ public class PhoneFactory { // call getInstance() sUiccController = UiccController.make(context); - if (sContext.getResources().getBoolean( - com.android.internal.R.bool.config_using_subscription_manager_service)) { + + if (isSubscriptionManagerServiceEnabled()) { Rlog.i(LOG_TAG, "Creating SubscriptionManagerService"); sSubscriptionManagerService = new SubscriptionManagerService(context, Looper.myLooper()); @@ -242,13 +248,15 @@ public class PhoneFactory { sMadeDefaults = true; - Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater "); - HandlerThread pfhandlerThread = new HandlerThread("PhoneFactoryHandlerThread"); - pfhandlerThread.start(); - sSubInfoRecordUpdater = TelephonyComponentFactory.getInstance().inject( - SubscriptionInfoUpdater.class.getName()). - makeSubscriptionInfoUpdater(pfhandlerThread. - getLooper(), context, SubscriptionController.getInstance()); + if (!isSubscriptionManagerServiceEnabled()) { + Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater "); + HandlerThread pfhandlerThread = new HandlerThread("PhoneFactoryHandlerThread"); + pfhandlerThread.start(); + sSubInfoRecordUpdater = TelephonyComponentFactory.getInstance().inject( + SubscriptionInfoUpdater.class.getName()) + .makeSubscriptionInfoUpdater(pfhandlerThread.getLooper(), context, + SubscriptionController.getInstance()); + } // Only bring up IMS if the device supports having an IMS stack. if (context.getPackageManager().hasSystemFeature( @@ -288,6 +296,14 @@ public class PhoneFactory { } } + /** + * @return {@code true} if the new {@link SubscriptionManagerService} is enabled, otherwise the + * old {@link SubscriptionController} is used. + */ + public static boolean isSubscriptionManagerServiceEnabled() { + return sSubscriptionManagerServiceEnabled; + } + /** * Upon single SIM to dual SIM switch or vice versa, we dynamically allocate or de-allocate * Phone and CommandInterface objects. @@ -444,6 +460,9 @@ public class PhoneFactory { /* Gets the default subscription */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static int getDefaultSubscription() { + if (isSubscriptionManagerServiceEnabled()) { + return SubscriptionManagerService.getInstance().getDefaultSubId(); + } return SubscriptionController.getInstance().getDefaultSubId(); } @@ -587,23 +606,27 @@ public class PhoneFactory { pw.decreaseIndent(); pw.println("++++++++++++++++++++++++++++++++"); - pw.println("SubscriptionController:"); - pw.increaseIndent(); - try { - SubscriptionController.getInstance().dump(fd, pw, args); - } catch (Exception e) { - e.printStackTrace(); - } - pw.flush(); - pw.decreaseIndent(); - pw.println("++++++++++++++++++++++++++++++++"); + if (isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().dump(fd, pw, args); + } else { + pw.println("SubscriptionController:"); + pw.increaseIndent(); + try { + SubscriptionController.getInstance().dump(fd, pw, args); + } catch (Exception e) { + e.printStackTrace(); + } + pw.flush(); + pw.decreaseIndent(); + pw.println("++++++++++++++++++++++++++++++++"); - pw.println("SubInfoRecordUpdater:"); - pw.increaseIndent(); - try { - sSubInfoRecordUpdater.dump(fd, pw, args); - } catch (Exception e) { - e.printStackTrace(); + pw.println("SubInfoRecordUpdater:"); + pw.increaseIndent(); + try { + sSubInfoRecordUpdater.dump(fd, pw, args); + } catch (Exception e) { + e.printStackTrace(); + } } pw.flush(); pw.decreaseIndent(); diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java index 02ddf57ca9..804461b589 100644 --- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java +++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java @@ -36,8 +36,11 @@ import android.telephony.ImsiEncryptionInfo; import android.telephony.PhoneNumberUtils; import android.telephony.SubscriptionManager; import android.telephony.TelephonyFrameworkInitializer; +import android.text.TextUtils; import android.util.EventLog; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IsimRecords; import com.android.internal.telephony.uicc.SIMRecords; import com.android.internal.telephony.uicc.UiccCardApplication; @@ -154,8 +157,13 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { long identity = Binder.clearCallingIdentity(); boolean isActive; try { - isActive = SubscriptionController.getInstance().isActiveSubId(subId, callingPackage, - callingFeatureId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId, + callingPackage, callingFeatureId); + } else { + isActive = SubscriptionController.getInstance().isActiveSubId(subId, callingPackage, + callingFeatureId); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -169,6 +177,14 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { } identity = Binder.clearCallingIdentity(); try { + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(subId); + if (subInfo != null && !TextUtils.isEmpty(subInfo.getImsi())) { + return subInfo.getImsi(); + } + return null; + } return SubscriptionController.getInstance().getImsiPrivileged(subId); } finally { Binder.restoreCallingIdentity(identity); diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 31716ff43b..1925275467 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -97,6 +97,8 @@ import com.android.internal.telephony.data.DataNetworkController.DataNetworkCont import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.IccRecords; @@ -345,6 +347,7 @@ public class ServiceStateTracker extends Handler { private SubscriptionManager mSubscriptionManager; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private SubscriptionController mSubscriptionController; + private SubscriptionManagerService mSubscriptionManagerService; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private final SstSubscriptionsChangedListener mOnSubscriptionsChangedListener = new SstSubscriptionsChangedListener(); @@ -649,7 +652,12 @@ public class ServiceStateTracker extends Handler { mCi.registerForCellInfoList(this, EVENT_UNSOL_CELL_INFO_LIST, null); mCi.registerForPhysicalChannelConfiguration(this, EVENT_PHYSICAL_CHANNEL_CONFIG, null); - mSubscriptionController = SubscriptionController.getInstance(); + if (mPhone.isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); + } else { + mSubscriptionController = SubscriptionController.getInstance(); + } + mSubscriptionManager = SubscriptionManager.from(phone.getContext()); mSubscriptionManager.addOnSubscriptionsChangedListener( new android.os.HandlerExecutor(this), mOnSubscriptionsChangedListener); @@ -2750,9 +2758,16 @@ public class ServiceStateTracker extends Handler { SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); - if (!mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), - data.shouldShowPlmn(), data.getPlmn(), data.shouldShowSpn(), data.getSpn())) { - mSpnUpdatePending = true; + if (mPhone.isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService.setCarrierName(mPhone.getSubId(), + getCarrierName(data.shouldShowPlmn(), data.getPlmn(), + data.shouldShowSpn(), data.getSpn())); + } else { + if (!mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), + data.shouldShowPlmn(), data.getPlmn(), data.shouldShowSpn(), + data.getSpn())) { + mSpnUpdatePending = true; + } } } @@ -2764,6 +2779,26 @@ public class ServiceStateTracker extends Handler { mCurPlmn = data.getPlmn(); } + @NonNull + private String getCarrierName(boolean showPlmn, String plmn, boolean showSpn, String spn) { + String carrierName = ""; + if (showPlmn) { + carrierName = plmn; + if (showSpn) { + // Need to show both plmn and spn if both are not same. + if (!Objects.equals(spn, plmn)) { + String separator = mPhone.getContext().getString( + com.android.internal.R.string.kg_text_message_separator).toString(); + carrierName = new StringBuilder().append(carrierName).append(separator) + .append(spn).toString(); + } + } + } else if (showSpn) { + carrierName = spn; + } + return carrierName; + } + private void updateSpnDisplayCdnr() { log("updateSpnDisplayCdnr+"); CarrierDisplayNameData data = mCdnr.getCarrierDisplayNameData(); @@ -4488,14 +4523,23 @@ public class ServiceStateTracker extends Handler { } Context context = mPhone.getContext(); - SubscriptionInfo info = mSubscriptionController - .getActiveSubscriptionInfo(mPhone.getSubId(), context.getOpPackageName(), - context.getAttributionTag()); + if (mPhone.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(mPhone.getSubId()); + if (subInfo == null || !subInfo.isVisible()) { + log("cannot setNotification on invisible subid mSubId=" + mSubId); + return; + } + } else { + SubscriptionInfo info = mSubscriptionController + .getActiveSubscriptionInfo(mPhone.getSubId(), context.getOpPackageName(), + context.getAttributionTag()); - //if subscription is part of a group and non-primary, suppress all notifications - if (info == null || (info.isOpportunistic() && info.getGroupUuid() != null)) { - log("cannot setNotification on invisible subid mSubId=" + mSubId); - return; + //if subscription is part of a group and non-primary, suppress all notifications + if (info == null || (info.isOpportunistic() && info.getGroupUuid() != null)) { + log("cannot setNotification on invisible subid mSubId=" + mSubId); + return; + } } // Needed because sprout RIL sends these when they shouldn't? @@ -4527,7 +4571,7 @@ public class ServiceStateTracker extends Handler { final boolean multipleSubscriptions = (((TelephonyManager) mPhone.getContext() .getSystemService(Context.TELEPHONY_SERVICE)).getPhoneCount() > 1); - final int simNumber = mSubscriptionController.getSlotIndex(mSubId) + 1; + int simNumber = SubscriptionManager.getSlotIndex(mSubId) + 1; switch (notifyType) { case PS_ENABLED: diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index b0f5b87010..d963ed12c7 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -404,7 +404,7 @@ public class SubscriptionDatabaseManager extends Handler { + uri.getLastPathSegment()); return Integer.parseInt(uri.getLastPathSegment()); } else { - loge("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " + logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " + "contentValues=" + contentValues); } return INVALID_ROW_INDEX; @@ -446,7 +446,7 @@ public class SubscriptionDatabaseManager extends Handler { .Builder(subInfo) .setId(subId).build()); } else { - loge("insertSubscriptionInfo: Failed to insert a new subscription. subInfo=" + logel("insertSubscriptionInfo: Failed to insert a new subscription. subInfo=" + subInfo); } } finally { @@ -468,8 +468,8 @@ public class SubscriptionDatabaseManager extends Handler { // Perform the update in the handler thread asynchronously. if (!mDatabaseLoaded) { - throw new IllegalStateException("Database has not been loaded. Can't update " - + "database at this point. contentValues=" + contentValues); + logel("Database has not been loaded. Can't update database at this point. " + + "contentValues=" + contentValues); } post(() -> { @@ -479,7 +479,7 @@ public class SubscriptionDatabaseManager extends Handler { logv("updateDatabaseAsync: Successfully updated subscription in the database. " + "subId=" + subId + ", contentValues= " + contentValues.getValues()); } else { - loge("updateDatabaseAsync: Unexpected update result. rowsUpdated=" + rowsUpdated + logel("updateDatabaseAsync: Unexpected update result. rowsUpdated=" + rowsUpdated + ", contentValues=" + contentValues); } }); @@ -532,7 +532,7 @@ public class SubscriptionDatabaseManager extends Handler { updateDatabaseAsync(subId, contentValues); } } else { - loge("Subscription doesn't exist. subId=" + subId); + logel("Subscription doesn't exist. subId=" + subId + ", columnName" + columnName); } } finally { mReadWriteLock.writeLock().unlock(); @@ -1416,6 +1416,16 @@ public class SubscriptionDatabaseManager extends Handler { if (VDBG) Rlog.v(LOG_TAG, s); } + /** + * Log error messages and also log into the local log. + * + * @param s debug messages + */ + private void logel(@NonNull String s) { + loge(s); + mLocalLog.log(s); + } + /** * Log debug messages and also log into the local log. * diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 8076242824..4f8b727cd9 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -980,6 +980,13 @@ public class SubscriptionInfoInternal { return mSimSlotIndex >= 0 || mType == SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM; } + /** + * @return {@code true} if the subscription is visible to the user. + */ + public boolean isVisible() { + return !isOpportunistic() || TextUtils.isEmpty(mGroupUuid); + } + /** @return converted {@link SubscriptionInfo}. */ @NonNull public SubscriptionInfo toSubscriptionInfo() { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 985a135ef7..8cabf7fd95 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -560,6 +560,29 @@ public class SubscriptionManagerService extends ISub.Stub { mSubscriptionDatabaseManager.setCountryIso(subId, iso); } + /** + * Set the name displayed to the user that identifies subscription provider name. This name + * is the SPN displayed in status bar and many other places. Can't be renamed by the user. + * + * @param subId Subscription id. + * @param carrierName The carrier name. + */ + public void setCarrierName(int subId, @NonNull String carrierName) { + mSubscriptionDatabaseManager.setCarrierName(subId, carrierName); + } + + /** + * Mark all subscriptions on this SIM slot index inactive. + * + * @param simSlotIndex The SIM slot index. + */ + public void markSubscriptionsInactive(int simSlotIndex) { + mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(subInfo -> subInfo.getSimSlotIndex() == simSlotIndex) + .forEach(subInfo -> mSubscriptionDatabaseManager.setSimSlotIndex( + subInfo.getSubscriptionId(), SubscriptionManager.INVALID_SIM_SLOT_INDEX)); + } + /** * Get all subscription info records from SIMs that are inserted now or were inserted before. * @@ -1265,8 +1288,7 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(subInfo -> subInfo.isActive() && (!visibleOnly - || (subInfo.getGroupUuid().isEmpty() || !subInfo.isOpportunistic()))) + .filter(subInfo -> subInfo.isActive() && (!visibleOnly || subInfo.isVisible())) .mapToInt(SubscriptionInfoInternal::getSubscriptionId) .toArray(); } finally { @@ -1306,10 +1328,35 @@ public class SubscriptionManagerService extends ISub.Stub { return 0; } + /** + * Check if a subscription is active. + * + * @param subId The subscription id. + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * + * @return {@code true} if the subscription is active. + */ @Override + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) public boolean isActiveSubId(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { - return true; + if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, + callingFeatureId, "isActiveSubId")) { + throw new SecurityException("Requires READ_PHONE_STATE permission."); + } + final long identity = Binder.clearCallingIdentity(); + try { + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + return subInfo != null && subInfo.isActive(); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override @@ -1514,5 +1561,14 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println(SubscriptionManagerService.class.getSimpleName() + ":"); + pw.println("All subscriptions:"); + pw.increaseIndent(); + mSubscriptionDatabaseManager.getAllSubscriptions().forEach(pw::println); + pw.decreaseIndent(); + pw.println("defaultSubId=" + getDefaultSubId()); + pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId()); + pw.println("defaultDataSubId" + getDefaultDataSubId()); + pw.println("defaultSmsSubId" + getDefaultSmsSubId()); + pw.decreaseIndent(); } } 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 6ca922de35..1ba69dc0e0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -198,7 +198,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setCountryIso(FAKE_COUNTRY_CODE2) .setCarrierId(FAKE_CARRIER_ID2) .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING) - .setType(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM) + .setType(SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM) .setGroupOwner(FAKE_OWNER2) .setEnabledMobileDataPolicies(FAKE_MOBILE_DATA_POLICY2) .setImsi(FAKE_IMSI2) 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 775bd83baf..988b0dab1b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -580,4 +580,26 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(b.containsKey(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isTrue(); assertThat(b.getInt(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX)).isEqualTo(1); } + + @Test + public void testIsActiveSubId() { + // Grant MODIFY_PHONE_STATE permission for insertion. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO2) + .setSimSlotIndex(SubscriptionManager.INVALID_SIM_SLOT_INDEX).build()); + // Remove MODIFY_PHONE_STATE + mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // Should fail without READ_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .isActiveSubId(1, CALLING_PACKAGE, CALLING_FEATURE)); + + // Grant READ_PRIVILEGED_PHONE_STATE permission for insertion. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.isActiveSubId( + 1, CALLING_PACKAGE, CALLING_FEATURE)).isTrue(); + assertThat(mSubscriptionManagerServiceUT.isActiveSubId( + 2, CALLING_PACKAGE, CALLING_FEATURE)).isFalse(); + } } -- GitLab From cfebd92972b699a8b601cedd125392e88cabfab3 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 27 Nov 2022 22:08:02 -0800 Subject: [PATCH 228/656] Migrated MultiSimSettingController Added subscription manager service support in MultiSimSettingController. Also added several APIs in SubscriptionManagerService. Test: atest SubscriptionManagerServiceTest MultiSimSettingControllerTest Bug: 239607619 Change-Id: I36e7782368f5ea1ae57fbbb805f98292714abe58 --- .../telephony/MultiSimSettingController.java | 370 ++++++++++++++---- .../telephony/SignalStrengthController.java | 14 +- .../telephony/SmsBroadcastUndelivered.java | 10 +- .../SubscriptionInfoInternal.java | 4 +- .../SubscriptionManagerService.java | 146 ++++++- .../MultiSimSettingControllerTest.java | 53 ++- .../SubscriptionManagerServiceTest.java | 35 ++ 7 files changed, 541 insertions(+), 91 deletions(-) diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index f2b33ddd5e..ebed17b934 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -54,6 +54,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.util.ArrayUtils; @@ -123,6 +124,8 @@ public class MultiSimSettingController extends Handler { protected final Context mContext; protected final SubscriptionController mSubController; + private final SubscriptionManagerService mSubscriptionManagerService; + // Keep a record of active primary (non-opportunistic) subscription list. @NonNull private List mPrimarySubList = new ArrayList<>(); @@ -234,6 +237,7 @@ public class MultiSimSettingController extends Handler { public MultiSimSettingController(Context context, SubscriptionController sc) { mContext = context; mSubController = sc; + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); // Initialize mCarrierConfigLoadedSubIds and register to listen to carrier config change. final int phoneCount = ((TelephonyManager) mContext.getSystemService( @@ -359,12 +363,26 @@ public class MultiSimSettingController extends Handler { // Make sure MOBILE_DATA of subscriptions in same group are synced. setUserDataEnabledForGroup(subId, enable); + SubscriptionInfo subInfo = null; + int defaultDataSubId; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId); + defaultDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); + } else { + subInfo = mSubController.getSubscriptionInfo(subId); + defaultDataSubId = mSubController.getDefaultDataSubId(); + } + // If user is enabling a non-default non-opportunistic subscription, make it default. - if (mSubController.getDefaultDataSubId() != subId && !mSubController.isOpportunistic(subId) - && enable && mSubController.isActiveSubId(subId) && setDefaultData) { - android.provider.Settings.Global.putInt(mContext.getContentResolver(), - SETTING_USER_PREF_DATA_SUB, subId); - mSubController.setDefaultDataSubId(subId); + if (defaultDataSubId != subId && subInfo != null && !subInfo.isOpportunistic() && enable + && subInfo.isActive() && setDefaultData) { + android.provider.Settings.Global.putInt(mContext.getContentResolver(), + SETTING_USER_PREF_DATA_SUB, subId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService.setDefaultDataSubId(subId); + } else { + mSubController.setDefaultDataSubId(subId); + } } } @@ -375,8 +393,13 @@ public class MultiSimSettingController extends Handler { if (DBG) log("onRoamingDataEnabled"); setRoamingDataEnabledForGroup(subId, enable); - // Also inform SubscriptionController as it keeps another copy of user setting. - mSubController.setDataRoaming(enable ? 1 : 0, subId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + // Also inform SubscriptionController as it keeps another copy of user setting. + mSubscriptionManagerService.setDataRoaming(enable ? 1 : 0, subId); + } else { + // Also inform SubscriptionController as it keeps another copy of user setting. + mSubController.setDataRoaming(enable ? 1 : 0, subId); + } } /** @@ -440,7 +463,11 @@ public class MultiSimSettingController extends Handler { // being specified in it. So here we do additional check to make sur we don't miss the // subId. if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - subId = mSubController.getSubId(phoneId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + subId = mSubscriptionManagerService.getSubId(phoneId); + } else { + subId = mSubController.getSubId(phoneId); + } if (SubscriptionManager.isValidSubscriptionId(subId)) { CarrierConfigManager cm = mContext.getSystemService(CarrierConfigManager.class); if (cm != null && cm.getConfigForSubId(subId) != null) { @@ -459,7 +486,12 @@ public class MultiSimSettingController extends Handler { */ @VisibleForTesting public boolean isCarrierConfigLoadedForAllSub() { - int[] activeSubIds = mSubController.getActiveSubIdList(false); + int[] activeSubIds; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + activeSubIds = mSubscriptionManagerService.getActiveSubIdList(false); + } else { + activeSubIds = mSubController.getActiveSubIdList(false); + } for (int activeSubId : activeSubIds) { boolean isLoaded = false; for (int configLoadedSub : mCarrierConfigLoadedSubIds) { @@ -526,20 +558,29 @@ public class MultiSimSettingController extends Handler { private void onSubscriptionGroupChanged(ParcelUuid groupUuid) { if (DBG) log("onSubscriptionGroupChanged"); - List infoList = mSubController.getSubscriptionsInGroup( - groupUuid, mContext.getOpPackageName(), mContext.getAttributionTag()); - if (infoList == null || infoList.isEmpty()) return; + List infoList; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + infoList = mSubscriptionManagerService.getSubscriptionsInGroup( + groupUuid, mContext.getOpPackageName(), mContext.getAttributionTag()); + if (infoList == null || infoList.isEmpty()) return; + + } else { + infoList = mSubController.getSubscriptionsInGroup( + groupUuid, mContext.getOpPackageName(), mContext.getAttributionTag()); + if (infoList == null || infoList.isEmpty()) return; + } // Get a reference subscription to copy settings from. // TODO: the reference sub should be passed in from external caller. int refSubId = infoList.get(0).getSubscriptionId(); for (SubscriptionInfo info : infoList) { int subId = info.getSubscriptionId(); - if (mSubController.isActiveSubId(subId) && !mSubController.isOpportunistic(subId)) { + if (info.isActive() && !info.isOpportunistic()) { refSubId = subId; break; } } + if (DBG) log("refSubId is " + refSubId); boolean enable = false; @@ -552,8 +593,14 @@ public class MultiSimSettingController extends Handler { mContext, Settings.Global.MOBILE_DATA, INVALID_SUBSCRIPTION_ID, enable); } boolean setDefaultData = true; - List activeSubList = mSubController.getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); + List activeSubList; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + activeSubList = mSubscriptionManagerService.getActiveSubscriptionInfoList( + mContext.getOpPackageName(), mContext.getAttributionTag()); + } else { + activeSubList = mSubController.getActiveSubscriptionInfoList( + mContext.getOpPackageName(), mContext.getAttributionTag()); + } for (SubscriptionInfo activeInfo : activeSubList) { if (!(groupUuid.equals(activeInfo.getGroupUuid()))) { // Do not set refSubId as defaultDataSubId if there are other active @@ -576,8 +623,12 @@ public class MultiSimSettingController extends Handler { onRoamingDataEnabled(refSubId, enable); } - // Sync settings in subscription database.. - mSubController.syncGroupedSetting(refSubId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService.syncGroupedSetting(refSubId); + } else { + // Sync settings in subscription database.. + mSubController.syncGroupedSetting(refSubId); + } } /** @@ -599,21 +650,38 @@ public class MultiSimSettingController extends Handler { if (!isReadyToReevaluate()) return; - List activeSubInfos = mSubController - .getActiveSubscriptionInfoList(mContext.getOpPackageName(), - mContext.getAttributionTag()); + List activeSubInfos; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + activeSubInfos = mSubscriptionManagerService.getActiveSubscriptionInfoList( + mContext.getOpPackageName(), mContext.getAttributionTag()); - if (ArrayUtils.isEmpty(activeSubInfos)) { - mPrimarySubList.clear(); - if (DBG) log("[updateDefaultValues] No active sub. Setting default to INVALID sub."); - mSubController.setDefaultDataSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mSubController.setDefaultVoiceSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mSubController.setDefaultSmsSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - return; + if (ArrayUtils.isEmpty(activeSubInfos)) { + mPrimarySubList.clear(); + if (DBG) log("updateDefaults: No active sub. Setting default to INVALID sub."); + mSubscriptionManagerService.setDefaultDataSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mSubscriptionManagerService.setDefaultVoiceSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mSubscriptionManagerService.setDefaultSmsSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + return; + } + } else { + activeSubInfos = mSubController.getActiveSubscriptionInfoList( + mContext.getOpPackageName(), mContext.getAttributionTag()); + + if (ArrayUtils.isEmpty(activeSubInfos)) { + mPrimarySubList.clear(); + if (DBG) log("updateDefaultValues: No active sub. Setting default to INVALID sub."); + mSubController.setDefaultDataSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mSubController.setDefaultVoiceSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mSubController.setDefaultSmsSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + return; + } } int change = updatePrimarySubListAndGetChangeType(activeSubInfos); - if (DBG) log("[updateDefaultValues] change: " + change); + if (DBG) log("updateDefaultValues: change: " + change); if (change == PRIMARY_SUB_NO_CHANGE) return; // If there's only one primary subscription active, we trigger PREFERRED_PICK_DIALOG @@ -625,34 +693,63 @@ public class MultiSimSettingController extends Handler { || ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE)) .getActiveModemCount() == 1)) { int subId = mPrimarySubList.get(0); - if (DBG) log("[updateDefaultValues] to only primary sub " + subId); - mSubController.setDefaultDataSubId(subId); - mSubController.setDefaultVoiceSubId(subId); - mSubController.setDefaultSmsSubId(subId); + if (DBG) log("updateDefaultValues: to only primary sub " + subId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService.setDefaultDataSubId(subId); + mSubscriptionManagerService.setDefaultVoiceSubId(subId); + mSubscriptionManagerService.setDefaultSmsSubId(subId); + } else { + mSubController.setDefaultDataSubId(subId); + mSubController.setDefaultVoiceSubId(subId); + mSubController.setDefaultSmsSubId(subId); + } sendDefaultSubConfirmedNotification(subId); return; } - if (DBG) log("[updateDefaultValues] records: " + mPrimarySubList); - - // Update default data subscription. - if (DBG) log("[updateDefaultValues] Update default data subscription"); - boolean dataSelected = updateDefaultValue(mPrimarySubList, - mSubController.getDefaultDataSubId(), - (newValue -> mSubController.setDefaultDataSubId(newValue))); + if (DBG) log("updateDefaultValues: records: " + mPrimarySubList); - // Update default voice subscription. - if (DBG) log("[updateDefaultValues] Update default voice subscription"); - boolean voiceSelected = updateDefaultValue(mPrimarySubList, - mSubController.getDefaultVoiceSubId(), - (newValue -> mSubController.setDefaultVoiceSubId(newValue))); + boolean dataSelected, voiceSelected, smsSelected; - // Update default sms subscription. - if (DBG) log("[updateDefaultValues] Update default sms subscription"); - boolean smsSelected = updateDefaultValue(mPrimarySubList, - mSubController.getDefaultSmsSubId(), - (newValue -> mSubController.setDefaultSmsSubId(newValue)), - mIsAskEverytimeSupportedForSms); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + // Update default data subscription. + if (DBG) log("updateDefaultValues: Update default data subscription"); + dataSelected = updateDefaultValue(mPrimarySubList, + mSubscriptionManagerService.getDefaultDataSubId(), + mSubscriptionManagerService::setDefaultDataSubId); + + // Update default voice subscription. + if (DBG) log("updateDefaultValues: Update default voice subscription"); + voiceSelected = updateDefaultValue(mPrimarySubList, + mSubscriptionManagerService.getDefaultVoiceSubId(), + mSubscriptionManagerService::setDefaultVoiceSubId); + + // Update default sms subscription. + if (DBG) log("updateDefaultValues: Update default sms subscription"); + smsSelected = updateDefaultValue(mPrimarySubList, + mSubscriptionManagerService.getDefaultSmsSubId(), + mSubscriptionManagerService::setDefaultSmsSubId, + mIsAskEverytimeSupportedForSms); + } else { + // Update default data subscription. + if (DBG) log("updateDefaultValues: Update default data subscription"); + dataSelected = updateDefaultValue(mPrimarySubList, + mSubController.getDefaultDataSubId(), + mSubController::setDefaultDataSubId); + + // Update default voice subscription. + if (DBG) log("updateDefaultValues: Update default voice subscription"); + voiceSelected = updateDefaultValue(mPrimarySubList, + mSubController.getDefaultVoiceSubId(), + mSubController::setDefaultVoiceSubId); + + // Update default sms subscription. + if (DBG) log("updateDefaultValues: Update default sms subscription"); + smsSelected = updateDefaultValue(mPrimarySubList, + mSubController.getDefaultSmsSubId(), + mSubController::setDefaultSmsSubId, + mIsAskEverytimeSupportedForSms); + } boolean autoFallbackEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_voice_data_sms_auto_fallback); @@ -703,7 +800,14 @@ public class MultiSimSettingController extends Handler { // any previous primary subscription becomes inactive, we consider it for (int subId : prevPrimarySubList) { if (mPrimarySubList.contains(subId)) continue; - if (!mSubController.isActiveSubId(subId)) { + SubscriptionInfo subInfo = null; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId); + } else { + subInfo = mSubController.getSubscriptionInfo(subId); + } + + if (subInfo == null || !subInfo.isActive()) { for (int currentSubId : mPrimarySubList) { if (areSubscriptionsInSameGroup(currentSubId, subId)) { return PRIMARY_SUB_REMOVED_IN_GROUP; @@ -711,10 +815,10 @@ public class MultiSimSettingController extends Handler { } return PRIMARY_SUB_REMOVED; } - if (!mSubController.isOpportunistic(subId)) { + if (!subInfo.isOpportunistic()) { // Should never happen. - loge("[updatePrimarySubListAndGetChangeType]: missing active primary subId " - + subId); + loge("[updatePrimarySubListAndGetChangeType]: missing active primary " + + "subId " + subId); } } return PRIMARY_SUB_MARKED_OPPT; @@ -813,9 +917,18 @@ public class MultiSimSettingController extends Handler { // If a dual CDMA SIM combination warning is needed. if (phone != null && phone.isCdmaSubscriptionAppPresent()) { cdmaPhoneCount++; - String simName = mSubController.getActiveSubscriptionInfo( - subId, mContext.getOpPackageName(), mContext.getAttributionTag()) - .getDisplayName().toString(); + String simName = null; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + if (subInfo != null) { + simName = subInfo.getDisplayName(); + } + } else { + simName = mSubController.getActiveSubscriptionInfo( + subId, mContext.getOpPackageName(), mContext.getAttributionTag()) + .getDisplayName().toString(); + } if (TextUtils.isEmpty(simName)) { // Fall back to carrier name. simName = phone.getCarrierName(); @@ -840,12 +953,25 @@ public class MultiSimSettingController extends Handler { protected void disableDataForNonDefaultNonOpportunisticSubscriptions() { if (!isReadyToReevaluate()) return; - int defaultDataSub = mSubController.getDefaultDataSubId(); + int defaultDataSub; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + defaultDataSub = mSubscriptionManagerService.getDefaultDataSubId(); + } else { + defaultDataSub = mSubController.getDefaultDataSubId(); + } for (Phone phone : PhoneFactory.getPhones()) { + boolean isOpportunistic; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(phone.getSubId()); + isOpportunistic = subInfo != null && subInfo.isOpportunistic(); + } else { + isOpportunistic = mSubController.isOpportunistic(phone.getSubId()); + } if (phone.getSubId() != defaultDataSub && SubscriptionManager.isValidSubscriptionId(phone.getSubId()) - && !mSubController.isOpportunistic(phone.getSubId()) + && !isOpportunistic && phone.isUserDataEnabled() && !areSubscriptionsInSameGroup(defaultDataSub, phone.getSubId())) { log("setting data to false on " + phone.getSubId()); @@ -861,9 +987,19 @@ public class MultiSimSettingController extends Handler { || !SubscriptionManager.isUsableSubscriptionId(subId2)) return false; if (subId1 == subId2) return true; - ParcelUuid groupUuid1 = mSubController.getGroupUuid(subId1); - ParcelUuid groupUuid2 = mSubController.getGroupUuid(subId2); - return groupUuid1 != null && groupUuid1.equals(groupUuid2); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo1 = + mSubscriptionManagerService.getSubscriptionInfoInternal(subId1); + SubscriptionInfoInternal subInfo2 = + mSubscriptionManagerService.getSubscriptionInfoInternal(subId2); + return subInfo1 != null && subInfo2 != null + && !TextUtils.isEmpty(subInfo1.getGroupUuid()) + && subInfo1.getGroupUuid().equals(subInfo2.getGroupUuid()); + } else { + ParcelUuid groupUuid1 = mSubController.getGroupUuid(subId1); + ParcelUuid groupUuid2 = mSubController.getGroupUuid(subId2); + return groupUuid1 != null && groupUuid1.equals(groupUuid2); + } } /** @@ -872,18 +1008,35 @@ public class MultiSimSettingController extends Handler { */ protected void setUserDataEnabledForGroup(int subId, boolean enable) { log("setUserDataEnabledForGroup subId " + subId + " enable " + enable); - List infoList = mSubController.getSubscriptionsInGroup( - mSubController.getGroupUuid(subId), mContext.getOpPackageName(), - mContext.getAttributionTag()); + List infoList = null; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + if (subInfo != null && !subInfo.getGroupUuid().isEmpty()) { + infoList = mSubscriptionManagerService.getSubscriptionsInGroup( + ParcelUuid.fromString(subInfo.getGroupUuid()), mContext.getOpPackageName(), + mContext.getAttributionTag()); + } + } else { + infoList = mSubController.getSubscriptionsInGroup( + mSubController.getGroupUuid(subId), mContext.getOpPackageName(), + mContext.getAttributionTag()); + } if (infoList == null) return; for (SubscriptionInfo info : infoList) { int currentSubId = info.getSubscriptionId(); // TODO: simplify when setUserDataEnabled becomes singleton - if (mSubController.isActiveSubId(currentSubId)) { + if (info.isActive()) { // For active subscription, call setUserDataEnabled through DataSettingsManager. - Phone phone = PhoneFactory.getPhone(mSubController.getPhoneId(currentSubId)); + Phone phone; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + phone = PhoneFactory.getPhone(mSubscriptionManagerService + .getPhoneId(currentSubId)); + } else { + phone = PhoneFactory.getPhone(mSubController.getPhoneId(currentSubId)); + } // If enable is true and it's not opportunistic subscription, we don't enable it, // as there can't be two if (phone != null) { @@ -906,8 +1059,11 @@ public class MultiSimSettingController extends Handler { private void setRoamingDataEnabledForGroup(int subId, boolean enable) { List infoList; if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + if (subInfo == null || subInfo.getGroupUuid().isEmpty()) return; infoList = SubscriptionManagerService.getInstance().getSubscriptionsInGroup( - mSubController.getGroupUuid(subId), mContext.getOpPackageName(), + ParcelUuid.fromString(subInfo.getGroupUuid()), mContext.getOpPackageName(), mContext.getAttributionTag()); } else { infoList = SubscriptionController.getInstance().getSubscriptionsInGroup( @@ -968,14 +1124,23 @@ public class MultiSimSettingController extends Handler { private void deactivateGroupedOpportunisticSubscriptionIfNeeded() { if (!SubscriptionInfoUpdater.isSubInfoInitialized()) return; - List opptSubList = mSubController.getOpportunisticSubscriptions( - mContext.getOpPackageName(), mContext.getAttributionTag()); + List opptSubList; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + opptSubList = mSubscriptionManagerService.getAllSubInfoList( + mContext.getOpPackageName(), mContext.getAttributionTag()).stream() + .filter(SubscriptionInfo::isOpportunistic) + .collect(Collectors.toList()); + + } else { + opptSubList = mSubController.getOpportunisticSubscriptions( + mContext.getOpPackageName(), mContext.getAttributionTag()); + } if (ArrayUtils.isEmpty(opptSubList)) return; for (SubscriptionInfo info : opptSubList) { - if (info.isGroupDisabled() && mSubController.isActiveSubId(info.getSubscriptionId())) { - log("[deactivateGroupedOpptSubIfNeeded] " + if (info.isGroupDisabled() && info.isActive()) { + log("deactivateGroupedOpportunisticSubscriptionIfNeeded: " + "Deactivating grouped opportunistic subscription " + info.getSubscriptionId()); deactivateSubscription(info); @@ -1005,6 +1170,59 @@ public class MultiSimSettingController extends Handler { // would be selected as preferred voice/data/sms SIM. private void updateUserPreferences(List primarySubList, boolean dataSelected, boolean voiceSelected, boolean smsSelected) { + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + + // In Single SIM case or if there are no activated subs available, no need to update. + // EXIT. + if ((primarySubList.isEmpty()) || (mSubscriptionManagerService + .getActiveSubInfoCountMax() == 1)) { + return; + } + + if (!isRadioAvailableOnAllSubs()) { + log("Radio is in Invalid state, Ignore Updating User Preference!!!"); + return; + } + final int defaultDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); + + if (DBG) { + log("updateUserPreferences: dds = " + defaultDataSubId + " voice = " + + mSubscriptionManagerService.getDefaultVoiceSubId() + + " sms = " + mSubscriptionManagerService.getDefaultSmsSubId()); + } + + int autoDefaultSubId = primarySubList.get(0); + + if ((primarySubList.size() == 1) && !smsSelected) { + mSubscriptionManagerService.setDefaultSmsSubId(autoDefaultSubId); + } + + if ((primarySubList.size() == 1) && !voiceSelected) { + mSubscriptionManagerService.setDefaultVoiceSubId(autoDefaultSubId); + } + + int userPrefDataSubId = getUserPrefDataSubIdFromDB(); + + log("User pref subId = " + userPrefDataSubId + " current dds " + defaultDataSubId + + " next active subId " + autoDefaultSubId); + + // If earlier user selected DDS is now available, set that as DDS subId. + if (primarySubList.contains(userPrefDataSubId) + && SubscriptionManager.isValidSubscriptionId(userPrefDataSubId) + && (defaultDataSubId != userPrefDataSubId)) { + mSubscriptionManagerService.setDefaultDataSubId(userPrefDataSubId); + } else if (!dataSelected) { + mSubscriptionManagerService.setDefaultDataSubId(autoDefaultSubId); + } + + if (DBG) { + log("updateUserPreferences: after dds = " + + mSubscriptionManagerService.getDefaultDataSubId() + " voice = " + + mSubscriptionManagerService.getDefaultVoiceSubId() + " sms = " + + mSubscriptionManagerService.getDefaultSmsSubId()); + } + return; + } // In Single SIM case or if there are no activated subs available, no need to update. EXIT. if ((primarySubList.isEmpty()) || (mSubController.getActiveSubInfoCountMax() == 1)) return; @@ -1043,9 +1261,11 @@ public class MultiSimSettingController extends Handler { } - if (DBG) log("updateUserPreferences: after dds = " + mSubController.getDefaultDataSubId() + - " voice = " + mSubController.getDefaultVoiceSubId() + " sms = " + - mSubController.getDefaultSmsSubId()); + if (DBG) { + log("updateUserPreferences: after dds = " + mSubController.getDefaultDataSubId() + + " voice = " + mSubController.getDefaultVoiceSubId() + " sms = " + + mSubController.getDefaultSmsSubId()); + } } private int getUserPrefDataSubIdFromDB() { diff --git a/src/java/com/android/internal/telephony/SignalStrengthController.java b/src/java/com/android/internal/telephony/SignalStrengthController.java index 0c21ebf158..06750315d3 100644 --- a/src/java/com/android/internal/telephony/SignalStrengthController.java +++ b/src/java/com/android/internal/telephony/SignalStrengthController.java @@ -48,6 +48,7 @@ import android.util.LocalLog; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -359,9 +360,16 @@ public class SignalStrengthController extends Handler { || (curTime - mSignalStrengthUpdatedTime > SIGNAL_STRENGTH_REFRESH_THRESHOLD_IN_MS); if (!isStale) return false; - List subInfoList = SubscriptionController.getInstance() - .getActiveSubscriptionInfoList(mPhone.getContext().getOpPackageName(), - mPhone.getContext().getAttributionTag()); + List subInfoList; + if (mPhone.isSubscriptionManagerServiceEnabled()) { + subInfoList = SubscriptionManagerService.getInstance().getActiveSubscriptionInfoList( + mPhone.getContext().getOpPackageName(), + mPhone.getContext().getAttributionTag()); + } else { + subInfoList = SubscriptionController.getInstance() + .getActiveSubscriptionInfoList(mPhone.getContext().getOpPackageName(), + mPhone.getContext().getAttributionTag()); + } if (!ArrayUtils.isEmpty(subInfoList)) { for (SubscriptionInfo info : subInfoList) { diff --git a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java index f5d9e9e715..2f3995853c 100644 --- a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java +++ b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java @@ -34,6 +34,7 @@ import android.telephony.SubscriptionManager; import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; import com.android.internal.telephony.gsm.GsmInboundSmsHandler; import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.telephony.Rlog; import java.util.HashMap; @@ -261,8 +262,13 @@ public class SmsBroadcastUndelivered { private static void broadcastSms(InboundSmsTracker tracker) { InboundSmsHandler handler; int subId = tracker.getSubId(); - // TODO consider other subs in this subId's group as well - int phoneId = SubscriptionController.getInstance().getPhoneId(subId); + int phoneId; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + phoneId = SubscriptionManagerService.getInstance().getPhoneId(subId); + } else { + // TODO consider other subs in this subId's group as well + phoneId = SubscriptionController.getInstance().getPhoneId(subId); + } if (!SubscriptionManager.isValidPhoneId(phoneId)) { Rlog.e(TAG, "broadcastSms: ignoring message; no phone found for subId " + subId); return; diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 4f8b727cd9..f063958acf 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -481,7 +481,7 @@ public class SubscriptionInfoInternal { * @see #getCarrierName() */ @NonNull - public CharSequence getDisplayName() { + public String getDisplayName() { return mDisplayName; } @@ -492,7 +492,7 @@ public class SubscriptionInfoInternal { * @see #getDisplayName() */ @NonNull - public CharSequence getCarrierName() { + public String getCarrierName() { return mCarrierName; } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 8cabf7fd95..60eac2bd31 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -412,6 +412,71 @@ public class SubscriptionManagerService extends ISub.Stub { return sInstance; } + /** + * Sync the settings from specified subscription to all groupped subscriptions. + * + * @param subId The subscription id of the referenced subscription. + */ + public void syncGroupedSetting(int subId) { + mHandler.post(() -> { + SubscriptionInfoInternal reference = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + if (reference == null) { + loge("syncSettings: Can't find subscription info for sub " + subId); + return; + } + + if (reference.getGroupUuid().isEmpty()) { + // The reference subscription is not in a group. No need to sync. + return; + } + + for (SubscriptionInfoInternal subInfo : mSubscriptionDatabaseManager + .getAllSubscriptions()) { + if (subInfo.getSubscriptionId() != subId + && subInfo.getGroupUuid().equals(reference.getGroupUuid())) { + // Copy all settings from reference sub to the grouped subscriptions. + SubscriptionInfoInternal newSubInfo = new SubscriptionInfoInternal + .Builder(subInfo) + .setEnhanced4GModeEnabled(reference.getEnhanced4GModeEnabled()) + .setVideoTelephonyEnabled(reference.getVideoTelephonyEnabled()) + .setWifiCallingEnabled(reference.getWifiCallingEnabled()) + .setWifiCallingModeForRoaming(reference.getWifiCallingModeForRoaming()) + .setWifiCallingMode(reference.getWifiCallingMode()) + .setWifiCallingEnabledForRoaming( + reference.getWifiCallingEnabledForRoaming()) + .setDataRoaming(reference.getDataRoaming()) + .setDisplayName(reference.getDisplayName()) + .setEnabledMobileDataPolicies(reference.getEnabledMobileDataPolicies()) + .setUiccApplicationsEnabled(reference.getUiccApplicationsEnabled()) + .setRcsUceEnabled(reference.getRcsUceEnabled()) + .setCrossSimCallingEnabled(reference.getCrossSimCallingEnabled()) + .setNrAdvancedCallingEnabled(reference.getNrAdvancedCallingEnabled()) + .setUserId(reference.getUserId()) + .build(); + mSubscriptionDatabaseManager.updateSubscription(newSubInfo); + log("Synced settings from sub " + subId + " to sub " + + newSubInfo.getSubscriptionId()); + } + } + }); + } + + /** + * Validate the passed in subscription id. + * + * @param subId The subscription id to validate. + * + * @throws IllegalArgumentException if the subscription is not valid. + */ + private void validateSubId(int subId) { + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + throw new IllegalArgumentException("Invalid sub id passed as parameter"); + } else if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + throw new IllegalArgumentException("Default sub id passed as parameter"); + } + } + /** * Check whether the {@code callingPackage} has access to the phone number on the specified * {@code subId} or not. @@ -607,6 +672,11 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override @NonNull + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) public List getAllSubInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID @@ -699,9 +769,44 @@ public class SubscriptionManagerService extends ISub.Stub { * device. */ @Override + @NonNull + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) public List getActiveSubscriptionInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { - return null; + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + + // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier + // privilege on any active subscription. The carrier app will get full subscription infos + // on the subs it has carrier privilege. + if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, + Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, + "getAllSubInfoList")) { + throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + + "carrier privilege to call getAllSubInfoList"); + } + + final long identity = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isActive) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getAllSubInfoList")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); + + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -722,7 +827,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int getActiveSubInfoCountMax() { - return 0; + return mTelephonyManager.getSimCount(); } /** @@ -897,7 +1002,21 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int setDataRoaming(int roaming, int subId) { - return 0; + enforcePermissions("setDataRoaming", Manifest.permission.MODIFY_PHONE_STATE); + + // Now that all security checks passes, perform the operation as ourselves. + final long identity = Binder.clearCallingIdentity(); + try { + validateSubId(subId); + if (roaming < 0) { + throw new IllegalArgumentException("Invalid roaming value" + roaming); + } + + mSubscriptionDatabaseManager.setDataRoaming(subId, roaming); + return 1; + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1136,9 +1255,10 @@ public class SubscriptionManagerService extends ISub.Stub { } @Override - public int getPhoneId(int subId) { - return 0; + // slot index and phone id are equivalent in the current implementation. + // It is intended NOT to return DEFAULT_PHONE_INDEX any more from this method. + return getSlotIndex(subId); } /** @@ -1502,7 +1622,7 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Get the subscription info by subscription id. + * Get the {@link SubscriptionInfoInternal} by subscription id. * * @param subId The subscription id. * @@ -1513,6 +1633,20 @@ public class SubscriptionManagerService extends ISub.Stub { return mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subId); } + /** + * Get the {@link SubscriptionInfo} by subscription id. + * + * @param subId The subscription id. + * + * @return The subscription info. {@code null} if not found. + */ + @Nullable + public SubscriptionInfo getSubscriptionInfo(int subId) { + SubscriptionInfoInternal subscriptionInfoInternal = getSubscriptionInfoInternal(subId); + return subscriptionInfoInternal != null + ? subscriptionInfoInternal.toSubscriptionInfo() : null; + } + /** * Log debug messages. * diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index 8a2730938e..2907346c0b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -103,19 +103,19 @@ public class MultiSimSettingControllerTest extends TelephonyTest { .setCountryIso("us") .build(); - private final SubscriptionInfo mSubInfo2 = new SubscriptionInfo.Builder(mSubInfo1) + private SubscriptionInfo mSubInfo2 = new SubscriptionInfo.Builder(mSubInfo1) .setId(2) .setIccId("subInfo2 IccId") .setGroupUuid(mGroupUuid1.toString()) .build(); - private final SubscriptionInfo mSubInfo3 = new SubscriptionInfo.Builder(mSubInfo1) + private SubscriptionInfo mSubInfo3 = new SubscriptionInfo.Builder(mSubInfo1) .setId(3) .setIccId("subInfo3 IccId") .setGroupUuid(mGroupUuid1.toString()) .build(); - private final SubscriptionInfo mSubInfo4 = new SubscriptionInfo.Builder(mSubInfo1) + private SubscriptionInfo mSubInfo4 = new SubscriptionInfo.Builder(mSubInfo1) .setId(4) .setIccId("subInfo4 IccId") .setGroupUuid(mGroupUuid1.toString()) @@ -141,10 +141,16 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(1).when(mSubControllerMock).getDefaultVoiceSubId(); doReturn(1).when(mSubControllerMock).getDefaultSmsSubId(); doReturn(true).when(mSubControllerMock).isActiveSubId(1); + doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(0).build()) + .when(mSubControllerMock).getSubscriptionInfo(1); doReturn(true).when(mSubControllerMock).isActiveSubId(2); + doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(1).build()) + .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(0).when(mSubControllerMock).getPhoneId(1); doReturn(1).when(mSubControllerMock).getPhoneId(2); doReturn(true).when(mSubControllerMock).isOpportunistic(5); + doReturn(new SubscriptionInfo.Builder().setId(5).setSimSlotIndex(1).setOpportunistic(true) + .build()).when(mSubControllerMock).getSubscriptionInfo(5); doReturn(1).when(mPhoneMock1).getSubId(); doReturn(2).when(mPhoneMock2).getSubId(); mPhoneMock1.mCi = mSimulatedCommands; @@ -193,6 +199,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Mark sub 2 as inactive. doReturn(false).when(mSubControllerMock).isActiveSubId(2); + doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId(); List infoList = Arrays.asList(mSubInfo1); @@ -241,7 +249,11 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Mark all subs as inactive. doReturn(false).when(mSubControllerMock).isActiveSubId(1); + doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(1); doReturn(false).when(mSubControllerMock).isActiveSubId(2); + doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(1); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock1).getSubId(); @@ -282,6 +294,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Mark sub 2 as inactive. doReturn(false).when(mSubControllerMock).isActiveSubId(2); + doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId(); List infoList = Arrays.asList(mSubInfo1); @@ -298,7 +312,11 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Sub 1 should be default sub silently. // Sub 1 switches to sub 2 in the same slot. doReturn(false).when(mSubControllerMock).isActiveSubId(1); + doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(1); doReturn(true).when(mSubControllerMock).isActiveSubId(2); + doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(0).build()) + .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(0).when(mSubControllerMock).getPhoneId(2); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(1); doReturn(2).when(mPhoneMock1).getSubId(); @@ -323,6 +341,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { public void testActivatingSecondSub() throws Exception { // Mark sub 2 as inactive. doReturn(false).when(mSubControllerMock).isActiveSubId(2); + doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId(); List infoList = Arrays.asList(mSubInfo1); @@ -344,6 +364,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { clearInvocations(mSubControllerMock); clearInvocations(mContext); doReturn(true).when(mSubControllerMock).isActiveSubId(2); + doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(1).build()) + .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(1).when(mSubControllerMock).getPhoneId(2); doReturn(2).when(mPhoneMock2).getSubId(); infoList = Arrays.asList(mSubInfo1, mSubInfo2); @@ -365,7 +387,11 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Switch from sub 2 to sub 3 in phone[1]. This should again trigger default data selection // dialog. doReturn(false).when(mSubControllerMock).isActiveSubId(2); + doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(true).when(mSubControllerMock).isActiveSubId(3); + doReturn(new SubscriptionInfo.Builder().setId(3).setSimSlotIndex(1).build()) + .when(mSubControllerMock).getSubscriptionInfo(3); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); doReturn(1).when(mSubControllerMock).getPhoneId(3); doReturn(3).when(mPhoneMock2).getSubId(); @@ -417,6 +443,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Taking out SIM 1. clearInvocations(mSubControllerMock); doReturn(false).when(mSubControllerMock).isActiveSubId(1); + doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(1); List infoList = Arrays.asList(mSubInfo2); doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), nullable(String.class)); @@ -520,6 +548,9 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(3); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(4); + mSubInfo2 = new SubscriptionInfo.Builder(mSubInfo2).setSimSlotIndex(1).build(); + mSubInfo3 = new SubscriptionInfo.Builder(mSubInfo3).setSimSlotIndex(-1).build(); + mSubInfo4 = new SubscriptionInfo.Builder(mSubInfo4).setSimSlotIndex(-1).build(); doReturn(Arrays.asList(mSubInfo2, mSubInfo3, mSubInfo4)).when(mSubControllerMock) .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); @@ -579,6 +610,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { public void testCbrs() throws Exception { replaceInstance(SubscriptionInfo.class, "mIsOpportunistic", mSubInfo1, true); doReturn(true).when(mSubControllerMock).isOpportunistic(1); + doReturn(new SubscriptionInfo.Builder(mSubInfo1).setOpportunistic(true).build()) + .when(mSubControllerMock).getSubscriptionInfo(1); doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.DATA_ROAMING, 2, false); @@ -627,6 +660,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { replaceInstance(SubscriptionInfo.class, "mIsOpportunistic", mSubInfo1, true); replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); doReturn(true).when(mSubControllerMock).isOpportunistic(1); + doReturn(new SubscriptionInfo.Builder(mSubInfo1).setOpportunistic(true).build()) + .when(mSubControllerMock).getSubscriptionInfo(1); // Make opportunistic sub 1 and sub 2 data enabled. doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); @@ -685,6 +720,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Take out SIM 1. clearInvocations(mSubControllerMock); doReturn(false).when(mSubControllerMock).isActiveSubId(1); + doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(1); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(1); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock1).getSubId(); List infoList = Arrays.asList(mSubInfo2); @@ -766,7 +803,11 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Switch from sub 2 to sub 3 in phone[1]. clearInvocations(mSubControllerMock); doReturn(false).when(mSubControllerMock).isActiveSubId(2); + doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(true).when(mSubControllerMock).isActiveSubId(3); + doReturn(new SubscriptionInfo.Builder().setId(3).setSimSlotIndex(1).build()) + .when(mSubControllerMock).getSubscriptionInfo(3); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); doReturn(1).when(mSubControllerMock).getPhoneId(3); doReturn(3).when(mPhoneMock2).getSubId(); @@ -795,7 +836,11 @@ public class MultiSimSettingControllerTest extends TelephonyTest { public void testGroupChangeOnInactiveSub_shouldNotMarkAsDefaultDataSub() throws Exception { // Make sub1 and sub3 as active sub. doReturn(false).when(mSubControllerMock).isActiveSubId(2); + doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) + .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(true).when(mSubControllerMock).isActiveSubId(3); + doReturn(new SubscriptionInfo.Builder().setId(3).setSimSlotIndex(1).build()) + .when(mSubControllerMock).getSubscriptionInfo(3); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); doReturn(1).when(mSubControllerMock).getPhoneId(3); doReturn(3).when(mPhoneMock2).getSubId(); @@ -822,6 +867,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Mark sub3 as oppt and notify grouping doReturn(true).when(mSubControllerMock).isOpportunistic(3); + doReturn(new SubscriptionInfo.Builder().setId(3).setSimSlotIndex(0).setOpportunistic(true) + .build()).when(mSubControllerMock).getSubscriptionInfo(3); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // Shouldn't mark sub 2 as default data, as sub 2 is in active. 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 988b0dab1b..46e0af30b4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -602,4 +602,39 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.isActiveSubId( 2, CALLING_PACKAGE, CALLING_FEATURE)).isFalse(); } + + @Test + public void testGetActiveSubscriptionInfoList() { + doReturn(new int[]{1}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); + // Grant MODIFY_PHONE_STATE permission for insertion. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO2) + .setSimSlotIndex(SubscriptionManager.INVALID_SIM_SLOT_INDEX).build()); + // Remove MODIFY_PHONE_STATE + mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // Should fail without READ_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE)); + + // Grant READ_PHONE_STATE permission for insertion. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); + + List subInfos = mSubscriptionManagerServiceUT + .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE); + assertThat(subInfos).hasSize(1); + assertThat(subInfos.get(0).getIccId()).isEmpty(); + assertThat(subInfos.get(0).getCardString()).isEmpty(); + assertThat(subInfos.get(0).getNumber()).isEmpty(); + assertThat(subInfos.get(0).getGroupUuid()).isNull(); + + // Grant carrier privilege + setCarrierPrivilegesForSubId(true, 1); + + subInfos = mSubscriptionManagerServiceUT + .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE); + assertThat(subInfos).hasSize(1); + assertThat(subInfos.get(0)).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); + } } -- GitLab From 1d11d80cf14b3e7728b51ee31fefdcb8aa22943e Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 29 Nov 2022 20:32:08 -0800 Subject: [PATCH 229/656] Replaced more places to use SubscriptionManagerService Replaced more places to use SubscriptionManagerService Test: atest FrameworksTelephonyTests Bug: 239607619 Change-Id: Ifc72802f3f4b124b0aa18b166764a6cda8cc25e6 --- .../com/android/internal/telephony/Phone.java | 31 +++++--- .../internal/telephony/SMSDispatcher.java | 22 +++++- .../internal/telephony/SmsController.java | 27 +++++-- .../telephony/UiccPhoneBookController.java | 10 ++- .../internal/telephony/cat/CatService.java | 15 +++- .../data/CellularNetworkValidator.java | 34 +++++++-- .../telephony/data/DataSettingsManager.java | 70 +++++++++++++++---- .../telephony/data/PhoneSwitcher.java | 4 +- .../SubscriptionManagerService.java | 21 ++++++ 9 files changed, 189 insertions(+), 45 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index f77eb583d8..7c5db11358 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -2377,17 +2377,29 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * Loads the allowed network type from subscription database. */ public void loadAllowedNetworksFromSubscriptionDatabase() { - // Try to load ALLOWED_NETWORK_TYPES from SIMINFO. - if (SubscriptionController.getInstance() == null) { - return; + String result = null; + if (isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(getSubId()); + if (subInfo != null) { + result = subInfo.getAllowedNetworkTypesForReasons(); + } + } else { + // Try to load ALLOWED_NETWORK_TYPES from SIMINFO. + if (SubscriptionController.getInstance() == null) { + return; + } + + result = SubscriptionController.getInstance().getSubscriptionProperty( + getSubId(), + SubscriptionManager.ALLOWED_NETWORK_TYPES); } - String result = SubscriptionController.getInstance().getSubscriptionProperty( - getSubId(), - SubscriptionManager.ALLOWED_NETWORK_TYPES); // After fw load network type from DB, do unlock if subId is valid. - mIsAllowedNetworkTypesLoadedFromDb = SubscriptionManager.isValidSubscriptionId(getSubId()); - if (result == null) { + mIsAllowedNetworkTypesLoadedFromDb = SubscriptionManager.isValidSubscriptionId( + getSubId()); + + if (TextUtils.isEmpty(result)) { return; } @@ -4055,6 +4067,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ @UnsupportedAppUsage public int getSubId() { + if (isSubscriptionManagerServiceEnabled()) { + return mSubscriptionManagerService.getSubId(mPhoneId); + } if (SubscriptionController.getInstance() == null) { // TODO b/78359408 getInstance sometimes returns null in Treehugger tests, which causes // flakiness. Even though we haven't seen this crash in the wild we should keep this diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 42116761d4..3002ae109c 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -85,6 +85,8 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; import com.android.internal.telephony.cdma.sms.UserData; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -413,7 +415,15 @@ public abstract class SMSDispatcher extends Handler { */ mMessageRef = getTpmrValueFromSIM(); if (mMessageRef == -1) { - mMessageRef = SubscriptionController.getInstance().getMessageRef(msg.arg1); + if (mPhone.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(msg.arg1); + if (subInfo != null) { + mMessageRef = subInfo.getLastUsedTPMessageReference(); + } + } else { + mMessageRef = SubscriptionController.getInstance().getMessageRef(msg.arg1); + } } break; @@ -435,7 +445,12 @@ public abstract class SMSDispatcher extends Handler { updateSIMLastTPMRValue(mMessageRef); final long identity = Binder.clearCallingIdentity(); try { - SubscriptionController.getInstance().updateMessageRef(getSubId(), mMessageRef); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance() + .setLastUsedTPMessageReference(getSubId(), mMessageRef); + } else { + SubscriptionController.getInstance().updateMessageRef(getSubId(), mMessageRef); + } } catch (SecurityException e) { Rlog.e(TAG, "Security Exception caused on messageRef updation to DB " + e.getMessage()); } finally { @@ -2862,6 +2877,9 @@ public abstract class SMSDispatcher extends Handler { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected int getSubId() { + if (mPhone.isSubscriptionManagerServiceEnabled()) { + return SubscriptionManagerService.getInstance().getSubId(mPhone.getPhoneId()); + } return SubscriptionController.getInstance().getSubId(mPhone.getPhoneId()); } diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 1e947e50f8..4d59180d9a 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -42,6 +42,7 @@ import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -564,18 +565,32 @@ public class SmsController extends ISmsImplBase { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Override public int getPreferredSmsSubscription() { - // If there is a default, choose that one. - int defaultSubId = SubscriptionController.getInstance().getDefaultSmsSubId(); + int defaultSubId; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + // If there is a default, choose that one. + defaultSubId = SubscriptionManagerService.getInstance().getDefaultSmsSubId(); + } else { + // If there is a default, choose that one. + defaultSubId = SubscriptionController.getInstance().getDefaultSmsSubId(); + } if (SubscriptionManager.isValidSubscriptionId(defaultSubId)) { return defaultSubId; } // No default, if there is only one sub active, choose that as the "preferred" sub id. long token = Binder.clearCallingIdentity(); try { - int[] activeSubs = SubscriptionController.getInstance() - .getActiveSubIdList(true /*visibleOnly*/); - if (activeSubs.length == 1) { - return activeSubs[0]; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + int[] activeSubs = SubscriptionManagerService.getInstance() + .getActiveSubIdList(true /*visibleOnly*/); + if (activeSubs.length == 1) { + return activeSubs[0]; + } + } else { + int[] activeSubs = SubscriptionController.getInstance() + .getActiveSubIdList(true /*visibleOnly*/); + if (activeSubs.length == 1) { + return activeSubs[0]; + } } } finally { Binder.restoreCallingIdentity(token); diff --git a/src/java/com/android/internal/telephony/UiccPhoneBookController.java b/src/java/com/android/internal/telephony/UiccPhoneBookController.java index 5b55c35631..8b8457c2b8 100644 --- a/src/java/com/android/internal/telephony/UiccPhoneBookController.java +++ b/src/java/com/android/internal/telephony/UiccPhoneBookController.java @@ -19,11 +19,12 @@ package com.android.internal.telephony; import android.compat.annotation.UnsupportedAppUsage; +import android.content.ContentValues; import android.os.Build; import android.os.TelephonyServiceManager.ServiceRegisterer; import android.telephony.TelephonyFrameworkInitializer; -import android.content.ContentValues; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.AdnCapacity; import com.android.internal.telephony.uicc.AdnRecord; import com.android.telephony.Rlog; @@ -146,7 +147,12 @@ public class UiccPhoneBookController extends IIccPhoneBook.Stub { private IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(int subId) { - int phoneId = SubscriptionController.getInstance().getPhoneId(subId); + int phoneId; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + phoneId = SubscriptionManagerService.getInstance().getPhoneId(subId); + } else { + phoneId = SubscriptionController.getInstance().getPhoneId(subId); + } try { return PhoneFactory.getPhone(phoneId).getIccPhoneBookInterfaceManager(); } catch (NullPointerException e) { diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java index f0ac9af9ad..31b997fb57 100644 --- a/src/java/com/android/internal/telephony/cat/CatService.java +++ b/src/java/com/android/internal/telephony/cat/CatService.java @@ -46,9 +46,11 @@ import android.telephony.TelephonyManager; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ProxyController; import com.android.internal.telephony.SmsController; import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.IccFileHandler; import com.android.internal.telephony.uicc.IccRecords; @@ -931,9 +933,16 @@ public class CatService extends Handler implements AppInterface { //TODO Need to take care for MSIM public static AppInterface getInstance() { int slotId = PhoneConstants.DEFAULT_SLOT_INDEX; - SubscriptionController sControl = SubscriptionController.getInstance(); - if (sControl != null) { - slotId = sControl.getSlotIndex(sControl.getDefaultSubId()); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + if (SubscriptionManagerService.getInstance() != null) { + slotId = SubscriptionManagerService.getInstance().getSlotIndex( + SubscriptionManagerService.getInstance().getDefaultSubId()); + } + } else { + SubscriptionController sControl = SubscriptionController.getInstance(); + if (sControl != null) { + slotId = sControl.getSlotIndex(sControl.getDefaultSubId()); + } } return getInstance(null, null, null, slotId); } diff --git a/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java b/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java index 6d020f7c42..aa830aeea4 100644 --- a/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java +++ b/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java @@ -43,6 +43,8 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import java.util.Comparator; import java.util.HashMap; @@ -164,9 +166,17 @@ public class CellularNetworkValidator { private String getValidationNetworkIdentity(int subId) { if (!SubscriptionManager.isUsableSubscriptionId(subId)) return null; - SubscriptionController subController = SubscriptionController.getInstance(); - if (subController == null) return null; - Phone phone = PhoneFactory.getPhone(subController.getPhoneId(subId)); + Phone phone; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + if (SubscriptionManagerService.getInstance() == null) return null; + phone = PhoneFactory.getPhone(SubscriptionManagerService.getInstance() + .getPhoneId(subId)); + } else { + SubscriptionController subController = SubscriptionController.getInstance(); + if (subController == null) return null; + phone = PhoneFactory.getPhone(subController.getPhoneId(subId)); + } + if (phone == null || phone.getServiceState() == null) return null; NetworkRegistrationInfo regInfo = phone.getServiceState().getNetworkRegistrationInfo( @@ -257,10 +267,20 @@ public class CellularNetworkValidator { // If it's already validating the same subscription, do nothing. if (subId == mSubId) return; - if (!SubscriptionController.getInstance().isActiveSubId(subId)) { - logd("Failed to start validation. Inactive subId " + subId); - callback.onValidationDone(false, subId); - return; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(subId); + if (subInfo == null || !subInfo.isActive()) { + logd("Failed to start validation. Inactive subId " + subId); + callback.onValidationDone(false, subId); + return; + } + } else { + if (!SubscriptionController.getInstance().isActiveSubId(subId)) { + logd("Failed to start validation. Inactive subId " + subId); + callback.onValidationDone(false, subId); + return; + } } if (isValidating()) { diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index 15743d77d6..3c29537180 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -19,7 +19,6 @@ package com.android.internal.telephony.data; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.content.ContentResolver; -import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; import android.os.Looper; @@ -50,6 +49,8 @@ import com.android.internal.telephony.SettingsObserver; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback; import com.android.internal.telephony.metrics.DeviceTelephonyPropertiesStats; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -395,9 +396,16 @@ public class DataSettingsManager extends Handler { } } - private static boolean isStandAloneOpportunistic(int subId, Context context) { + private boolean isStandAloneOpportunistic(int subId) { + if (mPhone.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(subId); + return subInfo != null && subInfo.isOpportunistic() + && TextUtils.isEmpty(subInfo.getGroupUuid()); + } SubscriptionInfo info = SubscriptionController.getInstance().getActiveSubscriptionInfo( - subId, context.getOpPackageName(), context.getAttributionTag()); + subId, mPhone.getContext().getOpPackageName(), + mPhone.getContext().getAttributionTag()); return (info != null) && info.isOpportunistic() && info.getGroupUuid() == null; } @@ -408,7 +416,7 @@ public class DataSettingsManager extends Handler { */ private void setUserDataEnabled(boolean enabled, String callingPackage) { // Can't disable data for stand alone opportunistic subscription. - if (isStandAloneOpportunistic(mSubId, mPhone.getContext()) && !enabled) return; + if (isStandAloneOpportunistic(mSubId) && !enabled) return; boolean changed = GlobalSettingsHelper.setInt(mPhone.getContext(), Settings.Global.MOBILE_DATA, mSubId, (enabled ? 1 : 0)); log("Set user data enabled to " + enabled + ", changed=" + changed + ", callingPackage=" @@ -430,7 +438,7 @@ public class DataSettingsManager extends Handler { } // User data should always be true for opportunistic subscription. - if (isStandAloneOpportunistic(mSubId, mPhone.getContext())) return true; + if (isStandAloneOpportunistic(mSubId)) return true; boolean defaultVal = TelephonyProperties.mobile_data().orElse(true); @@ -580,8 +588,17 @@ public class DataSettingsManager extends Handler { /** Refresh the enabled mobile data policies from Telephony database */ private void refreshEnabledMobileDataPolicy() { - mEnabledMobileDataPolicy = getMobileDataPolicyEnabled(SubscriptionController - .getInstance().getEnabledMobileDataPolicies(mSubId)); + if (mPhone.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(mSubId); + if (subInfo != null) { + mEnabledMobileDataPolicy = getMobileDataPolicyEnabled( + subInfo.getEnabledMobileDataPolicies()); + } + } else { + mEnabledMobileDataPolicy = getMobileDataPolicyEnabled(SubscriptionController + .getInstance().getEnabledMobileDataPolicies(mSubId)); + } } /** @@ -621,14 +638,23 @@ public class DataSettingsManager extends Handler { String enabledMobileDataPolicies = mEnabledMobileDataPolicy.stream().map(String::valueOf) .collect(Collectors.joining(",")); - if (SubscriptionController.getInstance().setEnabledMobileDataPolicies( - mSubId, enabledMobileDataPolicies)) { + if (mPhone.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().setEnabledMobileDataPolicies(mSubId, + enabledMobileDataPolicies); logl(TelephonyUtils.mobileDataPolicyToString(mobileDataPolicy) + " changed to " + enable); updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_OVERRIDE); notifyDataEnabledOverrideChanged(enable, mobileDataPolicy); } else { - loge("onSetMobileDataPolicy: failed to set " + enabledMobileDataPolicies); + if (SubscriptionController.getInstance().setEnabledMobileDataPolicies( + mSubId, enabledMobileDataPolicies)) { + logl(TelephonyUtils.mobileDataPolicyToString(mobileDataPolicy) + " changed to " + + enable); + updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_OVERRIDE); + notifyDataEnabledOverrideChanged(enable, mobileDataPolicy); + } else { + loge("onSetMobileDataPolicy: failed to set " + enabledMobileDataPolicies); + } } } @@ -722,8 +748,14 @@ public class DataSettingsManager extends Handler { overridden = apnType == ApnSetting.TYPE_MMS; } - SubscriptionController subscriptionController = SubscriptionController.getInstance(); - boolean isNonDds = mPhone.getSubId() != subscriptionController.getDefaultDataSubId(); + boolean isNonDds; + if (mPhone.isSubscriptionManagerServiceEnabled()) { + isNonDds = mPhone.getSubId() != SubscriptionManagerService.getInstance() + .getDefaultDataSubId(); + } else { + isNonDds = mPhone.getSubId() != SubscriptionController.getInstance() + .getDefaultDataSubId(); + } // mobile data policy : data during call if (isMobileDataPolicyEnabled(TelephonyManager @@ -733,9 +765,17 @@ public class DataSettingsManager extends Handler { // mobile data policy : auto data switch if (isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)) { - // check user enabled data on the default data phone - Phone defaultDataPhone = PhoneFactory.getPhone(subscriptionController.getPhoneId( - subscriptionController.getDefaultDataSubId())); + Phone defaultDataPhone; + if (mPhone.isSubscriptionManagerServiceEnabled()) { + // check user enabled data on the default data phone + defaultDataPhone = PhoneFactory.getPhone(SubscriptionManagerService.getInstance() + .getPhoneId(SubscriptionManagerService.getInstance() + .getDefaultDataSubId())); + } else { + // check user enabled data on the default data phone + defaultDataPhone = PhoneFactory.getPhone(SubscriptionController.getInstance() + .getPhoneId(SubscriptionController.getInstance().getDefaultDataSubId())); + } if (defaultDataPhone == null) { loge("isDataEnabledOverriddenForApn: unexpected defaultDataPhone is null"); } else { diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 44e40ad6b4..5fcc960141 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -675,7 +675,7 @@ public class PhoneSwitcher extends Handler { return false; } - SubscriptionInfo info = SubscriptionController.getInstance() + SubscriptionInfo info = mSubscriptionController .getActiveSubscriptionInfoForSimSlotIndex(slotIndex, mContext.getOpPackageName(), null); boolean uiccAppsEnabled = info != null && info.areUiccApplicationsEnabled(); @@ -1583,7 +1583,7 @@ public class PhoneSwitcher extends Handler { protected void updatePreferredDataPhoneId() { Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); // check user enabled data on the default phone - int defaultDataPhoneId = SubscriptionController.getInstance().getPhoneId(mPrimaryDataSubId); + int defaultDataPhoneId = mSubscriptionController.getPhoneId(mPrimaryDataSubId); Phone defaultDataPhone = findPhoneById(defaultDataPhoneId); boolean isDataEnabled = false; if (voicePhone != null && defaultDataPhone != null diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 60eac2bd31..2a903ea2c5 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -636,6 +636,27 @@ public class SubscriptionManagerService extends ISub.Stub { mSubscriptionDatabaseManager.setCarrierName(subId, carrierName); } + /** + * Set last used TP message reference. + * + * @param subId Subscription id. + * @param lastUsedTPMessageReference Last used TP message reference. + */ + public void setLastUsedTPMessageReference(int subId, int lastUsedTPMessageReference) { + mSubscriptionDatabaseManager.setLastUsedTPMessageReference( + subId, lastUsedTPMessageReference); + } + + /** + * Set the enabled mobile data policies. + * + * @param subId Subscription id. + * @param enabledMobileDataPolicies The enabled mobile data policies. + */ + public void setEnabledMobileDataPolicies(int subId, @NonNull String enabledMobileDataPolicies) { + mSubscriptionDatabaseManager.setEnabledMobileDataPolicies(subId, enabledMobileDataPolicies); + } + /** * Mark all subscriptions on this SIM slot index inactive. * -- GitLab From 055e478a23480d32da5531017b7a5b454e9f0807 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 30 Nov 2022 00:29:15 -0800 Subject: [PATCH 230/656] Migrated PhoneSwitcher to use SubscriptionManagerService Test: atest FrameworksTelephonyTests Bug: 239607619 Change-Id: I42ad1ec0aaddb1111f9b820e8029af7c23a13cda --- .../telephony/data/PhoneSwitcher.java | 239 ++++++++++++------ .../data/TelephonyNetworkFactory.java | 24 +- .../emergency/EmergencyNumberTracker.java | 15 +- .../SubscriptionManagerService.java | 41 ++- .../SubscriptionManagerServiceTest.java | 46 +++- 5 files changed, 264 insertions(+), 101 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 5fcc960141..304c32453f 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -94,6 +94,8 @@ import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.util.NotificationChannelController; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -204,6 +206,7 @@ public class PhoneSwitcher extends Handler { private final @NonNull NetworkRequestList mNetworkRequestList = new NetworkRequestList(); protected final RegistrantList mActivePhoneRegistrants; protected final SubscriptionController mSubscriptionController; + private final SubscriptionManagerService mSubscriptionManagerService; protected final Context mContext; private final LocalLog mLocalLog; protected PhoneState[] mPhoneStates; @@ -550,6 +553,7 @@ public class PhoneSwitcher extends Handler { mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES); mSubscriptionController = SubscriptionController.getInstance(); + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); mRadioConfig = RadioConfig.getInstance(); mValidator = CellularNetworkValidator.getInstance(); @@ -675,9 +679,16 @@ public class PhoneSwitcher extends Handler { return false; } - SubscriptionInfo info = mSubscriptionController - .getActiveSubscriptionInfoForSimSlotIndex(slotIndex, - mContext.getOpPackageName(), null); + SubscriptionInfo info; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + info = mSubscriptionManagerService + .getActiveSubscriptionInfoForSimSlotIndex(slotIndex, + mContext.getOpPackageName(), mContext.getAttributionTag()); + } else { + info = mSubscriptionController + .getActiveSubscriptionInfoForSimSlotIndex(slotIndex, + mContext.getOpPackageName(), null); + } boolean uiccAppsEnabled = info != null && info.areUiccApplicationsEnabled(); IccCard iccCard = PhoneFactory.getPhone(slotIndex).getIccCard(); @@ -927,7 +938,7 @@ public class PhoneSwitcher extends Handler { * Register for device config change on the primary data phone. */ private void registerConfigChange() { - Phone phone = findPhoneById(mSubscriptionController.getPhoneId(mPrimaryDataSubId)); + Phone phone = getPhoneBySubId(mPrimaryDataSubId); if (phone != null) { DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); dataConfig.registerCallback(mDataConfigManagerCallback); @@ -940,7 +951,7 @@ public class PhoneSwitcher extends Handler { * Update data config. */ private void updateConfig() { - Phone phone = findPhoneById(mSubscriptionController.getPhoneId(mPrimaryDataSubId)); + Phone phone = getPhoneBySubId(mPrimaryDataSubId); if (phone != null) { DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); mAutoDataSwitchAvailabilityStabilityTimeThreshold = @@ -1114,74 +1125,84 @@ public class PhoneSwitcher extends Handler { // auto data switch feature is disabled from server if (mAutoDataSwitchAvailabilityStabilityTimeThreshold < 0) return; // check is valid DSDS - if (!mSubscriptionController.isActiveSubId(mPrimaryDataSubId) - || mSubscriptionController.getActiveSubIdList(true).length <= 1) { + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + if (!isActiveSubId(mPrimaryDataSubId) || mSubscriptionManagerService + .getActiveSubIdList(true).length <= 1) { + return; + } + } else { + if (!isActiveSubId(mPrimaryDataSubId) + || mSubscriptionController.getActiveSubIdList(true).length <= 1) { + return; + } + } + + Phone primaryDataPhone = getPhoneBySubId(mPrimaryDataSubId); + if (primaryDataPhone == null) { + loge("evaluateIfAutoSwitchIsNeeded: cannot find primary data phone. subId=" + + mPrimaryDataSubId); return; } - int primaryPhoneId = mSubscriptionController.getPhoneId(mPrimaryDataSubId); + int primaryPhoneId = primaryDataPhone.getPhoneId(); log("evaluateIfAutoSwitchIsNeeded: primaryPhoneId: " + primaryPhoneId + " preferredPhoneId: " + mPreferredDataPhoneId); - Phone primaryDataPhone = findPhoneById(primaryPhoneId); Phone secondaryDataPhone; - if (primaryDataPhone != null) { - if (mPreferredDataPhoneId == primaryPhoneId) { - // on primary data sub + if (mPreferredDataPhoneId == primaryPhoneId) { + // on primary data sub - if (isAnyVoiceCallActiveOnDevice()) { - // if on voice call, switch immediately - evaluateIfImmediateDataSwitchIsNeeded( - "user updates data settings during voice call", - DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); - return; - } - - int candidateSubId = getAutoSwitchTargetSubIdIfExists(); - if (candidateSubId != INVALID_SUBSCRIPTION_ID) { - startAutoDataSwitchStabilityCheck(candidateSubId, true); - } else { - cancelPendingAutoDataSwitch(); - } - } else if ((secondaryDataPhone = findPhoneById(mPreferredDataPhoneId)) != null) { - // on secondary data sub - - if (!primaryDataPhone.isUserDataEnabled() - || !secondaryDataPhone.isDataAllowed()) { - // immediately switch back if user setting changes - mAutoSelectedDataSubId = DEFAULT_SUBSCRIPTION_ID; - evaluateIfImmediateDataSwitchIsNeeded("User disabled data settings", - DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL); - return; - } + if (isAnyVoiceCallActiveOnDevice()) { + // if on voice call, switch immediately + evaluateIfImmediateDataSwitchIsNeeded( + "user updates data settings during voice call", + DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); + return; + } - NetworkCapabilities defaultNetworkCapabilities = mConnectivityManager - .getNetworkCapabilities(mConnectivityManager.getActiveNetwork()); - if (defaultNetworkCapabilities != null && !defaultNetworkCapabilities - .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - log("evaluateIfAutoSwitchIsNeeded:" - + "Default network is active on non-cellular transport"); - startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, false); - return; - } + int candidateSubId = getAutoSwitchTargetSubIdIfExists(); + if (candidateSubId != INVALID_SUBSCRIPTION_ID) { + startAutoDataSwitchStabilityCheck(candidateSubId, true); + } else { + cancelPendingAutoDataSwitch(); + } + } else if ((secondaryDataPhone = findPhoneById(mPreferredDataPhoneId)) != null) { + // on secondary data sub + + if (!primaryDataPhone.isUserDataEnabled() + || !secondaryDataPhone.isDataAllowed()) { + // immediately switch back if user setting changes + mAutoSelectedDataSubId = DEFAULT_SUBSCRIPTION_ID; + evaluateIfImmediateDataSwitchIsNeeded("User disabled data settings", + DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL); + return; + } - if (mPhoneStates[secondaryDataPhone.getPhoneId()].dataRegState - != NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { - // secondary phone lost its HOME availability - startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, false); - return; - } + NetworkCapabilities defaultNetworkCapabilities = mConnectivityManager + .getNetworkCapabilities(mConnectivityManager.getActiveNetwork()); + if (defaultNetworkCapabilities != null && !defaultNetworkCapabilities + .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + log("evaluateIfAutoSwitchIsNeeded:" + + "Default network is active on non-cellular transport"); + startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, false); + return; + } - if (isInService(mPhoneStates[primaryPhoneId])) { - // primary becomes available - startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, true); - return; - } + if (mPhoneStates[secondaryDataPhone.getPhoneId()].dataRegState + != NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { + // secondary phone lost its HOME availability + startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, false); + return; + } - // cancel any previous attempts of switching back to primary - cancelPendingAutoDataSwitch(); + if (isInService(mPhoneStates[primaryPhoneId])) { + // primary becomes available + startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, true); + return; } + // cancel any previous attempts of switching back to primary + cancelPendingAutoDataSwitch(); } } @@ -1234,14 +1255,14 @@ public class PhoneSwitcher extends Handler { * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} */ private int getAutoSwitchTargetSubIdIfExists() { - int primaryPhoneId = mSubscriptionController.getPhoneId(mPrimaryDataSubId); - Phone primaryDataPhone = findPhoneById(primaryPhoneId); - + Phone primaryDataPhone = getPhoneBySubId(mPrimaryDataSubId); if (primaryDataPhone == null) { log("getAutoSwitchTargetSubId: no sim loaded"); return INVALID_SUBSCRIPTION_ID; } + int primaryPhoneId = primaryDataPhone.getPhoneId(); + if (!primaryDataPhone.isUserDataEnabled()) { log("getAutoSwitchTargetSubId: user disabled data"); return INVALID_SUBSCRIPTION_ID; @@ -1300,7 +1321,12 @@ public class PhoneSwitcher extends Handler { boolean diffDetected = mHalCommandToUse != HAL_COMMAND_PREFERRED_DATA && requestsChanged; // Check if user setting of default non-opportunistic data sub is changed. - final int primaryDataSubId = mSubscriptionController.getDefaultDataSubId(); + int primaryDataSubId; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + primaryDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); + } else { + primaryDataSubId = mSubscriptionController.getDefaultDataSubId(); + } if (primaryDataSubId != mPrimaryDataSubId) { sb.append(" mPrimaryDataSubId ").append(mPrimaryDataSubId).append("->") .append(primaryDataSubId); @@ -1313,7 +1339,12 @@ public class PhoneSwitcher extends Handler { // Check if phoneId to subId mapping is changed. for (int i = 0; i < mActiveModemCount; i++) { - int sub = mSubscriptionController.getSubId(i); + int sub; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + sub = mSubscriptionManagerService.getSubId(i); + } else { + sub = mSubscriptionController.getSubId(i); + } if (SubscriptionManager.isValidSubscriptionId(sub)) hasAnyActiveSubscription = true; @@ -1570,8 +1601,18 @@ public class PhoneSwitcher extends Handler { return INVALID_SUBSCRIPTION_ID; } + private boolean isActiveSubId(int subId) { + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + return subInfo != null && subInfo.isActive(); + } else { + return mSubscriptionController.isActiveSubId(subId); + } + } + private int getSubIdForDefaultNetworkRequests() { - if (mSubscriptionController.isActiveSubId(mAutoSelectedDataSubId)) { + if (isActiveSubId(mAutoSelectedDataSubId)) { return mAutoSelectedDataSubId; } else { return mPrimaryDataSubId; @@ -1583,8 +1624,7 @@ public class PhoneSwitcher extends Handler { protected void updatePreferredDataPhoneId() { Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); // check user enabled data on the default phone - int defaultDataPhoneId = mSubscriptionController.getPhoneId(mPrimaryDataSubId); - Phone defaultDataPhone = findPhoneById(defaultDataPhoneId); + Phone defaultDataPhone = getPhoneBySubId(mPrimaryDataSubId); boolean isDataEnabled = false; if (voicePhone != null && defaultDataPhone != null && defaultDataPhone.isUserDataEnabled()) { @@ -1623,8 +1663,11 @@ public class PhoneSwitcher extends Handler { mPreferredDataPhoneId = phoneId; } - mPreferredDataSubId.set( - mSubscriptionController.getSubId(mPreferredDataPhoneId)); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + mPreferredDataSubId.set(mSubscriptionManagerService.getSubId(mPreferredDataPhoneId)); + } else { + mPreferredDataSubId.set(mSubscriptionController.getSubId(mPreferredDataPhoneId)); + } } protected void transitionToEmergencyPhone() { @@ -1644,6 +1687,14 @@ public class PhoneSwitcher extends Handler { } } + private Phone getPhoneBySubId(int subId) { + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + return findPhoneById(mSubscriptionManagerService.getPhoneId(subId)); + } else { + return findPhoneById(mSubscriptionController.getPhoneId(subId)); + } + } + private Phone findPhoneById(final int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId)) { return null; @@ -1655,15 +1706,21 @@ public class PhoneSwitcher extends Handler { TelephonyNetworkRequest networkRequest, int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId)) return false; + int subId; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + subId = mSubscriptionManagerService.getSubId(phoneId); + } else { + subId = mSubscriptionController.getSubId(phoneId); + } + // In any case, if phone state is inactive, don't apply the network request. - if (!isPhoneActive(phoneId) || ( - mSubscriptionController.getSubId(phoneId) == INVALID_SUBSCRIPTION_ID + if (!isPhoneActive(phoneId) || (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID && !isEmergencyNetworkRequest(networkRequest))) { return false; } NetworkRequest netRequest = networkRequest.getNativeNetworkRequest(); - int subId = getSubIdFromNetworkSpecifier(netRequest.getNetworkSpecifier()); + subId = getSubIdFromNetworkSpecifier(netRequest.getNetworkSpecifier()); //if this phone is an emergency networkRequest //and subId is not specified that is invalid or default @@ -1738,7 +1795,7 @@ public class PhoneSwitcher extends Handler { + " needValidation=" + needValidation); int subIdToValidate = (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) ? mPrimaryDataSubId : subId; - if (!mSubscriptionController.isActiveSubId(subIdToValidate)) { + if (!isActiveSubId(subIdToValidate)) { logl("Can't switch data to inactive subId " + subIdToValidate); if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { // the default data sub is not selected yet, store the intent of switching to @@ -1834,7 +1891,7 @@ public class PhoneSwitcher extends Handler { private void confirmSwitch(int subId, boolean confirm) { logl("confirmSwitch: subId " + subId + (confirm ? " confirmed." : " cancelled.")); int resultForCallBack; - if (!mSubscriptionController.isActiveSubId(subId)) { + if (!isActiveSubId(subId)) { logl("confirmSwitch: subId " + subId + " is no longer active"); resultForCallBack = SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION; mAutoSwitchRetryFailedCount = 0; @@ -2071,9 +2128,15 @@ public class PhoneSwitcher extends Handler { } pw.println("mPreferredDataPhoneId=" + mPreferredDataPhoneId); pw.println("mPreferredDataSubId=" + mPreferredDataSubId.get()); - pw.println("DefaultDataSubId=" + mSubscriptionController.getDefaultDataSubId()); - pw.println("DefaultDataPhoneId=" + mSubscriptionController.getPhoneId( - mSubscriptionController.getDefaultDataSubId())); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + pw.println("DefaultDataSubId=" + mSubscriptionManagerService.getDefaultDataSubId()); + pw.println("DefaultDataPhoneId=" + mSubscriptionManagerService.getPhoneId( + mSubscriptionManagerService.getDefaultDataSubId())); + } else { + pw.println("DefaultDataSubId=" + mSubscriptionController.getDefaultDataSubId()); + pw.println("DefaultDataPhoneId=" + mSubscriptionController.getPhoneId( + mSubscriptionController.getDefaultDataSubId())); + } pw.println("mPrimaryDataSubId=" + mPrimaryDataSubId); pw.println("mAutoSelectedDataSubId=" + mAutoSelectedDataSubId); pw.println("mIsRegisteredForImsRadioTechChange=" + mIsRegisteredForImsRadioTechChange); @@ -2159,8 +2222,12 @@ public class PhoneSwitcher extends Handler { + switchReasonToString(mLastSwitchPreferredDataReason)); return; } - SubscriptionInfo subInfo = mSubscriptionController.getSubscriptionInfo( - mAutoSelectedDataSubId); + SubscriptionInfo subInfo; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + subInfo = mSubscriptionManagerService.getSubscriptionInfo(mAutoSelectedDataSubId); + } else { + subInfo = mSubscriptionController.getSubscriptionInfo(mAutoSelectedDataSubId); + } if (subInfo == null || subInfo.isOpportunistic()) { loge("displayAutoDataSwitchNotification:mAutoSelectedDataSubId=" + mAutoSelectedDataSubId + " unexpected subInfo " + subInfo); @@ -2199,16 +2266,20 @@ public class PhoneSwitcher extends Handler { } private boolean isPhoneIdValidForRetry(int phoneId) { - int phoneIdForRequest = INVALID_PHONE_INDEX; - int ddsPhoneId = mSubscriptionController.getPhoneId( - mSubscriptionController.getDefaultDataSubId()); + int ddsPhoneId; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + ddsPhoneId = mSubscriptionManagerService.getPhoneId( + mSubscriptionManagerService.getDefaultDataSubId()); + } else { + ddsPhoneId = mSubscriptionController.getPhoneId( + mSubscriptionController.getDefaultDataSubId()); + } if (ddsPhoneId != INVALID_PHONE_INDEX && ddsPhoneId == phoneId) { return true; } else { if (mNetworkRequestList.isEmpty()) return false; for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { - phoneIdForRequest = phoneIdForRequest(networkRequest); - if (phoneIdForRequest == phoneId) { + if (phoneIdForRequest(networkRequest) == phoneId) { return true; } } diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java index 3a71055558..5e463e9a54 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java @@ -31,6 +31,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.metrics.NetworkRequestsStats; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -63,7 +64,6 @@ public class TelephonyNetworkFactory extends NetworkFactory { private static final int EVENT_NETWORK_RELEASE = 4; private final PhoneSwitcher mPhoneSwitcher; - private final SubscriptionController mSubscriptionController; private final LocalLog mLocalLog = new LocalLog(REQUEST_LOG_SIZE); // Key: network request. Value: the transport of the network request applies to, @@ -86,10 +86,9 @@ public class TelephonyNetworkFactory extends NetworkFactory { mPhone = phone; mInternalHandler = new InternalHandler(looper); - mSubscriptionController = SubscriptionController.getInstance(); mAccessNetworksManager = mPhone.getAccessNetworksManager(); - setCapabilityFilter(makeNetworkFilter(mSubscriptionController, mPhone.getPhoneId())); + setCapabilityFilter(makeNetworkFilterByPhoneId(mPhone.getPhoneId())); setScoreFilter(TELEPHONY_NETWORK_SCORE); mPhoneSwitcher = PhoneSwitcher.getInstance(); @@ -113,10 +112,12 @@ public class TelephonyNetworkFactory extends NetworkFactory { } }; - private NetworkCapabilities makeNetworkFilter(SubscriptionController subscriptionController, - int phoneId) { - final int subscriptionId = subscriptionController.getSubId(phoneId); - return makeNetworkFilter(subscriptionId); + private NetworkCapabilities makeNetworkFilterByPhoneId(int phoneId) { + if (mPhone.isSubscriptionManagerServiceEnabled()) { + return makeNetworkFilter(SubscriptionManagerService.getInstance().getSubId(phoneId)); + } else { + return makeNetworkFilter(SubscriptionController.getInstance().getSubId(phoneId)); + } } /** @@ -238,8 +239,13 @@ public class TelephonyNetworkFactory extends NetworkFactory { // watch for phone->subId changes, reapply new filter and let // that flow through to apply/revoke of requests private void onSubIdChange() { - final int newSubscriptionId = mSubscriptionController.getSubId( - mPhone.getPhoneId()); + int newSubscriptionId; + if (mPhone.isSubscriptionManagerServiceEnabled()) { + newSubscriptionId = SubscriptionManagerService.getInstance().getSubId( + mPhone.getPhoneId()); + } else { + newSubscriptionId = SubscriptionController.getInstance().getSubId(mPhone.getPhoneId()); + } if (mSubscriptionId != newSubscriptionId) { if (DBG) logl("onSubIdChange " + mSubscriptionId + "->" + newSubscriptionId); mSubscriptionId = newSubscriptionId; diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index af40f2c0b5..85cc5be2af 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -55,6 +55,7 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.IndentingPrintWriter; import com.android.phone.ecc.nano.ProtobufEccData; import com.android.phone.ecc.nano.ProtobufEccData.EccInfo; @@ -293,7 +294,12 @@ public class EmergencyNumberTracker extends Handler { @VisibleForTesting public boolean isSimAbsent() { for (Phone phone: PhoneFactory.getPhones()) { - int slotId = SubscriptionController.getInstance().getSlotIndex(phone.getSubId()); + int slotId; + if (phone.isSubscriptionManagerServiceEnabled()) { + slotId = SubscriptionManagerService.getInstance().getSlotIndex(phone.getSubId()); + } else { + slotId = SubscriptionController.getInstance().getSlotIndex(phone.getSubId()); + } // If slot id is invalid, it means that there is no sim card. if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { // If there is at least one sim active, sim is not absent; it returns false @@ -1031,7 +1037,12 @@ public class EmergencyNumberTracker extends Handler { } private String getEmergencyNumberListForHalv1_3() { - int slotId = SubscriptionController.getInstance().getSlotIndex(mPhone.getSubId()); + int slotId; + if (mPhone.isSubscriptionManagerServiceEnabled()) { + slotId = SubscriptionManagerService.getInstance().getSlotIndex(mPhone.getSubId()); + } else { + slotId = SubscriptionController.getInstance().getSlotIndex(mPhone.getSubId()); + } String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); String emergencyNumbers = SystemProperties.get(ecclist, ""); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 2a903ea2c5..e09f6ec395 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -766,15 +766,41 @@ public class SubscriptionManagerService extends ISub.Stub { /** * Get the active {@link SubscriptionInfo} associated with the logical SIM slot index. * - * @param slotIndex the logical SIM slot index which the subscription is inserted - * @param callingPackage The package making the call - * @param callingFeatureId The feature in the package + * @param slotIndex the logical SIM slot index which the subscription is inserted. + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * - * @return SubscriptionInfo, null for Remote-SIMs or non-active logical SIM slot index. + * @return {@link SubscriptionInfo}, null for Remote-SIMs or non-active logical SIM slot index. */ @Override + @Nullable + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, @NonNull String callingPackage, @Nullable String callingFeatureId) { + int subId = mSlotIndexToSubId.getOrDefault(slotIndex, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + + if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, + callingPackage, callingFeatureId, + "getActiveSubscriptionInfoForSimSlotIndex")) { + throw new SecurityException("Requires READ_PHONE_STATE permission."); + } + + if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { + throw new IllegalArgumentException("Invalid slot index " + slotIndex); + } + + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + if (subInfo != null && subInfo.isActive()) { + return conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), callingPackage, + callingFeatureId, "getActiveSubscriptionInfoForSimSlotIndex"); + } + return null; } @@ -939,7 +965,11 @@ public class SubscriptionManagerService extends ISub.Stub { // Check if the record exists or not. if (subInfo == null) { // Record does not exist. - mSubscriptionDatabaseManager.insertSubscriptionInfo( + if (mSlotIndexToSubId.containsKey(slotIndex)) { + loge("Already a subscription on slot " + slotIndex); + return -1; + } + int subId = mSubscriptionDatabaseManager.insertSubscriptionInfo( new SubscriptionInfoInternal.Builder() .setIccId(iccId) .setSimSlotIndex(slotIndex) @@ -947,6 +977,7 @@ public class SubscriptionManagerService extends ISub.Stub { .setType(subscriptionType) .build() ); + mSlotIndexToSubId.put(slotIndex, subId); } else { // Record already exists. loge("Subscription record already existed."); 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 46e0af30b4..ae5d2fdab1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -174,7 +174,21 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { Method method = SubscriptionDatabaseManager.class.getDeclaredMethod( "insertSubscriptionInfo", cArgs); method.setAccessible(true); - return (int) method.invoke(sdbm, subInfo); + int subId = (int) method.invoke(sdbm, subInfo); + + Class WatchedMapClass = Class.forName("com.android.internal.telephony.subscription" + + ".SubscriptionManagerService$WatchedMap"); + field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); + field.setAccessible(true); + Object map = field.get(mSubscriptionManagerServiceUT); + cArgs = new Class[2]; + cArgs[0] = Object.class; + cArgs[1] = Object.class; + + method = WatchedMapClass.getDeclaredMethod("put", cArgs); + method.setAccessible(true); + method.invoke(map, subInfo.getSimSlotIndex(), subId); + return subId; } catch (Exception e) { fail("Failed to insert subscription. e=" + e); } @@ -637,4 +651,34 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfos).hasSize(1); assertThat(subInfos.get(0)).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); } + + @Test + public void testGetActiveSubscriptionInfoForSimSlotIndex() { + // Grant MODIFY_PHONE_STATE permission for insertion. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + // Remove MODIFY_PHONE_STATE + mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // Should fail without READ_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getActiveSubscriptionInfoForSimSlotIndex(0, CALLING_PACKAGE, CALLING_FEATURE)); + + // Grant READ_PHONE_STATE permission for insertion. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); + SubscriptionInfo subInfo = mSubscriptionManagerServiceUT + .getActiveSubscriptionInfoForSimSlotIndex(0, CALLING_PACKAGE, + CALLING_FEATURE); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getSubscriptionId()).isEqualTo(1); + assertThat(subInfo.getIccId()).isEmpty(); + assertThat(subInfo.getNumber()).isEmpty(); + + // Grant carrier privilege for sub 1 + setCarrierPrivilegesForSubId(true, 1); + subInfo = mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex( + 0, CALLING_PACKAGE, CALLING_FEATURE); + assertThat(subInfo).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); + } } -- GitLab From 1035f6adde3c33634531fb0dd527e8ce930534ba Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 1 Dec 2022 01:10:51 -0800 Subject: [PATCH 231/656] Added update embedded subscriptions support Added logic to retrieve embedded profiles and convert to subscription records. Bug: 239607619 Test: atest SubscriptionManagerServiceTest Change-Id: I2b596a478eb8bd5bf9fd4b0e492947a074c71985 --- .../telephony/euicc/EuiccCardController.java | 36 +++- .../telephony/euicc/EuiccController.java | 13 +- .../SubscriptionInfoInternal.java | 18 ++ .../SubscriptionManagerService.java | 184 +++++++++++++++++- .../SubscriptionManagerServiceTest.java | 82 ++++++++ 5 files changed, 319 insertions(+), 14 deletions(-) diff --git a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java index 6a0011dfcd..a63ae1d996 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java @@ -39,7 +39,9 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.uicc.UiccPort; @@ -51,6 +53,7 @@ import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.List; /** Backing implementation of {@link EuiccCardManager}. */ public class EuiccCardController extends IEuiccCardController.Stub { @@ -649,9 +652,14 @@ public class EuiccCardController extends IEuiccCardController.Stub { @Override public void onResult(Void result) { Log.i(TAG, "Request subscription info list refresh after delete."); - SubscriptionController.getInstance() - .requestEmbeddedSubscriptionInfoListRefresh( - mUiccController.convertToPublicCardId(cardId)); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( + List.of(mUiccController.convertToPublicCardId(cardId)), null); + } else { + SubscriptionController.getInstance() + .requestEmbeddedSubscriptionInfoListRefresh( + mUiccController.convertToPublicCardId(cardId)); + } try { callback.onComplete(EuiccCardManager.RESULT_OK); } catch (RemoteException exception) { @@ -701,9 +709,14 @@ public class EuiccCardController extends IEuiccCardController.Stub { @Override public void onResult(Void result) { Log.i(TAG, "Request subscription info list refresh after reset memory."); - SubscriptionController.getInstance() - .requestEmbeddedSubscriptionInfoListRefresh( - mUiccController.convertToPublicCardId(cardId)); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( + List.of(mUiccController.convertToPublicCardId(cardId)), null); + } else { + SubscriptionController.getInstance() + .requestEmbeddedSubscriptionInfoListRefresh( + mUiccController.convertToPublicCardId(cardId)); + } try { callback.onComplete(EuiccCardManager.RESULT_OK); } catch (RemoteException exception) { @@ -1190,9 +1203,14 @@ public class EuiccCardController extends IEuiccCardController.Stub { @Override public void onResult(byte[] result) { Log.i(TAG, "Request subscription info list refresh after install."); - SubscriptionController.getInstance() - .requestEmbeddedSubscriptionInfoListRefresh( - mUiccController.convertToPublicCardId(cardId)); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( + List.of(mUiccController.convertToPublicCardId(cardId)), null); + } else { + SubscriptionController.getInstance() + .requestEmbeddedSubscriptionInfoListRefresh( + mUiccController.convertToPublicCardId(cardId)); + } try { callback.onComplete(EuiccCardManager.RESULT_OK, result); } catch (RemoteException exception) { diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java index f109cde7b4..9b4894e80a 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccController.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java @@ -61,6 +61,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.uicc.UiccPort; @@ -1587,9 +1588,15 @@ public class EuiccController extends IEuiccController.Stub { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public void refreshSubscriptionsAndSendResult( PendingIntent callbackIntent, int resultCode, Intent extrasIntent) { - SubscriptionController.getInstance() - .requestEmbeddedSubscriptionInfoListRefresh( - () -> sendResult(callbackIntent, resultCode, extrasIntent)); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( + List.of(mTelephonyManager.getCardIdForDefaultEuicc()), + () -> sendResult(callbackIntent, resultCode, extrasIntent)); + } else { + SubscriptionController.getInstance() + .requestEmbeddedSubscriptionInfoListRefresh( + () -> sendResult(callbackIntent, resultCode, extrasIntent)); + } } /** Dispatch the given callback intent with the given result code and data. */ diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index f063958acf..7e882f28b0 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -1764,6 +1764,24 @@ public class SubscriptionInfoInternal { return this; } + /** + * Set the native access rules for this subscription, if it is embedded and defines any. + * This does not include access rules for non-embedded subscriptions. + * + * @param nativeAccessRules The native access rules for this subscription. + * + * @return The builder. + */ + @NonNull + public Builder setNativeAccessRules(@NonNull List nativeAccessRules) { + Objects.requireNonNull(nativeAccessRules); + if (!nativeAccessRules.isEmpty()) { + mNativeAccessRules = UiccAccessRule.encodeRules( + nativeAccessRules.toArray(new UiccAccessRule[0])); + } + return this; + } + /** * Set the carrier certificates for this subscription that are saved in carrier configs. * This does not include access rules from the Uicc, whether embedded or non-embedded. diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index e09f6ec395..c001fc4f3f 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -37,15 +37,21 @@ import android.os.ParcelUuid; import android.os.TelephonyServiceManager; import android.os.UserHandle; import android.provider.Settings; +import android.service.carrier.CarrierIdentifier; +import android.service.euicc.EuiccProfileInfo; +import android.service.euicc.EuiccService; +import android.service.euicc.GetEuiccProfileInfoListResult; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.PhoneNumberSource; +import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; +import android.telephony.UiccAccessRule; import android.telephony.euicc.EuiccManager; import android.text.TextUtils; import android.util.ArraySet; @@ -54,11 +60,13 @@ import android.util.IndentingPrintWriter; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.CarrierResolver; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; +import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.UiccController; @@ -107,17 +115,31 @@ public class SubscriptionManagerService extends ISub.Stub { private final Context mContext; /** Telephony manager instance. */ + @NonNull private final TelephonyManager mTelephonyManager; /** Subscription manager instance. */ + @NonNull private final SubscriptionManager mSubscriptionManager; - /** Euicc manager instance. */ + /** + * Euicc manager instance. Will be null if the device does not support + * {@link PackageManager#FEATURE_TELEPHONY_EUICC}. + */ + @Nullable private final EuiccManager mEuiccManager; /** Uicc controller instance. */ + @NonNull private final UiccController mUiccController; + /** + * Euicc controller instance. Will be null if the device does not support + * {@link PackageManager#FEATURE_TELEPHONY_EUICC}. + */ + @Nullable + private EuiccController mEuiccController; + /** The main handler of subscription manager service. */ @NonNull private final Handler mHandler; @@ -288,6 +310,7 @@ public class SubscriptionManagerService extends ISub.Stub { mTelephonyManager = context.getSystemService(TelephonyManager.class); mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mEuiccManager = context.getSystemService(EuiccManager.class); + mUiccController = UiccController.getInstance(); mHandler = new Handler(looper); TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = @@ -402,6 +425,15 @@ public class SubscriptionManagerService extends ISub.Stub { }); updateDefaultSubId(); + + mHandler.post(() -> { + // EuiccController is created after SubscriptionManagerService. So we need to get + // the instance later in the handler. + if (mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_TELEPHONY_EUICC)) { + mEuiccController = EuiccController.get(); + } + }); } /** @@ -669,6 +701,153 @@ public class SubscriptionManagerService extends ISub.Stub { subInfo.getSubscriptionId(), SubscriptionManager.INVALID_SIM_SLOT_INDEX)); } + /** + * This is only for internal use and the returned priority is arbitrary. The idea is to give a + * higher value to name source that has higher priority to override other name sources. + * + * @param nameSource Source of display name. + * + * @return The priority. Higher value means higher priority. + */ + private static int getNameSourcePriority(@SimDisplayNameSource int nameSource) { + int index = Arrays.asList( + SubscriptionManager.NAME_SOURCE_UNKNOWN, + SubscriptionManager.NAME_SOURCE_CARRIER_ID, + SubscriptionManager.NAME_SOURCE_SIM_PNN, + SubscriptionManager.NAME_SOURCE_SIM_SPN, + SubscriptionManager.NAME_SOURCE_CARRIER, + SubscriptionManager.NAME_SOURCE_USER_INPUT // user has highest priority. + ).indexOf(nameSource); + return Math.max(0, index); + } + + /** + * Get the embedded profile port index by ICCID. + * + * @param iccId The ICCID. + * @return The port index. + */ + private int getEmbeddedProfilePortIndex(String iccId) { + UiccSlot[] slots = UiccController.getInstance().getUiccSlots(); + for (UiccSlot slot : slots) { + if (slot != null && slot.isEuicc() + && slot.getPortIndexFromIccId(iccId) != TelephonyManager.INVALID_PORT_INDEX) { + return slot.getPortIndexFromIccId(iccId); + } + } + return TelephonyManager.INVALID_PORT_INDEX; + } + + /** + * Pull the embedded subscription from {@link EuiccController} for the eUICC with the given list + * of card IDs {@code cardIds}. + * + * @param cardIds The card ids of the embedded subscriptions. + * @param callback Callback to be called upon completion. + */ + public void updateEmbeddedSubscriptions(@NonNull List cardIds, + @Nullable Runnable callback) { + mHandler.post(() -> { + // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but + // they are filtered out of list calls as long as EuiccManager.isEnabled returns false). + if (mEuiccManager == null || !mEuiccManager.isEnabled()) { + loge("updateEmbeddedSubscriptions: eUICC not enabled"); + if (callback != null) { + callback.run(); + } + return; + } + + log("updateEmbeddedSubscriptions: start to get euicc profiles."); + for (int cardId : cardIds) { + GetEuiccProfileInfoListResult result = mEuiccController + .blockingGetEuiccProfileInfoList(cardId); + log("updateEmbeddedSubscriptions: cardId=" + cardId + ", result=" + result); + + if (result.getResult() != EuiccService.RESULT_OK) { + loge("Failed to get euicc profile info. result=" + + EuiccService.resultToString(result.getResult())); + continue; + } + + if (result.getProfiles() == null || result.getProfiles().isEmpty()) { + loge("No profiles returned."); + continue; + } + + final boolean isRemovable = result.getIsRemovable(); + + for (EuiccProfileInfo embeddedProfile : result.getProfiles()) { + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternalByIccId(embeddedProfile.getIccid()); + + // The subscription does not exist in the database. Insert a new one here. + if (subInfo == null) { + subInfo = new SubscriptionInfoInternal.Builder() + .setIccId(embeddedProfile.getIccid()) + .build(); + int subId = mSubscriptionDatabaseManager.insertSubscriptionInfo(subInfo); + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setId(subId).build(); + } + + int nameSource = subInfo.getDisplayNameSource(); + int carrierId = subInfo.getCarrierId(); + + SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal + .Builder(subInfo); + + builder.setEmbedded(1); + + List ruleList = embeddedProfile.getUiccAccessRules(); + if (ruleList != null && !ruleList.isEmpty()) { + builder.setNativeAccessRules(embeddedProfile.getUiccAccessRules()); + } + builder.setRemovableEmbedded(isRemovable ? 1 : 0); + + // override DISPLAY_NAME if the priority of existing nameSource is <= carrier + if (getNameSourcePriority(nameSource) <= getNameSourcePriority( + SubscriptionManager.NAME_SOURCE_CARRIER)) { + builder.setDisplayName(embeddedProfile.getNickname()); + builder.setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER); + } + builder.setProfileClass(embeddedProfile.getProfileClass()); + builder.setPortIndex(getEmbeddedProfilePortIndex(embeddedProfile.getIccid())); + + CarrierIdentifier cid = embeddedProfile.getCarrierIdentifier(); + if (cid != null) { + // Due to the limited subscription information, carrier id identified here + // might not be accurate compared with CarrierResolver. Only update carrier + // id if there is no valid carrier id present. + if (carrierId == TelephonyManager.UNKNOWN_CARRIER_ID) { + builder.setCarrierId(CarrierResolver + .getCarrierIdFromIdentifier(mContext, cid)); + } + String mcc = cid.getMcc(); + String mnc = cid.getMnc(); + builder.setMcc(mcc); + builder.setMnc(mnc); + } + // If cardId = unsupported or un-initialized, we have no reason to update DB. + // Additionally, if the device does not support cardId for default eUICC, the + // CARD_ID field should not contain the EID + if (cardId >= 0 && mUiccController.getCardIdForDefaultEuicc() + != TelephonyManager.UNSUPPORTED_CARD_ID) { + builder.setCardString(mUiccController.convertToCardString(cardId)); + } + + subInfo = builder.build(); + log("updateEmbeddedSubscriptions: update subscription " + subInfo); + mSubscriptionDatabaseManager.updateSubscription(subInfo); + } + } + }); + log("updateEmbeddedSubscriptions: Finished embedded subscription update."); + if (callback != null) { + callback.run(); + } + } + /** * Get all subscription info records from SIMs that are inserted now or were inserted before. * @@ -905,7 +1084,8 @@ public class SubscriptionManagerService extends ISub.Stub { return mSubscriptionDatabaseManager.getAllSubscriptions().stream() .filter(subInfo -> subInfo.isActive() || iccIds.contains(subInfo.getIccId()) - || (mEuiccManager.isEnabled() && subInfo.isEmbedded())) + || (mEuiccManager != null && mEuiccManager.isEnabled() + && subInfo.isEmbedded())) .map(SubscriptionInfoInternal::toSubscriptionInfo) .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) .thenComparing(SubscriptionInfo::getSubscriptionId)) 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 ae5d2fdab1..c99f84c388 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -17,13 +17,19 @@ package com.android.internal.telephony.subscription; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MCC1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MCC2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MNC1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MNC2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_NATIVE_ACCESS_RULES1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_NATIVE_ACCESS_RULES2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SUBSCRIPTION_INFO1; @@ -59,8 +65,13 @@ import android.os.ParcelUuid; import android.os.UserHandle; import android.provider.Settings; import android.provider.Telephony; +import android.service.carrier.CarrierIdentifier; +import android.service.euicc.EuiccProfileInfo; +import android.service.euicc.EuiccService; +import android.service.euicc.GetEuiccProfileInfoListResult; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.telephony.UiccAccessRule; import android.test.mock.MockContentResolver; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -68,6 +79,7 @@ import android.testing.TestableLooper; import com.android.internal.telephony.ContextFixture; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; @@ -84,6 +96,7 @@ import org.mockito.Mockito; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.List; @RunWith(AndroidTestingRunner.class) @@ -100,6 +113,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // mocked private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback; + private EuiccController mEuiccController; @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule(); @@ -108,10 +122,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionManagerServiceTest +Setup!"); super.setUp(getClass().getSimpleName()); + mContextFixture.addSystemFeature(PackageManager.FEATURE_TELEPHONY_EUICC); setupMocksForTelephonyPermissions(Build.VERSION_CODES.UPSIDE_DOWN_CAKE); PropertyInvalidatedCache.disableForCurrentProcess("cache_key.is_compat_change_enabled"); doReturn(true).when(mTelephonyManager).isVoiceCapable(); + mEuiccController = Mockito.mock(EuiccController.class); + replaceInstance(EuiccController.class, "sInstance", null, mEuiccController); mMockedSubscriptionManagerServiceCallback = Mockito.mock( SubscriptionManagerServiceCallback.class); ((MockContentResolver) mContext.getContentResolver()).addProvider( @@ -681,4 +698,69 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { 0, CALLING_PACKAGE, CALLING_FEATURE); assertThat(subInfo).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); } + + @Test + public void testUpdateEmbeddedSubscriptions() { + EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID1) + .setIccid(FAKE_ICCID1) + .setNickname(FAKE_CARRIER_NAME1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL) + .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC1, FAKE_MNC1, null, null, null, + null, FAKE_CARRIER_ID1, FAKE_CARRIER_ID1)) + .setUiccAccessRule(Arrays.asList(UiccAccessRule.decodeRules( + FAKE_NATIVE_ACCESS_RULES1))) + .build(); + EuiccProfileInfo profileInfo2 = new EuiccProfileInfo.Builder(FAKE_ICCID2) + .setIccid(FAKE_ICCID2) + .setNickname(FAKE_CARRIER_NAME2) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL) + .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC2, FAKE_MNC2, null, null, null, + null, FAKE_CARRIER_ID2, FAKE_CARRIER_ID2)) + .setUiccAccessRule(Arrays.asList(UiccAccessRule.decodeRules( + FAKE_NATIVE_ACCESS_RULES2))) + .build(); + + GetEuiccProfileInfoListResult result = new GetEuiccProfileInfoListResult( + EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo1}, false); + doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); + result = new GetEuiccProfileInfoListResult(EuiccService.RESULT_OK, + new EuiccProfileInfo[]{profileInfo2}, false); + doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(2)); + doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1)); + doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(2)); + + mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1, 2), null); + processAllMessages(); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo.getSubscriptionId()).isEqualTo(1); + assertThat(subInfo.getSimSlotIndex()).isEqualTo(SubscriptionManager.INVALID_SIM_SLOT_INDEX); + assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID1); + assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); + assertThat(subInfo.getDisplayNameSource()).isEqualTo( + SubscriptionManager.NAME_SOURCE_CARRIER); + assertThat(subInfo.getMcc()).isEqualTo(FAKE_MCC1); + assertThat(subInfo.getMnc()).isEqualTo(FAKE_MNC1); + assertThat(subInfo.getProfileClass()).isEqualTo( + SubscriptionManager.PROFILE_CLASS_OPERATIONAL); + assertThat(subInfo.isEmbedded()).isTrue(); + assertThat(subInfo.isRemovableEmbedded()).isFalse(); + assertThat(subInfo.getNativeAccessRules()).isEqualTo(FAKE_NATIVE_ACCESS_RULES1); + + subInfo = mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2); + assertThat(subInfo.getSubscriptionId()).isEqualTo(2); + assertThat(subInfo.getSimSlotIndex()).isEqualTo(SubscriptionManager.INVALID_SIM_SLOT_INDEX); + assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID2); + assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_CARRIER_NAME2); + assertThat(subInfo.getDisplayNameSource()).isEqualTo( + SubscriptionManager.NAME_SOURCE_CARRIER); + assertThat(subInfo.getMcc()).isEqualTo(FAKE_MCC2); + assertThat(subInfo.getMnc()).isEqualTo(FAKE_MNC2); + assertThat(subInfo.getProfileClass()).isEqualTo( + SubscriptionManager.PROFILE_CLASS_OPERATIONAL); + assertThat(subInfo.isEmbedded()).isTrue(); + assertThat(subInfo.isRemovableEmbedded()).isFalse(); + assertThat(subInfo.getNativeAccessRules()).isEqualTo(FAKE_NATIVE_ACCESS_RULES2); + } } -- GitLab From c79fdc91431ade0f2b2fa3e86439f0d84d2795af Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 2 Dec 2022 22:46:51 -0800 Subject: [PATCH 232/656] Added GetActiveSubscriptionInfo support 1. Added GetActiveSubscriptionInfo. 2. Added SetDisplayNameUsingSrc. 3. Converted more modules to use SubscriptionManagerService. Test: atest FrameworksTelephonyTests Bug: 239607619 Change-Id: I8c0aa35d4430b7c6ca6d02c4e68a00b7d5ef9b94 --- .../telephony/MultiSimSettingController.java | 6 +- .../com/android/internal/telephony/Phone.java | 12 +- .../internal/telephony/SMSDispatcher.java | 6 +- .../telephony/data/PhoneSwitcher.java | 20 +- .../data/TelephonyNetworkFactory.java | 16 +- .../internal/telephony/imsphone/ImsPhone.java | 32 ++- .../imsphone/ImsPhoneCallTracker.java | 20 +- .../metrics/DataCallSessionStats.java | 24 +- .../metrics/DataStallRecoveryStats.java | 9 +- .../telephony/metrics/PerSimStatus.java | 60 +++-- .../SubscriptionManagerService.java | 212 +++++++++++++++++- .../internal/telephony/uicc/RuimRecords.java | 3 +- .../internal/telephony/uicc/SIMRecords.java | 4 +- .../internal/telephony/uicc/UiccProfile.java | 67 ++++-- .../MultiSimSettingControllerTest.java | 46 +++- .../telephony/data/PhoneSwitcherTest.java | 28 ++- .../data/TelephonyNetworkFactoryTest.java | 13 ++ .../SubscriptionManagerServiceTest.java | 74 ++++-- .../telephony/uicc/UiccProfileTest.java | 9 + 19 files changed, 518 insertions(+), 143 deletions(-) diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index ebed17b934..45ea8bc4c3 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -463,11 +463,7 @@ public class MultiSimSettingController extends Handler { // being specified in it. So here we do additional check to make sur we don't miss the // subId. if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - subId = mSubscriptionManagerService.getSubId(phoneId); - } else { - subId = mSubController.getSubId(phoneId); - } + subId = SubscriptionManager.getSubscriptionId(phoneId); if (SubscriptionManager.isValidSubscriptionId(subId)) { CarrierConfigManager cm = mContext.getSystemService(CarrierConfigManager.class); if (cm != null && cm.getConfigForSubId(subId) != null) { diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 7c5db11358..350baeedf1 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -609,6 +609,12 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // Initialize SMS stats mSmsStats = new SmsStats(this); + mIsSubscriptionManagerServiceEnabled = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_using_subscription_manager_service); + if (isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); + } + if (getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { return; } @@ -617,12 +623,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mTelephonyTester = new TelephonyTester(this); } - mIsSubscriptionManagerServiceEnabled = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_using_subscription_manager_service); - if (isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService = SubscriptionManagerService.getInstance(); - } - // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers. mTelephonyComponentFactory = telephonyComponentFactory; mSmsStorageMonitor = mTelephonyComponentFactory.inject(SmsStorageMonitor.class.getName()) diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 3002ae109c..5b2d7456aa 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -65,6 +65,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; import android.telephony.SmsManager; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.Html; import android.text.Spanned; @@ -2877,10 +2878,7 @@ public abstract class SMSDispatcher extends Handler { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected int getSubId() { - if (mPhone.isSubscriptionManagerServiceEnabled()) { - return SubscriptionManagerService.getInstance().getSubId(mPhone.getPhoneId()); - } - return SubscriptionController.getInstance().getSubId(mPhone.getPhoneId()); + return SubscriptionManager.getSubscriptionId(mPhone.getPhoneId()); } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 304c32453f..4262436ab4 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -1339,12 +1339,7 @@ public class PhoneSwitcher extends Handler { // Check if phoneId to subId mapping is changed. for (int i = 0; i < mActiveModemCount; i++) { - int sub; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - sub = mSubscriptionManagerService.getSubId(i); - } else { - sub = mSubscriptionController.getSubId(i); - } + int sub = SubscriptionManager.getSubscriptionId(i); if (SubscriptionManager.isValidSubscriptionId(sub)) hasAnyActiveSubscription = true; @@ -1663,11 +1658,7 @@ public class PhoneSwitcher extends Handler { mPreferredDataPhoneId = phoneId; } - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - mPreferredDataSubId.set(mSubscriptionManagerService.getSubId(mPreferredDataPhoneId)); - } else { - mPreferredDataSubId.set(mSubscriptionController.getSubId(mPreferredDataPhoneId)); - } + mPreferredDataSubId.set(SubscriptionManager.getSubscriptionId(mPreferredDataPhoneId)); } protected void transitionToEmergencyPhone() { @@ -1706,12 +1697,7 @@ public class PhoneSwitcher extends Handler { TelephonyNetworkRequest networkRequest, int phoneId) { if (!SubscriptionManager.isValidPhoneId(phoneId)) return false; - int subId; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - subId = mSubscriptionManagerService.getSubId(phoneId); - } else { - subId = mSubscriptionController.getSubId(phoneId); - } + int subId = SubscriptionManager.getSubscriptionId(phoneId); // In any case, if phone state is inactive, don't apply the network request. if (!isPhoneActive(phoneId) || (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID diff --git a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java index 5e463e9a54..2cdf807006 100644 --- a/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java +++ b/src/java/com/android/internal/telephony/data/TelephonyNetworkFactory.java @@ -29,9 +29,7 @@ import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.metrics.NetworkRequestsStats; -import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -113,11 +111,7 @@ public class TelephonyNetworkFactory extends NetworkFactory { }; private NetworkCapabilities makeNetworkFilterByPhoneId(int phoneId) { - if (mPhone.isSubscriptionManagerServiceEnabled()) { - return makeNetworkFilter(SubscriptionManagerService.getInstance().getSubId(phoneId)); - } else { - return makeNetworkFilter(SubscriptionController.getInstance().getSubId(phoneId)); - } + return makeNetworkFilter(SubscriptionManager.getSubscriptionId(phoneId)); } /** @@ -239,13 +233,7 @@ public class TelephonyNetworkFactory extends NetworkFactory { // watch for phone->subId changes, reapply new filter and let // that flow through to apply/revoke of requests private void onSubIdChange() { - int newSubscriptionId; - if (mPhone.isSubscriptionManagerServiceEnabled()) { - newSubscriptionId = SubscriptionManagerService.getInstance().getSubId( - mPhone.getPhoneId()); - } else { - newSubscriptionId = SubscriptionController.getInstance().getSubId(mPhone.getPhoneId()); - } + int newSubscriptionId = SubscriptionManager.getSubscriptionId(mPhone.getPhoneId()); if (mSubscriptionId != newSubscriptionId) { if (DBG) logl("onSubIdChange " + mSubscriptionId + "->" + newSubscriptionId); mSubscriptionId = newSubscriptionId; diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index b206b861bd..c876920b08 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -116,6 +116,7 @@ import com.android.internal.telephony.metrics.ImsStats; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.metrics.VoiceCallSessionStats; import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.util.NotificationChannelController; import com.android.internal.telephony.util.TelephonyUtils; @@ -2524,15 +2525,30 @@ public class ImsPhone extends ImsPhoneBase { // IMS callbacks are sent back to telephony after SIM state changed. return; } - SubscriptionController subController = SubscriptionController.getInstance(); - String countryIso = getCountryIso(subController, subId); - // Format the number as one more defense to reject garbage values: - // phoneNumber will become null. - phoneNumber = PhoneNumberUtils.formatNumberToE164(phoneNumber, countryIso); - if (phoneNumber == null) { - return; + + if (isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + if (subInfo != null) { + phoneNumber = PhoneNumberUtils.formatNumberToE164(phoneNumber, + subInfo.getCountryIso()); + if (phoneNumber == null) { + return; + } + mSubscriptionManagerService.setNumberFromIms(subId, phoneNumber); + } + } else { + SubscriptionController subController = SubscriptionController.getInstance(); + String countryIso = getCountryIso(subController, subId); + // Format the number as one more defense to reject garbage values: + // phoneNumber will become null. + phoneNumber = PhoneNumberUtils.formatNumberToE164(phoneNumber, countryIso); + if (phoneNumber == null) { + return; + } + subController.setSubscriptionProperty(subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, + phoneNumber); } - subController.setSubscriptionProperty(subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, phoneNumber); } private static String getCountryIso(SubscriptionController subController, int subId) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 1c9ee8877e..68e141e291 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -142,6 +142,8 @@ import com.android.internal.telephony.metrics.CallQualityMetrics; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession; import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.ImsCommand; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.util.TelephonyUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -1649,10 +1651,20 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // Check for changes due to carrier config. maybeConfigureRtpHeaderExtensions(); - if (!SubscriptionController.getInstance().isActiveSubId(subId)) { - loge("updateCarrierConfiguration: skipping notification to ImsService, non" - + "active subId = " + subId); - return; + if (mPhone.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(subId); + if (subInfo == null || !subInfo.isActive()) { + loge("updateCarrierConfiguration: skipping notification to ImsService, non" + + "active subId = " + subId); + return; + } + } else { + if (!SubscriptionController.getInstance().isActiveSubId(subId)) { + loge("updateCarrierConfiguration: skipping notification to ImsService, non" + + "active subId = " + subId); + return; + } } Phone defaultPhone = getPhone().getDefaultPhone(); diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java index cdade427bc..9af66272a8 100644 --- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java @@ -43,6 +43,8 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.telephony.Rlog; import java.util.Arrays; @@ -260,8 +262,14 @@ public class DataCallSessionStats { mDataCallSession.oosAtEnd = getIsOos(); mDataCallSession.ongoing = false; // set if this data call is established for internet on the non-Dds - SubscriptionInfo subInfo = SubscriptionController.getInstance() - .getSubscriptionInfo(mPhone.getSubId()); + SubscriptionInfo subInfo; + if (mPhone.isSubscriptionManagerServiceEnabled()) { + subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfo(mPhone.getSubId()); + } else { + subInfo = SubscriptionController.getInstance() + .getSubscriptionInfo(mPhone.getSubId()); + } if (mPhone.getSubId() != SubscriptionController.getInstance().getDefaultDataSubId() && ((mDataCallSession.apnTypeBitmask & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) @@ -337,12 +345,17 @@ public class DataCallSessionStats { ServiceStateTracker serviceStateTracker = mPhone.getServiceStateTracker(); ServiceState serviceState = serviceStateTracker != null ? serviceStateTracker.getServiceState() : null; - return serviceState != null ? serviceState.getRoaming() : false; + return serviceState != null && serviceState.getRoaming(); } private boolean getIsOpportunistic() { + if (mPhone.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(mPhone.getSubId()); + return subInfo != null && subInfo.isOpportunistic(); + } SubscriptionController subController = SubscriptionController.getInstance(); - return subController != null ? subController.isOpportunistic(mPhone.getSubId()) : false; + return subController != null && subController.isOpportunistic(mPhone.getSubId()); } private boolean getIsOos() { @@ -350,8 +363,7 @@ public class DataCallSessionStats { ServiceState serviceState = serviceStateTracker != null ? serviceStateTracker.getServiceState() : null; return serviceState != null - ? serviceState.getDataRegistrationState() == ServiceState.STATE_OUT_OF_SERVICE - : false; + && serviceState.getDataRegistrationState() == ServiceState.STATE_OUT_OF_SERVICE; } private void logi(String format, Object... args) { diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java index ee4e842233..9391e2db50 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -30,6 +30,8 @@ import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyStatsLog; import com.android.internal.telephony.data.DataStallRecoveryManager; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; /** Generates metrics related to data stall recovery events per phone ID for the pushed atom. */ public class DataStallRecoveryStats { @@ -124,7 +126,12 @@ public class DataStallRecoveryStats { } private static boolean getIsOpportunistic(Phone phone) { + if (phone.isSubscriptionManagerServiceEnabled()) { + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(phone.getSubId()); + return subInfo != null && subInfo.isOpportunistic(); + } SubscriptionController subController = SubscriptionController.getInstance(); - return subController != null ? subController.isOpportunistic(phone.getSubId()) : false; + return subController != null && subController.isOpportunistic(phone.getSubId()); } } diff --git a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java index 4b3e35073e..0b5581515f 100644 --- a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java +++ b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java @@ -18,9 +18,6 @@ package com.android.internal.telephony.metrics; import static android.provider.Telephony.Carriers.CONTENT_URI; import static android.telephony.PhoneNumberUtils.areSamePhoneNumber; -import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER; -import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_IMS; -import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_UICC; import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_A; import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_B; @@ -36,6 +33,7 @@ import android.database.Cursor; import android.net.Uri; import android.provider.Telephony; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.ims.ImsManager; @@ -46,6 +44,8 @@ import com.android.internal.telephony.IccCard; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.uicc.UiccSlot; @@ -172,25 +172,43 @@ public class PerSimStatus { */ @Nullable private static int[] getNumberIds(Phone phone) { - SubscriptionController subscriptionController = SubscriptionController.getInstance(); - if (subscriptionController == null) { - return null; + String countryIso = ""; + String[] numbersFromAllSources; + + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + if (SubscriptionManagerService.getInstance() == null) return null; + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(phone.getSubId()); + if (subInfo != null) { + countryIso = subInfo.getCountryIso(); + } + numbersFromAllSources = new String[]{ + SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), + SubscriptionManager.PHONE_NUMBER_SOURCE_UICC, null, null), + SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), + SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, null, null), + SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), + SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, null, null) + }; + } else { + SubscriptionController subscriptionController = SubscriptionController.getInstance(); + if (subscriptionController == null) { + return null; + } + int subId = phone.getSubId(); + countryIso = Optional.ofNullable(subscriptionController.getSubscriptionInfo(subId)) + .map(SubscriptionInfo::getCountryIso) + .orElse(""); + // numbersFromAllSources[] - phone numbers from each sources: + numbersFromAllSources = new String[]{ + subscriptionController.getPhoneNumber(subId, + SubscriptionManager.PHONE_NUMBER_SOURCE_UICC, null, null), // 0 + subscriptionController.getPhoneNumber(subId, + SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, null, null), // 1 + subscriptionController.getPhoneNumber(subId, + SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, null, null), // 2 + }; } - int subId = phone.getSubId(); - String countryIso = - Optional.ofNullable(subscriptionController.getSubscriptionInfo(subId)) - .map(SubscriptionInfo::getCountryIso) - .orElse(""); - // numbersFromAllSources[] - phone numbers from each sources: - String[] numbersFromAllSources = - new String[] { - subscriptionController.getPhoneNumber( - subId, PHONE_NUMBER_SOURCE_UICC, null, null), // 0 - subscriptionController.getPhoneNumber( - subId, PHONE_NUMBER_SOURCE_CARRIER, null, null), // 1 - subscriptionController.getPhoneNumber( - subId, PHONE_NUMBER_SOURCE_IMS, null, null), // 2 - }; int[] numberIds = new int[numbersFromAllSources.length]; // default value 0 for (int i = 0, idForNextUniqueNumber = 1; i < numberIds.length; i++) { if (TextUtils.isEmpty(numbersFromAllSources[i])) { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index c001fc4f3f..09171aca83 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -22,12 +22,14 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.app.AppOpsManager; +import android.app.PendingIntent; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -59,11 +61,14 @@ import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.LocalLog; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CarrierResolver; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; import com.android.internal.telephony.MultiSimSettingController; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.telephony.euicc.EuiccController; @@ -689,6 +694,16 @@ public class SubscriptionManagerService extends ISub.Stub { mSubscriptionDatabaseManager.setEnabledMobileDataPolicies(subId, enabledMobileDataPolicies); } + /** + * Set the phone number retrieved from IMS. + * + * @param subId Subscription id. + * @param numberFromIms The phone number retrieved from IMS. + */ + public void setNumberFromIms(int subId, @NonNull String numberFromIms) { + mSubscriptionDatabaseManager.setNumberFromIms(subId, numberFromIms); + } + /** * Mark all subscriptions on this SIM slot index inactive. * @@ -890,7 +905,7 @@ public class SubscriptionManagerService extends ISub.Stub { Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, "getAllSubInfoList")) { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " - + "carrier privilege to call getAllSubInfoList"); + + "carrier privilege"); } final long identity = Binder.clearCallingIdentity(); @@ -921,8 +936,29 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override @Nullable + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) public SubscriptionInfo getActiveSubscriptionInfo(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { + if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, + callingFeatureId, "getActiveSubscriptionInfo")) { + throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + + "carrier privilege"); + } + + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + throw new IllegalArgumentException("Invalid sub id " + subId); + } + + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + if (subInfo.isActive()) { + return conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), callingPackage, + callingFeatureId, "getActiveSubscriptionInfo"); + } return null; } @@ -966,7 +1002,9 @@ public class SubscriptionManagerService extends ISub.Stub { if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "getActiveSubscriptionInfoForSimSlotIndex")) { - throw new SecurityException("Requires READ_PHONE_STATE permission."); + throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + + "carrier privilege"); + } if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { @@ -1014,7 +1052,7 @@ public class SubscriptionManagerService extends ISub.Stub { Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, "getAllSubInfoList")) { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " - + "carrier privilege to call getAllSubInfoList"); + + "carrier privilege"); } final long identity = Binder.clearCallingIdentity(); @@ -1198,17 +1236,88 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Set display name by simInfo index with name source. + * Set display name of a subscription. * - * @param displayName the display name of SIM card - * @param subId the unique SubscriptionInfo index in database - * @param nameSource 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT + * @param displayName The display name of SIM card. + * @param subId The subscription id. + * @param nameSource The display name source. * * @return the number of records updated */ @Override - public int setDisplayNameUsingSrc(@NonNull String displayName, int subId, int nameSource) { - return 0; + public int setDisplayNameUsingSrc(@NonNull String displayName, int subId, + @SimDisplayNameSource int nameSource) { + enforcePermissions("setDisplayNameUsingSrc", Manifest.permission.MODIFY_PHONE_STATE); + + final long identity = Binder.clearCallingIdentity(); + try { + if (displayName == null) { + throw new IllegalArgumentException("displayName is null"); + } + + if (nameSource < SubscriptionManager.NAME_SOURCE_CARRIER_ID + || nameSource > SubscriptionManager.NAME_SOURCE_SIM_PNN) { + throw new IllegalArgumentException("illegal name source " + nameSource); + } + + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + + if (subInfo == null) { + throw new IllegalArgumentException("Cannot find subscription info with sub id " + + subId); + } + + if (getNameSourcePriority(subInfo.getDisplayNameSource()) + > getNameSourcePriority(nameSource) + || (getNameSourcePriority(subInfo.getDisplayNameSource()) + == getNameSourcePriority(nameSource)) + && (TextUtils.equals(displayName, subInfo.getDisplayName()))) { + log("No need to update the display name. nameSource=" + + SubscriptionManager.displayNameSourceToString(nameSource) + + ", existing name=" + subInfo.getDisplayName() + ", source=" + + SubscriptionManager.displayNameSourceToString( + subInfo.getDisplayNameSource())); + return 0; + } + + String nameToSet; + if (TextUtils.isEmpty(displayName) || displayName.trim().length() == 0) { + nameToSet = mTelephonyManager.getSimOperatorName(subId); + if (TextUtils.isEmpty(nameToSet)) { + if (nameSource == SubscriptionManager.NAME_SOURCE_USER_INPUT + && SubscriptionManager.isValidSlotIndex(getSlotIndex(subId))) { + Resources r = Resources.getSystem(); + nameToSet = r.getString(R.string.default_card_name, + (getSlotIndex(subId) + 1)); + } else { + nameToSet = mContext.getString(SubscriptionManager.DEFAULT_NAME_RES); + } + } + } else { + nameToSet = displayName; + } + + mSubscriptionDatabaseManager.setDisplayName(subId, nameToSet); + mSubscriptionDatabaseManager.setDisplayNameSource(subId, nameSource); + + // Update the nickname on the eUICC chip if it's an embedded subscription. + SubscriptionInfo sub = getSubscriptionInfo(subId); + if (sub != null && sub.isEmbedded()) { + int cardId = sub.getCardId(); + log("Updating embedded sub nickname on cardId: " + cardId); + mEuiccManager.updateSubscriptionNickname(subId, displayName, + // This PendingIntent simply fulfills the requirement to pass in a callback; + // we don't care about the result (hence 0 requestCode and no action + // specified on the intent). + PendingIntent.getService(mContext, 0 /* requestCode */, new Intent(), + PendingIntent.FLAG_IMMUTABLE /* flags */)); + } + + return 1; + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1699,7 +1808,8 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable String callingFeatureId) { if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "isActiveSubId")) { - throw new SecurityException("Requires READ_PHONE_STATE permission."); + throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + + "carrier privilege"); } final long identity = Binder.clearCallingIdentity(); try { @@ -1737,10 +1847,88 @@ public class SubscriptionManagerService extends ISub.Stub { return 0; } + /** + * Returns the phone number for the given {@code subscriptionId} and {@code source}, + * or an empty string if not available. + * + *

General apps that need to know the phone number should use {@link #getPhoneNumber(int)} + * instead. This API may be suitable specific apps that needs to know the phone number from + * a specific source. For example, a carrier app needs to know exactly what's on + * {@link #PHONE_NUMBER_SOURCE_UICC UICC} and decide if the previously set phone number + * of source {@link #PHONE_NUMBER_SOURCE_CARRIER carrier} should be updated. + * + *

The API provides no guarantees of what format the number is in: the format can vary + * depending on the {@code source} and the network etc. Programmatic parsing should be done + * cautiously, for example, after formatting the number to a consistent format with + * {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}. + * + *

Note the assumption is that one subscription (which usually means one SIM) has + * only one phone number. The multiple sources backup each other so hopefully at least one + * is availavle. For example, for a carrier that doesn't typically set phone numbers + * on {@link SubscriptionManager#PHONE_NUMBER_SOURCE_UICC UICC}, the source + * {@link SubscriptionManager#PHONE_NUMBER_SOURCE_IMS IMS} may provide one. Or, a carrier may + * decide to provide the phone number via source + * {@link SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER carrier} if neither source UICC nor + * IMS is available. + * + *

The availability and correctness of the phone number depends on the underlying source + * and the network etc. Additional verification is needed to use this number for + * security-related or other sensitive scenarios. + * + * @param subId The subscription ID. + * @param source The source of the phone number. + * + * @return The phone number, or an empty string if not available. + * + * @throws IllegalArgumentException if {@code source} or {@code subId} is invalid. + * @throws SecurityException if the caller doesn't have permissions required. + * + * @see SubscriptionManager#PHONE_NUMBER_SOURCE_UICC + * @see SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER + * @see SubscriptionManager#PHONE_NUMBER_SOURCE_IMS + */ @Override - public String getPhoneNumber(int subId, int source, + @NonNull + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_NUMBERS, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) + public String getPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String callingPackage, @Nullable String callingFeatureId) { - return null; + TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( + mContext, subId, Binder.getCallingUid(), "getPhoneNumber", + Manifest.permission.READ_PHONE_NUMBERS, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + final long identity = Binder.clearCallingIdentity(); + + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + + if (subInfo == null) { + throw new IllegalArgumentException("Invalid sub id " + subId); + } + + try { + switch(source) { + case SubscriptionManager.PHONE_NUMBER_SOURCE_UICC: + Phone phone = PhoneFactory.getPhone(getPhoneId(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); + } } @Override diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java index e039c55453..041b5dde62 100644 --- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java +++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java @@ -33,7 +33,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.MccTable; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; import com.android.internal.util.BitwiseInputStream; @@ -821,7 +820,7 @@ public class RuimRecords extends IccRecords { // TODO: The below is hacky since the SubscriptionController may not be ready at this time. if (!TextUtils.isEmpty(mMdn)) { int phoneId = mParentApp.getUiccProfile().getPhoneId(); - int subId = SubscriptionController.getInstance().getSubId(phoneId); + int subId = SubscriptionManager.getSubscriptionId(phoneId); if (SubscriptionManager.isValidSubscriptionId(subId)) { SubscriptionManager.from(mContext).setDisplayNumber(mMdn, subId); } else { diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index b8fb2a6f2c..49292b04b4 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -30,6 +30,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.PhoneNumberUtils; import android.telephony.SmsMessage; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -38,7 +39,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.MccTable; import com.android.internal.telephony.SmsConstants; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.gsm.SimTlv; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; import com.android.telephony.Rlog; @@ -1079,7 +1079,7 @@ public class SIMRecords extends IccRecords { mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); if (ar.exception != null && configManager != null) { PersistableBundle b = configManager.getConfigForSubId( - SubscriptionController.getInstance().getSubId( + SubscriptionManager.getSubscriptionId( mParentApp.getPhoneId())); if (b != null && b.getBoolean( CarrierConfigManager.KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL)) { diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index 154e59fc33..d882e49d01 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -35,6 +35,7 @@ import android.os.AsyncResult; import android.os.Binder; import android.os.Handler; import android.os.Message; +import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; @@ -64,6 +65,8 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyStatsLog; import com.android.internal.telephony.cat.CatService; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState; import com.android.internal.telephony.uicc.IccCardStatus.CardState; @@ -432,8 +435,7 @@ public class UiccProfile extends IccCard { * if an override is provided. */ private void handleCarrierNameOverride() { - SubscriptionController subCon = SubscriptionController.getInstance(); - final int subId = subCon.getSubId(mPhoneId); + final int subId = SubscriptionManager.getSubscriptionId(mPhoneId); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { loge("subId not valid for Phone " + mPhoneId); return; @@ -482,7 +484,7 @@ public class UiccProfile extends IccCard { mOperatorBrandOverrideRegistrants.notifyRegistrants(); } - updateCarrierNameForSubscription(subCon, subId, nameSource); + updateCarrierNameForSubscription(subId, nameSource); } /** @@ -497,8 +499,7 @@ public class UiccProfile extends IccCard { * MCC table */ private void handleSimCountryIsoOverride() { - SubscriptionController subCon = SubscriptionController.getInstance(); - final int subId = subCon.getSubId(mPhoneId); + final int subId = SubscriptionManager.getSubscriptionId(mPhoneId); if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { loge("subId not valid for Phone " + mPhoneId); return; @@ -513,17 +514,20 @@ public class UiccProfile extends IccCard { PersistableBundle config = configLoader.getConfigForSubId(subId); String iso = config.getString(CarrierConfigManager.KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING); - if (!TextUtils.isEmpty(iso) && - !iso.equals(mTelephonyManager.getSimCountryIsoForPhone(mPhoneId))) { + if (!TextUtils.isEmpty(iso) + && !iso.equals(TelephonyManager.getSimCountryIsoForPhone(mPhoneId))) { mTelephonyManager.setSimCountryIsoForPhone(mPhoneId, iso); - subCon.setCountryIso(iso, subId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().setCountryIso(subId, iso); + } else { + SubscriptionController.getInstance().setCountryIso(iso, subId); + } } } - private void updateCarrierNameForSubscription(SubscriptionController subCon, int subId, - int nameSource) { + private void updateCarrierNameForSubscription(int subId, int nameSource) { /* update display name with carrier override */ - SubscriptionInfo subInfo = subCon.getActiveSubscriptionInfo( + SubscriptionInfo subInfo = SubscriptionController.getInstance().getActiveSubscriptionInfo( subId, mContext.getOpPackageName(), mContext.getAttributionTag()); if (subInfo == null) { @@ -535,7 +539,13 @@ public class UiccProfile extends IccCard { if (!TextUtils.isEmpty(newCarrierName) && !newCarrierName.equals(oldSubName)) { log("sim name[" + mPhoneId + "] = " + newCarrierName); - subCon.setDisplayNameUsingSrc(newCarrierName, subId, nameSource); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().setDisplayNameUsingSrc( + newCarrierName, subId, nameSource); + } else { + SubscriptionController.getInstance().setDisplayNameUsingSrc( + newCarrierName, subId, nameSource); + } } } @@ -1696,9 +1706,36 @@ public class UiccProfile extends IccCard { if (TextUtils.isEmpty(iccId)) { return false; } - if (!SubscriptionController.getInstance().checkPhoneIdAndIccIdMatch(getPhoneId(), iccId)) { - loge("iccId doesn't match current active subId."); - return false; + + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + int subId = SubscriptionManager.getSubscriptionId(getPhoneId()); + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(subId); + if (subInfo == null) { + loge("setOperatorBrandOverride: Cannot find subscription info for sub " + subId); + return false; + } + + List subInfos = new ArrayList<>(); + subInfos.add(subInfo.toSubscriptionInfo()); + String groupUuid = subInfo.getGroupUuid(); + if (!TextUtils.isEmpty(groupUuid)) { + subInfos.addAll(SubscriptionManagerService.getInstance() + .getSubscriptionsInGroup(ParcelUuid.fromString(groupUuid), + mContext.getOpPackageName(), mContext.getFeatureId())); + } + + if (subInfos.stream().noneMatch(info -> TextUtils.equals(IccUtils.stripTrailingFs( + info.getIccId()), IccUtils.stripTrailingFs(iccId)))) { + loge("iccId doesn't match current active subId."); + return false; + } + } else { + if (!SubscriptionController.getInstance().checkPhoneIdAndIccIdMatch( + getPhoneId(), iccId)) { + loge("iccId doesn't match current active subId."); + return false; + } } SharedPreferences.Editor spEditor = diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index 2907346c0b..93d584bb62 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -83,6 +83,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Mocked classes private SubscriptionController mSubControllerMock; + private ISub mMockedIsub; private Phone mPhoneMock1; private Phone mPhoneMock2; private DataSettingsManager mDataSettingsManagerMock1; @@ -131,6 +132,12 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mDataSettingsManagerMock1 = mock(DataSettingsManager.class); mDataSettingsManagerMock2 = mock(DataSettingsManager.class); mMockCi = mock(CommandsInterface.class); + mMockedIsub = mock(ISub.class); + + doReturn(mMockedIsub).when(mIBinder).queryLocalInterface(anyString()); + doReturn(mPhone).when(mPhone).getImsPhone(); + mServiceManagerMockedServices.put("isub", mIBinder); + // Default configuration: // DSDS device. // Sub 1 is the default sub. @@ -138,8 +145,11 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(DUAL_SIM).when(mTelephonyManager).getPhoneCount(); doReturn(DUAL_SIM).when(mTelephonyManager).getActiveModemCount(); doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(1).when(mMockedIsub).getDefaultDataSubId(); doReturn(1).when(mSubControllerMock).getDefaultVoiceSubId(); + doReturn(1).when(mMockedIsub).getDefaultVoiceSubId(); doReturn(1).when(mSubControllerMock).getDefaultSmsSubId(); + doReturn(1).when(mMockedIsub).getDefaultSmsSubId(); doReturn(true).when(mSubControllerMock).isActiveSubId(1); doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(0).build()) .when(mSubControllerMock).getSubscriptionInfo(1); @@ -147,7 +157,9 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(1).build()) .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(0).when(mSubControllerMock).getPhoneId(1); + doReturn(0).when(mMockedIsub).getPhoneId(1); doReturn(1).when(mSubControllerMock).getPhoneId(2); + doReturn(1).when(mMockedIsub).getPhoneId(2); doReturn(true).when(mSubControllerMock).isOpportunistic(5); doReturn(new SubscriptionInfo.Builder().setId(5).setSimSlotIndex(1).setOpportunistic(true) .build()).when(mSubControllerMock).getSubscriptionInfo(5); @@ -202,6 +214,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); + doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(2); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId(); List infoList = Arrays.asList(mSubInfo1); doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), @@ -255,7 +268,9 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(1); + doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(1); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); + doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(2); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock1).getSubId(); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId(); List infoList = new ArrayList<>(); @@ -318,7 +333,9 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(0).build()) .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(0).when(mSubControllerMock).getPhoneId(2); + doReturn(0).when(mMockedIsub).getPhoneId(2); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(1); + doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(1); doReturn(2).when(mPhoneMock1).getSubId(); infoList = Arrays.asList(mSubInfo2); doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), @@ -344,6 +361,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); + doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(1); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId(); List infoList = Arrays.asList(mSubInfo1); doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), @@ -367,6 +385,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(1).build()) .when(mSubControllerMock).getSubscriptionInfo(2); doReturn(1).when(mSubControllerMock).getPhoneId(2); + doReturn(1).when(mMockedIsub).getPhoneId(2); doReturn(2).when(mPhoneMock2).getSubId(); infoList = Arrays.asList(mSubInfo1, mSubInfo2); doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), @@ -393,6 +412,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new SubscriptionInfo.Builder().setId(3).setSimSlotIndex(1).build()) .when(mSubControllerMock).getSubscriptionInfo(3); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); + doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(2); doReturn(1).when(mSubControllerMock).getPhoneId(3); doReturn(3).when(mPhoneMock2).getSubId(); infoList = Arrays.asList(mSubInfo1, mSubInfo3); @@ -413,7 +433,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Test @SmallTest - public void testSimpleDsds() { + public void testSimpleDsds() throws Exception { doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); // After initialization, sub 2 should have mobile data off. @@ -431,6 +451,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Changing default data to sub 2 should trigger disabling data on sub 1. doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(2).when(mMockedIsub).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); verify(mDataSettingsManagerMock1).setDataEnabled( @@ -467,9 +488,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Test @SmallTest - public void testSimpleDsdsFirstBoot() { + public void testSimpleDsdsFirstBoot() throws Exception { // at first boot default is not set doReturn(-1).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(-1).when(mMockedIsub).getDefaultDataSubId(); doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); @@ -494,6 +516,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Setting default data should not trigger any more setDataEnabled(). doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(2).when(mMockedIsub).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); verify(mDataSettingsManagerMock1, times(1)) @@ -504,9 +527,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Test @SmallTest - public void testSimpleDsdsInSuW() { + public void testSimpleDsdsInSuW() throws Exception { // at first boot default is not set doReturn(-1).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(-1).when(mMockedIsub).getDefaultDataSubId(); doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); @@ -533,7 +557,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Test @SmallTest - public void testDsdsGrouping() { + public void testDsdsGrouping() throws Exception { doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); doReturn(false).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); @@ -570,6 +594,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Making sub 1 default data sub should result in disabling data on sub 2, 3, 4. doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(1).when(mMockedIsub).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); verify(mDataSettingsManagerMock2).setDataEnabled( @@ -587,8 +612,11 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Default data and default sms should become subscription 3. clearInvocations(mSubControllerMock); doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(2).when(mMockedIsub).getDefaultDataSubId(); doReturn(2).when(mSubControllerMock).getDefaultSmsSubId(); + doReturn(2).when(mMockedIsub).getDefaultSmsSubId(); doReturn(1).when(mSubControllerMock).getDefaultVoiceSubId(); + doReturn(1).when(mMockedIsub).getDefaultVoiceSubId(); List infoList = Arrays.asList(mSubInfo1, mSubInfo3); doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), nullable(String.class)); @@ -631,6 +659,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { clearInvocations(mDataSettingsManagerMock1); clearInvocations(mDataSettingsManagerMock2); doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(2).when(mMockedIsub).getDefaultDataSubId(); // Toggle data on sub 1 or sub 2. Nothing should happen as they are independent. mMultiSimSettingControllerUT.notifyUserDataEnabled(1, false); mMultiSimSettingControllerUT.notifyUserDataEnabled(1, true); @@ -723,6 +752,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) .when(mSubControllerMock).getSubscriptionInfo(1); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(1); + doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(1); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock1).getSubId(); List infoList = Arrays.asList(mSubInfo2); doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), @@ -750,6 +780,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @SmallTest public void testGroupedPrimarySubscriptions() throws Exception { doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(1).when(mMockedIsub).getDefaultDataSubId(); doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(false).when(mPhoneMock2).isUserDataEnabled(); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 1, true); @@ -809,7 +840,9 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new SubscriptionInfo.Builder().setId(3).setSimSlotIndex(1).build()) .when(mSubControllerMock).getSubscriptionInfo(3); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); + doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(2); doReturn(1).when(mSubControllerMock).getPhoneId(3); + doReturn(1).when(mMockedIsub).getPhoneId(3); doReturn(3).when(mPhoneMock2).getSubId(); List infoList = Arrays.asList(mSubInfo1, mSubInfo3); doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), @@ -843,6 +876,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { .when(mSubControllerMock).getSubscriptionInfo(3); doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); doReturn(1).when(mSubControllerMock).getPhoneId(3); + doReturn(1).when(mMockedIsub).getPhoneId(3); doReturn(3).when(mPhoneMock2).getSubId(); List infoList = Arrays.asList(mSubInfo1, mSubInfo3); doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), @@ -853,6 +887,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Sub 3 and sub 2's mobile data are enabled, and sub 3 is the default data sub. doReturn(3).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(3).when(mMockedIsub).getDefaultDataSubId(); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 1, false); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 2, true); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 3, true); @@ -896,6 +931,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Still notify carrier config without specifying subId2, but this time subController // and CarrierConfigManager have subId 2 active and ready. doReturn(2).when(mSubControllerMock).getSubId(1); + doReturn(2).when(mMockedIsub).getSubId(1); CarrierConfigManager cm = (CarrierConfigManager) mContext.getSystemService( mContext.CARRIER_CONFIG_SERVICE); doReturn(new PersistableBundle()).when(cm).getConfigForSubId(2); @@ -948,6 +984,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @SmallTest public void testVoiceDataSmsAutoFallback() throws Exception { doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(1).when(mMockedIsub).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0,1); mMultiSimSettingControllerUT.notifyCarrierConfigChanged(2, 3); @@ -989,6 +1026,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Test public void onSubscriptionGroupChanged_allActiveSubArePartOfGroup() throws Exception { doReturn(3).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(3).when(mMockedIsub).getDefaultDataSubId(); // Create subscription grouping of subs 1 and 2. replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(1); 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 45a312bfe5..bcd6160c67 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -37,6 +37,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; @@ -73,6 +74,7 @@ import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.GsmCdmaCall; import com.android.internal.telephony.ISetOpportunisticDataCallback; +import com.android.internal.telephony.ISub; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; @@ -121,6 +123,7 @@ public class PhoneSwitcherTest extends TelephonyTest { private ISetOpportunisticDataCallback mSetOpptDataCallback2; PhoneSwitcher.ImsRegTechProvider mMockImsRegTechProvider; private SubscriptionInfo mSubscriptionInfo; + private ISub mMockedIsub; private PhoneSwitcher mPhoneSwitcherUT; private SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener; @@ -156,6 +159,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mSetOpptDataCallback2 = mock(ISetOpportunisticDataCallback.class); mMockImsRegTechProvider = mock(PhoneSwitcher.ImsRegTechProvider.class); mSubscriptionInfo = mock(SubscriptionInfo.class); + mMockedIsub = mock(ISub.class); PhoneCapability phoneCapability = new PhoneCapability(1, 1, null, false, new int[0]); doReturn(phoneCapability).when(mPhoneConfigurationManager).getCurrentPhoneCapability(); @@ -172,6 +176,11 @@ public class PhoneSwitcherTest extends TelephonyTest { replaceInstance(Phone.class, "mCi", mPhone, mCommandsInterface0); replaceInstance(Phone.class, "mCi", mPhone2, mCommandsInterface1); + + doReturn(1).when(mMockedIsub).getDefaultDataSubId(); + doReturn(mMockedIsub).when(mIBinder).queryLocalInterface(anyString()); + doReturn(mPhone).when(mPhone).getImsPhone(); + mServiceManagerMockedServices.put("isub", mIBinder); } @After @@ -1977,10 +1986,13 @@ public class PhoneSwitcherTest extends TelephonyTest { * Capture mNetworkProviderMessenger so that testing can request or release * network requests on PhoneSwitcher. */ - private void initializeSubControllerMock() { + private void initializeSubControllerMock() throws Exception { doReturn(mDefaultDataSub).when(mSubscriptionController).getDefaultDataSubId(); + doReturn(mDefaultDataSub).when(mMockedIsub).getDefaultDataSubId(); doReturn(0).when(mSubscriptionController).getPhoneId(1); + doReturn(0).when(mMockedIsub).getPhoneId(1); doReturn(1).when(mSubscriptionController).getPhoneId(2); + doReturn(1).when(mMockedIsub).getPhoneId(2); doAnswer(invocation -> { int phoneId = (int) invocation.getArguments()[0]; if (phoneId == SubscriptionManager.INVALID_PHONE_INDEX) { @@ -1992,6 +2004,17 @@ public class PhoneSwitcherTest extends TelephonyTest { } }).when(mSubscriptionController).getSubId(anyInt()); + doAnswer(invocation -> { + int phoneId = (int) invocation.getArguments()[0]; + if (phoneId == SubscriptionManager.INVALID_PHONE_INDEX) { + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) { + return mSlotIndexToSubId[0][0]; + } else { + return mSlotIndexToSubId[phoneId][0]; + } + }).when(mMockedIsub).getSubId(anyInt()); + doAnswer(invocation -> { int subId = (int) invocation.getArguments()[0]; @@ -2006,9 +2029,10 @@ public class PhoneSwitcherTest extends TelephonyTest { .getActiveSubIdList(true); } - private void setDefaultDataSubId(int defaultDataSub) { + private void setDefaultDataSubId(int defaultDataSub) throws Exception { mDefaultDataSub = defaultDataSub; doReturn(mDefaultDataSub).when(mSubscriptionController).getDefaultDataSubId(); + doReturn(mDefaultDataSub).when(mMockedIsub).getDefaultDataSubId(); sendDefaultDataSubChanged(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java index 86e508917e..b7e6b59540 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java @@ -22,6 +22,7 @@ import static com.android.internal.telephony.NetworkFactory.CMD_REQUEST_NETWORK; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -41,6 +42,7 @@ import android.util.ArraySet; import androidx.test.filters.FlakyTest; +import com.android.internal.telephony.ISub; import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.TelephonyTest; import com.android.telephony.Rlog; @@ -63,6 +65,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { // Mocked classes PhoneSwitcher mPhoneSwitcher; private RadioConfig mMockRadioConfig; + private ISub mMockedIsub; private String mTestName = ""; @@ -144,8 +147,13 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mPhoneSwitcher = mock(PhoneSwitcher.class); mMockRadioConfig = mock(RadioConfig.class); + mMockedIsub = mock(ISub.class); replaceInstance(RadioConfig.class, "sRadioConfig", null, mMockRadioConfig); + doReturn(mMockedIsub).when(mIBinder).queryLocalInterface(anyString()); + doReturn(mPhone).when(mPhone).getImsPhone(); + mServiceManagerMockedServices.put("isub", mIBinder); + mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes, new String[]{"wifi,1,1,1,-1,true", "mobile,0,0,0,-1,true", "mobile_mms,2,0,2,60000,true", "mobile_supl,3,0,2,60000,true", @@ -231,6 +239,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { doReturn(false).when(mPhoneSwitcher).shouldApplyNetworkRequest(any(), anyInt()); doReturn(subId).when(mSubscriptionController).getSubId(phoneId); + doReturn(subId).when(mMockedIsub).getSubId(phoneId); // fake onSubscriptionChangedListener being triggered. mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); @@ -304,6 +313,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { createMockedTelephonyComponents(); doReturn(subId).when(mSubscriptionController).getSubId(phoneId); + doReturn(subId).when(mMockedIsub).getSubId(phoneId); mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); processAllMessages(); @@ -318,6 +328,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { assertEquals(1, mNetworkRequestList.size()); doReturn(altSubId).when(mSubscriptionController).getSubId(altPhoneId); + doReturn(altSubId).when(mMockedIsub).getSubId(altPhoneId); processAllMessages(); assertEquals(1, mNetworkRequestList.size()); @@ -333,6 +344,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { assertEquals(1, mNetworkRequestList.size()); doReturn(unusedSubId).when(mSubscriptionController).getSubId(phoneId); + doReturn(unusedSubId).when(mMockedIsub).getSubId(phoneId); mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); processAllMessages(); @@ -343,6 +355,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { assertEquals(0, mNetworkRequestList.size()); doReturn(subId).when(mSubscriptionController).getSubId(phoneId); + doReturn(subId).when(mMockedIsub).getSubId(phoneId); mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); processAllMessages(); 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 c99f84c388..e59aad0823 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -177,6 +177,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { */ private int insertSubscription(@NonNull SubscriptionInfoInternal subInfo) { try { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID).build(); @@ -205,6 +206,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { method = WatchedMapClass.getDeclaredMethod("put", cArgs); method.setAccessible(true); method.invoke(map, subInfo.getSimSlotIndex(), subId); + mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); return subId; } catch (Exception e) { fail("Failed to insert subscription. e=" + e); @@ -492,12 +494,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetDefaultVoiceSubId() throws Exception { - // Grant MODIFY_PHONE_STATE permission for insertion. - mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); - // Remove MODIFY_PHONE_STATE - mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); // Should fail without MODIFY_PHONE_STATE @@ -537,12 +535,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetDefaultDataSubId() throws Exception { doReturn(false).when(mTelephonyManager).isVoiceCapable(); - // Grant MODIFY_PHONE_STATE permission for insertion. - mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); - // Remove MODIFY_PHONE_STATE - mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); // Should fail without MODIFY_PHONE_STATE @@ -581,12 +575,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetDefaultSmsSubId() throws Exception { - // Grant MODIFY_PHONE_STATE permission for insertion. - mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); - // Remove MODIFY_PHONE_STATE - mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); // Should fail without MODIFY_PHONE_STATE assertThrows(SecurityException.class, @@ -614,13 +604,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testIsActiveSubId() { - // Grant MODIFY_PHONE_STATE permission for insertion. - mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO2) .setSimSlotIndex(SubscriptionManager.INVALID_SIM_SLOT_INDEX).build()); - // Remove MODIFY_PHONE_STATE - mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); // Should fail without READ_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT @@ -671,12 +657,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testGetActiveSubscriptionInfoForSimSlotIndex() { - // Grant MODIFY_PHONE_STATE permission for insertion. - mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); - // Remove MODIFY_PHONE_STATE - mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); // Should fail without READ_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT @@ -763,4 +745,56 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfo.isRemovableEmbedded()).isFalse(); assertThat(subInfo.getNativeAccessRules()).isEqualTo(FAKE_NATIVE_ACCESS_RULES2); } + + @Test + public void testGetActiveSubscriptionInfo() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without READ_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getActiveSubscriptionInfo(1, CALLING_PACKAGE, CALLING_FEATURE)); + + // Grant READ_PHONE_STATE permission for insertion. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); + SubscriptionInfo subInfo = mSubscriptionManagerServiceUT + .getActiveSubscriptionInfoForSimSlotIndex(0, CALLING_PACKAGE, + CALLING_FEATURE); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getSubscriptionId()).isEqualTo(1); + assertThat(subInfo.getIccId()).isEmpty(); + assertThat(subInfo.getNumber()).isEmpty(); + + // Grant carrier privilege for sub 1 + setCarrierPrivilegesForSubId(true, 1); + subInfo = mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForSimSlotIndex( + 0, CALLING_PACKAGE, CALLING_FEATURE); + assertThat(subInfo).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); + } + + @Test + public void testSetDisplayNameUsingSrc() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setDisplayNameUsingSrc(FAKE_CARRIER_NAME2, 1, + SubscriptionManager.NAME_SOURCE_CARRIER_ID)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // Carrier ID name source should have lower priority. Should not be able to update the + // display name. + assertThat(mSubscriptionManagerServiceUT.setDisplayNameUsingSrc(FAKE_CARRIER_NAME2, + 1, SubscriptionManager.NAME_SOURCE_CARRIER_ID)).isEqualTo(0); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1).getDisplayName()) + .isEqualTo(FAKE_CARRIER_NAME1); + + // User input display name should have highest priority. + assertThat(mSubscriptionManagerServiceUT.setDisplayNameUsingSrc(FAKE_CARRIER_NAME2, + 1, SubscriptionManager.NAME_SOURCE_USER_INPUT)).isEqualTo(1); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1).getDisplayName()) + .isEqualTo(FAKE_CARRIER_NAME2); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java index 856639a7be..e139e958e3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java @@ -46,6 +46,7 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; +import com.android.internal.telephony.ISub; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.cat.CatService; @@ -78,6 +79,7 @@ public class UiccProfileTest extends TelephonyTest { private Handler mMockedHandler; private UiccCard mUiccCard; private SubscriptionInfo mSubscriptionInfo; + private ISub mMockedIsub; private IccCardApplicationStatus composeUiccApplicationStatus( IccCardApplicationStatus.AppType appType, @@ -99,6 +101,13 @@ public class UiccProfileTest extends TelephonyTest { mMockedHandler = mock(Handler.class); mUiccCard = mock(UiccCard.class); mSubscriptionInfo = mock(SubscriptionInfo.class); + mMockedIsub = mock(ISub.class); + + doReturn(mMockedIsub).when(mIBinder).queryLocalInterface(anyString()); + mServiceManagerMockedServices.put("isub", mIBinder); + + doReturn(1).when(mMockedIsub).getSubId(0); + /* initially there are no application available, but the array should not be empty. */ IccCardApplicationStatus umtsApp = composeUiccApplicationStatus( IccCardApplicationStatus.AppType.APPTYPE_USIM, -- GitLab From c61d2f7c37c84e37b36a1f3f79a7a2687637234a Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 3 Dec 2022 01:23:53 -0800 Subject: [PATCH 233/656] Added getActiveSubInfoCount Added getActiveSubInfoCount and migrated more modules to use SubscrtipionManagerService. Test: atest FrameworksTelephonyTests Bug: 239607619 Change-Id: Iee6801573e4ad4ea08da7d725dd0c0292b7d96d2 --- .../SubscriptionManagerService.java | 92 ++++++++++++++++++- .../SubscriptionManagerServiceTest.java | 15 +++ 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 09171aca83..35df346661 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -943,6 +943,10 @@ public class SubscriptionManagerService extends ISub.Stub { }) public SubscriptionInfo getActiveSubscriptionInfo(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "getActiveSubscriptionInfo")) { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " @@ -975,6 +979,10 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable public SubscriptionInfo getActiveSubscriptionInfoForIccId(@NonNull String iccId, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + return null; } @@ -996,6 +1004,10 @@ public class SubscriptionManagerService extends ISub.Stub { }) public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + int subId = mSlotIndexToSubId.getOrDefault(slotIndex, SubscriptionManager.INVALID_SUBSCRIPTION_ID); @@ -1078,12 +1090,34 @@ public class SubscriptionManagerService extends ISub.Stub { * * @param callingPackage The package making the call * @param callingFeatureId The feature in the package - * @return the number of active subscriptions + * + * @return the number of active subscriptions. */ @Override + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) public int getActiveSubInfoCount(@NonNull String callingPackage, @Nullable String callingFeatureId) { - return 0; + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + + if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, + Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, + "getAllSubInfoList")) { + throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + + "carrier privilege"); + } + + final long token = Binder.clearCallingIdentity(); + try { + return getActiveSubIdList(false).length; + } finally { + Binder.restoreCallingIdentity(token); + } } /** @@ -1139,6 +1173,10 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public List getAccessibleSubscriptionInfoList( @NonNull String callingPackage) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + return null; } @@ -1371,6 +1409,11 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int setOpportunistic(boolean opportunistic, int subId, @NonNull String callingPackage) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + + return 0; } @@ -1392,6 +1435,11 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public ParcelUuid createSubscriptionGroup(int[] subIdList, @NonNull String callingPackage) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + + return null; } @@ -1424,17 +1472,29 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull public List getOpportunisticSubscriptions(@NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + return Collections.emptyList(); } @Override public void removeSubscriptionsFromGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + } @Override public void addSubscriptionsIntoGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + } /** @@ -1468,6 +1528,10 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull public List getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + // If the calling app neither has carrier privileges nor READ_PHONE_STATE and access to // device identifiers, it will throw a SecurityException. if (CompatChanges.isChangeEnabled(REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID, @@ -1766,6 +1830,10 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public String getSubscriptionProperty(int subId, @NonNull String propKey, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + return null; } @@ -1806,6 +1874,10 @@ public class SubscriptionManagerService extends ISub.Stub { }) public boolean isActiveSubId(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "isActiveSubId")) { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " @@ -1896,6 +1968,10 @@ public class SubscriptionManagerService extends ISub.Stub { }) public String getPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( mContext, subId, Binder.getCallingUid(), "getPhoneNumber", Manifest.permission.READ_PHONE_NUMBERS, @@ -1934,12 +2010,20 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public String getPhoneNumberFromFirstAvailableSource(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + return null; } @Override public void setPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String number, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + if (source != SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER) { throw new IllegalArgumentException("setPhoneNumber doesn't accept source " + SubscriptionManager.phoneNumberSourceToString(source)); @@ -1970,6 +2054,10 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int setUsageSetting(int usageSetting, int subId, @NonNull String callingPackage) { + // Verify that the callingPackage belongs to the calling UID + mContext.getSystemService(AppOpsManager.class) + .checkPackage(Binder.getCallingUid(), callingPackage); + return 0; } 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 e59aad0823..2ad2311160 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -797,4 +797,19 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1).getDisplayName()) .isEqualTo(FAKE_CARRIER_NAME2); } + + @Test + public void testGetActiveSubInfoCount() { + doReturn(new int[]{1, 2}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + + // Should fail without READ_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getActiveSubInfoCount(CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount( + CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(2); + } } -- GitLab From b4e29438ce79fa7a41322cb0bb7f8692ed6e05b1 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 3 Dec 2022 18:40:31 -0800 Subject: [PATCH 234/656] Added sync update database support Added a config allowing updating subscription database synchronously or asynchronously. Test: atest FrameworksTelephonyTests Bug: 239607619 Change-Id: Iad7999c10652839ba055fe798c4598f493fc566d --- .../SubscriptionDatabaseManager.java | 97 ++++++++++++------- .../SubscriptionDatabaseManagerTest.java | 24 +++++ 2 files changed, 86 insertions(+), 35 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index d963ed12c7..2af1141fae 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -62,9 +62,9 @@ import java.util.function.Function; /** * The subscription database manager is the wrapper of {@link SimInfo} - * table. It's a full memory cache of the entire subscription database, and it's intended to run - * on a separate thread to perform asynchronous database update. The database's cache allows - * multi threads to read simultaneously, if no write is ongoing. + * table. It's a full memory cache of the entire subscription database, and the update can be + * asynchronously or synchronously. The database's cache allows multi threads to read + * simultaneously, if no write is ongoing. * * Note that from Android 14, directly writing into the subscription database through content * resolver with {@link SimInfo#CONTENT_URI} will cause cache/db out of sync. All the read/write @@ -247,6 +247,9 @@ public class SubscriptionDatabaseManager extends Handler { @NonNull private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock(); + /** Indicating whether access the database asynchronously or not. */ + private final boolean mAsyncMode; + /** Local log for most important debug messages. */ @NonNull private final LocalLog mLocalLog = new LocalLog(128); @@ -334,6 +337,8 @@ public class SubscriptionDatabaseManager extends Handler { mContext = context; mCallback = callback; mUiccController = UiccController.getInstance(); + mAsyncMode = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_subscription_database_async_update); loadFromDatabase(); } @@ -458,31 +463,39 @@ public class SubscriptionDatabaseManager extends Handler { } /** - * Update a subscription in database asynchronously. + * Update a subscription in the database (synchronously or asynchronously). * * @param subId The subscription id of the subscription to be updated. * @param contentValues The fields to be update. + * + * @return The number of rows updated. Note if the database is configured as asynchronously + * update, then this will be always 1. */ - private void updateDatabaseAsync(int subId, @NonNull ContentValues contentValues) { - logv("updateDatabaseAsync: prepare to update sub " + subId); - // Perform the update in the handler thread asynchronously. + private int updateDatabase(int subId, @NonNull ContentValues contentValues) { + logv("updateDatabase: prepare to update sub " + subId); if (!mDatabaseLoaded) { - logel("Database has not been loaded. Can't update database at this point. " - + "contentValues=" + contentValues); + logel("updateDatabase: Database has not been loaded. Can't update database at this " + + "point. contentValues=" + contentValues); + return 0; } - post(() -> { - int rowsUpdated = mContext.getContentResolver().update(Uri.withAppendedPath( + if (mAsyncMode) { + // Perform the update in the handler thread asynchronously. + post(() -> { + mContext.getContentResolver().update(Uri.withAppendedPath( + SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null); + logv("updateDatabase: async updated subscription in the database." + + " subId=" + subId + ", contentValues= " + contentValues.getValues()); + }); + return 1; + } else { + logv("updateDatabase: sync updated subscription in the database." + + " subId=" + subId + ", contentValues= " + contentValues.getValues()); + + return mContext.getContentResolver().update(Uri.withAppendedPath( SimInfo.CONTENT_URI, String.valueOf(subId)), contentValues, null, null); - if (rowsUpdated == 1) { - logv("updateDatabaseAsync: Successfully updated subscription in the database. " - + "subId=" + subId + ", contentValues= " + contentValues.getValues()); - } else { - logel("updateDatabaseAsync: Unexpected update result. rowsUpdated=" + rowsUpdated - + ", contentValues=" + contentValues); - } - }); + } } /** @@ -522,14 +535,13 @@ public class SubscriptionDatabaseManager extends Handler { // builder.setXxxxxx(newValue); builder = builderSetMethod.apply(builder, newValue); - // Update the subscription database cache. - mAllSubscriptionInfoInternalCache.put(subId, builder.build()); - mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); - // Prepare the content value for update. contentValues.putObject(columnName, newValue); - // Writing into the database is slow. So do this asynchronously. - updateDatabaseAsync(subId, contentValues); + if (updateDatabase(subId, contentValues) > 0) { + // Update the subscription database cache. + mAllSubscriptionInfoInternalCache.put(subId, builder.build()); + mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); + } } } else { logel("Subscription doesn't exist. subId=" + subId + ", columnName" + columnName); @@ -558,14 +570,15 @@ public class SubscriptionDatabaseManager extends Handler { + subId); } if (oldSubInfo.equals(newSubInfo)) return; - mAllSubscriptionInfoInternalCache.put(subId, newSubInfo); - mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); - if (oldSubInfo.areUiccApplicationsEnabled() - != newSubInfo.areUiccApplicationsEnabled()) { - mCallback.invokeFromExecutor(() -> mCallback.onUiccApplicationsEnabled(subId)); + + if (updateDatabase(subId, createDeltaContentValues(oldSubInfo, newSubInfo)) > 0) { + mAllSubscriptionInfoInternalCache.put(subId, newSubInfo); + mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); + if (oldSubInfo.areUiccApplicationsEnabled() + != newSubInfo.areUiccApplicationsEnabled()) { + mCallback.invokeFromExecutor(() -> mCallback.onUiccApplicationsEnabled(subId)); + } } - // Writing into the database is slow. So do this asynchronously. - updateDatabaseAsync(subId, createDeltaContentValues(oldSubInfo, newSubInfo)); } finally { mReadWriteLock.writeLock().unlock(); } @@ -760,6 +773,7 @@ public class SubscriptionDatabaseManager extends Handler { mReadWriteLock.writeLock().lock(); try { SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get(subId); + if (subInfoCache == null) return; mAllSubscriptionInfoInternalCache.put(subId, new SubscriptionInfoInternal.Builder(subInfoCache) .setCardId(cardId).build()); @@ -1192,7 +1206,7 @@ public class SubscriptionDatabaseManager extends Handler { */ private void loadFromDatabase() { // Perform the task in the handler thread. - post(() -> { + Runnable r = () -> { try (Cursor cursor = mContext.getContentResolver().query( SimInfo.CONTENT_URI, null, null, null, null)) { mReadWriteLock.writeLock().lock(); @@ -1213,7 +1227,15 @@ public class SubscriptionDatabaseManager extends Handler { mReadWriteLock.writeLock().unlock(); } } - }); + }; + + if (mAsyncMode) { + // Load the database asynchronously. + post(r); + } else { + // Load the database synchronously. + r.run(); + } } /** @@ -1361,7 +1383,12 @@ public class SubscriptionDatabaseManager extends Handler { */ @NonNull public List getAllSubscriptions() { - return new ArrayList<>(mAllSubscriptionInfoInternalCache.values()); + mReadWriteLock.readLock().lock(); + try { + return new ArrayList<>(mAllSubscriptionInfoInternalCache.values()); + } finally { + mReadWriteLock.readLock().unlock(); + } } /** 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 1ba69dc0e0..722f297eac 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -426,6 +426,30 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { verify(mSubscriptionDatabaseManagerCallback, never()).onSubscriptionChanged(anyInt()); } + @Test + public void testUpdateSubscriptionSync() throws Exception { + mContextFixture.putBooleanResource(com.android.internal.R.bool + .config_subscription_database_async_update, false); + mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper(), + mSubscriptionDatabaseManagerCallback); + + assertThat(insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1).getSubscriptionId()) + .isEqualTo(1); + SubscriptionInfoInternal subInfo = new SubscriptionInfoInternal + .Builder(FAKE_SUBSCRIPTION_INFO2) + .setId(1) + .build(); + mDatabaseManagerUT.updateSubscription(subInfo); + + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + Mockito.clearInvocations(mSubscriptionDatabaseManagerCallback); + + // Same sub info again. Should not trigger callback + mDatabaseManagerUT.updateSubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, never()).onSubscriptionChanged(anyInt()); + } + @Test public void testUpdateIccId() throws Exception { SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); -- GitLab From 2041b76d84b7229ec11f0970116415c66a6490cb Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 4 Dec 2022 01:20:57 -0800 Subject: [PATCH 235/656] Added setIconTint Test: atest FrameworksTelephonyTests Bug: 239607619 Change-Id: I35680bdd91af4fe492cd554ab327255c8d4709bd --- .../telephony/SubscriptionController.java | 6 +- .../SubscriptionDatabaseManager.java | 121 +++++++++- .../SubscriptionInfoInternal.java | 3 + .../SubscriptionManagerService.java | 46 +++- .../SubscriptionDatabaseManagerTest.java | 210 +++++++++++++++++- .../SubscriptionManagerServiceTest.java | 24 +- 6 files changed, 384 insertions(+), 26 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index c11c23acde..5e3c4b500b 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -1858,12 +1858,14 @@ public class SubscriptionController extends ISub.Stub { /** * Set SIM color tint by simInfo index - * @param tint the tint color of the SIM + * * @param subId the unique SubInfoRecord index in database + * @param tint the tint color of the SIM + * * @return the number of records updated */ @Override - public int setIconTint(int tint, int subId) { + public int setIconTint(int subId, int tint) { if (DBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId); enforceModifyPhoneState("setIconTint"); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 2af1141fae..a0ced874ad 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -17,6 +17,7 @@ package com.android.internal.telephony.subscription; import android.annotation.CallbackExecutor; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentValues; @@ -510,6 +511,8 @@ public class SubscriptionDatabaseManager extends Handler { * when constructing the new {@link SubscriptionInfo}. This should be one of the * SubscriptionInfoInternal.Builder.setXxxx method. * @param The type of newValue for subscription cache update. + * + * @throws IllegalArgumentException if the subscription does not exist. */ private void writeDatabaseAndCacheHelper(int subId, @NonNull String columnName, @Nullable T newValue, @@ -544,7 +547,9 @@ public class SubscriptionDatabaseManager extends Handler { } } } else { - logel("Subscription doesn't exist. subId=" + subId + ", columnName" + columnName); + logel("Subscription doesn't exist. subId=" + subId + ", columnName=" + columnName); + throw new IllegalArgumentException("Subscription doesn't exist. subId=" + subId + + ", columnName=" + columnName); } } finally { mReadWriteLock.writeLock().unlock(); @@ -555,6 +560,8 @@ public class SubscriptionDatabaseManager extends Handler { * Update the database with the {@link SubscriptionInfoInternal}, and also update the cache. * * @param newSubInfo The new {@link SubscriptionInfoInternal}. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void updateSubscription(@NonNull SubscriptionInfoInternal newSubInfo) { Objects.requireNonNull(newSubInfo); @@ -566,8 +573,8 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal oldSubInfo = mAllSubscriptionInfoInternalCache.get( newSubInfo.getSubscriptionId()); if (oldSubInfo == null) { - throw new RuntimeException("updateSubscription: subscription does not exist. subId=" - + subId); + throw new IllegalArgumentException("updateSubscription: subscription does not " + + "exist. subId=" + subId); } if (oldSubInfo.equals(newSubInfo)) return; @@ -589,6 +596,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param iccId The ICCID of the SIM that is associated with this subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setIccId(int subId, @NonNull String iccId) { Objects.requireNonNull(iccId); @@ -602,6 +611,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param simSlotIndex The SIM slot index. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setSimSlotIndex(int subId, int simSlotIndex) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SIM_SLOT_INDEX, simSlotIndex, @@ -614,6 +625,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param displayName The display name. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setDisplayName(int subId, @NonNull String displayName) { Objects.requireNonNull(displayName); @@ -627,6 +640,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param carrierName The carrier name. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setCarrierName(int subId, @NonNull String carrierName) { Objects.requireNonNull(carrierName); @@ -640,6 +655,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param displayNameSource The source of the display name. * + * @throws IllegalArgumentException if the subscription does not exist. + * * @see SubscriptionInfo#getDisplayName() */ public void setDisplayNameSource(int subId, @SimDisplayNameSource int displayNameSource) { @@ -652,8 +669,10 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param iconTint The color to be used for tinting the icon when displaying to the user. + * + * @throws IllegalArgumentException if the subscription does not exist. */ - public void setIconTint(int subId, int iconTint) { + public void setIconTint(int subId, @ColorInt int iconTint) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_COLOR, iconTint, SubscriptionInfoInternal.Builder::setIconTint); } @@ -663,6 +682,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param number the number presented to the user identify this subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setNumber(int subId, @NonNull String number) { Objects.requireNonNull(number); @@ -677,6 +698,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param dataRoaming Data roaming mode. Either * {@link SubscriptionManager#DATA_ROAMING_ENABLE} or * {@link SubscriptionManager#DATA_ROAMING_DISABLE} + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setDataRoaming(int subId, int dataRoaming) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_DATA_ROAMING, dataRoaming, @@ -688,6 +711,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param mcc The mobile country code. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setMcc(int subId, @NonNull String mcc) { Objects.requireNonNull(mcc); @@ -700,6 +725,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param mnc Mobile network code. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setMnc(int subId, @NonNull String mnc) { Objects.requireNonNull(mnc); @@ -712,6 +739,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param ehplmns EHPLMNs associated with the subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setEhplmns(int subId, @NonNull String[] ehplmns) { Objects.requireNonNull(ehplmns); @@ -724,6 +753,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param hplmns HPLMNs associated with the subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setHplmns(int subId, @NonNull String[] hplmns) { Objects.requireNonNull(hplmns); @@ -736,6 +767,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param isEmbedded {@code true} if the subscription is from eSIM. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setEmbedded(int subId, boolean isEmbedded) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_EMBEDDED, isEmbedded ? 1 : 0, @@ -748,6 +781,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param cardString The card string of the SIM card. * + * @throws IllegalArgumentException if the subscription does not exist. + * * @see SubscriptionInfo#getCardString() */ public void setCardString(int subId, @NonNull String cardString) { @@ -765,6 +800,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param cardId The card id. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setCardId(int subId, int cardId) { // card id does not have a corresponding SimInfo column. So we only update the cache. @@ -773,7 +810,10 @@ public class SubscriptionDatabaseManager extends Handler { mReadWriteLock.writeLock().lock(); try { SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get(subId); - if (subInfoCache == null) return; + if (subInfoCache == null) { + throw new IllegalArgumentException("Subscription doesn't exist. subId=" + subId + + ", columnName=cardId"); + } mAllSubscriptionInfoInternalCache.put(subId, new SubscriptionInfoInternal.Builder(subInfoCache) .setCardId(cardId).build()); @@ -788,6 +828,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param nativeAccessRules The native access rules for this subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setNativeAccessRules(int subId, @NonNull UiccAccessRule[] nativeAccessRules) { Objects.requireNonNull(nativeAccessRules); @@ -802,6 +844,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param carrierConfigAccessRules The carrier certificates for this subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setCarrierConfigAccessRules(int subId, @NonNull UiccAccessRule[] carrierConfigAccessRules) { @@ -819,6 +863,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param isRemovableEmbedded {@code true} if the subscription is from the removable * embedded SIM. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setRemovableEmbedded(int subId, boolean isRemovableEmbedded) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_REMOVABLE, isRemovableEmbedded ? 1 : 0, @@ -830,6 +876,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param isEnhanced4GModeEnabled whether enhanced 4G mode is enabled by the user or not. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setEnhanced4GModeEnabled(int subId, boolean isEnhanced4GModeEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, @@ -842,6 +890,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param isVideoTelephonyEnabled whether video telephony is enabled by the user or not. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setVideoTelephonyEnabled(int subId, boolean isVideoTelephonyEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VT_IMS_ENABLED, @@ -855,6 +905,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param isWifiCallingEnabled whether Wi-Fi calling is enabled by the user or not when the * device is not roaming. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setWifiCallingEnabled(int subId, boolean isWifiCallingEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ENABLED, @@ -867,6 +919,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param wifiCallingMode Wi-Fi calling mode when the device is not roaming. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setWifiCallingMode(int subId, @ImsMmTelManager.WiFiCallingMode int wifiCallingMode) { @@ -879,6 +933,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param wifiCallingModeForRoaming Wi-Fi calling mode when the device is roaming. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setWifiCallingModeForRoaming(int subId, @ImsMmTelManager.WiFiCallingMode int wifiCallingModeForRoaming) { @@ -893,6 +949,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param isWifiCallingEnabledForRoaming whether Wi-Fi calling is enabled by the user or not * when the device is roaming. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setWifiCallingEnabledForRoaming(int subId, boolean isWifiCallingEnabledForRoaming) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, @@ -905,6 +963,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param isOpportunistic {@code true} if the subscription is opportunistic. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setOpportunistic(int subId, boolean isOpportunistic) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_OPPORTUNISTIC, isOpportunistic ? 1 : 0, @@ -917,6 +977,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param groupUuid The group UUID. * + * @throws IllegalArgumentException if the subscription does not exist. + * * @see SubscriptionInfo#getGroupUuid() */ public void setGroupUuid(int subId, @NonNull String groupUuid) { @@ -930,6 +992,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param countryIso The ISO country code for the subscription's provider. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setCountryIso(int subId, @NonNull String countryIso) { Objects.requireNonNull(countryIso); @@ -943,6 +1007,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param carrierId The carrier id. * + * @throws IllegalArgumentException if the subscription does not exist. + * * @see TelephonyManager#getSimCarrierId() */ public void setCarrierId(int subId, int carrierId) { @@ -956,6 +1022,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param profileClass the profile class populated from the profile metadata if present. * + * @throws IllegalArgumentException if the subscription does not exist. + * * @see SubscriptionInfo#getProfileClass() */ public void setProfileClass(int subId, @ProfileClass int profileClass) { @@ -968,6 +1036,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param type Subscription type. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setSubscriptionType(int subId, @SubscriptionType int type) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SUBSCRIPTION_TYPE, type, @@ -979,6 +1049,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param groupOwner Owner package of group the subscription belongs to. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setGroupOwner(int subId, @NonNull String groupOwner) { Objects.requireNonNull(groupOwner); @@ -991,6 +1063,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param enabledMobileDataPolicies The enabled mobile data policies. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setEnabledMobileDataPolicies(int subId, @NonNull String enabledMobileDataPolicies) { Objects.requireNonNull(enabledMobileDataPolicies); @@ -1004,6 +1078,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param imsi The IMSI. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setImsi(int subId, @NonNull String imsi) { Objects.requireNonNull(imsi); @@ -1017,6 +1093,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param areUiccApplicationsEnabled {@code true} if Uicc applications are configured to * enable. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setUiccApplicationsEnabled(int subId, boolean areUiccApplicationsEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED, @@ -1030,6 +1108,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param isRcsUceEnabled If the user enabled RCS UCE for this subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setRcsUceEnabled(int subId, boolean isRcsUceEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, @@ -1042,6 +1122,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param isCrossSimCallingEnabled If the user enabled cross SIM calling for this * subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setCrossSimCallingEnabled(int subId, boolean isCrossSimCallingEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, @@ -1054,6 +1136,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param rcsConfig The RCS config for this subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setRcsConfig(int subId, @NonNull byte[] rcsConfig) { Objects.requireNonNull(rcsConfig); @@ -1066,11 +1150,10 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param allowedNetworkTypesForReasons The allowed network types for reasons in string - * format. The format is - * "[reason]=[network types bitmask], [reason]=[network types bitmask], ..." - * - * For example, "user=1239287394, thermal=298791239, carrier=3456812312". + * format. The format is "[reason]=[network types bitmask], [reason]=[network types bitmask], + * ...". For example, "user=1239287394, thermal=298791239, carrier=3456812312". * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setAllowedNetworkTypesForReasons(int subId, @NonNull String allowedNetworkTypesForReasons) { @@ -1085,6 +1168,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param deviceToDeviceStatusSharingPreference Device to device sharing status. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setDeviceToDeviceStatusSharingPreference(int subId, @DeviceToDeviceStatusSharingPreference int deviceToDeviceStatusSharingPreference) { @@ -1098,6 +1183,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param isVoImsOptInEnabled Whether the user has opted-in voice over IMS. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setVoImsOptInEnabled(int subId, boolean isVoImsOptInEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, @@ -1111,6 +1198,8 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId Subscription id. * @param deviceToDeviceStatusSharingContacts contacts information that allow device to * device sharing. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setDeviceToDeviceStatusSharingContacts(int subId, @NonNull String deviceToDeviceStatusSharingContacts) { @@ -1125,6 +1214,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param isNrAdvancedCallingEnabled Whether the user has enabled NR advanced calling. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setNrAdvancedCallingEnabled(int subId, boolean isNrAdvancedCallingEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, @@ -1137,6 +1228,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param numberFromCarrier The phone number retrieved from carrier. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setNumberFromCarrier(int subId, @NonNull String numberFromCarrier) { Objects.requireNonNull(numberFromCarrier); @@ -1149,6 +1242,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param numberFromIms The phone number retrieved from IMS. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setNumberFromIms(int subId, @NonNull String numberFromIms) { Objects.requireNonNull(numberFromIms); @@ -1161,6 +1256,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param portIndex The port index of the Uicc card. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setPortIndex(int subId, int portIndex) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_PORT_INDEX, portIndex, @@ -1172,6 +1269,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param usageSetting Subscription's preferred usage setting. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setUsageSetting(int subId, @UsageSetting int usageSetting) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_USAGE_SETTING, usageSetting, @@ -1183,6 +1282,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param lastUsedTPMessageReference Last used TP message reference. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setLastUsedTPMessageReference(int subId, int lastUsedTPMessageReference) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_TP_MESSAGE_REF, @@ -1195,6 +1296,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @param subId Subscription id. * @param userId The user id associated with this subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. */ public void setUserId(int subId, int userId) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_USER_HANDLE, userId, diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 7e882f28b0..4e9a47f452 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -31,6 +31,7 @@ package com.android.internal.telephony.subscription; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.os.UserHandle; import android.provider.Telephony.SimInfo; @@ -113,6 +114,7 @@ public class SubscriptionInfoInternal { /** * The color to be used for tinting the icon when displaying to the user. */ + @ColorInt private final int mIconTint; /** @@ -509,6 +511,7 @@ public class SubscriptionInfoInternal { * * @return A hexadecimal color value. */ + @ColorInt public int getIconTint() { return mIconTint; } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 35df346661..f6b7eb0b31 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -18,6 +18,7 @@ package com.android.internal.telephony.subscription; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -635,6 +636,9 @@ public class SubscriptionManagerService extends ISub.Stub { * @param subId Subscription id. * @param carrierId The carrier id. * + * @throws IllegalArgumentException if {@code subId} is invalid or the subscription does not + * exist. + * * @see TelephonyManager#getSimCarrierId() */ public void setCarrierId(int subId, int carrierId) { @@ -646,6 +650,9 @@ public class SubscriptionManagerService extends ISub.Stub { * * @param mccMnc MCC/MNC associated with the subscription. * @param subId The subscription id. + * + * @throws IllegalArgumentException if {@code subId} is invalid or the subscription does not + * exist. */ public void setMccMnc(int subId, @NonNull String mccMnc) { mSubscriptionDatabaseManager.setMcc(subId, mccMnc.substring(0, 3)); @@ -1263,14 +1270,31 @@ public class SubscriptionManagerService extends ISub.Stub { /** * Set SIM icon tint color by simInfo index. * - * @param tint the icon tint color of the SIM * @param subId the unique subscription index in database + * @param tint the icon tint color of the SIM * * @return the number of records updated + * + * @throws IllegalArgumentException if {@code subId} is invalid or the subscription does not + * exist. + * @throws SecurityException if callers do not hold the required permission. */ @Override - public int setIconTint(int tint, int subId) { - return 0; + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public int setIconTint(int subId, @ColorInt int tint) { + enforcePermissions("setIconTint", Manifest.permission.MODIFY_PHONE_STATE); + + final long identity = Binder.clearCallingIdentity(); + try { + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + throw new IllegalArgumentException("Invalid sub id passed as parameter"); + } + + mSubscriptionDatabaseManager.setIconTint(subId, tint); + return 1; + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1344,7 +1368,7 @@ public class SubscriptionManagerService extends ISub.Stub { if (sub != null && sub.isEmbedded()) { int cardId = sub.getCardId(); log("Updating embedded sub nickname on cardId: " + cardId); - mEuiccManager.updateSubscriptionNickname(subId, displayName, + mEuiccManager.updateSubscriptionNickname(subId, nameToSet, // This PendingIntent simply fulfills the requirement to pass in a callback; // we don't care about the result (hence 0 requestCode and no action // specified on the intent). @@ -1406,6 +1430,9 @@ public class SubscriptionManagerService extends ISub.Stub { * @param callingPackage The package making the call * * @return the number of records updated + * + * @throws IllegalArgumentException if {@code subId} is invalid or the subscription does not + * exist. */ @Override public int setOpportunistic(boolean opportunistic, int subId, @NonNull String callingPackage) { @@ -1923,11 +1950,12 @@ public class SubscriptionManagerService extends ISub.Stub { * Returns the phone number for the given {@code subscriptionId} and {@code source}, * or an empty string if not available. * - *

General apps that need to know the phone number should use {@link #getPhoneNumber(int)} - * instead. This API may be suitable specific apps that needs to know the phone number from - * a specific source. For example, a carrier app needs to know exactly what's on - * {@link #PHONE_NUMBER_SOURCE_UICC UICC} and decide if the previously set phone number - * of source {@link #PHONE_NUMBER_SOURCE_CARRIER carrier} should be updated. + *

General apps that need to know the phone number should use + * {@link SubscriptionManager#getPhoneNumber(int)} instead. This API may be suitable specific + * apps that needs to know the phone number from a specific source. For example, a carrier app + * needs to know exactly what's on {@link SubscriptionManager#PHONE_NUMBER_SOURCE_UICC UICC} and + * decide if the previously set phone number of source + * {@link SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER carrier} should be updated. * *

The API provides no guarantees of what format the number is in: the format can vary * depending on the {@code source} and the network etc. Programmatic parsing should be done 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 722f297eac..e7677dee6f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -19,6 +19,7 @@ package com.android.internal.telephony.subscription; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -409,12 +410,17 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateSubscription() throws Exception { - assertThat(insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1).getSubscriptionId()) - .isEqualTo(1); SubscriptionInfoInternal subInfo = new SubscriptionInfoInternal .Builder(FAKE_SUBSCRIPTION_INFO2) .setId(1) .build(); + + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.updateSubscription(subInfo)); + + assertThat(insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1).getSubscriptionId()) + .isEqualTo(1); mDatabaseManagerUT.updateSubscription(subInfo); processAllMessages(); verifySubscription(subInfo); @@ -452,6 +458,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateIccId() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setIccId(1, FAKE_ICCID2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setIccId(subInfo.getSubscriptionId(), FAKE_ICCID2); processAllMessages(); @@ -463,6 +473,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateSimSlotIndex() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setSimSlotIndex(1, + SubscriptionManager.INVALID_SIM_SLOT_INDEX)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setSimSlotIndex(subInfo.getSubscriptionId(), SubscriptionManager.INVALID_SIM_SLOT_INDEX); @@ -476,6 +491,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateDisplayName() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setDisplayName(1, FAKE_CARRIER_NAME2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setDisplayName(subInfo.getSubscriptionId(), FAKE_CARRIER_NAME2); processAllMessages(); @@ -488,6 +507,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateCarrierName() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCarrierName(1, FAKE_CARRIER_NAME2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setCarrierName(subInfo.getSubscriptionId(), FAKE_CARRIER_NAME2); processAllMessages(); @@ -500,18 +523,28 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateDisplayNameSource() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setDisplayNameSource(1, + SubscriptionManager.NAME_SOURCE_USER_INPUT)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setCarrierName(subInfo.getSubscriptionId(), FAKE_CARRIER_NAME2); + mDatabaseManagerUT.setDisplayNameSource(subInfo.getSubscriptionId(), + SubscriptionManager.NAME_SOURCE_USER_INPUT); processAllMessages(); - subInfo = new SubscriptionInfoInternal.Builder(subInfo).setCarrierName( - FAKE_CARRIER_NAME2).build(); + subInfo = new SubscriptionInfoInternal.Builder(subInfo).setDisplayNameSource( + SubscriptionManager.NAME_SOURCE_USER_INPUT).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); } @Test public void testUpdateIconTint() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setIconTint(1, FAKE_COLOR2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setIconTint(subInfo.getSubscriptionId(), FAKE_COLOR2); processAllMessages(); @@ -523,6 +556,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateNumber() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setNumber(1, FAKE_PHONE_NUMBER2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setNumber(subInfo.getSubscriptionId(), FAKE_PHONE_NUMBER2); processAllMessages(); @@ -535,6 +572,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateDataRoaming() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setDataRoaming(1, + SubscriptionManager.DATA_ROAMING_DISABLE)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setDataRoaming(subInfo.getSubscriptionId(), SubscriptionManager.DATA_ROAMING_DISABLE); @@ -548,6 +590,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateMcc() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setMcc(1, FAKE_MCC2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setMcc(subInfo.getSubscriptionId(), FAKE_MCC2); processAllMessages(); @@ -559,6 +605,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateMnc() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setMnc(1, FAKE_MNC2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setMnc(subInfo.getSubscriptionId(), FAKE_MNC2); processAllMessages(); @@ -570,6 +620,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateEhplmns() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setEhplmns(1, FAKE_EHPLMNS2.split(","))); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setEhplmns(subInfo.getSubscriptionId(), FAKE_EHPLMNS2.split(",")); processAllMessages(); @@ -581,6 +635,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateHplmns() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setHplmns(1, FAKE_HPLMNS2.split(","))); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setHplmns(subInfo.getSubscriptionId(), FAKE_HPLMNS2.split(",")); processAllMessages(); @@ -592,6 +650,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateEmbedded() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setEmbedded(1, false)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setEmbedded(subInfo.getSubscriptionId(), false); processAllMessages(); @@ -603,6 +665,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateCardString() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCardString(1, FAKE_ICCID2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setCardString(subInfo.getSubscriptionId(), FAKE_ICCID2); processAllMessages(); @@ -617,6 +683,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateNativeAccessRules() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setNativeAccessRules(1, + UiccAccessRule.decodeRules(FAKE_NATIVE_ACCESS_RULES2))); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setNativeAccessRules(subInfo.getSubscriptionId(), UiccAccessRule.decodeRules(FAKE_NATIVE_ACCESS_RULES2)); @@ -630,6 +701,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateCarrierConfigAccessRules() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCarrierConfigAccessRules(1, + UiccAccessRule.decodeRules(FAKE_CARRIER_CONFIG_ACCESS_RULES2))); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setCarrierConfigAccessRules(subInfo.getSubscriptionId(), UiccAccessRule.decodeRules(FAKE_CARRIER_CONFIG_ACCESS_RULES2)); @@ -643,6 +719,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateRemovableEmbedded() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setRemovableEmbedded(1, true)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setRemovableEmbedded(subInfo.getSubscriptionId(), true); processAllMessages(); @@ -654,6 +734,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateEnhanced4GModeEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setEnhanced4GModeEnabled(1, false)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setEnhanced4GModeEnabled(subInfo.getSubscriptionId(), false); processAllMessages(); @@ -665,6 +749,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateVideoTelephonyEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setVideoTelephonyEnabled(1, false)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setVideoTelephonyEnabled(subInfo.getSubscriptionId(), false); processAllMessages(); @@ -676,6 +764,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateWifiCallingEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setWifiCallingEnabled(1, false)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setWifiCallingEnabled(subInfo.getSubscriptionId(), false); processAllMessages(); @@ -687,6 +779,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateWifiCallingMode() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setWifiCallingMode( + 1, ImsMmTelManager.WIFI_MODE_WIFI_ONLY)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setWifiCallingMode(subInfo.getSubscriptionId(), ImsMmTelManager.WIFI_MODE_WIFI_ONLY); @@ -700,6 +797,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateWifiCallingModeForRoaming() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setWifiCallingModeForRoaming( + 1, ImsMmTelManager.WIFI_MODE_WIFI_ONLY)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setWifiCallingModeForRoaming(subInfo.getSubscriptionId(), ImsMmTelManager.WIFI_MODE_WIFI_ONLY); @@ -713,6 +815,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateWifiCallingEnabledForRoaming() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setWifiCallingEnabledForRoaming(1, false)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setWifiCallingEnabledForRoaming(subInfo.getSubscriptionId(), false); processAllMessages(); @@ -725,6 +831,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateOpportunistic() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setOpportunistic(1, true)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setOpportunistic(subInfo.getSubscriptionId(), true); processAllMessages(); @@ -736,6 +846,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateGroupUuid() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setGroupUuid(1, FAKE_UUID2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setGroupUuid(subInfo.getSubscriptionId(), FAKE_UUID2); processAllMessages(); @@ -747,6 +861,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateCountryIso() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCountryIso(1, FAKE_COUNTRY_CODE2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setCountryIso(subInfo.getSubscriptionId(), FAKE_COUNTRY_CODE2); processAllMessages(); @@ -759,6 +877,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateCarrierId() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCarrierId(1, FAKE_CARRIER_ID2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setCarrierId(subInfo.getSubscriptionId(), FAKE_CARRIER_ID2); processAllMessages(); @@ -771,6 +893,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateProfileClass() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setProfileClass( + 1, SubscriptionManager.PROFILE_CLASS_TESTING)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setProfileClass(subInfo.getSubscriptionId(), SubscriptionManager.PROFILE_CLASS_TESTING); @@ -784,6 +911,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateSubscriptionType() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setSubscriptionType( + 1, SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setSubscriptionType(subInfo.getSubscriptionId(), SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); @@ -797,6 +929,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateGroupOwner() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setGroupOwner(1, FAKE_OWNER2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setGroupOwner(subInfo.getSubscriptionId(), FAKE_OWNER2); processAllMessages(); @@ -809,6 +945,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateEnabledMobileDataPolicies() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setEnabledMobileDataPolicies(1, FAKE_MOBILE_DATA_POLICY2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setEnabledMobileDataPolicies(subInfo.getSubscriptionId(), FAKE_MOBILE_DATA_POLICY2); @@ -822,6 +962,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateImsi() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setImsi(1, FAKE_IMSI2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setImsi(subInfo.getSubscriptionId(), FAKE_IMSI2); processAllMessages(); @@ -834,6 +978,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateUiccApplicationsEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setUiccApplicationsEnabled(1, false)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setUiccApplicationsEnabled(subInfo.getSubscriptionId(), false); processAllMessages(); @@ -846,6 +994,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateRcsUceEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setRcsUceEnabled(1, false)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setRcsUceEnabled(subInfo.getSubscriptionId(), false); processAllMessages(); @@ -858,6 +1010,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateCrossSimCallingEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCrossSimCallingEnabled(1, false)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setCrossSimCallingEnabled(subInfo.getSubscriptionId(), false); processAllMessages(); @@ -870,6 +1026,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateRcsConfig() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setRcsConfig(1, FAKE_RCS_CONFIG2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setRcsConfig(subInfo.getSubscriptionId(), FAKE_RCS_CONFIG2); processAllMessages(); @@ -882,6 +1042,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateAllowedNetworkTypesForReasons() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setAllowedNetworkTypesForReasons( + 1, FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setAllowedNetworkTypesForReasons(subInfo.getSubscriptionId(), FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2); @@ -895,6 +1060,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateDeviceToDeviceStatusSharingPreference() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setDeviceToDeviceStatusSharingPreference( + 1, SubscriptionManager.D2D_SHARING_DISABLED)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setDeviceToDeviceStatusSharingPreference(subInfo.getSubscriptionId(), SubscriptionManager.D2D_SHARING_DISABLED); @@ -909,6 +1079,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateNrAdvancedCallingEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setNrAdvancedCallingEnabled(1, false)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setNrAdvancedCallingEnabled(subInfo.getSubscriptionId(), false); processAllMessages(); @@ -921,6 +1095,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateNumberFromCarrier() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setNumberFromCarrier(1, FAKE_PHONE_NUMBER2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setNumberFromCarrier(subInfo.getSubscriptionId(), FAKE_PHONE_NUMBER2); processAllMessages(); @@ -933,6 +1111,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateNumberFromIms() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setNumberFromIms(1, FAKE_PHONE_NUMBER2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setNumberFromIms(subInfo.getSubscriptionId(), FAKE_PHONE_NUMBER2); processAllMessages(); @@ -945,6 +1127,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdatePortIndex() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setPortIndex(1, 1)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setPortIndex(subInfo.getSubscriptionId(), 1); processAllMessages(); @@ -957,6 +1143,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateUsageSetting() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setUsageSetting( + 1, SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setUsageSetting(subInfo.getSubscriptionId(), SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC); @@ -970,6 +1161,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateLastUsedTPMessageReference() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setLastUsedTPMessageReference( + 1, FAKE_TP_MESSAGE_REFERENCE2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setLastUsedTPMessageReference(subInfo.getSubscriptionId(), FAKE_TP_MESSAGE_REFERENCE2); @@ -983,6 +1179,10 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testUpdateUserId() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setUserId(1, FAKE_USER_ID2)); + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setUserId(subInfo.getSubscriptionId(), FAKE_USER_ID2); processAllMessages(); 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 2ad2311160..55e2f4d174 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -194,6 +194,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { method.setAccessible(true); int subId = (int) method.invoke(sdbm, subInfo); + // Insertion is sync, but the onSubscriptionChanged callback is handled by the handler. + processAllMessages(); + Class WatchedMapClass = Class.forName("com.android.internal.telephony.subscription" + ".SubscriptionManagerService$WatchedMap"); field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); @@ -333,7 +336,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(new int[]{1, 2}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); - processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(2)); @@ -812,4 +814,24 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.getActiveSubInfoCount( CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(2); } + + @Test + public void testSetIconTint() throws Exception { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); + + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setIconTint(1, 12345)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + mSubscriptionManagerServiceUT.setIconTint(1, 12345); + processAllMessages(); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getIconTint()).isEqualTo(12345); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + } } -- GitLab From ddd03960bb1d463f3c869edb89ccb6566a3bb2ce Mon Sep 17 00:00:00 2001 From: Hyunho Shin Date: Tue, 6 Dec 2022 02:34:42 +0000 Subject: [PATCH 236/656] Revert "Fix SsDomainController to support terminal-based CLIR with vendor IMS" This reverts commit 02f3fed27eb2a6d0300b4a7bad3642549207dd75. Reason for revert: UT domain selection should go back to legacy. Change-Id: I681680035a02ce4dd07c16b85c7c67f066ebbb18 --- .../internal/telephony/GsmCdmaPhone.java | 38 ++++------------ .../telephony/SsDomainController.java | 44 ++++++------------- .../internal/telephony/GsmCdmaPhoneTest.java | 29 ------------ .../telephony/SsDomainControllerTest.java | 39 +--------------- 4 files changed, 24 insertions(+), 126 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index f9bd7189c5..01851cb7e4 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -2284,18 +2284,18 @@ public class GsmCdmaPhone extends Phone { /** * Checks the availability of Ut directly without SsDomainController. - * This is only applicable for the case that the terminal-based service - * is handled by the IMS service alone without interworking with framework. + * This is only applicable for the case that the terminal-based call waiting service + * is handled by the IMS service alone without interworking with CallWaitingController. */ - private boolean useTerminalBasedServiceOverIms(Message onComplete) { + private boolean useCallWaitingOverUt(Message onComplete) { Phone imsPhone = mImsPhone; if (imsPhone == null) { - logd("useTerminalBasedServiceOverIms: called for GsmCdma"); + logd("useCallWaitingOverUt: called for GsmCdma"); return false; } boolean isUtEnabled = imsPhone.isUtEnabled(); - Rlog.d(LOG_TAG, "useTerminalBasedServiceOverIms isUtEnabled= " + isUtEnabled + Rlog.d(LOG_TAG, "useCallWaitingOverUt isUtEnabled= " + isUtEnabled + " isCsRetry(onComplete))= " + isCsRetry(onComplete)); return isUtEnabled && !isCsRetry(onComplete); } @@ -2315,14 +2315,6 @@ public class GsmCdmaPhone extends Phone { return mSsDomainController.getOemHandlesTerminalBasedCallWaiting(); } - /** - * Returns whether the carrier supports the terminal-based CLIR - * and Ims service handles it by itself. - */ - private boolean getOemHandlesTerminalBasedClir() { - return mSsDomainController.getOemHandlesTerminalBasedClir(); - } - /** * Sends response indicating no nework is available for supplementary services. */ @@ -2582,13 +2574,6 @@ public class GsmCdmaPhone extends Phone { responseInvalidState(onComplete); return; } - } else if (getOemHandlesTerminalBasedClir()) { - // Ims service handles the terminal-based CLIR by itself. - // Use legacy implementation. Forward the request to Ims service if Ut is available. - if (useTerminalBasedServiceOverIms(onComplete)) { - imsPhone.getOutgoingCallerIdDisplay(onComplete); - return; - } } if (isPhoneTypeGsm()) { @@ -2621,13 +2606,6 @@ public class GsmCdmaPhone extends Phone { responseInvalidState(onComplete); return; } - } else if (getOemHandlesTerminalBasedClir()) { - // Ims service handles the terminal-based CLIR by itself. - // Use legacy implementation. Forward the request to Ims service if Ut is available. - if (useTerminalBasedServiceOverIms(onComplete)) { - imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete); - return; - } } if (isPhoneTypeGsm()) { @@ -2699,7 +2677,7 @@ public class GsmCdmaPhone extends Phone { } else if (getOemHandlesTerminalBasedCallWaiting()) { // Ims service handles the terminal-based call waiting service by itself. // Use legacy implementation. Forward the request to Ims service if Ut is available. - if (useTerminalBasedServiceOverIms(onComplete)) { + if (useCallWaitingOverUt(onComplete)) { imsPhone.getCallWaiting(onComplete); return; } @@ -2764,7 +2742,7 @@ public class GsmCdmaPhone extends Phone { } else if (getOemHandlesTerminalBasedCallWaiting()) { // Ims service handles the terminal-based call waiting service by itself. // Use legacy implementation. Forward the request to Ims service if Ut is available. - if (useTerminalBasedServiceOverIms(onComplete)) { + if (useCallWaitingOverUt(onComplete)) { imsPhone.setCallWaiting(enable, onComplete); return; } @@ -2808,7 +2786,7 @@ public class GsmCdmaPhone extends Phone { @Override public void setTerminalBasedCallWaitingSupported(boolean supported) { mCallWaitingController.setTerminalBasedCallWaitingSupported(supported); - mSsDomainController.setOemHandlesTerminalBasedService(!supported); + mSsDomainController.setOemHandlesTerminalBasedCallWaiting(!supported); } @Override diff --git a/src/java/com/android/internal/telephony/SsDomainController.java b/src/java/com/android/internal/telephony/SsDomainController.java index b0c7dfd7ae..eef9b68fea 100644 --- a/src/java/com/android/internal/telephony/SsDomainController.java +++ b/src/java/com/android/internal/telephony/SsDomainController.java @@ -170,10 +170,9 @@ public class SsDomainController { private Set mUtAvailableRats = new HashSet<>(); private boolean mWiFiAvailable = false; private boolean mIsMonitoringConnectivity = false; - /** true if Ims service handles the terminal-based service by itself. */ - private boolean mOemHandlesTerminalBasedService = false; + /** true if Ims service handles the terminal-based call waiting service by itself. */ + private boolean mOemHandlesTerminalBasedCallWaiting = false; private boolean mSupportsTerminalBasedCallWaiting = false; - private boolean mSupportsTerminalBasedClir = false; public SsDomainController(GsmCdmaPhone phone) { mPhone = phone; @@ -222,19 +221,16 @@ public class SsDomainController { mUtAvailableWhenRoaming = availableWhenRoaming; mSupportsTerminalBasedCallWaiting = false; - mSupportsTerminalBasedClir = false; if (tbServices != null) { for (int tbService : tbServices) { if (tbService == SUPPLEMENTARY_SERVICE_CW) { mSupportsTerminalBasedCallWaiting = true; - } - if (tbService == SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR) { - mSupportsTerminalBasedClir = true; + break; } } } - logi("updateSsOverUtConfig terminal-based cw=" + mSupportsTerminalBasedCallWaiting - + ", clir=" + mSupportsTerminalBasedClir); + logi("updateSsOverUtConfig terminal-based cw " + + mSupportsTerminalBasedCallWaiting); mCbOverUtSupported.clear(); mCfOverUtSupported.clear(); @@ -539,9 +535,8 @@ public class SsDomainController { * Only for ImsPhoneMmiCode. */ public SuppServiceRoutingInfo getSuppServiceRoutingInfoForSs(String service) { - if ((SS_CW.equals(service) && getOemHandlesTerminalBasedCallWaiting()) - || (SS_CLIR.equals(service) && getOemHandlesTerminalBasedClir())) { - // Ims service handles the terminal based service by itself. + if (SS_CW.equals(service) && getOemHandlesTerminalBasedCallWaiting()) { + // Ims service handles the terminal based call waiting service by itself. // Use legacy implementation. Forward the request to Ims service if Ut is available. Phone imsPhone = mPhone.getImsPhone(); boolean isUtEnabled = (imsPhone != null) && imsPhone.isUtEnabled(); @@ -580,12 +575,12 @@ public class SsDomainController { } /** - * @param state true if Ims service handles the terminal-based service by itself. + * @param state true if Ims service handles the terminal-based call waiting service by itself. * Otherwise, false. */ - public void setOemHandlesTerminalBasedService(boolean state) { - logi("setOemHandlesTerminalBasedService " + state); - mOemHandlesTerminalBasedService = state; + public void setOemHandlesTerminalBasedCallWaiting(boolean state) { + logi("setOemHandlesTerminalBasedCallWaiting " + state); + mOemHandlesTerminalBasedCallWaiting = state; } /** @@ -594,18 +589,8 @@ public class SsDomainController { */ public boolean getOemHandlesTerminalBasedCallWaiting() { logi("getOemHandlesTerminalBasedCallWaiting " - + mSupportsTerminalBasedCallWaiting + ", " + mOemHandlesTerminalBasedService); - return mSupportsTerminalBasedCallWaiting && mOemHandlesTerminalBasedService; - } - - /** - * Returns whether the carrier supports the terminal-based CLIR - * and Ims service handles it by itself. - */ - public boolean getOemHandlesTerminalBasedClir() { - logi("getOemHandlesTerminalBasedClir " - + mSupportsTerminalBasedClir + ", " + mOemHandlesTerminalBasedService); - return mSupportsTerminalBasedClir && mOemHandlesTerminalBasedService; + + mSupportsTerminalBasedCallWaiting + ", " + mOemHandlesTerminalBasedCallWaiting); + return mSupportsTerminalBasedCallWaiting && mOemHandlesTerminalBasedCallWaiting; } /** @@ -625,9 +610,8 @@ public class SsDomainController { pw.println(" mUtAvailableWhenRoaming=" + mUtAvailableWhenRoaming); pw.println(" mUtAvailableRats=" + mUtAvailableRats); pw.println(" mWiFiAvailable=" + mWiFiAvailable); - pw.println(" mOemHandlesTerminalBasedService=" + mOemHandlesTerminalBasedService); + pw.println(" mOemHandlesTerminalBasedCallWaiting=" + mOemHandlesTerminalBasedCallWaiting); pw.println(" mSupportsTerminalBasedCallWaiting=" + mSupportsTerminalBasedCallWaiting); - pw.println(" mSupportsTerminalBasedClir=" + mSupportsTerminalBasedClir); pw.decreaseIndent(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 46fe5d32c0..5b5a2b126a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -18,7 +18,6 @@ package com.android.internal.telephony; import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; -import static com.android.internal.telephony.CommandsInterface.CLIR_SUPPRESSION; import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED; import static com.android.internal.telephony.Phone.EVENT_SRVCC_STATE_CHANGED; import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED; @@ -2258,32 +2257,4 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); verify(mImsPhone, times(1)).setCallWaiting(eq(false), any()); } - - @Test - @SmallTest - public void testOemHandlesTerminalBasedClir() throws Exception { - doReturn(true).when(mImsPhone).isUtEnabled(); - replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); - - // Ut is disabled in config - doReturn(false).when(mSsDomainController).useSsOverUt(anyString()); - doReturn(false).when(mSsDomainController).getOemHandlesTerminalBasedClir(); - - replaceInstance(GsmCdmaPhone.class, "mSsDomainController", mPhoneUT, mSsDomainController); - - mPhoneUT.getOutgoingCallerIdDisplay(null); - verify(mImsPhone, times(0)).getOutgoingCallerIdDisplay(any()); - - mPhoneUT.setOutgoingCallerIdDisplay(CLIR_SUPPRESSION, null); - verify(mImsPhone, times(0)).setOutgoingCallerIdDisplay(anyInt(), any()); - - // OEM handles the terminal-based CLIR by itself. - doReturn(true).when(mSsDomainController).getOemHandlesTerminalBasedClir(); - - mPhoneUT.getOutgoingCallerIdDisplay(null); - verify(mImsPhone, times(1)).getOutgoingCallerIdDisplay(any()); - - mPhoneUT.setOutgoingCallerIdDisplay(CLIR_SUPPRESSION, null); - verify(mImsPhone, times(1)).setOutgoingCallerIdDisplay(eq(CLIR_SUPPRESSION), any()); - } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java index 82dba86379..a0867fd4f7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java @@ -440,54 +440,19 @@ public class SsDomainControllerTest extends TelephonyTest { new int[] {}, UT_OVER_ALL, new int[] { SUPPLEMENTARY_SERVICE_CW }); String sc = mServices.get(SS_CW); - mSdc.setOemHandlesTerminalBasedService(false); + mSdc.setOemHandlesTerminalBasedCallWaiting(false); SsDomainController.SuppServiceRoutingInfo ssCode = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); assertNotNull(ssCode); assertFalse(ssCode.useSsOverUt()); - mSdc.setOemHandlesTerminalBasedService(true); + mSdc.setOemHandlesTerminalBasedCallWaiting(true); ssCode = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); assertNotNull(ssCode); assertTrue(ssCode.useSsOverUt()); } - @Test - @SmallTest - public void testOemHandlesTerminalBasedClir() { - setUtEnabled(); - - // Enable terminal-based CLIR - mSdc.updateCarrierConfigForTest(true, true, false, true, true, - new int[] {}, UT_OVER_ALL, new int[] { SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR }); - String sc = mServices.get(SS_CLIR); - - mSdc.setOemHandlesTerminalBasedService(false); - SsDomainController.SuppServiceRoutingInfo ssCode = - ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); - - assertNotNull(ssCode); - assertFalse(ssCode.useSsOverUt()); - assertFalse(mSdc.getOemHandlesTerminalBasedClir()); - - mSdc.setOemHandlesTerminalBasedService(true); - ssCode = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); - - assertNotNull(ssCode); - assertTrue(ssCode.useSsOverUt()); - assertTrue(mSdc.getOemHandlesTerminalBasedClir()); - - // Disable terminal-based CLIR - mSdc.updateCarrierConfigForTest(true, true, false, true, true, - new int[] {}, UT_OVER_ALL, new int[] {}); - ssCode = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); - - assertNotNull(ssCode); - assertFalse(ssCode.useSsOverUt()); - assertFalse(mSdc.getOemHandlesTerminalBasedClir()); - } - private void setUtEnabled() { doReturn(0).when(mImsPhone).getSubId(); mSdc.updateWifiForUt(false); -- GitLab From dafe17e6a4ec1776c6235207e9779539e9f7a1ff Mon Sep 17 00:00:00 2001 From: Hyunho Shin Date: Tue, 6 Dec 2022 03:20:13 +0000 Subject: [PATCH 237/656] Revert "Interworking between CallWaitingController and SsDomainController" This reverts commit b91f7a2f8b807d67e51a6e674f834ac247afec4e. Reason for revert: UT domain selection should go back to legacy. Change-Id: I25a78174d5ff1f1c54fe8a9d8f0053668d0730b3 --- .../internal/telephony/GsmCdmaPhone.java | 41 ------------ .../telephony/SsDomainController.java | 63 +++++-------------- .../telephony/imsphone/ImsPhoneMmiCode.java | 8 +-- .../internal/telephony/GsmCdmaPhoneTest.java | 28 --------- .../telephony/SsDomainControllerTest.java | 27 +------- 5 files changed, 20 insertions(+), 147 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 01851cb7e4..294959ba8c 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -2282,24 +2282,6 @@ public class GsmCdmaPhone extends Phone { return false; } - /** - * Checks the availability of Ut directly without SsDomainController. - * This is only applicable for the case that the terminal-based call waiting service - * is handled by the IMS service alone without interworking with CallWaitingController. - */ - private boolean useCallWaitingOverUt(Message onComplete) { - Phone imsPhone = mImsPhone; - if (imsPhone == null) { - logd("useCallWaitingOverUt: called for GsmCdma"); - return false; - } - - boolean isUtEnabled = imsPhone.isUtEnabled(); - Rlog.d(LOG_TAG, "useCallWaitingOverUt isUtEnabled= " + isUtEnabled - + " isCsRetry(onComplete))= " + isCsRetry(onComplete)); - return isUtEnabled && !isCsRetry(onComplete); - } - /** * Returns whether CSFB is supported for supplementary services. */ @@ -2307,14 +2289,6 @@ public class GsmCdmaPhone extends Phone { return mSsDomainController.supportCsfb(); } - /** - * Returns whether the carrier supports the terminal-based call waiting service - * and Ims service handles it by itself. - */ - private boolean getOemHandlesTerminalBasedCallWaiting() { - return mSsDomainController.getOemHandlesTerminalBasedCallWaiting(); - } - /** * Sends response indicating no nework is available for supplementary services. */ @@ -2674,13 +2648,6 @@ public class GsmCdmaPhone extends Phone { responseInvalidState(onComplete); return; } - } else if (getOemHandlesTerminalBasedCallWaiting()) { - // Ims service handles the terminal-based call waiting service by itself. - // Use legacy implementation. Forward the request to Ims service if Ut is available. - if (useCallWaitingOverUt(onComplete)) { - imsPhone.getCallWaiting(onComplete); - return; - } } if (isPhoneTypeGsm()) { @@ -2739,13 +2706,6 @@ public class GsmCdmaPhone extends Phone { responseInvalidState(onComplete); return; } - } else if (getOemHandlesTerminalBasedCallWaiting()) { - // Ims service handles the terminal-based call waiting service by itself. - // Use legacy implementation. Forward the request to Ims service if Ut is available. - if (useCallWaitingOverUt(onComplete)) { - imsPhone.setCallWaiting(enable, onComplete); - return; - } } if (isPhoneTypeGsm()) { @@ -2786,7 +2746,6 @@ public class GsmCdmaPhone extends Phone { @Override public void setTerminalBasedCallWaitingSupported(boolean supported) { mCallWaitingController.setTerminalBasedCallWaitingSupported(supported); - mSsDomainController.setOemHandlesTerminalBasedCallWaiting(!supported); } @Override diff --git a/src/java/com/android/internal/telephony/SsDomainController.java b/src/java/com/android/internal/telephony/SsDomainController.java index eef9b68fea..a9f14b5387 100644 --- a/src/java/com/android/internal/telephony/SsDomainController.java +++ b/src/java/com/android/internal/telephony/SsDomainController.java @@ -127,6 +127,10 @@ public class SsDomainController { public static final String SS_COLP = "COLP"; public static final String SS_COLR = "COLR"; + // Common instance indicating that Ut is available. + public static final SuppServiceRoutingInfo SS_ROUTING_OVER_UT = + new SuppServiceRoutingInfo(true, true, true); + // Barring list of incoming numbers public static final String CB_FACILITY_BIL = "BIL"; // Barring of all anonymous incoming number @@ -170,9 +174,6 @@ public class SsDomainController { private Set mUtAvailableRats = new HashSet<>(); private boolean mWiFiAvailable = false; private boolean mIsMonitoringConnectivity = false; - /** true if Ims service handles the terminal-based call waiting service by itself. */ - private boolean mOemHandlesTerminalBasedCallWaiting = false; - private boolean mSupportsTerminalBasedCallWaiting = false; public SsDomainController(GsmCdmaPhone phone) { mPhone = phone; @@ -203,16 +204,13 @@ public class SsDomainController { int[] utRats = b.getIntArray( CarrierConfigManager.ImsSs.KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY); - int[] tbServices = b.getIntArray( - CarrierConfigManager.ImsSs.KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY); - updateSsOverUtConfig(supportsUt, supportsCsfb, requiresImsRegistration, - availableWhenPsDataOff, availableWhenRoaming, services, utRats, tbServices); + availableWhenPsDataOff, availableWhenRoaming, services, utRats); } private void updateSsOverUtConfig(boolean supportsUt, boolean supportsCsfb, boolean requiresImsRegistration, boolean availableWhenPsDataOff, - boolean availableWhenRoaming, int[] services, int[] utRats, int[] tbServices) { + boolean availableWhenRoaming, int[] services, int[] utRats) { mUtSupported = supportsUt; mCsfbSupported = supportsCsfb; @@ -220,6 +218,7 @@ public class SsDomainController { mUtAvailableWhenPsDataOff = availableWhenPsDataOff; mUtAvailableWhenRoaming = availableWhenRoaming; + mSupportsTerminalBasedCallWaiting = false; if (tbServices != null) { for (int tbService : tbServices) { @@ -232,6 +231,7 @@ public class SsDomainController { logi("updateSsOverUtConfig terminal-based cw " + mSupportsTerminalBasedCallWaiting); + mCbOverUtSupported.clear(); mCfOverUtSupported.clear(); mSsOverUtSupported.clear(); @@ -535,24 +535,9 @@ public class SsDomainController { * Only for ImsPhoneMmiCode. */ public SuppServiceRoutingInfo getSuppServiceRoutingInfoForSs(String service) { - if (SS_CW.equals(service) && getOemHandlesTerminalBasedCallWaiting()) { - // Ims service handles the terminal based call waiting service by itself. - // Use legacy implementation. Forward the request to Ims service if Ut is available. - Phone imsPhone = mPhone.getImsPhone(); - boolean isUtEnabled = (imsPhone != null) && imsPhone.isUtEnabled(); - return new SuppServiceRoutingInfo(true, isUtEnabled, true); - } return new SuppServiceRoutingInfo(useSsOverUt(service), isUtEnabled(), supportCsfb()); } - /** - * Returns SuppServiceRoutingInfo instance for a service will be served by Ut interface. - * Only for ImsPhoneMmiCode. - */ - public SuppServiceRoutingInfo getSsRoutingOverUt() { - return new SuppServiceRoutingInfo(true, isUtEnabled(), true); - } - /** * Set the carrier configuration for test. * Test purpose only. @@ -560,37 +545,19 @@ public class SsDomainController { @VisibleForTesting public void updateCarrierConfigForTest(boolean supportsUt, boolean supportsCsfb, boolean requiresImsRegistration, boolean availableWhenPsDataOff, - boolean availableWhenRoaming, int[] services, int[] utRats, int[] tbServices) { - logi("updateCarrierConfigForTest supportsUt=" + supportsUt + + boolean availableWhenRoaming, int[] services, int[] utRats) { + Rlog.i(LOG_TAG, "updateCarrierConfigForTest supportsUt=" + supportsUt + + ", csfb=" + supportsCsfb + ", reg=" + requiresImsRegistration + ", whenPsDataOff=" + availableWhenPsDataOff + ", whenRoaming=" + availableWhenRoaming + ", services=" + Arrays.toString(services) - + ", rats=" + Arrays.toString(utRats) - + ", tbServices=" + Arrays.toString(tbServices)); + + ", rats=" + Arrays.toString(utRats)); updateSsOverUtConfig(supportsUt, supportsCsfb, requiresImsRegistration, - availableWhenPsDataOff, availableWhenRoaming, services, utRats, tbServices); - } - - /** - * @param state true if Ims service handles the terminal-based call waiting service by itself. - * Otherwise, false. - */ - public void setOemHandlesTerminalBasedCallWaiting(boolean state) { - logi("setOemHandlesTerminalBasedCallWaiting " + state); - mOemHandlesTerminalBasedCallWaiting = state; - } - - /** - * Returns whether the carrier supports the terminal-based call waiting service - * and Ims service handles it by itself. - */ - public boolean getOemHandlesTerminalBasedCallWaiting() { - logi("getOemHandlesTerminalBasedCallWaiting " - + mSupportsTerminalBasedCallWaiting + ", " + mOemHandlesTerminalBasedCallWaiting); - return mSupportsTerminalBasedCallWaiting && mOemHandlesTerminalBasedCallWaiting; + availableWhenPsDataOff, availableWhenRoaming, services, utRats); } /** @@ -610,8 +577,6 @@ public class SsDomainController { pw.println(" mUtAvailableWhenRoaming=" + mUtAvailableWhenRoaming); pw.println(" mUtAvailableRats=" + mUtAvailableRats); pw.println(" mWiFiAvailable=" + mWiFiAvailable); - pw.println(" mOemHandlesTerminalBasedCallWaiting=" + mOemHandlesTerminalBasedCallWaiting); - pw.println(" mSupportsTerminalBasedCallWaiting=" + mSupportsTerminalBasedCallWaiting); pw.decreaseIndent(); } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java index 1f8c8c5b17..1173d36e29 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java @@ -542,7 +542,7 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { return controller.getSuppServiceRoutingInfoForCb(scToBarringFacility(sc)); } else if (sc != null && sc.equals(SC_CFUT)) { // for backward compatibility, not specified by CarrierConfig - return controller.getSsRoutingOverUt(); + return SsDomainController.SS_ROUTING_OVER_UT; } else if (sc != null && sc.equals(SC_CLIP)) { return controller.getSuppServiceRoutingInfoForSs(SS_CLIP); } else if (sc != null && sc.equals(SC_CLIR)) { @@ -553,7 +553,7 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { return controller.getSuppServiceRoutingInfoForSs(SS_COLR); } else if (sc != null && sc.equals(SC_CNAP)) { // for backward compatibility, not specified by CarrierConfig - return controller.getSsRoutingOverUt(); + return SsDomainController.SS_ROUTING_OVER_UT; } else if (sc != null && sc.equals(SC_BS_MT)) { return controller.getSuppServiceRoutingInfoForCb( SsDomainController.CB_FACILITY_BIL); @@ -562,12 +562,12 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { SsDomainController.CB_FACILITY_ACR); } else if (sc != null && sc.equals(SC_PWD)) { // for backward compatibility, not specified by CarrierConfig - return controller.getSsRoutingOverUt(); + return SsDomainController.SS_ROUTING_OVER_UT; } else if (sc != null && sc.equals(SC_WAIT)) { return controller.getSuppServiceRoutingInfoForSs(SS_CW); } else if (isPinPukCommand(sc)) { // for backward compatibility, not specified by CarrierConfig - return controller.getSsRoutingOverUt(); + return SsDomainController.SS_ROUTING_OVER_UT; } } return null; diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 5b5a2b126a..860db01166 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -2229,32 +2229,4 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); verify(mImsPhone, times(1)).setCallWaiting(eq(false), any()); } - - @Test - @SmallTest - public void testOemHandlesTerminalBasedCallWaiting() throws Exception { - doReturn(true).when(mImsPhone).isUtEnabled(); - replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); - - // Ut is disabled in config - doReturn(false).when(mSsDomainController).useSsOverUt(anyString()); - doReturn(false).when(mSsDomainController).getOemHandlesTerminalBasedCallWaiting(); - - replaceInstance(GsmCdmaPhone.class, "mSsDomainController", mPhoneUT, mSsDomainController); - - mPhoneUT.getCallWaiting(null); - verify(mImsPhone, times(0)).getCallWaiting(any()); - - mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); - verify(mImsPhone, times(0)).setCallWaiting(eq(false), any()); - - // OEM handles the terminal-based call waiting service by itself. - doReturn(true).when(mSsDomainController).getOemHandlesTerminalBasedCallWaiting(); - - mPhoneUT.getCallWaiting(null); - verify(mImsPhone, times(1)).getCallWaiting(any()); - - mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); - verify(mImsPhone, times(1)).setCallWaiting(eq(false), any()); - } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java index a0867fd4f7..53679e0dbe 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java @@ -430,29 +430,6 @@ public class SsDomainControllerTest extends TelephonyTest { assertFalse(mSdc.isUtEnabled()); } - @Test - @SmallTest - public void testOemHandlesTerminalBasedCallWaiting() { - setUtEnabled(); - - // Enable terminal-based call waiting - mSdc.updateCarrierConfigForTest(true, true, false, true, true, - new int[] {}, UT_OVER_ALL, new int[] { SUPPLEMENTARY_SERVICE_CW }); - String sc = mServices.get(SS_CW); - - mSdc.setOemHandlesTerminalBasedCallWaiting(false); - SsDomainController.SuppServiceRoutingInfo ssCode = - ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); - assertNotNull(ssCode); - assertFalse(ssCode.useSsOverUt()); - - mSdc.setOemHandlesTerminalBasedCallWaiting(true); - ssCode = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); - - assertNotNull(ssCode); - assertTrue(ssCode.useSsOverUt()); - } - private void setUtEnabled() { doReturn(0).when(mImsPhone).getSubId(); mSdc.updateWifiForUt(false); @@ -489,10 +466,10 @@ public class SsDomainControllerTest extends TelephonyTest { private void updateCarrierConfig(boolean supportsCsfb, boolean requiresImsRegistration, boolean availableWhenPsDataOff, boolean availableWhenRoaming, int[] utRats) { mSdc.updateCarrierConfigForTest(true, supportsCsfb, requiresImsRegistration, - availableWhenPsDataOff, availableWhenRoaming, null, utRats, null); + availableWhenPsDataOff, availableWhenRoaming, null, utRats); } private void updateCarrierConfig(int[] services) { - mSdc.updateCarrierConfigForTest(true, true, false, true, true, services, UT_OVER_ALL, null); + mSdc.updateCarrierConfigForTest(true, true, false, true, true, services, UT_OVER_ALL); } } -- GitLab From 4aa218e7192b111d9dc0d685ff5676282d4bd983 Mon Sep 17 00:00:00 2001 From: Hyunho Shin Date: Tue, 6 Dec 2022 02:35:00 +0000 Subject: [PATCH 238/656] Revert "Implement the domain selection of supplementary services over Ut" This reverts commit b45853e3db2c9cf33ff53821f8566a5144c2741b. Reason for revert: UT domain selection should go back to legacy. Change-Id: I47aea220aaec0ccfe8c29fa9effd8ea31fa7e304 --- .../internal/telephony/GsmCdmaPhone.java | 189 ++---- .../com/android/internal/telephony/Phone.java | 12 +- .../telephony/SsDomainController.java | 590 ------------------ .../internal/telephony/gsm/GsmMmiCode.java | 15 - .../telephony/imsphone/ImsPhoneMmiCode.java | 74 +-- .../internal/telephony/GsmCdmaPhoneTest.java | 146 ----- .../telephony/SsDomainControllerTest.java | 475 -------------- .../internal/telephony/TelephonyTest.java | 2 - .../imsphone/ImsPhoneMmiCodeTest.java | 31 - 9 files changed, 72 insertions(+), 1462 deletions(-) delete mode 100644 src/java/com/android/internal/telephony/SsDomainController.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 294959ba8c..e7a9f0b4ed 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -29,9 +29,6 @@ import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REA import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; -import static com.android.internal.telephony.SsDomainController.SS_CLIP; -import static com.android.internal.telephony.SsDomainController.SS_CLIR; -import static com.android.internal.telephony.SsDomainController.SS_CW; import android.annotation.NonNull; import android.annotation.Nullable; @@ -266,8 +263,6 @@ public class GsmCdmaPhone extends Phone { private boolean mResetModemOnRadioTechnologyChange = false; private boolean mSsOverCdmaSupported = false; - private SsDomainController mSsDomainController; - private int mRilVersion; private boolean mBroadcastEmergencyCallStateChanges = false; private @ServiceState.RegState int mTelecomVoiceServiceStateOverride = @@ -386,8 +381,6 @@ public class GsmCdmaPhone extends Phone { subMan.addOnSubscriptionsChangedListener( new HandlerExecutor(this), mSubscriptionsChangedListener); - mSsDomainController = new SsDomainController(this); - logd("GsmCdmaPhone: constructor: sub = " + mPhoneId); } @@ -1375,10 +1368,9 @@ public class GsmCdmaPhone extends Phone { stripSeparators(dialString)); boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#")) && dialPart.endsWith("#"); - SsDomainController.SuppServiceRoutingInfo ssInfo = - ImsPhoneMmiCode.getSuppServiceRoutingInfo(dialPart, this); - boolean isPotentialUssdCode = isMmiCode && (ssInfo == null); - boolean useImsForUt = ssInfo != null && ssInfo.useSsOverUt(); + boolean isSuppServiceCode = ImsPhoneMmiCode.isSuppServiceCodes(dialPart, this); + boolean isPotentialUssdCode = isMmiCode && !isSuppServiceCode; + boolean useImsForUt = imsPhone != null && imsPhone.isUtEnabled(); boolean useImsForCall = useImsForCall(dialArgs) && (isWpsCall ? allowWpsOverIms : true); @@ -1389,8 +1381,7 @@ public class GsmCdmaPhone extends Phone { + ", useImsForEmergency=" + useImsForEmergency + ", useImsForUt=" + useImsForUt + ", isUt=" + isMmiCode - + ", isSuppServiceCode=" + (ssInfo != null) - + ", useSsOverUt=" + (ssInfo != null && ssInfo.useSsOverUt()) + + ", isSuppServiceCode=" + isSuppServiceCode + ", isPotentialUssdCode=" + isPotentialUssdCode + ", isWpsCall=" + isWpsCall + ", allowWpsOverIms=" + allowWpsOverIms @@ -1446,10 +1437,6 @@ public class GsmCdmaPhone extends Phone { } } - if (ssInfo != null && !ssInfo.supportsCsfb()) { - throw new CallStateException("not support csfb for supplementary services"); - } - if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE && mSST.mSS.getDataRegistrationState() != ServiceState.STATE_IN_SERVICE && !isEmergency) { @@ -2245,36 +2232,12 @@ public class GsmCdmaPhone extends Phone { mSsOverCdmaSupported = b.getBoolean(CarrierConfigManager.KEY_SUPPORT_SS_OVER_CDMA_BOOL); } - private void updateSsOverUtConfig(PersistableBundle b) { - mSsDomainController.updateSsOverUtConfig(b); - } - - @Override - public SsDomainController getSsDomainController() { - return mSsDomainController; - } - - /** Checks the static configuration for the given Call Barring service. */ - public boolean useCbOverUt(String facility) { - return mSsDomainController.useCbOverUt(facility); - } - - /** Checks the static configuration for the given Call Forwarding service. */ - public boolean useCfOverUt(int reason) { - return mSsDomainController.useCfOverUt(reason); - } - - /** Checks the static configuration for the given supplementary service. */ - public boolean useSsOverUt(String service) { - return mSsDomainController.useSsOverUt(service); - } - @Override - public boolean useSsOverUt(Message onComplete) { + public boolean useSsOverIms(Message onComplete) { boolean isUtEnabled = isUtEnabled(); - Rlog.d(LOG_TAG, "useSsOverUt: isUtEnabled()= " + isUtEnabled - + " isCsRetry(onComplete))= " + isCsRetry(onComplete)); + Rlog.d(LOG_TAG, "useSsOverIms: isUtEnabled()= " + isUtEnabled + + " isCsRetry(onComplete))= " + isCsRetry(onComplete)); if (isUtEnabled && !isCsRetry(onComplete)) { return true; @@ -2282,24 +2245,6 @@ public class GsmCdmaPhone extends Phone { return false; } - /** - * Returns whether CSFB is supported for supplementary services. - */ - public boolean supportCsfbForSs() { - return mSsDomainController.supportCsfb(); - } - - /** - * Sends response indicating no nework is available for supplementary services. - */ - private void responseInvalidState(Message onComplete) { - if (onComplete == null) return; - AsyncResult.forMessage(onComplete, null, - new CommandException(CommandException.Error.INVALID_STATE, - "No network available for supplementary services")); - onComplete.sendToTarget(); - } - @Override public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { getCallForwardingOption(commandInterfaceCFReason, @@ -2319,15 +2264,9 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useCfOverUt(commandInterfaceCFReason)) { - if (useSsOverUt(onComplete)) { - imsPhone.getCallForwardingOption(commandInterfaceCFReason, - serviceClass, onComplete); - return; - } else if (!supportCsfbForSs()) { - responseInvalidState(onComplete); - return; - } + if (useSsOverIms(onComplete)) { + imsPhone.getCallForwardingOption(commandInterfaceCFReason, serviceClass, onComplete); + return; } if (isPhoneTypeGsm()) { @@ -2384,15 +2323,10 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useCfOverUt(commandInterfaceCFReason)) { - if (useSsOverUt(onComplete)) { - imsPhone.setCallForwardingOption(commandInterfaceCFAction, commandInterfaceCFReason, - dialingNumber, serviceClass, timerSeconds, onComplete); - return; - } else if (!supportCsfbForSs()) { - responseInvalidState(onComplete); - return; - } + if (useSsOverIms(onComplete)) { + imsPhone.setCallForwardingOption(commandInterfaceCFAction, commandInterfaceCFReason, + dialingNumber, serviceClass, timerSeconds, onComplete); + return; } if (isPhoneTypeGsm()) { @@ -2451,14 +2385,9 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useCbOverUt(facility)) { - if (useSsOverUt(onComplete)) { - imsPhone.getCallBarring(facility, password, onComplete, serviceClass); - return; - } else if (!supportCsfbForSs()) { - responseInvalidState(onComplete); - return; - } + if (useSsOverIms(onComplete)) { + imsPhone.getCallBarring(facility, password, onComplete, serviceClass); + return; } if (isPhoneTypeGsm()) { @@ -2483,14 +2412,9 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useCbOverUt(facility)) { - if (useSsOverUt(onComplete)) { - imsPhone.setCallBarring(facility, lockState, password, onComplete, serviceClass); - return; - } else if (!supportCsfbForSs()) { - responseInvalidState(onComplete); - return; - } + if (useSsOverIms(onComplete)) { + imsPhone.setCallBarring(facility, lockState, password, onComplete, serviceClass); + return; } if (isPhoneTypeGsm()) { @@ -2540,14 +2464,10 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverUt(SS_CLIR)) { - if (useSsOverUt(onComplete)) { - imsPhone.getOutgoingCallerIdDisplay(onComplete); - return; - } else if (!supportCsfbForSs()) { - responseInvalidState(onComplete); - return; - } + + if (useSsOverIms(onComplete)) { + imsPhone.getOutgoingCallerIdDisplay(onComplete); + return; } if (isPhoneTypeGsm()) { @@ -2572,14 +2492,9 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverUt(SS_CLIR)) { - if (useSsOverUt(onComplete)) { - imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete); - return; - } else if (!supportCsfbForSs()) { - responseInvalidState(onComplete); - return; - } + if (useSsOverIms(onComplete)) { + imsPhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete); + return; } if (isPhoneTypeGsm()) { @@ -2607,14 +2522,9 @@ public class GsmCdmaPhone extends Phone { } Phone imsPhone = mImsPhone; - if (useSsOverUt(SS_CLIP)) { - if (useSsOverUt(onComplete)) { - imsPhone.queryCLIP(onComplete); - return; - } else if (!supportCsfbForSs()) { - responseInvalidState(onComplete); - return; - } + if (useSsOverIms(onComplete)) { + imsPhone.queryCLIP(onComplete); + return; } if (isPhoneTypeGsm()) { @@ -2640,14 +2550,9 @@ public class GsmCdmaPhone extends Phone { if (mCallWaitingController.getCallWaiting(onComplete)) return; Phone imsPhone = mImsPhone; - if (useSsOverUt(SS_CW)) { - if (useSsOverUt(onComplete)) { - imsPhone.getCallWaiting(onComplete); - return; - } else if (!supportCsfbForSs()) { - responseInvalidState(onComplete); - return; - } + if (useSsOverIms(onComplete)) { + imsPhone.getCallWaiting(onComplete); + return; } if (isPhoneTypeGsm()) { @@ -2698,14 +2603,9 @@ public class GsmCdmaPhone extends Phone { if (mCallWaitingController.setCallWaiting(enable, serviceClass, onComplete)) return; Phone imsPhone = mImsPhone; - if (useSsOverUt(SS_CW)) { - if (useSsOverUt(onComplete)) { - imsPhone.setCallWaiting(enable, onComplete); - return; - } else if (!supportCsfbForSs()) { - responseInvalidState(onComplete); - return; - } + if (useSsOverIms(onComplete)) { + imsPhone.setCallWaiting(enable, onComplete); + return; } if (isPhoneTypeGsm()) { @@ -3185,7 +3085,6 @@ public class GsmCdmaPhone extends Phone { updateVoNrSettings(b); updateSsOverCdmaSupported(b); loadAllowedNetworksFromSubscriptionDatabase(); - updateSsOverUtConfig(b); // Obtain new radio capabilities from the modem, since some are SIM-dependent mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY)); break; @@ -4391,14 +4290,6 @@ public class GsmCdmaPhone extends Phone { + ServiceState.rilServiceStateToString(mTelecomVoiceServiceStateOverride) + ")"); pw.flush(); - - try { - mSsDomainController.dump(pw); - } catch (Exception e) { - e.printStackTrace(); - } - pw.flush(); - try { mCallWaitingController.dump(pw); } catch (Exception e) { @@ -4701,7 +4592,13 @@ public class GsmCdmaPhone extends Phone { @Override public boolean isUtEnabled() { - return mSsDomainController.isUtEnabled(); + Phone imsPhone = mImsPhone; + if (imsPhone != null) { + return imsPhone.isUtEnabled(); + } else { + logd("isUtEnabled: called for GsmCdma"); + return false; + } } public String getDtmfToneDelayKey() { diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 3bf0a4f7de..389818a227 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -4770,17 +4770,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } - /** - * Returns the instance of SsDomainController - */ - public SsDomainController getSsDomainController() { - return null; - } - - /** - * Returns whether it will be served with Ut or not. - */ - public boolean useSsOverUt(Message onComplete) { + public boolean useSsOverIms(Message onComplete) { return false; } diff --git a/src/java/com/android/internal/telephony/SsDomainController.java b/src/java/com/android/internal/telephony/SsDomainController.java deleted file mode 100644 index a9f14b5387..0000000000 --- a/src/java/com/android/internal/telephony/SsDomainController.java +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN; -import static android.telephony.AccessNetworkConstants.AccessNetworkType.GERAN; -import static android.telephony.AccessNetworkConstants.AccessNetworkType.IWLAN; -import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN; -import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_ACR; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_ALL; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BAIC; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BAOC; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BIC_ROAM; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BIL; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BOIC; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BOIC_EXHC; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_IBS; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_OBS; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_ALL; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_ALL_CONDITONAL_FORWARDING; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFB; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFNRC; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFNRY; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFU; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CW; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIP; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIP; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIR; - -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOIC; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOICxH; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; -import android.os.PersistableBundle; -import android.os.SystemProperties; -import android.provider.Settings; -import android.telephony.AccessNetworkConstants; -import android.telephony.CarrierConfigManager; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.ServiceState; -import android.telephony.TelephonyManager; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.IndentingPrintWriter; -import com.android.telephony.Rlog; - -import java.io.PrintWriter; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * The cache of the carrier configuration - */ -public class SsDomainController { - private static final String LOG_TAG = "SsDomainController"; - - /** - * A Helper class to carry the information indicating Ut is available or not. - */ - public static class SuppServiceRoutingInfo { - private final boolean mUseSsOverUt; - private final boolean mSupportsCsfb; - - public SuppServiceRoutingInfo(boolean useSsOverUt, - boolean isUtEnabled, boolean supportsCsfb) { - if (useSsOverUt) { - mUseSsOverUt = isUtEnabled; - mSupportsCsfb = supportsCsfb; - } else { - mUseSsOverUt = false; - mSupportsCsfb = true; - } - } - - /** - * Returns whether Ut is available. - */ - public boolean useSsOverUt() { - return mUseSsOverUt; - } - - /** - * Returns whether CSFB is allowed. - */ - public boolean supportsCsfb() { - return mSupportsCsfb; - } - } - - public static final String SS_CW = "CW"; - public static final String SS_CLIP = "CLIP"; - public static final String SS_CLIR = "CLIR"; - public static final String SS_COLP = "COLP"; - public static final String SS_COLR = "COLR"; - - // Common instance indicating that Ut is available. - public static final SuppServiceRoutingInfo SS_ROUTING_OVER_UT = - new SuppServiceRoutingInfo(true, true, true); - - // Barring list of incoming numbers - public static final String CB_FACILITY_BIL = "BIL"; - // Barring of all anonymous incoming number - public static final String CB_FACILITY_ACR = "ACR"; - - /** - * Network callback used to determine whether Wi-Fi is connected or not. - */ - private ConnectivityManager.NetworkCallback mNetworkCallback = - new ConnectivityManager.NetworkCallback() { - @Override - public void onAvailable(Network network) { - logi("Network available: " + network); - updateWifiForUt(true); - } - - @Override - public void onLost(Network network) { - logi("Network lost: " + network); - updateWifiForUt(false); - } - - @Override - public void onUnavailable() { - logi("Network unavailable"); - updateWifiForUt(false); - } - }; - - private final GsmCdmaPhone mPhone; - - private final HashSet mCbOverUtSupported = new HashSet<>(); - private final HashSet mCfOverUtSupported = new HashSet<>(); - private final HashSet mSsOverUtSupported = new HashSet<>(); - private boolean mUtSupported = false; - private boolean mCsfbSupported = true; - - private boolean mUtRequiresImsRegistration = false; - private boolean mUtAvailableWhenPsDataOff = false; - private boolean mUtAvailableWhenRoaming = false; - private Set mUtAvailableRats = new HashSet<>(); - private boolean mWiFiAvailable = false; - private boolean mIsMonitoringConnectivity = false; - - public SsDomainController(GsmCdmaPhone phone) { - mPhone = phone; - } - - /** - * Cache the configurations - */ - public void updateSsOverUtConfig(PersistableBundle b) { - if (b == null) { - b = CarrierConfigManager.getDefaultConfig(); - } - - boolean supportsCsfb = b.getBoolean( - CarrierConfigManager.ImsSs.KEY_USE_CSFB_ON_XCAP_OVER_UT_FAILURE_BOOL); - boolean requiresImsRegistration = b.getBoolean( - CarrierConfigManager.ImsSs.KEY_UT_REQUIRES_IMS_REGISTRATION_BOOL); - boolean availableWhenPsDataOff = b.getBoolean( - CarrierConfigManager.ImsSs.KEY_UT_SUPPORTED_WHEN_PS_DATA_OFF_BOOL); - boolean availableWhenRoaming = b.getBoolean( - CarrierConfigManager.ImsSs.KEY_UT_SUPPORTED_WHEN_ROAMING_BOOL); - - boolean supportsUt = b.getBoolean( - CarrierConfigManager.KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL); - int[] services = b.getIntArray( - CarrierConfigManager.ImsSs.KEY_UT_SERVER_BASED_SERVICES_INT_ARRAY); - - int[] utRats = b.getIntArray( - CarrierConfigManager.ImsSs.KEY_XCAP_OVER_UT_SUPPORTED_RATS_INT_ARRAY); - - updateSsOverUtConfig(supportsUt, supportsCsfb, requiresImsRegistration, - availableWhenPsDataOff, availableWhenRoaming, services, utRats); - } - - private void updateSsOverUtConfig(boolean supportsUt, boolean supportsCsfb, - boolean requiresImsRegistration, boolean availableWhenPsDataOff, - boolean availableWhenRoaming, int[] services, int[] utRats) { - - mUtSupported = supportsUt; - mCsfbSupported = supportsCsfb; - mUtRequiresImsRegistration = requiresImsRegistration; - mUtAvailableWhenPsDataOff = availableWhenPsDataOff; - mUtAvailableWhenRoaming = availableWhenRoaming; - - - mSupportsTerminalBasedCallWaiting = false; - if (tbServices != null) { - for (int tbService : tbServices) { - if (tbService == SUPPLEMENTARY_SERVICE_CW) { - mSupportsTerminalBasedCallWaiting = true; - break; - } - } - } - logi("updateSsOverUtConfig terminal-based cw " - + mSupportsTerminalBasedCallWaiting); - - - mCbOverUtSupported.clear(); - mCfOverUtSupported.clear(); - mSsOverUtSupported.clear(); - mUtAvailableRats.clear(); - - if (!mUtSupported) { - logd("updateSsOverUtConfig Ut is not supported"); - unregisterForConnectivityChanges(); - return; - } - - if (services != null) { - for (int service : services) { - updateConfig(service); - } - } - - if (utRats != null) { - mUtAvailableRats = Arrays.stream(utRats).boxed().collect(Collectors.toSet()); - } - - if (mUtAvailableRats.contains(IWLAN)) { - registerForConnectivityChanges(); - } else { - unregisterForConnectivityChanges(); - } - - logi("updateSsOverUtConfig supportsUt=" + mUtSupported - + ", csfb=" + mCsfbSupported - + ", regRequire=" + mUtRequiresImsRegistration - + ", whenPsDataOff=" + mUtAvailableWhenPsDataOff - + ", whenRoaming=" + mUtAvailableWhenRoaming - + ", cbOverUtSupported=" + mCbOverUtSupported - + ", cfOverUtSupported=" + mCfOverUtSupported - + ", ssOverUtSupported=" + mSsOverUtSupported - + ", utAvailableRats=" + mUtAvailableRats - + ", including IWLAN=" + mUtAvailableRats.contains(IWLAN)); - } - - private void updateConfig(int service) { - switch(service) { - case SUPPLEMENTARY_SERVICE_CW: mSsOverUtSupported.add(SS_CW); return; - - case SUPPLEMENTARY_SERVICE_CF_ALL: mCfOverUtSupported.add(CF_REASON_ALL); return; - case SUPPLEMENTARY_SERVICE_CF_CFU: - mCfOverUtSupported.add(CF_REASON_UNCONDITIONAL); - return; - case SUPPLEMENTARY_SERVICE_CF_ALL_CONDITONAL_FORWARDING: - mCfOverUtSupported.add(CF_REASON_ALL_CONDITIONAL); - return; - case SUPPLEMENTARY_SERVICE_CF_CFB: mCfOverUtSupported.add(CF_REASON_BUSY); return; - case SUPPLEMENTARY_SERVICE_CF_CFNRY: mCfOverUtSupported.add(CF_REASON_NO_REPLY); return; - case SUPPLEMENTARY_SERVICE_CF_CFNRC: - mCfOverUtSupported.add(CF_REASON_NOT_REACHABLE); - return; - - case SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIP: mSsOverUtSupported.add(SS_CLIP); return; - case SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIP: mSsOverUtSupported.add(SS_COLP); return; - case SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR: mSsOverUtSupported.add(SS_CLIR); return; - case SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIR: mSsOverUtSupported.add(SS_COLR); return; - - case SUPPLEMENTARY_SERVICE_CB_BAOC: mCbOverUtSupported.add(CB_FACILITY_BAOC); return; - case SUPPLEMENTARY_SERVICE_CB_BOIC: mCbOverUtSupported.add(CB_FACILITY_BAOIC); return; - case SUPPLEMENTARY_SERVICE_CB_BOIC_EXHC: - mCbOverUtSupported.add(CB_FACILITY_BAOICxH); - return; - case SUPPLEMENTARY_SERVICE_CB_BAIC: mCbOverUtSupported.add(CB_FACILITY_BAIC); return; - case SUPPLEMENTARY_SERVICE_CB_BIC_ROAM: - mCbOverUtSupported.add(CB_FACILITY_BAICr); - return; - case SUPPLEMENTARY_SERVICE_CB_ACR: mCbOverUtSupported.add(CB_FACILITY_ACR); return; - case SUPPLEMENTARY_SERVICE_CB_BIL: mCbOverUtSupported.add(CB_FACILITY_BIL); return; - case SUPPLEMENTARY_SERVICE_CB_ALL: mCbOverUtSupported.add(CB_FACILITY_BA_ALL); return; - case SUPPLEMENTARY_SERVICE_CB_OBS: mCbOverUtSupported.add(CB_FACILITY_BA_MO); return; - case SUPPLEMENTARY_SERVICE_CB_IBS: mCbOverUtSupported.add(CB_FACILITY_BA_MT); return; - - default: - break; - } - } - - /** - * Determines whether Ut service is available or not. - * - * @return {@code true} if Ut service is available - */ - @VisibleForTesting - public boolean isUtEnabled() { - Phone imsPhone = mPhone.getImsPhone(); - if (imsPhone == null) { - logd("isUtEnabled: called for GsmCdma"); - return false; - } - - if (!mUtSupported) { - logd("isUtEnabled: not supported"); - return false; - } - - if (mUtRequiresImsRegistration - && imsPhone.getServiceState().getState() != ServiceState.STATE_IN_SERVICE) { - logd("isUtEnabled: not registered"); - return false; - } - - if (isUtAvailableOnAnyTransport()) { - return imsPhone.isUtEnabled(); - } - - return false; - } - - private boolean isMobileDataEnabled() { - boolean enabled; - int state = Settings.Global.getInt(mPhone.getContext().getContentResolver(), - Settings.Global.MOBILE_DATA, -1); - if (state == -1) { - logi("isMobileDataEnabled MOBILE_DATA not found"); - enabled = "true".equalsIgnoreCase( - SystemProperties.get("ro.com.android.mobiledata", "true")); - } else { - enabled = (state != 0); - } - logi("isMobileDataEnabled enabled=" + enabled); - return enabled; - } - - private boolean isUtAvailableOnAnyTransport() { - if (mUtAvailableWhenPsDataOff || isMobileDataEnabled()) { - if (isUtAvailableOverCellular()) { - logi("isUtAvailableOnAnyTransport found cellular"); - return true; - } - } - - logi("isUtAvailableOnAnyTransport wifiConnected=" + mWiFiAvailable); - if (mWiFiAvailable) { - if (mUtAvailableRats.contains(IWLAN)) { - logi("isUtAvailableOnAnyTransport found wifi"); - return true; - } - logi("isUtAvailableOnAnyTransport wifi not support Ut"); - } - - logi("isUtAvailableOnAnyTransport no transport"); - return false; - } - - private boolean isUtAvailableOverCellular() { - NetworkRegistrationInfo nri = mPhone.getServiceState().getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - if (nri != null && nri.isRegistered()) { - if (!mUtAvailableWhenRoaming && nri.isRoaming()) { - logi("isUtAvailableOverCellular not available in roaming"); - return false; - } - - int networkType = nri.getAccessNetworkTechnology(); - switch (networkType) { - case TelephonyManager.NETWORK_TYPE_NR: - if (mUtAvailableRats.contains(NGRAN)) return true; - break; - case TelephonyManager.NETWORK_TYPE_LTE: - if (mUtAvailableRats.contains(EUTRAN)) return true; - break; - - case TelephonyManager.NETWORK_TYPE_UMTS: - case TelephonyManager.NETWORK_TYPE_HSDPA: - case TelephonyManager.NETWORK_TYPE_HSUPA: - case TelephonyManager.NETWORK_TYPE_HSPA: - case TelephonyManager.NETWORK_TYPE_HSPAP: - if (mUtAvailableRats.contains(UTRAN)) return true; - break; - case TelephonyManager.NETWORK_TYPE_GPRS: - case TelephonyManager.NETWORK_TYPE_EDGE: - case TelephonyManager.NETWORK_TYPE_GSM: - if (mUtAvailableRats.contains(GERAN)) return true; - break; - default: - break; - } - } - - logi("isUtAvailableOverCellular no cellular"); - return false; - } - - /** - * Updates the Wi-Fi connection state. - */ - @VisibleForTesting - public void updateWifiForUt(boolean available) { - mWiFiAvailable = available; - } - - /** - * Registers for changes to network connectivity. - */ - private void registerForConnectivityChanges() { - if (mIsMonitoringConnectivity) { - return; - } - - ConnectivityManager cm = (ConnectivityManager) mPhone.getContext() - .getSystemService(Context.CONNECTIVITY_SERVICE); - if (cm != null) { - logi("registerForConnectivityChanges"); - NetworkRequest.Builder builder = new NetworkRequest.Builder(); - builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); - cm.registerNetworkCallback(builder.build(), mNetworkCallback); - mIsMonitoringConnectivity = true; - } - } - - /** - * Unregisters for connectivity changes. - */ - private void unregisterForConnectivityChanges() { - if (!mIsMonitoringConnectivity) { - return; - } - - ConnectivityManager cm = (ConnectivityManager) mPhone.getContext() - .getSystemService(Context.CONNECTIVITY_SERVICE); - if (cm != null) { - logi("unregisterForConnectivityChanges"); - cm.unregisterNetworkCallback(mNetworkCallback); - mIsMonitoringConnectivity = false; - } - } - - /** - * Returns whether Ut is available for the given Call Barring service. - */ - @VisibleForTesting - public boolean useCbOverUt(String facility) { - if (!mUtSupported) { - logd("useCbOverUt: Ut not supported"); - return false; - } - - return mCbOverUtSupported.contains(facility); - } - - /** - * Returns whether Ut is available for the given Call Forwarding service. - */ - @VisibleForTesting - public boolean useCfOverUt(int reason) { - if (!mUtSupported) { - logd("useCfOverUt: Ut not supported"); - return false; - } - - return mCfOverUtSupported.contains(reason); - } - - /** - * Returns whether Ut is available for the given supplementary service. - */ - @VisibleForTesting - public boolean useSsOverUt(String service) { - if (!mUtSupported) { - logd("useSsOverUt: Ut not supported"); - return false; - } - - return mSsOverUtSupported.contains(service); - } - - /** - * Returns whether CSFB is supported for supplementary services. - */ - public boolean supportCsfb() { - if (!mUtSupported) { - logd("supportsCsfb: Ut not supported"); - return true; - } - - return mCsfbSupported; - } - - /** - * Returns SuppServiceRoutingInfo instance for the given Call Barring service. - * Only for ImsPhoneMmiCode. - */ - public SuppServiceRoutingInfo getSuppServiceRoutingInfoForCb(String facility) { - return new SuppServiceRoutingInfo(useCbOverUt(facility), isUtEnabled(), supportCsfb()); - } - - /** - * Returns SuppServiceRoutingInfo instance for the given Call Forwarding service. - * Only for ImsPhoneMmiCode. - */ - public SuppServiceRoutingInfo getSuppServiceRoutingInfoForCf(int reason) { - return new SuppServiceRoutingInfo(useCfOverUt(reason), isUtEnabled(), supportCsfb()); - } - - /** - * Returns SuppServiceRoutingInfo instance for the given supplementary service. - * Only for ImsPhoneMmiCode. - */ - public SuppServiceRoutingInfo getSuppServiceRoutingInfoForSs(String service) { - return new SuppServiceRoutingInfo(useSsOverUt(service), isUtEnabled(), supportCsfb()); - } - - /** - * Set the carrier configuration for test. - * Test purpose only. - */ - @VisibleForTesting - public void updateCarrierConfigForTest(boolean supportsUt, boolean supportsCsfb, - boolean requiresImsRegistration, boolean availableWhenPsDataOff, - - boolean availableWhenRoaming, int[] services, int[] utRats) { - Rlog.i(LOG_TAG, "updateCarrierConfigForTest supportsUt=" + supportsUt - - + ", csfb=" + supportsCsfb - + ", reg=" + requiresImsRegistration - + ", whenPsDataOff=" + availableWhenPsDataOff - + ", whenRoaming=" + availableWhenRoaming - + ", services=" + Arrays.toString(services) - + ", rats=" + Arrays.toString(utRats)); - - updateSsOverUtConfig(supportsUt, supportsCsfb, requiresImsRegistration, - availableWhenPsDataOff, availableWhenRoaming, services, utRats); - } - - /** - * Dump this instance into a readable format for dumpsys usage. - */ - public void dump(PrintWriter printWriter) { - IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); - pw.increaseIndent(); - pw.println("SsDomainController:"); - pw.println(" mUtSupported=" + mUtSupported); - pw.println(" mCsfbSupported=" + mCsfbSupported); - pw.println(" mCbOverUtSupported=" + mCbOverUtSupported); - pw.println(" mCfOverUtSupported=" + mCfOverUtSupported); - pw.println(" mSsOverUtSupported=" + mSsOverUtSupported); - pw.println(" mUtRequiresImsRegistration=" + mUtRequiresImsRegistration); - pw.println(" mUtAvailableWhenPsDataOff=" + mUtAvailableWhenPsDataOff); - pw.println(" mUtAvailableWhenRoaming=" + mUtAvailableWhenRoaming); - pw.println(" mUtAvailableRats=" + mUtAvailableRats); - pw.println(" mWiFiAvailable=" + mWiFiAvailable); - pw.decreaseIndent(); - } - - private void logi(String msg) { - Rlog.i(LOG_TAG, "[" + mPhone.getPhoneId() + "] " + msg); - } - - private void logd(String msg) { - Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "] " + msg); - } -} diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 58e03ae4c3..9de3ee9e69 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -1049,9 +1049,6 @@ public final class GsmMmiCode extends Handler implements MmiCode { throw new RuntimeException ("Invalid or Unsupported MMI Code"); } else if (mSc != null && mSc.equals(SC_CLIP)) { Rlog.d(LOG_TAG, "processCode: is CLIP"); - if (!mPhone.supportCsfbForSs()) { - throw new RuntimeException("No network to support supplementary services"); - } if (isInterrogate()) { mPhone.mCi.queryCLIP( obtainMessage(EVENT_QUERY_COMPLETE, this)); @@ -1060,9 +1057,6 @@ public final class GsmMmiCode extends Handler implements MmiCode { } } else if (mSc != null && mSc.equals(SC_CLIR)) { Rlog.d(LOG_TAG, "processCode: is CLIR"); - if (!mPhone.supportCsfbForSs()) { - throw new RuntimeException("No network to support supplementary services"); - } if (isActivate() && !mPhone.isClirActivationAndDeactivationPrevented()) { mPhone.mCi.setCLIR(CommandsInterface.CLIR_INVOCATION, obtainMessage(EVENT_SET_COMPLETE, this)); @@ -1077,9 +1071,6 @@ public final class GsmMmiCode extends Handler implements MmiCode { } } else if (isServiceCodeCallForwarding(mSc)) { Rlog.d(LOG_TAG, "processCode: is CF"); - if (!mPhone.supportCsfbForSs()) { - throw new RuntimeException("No network to support supplementary services"); - } String dialingNumber = mSia; int serviceClass = siToServiceClass(mSib); @@ -1127,9 +1118,6 @@ public final class GsmMmiCode extends Handler implements MmiCode { isEnableDesired, this)); } } else if (isServiceCodeCallBarring(mSc)) { - if (!mPhone.supportCsfbForSs()) { - throw new RuntimeException("No network to support supplementary services"); - } // sia = password // sib = basic service group @@ -1177,9 +1165,6 @@ public final class GsmMmiCode extends Handler implements MmiCode { } } else if (mSc != null && mSc.equals(SC_WAIT)) { - if (!mPhone.supportCsfbForSs()) { - throw new RuntimeException("No network to support supplementary services"); - } // sia = basic service group int serviceClass = siToServiceClass(mSia); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java index 1173d36e29..a033edd661 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java @@ -32,14 +32,10 @@ import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_PAC import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_PAD; import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_SMS; import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; -import static com.android.internal.telephony.SsDomainController.SS_CLIP; -import static com.android.internal.telephony.SsDomainController.SS_CLIR; -import static com.android.internal.telephony.SsDomainController.SS_COLP; -import static com.android.internal.telephony.SsDomainController.SS_COLR; -import static com.android.internal.telephony.SsDomainController.SS_CW; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.res.Resources; import android.os.AsyncResult; import android.os.Build; import android.os.Handler; @@ -67,7 +63,6 @@ import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.MmiCode; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.SsDomainController; import com.android.internal.telephony.gsm.GsmMmiCode; import com.android.internal.telephony.uicc.IccRecords; import com.android.telephony.Rlog; @@ -493,12 +488,17 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { static boolean isServiceCodeCallBarring(String sc) { - return sc != null - && (sc.equals(SC_BAOC) - || sc.equals(SC_BAOIC) || sc.equals(SC_BAOICxH) - || sc.equals(SC_BAIC) || sc.equals(SC_BAICr) - || sc.equals(SC_BA_ALL) || sc.equals(SC_BA_MO) - || sc.equals(SC_BA_MT)); + Resources resource = Resources.getSystem(); + if (sc != null) { + String[] barringMMI = resource.getStringArray( + com.android.internal.R.array.config_callBarringMMI_for_ims); + if (barringMMI != null) { + for (String match : barringMMI) { + if (sc.equals(match)) return true; + } + } + } + return false; } static boolean isPinPukCommand(String sc) { @@ -510,11 +510,9 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { * Whether the dial string is supplementary service code. * * @param dialString The dial string. - * @return an instance of SsDomainController.SuppServiceRoutingInfo if the dial string - * is supplementary service code, and null otherwise. + * @return true if the dial string is supplementary service code, and {@code false} otherwise. */ - public static SsDomainController.SuppServiceRoutingInfo getSuppServiceRoutingInfo( - String dialString, Phone phone) { + public static boolean isSuppServiceCodes(String dialString, Phone phone) { if (phone != null && phone.getServiceState().getVoiceRoaming() && phone.getDefaultPhone().supportsConversionOfCdmaCallerIdMmiCodesWhileRoaming()) { /* The CDMA MMI coded dialString will be converted to a 3GPP MMI Coded dialString @@ -523,54 +521,38 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { dialString = convertCdmaMmiCodesTo3gppMmiCodes(dialString); } - if (phone == null) return null; - return getSuppServiceRoutingInfo(dialString, phone.getSsDomainController()); - } - - /** - * Whether the dial string is supplementary service code. - */ - @VisibleForTesting - public static SsDomainController.SuppServiceRoutingInfo getSuppServiceRoutingInfo( - String dialString, SsDomainController controller) { Matcher m = sPatternSuppService.matcher(dialString); if (m.matches()) { String sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE)); if (isServiceCodeCallForwarding(sc)) { - return controller.getSuppServiceRoutingInfoForCf(scToCallForwardReason(sc)); + return true; } else if (isServiceCodeCallBarring(sc)) { - return controller.getSuppServiceRoutingInfoForCb(scToBarringFacility(sc)); + return true; } else if (sc != null && sc.equals(SC_CFUT)) { - // for backward compatibility, not specified by CarrierConfig - return SsDomainController.SS_ROUTING_OVER_UT; + return true; } else if (sc != null && sc.equals(SC_CLIP)) { - return controller.getSuppServiceRoutingInfoForSs(SS_CLIP); + return true; } else if (sc != null && sc.equals(SC_CLIR)) { - return controller.getSuppServiceRoutingInfoForSs(SS_CLIR); + return true; } else if (sc != null && sc.equals(SC_COLP)) { - return controller.getSuppServiceRoutingInfoForSs(SS_COLP); + return true; } else if (sc != null && sc.equals(SC_COLR)) { - return controller.getSuppServiceRoutingInfoForSs(SS_COLR); + return true; } else if (sc != null && sc.equals(SC_CNAP)) { - // for backward compatibility, not specified by CarrierConfig - return SsDomainController.SS_ROUTING_OVER_UT; + return true; } else if (sc != null && sc.equals(SC_BS_MT)) { - return controller.getSuppServiceRoutingInfoForCb( - SsDomainController.CB_FACILITY_BIL); + return true; } else if (sc != null && sc.equals(SC_BAICa)) { - return controller.getSuppServiceRoutingInfoForCb( - SsDomainController.CB_FACILITY_ACR); + return true; } else if (sc != null && sc.equals(SC_PWD)) { - // for backward compatibility, not specified by CarrierConfig - return SsDomainController.SS_ROUTING_OVER_UT; + return true; } else if (sc != null && sc.equals(SC_WAIT)) { - return controller.getSuppServiceRoutingInfoForSs(SS_CW); + return true; } else if (isPinPukCommand(sc)) { - // for backward compatibility, not specified by CarrierConfig - return SsDomainController.SS_ROUTING_OVER_UT; + return true; } } - return null; + return false; } static String diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 860db01166..1ff45440d4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -2083,150 +2083,4 @@ public class GsmCdmaPhoneTest extends TelephonyTest { doReturn(false).when(mUiccCardApplication3gpp).getIccFdnEnabled(); } - @Test - @SmallTest - public void testUpdateSsOverUtSupported() throws Exception { - doReturn(true).when(mImsPhone).isUtEnabled(); - replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); - - // Ut is disabled in config - doReturn(false).when(mSsDomainController).useCfOverUt(anyInt()); - doReturn(false).when(mSsDomainController).useCbOverUt(anyString()); - doReturn(false).when(mSsDomainController).useSsOverUt(anyString()); - replaceInstance(GsmCdmaPhone.class, "mSsDomainController", mPhoneUT, mSsDomainController); - - mPhoneUT.getCallForwardingOption(0, 0, null); - verify(mImsPhone, times(0)).getCallForwardingOption(eq(0), eq(0), any()); - - mPhoneUT.setCallForwardingOption(0, 0, null, 0, 0, null); - verify(mImsPhone, times(0)).setCallForwardingOption( - eq(0), eq(0), any(), eq(0), eq(0), any()); - - mPhoneUT.getCallBarring(CommandsInterface.CB_FACILITY_BAIC, null, null, 0); - verify(mImsPhone, times(0)).getCallBarring( - eq(CommandsInterface.CB_FACILITY_BAIC), any(), any(), eq(0)); - - mPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BAOC, false, null, null, 0); - verify(mImsPhone, times(0)).setCallBarring( - eq(CommandsInterface.CB_FACILITY_BAOC), eq(false), any(), any(), eq(0)); - - mPhoneUT.getOutgoingCallerIdDisplay(null); - verify(mImsPhone, times(0)).getOutgoingCallerIdDisplay(any()); - - mPhoneUT.setOutgoingCallerIdDisplay(0, null); - verify(mImsPhone, times(0)).setOutgoingCallerIdDisplay(eq(0), any()); - - mPhoneUT.queryCLIP(null); - verify(mImsPhone, times(0)).queryCLIP(any()); - - mPhoneUT.getCallWaiting(null); - verify(mImsPhone, times(0)).getCallWaiting(any()); - - mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); - verify(mImsPhone, times(0)).setCallWaiting(eq(false), any()); - - // config changed but isUtEnabled still returns false - doReturn(true).when(mSsDomainController).useCfOverUt(anyInt()); - doReturn(true).when(mSsDomainController).useCbOverUt(anyString()); - doReturn(true).when(mSsDomainController).useSsOverUt(anyString()); - - mPhoneUT.getCallForwardingOption(0, 0, null); - verify(mImsPhone, times(0)).getCallForwardingOption(eq(0), eq(0), any()); - - mPhoneUT.setCallForwardingOption(0, 0, null, 0, 0, null); - verify(mImsPhone, times(0)).setCallForwardingOption( - eq(0), eq(0), any(), eq(0), eq(0), any()); - - mPhoneUT.getCallBarring(CommandsInterface.CB_FACILITY_BAIC, null, null, 0); - verify(mImsPhone, times(0)).getCallBarring( - eq(CommandsInterface.CB_FACILITY_BAIC), any(), any(), eq(0)); - - mPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BAOC, false, null, null, 0); - verify(mImsPhone, times(0)).setCallBarring( - eq(CommandsInterface.CB_FACILITY_BAOC), eq(false), any(), any(), eq(0)); - - mPhoneUT.getOutgoingCallerIdDisplay(null); - verify(mImsPhone, times(0)).getOutgoingCallerIdDisplay(any()); - - mPhoneUT.setOutgoingCallerIdDisplay(0, null); - verify(mImsPhone, times(0)).setOutgoingCallerIdDisplay(eq(0), any()); - - mPhoneUT.queryCLIP(null); - verify(mImsPhone, times(0)).queryCLIP(any()); - - mPhoneUT.getCallWaiting(null); - verify(mImsPhone, times(0)).getCallWaiting(any()); - - mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); - verify(mImsPhone, times(0)).setCallWaiting(eq(false), any()); - - // isUtEnabled returns true - doReturn(true).when(mSsDomainController).isUtEnabled(); - - mPhoneUT.getCallForwardingOption(0, 0, null); - verify(mImsPhone, times(1)).getCallForwardingOption(eq(0), eq(0), any()); - - mPhoneUT.setCallForwardingOption(0, 0, null, 0, 0, null); - verify(mImsPhone, times(1)).setCallForwardingOption( - eq(0), eq(0), any(), eq(0), eq(0), any()); - - mPhoneUT.getCallBarring(CommandsInterface.CB_FACILITY_BAIC, null, null, 0); - verify(mImsPhone, times(1)).getCallBarring( - eq(CommandsInterface.CB_FACILITY_BAIC), any(), any(), eq(0)); - - mPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BAOC, false, null, null, 0); - verify(mImsPhone, times(1)).setCallBarring( - eq(CommandsInterface.CB_FACILITY_BAOC), eq(false), any(), any(), eq(0)); - - mPhoneUT.getOutgoingCallerIdDisplay(null); - verify(mImsPhone, times(1)).getOutgoingCallerIdDisplay(any()); - - mPhoneUT.setOutgoingCallerIdDisplay(0, null); - verify(mImsPhone, times(1)).setOutgoingCallerIdDisplay(eq(0), any()); - - mPhoneUT.queryCLIP(null); - verify(mImsPhone, times(1)).queryCLIP(any()); - - mPhoneUT.getCallWaiting(null); - verify(mImsPhone, times(1)).getCallWaiting(any()); - - mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); - verify(mImsPhone, times(1)).setCallWaiting(eq(false), any()); - - // configure changed, not support Ut - doReturn(false).when(mSsDomainController).useCfOverUt(anyInt()); - doReturn(false).when(mSsDomainController).useCbOverUt(anyString()); - doReturn(false).when(mSsDomainController).useSsOverUt(anyString()); - - // no change in interfactiion counts - mPhoneUT.getCallForwardingOption(0, 0, null); - verify(mImsPhone, times(1)).getCallForwardingOption(eq(0), eq(0), any()); - - mPhoneUT.setCallForwardingOption(0, 0, null, 0, 0, null); - verify(mImsPhone, times(1)).setCallForwardingOption( - eq(0), eq(0), any(), eq(0), eq(0), any()); - - mPhoneUT.getCallBarring(CommandsInterface.CB_FACILITY_BAIC, null, null, 0); - verify(mImsPhone, times(1)).getCallBarring( - eq(CommandsInterface.CB_FACILITY_BAIC), any(), any(), eq(0)); - - mPhoneUT.setCallBarring(CommandsInterface.CB_FACILITY_BAOC, false, null, null, 0); - verify(mImsPhone, times(1)).setCallBarring( - eq(CommandsInterface.CB_FACILITY_BAOC), eq(false), any(), any(), eq(0)); - - mPhoneUT.getOutgoingCallerIdDisplay(null); - verify(mImsPhone, times(1)).getOutgoingCallerIdDisplay(any()); - - mPhoneUT.setOutgoingCallerIdDisplay(0, null); - verify(mImsPhone, times(1)).setOutgoingCallerIdDisplay(eq(0), any()); - - mPhoneUT.queryCLIP(null); - verify(mImsPhone, times(1)).queryCLIP(any()); - - mPhoneUT.getCallWaiting(null); - verify(mImsPhone, times(1)).getCallWaiting(any()); - - mPhoneUT.setCallWaiting(false, CommandsInterface.SERVICE_CLASS_VOICE, null); - verify(mImsPhone, times(1)).setCallWaiting(eq(false), any()); - } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java deleted file mode 100644 index 53679e0dbe..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/SsDomainControllerTest.java +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN; -import static android.telephony.AccessNetworkConstants.AccessNetworkType.GERAN; -import static android.telephony.AccessNetworkConstants.AccessNetworkType.IWLAN; -import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN; -import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_ACR; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_ALL; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BAIC; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BAOC; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BIC_ROAM; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BIL; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BOIC; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_BOIC_EXHC; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_IBS; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CB_OBS; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_ALL; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_ALL_CONDITONAL_FORWARDING; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFB; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFNRC; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFNRY; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CF_CFU; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_CW; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIP; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIP; -import static android.telephony.CarrierConfigManager.ImsSs.SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIR; - -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOIC; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOICxH; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO; -import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; -import static com.android.internal.telephony.SsDomainController.CB_FACILITY_ACR; -import static com.android.internal.telephony.SsDomainController.CB_FACILITY_BIL; -import static com.android.internal.telephony.SsDomainController.SS_CLIP; -import static com.android.internal.telephony.SsDomainController.SS_CLIR; -import static com.android.internal.telephony.SsDomainController.SS_COLP; -import static com.android.internal.telephony.SsDomainController.SS_COLR; -import static com.android.internal.telephony.SsDomainController.SS_CW; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doReturn; - -import android.telephony.AccessNetworkConstants; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.ServiceState; -import android.telephony.TelephonyManager; -import android.test.suitebuilder.annotation.SmallTest; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.text.TextUtils; - -import com.android.internal.telephony.imsphone.ImsPhoneMmiCode; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.HashMap; -import java.util.Map; - -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class SsDomainControllerTest extends TelephonyTest { - private static final int[] UT_OVER_ALL = new int[] { - NGRAN, - EUTRAN, - IWLAN, - UTRAN, - GERAN - }; - - private static final int[] UT_OVER_LTE_WIFI = new int[] { - EUTRAN, - IWLAN - }; - - private Map mFacilities = new HashMap() {{ - put(CB_FACILITY_BAOC, "33"); - put(CB_FACILITY_BAOIC, "331"); - put(CB_FACILITY_BAOICxH, "332"); - put(CB_FACILITY_BAIC, "35"); - put(CB_FACILITY_BAICr, "351"); - put(CB_FACILITY_BA_ALL, "330"); - put(CB_FACILITY_BA_MO, "333"); - put(CB_FACILITY_BA_MT, "353"); - put(CB_FACILITY_BIL, "156"); - put(CB_FACILITY_ACR, "157"); - }}; - - private Map mReasons = new HashMap() {{ - put(CF_REASON_ALL, "002"); - put(CF_REASON_UNCONDITIONAL, "21"); - put(CF_REASON_BUSY, "67"); - put(CF_REASON_NOT_REACHABLE, "62"); - put(CF_REASON_NO_REPLY, "61"); - put(CF_REASON_ALL_CONDITIONAL, "004"); - }}; - - private Map mServices = new HashMap() {{ - put(SS_CW, "43"); - put(SS_CLIP, "30"); - put(SS_CLIR, "31"); - put(SS_COLP, "76"); - put(SS_COLR, "77"); - }}; - - private SsDomainController mSdc; - - @Before - public void setUp() throws Exception { - super.setUp(this.getClass().getSimpleName()); - - mSdc = new SsDomainController(mPhone); - } - - @After - public void tearDown() throws Exception { - mSdc = null; - super.tearDown(); - } - - private void verifyCb(String facility) { - for (String f : mFacilities.keySet()) { - String sc = mFacilities.get(f); - - SsDomainController.SuppServiceRoutingInfo ssCode = - ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); - assertNotNull(f + ", only " + facility + " available", ssCode); - if (TextUtils.equals(f, facility)) { - assertTrue(f + ", only " + facility + " available", mSdc.useCbOverUt(f)); - assertTrue(f + ", only " + facility + " available", ssCode.useSsOverUt()); - } else { - assertFalse(f + ", only " + facility + " available", mSdc.useCbOverUt(f)); - assertFalse(f + ", only " + facility + " available", ssCode.useSsOverUt()); - } - } - } - - @Test - @SmallTest - public void testUseCbOverUt() { - setUtEnabled(); - updateCarrierConfig(new int[] {}); - - verifyCb(""); - - /** barring_of_all_outgoing_calls (BAOC) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BAOC }); - - verifyCb(CB_FACILITY_BAOC); - - /** barring_of_outgoing_international_calls (BOIC) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BOIC }); - - verifyCb(CB_FACILITY_BAOIC); - - /** barring_of_outgoing_international_calls_except_to_home_plmn (BoICExHC) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BOIC_EXHC }); - - verifyCb(CB_FACILITY_BAOICxH); - - /** barring of all incoming calls (BAIC) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BAIC }); - - verifyCb(CB_FACILITY_BAIC); - - /** barring of incoming calls when roaming outside home PLMN Country (BICRoam) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BIC_ROAM }); - - verifyCb(CB_FACILITY_BAICr); - - /** barring list of incoming numbers (bil) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_BIL }); - - verifyCb(CB_FACILITY_BIL); - - /** barring of all anonymous incoming number (acr) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_ACR }); - - verifyCb(CB_FACILITY_ACR); - - /** all barring services(BA_ALL) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_ALL }); - - verifyCb(CB_FACILITY_BA_ALL); - - /** outgoing barring services(BA_MO) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_OBS }); - - verifyCb(CB_FACILITY_BA_MO); - - /** incoming barring services(BA_MT) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CB_IBS }); - - verifyCb(CB_FACILITY_BA_MT); - } - - private void verifyCf(int reason) { - for (Integer r : mReasons.keySet()) { - String sc = mReasons.get(r); - - SsDomainController.SuppServiceRoutingInfo ssCode = - ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); - assertNotNull(r + ", only " + reason + " available", ssCode); - if (r == reason) { - assertTrue(r + ", only " + reason + " available", mSdc.useCfOverUt(r)); - assertTrue(r + ", only " + reason + " available", ssCode.useSsOverUt()); - } else { - assertFalse(r + ", only " + reason + " available", mSdc.useCfOverUt(r)); - assertFalse(r + ", only " + reason + " available", ssCode.useSsOverUt()); - } - } - } - - @Test - @SmallTest - public void testUseCfOverUt() { - setUtEnabled(); - updateCarrierConfig(new int[] {}); - - verifyCf(-1); - - /** all_call_forwarding (CFAll) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_ALL }); - - verifyCf(CF_REASON_ALL); - - /** all_forwarding_unconditional (CFU) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_CFU }); - - verifyCf(CF_REASON_UNCONDITIONAL); - - /** all_call_conditional_forwarding (allCondForwarding) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_ALL_CONDITONAL_FORWARDING }); - - verifyCf(CF_REASON_ALL_CONDITIONAL); - - /** call_forwarding_on_mobile_subscriber_busy (CFB) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_CFB }); - - verifyCf(CF_REASON_BUSY); - - /** call_forwarding_on_no_reply (CFNRY) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_CFNRY }); - - verifyCf(CF_REASON_NO_REPLY); - - /** call_forwarding_on_mobile_subscriber_unreachable (CFNRC) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CF_CFNRC }); - - verifyCf(CF_REASON_NOT_REACHABLE); - } - - private void verifySs(String service) { - for (String s : mServices.keySet()) { - String sc = mServices.get(s); - - SsDomainController.SuppServiceRoutingInfo ssCode = - ImsPhoneMmiCode.getSuppServiceRoutingInfo("*#" + sc + "#", mSdc); - assertNotNull(s + ", only " + service + " available", ssCode); - if (TextUtils.equals(s, service)) { - assertTrue(s + ", only " + service + " available", mSdc.useSsOverUt(s)); - assertTrue(s + ", only " + service + " available", ssCode.useSsOverUt()); - } else { - assertFalse(s + ", only " + service + " available", mSdc.useSsOverUt(s)); - assertFalse(s + ", only " + service + " available", ssCode.useSsOverUt()); - } - } - } - - @Test - @SmallTest - public void testUseSsOverUt() { - setUtEnabled(); - updateCarrierConfig(new int[] {}); - verifySs(""); - - /** call waiting (CW) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_CW }); - - verifySs(SS_CW); - - /** OIP (clip) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIP }); - - verifySs(SS_CLIP); - - /** TIP (colp) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIP }); - - verifySs(SS_COLP); - - /** TIR (colr) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_IDENTIFICATION_TIR }); - - verifySs(SS_COLR); - - /** OIR (clir) */ - updateCarrierConfig(new int[] { SUPPLEMENTARY_SERVICE_IDENTIFICATION_OIR }); - - verifySs(SS_CLIR); - } - - @Test - @SmallTest - public void testUtEnabled() { - doReturn(0).when(mImsPhone).getSubId(); - mSdc.updateWifiForUt(false); - - ServiceState imsSs = new ServiceState(); - // IMS is not registered - imsSs.setState(ServiceState.STATE_OUT_OF_SERVICE); - doReturn(imsSs).when(mImsPhone).getServiceState(); - - doReturn(true).when(mImsPhone).isUtEnabled(); - doReturn(mImsPhone).when(mPhone).getImsPhone(); - - ServiceState ss = new ServiceState(); - // IMS is not registered - ss.setState(ServiceState.STATE_OUT_OF_SERVICE); - doReturn(ss).when(mPhone).getServiceState(); - - // WWAN_LEGACY is registered - NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) - .build(); - - ss.addNetworkRegistrationInfo(nri); - - // IMS Registration is NOT required, enabled when roaming, transport = ALL - updateCarrierConfig(false, true, UT_OVER_ALL); - - assertTrue(mSdc.isUtEnabled()); - - // IMS Registration is NOT required, enabled when roaming, transport = LTE | WiFi - updateCarrierConfig(false, true, UT_OVER_LTE_WIFI); - - // Ut is not available over 3G and 2G. - assertFalse(mSdc.isUtEnabled()); - - // Wi-Fi is connected - mSdc.updateWifiForUt(true); - - // Ut is available over WiFi. - assertTrue(mSdc.isUtEnabled()); - - // IMS Registration is REQUIRED, enabled when roaming, transport = LTE | WiFi - updateCarrierConfig(true, true, UT_OVER_LTE_WIFI); - - // IMS is not registered. - assertFalse(mSdc.isUtEnabled()); - - // IMS is registered - imsSs.setState(ServiceState.STATE_IN_SERVICE); - - assertTrue(mSdc.isUtEnabled()); - } - - @Test - @SmallTest - public void testUtWhenRoaming() { - doReturn(0).when(mImsPhone).getSubId(); - mSdc.updateWifiForUt(false); - - ServiceState imsSs = new ServiceState(); - // IMS is not registered - imsSs.setState(ServiceState.STATE_OUT_OF_SERVICE); - doReturn(imsSs).when(mImsPhone).getServiceState(); - - doReturn(true).when(mImsPhone).isUtEnabled(); - doReturn(mImsPhone).when(mPhone).getImsPhone(); - - ServiceState ss = new ServiceState(); - // IMS is not registered - ss.setState(ServiceState.STATE_OUT_OF_SERVICE); - doReturn(ss).when(mPhone).getServiceState(); - - // WWAN_LEGACY is registered - NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) - .build(); - - ss.addNetworkRegistrationInfo(nri); - - // IMS Registration is NOT required, enabled when roaming, transport = ALL - updateCarrierConfig(false, true, UT_OVER_ALL); - - assertTrue(mSdc.isUtEnabled()); - - // IMS Registration is NOT required, disabled when roaming, transport = ALL - updateCarrierConfig(false, false, UT_OVER_ALL); - - // Ut is not available when roaming - assertFalse(mSdc.isUtEnabled()); - } - - private void setUtEnabled() { - doReturn(0).when(mImsPhone).getSubId(); - mSdc.updateWifiForUt(false); - - ServiceState imsSs = new ServiceState(); - // IMS is not registered - imsSs.setState(ServiceState.STATE_OUT_OF_SERVICE); - doReturn(imsSs).when(mImsPhone).getServiceState(); - - doReturn(true).when(mImsPhone).isUtEnabled(); - doReturn(mImsPhone).when(mPhone).getImsPhone(); - - ServiceState ss = new ServiceState(); - // IMS is not registered - ss.setState(ServiceState.STATE_OUT_OF_SERVICE); - doReturn(ss).when(mPhone).getServiceState(); - - // WWAN_LEGACY is registered - NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_UMTS) - .build(); - - ss.addNetworkRegistrationInfo(nri); - } - - private void updateCarrierConfig(boolean requiresImsRegistration, - boolean availableWhenRoaming, int[] utRats) { - updateCarrierConfig(true, requiresImsRegistration, true, availableWhenRoaming, utRats); - } - - private void updateCarrierConfig(boolean supportsCsfb, boolean requiresImsRegistration, - boolean availableWhenPsDataOff, boolean availableWhenRoaming, int[] utRats) { - mSdc.updateCarrierConfigForTest(true, supportsCsfb, requiresImsRegistration, - availableWhenPsDataOff, availableWhenRoaming, null, utRats); - } - - private void updateCarrierConfig(int[] services) { - mSdc.updateCarrierConfigForTest(true, true, false, true, true, services, UT_OVER_ALL); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index b0b72e41c9..ce335a39dc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -259,7 +259,6 @@ public abstract class TelephonyTest { protected CellLocation mCellLocation; protected DataServiceManager mMockedWwanDataServiceManager; protected DataServiceManager mMockedWlanDataServiceManager; - protected SsDomainController mSsDomainController; // Initialized classes protected ActivityManager mActivityManager; @@ -489,7 +488,6 @@ public abstract class TelephonyTest { mCellLocation = Mockito.mock(CellLocation.class); mMockedWwanDataServiceManager = Mockito.mock(DataServiceManager.class); mMockedWlanDataServiceManager = Mockito.mock(DataServiceManager.class); - mSsDomainController = Mockito.mock(SsDomainController.class); TelephonyManager.disableServiceHandleCaching(); PropertyInvalidatedCache.disableForTestMode(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java index 724f9d48fe..d8173a22b1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneMmiCodeTest.java @@ -18,7 +18,6 @@ package com.android.internal.telephony.imsphone; import static junit.framework.Assert.fail; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -35,7 +34,6 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.CommandException; -import com.android.internal.telephony.SsDomainController; import com.android.internal.telephony.TelephonyTest; import org.junit.After; @@ -125,35 +123,6 @@ public class ImsPhoneMmiCodeTest extends TelephonyTest { doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); } - @Test - @SmallTest - public void testGetSuppServiceRoutingInfo() { - // Tests for valid service codes are done in SsDomainControllerTest. - - // verifies that null returns when invalid service code is given - // emergency number - SsDomainController.SuppServiceRoutingInfo ssInfo = - ImsPhoneMmiCode.getSuppServiceRoutingInfo("911", - (SsDomainController) null); - assertNull(ssInfo); - - // normal number - ssInfo = ImsPhoneMmiCode.getSuppServiceRoutingInfo("0123456789", - (SsDomainController) null); - assertNull(ssInfo); - ssInfo = ImsPhoneMmiCode.getSuppServiceRoutingInfo("+1234567890", - (SsDomainController) null); - assertNull(ssInfo); - - // USSD - ssInfo = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*0123456789#", - (SsDomainController) null); - assertNull(ssInfo); - ssInfo = ImsPhoneMmiCode.getSuppServiceRoutingInfo("*1234#56789#", - (SsDomainController) null); - assertNull(ssInfo); - } - /** * Ensure that when an operation is not supported that the correct message is returned. */ -- GitLab From 02fc67fa33d640c392f635e7a5a343a59dfa80a5 Mon Sep 17 00:00:00 2001 From: Terry Huang Date: Tue, 6 Dec 2022 19:04:05 +0800 Subject: [PATCH 239/656] Fix HIDL re-connect fail after switching from Mock Modem Bug: 259439704 Test: Run Mock Modem test case on HIDL/AIDL device Change-Id: I86a324d6820ee9716a695bbeaeefae96a135dad5 --- src/java/com/android/internal/telephony/RIL.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 0bdcbaca9e..1a5f393328 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -565,9 +565,20 @@ public class RIL extends BaseCommands implements CommandsInterface { if (mMockModem != null) { mMockModem = null; for (int service = MIN_SERVICE_IDX; service <= MAX_SERVICE_IDX; service++) { - if (isRadioServiceSupported(service)) { - resetProxyAndRequestList(service); + if (service == HAL_SERVICE_RADIO) { + if (isRadioVersion2_0()) { + mHalVersion.put(service, RADIO_HAL_VERSION_2_0); + } else { + mHalVersion.put(service, RADIO_HAL_VERSION_UNKNOWN); + } + } else { + if (isRadioServiceSupported(service)) { + mHalVersion.put(service, RADIO_HAL_VERSION_UNKNOWN); + } else { + mHalVersion.put(service, RADIO_HAL_VERSION_UNSUPPORTED); + } } + resetProxyAndRequestList(service); } } } -- GitLab From 320b620729a0d82ccf44ea805f64285039a498f8 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Mon, 5 Dec 2022 13:01:08 -0800 Subject: [PATCH 240/656] Clear calling identity before calling getSubscriptionUserHandle Bug: 261200119 Test: atest CtsTelephonyTestCases:android.telephony.cts.SmsManagerTest Change-Id: Iab22f9a8b37da4cdd512fa68b2a4018a98e02ff9 --- .../internal/telephony/SmsPermissions.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/SmsPermissions.java b/src/java/com/android/internal/telephony/SmsPermissions.java index e45cee3f7f..f6af69dbb2 100644 --- a/src/java/com/android/internal/telephony/SmsPermissions.java +++ b/src/java/com/android/internal/telephony/SmsPermissions.java @@ -134,7 +134,15 @@ public class SmsPermissions { */ public boolean checkCallingOrSelfCanGetSmscAddress(String callingPackage, String message) { // Allow it to the default SMS app always. - if (!isCallerDefaultSmsPackage(callingPackage)) { + boolean isDefaultSmsPackage; + final long identity = Binder.clearCallingIdentity(); + try { + isDefaultSmsPackage = isCallerDefaultSmsPackage(callingPackage); + } finally { + Binder.restoreCallingIdentity(identity); + } + + if (!isDefaultSmsPackage) { TelephonyPermissions .enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege( mContext, mPhone.getSubId(), message); @@ -153,7 +161,15 @@ public class SmsPermissions { */ public boolean checkCallingOrSelfCanSetSmscAddress(String callingPackage, String message) { // Allow it to the default SMS app always. - if (!isCallerDefaultSmsPackage(callingPackage)) { + boolean isDefaultSmsPackage; + final long identity = Binder.clearCallingIdentity(); + try { + isDefaultSmsPackage = isCallerDefaultSmsPackage(callingPackage); + } finally { + Binder.restoreCallingIdentity(identity); + } + + if (!isDefaultSmsPackage) { // Allow it with MODIFY_PHONE_STATE or Carrier Privileges TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege( mContext, mPhone.getSubId(), message); -- GitLab From f75e8abfb979bf6e6b498c04510e032b52732f94 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Sun, 16 Oct 2022 01:39:07 +0000 Subject: [PATCH 241/656] Unit Testing for RP-SMMA Implementation in frameworks - Added testcases for the new API in SmsDispatcherController, ImsSmsDispatcher and SmsStorageMonitor - Bug: b/240883268 Test: atest SmsDispatcherControllerTest, atest ImsSmsDispatcherTest, atest SmsStorageMonitorTest Change-Id: I2468be62da212d338b8831345ef97a379f19a384 --- .../telephony/ImsSmsDispatcherTest.java | 12 ++++++ .../SmsDispatchersControllerTest.java | 26 ++++++++++++ .../telephony/SmsStorageMonitorTest.java | 40 +++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java index b9c83d312b..548f65895d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java @@ -98,6 +98,18 @@ public class ImsSmsDispatcherTest extends TelephonyTest { super.tearDown(); } + /** + * Send Memory Availability Notification and verify that the token is correct. + */ + @Test + @SmallTest + public void testOnMemoryAvailable() throws Exception { + int token = mImsSmsDispatcher.mNextToken.get(); + //Send SMMA + mImsSmsDispatcher.onMemoryAvailable(); + assertEquals(token + 1, mImsSmsDispatcher.mNextToken.get()); + verify(mImsManager).onMemoryAvailable(eq(token + 1)); + } /** * Send an SMS and verify that the token and PDU is correct. */ diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java index fecfc88d0a..008ad8fb4c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java @@ -19,6 +19,7 @@ package com.android.internal.telephony; import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; @@ -33,6 +34,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.os.AsyncResult; import android.os.Message; import android.provider.Telephony.Sms.Intents; import android.telephony.PhoneNumberUtils; @@ -96,6 +98,30 @@ public class SmsDispatchersControllerTest extends TelephonyTest { assertTrue(mSmsDispatchersController.isIms()); } + @Test @SmallTest + public void testReportSmsMemoryStatus() throws Exception { + int eventReportMemoryStatusDone = 3; + SmsStorageMonitor smsStorageMonnitor = new SmsStorageMonitor(mPhone); + Message result = smsStorageMonnitor.obtainMessage(eventReportMemoryStatusDone); + ImsSmsDispatcher mImsSmsDispatcher = Mockito.mock(ImsSmsDispatcher.class); + mSmsDispatchersController.setImsSmsDispatcher(mImsSmsDispatcher); + mSmsDispatchersController.reportSmsMemoryStatus(result); + AsyncResult ar = (AsyncResult) result.obj; + verify(mImsSmsDispatcher).onMemoryAvailable(); + assertNull(ar.exception); + } + + @Test @SmallTest + public void testReportSmsMemoryStatusFailure() throws Exception { + int eventReportMemoryStatusDone = 3; + SmsStorageMonitor smsStorageMonnitor = new SmsStorageMonitor(mPhone); + Message result = smsStorageMonnitor.obtainMessage(eventReportMemoryStatusDone); + mSmsDispatchersController.setImsSmsDispatcher(null); + mSmsDispatchersController.reportSmsMemoryStatus(result); + AsyncResult ar = (AsyncResult) result.obj; + assertNotNull(ar.exception); + } + @Test @SmallTest @FlakyTest public void testSendImsGmsTest() throws Exception { switchImsSmsFormat(PhoneConstants.PHONE_TYPE_GSM); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java index 3eace63e46..b6775eb2ea 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java @@ -20,8 +20,11 @@ import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; import android.content.Intent; +import android.content.res.Resources; import android.os.Message; import android.provider.Telephony; import android.test.suitebuilder.annotation.MediumTest; @@ -34,6 +37,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -137,6 +142,41 @@ public class SmsStorageMonitorTest extends TelephonyTest { .reportSmsMemoryStatus(eq(false), any(Message.class)); } + @Test @SmallTest + public void testReportSmsMemoryStatusToIms() { + Resources mockResources = Mockito.mock(Resources.class); + doReturn(mockResources).when(mContext).getResources(); + doReturn(true).when(mockResources).getBoolean(anyInt()); + doReturn(true).when(mIccSmsInterfaceManager.mDispatchersController).isIms(); + + mSimulatedCommands.notifyRadioOn(); + processAllMessages(); + + verify(mSimulatedCommandsVerifier, never()).reportSmsMemoryStatus(anyBoolean(), + any(Message.class)); + + // Send DEVICE_STORAGE_FULL + mContextFixture.getTestDouble().sendBroadcast( + new Intent(Intent.ACTION_DEVICE_STORAGE_FULL)); + processAllMessages(); + + verify(mSimulatedCommandsVerifier).reportSmsMemoryStatus(eq(false), any(Message.class)); + assertFalse(mSmsStorageMonitor.isStorageAvailable()); + + mSimulatedCommands.notifyRadioOn(); + processAllMessages(); + + verify(mSimulatedCommandsVerifier).reportSmsMemoryStatus(eq(false), any(Message.class)); + + // Send DEVICE_STORAGE_NOT_FULL + mContextFixture.getTestDouble().sendBroadcast( + new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL)); + processAllMessages(); + + verify(mIccSmsInterfaceManager.mDispatchersController) + .reportSmsMemoryStatus(any(Message.class)); + } + @Test @SmallTest public void testReportSmsMemoryStatusDuringRetry() { mSimulatedCommands.setReportSmsMemoryStatusFailResponse(true); -- GitLab From c749610f116d008d69a4b2f6754ec0f67877f4c8 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Thu, 10 Nov 2022 10:28:24 +0000 Subject: [PATCH 242/656] Adding Test API to send Memory Status Event For CTS - Send memory status to SmsStorageMonitor - Bug: b/255881498 Test: atest CtsTelephonyTestCases:ImsServiceTest Change-Id: Ia108d9df2f321e8f4cd4bf2f166a3c61a80b5ac2 --- .../internal/telephony/SmsController.java | 54 +++++++++++++++++++ .../internal/telephony/SmsStorageMonitor.java | 31 ++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 4d59180d9a..8b99c3e09c 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -18,6 +18,8 @@ package com.android.internal.telephony; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + import static com.android.internal.telephony.util.TelephonyUtils.checkDumpPermission; import android.annotation.Nullable; @@ -792,6 +794,58 @@ public class SmsController extends ISmsImplBase { return getPhone(subId).getAppSmsManager().createAppSpecificSmsToken(callingPkg, intent); } + @Override + public void setStorageMonitorMemoryStatusOverride(int subId, boolean isStorageAvailable) { + Phone phone = getPhone(subId); + Context context; + if (phone != null) { + context = phone.getContext(); + } else { + Rlog.e(LOG_TAG, "Phone Object is Null"); + return; + } + // If it doesn't have modify phone state permission + // a SecurityException will be thrown. + if (context.checkPermission(android.Manifest + .permission.MODIFY_PHONE_STATE, Binder.getCallingPid(), + Binder.getCallingUid()) != PERMISSION_GRANTED) { + throw new SecurityException( + "setStorageMonitorMemoryStatusOverride needs MODIFY_PHONE_STATE"); + } + final long identity = Binder.clearCallingIdentity(); + try { + phone.mSmsStorageMonitor.sendMemoryStatusOverride(isStorageAvailable); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void clearStorageMonitorMemoryStatusOverride(int subId) { + Phone phone = getPhone(subId); + Context context; + if (phone != null) { + context = phone.getContext(); + } else { + Rlog.e(LOG_TAG, "Phone Object is Null"); + return; + } + // If it doesn't have modify phone state permission + // a SecurityException will be thrown. + if (context.checkPermission(android.Manifest + .permission.MODIFY_PHONE_STATE, Binder.getCallingPid(), + Binder.getCallingUid()) != PERMISSION_GRANTED) { + throw new SecurityException( + "clearStorageMonitorMemoryStatusOverride needs MODIFY_PHONE_STATE"); + } + final long identity = Binder.clearCallingIdentity(); + try { + phone.mSmsStorageMonitor.clearMemoryStatusOverride(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + @Override public int checkSmsShortCodeDestination(int subId, String callingPackage, String callingFeatureId, String destAddress, String countryIso) { diff --git a/src/java/com/android/internal/telephony/SmsStorageMonitor.java b/src/java/com/android/internal/telephony/SmsStorageMonitor.java index 89e35450c3..7bc669a911 100644 --- a/src/java/com/android/internal/telephony/SmsStorageMonitor.java +++ b/src/java/com/android/internal/telephony/SmsStorageMonitor.java @@ -43,7 +43,7 @@ import com.android.telephony.Rlog; * dual-mode devices that require support for both 3GPP and 3GPP2 format messages. */ public class SmsStorageMonitor extends Handler { - private static final String TAG = "SmsStorageMonitor"; + private static final String TAG = "SmsStorageMonitor1"; /** Maximum number of times to retry memory status reporting */ private static final int MAX_RETRIES = 1; @@ -86,6 +86,10 @@ public class SmsStorageMonitor extends Handler { final CommandsInterface mCi; boolean mStorageAvailable = true; + boolean mInitialStorageAvailableStatus = true; + + private boolean mMemoryStatusOverrideFlag = false; + /** * Hold the wake lock for 5 seconds, which should be enough time for * any receiver(s) to grab its own wake lock. @@ -114,6 +118,31 @@ public class SmsStorageMonitor extends Handler { mContext.registerReceiver(mResultReceiver, filter); } + /** + * Overriding of the Memory Status by the TestApi and send the event to Handler to test + * the RP-SMMA feature + * @param isStorageAvailable boolean value specifies the MemoryStatus to be + * sent to Handler + */ + public void sendMemoryStatusOverride(boolean isStorageAvailable) { + if (!mMemoryStatusOverrideFlag) { + mInitialStorageAvailableStatus = mStorageAvailable; + mMemoryStatusOverrideFlag = true; + } + mStorageAvailable = isStorageAvailable; + if (isStorageAvailable) { + sendMessage(obtainMessage(EVENT_REPORT_MEMORY_STATUS)); + } + } + + /** + * reset Memory Status change made by {@link #sendMemoryStatusOverride} + */ + public void clearMemoryStatusOverride() { + mStorageAvailable = mInitialStorageAvailableStatus; + mMemoryStatusOverrideFlag = false; + } + @VisibleForTesting public void setMaxRetries(int maxCount) { mMaxRetryCount = maxCount; -- GitLab From 14d817c16bd245d7ef1f3fb7c38e7a4586d584d0 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Fri, 16 Sep 2022 01:21:45 +0000 Subject: [PATCH 243/656] Handling of Memory Not Full Event from SmsStorageMonitor - Check if SMS over IMS is available - Send Memory Not Full Event to ImsManager - Receive the result of sending the event back StorageMonitor - Bug: b/240883268 Test: Tested Memory full and available conditions in Pixel6 Change-Id: I4f83dffc383ebd9202ebc9b8e6b555afa1f65bb8 --- .../internal/telephony/ImsSmsDispatcher.java | 14 ++++++++++++ .../telephony/SmsDispatchersController.java | 22 +++++++++++++++++++ .../internal/telephony/SmsStorageMonitor.java | 13 +++++++++++ 3 files changed, 49 insertions(+) diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java index 91cee51e62..041102f79e 100644 --- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java +++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java @@ -447,6 +447,20 @@ public class ImsSmsDispatcher extends SMSDispatcher { return SMSDispatcherUtil.calculateLength(isCdmaMo(), messageBody, use7bitOnly); } + /** + * Send the Memory Available Event to the ImsService + */ + public void onMemoryAvailable() { + logd("onMemoryAvailable "); + int token = mNextToken.incrementAndGet(); + try { + logd("onMemoryAvailable: token = " + token); + getImsManager().onMemoryAvailable(token); + } catch (ImsException e) { + loge("onMemoryAvailable failed: " + e.getMessage()); + } + } + @Override public void sendSms(SmsTracker tracker) { logd("sendSms: " diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java index a57a68c04c..51b22fdf31 100644 --- a/src/java/com/android/internal/telephony/SmsDispatchersController.java +++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java @@ -409,6 +409,11 @@ public class SmsDispatchersController extends Handler { injectSmsPdu(msg, format, callback, false /* ignoreClass */, isOverIms, 0 /* unused */); } + @VisibleForTesting + public void setImsSmsDispatcher(ImsSmsDispatcher imsSmsDispatcher) { + mImsSmsDispatcher = imsSmsDispatcher; + } + /** * Inject an SMS PDU into the android platform. * @@ -573,6 +578,23 @@ public class SmsDispatchersController extends Handler { dispatcher.sendSms(tracker); } + /** + * Memory Available Event + * @param result callback message + */ + public void reportSmsMemoryStatus(Message result) { + Rlog.d(TAG, "reportSmsMemoryStatus: "); + try { + mImsSmsDispatcher.onMemoryAvailable(); + AsyncResult.forMessage(result, null, null); + result.sendToTarget(); + } catch (Exception e) { + Rlog.e(TAG, "reportSmsMemoryStatus Failed ", e); + AsyncResult.forMessage(result, null, e); + result.sendToTarget(); + } + } + /** * SMS over IMS is supported if IMS is registered and SMS is supported on IMS. * diff --git a/src/java/com/android/internal/telephony/SmsStorageMonitor.java b/src/java/com/android/internal/telephony/SmsStorageMonitor.java index 89e35450c3..4a20f92924 100644 --- a/src/java/com/android/internal/telephony/SmsStorageMonitor.java +++ b/src/java/com/android/internal/telephony/SmsStorageMonitor.java @@ -22,6 +22,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.os.AsyncResult; import android.os.Build; import android.os.Handler; @@ -212,6 +213,18 @@ public class SmsStorageMonitor extends Handler { private void sendMemoryStatusReport(boolean isAvailable) { mIsWaitingResponse = true; + Resources r = mContext.getResources(); + if (r.getBoolean(com.android.internal.R.bool.config_smma_notification_supported_over_ims)) { + IccSmsInterfaceManager smsIfcMngr = mPhone.getIccSmsInterfaceManager(); + if (smsIfcMngr != null) { + Rlog.d(TAG, "sendMemoryStatusReport: smsIfcMngr is available"); + if (smsIfcMngr.mDispatchersController.isIms() && isAvailable) { + smsIfcMngr.mDispatchersController.reportSmsMemoryStatus( + obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); + return; + } + } + } mCi.reportSmsMemoryStatus(isAvailable, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); } -- GitLab From 269fc7bd21738e103ff797322ad614ad19d7f1ba Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 6 Dec 2022 18:47:12 -0800 Subject: [PATCH 244/656] Added few more APIs Adde getActiveSubscriptionInfoForIccId, getAccessibleSubscriptionInfoList, isSubscriptionEnabled getEnabledSubscriptionId, getActiveDataSubscriptionId Test: atest SubscriptionManagerServiceTest Bug: 239607619 Change-Id: I7a27d07487f4233d8656182163b4514a1db886ab --- .../SubscriptionManagerService.java | 203 +++++++++++++----- .../internal/telephony/TelephonyTest.java | 4 + .../SubscriptionManagerServiceTest.java | 78 ++++++- 3 files changed, 231 insertions(+), 54 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index f6b7eb0b31..03a2ae6a32 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -51,6 +51,7 @@ import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.PhoneNumberSource; import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; +import android.telephony.TelephonyCallback; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; @@ -72,6 +73,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; +import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; @@ -120,6 +122,10 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull private final Context mContext; + /** App Ops manager instance. */ + @NonNull + private final AppOpsManager mAppOpsManager; + /** Telephony manager instance. */ @NonNull private final TelephonyManager mTelephonyManager; @@ -316,6 +322,7 @@ public class SubscriptionManagerService extends ISub.Stub { mTelephonyManager = context.getSystemService(TelephonyManager.class); mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mEuiccManager = context.getSystemService(EuiccManager.class); + mAppOpsManager = context.getSystemService(AppOpsManager.class); mUiccController = UiccController.getInstance(); mHandler = new Handler(looper); @@ -902,8 +909,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List getAllSubInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos @@ -951,8 +957,7 @@ public class SubscriptionManagerService extends ISub.Stub { public SubscriptionInfo getActiveSubscriptionInfo(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "getActiveSubscriptionInfo")) { @@ -977,20 +982,33 @@ public class SubscriptionManagerService extends ISub.Stub { * Get the active {@link SubscriptionInfo} associated with the iccId. * * @param iccId the IccId of SIM card - * @param callingPackage The package making the call - * @param callingFeatureId The feature in the package + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * * @return The subscription info. */ @Override @Nullable + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public SubscriptionInfo getActiveSubscriptionInfoForIccId(@NonNull String iccId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - return null; + enforcePermissions("getActiveSubscriptionInfoForIccId", + Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + final long identity = Binder.clearCallingIdentity(); + try { + iccId = IccUtils.stripTrailingFs(iccId); + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternalByIccId(iccId); + + return (subInfo != null && subInfo.isActive()) ? subInfo.toSubscriptionInfo() : null; + + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1012,8 +1030,7 @@ public class SubscriptionManagerService extends ISub.Stub { public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); int subId = mSlotIndexToSubId.getOrDefault(slotIndex, SubscriptionManager.INVALID_SUBSCRIPTION_ID); @@ -1061,8 +1078,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List getActiveSubscriptionInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos @@ -1109,8 +1125,7 @@ public class SubscriptionManagerService extends ISub.Stub { public int getActiveSubInfoCount(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, @@ -1147,8 +1162,8 @@ public class SubscriptionManagerService extends ISub.Stub { public List getAvailableSubscriptionInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); + enforcePermissions("getAvailableSubscriptionInfoList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); @@ -1175,16 +1190,41 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * @see SubscriptionManager#getAccessibleSubscriptionInfoList + * Gets the SubscriptionInfo(s) of all embedded subscriptions accessible to the calling app, if + * any. + * + *

Only those subscriptions for which the calling app has carrier privileges per the + * subscription metadata, if any, will be included in the returned list. + * + *

The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by + * {@link SubscriptionInfo#getSubscriptionId}. + * + * @return Sorted list of the current embedded {@link SubscriptionInfo} records available on the + * device which are accessible to the caller. + *

    + *
  • + * + * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} + * then by {@link SubscriptionInfo#getSubscriptionId}. + *
*/ @Override public List getAccessibleSubscriptionInfoList( @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - return null; + if (!mEuiccManager.isEnabled()) { + return null; + } + + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .map(SubscriptionInfoInternal::toSubscriptionInfo) + .filter(subInfo -> mSubscriptionManager + .canManageSubscription(subInfo, callingPackage)) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); } /** @@ -1437,9 +1477,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public int setOpportunistic(boolean opportunistic, int subId, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); - + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return 0; } @@ -1463,9 +1501,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public ParcelUuid createSubscriptionGroup(int[] subIdList, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); - + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; } @@ -1500,8 +1536,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List getOpportunisticSubscriptions(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return Collections.emptyList(); } @@ -1510,8 +1545,7 @@ public class SubscriptionManagerService extends ISub.Stub { public void removeSubscriptionsFromGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); } @@ -1519,9 +1553,7 @@ public class SubscriptionManagerService extends ISub.Stub { public void addSubscriptionsIntoGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); - + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); } /** @@ -1556,8 +1588,7 @@ public class SubscriptionManagerService extends ISub.Stub { public List getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); // If the calling app neither has carrier privileges nor READ_PHONE_STATE and access to // device identifiers, it will throw a SecurityException. @@ -1858,8 +1889,7 @@ public class SubscriptionManagerService extends ISub.Stub { public String getSubscriptionProperty(int subId, @NonNull String propKey, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; } @@ -1869,14 +1899,62 @@ public class SubscriptionManagerService extends ISub.Stub { return true; } + /** + * Check if a subscription is active. + * + * @param subId The subscription id to check. + * + * @return {@code true} if the subscription is active. + * + * @throws IllegalArgumentException if the provided slot index is invalid. + */ @Override + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSubscriptionEnabled(int subId) { - return true; + enforcePermissions("isSubscriptionEnabled", + Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + throw new IllegalArgumentException("Invalid subscription id " + subId); + } + + final long identity = Binder.clearCallingIdentity(); + try { + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + return subInfo != null && subInfo.isActive(); + } finally { + Binder.restoreCallingIdentity(identity); + } } + /** + * Get the active subscription id by logical SIM slot index. + * + * @param slotIndex The logical SIM slot index. + * @return The active subscription id. + * + * @throws IllegalArgumentException if the provided slot index is invalid. + */ @Override + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int slotIndex) { - return 0; + enforcePermissions("getEnabledSubscriptionId", + Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { + throw new IllegalArgumentException("Invalid slot index " + slotIndex); + } + + final long identity = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(subInfo -> subInfo.isActive() && subInfo.getSimSlotIndex() == slotIndex) + .mapToInt(SubscriptionInfoInternal::getSubscriptionId) + .findFirst() + .orElse(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override @@ -1902,8 +1980,7 @@ public class SubscriptionManagerService extends ISub.Stub { public boolean isActiveSubId(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "isActiveSubId")) { @@ -1920,9 +1997,33 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Get active data subscription id. Active data subscription refers to the subscription + * currently chosen to provide cellular internet connection to the user. This may be + * different from getDefaultDataSubscriptionId(). + * + * @return Active data subscription id if any is chosen, or + * SubscriptionManager.INVALID_SUBSCRIPTION_ID if not. + * + * @see TelephonyCallback.ActiveDataSubscriptionIdListener + */ @Override public int getActiveDataSubscriptionId() { - return 0; + final long token = Binder.clearCallingIdentity(); + try { + PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); + if (phoneSwitcher != null) { + int activeDataSubId = phoneSwitcher.getActiveDataSubId(); + if (SubscriptionManager.isUsableSubscriptionId(activeDataSubId)) { + return activeDataSubId; + } + } + // If phone switcher isn't ready, or active data sub id is not available, use default + // sub id from settings. + return getDefaultDataSubId(); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override @@ -1997,8 +2098,7 @@ public class SubscriptionManagerService extends ISub.Stub { public String getPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( mContext, subId, Binder.getCallingUid(), "getPhoneNumber", @@ -2039,8 +2139,7 @@ public class SubscriptionManagerService extends ISub.Stub { public String getPhoneNumberFromFirstAvailableSource(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return null; } @@ -2049,8 +2148,7 @@ public class SubscriptionManagerService extends ISub.Stub { public void setPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String number, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); if (source != SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER) { throw new IllegalArgumentException("setPhoneNumber doesn't accept source " @@ -2083,8 +2181,7 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public int setUsageSetting(int usageSetting, int subId, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID - mContext.getSystemService(AppOpsManager.class) - .checkPackage(Binder.getCallingUid(), callingPackage); + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); return 0; } @@ -2238,7 +2335,11 @@ public class SubscriptionManagerService extends ISub.Stub { pw.println("defaultSubId=" + getDefaultSubId()); pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId()); pw.println("defaultDataSubId" + getDefaultDataSubId()); + pw.println("activeDataSubId" + getActiveDataSubscriptionId()); pw.println("defaultSmsSubId" + getDefaultSmsSubId()); + if (mEuiccManager != null) { + pw.println("Euicc enabled=" + mEuiccManager.isEnabled()); + } pw.decreaseIndent(); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index b0b72e41c9..951f27deb7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -103,6 +103,7 @@ import com.android.internal.telephony.data.DataRetryManager; import com.android.internal.telephony.data.DataServiceManager; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; +import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; @@ -212,6 +213,7 @@ public abstract class TelephonyTest { protected RuimRecords mRuimRecords; protected IsimUiccRecords mIsimUiccRecords; protected ProxyController mProxyController; + protected PhoneSwitcher mPhoneSwitcher; protected Singleton mIActivityManagerSingleton; protected IActivityManager mIActivityManager; protected IIntentSender mIIntentSender; @@ -442,6 +444,7 @@ public abstract class TelephonyTest { mRuimRecords = Mockito.mock(RuimRecords.class); mIsimUiccRecords = Mockito.mock(IsimUiccRecords.class); mProxyController = Mockito.mock(ProxyController.class); + mPhoneSwitcher = Mockito.mock(PhoneSwitcher.class); mIActivityManagerSingleton = Mockito.mock(Singleton.class); mIActivityManager = Mockito.mock(IActivityManager.class); mIIntentSender = Mockito.mock(IIntentSender.class); @@ -808,6 +811,7 @@ public abstract class TelephonyTest { replaceInstance(CdmaSubscriptionSourceManager.class, "sInstance", null, mCdmaSSM); replaceInstance(SubscriptionController.class, "sInstance", null, mSubscriptionController); replaceInstance(ProxyController.class, "sProxyController", null, mProxyController); + replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mPhoneSwitcher); replaceInstance(ActivityManager.class, "IActivityManagerSingleton", null, mIActivityManagerSingleton); replaceInstance(CdmaSubscriptionSourceManager.class, 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 55e2f4d174..bd7a168758 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -210,6 +210,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { method.setAccessible(true); method.invoke(map, subInfo.getSimSlotIndex(), subId); mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + processAllMessages(); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(subId)); + Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); return subId; } catch (Exception e) { fail("Failed to insert subscription. e=" + e); @@ -337,8 +340,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); - verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(2)); - // Should throw security exception if the caller does not have permission. assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT.getAllSubInfoList( @@ -818,7 +819,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetIconTint() throws Exception { insertSubscription(FAKE_SUBSCRIPTION_INFO1); - Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); // Should fail without MODIFY_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT @@ -834,4 +834,76 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfo.getIconTint()).isEqualTo(12345); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); } + + @Test + public void testGetActiveSubscriptionInfoForIccId() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without READ_PRIVILEGED_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getActiveSubscriptionInfoForIccId(FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + SubscriptionInfo subInfo = mSubscriptionManagerServiceUT.getActiveSubscriptionInfoForIccId( + FAKE_ICCID1, CALLING_PACKAGE, CALLING_FEATURE); + assertThat(subInfo).isEqualTo(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()); + } + + @Test + public void testGetAccessibleSubscriptionInfoList() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + doReturn(false).when(mEuiccManager).isEnabled(); + assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( + CALLING_PACKAGE)).isNull(); + + doReturn(true).when(mEuiccManager).isEnabled(); + assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( + CALLING_PACKAGE)).isEmpty(); + + doReturn(true).when(mSubscriptionManager).canManageSubscription( + eq(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()), eq(CALLING_PACKAGE)); + + assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( + CALLING_PACKAGE)).isEqualTo(List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo())); + } + + @Test + public void testIsSubscriptionEnabled() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without READ_PRIVILEGED_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .isSubscriptionEnabled(1)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(1)).isTrue(); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionEnabled(2)).isFalse(); + } + + @Test + public void testGetEnabledSubscriptionId() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without READ_PRIVILEGED_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getEnabledSubscriptionId(0)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThrows(IllegalArgumentException.class, () -> mSubscriptionManagerServiceUT + .getEnabledSubscriptionId(SubscriptionManager.INVALID_SIM_SLOT_INDEX)); + + doReturn(2).when(mTelephonyManager).getActiveModemCount(); + assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(0)).isEqualTo(1); + assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(1)).isEqualTo( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + assertThrows(IllegalArgumentException.class, () -> mSubscriptionManagerServiceUT + .getEnabledSubscriptionId(2)); + } + + @Test + public void testGetActiveDataSubscriptionId() { + doReturn(12345).when(mPhoneSwitcher).getActiveDataSubId(); + assertThat(mSubscriptionManagerServiceUT.getActiveDataSubscriptionId()).isEqualTo(12345); + } } -- GitLab From 80b86fa2746aae5e7cd5b7741002129d3dcb5511 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 8 Dec 2022 00:49:44 -0800 Subject: [PATCH 245/656] Migrate getSimStateForSlotIndex to TelephonyManager Most of the SIM APIs are in TelephonyManager. SubscriptionManager handles subscription related information only. Test: Manual Bug: 239607619 Change-Id: Ib9b23312f73a5c2bdefd2a770ef0b6c848a7d387 --- .../telephony/SubscriptionController.java | 41 ------------------- .../SubscriptionManagerService.java | 5 --- 2 files changed, 46 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 5e3c4b500b..cb89d202c2 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -77,7 +77,6 @@ import android.util.Log; import com.android.ims.ImsManager; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.uicc.IccUtils; @@ -3162,46 +3161,6 @@ public class SubscriptionController extends ISub.Stub { return retVal; } - /** - * Get the SIM state for the slot index. - * For Remote-SIMs, this method returns {@link IccCardConstants.State#UNKNOWN} - * @return SIM state as the ordinal of {@link IccCardConstants.State} - */ - @Override - public int getSimStateForSlotIndex(int slotIndex) { - State simState; - String err; - if (slotIndex < 0) { - simState = IccCardConstants.State.UNKNOWN; - err = "invalid slotIndex"; - } else { - Phone phone = null; - try { - phone = PhoneFactory.getPhone(slotIndex); - } catch (IllegalStateException e) { - // ignore - } - if (phone == null) { - simState = IccCardConstants.State.UNKNOWN; - err = "phone == null"; - } else { - IccCard icc = phone.getIccCard(); - if (icc == null) { - simState = IccCardConstants.State.UNKNOWN; - err = "icc == null"; - } else { - simState = icc.getState(); - err = ""; - } - } - } - if (VDBG) { - logd("getSimStateForSlotIndex: " + err + " simState=" + simState - + " ordinal=" + simState.ordinal() + " slotIndex=" + slotIndex); - } - return simState.ordinal(); - } - /** * Store properties associated with SubscriptionInfo in database * @param subId Subscription Id of Subscription diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index f6b7eb0b31..922e6c2829 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1879,11 +1879,6 @@ public class SubscriptionManagerService extends ISub.Stub { return 0; } - @Override - public int getSimStateForSlotIndex(int slotIndex) { - return 0; - } - /** * Check if a subscription is active. * -- GitLab From d67a6f0ec3e61070d095615e2b9d80d3961334d2 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 17 Nov 2022 12:35:16 -0800 Subject: [PATCH 246/656] Update tests and utils for NR timing advance Test: atest CTS and unit tests Bug: 141097448 Change-Id: I8670669bd257f469bb3510ca6cf00c44fd6eb740 --- .../android/internal/telephony/RILUtils.java | 5 +- .../telephony/CellSignalStrengthNrTest.java | 58 +++++++++++-------- .../telephony/SignalStrengthTest.java | 2 +- 3 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 85783ca17b..004444feb3 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -3275,7 +3275,8 @@ public class RILUtils { return new CellSignalStrengthNr(CellSignalStrengthNr.flip(ss.base.csiRsrp), CellSignalStrengthNr.flip(ss.base.csiRsrq), ss.base.csiSinr, ss.csiCqiTableIndex, ss.csiCqiReport, CellSignalStrengthNr.flip(ss.base.ssRsrp), - CellSignalStrengthNr.flip(ss.base.ssRsrq), ss.base.ssSinr); + CellSignalStrengthNr.flip(ss.base.ssRsrq), ss.base.ssSinr, + CellInfo.UNAVAILABLE); } return null; } @@ -3290,7 +3291,7 @@ public class RILUtils { return new CellSignalStrengthNr(CellSignalStrengthNr.flip(ss.csiRsrp), CellSignalStrengthNr.flip(ss.csiRsrq), ss.csiSinr, ss.csiCqiTableIndex, primitiveArrayToArrayList(ss.csiCqiReport), CellSignalStrengthNr.flip(ss.ssRsrp), - CellSignalStrengthNr.flip(ss.ssRsrq), ss.ssSinr); + CellSignalStrengthNr.flip(ss.ssRsrq), ss.ssSinr, ss.timingAdvance); } private static ClosedSubscriberGroupInfo convertHalClosedSubscriberGroupInfo( diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java index 47f545f995..11d57bfaa5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CellSignalStrengthNrTest.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import android.hardware.radio.V1_6.NrSignalStrength; +import android.hardware.radio.network.NrSignalStrength; import android.os.Parcel; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -55,9 +55,11 @@ public class CellSignalStrengthNrTest extends TelephonyTest { private static final int CSICQI_TABLE_INDEX = 1; private static final ArrayList CSICQI_REPORT = new ArrayList<>(Arrays.asList((byte) 3, (byte) 2, (byte) 1)); + private static final byte[] CSICQI_REPORT_PRIMITIVE = new byte[] {(byte) 3, (byte) 2, (byte) 1}; private static final int SSRSRP = -112; private static final int SSRSRQ = -13; private static final int SSSINR = 32; + private static final int TIMING_ADVANCE = 10; // Mocked classes ServiceState mSS; @@ -83,7 +85,7 @@ public class CellSignalStrengthNrTest extends TelephonyTest { public void testGetMethod() { // GIVEN an instance of CellSignalStrengthNr CellSignalStrengthNr css = new CellSignalStrengthNr(CSIRSRP, CSIRSRQ, CSISINR, - CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR); + CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR, TIMING_ADVANCE); // THEN the get method should return correct value assertThat(css.getCsiRsrp()).isEqualTo(CSIRSRP); @@ -95,20 +97,22 @@ public class CellSignalStrengthNrTest extends TelephonyTest { assertThat(css.getSsRsrq()).isEqualTo(SSRSRQ); assertThat(css.getSsSinr()).isEqualTo(SSSINR); assertThat(css.getDbm()).isEqualTo(SSRSRP); + assertThat(css.getTimingAdvanceMicros()).isEqualTo(TIMING_ADVANCE); } @Test public void testGetMethodWithHal() { // GIVEN an instance of NrSignalStrength with some positive values NrSignalStrength nrSignalStrength = new NrSignalStrength(); - nrSignalStrength.base.csiRsrp = -CSIRSRP; - nrSignalStrength.base.csiRsrq = -CSIRSRQ; - nrSignalStrength.base.csiSinr = CSISINR; + nrSignalStrength.csiRsrp = -CSIRSRP; + nrSignalStrength.csiRsrq = -CSIRSRQ; + nrSignalStrength.csiSinr = CSISINR; nrSignalStrength.csiCqiTableIndex = CSICQI_TABLE_INDEX; - nrSignalStrength.csiCqiReport = CSICQI_REPORT; - nrSignalStrength.base.ssRsrp = -SSRSRP; - nrSignalStrength.base.ssRsrq = -SSRSRQ; - nrSignalStrength.base.ssSinr = SSSINR; + nrSignalStrength.csiCqiReport = CSICQI_REPORT_PRIMITIVE; + nrSignalStrength.ssRsrp = -SSRSRP; + nrSignalStrength.ssRsrq = -SSRSRQ; + nrSignalStrength.ssSinr = SSSINR; + nrSignalStrength.timingAdvance = TIMING_ADVANCE; // THEN the get method should return the correct value CellSignalStrengthNr css = RILUtils.convertHalNrSignalStrength(nrSignalStrength); @@ -121,20 +125,22 @@ public class CellSignalStrengthNrTest extends TelephonyTest { assertThat(css.getSsRsrq()).isEqualTo(SSRSRQ); assertThat(css.getSsSinr()).isEqualTo(SSSINR); assertThat(css.getDbm()).isEqualTo(SSRSRP); + assertThat(css.getTimingAdvanceMicros()).isEqualTo(TIMING_ADVANCE); } @Test public void testUnavailableValueWithHal() { // GIVEN an instance of NrSignalStrength NrSignalStrength nrSignalStrength = new NrSignalStrength(); - nrSignalStrength.base.csiRsrp = CellInfo.UNAVAILABLE; - nrSignalStrength.base.csiRsrq = CellInfo.UNAVAILABLE; - nrSignalStrength.base.csiSinr = CellInfo.UNAVAILABLE; + nrSignalStrength.csiRsrp = CellInfo.UNAVAILABLE; + nrSignalStrength.csiRsrq = CellInfo.UNAVAILABLE; + nrSignalStrength.csiSinr = CellInfo.UNAVAILABLE; nrSignalStrength.csiCqiTableIndex = CellInfo.UNAVAILABLE; - nrSignalStrength.csiCqiReport = new ArrayList(); - nrSignalStrength.base.ssRsrp = CellInfo.UNAVAILABLE; - nrSignalStrength.base.ssRsrq = CellInfo.UNAVAILABLE; - nrSignalStrength.base.ssSinr = CellInfo.UNAVAILABLE; + nrSignalStrength.csiCqiReport = new byte[]{}; + nrSignalStrength.ssRsrp = CellInfo.UNAVAILABLE; + nrSignalStrength.ssRsrq = CellInfo.UNAVAILABLE; + nrSignalStrength.ssSinr = CellInfo.UNAVAILABLE; + nrSignalStrength.timingAdvance = CellInfo.UNAVAILABLE; // THEN the get method should return unavailable value CellSignalStrengthNr css = RILUtils.convertHalNrSignalStrength(nrSignalStrength); @@ -147,15 +153,16 @@ public class CellSignalStrengthNrTest extends TelephonyTest { assertThat(css.getSsRsrq()).isEqualTo(CellInfo.UNAVAILABLE); assertThat(css.getSsSinr()).isEqualTo(CellInfo.UNAVAILABLE); assertThat(css.getDbm()).isEqualTo(CellInfo.UNAVAILABLE); + assertThat(css.getTimingAdvanceMicros()).isEqualTo(CellInfo.UNAVAILABLE); } @Test public void testEquals_sameParameters() { // GIVEN an instance of CellSignalStrengthNr and another object with the same parameters CellSignalStrengthNr css = new CellSignalStrengthNr(CSIRSRP, CSIRSRQ, CSISINR, - CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR); + CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR, TIMING_ADVANCE); CellSignalStrengthNr anotherCss = new CellSignalStrengthNr(CSIRSRP, CSIRSRQ, CSISINR, - CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR); + CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR, TIMING_ADVANCE); // THEN this two objects are equivalent assertThat(css).isEqualTo(anotherCss); @@ -166,10 +173,10 @@ public class CellSignalStrengthNrTest extends TelephonyTest { // GIVEN an instance of CellSignalStrengthNr and another object with some different // parameters CellSignalStrengthNr css = new CellSignalStrengthNr(CSIRSRP, CSIRSRQ, CSISINR, - CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR); + CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR, TIMING_ADVANCE); CellSignalStrengthNr anotherCss = new CellSignalStrengthNr(ANOTHER_CSIRSRP, ANOTHER_CSIRSRQ, CSISINR, CSICQI_TABLE_INDEX, CSICQI_REPORT, - SSRSRP, SSRSRQ, SSSINR); + SSRSRP, SSRSRQ, SSSINR, TIMING_ADVANCE); // THEN this two objects are different assertThat(css).isNotEqualTo(anotherCss); @@ -179,7 +186,7 @@ public class CellSignalStrengthNrTest extends TelephonyTest { public void testAusLevel_validValue() { // GIVEN an instance of CellSignalStrengthNr with valid csirsrp CellSignalStrengthNr css = new CellSignalStrengthNr(CSIRSRP, CSIRSRQ, CSISINR, - CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR); + CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR, TIMING_ADVANCE); // THEN the asu level is in range [0, 97] assertThat(css.getAsuLevel()).isIn(Range.range(0, BoundType.CLOSED, 97, BoundType.CLOSED)); @@ -189,7 +196,7 @@ public class CellSignalStrengthNrTest extends TelephonyTest { public void testAsuLevel_invalidValue() { // GIVEN an instance of CellSignalStrengthNr with invalid csirsrp CellSignalStrengthNr css = new CellSignalStrengthNr(INVALID_CSIRSRP, CSIRSRQ, CSISINR, - CSICQI_TABLE_INDEX, CSICQI_REPORT, INVALID_SSRSRP, SSRSRQ, SSSINR); + CSICQI_TABLE_INDEX, CSICQI_REPORT, INVALID_SSRSRP, SSRSRQ, SSSINR, TIMING_ADVANCE); // THEN the asu level is unknown assertThat(css.getAsuLevel()).isEqualTo(CellSignalStrengthNr.UNKNOWN_ASU_LEVEL); @@ -200,7 +207,7 @@ public class CellSignalStrengthNrTest extends TelephonyTest { for (int ssRsrp = -156; ssRsrp <= -31; ssRsrp++) { // GIVEN an instance of CellSignalStrengthNr with valid csirsrp CellSignalStrengthNr css = new CellSignalStrengthNr(CSIRSRP, CSIRSRQ, CSISINR, - CSICQI_TABLE_INDEX, CSICQI_REPORT, ssRsrp, SSRSRQ, SSSINR); + CSICQI_TABLE_INDEX, CSICQI_REPORT, ssRsrp, SSRSRQ, SSSINR, TIMING_ADVANCE); // THEN the signal level is valid assertThat(css.getLevel()).isIn(Range.range( @@ -213,7 +220,7 @@ public class CellSignalStrengthNrTest extends TelephonyTest { public void testSignalLevel_invalidValue() { // GIVEN an instance of CellSignalStrengthNr with invalid csirsrp CellSignalStrengthNr css = new CellSignalStrengthNr(INVALID_CSIRSRP, CSIRSRQ, CSISINR, - CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR); + CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR, TIMING_ADVANCE); // THEN the signal level is unknown assertThat(css.getLevel()).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN); @@ -223,7 +230,7 @@ public class CellSignalStrengthNrTest extends TelephonyTest { public void testParcel() { // GIVEN an instance of CellSignalStrengthNr CellSignalStrengthNr css = new CellSignalStrengthNr(CSIRSRP, CSIRSRQ, CSISINR, - CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR); + CSICQI_TABLE_INDEX, CSICQI_REPORT, SSRSRP, SSRSRQ, SSSINR, TIMING_ADVANCE); // WHEN write the object to parcel and create another object with that parcel Parcel parcel = Parcel.obtain(); @@ -241,6 +248,7 @@ public class CellSignalStrengthNrTest extends TelephonyTest { assertThat(anotherCss.getSsRsrp()).isEqualTo(SSRSRP); assertThat(anotherCss.getSsRsrq()).isEqualTo(SSRSRQ); assertThat(anotherCss.getSsSinr()).isEqualTo(SSSINR); + assertThat(anotherCss.getTimingAdvanceMicros()).isEqualTo(TIMING_ADVANCE); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java index f15845cd42..96184c5ec7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthTest.java @@ -98,7 +98,7 @@ public class SignalStrengthTest { new CellSignalStrengthWcdma(-94, 4, -102, -5), new CellSignalStrengthTdscdma(-95, 2, -103), new CellSignalStrengthLte(-85, -91, -6, -10, 1, 12, 1), - new CellSignalStrengthNr(-91, -6, 3, 1, NrCqiReport, -80, -7, 4)); + new CellSignalStrengthNr(-91, -6, 3, 1, NrCqiReport, -80, -7, 4, 1)); assertParcelingIsLossless(s); PersistableBundle bundle = new PersistableBundle(); -- GitLab From 1d2c0802ee91ba95044d441c31e7999fa622ffe8 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Fri, 9 Dec 2022 00:20:05 -0800 Subject: [PATCH 247/656] Carrier config, log, and typo cleanup No major functional/behavioral changes. Query carrier configs once when they're updated instead of every time. Use carrier-specific configs if they exist, otherwise use default. Fix logs that were getting cut off or not printed properly. Fix typos in variable names. Remove unused variables or methods. Test: atest ServiceStateTrackerTest, NetworkTypeControllerTest Change-Id: Ib1be6804ef6f38c603414c5aa03ad52bcb3691cd --- .../telephony/NetworkTypeController.java | 175 ++++++--------- .../telephony/ServiceStateTracker.java | 200 +++++++----------- .../data/DataStallRecoveryManager.java | 22 +- .../telephony/NetworkTypeControllerTest.java | 63 +----- .../telephony/ServiceStateTrackerTest.java | 2 +- 5 files changed, 166 insertions(+), 296 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 1c4b9b55c8..c02a9c3e58 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -40,6 +40,7 @@ import android.telephony.data.DataCallResponse.LinkStatus; import android.text.TextUtils; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; +import com.android.internal.telephony.data.DataUtils; import com.android.internal.telephony.util.ArrayUtils; import com.android.internal.util.IState; import com.android.internal.util.IndentingPrintWriter; @@ -154,7 +155,7 @@ public class NetworkTypeController extends StateMachine { private boolean mIsPhysicalChannelConfigOn; private boolean mIsPrimaryTimerActive; private boolean mIsSecondaryTimerActive; - private boolean mIsTimerResetEnabledForLegacyStateRRCIdle; + private boolean mIsTimerResetEnabledForLegacyStateRrcIdle; private int mLtePlusThresholdBandwidth; private int mNrAdvancedThresholdBandwidth; private boolean mIncludeLteForNrAdvancedThresholdBandwidth; @@ -192,13 +193,14 @@ public class NetworkTypeController extends StateMachine { mPrimaryTimerState = ""; mSecondaryTimerState = ""; mPreviousState = ""; - addState(mDefaultState); - addState(mLegacyState, mDefaultState); - addState(mIdleState, mDefaultState); - addState(mLteConnectedState, mDefaultState); - addState(mNrConnectedState, mDefaultState); - addState(mNrConnectedAdvancedState, mDefaultState); - setInitialState(mDefaultState); + DefaultState defaultState = new DefaultState(); + addState(defaultState); + addState(mLegacyState, defaultState); + addState(mIdleState, defaultState); + addState(mLteConnectedState, defaultState); + addState(mNrConnectedState, defaultState); + addState(mNrConnectedAdvancedState, defaultState); + setInitialState(defaultState); start(); mServiceState = mPhone.getServiceStateTracker().getServiceState(); @@ -263,69 +265,34 @@ public class NetworkTypeController extends StateMachine { } private void parseCarrierConfigs() { - String nrIconConfiguration = CarrierConfigManager.getDefaultConfig().getString( - CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING); - String overrideTimerRule = CarrierConfigManager.getDefaultConfig().getString( - CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING); - String overrideSecondaryTimerRule = CarrierConfigManager.getDefaultConfig().getString( - CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING); - mLteEnhancedPattern = CarrierConfigManager.getDefaultConfig().getString( + PersistableBundle config = CarrierConfigManager.getDefaultConfig(); + CarrierConfigManager configManager = + mPhone.getContext().getSystemService(CarrierConfigManager.class); + if (configManager != null) { + PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); + if (b != null) { + config = b; + } + } + mLteEnhancedPattern = config.getString( CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING); - mIsTimerResetEnabledForLegacyStateRRCIdle = - CarrierConfigManager.getDefaultConfig().getBoolean( - CarrierConfigManager.KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL); - mLtePlusThresholdBandwidth = CarrierConfigManager.getDefaultConfig().getInt( + mIsTimerResetEnabledForLegacyStateRrcIdle = config.getBoolean( + CarrierConfigManager.KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL); + mLtePlusThresholdBandwidth = config.getInt( CarrierConfigManager.KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT); - mNrAdvancedThresholdBandwidth = CarrierConfigManager.getDefaultConfig().getInt( + mNrAdvancedThresholdBandwidth = config.getInt( CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT); - mIncludeLteForNrAdvancedThresholdBandwidth = CarrierConfigManager.getDefaultConfig() - .getBoolean(CarrierConfigManager - .KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); - mEnableNrAdvancedWhileRoaming = CarrierConfigManager.getDefaultConfig().getBoolean( + mIncludeLteForNrAdvancedThresholdBandwidth = config.getBoolean( + CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); + mEnableNrAdvancedWhileRoaming = config.getBoolean( CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL); - - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager != null) { - PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); - if (b != null) { - if (b.getString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING) != null) { - nrIconConfiguration = b.getString( - CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING); - } - if (b.getString(CarrierConfigManager - .KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING) != null) { - overrideTimerRule = b.getString( - CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING); - } - if (b.getString(CarrierConfigManager - .KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING) != null) { - overrideSecondaryTimerRule = b.getString( - CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING); - } - if (b.getString(CarrierConfigManager - .KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING) != null) { - mLteEnhancedPattern = b.getString( - CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING); - } - mIsTimerResetEnabledForLegacyStateRRCIdle = b.getBoolean( - CarrierConfigManager.KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL); - mLtePlusThresholdBandwidth = b.getInt( - CarrierConfigManager.KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, - mLtePlusThresholdBandwidth); - mNrAdvancedThresholdBandwidth = b.getInt( - CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, - mNrAdvancedThresholdBandwidth); - mIncludeLteForNrAdvancedThresholdBandwidth = b.getBoolean(CarrierConfigManager - .KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, - mIncludeLteForNrAdvancedThresholdBandwidth); - mAdditionalNrAdvancedBandsList = b.getIntArray( - CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY); - mNrAdvancedCapablePcoId = b.getInt( - CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT); - if (mNrAdvancedCapablePcoId > 0 && mNrAdvancedCapableByPcoChangedCallback == null) { - mNrAdvancedCapableByPcoChangedCallback = - new DataNetworkControllerCallback(getHandler()::post) { + mAdditionalNrAdvancedBandsList = config.getIntArray( + CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY); + mNrAdvancedCapablePcoId = config.getInt( + CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT); + if (mNrAdvancedCapablePcoId > 0 && mNrAdvancedCapableByPcoChangedCallback == null) { + mNrAdvancedCapableByPcoChangedCallback = + new DataNetworkControllerCallback(getHandler()::post) { @Override public void onNrAdvancedCapableByPcoChanged(boolean nrAdvancedCapable) { log("mIsNrAdvancedAllowedByPco=" + nrAdvancedCapable); @@ -333,39 +300,39 @@ public class NetworkTypeController extends StateMachine { sendMessage(EVENT_UPDATE); } }; - mPhone.getDataNetworkController().registerDataNetworkControllerCallback( - mNrAdvancedCapableByPcoChangedCallback); - } else if (mNrAdvancedCapablePcoId == 0 - && mNrAdvancedCapableByPcoChangedCallback != null) { - mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( - mNrAdvancedCapableByPcoChangedCallback); - mNrAdvancedCapableByPcoChangedCallback = null; - } - mEnableNrAdvancedWhileRoaming = b.getBoolean( - CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL); - mIsUsingUserDataForRrcDetection = b.getBoolean( - CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL); - if (!mIsPhysicalChannelConfig16Supported || mIsUsingUserDataForRrcDetection) { - if (mNrPhysicalLinkStatusChangedCallback == null) { - mNrPhysicalLinkStatusChangedCallback = - new DataNetworkControllerCallback(getHandler()::post) { + mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + mNrAdvancedCapableByPcoChangedCallback); + } else if (mNrAdvancedCapablePcoId == 0 && mNrAdvancedCapableByPcoChangedCallback != null) { + mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( + mNrAdvancedCapableByPcoChangedCallback); + mNrAdvancedCapableByPcoChangedCallback = null; + } + mIsUsingUserDataForRrcDetection = config.getBoolean( + CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL); + if (!isUsingPhysicalChannelConfigForRrcDetection()) { + if (mNrPhysicalLinkStatusChangedCallback == null) { + mNrPhysicalLinkStatusChangedCallback = + new DataNetworkControllerCallback(getHandler()::post) { @Override - public void onPhysicalLinkStatusChanged( - @LinkStatus int status) { - sendMessage(obtainMessage( - EVENT_PHYSICAL_LINK_STATUS_CHANGED, + public void onPhysicalLinkStatusChanged(@LinkStatus int status) { + sendMessage(obtainMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, new AsyncResult(null, status, null))); - }}; - mPhone.getDataNetworkController().registerDataNetworkControllerCallback( - mNrPhysicalLinkStatusChangedCallback); - } - } else if (mNrPhysicalLinkStatusChangedCallback != null) { - mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( - mNrPhysicalLinkStatusChangedCallback); - mNrPhysicalLinkStatusChangedCallback = null; - } + } + }; + mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + mNrPhysicalLinkStatusChangedCallback); } + } else if (mNrPhysicalLinkStatusChangedCallback != null) { + mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( + mNrPhysicalLinkStatusChangedCallback); + mNrPhysicalLinkStatusChangedCallback = null; } + String nrIconConfiguration = config.getString( + CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING); + String overrideTimerRule = config.getString( + CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING); + String overrideSecondaryTimerRule = config.getString( + CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING); createTimerRules(nrIconConfiguration, overrideTimerRule, overrideSecondaryTimerRule); } @@ -661,8 +628,6 @@ public class NetworkTypeController extends StateMachine { } } - private final DefaultState mDefaultState = new DefaultState(); - /** * Device does not have NR available, due to any of the below reasons: *
    @@ -721,7 +686,7 @@ public class NetworkTypeController extends StateMachine { if (DBG) log("Physical channel configs updated: " + mPhysicalChannelConfigs); if (isUsingPhysicalChannelConfigForRrcDetection()) { mPhysicalLinkStatus = getPhysicalLinkStatusFromPhysicalChannelConfig(); - if (mIsTimerResetEnabledForLegacyStateRRCIdle && !isPhysicalLinkActive()) { + if (mIsTimerResetEnabledForLegacyStateRrcIdle && !isPhysicalLinkActive()) { if (DBG) log("Reset timers since timer reset is enabled for RRC idle."); resetAllTimers(); } @@ -730,7 +695,7 @@ public class NetworkTypeController extends StateMachine { case EVENT_PHYSICAL_LINK_STATUS_CHANGED: AsyncResult ar = (AsyncResult) msg.obj; mPhysicalLinkStatus = (int) ar.result; - if (mIsTimerResetEnabledForLegacyStateRRCIdle && !isPhysicalLinkActive()) { + if (mIsTimerResetEnabledForLegacyStateRrcIdle && !isPhysicalLinkActive()) { if (DBG) log("Reset timers since timer reset is enabled for RRC idle."); resetAllTimers(); updateOverrideNetworkType(); @@ -1394,16 +1359,16 @@ public class NetworkTypeController extends StateMachine { pw.println("mIsPhysicalChannelConfigOn=" + mIsPhysicalChannelConfigOn); pw.println("mIsPrimaryTimerActive=" + mIsPrimaryTimerActive); pw.println("mIsSecondaryTimerActive=" + mIsSecondaryTimerActive); - pw.println("mIsTimerRestEnabledForLegacyStateRRCIdle=" - + mIsTimerResetEnabledForLegacyStateRRCIdle); + pw.println("mIsTimerResetEnabledForLegacyStateRrcIdle=" + + mIsTimerResetEnabledForLegacyStateRrcIdle); pw.println("mLtePlusThresholdBandwidth=" + mLtePlusThresholdBandwidth); pw.println("mNrAdvancedThresholdBandwidth=" + mNrAdvancedThresholdBandwidth); + pw.println("mAdditionalNrAdvancedBandsList=" + + Arrays.toString(mAdditionalNrAdvancedBandsList)); pw.println("mPrimaryTimerState=" + mPrimaryTimerState); pw.println("mSecondaryTimerState=" + mSecondaryTimerState); pw.println("mPreviousState=" + mPreviousState); - pw.println("mPhysicalLinkStatus=" + mPhysicalLinkStatus); - pw.println("mAdditionalNrAdvancedBandsList=" - + Arrays.toString(mAdditionalNrAdvancedBandsList)); + pw.println("mPhysicalLinkStatus=" + DataUtils.linkStatusToString(mPhysicalLinkStatus)); pw.println("mIsPhysicalChannelConfig16Supported=" + mIsPhysicalChannelConfig16Supported); pw.println("mIsNrAdvancedAllowedByPco=" + mIsNrAdvancedAllowedByPco); pw.println("mNrAdvancedCapablePcoId=" + mNrAdvancedCapablePcoId); diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 1925275467..1df84da4ac 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -147,7 +147,7 @@ public class ServiceStateTracker extends Handler { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private UiccController mUiccController = null; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private UiccCardApplication mUiccApplcation = null; + private UiccCardApplication mUiccApplication = null; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private IccRecords mIccRecords = null; @@ -183,13 +183,12 @@ public class ServiceStateTracker extends Handler { private final Set mRadioPowerOffReasons = new HashSet(); - // TODO - this should not be public, right now used externally GsmConnetion. + // TODO - this should not be public, right now used externally GsmConnection. public RestrictedState mRestrictedState; /** - * A unique identifier to track requests associated with a poll - * and ignore stale responses. The value is a count-down of - * expected responses in this pollingContext. + * A unique identifier to track requests associated with a poll and ignore stale responses. + * The value is a count-down of expected responses in this pollingContext. */ @VisibleForTesting public int[] mPollingContext; @@ -310,7 +309,7 @@ public class ServiceStateTracker extends Handler { // Show PLMN only and only if this bit is set. public static final int CARRIER_NAME_DISPLAY_BITMASK_SHOW_PLMN = 1 << 1; - private List mPendingCellInfoRequests = new LinkedList(); + private List mPendingCellInfoRequests = new LinkedList<>(); // @GuardedBy("mPendingCellInfoRequests") private boolean mIsPendingCellInfoRequest = false; @@ -352,7 +351,6 @@ public class ServiceStateTracker extends Handler { private final SstSubscriptionsChangedListener mOnSubscriptionsChangedListener = new SstSubscriptionsChangedListener(); - private final RatRatcheter mRatRatcheter; private final LocaleTracker mLocaleTracker; @@ -365,6 +363,7 @@ public class ServiceStateTracker extends Handler { private final LocalLog mCdnrLogs = new LocalLog(64); private Pattern mOperatorNameStringPattern; + private PersistableBundle mCarrierConfig; private class SstSubscriptionsChangedListener extends OnSubscriptionsChangedListener { @@ -662,6 +661,7 @@ public class ServiceStateTracker extends Handler { mSubscriptionManager.addOnSubscriptionsChangedListener( new android.os.HandlerExecutor(this), mOnSubscriptionsChangedListener); mRestrictedState = new RestrictedState(); + mCarrierConfig = getCarrierConfig(); mAccessNetworksManager = mPhone.getAccessNetworksManager(); mOutOfServiceSS = new ServiceState(); @@ -693,7 +693,6 @@ public class ServiceStateTracker extends Handler { mRadioPowerLog.log("init : airplane mode = " + airplaneMode + " enableCellularOnBoot = " + enableCellularOnBoot); - mPhone.getCarrierActionAgent().registerForCarrierAction(CARRIER_ACTION_SET_RADIO_ENABLED, this, EVENT_RADIO_POWER_FROM_CARRIER, null, false); @@ -1097,8 +1096,8 @@ public class ServiceStateTracker extends Handler { /** * Turn on or off radio power with option to specify whether it's for emergency call and specify * a reason for setting the power state. - * More details check {@link PhoneInternalInterface#setRadioPower( - * boolean, boolean, boolean, boolean, int)}. + * More details check {@link + * PhoneInternalInterface#setRadioPowerForReason(boolean, boolean, boolean, boolean, int)}. */ public void setRadioPowerForReason(boolean power, boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, boolean forceApply, int reason) { @@ -1204,8 +1203,8 @@ public class ServiceStateTracker extends Handler { mCdnr.updateEfFromUsim(null /* Usim */); } onUpdateIccAvailability(); - if (mUiccApplcation == null - || mUiccApplcation.getState() != AppState.APPSTATE_READY) { + if (mUiccApplication == null + || mUiccApplication.getState() != AppState.APPSTATE_READY) { mIsSimReady = false; updateSpnDisplay(); } @@ -2187,8 +2186,6 @@ public class ServiceStateTracker extends Handler { int registrationState = networkRegState.getInitialRegistrationState(); int cssIndicator = voiceSpecificStates.cssSupported ? 1 : 0; - int newVoiceRat = ServiceState.networkTypeToRilRadioTechnology( - networkRegState.getAccessNetworkTechnology()); mNewSS.setVoiceRegState(regCodeToServiceState(registrationState)); mNewSS.setCssIndicator(cssIndicator); mNewSS.addNetworkRegistrationInfo(networkRegState); @@ -2221,7 +2218,7 @@ public class ServiceStateTracker extends Handler { && !isRoamIndForHomeSystem(roamingIndicator); mNewSS.setVoiceRoaming(cdmaRoaming); mRoamingIndicator = roamingIndicator; - mIsInPrl = (systemIsInPrl == 0) ? false : true; + mIsInPrl = systemIsInPrl != 0; mDefaultRoamingIndicator = defaultRoamingIndicator; int systemId = 0; @@ -2598,8 +2595,7 @@ public class ServiceStateTracker extends Handler { */ private boolean isRoamIndForHomeSystem(int roamInd) { // retrieve the carrier-specified list of ERIs for home system - final PersistableBundle config = getCarrierConfig(); - int[] homeRoamIndicators = config.getIntArray(CarrierConfigManager + int[] homeRoamIndicators = mCarrierConfig.getIntArray(CarrierConfigManager .KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY); log("isRoamIndForHomeSystem: homeRoamIndicators=" + Arrays.toString(homeRoamIndicators)); @@ -2628,8 +2624,6 @@ public class ServiceStateTracker extends Handler { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) protected void updateRoamingState() { - PersistableBundle bundle = getCarrierConfig(); - if (mPhone.isPhoneTypeGsm()) { /** * Since the roaming state of gsm service (from +CREG) and @@ -2654,14 +2648,14 @@ public class ServiceStateTracker extends Handler { roaming = false; } - if (alwaysOnHomeNetwork(bundle)) { + if (alwaysOnHomeNetwork(mCarrierConfig)) { log("updateRoamingState: carrier config override always on home network"); roaming = false; - } else if (isNonRoamingInGsmNetwork(bundle, mNewSS.getOperatorNumeric())) { + } else if (isNonRoamingInGsmNetwork(mCarrierConfig, mNewSS.getOperatorNumeric())) { log("updateRoamingState: carrier config override set non roaming:" + mNewSS.getOperatorNumeric()); roaming = false; - } else if (isRoamingInGsmNetwork(bundle, mNewSS.getOperatorNumeric())) { + } else if (isRoamingInGsmNetwork(mCarrierConfig, mNewSS.getOperatorNumeric())) { log("updateRoamingState: carrier config override set roaming:" + mNewSS.getOperatorNumeric()); roaming = true; @@ -2671,16 +2665,16 @@ public class ServiceStateTracker extends Handler { } else { String systemId = Integer.toString(mNewSS.getCdmaSystemId()); - if (alwaysOnHomeNetwork(bundle)) { + if (alwaysOnHomeNetwork(mCarrierConfig)) { log("updateRoamingState: carrier config override always on home network"); setRoamingOff(); - } else if (isNonRoamingInGsmNetwork(bundle, mNewSS.getOperatorNumeric()) - || isNonRoamingInCdmaNetwork(bundle, systemId)) { + } else if (isNonRoamingInGsmNetwork(mCarrierConfig, mNewSS.getOperatorNumeric()) + || isNonRoamingInCdmaNetwork(mCarrierConfig, systemId)) { log("updateRoamingState: carrier config override set non-roaming:" + mNewSS.getOperatorNumeric() + ", " + systemId); setRoamingOff(); - } else if (isRoamingInGsmNetwork(bundle, mNewSS.getOperatorNumeric()) - || isRoamingInCdmaNetwork(bundle, systemId)) { + } else if (isRoamingInGsmNetwork(mCarrierConfig, mNewSS.getOperatorNumeric()) + || isRoamingInCdmaNetwork(mCarrierConfig, systemId)) { log("updateRoamingState: carrier config override set roaming:" + mNewSS.getOperatorNumeric() + ", " + systemId); setRoamingOn(); @@ -2711,17 +2705,14 @@ public class ServiceStateTracker extends Handler { if (!mPhone.isPhoneTypeGsm() && !mSS.getRoaming()) { boolean hasBrandOverride = mUiccController.getUiccPort(getPhoneId()) != null && mUiccController.getUiccPort(getPhoneId()).getOperatorBrandOverride() != null; - if (!hasBrandOverride) { - PersistableBundle config = getCarrierConfig(); - if (config.getBoolean( + if (!hasBrandOverride && mCarrierConfig.getBoolean( CarrierConfigManager.KEY_CDMA_HOME_REGISTERED_PLMN_NAME_OVERRIDE_BOOL)) { - String operator = config.getString( - CarrierConfigManager.KEY_CDMA_HOME_REGISTERED_PLMN_NAME_STRING); - log("updateOperatorNameFromCarrierConfig: changing from " - + mSS.getOperatorAlpha() + " to " + operator); - // override long and short operator name, keeping numeric the same - mSS.setOperatorName(operator, operator, mSS.getOperatorNumeric()); - } + String operator = mCarrierConfig.getString( + CarrierConfigManager.KEY_CDMA_HOME_REGISTERED_PLMN_NAME_STRING); + log("updateOperatorNameFromCarrierConfig: changing from " + + mSS.getOperatorAlpha() + " to " + operator); + // override long and short operator name, keeping numeric the same + mSS.setOperatorName(operator, operator, mSS.getOperatorNumeric()); } } } @@ -2809,8 +2800,8 @@ public class ServiceStateTracker extends Handler { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @VisibleForTesting public void updateSpnDisplay() { - PersistableBundle config = getCarrierConfig(); - if (config.getBoolean(CarrierConfigManager.KEY_ENABLE_CARRIER_DISPLAY_NAME_RESOLVER_BOOL)) { + if (mCarrierConfig.getBoolean( + CarrierConfigManager.KEY_ENABLE_CARRIER_DISPLAY_NAME_RESOLVER_BOOL)) { updateSpnDisplayCdnr(); } else { updateSpnDisplayLegacy(); @@ -2823,8 +2814,8 @@ public class ServiceStateTracker extends Handler { String spn = null; String dataSpn = null; boolean showSpn = false; - String plmn = null; - boolean showPlmn = false; + String plmn; + boolean showPlmn; String wfcVoiceSpnFormat = null; String wfcDataSpnFormat = null; @@ -2842,20 +2833,17 @@ public class ServiceStateTracker extends Handler { // // 2) Show PLMN + Wi-Fi Calling if there is no valid SPN in case 1 - int voiceIdx = 0; - int dataIdx = 0; - int flightModeIdx = -1; - boolean useRootLocale = false; - - PersistableBundle bundle = getCarrierConfig(); + int voiceIdx; + int dataIdx; + int flightModeIdx; + boolean useRootLocale; - voiceIdx = bundle.getInt(CarrierConfigManager.KEY_WFC_SPN_FORMAT_IDX_INT); - dataIdx = bundle.getInt( - CarrierConfigManager.KEY_WFC_DATA_SPN_FORMAT_IDX_INT); - flightModeIdx = bundle.getInt( + voiceIdx = mCarrierConfig.getInt(CarrierConfigManager.KEY_WFC_SPN_FORMAT_IDX_INT); + dataIdx = mCarrierConfig.getInt(CarrierConfigManager.KEY_WFC_DATA_SPN_FORMAT_IDX_INT); + flightModeIdx = mCarrierConfig.getInt( CarrierConfigManager.KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT); useRootLocale = - bundle.getBoolean(CarrierConfigManager.KEY_WFC_SPN_USE_ROOT_LOCALE); + mCarrierConfig.getBoolean(CarrierConfigManager.KEY_WFC_SPN_USE_ROOT_LOCALE); String[] wfcSpnFormats = SubscriptionManager.getResourcesForSubId(mPhone.getContext(), mPhone.getSubId(), useRootLocale) @@ -2886,21 +2874,19 @@ public class ServiceStateTracker extends Handler { && (mPhone.getImsPhone() != null) && (mPhone.getImsPhone().getImsRegistrationTech() == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM)) { - // In Cros SIM Calling mode show SPN or PLMN + Cross SIM Calling + // In Cross SIM Calling mode show SPN or PLMN + Cross SIM Calling // // 1) Show SPN + Cross SIM Calling If SIM has SPN and SPN display condition // is satisfied or SPN override is enabled for this carrier // // 2) Show PLMN + Cross SIM Calling if there is no valid SPN in case 1 - PersistableBundle bundle = getCarrierConfig(); int crossSimSpnFormatIdx = - bundle.getInt(CarrierConfigManager.KEY_CROSS_SIM_SPN_FORMAT_INT); + mCarrierConfig.getInt(CarrierConfigManager.KEY_CROSS_SIM_SPN_FORMAT_INT); boolean useRootLocale = - bundle.getBoolean(CarrierConfigManager.KEY_WFC_SPN_USE_ROOT_LOCALE); + mCarrierConfig.getBoolean(CarrierConfigManager.KEY_WFC_SPN_USE_ROOT_LOCALE); String[] crossSimSpnFormats = SubscriptionManager.getResourcesForSubId( - mPhone.getContext(), - mPhone.getSubId(), useRootLocale) + mPhone.getContext(), mPhone.getSubId(), useRootLocale) .getStringArray(R.array.crossSimSpnFormats); if (crossSimSpnFormatIdx < 0 || crossSimSpnFormatIdx >= crossSimSpnFormats.length) { @@ -2930,7 +2916,6 @@ public class ServiceStateTracker extends Handler { // EXTRA_SHOW_PLMN = true // EXTRA_PLMN = null - IccRecords iccRecords = mIccRecords; int rule = getCarrierNameDisplayBitmask(mSS); boolean noService = false; if (combinedRegState == ServiceState.STATE_OUT_OF_SERVICE @@ -2946,8 +2931,7 @@ public class ServiceStateTracker extends Handler { } else { // No service at all plmn = Resources.getSystem() - .getText( - com.android.internal.R.string.lockscreen_carrier_default) + .getText(com.android.internal.R.string.lockscreen_carrier_default) .toString(); noService = true; } @@ -2990,8 +2974,7 @@ public class ServiceStateTracker extends Handler { } else if (!TextUtils.isEmpty(plmn)) { // Show PLMN + Cross-SIM Calling if there is no valid SPN in the above case String originalPlmn = plmn.trim(); - PersistableBundle config = getCarrierConfig(); - if (mIccRecords != null && config.getBoolean( + if (mIccRecords != null && mCarrierConfig.getBoolean( CarrierConfigManager.KEY_WFC_CARRIER_NAME_OVERRIDE_BY_PNN_BOOL)) { originalPlmn = mIccRecords.getPnnHomeName(); } @@ -3016,8 +2999,7 @@ public class ServiceStateTracker extends Handler { // Show PLMN + Wi-Fi Calling if there is no valid SPN in the above case String originalPlmn = plmn.trim(); - PersistableBundle config = getCarrierConfig(); - if (mIccRecords != null && config.getBoolean( + if (mIccRecords != null && mCarrierConfig.getBoolean( CarrierConfigManager.KEY_WFC_CARRIER_NAME_OVERRIDE_BY_PNN_BOOL)) { originalPlmn = mIccRecords.getPnnHomeName(); } @@ -3137,7 +3119,6 @@ public class ServiceStateTracker extends Handler { /** * Cancel the EVENT_POWER_OFF_RADIO_DELAYED event if it is currently pending to be completed. - * @return true if there was a pending timeout message in the queue, false otherwise. */ private void cancelDelayRadioOffWaitingForImsDeregTimeout() { if (hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT)) { @@ -3146,21 +3127,6 @@ public class ServiceStateTracker extends Handler { } } - /** - * Start a timer to turn off the radio if IMS does not move to deregistered after the - * radio power off event occurred. If this event already exists in the message queue, then - * ignore the new request and use the existing one. - */ - private void startDelayRadioOffWaitingForImsDeregTimeout() { - if (hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT)) { - if (DBG) log("startDelayRadioOffWaitingForImsDeregTimeout: timer exists, ignoring"); - return; - } - if (DBG) log("startDelayRadioOffWaitingForImsDeregTimeout: starting timer"); - sendEmptyMessageDelayed(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT, - getRadioPowerOffDelayTimeoutForImsRegistration()); - } - protected void onUpdateIccAvailability() { if (mUiccController == null ) { return; @@ -3168,7 +3134,7 @@ public class ServiceStateTracker extends Handler { UiccCardApplication newUiccApplication = getUiccCardApplication(); - if (mUiccApplcation != newUiccApplication) { + if (mUiccApplication != newUiccApplication) { // Remove the EF records that come from UICC if (mIccRecords instanceof SIMRecords) { @@ -3177,26 +3143,26 @@ public class ServiceStateTracker extends Handler { mCdnr.updateEfFromRuim(null /* ruim */); } - if (mUiccApplcation != null) { + if (mUiccApplication != null) { log("Removing stale icc objects."); - mUiccApplcation.unregisterForReady(this); + mUiccApplication.unregisterForReady(this); if (mIccRecords != null) { mIccRecords.unregisterForRecordsLoaded(this); } mIccRecords = null; - mUiccApplcation = null; + mUiccApplication = null; } if (newUiccApplication != null) { log("New card found"); - mUiccApplcation = newUiccApplication; - mIccRecords = mUiccApplcation.getIccRecords(); + mUiccApplication = newUiccApplication; + mIccRecords = mUiccApplication.getIccRecords(); if (mPhone.isPhoneTypeGsm()) { - mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null); + mUiccApplication.registerForReady(this, EVENT_SIM_READY, null); if (mIccRecords != null) { mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); } } else if (mIsSubscriptionFromRuim) { - mUiccApplcation.registerForReady(this, EVENT_RUIM_READY, null); + mUiccApplication.registerForReady(this, EVENT_RUIM_READY, null); if (mIccRecords != null) { mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null); } @@ -3455,9 +3421,9 @@ public class ServiceStateTracker extends Handler { setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity()); if (DBG) { - log("Poll ServiceState done: " - + " oldSS=[" + mSS + "] newSS=[" + mNewSS + "]" - + " oldMaxDataCalls=" + mMaxDataCalls + log("Poll ServiceState done: oldSS=" + mSS); + log("Poll ServiceState done: newSS=" + mNewSS); + log("Poll ServiceState done: oldMaxDataCalls=" + mMaxDataCalls + " mNewMaxDataCalls=" + mNewMaxDataCalls + " oldReasonDataDenied=" + mReasonDataDenied + " mNewReasonDataDenied=" + mNewReasonDataDenied); @@ -3968,8 +3934,9 @@ public class ServiceStateTracker extends Handler { } } - if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY && - mIccRecords != null && getCombinedRegState(mSS) == ServiceState.STATE_IN_SERVICE + if (mUiccApplication != null && mUiccApplication.getState() == AppState.APPSTATE_READY + && mIccRecords != null + && getCombinedRegState(mSS) == ServiceState.STATE_IN_SERVICE && !ServiceState.isPsOnlyTech(mSS.getRilVoiceRadioTechnology())) { // SIM is found on the device. If ERI roaming is OFF, and SID/NID matches // one configured in SIM, use operator name from CSIM record. Note that ERI, SID, @@ -4000,10 +3967,9 @@ public class ServiceStateTracker extends Handler { } String carrierName = mIccRecords != null ? mIccRecords.getServiceProviderName() : ""; - PersistableBundle config = getCarrierConfig(); - if (config.getBoolean(CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL) + if (mCarrierConfig.getBoolean(CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL) || TextUtils.isEmpty(carrierName)) { - return config.getString(CarrierConfigManager.KEY_CARRIER_NAME_STRING); + return mCarrierConfig.getString(CarrierConfigManager.KEY_CARRIER_NAME_STRING); } return carrierName; @@ -4022,7 +3988,6 @@ public class ServiceStateTracker extends Handler { */ @CarrierNameDisplayBitmask public int getCarrierNameDisplayBitmask(ServiceState ss) { - PersistableBundle config = getCarrierConfig(); if (!TextUtils.isEmpty(getOperatorBrandOverride())) { // If the operator has been overridden, all PLMNs will be considered HOME PLMNs, only // show SPN. @@ -4032,7 +3997,7 @@ public class ServiceStateTracker extends Handler { // This is a hack from IccRecords#getServiceProviderName(). return CARRIER_NAME_DISPLAY_BITMASK_SHOW_PLMN; } else { - boolean useRoamingFromServiceState = config.getBoolean( + boolean useRoamingFromServiceState = mCarrierConfig.getBoolean( CarrierConfigManager.KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL); int carrierDisplayNameConditionFromSim = mIccRecords == null ? 0 : mIccRecords.getCarrierNameDisplayCondition(); @@ -4252,8 +4217,7 @@ public class ServiceStateTracker extends Handler { private boolean isOperatorConsideredNonRoaming(ServiceState s) { String operatorNumeric = s.getOperatorNumeric(); - PersistableBundle config = getCarrierConfig(); - String[] numericArray = config.getStringArray( + String[] numericArray = mCarrierConfig.getStringArray( CarrierConfigManager.KEY_NON_ROAMING_OPERATOR_STRING_ARRAY); if (ArrayUtils.isEmpty(numericArray) || operatorNumeric == null) { @@ -4270,8 +4234,7 @@ public class ServiceStateTracker extends Handler { private boolean isOperatorConsideredRoaming(ServiceState s) { String operatorNumeric = s.getOperatorNumeric(); - PersistableBundle config = getCarrierConfig(); - String[] numericArray = config.getStringArray( + String[] numericArray = mCarrierConfig.getStringArray( CarrierConfigManager.KEY_ROAMING_OPERATOR_STRING_ARRAY); if (ArrayUtils.isEmpty(numericArray) || operatorNumeric == null) { return false; @@ -4304,12 +4267,12 @@ public class ServiceStateTracker extends Handler { ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) || ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); //ignore the normal call and data restricted state before SIM READY - if (mUiccApplcation != null && mUiccApplcation.getState() == AppState.APPSTATE_READY) { + if (mUiccApplication != null + && mUiccApplication.getState() == AppState.APPSTATE_READY) { newRs.setCsNormalRestricted( ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) || ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) ); - newRs.setPsRestricted( - (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0); + newRs.setPsRestricted((state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL) != 0); } if (DBG) log("onRestrictedStateChanged: new rs "+ newRs); @@ -4550,10 +4513,8 @@ public class ServiceStateTracker extends Handler { return; } - boolean autoCancelCsRejectNotification = false; - - PersistableBundle bundle = getCarrierConfig(); - boolean disableVoiceBarringNotification = bundle.getBoolean( + boolean autoCancelCsRejectNotification; + boolean disableVoiceBarringNotification = mCarrierConfig.getBoolean( CarrierConfigManager.KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false); if (disableVoiceBarringNotification && (notifyType == CS_ENABLED || notifyType == CS_NORMAL_ENABLED @@ -4561,7 +4522,7 @@ public class ServiceStateTracker extends Handler { if (DBG) log("Voice/emergency call barred notification disabled"); return; } - autoCancelCsRejectNotification = bundle.getBoolean( + autoCancelCsRejectNotification = mCarrierConfig.getBoolean( CarrierConfigManager.KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false); CharSequence details = ""; @@ -5055,8 +5016,8 @@ public class ServiceStateTracker extends Handler { } private void onCarrierConfigChanged() { - PersistableBundle config = getCarrierConfig(); - log("CarrierConfigChange " + config); + mCarrierConfig = getCarrierConfig(); + log("CarrierConfigChange " + mCarrierConfig); // Load the ERI based on carrier config. Carrier might have their specific ERI. if (mEriManager != null) { @@ -5064,8 +5025,8 @@ public class ServiceStateTracker extends Handler { mCdnr.updateEfForEri(getOperatorNameFromEri()); } - updateOperatorNamePattern(config); - mCdnr.updateEfFromCarrierConfig(config); + updateOperatorNamePattern(mCarrierConfig); + mCdnr.updateEfFromCarrierConfig(mCarrierConfig); mPhone.notifyCallForwardingIndicator(); // Sometimes the network registration information comes before carrier config is ready. @@ -5123,8 +5084,8 @@ public class ServiceStateTracker extends Handler { // Determine if the Icc card exists private boolean iccCardExists() { boolean iccCardExist = false; - if (mUiccApplcation != null) { - iccCardExist = mUiccApplcation.getState() != AppState.APPSTATE_UNKNOWN; + if (mUiccApplication != null) { + iccCardExist = mUiccApplication.getState() != AppState.APPSTATE_UNKNOWN; } return iccCardExist; } @@ -5551,11 +5512,6 @@ public class ServiceStateTracker extends Handler { return mPhone.getPhoneId(); } - /* Reset Service state when IWLAN is enabled as polling in airplane mode - * causes state to go to OUT_OF_SERVICE state instead of STATE_OFF - */ - - /** * This method adds IWLAN registration info for legacy mode devices camped on IWLAN. It also * makes some adjustments when the device camps on IWLAN in airplane mode. diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index d0120331ba..d03e1a1828 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -146,7 +146,7 @@ public class DataStallRecoveryManager extends Handler { private final @NonNull DataServiceManager mWwanDataServiceManager; /** The data stall recovery action. */ - private @RecoveryAction int mRecovryAction; + private @RecoveryAction int mRecoveryAction; /** The elapsed real time of last recovery attempted */ private @ElapsedRealtimeLong long mTimeLastRecoveryStartMs; /** Whether current network is good or not */ @@ -362,7 +362,7 @@ public class DataStallRecoveryManager extends Handler { cancelNetworkCheckTimer(); mTimeLastRecoveryStartMs = 0; mLastAction = RECOVERY_ACTION_GET_DATA_CALL_LIST; - mRecovryAction = RECOVERY_ACTION_GET_DATA_CALL_LIST; + mRecoveryAction = RECOVERY_ACTION_GET_DATA_CALL_LIST; } /** @@ -402,8 +402,8 @@ public class DataStallRecoveryManager extends Handler { @VisibleForTesting @RecoveryAction public int getRecoveryAction() { - log("getRecoveryAction: " + recoveryActionToString(mRecovryAction)); - return mRecovryAction; + log("getRecoveryAction: " + recoveryActionToString(mRecoveryAction)); + return mRecoveryAction; } /** @@ -413,24 +413,24 @@ public class DataStallRecoveryManager extends Handler { */ @VisibleForTesting public void setRecoveryAction(@RecoveryAction int action) { - mRecovryAction = action; + mRecoveryAction = action; // Check if the mobile data enabled is TRUE, it means that the mobile data setting changed // from DISABLED to ENABLED, we will set the next recovery action to // RECOVERY_ACTION_RADIO_RESTART due to already did the RECOVERY_ACTION_CLEANUP. if (mMobileDataChangedToEnabledDuringDataStall - && mRecovryAction < RECOVERY_ACTION_RADIO_RESTART) { - mRecovryAction = RECOVERY_ACTION_RADIO_RESTART; + && mRecoveryAction < RECOVERY_ACTION_RADIO_RESTART) { + mRecoveryAction = RECOVERY_ACTION_RADIO_RESTART; } // Check if the radio state changed from off to on, it means that the modem already // did the radio restart, we will set the next action to RECOVERY_ACTION_RESET_MODEM. if (mRadioStateChangedDuringDataStall && mRadioPowerState == TelephonyManager.RADIO_POWER_ON) { - mRecovryAction = RECOVERY_ACTION_RESET_MODEM; + mRecoveryAction = RECOVERY_ACTION_RESET_MODEM; } // To check the flag from DataConfigManager if we need to skip the step. - if (shouldSkipRecoveryAction(mRecovryAction)) { - switch (mRecovryAction) { + if (shouldSkipRecoveryAction(mRecoveryAction)) { + switch (mRecoveryAction) { case RECOVERY_ACTION_GET_DATA_CALL_LIST: setRecoveryAction(RECOVERY_ACTION_CLEANUP); break; @@ -446,7 +446,7 @@ public class DataStallRecoveryManager extends Handler { } } - log("setRecoveryAction: " + recoveryActionToString(mRecovryAction)); + log("setRecoveryAction: " + recoveryActionToString(mRecoveryAction)); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index d95e5bc158..74164a2967 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -91,6 +91,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { mBundle.putString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING, "connected_mmwave:5G_Plus,connected:5G,not_restricted_rrc_idle:5G," + "not_restricted_rrc_con:5G"); + mBundle.putInt(CarrierConfigManager.KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); broadcastCarrierConfigs(); replaceInstance(Handler.class, "mLooper", mDisplayInfoController, Looper.myLooper()); @@ -149,7 +150,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testUpdateOverrideNetworkTypeNrSa() throws Exception { // not NR - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); updateOverrideNetworkType(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, @@ -164,7 +164,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { anyInt(), anyInt()); updateOverrideNetworkType(); - assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, mNetworkTypeController.getOverrideNetworkType()); } @@ -172,7 +171,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testUpdateOverrideNetworkTypeNrSaMmwave() throws Exception { // not NR - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); updateOverrideNetworkType(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, @@ -188,7 +186,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); updateOverrideNetworkType(); - assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); } @@ -242,7 +239,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testTransitionToCurrentStateLegacy() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_HSPAP).when(mServiceState).getDataNetworkType(); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); assertEquals("legacy", getCurrentState().getName()); @@ -251,7 +247,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testTransitionToCurrentStateRestricted() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); @@ -261,7 +256,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testTransitionToCurrentStateIdle() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_DORMANT, null)); @@ -278,7 +272,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); setPhysicalLinkStatus(false); mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); @@ -298,7 +291,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_DORMANT, null)); @@ -310,7 +302,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testTransitionToCurrentStateLteConnected() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_ACTIVE, null)); @@ -329,7 +320,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); setPhysicalLinkStatus(true); mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); @@ -350,7 +340,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_ACTIVE, null)); @@ -362,7 +351,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testTransitionToCurrentStateNrConnected() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); @@ -373,7 +361,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testTransitionToCurrentStateNrConnectedMmwave() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); @@ -386,7 +373,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { public void testTransitionToCurrentStateNrConnectedMmwaveWithAdditionalBandAndNoMmwave() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange(); mBundle.putIntArray(CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY, @@ -410,7 +396,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { public void testTransitionToCurrentStateNrConnectedWithNoAdditionalBandAndNoMmwave() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange(); mBundle.putIntArray(CarrierConfigManager.KEY_ADDITIONAL_NR_ADVANCED_BANDS_INT_ARRAY, @@ -433,7 +418,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testTransitionToCurrentStateNrConnectedWithNrAdvancedCapable() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); broadcastCarrierConfigs(); @@ -447,7 +431,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { public void testTransitionToCurrentStateNrConnectedWithPcoAndNoNrAdvancedCapable() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); @@ -467,7 +450,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { public void testTransitionToCurrentStateNrConnectedWithWrongPcoAndNoNrAdvancedCapable() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF00); @@ -487,7 +469,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { public void testTransitionToCurrentStateNrConnectedWithNrAdvancedCapableAndPco() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); @@ -506,7 +487,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testEventDataRatChanged() throws Exception { testTransitionToCurrentStateLegacy(); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); @@ -549,7 +529,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testNrPhysicalChannelChangeFromNrConnectedMmwaveToLteConnected() throws Exception { testTransitionToCurrentStateNrConnectedMmwave(); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, @@ -567,14 +546,12 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); processAllMessages(); testTransitionToCurrentStateNrConnectedMmwave(); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); setPhysicalLinkStatus(true); mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals("not_restricted_rrc_con", getCurrentState().getName()); } @@ -590,21 +567,18 @@ public class NetworkTypeControllerTest extends TelephonyTest { broadcastCarrierConfigs(); processAllMessages(); testTransitionToCurrentStateNrConnectedMmwave(); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_ACTIVE, null)); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals("not_restricted_rrc_con", getCurrentState().getName()); } @Test public void testEventPhysicalChannelChangeFromLteToLteCaInLegacyState() throws Exception { testTransitionToCurrentStateLegacy(); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); updateOverrideNetworkType(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, mNetworkTypeController.getOverrideNetworkType()); @@ -614,7 +588,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA, mNetworkTypeController.getOverrideNetworkType()); } @@ -628,7 +601,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { broadcastCarrierConfigs(); // Transition to LTE connected state - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_ACTIVE, null)); @@ -644,7 +616,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA, mNetworkTypeController.getOverrideNetworkType()); } @@ -658,7 +629,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { broadcastCarrierConfigs(); // Transition to idle state - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, new AsyncResult(null, DataCallResponse.LINK_STATUS_DORMANT, null)); @@ -674,7 +644,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA, mNetworkTypeController.getOverrideNetworkType()); } @@ -687,7 +656,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { new AsyncResult(null, DataCallResponse.LINK_STATUS_DORMANT, null)); processAllMessages(); - assertEquals("not_restricted_rrc_idle", getCurrentState().getName()); } @@ -704,7 +672,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); - assertEquals("not_restricted_rrc_idle", getCurrentState().getName()); } @@ -724,7 +691,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { new AsyncResult(null, DataCallResponse.LINK_STATUS_DORMANT, null)); processAllMessages(); - assertEquals("not_restricted_rrc_idle", getCurrentState().getName()); } @@ -748,8 +714,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController.getOverrideNetworkType()); doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); - doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getDataNetworkType(); - mNetworkTypeController.sendMessage(9 /* EVENT_RADIO_OFF_OR_UNAVAILABLE */); processAllMessages(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, @@ -775,7 +739,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testPrimaryTimerExpire() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); @@ -807,7 +770,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testPrimaryTimerDeviceIdleMode() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); @@ -837,7 +799,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testPrimaryTimerReset() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); @@ -874,7 +835,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testPrimaryTimerReset_theNetworkModeWithoutNr() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); @@ -904,7 +864,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testPrimaryTimerExpireMmwave() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, @@ -937,7 +896,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testPrimaryTimerResetMmwave() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, @@ -975,7 +933,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testSecondaryTimerExpire() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); @@ -1019,7 +976,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testSecondaryTimerReset() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); @@ -1068,7 +1024,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testSecondaryTimerExpireMmwave() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, @@ -1113,7 +1068,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testSecondaryTimerResetMmwave() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, @@ -1163,7 +1117,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testNrTimerResetIn3g() throws Exception { - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, @@ -1202,12 +1155,12 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertFalse(mNetworkTypeController.areAnyTimersActive()); } - private void setPhysicalLinkStatus(Boolean state) { + private void setPhysicalLinkStatus(boolean state) { List lastPhysicalChannelConfigList = new ArrayList<>(); - // If PhysicalChannelConfigList is empty, PhysicalLinkStatus is DcController - // .PHYSICAL_LINK_NOT_ACTIVE - // If PhysicalChannelConfigList is not empty, PhysicalLinkStatus is DcController - // .PHYSICAL_LINK_ACTIVE + // If PhysicalChannelConfigList is empty, PhysicalLinkStatus is + // DataCallResponse.LINK_STATUS_DORMANT + // If PhysicalChannelConfigList is not empty, PhysicalLinkStatus is + // DataCallResponse.LINK_STATUS_ACTIVE if (state) { PhysicalChannelConfig physicalChannelConfig = new PhysicalChannelConfig.Builder() @@ -1222,7 +1175,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testTransitionToCurrentStateNrConnectedWithLowBandwidth() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); doReturn(new int[] {19999}).when(mServiceState).getCellBandwidths(); @@ -1237,7 +1189,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testTransitionToCurrentStateNrConnectedWithHighBandwidth() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); List lastPhysicalChannelConfigList = new ArrayList<>(); @@ -1258,7 +1209,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { public void testTransitionToCurrentStateNrConnectedWithHighBandwidthIncludingLte() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); List lastPhysicalChannelConfigList = new ArrayList<>(); @@ -1285,7 +1235,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { @Test public void testNrAdvancedDisabledWhileRoaming() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); doReturn(true).when(mServiceState).getDataRoaming(); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 51f501a2c2..12bf05d88e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -2471,7 +2471,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @SmallTest - public void testGetMdn() throws Exception { + public void testGetMdn() { doReturn(false).when(mPhone).isPhoneTypeGsm(); doReturn(false).when(mPhone).isPhoneTypeCdma(); doReturn(true).when(mPhone).isPhoneTypeCdmaLte(); -- GitLab From b6a79f5bf395ee1839d0107ee0b0ebe476fc07b7 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 7 Dec 2022 17:18:13 -0800 Subject: [PATCH 248/656] Ratchet PCC bandwidths only if anchor cell is the same and ignore empty Similar to how LTE ratcheting works, only ratchet bandwidths from physical channel configs if the anchor NR cell is the same. The previous behavior would always ratchet, which was not correct in all scenarios. Ignore empty PCC list if the previous list had an anchor NR cell (NR connected). Test: manual Test: atest NetworkTypeControllerTest, ServiceStateTrackerTest Bug: 257135958 Change-Id: Ica63ad5cbdc7967ea189a9e756ca914f2a74cec3 --- .../telephony/NetworkTypeController.java | 18 ++----- .../telephony/ServiceStateTracker.java | 53 +++++++++++++++++-- .../telephony/NetworkTypeControllerTest.java | 35 +----------- .../telephony/ServiceStateTrackerTest.java | 33 +++++++++--- 4 files changed, 79 insertions(+), 60 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index c02a9c3e58..e95368240e 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -158,7 +158,6 @@ public class NetworkTypeController extends StateMachine { private boolean mIsTimerResetEnabledForLegacyStateRrcIdle; private int mLtePlusThresholdBandwidth; private int mNrAdvancedThresholdBandwidth; - private boolean mIncludeLteForNrAdvancedThresholdBandwidth; private @NonNull int[] mAdditionalNrAdvancedBandsList; private @NonNull String mPrimaryTimerState; private @NonNull String mSecondaryTimerState; @@ -282,8 +281,6 @@ public class NetworkTypeController extends StateMachine { CarrierConfigManager.KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT); mNrAdvancedThresholdBandwidth = config.getInt( CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT); - mIncludeLteForNrAdvancedThresholdBandwidth = config.getBoolean( - CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); mEnableNrAdvancedWhileRoaming = config.getBoolean( CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL); mAdditionalNrAdvancedBandsList = config.getIntArray( @@ -1259,20 +1256,11 @@ public class NetworkTypeController extends StateMachine { return false; } - int bandwidths = 0; - if (mPhone.getServiceStateTracker().getPhysicalChannelConfigList() != null) { - bandwidths = mPhone.getServiceStateTracker().getPhysicalChannelConfigList() - .stream() - .filter(config -> mIncludeLteForNrAdvancedThresholdBandwidth - || config.getNetworkType() == TelephonyManager.NETWORK_TYPE_NR) - .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) - .mapToInt(Integer::intValue) - .sum(); - } - // Check if meeting minimum bandwidth requirement. For most carriers, there is no minimum // bandwidth requirement and mNrAdvancedThresholdBandwidth is 0. - if (mNrAdvancedThresholdBandwidth > 0 && bandwidths < mNrAdvancedThresholdBandwidth) { + if (mNrAdvancedThresholdBandwidth > 0 + && IntStream.of(mPhone.getServiceState().getCellBandwidths()).sum() + < mNrAdvancedThresholdBandwidth) { return false; } diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 1df84da4ac..992aaa8652 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -180,6 +180,7 @@ public class ServiceStateTracker extends Handler { private long mLastCellInfoReqTime; private List mLastCellInfoList = null; private List mLastPhysicalChannelConfigList = null; + private int mLastAnchorNrCellId = PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN; private final Set mRadioPowerOffReasons = new HashSet(); @@ -1637,8 +1638,20 @@ public class ServiceStateTracker extends Handler { if (ar.exception == null) { List list = (List) ar.result; if (VDBG) { - log("EVENT_PHYSICAL_CHANNEL_CONFIG: size=" + list.size() + " list=" - + list); + log("EVENT_PHYSICAL_CHANNEL_CONFIG: list=" + list + + (list == null ? "" : ", list.size()=" + list.size())); + } + if ((list == null || list.isEmpty()) + && mLastAnchorNrCellId != PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN + && mPhone.getContext().getSystemService(TelephonyManager.class) + .isRadioInterfaceCapabilitySupported(TelephonyManager + .CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED) + && !mCarrierConfig.getBoolean(CarrierConfigManager + .KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL) + && mCarrierConfig.getBoolean(CarrierConfigManager + .KEY_RATCHET_NR_ADVANCED_BANDWIDTH_IF_RRC_IDLE_BOOL)) { + log("Ignore empty PCC list when RRC idle."); + break; } mLastPhysicalChannelConfigList = list; boolean hasChanged = false; @@ -1650,8 +1663,40 @@ public class ServiceStateTracker extends Handler { mNrFrequencyChangedRegistrants.notifyRegistrants(); hasChanged = true; } - hasChanged |= RatRatcheter - .updateBandwidths(getBandwidthsFromConfigs(list), mSS); + int anchorNrCellId = PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN; + if (list != null) { + anchorNrCellId = list + .stream() + .filter(config -> config.getNetworkType() + == TelephonyManager.NETWORK_TYPE_NR + && config.getConnectionStatus() + == PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING) + .map(PhysicalChannelConfig::getPhysicalCellId) + .findFirst() + .orElse(PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN); + } + boolean includeLte = mCarrierConfig.getBoolean(CarrierConfigManager + .KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); + int[] bandwidths = new int[0]; + if (list != null) { + bandwidths = list.stream() + .filter(config -> includeLte || config.getNetworkType() + == TelephonyManager.NETWORK_TYPE_NR) + .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) + .mapToInt(Integer::intValue) + .toArray(); + } + if (anchorNrCellId == mLastAnchorNrCellId + && anchorNrCellId != PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN) { + log("Ratchet bandwidths since anchor NR cell is the same."); + hasChanged |= RatRatcheter.updateBandwidths(bandwidths, mSS); + } else { + log("Do not ratchet bandwidths since anchor NR cell is different (" + + mLastAnchorNrCellId + "->" + anchorNrCellId + ")."); + mLastAnchorNrCellId = anchorNrCellId; + hasChanged = !Arrays.equals(mSS.getCellBandwidths(), bandwidths); + mSS.setCellBandwidths(bandwidths); + } mPhone.notifyPhysicalChannelConfig(list); // Notify NR frequency, NR connection status or bandwidths changed. diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index 74164a2967..6dfde48818 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -555,7 +555,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("not_restricted_rrc_con", getCurrentState().getName()); } - @Test public void testUsingUserDataForRrcDetection_FromNrConnectedMmwaveToLteConnected() throws Exception { @@ -1191,12 +1190,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("DefaultState", getCurrentState().getName()); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - List lastPhysicalChannelConfigList = new ArrayList<>(); - lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() - .setNetworkType(TelephonyManager.NETWORK_TYPE_NR) - .setCellBandwidthDownlinkKhz(20001) - .build()); - doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); + doReturn(new int[] {20001}).when(mServiceState).getCellBandwidths(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); broadcastCarrierConfigs(); @@ -1205,33 +1199,6 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected_mmwave", getCurrentState().getName()); } - @Test - public void testTransitionToCurrentStateNrConnectedWithHighBandwidthIncludingLte() - throws Exception { - assertEquals("DefaultState", getCurrentState().getName()); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); - doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - List lastPhysicalChannelConfigList = new ArrayList<>(); - lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() - .setNetworkType(TelephonyManager.NETWORK_TYPE_NR) - .setCellBandwidthDownlinkKhz(20000) - .build()); - lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() - .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) - .setCellBandwidthDownlinkKhz(10000) - .build()); - doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); - mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); - mBundle.putBoolean( - CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, - true); - broadcastCarrierConfigs(); - - mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); - processAllMessages(); - assertEquals("connected_mmwave", getCurrentState().getName()); - } - @Test public void testNrAdvancedDisabledWhileRoaming() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 12bf05d88e..e6a3ac7b60 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -251,6 +252,15 @@ public class ServiceStateTrackerTest extends TelephonyTest { // UMTS < GPRS < EDGE new String[]{"3,1,2"}); + mBundle.putBoolean(CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL, + false); + + mBundle.putBoolean(CarrierConfigManager.KEY_RATCHET_NR_ADVANCED_BANDWIDTH_IF_RRC_IDLE_BOOL, + true); + + doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( + TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); + mSimulatedCommands.setVoiceRegState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME); mSimulatedCommands.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_HSPA); mSimulatedCommands.setDataRegState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME); @@ -2237,16 +2247,20 @@ public class ServiceStateTrackerTest extends TelephonyTest { } @Test - public void testPhyChanBandwidthRatchetedOnPhyChanBandwidth() throws Exception { + public void testPhyChanBandwidthRatchetedOnPhyChanBandwidth() { + mBundle.putBoolean( + CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, + true); + // LTE Cell with bandwidth = 10000 CellIdentityLte cellIdentity10 = new CellIdentityLte(1, 1, 1, 1, new int[] {1, 2}, 10000, "1", "1", "test", "tst", Collections.emptyList(), null); sendRegStateUpdateForLteCellId(cellIdentity10); - assertTrue(Arrays.equals(new int[] {10000}, sst.mSS.getCellBandwidths())); + assertArrayEquals(new int[]{10000}, sst.mSS.getCellBandwidths()); sendPhyChanConfigChange(new int[] {10000, 5000}, TelephonyManager.NETWORK_TYPE_LTE, 1); - assertTrue(Arrays.equals(new int[] {10000, 5000}, sst.mSS.getCellBandwidths())); + assertArrayEquals(new int[]{10000, 5000}, sst.mSS.getCellBandwidths()); } @Test @@ -2258,7 +2272,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { } @Test - public void testPhyChanBandwidthResetsOnOos() throws Exception { + public void testPhyChanBandwidthResetsOnOos() { testPhyChanBandwidthRatchetedOnPhyChanBandwidth(); LteVopsSupportInfo lteVopsSupportInfo = new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE, @@ -2288,11 +2302,16 @@ public class ServiceStateTrackerTest extends TelephonyTest { public void testPhyChanBandwidthForNr() { // NR Cell with bandwidth = 10000 CellIdentityNr nrCi = new CellIdentityNr( - 0, 0, 0, new int[] {}, "", "", 5, "", "", Collections.emptyList()); + 0, 0, 0, new int[]{10000}, "", "", 5, "", "", Collections.emptyList()); - sendPhyChanConfigChange(new int[] {10000, 5000}, TelephonyManager.NETWORK_TYPE_NR, 0); sendRegStateUpdateForNrCellId(nrCi); - assertTrue(Arrays.equals(new int[] {10000, 5000}, sst.mSS.getCellBandwidths())); + // should ratchet for NR + sendPhyChanConfigChange(new int[] {10000, 5000}, TelephonyManager.NETWORK_TYPE_NR, 0); + assertArrayEquals(new int[]{10000, 5000}, sst.mSS.getCellBandwidths()); + + // should not ratchet for LTE + sendPhyChanConfigChange(new int[] {100}, TelephonyManager.NETWORK_TYPE_LTE, 0); + assertArrayEquals(new int[]{}, sst.mSS.getCellBandwidths()); } /** -- GitLab From 323f44c738e50f5cc3954ae396c8ffd4ef47e465 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 9 Dec 2022 02:23:13 -0800 Subject: [PATCH 249/656] Added 15 APIs support Added setDisplayNumber, setOpportunistic, createSubscriptionGroup setPreferredDataSubscriptionId, getPreferredDataSubscriptionId getOpportunisticSubscriptions, addSubscriptionsIntoGroup canDisablePhysicalSubscription, setUiccApplicationsEnabled setDeviceToDeviceStatusSharing, setDeviceToDeviceStatusSharingContacts getPhoneNumberFromFirstAvailableSource, setUsageSetting setSubscriptionUserHandle, getSubscriptionUserHandle Test: atest SubscriptionManagerServiceTest Bug: 239607619 Change-Id: I8f7fa5a14b5495dec496c77c8c54e0dce70d2001 --- .../SubscriptionDatabaseManager.java | 3 +- .../SubscriptionManagerService.java | 752 ++++++++++++++++-- .../SubscriptionManagerServiceTest.java | 280 ++++++- 3 files changed, 943 insertions(+), 92 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index a0ced874ad..2b59a83bc4 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -30,6 +30,7 @@ import android.provider.Telephony; import android.provider.Telephony.SimInfo; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionManager.DataRoamingMode; import android.telephony.SubscriptionManager.DeviceToDeviceStatusSharingPreference; import android.telephony.SubscriptionManager.ProfileClass; import android.telephony.SubscriptionManager.SimDisplayNameSource; @@ -701,7 +702,7 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setDataRoaming(int subId, int dataRoaming) { + public void setDataRoaming(int subId, @DataRoamingMode int dataRoaming) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_DATA_ROAMING, dataRoaming, SubscriptionInfoInternal.Builder::setDataRoaming); } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 03a2ae6a32..78a2491cc6 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -37,6 +37,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.ParcelUuid; +import android.os.RemoteException; import android.os.TelephonyServiceManager; import android.os.UserHandle; import android.provider.Settings; @@ -46,12 +47,15 @@ import android.service.euicc.EuiccService; import android.service.euicc.GetEuiccProfileInfoListResult; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionManager.DataRoamingMode; +import android.telephony.SubscriptionManager.DeviceToDeviceStatusSharingPreference; import android.telephony.SubscriptionManager.PhoneNumberSource; import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; -import android.telephony.TelephonyCallback; +import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; import android.telephony.TelephonyRegistryManager; @@ -79,18 +83,19 @@ import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.S import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.uicc.UiccSlot; +import com.android.internal.telephony.util.ArrayUtils; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.stream.Collectors; @@ -457,6 +462,88 @@ public class SubscriptionManagerService extends ISub.Stub { return sInstance; } + /** + * Check if the calling package can manage the subscription group. + * + * @param groupUuid a UUID assigned to the subscription group. + * @param callingPackage the package making the IPC. + * + * @return {@code true} if calling package is the owner of or has carrier privileges for all + * subscriptions in the group. + */ + private boolean canPackageManageGroup(@NonNull ParcelUuid groupUuid, + @NonNull String callingPackage) { + if (groupUuid == null) { + throw new IllegalArgumentException("Invalid groupUuid"); + } + + if (TextUtils.isEmpty(callingPackage)) { + throw new IllegalArgumentException("Empty callingPackage"); + } + + List infoList; + + // Getting all subscriptions in the group. + infoList = mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(subInfo -> subInfo.getGroupUuid().equals(groupUuid.toString())) + .map(SubscriptionInfoInternal::toSubscriptionInfo) + .collect(Collectors.toList()); + + // If the group does not exist, then by default the UUID is up for grabs so no need to + // restrict management of a group (that someone may be attempting to create). + if (ArrayUtils.isEmpty(infoList)) { + return true; + } + + // If the calling package is the group owner, skip carrier permission check and return + // true as it was done before. + if (callingPackage.equals(infoList.get(0).getGroupOwner())) return true; + + // Check carrier privilege for all subscriptions in the group. + return (checkCarrierPrivilegeOnSubList(infoList.stream() + .mapToInt(SubscriptionInfo::getSubscriptionId).toArray(), callingPackage)); + } + + /** + * Helper function to check if the caller has carrier privilege permissions on a list of subId. + * The check can either be processed against access rules on currently active SIM cards, or + * the access rules we keep in our database for currently inactive SIMs. + * + * @param subIdList List of subscription ids. + * @param callingPackage The package making the call. + * + * @throws IllegalArgumentException if the some subId is invalid or doesn't exist. + * + * @return {@code true} if checking passes on all subId, {@code false} otherwise. + */ + private boolean checkCarrierPrivilegeOnSubList(@NonNull int[] subIdList, + @NonNull String callingPackage) { + for (int subId : subIdList) { + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + if (subInfo == null) { + loge("checkCarrierPrivilegeOnSubList: subId " + subId + " does not exist."); + return false; + } + + if (subInfo.isActive()) { + if (!mTelephonyManager.hasCarrierPrivileges(subId)) { + loge("checkCarrierPrivilegeOnSubList: Does not have carrier privilege on sub " + + subId); + return false; + } + } else { + if (!mSubscriptionManager.canManageSubscription(subInfo.toSubscriptionInfo(), + callingPackage)) { + loge("checkCarrierPrivilegeOnSubList: cannot manage sub " + subId); + return false; + } + } + } + + return true; + } + /** * Sync the settings from specified subscription to all groupped subscriptions. * @@ -507,21 +594,6 @@ public class SubscriptionManagerService extends ISub.Stub { }); } - /** - * Validate the passed in subscription id. - * - * @param subId The subscription id to validate. - * - * @throws IllegalArgumentException if the subscription is not valid. - */ - private void validateSubId(int subId) { - if (!SubscriptionManager.isValidSubscriptionId(subId)) { - throw new IllegalArgumentException("Invalid sub id passed as parameter"); - } else if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - throw new IllegalArgumentException("Default sub id passed as parameter"); - } - } - /** * Check whether the {@code callingPackage} has access to the phone number on the specified * {@code subId} or not. @@ -649,7 +721,12 @@ public class SubscriptionManagerService extends ISub.Stub { * @see TelephonyManager#getSimCarrierId() */ public void setCarrierId(int subId, int carrierId) { - mSubscriptionDatabaseManager.setCarrierId(subId, carrierId); + // This can throw IllegalArgumentException if the subscription does not exist. + try { + mSubscriptionDatabaseManager.setCarrierId(subId, carrierId); + } catch (IllegalArgumentException e) { + loge("setCarrierId: invalid subId=" + subId); + } } /** @@ -657,13 +734,15 @@ public class SubscriptionManagerService extends ISub.Stub { * * @param mccMnc MCC/MNC associated with the subscription. * @param subId The subscription id. - * - * @throws IllegalArgumentException if {@code subId} is invalid or the subscription does not - * exist. */ public void setMccMnc(int subId, @NonNull String mccMnc) { - mSubscriptionDatabaseManager.setMcc(subId, mccMnc.substring(0, 3)); - mSubscriptionDatabaseManager.setMnc(subId, mccMnc.substring(3)); + // This can throw IllegalArgumentException if the subscription does not exist. + try { + mSubscriptionDatabaseManager.setMcc(subId, mccMnc.substring(0, 3)); + mSubscriptionDatabaseManager.setMnc(subId, mccMnc.substring(3)); + } catch (IllegalArgumentException e) { + loge("setMccMnc: invalid subId=" + subId); + } } /** @@ -673,7 +752,12 @@ public class SubscriptionManagerService extends ISub.Stub { * @param subId The subscription id. */ public void setCountryIso(int subId, @NonNull String iso) { - mSubscriptionDatabaseManager.setCountryIso(subId, iso); + // This can throw IllegalArgumentException if the subscription does not exist. + try { + mSubscriptionDatabaseManager.setCountryIso(subId, iso); + } catch (IllegalArgumentException e) { + loge("setCountryIso: invalid subId=" + subId); + } } /** @@ -684,7 +768,12 @@ public class SubscriptionManagerService extends ISub.Stub { * @param carrierName The carrier name. */ public void setCarrierName(int subId, @NonNull String carrierName) { - mSubscriptionDatabaseManager.setCarrierName(subId, carrierName); + // This can throw IllegalArgumentException if the subscription does not exist. + try { + mSubscriptionDatabaseManager.setCarrierName(subId, carrierName); + } catch (IllegalArgumentException e) { + loge("setCarrierName: invalid subId=" + subId); + } } /** @@ -694,8 +783,13 @@ public class SubscriptionManagerService extends ISub.Stub { * @param lastUsedTPMessageReference Last used TP message reference. */ public void setLastUsedTPMessageReference(int subId, int lastUsedTPMessageReference) { - mSubscriptionDatabaseManager.setLastUsedTPMessageReference( - subId, lastUsedTPMessageReference); + // This can throw IllegalArgumentException if the subscription does not exist. + try { + mSubscriptionDatabaseManager.setLastUsedTPMessageReference( + subId, lastUsedTPMessageReference); + } catch (IllegalArgumentException e) { + loge("setLastUsedTPMessageReference: invalid subId=" + subId); + } } /** @@ -705,7 +799,13 @@ public class SubscriptionManagerService extends ISub.Stub { * @param enabledMobileDataPolicies The enabled mobile data policies. */ public void setEnabledMobileDataPolicies(int subId, @NonNull String enabledMobileDataPolicies) { - mSubscriptionDatabaseManager.setEnabledMobileDataPolicies(subId, enabledMobileDataPolicies); + // This can throw IllegalArgumentException if the subscription does not exist. + try { + mSubscriptionDatabaseManager.setEnabledMobileDataPolicies( + subId, enabledMobileDataPolicies); + } catch (IllegalArgumentException e) { + loge("setEnabledMobileDataPolicies: invalid subId=" + subId); + } } /** @@ -715,7 +815,12 @@ public class SubscriptionManagerService extends ISub.Stub { * @param numberFromIms The phone number retrieved from IMS. */ public void setNumberFromIms(int subId, @NonNull String numberFromIms) { - mSubscriptionDatabaseManager.setNumberFromIms(subId, numberFromIms); + // This can throw IllegalArgumentException if the subscription does not exist. + try { + mSubscriptionDatabaseManager.setNumberFromIms(subId, numberFromIms); + } catch (IllegalArgumentException e) { + loge("setNumberFromIms: invalid subId=" + subId); + } } /** @@ -889,7 +994,8 @@ public class SubscriptionManagerService extends ISub.Stub { * *

    * The carrier app will always have full {@link SubscriptionInfo} for the subscriptions - * that it has carrier privilege. + * that it has carrier privilege. Subscriptions that the carrier app has no privilege will be + * excluded from the list. * * @return List of all {@link SubscriptionInfo} records from SIMs that are inserted or * inserted before. Sorted by {@link SubscriptionInfo#getSimSlotIndex()}, then @@ -898,6 +1004,8 @@ public class SubscriptionManagerService extends ISub.Stub { * @param callingPackage The package making the call. * @param callingFeatureId The feature in the package. * + * @throws SecurityException if the caller does not have required permissions. + * */ @Override @NonNull @@ -924,6 +1032,11 @@ public class SubscriptionManagerService extends ISub.Stub { final long identity = Binder.clearCallingIdentity(); try { return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full + // list. Carrier apps can only get the subscriptions they have privileged. + .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( + mContext, subInfo.getSubscriptionId(), callingPackage, callingFeatureId, + "getAllSubInfoList")) // Remove the identifier if the caller does not have sufficient permission. // carrier apps will get full subscription info on the subscriptions associated // to them. @@ -946,6 +1059,8 @@ public class SubscriptionManagerService extends ISub.Stub { * @param callingFeatureId The feature in the package. * * @return The subscription info. + * + * @throws SecurityException if the caller does not have required permissions. */ @Override @Nullable @@ -986,6 +1101,8 @@ public class SubscriptionManagerService extends ISub.Stub { * @param callingFeatureId The feature in the package. * * @return The subscription info. + * + * @throws SecurityException if the caller does not have required permissions. */ @Override @Nullable @@ -1019,6 +1136,8 @@ public class SubscriptionManagerService extends ISub.Stub { * @param callingFeatureId The feature in the package. * * @return {@link SubscriptionInfo}, null for Remote-SIMs or non-active logical SIM slot index. + * + * @throws SecurityException if the caller does not have required permissions. */ @Override @Nullable @@ -1067,6 +1186,8 @@ public class SubscriptionManagerService extends ISub.Stub { * * @return Sorted list of the currently {@link SubscriptionInfo} records available on the * device. + * + * @throws SecurityException if the caller does not have required permissions. */ @Override @NonNull @@ -1111,10 +1232,12 @@ public class SubscriptionManagerService extends ISub.Stub { /** * Get the number of active {@link SubscriptionInfo}. * - * @param callingPackage The package making the call - * @param callingFeatureId The feature in the package + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * * @return the number of active subscriptions. + * + * @throws SecurityException if the caller does not have required permissions. */ @Override @RequiresPermission(anyOf = { @@ -1156,6 +1279,13 @@ public class SubscriptionManagerService extends ISub.Stub { * Available subscriptions include active ones (those with a non-negative * {@link SubscriptionInfo#getSimSlotIndex()}) as well as inactive but installed embedded * subscriptions. + * + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * + * @return The available subscription info. + * + * @throws SecurityException if the caller does not have required permissions. */ @Override @NonNull @@ -1207,6 +1337,10 @@ public class SubscriptionManagerService extends ISub.Stub { * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} * then by {@link SubscriptionInfo#getSubscriptionId}. *

+ * + * @param callingPackage The package making the call. + * + * @throws SecurityException if the caller does not have required permissions. */ @Override public List getAccessibleSubscriptionInfoList( @@ -1244,8 +1378,11 @@ public class SubscriptionManagerService extends ISub.Stub { * @param subscriptionType the type of subscription to be added * * @return 0 if success, < 0 on error + * + * @throws SecurityException if the caller does not have required permissions. */ @Override + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public int addSubInfo(@NonNull String iccId, @NonNull String displayName, int slotIndex, @SubscriptionType int subscriptionType) { log("addSubInfo: iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + ", slotIndex=" @@ -1345,17 +1482,21 @@ public class SubscriptionManagerService extends ISub.Stub { * @param nameSource The display name source. * * @return the number of records updated + * + * @throws IllegalArgumentException if {@code nameSource} is invalid, or {@code subId} is + * invalid. + * @throws NullPointerException if {@code displayName} is {@code null}. + * @throws SecurityException if callers do not hold the required permission. */ @Override + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public int setDisplayNameUsingSrc(@NonNull String displayName, int subId, @SimDisplayNameSource int nameSource) { enforcePermissions("setDisplayNameUsingSrc", Manifest.permission.MODIFY_PHONE_STATE); final long identity = Binder.clearCallingIdentity(); try { - if (displayName == null) { - throw new IllegalArgumentException("displayName is null"); - } + Objects.requireNonNull(displayName, "setDisplayNameUsingSrc"); if (nameSource < SubscriptionManager.NAME_SOURCE_CARRIER_ID || nameSource > SubscriptionManager.NAME_SOURCE_SIM_PNN) { @@ -1425,14 +1566,27 @@ public class SubscriptionManagerService extends ISub.Stub { /** * Set phone number by subscription id. * - * @param number the phone number of the SIM - * @param subId the unique SubscriptionInfo index in database + * @param number the phone number of the SIM. + * @param subId the unique SubscriptionInfo index in database. * - * @return the number of records updated + * @return the number of records updated. + * + * @throws SecurityException if callers do not hold the required permission. + * @throws NullPointerException if {@code number} is {@code null}. */ @Override + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public int setDisplayNumber(@NonNull String number, int subId) { - return 0; + enforcePermissions("setDisplayNumber", Manifest.permission.MODIFY_PHONE_STATE); + + // Now that all security checks passes, perform the operation as ourselves. + final long identity = Binder.clearCallingIdentity(); + try { + mSubscriptionDatabaseManager.setDisplayName(subId, number); + return 1; + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1442,17 +1596,20 @@ public class SubscriptionManagerService extends ISub.Stub { * @param subId the unique SubscriptionInfo index in database * * @return the number of records updated + * + * @throws IllegalArgumentException if {@code subId} or {@code roaming} is not valid. + * @throws SecurityException if callers do not hold the required permission. */ @Override - public int setDataRoaming(int roaming, int subId) { + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public int setDataRoaming(@DataRoamingMode int roaming, int subId) { enforcePermissions("setDataRoaming", Manifest.permission.MODIFY_PHONE_STATE); // Now that all security checks passes, perform the operation as ourselves. final long identity = Binder.clearCallingIdentity(); try { - validateSubId(subId); if (roaming < 0) { - throw new IllegalArgumentException("Invalid roaming value" + roaming); + throw new IllegalArgumentException("Invalid roaming value " + roaming); } mSubscriptionDatabaseManager.setDataRoaming(subId, roaming); @@ -1471,15 +1628,25 @@ public class SubscriptionManagerService extends ISub.Stub { * * @return the number of records updated * - * @throws IllegalArgumentException if {@code subId} is invalid or the subscription does not - * exist. + * @throws IllegalArgumentException if {@code subId} is invalid. + * @throws SecurityException if callers do not hold the required permission. */ @Override public int setOpportunistic(boolean opportunistic, int subId, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - return 0; + TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( + mContext, Binder.getCallingUid(), subId, true, "setOpportunistic", + Manifest.permission.MODIFY_PHONE_STATE); + + long token = Binder.clearCallingIdentity(); + try { + mSubscriptionDatabaseManager.setOpportunistic(subId, opportunistic); + return 1; + } finally { + Binder.restoreCallingIdentity(token); + } } /** @@ -1490,20 +1657,58 @@ public class SubscriptionManagerService extends ISub.Stub { * Being in the same group means they might be activated or deactivated together, some of them * may be invisible to the users, etc. * - * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} permission or + * Caller will either have {@link Manifest.permission#MODIFY_PHONE_STATE} permission or * can manage all subscriptions in the list, according to their access rules. * - * @param subIdList list of subId that will be in the same group - * @param callingPackage The package making the call + * @param subIdList list of subId that will be in the same group. + * @param callingPackage The package making the call. * * @return groupUUID a UUID assigned to the subscription group. It returns null if fails. + * + * @throws IllegalArgumentException if {@code subId} is invalid. + * @throws SecurityException if callers do not hold the required permission. */ @Override - public ParcelUuid createSubscriptionGroup(int[] subIdList, @NonNull String callingPackage) { + @RequiresPermission(anyOf = { + Manifest.permission.MODIFY_PHONE_STATE, + "carrier privileges", + }) + public ParcelUuid createSubscriptionGroup(@NonNull int[] subIdList, + @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - return null; + Objects.requireNonNull(subIdList, "createSubscriptionGroup"); + if (subIdList.length == 0) { + throw new IllegalArgumentException("Invalid subIdList " + Arrays.toString(subIdList)); + } + + // If it doesn't have modify phone state permission, or carrier privilege permission, + // a SecurityException will be thrown. + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + != PackageManager.PERMISSION_GRANTED && !checkCarrierPrivilegeOnSubList( + subIdList, callingPackage)) { + throw new SecurityException("CreateSubscriptionGroup needs MODIFY_PHONE_STATE or" + + " carrier privilege permission on all specified subscriptions"); + } + + long identity = Binder.clearCallingIdentity(); + + try { + // Generate a UUID. + ParcelUuid groupUUID = new ParcelUuid(UUID.randomUUID()); + String uuidString = groupUUID.toString(); + + for (int subId : subIdList) { + mSubscriptionDatabaseManager.setGroupUuid(subId, uuidString); + mSubscriptionDatabaseManager.setGroupOwner(subId, callingPackage); + } + + MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUUID); + return groupUUID; + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1513,32 +1718,122 @@ public class SubscriptionManagerService extends ISub.Stub { * @param subId which subscription is preferred to for cellular data * @param needValidation whether validation is needed before switching * @param callback callback upon request completion + * + * @throws SecurityException if callers do not hold the required permission. */ @Override + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int subId, boolean needValidation, @Nullable ISetOpportunisticDataCallback callback) { + enforcePermissions("setPreferredDataSubscriptionId", + Manifest.permission.MODIFY_PHONE_STATE); + final long token = Binder.clearCallingIdentity(); + + try { + PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); + if (phoneSwitcher == null) { + loge("Set preferred data sub: phoneSwitcher is null."); + if (callback != null) { + try { + callback.onComplete( + TelephonyManager.SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION); + } catch (RemoteException exception) { + loge("RemoteException " + exception); + } + } + return; + } + + phoneSwitcher.trySetOpportunisticDataSubscription(subId, needValidation, callback); + } finally { + Binder.restoreCallingIdentity(token); + } } /** * @return The subscription id of preferred subscription for cellular data. This reflects * the active modem which can serve large amount of cellular data. + * + * @throws SecurityException if callers do not hold the required permission. */ @Override + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getPreferredDataSubscriptionId() { - return 0; + enforcePermissions("getPreferredDataSubscriptionId", + Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + final long token = Binder.clearCallingIdentity(); + + try { + PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); + if (phoneSwitcher == null) { + loge("getPreferredDataSubscriptionId: PhoneSwitcher not available. Return the " + + "default data sub " + getDefaultDataSubId()); + return getDefaultDataSubId(); + } + + return phoneSwitcher.getAutoSelectedDataSubId(); + } finally { + Binder.restoreCallingIdentity(token); + } } /** + * Get the opportunistic subscriptions. + * + * Callers with {@link Manifest.permission#READ_PHONE_STATE} or + * {@link Manifest.permission#READ_PRIVILEGED_PHONE_STATE} will have a full list of + * opportunistic subscriptions. Subscriptions that the carrier app has no privilege will be + * excluded from the list. + * + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * * @return The list of opportunistic subscription info that can be accessed by the callers. + * + * @throws SecurityException if callers do not hold the required permission. */ @Override @NonNull + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) public List getOpportunisticSubscriptions(@NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - return Collections.emptyList(); + // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier + // privilege on any active subscription. The carrier app will get full subscription infos + // on the subs it has carrier privilege. + if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, + Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, + "getOpportunisticSubscriptions")) { + throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + + "carrier privilege"); + } + + final long identity = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full + // list. Carrier apps can only get the subscriptions they have privileged. + .filter(subInfo -> subInfo.isOpportunistic() + && TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( + mContext, subInfo.getSubscriptionId(), callingPackage, + callingFeatureId, "getOpportunisticSubscriptions")) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getOpportunisticSubscriptions")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override @@ -1546,14 +1841,67 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - } + /** + * Add a list of subscriptions into a group. + * + * Caller should either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * permission or had carrier privilege permission on the subscriptions. + * + * @param subIdList list of subId that need adding into the group + * @param groupUuid the groupUuid the subscriptions are being added to. + * + * @throws SecurityException if the caller doesn't meet the requirements outlined above. + * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist. + * + * @see SubscriptionManager#createSubscriptionGroup(List) + */ + @RequiresPermission(anyOf = { + Manifest.permission.MODIFY_PHONE_STATE, + "carrier privileges", + }) @Override - public void addSubscriptionsIntoGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, + public void addSubscriptionsIntoGroup(@NonNull int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); + + Objects.requireNonNull(subIdList, "subIdList"); + if (subIdList.length == 0) { + throw new IllegalArgumentException("Invalid subId list"); + } + + Objects.requireNonNull(groupUuid, "groupUuid"); + String groupUuidString = groupUuid.toString(); + if (groupUuidString.equals(CarrierConfigManager.REMOVE_GROUP_UUID_STRING)) { + throw new IllegalArgumentException("Invalid groupUuid"); + } + + // If it doesn't have modify phone state permission, or carrier privilege permission, + // a SecurityException will be thrown. + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + != PackageManager.PERMISSION_GRANTED + && !(checkCarrierPrivilegeOnSubList(subIdList, callingPackage) + && canPackageManageGroup(groupUuid, callingPackage))) { + throw new SecurityException("Requires MODIFY_PHONE_STATE or carrier privilege" + + " permissions on subscriptions and the group."); + } + + long identity = Binder.clearCallingIdentity(); + + try { + for (int subId : subIdList) { + mSubscriptionDatabaseManager.setGroupUuid(subId, groupUuidString); + mSubscriptionDatabaseManager.setGroupOwner(subId, callingPackage); + } + + MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUuid); + logl("addSubscriptionsIntoGroup: add subs " + Arrays.toString(subIdList) + + " to the group."); + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1581,10 +1929,14 @@ public class SubscriptionManagerService extends ISub.Stub { * subscription itself. It will return an empty list if no subscription belongs to the group. * * @throws SecurityException if the caller doesn't meet the requirements outlined above. - * */ @Override @NonNull + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) public List getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID @@ -1611,7 +1963,7 @@ public class SubscriptionManagerService extends ISub.Stub { .map(SubscriptionInfoInternal::toSubscriptionInfo) .filter(info -> groupUuid.equals(info.getGroupUuid()) && (mSubscriptionManager.canManageSubscription(info, callingPackage) - || TelephonyPermissions.checkCallingOrSelfReadPhoneState( + || TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( mContext, info.getSubscriptionId(), callingPackage, callingFeatureId, "getSubscriptionsInGroup"))) .map(subscriptionInfo -> conditionallyRemoveIdentifiers(subscriptionInfo, @@ -1738,6 +2090,8 @@ public class SubscriptionManagerService extends ISub.Stub { * Set the default data subscription id. * * @param subId The default data subscription id. + * + * @throws SecurityException if callers do not hold the required permission. */ @Override @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @@ -1779,6 +2133,8 @@ public class SubscriptionManagerService extends ISub.Stub { * Set the default voice subscription id. * * @param subId The default SMS subscription id. + * + * @throws SecurityException if callers do not hold the required permission. */ @Override @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @@ -1827,6 +2183,8 @@ public class SubscriptionManagerService extends ISub.Stub { * Set the default SMS subscription id. * * @param subId The default SMS subscription id. + * + * @throws SecurityException if callers do not hold the required permission. */ @Override @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @@ -1862,6 +2220,8 @@ public class SubscriptionManagerService extends ISub.Stub { * @param visibleOnly {@code true} if only includes user visible subscription's sub id. * * @return List of the active subscription id. + * + * @throws SecurityException if callers do not hold the required permission. */ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @@ -1907,6 +2267,7 @@ public class SubscriptionManagerService extends ISub.Stub { * @return {@code true} if the subscription is active. * * @throws IllegalArgumentException if the provided slot index is invalid. + * @throws SecurityException if callers do not hold the required permission. * */ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @@ -1934,6 +2295,7 @@ public class SubscriptionManagerService extends ISub.Stub { * @return The active subscription id. * * @throws IllegalArgumentException if the provided slot index is invalid. + * @throws SecurityException if callers do not hold the required permission. */ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @@ -1970,6 +2332,8 @@ public class SubscriptionManagerService extends ISub.Stub { * @param callingFeatureId The feature in the package. * * @return {@code true} if the subscription is active. + * + * @throws SecurityException if callers do not hold the required permission. */ @Override @RequiresPermission(anyOf = { @@ -2005,7 +2369,7 @@ public class SubscriptionManagerService extends ISub.Stub { * @return Active data subscription id if any is chosen, or * SubscriptionManager.INVALID_SUBSCRIPTION_ID if not. * - * @see TelephonyCallback.ActiveDataSubscriptionIdListener + * @see android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener */ @Override public int getActiveDataSubscriptionId() { @@ -2026,25 +2390,127 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Whether it's supported to disable / re-enable a subscription on a physical (non-euicc) SIM. + * + * Physical SIM refers non-euicc, or aka non-programmable SIM. + * + * It provides whether a physical SIM card can be disabled without taking it out, which is done + * via {@link SubscriptionManager#setSubscriptionEnabled(int, boolean)} API. + * + * @return whether can disable subscriptions on physical SIMs. + * + * @throws SecurityException if callers do not hold the required permission. + */ @Override + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean canDisablePhysicalSubscription() { - return false; + enforcePermissions("canDisablePhysicalSubscription", + Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + final long identity = Binder.clearCallingIdentity(); + try { + Phone phone = PhoneFactory.getDefaultPhone(); + return phone != null && phone.canDisablePhysicalSubscription(); + } finally { + Binder.restoreCallingIdentity(identity); + } } + /** + * Set uicc applications being enabled or disabled. + * + * The value will be remembered on the subscription and will be applied whenever it's present. + * If the subscription in currently present, it will also apply the setting to modem + * immediately (the setting in the modem will not change until the modem receives and responds + * to the request, but typically this should only take a few seconds. The user visible setting + * available from {@link SubscriptionInfo#areUiccApplicationsEnabled()} will be updated + * immediately.) + * + * @param enabled whether uicc applications are enabled or disabled. + * @param subId which subscription to operate on. + * + * @return the number of records updated. + * + * @throws IllegalArgumentException if the subscription does not exist. + * @throws SecurityException if callers do not hold the required permission. + */ @Override - public int setUiccApplicationsEnabled(boolean enabled, int subscriptionId) { - return 0; + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public int setUiccApplicationsEnabled(boolean enabled, int subId) { + enforcePermissions("setUiccApplicationsEnabled", + Manifest.permission.MODIFY_PHONE_STATE); + + long identity = Binder.clearCallingIdentity(); + try { + mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, enabled); + return 1; + } finally { + Binder.restoreCallingIdentity(identity); + } } + /** + * Set the device to device status sharing user preference for a subscription ID. The setting + * app uses this method to indicate with whom they wish to share device to device status + * information. + * + * @param sharing the status sharing preference. + * @param subId the unique Subscription ID in database. + * + * @return the number of records updated. + * + * @throws IllegalArgumentException if the subscription does not exist, or the sharing + * preference is invalid. + * @throws SecurityException if callers do not hold the required permission. + */ @Override - public int setDeviceToDeviceStatusSharing(int sharing, int subId) { - return 0; + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public int setDeviceToDeviceStatusSharing(@DeviceToDeviceStatusSharingPreference int sharing, + int subId) { + enforcePermissions("setDeviceToDeviceStatusSharing", + Manifest.permission.MODIFY_PHONE_STATE); + + final long identity = Binder.clearCallingIdentity(); + try { + if (sharing < SubscriptionManager.D2D_SHARING_DISABLED + || sharing > SubscriptionManager.D2D_SHARING_ALL) { + throw new IllegalArgumentException("invalid sharing " + sharing); + } + + mSubscriptionDatabaseManager.setDeviceToDeviceStatusSharingPreference(subId, sharing); + return 1; + } finally { + Binder.restoreCallingIdentity(identity); + } } + /** + * Set the list of contacts that allow device to device status sharing for a subscription ID. + * The setting app uses this method to indicate with whom they wish to share device to device + * status information. + * + * @param contacts The list of contacts that allow device to device status sharing + * @param subId The unique Subscription ID in database. + * + * @throws IllegalArgumentException if {@code subId} is invalid. + * @throws NullPointerException if {@code contacts} is {@code null}. + * @throws SecurityException if callers do not hold the required permission. + */ @Override - public int setDeviceToDeviceStatusSharingContacts(@NonNull String contacts, - int subscriptionId) { - return 0; + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public int setDeviceToDeviceStatusSharingContacts(@NonNull String contacts, int subId) { + enforcePermissions("setDeviceToDeviceStatusSharingContacts", + Manifest.permission.MODIFY_PHONE_STATE); + + final long identity = Binder.clearCallingIdentity(); + try { + Objects.requireNonNull(contacts, "contacts"); + mSubscriptionDatabaseManager.setDeviceToDeviceStatusSharingContacts(subId, contacts); + return 1; + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -2078,6 +2544,8 @@ public class SubscriptionManagerService extends ISub.Stub { * * @param subId The subscription ID. * @param source The source of the phone number. + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. * * @return The phone number, or an empty string if not available. * @@ -2087,6 +2555,9 @@ public class SubscriptionManagerService extends ISub.Stub { * @see SubscriptionManager#PHONE_NUMBER_SOURCE_UICC * @see SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER * @see SubscriptionManager#PHONE_NUMBER_SOURCE_IMS + * + * @throws IllegalArgumentException if {@code subId} is invalid. + * @throws SecurityException if callers do not hold the required permission. */ @Override @NonNull @@ -2135,32 +2606,95 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Get phone number from first available source. The order would be + * {@link SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER}, + * {@link SubscriptionManager#PHONE_NUMBER_SOURCE_UICC}, then + * {@link SubscriptionManager#PHONE_NUMBER_SOURCE_IMS}. + * + * @param subId The subscription ID. + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * + * @return The phone number from the first available source. + * + * @throws IllegalArgumentException if {@code subId} is invalid. + * @throws SecurityException if callers do not hold the required permission. + */ @Override + @NonNull + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_NUMBERS, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) public String getPhoneNumberFromFirstAvailableSource(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - return null; + TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( + mContext, subId, Binder.getCallingUid(), "getPhoneNumberFromFirstAvailableSource", + Manifest.permission.READ_PHONE_NUMBERS, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + final long identity = Binder.clearCallingIdentity(); + try { + 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 ""; + } finally { + Binder.restoreCallingIdentity(identity); + } } + /** + * Set the phone number of the subscription. + * + * @param subId The subscription id. + * @param source The phone number source. + * @param number The phone number. + * @param callingPackage The package making the call. + * @param callingFeatureId The feature in the package. + * + * @throws IllegalArgumentException {@code subId} is invalid, or {@code source} is not + * {@link SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER}. + * @throws NullPointerException if {@code number} is {@code null}. + */ @Override + @RequiresPermission("carrier privileges") public void setPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String number, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - if (source != SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER) { - throw new IllegalArgumentException("setPhoneNumber doesn't accept source " - + SubscriptionManager.phoneNumberSourceToString(source)); - } if (!TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext, subId)) { throw new SecurityException("setPhoneNumber for CARRIER needs carrier privilege."); } - if (number == null) { - throw new NullPointerException("invalid number null"); + + if (source != SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER) { + throw new IllegalArgumentException("setPhoneNumber doesn't accept source " + + SubscriptionManager.phoneNumberSourceToString(source)); } + Objects.requireNonNull(number, "number"); + final long identity = Binder.clearCallingIdentity(); try { mSubscriptionDatabaseManager.setNumberFromCarrier(subId, number); @@ -2176,30 +2710,68 @@ public class SubscriptionManagerService extends ISub.Stub { * @param subId the unique SubscriptionInfo index in database * @param callingPackage The package making the IPC. * + * @throws IllegalArgumentException if the subscription does not exist, or {@code usageSetting} + * is invalid. * @throws SecurityException if doesn't have MODIFY_PHONE_STATE or Carrier Privileges */ @Override - public int setUsageSetting(int usageSetting, int subId, @NonNull String callingPackage) { + @RequiresPermission(anyOf = { + Manifest.permission.MODIFY_PHONE_STATE, + "carrier privileges", + }) + public int setUsageSetting(@UsageSetting int usageSetting, int subId, + @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - return 0; + TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( + mContext, Binder.getCallingUid(), subId, true, "setUsageSetting", + Manifest.permission.MODIFY_PHONE_STATE); + + if (usageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT + || usageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { + throw new IllegalArgumentException("setUsageSetting: Invalid usage setting: " + + usageSetting); + } + + final long token = Binder.clearCallingIdentity(); + try { + mSubscriptionDatabaseManager.setUsageSetting(subId, usageSetting); + return 1; + } finally { + Binder.restoreCallingIdentity(token); + } } /** - * Set UserHandle for this subscription + * Set UserHandle for this subscription. * * @param userHandle the userHandle associated with the subscription * Pass {@code null} user handle to clear the association * @param subId the unique SubscriptionInfo index in database * @return the number of records updated. * - * @throws SecurityException if doesn't have required permission. - * @throws IllegalArgumentException if subId is invalid. + * @throws SecurityException if callers do not hold the required permission. + * @throws IllegalArgumentException if {@code subId} is invalid. */ @Override + @RequiresPermission(Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION) public int setSubscriptionUserHandle(@Nullable UserHandle userHandle, int subId) { - return 0; + enforcePermissions("setSubscriptionUserHandle", + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + + if (userHandle == null) { + userHandle = UserHandle.of(UserHandle.USER_NULL); + } + + long token = Binder.clearCallingIdentity(); + try { + // This can throw IllegalArgumentException if the subscription does not exist. + mSubscriptionDatabaseManager.setUserId(subId, userHandle.getIdentifier()); + return 1; + } finally { + Binder.restoreCallingIdentity(token); + } } /** @@ -2210,11 +2782,31 @@ public class SubscriptionManagerService extends ISub.Stub { * or {@code null} if subscription is not associated with any user. * * @throws SecurityException if doesn't have required permission. - * @throws IllegalArgumentException if subId is invalid. + * @throws IllegalArgumentException if {@code subId} is invalid. */ @Override + @RequiresPermission(Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION) public UserHandle getSubscriptionUserHandle(int subId) { - return null; + enforcePermissions("getSubscriptionUserHandle", + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + + long token = Binder.clearCallingIdentity(); + try { + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + if (subInfo == null) { + throw new IllegalArgumentException("getSubscriptionUserHandle: Invalid subId: " + + subId); + } + + UserHandle userHandle = UserHandle.of(subInfo.getUserId()); + if (userHandle.getIdentifier() == UserHandle.USER_NULL) { + return null; + } + return userHandle; + } finally { + Binder.restoreCallingIdentity(token); + } } /** 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 bd7a168758..ef8a5a709c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -21,6 +21,7 @@ import static com.android.internal.telephony.subscription.SubscriptionDatabaseMa import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CONTACT2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID2; @@ -306,12 +307,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); - // Source IMS is not acceptable - assertThrows(IllegalArgumentException.class, - () -> mSubscriptionManagerServiceUT.setPhoneNumber(1, - SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, FAKE_PHONE_NUMBER2, - CALLING_PACKAGE, CALLING_FEATURE)); - // Caller does not have carrier privilege assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT.setPhoneNumber(1, @@ -321,6 +316,12 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // Grant carrier privilege setCarrierPrivilegesForSubId(true, 1); + // Source IMS is not acceptable + assertThrows(IllegalArgumentException.class, + () -> mSubscriptionManagerServiceUT.setPhoneNumber(1, + SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, FAKE_PHONE_NUMBER2, + CALLING_PACKAGE, CALLING_FEATURE)); + mSubscriptionManagerServiceUT.setPhoneNumber(1, SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, FAKE_PHONE_NUMBER2, CALLING_PACKAGE, CALLING_FEATURE); @@ -363,15 +364,12 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { subInfos = mSubscriptionManagerServiceUT.getAllSubInfoList( CALLING_PACKAGE, CALLING_FEATURE); - assertThat(subInfos).hasSize(2); + // Should only have access to one sub. + assertThat(subInfos).hasSize(1); assertThat(subInfos.get(0).getIccId()).isEqualTo(FAKE_ICCID1); assertThat(subInfos.get(0).getCardString()).isEqualTo(FAKE_ICCID1); assertThat(subInfos.get(0).getNumber()).isEqualTo(FAKE_PHONE_NUMBER1); - // identifiers should be empty due to insufficient permission. - assertThat(subInfos.get(1).getIccId()).isEmpty(); - assertThat(subInfos.get(1).getCardString()).isEmpty(); - assertThat(subInfos.get(1).getNumber()).isEmpty(); // Grant READ_PHONE_STATE permission mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); @@ -906,4 +904,264 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(12345).when(mPhoneSwitcher).getActiveDataSubId(); assertThat(mSubscriptionManagerServiceUT.getActiveDataSubscriptionId()).isEqualTo(12345); } + + @Test + public void testSetGetSubscriptionUserHandle() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionUserHandle(new UserHandle(12), 1)); + + mContextFixture.addCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + mSubscriptionManagerServiceUT.setSubscriptionUserHandle(new UserHandle(12), 1); + + processAllMessages(); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getUserId()).isEqualTo(12); + + mContextFixture.removeCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + // Should fail without MANAGE_SUBSCRIPTION_USER_ASSOCIATION + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getSubscriptionUserHandle(1)); + + mContextFixture.addCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionUserHandle(1)) + .isEqualTo(new UserHandle(12)); + } + + @Test + public void testSetUsageSetting() { + doReturn(new int[]{1}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setUsageSetting(SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC, 1, + CALLING_PACKAGE)); + + // Grant carrier privilege + setCarrierPrivilegesForSubId(true, 1); + mSubscriptionManagerServiceUT.setUsageSetting( + SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC, 1, CALLING_PACKAGE); + + processAllMessages(); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getUsageSetting()).isEqualTo( + SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC); + } + + @Test + public void testSetDisplayNumber() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setDisplayNumber(FAKE_PHONE_NUMBER2, 1)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + mSubscriptionManagerServiceUT.setDisplayNumber(FAKE_PHONE_NUMBER2, 1); + processAllMessages(); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_PHONE_NUMBER2); + } + + @Test + public void testSetOpportunistic() { + doReturn(new int[]{1}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setOpportunistic(true, 1, CALLING_PACKAGE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + mSubscriptionManagerServiceUT.setOpportunistic(true, 1, CALLING_PACKAGE); + processAllMessages(); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.isOpportunistic()).isTrue(); + } + + @Test + public void testGetOpportunisticSubscriptions() { + testSetOpportunistic(); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + + // Should fail without READ_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getOpportunisticSubscriptions(CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); + + setIdentifierAccess(true); + setPhoneNumberAccess(PackageManager.PERMISSION_GRANTED); + + List subInfos = mSubscriptionManagerServiceUT + .getOpportunisticSubscriptions(CALLING_PACKAGE, CALLING_FEATURE); + assertThat(subInfos).hasSize(2); + assertThat(subInfos.get(0)).isEqualTo(new SubscriptionInfoInternal + .Builder(FAKE_SUBSCRIPTION_INFO1).setOpportunistic(1).build().toSubscriptionInfo()); + assertThat(subInfos.get(1)).isEqualTo(FAKE_SUBSCRIPTION_INFO2.toSubscriptionInfo()); + } + + @Test + public void testSetPreferredDataSubscriptionId() { + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setPreferredDataSubscriptionId(1, false, null)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + mSubscriptionManagerServiceUT.setPreferredDataSubscriptionId(1, false, null); + verify(mPhoneSwitcher).trySetOpportunisticDataSubscription(eq(1), eq(false), eq(null)); + } + + @Test + public void testGetPreferredDataSubscriptionId() { + // Should fail without READ_PRIVILEGED_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getPreferredDataSubscriptionId()); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + doReturn(12345).when(mPhoneSwitcher).getAutoSelectedDataSubId(); + assertThat(mSubscriptionManagerServiceUT.getPreferredDataSubscriptionId()).isEqualTo(12345); + } + + @Test + public void testAddSubscriptionsIntoGroup() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + + ParcelUuid newUuid = ParcelUuid.fromString("6adbc864-691c-45dc-b698-8fc9a2176fae"); + String newOwner = "new owner"; + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .addSubscriptionsIntoGroup(new int[]{1, 2}, newUuid, CALLING_PACKAGE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + mSubscriptionManagerServiceUT.addSubscriptionsIntoGroup( + new int[]{1, 2}, newUuid, newOwner); + + SubscriptionInfo subInfo = mSubscriptionManagerServiceUT.getSubscriptionInfo(1); + assertThat(subInfo.getGroupUuid()).isEqualTo(newUuid); + assertThat(subInfo.getGroupOwner()).isEqualTo(newOwner); + + subInfo = mSubscriptionManagerServiceUT.getSubscriptionInfo(2); + assertThat(subInfo.getGroupUuid()).isEqualTo(newUuid); + assertThat(subInfo.getGroupOwner()).isEqualTo(newOwner); + } + + @Test + public void testSetDeviceToDeviceStatusSharing() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setDeviceToDeviceStatusSharing(SubscriptionManager.D2D_SHARING_SELECTED_CONTACTS, + 1)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + mSubscriptionManagerServiceUT.setDeviceToDeviceStatusSharing( + SubscriptionManager.D2D_SHARING_SELECTED_CONTACTS, 1); + processAllMessages(); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getDeviceToDeviceStatusSharingPreference()).isEqualTo( + SubscriptionManager.D2D_SHARING_SELECTED_CONTACTS); + } + + @Test + public void testSetDeviceToDeviceStatusSharingContacts() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setDeviceToDeviceStatusSharingContacts(FAKE_CONTACT2, 1)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + mSubscriptionManagerServiceUT.setDeviceToDeviceStatusSharingContacts(FAKE_CONTACT2, 1); + processAllMessages(); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.getDeviceToDeviceStatusSharingContacts()).isEqualTo(FAKE_CONTACT2); + } + + @Test + public void testGetPhoneNumberFromFirstAvailableSource() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without phone number access + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getPhoneNumberFromFirstAvailableSource(1, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_NUMBERS); + + assertThat(mSubscriptionManagerServiceUT.getPhoneNumberFromFirstAvailableSource( + 1, CALLING_PACKAGE, CALLING_FEATURE)).isEqualTo(FAKE_PHONE_NUMBER1); + } + + @Test + public void testSetUiccApplicationsEnabled() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + // Should fail without MODIFY_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setUiccApplicationsEnabled(false, 1)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + mSubscriptionManagerServiceUT.setUiccApplicationsEnabled(false, 1); + processAllMessages(); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo).isNotNull(); + assertThat(subInfo.areUiccApplicationsEnabled()).isFalse(); + } + + @Test + public void testCanDisablePhysicalSubscription() { + // Should fail without READ_PRIVILEGED_PHONE_STATE + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .canDisablePhysicalSubscription()); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + doReturn(false).when(mPhone).canDisablePhysicalSubscription(); + assertThat(mSubscriptionManagerServiceUT.canDisablePhysicalSubscription()).isFalse(); + + doReturn(true).when(mPhone).canDisablePhysicalSubscription(); + assertThat(mSubscriptionManagerServiceUT.canDisablePhysicalSubscription()).isTrue(); + } } -- GitLab From 40d177b2e0ab689ec3c95ddc4a7b23bbb0a55eca Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Fri, 9 Dec 2022 14:13:55 -0800 Subject: [PATCH 250/656] Instantiate displayInfo nonNull TelephonyDisplayInfo is always assumed non null. This change assign it a default value. Bug: 261356610 Test: atest Change-Id: Ic799427f70ef8a985614159caef1462095772927 --- .../android/internal/telephony/DisplayInfoController.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/DisplayInfoController.java b/src/java/com/android/internal/telephony/DisplayInfoController.java index 67dcef1ffd..4a52a10ad0 100644 --- a/src/java/com/android/internal/telephony/DisplayInfoController.java +++ b/src/java/com/android/internal/telephony/DisplayInfoController.java @@ -65,11 +65,14 @@ public class DisplayInfoController extends Handler { private final Phone mPhone; private final NetworkTypeController mNetworkTypeController; private final RegistrantList mTelephonyDisplayInfoChangedRegistrants = new RegistrantList(); - private TelephonyDisplayInfo mTelephonyDisplayInfo; + private @NonNull TelephonyDisplayInfo mTelephonyDisplayInfo; public DisplayInfoController(Phone phone) { mPhone = phone; mLogTag = "DIC-" + mPhone.getPhoneId(); + mTelephonyDisplayInfo = new TelephonyDisplayInfo( + TelephonyManager.NETWORK_TYPE_UNKNOWN, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); mNetworkTypeController = new NetworkTypeController(phone, this); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); } @@ -77,7 +80,7 @@ public class DisplayInfoController extends Handler { /** * @return the current TelephonyDisplayInfo */ - public TelephonyDisplayInfo getTelephonyDisplayInfo() { + public @NonNull TelephonyDisplayInfo getTelephonyDisplayInfo() { return mTelephonyDisplayInfo; } -- GitLab From 1e794f1a6cbd0fb65986f0bdb5e8368b354e5cdf Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 15 Dec 2021 09:23:49 +0000 Subject: [PATCH 251/656] Notifies IMS that radio triggered IMS deregistration Bug: 219242993 Test: atest GsmCdmaPhoneTest#testTriggerImsDeregistration Change-Id: I2036674518b74f6003db4907acb390a5bad776ae --- .../internal/telephony/GsmCdmaPhone.java | 11 +++++++++++ .../internal/telephony/ImsIndication.java | 2 +- .../com/android/internal/telephony/Phone.java | 15 ++++++++++++++- .../android/internal/telephony/RILUtils.java | 17 +++++++++++++++++ .../internal/telephony/imsphone/ImsPhone.java | 7 +++++++ .../telephony/imsphone/ImsPhoneCallTracker.java | 14 ++++++++++++++ .../internal/telephony/GsmCdmaPhoneTest.java | 15 +++++++++++++++ 7 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index e7a9f0b4ed..0fc9d59d6c 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -458,6 +458,7 @@ public class GsmCdmaPhone extends Phone { mCi.registerForLceInfo(this, EVENT_LINK_CAPACITY_CHANGED, null); mCi.registerForCarrierInfoForImsiEncryption(this, EVENT_RESET_CARRIER_KEY_IMSI_ENCRYPTION, null); + mCi.registerForTriggerImsDeregistration(this, EVENT_IMS_DEREGISTRATION_TRIGGERED, null); IntentFilter filter = new IntentFilter( CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED); @@ -3378,6 +3379,16 @@ public class GsmCdmaPhone extends Phone { updateUsageSetting(); break; + case EVENT_IMS_DEREGISTRATION_TRIGGERED: + logd("EVENT_IMS_DEREGISTRATION_TRIGGERED"); + ar = (AsyncResult) msg.obj; + if (ar.exception == null) { + mImsPhone.triggerImsDeregistration(((int[]) ar.result)[0]); + } else { + Rlog.e(LOG_TAG, "Unexpected unsol with exception", ar.exception); + } + break; + default: super.handleMessage(msg); } diff --git a/src/java/com/android/internal/telephony/ImsIndication.java b/src/java/com/android/internal/telephony/ImsIndication.java index 80d75ce447..65540efdd8 100644 --- a/src/java/com/android/internal/telephony/ImsIndication.java +++ b/src/java/com/android/internal/telephony/ImsIndication.java @@ -111,7 +111,7 @@ public class ImsIndication extends IRadioImsIndication.Stub { if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION, reason); int[] response = new int[1]; - response[0] = reason; + response[0] = RILUtils.convertHalDeregistrationReason(reason); mRil.mTriggerImsDeregistrationRegistrants.notifyRegistrants( new AsyncResult(null, response, null)); diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 2025e2df0b..ab814837ea 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -238,8 +238,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected static final int EVENT_SUBSCRIPTIONS_CHANGED = 62; protected static final int EVENT_GET_USAGE_SETTING_DONE = 63; protected static final int EVENT_SET_USAGE_SETTING_DONE = 64; + protected static final int EVENT_IMS_DEREGISTRATION_TRIGGERED = 65; - protected static final int EVENT_LAST = EVENT_SET_USAGE_SETTING_DONE; + protected static final int EVENT_LAST = EVENT_IMS_DEREGISTRATION_TRIGGERED; // For shared prefs. private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_"; @@ -5005,6 +5006,18 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.setNullCipherAndIntegrityEnabled(result, enabled); } + /** + * Notifies that IMS deregistration is triggered. + * + * @param reason the reason why the deregistration is triggered. + */ + public void triggerImsDeregistration( + @ImsRegistrationImplBase.ImsDeregistrationReason int reason) { + if (mImsPhone != null) { + mImsPhone.triggerImsDeregistration(reason); + } + } + /** * @return Telephony tester instance. */ diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 004444feb3..d8188d86b4 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -346,6 +346,8 @@ import android.telephony.data.RouteSelectionDescriptor; import android.telephony.data.TrafficDescriptor; import android.telephony.data.UrspRule; import android.telephony.ims.RegistrationManager; +import android.telephony.ims.stub.ImsRegistrationImplBase; +import android.telephony.ims.stub.ImsRegistrationImplBase.ImsDeregistrationReason; import android.text.TextUtils; import android.util.ArraySet; import android.util.SparseArray; @@ -4707,6 +4709,21 @@ public class RILUtils { } } + /** Convert IMS deregistration reason */ + public static @ImsDeregistrationReason int convertHalDeregistrationReason(int reason) { + switch (reason) { + case android.hardware.radio.ims.ImsDeregistrationReason.REASON_SIM_REMOVED: + return ImsRegistrationImplBase.REASON_SIM_REMOVED; + case android.hardware.radio.ims.ImsDeregistrationReason.REASON_SIM_REFRESH: + return ImsRegistrationImplBase.REASON_SIM_REFRESH; + case android.hardware.radio.ims.ImsDeregistrationReason + .REASON_ALLOWED_NETWORK_TYPES_CHANGED: + return ImsRegistrationImplBase.REASON_ALLOWED_NETWORK_TYPES_CHANGED; + default: + return ImsRegistrationImplBase.REASON_UNKNOWN; + } + } + /** Append the data to the end of an ArrayList */ public static void appendPrimitiveArrayToArrayList(byte[] src, ArrayList dst) { for (byte b : src) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index c876920b08..6b2073b239 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -82,6 +82,7 @@ import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsSsData; import android.telephony.ims.ImsSsInfo; import android.telephony.ims.RegistrationManager; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsUtImplBase; import android.text.TextUtils; import android.util.LocalLog; @@ -2642,6 +2643,12 @@ public class ImsPhone extends ImsPhoneBase { mDefaultPhone.triggerEpsFallback(reason, response); } + @Override + public void triggerImsDeregistration( + @ImsRegistrationImplBase.ImsDeregistrationReason int reason) { + mCT.triggerImsDeregistration(reason); + } + @Override public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 68e141e291..eb1f252a22 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -5733,4 +5733,18 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } return false; } + + /** + * Notifies that radio triggered IMS deregistration. + * @param reason the reason why the deregistration is triggered. + */ + public void triggerImsDeregistration( + @ImsRegistrationImplBase.ImsDeregistrationReason int reason) { + if (mImsManager == null) return; + try { + mImsManager.triggerDeregistration(reason); + } catch (ImsException e) { + loge("triggerImsDeregistration: exception " + e); + } + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 1ff45440d4..3222c310b5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -19,6 +19,7 @@ package com.android.internal.telephony; import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED; +import static com.android.internal.telephony.Phone.EVENT_IMS_DEREGISTRATION_TRIGGERED; import static com.android.internal.telephony.Phone.EVENT_SRVCC_STATE_CHANGED; import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; @@ -68,6 +69,7 @@ import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -2083,4 +2085,17 @@ public class GsmCdmaPhoneTest extends TelephonyTest { doReturn(false).when(mUiccCardApplication3gpp).getIccFdnEnabled(); } + @Test + @SmallTest + public void testTriggerImsDeregistration() throws Exception { + replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); + + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(EVENT_IMS_DEREGISTRATION_TRIGGERED, + new AsyncResult(null, + new int[]{ImsRegistrationImplBase.REASON_SIM_REFRESH}, null))); + processAllMessages(); + + verify(mImsPhone, times(1)).triggerImsDeregistration( + eq(ImsRegistrationImplBase.REASON_SIM_REFRESH)); + } } -- GitLab From bc80e8771ee9b6b6c9e1f05e25b54529c66dbb4f Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Sun, 25 Sep 2022 08:40:00 +0000 Subject: [PATCH 252/656] Add DomainSelectionController for the domain selection service Bug: 243344927 Bug: 258302615 Test: atest EmergencyCallDomainSelectionConnectionTest Change-Id: Iedae4cf261e30f9dd30ef2b462e99e0b0007b225 --- .../internal/telephony/CommandsInterface.java | 10 + .../internal/telephony/GsmCdmaPhone.java | 24 + .../internal/telephony/NetworkIndication.java | 2 +- .../com/android/internal/telephony/Phone.java | 28 ++ .../com/android/internal/telephony/RIL.java | 15 + .../DomainSelectionConnection.java | 441 ++++++++++++++++++ .../DomainSelectionController.java | 300 ++++++++++++ ...mergencyCallDomainSelectionConnection.java | 197 ++++++++ .../NormalCallDomainSelectionConnection.java | 94 ++++ .../DomainSelectionConnectionTest.java | 311 ++++++++++++ ...encyCallDomainSelectionConnectionTest.java | 219 +++++++++ 11 files changed, 1640 insertions(+), 1 deletion(-) create mode 100644 src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java create mode 100644 src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java create mode 100644 src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java create mode 100644 src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 98de4be845..cada6a4933 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -27,6 +27,7 @@ import android.os.Message; import android.os.WorkSource; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; +import android.telephony.BarringInfo; import android.telephony.CarrierRestrictionRules; import android.telephony.ClientRequestStats; import android.telephony.DomainSelectionService; @@ -2641,6 +2642,15 @@ public interface CommandsInterface { */ default void getBarringInfo(Message result) {}; + /** + * Returns the last barring information received. + * + * @return the last barring information. + */ + default @Nullable BarringInfo getLastBarringInfo() { + return null; + }; + /** * Allocates a pdu session id * diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 0fc9d59d6c..91d73d305c 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -64,6 +64,7 @@ import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telecom.VideoProfile; +import android.telephony.AccessNetworkConstants.TransportType; import android.telephony.Annotation.DataActivityType; import android.telephony.Annotation.RadioPowerState; import android.telephony.BarringInfo; @@ -228,6 +229,8 @@ public class GsmCdmaPhone extends Phone { private final RegistrantList mVolteSilentRedialRegistrants = new RegistrantList(); private DialArgs mDialArgs = null; + private final RegistrantList mEmergencyDomainSelectedRegistrants = new RegistrantList(); + private String mImei; private String mImeiSv; private String mVmNumber; @@ -4531,6 +4534,27 @@ public class GsmCdmaPhone extends Phone { mVolteSilentRedialRegistrants.notifyRegistrants(ar); } + /** {@inheritDoc} */ + @Override + public void registerForEmergencyDomainSelected( + @NonNull Handler h, int what, @Nullable Object obj) { + mEmergencyDomainSelectedRegistrants.addUnique(h, what, obj); + } + + /** {@inheritDoc} */ + @Override + public void unregisterForEmergencyDomainSelected(@NonNull Handler h) { + mEmergencyDomainSelectedRegistrants.remove(h); + } + + /** {@inheritDoc} */ + @Override + public void notifyEmergencyDomainSelected(@TransportType int transportType) { + logd("notifyEmergencyDomainSelected transportType=" + transportType); + mEmergencyDomainSelectedRegistrants.notifyRegistrants( + new AsyncResult(null, transportType, null)); + } + /** * Sets the SIM voice message waiting indicator records. * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index 8d518f0249..d1370030e9 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -88,7 +88,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { BarringInfo cbi = new BarringInfo(RILUtils.convertHalCellIdentity(cellIdentity), RILUtils.convertHalBarringInfoList(barringInfos)); - mRil.mBarringInfoChangedRegistrants.notifyRegistrants(new AsyncResult(null, cbi, null)); + mRil.notifyBarringInfoChanged(cbi); } /** diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index ab814837ea..b871eefdd9 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5018,6 +5018,34 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } } + /** + * Registers for the domain selected for emergency calls. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForEmergencyDomainSelected( + @NonNull Handler h, int what, @Nullable Object obj) { + } + + /** + * Unregisters for the domain selected for emergency calls. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForEmergencyDomainSelected(@NonNull Handler h) { + } + + /** + * Notifies the domain selected. + * + * @param transportType The preferred transport type. + */ + public void notifyEmergencyDomainSelected( + @AccessNetworkConstants.TransportType int transportType) { + } + /** * @return Telephony tester instance. */ diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 1a5f393328..893e102c22 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -56,6 +56,7 @@ import android.provider.Settings; import android.sysprop.TelephonyProperties; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; +import android.telephony.BarringInfo; import android.telephony.CarrierRestrictionRules; import android.telephony.CellInfo; import android.telephony.CellSignalStrengthCdma; @@ -267,6 +268,9 @@ public class RIL extends BaseCommands implements CommandsInterface { final RilHandler mRilHandler; private MockModem mMockModem; + // The last barring information received + private BarringInfo mLastBarringInfo = null; + // Thread-safe HashMap to map from RIL_REQUEST_XXX constant to HalVersion. // This is for Radio HAL Fallback Compatibility feature. When a RIL request // is received, the HAL method from the mapping HalVersion here (if present), @@ -6433,6 +6437,17 @@ public class RIL extends BaseCommands implements CommandsInterface { new CellSignalStrengthNr()); } + void notifyBarringInfoChanged(@NonNull BarringInfo barringInfo) { + mLastBarringInfo = barringInfo; + mBarringInfoChangedRegistrants.notifyRegistrants(new AsyncResult(null, barringInfo, null)); + } + + /** {@inheritDoc} */ + @Override + public @Nullable BarringInfo getLastBarringInfo() { + return mLastBarringInfo; + } + /** * Get the HAL version with a specific service. * diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java new file mode 100644 index 0000000000..e10c199c83 --- /dev/null +++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.AsyncResult; +import android.os.CancellationSignal; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.telephony.AccessNetworkConstants.RadioAccessNetworkType; +import android.telephony.Annotation.DisconnectCauses; +import android.telephony.DomainSelectionService; +import android.telephony.DomainSelectionService.EmergencyScanType; +import android.telephony.DomainSelector; +import android.telephony.EmergencyRegResult; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.TransportSelectorCallback; +import android.telephony.WwanSelectorCallback; +import android.util.LocalLog; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.infra.AndroidFuture; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.util.TelephonyUtils; + +import java.io.PrintWriter; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.function.Consumer; + + +/** + * Manages the information of request and the callback binder. + */ +public class DomainSelectionConnection { + + private static final boolean DBG = TelephonyUtils.IS_DEBUGGABLE; + + protected static final int EVENT_EMERGENCY_NETWORK_SCAN_RESULT = 1; + protected static final int EVENT_QUALIFIED_NETWORKS_CHANGED = 2; + + /** Callback to receive responses from DomainSelectionConnection. */ + public interface DomainSelectionConnectionCallback { + /** + * Notifies that selection has terminated because there is no decision that can be made + * or a timeout has occurred. The call should be terminated when this method is called. + * + * @param cause Indicates the reason. + */ + void onSelectionTerminated(@DisconnectCauses int cause); + } + + /** An internal class implementing {@link TransportSelectorCallback} interface. */ + private final class TransportSelectorCallbackWrapper implements TransportSelectorCallback { + @Override + public void onCreated(@NonNull DomainSelector selector) { + mDomainSelector = selector; + DomainSelectionConnection.this.onCreated(); + } + + @Override + public void onWlanSelected() { + DomainSelectionConnection.this.onWlanSelected(); + } + + @Override + public @NonNull WwanSelectorCallback onWwanSelected() { + if (mWwanSelectorCallback == null) { + mWwanSelectorCallback = new WwanSelectorCallbackWrapper(); + } + DomainSelectionConnection.this.onWwanSelected(); + return mWwanSelectorCallback; + } + + @Override + public void onWwanSelected(final Consumer consumer) { + if (mWwanSelectorCallback == null) { + mWwanSelectorCallback = new WwanSelectorCallbackWrapper(); + } + if (mWwanSelectedExecutor == null) { + mWwanSelectedExecutor = Executors.newSingleThreadExecutor(); + } + mWwanSelectedExecutor.execute(() -> { + DomainSelectionConnection.this.onWwanSelected(); + consumer.accept(mWwanSelectorCallback); + }); + } + + @Override + public void onSelectionTerminated(int cause) { + DomainSelectionConnection.this.onSelectionTerminated(cause); + dispose(); + } + } + + /** An internal class implementing {@link WwanSelectorCallback} interface. */ + private final class WwanSelectorCallbackWrapper + implements WwanSelectorCallback, CancellationSignal.OnCancelListener { + @Override + public void onRequestEmergencyNetworkScan(@NonNull List preferredNetworks, + @EmergencyScanType int scanType, @NonNull CancellationSignal signal, + @NonNull Consumer consumer) { + if (signal != null) signal.setOnCancelListener(this); + mResultCallback = consumer; + initHandler(); + DomainSelectionConnection.this.onRequestEmergencyNetworkScan( + preferredNetworks.stream().mapToInt(Integer::intValue).toArray(), scanType); + } + + @Override + public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) { + DomainSelectionConnection.this.onDomainSelected(domain); + } + + @Override + public void onCancel() { + DomainSelectionConnection.this.onCancel(); + } + } + + protected final class DomainSelectionConnectionHandler extends Handler { + DomainSelectionConnectionHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + switch (msg.what) { + case EVENT_EMERGENCY_NETWORK_SCAN_RESULT: + mIsWaitingForScanResult = false; + if (mResultCallback == null) break; + ar = (AsyncResult) msg.obj; + EmergencyRegResult regResult = (EmergencyRegResult) ar.result; + if (DBG) logd("EVENT_EMERGENCY_NETWORK_SCAN_RESULT result=" + regResult); + CompletableFuture.runAsync( + () -> mResultCallback.accept(regResult), + mController.getDomainSelectionServiceExecutor()).join(); + break; + case EVENT_QUALIFIED_NETWORKS_CHANGED: + onQualifiedNetworksChanged(); + break; + default: + loge("handleMessage unexpected msg=" + msg.what); + break; + } + } + } + + protected String mTag = "DomainSelectionConnection"; + + private final LocalLog mLocalLog = new LocalLog(30); + private final @NonNull TransportSelectorCallback mTransportSelectorCallback; + + /** + * Controls the communication between {@link DomainSelectionConnection} and + * {@link DomainSelectionService}. + */ + private final @NonNull DomainSelectionController mController; + /** Indicates whether the requested service is for emergency services. */ + private final boolean mIsEmergency; + + /** Interface to receive the request to trigger emergency network scan and selected domain. */ + private @Nullable WwanSelectorCallback mWwanSelectorCallback; + /** Interface to return the result of emergency network scan. */ + private @Nullable Consumer mResultCallback; + /** Interface to the {@link DomainSelector} created for this service. */ + private @Nullable DomainSelector mDomainSelector; + + /** The slot requested this connection. */ + protected @NonNull Phone mPhone; + /** The requested domain selector type. */ + private @DomainSelectionService.SelectorType int mSelectorType; + + /** The attributes required to determine the domain. */ + private @Nullable DomainSelectionService.SelectionAttributes mSelectionAttributes; + + private @Nullable Looper mLooper; + protected @Nullable DomainSelectionConnectionHandler mHandler; + private boolean mRegisteredRegistrant; + private boolean mIsWaitingForScanResult; + + private @NonNull AndroidFuture mOnComplete; + + private @Nullable Executor mWwanSelectedExecutor; + + /** + * Creates an instance. + * + * @param phone For which this service is requested. + * @param selectorType Indicates the type of the requested service. + * @param isEmergency Indicates whether this request is for emergency service. + * @param controller The controller to communicate with the domain selection service. + */ + public DomainSelectionConnection(@NonNull Phone phone, + @DomainSelectionService.SelectorType int selectorType, boolean isEmergency, + @NonNull DomainSelectionController controller) { + mController = controller; + mPhone = phone; + mSelectorType = selectorType; + mIsEmergency = isEmergency; + + mTransportSelectorCallback = new TransportSelectorCallbackWrapper(); + mOnComplete = new AndroidFuture<>(); + } + + /** + * Returns the attributes required to determine the domain for a telephony service. + * + * @return The attributes required to determine the domain. + */ + public @Nullable DomainSelectionService.SelectionAttributes getSelectionAttributes() { + return mSelectionAttributes; + } + + /** + * Returns the interface for the callbacks. + * + * @return The {@link TransportSelectorCallback} interface. + */ + @VisibleForTesting + public @NonNull TransportSelectorCallback getTransportSelectorCallback() { + return mTransportSelectorCallback; + } + + /** + * Returns the {@link CompletableFuture} to receive the selected domain. + * + * @return The callback to receive response. + */ + public @NonNull CompletableFuture getCompletableFuture() { + return mOnComplete; + } + + /** + * Returs the {@link Phone} which requested this connection. + * + * @return The {@link Phone} instance. + */ + public @NonNull Phone getPhone() { + return mPhone; + } + + /** + * Requests the domain selection servic to select a domain. + * + * @param attr The attributes required to determine the domain. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) + public void selectDomain(@NonNull DomainSelectionService.SelectionAttributes attr) { + mSelectionAttributes = attr; + mController.selectDomain(attr, getTransportSelectorCallback()); + } + + /** + * Notifies that {@link DomainSelector} instance has been created for the selection request. + */ + public void onCreated() { + // Can be overridden if required + } + + /** + * Notifies that WLAN transport has been selected. + */ + public void onWlanSelected() { + // Can be overridden. + } + + /** + * Notifies that WWAN transport has been selected. + */ + public void onWwanSelected() { + // Can be overridden. + } + + /** + * Notifies that selection has terminated because there is no decision that can be made + * or a timeout has occurred. The call should be terminated when this method is called. + * + * @param cause Indicates the reason. + */ + public void onSelectionTerminated(@DisconnectCauses int cause) { + // Can be overridden. + } + + /** + * Requests the emergency network scan. + * + * @param preferredNetworks The ordered list of preferred networks to scan. + * @param scanType Indicates the scan preference, such as full service or limited service. + */ + public void onRequestEmergencyNetworkScan( + @NonNull @RadioAccessNetworkType int[] preferredNetworks, + @EmergencyScanType int scanType) { + // Can be overridden if required + if (!mRegisteredRegistrant) { + mPhone.registerForEmergencyNetworkScan(mHandler, + EVENT_EMERGENCY_NETWORK_SCAN_RESULT, null); + mRegisteredRegistrant = true; + } + mIsWaitingForScanResult = true; + mPhone.triggerEmergencyNetworkScan(preferredNetworks, scanType, null); + } + + /** + * Notifies the domain selected. + * @param domain The selected domain. + */ + public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) { + // Can be overridden if required + CompletableFuture future = getCompletableFuture(); + future.complete(domain); + } + + /** + * Notifies that the emergency network scan is canceled. + */ + public void onCancel() { + // Can be overridden if required + onCancel(false); + } + + private void onCancel(boolean resetScan) { + mIsWaitingForScanResult = false; + mPhone.cancelEmergencyNetworkScan(resetScan, null); + } + + /** + * Cancels an ongoing selection operation. It is up to the {@link DomainSelectionService} + * to clean up all ongoing operations with the framework. + */ + public void cancelSelection() { + if (mDomainSelector == null) return; + mDomainSelector.cancelSelection(); + dispose(); + } + + /** + * Requests the domain selection service to reselect a domain. + * + * @param attr The attributes required to determine the domain. + * @return The callback to receive the response. + */ + public @NonNull CompletableFuture reselectDomain( + @NonNull DomainSelectionService.SelectionAttributes attr) { + mSelectionAttributes = attr; + if (mDomainSelector == null) return null; + mOnComplete = new AndroidFuture<>(); + mDomainSelector.reselectDomain(attr); + return mOnComplete; + } + + /** + * Finishes the selection procedure and cleans everything up. + */ + public void finishSelection() { + if (mDomainSelector == null) return; + mDomainSelector.finishSelection(); + dispose(); + } + + /** Indicates that the service connection has been removed. */ + public void onServiceDisconnected() { + // Can be overridden. + dispose(); + } + + private void dispose() { + if (mRegisteredRegistrant) { + mPhone.unregisterForEmergencyNetworkScan(mHandler); + mRegisteredRegistrant = false; + } + if (mIsWaitingForScanResult) onCancel(true); + mController.removeConnection(this); + if (mLooper != null) mLooper.quitSafely(); + mLooper = null; + mHandler = null; + } + + protected void initHandler() { + if (mLooper == null) { + HandlerThread handlerThread = new HandlerThread(mTag); + handlerThread.start(); + mLooper = handlerThread.getLooper(); + } + if (mHandler == null) mHandler = new DomainSelectionConnectionHandler(mLooper); + } + + /** + * Notifies the change of qualified networks. + */ + protected void onQualifiedNetworksChanged() { + if (mIsEmergency + && (mSelectorType == DomainSelectionService.SELECTOR_TYPE_CALLING)) { + // DomainSelectionConnection for emergency calls shall override this. + throw new IllegalStateException("DomainSelectionConnection for emergency calls" + + " should override onQualifiedNetworksChanged()"); + } + } + + /** + * Dumps local log. + */ + public void dump(@NonNull PrintWriter printWriter) { + mLocalLog.dump(printWriter); + } + + protected void logd(String msg) { + Log.d(mTag, msg); + } + + protected void logi(String msg) { + Log.i(mTag, msg); + mLocalLog.log(msg); + } + + protected void loge(String msg) { + Log.e(mTag, msg); + mLocalLog.log(msg); + } +} diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java new file mode 100644 index 0000000000..61304c3df6 --- /dev/null +++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING; +import static android.telephony.DomainSelectionService.SELECTOR_TYPE_SMS; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.telephony.BarringInfo; +import android.telephony.DomainSelectionService; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.telephony.TransportSelectorCallback; +import android.util.LocalLog; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.util.TelephonyUtils; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.concurrent.Executor; + +/** + * Manages the connection to {@link DomainSelectionService}. + */ +public class DomainSelectionController { + private static final String TAG = "DomainSelectionController"; + private static final boolean DBG = TelephonyUtils.IS_DEBUGGABLE; + + private static final int EVENT_SERVICE_STATE_CHANGED = 1; + private static final int EVENT_BARRING_INFO_CHANGED = 2; + + private final HandlerThread mHandlerThread = + new HandlerThread("DomainSelectionControllerHandler"); + + private final DomainSelectionService mDomainSelectionService; + private final Handler mHandler; + // Only added or removed, never accessed on purpose. + private final LocalLog mLocalLog = new LocalLog(30); + + protected final Object mLock = new Object(); + protected final Context mContext; + + protected final int[] mConnectionCounts; + private final ArrayList mConnections = new ArrayList<>(); + + private final class DomainSelectionControllerHandler extends Handler { + DomainSelectionControllerHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + switch (msg.what) { + case EVENT_SERVICE_STATE_CHANGED: + ar = (AsyncResult) msg.obj; + updateServiceState((Phone) ar.userObj, (ServiceState) ar.result); + break; + case EVENT_BARRING_INFO_CHANGED: + ar = (AsyncResult) msg.obj; + updateBarringInfo((Phone) ar.userObj, (BarringInfo) ar.result); + break; + default: + loge("unexpected event=" + msg.what); + break; + } + } + } + + /** + * Creates an instance. + * + * @param context Context object from hosting application. + * @param service The {@link DomainSelectionService} instance. + */ + public DomainSelectionController(@NonNull Context context, + @NonNull DomainSelectionService service) { + this(context, service, null); + } + + /** + * Creates an instance. + * + * @param context Context object from hosting application. + * @param service The {@link DomainSelectionService} instance. + * @param looper Handles event messages. + */ + @VisibleForTesting + public DomainSelectionController(@NonNull Context context, + @NonNull DomainSelectionService service, @Nullable Looper looper) { + mContext = context; + mDomainSelectionService = service; + + if (looper == null) { + mHandlerThread.start(); + looper = mHandlerThread.getLooper(); + } + mHandler = new DomainSelectionControllerHandler(looper); + + int numPhones = TelephonyManager.getDefault().getActiveModemCount(); + mConnectionCounts = new int[numPhones]; + for (int i = 0; i < numPhones; i++) { + mConnectionCounts[i] = 0; + } + } + + /** + * Returns a {@link DomainSelectionConnection} instance. + * + * @param phone Indicates who requests the service. + * @param selectorType Indicates the selector type requested. + * @param isEmergency Indicates whether this is for emergency service. + * @return A {@link DomainSelectiionConnection} instance for the requested service. + * Returns {@code null} if the requested service is not supported. + */ + public @Nullable DomainSelectionConnection getDomainSelectionConnection( + @NonNull Phone phone, + @DomainSelectionService.SelectorType int selectorType, + boolean isEmergency) { + DomainSelectionConnection c = null; + + if (selectorType == SELECTOR_TYPE_CALLING) { + if (isEmergency) { + c = new EmergencyCallDomainSelectionConnection(phone, this); + } else { + c = new NormalCallDomainSelectionConnection(phone, this); + } + } else if (selectorType == SELECTOR_TYPE_SMS) { + // TODO(ag/20126511) uncomment when SmSDomainSelectionConnection is ready. + /*if (isEmergency) { + c = new EmergencySmsDomainSelectionConnection(phone, this); + } else { + c = new SmsDomainSelectionConnection(phone, this); + }*/ + } + + addConnection(c); + return c; + } + + private void addConnection(@Nullable DomainSelectionConnection c) { + if (c == null) return; + mConnections.add(c); + registerForStateChange(c); + } + + /** + * Releases resources for this connection. + */ + public void removeConnection(@Nullable DomainSelectionConnection c) { + if (c == null) return; + mConnections.remove(c); + unregisterForStateChange(c); + } + + /** + * Requests the domain selection. + * + * @param attr Attributetes required to determine the domain. + * @param callback A callback to receive the response. + */ + public void selectDomain(@NonNull DomainSelectionService.SelectionAttributes attr, + @NonNull TransportSelectorCallback callback) { + if (attr == null || callback == null) return; + if (DBG) logd("selectDomain"); + + Executor e = mDomainSelectionService.getCachedExecutor(); + e.execute(() -> mDomainSelectionService.onDomainSelection(attr, callback)); + } + + /** + * Notifies the change in {@link ServiceState} for a specific slot. + * + * @param phone {@link Phone} which the state changed. + * @param serviceState Updated {@link ServiceState}. + */ + private void updateServiceState(Phone phone, ServiceState serviceState) { + if (phone == null || serviceState == null) return; + if (DBG) logd("updateServiceState phoneId=" + phone.getPhoneId()); + + Executor e = mDomainSelectionService.getCachedExecutor(); + e.execute(() -> mDomainSelectionService.onServiceStateUpdated( + phone.getPhoneId(), phone.getSubId(), serviceState)); + } + + /** + * Notifies the change in {@link BarringInfo} for a specific slot. + * + * @param phone {@link Phone} which the state changed. + * @param info Updated {@link BarringInfo}. + */ + private void updateBarringInfo(Phone phone, BarringInfo info) { + if (phone == null || info == null) return; + if (DBG) logd("updateBarringInfo phoneId=" + phone.getPhoneId()); + + Executor e = mDomainSelectionService.getCachedExecutor(); + e.execute(() -> mDomainSelectionService.onBarringInfoUpdated( + phone.getPhoneId(), phone.getSubId(), info)); + } + + /** + * Registers for the notification of {@link ServiceState} and {@link BarringInfo}. + * + * @param c {@link DomainSelectionConnection} for which the registration is requested. + */ + private void registerForStateChange(DomainSelectionConnection c) { + Phone phone = c.getPhone(); + int count = mConnectionCounts[phone.getPhoneId()]; + if (count < 0) count = 0; + + mConnectionCounts[phone.getPhoneId()] = count + 1; + if (count > 0) return; + + phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, phone); + phone.mCi.registerForBarringInfoChanged(mHandler, EVENT_BARRING_INFO_CHANGED, phone); + + updateServiceState(phone, phone.getServiceStateTracker().getServiceState()); + updateBarringInfo(phone, phone.mCi.getLastBarringInfo()); + } + + /** + * Unregisters for the notification of {@link ServiceState} and {@link BarringInfo}. + * + * @param c {@link DomainSelectionConnection} for which the unregistration is requested. + */ + private void unregisterForStateChange(DomainSelectionConnection c) { + Phone phone = c.getPhone(); + int count = mConnectionCounts[phone.getPhoneId()]; + if (count < 1) count = 1; + + mConnectionCounts[phone.getPhoneId()] = count - 1; + if (count > 1) return; + + phone.unregisterForServiceStateChanged(mHandler); + phone.mCi.unregisterForBarringInfoChanged(mHandler); + } + + /** + * Notifies the {@link DomainSelectionConnection} instances registered + * of the service disconnection. + */ + private void notifyServiceDisconnected() { + for (DomainSelectionConnection c : mConnections) { + c.onServiceDisconnected(); + } + } + + /** + * Gets the {@link Executor} which executes methods of {@link DomainSelectionService.} + * @return {@link Executor} instance. + */ + public @NonNull Executor getDomainSelectionServiceExecutor() { + return mDomainSelectionService.getCachedExecutor(); + } + + /** + * Dumps logcal log + */ + public void dump(@NonNull PrintWriter printWriter) { + mLocalLog.dump(printWriter); + } + + private void logd(String msg) { + Log.d(TAG, msg); + } + + private void logi(String msg) { + Log.i(TAG, msg); + mLocalLog.log(msg); + } + + private void loge(String msg) { + Log.e(TAG, msg); + mLocalLog.log(msg); + } +} diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java new file mode 100644 index 0000000000..2646c48873 --- /dev/null +++ b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_INVALID; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; +import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN; +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.telephony.AccessNetworkConstants.TransportType; +import android.telephony.Annotation.DisconnectCauses; +import android.telephony.Annotation.NetCapability; +import android.telephony.DomainSelectionService; +import android.telephony.EmergencyRegResult; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.data.ApnSetting; +import android.telephony.ims.ImsReasonInfo; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.emergency.EmergencyStateTracker; + +import java.util.concurrent.CompletableFuture; + +/** + * Manages the information of request and the callback binder for emergency calling. + */ +public class EmergencyCallDomainSelectionConnection extends DomainSelectionConnection { + + private static final boolean DBG = false; + + private @NonNull EmergencyStateTracker mEmergencyStateTracker = null; + private @Nullable DomainSelectionConnectionCallback mCallback; + private @TransportType int mPreferredTransportType = TRANSPORT_TYPE_INVALID; + + /** + * Create an instance. + * + * @param phone For which this service is requested. + * @param controller The controller to communicate with the domain selection service. + */ + public EmergencyCallDomainSelectionConnection(@NonNull Phone phone, + @NonNull DomainSelectionController controller) { + this(phone, controller, EmergencyStateTracker.getInstance()); + } + + /** + * Create an instance. + * + * @param phone For which this service is requested. + * @param controller The controller to communicate with the domain selection service. + * @param tracker The {@link EmergencyStateTracker} instance. + */ + @VisibleForTesting + public EmergencyCallDomainSelectionConnection(@NonNull Phone phone, + @NonNull DomainSelectionController controller, @NonNull EmergencyStateTracker tracker) { + super(phone, SELECTOR_TYPE_CALLING, true, controller); + mTag = "EmergencyCallDomainSelectionConnection"; + + mEmergencyStateTracker = tracker; + } + + /** {@inheritDoc} */ + @Override + public void onWlanSelected() { + mEmergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WLAN); + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + if (anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY) != TRANSPORT_TYPE_WLAN) { + changePreferredTransport(TRANSPORT_TYPE_WLAN); + return; + } + + CompletableFuture future = getCompletableFuture(); + if (future != null) future.complete(DOMAIN_PS); + } + + /** {@inheritDoc} */ + @Override + public void onWwanSelected() { + mEmergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + } + + /** {@inheritDoc} */ + @Override + public void onSelectionTerminated(@DisconnectCauses int cause) { + if (mCallback != null) mCallback.onSelectionTerminated(cause); + } + + /** {@inheritDoc} */ + @Override + public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) { + if (domain == DOMAIN_PS) { + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + if (anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY) != TRANSPORT_TYPE_WWAN) { + changePreferredTransport(TRANSPORT_TYPE_WWAN); + return; + } + } + super.onDomainSelected(domain); + } + + /** + * Request a domain for emergency call. + * + * @param attr The attributes required to determine the domain. + * @param callback A callback to receive the response. + * @return the callback to receive the response. + */ + public @NonNull CompletableFuture createEmergencyConnection( + @NonNull DomainSelectionService.SelectionAttributes attr, + @NonNull DomainSelectionConnectionCallback callback) { + mCallback = callback; + selectDomain(attr); + return getCompletableFuture(); + } + + private void changePreferredTransport(@TransportType int transportType) { + initHandler(); + mPreferredTransportType = transportType; + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + anm.registerForQualifiedNetworksChanged(mHandler, EVENT_QUALIFIED_NETWORKS_CHANGED); + mPhone.notifyEmergencyDomainSelected(transportType); + } + + private AccessNetworksManager.AccessNetworksManagerCallback mPreferredTransportCallback = + new AccessNetworksManager.AccessNetworksManagerCallback(Runnable::run) { + @Override + public void onPreferredTransportChanged(@NetCapability int capability) { + } + }; + + /** {@inheritDoc} */ + @Override + protected void onQualifiedNetworksChanged() { + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + int preferredTransport = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); + if (preferredTransport == mPreferredTransportType) { + CompletableFuture future = getCompletableFuture(); + if (future != null) future.complete(DOMAIN_PS); + anm.unregisterForQualifiedNetworksChanged(mHandler); + } + } + + /** + * Returns the attributes required to determine the domain for a telephony service. + * + * @param slotId The slot identifier. + * @param subId The subscription identifier. + * @param exited {@code true} if the request caused the device to move out of airplane mode. + * @param callId The call identifier. + * @param number The dialed number. + * @param callFailCause The reason why the last CS attempt failed. + * @param imsReasonInfo The reason why the last PS attempt failed. + * @param emergencyRegResult The current registration result for emergency services. + * @return The attributes required to determine the domain. + */ + public static @NonNull DomainSelectionService.SelectionAttributes getSelectionAttributes( + int slotId, int subId, boolean exited, + @NonNull String callId, @NonNull String number, int callFailCause, + @Nullable ImsReasonInfo imsReasonInfo, + @Nullable EmergencyRegResult emergencyRegResult) { + DomainSelectionService.SelectionAttributes.Builder builder = + new DomainSelectionService.SelectionAttributes.Builder( + slotId, subId, SELECTOR_TYPE_CALLING) + .setEmergency(true) + .setExitedFromAirplaneMode(exited) + .setCallId(callId) + .setNumber(number) + .setCsDisconnectCause(callFailCause); + + if (imsReasonInfo != null) builder.setPsDisconnectCause(imsReasonInfo); + if (emergencyRegResult != null) builder.setEmergencyRegResult(emergencyRegResult); + + return builder.build(); + } +} diff --git a/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java new file mode 100644 index 0000000000..8aa54ac554 --- /dev/null +++ b/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.telephony.AccessNetworkConstants.RadioAccessNetworkType; +import android.telephony.Annotation.DisconnectCauses; +import android.telephony.DomainSelectionService; +import android.telephony.DomainSelectionService.EmergencyScanType; +import android.telephony.NetworkRegistrationInfo; + +import com.android.internal.telephony.Phone; + +import java.util.concurrent.CompletableFuture; + +/** + * Manages the information of request and the callback binder for normal calling. + */ +public class NormalCallDomainSelectionConnection extends DomainSelectionConnection { + + private static final boolean DBG = false; + + private @Nullable DomainSelectionConnectionCallback mCallback; + + /** + * Create an instance. + * + * @param phone For which this service is requested. + * @param controller The controller to communicate with the domain selection service. + */ + public NormalCallDomainSelectionConnection(@NonNull Phone phone, + @NonNull DomainSelectionController controller) { + super(phone, SELECTOR_TYPE_CALLING, false, controller); + mTag = "NormalCallDomainSelectionConnection"; + } + + /** {@inheritDoc} */ + @Override + public void onWlanSelected() { + CompletableFuture future = getCompletableFuture(); + future.complete(NetworkRegistrationInfo.DOMAIN_PS); + } + + /** {@inheritDoc} */ + @Override + public void onWwanSelected() { + } + + /** {@inheritDoc} */ + @Override + public void onSelectionTerminated(@DisconnectCauses int cause) { + if (mCallback != null) mCallback.onSelectionTerminated(cause); + } + + /** {@inheritDoc} */ + @Override + public void onRequestEmergencyNetworkScan(@RadioAccessNetworkType int[] preferredNetworks, + @EmergencyScanType int scanType) { + // Not expected with normal calling. + // Override to prevent abnormal behavior. + } + + /** + * Request a domain for normal call. + * + * @param attr The attributes required to determine the domain. + * @param callback A callback to receive the response. + * @return A {@link CompletableFuture} callback to receive the result. + */ + public CompletableFuture createNormalConnection( + @NonNull DomainSelectionService.SelectionAttributes attr, + @NonNull DomainSelectionConnectionCallback callback) { + mCallback = callback; + selectDomain(attr); + return getCompletableFuture(); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java new file mode 100644 index 0000000000..ce59cc6c32 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionConnectionTest.java @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN; +import static android.telephony.DomainSelectionService.SCAN_TYPE_NO_PREFERENCE; +import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.os.AsyncResult; +import android.os.CancellationSignal; +import android.os.Handler; +import android.telephony.DomainSelectionService; +import android.telephony.DomainSelector; +import android.telephony.EmergencyRegResult; +import android.telephony.TransportSelectorCallback; +import android.telephony.WwanSelectorCallback; +import android.telephony.ims.ImsReasonInfo; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.CallFailCause; +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DomainSelectionConnectionTest extends TelephonyTest { + + private static final String TELECOM_CALL_ID1 = "TC1"; + + private DomainSelectionController mDomainSelectionController; + private DomainSelectionConnection.DomainSelectionConnectionCallback mConnectionCallback; + private DomainSelectionConnection mDsc; + + @Before + public void setUp() throws Exception { + super.setUp(this.getClass().getSimpleName()); + + mDomainSelectionController = Mockito.mock(DomainSelectionController.class); + mConnectionCallback = + Mockito.mock(DomainSelectionConnection.DomainSelectionConnectionCallback.class); + } + + @After + public void tearDown() throws Exception { + mDsc = null; + super.tearDown(); + } + + @Test + @SmallTest + public void testTransportSelectorCallback() { + mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, + mDomainSelectionController); + + TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback(); + + assertNotNull(transportCallback); + } + + @Test + @SmallTest + public void testSelectDomain() { + mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, + mDomainSelectionController); + + TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback(); + + DomainSelectionService.SelectionAttributes attr = getSelectionAttributes( + mPhone.getPhoneId(), mPhone.getSubId(), SELECTOR_TYPE_CALLING, true, + false, 0, null, null, null, null); + + mDsc.selectDomain(attr); + + verify(mDomainSelectionController).selectDomain(any(), eq(transportCallback)); + } + + @Test + @SmallTest + public void testWwanSelectorCallback() throws Exception { + mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, + mDomainSelectionController); + + TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback(); + + assertNotNull(transportCallback); + + WwanSelectorCallback wwanCallback = null; + wwanCallback = transportCallback.onWwanSelected(); + + assertNotNull(wwanCallback); + } + + @Test + @SmallTest + public void testWwanSelectorCallbackAsync() throws Exception { + mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, + mDomainSelectionController); + replaceInstance(DomainSelectionConnection.class, "mWwanSelectedExecutor", + mDsc, new Executor() { + public void execute(Runnable command) { + command.run(); + } + }); + + TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback(); + + assertNotNull(transportCallback); + + Consumer consumer = Mockito.mock(Consumer.class); + transportCallback.onWwanSelected(consumer); + + verify(consumer).accept(any()); + } + + @Test + @SmallTest + public void testWwanSelectorCallbackOnRequestEmergencyNetworkScan() throws Exception { + mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, + mDomainSelectionController); + + TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback(); + + assertNotNull(transportCallback); + + WwanSelectorCallback wwanCallback = transportCallback.onWwanSelected(); + + assertNotNull(wwanCallback); + + replaceInstance(DomainSelectionConnection.class, "mLooper", + mDsc, mTestableLooper.getLooper()); + List preferredNetworks = new ArrayList<>(); + preferredNetworks.add(EUTRAN); + preferredNetworks.add(UTRAN); + int scanType = SCAN_TYPE_NO_PREFERENCE; + Consumer consumer = Mockito.mock(Consumer.class); + + wwanCallback.onRequestEmergencyNetworkScan(preferredNetworks, scanType, null, consumer); + + ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); + ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(Integer.class); + + verify(mPhone).registerForEmergencyNetworkScan( + handlerCaptor.capture(), eventCaptor.capture(), any()); + + int[] expectedPreferredNetworks = new int[] { EUTRAN, UTRAN }; + + verify(mPhone).triggerEmergencyNetworkScan(eq(expectedPreferredNetworks), + eq(scanType), any()); + + Handler handler = handlerCaptor.getValue(); + int event = eventCaptor.getValue(); + + assertNotNull(handler); + + doReturn(new Executor() { + public void execute(Runnable r) { + r.run(); + } + }).when(mDomainSelectionController).getDomainSelectionServiceExecutor(); + EmergencyRegResult regResult = + new EmergencyRegResult(UTRAN, 0, 0, true, false, 0, 0, "", "", ""); + handler.sendMessage(handler.obtainMessage(event, new AsyncResult(null, regResult, null))); + processAllMessages(); + + verify(consumer).accept(eq(regResult)); + } + + @Test + @SmallTest + public void testWwanSelectorCallbackOnRequestEmergencyNetworkScanAndCancel() throws Exception { + mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, + mDomainSelectionController); + + TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback(); + + assertNotNull(transportCallback); + + WwanSelectorCallback wwanCallback = transportCallback.onWwanSelected(); + + assertNotNull(wwanCallback); + + replaceInstance(DomainSelectionConnection.class, "mLooper", + mDsc, mTestableLooper.getLooper()); + CancellationSignal signal = new CancellationSignal(); + wwanCallback.onRequestEmergencyNetworkScan(new ArrayList<>(), + SCAN_TYPE_NO_PREFERENCE, signal, Mockito.mock(Consumer.class)); + + verify(mPhone).registerForEmergencyNetworkScan(any(), anyInt(), any()); + verify(mPhone).triggerEmergencyNetworkScan(any(), anyInt(), any()); + + signal.cancel(); + + verify(mPhone).cancelEmergencyNetworkScan(eq(false), any()); + } + + @Test + @SmallTest + public void testDomainSelectorCancelSelection() throws Exception { + mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, + mDomainSelectionController); + + TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback(); + + assertNotNull(transportCallback); + + DomainSelector domainSelector = Mockito.mock(DomainSelector.class); + transportCallback.onCreated(domainSelector); + + mDsc.cancelSelection(); + + verify(domainSelector).cancelSelection(); + } + + @Test + @SmallTest + public void testDomainSelectorReselectDomain() throws Exception { + mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, + mDomainSelectionController); + + TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback(); + + assertNotNull(transportCallback); + + DomainSelector domainSelector = Mockito.mock(DomainSelector.class); + transportCallback.onCreated(domainSelector); + + DomainSelectionService.SelectionAttributes attr = getSelectionAttributes( + mPhone.getPhoneId(), mPhone.getSubId(), SELECTOR_TYPE_CALLING, true, + false, CallFailCause.ERROR_UNSPECIFIED, null, null, null, null); + + CompletableFuture future = mDsc.reselectDomain(attr); + + assertNotNull(future); + assertFalse(future.isDone()); + + verify(domainSelector).reselectDomain(any()); + } + + @Test + @SmallTest + public void testDomainSelectorFinishSelection() throws Exception { + mDsc = new DomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true, + mDomainSelectionController); + + TransportSelectorCallback transportCallback = mDsc.getTransportSelectorCallback(); + + assertNotNull(transportCallback); + + DomainSelector domainSelector = Mockito.mock(DomainSelector.class); + transportCallback.onCreated(domainSelector); + + mDsc.finishSelection(); + + verify(domainSelector).finishSelection(); + } + + private DomainSelectionService.SelectionAttributes getSelectionAttributes( + int slotId, int subId, int selectorType, boolean isEmergency, + boolean exited, int callFailCause, String callId, String number, + ImsReasonInfo imsReasonInfo, EmergencyRegResult regResult) { + DomainSelectionService.SelectionAttributes.Builder builder = + new DomainSelectionService.SelectionAttributes.Builder( + slotId, subId, selectorType) + .setEmergency(isEmergency) + .setExitedFromAirplaneMode(exited) + .setCsDisconnectCause(callFailCause); + + if (callId != null) builder.setCallId(callId); + if (number != null) builder.setNumber(number); + if (imsReasonInfo != null) builder.setPsDisconnectCause(imsReasonInfo); + if (regResult != null) builder.setEmergencyRegResult(regResult); + + return builder.build(); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java new file mode 100644 index 0000000000..f646d7e93e --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; +import static android.telephony.DisconnectCause.ERROR_UNSPECIFIED; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; +import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN; + +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN; +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.telephony.DomainSelectionService; +import android.telephony.EmergencyRegResult; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.TransportSelectorCallback; +import android.telephony.WwanSelectorCallback; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.emergency.EmergencyStateTracker; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +import java.util.concurrent.CompletableFuture; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { + + private static final String TELECOM_CALL_ID1 = "TC1"; + + private DomainSelectionController mDomainSelectionController; + private DomainSelectionConnection.DomainSelectionConnectionCallback mConnectionCallback; + private EmergencyCallDomainSelectionConnection mEcDsc; + private AccessNetworksManager mAnm; + private TransportSelectorCallback mTransportCallback; + private EmergencyStateTracker mEmergencyStateTracker; + + @Before + public void setUp() throws Exception { + super.setUp(this.getClass().getSimpleName()); + + mDomainSelectionController = Mockito.mock(DomainSelectionController.class); + mConnectionCallback = + Mockito.mock(DomainSelectionConnection.DomainSelectionConnectionCallback.class); + mEmergencyStateTracker = Mockito.mock(EmergencyStateTracker.class); + mAnm = Mockito.mock(AccessNetworksManager.class); + doReturn(mAnm).when(mPhone).getAccessNetworksManager(); + mEcDsc = new EmergencyCallDomainSelectionConnection(mPhone, + mDomainSelectionController, mEmergencyStateTracker); + mTransportCallback = mEcDsc.getTransportSelectorCallback(); + } + + @After + public void tearDown() throws Exception { + mEcDsc = null; + super.tearDown(); + } + + @Test + @SmallTest + public void testSelectDomainWifi() throws Exception { + doReturn(TRANSPORT_TYPE_WLAN).when(mAnm).getPreferredTransport(anyInt()); + replaceInstance(EmergencyCallDomainSelectionConnection.class, + "mEmergencyStateTracker", mEcDsc, mEmergencyStateTracker); + + EmergencyRegResult regResult = new EmergencyRegResult( + EUTRAN, REGISTRATION_STATE_UNKNOWN, + NetworkRegistrationInfo.DOMAIN_PS, + true, false, 0, 0, "", "", ""); + + DomainSelectionService.SelectionAttributes attr = + EmergencyCallDomainSelectionConnection.getSelectionAttributes( + mPhone.getPhoneId(), mPhone.getSubId(), false, + TELECOM_CALL_ID1, "911", 0, null, regResult); + + CompletableFuture future = + mEcDsc.createEmergencyConnection(attr, mConnectionCallback); + + assertNotNull(future); + assertFalse(future.isDone()); + + verify(mDomainSelectionController).selectDomain(any(), any()); + + mTransportCallback.onWlanSelected(); + + assertTrue(future.isDone()); + assertEquals((long) DOMAIN_PS, (long) future.get()); + verify(mEmergencyStateTracker).onEmergencyTransportChanged(MODE_EMERGENCY_WLAN); + } + + @Test + @SmallTest + public void testSelectDomainCs() throws Exception { + doReturn(TRANSPORT_TYPE_WWAN).when(mAnm).getPreferredTransport(anyInt()); + replaceInstance(EmergencyCallDomainSelectionConnection.class, + "mEmergencyStateTracker", mEcDsc, mEmergencyStateTracker); + + EmergencyRegResult regResult = new EmergencyRegResult( + UTRAN, REGISTRATION_STATE_UNKNOWN, + NetworkRegistrationInfo.DOMAIN_CS, + true, false, 0, 0, "", "", ""); + + DomainSelectionService.SelectionAttributes attr = + EmergencyCallDomainSelectionConnection.getSelectionAttributes( + mPhone.getPhoneId(), mPhone.getSubId(), false, + TELECOM_CALL_ID1, "911", 0, null, regResult); + + CompletableFuture future = + mEcDsc.createEmergencyConnection(attr, mConnectionCallback); + + assertNotNull(future); + assertFalse(future.isDone()); + + verify(mDomainSelectionController).selectDomain(any(), any()); + + WwanSelectorCallback wwanCallback = null; + wwanCallback = mTransportCallback.onWwanSelected(); + + assertFalse(future.isDone()); + verify(mEmergencyStateTracker).onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + + wwanCallback.onDomainSelected(DOMAIN_CS); + + assertTrue(future.isDone()); + assertEquals((long) DOMAIN_CS, (long) future.get()); + } + + @Test + @SmallTest + public void testSelectDomainPs() throws Exception { + doReturn(TRANSPORT_TYPE_WWAN).when(mAnm).getPreferredTransport(anyInt()); + replaceInstance(EmergencyCallDomainSelectionConnection.class, + "mEmergencyStateTracker", mEcDsc, mEmergencyStateTracker); + + EmergencyRegResult regResult = new EmergencyRegResult( + EUTRAN, REGISTRATION_STATE_UNKNOWN, + NetworkRegistrationInfo.DOMAIN_PS, + true, true, 0, 0, "", "", ""); + + DomainSelectionService.SelectionAttributes attr = + EmergencyCallDomainSelectionConnection.getSelectionAttributes( + mPhone.getPhoneId(), mPhone.getSubId(), false, + TELECOM_CALL_ID1, "911", 0, null, regResult); + + CompletableFuture future = + mEcDsc.createEmergencyConnection(attr, mConnectionCallback); + + assertNotNull(future); + assertFalse(future.isDone()); + + verify(mDomainSelectionController).selectDomain(any(), any()); + + WwanSelectorCallback wwanCallback = null; + wwanCallback = mTransportCallback.onWwanSelected(); + + assertFalse(future.isDone()); + verify(mEmergencyStateTracker).onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + + wwanCallback.onDomainSelected(DOMAIN_PS); + + assertTrue(future.isDone()); + assertEquals((long) DOMAIN_PS, (long) future.get()); + } + + @Test + @SmallTest + public void testOnSelectionTerminated() throws Exception { + EmergencyRegResult regResult = new EmergencyRegResult( + EUTRAN, REGISTRATION_STATE_UNKNOWN, + NetworkRegistrationInfo.DOMAIN_PS, + true, true, 0, 0, "", "", ""); + + DomainSelectionService.SelectionAttributes attr = + EmergencyCallDomainSelectionConnection.getSelectionAttributes( + mPhone.getPhoneId(), mPhone.getSubId(), false, + TELECOM_CALL_ID1, "911", 0, null, regResult); + + mEcDsc.createEmergencyConnection(attr, mConnectionCallback); + mTransportCallback.onSelectionTerminated(ERROR_UNSPECIFIED); + + verify(mConnectionCallback).onSelectionTerminated(eq(ERROR_UNSPECIFIED)); + } +} -- GitLab From ee0755ee1f7c79ed3434db8cc605f7e81fe3beca Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 9 Feb 2022 15:56:41 +0000 Subject: [PATCH 253/656] Notifies IMS registration state to modem Bug: 219242990 Test: atest FrameworksTelephonyTests:ImsPhoneCallTrackerTest#testUpdateImsRegistrationInfo Change-Id: If83a9dbd87ef0a00346e1348affb3aac11347084 --- .../internal/telephony/CommandsInterface.java | 11 +- .../com/android/internal/telephony/RIL.java | 16 +- .../android/internal/telephony/RILUtils.java | 37 ++- .../internal/telephony/imsphone/ImsPhone.java | 110 +++++- .../imsphone/ImsPhoneCallTracker.java | 23 ++ .../ImsRegistrationCallbackHelper.java | 18 +- .../telephony/ims/ImsRegistrationTests.java | 11 +- .../internal/telephony/SimulatedCommands.java | 16 + .../imsphone/ImsPhoneCallTrackerTest.java | 32 ++ .../telephony/imsphone/ImsPhoneTest.java | 313 ++++++++++++++++++ .../ImsRegistrationCallbackHelperTest.java | 14 +- 11 files changed, 574 insertions(+), 27 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 98de4be845..0b89c290de 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -41,6 +41,8 @@ import android.telephony.data.DataProfile; import android.telephony.data.NetworkSliceInfo; import android.telephony.data.TrafficDescriptor; import android.telephony.emergency.EmergencyNumber; +import android.telephony.ims.RegistrationManager; +import android.telephony.ims.stub.ImsRegistrationImplBase; import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; import com.android.internal.telephony.emergency.EmergencyConstants; @@ -2900,13 +2902,14 @@ public interface CommandsInterface { * Updates the IMS registration information to the radio. * * @param state The current IMS registration state. - * @param accessNetworkType The type of underlying radio access network used. - * @param suggestedAction The expected action that modem should perform. + * @param imsRadioTech The type of underlying radio access network used. + * @param suggestedAction The suggested action for the radio to perform. * @param capabilities IMS capabilities such as VOICE, VIDEO and SMS. */ default void updateImsRegistrationInfo(int state, - @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, - int suggestedAction, int capabilities, Message result) {} + @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech, + @RegistrationManager.SuggestedAction int suggestedAction, + int capabilities, Message result) {} /** * Notifies the NAS and RRC layers of the radio the type of upcoming IMS traffic. diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 1a5f393328..3928afe894 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -84,6 +84,8 @@ import android.telephony.data.DataProfile; import android.telephony.data.NetworkSliceInfo; import android.telephony.data.TrafficDescriptor; import android.telephony.emergency.EmergencyNumber; +import android.telephony.ims.RegistrationManager; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.text.TextUtils; import android.util.SparseArray; @@ -5257,8 +5259,11 @@ public class RIL extends BaseCommands implements CommandsInterface { } @Override - public void updateImsRegistrationInfo(int state, - int accessNetworkType, int suggestedAction, int capabilities, Message result) { + public void updateImsRegistrationInfo( + @RegistrationManager.ImsRegistrationState int state, + @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech, + @RegistrationManager.SuggestedAction int suggestedAction, + int capabilities, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { @@ -5266,14 +5271,15 @@ public class RIL extends BaseCommands implements CommandsInterface { mRILDefaultWorkSource); if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " state=" + state + ", radioTech=" + imsRadioTech + + ", suggested=" + suggestedAction + ", cap=" + capabilities); } android.hardware.radio.ims.ImsRegistration registrationInfo = new android.hardware.radio.ims.ImsRegistration(); registrationInfo.regState = RILUtils.convertImsRegistrationState(state); - registrationInfo.accessNetworkType = accessNetworkType; + registrationInfo.accessNetworkType = RILUtils.convertImsRegistrationTech(imsRadioTech); registrationInfo.suggestedAction = suggestedAction; registrationInfo.capabilities = RILUtils.convertImsCapability(capabilities); diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index d8188d86b4..c362d65334 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -5616,7 +5616,12 @@ public class RILUtils { } } - /** Convert IMS registration state */ + /** + * Converts IMS registration state. + * + * @param state The IMS registration state. + * @return The converted HAL IMS registration state. + */ public static int convertImsRegistrationState(int state) { switch (state) { case RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED: @@ -5628,7 +5633,35 @@ public class RILUtils { } } - /** Convert IMS capability */ + /** + * Converts IMS service radio technology. + * + * @param imsRadioTech The IMS service radio technology. + * @return The converted HAL access network type. + */ + + public static int convertImsRegistrationTech( + @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) { + switch (imsRadioTech) { + case ImsRegistrationImplBase.REGISTRATION_TECH_LTE: + return android.hardware.radio.AccessNetwork.EUTRAN; + case ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN: + return android.hardware.radio.AccessNetwork.IWLAN; + case ImsRegistrationImplBase.REGISTRATION_TECH_NR: + return android.hardware.radio.AccessNetwork.NGRAN; + case ImsRegistrationImplBase.REGISTRATION_TECH_3G: + return android.hardware.radio.AccessNetwork.UTRAN; + default: + return android.hardware.radio.AccessNetwork.UNKNOWN; + } + } + + /** + * Converts IMS capabilities. + * + * @param capabilities The IMS capabilities. + * @return The converted HAL IMS capabilities. + */ public static int convertImsCapability(int capabilities) { int halCapabilities = android.hardware.radio.ims.ImsRegistration.IMS_MMTEL_CAPABILITY_NONE; if ((capabilities & CommandsInterface.IMS_MMTEL_CAPABILITY_VOICE) > 0) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 6b2073b239..622cfc354b 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -19,6 +19,12 @@ package com.android.internal.telephony.imsphone; import static android.provider.Telephony.SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS; import static android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE; 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.SUGGESTED_ACTION_NONE; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT; +import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC; import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr; @@ -42,6 +48,7 @@ import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDI import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE; import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; +import android.annotation.NonNull; import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; @@ -79,6 +86,7 @@ import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsCallForwardInfo; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.ImsSsData; import android.telephony.ims.ImsSsInfo; import android.telephony.ims.RegistrationManager; @@ -290,6 +298,14 @@ public class ImsPhone extends ImsPhoneBase { private ImsStats mImsStats; + private int mImsRegistrationState; + // The access network type where IMS is registered + private @ImsRegistrationImplBase.ImsRegistrationTech int mImsRegistrationTech = + REGISTRATION_TECH_NONE; + private @RegistrationManager.SuggestedAction int mImsRegistrationSuggestedAction; + private int mImsRegistrationCapabilities; + private boolean mNotifiedRegisteredState; + // A runnable which is used to automatically exit from Ecm after a period of time. private Runnable mExitEcmRunnable = new Runnable() { @Override @@ -2454,12 +2470,18 @@ public class ImsPhone extends ImsPhoneBase { public void resetImsRegistrationState() { if (DBG) logd("resetImsRegistrationState"); mImsMmTelRegistrationHelper.reset(); + int subId = getSubId(); + if (SubscriptionManager.isValidSubscriptionId(subId)) { + updateImsRegistrationInfo(REGISTRATION_STATE_NOT_REGISTERED, + REGISTRATION_TECH_NONE, SUGGESTED_ACTION_NONE); + } } private ImsRegistrationCallbackHelper.ImsRegistrationUpdate mMmTelRegistrationUpdate = new ImsRegistrationCallbackHelper.ImsRegistrationUpdate() { @Override - public void handleImsRegistered(int imsRadioTech) { + public void handleImsRegistered(@NonNull ImsRegistrationAttributes attributes) { + int imsRadioTech = attributes.getTransportType(); if (DBG) { logd("handleImsRegistered: onImsMmTelConnected imsRadioTech=" + AccessNetworkConstants.transportTypeToString(imsRadioTech)); @@ -2470,6 +2492,8 @@ public class ImsPhone extends ImsPhoneBase { getDefaultPhone().setImsRegistrationState(true); mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.CONNECTED, null); mImsStats.onImsRegistered(imsRadioTech); + updateImsRegistrationInfo(REGISTRATION_STATE_REGISTERED, + attributes.getRegistrationTechnology(), SUGGESTED_ACTION_NONE); } @Override @@ -2488,10 +2512,11 @@ public class ImsPhone extends ImsPhoneBase { } @Override - public void handleImsUnregistered(ImsReasonInfo imsReasonInfo) { + public void handleImsUnregistered(ImsReasonInfo imsReasonInfo, + @RegistrationManager.SuggestedAction int suggestedAction) { if (DBG) { logd("handleImsUnregistered: onImsMmTelDisconnected imsReasonInfo=" - + imsReasonInfo); + + imsReasonInfo + ", suggestedAction=" + suggestedAction); } mRegLocalLog.log("handleImsUnregistered: onImsMmTelDisconnected imsRadioTech=" + imsReasonInfo); @@ -2501,6 +2526,16 @@ public class ImsPhone extends ImsPhoneBase { mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.DISCONNECTED, imsReasonInfo); mImsStats.onImsUnregistered(imsReasonInfo); + mImsRegistrationTech = REGISTRATION_TECH_NONE; + int suggestedModemAction = SUGGESTED_ACTION_NONE; + if (imsReasonInfo.getCode() == ImsReasonInfo.CODE_REGISTRATION_ERROR) { + if ((suggestedAction == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK) + || (suggestedAction == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT)) { + suggestedModemAction = suggestedAction; + } + } + updateImsRegistrationInfo(REGISTRATION_STATE_NOT_REGISTERED, + REGISTRATION_TECH_NONE, suggestedModemAction); } @Override @@ -2633,6 +2668,75 @@ public class ImsPhone extends ImsPhoneBase { return mLastKnownRoamingState; } + /** + * Update IMS registration information to modem. + * + * @param capabilities indicate MMTEL capability such as VOICE, VIDEO and SMS. + */ + public void updateImsRegistrationInfo(int capabilities) { + if (mImsRegistrationState == REGISTRATION_STATE_REGISTERED) { + if (mNotifiedRegisteredState && (capabilities == mImsRegistrationCapabilities)) { + // Duplicated notification, no change in capabilities. + return; + } + + mImsRegistrationCapabilities = capabilities; + if (capabilities == 0) { + // Ignore this as this usually happens just before onUnregistered callback. + // We can notify modem when onUnregistered() flow occurs. + return; + } + + mDefaultPhone.mCi.updateImsRegistrationInfo(mImsRegistrationState, + mImsRegistrationTech, 0, capabilities, null); + mNotifiedRegisteredState = true; + } + } + + /** + * Update IMS registration info + * + * @param regState indicates IMS registration state. + * @param imsRadioTech indicates the type of the radio access network where IMS is registered. + * @param suggestedAction indicates the suggested action for the radio to perform. + */ + private void updateImsRegistrationInfo( + @RegistrationManager.ImsRegistrationState int regState, + @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech, + @RegistrationManager.SuggestedAction int suggestedAction) { + + if (regState == mImsRegistrationState) { + if ((regState == REGISTRATION_STATE_REGISTERED && imsRadioTech == mImsRegistrationTech) + || (regState == REGISTRATION_STATE_NOT_REGISTERED + && suggestedAction == mImsRegistrationSuggestedAction)) { + // Filter duplicate notification. + return; + } + } + + if (regState == REGISTRATION_STATE_NOT_REGISTERED) { + mDefaultPhone.mCi.updateImsRegistrationInfo(regState, + imsRadioTech, suggestedAction, 0, null); + } else if (mImsRegistrationState == REGISTRATION_STATE_REGISTERED) { + // This happens when radio tech is changed while in REGISTERED state. + if (mImsRegistrationCapabilities > 0) { + // Capability has been updated. Notify REGISTRATION_STATE_REGISTERED. + mDefaultPhone.mCi.updateImsRegistrationInfo(regState, imsRadioTech, 0, + mImsRegistrationCapabilities, null); + mImsRegistrationTech = imsRadioTech; + mNotifiedRegisteredState = true; + return; + } + } + + mImsRegistrationState = regState; + mImsRegistrationTech = imsRadioTech; + mImsRegistrationSuggestedAction = suggestedAction; + mImsRegistrationCapabilities = 0; + // REGISTRATION_STATE_REGISTERED will be notified when the capability is updated. + mNotifiedRegisteredState = false; + } + @Override public void setTerminalBasedCallWaitingStatus(int state) { mCT.setTerminalBasedCallWaitingStatus(state); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index eb1f252a22..f085f66b52 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -34,6 +34,9 @@ import static android.telephony.ims.ImsService.CAPABILITY_TERMINAL_BASED_CALL_WA import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import static com.android.internal.telephony.CallWaitingController.TERMINAL_BASED_ACTIVATED; import static com.android.internal.telephony.CallWaitingController.TERMINAL_BASED_NOT_SUPPORTED; +import static com.android.internal.telephony.CommandsInterface.IMS_MMTEL_CAPABILITY_SMS; +import static com.android.internal.telephony.CommandsInterface.IMS_MMTEL_CAPABILITY_VIDEO; +import static com.android.internal.telephony.CommandsInterface.IMS_MMTEL_CAPABILITY_VOICE; import static com.android.internal.telephony.Phone.CS_FALLBACK; import android.Manifest; @@ -4551,6 +4554,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { try { ImsFeature.Capabilities capabilities = (ImsFeature.Capabilities) args.arg1; handleFeatureCapabilityChanged(capabilities); + updateImsRegistrationInfo(); } finally { args.recycle(); } @@ -5747,4 +5751,23 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { loge("triggerImsDeregistration: exception " + e); } } + + private void updateImsRegistrationInfo() { + int capabilities = 0; + + if (mMmTelCapabilities.isCapable( + MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE)) { + capabilities |= IMS_MMTEL_CAPABILITY_VOICE; + } + if (mMmTelCapabilities.isCapable( + MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO)) { + capabilities |= IMS_MMTEL_CAPABILITY_VIDEO; + } + if (mMmTelCapabilities.isCapable( + MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS)) { + capabilities |= IMS_MMTEL_CAPABILITY_SMS; + } + + mPhone.updateImsRegistrationInfo(capabilities); + } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java b/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java index 115f6fe43b..fae9e23222 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java @@ -20,6 +20,7 @@ import android.annotation.AnyThread; import android.annotation.NonNull; import android.net.Uri; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RegistrationManager; import android.telephony.ims.aidl.IImsRegistrationCallback; import android.util.Log; @@ -40,7 +41,7 @@ public class ImsRegistrationCallbackHelper { /** * Handle the callback when IMS is registered. */ - void handleImsRegistered(int imsRadioTech); + void handleImsRegistered(@NonNull ImsRegistrationAttributes attributes); /** * Handle the callback when IMS is registering. @@ -50,7 +51,8 @@ public class ImsRegistrationCallbackHelper { /** * Handle the callback when IMS is unregistered. */ - void handleImsUnregistered(ImsReasonInfo imsReasonInfo); + void handleImsUnregistered(ImsReasonInfo imsReasonInfo, + @RegistrationManager.SuggestedAction int suggestedAction); /** * Handle the callback when the list of subscriber {@link Uri}s associated with this IMS @@ -66,9 +68,9 @@ public class ImsRegistrationCallbackHelper { private final RegistrationManager.RegistrationCallback mImsRegistrationCallback = new RegistrationManager.RegistrationCallback() { @Override - public void onRegistered(int imsRadioTech) { + public void onRegistered(@NonNull ImsRegistrationAttributes attributes) { updateRegistrationState(RegistrationManager.REGISTRATION_STATE_REGISTERED); - mImsRegistrationUpdate.handleImsRegistered(imsRadioTech); + mImsRegistrationUpdate.handleImsRegistered(attributes); } @Override @@ -79,8 +81,14 @@ public class ImsRegistrationCallbackHelper { @Override public void onUnregistered(ImsReasonInfo imsReasonInfo) { + onUnregistered(imsReasonInfo, RegistrationManager.SUGGESTED_ACTION_NONE); + } + + @Override + public void onUnregistered(ImsReasonInfo imsReasonInfo, + @RegistrationManager.SuggestedAction int suggestedAction) { updateRegistrationState(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED); - mImsRegistrationUpdate.handleImsUnregistered(imsReasonInfo); + mImsRegistrationUpdate.handleImsUnregistered(imsReasonInfo, suggestedAction); } @Override diff --git a/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java b/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java index af80bd778d..1ab4efed05 100644 --- a/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java +++ b/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java @@ -19,6 +19,7 @@ package android.telephony.ims; import static junit.framework.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -147,7 +148,7 @@ public class ImsRegistrationTests { ImsReasonInfo info = new ImsReasonInfo(); mRegistration.onDeregistered(info); - verify(mCallback).onDeregistered(eq(info)); + verify(mCallback).onDeregistered(eq(info), anyInt()); } @SmallTest @@ -218,10 +219,10 @@ public class ImsRegistrationTests { // The original callback that has been registered should get LTE tech in disconnected // message - verify(mCallback).onDeregistered(eq(info)); + verify(mCallback).onDeregistered(eq(info), anyInt()); // A callback that has just been registered should get NONE for tech in disconnected // message - verify(mCallback2).onDeregistered(eq(info)); + verify(mCallback2).onDeregistered(eq(info), anyInt()); } @SmallTest @@ -231,7 +232,7 @@ public class ImsRegistrationTests { mRegistration.onDeregistered(info); - verify(mCallback).onDeregistered(eq(info)); + verify(mCallback).onDeregistered(eq(info), anyInt()); assertEquals(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, mRegBinder.getRegistrationTechnology()); } @@ -242,7 +243,7 @@ public class ImsRegistrationTests { mRegBinder.addRegistrationCallback(mCallback2); // Verify that if we have never set the registration state, we do not callback immediately // with onUnregistered. - verify(mCallback2, never()).onDeregistered(any(ImsReasonInfo.class)); + verify(mCallback2, never()).onDeregistered(any(ImsReasonInfo.class), anyInt()); } @SmallTest diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index e9b644f8ae..9d00ed7b50 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -192,6 +192,9 @@ public class SimulatedCommands extends BaseCommands // mode for Icc Sim Authentication private int mAuthenticationMode; + + private int[] mImsRegistrationInfo = new int[4]; + //***** Constructor public SimulatedCommands() { @@ -2583,4 +2586,17 @@ public class SimulatedCommands extends BaseCommands public SrvccConnection[] getSrvccConnections() { return mSrvccConnections; } + + @Override + public void updateImsRegistrationInfo(int regState, + int imsRadioTech, int suggestedAction, int capabilities, Message result) { + mImsRegistrationInfo[0] = regState; + mImsRegistrationInfo[1] = imsRadioTech; + mImsRegistrationInfo[2] = suggestedAction; + mImsRegistrationInfo[3] = capabilities; + } + + public int[] getImsRegistrationInfo() { + return mImsRegistrationInfo; + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 23de7df755..9bdee13615 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -2316,6 +2316,38 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { assertEquals("5678", srvccConnections[1].getNumber()); } + /** + * Verifies that the expected access network tech and IMS features are notified + * to ImsPhone when capabilities are changed. + */ + @Test + @SmallTest + public void testUpdateImsRegistrationInfo() { + // LTE is registered. + doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_LTE).when( + mImsManager).getRegistrationTech(); + + // enable Voice and Video + MmTelFeature.MmTelCapabilities caps = new MmTelFeature.MmTelCapabilities(); + caps.addCapabilities(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE); + caps.addCapabilities(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO); + mCapabilityCallback.onCapabilitiesStatusChanged(caps); + processAllMessages(); + + verify(mImsPhone, times(1)).updateImsRegistrationInfo( + eq(CommandsInterface.IMS_MMTEL_CAPABILITY_VOICE + | CommandsInterface.IMS_MMTEL_CAPABILITY_VIDEO)); + + // enable SMS + caps = new MmTelFeature.MmTelCapabilities(); + caps.addCapabilities(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS); + mCapabilityCallback.onCapabilitiesStatusChanged(caps); + processAllMessages(); + + verify(mImsPhone, times(1)).updateImsRegistrationInfo( + eq(CommandsInterface.IMS_MMTEL_CAPABILITY_SMS)); + } + private void sendCarrierConfigChanged() { Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); 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 17a63ddfce..468c5dd77b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -22,9 +22,20 @@ import static android.telephony.CarrierConfigManager.USSD_OVER_CS_ONLY; import static android.telephony.CarrierConfigManager.USSD_OVER_CS_PREFERRED; import static android.telephony.CarrierConfigManager.USSD_OVER_IMS_ONLY; import static android.telephony.CarrierConfigManager.USSD_OVER_IMS_PREFERRED; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_NONE; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT; +import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_3G; +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 android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR; import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.IMS_MMTEL_CAPABILITY_SMS; +import static com.android.internal.telephony.CommandsInterface.IMS_MMTEL_CAPABILITY_VIDEO; +import static com.android.internal.telephony.CommandsInterface.IMS_MMTEL_CAPABILITY_VOICE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -65,6 +76,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RegistrationManager; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsUtImplBase; @@ -1068,6 +1080,307 @@ public class ImsPhoneTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(""); } + /** + * Verifies that valid radio technology is passed to RIL + * when IMS registration state changes to registered. + */ + @Test + @SmallTest + public void testUpdateImsRegistrationInfoRadioTech() { + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + + int[] regInfo = mSimulatedCommands.getImsRegistrationInfo(); + assertNotNull(regInfo); + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + RegistrationManager.RegistrationCallback registrationCallback = + mImsPhoneUT.getImsMmTelRegistrationCallback(); + + ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder( + REGISTRATION_TECH_LTE).build(); + registrationCallback.onRegistered(attr); + mImsPhoneUT.updateImsRegistrationInfo(IMS_MMTEL_CAPABILITY_VOICE); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_REGISTERED + && regInfo[1] == REGISTRATION_TECH_LTE + && regInfo[3] == IMS_MMTEL_CAPABILITY_VOICE); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // duplicated notification with the same radio technology + attr = new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_LTE).build(); + registrationCallback.onRegistered(attr); + + // verify that there is no change in SimulatedCommands + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // radio technology changed + attr = new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_NR).build(); + registrationCallback.onRegistered(attr); + + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_REGISTERED + && regInfo[1] == REGISTRATION_TECH_NR + && regInfo[3] == IMS_MMTEL_CAPABILITY_VOICE); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // duplicated notification with the same radio technology + attr = new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_NR).build(); + registrationCallback.onRegistered(attr); + + // verify that there is no change in SimulatedCommands + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // radio technology changed + attr = new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_IWLAN).build(); + registrationCallback.onRegistered(attr); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_REGISTERED + && regInfo[1] == REGISTRATION_TECH_IWLAN + && regInfo[3] == IMS_MMTEL_CAPABILITY_VOICE); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // duplicated notification with the same radio technology + attr = new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_IWLAN).build(); + registrationCallback.onRegistered(attr); + + // verify that there is no change in SimulatedCommands + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // radio technology changed + attr = new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_3G).build(); + registrationCallback.onRegistered(attr); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_REGISTERED + && regInfo[1] == REGISTRATION_TECH_3G + && regInfo[3] == IMS_MMTEL_CAPABILITY_VOICE); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // duplicated notification with the same radio technology + attr = new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_3G).build(); + registrationCallback.onRegistered(attr); + + // verify that there is no change in SimulatedCommands + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + } + + /** + * Verifies that valid capabilities is passed to RIL + * when IMS registration state changes to registered. + */ + @Test + @SmallTest + public void testUpdateImsRegistrationInfoCapabilities() { + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + + int[] regInfo = mSimulatedCommands.getImsRegistrationInfo(); + assertNotNull(regInfo); + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + RegistrationManager.RegistrationCallback registrationCallback = + mImsPhoneUT.getImsMmTelRegistrationCallback(); + + ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder( + REGISTRATION_TECH_LTE).build(); + registrationCallback.onRegistered(attr); + mImsPhoneUT.updateImsRegistrationInfo(IMS_MMTEL_CAPABILITY_VOICE); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_REGISTERED + && regInfo[1] == REGISTRATION_TECH_LTE + && regInfo[3] == IMS_MMTEL_CAPABILITY_VOICE); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // duplicated notification with the same capability + mImsPhoneUT.updateImsRegistrationInfo(IMS_MMTEL_CAPABILITY_VOICE); + + // verify that there is no change in SimulatedCommands + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // capability changed + mImsPhoneUT.updateImsRegistrationInfo(IMS_MMTEL_CAPABILITY_VIDEO); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_REGISTERED + && regInfo[1] == REGISTRATION_TECH_LTE + && regInfo[3] == IMS_MMTEL_CAPABILITY_VIDEO); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // duplicated notification with the same capability + mImsPhoneUT.updateImsRegistrationInfo(IMS_MMTEL_CAPABILITY_VIDEO); + + // verify that there is no change in SimulatedCommands + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // capability changed + mImsPhoneUT.updateImsRegistrationInfo(IMS_MMTEL_CAPABILITY_SMS); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_REGISTERED + && regInfo[1] == REGISTRATION_TECH_LTE + && regInfo[3] == IMS_MMTEL_CAPABILITY_SMS); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // duplicated notification with the same capability + mImsPhoneUT.updateImsRegistrationInfo(IMS_MMTEL_CAPABILITY_SMS); + + // verify that there is no change in SimulatedCommands + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + + // capability changed, but no capability + mImsPhoneUT.updateImsRegistrationInfo(IMS_MMTEL_CAPABILITY_SMS); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + // verify that there is no change in SimulatedCommands. + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[3] == 0); + } + + /** + * Verifies that valid state and reason is passed to RIL + * when IMS registration state changes to unregistered. + */ + @Test + @SmallTest + public void testUpdateImsRegistrationInfo() { + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + + int[] regInfo = mSimulatedCommands.getImsRegistrationInfo(); + assertNotNull(regInfo); + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + + RegistrationManager.RegistrationCallback registrationCallback = + mImsPhoneUT.getImsMmTelRegistrationCallback(); + + ImsReasonInfo reasonInfo = new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, + ImsReasonInfo.CODE_UNSPECIFIED, ""); + + // unregistered with fatal error + registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_NONE + && regInfo[2] == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + + // duplicated notification with the same suggested action + registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + // verify that there is no update in the SimulatedCommands + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + + // unregistered with repeated error + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_NONE + && regInfo[2] == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + + // duplicated notification with the same suggested action + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + // verify that there is no update in the SimulatedCommands + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + + // unregistered with temporary error + registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_NONE); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_NONE + && regInfo[2] == SUGGESTED_ACTION_NONE); + + // verifies that reason codes except ImsReasonInfo.CODE_REGISTRATION_ERROR are discarded. + reasonInfo = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_SERVICE, + ImsReasonInfo.CODE_UNSPECIFIED, ""); + registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_NONE + && regInfo[2] == SUGGESTED_ACTION_NONE); + + // change the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(1, 1, 1, 1, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 1 && regInfo[1] == 1 && regInfo[2] == 1); + + // duplicated notification with the same suggested action + registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_NONE); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + // verify that there is no update in the SimulatedCommands + assertTrue(regInfo[0] == 1 && regInfo[1] == 1 && regInfo[2] == 1); + } + private ServiceState getServiceStateDataAndVoice(int rat, int regState, boolean isRoaming) { ServiceState ss = new ServiceState(); ss.setStateOutOfService(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java index cce064673b..24efda6a89 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java @@ -16,10 +16,13 @@ package com.android.internal.telephony.imsphone; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_NONE; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -27,8 +30,10 @@ import static org.mockito.Mockito.verify; import android.net.Uri; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RegistrationManager; import android.telephony.ims.RegistrationManager.RegistrationCallback; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.TelephonyTest; @@ -121,11 +126,13 @@ public class ImsRegistrationCallbackHelperTest extends TelephonyTest { // When onRegistered is called, the registration state should be // REGISTRATION_STATE_REGISTERED - callback.onRegistered(AccessNetworkType.IWLAN); + ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder( + ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN).build(); + callback.onRegistered(attr); assertEquals(RegistrationManager.REGISTRATION_STATE_REGISTERED, mRegistrationCallbackHelper.getImsRegistrationState()); - verify(mMockRegistrationUpdate).handleImsRegistered(anyInt()); + verify(mMockRegistrationUpdate).handleImsRegistered(attr); } @Test @@ -158,7 +165,8 @@ public class ImsRegistrationCallbackHelperTest extends TelephonyTest { // The registration state should be REGISTRATION_STATE_NOT_REGISTERED assertEquals(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED, mRegistrationCallbackHelper.getImsRegistrationState()); - verify(mMockRegistrationUpdate).handleImsUnregistered(reasonInfo); + verify(mMockRegistrationUpdate).handleImsUnregistered(eq(reasonInfo), + eq(SUGGESTED_ACTION_NONE)); } @Test -- GitLab From d3c79fd812a0ec4ece64d5c6d6e32c0ba1c5e9bc Mon Sep 17 00:00:00 2001 From: Gil Cukierman Date: Wed, 7 Dec 2022 22:46:00 +0000 Subject: [PATCH 254/656] Update Null Cipher Enabled on Radio Available Adds a new handling method on Phone that is overriden by GsmCdmaPhone to handle requests for updates to the SharedPreference that backs the null cipher enablement API. The GsmCdmaPhone handles calling the handler on modem availability which covers a reboot of the device or a restart of the modem after crashes. Test: atest GsmCdmaPhoneTest Bug: 260844152 Change-Id: Ifaa70998d551c9fb7545211f725c51fad06ea80a --- .../internal/telephony/CommandsInterface.java | 4 +-- .../internal/telephony/GsmCdmaPhone.java | 11 ++++++ .../com/android/internal/telephony/Phone.java | 34 ++++++++++++------- .../com/android/internal/telephony/RIL.java | 2 +- .../internal/telephony/GsmCdmaPhoneTest.java | 14 ++++++-- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 98de4be845..ccd70036d5 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2946,9 +2946,9 @@ public interface CommandsInterface { * Set the UE's ability to accept/reject null ciphered and/or null integrity-protected * connections. * - * @param result Callback message containing the success or failure status. * @param enabled true to allow null ciphered and/or null integrity-protected connections, * false to disallow. + * @param result Callback message containing the success or failure status. */ - default void setNullCipherAndIntegrityEnabled(Message result, boolean enabled) {} + default void setNullCipherAndIntegrityEnabled(boolean enabled, Message result) {} } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 0fc9d59d6c..c4c7a5582f 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -2924,6 +2924,7 @@ public class GsmCdmaPhone extends Phone { mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY)); mCi.areUiccApplicationsEnabled(obtainMessage(EVENT_GET_UICC_APPS_ENABLEMENT_DONE)); + handleNullCipherEnabledChange(); startLceAfterRadioIsAvailable(); } @@ -3378,6 +3379,9 @@ public class GsmCdmaPhone extends Phone { logd("EVENT_SUBSCRIPTIONS_CHANGED"); updateUsageSetting(); break; + case EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE: + logd("EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE"); + break; case EVENT_IMS_DEREGISTRATION_TRIGGERED: logd("EVENT_IMS_DEREGISTRATION_TRIGGERED"); @@ -4914,4 +4918,11 @@ public class GsmCdmaPhone extends Phone { ArrayList controlStrings = GsmMmiCode.getControlStrings(requestType, serviceType); return FdnUtils.isSuppServiceRequestBlockedByFdn(mPhoneId, controlStrings, getCountryIso()); } + + @Override + public void handleNullCipherEnabledChange() { + mCi.setNullCipherAndIntegrityEnabled( + getNullCipherAndIntegrityEnabledPreference(), + obtainMessage(EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE)); + } } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index ab814837ea..e6cffa9c29 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -239,8 +239,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected static final int EVENT_GET_USAGE_SETTING_DONE = 63; protected static final int EVENT_SET_USAGE_SETTING_DONE = 64; protected static final int EVENT_IMS_DEREGISTRATION_TRIGGERED = 65; + protected static final int EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE = 66; - protected static final int EVENT_LAST = EVENT_IMS_DEREGISTRATION_TRIGGERED; + protected static final int EVENT_LAST = EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE; // For shared prefs. private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_"; @@ -267,6 +268,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // Integer used to let the calling application know that the we are ignoring auto mode switch. private static final int ALREADY_IN_AUTO_SELECTION = 1; + public static final String PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED = + "pref_null_cipher_and_integrity_enabled"; + /** * This method is invoked when the Phone exits Emergency Callback Mode. */ @@ -4994,18 +4998,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.unregisterForEmergencyNetworkScan(h); } - /** - * Set the UE's ability to accept/reject null ciphered and/or null integrity-protected - * connections. - * - * @param result Callback message. - * @param enabled true to allow null ciphered and/or null integrity-protected connections, - * false to disallow. - */ - public void setNullCipherAndIntegrityEnabled(@Nullable Message result, boolean enabled) { - mCi.setNullCipherAndIntegrityEnabled(result, enabled); - } - /** * Notifies that IMS deregistration is triggered. * @@ -5044,6 +5036,22 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { : null; } + /** + * @return global null cipher and integrity enabled preference + */ + public boolean getNullCipherAndIntegrityEnabledPreference() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + return sp.getBoolean(PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED, true); + } + + /** + * Override to implement handling of an update to the enablement of the null cipher and + * integrity preference. + * {@see #PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED} + */ + public void handleNullCipherEnabledChange() { + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 1a5f393328..6dd772ed50 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5555,7 +5555,7 @@ public class RIL extends BaseCommands implements CommandsInterface { * @param enabled true if null ciphering / null integrity modes are permitted, false otherwise */ @Override - public void setNullCipherAndIntegrityEnabled(Message result, boolean enabled) { + public void setNullCipherAndIntegrityEnabled(boolean enabled, Message result) { RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); if (networkProxy.isEmpty()) return; if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 3222c310b5..97c56ac46c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -20,6 +20,7 @@ import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED; import static com.android.internal.telephony.Phone.EVENT_IMS_DEREGISTRATION_TRIGGERED; +import static com.android.internal.telephony.Phone.EVENT_RADIO_AVAILABLE; import static com.android.internal.telephony.Phone.EVENT_SRVCC_STATE_CHANGED; import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; @@ -2044,7 +2045,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { } @Test - public void testDial_fdnCheck() throws Exception{ + public void testDial_fdnCheck() throws Exception { // dial setup mSST.mSS = mServiceState; doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState(); @@ -2072,7 +2073,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { connection = mPhoneUT.dial("1234567890", new PhoneInternalInterface.DialArgs.Builder().build()); fail("Expected CallStateException with ERROR_FDN_BLOCKED thrown."); - } catch(CallStateException e) { + } catch (CallStateException e) { assertEquals(CallStateException.ERROR_FDN_BLOCKED, e.getError()); } @@ -2080,6 +2081,15 @@ public class GsmCdmaPhoneTest extends TelephonyTest { fdnCheckCleanup(); } + @Test + public void testHandleNullCipherAndIntegrityEnabledOnRadioAvailable() { + GsmCdmaPhone spiedPhone = spy(mPhoneUT); + spiedPhone.sendMessage(spiedPhone.obtainMessage(EVENT_RADIO_AVAILABLE, + new AsyncResult(null, new int[]{ServiceState.RIL_RADIO_TECHNOLOGY_GSM}, null))); + processAllMessages(); + verify(spiedPhone, times(1)).handleNullCipherEnabledChange(); + } + public void fdnCheckCleanup() { doReturn(false).when(mUiccCardApplication3gpp).getIccFdnAvailable(); doReturn(false).when(mUiccCardApplication3gpp).getIccFdnEnabled(); -- GitLab From 61eeb3e56cc488c8dcd7b165acda425bc7e4d222 Mon Sep 17 00:00:00 2001 From: Kiwon Park Date: Tue, 22 Nov 2022 13:17:23 -0800 Subject: [PATCH 255/656] Collect isInternetPdnUp in CellularServiceState Bug: 256178417 Test: manually inspect atoms Change-Id: I3c95fc8dd18668a9d3a33262718dc7378324e876 --- proto/src/persist_atoms.proto | 1 + .../internal/telephony/GsmCdmaPhone.java | 1 + .../telephony/metrics/MetricsCollector.java | 3 +- .../metrics/PersistAtomsStorage.java | 3 +- .../telephony/metrics/ServiceStateStats.java | 58 ++++++++++-- .../internal/telephony/TelephonyTest.java | 4 + .../metrics/ServiceStateStatsTest.java | 90 ++++++++++++++++++- 7 files changed, 148 insertions(+), 12 deletions(-) diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index 1b4f56531a..e33cdda9e6 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -330,6 +330,7 @@ message CellularServiceState { optional int32 carrier_id = 8; optional int64 total_time_millis = 9; // Duration needs to be rounded when pulled optional bool is_emergency_only = 10; + optional bool is_internet_pdn_up = 11; // Internal use only optional int64 last_used_millis = 10001; diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index e7a9f0b4ed..6a0e89dace 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -345,6 +345,7 @@ public class GsmCdmaPhone extends Phone { mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, null); + mSST.getServiceStateStats().registerDataNetworkControllerCallback(); if (isSubscriptionManagerServiceEnabled()) { mSubscriptionManagerService.registerCallback(new SubscriptionManagerServiceCallback( diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 8a0cd48fbf..d30942f215 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -749,7 +749,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { state.isMultiSim, state.carrierId, roundAndConvertMillisToSeconds(state.totalTimeMillis), - state.isEmergencyOnly); + state.isEmergencyOnly, + state.isInternetPdnUp); } private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) { diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java index d1a60e8122..f92071f8e8 100644 --- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java +++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java @@ -1466,7 +1466,8 @@ public class PersistAtomsStorage { && state.simSlotIndex == key.simSlotIndex && state.isMultiSim == key.isMultiSim && state.carrierId == key.carrierId - && state.isEmergencyOnly == key.isEmergencyOnly) { + && state.isEmergencyOnly == key.isEmergencyOnly + && state.isInternetPdnUp == key.isInternetPdnUp) { return state; } } diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java index 9d9088eee1..5b78685701 100644 --- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java +++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java @@ -15,7 +15,13 @@ */ package com.android.internal.telephony.metrics; +import static android.telephony.TelephonyManager.DATA_CONNECTED; +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 android.annotation.NonNull; import android.annotation.Nullable; import android.os.SystemClock; import android.telephony.AccessNetworkConstants; @@ -24,24 +30,24 @@ import android.telephony.Annotation.NetworkType; import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.TelephonyManager; - -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 android.telephony.data.DataProfile; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.data.DataNetworkController; +import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch; import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState; import com.android.telephony.Rlog; +import java.util.List; import java.util.concurrent.atomic.AtomicReference; /** Tracks service state duration and switch metrics for each phone. */ -public class ServiceStateStats { +public class ServiceStateStats extends DataNetworkControllerCallback { private static final String TAG = ServiceStateStats.class.getSimpleName(); private final AtomicReference mLastState = @@ -50,6 +56,7 @@ public class ServiceStateStats { private final PersistAtomsStorage mStorage; public ServiceStateStats(Phone phone) { + super(Runnable::run); mPhone = phone; mStorage = PhoneFactory.getMetricsCollector().getAtomsStorage(); } @@ -80,6 +87,21 @@ public class ServiceStateStats { addServiceState(lastState, now); } + /** Registers for internet pdn connected callback. */ + public void registerDataNetworkControllerCallback() { + mPhone.getDataNetworkController().registerDataNetworkControllerCallback(this); + } + + /** Updates service state when internet pdn gets connected. */ + public void onInternetDataNetworkConnected(@NonNull List dataProfiles) { + onInternetDataNetworkChanged(true); + } + + /** Updates service state when internet pdn gets disconnected. */ + public void onInternetDataNetworkDisconnected() { + onInternetDataNetworkChanged(false); + } + /** Updates the current service state. */ public void onServiceStateChanged(ServiceState serviceState) { final long now = getTimeMillis(); @@ -97,7 +119,7 @@ public class ServiceStateStats { newState.isMultiSim = SimSlotState.isMultiSim(); newState.carrierId = mPhone.getCarrierId(); newState.isEmergencyOnly = isEmergencyOnly(serviceState); - + newState.isInternetPdnUp = isInternetPdnUp(mPhone); TimestampedServiceState prevState = mLastState.getAndSet(new TimestampedServiceState(newState, now)); addServiceStateAndSwitch( @@ -224,6 +246,7 @@ public class ServiceStateStats { copy.carrierId = state.carrierId; copy.totalTimeMillis = state.totalTimeMillis; copy.isEmergencyOnly = state.isEmergencyOnly; + copy.isInternetPdnUp = state.isInternetPdnUp; return copy; } @@ -310,6 +333,29 @@ public class ServiceStateStats { || nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED; } + private static boolean isInternetPdnUp(Phone phone) { + DataNetworkController dataNetworkController = phone.getDataNetworkController(); + if (dataNetworkController != null) { + return dataNetworkController.getInternetDataNetworkState() == DATA_CONNECTED; + } + return false; + } + + private void onInternetDataNetworkChanged(boolean internetPdnUp) { + final long now = getTimeMillis(); + TimestampedServiceState lastState = + mLastState.getAndUpdate( + state -> { + if (state.mServiceState == null) { + return new TimestampedServiceState(null, now); + } + CellularServiceState newServiceState = copyOf(state.mServiceState); + newServiceState.isInternetPdnUp = internetPdnUp; + return new TimestampedServiceState(newServiceState, now); + }); + addServiceState(lastState, now); + } + @VisibleForTesting protected long getTimeMillis() { return SystemClock.elapsedRealtime(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 93c671ea9b..09b7c10dbc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -111,6 +111,7 @@ import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.metrics.ImsStats; import com.android.internal.telephony.metrics.MetricsCollector; import com.android.internal.telephony.metrics.PersistAtomsStorage; +import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.SmsStats; import com.android.internal.telephony.metrics.VoiceCallSessionStats; import com.android.internal.telephony.test.SimulatedCommands; @@ -261,6 +262,7 @@ public abstract class TelephonyTest { protected CellLocation mCellLocation; protected DataServiceManager mMockedWwanDataServiceManager; protected DataServiceManager mMockedWlanDataServiceManager; + protected ServiceStateStats mServiceStateStats; // Initialized classes protected ActivityManager mActivityManager; @@ -491,6 +493,7 @@ public abstract class TelephonyTest { mCellLocation = Mockito.mock(CellLocation.class); mMockedWwanDataServiceManager = Mockito.mock(DataServiceManager.class); mMockedWlanDataServiceManager = Mockito.mock(DataServiceManager.class); + mServiceStateStats = Mockito.mock(ServiceStateStats.class); TelephonyManager.disableServiceHandleCaching(); PropertyInvalidatedCache.disableForTestMode(); @@ -710,6 +713,7 @@ public abstract class TelephonyTest { doReturn(TelephonyManager.PHONE_TYPE_GSM).when(mTelephonyManager).getPhoneType(); doReturn(mServiceState).when(mSST).getServiceState(); + doReturn(mServiceStateStats).when(mSST).getServiceStateStats(); mSST.mSS = mServiceState; mSST.mRestrictedState = mRestrictedState; mServiceManagerMockedServices.put("connectivity_metrics_logger", mConnMetLoggerBinder); diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java index 8406bc5cba..8885aa4f59 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java @@ -16,6 +16,13 @@ package com.android.internal.telephony.metrics; +import static android.telephony.TelephonyManager.DATA_CONNECTED; +import static android.telephony.TelephonyManager.DATA_UNKNOWN; + +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 org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; @@ -35,10 +42,6 @@ import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; -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 com.android.internal.telephony.Phone; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch; @@ -109,6 +112,9 @@ public class ServiceStateStatsTest extends TelephonyTest { mockWwanPsRat(TelephonyManager.NETWORK_TYPE_LTE); doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mImsStats).getImsVoiceRadioTech(); + doReturn(DATA_CONNECTED).when(mDataNetworkController).getInternetDataNetworkState(); + doReturn(mDataNetworkController).when(mSecondPhone).getDataNetworkController(); + mServiceStateStats = new TestableServiceStateStats(mPhone); } @@ -143,6 +149,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -155,6 +162,7 @@ public class ServiceStateStatsTest extends TelephonyTest { doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getDataNetworkType(); mockWwanCsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); + doReturn(DATA_UNKNOWN).when(mDataNetworkController).getInternetDataNetworkState(); mServiceStateStats.onServiceStateChanged(mServiceState); mServiceStateStats.incTimeMillis(100L); @@ -176,6 +184,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(false, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -221,6 +230,7 @@ public class ServiceStateStatsTest extends TelephonyTest { doReturn(CardState.CARDSTATE_ABSENT).when(mPhysicalSlot0).getCardState(); mockLimitedService(TelephonyManager.NETWORK_TYPE_UMTS); doReturn(-1).when(mPhone).getCarrierId(); + doReturn(DATA_UNKNOWN).when(mDataNetworkController).getInternetDataNetworkState(); mServiceStateStats.onServiceStateChanged(mServiceState); mServiceStateStats.incTimeMillis(100L); @@ -242,6 +252,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(-1, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(true, state.isEmergencyOnly); + assertEquals(false, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -256,6 +267,7 @@ public class ServiceStateStatsTest extends TelephonyTest { mockWwanCsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); doReturn(-1).when(mPhone).getCarrierId(); + doReturn(DATA_UNKNOWN).when(mDataNetworkController).getInternetDataNetworkState(); mServiceStateStats.onServiceStateChanged(mServiceState); mServiceStateStats.incTimeMillis(100L); @@ -277,6 +289,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(-1, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(false, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -308,6 +321,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -319,6 +333,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -355,6 +370,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat); @@ -366,6 +382,50 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + @SmallTest + public void onInternetDataNetworkDisconnected() throws Exception { + // Using default service state for LTE + mServiceStateStats.onServiceStateChanged(mServiceState); + + mServiceStateStats.incTimeMillis(100L); + mServiceStateStats.onInternetDataNetworkDisconnected(); + mServiceStateStats.incTimeMillis(200L); + mServiceStateStats.conclude(); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(CellularServiceState.class); + verify(mPersistAtomsStorage, times(2)) + .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null)); + assertNotSame(captor.getAllValues().get(0), captor.getAllValues().get(1)); + CellularServiceState state = captor.getAllValues().get(0); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); + assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.voiceRoamingType); + assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.dataRoamingType); + assertFalse(state.isEndc); + assertEquals(0, state.simSlotIndex); + assertFalse(state.isMultiSim); + assertEquals(CARRIER1_ID, state.carrierId); + assertEquals(100L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); + state = captor.getAllValues().get(1); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); + assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); + assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.voiceRoamingType); + assertEquals(ServiceState.ROAMING_TYPE_NOT_ROAMING, state.dataRoamingType); + assertFalse(state.isEndc); + assertEquals(0, state.simSlotIndex); + assertFalse(state.isMultiSim); + assertEquals(CARRIER1_ID, state.carrierId); + assertEquals(200L, state.totalTimeMillis); + assertEquals(false, state.isEmergencyOnly); + assertEquals(false, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -394,6 +454,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -431,6 +492,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = serviceStateCaptor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -442,6 +504,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); CellularDataServiceSwitch serviceSwitch = serviceSwitchCaptor.getAllValues().get(0); assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, serviceSwitch.ratFrom); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, serviceSwitch.ratTo); @@ -482,6 +545,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(true, state.isInternetPdnUp); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_IWLAN, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -492,6 +556,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertFalse(state.isMultiSim); assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); + assertEquals(true, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -520,6 +585,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(0L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -560,6 +626,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -571,6 +638,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = captor.getAllValues().get(2); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -582,6 +650,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(400L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = captor.getAllValues().get(3); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -593,6 +662,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(800L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -637,6 +707,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UNKNOWN, state.dataRat); @@ -648,6 +719,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(-1, state.carrierId); assertEquals(5000L, state.totalTimeMillis); assertEquals(true, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = captor.getAllValues().get(2); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -659,6 +731,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER2_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } @@ -703,6 +776,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = serviceStateCaptor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat); @@ -714,6 +788,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = serviceStateCaptor.getAllValues().get(2); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat); @@ -725,6 +800,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(400L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); CellularDataServiceSwitch serviceSwitch = serviceSwitchCaptor.getAllValues().get(0); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, serviceSwitch.ratFrom); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, serviceSwitch.ratTo); @@ -781,6 +857,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = serviceStateCaptor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -792,6 +869,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = serviceStateCaptor.getAllValues().get(2); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat); @@ -803,6 +881,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = serviceStateCaptor.getAllValues().get(3); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, state.dataRat); @@ -814,6 +893,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); CellularDataServiceSwitch serviceSwitch = serviceSwitchCaptor.getAllValues().get(0); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, serviceSwitch.ratFrom); assertEquals(TelephonyManager.NETWORK_TYPE_UMTS, serviceSwitch.ratTo); @@ -874,6 +954,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(100L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); state = captor.getAllValues().get(1); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.voiceRat); assertEquals(TelephonyManager.NETWORK_TYPE_LTE, state.dataRat); @@ -885,6 +966,7 @@ public class ServiceStateStatsTest extends TelephonyTest { assertEquals(CARRIER1_ID, state.carrierId); assertEquals(200L, state.totalTimeMillis); assertEquals(false, state.isEmergencyOnly); + assertEquals(true, state.isInternetPdnUp); verifyNoMoreInteractions(mPersistAtomsStorage); } -- GitLab From 3536b944c16a483232280cf0a0045a7a60f94a86 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 22 Nov 2022 21:34:18 -0800 Subject: [PATCH 256/656] Skip switch data if cross-sim call active The change is to fix 1) If data is currently temporarily on nDDS due to a voice call just ended, and at the same time a cross-SIM incoming call, the expected behavior is to keep data on nDDS until the cross-SIM call on DDS ends. The previous behavior is that since nDDS voice call ends and the cross-SIM call is ignored as a voice call, we would switch data to the cross-SIM call-ongoing DDS. 2) If a call is on VoWifi(IWLAN/cross-SIM), mPhoneIdInVoiceCall should still be updated because it seems also used by some emergency call check. Test: atest + setup DSDS, placing call on nDDS and observe data switched to nDDS; receiving call on DDS, hang up nDDS call, observing data stays on nDDS until the call on DDS ends. Fix: 249617164 Change-Id: Ib0fe315f886b20831c1b7a6fa29c7365aaddc3d8 --- .../telephony/data/PhoneSwitcher.java | 121 ++++++++---------- .../telephony/data/PhoneSwitcherTest.java | 25 +++- 2 files changed, 71 insertions(+), 75 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 4262436ab4..e32bb31cf2 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -74,6 +74,7 @@ import android.telephony.ims.RegistrationManager; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.ArrayMap; import android.util.LocalLog; +import android.util.Log; import com.android.ims.ImsException; import com.android.ims.ImsManager; @@ -119,7 +120,7 @@ import java.util.concurrent.CompletableFuture; */ public class PhoneSwitcher extends Handler { private static final String LOG_TAG = "PhoneSwitcher"; - protected static final boolean VDBG = false; + protected static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); /** Fragment "key" argument passed thru {@link #SETTINGS_EXTRA_SHOW_FRAGMENT_ARGUMENTS} */ private static final String SETTINGS_EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"; @@ -469,36 +470,14 @@ public class PhoneSwitcher extends Handler { return sPhoneSwitcher; } - /** - * Whether this phone IMS registration is on its original network. This result impacts - * whether we want to do DDS switch to the phone having voice call. - * If it's registered on IWLAN or cross SIM in multi-SIM case, return false. Otherwise, - * return true. - */ - private boolean isImsOnOriginalNetwork(Phone phone) { - if (phone == null) return false; - int phoneId = phone.getPhoneId(); - if (!SubscriptionManager.isValidPhoneId(phoneId)) return false; - - int imsRegTech = mImsRegTechProvider.get(mContext, phoneId); - // If IMS is registered on IWLAN or cross SIM, return false. - boolean isOnOriginalNetwork = (imsRegTech != REGISTRATION_TECH_IWLAN) - && (imsRegTech != REGISTRATION_TECH_CROSS_SIM); - if (!isOnOriginalNetwork) { - logl("IMS call on IWLAN or cross SIM. Call will be ignored for DDS switch"); - } - return isOnOriginalNetwork; - } - - private boolean isPhoneInVoiceCallChanged() { + private boolean updatesIfPhoneInVoiceCallChanged() { int oldPhoneIdInVoiceCall = mPhoneIdInVoiceCall; // If there's no active call, the value will become INVALID_PHONE_INDEX // and internet data will be switched back to system selected or user selected // subscription. mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX; for (Phone phone : PhoneFactory.getPhones()) { - if (isPhoneInVoiceCall(phone) || (isPhoneInVoiceCall(phone.getImsPhone()) - && isImsOnOriginalNetwork(phone))) { + if (isPhoneInVoiceCall(phone) || isPhoneInVoiceCall(phone.getImsPhone())) { mPhoneIdInVoiceCall = phone.getPhoneId(); break; } @@ -780,25 +759,25 @@ public class PhoneSwitcher extends Handler { onEvaluate(REQUESTS_UNCHANGED, EVALUATION_REASON_RADIO_ON); break; } - case EVENT_IMS_RADIO_TECH_CHANGED: + 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 the phoneId in voice call didn't change, do nothing. - if (!isPhoneInVoiceCallChanged()) { - 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()) { + evaluateIfImmediateDataSwitchIsNeeded("Ims radio tech changed", + DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); } - evaluateIfImmediateDataSwitchIsNeeded("Ims radio tech changed", - DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); break; - + } 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 the phoneId in voice call didn't change, do nothing. - if (!isPhoneInVoiceCallChanged()) { + if (!updatesIfPhoneInVoiceCallChanged()) { break; } @@ -1606,27 +1585,9 @@ public class PhoneSwitcher extends Handler { } } - private int getSubIdForDefaultNetworkRequests() { - if (isActiveSubId(mAutoSelectedDataSubId)) { - return mAutoSelectedDataSubId; - } else { - return mPrimaryDataSubId; - } - } - // This updates mPreferredDataPhoneId which decides which phone should handle default network // requests. protected void updatePreferredDataPhoneId() { - Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); - // check user enabled data on the default phone - Phone defaultDataPhone = getPhoneBySubId(mPrimaryDataSubId); - boolean isDataEnabled = false; - if (voicePhone != null && defaultDataPhone != null - && defaultDataPhone.isUserDataEnabled()) { - // check voice during call feature is enabled - isDataEnabled = voicePhone.isDataAllowed(); - } - if (mEmergencyOverride != null && findPhoneById(mEmergencyOverride.mPhoneId) != null) { // Override DDS for emergency even if user data is not enabled, since it is an // emergency. @@ -1636,31 +1597,55 @@ public class PhoneSwitcher extends Handler { + " phoneId = " + mEmergencyOverride.mPhoneId); mPreferredDataPhoneId = mEmergencyOverride.mPhoneId; mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; - } else if (isDataEnabled) { - // If a phone is in call and user enabled its mobile data, we - // should switch internet connection to it. Because the other modem - // will lose data connection anyway. - mPreferredDataPhoneId = mPhoneIdInVoiceCall; - mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL; } else { - int subId = getSubIdForDefaultNetworkRequests(); - int phoneId = SubscriptionManager.INVALID_PHONE_INDEX; - - if (SubscriptionManager.isUsableSubIdValue(subId)) { - for (int i = 0; i < mActiveModemCount; i++) { - if (mPhoneSubscriptions[i] == subId) { - phoneId = i; - break; - } + int imsRegTech = mImsRegTechProvider.get(mContext, mPhoneIdInVoiceCall); + if (isAnyVoiceCallActiveOnDevice() && imsRegTech != REGISTRATION_TECH_IWLAN) { + if (imsRegTech != REGISTRATION_TECH_CROSS_SIM) { + if (shouldSwitchDataDueToInCall()) mPreferredDataPhoneId = mPhoneIdInVoiceCall; + } else { + logl("IMS call on cross-SIM, skip switching data to phone " + + mPhoneIdInVoiceCall); } + } else { + mPreferredDataPhoneId = getFallbackDataPhoneIdForInternetRequests(); } - - mPreferredDataPhoneId = phoneId; } mPreferredDataSubId.set(SubscriptionManager.getSubscriptionId(mPreferredDataPhoneId)); } + /** + * @return the default data phone Id (or auto selected phone Id in auto data switch/CBRS case) + */ + private int getFallbackDataPhoneIdForInternetRequests() { + int fallbackSubId = isActiveSubId(mAutoSelectedDataSubId) + ? mAutoSelectedDataSubId : mPrimaryDataSubId; + + if (SubscriptionManager.isUsableSubIdValue(fallbackSubId)) { + for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { + if (mPhoneSubscriptions[phoneId] == fallbackSubId) { + return phoneId; + } + } + } + return SubscriptionManager.INVALID_PHONE_INDEX; + } + + /** + * If a phone is in call and user enabled its mobile data and auto data switch feature, we + * should switch internet connectionto it because the other modem will lose data connection + * anyway. + * @return {@code true} if should switch data to the phone in voice call + */ + private boolean shouldSwitchDataDueToInCall() { + Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); + Phone defaultDataPhone = getPhoneBySubId(mPrimaryDataSubId); + return defaultDataPhone != null // check user enabled data + && defaultDataPhone.isUserDataEnabled() + && voicePhone != null // check user enabled voice during call feature + && voicePhone.isDataAllowed(); + } + protected void transitionToEmergencyPhone() { if (mActiveModemCount <= 0) { logl("No phones: unable to reset preferred phone for emergency"); 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 bcd6160c67..6923eb0d42 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -95,7 +95,6 @@ import java.util.concurrent.LinkedBlockingQueue; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class PhoneSwitcherTest extends TelephonyTest { - private static final int AUTO_DATA_SWITCH_NOTIFICATION = 1; private static final int ACTIVE_PHONE_SWITCH = 1; private static final int EVENT_RADIO_ON = 108; private static final int EVENT_MODEM_COMMAND_DONE = 112; @@ -1176,7 +1175,7 @@ public class PhoneSwitcherTest extends TelephonyTest { assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); - // Phone2 has active call. So data switch to it. + // Phone2 has active call, and data is on. So data switch to it. doReturn(true).when(mPhone).isUserDataEnabled(); notifyDataEnabled(true); verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); @@ -1186,8 +1185,19 @@ public class PhoneSwitcherTest extends TelephonyTest { new TelephonyNetworkRequest(internetRequest, mPhone), 0)); clearInvocations(mMockRadioConfig); - // Phone2 call ended. So data switch back to default data sub. + // Phone2(nDDS) call ended. But Phone1 having cross-SIM call. Don't switch. + mockImsRegTech(1, REGISTRATION_TECH_CROSS_SIM); + notifyPhoneAsInIncomingCall(mPhone); notifyPhoneAsInactive(mPhone2); + verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 1)); + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 0)); + + // Phone1(DDS) call ended. So data switch back to default data sub. + mockImsRegTech(0, REGISTRATION_TECH_IWLAN); + notifyPhoneAsInactive(mPhone); verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); @@ -1195,13 +1205,14 @@ public class PhoneSwitcherTest extends TelephonyTest { new TelephonyNetworkRequest(internetRequest, mPhone), 1)); clearInvocations(mMockRadioConfig); - // Phone2 has holding call, but data is turned off. So no data switching should happen. + // Phone2 has holding call on VoWifi, no need to switch data + mockImsRegTech(1, REGISTRATION_TECH_IWLAN); notifyPhoneAsInHoldingCall(mPhone2); - verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); + verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( - new TelephonyNetworkRequest(internetRequest, mPhone), 1)); - assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 1)); } -- GitLab From bd8ad1b8ca2cb4c6f5a10b66c944e3f10864376b Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 7 Dec 2022 14:42:57 +0000 Subject: [PATCH 257/656] Add isNullCipherAndIntegrityEnabled interface Bug: b/237529943 Test: m Change-Id: Ib6d27473fb2ce6f79849844ae928613607a7a641 --- .../internal/telephony/NetworkResponse.java | 31 ++++++++++++++----- .../internal/telephony/RadioNetworkProxy.java | 14 +++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index 17c07a2fdf..f09dead732 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -477,6 +477,30 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void setNullCipherAndIntegrityEnabledResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); + } + + /** + * @param responseInfo Response info struct containing response type, serial no. and error. + * @param isEnabled Indicates whether null cipher and integrity is enabled, indicating + * potentially unencrypted communication + */ + public void isNullCipherAndIntegrityEnabledResponse(RadioResponseInfo responseInfo, + boolean isEnabled) { + RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo); + + if (rr != null) { + if (responseInfo.error == RadioError.NONE) { + RadioResponse.sendMessageResponse(rr.mResult, isEnabled); + } + mRil.processResponseDone(rr, responseInfo, isEnabled); + } + } + /** * @param responseInfo Response info struct containing response type, serial no. and error. * @param isEnabled Indicates whether N1 mode is enabled or not. @@ -525,11 +549,4 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { return IRadioNetworkResponse.VERSION; } - /** - * @param responseInfo Response info struct containing response type, serial no. and error - */ - public void setNullCipherAndIntegrityEnabledResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); - } - } diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java index 9e16edf408..4717ad60d0 100644 --- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java +++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java @@ -933,6 +933,20 @@ public class RadioNetworkProxy extends RadioServiceProxy { // Only supported on AIDL. } + /** + * Get if null ciphering / null integrity is permitted. + * @param serial Serial number of the request. + * @throws RemoteException + * + */ + public void isNullCipherAndIntegrityEnabled(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mNetworkProxy.isNullCipherAndIntegrityEnabled(serial); + } + // Only supported on AIDL. + } + /** * Checks whether N1 mode is enabled. * -- GitLab From 0b8eeb90e5357fbaf91c84fadc344761ef5d3fa6 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 2 Sep 2022 09:27:16 +0000 Subject: [PATCH 258/656] Refactoring for the domain selection service of emergency calls Bug: 243344927 Test: atest GsmCdmaPhoneTest Change-Id: If2ae9a2a5e383b8597478643eac1c8008f2349b8 --- .../internal/telephony/GsmCdmaPhone.java | 29 ++++++++ .../imsphone/ImsPhoneCallTracker.java | 9 ++- .../imsphone/ImsPhoneConnection.java | 10 ++- .../internal/telephony/GsmCdmaPhoneTest.java | 74 +++++++++++++++++++ .../imsphone/ImsPhoneCallTrackerTest.java | 17 +++++ .../imsphone/ImsPhoneConnectionTest.java | 20 +++-- 6 files changed, 149 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index c4c7a5582f..77129c6f6b 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + import static com.android.internal.telephony.CommandException.Error.GENERIC_FAILURE; import static com.android.internal.telephony.CommandException.Error.SIM_BUSY; import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE; @@ -1350,6 +1352,12 @@ public class GsmCdmaPhone extends Phone { logi("dial; isEmergency=" + isEmergency + " (based on all phones)"); } + // Undetectable emergeny number indicated by new domain selection service + if (dialArgs.isEmergency) { + logi("dial; isEmergency=" + isEmergency + " (domain selection module)"); + isEmergency = true; + } + /** Check if the call is Wireless Priority Service call */ boolean isWpsCall = dialString != null ? (dialString.startsWith(PREFIX_WPS) || dialString.startsWith(PREFIX_WPS_CLIR_ACTIVATE) @@ -1375,6 +1383,27 @@ public class GsmCdmaPhone extends Phone { boolean useImsForCall = useImsForCall(dialArgs) && (isWpsCall ? allowWpsOverIms : true); + Bundle extras = dialArgs.intentExtras; + // Only when the domain selection service is supported, EXTRA_DIAL_DOMAIN extra shall exist. + if (extras != null && extras.containsKey(PhoneConstants.EXTRA_DIAL_DOMAIN)) { + int domain = extras.getInt(PhoneConstants.EXTRA_DIAL_DOMAIN); + logi("dial domain=" + domain); + useImsForCall = false; + useImsForUt = false; + useImsForEmergency = false; + if (domain == DOMAIN_PS) { + if (isEmergency) { + useImsForEmergency = true; + } else if (!isMmiCode || isPotentialUssdCode) { + useImsForCall = true; + } else { + // should not reach here + loge("dial unexpected Ut domain selection, ignored"); + } + } + extras.remove(PhoneConstants.EXTRA_DIAL_DOMAIN); + } + if (DBG) { logi("useImsForCall=" + useImsForCall + ", useOnlyDialedSimEccList=" + useOnlyDialedSimEccList diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index f085f66b52..264d49b213 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -1543,7 +1543,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mLastDialString = dialString; mLastDialArgs = dialArgs; mPendingMO = new ImsPhoneConnection(mPhone, dialString, this, mForegroundCall, - isEmergencyNumber, isWpsCall); + isEmergencyNumber, isWpsCall, dialArgs); mOperationLocalLog.log("dial requested. connId=" + System.identityHashCode(mPendingMO)); if (isEmergencyNumber && dialArgs != null && dialArgs.intentExtras != null) { Rlog.i(LOG_TAG, "dial ims emergency dialer: " + dialArgs.intentExtras.getBoolean( @@ -3272,6 +3272,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { eccCategory = imsCall.getCallProfile().getEmergencyServiceCategories(); } + if (reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL) { + ImsPhoneConnection conn = findConnection(imsCall); + if (conn != null) { + conn.setNonDetectableEmergencyCallInfo(eccCategory); + } + } + if (mHoldSwitchingState == HoldSwapState.HOLDING_TO_ANSWER_INCOMING) { // If we put a call on hold to answer an incoming call, we should reset the // variables that keep track of the switch here. diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java index 68de4a3ec9..581b6fff8b 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java @@ -244,7 +244,8 @@ public class ImsPhoneConnection extends Connection implements /** This is an MO call, created when dialing */ public ImsPhoneConnection(Phone phone, String dialString, ImsPhoneCallTracker ct, - ImsPhoneCall parent, boolean isEmergency, boolean isWpsCall) { + ImsPhoneCall parent, boolean isEmergency, boolean isWpsCall, + ImsPhone.ImsDialArgs dialArgs) { super(PhoneConstants.PHONE_TYPE_IMS); createWakeLock(phone.getContext()); acquireWakeLock(); @@ -272,6 +273,13 @@ public class ImsPhoneConnection extends Connection implements mIsEmergency = isEmergency; if (isEmergency) { setEmergencyCallInfo(mOwner); + + if (getEmergencyNumberInfo() == null) { + // There was no emergency number info found for this call, however it is + // still marked as an emergency number. This may happen if it was a redialed + // non-detectable emergency call from IMS. + setNonDetectableEmergencyCallInfo(dialArgs.eccCategory); + } } mIsWpsCall = isWpsCall; diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 97c56ac46c..8a7398442c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -52,6 +52,7 @@ import static org.mockito.Mockito.when; import android.content.Intent; import android.content.SharedPreferences; import android.os.AsyncResult; +import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.PersistableBundle; @@ -2108,4 +2109,77 @@ public class GsmCdmaPhoneTest extends TelephonyTest { verify(mImsPhone, times(1)).triggerImsDeregistration( eq(ImsRegistrationImplBase.REASON_SIM_REFRESH)); } + + @Test + public void testDomainSelectionEmergencyCallCs() throws CallStateException { + setupEmergencyCallScenario(false /* USE_ONLY_DIALED_SIM_ECC_LIST */, + false /* isEmergencyOnDialedSim */); + + Bundle extras = new Bundle(); + extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, NetworkRegistrationInfo.DOMAIN_CS); + ImsPhone.ImsDialArgs dialArgs = new ImsPhone.ImsDialArgs.Builder() + .setIntentExtras(extras) + .build(); + mPhoneUT.dial(TEST_EMERGENCY_NUMBER, dialArgs); + + verify(mCT).dialGsm(anyString(), any(PhoneInternalInterface.DialArgs.class)); + } + + @Test + public void testDomainSelectionEmergencyCallPs() throws CallStateException { + setupEmergencyCallScenario(false /* USE_ONLY_DIALED_SIM_ECC_LIST */, + false /* isEmergencyOnDialedSim */); + + doReturn(false).when(mImsPhone).isImsAvailable(); + + Bundle extras = new Bundle(); + extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, NetworkRegistrationInfo.DOMAIN_PS); + ImsPhone.ImsDialArgs dialArgs = new ImsPhone.ImsDialArgs.Builder() + .setIntentExtras(extras) + .build(); + mPhoneUT.dial(TEST_EMERGENCY_NUMBER, dialArgs); + + verify(mImsPhone).dial(anyString(), any(PhoneInternalInterface.DialArgs.class)); + } + + @Test + public void testDomainSelectionDialCs() throws Exception { + doReturn(true).when(mImsPhone).isImsAvailable(); + doReturn(true).when(mImsManager).isVolteEnabledByPlatform(); + doReturn(true).when(mImsManager).isEnhanced4gLteModeSettingEnabledByUser(); + doReturn(true).when(mImsManager).isNonTtyOrTtyOnVolteEnabled(); + doReturn(true).when(mImsPhone).isVoiceOverCellularImsEnabled(); + doReturn(true).when(mImsPhone).isUtEnabled(); + + replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); + + Bundle extras = new Bundle(); + extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, NetworkRegistrationInfo.DOMAIN_CS); + ImsPhone.ImsDialArgs dialArgs = new ImsPhone.ImsDialArgs.Builder() + .setIntentExtras(extras) + .build(); + Connection connection = mPhoneUT.dial("1234567890", dialArgs); + verify(mCT).dialGsm(eq("1234567890"), any(PhoneInternalInterface.DialArgs.class)); + } + + @Test + public void testDomainSelectionDialPs() throws Exception { + mSST.mSS = mServiceState; + doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState(); + + mCT.mForegroundCall = mGsmCdmaCall; + mCT.mBackgroundCall = mGsmCdmaCall; + mCT.mRingingCall = mGsmCdmaCall; + doReturn(GsmCdmaCall.State.IDLE).when(mGsmCdmaCall).getState(); + + replaceInstance(Phone.class, "mImsPhone", mPhoneUT, mImsPhone); + + Bundle extras = new Bundle(); + extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, NetworkRegistrationInfo.DOMAIN_PS); + ImsPhone.ImsDialArgs dialArgs = new ImsPhone.ImsDialArgs.Builder() + .setIntentExtras(extras) + .build(); + Connection connection = mPhoneUT.dial("1234567890", dialArgs); + verify(mImsPhone).dial(eq("1234567890"), any(PhoneInternalInterface.DialArgs.class)); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 9bdee13615..222cb63dda 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -33,6 +33,7 @@ import static android.telephony.TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED; import static android.telephony.TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED; import static android.telephony.TelephonyManager.SRVCC_STATE_HANDOVER_FAILED; import static android.telephony.TelephonyManager.SRVCC_STATE_HANDOVER_STARTED; +import static android.telephony.emergency.EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE; import static android.telephony.ims.ImsStreamMediaProfile.DIRECTION_INACTIVE; import static android.telephony.ims.ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE; @@ -84,6 +85,7 @@ import android.telephony.DisconnectCause; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; import android.telephony.TelephonyManager; +import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsConferenceState; @@ -2348,6 +2350,21 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { eq(CommandsInterface.IMS_MMTEL_CAPABILITY_SMS)); } + @Test + @SmallTest + public void testDomainSelectionAlternateService() { + startOutgoingCall(); + ImsPhoneConnection c = mCTUT.mForegroundCall.getFirstConnection(); + mImsCallProfile.setEmergencyServiceCategories(EMERGENCY_SERVICE_CATEGORY_AMBULANCE); + mImsCallListener.onCallStartFailed(mSecondImsCall, + new ImsReasonInfo(ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL, -1)); + processAllMessages(); + EmergencyNumber emergencyNumber = c.getEmergencyNumberInfo(); + assertNotNull(emergencyNumber); + assertEquals(EMERGENCY_SERVICE_CATEGORY_AMBULANCE, + emergencyNumber.getEmergencyServiceCategoryBitmask()); + } + private void sendCarrierConfigChanged() { Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); 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 9779cfa027..396466c8db 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java @@ -58,6 +58,7 @@ import com.android.internal.telephony.Connection; import com.android.internal.telephony.GsmCdmaCall; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.imsphone.ImsPhone.ImsDialArgs; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.metrics.VoiceCallSessionStats; @@ -144,7 +145,8 @@ public class ImsPhoneConnectionTest extends TelephonyTest { logd("Testing initial state of MO ImsPhoneConnection"); mConnectionUT = new ImsPhoneConnection(mImsPhone, String.format("+1 (700).555-41NN%c1234", - PhoneNumberUtils.PAUSE), mImsCT, mForeGroundCall, false, false); + PhoneNumberUtils.PAUSE), mImsCT, mForeGroundCall, false, false, + new ImsDialArgs.Builder().build()); assertEquals(PhoneConstants.PRESENTATION_ALLOWED, mConnectionUT.getNumberPresentation()); assertEquals(PhoneConstants.PRESENTATION_ALLOWED, mConnectionUT.getCnapNamePresentation()); assertEquals("+1 (700).555-41NN,1234", mConnectionUT.getOrigDialString()); @@ -157,7 +159,7 @@ public class ImsPhoneConnectionTest extends TelephonyTest { public void testImsUpdateStateForeGround() { // MO Foreground Connection dailing -> active mConnectionUT = new ImsPhoneConnection(mImsPhone, "+1 (700).555-41NN1234", mImsCT, - mForeGroundCall, false, false); + mForeGroundCall, false, false, new ImsDialArgs.Builder().build()); // initially in dialing state doReturn(Call.State.DIALING).when(mForeGroundCall).getState(); assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE)); @@ -172,7 +174,7 @@ public class ImsPhoneConnectionTest extends TelephonyTest { public void testUpdateCodec() { // MO Foreground Connection dailing -> active mConnectionUT = new ImsPhoneConnection(mImsPhone, "+1 (700).555-41NN1234", mImsCT, - mForeGroundCall, false, false); + mForeGroundCall, false, false, new ImsDialArgs.Builder().build()); doReturn(Call.State.ACTIVE).when(mForeGroundCall).getState(); assertTrue(mConnectionUT.updateMediaCapabilities(mImsCall)); } @@ -195,7 +197,7 @@ public class ImsPhoneConnectionTest extends TelephonyTest { @SmallTest public void testImsUpdateStatePendingHold() { mConnectionUT = new ImsPhoneConnection(mImsPhone, "+1 (700).555-41NN1234", mImsCT, - mForeGroundCall, false, false); + mForeGroundCall, false, false, new ImsDialArgs.Builder().build()); doReturn(true).when(mImsCall).isPendingHold(); assertFalse(mConnectionUT.update(mImsCall, Call.State.ACTIVE)); verify(mForeGroundCall, times(0)).update(eq(mConnectionUT), eq(mImsCall), @@ -240,7 +242,8 @@ public class ImsPhoneConnectionTest extends TelephonyTest { @SmallTest public void testPostDialWait() { mConnectionUT = new ImsPhoneConnection(mImsPhone, String.format("+1 (700).555-41NN%c1234", - PhoneNumberUtils.WAIT), mImsCT, mForeGroundCall, false, false); + PhoneNumberUtils.WAIT), mImsCT, mForeGroundCall, false, false, + new ImsDialArgs.Builder().build()); doReturn(Call.State.DIALING).when(mForeGroundCall).getState(); doAnswer(new Answer() { @Override @@ -263,7 +266,8 @@ public class ImsPhoneConnectionTest extends TelephonyTest { @MediumTest public void testPostDialPause() { mConnectionUT = new ImsPhoneConnection(mImsPhone, String.format("+1 (700).555-41NN%c1234", - PhoneNumberUtils.PAUSE), mImsCT, mForeGroundCall, false, false); + PhoneNumberUtils.PAUSE), mImsCT, mForeGroundCall, false, false, + new ImsDialArgs.Builder().build()); doReturn(Call.State.DIALING).when(mForeGroundCall).getState(); doAnswer(new Answer() { @Override @@ -385,7 +389,7 @@ public class ImsPhoneConnectionTest extends TelephonyTest { {"12345*00000", "12346", "12346"}}; for (String[] testAddress : testAddressMappingSet) { mConnectionUT = new ImsPhoneConnection(mImsPhone, testAddress[0], mImsCT, - mForeGroundCall, false, false); + mForeGroundCall, false, false, new ImsDialArgs.Builder().build()); mConnectionUT.setIsIncoming(true); mImsCallProfile.setCallExtra(ImsCallProfile.EXTRA_OI, testAddress[1]); mConnectionUT.updateAddressDisplay(mImsCall); @@ -403,7 +407,7 @@ public class ImsPhoneConnectionTest extends TelephonyTest { String updateAddress = "6789"; mConnectionUT = new ImsPhoneConnection(mImsPhone, inputAddress, mImsCT, mForeGroundCall, - false, false); + false, false, new ImsDialArgs.Builder().build()); mConnectionUT.setIsIncoming(false); mImsCallProfile.setCallExtra(ImsCallProfile.EXTRA_OI, updateAddress); mConnectionUT.updateAddressDisplay(mImsCall); -- GitLab From 3cfd4f84877c68a281df30f52ed5bf14ac13587a Mon Sep 17 00:00:00 2001 From: Rafael Higuera Silva Date: Thu, 8 Dec 2022 19:51:34 +0000 Subject: [PATCH 259/656] Remove daily pull policy. The pull policy is enforce by persist atom storage class with a pull timestamp, so removing this policy will not affect the privacy requirements. Bug: 237740139 Test: make Change-Id: Ic53492de38e3ebaf64c40f1bae4cad1e0ec5816c --- .../telephony/metrics/MetricsCollector.java | 73 +++++++++---------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 8a0cd48fbf..81b2cb9e0b 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -47,7 +47,6 @@ import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_RAT_US import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION; import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__CALL_DURATION__CALL_DURATION_UNKNOWN; -import android.annotation.Nullable; import android.app.StatsManager; import android.content.Context; import android.telephony.SubscriptionManager; @@ -130,11 +129,6 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { private static final long DURATION_BUCKET_MILLIS = DBG ? 2L * MILLIS_PER_SECOND : 5L * MILLIS_PER_MINUTE; - private static final StatsManager.PullAtomMetadata POLICY_PULL_DAILY = - new StatsManager.PullAtomMetadata.Builder() - .setCoolDownMillis(MIN_COOLDOWN_MILLIS) - .build(); - private final PersistAtomsStorage mStorage; private final StatsManager mStatsManager; private final AirplaneModeStats mAirplaneModeStats; @@ -152,36 +146,36 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { mStorage = storage; mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER); if (mStatsManager != null) { - registerAtom(CELLULAR_DATA_SERVICE_SWITCH, POLICY_PULL_DAILY); - registerAtom(CELLULAR_SERVICE_STATE, POLICY_PULL_DAILY); - registerAtom(SIM_SLOT_STATE, null); - registerAtom(SUPPORTED_RADIO_ACCESS_FAMILY, null); - registerAtom(VOICE_CALL_RAT_USAGE, POLICY_PULL_DAILY); - registerAtom(VOICE_CALL_SESSION, POLICY_PULL_DAILY); - registerAtom(INCOMING_SMS, POLICY_PULL_DAILY); - registerAtom(OUTGOING_SMS, POLICY_PULL_DAILY); - registerAtom(CARRIER_ID_TABLE_VERSION, null); - registerAtom(DATA_CALL_SESSION, POLICY_PULL_DAILY); - registerAtom(IMS_REGISTRATION_STATS, POLICY_PULL_DAILY); - registerAtom(IMS_REGISTRATION_TERMINATION, POLICY_PULL_DAILY); - registerAtom(TELEPHONY_NETWORK_REQUESTS_V2, POLICY_PULL_DAILY); - registerAtom(IMS_REGISTRATION_FEATURE_TAG_STATS, POLICY_PULL_DAILY); - registerAtom(RCS_CLIENT_PROVISIONING_STATS, POLICY_PULL_DAILY); - registerAtom(RCS_ACS_PROVISIONING_STATS, POLICY_PULL_DAILY); - registerAtom(SIP_DELEGATE_STATS, POLICY_PULL_DAILY); - registerAtom(SIP_TRANSPORT_FEATURE_TAG_STATS, POLICY_PULL_DAILY); - registerAtom(SIP_MESSAGE_RESPONSE, POLICY_PULL_DAILY); - registerAtom(SIP_TRANSPORT_SESSION, POLICY_PULL_DAILY); - registerAtom(DEVICE_TELEPHONY_PROPERTIES, null); - registerAtom(IMS_DEDICATED_BEARER_LISTENER_EVENT, POLICY_PULL_DAILY); - registerAtom(IMS_DEDICATED_BEARER_EVENT, POLICY_PULL_DAILY); - registerAtom(IMS_REGISTRATION_SERVICE_DESC_STATS, POLICY_PULL_DAILY); - registerAtom(UCE_EVENT_STATS, POLICY_PULL_DAILY); - registerAtom(PRESENCE_NOTIFY_EVENT, POLICY_PULL_DAILY); - registerAtom(GBA_EVENT, POLICY_PULL_DAILY); - registerAtom(PER_SIM_STATUS, null); - registerAtom(OUTGOING_SHORT_CODE_SMS, POLICY_PULL_DAILY); - + // Most (but not all) of these are subject to cooldown specified by MIN_COOLDOWN_MILLIS. + registerAtom(CELLULAR_DATA_SERVICE_SWITCH); + registerAtom(CELLULAR_SERVICE_STATE); + registerAtom(SIM_SLOT_STATE); + registerAtom(SUPPORTED_RADIO_ACCESS_FAMILY); + registerAtom(VOICE_CALL_RAT_USAGE); + registerAtom(VOICE_CALL_SESSION); + registerAtom(INCOMING_SMS); + registerAtom(OUTGOING_SMS); + registerAtom(CARRIER_ID_TABLE_VERSION); + registerAtom(DATA_CALL_SESSION); + registerAtom(IMS_REGISTRATION_STATS); + registerAtom(IMS_REGISTRATION_TERMINATION); + registerAtom(TELEPHONY_NETWORK_REQUESTS_V2); + registerAtom(IMS_REGISTRATION_FEATURE_TAG_STATS); + registerAtom(RCS_CLIENT_PROVISIONING_STATS); + registerAtom(RCS_ACS_PROVISIONING_STATS); + registerAtom(SIP_DELEGATE_STATS); + registerAtom(SIP_TRANSPORT_FEATURE_TAG_STATS); + registerAtom(SIP_MESSAGE_RESPONSE); + registerAtom(SIP_TRANSPORT_SESSION); + registerAtom(DEVICE_TELEPHONY_PROPERTIES); + registerAtom(IMS_DEDICATED_BEARER_LISTENER_EVENT); + registerAtom(IMS_DEDICATED_BEARER_EVENT); + registerAtom(IMS_REGISTRATION_SERVICE_DESC_STATS); + registerAtom(UCE_EVENT_STATS); + registerAtom(PRESENCE_NOTIFY_EVENT); + registerAtom(GBA_EVENT); + registerAtom(PER_SIM_STATUS); + registerAtom(OUTGOING_SHORT_CODE_SMS); Rlog.d(TAG, "registered"); } else { Rlog.e(TAG, "could not get StatsManager, atoms not registered"); @@ -721,9 +715,10 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } } - /** Registers a pulled atom ID {@code atomId} with optional {@code policy} for pulling. */ - private void registerAtom(int atomId, @Nullable StatsManager.PullAtomMetadata policy) { - mStatsManager.setPullAtomCallback(atomId, policy, ConcurrentUtils.DIRECT_EXECUTOR, this); + /** Registers a pulled atom ID {@code atomId}. */ + private void registerAtom(int atomId) { + mStatsManager.setPullAtomCallback(atomId, /* metadata= */ null, + ConcurrentUtils.DIRECT_EXECUTOR, this); } private static StatsEvent buildStatsEvent(CellularDataServiceSwitch serviceSwitch) { -- GitLab From e4352baee19a61cc8db65ac4829e18264c8ab68b Mon Sep 17 00:00:00 2001 From: Helen Date: Tue, 6 Dec 2022 10:15:39 +0000 Subject: [PATCH 260/656] Add onAudioModeIsVoipChanged for dynamic audio switching feature Bug: 250815288 Bug: 255715090 Test: build and atest ImsCallingTest#testSetCallAudioHandler Change-Id: I11a383a43adbead8cd9fae64c597255b4b5a0a8d --- .../internal/telephony/Connection.java | 30 +++++++++++++++++++ .../imsphone/ImsPhoneCallTracker.java | 27 +++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/java/com/android/internal/telephony/Connection.java b/src/java/com/android/internal/telephony/Connection.java index f51bd2f89e..68fd6abcde 100644 --- a/src/java/com/android/internal/telephony/Connection.java +++ b/src/java/com/android/internal/telephony/Connection.java @@ -27,6 +27,8 @@ import android.telephony.ServiceState; import android.telephony.ServiceState.RilRadioTechnology; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RtpHeaderExtension; +import android.telephony.ims.feature.MmTelFeature; +import android.telephony.ims.feature.MmTelFeature.ImsAudioHandler; import android.util.Log; import com.android.ims.internal.ConferenceParticipant; @@ -139,6 +141,13 @@ public abstract class Connection { * @param extensionData The extension data. */ public void onReceivedRtpHeaderExtensions(@NonNull Set extensionData); + + /** + * Indicates that the audio handler for this connection is changed. + * + * @param imsAudioHandler {@link MmTelFeature#ImsAudioHandler}. + */ + void onAudioModeIsVoipChanged(@ImsAudioHandler int imsAudioHandler); } /** @@ -194,6 +203,8 @@ public abstract class Connection { public void onReceivedDtmfDigit(char digit) {} @Override public void onReceivedRtpHeaderExtensions(@NonNull Set extensionData) {} + @Override + public void onAudioModeIsVoipChanged(@ImsAudioHandler int imsAudioHandler) {} } public static final int AUDIO_QUALITY_STANDARD = 1; @@ -1574,6 +1585,25 @@ public abstract class Connection { } } + /** + * Called to report audio mode changed for Voip. + * @param imsAudioHandler the received value to handle the audio for this IMS call. + */ + public void onAudioModeIsVoipChanged(@ImsAudioHandler int imsAudioHandler) { + Rlog.i(TAG, "onAudioModeIsVoipChanged: conn imsAudioHandler " + imsAudioHandler); + + boolean isVoip = imsAudioHandler == MmTelFeature.AUDIO_HANDLER_ANDROID; + if (isVoip == mAudioModeIsVoip) return; + mAudioModeIsVoip = isVoip; + + Rlog.i(TAG, "onAudioModeIsVoipChanged: isVoip: " + isVoip + + "mAudioModeIsVoip:" + mAudioModeIsVoip); + + for (Listener l : mListeners) { + l.onAudioModeIsVoipChanged(imsAudioHandler); + } + } + /** * Called to report RTP header extensions received from the network. * @param extensionData the received extension data. diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 68e141e291..2f94180a2a 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -362,6 +362,33 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { }, mExecutor); } + @Override + public void onAudioModeIsVoipChanged(int imsAudioHandler) { + TelephonyUtils.runWithCleanCallingIdentity(()-> { + ImsCall imsCall = null; + if (mForegroundCall.hasConnections()) { + imsCall = mForegroundCall.getImsCall(); + } else if (mBackgroundCall.hasConnections()) { + imsCall = mBackgroundCall.getImsCall(); + } else if (mRingingCall.hasConnections()) { + imsCall = mRingingCall.getImsCall(); + } else if (mHandoverCall.hasConnections()) { + imsCall = mHandoverCall.getImsCall(); + } else { + Rlog.e(LOG_TAG, "onAudioModeIsVoipChanged: no Call"); + } + + if (imsCall != null) { + ImsPhoneConnection conn = findConnection(imsCall); + if (conn != null) { + conn.onAudioModeIsVoipChanged(imsAudioHandler); + } + } else { + Rlog.e(LOG_TAG, "onAudioModeIsVoipChanged: no ImsCall"); + } + }, mExecutor); + } + /** * Schedule the given Runnable on mExecutor and block this thread until it finishes. * @param r The Runnable to run. -- GitLab From 60ad5daf250bf3eab04d3c52df666372e9ea32b6 Mon Sep 17 00:00:00 2001 From: Hwangoo Park Date: Fri, 18 Nov 2022 00:20:45 +0000 Subject: [PATCH 261/656] Add DomainSelectionResolver for domain selection service The DomainSelectionResolver maintains the device specific configurations required to bind to the DomainSelectionService and creates the DomainSelectionController and manages this controller. And, it acts as a proxy interface to create the DomainSelectionConnection of each functional component(call/SMS/Ut) for performing the domain selection. Bug: 243878608 Test: atest DomainSelectionResolverTest Change-Id: I3311d7f0eed1c7b632550783ad8bfb19bbf73224 --- .../DomainSelectionResolver.java | 207 ++++++++++++++++++ .../DomainSelectionResolverTest.java | 178 +++++++++++++++ 2 files changed, 385 insertions(+) create mode 100644 src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionResolverTest.java diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java new file mode 100644 index 0000000000..cbb74fadd7 --- /dev/null +++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionResolver.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; + +import static com.android.internal.telephony.RIL.RADIO_HAL_VERSION_2_1; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.telephony.DomainSelectionService; +import android.util.IndentingPrintWriter; +import android.util.LocalLog; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** + * This class is an entry point to provide whether the AOSP domain selection is supported or not, + * and bind the {@link DomainSelectionController} with the given {@link DomainSelectionService} to + * provide a specific {@link DomainSelectionConnection} object for communicating with each domain + * selector. + */ +public class DomainSelectionResolver { + private static final String TAG = DomainSelectionResolver.class.getSimpleName(); + private static DomainSelectionResolver sInstance = null; + + /** + * Creates the DomainSelectionResolver singleton instance. + * + * @param context The context of the application. + * @param deviceConfigEnabled The flag to indicate whether or not the device supports + * the domain selection service or not. + */ + public static void make(Context context, boolean deviceConfigEnabled) { + if (sInstance == null) { + sInstance = new DomainSelectionResolver(context, deviceConfigEnabled); + } + } + + /** + * Returns the singleton instance of DomainSelectionResolver. + * + * @return A {@link DomainSelectionResolver} instance. + */ + public static DomainSelectionResolver getInstance() { + if (sInstance == null) { + throw new IllegalStateException("DomainSelectionResolver is not ready!"); + } + return sInstance; + } + + /** + * Sets a {@link DomainSelectionResolver} for injecting mock DomainSelectionResolver. + * + * @param resolver A {@link DomainSelectionResolver} instance to test. + */ + @VisibleForTesting + public static void setDomainSelectionResolver(DomainSelectionResolver resolver) { + sInstance = resolver; + } + + /** + * Testing interface for injecting mock DomainSelectionController. + */ + @VisibleForTesting + public interface DomainSelectionControllerFactory { + /** + * Returns a {@link DomainSelectionController} created using the specified + * context and {@link DomainSelectionService} instance. + */ + DomainSelectionController create(@NonNull Context context, + @NonNull DomainSelectionService service); + } + + private DomainSelectionControllerFactory mDomainSelectionControllerFactory = + new DomainSelectionControllerFactory() { + @Override + public DomainSelectionController create(@NonNull Context context, + @NonNull DomainSelectionService service) { + return new DomainSelectionController(context, service); + } + }; + + // Persistent Logging + private final LocalLog mEventLog = new LocalLog(10); + private final Context mContext; + // The flag to indicate whether the device supports the domain selection service or not. + private final boolean mDeviceConfigEnabled; + // DomainSelectionController, which are bound to DomainSelectionService. + private DomainSelectionController mController; + + public DomainSelectionResolver(Context context, boolean deviceConfigEnabled) { + mContext = context; + mDeviceConfigEnabled = deviceConfigEnabled; + logi("DomainSelectionResolver created: device-config=" + deviceConfigEnabled); + } + + /** + * Checks if the device supports the domain selection service to route the call / SMS / + * supplementary services to the appropriate domain. + * This checks the device-config and Radio HAL version for supporting the domain selection. + * The domain selection requires the Radio HAL version greater than or equal to 2.1. + * + * @return {@code true} if the domain selection is supported on the device, + * {@code false} otherwise. + */ + public boolean isDomainSelectionSupported() { + return mDeviceConfigEnabled && PhoneFactory.getDefaultPhone() + .getHalVersion(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1); + } + + /** + * Returns a {@link DomainSelectionConnection} instance. + * + * @param phone The Phone instance for witch this request is. + * @param selectorType Indicates the selector type requested. + * @param isEmergency Indicates whether this is for emergency service. + * @throws IllegalStateException If the {@link DomainSelectionController} is not created + * because {@link #initialize} method is not called even if the domain selection is + * supported. + * @return A {@link DomainSelectionConnection} instance if the device supports + * AOSP domain selection and IMS is available or {@code null} otherwise. + */ + public @Nullable DomainSelectionConnection getDomainSelectionConnection(Phone phone, + @DomainSelectionService.SelectorType int selectorType, boolean isEmergency) { + if (mController == null) { + // If the caller calls this method without checking whether the domain selection + // is supported or not, this exception will be thrown. + throw new IllegalStateException("DomainSelection is not supported!"); + } + + if (phone == null || !phone.isImsAvailable()) { + // If ImsPhone is null or the binder of ImsService is not available, + // CS domain is used for the telephony services. + return null; + } + + return mController.getDomainSelectionConnection(phone, selectorType, isEmergency); + } + + /** Sets a factory interface for creating {@link DomainSelectionController} instance. */ + @VisibleForTesting + public void setDomainSelectionControllerFactory(DomainSelectionControllerFactory factory) { + mDomainSelectionControllerFactory = factory; + } + + /** + * Needs to be called after the constructor to create a {@link DomainSelectionController} that + * is bound to the given {@link DomainSelectionService}. + * + * @param service A {@link DomainSelectionService} to be bound. + */ + public void initialize(@NonNull DomainSelectionService service) { + logi("Initialize."); + mController = mDomainSelectionControllerFactory.create(mContext, service); + } + + /** + * Dumps this instance into a readable format for dumpsys usage. + */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + ipw.println("Resolver:"); + ipw.increaseIndent(); + ipw.println("Event Log:"); + ipw.increaseIndent(); + mEventLog.dump(ipw); + ipw.decreaseIndent(); + ipw.decreaseIndent(); + + ipw.println("Controller:"); + ipw.increaseIndent(); + DomainSelectionController controller = mController; + if (controller == null) { + ipw.println("no active controller"); + } else { + controller.dump(ipw); + } + ipw.decreaseIndent(); + } + + private void logi(String s) { + Log.i(TAG, s); + mEventLog.log(s); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionResolverTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionResolverTest.java new file mode 100644 index 0000000000..2c65b50303 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/DomainSelectionResolverTest.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING; +import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; + +import static com.android.internal.telephony.RIL.RADIO_HAL_VERSION_2_0; +import static com.android.internal.telephony.RIL.RADIO_HAL_VERSION_2_1; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.telephony.DomainSelectionService; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.HalVersion; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +/** + * Unit tests for DomainSelectionResolver. + */ +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DomainSelectionResolverTest extends TelephonyTest { + // Mock classes + private DomainSelectionController mDsController; + private DomainSelectionConnection mDsConnection; + private DomainSelectionService mDsService; + + private DomainSelectionResolver mDsResolver; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + + mDsController = Mockito.mock(DomainSelectionController.class); + mDsConnection = Mockito.mock(DomainSelectionConnection.class); + mDsService = Mockito.mock(DomainSelectionService.class); + } + + @After + public void tearDown() throws Exception { + mDsResolver = null; + mDsService = null; + mDsConnection = null; + mDsController = null; + super.tearDown(); + } + + @Test + @SmallTest + public void testGetInstance() throws IllegalStateException { + assertThrows(IllegalStateException.class, () -> { + DomainSelectionResolver.getInstance(); + }); + + DomainSelectionResolver.make(mContext, true); + DomainSelectionResolver resolver = DomainSelectionResolver.getInstance(); + + assertNotNull(resolver); + } + + @Test + @SmallTest + public void testIsDomainSelectionSupportedWhenDeviceConfigDisabled() { + setUpResolver(false, RADIO_HAL_VERSION_2_1); + + assertFalse(mDsResolver.isDomainSelectionSupported()); + } + + @Test + @SmallTest + public void testIsDomainSelectionSupportedWhenHalVersionLessThan20() { + setUpResolver(true, RADIO_HAL_VERSION_2_0); + + assertFalse(mDsResolver.isDomainSelectionSupported()); + } + + @Test + @SmallTest + public void testIsDomainSelectionSupported() { + setUpResolver(true, RADIO_HAL_VERSION_2_1); + + assertTrue(mDsResolver.isDomainSelectionSupported()); + } + + @Test + @SmallTest + public void testGetDomainSelectionConnectionWhenNotInitialized() throws Exception { + setUpResolver(true, RADIO_HAL_VERSION_2_1); + + assertThrows(IllegalStateException.class, () -> { + mDsResolver.getDomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true); + }); + } + + @Test + @SmallTest + public void testGetDomainSelectionConnectionWhenPhoneNull() throws Exception { + setUpResolver(true, RADIO_HAL_VERSION_2_1); + mDsResolver.initialize(mDsService); + assertNull(mDsResolver.getDomainSelectionConnection(null, SELECTOR_TYPE_CALLING, true)); + } + + @Test + @SmallTest + public void testGetDomainSelectionConnectionWhenImsNotAvailable() throws Exception { + setUpResolver(true, RADIO_HAL_VERSION_2_1); + mDsResolver.initialize(mDsService); + when(mPhone.isImsAvailable()).thenReturn(false); + + assertNull(mDsResolver.getDomainSelectionConnection(mPhone, SELECTOR_TYPE_CALLING, true)); + } + + @Test + @SmallTest + public void testGetDomainSelectionConnection() throws Exception { + setUpResolver(true, RADIO_HAL_VERSION_2_1); + setUpController(); + mDsResolver.initialize(mDsService); + when(mPhone.isImsAvailable()).thenReturn(true); + + assertNotNull(mDsResolver.getDomainSelectionConnection( + mPhone, SELECTOR_TYPE_CALLING, true)); + } + + private void setUpResolver(boolean deviceConfigEnabled, HalVersion halVersion) { + mDsResolver = new DomainSelectionResolver(mContext, deviceConfigEnabled); + when(mPhone.getHalVersion(eq(HAL_SERVICE_NETWORK))).thenReturn(halVersion); + } + + private void setUpController() { + mDsResolver.setDomainSelectionControllerFactory( + new DomainSelectionResolver.DomainSelectionControllerFactory() { + @Override + public DomainSelectionController create(Context context, + DomainSelectionService service) { + return mDsController; + } + }); + + when(mDsController.getDomainSelectionConnection(any(Phone.class), anyInt(), anyBoolean())) + .thenReturn(mDsConnection); + } +} -- GitLab From be93e4ded6c8bf988c8b8eda0bb96826509c424a Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Mon, 12 Dec 2022 22:11:25 +0000 Subject: [PATCH 262/656] Add portIndex to EuiccService#GetMetaData API Include portIndex in metadata API to perform port sensitive operations. Test: Manual test on Pixel 7, atest FrameworksTelephonyTests Bug: 247657227 Change-Id: Id7c68885777b91ee4f869ddfb1cee815c5e919e4 --- .../internal/telephony/euicc/EuiccConnector.java | 10 ++++++++-- .../internal/telephony/euicc/EuiccController.java | 12 ++++++++---- .../telephony/euicc/EuiccControllerTest.java | 10 +++++----- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/java/com/android/internal/telephony/euicc/EuiccConnector.java b/src/java/com/android/internal/telephony/euicc/EuiccConnector.java index 96a9328bce..7d46a9ac78 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccConnector.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccConnector.java @@ -225,6 +225,8 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { static class GetMetadataRequest { DownloadableSubscription mSubscription; boolean mForceDeactivateSim; + boolean mSwitchAfterDownload; + int mPortIndex; GetMetadataCommandCallback mCallback; } @@ -447,13 +449,15 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { /** Asynchronously fetch metadata for the given downloadable subscription. */ @VisibleForTesting(visibility = PACKAGE) - public void getDownloadableSubscriptionMetadata(int cardId, - DownloadableSubscription subscription, + public void getDownloadableSubscriptionMetadata(int cardId, int portIndex, + DownloadableSubscription subscription, boolean switchAfterDownload, boolean forceDeactivateSim, GetMetadataCommandCallback callback) { GetMetadataRequest request = new GetMetadataRequest(); request.mSubscription = subscription; request.mForceDeactivateSim = forceDeactivateSim; + request.mSwitchAfterDownload = switchAfterDownload; + request.mPortIndex = portIndex; request.mCallback = callback; sendMessage(CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA, cardId, 0 /* arg2 */, request); } @@ -752,7 +756,9 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { case CMD_GET_DOWNLOADABLE_SUBSCRIPTION_METADATA: { GetMetadataRequest request = (GetMetadataRequest) message.obj; mEuiccService.getDownloadableSubscriptionMetadata(slotId, + request.mPortIndex, request.mSubscription, + request.mSwitchAfterDownload, request.mForceDeactivateSim, new IGetDownloadableSubscriptionMetadataCallback.Stub() { @Override diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java index 9b4894e80a..a3d3056019 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccController.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java @@ -386,6 +386,7 @@ public class EuiccController extends IEuiccController.Stub { void getDownloadableSubscriptionMetadata(int cardId, DownloadableSubscription subscription, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) { + Log.d(TAG, " getDownloadableSubscriptionMetadata callingPackage: " + callingPackage); if (!callerCanWriteEmbeddedSubscriptions()) { throw new SecurityException("Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get metadata"); } @@ -393,7 +394,8 @@ public class EuiccController extends IEuiccController.Stub { long token = Binder.clearCallingIdentity(); try { mConnector.getDownloadableSubscriptionMetadata(cardId, - subscription, forceDeactivateSim, + TelephonyManager.DEFAULT_PORT_INDEX, subscription, + false /* switchAfterDownload */, forceDeactivateSim, new GetMetadataCommandCallback( token, subscription, callingPackage, callbackIntent)); } finally { @@ -602,8 +604,8 @@ public class EuiccController extends IEuiccController.Stub { if (!isConsentNeededToResolvePortIndex && canManageSubscriptionOnTargetSim(cardId, callingPackage, true, portIndex)) { - mConnector.getDownloadableSubscriptionMetadata(cardId, subscription, - forceDeactivateSim, + mConnector.getDownloadableSubscriptionMetadata(cardId, portIndex, + subscription, switchAfterDownload, forceDeactivateSim, new DownloadSubscriptionGetMetadataCommandCallback(token, subscription, switchAfterDownload, callingPackage, forceDeactivateSim, callbackIntent, false /* withUserConsent */, portIndex)); @@ -714,7 +716,8 @@ public class EuiccController extends IEuiccController.Stub { Log.d(TAG, " downloadSubscriptionPrivilegedCheckMetadata cardId: " + cardId + " switchAfterDownload: " + switchAfterDownload + " portIndex: " + portIndex + " forceDeactivateSim: " + forceDeactivateSim); - mConnector.getDownloadableSubscriptionMetadata(cardId, subscription, forceDeactivateSim, + mConnector.getDownloadableSubscriptionMetadata(cardId, portIndex, + subscription, switchAfterDownload, forceDeactivateSim, new DownloadSubscriptionGetMetadataCommandCallback(callingToken, subscription, switchAfterDownload, callingPackage, forceDeactivateSim, callbackIntent, true /* withUserConsent */, portIndex)); @@ -863,6 +866,7 @@ public class EuiccController extends IEuiccController.Stub { void getDefaultDownloadableSubscriptionList(int cardId, boolean forceDeactivateSim, String callingPackage, PendingIntent callbackIntent) { + Log.d(TAG, " getDefaultDownloadableSubscriptionList callingPackage: " + callingPackage); if (!callerCanWriteEmbeddedSubscriptions()) { throw new SecurityException( "Must have WRITE_EMBEDDED_SUBSCRIPTIONS to get default list"); 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 600c94a6d3..62b665360c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java @@ -318,8 +318,8 @@ public class EuiccControllerTest extends TelephonyTest { SUBSCRIPTION, false /* complete */, null /* result */); verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0 /* detailedCode */); - verify(mMockConnector).getDownloadableSubscriptionMetadata(anyInt(), any(), anyBoolean(), - any()); + verify(mMockConnector).getDownloadableSubscriptionMetadata(anyInt(), anyInt(), any(), + anyBoolean(), anyBoolean(), any()); } @Test @@ -1492,7 +1492,7 @@ public class EuiccControllerTest extends TelephonyTest { @Override public Void answer(InvocationOnMock invocation) throws Exception { EuiccConnector.GetMetadataCommandCallback cb = invocation - .getArgument(3 /* resultCallback */); + .getArgument(5 /* resultCallback */); if (complete) { cb.onGetMetadataComplete(CARD_ID, result); } else { @@ -1500,8 +1500,8 @@ public class EuiccControllerTest extends TelephonyTest { } return null; } - }).when(mMockConnector).getDownloadableSubscriptionMetadata(anyInt(), any(), anyBoolean(), - any()); + }).when(mMockConnector).getDownloadableSubscriptionMetadata(anyInt(), anyInt(), any(), + anyBoolean(), anyBoolean(), any()); } private void callGetDownloadableSubscriptionMetadata(DownloadableSubscription subscription, -- GitLab From 24f9dfaa421eb6275d9b0053927a51ec545a0244 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 10 Dec 2022 02:16:15 -0800 Subject: [PATCH 263/656] Support get/set subscription property 1. Support getSubscriptionProperty. 2. Added group update support. Setting some fields in the subscription will automatically apply to the other subscriptions in the group. Bug: 239607619 Test: atest SubscriptionManagerServiceTest atest SubscriptionDatabaseManagerTest Change-Id: I7f11230398183a54a766d0b6c19a0e36dae70d6d --- .../SubscriptionDatabaseManager.java | 510 +++++++++++++++--- .../SubscriptionInfoInternal.java | 21 +- .../SubscriptionManagerService.java | 175 ++++-- .../SubscriptionDatabaseManagerTest.java | 448 +++++++++++++-- .../SubscriptionManagerServiceTest.java | 469 ++++++++++++++++ 5 files changed, 1473 insertions(+), 150 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 2b59a83bc4..dd1c083353 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -20,12 +20,14 @@ import android.annotation.CallbackExecutor; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.os.Handler; import android.os.Looper; +import android.os.ParcelUuid; import android.provider.Telephony; import android.provider.Telephony.SimInfo; import android.telephony.SubscriptionInfo; @@ -37,15 +39,16 @@ import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyManager; -import android.telephony.UiccAccessRule; import android.telephony.ims.ImsMmTelManager; import android.text.TextUtils; +import android.util.Base64; import android.util.IndentingPrintWriter; import android.util.LocalLog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.uicc.UiccController; +import com.android.internal.util.function.TriConsumer; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -56,6 +59,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -83,6 +87,7 @@ public class SubscriptionDatabaseManager extends Handler { /** The mapping from {@link SimInfo} table to {@link SubscriptionInfoInternal} get methods. */ private static final Map> + // TODO: Support SimInfo.COLUMN_CB_XXX which are still used by wear. SUBSCRIPTION_GET_METHOD_MAP = Map.ofEntries( new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, @@ -230,6 +235,227 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal::getUserId) ); + /** + * The mapping from columns in {@link android.provider.Telephony.SimInfo} table to + * {@link SubscriptionDatabaseManager} setting integer methods. + */ + private static final Map> + SUBSCRIPTION_SET_INTEGER_METHOD_MAP = Map.ofEntries( + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_SIM_SLOT_INDEX, + SubscriptionDatabaseManager::setSimSlotIndex), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_NAME_SOURCE, + SubscriptionDatabaseManager::setDisplayNameSource), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_COLOR, + SubscriptionDatabaseManager::setIconTint), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_DATA_ROAMING, + SubscriptionDatabaseManager::setDataRoaming), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_EMBEDDED, + SubscriptionDatabaseManager::setEmbedded), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_REMOVABLE, + SubscriptionDatabaseManager::setRemovableEmbedded), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, + SubscriptionDatabaseManager::setEnhanced4GModeEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_VT_IMS_ENABLED, + SubscriptionDatabaseManager::setVideoTelephonyEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_ENABLED, + SubscriptionDatabaseManager::setWifiCallingEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_MODE, + SubscriptionDatabaseManager::setWifiCallingMode), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, + SubscriptionDatabaseManager::setWifiCallingModeForRoaming), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, + SubscriptionDatabaseManager::setWifiCallingEnabledForRoaming), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IS_OPPORTUNISTIC, + SubscriptionDatabaseManager::setOpportunistic), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CARRIER_ID, + SubscriptionDatabaseManager::setCarrierId), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PROFILE_CLASS, + SubscriptionDatabaseManager::setProfileClass), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_SUBSCRIPTION_TYPE, + SubscriptionDatabaseManager::setSubscriptionType), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED, + SubscriptionDatabaseManager::setUiccApplicationsEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, + SubscriptionDatabaseManager::setRcsUceEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, + SubscriptionDatabaseManager::setCrossSimCallingEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_D2D_STATUS_SHARING, + SubscriptionDatabaseManager::setDeviceToDeviceStatusSharingPreference), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, + SubscriptionDatabaseManager::setVoImsOptInEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, + SubscriptionDatabaseManager::setNrAdvancedCallingEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PORT_INDEX, + SubscriptionDatabaseManager::setPortIndex), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_USAGE_SETTING, + SubscriptionDatabaseManager::setUsageSetting), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_TP_MESSAGE_REF, + SubscriptionDatabaseManager::setLastUsedTPMessageReference), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_USER_HANDLE, + SubscriptionDatabaseManager::setUserId) + ); + + /** + * The mapping from columns in {@link android.provider.Telephony.SimInfo} table to + * {@link SubscriptionDatabaseManager} setting string methods. + */ + private static final Map> + SUBSCRIPTION_SET_STRING_METHOD_MAP = Map.ofEntries( + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ICC_ID, + SubscriptionDatabaseManager::setIccId), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_DISPLAY_NAME, + SubscriptionDatabaseManager::setDisplayName), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CARRIER_NAME, + SubscriptionDatabaseManager::setCarrierName), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_NUMBER, + SubscriptionDatabaseManager::setNumber), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_MCC_STRING, + SubscriptionDatabaseManager::setMcc), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_MNC_STRING, + SubscriptionDatabaseManager::setMnc), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_EHPLMNS, + SubscriptionDatabaseManager::setEhplmns), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_HPLMNS, + SubscriptionDatabaseManager::setHplmns), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CARD_ID, + SubscriptionDatabaseManager::setCardString), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_GROUP_UUID, + SubscriptionDatabaseManager::setGroupUuid), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ISO_COUNTRY_CODE, + SubscriptionDatabaseManager::setCountryIso), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_GROUP_OWNER, + SubscriptionDatabaseManager::setGroupOwner), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, + SubscriptionDatabaseManager::setEnabledMobileDataPolicies), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_IMSI, + SubscriptionDatabaseManager::setImsi), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, + SubscriptionDatabaseManager::setAllowedNetworkTypesForReasons), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + SubscriptionDatabaseManager::setDeviceToDeviceStatusSharingContacts), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER, + SubscriptionDatabaseManager::setNumberFromCarrier), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS, + SubscriptionDatabaseManager::setNumberFromIms) + ); + + /** + * The mapping from columns in {@link android.provider.Telephony.SimInfo} table to + * {@link SubscriptionDatabaseManager} setting byte array methods. + */ + private static final Map> + SUBSCRIPTION_SET_BYTE_ARRAY_METHOD_MAP = Map.ofEntries( + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ACCESS_RULES, + SubscriptionDatabaseManager::setNativeAccessRules), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, + SubscriptionDatabaseManager::setCarrierConfigAccessRules), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_RCS_CONFIG, + SubscriptionDatabaseManager::setRcsConfig) + ); + + /** + * The columns that should be in-sync between the subscriptions in the same group. Changing + * the value in those fields will automatically apply to the rest of the subscriptions in the + * group. + * + * @see SubscriptionManager#getSubscriptionsInGroup(ParcelUuid) + */ + private static final Set GROUP_SHARING_COLUMNS = Set.of( + SimInfo.COLUMN_DISPLAY_NAME, + SimInfo.COLUMN_NAME_SOURCE, + SimInfo.COLUMN_COLOR, + SimInfo.COLUMN_DATA_ROAMING, + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, + SimInfo.COLUMN_VT_IMS_ENABLED, + SimInfo.COLUMN_WFC_IMS_ENABLED, + SimInfo.COLUMN_WFC_IMS_MODE, + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, + SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, + SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED, + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, + SimInfo.COLUMN_RCS_CONFIG, + SimInfo.COLUMN_D2D_STATUS_SHARING, + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, + SimInfo.COLUMN_USER_HANDLE + ); + + /** + * The deprecated columns that do not have corresponding set methods in + * {@link SubscriptionDatabaseManager}. + */ + private static final Set DEPRECATED_DATABASE_COLUMNS = Set.of( + SimInfo.COLUMN_DISPLAY_NUMBER_FORMAT, + SimInfo.COLUMN_MCC, + SimInfo.COLUMN_MNC, + SimInfo.COLUMN_SIM_PROVISIONING_STATUS, + SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT, + SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT, + SimInfo.COLUMN_CB_AMBER_ALERT, + SimInfo.COLUMN_CB_EMERGENCY_ALERT, + SimInfo.COLUMN_CB_ALERT_SOUND_DURATION, + SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL, + SimInfo.COLUMN_CB_ALERT_VIBRATE, + SimInfo.COLUMN_CB_ALERT_SPEECH, + SimInfo.COLUMN_CB_ETWS_TEST_ALERT, + SimInfo.COLUMN_CB_CHANNEL_50_ALERT, + SimInfo.COLUMN_CB_CMAS_TEST_ALERT, + SimInfo.COLUMN_CB_OPT_OUT_DIALOG, + SimInfo.COLUMN_IS_METERED, + SimInfo.COLUMN_DATA_ENABLED_OVERRIDE_RULES, + SimInfo.COLUMN_ALLOWED_NETWORK_TYPES + ); + /** The context */ @NonNull private final Context mContext; @@ -351,16 +577,94 @@ public class SubscriptionDatabaseManager extends Handler { * {@link SubscriptionInfoInternal} (except for unused or deprecated columns). * * @param subInfo The subscription info. - * @param columnName The corresponding database column name. + * @param columnName The database column name. * * @return The corresponding value from {@link SubscriptionInfoInternal}. + * + * @throws IllegalArgumentException if {@code columnName} is invalid. + * + * @see android.provider.Telephony.SimInfo for all the columns. */ - private Object getSubscriptionInfoFieldByColumnName(@NonNull SubscriptionInfoInternal subInfo, - @NonNull String columnName) { + @NonNull + private static Object getSubscriptionInfoFieldByColumnName( + @NonNull SubscriptionInfoInternal subInfo, @NonNull String columnName) { if (SUBSCRIPTION_GET_METHOD_MAP.containsKey(columnName)) { return SUBSCRIPTION_GET_METHOD_MAP.get(columnName).apply(subInfo); } - return null; + throw new IllegalArgumentException("Invalid column name " + columnName); + } + + /** + * Get a specific field from the subscription database by {@code subId} and {@code columnName}. + * + * @param subId The subscription id. + * @param columnName The database column name. + * + * @return The value from subscription database. + * + * @throws IllegalArgumentException if {@code subId} or {@code columnName} is invalid. + * + * @see android.provider.Telephony.SimInfo for all the columns. + */ + @NonNull + public Object getSubscriptionProperty(int subId, @NonNull String columnName) { + SubscriptionInfoInternal subInfo = getSubscriptionInfoInternal(subId); + if (subInfo == null) { + throw new IllegalArgumentException("Invalid subId " + subId); + } + + return getSubscriptionInfoFieldByColumnName(subInfo, columnName); + } + + /** + * Set a field in the subscription database. Note not all fields are supported. + * + * @param subId Subscription Id of Subscription. + * @param columnName Column name in the database. Note not all fields are supported. + * @param value Value to store in the database. + * + * @throws IllegalArgumentException if {@code subId} or {@code columnName} is invalid, or + * {@code value} cannot be converted to the corresponding database column format. + * @throws NumberFormatException if a string value cannot be converted to integer. + * @throws ClassCastException if {@code value} cannot be casted to the required type. + * + * @see android.provider.Telephony.SimInfo for all the columns. + */ + public void setSubscriptionProperty(int subId, @NonNull String columnName, + @NonNull Object value) { + if (SUBSCRIPTION_SET_INTEGER_METHOD_MAP.containsKey(columnName)) { + // For integer type columns, accepting both integer and string that can be converted to + // integer. + int intValue; + if (value instanceof String) { + intValue = Integer.parseInt((String) value); + } else if (value instanceof Integer) { + intValue = (int) value; + } else { + throw new ClassCastException("columnName=" + columnName + ", cannot cast " + + value.getClass() + " to integer."); + } + SUBSCRIPTION_SET_INTEGER_METHOD_MAP.get(columnName).accept(this, subId, intValue); + } else if (SUBSCRIPTION_SET_STRING_METHOD_MAP.containsKey(columnName)) { + // For string type columns. Will throw exception if value is not string type. + SUBSCRIPTION_SET_STRING_METHOD_MAP.get(columnName).accept(this, subId, (String) value); + } else if (SUBSCRIPTION_SET_BYTE_ARRAY_METHOD_MAP.containsKey(columnName)) { + // For byte array type columns, accepting both byte[] and string that can be converted + // to byte[] using base 64 encoding/decoding. + byte[] byteArrayValue; + if (value instanceof String) { + byteArrayValue = Base64.decode((String) value, Base64.DEFAULT); + } else if (value instanceof byte[]) { + byteArrayValue = (byte[]) value; + } else { + throw new ClassCastException("columnName=" + columnName + ", cannot cast " + + value.getClass() + " to byte[]."); + } + SUBSCRIPTION_SET_BYTE_ARRAY_METHOD_MAP.get(columnName).accept( + this, subId, byteArrayValue); + } else { + throw new IllegalArgumentException("Does not support set " + columnName + "."); + } } /** @@ -379,6 +683,7 @@ public class SubscriptionDatabaseManager extends Handler { ContentValues deltaContentValues = new ContentValues(); for (String columnName : Telephony.SimInfo.getAllColumns()) { + if (DEPRECATED_DATABASE_COLUMNS.contains(columnName)) continue; Object newValue = getSubscriptionInfoFieldByColumnName(newSubInfo, columnName); if (newValue != null) { Object oldValue = null; @@ -520,38 +825,49 @@ public class SubscriptionDatabaseManager extends Handler { BiFunction builderSetMethod) { ContentValues contentValues = new ContentValues(); - SubscriptionInfoInternal oldSubInfo; // Grab the write lock so no other threads can read or write the cache. mReadWriteLock.writeLock().lock(); try { - oldSubInfo = mAllSubscriptionInfoInternalCache.get(subId); - if (oldSubInfo != null) { - // Check if the new value is different from the old value in the cache. - if (!Objects.equals(getSubscriptionInfoFieldByColumnName(oldSubInfo, columnName), - newValue)) { - // If the value is different, then we need to update the cache. Since all fields - // in SubscriptionInfo is final, so we need to create a new SubscriptionInfo. - SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal - .Builder(oldSubInfo); - - // Apply the new value to the builder. This line is equivalent to - // builder.setXxxxxx(newValue); - builder = builderSetMethod.apply(builder, newValue); - - // Prepare the content value for update. - contentValues.putObject(columnName, newValue); - if (updateDatabase(subId, contentValues) > 0) { - // Update the subscription database cache. - mAllSubscriptionInfoInternalCache.put(subId, builder.build()); - mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); - } - } - } else { + final SubscriptionInfoInternal oldSubInfo = + mAllSubscriptionInfoInternalCache.get(subId); + if (oldSubInfo == null) { logel("Subscription doesn't exist. subId=" + subId + ", columnName=" + columnName); throw new IllegalArgumentException("Subscription doesn't exist. subId=" + subId + ", columnName=" + columnName); } + + // Check if writing this field should automatically write to the rest of subscriptions + // in the same group. + final boolean syncToGroup = GROUP_SHARING_COLUMNS.contains(columnName); + + mAllSubscriptionInfoInternalCache.forEach((id, subInfo) -> { + if (id == subId || (syncToGroup && !oldSubInfo.getGroupUuid().isEmpty() + && oldSubInfo.getGroupUuid().equals(subInfo.getGroupUuid()))) { + // Check if the new value is different from the old value in the cache. + if (!Objects.equals(getSubscriptionInfoFieldByColumnName(subInfo, columnName), + newValue)) { + // If the value is different, then we need to update the cache. Since all + // fields in SubscriptionInfo are final, we need to create a new + // SubscriptionInfo. + SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal + .Builder(subInfo); + + // Apply the new value to the builder. This line is equivalent to + // builder.setXxxxxx(newValue); + builder = builderSetMethod.apply(builder, newValue); + + // Prepare the content value for update. + contentValues.putObject(columnName, newValue); + if (updateDatabase(id, contentValues) > 0) { + // Update the subscription database cache. + mAllSubscriptionInfoInternalCache.put(id, builder.build()); + mCallback.invokeFromExecutor(() + -> mCallback.onSubscriptionChanged(subId)); + } + } + } + }); } finally { mReadWriteLock.writeLock().unlock(); } @@ -743,9 +1059,9 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setEhplmns(int subId, @NonNull String[] ehplmns) { + public void setEhplmns(int subId, @NonNull String ehplmns) { Objects.requireNonNull(ehplmns); - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_EHPLMNS, TextUtils.join(",", ehplmns), + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_EHPLMNS, ehplmns, SubscriptionInfoInternal.Builder::setEhplmns); } @@ -757,12 +1073,25 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setHplmns(int subId, @NonNull String[] hplmns) { + public void setHplmns(int subId, @NonNull String hplmns) { Objects.requireNonNull(hplmns); - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_HPLMNS, TextUtils.join(",", hplmns), + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_HPLMNS, hplmns, SubscriptionInfoInternal.Builder::setHplmns); } + /** + * Set whether the subscription is from eSIM or not. + * + * @param subId Subscription id. + * @param isEmbedded if the subscription is from eSIM. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setEmbedded(int subId, int isEmbedded) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_EMBEDDED, isEmbedded, + SubscriptionInfoInternal.Builder::setEmbedded); + } + /** * Set whether the subscription is from eSIM or not. * @@ -772,8 +1101,7 @@ public class SubscriptionDatabaseManager extends Handler { * @throws IllegalArgumentException if the subscription does not exist. */ public void setEmbedded(int subId, boolean isEmbedded) { - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_EMBEDDED, isEmbedded ? 1 : 0, - SubscriptionInfoInternal.Builder::setEmbedded); + setEmbedded(subId, isEmbedded ? 1 : 0); } /** @@ -832,10 +1160,9 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setNativeAccessRules(int subId, @NonNull UiccAccessRule[] nativeAccessRules) { + public void setNativeAccessRules(int subId, @NonNull byte[] nativeAccessRules) { Objects.requireNonNull(nativeAccessRules); - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES, - UiccAccessRule.encodeRules(nativeAccessRules), + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES, nativeAccessRules, SubscriptionInfoInternal.Builder::setNativeAccessRules); } @@ -848,27 +1175,25 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setCarrierConfigAccessRules(int subId, - @NonNull UiccAccessRule[] carrierConfigAccessRules) { + public void setCarrierConfigAccessRules(int subId, @NonNull byte[] carrierConfigAccessRules) { Objects.requireNonNull(carrierConfigAccessRules); writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, - UiccAccessRule.encodeRules(carrierConfigAccessRules), + carrierConfigAccessRules, SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules); } /** * Set whether an embedded subscription is on a removable card. Such subscriptions are * marked inaccessible as soon as the current card is removed. Otherwise, they will remain - * accessible unless explicitly deleted. Only meaningful when for embedded subscription. + * accessible unless explicitly deleted. Only meaningful for embedded subscription. * * @param subId Subscription id. - * @param isRemovableEmbedded {@code true} if the subscription is from the removable - * embedded SIM. + * @param isRemovableEmbedded if the subscription is from the removable embedded SIM. * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setRemovableEmbedded(int subId, boolean isRemovableEmbedded) { - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_REMOVABLE, isRemovableEmbedded ? 1 : 0, + public void setRemovableEmbedded(int subId, int isRemovableEmbedded) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_REMOVABLE, isRemovableEmbedded, SubscriptionInfoInternal.Builder::setRemovableEmbedded); } @@ -880,9 +1205,9 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setEnhanced4GModeEnabled(int subId, boolean isEnhanced4GModeEnabled) { + public void setEnhanced4GModeEnabled(int subId, int isEnhanced4GModeEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, - isEnhanced4GModeEnabled ? 1 : 0, + isEnhanced4GModeEnabled, SubscriptionInfoInternal.Builder::setEnhanced4GModeEnabled); } @@ -894,9 +1219,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setVideoTelephonyEnabled(int subId, boolean isVideoTelephonyEnabled) { - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VT_IMS_ENABLED, - isVideoTelephonyEnabled ? 1 : 0, + public void setVideoTelephonyEnabled(int subId, int isVideoTelephonyEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VT_IMS_ENABLED, isVideoTelephonyEnabled, SubscriptionInfoInternal.Builder::setVideoTelephonyEnabled); } @@ -909,9 +1233,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setWifiCallingEnabled(int subId, boolean isWifiCallingEnabled) { - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ENABLED, - isWifiCallingEnabled ? 1 : 0, + public void setWifiCallingEnabled(int subId, int isWifiCallingEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ENABLED, isWifiCallingEnabled, SubscriptionInfoInternal.Builder::setWifiCallingEnabled); } @@ -953,9 +1276,9 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setWifiCallingEnabledForRoaming(int subId, boolean isWifiCallingEnabledForRoaming) { + public void setWifiCallingEnabledForRoaming(int subId, int isWifiCallingEnabledForRoaming) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, - isWifiCallingEnabledForRoaming ? 1 : 0, + isWifiCallingEnabledForRoaming, SubscriptionInfoInternal.Builder::setWifiCallingEnabledForRoaming); } @@ -963,12 +1286,24 @@ public class SubscriptionDatabaseManager extends Handler { * Set whether the subscription is opportunistic or not. * * @param subId Subscription id. - * @param isOpportunistic {@code true} if the subscription is opportunistic. + * @param isOpportunistic if the subscription is opportunistic. * * @throws IllegalArgumentException if the subscription does not exist. */ public void setOpportunistic(int subId, boolean isOpportunistic) { - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_OPPORTUNISTIC, isOpportunistic ? 1 : 0, + setOpportunistic(subId, isOpportunistic ? 1 : 0); + } + + /** + * Set whether the subscription is opportunistic or not. + * + * @param subId Subscription id. + * @param isOpportunistic if the subscription is opportunistic. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setOpportunistic(int subId, int isOpportunistic) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IS_OPPORTUNISTIC, isOpportunistic, SubscriptionInfoInternal.Builder::setOpportunistic); } @@ -1092,14 +1427,25 @@ public class SubscriptionDatabaseManager extends Handler { * Set whether Uicc applications are configured to enable or not. * * @param subId Subscription id. - * @param areUiccApplicationsEnabled {@code true} if Uicc applications are configured to - * enable. + * @param areUiccApplicationsEnabled if Uicc applications are configured to enable. * * @throws IllegalArgumentException if the subscription does not exist. */ public void setUiccApplicationsEnabled(int subId, boolean areUiccApplicationsEnabled) { + setUiccApplicationsEnabled(subId, areUiccApplicationsEnabled ? 1 : 0); + } + + /** + * Set whether Uicc applications are configured to enable or not. + * + * @param subId Subscription id. + * @param areUiccApplicationsEnabled if Uicc applications are configured to enable. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setUiccApplicationsEnabled(int subId, int areUiccApplicationsEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED, - areUiccApplicationsEnabled ? 1 : 0, + areUiccApplicationsEnabled, SubscriptionInfoInternal.Builder::setUiccApplicationsEnabled); } @@ -1112,9 +1458,9 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setRcsUceEnabled(int subId, boolean isRcsUceEnabled) { - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, - isRcsUceEnabled ? 1 : 0, SubscriptionInfoInternal.Builder::setRcsUceEnabled); + public void setRcsUceEnabled(int subId, int isRcsUceEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, isRcsUceEnabled, + SubscriptionInfoInternal.Builder::setRcsUceEnabled); } /** @@ -1126,9 +1472,9 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setCrossSimCallingEnabled(int subId, boolean isCrossSimCallingEnabled) { + public void setCrossSimCallingEnabled(int subId, int isCrossSimCallingEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, - isCrossSimCallingEnabled ? 1 : 0, + isCrossSimCallingEnabled, SubscriptionInfoInternal.Builder::setCrossSimCallingEnabled); } @@ -1187,9 +1533,8 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setVoImsOptInEnabled(int subId, boolean isVoImsOptInEnabled) { - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, - isVoImsOptInEnabled ? 1 : 0, + public void setVoImsOptInEnabled(int subId, int isVoImsOptInEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, isVoImsOptInEnabled, SubscriptionInfoInternal.Builder::setVoImsOptInEnabled); } @@ -1218,9 +1563,9 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setNrAdvancedCallingEnabled(int subId, boolean isNrAdvancedCallingEnabled) { + public void setNrAdvancedCallingEnabled(int subId, int isNrAdvancedCallingEnabled) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, - isNrAdvancedCallingEnabled ? 1 : 0, + isNrAdvancedCallingEnabled, SubscriptionInfoInternal.Builder::setNrAdvancedCallingEnabled); } @@ -1300,7 +1645,7 @@ public class SubscriptionDatabaseManager extends Handler { * * @throws IllegalArgumentException if the subscription does not exist. */ - public void setUserId(int subId, int userId) { + public void setUserId(int subId, @UserIdInt int userId) { writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_USER_HANDLE, userId, SubscriptionInfoInternal.Builder::setUserId); } @@ -1465,6 +1810,27 @@ public class SubscriptionDatabaseManager extends Handler { return builder.build(); } + /** + * Sync the group sharing fields from reference subscription to the rest of the subscriptions in + * the same group. For example, if user enables wifi calling, the same setting should be applied + * to all subscriptions in the same group. + * + * @param subId The subscription id of reference subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void syncToGroup(int subId) { + if (!mAllSubscriptionInfoInternalCache.containsKey(subId)) { + throw new IllegalArgumentException("Invalid subId " + subId); + } + + for (String column : GROUP_SHARING_COLUMNS) { + // Get the value from the reference subscription, and set to itself again. + // writeDatabaseAndCacheHelper() will automatically sync to the rest of the group. + setSubscriptionProperty(subId, column, getSubscriptionProperty(subId, column)); + } + } + /** * Get the subscription info by subscription id. * diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 4e9a47f452..b0262b0271 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -33,6 +33,7 @@ package com.android.internal.telephony.subscription; import android.annotation.ColorInt; import android.annotation.NonNull; +import android.annotation.UserIdInt; import android.os.UserHandle; import android.provider.Telephony.SimInfo; import android.telephony.SubscriptionInfo; @@ -952,6 +953,7 @@ public class SubscriptionInfoInternal { /** * @return The user id associated with this subscription. */ + @UserIdInt public int getUserId() { return mUserId; } @@ -1800,6 +1802,23 @@ public class SubscriptionInfoInternal { return this; } + /** + * Set whether an embedded subscription is on a removable card. Such subscriptions are + * marked inaccessible as soon as the current card is removed. Otherwise, they will remain + * accessible unless explicitly deleted. Only meaningful when {@link #getEmbedded()} is + * {@code 1}. + * + * @param isRemovableEmbedded {@code true} if the subscription is from the removable + * embedded SIM. + * + * @return The builder. + */ + @NonNull + public Builder setRemovableEmbedded(boolean isRemovableEmbedded) { + mIsRemovableEmbedded = isRemovableEmbedded ? 1 : 0; + return this; + } + /** * Set whether an embedded subscription is on a removable card. Such subscriptions are * marked inaccessible as soon as the current card is removed. Otherwise, they will remain @@ -2207,7 +2226,7 @@ public class SubscriptionInfoInternal { * @return The builder. */ @NonNull - public Builder setUserId(int userId) { + public Builder setUserId(@UserIdInt int userId) { mUserId = userId; return this; } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index b560106045..be933e6a64 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -41,6 +41,7 @@ import android.os.RemoteException; import android.os.TelephonyServiceManager; import android.os.UserHandle; import android.provider.Settings; +import android.provider.Telephony.SimInfo; import android.service.carrier.CarrierIdentifier; import android.service.euicc.EuiccProfileInfo; import android.service.euicc.EuiccService; @@ -63,6 +64,7 @@ import android.telephony.UiccAccessRule; import android.telephony.euicc.EuiccManager; import android.text.TextUtils; import android.util.ArraySet; +import android.util.Base64; import android.util.EventLog; import android.util.IndentingPrintWriter; import android.util.LocalLog; @@ -110,6 +112,35 @@ public class SubscriptionManagerService extends ISub.Stub { /** Whether enabling verbose debugging message or not. */ private static final boolean VDBG = false; + /** + * The columns in {@link SimInfo} table that can be directly accessed through + * {@link #getSubscriptionProperty(int, String, String, String)} or + * {@link #setSubscriptionProperty(int, String, String)}. Usually those fields are not + * sensitive. Mostly they are related to user settings, for example, wifi calling + * user settings, cross sim calling user settings, etc...Those fields are protected with + * {@link Manifest.permission#READ_PHONE_STATE} permission only. + * + * For sensitive fields, they usually requires special methods to access. For example, + * {@link #getSubscriptionUserHandle(int)} or {@link #getPhoneNumber(int, int, String, String)} + * that requires higher permission to access. + */ + private static final Set DIRECT_ACCESS_SUBSCRIPTION_COLUMNS = Set.of( + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, + SimInfo.COLUMN_VT_IMS_ENABLED, + SimInfo.COLUMN_WFC_IMS_ENABLED, + SimInfo.COLUMN_WFC_IMS_MODE, + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, + SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, + SimInfo.COLUMN_RCS_CONFIG, + SimInfo.COLUMN_D2D_STATUS_SHARING, + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED + ); + /** * Apps targeting on Android T and beyond will get exception if there is no access to device * identifiers nor has carrier privileges when calling @@ -545,7 +576,7 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Sync the settings from specified subscription to all groupped subscriptions. + * Sync the settings from specified subscription to all grouped subscriptions. * * @param subId The subscription id of the referenced subscription. */ @@ -558,39 +589,7 @@ public class SubscriptionManagerService extends ISub.Stub { return; } - if (reference.getGroupUuid().isEmpty()) { - // The reference subscription is not in a group. No need to sync. - return; - } - - for (SubscriptionInfoInternal subInfo : mSubscriptionDatabaseManager - .getAllSubscriptions()) { - if (subInfo.getSubscriptionId() != subId - && subInfo.getGroupUuid().equals(reference.getGroupUuid())) { - // Copy all settings from reference sub to the grouped subscriptions. - SubscriptionInfoInternal newSubInfo = new SubscriptionInfoInternal - .Builder(subInfo) - .setEnhanced4GModeEnabled(reference.getEnhanced4GModeEnabled()) - .setVideoTelephonyEnabled(reference.getVideoTelephonyEnabled()) - .setWifiCallingEnabled(reference.getWifiCallingEnabled()) - .setWifiCallingModeForRoaming(reference.getWifiCallingModeForRoaming()) - .setWifiCallingMode(reference.getWifiCallingMode()) - .setWifiCallingEnabledForRoaming( - reference.getWifiCallingEnabledForRoaming()) - .setDataRoaming(reference.getDataRoaming()) - .setDisplayName(reference.getDisplayName()) - .setEnabledMobileDataPolicies(reference.getEnabledMobileDataPolicies()) - .setUiccApplicationsEnabled(reference.getUiccApplicationsEnabled()) - .setRcsUceEnabled(reference.getRcsUceEnabled()) - .setCrossSimCallingEnabled(reference.getCrossSimCallingEnabled()) - .setNrAdvancedCallingEnabled(reference.getNrAdvancedCallingEnabled()) - .setUserId(reference.getUserId()) - .build(); - mSubscriptionDatabaseManager.updateSubscription(newSubInfo); - log("Synced settings from sub " + subId + " to sub " - + newSubInfo.getSubscriptionId()); - } - } + mSubscriptionDatabaseManager.syncToGroup(subId); }); } @@ -937,7 +936,7 @@ public class SubscriptionManagerService extends ISub.Stub { if (ruleList != null && !ruleList.isEmpty()) { builder.setNativeAccessRules(embeddedProfile.getUiccAccessRules()); } - builder.setRemovableEmbedded(isRemovable ? 1 : 0); + builder.setRemovableEmbedded(isRemovable); // override DISPLAY_NAME if the priority of existing nameSource is <= carrier if (getNameSourcePriority(nameSource) <= getNameSourcePriority( @@ -2239,19 +2238,115 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Set a field in the subscription database. Note not all fields are supported. + * + * @param subId Subscription Id of Subscription. + * @param columnName Column name in the database. Note not all fields are supported. + * @param value Value to store in the database. + * + * // TODO: Remove return value after SubscriptionController is deleted. + * @return always 1 + * + * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not + * exposed. + * @throws SecurityException if callers do not hold the required permission. + * + * @see #getSubscriptionProperty(int, String, String, String) + * @see SimInfo for all the columns. + */ @Override - public int setSubscriptionProperty(int subId, @NonNull String propKey, - @NonNull String propValue) { - return 0; + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public int setSubscriptionProperty(int subId, @NonNull String columnName, + @NonNull String value) { + enforcePermissions("setSubscriptionProperty", Manifest.permission.MODIFY_PHONE_STATE); + + final long token = Binder.clearCallingIdentity(); + try { + if (!SimInfo.getAllColumns().contains(columnName)) { + throw new IllegalArgumentException("Invalid column name " + columnName); + } + + // Check if the columns are allowed to be accessed through the generic + // getSubscriptionProperty method. + if (!DIRECT_ACCESS_SUBSCRIPTION_COLUMNS.contains(columnName)) { + throw new SecurityException("Column " + columnName + " is not allowed be directly " + + "accessed through setSubscriptionProperty."); + } + + mSubscriptionDatabaseManager.setSubscriptionProperty(subId, columnName, value); + return 1; + } finally { + Binder.restoreCallingIdentity(token); + } } + /** + * Get specific field in string format from the subscription info database. + * + * @param subId Subscription id of the subscription. + * @param columnName Column name in subscription database. + * + * @return Value in string format associated with {@code subscriptionId} and {@code columnName} + * from the database. + * + * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not + * exposed. + * @throws SecurityException if callers do not hold the required permission. + * + * @see SimInfo for all the columns. + */ @Override - public String getSubscriptionProperty(int subId, @NonNull String propKey, + @NonNull + @RequiresPermission(anyOf = { + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + "carrier privileges", + }) + public String getSubscriptionProperty(int subId, @NonNull String columnName, @NonNull String callingPackage, @Nullable String callingFeatureId) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - return null; + Objects.requireNonNull(columnName); + if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, + callingPackage, callingFeatureId, + "getSubscriptionProperty")) { + throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " + + "carrier privilege"); + } + + if (!SimInfo.getAllColumns().contains(columnName)) { + throw new IllegalArgumentException("Invalid column name " + columnName); + } + + // Check if the columns are allowed to be accessed through the generic + // getSubscriptionProperty method. + if (!DIRECT_ACCESS_SUBSCRIPTION_COLUMNS.contains(columnName)) { + throw new SecurityException("Column " + columnName + " is not allowed be directly " + + "accessed through getSubscriptionProperty."); + } + + final long token = Binder.clearCallingIdentity(); + try { + Object value = mSubscriptionDatabaseManager.getSubscriptionProperty(subId, columnName); + // The raw types of subscription database should only have 3 different types. + if (value instanceof Integer) { + return String.valueOf(value); + } else if (value instanceof String) { + return (String) value; + } else if (value instanceof byte[]) { + return Base64.encodeToString((byte[]) value, Base64.DEFAULT); + } else { + // This should not happen unless SubscriptionDatabaseManager.getSubscriptionProperty + // did not implement correctly. + throw new RuntimeException("Unexpected type " + value.getClass().getTypeName() + + " was returned from SubscriptionDatabaseManager for column " + + columnName); + } + } finally { + Binder.restoreCallingIdentity(token); + } } @Override 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 e7677dee6f..2810b1250f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -37,6 +37,7 @@ import android.database.MatrixCursor; import android.net.Uri; import android.os.Looper; import android.provider.Telephony; +import android.provider.Telephony.SimInfo; import android.telephony.SubscriptionManager; import android.telephony.UiccAccessRule; import android.telephony.ims.ImsMmTelManager; @@ -235,14 +236,14 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { private final List mAllColumns; SubscriptionProvider() { - mAllColumns = Telephony.SimInfo.getAllColumns(); + mAllColumns = SimInfo.getAllColumns(); } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { logd("SubscriptionProvider: query. uri=" + uri); - if (!Telephony.SimInfo.CONTENT_URI.equals(uri)) { + if (!SimInfo.CONTENT_URI.equals(uri)) { throw new UnsupportedOperationException("Unsupported uri=" + uri); } if (projection != null || selection != null || selectionArgs != null) { @@ -267,7 +268,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Override public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { - if (!uri.isPathPrefixMatch(Telephony.SimInfo.CONTENT_URI)) { + if (!uri.isPathPrefixMatch(SimInfo.CONTENT_URI)) { throw new UnsupportedOperationException("Unsupported uri=" + uri); } @@ -295,7 +296,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Override public Uri insert(Uri uri, ContentValues values) { logd("SubscriptionProvider: insert. uri=" + uri + ", values=" + values); - if (!Telephony.SimInfo.CONTENT_URI.equals(uri)) { + if (!SimInfo.CONTENT_URI.equals(uri)) { throw new UnsupportedOperationException("Unsupported uri=" + uri); } @@ -305,9 +306,9 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { } } int subId = mDatabase.size() + 1; - values.put(Telephony.SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, subId); + values.put(SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, subId); mDatabase.add(values); - return ContentUris.withAppendedId(Telephony.SimInfo.CONTENT_URI, subId); + return ContentUris.withAppendedId(SimInfo.CONTENT_URI, subId); } } @@ -382,7 +383,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Test public void testGetAllColumns() throws Exception { - Field[] declaredFields = Telephony.SimInfo.class.getDeclaredFields(); + Field[] declaredFields = SimInfo.class.getDeclaredFields(); List columnNames = new ArrayList<>(); for (Field field : declaredFields) { if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("COLUMN_")) { @@ -391,7 +392,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { } // When you add a new column in Telephony.SimInfo, did you remember to modify // Telephony.SimInfo.getAllColumns() as well? - assertThat(Telephony.SimInfo.getAllColumns()).containsExactlyElementsIn(columnNames); + assertThat(SimInfo.getAllColumns()).containsExactlyElementsIn(columnNames); } @Test @@ -469,6 +470,12 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setIccId(FAKE_ICCID2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_ICC_ID)).isEqualTo(FAKE_ICCID2); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_ICC_ID, FAKE_ICCID1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getIccId()) + .isEqualTo(FAKE_ICCID1); } @Test @@ -487,6 +494,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { SubscriptionManager.INVALID_SIM_SLOT_INDEX).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_SIM_SLOT_INDEX)) + .isEqualTo(SubscriptionManager.INVALID_SIM_SLOT_INDEX); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_SIM_SLOT_INDEX, 123); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getSimSlotIndex()) + .isEqualTo(123); } @Test @@ -503,6 +517,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { FAKE_CARRIER_NAME2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_DISPLAY_NAME)) + .isEqualTo(FAKE_CARRIER_NAME2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_DISPLAY_NAME, FAKE_CARRIER_NAME1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getDisplayName()) + .isEqualTo(FAKE_CARRIER_NAME1); } @Test @@ -519,6 +540,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { FAKE_CARRIER_NAME2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_CARRIER_NAME)) + .isEqualTo(FAKE_CARRIER_NAME2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_CARRIER_NAME, FAKE_CARRIER_NAME1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getCarrierName()) + .isEqualTo(FAKE_CARRIER_NAME1); } @Test @@ -537,6 +565,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { SubscriptionManager.NAME_SOURCE_USER_INPUT).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_NAME_SOURCE)) + .isEqualTo(SubscriptionManager.NAME_SOURCE_USER_INPUT); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_NAME_SOURCE, SubscriptionManager.NAME_SOURCE_SIM_PNN); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getDisplayNameSource()) + .isEqualTo(SubscriptionManager.NAME_SOURCE_SIM_PNN); } @Test @@ -552,6 +587,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setIconTint(FAKE_COLOR2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_COLOR)) + .isEqualTo(FAKE_COLOR2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_COLOR, FAKE_COLOR1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getIconTint()) + .isEqualTo(FAKE_COLOR1); } @Test @@ -568,6 +610,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setNumber(FAKE_PHONE_NUMBER2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_NUMBER)) + .isEqualTo(FAKE_PHONE_NUMBER2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_NUMBER, FAKE_PHONE_NUMBER1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getNumber()) + .isEqualTo(FAKE_PHONE_NUMBER1); } @Test @@ -586,6 +635,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setDataRoaming(SubscriptionManager.DATA_ROAMING_DISABLE).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_DATA_ROAMING)) + .isEqualTo(SubscriptionManager.DATA_ROAMING_DISABLE); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_DATA_ROAMING, SubscriptionManager.DATA_ROAMING_ENABLE); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getDataRoaming()) + .isEqualTo(SubscriptionManager.DATA_ROAMING_ENABLE); } @Test @@ -601,6 +657,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setMcc(FAKE_MCC2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_MCC_STRING)) + .isEqualTo(FAKE_MCC2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_MCC_STRING, FAKE_MCC1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getMcc()) + .isEqualTo(FAKE_MCC1); } @Test @@ -616,36 +679,57 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setMnc(FAKE_MNC2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_MNC_STRING)) + .isEqualTo(FAKE_MNC2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_MNC_STRING, FAKE_MNC1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getMnc()) + .isEqualTo(FAKE_MNC1); } @Test public void testUpdateEhplmns() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setEhplmns(1, FAKE_EHPLMNS2.split(","))); + () -> mDatabaseManagerUT.setEhplmns(1, FAKE_EHPLMNS2)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setEhplmns(subInfo.getSubscriptionId(), FAKE_EHPLMNS2.split(",")); + mDatabaseManagerUT.setEhplmns(subInfo.getSubscriptionId(), FAKE_EHPLMNS2); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo).setEhplmns(FAKE_EHPLMNS2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_EHPLMNS)) + .isEqualTo(FAKE_EHPLMNS2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_EHPLMNS, FAKE_EHPLMNS1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getEhplmns()) + .isEqualTo(FAKE_EHPLMNS1); } @Test public void testUpdateHplmns() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setHplmns(1, FAKE_HPLMNS2.split(","))); + () -> mDatabaseManagerUT.setHplmns(1, FAKE_HPLMNS2)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setHplmns(subInfo.getSubscriptionId(), FAKE_HPLMNS2.split(",")); + mDatabaseManagerUT.setHplmns(subInfo.getSubscriptionId(), FAKE_HPLMNS2); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo).setHplmns(FAKE_HPLMNS2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_HPLMNS)) + .isEqualTo(FAKE_HPLMNS2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_HPLMNS, FAKE_HPLMNS1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getHplmns()) + .isEqualTo(FAKE_HPLMNS1); } @Test @@ -661,6 +745,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setEmbedded(0).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_IS_EMBEDDED)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_IS_EMBEDDED, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getEmbedded()) + .isEqualTo(1); } @Test @@ -679,24 +770,37 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_CARD_ID)) + .isEqualTo(FAKE_ICCID2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_CARD_ID, FAKE_ICCID1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getCardString()) + .isEqualTo(FAKE_ICCID1); } @Test public void testUpdateNativeAccessRules() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setNativeAccessRules(1, - UiccAccessRule.decodeRules(FAKE_NATIVE_ACCESS_RULES2))); + () -> mDatabaseManagerUT.setNativeAccessRules(1, FAKE_NATIVE_ACCESS_RULES2)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setNativeAccessRules(subInfo.getSubscriptionId(), - UiccAccessRule.decodeRules(FAKE_NATIVE_ACCESS_RULES2)); + FAKE_NATIVE_ACCESS_RULES2); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setNativeAccessRules(FAKE_NATIVE_ACCESS_RULES2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_ACCESS_RULES)) + .isEqualTo(FAKE_NATIVE_ACCESS_RULES2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_ACCESS_RULES, FAKE_NATIVE_ACCESS_RULES1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getNativeAccessRules()) + .isEqualTo(FAKE_NATIVE_ACCESS_RULES1); } @Test @@ -704,77 +808,110 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, () -> mDatabaseManagerUT.setCarrierConfigAccessRules(1, - UiccAccessRule.decodeRules(FAKE_CARRIER_CONFIG_ACCESS_RULES2))); + FAKE_CARRIER_CONFIG_ACCESS_RULES2)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); mDatabaseManagerUT.setCarrierConfigAccessRules(subInfo.getSubscriptionId(), - UiccAccessRule.decodeRules(FAKE_CARRIER_CONFIG_ACCESS_RULES2)); + FAKE_CARRIER_CONFIG_ACCESS_RULES2); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setCarrierConfigAccessRules(FAKE_CARRIER_CONFIG_ACCESS_RULES2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS)) + .isEqualTo(FAKE_CARRIER_CONFIG_ACCESS_RULES2); + mDatabaseManagerUT.setSubscriptionProperty(1, + SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, + FAKE_CARRIER_CONFIG_ACCESS_RULES2); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getCarrierConfigAccessRules()) + .isEqualTo(FAKE_CARRIER_CONFIG_ACCESS_RULES2); } @Test public void testUpdateRemovableEmbedded() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setRemovableEmbedded(1, true)); + () -> mDatabaseManagerUT.setRemovableEmbedded(1, 1)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setRemovableEmbedded(subInfo.getSubscriptionId(), true); + mDatabaseManagerUT.setRemovableEmbedded(subInfo.getSubscriptionId(), 1); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo).setRemovableEmbedded(1).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_IS_REMOVABLE)) + .isEqualTo(1); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_IS_REMOVABLE, 0); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getRemovableEmbedded()) + .isEqualTo(0); } @Test public void testUpdateEnhanced4GModeEnabled() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setEnhanced4GModeEnabled(1, false)); + () -> mDatabaseManagerUT.setEnhanced4GModeEnabled(1, 0)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setEnhanced4GModeEnabled(subInfo.getSubscriptionId(), false); + mDatabaseManagerUT.setEnhanced4GModeEnabled(subInfo.getSubscriptionId(), 0); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo).setEnhanced4GModeEnabled(0).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED)).isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getEnhanced4GModeEnabled()) + .isEqualTo(1); } @Test public void testUpdateVideoTelephonyEnabled() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setVideoTelephonyEnabled(1, false)); + () -> mDatabaseManagerUT.setVideoTelephonyEnabled(1, 0)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setVideoTelephonyEnabled(subInfo.getSubscriptionId(), false); + mDatabaseManagerUT.setVideoTelephonyEnabled(subInfo.getSubscriptionId(), 0); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo).setVideoTelephonyEnabled(0).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_VT_IMS_ENABLED)).isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_VT_IMS_ENABLED, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getVideoTelephonyEnabled()) + .isEqualTo(1); } @Test public void testUpdateWifiCallingEnabled() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setWifiCallingEnabled(1, false)); + () -> mDatabaseManagerUT.setWifiCallingEnabled(1, 0)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setWifiCallingEnabled(subInfo.getSubscriptionId(), false); + mDatabaseManagerUT.setWifiCallingEnabled(subInfo.getSubscriptionId(), 0); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo).setWifiCallingEnabled(0).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_WFC_IMS_ENABLED)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_WFC_IMS_ENABLED, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getWifiCallingEnabled()) + .isEqualTo(1); } @Test @@ -793,6 +930,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setWifiCallingMode(ImsMmTelManager.WIFI_MODE_WIFI_ONLY).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_WFC_IMS_MODE)) + .isEqualTo(ImsMmTelManager.WIFI_MODE_WIFI_ONLY); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_WFC_IMS_MODE, + ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getWifiCallingMode()) + .isEqualTo(ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED); } @Test @@ -811,37 +955,80 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setWifiCallingModeForRoaming(ImsMmTelManager.WIFI_MODE_WIFI_ONLY).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_WFC_IMS_ROAMING_MODE)) + .isEqualTo(ImsMmTelManager.WIFI_MODE_WIFI_ONLY); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, + ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getWifiCallingModeForRoaming()) + .isEqualTo(ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED); } @Test public void testUpdateWifiCallingEnabledForRoaming() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setWifiCallingEnabledForRoaming(1, false)); + () -> mDatabaseManagerUT.setWifiCallingEnabledForRoaming(1, 0)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setWifiCallingEnabledForRoaming(subInfo.getSubscriptionId(), false); + mDatabaseManagerUT.setWifiCallingEnabledForRoaming(subInfo.getSubscriptionId(), 0); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setWifiCallingEnabledForRoaming(0).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED)).isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getWifiCallingEnabledForRoaming()).isEqualTo(1); + } + + @Test + public void testUpdateVoImsOptInEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setVoImsOptInEnabled(1, 0)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setVoImsOptInEnabled(subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setVoImsOptInEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS)).isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getVoImsOptInEnabled()).isEqualTo(1); } + @Test public void testUpdateOpportunistic() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setOpportunistic(1, true)); + () -> mDatabaseManagerUT.setOpportunistic(1, 1)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setOpportunistic(subInfo.getSubscriptionId(), true); + mDatabaseManagerUT.setOpportunistic(subInfo.getSubscriptionId(), 1); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo).setOpportunistic(1).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_IS_OPPORTUNISTIC)).isEqualTo(1); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_IS_OPPORTUNISTIC, 0); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getOpportunistic()).isEqualTo(0); } @Test @@ -857,6 +1044,12 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { subInfo = new SubscriptionInfoInternal.Builder(subInfo).setGroupUuid(FAKE_UUID2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_GROUP_UUID)).isEqualTo(FAKE_UUID2); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_GROUP_UUID, FAKE_UUID1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getGroupUuid()).isEqualTo(FAKE_UUID1); } @Test @@ -873,6 +1066,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setCountryIso(FAKE_COUNTRY_CODE2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_ISO_COUNTRY_CODE)).isEqualTo(FAKE_COUNTRY_CODE2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_ISO_COUNTRY_CODE, FAKE_COUNTRY_CODE1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCountryIso()).isEqualTo(FAKE_COUNTRY_CODE1); } @Test @@ -889,6 +1089,12 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setCarrierId(FAKE_CARRIER_ID2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_CARRIER_ID)) + .isEqualTo(FAKE_CARRIER_ID2); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CARRIER_ID, FAKE_CARRIER_ID1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getCarrierId()) + .isEqualTo(FAKE_CARRIER_ID1); } @Test @@ -907,6 +1113,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setProfileClass(SubscriptionManager.PROFILE_CLASS_TESTING).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_PROFILE_CLASS)) + .isEqualTo(SubscriptionManager.PROFILE_CLASS_TESTING); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_PROFILE_CLASS, + SubscriptionManager.PROFILE_CLASS_PROVISIONING); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getProfileClass()) + .isEqualTo(SubscriptionManager.PROFILE_CLASS_PROVISIONING); } @Test @@ -925,6 +1138,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setType(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_SUBSCRIPTION_TYPE)) + .isEqualTo(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_SUBSCRIPTION_TYPE, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getSubscriptionType()) + .isEqualTo(SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); } @Test @@ -941,6 +1161,12 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setGroupOwner(FAKE_OWNER2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_GROUP_OWNER)) + .isEqualTo(FAKE_OWNER2); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_GROUP_OWNER, FAKE_OWNER1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getGroupOwner()) + .isEqualTo(FAKE_OWNER1); } @Test @@ -958,6 +1184,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setEnabledMobileDataPolicies(FAKE_MOBILE_DATA_POLICY2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES)).isEqualTo(FAKE_MOBILE_DATA_POLICY2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, FAKE_MOBILE_DATA_POLICY1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getEnabledMobileDataPolicies()) + .isEqualTo(FAKE_MOBILE_DATA_POLICY1); } @Test @@ -974,54 +1207,78 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setImsi(FAKE_IMSI2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_IMSI)) + .isEqualTo(FAKE_IMSI2); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_IMSI, FAKE_IMSI1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getImsi()) + .isEqualTo(FAKE_IMSI1); } @Test public void testUpdateUiccApplicationsEnabled() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setUiccApplicationsEnabled(1, false)); + () -> mDatabaseManagerUT.setUiccApplicationsEnabled(1, 0)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setUiccApplicationsEnabled(subInfo.getSubscriptionId(), false); + mDatabaseManagerUT.setUiccApplicationsEnabled(subInfo.getSubscriptionId(), 0); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setUiccApplicationsEnabled(0).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED)).isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getUiccApplicationsEnabled()) + .isEqualTo(1); } @Test public void testUpdateRcsUceEnabled() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setRcsUceEnabled(1, false)); + () -> mDatabaseManagerUT.setRcsUceEnabled(1, 0)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setRcsUceEnabled(subInfo.getSubscriptionId(), false); + mDatabaseManagerUT.setRcsUceEnabled(subInfo.getSubscriptionId(), 0); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setRcsUceEnabled(0).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_IMS_RCS_UCE_ENABLED)).isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getRcsUceEnabled()) + .isEqualTo(1); } @Test public void testUpdateCrossSimCallingEnabled() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setCrossSimCallingEnabled(1, false)); + () -> mDatabaseManagerUT.setCrossSimCallingEnabled(1, 0)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setCrossSimCallingEnabled(subInfo.getSubscriptionId(), false); + mDatabaseManagerUT.setCrossSimCallingEnabled(subInfo.getSubscriptionId(), 0); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setCrossSimCallingEnabled(0).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED)).isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getCrossSimCallingEnabled()) + .isEqualTo(1); } @Test @@ -1038,6 +1295,12 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setRcsConfig(FAKE_RCS_CONFIG2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_RCS_CONFIG)).isEqualTo(FAKE_RCS_CONFIG2); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_RCS_CONFIG, FAKE_RCS_CONFIG1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getRcsConfig()) + .isEqualTo(FAKE_RCS_CONFIG1); } @Test @@ -1056,6 +1319,16 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setAllowedNetworkTypesForReasons(FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS)) + .isEqualTo(FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS2); + mDatabaseManagerUT.setSubscriptionProperty(1, + SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, + FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getAllowedNetworkTypesForReasons()) + .isEqualTo(FAKE_ALLOWED_NETWORK_TYPES_FOR_REASONS1); } @Test @@ -1075,22 +1348,38 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { SubscriptionManager.D2D_SHARING_DISABLED).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_D2D_STATUS_SHARING)) + .isEqualTo(SubscriptionManager.D2D_SHARING_DISABLED); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_D2D_STATUS_SHARING, + SubscriptionManager.D2D_SHARING_ALL); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getDeviceToDeviceStatusSharingPreference()) + .isEqualTo(SubscriptionManager.D2D_SHARING_ALL); } @Test public void testUpdateNrAdvancedCallingEnabled() throws Exception { // exception is expected if there is nothing in the database. assertThrows(IllegalArgumentException.class, - () -> mDatabaseManagerUT.setNrAdvancedCallingEnabled(1, false)); + () -> mDatabaseManagerUT.setNrAdvancedCallingEnabled(1, 0)); SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); - mDatabaseManagerUT.setNrAdvancedCallingEnabled(subInfo.getSubscriptionId(), false); + mDatabaseManagerUT.setNrAdvancedCallingEnabled(subInfo.getSubscriptionId(), 0); processAllMessages(); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setNrAdvancedCallingEnabled(0).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED)).isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getNrAdvancedCallingEnabled()).isEqualTo(1); } @Test @@ -1107,6 +1396,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setNumberFromCarrier(FAKE_PHONE_NUMBER2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER)).isEqualTo(FAKE_PHONE_NUMBER2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER, FAKE_PHONE_NUMBER1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getNumberFromCarrier()).isEqualTo(FAKE_PHONE_NUMBER1); } @Test @@ -1123,6 +1419,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setNumberFromIms(FAKE_PHONE_NUMBER2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS)).isEqualTo(FAKE_PHONE_NUMBER2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS, FAKE_PHONE_NUMBER1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getNumberFromIms()).isEqualTo(FAKE_PHONE_NUMBER1); } @Test @@ -1139,6 +1442,12 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setPortIndex(1).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_PORT_INDEX)) + .isEqualTo(1); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_PORT_INDEX, 2); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getPortIndex()) + .isEqualTo(2); } @Test @@ -1157,6 +1466,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setUsageSetting(SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_USAGE_SETTING)) + .isEqualTo(SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_USAGE_SETTING, SubscriptionManager.USAGE_SETTING_DATA_CENTRIC); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getUsageSetting()) + .isEqualTo(SubscriptionManager.USAGE_SETTING_DATA_CENTRIC); } @Test @@ -1175,6 +1491,13 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setLastUsedTPMessageReference(FAKE_TP_MESSAGE_REFERENCE2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_TP_MESSAGE_REF)) + .isEqualTo(FAKE_TP_MESSAGE_REFERENCE2); + mDatabaseManagerUT.setSubscriptionProperty( + 1, SimInfo.COLUMN_TP_MESSAGE_REF, FAKE_TP_MESSAGE_REFERENCE1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getLastUsedTPMessageReference()).isEqualTo(FAKE_TP_MESSAGE_REFERENCE1); } @Test @@ -1191,5 +1514,56 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setUserId(FAKE_USER_ID2).build(); verifySubscription(subInfo); verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty(1, SimInfo.COLUMN_USER_HANDLE)) + .isEqualTo(FAKE_USER_ID2); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_USER_HANDLE, FAKE_USER_ID1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getUserId()).isEqualTo(FAKE_USER_ID1); + } + + @Test + public void testUpdateSubscriptionsInGroup() throws Exception { + insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO2); + // Two subs are now in the same group + mDatabaseManagerUT.setGroupUuid(2, FAKE_UUID1); + + mDatabaseManagerUT.setWifiCallingEnabled(1, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .isWifiCallingEnabled()).isTrue(); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2) + .isWifiCallingEnabled()).isTrue(); + + mDatabaseManagerUT.setWifiCallingEnabled(1, 0); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .isWifiCallingEnabled()).isFalse(); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2) + .isWifiCallingEnabled()).isFalse(); + + mDatabaseManagerUT.setUserId(1, 5678); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getUserId()).isEqualTo(5678); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2) + .getUserId()).isEqualTo(5678); + + mDatabaseManagerUT.setWifiCallingEnabledForRoaming(1, 0); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .isWifiCallingEnabledForRoaming()).isFalse(); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2) + .isWifiCallingEnabledForRoaming()).isFalse(); + + mDatabaseManagerUT.setDisplayName(1, "Pokemon"); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getDisplayName()).isEqualTo("Pokemon"); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2) + .getDisplayName()).isEqualTo("Pokemon"); + + // ICCID is not the field that will be synced to all subs in the group. + mDatabaseManagerUT.setIccId(1, "0987"); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getIccId()).isEqualTo("0987"); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2) + .getIccId()).isEqualTo(FAKE_ICCID2); } } 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 ef8a5a709c..6448f40fdb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -21,6 +21,7 @@ import static com.android.internal.telephony.subscription.SubscriptionDatabaseMa import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CONTACT1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CONTACT2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID1; @@ -29,10 +30,14 @@ import static com.android.internal.telephony.subscription.SubscriptionDatabaseMa import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MCC2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MNC1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MNC2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MOBILE_DATA_POLICY1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MOBILE_DATA_POLICY2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_NATIVE_ACCESS_RULES1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_NATIVE_ACCESS_RULES2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_PHONE_NUMBER2; +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_SUBSCRIPTION_INFO1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_SUBSCRIPTION_INFO2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_UUID1; @@ -66,6 +71,7 @@ import android.os.ParcelUuid; import android.os.UserHandle; import android.provider.Settings; import android.provider.Telephony; +import android.provider.Telephony.SimInfo; import android.service.carrier.CarrierIdentifier; import android.service.euicc.EuiccProfileInfo; import android.service.euicc.EuiccService; @@ -76,6 +82,7 @@ import android.telephony.UiccAccessRule; import android.test.mock.MockContentResolver; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.Base64; import com.android.internal.telephony.ContextFixture; import com.android.internal.telephony.TelephonyIntents; @@ -99,6 +106,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; +import java.util.Set; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -1164,4 +1172,465 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(true).when(mPhone).canDisablePhysicalSubscription(); assertThat(mSubscriptionManagerServiceUT.canDisablePhysicalSubscription()).isTrue(); } + + @Test + public void testSetGetEnhanced4GModeEnabled() throws Exception { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("1"); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_ENHANCED_4G_MODE_ENABLED + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, "0"); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getEnhanced4GModeEnabled()).isEqualTo(0); + } + + @Test + public void testSetGetVideoTelephonyEnabled() throws Exception { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_VT_IMS_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_VT_IMS_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("1"); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_VT_IMS_ENABLED, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_VT_IMS_ENABLED + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_VT_IMS_ENABLED, "0"); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getVideoTelephonyEnabled()).isEqualTo(0); + } + + @Test + public void testSetGetWifiCallingEnabled() throws Exception { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_WFC_IMS_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_WFC_IMS_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("1"); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_WFC_IMS_ENABLED, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_WFC_IMS_ENABLED + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_WFC_IMS_ENABLED, "0"); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getWifiCallingEnabled()).isEqualTo(0); + } + + @Test + public void testSetGetWifiCallingMode() throws Exception { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_WFC_IMS_MODE, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_WFC_IMS_MODE, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("1"); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_WFC_IMS_MODE, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_WFC_IMS_MODE + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_WFC_IMS_MODE, "0"); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getWifiCallingMode()).isEqualTo(0); + } + + @Test + public void testSetGetWifiCallingModeForRoaming() throws Exception { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("2"); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_WFC_IMS_ROAMING_MODE + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, "0"); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getWifiCallingModeForRoaming()).isEqualTo(0); + } + + @Test + public void testSetGetEnabledMobileDataPolicies() throws Exception { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, CALLING_PACKAGE, + CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo(FAKE_MOBILE_DATA_POLICY1); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_ENABLED_MOBILE_DATA_POLICIES + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, FAKE_MOBILE_DATA_POLICY2); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getEnabledMobileDataPolicies()).isEqualTo(FAKE_MOBILE_DATA_POLICY2); + } + + @Test + public void testSetGetRcsUceEnabled() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("1"); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_IMS_RCS_UCE_ENABLED + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("1"); + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, "0"); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getRcsUceEnabled()).isEqualTo(0); + } + + @Test + public void testSetGetCrossSimCallingEnabled() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, CALLING_PACKAGE, + CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("1"); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_CROSS_SIM_CALLING_ENABLED + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, "0"); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getCrossSimCallingEnabled()).isEqualTo(0); + } + + @Test + public void testSetGetRcsConfig() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_RCS_CONFIG, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_RCS_CONFIG, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo(Base64.encodeToString(FAKE_RCS_CONFIG1, Base64.DEFAULT)); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_RCS_CONFIG, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_RCS_CONFIG + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_RCS_CONFIG, + Base64.encodeToString(FAKE_RCS_CONFIG2, Base64.DEFAULT)); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getRcsConfig()).isEqualTo(FAKE_RCS_CONFIG2); + } + + @Test + public void testSetGetDeviceToDeviceStatusSharingPreference() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_D2D_STATUS_SHARING, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_D2D_STATUS_SHARING, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("1"); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_D2D_STATUS_SHARING, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_D2D_STATUS_SHARING + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_D2D_STATUS_SHARING, "0"); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getDeviceToDeviceStatusSharingPreference()).isEqualTo(0); + } + + @Test + public void testSetGetVoImsOptInEnabled() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, CALLING_PACKAGE, CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("1"); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_VOIMS_OPT_IN_STATUS + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, "0"); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getVoImsOptInEnabled()).isEqualTo(0); + } + + @Test + public void testSetGetDeviceToDeviceStatusSharingContacts() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, CALLING_PACKAGE, + CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, CALLING_PACKAGE, + CALLING_FEATURE)).isEqualTo(FAKE_CONTACT1); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + FAKE_CONTACT2)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, FAKE_CONTACT2); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getDeviceToDeviceStatusSharingContacts()).isEqualTo(FAKE_CONTACT2); + } + + @Test + public void testSetGetNrAdvancedCallingEnabled() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, CALLING_PACKAGE, + CALLING_FEATURE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionProperty(1, + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo("1"); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, "0")); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // COLUMN_NR_ADVANCED_CALLING_ENABLED + mSubscriptionManagerServiceUT.setSubscriptionProperty(1, + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, "0"); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getNrAdvancedCallingEnabled()).isEqualTo(0); + } + + @Test + public void testSetSubscriptionPropertyInvalidField() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + assertThrows(IllegalArgumentException.class, () -> mSubscriptionManagerServiceUT + .setSubscriptionProperty(1, "hahahaha", "0")); + } + + @Test + public void testGetNonAccessibleFields() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + Set accessibleColumns = Set.of( + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, + SimInfo.COLUMN_VT_IMS_ENABLED, + SimInfo.COLUMN_WFC_IMS_ENABLED, + SimInfo.COLUMN_WFC_IMS_MODE, + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, + SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, + SimInfo.COLUMN_RCS_CONFIG, + SimInfo.COLUMN_D2D_STATUS_SHARING, + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED + ); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + for (String column : SimInfo.getAllColumns()) { + if (accessibleColumns.contains(column)) { + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, column, + CALLING_PACKAGE, CALLING_FEATURE); + } else { + assertThrows(SecurityException.class, () -> + mSubscriptionManagerServiceUT.getSubscriptionProperty(1, column, + CALLING_PACKAGE, CALLING_FEATURE)); + } + } + } + + @Test + public void testSyncToGroup() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + mSubscriptionManagerServiceUT.createSubscriptionGroup(new int[]{1, 2}, CALLING_PACKAGE); + + mSubscriptionManagerServiceUT.syncGroupedSetting(1); + processAllMessages(); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2).getIconTint()) + .isEqualTo(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getIconTint()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2).getDataRoaming()) + .isEqualTo(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1) + .getDataRoaming()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getEnhanced4GModeEnabled()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getEnhanced4GModeEnabled()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getVideoTelephonyEnabled()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getVideoTelephonyEnabled()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getWifiCallingEnabled()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getWifiCallingEnabled()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getWifiCallingMode()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getWifiCallingMode()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getWifiCallingModeForRoaming()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getWifiCallingModeForRoaming()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getWifiCallingEnabledForRoaming()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getWifiCallingEnabledForRoaming()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getEnabledMobileDataPolicies()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getEnabledMobileDataPolicies()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getUiccApplicationsEnabled()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getUiccApplicationsEnabled()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getRcsUceEnabled()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getRcsUceEnabled()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getCrossSimCallingEnabled()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getCrossSimCallingEnabled()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getRcsConfig()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getRcsConfig()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getDeviceToDeviceStatusSharingPreference()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getDeviceToDeviceStatusSharingPreference()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getVoImsOptInEnabled()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getVoImsOptInEnabled()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getDeviceToDeviceStatusSharingContacts()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getDeviceToDeviceStatusSharingContacts()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getNrAdvancedCallingEnabled()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getNrAdvancedCallingEnabled()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2) + .getUserId()).isEqualTo(mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1).getUserId()); + } } -- GitLab From 8ebff6d78a6b019f453c5ff1abcb0af924d2dd2c Mon Sep 17 00:00:00 2001 From: Daniel Banta Date: Fri, 16 Sep 2022 02:18:04 +0000 Subject: [PATCH 264/656] Add EmergencyStateTracker for domain selection. Requirement 1 - Track Emergency Call State and Notify Radio/Listeners: - Turning on the radio and switching DDS is moved to EmergencyStateTracker. - The existing logic for tracking the emergency call state of the device is moved from Phone.java. - Sending the emergency mode to the modem on a per-transport basis and notifying changes to emergency mode to the modem. - Notifying changes to the emergency mode to external app listeners. Bug: 247639718 Change-Id: I8ada9fe29ad999484206d94ca7ce8579dcf9d542 --- .../emergency/EmergencyStateTracker.java | 560 ++++++++++++++++++ .../telephony/emergency/RadioOnHelper.java | 158 +++++ .../emergency/RadioOnStateListener.java | 403 +++++++++++++ .../emergency/EmergencyStateTrackerTest.java | 508 ++++++++++++++++ .../emergency/RadioOnStateListenerTest.java | 187 ++++++ 5 files changed, 1816 insertions(+) create mode 100644 src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java create mode 100644 src/java/com/android/internal/telephony/emergency/RadioOnHelper.java create mode 100644 src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java new file mode 100644 index 0000000000..b4f4554775 --- /dev/null +++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java @@ -0,0 +1,560 @@ +/* + * Copyright (C) 2022 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.emergency; + +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_NONE; +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; + +import android.annotation.NonNull; +import android.content.Context; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings; +import android.telephony.CarrierConfigManager; +import android.telephony.DisconnectCause; +import android.telephony.EmergencyRegResult; +import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.telephony.emergency.EmergencyNumber; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.Call; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.RIL; +import com.android.internal.telephony.data.PhoneSwitcher; +import com.android.telephony.Rlog; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +/** + * Tracks the emergency call state and notifies listeners of changes to the emergency mode. + */ +public class EmergencyStateTracker { + + private static final String TAG = "EmergencyStateTracker"; + + // Timeout before we continue with the emergency call without waiting for DDS switch response + // from the modem. + private static final int DEFAULT_DATA_SWITCH_TIMEOUT_MS = 1000; + + private static EmergencyStateTracker INSTANCE = null; + + private final Context mContext; + private final Handler mHandler; + private @EmergencyConstants.EmergencyMode int mEmergencyMode = MODE_EMERGENCY_NONE; + private Phone mPhone; + private RadioOnHelper mRadioOnHelper; + private CompletableFuture mOnCompleted = null; + /** Tracks emergency calls by callId that have reached {@link Call.State.Active}.*/ + private Set mActiveEmergencyCalls = new HashSet(); + private boolean mIsSuplDdsSwitchRequiredForEmergencyCall; + private EmergencyRegResult mLastEmergencyRegResult; + private boolean mIsInEmergencyCall; + private boolean mIsTestEmergencyNumber; + + /** PhoneFactory Dependencies for testing. */ + @VisibleForTesting + public interface PhoneFactoryProxy { + Phone[] getPhones(); + } + + private PhoneFactoryProxy mPhoneFactoryProxy = new PhoneFactoryProxy() { + @Override + public Phone[] getPhones() { + return PhoneFactory.getPhones(); + } + }; + + /** PhoneSwitcher dependencies for testing. */ + @VisibleForTesting + public interface PhoneSwitcherProxy { + + PhoneSwitcher getPhoneSwitcher(); + } + + private PhoneSwitcherProxy mPhoneSwitcherProxy = new PhoneSwitcherProxy() { + @Override + public PhoneSwitcher getPhoneSwitcher() { + return PhoneSwitcher.getInstance(); + } + }; + + /** + * TelephonyManager dependencies for testing. + */ + @VisibleForTesting + public interface TelephonyManagerProxy { + int getPhoneCount(); + } + + private TelephonyManagerProxy mTelephonyManagerProxy; + + private static class TelephonyManagerProxyImpl implements TelephonyManagerProxy { + private final TelephonyManager mTelephonyManager; + + + TelephonyManagerProxyImpl(Context context) { + mTelephonyManager = new TelephonyManager(context); + } + + @Override + public int getPhoneCount() { + return mTelephonyManager.getPhoneCount(); + } + } + + /** + * Return the handler for testing. + */ + @VisibleForTesting + public Handler getHandler() { + return mHandler; + } + + @VisibleForTesting + public static final int MSG_SET_EMERGENCY_MODE_DONE = 1; + @VisibleForTesting + public static final int MSG_EXIT_EMERGENCY_MODE_DONE = 2; + + private final class MyHandler extends Handler { + + MyHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch (msg.what) { + case MSG_SET_EMERGENCY_MODE_DONE: + Rlog.v(TAG, "MSG_SET_EMERGENCY_MODE_DONE"); + ar = (AsyncResult) msg.obj; + if (ar.exception == null) { + mLastEmergencyRegResult = (EmergencyRegResult) ar.result; + } else { + Rlog.w(TAG, "LastEmergencyRegResult not set. AsyncResult.exception: " + + ar.exception); + } + setIsInEmergencyCall(true); + mOnCompleted.complete(DisconnectCause.NOT_DISCONNECTED); + break; + + case MSG_EXIT_EMERGENCY_MODE_DONE: + Rlog.v(TAG, "MSG_EXIT_EMERGENCY_MODE_DONE"); + setIsInEmergencyCall(false); + break; + + default: + break; + } + } + } + + /** + * Creates the EmergencyStateTracker singleton instance. + * + * @param context The context of the application. + * @param isSuplDdsSwitchRequiredForEmergencyCall Whether gnss supl requires default data for + * emergency call. + */ + public static void make(Context context, boolean isSuplDdsSwitchRequiredForEmergencyCall) { + if (INSTANCE == null) { + INSTANCE = new EmergencyStateTracker(context, Looper.myLooper(), + isSuplDdsSwitchRequiredForEmergencyCall); + } + } + + /** + * Returns the singleton instance of EmergencyStateTracker. + * + * @return {@link EmergencyStateTracker} instance. + */ + public static EmergencyStateTracker getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("EmergencyStateTracker is not ready!"); + } + return INSTANCE; + } + + /** + * Initializes EmergencyStateTracker. + */ + private EmergencyStateTracker(Context context, Looper looper, + boolean isSuplDdsSwitchRequiredForEmergencyCall) { + mContext = context; + mHandler = new MyHandler(looper); + mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall; + mTelephonyManagerProxy = new TelephonyManagerProxyImpl(context); + } + + /** + * Initializes EmergencyStateTracker with injections for testing. + * + * @param context The context of the application. + * @param looper The {@link Looper} of the application. + * @param isSuplDdsSwitchRequiredForEmergencyCall Whether gnss supl requires default data for + * emergency call. + * @param phoneFactoryProxy The {@link PhoneFactoryProxy} to be injected. + * @param phoneSwitcherProxy The {@link PhoneSwitcherProxy} to be injected. + * @param telephonyManagerProxy The {@link TelephonyManagerProxy} to be + * injected. + * @param radioOnHelper The {@link RadioOnHelper} to be injected. + */ + @VisibleForTesting + public EmergencyStateTracker(Context context, Looper looper, + boolean isSuplDdsSwitchRequiredForEmergencyCall, PhoneFactoryProxy phoneFactoryProxy, + PhoneSwitcherProxy phoneSwitcherProxy, TelephonyManagerProxy telephonyManagerProxy, + RadioOnHelper radioOnHelper) { + mContext = context; + mHandler = new MyHandler(looper); + mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall; + mPhoneFactoryProxy = phoneFactoryProxy; + mPhoneSwitcherProxy = phoneSwitcherProxy; + mTelephonyManagerProxy = telephonyManagerProxy; + mRadioOnHelper = radioOnHelper; + } + + /** + * Starts the process of an emergency call. + * + *

+ * Handles turning on radio and switching DDS. + * + * @param phone the {@code Phone} on which to process the emergency call. + * @param callId the call id on which to process the emergency call. + * @param isTestEmergencyNumber whether this is a test emergency number. + * @return a {@code CompletableFuture} that results in {@code DisconnectCause.NOT_DISCONNECTED} + * if emergency call successfully started. + */ + public CompletableFuture startEmergencyCall(Phone phone, String callId, + boolean isTestEmergencyNumber) { + Rlog.i(TAG, "startEmergencyCall"); + + if (mPhone != null) { + Rlog.e(TAG, "startEmergencyCall failed. Existing emergency call in progress."); + // Create new future to return as to not interfere with any uncompleted futures. + CompletableFuture future = new CompletableFuture<>(); + future.complete(DisconnectCause.ERROR_UNSPECIFIED); + return future; + } + mPhone = phone; + mIsTestEmergencyNumber = isTestEmergencyNumber; + mLastEmergencyRegResult = null; + mOnCompleted = new CompletableFuture<>(); + + final boolean isAirplaneModeOn = isAirplaneModeOn(mContext); + boolean needToTurnOnRadio = !isRadioOn() || isAirplaneModeOn; + + if (needToTurnOnRadio) { + if (mRadioOnHelper == null) { + mRadioOnHelper = new RadioOnHelper(mContext); + } + + mRadioOnHelper.triggerRadioOnAndListen(new RadioOnStateListener.Callback() { + @Override + public void onComplete(RadioOnStateListener listener, boolean isRadioReady) { + if (!isRadioReady) { + // Could not turn radio on + Rlog.e(TAG, "Failed to turn on radio."); + mOnCompleted.complete(DisconnectCause.POWER_OFF); + mPhone = null; + } else { + delayDialAndSetEmergencyMode(phone); + } + } + + @Override + public boolean isOkToCall(Phone phone, int serviceState) { + // We currently only look to make sure that the radio is on before dialing. We + // should be able to make emergency calls at any time after the radio has been + // powered on and isn't in the UNAVAILABLE state, even if it is reporting the + // OUT_OF_SERVICE state. + return phone.getServiceStateTracker().isRadioOn(); + } + }, !isTestEmergencyNumber, phone, isTestEmergencyNumber); + } else { + delayDialAndSetEmergencyMode(phone); + } + + return mOnCompleted; + } + + private void delayDialAndSetEmergencyMode(Phone phone) { + delayDialForDdsSwitch(phone, result -> { + Rlog.i(TAG, "delayDialForDdsSwitch: result = " + result); + if (!result) { + // DDS Switch timed out/failed, but continue with call as it may still succeed. + Rlog.e(TAG, "DDS Switch failed."); + } + // Once radio is on and DDS switched, must call setEmergencyMode() before selecting + // emergency domain. EmergencyRegResult is required to determine domain and this is the + // only API that can receive it before starting domain selection. Once domain selection + // is finished, the actual emergency mode will be set when onEmergencyTransportChanged() + // is called. + setEmergencyMode(MODE_EMERGENCY_WWAN); + }); + } + + /** + * Triggers modem to set new emergency mode. + * + * @param mode the new emergency mode + */ + private void setEmergencyMode(@EmergencyConstants.EmergencyMode int mode) { + Rlog.i(TAG, "setEmergencyMode from " + mEmergencyMode + " to " + mode); + + if (mEmergencyMode == mode) { + return; + } + mEmergencyMode = mode; + + if (mIsTestEmergencyNumber) { + Rlog.d(TAG, "IsTestEmergencyNumber true. Skipping setting emergency mode on modem."); + return; + } + mPhone.setEmergencyMode(mode, mHandler.obtainMessage(MSG_SET_EMERGENCY_MODE_DONE)); + } + + /** + * Notifies external app listeners of emergency mode changes. + * + * @param callActive whether there is an active emergency call. + */ + private void setIsInEmergencyCall(boolean callActive) { + mIsInEmergencyCall = callActive; + } + + /** + * Checks if there is an ongoing emergency call. + * + * @return true if in emergency call + */ + public boolean isInEmergencyCall() { + return mIsInEmergencyCall; + } + + /** + * Triggers modem to exit emergency mode. + */ + private void exitEmergencyMode() { + Rlog.i(TAG, "exitEmergencyMode"); + + mEmergencyMode = MODE_EMERGENCY_NONE; + + mPhone.exitEmergencyMode(mHandler.obtainMessage(MSG_EXIT_EMERGENCY_MODE_DONE)); + } + + /** + * Ends emergency call. + * + * @param callId the call id on which to end the emergency call. + */ + public void endCall(String callId) { + mActiveEmergencyCalls.remove(callId); + exitEmergencyMode(); + mPhone = null; + } + + /** Returns last {@link EmergencyRegResult} as set by {@code setEmergencyMode()}. */ + public EmergencyRegResult getEmergencyRegResult() { + return mLastEmergencyRegResult; + }; + + /** + * Handles emergency transport change by setting new emergency mode. + * + * @param mode the new emergency mode + */ + public void onEmergencyTransportChanged(@EmergencyConstants.EmergencyMode int mode) { + setEmergencyMode(mode); + } + + /** + * Handles emergency call state change. + * + * @param state the new call state + * @param callId the callId whose state has changed + */ + public void onEmergencyCallStateChanged(Call.State state, String callId) { + if (state == Call.State.ACTIVE) { + mActiveEmergencyCalls.add(callId); + } + } + + /** Returns {@code true} if any phones from PhoneFactory have radio on. */ + private boolean isRadioOn() { + boolean result = false; + for (Phone phone : mPhoneFactoryProxy.getPhones()) { + result |= phone.isRadioOn(); + } + return result; + } + + /** Returns {@code true} if airplane mode is on. */ + private boolean isAirplaneModeOn(Context context) { + return Settings.Global.getInt(context.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) > 0; + } + + /** + * If needed, block until the default data is switched for outgoing emergency call, or + * timeout expires. + * + * @param phone The Phone to switch the DDS on. + * @param completeConsumer The consumer to call once the default data subscription has been + * switched, provides {@code true} result if the switch happened + * successfully or {@code false} if the operation timed out/failed. + */ + @VisibleForTesting + public void delayDialForDdsSwitch(Phone phone, Consumer completeConsumer) { + if (phone == null) { + // Do not block indefinitely. + completeConsumer.accept(false); + } + try { + // Waiting for PhoneSwitcher to complete the operation. + CompletableFuture future = possiblyOverrideDefaultDataForEmergencyCall(phone); + // In the case that there is an issue or bug in PhoneSwitcher logic, do not wait + // indefinitely for the future to complete. Instead, set a timeout that will complete + // the future as to not block the outgoing call indefinitely. + CompletableFuture timeout = new CompletableFuture<>(); + mHandler.postDelayed(() -> timeout.complete(false), DEFAULT_DATA_SWITCH_TIMEOUT_MS); + // Also ensure that the Consumer is completed on the main thread. + CompletableFuture unused = future.acceptEitherAsync(timeout, completeConsumer, + phone.getContext().getMainExecutor()); + } catch (Exception e) { + Rlog.w(TAG, "delayDialForDdsSwitch - exception= " + e.getMessage()); + } + } + + /** + * If needed, block until Default Data subscription is switched for outgoing emergency call. + * + *

+ * In some cases, we need to try to switch the Default Data subscription before placing the + * emergency call on DSDS devices. This includes the following situation: - The modem does not + * support processing GNSS SUPL requests on the non-default data subscription. For some carriers + * that do not provide a control plane fallback mechanism, the SUPL request will be dropped and + * we will not be able to get the user's location for the emergency call. In this case, we need + * to swap default data temporarily. + * + * @param phone Evaluates whether or not the default data should be moved to the phone + * specified. Should not be null. + */ + private CompletableFuture possiblyOverrideDefaultDataForEmergencyCall( + @NonNull Phone phone) { + int phoneCount = mTelephonyManagerProxy.getPhoneCount(); + // Do not override DDS if this is a single SIM device. + if (phoneCount <= PhoneConstants.MAX_PHONE_COUNT_SINGLE_SIM) { + return CompletableFuture.completedFuture(Boolean.TRUE); + } + + // Do not switch Default data if this device supports emergency SUPL on non-DDS. + if (!mIsSuplDdsSwitchRequiredForEmergencyCall) { + Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, does not " + + "require DDS switch."); + return CompletableFuture.completedFuture(Boolean.TRUE); + } + + CarrierConfigManager cfgManager = (CarrierConfigManager) phone.getContext() + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (cfgManager == null) { + // For some reason CarrierConfigManager is unavailable. Do not block emergency call. + Rlog.w(TAG, "possiblyOverrideDefaultDataForEmergencyCall: couldn't get" + + "CarrierConfigManager"); + return CompletableFuture.completedFuture(Boolean.TRUE); + } + + // Only override default data if we are IN_SERVICE already. + if (!isAvailableForEmergencyCalls(phone)) { + Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS"); + return CompletableFuture.completedFuture(Boolean.TRUE); + } + + // Only override default data if we are not roaming, we do not want to switch onto a network + // that only supports data plane only (if we do not know). + boolean isRoaming = phone.getServiceState().getVoiceRoaming(); + // In some roaming conditions, we know the roaming network doesn't support control plane + // fallback even though the home operator does. For these operators we will need to do a DDS + // switch anyway to make sure the SUPL request doesn't fail. + boolean roamingNetworkSupportsControlPlaneFallback = true; + String[] dataPlaneRoamPlmns = cfgManager.getConfigForSubId(phone.getSubId()).getStringArray( + CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY); + if (dataPlaneRoamPlmns != null && Arrays.asList(dataPlaneRoamPlmns) + .contains(phone.getServiceState().getOperatorNumeric())) { + roamingNetworkSupportsControlPlaneFallback = false; + } + if (isRoaming && roamingNetworkSupportsControlPlaneFallback) { + Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: roaming network is assumed " + + "to support CP fallback, not switching DDS."); + return CompletableFuture.completedFuture(Boolean.TRUE); + } + // Do not try to swap default data if we support CS fallback or it is assumed that the + // roaming network supports control plane fallback, we do not want to introduce a lag in + // emergency call setup time if possible. + final boolean supportsCpFallback = cfgManager.getConfigForSubId(phone.getSubId()).getInt( + CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_ONLY) + != CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY; + if (supportsCpFallback && roamingNetworkSupportsControlPlaneFallback) { + Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS, carrier " + + "supports CP fallback."); + return CompletableFuture.completedFuture(Boolean.TRUE); + } + + // Get extension time, may be 0 for some carriers that support ECBM as well. Use + // CarrierConfig default if format fails. + int extensionTime = 0; + try { + extensionTime = Integer.parseInt(cfgManager.getConfigForSubId(phone.getSubId()) + .getString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0")); + } catch (NumberFormatException e) { + // Just use default. + } + CompletableFuture modemResultFuture = new CompletableFuture<>(); + try { + Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: overriding DDS for " + + extensionTime + "seconds"); + mPhoneSwitcherProxy.getPhoneSwitcher().overrideDefaultDataForEmergency( + phone.getPhoneId(), extensionTime, modemResultFuture); + // Catch all exceptions, we want to continue with emergency call if possible. + } catch (Exception e) { + Rlog.w(TAG, + "possiblyOverrideDefaultDataForEmergencyCall: exception = " + e.getMessage()); + modemResultFuture = CompletableFuture.completedFuture(Boolean.FALSE); + } + return modemResultFuture; + } + + /** + * Returns true if the state of the Phone is IN_SERVICE or available for emergency calling only. + */ + private boolean isAvailableForEmergencyCalls(Phone phone) { + return ServiceState.STATE_IN_SERVICE == phone.getServiceState().getState() + || phone.getServiceState().isEmergencyOnly(); + } +} diff --git a/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java b/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java new file mode 100644 index 0000000000..827e495f85 --- /dev/null +++ b/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2022 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.emergency; + +import android.content.Context; +import android.content.Intent; +import android.os.UserHandle; +import android.provider.Settings; +import android.telephony.TelephonyManager; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.telephony.Rlog; + +import java.util.ArrayList; +import java.util.List; + +/** + * Helper class that implements special behavior related to emergency calls or making phone calls + * when the radio is in the POWER_OFF STATE. Specifically, this class handles the case of the user + * trying to dial an emergency number while the radio is off (i.e. the device is in airplane mode) + * or a normal number while the radio is off (because of the device is on Bluetooth), by turning the + * radio back on, waiting for it to come up, and then retrying the call. + */ +public class RadioOnHelper implements RadioOnStateListener.Callback { + + private static final String TAG = "RadioOnStateListener"; + + private final Context mContext; + private RadioOnStateListener.Callback mCallback; + private List mListeners; + private List mInProgressListeners; + private boolean mIsRadioOnCallingEnabled; + + public RadioOnHelper(Context context) { + mContext = context; + mInProgressListeners = new ArrayList<>(2); + } + + private void setupListeners() { + if (mListeners == null) { + mListeners = new ArrayList<>(2); + } + int activeModems = TelephonyManager.from(mContext).getActiveModemCount(); + // Add new listeners if active modem count increased. + while (mListeners.size() < activeModems) { + mListeners.add(new RadioOnStateListener()); + } + // Clean up listeners if active modem count decreased. + while (mListeners.size() > activeModems) { + mListeners.get(mListeners.size() - 1).cleanup(); + mListeners.remove(mListeners.size() - 1); + } + } + + /** + * Starts the "turn on radio" sequence. This is the (single) external API of the RadioOnHelper + * class. + * + * This method kicks off the following sequence: + * - Power on the radio for each Phone + * - Listen for radio events telling us the radio has come up. + * - Retry if we've gone a significant amount of time without any response from the radio. + * - Finally, clean up any leftover state. + * + * This method is safe to call from any thread, since it simply posts a message to the + * RadioOnHelper's handler (thus ensuring that the rest of the sequence is entirely serialized, + * and runs on the main looper.) + */ + public void triggerRadioOnAndListen(RadioOnStateListener.Callback callback, + boolean forEmergencyCall, Phone phoneForEmergencyCall, boolean isTestEmergencyNumber) { + setupListeners(); + mCallback = callback; + mInProgressListeners.clear(); + mIsRadioOnCallingEnabled = false; + for (int i = 0; i < TelephonyManager.from(mContext).getActiveModemCount(); i++) { + Phone phone = PhoneFactory.getPhone(i); + if (phone == null) { + continue; + } + + mInProgressListeners.add(mListeners.get(i)); + mListeners.get(i).waitForRadioOn(phone, this, forEmergencyCall, forEmergencyCall + && phone == phoneForEmergencyCall); + } + powerOnRadio(forEmergencyCall, phoneForEmergencyCall, isTestEmergencyNumber); + } + + /** + * Attempt to power on the radio (i.e. take the device out of airplane mode). We'll eventually + * get an onServiceStateChanged() callback when the radio successfully comes up. + */ + private void powerOnRadio(boolean forEmergencyCall, Phone phoneForEmergencyCall, + boolean isTestEmergencyNumber) { + + // Always try to turn on the radio here independent of APM setting - if we got here in the + // first place, the radio is off independent of APM setting. + for (Phone phone : PhoneFactory.getPhones()) { + Rlog.d(TAG, "powerOnRadio, enabling Radio"); + if (isTestEmergencyNumber) { + phone.setRadioPowerOnForTestEmergencyCall(phone == phoneForEmergencyCall); + } else { + phone.setRadioPower(true, forEmergencyCall, phone == phoneForEmergencyCall, + false); + } + } + + // If airplane mode is on, we turn it off the same way that the Settings activity turns it + // off to keep the setting in sync. + if (Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) > 0) { + Rlog.d(TAG, "==> Turning off airplane mode for emergency call."); + + // Change the system setting + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0); + + // Post the broadcast intend for change in airplane mode TODO: We really should not be + // in charge of sending this broadcast. If changing the setting is sufficient to trigger + // all of the rest of the logic, then that should also trigger the broadcast intent. + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", false); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } + } + + /** + * This method is called from multiple Listeners on the Main Looper. Synchronization is not + * necessary. + */ + @Override + public void onComplete(RadioOnStateListener listener, boolean isRadioReady) { + mIsRadioOnCallingEnabled |= isRadioReady; + mInProgressListeners.remove(listener); + if (mCallback != null && mInProgressListeners.isEmpty()) { + mCallback.onComplete(null, mIsRadioOnCallingEnabled); + } + } + + @Override + public boolean isOkToCall(Phone phone, int serviceState) { + return (mCallback == null) ? false : mCallback.isOkToCall(phone, serviceState); + } +} diff --git a/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java b/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java new file mode 100644 index 0000000000..01eaaa6307 --- /dev/null +++ b/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2022 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.emergency; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.telephony.ServiceState; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.SomeArgs; +import com.android.internal.telephony.Phone; +import com.android.telephony.Rlog; + +import java.util.Locale; + +/** + * Helper class that listens to a Phone's radio state and sends an onComplete callback when we + * return true for isOkToCall. + */ +public class RadioOnStateListener { + + public interface Callback { + /** + * Receives the result of the RadioOnStateListener's attempt to turn on the radio. + */ + void onComplete(RadioOnStateListener listener, boolean isRadioReady); + + /** + * Given the Phone and the new service state of that phone, return whether or not this phone + * is ok to call. If it is, onComplete will be called shortly after. + */ + boolean isOkToCall(Phone phone, int serviceState); + } + + private static final String TAG = "RadioOnStateListener"; + + // Number of times to retry the call, and time between retry attempts. + // not final for testing + private static int MAX_NUM_RETRIES = 5; + // not final for testing + private static long TIME_BETWEEN_RETRIES_MILLIS = 5000; // msec + + // Handler message codes; see handleMessage() + private static final int MSG_START_SEQUENCE = 1; + @VisibleForTesting + public static final int MSG_SERVICE_STATE_CHANGED = 2; + private static final int MSG_RETRY_TIMEOUT = 3; + @VisibleForTesting + public static final int MSG_RADIO_ON = 4; + public static final int MSG_RADIO_OFF_OR_NOT_AVAILABLE = 5; + + private final Handler mHandler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_START_SEQUENCE: + SomeArgs args = (SomeArgs) msg.obj; + try { + Phone phone = (Phone) args.arg1; + RadioOnStateListener.Callback callback = + (RadioOnStateListener.Callback) args.arg2; + boolean forEmergencyCall = (boolean) args.arg3; + boolean isSelectedPhoneForEmergencyCall = (boolean) args.arg4; + startSequenceInternal(phone, callback, forEmergencyCall, + isSelectedPhoneForEmergencyCall); + } finally { + args.recycle(); + } + break; + case MSG_SERVICE_STATE_CHANGED: + onServiceStateChanged((ServiceState) ((AsyncResult) msg.obj).result); + break; + case MSG_RADIO_ON: + onRadioOn(); + break; + case MSG_RADIO_OFF_OR_NOT_AVAILABLE: + registerForRadioOn(); + break; + case MSG_RETRY_TIMEOUT: + onRetryTimeout(); + break; + default: + Rlog.w(TAG, String.format(Locale.getDefault(), + "handleMessage: unexpected message: %d.", msg.what)); + break; + } + } + }; + + private Callback mCallback; // The callback to notify upon completion. + private Phone mPhone; // The phone that will attempt to place the call. + private boolean mForEmergencyCall; // Whether radio is being turned on for emergency call. + // Whether this phone is selected to place emergency call. Can be true only if + // mForEmergencyCall is true. + private boolean mSelectedPhoneForEmergencyCall; + private int mNumRetriesSoFar; + + /** + * Starts the "wait for radio" sequence. This is the (single) external API of the + * RadioOnStateListener class. + * + * This method kicks off the following sequence: + * - Listen for the service state change event telling us the radio has come up. + * - Retry if we've gone {@link #TIME_BETWEEN_RETRIES_MILLIS} without any response from the + * radio. + * - Finally, clean up any leftover state. + * + * This method is safe to call from any thread, since it simply posts a message to the + * RadioOnStateListener's handler (thus ensuring that the rest of the sequence is entirely + * serialized, and runs only on the handler thread.) + */ + public void waitForRadioOn(Phone phone, Callback callback, + boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) { + Rlog.d(TAG, "waitForRadioOn: Phone " + phone.getPhoneId()); + + if (mPhone != null) { + // If there already is an ongoing request, ignore the new one! + return; + } + + SomeArgs args = SomeArgs.obtain(); + args.arg1 = phone; + args.arg2 = callback; + args.arg3 = forEmergencyCall; + args.arg4 = isSelectedPhoneForEmergencyCall; + mHandler.obtainMessage(MSG_START_SEQUENCE, args).sendToTarget(); + } + + /** + * Actual implementation of waitForRadioOn(), guaranteed to run on the handler thread. + * + * @see #waitForRadioOn + */ + private void startSequenceInternal(Phone phone, Callback callback, + boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) { + Rlog.d(TAG, "startSequenceInternal: Phone " + phone.getPhoneId()); + + // First of all, clean up any state left over from a prior RadioOn call sequence. This + // ensures that we'll behave sanely if another startTurnOnRadioSequence() comes in while + // we're already in the middle of the sequence. + cleanup(); + + mPhone = phone; + mCallback = callback; + mForEmergencyCall = forEmergencyCall; + mSelectedPhoneForEmergencyCall = isSelectedPhoneForEmergencyCall; + + registerForServiceStateChanged(); + // Register for RADIO_OFF to handle cases where emergency call is dialed before + // we receive UNSOL_RESPONSE_RADIO_STATE_CHANGED with RADIO_OFF. + registerForRadioOff(); + // Next step: when the SERVICE_STATE_CHANGED event comes in, we'll retry the call; see + // onServiceStateChanged(). But also, just in case, start a timer to make sure we'll retry + // the call even if the SERVICE_STATE_CHANGED event never comes in for some reason. + startRetryTimer(); + } + + /** + * Handles the SERVICE_STATE_CHANGED event. This event tells us that the radio state has changed + * and is probably coming up. We can now check to see if the conditions are met to place the + * call with {@link Callback#isOkToCall} + */ + private void onServiceStateChanged(ServiceState state) { + if (mPhone == null) { + return; + } + Rlog.d(TAG, String.format("onServiceStateChanged(), new state = %s, Phone = %s", state, + mPhone.getPhoneId())); + + // Possible service states: + // - STATE_IN_SERVICE // Normal operation + // - STATE_OUT_OF_SERVICE // Still searching for an operator to register to, + // // or no radio signal + // - STATE_EMERGENCY_ONLY // Only emergency numbers are allowed; currently not used + // - STATE_POWER_OFF // Radio is explicitly powered off (airplane mode) + + if (isOkToCall(state.getState())) { + // Woo hoo! It's OK to actually place the call. + Rlog.d(TAG, "onServiceStateChanged: ok to call!"); + + onComplete(true); + cleanup(); + } else { + // The service state changed, but we're still not ready to call yet. + Rlog.d(TAG, "onServiceStateChanged: not ready to call yet, keep waiting."); + } + } + + private void onRadioOn() { + if (mPhone == null) { + return; + } + ServiceState state = mPhone.getServiceState(); + Rlog.d(TAG, String.format("onRadioOn, state = %s, Phone = %s", state, mPhone.getPhoneId())); + if (isOkToCall(state.getState())) { + onComplete(true); + cleanup(); + } else { + Rlog.d(TAG, "onRadioOn: not ready to call yet, keep waiting."); + } + } + + /** + * Callback to see if it is okay to call yet, given the current conditions. + */ + private boolean isOkToCall(int serviceState) { + return (mCallback == null) ? false : mCallback.isOkToCall(mPhone, serviceState); + } + + /** + * Handles the retry timer expiring. + */ + private void onRetryTimeout() { + if (mPhone == null) { + return; + } + int serviceState = mPhone.getServiceState().getState(); + Rlog.d(TAG, + String.format(Locale.getDefault(), + "onRetryTimeout(): phone state = %s, service state = %d, retries = %d.", + mPhone.getState(), serviceState, mNumRetriesSoFar)); + + // - If we're actually in a call, we've succeeded. + // - Otherwise, if the radio is now on, that means we successfully got out of airplane mode + // but somehow didn't get the service state change event. In that case, try to place the + // call. + // - If the radio is still powered off, try powering it on again. + + if (isOkToCall(serviceState)) { + Rlog.d(TAG, "onRetryTimeout: Radio is on. Cleaning up."); + + // Woo hoo -- we successfully got out of airplane mode. + onComplete(true); + cleanup(); + } else { + // Uh oh; we've waited the full TIME_BETWEEN_RETRIES_MILLIS and the radio is still not + // powered-on. Try again. + + mNumRetriesSoFar++; + Rlog.d(TAG, "mNumRetriesSoFar is now " + mNumRetriesSoFar); + + if (mNumRetriesSoFar > MAX_NUM_RETRIES) { + Rlog.w(TAG, "Hit MAX_NUM_RETRIES; giving up."); + cleanup(); + } else { + Rlog.d(TAG, "Trying (again) to turn on the radio."); + mPhone.setRadioPower(true, mForEmergencyCall, mSelectedPhoneForEmergencyCall, + false); + startRetryTimer(); + } + } + } + + /** + * Clean up when done with the whole sequence: either after successfully turning on the radio, + * or after bailing out because of too many failures. + * + * The exact cleanup steps are: + * - Notify callback if we still hadn't sent it a response. + * - Double-check that we're not still registered for any telephony events + * - Clean up any extraneous handler messages (like retry timeouts) still in the queue + * + * Basically this method guarantees that there will be no more activity from the + * RadioOnStateListener until someone kicks off the whole sequence again with another call to + * {@link #waitForRadioOn} + * + * TODO: Do the work for the comment below: Note we don't call this method simply after a + * successful call to placeCall(), since it's still possible the call will disconnect very + * quickly with an OUT_OF_SERVICE error. + */ + public void cleanup() { + Rlog.d(TAG, "cleanup()"); + + // This will send a failure call back if callback has yet to be invoked. If the callback was + // already invoked, it's a no-op. + onComplete(false); + + unregisterForServiceStateChanged(); + unregisterForRadioOff(); + unregisterForRadioOn(); + cancelRetryTimer(); + + // Used for unregisterForServiceStateChanged() so we null it out here instead. + mPhone = null; + mNumRetriesSoFar = 0; + } + + private void startRetryTimer() { + cancelRetryTimer(); + mHandler.sendEmptyMessageDelayed(MSG_RETRY_TIMEOUT, TIME_BETWEEN_RETRIES_MILLIS); + } + + private void cancelRetryTimer() { + mHandler.removeMessages(MSG_RETRY_TIMEOUT); + } + + private void registerForServiceStateChanged() { + // Unregister first, just to make sure we never register ourselves twice. (We need this + // because Phone.registerForServiceStateChanged() does not prevent multiple registration of + // the same handler.) + unregisterForServiceStateChanged(); + mPhone.registerForServiceStateChanged(mHandler, MSG_SERVICE_STATE_CHANGED, null); + } + + private void unregisterForServiceStateChanged() { + // This method is safe to call even if we haven't set mPhone yet. + if (mPhone != null) { + mPhone.unregisterForServiceStateChanged(mHandler); // Safe even if unnecessary + } + mHandler.removeMessages(MSG_SERVICE_STATE_CHANGED); // Clean up any pending messages too + } + + private void registerForRadioOff() { + mPhone.mCi.registerForOffOrNotAvailable(mHandler, MSG_RADIO_OFF_OR_NOT_AVAILABLE, null); + } + + private void unregisterForRadioOff() { + // This method is safe to call even if we haven't set mPhone yet. + if (mPhone != null) { + mPhone.mCi.unregisterForOffOrNotAvailable(mHandler); // Safe even if unnecessary + } + mHandler.removeMessages(MSG_RADIO_OFF_OR_NOT_AVAILABLE); // Clean up any pending messages + } + + private void registerForRadioOn() { + unregisterForRadioOff(); + mPhone.mCi.registerForOn(mHandler, MSG_RADIO_ON, null); + } + + private void unregisterForRadioOn() { + // This method is safe to call even if we haven't set mPhone yet. + if (mPhone != null) { + mPhone.mCi.unregisterForOn(mHandler); // Safe even if unnecessary + } + mHandler.removeMessages(MSG_RADIO_ON); // Clean up any pending messages too + } + + private void onComplete(boolean isRadioReady) { + if (mCallback != null) { + Callback tempCallback = mCallback; + mCallback = null; + tempCallback.onComplete(this, isRadioReady); + } + } + + @VisibleForTesting + public Handler getHandler() { + return mHandler; + } + + @VisibleForTesting + public void setMaxNumRetries(int retries) { + MAX_NUM_RETRIES = retries; + } + + @VisibleForTesting + public void setTimeBetweenRetriesMillis(long timeMs) { + TIME_BETWEEN_RETRIES_MILLIS = timeMs; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || !getClass().equals(o.getClass())) + return false; + + RadioOnStateListener that = (RadioOnStateListener) o; + + if (mNumRetriesSoFar != that.mNumRetriesSoFar) { + return false; + } + if (mCallback != null ? !mCallback.equals(that.mCallback) : that.mCallback != null) { + return false; + } + return mPhone != null ? mPhone.equals(that.mPhone) : that.mPhone == null; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 31 * hash + mNumRetriesSoFar; + hash = 31 * hash + (mCallback == null ? 0 : mCallback.hashCode()); + hash = 31 * hash + (mPhone == null ? 0 : mPhone.hashCode()); + return hash; + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java new file mode 100644 index 0000000000..ef779848b3 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2022 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.emergency; + +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.AsyncResult; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings; +import android.telephony.CarrierConfigManager; +import android.telephony.DisconnectCause; +import android.telephony.EmergencyRegResult; +import android.telephony.ServiceState; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.data.PhoneSwitcher; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +/** + * Unit tests for EmergencyStateTracker + */ +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class EmergencyStateTrackerTest extends TelephonyTest { + + private static final String TEST_CALL_ID = "00001"; + + @Mock EmergencyStateTracker.PhoneFactoryProxy mPhoneFactoryProxy; + @Mock EmergencyStateTracker.PhoneSwitcherProxy mPhoneSwitcherProxy; + @Mock EmergencyStateTracker.TelephonyManagerProxy mTelephonyManagerProxy; + @Mock PhoneSwitcher mPhoneSwitcher; + @Mock RadioOnHelper mRadioOnHelper; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + MockitoAnnotations.initMocks(this); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + @SmallTest + public void getInstance_notInitializedTillMake() throws IllegalStateException { + assertThrows(IllegalStateException.class, () -> { + EmergencyStateTracker.getInstance(); + }); + + EmergencyStateTracker.make(mContext, true); + + assertNotNull(EmergencyStateTracker.getInstance()); + } + + @Test + @SmallTest + public void getInstance_returnsSameInstance() { + EmergencyStateTracker.make(mContext, true); + EmergencyStateTracker instance1 = EmergencyStateTracker.getInstance(); + EmergencyStateTracker instance2 = EmergencyStateTracker.getInstance(); + + assertSame(instance1, instance2); + } + + /** + * Test that the EmergencyStateTracker turns on radio, performs a DDS switch and sets emergency + * mode switch when we are not roaming and the carrier only supports SUPL over the data plane. + */ + @Test + @SmallTest + public void startEmergencyCall_radioOff_turnOnRadioSwitchDdsAndSetEmergencyMode() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones and set radio off + Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */, + false /* isRadioOn */); + CarrierConfigManager cfgManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( + CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, + null); + cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( + CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY); + cfgManager.getConfigForSubId(testPhone.getSubId()) + .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "150"); + // Spy is used to capture consumer in delayDialForDdsSwitch + EmergencyStateTracker spyEst = spy(emergencyStateTracker); + + CompletableFuture unused = spyEst.startEmergencyCall(testPhone, TEST_CALL_ID, + false); + + // startEmergencyCall should trigger radio on + ArgumentCaptor callback = ArgumentCaptor + .forClass(RadioOnStateListener.Callback.class); + verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone), + eq(false)); + // isOkToCall() should return true once radio is on + assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE)); + when(mSST.isRadioOn()).thenReturn(true); + assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE)); + // Once radio on is complete, trigger delay dial + callback.getValue().onComplete(null, true); + ArgumentCaptor> completeConsumer = ArgumentCaptor + .forClass(Consumer.class); + verify(spyEst).delayDialForDdsSwitch(eq(testPhone), completeConsumer.capture()); + verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /* phoneId */ , + eq(150) /* extensionTime */, any()); + // After dds switch completes successfully, set emergency mode + completeConsumer.getValue().accept(true); + verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any()); + } + + /** + * Test that if startEmergencyCall fails to turn on radio, then it's future completes with + * DisconnectCause.POWER_OFF. + */ + @Test + @SmallTest + public void startEmergencyCall_radioOnFails_returnsDisconnectCausePowerOff() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones and set radio off + Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */, + false /* isRadioOn */); + + CompletableFuture future = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // startEmergencyCall should trigger radio on + ArgumentCaptor callback = ArgumentCaptor + .forClass(RadioOnStateListener.Callback.class); + verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone), + eq(false)); + // Verify future completes with DisconnectCause.POWER_OFF if radio not ready + CompletableFuture unused = future.thenAccept((result) -> { + assertEquals((Integer) result, (Integer) DisconnectCause.POWER_OFF); + }); + callback.getValue().onComplete(null, false /* isRadioReady */); + } + + /** + * Test that the EmergencyStateTracker does not perform a DDS switch when the carrier supports + * control-plane fallback. Radio is set to on so RadioOnHelper not triggered. + */ + @Test + @SmallTest + public void startEmergencyCall_cpFallback_noDdsSwitch() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones and set radio on + Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */, + true /* isRadioOn */); + CarrierConfigManager cfgManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( + CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, + null); + cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( + CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK); + cfgManager.getConfigForSubId(testPhone.getSubId()) + .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"); + + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // Radio already on so shouldn't trigger this + verify(mRadioOnHelper, never()).triggerRadioOnAndListen(any(), anyBoolean(), any(), + anyBoolean()); + // Carrier supports control-plane fallback, so no DDS switch + verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any()); + } + + /** + * Test that the EmergencyStateTracker does not perform a DDS switch if the non-DDS supports + * SUPL. + */ + @Test + @SmallTest + public void startEmergencyCall_supportsSuplOnNonDds_noDdsSwitch() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + false /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones + Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */, + true /* isRadioOn */); + CarrierConfigManager cfgManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( + CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, + null); + cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( + CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY); + cfgManager.getConfigForSubId(testPhone.getSubId()) + .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"); + + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // non-DDS supports SUPL, so no DDS switch + verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any()); + } + + /** + * Test that the EmergencyStateTracker does not perform a DDS switch when the carrier does not + * support control-plane fallback while roaming. + */ + @Test + @SmallTest + public void startEmergencyCall_roaming_noDdsSwitch() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones + Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, + true /* isRadioOn */); + CarrierConfigManager cfgManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( + CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, + null); + cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( + CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY); + cfgManager.getConfigForSubId(testPhone.getSubId()) + .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"); + + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // Is roaming, so no DDS switch + verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any()); + } + + /** + * Test that the EmergencyStateTracker does perform a DDS switch even though the carrier + * supports control-plane fallback and the roaming partner is configured to look like a home + * network. + */ + @Test + @SmallTest + public void startEmergencyCall_roamingCarrierConfig_switchDds() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones + Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */, + true /* isRadioOn */); + // Setup voice roaming scenario + String testRoamingOperator = "001001"; + testPhone.getServiceState().setOperatorName("TestTel", "TestTel", testRoamingOperator); + String[] roamingPlmns = new String[1]; + roamingPlmns[0] = testRoamingOperator; + CarrierConfigManager cfgManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( + CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, + roamingPlmns); + cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( + CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK); + cfgManager.getConfigForSubId(testPhone.getSubId()) + .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"); + + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // Verify DDS switch + verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /* phoneId */, + eq(0) /* extensionTime */, any()); + } + + /** + * Test that the EmergencyStateTracker does perform a DDS switch even though the carrier + * supports control-plane fallback if we are roaming and the roaming partner is configured to + * use data plane only SUPL. + */ + @Test + @SmallTest + public void startEmergencyCall_roamingCarrierConfigWhileRoaming_switchDds() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones + Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, + true /* isRadioOn */); + // Setup voice roaming scenario + String testRoamingOperator = "001001"; + testPhone.getServiceState().setOperatorName("TestTel", "TestTel", testRoamingOperator); + String[] roamingPlmns = new String[1]; + roamingPlmns[0] = testRoamingOperator; + CarrierConfigManager cfgManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( + CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, + roamingPlmns); + cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( + CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK); + cfgManager.getConfigForSubId(testPhone.getSubId()) + .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"); + + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // Verify DDS switch + verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /* phoneId */, + eq(0) /* extensionTime */, any()); + } + + /** + * Test that once EmergencyStateTracker handler receives set emergency mode done message it sets + * IsInEmergencyCall to true, sets LastEmergencyRegResult and completes future with + * DisconnectCause.NOT_DISCONNECTED. + */ + @Test + @SmallTest + public void setEmergencyModeDone_notifiesListenersAndCompletesFuture() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phone + Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, + true /* isRadioOn */); + // Call startEmergencyCall() to set testPhone + CompletableFuture future = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + // Verify future completes with DisconnectCause.NOT_DISCONNECTED + CompletableFuture unused = future.thenAccept((result) -> { + assertEquals((Integer) result, (Integer) DisconnectCause.NOT_DISCONNECTED); + }); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + Handler handler = emergencyStateTracker.getHandler(); + Message msg = new Message(); + EmergencyRegResult regResult = new EmergencyRegResult(0, 0, 0, true, false, 0, 1, "testMcc", + "testMnc", "testIso"); + AsyncResult ar = new AsyncResult(msg, regResult, null); + msg.obj = ar; + + msg.what = EmergencyStateTracker.MSG_SET_EMERGENCY_MODE_DONE; + handler.handleMessage(msg); + + assertTrue(emergencyStateTracker.isInEmergencyCall()); + assertTrue(emergencyStateTracker.getEmergencyRegResult().equals(regResult)); + } + + /** + * Test that once EmergencyStateTracker handler receives message to exit emergency mode, it sets + * IsInEmergencyCall to false. + */ + @Test + @SmallTest + public void exitEmergencyModeDone_isInEmergencyCallFalse() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phone + Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, + true /* isRadioOn */); + // Call startEmergencyCall() to set testPhone + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + Handler handler = emergencyStateTracker.getHandler(); + Message msg = new Message(); + EmergencyRegResult regResult = new EmergencyRegResult(0, 0, 0, true, false, 0, 1, "testMcc", + "testMnc", "testIso"); + AsyncResult ar = new AsyncResult(msg, regResult, null); + msg.obj = ar; + // Send message to set isInEmergencyCall to true + msg.what = EmergencyStateTracker.MSG_SET_EMERGENCY_MODE_DONE; + handler.handleMessage(msg); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + + msg.what = EmergencyStateTracker.MSG_EXIT_EMERGENCY_MODE_DONE; + handler.handleMessage(msg); + + assertFalse(emergencyStateTracker.isInEmergencyCall()); + } + + /** + * Test that once EmergencyStateTracker ends call, it exits emergency mode. + */ + @Test + @SmallTest + public void endCall_exitsEmergencyMode() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones + Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, + true /* isRadioOn */); + // Call startEmergencyCall() to set testPhone + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + emergencyStateTracker.endCall("testId"); + + verify(testPhone).exitEmergencyMode(any()); + } + + /** + * Test that onEmergencyTransportChanged sets the new emergency mode. + */ + @Test + @SmallTest + public void onEmergencyTransportChanged_setsEmergencyMode() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + true /* isSuplDdsSwitchRequiredForEmergencyCall */); + // Create test Phones + Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, + true /* isRadioOn */); + // Call startEmergencyCall() to set testPhone + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + emergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + + verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any()); + } + + private EmergencyStateTracker setupEmergencyStateTracker( + boolean isSuplDdsSwitchRequiredForEmergencyCall) { + doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); + return new EmergencyStateTracker(mContext, Looper.getMainLooper(), + isSuplDdsSwitchRequiredForEmergencyCall, mPhoneFactoryProxy, mPhoneSwitcherProxy, + mTelephonyManagerProxy, mRadioOnHelper); + } + + private Phone setupTestPhoneForEmergencyCall(boolean isRoaming, boolean isRadioOn) { + Phone testPhone0 = makeTestPhone(0 /* phoneId */, ServiceState.STATE_IN_SERVICE, + false /* isEmergencyOnly */); + Phone testPhone1 = makeTestPhone(1 /* phoneId */, ServiceState.STATE_OUT_OF_SERVICE, + false /* isEmergencyOnly */); + List phones = new ArrayList<>(2); + phones.add(testPhone0); + phones.add(testPhone1); + doReturn(isRadioOn).when(testPhone0).isRadioOn(); + doReturn(isRadioOn).when(testPhone1).isRadioOn(); + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); + doReturn(2).when(mTelephonyManagerProxy).getPhoneCount(); + when(mPhoneFactoryProxy.getPhones()).thenReturn(phones.toArray(new Phone[phones.size()])); + testPhone0.getServiceState().setRoaming(isRoaming); + return testPhone0; + } + + private Phone makeTestPhone(int phoneId, int serviceState, boolean isEmergencyOnly) { + Phone phone = mock(Phone.class); + ServiceState testServiceState = new ServiceState(); + testServiceState.setState(serviceState); + testServiceState.setEmergencyOnly(isEmergencyOnly); + when(phone.getContext()).thenReturn(mContext); + when(phone.getServiceState()).thenReturn(testServiceState); + when(phone.getPhoneId()).thenReturn(phoneId); + when(phone.getSubId()).thenReturn(0); + when(phone.getServiceStateTracker()).thenReturn(mSST); + return phone; + } +} \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java new file mode 100644 index 0000000000..7ba6f01fc4 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2022 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.emergency; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.os.AsyncResult; +import android.os.Handler; +import android.telephony.ServiceState; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** + * Tests the RadioOnStateListener, which listens to one Phone and waits until its service state + * changes to accepting emergency calls or in service. If it can not find a tower to camp onto for + * emergency calls, then it will fail after a timeout period. + */ +@RunWith(AndroidJUnit4.class) +public class RadioOnStateListenerTest extends TelephonyTest { + + private static final long TIMEOUT_MS = 1000; + + @Mock Phone mMockPhone; + @Mock RadioOnStateListener.Callback mCallback; + @Mock CommandsInterface mMockCi; + RadioOnStateListener mListener; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + MockitoAnnotations.initMocks(this); + mListener = new RadioOnStateListener(); + } + + @After + public void tearDown() throws Exception { + mListener.setTimeBetweenRetriesMillis(5000); + mListener.setMaxNumRetries(5); + mListener.getHandler().removeCallbacksAndMessages(null); + // Wait for the queue to clear... + waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS /* ms timeout */); + mListener = null; + super.tearDown(); + } + + /** + * Ensure that we successfully register for the ServiceState changed messages in Telephony. + */ + @Test + public void testRegisterForCallback() { + mMockPhone.mCi = mMockCi; + mListener.waitForRadioOn(mMockPhone, mCallback, false, false); + + waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); + + verify(mMockPhone).unregisterForServiceStateChanged(any(Handler.class)); + verify(mMockPhone).registerForServiceStateChanged(any(Handler.class), + eq(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED), isNull()); + + verify(mMockCi).registerForOffOrNotAvailable(any(Handler.class), + eq(RadioOnStateListener.MSG_RADIO_OFF_OR_NOT_AVAILABLE), isNull()); + } + + /** + * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returns true, so we are + * expecting {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to + * return true. + */ + @Test + public void testPhoneChangeState_OkToCallTrue() { + ServiceState state = new ServiceState(); + state.setState(ServiceState.STATE_IN_SERVICE); + when(mMockPhone.getServiceState()).thenReturn(state); + when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(true); + mMockPhone.mCi = mMockCi; + mListener.waitForRadioOn(mMockPhone, mCallback, false, false); + waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); + + mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED, + new AsyncResult(null, state, null)).sendToTarget(); + + waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); + verify(mCallback).onComplete(eq(mListener), eq(true)); + } + + /** + * We never receive a + * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} because + * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returns false. + */ + @Test + public void testPhoneChangeState_NoOkToCall_Timeout() { + ServiceState state = new ServiceState(); + state.setState(ServiceState.STATE_OUT_OF_SERVICE); + when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false); + when(mMockPhone.getServiceState()).thenReturn(state); + mMockPhone.mCi = mMockCi; + mListener.waitForRadioOn(mMockPhone, mCallback, false, false); + waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); + + mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED, + new AsyncResult(null, state, null)).sendToTarget(); + + waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); + verify(mCallback, never()).onComplete(any(RadioOnStateListener.class), anyBoolean()); + } + + /** + * Tests {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returning false and + * hitting the max number of retries. This should result in + * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} returning + * false. + */ + @Test + public void testTimeout_RetryFailure() { + ServiceState state = new ServiceState(); + state.setState(ServiceState.STATE_POWER_OFF); + when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); + when(mMockPhone.getServiceState()).thenReturn(state); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false); + mListener.setTimeBetweenRetriesMillis(0/* ms */); + mListener.setMaxNumRetries(2); + + // Wait for the timer to expire and check state manually in onRetryTimeout + mMockPhone.mCi = mMockCi; + mListener.waitForRadioOn(mMockPhone, mCallback, false, false); + waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS); + + verify(mCallback).onComplete(eq(mListener), eq(false)); + verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(false), eq(false), eq(false)); + } + + @Test + public void testTimeout_RetryFailure_ForEmergency() { + ServiceState state = new ServiceState(); + state.setState(ServiceState.STATE_POWER_OFF); + when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); + when(mMockPhone.getServiceState()).thenReturn(state); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false); + mListener.setTimeBetweenRetriesMillis(0/* ms */); + mListener.setMaxNumRetries(2); + + // Wait for the timer to expire and check state manually in onRetryTimeout + mMockPhone.mCi = mMockCi; + mListener.waitForRadioOn(mMockPhone, mCallback, true, true); + waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS ); + + verify(mCallback).onComplete(eq(mListener), eq(false)); + verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(true), eq(true), eq(false)); + } +} \ No newline at end of file -- GitLab From 69a3faac40a518fd0af268c700f3921cc93e1f78 Mon Sep 17 00:00:00 2001 From: Hwangoo Park Date: Wed, 14 Dec 2022 00:32:39 +0000 Subject: [PATCH 265/656] Refactor SMS handling for domain selection This change is to apply the domain selection model. If the domain selection model is supported, the domain selection for sending a MO SMS will be done by the domain selection service and SmsDispatchersController should wait for the completion of domain selection before sending a MO SMS. SmsDispatchersController sends a MO SMS according to the selected domain - DOMAIN_PS uses ImsSmsDispatcher, and DOMAIN_CS uses CdmaSMSDispatcher or GsmSMSDispatcher. If the domain selection model is not supported, it works with the existing logic to provide backward compatibility. The followings were considered while refactoring this component: 1) interwork with the domain selection module asynchronously. 2) interwork with the EmergencyStateTracker if an emergency SMS. 3) should handle sending the multiple SMS while the domain selection is running. 4) should handle sending the retry SMS also. Bug: 243377249 Test: atest SmsDispatchersControllerTest Test: manual (verify IMS/GSM/CDMA MO SMS for normal/emergency SMS when domain selection disabled) Test: manual (verify retry SMS for normal/emergency SMS when domain selection disabled) Test: manual (verify IMS/GSM/CDMA MO SMS for normal/emergency SMS when domain selection enabled) Test: manual (verify retry SMS for normal/emergency SMS when domain selection enabled) Change-Id: I09d9af248d6bee6a2ae50b408d07cad4362a57ba --- .../telephony/SmsDispatchersController.java | 640 +++++++++++++++++- .../SmsDispatchersControllerTest.java | 597 +++++++++++++++- 2 files changed, 1230 insertions(+), 7 deletions(-) diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java index 51b22fdf31..cbd1aafcb3 100644 --- a/src/java/com/android/internal/telephony/SmsDispatchersController.java +++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java @@ -20,6 +20,8 @@ import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE; import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_NONE; import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_TEMPORARY; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Activity; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; @@ -35,14 +37,22 @@ import android.os.Message; import android.os.UserManager; import android.provider.Telephony.Sms; import android.provider.Telephony.Sms.Intents; +import android.telephony.Annotation.DisconnectCauses; +import android.telephony.DomainSelectionService; +import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.SmsManager; import android.telephony.SmsMessage; +import android.telephony.TelephonyManager; import com.android.ims.ImsManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; import com.android.internal.telephony.cdma.CdmaSMSDispatcher; +import com.android.internal.telephony.domainselection.DomainSelectionConnection; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; +import com.android.internal.telephony.domainselection.EmergencySmsDomainSelectionConnection; +import com.android.internal.telephony.domainselection.SmsDomainSelectionConnection; import com.android.internal.telephony.gsm.GsmInboundSmsHandler; import com.android.internal.telephony.gsm.GsmSMSDispatcher; import com.android.telephony.Rlog; @@ -51,6 +61,8 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CompletableFuture; /** * @@ -115,6 +127,195 @@ public class SmsDispatchersController extends Handler { private HashMap mDeliveryPendingMapFor3GPP2 = new HashMap<>(); + /** + * Testing interface for injecting mock DomainSelectionConnection and a flag to indicate + * whether the domain selection is supported. + */ + @VisibleForTesting + public interface DomainSelectionResolverProxy { + /** + * Returns a {@link DomainSelectionConnection} created using the specified + * context and callback. + * + * @param phone The {@link Phone} instance. + * @param selectorType The domain selector type to identify the domain selection connection. + * A {@link DomainSelectionService#SELECTOR_TYPE_SMS} is used for SMS. + * @param isEmergency A flag to indicate whether this connection is + * for an emergency SMS or not. + */ + @Nullable DomainSelectionConnection getDomainSelectionConnection(Phone phone, + @DomainSelectionService.SelectorType int selectorType, boolean isEmergency); + + /** + * Checks if the device supports the domain selection service to route the call / SMS / + * supplementary services to the appropriate domain. + * + * @return {@code true} if the domain selection is supported on the device, + * {@code false} otherwise. + */ + boolean isDomainSelectionSupported(); + } + + private DomainSelectionResolverProxy mDomainSelectionResolverProxy = + new DomainSelectionResolverProxy() { + @Override + @Nullable + public DomainSelectionConnection getDomainSelectionConnection(Phone phone, + @DomainSelectionService.SelectorType int selectorType, + boolean isEmergency) { + try { + return DomainSelectionResolver.getInstance().getDomainSelectionConnection( + phone, selectorType, isEmergency); + } catch (IllegalStateException e) { + // In general, DomainSelectionResolver is always initialized by TeleService, + // but if it's not initialized (like in unit tests), + // it returns null to perform the legacy behavior in this case. + return null; + } + } + + @Override + public boolean isDomainSelectionSupported() { + return DomainSelectionResolver.getInstance().isDomainSelectionSupported(); + } + }; + + /** Stores the sending SMS information for a pending request. */ + private class PendingRequest { + public static final int TYPE_DATA = 1; + public static final int TYPE_TEXT = 2; + public static final int TYPE_MULTIPART_TEXT = 3; + public static final int TYPE_RETRY_SMS = 4; + + public final int type; + public final SMSDispatcher.SmsTracker tracker; + public final String callingPackage; + public final String destAddr; + public final String scAddr; + public final ArrayList sentIntents; + public final ArrayList deliveryIntents; + public final boolean isForVvm; + // sendData specific + public final byte[] data; + public final int destPort; + // sendText / sendMultipartText specific + public final ArrayList texts; + public final Uri messageUri; + public final boolean persistMessage; + public final int priority; + public final boolean expectMore; + public final int validityPeriod; + public final long messageId; + public final boolean skipShortCodeCheck; + + PendingRequest(int type, SMSDispatcher.SmsTracker tracker, String callingPackage, + String destAddr, String scAddr, ArrayList sentIntents, + ArrayList deliveryIntents, boolean isForVvm, byte[] data, + int destPort, ArrayList texts, Uri messageUri, boolean persistMessage, + int priority, boolean expectMore, int validityPeriod, long messageId, + boolean skipShortCodeCheck) { + this.type = type; + this.tracker = tracker; + this.callingPackage = callingPackage; + this.destAddr = destAddr; + this.scAddr = scAddr; + this.sentIntents = sentIntents; + this.deliveryIntents = deliveryIntents; + this.isForVvm = isForVvm; + + this.data = data; + this.destPort = destPort; + + this.texts = texts; + this.messageUri = messageUri; + this.persistMessage = persistMessage; + this.priority = priority; + this.expectMore = expectMore; + this.validityPeriod = validityPeriod; + this.messageId = messageId; + this.skipShortCodeCheck = skipShortCodeCheck; + } + } + + /** + * Manages the {@link DomainSelectionConnection} instance and its related information. + */ + @VisibleForTesting + protected class DomainSelectionConnectionHolder + implements DomainSelectionConnection.DomainSelectionConnectionCallback { + private final boolean mEmergency; + // Manages the pending request while selecting a proper domain. + private final List mPendingRequests = new ArrayList<>(); + // Manages the domain selection connections: MO SMS or emergency SMS. + private DomainSelectionConnection mConnection; + + DomainSelectionConnectionHolder(boolean emergency) { + mEmergency = emergency; + } + + /** + * Returns a {@link DomainSelectionConnection} instance. + */ + public DomainSelectionConnection getConnection() { + return mConnection; + } + + /** + * Returns a list of {@link PendingRequest} that was added + * while the domain selection is performed. + */ + public List getPendingRequests() { + return mPendingRequests; + } + + /** + * Checks whether or not the domain selection is requested. + * If there is no pending request, the domain selection request is needed to + * select a proper domain for MO SMS. + */ + public boolean isDomainSelectionRequested() { + return !mPendingRequests.isEmpty(); + } + + /** + * Checks whether or not this holder is for an emergency SMS. + */ + public boolean isEmergency() { + return mEmergency; + } + + /** + * Clears all pending requests. + */ + public void clearAllRequests() { + mPendingRequests.clear(); + } + + /** + * Add a new pending request. + */ + public void addRequest(@NonNull PendingRequest request) { + mPendingRequests.add(request); + } + + /** + * Sets a {@link DomainSelectionConnection} instance. + */ + public void setConnection(DomainSelectionConnection connection) { + mConnection = connection; + } + + + @Override + public void onSelectionTerminated(@DisconnectCauses int cause) { + notifyDomainSelectionTerminated(this); + } + } + + /** Manages the domain selection connections: MO SMS or emergency SMS. */ + private DomainSelectionConnectionHolder mDscHolder; + private DomainSelectionConnectionHolder mEmergencyDscHolder; + /** * Puts a delivery pending tracker to the map based on the format. * @@ -189,6 +390,9 @@ public class SmsDispatchersController extends Handler { mCdmaDispatcher.dispose(); mGsmInboundSmsHandler.dispose(); mCdmaInboundSmsHandler.dispose(); + // Cancels the domain selection request if it's still in progress. + finishDomainSelection(mDscHolder); + finishDomainSelection(mEmergencyDscHolder); } /** @@ -484,15 +688,42 @@ public class SmsDispatchersController extends Handler { * @param tracker holds the SMS message to send */ public void sendRetrySms(SMSDispatcher.SmsTracker tracker) { - String oldFormat = tracker.mFormat; boolean retryUsingImsService = false; - if (!tracker.mUsesImsServiceForIms && mImsSmsDispatcher.isAvailable()) { - // If this tracker has not been handled by ImsSmsDispatcher yet and IMS Service is - // available now, retry this failed tracker using IMS Service. - retryUsingImsService = true; + if (!tracker.mUsesImsServiceForIms) { + if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { + DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false); + + // If the DomainSelectionConnection is not available, + // fallback to the legacy implementation. + if (holder != null && holder.getConnection() != null) { + sendSmsUsingDomainSelection(holder, + new PendingRequest(PendingRequest.TYPE_RETRY_SMS, tracker, + null, null, null, null, null, false, null, 0, null, null, false, + 0, false, 0, 0L, false), + "sendRetrySms"); + return; + } + } + + if (mImsSmsDispatcher.isAvailable()) { + // If this tracker has not been handled by ImsSmsDispatcher yet and IMS Service is + // available now, retry this failed tracker using IMS Service. + retryUsingImsService = true; + } } + sendRetrySms(tracker, retryUsingImsService); + } + + /** + * Retry the message along to the radio. + * + * @param tracker holds the SMS message to send + * @param retryUsingImsService a flag to indicate whether the retry SMS can use the ImsService + */ + public void sendRetrySms(SMSDispatcher.SmsTracker tracker, boolean retryUsingImsService) { + String oldFormat = tracker.mFormat; // If retryUsingImsService is true, newFormat will be IMS SMS format. Otherwise, newFormat // will be based on voice technology. String newFormat = @@ -641,6 +872,347 @@ public class SmsDispatchersController extends Handler { return (mCdmaDispatcher.getFormat().equals(format)); } + /** Sets a proxy interface for accessing the methods of {@link DomainSelectionResolver}. */ + @VisibleForTesting + public void setDomainSelectionResolverProxy(@NonNull DomainSelectionResolverProxy proxy) { + mDomainSelectionResolverProxy = proxy; + } + + /** + * Determines whether or not to use CDMA format for MO SMS when the domain selection uses. + * If the domain is {@link NetworkRegistrationInfo#DOMAIN_PS}, then format is based on + * IMS SMS format, otherwise format is based on current phone type. + * + * @return {@code true} if CDMA format should be used for MO SMS, {@code false} otherwise. + */ + private boolean isCdmaMo(@NetworkRegistrationInfo.Domain int domain) { + if (domain != NetworkRegistrationInfo.DOMAIN_PS) { + // IMS is not registered, use voice technology to determine SMS format. + return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()); + } + // IMS is registered with SMS support + return isCdmaFormat(mImsSmsDispatcher.getFormat()); + } + + /** + * Returns a {@link DomainSelectionConnectionHolder} according to the flag specified. + * + * @param emergency The flag to indicate that the domain selection is for an emergency SMS. + * @return A {@link DomainSelectionConnectionHolder} instance or null. + */ + @VisibleForTesting + @Nullable + protected DomainSelectionConnectionHolder getDomainSelectionConnectionHolder( + boolean emergency) { + return emergency ? mEmergencyDscHolder : mDscHolder; + } + + /** + * Returns a {@link DomainSelectionConnectionHolder} if the domain selection supports, + * return null otherwise. + * + * @param emergency The flag to indicate that the domain selection is for an emergency SMS. + * @return A {@link DomainSelectionConnectionHolder} that grabs the + * {@link DomainSelectionConnection} and its related information to use the domain + * selection architecture. + */ + private DomainSelectionConnectionHolder getDomainSelectionConnection(boolean emergency) { + DomainSelectionConnectionHolder holder = getDomainSelectionConnectionHolder(emergency); + DomainSelectionConnection connection = (holder != null) ? holder.getConnection() : null; + boolean created = false; + + if (connection == null) { + connection = mDomainSelectionResolverProxy.getDomainSelectionConnection( + mPhone, DomainSelectionService.SELECTOR_TYPE_SMS, emergency); + + if (connection == null) { + // Domain selection architecture is not supported. + // Use the legacy architecture. + return null; + } + + created = true; + } + + if (holder == null) { + holder = new DomainSelectionConnectionHolder(emergency); + + if (emergency) { + mEmergencyDscHolder = holder; + } else { + mDscHolder = holder; + } + } + + holder.setConnection(connection); + + return holder; + } + + /** + * Requests the domain selection for MO SMS. + * + * @param holder The {@link DomainSelectionConnectionHolder} that contains the + * {@link DomainSelectionConnection} and its related information. + */ + private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder) { + DomainSelectionService.SelectionAttributes attr = + new DomainSelectionService.SelectionAttributes.Builder(mPhone.getPhoneId(), + mPhone.getSubId(), DomainSelectionService.SELECTOR_TYPE_SMS) + .setEmergency(holder.isEmergency()) + .build(); + + if (holder.isEmergency()) { + EmergencySmsDomainSelectionConnection emergencyConnection = + (EmergencySmsDomainSelectionConnection) holder.getConnection(); + CompletableFuture future = + emergencyConnection.requestDomainSelection(attr, holder); + future.thenAcceptAsync((domain) -> { + if (VDBG) { + logd("requestDomainSelection(emergency): domain=" + + DomainSelectionService.getDomainName(domain)); + } + sendAllPendingRequests(holder, domain); + finishDomainSelection(holder); + }, this::post); + } else { + SmsDomainSelectionConnection connection = + (SmsDomainSelectionConnection) holder.getConnection(); + CompletableFuture future = connection.requestDomainSelection(attr, holder); + future.thenAcceptAsync((domain) -> { + if (VDBG) { + logd("requestDomainSelection: domain=" + + DomainSelectionService.getDomainName(domain)); + } + sendAllPendingRequests(holder, domain); + finishDomainSelection(holder); + }, this::post); + } + } + + /** + * Sends a SMS after selecting the domain via the domain selection service. + * + * @param holder The {@link DomainSelectionConnectionHolder} that contains the + * {@link DomainSelectionConnection} and its related information. + * @param request The {@link PendingRequest} that stores the SMS request + * (data, text, multipart text) to be sent. + * @param logTag The log tag to display which method called this method. + */ + private void sendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder, + @NonNull PendingRequest request, @NonNull String logTag) { + boolean isDomainSelectionRequested = holder.isDomainSelectionRequested(); + // The domain selection is in progress so waits for the result of + // the domain selection by adding this request to the pending list. + holder.addRequest(request); + + if (!isDomainSelectionRequested) { + if (VDBG) { + logd("requestDomainSelection: " + logTag); + } + requestDomainSelection(holder); + } + } + + /** + * Finishes the domain selection for MO SMS. + * + * @param holder The {@link DomainSelectionConnectionHolder} object that is being finished. + */ + private void finishDomainSelection(DomainSelectionConnectionHolder holder) { + DomainSelectionConnection connection = (holder != null) ? holder.getConnection() : null; + + if (connection != null) { + // After this method is called, the domain selection service will clean up + // its resources and finish the procedure that are related to the current domain + // selection request. + connection.finishSelection(); + } + + if (holder != null) { + final List pendingRequests = holder.getPendingRequests(); + + logd("finishDomainSelection: pendingRequests=" + pendingRequests.size()); + + for (PendingRequest r : pendingRequests) { + triggerSentIntentForFailure(r.sentIntents); + } + + holder.clearAllRequests(); + holder.setConnection(null); + } + } + + /** + * Notifies the application that MO SMS is not sent by the error of domain selection. + * + * @param holder The {@link DomainSelectionConnectionHolder} object that is being terminated. + */ + private void notifyDomainSelectionTerminated(@NonNull DomainSelectionConnectionHolder holder) { + final List pendingRequests = holder.getPendingRequests(); + + logd("notifyDomainSelectionTerminated: pendingRequests=" + pendingRequests.size()); + + for (PendingRequest r : pendingRequests) { + triggerSentIntentForFailure(r.sentIntents); + } + + holder.setConnection(null); + holder.clearAllRequests(); + } + + /** + * Sends all pending requests for MO SMS. + * + * @param holder The {@link DomainSelectionConnectionHolder} object that all the pending + * requests are handled. + * @param domain The domain where the SMS is being sent, which can be one of the following: + * - {@link NetworkRegistrationInfo#DOMAIN_PS} + * - {@link NetworkRegistrationInfo#DOMAIN_CS} + */ + private void sendAllPendingRequests(@NonNull DomainSelectionConnectionHolder holder, + @NetworkRegistrationInfo.Domain int domain) { + final List pendingRequests = holder.getPendingRequests(); + + if (VDBG) { + logd("sendAllPendingRequests: domain=" + DomainSelectionService.getDomainName(domain) + + ", size=" + pendingRequests.size()); + } + + for (PendingRequest r : pendingRequests) { + switch (r.type) { + case PendingRequest.TYPE_DATA: + sendData(domain, r); + break; + case PendingRequest.TYPE_TEXT: + sendText(domain, r); + break; + case PendingRequest.TYPE_MULTIPART_TEXT: + sendMultipartText(domain, r); + break; + case PendingRequest.TYPE_RETRY_SMS: + sendRetrySms(r.tracker, (domain == NetworkRegistrationInfo.DOMAIN_PS)); + break; + default: + // Not reachable. + break; + } + } + + holder.clearAllRequests(); + } + + /** + * Sends a data based SMS to a specific application port. + * + * @param domain The domain where the SMS is being sent, which can be one of the following: + * - {@link NetworkRegistrationInfo#DOMAIN_PS} + * - {@link NetworkRegistrationInfo#DOMAIN_CS} + * @param request The pending request for MO SMS. + */ + private void sendData(@NetworkRegistrationInfo.Domain int domain, + @NonNull PendingRequest request) { + if (domain == NetworkRegistrationInfo.DOMAIN_PS) { + mImsSmsDispatcher.sendData(request.callingPackage, request.destAddr, request.scAddr, + request.destPort, request.data, request.sentIntents.get(0), + request.deliveryIntents.get(0), request.isForVvm); + } else if (isCdmaMo(domain)) { + mCdmaDispatcher.sendData(request.callingPackage, request.destAddr, request.scAddr, + request.destPort, request.data, request.sentIntents.get(0), + request.deliveryIntents.get(0), request.isForVvm); + } else { + mGsmDispatcher.sendData(request.callingPackage, request.destAddr, request.scAddr, + request.destPort, request.data, request.sentIntents.get(0), + request.deliveryIntents.get(0), request.isForVvm); + } + } + + /** + * Sends a text based SMS. + * + * @param domain The domain where the SMS is being sent, which can be one of the following: + * - {@link NetworkRegistrationInfo#DOMAIN_PS} + * - {@link NetworkRegistrationInfo#DOMAIN_CS} + * @param request The pending request for MO SMS. + */ + private void sendText(@NetworkRegistrationInfo.Domain int domain, + @NonNull PendingRequest request) { + if (domain == NetworkRegistrationInfo.DOMAIN_PS) { + mImsSmsDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), + request.sentIntents.get(0), request.deliveryIntents.get(0), + request.messageUri, request.callingPackage, request.persistMessage, + request.priority, false /*request.expectMore*/, request.validityPeriod, + request.isForVvm, request.messageId, request.skipShortCodeCheck); + } else { + if (isCdmaMo(domain)) { + mCdmaDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), + request.sentIntents.get(0), request.deliveryIntents.get(0), + request.messageUri, request.callingPackage, request.persistMessage, + request.priority, request.expectMore, request.validityPeriod, + request.isForVvm, request.messageId, request.skipShortCodeCheck); + } else { + mGsmDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), + request.sentIntents.get(0), request.deliveryIntents.get(0), + request.messageUri, request.callingPackage, request.persistMessage, + request.priority, request.expectMore, request.validityPeriod, + request.isForVvm, request.messageId, request.skipShortCodeCheck); + } + } + } + + /** + * Sends a multi-part text based SMS. + * + * @param domain The domain where the SMS is being sent, which can be one of the following: + * - {@link NetworkRegistrationInfo#DOMAIN_PS} + * - {@link NetworkRegistrationInfo#DOMAIN_CS} + * @param request The pending request for MO SMS. + */ + private void sendMultipartText(@NetworkRegistrationInfo.Domain int domain, + @NonNull PendingRequest request) { + if (domain == NetworkRegistrationInfo.DOMAIN_PS) { + mImsSmsDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, + request.sentIntents, request.deliveryIntents, request.messageUri, + request.callingPackage, request.persistMessage, request.priority, + false /*request.expectMore*/, request.validityPeriod, request.messageId); + } else { + if (isCdmaMo(domain)) { + mCdmaDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, + request.sentIntents, request.deliveryIntents, request.messageUri, + request.callingPackage, request.persistMessage, request.priority, + request.expectMore, request.validityPeriod, request.messageId); + } else { + mGsmDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, + request.sentIntents, request.deliveryIntents, request.messageUri, + request.callingPackage, request.persistMessage, request.priority, + request.expectMore, request.validityPeriod, request.messageId); + } + } + } + + private void triggerSentIntentForFailure(@NonNull PendingIntent sentIntent) { + try { + sentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE); + } catch (CanceledException e) { + logd("Intent has been canceled!"); + } + } + + private void triggerSentIntentForFailure(@NonNull List sentIntents) { + for (PendingIntent sentIntent : sentIntents) { + triggerSentIntentForFailure(sentIntent); + } + } + + /** + * Creates an ArrayList object from any object. + */ + private static ArrayList asArrayList(T object) { + ArrayList list = new ArrayList<>(); + list.add(object); + return list; + } + /** * Send a data based SMS to a specific application port. * @@ -725,6 +1297,23 @@ public class SmsDispatchersController extends Handler { if (scAddr == null) { scAddr = getSmscAddressFromUSIM(callingPackage); } + + if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { + DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false); + + // If the DomainSelectionConnection is not available, + // fallback to the legacy implementation. + if (holder != null && holder.getConnection() != null) { + sendSmsUsingDomainSelection(holder, + new PendingRequest(PendingRequest.TYPE_DATA, null, callingPackage, + destAddr, scAddr, asArrayList(sentIntent), + asArrayList(deliveryIntent), isForVvm, data, destPort, null, null, + false, 0, false, 0, 0L, false), + "sendData"); + return; + } + } + if (mImsSmsDispatcher.isAvailable()) { mImsSmsDispatcher.sendData(callingPackage, destAddr, scAddr, destPort, data, sentIntent, deliveryIntent, isForVvm); @@ -947,6 +1536,26 @@ public class SmsDispatchersController extends Handler { if (scAddr == null) { scAddr = getSmscAddressFromUSIM(callingPkg); } + + if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { + TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + boolean isEmergency = tm.isEmergencyNumber(destAddr); + DomainSelectionConnectionHolder holder = getDomainSelectionConnection(isEmergency); + + // If the DomainSelectionConnection is not available, + // fallback to the legacy implementation. + if (holder != null && holder.getConnection() != null) { + sendSmsUsingDomainSelection(holder, + new PendingRequest(PendingRequest.TYPE_TEXT, null, callingPkg, + destAddr, scAddr, asArrayList(sentIntent), + asArrayList(deliveryIntent), isForVvm, null, 0, asArrayList(text), + messageUri, persistMessage, priority, expectMore, validityPeriod, + messageId, skipShortCodeCheck), + "sendText"); + return; + } + } + if (mImsSmsDispatcher.isAvailable() || mImsSmsDispatcher.isEmergencySmsSupport(destAddr)) { mImsSmsDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage, priority, false /*expectMore*/, @@ -1076,6 +1685,23 @@ public class SmsDispatchersController extends Handler { if (scAddr == null) { scAddr = getSmscAddressFromUSIM(callingPkg); } + + if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { + DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false); + + // If the DomainSelectionConnection is not available, + // fallback to the legacy implementation. + if (holder != null && holder.getConnection() != null) { + sendSmsUsingDomainSelection(holder, + new PendingRequest(PendingRequest.TYPE_MULTIPART_TEXT, null, + callingPkg, destAddr, scAddr, sentIntents, deliveryIntents, false, + null, 0, parts, messageUri, persistMessage, priority, expectMore, + validityPeriod, messageId, false), + "sendMultipartText"); + return; + } + } + if (mImsSmsDispatcher.isAvailable()) { mImsSmsDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri, callingPkg, persistMessage, priority, @@ -1232,4 +1858,8 @@ public class SmsDispatchersController extends Handler { private void logd(String msg) { Rlog.d(TAG, msg); } + + private void logi(String s) { + Rlog.i(TAG + " [" + mPhone.getPhoneId() + "]", s); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java index 008ad8fb4c..a10751a1a7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java @@ -19,6 +19,7 @@ package com.android.internal.telephony; import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -29,14 +30,25 @@ import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.PendingIntent; +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.Message; import android.provider.Telephony.Sms.Intents; +import android.telephony.DisconnectCause; +import android.telephony.DomainSelectionService; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneNumberUtils; import android.telephony.SmsManager; import android.test.FlakyTest; @@ -46,6 +58,9 @@ import android.testing.TestableLooper; import android.util.Singleton; import com.android.ims.ImsManager; +import com.android.internal.telephony.domainselection.DomainSelectionConnection; +import com.android.internal.telephony.domainselection.EmergencySmsDomainSelectionConnection; +import com.android.internal.telephony.domainselection.SmsDomainSelectionConnection; import com.android.internal.telephony.uicc.IccUtils; import org.junit.After; @@ -55,16 +70,140 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class SmsDispatchersControllerTest extends TelephonyTest { + /** + * Inherits the SmsDispatchersController to verify the protected methods. + */ + private class TestSmsDispatchersController extends SmsDispatchersController { + TestSmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, + SmsUsageMonitor usageMonitor) { + super(phone, storageMonitor, usageMonitor); + } + + public DomainSelectionConnectionHolder testGetDomainSelectionConnectionHolder( + boolean emergency) { + return getDomainSelectionConnectionHolder(emergency); + } + + public void testSendData(String callingPackage, String destAddr, String scAddr, + int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, + boolean isForVvm) { + sendData(callingPackage, destAddr, scAddr, + destPort, data, sentIntent, deliveryIntent, isForVvm); + } + + public void testSendMultipartText(String destAddr, String scAddr, + ArrayList parts, ArrayList sentIntents, + ArrayList deliveryIntents, Uri messageUri, String callingPkg, + boolean persistMessage, int priority, boolean expectMore, int validityPeriod, + long messageId) { + sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents, messageUri, + callingPkg, persistMessage, priority, expectMore, validityPeriod, messageId); + } + } + + /** + * Inherits the SMSDispatcher to verify the abstract or protected methods. + */ + protected abstract class TestSmsDispatcher extends SMSDispatcher { + public TestSmsDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) { + super(phone, smsDispatchersController); + } + + @Override + public void sendData(String callingPackage, String destAddr, String scAddr, int destPort, + byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, + boolean isForVvm) { + super.sendData(callingPackage, destAddr, scAddr, destPort, + data, sentIntent, deliveryIntent, isForVvm); + } + + @Override + public void sendSms(SmsTracker tracker) { + } + + @Override + public String getFormat() { + return SmsConstants.FORMAT_3GPP; + } + } + + /** + * Inherits the SMSDispatcher to verify the protected methods. + */ + protected class TestImsSmsDispatcher extends ImsSmsDispatcher { + public TestImsSmsDispatcher(Phone phone, SmsDispatchersController smsDispatchersController, + FeatureConnectorFactory factory) { + super(phone, smsDispatchersController, factory); + } + + @Override + public void sendData(String callingPackage, String destAddr, String scAddr, int destPort, + byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, + boolean isForVvm) { + super.sendData(callingPackage, destAddr, scAddr, destPort, + data, sentIntent, deliveryIntent, isForVvm); + } + + @Override + public String getFormat() { + return SmsConstants.FORMAT_3GPP; + } + } + + /** + * Provides a Test class to verify the sent failure case. + */ + private class TestIntentReceiver extends BroadcastReceiver { + private final Context mContext; + private final CountDownLatch mLatch = new CountDownLatch(1); + private Intent mIntent; + + TestIntentReceiver(Context context) { + mContext = context; + mContext.registerReceiver(this, new IntentFilter(ACTION_TEST_SMS_SENT)); + } + + public void dispose() { + mContext.unregisterReceiver(this); + } + + @Override + public void onReceive(Context context, Intent intent) { + assertNull(mIntent); + mIntent = intent; + mLatch.countDown(); + } + + public Intent getIntent(long timeoutMillis) throws Exception { + mLatch.await(timeoutMillis, TimeUnit.MILLISECONDS); + return mIntent; + } + } + + private static final String ACTION_TEST_SMS_SENT = "TEST_SMS_SENT"; + // Mocked classes private SMSDispatcher.SmsTracker mTracker; + private PendingIntent mSentIntent; + private TestImsSmsDispatcher mImsSmsDispatcher; + private TestSmsDispatcher mGsmSmsDispatcher; + private TestSmsDispatcher mCdmaSmsDispatcher; + private SmsDomainSelectionConnection mSmsDsc; + private EmergencySmsDomainSelectionConnection mEmergencySmsDsc; - private SmsDispatchersController mSmsDispatchersController; + private TestSmsDispatchersController mSmsDispatchersController; private boolean mInjectionCallbackTriggered = false; + private CompletableFuture mDscFuture; + private TestIntentReceiver mIntentReceiver; @Before public void setUp() throws Exception { @@ -72,15 +211,26 @@ public class SmsDispatchersControllerTest extends TelephonyTest { mTracker = mock(SMSDispatcher.SmsTracker.class); setupMockPackagePermissionChecks(); - mSmsDispatchersController = new SmsDispatchersController(mPhone, mSmsStorageMonitor, + mSmsDispatchersController = new TestSmsDispatchersController(mPhone, mSmsStorageMonitor, mSmsUsageMonitor); + setUpDomainSelectionConnectionAsNotSupported(); processAllMessages(); } @After public void tearDown() throws Exception { + mImsSmsDispatcher = null; + mGsmSmsDispatcher = null; + mCdmaSmsDispatcher = null; + mSmsDsc = null; + mEmergencySmsDsc = null; + mDscFuture = null; mSmsDispatchersController.dispose(); mSmsDispatchersController = null; + if (mIntentReceiver != null) { + mIntentReceiver.dispose(); + mIntentReceiver = null; + } super.tearDown(); } @@ -228,6 +378,203 @@ public class SmsDispatchersControllerTest extends TelephonyTest { anyInt(), anyInt(), any(Message.class)); } + @Test + @SmallTest + public void testSendDataWhenDomainPs() throws Exception { + sendDataWithDomainSelection(NetworkRegistrationInfo.DOMAIN_PS, false); + } + + @Test + @SmallTest + public void testSendDataWhenDomainCsAndCdma() throws Exception { + when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_CDMA); + sendDataWithDomainSelection(NetworkRegistrationInfo.DOMAIN_PS, true); + } + + @Test + @SmallTest + public void testSendDataWhenDomainCsAndGsm() throws Exception { + when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM); + sendDataWithDomainSelection(NetworkRegistrationInfo.DOMAIN_PS, false); + } + + @Test + @SmallTest + public void testSendTextWhenDomainPs() throws Exception { + sendTextWithDomainSelection(NetworkRegistrationInfo.DOMAIN_PS, false); + } + + @Test + @SmallTest + public void testSendTextWhenDomainCsAndCdma() throws Exception { + when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_CDMA); + sendTextWithDomainSelection(NetworkRegistrationInfo.DOMAIN_PS, true); + } + + @Test + @SmallTest + public void testSendTextWhenDomainCsAndGsm() throws Exception { + when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM); + sendTextWithDomainSelection(NetworkRegistrationInfo.DOMAIN_PS, false); + } + + @Test + @SmallTest + public void testSendMultipartTextWhenDomainPs() throws Exception { + sendMultipartTextWithDomainSelection(NetworkRegistrationInfo.DOMAIN_PS, false); + } + + @Test + @SmallTest + public void testSendMultipartTextWhenDomainCsAndCdma() throws Exception { + when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_CDMA); + sendMultipartTextWithDomainSelection(NetworkRegistrationInfo.DOMAIN_PS, true); + } + + @Test + @SmallTest + public void testSendMultipartTextWhenDomainCsAndGsm() throws Exception { + when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM); + sendMultipartTextWithDomainSelection(NetworkRegistrationInfo.DOMAIN_PS, false); + } + + @Test + @SmallTest + public void testSendRetrySmsWhenDomainPs() throws Exception { + sendRetrySmsWithDomainSelection(NetworkRegistrationInfo.DOMAIN_PS, + PhoneConstants.PHONE_TYPE_GSM, SmsConstants.FORMAT_3GPP); + } + + @Test + @SmallTest + public void testSendRetrySmsWhenDomainCsAndCdma() throws Exception { + sendRetrySmsWithDomainSelection(NetworkRegistrationInfo.DOMAIN_CS, + PhoneConstants.PHONE_TYPE_CDMA, SmsConstants.FORMAT_3GPP2); + } + + @Test + @SmallTest + public void testSendRetrySmsWhenDomainCsAndGsm() throws Exception { + sendRetrySmsWithDomainSelection(NetworkRegistrationInfo.DOMAIN_CS, + PhoneConstants.PHONE_TYPE_GSM, SmsConstants.FORMAT_3GPP); + } + + @Test + @SmallTest + public void testSendRetrySmsWhenImsAlreadyUsedAndCdma() throws Exception { + sendRetrySmsWhenImsAlreadyUsed(PhoneConstants.PHONE_TYPE_CDMA, SmsConstants.FORMAT_3GPP2); + } + + @Test + @SmallTest + public void testSendRetrySmsWhenImsAlreadyUsedAndGsm() throws Exception { + sendRetrySmsWhenImsAlreadyUsed(PhoneConstants.PHONE_TYPE_GSM, SmsConstants.FORMAT_3GPP); + } + + @Test + @SmallTest + public void testSendEmergencyTextWhenDomainPs() throws Exception { + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + + mSmsDispatchersController.sendText("911", "2222", "text", mSentIntent, null, null, + "test-app", false, 0, false, 10, false, 1L, false); + + SmsDispatchersController.DomainSelectionConnectionHolder holder = + mSmsDispatchersController.testGetDomainSelectionConnectionHolder(true); + verify(mEmergencySmsDsc).requestDomainSelection(any(), any()); + assertNotNull(holder); + assertNotNull(holder.getConnection()); + assertTrue(holder.isEmergency()); + assertTrue(holder.isDomainSelectionRequested()); + assertEquals(1, holder.getPendingRequests().size()); + + mDscFuture.complete(NetworkRegistrationInfo.DOMAIN_PS); + processAllMessages(); + + verify(mEmergencySmsDsc).finishSelection(); + verify(mImsSmsDispatcher).sendText(eq("911"), eq("2222"), eq("text"), eq(mSentIntent), + any(), any(), eq("test-app"), eq(false), eq(0), eq(false), eq(10), eq(false), + eq(1L), eq(false)); + assertNull(holder.getConnection()); + assertFalse(holder.isDomainSelectionRequested()); + assertEquals(0, holder.getPendingRequests().size()); + } + + @Test + public void testNotifyDomainSelectionTerminated() throws Exception { + registerTestIntentReceiver(); + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + + mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null, + "test-app", false, 0, false, 10, false, 1L, false); + + SmsDispatchersController.DomainSelectionConnectionHolder holder = + mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); + ArgumentCaptor captor = + ArgumentCaptor.forClass( + DomainSelectionConnection.DomainSelectionConnectionCallback.class); + verify(mSmsDsc).requestDomainSelection(any(), captor.capture()); + assertNotNull(holder); + assertNotNull(holder.getConnection()); + assertTrue(holder.isDomainSelectionRequested()); + assertEquals(1, holder.getPendingRequests().size()); + + DomainSelectionConnection.DomainSelectionConnectionCallback callback = captor.getValue(); + assertNotNull(callback); + + mSmsDispatchersController.post(() -> { + callback.onSelectionTerminated(DisconnectCause.LOCAL); + }); + processAllMessages(); + + verify(mSmsDsc, never()).finishSelection(); + assertNull(holder.getConnection()); + assertFalse(holder.isDomainSelectionRequested()); + assertEquals(0, holder.getPendingRequests().size()); + + Intent intent = mIntentReceiver.getIntent(2000); + assertNotNull(intent); + assertEquals(SmsManager.RESULT_ERROR_GENERIC_FAILURE, mIntentReceiver.getResultCode()); + } + + @Test + @SmallTest + public void testSendTextContinuously() throws Exception { + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + + mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null, + "test-app", false, 0, false, 10, false, 1L, false); + + SmsDispatchersController.DomainSelectionConnectionHolder holder = + mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); + assertNotNull(holder); + assertNotNull(holder.getConnection()); + assertTrue(holder.isDomainSelectionRequested()); + assertEquals(1, holder.getPendingRequests().size()); + + mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null, + "test-app", false, 0, false, 10, false, 1L, false); + + verify(mSmsDsc).requestDomainSelection(any(), any()); + assertNotNull(holder.getConnection()); + assertTrue(holder.isDomainSelectionRequested()); + assertEquals(2, holder.getPendingRequests().size()); + + mDscFuture.complete(NetworkRegistrationInfo.DOMAIN_PS); + processAllMessages(); + + verify(mSmsDsc).finishSelection(); + verify(mImsSmsDispatcher, times(2)).sendText(eq("1111"), eq("2222"), eq("text"), + eq(mSentIntent), any(), any(), eq("test-app"), eq(false), eq(0), eq(false), eq(10), + eq(false), eq(1L), eq(false)); + assertNull(holder.getConnection()); + assertFalse(holder.isDomainSelectionRequested()); + assertEquals(0, holder.getPendingRequests().size()); + } + private void switchImsSmsFormat(int phoneType) { mSimulatedCommands.setImsRegistrationState(new int[]{1, phoneType}); mSimulatedCommands.notifyImsNetworkStateChanged(); @@ -241,4 +588,250 @@ public class SmsDispatchersControllerTest extends TelephonyTest { ImsManager imsManager = mock(ImsManager.class); assertTrue(mSmsDispatchersController.setImsManager(imsManager)); } + + private void registerTestIntentReceiver() throws Exception { + // unmock ActivityManager to be able to register receiver, create real PendingIntent and + // receive a test intent. + restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton); + restoreInstance(ActivityManager.class, "IActivityManagerSingleton", null); + mIntentReceiver = new TestIntentReceiver(TestApplication.getAppContext()); + } + + private void setUpDomainSelectionConnectionAsNotSupported() { + mSmsDispatchersController.setDomainSelectionResolverProxy( + new SmsDispatchersController.DomainSelectionResolverProxy() { + @Override + @Nullable + public DomainSelectionConnection getDomainSelectionConnection(Phone phone, + @DomainSelectionService.SelectorType int selectorType, + boolean isEmergency) { + return null; + } + + @Override + public boolean isDomainSelectionSupported() { + return false; + } + }); + } + + private void setUpDomainSelectionConnection() { + mEmergencySmsDsc = Mockito.mock(EmergencySmsDomainSelectionConnection.class); + mSmsDsc = Mockito.mock(SmsDomainSelectionConnection.class); + mSmsDispatchersController.setDomainSelectionResolverProxy( + new SmsDispatchersController.DomainSelectionResolverProxy() { + @Override + @Nullable + public DomainSelectionConnection getDomainSelectionConnection(Phone phone, + @DomainSelectionService.SelectorType int selectorType, + boolean isEmergency) { + return isEmergency ? mEmergencySmsDsc : mSmsDsc; + } + + @Override + public boolean isDomainSelectionSupported() { + return true; + } + }); + + mDscFuture = new CompletableFuture<>(); + when(mSmsDsc.requestDomainSelection( + any(DomainSelectionService.SelectionAttributes.class), + any(DomainSelectionConnection.DomainSelectionConnectionCallback.class))) + .thenReturn(mDscFuture); + when(mEmergencySmsDsc.requestDomainSelection( + any(DomainSelectionService.SelectionAttributes.class), + any(DomainSelectionConnection.DomainSelectionConnectionCallback.class))) + .thenReturn(mDscFuture); + } + + private void setUpSmsDispatchers() throws Exception { + mImsSmsDispatcher = Mockito.mock(TestImsSmsDispatcher.class); + mGsmSmsDispatcher = Mockito.mock(TestSmsDispatcher.class); + mCdmaSmsDispatcher = Mockito.mock(TestSmsDispatcher.class); + + replaceInstance(SmsDispatchersController.class, "mImsSmsDispatcher", + mSmsDispatchersController, mImsSmsDispatcher); + replaceInstance(SmsDispatchersController.class, "mGsmDispatcher", + mSmsDispatchersController, mGsmSmsDispatcher); + replaceInstance(SmsDispatchersController.class, "mCdmaDispatcher", + mSmsDispatchersController, mCdmaSmsDispatcher); + + when(mTelephonyManager.isEmergencyNumber(eq("911"))).thenReturn(true); + + mSentIntent = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0, + new Intent(ACTION_TEST_SMS_SENT), PendingIntent.FLAG_MUTABLE); + } + + private void sendDataWithDomainSelection(@NetworkRegistrationInfo.Domain int domain, + boolean isCdmaMo) throws Exception { + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + + byte[] data = new byte[] { 0x01 }; + mSmsDispatchersController.testSendData( + "test-app", "1111", "2222", 8080, data, mSentIntent, null, false); + + SmsDispatchersController.DomainSelectionConnectionHolder holder = + mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); + verify(mSmsDsc).requestDomainSelection(any(), any()); + assertNotNull(holder); + assertNotNull(holder.getConnection()); + assertTrue(holder.isDomainSelectionRequested()); + assertEquals(1, holder.getPendingRequests().size()); + + mDscFuture.complete(domain); + processAllMessages(); + + verify(mSmsDsc).finishSelection(); + if (domain == NetworkRegistrationInfo.DOMAIN_PS) { + verify(mImsSmsDispatcher).sendData(eq("test-app"), eq("1111"), eq("2222"), eq(8080), + eq(data), eq(mSentIntent), any(), eq(false)); + } else if (isCdmaMo) { + verify(mCdmaSmsDispatcher).sendData(eq("test-app"), eq("1111"), eq("2222"), eq(8080), + eq(data), eq(mSentIntent), any(), eq(false)); + } else { + verify(mGsmSmsDispatcher).sendData(eq("test-app"), eq("1111"), eq("2222"), eq(8080), + eq(data), eq(mSentIntent), any(), eq(false)); + } + assertNull(holder.getConnection()); + assertFalse(holder.isDomainSelectionRequested()); + assertEquals(0, holder.getPendingRequests().size()); + } + + private void sendTextWithDomainSelection(@NetworkRegistrationInfo.Domain int domain, + boolean isCdmaMo) throws Exception { + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + + mSmsDispatchersController.sendText("1111", "2222", "text", mSentIntent, null, null, + "test-app", false, 0, false, 10, false, 1L, false); + + SmsDispatchersController.DomainSelectionConnectionHolder holder = + mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); + verify(mSmsDsc).requestDomainSelection(any(), any()); + assertNotNull(holder); + assertNotNull(holder.getConnection()); + assertTrue(holder.isDomainSelectionRequested()); + assertEquals(1, holder.getPendingRequests().size()); + + mDscFuture.complete(domain); + processAllMessages(); + + verify(mSmsDsc).finishSelection(); + if (domain == NetworkRegistrationInfo.DOMAIN_PS) { + verify(mImsSmsDispatcher).sendText(eq("1111"), eq("2222"), eq("text"), eq(mSentIntent), + any(), any(), eq("test-app"), eq(false), eq(0), eq(false), eq(10), eq(false), + eq(1L), eq(false)); + } else if (isCdmaMo) { + verify(mCdmaSmsDispatcher).sendText(eq("1111"), eq("2222"), eq("text"), eq(mSentIntent), + any(), any(), eq("test-app"), eq(false), eq(0), eq(false), eq(10), eq(false), + eq(1L), eq(false)); + } else { + verify(mGsmSmsDispatcher).sendText(eq("1111"), eq("2222"), eq("text"), eq(mSentIntent), + any(), any(), eq("test-app"), eq(false), eq(0), eq(false), eq(10), eq(false), + eq(1L), eq(false)); + } + assertNull(holder.getConnection()); + assertFalse(holder.isDomainSelectionRequested()); + assertEquals(0, holder.getPendingRequests().size()); + } + + private void sendMultipartTextWithDomainSelection(@NetworkRegistrationInfo.Domain int domain, + boolean isCdmaMo) throws Exception { + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + + ArrayList parts = new ArrayList<>(); + ArrayList sentIntents = new ArrayList<>(); + ArrayList deliveryIntents = new ArrayList<>(); + mSmsDispatchersController.testSendMultipartText("1111", "2222", parts, sentIntents, + deliveryIntents, null, "test-app", false, 0, false, 10, 1L); + + SmsDispatchersController.DomainSelectionConnectionHolder holder = + mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); + verify(mSmsDsc).requestDomainSelection(any(), any()); + assertNotNull(holder); + assertNotNull(holder.getConnection()); + assertTrue(holder.isDomainSelectionRequested()); + assertEquals(1, holder.getPendingRequests().size()); + + mDscFuture.complete(domain); + processAllMessages(); + + verify(mSmsDsc).finishSelection(); + if (domain == NetworkRegistrationInfo.DOMAIN_PS) { + verify(mImsSmsDispatcher).sendMultipartText(eq("1111"), eq("2222"), eq(parts), + eq(sentIntents), eq(deliveryIntents), any(), eq("test-app"), eq(false), eq(0), + eq(false), eq(10), eq(1L)); + } else if (isCdmaMo) { + verify(mCdmaSmsDispatcher).sendMultipartText(eq("1111"), eq("2222"), eq(parts), + eq(sentIntents), eq(deliveryIntents), any(), eq("test-app"), eq(false), eq(0), + eq(false), eq(10), eq(1L)); + } else { + verify(mGsmSmsDispatcher).sendMultipartText(eq("1111"), eq("2222"), eq(parts), + eq(sentIntents), eq(deliveryIntents), any(), eq("test-app"), eq(false), eq(0), + eq(false), eq(10), eq(1L)); + } + assertNull(holder.getConnection()); + assertFalse(holder.isDomainSelectionRequested()); + assertEquals(0, holder.getPendingRequests().size()); + } + + private void sendRetrySmsWithDomainSelection(@NetworkRegistrationInfo.Domain int domain, + int phoneType, String smsFormat) throws Exception { + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + when(mPhone.getPhoneType()).thenReturn(phoneType); + when(mImsSmsDispatcher.getFormat()).thenReturn(SmsConstants.FORMAT_3GPP); + when(mCdmaSmsDispatcher.getFormat()).thenReturn(SmsConstants.FORMAT_3GPP2); + when(mGsmSmsDispatcher.getFormat()).thenReturn(SmsConstants.FORMAT_3GPP); + replaceInstance(SMSDispatcher.SmsTracker.class, "mFormat", mTracker, smsFormat); + + mSmsDispatchersController.sendRetrySms(mTracker); + + SmsDispatchersController.DomainSelectionConnectionHolder holder = + mSmsDispatchersController.testGetDomainSelectionConnectionHolder(false); + verify(mSmsDsc).requestDomainSelection(any(), any()); + assertNotNull(holder); + assertNotNull(holder.getConnection()); + assertTrue(holder.isDomainSelectionRequested()); + assertEquals(1, holder.getPendingRequests().size()); + + mDscFuture.complete(domain); + processAllMessages(); + + verify(mSmsDsc).finishSelection(); + if (domain == NetworkRegistrationInfo.DOMAIN_PS) { + verify(mImsSmsDispatcher).sendSms(eq(mTracker)); + } else if (SmsConstants.FORMAT_3GPP2.equals(smsFormat)) { + verify(mCdmaSmsDispatcher).sendSms(eq(mTracker)); + } else { + verify(mGsmSmsDispatcher).sendSms(eq(mTracker)); + } + assertNull(holder.getConnection()); + assertFalse(holder.isDomainSelectionRequested()); + assertEquals(0, holder.getPendingRequests().size()); + } + + private void sendRetrySmsWhenImsAlreadyUsed(int phoneType, String smsFormat) throws Exception { + setUpDomainSelectionConnection(); + setUpSmsDispatchers(); + when(mPhone.getPhoneType()).thenReturn(phoneType); + when(mImsSmsDispatcher.getFormat()).thenReturn(SmsConstants.FORMAT_3GPP); + when(mCdmaSmsDispatcher.getFormat()).thenReturn(SmsConstants.FORMAT_3GPP2); + when(mGsmSmsDispatcher.getFormat()).thenReturn(SmsConstants.FORMAT_3GPP); + replaceInstance(SMSDispatcher.SmsTracker.class, "mFormat", mTracker, smsFormat); + mTracker.mUsesImsServiceForIms = true; + + mSmsDispatchersController.sendRetrySms(mTracker); + + verify(mSmsDsc, never()).requestDomainSelection(any(), any()); + + if (SmsConstants.FORMAT_3GPP2.equals(smsFormat)) { + verify(mCdmaSmsDispatcher).sendSms(eq(mTracker)); + } else { + verify(mGsmSmsDispatcher).sendSms(eq(mTracker)); + } + } } -- GitLab From 5b20f5c6521c9c1c62d5b33f632047b501858e3d Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 12 Dec 2022 21:44:46 -0800 Subject: [PATCH 266/656] Added remove subscription support Bug: 239607619 Test: atest SubscriptionManagerServiceTest atest SubscriptionDatabaseManagerTest Change-Id: Ia19ea13132420278b50ddb6c0faba29d9ddacbf2 --- .../telephony/SubscriptionController.java | 1 - .../SubscriptionDatabaseManager.java | 28 +++ .../SubscriptionManagerService.java | 182 +++++++++++++++--- .../SubscriptionDatabaseManagerTest.java | 81 +++++++- .../SubscriptionManagerServiceTest.java | 19 ++ 5 files changed, 282 insertions(+), 29 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index cb89d202c2..2535b3244a 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -2717,7 +2717,6 @@ public class SubscriptionController extends ISub.Stub { /** * @return the number of records cleared */ - @Override public int clearSubInfo() { enforceModifyPhoneState("clearSubInfo"); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index dd1c083353..501d4f0cc5 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -769,6 +769,34 @@ public class SubscriptionDatabaseManager extends Handler { return subId; } + /** + * Remove a subscription record from the database. + * + * @param subId The subscription id of the subscription to be deleted. + * + * @throws IllegalArgumentException If {@code subId} is invalid. + */ + public void removeSubscriptionInfo(int subId) { + if (!mAllSubscriptionInfoInternalCache.containsKey(subId)) { + throw new IllegalArgumentException("subId " + subId + " is invalid."); + } + + mReadWriteLock.writeLock().lock(); + try { + if (mContext.getContentResolver().delete(SimInfo.CONTENT_URI, + SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + "=?", + new String[]{Integer.toString(subId)}) > 0) { + mAllSubscriptionInfoInternalCache.remove(subId); + } else { + logel("Failed to remove subscription with subId=" + subId); + } + } finally { + mReadWriteLock.writeLock().unlock(); + } + + mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); + } + /** * Update a subscription in the database (synchronously or asynchronously). * diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index be933e6a64..ea5c020ada 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -101,6 +101,7 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * The subscription manager service is the backend service of {@link SubscriptionManager}. @@ -830,8 +831,11 @@ public class SubscriptionManagerService extends ISub.Stub { public void markSubscriptionsInactive(int simSlotIndex) { mSubscriptionDatabaseManager.getAllSubscriptions().stream() .filter(subInfo -> subInfo.getSimSlotIndex() == simSlotIndex) - .forEach(subInfo -> mSubscriptionDatabaseManager.setSimSlotIndex( - subInfo.getSubscriptionId(), SubscriptionManager.INVALID_SIM_SLOT_INDEX)); + .forEach(subInfo -> { + mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), + SubscriptionManager.INVALID_SIM_SLOT_INDEX); + mSlotIndexToSubId.remove(simSlotIndex); + }); } /** @@ -1364,8 +1368,9 @@ public class SubscriptionManagerService extends ISub.Stub { * @see SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh */ @Override + // TODO: Remove this after SubscriptionController is removed. public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) { - + updateEmbeddedSubscriptions(List.of(cardId), null); } /** @@ -1430,17 +1435,40 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Remove subscription info record for the given device. + * Remove subscription info record from the subscription database. * * @param uniqueId This is the unique identifier for the subscription within the specific * subscription type. - * @param subscriptionType the type of subscription to be removed + * @param subscriptionType the type of subscription to be removed. * - * @return 0 if success, < 0 on error + * // TODO: Remove this terrible return value once SubscriptionController is removed. + * @return 0 if success, < 0 on error. + * + * @throws NullPointerException if {@code uniqueId} is {@code null}. + * @throws SecurityException if callers do not hold the required permission. */ @Override + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public int removeSubInfo(@NonNull String uniqueId, int subscriptionType) { - return 0; + enforcePermissions("removeSubInfo", Manifest.permission.MODIFY_PHONE_STATE); + + final long identity = Binder.clearCallingIdentity(); + try { + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternalByIccId(uniqueId); + if (subInfo == null) { + loge("Cannot find subscription with uniqueId " + uniqueId); + return -1; + } + if (subInfo.getSubscriptionType() != subscriptionType) { + loge("The subscription type does not match."); + return -1; + } + mSubscriptionDatabaseManager.removeSubscriptionInfo(subInfo.getSubscriptionId()); + return 0; + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1631,6 +1659,10 @@ public class SubscriptionManagerService extends ISub.Stub { * @throws SecurityException if callers do not hold the required permission. */ @Override + @RequiresPermission(anyOf = { + Manifest.permission.MODIFY_PHONE_STATE, + "carrier privileges", + }) public int setOpportunistic(boolean opportunistic, int subId, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); @@ -1835,11 +1867,76 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Remove a list of subscriptions from their subscription group. + * + * @param subIdList list of subId that need removing from their groups. + * @param groupUuid The UUID of the subscription group. + * @param callingPackage The package making the call. + * + * @throws SecurityException if the caller doesn't meet the requirements outlined above. + * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong the + * specified group. + * + * @see SubscriptionManager#createSubscriptionGroup(List) + */ @Override - public void removeSubscriptionsFromGroup(int[] subIdList, @NonNull ParcelUuid groupUuid, - @NonNull String callingPackage) { + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void removeSubscriptionsFromGroup(@NonNull int[] subIdList, + @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); + + // If it doesn't have modify phone state permission, or carrier privilege permission, + // a SecurityException will be thrown. If it's due to invalid parameter or internal state, + // it will return null. + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + != PackageManager.PERMISSION_GRANTED + && !(checkCarrierPrivilegeOnSubList(subIdList, callingPackage) + && canPackageManageGroup(groupUuid, callingPackage))) { + throw new SecurityException("removeSubscriptionsFromGroup needs MODIFY_PHONE_STATE or" + + " carrier privilege permission on all specified subscriptions."); + } + + Objects.requireNonNull(subIdList); + Objects.requireNonNull(groupUuid); + + if (subIdList.length == 0) { + throw new IllegalArgumentException("subIdList is empty."); + } + + long identity = Binder.clearCallingIdentity(); + + try { + for (int subId : subIdList) { + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + if (subInfo == null) { + throw new IllegalArgumentException("The provided sub id " + subId + + " is not valid."); + } + if (!groupUuid.toString().equals(subInfo.getGroupUuid())) { + throw new IllegalArgumentException("Subscription " + subInfo.getSubscriptionId() + + " doesn't belong to group " + groupUuid); + } + } + + for (SubscriptionInfoInternal subInfo : + mSubscriptionDatabaseManager.getAllSubscriptions()) { + if (IntStream.of(subIdList).anyMatch( + subId -> subId == subInfo.getSubscriptionId())) { + mSubscriptionDatabaseManager.setGroupUuid(subInfo.getSubscriptionId(), ""); + mSubscriptionDatabaseManager.setGroupOwner(subInfo.getSubscriptionId(), ""); + } else if (subInfo.getGroupUuid().equals(groupUuid.toString())) { + // Pre-T behavior. If there are still subscriptions having the same UUID, update + // to the new owner. + mSubscriptionDatabaseManager.setGroupOwner( + subInfo.getSubscriptionId(), callingPackage); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1850,17 +1947,18 @@ public class SubscriptionManagerService extends ISub.Stub { * * @param subIdList list of subId that need adding into the group * @param groupUuid the groupUuid the subscriptions are being added to. + * @param callingPackage The package making the call. * * @throws SecurityException if the caller doesn't meet the requirements outlined above. * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist. * * @see SubscriptionManager#createSubscriptionGroup(List) */ + @Override @RequiresPermission(anyOf = { Manifest.permission.MODIFY_PHONE_STATE, "carrier privileges", }) - @Override public void addSubscriptionsIntoGroup(@NonNull int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { // Verify that the callingPackage belongs to the calling UID @@ -1975,7 +2073,7 @@ public class SubscriptionManagerService extends ISub.Stub { * * @param subId The subscription id. * - * @return Logical slot indexx (i.e. phone id) as a positive integer or + * @return Logical slot index (i.e. phone id) as a positive integer or * {@link SubscriptionManager#INVALID_SIM_SLOT_INDEX} if the supplied {@code subId} doesn't have * an associated slot index. */ @@ -2058,16 +2156,22 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * @return The default subscription id. + */ @Override public int getDefaultSubId() { return mDefaultSubId.get(); } - @Override - public int clearSubInfo() { - return 0; - } - + /** + * Get phone id from the subscription id. In the implementation, the logical SIM slot index + * is equivalent to phone id. So this method is same as {@link #getSlotIndex(int)}. + * + * @param subId The subscription id. + * + * @return The phone id. + */ @Override public int getPhoneId(int subId) { // slot index and phone id are equivalent in the current implementation. @@ -2123,6 +2227,9 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * @return The default subscription id for voice. + */ @Override public int getDefaultVoiceSubId() { return mDefaultVoiceSubId.get(); @@ -2173,6 +2280,9 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * @return The default subscription id for SMS. + */ @Override public int getDefaultSmsSubId() { return mDefaultSmsSubId.get(); @@ -2351,6 +2461,9 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public boolean setSubscriptionEnabled(boolean enable, int subId) { + enforcePermissions("setSubscriptionEnabled", Manifest.permission.MODIFY_PHONE_STATE); + + return true; } @@ -2362,7 +2475,7 @@ public class SubscriptionManagerService extends ISub.Stub { * @return {@code true} if the subscription is active. * * @throws IllegalArgumentException if the provided slot index is invalid. - * @throws SecurityException if callers do not hold the required permission. * + * @throws SecurityException if callers do not hold the required permission. */ @Override @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @@ -2621,7 +2734,7 @@ public class SubscriptionManagerService extends ISub.Stub { * *

Note the assumption is that one subscription (which usually means one SIM) has * only one phone number. The multiple sources backup each other so hopefully at least one - * is availavle. For example, for a carrier that doesn't typically set phone numbers + * is available. For example, for a carrier that doesn't typically set phone numbers * on {@link SubscriptionManager#PHONE_NUMBER_SOURCE_UICC UICC}, the source * {@link SubscriptionManager#PHONE_NUMBER_SOURCE_IMS IMS} may provide one. Or, a carrier may * decide to provide the phone number via source @@ -3010,15 +3123,38 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println(SubscriptionManagerService.class.getSimpleName() + ":"); + pw.println("Logical SIM slot sub id mapping:"); + pw.increaseIndent(); + mSlotIndexToSubId.forEach((slotIndex, subId) + -> pw.println("Logical slot " + slotIndex + ": subId=" + subId)); + pw.increaseIndent(); + + pw.println("defaultSubId=" + getDefaultSubId()); + pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId()); + pw.println("defaultDataSubId=" + getDefaultDataSubId()); + pw.println("activeDataSubId=" + getActiveDataSubscriptionId()); + pw.println("defaultSmsSubId=" + getDefaultSmsSubId()); + + pw.println("Active subscriptions:"); + pw.increaseIndent(); + mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isActive).forEach(pw::println); + pw.decreaseIndent(); + pw.println("Embedded subscriptions:"); + pw.increaseIndent(); + mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isEmbedded).forEach(pw::println); + pw.decreaseIndent(); + pw.println("Opportunistic subscriptions:"); + pw.increaseIndent(); + mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isOpportunistic).forEach(pw::println); + pw.decreaseIndent(); pw.println("All subscriptions:"); pw.increaseIndent(); mSubscriptionDatabaseManager.getAllSubscriptions().forEach(pw::println); pw.decreaseIndent(); - pw.println("defaultSubId=" + getDefaultSubId()); - pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId()); - pw.println("defaultDataSubId" + getDefaultDataSubId()); - pw.println("activeDataSubId" + getActiveDataSubscriptionId()); - pw.println("defaultSmsSubId" + getDefaultSmsSubId()); + if (mEuiccManager != null) { pw.println("Euicc enabled=" + mEuiccManager.isEnabled()); } 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 2810b1250f..3f3a2c650f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -273,10 +273,17 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { } int subId = Integer.parseInt(uri.getLastPathSegment()); - assertThat(mDatabase.size()).isAtLeast(subId); - - ContentValues existingValues = mDatabase.get(subId - 1); logd("update: subId=" + subId + ", contentValues=" + values); + + ContentValues existingValues = mDatabase.stream() + .filter(contentValues -> contentValues.get( + SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID).equals(subId)) + .findFirst() + .orElse(null); + if (existingValues == null) { + throw new IllegalArgumentException("Invalid sub id " + subId); + } + for (Map.Entry entry : values.valueSet()) { String column = entry.getKey(); Object value = entry.getValue(); @@ -290,7 +297,24 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { @Override public int delete(Uri uri, String selection, String[] selectionArgs) { - throw new UnsupportedOperationException("delete is not supported uri=" + uri); + if (!uri.isPathPrefixMatch(SimInfo.CONTENT_URI)) { + throw new UnsupportedOperationException("Unsupported uri=" + uri); + } + + logd("delete: uri=" + uri + ", selection=" + selection + ", selectionArgs=" + + Arrays.toString(selectionArgs)); + if (!selection.equals(SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID + "=?")) { + throw new UnsupportedOperationException("Only support delete by sub id."); + } + + int rowsRemoved = 0; + for (String selectionArg : selectionArgs) { + int subId = Integer.parseInt(selectionArg); + // Clear it to null instead of removing it. + rowsRemoved += mDatabase.removeIf(contentValues -> contentValues.get( + SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID).equals(subId)) ? 1 : 0; + } + return rowsRemoved; } @Override @@ -305,7 +329,14 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { throw new IllegalArgumentException("Insert with unknown column " + column); } } - int subId = mDatabase.size() + 1; + // The last row's subId + 1 + int subId; + if (mDatabase.isEmpty()) { + subId = 1; + } else { + subId = (int) mDatabase.get(mDatabase.size() - 1) + .get(SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID) + 1; + } values.put(SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, subId); mDatabase.add(values); return ContentUris.withAppendedId(SimInfo.CONTENT_URI, subId); @@ -1566,4 +1597,44 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2) .getIccId()).isEqualTo(FAKE_ICCID2); } + + @Test + public void testRemoveSubscriptionInfo() throws Exception { + insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO2); + Mockito.clearInvocations(mSubscriptionDatabaseManagerCallback); + + mDatabaseManagerUT.removeSubscriptionInfo(1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1)).isNull(); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2)) + .isEqualTo(FAKE_SUBSCRIPTION_INFO2); + verify(mSubscriptionDatabaseManagerCallback).onSubscriptionChanged(eq(1)); + + // Insert a new one. Should become sub 3. + Mockito.clearInvocations(mSubscriptionDatabaseManagerCallback); + insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1)).isNull(); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2)) + .isEqualTo(FAKE_SUBSCRIPTION_INFO2); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(3)) + .isEqualTo(new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO1) + .setId(3).build()); + verify(mSubscriptionDatabaseManagerCallback).onSubscriptionChanged(eq(3)); + + Mockito.clearInvocations(mSubscriptionDatabaseManagerCallback); + mDatabaseManagerUT.removeSubscriptionInfo(2); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1)).isNull(); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2)).isNull(); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(3)) + .isEqualTo(new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO1) + .setId(3).build()); + verify(mSubscriptionDatabaseManagerCallback).onSubscriptionChanged(eq(2)); + + Mockito.clearInvocations(mSubscriptionDatabaseManagerCallback); + mDatabaseManagerUT.removeSubscriptionInfo(3); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1)).isNull(); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(2)).isNull(); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(3)).isNull(); + verify(mSubscriptionDatabaseManagerCallback).onSubscriptionChanged(eq(3)); + } } 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 6448f40fdb..0c85582d3d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -1633,4 +1633,23 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { .getUserId()).isEqualTo(mSubscriptionManagerServiceUT .getSubscriptionInfoInternal(1).getUserId()); } + + @Test + public void testRemoveSubInfo() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .removeSubInfo(FAKE_ICCID1, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.removeSubInfo(FAKE_ICCID1, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM)).isEqualTo(0); + assertThat(mSubscriptionManagerServiceUT.removeSubInfo(FAKE_ICCID2, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM)).isEqualTo(0); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList( + CALLING_PACKAGE, CALLING_FEATURE).isEmpty()).isTrue(); + } } -- GitLab From 7dd5027619f60138979302eb2736e255fae32819 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 14 Oct 2022 15:03:44 +0000 Subject: [PATCH 267/656] Notifies IMS call information to the modem Bug: 255450284 Test: atest ImsCallInfoNotifierTest Change-Id: I320d39421824c6dc69450a976129392149dd7284 --- .../internal/telephony/CommandsInterface.java | 9 + .../com/android/internal/telephony/Phone.java | 11 + .../com/android/internal/telephony/RIL.java | 33 ++ .../android/internal/telephony/RILUtils.java | 63 +++ .../telephony/imsphone/ImsCallInfo.java | 116 ++++++ .../imsphone/ImsCallInfoTracker.java | 145 +++++++ .../internal/telephony/imsphone/ImsPhone.java | 5 + .../imsphone/ImsPhoneCallTracker.java | 12 + .../imsphone/ImsCallInfoTrackerTest.java | 382 ++++++++++++++++++ .../imsphone/ImsPhoneCallTrackerTest.java | 52 +++ 10 files changed, 828 insertions(+) create mode 100644 src/java/com/android/internal/telephony/imsphone/ImsCallInfo.java create mode 100644 src/java/com/android/internal/telephony/imsphone/ImsCallInfoTracker.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallInfoTrackerTest.java diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 25e42168ff..a8e71b0d58 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -48,6 +48,7 @@ import android.telephony.ims.stub.ImsRegistrationImplBase; import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; import com.android.internal.telephony.emergency.EmergencyConstants; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; +import com.android.internal.telephony.imsphone.ImsCallInfo; import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState; import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.SimPhonebookRecord; @@ -2964,4 +2965,12 @@ public interface CommandsInterface { * @param result Callback message containing the success or failure status. */ default void setNullCipherAndIntegrityEnabled(boolean enabled, Message result) {} + + /** + * Notifies the IMS call status to the modem. + * + * @param imsCallInfo The list of {@link ImsCallInfo}. + * @param result A callback to receive the response. + */ + default void updateImsCallStatus(@NonNull List imsCallInfo, Message result) {} } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 772ac72d2c..e76eb72d0e 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -85,6 +85,7 @@ import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.emergency.EmergencyConstants; import com.android.internal.telephony.emergency.EmergencyNumberTracker; +import com.android.internal.telephony.imsphone.ImsCallInfo; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; import com.android.internal.telephony.metrics.SmsStats; @@ -5080,6 +5081,16 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public void handleNullCipherEnabledChange() { } + /** + * Notifies the IMS call status to the modem. + * + * @param imsCallInfo The list of {@link ImsCallInfo}. + * @param response A callback to receive the response. + */ + public void updateImsCallStatus(@NonNull List imsCallInfo, Message response) { + mCi.updateImsCallStatus(imsCallInfo, response); + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index b552760bce..61c61d3505 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -95,6 +95,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.gsm.SmsBroadcastConfigInfo; +import com.android.internal.telephony.imsphone.ImsCallInfo; import com.android.internal.telephony.metrics.ModemRestartStats; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.TelephonyProto.SmsSession; @@ -5594,6 +5595,38 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * {@inheritDoc} + */ + @Override + public void updateImsCallStatus(@NonNull List imsCallInfo, Message result) { + RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); + if (imsProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_UPDATE_IMS_CALL_STATUS, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " " + imsCallInfo); + } + try { + imsProxy.updateImsCallStatus(rr.mSerial, RILUtils.convertImsCallInfo(imsCallInfo)); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "updateImsCallStatus", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "updateImsCallStatus: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + //***** Private Methods /** * This is a helper function to be called when an indication callback is called for any radio diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index c362d65334..3d09e32a19 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -210,6 +210,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_WAI import static com.android.internal.telephony.RILConstants.RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_TRIGGER_EPS_FALLBACK; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UDUB; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UPDATE_IMS_CALL_STATUS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORD; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_VOICE_RADIO_TECH; @@ -361,6 +362,7 @@ import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress; import com.android.internal.telephony.cdma.sms.SmsEnvelope; import com.android.internal.telephony.data.KeepaliveStatus; import com.android.internal.telephony.data.KeepaliveStatus.KeepaliveStatusCode; +import com.android.internal.telephony.imsphone.ImsCallInfo; import com.android.internal.telephony.uicc.AdnCapacity; import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccCardStatus; @@ -5197,6 +5199,8 @@ public class RILUtils { return "TRIGGER_EPS_FALLBACK"; case RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED: return "SET_NULL_CIPHER_AND_INTEGRITY_ENABLED"; + case RIL_REQUEST_UPDATE_IMS_CALL_STATUS: + return "UPDATE_IMS_CALL_STATUS"; default: return ""; } @@ -5681,6 +5685,65 @@ public class RILUtils { return halCapabilities; } + /** Converts the ImsCallInfo instances to HAL ImsCall instances. */ + public static android.hardware.radio.ims.ImsCall[] convertImsCallInfo( + List imsCallInfos) { + if (imsCallInfos == null) { + return new android.hardware.radio.ims.ImsCall[0]; + } + + int length = 0; + for (int i = 0; i < imsCallInfos.size(); i++) { + if (imsCallInfos.get(i) != null) length++; + } + if (length == 0) { + return new android.hardware.radio.ims.ImsCall[0]; + } + + android.hardware.radio.ims.ImsCall[] halInfos = + new android.hardware.radio.ims.ImsCall[length]; + + int index = 0; + for (int i = 0; i < imsCallInfos.size(); i++) { + ImsCallInfo info = imsCallInfos.get(i); + if (info == null) continue; + + halInfos[index] = new android.hardware.radio.ims.ImsCall(); + halInfos[index].index = info.getIndex(); + halInfos[index].callState = convertToHalImsCallState(info.getCallState()); + halInfos[index].callType = info.isEmergencyCall() + ? android.hardware.radio.ims.ImsCall.CallType.EMERGENCY + : android.hardware.radio.ims.ImsCall.CallType.NORMAL; + halInfos[index].accessNetwork = convertToHalAccessNetworkAidl(info.getCallRadioTech()); + halInfos[index].direction = info.isIncoming() + ? android.hardware.radio.ims.ImsCall.Direction.INCOMING + : android.hardware.radio.ims.ImsCall.Direction.OUTGOING; + halInfos[index].isHeldByRemote = info.isHeldByRemote(); + index++; + } + + return halInfos; + } + + /** + * Converts the call state to HAL IMS call state. + * + * @param state The {@link Call.State}. + * @return The converted {@link android.hardware.radio.ims.ImsCall.CallState}. + */ + private static int convertToHalImsCallState(Call.State state) { + switch (state) { + case ACTIVE: return android.hardware.radio.ims.ImsCall.CallState.ACTIVE; + case HOLDING: return android.hardware.radio.ims.ImsCall.CallState.HOLDING; + case DIALING: return android.hardware.radio.ims.ImsCall.CallState.DIALING; + case ALERTING: return android.hardware.radio.ims.ImsCall.CallState.ALERTING; + case INCOMING: return android.hardware.radio.ims.ImsCall.CallState.INCOMING; + case WAITING: return android.hardware.radio.ims.ImsCall.CallState.WAITING; + case DISCONNECTING: return android.hardware.radio.ims.ImsCall.CallState.DISCONNECTING; + default: return android.hardware.radio.ims.ImsCall.CallState.DISCONNECTED; + } + } + private static void logd(String log) { Rlog.d("RILUtils", log); } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsCallInfo.java b/src/java/com/android/internal/telephony/imsphone/ImsCallInfo.java new file mode 100644 index 0000000000..718a98863b --- /dev/null +++ b/src/java/com/android/internal/telephony/imsphone/ImsCallInfo.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2022 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.imsphone; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.telephony.AccessNetworkConstants; +import android.telephony.ServiceState; + +import com.android.internal.telephony.Call; + +/** + * Contains call state to be notified to modem. + */ +public class ImsCallInfo { + + private final int mIndex; + private @Nullable ImsPhoneConnection mConnection = null; + private Call.State mState = Call.State.IDLE; + private boolean mIsHeldByRemote = false; + + public ImsCallInfo(int index) { + mIndex = index; + } + + /** Clears the call state. */ + public void reset() { + mConnection = null; + mState = Call.State.IDLE; + mIsHeldByRemote = false; + } + + /** + * Updates the state of the IMS call. + * + * @param c The instance of {@link ImsPhoneConnection}. + */ + public void update(@NonNull ImsPhoneConnection c) { + mConnection = c; + mState = c.getState(); + } + + /** + * Updates the state of the IMS call. + * + * @param c The instance of {@link ImsPhoneConnection}. + * @param holdReceived {@code true} if the remote party held the call. + * @param resumeReceived {@code true} if the remote party resumed the call. + */ + public boolean update(@NonNull ImsPhoneConnection c, + boolean holdReceived, boolean resumeReceived) { + Call.State state = c.getState(); + boolean changed = mState != state; + mState = state; + + if (holdReceived && !mIsHeldByRemote) { + changed = true; + mIsHeldByRemote = true; + } else if (resumeReceived && mIsHeldByRemote) { + changed = true; + mIsHeldByRemote = false; + } + + return changed; + } + + /** @return the call index. */ + public int getIndex() { + return mIndex; + } + + /** @return the call state. */ + public Call.State getCallState() { + return mState; + } + + /** @return whether the remote party is holding the call. */ + public boolean isHeldByRemote() { + return mIsHeldByRemote; + } + + /** @return {@code true} if the call is an incoming call. */ + public boolean isIncoming() { + return mConnection.isIncoming(); + } + + /** @return {@code true} if the call is an emergency call. */ + public boolean isEmergencyCall() { + return mConnection.isEmergencyCall(); + } + + /** @return the radio technology used for current connection. */ + public @AccessNetworkConstants.RadioAccessNetworkType int getCallRadioTech() { + return ServiceState.rilRadioTechnologyToAccessNetworkType(mConnection.getCallRadioTech()); + } + + @Override + public String toString() { + return "[ id=" + mIndex + ", state=" + mState + + ", isMT=" + isIncoming() + ", heldByRemote=" + mIsHeldByRemote + " ]"; + } +} diff --git a/src/java/com/android/internal/telephony/imsphone/ImsCallInfoTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsCallInfoTracker.java new file mode 100644 index 0000000000..aabe8d3ad5 --- /dev/null +++ b/src/java/com/android/internal/telephony/imsphone/ImsCallInfoTracker.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2022 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.imsphone; + +import static com.android.internal.telephony.Call.State.DISCONNECTED; +import static com.android.internal.telephony.Call.State.IDLE; + +import android.annotation.NonNull; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.Call; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.Phone; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Contains the state of all IMS calls. + */ +public class ImsCallInfoTracker { + + private final Phone mPhone; + private final List mQueue = new ArrayList<>(); + private int mNextIndex = 1; + + private final Map mImsCallInfo = new HashMap<>(); + + public ImsCallInfoTracker(Phone phone) { + mPhone = phone; + } + + /** + * Adds a new instance of the IMS call. + * + * @param c The instance of {@link ImsPhoneConnection}. + */ + public void addImsCallStatus(@NonNull ImsPhoneConnection c) { + synchronized (mImsCallInfo) { + if (mQueue.isEmpty()) { + mQueue.add(new ImsCallInfo(mNextIndex++)); + } + + Iterator it = mQueue.iterator(); + ImsCallInfo imsCallInfo = it.next(); + mQueue.remove(imsCallInfo); + + imsCallInfo.update(c); + mImsCallInfo.put(c, imsCallInfo); + + notifyImsCallStatus(); + } + } + + /** + * Updates the list of IMS calls. + * + * @param c The instance of {@link ImsPhoneConnection}. + */ + public void updateImsCallStatus(@NonNull ImsPhoneConnection c) { + updateImsCallStatus(c, false, false); + } + + /** + * Updates the list of IMS calls. + * + * @param c The instance of {@link ImsPhoneConnection}. + * @param holdReceived {@code true} if the remote party held the call. + * @param resumeReceived {@code true} if the remote party resumed the call. + */ + public void updateImsCallStatus(@NonNull ImsPhoneConnection c, + boolean holdReceived, boolean resumeReceived) { + + synchronized (mImsCallInfo) { + ImsCallInfo info = mImsCallInfo.get(c); + + boolean changed = info.update(c, holdReceived, resumeReceived); + + if (changed) notifyImsCallStatus(); + + Call.State state = c.getState(); + + // Call is disconnected. There are 2 cases in disconnected state: + // if silent redial, state == IDLE, otherwise, state == DISCONNECTED. + if (state == DISCONNECTED || state == IDLE) { + // clear the disconnected call + mImsCallInfo.remove(c); + info.reset(); + if (info.getIndex() < (mNextIndex - 1)) { + mQueue.add(info); + sort(mQueue); + } else { + mNextIndex--; + } + } + } + } + + private void notifyImsCallStatus() { + Collection infos = mImsCallInfo.values(); + ArrayList imsCallInfo = new ArrayList(infos); + sort(imsCallInfo); + mPhone.updateImsCallStatus(imsCallInfo, null); + } + + /** + * Sorts the list of IMS calls by the call index. + * + * @param infos The list of IMS calls. + */ + @VisibleForTesting + public static void sort(List infos) { + Collections.sort(infos, new Comparator() { + @Override + public int compare(ImsCallInfo l, ImsCallInfo r) { + if (l.getIndex() > r.getIndex()) { + return 1; + } else if (l.getIndex() < r.getIndex()) { + return -1; + } + return 0; + } + }); + } +} diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 622cfc354b..beaf1b96ce 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -2753,6 +2753,11 @@ public class ImsPhone extends ImsPhoneBase { mCT.triggerImsDeregistration(reason); } + @Override + public void updateImsCallStatus(List imsCallInfo, Message response) { + mDefaultPhone.updateImsCallStatus(imsCallInfo, response); + } + @Override public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 301b1ce16c..4cf2987769 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -339,6 +339,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); + mImsCallInfoTracker.addImsCallStatus(conn); } catch (ImsException | RemoteException e) { loge("processIncomingCall: exception " + e); mOperationLocalLog.log("onIncomingCall: exception processing: " + e); @@ -677,6 +678,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private ImsDialArgs mLastDialArgs = null; private Executor mExecutor = Runnable::run; + private final ImsCallInfoTracker mImsCallInfoTracker; + /** * Listeners to changes in the phone state. Intended for use by other interested IMS components * without the need to register a full blown {@link android.telephony.PhoneStateListener}. @@ -1161,6 +1164,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { }, executor); // It can take some time for ITelephony to get published, so defer connecting. post(mConnectorRunnable); + + mImsCallInfoTracker = new ImsCallInfoTracker(phone); } /** @@ -1946,6 +1951,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { setVideoCallProvider(conn, imsCall); conn.setAllowAddCallDuringVideoCall(mAllowAddCallDuringVideoCall); conn.setAllowHoldingVideoCall(mAllowHoldingVideoCall); + mImsCallInfoTracker.addImsCallStatus(conn); } catch (ImsException e) { loge("dialInternal : " + e); mOperationLocalLog.log("dialInternal exception: " + e); @@ -2667,6 +2673,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { + System.identityHashCode(conn)); call.onHangupLocal(); + mImsCallInfoTracker.updateImsCallStatus(conn); try { if (imsCall != null) { @@ -2904,6 +2911,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } if (changed) { + mImsCallInfoTracker.updateImsCallStatus(conn); if (conn.getCall() == mHandoverCall) return; updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); @@ -3332,6 +3340,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { && isForegroundHigherPriority()) { mForegroundCall.detach(mPendingMO); removeConnection(mPendingMO); + mImsCallInfoTracker.updateImsCallStatus(mPendingMO); mPendingMO.finalize(); mPendingMO = null; // if we need to perform CSFB of call, hang up any background call @@ -3363,6 +3372,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { if (conn != null) { mForegroundCall.detach(conn); removeConnection(conn); + mImsCallInfoTracker.updateImsCallStatus(conn); } updatePhoneState(); mPhone.initiateSilentRedial(reasonInfo.getExtraCode() == @@ -3782,6 +3792,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mOnHoldToneStarted = false; } conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_REMOTELY_UNHELD, null); + mImsCallInfoTracker.updateImsCallStatus(conn, false, true); } boolean useVideoPauseWorkaround = mPhone.getContext().getResources().getBoolean( @@ -5490,6 +5501,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mOnHoldToneId = System.identityHashCode(conn); } conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_REMOTELY_HELD, null); + mImsCallInfoTracker.updateImsCallStatus(conn, true, false); boolean useVideoPauseWorkaround = mPhone.getContext().getResources().getBoolean( com.android.internal.R.bool.config_useVideoPauseWorkaround); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallInfoTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallInfoTrackerTest.java new file mode 100644 index 0000000000..a0fc4b922b --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallInfoTrackerTest.java @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2022 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.imsphone; + +import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN; + +import static junit.framework.Assert.assertNotNull; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.telephony.ServiceState; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class ImsCallInfoTrackerTest extends TelephonyTest { + + private ImsCallInfoTracker mImsCallInfoTracker; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + + mImsCallInfoTracker = new ImsCallInfoTracker(mImsPhone); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testDialingNormalCall() throws Exception { + ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); + + ImsPhoneConnection c = getConnection(Call.State.DIALING, false); + mImsCallInfoTracker.addImsCallStatus(c); + + verify(mImsPhone, times(1)).updateImsCallStatus(captor.capture(), any()); + + List imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + ImsCallInfo info = imsCallInfos.get(0); + + assertNotNull(info); + assertEquals(1, info.getIndex()); + assertEquals(Call.State.DIALING, info.getCallState()); + assertFalse(info.isIncoming()); + assertFalse(info.isEmergencyCall()); + assertEquals(EUTRAN, info.getCallRadioTech()); + assertFalse(info.isHeldByRemote()); + } + + @Test + public void testDialingEmergencyCall() throws Exception { + ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); + + ImsPhoneConnection c = getConnection(Call.State.DIALING, true); + mImsCallInfoTracker.addImsCallStatus(c); + + verify(mImsPhone, times(1)).updateImsCallStatus(captor.capture(), any()); + + List imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + ImsCallInfo info = imsCallInfos.get(0); + + assertNotNull(info); + assertEquals(1, info.getIndex()); + assertEquals(Call.State.DIALING, info.getCallState()); + assertFalse(info.isIncoming()); + assertTrue(info.isEmergencyCall()); + assertEquals(EUTRAN, info.getCallRadioTech()); + assertFalse(info.isHeldByRemote()); + } + + @Test + public void testIncomingCall() throws Exception { + ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); + + ImsPhoneConnection c = getConnection(Call.State.INCOMING, false); + mImsCallInfoTracker.addImsCallStatus(c); + + verify(mImsPhone, times(1)).updateImsCallStatus(captor.capture(), any()); + + List imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + ImsCallInfo info = imsCallInfos.get(0); + + assertNotNull(info); + assertEquals(1, info.getIndex()); + assertEquals(Call.State.INCOMING, info.getCallState()); + assertTrue(info.isIncoming()); + assertFalse(info.isEmergencyCall()); + assertEquals(EUTRAN, info.getCallRadioTech()); + assertFalse(info.isHeldByRemote()); + + // Answer the call + doReturn(Call.State.ACTIVE).when(c).getState(); + mImsCallInfoTracker.updateImsCallStatus(c); + + verify(mImsPhone, times(2)).updateImsCallStatus(captor.capture(), any()); + + imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + info = imsCallInfos.get(0); + + assertNotNull(info); + assertEquals(1, info.getIndex()); + assertEquals(Call.State.ACTIVE, info.getCallState()); + + // Hold the call + doReturn(Call.State.HOLDING).when(c).getState(); + mImsCallInfoTracker.updateImsCallStatus(c); + + verify(mImsPhone, times(3)).updateImsCallStatus(captor.capture(), any()); + + imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + info = imsCallInfos.get(0); + + assertNotNull(info); + assertEquals(1, info.getIndex()); + assertEquals(Call.State.HOLDING, info.getCallState()); + + // Disconnect the call + doReturn(Call.State.DISCONNECTING).when(c).getState(); + mImsCallInfoTracker.updateImsCallStatus(c); + + verify(mImsPhone, times(4)).updateImsCallStatus(captor.capture(), any()); + + imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + info = imsCallInfos.get(0); + + assertNotNull(info); + assertEquals(1, info.getIndex()); + assertEquals(Call.State.DISCONNECTING, info.getCallState()); + + // Call disconnected + doReturn(Call.State.DISCONNECTED).when(c).getState(); + mImsCallInfoTracker.updateImsCallStatus(c); + + verify(mImsPhone, times(5)).updateImsCallStatus(captor.capture(), any()); + + imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + info = imsCallInfos.get(0); + + assertNotNull(info); + assertEquals(1, info.getIndex()); + assertEquals(Call.State.IDLE, info.getCallState()); + } + + @Test + public void testMultiCalls() throws Exception { + ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); + + ImsPhoneConnection c1 = getConnection(Call.State.INCOMING, false); + mImsCallInfoTracker.addImsCallStatus(c1); + + verify(mImsPhone, times(1)).updateImsCallStatus(captor.capture(), any()); + + doReturn(Call.State.ACTIVE).when(c1).getState(); + mImsCallInfoTracker.updateImsCallStatus(c1); + + verify(mImsPhone, times(2)).updateImsCallStatus(captor.capture(), any()); + + List imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + // 1st call + ImsCallInfo info1 = imsCallInfos.get(0); + + assertNotNull(info1); + assertEquals(1, info1.getIndex()); + assertEquals(Call.State.ACTIVE, info1.getCallState()); + + // Add 2nd WAITING call + ImsPhoneConnection c2 = getConnection(Call.State.WAITING, false); + mImsCallInfoTracker.addImsCallStatus(c2); + + verify(mImsPhone, times(3)).updateImsCallStatus(captor.capture(), any()); + + imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(2, imsCallInfos.size()); + + // 1st call + info1 = imsCallInfos.get(0); + + assertNotNull(info1); + assertEquals(1, info1.getIndex()); + assertEquals(Call.State.ACTIVE, info1.getCallState()); + + // 2nd call + ImsCallInfo info2 = imsCallInfos.get(1); + + assertNotNull(info2); + assertEquals(2, info2.getIndex()); + assertEquals(Call.State.WAITING, info2.getCallState()); + assertTrue(info2.isIncoming()); + + // Disconnect 1st call + doReturn(Call.State.DISCONNECTED).when(c1).getState(); + mImsCallInfoTracker.updateImsCallStatus(c1); + + verify(mImsPhone, times(4)).updateImsCallStatus(captor.capture(), any()); + + imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(2, imsCallInfos.size()); + + // 1st call + info1 = imsCallInfos.get(0); + + assertNotNull(info1); + assertEquals(1, info1.getIndex()); + assertEquals(Call.State.IDLE, info1.getCallState()); + + // 2nd call + info2 = imsCallInfos.get(1); + + assertNotNull(info2); + assertEquals(2, info2.getIndex()); + assertEquals(Call.State.WAITING, info2.getCallState()); + + // Answer WAITING call + doReturn(Call.State.ACTIVE).when(c2).getState(); + mImsCallInfoTracker.updateImsCallStatus(c2); + + verify(mImsPhone, times(5)).updateImsCallStatus(captor.capture(), any()); + + imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + // 2nd call + info2 = imsCallInfos.get(0); + + assertNotNull(info2); + assertEquals(2, info2.getIndex()); + assertEquals(Call.State.ACTIVE, info2.getCallState()); + } + + @Test + public void testHeldByRemote() throws Exception { + ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); + + ImsPhoneConnection c = getConnection(Call.State.INCOMING, false); + mImsCallInfoTracker.addImsCallStatus(c); + + verify(mImsPhone, times(1)).updateImsCallStatus(captor.capture(), any()); + + doReturn(Call.State.ACTIVE).when(c).getState(); + mImsCallInfoTracker.updateImsCallStatus(c); + + verify(mImsPhone, times(2)).updateImsCallStatus(captor.capture(), any()); + + // Hold received + mImsCallInfoTracker.updateImsCallStatus(c, true, false); + + verify(mImsPhone, times(3)).updateImsCallStatus(captor.capture(), any()); + + List imsCallInfos = captor.getValue(); + + assertEquals(1, imsCallInfos.size()); + + ImsCallInfo info = imsCallInfos.get(0); + + assertNotNull(info); + assertEquals(1, info.getIndex()); + assertEquals(Call.State.ACTIVE, info.getCallState()); + assertTrue(info.isHeldByRemote()); + + // Resume received + mImsCallInfoTracker.updateImsCallStatus(c, false, true); + + verify(mImsPhone, times(4)).updateImsCallStatus(captor.capture(), any()); + + imsCallInfos = captor.getValue(); + + assertEquals(1, imsCallInfos.size()); + + info = imsCallInfos.get(0); + + assertNotNull(info); + assertEquals(1, info.getIndex()); + assertEquals(Call.State.ACTIVE, info.getCallState()); + assertFalse(info.isHeldByRemote()); + } + + @Test + public void testSortImsCallInfo() throws Exception { + List imsCallInfos = new ArrayList<>(); + imsCallInfos.add(new ImsCallInfo(2)); + imsCallInfos.add(new ImsCallInfo(1)); + + assertEquals(2, imsCallInfos.get(0).getIndex()); + assertEquals(1, imsCallInfos.get(1).getIndex()); + + ImsCallInfoTracker.sort(imsCallInfos); + + assertEquals(1, imsCallInfos.get(0).getIndex()); + assertEquals(2, imsCallInfos.get(1).getIndex()); + } + + private ImsPhoneConnection getConnection(Call.State state, boolean isEmergency) { + ImsPhoneConnection c = mock(ImsPhoneConnection.class); + doReturn(isEmergency).when(c).isEmergencyCall(); + doReturn(state).when(c).getState(); + doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(c).getCallRadioTech(); + switch (state) { + case INCOMING: + case WAITING: + doReturn(true).when(c).isIncoming(); + break; + default: + doReturn(false).when(c).isIncoming(); + } + + return c; + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 222cb63dda..57ddb113ab 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -2365,6 +2365,58 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { emergencyNumber.getEmergencyServiceCategoryBitmask()); } + @Test + public void testUpdateImsCallStatusIncoming() throws Exception { + // Incoming call + ImsPhoneConnection connection = setupRingingConnection(); + + verify(mImsPhone, times(1)).updateImsCallStatus(any(), any()); + + // Disconnect the call + mImsCallListener.onCallTerminated(connection.getImsCall(), + new ImsReasonInfo(ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE, 0)); + + verify(mImsPhone, times(2)).updateImsCallStatus(any(), any()); + } + + @Test + public void testUpdateImsCallStatus() throws Exception { + // Dialing + ImsPhoneConnection connection = placeCall(); + + verify(mImsPhone, times(1)).updateImsCallStatus(any(), any()); + + // Alerting + ImsCall imsCall = connection.getImsCall(); + imsCall.getImsCallSessionListenerProxy().callSessionProgressing(imsCall.getSession(), + new ImsStreamMediaProfile()); + + verify(mImsPhone, times(2)).updateImsCallStatus(any(), any()); + + // Active + imsCall.getImsCallSessionListenerProxy().callSessionStarted(imsCall.getSession(), + new ImsCallProfile()); + + verify(mImsPhone, times(3)).updateImsCallStatus(any(), any()); + + // Held by remote + mCTUT.onCallHoldReceived(imsCall); + + verify(mImsPhone, times(4)).updateImsCallStatus(any(), any()); + + // Resumed by remote + mImsCallListener.onCallResumeReceived(imsCall); + + verify(mImsPhone, times(5)).updateImsCallStatus(any(), any()); + + // Disconnecting and then Disconnected + mCTUT.hangup(connection); + mImsCallListener.onCallTerminated(imsCall, + new ImsReasonInfo(ImsReasonInfo.CODE_USER_TERMINATED, 0)); + + verify(mImsPhone, times(7)).updateImsCallStatus(any(), any()); + } + private void sendCarrierConfigChanged() { Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); -- GitLab From c9d93096f4eb835bfc0ab5fc67b454da3dd0ca96 Mon Sep 17 00:00:00 2001 From: Hwangoo Park Date: Wed, 14 Dec 2022 12:41:55 +0000 Subject: [PATCH 268/656] Add domain selection connection for SMS This is for a normal and an emergency SMS domain selection connection. Each domain selection connection acts as a client to communicate with the domain selection service. Bug: 243377249 Test: atest SmsDomainSelectionConnectionTest Test: atest EmergencySmsDomainSelectionConnectionTest Test: manual (verify IMS/GSM/CDMA MO SMS for normal/emergency SMS when domain selection disabled) Test: manual (verify retry SMS for normal/emergency SMS when domain selection disabled) Test: manual (verify IMS/GSM/CDMA MO SMS for normal/emergency SMS when domain selection enabled) Test: manual (verify retry SMS for normal/emergency SMS when domain selection enabled) Change-Id: I75682ecadefbfd5b75a4658123ebb6eab93df3d3 --- .../DomainSelectionController.java | 5 +- ...EmergencySmsDomainSelectionConnection.java | 146 +++++++ .../SmsDomainSelectionConnection.java | 83 ++++ ...gencySmsDomainSelectionConnectionTest.java | 399 ++++++++++++++++++ .../SmsDomainSelectionConnectionTest.java | 212 ++++++++++ 5 files changed, 842 insertions(+), 3 deletions(-) create mode 100644 src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java create mode 100644 src/java/com/android/internal/telephony/domainselection/SmsDomainSelectionConnection.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/domainselection/SmsDomainSelectionConnectionTest.java diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java index 61304c3df6..52c9960076 100644 --- a/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java +++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionController.java @@ -150,12 +150,11 @@ public class DomainSelectionController { c = new NormalCallDomainSelectionConnection(phone, this); } } else if (selectorType == SELECTOR_TYPE_SMS) { - // TODO(ag/20126511) uncomment when SmSDomainSelectionConnection is ready. - /*if (isEmergency) { + if (isEmergency) { c = new EmergencySmsDomainSelectionConnection(phone, this); } else { c = new SmsDomainSelectionConnection(phone, this); - }*/ + } } addConnection(c); diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java new file mode 100644 index 0000000000..bf8cccafd9 --- /dev/null +++ b/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN; +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; + +import android.annotation.NonNull; +import android.telephony.AccessNetworkConstants; +import android.telephony.AccessNetworkConstants.TransportType; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.data.ApnSetting; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.emergency.EmergencyStateTracker; + +/** + * Manages the information of request and the callback binder for an emergency SMS. + */ +public class EmergencySmsDomainSelectionConnection extends SmsDomainSelectionConnection { + private final Object mLock = new Object(); + private @NonNull EmergencyStateTracker mEmergencyStateTracker; + private @TransportType int mPreferredTransportType = + AccessNetworkConstants.TRANSPORT_TYPE_INVALID; + + public EmergencySmsDomainSelectionConnection( + Phone phone, DomainSelectionController controller) { + this(phone, controller, EmergencyStateTracker.getInstance()); + } + + @VisibleForTesting + public EmergencySmsDomainSelectionConnection(Phone phone, + DomainSelectionController controller, EmergencyStateTracker tracker) { + super(phone, controller, true); + mTag = "DomainSelectionConnection-EmergencySMS"; + mEmergencyStateTracker = tracker; + } + + @Override + public void onWlanSelected() { + synchronized (mLock) { + if (mPreferredTransportType != AccessNetworkConstants.TRANSPORT_TYPE_INVALID) { + logi("Domain selection completion is in progress"); + return; + } + + mEmergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WLAN); + + // Change the transport type if the current preferred transport type for an emergency + // is not {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}. + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + if (anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY) + != AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { + changePreferredTransport(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + // The {@link #onDomainSlected()} will be called after the preferred transport + // is successfully changed and notified from the {@link AccessNetworksManager}. + return; + } + + super.onWlanSelected(); + } + } + + @Override + public void onWwanSelected() { + mEmergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + } + + @Override + public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) { + synchronized (mLock) { + if (mPreferredTransportType != AccessNetworkConstants.TRANSPORT_TYPE_INVALID) { + logi("Domain selection completion is in progress"); + return; + } + + if (domain == NetworkRegistrationInfo.DOMAIN_PS) { + // Change the transport type if the current preferred transport type for + // an emergency is not {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}. + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + if (anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY) + != AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { + changePreferredTransport(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + // The {@link #onDomainSlected()} will be called after the preferred transport + // is successfully changed and notified from the {@link AccessNetworksManager}. + return; + } + } + + super.onDomainSelected(domain); + } + } + + @Override + public void finishSelection() { + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + + synchronized (mLock) { + if (mPreferredTransportType != AccessNetworkConstants.TRANSPORT_TYPE_INVALID) { + mPreferredTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; + anm.unregisterForQualifiedNetworksChanged(mHandler); + } + } + + super.finishSelection(); + } + + @Override + protected void onQualifiedNetworksChanged() { + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + int preferredTransportType = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); + + synchronized (mLock) { + if (preferredTransportType == mPreferredTransportType) { + mPreferredTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; + super.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + anm.unregisterForQualifiedNetworksChanged(mHandler); + } + } + } + + private void changePreferredTransport(@TransportType int transportType) { + logi("Change preferred transport: " + transportType); + initHandler(); + mPreferredTransportType = transportType; + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + anm.registerForQualifiedNetworksChanged(mHandler, EVENT_QUALIFIED_NETWORKS_CHANGED); + mPhone.notifyEmergencyDomainSelected(transportType); + } +} diff --git a/src/java/com/android/internal/telephony/domainselection/SmsDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/SmsDomainSelectionConnection.java new file mode 100644 index 0000000000..36a7b17384 --- /dev/null +++ b/src/java/com/android/internal/telephony/domainselection/SmsDomainSelectionConnection.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static android.telephony.DomainSelectionService.SELECTOR_TYPE_SMS; + +import android.annotation.NonNull; +import android.telephony.Annotation.DisconnectCauses; +import android.telephony.DomainSelectionService; +import android.telephony.NetworkRegistrationInfo; + +import com.android.internal.telephony.Phone; + +import java.util.concurrent.CompletableFuture; + +/** + * Manages the information of request and the callback binder for SMS. + */ +public class SmsDomainSelectionConnection extends DomainSelectionConnection { + private DomainSelectionConnectionCallback mCallback; + + public SmsDomainSelectionConnection(Phone phone, DomainSelectionController controller) { + this(phone, controller, false); + mTag = "DomainSelectionConnection-SMS"; + } + + protected SmsDomainSelectionConnection(Phone phone, DomainSelectionController controller, + boolean isEmergency) { + super(phone, SELECTOR_TYPE_SMS, isEmergency, controller); + } + + @Override + public void onWlanSelected() { + super.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + } + + @Override + public void onSelectionTerminated(@DisconnectCauses int cause) { + if (mCallback != null) mCallback.onSelectionTerminated(cause); + } + + @Override + public void finishSelection() { + CompletableFuture future = getCompletableFuture(); + + if (future != null && !future.isDone()) { + cancelSelection(); + } else { + super.finishSelection(); + } + } + + /** + * Requests a domain selection for SMS. + * + * @param attr The attributes required to determine the domain. + * @param callback A callback to notify an error of the domain selection. + * @return A {@link CompletableFuture} to get the selected domain + * {@link NetworkRegistrationInfo#DOMAIN_PS} or + * {@link NetworkRegistrationInfo#DOMAIN_CS}. + */ + public @NonNull CompletableFuture requestDomainSelection( + @NonNull DomainSelectionService.SelectionAttributes attr, + @NonNull DomainSelectionConnectionCallback callback) { + mCallback = callback; + selectDomain(attr); + return getCompletableFuture(); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java new file mode 100644 index 0000000000..ff951d566b --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN; +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.telephony.AccessNetworkConstants; +import android.telephony.DomainSelectionService; +import android.telephony.DomainSelector; +import android.telephony.NetworkRegistrationInfo; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.emergency.EmergencyStateTracker; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import java.util.concurrent.CompletableFuture; + +/** + * Unit tests for EmergencySmsDomainSelectionConnection. + */ +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { + private DomainSelectionController mDsController; + private DomainSelectionConnection.DomainSelectionConnectionCallback mDscCallback; + private DomainSelector mDomainSelector; + private EmergencyStateTracker mEmergencyStateTracker; + + private Handler mHandler; + private AccessNetworksManager mAnm; + private DomainSelectionService.SelectionAttributes mDsAttr; + private EmergencySmsDomainSelectionConnection mDsConnection; + + @Before + public void setUp() throws Exception { + super.setUp(this.getClass().getSimpleName()); + + if (Looper.myLooper() == null) { + Looper.prepare(); + } + + mHandler = new Handler(Looper.myLooper()); + mDsController = Mockito.mock(DomainSelectionController.class); + mDscCallback = Mockito.mock( + DomainSelectionConnection.DomainSelectionConnectionCallback.class); + mDomainSelector = Mockito.mock(DomainSelector.class); + mEmergencyStateTracker = Mockito.mock(EmergencyStateTracker.class); + mAnm = Mockito.mock(AccessNetworksManager.class); + when(mPhone.getAccessNetworksManager()).thenReturn(mAnm); + + mDsConnection = new EmergencySmsDomainSelectionConnection( + mPhone, mDsController, mEmergencyStateTracker); + mDsConnection.getTransportSelectorCallback().onCreated(mDomainSelector); + mDsAttr = new DomainSelectionService.SelectionAttributes.Builder( + mPhone.getPhoneId(), mPhone.getSubId(), DomainSelectionService.SELECTOR_TYPE_SMS) + .setEmergency(true) + .build(); + } + + @After + public void tearDown() throws Exception { + mDomainSelector = null; + mDsAttr = null; + mDsConnection = null; + mDscCallback = null; + mDsController = null; + mEmergencyStateTracker = null; + super.tearDown(); + } + + @Test + @SmallTest + public void testOnWlanSelected() throws Exception { + when(mAnm.getPreferredTransport(anyInt())) + .thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onWlanSelected(); + processAllMessages(); + + assertTrue(future.isDone()); + verify(mEmergencyStateTracker).onEmergencyTransportChanged(eq(MODE_EMERGENCY_WLAN)); + } + + @Test + @SmallTest + public void testOnWlanSelectedWithDifferentTransportType() throws Exception { + when(mAnm.getPreferredTransport(anyInt())).thenReturn( + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onWlanSelected(); + processAllMessages(); + + ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mEmergencyStateTracker).onEmergencyTransportChanged(eq(MODE_EMERGENCY_WLAN)); + verify(mAnm).registerForQualifiedNetworksChanged( + handlerCaptor.capture(), msgCaptor.capture()); + verify(mPhone).notifyEmergencyDomainSelected( + eq(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)); + + Handler handler = handlerCaptor.getValue(); + Integer msg = msgCaptor.getValue(); + handler.handleMessage(Message.obtain(handler, msg.intValue())); + processAllMessages(); + + assertTrue(future.isDone()); + verify(mAnm).unregisterForQualifiedNetworksChanged(any(Handler.class)); + } + + @Test + @SmallTest + public void testOnWlanSelectedWithDifferentTransportTypeWhilePreferredTransportChanged() + throws Exception { + when(mAnm.getPreferredTransport(anyInt())).thenReturn( + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onWlanSelected(); + // When onWlanSelected() is called again, + // it will be ignored because the change of preferred transport is in progress. + // => onEmergencyTransportChanged() is called only once. + mDsConnection.onWlanSelected(); + processAllMessages(); + + ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mEmergencyStateTracker).onEmergencyTransportChanged(eq(MODE_EMERGENCY_WLAN)); + verify(mAnm).registerForQualifiedNetworksChanged( + handlerCaptor.capture(), msgCaptor.capture()); + verify(mPhone).notifyEmergencyDomainSelected( + eq(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)); + + Handler handler = handlerCaptor.getValue(); + Integer msg = msgCaptor.getValue(); + handler.handleMessage(Message.obtain(handler, msg.intValue())); + processAllMessages(); + + assertTrue(future.isDone()); + verify(mAnm).unregisterForQualifiedNetworksChanged(any(Handler.class)); + } + + @Test + @SmallTest + public void testOnWwanSelected() throws Exception { + mDsConnection.onWwanSelected(); + + verify(mEmergencyStateTracker).onEmergencyTransportChanged(eq(MODE_EMERGENCY_WWAN)); + } + + @Test + @SmallTest + public void testOnDomainSelectedPs() throws Exception { + when(mAnm.getPreferredTransport(anyInt())) + .thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + processAllMessages(); + + assertTrue(future.isDone()); + } + + @Test + @SmallTest + public void testOnDomainSelectedPsWithDifferentTransportType() throws Exception { + when(mAnm.getPreferredTransport(anyInt())).thenReturn( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + processAllMessages(); + + ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mAnm).registerForQualifiedNetworksChanged( + handlerCaptor.capture(), msgCaptor.capture()); + verify(mPhone).notifyEmergencyDomainSelected( + eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + + Handler handler = handlerCaptor.getValue(); + Integer msg = msgCaptor.getValue(); + handler.handleMessage(Message.obtain(handler, msg.intValue())); + processAllMessages(); + + assertTrue(future.isDone()); + verify(mAnm).unregisterForQualifiedNetworksChanged(any(Handler.class)); + } + + @Test + @SmallTest + public void testOnDomainSelectedPsWithDifferentTransportTypeAndNotChanged() throws Exception { + when(mAnm.getPreferredTransport(anyInt())).thenReturn( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + processAllMessages(); + + ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mAnm).registerForQualifiedNetworksChanged( + handlerCaptor.capture(), msgCaptor.capture()); + verify(mPhone).notifyEmergencyDomainSelected( + eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + + Handler handler = handlerCaptor.getValue(); + Integer msg = msgCaptor.getValue(); + handler.handleMessage(Message.obtain(handler, msg.intValue())); + processAllMessages(); + + assertFalse(future.isDone()); + verify(mAnm, never()).unregisterForQualifiedNetworksChanged(any(Handler.class)); + } + + @Test + @SmallTest + public void testOnDomainSelectedPsWithDifferentTransportTypeWhilePreferredTransportChanged() + throws Exception { + when(mAnm.getPreferredTransport(anyInt())).thenReturn( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + // When onDomainSelected() is called again with the different domain, + // it will be ignored because the change of preferred transport is in progress. + // => The domain selection result is DOMAIN_PS. + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_CS); + processAllMessages(); + + ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mAnm).registerForQualifiedNetworksChanged( + handlerCaptor.capture(), msgCaptor.capture()); + verify(mPhone).notifyEmergencyDomainSelected( + eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + + Handler handler = handlerCaptor.getValue(); + Integer msg = msgCaptor.getValue(); + handler.handleMessage(Message.obtain(handler, msg.intValue())); + processAllMessages(); + + assertTrue(future.isDone()); + verify(mAnm).unregisterForQualifiedNetworksChanged(any(Handler.class)); + } + + @Test + @SmallTest + public void testOnDomainSelectedCs() throws Exception { + when(mAnm.getPreferredTransport(anyInt())) + .thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_CS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_CS); + processAllMessages(); + + assertTrue(future.isDone()); + } + + @Test + @SmallTest + public void testFinishSelection() throws Exception { + when(mAnm.getPreferredTransport(anyInt())).thenReturn( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + processAllMessages(); + + ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mAnm).registerForQualifiedNetworksChanged( + handlerCaptor.capture(), msgCaptor.capture()); + verify(mPhone).notifyEmergencyDomainSelected( + eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + + mDsConnection.finishSelection(); + processAllMessages(); + + assertFalse(future.isDone()); + verify(mAnm).unregisterForQualifiedNetworksChanged(any(Handler.class)); + verify(mDomainSelector).cancelSelection(); + } + + @Test + @SmallTest + public void testFinishSelectionAfterDomainSelectionCompleted() throws Exception { + when(mAnm.getPreferredTransport(anyInt())).thenReturn( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + processAllMessages(); + + ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Integer.class); + verify(mAnm).registerForQualifiedNetworksChanged( + handlerCaptor.capture(), msgCaptor.capture()); + verify(mPhone).notifyEmergencyDomainSelected( + eq(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + + Handler handler = handlerCaptor.getValue(); + Integer msg = msgCaptor.getValue(); + handler.handleMessage(Message.obtain(handler, msg.intValue())); + processAllMessages(); + mDsConnection.finishSelection(); + + assertTrue(future.isDone()); + // This method should be invoked one time. + verify(mAnm).unregisterForQualifiedNetworksChanged(any(Handler.class)); + verify(mDomainSelector).finishSelection(); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/SmsDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/SmsDomainSelectionConnectionTest.java new file mode 100644 index 0000000000..77d836721d --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/SmsDomainSelectionConnectionTest.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2022 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.domainselection; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import android.os.Handler; +import android.os.HandlerThread; +import android.telephony.DisconnectCause; +import android.telephony.DomainSelectionService; +import android.telephony.DomainSelector; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.TransportSelectorCallback; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.TestableLooper; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.telephony.Phone; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.CompletableFuture; + +/** + * Unit tests for SmsDomainSelectionConnection. + */ +@RunWith(AndroidJUnit4.class) +public class SmsDomainSelectionConnectionTest { + private static final int SLOT_ID = 0; + private static final int SUB_ID = 1; + + @Mock private Phone mPhone; + @Mock private DomainSelectionController mDsController; + @Mock private DomainSelectionConnection.DomainSelectionConnectionCallback mDscCallback; + @Mock private DomainSelector mDomainSelector; + + private Handler mHandler; + private TestableLooper mTestableLooper; + private DomainSelectionService.SelectionAttributes mDsAttr; + private SmsDomainSelectionConnection mDsConnection; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + HandlerThread handlerThread = new HandlerThread( + SmsDomainSelectionConnectionTest.class.getSimpleName()); + handlerThread.start(); + + mHandler = new Handler(handlerThread.getLooper()); + mDsConnection = new SmsDomainSelectionConnection(mPhone, mDsController); + mDsConnection.getTransportSelectorCallback().onCreated(mDomainSelector); + mDsAttr = new DomainSelectionService.SelectionAttributes.Builder( + SLOT_ID, SUB_ID, DomainSelectionService.SELECTOR_TYPE_SMS).build(); + } + + @After + public void tearDown() throws Exception { + if (mTestableLooper != null) { + mTestableLooper.destroy(); + mTestableLooper = null; + } + + if (mHandler != null) { + mHandler.getLooper().quit(); + mHandler = null; + } + + mDomainSelector = null; + mDsAttr = null; + mDsConnection = null; + mDscCallback = null; + mDsController = null; + mPhone = null; + } + + @Test + @SmallTest + public void testRequestDomainSelection() { + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + + assertNotNull(future); + verify(mDsController).selectDomain(eq(mDsAttr), any(TransportSelectorCallback.class)); + } + + @Test + @SmallTest + public void testOnWlanSelected() throws Exception { + setUpTestableLooper(); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onWlanSelected(); + processAllMessages(); + + assertTrue(future.isDone()); + } + + @Test + @SmallTest + public void testOnSelectionTerminated() { + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + mDsConnection.onSelectionTerminated(DisconnectCause.LOCAL); + + assertFalse(future.isDone()); + verify(mDscCallback).onSelectionTerminated(eq(DisconnectCause.LOCAL)); + } + + @Test + @SmallTest + public void testOnDomainSelectedPs() throws Exception { + setUpTestableLooper(); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + processAllMessages(); + + assertTrue(future.isDone()); + } + + @Test + @SmallTest + public void testOnDomainSelectedCs() throws Exception { + setUpTestableLooper(); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_CS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_CS); + processAllMessages(); + + assertTrue(future.isDone()); + } + + @Test + @SmallTest + public void testFinishSelection() throws Exception { + setUpTestableLooper(); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + processAllMessages(); + mDsConnection.finishSelection(); + + verify(mDomainSelector).finishSelection(); + } + + @Test + @SmallTest + public void testCancelSelection() throws Exception { + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.finishSelection(); + + verify(mDomainSelector).cancelSelection(); + } + + private void setUpTestableLooper() throws Exception { + mTestableLooper = new TestableLooper(mHandler.getLooper()); + } + + private void processAllMessages() { + while (!mTestableLooper.getLooper().getQueue().isIdle()) { + mTestableLooper.processAllMessages(); + } + } +} -- GitLab From 81ac5f5bf8ac8ebbeb6a0b9d96569dc923b12427 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 10 Aug 2022 04:10:36 +0000 Subject: [PATCH 269/656] Implement onTriggerEpsFallback. Bug: 234803835 Test: atest MmTelFeatureTestOnMockModem#testTriggerEpsFallback Change-Id: Id5c1e27ba6bf8622550a15c8544fa6d695f6bd5a --- src/java/com/android/internal/telephony/Phone.java | 3 ++- .../com/android/internal/telephony/imsphone/ImsPhone.java | 3 ++- .../internal/telephony/imsphone/ImsPhoneCallTracker.java | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index e76eb72d0e..44ea61ceda 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -67,6 +67,7 @@ import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.HalService; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RegistrationManager; +import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.text.TextUtils; import android.util.LocalLog; @@ -4929,7 +4930,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @param reason specifies the reason for EPS fallback. * @param response is callback message. */ - public void triggerEpsFallback(int reason, Message response) { + public void triggerEpsFallback(@MmTelFeature.EpsFallbackReason int reason, Message response) { mCi.triggerEpsFallback(reason, response); } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index beaf1b96ce..4b0229b984 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -90,6 +90,7 @@ import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.ImsSsData; import android.telephony.ims.ImsSsInfo; import android.telephony.ims.RegistrationManager; +import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsUtImplBase; import android.text.TextUtils; @@ -2743,7 +2744,7 @@ public class ImsPhone extends ImsPhoneBase { } @Override - public void triggerEpsFallback(int reason, Message response) { + public void triggerEpsFallback(@MmTelFeature.EpsFallbackReason int reason, Message response) { mDefaultPhone.triggerEpsFallback(reason, response); } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 4cf2987769..4fd41a9e39 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -393,6 +393,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { }, mExecutor); } + @Override + public void onTriggerEpsFallback(@MmTelFeature.EpsFallbackReason int reason) { + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (DBG) log("onTriggerEpsFallback reason=" + reason); + mPhone.triggerEpsFallback(reason, null); + }, mExecutor); + } + /** * Schedule the given Runnable on mExecutor and block this thread until it finishes. * @param r The Runnable to run. -- GitLab From 7b30ca1459653fce9cb93adde6e6e6ae82a189d8 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Mon, 14 Nov 2022 18:44:35 +0000 Subject: [PATCH 270/656] Add isN1ModeEnabled and setN1ModeEnabled to Phone Bug: 255450196 Test: build Change-Id: I764c810a923f0640ed29127c472cc9366d933779 --- .../internal/telephony/CommandsInterface.java | 14 ++++ .../com/android/internal/telephony/Phone.java | 18 +++++ .../com/android/internal/telephony/RIL.java | 65 +++++++++++++++++++ .../android/internal/telephony/RILUtils.java | 6 ++ 4 files changed, 103 insertions(+) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index a8e71b0d58..3517b21afd 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2973,4 +2973,18 @@ public interface CommandsInterface { * @param result A callback to receive the response. */ default void updateImsCallStatus(@NonNull List imsCallInfo, Message result) {} + + /** + * Enables or disables N1 mode (access to 5G core network) in accordance with + * 3GPP TS 24.501 4.9. + * @param enable {@code true} to enable N1 mode, {@code false} to disable N1 mode. + * @param result Callback message to receive the result. + */ + default void setN1ModeEnabled(boolean enable, Message result) {} + + /** + * Check whether N1 mode (access to 5G core network) is enabled or not. + * @param result Callback message to receive the result. + */ + default void isN1ModeEnabled(Message result) {} } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index e76eb72d0e..98fbca1353 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5091,6 +5091,24 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.updateImsCallStatus(imsCallInfo, response); } + /** + * Enables or disables N1 mode (access to 5G core network) in accordance with + * 3GPP TS 24.501 4.9. + * @param enable {@code true} to enable N1 mode, {@code false} to disable N1 mode. + * @param result Callback message to receive the result. + */ + public void setN1ModeEnabled(boolean enable, Message result) { + mCi.setN1ModeEnabled(enable, result); + } + + /** + * Check whether N1 mode (access to 5G core network) is enabled or not. + * @param result Callback message to receive the result. + */ + public void isN1ModeEnabled(Message result) { + mCi.isN1ModeEnabled(result); + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 61c61d3505..c248a188a0 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5627,6 +5627,71 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * {@inheritDoc} + */ + @Override + public void setN1ModeEnabled(boolean enable, Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); + if (networkProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_SET_N1_MODE_ENABLED, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " enable=" + enable); + } + + try { + networkProxy.setN1ModeEnabled(rr.mSerial, enable); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "setN1ModeEnabled", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "setN1ModeEnabled: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void isN1ModeEnabled(Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); + if (networkProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_IS_N1_MODE_ENABLED, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + networkProxy.isN1ModeEnabled(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_NETWORK, "isN1ModeEnabled", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "isN1ModeEnabled: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + //***** Private Methods /** * This is a helper function to be called when an indication callback is called for any radio diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 3d09e32a19..19ddecdacd 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -114,6 +114,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_WAI import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IMS_REGISTRATION_STATE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IMS_SEND_SMS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ISIM_AUTHENTICATION; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_N1_MODE_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_VONR_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_LAST_CALL_FAIL_CAUSE; @@ -164,6 +165,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LINK_C import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LOCATION_UPDATES; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_MUTE; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_N1_MODE_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED; @@ -5201,6 +5203,10 @@ public class RILUtils { return "SET_NULL_CIPHER_AND_INTEGRITY_ENABLED"; case RIL_REQUEST_UPDATE_IMS_CALL_STATUS: return "UPDATE_IMS_CALL_STATUS"; + case RIL_REQUEST_SET_N1_MODE_ENABLED: + return "SET_N1_MODE_ENABLED"; + case RIL_REQUEST_IS_N1_MODE_ENABLED: + return "IS_N1_MODE_ENABLED"; default: return ""; } -- GitLab From 8557ae4c0308ae4f1488de1e1e9a9c25123636be Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Mon, 5 Dec 2022 14:59:23 -0600 Subject: [PATCH 271/656] Add new Telephony APIs for Cell Broadcast Bug: 256043136 Test: atest CtsTelephonyTestCases Test: atest com.android.internal.telephony.GsmCdmaPhoneTest Test: manual Change-Id: Ie7f8b82820b930ea688cff68d1ce194264e6c580 --- .../telephony/CellBroadcastConfigTracker.java | 461 ++++++++++++++++++ .../internal/telephony/GsmCdmaPhone.java | 20 + .../com/android/internal/telephony/Phone.java | 16 + .../cdma/CdmaSmsBroadcastConfigInfo.java | 20 + .../internal/telephony/GsmCdmaPhoneTest.java | 376 ++++++++++++++ 5 files changed, 893 insertions(+) create mode 100644 src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java diff --git a/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java b/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java new file mode 100644 index 0000000000..d6efaeddd1 --- /dev/null +++ b/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java @@ -0,0 +1,461 @@ +/* + * Copyright 2022 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; + +import android.annotation.NonNull; +import android.os.AsyncResult; +import android.os.Build; +import android.os.Handler; +import android.os.Message; +import android.telephony.CellBroadcastIdRange; +import android.telephony.SmsCbMessage; +import android.telephony.TelephonyManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; + +/** + * This class is to track the state to set cell broadcast config + */ + +public final class CellBroadcastConfigTracker extends StateMachine { + private static final boolean DBG = Build.IS_DEBUGGABLE; + + private static final int EVENT_REQUEST = 1; + private static final int EVENT_CONFIGURATION_DONE = 2; + private static final int EVENT_ACTIVATION_DONE = 3; + + private static final int SMS_CB_CODE_SCHEME_MIN = 0; + private static final int SMS_CB_CODE_SCHEME_MAX = 255; + + // Cache of current cell broadcast id ranges of 3gpp + private List mCbRanges3gpp = new CopyOnWriteArrayList<>(); + // Cache of current cell broadcast id ranges of 3gpp2 + private List mCbRanges3gpp2 = new CopyOnWriteArrayList<>(); + private Phone mPhone; + + + /** + * The class is to present the request to set cell broadcast id ranges + */ + private static class Request { + private final List mCbRangesRequest3gpp = + new CopyOnWriteArrayList<>(); + private final List mCbRangesRequest3gpp2 = + new CopyOnWriteArrayList<>(); + Consumer mCallback; + + Request(@NonNull List ranges, @NonNull Consumer callback) { + ranges.forEach(r -> { + if (r.getType() == SmsCbMessage.MESSAGE_FORMAT_3GPP) { + mCbRangesRequest3gpp.add(r); + } else { + mCbRangesRequest3gpp2.add(r); + } + }); + mCallback = callback; + } + + List get3gppRanges() { + return mCbRangesRequest3gpp; + } + + List get3gpp2Ranges() { + return mCbRangesRequest3gpp2; + } + + Consumer getCallback() { + return mCallback; + } + + @Override + public String toString() { + return "Request[mCbRangesRequest3gpp = " + mCbRangesRequest3gpp + ", " + + "mCbRangesRequest3gpp2 = " + mCbRangesRequest3gpp2 + ", " + + "mCallback = " + mCallback + "]"; + } + } + + /* + * The idle state which does not have ongoing radio request. + */ + private class IdleState extends State { + @Override + public boolean processMessage(Message msg) { + boolean retVal = NOT_HANDLED; + if (DBG) { + logd("IdleState message:" + msg.what); + } + switch (msg.what) { + case EVENT_REQUEST: + Request request = (Request) msg.obj; + if (DBG) { + logd("IdleState handle EVENT_REQUEST with request:" + request); + } + if (!mCbRanges3gpp.equals(request.get3gppRanges())) { + // set gsm config if the config is changed + setGsmConfig(request.get3gppRanges(), request); + transitionTo(mGsmConfiguringState); + } else if (!mCbRanges3gpp2.equals(request.get3gpp2Ranges())) { + // set cdma config directly if no gsm config change but cdma config is + // changed + setCdmaConfig(request.get3gpp2Ranges(), request); + transitionTo(mCdmaConfiguringState); + } else { + logd("Do nothing as the requested ranges are same as now"); + request.getCallback().accept(TelephonyManager.CELLBROADCAST_RESULT_SUCCESS); + } + retVal = HANDLED; + break; + default: + break; + } + return retVal; + } + } + private IdleState mIdleState = new IdleState(); + + /* + * The state waiting for the result to set gsm config. + */ + private class GsmConfiguringState extends State { + @Override + public boolean processMessage(Message msg) { + boolean retVal = NOT_HANDLED; + if (DBG) { + logd("GsmConfiguringState message:" + msg.what); + } + switch (msg.what) { + case EVENT_REQUEST: + deferMessage(msg); + retVal = HANDLED; + break; + case EVENT_CONFIGURATION_DONE: + AsyncResult ar = (AsyncResult) msg.obj; + Request request = (Request) ar.userObj; + if (DBG) { + logd("GsmConfiguringState handle EVENT_CONFIGURATION_DONE with request:" + + request); + } + if (ar.exception == null) { + // set gsm activation and transit to gsm activating state + setActivation(SmsCbMessage.MESSAGE_FORMAT_3GPP, + !request.get3gppRanges().isEmpty(), request); + transitionTo(mGsmActivatingState); + } else { + logd("Failed to set gsm config"); + request.getCallback().accept( + TelephonyManager.CELLBROADCAST_RESULT_FAIL_CONFIG); + // transit to idle state on the failure case + transitionTo(mIdleState); + } + retVal = HANDLED; + break; + default: + break; + } + return retVal; + } + } + private GsmConfiguringState mGsmConfiguringState = new GsmConfiguringState(); + + /* + * The state waiting for the result to set gsm activation. + */ + private class GsmActivatingState extends State { + @Override + public boolean processMessage(Message msg) { + boolean retVal = NOT_HANDLED; + if (DBG) { + logd("GsmActivatingState message:" + msg.what); + } + switch (msg.what) { + case EVENT_REQUEST: + deferMessage(msg); + retVal = HANDLED; + break; + case EVENT_ACTIVATION_DONE: + AsyncResult ar = (AsyncResult) msg.obj; + Request request = (Request) ar.userObj; + if (DBG) { + logd("GsmActivatingState handle EVENT_ACTIVATION_DONE with request:" + + request); + } + if (ar.exception == null) { + mCbRanges3gpp = request.get3gppRanges(); + if (!mCbRanges3gpp2.equals(request.get3gpp2Ranges())) { + // set cdma config and transit to cdma configuring state if the config + // is changed. + setCdmaConfig(request.get3gpp2Ranges(), request); + transitionTo(mCdmaConfiguringState); + } else { + logd("Done as no need to update ranges for 3gpp2"); + request.getCallback().accept( + TelephonyManager.CELLBROADCAST_RESULT_SUCCESS); + // transit to idle state if there is no cdma config change + transitionTo(mIdleState); + } + } else { + logd("Failed to set gsm activation"); + request.getCallback().accept( + TelephonyManager.CELLBROADCAST_RESULT_FAIL_ACTIVATION); + // transit to idle state on the failure case + transitionTo(mIdleState); + } + retVal = HANDLED; + break; + default: + break; + } + return retVal; + } + } + private GsmActivatingState mGsmActivatingState = new GsmActivatingState(); + + /* + * The state waiting for the result to set cdma config. + */ + private class CdmaConfiguringState extends State { + @Override + public boolean processMessage(Message msg) { + boolean retVal = NOT_HANDLED; + if (DBG) { + logd("CdmaConfiguringState message:" + msg.what); + } + switch (msg.what) { + case EVENT_REQUEST: + deferMessage(msg); + retVal = HANDLED; + break; + case EVENT_CONFIGURATION_DONE: + AsyncResult ar = (AsyncResult) msg.obj; + Request request = (Request) ar.userObj; + if (DBG) { + logd("CdmaConfiguringState handle EVENT_ACTIVATION_DONE with request:" + + request); + } + if (ar.exception == null) { + // set cdma activation and transit to cdma activating state + setActivation(SmsCbMessage.MESSAGE_FORMAT_3GPP2, + !request.get3gpp2Ranges().isEmpty(), request); + transitionTo(mCdmaActivatingState); + } else { + logd("Failed to set cdma config"); + request.getCallback().accept( + TelephonyManager.CELLBROADCAST_RESULT_FAIL_CONFIG); + // transit to idle state on the failure case + transitionTo(mIdleState); + } + retVal = HANDLED; + break; + default: + break; + } + return retVal; + } + } + private CdmaConfiguringState mCdmaConfiguringState = new CdmaConfiguringState(); + + /* + * The state waiting for the result to set cdma activation. + */ + private class CdmaActivatingState extends State { + @Override + public boolean processMessage(Message msg) { + boolean retVal = NOT_HANDLED; + if (DBG) { + logd("CdmaActivatingState message:" + msg.what); + } + switch (msg.what) { + case EVENT_REQUEST: + deferMessage(msg); + retVal = HANDLED; + break; + case EVENT_ACTIVATION_DONE: + AsyncResult ar = (AsyncResult) msg.obj; + Request request = (Request) ar.userObj; + if (DBG) { + logd("CdmaActivatingState handle EVENT_ACTIVATION_DONE with request:" + + request); + } + if (ar.exception == null) { + mCbRanges3gpp2 = request.get3gpp2Ranges(); + request.getCallback().accept( + TelephonyManager.CELLBROADCAST_RESULT_SUCCESS); + } else { + logd("Failed to set cdma activation"); + request.getCallback().accept( + TelephonyManager.CELLBROADCAST_RESULT_FAIL_ACTIVATION); + } + // transit to idle state anyway + transitionTo(mIdleState); + retVal = HANDLED; + break; + default: + break; + } + return retVal; + } + } + private CdmaActivatingState mCdmaActivatingState = new CdmaActivatingState(); + + private CellBroadcastConfigTracker(Phone phone) { + super("CellBroadcastConfigTracker-" + phone.getPhoneId()); + init(phone); + } + + private CellBroadcastConfigTracker(Phone phone, Handler handler) { + super("CellBroadcastConfigTracker-" + phone.getPhoneId(), handler); + init(phone); + } + + private void init(Phone phone) { + logd("init"); + mPhone = phone; + + addState(mIdleState); + addState(mGsmConfiguringState); + addState(mGsmActivatingState); + addState(mCdmaConfiguringState); + addState(mCdmaActivatingState); + setInitialState(mIdleState); + } + + /** + * create a CellBroadcastConfigTracker instance for the phone + */ + public static CellBroadcastConfigTracker make(Phone phone, Handler handler) { + CellBroadcastConfigTracker tracker = handler == null + ? new CellBroadcastConfigTracker(phone) + : new CellBroadcastConfigTracker(phone, handler); + tracker.start(); + return tracker; + } + + /** + * Return current cell broadcast ranges. + */ + @NonNull public List getCellBroadcastIdRanges() { + List ranges = new ArrayList<>(); + ranges.addAll(mCbRanges3gpp); + ranges.addAll(mCbRanges3gpp2); + return ranges; + } + + /** + * Set reception of cell broadcast messages with the list of the given ranges. + */ + public void setCellBroadcastIdRanges( + @NonNull List ranges, @NonNull Consumer callback) { + if (DBG) { + logd("setCellBroadcastIdRanges with ranges:" + ranges); + } + ranges = mergeRangesAsNeeded(ranges); + sendMessage(EVENT_REQUEST, new Request(ranges, callback)); + } + + /** + * Merge the overlapped CellBroadcastIdRanges in the list as needed + * @param ranges the list of CellBroadcastIdRanges + * @return the list of CellBroadcastIdRanges without overlapping + * + * @throws IllegalArgumentException if there is conflict of the ranges. For instance, + * the channel is enabled in some range, but disable in others. + */ + @VisibleForTesting + public static @NonNull List mergeRangesAsNeeded( + @NonNull List ranges) throws IllegalArgumentException { + ranges.sort((r1, r2) -> r1.getType() != r2.getType() ? r1.getType() - r2.getType() + : (r1.getStartId() != r2.getStartId() ? r1.getStartId() - r2.getStartId() + : r2.getEndId() - r1.getEndId())); + final List newRanges = new ArrayList<>(); + ranges.forEach(r -> { + if (newRanges.isEmpty() || newRanges.get(newRanges.size() - 1).getType() != r.getType() + || newRanges.get(newRanges.size() - 1).getEndId() + 1 < r.getStartId() + || (newRanges.get(newRanges.size() - 1).getEndId() + 1 == r.getStartId() + && newRanges.get(newRanges.size() - 1).isEnabled() != r.isEnabled())) { + newRanges.add(new CellBroadcastIdRange(r.getStartId(), r.getEndId(), + r.getType(), r.isEnabled())); + } else { + if (newRanges.get(newRanges.size() - 1).isEnabled() != r.isEnabled()) { + throw new IllegalArgumentException("range conflict " + r); + } + if (r.getEndId() > newRanges.get(newRanges.size() - 1).getEndId()) { + CellBroadcastIdRange range = newRanges.get(newRanges.size() - 1); + newRanges.set(newRanges.size() - 1, new CellBroadcastIdRange( + range.getStartId(), r.getEndId(), range.getType(), range.isEnabled())); + } + } + }); + return newRanges; + } + + private void setGsmConfig(List ranges, Request request) { + if (DBG) { + logd("setGsmConfig with " + ranges); + } + + SmsBroadcastConfigInfo[] configs = new SmsBroadcastConfigInfo[ranges.size()]; + for (int i = 0; i < configs.length; i++) { + CellBroadcastIdRange r = ranges.get(i); + configs[i] = new SmsBroadcastConfigInfo(r.getStartId(), r.getEndId(), + SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, r.isEnabled()); + } + + Message response = obtainMessage(EVENT_CONFIGURATION_DONE, request); + mPhone.mCi.setGsmBroadcastConfig(configs, response); + } + + private void setCdmaConfig(List ranges, Request request) { + if (DBG) { + logd("setCdmaConfig with " + ranges); + } + + CdmaSmsBroadcastConfigInfo[] configs = + new CdmaSmsBroadcastConfigInfo[ranges.size()]; + for (int i = 0; i < configs.length; i++) { + CellBroadcastIdRange r = ranges.get(i); + configs[i] = new CdmaSmsBroadcastConfigInfo( + r.getStartId(), r.getEndId(), 1, r.isEnabled()); + } + + Message response = obtainMessage(EVENT_CONFIGURATION_DONE, request); + mPhone.mCi.setCdmaBroadcastConfig(configs, response); + } + + private void setActivation(int type, boolean activate, Request request) { + if (DBG) { + logd("setActivation(" + type + "." + activate + ')'); + } + + Message response = obtainMessage(EVENT_ACTIVATION_DONE, request); + + if (type == SmsCbMessage.MESSAGE_FORMAT_3GPP) { + mPhone.mCi.setGsmBroadcastActivation(activate, response); + } else if (type == SmsCbMessage.MESSAGE_FORMAT_3GPP2) { + mPhone.mCi.setCdmaBroadcastActivation(activate, response); + } + } +} diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 6615c70509..ea7831d633 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -71,6 +71,7 @@ import android.telephony.Annotation.DataActivityType; import android.telephony.Annotation.RadioPowerState; import android.telephony.BarringInfo; import android.telephony.CarrierConfigManager; +import android.telephony.CellBroadcastIdRange; import android.telephony.CellIdentity; import android.telephony.ImsiEncryptionInfo; import android.telephony.LinkCapacityEstimate; @@ -237,6 +238,9 @@ public class GsmCdmaPhone extends Phone { private String mImeiSv; private String mVmNumber; + CellBroadcastConfigTracker mCellBroadcastConfigTracker = + CellBroadcastConfigTracker.make(this, null); + // Create Cfu (Call forward unconditional) so that dialing number & // mOnComplete (Message object passed by client) can be packed & // given as a single Cfu object as user data to RIL. @@ -4960,6 +4964,22 @@ public class GsmCdmaPhone extends Phone { return mIccSmsInterfaceManager.getInboundSmsHandler(is3gpp2); } + /** + * Return current cell broadcast ranges. + */ + public List getCellBroadcastIdRanges() { + return mCellBroadcastConfigTracker.getCellBroadcastIdRanges(); + } + + /** + * Set reception of cell broadcast messages with the list of the given ranges. + */ + @Override + public void setCellBroadcastIdRanges( + @NonNull List ranges, Consumer callback) { + mCellBroadcastConfigTracker.setCellBroadcastIdRanges(ranges, callback); + } + /** * The following function checks if supplementary service request is blocked due to FDN. * @param requestType request type associated with the supplementary service diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 98fbca1353..5bdcee3d94 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -46,6 +46,7 @@ import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.SrvccState; import android.telephony.CarrierConfigManager; import android.telephony.CarrierRestrictionRules; +import android.telephony.CellBroadcastIdRange; import android.telephony.CellIdentity; import android.telephony.CellInfo; import android.telephony.ClientRequestStats; @@ -5109,6 +5110,21 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.isN1ModeEnabled(result); } + /** + * Return current cell broadcast ranges. + */ + public List getCellBroadcastIdRanges() { + return new ArrayList<>(); + } + + /** + * Set reception of cell broadcast messages with the list of the given ranges. + */ + public void setCellBroadcastIdRanges( + @NonNull List ranges, Consumer callback) { + callback.accept(TelephonyManager.CELLBROADCAST_RESULT_UNSUPPORTED); + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo.java b/src/java/com/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo.java index b31df59151..24ee56dd5c 100644 --- a/src/java/com/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo.java +++ b/src/java/com/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo.java @@ -17,6 +17,8 @@ package com.android.internal.telephony.cdma; +import java.util.Objects; + /** * CdmaSmsBroadcastConfigInfo defines one configuration of Cdma Broadcast * Message to be received by the ME @@ -84,4 +86,22 @@ public class CdmaSmsBroadcastConfigInfo { mFromServiceCategory + ", " + mToServiceCategory + "] " + (isSelected() ? "ENABLED" : "DISABLED"); } + + @Override + public int hashCode() { + return Objects.hash(mFromServiceCategory, mToServiceCategory, mLanguage, mSelected); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof CdmaSmsBroadcastConfigInfo)) { + return false; + } + + CdmaSmsBroadcastConfigInfo other = (CdmaSmsBroadcastConfigInfo) obj; + + return mFromServiceCategory == other.mFromServiceCategory + && mToServiceCategory == other.mToServiceCategory + && mLanguage == other.mLanguage && mSelected == other.mSelected; + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 8a7398442c..33531f72fb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import static com.android.internal.telephony.CellBroadcastConfigTracker.mergeRangesAsNeeded; import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED; @@ -29,6 +30,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -62,12 +64,14 @@ import android.preference.PreferenceManager; import android.telecom.VideoProfile; import android.telephony.AccessNetworkConstants; import android.telephony.CarrierConfigManager; +import android.telephony.CellBroadcastIdRange; import android.telephony.CellIdentity; import android.telephony.CellIdentityCdma; import android.telephony.CellIdentityGsm; import android.telephony.LinkCapacityEstimate; import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; +import android.telephony.SmsCbMessage; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -78,6 +82,8 @@ import android.testing.TestableLooper; import androidx.test.filters.FlakyTest; +import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.test.SimulatedCommandsVerifier; @@ -103,6 +109,7 @@ import org.mockito.InOrder; import org.mockito.Mockito; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; @RunWith(AndroidTestingRunner.class) @@ -2182,4 +2189,373 @@ public class GsmCdmaPhoneTest extends TelephonyTest { Connection connection = mPhoneUT.dial("1234567890", dialArgs); verify(mImsPhone).dial(eq("1234567890"), any(PhoneInternalInterface.DialArgs.class)); } + + @Test + @SmallTest + public void testSetCellBroadcastIdRangesSuccess() throws Exception { + final int[][] channelValues = { + {0, 999}, {1000, 1003}, {1004, 0x0FFF}, {0x1000, 0x10FF}, {0x1100, 0x112F}, + {0x1130, 0x1900}, {0x1901, 0x9FFF}, {0xA000, 0xFFFE}, {0xFFFF, 0xFFFF}}; + List ranges = new ArrayList<>(); + for (int i = 0; i < channelValues.length; i++) { + ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + SmsCbMessage.MESSAGE_FORMAT_3GPP, i > 0 ? true : false)); + } + + List gsmConfigs = new ArrayList<>(); + gsmConfigs.add(new SmsBroadcastConfigInfo(0, 999, 0, 255, false)); + gsmConfigs.add(new SmsBroadcastConfigInfo(1000, 0xFFFF, 0, 255, true)); + + ArgumentCaptor gsmCaptor = ArgumentCaptor.forClass( + SmsBroadcastConfigInfo[].class); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + + mPhoneUT.mCi = mMockCi; + + mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELLBROADCAST_RESULT_SUCCESS == r)); + waitForMs(100); + + verify(mMockCi, times(1)).setGsmBroadcastConfig(gsmCaptor.capture(), msgCaptor.capture()); + List gsmArgs = Arrays.asList( + (SmsBroadcastConfigInfo[]) gsmCaptor.getValue()); + assertEquals(gsmConfigs, gsmArgs); + + Message msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(1)).setGsmBroadcastActivation(eq(true), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, never()).setCdmaBroadcastConfig(any(), any()); + verify(mMockCi, never()).setCdmaBroadcastActivation(anyBoolean(), any()); + + assertEquals(mPhoneUT.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); + + //Verify to set cdma config and activate, but no more for gsm as no change + for (int i = 0; i < channelValues.length; i++) { + ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + SmsCbMessage.MESSAGE_FORMAT_3GPP2, i > 0 ? true : false)); + } + List cdmaConfigs = new ArrayList<>(); + cdmaConfigs.add(new CdmaSmsBroadcastConfigInfo(0, 999, 1, false)); + cdmaConfigs.add(new CdmaSmsBroadcastConfigInfo(1000, 0xFFFF, 1, true)); + ArgumentCaptor cdmaCaptor = ArgumentCaptor.forClass( + CdmaSmsBroadcastConfigInfo[].class); + + mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELLBROADCAST_RESULT_SUCCESS == r)); + waitForMs(100); + + verify(mMockCi, times(1)).setGsmBroadcastConfig(any(), any()); + verify(mMockCi, times(1)).setCdmaBroadcastConfig(cdmaCaptor.capture(), msgCaptor.capture()); + List cdmaArgs = Arrays.asList( + (CdmaSmsBroadcastConfigInfo[]) cdmaCaptor.getValue()); + assertEquals(cdmaConfigs, cdmaArgs); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(1)).setGsmBroadcastActivation(anyBoolean(), any()); + verify(mMockCi, times(1)).setCdmaBroadcastActivation(eq(true), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + assertEquals(mPhoneUT.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); + + // Verify not to set cdma or gsm config as the config is not changed + mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELLBROADCAST_RESULT_SUCCESS == r)); + waitForMs(100); + + verify(mMockCi, times(1)).setCdmaBroadcastConfig(any(), any()); + verify(mMockCi, times(1)).setCdmaBroadcastActivation(anyBoolean(), any()); + verify(mMockCi, times(1)).setGsmBroadcastConfig(any(), any()); + verify(mMockCi, times(1)).setGsmBroadcastActivation(anyBoolean(), any()); + + assertEquals(mPhoneUT.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); + + // Verify to reset ranges with empty ranges list + mPhoneUT.setCellBroadcastIdRanges(new ArrayList<>(), r -> assertTrue( + TelephonyManager.CELLBROADCAST_RESULT_SUCCESS == r)); + + waitForMs(100); + + verify(mMockCi, times(2)).setGsmBroadcastConfig(gsmCaptor.capture(), msgCaptor.capture()); + assertEquals(0, ((SmsBroadcastConfigInfo[]) gsmCaptor.getValue()).length); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + // Verify to deavtivate gsm broadcast on empty ranges + verify(mMockCi, times(1)).setGsmBroadcastActivation(eq(false), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(2)).setCdmaBroadcastConfig(cdmaCaptor.capture(), msgCaptor.capture()); + assertEquals(0, ((CdmaSmsBroadcastConfigInfo[]) cdmaCaptor.getValue()).length); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + waitForMs(100); + + // Verify to deavtivate cdma broadcast on empty ranges + verify(mMockCi, times(1)).setCdmaBroadcastActivation(eq(false), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + waitForMs(100); + + assertTrue(mPhoneUT.getCellBroadcastIdRanges().isEmpty()); + + //Verify to set gsm and cdma config then activate again + mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELLBROADCAST_RESULT_SUCCESS == r)); + + waitForMs(100); + + verify(mMockCi, times(3)).setGsmBroadcastConfig(gsmCaptor.capture(), msgCaptor.capture()); + gsmArgs = Arrays.asList((SmsBroadcastConfigInfo[]) gsmCaptor.getValue()); + assertEquals(gsmConfigs, gsmArgs); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(2)).setGsmBroadcastActivation(eq(true), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(3)).setCdmaBroadcastConfig(cdmaCaptor.capture(), msgCaptor.capture()); + cdmaArgs = Arrays.asList((CdmaSmsBroadcastConfigInfo[]) cdmaCaptor.getValue()); + assertEquals(cdmaConfigs, cdmaArgs); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(2)).setCdmaBroadcastActivation(eq(true), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + assertEquals(mPhoneUT.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); + } + + @Test + @SmallTest + public void testSetCellBroadcastIdRangesFailure() throws Exception { + List ranges = new ArrayList<>(); + + // Verify to throw exception for invalid ranges + ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); + ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, false)); + + assertThrows(IllegalArgumentException.class, + () -> mPhoneUT.setCellBroadcastIdRanges(ranges, r -> {})); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + ranges.clear(); + ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); + ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP2, true)); + mPhoneUT.mCi = mMockCi; + + // Verify the result on setGsmBroadcastConfig failure + mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELLBROADCAST_RESULT_FAIL_CONFIG == r)); + waitForMs(100); + + verify(mMockCi, times(1)).setGsmBroadcastConfig(any(), msgCaptor.capture()); + + Message msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg).exception = new RuntimeException(); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(0)).setGsmBroadcastActivation(anyBoolean(), any()); + verify(mMockCi, times(0)).setCdmaBroadcastConfig(any(), any()); + verify(mMockCi, times(0)).setCdmaBroadcastActivation(anyBoolean(), any()); + assertTrue(mPhoneUT.getCellBroadcastIdRanges().isEmpty()); + + // Verify the result on setGsmBroadcastActivation failure + mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELLBROADCAST_RESULT_FAIL_ACTIVATION == r)); + waitForMs(100); + + verify(mMockCi, times(2)).setGsmBroadcastConfig(any(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(1)).setGsmBroadcastActivation(anyBoolean(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg).exception = new RuntimeException(); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(0)).setCdmaBroadcastConfig(any(), any()); + verify(mMockCi, times(0)).setCdmaBroadcastActivation(anyBoolean(), any()); + assertTrue(mPhoneUT.getCellBroadcastIdRanges().isEmpty()); + + // Verify the result on setCdmaBroadcastConfig failure + mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELLBROADCAST_RESULT_FAIL_CONFIG == r)); + waitForMs(100); + + verify(mMockCi, times(3)).setGsmBroadcastConfig(any(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(2)).setGsmBroadcastActivation(anyBoolean(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(1)).setCdmaBroadcastConfig(any(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg).exception = new RuntimeException(); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(0)).setCdmaBroadcastActivation(anyBoolean(), any()); + + List ranges3gpp = new ArrayList<>(); + ranges3gpp.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); + + assertEquals(mPhoneUT.getCellBroadcastIdRanges(), ranges3gpp); + + // Verify the result on setCdmaBroadcastActivation failure + mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELLBROADCAST_RESULT_FAIL_ACTIVATION == r)); + waitForMs(200); + + // Verify no more calls as there is no change of ranges for 3gpp + verify(mMockCi, times(3)).setGsmBroadcastConfig(any(), any()); + verify(mMockCi, times(2)).setGsmBroadcastActivation(anyBoolean(), any()); + verify(mMockCi, times(2)).setCdmaBroadcastConfig(any(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + waitForMs(100); + + verify(mMockCi, times(1)).setCdmaBroadcastActivation(anyBoolean(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg).exception = new RuntimeException(); + msg.sendToTarget(); + waitForMs(100); + + assertEquals(mPhoneUT.getCellBroadcastIdRanges(), ranges3gpp); + } + + @Test + @SmallTest + public void testMergeCellBroadcastIdRangesAsNeeded() { + final int[][] channelValues = { + {0, 999}, {1000, 1003}, {1004, 0x0FFF}, {0x1000, 0x10FF}, {0x1100, 0x112F}, + {0x1130, 0x1900}, {0x1901, 0x9FFF}, {0xA000, 0xFFFE}, {0xFFFF, 0xFFFF}}; + final int[] typeValues = { + SmsCbMessage.MESSAGE_FORMAT_3GPP, SmsCbMessage.MESSAGE_FORMAT_3GPP2}; + final boolean[] enabledValues = {true, false}; + + List ranges = new ArrayList<>(); + for (int i = 0; i < channelValues.length; i++) { + ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + typeValues[0], enabledValues[0])); + } + + ranges = mergeRangesAsNeeded(ranges); + + assertEquals(ranges.size(), 1); + assertEquals(ranges.get(0).getStartId(), channelValues[0][0]); + assertEquals(ranges.get(0).getEndId(), channelValues[channelValues.length - 1][0]); + + // Verify not to merge the ranges with different types. + ranges.clear(); + for (int i = 0; i < channelValues.length; i++) { + ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + typeValues[0], enabledValues[0])); + ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + typeValues[1], enabledValues[0])); + } + + ranges = mergeRangesAsNeeded(ranges); + + assertEquals(ranges.size(), 2); + assertEquals(ranges.get(0).getStartId(), channelValues[0][0]); + assertEquals(ranges.get(0).getEndId(), channelValues[channelValues.length - 1][0]); + assertEquals(ranges.get(1).getStartId(), channelValues[0][0]); + assertEquals(ranges.get(1).getEndId(), channelValues[channelValues.length - 1][0]); + assertTrue(ranges.get(0).getType() != ranges.get(1).getType()); + + // Verify to throw IllegalArgumentException if the same range is enabled and disabled + // in the range list. + final List ranges2 = new ArrayList<>(); + for (int i = 0; i < channelValues.length; i++) { + ranges2.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + typeValues[0], enabledValues[0])); + ranges2.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + typeValues[0], enabledValues[1])); + } + + assertThrows(IllegalArgumentException.class, () -> + mergeRangesAsNeeded(ranges2)); + } } -- GitLab From 10c7e08c17dd9e708c30008cc92fcf8438b55ad0 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 13 Dec 2022 06:34:00 +0000 Subject: [PATCH 272/656] Add imsRadioTech param to handleImsUnregistered Bug: 219242990 Bug: 260953481 Test: astest ImsRegistrationCallbackHelperTest Change-Id: If44ade51f508035e1a5fa68cead5d1e1449229bf --- .../internal/telephony/imsphone/ImsPhone.java | 18 ++++++-- .../ImsRegistrationCallbackHelper.java | 13 ++++-- .../telephony/ims/ImsRegistrationTests.java | 24 +++++++--- .../telephony/imsphone/ImsPhoneTest.java | 45 ++++++++++++++----- .../ImsRegistrationCallbackHelperTest.java | 22 ++++++++- 5 files changed, 96 insertions(+), 26 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index beaf1b96ce..809ee39278 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -303,6 +303,8 @@ public class ImsPhone extends ImsPhoneBase { private @ImsRegistrationImplBase.ImsRegistrationTech int mImsRegistrationTech = REGISTRATION_TECH_NONE; private @RegistrationManager.SuggestedAction int mImsRegistrationSuggestedAction; + private @ImsRegistrationImplBase.ImsRegistrationTech int mImsDeregistrationTech = + REGISTRATION_TECH_NONE; private int mImsRegistrationCapabilities; private boolean mNotifiedRegisteredState; @@ -2513,10 +2515,12 @@ public class ImsPhone extends ImsPhoneBase { @Override public void handleImsUnregistered(ImsReasonInfo imsReasonInfo, - @RegistrationManager.SuggestedAction int suggestedAction) { + @RegistrationManager.SuggestedAction int suggestedAction, + @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) { if (DBG) { logd("handleImsUnregistered: onImsMmTelDisconnected imsReasonInfo=" - + imsReasonInfo + ", suggestedAction=" + suggestedAction); + + imsReasonInfo + ", suggestedAction=" + suggestedAction + + ", disconnectedRadioTech=" + imsRadioTech); } mRegLocalLog.log("handleImsUnregistered: onImsMmTelDisconnected imsRadioTech=" + imsReasonInfo); @@ -2535,7 +2539,7 @@ public class ImsPhone extends ImsPhoneBase { } } updateImsRegistrationInfo(REGISTRATION_STATE_NOT_REGISTERED, - REGISTRATION_TECH_NONE, suggestedModemAction); + imsRadioTech, suggestedModemAction); } @Override @@ -2708,7 +2712,8 @@ public class ImsPhone extends ImsPhoneBase { if (regState == mImsRegistrationState) { if ((regState == REGISTRATION_STATE_REGISTERED && imsRadioTech == mImsRegistrationTech) || (regState == REGISTRATION_STATE_NOT_REGISTERED - && suggestedAction == mImsRegistrationSuggestedAction)) { + && suggestedAction == mImsRegistrationSuggestedAction + && imsRadioTech == mImsDeregistrationTech)) { // Filter duplicate notification. return; } @@ -2732,6 +2737,11 @@ public class ImsPhone extends ImsPhoneBase { mImsRegistrationState = regState; mImsRegistrationTech = imsRadioTech; mImsRegistrationSuggestedAction = suggestedAction; + if (regState == REGISTRATION_STATE_NOT_REGISTERED) { + mImsDeregistrationTech = imsRadioTech; + } else { + mImsDeregistrationTech = REGISTRATION_TECH_NONE; + } mImsRegistrationCapabilities = 0; // REGISTRATION_STATE_REGISTERED will be notified when the capability is updated. mNotifiedRegisteredState = false; diff --git a/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java b/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java index fae9e23222..9452e2a553 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelper.java @@ -23,6 +23,7 @@ import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RegistrationManager; import android.telephony.ims.aidl.IImsRegistrationCallback; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.Log; import java.util.concurrent.Executor; @@ -52,7 +53,8 @@ public class ImsRegistrationCallbackHelper { * Handle the callback when IMS is unregistered. */ void handleImsUnregistered(ImsReasonInfo imsReasonInfo, - @RegistrationManager.SuggestedAction int suggestedAction); + @RegistrationManager.SuggestedAction int suggestedAction, + @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech); /** * Handle the callback when the list of subscriber {@link Uri}s associated with this IMS @@ -81,14 +83,17 @@ public class ImsRegistrationCallbackHelper { @Override public void onUnregistered(ImsReasonInfo imsReasonInfo) { - onUnregistered(imsReasonInfo, RegistrationManager.SUGGESTED_ACTION_NONE); + onUnregistered(imsReasonInfo, RegistrationManager.SUGGESTED_ACTION_NONE, + ImsRegistrationImplBase.REGISTRATION_TECH_NONE); } @Override public void onUnregistered(ImsReasonInfo imsReasonInfo, - @RegistrationManager.SuggestedAction int suggestedAction) { + @RegistrationManager.SuggestedAction int suggestedAction, + @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) { updateRegistrationState(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED); - mImsRegistrationUpdate.handleImsUnregistered(imsReasonInfo, suggestedAction); + mImsRegistrationUpdate.handleImsUnregistered(imsReasonInfo, suggestedAction, + imsRadioTech); } @Override diff --git a/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java b/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java index 1ab4efed05..4a445fd075 100644 --- a/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java +++ b/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java @@ -16,6 +16,9 @@ package android.telephony.ims; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK; +import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; + import static junit.framework.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; @@ -148,7 +151,18 @@ public class ImsRegistrationTests { ImsReasonInfo info = new ImsReasonInfo(); mRegistration.onDeregistered(info); - verify(mCallback).onDeregistered(eq(info), anyInt()); + verify(mCallback).onDeregistered(eq(info), anyInt(), anyInt()); + } + + @SmallTest + @Test + public void testRegistrationCallbackOnDeregisteredWithSuggestedAction() throws RemoteException { + ImsReasonInfo info = new ImsReasonInfo(); + mRegistration.onDeregistered(info, + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK, REGISTRATION_TECH_LTE); + + verify(mCallback).onDeregistered(eq(info), + eq(SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK), eq(REGISTRATION_TECH_LTE)); } @SmallTest @@ -219,10 +233,10 @@ public class ImsRegistrationTests { // The original callback that has been registered should get LTE tech in disconnected // message - verify(mCallback).onDeregistered(eq(info), anyInt()); + verify(mCallback).onDeregistered(eq(info), anyInt(), anyInt()); // A callback that has just been registered should get NONE for tech in disconnected // message - verify(mCallback2).onDeregistered(eq(info), anyInt()); + verify(mCallback2).onDeregistered(eq(info), anyInt(), anyInt()); } @SmallTest @@ -232,7 +246,7 @@ public class ImsRegistrationTests { mRegistration.onDeregistered(info); - verify(mCallback).onDeregistered(eq(info), anyInt()); + verify(mCallback).onDeregistered(eq(info), anyInt(), anyInt()); assertEquals(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, mRegBinder.getRegistrationTechnology()); } @@ -243,7 +257,7 @@ public class ImsRegistrationTests { mRegBinder.addRegistrationCallback(mCallback2); // Verify that if we have never set the registration state, we do not callback immediately // with onUnregistered. - verify(mCallback2, never()).onDeregistered(any(ImsReasonInfo.class), anyInt()); + verify(mCallback2, never()).onDeregistered(any(ImsReasonInfo.class), anyInt(), anyInt()); } @SmallTest 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 468c5dd77b..6afd20c7c6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -28,7 +28,6 @@ import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_3G; 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 android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NR; import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; @@ -1306,11 +1305,27 @@ public class ImsPhoneTest extends TelephonyTest { ImsReasonInfo.CODE_UNSPECIFIED, ""); // unregistered with fatal error - registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK); + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK, REGISTRATION_TECH_NR); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED + && regInfo[1] == REGISTRATION_TECH_NR + && regInfo[2] == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK); + + // reset the registration info saved in the SimulatedCommands + mSimulatedCommands.updateImsRegistrationInfo(0, 0, 0, 0, null); + regInfo = mSimulatedCommands.getImsRegistrationInfo(); + + assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); + + // unregistered with fatal error but rat changed + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK, REGISTRATION_TECH_LTE); regInfo = mSimulatedCommands.getImsRegistrationInfo(); assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED - && regInfo[1] == REGISTRATION_TECH_NONE + && regInfo[1] == REGISTRATION_TECH_LTE && regInfo[2] == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK); // reset the registration info saved in the SimulatedCommands @@ -1320,7 +1335,8 @@ public class ImsPhoneTest extends TelephonyTest { assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); // duplicated notification with the same suggested action - registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK); + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK, REGISTRATION_TECH_LTE); regInfo = mSimulatedCommands.getImsRegistrationInfo(); // verify that there is no update in the SimulatedCommands @@ -1328,11 +1344,12 @@ public class ImsPhoneTest extends TelephonyTest { // unregistered with repeated error registrationCallback.onUnregistered(reasonInfo, - SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT); + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT, + REGISTRATION_TECH_LTE); regInfo = mSimulatedCommands.getImsRegistrationInfo(); assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED - && regInfo[1] == REGISTRATION_TECH_NONE + && regInfo[1] == REGISTRATION_TECH_LTE && regInfo[2] == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT); // reset the registration info saved in the SimulatedCommands @@ -1343,28 +1360,31 @@ public class ImsPhoneTest extends TelephonyTest { // duplicated notification with the same suggested action registrationCallback.onUnregistered(reasonInfo, - SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT); + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT, + REGISTRATION_TECH_LTE); regInfo = mSimulatedCommands.getImsRegistrationInfo(); // verify that there is no update in the SimulatedCommands assertTrue(regInfo[0] == 0 && regInfo[1] == 0 && regInfo[2] == 0); // unregistered with temporary error - registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_NONE); + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_NONE, REGISTRATION_TECH_LTE); regInfo = mSimulatedCommands.getImsRegistrationInfo(); assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED - && regInfo[1] == REGISTRATION_TECH_NONE + && regInfo[1] == REGISTRATION_TECH_LTE && regInfo[2] == SUGGESTED_ACTION_NONE); // verifies that reason codes except ImsReasonInfo.CODE_REGISTRATION_ERROR are discarded. reasonInfo = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NETWORK_NO_SERVICE, ImsReasonInfo.CODE_UNSPECIFIED, ""); - registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK); + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK, REGISTRATION_TECH_NR); regInfo = mSimulatedCommands.getImsRegistrationInfo(); assertTrue(regInfo[0] == RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED - && regInfo[1] == REGISTRATION_TECH_NONE + && regInfo[1] == REGISTRATION_TECH_NR && regInfo[2] == SUGGESTED_ACTION_NONE); // change the registration info saved in the SimulatedCommands @@ -1374,7 +1394,8 @@ public class ImsPhoneTest extends TelephonyTest { assertTrue(regInfo[0] == 1 && regInfo[1] == 1 && regInfo[2] == 1); // duplicated notification with the same suggested action - registrationCallback.onUnregistered(reasonInfo, SUGGESTED_ACTION_NONE); + registrationCallback.onUnregistered(reasonInfo, + SUGGESTED_ACTION_NONE, REGISTRATION_TECH_NR); regInfo = mSimulatedCommands.getImsRegistrationInfo(); // verify that there is no update in the SimulatedCommands diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java index 24efda6a89..93fbfdc194 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsRegistrationCallbackHelperTest.java @@ -17,6 +17,9 @@ package com.android.internal.telephony.imsphone; import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_NONE; +import static android.telephony.ims.RegistrationManager.SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK; +import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; +import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -166,7 +169,24 @@ public class ImsRegistrationCallbackHelperTest extends TelephonyTest { assertEquals(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED, mRegistrationCallbackHelper.getImsRegistrationState()); verify(mMockRegistrationUpdate).handleImsUnregistered(eq(reasonInfo), - eq(SUGGESTED_ACTION_NONE)); + eq(SUGGESTED_ACTION_NONE), eq(REGISTRATION_TECH_NONE)); + } + + @Test + @SmallTest + public void testImsUnRegisteredWithSuggestedAction() { + // Verify the RegistrationCallback should not be null + RegistrationCallback callback = mRegistrationCallbackHelper.getCallback(); + assertNotNull(callback); + + ImsReasonInfo reasonInfo = new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 0); + callback.onUnregistered(reasonInfo, SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK, + REGISTRATION_TECH_LTE); + + assertEquals(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED, + mRegistrationCallbackHelper.getImsRegistrationState()); + verify(mMockRegistrationUpdate).handleImsUnregistered(eq(reasonInfo), + eq(SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK), eq(REGISTRATION_TECH_LTE)); } @Test -- GitLab From c19f68c97d69ebdd50d4e85b03b17160c5ff6ccc Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Fri, 25 Nov 2022 01:59:52 +0000 Subject: [PATCH 273/656] Unable to accept incoming call when using main Executor in MmTelFeature Add new API notfyIncomingCall() which returns ImsCallSessionListener as blocking API to prevent deadlock Bug: 257554011 Test: atest ImsPhoneCallTrackerTest, E2E Call regression Test Change-Id: Ia19462dc733be23a72f283e71b6c5011f3f2c1b0 --- .../imsphone/ImsPhoneCallTracker.java | 54 ++++++++++++++----- .../telephony/ims/MmTelFeatureTests.java | 17 +++++- .../telephony/ims/TestMmTelFeature.java | 5 ++ .../imsphone/ImsPhoneCallTrackerTest.java | 12 ++--- 4 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 4fd41a9e39..97f84d1ff0 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -96,6 +96,7 @@ import android.telephony.ims.ProvisioningManager; import android.telephony.ims.RtpHeaderExtension; import android.telephony.ims.RtpHeaderExtensionType; import android.telephony.ims.SrvccCall; +import android.telephony.ims.aidl.IImsCallSessionListener; import android.telephony.ims.aidl.ISrvccStartedCallback; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.MmTelFeature; @@ -168,10 +169,12 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.function.Supplier; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -234,16 +237,18 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private final MmTelFeatureListener mMmTelFeatureListener = new MmTelFeatureListener(); private class MmTelFeatureListener extends MmTelFeature.Listener { - private void processIncomingCall(IImsCallSession c, Bundle extras) { + private IImsCallSessionListener processIncomingCall(@NonNull IImsCallSession c, + @Nullable String callId, @Nullable Bundle extras) { if (DBG) log("processIncomingCall: incoming call intent"); if (extras == null) extras = new Bundle(); - if (mImsManager == null) return; + if (mImsManager == null) return null; try { + IImsCallSessionListener iimsCallSessionListener; // Network initiated USSD will be treated by mImsUssdListener boolean isUssd = extras.getBoolean(MmTelFeature.EXTRA_IS_USSD, false); - // For compatibility purposes with older vendor implmentations. + // For compatibility purposes with older vendor implementations. isUssd |= extras.getBoolean(ImsManager.EXTRA_USSD, false); if (isUssd) { if (DBG) log("processIncomingCall: USSD"); @@ -252,11 +257,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { if (mUssdSession != null) { mUssdSession.accept(ImsCallProfile.CALL_TYPE_VOICE); } - return; + if (callId != null) mUssdSession.getCallSession().setCallId(callId); + iimsCallSessionListener = (IImsCallSessionListener) mUssdSession + .getCallSession().getIImsCallSessionListenerProxy(); + return iimsCallSessionListener; } boolean isUnknown = extras.getBoolean(MmTelFeature.EXTRA_IS_UNKNOWN_CALL, false); - // For compatibility purposes with older vendor implmentations. + // For compatibility purposes with older vendor implementations. isUnknown |= extras.getBoolean(ImsManager.EXTRA_IS_UNKNOWN_CALL, false); if (DBG) { log("processIncomingCall: isUnknown = " + isUnknown @@ -266,6 +274,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // Normal MT/Unknown call ImsCall imsCall = mImsManager.takeCall(c, mImsCallListener); + if (callId != null) imsCall.getCallSession().setCallId(callId); + iimsCallSessionListener = (IImsCallSessionListener) imsCall + .getCallSession().getIImsCallSessionListenerProxy(); ImsPhoneConnection conn = new ImsPhoneConnection(mPhone, imsCall, ImsPhoneCallTracker.this, (isUnknown ? mForegroundCall : mRingingCall), isUnknown); @@ -288,13 +299,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { if ((c != null) && (c.getCallProfile() != null) && (c.getCallProfile().getCallExtras() != null) && (c.getCallProfile().getCallExtras() - .containsKey(ImsCallProfile.EXTRA_CALL_DISCONNECT_CAUSE))) { + .containsKey(ImsCallProfile.EXTRA_CALL_DISCONNECT_CAUSE))) { String error = c.getCallProfile() .getCallExtra(ImsCallProfile.EXTRA_CALL_DISCONNECT_CAUSE, null); if (error != null) { try { int cause = getDisconnectCauseFromReasonInfo( - new ImsReasonInfo(Integer.parseInt(error), 0, null), + new ImsReasonInfo(Integer.parseInt(error), 0, null), conn.getState()); if (cause == DisconnectCause.INCOMING_AUTO_REJECTED) { conn.setDisconnectCause(cause); @@ -340,18 +351,19 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); mImsCallInfoTracker.addImsCallStatus(conn); + return iimsCallSessionListener; } catch (ImsException | RemoteException e) { loge("processIncomingCall: exception " + e); mOperationLocalLog.log("onIncomingCall: exception processing: " + e); + return null; } } @Override - public void onIncomingCall(IImsCallSession c, Bundle extras) { - // we want to ensure we block this binder thread until incoming call setup completes - // as to avoid race conditions where the ImsService tries to update the state of the - // call before the listeners have been attached. - executeAndWait(()-> processIncomingCall(c, extras)); + @Nullable + public IImsCallSessionListener onIncomingCall( + @NonNull IImsCallSession c, @Nullable String callId, @Nullable Bundle extras) { + return executeAndWaitForReturn(()-> processIncomingCall(c, callId, extras)); } @Override @@ -413,6 +425,24 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { logw("Binder - exception: " + e.getMessage()); } } + + /** + * Schedule the given Runnable on mExecutor and block this thread until it finishes. + * @param r The Runnable to run. + */ + private T executeAndWaitForReturn(Supplier r) { + + CompletableFuture future = CompletableFuture.supplyAsync( + () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor); + + try { + return future.get(); + } catch (ExecutionException | InterruptedException e) { + Log.w(LOG_TAG, "ImsPhoneCallTracker : executeAndWaitForReturn exception: " + + e.getMessage()); + return null; + } + } } /** diff --git a/tests/telephonytests/src/android/telephony/ims/MmTelFeatureTests.java b/tests/telephonytests/src/android/telephony/ims/MmTelFeatureTests.java index 5af871c324..b002b359f3 100644 --- a/tests/telephonytests/src/android/telephony/ims/MmTelFeatureTests.java +++ b/tests/telephonytests/src/android/telephony/ims/MmTelFeatureTests.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.net.Uri; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -151,11 +152,25 @@ public class MmTelFeatureTests extends ImsTestBase { mFeature.incomingCall(session); ArgumentCaptor captor = ArgumentCaptor.forClass(IImsCallSession.class); - verify(mListener).onIncomingCall(captor.capture(), any()); + verify(mListener).onIncomingCall(captor.capture(), eq(null), any()); assertEquals(sessionBinder, captor.getValue()); } + @SmallTest + @Test + public void testNewIncomingCallReturnListener() throws Exception { + IImsCallSession sessionBinder = Mockito.mock(IImsCallSession.class); + ImsCallSessionImplBase session = new ImsCallSessionImplBase(); + session.setServiceImpl(sessionBinder); + String callId = "callID"; + Bundle extra = new Bundle(); + mFeature.incomingCall(session, callId, extra); + ArgumentCaptor captor = ArgumentCaptor.forClass(IImsCallSession.class); + verify(mListener).onIncomingCall(captor.capture(), eq(callId), eq(extra)); + assertEquals(sessionBinder, captor.getValue()); + } + @SmallTest @Test public void testSetTtyMessageMessenger() throws Exception { diff --git a/tests/telephonytests/src/android/telephony/ims/TestMmTelFeature.java b/tests/telephonytests/src/android/telephony/ims/TestMmTelFeature.java index 9ee1e30b70..1269cc8904 100644 --- a/tests/telephonytests/src/android/telephony/ims/TestMmTelFeature.java +++ b/tests/telephonytests/src/android/telephony/ims/TestMmTelFeature.java @@ -64,6 +64,11 @@ public class TestMmTelFeature extends MmTelFeature { notifyIncomingCall(c, new Bundle()); } + public ImsCallSessionListener incomingCall( + ImsCallSessionImplBase c, String callId, Bundle extra) { + return notifyIncomingCall(c, callId, extra); + } + @Override public ImsCallProfile createCallProfile(int callSessionType, int callType) { return super.createCallProfile(callSessionType, callType); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 57ddb113ab..6aa0cd6a09 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -556,7 +556,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); assertFalse(mCTUT.mRingingCall.isRinging()); // mock a MT call - mMmTelListener.onIncomingCall(mock(IImsCallSession.class), Bundle.EMPTY); + mMmTelListener.onIncomingCall(mock(IImsCallSession.class), null, Bundle.EMPTY); verify(mImsPhone, times(1)).notifyNewRingingConnection((Connection) any()); verify(mImsPhone, times(1)).notifyIncomingRing(); assertEquals(PhoneConstants.State.RINGING, mCTUT.getState()); @@ -708,7 +708,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { ex.printStackTrace(); Assert.fail("unexpected exception thrown" + ex.getMessage()); } - mMmTelListener.onIncomingCall(mock(IImsCallSession.class), Bundle.EMPTY); + mMmTelListener.onIncomingCall(mock(IImsCallSession.class), null, Bundle.EMPTY); verify(mImsPhone, times(2)).notifyNewRingingConnection((Connection) any()); verify(mImsPhone, times(2)).notifyIncomingRing(); @@ -746,7 +746,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { ex.printStackTrace(); Assert.fail("unexpected exception thrown" + ex.getMessage()); } - mMmTelListener.onIncomingCall(mock(IImsCallSession.class), Bundle.EMPTY); + mMmTelListener.onIncomingCall(mock(IImsCallSession.class), null, Bundle.EMPTY); verify(mImsPhone, times(2)).notifyNewRingingConnection((Connection) any()); verify(mImsPhone, times(2)).notifyIncomingRing(); @@ -938,7 +938,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { try { doReturn(mSecondImsCall).when(mImsManager).takeCall(any(IImsCallSession.class), any(ImsCall.Listener.class)); - mMmTelListener.onIncomingCall(mock(IImsCallSession.class), Bundle.EMPTY); + mMmTelListener.onIncomingCall(mock(IImsCallSession.class), null, Bundle.EMPTY); mCTUT.acceptCall(ImsCallProfile.CALL_TYPE_VOICE); } catch (Exception ex) { ex.printStackTrace(); @@ -1756,7 +1756,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); assertFalse(mCTUT.mRingingCall.isRinging()); // mock a MT call - mMmTelListener.onIncomingCall(mock(IImsCallSession.class), Bundle.EMPTY); + mMmTelListener.onIncomingCall(mock(IImsCallSession.class), null, Bundle.EMPTY); verify(mImsPhone, times(1)).notifyNewRingingConnection((Connection) any()); verify(mImsPhone, times(1)).notifyIncomingRing(); assertEquals(PhoneConstants.State.RINGING, mCTUT.getState()); @@ -1794,7 +1794,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { assertEquals(PhoneConstants.State.IDLE, mCTUT.getState()); assertFalse(mCTUT.mRingingCall.isRinging()); // mock a MT call - mMmTelListener.onIncomingCall(mock(IImsCallSession.class), Bundle.EMPTY); + mMmTelListener.onIncomingCall(mock(IImsCallSession.class), null, Bundle.EMPTY); verify(mImsPhone, times(1)).notifyNewRingingConnection((Connection) any()); verify(mImsPhone, times(1)).notifyIncomingRing(); assertEquals(PhoneConstants.State.RINGING, mCTUT.getState()); -- GitLab From d8d3ed41243ba1fc4b5a5a2a6e30be3f6a404a9d Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 5 Aug 2022 09:12:03 -0700 Subject: [PATCH 274/656] Removed IWLAN legacy mode support Fix: 241716913 Test: Manual Change-Id: I8b5d53dc913a46a18093b865bd4fc12eed20d711 --- .../telephony/ServiceStateTracker.java | 65 ++--------- .../telephony/data/AccessNetworksManager.java | 105 +++--------------- .../internal/telephony/data/DataNetwork.java | 5 +- .../telephony/data/DataNetworkController.java | 20 ++-- .../telephony/data/DataRetryManager.java | 7 +- .../internal/telephony/imsphone/ImsPhone.java | 42 +------ .../internal/telephony/TelephonyTest.java | 3 - .../data/AccessNetworksManagerTest.java | 3 +- .../telephony/imsphone/ImsPhoneTest.java | 79 ------------- 9 files changed, 45 insertions(+), 284 deletions(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 1df84da4ac..bb291c5e32 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -665,7 +665,7 @@ public class ServiceStateTracker extends Handler { mAccessNetworksManager = mPhone.getAccessNetworksManager(); mOutOfServiceSS = new ServiceState(); - mOutOfServiceSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); + mOutOfServiceSS.setOutOfService(false); for (int transportType : mAccessNetworksManager.getAvailableTransports()) { mRegStateManagers.append(transportType, new NetworkRegistrationManager( @@ -766,9 +766,9 @@ public class ServiceStateTracker extends Handler { } mSS = new ServiceState(); - mSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); + mSS.setOutOfService(false); mNewSS = new ServiceState(); - mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); + mNewSS.setOutOfService(false); mLastCellInfoReqTime = 0; mLastCellInfoList = null; mStartedGprsRegCheck = false; @@ -3300,7 +3300,7 @@ public class ServiceStateTracker extends Handler { nri = mNewSS.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); + mNewSS.setOutOfService(false); // Add the IWLAN registration info back to service state. if (nri != null) { mNewSS.addNetworkRegistrationInfo(nri); @@ -3317,7 +3317,7 @@ public class ServiceStateTracker extends Handler { nri = mNewSS.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), true); + mNewSS.setOutOfService(true); // Add the IWLAN registration info back to service state. if (nri != null) { mNewSS.addNetworkRegistrationInfo(nri); @@ -3444,14 +3444,10 @@ public class ServiceStateTracker extends Handler { mSS.getState() == ServiceState.STATE_POWER_OFF && mNewSS.getState() != ServiceState.STATE_POWER_OFF; - SparseBooleanArray hasDataAttached = new SparseBooleanArray( - mAccessNetworksManager.getAvailableTransports().length); - SparseBooleanArray hasDataDetached = new SparseBooleanArray( - mAccessNetworksManager.getAvailableTransports().length); - SparseBooleanArray hasRilDataRadioTechnologyChanged = new SparseBooleanArray( - mAccessNetworksManager.getAvailableTransports().length); - SparseBooleanArray hasDataRegStateChanged = new SparseBooleanArray( - mAccessNetworksManager.getAvailableTransports().length); + SparseBooleanArray hasDataAttached = new SparseBooleanArray(); + SparseBooleanArray hasDataDetached = new SparseBooleanArray(); + SparseBooleanArray hasRilDataRadioTechnologyChanged = new SparseBooleanArray(); + SparseBooleanArray hasDataRegStateChanged = new SparseBooleanArray(); boolean anyDataRegChanged = false; boolean anyDataRatChanged = false; boolean hasAlphaRawChanged = @@ -3640,7 +3636,7 @@ public class ServiceStateTracker extends Handler { ServiceState oldMergedSS = new ServiceState(mPhone.getServiceState()); mSS = new ServiceState(mNewSS); - mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), false); + mNewSS.setOutOfService(false); mCellIdentity = primaryCellIdentity; if (mSS.getState() == ServiceState.STATE_IN_SERVICE && primaryCellIdentity != null) { @@ -5513,8 +5509,7 @@ public class ServiceStateTracker extends Handler { } /** - * This method adds IWLAN registration info for legacy mode devices camped on IWLAN. It also - * makes some adjustments when the device camps on IWLAN in airplane mode. + * This method makes some adjustments when the device camps on IWLAN in airplane mode. */ private void processIwlanRegistrationInfo() { if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF) { @@ -5528,7 +5523,7 @@ public class ServiceStateTracker extends Handler { } // operator info should be kept in SS String operator = mNewSS.getOperatorAlphaLong(); - mNewSS.setOutOfService(mAccessNetworksManager.isInLegacyMode(), true); + mNewSS.setOutOfService(true); if (resetIwlanRatVal) { mNewSS.setDataRegState(ServiceState.STATE_IN_SERVICE); NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() @@ -5538,17 +5533,6 @@ public class ServiceStateTracker extends Handler { .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) .build(); mNewSS.addNetworkRegistrationInfo(nri); - if (mAccessNetworksManager.isInLegacyMode()) { - // If in legacy mode, simulate the behavior that IWLAN registration info - // is reported through WWAN transport. - nri = new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .build(); - mNewSS.addNetworkRegistrationInfo(nri); - } mNewSS.setOperatorAlphaLong(operator); // Since it's in airplane mode, cellular must be out of service. The only possible // transport for data to go through is the IWLAN transport. Setting this to true @@ -5558,31 +5542,6 @@ public class ServiceStateTracker extends Handler { } return; } - - // If the device operates in legacy mode and camps on IWLAN, modem reports IWLAN as a RAT - // through WWAN registration info. To be consistent with the behavior with AP-assisted mode, - // we manually make a WLAN registration info for clients to consume. In this scenario, - // both WWAN and WLAN registration info are the IWLAN registration info and that's the - // unfortunate limitation we have when the device operates in legacy mode. In AP-assisted - // mode, the WWAN registration will correctly report the actual cellular registration info - // when the device camps on IWLAN. - if (mAccessNetworksManager.isInLegacyMode()) { - NetworkRegistrationInfo wwanNri = mNewSS.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - if (wwanNri != null && wwanNri.getAccessNetworkTechnology() - == TelephonyManager.NETWORK_TYPE_IWLAN) { - NetworkRegistrationInfo wlanNri = new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .setRegistrationState(wwanNri.getInitialRegistrationState()) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRejectCause(wwanNri.getRejectCause()) - .setEmergencyOnly(wwanNri.isEmergencyEnabled()) - .setAvailableServices(wwanNri.getAvailableServices()) - .build(); - mNewSS.addNetworkRegistrationInfo(wlanNri); - } - } } /** diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index 66996f4755..d51f586932 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -16,12 +16,9 @@ package com.android.internal.telephony.data; -import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; - import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.StringDef; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -36,7 +33,6 @@ import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; -import android.os.SystemProperties; import android.os.UserHandle; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; @@ -58,14 +54,11 @@ import android.util.LocalLog; import android.util.SparseArray; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.RIL; import com.android.internal.telephony.SlidingWindowEventCounter; import com.android.telephony.Rlog; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -83,35 +76,6 @@ import java.util.stream.Collectors; */ public class AccessNetworksManager extends Handler { private static final boolean DBG = false; - public static final String SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE = - "ro.telephony.iwlan_operation_mode"; - - @Retention(RetentionPolicy.SOURCE) - @StringDef(prefix = {"IWLAN_OPERATION_MODE_"}, - value = { - IWLAN_OPERATION_MODE_DEFAULT, - IWLAN_OPERATION_MODE_LEGACY, - IWLAN_OPERATION_MODE_AP_ASSISTED}) - public @interface IwlanOperationMode {} - - /** - * IWLAN default mode. On device that has IRadio 1.4 or above, it means - * {@link #IWLAN_OPERATION_MODE_AP_ASSISTED}. On device that has IRadio 1.3 or below, it means - * {@link #IWLAN_OPERATION_MODE_LEGACY}. - */ - public static final String IWLAN_OPERATION_MODE_DEFAULT = "default"; - - /** - * IWLAN legacy mode. IWLAN is completely handled by the modem, and when the device is on - * IWLAN, modem reports IWLAN as a RAT. - */ - public static final String IWLAN_OPERATION_MODE_LEGACY = "legacy"; - - /** - * IWLAN application processor assisted mode. IWLAN is handled by the bound IWLAN data service - * and network service separately. - */ - public static final String IWLAN_OPERATION_MODE_AP_ASSISTED = "AP-assisted"; /** * The counters to detect frequent QNS attempt to change preferred network transport by ApnType. @@ -368,28 +332,19 @@ public class AccessNetworksManager extends Handler { Context.CARRIER_CONFIG_SERVICE); mLogTag = "ANM-" + mPhone.getPhoneId(); mApnTypeToQnsChangeNetworkCounter = new SparseArray<>(); - - if (isInLegacyMode()) { - log("operates in legacy mode."); - // For legacy mode, WWAN is the only transport to handle all data connections, even - // the IWLAN ones. - mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN}; - } else { - log("operates in AP-assisted mode."); - mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - try { - Context contextAsUser = phone.getContext().createPackageContextAsUser( - phone.getContext().getPackageName(), 0, UserHandle.ALL); - contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter, - null /* broadcastPermission */, null); - } catch (PackageManager.NameNotFoundException e) { - loge("Package name not found: ", e); - } - bindQualifiedNetworksService(); + mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + try { + Context contextAsUser = phone.getContext().createPackageContextAsUser( + phone.getContext().getPackageName(), 0, UserHandle.ALL); + contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter, + null /* broadcastPermission */, null); + } catch (PackageManager.NameNotFoundException e) { + loge("Package name not found: ", e); } + bindQualifiedNetworksService(); // Using post to delay the registering because data retry manager and data config // manager instances are created later than access networks manager. @@ -492,8 +447,7 @@ public class AccessNetworksManager extends Handler { /** * Get the qualified network service package. * - * @return package name of the qualified networks service package. Return empty string when in - * legacy mode (i.e. Dedicated IWLAN data/network service is not supported). + * @return package name of the qualified networks service package. */ private String getQualifiedNetworksServicePackageName() { // Read package name from the resource @@ -570,30 +524,9 @@ public class AccessNetworksManager extends Handler { } /** - * @return {@code true} if the device operates in legacy mode, otherwise {@code false}. + * @return The available transports. */ - public boolean isInLegacyMode() { - // Get IWLAN operation mode from the system property. If the system property is configured - // to default or not configured, the mode is tied to IRadio version. For 1.4 or above, it's - // AP-assisted mode, for 1.3 or below, it's legacy mode. - String mode = SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE); - - if (mode.equals(IWLAN_OPERATION_MODE_AP_ASSISTED)) { - return false; - } else if (mode.equals(IWLAN_OPERATION_MODE_LEGACY)) { - return true; - } - - return mPhone.getHalVersion(HAL_SERVICE_DATA).less(RIL.RADIO_HAL_VERSION_1_4); - } - - /** - * @return The available transports. Note that on legacy devices, the only available transport - * would be WWAN only. If the device is configured as AP-assisted mode, the available transport - * will always be WWAN and WLAN (even if the device is not camped on IWLAN). - * See {@link #isInLegacyMode()} for mode details. - */ - public synchronized @NonNull int[] getAvailableTransports() { + public @NonNull int[] getAvailableTransports() { return mAvailableTransports; } @@ -628,11 +561,6 @@ public class AccessNetworksManager extends Handler { * @return The preferred transport. */ public @TransportType int getPreferredTransport(@ApnType int apnType) { - // In legacy mode, always preferred on cellular. - if (isInLegacyMode()) { - return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; - } - return mPreferredTransports.get(apnType) == null ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mPreferredTransports.get(apnType); } @@ -735,9 +663,6 @@ public class AccessNetworksManager extends Handler { } pw.decreaseIndent(); - pw.println("isInLegacy=" + isInLegacyMode()); - pw.println("IWLAN operation mode=" - + SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE)); pw.println("Local logs="); pw.increaseIndent(); mLocalLog.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index cd855ff3a7..9797fef3bb 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -898,8 +898,9 @@ public class DataNetwork extends StateMachine { mDataAllowedReason = dataAllowedReason; dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); mAttachedNetworkRequestList.addAll(networkRequestList); - mCid.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, INVALID_CID); - mCid.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, INVALID_CID); + for (int transportType : mAccessNetworksManager.getAvailableTransports()) { + mCid.put(transportType, INVALID_CID); + } mTcpBufferSizes = mDataConfigManager.getDefaultTcpConfigString(); mTelephonyDisplayInfo = mPhone.getDisplayInfoController().getTelephonyDisplayInfo(); diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 6e8f4ada42..440ee5ab76 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -780,13 +780,11 @@ public class DataNetworkController extends Handler { log("DataNetworkController created."); mAccessNetworksManager = phone.getAccessNetworksManager(); - mDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - new DataServiceManager(mPhone, looper, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); - if (!mAccessNetworksManager.isInLegacyMode()) { - mDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, - new DataServiceManager(mPhone, looper, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN)); + for (int transport : mAccessNetworksManager.getAvailableTransports()) { + mDataServiceManagers.put(transport, new DataServiceManager(mPhone, looper, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); } + mDataConfigManager = new DataConfigManager(mPhone, looper); // ========== Anomaly counters ========== @@ -989,12 +987,10 @@ public class DataNetworkController extends Handler { mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) .registerForServiceBindingChanged(this, EVENT_DATA_SERVICE_BINDING_CHANGED); - if (!mAccessNetworksManager.isInLegacyMode()) { - mPhone.getServiceStateTracker().registerForServiceStateChanged(this, - EVENT_SERVICE_STATE_CHANGED, null); - mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .registerForServiceBindingChanged(this, EVENT_DATA_SERVICE_BINDING_CHANGED); - } + mPhone.getServiceStateTracker().registerForServiceStateChanged(this, + EVENT_SERVICE_STATE_CHANGED, null); + mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + .registerForServiceBindingChanged(this, EVENT_DATA_SERVICE_BINDING_CHANGED); mPhone.getContext().getSystemService(TelephonyRegistryManager.class) .addOnSubscriptionsChangedListener(new OnSubscriptionsChangedListener() { diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index 0beea1fdb3..c2b3b9ae3b 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -958,10 +958,9 @@ public class DataRetryManager extends Handler { DataRetryManager.this.onCarrierConfigUpdated(); } }); - mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .registerForApnUnthrottled(this, EVENT_DATA_PROFILE_UNTHROTTLED); - if (!mPhone.getAccessNetworksManager().isInLegacyMode()) { - mDataServiceManagers.get(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) + + for (int transport : mPhone.getAccessNetworksManager().getAvailableTransports()) { + mDataServiceManagers.get(transport) .registerForApnUnthrottled(this, EVENT_DATA_PROFILE_UNTHROTTLED); } mDataProfileManager.registerCallback(new DataProfileManagerCallback(this::post) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 622cfc354b..d3dc720d6a 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -475,11 +475,7 @@ public class ImsPhone extends ImsPhoneBase { mCT.registerPhoneStateListener(mExternalCallTracker); mExternalCallTracker.setCallPuller(mCT); - boolean legacyMode = true; - if (mDefaultPhone.getAccessNetworksManager() != null) { - legacyMode = mDefaultPhone.getAccessNetworksManager().isInLegacyMode(); - } - mSS.setOutOfService(legacyMode, false); + mSS.setOutOfService(false); mPhoneId = mDefaultPhone.getPhoneId(); @@ -2388,7 +2384,7 @@ public class ImsPhone extends ImsPhoneBase { /** * Update roaming state and WFC mode in the following situations: * 1) voice is in service. - * 2) data is in service and it is not IWLAN (if in legacy mode). + * 2) data is in service. * @param ss non-null ServiceState */ private void updateRoamingState(ServiceState ss) { @@ -2409,15 +2405,7 @@ public class ImsPhone extends ImsPhoneBase { logi("updateRoamingState: we are not IN_SERVICE, ignoring roaming change."); return; } - // We ignore roaming changes when moving to IWLAN because it always sets the roaming - // mode to home and masks the actual cellular roaming status if voice is not registered. If - // we just moved to IWLAN because WFC roaming mode is IWLAN preferred and WFC home mode is - // cell preferred, we can get into a condition where the modem keeps bouncing between - // IWLAN->cell->IWLAN->cell... - if (isCsNotInServiceAndPsWwanReportingWlan(ss)) { - logi("updateRoamingState: IWLAN masking roaming, ignore roaming change."); - return; - } + if (mCT.getState() == PhoneConstants.State.IDLE) { if (DBG) logd("updateRoamingState now: " + newRoamingState); mLastKnownRoamingState = newRoamingState; @@ -2436,30 +2424,6 @@ public class ImsPhone extends ImsPhoneBase { } } - /** - * In legacy mode, data registration will report IWLAN when we are using WLAN for data, - * effectively masking the true roaming state of the device if voice is not registered. - * - * @return true if we are reporting not in service for CS domain over WWAN transport and WLAN - * for PS domain over WWAN transport. - */ - private boolean isCsNotInServiceAndPsWwanReportingWlan(ServiceState ss) { - // We can not get into this condition if we are in AP-Assisted mode. - if (mDefaultPhone.getAccessNetworksManager() == null - || !mDefaultPhone.getAccessNetworksManager().isInLegacyMode()) { - return false; - } - NetworkRegistrationInfo csInfo = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - NetworkRegistrationInfo psInfo = ss.getNetworkRegistrationInfo( - NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); - // We will return roaming state correctly if the CS domain is in service because - // ss.getRoaming() returns isVoiceRoaming||isDataRoaming result and isDataRoaming==false - // when the modem reports IWLAN RAT. - return psInfo != null && csInfo != null && !csInfo.isInService() - && psInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN; - } - public RegistrationManager.RegistrationCallback getImsMmTelRegistrationCallback() { return mImsMmTelRegistrationHelper.getCallback(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 93c671ea9b..967c7817cf 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -716,9 +716,6 @@ public abstract class TelephonyTest { mServiceManagerMockedServices.put("package", mMockPackageManager); mServiceManagerMockedServices.put("legacy_permission", mMockLegacyPermissionManager); logd("mMockLegacyPermissionManager replaced"); - doReturn(new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) - .when(mAccessNetworksManager).getAvailableTransports(); doReturn(new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) .when(mAccessNetworksManager).getAvailableTransports(); 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 c8eee8c7a6..4c4333cde2 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java @@ -18,7 +18,6 @@ package com.android.internal.telephony.data; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -113,7 +112,7 @@ public class AccessNetworksManagerTest extends TelephonyTest { processAllMessages(); replaceInstance(AccessNetworksManager.class, "mDataConfigManager", mAccessNetworksManager, mMockedDataConfigManager); - assumeFalse(mAccessNetworksManager.isInLegacyMode()); + logd("-setUp"); } 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 468c5dd77b..c3ccc925c0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -746,7 +746,6 @@ public class ImsPhoneTest extends TelephonyTest { @Test @SmallTest public void testRoamingToAirplanModeIwlanInService() throws Exception { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); doReturn(true).when(mPhone).isRadioOn(); @@ -774,7 +773,6 @@ public class ImsPhoneTest extends TelephonyTest { @Test @SmallTest public void testRoamingToOutOfService() throws Exception { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); doReturn(true).when(mPhone).isRadioOn(); @@ -797,83 +795,6 @@ public class ImsPhoneTest extends TelephonyTest { verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean()); } - @Test - @SmallTest - public void testRoamingChangeForLteInLegacyMode() throws Exception { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); - doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); - doReturn(true).when(mPhone).isRadioOn(); - - //roaming - data registration only on LTE - Message m = getServiceStateChangedMessage(getServiceStateDataOnly( - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true)); - // Inject the message synchronously instead of waiting for the thread to do it. - mImsPhoneUT.handleMessage(m); - m.recycle(); - - verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true)); - - // not roaming - data registration on LTE - m = getServiceStateChangedMessage(getServiceStateDataOnly( - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, false)); - mImsPhoneUT.handleMessage(m); - m.recycle(); - - verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(false)); - } - - @Test - @SmallTest - public void testDataOnlyRoamingCellToIWlanInLegacyMode() throws Exception { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); - doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); - doReturn(true).when(mPhone).isRadioOn(); - - //roaming - data registration only on LTE - Message m = getServiceStateChangedMessage(getServiceStateDataOnly( - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true)); - // Inject the message synchronously instead of waiting for the thread to do it. - mImsPhoneUT.handleMessage(m); - m.recycle(); - - verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true)); - - // not roaming - data registration onto IWLAN - m = getServiceStateChangedMessage(getServiceStateDataOnly( - ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, ServiceState.STATE_IN_SERVICE, false)); - mImsPhoneUT.handleMessage(m); - m.recycle(); - - // Verify that it hasn't been called again. - verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean()); - } - - @Test - @SmallTest - public void testCellVoiceDataChangeToWlanInLegacyMode() throws Exception { - doReturn(true).when(mAccessNetworksManager).isInLegacyMode(); - doReturn(PhoneConstants.State.IDLE).when(mImsCT).getState(); - doReturn(true).when(mPhone).isRadioOn(); - - //roaming - voice/data registration on LTE - ServiceState ss = getServiceStateDataAndVoice( - ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.STATE_IN_SERVICE, true); - Message m = getServiceStateChangedMessage(ss); - // Inject the message synchronously instead of waiting for the thread to do it. - mImsPhoneUT.handleMessage(m); - - verify(mImsManager, times(1)).setWfcMode(anyInt(), eq(true)); - - // roaming - voice LTE, data registration onto IWLAN - modifyServiceStateData(ss, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, - ServiceState.STATE_IN_SERVICE, false); - mImsPhoneUT.handleMessage(m); - m.recycle(); - - // Verify that it hasn't been called again. - verify(mImsManager, times(1)).setWfcMode(anyInt(), anyBoolean()); - } - @Test public void testNonNullTrackersInImsPhone() throws Exception { assertNotNull(mImsPhoneUT.getEmergencyNumberTracker()); -- GitLab From c226db005221530aaac403a6962b13abbb3e1bc6 Mon Sep 17 00:00:00 2001 From: Willy Hu Date: Wed, 14 Dec 2022 14:25:29 +0800 Subject: [PATCH 275/656] Add metrics for data stall recovery enhancement MDR: https://eldar.corp.google.com/assessments/296451350/drafts/988759905?jsmode=o Bug: 262382363 Test: atest DataStallRecoveryManagerTest passed Change-Id: I173e936315c9976a4dcbc592273e74388233f90b --- .../data/DataStallRecoveryManager.java | 54 ++++++++++++------- .../metrics/DataStallRecoveryStats.java | 22 +++++++- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index d03e1a1828..6632c67cb3 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -592,39 +592,55 @@ public class DataStallRecoveryManager extends Handler { * @param isValid true for validation passed & false for validation failed */ private void setNetworkValidationState(boolean isValid) { + boolean isLogNeeded = false; + int timeDuration = 0; + boolean isFirstDataStall = false; + boolean isFirstValidationAfterDoRecovery = false; + @RecoveredReason int reason = getRecoveredReason(isValid); // Validation status is true and was not data stall. if (isValid && !mDataStalled) { return; } if (!mDataStalled) { + // First data stall + isLogNeeded = true; mDataStalled = true; - mDataStallStartMs = SystemClock.elapsedRealtime(); - logl("data stall: start time = " + DataUtils.elapsedTimeToString(mDataStallStartMs)); - return; - } - - if (!mLastActionReported) { - @RecoveredReason int reason = getRecoveredReason(isValid); - int timeDuration = (int) (SystemClock.elapsedRealtime() - mDataStallStartMs); - logl( - "data stall: lastaction = " - + recoveryActionToString(mLastAction) - + ", isRecovered = " - + isValid - + ", reason = " - + recoveredReasonToString(reason) - + ", TimeDuration = " - + timeDuration); - DataStallRecoveryStats.onDataStallEvent( - mLastAction, mPhone, isValid, timeDuration, reason); + isFirstDataStall = true; + } else if (!mLastActionReported) { + // When the first validation status appears, enter this block. + isLogNeeded = true; + timeDuration = (int) (SystemClock.elapsedRealtime() - mDataStallStartMs); mLastActionReported = true; + isFirstValidationAfterDoRecovery = true; } if (isValid) { + // When the validation passed(mobile data resume), enter this block. + isLogNeeded = true; + timeDuration = (int) (SystemClock.elapsedRealtime() - mDataStallStartMs); mLastActionReported = false; mDataStalled = false; } + + if (isLogNeeded) { + DataStallRecoveryStats.onDataStallEvent( + mLastAction, mPhone, isValid, timeDuration, reason, + isFirstValidationAfterDoRecovery); + logl( + "data stall: " + + (isFirstDataStall == true ? "start" : isValid == false ? "in process" : "end") + + ", lastaction=" + + recoveryActionToString(mLastAction) + + ", isRecovered=" + + isValid + + ", reason=" + + recoveredReasonToString(reason) + + ", isFirstValidationAfterDoRecovery=" + + isFirstValidationAfterDoRecovery + + ", TimeDuration=" + + timeDuration); + } } /** diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java index 9391e2db50..38db78d8d5 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -54,13 +54,15 @@ public class DataStallRecoveryStats { * @param isRecovered The data stall symptom recovered or not. * @param durationMillis The duration from data stall symptom occurred. * @param reason The recovered(data resume) reason. + * @param isFirstValidation The validation status if it's the first come after recovery. */ public static void onDataStallEvent( @DataStallRecoveryManager.RecoveryAction int recoveryAction, Phone phone, boolean isRecovered, int durationMillis, - @DataStallRecoveryManager.RecoveredReason int reason) { + @DataStallRecoveryManager.RecoveredReason int reason, + boolean isFirstValidation) { if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { phone = phone.getDefaultPhone(); } @@ -99,6 +101,19 @@ public class DataStallRecoveryStats { } } + // the number returned here matches the NetworkRegistrationState enum we have + int phoneNetworkRegState = NetworkRegistrationInfo + .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; + + NetworkRegistrationInfo phoneRegInfo = phone.getServiceState() + .getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (phoneRegInfo != null) { + phoneNetworkRegState = phoneRegInfo.getRegistrationState(); + } + + int phoneId = phone.getPhoneId(); + TelephonyStatsLog.write( TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, carrierId, @@ -112,7 +127,10 @@ public class DataStallRecoveryStats { durationMillis, reason, otherSignalStrength, - otherNetworkRegState); + otherNetworkRegState, + phoneNetworkRegState, + isFirstValidation, + phoneId); } /** Returns the RAT used for data (including IWLAN). */ -- GitLab From 4558b805f1821b4ee1798b169ca71546835e59a7 Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Wed, 7 Dec 2022 16:25:42 +0000 Subject: [PATCH 276/656] Overriding of setHysteresisDb value support -Set minimum of system/cc/smaller of smallest threshold delta as hysteresis db value to ril/modem from framework Bug: 248861663 Bug: 240215633 Test: manual & atest FrameworksTelephonyTests Change-Id: I18b17ce6fe15de51df68c3aedca696c36d264be7 --- .../telephony/SignalStrengthController.java | 124 +++++++++- .../SignalStrengthControllerTest.java | 213 +++++++++++++++++- .../telephony/SignalThresholdInfoTest.java | 59 ++++- 3 files changed, 384 insertions(+), 12 deletions(-) diff --git a/src/java/com/android/internal/telephony/SignalStrengthController.java b/src/java/com/android/internal/telephony/SignalStrengthController.java index 06750315d3..0c32f83c0e 100644 --- a/src/java/com/android/internal/telephony/SignalStrengthController.java +++ b/src/java/com/android/internal/telephony/SignalStrengthController.java @@ -602,12 +602,14 @@ public class SignalStrengthController extends Handler { measurementType, mPhone.getSubId(), mPhone.isDeviceIdle()); + int hysteresisDb = getMinimumHysteresisDb(isEnabledForAppRequest, ran, measurementType, + consolidatedThresholds); consolidatedSignalThresholdInfos.add( new SignalThresholdInfo.Builder() .setRadioAccessNetworkType(ran) .setSignalMeasurementType(measurementType) .setHysteresisMs(REPORTING_HYSTERESIS_MILLIS) - .setHysteresisDb(REPORTING_HYSTERESIS_DB) + .setHysteresisDb(hysteresisDb) .setThresholds(consolidatedThresholds, true /*isSystem*/) .setIsEnabled(isEnabledForSystem || isEnabledForAppRequest) .build()); @@ -618,6 +620,126 @@ public class SignalStrengthController extends Handler { + consolidatedSignalThresholdInfos); } + /** + * Return the minimum hysteresis dB from all available sources: + * - system default + * - value set by client through API + * - threshold delta + */ + @VisibleForTesting + public int getMinimumHysteresisDb(boolean isEnabledForAppRequest, int ran, int measurementType, + final int[] consolidatedThresholdList) { + + int currHysteresisDb = getHysteresisDbFromCarrierConfig(ran, measurementType); + + if (isEnabledForAppRequest) { + // Get minimum hysteresisDb at api + int apiHysteresisDb = + getHysteresisDbFromSignalThresholdInfoRequests(ran, measurementType); + + // Choose minimum of hysteresisDb between api Vs current system/cc value set + currHysteresisDb = Math.min(currHysteresisDb, apiHysteresisDb); + + // Hal Req: choose hysteresis db value to be smaller of smallest of threshold delta + currHysteresisDb = computeHysteresisDbOnSmallestThresholdDelta( + currHysteresisDb, consolidatedThresholdList); + } + return currHysteresisDb; + } + + /** + * Get the hysteresis db value from Signal Requests + * Note: Based on the current use case, there does not exist multile App signal threshold info + * requests with hysteresis db value, so this logic picks the latest hysteresis db value set. + * + * TODO(b/262655157): Support Multiple App Hysteresis DB value customisation + */ + private int getHysteresisDbFromSignalThresholdInfoRequests( + @AccessNetworkConstants.RadioAccessNetworkType int ran, + @SignalThresholdInfo.SignalMeasurementType int measurement) { + int apiHysteresisDb = REPORTING_HYSTERESIS_DB; + for (SignalRequestRecord record : mSignalRequestRecords) { + for (SignalThresholdInfo info : record.mRequest.getSignalThresholdInfos()) { + if (isRanAndSignalMeasurementTypeMatch(ran, measurement, info)) { + if (info.getHysteresisDb() >= 0) { + apiHysteresisDb = info.getHysteresisDb(); + } + } + } + } + return apiHysteresisDb; + } + + private int getHysteresisDbFromCarrierConfig(int ran, int measurement) { + int configHysteresisDb = REPORTING_HYSTERESIS_DB; + String configKey = null; + + switch (ran) { + case AccessNetworkConstants.AccessNetworkType.GERAN: + if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) { + configKey = CarrierConfigManager.KEY_GERAN_RSSI_HYSTERESIS_DB_INT; + } + break; + case AccessNetworkConstants.AccessNetworkType.UTRAN: + if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSCP) { + configKey = CarrierConfigManager.KEY_UTRAN_RSCP_HYSTERESIS_DB_INT; + } else if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO) { + configKey = CarrierConfigManager.KEY_UTRAN_ECNO_HYSTERESIS_DB_INT; + } + break; + case AccessNetworkConstants.AccessNetworkType.EUTRAN: + if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP) { + configKey = CarrierConfigManager.KEY_EUTRAN_RSRP_HYSTERESIS_DB_INT; + } else if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRQ) { + configKey = CarrierConfigManager.KEY_EUTRAN_RSRQ_HYSTERESIS_DB_INT; + } else if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSNR) { + configKey = CarrierConfigManager.KEY_EUTRAN_RSSNR_HYSTERESIS_DB_INT; + } + break; + case AccessNetworkConstants.AccessNetworkType.NGRAN: + if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP) { + configKey = CarrierConfigManager.KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT; + } else if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRQ) { + configKey = CarrierConfigManager.KEY_NGRAN_SSRSRQ_HYSTERESIS_DB_INT; + } else if (measurement == SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR) { + configKey = CarrierConfigManager.KEY_NGRAN_SSSINR_HYSTERESIS_DB_INT; + } + break; + default: + localLog("No matching configuration"); + } + if (configKey != null) { + configHysteresisDb = mCarrierConfig.getInt(configKey, REPORTING_HYSTERESIS_DB); + } + return configHysteresisDb >= SignalThresholdInfo.HYSTERESIS_DB_MINIMUM + ? configHysteresisDb : REPORTING_HYSTERESIS_DB; + } + + /** + * This method computes the hysteresis db value between smaller of the smallest Threshold Delta + * and system / cc / api hysteresis db value determined. + * + * @param currMinHysteresisDb smaller value between system / cc / api hysteresis db value + * @param signalThresholdInfoArray consolidated threshold info with App request consolidated. + * @return current minimum hysteresis db value computed between above params. + * + */ + private int computeHysteresisDbOnSmallestThresholdDelta( + int currMinHysteresisDb, final int[] signalThresholdInfoArray) { + int index = 0; + if (signalThresholdInfoArray.length > 1) { + while (index != signalThresholdInfoArray.length - 1) { + if (signalThresholdInfoArray[index + 1] - signalThresholdInfoArray[index] + < currMinHysteresisDb) { + currMinHysteresisDb = + signalThresholdInfoArray[index + 1] - signalThresholdInfoArray[index]; + } + index++; + } + } + return currMinHysteresisDb; + } + void setSignalStrengthDefaultValues() { mSignalStrength = new SignalStrength(); mSignalStrengthUpdatedTime = System.currentTimeMillis(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java index 8b4a2fa431..f72bf98519 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSRP; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI; +import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSRSRP; import static android.telephony.SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_SSSINR; import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; @@ -27,6 +28,7 @@ import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -113,6 +115,7 @@ public class SignalStrengthControllerTest extends TelephonyTest { -97, /* SIGNAL_STRENGTH_GOOD */ -89, /* SIGNAL_STRENGTH_GREAT */ }); + mBundle.putInt(CarrierConfigManager.KEY_GERAN_RSSI_HYSTERESIS_DB_INT, 6); // Support EUTRAN with RSRP mBundle.putInt(CarrierConfigManager.KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT, 1 /* USE_RSRP */); @@ -123,6 +126,7 @@ public class SignalStrengthControllerTest extends TelephonyTest { -95, /* SIGNAL_STRENGTH_GOOD */ -85, /* SIGNAL_STRENGTH_GREAT */ }); + mBundle.putInt(CarrierConfigManager.KEY_EUTRAN_RSRP_HYSTERESIS_DB_INT, 3); // Support NR with SSRSRP mBundle.putInt(CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, 1 /* USE_SSRSRP */); @@ -133,6 +137,7 @@ public class SignalStrengthControllerTest extends TelephonyTest { -80, /* SIGNAL_STRENGTH_GOOD */ -64, /* SIGNAL_STRENGTH_GREAT */ }); + mBundle.putInt(CarrierConfigManager.KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT, 1); // By default, NR with SSRSRQ and SSSINR is not supported mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY, new int[] { @@ -505,6 +510,212 @@ public class SignalStrengthControllerTest extends TelephonyTest { CellSignalStrength.SIGNAL_STRENGTH_MODERATE); } + @Test + public void testSetMinimumHysteresisDb_FromThresholdDelta() { + final int[] consolidatedThresholdList = new int[] {-120, -116, -113, -112}; + + SignalThresholdInfo info = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) + .setSignalMeasurementType(SIGNAL_MEASUREMENT_TYPE_RSSI) + .setThresholds(new int[] {-113}, true) + .setHysteresisDb(2) + .build(); + SignalStrengthUpdateRequest request = + createTestSignalStrengthUpdateRequest( + info, + false /* shouldReportWhileIdle*/, + false /* shouldReportSystemWhileIdle */); + mSsc.setSignalStrengthUpdateRequest( + ACTIVE_SUB_ID, CALLING_UID, request, Message.obtain(mHandler)); + processAllMessages(); + + int minHysteresis = + mSsc.getMinimumHysteresisDb(true, + AccessNetworkConstants.AccessNetworkType.GERAN, + SIGNAL_MEASUREMENT_TYPE_RSSI, + consolidatedThresholdList); + assertEquals(1, minHysteresis); + mSsc.clearSignalStrengthUpdateRequest( + ACTIVE_SUB_ID, CALLING_UID, request, Message.obtain(mHandler)); + processAllMessages(); + } + + @Test + public void testSetMinimumHysteresisDb_FromSignalThresholdRequest() { + final int[] consolidatedThresholdList = new int[] {-120, -116, -112, -108}; + + SignalThresholdInfo info = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.EUTRAN) + .setSignalMeasurementType(SIGNAL_MEASUREMENT_TYPE_RSRP) + .setThresholds(new int[] {-113}, true) + .setHysteresisDb(3) + .build(); + SignalStrengthUpdateRequest request = + createTestSignalStrengthUpdateRequest( + info, + false /* shouldReportWhileIdle*/, + false /* shouldReportSystemWhileIdle */); + mSsc.setSignalStrengthUpdateRequest( + ACTIVE_SUB_ID, CALLING_UID, request, Message.obtain(mHandler)); + processAllMessages(); + + int minHysteresis = + mSsc.getMinimumHysteresisDb(true, + AccessNetworkConstants.AccessNetworkType.EUTRAN, + SIGNAL_MEASUREMENT_TYPE_RSRP, + consolidatedThresholdList); + assertEquals(3, minHysteresis); + + mSsc.clearSignalStrengthUpdateRequest( + ACTIVE_SUB_ID, CALLING_UID, request, Message.obtain(mHandler)); + processAllMessages(); + } + + @Test + public void testSetMinimumHysteresisDb_FromCarrierConfig() { + final int[] consolidatedThresholdList = new int[] {-120, -115, -108, -103}; + + SignalThresholdInfo info = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) + .setSignalMeasurementType(SIGNAL_MEASUREMENT_TYPE_SSRSRP) + .setThresholds(new int[] {-113}, true) + .setHysteresisDb(6) + .build(); + SignalStrengthUpdateRequest request = + createTestSignalStrengthUpdateRequest( + info, + false /* shouldReportWhileIdle*/, + false /* shouldReportSystemWhileIdle */); + mSsc.setSignalStrengthUpdateRequest( + ACTIVE_SUB_ID, CALLING_UID, request, Message.obtain(mHandler)); + processAllMessages(); + + int minHysteresis = + mSsc.getMinimumHysteresisDb(true, + AccessNetworkConstants.AccessNetworkType.NGRAN, + SIGNAL_MEASUREMENT_TYPE_SSRSRP, + consolidatedThresholdList); + assertEquals(1, minHysteresis); + mSsc.clearSignalStrengthUpdateRequest( + ACTIVE_SUB_ID, CALLING_UID, request, Message.obtain(mHandler)); + processAllMessages(); + } + + @Test + public void testSetHysteresisDb_WithCarrierConfigValue() { + when(mPhone.isDeviceIdle()).thenReturn(true); + when(mPhone.getSubId()).thenReturn(ACTIVE_SUB_ID); + + mBundle.putInt(CarrierConfigManager.KEY_GERAN_RSSI_HYSTERESIS_DB_INT, 5); + mBundle.putInt(CarrierConfigManager.KEY_EUTRAN_RSRP_HYSTERESIS_DB_INT, 3); + mBundle.putInt(CarrierConfigManager.KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT, 2); + sendCarrierConfigUpdate(); + + ArgumentCaptor> signalThresholdInfoCaptor = + ArgumentCaptor.forClass(List.class); + verify(mSimulatedCommandsVerifier, atLeastOnce()) + .setSignalStrengthReportingCriteria(signalThresholdInfoCaptor.capture(), isNull()); + List capturedInfos = signalThresholdInfoCaptor.getAllValues().get(0); + assertThat(capturedInfos).isNotEmpty(); + + for (SignalThresholdInfo signalThresholdInfo : capturedInfos) { + if (signalThresholdInfo.getSignalMeasurementType() == SIGNAL_MEASUREMENT_TYPE_RSRP) { + assertEquals(3, signalThresholdInfo.getHysteresisDb()); + } + if (signalThresholdInfo.getSignalMeasurementType() == SIGNAL_MEASUREMENT_TYPE_RSSI) { + assertEquals(5, signalThresholdInfo.getHysteresisDb()); + } + if (signalThresholdInfo.getSignalMeasurementType() == SIGNAL_MEASUREMENT_TYPE_SSRSRP) { + assertEquals(2, signalThresholdInfo.getHysteresisDb()); + } + } + reset(mSimulatedCommandsVerifier); + } + + @Test + public void testSetHysteresisDb_BetweenCarrierConfigSignalThresholdInfoThresholdDelta() { + SignalThresholdInfo info = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.NGRAN) + .setSignalMeasurementType(SIGNAL_MEASUREMENT_TYPE_SSRSRP) + .setThresholds(new int[] {-116}, true) + .setHysteresisDb(3) + .build(); + SignalStrengthUpdateRequest request = + createTestSignalStrengthUpdateRequest( + info, + false /* shouldReportWhileIdle*/, + false /* shouldReportSystemWhileIdle */); + mSsc.setSignalStrengthUpdateRequest( + ACTIVE_SUB_ID, CALLING_UID, request, Message.obtain(mHandler)); + processAllMessages(); + + reset(mSimulatedCommandsVerifier); + when(mPhone.isDeviceIdle()).thenReturn(false); + when(mPhone.getSubId()).thenReturn(ACTIVE_SUB_ID); + mBundle.putIntArray(CarrierConfigManager.KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY, + new int[] { + -113, /* SIGNAL_STRENGTH_POOR */ + -107, /* SIGNAL_STRENGTH_MODERATE */ + -100, /* SIGNAL_STRENGTH_GOOD */ + -95, /* SIGNAL_STRENGTH_GREAT */ + }); + + mBundle.putInt(CarrierConfigManager.KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT, + 1 /* USE_SSRSRP */); + mBundle.putInt(CarrierConfigManager.KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT, 4); + sendCarrierConfigUpdate(); + + ArgumentCaptor> signalThresholdInfoCaptor = + ArgumentCaptor.forClass(List.class); + verify(mSimulatedCommandsVerifier, atLeastOnce()) + .setSignalStrengthReportingCriteria(signalThresholdInfoCaptor.capture(), isNull()); + List capturedInfos = signalThresholdInfoCaptor.getAllValues().get(0); + assertThat(capturedInfos).isNotEmpty(); + + for (SignalThresholdInfo signalThresholdInfo : capturedInfos) { + if (signalThresholdInfo.getSignalMeasurementType() == SIGNAL_MEASUREMENT_TYPE_SSRSRP) { + assertEquals(4, + mBundle.getInt(CarrierConfigManager.KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT)); + assertEquals(3, signalThresholdInfo.getHysteresisDb()); + } + } + } + + @Test + public void testSetHysteresisDb_WithInvalidCarrierConfigValue() { + when(mPhone.isDeviceIdle()).thenReturn(true); + when(mPhone.getSubId()).thenReturn(ACTIVE_SUB_ID); + + mBundle.putInt(CarrierConfigManager.KEY_GERAN_RSSI_HYSTERESIS_DB_INT, -4); + mBundle.putInt(CarrierConfigManager.KEY_EUTRAN_RSRP_HYSTERESIS_DB_INT, -5); + mBundle.putInt(CarrierConfigManager.KEY_NGRAN_SSRSRP_HYSTERESIS_DB_INT, -2); + sendCarrierConfigUpdate(); + + ArgumentCaptor> signalThresholdInfoCaptor = + ArgumentCaptor.forClass(List.class); + verify(mSimulatedCommandsVerifier, atLeastOnce()) + .setSignalStrengthReportingCriteria(signalThresholdInfoCaptor.capture(), isNull()); + List capturedInfos = signalThresholdInfoCaptor.getAllValues().get(0); + assertThat(capturedInfos).isNotEmpty(); + + for (SignalThresholdInfo signalThresholdInfo : capturedInfos) { + if (signalThresholdInfo.getSignalMeasurementType() == SIGNAL_MEASUREMENT_TYPE_RSRP) { + assertEquals(2, signalThresholdInfo.getHysteresisDb()); + } + if (signalThresholdInfo.getSignalMeasurementType() == SIGNAL_MEASUREMENT_TYPE_RSSI) { + assertEquals(2, signalThresholdInfo.getHysteresisDb()); + } + if (signalThresholdInfo.getSignalMeasurementType() == SIGNAL_MEASUREMENT_TYPE_SSRSRP) { + assertEquals(2, signalThresholdInfo.getHysteresisDb()); + } + } + reset(mSimulatedCommandsVerifier); + } + @Test public void testLteSignalStrengthReportingCriteria_convertRssnrUnitFromTenDbToDB() { SignalStrength ss = new SignalStrength( @@ -790,4 +1001,4 @@ public class SignalStrengthControllerTest extends TelephonyTest { } return builder.build(); } -} +} \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java index 5f39c0937b..e22d7ab24e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SignalThresholdInfoTest.java @@ -210,13 +210,17 @@ public class SignalThresholdInfoTest extends TestCase { assertThat(stList.get(1).getSignalMeasurementType()) .isEqualTo(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI); assertThat(stList.get(1).getThresholds()).isEqualTo(mRssiThresholds); + assertThat(stList.get(0).getHysteresisDb()) + .isEqualTo(SignalThresholdInfo.HYSTERESIS_DB_MINIMUM); + assertThat(stList.get(1).getHysteresisDb()) + .isEqualTo(HYSTERESIS_DB); } @Test @SmallTest public void testEqualsSignalThresholdInfo() { final int[] dummyThresholds = new int[] {-100, -90, -70, -60}; - final int[] dummyThreholdsDisordered = new int[] {-60, -90, -100, -70}; + final int[] dummyThresholdsDisordered = new int[] {-60, -90, -100, -70}; SignalThresholdInfo st1 = new SignalThresholdInfo.Builder() .setRadioAccessNetworkType(1) @@ -259,7 +263,7 @@ public class SignalThresholdInfoTest extends TestCase { .setSignalMeasurementType(1) .setHysteresisMs(HYSTERESIS_MS) .setHysteresisDb(HYSTERESIS_DB) - .setThresholds(dummyThreholdsDisordered) + .setThresholds(dummyThresholdsDisordered) .setIsEnabled(false) .build(); @@ -274,6 +278,34 @@ public class SignalThresholdInfoTest extends TestCase { assertFalse(st1.equals(new String("test"))); } + @Test + @SmallTest + public void testHysteresisDbSettings_WithValidRange() { + SignalThresholdInfo st1 = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) + .setThresholds(new int[] {}, true) + .build(); + SignalThresholdInfo st2 = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) + .setThresholds(new int[] {}, true) + .setHysteresisDb(3) + .build(); + SignalThresholdInfo st3 = + new SignalThresholdInfo.Builder() + .setRadioAccessNetworkType(AccessNetworkConstants.AccessNetworkType.GERAN) + .setSignalMeasurementType(SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI) + .setThresholds(new int[] {}, true) + .setHysteresisDb(1) + .build(); + assertThat(st1.getHysteresisDb()).isEqualTo(HYSTERESIS_DB); + assertThat(st2.getHysteresisDb()).isEqualTo(3); + assertThat(st3.getHysteresisDb()).isEqualTo(1); + } + @Test @SmallTest public void testBuilderWithValidParameters() { @@ -283,7 +315,7 @@ public class SignalThresholdInfoTest extends TestCase { SignalThresholdInfo st = stList.get(i); assertThat(st.getThresholds()).isEqualTo(mThresholds[i]); assertThat(st.getHysteresisMs()).isEqualTo(SignalThresholdInfo.HYSTERESIS_MS_DISABLED); - assertThat(st.getHysteresisDb()).isEqualTo(SignalThresholdInfo.HYSTERESIS_DB_DISABLED); + assertThat(st.getHysteresisDb()).isEqualTo(HYSTERESIS_DB); assertFalse(st.isEnabled()); } } @@ -297,26 +329,32 @@ public class SignalThresholdInfoTest extends TestCase { buildWithInvalidParameterThrowException( AccessNetworkConstants.AccessNetworkType.GERAN, signalMeasurementType, - new int[] {-1}); + new int[] {-1}, 2); } // Null thresholds array buildWithInvalidParameterThrowException( AccessNetworkConstants.AccessNetworkType.GERAN, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, - null); + null, 0); // Empty thresholds buildWithInvalidParameterThrowException( AccessNetworkConstants.AccessNetworkType.GERAN, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, - new int[] {}); + new int[] {}, 5); // Too long thresholds array buildWithInvalidParameterThrowException( AccessNetworkConstants.AccessNetworkType.GERAN, SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, - new int[] {-100, -90, -70, -60, -58}); + new int[] {-100, -90, -70, -60, -58}, 3); + + // Test Hysteresis Db invalid Range + buildWithInvalidParameterThrowException( + AccessNetworkConstants.AccessNetworkType.GERAN, + SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_RSSI, + new int[] {-100, -90, -70, -60}, -1); // Thresholds value out of range for (int signalMeasurementType : INVALID_THRESHOLDS_MAP.keySet()) { @@ -325,7 +363,7 @@ public class SignalThresholdInfoTest extends TestCase { buildWithInvalidParameterThrowException( getValidRan(signalMeasurementType), signalMeasurementType, - new int[] {threshold}); + new int[] {threshold}, 1); } } @@ -336,19 +374,20 @@ public class SignalThresholdInfoTest extends TestCase { type <= SignalThresholdInfo.SIGNAL_MEASUREMENT_TYPE_ECNO; type++) { if (!validTypes.contains(type)) { - buildWithInvalidParameterThrowException(ran, type, new int[] {-1}); + buildWithInvalidParameterThrowException(ran, type, new int[] {-1}, 2); } } } } private void buildWithInvalidParameterThrowException( - int ran, int signalMeasurementType, int[] thresholds) { + int ran, int signalMeasurementType, int[] thresholds, int hysteresisDb) { try { new SignalThresholdInfo.Builder() .setRadioAccessNetworkType(ran) .setSignalMeasurementType(signalMeasurementType) .setThresholds(thresholds) + .setHysteresisDb(hysteresisDb) .build(); fail("exception expected"); } catch (IllegalArgumentException | NullPointerException expected) { -- GitLab From cb3f3942436f67be5fe82d48b292b39889e585da Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 15 Dec 2022 14:37:05 -0800 Subject: [PATCH 277/656] Update internet data state when capabilities change When network capabilities change for a data network with INTERNET capabilities, reevaluate the internet data state. Other capabilities that might change isInternetSupported (ie. NOT_RESTRICTED) could have changed, which could affect the internet data state. Test: atest DataNetworkControllerTest Bug: 246845511 Change-Id: Ibeccad57760d1e1b7b25ef5c95e070b561b151ba --- .../telephony/data/DataNetworkController.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 6e8f4ada42..52ce7b5019 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -3172,6 +3172,12 @@ public class DataNetworkController extends Handler { log("Found more network requests that can be satisfied. " + networkRequestList); dataNetwork.attachNetworkRequests(networkRequestList); } + + if (dataNetwork.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + // Update because DataNetwork#isInternetSupported might have changed with capabilities. + updateOverallInternetDataState(); + } } /** @@ -3322,9 +3328,9 @@ public class DataNetworkController extends Handler { } /** - * Update the internet data network state. For now only {@link TelephonyManager#DATA_CONNECTED} - * , {@link TelephonyManager#DATA_SUSPENDED}, and - * {@link TelephonyManager#DATA_DISCONNECTED} are supported. + * Update the internet data network state. For now only {@link TelephonyManager#DATA_CONNECTED}, + * {@link TelephonyManager#DATA_SUSPENDED}, and {@link TelephonyManager#DATA_DISCONNECTED} + * are supported. */ private void updateOverallInternetDataState() { boolean anyInternetConnected = mDataNetworkList.stream() @@ -3592,8 +3598,8 @@ public class DataNetworkController extends Handler { /** * Get the internet data network state. Note that this is the best effort if more than one - * data network supports internet. For now only {@link TelephonyManager#DATA_CONNECTED} - * , {@link TelephonyManager#DATA_SUSPENDED}, and {@link TelephonyManager#DATA_DISCONNECTED} + * data network supports internet. For now only {@link TelephonyManager#DATA_CONNECTED}, + * {@link TelephonyManager#DATA_SUSPENDED}, and {@link TelephonyManager#DATA_DISCONNECTED} * are supported. * * @return The data network state. -- GitLab From ebec0dd34de4c76ef1bc89daacdb807c0a307b71 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 13 Dec 2022 18:23:25 -0800 Subject: [PATCH 278/656] Evaluate auto data switch upon hangup voice call Upon hangup voice call, reevalute whether we should auto data switch. Also clean up the dataEnableChanged event interacting with voice call: Before the change, if data is disabled during call, the expected behavior is that user loses access to data immediately during call, but the previous behavior is that user still has data access. Fix: 262335341 Test: atest + toggle mobile data during call Change-Id: Iabfa73c70e344b4f49950a9a495edf6f00f8b144 --- .../telephony/data/PhoneSwitcher.java | 52 ++++++---- .../telephony/data/PhoneSwitcherTest.java | 96 +++++++++++++------ 2 files changed, 98 insertions(+), 50 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index e32bb31cf2..1eb07aa4fb 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -561,8 +561,7 @@ public class PhoneSwitcher extends Handler { public void onDataEnabledChanged(boolean enabled, @TelephonyManager.DataEnabledChangedReason int reason, @NonNull String callingPackage) { - logl("user changed data settings"); - evaluateIfAutoSwitchIsNeeded(); + PhoneSwitcher.this.onDataEnabledChanged(); }}); phone.getDataSettingsManager().registerCallback( mDataSettingsManagerCallbacks.get(phoneId)); @@ -806,8 +805,14 @@ public class PhoneSwitcher extends Handler { mEmergencyOverride.mPendingOriginatingCall = false; } } + // Always update data modem via data during call code path, because + // mAutoSelectedDataSubId doesn't know about any data switch due to voice call evaluateIfImmediateDataSwitchIsNeeded("precise call state changed", DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); + if (!isAnyVoiceCallActiveOnDevice()) { + // consider auto switch on hang up all voice call + evaluateIfAutoSwitchIsNeeded(); + } break; } case EVENT_NETWORK_VALIDATION_DONE: { @@ -974,10 +979,7 @@ public class PhoneSwitcher extends Handler { public void onDataEnabledChanged(boolean enabled, @TelephonyManager.DataEnabledChangedReason int reason, @NonNull String callingPackage) { - logl("user changed data settings"); - evaluateIfImmediateDataSwitchIsNeeded("user changed data settings", - DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); - evaluateIfAutoSwitchIsNeeded(); + PhoneSwitcher.this.onDataEnabledChanged(); } }); phone.getDataSettingsManager().registerCallback( @@ -991,6 +993,23 @@ public class PhoneSwitcher extends Handler { } } + /** + * Called when + * 1. user changed mobile data settings + * 2. OR user changed auto data switch feature + */ + private void onDataEnabledChanged() { + logl("user changed data related settings"); + if (isAnyVoiceCallActiveOnDevice()) { + // user changed data related settings during call, switch or turn off immediately + evaluateIfImmediateDataSwitchIsNeeded( + "user changed data settings during call", + DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); + } else { + evaluateIfAutoSwitchIsNeeded(); + } + } + private boolean isInEmergencyCallbackMode() { for (Phone p : PhoneFactory.getPhones()) { if (p == null) continue; @@ -1088,7 +1107,7 @@ public class PhoneSwitcher extends Handler { .getRegistrationState(); if (newRegState != mPhoneStates[phoneId].dataRegState) { mPhoneStates[phoneId].dataRegState = newRegState; - logl("onServiceStateChanged:phoneId:" + phoneId + " dataReg-> " + logl("onServiceStateChanged: phoneId:" + phoneId + " dataReg-> " + NetworkRegistrationInfo.registrationStateToString(newRegState)); if (!hasMessages(EVENT_EVALUATE_AUTO_SWITCH)) { sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); @@ -1131,14 +1150,6 @@ public class PhoneSwitcher extends Handler { if (mPreferredDataPhoneId == primaryPhoneId) { // on primary data sub - if (isAnyVoiceCallActiveOnDevice()) { - // if on voice call, switch immediately - evaluateIfImmediateDataSwitchIsNeeded( - "user updates data settings during voice call", - DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); - return; - } - int candidateSubId = getAutoSwitchTargetSubIdIfExists(); if (candidateSubId != INVALID_SUBSCRIPTION_ID) { startAutoDataSwitchStabilityCheck(candidateSubId, true); @@ -1161,7 +1172,7 @@ public class PhoneSwitcher extends Handler { .getNetworkCapabilities(mConnectivityManager.getActiveNetwork()); if (defaultNetworkCapabilities != null && !defaultNetworkCapabilities .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { - log("evaluateIfAutoSwitchIsNeeded:" + log("evaluateIfAutoSwitchIsNeeded: " + "Default network is active on non-cellular transport"); startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, false); return; @@ -1353,7 +1364,7 @@ public class PhoneSwitcher extends Handler { if (hasAnyActiveSubscription) updatePreferredDataPhoneId(); if (oldPreferredDataPhoneId != mPreferredDataPhoneId) { - sb.append(" preferred phoneId ").append(oldPreferredDataPhoneId) + sb.append(" preferred data phoneId ").append(oldPreferredDataPhoneId) .append("->").append(mPreferredDataPhoneId); diffDetected = true; } else if (oldPreferredDataSubId != mPreferredDataSubId.get()) { @@ -1601,7 +1612,8 @@ public class PhoneSwitcher extends Handler { int imsRegTech = mImsRegTechProvider.get(mContext, mPhoneIdInVoiceCall); if (isAnyVoiceCallActiveOnDevice() && imsRegTech != REGISTRATION_TECH_IWLAN) { if (imsRegTech != REGISTRATION_TECH_CROSS_SIM) { - if (shouldSwitchDataDueToInCall()) mPreferredDataPhoneId = mPhoneIdInVoiceCall; + mPreferredDataPhoneId = shouldSwitchDataDueToInCall() + ? mPhoneIdInVoiceCall : getFallbackDataPhoneIdForInternetRequests(); } else { logl("IMS call on cross-SIM, skip switching data to phone " + mPhoneIdInVoiceCall); @@ -1633,7 +1645,7 @@ public class PhoneSwitcher extends Handler { /** * If a phone is in call and user enabled its mobile data and auto data switch feature, we - * should switch internet connectionto it because the other modem will lose data connection + * should switch internet connection to it because the other modem will lose data connection * anyway. * @return {@code true} if should switch data to the phone in voice call */ @@ -2200,7 +2212,7 @@ public class PhoneSwitcher extends Handler { subInfo = mSubscriptionController.getSubscriptionInfo(mAutoSelectedDataSubId); } if (subInfo == null || subInfo.isOpportunistic()) { - loge("displayAutoDataSwitchNotification:mAutoSelectedDataSubId=" + loge("displayAutoDataSwitchNotification: mAutoSelectedDataSubId=" + mAutoSelectedDataSubId + " unexpected subInfo " + subInfo); return; } 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 6923eb0d42..5ff51b6e56 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -748,8 +748,7 @@ public class PhoneSwitcherTest extends TelephonyTest { * The following events can set preferred data subId with priority in the order of * 1. Emergency call * 2. Voice call (when data during call feature is enabled). - * 3. CBRS requests - * 4. Auto switch requests + * 3. CBRS requests OR Auto switch requests - only one case applies at a time */ @Test @SmallTest @@ -762,6 +761,8 @@ public class PhoneSwitcherTest extends TelephonyTest { // Both are active subscriptions are active sub, as they are in both active slots. setSlotIndexToSubId(0, 1); setSlotIndexToSubId(1, 2); + // single visible sub, as the other one is CBRS + doReturn(new int[1]).when(mSubscriptionController).getActiveSubIdList(true); setDefaultDataSubId(1); // Notify phoneSwitcher about default data sub and default network request. @@ -1000,14 +1001,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInCall(mImsPhone); - // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); - - // User turns on data on Phone 0 - doReturn(true).when(mPhone).isUserDataEnabled(); - notifyDataEnabled(true); - - // Phone 1 should become the default data phone. + // Phone 1 should become the preferred data phone. assertEquals(1, mPhoneSwitcherUT.getPreferredDataPhoneId()); } @@ -1036,14 +1030,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInDial(mImsPhone); - // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); - - // User turns on data on Phone 0 - doReturn(true).when(mPhone).isUserDataEnabled(); - notifyDataEnabled(true); - - // Phone 1 should become the default data phone. + // Phone2 should be preferred data phone assertEquals(1, mPhoneSwitcherUT.getPreferredDataPhoneId()); } @Test @@ -1071,14 +1058,7 @@ public class PhoneSwitcherTest extends TelephonyTest { mockImsRegTech(1, REGISTRATION_TECH_LTE); notifyPhoneAsInIncomingCall(mImsPhone); - // Phone 0 should be the default data phoneId. - assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); - - // User turns on data on Phone 0 - doReturn(true).when(mPhone).isUserDataEnabled(); - notifyDataEnabled(true); - - // Phone 1 should become the default data phone. + // Phone 1 should become the preferred data phone. assertEquals(1, mPhoneSwitcherUT.getPreferredDataPhoneId()); } @@ -1186,7 +1166,7 @@ public class PhoneSwitcherTest extends TelephonyTest { clearInvocations(mMockRadioConfig); // Phone2(nDDS) call ended. But Phone1 having cross-SIM call. Don't switch. - mockImsRegTech(1, REGISTRATION_TECH_CROSS_SIM); + mockImsRegTech(0, REGISTRATION_TECH_CROSS_SIM); notifyPhoneAsInIncomingCall(mPhone); notifyPhoneAsInactive(mPhone2); verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); @@ -1195,17 +1175,28 @@ public class PhoneSwitcherTest extends TelephonyTest { assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); - // Phone1(DDS) call ended. So data switch back to default data sub. - mockImsRegTech(0, REGISTRATION_TECH_IWLAN); + // Phone(DDS) call ended. + // Honor auto data switch's suggestion: if DDS is OOS, auto switch to Phone2(nDDS). + serviceStateChanged(1, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + serviceStateChanged(0, NetworkRegistrationInfo + .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING); + doReturn(null).when(mConnectivityManager).getNetworkCapabilities(any()); notifyPhoneAsInactive(mPhone); + + // verify immediately switch back to DDS upon call ends verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 0)); assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( new TelephonyNetworkRequest(internetRequest, mPhone), 1)); - clearInvocations(mMockRadioConfig); + + // verify the attempt to do auto data switch to Phone2(nDDS) + processAllFutureMessages(); + verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), + eq(mPhoneSwitcherUT.mValidationCallback)); // Phone2 has holding call on VoWifi, no need to switch data + clearInvocations(mMockRadioConfig); mockImsRegTech(1, REGISTRATION_TECH_IWLAN); notifyPhoneAsInHoldingCall(mPhone2); verify(mMockRadioConfig, never()).setPreferredDataModem(anyInt(), any()); @@ -1215,6 +1206,43 @@ public class PhoneSwitcherTest extends TelephonyTest { new TelephonyNetworkRequest(internetRequest, mPhone), 1)); } + @Test + @SmallTest + public void testDataEnabledChangedDuringVoiceCall() throws Exception { + doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported(); + initialize(); + // 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); + NetworkRequest internetRequest = addInternetNetworkRequest(null, 50); + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 0)); + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 1)); + clearInvocations(mMockRadioConfig); + setAllPhonesInactive(); + // Initialization done. + + // Phone2 has active call and data is on. So switch to nDDS Phone2 + notifyDataEnabled(true); + notifyPhoneAsInCall(mPhone2); + verify(mMockRadioConfig).setPreferredDataModem(eq(1), any()); + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 0)); + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 1)); + + // During the active call, user turns off data, should immediately switch back to DDS + notifyDataEnabled(false); + verify(mMockRadioConfig).setPreferredDataModem(eq(0), any()); + assertTrue(mPhoneSwitcherUT.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 0)); + assertFalse(mPhoneSwitcherUT.shouldApplyNetworkRequest( + new TelephonyNetworkRequest(internetRequest, mPhone), 1)); + } @Test @SmallTest @@ -1810,6 +1838,7 @@ public class PhoneSwitcherTest extends TelephonyTest { } private void notifyDataEnabled(boolean dataEnabled) { + doReturn(true).when(mPhone).isUserDataEnabled(); doReturn(dataEnabled).when(mDataSettingsManager).isDataEnabled(); doReturn(dataEnabled).when(mPhone2).isDataAllowed(); mDataSettingsManagerCallbacks.get(0).onDataEnabledChanged(dataEnabled, 123 , ""); @@ -2044,6 +2073,13 @@ public class PhoneSwitcherTest extends TelephonyTest { mDefaultDataSub = defaultDataSub; doReturn(mDefaultDataSub).when(mSubscriptionController).getDefaultDataSubId(); doReturn(mDefaultDataSub).when(mMockedIsub).getDefaultDataSubId(); + if (defaultDataSub == 1) { + doReturn(true).when(mPhone).isUserDataEnabled(); + doReturn(false).when(mPhone2).isUserDataEnabled(); + } else { + doReturn(false).when(mPhone).isUserDataEnabled(); + doReturn(true).when(mPhone2).isUserDataEnabled(); + } sendDefaultDataSubChanged(); } -- GitLab From d58fa9e0c73d10ec33ceabe05081b6ca0b8a8e3f Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 5 Dec 2022 15:21:49 -0600 Subject: [PATCH 279/656] Improve CarrierPrivilegesTracker with new CarrierConfigManager APIs This CL improve the performance of CarrierPrivilegsTracker with the new introduced CarrierConfigManager API: - Replace carrier config change broadcast receiver with listener which has much low lagency - Retrieve subset of carrier config to reduce memory consumption Bug: 244087782 Test: atest CarrierPrivilegesTrackerTest Change-Id: I1d3a49a0d669fed4c6db08364c9e1c9f7f5f1eb8 --- .../telephony/CarrierPrivilegesTracker.java | 50 +++++++------------ .../CarrierPrivilegesTrackerTest.java | 41 ++++++++------- 2 files changed, 41 insertions(+), 50 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index b3afb66102..83624edfe2 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -16,11 +16,8 @@ package com.android.internal.telephony; -import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; -import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY; import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; -import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED; @@ -129,6 +126,13 @@ public class CarrierPrivilegesTracker extends Handler { | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS; + /** + * All carrier config keys used in this class should list here in alphabetical order. + */ + private static final String[] CARRIER_CONFIG_KEYS = { + KEY_CARRIER_CERTIFICATE_STRING_ARRAY, + }; + /** * Action to register a Registrant with this Tracker. * obj: Registrant that will be notified of Carrier Privileged UID changes. @@ -141,13 +145,6 @@ public class CarrierPrivilegesTracker extends Handler { */ private static final int ACTION_UNREGISTER_LISTENER = 2; - /** - * Action for tracking when Carrier Configs are updated. - * arg1: Subscription Id for the Carrier Configs update being broadcast - * arg2: Slot Index for the Carrier Configs update being broadcast - */ - private static final int ACTION_CARRIER_CONFIG_CERTS_UPDATED = 3; - /** * Action for tracking when the Phone's SIM state changes. * arg1: slotId that this Action applies to @@ -297,19 +294,6 @@ public class CarrierPrivilegesTracker extends Handler { if (action == null) return; switch (action) { - case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: { - Bundle extras = intent.getExtras(); - int slotIndex = extras.getInt(EXTRA_SLOT_INDEX); - int subId = - extras.getInt( - EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID); - sendMessage( - obtainMessage( - ACTION_CARRIER_CONFIG_CERTS_UPDATED, - subId, - slotIndex)); - break; - } case TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED: // fall through case TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED: { Bundle extras = intent.getExtras(); @@ -372,13 +356,16 @@ public class CarrierPrivilegesTracker extends Handler { mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mCarrierConfigManager = (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); + // Callback is executed in handler thread and directly handles carrier config update + mCarrierConfigManager.registerCarrierConfigChangeListener(this::post, + (slotIndex, subId, carrierId, specificCarrierId) -> handleCarrierConfigUpdated( + subId, slotIndex)); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mTelephonyRegistryManager = (TelephonyRegistryManager) mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); IntentFilter certFilter = new IntentFilter(); - certFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); certFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); certFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); mContext.registerReceiver(mIntentReceiver, certFilter); @@ -408,12 +395,6 @@ public class CarrierPrivilegesTracker extends Handler { handleUnregisterListener((Handler) msg.obj); break; } - case ACTION_CARRIER_CONFIG_CERTS_UPDATED: { - int subId = msg.arg1; - int slotIndex = msg.arg2; - handleCarrierConfigUpdated(subId, slotIndex); - break; - } case ACTION_SIM_STATE_UPDATED: { handleSimStateChanged(msg.arg1, msg.arg2); break; @@ -490,7 +471,14 @@ public class CarrierPrivilegesTracker extends Handler { @NonNull private List getCarrierConfigRules(int subId) { - PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); + PersistableBundle carrierConfigs = null; + try { + carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId, CARRIER_CONFIG_KEYS); + } catch (RuntimeException e) { + mLocalLog.log("CarrierConfigLoader is not available, try it later."); + } + + // CarrierConfigManager#isConfigForIdentifiedCarrier can handle null or empty bundle if (!mCarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) { return Collections.EMPTY_LIST; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java index 221b2b525e..96c46b3f92 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java @@ -17,8 +17,6 @@ package com.android.internal.telephony; import static android.os.UserHandle.SYSTEM; -import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX; -import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX; import static android.telephony.CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY; import static android.telephony.CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -76,8 +74,8 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.InOrder; -import org.mockito.Mock; import java.security.MessageDigest; import java.util.ArrayList; @@ -129,11 +127,10 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS; - @Mock private Signature mSignature; - private PersistableBundle mCarrierConfigs; private CarrierPrivilegesTrackerTestHandler mHandler; private CarrierPrivilegesTracker mCarrierPrivilegesTracker; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; @Before public void setUp() throws Exception { @@ -164,7 +161,8 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { private void setupCarrierConfigRules(String... rules) { mCarrierConfigs.putStringArray(KEY_CARRIER_CERTIFICATE_STRING_ARRAY, rules); mCarrierConfigs.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, true); - when(mCarrierConfigManager.getConfigForSubId(SUB_ID)).thenReturn(mCarrierConfigs); + when(mCarrierConfigManager.getConfigForSubId(eq(SUB_ID), any())) + .thenReturn(mCarrierConfigs); } private static String carrierConfigRuleString(String certificateHash, String... packageNames) { @@ -222,8 +220,14 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { * #setupInstalledPackages}. */ private CarrierPrivilegesTracker createCarrierPrivilegesTracker() throws Exception { + // Capture CarrierConfigChangeListener to emulate the carrier config change notification + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); CarrierPrivilegesTracker cpt = new CarrierPrivilegesTracker(mTestableLooper.getLooper(), mPhone, mContext); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); mTestableLooper.processAllMessages(); cpt.registerCarrierPrivilegesListener(mHandler, REGISTRANT_WHAT, null); @@ -371,7 +375,7 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { verifyCarrierPrivilegesChangedUpdates(List.of()); // Clear UIDs - sendCarrierConfigChangedIntent(INVALID_SUBSCRIPTION_ID, PHONE_ID); + sendCarrierConfigChanged(INVALID_SUBSCRIPTION_ID, PHONE_ID); mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(), new int[0]); @@ -389,7 +393,7 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { setupCarrierConfigRules( carrierConfigRuleString(getHash(CERT_1)), carrierConfigRuleString(getHash(CERT_2))); - sendCarrierConfigChangedIntent(SUB_ID, PHONE_ID); + sendCarrierConfigChanged(SUB_ID, PHONE_ID); mTestableLooper.processAllMessages(); verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); @@ -403,7 +407,7 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // Start with privileges. Incorrect phoneId shouldn't affect certs setupCarrierPrivilegesTrackerWithCarrierConfigUids(); - sendCarrierConfigChangedIntent(SUB_ID, PHONE_ID_INCORRECT); + sendCarrierConfigChanged(SUB_ID, PHONE_ID_INCORRECT); mTestableLooper.processAllMessages(); verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); @@ -417,7 +421,7 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // Start with privileges, verify clearing certs clears UIDs setupCarrierPrivilegesTrackerWithCarrierConfigUids(); - sendCarrierConfigChangedIntent(INVALID_SUBSCRIPTION_ID, PHONE_ID); + sendCarrierConfigChanged(INVALID_SUBSCRIPTION_ID, PHONE_ID); mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(), new int[0]); @@ -434,9 +438,10 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { setupCarrierPrivilegesTrackerWithCarrierConfigUids(); mCarrierConfigs.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false); - when(mCarrierConfigManager.getConfigForSubId(SUB_ID)).thenReturn(mCarrierConfigs); + when(mCarrierConfigManager.getConfigForSubId(eq(SUB_ID), any())) + .thenReturn(mCarrierConfigs); - sendCarrierConfigChangedIntent(SUB_ID, PHONE_ID); + sendCarrierConfigChanged(SUB_ID, PHONE_ID); mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(), new int[0]); @@ -456,7 +461,7 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { carrierConfigRuleString(getHash(CERT_1), PACKAGE_1), carrierConfigRuleString(getHash(CERT_2), PACKAGE_1)); - sendCarrierConfigChangedIntent(SUB_ID, PHONE_ID); + sendCarrierConfigChanged(SUB_ID, PHONE_ID); mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(PACKAGE_1), new int[] {UID_1}); @@ -469,7 +474,7 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { carrierConfigRuleString(getHash(CERT_1), PACKAGE_1), carrierConfigRuleString(getHash(CERT_2), PACKAGE_1, PACKAGE_2)); - sendCarrierConfigChangedIntent(SUB_ID, PHONE_ID); + sendCarrierConfigChanged(SUB_ID, PHONE_ID); mTestableLooper.processAllMessages(); verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); @@ -1130,11 +1135,9 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { verify(mPackageManager).queryIntentServices(any(), anyInt()); } - private void sendCarrierConfigChangedIntent(int subId, int phoneId) { - mContext.sendBroadcast( - new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED) - .putExtra(EXTRA_SUBSCRIPTION_INDEX, subId) - .putExtra(EXTRA_SLOT_INDEX, phoneId)); + private void sendCarrierConfigChanged(int subId, int phoneId) { + mCarrierConfigChangeListener.onCarrierConfigChanged(phoneId, subId, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); } private void sendSimCardStateChangedIntent(int phoneId, int simState) { -- GitLab From 66e6df9ff4b79c2d5103876a0dc6a956cd47795c Mon Sep 17 00:00:00 2001 From: Avinash Malipatil Date: Wed, 16 Nov 2022 11:10:33 +0000 Subject: [PATCH 280/656] Add getSelectionAttributes utility method to NormalCallDomainSelectionConnection Bug: 246719281 Test: atest FrameworksTelephonyTests:NormalCallDomainSelectionConnectionTest Change-Id: Icd8b7bc4a5fe9dd6a35a657e216f88f067f11345 --- .../NormalCallDomainSelectionConnection.java | 32 +++ ...rmalCallDomainSelectionConnectionTest.java | 191 ++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java diff --git a/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java index 8aa54ac554..516d6b9b89 100644 --- a/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java @@ -25,6 +25,7 @@ import android.telephony.Annotation.DisconnectCauses; import android.telephony.DomainSelectionService; import android.telephony.DomainSelectionService.EmergencyScanType; import android.telephony.NetworkRegistrationInfo; +import android.telephony.ims.ImsReasonInfo; import com.android.internal.telephony.Phone; @@ -91,4 +92,35 @@ public class NormalCallDomainSelectionConnection extends DomainSelectionConnecti selectDomain(attr); return getCompletableFuture(); } + + /** + * Returns the attributes required to determine the domain for a normal call. + * + * @param slotId The slot identifier. + * @param subId The subscription identifier. + * @param callId The call identifier. + * @param number The dialed number. + * @param isVideoCall flag for video call. + * @param callFailCause The reason why the last CS attempt failed. + * @param imsReasonInfo The reason why the last PS attempt failed. + * @return The attributes required to determine the domain. + */ + public static @NonNull DomainSelectionService.SelectionAttributes getSelectionAttributes( + int slotId, int subId, @NonNull String callId, @NonNull String number, + boolean isVideoCall, int callFailCause, @Nullable ImsReasonInfo imsReasonInfo) { + + DomainSelectionService.SelectionAttributes.Builder builder = + new DomainSelectionService.SelectionAttributes.Builder( + slotId, subId, SELECTOR_TYPE_CALLING) + .setEmergency(false) + .setCallId(callId) + .setNumber(number) + .setCsDisconnectCause(callFailCause) + .setVideoCall(isVideoCall); + + if (imsReasonInfo != null) { + builder.setPsDisconnectCause(imsReasonInfo); + } + return builder.build(); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java new file mode 100644 index 0000000000..8b7e872780 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2022 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. + */ + +import static android.telephony.DisconnectCause.ERROR_UNSPECIFIED; +import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.telephony.DomainSelectionService; +import android.telephony.TransportSelectorCallback; +import android.telephony.WwanSelectorCallback; +import android.telephony.ims.ImsReasonInfo; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.domainselection.DomainSelectionConnection; +import com.android.internal.telephony.domainselection.DomainSelectionController; +import com.android.internal.telephony.domainselection.NormalCallDomainSelectionConnection; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.CompletableFuture; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class NormalCallDomainSelectionConnectionTest extends TelephonyTest { + + private static final String TELECOM_CALL_ID1 = "TC1"; + + @Mock + private DomainSelectionController mMockDomainSelectionController; + @Mock + private DomainSelectionConnection.DomainSelectionConnectionCallback mMockConnectionCallback; + @Mock + private AccessNetworksManager mMockAccessNetworksManager; + + private TransportSelectorCallback mTransportCallback; + private NormalCallDomainSelectionConnection mNormalCallDomainSelectionConnection; + + @Before + public void setUp() throws Exception { + super.setUp(this.getClass().getSimpleName()); + MockitoAnnotations.initMocks(this); + doReturn(mMockAccessNetworksManager).when(mPhone).getAccessNetworksManager(); + mNormalCallDomainSelectionConnection = + new NormalCallDomainSelectionConnection(mPhone, mMockDomainSelectionController); + mTransportCallback = mNormalCallDomainSelectionConnection.getTransportSelectorCallback(); + } + + @After + public void tearDown() throws Exception { + mNormalCallDomainSelectionConnection = null; + super.tearDown(); + } + + @Test + @SmallTest + public void testSelectDomainWifi() throws Exception { + DomainSelectionService.SelectionAttributes attributes = + NormalCallDomainSelectionConnection.getSelectionAttributes(mPhone.getPhoneId(), + mPhone.getSubId(), TELECOM_CALL_ID1, "123", false, 0, null); + + CompletableFuture future = + mNormalCallDomainSelectionConnection + .createNormalConnection(attributes, mMockConnectionCallback); + + assertNotNull(future); + assertFalse(future.isDone()); + + verify(mMockDomainSelectionController).selectDomain(any(), any()); + + mTransportCallback.onWlanSelected(); + + assertTrue(future.isDone()); + assertEquals((long) DOMAIN_PS, (long) future.get()); + } + + @Test + @SmallTest + public void testSelectDomainCs() throws Exception { + DomainSelectionService.SelectionAttributes attributes = + NormalCallDomainSelectionConnection.getSelectionAttributes(mPhone.getPhoneId(), + mPhone.getSubId(), TELECOM_CALL_ID1, "123", false, 0, null); + + CompletableFuture future = + mNormalCallDomainSelectionConnection + .createNormalConnection(attributes, mMockConnectionCallback); + + assertNotNull(future); + assertFalse(future.isDone()); + + verify(mMockDomainSelectionController).selectDomain(any(), any()); + + WwanSelectorCallback wwanCallback = null; + wwanCallback = mTransportCallback.onWwanSelected(); + + assertFalse(future.isDone()); + wwanCallback.onDomainSelected(DOMAIN_CS); + + assertTrue(future.isDone()); + assertEquals((long) DOMAIN_CS, (long) future.get()); + } + + @Test + @SmallTest + public void testSelectDomainPs() throws Exception { + DomainSelectionService.SelectionAttributes attributes = + NormalCallDomainSelectionConnection.getSelectionAttributes(mPhone.getPhoneId(), + mPhone.getSubId(), TELECOM_CALL_ID1, "123", false, 0, null); + + CompletableFuture future = + mNormalCallDomainSelectionConnection + .createNormalConnection(attributes, mMockConnectionCallback); + + assertNotNull(future); + assertFalse(future.isDone()); + + verify(mMockDomainSelectionController).selectDomain(any(), any()); + + WwanSelectorCallback wwanCallback = null; + wwanCallback = mTransportCallback.onWwanSelected(); + + assertFalse(future.isDone()); + wwanCallback.onDomainSelected(DOMAIN_PS); + + assertTrue(future.isDone()); + assertEquals((long) DOMAIN_PS, (long) future.get()); + } + + @Test + @SmallTest + public void testOnSelectionTerminated() throws Exception { + DomainSelectionService.SelectionAttributes attributes = + NormalCallDomainSelectionConnection.getSelectionAttributes(mPhone.getPhoneId(), + mPhone.getSubId(), TELECOM_CALL_ID1, "123", false, 0, null); + + CompletableFuture future = mNormalCallDomainSelectionConnection + .createNormalConnection(attributes, mMockConnectionCallback); + mTransportCallback.onSelectionTerminated(ERROR_UNSPECIFIED); + + verify(mMockConnectionCallback).onSelectionTerminated(eq(ERROR_UNSPECIFIED)); + } + + @Test + public void testGetSelectionAttributes() throws Exception { + ImsReasonInfo imsReasonInfo = new ImsReasonInfo(); + DomainSelectionService.SelectionAttributes attributes = + NormalCallDomainSelectionConnection.getSelectionAttributes(1, 2, + TELECOM_CALL_ID1, "123", false, 10, imsReasonInfo); + + assertEquals(attributes.getSlotId(), 1); + assertEquals(attributes.getSubId(), 2); + assertEquals(attributes.getCallId(), TELECOM_CALL_ID1); + assertEquals(attributes.getNumber(), "123"); + assertEquals(attributes.isVideoCall(), false); + assertEquals(attributes.isEmergency(), false); + assertEquals(attributes.getSelectorType(), SELECTOR_TYPE_CALLING); + assertEquals(attributes.getCsDisconnectCause(), 10); + assertEquals(attributes.getPsDisconnectCause(), imsReasonInfo); + } +} -- GitLab From 7988f17804a9f1337a605245b6017e2ab10223c2 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Wed, 9 Nov 2022 06:55:15 +0000 Subject: [PATCH 281/656] Create a SipDetails file and set it as a variable in ImsRegistrationAttributes In order to more quickly debug issues during the registration, the caller should have access to specific SIP signaling information. To access SIP information, create a class including SIP information and set it as a variable in the class related to IMS registration. Bug: b/238192631 Test: atest ImsRegistrationTests Change-Id: Ic41fe4f88bbbd8d4502516551663763de8a743dc --- .../telephony/ims/ImsRegistrationTests.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java b/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java index 4a445fd075..56ce6bcbc3 100644 --- a/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java +++ b/tests/telephonytests/src/android/telephony/ims/ImsRegistrationTests.java @@ -165,6 +165,21 @@ public class ImsRegistrationTests { eq(SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK), eq(REGISTRATION_TECH_LTE)); } + @SmallTest + @Test + public void testRegistrationCallbackOnDeregisteredWithRegistrationAttributes() + throws RemoteException { + ImsReasonInfo info = new ImsReasonInfo(); + SipDetails details = new SipDetails.Builder(SipDetails.METHOD_REGISTER) + .setCSeq(1).setSipResponseCode(200, "OK") + .setSipResponseReasonHeader(10, "reasonText") + .setCallId("testCallId").build(); + + mRegistration.onDeregistered(info, details); + + verify(mCallback).onDeregisteredWithDetails(eq(info), anyInt(), anyInt(), eq(details)); + } + @SmallTest @Test public void testRegistrationCallbackOnTechChangeFailed() throws RemoteException { -- GitLab From 330de801ae45cf32d9d568540f8bcefa5d9cf208 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 26 Apr 2022 06:24:21 +0000 Subject: [PATCH 282/656] Get LTE attach information from AccessTechnologySpecificInfo Replace DataSpecificRegistrationInfo's constructor with DataSpecificRegistration.Builder. Bug: 219242992 Test: atest ServiceStateTest#testAttachResultTypeInfo Change-Id: I6121ad6004bfc66ef0404290dd006163cebf5e60 --- .../telephony/CellularNetworkService.java | 34 ++++- .../DataSpecificRegistrationInfoTest.java | 80 ++++++++++++ .../NetworkRegistrationInfoTest.java | 52 ++++++++ .../data/DataNetworkControllerTest.java | 120 ++++++++++++------ .../telephony/data/DataNetworkTest.java | 40 ++++-- 5 files changed, 273 insertions(+), 53 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/DataSpecificRegistrationInfoTest.java diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java index 19a585d319..bd47d3d399 100644 --- a/src/java/com/android/internal/telephony/CellularNetworkService.java +++ b/src/java/com/android/internal/telephony/CellularNetworkService.java @@ -18,9 +18,9 @@ package com.android.internal.telephony; import android.annotation.NonNull; import android.annotation.Nullable; -import android.hardware.radio.V1_0.RegState; import android.hardware.radio.V1_4.DataRegStateResult.VopsInfo.hidl_discriminator; import android.hardware.radio.V1_6.RegStateResult.AccessTechnologySpecificInfo; +import android.hardware.radio.network.RegState; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; @@ -35,6 +35,7 @@ import android.telephony.CellIdentityLte; import android.telephony.CellIdentityNr; import android.telephony.CellIdentityTdscdma; import android.telephony.CellIdentityWcdma; +import android.telephony.DataSpecificRegistrationInfo; import android.telephony.LteVopsSupportInfo; import android.telephony.NetworkRegistrationInfo; import android.telephony.NetworkService; @@ -190,6 +191,8 @@ public class CellularNetworkService extends NetworkService { return NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN; case RegState.REG_ROAMING: return NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; + case RegState.REG_EM: + return NetworkRegistrationInfo.REGISTRATION_STATE_EMERGENCY; default: return NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; } @@ -201,6 +204,7 @@ public class CellularNetworkService extends NetworkService { case RegState.NOT_REG_MT_SEARCHING_OP_EM: case RegState.REG_DENIED_EM: case RegState.UNKNOWN_EM: + case RegState.REG_EM: return true; case RegState.NOT_REG_MT_NOT_SEARCHING_OP: case RegState.REG_HOME: @@ -514,6 +518,8 @@ public class CellularNetworkService extends NetworkService { boolean isNrAvailable = false; boolean isDcNrRestricted = false; VopsSupportInfo vopsInfo = null; + int lteAttachResultType = 0; + int lteAttachExtraInfo = 0; android.hardware.radio.network.AccessTechnologySpecificInfo info = regResult.accessTechnologySpecificInfo; @@ -532,6 +538,8 @@ public class CellularNetworkService extends NetworkService { vopsInfo = convertHalLteVopsSupportInfo( info.getEutranInfo().lteVopsInfo.isVopsSupported, info.getEutranInfo().lteVopsInfo.isEmcBearerSupported); + lteAttachResultType = info.getEutranInfo().lteAttachResultType; + lteAttachExtraInfo = info.getEutranInfo().extraInfo; break; case android.hardware.radio.network.AccessTechnologySpecificInfo.ngranNrVopsInfo: vopsInfo = new NrVopsSupportInfo(info.getNgranNrVopsInfo().vopsSupported, @@ -557,10 +565,26 @@ public class CellularNetworkService extends NetworkService { loge("Unknown domain passed to CellularNetworkService= " + domain); // fall through case NetworkRegistrationInfo.DOMAIN_PS: - return new NetworkRegistrationInfo(domain, transportType, regState, networkType, - reasonForDenial, isEmergencyOnly, availableServices, cellIdentity, - rplmn, MAX_DATA_CALLS, isDcNrRestricted, isNrAvailable, isEndcAvailable, - vopsInfo); + return new NetworkRegistrationInfo.Builder() + .setDomain(domain) + .setTransportType(transportType) + .setRegistrationState(regState) + .setAccessNetworkTechnology(networkType) + .setRejectCause(reasonForDenial) + .setEmergencyOnly(isEmergencyOnly) + .setAvailableServices(availableServices) + .setCellIdentity(cellIdentity) + .setRegisteredPlmn(rplmn) + .setDataSpecificInfo( + new DataSpecificRegistrationInfo.Builder(MAX_DATA_CALLS) + .setDcNrRestricted(isDcNrRestricted) + .setNrAvailable(isNrAvailable) + .setEnDcAvailable(isEndcAvailable) + .setVopsSupportInfo(vopsInfo) + .setLteAttachResultType(lteAttachResultType) + .setLteAttachExtraInfo(lteAttachExtraInfo) + .build()) + .build(); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/DataSpecificRegistrationInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/DataSpecificRegistrationInfoTest.java new file mode 100644 index 0000000000..50390ccd9c --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/DataSpecificRegistrationInfoTest.java @@ -0,0 +1,80 @@ +/* + * Copyright 2022 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; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; + +import android.os.Parcel; +import android.telephony.DataSpecificRegistrationInfo; +import android.telephony.LteVopsSupportInfo; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** Unit tests for {@link DataSpecificRegistrationInfo}. */ +public class DataSpecificRegistrationInfoTest { + @Test + @SmallTest + public void testBuilder() { + DataSpecificRegistrationInfo dsri = + new DataSpecificRegistrationInfo.Builder(3) + .setNrAvailable(true) + .setEnDcAvailable(true) + .build(); + + assertEquals(3, dsri.maxDataCalls); + assertEquals(false, dsri.isDcNrRestricted); + assertEquals(true, dsri.isNrAvailable); + assertEquals(true, dsri.isEnDcAvailable); + assertNull(dsri.getVopsSupportInfo()); + + LteVopsSupportInfo vopsInfo = new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, LteVopsSupportInfo.LTE_STATUS_SUPPORTED); + dsri = new DataSpecificRegistrationInfo.Builder(5) + .setDcNrRestricted(true) + .setVopsSupportInfo(vopsInfo) + .build(); + + assertEquals(5, dsri.maxDataCalls); + assertEquals(true, dsri.isDcNrRestricted); + assertEquals(false, dsri.isNrAvailable); + assertEquals(false, dsri.isEnDcAvailable); + assertEquals(vopsInfo, dsri.getVopsSupportInfo()); + } + + @Test + @SmallTest + public void testParcel() { + DataSpecificRegistrationInfo dsri = + new DataSpecificRegistrationInfo.Builder(3) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setLteAttachResultType(DataSpecificRegistrationInfo.LTE_ATTACH_TYPE_COMBINED) + .setLteAttachExtraInfo(DataSpecificRegistrationInfo.LTE_ATTACH_EXTRA_INFO_SMS_ONLY) + .build(); + + Parcel p = Parcel.obtain(); + dsri.writeToParcel(p, 0); + p.setDataPosition(0); + + DataSpecificRegistrationInfo newDsri = + DataSpecificRegistrationInfo.CREATOR.createFromParcel(p); + assertEquals(dsri, newDsri); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationInfoTest.java index 3d5379c2da..30cbfb3ece 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationInfoTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationInfoTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import static junit.framework.Assert.assertEquals; +import android.compat.testing.PlatformCompatChangeRule; import android.os.Parcel; import android.telephony.AccessNetworkConstants; import android.telephony.CellIdentityLte; @@ -27,13 +28,21 @@ import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; +import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import java.util.Arrays; /** Unit tests for {@link NetworkRegistrationInfo}. */ public class NetworkRegistrationInfoTest { + @Rule + public TestRule compatChangeRule = new PlatformCompatChangeRule(); + @Test @SmallTest public void testParcel() { @@ -87,4 +96,47 @@ public class NetworkRegistrationInfoTest { assertEquals(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING, nri.getInitialRegistrationState()); } + + @Test + @DisableCompatChanges({NetworkRegistrationInfo.RETURN_REGISTRATION_STATE_EMERGENCY}) + public void testReturnRegistrationStateEmergencyDisabled() { + // LTE + NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_EMERGENCY) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .build(); + + assertEquals(NetworkRegistrationInfo.REGISTRATION_STATE_DENIED, nri.getRegistrationState()); + + // NR + nri = new NetworkRegistrationInfo.Builder() + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_EMERGENCY) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) + .build(); + + assertEquals(NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, + nri.getRegistrationState()); + } + + @Test + @EnableCompatChanges({NetworkRegistrationInfo.RETURN_REGISTRATION_STATE_EMERGENCY}) + public void testReturnRegistrationStateEmergencyEnabled() { + // LTE + NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_EMERGENCY) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .build(); + + assertEquals(NetworkRegistrationInfo.REGISTRATION_STATE_EMERGENCY, + nri.getRegistrationState()); + + // NR + nri = new NetworkRegistrationInfo.Builder() + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_EMERGENCY) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) + .build(); + + assertEquals(NetworkRegistrationInfo.REGISTRATION_STATE_EMERGENCY, + nri.getRegistrationState()); + } } 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 a967539175..48c9d92d9f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -509,9 +509,13 @@ public class DataNetworkControllerTest extends TelephonyTest { private void serviceStateChanged(@NetworkType int networkType, @RegistrationState int regState) { - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) + .build(); serviceStateChanged(networkType, regState, regState, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); @@ -541,9 +545,13 @@ public class DataNetworkControllerTest extends TelephonyTest { @RegistrationState int dataRegState, @RegistrationState int voiceRegState, @RegistrationState int iwlanRegState, DataSpecificRegistrationInfo dsri) { if (dsri == null) { - dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); + dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) + .build(); } ServiceState ss = new ServiceState(); @@ -3030,9 +3038,13 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testNonVoPSNoIMSSetup() throws Exception { - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) + .build(); serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); @@ -3052,9 +3064,13 @@ public class DataNetworkControllerTest extends TelephonyTest { carrierConfigChanged(); // VOPS not supported - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) + .build(); serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); @@ -3065,9 +3081,13 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); // VoPS supported - dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); + dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) + .build(); serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); @@ -3507,9 +3527,13 @@ public class DataNetworkControllerTest extends TelephonyTest { public void testHandoverDataNetworkNonVops() throws Exception { ServiceState ss = new ServiceState(); - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) + .build(); ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) @@ -3570,9 +3594,13 @@ public class DataNetworkControllerTest extends TelephonyTest { ServiceState ss = new ServiceState(); - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) + .build(); ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) @@ -3630,9 +3658,13 @@ public class DataNetworkControllerTest extends TelephonyTest { public void testNonMmtelImsHandoverDataNetworkNonVops() throws Exception { ServiceState ss = new ServiceState(); - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) + .build(); ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) @@ -3698,9 +3730,13 @@ public class DataNetworkControllerTest extends TelephonyTest { ServiceState ss = new ServiceState(); // VoPS network - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) + .build(); ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) @@ -3745,9 +3781,13 @@ public class DataNetworkControllerTest extends TelephonyTest { ss = new ServiceState(); // Non VoPS network - dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); + dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) + .build(); ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) @@ -3799,9 +3839,13 @@ public class DataNetworkControllerTest extends TelephonyTest { carrierConfigChanged(); // VoPS supported - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) + .build(); serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); @@ -3813,9 +3857,13 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(PhoneConstants.State.OFFHOOK).when(mCT).getState(); - dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); + dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) + .build(); serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); 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 f6edd768fa..d13fb76d75 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -471,9 +471,13 @@ public class DataNetworkTest extends TelephonyTest { @Test public void testCreateDataNetworkWhenOos() throws Exception { - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) + .build(); // Out of service serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, dsri); @@ -513,9 +517,13 @@ public class DataNetworkTest extends TelephonyTest { public void testRecreateAgentWhenOos() throws Exception { testCreateDataNetwork(); - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) + .build(); // Out of service serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, dsri); @@ -1363,9 +1371,13 @@ public class DataNetworkTest extends TelephonyTest { @Test public void testMovingToNonVops() throws Exception { - DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_SUPPORTED)); + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) + .build(); serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); testCreateImsDataNetwork(); @@ -1373,9 +1385,13 @@ public class DataNetworkTest extends TelephonyTest { assertThat(mDataNetworkUT.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_MMTEL)).isTrue(); - dsri = new DataSpecificRegistrationInfo(8, false, true, true, - new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, - LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)); + dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED)) + .build(); logd("Trigger non VoPS"); serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, dsri); -- GitLab From 069c6b4410e66746d3bb460ffb8a223987a204a8 Mon Sep 17 00:00:00 2001 From: sangyun Date: Tue, 15 Nov 2022 14:42:57 +0900 Subject: [PATCH 283/656] Explicitly use overridden or non-overridden roaming state. - Deliver the overridden boolean isRoaming to TelephonyDisplayInfo. - Use the non-overridden registration state from network instead of the initial registration state. Bug: 260017781 Test: atest DisplayInfoControllerTest Change-Id: I1e54aafcca9e720d9a9fe718553e6f13cef1922b --- .../telephony/DisplayInfoController.java | 27 +- .../telephony/ServiceStateTracker.java | 14 +- .../telephony/DisplayInfoControllerTest.java | 280 ++++++++++++++++++ .../NetworkRegistrationInfoTest.java | 2 +- .../telephony/TelephonyRegistryTest.java | 15 +- .../internal/telephony/TelephonyTest.java | 2 +- .../data/DataNetworkControllerTest.java | 6 +- 7 files changed, 328 insertions(+), 18 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java diff --git a/src/java/com/android/internal/telephony/DisplayInfoController.java b/src/java/com/android/internal/telephony/DisplayInfoController.java index 4a52a10ad0..597ae90bd9 100644 --- a/src/java/com/android/internal/telephony/DisplayInfoController.java +++ b/src/java/com/android/internal/telephony/DisplayInfoController.java @@ -18,9 +18,11 @@ package com.android.internal.telephony; import android.annotation.NonNull; import android.os.Handler; +import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.telephony.AnomalyReporter; +import android.telephony.ServiceState; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.util.IndentingPrintWriter; @@ -62,10 +64,14 @@ public class DisplayInfoController extends Handler { TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) ); + /** Event for service state changed (roaming). */ + private static final int EVENT_SERVICE_STATE_CHANGED = 1; + private final Phone mPhone; private final NetworkTypeController mNetworkTypeController; private final RegistrantList mTelephonyDisplayInfoChangedRegistrants = new RegistrantList(); private @NonNull TelephonyDisplayInfo mTelephonyDisplayInfo; + private @NonNull ServiceState mServiceState; public DisplayInfoController(Phone phone) { mPhone = phone; @@ -75,6 +81,13 @@ public class DisplayInfoController extends Handler { TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); mNetworkTypeController = new NetworkTypeController(phone, this); mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + + mServiceState = mPhone.getServiceStateTracker().getServiceState(); + post(() -> { + mPhone.getServiceStateTracker() + .registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); + updateTelephonyDisplayInfo(); + }); } /** @@ -91,7 +104,8 @@ public class DisplayInfoController extends Handler { public void updateTelephonyDisplayInfo() { TelephonyDisplayInfo newDisplayInfo = new TelephonyDisplayInfo( mNetworkTypeController.getDataNetworkType(), - mNetworkTypeController.getOverrideNetworkType()); + mNetworkTypeController.getOverrideNetworkType(), + mServiceState.getRoaming()); if (!newDisplayInfo.equals(mTelephonyDisplayInfo)) { logl("TelephonyDisplayInfo changed from " + mTelephonyDisplayInfo + " to " + newDisplayInfo); @@ -153,6 +167,17 @@ public class DisplayInfoController extends Handler { mTelephonyDisplayInfoChangedRegistrants.remove(h); } + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_SERVICE_STATE_CHANGED: + mServiceState = mPhone.getServiceStateTracker().getServiceState(); + log("ServiceState updated, isRoaming=" + mServiceState.getRoaming()); + updateTelephonyDisplayInfo(); + break; + } + } + /** * Log debug messages. * @param s debug messages diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index bb291c5e32..9c7178a63d 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -908,7 +908,7 @@ public class ServiceStateTracker extends Handler { if (nrs != null) { int rat = ServiceState.networkTypeToRilRadioTechnology( nrs.getAccessNetworkTechnology()); - int drs = regCodeToServiceState(nrs.getInitialRegistrationState()); + int drs = regCodeToServiceState(nrs.getNetworkRegistrationState()); return new Pair<>(drs, rat); } return null; @@ -2161,14 +2161,14 @@ public class ServiceStateTracker extends Handler { if (wlanPsRegState != null && wlanPsRegState.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN - && wlanPsRegState.getInitialRegistrationState() + && wlanPsRegState.getNetworkRegistrationState() == NetworkRegistrationInfo.REGISTRATION_STATE_HOME && isIwlanPreferred) { serviceState.setDataRegState(ServiceState.STATE_IN_SERVICE); } else if (wwanPsRegState != null) { // If the device is not camped on IWLAN, then we use cellular PS registration state // to compute reg state and rat. - int regState = wwanPsRegState.getInitialRegistrationState(); + int regState = wwanPsRegState.getNetworkRegistrationState(); serviceState.setDataRegState(regCodeToServiceState(regState)); } if (DBG) { @@ -2184,7 +2184,7 @@ public class ServiceStateTracker extends Handler { VoiceSpecificRegistrationInfo voiceSpecificStates = networkRegState.getVoiceSpecificInfo(); - int registrationState = networkRegState.getInitialRegistrationState(); + int registrationState = networkRegState.getNetworkRegistrationState(); int cssIndicator = voiceSpecificStates.cssSupported ? 1 : 0; mNewSS.setVoiceRegState(regCodeToServiceState(registrationState)); mNewSS.setCssIndicator(cssIndicator); @@ -2264,7 +2264,7 @@ public class ServiceStateTracker extends Handler { mNewSS.addNetworkRegistrationInfo(networkRegState); DataSpecificRegistrationInfo dataSpecificStates = networkRegState.getDataSpecificInfo(); - int registrationState = networkRegState.getInitialRegistrationState(); + int registrationState = networkRegState.getNetworkRegistrationState(); int serviceState = regCodeToServiceState(registrationState); int newDataRat = ServiceState.networkTypeToRilRadioTechnology( networkRegState.getAccessNetworkTechnology()); @@ -3485,9 +3485,9 @@ public class ServiceStateTracker extends Handler { anyDataRatChanged = true; } - int oldRegState = oldNrs != null ? oldNrs.getInitialRegistrationState() + int oldRegState = oldNrs != null ? oldNrs.getNetworkRegistrationState() : NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN; - int newRegState = newNrs != null ? newNrs.getInitialRegistrationState() + int newRegState = newNrs != null ? newNrs.getNetworkRegistrationState() : NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN; hasDataRegStateChanged.put(transport, oldRegState != newRegState); if (oldRegState != newRegState) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java new file mode 100644 index 0000000000..fa00362c1e --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2020 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; + +import static org.junit.Assert.assertFalse; +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.when; + +import android.content.Context; +import android.content.Intent; +import android.os.AsyncResult; +import android.os.HandlerThread; +import android.os.PersistableBundle; +import android.telephony.AccessNetworkConstants; +import android.telephony.CarrierConfigManager; +import android.telephony.CellIdentity; +import android.telephony.CellIdentityCdma; +import android.telephony.CellIdentityLte; +import android.telephony.LteVopsSupportInfo; +import android.telephony.NetworkRegistrationInfo; +import android.telephony.ServiceState; +import android.telephony.TelephonyDisplayInfo; +import android.telephony.TelephonyManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.text.TextUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +import java.util.Collections; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DisplayInfoControllerTest extends TelephonyTest { + + private static final int PHONE_ID = 0; + private static final String MCC = "600"; + private static final String MNC = "01"; + private static final String NUMERIC = MCC + MNC; + private static final String NETWORK = "TestNet"; + + private DisplayInfoController mDic; + private ServiceStateTracker mSst; + private ServiceStateTrackerTestHandler mSstHandler; + private SignalStrengthController mSsc; + private PersistableBundle mBundle; + + private class ServiceStateTrackerTestHandler extends HandlerThread { + private ServiceStateTrackerTestHandler(String name) { + super(name); + } + + @Override + public void onLooperPrepared() { + mSsc = new SignalStrengthController(mPhone); + doReturn(mSsc).when(mPhone).getSignalStrengthController(); + doReturn(new ServiceState()).when(mPhone).getServiceState(); + doReturn(NUMERIC).when(mTelephonyManager).getSimOperatorNumericForPhone(eq(PHONE_ID)); + doReturn(NETWORK).when(mTelephonyManager).getSimOperatorNameForPhone(eq(PHONE_ID)); + + mSst = new ServiceStateTracker(mPhone, mSimulatedCommands); + doReturn(mSst).when(mPhone).getServiceStateTracker(); + setReady(true); + } + } + + @Before + public void setUp() throws Exception { + logd("DisplayInfoControllerTest setup!"); + super.setUp(getClass().getSimpleName()); + + mSstHandler = new ServiceStateTrackerTestHandler(getClass().getSimpleName()); + mSstHandler.start(); + waitUntilReady(); + waitForLastHandlerAction(mSstHandler.getThreadHandler()); + } + + @After + public void tearDown() throws Exception { + mSst.removeCallbacksAndMessages(null); + mSst = null; + mSstHandler.quit(); + mSstHandler.join(); + mSstHandler = null; + mBundle = null; + super.tearDown(); + } + + private void sendCarrierConfigUpdate() { + CarrierConfigManager mockConfigManager = Mockito.mock(CarrierConfigManager.class); + when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) + .thenReturn(mockConfigManager); + when(mockConfigManager.getConfigForSubId(anyInt())).thenReturn(mBundle); + + Intent intent = new Intent().setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, PHONE_ID); + mContext.sendBroadcast(intent); + waitForLastHandlerAction(mSstHandler.getThreadHandler()); + } + + private static String getPlmnFromCellIdentity(final CellIdentity ci) { + if (ci == null || ci instanceof CellIdentityCdma) return ""; + + final String mcc = ci.getMccString(); + final String mnc = ci.getMncString(); + + if (TextUtils.isEmpty(mcc) || TextUtils.isEmpty(mnc)) return ""; + + return mcc + mnc; + } + + private void changeRegState(int state) { + int voiceRat = TelephonyManager.NETWORK_TYPE_LTE; + int dataRat = TelephonyManager.NETWORK_TYPE_LTE; + CellIdentityLte cid = + new CellIdentityLte(1, 1, 5, 1, new int[] {1, 2}, 5000, + MCC, MNC, NETWORK, NETWORK, Collections.emptyList(), null); + LteVopsSupportInfo lteVopsSupportInfo = + new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED); + waitForLastHandlerAction(mSstHandler.getThreadHandler()); + NetworkRegistrationInfo dataResult = new NetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + state, dataRat, 0, false, null, cid, getPlmnFromCellIdentity(cid), 1, false, false, + false, lteVopsSupportInfo); + mSst.mPollingContext[0] = 3; + final String[] oldOpNamesResult = new String[] {"test", "test", NUMERIC}; + mSst.sendMessage( + mSst.obtainMessage( + ServiceStateTracker.EVENT_POLL_STATE_OPERATOR, + new AsyncResult(mSst.mPollingContext, oldOpNamesResult, null))); + waitForLastHandlerAction(mSstHandler.getThreadHandler()); + // update data reg state to be in service + mSst.sendMessage( + mSst.obtainMessage( + ServiceStateTracker.EVENT_POLL_STATE_PS_CELLULAR_REGISTRATION, + new AsyncResult(mSst.mPollingContext, dataResult, null))); + waitForLastHandlerAction(mSstHandler.getThreadHandler()); + NetworkRegistrationInfo voiceResult = new NetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + state, voiceRat, 0, false, null, cid, getPlmnFromCellIdentity(cid), false, 0, 0, 0); + mSst.sendMessage( + mSst.obtainMessage( + ServiceStateTracker.EVENT_POLL_STATE_CS_CELLULAR_REGISTRATION, + new AsyncResult(mSst.mPollingContext, voiceResult, null))); + waitForLastHandlerAction(mSstHandler.getThreadHandler()); + } + + @Test + public void testIsRoamingOverride_NonRoamingOperator() { + doReturn(true).when(mPhone).isPhoneTypeGsm(); + + mBundle = mContextFixture.getCarrierConfigBundle(); + mBundle.putStringArray( + CarrierConfigManager.KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, new String[] {NUMERIC}); + sendCarrierConfigUpdate(); + + changeRegState(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + ServiceState ss = mSst.getServiceState(); + + assertFalse(ss.getRoaming()); // home + + doReturn(mSst).when(mPhone).getServiceStateTracker(); + mDic = new DisplayInfoController(mPhone); + mDic.updateTelephonyDisplayInfo(); + TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); + + assertFalse(tdi.isRoaming()); + } + + @Test + public void testIsRoamingOverride_ForceHomeNetwork() { + doReturn(true).when(mPhone).isPhoneTypeGsm(); + + mBundle = mContextFixture.getCarrierConfigBundle(); + mBundle.putBoolean(CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL, true); + sendCarrierConfigUpdate(); + + changeRegState(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + ServiceState ss = mSst.getServiceState(); + + assertFalse(ss.getRoaming()); // home + + doReturn(mSst).when(mPhone).getServiceStateTracker(); + mDic = new DisplayInfoController(mPhone); + mDic.updateTelephonyDisplayInfo(); + TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); + + assertFalse(tdi.isRoaming()); + } + + @Test + public void testIsRoamingOverride_RoamingOperator() { + doReturn(true).when(mPhone).isPhoneTypeGsm(); + + mBundle = mContextFixture.getCarrierConfigBundle(); + mBundle.putStringArray( + CarrierConfigManager.KEY_ROAMING_OPERATOR_STRING_ARRAY, new String[] {"60101"}); + sendCarrierConfigUpdate(); + + changeRegState(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + ServiceState ss1 = mSst.getServiceState(); + + assertTrue(ss1.getRoaming()); // roam + + doReturn(mSst).when(mPhone).getServiceStateTracker(); + mDic = new DisplayInfoController(mPhone); + mDic.updateTelephonyDisplayInfo(); + TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); + + assertTrue(tdi.isRoaming()); + } + + @Test + public void testIsRoamingOverride_NonRoamingGsmOperator() { + doReturn(true).when(mPhone).isPhoneTypeGsm(); + + mBundle = mContextFixture.getCarrierConfigBundle(); + mBundle.putStringArray( + CarrierConfigManager.KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, + new String[] {NUMERIC}); + sendCarrierConfigUpdate(); + + changeRegState(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + ServiceState ss = mSst.getServiceState(); + + assertFalse(ss.getRoaming()); // home + + doReturn(mSst).when(mPhone).getServiceStateTracker(); + mDic = new DisplayInfoController(mPhone); + mDic.updateTelephonyDisplayInfo(); + TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); + + assertFalse(tdi.isRoaming()); + } + + @Test + public void testIsRoamingOverride_RoamingGsmOperator() { + doReturn(true).when(mPhone).isPhoneTypeGsm(); + + mBundle = mContextFixture.getCarrierConfigBundle(); + mBundle.putStringArray( + CarrierConfigManager.KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, new String[] {NUMERIC}); + sendCarrierConfigUpdate(); + + changeRegState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + ServiceState ss1 = mSst.getServiceState(); + + assertTrue(ss1.getRoaming()); // roam + + doReturn(mSst).when(mPhone).getServiceStateTracker(); + mDic = new DisplayInfoController(mPhone); + mDic.updateTelephonyDisplayInfo(); + TelephonyDisplayInfo tdi = mDic.getTelephonyDisplayInfo(); + + assertTrue(tdi.isRoaming()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationInfoTest.java index 3d5379c2da..a275bb8b59 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationInfoTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkRegistrationInfoTest.java @@ -85,6 +85,6 @@ public class NetworkRegistrationInfoTest { nri.setRoamingType(ServiceState.ROAMING_TYPE_NOT_ROAMING); assertEquals(NetworkRegistrationInfo.REGISTRATION_STATE_HOME, nri.getRegistrationState()); assertEquals(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING, - nri.getInitialRegistrationState()); + nri.getNetworkRegistrationState()); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java index 0a5a2ea7b1..91dd89d50d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java @@ -1070,7 +1070,8 @@ public class TelephonyRegistryTest extends TelephonyTest { anyString(), any())).thenReturn(true); TelephonyDisplayInfo displayInfo = new TelephonyDisplayInfo( TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED); + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, + false); // Notify with invalid subId on default phone. Should NOT trigger callback. mTelephonyRegistry.notifyDisplayInfoChanged(0, INVALID_SUBSCRIPTION_ID, displayInfo); @@ -1096,10 +1097,12 @@ public class TelephonyRegistryTest extends TelephonyTest { anyString(), any())).thenReturn(false); TelephonyDisplayInfo displayInfo = new TelephonyDisplayInfo( TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED); + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, + false); TelephonyDisplayInfo expectDisplayInfo = new TelephonyDisplayInfo( TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE); + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE, + false); // Notify with invalid subId on default phone. Should NOT trigger callback. mTelephonyRegistry.notifyDisplayInfoChanged(0, INVALID_SUBSCRIPTION_ID, displayInfo); @@ -1121,10 +1124,12 @@ public class TelephonyRegistryTest extends TelephonyTest { int[] events = {TelephonyCallback.EVENT_DISPLAY_INFO_CHANGED}; TelephonyDisplayInfo displayInfo = new TelephonyDisplayInfo( TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED); + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, + false); TelephonyDisplayInfo expectDisplayInfo = new TelephonyDisplayInfo( TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE); + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE, + false); TelephonyCallback telephonyCallback2 = new TelephonyCallbackWrapper() { @Override public void onDisplayInfoChanged(TelephonyDisplayInfo displayInfoNotify) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 3e79ac00fa..9465bb6138 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -697,7 +697,7 @@ public abstract class TelephonyTest { doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState) .getRilDataRadioTechnology(); doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false)) .when(mDisplayInfoController).getTelephonyDisplayInfo(); doReturn(mPhone).when(mCT).getPhone(); doReturn(mImsEcbm).when(mImsManager).getEcbmInterface(); 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 a967539175..db66d0cb1f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -1907,7 +1907,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Change data network type to NR doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_NR, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false)) .when(mDisplayInfoController).getTelephonyDisplayInfo(); dataNetwork.sendMessage(13/*EVENT_DISPLAY_INFO_CHANGED*/); processAllMessages(); @@ -1950,7 +1950,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Change data network type to NR doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_NR, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false)) .when(mDisplayInfoController).getTelephonyDisplayInfo(); dataNetwork.sendMessage(13/*EVENT_DISPLAY_INFO_CHANGED*/); processAllMessages(); @@ -2006,7 +2006,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Change data network type to NR doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_NR, - TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE)) + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, false)) .when(mDisplayInfoController).getTelephonyDisplayInfo(); dataNetwork.sendMessage(13/*EVENT_DISPLAY_INFO_CHANGED*/); processAllMessages(); -- GitLab From 430e92f2e469eaed014c5ea3576b727b939de5e5 Mon Sep 17 00:00:00 2001 From: Gil Cukierman Date: Thu, 15 Dec 2022 20:52:02 +0000 Subject: [PATCH 284/656] Honor Feature Flag When Updating Null Cipher Settings When a GsmCdmaPhone instance is asked to handle a null cipher update, it will first check the cellular_security namespace for the enable_null_cipher_toggle flag. If the flag is false (the default), no command will be sent through the RIL to the modem. When the feature flag is set to false after previously having been set to true (feature disablement), the user's device will maintain the behavior of the active setting until the modem reboots. Since one reason we may want to disable this feature is an issue in the HAL integration itself, it could be unsafe to try and call the modem to reset state, so we implement the simpler and safer option. Bug: b/262063470 Test: atest GsmCdmaPhoneTest Change-Id: I0ab9f118ef2df816c3b878c3a34d60f1c35518ab --- .../internal/telephony/GsmCdmaPhone.java | 6 +++ .../internal/telephony/ContextFixture.java | 5 ++ .../internal/telephony/GsmCdmaPhoneTest.java | 47 +++++++++++++++++-- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 37b7509c8f..cf743835e1 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -59,6 +59,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; import android.preference.PreferenceManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Telephony; import android.sysprop.TelephonyProperties; @@ -4995,6 +4996,11 @@ public class GsmCdmaPhone extends Phone { @Override public void handleNullCipherEnabledChange() { + if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CELLULAR_SECURITY, + TelephonyManager.PROPERTY_ENABLE_NULL_CIPHER_TOGGLE, false)) { + logi("Not handling null cipher update. Feature disabled by DeviceConfig."); + return; + } mCi.setNullCipherAndIntegrityEnabled( getNullCipherAndIntegrityEnabledPreference(), obtainMessage(EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE)); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java index 82ade7388e..23fc448c08 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java @@ -176,6 +176,11 @@ public class ContextFixture implements TestFixture { mKeyValuePairs.put(request, (String)args.get("value")); mNumKeyValuePairs++; break; + case Settings.CALL_METHOD_PUT_CONFIG: + logd("PUT_config called"); + logd("adding config flag: " + request + "-" + args.getString("value")); + mFlags.put(request, args.getString("value")); + break; case Settings.CALL_METHOD_LIST_CONFIG: logd("LIST_config: " + mFlags); Bundle result = new Bundle(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 33531f72fb..ae8f12af75 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -61,6 +61,7 @@ import android.os.PersistableBundle; import android.os.Process; import android.os.WorkSource; import android.preference.PreferenceManager; +import android.provider.DeviceConfig; import android.telecom.VideoProfile; import android.telephony.AccessNetworkConstants; import android.telephony.CarrierConfigManager; @@ -79,6 +80,7 @@ import android.telephony.ims.stub.ImsRegistrationImplBase; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.Log; import androidx.test.filters.FlakyTest; @@ -115,6 +117,7 @@ import java.util.List; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class GsmCdmaPhoneTest extends TelephonyTest { + private static final String LOG_TAG = "GsmCdmaPhoneTest"; private static final String TEST_EMERGENCY_NUMBER = "555"; // Mocked classes @@ -126,6 +129,11 @@ public class GsmCdmaPhoneTest extends TelephonyTest { //mPhoneUnderTest private GsmCdmaPhone mPhoneUT; + // Ideally we would use TestableDeviceConfig, but that's not doable because the Settings + // app is not currently debuggable. For now, we use the real device config and ensure that + // we reset the cellular_security namespace property to its pre-test value after every test. + private DeviceConfig.Properties mPreTestProperties; + private static final int EVENT_EMERGENCY_CALLBACK_MODE_EXIT = 1; private static final int EVENT_EMERGENCY_CALL_TOGGLE = 2; private static final int EVENT_SET_ICC_LOCK_ENABLED = 3; @@ -149,6 +157,8 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + mPreTestProperties = DeviceConfig.getProperties( + TelephonyManager.PROPERTY_ENABLE_NULL_CIPHER_TOGGLE); mTestHandler = Mockito.mock(Handler.class); mUiccSlot = Mockito.mock(UiccSlot.class); mUiccPort = Mockito.mock(UiccPort.class); @@ -173,6 +183,13 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void tearDown() throws Exception { mPhoneUT.removeCallbacksAndMessages(null); mPhoneUT = null; + try { + DeviceConfig.setProperties(mPreTestProperties); + } catch (DeviceConfig.BadConfigException e) { + Log.e(LOG_TAG, + "Failed to reset DeviceConfig to pre-test state. Test results may be impacted. " + + e.getMessage()); + } super.tearDown(); } @@ -2090,12 +2107,34 @@ public class GsmCdmaPhoneTest extends TelephonyTest { } @Test - public void testHandleNullCipherAndIntegrityEnabledOnRadioAvailable() { - GsmCdmaPhone spiedPhone = spy(mPhoneUT); - spiedPhone.sendMessage(spiedPhone.obtainMessage(EVENT_RADIO_AVAILABLE, + public void testHandleNullCipherAndIntegrityEnabled_featureFlagOn() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_CELLULAR_SECURITY, + TelephonyManager.PROPERTY_ENABLE_NULL_CIPHER_TOGGLE, Boolean.TRUE.toString(), + false); + mPhoneUT.mCi = mMockCi; + + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(EVENT_RADIO_AVAILABLE, new AsyncResult(null, new int[]{ServiceState.RIL_RADIO_TECHNOLOGY_GSM}, null))); processAllMessages(); - verify(spiedPhone, times(1)).handleNullCipherEnabledChange(); + + verify(mMockCi, times(1)).setNullCipherAndIntegrityEnabled(anyBoolean(), + any(Message.class)); + } + + @Test + public void testHandleNullCipherAndIntegrityEnabled_featureFlagOff() { + mPhoneUT.mCi = mMockCi; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_CELLULAR_SECURITY, + TelephonyManager.PROPERTY_ENABLE_NULL_CIPHER_TOGGLE, Boolean.FALSE.toString(), + false); + + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(EVENT_RADIO_AVAILABLE, + new AsyncResult(null, new int[]{ServiceState.RIL_RADIO_TECHNOLOGY_GSM}, null))); + processAllMessages(); + + verify(mMockCi, times(0)).setNullCipherAndIntegrityEnabled(anyBoolean(), + any(Message.class)); + } public void fdnCheckCleanup() { -- GitLab From f29c892682610c76f22137a0e498c34fdbad0a6f Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Thu, 15 Dec 2022 22:47:09 +0000 Subject: [PATCH 285/656] Added resource overlay flag to enable/disable getSubscriptionUserHandle api. API is enabled by default. Bug: 250620312 Test: atest FrameworkTelephonyTestCases Change-Id: I69e43883b913e29effa50847268a34fc01f88de4 --- .../telephony/SubscriptionController.java | 6 ++++++ .../subscription/SubscriptionManagerService.java | 6 ++++++ .../telephony/SubscriptionControllerTest.java | 16 ++++++++++++++++ .../SubscriptionManagerServiceTest.java | 7 ++++++- 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 2535b3244a..ab519bbf2b 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -4821,9 +4821,15 @@ public class SubscriptionController extends ISub.Stub { * @throws IllegalArgumentException if subId is invalid. */ @Override + @Nullable public UserHandle getSubscriptionUserHandle(int subId) { enforceManageSubscriptionUserAssociation("getSubscriptionUserHandle"); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_enable_get_subscription_user_handle)) { + return null; + } + long token = Binder.clearCallingIdentity(); try { String userHandleStr = getSubscriptionProperty(subId, SubscriptionManager.USER_HANDLE); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index ea5c020ada..3fad17aba6 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -2988,11 +2988,17 @@ public class SubscriptionManagerService extends ISub.Stub { * @throws IllegalArgumentException if {@code subId} is invalid. */ @Override + @Nullable @RequiresPermission(Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION) public UserHandle getSubscriptionUserHandle(int subId) { enforcePermissions("getSubscriptionUserHandle", Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + if (!mContext.getResources().getBoolean( + com.android.internal.R.bool.config_enable_get_subscription_user_handle)) { + return null; + } + long token = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index 0bb6eb243f..eb628eff56 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -50,6 +50,7 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -2142,6 +2143,7 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test public void setSubscriptionUserHandle_withoutPermission() { testInsertSim(); + enableGetSubscriptionUserHandle(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); @@ -2156,6 +2158,7 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test public void setGetSubscriptionUserHandle_userHandleNull() { testInsertSim(); + enableGetSubscriptionUserHandle(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); @@ -2169,6 +2172,8 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test public void setSubscriptionUserHandle_invalidSubId() { + enableGetSubscriptionUserHandle(); + assertThrows(IllegalArgumentException.class, () -> mSubscriptionControllerUT.setSubscriptionUserHandle( UserHandle.of(UserHandle.USER_SYSTEM), @@ -2178,6 +2183,7 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test public void setGetSubscriptionUserHandle_withValidUserHandleAndSubId() { testInsertSim(); + enableGetSubscriptionUserHandle(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); @@ -2193,6 +2199,7 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test public void getSubscriptionUserHandle_withoutPermission() { testInsertSim(); + enableGetSubscriptionUserHandle(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); @@ -2205,8 +2212,17 @@ public class SubscriptionControllerTest extends TelephonyTest { @Test public void getSubscriptionUserHandle_invalidSubId() { + enableGetSubscriptionUserHandle(); + assertThrows(IllegalArgumentException.class, () -> mSubscriptionControllerUT.getSubscriptionUserHandle( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)); } + + private void enableGetSubscriptionUserHandle() { + Resources mResources = mock(Resources.class); + doReturn(true).when(mResources).getBoolean( + eq(com.android.internal.R.bool.config_enable_get_subscription_user_handle)); + doReturn(mResources).when(mContext).getResources(); + } } \ No newline at end of file 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 0c85582d3d..109d5e40c7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -64,6 +64,7 @@ import android.app.PropertyInvalidatedCache; import android.compat.testing.PlatformCompatChangeRule; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.os.Build; import android.os.Bundle; import android.os.Looper; @@ -916,8 +917,12 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetGetSubscriptionUserHandle() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); + Resources mResources = Mockito.mock(Resources.class); + doReturn(true).when(mResources).getBoolean( + eq(com.android.internal.R.bool.config_enable_get_subscription_user_handle)); + doReturn(mResources).when(mContext).getResources(); - // Should fail without MODIFY_PHONE_STATE + // Should fail without MANAGE_SUBSCRIPTION_USER_ASSOCIATION assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT .setSubscriptionUserHandle(new UserHandle(12), 1)); -- GitLab From 1cc844a3e81839c81022b1d314b2565824e53a83 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 29 Mar 2022 15:42:05 +0000 Subject: [PATCH 286/656] Notifies the IMS traffic activities to modem Bug: 219242095 Test: atest CtsTelephonyTestCases:MmTelFeatureTestOnMockModem Change-Id: I8dc3778e7fd84e349a70b6691ae101eddd9eab17 --- .../internal/telephony/CommandsInterface.java | 11 +- .../internal/telephony/ImsIndication.java | 10 +- .../internal/telephony/ImsResponse.java | 14 +- .../com/android/internal/telephony/Phone.java | 47 ++++++ .../com/android/internal/telephony/RIL.java | 32 ++++- .../android/internal/telephony/RILUtils.java | 79 ++++++++++ .../internal/telephony/imsphone/ImsPhone.java | 24 ++++ .../imsphone/ImsPhoneCallTracker.java | 136 ++++++++++++++++++ .../imsphone/ImsPhoneCallTrackerTest.java | 69 +++++++++ 9 files changed, 400 insertions(+), 22 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 3517b21afd..e45852f6ed 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -43,6 +43,7 @@ import android.telephony.data.NetworkSliceInfo; import android.telephony.data.TrafficDescriptor; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RegistrationManager; +import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; @@ -2783,7 +2784,7 @@ public interface CommandsInterface { public void unregisterForSimPhonebookRecordsReceived(Handler h); /** - * Registers for notifications when connection setup fails. + * Registers for notifications of connection setup failure. * * @param h Handler for notification message. * @param what User-defined message code. @@ -2792,7 +2793,7 @@ public interface CommandsInterface { default void registerForConnectionSetupFailure(Handler h, int what, Object obj) {} /** - * Unregisters for notifications when connection setup fails. + * Unregisters for notifications of connection setup failure. * * @param h Handler to be removed from the registrant list. */ @@ -2928,9 +2929,13 @@ public interface CommandsInterface { * @param token A nonce to identify the request. * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. * @param accessNetworkType The type of underlying radio access network used. + * @param trafficDirection Indicates whether traffic is originated by mobile originated or + * mobile terminated use case eg. MO/MT call/SMS etc. */ - default void startImsTraffic(int token, int trafficType, + default void startImsTraffic(int token, + @MmTelFeature.ImsTrafficType int trafficType, @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, + @MmTelFeature.ImsTrafficDirection int trafficDirection, Message result) {} /** diff --git a/src/java/com/android/internal/telephony/ImsIndication.java b/src/java/com/android/internal/telephony/ImsIndication.java index 65540efdd8..00652f888d 100644 --- a/src/java/com/android/internal/telephony/ImsIndication.java +++ b/src/java/com/android/internal/telephony/ImsIndication.java @@ -24,6 +24,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_TRIGGER_IMS_ import android.hardware.radio.ims.IRadioImsIndication; import android.os.AsyncResult; +import android.telephony.ims.feature.ConnectionFailureInfo; /** * Interface declaring unsolicited radio indications for IMS APIs. @@ -57,14 +58,11 @@ public class ImsIndication extends IRadioImsIndication.Stub { android.hardware.radio.ims.ConnectionFailureInfo failureInfo) { mRil.processIndication(HAL_SERVICE_IMS, indicationType); - int[] info = new int[3]; - info[0] = failureInfo.failureReason; - info[1] = failureInfo.causeCode; - info[2] = failureInfo.waitTimeMillis; - Object[] response = new Object[2]; response[0] = token; - response[1] = info; + response[1] = new ConnectionFailureInfo( + RILUtils.convertHalConnectionFailureReason(failureInfo.failureReason), + failureInfo.causeCode, failureInfo.waitTimeMillis); if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_CONNECTION_SETUP_FAILURE, response); diff --git a/src/java/com/android/internal/telephony/ImsResponse.java b/src/java/com/android/internal/telephony/ImsResponse.java index 574cf359a7..1adc000063 100644 --- a/src/java/com/android/internal/telephony/ImsResponse.java +++ b/src/java/com/android/internal/telephony/ImsResponse.java @@ -17,10 +17,12 @@ package com.android.internal.telephony; import static android.telephony.TelephonyManager.HAL_SERVICE_IMS; +import static android.telephony.ims.feature.MmTelFeature.ImsTrafficSessionCallbackWrapper.INVALID_TOKEN; import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.ims.IRadioImsResponse; +import android.telephony.ims.feature.ConnectionFailureInfo; /** * Interface declaring response functions to solicited radio requests for IMS APIs. @@ -65,17 +67,13 @@ public class ImsResponse extends IRadioImsResponse.Stub { RILRequest rr = mRil.processResponse(HAL_SERVICE_IMS, responseInfo); if (rr != null) { - Object[] response = { "", null }; - + Object[] response = { new Integer(INVALID_TOKEN), null }; if (responseInfo.error == RadioError.NONE) { if (failureInfo != null) { - int[] info = new int[3]; - info[0] = failureInfo.failureReason; - info[1] = failureInfo.causeCode; - info[2] = failureInfo.waitTimeMillis; - response[1] = info; + response[1] = new ConnectionFailureInfo( + RILUtils.convertHalConnectionFailureReason(failureInfo.failureReason), + failureInfo.causeCode, failureInfo.waitTimeMillis); } - RadioResponse.sendMessageResponse(rr.mResult, response); } mRil.processResponseDone(rr, responseInfo, response); diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index edb682f45f..586f01651b 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -4925,6 +4925,53 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public void setTerminalBasedCallWaitingSupported(boolean supported) { } + /** + * Notifies the NAS and RRC layers of the radio the type of upcoming IMS traffic. + * + * @param token A nonce to identify the request. + * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. + * @param accessNetworkType The type of the radio access network used. + * @param trafficDirection Indicates whether traffic is originated by mobile originated or + * mobile terminated use case eg. MO/MT call/SMS etc. + * @param response is callback message. + */ + public void startImsTraffic(int token, + @MmTelFeature.ImsTrafficType int trafficType, + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, + @MmTelFeature.ImsTrafficDirection int trafficDirection, Message response) { + mCi.startImsTraffic(token, trafficType, accessNetworkType, trafficDirection, response); + } + + /** + * Notifies IMS traffic has been stopped. + * + * @param token The token assigned by startImsTraffic. + * @param response is callback message. + */ + public void stopImsTraffic(int token, Message response) { + mCi.stopImsTraffic(token, response); + } + + /** + * Register for notifications of connection setup failure + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForConnectionSetupFailure(Handler h, int what, Object obj) { + mCi.registerForConnectionSetupFailure(h, what, obj); + } + + /** + * Unregister for notifications of connection setup failure + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForConnectionSetupFailure(Handler h) { + mCi.unregisterForConnectionSetupFailure(h); + } + /** * Triggers the UE initiated EPS fallback procedure. * diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index c248a188a0..7bb0b8f057 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -86,6 +86,7 @@ import android.telephony.data.NetworkSliceInfo; import android.telephony.data.TrafficDescriptor; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RegistrationManager; +import android.telephony.ims.feature.ConnectionFailureInfo; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.text.TextUtils; import android.util.SparseArray; @@ -5306,7 +5307,8 @@ public class RIL extends BaseCommands implements CommandsInterface { } @Override - public void startImsTraffic(int token, int trafficType, int accessNetworkType, Message result) { + public void startImsTraffic(int token, + int trafficType, int accessNetworkType, int trafficDirection, Message result) { RadioImsProxy imsProxy = getRadioServiceProxy(RadioImsProxy.class, result); if (imsProxy.isEmpty()) return; if (mHalVersion.get(HAL_SERVICE_IMS).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { @@ -5314,12 +5316,15 @@ public class RIL extends BaseCommands implements CommandsInterface { mRILDefaultWorkSource); if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + "{" + token + ", " + trafficType + ", " + + accessNetworkType + ", " + trafficDirection + "}"); } try { - // TODO(ag/20335448): replace 0 with actual trafficDirection - imsProxy.startImsTraffic(rr.mSerial, token, trafficType, accessNetworkType, 0); + imsProxy.startImsTraffic(rr.mSerial, token, + RILUtils.convertImsTrafficType(trafficType), accessNetworkType, + RILUtils.convertImsTrafficDirection(trafficDirection)); } catch (RemoteException | RuntimeException e) { handleRadioProxyExceptionForRR(HAL_SERVICE_IMS, "startImsTraffic", e); } @@ -5344,7 +5349,8 @@ public class RIL extends BaseCommands implements CommandsInterface { mRILDefaultWorkSource); if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + "{" + token + "}"); } try { @@ -6282,6 +6288,22 @@ public class RIL extends BaseCommands implements CommandsInterface { sb.append("[").append(hwcfg).append("] "); } s = sb.toString(); + } else if (req == RIL_REQUEST_START_IMS_TRAFFIC + || req == RIL_UNSOL_CONNECTION_SETUP_FAILURE) { + sb = new StringBuilder("{"); + Object[] info = (Object[]) ret; + int token = (Integer) info[0]; + sb.append(token).append(", "); + if (info[1] != null) { + ConnectionFailureInfo failureInfo = (ConnectionFailureInfo) info[1]; + sb.append(failureInfo.getReason()).append(", "); + sb.append(failureInfo.getCauseCode()).append(", "); + sb.append(failureInfo.getWaitTimeMillis()); + } else { + sb.append("null"); + } + sb.append("}"); + s = sb.toString(); } else { // Check if toString() was overridden. Java classes created from HIDL have a built-in // toString() method, but AIDL classes only have it if the parcelable contains a diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 19ddecdacd..9aac98b11c 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -349,6 +349,8 @@ import android.telephony.data.RouteSelectionDescriptor; import android.telephony.data.TrafficDescriptor; import android.telephony.data.UrspRule; import android.telephony.ims.RegistrationManager; +import android.telephony.ims.feature.ConnectionFailureInfo; +import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsRegistrationImplBase.ImsDeregistrationReason; import android.text.TextUtils; @@ -4728,6 +4730,83 @@ public class RILUtils { } } + /** + * Convert the IMS traffic type. + * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc. + * @return The converted IMS traffic type. + */ + public static int convertImsTrafficType(@MmTelFeature.ImsTrafficType int trafficType) { + switch (trafficType) { + case MmTelFeature.IMS_TRAFFIC_TYPE_EMERGENCY: + return android.hardware.radio.ims.ImsTrafficType.EMERGENCY; + case MmTelFeature.IMS_TRAFFIC_TYPE_EMERGENCY_SMS: + return android.hardware.radio.ims.ImsTrafficType.EMERGENCY_SMS; + case MmTelFeature.IMS_TRAFFIC_TYPE_VOICE: + return android.hardware.radio.ims.ImsTrafficType.VOICE; + case MmTelFeature.IMS_TRAFFIC_TYPE_VIDEO: + return android.hardware.radio.ims.ImsTrafficType.VIDEO; + case MmTelFeature.IMS_TRAFFIC_TYPE_SMS: + return android.hardware.radio.ims.ImsTrafficType.SMS; + case MmTelFeature.IMS_TRAFFIC_TYPE_REGISTRATION: + return android.hardware.radio.ims.ImsTrafficType.REGISTRATION; + } + return android.hardware.radio.ims.ImsTrafficType.UT_XCAP; + } + + /** + * Convert the IMS traffic direction. + * @param trafficDirection Indicates the traffic direction. + * @return The converted IMS traffic direction. + */ + public static int convertImsTrafficDirection( + @MmTelFeature.ImsTrafficDirection int trafficDirection) { + switch (trafficDirection) { + case MmTelFeature.IMS_TRAFFIC_DIRECTION_INCOMING: + return android.hardware.radio.ims.ImsCall.Direction.INCOMING; + default: + return android.hardware.radio.ims.ImsCall.Direction.OUTGOING; + } + } + + /** + * Convert the IMS connection failure reason. + * @param halReason Specifies the reason that IMS connection failed. + * @return The converted IMS connection failure reason. + */ + public static @ConnectionFailureInfo.FailureReason int convertHalConnectionFailureReason( + int halReason) { + switch (halReason) { + case android.hardware.radio.ims.ConnectionFailureInfo + .ConnectionFailureReason.REASON_ACCESS_DENIED: + return ConnectionFailureInfo.REASON_ACCESS_DENIED; + case android.hardware.radio.ims.ConnectionFailureInfo + .ConnectionFailureReason.REASON_NAS_FAILURE: + return ConnectionFailureInfo.REASON_NAS_FAILURE; + case android.hardware.radio.ims.ConnectionFailureInfo + .ConnectionFailureReason.REASON_RACH_FAILURE: + return ConnectionFailureInfo.REASON_RACH_FAILURE; + case android.hardware.radio.ims.ConnectionFailureInfo + .ConnectionFailureReason.REASON_RLC_FAILURE: + return ConnectionFailureInfo.REASON_RLC_FAILURE; + case android.hardware.radio.ims.ConnectionFailureInfo + .ConnectionFailureReason.REASON_RRC_REJECT: + return ConnectionFailureInfo.REASON_RRC_REJECT; + case android.hardware.radio.ims.ConnectionFailureInfo + .ConnectionFailureReason.REASON_RRC_TIMEOUT: + return ConnectionFailureInfo.REASON_RRC_TIMEOUT; + case android.hardware.radio.ims.ConnectionFailureInfo + .ConnectionFailureReason.REASON_NO_SERVICE: + return ConnectionFailureInfo.REASON_NO_SERVICE; + case android.hardware.radio.ims.ConnectionFailureInfo + .ConnectionFailureReason.REASON_PDN_NOT_AVAILABLE: + return ConnectionFailureInfo.REASON_PDN_NOT_AVAILABLE; + case android.hardware.radio.ims.ConnectionFailureInfo + .ConnectionFailureReason.REASON_RF_BUSY: + return ConnectionFailureInfo.REASON_RF_BUSY; + } + return ConnectionFailureInfo.REASON_UNSPECIFIED; + } + /** Append the data to the end of an ArrayList */ public static void appendPrimitiveArrayToArrayList(byte[] src, ArrayList dst) { for (byte b : src) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 53fd32a0d9..5067da89e6 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -2722,6 +2722,30 @@ public class ImsPhone extends ImsPhoneBase { mDefaultPhone.triggerEpsFallback(reason, response); } + @Override + public void startImsTraffic(int token, + @MmTelFeature.ImsTrafficType int trafficType, + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, + @MmTelFeature.ImsTrafficDirection int trafficDirection, Message response) { + mDefaultPhone.startImsTraffic(token, trafficType, + accessNetworkType, trafficDirection, response); + } + + @Override + public void stopImsTraffic(int token, Message response) { + mDefaultPhone.stopImsTraffic(token, response); + } + + @Override + public void registerForConnectionSetupFailure(Handler h, int what, Object obj) { + mDefaultPhone.registerForConnectionSetupFailure(h, what, obj); + } + + @Override + public void unregisterForConnectionSetupFailure(Handler h) { + mDefaultPhone.unregisterForConnectionSetupFailure(h); + } + @Override public void triggerImsDeregistration( @ImsRegistrationImplBase.ImsDeregistrationReason int reason) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 97f84d1ff0..bab3924f66 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -30,6 +30,8 @@ import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_INCOMING; import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_INCOMING_SETUP; import static android.telephony.PreciseCallState.PRECISE_CALL_STATE_WAITING; import static android.telephony.ims.ImsService.CAPABILITY_TERMINAL_BASED_CALL_WAITING; +import static android.telephony.ims.feature.ConnectionFailureInfo.REASON_UNSPECIFIED; +import static android.telephony.ims.feature.MmTelFeature.ImsTrafficSessionCallbackWrapper.INVALID_TOKEN; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import static com.android.internal.telephony.CallWaitingController.TERMINAL_BASED_ACTIVATED; @@ -74,6 +76,7 @@ import android.sysprop.TelephonyProperties; import android.telecom.Connection.VideoProvider; import android.telecom.TelecomManager; import android.telecom.VideoProfile; +import android.telephony.AccessNetworkConstants; import android.telephony.CallQuality; import android.telephony.CarrierConfigManager; import android.telephony.DisconnectCause; @@ -97,7 +100,9 @@ import android.telephony.ims.RtpHeaderExtension; import android.telephony.ims.RtpHeaderExtensionType; import android.telephony.ims.SrvccCall; import android.telephony.ims.aidl.IImsCallSessionListener; +import android.telephony.ims.aidl.IImsTrafficSessionCallback; import android.telephony.ims.aidl.ISrvccStartedCallback; +import android.telephony.ims.feature.ConnectionFailureInfo; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; @@ -207,6 +212,20 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { SharedPreferences getDefaultSharedPreferences(Context context); } + private static class ImsTrafficSession { + private final @MmTelFeature.ImsTrafficType int mTrafficType; + private final @MmTelFeature.ImsTrafficDirection int mTrafficDirection; + private final @NonNull IImsTrafficSessionCallback mCallback; + + ImsTrafficSession(@MmTelFeature.ImsTrafficType int trafficType, + @MmTelFeature.ImsTrafficDirection int trafficDirection, + @NonNull IImsTrafficSessionCallback callback) { + mTrafficType = trafficType; + mTrafficDirection = trafficDirection; + mCallback = callback; + } + } + private static final boolean DBG = true; // When true, dumps the state of ImsPhoneCallTracker after changes to foreground and background @@ -413,6 +432,55 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { }, mExecutor); } + @Override + public void onStartImsTrafficSession(int token, + @MmTelFeature.ImsTrafficType int trafficType, + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, + @MmTelFeature.ImsTrafficDirection int trafficDirection, + IImsTrafficSessionCallback callback) { + registerImsTrafficSession(token, trafficType, trafficDirection, callback); + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (DBG) { + log("onStartImsTrafficSession token=" + token + ", traffic=" + trafficType + + ", networkType=" + accessNetworkType + + ", direction=" + trafficDirection); + } + mPhone.startImsTraffic(token, trafficType, accessNetworkType, trafficDirection, + obtainMessage(EVENT_START_IMS_TRAFFIC_DONE, callback)); + }, mExecutor); + } + + @Override + public void onModifyImsTrafficSession(int token, + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType) { + ImsTrafficSession session = getImsTrafficSession(token); + if (session == null) { + loge("onModifyImsTrafficSession unknown session, token=" + token); + return; + } + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (DBG) { + log("onModifyImsTrafficSession token=" + token + + ", networkType=" + accessNetworkType); + } + mPhone.startImsTraffic(token, session.mTrafficType, + accessNetworkType, session.mTrafficDirection, + obtainMessage(EVENT_START_IMS_TRAFFIC_DONE, session.mCallback)); + }, mExecutor); + } + + @Override + public void onStopImsTrafficSession(int token) { + unregisterImsTrafficSession(token); + if (token == INVALID_TOKEN) return; + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (DBG) { + log("onStopImsTrafficSession token=" + token); + } + mPhone.stopImsTraffic(token, null); + }, mExecutor); + } + /** * Schedule the given Runnable on mExecutor and block this thread until it finishes. * @param r The Runnable to run. @@ -574,6 +642,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private static final int EVENT_ANSWER_WAITING_CALL = 30; private static final int EVENT_RESUME_NOW_FOREGROUND_CALL = 31; private static final int EVENT_REDIAL_WITHOUT_RTT = 32; + private static final int EVENT_START_IMS_TRAFFIC_DONE = 33; + private static final int EVENT_CONNECTION_SETUP_FAILURE = 34; private static final int TIMEOUT_HANGUP_PENDINGMO = 500; @@ -1089,6 +1159,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // Used for important operational related events for logging. private final LocalLog mOperationLocalLog = new LocalLog(64); + private final ConcurrentHashMap mImsTrafficSessions = + new ConcurrentHashMap<>(); + /** * Container to ease passing around a tuple of two objects. This object provides a sensible * implementation of equals(), returning true/false using equals() for one object (Integer) @@ -1137,6 +1210,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { return (first == null ? 0 : first.hashCode()); } } + //***** Events @@ -1198,12 +1272,15 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { postDelayed(mConnectorRunnable, CONNECTOR_RETRY_DELAY_MS); } stopListeningForCalls(); + stopAllImsTrafficTypes(); } }, executor); // It can take some time for ITelephony to get published, so defer connecting. post(mConnectorRunnable); mImsCallInfoTracker = new ImsCallInfoTracker(phone); + + mPhone.registerForConnectionSetupFailure(this, EVENT_CONNECTION_SETUP_FAILURE, null); } /** @@ -1422,6 +1499,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { (NetworkStatsManager) mPhone.getContext().getSystemService( Context.NETWORK_STATS_SERVICE); statsManager.unregisterNetworkStatsProvider(mVtDataUsageProvider); + + mPhone.unregisterForConnectionSetupFailure(this); } @Override @@ -4720,6 +4799,37 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } break; } + + case EVENT_START_IMS_TRAFFIC_DONE: // fallthrough + case EVENT_CONNECTION_SETUP_FAILURE: { + ar = (AsyncResult) msg.obj; + // Not-null with EVENT_START_IMS_TRAFFIC_DONE + IImsTrafficSessionCallback callback = (IImsTrafficSessionCallback) ar.userObj; + try { + if (ar.exception == null) { + Object[] result = (Object[]) ar.result; + if (result != null && result.length > 1) { + if (callback == null) { + //EVENT_CONNECTION_SETUP_FAILURE + ImsTrafficSession session = + getImsTrafficSession((int) result[0]); + if (session != null) callback = session.mCallback; + } + if (callback == null) break; + + if (result[1] == null) callback.onReady(); + else callback.onError((ConnectionFailureInfo) result[1]); + break; + } + } + if (callback != null) { + callback.onError(new ConnectionFailureInfo(REASON_UNSPECIFIED, 0, -1)); + } + } catch (RemoteException e) { + Rlog.e(LOG_TAG, "Exception: " + e); + } + break; + } } } @@ -5854,4 +5964,30 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mPhone.updateImsRegistrationInfo(capabilities); } + + private void registerImsTrafficSession(int token, + @MmTelFeature.ImsTrafficType int trafficType, + @MmTelFeature.ImsTrafficDirection int trafficDirection, + @NonNull IImsTrafficSessionCallback callback) { + mImsTrafficSessions.put(Integer.valueOf(token), + new ImsTrafficSession(trafficType, trafficDirection, callback)); + } + + private void unregisterImsTrafficSession(int token) { + mImsTrafficSessions.remove(Integer.valueOf(token)); + } + + private ImsTrafficSession getImsTrafficSession(int token) { + return mImsTrafficSessions.get(Integer.valueOf(token)); + } + + private void stopAllImsTrafficTypes() { + boolean isEmpty = mImsTrafficSessions.isEmpty(); + logi("stopAllImsTrafficTypes empty=" + isEmpty); + + if (isEmpty) return; + + mImsTrafficSessions.forEachKey(1, token -> mPhone.stopImsTraffic(token, null)); + mImsTrafficSessions.clear(); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 6aa0cd6a09..57cdd69ba8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -36,6 +36,8 @@ import static android.telephony.TelephonyManager.SRVCC_STATE_HANDOVER_STARTED; import static android.telephony.emergency.EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE; import static android.telephony.ims.ImsStreamMediaProfile.DIRECTION_INACTIVE; import static android.telephony.ims.ImsStreamMediaProfile.DIRECTION_SEND_RECEIVE; +import static android.telephony.ims.feature.MmTelFeature.IMS_TRAFFIC_DIRECTION_INCOMING; +import static android.telephony.ims.feature.MmTelFeature.IMS_TRAFFIC_DIRECTION_OUTGOING; import static com.android.testutils.NetworkStatsUtilsKt.assertNetworkStatsEquals; @@ -80,6 +82,7 @@ import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteException; import android.telecom.VideoProfile; +import android.telephony.AccessNetworkConstants; import android.telephony.CarrierConfigManager; import android.telephony.DisconnectCause; import android.telephony.PhoneNumberUtils; @@ -94,6 +97,7 @@ import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsStreamMediaProfile; import android.telephony.ims.RtpHeaderExtensionType; import android.telephony.ims.SrvccCall; +import android.telephony.ims.aidl.IImsTrafficSessionCallback; import android.telephony.ims.aidl.ISrvccStartedCallback; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.MmTelFeature; @@ -130,6 +134,7 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -2417,6 +2422,70 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { verify(mImsPhone, times(7)).updateImsCallStatus(any(), any()); } + /** Verifies that the request from ImsService is passed to ImsPhone as expected. */ + @Test + @SmallTest + public void testStartAndStopImsTrafficSession() { + IImsTrafficSessionCallback binder = Mockito.mock(IImsTrafficSessionCallback.class); + mMmTelListener.onStartImsTrafficSession(1, MmTelFeature.IMS_TRAFFIC_TYPE_EMERGENCY, + AccessNetworkConstants.AccessNetworkType.EUTRAN, + IMS_TRAFFIC_DIRECTION_OUTGOING, binder); + verify(mImsPhone, times(1)).startImsTraffic(eq(1), + eq(MmTelFeature.IMS_TRAFFIC_TYPE_EMERGENCY), + eq(AccessNetworkConstants.AccessNetworkType.EUTRAN), + eq(IMS_TRAFFIC_DIRECTION_OUTGOING), any()); + + mMmTelListener.onStopImsTrafficSession(1); + verify(mImsPhone, times(1)).stopImsTraffic(eq(1), any()); + + mMmTelListener.onStartImsTrafficSession(2, MmTelFeature.IMS_TRAFFIC_TYPE_EMERGENCY_SMS, + AccessNetworkConstants.AccessNetworkType.IWLAN, + IMS_TRAFFIC_DIRECTION_OUTGOING, binder); + verify(mImsPhone, times(1)).startImsTraffic(eq(2), + eq(MmTelFeature.IMS_TRAFFIC_TYPE_EMERGENCY_SMS), + eq(AccessNetworkConstants.AccessNetworkType.IWLAN), + eq(IMS_TRAFFIC_DIRECTION_OUTGOING), any()); + + mMmTelListener.onStartImsTrafficSession(3, MmTelFeature.IMS_TRAFFIC_TYPE_VOICE, + AccessNetworkConstants.AccessNetworkType.EUTRAN, + IMS_TRAFFIC_DIRECTION_INCOMING, binder); + verify(mImsPhone, times(1)).startImsTraffic(eq(3), + eq(MmTelFeature.IMS_TRAFFIC_TYPE_VOICE), + eq(AccessNetworkConstants.AccessNetworkType.EUTRAN), + eq(IMS_TRAFFIC_DIRECTION_INCOMING), any()); + + mMmTelListener.onStartImsTrafficSession(4, MmTelFeature.IMS_TRAFFIC_TYPE_VIDEO, + AccessNetworkConstants.AccessNetworkType.EUTRAN, + IMS_TRAFFIC_DIRECTION_OUTGOING, binder); + verify(mImsPhone, times(1)).startImsTraffic(eq(4), + eq(MmTelFeature.IMS_TRAFFIC_TYPE_VIDEO), + eq(AccessNetworkConstants.AccessNetworkType.EUTRAN), + eq(IMS_TRAFFIC_DIRECTION_OUTGOING), any()); + + mMmTelListener.onStartImsTrafficSession(5, MmTelFeature.IMS_TRAFFIC_TYPE_SMS, + AccessNetworkConstants.AccessNetworkType.EUTRAN, + IMS_TRAFFIC_DIRECTION_OUTGOING, binder); + verify(mImsPhone, times(1)).startImsTraffic(eq(5), + eq(MmTelFeature.IMS_TRAFFIC_TYPE_SMS), + eq(AccessNetworkConstants.AccessNetworkType.EUTRAN), + eq(IMS_TRAFFIC_DIRECTION_OUTGOING), any()); + + mMmTelListener.onStartImsTrafficSession(6, MmTelFeature.IMS_TRAFFIC_TYPE_REGISTRATION, + AccessNetworkConstants.AccessNetworkType.EUTRAN, + IMS_TRAFFIC_DIRECTION_OUTGOING, binder); + verify(mImsPhone, times(1)).startImsTraffic(eq(6), + eq(MmTelFeature.IMS_TRAFFIC_TYPE_REGISTRATION), + eq(AccessNetworkConstants.AccessNetworkType.EUTRAN), + eq(IMS_TRAFFIC_DIRECTION_OUTGOING), any()); + + mMmTelListener.onModifyImsTrafficSession(6, + AccessNetworkConstants.AccessNetworkType.IWLAN); + verify(mImsPhone, times(1)).startImsTraffic(eq(6), + eq(MmTelFeature.IMS_TRAFFIC_TYPE_REGISTRATION), + eq(AccessNetworkConstants.AccessNetworkType.IWLAN), + eq(IMS_TRAFFIC_DIRECTION_OUTGOING), any()); + } + private void sendCarrierConfigChanged() { Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); -- GitLab From db24010da8d81058455111026b668c6c6bc63c7f Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 15 Dec 2022 16:39:26 -0800 Subject: [PATCH 287/656] Exposed getAllSubscriptionInfoList and getSubscriptionId 1. Added getAllSubscriptionInfoList for getting all the subscriptions from the subscription database. 2. Added getSubscriptionId for getting the active subscription id from the specified slot. 3. Deprecated getSubscriptionIds, which is imposible to return more than one subscription in today's implementation. Fix: 261041952 Test: Manual + CTS Change-Id: I542be7f798b16227614f0467259015f856720d14 --- .../subscription/SubscriptionManagerService.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index ea5c020ada..23eb5c41ff 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -986,7 +986,7 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Get all subscription info records from SIMs that are inserted now or were inserted before. + * Get all subscription info records from SIMs that are inserted now or previously inserted. * *

* If the caller does not have {@link Manifest.permission#READ_PHONE_NUMBERS} permission, @@ -996,19 +996,17 @@ public class SubscriptionManagerService extends ISub.Stub { * empty string, and {@link SubscriptionInfo#getGroupUuid()} will return {@code null}. * *

- * The carrier app will always have full {@link SubscriptionInfo} for the subscriptions - * that it has carrier privilege. Subscriptions that the carrier app has no privilege will be - * excluded from the list. - * - * @return List of all {@link SubscriptionInfo} records from SIMs that are inserted or - * inserted before. Sorted by {@link SubscriptionInfo#getSimSlotIndex()}, then - * {@link SubscriptionInfo#getSubscriptionId()}. + * The carrier app will only get the list of subscriptions that it has carrier privilege on, + * but will have non-stripped {@link SubscriptionInfo} in the list. * * @param callingPackage The package making the call. * @param callingFeatureId The feature in the package. * - * @throws SecurityException if the caller does not have required permissions. + * @return List of all {@link SubscriptionInfo} records from SIMs that are inserted or + * previously inserted. Sorted by {@link SubscriptionInfo#getSimSlotIndex()}, then + * {@link SubscriptionInfo#getSubscriptionId()}. * + * @throws SecurityException if callers do not hold the required permission. */ @Override @NonNull -- GitLab From 727b169f762b793890579ca2eb5cc314831e6bf9 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 16 Dec 2022 18:22:25 -0800 Subject: [PATCH 288/656] Moved SimStateToString to TelephonyManager Bug: 239607619 Test: Manual Change-Id: I15a4f0504980211e17a7a1c5c0e21c9c1e9e0c98 --- .../telephony/CarrierPrivilegesTracker.java | 4 +- .../telephony/SubscriptionInfoUpdater.java | 50 +++---------------- .../telephony/data/DataNetworkController.java | 7 ++- .../internal/telephony/uicc/PinStorage.java | 5 +- 4 files changed, 12 insertions(+), 54 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index b3afb66102..b581930b5b 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -31,8 +31,6 @@ import static android.telephony.TelephonyManager.SIM_STATE_NOT_READY; import static android.telephony.TelephonyManager.SIM_STATE_READY; import static android.telephony.TelephonyManager.SIM_STATE_UNKNOWN; -import static com.android.internal.telephony.SubscriptionInfoUpdater.simStateString; - import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; import android.annotation.Nullable; @@ -526,7 +524,7 @@ public class CarrierPrivilegesTracker extends Handler { SystemClock.uptimeMillis() + CLEAR_UICC_RULES_DELAY_MILLIS; sendMessageAtTime(obtainMessage(ACTION_CLEAR_UICC_RULES), mClearUiccRulesUptimeMillis); - mLocalLog.log("SIM is gone, simState=" + simStateString(simState) + mLocalLog.log("SIM is gone, simState=" + TelephonyManager.simStateToString(simState) + ". Delay " + TimeUnit.MILLISECONDS.toSeconds( CLEAR_UICC_RULES_DELAY_MILLIS) + " seconds to clear UICC rules."); } else { diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index 2a9aac6584..1681d140b7 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -46,7 +46,6 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.SimState; import android.telephony.UiccAccessRule; import android.telephony.euicc.EuiccManager; import android.text.TextUtils; @@ -1301,9 +1300,9 @@ public class SubscriptionInfoUpdater extends Handler { if (slot != null) { i.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); } - logd("Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " + simStateString(state) - + " for phone: " + phoneId + " slot: " + slotId + " port: " - + slot.getPortIndexFromPhoneId(phoneId)); + logd("Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " + + TelephonyManager.simStateToString(state) + " for phone: " + phoneId + + " slot: " + slotId + " port: " + slot.getPortIndexFromPhoneId(phoneId)); sContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); TelephonyMetrics.getInstance().updateSimState(phoneId, state); } @@ -1333,51 +1332,14 @@ public class SubscriptionInfoUpdater extends Handler { if (slot != null) { i.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); } - logd("Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " + simStateString(state) - + " for phone: " + phoneId + " slot: " + slotId + "port: " - + slot.getPortIndexFromPhoneId(phoneId)); + logd("Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " + + TelephonyManager.simStateToString(state) + " for phone: " + phoneId + + " slot: " + slotId + "port: " + slot.getPortIndexFromPhoneId(phoneId)); sContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); TelephonyMetrics.getInstance().updateSimState(phoneId, state); } } - /** - * Convert SIM state into string - * - * @param state SIM state - * @return SIM state in string format - */ - public static String simStateString(@SimState int state) { - switch (state) { - case TelephonyManager.SIM_STATE_UNKNOWN: - return "UNKNOWN"; - case TelephonyManager.SIM_STATE_ABSENT: - return "ABSENT"; - case TelephonyManager.SIM_STATE_PIN_REQUIRED: - return "PIN_REQUIRED"; - case TelephonyManager.SIM_STATE_PUK_REQUIRED: - return "PUK_REQUIRED"; - case TelephonyManager.SIM_STATE_NETWORK_LOCKED: - return "NETWORK_LOCKED"; - case TelephonyManager.SIM_STATE_READY: - return "READY"; - case TelephonyManager.SIM_STATE_NOT_READY: - return "NOT_READY"; - case TelephonyManager.SIM_STATE_PERM_DISABLED: - return "PERM_DISABLED"; - case TelephonyManager.SIM_STATE_CARD_IO_ERROR: - return "CARD_IO_ERROR"; - case TelephonyManager.SIM_STATE_CARD_RESTRICTED: - return "CARD_RESTRICTED"; - case TelephonyManager.SIM_STATE_LOADED: - return "LOADED"; - case TelephonyManager.SIM_STATE_PRESENT: - return "PRESENT"; - default: - return "INVALID"; - } - } - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private static void logd(String message) { Rlog.d(LOG_TAG, message); diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 36c5de6406..8ea453efb9 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -82,7 +82,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.SlidingWindowEventCounter; -import com.android.internal.telephony.SubscriptionInfoUpdater; import com.android.internal.telephony.TelephonyComponentFactory; import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback; import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback; @@ -2327,7 +2326,7 @@ public class DataNetworkController extends Handler { log("onCarrierConfigUpdated: config is " + (mDataConfigManager.isConfigCarrierSpecific() ? "" : "not ") + "carrier specific. mSimState=" - + SubscriptionInfoUpdater.simStateString(mSimState)); + + TelephonyManager.simStateToString(mSimState)); updateNetworkRequestsPriority(); onReevaluateUnsatisfiedNetworkRequests(DataEvaluationReason.DATA_CONFIG_CHANGED); } @@ -2985,7 +2984,7 @@ public class DataNetworkController extends Handler { * @param simState SIM state. (Note this is mixed with card state and application state.) */ private void onSimStateChanged(@SimState int simState) { - log("onSimStateChanged: state=" + SubscriptionInfoUpdater.simStateString(simState)); + log("onSimStateChanged: state=" + TelephonyManager.simStateToString(simState)); if (mSimState != simState) { mSimState = simState; if (simState == TelephonyManager.SIM_STATE_ABSENT) { @@ -3705,7 +3704,7 @@ public class DataNetworkController extends Handler { pw.println("mImsDataNetworkState=" + TelephonyUtils.dataStateToString(mImsDataNetworkState)); pw.println("mDataServiceBound=" + mDataServiceBound); - pw.println("mSimState=" + SubscriptionInfoUpdater.simStateString(mSimState)); + pw.println("mSimState=" + TelephonyManager.simStateToString(mSimState)); pw.println("mDataNetworkControllerCallbacks=" + mDataNetworkControllerCallbacks); pw.println("Subscription plans:"); pw.increaseIndent(); diff --git a/src/java/com/android/internal/telephony/uicc/PinStorage.java b/src/java/com/android/internal/telephony/uicc/PinStorage.java index 1154e0f04a..ed16ee4403 100644 --- a/src/java/com/android/internal/telephony/uicc/PinStorage.java +++ b/src/java/com/android/internal/telephony/uicc/PinStorage.java @@ -61,7 +61,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionInfoUpdater; import com.android.internal.telephony.TelephonyStatsLog; import com.android.internal.telephony.nano.StoredPinProto.EncryptedPin; import com.android.internal.telephony.nano.StoredPinProto.StoredPin; @@ -519,8 +518,8 @@ public class PinStorage extends Handler { /** Handle the update of the {@code state} of the SIM card in {@code slotId}. */ private synchronized void onSimStatusChange(int slotId, @SimState int state) { - logd("SIM card/application changed[%d]: %s", - slotId, SubscriptionInfoUpdater.simStateString(state)); + logd("SIM card/application changed[%d]: %s", slotId, + TelephonyManager.simStateToString(state)); switch (state) { case TelephonyManager.SIM_STATE_ABSENT: case TelephonyManager.SIM_STATE_PIN_REQUIRED: { -- GitLab From 10067d3b577096ec211ea7c330bf11233cdb59eb Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Sat, 3 Dec 2022 11:27:17 +0000 Subject: [PATCH 289/656] PrimaryImei framework changes Bug: 184001777 Test: atest frameworks/opt/telephony/tests/telephonytests/src/com/android/internal/telephony Change-Id: I99921b027f12a3ecfe976078e93ca4423bc5da3e --- .../internal/telephony/CommandsInterface.java | 11 +++++ .../internal/telephony/GsmCdmaPhone.java | 33 ++++++++++--- .../internal/telephony/ModemResponse.java | 12 +++-- .../com/android/internal/telephony/Phone.java | 9 +++- .../telephony/PhoneInternalInterface.java | 4 ++ .../com/android/internal/telephony/RIL.java | 29 ++++++++++++ .../internal/telephony/RadioModemProxy.java | 13 +++++ .../telephony/imsphone/ImsPhoneBase.java | 5 ++ .../imsphone/ImsPhoneCommandInterface.java | 4 ++ .../internal/telephony/GsmCdmaPhoneTest.java | 47 +++++++++++++++++-- .../android/internal/telephony/RILTest.java | 41 ++++++++++++++++ .../internal/telephony/SimulatedCommands.java | 12 +++++ .../telephony/SimulatedCommandsVerifier.java | 5 ++ 13 files changed, 210 insertions(+), 15 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 3517b21afd..525498994c 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -1789,6 +1789,17 @@ public interface CommandsInterface { */ public void getDeviceIdentity(Message response); + /** + * Request the device IMEI / IMEI type / IMEISV + * "response" is ImeiInfo object that contains + * [0] ImeiType Indicates whether IMEI is of primary or secondary type + * [1] IMEI if GSM subscription is available + * [2] IMEISV if GSM subscription is available + * + * @param response Message + */ + public void getImei(Message response); + /** * Request the device MDN / H_SID / H_NID / MIN. * "response" is const char ** diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 37b7509c8f..568507be89 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -42,6 +42,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.SQLException; +import android.hardware.radio.modem.ImeiInfo; import android.net.Uri; import android.os.AsyncResult; import android.os.Build; @@ -231,12 +232,11 @@ public class GsmCdmaPhone extends Phone { private final RegistrantList mVolteSilentRedialRegistrants = new RegistrantList(); private DialArgs mDialArgs = null; - private final RegistrantList mEmergencyDomainSelectedRegistrants = new RegistrantList(); - private String mImei; private String mImeiSv; private String mVmNumber; + private int mImeiType = IMEI_TYPE_UNKNOWN; CellBroadcastConfigTracker mCellBroadcastConfigTracker = CellBroadcastConfigTracker.make(this, null); @@ -1907,6 +1907,11 @@ public class GsmCdmaPhone extends Phone { return mImei; } + @Override + public int getImeiType() { + return mImeiType; + } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Override public String getEsn() { @@ -2956,7 +2961,7 @@ public class GsmCdmaPhone extends Phone { private void handleRadioAvailable() { mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE)); - + mCi.getImei(obtainMessage(EVENT_GET_DEVICE_IMEI_DONE)); mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE)); mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY)); mCi.areUiccApplicationsEnabled(obtainMessage(EVENT_GET_UICC_APPS_ENABLEMENT_DONE)); @@ -3007,7 +3012,21 @@ public class GsmCdmaPhone extends Phone { handleRadioAvailable(); } break; - + case EVENT_GET_DEVICE_IMEI_DONE : + ar = (AsyncResult)msg.obj; + if (ar.exception != null || ar.result == null) { + loge("Exception received : " + ar.exception); + break; + } + ImeiInfo imeiInfo = (ImeiInfo) ar.result; + if (!TextUtils.isEmpty(imeiInfo.imei)) { + mImeiType = imeiInfo.type; + mImei = imeiInfo.imei; + mImeiSv = imeiInfo.svn; + } else { + // TODO Report telephony anomaly + } + break; case EVENT_GET_DEVICE_IDENTITY_DONE:{ ar = (AsyncResult)msg.obj; @@ -3015,8 +3034,10 @@ public class GsmCdmaPhone extends Phone { break; } String[] respId = (String[])ar.result; - mImei = respId[0]; - mImeiSv = respId[1]; + if (TextUtils.isEmpty(mImei)) { + mImei = respId[0]; + mImeiSv = respId[1]; + } mEsn = respId[2]; mMeid = respId[3]; // some modems return all 0's instead of null/empty string when MEID is unavailable diff --git a/src/java/com/android/internal/telephony/ModemResponse.java b/src/java/com/android/internal/telephony/ModemResponse.java index 47eb6856c5..bd04d16ebc 100644 --- a/src/java/com/android/internal/telephony/ModemResponse.java +++ b/src/java/com/android/internal/telephony/ModemResponse.java @@ -79,13 +79,19 @@ public class ModemResponse extends IRadioModemResponse.Stub { } /** - * * @param responseInfo Response info struct containing response type, serial no. and error - * @param imeiInfo imeiInfo object containing ImeiType, device IMEI and IMEISV + * @param imeiInfo object containing ImeiType, device IMEI and IMEISV */ public void getImeiResponse(RadioResponseInfo responseInfo, ImeiInfo imeiInfo) { - // TODO as part of the framework coding + RILRequest rr = mRil.processResponse(HAL_SERVICE_MODEM, responseInfo); + if (rr != null) { + if (responseInfo.error == RadioError.NONE) { + RadioResponse.sendMessageResponse(rr.mResult, imeiInfo); + } + mRil.processResponseDone(rr, responseInfo, imeiInfo); + } } + /** * @param responseInfo Response info struct containing response type, serial no. and error * @param config Array of HardwareConfig of the radio diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index edb682f45f..89c4eb744a 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -25,6 +25,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.hardware.radio.modem.ImeiInfo; import android.content.res.Configuration; import android.net.Uri; import android.os.AsyncResult; @@ -243,8 +244,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected static final int EVENT_SET_USAGE_SETTING_DONE = 64; protected static final int EVENT_IMS_DEREGISTRATION_TRIGGERED = 65; protected static final int EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE = 66; + protected static final int EVENT_GET_DEVICE_IMEI_DONE = 67; - protected static final int EVENT_LAST = EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE; + protected static final int EVENT_LAST = EVENT_GET_DEVICE_IMEI_DONE; // For shared prefs. private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_"; @@ -480,6 +482,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected LinkBandwidthEstimator mLinkBandwidthEstimator; + public static final int IMEI_TYPE_UNKNOWN = -1; + public static final int IMEI_TYPE_PRIMARY = ImeiInfo.ImeiType.PRIMARY; + public static final int IMEI_TYPE_SECONDARY = ImeiInfo.ImeiType.SECONDARY; + public IccRecords getIccRecords() { return mIccRecords.get(); } @@ -4381,6 +4387,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // When radio capability switch is done, query IMEI value and update it in Phone objects // to make it in sync with the IMEI value currently used by Logical-Modem. if (capabilitySwitched) { + mCi.getImei(obtainMessage(EVENT_GET_DEVICE_IMEI_DONE)); mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE)); } } diff --git a/src/java/com/android/internal/telephony/PhoneInternalInterface.java b/src/java/com/android/internal/telephony/PhoneInternalInterface.java index f25de35a69..32c0c73f9b 100644 --- a/src/java/com/android/internal/telephony/PhoneInternalInterface.java +++ b/src/java/com/android/internal/telephony/PhoneInternalInterface.java @@ -1034,6 +1034,10 @@ public interface PhoneInternalInterface { */ String getImei(); + /** + * Retrieves IMEI type for phones. + */ + int getImeiType(); /** * Retrieves the IccPhoneBookInterfaceManager of the Phone */ diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index c248a188a0..66769a90fd 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -3721,6 +3721,35 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + @Override + public void getImei(Message result) { + RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); + if (!modemProxy.isEmpty() && + mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_DEVICE_IMEI, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + modemProxy.getImei(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_MODEM, "getImei", e); + } + } else { + if (RILJ_LOGD) { + Rlog.e(RILJ_LOG_TAG, "getImei: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + @Override public void exitEmergencyCallbackMode(Message result) { RadioVoiceProxy voiceProxy = getRadioServiceProxy(RadioVoiceProxy.class, result); diff --git a/src/java/com/android/internal/telephony/RadioModemProxy.java b/src/java/com/android/internal/telephony/RadioModemProxy.java index a9558a509a..26287510b7 100644 --- a/src/java/com/android/internal/telephony/RadioModemProxy.java +++ b/src/java/com/android/internal/telephony/RadioModemProxy.java @@ -130,6 +130,19 @@ public class RadioModemProxy extends RadioServiceProxy { } } + /** + * Call IRadioModem#getImei + * + * @param serial Serial number of request + * @throws RemoteException + */ + public void getImei(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mModemProxy.getImei(serial); + } + } + /** * Call IRadioModem#getHardwareConfig * @param serial Serial number of request diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index 1d8a88c025..76e72e1792 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -332,6 +332,11 @@ abstract class ImsPhoneBase extends Phone { return null; } + @Override + public int getImeiType() { + return Phone.IMEI_TYPE_UNKNOWN; + } + @Override public String getEsn() { Rlog.e(LOG_TAG, "[VoltePhone] getEsn() is a CDMA method"); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java index 14952b72fe..ed1ca2d984 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java @@ -510,6 +510,10 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface public void getDeviceIdentity(Message response) { } + @Override + public void getImei(Message response) { + } + @Override public void getCDMASubscription(Message response) { } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 33531f72fb..b8f309f856 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -25,6 +25,8 @@ import static com.android.internal.telephony.Phone.EVENT_RADIO_AVAILABLE; import static com.android.internal.telephony.Phone.EVENT_SRVCC_STATE_CHANGED; import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; +import static com.android.internal.telephony.test.SimulatedCommands.FAKE_IMEI; +import static com.android.internal.telephony.test.SimulatedCommands.FAKE_IMEISV; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -53,6 +55,7 @@ import static org.mockito.Mockito.when; import android.content.Intent; import android.content.SharedPreferences; +import android.hardware.radio.modem.ImeiInfo; import android.os.AsyncResult; import android.os.Bundle; import android.os.Handler; @@ -969,7 +972,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { verify(mTelephonyManager).setBasebandVersionForPhone(eq(mPhoneUT.getPhoneId()), nullable(String.class)); // IMEI - assertEquals(SimulatedCommands.FAKE_IMEI, mPhoneUT.getImei()); + assertEquals(FAKE_IMEI, mPhoneUT.getImei()); // IMEISV assertEquals(SimulatedCommands.FAKE_IMEISV, mPhoneUT.getDeviceSvn()); // radio capability @@ -995,7 +998,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { verify(mTelephonyManager, times(2)).setBasebandVersionForPhone(eq(mPhoneUT.getPhoneId()), nullable(String.class)); // device identity - assertEquals(SimulatedCommands.FAKE_IMEI, mPhoneUT.getImei()); + assertEquals(FAKE_IMEI, mPhoneUT.getImei()); assertEquals(SimulatedCommands.FAKE_IMEISV, mPhoneUT.getDeviceSvn()); assertEquals(SimulatedCommands.FAKE_ESN, mPhoneUT.getEsn()); assertEquals(SimulatedCommands.FAKE_MEID, mPhoneUT.getMeid()); @@ -2509,10 +2512,10 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @SmallTest public void testMergeCellBroadcastIdRangesAsNeeded() { final int[][] channelValues = { - {0, 999}, {1000, 1003}, {1004, 0x0FFF}, {0x1000, 0x10FF}, {0x1100, 0x112F}, - {0x1130, 0x1900}, {0x1901, 0x9FFF}, {0xA000, 0xFFFE}, {0xFFFF, 0xFFFF}}; + {0, 999}, {1000, 1003}, {1004, 0x0FFF}, {0x1000, 0x10FF}, {0x1100, 0x112F}, + {0x1130, 0x1900}, {0x1901, 0x9FFF}, {0xA000, 0xFFFE}, {0xFFFF, 0xFFFF}}; final int[] typeValues = { - SmsCbMessage.MESSAGE_FORMAT_3GPP, SmsCbMessage.MESSAGE_FORMAT_3GPP2}; + SmsCbMessage.MESSAGE_FORMAT_3GPP, SmsCbMessage.MESSAGE_FORMAT_3GPP2}; final boolean[] enabledValues = {true, false}; List ranges = new ArrayList<>(); @@ -2558,4 +2561,38 @@ public class GsmCdmaPhoneTest extends TelephonyTest { assertThrows(IllegalArgumentException.class, () -> mergeRangesAsNeeded(ranges2)); } + + @Test + public void getImeiType_primary() { + Message message = mPhoneUT.obtainMessage(Phone.EVENT_GET_DEVICE_IMEI_DONE); + ImeiInfo imeiInfo = new ImeiInfo(); + imeiInfo.imei = FAKE_IMEI; + imeiInfo.svn = FAKE_IMEISV; + imeiInfo.type = ImeiInfo.ImeiType.PRIMARY; + AsyncResult.forMessage(message, imeiInfo, null); + mPhoneUT.handleMessage(message); + assertEquals(Phone.IMEI_TYPE_PRIMARY, mPhoneUT.getImeiType()); + assertEquals(FAKE_IMEI, mPhoneUT.getImei()); + } + + @Test + public void getImeiType_Secondary() { + Message message = mPhoneUT.obtainMessage(Phone.EVENT_GET_DEVICE_IMEI_DONE); + ImeiInfo imeiInfo = new ImeiInfo(); + imeiInfo.imei = FAKE_IMEI; + imeiInfo.svn = FAKE_IMEISV; + imeiInfo.type = ImeiInfo.ImeiType.SECONDARY; + AsyncResult.forMessage(message, imeiInfo, null); + mPhoneUT.handleMessage(message); + assertEquals(Phone.IMEI_TYPE_SECONDARY, mPhoneUT.getImeiType()); + assertEquals(FAKE_IMEI, mPhoneUT.getImei()); + } + + @Test + public void getImei() { + assertTrue(mPhoneUT.isPhoneTypeGsm()); + Message message = mPhoneUT.obtainMessage(Phone.EVENT_RADIO_AVAILABLE); + mPhoneUT.handleMessage(message); + verify(mSimulatedCommandsVerifier, times(2)).getImei(nullable(Message.class)); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java index 8054c203c0..f5c09ca935 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import static android.telephony.TelephonyManager.HAL_SERVICE_DATA; +import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; import static android.telephony.TelephonyManager.HAL_SERVICE_RADIO; import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; @@ -32,6 +33,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CONFERENCE import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DATA_REGISTRATION_STATE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DELETE_SMS_ON_SIM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEVICE_IDENTITY; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEVICE_IMEI; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DTMF; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ENABLE_UICC_APPLICATIONS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION; @@ -95,6 +97,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -125,12 +128,14 @@ import android.hardware.radio.V1_6.IRadio; import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.LinkAddress; +import android.os.AsyncResult; import android.os.Handler; import android.os.IPowerManager; import android.os.IThermalService; import android.os.Looper; import android.os.Message; import android.os.PowerManager; +import android.os.RemoteException; import android.os.WorkSource; import android.service.carrier.CarrierIdentifier; import android.telephony.AccessNetworkConstants; @@ -177,6 +182,7 @@ import androidx.test.filters.FlakyTest; import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -212,6 +218,7 @@ public class RILTest extends TelephonyTest { private RadioDataProxy mDataProxy; private RadioNetworkProxy mNetworkProxy; private RadioSimProxy mSimProxy; + private RadioModemProxy mRadioModemProxy; private Map mHalVersionV10 = new HashMap<>(); private Map mHalVersionV11 = new HashMap<>(); @@ -220,6 +227,7 @@ public class RILTest extends TelephonyTest { private Map mHalVersionV14 = new HashMap<>(); private Map mHalVersionV15 = new HashMap<>(); private Map mHalVersionV16 = new HashMap<>(); + private Map mHalVersionV21 = new HashMap<>(); private RIL mRILInstance; private RIL mRILUnderTest; @@ -307,6 +315,7 @@ public class RILTest extends TelephonyTest { mDataProxy = mock(RadioDataProxy.class); mNetworkProxy = mock(RadioNetworkProxy.class); mSimProxy = mock(RadioSimProxy.class); + mRadioModemProxy = mock(RadioModemProxy.class); try { TelephonyDevController.create(); } catch (RuntimeException e) { @@ -327,6 +336,7 @@ public class RILTest extends TelephonyTest { proxies.put(HAL_SERVICE_DATA, mDataProxy); proxies.put(HAL_SERVICE_NETWORK, mNetworkProxy); proxies.put(HAL_SERVICE_SIM, mSimProxy); + proxies.put(HAL_SERVICE_MODEM, mRadioModemProxy); mRILInstance = new RIL(context, RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE), Phone.PREFERRED_CDMA_SUBSCRIPTION, 0, proxies); @@ -338,9 +348,12 @@ public class RILTest extends TelephonyTest { eq(RadioNetworkProxy.class), any()); doReturn(mSimProxy).when(mRILUnderTest).getRadioServiceProxy(eq(RadioSimProxy.class), any()); + doReturn(mRadioModemProxy).when(mRILUnderTest).getRadioServiceProxy( + eq(RadioModemProxy.class), any()); doReturn(false).when(mDataProxy).isEmpty(); doReturn(false).when(mNetworkProxy).isEmpty(); doReturn(false).when(mSimProxy).isEmpty(); + doReturn(false).when(mRadioModemProxy).isEmpty(); try { for (int service = RIL.MIN_SERVICE_IDX; service <= RIL.MAX_SERVICE_IDX; service++) { mHalVersionV10.put(service, new HalVersion(1, 0)); @@ -350,6 +363,7 @@ public class RILTest extends TelephonyTest { mHalVersionV14.put(service, new HalVersion(1, 4)); mHalVersionV15.put(service, new HalVersion(1, 5)); mHalVersionV16.put(service, new HalVersion(1, 6)); + mHalVersionV21.put(service, new HalVersion(2, 1)); } replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV10); } catch (Exception e) { @@ -2926,4 +2940,31 @@ public class RILTest extends TelephonyTest { verifyRILResponse_1_6( mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_GET_SLICING_CONFIG); } + + @Test + public void getImei() throws RemoteException { + try { + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV21); + } catch (Exception e) { + fail(); + } + mRILUnderTest.getImei(obtainMessage()); + verify(mRadioModemProxy, atLeast(1)).getImei(mSerialNumberCaptor.capture()); + verifyRILResponse(mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_DEVICE_IMEI); + } + + @Test + public void getImeiNotSupported() { + try { + replaceInstance(RIL.class, "mHalVersion", mRILUnderTest, mHalVersionV16); + } catch (Exception e) { + fail(); + } + Message message = obtainMessage(); + mRILUnderTest.getImei(message); + AsyncResult ar = (AsyncResult) message.obj; + Assert.assertEquals(null, ar.result); + Assert.assertNotNull(ar.exception.getMessage()); + Assert.assertEquals("REQUEST_NOT_SUPPORTED", ar.exception.getMessage()); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index 9d00ed7b50..26c74183c3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -21,6 +21,7 @@ import android.hardware.radio.RadioError; import android.hardware.radio.V1_0.DataRegStateResult; import android.hardware.radio.V1_0.SetupDataCallResult; import android.hardware.radio.V1_0.VoiceRegStateResult; +import android.hardware.radio.modem.ImeiInfo; import android.net.KeepalivePacketData; import android.net.LinkProperties; import android.os.AsyncResult; @@ -67,6 +68,7 @@ import com.android.internal.telephony.RILUtils; import com.android.internal.telephony.RadioCapability; import com.android.internal.telephony.SmsResponse; import com.android.internal.telephony.SrvccConnection; +import com.android.internal.telephony.test.SimulatedCommandsVerifier; import com.android.internal.telephony.UUSInfo; import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; @@ -1810,6 +1812,16 @@ public class SimulatedCommands extends BaseCommands resultSuccess(response, new String[] {FAKE_IMEI, FAKE_IMEISV, FAKE_ESN, FAKE_MEID}); } + @Override + public void getImei(Message response) { + SimulatedCommandsVerifier.getInstance().getImei(response); + ImeiInfo imeiInfo = new ImeiInfo(); + imeiInfo.imei = FAKE_IMEI; + imeiInfo.svn = FAKE_IMEISV; + imeiInfo.type = ImeiInfo.ImeiType.SECONDARY; + resultSuccess(response, imeiInfo); + } + @Override public void getCDMASubscription(Message result) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java index 60add09651..37303c25d3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java @@ -1159,6 +1159,11 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } + @Override + public void getImei(Message response) { + + } + @Override public void getCDMASubscription(Message response) { -- GitLab From 9083d338a815a92b0e5d86af37d8b07815143543 Mon Sep 17 00:00:00 2001 From: rambowang Date: Tue, 6 Dec 2022 21:11:43 -0600 Subject: [PATCH 290/656] Update DataConfigManager with new CarrierConfigManager APIs - Replace carrier config change broadcast receiver with listener - Retrieve subset of carrier config as needed to save memory Bug: 244087782 Test: atest DataConfigManagerTest Change-Id: Idcf5c4ce96b48dd6da6b14f1f3b8f66842108c82 --- .../telephony/data/DataConfigManager.java | 23 ++++--------------- .../telephony/data/DataConfigManagerTest.java | 8 +++++++ .../data/DataNetworkControllerTest.java | 17 ++++++++++---- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index 81bf25f976..731aac75f3 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -19,10 +19,6 @@ package com.android.internal.telephony.data; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.StringDef; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.res.Resources; import android.net.LinkProperties; import android.net.NetworkCapabilities; @@ -338,22 +334,13 @@ public class DataConfigManager extends Handler { log("DataConfigManager created."); mCarrierConfigManager = mPhone.getContext().getSystemService(CarrierConfigManager.class); - - // Register for carrier configs update - IntentFilter filter = new IntentFilter(); - filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - mPhone.getContext().registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - if (mPhone.getPhoneId() == intent.getIntExtra( - CarrierConfigManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { + // Callback send msg to handler thread, so callback itself can be executed in binder thread. + mCarrierConfigManager.registerCarrierConfigChangeListener(Runnable::run, + (slotIndex, subId, carrierId, specificCarrierId) -> { + if (slotIndex == mPhone.getPhoneId()) { sendEmptyMessage(EVENT_CARRIER_CONFIG_CHANGED); } - } - } - }, filter, null, mPhone); + }); // Register for device config update DeviceConfig.addOnPropertiesChangedListener( diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java index 7b0443fcf3..f3128089aa 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataConfigManagerTest.java @@ -18,7 +18,12 @@ package com.android.internal.telephony.data; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; + import android.os.Looper; +import android.os.PersistableBundle; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -33,11 +38,14 @@ import org.junit.runner.RunWith; @TestableLooper.RunWithLooper public class DataConfigManagerTest extends TelephonyTest { private DataConfigManager mDataConfigManagerUT; + private PersistableBundle mBundle; @Before public void setUp() throws Exception { logd("DataConfigManagerTest +Setup!"); super.setUp(getClass().getSimpleName()); + mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); mDataConfigManagerUT = new DataConfigManager(mPhone, Looper.myLooper()); logd("DataConfigManagerTest -Setup!"); } 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 a967539175..0b243e7b2e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -43,7 +43,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.NonNull; -import android.content.Intent; import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.LinkAddress; @@ -75,6 +74,7 @@ import android.telephony.NetworkRegistrationInfo.RegistrationState; import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.SubscriptionPlan; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; @@ -165,6 +165,7 @@ public class DataNetworkControllerTest extends TelephonyTest { private final SparseArray mDataCallListChangedRegistrants = new SparseArray<>(); private DataNetworkController mDataNetworkControllerUT; private PersistableBundle mCarrierConfig; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; private AccessNetworksManagerCallback mAccessNetworksManagerCallback; private LinkBandwidthEstimatorCallback mLinkBandwidthEstimatorCallback; @@ -471,9 +472,10 @@ public class DataNetworkControllerTest extends TelephonyTest { private void carrierConfigChanged() { // Trigger carrier config reloading - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, 0); - mContext.sendBroadcast(intent); + mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* logicalSlotIndex */, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); + processAllMessages(); } @@ -768,6 +770,9 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(-1).when(mPhone).getSubId(); + // Capture listener to emulate the carrier config change notification used later + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); // Note that creating a "real" data network controller will also result in creating // real DataRetryManager, DataConfigManager, etc...Normally in unit test we should isolate // other modules and make them mocked, but only focusing on testing the unit we would like @@ -775,6 +780,10 @@ public class DataNetworkControllerTest extends TelephonyTest { // between DataNetworkController and its sub-modules, we intend to make those modules "real" // as well, except some modules below we replaced with mocks. mDataNetworkControllerUT = new DataNetworkController(mPhone, Looper.myLooper()); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); + assertThat(mCarrierConfigChangeListener).isNotNull(); doReturn(mDataNetworkControllerUT).when(mPhone).getDataNetworkController(); doReturn(1).when(mPhone).getSubId(); -- GitLab From 398781154823eeda684abf6407668e5af132dd07 Mon Sep 17 00:00:00 2001 From: Helen Date: Sat, 3 Dec 2022 19:32:16 +0000 Subject: [PATCH 291/656] Add a new system Api for ANBR - callSessionSendAnbrQuery - callSessionNotifyAnbr Bug: 259254356 Test: Build Change-Id: Ia465da88c18b8d2095b58273843683525eeefb7e --- .../internal/telephony/CommandsInterface.java | 13 ++++++ .../internal/telephony/GsmCdmaPhone.java | 8 ++++ .../com/android/internal/telephony/Phone.java | 17 +++++++- .../internal/telephony/imsphone/ImsPhone.java | 5 +++ .../imsphone/ImsPhoneCallTracker.java | 42 +++++++++++++++++++ 5 files changed, 83 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 25a27cf57c..3d84dbadd4 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2969,9 +2969,22 @@ public interface CommandsInterface { * @param mediaType Media type is used to identify media stream such as audio or video. * @param direction Direction of this packet stream (e.g. uplink or downlink). * @param bitsPerSecond The bit rate requested by the opponent UE. + * @param result Callback message to receive the result. */ default void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond, Message result) {} + /** + * Notifies the recommended bit rate for the indicated logical channel and direction. + * + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond The recommended bit rate for the UE for a specific logical channel and + * a specific direction by NW. + * @param result Callback message to receive the result. + */ + default void triggerNotifyAnbr(int mediaType, int direction, int bitsPerSecond, + Message result) {} + /** * Set the UE's ability to accept/reject null ciphered and/or null integrity-protected * connections. diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index fedb703b0b..e325678589 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -3452,6 +3452,14 @@ public class GsmCdmaPhone extends Phone { } break; + case EVENT_TRIGGER_NOTIFY_ANBR: + logd("EVENT_TRIGGER_NOTIFY_ANBR"); + ar = (AsyncResult) msg.obj; + if (ar.exception == null) { + mImsPhone.triggerNotifyAnbr(((int[]) ar.result)[0], ((int[]) ar.result)[1], + ((int[]) ar.result)[2]); + } + break; default: super.handleMessage(msg); } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index acea4f2810..6a5b7f55be 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -25,8 +25,8 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.hardware.radio.modem.ImeiInfo; import android.content.res.Configuration; +import android.hardware.radio.modem.ImeiInfo; import android.net.Uri; import android.os.AsyncResult; import android.os.Build; @@ -245,8 +245,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected static final int EVENT_IMS_DEREGISTRATION_TRIGGERED = 65; protected static final int EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE = 66; protected static final int EVENT_GET_DEVICE_IMEI_DONE = 67; + protected static final int EVENT_TRIGGER_NOTIFY_ANBR = 68; - protected static final int EVENT_LAST = EVENT_GET_DEVICE_IMEI_DONE; + protected static final int EVENT_LAST = EVENT_TRIGGER_NOTIFY_ANBR; // For shared prefs. private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_"; @@ -4989,6 +4990,18 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.triggerEpsFallback(reason, response); } + /** + * Notifies the recommended bit rate for the indicated logical channel and direction. + * + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond The recommended bit rate for the UE for a specific logical channel and + * a specific direction by NW. + */ + public void triggerNotifyAnbr(int mediaType, int direction, int bitsPerSecond) { + mCi.triggerNotifyAnbr(mediaType, direction, bitsPerSecond, null); + } + /** * Sets the emergency mode * diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 5067da89e6..31190a0d93 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -2757,6 +2757,11 @@ public class ImsPhone extends ImsPhoneBase { mDefaultPhone.updateImsCallStatus(imsCallInfo, response); } + @Override + public void triggerNotifyAnbr(int mediaType, int direction, int bitsPerSecond) { + mCT.triggerNotifyAnbr(mediaType, direction, bitsPerSecond); + } + @Override public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index bab3924f66..fc8a4ffc5c 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -4319,6 +4319,26 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { conn.receivedRtpHeaderExtensions(rtpHeaderExtensionData); } } + + /** + * Access Network Bitrate Recommendation Query (ANBRQ), see 3GPP TS 26.114. + * This API triggers radio to send ANBRQ message to the access network to query the desired + * bitrate. + * + * @param imsCall The ImsCall the data was received on. + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate requested by the other party UE through + * RTP CMR, RTCPAPP or TMMBR, and ImsStack converts this value to the MAC bitrate + * (defined in TS36.321, range: 0 ~ 8000 kbit/s). + */ + @Override + public void onCallSessionSendAnbrQuery(ImsCall imsCall, int mediaType, int direction, + int bitsPerSecond) { + log("onCallSessionSendAnbrQuery mediaType=" + mediaType + ", direction=" + + direction + ", bitPerSecond=" + bitsPerSecond); + handleSendAnbrQuery(mediaType, direction, bitsPerSecond); + } }; /** @@ -5837,6 +5857,28 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { return connList.toArray(new SrvccConnection[0]); } + /** Send the mediaType, direction, bitrate for ANBR Query to the radio */ + public void handleSendAnbrQuery(int mediaType, int direction, int bitsPerSecond) { + mPhone.getDefaultPhone().mCi.sendAnbrQuery(mediaType, direction, bitsPerSecond, null); + } + + + /** + * Notifies the recommended bit rate for the indicated logical channel and direction. + * + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond The recommended bit rate for the UE for a specific logical channel and + * a specific direction by NW. + */ + public void triggerNotifyAnbr(int mediaType, int direction, int bitsPerSecond) { + ImsCall activeCall = mForegroundCall.getFirstConnection().getImsCall(); + + if (activeCall != null) { + activeCall.callSessionNotifyAnbr(mediaType, direction, bitsPerSecond); + } + } + private boolean isCallProfileSupported(SrvccCall profile) { if (profile == null) return false; -- GitLab From 63f47bb93858da5837d264baff122843f4dfe340 Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Tue, 6 Dec 2022 13:14:18 +0000 Subject: [PATCH 292/656] Add MEP-A1 support in platform Test: Manual test on Pixel 7, atest FrameworksTelephonyTests Bug: 254866604 Change-Id: Ieef6c320d70ad8433af00444aff365a58a2a2d4c --- .../internal/telephony/CommandsInterface.java | 21 +++++ .../com/android/internal/telephony/RIL.java | 9 ++- .../android/internal/telephony/RILUtils.java | 17 +++- .../internal/telephony/RadioSimProxy.java | 27 ++++++- .../imsphone/ImsPhoneCommandInterface.java | 6 ++ .../telephony/uicc/IccCardStatus.java | 26 +++++++ .../telephony/uicc/IccSlotStatus.java | 54 +++++++++++++ .../internal/telephony/uicc/PortUtils.java | 77 +++++++++++++++++++ .../internal/telephony/uicc/UiccCard.java | 15 +++- .../telephony/uicc/UiccController.java | 12 +++ .../internal/telephony/uicc/UiccSlot.java | 26 ++++++- .../telephony/uicc/euicc/EuiccCard.java | 12 ++- .../telephony/uicc/euicc/EuiccPort.java | 28 +++++-- .../uicc/euicc/apdu/ApduCommand.java | 11 ++- .../TransmitApduLogicalChannelInvocation.java | 3 +- .../internal/telephony/SimulatedCommands.java | 5 ++ .../telephony/SimulatedCommandsVerifier.java | 7 ++ .../telephony/uicc/PortUtilsTest.java | 74 ++++++++++++++++++ .../internal/telephony/uicc/UiccCardTest.java | 2 +- .../telephony/uicc/UiccControllerTest.java | 4 + .../internal/telephony/uicc/UiccSlotTest.java | 47 +++++++++++ .../uicc/UiccStateChangedLauncherTest.java | 3 +- .../telephony/uicc/euicc/EuiccCardTest.java | 13 +++- .../telephony/uicc/euicc/EuiccPortTest.java | 28 ++++++- .../uicc/euicc/apdu/ApduSenderTest.java | 47 +++++------ .../uicc/euicc/apdu/LogicalChannelMocker.java | 51 ++++++++---- 26 files changed, 551 insertions(+), 74 deletions(-) create mode 100644 src/java/com/android/internal/telephony/uicc/PortUtils.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/uicc/PortUtilsTest.java diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index e6ddf249a8..1cf31724b0 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2126,6 +2126,27 @@ public interface CommandsInterface { public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, int p3, String data, Message response); + /** + * Exchange APDUs with the SIM on a logical channel. + * + * Input parameters equivalent to TS 27.007 AT+CGLA command. + * + * @param channel Channel id of the channel to use for communication. Has to + * be greater than zero. + * @param cla Class of the APDU command. + * @param instruction Instruction of the APDU command. + * @param p1 P1 value of the APDU command. + * @param p2 P2 value of the APDU command. + * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU + * is sent to the SIM. + * @param data Data to be sent with the APDU. + * @param isEs10Command whether APDU command is an ES10 command or a regular APDU + * @param response Callback message. response.obj.userObj will be + * an IccIoResult on success. + */ + void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, + int p1, int p2, int p3, String data, boolean isEs10Command, Message response); + /** * Exchange APDUs with the SIM on a basic channel. * diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 084ea10cc9..79d4e62fdb 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -4077,6 +4077,12 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, int p3, String data, Message result) { + iccTransmitApduLogicalChannel(channel, cla, instruction, p1, p2, p3, data, false, result); + } + + @Override + public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, + int p3, String data, boolean isEs10Command, Message result) { if (channel <= 0) { throw new RuntimeException( "Invalid channel in iccTransmitApduLogicalChannel: " + channel); @@ -4093,6 +4099,7 @@ public class RIL extends BaseCommands implements CommandsInterface { + String.format(" channel = %d", channel) + String.format(" cla = 0x%02X ins = 0x%02X", cla, instruction) + String.format(" p1 = 0x%02X p2 = 0x%02X p3 = 0x%02X", p1, p2, p3) + + " isEs10Command = " + isEs10Command + " data = " + data); } else { riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); @@ -4101,7 +4108,7 @@ public class RIL extends BaseCommands implements CommandsInterface { try { simProxy.iccTransmitApduLogicalChannel( - rr.mSerial, channel, cla, instruction, p1, p2, p3, data); + rr.mSerial, channel, cla, instruction, p1, p2, p3, data, isEs10Command); } catch (RemoteException | RuntimeException e) { handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccTransmitApduLogicalChannel", e); } diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index c362d65334..f112d58a03 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -368,6 +368,7 @@ import com.android.internal.telephony.uicc.IccSimPortInfo; import com.android.internal.telephony.uicc.IccSlotPortMapping; import com.android.internal.telephony.uicc.IccSlotStatus; import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.uicc.PortUtils; import com.android.internal.telephony.uicc.SimPhonebookRecord; import com.android.telephony.Rlog; @@ -1822,10 +1823,12 @@ public class RILUtils { * @param p2 p2 * @param p3 p3 * @param data data + * @param radioHalVersion radio hal version * @return The converted SimApdu */ public static android.hardware.radio.sim.SimApdu convertToHalSimApduAidl(int channel, int cla, - int instruction, int p1, int p2, int p3, String data) { + int instruction, int p1, int p2, int p3, String data, boolean isEs10Command, + HalVersion radioHalVersion) { android.hardware.radio.sim.SimApdu msg = new android.hardware.radio.sim.SimApdu(); msg.sessionId = channel; msg.cla = cla; @@ -1834,6 +1837,9 @@ public class RILUtils { msg.p2 = p2; msg.p3 = p3; msg.data = convertNullToEmptyString(data); + if (radioHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_2_1)) { + msg.isEs10 = isEs10Command; + } return msg; } @@ -4353,6 +4359,7 @@ public class RILUtils { android.hardware.radio.sim.CardStatus cardStatus) { IccCardStatus iccCardStatus = new IccCardStatus(); iccCardStatus.setCardState(cardStatus.cardState); + iccCardStatus.setMultipleEnabledProfilesMode(cardStatus.supportedMepMode); iccCardStatus.setUniversalPinState(cardStatus.universalPinState); iccCardStatus.mGsmUmtsSubscriptionAppIndex = cardStatus.gsmUmtsSubscriptionAppIndex; iccCardStatus.mCdmaSubscriptionAppIndex = cardStatus.cdmaSubscriptionAppIndex; @@ -4380,7 +4387,9 @@ public class RILUtils { } IccSlotPortMapping slotPortMapping = new IccSlotPortMapping(); slotPortMapping.mPhysicalSlotIndex = cardStatus.slotMap.physicalSlotId; - slotPortMapping.mPortIndex = cardStatus.slotMap.portId; + slotPortMapping.mPortIndex = PortUtils.convertFromHalPortIndex( + cardStatus.slotMap.physicalSlotId, cardStatus.slotMap.portId, + iccCardStatus.mCardState, iccCardStatus.mSupportedMepMode); iccCardStatus.mSlotPortMapping = slotPortMapping; return iccCardStatus; } @@ -4496,6 +4505,7 @@ public class RILUtils { } iccSlotStatus.atr = slotStatus.atr; iccSlotStatus.eid = slotStatus.eid; + iccSlotStatus.setMultipleEnabledProfilesMode(slotStatus.supportedMepMode); response.add(iccSlotStatus); } return response; @@ -4563,7 +4573,8 @@ public class RILUtils { int logicalSlotIdx = mapping.getLogicalSlotIndex(); res[logicalSlotIdx] = new android.hardware.radio.config.SlotPortMapping(); res[logicalSlotIdx].physicalSlotId = mapping.getPhysicalSlotIndex(); - res[logicalSlotIdx].portId = mapping.getPortIndex(); + res[logicalSlotIdx].portId = PortUtils.convertToHalPortIndex( + mapping.getPhysicalSlotIndex(), mapping.getPortIndex()); } return res; } diff --git a/src/java/com/android/internal/telephony/RadioSimProxy.java b/src/java/com/android/internal/telephony/RadioSimProxy.java index d1bb6b111a..a305de96af 100644 --- a/src/java/com/android/internal/telephony/RadioSimProxy.java +++ b/src/java/com/android/internal/telephony/RadioSimProxy.java @@ -53,6 +53,9 @@ public class RadioSimProxy extends RadioServiceProxy { HalVersion newHalVersion; int version = sim.getInterfaceVersion(); switch(version) { + case 2: + newHalVersion = RIL.RADIO_HAL_VERSION_2_1; + break; default: newHalVersion = RIL.RADIO_HAL_VERSION_2_0; break; @@ -373,7 +376,8 @@ public class RadioSimProxy extends RadioServiceProxy { if (isEmpty()) return; if (isAidl()) { mSimProxy.iccTransmitApduBasicChannel(serial, - RILUtils.convertToHalSimApduAidl(0, cla, instruction, p1, p2, p3, data)); + RILUtils.convertToHalSimApduAidl(0, cla, instruction, p1, p2, p3, data, + false, mHalVersion)); } else { mRadioProxy.iccTransmitApduBasicChannel(serial, RILUtils.convertToHalSimApdu(0, cla, instruction, p1, p2, p3, data)); @@ -394,10 +398,29 @@ public class RadioSimProxy extends RadioServiceProxy { */ public void iccTransmitApduLogicalChannel(int serial, int channel, int cla, int instruction, int p1, int p2, int p3, String data) throws RemoteException { + iccTransmitApduLogicalChannel(serial, channel, cla, instruction, p1, p2, p3, data, false); + } + + /** + * Call IRadioSim#iccTransmitApduLogicalChannel + * @param serial Serial number of request + * @param channel Channel ID of the channel to use for communication + * @param cla Class of the command + * @param instruction Instruction of the command + * @param p1 P1 value of the command + * @param p2 P2 value of the command + * @param p3 P3 value of the command + * @param data Data to be sent + * @param isEs10Command APDU is an isEs10 command or not + * @throws RemoteException + */ + public void iccTransmitApduLogicalChannel(int serial, int channel, int cla, int instruction, + int p1, int p2, int p3, String data, boolean isEs10Command) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mSimProxy.iccTransmitApduLogicalChannel(serial, - RILUtils.convertToHalSimApduAidl(channel, cla, instruction, p1, p2, p3, data)); + RILUtils.convertToHalSimApduAidl(channel, cla, instruction, p1, p2, p3, data, + isEs10Command, mHalVersion)); } else { mRadioProxy.iccTransmitApduLogicalChannel(serial, RILUtils.convertToHalSimApdu(channel, cla, instruction, p1, p2, p3, data)); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java index 14952b72fe..31891a00af 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java @@ -609,6 +609,12 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, int p3, String data, Message response) {} + + @Override + public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, + int p1, int p2, int p3, String data, + boolean isEs10Command, Message response) {} + @Override public void iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, int p3, String data, Message response) {} diff --git a/src/java/com/android/internal/telephony/uicc/IccCardStatus.java b/src/java/com/android/internal/telephony/uicc/IccCardStatus.java index ec07780c8f..e2cc9e9632 100644 --- a/src/java/com/android/internal/telephony/uicc/IccCardStatus.java +++ b/src/java/com/android/internal/telephony/uicc/IccCardStatus.java @@ -20,6 +20,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.telephony.SubscriptionInfo; +import com.android.internal.telephony.uicc.IccSlotStatus.MultipleEnabledProfilesMode; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -90,6 +91,30 @@ public class IccCardStatus { public IccSlotPortMapping mSlotPortMapping; + public MultipleEnabledProfilesMode mSupportedMepMode = MultipleEnabledProfilesMode.NONE; + + /** + * Set the MultipleEnabledProfilesMode according to the input mode. + */ + public void setMultipleEnabledProfilesMode(int mode) { + switch(mode) { + case 0: + mSupportedMepMode = MultipleEnabledProfilesMode.NONE; + break; + case 1: + mSupportedMepMode = MultipleEnabledProfilesMode.MEP_A1; + break; + case 2: + mSupportedMepMode = MultipleEnabledProfilesMode.MEP_A2; + break; + case 3: + mSupportedMepMode = MultipleEnabledProfilesMode.MEP_B; + break; + default: + throw new RuntimeException("Unrecognized RIL_MultipleEnabledProfilesMode: " + mode); + } + } + public void setCardState(int state) { switch(state) { case 0: @@ -174,6 +199,7 @@ public class IccCardStatus { sb.append(",atr=").append(atr); sb.append(",iccid=").append(SubscriptionInfo.givePrintableIccid(iccid)); sb.append(",eid=").append(Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, eid)); + sb.append(",SupportedMepMode=").append(mSupportedMepMode); sb.append(",SlotPortMapping=").append(mSlotPortMapping); sb.append("}"); diff --git a/src/java/com/android/internal/telephony/uicc/IccSlotStatus.java b/src/java/com/android/internal/telephony/uicc/IccSlotStatus.java index 96a3a33ffd..3bbef23518 100644 --- a/src/java/com/android/internal/telephony/uicc/IccSlotStatus.java +++ b/src/java/com/android/internal/telephony/uicc/IccSlotStatus.java @@ -30,11 +30,42 @@ public class IccSlotStatus { /* Added state active to check slotState in old HAL case.*/ public static final int STATE_ACTIVE = 1; + public enum MultipleEnabledProfilesMode { + /** + * If there is no jointly supported MEP mode, set supported MEP mode to NONE. + */ + NONE, + /** + * In case of MEP-A1, the ISD-R is selected on eSIM port 0 only and profiles are selected + * on eSIM ports 1 and higher, with the eSIM port being assigned by the LPA or platform. + */ + MEP_A1, + /** + * In case of MEP-A2, the ISD-R is selected on eSIM port 0 only and profiles are selected + * on eSIM ports 1 and higher, with the eSIM port being assigned by the eUICC. + */ + MEP_A2, + /** + * In case of MEP-B, profiles are selected on eSIM ports 0 and higher, with the ISD-R being + * selectable on any of these eSIM ports. + */ + MEP_B; + + public boolean isMepAMode() { + return (this == MEP_A1 || this == MEP_A2); + } + + public boolean isMepA1Mode() { + return this == MEP_A1; + } + } + public IccCardStatus.CardState cardState; public String atr; public String eid; public IccSimPortInfo[] mSimPortInfos; + public MultipleEnabledProfilesMode mSupportedMepMode = MultipleEnabledProfilesMode.NONE; /** * Set the cardState according to the input state. @@ -58,6 +89,28 @@ public class IccSlotStatus { } } + /** + * Set the MultipleEnabledProfilesMode according to the input mode. + */ + public void setMultipleEnabledProfilesMode(int mode) { + switch(mode) { + case 0: + mSupportedMepMode = MultipleEnabledProfilesMode.NONE; + break; + case 1: + mSupportedMepMode = MultipleEnabledProfilesMode.MEP_A1; + break; + case 2: + mSupportedMepMode = MultipleEnabledProfilesMode.MEP_A2; + break; + case 3: + mSupportedMepMode = MultipleEnabledProfilesMode.MEP_B; + break; + default: + throw new RuntimeException("Unrecognized RIL_MultipleEnabledProfilesMode: " + mode); + } + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -72,6 +125,7 @@ public class IccSlotStatus { } else { sb.append("num_ports=null"); } + sb.append(", SupportedMepMode=" + mSupportedMepMode); sb.append("}"); return sb.toString(); } diff --git a/src/java/com/android/internal/telephony/uicc/PortUtils.java b/src/java/com/android/internal/telephony/uicc/PortUtils.java new file mode 100644 index 0000000000..4a18b5688d --- /dev/null +++ b/src/java/com/android/internal/telephony/uicc/PortUtils.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2022 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.uicc; + +import android.annotation.NonNull; + +import com.android.internal.telephony.uicc.IccSlotStatus.MultipleEnabledProfilesMode; + +/** + * Various methods, useful for dealing with port. + */ +public class PortUtils { + + /** + * Converts the port index to compatible with the HAL. + * + * @param mepMode supported MultipleEnabledProfilesMode + * @param portIndex port index + * @return target index according to the MultipleEnabledProfilesMode + */ + public static int convertToHalPortIndex(@NonNull MultipleEnabledProfilesMode mepMode, + int portIndex) { + // In case of MEP-A1 and MEP-A2, profiles are selected on eSIM Ports 1 and higher, hence + // HAL expects the ports are indexed with 1, 2... etc. + // So inorder to compatible with HAL, shift the port index. + return mepMode.isMepAMode() ? ++portIndex : portIndex; + } + + /** + * Converts the port index to compatible with the HAL. + * + * @param slotIndex physical slot index corresponding to the portIndex + * @param portIndex port index + * @return target port index according to the MultipleEnabledProfilesMode + */ + public static int convertToHalPortIndex(int slotIndex, int portIndex) { + return convertToHalPortIndex(UiccController.getInstance().getSupportedMepMode(slotIndex), + portIndex); + } + + /** + * Converts the port index to compatible with the platform. + * + * @param slotIndex physical slot index corresponding to the portIndex + * @param portIndex target port index + * @param cardState cardState + * @param supportedMepMode supported MEP mode + * @return shifted port index according to the MultipleEnabledProfilesMode + */ + public static int convertFromHalPortIndex(int slotIndex, int portIndex, + IccCardStatus.CardState cardState, MultipleEnabledProfilesMode supportedMepMode) { + // In case of MEP-A1 and MEP-A2, profiles are selected on eSIM Ports 1 and higher. + // But inorder to platform code MEP mode agnostic, platform always expects the ports + // are indexed with 0, 1... etc. Hence shift the target port index to be compatible + // with platform. + + // When the SIM_STATUS is related to CARDSTATE_ABSENT, CardStatus will not contain proper + // MEP mode info, fallback onto to the supportedMepMode data available in UiccSlot. + MultipleEnabledProfilesMode mepMode = cardState.isCardPresent() ? supportedMepMode + : UiccController.getInstance().getSupportedMepMode(slotIndex); + return mepMode.isMepAMode() ? --portIndex : portIndex; + } +} diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java index 54324b98c5..67f120fd54 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCard.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java @@ -24,6 +24,7 @@ import android.text.TextUtils; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.uicc.IccCardStatus.CardState; +import com.android.internal.telephony.uicc.IccSlotStatus.MultipleEnabledProfilesMode; import com.android.internal.telephony.uicc.euicc.EuiccCard; import com.android.internal.telephony.uicc.euicc.EuiccPort; import com.android.telephony.Rlog; @@ -51,16 +52,19 @@ public class UiccCard { private CardState mCardState; protected String mCardId; protected boolean mIsSupportsMultipleEnabledProfiles; + protected MultipleEnabledProfilesMode mSupportedMepMode; protected LinkedHashMap mUiccPorts = new LinkedHashMap<>(); private HashMap mPhoneIdToPortIdx = new HashMap<>(); public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, - boolean isSupportsMultipleEnabledProfiles) { + boolean isSupportsMultipleEnabledProfiles, + MultipleEnabledProfilesMode supportedMepMode) { if (DBG) log("Creating"); mCardState = ics.mCardState; mLock = lock; mIsSupportsMultipleEnabledProfiles = isSupportsMultipleEnabledProfiles; + mSupportedMepMode = supportedMepMode; update(c, ci, ics, phoneId); } @@ -110,7 +114,7 @@ public class UiccCard { if (port == null) { if (this instanceof EuiccCard) { port = new EuiccPort(c, ci, ics, phoneId, mLock, this, - mIsSupportsMultipleEnabledProfiles); // eSim + mIsSupportsMultipleEnabledProfiles, mSupportedMepMode); // eSim } else { port = new UiccPort(c, ci, ics, phoneId, mLock, this); // pSim } @@ -144,13 +148,16 @@ public class UiccCard { /** - * Updates MEP(Multiple Enabled Profile) support flag. + * Updates MEP(Multiple Enabled Profile) support and supported mode flags. * *

If IccSlotStatus comes later, the number of ports reported is only known after the * UiccCard creation which will impact UICC MEP capability. */ - public void updateSupportMultipleEnabledProfile(boolean supported) { + public void updateSupportMepProperties(boolean supported, + MultipleEnabledProfilesMode supportedMepMode) { + // TODO(b/262449536): Handle with single MEP flag to avoid inconsistency. mIsSupportsMultipleEnabledProfiles = supported; + mSupportedMepMode = supportedMepMode; } @UnsupportedAppUsage diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 4743bce77d..ea99d9a3f6 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -1453,6 +1453,18 @@ public class UiccController extends Handler { return mUseRemovableEsimAsDefault; } + /** + * Returns the MEP mode supported by the UiccSlot associated with slotIndex. + * @param slotIndex physical slot index + * @return MultipleEnabledProfilesMode supported by the slot + */ + public IccSlotStatus.MultipleEnabledProfilesMode getSupportedMepMode(int slotIndex) { + synchronized (mLock) { + UiccSlot slot = getUiccSlot(slotIndex); + return slot != null ? slot.getSupportedMepMode() + : IccSlotStatus.MultipleEnabledProfilesMode.NONE; + } + } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private void log(String string) { diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index 8de7e0108a..ec4919609c 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -41,6 +41,7 @@ import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.uicc.IccCardStatus.CardState; +import com.android.internal.telephony.uicc.IccSlotStatus.MultipleEnabledProfilesMode; import com.android.internal.telephony.uicc.euicc.EuiccCard; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -87,6 +88,8 @@ public class UiccSlot extends Handler { private String mEid; private AnswerToReset mAtr; private boolean mIsRemovable; + private MultipleEnabledProfilesMode mSupportedMepMode; + // Map each available portIdx to phoneId private HashMap mPortIdxToPhoneId = new HashMap<>(); //Map each available portIdx with old radio state for state checking @@ -102,6 +105,7 @@ public class UiccSlot extends Handler { mContext = c; mActive = isActive; mCardState = null; + mSupportedMepMode = MultipleEnabledProfilesMode.NONE; } /** @@ -115,6 +119,10 @@ public class UiccSlot extends Handler { mIccIds.put(ics.mSlotPortMapping.mPortIndex, ics.iccid); parseAtr(ics.atr); mIsRemovable = isSlotRemovable(slotIndex); + // Update supported MEP mode in IccCardStatus if the CardState is present. + if (ics.mCardState.isCardPresent()) { + mSupportedMepMode = ics.mSupportedMepMode; + } int radioState = ci.getRadioState(); if (DBG) { @@ -147,7 +155,8 @@ public class UiccSlot extends Handler { if (!mIsEuicc) { // Uicc does not support MEP, passing false by default. - mUiccCard = new UiccCard(mContext, ci, ics, phoneId, mLock, false); + mUiccCard = new UiccCard(mContext, ci, ics, phoneId, mLock, false, + MultipleEnabledProfilesMode.NONE); } else { // The EID should be reported with the card status, but in case it's not we want // to catch that here @@ -156,7 +165,7 @@ public class UiccSlot extends Handler { + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, ics.eid)); } mUiccCard = new EuiccCard(mContext, ci, ics, phoneId, mLock, - isMultipleEnabledProfileSupported()); + isMultipleEnabledProfileSupported(), getSupportedMepMode()); } } else { if (mUiccCard != null) { @@ -178,6 +187,7 @@ public class UiccSlot extends Handler { mCardState = iss.cardState; mEid = iss.eid; mIsRemovable = isSlotRemovable(slotIndex); + mSupportedMepMode = iss.mSupportedMepMode; for (int i = 0; i < simPortInfos.length; i++) { int phoneId = iss.mSimPortInfos[i].mLogicalSlotIndex; @@ -224,7 +234,8 @@ public class UiccSlot extends Handler { // Since the MEP capability is related with number ports reported, thus need to // update the flag after UiccCard creation. if (mUiccCard != null) { - mUiccCard.updateSupportMultipleEnabledProfile(isMultipleEnabledProfileSupported()); + mUiccCard.updateSupportMepProperties(isMultipleEnabledProfileSupported(), + getSupportedMepMode()); } } } @@ -566,6 +577,14 @@ public class UiccSlot extends Handler { } } + /** + * Returns the supported MEP mode. + */ + public MultipleEnabledProfilesMode getSupportedMepMode() { + synchronized (mLock) { + return mSupportedMepMode; + } + } /** * Processes radio state unavailable event */ @@ -612,6 +631,7 @@ public class UiccSlot extends Handler { pw.println(" mPortIdxToPhoneId=" + mPortIdxToPhoneId); pw.println(" mEid=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mEid)); pw.println(" mCardState=" + mCardState); + pw.println(" mSupportedMepMode=" + mSupportedMepMode); if (mUiccCard != null) { pw.println(" mUiccCard=" + mUiccCard); mUiccCard.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java index 75bc3ba710..0d98e185f9 100644 --- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java +++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java @@ -27,6 +27,7 @@ import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.uicc.IccCardStatus; +import com.android.internal.telephony.uicc.IccSlotStatus.MultipleEnabledProfilesMode; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccPort; import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback; @@ -43,8 +44,9 @@ public class EuiccCard extends UiccCard { private RegistrantList mEidReadyRegistrants; public EuiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, - boolean isSupportsMultipleEnabledProfiles) { - super(c, ci, ics, phoneId, lock, isSupportsMultipleEnabledProfiles); + boolean isSupportsMultipleEnabledProfiles, + MultipleEnabledProfilesMode supportedMepMode) { + super(c, ci, ics, phoneId, lock, isSupportsMultipleEnabledProfiles, supportedMepMode); if (TextUtils.isEmpty(ics.eid)) { loge("no eid given in constructor for phone " + phoneId); loadEidAndNotifyRegistrants(); @@ -61,11 +63,13 @@ public class EuiccCard extends UiccCard { * UiccCard creation which will impact UICC MEP capability. */ @Override - public void updateSupportMultipleEnabledProfile(boolean supported) { + public void updateSupportMepProperties(boolean supported, + MultipleEnabledProfilesMode supportedMepMode) { mIsSupportsMultipleEnabledProfiles = supported; + mSupportedMepMode = supportedMepMode; for (UiccPort port : mUiccPorts.values()) { if (port instanceof EuiccPort) { - ((EuiccPort) port).updateSupportMultipleEnabledProfile(supported); + ((EuiccPort) port).updateSupportMepProperties(supported, supportedMepMode); } else { loge("eUICC card has non-euicc port object:" + port.toString()); } diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java index 73d5866616..3dd260ecac 100644 --- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java +++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java @@ -35,7 +35,9 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.IccIoResult; +import com.android.internal.telephony.uicc.IccSlotStatus.MultipleEnabledProfilesMode; import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.uicc.PortUtils; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccPort; import com.android.internal.telephony.uicc.asn1.Asn1Decoder; @@ -125,9 +127,11 @@ public class EuiccPort extends UiccPort { private volatile String mEid; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public boolean mIsSupportsMultipleEnabledProfiles; + private MultipleEnabledProfilesMode mSupportedMepMode; public EuiccPort(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, - UiccCard card, boolean isSupportsMultipleEnabledProfiles) { + UiccCard card, boolean isSupportsMultipleEnabledProfiles, + MultipleEnabledProfilesMode supportedMepMode) { super(c, ci, ics, phoneId, lock, card); // TODO: Set supportExtendedApdu based on ATR. mApduSender = new ApduSender(ci, ISD_R_AID, false /* supportExtendedApdu */); @@ -138,6 +142,7 @@ public class EuiccPort extends UiccPort { mCardId = ics.eid; } mIsSupportsMultipleEnabledProfiles = isSupportsMultipleEnabledProfiles; + mSupportedMepMode = supportedMepMode; } /** @@ -165,12 +170,14 @@ public class EuiccPort extends UiccPort { } /** - * Updates MEP(Multiple Enabled Profile) support flag. + * Updates MEP(Multiple Enabled Profile) support and mode flags. * The flag can be updated after the port creation. */ - public void updateSupportMultipleEnabledProfile(boolean supported) { + public void updateSupportMepProperties(boolean supported, + MultipleEnabledProfilesMode supportedMepMode) { logd("updateSupportMultipleEnabledProfile"); mIsSupportsMultipleEnabledProfiles = supported; + mSupportedMepMode = supportedMepMode; } /** @@ -303,11 +310,20 @@ public class EuiccPort extends UiccPort { sendApduWithSimResetErrorWorkaround( newRequestProvider((RequestBuilder requestBuilder) -> { byte[] iccidBytes = IccUtils.bcdToBytes(padTrailingFs(iccid)); - requestBuilder.addStoreData(Asn1Node.newBuilder(Tags.TAG_ENABLE_PROFILE) + Asn1Node.Builder builder = Asn1Node.newBuilder(Tags.TAG_ENABLE_PROFILE) .addChild(Asn1Node.newBuilder(Tags.TAG_CTX_COMP_0) .addChildAsBytes(Tags.TAG_ICCID, iccidBytes)) - .addChildAsBoolean(Tags.TAG_CTX_1, refresh) - .build().toHex()); + .addChildAsBoolean(Tags.TAG_CTX_1, refresh); + // Port index should be added only in case of MEP-A1 mode. + if (mSupportedMepMode.isMepA1Mode()) { + // In case of MEP-A1 and MEP-A2, profiles are selected on eSIM Ports 1 and + // higher (refer as target port). Hence, convert the portIndex to + // target port index before adding. + builder.addChildAsInteger(Tags.TAG_CTX_2, + PortUtils.convertToHalPortIndex(mSupportedMepMode, + super.getPortIdx())); + } + requestBuilder.addStoreData(builder.build().toHex()); }), response -> { int result; diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduCommand.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduCommand.java index 7a8978f822..8fbeb4450f 100644 --- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduCommand.java +++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduCommand.java @@ -43,6 +43,12 @@ class ApduCommand { /** Command data of an APDU as defined in GlobalPlatform Card Specification v.2.3. */ public final String cmdHex; + /** + * isEs10 indicates that the current streaming APDU contains an ES10 command or it is a regular + * APDU. (As per spec SGP.22 V3.0, ES10 commands needs to be sent over command port of MEP-A1) + */ + public final boolean isEs10; + /** The parameters are defined as in GlobalPlatform Card Specification v.2.3. */ ApduCommand(int channel, int cla, int ins, int p1, int p2, int p3, String cmdHex) { this.channel = channel; @@ -52,11 +58,14 @@ class ApduCommand { this.p2 = p2; this.p3 = p3; this.cmdHex = cmdHex; + // TODO: Currently ApduCommand is used for ES10 commands, so updating to true by default. + // Modify it in case used for non ES10 commands in future. + this.isEs10 = true; } @Override public String toString() { return "ApduCommand(channel=" + channel + ", cla=" + cla + ", ins=" + ins + ", p1=" + p1 - + ", p2=" + p2 + ", p3=" + p3 + ", cmd=" + cmdHex + ")"; + + ", p2=" + p2 + ", p3=" + p3 + ", cmd=" + cmdHex + ", isEs10=" + isEs10 + ")"; } } diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/TransmitApduLogicalChannelInvocation.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/TransmitApduLogicalChannelInvocation.java index 09de54a804..ca75beb55f 100644 --- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/TransmitApduLogicalChannelInvocation.java +++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/TransmitApduLogicalChannelInvocation.java @@ -48,7 +48,8 @@ public class TransmitApduLogicalChannelInvocation protected void sendRequestMessage(ApduCommand command, Message msg) { Rlog.v(LOG_TAG, "Send: " + command); mCi.iccTransmitApduLogicalChannel(command.channel, command.cla | command.channel, - command.ins, command.p1, command.p2, command.p3, command.cmdHex, msg); + command.ins, command.p1, command.p2, command.p3, command.cmdHex, command.isEs10, + msg); } @Override diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index 9d00ed7b50..400872cd35 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -2171,6 +2171,11 @@ public class SimulatedCommands extends BaseCommands } } + @Override + public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, + int p1, int p2, int p3, String data, boolean isEs10Command, Message response) { + } + @Override public void iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, int p3, String data, Message response) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java index 60add09651..f09f3bcf60 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java @@ -1309,6 +1309,13 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } + @Override + public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, + int p2, int p3, String data, + boolean isEs10Command, Message response) { + + } + @Override public void iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, int p3, String data, Message response) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/PortUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/PortUtilsTest.java new file mode 100644 index 0000000000..69d9a7d004 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/PortUtilsTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony.uicc; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class PortUtilsTest extends TelephonyTest { + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + doReturn(IccSlotStatus.MultipleEnabledProfilesMode.NONE) + .when(mUiccController).getSupportedMepMode(anyInt()); + processAllMessages(); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testConvertToHalPortIndex() { + assertEquals(0, PortUtils.convertToHalPortIndex(0, 0)); + doReturn(IccSlotStatus.MultipleEnabledProfilesMode.MEP_A1) + .when(mUiccController).getSupportedMepMode(anyInt()); + assertEquals(1, PortUtils.convertToHalPortIndex(0, 0)); + } + + @Test + public void testConvertFromHalPortIndex() { + assertEquals(0, PortUtils.convertFromHalPortIndex(0, 1, + IccCardStatus.CardState.CARDSTATE_PRESENT, + IccSlotStatus.MultipleEnabledProfilesMode.MEP_A1)); + assertEquals(1, PortUtils.convertFromHalPortIndex(0, 1, + IccCardStatus.CardState.CARDSTATE_PRESENT, + IccSlotStatus.MultipleEnabledProfilesMode.MEP_B)); + assertEquals(1, PortUtils.convertFromHalPortIndex(0, 1, + IccCardStatus.CardState.CARDSTATE_ABSENT, + IccSlotStatus.MultipleEnabledProfilesMode.MEP_A1)); + doReturn(IccSlotStatus.MultipleEnabledProfilesMode.MEP_A1) + .when(mUiccController).getSupportedMepMode(anyInt()); + assertEquals(0, PortUtils.convertFromHalPortIndex(0, 1, + IccCardStatus.CardState.CARDSTATE_ABSENT, + IccSlotStatus.MultipleEnabledProfilesMode.NONE)); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java index b30c3a7c17..0ed112d39d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java @@ -61,7 +61,7 @@ public class UiccCardTest extends TelephonyTest { mIccIoResult = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes("FF40")); mSimulatedCommands.setIccIoResultForApduLogicalChannel(mIccIoResult); mUiccCard = new UiccCard(mContext, mSimulatedCommands, mIccCardStatus, 0 /* phoneId */, - new Object(), false); + new Object(), false, IccSlotStatus.MultipleEnabledProfilesMode.NONE); processAllMessages(); logd("create UiccCard"); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java index 0344e5772f..2ab23f3f19 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java @@ -104,6 +104,8 @@ public class UiccControllerTest extends TelephonyTest { doReturn(PHONE_COUNT).when(mTelephonyManager).getPhoneCount(); doReturn(PHONE_COUNT).when(mTelephonyManager).getSimCount(); + doReturn(IccSlotStatus.MultipleEnabledProfilesMode.NONE) + .when(mMockSlot).getSupportedMepMode(); // set number of slots to 1 mContextFixture.putIntResource(com.android.internal.R.integer.config_num_physical_slots, 1); @@ -114,6 +116,8 @@ public class UiccControllerTest extends TelephonyTest { mIccCardStatus.mCdmaSubscriptionAppIndex = mIccCardStatus.mImsSubscriptionAppIndex = mIccCardStatus.mGsmUmtsSubscriptionAppIndex = -1; + mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_PRESENT; + mIccCardStatus.mSupportedMepMode = IccSlotStatus.MultipleEnabledProfilesMode.NONE; mSimulatedCommands.setIccCardStatus(mIccCardStatus); // for testing we pretend slotIndex is set. In reality it would be invalid on older versions // (before 1.2) of hal diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java index 7bc737bfd7..6aab7ad9d0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java @@ -511,4 +511,51 @@ public class UiccSlotTest extends TelephonyTest { assertTrue("EuiccCard should be removable", mUiccSlot.isRemovable()); } + @Test + @SmallTest + public void testMultipleEnabledProfilesData() { + IccSlotStatus iss = new IccSlotStatus(); + IccSimPortInfo simPortInfo1 = new IccSimPortInfo(); + simPortInfo1.mPortActive = false; + simPortInfo1.mLogicalSlotIndex = -1; + simPortInfo1.mIccId = "fake-iccid"; + + IccSimPortInfo simPortInfo2 = new IccSimPortInfo(); + simPortInfo2.mPortActive = true; + simPortInfo2.mLogicalSlotIndex = 0; + simPortInfo2.mIccId = "fake-iccid"; + + iss.mSimPortInfos = new IccSimPortInfo[] {simPortInfo1, simPortInfo2}; + iss.cardState = IccCardStatus.CardState.CARDSTATE_PRESENT; + iss.atr = "3B9F97C00AB1FE453FC6838031E073FE211F65D002341569810F21"; + iss.setMultipleEnabledProfilesMode(3); + + + // initial state + assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); + assertEquals(IccSlotStatus.MultipleEnabledProfilesMode.NONE, + mUiccSlot.getSupportedMepMode()); + assertFalse(mUiccSlot.isMultipleEnabledProfileSupported()); + + // update slot to inactive + mUiccSlot.update(null, iss, 0 /* slotIndex */); + + // assert on updated values + assertNull(mUiccSlot.getUiccCard()); + assertEquals(IccCardStatus.CardState.CARDSTATE_PRESENT, mUiccSlot.getCardState()); + assertTrue(mUiccSlot.isMultipleEnabledProfileSupported()); + assertEquals(IccSlotStatus.MultipleEnabledProfilesMode.MEP_B, + mUiccSlot.getSupportedMepMode()); + + iss.mSimPortInfos = new IccSimPortInfo[] {simPortInfo1}; + iss.setMultipleEnabledProfilesMode(1); // Set MEP mode to MEP-A1 + + // update port info and MEP mode + mUiccSlot.update(null, iss, 0 /* slotIndex */); + + // assert on updated values + assertFalse(mUiccSlot.isMultipleEnabledProfileSupported()); + assertEquals(IccSlotStatus.MultipleEnabledProfilesMode.MEP_A1, + mUiccSlot.getSupportedMepMode()); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java index 18247d38d0..aa0b0d9652 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java @@ -99,7 +99,8 @@ public class UiccStateChangedLauncherTest extends TelephonyTest { // The first broadcast should be sent after initialization. UiccCard card = new UiccCard(mContext, mSimulatedCommands, - makeCardStatus(CardState.CARDSTATE_PRESENT), 0 /* phoneId */, new Object(), false); + makeCardStatus(CardState.CARDSTATE_PRESENT), 0 /* phoneId */, new Object(), false, + IccSlotStatus.MultipleEnabledProfilesMode.NONE); when(UiccController.getInstance().getUiccCardForPhone(0)).thenReturn(card); uiccLauncher.handleMessage(msg); diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java index 79c4af47b8..c5eff90634 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java @@ -18,6 +18,7 @@ package com.android.internal.telephony.uicc.euicc; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -34,6 +35,7 @@ import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.IccSlotPortMapping; +import com.android.internal.telephony.uicc.IccSlotStatus; import com.android.internal.telephony.uicc.euicc.apdu.LogicalChannelMocker; import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback; @@ -94,7 +96,8 @@ public class EuiccCardTest extends TelephonyTest { mEuiccCard = new EuiccCard(mContext, mMockCi, mMockIccCardStatus, - 0 /* phoneId */, new Object(), false) { + 0 /* phoneId */, new Object(), false, + IccSlotStatus.MultipleEnabledProfilesMode.NONE) { @Override protected void loadEidAndNotifyRegistrants() {} @@ -133,7 +136,8 @@ public class EuiccCardTest extends TelephonyTest { public void testPassEidInConstructor() { mMockIccCardStatus.eid = "1A2B3C4D"; mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi, - mMockIccCardStatus, 0 /* phoneId */, new Object(), false); + mMockIccCardStatus, 0 /* phoneId */, new Object(), false, + IccSlotStatus.MultipleEnabledProfilesMode.NONE); final int eventEidReady = 0; Handler handler = new Handler(Looper.myLooper()) { @@ -154,7 +158,8 @@ public class EuiccCardTest extends TelephonyTest { int channel = mockLogicalChannelResponses("BF3E065A041A2B3C4D9000"); mHandler.post(() -> { mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi, - mMockIccCardStatus, 0 /* phoneId */, new Object(), false); + mMockIccCardStatus, 0 /* phoneId */, new Object(), false, + IccSlotStatus.MultipleEnabledProfilesMode.NONE); }); processAllMessages(); @@ -188,7 +193,7 @@ public class EuiccCardTest extends TelephonyTest { private void verifyStoreData(int channel, String command) { verify(mMockCi, times(1)) .iccTransmitApduLogicalChannel(eq(channel), eq(0x80 | channel), eq(0xE2), eq(0x91), - eq(0), eq(command.length() / 2), eq(command), any()); + eq(0), eq(command.length() / 2), eq(command), anyBoolean(), any()); } private int mockLogicalChannelResponses(Object... responses) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccPortTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccPortTest.java index 8caa2488ef..2f8c19e96d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccPortTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccPortTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -49,6 +50,7 @@ import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.IccSlotPortMapping; +import com.android.internal.telephony.uicc.IccSlotStatus; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.asn1.Asn1Node; import com.android.internal.telephony.uicc.asn1.InvalidAsn1DataException; @@ -118,7 +120,8 @@ public class EuiccPortTest extends TelephonyTest { mMockIccCardStatus.mSlotPortMapping = new IccSlotPortMapping(); mEuiccPort = new EuiccPort(mContext, mMockCi, mMockIccCardStatus, - 0 /* phoneId */, new Object(), mEuiccCard, false) { + 0 /* phoneId */, new Object(), mEuiccCard, false, + IccSlotStatus.MultipleEnabledProfilesMode.NONE) { @Override protected byte[] getDeviceId() { return IccUtils.bcdToBytes("987654321012345"); @@ -374,6 +377,23 @@ public class EuiccPortTest extends TelephonyTest { verifyStoreData(channel, "BF3111A00C5A0A896700000000004523018101FF"); } + @Test + public void testSwitchToProfile_MepA1() { + int channel = mockLogicalChannelResponses("BF31038001039000"); + + ResultCaptor resultCaptor = new ResultCaptor<>(); + mMockIccCardStatus.mSlotPortMapping.mPortIndex = 1; + mEuiccPort.updateSupportMepProperties(true, + IccSlotStatus.MultipleEnabledProfilesMode.MEP_A1); + mEuiccPort.update(mContext, mMockCi, mMockIccCardStatus, mEuiccCard); + mEuiccPort.switchToProfile("98760000000000543210", true, resultCaptor, mHandler); + processAllMessages(); + + assertEquals(3, ((EuiccCardErrorException) resultCaptor.exception).getErrorCode()); + // In case of MEP-A1, verify portIndex is shifted or not. + verifyStoreData(channel, "BF3114A00C5A0A896700000000004523018101FF820102"); + } + @Test public void testGetEid() { int channel = mockLogicalChannelResponses("BF3E065A041A2B3C4D9000"); @@ -884,7 +904,7 @@ public class EuiccPortTest extends TelephonyTest { verify(mMockCi, never()) .iccTransmitApduLogicalChannel( eq(channel), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), any(), - any()); + anyBoolean(), any()); } @Test @@ -917,7 +937,7 @@ public class EuiccPortTest extends TelephonyTest { verify(mMockCi, never()) .iccTransmitApduLogicalChannel( eq(channel), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), any(), - any()); + anyBoolean(), any()); } @Test @@ -1175,7 +1195,7 @@ public class EuiccPortTest extends TelephonyTest { private void verifyStoreData(int channel, String command) { verify(mMockCi, times(1)) .iccTransmitApduLogicalChannel(eq(channel), eq(0x80 | channel), eq(0xE2), eq(0x91), - eq(0), eq(command.length() / 2), eq(command), any()); + eq(0), eq(command.length() / 2), eq(command), anyBoolean(), any()); } private int mockLogicalChannelResponses(Object... responses) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java index 2b9e7671ac..e637ec08b6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -149,7 +150,7 @@ public class ApduSenderTest { assertEquals("A1A1A1", IccUtils.bytesToHexString(mResponseCaptor.response)); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(0), eq("a"), any()); + eq(3), eq(0), eq("a"), anyBoolean(), any()); } @Test @@ -169,13 +170,13 @@ public class ApduSenderTest { assertEquals("A4", IccUtils.bytesToHexString(mResponseCaptor.response)); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(0), eq("a"), any()); + eq(3), eq(0), eq("a"), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(1), eq("ab"), any()); + eq(3), eq(1), eq("ab"), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(0), eq(""), any()); + eq(3), eq(0), eq(""), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x91), - eq(0), eq(2), eq("abcd"), any()); + eq(0), eq(2), eq("abcd"), anyBoolean(), any()); } @Test @@ -196,11 +197,11 @@ public class ApduSenderTest { assertEquals("A3", IccUtils.bytesToHexString(mResponseCaptor.response)); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(0), eq("a"), any()); + eq(3), eq(0), eq("a"), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(1), eq("ab"), any()); + eq(3), eq(1), eq("ab"), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(0), eq(""), any()); + eq(3), eq(0), eq(""), anyBoolean(), any()); } @Test @@ -216,11 +217,11 @@ public class ApduSenderTest { assertEquals("A1A1A1B2B2B2B2C3C3", IccUtils.bytesToHexString(mResponseCaptor.response)); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(0), eq("a"), any()); + eq(3), eq(0), eq("a"), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel), eq(0xC0), eq(0), - eq(0), eq(4), eq(""), any()); + eq(0), eq(4), eq(""), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel), eq(0xC0), eq(0), - eq(0), eq(2), eq(""), any()); + eq(0), eq(2), eq(""), anyBoolean(), any()); } @Test @@ -244,15 +245,15 @@ public class ApduSenderTest { assertEquals("C3", IccUtils.bytesToHexString(mResponseCaptor.response)); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(0), eq("a"), any()); + eq(3), eq(0), eq("a"), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(0), eq("b"), any()); + eq(3), eq(0), eq("b"), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x11), - eq(0), eq(0xFF), eq(s1), any()); + eq(0), eq(0xFF), eq(s1), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x11), - eq(1), eq(0xFF), eq(s2), any()); + eq(1), eq(0xFF), eq(s2), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x91), - eq(2), eq(16), eq(s3), any()); + eq(2), eq(16), eq(s3), anyBoolean(), any()); } @Test @@ -272,9 +273,9 @@ public class ApduSenderTest { assertEquals("B2222B", IccUtils.bytesToHexString(mResponseCaptor.response)); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x11), - eq(0), eq(0xFF), eq(s1), any()); + eq(0), eq(0xFF), eq(s1), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x91), - eq(1), eq(0xFF), eq(s2), any()); + eq(1), eq(0xFF), eq(s2), anyBoolean(), any()); } @Test @@ -290,7 +291,7 @@ public class ApduSenderTest { assertEquals("B2222B", IccUtils.bytesToHexString(mResponseCaptor.response)); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x91), - eq(0), eq(0), eq(""), any()); + eq(0), eq(0), eq(""), anyBoolean(), any()); } @Test @@ -313,13 +314,13 @@ public class ApduSenderTest { assertEquals(0x6985, ((ApduException) mResponseCaptor.exception).getApduStatus()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2), - eq(3), eq(0), eq("a"), any()); + eq(3), eq(0), eq("a"), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x11), - eq(0), eq(0xFF), eq(s1), any()); + eq(0), eq(0xFF), eq(s1), anyBoolean(), any()); verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x11), - eq(1), eq(0xFF), eq(s2), any()); + eq(1), eq(0xFF), eq(s2), anyBoolean(), any()); verify(mMockCi, never()).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), - eq(0x91), eq(2), eq(16), eq(s3), any()); + eq(0x91), eq(2), eq(16), eq(s3), anyBoolean(), any()); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/LogicalChannelMocker.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/LogicalChannelMocker.java index e9796a1778..e7bceee2b0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/LogicalChannelMocker.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/LogicalChannelMocker.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.uicc.euicc.apdu; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -70,26 +71,44 @@ public final class LogicalChannelMocker { @Override public Object answer(InvocationOnMock invocation) throws Throwable { Object responseObject = responseObjects[mIndex++]; - boolean isException = responseObject instanceof Throwable; - int sw1 = 0; - int sw2 = 0; - String hex = responseObject.toString(); - if (!isException) { - int l = hex.length(); - sw1 = Integer.parseInt(hex.substring(l - 4, l - 2), 16); - sw2 = Integer.parseInt(hex.substring(l - 2), 16); - hex = hex.substring(0, l - 4); - } - IccIoResult result = isException ? null : new IccIoResult(sw1, sw2, hex); - Throwable exception = isException ? (Throwable) responseObject : null; - - Message msg = response.getValue(); - AsyncResult.forMessage(msg, result, exception); - msg.sendToTarget(); + mockIccTransmitApduLogicalChannelResponse(response, responseObject); return null; } }).when(mockCi).iccTransmitApduLogicalChannel(eq(channel), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyString(), response.capture()); + + doAnswer(new Answer() { + private int mIndex = 0; + + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object responseObject = responseObjects[mIndex++]; + mockIccTransmitApduLogicalChannelResponse(response, responseObject); + return null; + } + }).when(mockCi).iccTransmitApduLogicalChannel(eq(channel), anyInt(), anyInt(), anyInt(), + anyInt(), anyInt(), anyString(), anyBoolean(), response.capture()); + } + + private static void mockIccTransmitApduLogicalChannelResponse(ArgumentCaptor response, + Object responseObject) throws Throwable { + + boolean isException = responseObject instanceof Throwable; + int sw1 = 0; + int sw2 = 0; + String hex = responseObject.toString(); + if (!isException) { + int l = hex.length(); + sw1 = Integer.parseInt(hex.substring(l - 4, l - 2), 16); + sw2 = Integer.parseInt(hex.substring(l - 2), 16); + hex = hex.substring(0, l - 4); + } + IccIoResult result = isException ? null : new IccIoResult(sw1, sw2, hex); + Throwable exception = isException ? (Throwable) responseObject : null; + + Message msg = response.getValue(); + AsyncResult.forMessage(msg, result, exception); + msg.sendToTarget(); } public static void mockCloseLogicalChannel(CommandsInterface mockCi, int channel) { -- GitLab From 7697a032f333bde21c253405c6d9d753e06ba6a1 Mon Sep 17 00:00:00 2001 From: Hwangoo Park Date: Mon, 19 Dec 2022 00:20:27 +0000 Subject: [PATCH 293/656] Fix a test failure reported as flaky When the BroadcastReceiver is used for receiving the sent result, but it can be reported as a flaky test since sometimes broadcasts can take a long time if the system is under load. This change uses the IActivityManager instead of the BroadcastReceiver to check whether the PendingIntent#send(int) is successfully called or not. Bug: 262934689 Test: atest FrameworksTelephonyTests, SmsDispatchersControllerTest Change-Id: I1111e7c0f329080149572fb7484f25ea8b9397ac --- .../SmsDispatchersControllerTest.java | 66 ++++--------------- 1 file changed, 11 insertions(+), 55 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java index a10751a1a7..7912832443 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java @@ -38,10 +38,7 @@ import static org.mockito.Mockito.when; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.PendingIntent; -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.Message; @@ -73,8 +70,6 @@ import org.mockito.Mockito; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -82,7 +77,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { /** * Inherits the SmsDispatchersController to verify the protected methods. */ - private class TestSmsDispatchersController extends SmsDispatchersController { + private static class TestSmsDispatchersController extends SmsDispatchersController { TestSmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, SmsUsageMonitor usageMonitor) { super(phone, storageMonitor, usageMonitor); @@ -113,7 +108,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { /** * Inherits the SMSDispatcher to verify the abstract or protected methods. */ - protected abstract class TestSmsDispatcher extends SMSDispatcher { + protected abstract static class TestSmsDispatcher extends SMSDispatcher { public TestSmsDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) { super(phone, smsDispatchersController); } @@ -139,7 +134,7 @@ public class SmsDispatchersControllerTest extends TelephonyTest { /** * Inherits the SMSDispatcher to verify the protected methods. */ - protected class TestImsSmsDispatcher extends ImsSmsDispatcher { + protected static class TestImsSmsDispatcher extends ImsSmsDispatcher { public TestImsSmsDispatcher(Phone phone, SmsDispatchersController smsDispatchersController, FeatureConnectorFactory factory) { super(phone, smsDispatchersController, factory); @@ -159,36 +154,6 @@ public class SmsDispatchersControllerTest extends TelephonyTest { } } - /** - * Provides a Test class to verify the sent failure case. - */ - private class TestIntentReceiver extends BroadcastReceiver { - private final Context mContext; - private final CountDownLatch mLatch = new CountDownLatch(1); - private Intent mIntent; - - TestIntentReceiver(Context context) { - mContext = context; - mContext.registerReceiver(this, new IntentFilter(ACTION_TEST_SMS_SENT)); - } - - public void dispose() { - mContext.unregisterReceiver(this); - } - - @Override - public void onReceive(Context context, Intent intent) { - assertNull(mIntent); - mIntent = intent; - mLatch.countDown(); - } - - public Intent getIntent(long timeoutMillis) throws Exception { - mLatch.await(timeoutMillis, TimeUnit.MILLISECONDS); - return mIntent; - } - } - private static final String ACTION_TEST_SMS_SENT = "TEST_SMS_SENT"; // Mocked classes @@ -203,7 +168,6 @@ public class SmsDispatchersControllerTest extends TelephonyTest { private TestSmsDispatchersController mSmsDispatchersController; private boolean mInjectionCallbackTriggered = false; private CompletableFuture mDscFuture; - private TestIntentReceiver mIntentReceiver; @Before public void setUp() throws Exception { @@ -227,10 +191,6 @@ public class SmsDispatchersControllerTest extends TelephonyTest { mDscFuture = null; mSmsDispatchersController.dispose(); mSmsDispatchersController = null; - if (mIntentReceiver != null) { - mIntentReceiver.dispose(); - mIntentReceiver = null; - } super.tearDown(); } @@ -502,8 +462,8 @@ public class SmsDispatchersControllerTest extends TelephonyTest { } @Test + @SmallTest public void testNotifyDomainSelectionTerminated() throws Exception { - registerTestIntentReceiver(); setUpDomainSelectionConnection(); setUpSmsDispatchers(); @@ -534,9 +494,13 @@ public class SmsDispatchersControllerTest extends TelephonyTest { assertFalse(holder.isDomainSelectionRequested()); assertEquals(0, holder.getPendingRequests().size()); - Intent intent = mIntentReceiver.getIntent(2000); - assertNotNull(intent); - assertEquals(SmsManager.RESULT_ERROR_GENERIC_FAILURE, mIntentReceiver.getResultCode()); + // We can use the IntentReceiver for receiving the sent result, but it can be reported as + // a flaky test since sometimes broadcasts can take a long time if the system is under load. + // At this point, we couldn't use the PendingIntent as a mock because it's a final class + // so this test checks the method in the IActivityManager when the PendingIntent#send(int) + // is called. + verify(mIActivityManager).sendIntentSender(any(), any(), any(), + eq(SmsManager.RESULT_ERROR_GENERIC_FAILURE), any(), any(), any(), any(), any()); } @Test @@ -589,14 +553,6 @@ public class SmsDispatchersControllerTest extends TelephonyTest { assertTrue(mSmsDispatchersController.setImsManager(imsManager)); } - private void registerTestIntentReceiver() throws Exception { - // unmock ActivityManager to be able to register receiver, create real PendingIntent and - // receive a test intent. - restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton); - restoreInstance(ActivityManager.class, "IActivityManagerSingleton", null); - mIntentReceiver = new TestIntentReceiver(TestApplication.getAppContext()); - } - private void setUpDomainSelectionConnectionAsNotSupported() { mSmsDispatchersController.setDomainSelectionResolverProxy( new SmsDispatchersController.DomainSelectionResolverProxy() { -- GitLab From 84b78004548e5f9a8415430fabf6e633d9161213 Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Tue, 6 Dec 2022 00:49:17 +0000 Subject: [PATCH 294/656] Media quality CB: Telephony FWK implementation ImsPhoneCallTracker: - set Media threhold & listen media quality. ImsPhoneBase, PhoneNotifier: - notify media quality status reported from IMS service. Bug: 242934908 Test: system build, device test b/259482963 Change-Id: Id16471de683f2ba5e971d18125830dfbf6b52536 --- .../telephony/DefaultPhoneNotifier.java | 7 ++ .../internal/telephony/PhoneNotifier.java | 4 + .../telephony/imsphone/ImsPhoneBase.java | 5 ++ .../imsphone/ImsPhoneCallTracker.java | 83 ++++++++++++++++++- 4 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java index cabceb2fc7..8eafeba0d4 100644 --- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -37,6 +37,7 @@ import android.telephony.TelephonyRegistryManager; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.MediaQualityStatus; import com.android.telephony.Rlog; @@ -237,6 +238,12 @@ public class DefaultPhoneNotifier implements PhoneNotifier { callQuality, callNetworkType); } + @Override + public void notifyMediaQualityStatusChanged(Phone sender, MediaQualityStatus status) { + mTelephonyRegistryMgr.notifyMediaQualityStatusChanged( + sender.getPhoneId(), sender.getSubId(), status); + } + @Override public void notifyRegistrationFailed(Phone sender, @NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode) { diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java index 7617bdf225..2a439a304f 100644 --- a/src/java/com/android/internal/telephony/PhoneNotifier.java +++ b/src/java/com/android/internal/telephony/PhoneNotifier.java @@ -34,6 +34,7 @@ import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager.DataEnabledReason; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.MediaQualityStatus; import java.util.List; @@ -117,6 +118,9 @@ public interface PhoneNotifier { /** Notify of a change to the call quality of an active foreground call. */ void notifyCallQualityChanged(Phone sender, CallQuality callQuality, int callNetworkType); + /** Notify of a change to the media quality status of an active foreground call. */ + void notifyMediaQualityStatusChanged(Phone sender, MediaQualityStatus status); + /** Notify registration failed */ void notifyRegistrationFailed(Phone sender, @NonNull CellIdentity cellIdentity, @NonNull String chosenPlmn, int domain, int causeCode, int additionalCauseCode); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index 76e72e1792..1426ac84d3 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -30,6 +30,7 @@ import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.MediaQualityStatus; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; @@ -139,6 +140,10 @@ abstract class ImsPhoneBase extends Phone { mNotifier.notifyCallQualityChanged(this, callQuality, callNetworkType); } + public void onMediaQualityStatusChanged(MediaQualityStatus status) { + mNotifier.notifyMediaQualityStatusChanged(this, status); + } + @Override public ServiceState getServiceState() { // FIXME: we may need to provide this when data connectivity is lost diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index bab3924f66..195492b05d 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -95,6 +95,8 @@ import android.telephony.ims.ImsMmTelManager; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsStreamMediaProfile; import android.telephony.ims.ImsSuppServiceNotification; +import android.telephony.ims.MediaQualityStatus; +import android.telephony.ims.MediaThreshold; import android.telephony.ims.ProvisioningManager; import android.telephony.ims.RtpHeaderExtension; import android.telephony.ims.RtpHeaderExtensionType; @@ -481,6 +483,18 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { }, mExecutor); } + @Override + public void onMediaQualityStatusChanged(MediaQualityStatus status) { + TelephonyUtils.runWithCleanCallingIdentity(()-> { + if (mPhone != null && mPhone.mDefaultPhone != null) { + if (DBG) log("onMediaQualityStatusChanged " + status); + mPhone.onMediaQualityStatusChanged(status); + } else { + loge("onMediaQualityStatusChanged: null phone"); + } + }, mExecutor); + } + /** * Schedule the given Runnable on mExecutor and block this thread until it finishes. * @param r The Runnable to run. @@ -644,6 +658,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private static final int EVENT_REDIAL_WITHOUT_RTT = 32; private static final int EVENT_START_IMS_TRAFFIC_DONE = 33; private static final int EVENT_CONNECTION_SETUP_FAILURE = 34; + private static final int EVENT_NEW_ACTIVE_CALL_STARTED = 35; private static final int TIMEOUT_HANGUP_PENDINGMO = 500; @@ -776,11 +791,15 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private boolean mSupportCepOnPeer = true; private boolean mSupportD2DUsingRtp = false; private boolean mSupportSdpForRtpHeaderExtensions = false; + private int mThresholdRtpPacketLoss; + private int mThresholdRtpJitter; + private long mThresholdRtpInactivityTime; private final List mSrvccTypeSupported = new ArrayList<>(); private final SrvccStartedCallback mSrvccStartedCallback = new SrvccStartedCallback(); // Tracks the state of our background/foreground calls while a call hold/swap operation is // in progress. Values listed above. private HoldSwapState mHoldSwitchingState = HoldSwapState.INACTIVE; + private MediaThreshold mMediaThreshold; private String mLastDialString = null; private ImsDialArgs mLastDialArgs = null; @@ -1419,6 +1438,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mUtInterface = null; } mCurrentlyConnectedSubId = Optional.empty(); + mMediaThreshold = null; resetImsCapabilities(); hangupAllOrphanedConnections(DisconnectCause.LOST_SIGNAL); // For compatibility with apps that still use deprecated intent @@ -1843,6 +1863,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { logi("updateCarrierConfiguration: Updating ImsService configs."); mCarrierConfigLoadedForSubscription = true; updateImsServiceConfig(); + updateMediaThreshold( + mThresholdRtpPacketLoss, mThresholdRtpJitter, mThresholdRtpInactivityTime); } /** @@ -1891,6 +1913,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mSupportSdpForRtpHeaderExtensions = carrierConfig.getBoolean( CarrierConfigManager .KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL); + mThresholdRtpPacketLoss = carrierConfig.getInt( + CarrierConfigManager.ImsVoice.KEY_VOICE_RTP_PACKET_LOSS_RATE_THRESHOLD_INT); + mThresholdRtpInactivityTime = carrierConfig.getLong( + CarrierConfigManager.ImsVoice + .KEY_VOICE_RTP_INACTIVITY_TIME_THRESHOLD_MILLIS_LONG); + mThresholdRtpJitter = carrierConfig.getInt( + CarrierConfigManager.ImsVoice.KEY_VOICE_RTP_JITTER_THRESHOLD_MILLIS_INT); if (mPhone.getContext().getResources().getBoolean( com.android.internal.R.bool.config_allow_ussd_over_ims)) { @@ -1947,6 +1976,33 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } } + private void updateMediaThreshold( + int thresholdPacketLoss, int thresholdJitter, long thresholdInactivityTime) { + if (!MediaThreshold.isValidRtpInactivityTimeMillis(thresholdInactivityTime) + && !MediaThreshold.isValidJitterMillis(thresholdJitter) + && !MediaThreshold.isValidRtpPacketLossRate(thresholdPacketLoss)) { + logi("There is no valid RTP threshold value"); + return; + } + int[] thPacketLosses = {thresholdPacketLoss}; + long[] thInactivityTimesMillis = {thresholdInactivityTime}; + int[] thJitters = {thresholdJitter}; + MediaThreshold threshold = new MediaThreshold.Builder() + .setThresholdsRtpPacketLossRate(thPacketLosses) + .setThresholdsRtpInactivityTimeMillis(thInactivityTimesMillis) + .setThresholdsRtpJitterMillis(thJitters).build(); + if (mMediaThreshold == null || !mMediaThreshold.equals(threshold)) { + logi("setMediaThreshold :" + threshold); + try { + mImsManager.setMediaThreshold(MediaQualityStatus.MEDIA_SESSION_TYPE_AUDIO, + threshold); + mMediaThreshold = threshold; + } catch (ImsException e) { + loge("setMediaThreshold Failed: " + e); + } + } + } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private void handleEcmTimer(int action) { mPhone.handleTimerInEmergencyCallbackMode(action); @@ -2997,8 +3053,15 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // Do not log operations that do not change the state mOperationLocalLog.log("processCallStateChange: state=" + state + " cause=" + cause + " connId=" + System.identityHashCode(conn)); - + boolean noActiveCall = false; + if (mForegroundCall.getState() != ImsPhoneCall.State.ACTIVE + && mBackgroundCall.getState() != ImsPhoneCall.State.ACTIVE) { + noActiveCall = true; + } changed = conn.update(imsCall, state); + if (noActiveCall && changed && state == ImsPhoneCall.State.ACTIVE) { + sendMessage(obtainMessage(EVENT_NEW_ACTIVE_CALL_STARTED)); + } if (state == ImsPhoneCall.State.DISCONNECTED) { changed = conn.onDisconnect(cause) || changed; //detach the disconnected connections @@ -4830,6 +4893,24 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } break; } + + case EVENT_NEW_ACTIVE_CALL_STARTED: { + try { + MediaQualityStatus status = mImsManager + .queryMediaQualityStatus(MediaQualityStatus.MEDIA_SESSION_TYPE_AUDIO); + if (status != null) { + if (mPhone != null && mPhone.mDefaultPhone != null) { + if (DBG) log("notify media quality status: " + status); + mPhone.onMediaQualityStatusChanged(status); + } else { + loge("onMediaQualityStatusChanged: null phone"); + } + } + } catch (ImsException e) { + Rlog.e(LOG_TAG, "Exception in queryMediaQualityStatus: " + e); + } + break; + } } } -- GitLab From dc1f5286d3872b807c95900cc40c3eb61b37230d Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 17 Dec 2022 02:23:31 -0800 Subject: [PATCH 295/656] Moved SIM state broadcast back to UiccController Moved the SIM related stuffs back to UiccController. SubscriptionManagerService will mainly handle subscription related stuffs. The same SIM state broadcast is ported from SubscriptionInfoUpdater. Bug: 239607619 Test: Manual Change-Id: I174353a8a37f6654f924491e414056ba9ea09953 --- .../telephony/CarrierServiceBindHelper.java | 9 +- .../telephony/SubscriptionInfoUpdater.java | 2 +- .../SubscriptionManagerService.java | 144 +++++++- .../telephony/uicc/UiccController.java | 342 +++++++++++++++++- .../internal/telephony/uicc/UiccProfile.java | 4 +- .../internal/telephony/uicc/UiccSlot.java | 10 +- .../internal/telephony/uicc/UiccSlotTest.java | 23 +- 7 files changed, 490 insertions(+), 44 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java index dfa53b3958..035714e5bc 100644 --- a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java +++ b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -200,7 +201,13 @@ public class CarrierServiceBindHelper { } } - void updateForPhoneId(int phoneId, String simState) { + /** + * Update SIM state. + * + * @param phoneId The phone id. + * @param simState The legacy SIM state. + */ + public void updateSimState(int phoneId, @NonNull String simState) { logdWithLocalLog("update binding for phoneId: " + phoneId + " simState: " + simState); if (!SubscriptionManager.isValidPhoneId(phoneId)) { return; diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index 1681d140b7..fa52db5012 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -700,7 +700,7 @@ public class SubscriptionInfoUpdater extends Handler { CarrierConfigManager configManager = (CarrierConfigManager) sContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); configManager.updateConfigForPhoneId(phoneId, simState); - mCarrierServiceBindHelper.updateForPhoneId(phoneId, simState); + mCarrierServiceBindHelper.updateSimState(phoneId, simState); } private void updateSubscriptionCarrierId(int phoneId, String simState) { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 9ea34f60f8..d3793e2caa 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -59,6 +59,7 @@ import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.SimState; import android.telephony.TelephonyRegistryManager; import android.telephony.UiccAccessRule; import android.telephony.euicc.EuiccManager; @@ -427,6 +428,10 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public void onDatabaseLoaded() { log("Subscription database has been loaded."); + for (int phoneId = 0; phoneId < mTelephonyManager.getActiveModemCount() + ; phoneId++) { + markSubscriptionsInactive(phoneId); + } } /** @@ -826,7 +831,7 @@ public class SubscriptionManagerService extends ISub.Stub { /** * Mark all subscriptions on this SIM slot index inactive. * - * @param simSlotIndex The SIM slot index. + * @param simSlotIndex The logical SIM slot index (i.e. phone id). */ public void markSubscriptionsInactive(int simSlotIndex) { mSubscriptionDatabaseManager.getAllSubscriptions().stream() @@ -985,6 +990,15 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Update the subscriptions on the logical SIM slot index (i.e. phone id). + * + * @param slotIndex The logical SIM slot index. + */ + private void updateSubscriptions(int slotIndex) { + + } + /** * Get all subscription info records from SIMs that are inserted now or previously inserted. * @@ -3079,6 +3093,134 @@ public class SubscriptionManagerService extends ISub.Stub { ? subscriptionInfoInternal.toSubscriptionInfo() : null; } + /** + * Called when SIM state changed to absent. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimAbsent(int slotIndex) { + if (mSlotIndexToSubId.containsKey(slotIndex)) { + // Re-enable the SIM when it's removed, so it will be in enabled state when it gets + // re-inserted again. (pre-U behavior) + mSubscriptionDatabaseManager.setUiccApplicationsEnabled( + mSlotIndexToSubId.get(slotIndex), true); + // When sim is absent, set the port index to invalid port index. (pre-U behavior) + mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(slotIndex), + TelephonyManager.INVALID_PORT_INDEX); + } + updateSubscriptions(slotIndex); + } + + /** + * Called when SIM state changed to locked. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimLocked(int slotIndex) { + + } + + /** + * Called when SIM state changed to ready. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimReady(int slotIndex) { + + } + + /** + * Called when SIM state changed to not ready. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimNotReady(int slotIndex) { + + } + + /** + * Called when SIM encounters error. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimError(int slotIndex) { + + } + + /** + * Called when SIM state changed to loaded. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimLoaded(int slotIndex) { + } + + /** + * Called when eSIM becomes inactive. + * + * @param slotIndex The logical SIM slot index. + */ + public void updateSimStateForInactivePort(int slotIndex) { + mHandler.post(() -> { + if (mSlotIndexToSubId.containsKey(slotIndex)) { + // Re-enable the UICC application , so it will be in enabled state when it becomes + // active again. (pre-U behavior) + mSubscriptionDatabaseManager.setUiccApplicationsEnabled( + mSlotIndexToSubId.get(slotIndex), true); + updateSubscriptions(slotIndex); + } + }); + } + + /** + * Update SIM state. This method is supposed to be called by {@link UiccController} only. + * + * @param slotIndex The logical SIM slot index. + * @param simState SIM state. + * @param executor The executor to execute the callback. + * @param updateCompleteCallback The callback to call when subscription manager service + * completes subscription update. SIM state changed event will be broadcasted by + * {@link UiccController} upon receiving callback. + */ + public void updateSimState(int slotIndex, @SimState int simState, + @Nullable @CallbackExecutor Executor executor, + @Nullable Runnable updateCompleteCallback) { + mHandler.post(() -> { + switch (simState) { + case TelephonyManager.SIM_STATE_ABSENT: + onSimAbsent(slotIndex); + break; + case TelephonyManager.SIM_STATE_PIN_REQUIRED: + case TelephonyManager.SIM_STATE_PUK_REQUIRED: + case TelephonyManager.SIM_STATE_NETWORK_LOCKED: + case TelephonyManager.SIM_STATE_PERM_DISABLED: + onSimLocked(slotIndex); + break; + case TelephonyManager.SIM_STATE_READY: + onSimReady(slotIndex); + break; + case TelephonyManager.SIM_STATE_NOT_READY: + onSimNotReady(slotIndex); + break; + case TelephonyManager.SIM_STATE_CARD_IO_ERROR: + onSimError(slotIndex); + break; + case TelephonyManager.SIM_STATE_CARD_RESTRICTED: + // No specific things needed to be done. Just return and broadcast the SIM + // states. + break; + case TelephonyManager.SIM_STATE_LOADED: + onSimLoaded(slotIndex); + break; + default: + break; + } + if (executor != null && updateCompleteCallback != null) { + executor.execute(updateCompleteCallback); + } + }); + } + /** * Log debug messages. * diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index ea99d9a3f6..1ad7ee35f6 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -21,6 +21,8 @@ import static android.telephony.TelephonyManager.UNSUPPORTED_CARD_ID; import static java.util.Arrays.copyOf; +import android.Manifest; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.BroadcastOptions; import android.compat.annotation.UnsupportedAppUsage; @@ -38,8 +40,10 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.SimState; import android.telephony.UiccCardInfo; import android.telephony.UiccPortInfo; import android.telephony.UiccSlotMapping; @@ -49,14 +53,20 @@ import android.util.LocalLog; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.CarrierServiceBindHelper; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccCardConstants; +import com.android.internal.telephony.IntentBroadcaster; import com.android.internal.telephony.PhoneConfigurationManager; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.SubscriptionInfoUpdater; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.euicc.EuiccCard; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -140,6 +150,9 @@ public class UiccController extends Handler { private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 10; // NOTE: any new EVENT_* values must be added to eventToString. + @NonNull + private final TelephonyManager mTelephonyManager; + // this needs to be here, because on bootup we dont know which index maps to which UiccSlot @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private CommandsInterface[] mCis; @@ -151,11 +164,25 @@ public class UiccController extends Handler { // This maps the externally exposed card ID (int) to the internal card ID string (ICCID/EID). // The array index is the card ID (int). // This mapping exists to expose card-based functionality without exposing the EID, which is - // considered sensetive information. + // considered sensitive information. // mCardStrings is populated using values from the IccSlotStatus and IccCardStatus. For // HAL < 1.2, these do not contain the EID or the ICCID, so mCardStrings will be empty private ArrayList mCardStrings; + /** + * SIM card state. + */ + @NonNull + @SimState + private final int[] mSimCardState; + + /** + * SIM application state. + */ + @NonNull + @SimState + private final int[] mSimApplicationState; + // This is the card ID of the default eUICC. It starts as UNINITIALIZED_CARD_ID. // When we load the EID (either with slot status or from the EuiccCard), we set it to the eUICC // with the lowest slot index. @@ -205,6 +232,9 @@ public class UiccController extends Handler { protected RegistrantList mIccChangedRegistrants = new RegistrantList(); + @NonNull + private final CarrierServiceBindHelper mCarrierServiceBindHelper; + private UiccStateChangedLauncher mLauncher; private RadioConfig mRadioConfig; @@ -243,8 +273,13 @@ public class UiccController extends Handler { numPhysicalSlots = mCis.length; } + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + mUiccSlots = new UiccSlot[numPhysicalSlots]; mPhoneIdToSlotId = new int[mCis.length]; + int supportedModemCount = mTelephonyManager.getSupportedModemCount(); + mSimCardState = new int[supportedModemCount]; + mSimApplicationState = new int[supportedModemCount]; Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID); if (VDBG) logPhoneIdToSlotIdMapping(); mRadioConfig = RadioConfig.getInstance(); @@ -260,6 +295,8 @@ public class UiccController extends Handler { mCardStrings = loadCardStrings(); mDefaultEuiccCardId = UNINITIALIZED_CARD_ID; + mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); + mEuiccSlots = mContext.getResources() .getIntArray(com.android.internal.R.array.non_removable_euicc_slots); mHasBuiltInEuicc = hasBuiltInEuicc(); @@ -707,35 +744,300 @@ public class UiccController extends Handler { } } - static void updateInternalIccStateForInactivePort( - Context context, int prevActivePhoneId, String iccId) { - if (SubscriptionManager.isValidPhoneId(prevActivePhoneId)) { + /** + * Update SIM state for the inactive eSIM port. + * + * @param phoneId Previously active phone id. + * @param iccId ICCID of the SIM. + */ + public void updateSimStateForInactivePort(int phoneId, String iccId) { + if (SubscriptionManager.isValidPhoneId(phoneId)) { // Mark SIM state as ABSENT on previously phoneId. - TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - telephonyManager.setSimStateForPhone(prevActivePhoneId, + mTelephonyManager.setSimStateForPhone(phoneId, IccCardConstants.State.ABSENT.toString()); } - SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); - if (subInfoUpdator != null) { - subInfoUpdator.updateInternalIccStateForInactivePort(prevActivePhoneId, iccId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + SubscriptionManagerService.getInstance().updateSimStateForInactivePort(phoneId); } else { - Rlog.e(LOG_TAG, "subInfoUpdate is null."); + SubscriptionInfoUpdater subInfoUpdater = PhoneFactory.getSubscriptionInfoUpdater(); + if (subInfoUpdater != null) { + subInfoUpdater.updateInternalIccStateForInactivePort(phoneId, iccId); + } else { + Rlog.e(LOG_TAG, "subInfoUpdate is null."); + } } } - static void updateInternalIccState(Context context, IccCardConstants.State state, String reason, - int phoneId) { - TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - telephonyManager.setSimStateForPhone(phoneId, state.toString()); + /** + * Broadcast the legacy SIM state changed event. + * + * @param phoneId The phone id. + * @param state The legacy SIM state. + * @param reason The reason of SIM state change. + */ + private void broadcastSimStateChanged(int phoneId, @NonNull String state, + @Nullable String reason) { + // Note: This intent is way deprecated and is only being kept around because there's no + // graceful way to deprecate a sticky broadcast that has a lot of listeners. + // DO NOT add any new extras to this broadcast -- it is not protected by any permissions. + Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); + intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state); + intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); + SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); + Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " + + reason + " for phone: " + phoneId); + IntentBroadcaster.getInstance().broadcastStickyIntent(mContext, intent, phoneId); + } - SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); - if (subInfoUpdator != null) { - subInfoUpdator.updateInternalIccState(getIccStateIntentString(state), reason, phoneId); + /** + * Broadcast SIM card state changed event. + * + * @param phoneId The phone id. + * @param state The SIM card state. + */ + private void broadcastSimCardStateChanged(int phoneId, @SimState int state) { + if (state != mSimCardState[phoneId]) { + mSimCardState[phoneId] = state; + Intent intent = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); + SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); + // TODO(b/130664115) we manually populate this intent with the slotId. In the future we + // should do a review of whether to make this public + UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); + int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); + intent.putExtra(PhoneConstants.SLOT_KEY, slotId); + if (slot != null) { + intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); + } + Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " + + TelephonyManager.simStateToString(state) + " for phone: " + phoneId + + " slot: " + slotId + " port: " + slot.getPortIndexFromPhoneId(phoneId)); + mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + TelephonyMetrics.getInstance().updateSimState(phoneId, state); + } + } + + /** + * Broadcast SIM application state changed event. + * + * @param phoneId The phone id. + * @param state The SIM application state. + */ + private void broadcastSimApplicationStateChanged(int phoneId, @SimState int state) { + // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY, + // because that's the initial state and a broadcast should be sent only on a transition + // after SIM is PRESENT. The only exception is eSIM boot profile, where NOT_READY is the + // terminal state. + boolean isUnknownToNotReady = + (mSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN + && state == TelephonyManager.SIM_STATE_NOT_READY); + IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); + boolean emptyProfile = iccCard != null && iccCard.isEmptyProfile(); + if (state != mSimApplicationState[phoneId] && (!isUnknownToNotReady || emptyProfile)) { + mSimApplicationState[phoneId] = state; + Intent intent = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); + SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); + // TODO(b/130664115) we populate this intent with the actual slotId. In the future we + // should do a review of whether to make this public + UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); + int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); + intent.putExtra(PhoneConstants.SLOT_KEY, slotId); + if (slot != null) { + intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); + } + Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " + + TelephonyManager.simStateToString(state) + + " for phone: " + phoneId + " slot: " + slotId + "port: " + + slot.getPortIndexFromPhoneId(phoneId)); + mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + TelephonyMetrics.getInstance().updateSimState(phoneId, state); + } + } + + /** + * Get SIM state from SIM lock reason. + * + * @param lockedReason The SIM lock reason. + * + * @return The SIM state. + */ + @SimState + private static int getSimStateFromLockedReason(String lockedReason) { + switch (lockedReason) { + case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN: + return TelephonyManager.SIM_STATE_PIN_REQUIRED; + case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK: + return TelephonyManager.SIM_STATE_PUK_REQUIRED; + case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK: + return TelephonyManager.SIM_STATE_NETWORK_LOCKED; + case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED: + return TelephonyManager.SIM_STATE_PERM_DISABLED; + default: + Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason); + return TelephonyManager.SIM_STATE_UNKNOWN; + } + } + + /** + * Broadcast SIM state events. + * + * @param phoneId The phone id. + * @param simState The SIM state. + * @param reason SIM state changed reason. + */ + private void broadcastSimStateEvents(int phoneId, IccCardConstants.State simState, + @Nullable String reason) { + String legacyStringSimState = getIccStateIntentString(simState); + int cardState = TelephonyManager.SIM_STATE_UNKNOWN; + int applicationState = TelephonyManager.SIM_STATE_UNKNOWN; + + switch (simState) { + case ABSENT: + cardState = TelephonyManager.SIM_STATE_ABSENT; + break; + case PIN_REQUIRED: + case PUK_REQUIRED: + case NETWORK_LOCKED: + case PERM_DISABLED: + cardState = TelephonyManager.SIM_STATE_PRESENT; + applicationState = getSimStateFromLockedReason(reason); + break; + case READY: + case NOT_READY: + // Both READY and NOT_READY have the same card state and application state. + cardState = TelephonyManager.SIM_STATE_PRESENT; + applicationState = TelephonyManager.SIM_STATE_NOT_READY; + break; + case CARD_IO_ERROR: + cardState = TelephonyManager.SIM_STATE_CARD_IO_ERROR; + applicationState = TelephonyManager.SIM_STATE_NOT_READY; + break; + case CARD_RESTRICTED: + cardState = TelephonyManager.SIM_STATE_CARD_RESTRICTED; + applicationState = TelephonyManager.SIM_STATE_NOT_READY; + break; + case LOADED: + cardState = TelephonyManager.SIM_STATE_PRESENT; + applicationState = TelephonyManager.SIM_STATE_LOADED; + break; + case UNKNOWN: + default: + break; + } + + broadcastSimStateChanged(phoneId, legacyStringSimState, reason); + broadcastSimCardStateChanged(phoneId, cardState); + broadcastSimApplicationStateChanged(phoneId, applicationState); + } + + /** + * Update carrier service. + * + * @param phoneId The phone id. + * @param simState The SIM state. + */ + private void updateCarrierServices(int phoneId, @NonNull String simState) { + CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class); + if (configManager != null) { + configManager.updateConfigForPhoneId(phoneId, simState); + } + mCarrierServiceBindHelper.updateSimState(phoneId, simState); + } + + /** + * Check if the SIM application is enabled on the card or not. + * + * @param phoneId The phone id. + * @return {@code true} if the application is enabled. + */ + private boolean areUiccAppsEnabledOnCard(int phoneId) { + // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from + // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another + // handleSimNotReady so this will be evaluated again. + UiccSlot slot = getUiccSlotForPhone(phoneId); + if (slot == null) return false; + UiccPort port = getUiccPort(phoneId); + String iccId = (port == null) ? null : port.getIccId(); + if (iccId == null) { + return false; + } + SubscriptionInfo info = SubscriptionManagerService.getInstance() + .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) + .stream().filter(subInfo -> subInfo.getIccId().equals( + IccUtils.stripTrailingFs(iccId))) + .findFirst().orElse(null); + return info != null && info.areUiccApplicationsEnabled(); + } + + /** + * Update the SIM state. + * + * @param phoneId Phone id. + * @param state SIM state (legacy). + * @param reason The reason for SIM state update. + */ + public void updateSimState(int phoneId, @NonNull IccCardConstants.State state, + @Nullable String reason) { + log("updateSimState: phoneId=" + phoneId + ", state=" + state + ", reason=" + reason); + if (!SubscriptionManager.isValidPhoneId(phoneId)) { + Rlog.e(LOG_TAG, "updateInternalIccState: Invalid phone id " + phoneId); + return; + } + + mTelephonyManager.setSimStateForPhone(phoneId, state.toString()); + + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + String legacySimState = getIccStateIntentString(state); + int simState = state.ordinal(); + SubscriptionManagerService.getInstance().updateSimState(phoneId, simState, this::post, + () -> { + // The following are executed after subscription update completed in + // subscription manager service. + + broadcastSimStateEvents(phoneId, state, reason); + + UiccProfile uiccProfile = getUiccProfileForPhone(phoneId); + + if (simState == TelephonyManager.SIM_STATE_READY) { + // SIM_STATE_READY is not a final state. + return; + } + + if (simState == TelephonyManager.SIM_STATE_NOT_READY + && (uiccProfile != null && !uiccProfile.isEmptyProfile()) + && areUiccAppsEnabledOnCard(phoneId)) { + // STATE_NOT_READY is not a final state for when both + // 1) It's not an empty profile, and + // 2) Its uicc applications are set to enabled. + // + // At this phase, we consider STATE_NOT_READY not a final state, so + // return for now. + log("updateSimState: SIM_STATE_NOT_READY is not a final state."); + return; + } + + // At this point, the SIM state must be a final state (meaning we won't + // get more SIM state updates). So resolve the carrier id and update the + // carrier services. + log("updateSimState: resolve carrier id and update carrier services."); + PhoneFactory.getPhone(phoneId).resolveSubscriptionCarrierId(legacySimState); + updateCarrierServices(phoneId, legacySimState); + } + ); } else { - Rlog.e(LOG_TAG, "subInfoUpdate is null."); + SubscriptionInfoUpdater subInfoUpdater = PhoneFactory.getSubscriptionInfoUpdater(); + if (subInfoUpdater != null) { + subInfoUpdater.updateInternalIccState(getIccStateIntentString(state), reason, + phoneId); + } else { + Rlog.e(LOG_TAG, "subInfoUpdate is null."); + } } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index d882e49d01..d9ff3f15d6 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -802,8 +802,8 @@ public class UiccProfile extends IccCard { } log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState); - UiccController.updateInternalIccState(mContext, mExternalState, - getIccStateReason(mExternalState), mPhoneId); + UiccController.getInstance().updateSimState(mPhoneId, mExternalState, + getIccStateReason(mExternalState)); } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index ec4919609c..069a29d251 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -195,7 +195,7 @@ public class UiccSlot extends Handler { if (!iss.mSimPortInfos[i].mPortActive) { // TODO: (b/79432584) evaluate whether should broadcast card state change // even if it's inactive. - UiccController.updateInternalIccStateForInactivePort(mContext, + UiccController.getInstance().updateSimStateForInactivePort( mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID), iss.mSimPortInfos[i].mIccId); mLastRadioState.put(i, TelephonyManager.RADIO_POWER_UNAVAILABLE); @@ -330,8 +330,8 @@ public class UiccSlot extends Handler { if (DBG) log("update: notify card removed"); sendMessage(obtainMessage(EVENT_CARD_REMOVED, null)); } - UiccController.updateInternalIccState(mContext, IccCardConstants.State.ABSENT, - null, phoneId); + UiccController.getInstance().updateSimState(phoneId, IccCardConstants.State.ABSENT, + null); // no card present in the slot now; dispose card and make mUiccCard null nullifyUiccCard(false /* sim state is not unknown */); mLastRadioState.put(portIndex, TelephonyManager.RADIO_POWER_UNAVAILABLE); @@ -592,8 +592,8 @@ public class UiccSlot extends Handler { nullifyUiccCard(true /* sim state is unknown */); if (phoneId != INVALID_PHONE_ID) { - UiccController.updateInternalIccState( - mContext, IccCardConstants.State.UNKNOWN, null, phoneId); + UiccController.getInstance().updateSimState(phoneId, + IccCardConstants.State.UNKNOWN, null); mLastRadioState.put(getPortIndexFromPhoneId(phoneId), TelephonyManager.RADIO_POWER_UNAVAILABLE); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java index 6aab7ad9d0..87b29840f0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java @@ -158,8 +158,7 @@ public class UiccSlotTest extends TelephonyTest { assertTrue(mUiccSlot.isActive()); assertNull(mUiccSlot.getUiccCard()); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); } @Test @@ -380,8 +379,7 @@ public class UiccSlotTest extends TelephonyTest { // Make sure when received CARDSTATE_ABSENT state in the first time, mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); } @@ -414,7 +412,7 @@ public class UiccSlotTest extends TelephonyTest { assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); // assert that we tried to update subscriptions - verify(mSubInfoRecordUpdater).updateInternalIccStateForInactivePort( + verify(mUiccController).updateSimStateForInactivePort( activeIss.mSimPortInfos[0].mLogicalSlotIndex, inactiveIss.mSimPortInfos[0].mIccId); } @@ -435,11 +433,10 @@ public class UiccSlotTest extends TelephonyTest { assertNotNull(mUiccSlot.getUiccCard()); // Simulate when SIM is removed, UiccCard and UiccProfile should be disposed and ABSENT - // state is sent to SubscriptionInfoUpdater. + // state is sent to UiccController. mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); verify(mUiccProfile).dispose(); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); @@ -462,9 +459,8 @@ public class UiccSlotTest extends TelephonyTest { // radio state unavailable mUiccSlot.onRadioStateUnavailable(phoneId); - // Verify that UNKNOWN state is sent to SubscriptionInfoUpdater in this case. - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null, phoneId); + // Verify that UNKNOWN state is sent to UiccController in this case. + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.UNKNOWN, null); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); @@ -472,9 +468,8 @@ public class UiccSlotTest extends TelephonyTest { mIccCardStatus.mCardState = CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - // Verify that ABSENT state is sent to SubscriptionInfoUpdater in this case. - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + // Verify that ABSENT state is sent to UiccController in this case. + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); } -- GitLab From fa7d389cc561cac3a191ae827274563fb3fea683 Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 5 Dec 2022 19:32:23 -0600 Subject: [PATCH 296/656] Update MultiSimSettingController with carrier config change listener Replace the carrier config change broadcast receiver with listener which haas better performance. Bug: 244087782 Test: atest MultiSimSettingControllerTest Change-Id: I677fcf604f05f4870b5253dc38b4ff2dc27800ae --- .../telephony/MultiSimSettingController.java | 37 ++----- .../MultiSimSettingControllerTest.java | 98 +++++++++++-------- 2 files changed, 61 insertions(+), 74 deletions(-) diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index 45ea8bc4c3..f188ceb1e1 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -33,10 +33,8 @@ import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; @@ -85,7 +83,6 @@ public class MultiSimSettingController extends Handler { private static final int EVENT_SUBSCRIPTION_INFO_CHANGED = 4; private static final int EVENT_SUBSCRIPTION_GROUP_CHANGED = 5; private static final int EVENT_DEFAULT_DATA_SUBSCRIPTION_CHANGED = 6; - private static final int EVENT_CARRIER_CONFIG_CHANGED = 7; private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 8; @VisibleForTesting public static final int EVENT_RADIO_STATE_CHANGED = 9; @@ -162,19 +159,6 @@ public class MultiSimSettingController extends Handler { private static final String SETTING_USER_PREF_DATA_SUB = "user_preferred_data_sub"; - private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { - int phoneId = intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_SIM_SLOT_INDEX); - int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - notifyCarrierConfigChanged(phoneId, subId); - } - } - }; - private static class DataSettingsControllerCallback extends DataSettingsManagerCallback { private final Phone mPhone; @@ -250,8 +234,12 @@ public class MultiSimSettingController extends Handler { mIsAskEverytimeSupportedForSms = mContext.getResources() .getBoolean(com.android.internal.R.bool.config_sms_ask_every_time_support); - context.registerReceiver(mIntentReceiver, new IntentFilter( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + + CarrierConfigManager ccm = mContext.getSystemService(CarrierConfigManager.class); + // Listener callback is executed on handler thread to directly handle config change + ccm.registerCarrierConfigChangeListener(this::post, + (slotIndex, subId, carrierId, specificCarrierId) -> + onCarrierConfigChanged(slotIndex, subId)); } /** @@ -330,11 +318,6 @@ public class MultiSimSettingController extends Handler { case EVENT_DEFAULT_DATA_SUBSCRIPTION_CHANGED: onDefaultDataSettingChanged(); break; - case EVENT_CARRIER_CONFIG_CHANGED: - int phoneId = msg.arg1; - int subId = msg.arg2; - onCarrierConfigChanged(phoneId, subId); - break; case EVENT_MULTI_SIM_CONFIG_CHANGED: int activeModems = (int) ((AsyncResult) msg.obj).result; onMultiSimConfigChanged(activeModems); @@ -444,14 +427,6 @@ public class MultiSimSettingController extends Handler { reEvaluateAll(); } - /** - * Called when carrier config changes on any phone. - */ - @VisibleForTesting - public void notifyCarrierConfigChanged(int phoneId, int subId) { - obtainMessage(EVENT_CARRIER_CONFIG_CHANGED, phoneId, subId).sendToTarget(); - } - private void onCarrierConfigChanged(int phoneId, int subId) { log("onCarrierConfigChanged phoneId " + phoneId + " subId " + subId); if (!SubscriptionManager.isValidPhoneId(phoneId)) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index 93d584bb62..f5d617ee2a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -25,6 +25,7 @@ import static android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -80,6 +81,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { private MultiSimSettingController mMultiSimSettingControllerUT; private Phone[] mPhones; private ParcelUuid mGroupUuid1 = new ParcelUuid(UUID.randomUUID()); + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; // Mocked classes private SubscriptionController mSubControllerMock; @@ -122,6 +124,11 @@ public class MultiSimSettingControllerTest extends TelephonyTest { .setGroupUuid(mGroupUuid1.toString()) .build(); + private void sendCarrierConfigChanged(int phoneId, int subId) { + mCarrierConfigChangeListener.onCarrierConfigChanged(phoneId, subId, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); + } + @Before public void setUp() throws Exception { @@ -187,8 +194,15 @@ public class MultiSimSettingControllerTest extends TelephonyTest { replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); replaceInstance(SubscriptionController.class, "sInstance", null, mSubControllerMock); + // Capture listener to emulate the carrier config change notification used later + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); mMultiSimSettingControllerUT = new MultiSimSettingController(mContext, mSubControllerMock); processAllMessages(); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); + assertNotNull(mCarrierConfigChangeListener); } @After @@ -229,7 +243,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { verify(mSubControllerMock, never()).setDefaultSmsSubId(anyInt()); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(0, 1); processAllMessages(); // Sub 1 should be default sub silently. @@ -242,8 +256,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Test public void testSubInfoChangeAfterRadioUnavailable() throws Exception { mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 2); processAllMessages(); // Ensure all subscription loaded only updates state once @@ -319,7 +333,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new int[]{1}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(0, 1); processAllMessages(); verifyDismissIntentSent(); clearInvocations(mContext); @@ -343,7 +357,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new int[]{2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 2); + sendCarrierConfigChanged(0, 2); processAllMessages(); // Sub 1 should be default sub silently. @@ -369,7 +383,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new int[]{1}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(0, 1); processAllMessages(); // Sub 1 should be default sub silently. @@ -393,7 +407,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new int[]{1, 2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(1, 2); processAllMessages(); // Intent should be broadcast to ask default data selection. @@ -421,7 +435,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new int[]{1, 3}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 3); + sendCarrierConfigChanged(1, 3); processAllMessages(); // Intent should be broadcast to ask default data selection. @@ -438,8 +452,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(true).when(mPhoneMock2).isUserDataEnabled(); // After initialization, sub 2 should have mobile data off. mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 2); processAllMessages(); verify(mDataSettingsManagerMock2).setDataEnabled( TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); @@ -471,9 +485,10 @@ public class MultiSimSettingControllerTest extends TelephonyTest { nullable(String.class)); doReturn(new int[]{2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged( - 1, SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); + sendCarrierConfigChanged(1, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + processAllMessages(); + verify(mSubControllerMock).setDefaultDataSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); verify(mSubControllerMock).setDefaultSmsSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); verify(mSubControllerMock, never()).setDefaultVoiceSubId(anyInt()); @@ -497,8 +512,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(true).when(mPhoneMock2).isUserDataEnabled(); // After initialization, sub 2 should have mobile data off. mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 2); processAllMessages(); verify(mDataSettingsManagerMock1).setDataEnabled( TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); @@ -539,8 +554,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { Settings.Global.DEVICE_PROVISIONED, 0); // After initialization, sub 2 should have mobile data off. mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 2); processAllMessages(); verify(mDataSettingsManagerMock1).setDataEnabled( TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); @@ -564,8 +579,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 2, true); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.DATA_ROAMING, 2, false); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 2); processAllMessages(); // Create subscription grouping. @@ -623,7 +638,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(new int[]{1, 3}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 3); + sendCarrierConfigChanged(1, 3); processAllMessages(); verify(mSubControllerMock).setDefaultDataSubId(3); @@ -647,8 +662,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Notify subscriptions ready. Sub 2 should become the default. But shouldn't turn off // data of oppt sub 1. mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 2); processAllMessages(); verify(mSubControllerMock).setDefaultDataSubId(2); verify(mDataSettingsManagerMock1, never()).setDataEnabled( @@ -698,8 +713,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Notify subscriptions ready. Sub 2 should become the default, as sub 1 is opportunistic. mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 2); processAllMessages(); verify(mSubControllerMock).setDefaultDataSubId(2); @@ -739,8 +754,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 2); processAllMessages(); // Defaults not touched, sub 1 is already default. @@ -759,8 +774,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { nullable(String.class)); doReturn(new int[]{2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged( - 0, SubscriptionManager.INVALID_SUBSCRIPTION_ID); + sendCarrierConfigChanged(0, SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); // Sub 2 should be made the default sub silently. @@ -786,8 +800,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 1, true); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.DATA_ROAMING, 1, false); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 2); processAllMessages(); // Create subscription grouping. @@ -822,11 +836,11 @@ public class MultiSimSettingControllerTest extends TelephonyTest { processAllMessages(); verify(mDataSettingsManagerMock2, never()).setDataEnabled( TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(0, 1); processAllMessages(); verify(mDataSettingsManagerMock2, never()).setDataEnabled( TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(1, 2); processAllMessages(); verify(mDataSettingsManagerMock2).setDataEnabled( TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); @@ -854,7 +868,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { processAllMessages(); verify(mContext, never()).sendBroadcast(any()); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 3); + sendCarrierConfigChanged(1, 3); processAllMessages(); // Intent should be broadcast to ask default data selection. Intent intent = captureBroadcastIntent(); @@ -896,8 +910,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Sub 2 should have mobile data off, but it shouldn't happen until carrier configs are // loaded on both subscriptions. mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 3); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 3); processAllMessages(); // Mark sub3 as oppt and notify grouping @@ -919,10 +933,9 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(true).when(mPhoneMock2).isUserDataEnabled(); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); processAllMessages(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(0, 1); // Notify carrier config change on phone1 without specifying subId. - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); + sendCarrierConfigChanged(1, SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); // Nothing should happen as carrier config is not ready for sub 2. verify(mDataSettingsManagerMock2, never()).setDataEnabled( @@ -935,8 +948,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { CarrierConfigManager cm = (CarrierConfigManager) mContext.getSystemService( mContext.CARRIER_CONFIG_SERVICE); doReturn(new PersistableBundle()).when(cm).getConfigForSubId(2); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); + sendCarrierConfigChanged(1, SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); // This time user data should be disabled on phone1. verify(mDataSettingsManagerMock2).setDataEnabled( @@ -986,8 +998,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); doReturn(1).when(mMockedIsub).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0,1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(2, 3); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(2, 2); processAllMessages(); verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); verify(mSubControllerMock, never()).getActiveSubInfoCountMax(); @@ -1003,8 +1015,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(true).when(resources).getBoolean( com.android.internal.R.bool.config_voice_data_sms_auto_fallback); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0,1); - mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2); + sendCarrierConfigChanged(0, 1); + sendCarrierConfigChanged(1, 2); processAllMessages(); verify(mSubControllerMock).getActiveSubInfoCountMax(); verify(mSubControllerMock).setDefaultDataSubId(anyInt()); -- GitLab From 9cbb6ea6779e5efbb24bfd0376b9f49269ffc183 Mon Sep 17 00:00:00 2001 From: Avinash Malipatil Date: Tue, 20 Dec 2022 03:54:27 +0000 Subject: [PATCH 297/656] Add packagename to NormalCallDomainSelectionConnectionTest class and remove warnings. Bug: 262928599 Change-Id: I49676503d0a7bae58bf812ecdb5bc2672267ae54 Test: Run ErrorProne and check the warnings. --- ...rmalCallDomainSelectionConnectionTest.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java index 8b7e872780..1db2c99918 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java @@ -14,6 +14,8 @@ * limitations under the License. */ +package com.android.internal.telephony.domainselection; + import static android.telephony.DisconnectCause.ERROR_UNSPECIFIED; import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING; import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS; @@ -121,8 +123,7 @@ public class NormalCallDomainSelectionConnectionTest extends TelephonyTest { verify(mMockDomainSelectionController).selectDomain(any(), any()); - WwanSelectorCallback wwanCallback = null; - wwanCallback = mTransportCallback.onWwanSelected(); + WwanSelectorCallback wwanCallback = mTransportCallback.onWwanSelected(); assertFalse(future.isDone()); wwanCallback.onDomainSelected(DOMAIN_CS); @@ -147,8 +148,7 @@ public class NormalCallDomainSelectionConnectionTest extends TelephonyTest { verify(mMockDomainSelectionController).selectDomain(any(), any()); - WwanSelectorCallback wwanCallback = null; - wwanCallback = mTransportCallback.onWwanSelected(); + WwanSelectorCallback wwanCallback = mTransportCallback.onWwanSelected(); assertFalse(future.isDone()); wwanCallback.onDomainSelected(DOMAIN_PS); @@ -169,6 +169,7 @@ public class NormalCallDomainSelectionConnectionTest extends TelephonyTest { mTransportCallback.onSelectionTerminated(ERROR_UNSPECIFIED); verify(mMockConnectionCallback).onSelectionTerminated(eq(ERROR_UNSPECIFIED)); + assertNotNull(future); } @Test @@ -178,14 +179,14 @@ public class NormalCallDomainSelectionConnectionTest extends TelephonyTest { NormalCallDomainSelectionConnection.getSelectionAttributes(1, 2, TELECOM_CALL_ID1, "123", false, 10, imsReasonInfo); - assertEquals(attributes.getSlotId(), 1); - assertEquals(attributes.getSubId(), 2); - assertEquals(attributes.getCallId(), TELECOM_CALL_ID1); - assertEquals(attributes.getNumber(), "123"); - assertEquals(attributes.isVideoCall(), false); - assertEquals(attributes.isEmergency(), false); - assertEquals(attributes.getSelectorType(), SELECTOR_TYPE_CALLING); - assertEquals(attributes.getCsDisconnectCause(), 10); - assertEquals(attributes.getPsDisconnectCause(), imsReasonInfo); + assertEquals(1, attributes.getSlotId()); + assertEquals(2, attributes.getSubId()); + assertEquals(TELECOM_CALL_ID1, attributes.getCallId()); + assertEquals("123", attributes.getNumber()); + assertEquals(false, attributes.isVideoCall()); + assertEquals(false, attributes.isEmergency()); + assertEquals(SELECTOR_TYPE_CALLING, attributes.getSelectorType()); + assertEquals(10, attributes.getCsDisconnectCause()); + assertEquals(imsReasonInfo, attributes.getPsDisconnectCause()); } } -- GitLab From b5929bd429d700c1542fedca765c72c1fb193326 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Thu, 8 Dec 2022 10:17:48 +0000 Subject: [PATCH 298/656] Implementation for SMS retry based on config - Reads the Maximum retry count and retry timer from Carrier config - Applies the retry count and timer values to SMS retry on Error Bug: b/230707485 Test: manual(received temp error for and attempt retry) Change-Id: Ie950df4e7cef10f7ee13c93cda1fc6cc8c4ae5a9 --- .../internal/telephony/ImsSmsDispatcher.java | 51 ++++++++++++++++++- .../internal/telephony/SMSDispatcher.java | 26 ++++++++-- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java index 041102f79e..b84a39e18e 100644 --- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java +++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java @@ -171,10 +171,11 @@ public class ImsSmsDispatcher extends SMSDispatcher { mTrackers.remove(token); break; case ImsSmsImplBase.SEND_STATUS_ERROR_RETRY: - if (tracker.mRetryCount < MAX_SEND_RETRIES) { + if (tracker.mRetryCount < getMaxSmsRetryCount()) { tracker.mRetryCount += 1; sendMessageDelayed( - obtainMessage(EVENT_SEND_RETRY, tracker), SEND_RETRY_DELAY); + obtainMessage(EVENT_SEND_RETRY, tracker), + getSmsRetryDelayValue()); } else { tracker.onFailed(mContext, reason, networkReasonCode); mTrackers.remove(token); @@ -405,6 +406,52 @@ public class ImsSmsDispatcher extends SMSDispatcher { } } + @Override + protected int getMaxSmsRetryCount() { + int retryCount = MAX_SEND_RETRIES; + CarrierConfigManager mConfigManager; + + mConfigManager = (CarrierConfigManager) mContext.getSystemService( + Context.CARRIER_CONFIG_SERVICE); + + if (mConfigManager != null) { + PersistableBundle carrierConfig = mConfigManager.getConfigForSubId( + getSubId()); + + if (carrierConfig != null) { + retryCount = carrierConfig.getInt( + CarrierConfigManager.ImsSms.KEY_SMS_MAX_RETRY_COUNT_INT); + } + } + + Rlog.d(TAG, "Retry Count: " + retryCount); + + return retryCount; + } + + @Override + protected int getSmsRetryDelayValue() { + int retryDelay = SEND_RETRY_DELAY; + CarrierConfigManager mConfigManager; + + mConfigManager = (CarrierConfigManager) mContext.getSystemService( + Context.CARRIER_CONFIG_SERVICE); + + if (mConfigManager != null) { + PersistableBundle carrierConfig = mConfigManager.getConfigForSubId( + getSubId()); + + if (carrierConfig != null) { + retryDelay = carrierConfig.getInt( + CarrierConfigManager.ImsSms.KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT); + } + } + + Rlog.d(TAG, "Retry delay: " + retryDelay); + + return retryDelay; + } + @Override protected boolean shouldBlockSmsForEcbm() { // We should not block outgoing SMS during ECM on IMS. It only applies to outgoing CDMA diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 5b2d7456aa..6746d7bab2 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -315,6 +315,26 @@ public abstract class SMSDispatcher extends Handler { */ protected abstract String getFormat(); + /** + * Gets the maximum number of times the SMS can be retried upon Failure, + * from the {@link android.telephony.CarrierConfigManager} + * + * @return the default maximum number of times SMS can be sent + */ + protected int getMaxSmsRetryCount() { + return MAX_SEND_RETRIES; + } + + /** + * Gets the Time delay before next send attempt on a failed SMS, + * from the {@link android.telephony.CarrierConfigManager} + * + * @return the Time in miiliseconds for delay before next send attempt on a failed SMS + */ + protected int getSmsRetryDelayValue() { + return SEND_RETRY_DELAY; + } + /** * Called when a status report is received. This should correspond to a previously successful * SEND. @@ -1014,7 +1034,7 @@ public abstract class SMSDispatcher extends Handler { // This is retry after failure over IMS but voice is not available. // Set retry to max allowed, so no retry is sent and cause // SmsManager.RESULT_ERROR_GENERIC_FAILURE to be returned to app. - tracker.mRetryCount = MAX_SEND_RETRIES; + tracker.mRetryCount = getMaxSmsRetryCount(); Rlog.d(TAG, "handleSendComplete: Skipping retry: " + " isIms()=" + isIms() @@ -1037,7 +1057,7 @@ public abstract class SMSDispatcher extends Handler { tracker.isFromDefaultSmsApplication(mContext), tracker.getInterval()); } else if (error == SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY - && tracker.mRetryCount < MAX_SEND_RETRIES) { + && tracker.mRetryCount < getMaxSmsRetryCount()) { // Retry after a delay if needed. // TODO: According to TS 23.040, 9.2.3.6, we should resend // with the same TP-MR as the failed message, and @@ -1049,7 +1069,7 @@ public abstract class SMSDispatcher extends Handler { tracker.mRetryCount++; int errorCode = (smsResponse != null) ? smsResponse.mErrorCode : NO_ERROR_CODE; Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker); - sendMessageDelayed(retryMsg, SEND_RETRY_DELAY); + sendMessageDelayed(retryMsg, getSmsRetryDelayValue()); mPhone.getSmsStats().onOutgoingSms( tracker.mImsRetry > 0 /* isOverIms */, SmsConstants.FORMAT_3GPP2.equals(getFormat()), -- GitLab From 3255c23981e40ff6ed48336f98cac74b003a0a52 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Thu, 8 Dec 2022 10:36:14 +0000 Subject: [PATCH 299/656] Implementation for SMS retry based on config - Reads the count to retry Sms over IMS from Carrier config - Applies the retry count SMS retry over IMS on Error BUg: b/230707485 Test: manual(received temp error for and attempt retry) Change-Id: Ib7c32ce7a77f233dbc241e677cc9253549e890ed --- .../internal/telephony/ImsSmsDispatcher.java | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java index b84a39e18e..c6a17a620d 100644 --- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java +++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java @@ -59,6 +59,7 @@ public class ImsSmsDispatcher extends SMSDispatcher { private static final String TAG = "ImsSmsDispatcher"; private static final int CONNECT_DELAY_MS = 5000; // 5 seconds; + public static final int MAX_SEND_RETRIES_OVER_IMS = MAX_SEND_RETRIES; /** * Creates FeatureConnector instances for ImsManager, used during testing to inject mock @@ -171,7 +172,15 @@ public class ImsSmsDispatcher extends SMSDispatcher { mTrackers.remove(token); break; case ImsSmsImplBase.SEND_STATUS_ERROR_RETRY: + int maxRetryCountOverIms = getMaxRetryCountOverIms(); if (tracker.mRetryCount < getMaxSmsRetryCount()) { + if (maxRetryCountOverIms < getMaxSmsRetryCount() + && tracker.mRetryCount >= maxRetryCountOverIms) { + tracker.mRetryCount += 1; + mTrackers.remove(token); + fallbackToPstn(tracker); + break; + } tracker.mRetryCount += 1; sendMessageDelayed( obtainMessage(EVENT_SEND_RETRY, tracker), @@ -407,7 +416,7 @@ public class ImsSmsDispatcher extends SMSDispatcher { } @Override - protected int getMaxSmsRetryCount() { + public int getMaxSmsRetryCount() { int retryCount = MAX_SEND_RETRIES; CarrierConfigManager mConfigManager; @@ -429,8 +438,37 @@ public class ImsSmsDispatcher extends SMSDispatcher { return retryCount; } + /** + * Returns the number of times SMS can be sent over IMS + * + * @return retry count over Ims from carrier configuration + */ + @VisibleForTesting + public int getMaxRetryCountOverIms() { + int retryCountOverIms = MAX_SEND_RETRIES_OVER_IMS; + CarrierConfigManager mConfigManager; + + mConfigManager = (CarrierConfigManager) mContext.getSystemService(Context + .CARRIER_CONFIG_SERVICE); + + if (mConfigManager != null) { + PersistableBundle carrierConfig = mConfigManager.getConfigForSubId( + getSubId()); + + + if (carrierConfig != null) { + retryCountOverIms = carrierConfig.getInt( + CarrierConfigManager.ImsSms.KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT); + } + } + + Rlog.d(TAG, "Retry Count Over Ims: " + retryCountOverIms); + + return retryCountOverIms; + } + @Override - protected int getSmsRetryDelayValue() { + public int getSmsRetryDelayValue() { int retryDelay = SEND_RETRY_DELAY; CarrierConfigManager mConfigManager; -- GitLab From 654b2710fb90d3ed773d4996a69f47e6c6f3367c Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Mon, 12 Dec 2022 08:48:22 +0000 Subject: [PATCH 300/656] Unit Test for SMS Retry based on Configuration - Test Retry SMS based on retry Count, retry Count over Ims and retry delay value as per Carrier Configuration. - Bug: b/230707485 Test: atest ImsSmsDispatcherTest Change-Id: I91843a4ee3ea3b55ddb314043fda04c7c4d555f0 --- .../telephony/ImsSmsDispatcherTest.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java index 548f65895d..858fa2f50e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java @@ -33,6 +33,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; import android.telephony.SmsMessage; import android.telephony.ims.stub.ImsSmsImplBase; import android.test.suitebuilder.annotation.SmallTest; @@ -64,7 +66,9 @@ public class ImsSmsDispatcherTest extends TelephonyTest { private FeatureConnector.Listener mImsManagerListener; private HashMap mTrackerData; private ImsSmsDispatcher mImsSmsDispatcher; + PersistableBundle mBundle = new PersistableBundle(); private static final int SUB_0 = 0; + private static final String TAG = "ImsSmsDispatcherTest"; @Before public void setUp() throws Exception { @@ -168,6 +172,13 @@ public class ImsSmsDispatcherTest extends TelephonyTest { @SmallTest public void testErrorImsRetry() throws Exception { int token = mImsSmsDispatcher.mNextToken.get(); + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms + .KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT, + 2000); + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms + .KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT, 3); + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms + .KEY_SMS_MAX_RETRY_COUNT_INT, 3); mTrackerData.put("pdu", com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(null, "+15555551212", "Test", false).encodedMessage); when(mImsManager.getSmsFormat()).thenReturn(SmsMessage.FORMAT_3GPP); @@ -285,6 +296,13 @@ public class ImsSmsDispatcherTest extends TelephonyTest { public void testErrorImsRetrywithMessageRef() throws Exception { int token = mImsSmsDispatcher.mNextToken.get(); int messageRef = mImsSmsDispatcher.nextMessageRef() + 1; + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms + .KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT, + 2000); + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms + .KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT, 3); + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms + .KEY_SMS_MAX_RETRY_COUNT_INT, 3); when(mImsManager.getSmsFormat()).thenReturn(SmsMessage.FORMAT_3GPP); when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM); doReturn(mSmsUsageMonitor).when(mSmsDispatchersController).getUsageMonitor(); @@ -309,4 +327,66 @@ public class ImsSmsDispatcherTest extends TelephonyTest { assertEquals(messageRef, pdu[1]); assertEquals(0x04, (pdu[0] & 0x04)); } + + @Test + public void testErrorImsRetrywithRetryConfig() throws Exception { + int token = mImsSmsDispatcher.mNextToken.get(); + int messageRef = mImsSmsDispatcher.nextMessageRef() + 1; + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms + .KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT, + 3000); + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms + .KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT, 2); + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms + .KEY_SMS_MAX_RETRY_COUNT_INT, 3); + when(mImsManager.getSmsFormat()).thenReturn(SmsMessage.FORMAT_3GPP); + when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM); + doReturn(mSmsUsageMonitor).when(mSmsDispatchersController).getUsageMonitor(); + mImsSmsDispatcher.sendText("+15555551212", null, "Retry test", + null, null, null, null, false, + -1, false, -1, false, 0); + verify(mImsManager).sendSms(eq(token + 1), eq(messageRef), eq(SmsMessage.FORMAT_3GPP), + nullable(String.class), eq(false), (byte[]) any()); + assertEquals(2, mImsSmsDispatcher.getMaxRetryCountOverIms()); + assertEquals(3, mImsSmsDispatcher.getMaxSmsRetryCount()); + assertEquals(3000, mImsSmsDispatcher.getSmsRetryDelayValue()); + // Retry over IMS + mImsSmsDispatcher.getSmsListener().onSendSmsResult(token + 1, messageRef, + ImsSmsImplBase.SEND_STATUS_ERROR_RETRY, 0, SmsResponse.NO_ERROR_CODE); + waitForMs(mImsSmsDispatcher.getSmsRetryDelayValue() + 200); + processAllMessages(); + + // Make sure tpmr value is same and retry bit set + ArgumentCaptor byteCaptor = ArgumentCaptor.forClass(byte[].class); + verify(mImsManager).sendSms(eq(token + 2), eq(messageRef), eq(SmsMessage.FORMAT_3GPP), + nullable(String.class), eq(true), byteCaptor.capture()); + byte[] pdu = byteCaptor.getValue(); + assertEquals(messageRef, pdu[1]); + assertEquals(0x04, (pdu[0] & 0x04)); + // Retry over IMS for the second time + mImsSmsDispatcher.getSmsListener().onSendSmsResult(token + 2, messageRef, + ImsSmsImplBase.SEND_STATUS_ERROR_RETRY, 0, SmsResponse.NO_ERROR_CODE); + waitForMs(mImsSmsDispatcher.getSmsRetryDelayValue() + 200); + processAllMessages(); + // Make sure tpmr value is same and retry bit set + ArgumentCaptor byteCaptor2 = ArgumentCaptor.forClass(byte[].class); + verify(mImsManager).sendSms(eq(token + 3), eq(messageRef), eq(SmsMessage.FORMAT_3GPP), + nullable(String.class), eq(true), byteCaptor2.capture()); + byte[] pdu2 = byteCaptor2.getValue(); + assertEquals(messageRef, pdu2[1]); + assertEquals(0x04, (pdu2[0] & 0x04)); + + mImsSmsDispatcher.getSmsListener().onSendSmsResult(token + 3, messageRef, + ImsSmsImplBase.SEND_STATUS_ERROR_RETRY, 0, SmsResponse.NO_ERROR_CODE); + waitForMs(mImsSmsDispatcher.getSmsRetryDelayValue() + 200); + processAllMessages(); + // Make sure tpmr value is same and retry bit set + ArgumentCaptor captor = + ArgumentCaptor.forClass(SMSDispatcher.SmsTracker.class); + // Ensure GsmSmsDispatcher calls sendSms + verify(mSmsDispatchersController).sendRetrySms(captor.capture()); + + assertNotNull(captor.getValue()); + assertTrue(captor.getValue().mRetryCount > 0); + } } -- GitLab From 2f9cdb48d29474c574bd0f5557a21341921fb50a Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Sat, 3 Dec 2022 00:09:53 +0000 Subject: [PATCH 301/656] Add subscription-user association check. Bug: 250620312 Test: Manually sending/receiving SMS/MMS, atest com.android.internal.telephony.SmsControllerTest, atest com.android.internal.telephony.SubscriptionControllerTest, atest com.android.internal.telephony.subscription.SubscriptionManagerServiceTest, atest CtsTelephonyTestCases Change-Id: I12bb0f34042529b76d0953ed51163e8efd1f498f --- .../internal/telephony/SmsController.java | 51 +++++++++- .../telephony/SubscriptionController.java | 93 ++++++++++++++++++ .../SubscriptionManagerService.java | 95 +++++++++++++++++++ .../internal/telephony/SmsControllerTest.java | 11 ++- .../telephony/SubscriptionControllerTest.java | 76 +++++++++++++++ .../SubscriptionManagerServiceTest.java | 51 ++++++++-- 6 files changed, 366 insertions(+), 11 deletions(-) diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 8b99c3e09c..c33dbe2232 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -35,6 +35,7 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.TelephonyServiceManager.ServiceRegisterer; +import android.os.UserHandle; import android.provider.Telephony.Sms.Intents; import android.telephony.CarrierConfigManager; import android.telephony.SmsManager; @@ -160,6 +161,14 @@ public class SmsController extends ISmsImplBase { } Rlog.d(LOG_TAG, "sendDataForSubscriber caller=" + callingPackage); + // Check if user is associated with the subscription + if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, + Binder.getCallingUserHandle())) { + // TODO(b/258629881): Display error dialog. + sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); + return; + } + // Perform FDN check if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); @@ -249,6 +258,14 @@ public class SmsController extends ISmsImplBase { return; } + // Check if user is associated with the subscription + if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, + Binder.getCallingUserHandle())) { + // TODO(b/258629881): Display error dialog. + sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); + return; + } + // Perform FDN check if (!skipFdnCheck && isNumberBlockedByFDN(subId, destAddr, callingPackage)) { sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); @@ -324,6 +341,14 @@ public class SmsController extends ISmsImplBase { } Rlog.d(LOG_TAG, "sendTextForSubscriberWithOptions caller=" + callingPackage); + // Check if user is associated with the subscription + if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, + Binder.getCallingUserHandle())) { + // TODO(b/258629881): Display error dialog. + sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); + return; + } + // Perform FDN check if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); @@ -354,6 +379,14 @@ public class SmsController extends ISmsImplBase { } Rlog.d(LOG_TAG, "sendMultipartTextForSubscriber caller=" + callingPackage); + // Check if user is associated with the subscription + if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, + Binder.getCallingUserHandle())) { + // TODO(b/258629881): Display error dialog. + sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_USER_NOT_ALLOWED); + return; + } + // Perform FDN check if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); @@ -382,6 +415,14 @@ public class SmsController extends ISmsImplBase { } Rlog.d(LOG_TAG, "sendMultipartTextForSubscriberWithOptions caller=" + callingPackage); + // Check if user is associated with the subscription + if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, + Binder.getCallingUserHandle())) { + // TODO(b/258629881): Display error dialog. + sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_USER_NOT_ALLOWED); + return; + } + // Perform FDN check if (isNumberBlockedByFDN(subId, destAddr, callingPackage)) { sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE); @@ -880,6 +921,14 @@ public class SmsController extends ISmsImplBase { return; } + // Check if user is associated with the subscription + if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, + Binder.getCallingUserHandle())) { + // TODO(b/258629881): Display error dialog. + sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); + return; + } + if (port == 0) { sendTextForSubscriberWithSelfPermissionsInternal(subId, callingPackage, callingAttributionTag, number, null, text, sentIntent, null, false, @@ -1067,4 +1116,4 @@ public class SmsController extends ISmsImplBase { // Check if smscAddr is present in FDN list return FdnUtils.isNumberBlockedByFDN(phoneId, smscAddr, defaultCountryIso); } -} +} \ No newline at end of file diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index ab519bbf2b..4974182a9b 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -4847,6 +4847,99 @@ public class SubscriptionController extends ISub.Stub { } } + /** + * Check if subscription and user are associated with each other. + * + * @param subscriptionId the subId of the subscription + * @param userHandle user handle of the user + * @return {@code true} if subscription is associated with user + * {code true} if there are no subscriptions on device + * else {@code false} if subscription is not associated with user. + * + * @throws SecurityException if the caller doesn't have permissions required. + * @throws IllegalStateException if subscription service is not available. + * + */ + @Override + public boolean isSubscriptionAssociatedWithUser(int subscriptionId, + @NonNull UserHandle userHandle) { + enforceManageSubscriptionUserAssociation("isSubscriptionAssociatedWithUser"); + + long token = Binder.clearCallingIdentity(); + try { + // Return true if there are no subscriptions on the device. + List subInfoList = getAllSubInfoList( + mContext.getOpPackageName(), mContext.getAttributionTag()); + if (subInfoList == null || subInfoList.isEmpty()) { + return true; + } + + // Get list of subscriptions associated with this user. + List associatedSubscriptionsList = + getSubscriptionInfoListAssociatedWithUser(userHandle); + if (associatedSubscriptionsList.isEmpty()) { + return false; + } + + // Return true if required subscription is present in associated subscriptions list. + for (SubscriptionInfo subInfo: associatedSubscriptionsList) { + if (subInfo.getSubscriptionId() == subscriptionId){ + return true; + } + } + return false; + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** + * Get list of subscriptions associated with user. + * + * If user handle is associated with some subscriptions, return subscriptionsAssociatedWithUser + * else return all the subscriptions which are not associated with any user. + * + * @param userHandle user handle of the user + * @return list of subscriptionInfo associated with the user. + * + * @throws SecurityException if the caller doesn't have permissions required. + * @throws IllegalStateException if subscription service is not available. + * + */ + @Override + public @NonNull List getSubscriptionInfoListAssociatedWithUser( + @NonNull UserHandle userHandle) { + enforceManageSubscriptionUserAssociation("getActiveSubscriptionInfoListAssociatedWithUser"); + + long token = Binder.clearCallingIdentity(); + try { + List subInfoList = getAllSubInfoList( + mContext.getOpPackageName(), mContext.getAttributionTag()); + if (subInfoList == null || subInfoList.isEmpty()) { + return new ArrayList<>(); + } + + List subscriptionsAssociatedWithUser = new ArrayList<>(); + List subscriptionsWithNoAssociation = new ArrayList<>(); + for (SubscriptionInfo subInfo : subInfoList) { + int subId = subInfo.getSubscriptionId(); + UserHandle subIdUserHandle = getSubscriptionUserHandle(subId); + if (userHandle.equals(subIdUserHandle)) { + // Store subscriptions whose user handle matches with required user handle. + subscriptionsAssociatedWithUser.add(subInfo); + } else if (subIdUserHandle == null) { + // Store subscriptions whose user handle is set to null. + subscriptionsWithNoAssociation.add(subInfo); + } + } + + return subscriptionsAssociatedWithUser.isEmpty() ? + subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser; + } finally { + Binder.restoreCallingIdentity(token); + } + } + /** * @hide */ diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 3fad17aba6..9d0f806461 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -3018,6 +3018,101 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Check if subscription and user are associated with each other. + * + * @param subscriptionId the subId of the subscription + * @param userHandle user handle of the user + * @return {@code true} if subscription is associated with user + * {code true} if there are no subscriptions on device + * else {@code false} if subscription is not associated with user. + * + * @throws SecurityException if the caller doesn't have permissions required. + * @throws IllegalStateException if subscription service is not available. + * + */ + @Override + public boolean isSubscriptionAssociatedWithUser(int subscriptionId, + @NonNull UserHandle userHandle) { + enforcePermissions("isSubscriptionAssociatedWithUser", + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + + long token = Binder.clearCallingIdentity(); + try { + // Return true if there are no subscriptions on the device. + List subInfoList = getAllSubInfoList( + mContext.getOpPackageName(), mContext.getAttributionTag()); + if (subInfoList == null || subInfoList.isEmpty()) { + return true; + } + + // Get list of subscriptions associated with this user. + List associatedSubscriptionsList = + getSubscriptionInfoListAssociatedWithUser(userHandle); + if (associatedSubscriptionsList.isEmpty()) { + return false; + } + + // Return true if required subscription is present in associated subscriptions list. + for (SubscriptionInfo subInfo: associatedSubscriptionsList) { + if (subInfo.getSubscriptionId() == subscriptionId){ + return true; + } + } + return false; + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** + * Get list of subscriptions associated with user. + * + * If user handle is associated with some subscriptions, return subscriptionsAssociatedWithUser + * else return all the subscriptions which are not associated with any user. + * + * @param userHandle user handle of the user + * @return list of subscriptionInfo associated with the user. + * + * @throws SecurityException if the caller doesn't have permissions required. + * @throws IllegalStateException if subscription service is not available. + * + */ + @Override + public @NonNull List getSubscriptionInfoListAssociatedWithUser( + @NonNull UserHandle userHandle) { + enforcePermissions("getSubscriptionInfoListAssociatedWithUser", + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + + long token = Binder.clearCallingIdentity(); + try { + List subInfoList = getAllSubInfoList( + mContext.getOpPackageName(), mContext.getAttributionTag()); + if (subInfoList == null || subInfoList.isEmpty()) { + return new ArrayList<>(); + } + + List subscriptionsAssociatedWithUser = new ArrayList<>(); + List subscriptionsWithNoAssociation = new ArrayList<>(); + for (SubscriptionInfo subInfo : subInfoList) { + int subId = subInfo.getSubscriptionId(); + UserHandle subIdUserHandle = getSubscriptionUserHandle(subId); + if (userHandle.equals(subIdUserHandle)) { + // Store subscriptions whose user handle matches with required user handle. + subscriptionsAssociatedWithUser.add(subInfo); + } else if (subIdUserHandle == null) { + // Store subscriptions whose user handle is set to null. + subscriptionsWithNoAssociation.add(subInfo); + } + } + + return subscriptionsAssociatedWithUser.isEmpty() ? + subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser; + } finally { + Binder.restoreCallingIdentity(token); + } + } + /** * Register the callback for receiving information from {@link SubscriptionManagerService}. * diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java index 63f7d00552..ab2907664a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java @@ -173,9 +173,12 @@ public class SmsControllerTest extends TelephonyTest { @Test public void sendVisualVoicemailSmsForSubscriber_phoneIsNotInEcm() { assertFalse(mPhone.isInEcm()); + int subId = 1; + doReturn(true).when(mSubscriptionManager) + .isSubscriptionAssociatedWithUser(eq(subId), any()); mSmsControllerUT.sendVisualVoicemailSmsForSubscriber(mCallingPackage,null , - 1, null, 0, null, null); + subId, null, 0, null, null); verify(mIccSmsInterfaceManager).sendTextWithSelfPermissions(any(), any(), any(), any(), any(), any(), any(), eq(false), eq(true)); } @@ -194,7 +197,11 @@ public class SmsControllerTest extends TelephonyTest { @Test public void sendsendTextForSubscriberTest() { - mSmsControllerUT.sendTextForSubscriber(1, mCallingPackage, null, "1234", + int subId = 1; + doReturn(true).when(mSubscriptionManager) + .isSubscriptionAssociatedWithUser(eq(subId), any()); + + mSmsControllerUT.sendTextForSubscriber(subId, mCallingPackage, null, "1234", null, "text", null, null, false, 0L, true, true); verify(mIccSmsInterfaceManager, Mockito.times(1)) .sendText(mCallingPackage, "1234", null, "text", null, null, false, 0L, true); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index eb628eff56..019a717dfc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -2219,6 +2219,82 @@ public class SubscriptionControllerTest extends TelephonyTest { SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)); } + @Test + public void isSubscriptionAssociatedWithUser_withoutPermission() { + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); + + assertThrows(SecurityException.class, + () -> mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(1, + UserHandle.of(UserHandle.USER_SYSTEM))); + } + + @Test + public void isSubscriptionAssociatedWithUser_noSubscription() { + // isSubscriptionAssociatedWithUser should return true if there are no active subscriptions. + assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(1, + UserHandle.of(UserHandle.USER_SYSTEM))).isEqualTo(true); + } + + @Test + public void isSubscriptionAssociatedWithUser_unknownSubId() { + testInsertSim(); + /* Get SUB ID */ + int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); + assertTrue(subIds != null && subIds.length != 0); + int unknownSubId = 123; + + assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(unknownSubId, + UserHandle.of(UserHandle.USER_SYSTEM))).isEqualTo(false); + } + + @Test + public void isSubscriptionAssociatedWithUser_userAssociatedWithSubscription() { + testInsertSim(); + /* Get SUB ID */ + int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); + assertTrue(subIds != null && subIds.length != 0); + final int subId = subIds[0]; + + mSubscriptionControllerUT.setSubscriptionUserHandle( + UserHandle.of(UserHandle.USER_SYSTEM), subId); + + assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(subId, + UserHandle.of(UserHandle.USER_SYSTEM))).isEqualTo(true); + } + + @Test + public void isSubscriptionAssociatedWithUser_userNotAssociatedWithSubscription() { + testInsertSim(); + enableGetSubscriptionUserHandle(); + /* Get SUB ID */ + int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); + assertTrue(subIds != null && subIds.length != 0); + final int subId = subIds[0]; + + mSubscriptionControllerUT.setSubscriptionUserHandle(UserHandle.of(UserHandle.USER_SYSTEM), + subId); + + assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(subId, + UserHandle.of(10))).isEqualTo(false); + } + + + @Test + public void getSubscriptionInfoListAssociatedWithUser_withoutPermission() { + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); + + assertThrows(SecurityException.class, + () -> mSubscriptionControllerUT.getSubscriptionInfoListAssociatedWithUser( + UserHandle.of(UserHandle.USER_SYSTEM))); + } + + @Test + public void getSubscriptionInfoListAssociatedWithUser_noSubscription() { + List associatedSubInfoList = mSubscriptionControllerUT + .getSubscriptionInfoListAssociatedWithUser(UserHandle.of(UserHandle.USER_SYSTEM)); + assertThat(associatedSubInfoList.size()).isEqualTo(0); + } + private void enableGetSubscriptionUserHandle() { Resources mResources = mock(Resources.class); doReturn(true).when(mResources).getBoolean( 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 109d5e40c7..51dea369d1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -54,6 +54,7 @@ import static org.mockito.ArgumentMatchers.nullable; 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.times; import static org.mockito.Mockito.verify; @@ -121,6 +122,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { private final SubscriptionProvider mSubscriptionProvider = new SubscriptionProvider(); + private static final UserHandle FAKE_USER_HANDLE = new UserHandle(12); + // mocked private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback; private EuiccController mEuiccController; @@ -230,6 +233,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } + private void enableGetSubscriptionUserHandle() { + Resources mResources = mock(Resources.class); + doReturn(true).when(mResources).getBoolean( + eq(com.android.internal.R.bool.config_enable_get_subscription_user_handle)); + doReturn(mResources).when(mContext).getResources(); + } + @Test public void testAddSubInfo() { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); @@ -917,18 +927,15 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetGetSubscriptionUserHandle() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); - Resources mResources = Mockito.mock(Resources.class); - doReturn(true).when(mResources).getBoolean( - eq(com.android.internal.R.bool.config_enable_get_subscription_user_handle)); - doReturn(mResources).when(mContext).getResources(); + enableGetSubscriptionUserHandle(); // Should fail without MANAGE_SUBSCRIPTION_USER_ASSOCIATION assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT - .setSubscriptionUserHandle(new UserHandle(12), 1)); + .setSubscriptionUserHandle(FAKE_USER_HANDLE, 1)); mContextFixture.addCallingOrSelfPermission( Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); - mSubscriptionManagerServiceUT.setSubscriptionUserHandle(new UserHandle(12), 1); + mSubscriptionManagerServiceUT.setSubscriptionUserHandle(FAKE_USER_HANDLE, 1); processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); @@ -936,7 +943,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT .getSubscriptionInfoInternal(1); assertThat(subInfo).isNotNull(); - assertThat(subInfo.getUserId()).isEqualTo(12); + assertThat(subInfo.getUserId()).isEqualTo(FAKE_USER_HANDLE.getIdentifier()); mContextFixture.removeCallingOrSelfPermission( Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); @@ -948,7 +955,35 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); assertThat(mSubscriptionManagerServiceUT.getSubscriptionUserHandle(1)) - .isEqualTo(new UserHandle(12)); + .isEqualTo(FAKE_USER_HANDLE); + } + + @Test + public void testIsSubscriptionAssociatedWithUser() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + enableGetSubscriptionUserHandle(); + + // Should fail without MANAGE_SUBSCRIPTION_USER_ASSOCIATION + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .isSubscriptionAssociatedWithUser(1, FAKE_USER_HANDLE)); + assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT + .getSubscriptionInfoListAssociatedWithUser(FAKE_USER_HANDLE)); + + mContextFixture.addCallingOrSelfPermission( + Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + mSubscriptionManagerServiceUT.setSubscriptionUserHandle(FAKE_USER_HANDLE, 1); + processAllMessages(); + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + + List associatedSubInfoList = mSubscriptionManagerServiceUT + .getSubscriptionInfoListAssociatedWithUser(FAKE_USER_HANDLE); + assertThat(associatedSubInfoList.size()).isEqualTo(1); + assertThat(associatedSubInfoList.get(0).getSubscriptionId()).isEqualTo(1); + + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, + FAKE_USER_HANDLE)).isEqualTo(true); } @Test -- GitLab From 787f83ca9aee7fc483abb377eb5d3160aaf5e476 Mon Sep 17 00:00:00 2001 From: sangyun Date: Wed, 21 Dec 2022 13:34:58 +0900 Subject: [PATCH 302/656] Fix to set transportType when creating DataServiceManager. DSM for iwlan is not created in DataNetworkController, then, fixed to set transportType each WWAN and WLAN to DataServiceManager. Bug: 263271203 Test: atest + handover btw WWAN and WWLAN Change-Id: Ide4834512719d58720cd059de6d9d3ff05f6e4a3 --- .../android/internal/telephony/data/DataNetworkController.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 8ea453efb9..7609045ded 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -780,8 +780,7 @@ public class DataNetworkController extends Handler { mAccessNetworksManager = phone.getAccessNetworksManager(); for (int transport : mAccessNetworksManager.getAvailableTransports()) { - mDataServiceManagers.put(transport, new DataServiceManager(mPhone, looper, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + mDataServiceManagers.put(transport, new DataServiceManager(mPhone, looper, transport)); } mDataConfigManager = new DataConfigManager(mPhone, looper); -- GitLab From 9adac74d4c1fb3335f2866802c5520c8b8a14cb5 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 20 Dec 2022 16:31:26 -0800 Subject: [PATCH 303/656] Skip retry delay for handover not allowed by policy Fix: 235478296 Test: manual voice call Change-Id: I83d60b4bb72623ddd184e8172ee99f9fc8ee3af9 --- .../internal/telephony/data/DataNetwork.java | 21 +++++++++++++++---- .../telephony/data/DataNetworkController.java | 20 +++++++++++------- .../data/DataNetworkControllerTest.java | 2 +- .../telephony/data/DataNetworkTest.java | 14 ++++++------- 4 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 6a6e027f1c..3a0489f451 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -266,8 +266,9 @@ public class DataNetwork extends StateMachine { private static final int DEFAULT_INTERNET_NETWORK_SCORE = 50; private static final int OTHER_NETWORK_SCORE = 45; - @IntDef(prefix = {"DEACTIVATION_REASON_"}, + @IntDef(prefix = {"TEAR_DOWN_REASON_"}, value = { + TEAR_DOWN_REASON_NONE, TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED, TEAR_DOWN_REASON_SIM_REMOVAL, TEAR_DOWN_REASON_AIRPLANE_MODE_ON, @@ -300,6 +301,9 @@ public class DataNetwork extends StateMachine { }) public @interface TearDownReason {} + /** Data network was not torn down. */ + public static final int TEAR_DOWN_REASON_NONE = 0; + /** Data network tear down requested by connectivity service. */ public static final int TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED = 1; @@ -377,7 +381,7 @@ public class DataNetwork extends StateMachine { /** Data network tear down due to data profile not preferred. */ public static final int TEAR_DOWN_REASON_DATA_PROFILE_NOT_PREFERRED = 26; - /** Data network tear down due to not allowed by policy. */ + /** Data network tear down due to handover not allowed by policy. */ public static final int TEAR_DOWN_REASON_NOT_ALLOWED_BY_POLICY = 27; /** Data network tear down due to illegal state. */ @@ -625,6 +629,11 @@ public class DataNetwork extends StateMachine { */ private @DataFailureCause int mFailCause = DataFailCause.NONE; + /** + * The tear down reason if the data call is voluntarily deactivated, not due to failure. + */ + private @TearDownReason int mTearDownReason = TEAR_DOWN_REASON_NONE; + /** * The retry delay in milliseconds from setup data failure. */ @@ -785,9 +794,10 @@ public class DataNetwork extends StateMachine { * * @param dataNetwork The data network. * @param cause The disconnect cause. + * @param tearDownReason The reason the network was torn down */ public abstract void onDisconnected(@NonNull DataNetwork dataNetwork, - @DataFailureCause int cause); + @DataFailureCause int cause, @TearDownReason int tearDownReason); /** * Called when handover between IWLAN and cellular network succeeded. @@ -1564,7 +1574,7 @@ public class DataNetwork extends StateMachine { if (mEverConnected) { mDataNetworkCallback.invokeFromExecutor(() -> mDataNetworkCallback - .onDisconnected(DataNetwork.this, mFailCause)); + .onDisconnected(DataNetwork.this, mFailCause, mTearDownReason)); if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { unregisterForWwanEvents(); } @@ -2532,6 +2542,7 @@ public class DataNetwork extends StateMachine { if (getCurrentState() == null || isDisconnected()) { return; } + mTearDownReason = reason; sendMessage(obtainMessage(EVENT_TEAR_DOWN_NETWORK, reason)); } @@ -3357,6 +3368,8 @@ public class DataNetwork extends StateMachine { */ 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: diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 8ea453efb9..3aa95b269f 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -1851,7 +1851,7 @@ public class DataNetworkController extends Handler { } } - log("Evaluated " + dataNetwork + ", " + evaluation.toString()); + log("Evaluated " + dataNetwork + ", " + evaluation); return evaluation; } @@ -2045,7 +2045,7 @@ public class DataNetworkController extends Handler { return DataNetwork.TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK; } } - return 0; + return DataNetwork.TEAR_DOWN_REASON_NONE; } /** @@ -2487,9 +2487,9 @@ public class DataNetworkController extends Handler { @Override public void onDisconnected(@NonNull DataNetwork dataNetwork, - @DataFailureCause int cause) { + @DataFailureCause int cause, @TearDownReason int tearDownReason) { DataNetworkController.this.onDataNetworkDisconnected( - dataNetwork, cause); + dataNetwork, cause, tearDownReason); } @Override @@ -2811,11 +2811,13 @@ public class DataNetworkController extends Handler { * * @param dataNetwork The data network. * @param cause The disconnect cause. + * @param tearDownReason The reason the network was torn down */ private void onDataNetworkDisconnected(@NonNull DataNetwork dataNetwork, - @DataFailureCause int cause) { + @DataFailureCause int cause, @TearDownReason int tearDownReason) { logl("onDataNetworkDisconnected: " + dataNetwork + ", cause=" - + DataFailCause.toString(cause) + "(" + cause + ")"); + + DataFailCause.toString(cause) + "(" + cause + "), tearDownReason=" + + DataNetwork.tearDownReasonToString(tearDownReason)); mDataNetworkList.remove(dataNetwork); mPendingImsDeregDataNetworks.remove(dataNetwork); mDataRetryManager.cancelPendingHandoverRetry(dataNetwork); @@ -2836,11 +2838,13 @@ public class DataNetworkController extends Handler { () -> callback.onAnyDataNetworkExistingChanged(mAnyDataNetworkExisting))); } + // Immediately reestablish on target transport if network was torn down due to policy + long delayMillis = tearDownReason == DataNetwork.TEAR_DOWN_REASON_HANDOVER_NOT_ALLOWED + ? 0 : mDataConfigManager.getRetrySetupAfterDisconnectMillis(); // Sometimes network was unsolicitedly reported lost for reasons. We should re-evaluate // and see if data network can be re-established again. sendMessageDelayed(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, - DataEvaluationReason.RETRY_AFTER_DISCONNECTED), - mDataConfigManager.getRetrySetupAfterDisconnectMillis()); + DataEvaluationReason.RETRY_AFTER_DISCONNECTED), delayMillis); } /** 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 0b243e7b2e..bf5e01040f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -3451,7 +3451,7 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testHandoverDataNetworkSourceOos() throws Exception { testSetupImsDataNetwork(); - // Configured handover is allowed from OOS to 4G/5G/IWLAN. + // Configured handover is disallowed from OOS to 4G/5G/IWLAN. mCarrierConfig.putStringArray( CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, new String[]{ 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 f6edd768fa..60cf1204a4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -365,8 +365,7 @@ public class DataNetworkTest extends TelephonyTest { .setQosBearerSessions(new ArrayList<>()) .setTrafficDescriptors(new ArrayList<>()) .build(); - mDataNetworkUT.sendMessage(7/*EVENT_TEAR_DOWN_NETWORK*/, - 1/*TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED*/); + mDataNetworkUT.tearDown(1/*TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED*/); mDataNetworkUT.sendMessage(8/*EVENT_DATA_STATE_CHANGED*/, new AsyncResult(transport, new ArrayList<>(Arrays.asList(response)), null)); processAllMessages(); @@ -591,7 +590,7 @@ public class DataNetworkTest extends TelephonyTest { processAllMessages(); verify(mDataNetworkCallback).onDisconnected(eq(mDataNetworkUT), - eq(DataFailCause.RADIO_NOT_AVAILABLE)); + eq(DataFailCause.RADIO_NOT_AVAILABLE), eq(DataNetwork.TEAR_DOWN_REASON_NONE)); } @Test @@ -849,8 +848,9 @@ public class DataNetworkTest extends TelephonyTest { anyInt()); verify(mMockedWwanDataServiceManager).deactivateDataCall(eq(123), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); - verify(mDataNetworkCallback).onDisconnected(eq(mDataNetworkUT), eq( - DataFailCause.EMM_DETACHED)); + verify(mDataNetworkCallback).onDisconnected(eq(mDataNetworkUT), + eq(DataFailCause.EMM_DETACHED), + eq(DataNetwork.TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED)); ArgumentCaptor pdcsCaptor = ArgumentCaptor.forClass(PreciseDataConnectionState.class); @@ -963,7 +963,7 @@ public class DataNetworkTest extends TelephonyTest { verify(mMockedWlanDataServiceManager).deactivateDataCall(eq(123), eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); verify(mDataNetworkCallback).onDisconnected(eq(mDataNetworkUT), eq( - DataFailCause.EMM_DETACHED)); + DataFailCause.EMM_DETACHED), anyInt() /* tear down reason */); ArgumentCaptor pdcsCaptor = ArgumentCaptor.forClass(PreciseDataConnectionState.class); @@ -1237,7 +1237,7 @@ public class DataNetworkTest extends TelephonyTest { processAllMessages(); verify(mDataNetworkCallback).onDisconnected(eq(mDataNetworkUT), eq( - DataFailCause.RADIO_NOT_AVAILABLE)); + DataFailCause.RADIO_NOT_AVAILABLE), eq(DataNetwork.TEAR_DOWN_REASON_NONE)); assertThat(mDataNetworkUT.isConnected()).isFalse(); } -- GitLab From e826250d17e998d2d9a3969e3f7935153e8caf84 Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Mon, 12 Dec 2022 09:49:32 +0000 Subject: [PATCH 304/656] UnitTest:TelephonyCallback location renounced EV Provide unit test for listening BarringInfo & RegistrationFailed event with renouncing location access. Bug: 259614273 Test: atest FrameworksTelephonyTests Change-Id: Icb9e966a62f4967f458a0f3f9aa76adcaaf42cf5 --- .../telephony/TelephonyRegistryTest.java | 157 +++++++++++++++++- 1 file changed, 150 insertions(+), 7 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java index 0a5a2ea7b1..5c6302d040 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java @@ -25,7 +25,9 @@ import static android.telephony.TelephonyManager.RADIO_POWER_ON; import static android.telephony.TelephonyManager.RADIO_POWER_UNAVAILABLE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -35,9 +37,11 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import android.Manifest; import android.content.Intent; import android.content.pm.UserInfo; import android.net.LinkProperties; +import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -108,6 +112,8 @@ public class TelephonyRegistryTest extends TelephonyTest { private CellLocation mCellLocation; private List mCellInfo; private BarringInfo mBarringInfo = null; + private CellIdentity mCellIdentityForRegiFail; + private int mRegistrationFailReason; // All events contribute to TelephonyRegistry#isPhoneStatePermissionRequired private static final Set READ_PHONE_STATE_EVENTS; @@ -176,7 +182,8 @@ public class TelephonyRegistryTest extends TelephonyTest { TelephonyCallback.CellLocationListener, TelephonyCallback.ServiceStateListener, TelephonyCallback.CellInfoListener, - TelephonyCallback.BarringInfoListener { + TelephonyCallback.BarringInfoListener, + TelephonyCallback.RegistrationFailedListener { // This class isn't mockable to get invocation counts because the IBinder is null and // crashes the TelephonyRegistry. Make a cheesy verify(times()) alternative. public AtomicInteger invocationCount = new AtomicInteger(0); @@ -250,6 +257,15 @@ public class TelephonyRegistryTest extends TelephonyTest { invocationCount.incrementAndGet(); mBarringInfo = barringInfo; } + + public void onRegistrationFailed(@android.annotation.NonNull CellIdentity cellIdentity, + @android.annotation.NonNull String chosenPlmn, + @NetworkRegistrationInfo.Domain int domain, + int causeCode, int additionalCauseCode) { + invocationCount.incrementAndGet(); + mCellIdentityForRegiFail = cellIdentity; + mRegistrationFailReason = causeCode; + } } private void addTelephonyRegistryService() { @@ -897,24 +913,48 @@ public class TelephonyRegistryTest extends TelephonyTest { } @Test - public void testBarringInfoChanged() { + public void testBarringInfoChangedWithLocationFinePermission() throws Exception { + checkBarringInfoWithLocationPermission(Manifest.permission.ACCESS_FINE_LOCATION); + } + + @Test + public void testBarringInfoChangedLocationCoarsePermission() throws Exception { + checkBarringInfoWithLocationPermission(Manifest.permission.ACCESS_COARSE_LOCATION); + } + + @Test + public void testBarringInfoChangedWithoutLocationPermission() throws Exception { + checkBarringInfoWithLocationPermission(null); + } + + private void checkBarringInfoWithLocationPermission(String permission) throws Exception { // Return a slotIndex / phoneId of 0 for all sub ids given. doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt()); doReturn(0/*slotIndex*/).when(mMockSubInfo).getSimSlotIndex(); doReturn(true).when(mLocationManager).isLocationEnabledForUser(any(UserHandle.class)); + mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.TIRAMISU; + doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(anyString(), anyInt()); + mContextFixture.addCallingOrSelfPermission(""); + mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE); + mContextFixture.addCallingOrSelfPermission( + android.Manifest.permission.READ_PRECISE_PHONE_STATE); + if (permission != null) { + mContextFixture.addCallingOrSelfPermission(permission); + } + final int subId = 1; int[] events = {TelephonyCallback.EVENT_BARRING_INFO_CHANGED}; SparseArray bsi = new SparseArray(1); - bsi.set(BarringInfo.BARRING_SERVICE_TYPE_MO_DATA, + bsi.set(BarringInfo.BARRING_SERVICE_TYPE_MMTEL_VOICE, new BarringInfo.BarringServiceInfo( BarringInfo.BarringServiceInfo.BARRING_TYPE_CONDITIONAL, false /*isConditionallyBarred*/, 30 /*conditionalBarringFactor*/, 10 /*conditionalBarringTimeSeconds*/)); - BarringInfo info = new BarringInfo(new CellIdentityLte(), bsi); - - // Registering for info causes Barring Info to be sent to caller + BarringInfo info = new BarringInfo( + new CellIdentityLte(777, 333, 12345, 222, 13579), bsi); + // 1. Register listener which requires location access. mTelephonyRegistry.listenWithEventList(false, false, subId, mContext.getOpPackageName(), mContext.getAttributionTag(), mTelephonyCallback.callback, events, true); processAllMessages(); @@ -925,12 +965,115 @@ public class TelephonyRegistryTest extends TelephonyTest { mTelephonyRegistry.notifyBarringInfoChanged(0, subId, info); processAllMessages(); assertEquals(2, mTelephonyCallback.invocationCount.get()); - assertEquals(mBarringInfo, info); + assertEquals(mBarringInfo + .getBarringServiceInfo(BarringInfo.BARRING_SERVICE_TYPE_MMTEL_VOICE), + info.getBarringServiceInfo(BarringInfo.BARRING_SERVICE_TYPE_MMTEL_VOICE)); + String log = mBarringInfo.toString(); + assertTrue(log.contains("777")); + assertTrue(log.contains("333")); + if (permission != null && permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)) { + assertTrue(log.contains("12345")); + assertTrue(log.contains("222")); + assertTrue(log.contains("13579")); + } else { + assertFalse(log.contains("12345")); + assertFalse(log.contains("222")); + assertFalse(log.contains("13579")); + } // Duplicate BarringInfo notifications do not trigger callback mTelephonyRegistry.notifyBarringInfoChanged(0, subId, info); processAllMessages(); assertEquals(2, mTelephonyCallback.invocationCount.get()); + + mTelephonyRegistry.listenWithEventList(true, true, subId, mContext.getOpPackageName(), + mContext.getAttributionTag(), mTelephonyCallback.callback, new int[0], true); + // 2. Register listener renounces location access. + mTelephonyRegistry.listenWithEventList(true, true, subId, mContext.getOpPackageName(), + mContext.getAttributionTag(), mTelephonyCallback.callback, events, true); + processAllMessages(); + // check receiving barring info without location info. + assertEquals(3, mTelephonyCallback.invocationCount.get()); + assertNotNull(mBarringInfo); + assertEquals(mBarringInfo + .getBarringServiceInfo(BarringInfo.BARRING_SERVICE_TYPE_MMTEL_VOICE), + info.getBarringServiceInfo(BarringInfo.BARRING_SERVICE_TYPE_MMTEL_VOICE)); + log = mBarringInfo.toString(); + assertTrue(log.contains("777")); + assertTrue(log.contains("333")); + assertFalse(log.contains("12345")); + assertFalse(log.contains("222")); + assertFalse(log.contains("13579")); + } + + @Test + public void testRegistrationFailedEventWithLocationFinePermission() throws Exception { + checkRegistrationFailedEventWithLocationPermission( + Manifest.permission.ACCESS_FINE_LOCATION); + } + @Test + public void testRegistrationFailedEventWithLocationCoarsePermission() throws Exception { + checkRegistrationFailedEventWithLocationPermission( + Manifest.permission.ACCESS_COARSE_LOCATION); + } + + @Test + public void testRegistrationFailedEventWithoutLocationPermission() throws Exception { + checkRegistrationFailedEventWithLocationPermission(null); + } + + private void checkRegistrationFailedEventWithLocationPermission(String permission) + throws Exception { + // Return a slotIndex / phoneId of 0 for all sub ids given. + doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt()); + doReturn(0/*slotIndex*/).when(mMockSubInfo).getSimSlotIndex(); + doReturn(true).when(mLocationManager).isLocationEnabledForUser(any(UserHandle.class)); + + mApplicationInfo.targetSdkVersion = Build.VERSION_CODES.TIRAMISU; + doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(anyString(), anyInt()); + mContextFixture.addCallingOrSelfPermission(""); + mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE); + mContextFixture.addCallingOrSelfPermission( + android.Manifest.permission.READ_PRECISE_PHONE_STATE); + if (permission != null) { + mContextFixture.addCallingOrSelfPermission(permission); + } + + final int subId = 1; + int[] events = {TelephonyCallback.EVENT_REGISTRATION_FAILURE}; + CellIdentity cellIdentity = + new CellIdentityLte(777, 333, 12345, 227, 13579); + + // 1. Register listener which requires location access. + mTelephonyRegistry.listenWithEventList(false, false, subId, mContext.getOpPackageName(), + mContext.getAttributionTag(), mTelephonyCallback.callback, events, true); + processAllMessages(); + int invocationCount = mTelephonyCallback.invocationCount.get(); + // Updating the RegistrationFailed info to be updated + mTelephonyRegistry.notifyRegistrationFailed( + 0, subId, cellIdentity, "88888", 1, 333, 22); + processAllMessages(); + assertEquals(invocationCount + 1, mTelephonyCallback.invocationCount.get()); + if (permission != null && permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)) { + assertEquals(cellIdentity, mCellIdentityForRegiFail); + } else { + assertEquals(cellIdentity.sanitizeLocationInfo(), mCellIdentityForRegiFail); + } + assertEquals(333, mRegistrationFailReason); + mTelephonyRegistry.listenWithEventList(true, true, subId, mContext.getOpPackageName(), + mContext.getAttributionTag(), mTelephonyCallback.callback, new int[0], true); + + // 2. Register listener which renounces location access. + mTelephonyRegistry.listenWithEventList(true, true, subId, mContext.getOpPackageName(), + mContext.getAttributionTag(), mTelephonyCallback.callback, events, true); + invocationCount = mTelephonyCallback.invocationCount.get(); + // Updating the RegistrationFailed info to be updated + mTelephonyRegistry.notifyRegistrationFailed( + 0, subId, cellIdentity, "88888", 1, 555, 22); + processAllMessages(); + assertEquals(invocationCount + 1, mTelephonyCallback.invocationCount.get()); + assertEquals(cellIdentity.sanitizeLocationInfo(), mCellIdentityForRegiFail); + assertEquals(555, mRegistrationFailReason); } /** -- GitLab From f41702d28f106cc4af69040952ee17f2421da63d Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Wed, 21 Dec 2022 19:05:49 +0000 Subject: [PATCH 305/656] isSimPortAvailable API should return true if the calling app can activate a new profile on the selected port without any user consent or deactivate dialog. Currently isSimPortAvailable API returns true if the port is active without any profile enabled on it or the calling app has carrier privileges over the selected port. It is hampering switching to MEP mode when the psim is active and empty. Test: Manually verified isSimPortAvailable API behavior with EuiccPartnerApp and Fi App on C10 Bug: 240273417 Change-Id: I329f2d30ace7845ff591ec476f957a69d03bc528 --- .../telephony/euicc/EuiccController.java | 110 ++++++++------- .../telephony/euicc/EuiccControllerTest.java | 133 ++++++++++++++++++ 2 files changed, 196 insertions(+), 47 deletions(-) diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java index 9b4894e80a..4e74de8fad 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccController.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java @@ -1890,8 +1890,6 @@ public class EuiccController extends IEuiccController.Stub { boolean hasActiveEmbeddedSubscription = subInfoList.stream().anyMatch( subInfo -> subInfo.isEmbedded() && subInfo.getCardId() == cardId && (!usePortIndex || subInfo.getPortIndex() == targetPortIndex)); - Log.d(TAG, "canManageSubscriptionOnTargetSim hasActiveEmbeddedSubscriptions: " - + hasActiveEmbeddedSubscription); if (hasActiveEmbeddedSubscription) { // hasActiveEmbeddedSubscription is true if there is an active embedded subscription // on the target port(in case of usePortIndex is true) or if there is an active @@ -1948,59 +1946,77 @@ public class EuiccController extends IEuiccController.Stub { @Override public boolean isSimPortAvailable(int cardId, int portIndex, String callingPackage) { - List cardInfos; + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); + // In the event that this check is coming from ONS, WRITE_EMBEDDED_SUBSCRIPTIONS will be + // required for the case where a port is inactive but could trivially be enabled without + // requiring user consent. + boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions(); final long token = Binder.clearCallingIdentity(); try { - cardInfos = mTelephonyManager.getUiccCardsInfo(); - } finally { - Binder.restoreCallingIdentity(token); - } - for (UiccCardInfo info : cardInfos) { - if (info == null || info.getCardId() != cardId) { - continue; - } - // Return false in case of non esim or passed port index is greater than - // the available ports. - if (!info.isEuicc() || (portIndex == TelephonyManager.INVALID_PORT_INDEX) - || portIndex >= info.getPorts().size()) { - return false; - } - for (UiccPortInfo portInfo : info.getPorts()) { - if (portInfo == null || portInfo.getPortIndex() != portIndex) { + List cardInfos = mTelephonyManager.getUiccCardsInfo(); + for (UiccCardInfo info : cardInfos) { + if (info == null || info.getCardId() != cardId) { continue; } - // Return false if port is not active. - if (!portInfo.isActive()) { + // Return false in case of non esim or passed port index is greater than + // the available ports. + if (!info.isEuicc() || (portIndex == TelephonyManager.INVALID_PORT_INDEX) + || portIndex >= info.getPorts().size()) { return false; } - // A port is available if it has no profiles enabled on it or calling app has - // Carrier privilege over the profile installed on the selected port. - if (TextUtils.isEmpty(portInfo.getIccId())) { - return true; - } - UiccPort uiccPort = - UiccController.getInstance().getUiccPortForSlot( - info.getPhysicalSlotIndex(), portIndex); - // Some eSim Vendors return boot profile iccid if no profile is installed. - // So in this case if profile is empty, port is available. - if (uiccPort != null - && uiccPort.getUiccProfile() != null - && uiccPort.getUiccProfile().isEmptyProfile()) { - return true; - } - Phone phone = PhoneFactory.getPhone(portInfo.getLogicalSlotIndex()); - if (phone == null) { - Log.e(TAG, "Invalid logical slot: " + portInfo.getLogicalSlotIndex()); - return false; - } - CarrierPrivilegesTracker cpt = phone.getCarrierPrivilegesTracker(); - if (cpt == null) { - Log.e(TAG, "No CarrierPrivilegesTracker"); - return false; + for (UiccPortInfo portInfo : info.getPorts()) { + if (portInfo == null || portInfo.getPortIndex() != portIndex) { + continue; + } + if (!portInfo.isActive()) { + // port is inactive, check whether the caller can activate a new profile + // seamlessly. This is possible in below condition: + // 1. Device in DSDS Mode(P+E). + // 2. pSIM slot is active but no active subscription. + // 3. Caller has carrier privileges on any phone or has + // WRITE_EMBEDDED_SUBSCRIPTIONS. The latter covers calls from ONS + // which does not have carrier privileges. + boolean hasActiveRemovableNonEuiccSlot = getRemovableNonEuiccSlot() != null + && getRemovableNonEuiccSlot().isActive(); + boolean hasCarrierPrivileges = mTelephonyManager + .checkCarrierPrivilegesForPackageAnyPhone(callingPackage) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; + return mTelephonyManager.isMultiSimEnabled() + && hasActiveRemovableNonEuiccSlot + && !isRemovalNonEuiccSlotHasActiveSubscription() + && (hasCarrierPrivileges || callerCanWriteEmbeddedSubscriptions); + } + // A port is available if it has no profiles enabled on it or calling app has + // Carrier privilege over the profile installed on the selected port. + if (TextUtils.isEmpty(portInfo.getIccId())) { + return true; + } + UiccPort uiccPort = + UiccController.getInstance().getUiccPortForSlot( + info.getPhysicalSlotIndex(), portIndex); + // Some eSim Vendors return boot profile iccid if no profile is installed. + // So in this case if profile is empty, port is available. + if (uiccPort != null + && uiccPort.getUiccProfile() != null + && uiccPort.getUiccProfile().isEmptyProfile()) { + return true; + } + Phone phone = PhoneFactory.getPhone(portInfo.getLogicalSlotIndex()); + if (phone == null) { + Log.e(TAG, "Invalid logical slot: " + portInfo.getLogicalSlotIndex()); + return false; + } + CarrierPrivilegesTracker cpt = phone.getCarrierPrivilegesTracker(); + if (cpt == null) { + Log.e(TAG, "No CarrierPrivilegesTracker"); + return false; + } + return (cpt.getCarrierPrivilegeStatusForPackage(callingPackage) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); } - return (cpt.getCarrierPrivilegeStatusForPackage(callingPackage) - == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); } + } finally { + Binder.restoreCallingIdentity(token); } return false; } 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 600c94a6d3..1fd767f413 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java @@ -65,6 +65,8 @@ import android.telephony.euicc.EuiccManager; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.euicc.EuiccConnector.GetOtaStatusCommandCallback; import com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback; @@ -89,6 +91,7 @@ import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; @RunWith(AndroidJUnit4.class) public class EuiccControllerTest extends TelephonyTest { @@ -128,6 +131,7 @@ public class EuiccControllerTest extends TelephonyTest { private static final int SUBSCRIPTION_ID = 12345; private static final String ICC_ID = "54321"; private static final int CARD_ID = 25; + private static final int REMOVABLE_CARD_ID = 26; // Mocked classes private EuiccConnector mMockConnector; @@ -1290,6 +1294,135 @@ public class EuiccControllerTest extends TelephonyTest { SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE)); } + @Test + public void testIsSimPortAvailable_invalidCase() { + setUiccCardInfos(false, true, true); + // assert non euicc card id + assertFalse(mController.isSimPortAvailable(REMOVABLE_CARD_ID, 0, PACKAGE_NAME)); + + // assert invalid port index + assertFalse(mController.isSimPortAvailable(CARD_ID, 5 /* portIndex */, PACKAGE_NAME)); + } + + @Test + public void testIsSimPortAvailable_port_active() throws Exception { + setUiccCardInfos(false, true, true); + + // port has empty iccid + assertTrue(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + + // Set port is active, has valid iccid(may be boot profile) and UiccProfile is empty + setUiccCardInfos(false, true, false); + when(mUiccController.getUiccPortForSlot(anyInt(), anyInt())).thenReturn(mUiccPort); + when(mUiccPort.getUiccProfile()).thenReturn(mUiccProfile); + when(mUiccProfile.isEmptyProfile()).thenReturn(true); + assertTrue(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + + // port is active, valid iccid, not empty profile but Phone object is null + when(mUiccPort.getUiccProfile()).thenReturn(mUiccProfile); + when(mUiccProfile.isEmptyProfile()).thenReturn(false); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); + // logicalSlotIndex of port#0 is 1, Phone object should be null + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + + // port is active, valid iccid, not empty profile but no carrier privileges + when(mUiccPort.getUiccProfile()).thenReturn(mUiccProfile); + when(mUiccProfile.isEmptyProfile()).thenReturn(false); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone, mPhone}); + when(mPhone.getCarrierPrivilegesTracker()).thenReturn(null); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + when(mPhone.getCarrierPrivilegesTracker()).thenReturn(mCarrierPrivilegesTracker); + when(mCarrierPrivilegesTracker.getCarrierPrivilegeStatusForPackage(PACKAGE_NAME)) + .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + + // port is active, valid iccid, not empty profile and has carrier privileges + when(mCarrierPrivilegesTracker.getCarrierPrivilegeStatusForPackage(PACKAGE_NAME)) + .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); + assertTrue(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + } + + @Test + public void testIsSimPortAvailable_port_inActive() { + setUiccCardInfos(false, false, true); + when(mUiccController.getUiccSlots()).thenReturn(new UiccSlot[]{mUiccSlot}); + when(mUiccSlot.isRemovable()).thenReturn(true); + + // Check getRemovableNonEuiccSlot null case + when(mUiccSlot.isEuicc()).thenReturn(true); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + + // Check getRemovableNonEuiccSlot isActive() false case + when(mUiccSlot.isEuicc()).thenReturn(false); + when(mUiccSlot.isActive()).thenReturn(false); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + + // assert false,multisim is not enabled + when(mUiccSlot.isEuicc()).thenReturn(false); + when(mUiccSlot.isActive()).thenReturn(true); + when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(PACKAGE_NAME)).thenReturn( + TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); + when(mTelephonyManager.isMultiSimEnabled()).thenReturn(false); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + + // assert false, caller does not have carrier privileges + setHasWriteEmbeddedPermission(false); + when(mTelephonyManager.isMultiSimEnabled()).thenReturn(true); + when(mUiccSlot.getPortList()).thenReturn(new int[] {0}); + when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(anyInt())).thenReturn( + new SubscriptionInfo.Builder().build()); + when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(PACKAGE_NAME)).thenReturn( + TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + + // assert true, caller does not have carrier privileges but has write_embedded permission + setHasWriteEmbeddedPermission(true); + assertTrue(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + + // assert true, caller has carrier privileges + setHasWriteEmbeddedPermission(false); + when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(PACKAGE_NAME)).thenReturn( + TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); + assertTrue(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + } + + + private void setUiccCardInfos(boolean isMepSupported, boolean isPortActive, + boolean isEmptyPort) { + List euiccPortInfoList; + if (isMepSupported) { + euiccPortInfoList = Arrays.asList( + new UiccPortInfo(isEmptyPort ? "" : ICC_ID /* iccId */, 0 /* portIdx */, + isPortActive ? 1 : -1 /* logicalSlotIdx */, + isPortActive /* isActive */), + new UiccPortInfo(isEmptyPort ? "" : ICC_ID /* iccId */, 1 /* portIdx */, + -1 /* logicalSlotIdx */, + isPortActive /* isActive */)); + } else { + euiccPortInfoList = Collections.singletonList( + new UiccPortInfo(isEmptyPort ? "" : ICC_ID /* iccId */, 0 /* portIdx */, + isPortActive ? 1 : -1 /* logicalSlotIdx */, + isPortActive /* isActive */) + ); + } + + UiccCardInfo cardInfo1 = new UiccCardInfo(true, CARD_ID, "", 0, + false /* isRemovable */, + isMepSupported /* isMultipleEnabledProfileSupported */, + euiccPortInfoList); + UiccCardInfo cardInfo2 = new UiccCardInfo(false /* isEuicc */, + REMOVABLE_CARD_ID /* cardId */, + "", 0, true /* isRemovable */, + false /* isMultipleEnabledProfileSupported */, + Collections.singletonList( + new UiccPortInfo("" /* iccId */, 0 /* portIdx */, + 0 /* logicalSlotIdx */, true /* isActive */))); + ArrayList cardInfos = new ArrayList<>(); + cardInfos.add(cardInfo1); + cardInfos.add(cardInfo2); + when(mTelephonyManager.getUiccCardsInfo()).thenReturn(cardInfos); + } + private void setUpUiccSlotData() { when(mUiccController.getUiccSlot(anyInt())).thenReturn(mUiccSlot); // TODO(b/199559633): Add test cases for isMultipleEnabledProfileSupported true case -- GitLab From 158acc3b67bc57f173cbbdbe6ba210fa755f5c6c Mon Sep 17 00:00:00 2001 From: sangyun Date: Wed, 21 Dec 2022 13:34:58 +0900 Subject: [PATCH 306/656] Fix to set transportType when creating DataServiceManager. DSM for iwlan is not created in DataNetworkController, then, fixed to set transportType each WWAN and WLAN to DataServiceManager. Bug: 263271203 Test: atest + handover btw WWAN and WWLAN Change-Id: Ide4834512719d58720cd059de6d9d3ff05f6e4a3 (cherry picked from commit 787f83ca9aee7fc483abb377eb5d3160aaf5e476) Merged-In: Ide4834512719d58720cd059de6d9d3ff05f6e4a3 --- .../android/internal/telephony/data/DataNetworkController.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 8ea453efb9..7609045ded 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -780,8 +780,7 @@ public class DataNetworkController extends Handler { mAccessNetworksManager = phone.getAccessNetworksManager(); for (int transport : mAccessNetworksManager.getAvailableTransports()) { - mDataServiceManagers.put(transport, new DataServiceManager(mPhone, looper, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN)); + mDataServiceManagers.put(transport, new DataServiceManager(mPhone, looper, transport)); } mDataConfigManager = new DataConfigManager(mPhone, looper); -- GitLab From 787f7c56e4fd83a9776aff34e00f0f13e3a6420b Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 22 Dec 2022 03:36:19 -0800 Subject: [PATCH 307/656] Added SIM events handling and fix crashes 1. Added SIM events handling in subscription manager service. 2. Fixed all crashes found during boot up. 3. Update subscription before broadcasting carrier config changed event. Bug: 239607619 Test: Manual Change-Id: I97fe3454548426027fd403e820aecb34481a22f4 --- .../internal/telephony/PhoneFactory.java | 9 +- .../telephony/ServiceStateTracker.java | 4 +- .../telephony/SubscriptionController.java | 5 +- .../telephony/data/PhoneSwitcher.java | 10 +- .../SubscriptionDatabaseManager.java | 61 +- .../SubscriptionManagerService.java | 520 +++++++++++++----- .../telephony/uicc/UiccController.java | 29 +- .../internal/telephony/uicc/UiccProfile.java | 11 +- .../SubscriptionManagerServiceTest.java | 23 +- 9 files changed, 464 insertions(+), 208 deletions(-) diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index cb8f984b0f..43aa15434b 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -214,9 +214,14 @@ public class PhoneFactory { TelephonyComponentFactory.getInstance().inject(SubscriptionController.class .getName()).initSubscriptionController(context); } + + SubscriptionController sc = null; + if (!isSubscriptionManagerServiceEnabled()) { + sc = SubscriptionController.getInstance(); + } + TelephonyComponentFactory.getInstance().inject(MultiSimSettingController.class. - getName()).initMultiSimSettingController(context, - SubscriptionController.getInstance()); + getName()).initMultiSimSettingController(context, sc); if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY_EUICC)) { diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 9c7178a63d..2a76a84eea 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -2751,8 +2751,8 @@ public class ServiceStateTracker extends Handler { if (mPhone.isSubscriptionManagerServiceEnabled()) { mSubscriptionManagerService.setCarrierName(mPhone.getSubId(), - getCarrierName(data.shouldShowPlmn(), data.getPlmn(), - data.shouldShowSpn(), data.getSpn())); + TextUtils.emptyIfNull(getCarrierName(data.shouldShowPlmn(), data.getPlmn(), + data.shouldShowSpn(), data.getSpn()))); } else { if (!mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), data.shouldShowPlmn(), data.getPlmn(), data.shouldShowSpn(), diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index ab519bbf2b..46a067e9c5 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -331,8 +331,11 @@ public class SubscriptionController extends ISub.Stub { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static SubscriptionController getInstance() { + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + throw new RuntimeException("getInstance should not be called."); + } if (sInstance == null) { - Log.wtf(LOG_TAG, "getInstance null"); + Log.wtf(LOG_TAG, "getInstance null"); } return sInstance; diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 1eb07aa4fb..fe63ada5a8 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -531,8 +531,14 @@ public class PhoneSwitcher extends Handler { mMaxDataAttachModemCount = maxActivePhones; mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES); - mSubscriptionController = SubscriptionController.getInstance(); - mSubscriptionManagerService = SubscriptionManagerService.getInstance(); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); + mSubscriptionController = null; + } else { + mSubscriptionController = SubscriptionController.getInstance(); + mSubscriptionManagerService = null; + } + mRadioConfig = RadioConfig.getInstance(); mValidator = CellularNetworkValidator.getInstance(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 501d4f0cc5..199d2d4f30 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -39,6 +39,7 @@ import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyManager; +import android.telephony.UiccAccessRule; import android.telephony.ims.ImsMmTelManager; import android.text.TextUtils; import android.util.Base64; @@ -562,6 +563,7 @@ public class SubscriptionDatabaseManager extends Handler { public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper, @NonNull SubscriptionDatabaseManagerCallback callback) { super(looper); + log("Created SubscriptionDatabaseManager."); mContext = context; mCallback = callback; mUiccController = UiccController.getInstance(); @@ -684,6 +686,8 @@ public class SubscriptionDatabaseManager extends Handler { for (String columnName : Telephony.SimInfo.getAllColumns()) { if (DEPRECATED_DATABASE_COLUMNS.contains(columnName)) continue; + // subId is generated by the database. Cannot be updated. + if (columnName.equals(SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID)) continue; Object newValue = getSubscriptionInfoFieldByColumnName(newSubInfo, columnName); if (newValue != null) { Object oldValue = null; @@ -712,13 +716,16 @@ public class SubscriptionDatabaseManager extends Handler { Objects.requireNonNull(contentValues); Uri uri = mContext.getContentResolver().insert(SimInfo.CONTENT_URI, contentValues); if (uri != null && uri.getLastPathSegment() != null) { - logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" - + uri.getLastPathSegment()); - return Integer.parseInt(uri.getLastPathSegment()); - } else { - logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " - + "contentValues=" + contentValues); + int subId = Integer.parseInt(uri.getLastPathSegment()); + if (SubscriptionManager.isValidSubscriptionId(subId)) { + logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" + + uri.getLastPathSegment()); + return subId; + } } + + logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " + + "contentValues=" + contentValues); return INVALID_ROW_INDEX; } @@ -875,6 +882,8 @@ public class SubscriptionDatabaseManager extends Handler { // Check if the new value is different from the old value in the cache. if (!Objects.equals(getSubscriptionInfoFieldByColumnName(subInfo, columnName), newValue)) { + logv("writeDatabaseAndCacheHelper: subId=" + subId + ",columnName=" + + columnName + ", newValue=" + newValue); // If the value is different, then we need to update the cache. Since all // fields in SubscriptionInfo are final, we need to create a new // SubscriptionInfo. @@ -1210,6 +1219,24 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules); } + /** + * Set the carrier certificates for this subscription that are saved in carrier configs. + * This does not include access rules from the Uicc, whether embedded or non-embedded. + * + * @param subId Subscription id. + * @param carrierConfigAccessRules The carrier certificates for this subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCarrierConfigAccessRules(int subId, + @NonNull UiccAccessRule[] carrierConfigAccessRules) { + Objects.requireNonNull(carrierConfigAccessRules); + byte[] carrierConfigAccessRulesBytes = UiccAccessRule.encodeRules(carrierConfigAccessRules); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, + carrierConfigAccessRulesBytes, + SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules); + } + /** * Set whether an embedded subscription is on a removable card. Such subscriptions are * marked inaccessible as soon as the current card is removed. Otherwise, they will remain @@ -1761,11 +1788,23 @@ public class SubscriptionDatabaseManager extends Handler { // publicCardId is the publicly exposed int card ID int publicCardId = mUiccController.convertToPublicCardId(cardString); + byte[] rules = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_ACCESS_RULES)); + if (rules != null) { + builder.setNativeAccessRules(rules); + } + + rules = cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS)); + if (rules != null) { + builder.setCarrierConfigAccessRules(rules); + } + + byte[] config = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_RCS_CONFIG)); + if (config != null) { + builder.setRcsConfig(config); + } + builder.setCardId(publicCardId) - .setNativeAccessRules(cursor.getBlob(cursor.getColumnIndexOrThrow( - SimInfo.COLUMN_ACCESS_RULES))) - .setCarrierConfigAccessRules(cursor.getBlob(cursor.getColumnIndexOrThrow( - SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS))) .setRemovableEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_IS_REMOVABLE))) .setEnhanced4GModeEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( @@ -1805,8 +1844,6 @@ public class SubscriptionDatabaseManager extends Handler { SimInfo.COLUMN_IMS_RCS_UCE_ENABLED))) .setCrossSimCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED))) - .setRcsConfig(cursor.getBlob(cursor.getColumnIndexOrThrow( - SimInfo.COLUMN_RCS_CONFIG))) .setAllowedNetworkTypesForReasons(TextUtils.emptyIfNull( cursor.getString(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS)))) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index d3793e2caa..2555fd1c6d 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -37,6 +37,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.ParcelUuid; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.TelephonyServiceManager; import android.os.UserHandle; @@ -75,6 +76,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CarrierResolver; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; +import com.android.internal.telephony.IccCard; import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; @@ -84,7 +86,9 @@ import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccController; +import com.android.internal.telephony.uicc.UiccPort; import com.android.internal.telephony.uicc.UiccSlot; import com.android.internal.telephony.util.ArrayUtils; import com.android.telephony.Rlog; @@ -137,6 +141,7 @@ public class SubscriptionManagerService extends ISub.Stub { SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, SimInfo.COLUMN_RCS_CONFIG, + SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, SimInfo.COLUMN_D2D_STATUS_SHARING, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, @@ -230,6 +235,10 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull private final WatchedInt mDefaultSmsSubId; + /** Sim state per logical SIM slot index. */ + @NonNull + private final int[] mSimState; + /** * Watched map that automatically invalidate cache in {@link SubscriptionManager}. */ @@ -263,7 +272,7 @@ public class SubscriptionManagerService extends ISub.Stub { * Watched integer. */ public static class WatchedInt { - private int mValue; + protected int mValue; /** * Constructor. @@ -377,7 +386,9 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { + int oldValue = mValue; if (super.set(newValue)) { + logl("Default voice sub changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, newValue); return true; @@ -391,7 +402,9 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { + int oldValue = mValue; if (super.set(newValue)) { + logl("Default data sub changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, newValue); return true; @@ -405,7 +418,9 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { + int oldValue = mValue; if (super.set(newValue)) { + logl("Default voice sms changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, newValue); return true; @@ -416,6 +431,9 @@ public class SubscriptionManagerService extends ISub.Stub { mDefaultSubId = new WatchedInt(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mSimState = new int[mTelephonyManager.getSupportedModemCount()]; + Arrays.fill(mSimState, TelephonyManager.SIM_STATE_UNKNOWN); + // Create a separate thread for subscription database manager. The database will be updated // from a different thread. HandlerThread handlerThread = new HandlerThread(LOG_TAG); @@ -990,13 +1008,292 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Check if the SIM application is enabled on the card or not. + * + * @param phoneId The phone id. + * + * @return {@code true} if the application is enabled. + */ + public boolean areUiccAppsEnabledOnCard(int phoneId) { + // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from + // cardStatus (since IRadio 1.2). And upon cardStatus change we'll receive another + // handleSimNotReady so this will be evaluated again. + UiccSlot slot = mUiccController.getUiccSlotForPhone(phoneId); + if (slot == null) return false; + UiccPort port = mUiccController.getUiccPort(phoneId); + String iccId = (port == null) ? null : port.getIccId(); + if (iccId == null) { + return false; + } + + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternalByIccId(IccUtils.stripTrailingFs(iccId)); + return subInfo != null && subInfo.areUiccApplicationsEnabled(); + } + + /** + * Get ICCID by phone id. + * + * @param phoneId The phone id (i.e. Logical SIM slot index.) + * + * @return The ICCID. Empty string if not available. + */ + @NonNull + private String getIccId(int phoneId) { + UiccPort port = mUiccController.getUiccPort(phoneId); + return (port == null) ? "" : TextUtils.emptyIfNull( + IccUtils.stripTrailingFs(port.getIccId())); + } + /** * Update the subscriptions on the logical SIM slot index (i.e. phone id). * - * @param slotIndex The logical SIM slot index. + * @param phoneId The phone id (i.e. Logical SIM slot index) + */ + private void updateSubscriptions(int phoneId) { + int simState = mSimState[phoneId]; + log("updateSubscriptions: phoneId=" + phoneId + ", simState=" + + TelephonyManager.simStateToString(simState)); + if (simState == TelephonyManager.SIM_STATE_ABSENT) { + if (mSlotIndexToSubId.containsKey(phoneId)) { + // Re-enable the SIM when it's removed, so it will be in enabled state when it gets + // re-inserted again. (pre-U behavior) + mSubscriptionDatabaseManager.setUiccApplicationsEnabled( + mSlotIndexToSubId.get(phoneId), true); + // When sim is absent, set the port index to invalid port index. (pre-U behavior) + mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(phoneId), + TelephonyManager.INVALID_PORT_INDEX); + } + } else if (simState == TelephonyManager.SIM_STATE_NOT_READY) { + // Check if this is the final state. Only update the subscription if NOT_READY is a + // final state. + IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); + if (!iccCard.isEmptyProfile() && areUiccAppsEnabledOnCard(phoneId)) { + log("updateSubscriptions: SIM_STATE_NOT_READY is not a final state. Will update " + + "subscription later."); + return; + } + } + + String iccId = getIccId(phoneId); + // Loop through all the subscriptions. If we found any ICCID matched, apply the right + // logical index to that. + int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + for (SubscriptionInfoInternal subInfo + : mSubscriptionDatabaseManager.getAllSubscriptions()) { + int simSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX; + if (!TextUtils.isEmpty(iccId) && subInfo.getIccId().equals(iccId)) { + subId = subInfo.getSubscriptionId(); + simSlotIndex = phoneId; + mSlotIndexToSubId.put(simSlotIndex, subId); + logl("updateSubscriptions: Found sub " + subInfo.getSubscriptionId() + + ", phoneId=" + phoneId); + } + mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), simSlotIndex); + } + + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + logl("updateSubscriptions: Did not find any subscription. phoneId=" + phoneId); + mSlotIndexToSubId.remove(phoneId); + } + + if (!TextUtils.isEmpty(iccId)) { + // Check if the subscription already existed. + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternalByIccId(iccId); + if (subInfo == null) { + // This is a new SIM card. Insert a new record. + subId = mSubscriptionDatabaseManager.insertSubscriptionInfo( + new SubscriptionInfoInternal.Builder() + .setIccId(iccId) + .setSimSlotIndex(phoneId) + .build()); + logl("updateSubscriptions: Inserted a new subscription. subId=" + subId + + ", phoneId=" + phoneId); + } else { + subId = subInfo.getSubscriptionId(); + } + + // Update the SIM slot index. This will make the subscription active. + mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId); + + // Update the card id. + UiccCard card = mUiccController.getUiccCardForPhone(phoneId); + if (card != null) { + String cardId = card.getCardId(); + if (cardId != null) { + mSubscriptionDatabaseManager.setCardString(subId, cardId); + } + } + + // Update the port index. + UiccSlot slot = mUiccController.getUiccSlotForPhone(phoneId); + if (slot != null && !slot.isEuicc()) { + int portIndex = slot.getPortIndexFromIccId(iccId); + mSubscriptionDatabaseManager.setPortIndex(subId, portIndex); + } + } + + updateDefaultSubIds(); + } + + /** + * Calculate the usage setting based on the carrier request. + * + * @param currentUsageSetting the current setting in the subscription DB. + * @param preferredUsageSetting provided by the carrier config. + * + * @return the calculated usage setting. + */ + @VisibleForTesting + @UsageSetting public int calculateUsageSetting(@UsageSetting int currentUsageSetting, + @UsageSetting int preferredUsageSetting) { + int[] supportedUsageSettings; + + // Load the resources to provide the device capability + try { + supportedUsageSettings = mContext.getResources().getIntArray( + com.android.internal.R.array.config_supported_cellular_usage_settings); + // If usage settings are not supported, return the default setting, which is UNKNOWN. + if (supportedUsageSettings == null + || supportedUsageSettings.length < 1) return currentUsageSetting; + } catch (Resources.NotFoundException nfe) { + loge("calculateUsageSetting: Failed to load usage setting resources!"); + return currentUsageSetting; + } + + // If the current setting is invalid, including the first time the value is set, + // update it to default (this will trigger a change in the DB). + if (currentUsageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT + || currentUsageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { + log("calculateUsageSetting: Updating usage setting for current subscription"); + currentUsageSetting = SubscriptionManager.USAGE_SETTING_DEFAULT; + } + + // Range check the inputs, and on failure, make no changes + if (preferredUsageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT + || preferredUsageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { + loge("calculateUsageSetting: Invalid usage setting!" + preferredUsageSetting); + return currentUsageSetting; + } + + // Default is always allowed + if (preferredUsageSetting == SubscriptionManager.USAGE_SETTING_DEFAULT) { + return preferredUsageSetting; + } + + // Forced setting must be explicitly supported + for (int supportedUsageSetting : supportedUsageSettings) { + if (preferredUsageSetting == supportedUsageSetting) return preferredUsageSetting; + } + + // If the preferred setting is not possible, just keep the current setting. + return currentUsageSetting; + } + + /** + * Called by CarrierConfigLoader to update the subscription before sending a broadcast. */ - private void updateSubscriptions(int slotIndex) { + public void updateSubscriptionByCarrierConfig(int phoneId, @NonNull String configPackageName, + @NonNull PersistableBundle config, @NonNull Runnable callback) { + mHandler.post(() -> { + updateSubscriptionByCarrierConfigInternal(phoneId, configPackageName, config); + callback.run(); + }); + } + + private void updateSubscriptionByCarrierConfigInternal(int phoneId, + @NonNull String configPackageName, @NonNull PersistableBundle config) { + log("updateSubscriptionByCarrierConfig: phoneId=" + phoneId + ", configPackageName=" + + configPackageName); + if (!SubscriptionManager.isValidPhoneId(phoneId) + || TextUtils.isEmpty(configPackageName) || config == null) { + loge("updateSubscriptionByCarrierConfig: Failed to update the subscription. phoneId=" + + phoneId + " configPackageName=" + configPackageName + " config=" + + ((config == null) ? "null" : config.hashCode())); + return; + } + + if (!mSlotIndexToSubId.containsKey(phoneId)) { + log("updateSubscriptionByCarrierConfig: No subscription is active for phone being " + + "updated."); + return; + } + + int subId = mSlotIndexToSubId.get(phoneId); + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + if (subInfo == null) { + loge("updateSubscriptionByCarrierConfig: Couldn't retrieve subscription info for " + + "current subscription. subId=" + subId); + return; + } + + ParcelUuid groupUuid; + + // carrier certificates are not subscription-specific, so we want to load them even if + // this current package is not a CarrierServicePackage + String[] certs = config.getStringArray( + CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY); + UiccAccessRule[] carrierConfigAccessRules = UiccAccessRule.decodeRulesFromCarrierConfig( + certs); + if (carrierConfigAccessRules != null) { + mSubscriptionDatabaseManager.setCarrierConfigAccessRules( + subId, carrierConfigAccessRules); + } + + boolean isOpportunistic = config.getBoolean( + CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, + subInfo.isOpportunistic()); + mSubscriptionDatabaseManager.setOpportunistic(subId, isOpportunistic); + + String groupUuidString = config.getString( + CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, ""); + String oldGroupUuidString = subInfo.getGroupUuid(); + if (!TextUtils.isEmpty(groupUuidString)) { + try { + // Update via a UUID Structure to ensure consistent formatting + groupUuid = ParcelUuid.fromString(groupUuidString); + if (groupUuidString.equals(CarrierConfigManager.REMOVE_GROUP_UUID_STRING)) { + // Remove the group UUID. + mSubscriptionDatabaseManager.setGroupUuid(subId, ""); + } else if (canPackageManageGroup(groupUuid, configPackageName)) { + mSubscriptionDatabaseManager.setGroupUuid(subId, groupUuidString); + mSubscriptionDatabaseManager.setGroupOwner(subId, configPackageName); + log("updateSubscriptionByCarrierConfig: Group added for sub " + subId); + } else { + loge("updateSubscriptionByCarrierConfig: configPackageName " + + configPackageName + " doesn't own groupUuid " + groupUuid); + } + + if (!groupUuidString.equals(oldGroupUuidString)) { + MultiSimSettingController.getInstance() + .notifySubscriptionGroupChanged(groupUuid); + } + } catch (IllegalArgumentException e) { + loge("updateSubscriptionByCarrierConfig: Invalid Group UUID=" + + groupUuidString); + } + } + + final int preferredUsageSetting = config.getInt( + CarrierConfigManager.KEY_CELLULAR_USAGE_SETTING_INT, + SubscriptionManager.USAGE_SETTING_UNKNOWN); + + int newUsageSetting = calculateUsageSetting( + subInfo.getUsageSetting(), preferredUsageSetting); + + if (newUsageSetting != subInfo.getUsageSetting()) { + mSubscriptionDatabaseManager.setUsageSetting(subId, newUsageSetting); + log("updateSubscriptionByCarrierConfig: UsageSetting changed," + + " oldSetting=" + SubscriptionManager.usageSettingToString( + subInfo.getUsageSetting()) + + " preferredSetting=" + SubscriptionManager.usageSettingToString( + preferredUsageSetting) + + " newSetting=" + SubscriptionManager.usageSettingToString(newUsageSetting)); + } } /** @@ -1044,26 +1341,20 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - final long identity = Binder.clearCallingIdentity(); - try { - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full - // list. Carrier apps can only get the subscriptions they have privileged. - .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( - mContext, subInfo.getSubscriptionId(), callingPackage, callingFeatureId, - "getAllSubInfoList")) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getAllSubInfoList")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); - - } finally { - Binder.restoreCallingIdentity(identity); - } + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full + // list. Carrier apps can only get the subscriptions they have privileged. + .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( + mContext, subInfo.getSubscriptionId(), callingPackage, callingFeatureId, + "getAllSubInfoList")) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getAllSubInfoList")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); } /** @@ -1226,22 +1517,16 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - final long identity = Binder.clearCallingIdentity(); - try { - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(SubscriptionInfoInternal::isActive) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getAllSubInfoList")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); - - } finally { - Binder.restoreCallingIdentity(identity); - } + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isActive) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getAllSubInfoList")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); } /** @@ -1285,7 +1570,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int getActiveSubInfoCountMax() { - return mTelephonyManager.getSimCount(); + return mTelephonyManager.getActiveModemCount(); } /** @@ -1857,26 +2142,21 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - final long identity = Binder.clearCallingIdentity(); - try { - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full - // list. Carrier apps can only get the subscriptions they have privileged. - .filter(subInfo -> subInfo.isOpportunistic() - && TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( - mContext, subInfo.getSubscriptionId(), callingPackage, - callingFeatureId, "getOpportunisticSubscriptions")) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getOpportunisticSubscriptions")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); - } finally { - Binder.restoreCallingIdentity(identity); - } + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full + // list. Carrier apps can only get the subscriptions they have privileged. + .filter(subInfo -> subInfo.isOpportunistic() + && TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( + mContext, subInfo.getSubscriptionId(), callingPackage, + callingFeatureId, "getOpportunisticSubscriptions")) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getOpportunisticSubscriptions")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); } /** @@ -2131,6 +2411,32 @@ public class SubscriptionManagerService extends ISub.Stub { return new int[]{getSubId(slotIndex)}; } + /** + * Update default voice, sms, and data sub id. + */ + private void updateDefaultSubIds() { + if (getActiveSubInfoCountMax() == 0) { + mDefaultVoiceSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mDefaultSmsSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mDefaultDataSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + if (getActiveSubInfoCountMax() == 1) { + int[] activeSubIds = getActiveSubIdList(false); + if (activeSubIds.length == 1) { + mDefaultVoiceSubId.set(activeSubIds[0]); + mDefaultSmsSubId.set(activeSubIds[0]); + mDefaultDataSubId.set(activeSubIds[0]); + } else { + loge("updateDefaultSubIds: Single SIM device, but active subs are more than one." + + " activeSubIds=" + Arrays.toString(activeSubIds)); + } + } else { + // TODO: Support dual sim + } + + updateDefaultSubId(); + } + /** * Update default sub id. */ @@ -2351,9 +2657,12 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(subInfo -> subInfo.isActive() && (!visibleOnly || subInfo.isVisible())) - .mapToInt(SubscriptionInfoInternal::getSubscriptionId) + return mSlotIndexToSubId.values().stream() + .filter(subId -> { + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + return subInfo != null && (!visibleOnly || subInfo.isVisible()); }) + .mapToInt(x -> x) .toArray(); } finally { Binder.restoreCallingIdentity(token); @@ -2558,9 +2867,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public boolean isActiveSubId(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "isActiveSubId")) { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " @@ -3093,68 +3399,6 @@ public class SubscriptionManagerService extends ISub.Stub { ? subscriptionInfoInternal.toSubscriptionInfo() : null; } - /** - * Called when SIM state changed to absent. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimAbsent(int slotIndex) { - if (mSlotIndexToSubId.containsKey(slotIndex)) { - // Re-enable the SIM when it's removed, so it will be in enabled state when it gets - // re-inserted again. (pre-U behavior) - mSubscriptionDatabaseManager.setUiccApplicationsEnabled( - mSlotIndexToSubId.get(slotIndex), true); - // When sim is absent, set the port index to invalid port index. (pre-U behavior) - mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(slotIndex), - TelephonyManager.INVALID_PORT_INDEX); - } - updateSubscriptions(slotIndex); - } - - /** - * Called when SIM state changed to locked. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimLocked(int slotIndex) { - - } - - /** - * Called when SIM state changed to ready. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimReady(int slotIndex) { - - } - - /** - * Called when SIM state changed to not ready. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimNotReady(int slotIndex) { - - } - - /** - * Called when SIM encounters error. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimError(int slotIndex) { - - } - - /** - * Called when SIM state changed to loaded. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimLoaded(int slotIndex) { - } - /** * Called when eSIM becomes inactive. * @@ -3186,34 +3430,24 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable @CallbackExecutor Executor executor, @Nullable Runnable updateCompleteCallback) { mHandler.post(() -> { + mSimState[slotIndex] = simState; switch (simState) { case TelephonyManager.SIM_STATE_ABSENT: - onSimAbsent(slotIndex); - break; case TelephonyManager.SIM_STATE_PIN_REQUIRED: case TelephonyManager.SIM_STATE_PUK_REQUIRED: case TelephonyManager.SIM_STATE_NETWORK_LOCKED: case TelephonyManager.SIM_STATE_PERM_DISABLED: - onSimLocked(slotIndex); - break; case TelephonyManager.SIM_STATE_READY: - onSimReady(slotIndex); - break; - case TelephonyManager.SIM_STATE_NOT_READY: - onSimNotReady(slotIndex); - break; case TelephonyManager.SIM_STATE_CARD_IO_ERROR: - onSimError(slotIndex); + case TelephonyManager.SIM_STATE_LOADED: + case TelephonyManager.SIM_STATE_NOT_READY: + updateSubscriptions(slotIndex); break; case TelephonyManager.SIM_STATE_CARD_RESTRICTED: + default: // No specific things needed to be done. Just return and broadcast the SIM // states. break; - case TelephonyManager.SIM_STATE_LOADED: - onSimLoaded(slotIndex); - break; - default: - break; } if (executor != null && updateCompleteCallback != null) { executor.execute(updateCompleteCallback); diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 1ad7ee35f6..f88aa7d1ed 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -40,7 +40,6 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.SimState; @@ -950,31 +949,6 @@ public class UiccController extends Handler { mCarrierServiceBindHelper.updateSimState(phoneId, simState); } - /** - * Check if the SIM application is enabled on the card or not. - * - * @param phoneId The phone id. - * @return {@code true} if the application is enabled. - */ - private boolean areUiccAppsEnabledOnCard(int phoneId) { - // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from - // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another - // handleSimNotReady so this will be evaluated again. - UiccSlot slot = getUiccSlotForPhone(phoneId); - if (slot == null) return false; - UiccPort port = getUiccPort(phoneId); - String iccId = (port == null) ? null : port.getIccId(); - if (iccId == null) { - return false; - } - SubscriptionInfo info = SubscriptionManagerService.getInstance() - .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) - .stream().filter(subInfo -> subInfo.getIccId().equals( - IccUtils.stripTrailingFs(iccId))) - .findFirst().orElse(null); - return info != null && info.areUiccApplicationsEnabled(); - } - /** * Update the SIM state. * @@ -1011,7 +985,8 @@ public class UiccController extends Handler { if (simState == TelephonyManager.SIM_STATE_NOT_READY && (uiccProfile != null && !uiccProfile.isEmptyProfile()) - && areUiccAppsEnabledOnCard(phoneId)) { + && SubscriptionManagerService.getInstance() + .areUiccAppsEnabledOnCard(phoneId)) { // STATE_NOT_READY is not a final state for when both // 1) It's not an empty profile, and // 2) Its uicc applications are set to enabled. diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index d9ff3f15d6..11f6738652 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -527,8 +527,15 @@ public class UiccProfile extends IccCard { private void updateCarrierNameForSubscription(int subId, int nameSource) { /* update display name with carrier override */ - SubscriptionInfo subInfo = SubscriptionController.getInstance().getActiveSubscriptionInfo( - subId, mContext.getOpPackageName(), mContext.getAttributionTag()); + SubscriptionInfo subInfo; + + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + subInfo = SubscriptionManagerService.getInstance().getActiveSubscriptionInfo(subId, + mContext.getOpPackageName(), mContext.getAttributionTag()); + } else { + subInfo = SubscriptionController.getInstance().getActiveSubscriptionInfo( + subId, mContext.getOpPackageName(), mContext.getAttributionTag()); + } if (subInfo == null) { return; 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 109d5e40c7..8eee9a601b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -1522,24 +1522,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { } @Test - public void testGetNonAccessibleFields() { + public void testGetNonAccessibleFields() throws Exception { insertSubscription(FAKE_SUBSCRIPTION_INFO1); - Set accessibleColumns = Set.of( - SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, - SimInfo.COLUMN_VT_IMS_ENABLED, - SimInfo.COLUMN_WFC_IMS_ENABLED, - SimInfo.COLUMN_WFC_IMS_MODE, - SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, - SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, - SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, - SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, - SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, - SimInfo.COLUMN_RCS_CONFIG, - SimInfo.COLUMN_D2D_STATUS_SHARING, - SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, - SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, - SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED - ); + + Field field = SubscriptionManagerService.class.getDeclaredField( + "DIRECT_ACCESS_SUBSCRIPTION_COLUMNS"); + field.setAccessible(true); + Set accessibleColumns = (Set) field.get(null); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); -- GitLab From 25d70aa8300c47c32e84531268d3cd832c0a74cf Mon Sep 17 00:00:00 2001 From: Terry Huang Date: Mon, 26 Dec 2022 01:39:39 +0000 Subject: [PATCH 308/656] Revert "[Telephony] Add Location Privacy HAL" Revert submission 20513346-LocationPrivacy-HAL Reason for revert: Move feature to Android V Reverted changes: /q/submissionid:20513346-LocationPrivacy-HAL Change-Id: I7177d824ed52da734a3849c7b880190b343767ab --- .../internal/telephony/NetworkIndication.java | 15 --------------- .../internal/telephony/NetworkResponse.java | 16 ---------------- 2 files changed, 31 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index 8d518f0249..a19d4df264 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -25,7 +25,6 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EMERGENCY_NE import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_NETWORK_INITIATED_LOCATION_RESULT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED; @@ -403,20 +402,6 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { new AsyncResult(null, response, null)); } - /** - * Reports the result of the network initiated location request. - * - * @param locationResponseType result of the network initiated location request. - * Define by LocationResponseType. - */ - public void onNetworkInitiatedLocationResult(int indicationType, int locationResponseType) { - mRil.processIndication(HAL_SERVICE_NETWORK, indicationType); - - if (mRil.isLogOrTrace()) { - mRil.unsljLogvRet(RIL_UNSOL_ON_NETWORK_INITIATED_LOCATION_RESULT, locationResponseType); - } - } - @Override public String getInterfaceHash() { return IRadioNetworkIndication.HASH; diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java index 17c07a2fdf..34e3766d36 100644 --- a/src/java/com/android/internal/telephony/NetworkResponse.java +++ b/src/java/com/android/internal/telephony/NetworkResponse.java @@ -499,22 +499,6 @@ public class NetworkResponse extends IRadioNetworkResponse.Stub { RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); } - /** - * @param responseInfo Response info struct containing response type, serial no. and error - */ - public void setLocationPrivacySettingResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo); - } - - /** - * @param responseInfo Response info struct containing response type, serial no. and error. - * @param shareLocation Indicates whether the location sharing is allowed or not. - */ - public void getLocationPrivacySettingResponse( - RadioResponseInfo responseInfo, boolean shareLocation) { - RadioResponse.responseInts(HAL_SERVICE_NETWORK, mRil, responseInfo, shareLocation ? 1 : 0); - } - @Override public String getInterfaceHash() { return IRadioNetworkResponse.HASH; -- GitLab From cd581c20475354c3102d3f7291ba4d81d6476e68 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Fri, 9 Dec 2022 14:12:05 -0800 Subject: [PATCH 309/656] Add SMS and telephonyProperties metrics for work profile Bug: 261776686 Test: sample: https://paste.googleplex.com/5101693573267456 Change-Id: I8b2738d2ee3ef20c4922b18bf723d571e2c06493 --- proto/src/persist_atoms.proto | 2 ++ .../com/android/internal/telephony/Phone.java | 15 +++++++++++ .../telephony/metrics/MetricsCollector.java | 26 ++++++++++--------- .../internal/telephony/metrics/SmsStats.java | 2 ++ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index e33cdda9e6..30ad097851 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -259,6 +259,7 @@ message IncomingSms { optional int32 carrier_id = 13; optional int64 message_id = 14; optional int32 count = 15; + optional bool is_managed_profile = 16; // Internal use only optional int32 hashCode = 10001; @@ -282,6 +283,7 @@ message OutgoingSms { optional int32 count = 15; optional int32 send_error_code = 16; optional int32 network_error_code = 17; + optional bool is_managed_profile = 18; // Internal use only optional int32 hashCode = 10001; diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 6a5b7f55be..e530724705 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -39,6 +39,7 @@ import android.os.RegistrantList; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.UserManager; import android.os.WorkSource; import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; @@ -5134,6 +5135,20 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { : null; } + /** + * Checks if the context user is a managed profile. + * + * Note that this applies specifically to managed profiles. + * + * @return whether the context user is a managed profile. + */ + public boolean isManagedProfile() { + UserHandle userHandle = getUserHandle(); + UserManager userManager = mContext.getSystemService(UserManager.class); + if (userHandle == null || userManager == null) return false; + return userManager.isManagedProfile(userHandle.getIdentifier()); + } + /** * @return global null cipher and integrity enabled preference */ diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 2c90b73f58..360eda8282 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -483,17 +483,17 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { if (phones.length == 0) { return StatsManager.PULL_SKIP; } - boolean isAutoDataSwitchOn = false; - for (Phone phone : phones) { - // only applies to non-DDS - if (phone.getSubId() != SubscriptionManager.getDefaultDataSubscriptionId()) { - isAutoDataSwitchOn = phone.getDataSettingsManager().isMobileDataPolicyEnabled( - TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH); - break; - } - } + boolean isAutoDataSwitchOn = Arrays.stream(phones) + .anyMatch(phone -> + phone.getSubId() != SubscriptionManager.getDefaultDataSubscriptionId() + && phone.getDataSettingsManager().isMobileDataPolicyEnabled( + TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)); + boolean hasDedicatedManagedProfileSub = Arrays.stream(phones) + .anyMatch(Phone::isManagedProfile); + data.add(TelephonyStatsLog.buildStatsEvent(DEVICE_TELEPHONY_PROPERTIES, true, - isAutoDataSwitchOn, mStorage.getAutoDataSwitchToggleCount())); + isAutoDataSwitchOn, mStorage.getAutoDataSwitchToggleCount(), + hasDedicatedManagedProfileSub)); return StatsManager.PULL_SUCCESS; } @@ -816,7 +816,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { sms.isEsim, sms.carrierId, sms.messageId, - sms.count); + sms.count, + sms.isManagedProfile); } private static StatsEvent buildStatsEvent(OutgoingSms sms) { @@ -838,7 +839,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { sms.intervalMillis, sms.count, sms.sendErrorCode, - sms.networkErrorCode); + sms.networkErrorCode, + sms.isManagedProfile); } private static StatsEvent buildStatsEvent(DataCallSession dataCallSession) { diff --git a/src/java/com/android/internal/telephony/metrics/SmsStats.java b/src/java/com/android/internal/telephony/metrics/SmsStats.java index 5e81282881..2f1e6a7182 100644 --- a/src/java/com/android/internal/telephony/metrics/SmsStats.java +++ b/src/java/com/android/internal/telephony/metrics/SmsStats.java @@ -233,6 +233,7 @@ public class SmsStats { // SMS messages (e.g. those handled by OS or error cases). proto.messageId = RANDOM.nextLong(); proto.count = 1; + proto.isManagedProfile = mPhone.isManagedProfile(); return proto; } @@ -258,6 +259,7 @@ public class SmsStats { proto.retryId = 0; proto.intervalMillis = intervalMillis; proto.count = 1; + proto.isManagedProfile = mPhone.isManagedProfile(); return proto; } -- GitLab From da5a075778309cf267a5d993afce7df380784407 Mon Sep 17 00:00:00 2001 From: sparvathy Date: Sat, 17 Dec 2022 18:25:50 +0000 Subject: [PATCH 310/656] Send routing type as unknown in oos For normal routing numbers based on per mnc routing type will be sent as unknown during OOS. As it cannot be decided that ec call should be triggered on emergency or normal. Test: atest EmergencyNumberTest & emergency call test in device Bug: 238359415 Change-Id: I0a8a52510dff6614df182121f388313199f7daff --- .../emergency/EmergencyNumberTracker.java | 44 +++++++-------- .../emergency/EmergencyNumberTrackerTest.java | 53 +++++++++++++++++++ 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 85cc5be2af..9a3e97bbc9 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -510,7 +510,7 @@ public class EmergencyNumberTracker extends Handler { if (((eccInfo.normalRoutingMncs).length != 0) && (eccInfo.normalRoutingMncs[0].length() > 0)) { - emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY; + emergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN; for (String routingMnc : eccInfo.normalRoutingMncs) { boolean mncExist = normalRoutedNumbers.containsKey(routingMnc); @@ -815,16 +815,7 @@ public class EmergencyNumberTracker extends Handler { */ private boolean shouldAdjustForRouting() { if (!shouldEmergencyNumberRoutingFromDbBeIgnored() && !mNormalRoutedNumbers.isEmpty()) { - CellIdentity cellIdentity = mPhone.getCurrentCellIdentity(); - if (cellIdentity != null) { - String networkMnc = cellIdentity.getMncString(); - if (mNormalRoutedNumbers.containsKey(networkMnc)) { - Set phoneNumbers = mNormalRoutedNumbers.get(networkMnc); - if (phoneNumbers != null && !phoneNumbers.isEmpty()) { - return true; - } - } - } + return true; } return false; } @@ -837,16 +828,15 @@ public class EmergencyNumberTracker extends Handler { CellIdentity cellIdentity = mPhone.getCurrentCellIdentity(); if (cellIdentity != null) { String networkMnc = cellIdentity.getMncString(); - Set normalRoutedPhoneNumbers = mNormalRoutedNumbers.get(networkMnc); - if (normalRoutedPhoneNumbers == null || normalRoutedPhoneNumbers.isEmpty()) { - return emergencyNumbers; - } Set normalRoutedPhoneNumbersWithPrefix = new ArraySet(); - for (String num : normalRoutedPhoneNumbers) { - Set phoneNumbersWithPrefix = addPrefixToEmergencyNumber(num); - if (phoneNumbersWithPrefix != null && !phoneNumbersWithPrefix.isEmpty()) { - normalRoutedPhoneNumbersWithPrefix.addAll(phoneNumbersWithPrefix); + + if (normalRoutedPhoneNumbers != null && !normalRoutedPhoneNumbers.isEmpty()) { + for (String num : normalRoutedPhoneNumbers) { + Set phoneNumbersWithPrefix = addPrefixToEmergencyNumber(num); + if (phoneNumbersWithPrefix != null && !phoneNumbersWithPrefix.isEmpty()) { + normalRoutedPhoneNumbersWithPrefix.addAll(phoneNumbersWithPrefix); + } } } List adjustedEmergencyNumberList = new ArrayList<>(); @@ -855,12 +845,16 @@ public class EmergencyNumberTracker extends Handler { for (EmergencyNumber num : emergencyNumbers) { routing = num.getEmergencyCallRouting(); mnc = num.getMnc(); - if (num.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE) - && (normalRoutedPhoneNumbers.contains(num.getNumber()) - || (normalRoutedPhoneNumbersWithPrefix.contains(num.getNumber())))) { - routing = EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL; - mnc = networkMnc; - logd("adjustRoutingForEmergencyNumbers for number" + num.getNumber()); + if (num.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE)) { + if ((normalRoutedPhoneNumbers != null + && normalRoutedPhoneNumbers.contains(num.getNumber())) + || normalRoutedPhoneNumbersWithPrefix.contains(num.getNumber())) { + routing = EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL; + mnc = networkMnc; + logd("adjustRoutingForEmergencyNumbers for number" + num.getNumber()); + } else if (routing == EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN) { + routing = EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY; + } } adjustedEmergencyNumberList.add(new EmergencyNumber(num.getNumber(), num.getCountryIso(), mnc, diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index 6121127acc..c2d0b40e9e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -711,6 +711,59 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { emergencyNumberTrackerMock.getEmergencyNumberList())); } + @Test + public void testUsingEmergencyNumberDatabaseWithRoutingInOOS() { + doReturn(mMockContext).when(mPhone).getContext(); + doReturn(mContext.getAssets()).when(mMockContext).getAssets(); + doReturn(mResources).when(mMockContext).getResources(); + doReturn(false).when(mResources).getBoolean( + com.android.internal.R.bool.ignore_emergency_number_routing_from_db); + + EmergencyNumberTracker emergencyNumberTrackerMock = new EmergencyNumberTracker( + mPhone, mSimulatedCommands); + emergencyNumberTrackerMock.sendMessage( + emergencyNumberTrackerMock.obtainMessage( + 1 /* EVENT_UNSOL_EMERGENCY_NUMBER_LIST */, + new AsyncResult(null, mEmergencyNumberListTestSample, null))); + sendEmergencyNumberPrefix(emergencyNumberTrackerMock); + emergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones("us"); + processAllMessages(); + + // Check routing when cellidentity is null, which is oos + doReturn(null).when(mPhone).getCurrentCellIdentity(); + EmergencyNumber emergencyNumber = new EmergencyNumber( + CONFIG_EMERGENCY_NUMBER_ADDRESS, CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + + // Check routing when cellidentity is 04, which is not part of normal routing mncs + doReturn(mCellIdentity).when(mPhone).getCurrentCellIdentity(); + doReturn("04").when(mCellIdentity).getMncString(); + emergencyNumber = new EmergencyNumber( + CONFIG_EMERGENCY_NUMBER_ADDRESS, CONFIG_EMERGENCY_NUMBER_COUNTRY, + "", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY); + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + + // Check routing when cellidentity is 05, which is part of normal routing mncs + doReturn("05").when(mCellIdentity).getMncString(); + emergencyNumber = new EmergencyNumber( + CONFIG_EMERGENCY_NUMBER_ADDRESS, CONFIG_EMERGENCY_NUMBER_COUNTRY, + "05", CONFIG_EMERGENCY_NUMBER_SERVICE_CATEGORIES, + CONFIG_EMERGENCY_NUMBER_SERVICE_URNS, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + assertTrue(hasDbEmergencyNumber(emergencyNumber, + emergencyNumberTrackerMock.getEmergencyNumberList())); + } + /** * Test OTA Emergency Number Database Update Status. */ -- GitLab From 73b81890f6025a6fbd72cf07d15771dcfd4291ce Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Tue, 3 Jan 2023 22:59:16 +0000 Subject: [PATCH 311/656] Update annotation, constant name, and javadoc of cell broadcast API Bug: 264252000 Test: atest CtsTelephonyTestCases Test: atest com.android.internal.telephony.GsmCdmaPhoneTest Test: atest CellBroadcastReceiverOemUnitTests Change-Id: I1c187dbe91677094c5f0ec68faa2200ae6fe00b7 --- .../telephony/CellBroadcastConfigTracker.java | 15 ++++++++------- .../com/android/internal/telephony/Phone.java | 2 +- .../internal/telephony/GsmCdmaPhoneTest.java | 18 +++++++++--------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java b/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java index d6efaeddd1..32cfdfeb48 100644 --- a/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java +++ b/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java @@ -125,7 +125,8 @@ public final class CellBroadcastConfigTracker extends StateMachine { transitionTo(mCdmaConfiguringState); } else { logd("Do nothing as the requested ranges are same as now"); - request.getCallback().accept(TelephonyManager.CELLBROADCAST_RESULT_SUCCESS); + request.getCallback().accept( + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS); } retVal = HANDLED; break; @@ -167,7 +168,7 @@ public final class CellBroadcastConfigTracker extends StateMachine { } else { logd("Failed to set gsm config"); request.getCallback().accept( - TelephonyManager.CELLBROADCAST_RESULT_FAIL_CONFIG); + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_CONFIG); // transit to idle state on the failure case transitionTo(mIdleState); } @@ -213,14 +214,14 @@ public final class CellBroadcastConfigTracker extends StateMachine { } else { logd("Done as no need to update ranges for 3gpp2"); request.getCallback().accept( - TelephonyManager.CELLBROADCAST_RESULT_SUCCESS); + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS); // transit to idle state if there is no cdma config change transitionTo(mIdleState); } } else { logd("Failed to set gsm activation"); request.getCallback().accept( - TelephonyManager.CELLBROADCAST_RESULT_FAIL_ACTIVATION); + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_ACTIVATION); // transit to idle state on the failure case transitionTo(mIdleState); } @@ -264,7 +265,7 @@ public final class CellBroadcastConfigTracker extends StateMachine { } else { logd("Failed to set cdma config"); request.getCallback().accept( - TelephonyManager.CELLBROADCAST_RESULT_FAIL_CONFIG); + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_CONFIG); // transit to idle state on the failure case transitionTo(mIdleState); } @@ -303,11 +304,11 @@ public final class CellBroadcastConfigTracker extends StateMachine { if (ar.exception == null) { mCbRanges3gpp2 = request.get3gpp2Ranges(); request.getCallback().accept( - TelephonyManager.CELLBROADCAST_RESULT_SUCCESS); + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS); } else { logd("Failed to set cdma activation"); request.getCallback().accept( - TelephonyManager.CELLBROADCAST_RESULT_FAIL_ACTIVATION); + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_ACTIVATION); } // transit to idle state anyway transitionTo(mIdleState); diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 6a5b7f55be..b34a6955c9 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5190,7 +5190,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ public void setCellBroadcastIdRanges( @NonNull List ranges, Consumer callback) { - callback.accept(TelephonyManager.CELLBROADCAST_RESULT_UNSUPPORTED); + callback.accept(TelephonyManager.CELL_BROADCAST_RESULT_UNSUPPORTED); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 7321789262..c7f943a22a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -2255,7 +2255,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.mCi = mMockCi; mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELLBROADCAST_RESULT_SUCCESS == r)); + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); waitForMs(100); verify(mMockCi, times(1)).setGsmBroadcastConfig(gsmCaptor.capture(), msgCaptor.capture()); @@ -2294,7 +2294,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { CdmaSmsBroadcastConfigInfo[].class); mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELLBROADCAST_RESULT_SUCCESS == r)); + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); waitForMs(100); verify(mMockCi, times(1)).setGsmBroadcastConfig(any(), any()); @@ -2322,7 +2322,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // Verify not to set cdma or gsm config as the config is not changed mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELLBROADCAST_RESULT_SUCCESS == r)); + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); waitForMs(100); verify(mMockCi, times(1)).setCdmaBroadcastConfig(any(), any()); @@ -2334,7 +2334,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // Verify to reset ranges with empty ranges list mPhoneUT.setCellBroadcastIdRanges(new ArrayList<>(), r -> assertTrue( - TelephonyManager.CELLBROADCAST_RESULT_SUCCESS == r)); + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); waitForMs(100); @@ -2380,7 +2380,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { //Verify to set gsm and cdma config then activate again mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELLBROADCAST_RESULT_SUCCESS == r)); + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); waitForMs(100); @@ -2443,7 +2443,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // Verify the result on setGsmBroadcastConfig failure mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELLBROADCAST_RESULT_FAIL_CONFIG == r)); + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_CONFIG == r)); waitForMs(100); verify(mMockCi, times(1)).setGsmBroadcastConfig(any(), msgCaptor.capture()); @@ -2461,7 +2461,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // Verify the result on setGsmBroadcastActivation failure mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELLBROADCAST_RESULT_FAIL_ACTIVATION == r)); + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_ACTIVATION == r)); waitForMs(100); verify(mMockCi, times(2)).setGsmBroadcastConfig(any(), msgCaptor.capture()); @@ -2486,7 +2486,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // Verify the result on setCdmaBroadcastConfig failure mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELLBROADCAST_RESULT_FAIL_CONFIG == r)); + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_CONFIG == r)); waitForMs(100); verify(mMockCi, times(3)).setGsmBroadcastConfig(any(), msgCaptor.capture()); @@ -2522,7 +2522,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // Verify the result on setCdmaBroadcastActivation failure mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELLBROADCAST_RESULT_FAIL_ACTIVATION == r)); + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_ACTIVATION == r)); waitForMs(200); // Verify no more calls as there is no change of ranges for 3gpp -- GitLab From 9c185193949cd67e87d172f5ba1f3919e8bb7fc3 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Wed, 4 Jan 2023 23:02:56 +0000 Subject: [PATCH 312/656] Revert "Added SIM events handling and fix crashes" Revert submission 20813798-smsvc_bootup Reason for revert: b/263772382 Reverted changes: /q/submissionid:20813798-smsvc_bootup Change-Id: I3fb32444d6f50dc8ace1276f2998551118832c7f --- .../internal/telephony/PhoneFactory.java | 9 +- .../telephony/ServiceStateTracker.java | 4 +- .../telephony/SubscriptionController.java | 5 +- .../telephony/data/PhoneSwitcher.java | 10 +- .../SubscriptionDatabaseManager.java | 61 +- .../SubscriptionManagerService.java | 520 +++++------------- .../telephony/uicc/UiccController.java | 29 +- .../internal/telephony/uicc/UiccProfile.java | 11 +- .../SubscriptionManagerServiceTest.java | 23 +- 9 files changed, 208 insertions(+), 464 deletions(-) diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index 43aa15434b..cb8f984b0f 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -214,14 +214,9 @@ public class PhoneFactory { TelephonyComponentFactory.getInstance().inject(SubscriptionController.class .getName()).initSubscriptionController(context); } - - SubscriptionController sc = null; - if (!isSubscriptionManagerServiceEnabled()) { - sc = SubscriptionController.getInstance(); - } - TelephonyComponentFactory.getInstance().inject(MultiSimSettingController.class. - getName()).initMultiSimSettingController(context, sc); + getName()).initMultiSimSettingController(context, + SubscriptionController.getInstance()); if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY_EUICC)) { diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 2a76a84eea..9c7178a63d 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -2751,8 +2751,8 @@ public class ServiceStateTracker extends Handler { if (mPhone.isSubscriptionManagerServiceEnabled()) { mSubscriptionManagerService.setCarrierName(mPhone.getSubId(), - TextUtils.emptyIfNull(getCarrierName(data.shouldShowPlmn(), data.getPlmn(), - data.shouldShowSpn(), data.getSpn()))); + getCarrierName(data.shouldShowPlmn(), data.getPlmn(), + data.shouldShowSpn(), data.getSpn())); } else { if (!mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), data.shouldShowPlmn(), data.getPlmn(), data.shouldShowSpn(), diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 46a067e9c5..ab519bbf2b 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -331,11 +331,8 @@ public class SubscriptionController extends ISub.Stub { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static SubscriptionController getInstance() { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - throw new RuntimeException("getInstance should not be called."); - } if (sInstance == null) { - Log.wtf(LOG_TAG, "getInstance null"); + Log.wtf(LOG_TAG, "getInstance null"); } return sInstance; diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index fe63ada5a8..1eb07aa4fb 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -531,14 +531,8 @@ public class PhoneSwitcher extends Handler { mMaxDataAttachModemCount = maxActivePhones; mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService = SubscriptionManagerService.getInstance(); - mSubscriptionController = null; - } else { - mSubscriptionController = SubscriptionController.getInstance(); - mSubscriptionManagerService = null; - } - + mSubscriptionController = SubscriptionController.getInstance(); + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); mRadioConfig = RadioConfig.getInstance(); mValidator = CellularNetworkValidator.getInstance(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 199d2d4f30..501d4f0cc5 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -39,7 +39,6 @@ import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyManager; -import android.telephony.UiccAccessRule; import android.telephony.ims.ImsMmTelManager; import android.text.TextUtils; import android.util.Base64; @@ -563,7 +562,6 @@ public class SubscriptionDatabaseManager extends Handler { public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper, @NonNull SubscriptionDatabaseManagerCallback callback) { super(looper); - log("Created SubscriptionDatabaseManager."); mContext = context; mCallback = callback; mUiccController = UiccController.getInstance(); @@ -686,8 +684,6 @@ public class SubscriptionDatabaseManager extends Handler { for (String columnName : Telephony.SimInfo.getAllColumns()) { if (DEPRECATED_DATABASE_COLUMNS.contains(columnName)) continue; - // subId is generated by the database. Cannot be updated. - if (columnName.equals(SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID)) continue; Object newValue = getSubscriptionInfoFieldByColumnName(newSubInfo, columnName); if (newValue != null) { Object oldValue = null; @@ -716,16 +712,13 @@ public class SubscriptionDatabaseManager extends Handler { Objects.requireNonNull(contentValues); Uri uri = mContext.getContentResolver().insert(SimInfo.CONTENT_URI, contentValues); if (uri != null && uri.getLastPathSegment() != null) { - int subId = Integer.parseInt(uri.getLastPathSegment()); - if (SubscriptionManager.isValidSubscriptionId(subId)) { - logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" - + uri.getLastPathSegment()); - return subId; - } + logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" + + uri.getLastPathSegment()); + return Integer.parseInt(uri.getLastPathSegment()); + } else { + logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " + + "contentValues=" + contentValues); } - - logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " - + "contentValues=" + contentValues); return INVALID_ROW_INDEX; } @@ -882,8 +875,6 @@ public class SubscriptionDatabaseManager extends Handler { // Check if the new value is different from the old value in the cache. if (!Objects.equals(getSubscriptionInfoFieldByColumnName(subInfo, columnName), newValue)) { - logv("writeDatabaseAndCacheHelper: subId=" + subId + ",columnName=" - + columnName + ", newValue=" + newValue); // If the value is different, then we need to update the cache. Since all // fields in SubscriptionInfo are final, we need to create a new // SubscriptionInfo. @@ -1219,24 +1210,6 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules); } - /** - * Set the carrier certificates for this subscription that are saved in carrier configs. - * This does not include access rules from the Uicc, whether embedded or non-embedded. - * - * @param subId Subscription id. - * @param carrierConfigAccessRules The carrier certificates for this subscription. - * - * @throws IllegalArgumentException if the subscription does not exist. - */ - public void setCarrierConfigAccessRules(int subId, - @NonNull UiccAccessRule[] carrierConfigAccessRules) { - Objects.requireNonNull(carrierConfigAccessRules); - byte[] carrierConfigAccessRulesBytes = UiccAccessRule.encodeRules(carrierConfigAccessRules); - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, - carrierConfigAccessRulesBytes, - SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules); - } - /** * Set whether an embedded subscription is on a removable card. Such subscriptions are * marked inaccessible as soon as the current card is removed. Otherwise, they will remain @@ -1788,23 +1761,11 @@ public class SubscriptionDatabaseManager extends Handler { // publicCardId is the publicly exposed int card ID int publicCardId = mUiccController.convertToPublicCardId(cardString); - byte[] rules = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_ACCESS_RULES)); - if (rules != null) { - builder.setNativeAccessRules(rules); - } - - rules = cursor.getBlob(cursor.getColumnIndexOrThrow( - SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS)); - if (rules != null) { - builder.setCarrierConfigAccessRules(rules); - } - - byte[] config = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_RCS_CONFIG)); - if (config != null) { - builder.setRcsConfig(config); - } - builder.setCardId(publicCardId) + .setNativeAccessRules(cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ACCESS_RULES))) + .setCarrierConfigAccessRules(cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS))) .setRemovableEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_IS_REMOVABLE))) .setEnhanced4GModeEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( @@ -1844,6 +1805,8 @@ public class SubscriptionDatabaseManager extends Handler { SimInfo.COLUMN_IMS_RCS_UCE_ENABLED))) .setCrossSimCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED))) + .setRcsConfig(cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_RCS_CONFIG))) .setAllowedNetworkTypesForReasons(TextUtils.emptyIfNull( cursor.getString(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS)))) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 2555fd1c6d..d3793e2caa 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -37,7 +37,6 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.ParcelUuid; -import android.os.PersistableBundle; import android.os.RemoteException; import android.os.TelephonyServiceManager; import android.os.UserHandle; @@ -76,7 +75,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CarrierResolver; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; -import com.android.internal.telephony.IccCard; import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; @@ -86,9 +84,7 @@ import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; -import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccController; -import com.android.internal.telephony.uicc.UiccPort; import com.android.internal.telephony.uicc.UiccSlot; import com.android.internal.telephony.util.ArrayUtils; import com.android.telephony.Rlog; @@ -141,7 +137,6 @@ public class SubscriptionManagerService extends ISub.Stub { SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, SimInfo.COLUMN_RCS_CONFIG, - SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, SimInfo.COLUMN_D2D_STATUS_SHARING, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, @@ -235,10 +230,6 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull private final WatchedInt mDefaultSmsSubId; - /** Sim state per logical SIM slot index. */ - @NonNull - private final int[] mSimState; - /** * Watched map that automatically invalidate cache in {@link SubscriptionManager}. */ @@ -272,7 +263,7 @@ public class SubscriptionManagerService extends ISub.Stub { * Watched integer. */ public static class WatchedInt { - protected int mValue; + private int mValue; /** * Constructor. @@ -386,9 +377,7 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { - int oldValue = mValue; if (super.set(newValue)) { - logl("Default voice sub changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, newValue); return true; @@ -402,9 +391,7 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { - int oldValue = mValue; if (super.set(newValue)) { - logl("Default data sub changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, newValue); return true; @@ -418,9 +405,7 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { - int oldValue = mValue; if (super.set(newValue)) { - logl("Default voice sms changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, newValue); return true; @@ -431,9 +416,6 @@ public class SubscriptionManagerService extends ISub.Stub { mDefaultSubId = new WatchedInt(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mSimState = new int[mTelephonyManager.getSupportedModemCount()]; - Arrays.fill(mSimState, TelephonyManager.SIM_STATE_UNKNOWN); - // Create a separate thread for subscription database manager. The database will be updated // from a different thread. HandlerThread handlerThread = new HandlerThread(LOG_TAG); @@ -1008,292 +990,13 @@ public class SubscriptionManagerService extends ISub.Stub { } } - /** - * Check if the SIM application is enabled on the card or not. - * - * @param phoneId The phone id. - * - * @return {@code true} if the application is enabled. - */ - public boolean areUiccAppsEnabledOnCard(int phoneId) { - // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from - // cardStatus (since IRadio 1.2). And upon cardStatus change we'll receive another - // handleSimNotReady so this will be evaluated again. - UiccSlot slot = mUiccController.getUiccSlotForPhone(phoneId); - if (slot == null) return false; - UiccPort port = mUiccController.getUiccPort(phoneId); - String iccId = (port == null) ? null : port.getIccId(); - if (iccId == null) { - return false; - } - - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager - .getSubscriptionInfoInternalByIccId(IccUtils.stripTrailingFs(iccId)); - return subInfo != null && subInfo.areUiccApplicationsEnabled(); - } - - /** - * Get ICCID by phone id. - * - * @param phoneId The phone id (i.e. Logical SIM slot index.) - * - * @return The ICCID. Empty string if not available. - */ - @NonNull - private String getIccId(int phoneId) { - UiccPort port = mUiccController.getUiccPort(phoneId); - return (port == null) ? "" : TextUtils.emptyIfNull( - IccUtils.stripTrailingFs(port.getIccId())); - } - /** * Update the subscriptions on the logical SIM slot index (i.e. phone id). * - * @param phoneId The phone id (i.e. Logical SIM slot index) - */ - private void updateSubscriptions(int phoneId) { - int simState = mSimState[phoneId]; - log("updateSubscriptions: phoneId=" + phoneId + ", simState=" - + TelephonyManager.simStateToString(simState)); - if (simState == TelephonyManager.SIM_STATE_ABSENT) { - if (mSlotIndexToSubId.containsKey(phoneId)) { - // Re-enable the SIM when it's removed, so it will be in enabled state when it gets - // re-inserted again. (pre-U behavior) - mSubscriptionDatabaseManager.setUiccApplicationsEnabled( - mSlotIndexToSubId.get(phoneId), true); - // When sim is absent, set the port index to invalid port index. (pre-U behavior) - mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(phoneId), - TelephonyManager.INVALID_PORT_INDEX); - } - } else if (simState == TelephonyManager.SIM_STATE_NOT_READY) { - // Check if this is the final state. Only update the subscription if NOT_READY is a - // final state. - IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); - if (!iccCard.isEmptyProfile() && areUiccAppsEnabledOnCard(phoneId)) { - log("updateSubscriptions: SIM_STATE_NOT_READY is not a final state. Will update " - + "subscription later."); - return; - } - } - - String iccId = getIccId(phoneId); - // Loop through all the subscriptions. If we found any ICCID matched, apply the right - // logical index to that. - int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - for (SubscriptionInfoInternal subInfo - : mSubscriptionDatabaseManager.getAllSubscriptions()) { - int simSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - if (!TextUtils.isEmpty(iccId) && subInfo.getIccId().equals(iccId)) { - subId = subInfo.getSubscriptionId(); - simSlotIndex = phoneId; - mSlotIndexToSubId.put(simSlotIndex, subId); - logl("updateSubscriptions: Found sub " + subInfo.getSubscriptionId() - + ", phoneId=" + phoneId); - } - mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), simSlotIndex); - } - - if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - logl("updateSubscriptions: Did not find any subscription. phoneId=" + phoneId); - mSlotIndexToSubId.remove(phoneId); - } - - if (!TextUtils.isEmpty(iccId)) { - // Check if the subscription already existed. - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager - .getSubscriptionInfoInternalByIccId(iccId); - if (subInfo == null) { - // This is a new SIM card. Insert a new record. - subId = mSubscriptionDatabaseManager.insertSubscriptionInfo( - new SubscriptionInfoInternal.Builder() - .setIccId(iccId) - .setSimSlotIndex(phoneId) - .build()); - logl("updateSubscriptions: Inserted a new subscription. subId=" + subId - + ", phoneId=" + phoneId); - } else { - subId = subInfo.getSubscriptionId(); - } - - // Update the SIM slot index. This will make the subscription active. - mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId); - - // Update the card id. - UiccCard card = mUiccController.getUiccCardForPhone(phoneId); - if (card != null) { - String cardId = card.getCardId(); - if (cardId != null) { - mSubscriptionDatabaseManager.setCardString(subId, cardId); - } - } - - // Update the port index. - UiccSlot slot = mUiccController.getUiccSlotForPhone(phoneId); - if (slot != null && !slot.isEuicc()) { - int portIndex = slot.getPortIndexFromIccId(iccId); - mSubscriptionDatabaseManager.setPortIndex(subId, portIndex); - } - } - - updateDefaultSubIds(); - } - - /** - * Calculate the usage setting based on the carrier request. - * - * @param currentUsageSetting the current setting in the subscription DB. - * @param preferredUsageSetting provided by the carrier config. - * - * @return the calculated usage setting. - */ - @VisibleForTesting - @UsageSetting public int calculateUsageSetting(@UsageSetting int currentUsageSetting, - @UsageSetting int preferredUsageSetting) { - int[] supportedUsageSettings; - - // Load the resources to provide the device capability - try { - supportedUsageSettings = mContext.getResources().getIntArray( - com.android.internal.R.array.config_supported_cellular_usage_settings); - // If usage settings are not supported, return the default setting, which is UNKNOWN. - if (supportedUsageSettings == null - || supportedUsageSettings.length < 1) return currentUsageSetting; - } catch (Resources.NotFoundException nfe) { - loge("calculateUsageSetting: Failed to load usage setting resources!"); - return currentUsageSetting; - } - - // If the current setting is invalid, including the first time the value is set, - // update it to default (this will trigger a change in the DB). - if (currentUsageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT - || currentUsageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { - log("calculateUsageSetting: Updating usage setting for current subscription"); - currentUsageSetting = SubscriptionManager.USAGE_SETTING_DEFAULT; - } - - // Range check the inputs, and on failure, make no changes - if (preferredUsageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT - || preferredUsageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { - loge("calculateUsageSetting: Invalid usage setting!" + preferredUsageSetting); - return currentUsageSetting; - } - - // Default is always allowed - if (preferredUsageSetting == SubscriptionManager.USAGE_SETTING_DEFAULT) { - return preferredUsageSetting; - } - - // Forced setting must be explicitly supported - for (int supportedUsageSetting : supportedUsageSettings) { - if (preferredUsageSetting == supportedUsageSetting) return preferredUsageSetting; - } - - // If the preferred setting is not possible, just keep the current setting. - return currentUsageSetting; - } - - /** - * Called by CarrierConfigLoader to update the subscription before sending a broadcast. + * @param slotIndex The logical SIM slot index. */ - public void updateSubscriptionByCarrierConfig(int phoneId, @NonNull String configPackageName, - @NonNull PersistableBundle config, @NonNull Runnable callback) { - mHandler.post(() -> { - updateSubscriptionByCarrierConfigInternal(phoneId, configPackageName, config); - callback.run(); - }); - } - - private void updateSubscriptionByCarrierConfigInternal(int phoneId, - @NonNull String configPackageName, @NonNull PersistableBundle config) { - log("updateSubscriptionByCarrierConfig: phoneId=" + phoneId + ", configPackageName=" - + configPackageName); - if (!SubscriptionManager.isValidPhoneId(phoneId) - || TextUtils.isEmpty(configPackageName) || config == null) { - loge("updateSubscriptionByCarrierConfig: Failed to update the subscription. phoneId=" - + phoneId + " configPackageName=" + configPackageName + " config=" - + ((config == null) ? "null" : config.hashCode())); - return; - } - - if (!mSlotIndexToSubId.containsKey(phoneId)) { - log("updateSubscriptionByCarrierConfig: No subscription is active for phone being " - + "updated."); - return; - } - - int subId = mSlotIndexToSubId.get(phoneId); + private void updateSubscriptions(int slotIndex) { - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager - .getSubscriptionInfoInternal(subId); - if (subInfo == null) { - loge("updateSubscriptionByCarrierConfig: Couldn't retrieve subscription info for " - + "current subscription. subId=" + subId); - return; - } - - ParcelUuid groupUuid; - - // carrier certificates are not subscription-specific, so we want to load them even if - // this current package is not a CarrierServicePackage - String[] certs = config.getStringArray( - CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY); - UiccAccessRule[] carrierConfigAccessRules = UiccAccessRule.decodeRulesFromCarrierConfig( - certs); - if (carrierConfigAccessRules != null) { - mSubscriptionDatabaseManager.setCarrierConfigAccessRules( - subId, carrierConfigAccessRules); - } - - boolean isOpportunistic = config.getBoolean( - CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, - subInfo.isOpportunistic()); - mSubscriptionDatabaseManager.setOpportunistic(subId, isOpportunistic); - - String groupUuidString = config.getString( - CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, ""); - String oldGroupUuidString = subInfo.getGroupUuid(); - if (!TextUtils.isEmpty(groupUuidString)) { - try { - // Update via a UUID Structure to ensure consistent formatting - groupUuid = ParcelUuid.fromString(groupUuidString); - if (groupUuidString.equals(CarrierConfigManager.REMOVE_GROUP_UUID_STRING)) { - // Remove the group UUID. - mSubscriptionDatabaseManager.setGroupUuid(subId, ""); - } else if (canPackageManageGroup(groupUuid, configPackageName)) { - mSubscriptionDatabaseManager.setGroupUuid(subId, groupUuidString); - mSubscriptionDatabaseManager.setGroupOwner(subId, configPackageName); - log("updateSubscriptionByCarrierConfig: Group added for sub " + subId); - } else { - loge("updateSubscriptionByCarrierConfig: configPackageName " - + configPackageName + " doesn't own groupUuid " + groupUuid); - } - - if (!groupUuidString.equals(oldGroupUuidString)) { - MultiSimSettingController.getInstance() - .notifySubscriptionGroupChanged(groupUuid); - } - } catch (IllegalArgumentException e) { - loge("updateSubscriptionByCarrierConfig: Invalid Group UUID=" - + groupUuidString); - } - } - - final int preferredUsageSetting = config.getInt( - CarrierConfigManager.KEY_CELLULAR_USAGE_SETTING_INT, - SubscriptionManager.USAGE_SETTING_UNKNOWN); - - int newUsageSetting = calculateUsageSetting( - subInfo.getUsageSetting(), preferredUsageSetting); - - if (newUsageSetting != subInfo.getUsageSetting()) { - mSubscriptionDatabaseManager.setUsageSetting(subId, newUsageSetting); - log("updateSubscriptionByCarrierConfig: UsageSetting changed," - + " oldSetting=" + SubscriptionManager.usageSettingToString( - subInfo.getUsageSetting()) - + " preferredSetting=" + SubscriptionManager.usageSettingToString( - preferredUsageSetting) - + " newSetting=" + SubscriptionManager.usageSettingToString(newUsageSetting)); - } } /** @@ -1341,20 +1044,26 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full - // list. Carrier apps can only get the subscriptions they have privileged. - .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( - mContext, subInfo.getSubscriptionId(), callingPackage, callingFeatureId, - "getAllSubInfoList")) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getAllSubInfoList")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); + final long identity = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full + // list. Carrier apps can only get the subscriptions they have privileged. + .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( + mContext, subInfo.getSubscriptionId(), callingPackage, callingFeatureId, + "getAllSubInfoList")) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getAllSubInfoList")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); + + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1517,16 +1226,22 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(SubscriptionInfoInternal::isActive) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getAllSubInfoList")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); + final long identity = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isActive) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getAllSubInfoList")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); + + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1570,7 +1285,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int getActiveSubInfoCountMax() { - return mTelephonyManager.getActiveModemCount(); + return mTelephonyManager.getSimCount(); } /** @@ -2142,21 +1857,26 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full - // list. Carrier apps can only get the subscriptions they have privileged. - .filter(subInfo -> subInfo.isOpportunistic() - && TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( - mContext, subInfo.getSubscriptionId(), callingPackage, - callingFeatureId, "getOpportunisticSubscriptions")) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getOpportunisticSubscriptions")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); + final long identity = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full + // list. Carrier apps can only get the subscriptions they have privileged. + .filter(subInfo -> subInfo.isOpportunistic() + && TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( + mContext, subInfo.getSubscriptionId(), callingPackage, + callingFeatureId, "getOpportunisticSubscriptions")) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getOpportunisticSubscriptions")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -2411,32 +2131,6 @@ public class SubscriptionManagerService extends ISub.Stub { return new int[]{getSubId(slotIndex)}; } - /** - * Update default voice, sms, and data sub id. - */ - private void updateDefaultSubIds() { - if (getActiveSubInfoCountMax() == 0) { - mDefaultVoiceSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mDefaultSmsSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mDefaultDataSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - } - if (getActiveSubInfoCountMax() == 1) { - int[] activeSubIds = getActiveSubIdList(false); - if (activeSubIds.length == 1) { - mDefaultVoiceSubId.set(activeSubIds[0]); - mDefaultSmsSubId.set(activeSubIds[0]); - mDefaultDataSubId.set(activeSubIds[0]); - } else { - loge("updateDefaultSubIds: Single SIM device, but active subs are more than one." - + " activeSubIds=" + Arrays.toString(activeSubIds)); - } - } else { - // TODO: Support dual sim - } - - updateDefaultSubId(); - } - /** * Update default sub id. */ @@ -2657,12 +2351,9 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { - return mSlotIndexToSubId.values().stream() - .filter(subId -> { - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager - .getSubscriptionInfoInternal(subId); - return subInfo != null && (!visibleOnly || subInfo.isVisible()); }) - .mapToInt(x -> x) + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(subInfo -> subInfo.isActive() && (!visibleOnly || subInfo.isVisible())) + .mapToInt(SubscriptionInfoInternal::getSubscriptionId) .toArray(); } finally { Binder.restoreCallingIdentity(token); @@ -2867,6 +2558,9 @@ public class SubscriptionManagerService extends ISub.Stub { }) public boolean isActiveSubId(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); + if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "isActiveSubId")) { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " @@ -3399,6 +3093,68 @@ public class SubscriptionManagerService extends ISub.Stub { ? subscriptionInfoInternal.toSubscriptionInfo() : null; } + /** + * Called when SIM state changed to absent. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimAbsent(int slotIndex) { + if (mSlotIndexToSubId.containsKey(slotIndex)) { + // Re-enable the SIM when it's removed, so it will be in enabled state when it gets + // re-inserted again. (pre-U behavior) + mSubscriptionDatabaseManager.setUiccApplicationsEnabled( + mSlotIndexToSubId.get(slotIndex), true); + // When sim is absent, set the port index to invalid port index. (pre-U behavior) + mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(slotIndex), + TelephonyManager.INVALID_PORT_INDEX); + } + updateSubscriptions(slotIndex); + } + + /** + * Called when SIM state changed to locked. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimLocked(int slotIndex) { + + } + + /** + * Called when SIM state changed to ready. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimReady(int slotIndex) { + + } + + /** + * Called when SIM state changed to not ready. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimNotReady(int slotIndex) { + + } + + /** + * Called when SIM encounters error. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimError(int slotIndex) { + + } + + /** + * Called when SIM state changed to loaded. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimLoaded(int slotIndex) { + } + /** * Called when eSIM becomes inactive. * @@ -3430,24 +3186,34 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable @CallbackExecutor Executor executor, @Nullable Runnable updateCompleteCallback) { mHandler.post(() -> { - mSimState[slotIndex] = simState; switch (simState) { case TelephonyManager.SIM_STATE_ABSENT: + onSimAbsent(slotIndex); + break; case TelephonyManager.SIM_STATE_PIN_REQUIRED: case TelephonyManager.SIM_STATE_PUK_REQUIRED: case TelephonyManager.SIM_STATE_NETWORK_LOCKED: case TelephonyManager.SIM_STATE_PERM_DISABLED: + onSimLocked(slotIndex); + break; case TelephonyManager.SIM_STATE_READY: - case TelephonyManager.SIM_STATE_CARD_IO_ERROR: - case TelephonyManager.SIM_STATE_LOADED: + onSimReady(slotIndex); + break; case TelephonyManager.SIM_STATE_NOT_READY: - updateSubscriptions(slotIndex); + onSimNotReady(slotIndex); + break; + case TelephonyManager.SIM_STATE_CARD_IO_ERROR: + onSimError(slotIndex); break; case TelephonyManager.SIM_STATE_CARD_RESTRICTED: - default: // No specific things needed to be done. Just return and broadcast the SIM // states. break; + case TelephonyManager.SIM_STATE_LOADED: + onSimLoaded(slotIndex); + break; + default: + break; } if (executor != null && updateCompleteCallback != null) { executor.execute(updateCompleteCallback); diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index f88aa7d1ed..1ad7ee35f6 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -40,6 +40,7 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.SimState; @@ -949,6 +950,31 @@ public class UiccController extends Handler { mCarrierServiceBindHelper.updateSimState(phoneId, simState); } + /** + * Check if the SIM application is enabled on the card or not. + * + * @param phoneId The phone id. + * @return {@code true} if the application is enabled. + */ + private boolean areUiccAppsEnabledOnCard(int phoneId) { + // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from + // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another + // handleSimNotReady so this will be evaluated again. + UiccSlot slot = getUiccSlotForPhone(phoneId); + if (slot == null) return false; + UiccPort port = getUiccPort(phoneId); + String iccId = (port == null) ? null : port.getIccId(); + if (iccId == null) { + return false; + } + SubscriptionInfo info = SubscriptionManagerService.getInstance() + .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) + .stream().filter(subInfo -> subInfo.getIccId().equals( + IccUtils.stripTrailingFs(iccId))) + .findFirst().orElse(null); + return info != null && info.areUiccApplicationsEnabled(); + } + /** * Update the SIM state. * @@ -985,8 +1011,7 @@ public class UiccController extends Handler { if (simState == TelephonyManager.SIM_STATE_NOT_READY && (uiccProfile != null && !uiccProfile.isEmptyProfile()) - && SubscriptionManagerService.getInstance() - .areUiccAppsEnabledOnCard(phoneId)) { + && areUiccAppsEnabledOnCard(phoneId)) { // STATE_NOT_READY is not a final state for when both // 1) It's not an empty profile, and // 2) Its uicc applications are set to enabled. diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index 11f6738652..d9ff3f15d6 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -527,15 +527,8 @@ public class UiccProfile extends IccCard { private void updateCarrierNameForSubscription(int subId, int nameSource) { /* update display name with carrier override */ - SubscriptionInfo subInfo; - - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - subInfo = SubscriptionManagerService.getInstance().getActiveSubscriptionInfo(subId, - mContext.getOpPackageName(), mContext.getAttributionTag()); - } else { - subInfo = SubscriptionController.getInstance().getActiveSubscriptionInfo( - subId, mContext.getOpPackageName(), mContext.getAttributionTag()); - } + SubscriptionInfo subInfo = SubscriptionController.getInstance().getActiveSubscriptionInfo( + subId, mContext.getOpPackageName(), mContext.getAttributionTag()); if (subInfo == null) { return; 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 8eee9a601b..109d5e40c7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -1522,13 +1522,24 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { } @Test - public void testGetNonAccessibleFields() throws Exception { + public void testGetNonAccessibleFields() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); - - Field field = SubscriptionManagerService.class.getDeclaredField( - "DIRECT_ACCESS_SUBSCRIPTION_COLUMNS"); - field.setAccessible(true); - Set accessibleColumns = (Set) field.get(null); + Set accessibleColumns = Set.of( + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, + SimInfo.COLUMN_VT_IMS_ENABLED, + SimInfo.COLUMN_WFC_IMS_ENABLED, + SimInfo.COLUMN_WFC_IMS_MODE, + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, + SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, + SimInfo.COLUMN_RCS_CONFIG, + SimInfo.COLUMN_D2D_STATUS_SHARING, + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED + ); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); -- GitLab From a26d3ea0d2b0955b5f1752d6aea91735eb83a6b7 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Wed, 4 Jan 2023 23:05:27 +0000 Subject: [PATCH 313/656] Revert "Moved SIM state broadcast back to UiccController" This reverts commit dc1f5286d3872b807c95900cc40c3eb61b37230d. Reason for revert: b/263772382 Change-Id: I8a1e3e1934f6b66ee6dd14c4373efb44daf64dc9 --- .../telephony/CarrierServiceBindHelper.java | 9 +- .../telephony/SubscriptionInfoUpdater.java | 2 +- .../SubscriptionManagerService.java | 144 +------- .../telephony/uicc/UiccController.java | 342 +----------------- .../internal/telephony/uicc/UiccProfile.java | 4 +- .../internal/telephony/uicc/UiccSlot.java | 10 +- .../internal/telephony/uicc/UiccSlotTest.java | 23 +- 7 files changed, 44 insertions(+), 490 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java index 035714e5bc..dfa53b3958 100644 --- a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java +++ b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java @@ -16,7 +16,6 @@ package com.android.internal.telephony; -import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -201,13 +200,7 @@ public class CarrierServiceBindHelper { } } - /** - * Update SIM state. - * - * @param phoneId The phone id. - * @param simState The legacy SIM state. - */ - public void updateSimState(int phoneId, @NonNull String simState) { + void updateForPhoneId(int phoneId, String simState) { logdWithLocalLog("update binding for phoneId: " + phoneId + " simState: " + simState); if (!SubscriptionManager.isValidPhoneId(phoneId)) { return; diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index fa52db5012..1681d140b7 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -700,7 +700,7 @@ public class SubscriptionInfoUpdater extends Handler { CarrierConfigManager configManager = (CarrierConfigManager) sContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); configManager.updateConfigForPhoneId(phoneId, simState); - mCarrierServiceBindHelper.updateSimState(phoneId, simState); + mCarrierServiceBindHelper.updateForPhoneId(phoneId, simState); } private void updateSubscriptionCarrierId(int phoneId, String simState) { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index d3793e2caa..9ea34f60f8 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -59,7 +59,6 @@ import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.SimState; import android.telephony.TelephonyRegistryManager; import android.telephony.UiccAccessRule; import android.telephony.euicc.EuiccManager; @@ -428,10 +427,6 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public void onDatabaseLoaded() { log("Subscription database has been loaded."); - for (int phoneId = 0; phoneId < mTelephonyManager.getActiveModemCount() - ; phoneId++) { - markSubscriptionsInactive(phoneId); - } } /** @@ -831,7 +826,7 @@ public class SubscriptionManagerService extends ISub.Stub { /** * Mark all subscriptions on this SIM slot index inactive. * - * @param simSlotIndex The logical SIM slot index (i.e. phone id). + * @param simSlotIndex The SIM slot index. */ public void markSubscriptionsInactive(int simSlotIndex) { mSubscriptionDatabaseManager.getAllSubscriptions().stream() @@ -990,15 +985,6 @@ public class SubscriptionManagerService extends ISub.Stub { } } - /** - * Update the subscriptions on the logical SIM slot index (i.e. phone id). - * - * @param slotIndex The logical SIM slot index. - */ - private void updateSubscriptions(int slotIndex) { - - } - /** * Get all subscription info records from SIMs that are inserted now or previously inserted. * @@ -3093,134 +3079,6 @@ public class SubscriptionManagerService extends ISub.Stub { ? subscriptionInfoInternal.toSubscriptionInfo() : null; } - /** - * Called when SIM state changed to absent. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimAbsent(int slotIndex) { - if (mSlotIndexToSubId.containsKey(slotIndex)) { - // Re-enable the SIM when it's removed, so it will be in enabled state when it gets - // re-inserted again. (pre-U behavior) - mSubscriptionDatabaseManager.setUiccApplicationsEnabled( - mSlotIndexToSubId.get(slotIndex), true); - // When sim is absent, set the port index to invalid port index. (pre-U behavior) - mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(slotIndex), - TelephonyManager.INVALID_PORT_INDEX); - } - updateSubscriptions(slotIndex); - } - - /** - * Called when SIM state changed to locked. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimLocked(int slotIndex) { - - } - - /** - * Called when SIM state changed to ready. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimReady(int slotIndex) { - - } - - /** - * Called when SIM state changed to not ready. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimNotReady(int slotIndex) { - - } - - /** - * Called when SIM encounters error. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimError(int slotIndex) { - - } - - /** - * Called when SIM state changed to loaded. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimLoaded(int slotIndex) { - } - - /** - * Called when eSIM becomes inactive. - * - * @param slotIndex The logical SIM slot index. - */ - public void updateSimStateForInactivePort(int slotIndex) { - mHandler.post(() -> { - if (mSlotIndexToSubId.containsKey(slotIndex)) { - // Re-enable the UICC application , so it will be in enabled state when it becomes - // active again. (pre-U behavior) - mSubscriptionDatabaseManager.setUiccApplicationsEnabled( - mSlotIndexToSubId.get(slotIndex), true); - updateSubscriptions(slotIndex); - } - }); - } - - /** - * Update SIM state. This method is supposed to be called by {@link UiccController} only. - * - * @param slotIndex The logical SIM slot index. - * @param simState SIM state. - * @param executor The executor to execute the callback. - * @param updateCompleteCallback The callback to call when subscription manager service - * completes subscription update. SIM state changed event will be broadcasted by - * {@link UiccController} upon receiving callback. - */ - public void updateSimState(int slotIndex, @SimState int simState, - @Nullable @CallbackExecutor Executor executor, - @Nullable Runnable updateCompleteCallback) { - mHandler.post(() -> { - switch (simState) { - case TelephonyManager.SIM_STATE_ABSENT: - onSimAbsent(slotIndex); - break; - case TelephonyManager.SIM_STATE_PIN_REQUIRED: - case TelephonyManager.SIM_STATE_PUK_REQUIRED: - case TelephonyManager.SIM_STATE_NETWORK_LOCKED: - case TelephonyManager.SIM_STATE_PERM_DISABLED: - onSimLocked(slotIndex); - break; - case TelephonyManager.SIM_STATE_READY: - onSimReady(slotIndex); - break; - case TelephonyManager.SIM_STATE_NOT_READY: - onSimNotReady(slotIndex); - break; - case TelephonyManager.SIM_STATE_CARD_IO_ERROR: - onSimError(slotIndex); - break; - case TelephonyManager.SIM_STATE_CARD_RESTRICTED: - // No specific things needed to be done. Just return and broadcast the SIM - // states. - break; - case TelephonyManager.SIM_STATE_LOADED: - onSimLoaded(slotIndex); - break; - default: - break; - } - if (executor != null && updateCompleteCallback != null) { - executor.execute(updateCompleteCallback); - } - }); - } - /** * Log debug messages. * diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 1ad7ee35f6..ea99d9a3f6 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -21,8 +21,6 @@ import static android.telephony.TelephonyManager.UNSUPPORTED_CARD_ID; import static java.util.Arrays.copyOf; -import android.Manifest; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.BroadcastOptions; import android.compat.annotation.UnsupportedAppUsage; @@ -40,10 +38,8 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.SimState; import android.telephony.UiccCardInfo; import android.telephony.UiccPortInfo; import android.telephony.UiccSlotMapping; @@ -53,20 +49,14 @@ import android.util.LocalLog; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.CarrierServiceBindHelper; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccCardConstants; -import com.android.internal.telephony.IntentBroadcaster; import com.android.internal.telephony.PhoneConfigurationManager; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.SubscriptionInfoUpdater; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.metrics.TelephonyMetrics; -import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.euicc.EuiccCard; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -150,9 +140,6 @@ public class UiccController extends Handler { private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 10; // NOTE: any new EVENT_* values must be added to eventToString. - @NonNull - private final TelephonyManager mTelephonyManager; - // this needs to be here, because on bootup we dont know which index maps to which UiccSlot @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private CommandsInterface[] mCis; @@ -164,25 +151,11 @@ public class UiccController extends Handler { // This maps the externally exposed card ID (int) to the internal card ID string (ICCID/EID). // The array index is the card ID (int). // This mapping exists to expose card-based functionality without exposing the EID, which is - // considered sensitive information. + // considered sensetive information. // mCardStrings is populated using values from the IccSlotStatus and IccCardStatus. For // HAL < 1.2, these do not contain the EID or the ICCID, so mCardStrings will be empty private ArrayList mCardStrings; - /** - * SIM card state. - */ - @NonNull - @SimState - private final int[] mSimCardState; - - /** - * SIM application state. - */ - @NonNull - @SimState - private final int[] mSimApplicationState; - // This is the card ID of the default eUICC. It starts as UNINITIALIZED_CARD_ID. // When we load the EID (either with slot status or from the EuiccCard), we set it to the eUICC // with the lowest slot index. @@ -232,9 +205,6 @@ public class UiccController extends Handler { protected RegistrantList mIccChangedRegistrants = new RegistrantList(); - @NonNull - private final CarrierServiceBindHelper mCarrierServiceBindHelper; - private UiccStateChangedLauncher mLauncher; private RadioConfig mRadioConfig; @@ -273,13 +243,8 @@ public class UiccController extends Handler { numPhysicalSlots = mCis.length; } - mTelephonyManager = mContext.getSystemService(TelephonyManager.class); - mUiccSlots = new UiccSlot[numPhysicalSlots]; mPhoneIdToSlotId = new int[mCis.length]; - int supportedModemCount = mTelephonyManager.getSupportedModemCount(); - mSimCardState = new int[supportedModemCount]; - mSimApplicationState = new int[supportedModemCount]; Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID); if (VDBG) logPhoneIdToSlotIdMapping(); mRadioConfig = RadioConfig.getInstance(); @@ -295,8 +260,6 @@ public class UiccController extends Handler { mCardStrings = loadCardStrings(); mDefaultEuiccCardId = UNINITIALIZED_CARD_ID; - mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); - mEuiccSlots = mContext.getResources() .getIntArray(com.android.internal.R.array.non_removable_euicc_slots); mHasBuiltInEuicc = hasBuiltInEuicc(); @@ -744,300 +707,35 @@ public class UiccController extends Handler { } } - /** - * Update SIM state for the inactive eSIM port. - * - * @param phoneId Previously active phone id. - * @param iccId ICCID of the SIM. - */ - public void updateSimStateForInactivePort(int phoneId, String iccId) { - if (SubscriptionManager.isValidPhoneId(phoneId)) { + static void updateInternalIccStateForInactivePort( + Context context, int prevActivePhoneId, String iccId) { + if (SubscriptionManager.isValidPhoneId(prevActivePhoneId)) { // Mark SIM state as ABSENT on previously phoneId. - mTelephonyManager.setSimStateForPhone(phoneId, + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + telephonyManager.setSimStateForPhone(prevActivePhoneId, IccCardConstants.State.ABSENT.toString()); } - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().updateSimStateForInactivePort(phoneId); + SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); + if (subInfoUpdator != null) { + subInfoUpdator.updateInternalIccStateForInactivePort(prevActivePhoneId, iccId); } else { - SubscriptionInfoUpdater subInfoUpdater = PhoneFactory.getSubscriptionInfoUpdater(); - if (subInfoUpdater != null) { - subInfoUpdater.updateInternalIccStateForInactivePort(phoneId, iccId); - } else { - Rlog.e(LOG_TAG, "subInfoUpdate is null."); - } + Rlog.e(LOG_TAG, "subInfoUpdate is null."); } } - /** - * Broadcast the legacy SIM state changed event. - * - * @param phoneId The phone id. - * @param state The legacy SIM state. - * @param reason The reason of SIM state change. - */ - private void broadcastSimStateChanged(int phoneId, @NonNull String state, - @Nullable String reason) { - // Note: This intent is way deprecated and is only being kept around because there's no - // graceful way to deprecate a sticky broadcast that has a lot of listeners. - // DO NOT add any new extras to this broadcast -- it is not protected by any permissions. - Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); - intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state); - intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); - Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " - + reason + " for phone: " + phoneId); - IntentBroadcaster.getInstance().broadcastStickyIntent(mContext, intent, phoneId); - } + static void updateInternalIccState(Context context, IccCardConstants.State state, String reason, + int phoneId) { + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + telephonyManager.setSimStateForPhone(phoneId, state.toString()); - /** - * Broadcast SIM card state changed event. - * - * @param phoneId The phone id. - * @param state The SIM card state. - */ - private void broadcastSimCardStateChanged(int phoneId, @SimState int state) { - if (state != mSimCardState[phoneId]) { - mSimCardState[phoneId] = state; - Intent intent = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); - // TODO(b/130664115) we manually populate this intent with the slotId. In the future we - // should do a review of whether to make this public - UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); - int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); - intent.putExtra(PhoneConstants.SLOT_KEY, slotId); - if (slot != null) { - intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); - } - Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " - + TelephonyManager.simStateToString(state) + " for phone: " + phoneId - + " slot: " + slotId + " port: " + slot.getPortIndexFromPhoneId(phoneId)); - mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - TelephonyMetrics.getInstance().updateSimState(phoneId, state); - } - } - - /** - * Broadcast SIM application state changed event. - * - * @param phoneId The phone id. - * @param state The SIM application state. - */ - private void broadcastSimApplicationStateChanged(int phoneId, @SimState int state) { - // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY, - // because that's the initial state and a broadcast should be sent only on a transition - // after SIM is PRESENT. The only exception is eSIM boot profile, where NOT_READY is the - // terminal state. - boolean isUnknownToNotReady = - (mSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN - && state == TelephonyManager.SIM_STATE_NOT_READY); - IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); - boolean emptyProfile = iccCard != null && iccCard.isEmptyProfile(); - if (state != mSimApplicationState[phoneId] && (!isUnknownToNotReady || emptyProfile)) { - mSimApplicationState[phoneId] = state; - Intent intent = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); - // TODO(b/130664115) we populate this intent with the actual slotId. In the future we - // should do a review of whether to make this public - UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); - int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); - intent.putExtra(PhoneConstants.SLOT_KEY, slotId); - if (slot != null) { - intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); - } - Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " - + TelephonyManager.simStateToString(state) - + " for phone: " + phoneId + " slot: " + slotId + "port: " - + slot.getPortIndexFromPhoneId(phoneId)); - mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - TelephonyMetrics.getInstance().updateSimState(phoneId, state); - } - } - - /** - * Get SIM state from SIM lock reason. - * - * @param lockedReason The SIM lock reason. - * - * @return The SIM state. - */ - @SimState - private static int getSimStateFromLockedReason(String lockedReason) { - switch (lockedReason) { - case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN: - return TelephonyManager.SIM_STATE_PIN_REQUIRED; - case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK: - return TelephonyManager.SIM_STATE_PUK_REQUIRED; - case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK: - return TelephonyManager.SIM_STATE_NETWORK_LOCKED; - case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED: - return TelephonyManager.SIM_STATE_PERM_DISABLED; - default: - Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason); - return TelephonyManager.SIM_STATE_UNKNOWN; - } - } - - /** - * Broadcast SIM state events. - * - * @param phoneId The phone id. - * @param simState The SIM state. - * @param reason SIM state changed reason. - */ - private void broadcastSimStateEvents(int phoneId, IccCardConstants.State simState, - @Nullable String reason) { - String legacyStringSimState = getIccStateIntentString(simState); - int cardState = TelephonyManager.SIM_STATE_UNKNOWN; - int applicationState = TelephonyManager.SIM_STATE_UNKNOWN; - - switch (simState) { - case ABSENT: - cardState = TelephonyManager.SIM_STATE_ABSENT; - break; - case PIN_REQUIRED: - case PUK_REQUIRED: - case NETWORK_LOCKED: - case PERM_DISABLED: - cardState = TelephonyManager.SIM_STATE_PRESENT; - applicationState = getSimStateFromLockedReason(reason); - break; - case READY: - case NOT_READY: - // Both READY and NOT_READY have the same card state and application state. - cardState = TelephonyManager.SIM_STATE_PRESENT; - applicationState = TelephonyManager.SIM_STATE_NOT_READY; - break; - case CARD_IO_ERROR: - cardState = TelephonyManager.SIM_STATE_CARD_IO_ERROR; - applicationState = TelephonyManager.SIM_STATE_NOT_READY; - break; - case CARD_RESTRICTED: - cardState = TelephonyManager.SIM_STATE_CARD_RESTRICTED; - applicationState = TelephonyManager.SIM_STATE_NOT_READY; - break; - case LOADED: - cardState = TelephonyManager.SIM_STATE_PRESENT; - applicationState = TelephonyManager.SIM_STATE_LOADED; - break; - case UNKNOWN: - default: - break; - } - - broadcastSimStateChanged(phoneId, legacyStringSimState, reason); - broadcastSimCardStateChanged(phoneId, cardState); - broadcastSimApplicationStateChanged(phoneId, applicationState); - } - - /** - * Update carrier service. - * - * @param phoneId The phone id. - * @param simState The SIM state. - */ - private void updateCarrierServices(int phoneId, @NonNull String simState) { - CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class); - if (configManager != null) { - configManager.updateConfigForPhoneId(phoneId, simState); - } - mCarrierServiceBindHelper.updateSimState(phoneId, simState); - } - - /** - * Check if the SIM application is enabled on the card or not. - * - * @param phoneId The phone id. - * @return {@code true} if the application is enabled. - */ - private boolean areUiccAppsEnabledOnCard(int phoneId) { - // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from - // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another - // handleSimNotReady so this will be evaluated again. - UiccSlot slot = getUiccSlotForPhone(phoneId); - if (slot == null) return false; - UiccPort port = getUiccPort(phoneId); - String iccId = (port == null) ? null : port.getIccId(); - if (iccId == null) { - return false; - } - SubscriptionInfo info = SubscriptionManagerService.getInstance() - .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) - .stream().filter(subInfo -> subInfo.getIccId().equals( - IccUtils.stripTrailingFs(iccId))) - .findFirst().orElse(null); - return info != null && info.areUiccApplicationsEnabled(); - } - - /** - * Update the SIM state. - * - * @param phoneId Phone id. - * @param state SIM state (legacy). - * @param reason The reason for SIM state update. - */ - public void updateSimState(int phoneId, @NonNull IccCardConstants.State state, - @Nullable String reason) { - log("updateSimState: phoneId=" + phoneId + ", state=" + state + ", reason=" + reason); - if (!SubscriptionManager.isValidPhoneId(phoneId)) { - Rlog.e(LOG_TAG, "updateInternalIccState: Invalid phone id " + phoneId); - return; - } - - mTelephonyManager.setSimStateForPhone(phoneId, state.toString()); - - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - String legacySimState = getIccStateIntentString(state); - int simState = state.ordinal(); - SubscriptionManagerService.getInstance().updateSimState(phoneId, simState, this::post, - () -> { - // The following are executed after subscription update completed in - // subscription manager service. - - broadcastSimStateEvents(phoneId, state, reason); - - UiccProfile uiccProfile = getUiccProfileForPhone(phoneId); - - if (simState == TelephonyManager.SIM_STATE_READY) { - // SIM_STATE_READY is not a final state. - return; - } - - if (simState == TelephonyManager.SIM_STATE_NOT_READY - && (uiccProfile != null && !uiccProfile.isEmptyProfile()) - && areUiccAppsEnabledOnCard(phoneId)) { - // STATE_NOT_READY is not a final state for when both - // 1) It's not an empty profile, and - // 2) Its uicc applications are set to enabled. - // - // At this phase, we consider STATE_NOT_READY not a final state, so - // return for now. - log("updateSimState: SIM_STATE_NOT_READY is not a final state."); - return; - } - - // At this point, the SIM state must be a final state (meaning we won't - // get more SIM state updates). So resolve the carrier id and update the - // carrier services. - log("updateSimState: resolve carrier id and update carrier services."); - PhoneFactory.getPhone(phoneId).resolveSubscriptionCarrierId(legacySimState); - updateCarrierServices(phoneId, legacySimState); - } - ); + SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); + if (subInfoUpdator != null) { + subInfoUpdator.updateInternalIccState(getIccStateIntentString(state), reason, phoneId); } else { - SubscriptionInfoUpdater subInfoUpdater = PhoneFactory.getSubscriptionInfoUpdater(); - if (subInfoUpdater != null) { - subInfoUpdater.updateInternalIccState(getIccStateIntentString(state), reason, - phoneId); - } else { - Rlog.e(LOG_TAG, "subInfoUpdate is null."); - } + Rlog.e(LOG_TAG, "subInfoUpdate is null."); } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index d9ff3f15d6..d882e49d01 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -802,8 +802,8 @@ public class UiccProfile extends IccCard { } log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState); - UiccController.getInstance().updateSimState(mPhoneId, mExternalState, - getIccStateReason(mExternalState)); + UiccController.updateInternalIccState(mContext, mExternalState, + getIccStateReason(mExternalState), mPhoneId); } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index 069a29d251..ec4919609c 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -195,7 +195,7 @@ public class UiccSlot extends Handler { if (!iss.mSimPortInfos[i].mPortActive) { // TODO: (b/79432584) evaluate whether should broadcast card state change // even if it's inactive. - UiccController.getInstance().updateSimStateForInactivePort( + UiccController.updateInternalIccStateForInactivePort(mContext, mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID), iss.mSimPortInfos[i].mIccId); mLastRadioState.put(i, TelephonyManager.RADIO_POWER_UNAVAILABLE); @@ -330,8 +330,8 @@ public class UiccSlot extends Handler { if (DBG) log("update: notify card removed"); sendMessage(obtainMessage(EVENT_CARD_REMOVED, null)); } - UiccController.getInstance().updateSimState(phoneId, IccCardConstants.State.ABSENT, - null); + UiccController.updateInternalIccState(mContext, IccCardConstants.State.ABSENT, + null, phoneId); // no card present in the slot now; dispose card and make mUiccCard null nullifyUiccCard(false /* sim state is not unknown */); mLastRadioState.put(portIndex, TelephonyManager.RADIO_POWER_UNAVAILABLE); @@ -592,8 +592,8 @@ public class UiccSlot extends Handler { nullifyUiccCard(true /* sim state is unknown */); if (phoneId != INVALID_PHONE_ID) { - UiccController.getInstance().updateSimState(phoneId, - IccCardConstants.State.UNKNOWN, null); + UiccController.updateInternalIccState( + mContext, IccCardConstants.State.UNKNOWN, null, phoneId); mLastRadioState.put(getPortIndexFromPhoneId(phoneId), TelephonyManager.RADIO_POWER_UNAVAILABLE); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java index 87b29840f0..6aab7ad9d0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java @@ -158,7 +158,8 @@ public class UiccSlotTest extends TelephonyTest { assertTrue(mUiccSlot.isActive()); assertNull(mUiccSlot.getUiccCard()); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); } @Test @@ -379,7 +380,8 @@ public class UiccSlotTest extends TelephonyTest { // Make sure when received CARDSTATE_ABSENT state in the first time, mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); } @@ -412,7 +414,7 @@ public class UiccSlotTest extends TelephonyTest { assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); // assert that we tried to update subscriptions - verify(mUiccController).updateSimStateForInactivePort( + verify(mSubInfoRecordUpdater).updateInternalIccStateForInactivePort( activeIss.mSimPortInfos[0].mLogicalSlotIndex, inactiveIss.mSimPortInfos[0].mIccId); } @@ -433,10 +435,11 @@ public class UiccSlotTest extends TelephonyTest { assertNotNull(mUiccSlot.getUiccCard()); // Simulate when SIM is removed, UiccCard and UiccProfile should be disposed and ABSENT - // state is sent to UiccController. + // state is sent to SubscriptionInfoUpdater. mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); verify(mUiccProfile).dispose(); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); @@ -459,8 +462,9 @@ public class UiccSlotTest extends TelephonyTest { // radio state unavailable mUiccSlot.onRadioStateUnavailable(phoneId); - // Verify that UNKNOWN state is sent to UiccController in this case. - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.UNKNOWN, null); + // Verify that UNKNOWN state is sent to SubscriptionInfoUpdater in this case. + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null, phoneId); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); @@ -468,8 +472,9 @@ public class UiccSlotTest extends TelephonyTest { mIccCardStatus.mCardState = CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - // Verify that ABSENT state is sent to UiccController in this case. - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + // Verify that ABSENT state is sent to SubscriptionInfoUpdater in this case. + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); } -- GitLab From 66606555bba677f33bab193a84079d5be551f916 Mon Sep 17 00:00:00 2001 From: sparvathy Date: Thu, 17 Nov 2022 17:15:16 +0000 Subject: [PATCH 314/656] Changed merging of logic in combined final emergency numbers list Used seperate utility api for merging logic in combined list of DB and radio list. Test: atest EmergencyNumberTrackerTest & device test EC call Bug: 238359415 Change-Id: I54a6405ddf3a294a7430054b97345f4f00378c3d --- .../emergency/EmergencyNumberTracker.java | 26 +- .../emergency/EmergencyNumberTest.java | 260 +++++++++++++++++- 2 files changed, 275 insertions(+), 11 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 85cc5be2af..c80595f539 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -785,7 +785,11 @@ public class EmergencyNumberTracker extends Handler { } mergedEmergencyNumberList.addAll(mEmergencyNumberListWithPrefix); mergedEmergencyNumberList.addAll(mEmergencyNumberListFromTestMode); - EmergencyNumber.mergeSameNumbersInEmergencyNumberList(mergedEmergencyNumberList); + if (shouldDeterminingOfUrnsAndCategoriesWhileMergingIgnored()) { + EmergencyNumber.mergeSameNumbersInEmergencyNumberList(mergedEmergencyNumberList); + } else { + EmergencyNumber.mergeSameNumbersInEmergencyNumberList(mergedEmergencyNumberList, true); + } mEmergencyNumberList = mergedEmergencyNumberList; } @@ -1278,7 +1282,12 @@ public class EmergencyNumberTracker extends Handler { mEmergencyNumberListFromDatabase)); } mergedEmergencyNumberList.addAll(getEmergencyNumberListTestMode()); - EmergencyNumber.mergeSameNumbersInEmergencyNumberList(mergedEmergencyNumberList); + + if (shouldDeterminingOfUrnsAndCategoriesWhileMergingIgnored()) { + EmergencyNumber.mergeSameNumbersInEmergencyNumberList(mergedEmergencyNumberList); + } else { + EmergencyNumber.mergeSameNumbersInEmergencyNumberList(mergedEmergencyNumberList, true); + } return mergedEmergencyNumberList; } @@ -1339,6 +1348,19 @@ public class EmergencyNumberTracker extends Handler { .ignore_emergency_number_routing_from_db); } + + /** + * @return {@code true} if determining of Urns & Service Categories while merging duplicate + * numbers should be ignored. + * {@code false} if determining of Urns & Service Categories while merging duplicate + * numbers should not be ignored. + */ + @VisibleForTesting + public boolean shouldDeterminingOfUrnsAndCategoriesWhileMergingIgnored() { + // TODO: Device config + return false; + } + /** * Dump Emergency Number List info in the tracking * diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java index d6aad72b77..5653209dee 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTest.java @@ -261,7 +261,7 @@ public class EmergencyNumberTest extends TestCase { EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); - assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2, false)); } @@ -284,7 +284,7 @@ public class EmergencyNumberTest extends TestCase { EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); - assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2, false)); } public void testSameEmergencyNumberDifferentMnc() throws Exception { @@ -306,7 +306,7 @@ public class EmergencyNumberTest extends TestCase { EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); - assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2, false)); } public void testSameEmergencyNumberDifferentCategories() throws Exception { @@ -328,7 +328,7 @@ public class EmergencyNumberTest extends TestCase { EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); - assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2, false)); } public void testSameEmergencyNumberDifferentUrns() throws Exception { @@ -357,7 +357,7 @@ public class EmergencyNumberTest extends TestCase { EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); - assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2, false)); } public void testSameEmergencyNumberCallRouting() throws Exception { @@ -382,7 +382,7 @@ public class EmergencyNumberTest extends TestCase { /* case 1: Check routing is not checked when comparing the same numbers. As routing will be unknown for all numbers apart from DB. Check merge when both are not from DB then routing value is merged from first number. */ - assertTrue(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + assertTrue(EmergencyNumber.areSameEmergencyNumbers(num1, num2, false)); assertEquals(num1, EmergencyNumber.mergeSameEmergencyNumbers(num1, num2)); num2 = new EmergencyNumber( @@ -397,7 +397,7 @@ public class EmergencyNumberTest extends TestCase { /* case 1: Check routing is not checked when comparing the same numbers. Check merge when one of the number is from DB then routing value is merged from DB number. Along with source value is masked with both*/ - assertTrue(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + assertTrue(EmergencyNumber.areSameEmergencyNumbers(num1, num2, false)); num2 = new EmergencyNumber( "911", @@ -430,7 +430,7 @@ public class EmergencyNumberTest extends TestCase { EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); - assertTrue(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + assertTrue(EmergencyNumber.areSameEmergencyNumbers(num1, num2, false)); } public void testSameEmergencyNumberDifferentSourceTestOrNot() throws Exception { @@ -452,7 +452,7 @@ public class EmergencyNumberTest extends TestCase { EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST, EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); - assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2)); + assertFalse(EmergencyNumber.areSameEmergencyNumbers(num1, num2, false)); } public void testMergeSameNumbersInEmergencyNumberListWithDifferentSources() throws Exception { @@ -624,4 +624,246 @@ public class EmergencyNumberTest extends TestCase { assertEquals(outputNumberList, inputNumberList); } + + public void testMergeSameNumbersEmergencyNumberListByDeterminingFields() throws Exception { + List urn1 = new ArrayList<>(); + urn1.add("sos"); + + List urn2 = new ArrayList<>(); + urn2.add("sos:ambulance"); + + List inputNumberList = new ArrayList<>(); + EmergencyNumber num1 = new EmergencyNumber( + "110", + "jp", + "30", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, + new ArrayList(), + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + + EmergencyNumber num2 = new EmergencyNumber( + "110", + "jp", + "30", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, + urn1, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + EmergencyNumber num3 = new EmergencyNumber( + "911", + "us", + "30", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, + new ArrayList(), + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + EmergencyNumber num4 = new EmergencyNumber( + "911", + "us", + "30", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE, + urn2, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY); + + EmergencyNumber num5 = new EmergencyNumber( + "112", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE, + urn2, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + + EmergencyNumber num6 = new EmergencyNumber( + "112", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, + urn1, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + EmergencyNumber num7 = new EmergencyNumber( + "108", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE, + urn2, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + EmergencyNumber num8 = new EmergencyNumber( + "108", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, + new ArrayList(), + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + EmergencyNumber num9 = new EmergencyNumber( + "102", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE, + urn2, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + EmergencyNumber num10 = new EmergencyNumber( + "102", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE, + urn1, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + EmergencyNumber num11 = new EmergencyNumber( + "100", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MIEC, + urn2, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY); + + EmergencyNumber num12 = new EmergencyNumber( + "100", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, + new ArrayList(), + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + + EmergencyNumber num13 = new EmergencyNumber( + "200", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, + new ArrayList(), + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY); + + EmergencyNumber num14 = new EmergencyNumber( + "200", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, + new ArrayList(), + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + inputNumberList.add(num1); + inputNumberList.add(num2); + inputNumberList.add(num3); + inputNumberList.add(num4); + inputNumberList.add(num5); + inputNumberList.add(num6); + inputNumberList.add(num7); + inputNumberList.add(num8); + inputNumberList.add(num9); + inputNumberList.add(num10); + inputNumberList.add(num11); + inputNumberList.add(num12); + inputNumberList.add(num13); + inputNumberList.add(num14); + + EmergencyNumber mergeOfNum1AndNum2 = new EmergencyNumber( + "110", + "jp", + "30", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, + urn1, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE + | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + + EmergencyNumber mergeOfNum3AndNum4 = new EmergencyNumber( + "911", + "us", + "30", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE, + urn2, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE + | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, + EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY); + + List mergedUrns1And2 = new ArrayList<>(); + mergedUrns1And2.add("sos"); + mergedUrns1And2.add("sos:ambulance"); + + EmergencyNumber mergeOfNum5AndNum6 = new EmergencyNumber( + "112", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE, + mergedUrns1And2, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE + | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM, + EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL); + + EmergencyNumber mergeOfNum7AndNum8 = new EmergencyNumber( + "108", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE, + urn2, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG + | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + EmergencyNumber mergeOfNum11AndNum12 = new EmergencyNumber( + "100", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, + urn2, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM + | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY); + + List mergedUrns2And1 = new ArrayList<>(); + mergedUrns2And1.add("sos:ambulance"); + mergedUrns2And1.add("sos"); + + EmergencyNumber mergeOfNum9AndNum10 = new EmergencyNumber( + "102", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE, + mergedUrns2And1, + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING + | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM, + EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN); + + EmergencyNumber mergeOfNum13AndNum14 = new EmergencyNumber( + "200", + "in", + "", + EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, + new ArrayList(), + EmergencyNumber.EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG + | EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY); + + List outputNumberList = new ArrayList<>(); + outputNumberList.add(mergeOfNum1AndNum2); + outputNumberList.add(mergeOfNum3AndNum4); + outputNumberList.add(mergeOfNum5AndNum6); + outputNumberList.add(mergeOfNum7AndNum8); + outputNumberList.add(mergeOfNum9AndNum10); + outputNumberList.add(mergeOfNum11AndNum12); + outputNumberList.add(mergeOfNum13AndNum14); + Collections.sort(outputNumberList); + + EmergencyNumber.mergeSameNumbersInEmergencyNumberList(inputNumberList, true); + assertEquals(outputNumberList, inputNumberList); + } } -- GitLab From c013f15a3eb0f9c5b14c61f0ce6899dfebedb323 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Wed, 4 Jan 2023 23:02:56 +0000 Subject: [PATCH 315/656] Revert "Added SIM events handling and fix crashes" Revert submission 20813798-smsvc_bootup Reason for revert: b/263772382 Reverted changes: /q/submissionid:20813798-smsvc_bootup Change-Id: I3fb32444d6f50dc8ace1276f2998551118832c7f (cherry picked from commit 9c185193949cd67e87d172f5ba1f3919e8bb7fc3) Merged-In: I3fb32444d6f50dc8ace1276f2998551118832c7f --- .../internal/telephony/PhoneFactory.java | 9 +- .../telephony/ServiceStateTracker.java | 4 +- .../telephony/SubscriptionController.java | 5 +- .../telephony/data/PhoneSwitcher.java | 10 +- .../SubscriptionDatabaseManager.java | 61 +- .../SubscriptionManagerService.java | 520 +++++------------- .../telephony/uicc/UiccController.java | 29 +- .../internal/telephony/uicc/UiccProfile.java | 11 +- .../SubscriptionManagerServiceTest.java | 23 +- 9 files changed, 208 insertions(+), 464 deletions(-) diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index 43aa15434b..cb8f984b0f 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -214,14 +214,9 @@ public class PhoneFactory { TelephonyComponentFactory.getInstance().inject(SubscriptionController.class .getName()).initSubscriptionController(context); } - - SubscriptionController sc = null; - if (!isSubscriptionManagerServiceEnabled()) { - sc = SubscriptionController.getInstance(); - } - TelephonyComponentFactory.getInstance().inject(MultiSimSettingController.class. - getName()).initMultiSimSettingController(context, sc); + getName()).initMultiSimSettingController(context, + SubscriptionController.getInstance()); if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY_EUICC)) { diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 2a76a84eea..9c7178a63d 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -2751,8 +2751,8 @@ public class ServiceStateTracker extends Handler { if (mPhone.isSubscriptionManagerServiceEnabled()) { mSubscriptionManagerService.setCarrierName(mPhone.getSubId(), - TextUtils.emptyIfNull(getCarrierName(data.shouldShowPlmn(), data.getPlmn(), - data.shouldShowSpn(), data.getSpn()))); + getCarrierName(data.shouldShowPlmn(), data.getPlmn(), + data.shouldShowSpn(), data.getSpn())); } else { if (!mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), data.shouldShowPlmn(), data.getPlmn(), data.shouldShowSpn(), diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index af759ead32..4974182a9b 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -331,11 +331,8 @@ public class SubscriptionController extends ISub.Stub { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static SubscriptionController getInstance() { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - throw new RuntimeException("getInstance should not be called."); - } if (sInstance == null) { - Log.wtf(LOG_TAG, "getInstance null"); + Log.wtf(LOG_TAG, "getInstance null"); } return sInstance; diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index fe63ada5a8..1eb07aa4fb 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -531,14 +531,8 @@ public class PhoneSwitcher extends Handler { mMaxDataAttachModemCount = maxActivePhones; mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService = SubscriptionManagerService.getInstance(); - mSubscriptionController = null; - } else { - mSubscriptionController = SubscriptionController.getInstance(); - mSubscriptionManagerService = null; - } - + mSubscriptionController = SubscriptionController.getInstance(); + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); mRadioConfig = RadioConfig.getInstance(); mValidator = CellularNetworkValidator.getInstance(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 199d2d4f30..501d4f0cc5 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -39,7 +39,6 @@ import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyManager; -import android.telephony.UiccAccessRule; import android.telephony.ims.ImsMmTelManager; import android.text.TextUtils; import android.util.Base64; @@ -563,7 +562,6 @@ public class SubscriptionDatabaseManager extends Handler { public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper, @NonNull SubscriptionDatabaseManagerCallback callback) { super(looper); - log("Created SubscriptionDatabaseManager."); mContext = context; mCallback = callback; mUiccController = UiccController.getInstance(); @@ -686,8 +684,6 @@ public class SubscriptionDatabaseManager extends Handler { for (String columnName : Telephony.SimInfo.getAllColumns()) { if (DEPRECATED_DATABASE_COLUMNS.contains(columnName)) continue; - // subId is generated by the database. Cannot be updated. - if (columnName.equals(SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID)) continue; Object newValue = getSubscriptionInfoFieldByColumnName(newSubInfo, columnName); if (newValue != null) { Object oldValue = null; @@ -716,16 +712,13 @@ public class SubscriptionDatabaseManager extends Handler { Objects.requireNonNull(contentValues); Uri uri = mContext.getContentResolver().insert(SimInfo.CONTENT_URI, contentValues); if (uri != null && uri.getLastPathSegment() != null) { - int subId = Integer.parseInt(uri.getLastPathSegment()); - if (SubscriptionManager.isValidSubscriptionId(subId)) { - logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" - + uri.getLastPathSegment()); - return subId; - } + logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" + + uri.getLastPathSegment()); + return Integer.parseInt(uri.getLastPathSegment()); + } else { + logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " + + "contentValues=" + contentValues); } - - logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " - + "contentValues=" + contentValues); return INVALID_ROW_INDEX; } @@ -882,8 +875,6 @@ public class SubscriptionDatabaseManager extends Handler { // Check if the new value is different from the old value in the cache. if (!Objects.equals(getSubscriptionInfoFieldByColumnName(subInfo, columnName), newValue)) { - logv("writeDatabaseAndCacheHelper: subId=" + subId + ",columnName=" - + columnName + ", newValue=" + newValue); // If the value is different, then we need to update the cache. Since all // fields in SubscriptionInfo are final, we need to create a new // SubscriptionInfo. @@ -1219,24 +1210,6 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules); } - /** - * Set the carrier certificates for this subscription that are saved in carrier configs. - * This does not include access rules from the Uicc, whether embedded or non-embedded. - * - * @param subId Subscription id. - * @param carrierConfigAccessRules The carrier certificates for this subscription. - * - * @throws IllegalArgumentException if the subscription does not exist. - */ - public void setCarrierConfigAccessRules(int subId, - @NonNull UiccAccessRule[] carrierConfigAccessRules) { - Objects.requireNonNull(carrierConfigAccessRules); - byte[] carrierConfigAccessRulesBytes = UiccAccessRule.encodeRules(carrierConfigAccessRules); - writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, - carrierConfigAccessRulesBytes, - SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules); - } - /** * Set whether an embedded subscription is on a removable card. Such subscriptions are * marked inaccessible as soon as the current card is removed. Otherwise, they will remain @@ -1788,23 +1761,11 @@ public class SubscriptionDatabaseManager extends Handler { // publicCardId is the publicly exposed int card ID int publicCardId = mUiccController.convertToPublicCardId(cardString); - byte[] rules = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_ACCESS_RULES)); - if (rules != null) { - builder.setNativeAccessRules(rules); - } - - rules = cursor.getBlob(cursor.getColumnIndexOrThrow( - SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS)); - if (rules != null) { - builder.setCarrierConfigAccessRules(rules); - } - - byte[] config = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_RCS_CONFIG)); - if (config != null) { - builder.setRcsConfig(config); - } - builder.setCardId(publicCardId) + .setNativeAccessRules(cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ACCESS_RULES))) + .setCarrierConfigAccessRules(cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS))) .setRemovableEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_IS_REMOVABLE))) .setEnhanced4GModeEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( @@ -1844,6 +1805,8 @@ public class SubscriptionDatabaseManager extends Handler { SimInfo.COLUMN_IMS_RCS_UCE_ENABLED))) .setCrossSimCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED))) + .setRcsConfig(cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_RCS_CONFIG))) .setAllowedNetworkTypesForReasons(TextUtils.emptyIfNull( cursor.getString(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS)))) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 27007f116b..9e314280e0 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -37,7 +37,6 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.ParcelUuid; -import android.os.PersistableBundle; import android.os.RemoteException; import android.os.TelephonyServiceManager; import android.os.UserHandle; @@ -76,7 +75,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CarrierResolver; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; -import com.android.internal.telephony.IccCard; import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; @@ -86,9 +84,7 @@ import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; -import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccController; -import com.android.internal.telephony.uicc.UiccPort; import com.android.internal.telephony.uicc.UiccSlot; import com.android.internal.telephony.util.ArrayUtils; import com.android.telephony.Rlog; @@ -141,7 +137,6 @@ public class SubscriptionManagerService extends ISub.Stub { SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, SimInfo.COLUMN_RCS_CONFIG, - SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, SimInfo.COLUMN_D2D_STATUS_SHARING, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, @@ -235,10 +230,6 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull private final WatchedInt mDefaultSmsSubId; - /** Sim state per logical SIM slot index. */ - @NonNull - private final int[] mSimState; - /** * Watched map that automatically invalidate cache in {@link SubscriptionManager}. */ @@ -272,7 +263,7 @@ public class SubscriptionManagerService extends ISub.Stub { * Watched integer. */ public static class WatchedInt { - protected int mValue; + private int mValue; /** * Constructor. @@ -386,9 +377,7 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { - int oldValue = mValue; if (super.set(newValue)) { - logl("Default voice sub changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, newValue); return true; @@ -402,9 +391,7 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { - int oldValue = mValue; if (super.set(newValue)) { - logl("Default data sub changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, newValue); return true; @@ -418,9 +405,7 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { - int oldValue = mValue; if (super.set(newValue)) { - logl("Default voice sms changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, newValue); return true; @@ -431,9 +416,6 @@ public class SubscriptionManagerService extends ISub.Stub { mDefaultSubId = new WatchedInt(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mSimState = new int[mTelephonyManager.getSupportedModemCount()]; - Arrays.fill(mSimState, TelephonyManager.SIM_STATE_UNKNOWN); - // Create a separate thread for subscription database manager. The database will be updated // from a different thread. HandlerThread handlerThread = new HandlerThread(LOG_TAG); @@ -1008,292 +990,13 @@ public class SubscriptionManagerService extends ISub.Stub { } } - /** - * Check if the SIM application is enabled on the card or not. - * - * @param phoneId The phone id. - * - * @return {@code true} if the application is enabled. - */ - public boolean areUiccAppsEnabledOnCard(int phoneId) { - // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from - // cardStatus (since IRadio 1.2). And upon cardStatus change we'll receive another - // handleSimNotReady so this will be evaluated again. - UiccSlot slot = mUiccController.getUiccSlotForPhone(phoneId); - if (slot == null) return false; - UiccPort port = mUiccController.getUiccPort(phoneId); - String iccId = (port == null) ? null : port.getIccId(); - if (iccId == null) { - return false; - } - - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager - .getSubscriptionInfoInternalByIccId(IccUtils.stripTrailingFs(iccId)); - return subInfo != null && subInfo.areUiccApplicationsEnabled(); - } - - /** - * Get ICCID by phone id. - * - * @param phoneId The phone id (i.e. Logical SIM slot index.) - * - * @return The ICCID. Empty string if not available. - */ - @NonNull - private String getIccId(int phoneId) { - UiccPort port = mUiccController.getUiccPort(phoneId); - return (port == null) ? "" : TextUtils.emptyIfNull( - IccUtils.stripTrailingFs(port.getIccId())); - } - /** * Update the subscriptions on the logical SIM slot index (i.e. phone id). * - * @param phoneId The phone id (i.e. Logical SIM slot index) - */ - private void updateSubscriptions(int phoneId) { - int simState = mSimState[phoneId]; - log("updateSubscriptions: phoneId=" + phoneId + ", simState=" - + TelephonyManager.simStateToString(simState)); - if (simState == TelephonyManager.SIM_STATE_ABSENT) { - if (mSlotIndexToSubId.containsKey(phoneId)) { - // Re-enable the SIM when it's removed, so it will be in enabled state when it gets - // re-inserted again. (pre-U behavior) - mSubscriptionDatabaseManager.setUiccApplicationsEnabled( - mSlotIndexToSubId.get(phoneId), true); - // When sim is absent, set the port index to invalid port index. (pre-U behavior) - mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(phoneId), - TelephonyManager.INVALID_PORT_INDEX); - } - } else if (simState == TelephonyManager.SIM_STATE_NOT_READY) { - // Check if this is the final state. Only update the subscription if NOT_READY is a - // final state. - IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); - if (!iccCard.isEmptyProfile() && areUiccAppsEnabledOnCard(phoneId)) { - log("updateSubscriptions: SIM_STATE_NOT_READY is not a final state. Will update " - + "subscription later."); - return; - } - } - - String iccId = getIccId(phoneId); - // Loop through all the subscriptions. If we found any ICCID matched, apply the right - // logical index to that. - int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - for (SubscriptionInfoInternal subInfo - : mSubscriptionDatabaseManager.getAllSubscriptions()) { - int simSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - if (!TextUtils.isEmpty(iccId) && subInfo.getIccId().equals(iccId)) { - subId = subInfo.getSubscriptionId(); - simSlotIndex = phoneId; - mSlotIndexToSubId.put(simSlotIndex, subId); - logl("updateSubscriptions: Found sub " + subInfo.getSubscriptionId() - + ", phoneId=" + phoneId); - } - mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), simSlotIndex); - } - - if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - logl("updateSubscriptions: Did not find any subscription. phoneId=" + phoneId); - mSlotIndexToSubId.remove(phoneId); - } - - if (!TextUtils.isEmpty(iccId)) { - // Check if the subscription already existed. - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager - .getSubscriptionInfoInternalByIccId(iccId); - if (subInfo == null) { - // This is a new SIM card. Insert a new record. - subId = mSubscriptionDatabaseManager.insertSubscriptionInfo( - new SubscriptionInfoInternal.Builder() - .setIccId(iccId) - .setSimSlotIndex(phoneId) - .build()); - logl("updateSubscriptions: Inserted a new subscription. subId=" + subId - + ", phoneId=" + phoneId); - } else { - subId = subInfo.getSubscriptionId(); - } - - // Update the SIM slot index. This will make the subscription active. - mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId); - - // Update the card id. - UiccCard card = mUiccController.getUiccCardForPhone(phoneId); - if (card != null) { - String cardId = card.getCardId(); - if (cardId != null) { - mSubscriptionDatabaseManager.setCardString(subId, cardId); - } - } - - // Update the port index. - UiccSlot slot = mUiccController.getUiccSlotForPhone(phoneId); - if (slot != null && !slot.isEuicc()) { - int portIndex = slot.getPortIndexFromIccId(iccId); - mSubscriptionDatabaseManager.setPortIndex(subId, portIndex); - } - } - - updateDefaultSubIds(); - } - - /** - * Calculate the usage setting based on the carrier request. - * - * @param currentUsageSetting the current setting in the subscription DB. - * @param preferredUsageSetting provided by the carrier config. - * - * @return the calculated usage setting. - */ - @VisibleForTesting - @UsageSetting public int calculateUsageSetting(@UsageSetting int currentUsageSetting, - @UsageSetting int preferredUsageSetting) { - int[] supportedUsageSettings; - - // Load the resources to provide the device capability - try { - supportedUsageSettings = mContext.getResources().getIntArray( - com.android.internal.R.array.config_supported_cellular_usage_settings); - // If usage settings are not supported, return the default setting, which is UNKNOWN. - if (supportedUsageSettings == null - || supportedUsageSettings.length < 1) return currentUsageSetting; - } catch (Resources.NotFoundException nfe) { - loge("calculateUsageSetting: Failed to load usage setting resources!"); - return currentUsageSetting; - } - - // If the current setting is invalid, including the first time the value is set, - // update it to default (this will trigger a change in the DB). - if (currentUsageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT - || currentUsageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { - log("calculateUsageSetting: Updating usage setting for current subscription"); - currentUsageSetting = SubscriptionManager.USAGE_SETTING_DEFAULT; - } - - // Range check the inputs, and on failure, make no changes - if (preferredUsageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT - || preferredUsageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { - loge("calculateUsageSetting: Invalid usage setting!" + preferredUsageSetting); - return currentUsageSetting; - } - - // Default is always allowed - if (preferredUsageSetting == SubscriptionManager.USAGE_SETTING_DEFAULT) { - return preferredUsageSetting; - } - - // Forced setting must be explicitly supported - for (int supportedUsageSetting : supportedUsageSettings) { - if (preferredUsageSetting == supportedUsageSetting) return preferredUsageSetting; - } - - // If the preferred setting is not possible, just keep the current setting. - return currentUsageSetting; - } - - /** - * Called by CarrierConfigLoader to update the subscription before sending a broadcast. + * @param slotIndex The logical SIM slot index. */ - public void updateSubscriptionByCarrierConfig(int phoneId, @NonNull String configPackageName, - @NonNull PersistableBundle config, @NonNull Runnable callback) { - mHandler.post(() -> { - updateSubscriptionByCarrierConfigInternal(phoneId, configPackageName, config); - callback.run(); - }); - } - - private void updateSubscriptionByCarrierConfigInternal(int phoneId, - @NonNull String configPackageName, @NonNull PersistableBundle config) { - log("updateSubscriptionByCarrierConfig: phoneId=" + phoneId + ", configPackageName=" - + configPackageName); - if (!SubscriptionManager.isValidPhoneId(phoneId) - || TextUtils.isEmpty(configPackageName) || config == null) { - loge("updateSubscriptionByCarrierConfig: Failed to update the subscription. phoneId=" - + phoneId + " configPackageName=" + configPackageName + " config=" - + ((config == null) ? "null" : config.hashCode())); - return; - } - - if (!mSlotIndexToSubId.containsKey(phoneId)) { - log("updateSubscriptionByCarrierConfig: No subscription is active for phone being " - + "updated."); - return; - } - - int subId = mSlotIndexToSubId.get(phoneId); + private void updateSubscriptions(int slotIndex) { - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager - .getSubscriptionInfoInternal(subId); - if (subInfo == null) { - loge("updateSubscriptionByCarrierConfig: Couldn't retrieve subscription info for " - + "current subscription. subId=" + subId); - return; - } - - ParcelUuid groupUuid; - - // carrier certificates are not subscription-specific, so we want to load them even if - // this current package is not a CarrierServicePackage - String[] certs = config.getStringArray( - CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY); - UiccAccessRule[] carrierConfigAccessRules = UiccAccessRule.decodeRulesFromCarrierConfig( - certs); - if (carrierConfigAccessRules != null) { - mSubscriptionDatabaseManager.setCarrierConfigAccessRules( - subId, carrierConfigAccessRules); - } - - boolean isOpportunistic = config.getBoolean( - CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, - subInfo.isOpportunistic()); - mSubscriptionDatabaseManager.setOpportunistic(subId, isOpportunistic); - - String groupUuidString = config.getString( - CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, ""); - String oldGroupUuidString = subInfo.getGroupUuid(); - if (!TextUtils.isEmpty(groupUuidString)) { - try { - // Update via a UUID Structure to ensure consistent formatting - groupUuid = ParcelUuid.fromString(groupUuidString); - if (groupUuidString.equals(CarrierConfigManager.REMOVE_GROUP_UUID_STRING)) { - // Remove the group UUID. - mSubscriptionDatabaseManager.setGroupUuid(subId, ""); - } else if (canPackageManageGroup(groupUuid, configPackageName)) { - mSubscriptionDatabaseManager.setGroupUuid(subId, groupUuidString); - mSubscriptionDatabaseManager.setGroupOwner(subId, configPackageName); - log("updateSubscriptionByCarrierConfig: Group added for sub " + subId); - } else { - loge("updateSubscriptionByCarrierConfig: configPackageName " - + configPackageName + " doesn't own groupUuid " + groupUuid); - } - - if (!groupUuidString.equals(oldGroupUuidString)) { - MultiSimSettingController.getInstance() - .notifySubscriptionGroupChanged(groupUuid); - } - } catch (IllegalArgumentException e) { - loge("updateSubscriptionByCarrierConfig: Invalid Group UUID=" - + groupUuidString); - } - } - - final int preferredUsageSetting = config.getInt( - CarrierConfigManager.KEY_CELLULAR_USAGE_SETTING_INT, - SubscriptionManager.USAGE_SETTING_UNKNOWN); - - int newUsageSetting = calculateUsageSetting( - subInfo.getUsageSetting(), preferredUsageSetting); - - if (newUsageSetting != subInfo.getUsageSetting()) { - mSubscriptionDatabaseManager.setUsageSetting(subId, newUsageSetting); - log("updateSubscriptionByCarrierConfig: UsageSetting changed," - + " oldSetting=" + SubscriptionManager.usageSettingToString( - subInfo.getUsageSetting()) - + " preferredSetting=" + SubscriptionManager.usageSettingToString( - preferredUsageSetting) - + " newSetting=" + SubscriptionManager.usageSettingToString(newUsageSetting)); - } } /** @@ -1341,20 +1044,26 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full - // list. Carrier apps can only get the subscriptions they have privileged. - .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( - mContext, subInfo.getSubscriptionId(), callingPackage, callingFeatureId, - "getAllSubInfoList")) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getAllSubInfoList")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); + final long identity = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full + // list. Carrier apps can only get the subscriptions they have privileged. + .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( + mContext, subInfo.getSubscriptionId(), callingPackage, callingFeatureId, + "getAllSubInfoList")) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getAllSubInfoList")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); + + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1517,16 +1226,22 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(SubscriptionInfoInternal::isActive) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getAllSubInfoList")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); + final long identity = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isActive) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getAllSubInfoList")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); + + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -1570,7 +1285,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int getActiveSubInfoCountMax() { - return mTelephonyManager.getActiveModemCount(); + return mTelephonyManager.getSimCount(); } /** @@ -2142,21 +1857,26 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full - // list. Carrier apps can only get the subscriptions they have privileged. - .filter(subInfo -> subInfo.isOpportunistic() - && TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( - mContext, subInfo.getSubscriptionId(), callingPackage, - callingFeatureId, "getOpportunisticSubscriptions")) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getOpportunisticSubscriptions")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); + final long identity = Binder.clearCallingIdentity(); + try { + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full + // list. Carrier apps can only get the subscriptions they have privileged. + .filter(subInfo -> subInfo.isOpportunistic() + && TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( + mContext, subInfo.getSubscriptionId(), callingPackage, + callingFeatureId, "getOpportunisticSubscriptions")) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getOpportunisticSubscriptions")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); + } finally { + Binder.restoreCallingIdentity(identity); + } } /** @@ -2411,32 +2131,6 @@ public class SubscriptionManagerService extends ISub.Stub { return new int[]{getSubId(slotIndex)}; } - /** - * Update default voice, sms, and data sub id. - */ - private void updateDefaultSubIds() { - if (getActiveSubInfoCountMax() == 0) { - mDefaultVoiceSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mDefaultSmsSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mDefaultDataSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - } - if (getActiveSubInfoCountMax() == 1) { - int[] activeSubIds = getActiveSubIdList(false); - if (activeSubIds.length == 1) { - mDefaultVoiceSubId.set(activeSubIds[0]); - mDefaultSmsSubId.set(activeSubIds[0]); - mDefaultDataSubId.set(activeSubIds[0]); - } else { - loge("updateDefaultSubIds: Single SIM device, but active subs are more than one." - + " activeSubIds=" + Arrays.toString(activeSubIds)); - } - } else { - // TODO: Support dual sim - } - - updateDefaultSubId(); - } - /** * Update default sub id. */ @@ -2657,12 +2351,9 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { - return mSlotIndexToSubId.values().stream() - .filter(subId -> { - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager - .getSubscriptionInfoInternal(subId); - return subInfo != null && (!visibleOnly || subInfo.isVisible()); }) - .mapToInt(x -> x) + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(subInfo -> subInfo.isActive() && (!visibleOnly || subInfo.isVisible())) + .mapToInt(SubscriptionInfoInternal::getSubscriptionId) .toArray(); } finally { Binder.restoreCallingIdentity(token); @@ -2867,6 +2558,9 @@ public class SubscriptionManagerService extends ISub.Stub { }) public boolean isActiveSubId(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { + // Verify that the callingPackage belongs to the calling UID + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); + if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "isActiveSubId")) { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " @@ -3494,6 +3188,68 @@ public class SubscriptionManagerService extends ISub.Stub { ? subscriptionInfoInternal.toSubscriptionInfo() : null; } + /** + * Called when SIM state changed to absent. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimAbsent(int slotIndex) { + if (mSlotIndexToSubId.containsKey(slotIndex)) { + // Re-enable the SIM when it's removed, so it will be in enabled state when it gets + // re-inserted again. (pre-U behavior) + mSubscriptionDatabaseManager.setUiccApplicationsEnabled( + mSlotIndexToSubId.get(slotIndex), true); + // When sim is absent, set the port index to invalid port index. (pre-U behavior) + mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(slotIndex), + TelephonyManager.INVALID_PORT_INDEX); + } + updateSubscriptions(slotIndex); + } + + /** + * Called when SIM state changed to locked. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimLocked(int slotIndex) { + + } + + /** + * Called when SIM state changed to ready. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimReady(int slotIndex) { + + } + + /** + * Called when SIM state changed to not ready. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimNotReady(int slotIndex) { + + } + + /** + * Called when SIM encounters error. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimError(int slotIndex) { + + } + + /** + * Called when SIM state changed to loaded. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimLoaded(int slotIndex) { + } + /** * Called when eSIM becomes inactive. * @@ -3525,24 +3281,34 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable @CallbackExecutor Executor executor, @Nullable Runnable updateCompleteCallback) { mHandler.post(() -> { - mSimState[slotIndex] = simState; switch (simState) { case TelephonyManager.SIM_STATE_ABSENT: + onSimAbsent(slotIndex); + break; case TelephonyManager.SIM_STATE_PIN_REQUIRED: case TelephonyManager.SIM_STATE_PUK_REQUIRED: case TelephonyManager.SIM_STATE_NETWORK_LOCKED: case TelephonyManager.SIM_STATE_PERM_DISABLED: + onSimLocked(slotIndex); + break; case TelephonyManager.SIM_STATE_READY: - case TelephonyManager.SIM_STATE_CARD_IO_ERROR: - case TelephonyManager.SIM_STATE_LOADED: + onSimReady(slotIndex); + break; case TelephonyManager.SIM_STATE_NOT_READY: - updateSubscriptions(slotIndex); + onSimNotReady(slotIndex); + break; + case TelephonyManager.SIM_STATE_CARD_IO_ERROR: + onSimError(slotIndex); break; case TelephonyManager.SIM_STATE_CARD_RESTRICTED: - default: // No specific things needed to be done. Just return and broadcast the SIM // states. break; + case TelephonyManager.SIM_STATE_LOADED: + onSimLoaded(slotIndex); + break; + default: + break; } if (executor != null && updateCompleteCallback != null) { executor.execute(updateCompleteCallback); diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index f88aa7d1ed..1ad7ee35f6 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -40,6 +40,7 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.SimState; @@ -949,6 +950,31 @@ public class UiccController extends Handler { mCarrierServiceBindHelper.updateSimState(phoneId, simState); } + /** + * Check if the SIM application is enabled on the card or not. + * + * @param phoneId The phone id. + * @return {@code true} if the application is enabled. + */ + private boolean areUiccAppsEnabledOnCard(int phoneId) { + // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from + // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another + // handleSimNotReady so this will be evaluated again. + UiccSlot slot = getUiccSlotForPhone(phoneId); + if (slot == null) return false; + UiccPort port = getUiccPort(phoneId); + String iccId = (port == null) ? null : port.getIccId(); + if (iccId == null) { + return false; + } + SubscriptionInfo info = SubscriptionManagerService.getInstance() + .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) + .stream().filter(subInfo -> subInfo.getIccId().equals( + IccUtils.stripTrailingFs(iccId))) + .findFirst().orElse(null); + return info != null && info.areUiccApplicationsEnabled(); + } + /** * Update the SIM state. * @@ -985,8 +1011,7 @@ public class UiccController extends Handler { if (simState == TelephonyManager.SIM_STATE_NOT_READY && (uiccProfile != null && !uiccProfile.isEmptyProfile()) - && SubscriptionManagerService.getInstance() - .areUiccAppsEnabledOnCard(phoneId)) { + && areUiccAppsEnabledOnCard(phoneId)) { // STATE_NOT_READY is not a final state for when both // 1) It's not an empty profile, and // 2) Its uicc applications are set to enabled. diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index 11f6738652..d9ff3f15d6 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -527,15 +527,8 @@ public class UiccProfile extends IccCard { private void updateCarrierNameForSubscription(int subId, int nameSource) { /* update display name with carrier override */ - SubscriptionInfo subInfo; - - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - subInfo = SubscriptionManagerService.getInstance().getActiveSubscriptionInfo(subId, - mContext.getOpPackageName(), mContext.getAttributionTag()); - } else { - subInfo = SubscriptionController.getInstance().getActiveSubscriptionInfo( - subId, mContext.getOpPackageName(), mContext.getAttributionTag()); - } + SubscriptionInfo subInfo = SubscriptionController.getInstance().getActiveSubscriptionInfo( + subId, mContext.getOpPackageName(), mContext.getAttributionTag()); if (subInfo == null) { return; 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 ebd4ad23a5..51dea369d1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -1557,13 +1557,24 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { } @Test - public void testGetNonAccessibleFields() throws Exception { + public void testGetNonAccessibleFields() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); - - Field field = SubscriptionManagerService.class.getDeclaredField( - "DIRECT_ACCESS_SUBSCRIPTION_COLUMNS"); - field.setAccessible(true); - Set accessibleColumns = (Set) field.get(null); + Set accessibleColumns = Set.of( + SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, + SimInfo.COLUMN_VT_IMS_ENABLED, + SimInfo.COLUMN_WFC_IMS_ENABLED, + SimInfo.COLUMN_WFC_IMS_MODE, + SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, + SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, + SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, + SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, + SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, + SimInfo.COLUMN_RCS_CONFIG, + SimInfo.COLUMN_D2D_STATUS_SHARING, + SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, + SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED + ); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); -- GitLab From eb73e2a6097193213a914d0451a9045d99cc931a Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Wed, 4 Jan 2023 23:05:27 +0000 Subject: [PATCH 316/656] Revert "Moved SIM state broadcast back to UiccController" This reverts commit dc1f5286d3872b807c95900cc40c3eb61b37230d. Reason for revert: b/263772382 Change-Id: I8a1e3e1934f6b66ee6dd14c4373efb44daf64dc9 (cherry picked from commit a26d3ea0d2b0955b5f1752d6aea91735eb83a6b7) Merged-In: I8a1e3e1934f6b66ee6dd14c4373efb44daf64dc9 --- .../telephony/CarrierServiceBindHelper.java | 9 +- .../telephony/SubscriptionInfoUpdater.java | 2 +- .../SubscriptionManagerService.java | 144 +------- .../telephony/uicc/UiccController.java | 342 +----------------- .../internal/telephony/uicc/UiccProfile.java | 4 +- .../internal/telephony/uicc/UiccSlot.java | 10 +- .../internal/telephony/uicc/UiccSlotTest.java | 23 +- 7 files changed, 44 insertions(+), 490 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java index 035714e5bc..dfa53b3958 100644 --- a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java +++ b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java @@ -16,7 +16,6 @@ package com.android.internal.telephony; -import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -201,13 +200,7 @@ public class CarrierServiceBindHelper { } } - /** - * Update SIM state. - * - * @param phoneId The phone id. - * @param simState The legacy SIM state. - */ - public void updateSimState(int phoneId, @NonNull String simState) { + void updateForPhoneId(int phoneId, String simState) { logdWithLocalLog("update binding for phoneId: " + phoneId + " simState: " + simState); if (!SubscriptionManager.isValidPhoneId(phoneId)) { return; diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index fa52db5012..1681d140b7 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -700,7 +700,7 @@ public class SubscriptionInfoUpdater extends Handler { CarrierConfigManager configManager = (CarrierConfigManager) sContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); configManager.updateConfigForPhoneId(phoneId, simState); - mCarrierServiceBindHelper.updateSimState(phoneId, simState); + mCarrierServiceBindHelper.updateForPhoneId(phoneId, simState); } private void updateSubscriptionCarrierId(int phoneId, String simState) { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 9e314280e0..5be96c1234 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -59,7 +59,6 @@ import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.SimState; import android.telephony.TelephonyRegistryManager; import android.telephony.UiccAccessRule; import android.telephony.euicc.EuiccManager; @@ -428,10 +427,6 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public void onDatabaseLoaded() { log("Subscription database has been loaded."); - for (int phoneId = 0; phoneId < mTelephonyManager.getActiveModemCount() - ; phoneId++) { - markSubscriptionsInactive(phoneId); - } } /** @@ -831,7 +826,7 @@ public class SubscriptionManagerService extends ISub.Stub { /** * Mark all subscriptions on this SIM slot index inactive. * - * @param simSlotIndex The logical SIM slot index (i.e. phone id). + * @param simSlotIndex The SIM slot index. */ public void markSubscriptionsInactive(int simSlotIndex) { mSubscriptionDatabaseManager.getAllSubscriptions().stream() @@ -990,15 +985,6 @@ public class SubscriptionManagerService extends ISub.Stub { } } - /** - * Update the subscriptions on the logical SIM slot index (i.e. phone id). - * - * @param slotIndex The logical SIM slot index. - */ - private void updateSubscriptions(int slotIndex) { - - } - /** * Get all subscription info records from SIMs that are inserted now or previously inserted. * @@ -3188,134 +3174,6 @@ public class SubscriptionManagerService extends ISub.Stub { ? subscriptionInfoInternal.toSubscriptionInfo() : null; } - /** - * Called when SIM state changed to absent. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimAbsent(int slotIndex) { - if (mSlotIndexToSubId.containsKey(slotIndex)) { - // Re-enable the SIM when it's removed, so it will be in enabled state when it gets - // re-inserted again. (pre-U behavior) - mSubscriptionDatabaseManager.setUiccApplicationsEnabled( - mSlotIndexToSubId.get(slotIndex), true); - // When sim is absent, set the port index to invalid port index. (pre-U behavior) - mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(slotIndex), - TelephonyManager.INVALID_PORT_INDEX); - } - updateSubscriptions(slotIndex); - } - - /** - * Called when SIM state changed to locked. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimLocked(int slotIndex) { - - } - - /** - * Called when SIM state changed to ready. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimReady(int slotIndex) { - - } - - /** - * Called when SIM state changed to not ready. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimNotReady(int slotIndex) { - - } - - /** - * Called when SIM encounters error. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimError(int slotIndex) { - - } - - /** - * Called when SIM state changed to loaded. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimLoaded(int slotIndex) { - } - - /** - * Called when eSIM becomes inactive. - * - * @param slotIndex The logical SIM slot index. - */ - public void updateSimStateForInactivePort(int slotIndex) { - mHandler.post(() -> { - if (mSlotIndexToSubId.containsKey(slotIndex)) { - // Re-enable the UICC application , so it will be in enabled state when it becomes - // active again. (pre-U behavior) - mSubscriptionDatabaseManager.setUiccApplicationsEnabled( - mSlotIndexToSubId.get(slotIndex), true); - updateSubscriptions(slotIndex); - } - }); - } - - /** - * Update SIM state. This method is supposed to be called by {@link UiccController} only. - * - * @param slotIndex The logical SIM slot index. - * @param simState SIM state. - * @param executor The executor to execute the callback. - * @param updateCompleteCallback The callback to call when subscription manager service - * completes subscription update. SIM state changed event will be broadcasted by - * {@link UiccController} upon receiving callback. - */ - public void updateSimState(int slotIndex, @SimState int simState, - @Nullable @CallbackExecutor Executor executor, - @Nullable Runnable updateCompleteCallback) { - mHandler.post(() -> { - switch (simState) { - case TelephonyManager.SIM_STATE_ABSENT: - onSimAbsent(slotIndex); - break; - case TelephonyManager.SIM_STATE_PIN_REQUIRED: - case TelephonyManager.SIM_STATE_PUK_REQUIRED: - case TelephonyManager.SIM_STATE_NETWORK_LOCKED: - case TelephonyManager.SIM_STATE_PERM_DISABLED: - onSimLocked(slotIndex); - break; - case TelephonyManager.SIM_STATE_READY: - onSimReady(slotIndex); - break; - case TelephonyManager.SIM_STATE_NOT_READY: - onSimNotReady(slotIndex); - break; - case TelephonyManager.SIM_STATE_CARD_IO_ERROR: - onSimError(slotIndex); - break; - case TelephonyManager.SIM_STATE_CARD_RESTRICTED: - // No specific things needed to be done. Just return and broadcast the SIM - // states. - break; - case TelephonyManager.SIM_STATE_LOADED: - onSimLoaded(slotIndex); - break; - default: - break; - } - if (executor != null && updateCompleteCallback != null) { - executor.execute(updateCompleteCallback); - } - }); - } - /** * Log debug messages. * diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 1ad7ee35f6..ea99d9a3f6 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -21,8 +21,6 @@ import static android.telephony.TelephonyManager.UNSUPPORTED_CARD_ID; import static java.util.Arrays.copyOf; -import android.Manifest; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.BroadcastOptions; import android.compat.annotation.UnsupportedAppUsage; @@ -40,10 +38,8 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.telephony.TelephonyManager.SimState; import android.telephony.UiccCardInfo; import android.telephony.UiccPortInfo; import android.telephony.UiccSlotMapping; @@ -53,20 +49,14 @@ import android.util.LocalLog; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.CarrierServiceBindHelper; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccCardConstants; -import com.android.internal.telephony.IntentBroadcaster; import com.android.internal.telephony.PhoneConfigurationManager; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.SubscriptionInfoUpdater; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.metrics.TelephonyMetrics; -import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.euicc.EuiccCard; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -150,9 +140,6 @@ public class UiccController extends Handler { private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 10; // NOTE: any new EVENT_* values must be added to eventToString. - @NonNull - private final TelephonyManager mTelephonyManager; - // this needs to be here, because on bootup we dont know which index maps to which UiccSlot @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private CommandsInterface[] mCis; @@ -164,25 +151,11 @@ public class UiccController extends Handler { // This maps the externally exposed card ID (int) to the internal card ID string (ICCID/EID). // The array index is the card ID (int). // This mapping exists to expose card-based functionality without exposing the EID, which is - // considered sensitive information. + // considered sensetive information. // mCardStrings is populated using values from the IccSlotStatus and IccCardStatus. For // HAL < 1.2, these do not contain the EID or the ICCID, so mCardStrings will be empty private ArrayList mCardStrings; - /** - * SIM card state. - */ - @NonNull - @SimState - private final int[] mSimCardState; - - /** - * SIM application state. - */ - @NonNull - @SimState - private final int[] mSimApplicationState; - // This is the card ID of the default eUICC. It starts as UNINITIALIZED_CARD_ID. // When we load the EID (either with slot status or from the EuiccCard), we set it to the eUICC // with the lowest slot index. @@ -232,9 +205,6 @@ public class UiccController extends Handler { protected RegistrantList mIccChangedRegistrants = new RegistrantList(); - @NonNull - private final CarrierServiceBindHelper mCarrierServiceBindHelper; - private UiccStateChangedLauncher mLauncher; private RadioConfig mRadioConfig; @@ -273,13 +243,8 @@ public class UiccController extends Handler { numPhysicalSlots = mCis.length; } - mTelephonyManager = mContext.getSystemService(TelephonyManager.class); - mUiccSlots = new UiccSlot[numPhysicalSlots]; mPhoneIdToSlotId = new int[mCis.length]; - int supportedModemCount = mTelephonyManager.getSupportedModemCount(); - mSimCardState = new int[supportedModemCount]; - mSimApplicationState = new int[supportedModemCount]; Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID); if (VDBG) logPhoneIdToSlotIdMapping(); mRadioConfig = RadioConfig.getInstance(); @@ -295,8 +260,6 @@ public class UiccController extends Handler { mCardStrings = loadCardStrings(); mDefaultEuiccCardId = UNINITIALIZED_CARD_ID; - mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); - mEuiccSlots = mContext.getResources() .getIntArray(com.android.internal.R.array.non_removable_euicc_slots); mHasBuiltInEuicc = hasBuiltInEuicc(); @@ -744,300 +707,35 @@ public class UiccController extends Handler { } } - /** - * Update SIM state for the inactive eSIM port. - * - * @param phoneId Previously active phone id. - * @param iccId ICCID of the SIM. - */ - public void updateSimStateForInactivePort(int phoneId, String iccId) { - if (SubscriptionManager.isValidPhoneId(phoneId)) { + static void updateInternalIccStateForInactivePort( + Context context, int prevActivePhoneId, String iccId) { + if (SubscriptionManager.isValidPhoneId(prevActivePhoneId)) { // Mark SIM state as ABSENT on previously phoneId. - mTelephonyManager.setSimStateForPhone(phoneId, + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + telephonyManager.setSimStateForPhone(prevActivePhoneId, IccCardConstants.State.ABSENT.toString()); } - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().updateSimStateForInactivePort(phoneId); + SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); + if (subInfoUpdator != null) { + subInfoUpdator.updateInternalIccStateForInactivePort(prevActivePhoneId, iccId); } else { - SubscriptionInfoUpdater subInfoUpdater = PhoneFactory.getSubscriptionInfoUpdater(); - if (subInfoUpdater != null) { - subInfoUpdater.updateInternalIccStateForInactivePort(phoneId, iccId); - } else { - Rlog.e(LOG_TAG, "subInfoUpdate is null."); - } + Rlog.e(LOG_TAG, "subInfoUpdate is null."); } } - /** - * Broadcast the legacy SIM state changed event. - * - * @param phoneId The phone id. - * @param state The legacy SIM state. - * @param reason The reason of SIM state change. - */ - private void broadcastSimStateChanged(int phoneId, @NonNull String state, - @Nullable String reason) { - // Note: This intent is way deprecated and is only being kept around because there's no - // graceful way to deprecate a sticky broadcast that has a lot of listeners. - // DO NOT add any new extras to this broadcast -- it is not protected by any permissions. - Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); - intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state); - intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); - Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " - + reason + " for phone: " + phoneId); - IntentBroadcaster.getInstance().broadcastStickyIntent(mContext, intent, phoneId); - } + static void updateInternalIccState(Context context, IccCardConstants.State state, String reason, + int phoneId) { + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + telephonyManager.setSimStateForPhone(phoneId, state.toString()); - /** - * Broadcast SIM card state changed event. - * - * @param phoneId The phone id. - * @param state The SIM card state. - */ - private void broadcastSimCardStateChanged(int phoneId, @SimState int state) { - if (state != mSimCardState[phoneId]) { - mSimCardState[phoneId] = state; - Intent intent = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); - // TODO(b/130664115) we manually populate this intent with the slotId. In the future we - // should do a review of whether to make this public - UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); - int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); - intent.putExtra(PhoneConstants.SLOT_KEY, slotId); - if (slot != null) { - intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); - } - Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " - + TelephonyManager.simStateToString(state) + " for phone: " + phoneId - + " slot: " + slotId + " port: " + slot.getPortIndexFromPhoneId(phoneId)); - mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - TelephonyMetrics.getInstance().updateSimState(phoneId, state); - } - } - - /** - * Broadcast SIM application state changed event. - * - * @param phoneId The phone id. - * @param state The SIM application state. - */ - private void broadcastSimApplicationStateChanged(int phoneId, @SimState int state) { - // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY, - // because that's the initial state and a broadcast should be sent only on a transition - // after SIM is PRESENT. The only exception is eSIM boot profile, where NOT_READY is the - // terminal state. - boolean isUnknownToNotReady = - (mSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN - && state == TelephonyManager.SIM_STATE_NOT_READY); - IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); - boolean emptyProfile = iccCard != null && iccCard.isEmptyProfile(); - if (state != mSimApplicationState[phoneId] && (!isUnknownToNotReady || emptyProfile)) { - mSimApplicationState[phoneId] = state; - Intent intent = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); - // TODO(b/130664115) we populate this intent with the actual slotId. In the future we - // should do a review of whether to make this public - UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); - int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); - intent.putExtra(PhoneConstants.SLOT_KEY, slotId); - if (slot != null) { - intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); - } - Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " - + TelephonyManager.simStateToString(state) - + " for phone: " + phoneId + " slot: " + slotId + "port: " - + slot.getPortIndexFromPhoneId(phoneId)); - mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - TelephonyMetrics.getInstance().updateSimState(phoneId, state); - } - } - - /** - * Get SIM state from SIM lock reason. - * - * @param lockedReason The SIM lock reason. - * - * @return The SIM state. - */ - @SimState - private static int getSimStateFromLockedReason(String lockedReason) { - switch (lockedReason) { - case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN: - return TelephonyManager.SIM_STATE_PIN_REQUIRED; - case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK: - return TelephonyManager.SIM_STATE_PUK_REQUIRED; - case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK: - return TelephonyManager.SIM_STATE_NETWORK_LOCKED; - case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED: - return TelephonyManager.SIM_STATE_PERM_DISABLED; - default: - Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason); - return TelephonyManager.SIM_STATE_UNKNOWN; - } - } - - /** - * Broadcast SIM state events. - * - * @param phoneId The phone id. - * @param simState The SIM state. - * @param reason SIM state changed reason. - */ - private void broadcastSimStateEvents(int phoneId, IccCardConstants.State simState, - @Nullable String reason) { - String legacyStringSimState = getIccStateIntentString(simState); - int cardState = TelephonyManager.SIM_STATE_UNKNOWN; - int applicationState = TelephonyManager.SIM_STATE_UNKNOWN; - - switch (simState) { - case ABSENT: - cardState = TelephonyManager.SIM_STATE_ABSENT; - break; - case PIN_REQUIRED: - case PUK_REQUIRED: - case NETWORK_LOCKED: - case PERM_DISABLED: - cardState = TelephonyManager.SIM_STATE_PRESENT; - applicationState = getSimStateFromLockedReason(reason); - break; - case READY: - case NOT_READY: - // Both READY and NOT_READY have the same card state and application state. - cardState = TelephonyManager.SIM_STATE_PRESENT; - applicationState = TelephonyManager.SIM_STATE_NOT_READY; - break; - case CARD_IO_ERROR: - cardState = TelephonyManager.SIM_STATE_CARD_IO_ERROR; - applicationState = TelephonyManager.SIM_STATE_NOT_READY; - break; - case CARD_RESTRICTED: - cardState = TelephonyManager.SIM_STATE_CARD_RESTRICTED; - applicationState = TelephonyManager.SIM_STATE_NOT_READY; - break; - case LOADED: - cardState = TelephonyManager.SIM_STATE_PRESENT; - applicationState = TelephonyManager.SIM_STATE_LOADED; - break; - case UNKNOWN: - default: - break; - } - - broadcastSimStateChanged(phoneId, legacyStringSimState, reason); - broadcastSimCardStateChanged(phoneId, cardState); - broadcastSimApplicationStateChanged(phoneId, applicationState); - } - - /** - * Update carrier service. - * - * @param phoneId The phone id. - * @param simState The SIM state. - */ - private void updateCarrierServices(int phoneId, @NonNull String simState) { - CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class); - if (configManager != null) { - configManager.updateConfigForPhoneId(phoneId, simState); - } - mCarrierServiceBindHelper.updateSimState(phoneId, simState); - } - - /** - * Check if the SIM application is enabled on the card or not. - * - * @param phoneId The phone id. - * @return {@code true} if the application is enabled. - */ - private boolean areUiccAppsEnabledOnCard(int phoneId) { - // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from - // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another - // handleSimNotReady so this will be evaluated again. - UiccSlot slot = getUiccSlotForPhone(phoneId); - if (slot == null) return false; - UiccPort port = getUiccPort(phoneId); - String iccId = (port == null) ? null : port.getIccId(); - if (iccId == null) { - return false; - } - SubscriptionInfo info = SubscriptionManagerService.getInstance() - .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) - .stream().filter(subInfo -> subInfo.getIccId().equals( - IccUtils.stripTrailingFs(iccId))) - .findFirst().orElse(null); - return info != null && info.areUiccApplicationsEnabled(); - } - - /** - * Update the SIM state. - * - * @param phoneId Phone id. - * @param state SIM state (legacy). - * @param reason The reason for SIM state update. - */ - public void updateSimState(int phoneId, @NonNull IccCardConstants.State state, - @Nullable String reason) { - log("updateSimState: phoneId=" + phoneId + ", state=" + state + ", reason=" + reason); - if (!SubscriptionManager.isValidPhoneId(phoneId)) { - Rlog.e(LOG_TAG, "updateInternalIccState: Invalid phone id " + phoneId); - return; - } - - mTelephonyManager.setSimStateForPhone(phoneId, state.toString()); - - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - String legacySimState = getIccStateIntentString(state); - int simState = state.ordinal(); - SubscriptionManagerService.getInstance().updateSimState(phoneId, simState, this::post, - () -> { - // The following are executed after subscription update completed in - // subscription manager service. - - broadcastSimStateEvents(phoneId, state, reason); - - UiccProfile uiccProfile = getUiccProfileForPhone(phoneId); - - if (simState == TelephonyManager.SIM_STATE_READY) { - // SIM_STATE_READY is not a final state. - return; - } - - if (simState == TelephonyManager.SIM_STATE_NOT_READY - && (uiccProfile != null && !uiccProfile.isEmptyProfile()) - && areUiccAppsEnabledOnCard(phoneId)) { - // STATE_NOT_READY is not a final state for when both - // 1) It's not an empty profile, and - // 2) Its uicc applications are set to enabled. - // - // At this phase, we consider STATE_NOT_READY not a final state, so - // return for now. - log("updateSimState: SIM_STATE_NOT_READY is not a final state."); - return; - } - - // At this point, the SIM state must be a final state (meaning we won't - // get more SIM state updates). So resolve the carrier id and update the - // carrier services. - log("updateSimState: resolve carrier id and update carrier services."); - PhoneFactory.getPhone(phoneId).resolveSubscriptionCarrierId(legacySimState); - updateCarrierServices(phoneId, legacySimState); - } - ); + SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); + if (subInfoUpdator != null) { + subInfoUpdator.updateInternalIccState(getIccStateIntentString(state), reason, phoneId); } else { - SubscriptionInfoUpdater subInfoUpdater = PhoneFactory.getSubscriptionInfoUpdater(); - if (subInfoUpdater != null) { - subInfoUpdater.updateInternalIccState(getIccStateIntentString(state), reason, - phoneId); - } else { - Rlog.e(LOG_TAG, "subInfoUpdate is null."); - } + Rlog.e(LOG_TAG, "subInfoUpdate is null."); } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index d9ff3f15d6..d882e49d01 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -802,8 +802,8 @@ public class UiccProfile extends IccCard { } log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState); - UiccController.getInstance().updateSimState(mPhoneId, mExternalState, - getIccStateReason(mExternalState)); + UiccController.updateInternalIccState(mContext, mExternalState, + getIccStateReason(mExternalState), mPhoneId); } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index 069a29d251..ec4919609c 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -195,7 +195,7 @@ public class UiccSlot extends Handler { if (!iss.mSimPortInfos[i].mPortActive) { // TODO: (b/79432584) evaluate whether should broadcast card state change // even if it's inactive. - UiccController.getInstance().updateSimStateForInactivePort( + UiccController.updateInternalIccStateForInactivePort(mContext, mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID), iss.mSimPortInfos[i].mIccId); mLastRadioState.put(i, TelephonyManager.RADIO_POWER_UNAVAILABLE); @@ -330,8 +330,8 @@ public class UiccSlot extends Handler { if (DBG) log("update: notify card removed"); sendMessage(obtainMessage(EVENT_CARD_REMOVED, null)); } - UiccController.getInstance().updateSimState(phoneId, IccCardConstants.State.ABSENT, - null); + UiccController.updateInternalIccState(mContext, IccCardConstants.State.ABSENT, + null, phoneId); // no card present in the slot now; dispose card and make mUiccCard null nullifyUiccCard(false /* sim state is not unknown */); mLastRadioState.put(portIndex, TelephonyManager.RADIO_POWER_UNAVAILABLE); @@ -592,8 +592,8 @@ public class UiccSlot extends Handler { nullifyUiccCard(true /* sim state is unknown */); if (phoneId != INVALID_PHONE_ID) { - UiccController.getInstance().updateSimState(phoneId, - IccCardConstants.State.UNKNOWN, null); + UiccController.updateInternalIccState( + mContext, IccCardConstants.State.UNKNOWN, null, phoneId); mLastRadioState.put(getPortIndexFromPhoneId(phoneId), TelephonyManager.RADIO_POWER_UNAVAILABLE); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java index 87b29840f0..6aab7ad9d0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java @@ -158,7 +158,8 @@ public class UiccSlotTest extends TelephonyTest { assertTrue(mUiccSlot.isActive()); assertNull(mUiccSlot.getUiccCard()); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); } @Test @@ -379,7 +380,8 @@ public class UiccSlotTest extends TelephonyTest { // Make sure when received CARDSTATE_ABSENT state in the first time, mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); } @@ -412,7 +414,7 @@ public class UiccSlotTest extends TelephonyTest { assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); // assert that we tried to update subscriptions - verify(mUiccController).updateSimStateForInactivePort( + verify(mSubInfoRecordUpdater).updateInternalIccStateForInactivePort( activeIss.mSimPortInfos[0].mLogicalSlotIndex, inactiveIss.mSimPortInfos[0].mIccId); } @@ -433,10 +435,11 @@ public class UiccSlotTest extends TelephonyTest { assertNotNull(mUiccSlot.getUiccCard()); // Simulate when SIM is removed, UiccCard and UiccProfile should be disposed and ABSENT - // state is sent to UiccController. + // state is sent to SubscriptionInfoUpdater. mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); verify(mUiccProfile).dispose(); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); @@ -459,8 +462,9 @@ public class UiccSlotTest extends TelephonyTest { // radio state unavailable mUiccSlot.onRadioStateUnavailable(phoneId); - // Verify that UNKNOWN state is sent to UiccController in this case. - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.UNKNOWN, null); + // Verify that UNKNOWN state is sent to SubscriptionInfoUpdater in this case. + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null, phoneId); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); @@ -468,8 +472,9 @@ public class UiccSlotTest extends TelephonyTest { mIccCardStatus.mCardState = CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - // Verify that ABSENT state is sent to UiccController in this case. - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + // Verify that ABSENT state is sent to SubscriptionInfoUpdater in this case. + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); } -- GitLab From 43ff289535f6bd38626c0e2bd66fd5ab83be20ea Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 5 Jan 2023 15:06:57 -0800 Subject: [PATCH 317/656] Update override network type after service state changes Previously, if the data rat was the same after a service state change, we would not do anything since the state is the same. However, the override network type could be different. Make sure to update the override network type (either directly or through a transition) whenever the service state changes. Test: atest NetworkTypeControllerTest Bug: 263678417 Change-Id: I74fb8f483a2dec281d16f86bf0f16e19acae9221 --- .../telephony/NetworkTypeController.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index c02a9c3e58..4fd3054f92 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -743,7 +743,8 @@ public class NetworkTypeController extends StateMachine { // fallthrough case EVENT_UPDATE: int rat = getDataNetworkType(); - if (rat == TelephonyManager.NETWORK_TYPE_NR || isLte(rat) && isNrConnected()) { + if (rat == TelephonyManager.NETWORK_TYPE_NR + || (isLte(rat) && isNrConnected())) { if (isNrAdvanced()) { transitionTo(mNrConnectedAdvancedState); } else { @@ -755,7 +756,7 @@ public class NetworkTypeController extends StateMachine { if (isPhysicalLinkActive()) { transitionWithTimerTo(mLteConnectedState); } else { - // Update in case of LTE/LTE+ switch + // Update in case the override network type changed updateOverrideNetworkType(); } } @@ -839,7 +840,7 @@ public class NetworkTypeController extends StateMachine { if (!isPhysicalLinkActive()) { transitionWithTimerTo(mIdleState); } else { - // Update in case of LTE/LTE+ switch + // Update in case the override network type changed updateOverrideNetworkType(); } } @@ -910,11 +911,13 @@ public class NetworkTypeController extends StateMachine { // fallthrough case EVENT_UPDATE: int rat = getDataNetworkType(); - if (rat == TelephonyManager.NETWORK_TYPE_NR || isLte(rat) && isNrConnected()) { + if (rat == TelephonyManager.NETWORK_TYPE_NR + || (isLte(rat) && isNrConnected())) { if (isNrAdvanced()) { transitionTo(mNrConnectedAdvancedState); } else { - // Same NR connected state + // Update in case the override network type changed + updateOverrideNetworkType(); } } else if (isLte(rat) && isNrNotRestricted()) { transitionWithTimerTo(isPhysicalLinkActive() @@ -985,7 +988,8 @@ public class NetworkTypeController extends StateMachine { if (rat == TelephonyManager.NETWORK_TYPE_NR || (isLte(rat) && isNrConnected())) { if (isNrAdvanced()) { - // Same NR advanced state + // Update in case the override network type changed + updateOverrideNetworkType(); } else { transitionWithTimerTo(mNrConnectedState); } -- GitLab From a4d2bb479e2634ed1922887d12b9fb34a43d0fd6 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Mon, 28 Nov 2022 15:52:50 +0000 Subject: [PATCH 318/656] Moved SmscIdentity to SMSManager also made it SystemApi Bug: 260577776 Test: atest frameworks/opt/telephony/tests/telephonytests/src/com/android/internal/telephony Change-Id: I57dcedad1b4f74061c8c86d38cfa076e3867696c --- .../telephony/PhoneSubInfoController.java | 40 +++++++++++-------- .../telephony/PhoneSubInfoControllerTest.java | 38 +++++++++--------- 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java index 804461b589..fafa245cd1 100644 --- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java +++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java @@ -27,6 +27,7 @@ import android.app.AppOpsManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; +import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.RemoteException; @@ -624,27 +625,34 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { } /** - * Returns SIP URI or tel URI of the Public Service Identity of the SM-SC that fetched from - * EFPSISMSC elementary field that are loaded based on the ISIM/USIM appType. + * Returns SIP URI or tel URI of the Public Service Identity of the SM-SC fetched from + * EF_PSISMSC elementary field as defined in Section 4.5.9 (3GPP TS 31.102). + * @throws IllegalStateException in case if phone or UiccApplication is not available. */ - public String getSmscIdentity(int subId, int appType) - throws RemoteException { - return callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getSmscIdentity", + public Uri getSmscIdentity(int subId, int appType) throws RemoteException { + Uri smscIdentityUri = callPhoneMethodForSubIdWithPrivilegedCheck(subId, "getSmscIdentity", (phone) -> { - UiccPort uiccPort = phone.getUiccPort(); - if (uiccPort == null || uiccPort.getUiccProfile() == null) { - loge("getSmscIdentity(): uiccPort or uiccProfile is null"); + try { + String smscIdentity = null; + UiccPort uiccPort = phone.getUiccPort(); + UiccCardApplication uiccApp = + uiccPort.getUiccProfile().getApplicationByType( + appType); + smscIdentity = (uiccApp != null) ? uiccApp.getIccRecords().getSmscIdentity() + : null; + if (TextUtils.isEmpty(smscIdentity)) { + return Uri.EMPTY; + } + return Uri.parse(smscIdentity); + } catch (NullPointerException ex) { + Rlog.e(TAG, "getSmscIdentity(): Exception = " + ex); return null; } - UiccCardApplication uiccApp = uiccPort.getUiccProfile().getApplicationByType( - appType); - if (uiccApp == null) { - loge("getSmscIdentity(): no app with specified type = " - + appType); - return null; - } - return uiccApp.getIccRecords().getSmscIdentity(); }); + if (smscIdentityUri == null) { + throw new IllegalStateException("Telephony service error"); + } + return smscIdentityUri; } private void log(String s) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java index 5eaead53ff..e4c1466127 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java @@ -17,6 +17,8 @@ package com.android.internal.telephony; import static android.Manifest.permission.READ_PHONE_STATE; import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; +import static android.telephony.TelephonyManager.APPTYPE_ISIM; +import static android.telephony.TelephonyManager.APPTYPE_USIM; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -52,9 +54,9 @@ import org.mockito.Mockito; public class PhoneSubInfoControllerTest extends TelephonyTest { private static final String FEATURE_ID = "myfeatureId"; private static final String PSI_SMSC_TEL1 = "tel:+91123456789"; - private static final String PSI_SMSC_SIP1 = "sip:+1234567890@msg.pc.t-mobile.com;user=phone"; + private static final String PSI_SMSC_SIP1 = "sip:+1234567890@abc.pc.operetor1.com;user=phone"; private static final String PSI_SMSC_TEL2 = "tel:+91987654321"; - private static final String PSI_SMSC_SIP2 = "sip:+19876543210@msg.pc.t-mobile.com;user=phone"; + private static final String PSI_SMSC_SIP2 = "sip:+19876543210@dcf.pc.operetor2.com;user=phone"; private PhoneSubInfoController mPhoneSubInfoControllerUT; private AppOpsManager mAppOsMgr; @@ -965,13 +967,13 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { try { setUpInitials(); assertEquals(PSI_SMSC_TEL1, mPhoneSubInfoControllerUT - .getSmscIdentity(0, 5)); + .getSmscIdentity(0, APPTYPE_ISIM).toString()); assertEquals(PSI_SMSC_TEL1, mPhoneSubInfoControllerUT - .getSmscIdentity(0, 3)); + .getSmscIdentity(0, APPTYPE_USIM).toString()); assertEquals(PSI_SMSC_TEL2, mPhoneSubInfoControllerUT - .getSmscIdentity(1, 5)); + .getSmscIdentity(1, APPTYPE_ISIM).toString()); assertEquals(PSI_SMSC_TEL2, mPhoneSubInfoControllerUT - .getSmscIdentity(1, 5)); + .getSmscIdentity(1, APPTYPE_USIM).toString()); } catch (RemoteException e) { e.printStackTrace(); } @@ -1003,13 +1005,13 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { doReturn(PSI_SMSC_SIP2).when(mIsimUiccRecords).getSmscIdentity(); assertEquals(PSI_SMSC_SIP1, mPhoneSubInfoControllerUT - .getSmscIdentity(0, 5)); + .getSmscIdentity(0, APPTYPE_ISIM).toString()); assertEquals(PSI_SMSC_SIP1, mPhoneSubInfoControllerUT - .getSmscIdentity(0, 3)); + .getSmscIdentity(0, APPTYPE_USIM).toString()); assertEquals(PSI_SMSC_SIP2, mPhoneSubInfoControllerUT - .getSmscIdentity(1, 5)); + .getSmscIdentity(1, APPTYPE_ISIM).toString()); assertEquals(PSI_SMSC_SIP2, mPhoneSubInfoControllerUT - .getSmscIdentity(1, 5)); + .getSmscIdentity(1, APPTYPE_USIM).toString()); } catch (RemoteException e) { e.printStackTrace(); } @@ -1022,7 +1024,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { //case 1: no READ_PRIVILEGED_PHONE_STATE & appOsMgr READ_PHONE_PERMISSION mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); try { - mPhoneSubInfoControllerUT.getSmscIdentity(0, 5); + mPhoneSubInfoControllerUT.getSmscIdentity(0, APPTYPE_ISIM); Assert.fail("expected Security Exception Thrown"); } catch (Exception ex) { assertTrue(ex instanceof SecurityException); @@ -1030,7 +1032,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { } try { - mPhoneSubInfoControllerUT.getSmscIdentity(1, 5); + mPhoneSubInfoControllerUT.getSmscIdentity(1, APPTYPE_ISIM); Assert.fail("expected Security Exception Thrown"); } catch (Exception ex) { assertTrue(ex instanceof SecurityException); @@ -1038,7 +1040,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { } try { - mPhoneSubInfoControllerUT.getSmscIdentity(0, 3); + mPhoneSubInfoControllerUT.getSmscIdentity(0, APPTYPE_USIM); Assert.fail("expected Security Exception Thrown"); } catch (Exception ex) { assertTrue(ex instanceof SecurityException); @@ -1046,7 +1048,7 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { } try { - mPhoneSubInfoControllerUT.getSmscIdentity(1, 3); + mPhoneSubInfoControllerUT.getSmscIdentity(1, APPTYPE_USIM); Assert.fail("expected Security Exception Thrown"); } catch (Exception ex) { assertTrue(ex instanceof SecurityException); @@ -1061,13 +1063,13 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { try { assertEquals(PSI_SMSC_TEL1, mPhoneSubInfoControllerUT - .getSmscIdentity(0, 5)); + .getSmscIdentity(0, APPTYPE_ISIM).toString()); assertEquals(PSI_SMSC_TEL1, mPhoneSubInfoControllerUT - .getSmscIdentity(0, 3)); + .getSmscIdentity(0, APPTYPE_USIM).toString()); assertEquals(PSI_SMSC_TEL2, mPhoneSubInfoControllerUT - .getSmscIdentity(1, 5)); + .getSmscIdentity(1, APPTYPE_ISIM).toString()); assertEquals(PSI_SMSC_TEL2, mPhoneSubInfoControllerUT - .getSmscIdentity(1, 5)); + .getSmscIdentity(1, APPTYPE_USIM).toString()); } catch (RemoteException e) { e.printStackTrace(); } -- GitLab From 35f6f041fede31b2bc18ab9159a817d721d2b5c0 Mon Sep 17 00:00:00 2001 From: Gil Cukierman Date: Fri, 6 Jan 2023 19:19:31 +0000 Subject: [PATCH 319/656] Track Modem Support for Null Cipher Disablement in Phone Adds Phone.isNullCipherAndIntegritySupported which, by default, is initialized to false in Phone (no support). When the radio becomes available, it attempts to make a request to set the user's null cipher and integrity preferences. If the response is anything other than a REQUEST_NOT_SUPPORTED exception, the phone then considers the feature supported by the modem. Bug: 264574296 Test: atest GsmCdmaPhoneTest Change-Id: Ib3ba1aa28da35758dbdf585704d929c9bc45ff97 --- .../internal/telephony/GsmCdmaPhone.java | 15 ++++++ .../com/android/internal/telephony/Phone.java | 8 ++++ .../internal/telephony/GsmCdmaPhoneTest.java | 47 ++++++++++++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index e325678589..89cbb10d79 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -242,6 +242,8 @@ public class GsmCdmaPhone extends Phone { CellBroadcastConfigTracker mCellBroadcastConfigTracker = CellBroadcastConfigTracker.make(this, null); + private boolean mIsNullCipherAndIntegritySupported = false; + // Create Cfu (Call forward unconditional) so that dialing number & // mOnComplete (Message object passed by client) can be packed & // given as a single Cfu object as user data to RIL. @@ -3440,6 +3442,14 @@ public class GsmCdmaPhone extends Phone { break; case EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE: logd("EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE"); + ar = (AsyncResult) msg.obj; + if (ar == null || ar.exception == null) { + mIsNullCipherAndIntegritySupported = true; + return; + } + CommandException.Error error = ((CommandException) ar.exception).getCommandError(); + mIsNullCipherAndIntegritySupported = !error.equals( + CommandException.Error.REQUEST_NOT_SUPPORTED); break; case EVENT_IMS_DEREGISTRATION_TRIGGERED: @@ -5034,4 +5044,9 @@ public class GsmCdmaPhone extends Phone { getNullCipherAndIntegrityEnabledPreference(), obtainMessage(EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE)); } + + @Override + public boolean isNullCipherAndIntegritySupported() { + return mIsNullCipherAndIntegritySupported; + } } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 7d3691a6ad..ed4214d354 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5157,6 +5157,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return sp.getBoolean(PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED, true); } + /** + * @return whether or not this Phone interacts with a modem that supports the null cipher + * and integrity feature. + */ + public boolean isNullCipherAndIntegritySupported() { + return false; + } + /** * Override to implement handling of an update to the enablement of the null cipher and * integrity preference. diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index c7f943a22a..903d82ce2e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -22,6 +22,7 @@ import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDI import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED; import static com.android.internal.telephony.Phone.EVENT_IMS_DEREGISTRATION_TRIGGERED; import static com.android.internal.telephony.Phone.EVENT_RADIO_AVAILABLE; +import static com.android.internal.telephony.Phone.EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE; import static com.android.internal.telephony.Phone.EVENT_SRVCC_STATE_CHANGED; import static com.android.internal.telephony.Phone.EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; @@ -2109,6 +2110,51 @@ public class GsmCdmaPhoneTest extends TelephonyTest { fdnCheckCleanup(); } + @Test + public void testHandleNullCipherAndIntegrityEnabled_radioFeatureUnsupported() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_CELLULAR_SECURITY, + TelephonyManager.PROPERTY_ENABLE_NULL_CIPHER_TOGGLE, Boolean.TRUE.toString(), + false); + mPhoneUT.mCi = mMockCi; + assertFalse(mPhoneUT.isNullCipherAndIntegritySupported()); + + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(EVENT_RADIO_AVAILABLE, + new AsyncResult(null, new int[]{ServiceState.RIL_RADIO_TECHNOLOGY_GSM}, null))); + processAllMessages(); + + verify(mMockCi, times(1)).setNullCipherAndIntegrityEnabled(anyBoolean(), + any(Message.class)); + + // Some ephemeral error occurred in the modem, but the feature was supported + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE, + new AsyncResult(null, null, + new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED)))); + processAllMessages(); + assertFalse(mPhoneUT.isNullCipherAndIntegritySupported()); + } + + @Test + public void testHandleNullCipherAndIntegrityEnabled_radioSupportsFeature() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_CELLULAR_SECURITY, + TelephonyManager.PROPERTY_ENABLE_NULL_CIPHER_TOGGLE, Boolean.TRUE.toString(), + false); + mPhoneUT.mCi = mMockCi; + assertFalse(mPhoneUT.isNullCipherAndIntegritySupported()); + + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(EVENT_RADIO_AVAILABLE, + new AsyncResult(null, new int[]{ServiceState.RIL_RADIO_TECHNOLOGY_GSM}, null))); + processAllMessages(); + + verify(mMockCi, times(1)).setNullCipherAndIntegrityEnabled(anyBoolean(), + any(Message.class)); + + // Some ephemeral error occurred in the modem, but the feature was supported + mPhoneUT.sendMessage(mPhoneUT.obtainMessage(EVENT_SET_NULL_CIPHER_AND_INTEGRITY_DONE, + new AsyncResult(null, null, null))); + processAllMessages(); + assertTrue(mPhoneUT.isNullCipherAndIntegritySupported()); + } + @Test public void testHandleNullCipherAndIntegrityEnabled_featureFlagOn() { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_CELLULAR_SECURITY, @@ -2137,7 +2183,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { verify(mMockCi, times(0)).setNullCipherAndIntegrityEnabled(anyBoolean(), any(Message.class)); - } public void fdnCheckCleanup() { -- GitLab From ab94af18c02dceea264428b8d62f6184bdc25f49 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 8 Jan 2023 18:49:16 -0800 Subject: [PATCH 320/656] Moved SIM state broadcast back to UiccController Moved the SIM related stuffs back to UiccController. SubscriptionManagerService will mainly handle subscription related stuffs. The same SIM state broadcast is ported from SubscriptionInfoUpdater. This CL is exactly same as the reverted ag/20770404 except 1. Removed the lock in getInstance. The instance is just a reference and should not be updated after created. 2. Seperate the old code with the feature flag with more conservative approach. 3. Update the SIM state with handler. Bug: 239607619 Test: Manual Change-Id: Ifb085003087aa1e270925c755fc6e819f0871dc0 --- .../telephony/CarrierServiceBindHelper.java | 9 +- .../SubscriptionManagerService.java | 144 +++++++- .../telephony/uicc/UiccController.java | 336 +++++++++++++++++- .../internal/telephony/uicc/UiccProfile.java | 9 +- .../internal/telephony/uicc/UiccSlot.java | 31 +- 5 files changed, 511 insertions(+), 18 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java index dfa53b3958..960d794303 100644 --- a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java +++ b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -200,7 +201,13 @@ public class CarrierServiceBindHelper { } } - void updateForPhoneId(int phoneId, String simState) { + /** + * Update SIM state. + * + * @param phoneId The phone id. + * @param simState The legacy SIM state. + */ + public void updateForPhoneId(int phoneId, @NonNull String simState) { logdWithLocalLog("update binding for phoneId: " + phoneId + " simState: " + simState); if (!SubscriptionManager.isValidPhoneId(phoneId)) { return; diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 5be96c1234..9e314280e0 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -59,6 +59,7 @@ import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.SimState; import android.telephony.TelephonyRegistryManager; import android.telephony.UiccAccessRule; import android.telephony.euicc.EuiccManager; @@ -427,6 +428,10 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public void onDatabaseLoaded() { log("Subscription database has been loaded."); + for (int phoneId = 0; phoneId < mTelephonyManager.getActiveModemCount() + ; phoneId++) { + markSubscriptionsInactive(phoneId); + } } /** @@ -826,7 +831,7 @@ public class SubscriptionManagerService extends ISub.Stub { /** * Mark all subscriptions on this SIM slot index inactive. * - * @param simSlotIndex The SIM slot index. + * @param simSlotIndex The logical SIM slot index (i.e. phone id). */ public void markSubscriptionsInactive(int simSlotIndex) { mSubscriptionDatabaseManager.getAllSubscriptions().stream() @@ -985,6 +990,15 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Update the subscriptions on the logical SIM slot index (i.e. phone id). + * + * @param slotIndex The logical SIM slot index. + */ + private void updateSubscriptions(int slotIndex) { + + } + /** * Get all subscription info records from SIMs that are inserted now or previously inserted. * @@ -3174,6 +3188,134 @@ public class SubscriptionManagerService extends ISub.Stub { ? subscriptionInfoInternal.toSubscriptionInfo() : null; } + /** + * Called when SIM state changed to absent. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimAbsent(int slotIndex) { + if (mSlotIndexToSubId.containsKey(slotIndex)) { + // Re-enable the SIM when it's removed, so it will be in enabled state when it gets + // re-inserted again. (pre-U behavior) + mSubscriptionDatabaseManager.setUiccApplicationsEnabled( + mSlotIndexToSubId.get(slotIndex), true); + // When sim is absent, set the port index to invalid port index. (pre-U behavior) + mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(slotIndex), + TelephonyManager.INVALID_PORT_INDEX); + } + updateSubscriptions(slotIndex); + } + + /** + * Called when SIM state changed to locked. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimLocked(int slotIndex) { + + } + + /** + * Called when SIM state changed to ready. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimReady(int slotIndex) { + + } + + /** + * Called when SIM state changed to not ready. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimNotReady(int slotIndex) { + + } + + /** + * Called when SIM encounters error. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimError(int slotIndex) { + + } + + /** + * Called when SIM state changed to loaded. + * + * @param slotIndex The logical SIM slot index. + */ + private void onSimLoaded(int slotIndex) { + } + + /** + * Called when eSIM becomes inactive. + * + * @param slotIndex The logical SIM slot index. + */ + public void updateSimStateForInactivePort(int slotIndex) { + mHandler.post(() -> { + if (mSlotIndexToSubId.containsKey(slotIndex)) { + // Re-enable the UICC application , so it will be in enabled state when it becomes + // active again. (pre-U behavior) + mSubscriptionDatabaseManager.setUiccApplicationsEnabled( + mSlotIndexToSubId.get(slotIndex), true); + updateSubscriptions(slotIndex); + } + }); + } + + /** + * Update SIM state. This method is supposed to be called by {@link UiccController} only. + * + * @param slotIndex The logical SIM slot index. + * @param simState SIM state. + * @param executor The executor to execute the callback. + * @param updateCompleteCallback The callback to call when subscription manager service + * completes subscription update. SIM state changed event will be broadcasted by + * {@link UiccController} upon receiving callback. + */ + public void updateSimState(int slotIndex, @SimState int simState, + @Nullable @CallbackExecutor Executor executor, + @Nullable Runnable updateCompleteCallback) { + mHandler.post(() -> { + switch (simState) { + case TelephonyManager.SIM_STATE_ABSENT: + onSimAbsent(slotIndex); + break; + case TelephonyManager.SIM_STATE_PIN_REQUIRED: + case TelephonyManager.SIM_STATE_PUK_REQUIRED: + case TelephonyManager.SIM_STATE_NETWORK_LOCKED: + case TelephonyManager.SIM_STATE_PERM_DISABLED: + onSimLocked(slotIndex); + break; + case TelephonyManager.SIM_STATE_READY: + onSimReady(slotIndex); + break; + case TelephonyManager.SIM_STATE_NOT_READY: + onSimNotReady(slotIndex); + break; + case TelephonyManager.SIM_STATE_CARD_IO_ERROR: + onSimError(slotIndex); + break; + case TelephonyManager.SIM_STATE_CARD_RESTRICTED: + // No specific things needed to be done. Just return and broadcast the SIM + // states. + break; + case TelephonyManager.SIM_STATE_LOADED: + onSimLoaded(slotIndex); + break; + default: + break; + } + if (executor != null && updateCompleteCallback != null) { + executor.execute(updateCompleteCallback); + } + }); + } + /** * Log debug messages. * diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index ea99d9a3f6..a28142cb59 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -21,6 +21,8 @@ import static android.telephony.TelephonyManager.UNSUPPORTED_CARD_ID; import static java.util.Arrays.copyOf; +import android.Manifest; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.BroadcastOptions; import android.compat.annotation.UnsupportedAppUsage; @@ -38,8 +40,10 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.TelephonyManager.SimState; import android.telephony.UiccCardInfo; import android.telephony.UiccPortInfo; import android.telephony.UiccSlotMapping; @@ -49,14 +53,20 @@ import android.util.LocalLog; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.CarrierServiceBindHelper; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccCardConstants; +import com.android.internal.telephony.IntentBroadcaster; import com.android.internal.telephony.PhoneConfigurationManager; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.SubscriptionInfoUpdater; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.euicc.EuiccCard; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -140,6 +150,9 @@ public class UiccController extends Handler { private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 10; // NOTE: any new EVENT_* values must be added to eventToString. + @NonNull + private final TelephonyManager mTelephonyManager; + // this needs to be here, because on bootup we dont know which index maps to which UiccSlot @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private CommandsInterface[] mCis; @@ -151,11 +164,25 @@ public class UiccController extends Handler { // This maps the externally exposed card ID (int) to the internal card ID string (ICCID/EID). // The array index is the card ID (int). // This mapping exists to expose card-based functionality without exposing the EID, which is - // considered sensetive information. + // considered sensitive information. // mCardStrings is populated using values from the IccSlotStatus and IccCardStatus. For // HAL < 1.2, these do not contain the EID or the ICCID, so mCardStrings will be empty private ArrayList mCardStrings; + /** + * SIM card state. + */ + @NonNull + @SimState + private final int[] mSimCardState; + + /** + * SIM application state. + */ + @NonNull + @SimState + private final int[] mSimApplicationState; + // This is the card ID of the default eUICC. It starts as UNINITIALIZED_CARD_ID. // When we load the EID (either with slot status or from the EuiccCard), we set it to the eUICC // with the lowest slot index. @@ -205,6 +232,9 @@ public class UiccController extends Handler { protected RegistrantList mIccChangedRegistrants = new RegistrantList(); + @NonNull + private final CarrierServiceBindHelper mCarrierServiceBindHelper; + private UiccStateChangedLauncher mLauncher; private RadioConfig mRadioConfig; @@ -243,8 +273,13 @@ public class UiccController extends Handler { numPhysicalSlots = mCis.length; } + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + mUiccSlots = new UiccSlot[numPhysicalSlots]; mPhoneIdToSlotId = new int[mCis.length]; + int supportedModemCount = mTelephonyManager.getSupportedModemCount(); + mSimCardState = new int[supportedModemCount]; + mSimApplicationState = new int[supportedModemCount]; Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID); if (VDBG) logPhoneIdToSlotIdMapping(); mRadioConfig = RadioConfig.getInstance(); @@ -260,6 +295,8 @@ public class UiccController extends Handler { mCardStrings = loadCardStrings(); mDefaultEuiccCardId = UNINITIALIZED_CARD_ID; + mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); + mEuiccSlots = mContext.getResources() .getIntArray(com.android.internal.R.array.non_removable_euicc_slots); mHasBuiltInEuicc = hasBuiltInEuicc(); @@ -300,13 +337,11 @@ public class UiccController extends Handler { @UnsupportedAppUsage public static UiccController getInstance() { - synchronized (mLock) { - if (mInstance == null) { - throw new RuntimeException( - "UiccController.getInstance can't be called before make()"); - } - return mInstance; + if (mInstance == null) { + throw new RuntimeException( + "UiccController.getInstance can't be called before make()"); } + return mInstance; } @UnsupportedAppUsage @@ -739,6 +774,293 @@ public class UiccController extends Handler { } } + /** + * Update SIM state for the inactive eSIM port. + * + * @param phoneId Previously active phone id. + * @param iccId ICCID of the SIM. + */ + public void updateSimStateForInactivePort(int phoneId, String iccId) { + post(() -> { + if (SubscriptionManager.isValidPhoneId(phoneId)) { + // Mark SIM state as ABSENT on previously phoneId. + mTelephonyManager.setSimStateForPhone(phoneId, + IccCardConstants.State.ABSENT.toString()); + } + + SubscriptionManagerService.getInstance().updateSimStateForInactivePort(phoneId); + }); + } + + /** + * Broadcast the legacy SIM state changed event. + * + * @param phoneId The phone id. + * @param state The legacy SIM state. + * @param reason The reason of SIM state change. + */ + private void broadcastSimStateChanged(int phoneId, @NonNull String state, + @Nullable String reason) { + // Note: This intent is way deprecated and is only being kept around because there's no + // graceful way to deprecate a sticky broadcast that has a lot of listeners. + // DO NOT add any new extras to this broadcast -- it is not protected by any permissions. + Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); + intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state); + intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); + SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); + Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " + + reason + " for phone: " + phoneId); + IntentBroadcaster.getInstance().broadcastStickyIntent(mContext, intent, phoneId); + } + + /** + * Broadcast SIM card state changed event. + * + * @param phoneId The phone id. + * @param state The SIM card state. + */ + private void broadcastSimCardStateChanged(int phoneId, @SimState int state) { + if (state != mSimCardState[phoneId]) { + mSimCardState[phoneId] = state; + Intent intent = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); + SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); + // TODO(b/130664115) we manually populate this intent with the slotId. In the future we + // should do a review of whether to make this public + UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); + int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); + intent.putExtra(PhoneConstants.SLOT_KEY, slotId); + if (slot != null) { + intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); + } + Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " + + TelephonyManager.simStateToString(state) + " for phone: " + phoneId + + " slot: " + slotId + " port: " + slot.getPortIndexFromPhoneId(phoneId)); + mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + TelephonyMetrics.getInstance().updateSimState(phoneId, state); + } + } + + /** + * Broadcast SIM application state changed event. + * + * @param phoneId The phone id. + * @param state The SIM application state. + */ + private void broadcastSimApplicationStateChanged(int phoneId, @SimState int state) { + // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY, + // because that's the initial state and a broadcast should be sent only on a transition + // after SIM is PRESENT. The only exception is eSIM boot profile, where NOT_READY is the + // terminal state. + boolean isUnknownToNotReady = + (mSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN + && state == TelephonyManager.SIM_STATE_NOT_READY); + IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); + boolean emptyProfile = iccCard != null && iccCard.isEmptyProfile(); + if (state != mSimApplicationState[phoneId] && (!isUnknownToNotReady || emptyProfile)) { + mSimApplicationState[phoneId] = state; + Intent intent = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); + SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId); + // TODO(b/130664115) we populate this intent with the actual slotId. In the future we + // should do a review of whether to make this public + UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); + int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); + intent.putExtra(PhoneConstants.SLOT_KEY, slotId); + if (slot != null) { + intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); + } + Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " + + TelephonyManager.simStateToString(state) + + " for phone: " + phoneId + " slot: " + slotId + "port: " + + slot.getPortIndexFromPhoneId(phoneId)); + mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + TelephonyMetrics.getInstance().updateSimState(phoneId, state); + } + } + + /** + * Get SIM state from SIM lock reason. + * + * @param lockedReason The SIM lock reason. + * + * @return The SIM state. + */ + @SimState + private static int getSimStateFromLockedReason(String lockedReason) { + switch (lockedReason) { + case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN: + return TelephonyManager.SIM_STATE_PIN_REQUIRED; + case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK: + return TelephonyManager.SIM_STATE_PUK_REQUIRED; + case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK: + return TelephonyManager.SIM_STATE_NETWORK_LOCKED; + case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED: + return TelephonyManager.SIM_STATE_PERM_DISABLED; + default: + Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason); + return TelephonyManager.SIM_STATE_UNKNOWN; + } + } + + /** + * Broadcast SIM state events. + * + * @param phoneId The phone id. + * @param simState The SIM state. + * @param reason SIM state changed reason. + */ + private void broadcastSimStateEvents(int phoneId, IccCardConstants.State simState, + @Nullable String reason) { + String legacyStringSimState = getIccStateIntentString(simState); + int cardState = TelephonyManager.SIM_STATE_UNKNOWN; + int applicationState = TelephonyManager.SIM_STATE_UNKNOWN; + + switch (simState) { + case ABSENT: + cardState = TelephonyManager.SIM_STATE_ABSENT; + break; + case PIN_REQUIRED: + case PUK_REQUIRED: + case NETWORK_LOCKED: + case PERM_DISABLED: + cardState = TelephonyManager.SIM_STATE_PRESENT; + applicationState = getSimStateFromLockedReason(reason); + break; + case READY: + case NOT_READY: + // Both READY and NOT_READY have the same card state and application state. + cardState = TelephonyManager.SIM_STATE_PRESENT; + applicationState = TelephonyManager.SIM_STATE_NOT_READY; + break; + case CARD_IO_ERROR: + cardState = TelephonyManager.SIM_STATE_CARD_IO_ERROR; + applicationState = TelephonyManager.SIM_STATE_NOT_READY; + break; + case CARD_RESTRICTED: + cardState = TelephonyManager.SIM_STATE_CARD_RESTRICTED; + applicationState = TelephonyManager.SIM_STATE_NOT_READY; + break; + case LOADED: + cardState = TelephonyManager.SIM_STATE_PRESENT; + applicationState = TelephonyManager.SIM_STATE_LOADED; + break; + case UNKNOWN: + default: + break; + } + + broadcastSimStateChanged(phoneId, legacyStringSimState, reason); + broadcastSimCardStateChanged(phoneId, cardState); + broadcastSimApplicationStateChanged(phoneId, applicationState); + } + + /** + * Update carrier service. + * + * @param phoneId The phone id. + * @param simState The SIM state. + */ + private void updateCarrierServices(int phoneId, @NonNull String simState) { + CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class); + if (configManager != null) { + configManager.updateConfigForPhoneId(phoneId, simState); + } + mCarrierServiceBindHelper.updateForPhoneId(phoneId, simState); + } + + /** + * Check if the SIM application is enabled on the card or not. + * + * @param phoneId The phone id. + * @return {@code true} if the application is enabled. + */ + private boolean areUiccAppsEnabledOnCard(int phoneId) { + // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from + // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another + // handleSimNotReady so this will be evaluated again. + UiccSlot slot = getUiccSlotForPhone(phoneId); + if (slot == null) return false; + UiccPort port = getUiccPort(phoneId); + String iccId = (port == null) ? null : port.getIccId(); + if (iccId == null) { + return false; + } + SubscriptionInfo info = SubscriptionManagerService.getInstance() + .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) + .stream().filter(subInfo -> subInfo.getIccId().equals( + IccUtils.stripTrailingFs(iccId))) + .findFirst().orElse(null); + return info != null && info.areUiccApplicationsEnabled(); + } + + /** + * Update the SIM state. + * + * @param phoneId Phone id. + * @param state SIM state (legacy). + * @param reason The reason for SIM state update. + */ + public void updateSimState(int phoneId, @NonNull IccCardConstants.State state, + @Nullable String reason) { + post(() -> { + log("updateSimState: phoneId=" + phoneId + ", state=" + state + ", reason=" + + reason); + if (!SubscriptionManager.isValidPhoneId(phoneId)) { + Rlog.e(LOG_TAG, "updateInternalIccState: Invalid phone id " + phoneId); + return; + } + + mTelephonyManager.setSimStateForPhone(phoneId, state.toString()); + + String legacySimState = getIccStateIntentString(state); + int simState = state.ordinal(); + SubscriptionManagerService.getInstance().updateSimState(phoneId, simState, + this::post, + () -> { + // The following are executed after subscription update completed in + // subscription manager service. + + broadcastSimStateEvents(phoneId, state, reason); + + UiccProfile uiccProfile = getUiccProfileForPhone(phoneId); + + if (simState == TelephonyManager.SIM_STATE_READY) { + // SIM_STATE_READY is not a final state. + return; + } + + if (simState == TelephonyManager.SIM_STATE_NOT_READY + && (uiccProfile != null && !uiccProfile.isEmptyProfile()) + && areUiccAppsEnabledOnCard(phoneId)) { + // STATE_NOT_READY is not a final state for when both + // 1) It's not an empty profile, and + // 2) Its uicc applications are set to enabled. + // + // At this phase, we consider STATE_NOT_READY not a final state, so + // return for now. + log("updateSimState: SIM_STATE_NOT_READY is not a final " + + "state."); + return; + } + + // At this point, the SIM state must be a final state (meaning we won't + // get more SIM state updates). So resolve the carrier id and update the + // carrier services. + log("updateSimState: resolve carrier id and update carrier " + + "services."); + PhoneFactory.getPhone(phoneId).resolveSubscriptionCarrierId( + legacySimState); + updateCarrierServices(phoneId, legacySimState); + } + ); + }); + } + private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) { if (ar.exception != null) { Rlog.e(LOG_TAG,"Error getting ICC status. " diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index d882e49d01..cc73ffa0ba 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -802,8 +802,13 @@ public class UiccProfile extends IccCard { } log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState); - UiccController.updateInternalIccState(mContext, mExternalState, - getIccStateReason(mExternalState), mPhoneId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + UiccController.getInstance().updateSimState(mPhoneId, mExternalState, + getIccStateReason(mExternalState)); + } else { + UiccController.updateInternalIccState(mContext, mExternalState, + getIccStateReason(mExternalState), mPhoneId); + } } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index ec4919609c..a395b2f7d8 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -195,9 +195,15 @@ public class UiccSlot extends Handler { if (!iss.mSimPortInfos[i].mPortActive) { // TODO: (b/79432584) evaluate whether should broadcast card state change // even if it's inactive. - UiccController.updateInternalIccStateForInactivePort(mContext, - mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID), - iss.mSimPortInfos[i].mIccId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + UiccController.getInstance().updateSimStateForInactivePort( + mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID), + iss.mSimPortInfos[i].mIccId); + } else { + UiccController.updateInternalIccStateForInactivePort(mContext, + mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID), + iss.mSimPortInfos[i].mIccId); + } mLastRadioState.put(i, TelephonyManager.RADIO_POWER_UNAVAILABLE); if (mUiccCard != null) { // Dispose the port @@ -330,8 +336,14 @@ public class UiccSlot extends Handler { if (DBG) log("update: notify card removed"); sendMessage(obtainMessage(EVENT_CARD_REMOVED, null)); } - UiccController.updateInternalIccState(mContext, IccCardConstants.State.ABSENT, - null, phoneId); + + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + UiccController.getInstance().updateSimState(phoneId, IccCardConstants.State.ABSENT, + null); + } else { + UiccController.updateInternalIccState(mContext, IccCardConstants.State.ABSENT, + null, phoneId); + } // no card present in the slot now; dispose card and make mUiccCard null nullifyUiccCard(false /* sim state is not unknown */); mLastRadioState.put(portIndex, TelephonyManager.RADIO_POWER_UNAVAILABLE); @@ -592,8 +604,13 @@ public class UiccSlot extends Handler { nullifyUiccCard(true /* sim state is unknown */); if (phoneId != INVALID_PHONE_ID) { - UiccController.updateInternalIccState( - mContext, IccCardConstants.State.UNKNOWN, null, phoneId); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + UiccController.getInstance().updateSimState(phoneId, + IccCardConstants.State.UNKNOWN, null); + } else { + UiccController.updateInternalIccState( + mContext, IccCardConstants.State.UNKNOWN, null, phoneId); + } mLastRadioState.put(getPortIndexFromPhoneId(phoneId), TelephonyManager.RADIO_POWER_UNAVAILABLE); } -- GitLab From ad5058dc9448e7117670f6222c89fffd23621cb5 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 22 Dec 2022 03:36:19 -0800 Subject: [PATCH 321/656] Added SIM events handling and fix crashes 1. Added SIM events handling in subscription manager service. 2. Fixed all crashes found during boot up. 3. Update subscription before broadcasting carrier config changed event. This is same as the reverted ag/20813887. Bug: 239607619 Test: Manual Change-Id: Ic3c2cd6ae21ec5199637d609c20d361b17de0726 --- .../internal/telephony/PhoneFactory.java | 9 +- .../telephony/ServiceStateTracker.java | 4 +- .../telephony/SubscriptionController.java | 5 +- .../telephony/data/PhoneSwitcher.java | 10 +- .../SubscriptionDatabaseManager.java | 61 +- .../SubscriptionManagerService.java | 520 +++++++++++++----- .../telephony/uicc/UiccController.java | 29 +- .../internal/telephony/uicc/UiccProfile.java | 11 +- .../SubscriptionManagerServiceTest.java | 23 +- 9 files changed, 464 insertions(+), 208 deletions(-) diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index cb8f984b0f..43aa15434b 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -214,9 +214,14 @@ public class PhoneFactory { TelephonyComponentFactory.getInstance().inject(SubscriptionController.class .getName()).initSubscriptionController(context); } + + SubscriptionController sc = null; + if (!isSubscriptionManagerServiceEnabled()) { + sc = SubscriptionController.getInstance(); + } + TelephonyComponentFactory.getInstance().inject(MultiSimSettingController.class. - getName()).initMultiSimSettingController(context, - SubscriptionController.getInstance()); + getName()).initMultiSimSettingController(context, sc); if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY_EUICC)) { diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 9c7178a63d..2a76a84eea 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -2751,8 +2751,8 @@ public class ServiceStateTracker extends Handler { if (mPhone.isSubscriptionManagerServiceEnabled()) { mSubscriptionManagerService.setCarrierName(mPhone.getSubId(), - getCarrierName(data.shouldShowPlmn(), data.getPlmn(), - data.shouldShowSpn(), data.getSpn())); + TextUtils.emptyIfNull(getCarrierName(data.shouldShowPlmn(), data.getPlmn(), + data.shouldShowSpn(), data.getSpn()))); } else { if (!mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), data.shouldShowPlmn(), data.getPlmn(), data.shouldShowSpn(), diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 4974182a9b..af759ead32 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -331,8 +331,11 @@ public class SubscriptionController extends ISub.Stub { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static SubscriptionController getInstance() { + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + throw new RuntimeException("getInstance should not be called."); + } if (sInstance == null) { - Log.wtf(LOG_TAG, "getInstance null"); + Log.wtf(LOG_TAG, "getInstance null"); } return sInstance; diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 1eb07aa4fb..fe63ada5a8 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -531,8 +531,14 @@ public class PhoneSwitcher extends Handler { mMaxDataAttachModemCount = maxActivePhones; mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES); - mSubscriptionController = SubscriptionController.getInstance(); - mSubscriptionManagerService = SubscriptionManagerService.getInstance(); + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); + mSubscriptionController = null; + } else { + mSubscriptionController = SubscriptionController.getInstance(); + mSubscriptionManagerService = null; + } + mRadioConfig = RadioConfig.getInstance(); mValidator = CellularNetworkValidator.getInstance(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 501d4f0cc5..199d2d4f30 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -39,6 +39,7 @@ import android.telephony.SubscriptionManager.SimDisplayNameSource; import android.telephony.SubscriptionManager.SubscriptionType; import android.telephony.SubscriptionManager.UsageSetting; import android.telephony.TelephonyManager; +import android.telephony.UiccAccessRule; import android.telephony.ims.ImsMmTelManager; import android.text.TextUtils; import android.util.Base64; @@ -562,6 +563,7 @@ public class SubscriptionDatabaseManager extends Handler { public SubscriptionDatabaseManager(@NonNull Context context, @NonNull Looper looper, @NonNull SubscriptionDatabaseManagerCallback callback) { super(looper); + log("Created SubscriptionDatabaseManager."); mContext = context; mCallback = callback; mUiccController = UiccController.getInstance(); @@ -684,6 +686,8 @@ public class SubscriptionDatabaseManager extends Handler { for (String columnName : Telephony.SimInfo.getAllColumns()) { if (DEPRECATED_DATABASE_COLUMNS.contains(columnName)) continue; + // subId is generated by the database. Cannot be updated. + if (columnName.equals(SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID)) continue; Object newValue = getSubscriptionInfoFieldByColumnName(newSubInfo, columnName); if (newValue != null) { Object oldValue = null; @@ -712,13 +716,16 @@ public class SubscriptionDatabaseManager extends Handler { Objects.requireNonNull(contentValues); Uri uri = mContext.getContentResolver().insert(SimInfo.CONTENT_URI, contentValues); if (uri != null && uri.getLastPathSegment() != null) { - logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" - + uri.getLastPathSegment()); - return Integer.parseInt(uri.getLastPathSegment()); - } else { - logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " - + "contentValues=" + contentValues); + int subId = Integer.parseInt(uri.getLastPathSegment()); + if (SubscriptionManager.isValidSubscriptionId(subId)) { + logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" + + uri.getLastPathSegment()); + return subId; + } } + + logel("insertNewRecordIntoDatabaseSync: Failed to insert subscription into database. " + + "contentValues=" + contentValues); return INVALID_ROW_INDEX; } @@ -875,6 +882,8 @@ public class SubscriptionDatabaseManager extends Handler { // Check if the new value is different from the old value in the cache. if (!Objects.equals(getSubscriptionInfoFieldByColumnName(subInfo, columnName), newValue)) { + logv("writeDatabaseAndCacheHelper: subId=" + subId + ",columnName=" + + columnName + ", newValue=" + newValue); // If the value is different, then we need to update the cache. Since all // fields in SubscriptionInfo are final, we need to create a new // SubscriptionInfo. @@ -1210,6 +1219,24 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules); } + /** + * Set the carrier certificates for this subscription that are saved in carrier configs. + * This does not include access rules from the Uicc, whether embedded or non-embedded. + * + * @param subId Subscription id. + * @param carrierConfigAccessRules The carrier certificates for this subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCarrierConfigAccessRules(int subId, + @NonNull UiccAccessRule[] carrierConfigAccessRules) { + Objects.requireNonNull(carrierConfigAccessRules); + byte[] carrierConfigAccessRulesBytes = UiccAccessRule.encodeRules(carrierConfigAccessRules); + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS, + carrierConfigAccessRulesBytes, + SubscriptionInfoInternal.Builder::setCarrierConfigAccessRules); + } + /** * Set whether an embedded subscription is on a removable card. Such subscriptions are * marked inaccessible as soon as the current card is removed. Otherwise, they will remain @@ -1761,11 +1788,23 @@ public class SubscriptionDatabaseManager extends Handler { // publicCardId is the publicly exposed int card ID int publicCardId = mUiccController.convertToPublicCardId(cardString); + byte[] rules = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_ACCESS_RULES)); + if (rules != null) { + builder.setNativeAccessRules(rules); + } + + rules = cursor.getBlob(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS)); + if (rules != null) { + builder.setCarrierConfigAccessRules(rules); + } + + byte[] config = cursor.getBlob(cursor.getColumnIndexOrThrow(SimInfo.COLUMN_RCS_CONFIG)); + if (config != null) { + builder.setRcsConfig(config); + } + builder.setCardId(publicCardId) - .setNativeAccessRules(cursor.getBlob(cursor.getColumnIndexOrThrow( - SimInfo.COLUMN_ACCESS_RULES))) - .setCarrierConfigAccessRules(cursor.getBlob(cursor.getColumnIndexOrThrow( - SimInfo.COLUMN_ACCESS_RULES_FROM_CARRIER_CONFIGS))) .setRemovableEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_IS_REMOVABLE))) .setEnhanced4GModeEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( @@ -1805,8 +1844,6 @@ public class SubscriptionDatabaseManager extends Handler { SimInfo.COLUMN_IMS_RCS_UCE_ENABLED))) .setCrossSimCallingEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED))) - .setRcsConfig(cursor.getBlob(cursor.getColumnIndexOrThrow( - SimInfo.COLUMN_RCS_CONFIG))) .setAllowedNetworkTypesForReasons(TextUtils.emptyIfNull( cursor.getString(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS)))) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 9e314280e0..27007f116b 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -37,6 +37,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.ParcelUuid; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.TelephonyServiceManager; import android.os.UserHandle; @@ -75,6 +76,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CarrierResolver; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; +import com.android.internal.telephony.IccCard; import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; @@ -84,7 +86,9 @@ import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccController; +import com.android.internal.telephony.uicc.UiccPort; import com.android.internal.telephony.uicc.UiccSlot; import com.android.internal.telephony.util.ArrayUtils; import com.android.telephony.Rlog; @@ -137,6 +141,7 @@ public class SubscriptionManagerService extends ISub.Stub { SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, SimInfo.COLUMN_RCS_CONFIG, + SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS, SimInfo.COLUMN_D2D_STATUS_SHARING, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, @@ -230,6 +235,10 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull private final WatchedInt mDefaultSmsSubId; + /** Sim state per logical SIM slot index. */ + @NonNull + private final int[] mSimState; + /** * Watched map that automatically invalidate cache in {@link SubscriptionManager}. */ @@ -263,7 +272,7 @@ public class SubscriptionManagerService extends ISub.Stub { * Watched integer. */ public static class WatchedInt { - private int mValue; + protected int mValue; /** * Constructor. @@ -377,7 +386,9 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { + int oldValue = mValue; if (super.set(newValue)) { + logl("Default voice sub changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, newValue); return true; @@ -391,7 +402,9 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { + int oldValue = mValue; if (super.set(newValue)) { + logl("Default data sub changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, newValue); return true; @@ -405,7 +418,9 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @Override public boolean set(int newValue) { + int oldValue = mValue; if (super.set(newValue)) { + logl("Default voice sms changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, newValue); return true; @@ -416,6 +431,9 @@ public class SubscriptionManagerService extends ISub.Stub { mDefaultSubId = new WatchedInt(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mSimState = new int[mTelephonyManager.getSupportedModemCount()]; + Arrays.fill(mSimState, TelephonyManager.SIM_STATE_UNKNOWN); + // Create a separate thread for subscription database manager. The database will be updated // from a different thread. HandlerThread handlerThread = new HandlerThread(LOG_TAG); @@ -990,13 +1008,292 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Check if the SIM application is enabled on the card or not. + * + * @param phoneId The phone id. + * + * @return {@code true} if the application is enabled. + */ + public boolean areUiccAppsEnabledOnCard(int phoneId) { + // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from + // cardStatus (since IRadio 1.2). And upon cardStatus change we'll receive another + // handleSimNotReady so this will be evaluated again. + UiccSlot slot = mUiccController.getUiccSlotForPhone(phoneId); + if (slot == null) return false; + UiccPort port = mUiccController.getUiccPort(phoneId); + String iccId = (port == null) ? null : port.getIccId(); + if (iccId == null) { + return false; + } + + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternalByIccId(IccUtils.stripTrailingFs(iccId)); + return subInfo != null && subInfo.areUiccApplicationsEnabled(); + } + + /** + * Get ICCID by phone id. + * + * @param phoneId The phone id (i.e. Logical SIM slot index.) + * + * @return The ICCID. Empty string if not available. + */ + @NonNull + private String getIccId(int phoneId) { + UiccPort port = mUiccController.getUiccPort(phoneId); + return (port == null) ? "" : TextUtils.emptyIfNull( + IccUtils.stripTrailingFs(port.getIccId())); + } + /** * Update the subscriptions on the logical SIM slot index (i.e. phone id). * - * @param slotIndex The logical SIM slot index. + * @param phoneId The phone id (i.e. Logical SIM slot index) + */ + private void updateSubscriptions(int phoneId) { + int simState = mSimState[phoneId]; + log("updateSubscriptions: phoneId=" + phoneId + ", simState=" + + TelephonyManager.simStateToString(simState)); + if (simState == TelephonyManager.SIM_STATE_ABSENT) { + if (mSlotIndexToSubId.containsKey(phoneId)) { + // Re-enable the SIM when it's removed, so it will be in enabled state when it gets + // re-inserted again. (pre-U behavior) + mSubscriptionDatabaseManager.setUiccApplicationsEnabled( + mSlotIndexToSubId.get(phoneId), true); + // When sim is absent, set the port index to invalid port index. (pre-U behavior) + mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(phoneId), + TelephonyManager.INVALID_PORT_INDEX); + } + } else if (simState == TelephonyManager.SIM_STATE_NOT_READY) { + // Check if this is the final state. Only update the subscription if NOT_READY is a + // final state. + IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); + if (!iccCard.isEmptyProfile() && areUiccAppsEnabledOnCard(phoneId)) { + log("updateSubscriptions: SIM_STATE_NOT_READY is not a final state. Will update " + + "subscription later."); + return; + } + } + + String iccId = getIccId(phoneId); + // Loop through all the subscriptions. If we found any ICCID matched, apply the right + // logical index to that. + int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + for (SubscriptionInfoInternal subInfo + : mSubscriptionDatabaseManager.getAllSubscriptions()) { + int simSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX; + if (!TextUtils.isEmpty(iccId) && subInfo.getIccId().equals(iccId)) { + subId = subInfo.getSubscriptionId(); + simSlotIndex = phoneId; + mSlotIndexToSubId.put(simSlotIndex, subId); + logl("updateSubscriptions: Found sub " + subInfo.getSubscriptionId() + + ", phoneId=" + phoneId); + } + mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), simSlotIndex); + } + + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + logl("updateSubscriptions: Did not find any subscription. phoneId=" + phoneId); + mSlotIndexToSubId.remove(phoneId); + } + + if (!TextUtils.isEmpty(iccId)) { + // Check if the subscription already existed. + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternalByIccId(iccId); + if (subInfo == null) { + // This is a new SIM card. Insert a new record. + subId = mSubscriptionDatabaseManager.insertSubscriptionInfo( + new SubscriptionInfoInternal.Builder() + .setIccId(iccId) + .setSimSlotIndex(phoneId) + .build()); + logl("updateSubscriptions: Inserted a new subscription. subId=" + subId + + ", phoneId=" + phoneId); + } else { + subId = subInfo.getSubscriptionId(); + } + + // Update the SIM slot index. This will make the subscription active. + mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId); + + // Update the card id. + UiccCard card = mUiccController.getUiccCardForPhone(phoneId); + if (card != null) { + String cardId = card.getCardId(); + if (cardId != null) { + mSubscriptionDatabaseManager.setCardString(subId, cardId); + } + } + + // Update the port index. + UiccSlot slot = mUiccController.getUiccSlotForPhone(phoneId); + if (slot != null && !slot.isEuicc()) { + int portIndex = slot.getPortIndexFromIccId(iccId); + mSubscriptionDatabaseManager.setPortIndex(subId, portIndex); + } + } + + updateDefaultSubIds(); + } + + /** + * Calculate the usage setting based on the carrier request. + * + * @param currentUsageSetting the current setting in the subscription DB. + * @param preferredUsageSetting provided by the carrier config. + * + * @return the calculated usage setting. + */ + @VisibleForTesting + @UsageSetting public int calculateUsageSetting(@UsageSetting int currentUsageSetting, + @UsageSetting int preferredUsageSetting) { + int[] supportedUsageSettings; + + // Load the resources to provide the device capability + try { + supportedUsageSettings = mContext.getResources().getIntArray( + com.android.internal.R.array.config_supported_cellular_usage_settings); + // If usage settings are not supported, return the default setting, which is UNKNOWN. + if (supportedUsageSettings == null + || supportedUsageSettings.length < 1) return currentUsageSetting; + } catch (Resources.NotFoundException nfe) { + loge("calculateUsageSetting: Failed to load usage setting resources!"); + return currentUsageSetting; + } + + // If the current setting is invalid, including the first time the value is set, + // update it to default (this will trigger a change in the DB). + if (currentUsageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT + || currentUsageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { + log("calculateUsageSetting: Updating usage setting for current subscription"); + currentUsageSetting = SubscriptionManager.USAGE_SETTING_DEFAULT; + } + + // Range check the inputs, and on failure, make no changes + if (preferredUsageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT + || preferredUsageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { + loge("calculateUsageSetting: Invalid usage setting!" + preferredUsageSetting); + return currentUsageSetting; + } + + // Default is always allowed + if (preferredUsageSetting == SubscriptionManager.USAGE_SETTING_DEFAULT) { + return preferredUsageSetting; + } + + // Forced setting must be explicitly supported + for (int supportedUsageSetting : supportedUsageSettings) { + if (preferredUsageSetting == supportedUsageSetting) return preferredUsageSetting; + } + + // If the preferred setting is not possible, just keep the current setting. + return currentUsageSetting; + } + + /** + * Called by CarrierConfigLoader to update the subscription before sending a broadcast. */ - private void updateSubscriptions(int slotIndex) { + public void updateSubscriptionByCarrierConfig(int phoneId, @NonNull String configPackageName, + @NonNull PersistableBundle config, @NonNull Runnable callback) { + mHandler.post(() -> { + updateSubscriptionByCarrierConfigInternal(phoneId, configPackageName, config); + callback.run(); + }); + } + + private void updateSubscriptionByCarrierConfigInternal(int phoneId, + @NonNull String configPackageName, @NonNull PersistableBundle config) { + log("updateSubscriptionByCarrierConfig: phoneId=" + phoneId + ", configPackageName=" + + configPackageName); + if (!SubscriptionManager.isValidPhoneId(phoneId) + || TextUtils.isEmpty(configPackageName) || config == null) { + loge("updateSubscriptionByCarrierConfig: Failed to update the subscription. phoneId=" + + phoneId + " configPackageName=" + configPackageName + " config=" + + ((config == null) ? "null" : config.hashCode())); + return; + } + + if (!mSlotIndexToSubId.containsKey(phoneId)) { + log("updateSubscriptionByCarrierConfig: No subscription is active for phone being " + + "updated."); + return; + } + + int subId = mSlotIndexToSubId.get(phoneId); + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + if (subInfo == null) { + loge("updateSubscriptionByCarrierConfig: Couldn't retrieve subscription info for " + + "current subscription. subId=" + subId); + return; + } + + ParcelUuid groupUuid; + + // carrier certificates are not subscription-specific, so we want to load them even if + // this current package is not a CarrierServicePackage + String[] certs = config.getStringArray( + CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY); + UiccAccessRule[] carrierConfigAccessRules = UiccAccessRule.decodeRulesFromCarrierConfig( + certs); + if (carrierConfigAccessRules != null) { + mSubscriptionDatabaseManager.setCarrierConfigAccessRules( + subId, carrierConfigAccessRules); + } + + boolean isOpportunistic = config.getBoolean( + CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, + subInfo.isOpportunistic()); + mSubscriptionDatabaseManager.setOpportunistic(subId, isOpportunistic); + + String groupUuidString = config.getString( + CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, ""); + String oldGroupUuidString = subInfo.getGroupUuid(); + if (!TextUtils.isEmpty(groupUuidString)) { + try { + // Update via a UUID Structure to ensure consistent formatting + groupUuid = ParcelUuid.fromString(groupUuidString); + if (groupUuidString.equals(CarrierConfigManager.REMOVE_GROUP_UUID_STRING)) { + // Remove the group UUID. + mSubscriptionDatabaseManager.setGroupUuid(subId, ""); + } else if (canPackageManageGroup(groupUuid, configPackageName)) { + mSubscriptionDatabaseManager.setGroupUuid(subId, groupUuidString); + mSubscriptionDatabaseManager.setGroupOwner(subId, configPackageName); + log("updateSubscriptionByCarrierConfig: Group added for sub " + subId); + } else { + loge("updateSubscriptionByCarrierConfig: configPackageName " + + configPackageName + " doesn't own groupUuid " + groupUuid); + } + + if (!groupUuidString.equals(oldGroupUuidString)) { + MultiSimSettingController.getInstance() + .notifySubscriptionGroupChanged(groupUuid); + } + } catch (IllegalArgumentException e) { + loge("updateSubscriptionByCarrierConfig: Invalid Group UUID=" + + groupUuidString); + } + } + + final int preferredUsageSetting = config.getInt( + CarrierConfigManager.KEY_CELLULAR_USAGE_SETTING_INT, + SubscriptionManager.USAGE_SETTING_UNKNOWN); + + int newUsageSetting = calculateUsageSetting( + subInfo.getUsageSetting(), preferredUsageSetting); + + if (newUsageSetting != subInfo.getUsageSetting()) { + mSubscriptionDatabaseManager.setUsageSetting(subId, newUsageSetting); + log("updateSubscriptionByCarrierConfig: UsageSetting changed," + + " oldSetting=" + SubscriptionManager.usageSettingToString( + subInfo.getUsageSetting()) + + " preferredSetting=" + SubscriptionManager.usageSettingToString( + preferredUsageSetting) + + " newSetting=" + SubscriptionManager.usageSettingToString(newUsageSetting)); + } } /** @@ -1044,26 +1341,20 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - final long identity = Binder.clearCallingIdentity(); - try { - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full - // list. Carrier apps can only get the subscriptions they have privileged. - .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( - mContext, subInfo.getSubscriptionId(), callingPackage, callingFeatureId, - "getAllSubInfoList")) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getAllSubInfoList")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); - - } finally { - Binder.restoreCallingIdentity(identity); - } + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full + // list. Carrier apps can only get the subscriptions they have privileged. + .filter(subInfo -> TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( + mContext, subInfo.getSubscriptionId(), callingPackage, callingFeatureId, + "getAllSubInfoList")) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getAllSubInfoList")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); } /** @@ -1226,22 +1517,16 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - final long identity = Binder.clearCallingIdentity(); - try { - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(SubscriptionInfoInternal::isActive) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getAllSubInfoList")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); - - } finally { - Binder.restoreCallingIdentity(identity); - } + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isActive) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getAllSubInfoList")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); } /** @@ -1285,7 +1570,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int getActiveSubInfoCountMax() { - return mTelephonyManager.getSimCount(); + return mTelephonyManager.getActiveModemCount(); } /** @@ -1857,26 +2142,21 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - final long identity = Binder.clearCallingIdentity(); - try { - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full - // list. Carrier apps can only get the subscriptions they have privileged. - .filter(subInfo -> subInfo.isOpportunistic() - && TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( - mContext, subInfo.getSubscriptionId(), callingPackage, - callingFeatureId, "getOpportunisticSubscriptions")) - // Remove the identifier if the caller does not have sufficient permission. - // carrier apps will get full subscription info on the subscriptions associated - // to them. - .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), - callingPackage, callingFeatureId, "getOpportunisticSubscriptions")) - .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) - .thenComparing(SubscriptionInfo::getSubscriptionId)) - .collect(Collectors.toList()); - } finally { - Binder.restoreCallingIdentity(identity); - } + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // callers have READ_PHONE_STATE or READ_PRIVILEGED_PHONE_STATE can get a full + // list. Carrier apps can only get the subscriptions they have privileged. + .filter(subInfo -> subInfo.isOpportunistic() + && TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow( + mContext, subInfo.getSubscriptionId(), callingPackage, + callingFeatureId, "getOpportunisticSubscriptions")) + // Remove the identifier if the caller does not have sufficient permission. + // carrier apps will get full subscription info on the subscriptions associated + // to them. + .map(subInfo -> conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), + callingPackage, callingFeatureId, "getOpportunisticSubscriptions")) + .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) + .thenComparing(SubscriptionInfo::getSubscriptionId)) + .collect(Collectors.toList()); } /** @@ -2131,6 +2411,32 @@ public class SubscriptionManagerService extends ISub.Stub { return new int[]{getSubId(slotIndex)}; } + /** + * Update default voice, sms, and data sub id. + */ + private void updateDefaultSubIds() { + if (getActiveSubInfoCountMax() == 0) { + mDefaultVoiceSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mDefaultSmsSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mDefaultDataSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + if (getActiveSubInfoCountMax() == 1) { + int[] activeSubIds = getActiveSubIdList(false); + if (activeSubIds.length == 1) { + mDefaultVoiceSubId.set(activeSubIds[0]); + mDefaultSmsSubId.set(activeSubIds[0]); + mDefaultDataSubId.set(activeSubIds[0]); + } else { + loge("updateDefaultSubIds: Single SIM device, but active subs are more than one." + + " activeSubIds=" + Arrays.toString(activeSubIds)); + } + } else { + // TODO: Support dual sim + } + + updateDefaultSubId(); + } + /** * Update default sub id. */ @@ -2351,9 +2657,12 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { - return mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(subInfo -> subInfo.isActive() && (!visibleOnly || subInfo.isVisible())) - .mapToInt(SubscriptionInfoInternal::getSubscriptionId) + return mSlotIndexToSubId.values().stream() + .filter(subId -> { + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + return subInfo != null && (!visibleOnly || subInfo.isVisible()); }) + .mapToInt(x -> x) .toArray(); } finally { Binder.restoreCallingIdentity(token); @@ -2558,9 +2867,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public boolean isActiveSubId(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "isActiveSubId")) { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " @@ -3188,68 +3494,6 @@ public class SubscriptionManagerService extends ISub.Stub { ? subscriptionInfoInternal.toSubscriptionInfo() : null; } - /** - * Called when SIM state changed to absent. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimAbsent(int slotIndex) { - if (mSlotIndexToSubId.containsKey(slotIndex)) { - // Re-enable the SIM when it's removed, so it will be in enabled state when it gets - // re-inserted again. (pre-U behavior) - mSubscriptionDatabaseManager.setUiccApplicationsEnabled( - mSlotIndexToSubId.get(slotIndex), true); - // When sim is absent, set the port index to invalid port index. (pre-U behavior) - mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(slotIndex), - TelephonyManager.INVALID_PORT_INDEX); - } - updateSubscriptions(slotIndex); - } - - /** - * Called when SIM state changed to locked. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimLocked(int slotIndex) { - - } - - /** - * Called when SIM state changed to ready. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimReady(int slotIndex) { - - } - - /** - * Called when SIM state changed to not ready. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimNotReady(int slotIndex) { - - } - - /** - * Called when SIM encounters error. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimError(int slotIndex) { - - } - - /** - * Called when SIM state changed to loaded. - * - * @param slotIndex The logical SIM slot index. - */ - private void onSimLoaded(int slotIndex) { - } - /** * Called when eSIM becomes inactive. * @@ -3281,34 +3525,24 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable @CallbackExecutor Executor executor, @Nullable Runnable updateCompleteCallback) { mHandler.post(() -> { + mSimState[slotIndex] = simState; switch (simState) { case TelephonyManager.SIM_STATE_ABSENT: - onSimAbsent(slotIndex); - break; case TelephonyManager.SIM_STATE_PIN_REQUIRED: case TelephonyManager.SIM_STATE_PUK_REQUIRED: case TelephonyManager.SIM_STATE_NETWORK_LOCKED: case TelephonyManager.SIM_STATE_PERM_DISABLED: - onSimLocked(slotIndex); - break; case TelephonyManager.SIM_STATE_READY: - onSimReady(slotIndex); - break; - case TelephonyManager.SIM_STATE_NOT_READY: - onSimNotReady(slotIndex); - break; case TelephonyManager.SIM_STATE_CARD_IO_ERROR: - onSimError(slotIndex); + case TelephonyManager.SIM_STATE_LOADED: + case TelephonyManager.SIM_STATE_NOT_READY: + updateSubscriptions(slotIndex); break; case TelephonyManager.SIM_STATE_CARD_RESTRICTED: + default: // No specific things needed to be done. Just return and broadcast the SIM // states. break; - case TelephonyManager.SIM_STATE_LOADED: - onSimLoaded(slotIndex); - break; - default: - break; } if (executor != null && updateCompleteCallback != null) { executor.execute(updateCompleteCallback); diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index a28142cb59..48524ff46b 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -40,7 +40,6 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.SimState; @@ -973,31 +972,6 @@ public class UiccController extends Handler { mCarrierServiceBindHelper.updateForPhoneId(phoneId, simState); } - /** - * Check if the SIM application is enabled on the card or not. - * - * @param phoneId The phone id. - * @return {@code true} if the application is enabled. - */ - private boolean areUiccAppsEnabledOnCard(int phoneId) { - // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from - // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another - // handleSimNotReady so this will be evaluated again. - UiccSlot slot = getUiccSlotForPhone(phoneId); - if (slot == null) return false; - UiccPort port = getUiccPort(phoneId); - String iccId = (port == null) ? null : port.getIccId(); - if (iccId == null) { - return false; - } - SubscriptionInfo info = SubscriptionManagerService.getInstance() - .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) - .stream().filter(subInfo -> subInfo.getIccId().equals( - IccUtils.stripTrailingFs(iccId))) - .findFirst().orElse(null); - return info != null && info.areUiccApplicationsEnabled(); - } - /** * Update the SIM state. * @@ -1036,7 +1010,8 @@ public class UiccController extends Handler { if (simState == TelephonyManager.SIM_STATE_NOT_READY && (uiccProfile != null && !uiccProfile.isEmptyProfile()) - && areUiccAppsEnabledOnCard(phoneId)) { + && SubscriptionManagerService.getInstance() + .areUiccAppsEnabledOnCard(phoneId)) { // STATE_NOT_READY is not a final state for when both // 1) It's not an empty profile, and // 2) Its uicc applications are set to enabled. diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index cc73ffa0ba..7dec239fc1 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -527,8 +527,15 @@ public class UiccProfile extends IccCard { private void updateCarrierNameForSubscription(int subId, int nameSource) { /* update display name with carrier override */ - SubscriptionInfo subInfo = SubscriptionController.getInstance().getActiveSubscriptionInfo( - subId, mContext.getOpPackageName(), mContext.getAttributionTag()); + SubscriptionInfo subInfo; + + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + subInfo = SubscriptionManagerService.getInstance().getActiveSubscriptionInfo(subId, + mContext.getOpPackageName(), mContext.getAttributionTag()); + } else { + subInfo = SubscriptionController.getInstance().getActiveSubscriptionInfo( + subId, mContext.getOpPackageName(), mContext.getAttributionTag()); + } if (subInfo == null) { return; 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 51dea369d1..ebd4ad23a5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -1557,24 +1557,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { } @Test - public void testGetNonAccessibleFields() { + public void testGetNonAccessibleFields() throws Exception { insertSubscription(FAKE_SUBSCRIPTION_INFO1); - Set accessibleColumns = Set.of( - SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, - SimInfo.COLUMN_VT_IMS_ENABLED, - SimInfo.COLUMN_WFC_IMS_ENABLED, - SimInfo.COLUMN_WFC_IMS_MODE, - SimInfo.COLUMN_WFC_IMS_ROAMING_MODE, - SimInfo.COLUMN_WFC_IMS_ROAMING_ENABLED, - SimInfo.COLUMN_ENABLED_MOBILE_DATA_POLICIES, - SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, - SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, - SimInfo.COLUMN_RCS_CONFIG, - SimInfo.COLUMN_D2D_STATUS_SHARING, - SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, - SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, - SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED - ); + + Field field = SubscriptionManagerService.class.getDeclaredField( + "DIRECT_ACCESS_SUBSCRIPTION_COLUMNS"); + field.setAccessible(true); + Set accessibleColumns = (Set) field.get(null); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); -- GitLab From 30f9f418cc0ecd82089542c81689af30d5519322 Mon Sep 17 00:00:00 2001 From: Helen Date: Tue, 3 Jan 2023 09:38:23 +0000 Subject: [PATCH 322/656] Update NotifyAnbr Api to deliver the unsol message to framework Bug: 259254356 Test: atest CtsTelephonyTestCases:ImsCallingTestOnMockModem atest ImsPhoneCallTrackerTest Change-Id: I2a5415d4104d5bfcdcc5d4721f6e4f807a684fa1 --- .../internal/telephony/CommandsInterface.java | 12 ------ .../internal/telephony/GsmCdmaPhone.java | 7 +++- .../com/android/internal/telephony/Phone.java | 1 - .../imsphone/ImsPhoneCallTracker.java | 6 ++- .../imsphone/ImsPhoneCallTrackerTest.java | 42 +++++++++++++++++++ 5 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 5af8718960..92f1696ec6 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2994,18 +2994,6 @@ public interface CommandsInterface { */ default void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond, Message result) {} - /** - * Notifies the recommended bit rate for the indicated logical channel and direction. - * - * @param mediaType MediaType is used to identify media stream such as audio or video. - * @param direction Direction of this packet stream (e.g. uplink or downlink). - * @param bitsPerSecond The recommended bit rate for the UE for a specific logical channel and - * a specific direction by NW. - * @param result Callback message to receive the result. - */ - default void triggerNotifyAnbr(int mediaType, int direction, int bitsPerSecond, - Message result) {} - /** * Set the UE's ability to accept/reject null ciphered and/or null integrity-protected * connections. diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index e325678589..40f3dc72d1 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -470,6 +470,7 @@ public class GsmCdmaPhone extends Phone { mCi.registerForCarrierInfoForImsiEncryption(this, EVENT_RESET_CARRIER_KEY_IMSI_ENCRYPTION, null); mCi.registerForTriggerImsDeregistration(this, EVENT_IMS_DEREGISTRATION_TRIGGERED, null); + mCi.registerForNotifyAnbr(this, EVENT_TRIGGER_NOTIFY_ANBR, null); IntentFilter filter = new IntentFilter( CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED); @@ -3456,8 +3457,10 @@ public class GsmCdmaPhone extends Phone { logd("EVENT_TRIGGER_NOTIFY_ANBR"); ar = (AsyncResult) msg.obj; if (ar.exception == null) { - mImsPhone.triggerNotifyAnbr(((int[]) ar.result)[0], ((int[]) ar.result)[1], - ((int[]) ar.result)[2]); + if (mImsPhone != null) { + mImsPhone.triggerNotifyAnbr(((int[]) ar.result)[0], ((int[]) ar.result)[1], + ((int[]) ar.result)[2]); + } } break; default: diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index e530724705..5ddf2dc2b8 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5000,7 +5000,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * a specific direction by NW. */ public void triggerNotifyAnbr(int mediaType, int direction, int bitsPerSecond) { - mCi.triggerNotifyAnbr(mediaType, direction, bitsPerSecond, null); } /** diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 83d3c0d99f..6f50661815 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -4398,8 +4398,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { @Override public void onCallSessionSendAnbrQuery(ImsCall imsCall, int mediaType, int direction, int bitsPerSecond) { - log("onCallSessionSendAnbrQuery mediaType=" + mediaType + ", direction=" + if (DBG) { + log("onCallSessionSendAnbrQuery mediaType=" + mediaType + ", direction=" + direction + ", bitPerSecond=" + bitsPerSecond); + } handleSendAnbrQuery(mediaType, direction, bitsPerSecond); } }; @@ -5940,6 +5942,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { /** Send the mediaType, direction, bitrate for ANBR Query to the radio */ public void handleSendAnbrQuery(int mediaType, int direction, int bitsPerSecond) { + if (DBG) log("handleSendAnbrQuery - mediaType=" + mediaType); mPhone.getDefaultPhone().mCi.sendAnbrQuery(mediaType, direction, bitsPerSecond, null); } @@ -5956,6 +5959,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { ImsCall activeCall = mForegroundCall.getFirstConnection().getImsCall(); if (activeCall != null) { + if (DBG) log("triggerNotifyAnbr - mediaType=" + mediaType); activeCall.callSessionNotifyAnbr(mediaType, direction, bitsPerSecond); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 57cdd69ba8..6ab76512d6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -121,6 +121,7 @@ import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; import com.android.internal.telephony.IccCardConstants; +import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.SrvccConnection; import com.android.internal.telephony.TelephonyTest; @@ -169,6 +170,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { private ImsPhoneConnection mImsPhoneConnection; private INetworkStatsProviderCallback mVtDataUsageProviderCb; private ImsPhoneCallTracker.ConnectorFactory mConnectorFactory; + private CommandsInterface mMockCi; private final Executor mExecutor = Runnable::run; @@ -229,6 +231,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { mSecondImsCall = spy(new ImsCall(mContext, mImsCallProfile)); mImsPhoneConnectionListener = mock(ImsPhoneConnection.Listener.class); mImsPhoneConnection = mock(ImsPhoneConnection.class); + mMockCi = mock(CommandsInterface.class); imsCallMocking(mImsCall); imsCallMocking(mSecondImsCall); doReturn(ImsFeature.STATE_READY).when(mImsManager).getImsServiceState(); @@ -1458,6 +1461,45 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { verify(mImsPhone, never()).startOnHoldTone(nullable(Connection.class)); } + @Test + @SmallTest + public void testSendAnbrQuery() throws Exception { + logd("ImsPhoneCallTracker testSendAnbrQuery"); + + replaceInstance(Phone.class, "mCi", mPhone, mMockCi); + //establish a MT call + testImsMTCallAccept(); + + ImsPhoneConnection connection = mCTUT.mForegroundCall.getFirstConnection(); + ImsCall imsCall = connection.getImsCall(); + imsCall.getImsCallSessionListenerProxy().callSessionSendAnbrQuery(1, 1, 24400); + + verify(mMockCi, times(1)).sendAnbrQuery(eq(1), eq(1), eq(24400), any()); + + // Disconnecting and then Disconnected + mCTUT.hangup(connection); + mImsCallListener.onCallTerminated(imsCall, + new ImsReasonInfo(ImsReasonInfo.CODE_USER_TERMINATED, 0)); + } + + @Test + @SmallTest + public void testTriggerNotifyAnbr() throws Exception { + logd("ImsPhoneCallTracker testTriggerNotifyAnbr"); + + testImsMTCallAccept(); + ImsPhoneConnection connection = mCTUT.mForegroundCall.getFirstConnection(); + ImsCall imsCall = connection.getImsCall(); + + mCTUT.triggerNotifyAnbr(1, 1, 24400); + verify(mImsCall, times(1)).callSessionNotifyAnbr(eq(1), eq(1), eq(24400)); + + // Disconnecting and then Disconnected + mCTUT.hangup(connection); + mImsCallListener.onCallTerminated(imsCall, + new ImsReasonInfo(ImsReasonInfo.CODE_USER_TERMINATED, 0)); + } + /** * Verifies that a remote hold tone is played when the call is remotely held and the media * direction is inactive (i.e. the audio stream is not playing, so we should play the tone). -- GitLab From 596782776c50c1500c63ee3d06dec4e20cabe626 Mon Sep 17 00:00:00 2001 From: Lalit Maganti Date: Tue, 10 Jan 2023 17:27:48 +0000 Subject: [PATCH 323/656] telephony: migrate off deprecated tracing method Change-Id: I4e716bd61c79b2e75eb066e9adef49767033a233 --- src/java/com/android/internal/telephony/RadioConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java index e455ecbe74..f098c6c09d 100644 --- a/src/java/com/android/internal/telephony/RadioConfig.java +++ b/src/java/com/android/internal/telephony/RadioConfig.java @@ -358,7 +358,7 @@ public class RadioConfig extends Handler { if (rr != null) { Trace.asyncTraceForTrackEnd( - Trace.TRACE_TAG_NETWORK, "RIL", "" /* unused */, rr.mSerial); + Trace.TRACE_TAG_NETWORK, "RIL", rr.mSerial); mRequestList.remove(serial); } } -- GitLab From f4610d5f6dea34e63725ab1cc450a8d2896b9906 Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Tue, 10 Jan 2023 16:27:59 +0000 Subject: [PATCH 324/656] Guide transport type for emergency data network. Bug: 265017237 Test: atest FrameworksTelephonyTests Change-Id: I8778f00a9511eaf9a3b19d25b0b41ff88568dbb3 --- .../telephony/data/AccessNetworksManager.java | 34 +++++++++++++++++++ .../data/AccessNetworksManagerTest.java | 28 +++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index d51f586932..a6b37a3d44 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -26,9 +26,11 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; +import android.os.AsyncResult; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.Message; import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; @@ -77,6 +79,9 @@ import java.util.stream.Collectors; public class AccessNetworksManager extends Handler { private static final boolean DBG = false; + /** Event to guide a transport type for initial data connection of emergency data network. */ + private static final int EVENT_GUIDE_TRANSPORT_TYPE_FOR_EMERGENCY = 1; + /** * The counters to detect frequent QNS attempt to change preferred network transport by ApnType. */ @@ -176,6 +181,19 @@ public class AccessNetworksManager extends Handler { } } + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_GUIDE_TRANSPORT_TYPE_FOR_EMERGENCY: + AsyncResult ar = (AsyncResult) msg.obj; + int transport = (int) ar.result; + onEmergencyDataNetworkPreferredTransportChanged(transport); + break; + default: + loge("Unexpected event " + msg.what); + } + } + private class AccessNetworksManagerDeathRecipient implements IBinder.DeathRecipient { @Override public void binderDied() { @@ -298,6 +316,20 @@ public class AccessNetworksManager extends Handler { } } + private void onEmergencyDataNetworkPreferredTransportChanged( + @AccessNetworkConstants.TransportType int transportType) { + try { + logl("onEmergencyDataNetworkPreferredTransportChanged: " + + AccessNetworkConstants.transportTypeToString(transportType)); + if (mIQualifiedNetworksService != null) { + mIQualifiedNetworksService.reportEmergencyDataNetworkPreferredTransportChanged( + mPhone.getPhoneId(), transportType); + } + } catch (Exception ex) { + loge("onEmergencyDataNetworkPreferredTransportChanged: ", ex); + } + } + /** * Access networks manager callback. This should be only used by {@link DataNetworkController}. */ @@ -372,6 +404,8 @@ public class AccessNetworksManager extends Handler { mApnTypeToQnsChangeNetworkCounter.clear(); } }); + mPhone.registerForEmergencyDomainSelected( + this, EVENT_GUIDE_TRANSPORT_TYPE_FOR_EMERGENCY, null); }); } 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 4c4333cde2..68e1fb2a6a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java @@ -31,8 +31,10 @@ import android.content.ComponentName; import android.content.IntentFilter; import android.content.pm.ServiceInfo; import android.net.NetworkCapabilities; +import android.os.AsyncResult; import android.os.IBinder; import android.os.Looper; +import android.os.Message; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.NetworkService; @@ -148,6 +150,32 @@ public class AccessNetworksManagerTest extends TelephonyTest { assertThat(mAccessNetworksManager.isAnyApnOnIwlan()).isTrue(); } + @Test + public void testGuideTransportTypeForEmergencyDataNetwork() throws Exception { + doAnswer(invocation -> { + int accessNetwork = AccessNetworkType.UNKNOWN; + if (invocation.getArguments()[1].equals(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)) { + accessNetwork = AccessNetworkType.IWLAN; + } else if (invocation.getArguments()[1] + .equals(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)) { + accessNetwork = AccessNetworkType.EUTRAN; + } + mQnsCallback.onQualifiedNetworkTypesChanged(ApnSetting.TYPE_EMERGENCY, + new int[]{accessNetwork}); + return null; + }).when(mMockedQns).reportEmergencyDataNetworkPreferredTransportChanged(anyInt(), anyInt()); + + AsyncResult asyncResult = + new AsyncResult(null, AccessNetworkConstants.TRANSPORT_TYPE_WLAN, null); + Message msg = this.mAccessNetworksManager + .obtainMessage(1 /* EVENT_GUIDE_TRANSPORT_TYPE_FOR_EMERGENCY */, asyncResult); + mAccessNetworksManager.sendMessage(msg); + processAllMessages(); + + assertThat(mAccessNetworksManager.getPreferredTransport(ApnSetting.TYPE_EMERGENCY)) + .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + } + @Test public void testEmptyNetworkTypes() throws Exception { testQualifiedNetworkTypesChanged(); -- GitLab From 408e62c56c995fab14b10aa7038bbbfdeb4a0d6f Mon Sep 17 00:00:00 2001 From: Gwen Lin Date: Wed, 11 Jan 2023 13:26:56 +0800 Subject: [PATCH 325/656] Apply KEY_CARRIER_USSD_METHOD_INT for short code Use the same USSD domain selection logic for short code. Bug: 264961636 Test: atest ImsPhoneTest Change-Id: Id5af10d3470b8b108aef3d5854a5e60784d4e128 --- .../telephony/imsphone/ImsPhoneMmiCode.java | 90 ++++++++++--------- .../telephony/imsphone/ImsPhoneTest.java | 36 +++++++- 2 files changed, 80 insertions(+), 46 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java index a033edd661..25fa8a2011 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java @@ -892,9 +892,15 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { Rlog.d(LOG_TAG, "processCode: isShortCode"); // These just get treated as USSD. - Rlog.d(LOG_TAG, "processCode: Sending short code '" - + mDialingNumber + "' over CS pipe."); - throw new CallStateException(Phone.CS_FALLBACK); + if (isUssdOverImsAllowed()) { + Rlog.d(LOG_TAG, "processCode: Sending short code '" + + mDialingNumber + "' over IMS pipe."); + sendUssd(mDialingNumber); + } else { + Rlog.d(LOG_TAG, "processCode: Sending short code '" + + mDialingNumber + "' over CS pipe."); + throw new CallStateException(Phone.CS_FALLBACK); + } } else if (isServiceCodeCallForwarding(mSc)) { Rlog.d(LOG_TAG, "processCode: is CF"); @@ -1120,47 +1126,11 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { throw new RuntimeException ("Invalid or Unsupported MMI Code"); } } else if (mPoundString != null) { - if (mContext.getResources().getBoolean( - com.android.internal.R.bool.config_allow_ussd_over_ims)) { - int ussd_method = getIntCarrierConfig( - CarrierConfigManager.KEY_CARRIER_USSD_METHOD_INT); - - switch (ussd_method) { - case USSD_OVER_CS_PREFERRED: - // We'll normally send USSD over the CS pipe, but if it happens that - // the CS phone is out of service, we'll just try over IMS instead. - if (mPhone.getDefaultPhone().getServiceStateTracker().mSS.getState() - == STATE_IN_SERVICE) { - Rlog.i(LOG_TAG, "processCode: Sending ussd string '" - + Rlog.pii(LOG_TAG, mPoundString) + "' over CS pipe " - + "(allowed over ims)."); - throw new CallStateException(Phone.CS_FALLBACK); - } else { - Rlog.i(LOG_TAG, "processCode: CS is out of service, " - + "sending ussd string '" - + Rlog.pii(LOG_TAG, mPoundString) + "' over IMS pipe."); - sendUssd(mPoundString); - } - break; - case USSD_OVER_IMS_PREFERRED: - case USSD_OVER_IMS_ONLY: - Rlog.i(LOG_TAG, "processCode: Sending ussd string '" - + Rlog.pii(LOG_TAG, mPoundString) + "' over IMS pipe."); - sendUssd(mPoundString); - break; - case USSD_OVER_CS_ONLY: - Rlog.i(LOG_TAG, "processCode: Sending ussd string '" - + Rlog.pii(LOG_TAG, mPoundString) + "' over CS pipe."); - throw new CallStateException(Phone.CS_FALLBACK); - default: - Rlog.i(LOG_TAG, "processCode: Sending ussd string '" - + Rlog.pii(LOG_TAG, mPoundString) + "' over CS pipe." - + "(unsupported method)"); - throw new CallStateException(Phone.CS_FALLBACK); - } + if (isUssdOverImsAllowed()) { + Rlog.i(LOG_TAG, "processCode: Sending ussd string '" + + Rlog.pii(LOG_TAG, mPoundString) + "' over IMS pipe."); + sendUssd(mPoundString); } else { - // USSD codes are not supported over IMS due to modem limitations; send over - // the CS pipe instead. This should be fixed in the future. Rlog.i(LOG_TAG, "processCode: Sending ussd string '" + Rlog.pii(LOG_TAG, mPoundString) + "' over CS pipe."); throw new CallStateException(Phone.CS_FALLBACK); @@ -1177,6 +1147,40 @@ public final class ImsPhoneMmiCode extends Handler implements MmiCode { } } + private boolean isUssdOverImsAllowed() { + if (mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allow_ussd_over_ims)) { + int ussd_method = getIntCarrierConfig( + CarrierConfigManager.KEY_CARRIER_USSD_METHOD_INT); + + switch (ussd_method) { + case USSD_OVER_CS_PREFERRED: + // We'll normally send USSD over the CS pipe, but if it happens that + // the CS phone is out of service, we'll just try over IMS instead. + if (mPhone.getDefaultPhone().getServiceStateTracker().mSS.getState() + == STATE_IN_SERVICE) { + return false; + } else { + Rlog.i(LOG_TAG, "isUssdOverImsAllowed: CS is out of service"); + return true; + } + case USSD_OVER_IMS_PREFERRED: + case USSD_OVER_IMS_ONLY: + return true; + case USSD_OVER_CS_ONLY: + return false; + default: + Rlog.i(LOG_TAG, "isUssdOverImsAllowed: Unsupported method"); + return false; + } + } else { + // USSD codes are not supported over IMS due to modem limitations; send over + // the CS pipe instead. This should be fixed in the future. + Rlog.i(LOG_TAG, "isUssdOverImsAllowed: USSD over IMS pipe is not supported."); + return false; + } + } + /** * Called from ImsPhone * 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 4b8cbaba07..3050beb575 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -813,6 +813,9 @@ public class ImsPhoneTest extends TelephonyTest { mImsPhoneUT.dial("*135#", new ImsPhone.ImsDialArgs.Builder().build()); verify(mImsCT).sendUSSD(eq("*135#"), any()); + + mImsPhoneUT.dial("91", new ImsPhone.ImsDialArgs.Builder().build()); + verify(mImsCT).sendUSSD(eq("91"), any()); } @Test @@ -833,6 +836,13 @@ public class ImsPhoneTest extends TelephonyTest { errorCode = e.getMessage(); } assertEquals(Phone.CS_FALLBACK, errorCode); + + try { + mImsPhoneUT.dial("91", new ImsPhone.ImsDialArgs.Builder().build()); + } catch (CallStateException e) { + errorCode = e.getMessage(); + } + assertEquals(Phone.CS_FALLBACK, errorCode); } @Test @@ -850,11 +860,18 @@ public class ImsPhoneTest extends TelephonyTest { errorCode = e.getMessage(); } assertEquals(Phone.CS_FALLBACK, errorCode); + + try { + mImsPhoneUT.dial("91", new ImsPhone.ImsDialArgs.Builder().build()); + } catch (CallStateException e) { + errorCode = e.getMessage(); + } + assertEquals(Phone.CS_FALLBACK, errorCode); } @Test @SmallTest - public void testSendUssdAllowUssdOverImswithIMSPreferred() throws Exception { + public void testSendUssdAllowUssdOverImsWithImsPreferred() throws Exception { Resources resources = mContext.getResources(); mBundle.putInt(CarrierConfigManager.KEY_CARRIER_USSD_METHOD_INT, @@ -865,11 +882,14 @@ public class ImsPhoneTest extends TelephonyTest { mImsPhoneUT.dial("*135#", new ImsPhone.ImsDialArgs.Builder().build()); verify(mImsCT).sendUSSD(eq("*135#"), any()); + + mImsPhoneUT.dial("91", new ImsPhone.ImsDialArgs.Builder().build()); + verify(mImsCT).sendUSSD(eq("91"), any()); } @Test @SmallTest - public void testSendUssdAllowUssdOverImswithCSOnly() throws Exception { + public void testSendUssdAllowUssdOverImsWithCsOnly() throws Exception { String errorCode = ""; Resources resources = mContext.getResources(); @@ -885,11 +905,18 @@ public class ImsPhoneTest extends TelephonyTest { errorCode = e.getMessage(); } assertEquals(Phone.CS_FALLBACK, errorCode); + + try { + mImsPhoneUT.dial("91", new ImsPhone.ImsDialArgs.Builder().build()); + } catch (CallStateException e) { + errorCode = e.getMessage(); + } + assertEquals(Phone.CS_FALLBACK, errorCode); } @Test @SmallTest - public void testSendUssdAllowUssdOverImswithIMSOnly() throws Exception { + public void testSendUssdAllowUssdOverImsWithImsOnly() throws Exception { Resources resources = mContext.getResources(); mBundle.putInt(CarrierConfigManager.KEY_CARRIER_USSD_METHOD_INT, @@ -900,6 +927,9 @@ public class ImsPhoneTest extends TelephonyTest { mImsPhoneUT.dial("*135#", new ImsPhone.ImsDialArgs.Builder().build()); verify(mImsCT).sendUSSD(eq("*135#"), any()); + + mImsPhoneUT.dial("91", new ImsPhone.ImsDialArgs.Builder().build()); + verify(mImsCT).sendUSSD(eq("91"), any()); } @Test -- GitLab From ef9e6afbbf92b3002df53e0e21a2136fe4f340e3 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Sun, 1 Jan 2023 14:22:17 +0000 Subject: [PATCH 326/656] Notifies SRVCC state before closing ImsCall when SRVCC has completed Bug: 263927721 Test: atest ImsPhoneCallTrackerTest Change-Id: I566733fe8ca8e18471b9a7ffdf92a9097351b449 --- .../imsphone/ImsPhoneCallTracker.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 6f50661815..59f01ec1a6 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -4625,6 +4625,22 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { public void notifySrvccState(int state) { if (DBG) log("notifySrvccState state=" + state); + if (mImsManager != null) { + try { + if (state == TelephonyManager.SRVCC_STATE_HANDOVER_STARTED) { + mImsManager.notifySrvccStarted(mSrvccStartedCallback); + } else if (state == TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED) { + mImsManager.notifySrvccCompleted(); + } else if (state == TelephonyManager.SRVCC_STATE_HANDOVER_FAILED) { + mImsManager.notifySrvccFailed(); + } else if (state == TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED) { + mImsManager.notifySrvccCanceled(); + } + } catch (ImsException e) { + loge("notifySrvccState : exception " + e); + } + } + switch(state) { case TelephonyManager.SRVCC_STATE_HANDOVER_STARTED: mSrvccState = Call.SrvccState.STARTED; @@ -4656,22 +4672,6 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { //ignore invalid state return; } - - if (mImsManager != null) { - try { - if (mSrvccState == Call.SrvccState.STARTED) { - mImsManager.notifySrvccStarted(mSrvccStartedCallback); - } else if (mSrvccState == Call.SrvccState.COMPLETED) { - mImsManager.notifySrvccCompleted(); - } else if (mSrvccState == Call.SrvccState.FAILED) { - mImsManager.notifySrvccFailed(); - } else if (mSrvccState == Call.SrvccState.CANCELED) { - mImsManager.notifySrvccCanceled(); - } - } catch (ImsException e) { - loge("notifySrvccState : exception " + e); - } - } } private void resetState() { -- GitLab From ced0695ba2479c62a723e35c7e863274d969aa83 Mon Sep 17 00:00:00 2001 From: Azhara Assanova Date: Thu, 12 Jan 2023 11:03:42 +0000 Subject: [PATCH 327/656] Make mutable PendingIntents explicit Starting from target SDK U, we will block creation of mutable PendingIntents with implicit Intents because attackers can mutate the Intent object within and launch altered behavior on behalf of victim apps. For more details on the vulnerability, see go/pendingintent-rca. From a quick analysis, we concluded that the PendingIntents here were only destined to the test app/to the app, so they were made explicit. Reviewers, please call out if this is not the case. Bug: 236704164 Bug: 229362273 Test: atest FrameworksTelephonyTests Change-Id: I71e4130d2139a2ac1c73c2fe67c8b0d71b1f928c --- .../android/internal/telephony/cat/CatService.java | 12 ++++++++---- .../internal/telephony/gsm/GsmSmsDispatcherTest.java | 12 +++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java index 31b997fb57..621ae7ddc8 100644 --- a/src/java/com/android/internal/telephony/cat/CatService.java +++ b/src/java/com/android/internal/telephony/cat/CatService.java @@ -618,11 +618,15 @@ public class CatService extends Handler implements AppInterface { public void sendStkSms(String text, String destAddr, int subId, CommandParams cmdParams, ProxyController proxyController) { PendingIntent sentPendingIntent = PendingIntent.getBroadcast(mContext, 0, - new Intent(SMS_SENT_ACTION).putExtra("cmdDetails", - cmdParams.mCmdDet), PendingIntent.FLAG_MUTABLE); + new Intent(SMS_SENT_ACTION) + .putExtra("cmdDetails", cmdParams.mCmdDet) + .setPackage(mContext.getPackageName()), + PendingIntent.FLAG_MUTABLE); PendingIntent deliveryPendingIntent = PendingIntent.getBroadcast(mContext, 0, - new Intent(SMS_DELIVERY_ACTION).putExtra("cmdDetails", - cmdParams.mCmdDet), PendingIntent.FLAG_MUTABLE); + new Intent(SMS_DELIVERY_ACTION) + .putExtra("cmdDetails", cmdParams.mCmdDet) + .setPackage(mContext.getPackageName()), + PendingIntent.FLAG_MUTABLE); SmsController smsController = proxyController.getSmsController(); smsController.sendTextForSubscriber(subId, mContext.getOpPackageName(), mContext.getAttributionTag(), destAddr, null, text, sentPendingIntent, diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java index 4bf54155b1..523c9bb78d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java @@ -385,7 +385,9 @@ public class GsmSmsDispatcherTest extends TelephonyTest { registerTestIntentReceiver(); PendingIntent pendingIntent = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0, - new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE); + new Intent(TEST_INTENT) + .setPackage(TestApplication.getAppContext().getPackageName()), + PendingIntent.FLAG_MUTABLE); mReceivedTestIntent = false; mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms", @@ -440,9 +442,13 @@ public class GsmSmsDispatcherTest extends TelephonyTest { ArrayList sentIntents = new ArrayList<>(); PendingIntent sentIntent1 = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0, - new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE); + new Intent(TEST_INTENT) + .setPackage(TestApplication.getAppContext().getPackageName()), + PendingIntent.FLAG_MUTABLE); PendingIntent sentIntent2 = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0, - new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE); + new Intent(TEST_INTENT) + .setPackage(TestApplication.getAppContext().getPackageName()), + PendingIntent.FLAG_MUTABLE); sentIntents.add(sentIntent1); sentIntents.add(sentIntent2); -- GitLab From 0d0a315b9b6a95249a369f944ffa6ce110123ba9 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 12 Jan 2023 09:30:06 -0800 Subject: [PATCH 328/656] Fixed the mismatched protocol anomaly detector Use the correct roaming information from network registration info. Bug: 264845395 Test: Manual Change-Id: I13bb670117a51c4778a06e8125db6693bbde2cd8 --- src/java/com/android/internal/telephony/data/DataNetwork.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 3a0489f451..047ce5b101 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -2479,7 +2479,8 @@ public class DataNetwork extends StateMachine { } NetworkRegistrationInfo nri = getNetworkRegistrationInfo(); if (mDataProfile.getApnSetting() != null && nri != null && nri.isInService()) { - boolean isRoaming = mPhone.getServiceState().getDataRoamingFromRegistration(); + boolean isRoaming = nri.getNetworkRegistrationState() + == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; int protocol = isRoaming ? mDataProfile.getApnSetting().getRoamingProtocol() : mDataProfile.getApnSetting().getProtocol(); String underlyingDataService = mTransport -- GitLab From 6e63c1301e7e5aa27e191ee3e52e65b793def1be Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 11 Jan 2023 00:13:03 +0000 Subject: [PATCH 329/656] Clear IMS call information when SRVCC has completed Bug: 255450284 Test: atest ImsCallInfoNotifierTest Change-Id: I82bd36dd736b2770e4ada47c4cb59e36318640a3 --- .../telephony/imsphone/ImsCallInfo.java | 5 ++ .../imsphone/ImsCallInfoTracker.java | 60 +++++++++++++++++++ .../imsphone/ImsPhoneCallTracker.java | 2 + .../imsphone/ImsCallInfoTrackerTest.java | 54 +++++++++++++++++ .../imsphone/ImsPhoneCallTrackerTest.java | 35 +++++++++++ 5 files changed, 156 insertions(+) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsCallInfo.java b/src/java/com/android/internal/telephony/imsphone/ImsCallInfo.java index 718a98863b..79ab9c5b55 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsCallInfo.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsCallInfo.java @@ -78,6 +78,11 @@ public class ImsCallInfo { return changed; } + /** Called when clearing orphaned connection. */ + public void onDisconnect() { + mState = Call.State.DISCONNECTED; + } + /** @return the call index. */ public int getIndex() { return mIndex; diff --git a/src/java/com/android/internal/telephony/imsphone/ImsCallInfoTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsCallInfoTracker.java index aabe8d3ad5..5783e489b4 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsCallInfoTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsCallInfoTracker.java @@ -25,6 +25,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Call; import com.android.internal.telephony.Connection; import com.android.internal.telephony.Phone; +import com.android.telephony.Rlog; import java.util.ArrayList; import java.util.Collection; @@ -39,6 +40,8 @@ import java.util.Map; * Contains the state of all IMS calls. */ public class ImsCallInfoTracker { + private static final String LOG_TAG = "ImsCallInfoTracker"; + private static final boolean DBG = false; private final Phone mPhone; private final List mQueue = new ArrayList<>(); @@ -56,6 +59,8 @@ public class ImsCallInfoTracker { * @param c The instance of {@link ImsPhoneConnection}. */ public void addImsCallStatus(@NonNull ImsPhoneConnection c) { + if (DBG) Rlog.d(LOG_TAG, "addImsCallStatus"); + synchronized (mImsCallInfo) { if (mQueue.isEmpty()) { mQueue.add(new ImsCallInfo(mNextIndex++)); @@ -69,6 +74,8 @@ public class ImsCallInfoTracker { mImsCallInfo.put(c, imsCallInfo); notifyImsCallStatus(); + + if (DBG) dump(); } } @@ -90,16 +97,26 @@ public class ImsCallInfoTracker { */ public void updateImsCallStatus(@NonNull ImsPhoneConnection c, boolean holdReceived, boolean resumeReceived) { + if (DBG) { + Rlog.d(LOG_TAG, "updateImsCallStatus holdReceived=" + holdReceived + + ", resumeReceived=" + resumeReceived); + } synchronized (mImsCallInfo) { ImsCallInfo info = mImsCallInfo.get(c); + if (info == null) { + // This happens when the user tries to hangup the call after handover has completed. + return; + } + boolean changed = info.update(c, holdReceived, resumeReceived); if (changed) notifyImsCallStatus(); Call.State state = c.getState(); + if (DBG) Rlog.d(LOG_TAG, "updateImsCallStatus state=" + state); // Call is disconnected. There are 2 cases in disconnected state: // if silent redial, state == IDLE, otherwise, state == DISCONNECTED. if (state == DISCONNECTED || state == IDLE) { @@ -113,6 +130,42 @@ public class ImsCallInfoTracker { mNextIndex--; } } + + if (DBG) dump(); + } + } + + /** Clears all orphaned IMS call information. */ + public void clearAllOrphanedConnections() { + if (DBG) Rlog.d(LOG_TAG, "clearAllOrphanedConnections"); + + Collection infos = mImsCallInfo.values(); + infos.stream().forEach(info -> { info.onDisconnect(); }); + notifyImsCallStatus(); + clearAllCallInfo(); + + if (DBG) dump(); + } + + /** Notifies that SRVCC has completed. */ + public void notifySrvccCompleted() { + if (DBG) Rlog.d(LOG_TAG, "notifySrvccCompleted"); + + clearAllCallInfo(); + notifyImsCallStatus(); + + if (DBG) dump(); + } + + private void clearAllCallInfo() { + try { + Collection infos = mImsCallInfo.values(); + infos.stream().forEach(info -> { info.reset(); }); + mImsCallInfo.clear(); + mQueue.clear(); + mNextIndex = 1; + } catch (UnsupportedOperationException e) { + Rlog.e(LOG_TAG, "e=" + e); } } @@ -142,4 +195,11 @@ public class ImsCallInfoTracker { } }); } + + private void dump() { + Collection infos = mImsCallInfo.values(); + ArrayList imsCallInfo = new ArrayList(infos); + sort(imsCallInfo); + Rlog.d(LOG_TAG, "imsCallInfos=" + imsCallInfo); + } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 59f01ec1a6..6840f4be83 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -1479,6 +1479,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // above. Remove all references to it. mPendingMO = null; updatePhoneState(); + mImsCallInfoTracker.clearAllOrphanedConnections(); } /** @@ -4658,6 +4659,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { transferHandoverConnections(mBackgroundCall); transferHandoverConnections(mRingingCall); updatePhoneState(); + mImsCallInfoTracker.notifySrvccCompleted(); break; case TelephonyManager.SRVCC_STATE_HANDOVER_FAILED: diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallInfoTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallInfoTrackerTest.java index a0fc4b922b..e3fc6d3c75 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallInfoTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsCallInfoTrackerTest.java @@ -363,6 +363,60 @@ public class ImsCallInfoTrackerTest extends TelephonyTest { assertEquals(2, imsCallInfos.get(1).getIndex()); } + @Test + public void testSrvccCompleted() throws Exception { + ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); + + ImsPhoneConnection c = getConnection(Call.State.DIALING, false); + mImsCallInfoTracker.addImsCallStatus(c); + + verify(mImsPhone, times(1)).updateImsCallStatus(captor.capture(), any()); + + List imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + mImsCallInfoTracker.notifySrvccCompleted(); + + verify(mImsPhone, times(2)).updateImsCallStatus(captor.capture(), any()); + + imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(0, imsCallInfos.size()); + } + + @Test + public void testClearAllOrphanedConnections() throws Exception { + ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class); + + ImsPhoneConnection c = getConnection(Call.State.DIALING, false); + mImsCallInfoTracker.addImsCallStatus(c); + + verify(mImsPhone, times(1)).updateImsCallStatus(captor.capture(), any()); + + List imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + mImsCallInfoTracker.clearAllOrphanedConnections(); + + verify(mImsPhone, times(2)).updateImsCallStatus(captor.capture(), any()); + + imsCallInfos = captor.getValue(); + + assertNotNull(imsCallInfos); + assertEquals(1, imsCallInfos.size()); + + ImsCallInfo info = imsCallInfos.get(0); + + assertNotNull(info); + assertEquals(1, info.getIndex()); + assertEquals(Call.State.IDLE, info.getCallState()); + } + private ImsPhoneConnection getConnection(Call.State state, boolean isEmergency) { ImsPhoneConnection c = mock(ImsPhoneConnection.class); doReturn(isEmergency).when(c).isEmergencyCall(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 6ab76512d6..0af95e8837 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -2464,6 +2464,41 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { verify(mImsPhone, times(7)).updateImsCallStatus(any(), any()); } + @Test + public void testUpdateImsCallStatusSrvccCompleted() throws Exception { + // Incoming call + setupRingingConnection(); + + verify(mImsPhone, times(1)).updateImsCallStatus(any(), any()); + + // no interaction when SRVCC has started, failed, or canceled. + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_STARTED); + + verify(mImsPhone, times(1)).updateImsCallStatus(any(), any()); + + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_FAILED); + + verify(mImsPhone, times(1)).updateImsCallStatus(any(), any()); + + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_CANCELED); + + verify(mImsPhone, times(1)).updateImsCallStatus(any(), any()); + + // interaction when SRVCC has completed + mCTUT.notifySrvccState(SRVCC_STATE_HANDOVER_COMPLETED); + + verify(mImsPhone, times(2)).updateImsCallStatus(any(), any()); + } + + @Test + public void testClearAllOrphanedConnectionInfo() throws Exception { + verify(mImsPhone, times(0)).updateImsCallStatus(any(), any()); + + mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); + + verify(mImsPhone, times(1)).updateImsCallStatus(any(), any()); + } + /** Verifies that the request from ImsService is passed to ImsPhone as expected. */ @Test @SmallTest -- GitLab From d1a497565aae54455f84f704209affc414c303de Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Mon, 31 Oct 2022 22:45:28 +0000 Subject: [PATCH 330/656] Make InboundSmsHandler run on the main thread Bug: 255583263 Test: run the following tests - manual send and receive SMS - atest com.android.internal.telephony.gsm.GsmInboundSmsHandlerTest - atest com.android.internal.telephony.SmsDispatchersControllerTest Change-Id: Ica671de809f3ad454948a220ed159f58d1c138b0 --- .../internal/telephony/InboundSmsHandler.java | 5 +++-- .../telephony/SmsDispatchersController.java | 13 +++++++++++-- .../telephony/cdma/CdmaInboundSmsHandler.java | 10 ++++++---- .../telephony/gsm/GsmInboundSmsHandler.java | 10 ++++++---- .../telephony/SmsDispatchersControllerTest.java | 8 ++++---- .../telephony/cdma/CdmaInboundSmsHandlerTest.java | 12 ++++++------ .../telephony/gsm/GsmInboundSmsHandlerTest.java | 3 +-- 7 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java index 802223d043..91667199b3 100644 --- a/src/java/com/android/internal/telephony/InboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java @@ -52,6 +52,7 @@ import android.net.Uri; import android.os.AsyncResult; import android.os.Build; import android.os.Bundle; +import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.PowerWhitelistManager; @@ -287,8 +288,8 @@ public abstract class InboundSmsHandler extends StateMachine { * @param storageMonitor the SmsStorageMonitor to check for storage availability */ protected InboundSmsHandler(String name, Context context, SmsStorageMonitor storageMonitor, - Phone phone) { - super(name); + Phone phone, Looper looper) { + super(name, looper); mContext = context; mStorageMonitor = storageMonitor; diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java index cbd1aafcb3..e434801c97 100644 --- a/src/java/com/android/internal/telephony/SmsDispatchersController.java +++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java @@ -33,6 +33,7 @@ import android.net.Uri; import android.os.AsyncResult; import android.os.Binder; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.UserManager; import android.provider.Telephony.Sms; @@ -331,6 +332,14 @@ public class SmsDispatchersController extends Handler { public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, SmsUsageMonitor usageMonitor) { + this(phone, storageMonitor, usageMonitor, phone.getLooper()); + } + + @VisibleForTesting + public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, + SmsUsageMonitor usageMonitor, Looper looper) { + super(looper); + Rlog.d(TAG, "SmsDispatchersController created"); mContext = phone.getContext(); @@ -343,9 +352,9 @@ public class SmsDispatchersController extends Handler { mImsSmsDispatcher = new ImsSmsDispatcher(phone, this, ImsManager::getConnector); mCdmaDispatcher = new CdmaSMSDispatcher(phone, this); mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), - storageMonitor, phone); + storageMonitor, phone, looper); mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), - storageMonitor, phone, (CdmaSMSDispatcher) mCdmaDispatcher); + storageMonitor, phone, (CdmaSMSDispatcher) mCdmaDispatcher, looper); mGsmDispatcher = new GsmSMSDispatcher(phone, this, mGsmInboundSmsHandler); SmsBroadcastUndelivered.initialize(phone.getContext(), mGsmInboundSmsHandler, mCdmaInboundSmsHandler); diff --git a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java index 096dba1419..784c9743f8 100644 --- a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; +import android.os.Looper; import android.os.Message; import android.os.RemoteCallback; import android.os.SystemProperties; @@ -77,8 +78,8 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler { * Create a new inbound SMS handler for CDMA. */ private CdmaInboundSmsHandler(Context context, SmsStorageMonitor storageMonitor, - Phone phone, CdmaSMSDispatcher smsDispatcher) { - super("CdmaInboundSmsHandler", context, storageMonitor, phone); + Phone phone, CdmaSMSDispatcher smsDispatcher, Looper looper) { + super("CdmaInboundSmsHandler", context, storageMonitor, phone, looper); mSmsDispatcher = smsDispatcher; phone.mCi.setOnNewCdmaSms(getHandler(), EVENT_NEW_SMS, null); @@ -169,9 +170,10 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler { * Wait for state machine to enter startup state. We can't send any messages until then. */ public static CdmaInboundSmsHandler makeInboundSmsHandler(Context context, - SmsStorageMonitor storageMonitor, Phone phone, CdmaSMSDispatcher smsDispatcher) { + SmsStorageMonitor storageMonitor, Phone phone, CdmaSMSDispatcher smsDispatcher, + Looper looper) { CdmaInboundSmsHandler handler = new CdmaInboundSmsHandler(context, storageMonitor, - phone, smsDispatcher); + phone, smsDispatcher, looper); handler.start(); return handler; } diff --git a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java index 98fbcf81be..907f1586a7 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/gsm/GsmInboundSmsHandler.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.AsyncResult; import android.os.Build; +import android.os.Looper; import android.os.Message; import android.os.SystemProperties; import android.provider.Telephony.Sms.Intents; @@ -57,8 +58,8 @@ public class GsmInboundSmsHandler extends InboundSmsHandler { * Create a new GSM inbound SMS handler. */ private GsmInboundSmsHandler(Context context, SmsStorageMonitor storageMonitor, - Phone phone) { - super("GsmInboundSmsHandler", context, storageMonitor, phone); + Phone phone, Looper looper) { + super("GsmInboundSmsHandler", context, storageMonitor, phone, looper); phone.mCi.setOnNewGsmSms(getHandler(), EVENT_NEW_SMS, null); mDataDownloadHandler = new UsimDataDownloadHandler(phone.mCi, phone.getPhoneId()); mCellBroadcastServiceManager.enable(); @@ -128,8 +129,9 @@ public class GsmInboundSmsHandler extends InboundSmsHandler { * Wait for state machine to enter startup state. We can't send any messages until then. */ public static GsmInboundSmsHandler makeInboundSmsHandler(Context context, - SmsStorageMonitor storageMonitor, Phone phone) { - GsmInboundSmsHandler handler = new GsmInboundSmsHandler(context, storageMonitor, phone); + SmsStorageMonitor storageMonitor, Phone phone, Looper looper) { + GsmInboundSmsHandler handler = + new GsmInboundSmsHandler(context, storageMonitor, phone, looper); handler.start(); return handler; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java index 7912832443..427963b10f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java @@ -41,6 +41,7 @@ import android.app.PendingIntent; import android.content.Intent; import android.net.Uri; import android.os.AsyncResult; +import android.os.Looper; import android.os.Message; import android.provider.Telephony.Sms.Intents; import android.telephony.DisconnectCause; @@ -79,8 +80,8 @@ public class SmsDispatchersControllerTest extends TelephonyTest { */ private static class TestSmsDispatchersController extends SmsDispatchersController { TestSmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, - SmsUsageMonitor usageMonitor) { - super(phone, storageMonitor, usageMonitor); + SmsUsageMonitor usageMonitor, Looper looper) { + super(phone, storageMonitor, usageMonitor, looper); } public DomainSelectionConnectionHolder testGetDomainSelectionConnectionHolder( @@ -174,9 +175,8 @@ public class SmsDispatchersControllerTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mTracker = mock(SMSDispatcher.SmsTracker.class); setupMockPackagePermissionChecks(); - mSmsDispatchersController = new TestSmsDispatchersController(mPhone, mSmsStorageMonitor, - mSmsUsageMonitor); + mSmsUsageMonitor, mTestableLooper.getLooper()); setUpDomainSelectionConnectionAsNotSupported(); processAllMessages(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java index 5df94e5db8..34459399bb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java @@ -57,11 +57,6 @@ import com.android.internal.telephony.cdma.sms.SmsEnvelope; import com.android.internal.util.IState; import com.android.internal.util.StateMachine; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -69,6 +64,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class CdmaInboundSmsHandlerTest extends TelephonyTest { @@ -157,7 +157,7 @@ public class CdmaInboundSmsHandlerTest extends TelephonyTest { Telephony.Sms.CONTENT_URI.getAuthority(), mContentProvider); mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(mContext, - mSmsStorageMonitor, mPhone, null); + mSmsStorageMonitor, mPhone, null, mTestableLooper.getLooper()); monitorTestableLooper(new TestableLooper(mCdmaInboundSmsHandler.getHandler().getLooper())); processAllMessages(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java index 1df90f8139..7a516404f8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java @@ -203,12 +203,11 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { Telephony.Sms.CONTENT_URI.getAuthority(), mContentProvider); mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(mContext, - mSmsStorageMonitor, mPhone); + mSmsStorageMonitor, mPhone, mTestableLooper.getLooper()); mSmsFilters = new ArrayList<>(); mSmsFilters.add(mSmsFilter); mSmsFilters.add(mSmsFilter2); mGsmInboundSmsHandler.setSmsFiltersForTesting(mSmsFilters); - monitorTestableLooper(new TestableLooper(mGsmInboundSmsHandler.getHandler().getLooper())); doReturn(mGsmInboundSmsHandler).when(mPhone).getInboundSmsHandler(false); doReturn(mCdmaInboundSmsHandler).when(mPhone).getInboundSmsHandler(true); -- GitLab From b709ee9da4b9e8a4848298e8fbbac63f5710137f Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 12 Jan 2023 14:52:01 -0800 Subject: [PATCH 331/656] Unregister callback on data network disconnect Remove the data network reference from dataNetworkControllerCallbacks when the network disconnect. Test: voice call + data browsing + review log Bug: 241212926 Change-Id: Ie37c67f462c122e32eaff4563c5aed5cc4aa6f3b --- .../internal/telephony/data/DataNetwork.java | 18 ++++++++++----- .../data/DataNetworkControllerTest.java | 22 ++++++++++++++++--- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 3a0489f451..42c4691152 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -551,6 +551,10 @@ public class DataNetwork extends StateMachine { /** Data network controller. */ private final @NonNull DataNetworkController mDataNetworkController; + /** Data network controller callback. */ + private final @NonNull DataNetworkController.DataNetworkControllerCallback + mDataNetworkControllerCallback; + /** Data config manager. */ private final @NonNull DataConfigManager mDataConfigManager; @@ -887,12 +891,14 @@ public class DataNetwork extends StateMachine { mAccessNetworksManager = phone.getAccessNetworksManager(); mVcnManager = mPhone.getContext().getSystemService(VcnManager.class); mDataNetworkController = phone.getDataNetworkController(); + mDataNetworkControllerCallback = new DataNetworkController.DataNetworkControllerCallback( + getHandler()::post) { + @Override + public void onSubscriptionPlanOverride() { + sendMessage(EVENT_SUBSCRIPTION_PLAN_OVERRIDE); + }}; mDataNetworkController.registerDataNetworkControllerCallback( - new DataNetworkController.DataNetworkControllerCallback(getHandler()::post) { - @Override - public void onSubscriptionPlanOverride() { - sendMessage(EVENT_SUBSCRIPTION_PLAN_OVERRIDE); - }}); + mDataNetworkControllerCallback); mDataConfigManager = mDataNetworkController.getDataConfigManager(); mDataCallSessionStats = new DataCallSessionStats(mPhone); mDataNetworkCallback = callback; @@ -1585,6 +1591,8 @@ public class DataNetwork extends StateMachine { } notifyPreciseDataConnectionState(); mNetworkAgent.unregister(); + mDataNetworkController.unregisterDataNetworkControllerCallback( + mDataNetworkControllerCallback); mDataCallSessionStats.onDataCallDisconnected(mFailCause); if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WLAN 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 de9d0ef61f..cd50dfb2fb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -1215,16 +1215,32 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testDataNetworkControllerCallback() throws Exception { + Field field = DataNetworkController.class.getDeclaredField( + "mDataNetworkControllerCallbacks"); + field.setAccessible(true); + Set dataNetworkControllerCallbacks = + (Set) field.get(mDataNetworkControllerUT); + + // Verify register callback mDataNetworkControllerUT.registerDataNetworkControllerCallback( mMockedDataNetworkControllerCallback); + TelephonyNetworkRequest request = createNetworkRequest( + NetworkCapabilities.NET_CAPABILITY_INTERNET); + mDataNetworkControllerUT.addNetworkRequest(request); processAllMessages(); - testSetupDataNetwork(); verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(true)); verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkConnected(any()); - mDataNetworkControllerUT.unregisterDataNetworkControllerCallback( - mMockedDataNetworkControllerCallback); + int countOfCallbacks = dataNetworkControllerCallbacks.size(); + + // Verify unregister callback + mDataNetworkControllerUT.removeNetworkRequest(request); processAllMessages(); + getDataNetworks().get(0).tearDown(DataNetwork + .TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED); + processAllFutureMessages(); + + assertEquals(countOfCallbacks - 1, dataNetworkControllerCallbacks.size()); } @Test -- GitLab From 27c7595c1a8dc37e34ae85375f9c6735ced56704 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 12 Jan 2023 16:13:31 -0800 Subject: [PATCH 332/656] Anomaly report only check IP on setup response Skip the detection for handover response and data state change because fwk doesn't have the most up-to-date roaming info comparing to the data services, thus fwk honor data service's decision in these cases. Fix: 263820928 Test: voice call + data browsing Change-Id: I5598acac410400b4e3abd9a3ca3d1ec29efcbbe6 --- .../internal/telephony/data/DataNetwork.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 5ed2c92fe8..ec34e7d5e0 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -2392,7 +2392,7 @@ public class DataNetwork extends StateMachine { logl("onSetupResponse: resultCode=" + DataServiceCallback.resultCodeToString(resultCode) + ", response=" + response); mFailCause = getFailCauseFromDataCallResponse(resultCode, response); - validateDataCallResponse(response); + validateDataCallResponse(response, true /*isSetupResponse*/); if (mFailCause == DataFailCause.NONE) { DataNetwork dataNetwork = mDataNetworkController.getDataNetworkByInterface( response.getInterfaceName()); @@ -2464,8 +2464,10 @@ public class DataNetwork extends StateMachine { * If the {@link DataCallResponse} contains invalid info, triggers an anomaly report. * * @param response The response to be validated + * @param isSetupResponse {@code true} if the response is for initial data call setup */ - private void validateDataCallResponse(@Nullable DataCallResponse response) { + private void validateDataCallResponse(@Nullable DataCallResponse response, + boolean isSetupResponse) { if (response == null || response.getLinkStatus() == DataCallResponse.LINK_STATUS_INACTIVE) return; int failCause = response.getCause(); @@ -2485,8 +2487,10 @@ public class DataNetwork extends StateMachine { reportAnomaly("Invalid DataCallResponse detected", "1f273e9d-b09c-46eb-ad1c-421d01f61164"); } + // Check IP for initial setup response NetworkRegistrationInfo nri = getNetworkRegistrationInfo(); - if (mDataProfile.getApnSetting() != null && nri != null && nri.isInService()) { + if (isSetupResponse + && mDataProfile.getApnSetting() != null && nri != null && nri.isInService()) { boolean isRoaming = nri.getNetworkRegistrationState() == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; int protocol = isRoaming ? mDataProfile.getApnSetting().getRoamingProtocol() @@ -2646,7 +2650,7 @@ public class DataNetwork extends StateMachine { if (response != null) { if (!response.equals(mDataCallResponse)) { log("onDataStateChanged: " + response); - validateDataCallResponse(response); + validateDataCallResponse(response, false /*isSetupResponse*/); mDataCallResponse = response; if (response.getLinkStatus() != DataCallResponse.LINK_STATUS_INACTIVE) { updateDataNetwork(response); @@ -3224,7 +3228,7 @@ public class DataNetwork extends StateMachine { logl("onHandoverResponse: resultCode=" + DataServiceCallback.resultCodeToString(resultCode) + ", response=" + response); mFailCause = getFailCauseFromDataCallResponse(resultCode, response); - validateDataCallResponse(response); + validateDataCallResponse(response, false /*isSetupResponse*/); if (mFailCause == DataFailCause.NONE) { // Handover succeeded. -- GitLab From 16da4b8361ae03df8e51f16ba660946478fe336f Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 5 Jan 2023 15:38:47 -0800 Subject: [PATCH 333/656] Use averagingWindowMillis instead of averagingWindowMs Use averagingWindowMs when averagingWindowMillis is unknown. Test: build Bug: 264261216 Change-Id: Ibf042932ddef203da887e861f9f9f58ae5984bb7 --- src/java/com/android/internal/telephony/RILUtils.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 95b0011fd3..708a642df1 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -3869,9 +3869,13 @@ public class RILUtils { convertHalQosBandwidth(eps.uplink), eps.qci); case android.hardware.radio.data.Qos.nr: android.hardware.radio.data.NrQos nr = qos.getNr(); + int averagingWindowMs = nr.averagingWindowMillis; + if (averagingWindowMs + == android.hardware.radio.data.NrQos.AVERAGING_WINDOW_UNKNOWN) { + averagingWindowMs = nr.averagingWindowMs; + } return new NrQos(convertHalQosBandwidth(nr.downlink), - convertHalQosBandwidth(nr.uplink), nr.qosFlowIdentifier, nr.fiveQi, - nr.averagingWindowMs); + convertHalQosBandwidth(nr.uplink), nr.qfi, nr.fiveQi, averagingWindowMs); default: return null; } -- GitLab From 4345e235163cd9e50ba6f1db7f0b53d3f2633257 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Sat, 17 Dec 2022 00:35:49 +0000 Subject: [PATCH 334/656] Handle the result of sending RP-SMMA in framework - Receive the callback Api onMemoryAvailbleResult in framework - Bug: b/240883268 Test: atest ImsSmsDispatcherTest, Tested Memory full and Not Full conditions in Pixel Change-Id: Ib1cffd39cdd51a6c8dd1dea6cf62d13d26af999c --- .../internal/telephony/ImsSmsDispatcher.java | 42 +++++++++++++++++++ .../internal/telephony/SMSDispatcher.java | 10 +++++ 2 files changed, 52 insertions(+) diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java index c6a17a620d..e0529e12e3 100644 --- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java +++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java @@ -44,7 +44,9 @@ import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.util.SMSDispatcherUtil; import com.android.telephony.Rlog; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; @@ -74,6 +76,7 @@ public class ImsSmsDispatcher extends SMSDispatcher { FeatureConnector.Listener listener, Executor executor); } + public List mMemoryAvailableNotifierList = new ArrayList(); @VisibleForTesting public Map mTrackers = new ConcurrentHashMap<>(); @VisibleForTesting @@ -141,6 +144,37 @@ public class ImsSmsDispatcher extends SMSDispatcher { }; private final IImsSmsListener mImsSmsListener = new IImsSmsListener.Stub() { + @Override + public void onMemoryAvailableResult(int token, @SendStatusResult int status, + int networkReasonCode) { + final long identity = Binder.clearCallingIdentity(); + try { + logd("onMemoryAvailableResult token=" + token + " status=" + status + + " networkReasonCode=" + networkReasonCode); + if (!mMemoryAvailableNotifierList.contains(token)) { + loge("onMemoryAvailableResult Invalid token"); + return; + } + mMemoryAvailableNotifierList.remove(Integer.valueOf(token)); + + /** + * The Retrans flag is set and reset As per section 6.3.3.1.2 in TS 124011 + * Note: Assuming that SEND_STATUS_ERROR_RETRY is sent in case of temporary failure + */ + if (status == ImsSmsImplBase.SEND_STATUS_ERROR_RETRY) { + if (!mRPSmmaRetried) { + sendMessageDelayed(obtainMessage(EVENT_RETRY_SMMA), SEND_RETRY_DELAY); + mRPSmmaRetried = true; + } else { + mRPSmmaRetried = false; + } + } else { + mRPSmmaRetried = false; + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } @Override public void onSendSmsResult(int token, int messageRef, @SendStatusResult int status, @SmsManager.Result int reason, int networkReasonCode) { @@ -293,6 +327,10 @@ public class ImsSmsDispatcher extends SMSDispatcher { logd("SMS retry.."); sendSms((SmsTracker) msg.obj); break; + case EVENT_RETRY_SMMA: + logd("SMMA Notification retry.."); + onMemoryAvailable(); + break; default: super.handleMessage(msg); } @@ -540,9 +578,13 @@ public class ImsSmsDispatcher extends SMSDispatcher { int token = mNextToken.incrementAndGet(); try { logd("onMemoryAvailable: token = " + token); + mMemoryAvailableNotifierList.add(token); getImsManager().onMemoryAvailable(token); } catch (ImsException e) { loge("onMemoryAvailable failed: " + e.getMessage()); + if (mMemoryAvailableNotifierList.contains(token)) { + mMemoryAvailableNotifierList.remove(Integer.valueOf(token)); + } } } diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 6746d7bab2..808761b24b 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -149,6 +149,8 @@ public abstract class SMSDispatcher extends Handler { /** New status report received. */ protected static final int EVENT_NEW_SMS_STATUS_REPORT = 10; + /** Retry Sending RP-SMMA Notification */ + protected static final int EVENT_RETRY_SMMA = 11; // other protected static final int EVENT_NEW_ICC_SMS = 14; protected static final int EVENT_ICC_CHANGED = 15; @@ -186,6 +188,14 @@ public abstract class SMSDispatcher extends Handler { /** Maximum number of times to retry sending a failed SMS. */ protected static final int MAX_SEND_RETRIES = 3; + + /** Retransmitted Flag as specified in section 6.3.1.2 in TS 124011 + * true: RP-SMMA Retried once and no more transmissions are permitted + * false: not retried at all and at least another transmission of the RP-SMMA message + * is currently permitted + */ + protected boolean mRPSmmaRetried = false; + /** Delay before next send attempt on a failed SMS, in milliseconds. */ @VisibleForTesting public static final int SEND_RETRY_DELAY = 2000; -- GitLab From 4f746244891d2fd56283db37f9beaab455ecb007 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Tue, 20 Dec 2022 05:37:38 +0000 Subject: [PATCH 335/656] Unit Tests for onMemoryAvailaleResult Api - Unit Testcases covering ERROR, ERROR_RETRY and OK scenarios Bug: b/240883268 Test: atest ImsSmsDispatcherTest Change-Id: Ic96d0437a771ebb9dbe848d89f3641f0cc9a637d --- .../telephony/ImsSmsDispatcherTest.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java index 858fa2f50e..6ffceaf0c1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java @@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -114,6 +115,73 @@ public class ImsSmsDispatcherTest extends TelephonyTest { assertEquals(token + 1, mImsSmsDispatcher.mNextToken.get()); verify(mImsManager).onMemoryAvailable(eq(token + 1)); } + + /** + * Receive SEND_STATUS_ERROR_RETRY with onMemoryAvailableResult Api and check if + * sending SMMA Notification is retried once + */ + @Test + @SmallTest + public void testOnMemoryAvailableResultErrorRetry() throws Exception { + int token = mImsSmsDispatcher.mNextToken.get(); + //Send SMMA + mImsSmsDispatcher.onMemoryAvailable(); + assertEquals(token + 1, mImsSmsDispatcher.mNextToken.get()); + verify(mImsManager).onMemoryAvailable(eq(token + 1)); + // Retry over IMS + mImsSmsDispatcher.getSmsListener().onMemoryAvailableResult(token + 1, + ImsSmsImplBase.SEND_STATUS_ERROR_RETRY, SmsResponse.NO_ERROR_CODE); + waitForMs(SMSDispatcher.SEND_RETRY_DELAY + 200); + processAllMessages(); + verify(mImsManager).onMemoryAvailable(eq(token + 2)); + //2nd Failure should not retry + mImsSmsDispatcher.getSmsListener().onMemoryAvailableResult(token + 2, + ImsSmsImplBase.SEND_STATUS_ERROR_RETRY, SmsResponse.NO_ERROR_CODE); + waitForMs(SMSDispatcher.SEND_RETRY_DELAY + 200); + processAllMessages(); + verify(mImsManager, times(0)).onMemoryAvailable(eq(token + 3)); + + } + /** + * Receive SEND_STATUS_OK with onMemoryAvailableResult Api and check if + * sending SMMA Notification behaviour is correct + */ + @Test + @SmallTest + public void testOnMemoryAvailableResultSuccess() throws Exception { + int token = mImsSmsDispatcher.mNextToken.get(); + //Send SMMA + mImsSmsDispatcher.onMemoryAvailable(); + assertEquals(token + 1, mImsSmsDispatcher.mNextToken.get()); + verify(mImsManager).onMemoryAvailable(eq(token + 1)); + // Retry over IMS + mImsSmsDispatcher.getSmsListener().onMemoryAvailableResult(token + 1, + ImsSmsImplBase.SEND_STATUS_OK, SmsResponse.NO_ERROR_CODE); + waitForMs(SMSDispatcher.SEND_RETRY_DELAY + 200); + processAllMessages(); + verify(mImsManager, times(0)).onMemoryAvailable(eq(token + 2)); + + } + /** + * Receive SEND_STATUS_ERROR with onMemoryAvailableResult Api and check if + * sending SMMA Notification behaviour is correct + */ + @Test + @SmallTest + public void testOnMemoryAvailableResultError() throws Exception { + int token = mImsSmsDispatcher.mNextToken.get(); + //Send SMMA + mImsSmsDispatcher.onMemoryAvailable(); + assertEquals(token + 1, mImsSmsDispatcher.mNextToken.get()); + verify(mImsManager).onMemoryAvailable(eq(token + 1)); + // Retry over IMS + mImsSmsDispatcher.getSmsListener().onMemoryAvailableResult(token + 1, + ImsSmsImplBase.SEND_STATUS_ERROR, SmsResponse.NO_ERROR_CODE); + waitForMs(SMSDispatcher.SEND_RETRY_DELAY + 200); + processAllMessages(); + verify(mImsManager, times(0)).onMemoryAvailable(eq(token + 2)); + + } /** * Send an SMS and verify that the token and PDU is correct. */ -- GitLab From 725f0e518abf1c1efaef720510e9877132f19577 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 14 Jan 2023 12:42:07 -0800 Subject: [PATCH 336/656] Fixed the set/getAllowedNetworkTypes debug messages Made the debug message more readable. Fix: 265535191 Test: Manual Change-Id: If24426143edcba17ef68fa6dedc39aa8d5a5d403 --- .../com/android/internal/telephony/Phone.java | 65 +++++-------------- .../data/LinkBandwidthEstimator.java | 6 +- .../SubscriptionInfoInternal.java | 31 +++++++-- 3 files changed, 46 insertions(+), 56 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index ed4214d354..806b0c01be 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -470,10 +470,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected SimulatedRadioControl mSimulatedRadioControl; private Map mAllowedNetworkTypesForReasons = new HashMap<>(); - private static final String ALLOWED_NETWORK_TYPES_TEXT_USER = "user"; - private static final String ALLOWED_NETWORK_TYPES_TEXT_POWER = "power"; - private static final String ALLOWED_NETWORK_TYPES_TEXT_CARRIER = "carrier"; - private static final String ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G = "enable_2g"; private static final int INVALID_ALLOWED_NETWORK_TYPES = -1; protected boolean mIsCarrierNrSupported = false; protected boolean mIsAllowedNetworkTypesLoadedFromDb = false; @@ -2328,9 +2324,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ public void notifyAllowedNetworkTypesChanged( @TelephonyManager.AllowedNetworkTypesReason int reason) { - logd("SubId" + getSubId() + ",notifyAllowedNetworkTypesChanged: reason: " + reason - + " value:" + TelephonyManager.convertNetworkTypeBitmaskToString( - getAllowedNetworkTypes(reason))); + logd("notifyAllowedNetworkTypesChanged: subId=" + getSubId() + ", reason=" + + TelephonyManager.allowedNetworkTypesReasonToString(reason) + + " network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( + getAllowedNetworkTypes(reason))); mNotifier.notifyAllowedNetworkTypesChanged(this, reason, getAllowedNetworkTypes(reason)); } @@ -2382,9 +2379,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { && reason == TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER) { allowedNetworkTypes = updateAllowedNetworkTypeForCarrierWithCarrierConfig(); } - logd("SubId" + getSubId() + ",get allowed network types " - + convertAllowedNetworkTypeMapIndexToDbName(reason) - + ": value = " + TelephonyManager.convertNetworkTypeBitmaskToString( + logd("getAllowedNetworkTypes: subId=" + getSubId() + ", reason=" + + TelephonyManager.allowedNetworkTypesReasonToString(reason) + + ", network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( allowedNetworkTypes)); return allowedNetworkTypes; } @@ -2419,7 +2416,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return; } - logd("SubId" + getSubId() + ",load allowed network types : value = " + result); + logd("loadAllowedNetworksFromSubscriptionDatabase: subId=" + getSubId() + ", " + + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(result)); Map oldAllowedNetworkTypes = new HashMap<>(mAllowedNetworkTypesForReasons); mAllowedNetworkTypesForReasons.clear(); try { @@ -2430,10 +2428,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { Rlog.e(LOG_TAG, "Invalid ALLOWED_NETWORK_TYPES from DB, value = " + pair); continue; } - int key = convertAllowedNetworkTypeDbNameToMapIndex(networkTypesValues[0]); + int key = TelephonyManager.allowedNetworkTypesReasonFromString( + networkTypesValues[0]); long value = Long.parseLong(networkTypesValues[1]); - if (key != INVALID_ALLOWED_NETWORK_TYPES - && value != INVALID_ALLOWED_NETWORK_TYPES) { + if (value != INVALID_ALLOWED_NETWORK_TYPES) { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(key, value); } @@ -2455,36 +2453,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } } - private int convertAllowedNetworkTypeDbNameToMapIndex(String name) { - switch (name) { - case ALLOWED_NETWORK_TYPES_TEXT_USER: - return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER; - case ALLOWED_NETWORK_TYPES_TEXT_POWER: - return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER; - case ALLOWED_NETWORK_TYPES_TEXT_CARRIER: - return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER; - case ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G: - return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G; - default: - return INVALID_ALLOWED_NETWORK_TYPES; - } - } - - private String convertAllowedNetworkTypeMapIndexToDbName(int reason) { - switch (reason) { - case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER: - return ALLOWED_NETWORK_TYPES_TEXT_USER; - case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER: - return ALLOWED_NETWORK_TYPES_TEXT_POWER; - case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER: - return ALLOWED_NETWORK_TYPES_TEXT_CARRIER; - case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G: - return ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G; - default: - return Integer.toString(INVALID_ALLOWED_NETWORK_TYPES); - } - } - private @TelephonyManager.NetworkTypeBitMask long updateAllowedNetworkTypeForCarrierWithCarrierConfig() { long defaultAllowedNetworkTypes = RadioAccessFamily.getRafFromNetworkType( @@ -2526,8 +2494,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } if (!SubscriptionManager.isUsableSubscriptionId(subId) || !mIsAllowedNetworkTypesLoadedFromDb) { - loge("setAllowedNetworkTypes: no sim or network type is not loaded. SubscriptionId: " - + subId + ", isNetworkTypeLoaded" + mIsAllowedNetworkTypesLoadedFromDb); + loge("setAllowedNetworkTypes: no sim or network type is not loaded. subId=" + + subId + ", isNetworkTypeLoaded=" + mIsAllowedNetworkTypesLoadedFromDb); if (response != null) { AsyncResult.forMessage(response, null, new CommandException(CommandException.Error.MISSING_RESOURCE)); @@ -2539,14 +2507,15 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(reason, networkTypes); mapAsString = mAllowedNetworkTypesForReasons.keySet().stream() - .map(key -> convertAllowedNetworkTypeMapIndexToDbName(key) + "=" + .map(key -> TelephonyManager.allowedNetworkTypesReasonToString(key) + "=" + mAllowedNetworkTypesForReasons.get(key)) .collect(Collectors.joining(",")); } SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, mapAsString); - logd("setAllowedNetworkTypes: SubId" + subId + ",setAllowedNetworkTypes " + mapAsString); + logd("setAllowedNetworkTypes: subId=" + subId + ", " + + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(mapAsString)); updateAllowedNetworkTypes(response); notifyAllowedNetworkTypesChanged(reason); diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index 994e8f67fb..73aa92d5bd 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -141,9 +141,9 @@ public class LinkBandwidthEstimator extends Handler { private static final int MAX_ERROR_PERCENT = 100 * 100; private static final String[] AVG_BW_PER_RAT = { "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA:14,14", - "CDMA - 1xRTT:30,30", "CDMA - EvDo rev. 0:750,48", "CDMA - EvDo rev. A:950,550", - "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "CDMA - EvDo rev. B:1500,550", - "CDMA - eHRPD:750,48", "HSPA+:13000,3400", "TD_SCDMA:115,115", + "1xRTT:30,30", "EVDO-0:750,48", "EVDO-A:950,550", + "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "EVDO-B:1500,550", + "eHRPD:750,48", "HSPA+:13000,3400", "TD-SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,18000", "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000", "NR_MMWAVE:145000,60000"}; private static final Map> AVG_BW_PER_RAT_MAP = new ArrayMap<>(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index b0262b0271..222c4b97f6 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -55,6 +55,8 @@ import com.android.telephony.Rlog; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * The class represents a single row of {@link SimInfo} table. All columns (excepts unused columns) @@ -1037,7 +1039,7 @@ public class SubscriptionInfoInternal { * * @return The stripped string. */ - public static String givePrintableId(String id) { + public static String getPrintableId(String id) { String idToPrint = null; if (id != null) { int len = id.length(); @@ -1050,10 +1052,28 @@ public class SubscriptionInfoInternal { return idToPrint; } + /** + * Convert the allowed network types for reasons to readable format. + * + * @param allowedNetworkTypesForReasons The raw value of allowed network types for reasons + * stored in the database. + * + * @return The converted string. + */ + public static String getPrintableAllowedNetworkTypesForReasons( + @NonNull String allowedNetworkTypesForReasons) { + if (TextUtils.isEmpty(allowedNetworkTypesForReasons)) return ""; + return Stream.of(allowedNetworkTypesForReasons.split(",")) + .map(s -> s.substring(0, s.indexOf("=") + 1) + + TelephonyManager.convertNetworkTypeBitmaskToString( + Long.parseLong(s.substring(s.indexOf("=") + 1)))) + .collect(Collectors.joining(", ")); + } + @Override public String toString() { return "[SubscriptionInfoInternal: id=" + mId - + " iccId=" + givePrintableId(mIccId) + + " iccId=" + getPrintableId(mIccId) + " simSlotIndex=" + mSimSlotIndex + " portIndex=" + mPortIndex + " isEmbedded=" + mIsEmbedded @@ -1073,7 +1093,7 @@ public class SubscriptionInfoInternal { + " mnc=" + mMnc + " ehplmns=" + mEhplmns + " hplmns=" + mHplmns - + " cardString=" + givePrintableId(mCardString) + + " cardString=" + getPrintableId(mCardString) + " cardId=" + mCardId + " nativeAccessRules=" + IccUtils.bytesToHexString(mNativeAccessRules) + " carrierConfigAccessRules=" + IccUtils.bytesToHexString( @@ -1091,11 +1111,12 @@ public class SubscriptionInfoInternal { + " wifiCallingModeForRoaming=" + ImsMmTelManager.wifiCallingModeToString(mWifiCallingModeForRoaming) + " enabledMobileDataPolicies=" + mEnabledMobileDataPolicies - + " imsi=" + givePrintableId(mImsi) + + " imsi=" + getPrintableId(mImsi) + " rcsUceEnabled=" + mIsRcsUceEnabled + " crossSimCallingEnabled=" + mIsCrossSimCallingEnabled + " rcsConfig=" + IccUtils.bytesToHexString(mRcsConfig) - + " allowedNetworkTypesForReasons=" + mAllowedNetworkTypesForReasons + + " allowedNetworkTypesForReasons=" + + getPrintableAllowedNetworkTypesForReasons(mAllowedNetworkTypesForReasons) + " deviceToDeviceStatusSharingPreference=" + mDeviceToDeviceStatusSharingPreference + " isVoImsOptInEnabled=" + mIsVoImsOptInEnabled + " deviceToDeviceStatusSharingContacts=" + mDeviceToDeviceStatusSharingContacts -- GitLab From bdb0d88ca9b9580e44975dd1bff347bc8022cd80 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Mon, 16 Jan 2023 06:25:50 +0000 Subject: [PATCH 337/656] Add logs to EmergencyCallDomainSelectionConnection Bug: 243344927 Test: atest EmergencyCallDomainSelectionConnectionTest Change-Id: Ic6a61ea4e861de6deeed60b2932064f84bee90de --- .../EmergencyCallDomainSelectionConnection.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java index 2646c48873..8d000f5a23 100644 --- a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java @@ -86,7 +86,9 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne public void onWlanSelected() { mEmergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WLAN); AccessNetworksManager anm = mPhone.getAccessNetworksManager(); - if (anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY) != TRANSPORT_TYPE_WLAN) { + int transportType = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); + logi("onWlanSelected curTransportType=" + transportType); + if (transportType != TRANSPORT_TYPE_WLAN) { changePreferredTransport(TRANSPORT_TYPE_WLAN); return; } @@ -112,7 +114,9 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) { if (domain == DOMAIN_PS) { AccessNetworksManager anm = mPhone.getAccessNetworksManager(); - if (anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY) != TRANSPORT_TYPE_WWAN) { + int transportType = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); + logi("onDomainSelected curTransportType=" + transportType); + if (transportType != TRANSPORT_TYPE_WWAN) { changePreferredTransport(TRANSPORT_TYPE_WWAN); return; } @@ -136,6 +140,7 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne } private void changePreferredTransport(@TransportType int transportType) { + logi("changePreferredTransport " + transportType); initHandler(); mPreferredTransportType = transportType; AccessNetworksManager anm = mPhone.getAccessNetworksManager(); @@ -155,6 +160,8 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne protected void onQualifiedNetworksChanged() { AccessNetworksManager anm = mPhone.getAccessNetworksManager(); int preferredTransport = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); + logi("onQualifiedNetworksChanged preferred=" + mPreferredTransportType + + ", current=" + preferredTransport); if (preferredTransport == mPreferredTransportType) { CompletableFuture future = getCompletableFuture(); if (future != null) future.complete(DOMAIN_PS); -- GitLab From 59f2c27713ac216f6078b9da46fbf284853d6702 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Thu, 15 Dec 2022 16:05:47 +0000 Subject: [PATCH 338/656] CarrierRestrictionStatus API implementation Bug:189884347 Test:Verified with CTS and manually with Test application Change-Id: I1d29e87c5fce70c3c2ddd5e8108f319e03c14051 --- src/java/com/android/internal/telephony/SimResponse.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/SimResponse.java b/src/java/com/android/internal/telephony/SimResponse.java index 5f05c584fc..55524865cc 100644 --- a/src/java/com/android/internal/telephony/SimResponse.java +++ b/src/java/com/android/internal/telephony/SimResponse.java @@ -20,6 +20,7 @@ import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; +import android.hardware.radio.sim.CarrierRestrictions; import android.hardware.radio.sim.IRadioSimResponse; import android.telephony.CarrierRestrictionRules; import android.telephony.TelephonyManager; @@ -127,7 +128,6 @@ public class SimResponse extends IRadioSimResponse.Stub { if (!carrierRestrictions.allowedCarriersPrioritized) { carrierRestrictionDefault = CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_ALLOWED; } - ret = CarrierRestrictionRules.newBuilder() .setAllowedCarriers(RILUtils.convertHalCarrierList( carrierRestrictions.allowedCarriers)) @@ -135,6 +135,7 @@ public class SimResponse extends IRadioSimResponse.Stub { carrierRestrictions.excludedCarriers)) .setDefaultCarrierRestriction(carrierRestrictionDefault) .setMultiSimPolicy(policy) + .setCarrierRestrictionStatus(carrierRestrictions.status) .build(); if (responseInfo.error == RadioError.NONE) { -- GitLab From bc374488c65497a7bbaff48a592a84f90cfd6a74 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 6 Jan 2023 13:37:32 +0000 Subject: [PATCH 339/656] Fix handling of CODE_SIP_ALTERNATE_EMERGENCY_CALL and CODE_LOCAL_CALL_CS_RETRY_REQUIRED Changed for domain selection service 1. Fix to cover the case mPendingMO is null. 2. Fix to cover the case onCallTerminated is called instead of onCallStartFailed. 3. Redirect CODE_LOCAL_CALL_CS_RETRY_REQUIRED error code to TelephonyConnectionService for normal calls. Bug: 243344927 Bug: 264511015 Test: atest ImsPhoneCallTrackerTest Change-Id: Ib18ad4a601acc1e13e6ec6fdec73b3613b17cc13 --- .../imsphone/ImsPhoneCallTracker.java | 41 ++++++++++++++--- .../imsphone/ImsPhoneCallTrackerTest.java | 44 ++++++++++++++++++- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 6840f4be83..cae34bf2ef 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -146,6 +146,7 @@ import com.android.internal.telephony.SrvccConnection; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.d2d.RtpTransport; import com.android.internal.telephony.data.DataSettingsManager; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.imsphone.ImsPhone.ImsDialArgs; @@ -3488,13 +3489,6 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { eccCategory = imsCall.getCallProfile().getEmergencyServiceCategories(); } - if (reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL) { - ImsPhoneConnection conn = findConnection(imsCall); - if (conn != null) { - conn.setNonDetectableEmergencyCallInfo(eccCategory); - } - } - if (mHoldSwitchingState == HoldSwapState.HOLDING_TO_ANSWER_INCOMING) { // If we put a call on hold to answer an incoming call, we should reset the // variables that keep track of the switch here. @@ -3514,6 +3508,27 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { reasonInfo.mExtraCode, reasonInfo.mExtraMessage)); + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + ImsPhoneConnection conn = findConnection(imsCall); + // Since onCallInitiating and onCallProgressing reset mPendingMO, + // we can't depend on mPendingMO. + if ((reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL + || reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED) + && conn != null) { + logi("onCallStartFailed eccCategory=" + eccCategory); + if (reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL + || reasonInfo.getExtraCode() + == ImsReasonInfo.EXTRA_CODE_CALL_RETRY_EMERGENCY) { + conn.setNonDetectableEmergencyCallInfo(eccCategory); + } + conn.setImsReasonInfo(reasonInfo); + sendCallStartFailedDisconnect(imsCall, reasonInfo); + mMetrics.writeOnImsCallStartFailed(mPhone.getPhoneId(), + imsCall.getCallSession(), reasonInfo); + return; + } + } + if (mPendingMO != null) { // To initiate dialing circuit-switched call if (reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED @@ -3673,6 +3688,18 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } if (reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL + && DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + if (conn != null) { + int eccCategory = EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED; + if (imsCall != null && imsCall.getCallProfile() != null) { + eccCategory = imsCall.getCallProfile().getEmergencyServiceCategories(); + logi("onCallTerminated eccCategory=" + eccCategory); + } + conn.setNonDetectableEmergencyCallInfo(eccCategory); + } + processCallStateChange(imsCall, ImsPhoneCall.State.DISCONNECTED, cause); + return; + } else if (reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL && mAutoRetryFailedWifiEmergencyCall) { Pair callInfo = new Pair<>(imsCall, reasonInfo); mPhone.getDefaultPhone().mCi.registerForOn(ImsPhoneCallTracker.this, diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 0af95e8837..e0bfcd7af3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -126,6 +126,7 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.SrvccConnection; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.d2d.RtpTransport; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker.VtDataUsageProvider; import org.junit.After; @@ -171,6 +172,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { private INetworkStatsProviderCallback mVtDataUsageProviderCb; private ImsPhoneCallTracker.ConnectorFactory mConnectorFactory; private CommandsInterface mMockCi; + private DomainSelectionResolver mDomainSelectionResolver; private final Executor mExecutor = Runnable::run; @@ -237,6 +239,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { doReturn(ImsFeature.STATE_READY).when(mImsManager).getImsServiceState(); doReturn(mImsCallProfile).when(mImsManager).createCallProfile(anyInt(), anyInt()); mContextFixture.addSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS); + mDomainSelectionResolver = mock(DomainSelectionResolver.class); doAnswer(invocation -> { mMmTelListener = (MmTelFeature.Listener) invocation.getArguments()[0]; @@ -272,6 +275,9 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { return mMockConnector; }).when(mConnectorFactory).create(any(), anyInt(), anyString(), any(), any()); + DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver); + doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported(); + mCTUT = new ImsPhoneCallTracker(mImsPhone, mConnectorFactory, Runnable::run); mCTUT.setDataEnabled(true); @@ -2399,7 +2405,8 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { @Test @SmallTest - public void testDomainSelectionAlternateService() { + public void testDomainSelectionAlternateServiceStartFailed() { + doReturn(true).when(mDomainSelectionResolver).isDomainSelectionSupported(); startOutgoingCall(); ImsPhoneConnection c = mCTUT.mForegroundCall.getFirstConnection(); mImsCallProfile.setEmergencyServiceCategories(EMERGENCY_SERVICE_CATEGORY_AMBULANCE); @@ -2412,6 +2419,41 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { emergencyNumber.getEmergencyServiceCategoryBitmask()); } + @Test + @SmallTest + public void testDomainSelectionAlternateServiceStartFailedNullPendingMO() { + doReturn(true).when(mDomainSelectionResolver).isDomainSelectionSupported(); + startOutgoingCall(); + ImsPhoneConnection c = mCTUT.mForegroundCall.getFirstConnection(); + mImsCallListener.onCallProgressing(mSecondImsCall); + processAllMessages(); + mImsCallProfile.setEmergencyServiceCategories(EMERGENCY_SERVICE_CATEGORY_AMBULANCE); + mImsCallListener.onCallStartFailed(mSecondImsCall, + new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED, + ImsReasonInfo.EXTRA_CODE_CALL_RETRY_EMERGENCY)); + processAllMessages(); + EmergencyNumber emergencyNumber = c.getEmergencyNumberInfo(); + assertNotNull(emergencyNumber); + assertEquals(EMERGENCY_SERVICE_CATEGORY_AMBULANCE, + emergencyNumber.getEmergencyServiceCategoryBitmask()); + } + + @Test + @SmallTest + public void testDomainSelectionAlternateServiceTerminated() { + doReturn(true).when(mDomainSelectionResolver).isDomainSelectionSupported(); + startOutgoingCall(); + ImsPhoneConnection c = mCTUT.mForegroundCall.getFirstConnection(); + mImsCallProfile.setEmergencyServiceCategories(EMERGENCY_SERVICE_CATEGORY_AMBULANCE); + mImsCallListener.onCallTerminated(mSecondImsCall, + new ImsReasonInfo(ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL, -1)); + processAllMessages(); + EmergencyNumber emergencyNumber = c.getEmergencyNumberInfo(); + assertNotNull(emergencyNumber); + assertEquals(EMERGENCY_SERVICE_CATEGORY_AMBULANCE, + emergencyNumber.getEmergencyServiceCategoryBitmask()); + } + @Test public void testUpdateImsCallStatusIncoming() throws Exception { // Incoming call -- GitLab From 9695d45db191bb90dfff25cb824d3128c6029242 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 17 Jan 2023 11:55:56 -0800 Subject: [PATCH 340/656] Remove orphaned hasBandwidthsChanged The variable hasBandwidthsChanged was abandoned in the SST, and the comparison to generate it has a bug. Thus, it's removed. Bug: 262486676 Test: make Change-Id: I10c5b817dba9645d6c8239ec069e0d6de879fdf3 --- .../com/android/internal/telephony/ServiceStateTracker.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 2a76a84eea..79841ca714 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -3544,8 +3544,6 @@ public class ServiceStateTracker extends Handler { boolean hasCssIndicatorChanged = (mSS.getCssIndicator() != mNewSS.getCssIndicator()); - boolean hasBandwidthChanged = mSS.getCellBandwidths() != mNewSS.getCellBandwidths(); - boolean has4gHandoff = false; boolean hasMultiApnSupport = false; boolean hasLostMultiApnSupport = false; @@ -3589,7 +3587,6 @@ public class ServiceStateTracker extends Handler { + " hasCssIndicatorChanged = " + hasCssIndicatorChanged + " hasNrFrequencyRangeChanged = " + hasNrFrequencyRangeChanged + " hasNrStateChanged = " + hasNrStateChanged - + " hasBandwidthChanged = " + hasBandwidthChanged + " hasAirplaneModeOnlChanged = " + hasAirplaneModeOnChanged); } -- GitLab From f07526c2babb75c95e4406a1a5d5ebd04e0915b4 Mon Sep 17 00:00:00 2001 From: Andrew Chant Date: Tue, 17 Jan 2023 20:08:02 +0000 Subject: [PATCH 341/656] Revert "Use averagingWindowMillis instead of averagingWindowMs" Revert submission 20886209-qfi Reason for revert: Build Break. Bug: 265823012 Reverted changes: /q/submissionid:20886209-qfi Change-Id: I1d5ddbac9bc62aea1a08d5e9eb5005da553c507c --- src/java/com/android/internal/telephony/RILUtils.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 708a642df1..95b0011fd3 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -3869,13 +3869,9 @@ public class RILUtils { convertHalQosBandwidth(eps.uplink), eps.qci); case android.hardware.radio.data.Qos.nr: android.hardware.radio.data.NrQos nr = qos.getNr(); - int averagingWindowMs = nr.averagingWindowMillis; - if (averagingWindowMs - == android.hardware.radio.data.NrQos.AVERAGING_WINDOW_UNKNOWN) { - averagingWindowMs = nr.averagingWindowMs; - } return new NrQos(convertHalQosBandwidth(nr.downlink), - convertHalQosBandwidth(nr.uplink), nr.qfi, nr.fiveQi, averagingWindowMs); + convertHalQosBandwidth(nr.uplink), nr.qosFlowIdentifier, nr.fiveQi, + nr.averagingWindowMs); default: return null; } -- GitLab From 13fabc3153a95d0aa6f66bca2f4e5fa682b4fc35 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 12 Jan 2023 14:20:17 -0800 Subject: [PATCH 342/656] Run embbeded subscription update in background thread Same as the pre-U behavior, update the embedded subscriptions on background thread. Bug: 239607619 Test: Manual + atest SubscriptionManagerServiceTest Change-Id: I819fe44b4eba6c9d4b15d2d42c622a5e78ed3411 --- .../SubscriptionManagerService.java | 20 +++++++++++++++++-- .../internal/telephony/TelephonyTest.java | 2 +- .../SubscriptionManagerServiceTest.java | 10 ++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 27007f116b..e95db57894 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -195,10 +195,19 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable private EuiccController mEuiccController; - /** The main handler of subscription manager service. */ + /** + * The main handler of subscription manager service. This is running on phone process's main + * thread. + */ @NonNull private final Handler mHandler; + /** + * The background handler. This is running on a separate thread. + */ + @NonNull + private final Handler mBackgroundHandler; + /** Local log for most important debug messages. */ @NonNull private final LocalLog mLocalLog = new LocalLog(128); @@ -373,6 +382,12 @@ public class SubscriptionManagerService extends ISub.Stub { mUiccController = UiccController.getInstance(); mHandler = new Handler(looper); + + HandlerThread backgroundThread = new HandlerThread(LOG_TAG); + backgroundThread.start(); + + mBackgroundHandler = new Handler(backgroundThread.getLooper()); + TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = TelephonyFrameworkInitializer .getTelephonyServiceManager() @@ -907,7 +922,8 @@ public class SubscriptionManagerService extends ISub.Stub { */ public void updateEmbeddedSubscriptions(@NonNull List cardIds, @Nullable Runnable callback) { - mHandler.post(() -> { + // Run this on a background thread. + mBackgroundHandler.post(() -> { // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but // they are filtered out of list calls as long as EuiccManager.isEnabled returns false). if (mEuiccManager == null || !mEuiccManager.isEnabled()) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 9465bb6138..855548c1f2 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -1141,7 +1141,7 @@ public abstract class TelephonyTest { * Remove a TestableLooper from the list of monitored loopers * @param looper removed if it does exist */ - public void unmonitorTestableLooper(TestableLooper looper) { + private void unmonitorTestableLooper(TestableLooper looper) { if (mTestableLoopers.contains(looper)) { mTestableLoopers.remove(looper); } 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 ebd4ad23a5..cfc4efacb9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -68,6 +68,7 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.os.Looper; import android.os.ParcelUuid; import android.os.UserHandle; @@ -148,6 +149,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); mSubscriptionManagerServiceUT = new SubscriptionManagerService(mContext, Looper.myLooper()); + monitorTestableLooper(new TestableLooper(getBackgroundHandler().getLooper())); + doAnswer(invocation -> { ((Runnable) invocation.getArguments()[0]).run(); return null; @@ -182,6 +185,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { super.tearDown(); } + private Handler getBackgroundHandler() throws Exception { + Field field = SubscriptionManagerService.class.getDeclaredField( + "mBackgroundHandler"); + field.setAccessible(true); + return (Handler) field.get(mSubscriptionManagerServiceUT); + } + /** * Insert the subscription info to the database. * -- GitLab From 71808a8fa64beb5074b617dd604abe06d2a45c74 Mon Sep 17 00:00:00 2001 From: Willy Hu Date: Wed, 18 Jan 2023 15:23:01 +0800 Subject: [PATCH 343/656] [DSRM] Shift the phone id value due to proto limitations Symptom: If we use the values 0 and 1 for the phone ID, when the device uploads the metrics with the old ROM, they will be mixed up(default value is 0). - To avoid this problem, we shift the value and it can filter out the old and new data. Bug: 260166714 Test: Manual test passed Change-Id: I111ea39a6bfae1588973a478c0afc93c25d8dc91 --- .../internal/telephony/metrics/DataStallRecoveryStats.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java index 38db78d8d5..c0be456f6b 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -112,7 +112,8 @@ public class DataStallRecoveryStats { phoneNetworkRegState = phoneRegInfo.getRegistrationState(); } - int phoneId = phone.getPhoneId(); + // reserve 0 for default value + int phoneId = phone.getPhoneId() + 1; TelephonyStatsLog.write( TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, -- GitLab From a92adbd5558de4045c121a0525393ae1c5eeae0c Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 5 Jan 2023 15:38:47 -0800 Subject: [PATCH 344/656] Use averagingWindowMillis instead of averagingWindowMs Use averagingWindowMs when averagingWindowMillis is unknown. This is the same change as ag/20886208. Test: build Bug: 264261216 Change-Id: I7c4e30fb975af5c39414cfcf4d71d896743616ea --- src/java/com/android/internal/telephony/RILUtils.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 95b0011fd3..708a642df1 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -3869,9 +3869,13 @@ public class RILUtils { convertHalQosBandwidth(eps.uplink), eps.qci); case android.hardware.radio.data.Qos.nr: android.hardware.radio.data.NrQos nr = qos.getNr(); + int averagingWindowMs = nr.averagingWindowMillis; + if (averagingWindowMs + == android.hardware.radio.data.NrQos.AVERAGING_WINDOW_UNKNOWN) { + averagingWindowMs = nr.averagingWindowMs; + } return new NrQos(convertHalQosBandwidth(nr.downlink), - convertHalQosBandwidth(nr.uplink), nr.qosFlowIdentifier, nr.fiveQi, - nr.averagingWindowMs); + convertHalQosBandwidth(nr.uplink), nr.qfi, nr.fiveQi, averagingWindowMs); default: return null; } -- GitLab From d74f3ac73b7b8bdbc4d10233dd808eee6c75916c Mon Sep 17 00:00:00 2001 From: rambowang Date: Thu, 15 Dec 2022 21:53:17 -0600 Subject: [PATCH 345/656] Update AccessNetworksManager with new CarrierConfigManager APIs - Replace carrier config change broadcast receiver with listener - Retrieve subset of carrier config as needed to save memory Bug: 263267340 Test: atest AccessNetworksManagerTest Change-Id: I29891a1d8ecd399f2c66df9b8909d9430095f3f8 --- .../telephony/data/AccessNetworksManager.java | 90 +++++++++---------- .../data/AccessNetworksManagerTest.java | 8 ++ 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index a6b37a3d44..2b29fa7ae7 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -19,13 +19,10 @@ package com.android.internal.telephony.data; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.ServiceConnection; -import android.content.pm.PackageManager; import android.os.AsyncResult; import android.os.Handler; import android.os.IBinder; @@ -35,7 +32,6 @@ import android.os.PersistableBundle; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; -import android.os.UserHandle; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.AccessNetworkConstants.RadioAccessNetworkType; @@ -125,22 +121,6 @@ public class AccessNetworksManager extends Handler { private final RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList(); - private final BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) - && mPhone.getPhoneId() == intent.getIntExtra( - CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) { - // 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 qualified network service."); - bindQualifiedNetworksService(); - } - } - }; - /** * The preferred transport of the APN type. The key is the APN type, and the value is the * transport. The preferred transports are updated as soon as QNS changes the preference. @@ -366,16 +346,18 @@ public class AccessNetworksManager extends Handler { mApnTypeToQnsChangeNetworkCounter = new SparseArray<>(); mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - try { - Context contextAsUser = phone.getContext().createPackageContextAsUser( - phone.getContext().getPackageName(), 0, UserHandle.ALL); - contextAsUser.registerReceiver(mConfigChangedReceiver, intentFilter, - null /* broadcastPermission */, null); - } catch (PackageManager.NameNotFoundException e) { - loge("Package name not found: ", e); - } + + // bindQualifiedNetworksService posts real work to handler thread. So here we can + // let the callback execute in binder thread to avoid post twice. + mCarrierConfigManager.registerCarrierConfigChangeListener(Runnable::run, + (slotIndex, subId, carrierId, specificCarrierId) -> { + if (slotIndex != mPhone.getPhoneId()) return; + // 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 qualified network service."); + bindQualifiedNetworksService(); + }); bindQualifiedNetworksService(); // Using post to delay the registering because data retry manager and data config @@ -488,16 +470,22 @@ public class AccessNetworksManager extends Handler { String packageName = mPhone.getContext().getResources().getString( com.android.internal.R.string.config_qualified_networks_service_package); - PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - if (b != null) { - // If carrier config overrides it, use the one from carrier config - String carrierConfigPackageName = b.getString(CarrierConfigManager - .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING); - if (!TextUtils.isEmpty(carrierConfigPackageName)) { - if (DBG) log("Found carrier config override " + carrierConfigPackageName); - packageName = carrierConfigPackageName; + PersistableBundle b; + try { + b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), + CarrierConfigManager + .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING); + if (!b.isEmpty()) { + // If carrier config overrides it, use the one from carrier config + String carrierConfigPackageName = b.getString(CarrierConfigManager + .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING); + if (!TextUtils.isEmpty(carrierConfigPackageName)) { + if (DBG) log("Found carrier config override " + carrierConfigPackageName); + packageName = carrierConfigPackageName; + } } + } catch (RuntimeException e) { + loge("Carrier config loader is not available."); } return packageName; @@ -513,16 +501,22 @@ public class AccessNetworksManager extends Handler { String className = mPhone.getContext().getResources().getString( com.android.internal.R.string.config_qualified_networks_service_class); - PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - if (b != null) { - // If carrier config overrides it, use the one from carrier config - String carrierConfigClassName = b.getString(CarrierConfigManager - .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING); - if (!TextUtils.isEmpty(carrierConfigClassName)) { - if (DBG) log("Found carrier config override " + carrierConfigClassName); - className = carrierConfigClassName; + PersistableBundle b; + try { + b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), + CarrierConfigManager + .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING); + if (!b.isEmpty()) { + // If carrier config overrides it, use the one from carrier config + String carrierConfigClassName = b.getString(CarrierConfigManager + .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING); + if (!TextUtils.isEmpty(carrierConfigClassName)) { + if (DBG) log("Found carrier config override " + carrierConfigClassName); + className = carrierConfigClassName; + } } + } catch (RuntimeException e) { + loge("Carrier config loader is not available."); } return className; 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 68e1fb2a6a..4d116a8553 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/AccessNetworksManagerTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.IntentFilter; @@ -35,6 +36,7 @@ import android.os.AsyncResult; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.NetworkService; @@ -67,6 +69,8 @@ public class AccessNetworksManagerTest extends TelephonyTest { // The real callback passed created by AccessNetworksManager. private IQualifiedNetworksServiceCallback.Stub mQnsCallback; + private PersistableBundle mBundle; + private void addQnsService() throws Exception { ServiceInfo QnsInfo = new ServiceInfo(); QnsInfo.packageName = "fake.qns"; @@ -97,6 +101,9 @@ public class AccessNetworksManagerTest extends TelephonyTest { mMockedQns = mock(IQualifiedNetworksService.class); mMockedIBinder = mock(IBinder.class); + mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); + addQnsService(); mContextFixture.putResource( com.android.internal.R.string.config_qualified_networks_service_package, @@ -121,6 +128,7 @@ public class AccessNetworksManagerTest extends TelephonyTest { @After public void tearDown() throws Exception { mAccessNetworksManager = null; + mBundle = null; super.tearDown(); } -- GitLab From be06813dc5d1bf8416427bb9a6d3ff738d83ba84 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 18 Jan 2023 19:26:00 +0000 Subject: [PATCH 346/656] Revert "Fixed the set/getAllowedNetworkTypes debug messages" This reverts commit 725f0e518abf1c1efaef720510e9877132f19577. Reason for revert: b/265950512 Change-Id: I7179f4ddb1bafbfa285544caaf1185acfcfde94e --- .../com/android/internal/telephony/Phone.java | 65 ++++++++++++++----- .../data/LinkBandwidthEstimator.java | 6 +- .../SubscriptionInfoInternal.java | 31 ++------- 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 806b0c01be..ed4214d354 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -470,6 +470,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected SimulatedRadioControl mSimulatedRadioControl; private Map mAllowedNetworkTypesForReasons = new HashMap<>(); + private static final String ALLOWED_NETWORK_TYPES_TEXT_USER = "user"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_POWER = "power"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_CARRIER = "carrier"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G = "enable_2g"; private static final int INVALID_ALLOWED_NETWORK_TYPES = -1; protected boolean mIsCarrierNrSupported = false; protected boolean mIsAllowedNetworkTypesLoadedFromDb = false; @@ -2324,10 +2328,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ public void notifyAllowedNetworkTypesChanged( @TelephonyManager.AllowedNetworkTypesReason int reason) { - logd("notifyAllowedNetworkTypesChanged: subId=" + getSubId() + ", reason=" - + TelephonyManager.allowedNetworkTypesReasonToString(reason) - + " network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( - getAllowedNetworkTypes(reason))); + logd("SubId" + getSubId() + ",notifyAllowedNetworkTypesChanged: reason: " + reason + + " value:" + TelephonyManager.convertNetworkTypeBitmaskToString( + getAllowedNetworkTypes(reason))); mNotifier.notifyAllowedNetworkTypesChanged(this, reason, getAllowedNetworkTypes(reason)); } @@ -2379,9 +2382,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { && reason == TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER) { allowedNetworkTypes = updateAllowedNetworkTypeForCarrierWithCarrierConfig(); } - logd("getAllowedNetworkTypes: subId=" + getSubId() + ", reason=" - + TelephonyManager.allowedNetworkTypesReasonToString(reason) - + ", network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( + logd("SubId" + getSubId() + ",get allowed network types " + + convertAllowedNetworkTypeMapIndexToDbName(reason) + + ": value = " + TelephonyManager.convertNetworkTypeBitmaskToString( allowedNetworkTypes)); return allowedNetworkTypes; } @@ -2416,8 +2419,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return; } - logd("loadAllowedNetworksFromSubscriptionDatabase: subId=" + getSubId() + ", " - + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(result)); + logd("SubId" + getSubId() + ",load allowed network types : value = " + result); Map oldAllowedNetworkTypes = new HashMap<>(mAllowedNetworkTypesForReasons); mAllowedNetworkTypesForReasons.clear(); try { @@ -2428,10 +2430,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { Rlog.e(LOG_TAG, "Invalid ALLOWED_NETWORK_TYPES from DB, value = " + pair); continue; } - int key = TelephonyManager.allowedNetworkTypesReasonFromString( - networkTypesValues[0]); + int key = convertAllowedNetworkTypeDbNameToMapIndex(networkTypesValues[0]); long value = Long.parseLong(networkTypesValues[1]); - if (value != INVALID_ALLOWED_NETWORK_TYPES) { + if (key != INVALID_ALLOWED_NETWORK_TYPES + && value != INVALID_ALLOWED_NETWORK_TYPES) { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(key, value); } @@ -2453,6 +2455,36 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } } + private int convertAllowedNetworkTypeDbNameToMapIndex(String name) { + switch (name) { + case ALLOWED_NETWORK_TYPES_TEXT_USER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER; + case ALLOWED_NETWORK_TYPES_TEXT_POWER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER; + case ALLOWED_NETWORK_TYPES_TEXT_CARRIER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER; + case ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G; + default: + return INVALID_ALLOWED_NETWORK_TYPES; + } + } + + private String convertAllowedNetworkTypeMapIndexToDbName(int reason) { + switch (reason) { + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER: + return ALLOWED_NETWORK_TYPES_TEXT_USER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER: + return ALLOWED_NETWORK_TYPES_TEXT_POWER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER: + return ALLOWED_NETWORK_TYPES_TEXT_CARRIER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G: + return ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G; + default: + return Integer.toString(INVALID_ALLOWED_NETWORK_TYPES); + } + } + private @TelephonyManager.NetworkTypeBitMask long updateAllowedNetworkTypeForCarrierWithCarrierConfig() { long defaultAllowedNetworkTypes = RadioAccessFamily.getRafFromNetworkType( @@ -2494,8 +2526,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } if (!SubscriptionManager.isUsableSubscriptionId(subId) || !mIsAllowedNetworkTypesLoadedFromDb) { - loge("setAllowedNetworkTypes: no sim or network type is not loaded. subId=" - + subId + ", isNetworkTypeLoaded=" + mIsAllowedNetworkTypesLoadedFromDb); + loge("setAllowedNetworkTypes: no sim or network type is not loaded. SubscriptionId: " + + subId + ", isNetworkTypeLoaded" + mIsAllowedNetworkTypesLoadedFromDb); if (response != null) { AsyncResult.forMessage(response, null, new CommandException(CommandException.Error.MISSING_RESOURCE)); @@ -2507,15 +2539,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(reason, networkTypes); mapAsString = mAllowedNetworkTypesForReasons.keySet().stream() - .map(key -> TelephonyManager.allowedNetworkTypesReasonToString(key) + "=" + .map(key -> convertAllowedNetworkTypeMapIndexToDbName(key) + "=" + mAllowedNetworkTypesForReasons.get(key)) .collect(Collectors.joining(",")); } SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, mapAsString); - logd("setAllowedNetworkTypes: subId=" + subId + ", " - + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(mapAsString)); + logd("setAllowedNetworkTypes: SubId" + subId + ",setAllowedNetworkTypes " + mapAsString); updateAllowedNetworkTypes(response); notifyAllowedNetworkTypesChanged(reason); diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index 73aa92d5bd..994e8f67fb 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -141,9 +141,9 @@ public class LinkBandwidthEstimator extends Handler { private static final int MAX_ERROR_PERCENT = 100 * 100; private static final String[] AVG_BW_PER_RAT = { "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA:14,14", - "1xRTT:30,30", "EVDO-0:750,48", "EVDO-A:950,550", - "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "EVDO-B:1500,550", - "eHRPD:750,48", "HSPA+:13000,3400", "TD-SCDMA:115,115", + "CDMA - 1xRTT:30,30", "CDMA - EvDo rev. 0:750,48", "CDMA - EvDo rev. A:950,550", + "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "CDMA - EvDo rev. B:1500,550", + "CDMA - eHRPD:750,48", "HSPA+:13000,3400", "TD_SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,18000", "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000", "NR_MMWAVE:145000,60000"}; private static final Map> AVG_BW_PER_RAT_MAP = new ArrayMap<>(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 222c4b97f6..b0262b0271 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -55,8 +55,6 @@ import com.android.telephony.Rlog; import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * The class represents a single row of {@link SimInfo} table. All columns (excepts unused columns) @@ -1039,7 +1037,7 @@ public class SubscriptionInfoInternal { * * @return The stripped string. */ - public static String getPrintableId(String id) { + public static String givePrintableId(String id) { String idToPrint = null; if (id != null) { int len = id.length(); @@ -1052,28 +1050,10 @@ public class SubscriptionInfoInternal { return idToPrint; } - /** - * Convert the allowed network types for reasons to readable format. - * - * @param allowedNetworkTypesForReasons The raw value of allowed network types for reasons - * stored in the database. - * - * @return The converted string. - */ - public static String getPrintableAllowedNetworkTypesForReasons( - @NonNull String allowedNetworkTypesForReasons) { - if (TextUtils.isEmpty(allowedNetworkTypesForReasons)) return ""; - return Stream.of(allowedNetworkTypesForReasons.split(",")) - .map(s -> s.substring(0, s.indexOf("=") + 1) - + TelephonyManager.convertNetworkTypeBitmaskToString( - Long.parseLong(s.substring(s.indexOf("=") + 1)))) - .collect(Collectors.joining(", ")); - } - @Override public String toString() { return "[SubscriptionInfoInternal: id=" + mId - + " iccId=" + getPrintableId(mIccId) + + " iccId=" + givePrintableId(mIccId) + " simSlotIndex=" + mSimSlotIndex + " portIndex=" + mPortIndex + " isEmbedded=" + mIsEmbedded @@ -1093,7 +1073,7 @@ public class SubscriptionInfoInternal { + " mnc=" + mMnc + " ehplmns=" + mEhplmns + " hplmns=" + mHplmns - + " cardString=" + getPrintableId(mCardString) + + " cardString=" + givePrintableId(mCardString) + " cardId=" + mCardId + " nativeAccessRules=" + IccUtils.bytesToHexString(mNativeAccessRules) + " carrierConfigAccessRules=" + IccUtils.bytesToHexString( @@ -1111,12 +1091,11 @@ public class SubscriptionInfoInternal { + " wifiCallingModeForRoaming=" + ImsMmTelManager.wifiCallingModeToString(mWifiCallingModeForRoaming) + " enabledMobileDataPolicies=" + mEnabledMobileDataPolicies - + " imsi=" + getPrintableId(mImsi) + + " imsi=" + givePrintableId(mImsi) + " rcsUceEnabled=" + mIsRcsUceEnabled + " crossSimCallingEnabled=" + mIsCrossSimCallingEnabled + " rcsConfig=" + IccUtils.bytesToHexString(mRcsConfig) - + " allowedNetworkTypesForReasons=" - + getPrintableAllowedNetworkTypesForReasons(mAllowedNetworkTypesForReasons) + + " allowedNetworkTypesForReasons=" + mAllowedNetworkTypesForReasons + " deviceToDeviceStatusSharingPreference=" + mDeviceToDeviceStatusSharingPreference + " isVoImsOptInEnabled=" + mIsVoImsOptInEnabled + " deviceToDeviceStatusSharingContacts=" + mDeviceToDeviceStatusSharingContacts -- GitLab From 7b688de97b2d4b937d7ff54b40fc36b8c91f433c Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 18 Jan 2023 19:26:00 +0000 Subject: [PATCH 347/656] Revert "Fixed the set/getAllowedNetworkTypes debug messages" This reverts commit 725f0e518abf1c1efaef720510e9877132f19577. Reason for revert: b/265950512 Change-Id: I7179f4ddb1bafbfa285544caaf1185acfcfde94e (cherry picked from commit be06813dc5d1bf8416427bb9a6d3ff738d83ba84) Merged-In: I7179f4ddb1bafbfa285544caaf1185acfcfde94e --- .../com/android/internal/telephony/Phone.java | 65 ++++++++++++++----- .../data/LinkBandwidthEstimator.java | 6 +- .../SubscriptionInfoInternal.java | 31 ++------- 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index ca6091f4c0..a69e71ec30 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -470,6 +470,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected SimulatedRadioControl mSimulatedRadioControl; private Map mAllowedNetworkTypesForReasons = new HashMap<>(); + private static final String ALLOWED_NETWORK_TYPES_TEXT_USER = "user"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_POWER = "power"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_CARRIER = "carrier"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G = "enable_2g"; private static final int INVALID_ALLOWED_NETWORK_TYPES = -1; protected boolean mIsCarrierNrSupported = false; protected boolean mIsAllowedNetworkTypesLoadedFromDb = false; @@ -2324,10 +2328,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ public void notifyAllowedNetworkTypesChanged( @TelephonyManager.AllowedNetworkTypesReason int reason) { - logd("notifyAllowedNetworkTypesChanged: subId=" + getSubId() + ", reason=" - + TelephonyManager.allowedNetworkTypesReasonToString(reason) - + " network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( - getAllowedNetworkTypes(reason))); + logd("SubId" + getSubId() + ",notifyAllowedNetworkTypesChanged: reason: " + reason + + " value:" + TelephonyManager.convertNetworkTypeBitmaskToString( + getAllowedNetworkTypes(reason))); mNotifier.notifyAllowedNetworkTypesChanged(this, reason, getAllowedNetworkTypes(reason)); } @@ -2379,9 +2382,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { && reason == TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER) { allowedNetworkTypes = updateAllowedNetworkTypeForCarrierWithCarrierConfig(); } - logd("getAllowedNetworkTypes: subId=" + getSubId() + ", reason=" - + TelephonyManager.allowedNetworkTypesReasonToString(reason) - + ", network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( + logd("SubId" + getSubId() + ",get allowed network types " + + convertAllowedNetworkTypeMapIndexToDbName(reason) + + ": value = " + TelephonyManager.convertNetworkTypeBitmaskToString( allowedNetworkTypes)); return allowedNetworkTypes; } @@ -2416,8 +2419,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return; } - logd("loadAllowedNetworksFromSubscriptionDatabase: subId=" + getSubId() + ", " - + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(result)); + logd("SubId" + getSubId() + ",load allowed network types : value = " + result); Map oldAllowedNetworkTypes = new HashMap<>(mAllowedNetworkTypesForReasons); mAllowedNetworkTypesForReasons.clear(); try { @@ -2428,10 +2430,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { Rlog.e(LOG_TAG, "Invalid ALLOWED_NETWORK_TYPES from DB, value = " + pair); continue; } - int key = TelephonyManager.allowedNetworkTypesReasonFromString( - networkTypesValues[0]); + int key = convertAllowedNetworkTypeDbNameToMapIndex(networkTypesValues[0]); long value = Long.parseLong(networkTypesValues[1]); - if (value != INVALID_ALLOWED_NETWORK_TYPES) { + if (key != INVALID_ALLOWED_NETWORK_TYPES + && value != INVALID_ALLOWED_NETWORK_TYPES) { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(key, value); } @@ -2453,6 +2455,36 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } } + private int convertAllowedNetworkTypeDbNameToMapIndex(String name) { + switch (name) { + case ALLOWED_NETWORK_TYPES_TEXT_USER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER; + case ALLOWED_NETWORK_TYPES_TEXT_POWER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER; + case ALLOWED_NETWORK_TYPES_TEXT_CARRIER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER; + case ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G; + default: + return INVALID_ALLOWED_NETWORK_TYPES; + } + } + + private String convertAllowedNetworkTypeMapIndexToDbName(int reason) { + switch (reason) { + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER: + return ALLOWED_NETWORK_TYPES_TEXT_USER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER: + return ALLOWED_NETWORK_TYPES_TEXT_POWER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER: + return ALLOWED_NETWORK_TYPES_TEXT_CARRIER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G: + return ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G; + default: + return Integer.toString(INVALID_ALLOWED_NETWORK_TYPES); + } + } + private @TelephonyManager.NetworkTypeBitMask long updateAllowedNetworkTypeForCarrierWithCarrierConfig() { long defaultAllowedNetworkTypes = RadioAccessFamily.getRafFromNetworkType( @@ -2494,8 +2526,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } if (!SubscriptionManager.isUsableSubscriptionId(subId) || !mIsAllowedNetworkTypesLoadedFromDb) { - loge("setAllowedNetworkTypes: no sim or network type is not loaded. subId=" - + subId + ", isNetworkTypeLoaded=" + mIsAllowedNetworkTypesLoadedFromDb); + loge("setAllowedNetworkTypes: no sim or network type is not loaded. SubscriptionId: " + + subId + ", isNetworkTypeLoaded" + mIsAllowedNetworkTypesLoadedFromDb); if (response != null) { AsyncResult.forMessage(response, null, new CommandException(CommandException.Error.MISSING_RESOURCE)); @@ -2507,15 +2539,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(reason, networkTypes); mapAsString = mAllowedNetworkTypesForReasons.keySet().stream() - .map(key -> TelephonyManager.allowedNetworkTypesReasonToString(key) + "=" + .map(key -> convertAllowedNetworkTypeMapIndexToDbName(key) + "=" + mAllowedNetworkTypesForReasons.get(key)) .collect(Collectors.joining(",")); } SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, mapAsString); - logd("setAllowedNetworkTypes: subId=" + subId + ", " - + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(mapAsString)); + logd("setAllowedNetworkTypes: SubId" + subId + ",setAllowedNetworkTypes " + mapAsString); updateAllowedNetworkTypes(response); notifyAllowedNetworkTypesChanged(reason); diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index 73aa92d5bd..994e8f67fb 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -141,9 +141,9 @@ public class LinkBandwidthEstimator extends Handler { private static final int MAX_ERROR_PERCENT = 100 * 100; private static final String[] AVG_BW_PER_RAT = { "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA:14,14", - "1xRTT:30,30", "EVDO-0:750,48", "EVDO-A:950,550", - "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "EVDO-B:1500,550", - "eHRPD:750,48", "HSPA+:13000,3400", "TD-SCDMA:115,115", + "CDMA - 1xRTT:30,30", "CDMA - EvDo rev. 0:750,48", "CDMA - EvDo rev. A:950,550", + "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "CDMA - EvDo rev. B:1500,550", + "CDMA - eHRPD:750,48", "HSPA+:13000,3400", "TD_SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,18000", "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000", "NR_MMWAVE:145000,60000"}; private static final Map> AVG_BW_PER_RAT_MAP = new ArrayMap<>(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 222c4b97f6..b0262b0271 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -55,8 +55,6 @@ import com.android.telephony.Rlog; import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * The class represents a single row of {@link SimInfo} table. All columns (excepts unused columns) @@ -1039,7 +1037,7 @@ public class SubscriptionInfoInternal { * * @return The stripped string. */ - public static String getPrintableId(String id) { + public static String givePrintableId(String id) { String idToPrint = null; if (id != null) { int len = id.length(); @@ -1052,28 +1050,10 @@ public class SubscriptionInfoInternal { return idToPrint; } - /** - * Convert the allowed network types for reasons to readable format. - * - * @param allowedNetworkTypesForReasons The raw value of allowed network types for reasons - * stored in the database. - * - * @return The converted string. - */ - public static String getPrintableAllowedNetworkTypesForReasons( - @NonNull String allowedNetworkTypesForReasons) { - if (TextUtils.isEmpty(allowedNetworkTypesForReasons)) return ""; - return Stream.of(allowedNetworkTypesForReasons.split(",")) - .map(s -> s.substring(0, s.indexOf("=") + 1) - + TelephonyManager.convertNetworkTypeBitmaskToString( - Long.parseLong(s.substring(s.indexOf("=") + 1)))) - .collect(Collectors.joining(", ")); - } - @Override public String toString() { return "[SubscriptionInfoInternal: id=" + mId - + " iccId=" + getPrintableId(mIccId) + + " iccId=" + givePrintableId(mIccId) + " simSlotIndex=" + mSimSlotIndex + " portIndex=" + mPortIndex + " isEmbedded=" + mIsEmbedded @@ -1093,7 +1073,7 @@ public class SubscriptionInfoInternal { + " mnc=" + mMnc + " ehplmns=" + mEhplmns + " hplmns=" + mHplmns - + " cardString=" + getPrintableId(mCardString) + + " cardString=" + givePrintableId(mCardString) + " cardId=" + mCardId + " nativeAccessRules=" + IccUtils.bytesToHexString(mNativeAccessRules) + " carrierConfigAccessRules=" + IccUtils.bytesToHexString( @@ -1111,12 +1091,11 @@ public class SubscriptionInfoInternal { + " wifiCallingModeForRoaming=" + ImsMmTelManager.wifiCallingModeToString(mWifiCallingModeForRoaming) + " enabledMobileDataPolicies=" + mEnabledMobileDataPolicies - + " imsi=" + getPrintableId(mImsi) + + " imsi=" + givePrintableId(mImsi) + " rcsUceEnabled=" + mIsRcsUceEnabled + " crossSimCallingEnabled=" + mIsCrossSimCallingEnabled + " rcsConfig=" + IccUtils.bytesToHexString(mRcsConfig) - + " allowedNetworkTypesForReasons=" - + getPrintableAllowedNetworkTypesForReasons(mAllowedNetworkTypesForReasons) + + " allowedNetworkTypesForReasons=" + mAllowedNetworkTypesForReasons + " deviceToDeviceStatusSharingPreference=" + mDeviceToDeviceStatusSharingPreference + " isVoImsOptInEnabled=" + mIsVoImsOptInEnabled + " deviceToDeviceStatusSharingContacts=" + mDeviceToDeviceStatusSharingContacts -- GitLab From 11866005e94bf46454baff3ee636f6c0553f8742 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Mon, 28 Nov 2022 20:20:59 -0800 Subject: [PATCH 348/656] Add SatelliteProxy Bug: 260644201 Test: atest VtsHalRadioTargetTest atest TelephonyManagerTestOnMockModem MO/MT SMS, MMS, voice calls with live network Change-Id: I6c8d6c5bb829cf378a17eb013cadf6f0289e747c --- Android.bp | 1 + .../internal/telephony/BaseCommands.java | 86 +++ .../internal/telephony/CommandsInterface.java | 238 +++++++ .../android/internal/telephony/MockModem.java | 34 + .../com/android/internal/telephony/RIL.java | 582 +++++++++++++++++- .../android/internal/telephony/RILUtils.java | 148 +++++ .../telephony/RadioSatelliteProxy.java | 290 +++++++++ .../telephony/SatelliteIndication.java | 179 ++++++ .../internal/telephony/SatelliteResponse.java | 220 +++++++ 9 files changed, 1775 insertions(+), 3 deletions(-) create mode 100644 src/java/com/android/internal/telephony/RadioSatelliteProxy.java create mode 100644 src/java/com/android/internal/telephony/SatelliteIndication.java create mode 100644 src/java/com/android/internal/telephony/SatelliteResponse.java diff --git a/Android.bp b/Android.bp index 4097571eb5..502763505e 100644 --- a/Android.bp +++ b/Android.bp @@ -90,6 +90,7 @@ java_library { "android.hardware.radio.modem-V2-java", "android.hardware.radio.network-V2-java", "android.hardware.radio.sim-V2-java", + "android.hardware.radio.satellite-V1-java", "android.hardware.radio.voice-V2-java", "voip-common", "ims-common", diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java index f36161a7d3..e32101f5e9 100644 --- a/src/java/com/android/internal/telephony/BaseCommands.java +++ b/src/java/com/android/internal/telephony/BaseCommands.java @@ -17,6 +17,8 @@ package com.android.internal.telephony; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.AsyncResult; @@ -118,6 +120,13 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mConnectionSetupFailureRegistrants = new RegistrantList(); protected RegistrantList mNotifyAnbrRegistrants = new RegistrantList(); protected RegistrantList mTriggerImsDeregistrationRegistrants = new RegistrantList(); + protected RegistrantList mPendingSatelliteMessageCountRegistrants = new RegistrantList(); + protected RegistrantList mNewSatelliteMessagesRegistrants = new RegistrantList(); + protected RegistrantList mSatelliteMessagesTransferCompleteRegistrants = new RegistrantList(); + protected RegistrantList mSatellitePointingInfoChangedRegistrants = new RegistrantList(); + protected RegistrantList mSatelliteModeChangedRegistrants = new RegistrantList(); + protected RegistrantList mSatelliteRadioTechnologyChangedRegistrants = new RegistrantList(); + protected RegistrantList mSatelliteProvisionStateChangedRegistrants = new RegistrantList(); @UnsupportedAppUsage protected Registrant mGsmSmsRegistrant; @@ -1188,4 +1197,81 @@ public abstract class BaseCommands implements CommandsInterface { public void unregisterForTriggerImsDeregistration(Handler h) { mTriggerImsDeregistrationRegistrants.remove(h); } + + @Override + public void registerForPendingSatelliteMessageCount( + @NonNull Handler h, int what, @Nullable Object obj) { + mPendingSatelliteMessageCountRegistrants.add(h, what, obj); + } + + @Override + public void unregisterForPendingSatelliteMessageCount(@NonNull Handler h) { + mPendingSatelliteMessageCountRegistrants.remove(h); + } + + @Override + public void registerForNewSatelliteMessages( + @NonNull Handler h, int what, @Nullable Object obj) { + mNewSatelliteMessagesRegistrants.add(h, what, obj); + } + + @Override + public void unregisterForNewSatelliteMessages(@NonNull Handler h) { + mNewSatelliteMessagesRegistrants.remove(h); + } + + @Override + public void registerForSatelliteMessagesTransferComplete(@NonNull Handler h, + int what, @Nullable Object obj) { + mSatelliteMessagesTransferCompleteRegistrants.add(h, what, obj); + } + + @Override + public void unregisterForSatelliteMessagesTransferComplete(@NonNull Handler h) { + mSatelliteMessagesTransferCompleteRegistrants.remove(h); + } + + @Override + public void registerForSatellitePointingInfoChanged(@NonNull Handler h, + int what, @Nullable Object obj) { + mSatellitePointingInfoChangedRegistrants.add(h, what, obj); + } + + @Override + public void unregisterForSatellitePointingInfoChanged(@NonNull Handler h) { + mSatellitePointingInfoChangedRegistrants.remove(h); + } + + @Override + public void registerForSatelliteModeChanged(@NonNull Handler h, + int what, @Nullable Object obj) { + mSatelliteModeChangedRegistrants.add(h, what, obj); + } + + @Override + public void unregisterForSatelliteModeChanged(@NonNull Handler h) { + mSatelliteModeChangedRegistrants.remove(h); + } + + @Override + public void registerForSatelliteRadioTechnologyChanged(@NonNull Handler h, + int what, @Nullable Object obj) { + mSatelliteRadioTechnologyChangedRegistrants.add(h, what, obj); + } + + @Override + public void unregisterForSatelliteRadioTechnologyChanged(@NonNull Handler h) { + mSatelliteRadioTechnologyChangedRegistrants.remove(h); + } + + @Override + public void registerForSatelliteProvisionStateChanged(@NonNull Handler h, + int what, @Nullable Object obj) { + mSatelliteProvisionStateChangedRegistrants.add(h, what, obj); + } + + @Override + public void unregisterForSatelliteProvisionStateChanged(@NonNull Handler h) { + mSatelliteProvisionStateChangedRegistrants.remove(h); + } } diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 92f1696ec6..915465f1ae 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -3025,4 +3025,242 @@ public interface CommandsInterface { * @param result Callback message to receive the result. */ default void isN1ModeEnabled(Message result) {} + + /** + * Get feature capabilities supported by satellite. + * + * @param result Message that will be sent back to the requester + */ + default void getSatelliteCapabilities(Message result) {} + + /** + * Turn satellite modem on/off. + * + * @param result Message that will be sent back to the requester + * @param on {@code true} for turning on. + * {@code false} for turning off. + */ + default void setSatellitePower(Message result, boolean on) {} + + /** + * Get satellite modem state. + * + * @param result Message that will be sent back to the requester + */ + default void getSatellitePowerState(Message result) {} + + /** + * Provision the subscription with a satellite provider. This is needed to register the + * subscription if the provider allows dynamic registration. + * + * @param result Message that will be sent back to the requester. + * @param imei IMEI of the SIM associated with the satellite modem. + * @param msisdn MSISDN of the SIM associated with the satellite modem. + * @param imsi IMSI of the SIM associated with the satellite modem. + * @param features List of features to be provisioned. + */ + default void provisionSatelliteService( + Message result, String imei, String msisdn, String imsi, int[] features) {} + + /** + * Add contacts that are allowed to be used for satellite communication. This is applicable for + * incoming messages as well. + * + * @param result Message that will be sent back to the requester. + * @param contacts List of allowed contacts to be added. + */ + default void addAllowedSatelliteContacts(Message result, String[] contacts) {} + + /** + * Remove contacts that are allowed to be used for satellite communication. This is applicable + * for incoming messages as well. + * + * @param result Message that will be sent back to the requester. + * @param contacts List of allowed contacts to be removed. + */ + default void removeAllowedSatelliteContacts(Message result, String[] contacts) {} + + /** + * Send text messages. + * + * @param result Message that will be sent back to the requester. + * @param messages List of messages in text format to be sent. + * @param destination The recipient of the message. + * @param latitude The current latitude of the device. + * @param longitude The current longitude of the device. The location (i.e., latitude and + * longitude) of the device will be filled for emergency messages. + */ + default void sendSatelliteMessages(Message result, String[] messages, String destination, + double latitude, double longitude) {} + + /** + * Get pending messages. + * + * @param result Message that will be sent back to the requester. + */ + default void getPendingSatelliteMessages(Message result) {} + + /** + * Get current satellite registration mode. + * + * @param result Message that will be sent back to the requester. + */ + default void getSatelliteMode(Message result) {} + + /** + * Set the filter for what type of indication framework want to receive from modem. + * + * @param result Message that will be sent back to the requester. + * @param filterBitmask The filter bitmask identifying what type of indication Telephony + * framework wants to receive from modem. + */ + default void setSatelliteIndicationFilter(Message result, int filterBitmask) {} + + /** + * User started pointing to the satellite. Modem should continue to update the ponting input + * as user moves device. + * + * @param result Message that will be sent back to the requester. + */ + default void startSendingSatellitePointingInfo(Message result) {} + + /** + * Stop sending satellite pointing info to the framework. + * + * @param result Message that will be sent back to the requester. + */ + default void stopSendingSatellitePointingInfo(Message result) {} + + /** + * Get max number of characters per text message. + * + * @param result Message that will be sent back to the requester. + */ + default void getMaxCharactersPerSatelliteTextMessage(Message result) {} + + /** + * Get time for next visibility of satellite. + * + * @param result Message that will be sent back to the requester. + */ + default void getTimeForNextSatelliteVisibility(Message result) {} + + /** + * Registers for pending message count from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForPendingSatelliteMessageCount(@NonNull Handler h, + int what, @Nullable Object obj) {} + + /** + * Unregisters for pending message count from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForPendingSatelliteMessageCount(@NonNull Handler h) {} + + /** + * Registers for new messages from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForNewSatelliteMessages(@NonNull Handler h, + int what, @Nullable Object obj) {} + + /** + * Unregisters for new messages from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForNewSatelliteMessages(@NonNull Handler h) {} + + /** + * Registers for messages transfer complete from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForSatelliteMessagesTransferComplete(@NonNull Handler h, + int what, @Nullable Object obj) {} + + /** + * Unregisters for messages transfer complete from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForSatelliteMessagesTransferComplete(@NonNull Handler h) {} + + /** + * Registers for pointing info changed from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForSatellitePointingInfoChanged(@NonNull Handler h, + int what, @Nullable Object obj) {} + + /** + * Unregisters for pointing info changed from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForSatellitePointingInfoChanged(@NonNull Handler h) {} + + /** + * Registers for mode changed from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForSatelliteModeChanged(@NonNull Handler h, + int what, @Nullable Object obj) {} + + /** + * Unregisters for mode changed from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForSatelliteModeChanged(@NonNull Handler h) {} + + /** + * Registers for radio technology changed from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForSatelliteRadioTechnologyChanged(@NonNull Handler h, + int what, @Nullable Object obj) {} + + /** + * Unregisters for radio technology changed from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForSatelliteRadioTechnologyChanged(@NonNull Handler h) {} + + /** + * Registers for provision state changed from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + default void registerForSatelliteProvisionStateChanged(@NonNull Handler h, + int what, @Nullable Object obj) {} + + /** + * Unregisters for provision state changed from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + default void unregisterForSatelliteProvisionStateChanged(@NonNull Handler h) {} } diff --git a/src/java/com/android/internal/telephony/MockModem.java b/src/java/com/android/internal/telephony/MockModem.java index a20e74818f..83417c53a5 100644 --- a/src/java/com/android/internal/telephony/MockModem.java +++ b/src/java/com/android/internal/telephony/MockModem.java @@ -21,6 +21,7 @@ import static android.telephony.TelephonyManager.HAL_SERVICE_IMS; import static android.telephony.TelephonyManager.HAL_SERVICE_MESSAGING; import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; +import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE; import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; @@ -44,6 +45,8 @@ public class MockModem { private static final String BIND_IRADIOVOICE = "android.telephony.mockmodem.iradiovoice"; private static final String BIND_IRADIOIMS = "android.telephony.mockmodem.iradioims"; private static final String BIND_IRADIOCONFIG = "android.telephony.mockmodem.iradioconfig"; + private static final String BIND_IRADIOSATELLITE = + "android.telephony.mockmodem.iradiosatellite"; private static final String PHONE_ID = "phone_id"; private static final byte DEFAULT_PHONE_ID = 0x00; @@ -65,6 +68,7 @@ public class MockModem { private IBinder mVoiceBinder; private IBinder mImsBinder; private IBinder mConfigBinder; + private IBinder mSatelliteBinder; private ServiceConnection mModemServiceConnection; private ServiceConnection mSimServiceConnection; private ServiceConnection mMessagingServiceConnection; @@ -73,6 +77,7 @@ public class MockModem { private ServiceConnection mVoiceServiceConnection; private ServiceConnection mImsServiceConnection; private ServiceConnection mConfigServiceConnection; + private ServiceConnection mSatelliteServiceConnection; private byte mPhoneId; private String mTag; @@ -115,6 +120,8 @@ public class MockModem { mVoiceBinder = binder; } else if (mService == HAL_SERVICE_IMS) { mImsBinder = binder; + } else if (mService == HAL_SERVICE_SATELLITE) { + mSatelliteBinder = binder; } else if (mService == RADIOCONFIG_SERVICE) { mConfigBinder = binder; } @@ -138,6 +145,8 @@ public class MockModem { mVoiceBinder = null; } else if (mService == HAL_SERVICE_IMS) { mImsBinder = null; + } else if (mService == HAL_SERVICE_SATELLITE) { + mSatelliteBinder = null; } else if (mService == RADIOCONFIG_SERVICE) { mConfigBinder = null; } @@ -179,6 +188,8 @@ public class MockModem { return mVoiceBinder; case HAL_SERVICE_IMS: return mImsBinder; + case HAL_SERVICE_SATELLITE: + return mSatelliteBinder; case RADIOCONFIG_SERVICE: return mConfigBinder; default: @@ -306,6 +317,20 @@ public class MockModem { } else { Rlog.d(TAG, "IRadio Ims is bound"); } + } else if (service == HAL_SERVICE_SATELLITE) { + if (mSatelliteBinder == null) { + mSatelliteServiceConnection = new MockModemConnection(HAL_SERVICE_SATELLITE); + + boolean status = + bindModuleToMockModemService( + mPhoneId, BIND_IRADIOSATELLITE, mSatelliteServiceConnection); + if (!status) { + Rlog.d(TAG, "IRadio Satellite bind fail"); + mSatelliteServiceConnection = null; + } + } else { + Rlog.d(TAG, "IRadio Satellite is bound"); + } } } @@ -368,6 +393,13 @@ public class MockModem { mImsBinder = null; Rlog.d(TAG, "unbind IRadio Ims"); } + } else if (service == HAL_SERVICE_SATELLITE) { + if (mSatelliteServiceConnection != null) { + mContext.unbindService(mSatelliteServiceConnection); + mSatelliteServiceConnection = null; + mSatelliteBinder = null; + Rlog.d(TAG, "unbind IRadio Satellite"); + } } } @@ -391,6 +423,8 @@ public class MockModem { return "voice"; case HAL_SERVICE_IMS: return "ims"; + case HAL_SERVICE_SATELLITE: + return "satellite"; case RADIOCONFIG_SERVICE: return "config"; default: diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 51fa529c99..fb23e8330d 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -22,6 +22,7 @@ import static android.telephony.TelephonyManager.HAL_SERVICE_MESSAGING; import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; import static android.telephony.TelephonyManager.HAL_SERVICE_RADIO; +import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE; import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; @@ -226,7 +227,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public static final int MIN_SERVICE_IDX = HAL_SERVICE_RADIO; - public static final int MAX_SERVICE_IDX = HAL_SERVICE_IMS; + public static final int MAX_SERVICE_IDX = HAL_SERVICE_SATELLITE; /** * An array of sets that records if services are disabled in the HAL for a specific phone ID @@ -261,6 +262,8 @@ public class RIL extends BaseCommands implements CommandsInterface { private ModemIndication mModemIndication; private NetworkResponse mNetworkResponse; private NetworkIndication mNetworkIndication; + private SatelliteResponse mSatelliteResponse; + private SatelliteIndication mSatelliteIndication; private SimResponse mSimResponse; private SimIndication mSimIndication; private VoiceResponse mVoiceResponse; @@ -746,7 +749,7 @@ public class RIL extends BaseCommands implements CommandsInterface { /** * Returns a {@link RadioDataProxy}, {@link RadioMessagingProxy}, {@link RadioModemProxy}, * {@link RadioNetworkProxy}, {@link RadioSimProxy}, {@link RadioVoiceProxy}, - * {@link RadioImsProxy}, or null if the service is not available. + * {@link RadioImsProxy}, {@link RadioSatelliteProxy}, or null if the service is not available. */ @NonNull public T getRadioServiceProxy(Class serviceClass, @@ -772,6 +775,9 @@ public class RIL extends BaseCommands implements CommandsInterface { if (serviceClass == RadioImsProxy.class) { return (T) getRadioServiceProxy(HAL_SERVICE_IMS, result); } + if (serviceClass == RadioSatelliteProxy.class) { + return (T) getRadioServiceProxy(HAL_SERVICE_SATELLITE, result); + } riljLoge("getRadioServiceProxy: unrecognized " + serviceClass); return null; } @@ -784,7 +790,8 @@ public class RIL extends BaseCommands implements CommandsInterface { @NonNull public synchronized RadioServiceProxy getRadioServiceProxy(int service, Message result) { if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return mServiceProxies.get(service); - if (service == HAL_SERVICE_IMS && !isRadioServiceSupported(service)) { + if ((service >= HAL_SERVICE_IMS) + && !isRadioServiceSupported(service)) { return mServiceProxies.get(service); } if (!mIsCellularSupported) { @@ -914,6 +921,21 @@ public class RIL extends BaseCommands implements CommandsInterface { .asInterface(binder))); } break; + case HAL_SERVICE_SATELLITE: + if (mMockModem == null) { + binder = ServiceManager.waitForDeclaredService( + android.hardware.radio.satellite.IRadioSatellite.DESCRIPTOR + + "/" + HIDL_SERVICE_NAME[mPhoneId]); + } else { + binder = mMockModem.getServiceBinder(HAL_SERVICE_SATELLITE); + } + if (binder != null) { + mHalVersion.put(service, ((RadioSatelliteProxy) serviceProxy).setAidl( + mHalVersion.get(service), + android.hardware.radio.satellite.IRadioSatellite.Stub + .asInterface(binder))); + } + break; } if (serviceProxy.isEmpty() @@ -1038,6 +1060,12 @@ public class RIL extends BaseCommands implements CommandsInterface { ((RadioImsProxy) serviceProxy).getAidl().setResponseFunctions( mImsResponse, mImsIndication); break; + case HAL_SERVICE_SATELLITE: + mDeathRecipients.get(service).linkToDeath( + ((RadioSatelliteProxy) serviceProxy).getAidl().asBinder()); + ((RadioSatelliteProxy) serviceProxy).getAidl().setResponseFunctions( + mSatelliteResponse, mSatelliteIndication); + break; } } else { if (mHalVersion.get(service) @@ -1152,6 +1180,8 @@ public class RIL extends BaseCommands implements CommandsInterface { mModemIndication = new ModemIndication(this); mNetworkResponse = new NetworkResponse(this); mNetworkIndication = new NetworkIndication(this); + mSatelliteResponse = new SatelliteResponse(this); + mSatelliteIndication = new SatelliteIndication(this); mSimResponse = new SimResponse(this); mSimIndication = new SimIndication(this); mVoiceResponse = new VoiceResponse(this); @@ -1186,6 +1216,7 @@ public class RIL extends BaseCommands implements CommandsInterface { mServiceProxies.put(HAL_SERVICE_SIM, new RadioSimProxy()); mServiceProxies.put(HAL_SERVICE_VOICE, new RadioVoiceProxy()); mServiceProxies.put(HAL_SERVICE_IMS, new RadioImsProxy()); + mServiceProxies.put(HAL_SERVICE_SATELLITE, new RadioSatelliteProxy()); } else { mServiceProxies = proxies; } @@ -1268,6 +1299,9 @@ public class RIL extends BaseCommands implements CommandsInterface { case HAL_SERVICE_IMS: serviceName = android.hardware.radio.ims.IRadioIms.DESCRIPTOR; break; + case HAL_SERVICE_SATELLITE: + serviceName = android.hardware.radio.satellite.IRadioSatellite.DESCRIPTOR; + break; } if (!serviceName.equals("") @@ -5734,6 +5768,545 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * Get feature capabilities supported by satellite. + * + * @param result Message that will be sent back to the requester + */ + @Override + public void getSatelliteCapabilities(Message result) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_GET_SATELLITE_CAPABILITIES, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.getCapabilities(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR( + HAL_SERVICE_SATELLITE, "getSatelliteCapabilities", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "getSatelliteCapabilities: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Turn satellite modem on/off. + * + * @param result Message that will be sent back to the requester + * @param on True for turning on. + * False for turning off. + */ + @Override + public void setSatellitePower(Message result, boolean on) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_SET_SATELLITE_POWER, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.setPower(rr.mSerial, on); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, "setSatellitePower", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "setSatellitePower: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Get satellite modem state. + * + * @param result Message that will be sent back to the requester + */ + @Override + public void getSatellitePowerState(Message result) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_GET_SATELLITE_POWER, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.getPowerState(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, "getSatellitePowerState", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "getSatellitePowerState: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Provision the subscription with a satellite provider. This is needed to register the + * subscription if the provider allows dynamic registration. + * + * @param result Message that will be sent back to the requester. + * @param imei IMEI of the SIM associated with the satellite modem. + * @param msisdn MSISDN of the SIM associated with the satellite modem. + * @param imsi IMSI of the SIM associated with the satellite modem. + * @param features List of features to be provisioned. + */ + @Override + public void provisionSatelliteService( + Message result, String imei, String msisdn, String imsi, int[] features) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_PROVISION_SATELLITE_SERVICE, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.provisionService(rr.mSerial, imei, msisdn, imsi, features); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR( + HAL_SERVICE_SATELLITE, "provisionSatelliteService", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "provisionSatelliteService: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Add contacts that are allowed to be used for satellite communication. This is applicable for + * incoming messages as well. + * + * @param result Message that will be sent back to the requester. + * @param contacts List of allowed contacts to be added. + */ + @Override + public void addAllowedSatelliteContacts(Message result, String[] contacts) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_ADD_ALLOWED_SATELLITE_CONTACTS, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.addAllowedSatelliteContacts(rr.mSerial, contacts); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, + "addAllowedSatelliteContacts", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "addAllowedSatelliteContacts: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Remove contacts that are allowed to be used for satellite communication. This is applicable + * for incoming messages as well. + * + * @param result Message that will be sent back to the requester. + * @param contacts List of allowed contacts to be removed. + */ + @Override + public void removeAllowedSatelliteContacts(Message result, String[] contacts) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_REMOVE_ALLOWED_SATELLITE_CONTACTS, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.removeAllowedSatelliteContacts(rr.mSerial, contacts); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, + "removeAllowedSatelliteContacts", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "removeAllowedSatelliteContacts: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Send text messages. + * + * @param result Message that will be sent back to the requester. + * @param messages List of messages in text format to be sent. + * @param destination The recipient of the message. + * @param latitude The current latitude of the device. + * @param longitude The current longitude of the device. + */ + @Override + public void sendSatelliteMessages(Message result, String[] messages, String destination, + double latitude, double longitude) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest( + RIL_REQUEST_SEND_SATELLITE_MESSAGES, result, mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.sendMessages(rr.mSerial, messages, destination, latitude, + longitude); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, "sendSatelliteMessages", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "sendSatelliteMessages: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Get pending messages. + * + * @param result Message that will be sent back to the requester. + */ + @Override + public void getPendingSatelliteMessages(Message result) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_GET_PENDING_SATELLITE_MESSAGES, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.getPendingMessages(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR( + HAL_SERVICE_SATELLITE, "getPendingSatelliteMessages", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "getPendingSatelliteMessages: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Get current satellite registration mode. + * + * @param result Message that will be sent back to the requester. + */ + @Override + public void getSatelliteMode(Message result) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_GET_SATELLITE_MODE, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.getSatelliteMode(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, "getSatelliteMode", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "getSatelliteMode: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Set the filter for what type of indication framework want to receive from modem. + * + * @param result Message that will be sent back to the requester. + * @param filterBitmask The filter bitmask identifying what type of indication framework want to + * receive from modem. + */ + @Override + public void setSatelliteIndicationFilter(Message result, int filterBitmask) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_SET_SATELLITE_INDICATION_FILTER, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.setIndicationFilter(rr.mSerial, filterBitmask); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, + "setSatelliteIndicationFilter", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "setSatelliteIndicationFilter: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * User started pointing to the satellite. Modem should continue to update the ponting input + * as user moves device. + * + * @param result Message that will be sent back to the requester. + */ + @Override + public void startSendingSatellitePointingInfo(Message result) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_START_SENDING_SATELLITE_POINTING_INFO, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.startSendingSatellitePointingInfo(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, + "startSendingSatellitePointingInfo", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, + "startSendingSatellitePointingInfo: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Stop pointing to satellite indications. + * + * @param result Message that will be sent back to the requester. + */ + @Override + public void stopSendingSatellitePointingInfo(Message result) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_STOP_SENDING_SATELLITE_POINTING_INFO, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.stopSendingSatellitePointingInfo(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, + "stopSendingSatellitePointingInfo", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, + "stopSendingSatellitePointingInfo: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Get max text limit for messaging per message. + * + * @param result Message that will be sent back to the requester. + */ + @Override + public void getMaxCharactersPerSatelliteTextMessage(Message result) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE, + result, mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.getMaxCharactersPerTextMessage(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, + "getMaxCharactersPerSatelliteTextMessage", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, + "getMaxCharactersPerSatelliteTextMessage: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + + /** + * Get time for next visibility of satellite. + * + * @param result Message that will be sent back to the requester. + */ + @Override + public void getTimeForNextSatelliteVisibility(Message result) { + RadioSatelliteProxy radioSatelliteProxy = + getRadioServiceProxy(RadioSatelliteProxy.class, result); + if (radioSatelliteProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { + RILRequest rr = obtainRequest(RIL_REQUEST_GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY, + result, mRILDefaultWorkSource); + + if (RILJ_LOGD) { + // Do not log function arg for privacy + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + radioSatelliteProxy.getTimeForNextSatelliteVisibility(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, + "getTimeForNextSatelliteVisibility", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, + "getTimeForNextSatelliteVisibility: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + //***** Private Methods /** * This is a helper function to be called when an indication callback is called for any radio @@ -6524,6 +7097,7 @@ public class RIL extends BaseCommands implements CommandsInterface { pw.println(" " + mServiceProxies.get(HAL_SERVICE_SIM)); pw.println(" " + mServiceProxies.get(HAL_SERVICE_VOICE)); pw.println(" " + mServiceProxies.get(HAL_SERVICE_IMS)); + pw.println(" " + mServiceProxies.get(HAL_SERVICE_SATELLITE)); pw.println(" mWakeLock=" + mWakeLock); pw.println(" mWakeLockTimeout=" + mWakeLockTimeout); synchronized (mRequestList) { @@ -6646,6 +7220,8 @@ public class RIL extends BaseCommands implements CommandsInterface { return "VOICE"; case HAL_SERVICE_IMS: return "IMS"; + case HAL_SERVICE_SATELLITE: + return "SATELLITE"; default: return "UNKNOWN:" + service; } diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 95b0011fd3..4064a5c82e 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -25,6 +25,7 @@ import static android.telephony.TelephonyManager.CAPABILITY_THERMAL_MITIGATION_D import static android.telephony.TelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ADD_ALLOWED_SATELLITE_CONTACTS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ALLOCATE_PDU_SESSION_ID; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ALLOW_DATA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ANSWER; @@ -90,12 +91,17 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_HARDWA import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMEI; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMEISV; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMSI; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MODEM_STATUS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MUTE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_NEIGHBORING_CELL_IDS; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PENDING_SATELLITE_MESSAGES; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PHONE_CAPABILITY; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_RADIO_CAPABILITY; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SATELLITE_CAPABILITIES; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SATELLITE_MODE; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SATELLITE_POWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_PHONEBOOK_CAPACITY; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_PHONEBOOK_RECORDS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_STATUS; @@ -103,6 +109,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLICIN import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLOT_STATUS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SMSC_ADDRESS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_USAGE_SETTING; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GSM_BROADCAST_ACTIVATION; @@ -126,6 +133,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_WRITE_I import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OEM_HOOK_RAW; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OEM_HOOK_STRINGS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OPERATOR; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PROVISION_SATELLITE_SERVICE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PULL_LCEDATA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_AVAILABLE_NETWORKS; @@ -137,12 +145,14 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_NETW import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_TTY_MODE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RELEASE_PDU_SESSION_ID; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REMOVE_ALLOWED_SATELLITE_CONTACTS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REPORT_SMS_MEMORY_STATUS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RESET_RADIO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SCREEN_STATE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_ANBR_QUERY; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_DEVICE_STATE; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SATELLITE_MESSAGES; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_USSD; @@ -172,6 +182,8 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NULL_C import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_DATA_MODEM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_RADIO_CAPABILITY; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SATELLITE_INDICATION_FILTER; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SATELLITE_POWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SIM_CARD_POWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SMSC_ADDRESS; @@ -197,6 +209,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_IMS_ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_KEEPALIVE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_LCE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_NETWORK_SCAN; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_SENDING_SATELLITE_POINTING_INFO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_GET_PROFILE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND; @@ -207,6 +220,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_IMS_T import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_KEEPALIVE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_LCE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_NETWORK_SCAN; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_SENDING_SATELLITE_POINTING_INFO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN; @@ -241,6 +255,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_KEEPALIVE_ST import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NEW_SATELLITE_MESSAGES; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NOTIFY_ANBR; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_OEM_HOOK_RAW; @@ -248,6 +263,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_SS; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD_REQUEST; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PCO_DATA; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RADIO_CAPABILITY; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_REGISTRATION_FAILED; @@ -267,6 +283,11 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_SIM import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESTRICTED_STATE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RIL_CONNECTED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RINGBACK_TONE; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MODE_CHANGED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIGNAL_STRENGTH; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIM_REFRESH; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIM_SMS_STORAGE_FULL; @@ -353,6 +374,9 @@ import android.telephony.ims.feature.ConnectionFailureInfo; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsRegistrationImplBase.ImsDeregistrationReason; +import android.telephony.satellite.PointingInfo; +import android.telephony.satellite.SatelliteCapabilities; +import android.telephony.satellite.stub.SatelliteImplBase; import android.text.TextUtils; import android.util.ArraySet; import android.util.SparseArray; @@ -5297,6 +5321,34 @@ public class RILUtils { return "SET_N1_MODE_ENABLED"; case RIL_REQUEST_IS_N1_MODE_ENABLED: return "IS_N1_MODE_ENABLED"; + case RIL_REQUEST_GET_SATELLITE_CAPABILITIES: + return "GET_SATELLITE_CAPABILITIES"; + case RIL_REQUEST_SET_SATELLITE_POWER: + return "SET_SATELLITE_POWER"; + case RIL_REQUEST_GET_SATELLITE_POWER: + return "GET_SATELLITE_POWER"; + case RIL_REQUEST_PROVISION_SATELLITE_SERVICE: + return "PROVISION_SATELLITE_SERVICE"; + case RIL_REQUEST_ADD_ALLOWED_SATELLITE_CONTACTS: + return "ADD_ALLOWED_SATELLITE_CONTACTS"; + case RIL_REQUEST_REMOVE_ALLOWED_SATELLITE_CONTACTS: + return "REMOVE_ALLOWED_SATELLITE_CONTACTS"; + case RIL_REQUEST_SEND_SATELLITE_MESSAGES: + return "SEND_SATELLITE_MESSAGES"; + case RIL_REQUEST_GET_PENDING_SATELLITE_MESSAGES: + return "GET_PENDING_SATELLITE_MESSAGES"; + case RIL_REQUEST_GET_SATELLITE_MODE: + return "GET_SATELLITE_MODE"; + case RIL_REQUEST_SET_SATELLITE_INDICATION_FILTER: + return "SET_SATELLITE_INDICATION_FILTER"; + case RIL_REQUEST_START_SENDING_SATELLITE_POINTING_INFO: + return "START_SENDING_SATELLITE_POINTING_INFO"; + case RIL_REQUEST_STOP_SENDING_SATELLITE_POINTING_INFO: + return "STOP_SENDING_SATELLITE_POINTING_INFO"; + case RIL_REQUEST_GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE: + return "GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE"; + case RIL_REQUEST_GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY: + return "GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY"; default: return ""; } @@ -5437,6 +5489,20 @@ public class RILUtils { return "UNSOL_NOTIFY_ANBR"; case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION: return "UNSOL_TRIGGER_IMS_DEREGISTRATION"; + case RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT: + return "UNSOL_PENDING_SATELLITE_MESSAGE_COUNT"; + case RIL_UNSOL_NEW_SATELLITE_MESSAGES: + return "UNSOL_NEW_SATELLITE_MESSAGES"; + case RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE: + return "UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE"; + case RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED: + return "UNSOL_SATELLITE_POINTING_INFO_CHANGED"; + case RIL_UNSOL_SATELLITE_MODE_CHANGED: + return "UNSOL_SATELLITE_MODE_CHANGED"; + case RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED: + return "UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED"; + case RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED: + return "UNSOL_SATELLITE_PROVISION_STATE_CHANGED"; default: return ""; } @@ -5821,6 +5887,88 @@ public class RILUtils { return halInfos; } + /** + * Convert android.hardware.radio.satellite.SatelliteCapabilities to + * android.telephony.satellite.SatelliteCapabilities + */ + public static SatelliteCapabilities convertHalSatelliteCapabilities( + android.hardware.radio.satellite.SatelliteCapabilities capabilities) { + Set supportedRadioTechnologies = new HashSet<>(); + if (capabilities.supportedRadioTechnologies != null + && capabilities.supportedRadioTechnologies.length > 0) { + for (int technology : capabilities.supportedRadioTechnologies) { + supportedRadioTechnologies.add(technology); + } + } + + Set supportedFeatures = new HashSet<>(); + if (capabilities.supportedFeatures != null + && capabilities.supportedFeatures.length > 0) { + for (int feature : capabilities.supportedFeatures) { + supportedFeatures.add(feature); + } + } + return new SatelliteCapabilities(supportedRadioTechnologies, capabilities.isAlwaysOn, + capabilities.needsPointingToSatellite, supportedFeatures, + capabilities.needsSeparateSimProfile); + } + + /** + * Convert from android.hardware.radio.satellite.Feature to + * android.telephony.satellite.stub.SatelliteImplBase.Feature + */ + public static int convertHalSatelliteFeature(int feature) { + switch (feature) { + case android.hardware.radio.satellite.SatelliteFeature.SOS_SMS: + return SatelliteImplBase.FEATURE_SOS_SMS; + case android.hardware.radio.satellite.SatelliteFeature.EMERGENCY_SMS: + return SatelliteImplBase.FEATURE_EMERGENCY_SMS; + case android.hardware.radio.satellite.SatelliteFeature.SMS: + return SatelliteImplBase.FEATURE_SMS; + case android.hardware.radio.satellite.SatelliteFeature.LOCATION_SHARING: + return SatelliteImplBase.FEATURE_LOCATION_SHARING; + default: return SatelliteImplBase.FEATURE_UNKNOWN; + } + } + /** + * Convert from android.hardware.radio.satellite.PointingInfo to + * android.telephony.satellite.stub.PointingInfo + */ + public static PointingInfo convertHalSatellitePointingInfo( + android.hardware.radio.satellite.PointingInfo pointingInfo) { + return new PointingInfo(pointingInfo.satelliteAzimuthDegrees, + pointingInfo.satelliteElevationDegrees, pointingInfo.antennaAzimuthDegrees, + pointingInfo.antennaPitchDegrees, pointingInfo.antennaRollDegrees); + } + + /** + * Convert array of android.hardware.radio.satellite.Feature to + * array of android.telephony.satellite.stub.SatelliteImplBase.Feature + */ + public static int[] convertHalSatelliteFeatures(int[] features) { + int[] convertedFeatrures = new int[features.length]; + for (int i = 0; i < features.length; i++) { + convertedFeatrures[i] = convertHalSatelliteFeature(features[i]); + } + return convertedFeatrures; + } + + /** + * Convert from android.telephony.satellite.stub.PointingInfo to + * android.hardware.radio.satellite.PointingInfo + */ + public static android.hardware.radio.satellite.PointingInfo convertToHalSatellitePointingInfo( + PointingInfo pointingInfo) { + android.hardware.radio.satellite.PointingInfo halPointingInfo = + new android.hardware.radio.satellite.PointingInfo(); + halPointingInfo.satelliteAzimuthDegrees = pointingInfo.getSatelliteAzimuthDegrees(); + halPointingInfo.satelliteElevationDegrees = pointingInfo.getSatelliteElevationDegrees(); + halPointingInfo.antennaAzimuthDegrees = pointingInfo.getAntennaAzimuthDegrees(); + halPointingInfo.antennaPitchDegrees = pointingInfo.getAntennaPitchDegrees(); + halPointingInfo.antennaRollDegrees = pointingInfo.getAntennaRollDegrees(); + return halPointingInfo; + } + /** * Converts the call state to HAL IMS call state. * diff --git a/src/java/com/android/internal/telephony/RadioSatelliteProxy.java b/src/java/com/android/internal/telephony/RadioSatelliteProxy.java new file mode 100644 index 0000000000..1530c1a2ca --- /dev/null +++ b/src/java/com/android/internal/telephony/RadioSatelliteProxy.java @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2022 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; + +import android.os.RemoteException; +import android.telephony.Rlog; + +/** + * A holder for IRadioSatellite. + * Use getAidl to get IRadioSatellite and call the AIDL implementations of the HAL APIs. + */ +public class RadioSatelliteProxy extends RadioServiceProxy { + private static final String TAG = "RadioSatelliteProxy"; + private volatile android.hardware.radio.satellite.IRadioSatellite mRadioSatelliteProxy = null; + + /** + * Sets IRadioSatellite as the AIDL implementation for RadioSatelliteProxy. + * @param halVersion Radio HAL version. + * @param radioSatellite IRadioSatellite implementation. + * + * @return updated HAL version. + */ + public HalVersion setAidl(HalVersion halVersion, + android.hardware.radio.satellite.IRadioSatellite radioSatellite) { + mHalVersion = halVersion; + mRadioSatelliteProxy = radioSatellite; + mIsAidl = true; + + try { + HalVersion newHalVersion; + int version = radioSatellite.getInterfaceVersion(); + switch(version) { + default: + newHalVersion = RIL.RADIO_HAL_VERSION_2_0; + break; + } + Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); + + if (mHalVersion.less(newHalVersion)) { + mHalVersion = newHalVersion; + } + } catch (RemoteException e) { + Rlog.e(TAG, "setAidl: " + e); + } + + Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); + return mHalVersion; + } + + /** + * Gets the AIDL implementation of RadioSatelliteProxy. + * @return IRadioSatellite implementation. + */ + public android.hardware.radio.satellite.IRadioSatellite getAidl() { + return mRadioSatelliteProxy; + } + + /** + * Resets RadioSatelliteProxy. + */ + @Override + public void clear() { + super.clear(); + mRadioSatelliteProxy = null; + } + + /** + * Checks whether a IRadioSatellite implementation exists. + * @return true if there is neither a HIDL nor AIDL implementation. + */ + @Override + public boolean isEmpty() { + return mRadioProxy == null && mRadioSatelliteProxy == null; + } + + /** + * Call IRadioSatellite#responseAcknowledgement + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + @Override + public void responseAcknowledgement() throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.responseAcknowledgement(); + } + } + + /** + * Call IRadioSatellite#getCapabilities + * @param serial Serial number of request. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void getCapabilities(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.getCapabilities(serial); + } + } + + /** + * Call IRadioSatellite#setPower + * @param serial Serial number of request. + * @param on True for turning on. + * False for turning off. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void setPower(int serial, boolean on) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.setPower(serial, on); + } + } + + /** + * Call IRadioSatellite#getPowerState + * @param serial Serial number of request. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void getPowerState(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.getPowerState(serial); + } + } + + /** + * Call IRadioSatellite#provisionService + * @param serial Serial number of request. + * @param imei IMEI of the SIM associated with the satellite modem. + * @param msisdn MSISDN of the SIM associated with the satellite modem. + * @param imsi IMSI of the SIM associated with the satellite modem. + * @param features List of features to be provisioned. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void provisionService( + int serial, + String imei, + String msisdn, + String imsi, + int[] features) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.provisionService(serial, imei, msisdn, imsi, features); + } + } + + /** + * Call IRadioSatellite#addAllowedSatelliteContacts + * @param serial Serial number of request. + * @param contacts List of allowed contacts to be added. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void addAllowedSatelliteContacts(int serial, String[] contacts) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.addAllowedSatelliteContacts(serial, contacts); + } + } + + /** + * Call IRadioSatellite#removeAllowedSatelliteContacts + * @param serial Serial number of request. + * @param contacts List of allowed contacts to be removed. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void removeAllowedSatelliteContacts(int serial, String[] contacts) + throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.removeAllowedSatelliteContacts(serial, contacts); + } + } + + /** + * Call IRadioSatellite#sendMessages + * @param serial Serial number of request. + * @param messages List of messages in text format to be sent. + * @param destination The recipient of the message. + * @param latitude The current latitude of the device. + * @param longitude The current longitude of the device + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void sendMessages(int serial, String[] messages, String destination, double latitude, + double longitude) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.sendMessages(serial, messages, destination, latitude, longitude); + } + } + + /** + * Call IRadioSatellite#getPendingMessages + * @param serial Serial number of request. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void getPendingMessages(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.getPendingMessages(serial); + } + } + + /** + * Call IRadioSatellite#getSatelliteMode + * @param serial Serial number of request. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void getSatelliteMode(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.getSatelliteMode(serial); + } + } + + /** + * Call IRadioSatellite#setIndicationFilter + * @param serial Serial number of request. + * @param filterBitmask The filter identifying what type of indication framework want to + * receive from modem. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void setIndicationFilter(int serial, int filterBitmask) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.setIndicationFilter(serial, filterBitmask); + } + } + + /** + * Call IRadioSatellite#startSendingSatellitePointingInfo + * @param serial Serial number of request. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void startSendingSatellitePointingInfo(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.startSendingSatellitePointingInfo(serial); + } + } + + /** + * Call IRadioSatellite#stopSendingSatellitePointingInfo + * @param serial Serial number of request. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void stopSendingSatellitePointingInfo(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.stopSendingSatellitePointingInfo(serial); + } + } + + /** + * Call IRadioSatellite#getMaxCharactersPerTextMessage + * @param serial Serial number of request. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void getMaxCharactersPerTextMessage(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.getMaxCharactersPerTextMessage(serial); + } + } + + /** + * Call IRadioSatellite#getTimeForNextSatelliteVisibility + * @param serial Serial number of request. + * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. + */ + public void getTimeForNextSatelliteVisibility(int serial) throws RemoteException { + if (isEmpty()) return; + if (isAidl()) { + mRadioSatelliteProxy.getTimeForNextSatelliteVisibility(serial); + } + } +} diff --git a/src/java/com/android/internal/telephony/SatelliteIndication.java b/src/java/com/android/internal/telephony/SatelliteIndication.java new file mode 100644 index 0000000000..9b1b0e5180 --- /dev/null +++ b/src/java/com/android/internal/telephony/SatelliteIndication.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2022 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; + +import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE; + +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NEW_SATELLITE_MESSAGES; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MODE_CHANGED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED; + +import android.hardware.radio.satellite.IRadioSatelliteIndication; +import android.os.AsyncResult; +import android.telephony.satellite.stub.SatelliteImplBase; + +/** + * Interface declaring unsolicited radio indications for Satellite APIs. + */ +public class SatelliteIndication extends IRadioSatelliteIndication.Stub { + private final RIL mRil; + + public SatelliteIndication(RIL ril) { + mRil = ril; + } + + @Override + public String getInterfaceHash() { + return IRadioSatelliteIndication.HASH; + } + + @Override + public int getInterfaceVersion() { + return IRadioSatelliteIndication.VERSION; + } + + /** + * Indicates that satellite has pending messages for the device to be pulled. + * + * @param indicationType Type of radio indication + * @param count Number of pending messages. + */ + public void onPendingMessageCount(int indicationType, int count) { + mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); + + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT); + + if (mRil.mPendingSatelliteMessageCountRegistrants != null) { + mRil.mPendingSatelliteMessageCountRegistrants.notifyRegistrants( + new AsyncResult(null, count, null)); + } + } + + /** + * Indicates new message received on device. + * + * @param indicationType Type of radio indication + * @param messages List of new messages received. + */ + public void onNewMessages(int indicationType, String[] messages) { + mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); + + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_NEW_SATELLITE_MESSAGES); + + if (mRil.mNewSatelliteMessagesRegistrants != null) { + mRil.mNewSatelliteMessagesRegistrants.notifyRegistrants( + new AsyncResult(null, messages, null)); + } + } + + /** + * Confirms that ongoing message transfer is complete. + * + * @param indicationType Type of radio indication + * @param complete True mean the transfer is complete. + * False means the transfer is not complete. + */ + public void onMessagesTransferComplete(int indicationType, boolean complete) { + mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); + + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE); + + if (mRil.mSatelliteMessagesTransferCompleteRegistrants != null) { + mRil.mSatelliteMessagesTransferCompleteRegistrants.notifyRegistrants( + new AsyncResult(null, complete, null)); + } + } + + /** + * Indicate that satellite Pointing input has changed. + * + * @param indicationType Type of radio indication + * @param pointingInfo The current pointing info. + */ + public void onSatellitePointingInfoChanged(int indicationType, + android.hardware.radio.satellite.PointingInfo pointingInfo) { + mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); + + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED); + + if (mRil.mSatellitePointingInfoChangedRegistrants != null) { + mRil.mSatellitePointingInfoChangedRegistrants.notifyRegistrants( + new AsyncResult( + null, + RILUtils.convertHalSatellitePointingInfo(pointingInfo), + null)); + } + } + + /** + * Indicate that satellite mode has changed. + * + * @param indicationType Type of radio indication + * @param mode The current mode of the satellite modem. + */ + public void onSatelliteModeChanged(int indicationType, @SatelliteImplBase.Mode int mode) { + mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); + + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_MODE_CHANGED); + + if (mRil.mSatelliteModeChangedRegistrants != null) { + mRil.mSatelliteModeChangedRegistrants.notifyRegistrants( + new AsyncResult(null, mode, null)); + } + } + + /** + * Indicate that satellite radio technology has changed. + * + * @param indicationType Type of radio indication + * @param technology The current technology of the satellite modem. + */ + public void onSatelliteRadioTechnologyChanged(int indicationType, + @SatelliteImplBase.NTRadioTechnology int technology) { + mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); + + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED); + + if (mRil.mSatelliteRadioTechnologyChangedRegistrants != null) { + mRil.mSatelliteRadioTechnologyChangedRegistrants.notifyRegistrants( + new AsyncResult(null, technology, null)); + } + } + + /** + * Indicate that satellite provision state has changed. + * + * @param indicationType Type of radio indication + * @param provisioned True means the service is provisioned. + * False means the service is not provisioned. + * @param features List of Feature whose provision state has changed. + */ + public void onProvisionStateChanged(int indicationType, boolean provisioned, int[] features) { + mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); + + if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED); + + if (mRil.mSatelliteProvisionStateChangedRegistrants != null) { + mRil.mSatelliteProvisionStateChangedRegistrants.notifyRegistrants( + new AsyncResult(null, RILUtils.convertHalSatelliteFeatures(features), null)); + } + } +} diff --git a/src/java/com/android/internal/telephony/SatelliteResponse.java b/src/java/com/android/internal/telephony/SatelliteResponse.java new file mode 100644 index 0000000000..e33f38bbde --- /dev/null +++ b/src/java/com/android/internal/telephony/SatelliteResponse.java @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2021 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; + +import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE; + +import android.hardware.radio.RadioError; +import android.hardware.radio.RadioResponseInfo; +import android.hardware.radio.satellite.IRadioSatelliteResponse; +import android.telephony.satellite.SatelliteCapabilities; +import android.telephony.satellite.stub.SatelliteImplBase; + +/** + * Interface declaring response functions to solicited radio requests for Satellite APIs. + */ +public class SatelliteResponse extends IRadioSatelliteResponse.Stub { + private final RIL mRil; + + public SatelliteResponse(RIL ril) { + mRil = ril; + } + + /** + * Acknowledge the receipt of radio request sent to the vendor. This must be sent only for + * radio request which take long time to respond. + * For more details, refer https://source.android.com/devices/tech/connect/ril.html + * @param serial Serial no. of the request whose acknowledgement is sent. + */ + public void acknowledgeRequest(int serial) { + mRil.processRequestAck(serial); + } + /** + * Response of the request getCapabilities. + * + * @param responseInfo Response info struct containing serial no. and error + * @param capabilities List of capabilities that the satellite modem supports. + */ + public void getCapabilitiesResponse(RadioResponseInfo responseInfo, + android.hardware.radio.satellite.SatelliteCapabilities capabilities) { + RILRequest rr = mRil.processResponse(HAL_SERVICE_SATELLITE, responseInfo); + + if (rr != null) { + SatelliteCapabilities convertedSatelliteCapabilities = + RILUtils.convertHalSatelliteCapabilities(capabilities); + if (responseInfo.error == RadioError.NONE) { + RadioResponse.sendMessageResponse(rr.mResult, convertedSatelliteCapabilities); + } + mRil.processResponseDone(rr, responseInfo, convertedSatelliteCapabilities); + } + } + + /** + * Response of the request setPower. + * + * @param responseInfo Response info struct containing serial no. and error + */ + public void setPowerResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); + } + + /** + * Response of the request getPowerState. + * + * @param responseInfo Response info struct containing serial no. and error + * @param on True means the modem is ON. + * False means the modem is OFF. + */ + public void getPowerStateResponse(RadioResponseInfo responseInfo, boolean on) { + RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, on ? 1 : 0); + } + + /** + * Response of the request provisionService. + * + * @param responseInfo Response info struct containing serial no. and error + * @param provisioned True means the service is provisioned. + * False means the service is not provisioned. + */ + public void provisionServiceResponse(RadioResponseInfo responseInfo, boolean provisioned) { + RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, provisioned ? 1 : 0); + } + + /** + * Response of the request addAllowedSatelliteContacts. + * + * @param responseInfo Response info struct containing serial no. and error + */ + public void addAllowedSatelliteContactsResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); + } + + /** + * Response of the request removeAllowedSatelliteContacts. + * + * @param responseInfo Response info struct containing serial no. and error + */ + public void removeAllowedSatelliteContactsResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); + } + + /** + * Response of the request sendMessages. + * + * @param responseInfo Response info struct containing serial no. and error + */ + public void sendMessagesResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); + } + + /** + * Response of the request getPendingMessages. + * + * @param responseInfo Response info struct containing serial no. and error + * @param messages List of pending messages received. + */ + public void getPendingMessagesResponse(RadioResponseInfo responseInfo, String[] messages) { + RILRequest rr = mRil.processResponse(HAL_SERVICE_SATELLITE, responseInfo); + + if (rr != null) { + if (responseInfo.error == RadioError.NONE) { + RadioResponse.sendMessageResponse(rr.mResult, messages); + } + mRil.processResponseDone(rr, responseInfo, messages); + } + } + + /** + * Response of the request getSatelliteMode. + * + * @param responseInfo Response info struct containing serial no. and error + * @param mode Current Mode of the satellite modem. + * @param technology The current technology of the satellite modem. + */ + public void getSatelliteModeResponse( + RadioResponseInfo responseInfo, @SatelliteImplBase.Mode int mode, + @SatelliteImplBase.NTRadioTechnology int technology) { + RILRequest rr = mRil.processResponse(HAL_SERVICE_SATELLITE, responseInfo); + + if (rr != null) { + int[] ret = new int[]{mode, technology}; + if (responseInfo.error == RadioError.NONE) { + RadioResponse.sendMessageResponse(rr.mResult, ret); + } + mRil.processResponseDone(rr, responseInfo, ret); + } + } + + /** + * Response of the request setIndicationFilter. + * + * @param responseInfo Response info struct containing serial no. and error + */ + public void setIndicationFilterResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); + } + + /** + * Response of the request startSendingSatellitePointingInfo. + * + * @param responseInfo Response info struct containing serial no. and error + */ + public void startSendingSatellitePointingInfoResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); + } + + /** + * Response of the request stopSendingSatellitePointingInfo. + * + * @param responseInfo Response info struct containing serial no. and error + */ + public void stopSendingSatellitePointingInfoResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); + } + + /** + * Response of the request getMaxCharactersPerTextMessage. + * + * @param responseInfo Response info struct containing serial no. and error + * @param charLimit Maximum number of characters in a text message that can be sent. + */ + public void getMaxCharactersPerTextMessageResponse( + RadioResponseInfo responseInfo, int charLimit) { + RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, charLimit); + } + + /** + * Response of the request getTimeForNextSatelliteVisibility. + * + * @param responseInfo Response info struct containing serial no. and error + * @param timeInSeconds The duration in seconds after which the satellite will be visible. + */ + public void getTimeForNextSatelliteVisibilityResponse( + RadioResponseInfo responseInfo, int timeInSeconds) { + RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, timeInSeconds); + } + + @Override + public String getInterfaceHash() { + return IRadioSatelliteResponse.HASH; + } + + @Override + public int getInterfaceVersion() { + return IRadioSatelliteResponse.VERSION; + } +} -- GitLab From e236237409943cff552511ee210bea0f193d8c31 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Thu, 22 Dec 2022 19:31:45 +0000 Subject: [PATCH 349/656] Add SubscriptionManager APIs for satellite communication. The following changes are made: - Added new SATELLITE_ENABLED column in SubscriptionInfoInteral. - Added SubscriptionManagerService#setSatelliteEnabled. Bug: 263502414 Test: atest android.telephony.cts.SubscriptionManagerTest, atest FrameworkTelephonyTestCases Change-Id: I5e43b8bd94694b5f5a9af523a81be8cc94c8a719 --- .../telephony/SubscriptionController.java | 2 + .../SubscriptionDatabaseManager.java | 29 +++++++++++++-- .../SubscriptionInfoInternal.java | 37 ++++++++++++++++++- .../SubscriptionManagerService.java | 3 +- .../SubscriptionDatabaseManagerTest.java | 29 +++++++++++++++ .../SubscriptionInfoInternalTest.java | 2 + 6 files changed, 95 insertions(+), 7 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index af759ead32..cd98fb4373 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -3221,6 +3221,7 @@ public class SubscriptionController extends ISub.Stub { case SubscriptionManager.NR_ADVANCED_CALLING_ENABLED: case SubscriptionManager.USAGE_SETTING: case SubscriptionManager.USER_HANDLE: + case SubscriptionManager.SATELLITE_ENABLED: value.put(propKey, Integer.parseInt(propValue)); break; case SubscriptionManager.ALLOWED_NETWORK_TYPES: @@ -3318,6 +3319,7 @@ public class SubscriptionController extends ISub.Stub { case SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS: case SubscriptionManager.USAGE_SETTING: case SubscriptionManager.USER_HANDLE: + case SubscriptionManager.SATELLITE_ENABLED: resultValue = cursor.getString(0); break; default: diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 199d2d4f30..672efad2bc 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -233,7 +233,10 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal::getLastUsedTPMessageReference), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_USER_HANDLE, - SubscriptionInfoInternal::getUserId) + SubscriptionInfoInternal::getUserId), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_SATELLITE_ENABLED, + SubscriptionInfoInternal::getSatelliteEnabled) ); /** @@ -319,7 +322,10 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionDatabaseManager::setLastUsedTPMessageReference), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_USER_HANDLE, - SubscriptionDatabaseManager::setUserId) + SubscriptionDatabaseManager::setUserId), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_SATELLITE_ENABLED, + SubscriptionDatabaseManager::setSatelliteEnabled) ); /** @@ -1705,6 +1711,20 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal.Builder::setUserId); } + /** + * Set whether satellite is enabled or not. + * + * @param subId Subscription id. + * @param isSatelliteEnabled if satellite is enabled or not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setSatelliteEnabled(int subId, int isSatelliteEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_SATELLITE_ENABLED, + isSatelliteEnabled, + SubscriptionInfoInternal.Builder::setSatelliteEnabled); + } + /** * Load the entire database into the cache. */ @@ -1870,8 +1890,9 @@ public class SubscriptionDatabaseManager extends Handler { .setLastUsedTPMessageReference(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_TP_MESSAGE_REF))) .setUserId(cursor.getInt(cursor.getColumnIndexOrThrow( - SimInfo.COLUMN_USER_HANDLE))); - + SimInfo.COLUMN_USER_HANDLE))) + .setSatelliteEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_SATELLITE_ENABLED))); return builder.build(); } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index b0262b0271..dc79c5eb2c 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -376,6 +376,12 @@ public class SubscriptionInfoInternal { */ private final int mUserId; + /** + * Whether satellite is enabled or disabled. + * By default, its disabled. It is intended to use integer to fit the database format. + */ + private final int mIsSatelliteEnabled; + // Below are the fields that do not exist in the SimInfo table. /** * The card ID of the SIM card. This maps uniquely to {@link #mCardString}. @@ -445,6 +451,7 @@ public class SubscriptionInfoInternal { this.mUsageSetting = builder.mUsageSetting; this.mLastUsedTPMessageReference = builder.mLastUsedTPMessageReference; this.mUserId = builder.mUserId; + this.mIsSatelliteEnabled = builder.mIsSatelliteEnabled; // Below are the fields that do not exist in the SimInfo table. this.mCardId = builder.mCardId; @@ -958,6 +965,13 @@ public class SubscriptionInfoInternal { return mUserId; } + /** + * @return {@code 1} if satellite is enabled. + */ + public int getSatelliteEnabled() { + return mIsSatelliteEnabled; + } + // Below are the fields that do not exist in SimInfo table. /** * @return The card ID of the SIM card which contains the subscription. @@ -1102,6 +1116,7 @@ public class SubscriptionInfoInternal { + " numberFromCarrier=" + mNumberFromCarrier + " numberFromIms=" + mNumberFromIms + " userId=" + mUserId + + " isSatelliteEnabled=" + mIsSatelliteEnabled + " isGroupDisabled=" + mIsGroupDisabled + "]"; } @@ -1148,7 +1163,8 @@ public class SubscriptionInfoInternal { && mAllowedNetworkTypesForReasons.equals(that.mAllowedNetworkTypesForReasons) && mDeviceToDeviceStatusSharingContacts.equals( that.mDeviceToDeviceStatusSharingContacts) && mNumberFromCarrier.equals( - that.mNumberFromCarrier) && mNumberFromIms.equals(that.mNumberFromIms); + that.mNumberFromCarrier) && mNumberFromIms.equals(that.mNumberFromIms) + && mIsSatelliteEnabled == that.mIsSatelliteEnabled; } @Override @@ -1165,7 +1181,7 @@ public class SubscriptionInfoInternal { mDeviceToDeviceStatusSharingContacts, mIsNrAdvancedCallingEnabled, mNumberFromCarrier, mNumberFromIms, mPortIndex, mUsageSetting, mLastUsedTPMessageReference, mUserId, - mCardId, mIsGroupDisabled); + mIsSatelliteEnabled, mCardId, mIsGroupDisabled); result = 31 * result + Arrays.hashCode(mNativeAccessRules); result = 31 * result + Arrays.hashCode(mCarrierConfigAccessRules); result = 31 * result + Arrays.hashCode(mRcsConfig); @@ -1463,6 +1479,11 @@ public class SubscriptionInfoInternal { */ private int mUserId = UserHandle.USER_NULL; + /** + * Whether satellite is enabled or not. + */ + private int mIsSatelliteEnabled = -1; + // The following fields do not exist in the SimInfo table. /** * The card ID of the SIM card which contains the subscription. @@ -1537,6 +1558,7 @@ public class SubscriptionInfoInternal { mUsageSetting = info.mUsageSetting; mLastUsedTPMessageReference = info.getLastUsedTPMessageReference(); mUserId = info.mUserId; + mIsSatelliteEnabled = info.mIsSatelliteEnabled; // Below are the fields that do not exist in the SimInfo table. mCardId = info.mCardId; mIsGroupDisabled = info.mIsGroupDisabled; @@ -2231,6 +2253,17 @@ public class SubscriptionInfoInternal { return this; } + /** + * Set whether satellite is enabled or not. + * @param isSatelliteEnabled {@code 1} if satellite is enabled. + * @return The builder. + */ + @NonNull + public Builder setSatelliteEnabled(int isSatelliteEnabled) { + mIsSatelliteEnabled = isSatelliteEnabled; + return this; + } + // Below are the fields that do not exist in the SimInfo table. /** * Set the card ID of the SIM card which contains the subscription. diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 27007f116b..1de6aedab5 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -145,7 +145,8 @@ public class SubscriptionManagerService extends ISub.Stub { SimInfo.COLUMN_D2D_STATUS_SHARING, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS, - SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED + SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, + SimInfo.COLUMN_SATELLITE_ENABLED ); /** 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 3f3a2c650f..f49f3dbb20 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -165,6 +165,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setUsageSetting(SubscriptionManager.USAGE_SETTING_DEFAULT) .setLastUsedTPMessageReference(FAKE_TP_MESSAGE_REFERENCE1) .setUserId(FAKE_USER_ID1) + .setSatelliteEnabled(0) .setGroupDisabled(false) .build(); @@ -220,6 +221,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setUsageSetting(SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) .setLastUsedTPMessageReference(FAKE_TP_MESSAGE_REFERENCE2) .setUserId(FAKE_USER_ID2) + .setSatelliteEnabled(1) .setGroupDisabled(false) .build(); @@ -1553,6 +1555,33 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .getUserId()).isEqualTo(FAKE_USER_ID1); } + @Test + public void testUpdateSatelliteEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, () -> mDatabaseManagerUT.setSatelliteEnabled( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setSatelliteEnabled(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + 1); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setSatelliteEnabled(1).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), SimInfo.COLUMN_SATELLITE_ENABLED)) + .isEqualTo(1); + + mDatabaseManagerUT.setSubscriptionProperty(FAKE_SUBSCRIPTION_INFO1.getSubscriptionId(), + SimInfo.COLUMN_SATELLITE_ENABLED, 0); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal( + FAKE_SUBSCRIPTION_INFO1.getSubscriptionId()).getSatelliteEnabled()) + .isEqualTo(0); + } + @Test public void testUpdateSubscriptionsInGroup() throws Exception { insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java index 7c78106f3a..0b5217da5b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java @@ -88,6 +88,7 @@ public class SubscriptionInfoInternalTest { .setLastUsedTPMessageReference(SubscriptionDatabaseManagerTest .FAKE_TP_MESSAGE_REFERENCE1) .setUserId(SubscriptionDatabaseManagerTest.FAKE_USER_ID1) + .setSatelliteEnabled(1) .setGroupDisabled(false) .build(); @@ -185,6 +186,7 @@ public class SubscriptionInfoInternalTest { assertThat(mSubInfo.getLastUsedTPMessageReference()).isEqualTo( SubscriptionDatabaseManagerTest.FAKE_TP_MESSAGE_REFERENCE1); assertThat(mSubInfo.getUserId()).isEqualTo(SubscriptionDatabaseManagerTest.FAKE_USER_ID1); + assertThat(mSubInfo.getSatelliteEnabled()).isEqualTo(1); assertThat(mSubInfo.isGroupDisabled()).isFalse(); } -- GitLab From ee72fe49f642532a2052904e29fc7c95cd6d51b3 Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 5 Dec 2022 13:38:21 -0600 Subject: [PATCH 350/656] Update CarrierKeyDownloadManager with new CarrierConfigManager APIs - Replace carrier config change broadcast receiver with listener which has much lower lagency - Retrieve subset of carrier config to reduce memory consumption Bug: 263267340 Test: atest CarrierKeyDownloadMgrTest Change-Id: I713fb48214c7785c1d261bf5e837d97e0b6c39b5 --- .../telephony/CarrierKeyDownloadManager.java | 35 ++++++++++++------- .../telephony/CarrierKeyDownloadMgrTest.java | 31 +++++++++++----- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java index edf3d5ff90..beb6b2653d 100644 --- a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java +++ b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java @@ -16,8 +16,6 @@ package com.android.internal.telephony; -import static android.telephony.CarrierConfigManager.KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL; - import static java.nio.charset.StandardCharsets.UTF_8; import android.app.AlarmManager; @@ -32,7 +30,6 @@ import android.net.Uri; import android.os.Handler; import android.os.Message; import android.os.PersistableBundle; -import android.provider.Telephony; import android.telephony.CarrierConfigManager; import android.telephony.ImsiEncryptionInfo; import android.telephony.SubscriptionManager; @@ -122,13 +119,22 @@ public class CarrierKeyDownloadManager extends Handler { mPhone = phone; mContext = phone.getContext(); IntentFilter filter = new IntentFilter(); - filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(INTENT_KEY_RENEWAL_ALARM_PREFIX); filter.addAction(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD); mContext.registerReceiver(mBroadcastReceiver, filter, null, phone); mDownloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE); mTelephonyManager = mContext.getSystemService(TelephonyManager.class) .createForSubscriptionId(mPhone.getSubId()); + 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) -> { + if (slotIndex == mPhone.getPhoneId()) { + Log.d(LOG_TAG, "Carrier Config changed: slotIndex=" + slotIndex); + handleAlarmOrConfigChange(); + } + }); } private final BroadcastReceiver mDownloadReceiver = new BroadcastReceiver() { @@ -161,12 +167,6 @@ public class CarrierKeyDownloadManager extends Handler { Log.d(LOG_TAG, "Handling reset intent: " + action); sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE); } - } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - if (phoneId == intent.getIntExtra(PhoneConstants.PHONE_KEY, - SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { - Log.d(LOG_TAG, "Carrier Config changed: " + action); - sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE); - } } } }; @@ -389,14 +389,23 @@ public class CarrierKeyDownloadManager extends Handler { return false; } int subId = mPhone.getSubId(); - PersistableBundle b = carrierConfigManager.getConfigForSubId(subId); - if (b == null) { + PersistableBundle b = null; + try { + b = carrierConfigManager.getConfigForSubId(subId, + CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, + 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."); + } + if (b == null || b.isEmpty()) { return false; } + mKeyAvailability = b.getInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT); mURL = b.getString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING); mAllowedOverMeteredNetwork = b.getBoolean( - KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL); + 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 diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java index 0b7da6f2a4..40e1821dba 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java @@ -45,6 +45,7 @@ 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 java.security.PublicKey; @@ -61,6 +62,8 @@ public class CarrierKeyDownloadMgrTest extends TelephonyTest { private CarrierKeyDownloadManager mCarrierKeyDM; + private PersistableBundle mBundle; + private final String mURL = "http://www.google.com"; private static final String CERT = "-----BEGIN CERTIFICATE-----\r\nMIIFjzCCBHegAwIBAgIUPxj3SLif82Ky1RlUy8p2EWJCh8MwDQYJKoZIhvcNAQELBQAwgY0xCzAJBgNVBAYTAk5MMRIwEAYDVQQHEwlBbXN0ZXJkYW0xJTAjBgNVBAoTHFZlcml6b24gRW50ZXJwcmlzZSBTb2x1dGlvbnMxEzARBgNVBAsTCkN5YmVydHJ1c3QxLjAsBgNVBAMTJVZlcml6b24gUHVibGljIFN1cmVTZXJ2ZXIgQ0EgRzE0LVNIQTIwHhcNMTcwODE0MTc0MzM4WhcNMTkwODE0MTc0MzM4WjCBmTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFjAUBgNVBAcTDUJhc2tpbmcgUmlkZ2UxIjAgBgNVBAoTGVZlcml6b24gRGF0YSBTZXJ2aWNlcyBMTEMxHzAdBgNVBAsTFk5ldHdvcmsgU3lzdGVtIFN1cHBvcnQxGDAWBgNVBAMTD3ZpMWx2Lmltc3ZtLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALUQKWTHi4Hjpd1LQwJ87RXa0Rs3rVonvVevliqdUH5BikjhAzvIqwPSXeRQqkaRTFIyp0NKcNqGdjAaHRo43gdHeWSH331sS6CMZDg988gZznskzCqJJo6ii5FuLC8qe2YDsHxT+CefXev2rn6Bj1ei2X74uZsy5KlkBRZfFHtPdK6/EK5TpzrvcXfDyOK1rn8FTno1bQOTAhL39GPcLhdrXV7AN+lu+EBpdCqlTdcoDxsqavi/91MwUIVEzxJmycKloT6OWfU44r7+L5SYYgc88NTaGL/BvCFwHRIa1ZgYSGeAPes45792MGG7tfr/ttAGp9UEwTv2zWTxzWnRP/UCAwEAAaOCAdcwggHTMAwGA1UdEwEB/wQCMAAwTAYDVR0gBEUwQzBBBgkrBgEEAbE+ATIwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly9zZWN1cmUub21uaXJvb3QuY29tL3JlcG9zaXRvcnkwgakGCCsGAQUFBwEBBIGcMIGZMC0GCCsGAQUFBzABhiFodHRwOi8vdnBzc2cxNDIub2NzcC5vbW5pcm9vdC5jb20wMwYIKwYBBQUHMAKGJ2h0dHA6Ly9jYWNlcnQub21uaXJvb3QuY29tL3Zwc3NnMTQyLmNydDAzBggrBgEFBQcwAoYnaHR0cDovL2NhY2VydC5vbW5pcm9vdC5jb20vdnBzc2cxNDIuZGVyMBoGA1UdEQQTMBGCD3ZpMWx2Lmltc3ZtLmNvbTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFOQtu5EBZSYftHo/oxUlpM6MRDM7MD4GA1UdHwQ3MDUwM6AxoC+GLWh0dHA6Ly92cHNzZzE0Mi5jcmwub21uaXJvb3QuY29tL3Zwc3NnMTQyLmNybDAdBgNVHQ4EFgQUv5SaSyNM/yXw1v0N9TNpjsFCaPcwDQYJKoZIhvcNAQELBQADggEBACNJusTULj1KyV4RwiskKfp4wI9Hsz3ESbZS/ijF9D57BQ0UwkELU9r6rEAhsYLUvMq4sDhDbYIdupgP4MBzFnjkKult7VQm5W3nCcuHgXYFAJ9Y1a4OZAo/4hrHj70W9TsQ1ioSMjUT4F8bDUYZI0kcyH8e/+2DaTsLUpHw3L+Keu8PsJVBLnvcKJjWrZD/Bgd6JuaTX2G84i0rY0GJuO9CxLNJa6n61Mz5cqLYIuwKgiVgTA2n71YITyFICOFPFX1vSx35AWvD6aVYblxtC8mpCdF2h4s1iyrpXeji2GCJLwsNVtTtNQ4zWX3Gnq683wzkYZeyOHUyftIgAQZ+HsY=\r\n-----END CERTIFICATE-----"; @@ -83,11 +86,23 @@ public class CarrierKeyDownloadMgrTest extends TelephonyTest { "{ \"carrier-keys\": [ { \"key-identifier\": \"key1=value\", " + "\"public-key\": \"" + CERT + "\"}]}"; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; + @Before public void setUp() throws Exception { logd("CarrierActionAgentTest +Setup!"); super.setUp(getClass().getSimpleName()); + mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); + + // Capture listener to emulate the carrier config change notification used later + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); + processAllMessages(); logd("CarrierActionAgentTest -Setup!"); } @@ -322,7 +337,7 @@ public class CarrierKeyDownloadMgrTest extends TelephonyTest { } /** - * Test sending the ACTION_CARRIER_CONFIG_CHANGED intent. + * Test notifying the carrier config change from listener. * Verify that the right mnc/mcc gets stored in the preferences. **/ @Test @@ -337,16 +352,16 @@ public class CarrierKeyDownloadMgrTest extends TelephonyTest { when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); when(mTelephonyManager.getSimCarrierId()).thenReturn(1); - Intent mIntent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - mIntent.putExtra(PhoneConstants.PHONE_KEY, 0); - mContext.sendBroadcast(mIntent); + mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); assertEquals("310260", mCarrierKeyDM.mMccMncForDownload); assertEquals(1, mCarrierKeyDM.mCarrierId); } /** - * Tests sending the ACTION_CARRIER_CONFIG_CHANGED intent with an empty key. + * Tests notifying carrier config change from listener with an empty key. * Verify that the carrier keys are removed if IMSI_KEY_DOWNLOAD_URL_STRING is null. */ @Test @@ -359,9 +374,9 @@ public class CarrierKeyDownloadMgrTest extends TelephonyTest { bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3); bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, null); - Intent mIntent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - mIntent.putExtra(PhoneConstants.PHONE_KEY, 0); - mContext.sendBroadcast(mIntent); + mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); assertNull(mCarrierKeyDM.mMccMncForDownload); -- GitLab From 4badb9887b9996fac2ca0c0310421a5d16fe2cb8 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 18 Jan 2023 05:47:41 +0000 Subject: [PATCH 351/656] Change the initial value of mLastBarringInfo If the device has never camped on any network after booting, the selector doesn't receive the BarringInfo. So the domain selection stucks. With non-null initial value even in this edge case, the selector continues to work. Reset the last BarringInfo if the radio state is off or unavailable. Bug: 264601502 Test: manual Change-Id: Id6d6bf4ddad73645b071cb856d30f48339f6cac8 --- .../com/android/internal/telephony/BaseCommands.java | 10 ++++++++++ src/java/com/android/internal/telephony/RIL.java | 9 --------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java index e32101f5e9..b8de97522e 100644 --- a/src/java/com/android/internal/telephony/BaseCommands.java +++ b/src/java/com/android/internal/telephony/BaseCommands.java @@ -28,6 +28,7 @@ import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.telephony.Annotation.RadioPowerState; +import android.telephony.BarringInfo; import android.telephony.TelephonyManager; import android.telephony.emergency.EmergencyNumber; @@ -173,6 +174,8 @@ public abstract class BaseCommands implements CommandsInterface { // Cache last emergency number list indication from radio private final List mLastEmergencyNumberListIndication = new ArrayList<>(); + // The last barring information received + protected BarringInfo mLastBarringInfo = new BarringInfo(); // Preferred network type received from PhoneFactory. // This is used when establishing a connection to the // vendor ril so it starts up in the correct mode. @@ -913,6 +916,7 @@ public abstract class BaseCommands implements CommandsInterface { || mState == TelephonyManager.RADIO_POWER_UNAVAILABLE) && (oldState == TelephonyManager.RADIO_POWER_ON)) { mOffOrNotAvailRegistrants.notifyRegistrants(); + mLastBarringInfo = new BarringInfo(); } } } @@ -931,6 +935,12 @@ public abstract class BaseCommands implements CommandsInterface { } } + /** {@inheritDoc} */ + @Override + public @NonNull BarringInfo getLastBarringInfo() { + return mLastBarringInfo; + } + /** * {@inheritDoc} */ diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index fb23e8330d..c5b3032a8a 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -275,9 +275,6 @@ public class RIL extends BaseCommands implements CommandsInterface { final RilHandler mRilHandler; private MockModem mMockModem; - // The last barring information received - private BarringInfo mLastBarringInfo = null; - // Thread-safe HashMap to map from RIL_REQUEST_XXX constant to HalVersion. // This is for Radio HAL Fallback Compatibility feature. When a RIL request // is received, the HAL method from the mapping HalVersion here (if present), @@ -7178,12 +7175,6 @@ public class RIL extends BaseCommands implements CommandsInterface { mBarringInfoChangedRegistrants.notifyRegistrants(new AsyncResult(null, barringInfo, null)); } - /** {@inheritDoc} */ - @Override - public @Nullable BarringInfo getLastBarringInfo() { - return mLastBarringInfo; - } - /** * Get the HAL version with a specific service. * -- GitLab From 80b86e12c3a0efbd206d5af1ef40febdae908f5f Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Thu, 5 Jan 2023 16:37:49 +0000 Subject: [PATCH 352/656] [MEP] Handle UiccCard and UiccPort disposal when more than one port is supported. Whenever platform receives the CARDSTATE_ABSENT for any one of the UiccPort, complete UiccCard is disposed. Modified the logic to improve the behavior of Port and Card disposal. Test: Manual test on Pixel 7 and Pixel 6, atest FrameworksTelephonyTests Bug: 237562186 Change-Id: I78e231043135516c9b5f9777add52367bf16d93f --- .../telephony/uicc/UiccController.java | 8 ++ .../internal/telephony/uicc/UiccSlot.java | 76 ++++++++++++------- 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 48524ff46b..4d87a3f18c 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -1091,6 +1091,14 @@ public class UiccController extends Handler { return; } + UiccPort port = card.getUiccPort(status.mSlotPortMapping.mPortIndex); + if (port == null) { + if (DBG) log("mUiccSlots[" + slotId + "] has no UiccPort with index[" + + status.mSlotPortMapping.mPortIndex + "]. Notifying IccChangedRegistrants"); + mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null)); + return; + } + String cardString = null; boolean isEuicc = mUiccSlots[slotId].isEuicc(); if (isEuicc) { diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index a395b2f7d8..a49a7d3c24 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -43,6 +43,7 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.IccSlotStatus.MultipleEnabledProfilesMode; import com.android.internal.telephony.uicc.euicc.EuiccCard; +import com.android.internal.telephony.util.ArrayUtils; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -80,7 +81,6 @@ public class UiccSlot extends Handler { private final Object mLock = new Object(); private boolean mActive; private boolean mStateIsUnknown = true; - private CardState mCardState; private Context mContext; private UiccCard mUiccCard; private boolean mIsEuicc; @@ -96,6 +96,9 @@ public class UiccSlot extends Handler { private HashMap mLastRadioState = new HashMap<>(); // Store iccId of each port. private HashMap mIccIds = new HashMap<>(); + // IccCardStatus and IccSlotStatus events order is not guaranteed. Inorder to handle MEP mode, + // map each available portIdx with CardState for card state checking + private HashMap mCardState = new HashMap<>(); private static final int EVENT_CARD_REMOVED = 13; private static final int EVENT_CARD_ADDED = 14; @@ -104,7 +107,6 @@ public class UiccSlot extends Handler { if (DBG) log("Creating"); mContext = c; mActive = isActive; - mCardState = null; mSupportedMepMode = MultipleEnabledProfilesMode.NONE; } @@ -114,8 +116,8 @@ public class UiccSlot extends Handler { public void update(CommandsInterface ci, IccCardStatus ics, int phoneId, int slotIndex) { synchronized (mLock) { mPortIdxToPhoneId.put(ics.mSlotPortMapping.mPortIndex, phoneId); - CardState oldState = mCardState; - mCardState = ics.mCardState; + CardState oldState = mCardState.get(ics.mSlotPortMapping.mPortIndex); + mCardState.put(ics.mSlotPortMapping.mPortIndex, ics.mCardState); mIccIds.put(ics.mSlotPortMapping.mPortIndex, ics.iccid); parseAtr(ics.atr); mIsRemovable = isSlotRemovable(slotIndex); @@ -129,7 +131,7 @@ public class UiccSlot extends Handler { log("update: radioState=" + radioState + " mLastRadioState=" + mLastRadioState); } - if (absentStateUpdateNeeded(oldState)) { + if (absentStateUpdateNeeded(oldState, ics.mSlotPortMapping.mPortIndex)) { updateCardStateAbsent(ci.getRadioState(), phoneId, ics.mSlotPortMapping.mPortIndex); // Because mUiccCard may be updated in both IccCardStatus and IccSlotStatus, we need to @@ -137,7 +139,8 @@ public class UiccSlot extends Handler { // 1. mCardState is changing from ABSENT to non ABSENT. // 2. The latest mCardState is not ABSENT, but there is no UiccCard instance. } else if ((oldState == null || oldState == CardState.CARDSTATE_ABSENT - || mUiccCard == null) && mCardState != CardState.CARDSTATE_ABSENT) { + || mUiccCard == null) && mCardState.get(ics.mSlotPortMapping.mPortIndex) + != CardState.CARDSTATE_ABSENT) { // No notification while we are just powering up if (radioState != TelephonyManager.RADIO_POWER_UNAVAILABLE && mLastRadioState.getOrDefault(ics.mSlotPortMapping.mPortIndex, @@ -148,9 +151,11 @@ public class UiccSlot extends Handler { } // card is present in the slot now; create new mUiccCard - if (mUiccCard != null) { + if (mUiccCard != null && (!mIsEuicc + || ArrayUtils.isEmpty(mUiccCard.getUiccPortList()))) { loge("update: mUiccCard != null when card was present; disposing it now"); mUiccCard.dispose(); + mUiccCard = null; } if (!mIsEuicc) { @@ -164,8 +169,14 @@ public class UiccSlot extends Handler { loge("update: eid is missing. ics.eid=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, ics.eid)); } - mUiccCard = new EuiccCard(mContext, ci, ics, phoneId, mLock, - isMultipleEnabledProfileSupported(), getSupportedMepMode()); + if (mUiccCard == null) { + mUiccCard = new EuiccCard(mContext, ci, ics, phoneId, mLock, + isMultipleEnabledProfileSupported(), getSupportedMepMode()); + } else { + // In MEP case, UiccCard instance is already created, just call update API. + // UiccPort initialization is handled inside UiccCard. + mUiccCard.update(mContext, ci, ics, phoneId); + } } } else { if (mUiccCard != null) { @@ -182,15 +193,15 @@ public class UiccSlot extends Handler { public void update(CommandsInterface[] ci, IccSlotStatus iss, int slotIndex) { synchronized (mLock) { IccSimPortInfo[] simPortInfos = iss.mSimPortInfos; - CardState oldState = mCardState; parseAtr(iss.atr); - mCardState = iss.cardState; mEid = iss.eid; mIsRemovable = isSlotRemovable(slotIndex); mSupportedMepMode = iss.mSupportedMepMode; for (int i = 0; i < simPortInfos.length; i++) { int phoneId = iss.mSimPortInfos[i].mLogicalSlotIndex; + CardState oldState = mCardState.get(i); + mCardState.put(i, iss.cardState); mIccIds.put(i, simPortInfos[i].mIccId); if (!iss.mSimPortInfos[i].mPortActive) { // TODO: (b/79432584) evaluate whether should broadcast card state change @@ -210,7 +221,7 @@ public class UiccSlot extends Handler { mUiccCard.disposePort(i); } } else { - if (absentStateUpdateNeeded(oldState)) { + if (absentStateUpdateNeeded(oldState, i)) { int radioState = SubscriptionManager.isValidPhoneId(phoneId) ? ci[phoneId].getRadioState() : TelephonyManager.RADIO_POWER_UNAVAILABLE; @@ -322,9 +333,9 @@ public class UiccSlot extends Handler { mAtr.isMultipleEnabledProfilesSupported(); } - private boolean absentStateUpdateNeeded(CardState oldState) { + private boolean absentStateUpdateNeeded(CardState oldState, int portIndex) { return (oldState != CardState.CARDSTATE_ABSENT || mUiccCard != null) - && mCardState == CardState.CARDSTATE_ABSENT; + && mCardState.get(portIndex) == CardState.CARDSTATE_ABSENT; } private void updateCardStateAbsent(int radioState, int phoneId, int portIndex) { @@ -344,8 +355,8 @@ public class UiccSlot extends Handler { UiccController.updateInternalIccState(mContext, IccCardConstants.State.ABSENT, null, phoneId); } - // no card present in the slot now; dispose card and make mUiccCard null - nullifyUiccCard(false /* sim state is not unknown */); + // no card present in the slot now; dispose port and then card if needed. + disposeUiccCardIfNeeded(false /* sim state is not unknown */, portIndex); mLastRadioState.put(portIndex, TelephonyManager.RADIO_POWER_UNAVAILABLE); } @@ -360,8 +371,21 @@ public class UiccSlot extends Handler { mUiccCard = null; } + private void disposeUiccCardIfNeeded(boolean isStateUnknown, int portIndex) { + // First dispose UiccPort corresponding to the portIndex + if (mUiccCard != null) { + mUiccCard.disposePort(portIndex); + if (ArrayUtils.isEmpty(mUiccCard.getUiccPortList())) { + // No UiccPort objects are found, safe to dispose the card + nullifyUiccCard(isStateUnknown); + } + } + } + public boolean isStateUnknown() { - if (mCardState == null || mCardState == CardState.CARDSTATE_ABSENT) { + // CardState is not specific to any port index, use default port. + CardState cardState = mCardState.get(TelephonyManager.DEFAULT_PORT_INDEX); + if (cardState == null || cardState == CardState.CARDSTATE_ABSENT) { // mStateIsUnknown is valid only in this scenario. return mStateIsUnknown; } @@ -572,11 +596,9 @@ public class UiccSlot extends Handler { */ public CardState getCardState() { synchronized (mLock) { - if (mCardState == null) { - return CardState.CARDSTATE_ABSENT; - } else { - return mCardState; - } + // CardState is not specific to any port index, use default port. + CardState cardState = mCardState.get(TelephonyManager.DEFAULT_PORT_INDEX); + return cardState == null ? CardState.CARDSTATE_ABSENT : cardState; } } @@ -601,7 +623,8 @@ public class UiccSlot extends Handler { * Processes radio state unavailable event */ public void onRadioStateUnavailable(int phoneId) { - nullifyUiccCard(true /* sim state is unknown */); + int portIndex = getPortIndexFromPhoneId(phoneId); + disposeUiccCardIfNeeded(true /* sim state is unknown */, portIndex); if (phoneId != INVALID_PHONE_ID) { if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { @@ -611,11 +634,10 @@ public class UiccSlot extends Handler { UiccController.updateInternalIccState( mContext, IccCardConstants.State.UNKNOWN, null, phoneId); } - mLastRadioState.put(getPortIndexFromPhoneId(phoneId), - TelephonyManager.RADIO_POWER_UNAVAILABLE); } - - mCardState = null; + mLastRadioState.put(portIndex, TelephonyManager.RADIO_POWER_UNAVAILABLE); + // Reset CardState + mCardState.put(portIndex, null); } private void log(String msg) { -- GitLab From 90daad0363c29b82fd902305e574f84a6011dccb Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Tue, 17 Jan 2023 02:43:28 +0000 Subject: [PATCH 353/656] Notify CallAttributeListener IMS call type change Fix to notify CallAttributesListener when IMS call type changed. Bug: 265610260 Test: device test. VZW TC VoWiFi 5.15 Change-Id: I5359edc5405b61735ab1473caefe2f5a64d8c7a7 --- .../android/internal/telephony/imsphone/ImsPhoneBase.java | 4 ++++ .../internal/telephony/imsphone/ImsPhoneCallTracker.java | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index 1426ac84d3..8a1041dec3 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -201,6 +201,10 @@ abstract class ImsPhoneBase extends Phone { AsyncResult ar = new AsyncResult(null, this, null); mPreciseCallStateRegistrants.notifyRegistrants(ar); + notifyPreciseCallStateToNotifier(); + } + + public void notifyPreciseCallStateToNotifier() { ImsPhoneCall ringingCall = (ImsPhoneCall) getRingingCall(); ImsPhoneCall foregroundCall = (ImsPhoneCall) getForegroundCall(); ImsPhoneCall backgroundCall = (ImsPhoneCall) getBackgroundCall(); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 6840f4be83..99423e3e12 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -3048,6 +3048,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { conn.maybeChangeRingbackState(); maybeSetVideoCallProvider(conn, imsCall); + // IMS call profile might be changed while call state is maintained. In this case, it's + // required to notify to CallAttributesListener. + // Since call state is not changed, TelephonyRegistry will not notify to + // PreciseCallStateListener. + mPhone.notifyPreciseCallStateToNotifier(); return; } -- GitLab From dec5fc0b22c663c936ac296775f73574fd525e3c Mon Sep 17 00:00:00 2001 From: Avinash Malipatil Date: Tue, 17 Jan 2023 06:54:35 +0000 Subject: [PATCH 354/656] Add method to check if dialed number is for WPS calls. Bug: 262006376 Test: Manual testing. Test tracker details in bug. Change-Id: Ic8ec475c1578fad11cf1138ff5d4a562f011a29b --- .../NormalCallDomainSelectionConnection.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java index 516d6b9b89..e157d24f37 100644 --- a/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnection.java @@ -38,6 +38,15 @@ public class NormalCallDomainSelectionConnection extends DomainSelectionConnecti private static final boolean DBG = false; + private static final String PREFIX_WPS = "*272"; + + // WPS prefix when CLIR is being activated for the call. + private static final String PREFIX_WPS_CLIR_ACTIVATE = "*31#*272"; + + // WPS prefix when CLIR is being deactivated for the call. + private static final String PREFIX_WPS_CLIR_DEACTIVATE = "#31#*272"; + + private @Nullable DomainSelectionConnectionCallback mCallback; /** @@ -123,4 +132,15 @@ public class NormalCallDomainSelectionConnection extends DomainSelectionConnecti } return builder.build(); } + + /** + * Check if the call is Wireless Priority Service call + * @param dialString The number being dialed. + * @return {@code true} if dialString matches WPS pattern and {@code false} otherwise. + */ + public static boolean isWpsCall(String dialString) { + return (dialString != null) && (dialString.startsWith(PREFIX_WPS) + || dialString.startsWith(PREFIX_WPS_CLIR_ACTIVATE) + || dialString.startsWith(PREFIX_WPS_CLIR_DEACTIVATE)); + } } -- GitLab From f00ca988c85f9ad030752326efe8b9482bd10e75 Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 5 Dec 2022 17:38:43 -0600 Subject: [PATCH 355/656] Update DataServiceManager with new CarrierConfigManager APIs Improve performance of DataServiceManager by: - Replacing carrier config change broadcast receiver with listener - Retrieving subset of carrier config to save memory Bug: 263267340 Test: atest DataServiceManagerTest Change-Id: Ie4ec6290488ba3c3b59dff2b917462f17aca0059 --- .../telephony/data/DataServiceManager.java | 61 ++++++++----------- .../data/DataNetworkControllerTest.java | 7 ++- .../data/DataServiceManagerTest.java | 6 ++ 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataServiceManager.java b/src/java/com/android/internal/telephony/data/DataServiceManager.java index 9f4615d7c2..957b703a90 100644 --- a/src/java/com/android/internal/telephony/data/DataServiceManager.java +++ b/src/java/com/android/internal/telephony/data/DataServiceManager.java @@ -22,11 +22,9 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -121,22 +119,6 @@ public class DataServiceManager extends Handler { private List mLastDataCallResponseList = Collections.EMPTY_LIST; - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) - && mPhone.getPhoneId() == intent.getIntExtra( - CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) { - // 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."); - sendEmptyMessage(EVENT_BIND_DATA_SERVICE); - } - } - }; - private class DataServiceManagerDeathRecipient implements IBinder.DeathRecipient { @Override public void binderDied() { @@ -409,16 +391,18 @@ public class DataServiceManager extends Handler { Context.LEGACY_PERMISSION_SERVICE); mAppOps = (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE); - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - try { - Context contextAsUser = phone.getContext().createPackageContextAsUser( - phone.getContext().getPackageName(), 0, UserHandle.ALL); - contextAsUser.registerReceiver(mBroadcastReceiver, intentFilter, - null /* broadcastPermission */, null); - } catch (PackageManager.NameNotFoundException e) { - loge("Package name not found: " + e.getMessage()); - } + // 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(); + } + }); + PhoneConfigurationManager.registerForMultiSimConfigChange( this, EVENT_BIND_DATA_SERVICE, null); @@ -587,9 +571,8 @@ public class DataServiceManager extends Handler { // Read package name from resource overlay packageName = mPhone.getContext().getResources().getString(resourceId); - PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { + PersistableBundle b = getCarrierConfigSubset(carrierConfig); + if (!b.isEmpty() && !TextUtils.isEmpty(b.getString(carrierConfig))) { // If carrier config overrides it, use the one from carrier config packageName = b.getString(carrierConfig, packageName); } @@ -636,9 +619,8 @@ public class DataServiceManager extends Handler { // Read package name from resource overlay className = mPhone.getContext().getResources().getString(resourceId); - PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { + PersistableBundle b = getCarrierConfigSubset(carrierConfig); + if (!b.isEmpty() && !TextUtils.isEmpty(b.getString(carrierConfig))) { // If carrier config overrides it, use the one from carrier config className = b.getString(carrierConfig, className); } @@ -646,6 +628,17 @@ public class DataServiceManager extends Handler { return className; } + @NonNull + private PersistableBundle getCarrierConfigSubset(String key) { + PersistableBundle configs = new PersistableBundle(); + try { + configs = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), key); + } catch (RuntimeException e) { + loge("CarrierConfigLoader is not available."); + } + return configs; + } + private void sendCompleteMessage(Message msg, @DataServiceCallback.ResultCode int code) { if (msg != null) { msg.arg1 = code; 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 cd50dfb2fb..701817c25e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -634,6 +634,7 @@ public class DataNetworkControllerTest extends TelephonyTest { private void initializeConfig() { mCarrierConfig = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mCarrierConfig); mCarrierConfig.putStringArray( CarrierConfigManager.KEY_TELEPHONY_NETWORK_CAPABILITY_PRIORITIES_STRING_ARRAY, new String[]{ @@ -788,9 +789,11 @@ public class DataNetworkControllerTest extends TelephonyTest { // between DataNetworkController and its sub-modules, we intend to make those modules "real" // as well, except some modules below we replaced with mocks. mDataNetworkControllerUT = new DataNetworkController(mPhone, Looper.myLooper()); - verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + // First two come from DataServiceManager and the third comes from DataConfigManager which + // is what we want to capture and assign to mCarrierConfigChangeListener + verify(mCarrierConfigManager, times(3)).registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); - mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(2); assertThat(mCarrierConfigChangeListener).isNotNull(); doReturn(mDataNetworkControllerUT).when(mPhone).getDataNetworkController(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataServiceManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataServiceManagerTest.java index e636f65903..88f642bd85 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataServiceManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataServiceManagerTest.java @@ -25,12 +25,14 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.IntentFilter; import android.content.pm.ServiceInfo; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.TelephonyManager; @@ -89,15 +91,19 @@ public class DataServiceManagerTest extends TelephonyTest { private Handler mHandler; private Handler mDataServiceHandler; + private PersistableBundle mBundle; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); } @After public void tearDown() throws Exception { mDataServiceManagerUT = null; + mBundle = null; super.tearDown(); } -- GitLab From 6cecf339e4ce546b27452f27227c07cab4ba6e58 Mon Sep 17 00:00:00 2001 From: Daniel Banta Date: Fri, 14 Oct 2022 01:26:54 +0000 Subject: [PATCH 356/656] [EmergencyStateTracker] Enter/Exit Emergency Callback Mode and Notify Listeners Bug: 247639718 Change-Id: I43fbf421a0f3e695e1f8705c5b84c882f01686d5 --- .../telephony/GsmCdmaCallTracker.java | 27 +- .../internal/telephony/GsmCdmaPhone.java | 14 +- .../com/android/internal/telephony/Phone.java | 11 + .../emergency/EmergencyStateTracker.java | 259 ++++++++++++++++-- .../internal/telephony/imsphone/ImsPhone.java | 6 + .../imsphone/ImsPhoneCallTracker.java | 15 + .../internal/telephony/GsmCdmaPhoneTest.java | 3 + .../emergency/EmergencyStateTrackerTest.java | 172 ++++++++++-- 8 files changed, 457 insertions(+), 50 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java index 263bfebc15..08561d75a0 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java +++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java @@ -45,6 +45,8 @@ import android.util.EventLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.PhoneInternalInterface.DialArgs; import com.android.internal.telephony.cdma.CdmaCallWaitingNotification; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; +import com.android.internal.telephony.emergency.EmergencyStateTracker; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.telephony.Rlog; @@ -480,16 +482,29 @@ public class GsmCdmaCallTracker extends CallTracker { disableDataCallInEmergencyCall(dialString); // In Ecm mode, if another emergency call is dialed, Ecm mode will not exit. - if(!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) { + if (!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) { mCi.dial(mPendingMO.getAddress(), mPendingMO.isEmergencyCall(), mPendingMO.getEmergencyNumberInfo(), - mPendingMO.hasKnownUserIntentEmergency(), - clirMode, obtainCompleteMessage()); + mPendingMO.hasKnownUserIntentEmergency(), clirMode, + obtainCompleteMessage()); + } else if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + mPendingCallInEcm = true; + final int finalClirMode = clirMode; + Runnable onComplete = new Runnable() { + @Override + public void run() { + mCi.dial(mPendingMO.getAddress(), mPendingMO.isEmergencyCall(), + mPendingMO.getEmergencyNumberInfo(), + mPendingMO.hasKnownUserIntentEmergency(), finalClirMode, + obtainCompleteMessage()); + } + }; + EmergencyStateTracker.getInstance().exitEmergencyCallbackMode(onComplete); } else { mPhone.exitEmergencyCallbackMode(); - mPhone.setOnEcbModeExitResponse(this,EVENT_EXIT_ECM_RESPONSE_CDMA, null); - mPendingCallClirMode=clirMode; - mPendingCallInEcm=true; + mPhone.setOnEcbModeExitResponse(this, EVENT_EXIT_ECM_RESPONSE_CDMA, null); + mPendingCallClirMode = clirMode; + mPendingCallInEcm = true; } } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index b22176bc76..76614f3dfb 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -98,7 +98,9 @@ import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.LinkBandwidthEstimator; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyNumberTracker; +import com.android.internal.telephony.emergency.EmergencyStateTracker; import com.android.internal.telephony.gsm.GsmMmiCode; import com.android.internal.telephony.gsm.SsData; import com.android.internal.telephony.gsm.SuppServiceNotification; @@ -1512,10 +1514,13 @@ public class GsmCdmaPhone extends Phone { } if (DBG) logd("Trying (non-IMS) CS call"); if (isDialedNumberSwapped && isEmergency) { - // Triggers ECM when CS call ends only for test emergency calls using - // ril.test.emergencynumber. - mIsTestingEmergencyCallbackMode = true; - mCi.testingEmergencyCall(); + // If domain selection is enabled, ECM testing is handled in EmergencyStateTracker + if (!DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + // Triggers ECM when CS call ends only for test emergency calls using + // ril.test.emergencynumber. + mIsTestingEmergencyCallbackMode = true; + mCi.testingEmergencyCall(); + } } chosenPhoneConsumer.accept(this); @@ -3909,6 +3914,7 @@ public class GsmCdmaPhone extends Phone { * otherwise, restart Ecm timer and notify apps the timer is restarted. */ public void handleTimerInEmergencyCallbackMode(int action) { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) return; switch(action) { case CANCEL_ECM_TIMER: removeCallbacks(mExitEcmRunnable); diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index a69e71ec30..da6382272b 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -87,8 +87,10 @@ import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.data.LinkBandwidthEstimator; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyConstants; import com.android.internal.telephony.emergency.EmergencyNumberTracker; +import com.android.internal.telephony.emergency.EmergencyStateTracker; import com.android.internal.telephony.imsphone.ImsCallInfo; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; @@ -2981,6 +2983,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // This property is used to handle phone process crashes, and is the same for CDMA and IMS // phones protected static boolean getInEcmMode() { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + return EmergencyStateTracker.getInstance().isInEcm(); + } return TelephonyProperties.in_ecm_mode().orElse(false); } @@ -2990,6 +2995,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * emergency operator. */ public boolean isInEcm() { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + return EmergencyStateTracker.getInstance().isInEcm(); + } return mIsPhoneInEcmState; } @@ -2998,6 +3006,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } public boolean isInCdmaEcm() { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + return EmergencyStateTracker.getInstance().isInCdmaEcm(); + } return getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA && isInEcm() && (mImsPhone == null || !mImsPhone.isInImsEcm()); } diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java index b4f4554775..a5da97e62a 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java @@ -16,29 +16,41 @@ package com.android.internal.telephony.emergency; +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_NONE; +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; import android.annotation.NonNull; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.PowerManager; +import android.os.UserHandle; import android.provider.Settings; +import android.sysprop.TelephonyProperties; import android.telephony.CarrierConfigManager; import android.telephony.DisconnectCause; import android.telephony.EmergencyRegResult; import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.emergency.EmergencyNumber; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Call; +import com.android.internal.telephony.GsmCdmaPhone; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RIL; +import com.android.internal.telephony.TelephonyCapabilities; +import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.telephony.Rlog; @@ -56,9 +68,16 @@ public class EmergencyStateTracker { private static final String TAG = "EmergencyStateTracker"; - // Timeout before we continue with the emergency call without waiting for DDS switch response - // from the modem. + /** + * Timeout before we continue with the emergency call without waiting for DDS switch response + * from the modem. + */ private static final int DEFAULT_DATA_SWITCH_TIMEOUT_MS = 1000; + /** Default value for if Emergency Callback Mode is supported. */ + private static final boolean DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED = true; + /** Default Emergency Callback Mode exit timeout value. */ + private static final long DEFAULT_ECM_EXIT_TIMEOUT_MS = 300000; + public long defaultEcmExitTimeoutMs = DEFAULT_ECM_EXIT_TIMEOUT_MS; private static EmergencyStateTracker INSTANCE = null; @@ -72,8 +91,40 @@ public class EmergencyStateTracker { private Set mActiveEmergencyCalls = new HashSet(); private boolean mIsSuplDdsSwitchRequiredForEmergencyCall; private EmergencyRegResult mLastEmergencyRegResult; - private boolean mIsInEmergencyCall; - private boolean mIsTestEmergencyNumber; + private boolean mIsInEmergencyCall = false; + private boolean mIsTestEmergencyNumber = false; + private boolean mIsPhoneInEcmState = false; + private PowerManager.WakeLock mWakeLock; + private Runnable mOnEcmExitCompleteRunnable = null; + + // A runnable which is used to automatically exit from Ecm after a period of time. + private Runnable mExitEcmRunnable = new Runnable() { + @Override + public void run() { + exitEmergencyCallbackMode(); + } + }; + + /** + * Listens for Emergency Callback Mode state change intents + */ + private BroadcastReceiver mEcmExitReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals( + TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { + + boolean isInEcm = intent.getBooleanExtra( + TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false); + Rlog.d(TAG, "Received ACTION_EMERGENCY_CALLBACK_MODE_CHANGED isInEcm = " + isInEcm); + + // If we exit ECM mode, notify all connections. + if (!isInEcm) { + exitEmergencyCallbackMode(); + } + } + } + }; /** PhoneFactory Dependencies for testing. */ @VisibleForTesting @@ -138,8 +189,10 @@ public class EmergencyStateTracker { public static final int MSG_SET_EMERGENCY_MODE_DONE = 1; @VisibleForTesting public static final int MSG_EXIT_EMERGENCY_MODE_DONE = 2; + @VisibleForTesting + public static final int MSG_SET_EMERGENCY_CALLBACK_MODE_DONE = 3; - private final class MyHandler extends Handler { + private class MyHandler extends Handler { MyHandler(Looper looper) { super(looper); @@ -166,6 +219,14 @@ public class EmergencyStateTracker { case MSG_EXIT_EMERGENCY_MODE_DONE: Rlog.v(TAG, "MSG_EXIT_EMERGENCY_MODE_DONE"); setIsInEmergencyCall(false); + if (mOnEcmExitCompleteRunnable != null) { + mOnEcmExitCompleteRunnable.run(); + mOnEcmExitCompleteRunnable = null; + } + break; + + case MSG_SET_EMERGENCY_CALLBACK_MODE_DONE: + Rlog.v(TAG, "MSG_SET_EMERGENCY_CALLBACK_MODE_DONE"); break; default: @@ -208,6 +269,14 @@ public class EmergencyStateTracker { mContext = context; mHandler = new MyHandler(looper); mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall; + + PowerManager pm = context.getSystemService(PowerManager.class); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + + // Register receiver for ECM exit. + IntentFilter filter = new IntentFilter(); + filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); + context.registerReceiver(mEcmExitReceiver, filter); mTelephonyManagerProxy = new TelephonyManagerProxyImpl(context); } @@ -228,7 +297,7 @@ public class EmergencyStateTracker { public EmergencyStateTracker(Context context, Looper looper, boolean isSuplDdsSwitchRequiredForEmergencyCall, PhoneFactoryProxy phoneFactoryProxy, PhoneSwitcherProxy phoneSwitcherProxy, TelephonyManagerProxy telephonyManagerProxy, - RadioOnHelper radioOnHelper) { + RadioOnHelper radioOnHelper, long ecmExitTimeoutMs) { mContext = context; mHandler = new MyHandler(looper); mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall; @@ -236,6 +305,12 @@ public class EmergencyStateTracker { mPhoneSwitcherProxy = phoneSwitcherProxy; mTelephonyManagerProxy = telephonyManagerProxy; mRadioOnHelper = radioOnHelper; + defaultEcmExitTimeoutMs = ecmExitTimeoutMs; + PowerManager pm = context.getSystemService(PowerManager.class); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + IntentFilter filter = new IntentFilter(); + filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); + context.registerReceiver(mEcmExitReceiver, filter); } /** @@ -281,7 +356,8 @@ public class EmergencyStateTracker { // Could not turn radio on Rlog.e(TAG, "Failed to turn on radio."); mOnCompleted.complete(DisconnectCause.POWER_OFF); - mPhone = null; + // If call setup fails, then move to MODE_EMERGENCY_NONE. + exitEmergencyMode(); } else { delayDialAndSetEmergencyMode(phone); } @@ -315,16 +391,17 @@ public class EmergencyStateTracker { // only API that can receive it before starting domain selection. Once domain selection // is finished, the actual emergency mode will be set when onEmergencyTransportChanged() // is called. - setEmergencyMode(MODE_EMERGENCY_WWAN); + setEmergencyMode(MODE_EMERGENCY_WWAN, MSG_SET_EMERGENCY_MODE_DONE); }); } /** * Triggers modem to set new emergency mode. * - * @param mode the new emergency mode + * @param mode the new emergency mode. + * @param msg the message to be sent once mode has been set. */ - private void setEmergencyMode(@EmergencyConstants.EmergencyMode int mode) { + private void setEmergencyMode(@EmergencyConstants.EmergencyMode int mode, int msg) { Rlog.i(TAG, "setEmergencyMode from " + mEmergencyMode + " to " + mode); if (mEmergencyMode == mode) { @@ -336,7 +413,7 @@ public class EmergencyStateTracker { Rlog.d(TAG, "IsTestEmergencyNumber true. Skipping setting emergency mode on modem."); return; } - mPhone.setEmergencyMode(mode, mHandler.obtainMessage(MSG_SET_EMERGENCY_MODE_DONE)); + mPhone.setEmergencyMode(mode, mHandler.obtainMessage(msg)); } /** @@ -363,20 +440,30 @@ public class EmergencyStateTracker { private void exitEmergencyMode() { Rlog.i(TAG, "exitEmergencyMode"); - mEmergencyMode = MODE_EMERGENCY_NONE; - - mPhone.exitEmergencyMode(mHandler.obtainMessage(MSG_EXIT_EMERGENCY_MODE_DONE)); + if (mEmergencyMode != MODE_EMERGENCY_NONE) { + mEmergencyMode = MODE_EMERGENCY_NONE; + mPhone.exitEmergencyMode(mHandler.obtainMessage(MSG_EXIT_EMERGENCY_MODE_DONE)); + } + mPhone = null; } /** * Ends emergency call. * + *

+ * Enter ECM only once all active emergency calls have ended. If a call never reached + * {@link Call.State.ACTIVE}, then no need to enter ECM. + * * @param callId the call id on which to end the emergency call. */ public void endCall(String callId) { - mActiveEmergencyCalls.remove(callId); - exitEmergencyMode(); - mPhone = null; + boolean wasActive = mActiveEmergencyCalls.remove(callId); + if ((wasActive && emergencyCallbackModeSupported() && mActiveEmergencyCalls.isEmpty()) + || mIsTestEmergencyNumber) { + enterEmergencyCallbackMode(); + } else { + exitEmergencyMode(); + } } /** Returns last {@link EmergencyRegResult} as set by {@code setEmergencyMode()}. */ @@ -390,7 +477,7 @@ public class EmergencyStateTracker { * @param mode the new emergency mode */ public void onEmergencyTransportChanged(@EmergencyConstants.EmergencyMode int mode) { - setEmergencyMode(mode); + setEmergencyMode(mode, MSG_SET_EMERGENCY_MODE_DONE); } /** @@ -405,7 +492,137 @@ public class EmergencyStateTracker { } } - /** Returns {@code true} if any phones from PhoneFactory have radio on. */ + /** + * Returns {@code true} if device and carrier support emergency callback mode. + */ + private boolean emergencyCallbackModeSupported() { + // Check Carrier Configs if ECM is enabled. + CarrierConfigManager cfgManager = (CarrierConfigManager) mPhone.getContext() + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (cfgManager == null) { + // If CarrierConfigManager is unavailable, return default value for ECM. + Rlog.w(TAG, "emergencyCallbackModeSupported: couldn't get CarrierConfigManager"); + return DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED; + } + + return cfgManager.getConfigForSubId(mPhone.getSubId()).getBoolean( + CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL); + } + + /** + * Trigger entry into emergency callback mode. + */ + private void enterEmergencyCallbackMode() { + setIsInEmergencyCall(false); + // Check if not in ECM already. + if (!isInEcm()) { + setIsInEcm(true); + if (!mPhone.getUnitTestMode()) { + TelephonyProperties.in_ecm_mode(true); + } + + // Notify listeners of the entrance to ECM. + sendEmergencyCallbackModeChange(); + if (mPhone.getImsPhone() != null) { + ((GsmCdmaPhone) mPhone).notifyEmergencyCallRegistrants(true); + } + + // Set emergency mode on modem. + setEmergencyMode(MODE_EMERGENCY_CALLBACK, MSG_SET_EMERGENCY_CALLBACK_MODE_DONE); + + // Post this runnable so we will automatically exit if no one invokes + // exitEmergencyCallbackMode() directly. + long delayInMillis = TelephonyProperties.ecm_exit_timer() + .orElse(defaultEcmExitTimeoutMs); + mHandler.postDelayed(mExitEcmRunnable, delayInMillis); + + // We don't want to go to sleep while in ECM. + mWakeLock.acquire(); + } + } + + /** + * Exits emergency callback mode and notifies relevant listeners. + */ + public void exitEmergencyCallbackMode() { + // Remove pending exit ECM runnable, if any. + mHandler.removeCallbacks(mExitEcmRunnable); + + if (isInEcm()) { + setIsInEcm(false); + if (!mPhone.getUnitTestMode()) { + TelephonyProperties.in_ecm_mode(false); + } + + // Release wakeLock. + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } + + // Send intents that ECM has changed. + sendEmergencyCallbackModeChange(); + ((GsmCdmaPhone) mPhone).notifyEmergencyCallRegistrants(false); + + // Exit emergency mode on modem. + exitEmergencyMode(); + } + } + + /** + * Exits emergency callback mode and triggers runnable after exit response is received. + */ + public void exitEmergencyCallbackMode(Runnable onComplete) { + mOnEcmExitCompleteRunnable = onComplete; + exitEmergencyCallbackMode(); + } + + /** + * Sends intents that emergency callback mode changed. + */ + private void sendEmergencyCallbackModeChange() { + Rlog.d(TAG, "sendEmergencyCallbackModeChange: isInEcm=" + isInEcm()); + + Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); + intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, isInEcm()); + SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + } + + /** + * Returns {@code true} if currently in emergency callback mode. + * + *

+ * This is a period where the phone should be using as little power as possible and be ready to + * receive an incoming call from the emergency operator. + */ + public boolean isInEcm() { + return mIsPhoneInEcmState; + } + + /** + * Sets the emergency callback mode state. + */ + private void setIsInEcm(boolean isInEcm) { + mIsPhoneInEcmState = isInEcm; + } + + /** + * Returns {@code true} if currently in emergency callback mode with an ImsPhone. + */ + public boolean isInImsEcm() { + return mPhone.getImsPhone() != null && isInEcm(); + } + + /** + * Returns {@code true} if currently in emergency callback mode with an ImsPhone. + */ + public boolean isInCdmaEcm() { + return mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA && isInEcm(); + } + + /** + * Returns {@code true} if any phones from PhoneFactory have radio on. + */ private boolean isRadioOn() { boolean result = false; for (Phone phone : mPhoneFactoryProxy.getPhones()) { @@ -414,7 +631,9 @@ public class EmergencyStateTracker { return result; } - /** Returns {@code true} if airplane mode is on. */ + /** + * Returns {@code true} if airplane mode is on. + */ private boolean isAirplaneModeOn(Context context) { return Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) > 0; diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 31190a0d93..282cc388cf 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -120,7 +120,9 @@ import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyComponentFactory; import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyNumberTracker; +import com.android.internal.telephony.emergency.EmergencyStateTracker; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.metrics.ImsStats; import com.android.internal.telephony.metrics.TelephonyMetrics; @@ -908,6 +910,9 @@ public class ImsPhone extends ImsPhoneBase { @Override public boolean isInImsEcm() { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + return EmergencyStateTracker.getInstance().isInImsEcm(); + } return mIsInImsEcm; } @@ -2104,6 +2109,7 @@ public class ImsPhone extends ImsPhoneBase { * Ecm timer and notify apps the timer is restarted. */ void handleTimerInEmergencyCallbackMode(int action) { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) return; switch (action) { case CANCEL_ECM_TIMER: removeCallbacks(mExitEcmRunnable); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 6840f4be83..8caee65a1e 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -146,7 +146,9 @@ import com.android.internal.telephony.SrvccConnection; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.d2d.RtpTransport; import com.android.internal.telephony.data.DataSettingsManager; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyNumberTracker; +import com.android.internal.telephony.emergency.EmergencyStateTracker; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.imsphone.ImsPhone.ImsDialArgs; import com.android.internal.telephony.metrics.CallQualityMetrics; @@ -1730,9 +1732,22 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { addConnection(mPendingMO); if (!holdBeforeDial) { + // In Ecm mode, if another emergency call is dialed, Ecm mode will not exit. if ((!isPhoneInEcmMode) || (isPhoneInEcmMode && isEmergencyNumber)) { dialInternal(mPendingMO, clirMode, videoState, dialArgs.retryCallFailCause, dialArgs.retryCallFailNetworkType, dialArgs.intentExtras); + } else if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + final int finalClirMode = clirMode; + final int finalVideoState = videoState; + Runnable onComplete = new Runnable() { + @Override + public void run() { + dialInternal(mPendingMO, finalClirMode, finalVideoState, + dialArgs.retryCallFailCause, dialArgs.retryCallFailNetworkType, + dialArgs.intentExtras); + } + }; + EmergencyStateTracker.getInstance().exitEmergencyCallbackMode(onComplete); } else { try { getEcbmInterface().exitEmergencyCallbackMode(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 903d82ce2e..6f93d087b9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -89,6 +89,7 @@ import android.util.Log; import androidx.test.filters.FlakyTest; import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.test.SimulatedCommands; @@ -171,6 +172,8 @@ public class GsmCdmaPhoneTest extends TelephonyTest { doReturn(false).when(mSST).isDeviceShuttingDown(); doReturn(true).when(mImsManager).isVolteEnabledByPlatform(); + DomainSelectionResolver.make(mContext, false); + mPhoneUT = new GsmCdmaPhone(mContext, mSimulatedCommands, mNotifier, true, 0, PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager); mPhoneUT.setVoiceCallSessionStats(mVoiceCallSessionStats); diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java index ef779848b3..68ea884fa9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.emergency; +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; import static org.junit.Assert.assertEquals; @@ -32,26 +33,33 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.Intent; import android.os.AsyncResult; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.UserHandle; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.DisconnectCause; import android.telephony.EmergencyRegResult; import android.telephony.ServiceState; +import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.Call; +import com.android.internal.telephony.GsmCdmaPhone; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.data.PhoneSwitcher; @@ -77,6 +85,7 @@ import java.util.function.Consumer; public class EmergencyStateTrackerTest extends TelephonyTest { private static final String TEST_CALL_ID = "00001"; + private static final String TEST_CALL_ID_02 = "00002"; @Mock EmergencyStateTracker.PhoneFactoryProxy mPhoneFactoryProxy; @Mock EmergencyStateTracker.PhoneSwitcherProxy mPhoneSwitcherProxy; @@ -429,51 +438,165 @@ public class EmergencyStateTrackerTest extends TelephonyTest { } /** - * Test that once EmergencyStateTracker ends call, it exits emergency mode. + * Test that onEmergencyTransportChanged sets the new emergency mode. */ @Test @SmallTest - public void endCall_exitsEmergencyMode() { + public void onEmergencyTransportChanged_setsEmergencyMode() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( - true /* isSuplDdsSwitchRequiredForEmergencyCall */); + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); // Create test Phones - Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, - true /* isRadioOn */); + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true ); // Call startEmergencyCall() to set testPhone CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); - emergencyStateTracker.endCall("testId"); + emergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); - verify(testPhone).exitEmergencyMode(any()); + verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any()); } /** - * Test that onEmergencyTransportChanged sets the new emergency mode. + * Test that after endCall() is called, EmergencyStateTracker will enter ECM if the call was + * ACTIVE and send related intents. */ @Test @SmallTest - public void onEmergencyTransportChanged_setsEmergencyMode() { + public void endCall_callWasActive_enterEcm() { + // Setup EmergencyStateTracker EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( - true /* isSuplDdsSwitchRequiredForEmergencyCall */); - // Create test Phones - Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, - true /* isRadioOn */); - // Call startEmergencyCall() to set testPhone + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + // Create test Phone + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + // Start emergency call then enter ECM CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + // Set ecm as supported + CarrierConfigManager cfgManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + cfgManager.getConfigForSubId(testPhone.getSubId()).putBoolean( + CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, true); + assertFalse(emergencyStateTracker.isInEcm()); + + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertTrue(emergencyStateTracker.isInEcm()); + // Verify intents are sent that ECM is entered + ArgumentCaptor ecmStateIntent = ArgumentCaptor.forClass(Intent.class); + verify(mContext).sendStickyBroadcastAsUser(ecmStateIntent.capture(), eq(UserHandle.ALL)); + assertTrue(ecmStateIntent.getValue() + .getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, true)); + // Verify emergency callback mode set on modem + verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any()); + } - emergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + /** + * Test that after endCall() is called, EmergencyStateTracker will not enter ECM if the call was + * not ACTIVE. + */ + @Test + @SmallTest + public void endCall_callNotActive_noEcm() { + // Setup EmergencyStateTracker + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + // Create test Phone + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + // Start emergency call then enter ECM + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + // Call does not reach ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.IDLE, TEST_CALL_ID); + // Set ecm as supported + setEcmSupportedConfig(testPhone, /* ecmSupported= */ true); - verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any()); + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertFalse(emergencyStateTracker.isInEcm()); + } + + /** + * Test that once endCall() is called and we enter ECM, then we exit ECM after the specified + * timeout. + */ + @Test + @SmallTest + public void endCall_entersEcm_thenExitsEcmAfterTimeout() { + // Setup EmergencyStateTracker + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + // Create test Phone + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + // Set ecm as supported + setEcmSupportedConfig(testPhone, /* ecmSupported= */ true); + + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertTrue(emergencyStateTracker.isInEcm()); + // Verify exitEmergencyMode() is called after timeout + verify(testPhone, timeout(emergencyStateTracker.defaultEcmExitTimeoutMs + 1000).times(1)) + .exitEmergencyMode(any()); + } + + /** + * Test that after exitEmergencyCallbackMode() is called, the correct intents are sent and + * emergency mode is exited on the modem. + */ + @Test + @SmallTest + public void exitEmergencyCallbackMode_sendsCorrectIntentsAndExitsEmergencyMode() { + // Setup EmergencyStateTracker + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + // Create test Phone + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + // Start emergency call then enter ECM + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + // Set ecm as supported + setEcmSupportedConfig(testPhone, /* ecmSupported= */ true); + // End call to enter ECM + emergencyStateTracker.endCall(TEST_CALL_ID); + assertTrue(emergencyStateTracker.isInEcm()); + + emergencyStateTracker.exitEmergencyCallbackMode(); + + assertFalse(emergencyStateTracker.isInEcm()); + // Intents sent for ECM: one for entering ECM and another for exiting + ArgumentCaptor ecmStateIntent = ArgumentCaptor.forClass(Intent.class); + verify(mContext, times(2)) + .sendStickyBroadcastAsUser(ecmStateIntent.capture(), eq(UserHandle.ALL)); + List capturedIntents = ecmStateIntent.getAllValues(); + assertTrue(capturedIntents.get(0) + .getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)); + assertFalse(capturedIntents.get(1) + .getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)); + // Verify exitEmergencyMode() is called only once + verify(testPhone, timeout(emergencyStateTracker.defaultEcmExitTimeoutMs + 1000).times(1)) + .exitEmergencyMode(any()); } private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall) { doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); - return new EmergencyStateTracker(mContext, Looper.getMainLooper(), - isSuplDdsSwitchRequiredForEmergencyCall, mPhoneFactoryProxy, mPhoneSwitcherProxy, - mTelephonyManagerProxy, mRadioOnHelper); + EmergencyStateTracker emergencyStateTracker = new EmergencyStateTracker(mContext, + Looper.getMainLooper(), isSuplDdsSwitchRequiredForEmergencyCall, mPhoneFactoryProxy, + mPhoneSwitcherProxy, mTelephonyManagerProxy, mRadioOnHelper, + /* ecmExitTimeoutMs= */ 3000); + return emergencyStateTracker; } private Phone setupTestPhoneForEmergencyCall(boolean isRoaming, boolean isRadioOn) { @@ -494,7 +617,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { } private Phone makeTestPhone(int phoneId, int serviceState, boolean isEmergencyOnly) { - Phone phone = mock(Phone.class); + Phone phone = mock(GsmCdmaPhone.class); ServiceState testServiceState = new ServiceState(); testServiceState.setState(serviceState); testServiceState.setEmergencyOnly(isEmergencyOnly); @@ -503,6 +626,15 @@ public class EmergencyStateTrackerTest extends TelephonyTest { when(phone.getPhoneId()).thenReturn(phoneId); when(phone.getSubId()).thenReturn(0); when(phone.getServiceStateTracker()).thenReturn(mSST); + when(phone.getUnitTestMode()).thenReturn(true); return phone; } + + private void setEcmSupportedConfig(Phone phone, boolean ecmSupported) { + CarrierConfigManager cfgManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + cfgManager.getConfigForSubId(phone.getSubId()).putBoolean( + CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, + ecmSupported); + } } \ No newline at end of file -- GitLab From 472138ca27fca5857d14374639d1126524f888bf Mon Sep 17 00:00:00 2001 From: Brad Ebinger Date: Fri, 13 Jan 2023 15:00:46 -0800 Subject: [PATCH 357/656] Enhance existing ECBM CL to also include domain specific ECBM logic This CL does a couple of things: - Cleans up some linting errors - Speeds up testing the EmergencyStateTracker test by reducing timeouts during testing and reducing scope of hidden variables. - Uses new CarrierConfigManager API vs old one to speed up config transactions over Binder - Fixes a bug where using a test number would cause the Radio response to never complete. We also now clear the mIsTestEmergencyNumber variable once the emergency modes are exited. - Enhances the code to take into account the domain that the emergency call is currently placed over. This is important for ECBM because we perform different procedures based on domain selected. - Added some logging. Test: atest EmergencyStateTrackerTest; placed/received call/sms/data Bug: 247639718 Change-Id: I829f757c6a1081218c868abc3eada433a851605a --- .../emergency/EmergencyStateTracker.java | 185 +++++++++++------- .../internal/telephony/ContextFixture.java | 1 + .../emergency/EmergencyStateTrackerTest.java | 122 ++++++++++-- 3 files changed, 223 insertions(+), 85 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java index a5da97e62a..5b667db69b 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java @@ -18,7 +18,6 @@ package com.android.internal.telephony.emergency; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_NONE; -import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; import android.annotation.NonNull; @@ -30,6 +29,7 @@ import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.os.PowerManager; import android.os.UserHandle; import android.provider.Settings; @@ -37,10 +37,10 @@ import android.sysprop.TelephonyProperties; import android.telephony.CarrierConfigManager; import android.telephony.DisconnectCause; import android.telephony.EmergencyRegResult; +import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.telephony.emergency.EmergencyNumber; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Call; @@ -48,15 +48,12 @@ import com.android.internal.telephony.GsmCdmaPhone; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.RIL; -import com.android.internal.telephony.TelephonyCapabilities; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.telephony.Rlog; import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -77,38 +74,38 @@ public class EmergencyStateTracker { private static final boolean DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED = true; /** Default Emergency Callback Mode exit timeout value. */ private static final long DEFAULT_ECM_EXIT_TIMEOUT_MS = 300000; - public long defaultEcmExitTimeoutMs = DEFAULT_ECM_EXIT_TIMEOUT_MS; private static EmergencyStateTracker INSTANCE = null; + private final long mEcmExitTimeoutMs; private final Context mContext; + private final CarrierConfigManager mConfigManager; private final Handler mHandler; - private @EmergencyConstants.EmergencyMode int mEmergencyMode = MODE_EMERGENCY_NONE; + private final boolean mIsSuplDdsSwitchRequiredForEmergencyCall; + /** Tracks emergency calls by callId that have reached {@link Call.State#ACTIVE}.*/ + private final Set mActiveEmergencyCalls = new HashSet<>(); + private final PowerManager.WakeLock mWakeLock; + + @EmergencyConstants.EmergencyMode + private int mEmergencyMode = MODE_EMERGENCY_NONE; private Phone mPhone; private RadioOnHelper mRadioOnHelper; private CompletableFuture mOnCompleted = null; - /** Tracks emergency calls by callId that have reached {@link Call.State.Active}.*/ - private Set mActiveEmergencyCalls = new HashSet(); - private boolean mIsSuplDdsSwitchRequiredForEmergencyCall; + // Domain of the active emergency call. Assuming here that there will only be one domain active. + private int mEmergencyCallDomain = -1; private EmergencyRegResult mLastEmergencyRegResult; private boolean mIsInEmergencyCall = false; private boolean mIsTestEmergencyNumber = false; private boolean mIsPhoneInEcmState = false; - private PowerManager.WakeLock mWakeLock; private Runnable mOnEcmExitCompleteRunnable = null; // A runnable which is used to automatically exit from Ecm after a period of time. - private Runnable mExitEcmRunnable = new Runnable() { - @Override - public void run() { - exitEmergencyCallbackMode(); - } - }; + private final Runnable mExitEcmRunnable = this::exitEmergencyCallbackMode; /** * Listens for Emergency Callback Mode state change intents */ - private BroadcastReceiver mEcmExitReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mEcmExitReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals( @@ -132,12 +129,7 @@ public class EmergencyStateTracker { Phone[] getPhones(); } - private PhoneFactoryProxy mPhoneFactoryProxy = new PhoneFactoryProxy() { - @Override - public Phone[] getPhones() { - return PhoneFactory.getPhones(); - } - }; + private PhoneFactoryProxy mPhoneFactoryProxy = PhoneFactory::getPhones; /** PhoneSwitcher dependencies for testing. */ @VisibleForTesting @@ -146,12 +138,7 @@ public class EmergencyStateTracker { PhoneSwitcher getPhoneSwitcher(); } - private PhoneSwitcherProxy mPhoneSwitcherProxy = new PhoneSwitcherProxy() { - @Override - public PhoneSwitcher getPhoneSwitcher() { - return PhoneSwitcher.getInstance(); - } - }; + private PhoneSwitcherProxy mPhoneSwitcherProxy = PhoneSwitcher::getInstance; /** * TelephonyManager dependencies for testing. @@ -161,7 +148,7 @@ public class EmergencyStateTracker { int getPhoneCount(); } - private TelephonyManagerProxy mTelephonyManagerProxy; + private final TelephonyManagerProxy mTelephonyManagerProxy; private static class TelephonyManagerProxyImpl implements TelephonyManagerProxy { private final TelephonyManager mTelephonyManager; @@ -173,7 +160,7 @@ public class EmergencyStateTracker { @Override public int getPhoneCount() { - return mTelephonyManager.getPhoneCount(); + return mTelephonyManager.getActiveModemCount(); } } @@ -266,12 +253,15 @@ public class EmergencyStateTracker { */ private EmergencyStateTracker(Context context, Looper looper, boolean isSuplDdsSwitchRequiredForEmergencyCall) { + mEcmExitTimeoutMs = DEFAULT_ECM_EXIT_TIMEOUT_MS; mContext = context; mHandler = new MyHandler(looper); mIsSuplDdsSwitchRequiredForEmergencyCall = isSuplDdsSwitchRequiredForEmergencyCall; PowerManager pm = context.getSystemService(PowerManager.class); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mWakeLock = (pm != null) ? pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + "telephony:" + TAG) : null; + mConfigManager = context.getSystemService(CarrierConfigManager.class); // Register receiver for ECM exit. IntentFilter filter = new IntentFilter(); @@ -305,9 +295,9 @@ public class EmergencyStateTracker { mPhoneSwitcherProxy = phoneSwitcherProxy; mTelephonyManagerProxy = telephonyManagerProxy; mRadioOnHelper = radioOnHelper; - defaultEcmExitTimeoutMs = ecmExitTimeoutMs; - PowerManager pm = context.getSystemService(PowerManager.class); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mEcmExitTimeoutMs = ecmExitTimeoutMs; + mWakeLock = null; // Don't declare a wakelock in tests + mConfigManager = context.getSystemService(CarrierConfigManager.class); IntentFilter filter = new IntentFilter(); filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); context.registerReceiver(mEcmExitReceiver, filter); @@ -327,7 +317,7 @@ public class EmergencyStateTracker { */ public CompletableFuture startEmergencyCall(Phone phone, String callId, boolean isTestEmergencyNumber) { - Rlog.i(TAG, "startEmergencyCall"); + Rlog.i(TAG, "startEmergencyCall for callId:" + callId); if (mPhone != null) { Rlog.e(TAG, "startEmergencyCall failed. Existing emergency call in progress."); @@ -409,8 +399,14 @@ public class EmergencyStateTracker { } mEmergencyMode = mode; + Message m = mHandler.obtainMessage(msg); if (mIsTestEmergencyNumber) { Rlog.d(TAG, "IsTestEmergencyNumber true. Skipping setting emergency mode on modem."); + // Send back a response for the command, but with null information + AsyncResult.forMessage(m, null, null); + // Ensure that we do not accidentally block indefinitely when trying to validate test + // emergency numbers + m.sendToTarget(); return; } mPhone.setEmergencyMode(mode, mHandler.obtainMessage(msg)); @@ -452,24 +448,26 @@ public class EmergencyStateTracker { * *

* Enter ECM only once all active emergency calls have ended. If a call never reached - * {@link Call.State.ACTIVE}, then no need to enter ECM. + * {@link Call.State#ACTIVE}, then no need to enter ECM. * * @param callId the call id on which to end the emergency call. */ public void endCall(String callId) { boolean wasActive = mActiveEmergencyCalls.remove(callId); - if ((wasActive && emergencyCallbackModeSupported() && mActiveEmergencyCalls.isEmpty()) - || mIsTestEmergencyNumber) { + if (mIsTestEmergencyNumber + || (wasActive && emergencyCallbackModeSupported() + && mActiveEmergencyCalls.isEmpty())) { enterEmergencyCallbackMode(); } else { exitEmergencyMode(); + mEmergencyCallDomain = -1; } } /** Returns last {@link EmergencyRegResult} as set by {@code setEmergencyMode()}. */ public EmergencyRegResult getEmergencyRegResult() { return mLastEmergencyRegResult; - }; + } /** * Handles emergency transport change by setting new emergency mode. @@ -480,6 +478,36 @@ public class EmergencyStateTracker { setEmergencyMode(mode, MSG_SET_EMERGENCY_MODE_DONE); } + /** + * Notify the tracker that the emergency call domain has been updated. + * @param phoneType The new PHONE_TYPE_* of the call. + * @param callId The ID of the call + */ + public void onEmergencyCallDomainUpdated(int phoneType, String callId) { + Rlog.d(TAG, "domain update for callId: " + callId); + int domain = -1; + switch(phoneType) { + case (PhoneConstants.PHONE_TYPE_CDMA_LTE): + //fallthrough + case (PhoneConstants.PHONE_TYPE_GSM): + //fallthrough + case (PhoneConstants.PHONE_TYPE_CDMA): { + domain = NetworkRegistrationInfo.DOMAIN_CS; + break; + } + case (PhoneConstants.PHONE_TYPE_IMS): { + domain = NetworkRegistrationInfo.DOMAIN_PS; + break; + } + default: { + Rlog.w(TAG, "domain updated: Unexpected phoneType:" + phoneType); + } + } + if (mEmergencyCallDomain == domain) return; + Rlog.i(TAG, "domain updated: from " + mEmergencyCallDomain + " to " + domain); + mEmergencyCallDomain = domain; + } + /** * Handles emergency call state change. * @@ -496,23 +524,16 @@ public class EmergencyStateTracker { * Returns {@code true} if device and carrier support emergency callback mode. */ private boolean emergencyCallbackModeSupported() { - // Check Carrier Configs if ECM is enabled. - CarrierConfigManager cfgManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (cfgManager == null) { - // If CarrierConfigManager is unavailable, return default value for ECM. - Rlog.w(TAG, "emergencyCallbackModeSupported: couldn't get CarrierConfigManager"); - return DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED; - } - - return cfgManager.getConfigForSubId(mPhone.getSubId()).getBoolean( - CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL); + return getConfig(mPhone.getSubId(), + CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, + DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED); } /** * Trigger entry into emergency callback mode. */ private void enterEmergencyCallbackMode() { + Rlog.d(TAG, "enter ECBM"); setIsInEmergencyCall(false); // Check if not in ECM already. if (!isInEcm()) { @@ -523,7 +544,9 @@ public class EmergencyStateTracker { // Notify listeners of the entrance to ECM. sendEmergencyCallbackModeChange(); - if (mPhone.getImsPhone() != null) { + if (isInImsEcm()) { + // emergency call registrants are not notified of new emergency call until entering + // ECBM (see ImsPhone#handleEnterEmergencyCallbackMode) ((GsmCdmaPhone) mPhone).notifyEmergencyCallRegistrants(true); } @@ -533,11 +556,11 @@ public class EmergencyStateTracker { // Post this runnable so we will automatically exit if no one invokes // exitEmergencyCallbackMode() directly. long delayInMillis = TelephonyProperties.ecm_exit_timer() - .orElse(defaultEcmExitTimeoutMs); + .orElse(mEcmExitTimeoutMs); mHandler.postDelayed(mExitEcmRunnable, delayInMillis); // We don't want to go to sleep while in ECM. - mWakeLock.acquire(); + if (mWakeLock != null) mWakeLock.acquire(mEcmExitTimeoutMs); } } @@ -545,8 +568,11 @@ public class EmergencyStateTracker { * Exits emergency callback mode and notifies relevant listeners. */ public void exitEmergencyCallbackMode() { + Rlog.d(TAG, "ecit ECBM"); // Remove pending exit ECM runnable, if any. mHandler.removeCallbacks(mExitEcmRunnable); + mEmergencyCallDomain = -1; + mIsTestEmergencyNumber = false; if (isInEcm()) { setIsInEcm(false); @@ -555,7 +581,7 @@ public class EmergencyStateTracker { } // Release wakeLock. - if (mWakeLock.isHeld()) { + if (mWakeLock != null && mWakeLock.isHeld()) { mWakeLock.release(); } @@ -607,17 +633,21 @@ public class EmergencyStateTracker { } /** - * Returns {@code true} if currently in emergency callback mode with an ImsPhone. + * Returns {@code true} if currently in emergency callback mode over PS */ public boolean isInImsEcm() { - return mPhone.getImsPhone() != null && isInEcm(); + return mEmergencyCallDomain == NetworkRegistrationInfo.DOMAIN_PS && isInEcm(); } /** - * Returns {@code true} if currently in emergency callback mode with an ImsPhone. + * Returns {@code true} if currently in emergency callback mode over CS */ public boolean isInCdmaEcm() { - return mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA && isInEcm(); + // Phone can be null in the case where we are not actively tracking an emergency call. + if (mPhone == null) return false; + // Ensure that this method doesn't return true when we are attached to GSM. + return mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA + && mEmergencyCallDomain == NetworkRegistrationInfo.DOMAIN_CS && isInEcm(); } /** @@ -699,15 +729,6 @@ public class EmergencyStateTracker { return CompletableFuture.completedFuture(Boolean.TRUE); } - CarrierConfigManager cfgManager = (CarrierConfigManager) phone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (cfgManager == null) { - // For some reason CarrierConfigManager is unavailable. Do not block emergency call. - Rlog.w(TAG, "possiblyOverrideDefaultDataForEmergencyCall: couldn't get" - + "CarrierConfigManager"); - return CompletableFuture.completedFuture(Boolean.TRUE); - } - // Only override default data if we are IN_SERVICE already. if (!isAvailableForEmergencyCalls(phone)) { Rlog.d(TAG, "possiblyOverrideDefaultDataForEmergencyCall: not switching DDS"); @@ -721,7 +742,7 @@ public class EmergencyStateTracker { // fallback even though the home operator does. For these operators we will need to do a DDS // switch anyway to make sure the SUPL request doesn't fail. boolean roamingNetworkSupportsControlPlaneFallback = true; - String[] dataPlaneRoamPlmns = cfgManager.getConfigForSubId(phone.getSubId()).getStringArray( + String[] dataPlaneRoamPlmns = getConfig(phone.getSubId(), CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY); if (dataPlaneRoamPlmns != null && Arrays.asList(dataPlaneRoamPlmns) .contains(phone.getServiceState().getOperatorNumeric())) { @@ -735,7 +756,7 @@ public class EmergencyStateTracker { // Do not try to swap default data if we support CS fallback or it is assumed that the // roaming network supports control plane fallback, we do not want to introduce a lag in // emergency call setup time if possible. - final boolean supportsCpFallback = cfgManager.getConfigForSubId(phone.getSubId()).getInt( + final boolean supportsCpFallback = getConfig(phone.getSubId(), CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_ONLY) != CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY; @@ -749,8 +770,8 @@ public class EmergencyStateTracker { // CarrierConfig default if format fails. int extensionTime = 0; try { - extensionTime = Integer.parseInt(cfgManager.getConfigForSubId(phone.getSubId()) - .getString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0")); + extensionTime = Integer.parseInt(getConfig(phone.getSubId(), + CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0")); } catch (NumberFormatException e) { // Just use default. } @@ -769,6 +790,24 @@ public class EmergencyStateTracker { return modemResultFuture; } + // Helper functions for easy CarrierConfigManager access + private String getConfig(int subId, String key, String defVal) { + return getConfigBundle(subId, key).getString(key, defVal); + } + private int getConfig(int subId, String key, int defVal) { + return getConfigBundle(subId, key).getInt(key, defVal); + } + private String[] getConfig(int subId, String key) { + return getConfigBundle(subId, key).getStringArray(key); + } + private boolean getConfig(int subId, String key, boolean defVal) { + return getConfigBundle(subId, key).getBoolean(key, defVal); + } + private PersistableBundle getConfigBundle(int subId, String key) { + if (mConfigManager == null) return new PersistableBundle(); + return mConfigManager.getConfigForSubId(subId, key); + } + /** * Returns true if the state of the Phone is IN_SERVICE or available for emergency calling only. */ diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java index 23fc448c08..760fc88a25 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java @@ -778,6 +778,7 @@ public class ContextFixture implements TestFixture { doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); doReturn(mBundle).when(mCarrierConfigManager).getConfig(); + doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString()); doAnswer(invocation -> mNetworkId++).when(mNetwork).getNetId(); doReturn(mNetwork).when(mConnectivityManager).registerNetworkAgent( any(), any(), any(), any(), any(), any(), anyInt()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java index 68ea884fa9..213bd6eeff 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java @@ -41,7 +41,6 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; import android.os.AsyncResult; -import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -59,9 +58,8 @@ import android.testing.TestableLooper; import com.android.internal.telephony.Call; import com.android.internal.telephony.GsmCdmaPhone; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyTest; -import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.data.PhoneSwitcher; import org.junit.After; @@ -84,8 +82,8 @@ import java.util.function.Consumer; @TestableLooper.RunWithLooper public class EmergencyStateTrackerTest extends TelephonyTest { - private static final String TEST_CALL_ID = "00001"; - private static final String TEST_CALL_ID_02 = "00002"; + private static final String TEST_CALL_ID = "TC@TEST1"; + private static final long TEST_ECM_EXIT_TIMEOUT_MS = 500; @Mock EmergencyStateTracker.PhoneFactoryProxy mPhoneFactoryProxy; @Mock EmergencyStateTracker.PhoneSwitcherProxy mPhoneSwitcherProxy; @@ -437,6 +435,97 @@ public class EmergencyStateTrackerTest extends TelephonyTest { assertFalse(emergencyStateTracker.isInEmergencyCall()); } + /** + * Test that onEmergencyCallDomainUpdated updates the domain correctly so ECBM PS domain is + * detected. + */ + @Test + @SmallTest + public void onEmergencyCallDomainUpdated_PsDomain() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + // Create test Phones + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + // Call startEmergencyCall() to set testPhone + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + // set domain + emergencyStateTracker.onEmergencyCallDomainUpdated(PhoneConstants.PHONE_TYPE_IMS, + TEST_CALL_ID); + // End call to enter ECM + emergencyStateTracker.endCall(TEST_CALL_ID); + + // Make sure CS ECBM is true + assertTrue(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInCdmaEcm()); + assertTrue(emergencyStateTracker.isInImsEcm()); + } + + /** + * Test that onEmergencyCallDomainUpdated updates the domain correctly so ECBM CS domain is + * detected. + */ + @Test + @SmallTest + public void onEmergencyCallDomainUpdated_CsDomain() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + // Create test Phones + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + // Call startEmergencyCall() to set testPhone + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + // set domain + emergencyStateTracker.onEmergencyCallDomainUpdated(PhoneConstants.PHONE_TYPE_CDMA, + TEST_CALL_ID); + // End call to enter ECM + emergencyStateTracker.endCall(TEST_CALL_ID); + + // Make sure IMS ECBM is true + assertTrue(emergencyStateTracker.isInEcm()); + assertTrue(emergencyStateTracker.isInCdmaEcm()); + assertFalse(emergencyStateTracker.isInImsEcm()); + } + + /** + * Ensure that if for some reason we enter ECBM for CS domain and the Phone type is GSM, + * isInCdmaEcm returns false. + */ + @Test + @SmallTest + public void onEmergencyCallDomainUpdated_CsDomain_Gsm() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + // Create test Phones + Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + // For some reason the Phone is reporting GSM instead of CDMA. + doReturn(PhoneConstants.PHONE_TYPE_GSM).when(testPhone).getPhoneType(); + // Call startEmergencyCall() to set testPhone + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, + TEST_CALL_ID, false); + + // Set call to ACTIVE + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + // set domain + emergencyStateTracker.onEmergencyCallDomainUpdated(PhoneConstants.PHONE_TYPE_CDMA, + TEST_CALL_ID); + // End call to enter ECM + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertTrue(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInCdmaEcm()); + assertFalse(emergencyStateTracker.isInImsEcm()); + } + /** * Test that onEmergencyTransportChanged sets the new emergency mode. */ @@ -544,7 +633,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { assertTrue(emergencyStateTracker.isInEcm()); // Verify exitEmergencyMode() is called after timeout - verify(testPhone, timeout(emergencyStateTracker.defaultEcmExitTimeoutMs + 1000).times(1)) + verify(testPhone, timeout(TEST_ECM_EXIT_TIMEOUT_MS + 1000).times(1)) .exitEmergencyMode(any()); } @@ -566,15 +655,23 @@ public class EmergencyStateTrackerTest extends TelephonyTest { TEST_CALL_ID, false); // Set call to ACTIVE emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + emergencyStateTracker.onEmergencyCallDomainUpdated( + PhoneConstants.PHONE_TYPE_IMS, TEST_CALL_ID); // Set ecm as supported setEcmSupportedConfig(testPhone, /* ecmSupported= */ true); // End call to enter ECM emergencyStateTracker.endCall(TEST_CALL_ID); + // verify ecbm states are correct assertTrue(emergencyStateTracker.isInEcm()); + assertTrue(emergencyStateTracker.isInImsEcm()); + assertFalse(emergencyStateTracker.isInCdmaEcm()); emergencyStateTracker.exitEmergencyCallbackMode(); + // Ensure ECBM states are all correctly false after we exit. assertFalse(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInImsEcm()); + assertFalse(emergencyStateTracker.isInCdmaEcm()); // Intents sent for ECM: one for entering ECM and another for exiting ArgumentCaptor ecmStateIntent = ArgumentCaptor.forClass(Intent.class); verify(mContext, times(2)) @@ -585,18 +682,16 @@ public class EmergencyStateTrackerTest extends TelephonyTest { assertFalse(capturedIntents.get(1) .getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)); // Verify exitEmergencyMode() is called only once - verify(testPhone, timeout(emergencyStateTracker.defaultEcmExitTimeoutMs + 1000).times(1)) + verify(testPhone, timeout(TEST_ECM_EXIT_TIMEOUT_MS + 1000).times(1)) .exitEmergencyMode(any()); } private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall) { doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); - EmergencyStateTracker emergencyStateTracker = new EmergencyStateTracker(mContext, - Looper.getMainLooper(), isSuplDdsSwitchRequiredForEmergencyCall, mPhoneFactoryProxy, - mPhoneSwitcherProxy, mTelephonyManagerProxy, mRadioOnHelper, - /* ecmExitTimeoutMs= */ 3000); - return emergencyStateTracker; + return new EmergencyStateTracker(mContext, Looper.getMainLooper(), + isSuplDdsSwitchRequiredForEmergencyCall, mPhoneFactoryProxy, mPhoneSwitcherProxy, + mTelephonyManagerProxy, mRadioOnHelper, TEST_ECM_EXIT_TIMEOUT_MS); } private Phone setupTestPhoneForEmergencyCall(boolean isRoaming, boolean isRadioOn) { @@ -627,6 +722,9 @@ public class EmergencyStateTrackerTest extends TelephonyTest { when(phone.getSubId()).thenReturn(0); when(phone.getServiceStateTracker()).thenReturn(mSST); when(phone.getUnitTestMode()).thenReturn(true); + // Initialize the phone as a CDMA phone for now for ease of testing ECBM. + // Tests can individually override this to GSM if required for the test. + doReturn(PhoneConstants.PHONE_TYPE_CDMA).when(phone).getPhoneType(); return phone; } -- GitLab From a1fbf01276c14d6dcbbb3c288ac37fcee7d636e8 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 14 Jan 2023 12:42:07 -0800 Subject: [PATCH 358/656] Fixed the set/getAllowedNetworkTypes debug messages Made the debug message more readable. Fix: 265535191 Test: Manual Change-Id: I643231a4816cfec34f24b2ab3719779a419cb89d --- .../com/android/internal/telephony/Phone.java | 65 +++++-------------- .../data/LinkBandwidthEstimator.java | 6 +- .../SubscriptionInfoInternal.java | 31 +++++++-- 3 files changed, 46 insertions(+), 56 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index a69e71ec30..ca6091f4c0 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -470,10 +470,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected SimulatedRadioControl mSimulatedRadioControl; private Map mAllowedNetworkTypesForReasons = new HashMap<>(); - private static final String ALLOWED_NETWORK_TYPES_TEXT_USER = "user"; - private static final String ALLOWED_NETWORK_TYPES_TEXT_POWER = "power"; - private static final String ALLOWED_NETWORK_TYPES_TEXT_CARRIER = "carrier"; - private static final String ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G = "enable_2g"; private static final int INVALID_ALLOWED_NETWORK_TYPES = -1; protected boolean mIsCarrierNrSupported = false; protected boolean mIsAllowedNetworkTypesLoadedFromDb = false; @@ -2328,9 +2324,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ public void notifyAllowedNetworkTypesChanged( @TelephonyManager.AllowedNetworkTypesReason int reason) { - logd("SubId" + getSubId() + ",notifyAllowedNetworkTypesChanged: reason: " + reason - + " value:" + TelephonyManager.convertNetworkTypeBitmaskToString( - getAllowedNetworkTypes(reason))); + logd("notifyAllowedNetworkTypesChanged: subId=" + getSubId() + ", reason=" + + TelephonyManager.allowedNetworkTypesReasonToString(reason) + + " network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( + getAllowedNetworkTypes(reason))); mNotifier.notifyAllowedNetworkTypesChanged(this, reason, getAllowedNetworkTypes(reason)); } @@ -2382,9 +2379,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { && reason == TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER) { allowedNetworkTypes = updateAllowedNetworkTypeForCarrierWithCarrierConfig(); } - logd("SubId" + getSubId() + ",get allowed network types " - + convertAllowedNetworkTypeMapIndexToDbName(reason) - + ": value = " + TelephonyManager.convertNetworkTypeBitmaskToString( + logd("getAllowedNetworkTypes: subId=" + getSubId() + ", reason=" + + TelephonyManager.allowedNetworkTypesReasonToString(reason) + + ", network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( allowedNetworkTypes)); return allowedNetworkTypes; } @@ -2419,7 +2416,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return; } - logd("SubId" + getSubId() + ",load allowed network types : value = " + result); + logd("loadAllowedNetworksFromSubscriptionDatabase: subId=" + getSubId() + ", " + + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(result)); Map oldAllowedNetworkTypes = new HashMap<>(mAllowedNetworkTypesForReasons); mAllowedNetworkTypesForReasons.clear(); try { @@ -2430,10 +2428,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { Rlog.e(LOG_TAG, "Invalid ALLOWED_NETWORK_TYPES from DB, value = " + pair); continue; } - int key = convertAllowedNetworkTypeDbNameToMapIndex(networkTypesValues[0]); + int key = TelephonyManager.allowedNetworkTypesReasonFromString( + networkTypesValues[0]); long value = Long.parseLong(networkTypesValues[1]); - if (key != INVALID_ALLOWED_NETWORK_TYPES - && value != INVALID_ALLOWED_NETWORK_TYPES) { + if (value != INVALID_ALLOWED_NETWORK_TYPES) { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(key, value); } @@ -2455,36 +2453,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } } - private int convertAllowedNetworkTypeDbNameToMapIndex(String name) { - switch (name) { - case ALLOWED_NETWORK_TYPES_TEXT_USER: - return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER; - case ALLOWED_NETWORK_TYPES_TEXT_POWER: - return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER; - case ALLOWED_NETWORK_TYPES_TEXT_CARRIER: - return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER; - case ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G: - return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G; - default: - return INVALID_ALLOWED_NETWORK_TYPES; - } - } - - private String convertAllowedNetworkTypeMapIndexToDbName(int reason) { - switch (reason) { - case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER: - return ALLOWED_NETWORK_TYPES_TEXT_USER; - case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER: - return ALLOWED_NETWORK_TYPES_TEXT_POWER; - case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER: - return ALLOWED_NETWORK_TYPES_TEXT_CARRIER; - case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G: - return ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G; - default: - return Integer.toString(INVALID_ALLOWED_NETWORK_TYPES); - } - } - private @TelephonyManager.NetworkTypeBitMask long updateAllowedNetworkTypeForCarrierWithCarrierConfig() { long defaultAllowedNetworkTypes = RadioAccessFamily.getRafFromNetworkType( @@ -2526,8 +2494,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } if (!SubscriptionManager.isUsableSubscriptionId(subId) || !mIsAllowedNetworkTypesLoadedFromDb) { - loge("setAllowedNetworkTypes: no sim or network type is not loaded. SubscriptionId: " - + subId + ", isNetworkTypeLoaded" + mIsAllowedNetworkTypesLoadedFromDb); + loge("setAllowedNetworkTypes: no sim or network type is not loaded. subId=" + + subId + ", isNetworkTypeLoaded=" + mIsAllowedNetworkTypesLoadedFromDb); if (response != null) { AsyncResult.forMessage(response, null, new CommandException(CommandException.Error.MISSING_RESOURCE)); @@ -2539,14 +2507,15 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(reason, networkTypes); mapAsString = mAllowedNetworkTypesForReasons.keySet().stream() - .map(key -> convertAllowedNetworkTypeMapIndexToDbName(key) + "=" + .map(key -> TelephonyManager.allowedNetworkTypesReasonToString(key) + "=" + mAllowedNetworkTypesForReasons.get(key)) .collect(Collectors.joining(",")); } SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, mapAsString); - logd("setAllowedNetworkTypes: SubId" + subId + ",setAllowedNetworkTypes " + mapAsString); + logd("setAllowedNetworkTypes: subId=" + subId + ", " + + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(mapAsString)); updateAllowedNetworkTypes(response); notifyAllowedNetworkTypesChanged(reason); diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index 994e8f67fb..73aa92d5bd 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -141,9 +141,9 @@ public class LinkBandwidthEstimator extends Handler { private static final int MAX_ERROR_PERCENT = 100 * 100; private static final String[] AVG_BW_PER_RAT = { "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA:14,14", - "CDMA - 1xRTT:30,30", "CDMA - EvDo rev. 0:750,48", "CDMA - EvDo rev. A:950,550", - "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "CDMA - EvDo rev. B:1500,550", - "CDMA - eHRPD:750,48", "HSPA+:13000,3400", "TD_SCDMA:115,115", + "1xRTT:30,30", "EVDO-0:750,48", "EVDO-A:950,550", + "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "EVDO-B:1500,550", + "eHRPD:750,48", "HSPA+:13000,3400", "TD-SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,18000", "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000", "NR_MMWAVE:145000,60000"}; private static final Map> AVG_BW_PER_RAT_MAP = new ArrayMap<>(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index b0262b0271..222c4b97f6 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -55,6 +55,8 @@ import com.android.telephony.Rlog; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * The class represents a single row of {@link SimInfo} table. All columns (excepts unused columns) @@ -1037,7 +1039,7 @@ public class SubscriptionInfoInternal { * * @return The stripped string. */ - public static String givePrintableId(String id) { + public static String getPrintableId(String id) { String idToPrint = null; if (id != null) { int len = id.length(); @@ -1050,10 +1052,28 @@ public class SubscriptionInfoInternal { return idToPrint; } + /** + * Convert the allowed network types for reasons to readable format. + * + * @param allowedNetworkTypesForReasons The raw value of allowed network types for reasons + * stored in the database. + * + * @return The converted string. + */ + public static String getPrintableAllowedNetworkTypesForReasons( + @NonNull String allowedNetworkTypesForReasons) { + if (TextUtils.isEmpty(allowedNetworkTypesForReasons)) return ""; + return Stream.of(allowedNetworkTypesForReasons.split(",")) + .map(s -> s.substring(0, s.indexOf("=") + 1) + + TelephonyManager.convertNetworkTypeBitmaskToString( + Long.parseLong(s.substring(s.indexOf("=") + 1)))) + .collect(Collectors.joining(", ")); + } + @Override public String toString() { return "[SubscriptionInfoInternal: id=" + mId - + " iccId=" + givePrintableId(mIccId) + + " iccId=" + getPrintableId(mIccId) + " simSlotIndex=" + mSimSlotIndex + " portIndex=" + mPortIndex + " isEmbedded=" + mIsEmbedded @@ -1073,7 +1093,7 @@ public class SubscriptionInfoInternal { + " mnc=" + mMnc + " ehplmns=" + mEhplmns + " hplmns=" + mHplmns - + " cardString=" + givePrintableId(mCardString) + + " cardString=" + getPrintableId(mCardString) + " cardId=" + mCardId + " nativeAccessRules=" + IccUtils.bytesToHexString(mNativeAccessRules) + " carrierConfigAccessRules=" + IccUtils.bytesToHexString( @@ -1091,11 +1111,12 @@ public class SubscriptionInfoInternal { + " wifiCallingModeForRoaming=" + ImsMmTelManager.wifiCallingModeToString(mWifiCallingModeForRoaming) + " enabledMobileDataPolicies=" + mEnabledMobileDataPolicies - + " imsi=" + givePrintableId(mImsi) + + " imsi=" + getPrintableId(mImsi) + " rcsUceEnabled=" + mIsRcsUceEnabled + " crossSimCallingEnabled=" + mIsCrossSimCallingEnabled + " rcsConfig=" + IccUtils.bytesToHexString(mRcsConfig) - + " allowedNetworkTypesForReasons=" + mAllowedNetworkTypesForReasons + + " allowedNetworkTypesForReasons=" + + getPrintableAllowedNetworkTypesForReasons(mAllowedNetworkTypesForReasons) + " deviceToDeviceStatusSharingPreference=" + mDeviceToDeviceStatusSharingPreference + " isVoImsOptInEnabled=" + mIsVoImsOptInEnabled + " deviceToDeviceStatusSharingContacts=" + mDeviceToDeviceStatusSharingContacts -- GitLab From d9d42a0503aa0f7d8cda48dff43c15388aa55461 Mon Sep 17 00:00:00 2001 From: Julian Thomassie Date: Wed, 18 Jan 2023 20:44:01 +0000 Subject: [PATCH 359/656] PinStorage: Record missing encryption key metric. Fixes: 224871949 Test: none, simple metrics improvement Change-Id: Id80213e76fb692a727720f4f30594512d4894677 --- .../com/android/internal/telephony/uicc/PinStorage.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/uicc/PinStorage.java b/src/java/com/android/internal/telephony/uicc/PinStorage.java index ed16ee4403..69776f4d2a 100644 --- a/src/java/com/android/internal/telephony/uicc/PinStorage.java +++ b/src/java/com/android/internal/telephony/uicc/PinStorage.java @@ -28,6 +28,7 @@ import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_COUNT_NOT_MATCHING_AFTER_REBOOT; import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_DECRYPTION_ERROR; import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_ENCRYPTION_ERROR; +import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_ENCRYPTION_KEY_MISSING; import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_REQUIRED_AFTER_REBOOT; import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_STORED_FOR_VERIFICATION; import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_VERIFICATION_FAILURE; @@ -723,7 +724,11 @@ public class PinStorage extends Handler { */ @Nullable private StoredPin decryptStoredPin(byte[] blob, @Nullable SecretKey secretKey) { - if (secretKey != null) { + if (secretKey == null) { + TelephonyStatsLog.write(PIN_STORAGE_EVENT, + PIN_STORAGE_EVENT__EVENT__PIN_ENCRYPTION_KEY_MISSING, + /* number_of_pins= */ 1, /* package_name= */ ""); + } else { try { byte[] decryptedPin = decrypt(secretKey, blob); if (decryptedPin.length > 0) { -- GitLab From eb223233808fa0947d6afe698987ef53d37ca80f Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 13 Jan 2023 00:50:11 -0800 Subject: [PATCH 360/656] Fixed SIM issues 1. Enable UICC application by default in new subscription. 2. Fixed slot/sub mapping table not updated when SIM inserted. 3. Fixed crash in getSubscriptionProperty by not throwing IllegalArgumentException when provided subId is invalid (for backward compatibility). 4. Filled in the missing field when SIM is loaded. 5. Added icon tint support. 6. Signal MultiSimSettingsController when subscriptions are all loaded. 7. Fixed a crash in getActiveSubscriptionInfo. Bug: 239607619 Test: Manual test with single SIM + atest FrameworksTelephonyTests Change-Id: I3a9c901443e1aa85edd289f3b0d41ab9b19dc2f1 --- .../internal/telephony/GsmCdmaPhone.java | 3 +- .../internal/telephony/PhoneFactory.java | 4 +- .../com/android/internal/telephony/RIL.java | 3 +- .../telephony/ServiceStateTracker.java | 8 +- .../metrics/DataCallSessionStats.java | 3 +- .../SubscriptionDatabaseManager.java | 40 +- .../SubscriptionInfoInternal.java | 10 +- .../SubscriptionManagerService.java | 356 +++++++++++------- .../SubscriptionManagerServiceTest.java | 3 + 9 files changed, 286 insertions(+), 144 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 76614f3dfb..2da338b8af 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -100,7 +100,6 @@ import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyNumberTracker; -import com.android.internal.telephony.emergency.EmergencyStateTracker; import com.android.internal.telephony.gsm.GsmMmiCode; import com.android.internal.telephony.gsm.SsData; import com.android.internal.telephony.gsm.SuppServiceNotification; @@ -4827,6 +4826,8 @@ public class GsmCdmaPhone extends Phone { IccUtils.stripTrailingFs(iccId)); } + logd("reapplyUiccAppsEnablementIfNeeded: retries=" + retries + ", subInfo=" + info); + // If info is null, it could be a new subscription. By default we enable it. boolean expectedValue = info == null || info.areUiccApplicationsEnabled(); diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index 43aa15434b..c69f84476a 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -611,9 +611,7 @@ public class PhoneFactory { pw.decreaseIndent(); pw.println("++++++++++++++++++++++++++++++++"); - if (isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().dump(fd, pw, args); - } else { + if (!isSubscriptionManagerServiceEnabled()) { pw.println("SubscriptionController:"); pw.increaseIndent(); try { diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index c5b3032a8a..498cd26254 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -4887,7 +4887,8 @@ public class RIL extends BaseCommands implements CommandsInterface { mRILDefaultWorkSource); if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " " + enable); } try { diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 79841ca714..a459d734bf 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -2750,9 +2750,11 @@ public class ServiceStateTracker extends Handler { mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); if (mPhone.isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService.setCarrierName(mPhone.getSubId(), - TextUtils.emptyIfNull(getCarrierName(data.shouldShowPlmn(), data.getPlmn(), - data.shouldShowSpn(), data.getSpn()))); + if (SubscriptionManager.isValidSubscriptionId(subId)) { + mSubscriptionManagerService.setCarrierName(subId, TextUtils.emptyIfNull( + getCarrierName(data.shouldShowPlmn(), data.getPlmn(), + data.shouldShowSpn(), data.getSpn()))); + } } else { if (!mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), data.shouldShowPlmn(), data.getPlmn(), data.shouldShowSpn(), diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java index 9af66272a8..83192f9f26 100644 --- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java @@ -30,6 +30,7 @@ import android.telephony.Annotation.NetworkType; import android.telephony.DataFailCause; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.data.ApnSetting.ProtocolType; @@ -270,7 +271,7 @@ public class DataCallSessionStats { subInfo = SubscriptionController.getInstance() .getSubscriptionInfo(mPhone.getSubId()); } - if (mPhone.getSubId() != SubscriptionController.getInstance().getDefaultDataSubId() + if (mPhone.getSubId() != SubscriptionManager.getDefaultDataSubscriptionId() && ((mDataCallSession.apnTypeBitmask & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) && subInfo != null && !subInfo.isOpportunistic()) { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 672efad2bc..665ba97321 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -56,6 +56,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.AbstractMap; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -66,6 +67,8 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.BiFunction; import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; /** * The subscription database manager is the wrapper of {@link SimInfo} @@ -618,7 +621,8 @@ public class SubscriptionDatabaseManager extends Handler { public Object getSubscriptionProperty(int subId, @NonNull String columnName) { SubscriptionInfoInternal subInfo = getSubscriptionInfoInternal(subId); if (subInfo == null) { - throw new IllegalArgumentException("Invalid subId " + subId); + throw new IllegalArgumentException("getSubscriptionProperty: Invalid subId " + subId + + ", columnName=" + columnName); } return getSubscriptionInfoFieldByColumnName(subInfo, columnName); @@ -907,6 +911,10 @@ public class SubscriptionDatabaseManager extends Handler { mAllSubscriptionInfoInternalCache.put(id, builder.build()); mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); + if (columnName.equals(SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED)) { + mCallback.invokeFromExecutor(() + -> mCallback.onUiccApplicationsEnabled(subId)); + } } } } @@ -1094,6 +1102,21 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal.Builder::setMnc); } + /** + * Set EHPLMNs associated with the subscription. + * + * @param subId Subscription id. + * @param ehplmns EHPLMNs associated with the subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setEhplmns(int subId, @NonNull String[] ehplmns) { + Objects.requireNonNull(ehplmns); + setEhplmns(subId, Arrays.stream(ehplmns) + .filter(Predicate.not(TextUtils::isEmpty)) + .collect(Collectors.joining(","))); + } + /** * Set EHPLMNs associated with the subscription. * @@ -1108,6 +1131,21 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal.Builder::setEhplmns); } + /** + * Set HPLMNs associated with the subscription. + * + * @param subId Subscription id. + * @param hplmns HPLMNs associated with the subscription. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setHplmns(int subId, @NonNull String[] hplmns) { + Objects.requireNonNull(hplmns); + setHplmns(subId, Arrays.stream(hplmns) + .filter(Predicate.not(TextUtils::isEmpty)) + .collect(Collectors.joining(","))); + } + /** * Set HPLMNs associated with the subscription. * diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index dc79c5eb2c..0616c144e1 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -1308,17 +1308,17 @@ public class SubscriptionInfoInternal { /** * Whether enhanced 4G mode is enabled by the user or not. */ - private int mIsEnhanced4GModeEnabled = 0; + private int mIsEnhanced4GModeEnabled = -1; /** * Whether video telephony is enabled by the user or not. */ - private int mIsVideoTelephonyEnabled = 0; + private int mIsVideoTelephonyEnabled = -1; /** * Whether Wi-Fi calling is enabled by the user or not when the device is not roaming. */ - private int mIsWifiCallingEnabled = 0; + private int mIsWifiCallingEnabled = -1; /** * Wi-Fi calling mode when the device is not roaming. @@ -1335,7 +1335,7 @@ public class SubscriptionInfoInternal { /** * Whether Wi-Fi calling is enabled by the user or not when the device is roaming. */ - private int mIsWifiCallingEnabledForRoaming = 0; + private int mIsWifiCallingEnabledForRoaming = -1; /** * Whether the subscription is opportunistic or not. @@ -1397,7 +1397,7 @@ public class SubscriptionInfoInternal { /** * Whether Uicc applications are configured to enable or not. */ - private int mAreUiccApplicationsEnabled = 0; + private int mAreUiccApplicationsEnabled = 1; /** * Whether the user has enabled IMS RCS User Capability Exchange (UCE) for this diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 9633c28e94..c116e138b9 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -77,6 +77,7 @@ import com.android.internal.telephony.CarrierResolver; import com.android.internal.telephony.ISetOpportunisticDataCallback; import com.android.internal.telephony.ISub; import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.MccTable; import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; @@ -85,6 +86,7 @@ import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManager.SubscriptionDatabaseManagerCallback; +import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccController; @@ -101,6 +103,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Random; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -404,7 +407,7 @@ public class SubscriptionManagerService extends ISub.Stub { public boolean set(int newValue) { int oldValue = mValue; if (super.set(newValue)) { - logl("Default voice sub changed from " + oldValue + " to " + newValue); + logl("Default voice subId changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, newValue); return true; @@ -420,7 +423,7 @@ public class SubscriptionManagerService extends ISub.Stub { public boolean set(int newValue) { int oldValue = mValue; if (super.set(newValue)) { - logl("Default data sub changed from " + oldValue + " to " + newValue); + logl("Default data subId changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, newValue); return true; @@ -436,7 +439,7 @@ public class SubscriptionManagerService extends ISub.Stub { public boolean set(int newValue) { int oldValue = mValue; if (super.set(newValue)) { - logl("Default voice sms changed from " + oldValue + " to " + newValue); + logl("Default SMS subId changed from " + oldValue + " to " + newValue); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, newValue); return true; @@ -868,6 +871,8 @@ public class SubscriptionManagerService extends ISub.Stub { * @param simSlotIndex The logical SIM slot index (i.e. phone id). */ public void markSubscriptionsInactive(int simSlotIndex) { + logl("markSubscriptionsInactive: slot " + simSlotIndex); + mSlotIndexToSubId.remove(simSlotIndex); mSubscriptionDatabaseManager.getAllSubscriptions().stream() .filter(subInfo -> subInfo.getSimSlotIndex() == simSlotIndex) .forEach(subInfo -> { @@ -897,6 +902,18 @@ public class SubscriptionManagerService extends ISub.Stub { return Math.max(0, index); } + /** + * Randomly pick a color from {@link R.array#sim_colors}. + * + * @return The selected color for the subscription. + */ + private int getColor() { + int[] colors = mContext.getResources().getIntArray(com.android.internal.R.array.sim_colors); + if (colors.length == 0) return 0xFFFFFFFF; // white + Random rand = new Random(); + return colors[rand.nextInt(colors.length)]; + } + /** * Get the embedded profile port index by ICCID. * @@ -962,6 +979,7 @@ public class SubscriptionManagerService extends ISub.Stub { if (subInfo == null) { subInfo = new SubscriptionInfoInternal.Builder() .setIccId(embeddedProfile.getIccid()) + .setIconTint(getColor()) .build(); int subId = mSubscriptionDatabaseManager.insertSubscriptionInfo(subInfo); subInfo = new SubscriptionInfoInternal.Builder(subInfo) @@ -1063,6 +1081,45 @@ public class SubscriptionManagerService extends ISub.Stub { IccUtils.stripTrailingFs(port.getIccId())); } + /** + * @return {@code true} if all the need-to-be-loaded subscriptions from SIM slots are already + * loaded. {@code false} if more than one are still being loaded. + */ + private boolean areAllSubscriptionsLoaded() { + for (int phoneId = 0; phoneId < mTelephonyManager.getActiveModemCount(); phoneId++) { + UiccSlot slot = mUiccController.getUiccSlotForPhone(phoneId); + if (slot == null) { + log("areAllSubscriptionsLoaded: slot is null. phoneId=" + phoneId); + return false; + } + if (!slot.isActive()) { + log("areAllSubscriptionsLoaded: slot is inactive. phoneId=" + phoneId); + return false; + } + if (slot.isEuicc() && mUiccController.getUiccPort(phoneId) == null) { + log("Wait for port corresponding to phone " + phoneId + " to be active, portIndex " + + "is " + slot.getPortIndexFromPhoneId(phoneId)); + return false; + } + + if (mSimState[phoneId] == TelephonyManager.SIM_STATE_NOT_READY) { + // Check if this is the final state. + IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); + if (!iccCard.isEmptyProfile() && areUiccAppsEnabledOnCard(phoneId)) { + log("areAllSubscriptionsLoaded: NOT_READY is not a final state."); + return false; + } + } + + if (mSimState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN) { + log("areAllSubscriptionsLoaded: SIM state is still unknown."); + return false; + } + } + + return true; + } + /** * Update the subscriptions on the logical SIM slot index (i.e. phone id). * @@ -1074,13 +1131,15 @@ public class SubscriptionManagerService extends ISub.Stub { + TelephonyManager.simStateToString(simState)); if (simState == TelephonyManager.SIM_STATE_ABSENT) { if (mSlotIndexToSubId.containsKey(phoneId)) { + int subId = mSlotIndexToSubId.get(phoneId); // Re-enable the SIM when it's removed, so it will be in enabled state when it gets // re-inserted again. (pre-U behavior) - mSubscriptionDatabaseManager.setUiccApplicationsEnabled( - mSlotIndexToSubId.get(phoneId), true); + log("updateSubscriptions: Re-enable Uicc application on sub " + subId); + mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, true); // When sim is absent, set the port index to invalid port index. (pre-U behavior) - mSubscriptionDatabaseManager.setPortIndex(mSlotIndexToSubId.get(phoneId), + mSubscriptionDatabaseManager.setPortIndex(subId, TelephonyManager.INVALID_PORT_INDEX); + markSubscriptionsInactive(phoneId); } } else if (simState == TelephonyManager.SIM_STATE_NOT_READY) { // Check if this is the final state. Only update the subscription if NOT_READY is a @@ -1091,49 +1150,41 @@ public class SubscriptionManagerService extends ISub.Stub { + "subscription later."); return; } - } - String iccId = getIccId(phoneId); - // Loop through all the subscriptions. If we found any ICCID matched, apply the right - // logical index to that. - int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - for (SubscriptionInfoInternal subInfo - : mSubscriptionDatabaseManager.getAllSubscriptions()) { - int simSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - if (!TextUtils.isEmpty(iccId) && subInfo.getIccId().equals(iccId)) { - subId = subInfo.getSubscriptionId(); - simSlotIndex = phoneId; - mSlotIndexToSubId.put(simSlotIndex, subId); - logl("updateSubscriptions: Found sub " + subInfo.getSubscriptionId() - + ", phoneId=" + phoneId); + if (!areUiccAppsEnabledOnCard(phoneId)) { + logl("updateSubscriptions: UICC app disabled on slot " + phoneId); + markSubscriptionsInactive(phoneId); } - mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), simSlotIndex); - } - - if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - logl("updateSubscriptions: Did not find any subscription. phoneId=" + phoneId); - mSlotIndexToSubId.remove(phoneId); } + String iccId = getIccId(phoneId); if (!TextUtils.isEmpty(iccId)) { // Check if the subscription already existed. SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager .getSubscriptionInfoInternalByIccId(iccId); + int subId; if (subInfo == null) { // This is a new SIM card. Insert a new record. subId = mSubscriptionDatabaseManager.insertSubscriptionInfo( new SubscriptionInfoInternal.Builder() .setIccId(iccId) .setSimSlotIndex(phoneId) + .setIconTint(getColor()) .build()); logl("updateSubscriptions: Inserted a new subscription. subId=" + subId + ", phoneId=" + phoneId); } else { subId = subInfo.getSubscriptionId(); + log("updateSubscriptions: Found existing subscription. subId= " + subId + + ", phoneId=" + phoneId); } - // Update the SIM slot index. This will make the subscription active. - mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId); + subInfo = mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subId); + if (subInfo != null && subInfo.areUiccApplicationsEnabled()) { + mSlotIndexToSubId.put(phoneId, subId); + // Update the SIM slot index. This will make the subscription active. + mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId); + } // Update the card id. UiccCard card = mUiccController.getUiccCardForPhone(phoneId); @@ -1150,9 +1201,66 @@ public class SubscriptionManagerService extends ISub.Stub { int portIndex = slot.getPortIndexFromIccId(iccId); mSubscriptionDatabaseManager.setPortIndex(subId, portIndex); } + + if (simState == TelephonyManager.SIM_STATE_LOADED) { + String mccMnc = mTelephonyManager.getSimOperatorNumeric(subId); + if (!TextUtils.isEmpty(mccMnc)) { + if (subId == getDefaultSubId()) { + MccTable.updateMccMncConfiguration(mContext, mccMnc); + } + setMccMnc(subId, mccMnc); + } else { + loge("updateSubscriptions: mcc/mnc is empty"); + } + + String iso = TelephonyManager.getSimCountryIsoForPhone(phoneId); + + if (!TextUtils.isEmpty(iso)) { + setCountryIso(subId, iso); + } else { + loge("updateSubscriptions: sim country iso is null"); + } + + String msisdn = mTelephonyManager.getLine1Number(subId); + if (!TextUtils.isEmpty(msisdn)) { + setDisplayNumber(msisdn, subId); + } + + String imsi = mTelephonyManager.createForSubscriptionId(subId).getSubscriberId(); + if (imsi != null) { + mSubscriptionDatabaseManager.setImsi(subId, imsi); + } + + IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); + if (iccCard != null) { + IccRecords records = iccCard.getIccRecords(); + if (records != null) { + String[] ehplmns = records.getEhplmns(); + if (ehplmns != null) { + mSubscriptionDatabaseManager.setEhplmns(subId, ehplmns); + } + String[] hplmns = records.getPlmnsFromHplmnActRecord(); + if (hplmns != null) { + mSubscriptionDatabaseManager.setHplmns(subId, hplmns); + } + } else { + loge("updateSubscriptions: ICC records are not available."); + } + } else { + loge("updateSubscriptions: ICC card is not available."); + } + } + } else { + log("updateSubscriptions: No ICCID available for phone " + phoneId); + mSlotIndexToSubId.remove(phoneId); } - updateDefaultSubIds(); + if (areAllSubscriptionsLoaded()) { + log("Notify all subscriptions loaded."); + MultiSimSettingController.getInstance().notifyAllSubscriptionLoaded(); + } + + updateDefaultSubId(); } /** @@ -1403,13 +1511,9 @@ public class SubscriptionManagerService extends ISub.Stub { + "carrier privilege"); } - if (!SubscriptionManager.isValidSubscriptionId(subId)) { - throw new IllegalArgumentException("Invalid sub id " + subId); - } - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager .getSubscriptionInfoInternal(subId); - if (subInfo.isActive()) { + if (subInfo != null && subInfo.isActive()) { return conditionallyRemoveIdentifiers(subInfo.toSubscriptionInfo(), callingPackage, callingFeatureId, "getActiveSubscriptionInfo"); } @@ -1608,9 +1712,6 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull public List getAvailableSubscriptionInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - enforcePermissions("getAvailableSubscriptionInfoList", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); @@ -1662,9 +1763,6 @@ public class SubscriptionManagerService extends ISub.Stub { @Override public List getAccessibleSubscriptionInfoList( @NonNull String callingPackage) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - if (!mEuiccManager.isEnabled()) { return null; } @@ -1732,6 +1830,7 @@ public class SubscriptionManagerService extends ISub.Stub { .setIccId(iccId) .setSimSlotIndex(slotIndex) .setDisplayName(displayName) + .setIconTint(getColor()) .setType(subscriptionType) .build() ); @@ -1745,7 +1844,6 @@ public class SubscriptionManagerService extends ISub.Stub { Binder.restoreCallingIdentity(identity); } return 0; - } /** @@ -2428,32 +2526,6 @@ public class SubscriptionManagerService extends ISub.Stub { return new int[]{getSubId(slotIndex)}; } - /** - * Update default voice, sms, and data sub id. - */ - private void updateDefaultSubIds() { - if (getActiveSubInfoCountMax() == 0) { - mDefaultVoiceSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mDefaultSmsSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mDefaultDataSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - } - if (getActiveSubInfoCountMax() == 1) { - int[] activeSubIds = getActiveSubIdList(false); - if (activeSubIds.length == 1) { - mDefaultVoiceSubId.set(activeSubIds[0]); - mDefaultSmsSubId.set(activeSubIds[0]); - mDefaultDataSubId.set(activeSubIds[0]); - } else { - loge("updateDefaultSubIds: Single SIM device, but active subs are more than one." - + " activeSubIds=" + Arrays.toString(activeSubIds)); - } - } else { - // TODO: Support dual sim - } - - updateDefaultSubId(); - } - /** * Update default sub id. */ @@ -2509,9 +2581,21 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override public int getPhoneId(int subId) { + if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + subId = getDefaultSubId(); + } + + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + return SubscriptionManager.INVALID_PHONE_INDEX; + } + // slot index and phone id are equivalent in the current implementation. - // It is intended NOT to return DEFAULT_PHONE_INDEX any more from this method. - return getSlotIndex(subId); + int slotIndex = getSlotIndex(subId); + if (SubscriptionManager.isValidSlotIndex(slotIndex)) { + return slotIndex; + } + + return SubscriptionManager.DEFAULT_PHONE_INDEX; } /** @@ -2542,11 +2626,7 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { - int oldDefaultDataSubId = mDefaultDataSubId.get(); if (mDefaultDataSubId.set(subId)) { - SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); - logl("Default data subId changed from " + oldDefaultDataSubId + " to " + subId); - MultiSimSettingController.getInstance().notifyDefaultDataSubChanged(); Intent intent = new Intent( @@ -2588,11 +2668,7 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { - int oldDefaultVoiceSubId = mDefaultVoiceSubId.get(); if (mDefaultVoiceSubId.set(subId)) { - SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); - logl("Default voice subId changed from " + oldDefaultVoiceSubId + " to " + subId); - Intent intent = new Intent( TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); @@ -2641,11 +2717,7 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { - int oldDefaultSmsSubId = mDefaultSmsSubId.get(); if (mDefaultSmsSubId.set(subId)) { - SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); - logl("Default SMS subId changed from " + oldDefaultSmsSubId + " to " + subId); - Intent intent = new Intent( SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); @@ -2711,6 +2783,9 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { + logl("setSubscriptionProperty: subId=" + subId + ", columnName=" + columnName + + ", value=" + value); + if (!SimInfo.getAllColumns().contains(columnName)) { throw new IllegalArgumentException("Invalid column name " + columnName); } @@ -2736,16 +2811,16 @@ public class SubscriptionManagerService extends ISub.Stub { * @param columnName Column name in subscription database. * * @return Value in string format associated with {@code subscriptionId} and {@code columnName} - * from the database. + * from the database. {@code null} if the {@code subscriptionId} is invalid (for backward + * compatible). * - * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not - * exposed. + * @throws IllegalArgumentException if the field is not exposed. * @throws SecurityException if callers do not hold the required permission. * * @see SimInfo for all the columns. */ @Override - @NonNull + @Nullable @RequiresPermission(anyOf = { Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_PRIVILEGED_PHONE_STATE, @@ -2792,6 +2867,9 @@ public class SubscriptionManagerService extends ISub.Stub { + " was returned from SubscriptionDatabaseManager for column " + columnName); } + } catch (IllegalArgumentException e) { + logv("getSubscriptionProperty: Invalid subId " + subId + ", columnName=" + columnName); + return null; } finally { Binder.restoreCallingIdentity(token); } @@ -2978,14 +3056,9 @@ public class SubscriptionManagerService extends ISub.Stub { public int setUiccApplicationsEnabled(boolean enabled, int subId) { enforcePermissions("setUiccApplicationsEnabled", Manifest.permission.MODIFY_PHONE_STATE); - - long identity = Binder.clearCallingIdentity(); - try { - mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, enabled); - return 1; - } finally { - Binder.restoreCallingIdentity(identity); - } + logl("setUiccApplicationsEnabled: subId=" + subId + ", enabled=" + enabled); + mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, enabled); + return 1; } /** @@ -3176,30 +3249,25 @@ public class SubscriptionManagerService extends ISub.Stub { Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - final long identity = Binder.clearCallingIdentity(); - try { - 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 ""; - } finally { - Binder.restoreCallingIdentity(identity); + 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 ""; } /** @@ -3518,6 +3586,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ public void updateSimStateForInactivePort(int slotIndex) { mHandler.post(() -> { + logl("updateSimStateForInactivePort: slotIndex=" + slotIndex); if (mSlotIndexToSubId.containsKey(slotIndex)) { // Re-enable the UICC application , so it will be in enabled state when it becomes // active again. (pre-U behavior) @@ -3543,6 +3612,8 @@ public class SubscriptionManagerService extends ISub.Stub { @Nullable Runnable updateCompleteCallback) { mHandler.post(() -> { mSimState[slotIndex] = simState; + logl("updateSimState: slot " + slotIndex + " " + + TelephonyManager.simStateToString(simState)); switch (simState) { case TelephonyManager.SIM_STATE_ABSENT: case TelephonyManager.SIM_STATE_PIN_REQUIRED: @@ -3618,38 +3689,65 @@ public class SubscriptionManagerService extends ISub.Stub { pw.println("Logical SIM slot sub id mapping:"); pw.increaseIndent(); mSlotIndexToSubId.forEach((slotIndex, subId) - -> pw.println("Logical slot " + slotIndex + ": subId=" + subId)); - pw.increaseIndent(); - + -> pw.println("Logical SIM slot " + slotIndex + ": subId=" + subId)); + pw.decreaseIndent(); + pw.println(); pw.println("defaultSubId=" + getDefaultSubId()); pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId()); pw.println("defaultDataSubId=" + getDefaultDataSubId()); pw.println("activeDataSubId=" + getActiveDataSubscriptionId()); pw.println("defaultSmsSubId=" + getDefaultSmsSubId()); + pw.println("areAllSubscriptionsLoaded=" + areAllSubscriptionsLoaded()); + pw.println(); + for (int i = 0; i < mSimState.length; i++) { + pw.println("mSimState[" + i + "]=" + TelephonyManager.simStateToString(mSimState[i])); + } + pw.println(); pw.println("Active subscriptions:"); pw.increaseIndent(); mSubscriptionDatabaseManager.getAllSubscriptions().stream() .filter(SubscriptionInfoInternal::isActive).forEach(pw::println); pw.decreaseIndent(); - pw.println("Embedded subscriptions:"); - pw.increaseIndent(); - mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(SubscriptionInfoInternal::isEmbedded).forEach(pw::println); - pw.decreaseIndent(); - pw.println("Opportunistic subscriptions:"); - pw.increaseIndent(); - mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(SubscriptionInfoInternal::isOpportunistic).forEach(pw::println); - pw.decreaseIndent(); + + pw.println(); pw.println("All subscriptions:"); pw.increaseIndent(); mSubscriptionDatabaseManager.getAllSubscriptions().forEach(pw::println); pw.decreaseIndent(); + pw.println(); + + pw.print("Embedded subscriptions: ["); + pw.println(mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isEmbedded) + .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) + .collect(Collectors.joining(", ")) + "]"); + + pw.print("Opportunistic subscriptions: ["); + pw.println(mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isOpportunistic) + .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) + .collect(Collectors.joining(", ")) + "]"); + + pw.print("getAvailableSubscriptionInfoList: ["); + pw.println(getAvailableSubscriptionInfoList( + mContext.getOpPackageName(), mContext.getFeatureId()).stream() + .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) + .collect(Collectors.joining(", ")) + "]"); + + pw.print("getSelectableSubscriptionInfoList: ["); + pw.println(mSubscriptionManager.getSelectableSubscriptionInfoList().stream() + .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) + .collect(Collectors.joining(", ")) + "]"); if (mEuiccManager != null) { pw.println("Euicc enabled=" + mEuiccManager.isEnabled()); } + pw.println(); + pw.println("Local log:"); + pw.increaseIndent(); + mLocalLog.dump(fd, pw, args); + pw.decreaseIndent(); pw.decreaseIndent(); } } 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 cfc4efacb9..c1de58ffa3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -136,6 +136,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionManagerServiceTest +Setup!"); super.setUp(getClass().getSimpleName()); + + mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[0]); + mContextFixture.addSystemFeature(PackageManager.FEATURE_TELEPHONY_EUICC); setupMocksForTelephonyPermissions(Build.VERSION_CODES.UPSIDE_DOWN_CAKE); PropertyInvalidatedCache.disableForCurrentProcess("cache_key.is_compat_change_enabled"); -- GitLab From 99e5013d83f77a319a24416045da78b0bd7c2f3e Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 17 Jan 2023 17:02:26 -0800 Subject: [PATCH 361/656] Delay IMS teardown during SRVCC handover Don't tear down IMS network when SRVCC is handover in process even if network type doesn't match. Bug: 245666094 Test: manual voice call + data browsing Change-Id: Id854ae0ac69627fdcaf3d1b3363cc8426a1309ea --- .../telephony/data/DataEvaluation.java | 2 + .../internal/telephony/data/DataNetwork.java | 13 +----- .../telephony/data/DataNetworkController.java | 46 +++++++++++++++++-- .../data/DataNetworkControllerTest.java | 27 +++++++++++ 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataEvaluation.java b/src/java/com/android/internal/telephony/data/DataEvaluation.java index 323e8b43b3..0af68374a7 100644 --- a/src/java/com/android/internal/telephony/data/DataEvaluation.java +++ b/src/java/com/android/internal/telephony/data/DataEvaluation.java @@ -230,6 +230,8 @@ public class DataEvaluation { PREFERRED_TRANSPORT_CHANGED(true), /** Slice config changed. */ SLICE_CONFIG_CHANGED(true), + /** SRVCC state changed. */ + SRVCC_STATE_CHANGED(true), /** * Single data network arbitration. On certain RATs, only one data network is allowed at the * same time. diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 5ed2c92fe8..87cb8357da 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -1332,17 +1332,6 @@ public class DataNetwork extends StateMachine { } int tearDownReason = msg.arg1; - // If the tear down request is from upper layer, for example, IMS service - // releases network request, we don't need to delay. The purpose of the delay - // is to have IMS service have time to perform IMS de-registration, so if this - // request is from IMS service itself, that means IMS service is already aware - // of the tear down. So there is no need to delay in this case. - if (tearDownReason != TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED - && shouldDelayImsTearDown()) { - logl("Delay IMS tear down until call ends. reason=" - + tearDownReasonToString(tearDownReason)); - break; - } removeMessages(EVENT_TEAR_DOWN_NETWORK); removeDeferredMessages(EVENT_TEAR_DOWN_NETWORK); @@ -2579,7 +2568,7 @@ public class DataNetwork extends StateMachine { * @return {@code true} if this is an IMS network and tear down should be delayed until call * ends on this data network. */ - public boolean shouldDelayImsTearDown() { + public boolean shouldDelayImsTearDownDueToInCall() { return mDataConfigManager.isImsDelayTearDownEnabled() && mNetworkCapabilities != null && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 39edee359d..a10a5bf67f 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -140,6 +140,9 @@ public class DataNetworkController extends Handler { /** Event for removing a network request. */ private static final int EVENT_REMOVE_NETWORK_REQUEST = 3; + /** Event for SRVCC state changed. */ + private static final int EVENT_SRVCC_STATE_CHANGED = 4; + /** Re-evaluate all unsatisfied network requests. */ private static final int EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS = 5; @@ -302,6 +305,9 @@ public class DataNetworkController extends Handler { /** Indicates if NR advanced is allowed by PCO. */ private boolean mNrAdvancedCapableByPco = false; + /** Indicates if srvcc is going on. */ + private boolean mIsSrvccHandoverInProcess = false; + /** * Indicates if the data services are bound. Key if the transport type, and value is the boolean * indicating service is bound or not. @@ -898,7 +904,7 @@ public class DataNetworkController extends Handler { preferredTransport)); return; } - if (dataNetwork.shouldDelayImsTearDown()) { + if (dataNetwork.shouldDelayImsTearDownDueToInCall()) { log("onDataNetworkHandoverRetryStopped: Delay IMS tear down until call " + "ends. " + dataNetwork); return; @@ -1010,6 +1016,7 @@ public class DataNetworkController extends Handler { this, EVENT_VOICE_CALL_ENDED, null); } mPhone.mCi.registerForSlicingConfigChanged(this, EVENT_SLICE_CONFIG_CHANGED, null); + mPhone.mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null); mPhone.getLinkBandwidthEstimator().registerCallback( new LinkBandwidthEstimatorCallback(this::post) { @@ -1023,6 +1030,7 @@ public class DataNetworkController extends Handler { @Override public void handleMessage(@NonNull Message msg) { + AsyncResult ar; switch (msg.what) { case EVENT_REGISTER_ALL_EVENTS: onRegisterAllEvents(); @@ -1057,6 +1065,12 @@ public class DataNetworkController extends Handler { sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, DataEvaluationReason.SLICE_CONFIG_CHANGED)); break; + case EVENT_SRVCC_STATE_CHANGED: + ar = (AsyncResult) msg.obj; + if (ar.exception == null) { + onSrvccStateChanged((int[]) ar.result); + } + break; case EVENT_PS_RESTRICT_ENABLED: mPsRestricted = true; break; @@ -1073,7 +1087,7 @@ public class DataNetworkController extends Handler { REEVALUATE_UNSATISFIED_NETWORK_REQUESTS_TAC_CHANGED_DELAY_MILLIS); break; case EVENT_DATA_SERVICE_BINDING_CHANGED: - AsyncResult ar = (AsyncResult) msg.obj; + ar = (AsyncResult) msg.obj; int transport = (int) ar.userObj; boolean bound = (boolean) ar.result; onDataServiceBindingChanged(transport, bound); @@ -1735,13 +1749,15 @@ public class DataNetworkController extends Handler { } } + boolean isMmtel = false; // If the data network is IMS that supports voice call, and has MMTEL request (client // specified VoPS is required.) if (dataNetwork.getAttachedNetworkRequestList().get( new int[]{NetworkCapabilities.NET_CAPABILITY_MMTEL}) != null) { // When reaching here, it means the network supports MMTEL, and also has MMTEL request // attached to it. - if (!dataNetwork.shouldDelayImsTearDown()) { + isMmtel = true; + if (!dataNetwork.shouldDelayImsTearDownDueToInCall()) { if (dataNetwork.getTransport() == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { NetworkRegistrationInfo nri = mServiceState.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, @@ -1788,7 +1804,9 @@ public class DataNetworkController extends Handler { // Sometimes network temporarily OOS and network type becomes UNKNOWN. We don't // tear down network in that case. if (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN - && !dataProfile.getApnSetting().canSupportLingeringNetworkType(networkType)) { + && !dataProfile.getApnSetting().canSupportLingeringNetworkType(networkType) + // delay IMS tear down if SRVCC in progress + && !(isMmtel && mIsSrvccHandoverInProcess)) { log("networkType=" + TelephonyManager.getNetworkTypeName(networkType) + ", networkTypeBitmask=" + TelephonyManager.convertNetworkTypeBitmaskToString( @@ -2955,6 +2973,25 @@ public class DataNetworkController extends Handler { DataNetwork.TEAR_DOWN_REASON_DATA_STALL)); } + /** + * Called when SRVCC handover state changes. To preserve the voice call, we don't tear down the + * IMS network while handover in process. We reevaluate the network when handover ends. + * + * @param state The handover state of SRVCC + */ + private void onSrvccStateChanged(@NonNull int[] state) { + if (state != null && state.length != 0) { + log("onSrvccStateChanged: " + TelephonyManager.srvccStateToString(state[0])); + mIsSrvccHandoverInProcess = state[0] == TelephonyManager.SRVCC_STATE_HANDOVER_STARTED; + // Reevaluate networks if SRVCC ends. + if (!mIsSrvccHandoverInProcess + && !hasMessages(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS)) { + sendMessage(obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS, + DataEvaluationReason.SRVCC_STATE_CHANGED)); + } + } + } + /** * Called when data service binding changed. * @@ -3707,6 +3744,7 @@ public class DataNetworkController extends Handler { pw.println("mImsDataNetworkState=" + TelephonyUtils.dataStateToString(mImsDataNetworkState)); pw.println("mDataServiceBound=" + mDataServiceBound); + pw.println("mIsSrvccHandoverInProcess=" + mIsSrvccHandoverInProcess); pw.println("mSimState=" + TelephonyManager.simStateToString(mSimState)); pw.println("mDataNetworkControllerCallbacks=" + mDataNetworkControllerCallbacks); pw.println("Subscription plans:"); 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 cd50dfb2fb..c431528306 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -3153,6 +3153,33 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyAllDataDisconnected(); } + @Test + public void testDelayImsTearDownDuringSrvcc() throws Exception { + testSetupImsDataNetwork(); + // SRVCC in progress, delay tear down + mDataNetworkControllerUT.obtainMessage(4 /*EVENT_SRVCC_STATE_CHANGED*/, + new AsyncResult(null, + new int[]{TelephonyManager.SRVCC_STATE_HANDOVER_STARTED}, null)) + .sendToTarget(); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_HSPAP, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME); + processAllMessages(); + + // Make sure IMS network is still connected. + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_MMTEL); + + // SRVCC handover ends, tear down as normal + mDataNetworkControllerUT.obtainMessage(4 /*EVENT_SRVCC_STATE_CHANGED*/, + new AsyncResult(null, + new int[]{TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED}, null)) + .sendToTarget(); + processAllFutureMessages(); + + // Make sure IMS network is torn down + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); + } + @Test public void testUnmeteredMmsWhenDataDisabled() throws Exception { mCarrierConfig.putStringArray( -- GitLab From e8ca59328162d077f80e77fa9a9edbc3b7505442 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 20 Jan 2023 18:15:39 -0800 Subject: [PATCH 362/656] Fixed display name not persisted The display number was incorrectly replacing the display name. Fix: 266228825 Test: Manual + atest SubscriptionManagerServiceTest Change-Id: I05ad5e129edcb9e7c426a1ea1f096d2447939e61 --- .../SubscriptionManagerService.java | 31 ++++++++++++++++--- .../SubscriptionManagerServiceTest.java | 2 +- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index c116e138b9..c41e5d019e 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1933,6 +1933,7 @@ public class SubscriptionManagerService extends ISub.Stub { @SimDisplayNameSource int nameSource) { enforcePermissions("setDisplayNameUsingSrc", Manifest.permission.MODIFY_PHONE_STATE); + String callingPackage = getCallingPackage(); final long identity = Binder.clearCallingIdentity(); try { Objects.requireNonNull(displayName, "setDisplayNameUsingSrc"); @@ -1980,6 +1981,9 @@ public class SubscriptionManagerService extends ISub.Stub { nameToSet = displayName; } + logl("setDisplayNameUsingSrc: subId=" + subId + ", name=" + nameToSet + + ", nameSource=" + SubscriptionManager.displayNameSourceToString(nameSource) + + ", calling package=" + callingPackage); mSubscriptionDatabaseManager.setDisplayName(subId, nameToSet); mSubscriptionDatabaseManager.setDisplayNameSource(subId, nameSource); @@ -2017,11 +2021,12 @@ public class SubscriptionManagerService extends ISub.Stub { @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public int setDisplayNumber(@NonNull String number, int subId) { enforcePermissions("setDisplayNumber", Manifest.permission.MODIFY_PHONE_STATE); - + logl("setDisplayNumber: subId=" + subId + ", number=" + number + + ", calling package=" + getCallingPackage()); // Now that all security checks passes, perform the operation as ourselves. final long identity = Binder.clearCallingIdentity(); try { - mSubscriptionDatabaseManager.setDisplayName(subId, number); + mSubscriptionDatabaseManager.setNumber(subId, number); return 1; } finally { Binder.restoreCallingIdentity(identity); @@ -3056,8 +3061,15 @@ public class SubscriptionManagerService extends ISub.Stub { public int setUiccApplicationsEnabled(boolean enabled, int subId) { enforcePermissions("setUiccApplicationsEnabled", Manifest.permission.MODIFY_PHONE_STATE); - logl("setUiccApplicationsEnabled: subId=" + subId + ", enabled=" + enabled); - mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, enabled); + logl("setUiccApplicationsEnabled: subId=" + subId + ", enabled=" + enabled + + ", calling package=" + getCallingPackage()); + + final long identity = Binder.clearCallingIdentity(); + try { + mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, enabled); + } finally { + Binder.restoreCallingIdentity(identity); + } return 1; } @@ -3638,6 +3650,17 @@ public class SubscriptionManagerService extends ISub.Stub { }); } + /** + * Get the calling package(s). + * + * @return The calling package(s). + */ + @NonNull + private String getCallingPackage() { + return Arrays.toString(mContext.getPackageManager().getPackagesForUid( + Binder.getCallingUid())); + } + /** * Log debug messages. * 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 c1de58ffa3..622a0980a0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -1041,7 +1041,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT .getSubscriptionInfoInternal(1); assertThat(subInfo).isNotNull(); - assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_PHONE_NUMBER2); + assertThat(subInfo.getNumber()).isEqualTo(FAKE_PHONE_NUMBER2); } @Test -- GitLab From 3fc8c2f55e71c9b528e7923a333598a431c9c955 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 23 Jan 2023 18:17:40 +0000 Subject: [PATCH 363/656] Revert "Fixed the set/getAllowedNetworkTypes debug messages" This reverts commit a1fbf01276c14d6dcbbb3c288ac37fcee7d636e8. Reason for revert: b/266431114 Change-Id: Ie31403f413e30bcdc787ff57de2e0dc896f5e008 --- .../com/android/internal/telephony/Phone.java | 65 ++++++++++++++----- .../data/LinkBandwidthEstimator.java | 6 +- .../SubscriptionInfoInternal.java | 31 ++------- 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index ca6091f4c0..a69e71ec30 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -470,6 +470,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected SimulatedRadioControl mSimulatedRadioControl; private Map mAllowedNetworkTypesForReasons = new HashMap<>(); + private static final String ALLOWED_NETWORK_TYPES_TEXT_USER = "user"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_POWER = "power"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_CARRIER = "carrier"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G = "enable_2g"; private static final int INVALID_ALLOWED_NETWORK_TYPES = -1; protected boolean mIsCarrierNrSupported = false; protected boolean mIsAllowedNetworkTypesLoadedFromDb = false; @@ -2324,10 +2328,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ public void notifyAllowedNetworkTypesChanged( @TelephonyManager.AllowedNetworkTypesReason int reason) { - logd("notifyAllowedNetworkTypesChanged: subId=" + getSubId() + ", reason=" - + TelephonyManager.allowedNetworkTypesReasonToString(reason) - + " network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( - getAllowedNetworkTypes(reason))); + logd("SubId" + getSubId() + ",notifyAllowedNetworkTypesChanged: reason: " + reason + + " value:" + TelephonyManager.convertNetworkTypeBitmaskToString( + getAllowedNetworkTypes(reason))); mNotifier.notifyAllowedNetworkTypesChanged(this, reason, getAllowedNetworkTypes(reason)); } @@ -2379,9 +2382,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { && reason == TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER) { allowedNetworkTypes = updateAllowedNetworkTypeForCarrierWithCarrierConfig(); } - logd("getAllowedNetworkTypes: subId=" + getSubId() + ", reason=" - + TelephonyManager.allowedNetworkTypesReasonToString(reason) - + ", network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( + logd("SubId" + getSubId() + ",get allowed network types " + + convertAllowedNetworkTypeMapIndexToDbName(reason) + + ": value = " + TelephonyManager.convertNetworkTypeBitmaskToString( allowedNetworkTypes)); return allowedNetworkTypes; } @@ -2416,8 +2419,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return; } - logd("loadAllowedNetworksFromSubscriptionDatabase: subId=" + getSubId() + ", " - + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(result)); + logd("SubId" + getSubId() + ",load allowed network types : value = " + result); Map oldAllowedNetworkTypes = new HashMap<>(mAllowedNetworkTypesForReasons); mAllowedNetworkTypesForReasons.clear(); try { @@ -2428,10 +2430,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { Rlog.e(LOG_TAG, "Invalid ALLOWED_NETWORK_TYPES from DB, value = " + pair); continue; } - int key = TelephonyManager.allowedNetworkTypesReasonFromString( - networkTypesValues[0]); + int key = convertAllowedNetworkTypeDbNameToMapIndex(networkTypesValues[0]); long value = Long.parseLong(networkTypesValues[1]); - if (value != INVALID_ALLOWED_NETWORK_TYPES) { + if (key != INVALID_ALLOWED_NETWORK_TYPES + && value != INVALID_ALLOWED_NETWORK_TYPES) { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(key, value); } @@ -2453,6 +2455,36 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } } + private int convertAllowedNetworkTypeDbNameToMapIndex(String name) { + switch (name) { + case ALLOWED_NETWORK_TYPES_TEXT_USER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER; + case ALLOWED_NETWORK_TYPES_TEXT_POWER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER; + case ALLOWED_NETWORK_TYPES_TEXT_CARRIER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER; + case ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G; + default: + return INVALID_ALLOWED_NETWORK_TYPES; + } + } + + private String convertAllowedNetworkTypeMapIndexToDbName(int reason) { + switch (reason) { + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER: + return ALLOWED_NETWORK_TYPES_TEXT_USER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER: + return ALLOWED_NETWORK_TYPES_TEXT_POWER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER: + return ALLOWED_NETWORK_TYPES_TEXT_CARRIER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G: + return ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G; + default: + return Integer.toString(INVALID_ALLOWED_NETWORK_TYPES); + } + } + private @TelephonyManager.NetworkTypeBitMask long updateAllowedNetworkTypeForCarrierWithCarrierConfig() { long defaultAllowedNetworkTypes = RadioAccessFamily.getRafFromNetworkType( @@ -2494,8 +2526,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } if (!SubscriptionManager.isUsableSubscriptionId(subId) || !mIsAllowedNetworkTypesLoadedFromDb) { - loge("setAllowedNetworkTypes: no sim or network type is not loaded. subId=" - + subId + ", isNetworkTypeLoaded=" + mIsAllowedNetworkTypesLoadedFromDb); + loge("setAllowedNetworkTypes: no sim or network type is not loaded. SubscriptionId: " + + subId + ", isNetworkTypeLoaded" + mIsAllowedNetworkTypesLoadedFromDb); if (response != null) { AsyncResult.forMessage(response, null, new CommandException(CommandException.Error.MISSING_RESOURCE)); @@ -2507,15 +2539,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(reason, networkTypes); mapAsString = mAllowedNetworkTypesForReasons.keySet().stream() - .map(key -> TelephonyManager.allowedNetworkTypesReasonToString(key) + "=" + .map(key -> convertAllowedNetworkTypeMapIndexToDbName(key) + "=" + mAllowedNetworkTypesForReasons.get(key)) .collect(Collectors.joining(",")); } SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, mapAsString); - logd("setAllowedNetworkTypes: subId=" + subId + ", " - + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(mapAsString)); + logd("setAllowedNetworkTypes: SubId" + subId + ",setAllowedNetworkTypes " + mapAsString); updateAllowedNetworkTypes(response); notifyAllowedNetworkTypesChanged(reason); diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index 73aa92d5bd..994e8f67fb 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -141,9 +141,9 @@ public class LinkBandwidthEstimator extends Handler { private static final int MAX_ERROR_PERCENT = 100 * 100; private static final String[] AVG_BW_PER_RAT = { "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA:14,14", - "1xRTT:30,30", "EVDO-0:750,48", "EVDO-A:950,550", - "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "EVDO-B:1500,550", - "eHRPD:750,48", "HSPA+:13000,3400", "TD-SCDMA:115,115", + "CDMA - 1xRTT:30,30", "CDMA - EvDo rev. 0:750,48", "CDMA - EvDo rev. A:950,550", + "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "CDMA - EvDo rev. B:1500,550", + "CDMA - eHRPD:750,48", "HSPA+:13000,3400", "TD_SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,18000", "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000", "NR_MMWAVE:145000,60000"}; private static final Map> AVG_BW_PER_RAT_MAP = new ArrayMap<>(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 222c4b97f6..b0262b0271 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -55,8 +55,6 @@ import com.android.telephony.Rlog; import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * The class represents a single row of {@link SimInfo} table. All columns (excepts unused columns) @@ -1039,7 +1037,7 @@ public class SubscriptionInfoInternal { * * @return The stripped string. */ - public static String getPrintableId(String id) { + public static String givePrintableId(String id) { String idToPrint = null; if (id != null) { int len = id.length(); @@ -1052,28 +1050,10 @@ public class SubscriptionInfoInternal { return idToPrint; } - /** - * Convert the allowed network types for reasons to readable format. - * - * @param allowedNetworkTypesForReasons The raw value of allowed network types for reasons - * stored in the database. - * - * @return The converted string. - */ - public static String getPrintableAllowedNetworkTypesForReasons( - @NonNull String allowedNetworkTypesForReasons) { - if (TextUtils.isEmpty(allowedNetworkTypesForReasons)) return ""; - return Stream.of(allowedNetworkTypesForReasons.split(",")) - .map(s -> s.substring(0, s.indexOf("=") + 1) - + TelephonyManager.convertNetworkTypeBitmaskToString( - Long.parseLong(s.substring(s.indexOf("=") + 1)))) - .collect(Collectors.joining(", ")); - } - @Override public String toString() { return "[SubscriptionInfoInternal: id=" + mId - + " iccId=" + getPrintableId(mIccId) + + " iccId=" + givePrintableId(mIccId) + " simSlotIndex=" + mSimSlotIndex + " portIndex=" + mPortIndex + " isEmbedded=" + mIsEmbedded @@ -1093,7 +1073,7 @@ public class SubscriptionInfoInternal { + " mnc=" + mMnc + " ehplmns=" + mEhplmns + " hplmns=" + mHplmns - + " cardString=" + getPrintableId(mCardString) + + " cardString=" + givePrintableId(mCardString) + " cardId=" + mCardId + " nativeAccessRules=" + IccUtils.bytesToHexString(mNativeAccessRules) + " carrierConfigAccessRules=" + IccUtils.bytesToHexString( @@ -1111,12 +1091,11 @@ public class SubscriptionInfoInternal { + " wifiCallingModeForRoaming=" + ImsMmTelManager.wifiCallingModeToString(mWifiCallingModeForRoaming) + " enabledMobileDataPolicies=" + mEnabledMobileDataPolicies - + " imsi=" + getPrintableId(mImsi) + + " imsi=" + givePrintableId(mImsi) + " rcsUceEnabled=" + mIsRcsUceEnabled + " crossSimCallingEnabled=" + mIsCrossSimCallingEnabled + " rcsConfig=" + IccUtils.bytesToHexString(mRcsConfig) - + " allowedNetworkTypesForReasons=" - + getPrintableAllowedNetworkTypesForReasons(mAllowedNetworkTypesForReasons) + + " allowedNetworkTypesForReasons=" + mAllowedNetworkTypesForReasons + " deviceToDeviceStatusSharingPreference=" + mDeviceToDeviceStatusSharingPreference + " isVoImsOptInEnabled=" + mIsVoImsOptInEnabled + " deviceToDeviceStatusSharingContacts=" + mDeviceToDeviceStatusSharingContacts -- GitLab From 1823461b2e2bb7670957008c038e2e9ab5fc4b53 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 23 Jan 2023 18:17:40 +0000 Subject: [PATCH 364/656] Revert "Fixed the set/getAllowedNetworkTypes debug messages" This reverts commit a1fbf01276c14d6dcbbb3c288ac37fcee7d636e8. Reason for revert: b/266431114 Change-Id: Ie31403f413e30bcdc787ff57de2e0dc896f5e008 (cherry picked from commit 3fc8c2f55e71c9b528e7923a333598a431c9c955) Merged-In: Ie31403f413e30bcdc787ff57de2e0dc896f5e008 --- .../com/android/internal/telephony/Phone.java | 65 ++++++++++++++----- .../data/LinkBandwidthEstimator.java | 6 +- .../SubscriptionInfoInternal.java | 31 ++------- 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 71744940fa..da6382272b 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -472,6 +472,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected SimulatedRadioControl mSimulatedRadioControl; private Map mAllowedNetworkTypesForReasons = new HashMap<>(); + private static final String ALLOWED_NETWORK_TYPES_TEXT_USER = "user"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_POWER = "power"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_CARRIER = "carrier"; + private static final String ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G = "enable_2g"; private static final int INVALID_ALLOWED_NETWORK_TYPES = -1; protected boolean mIsCarrierNrSupported = false; protected boolean mIsAllowedNetworkTypesLoadedFromDb = false; @@ -2326,10 +2330,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ public void notifyAllowedNetworkTypesChanged( @TelephonyManager.AllowedNetworkTypesReason int reason) { - logd("notifyAllowedNetworkTypesChanged: subId=" + getSubId() + ", reason=" - + TelephonyManager.allowedNetworkTypesReasonToString(reason) - + " network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( - getAllowedNetworkTypes(reason))); + logd("SubId" + getSubId() + ",notifyAllowedNetworkTypesChanged: reason: " + reason + + " value:" + TelephonyManager.convertNetworkTypeBitmaskToString( + getAllowedNetworkTypes(reason))); mNotifier.notifyAllowedNetworkTypesChanged(this, reason, getAllowedNetworkTypes(reason)); } @@ -2381,9 +2384,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { && reason == TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER) { allowedNetworkTypes = updateAllowedNetworkTypeForCarrierWithCarrierConfig(); } - logd("getAllowedNetworkTypes: subId=" + getSubId() + ", reason=" - + TelephonyManager.allowedNetworkTypesReasonToString(reason) - + ", network types=" + TelephonyManager.convertNetworkTypeBitmaskToString( + logd("SubId" + getSubId() + ",get allowed network types " + + convertAllowedNetworkTypeMapIndexToDbName(reason) + + ": value = " + TelephonyManager.convertNetworkTypeBitmaskToString( allowedNetworkTypes)); return allowedNetworkTypes; } @@ -2418,8 +2421,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return; } - logd("loadAllowedNetworksFromSubscriptionDatabase: subId=" + getSubId() + ", " - + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(result)); + logd("SubId" + getSubId() + ",load allowed network types : value = " + result); Map oldAllowedNetworkTypes = new HashMap<>(mAllowedNetworkTypesForReasons); mAllowedNetworkTypesForReasons.clear(); try { @@ -2430,10 +2432,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { Rlog.e(LOG_TAG, "Invalid ALLOWED_NETWORK_TYPES from DB, value = " + pair); continue; } - int key = TelephonyManager.allowedNetworkTypesReasonFromString( - networkTypesValues[0]); + int key = convertAllowedNetworkTypeDbNameToMapIndex(networkTypesValues[0]); long value = Long.parseLong(networkTypesValues[1]); - if (value != INVALID_ALLOWED_NETWORK_TYPES) { + if (key != INVALID_ALLOWED_NETWORK_TYPES + && value != INVALID_ALLOWED_NETWORK_TYPES) { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(key, value); } @@ -2455,6 +2457,36 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } } + private int convertAllowedNetworkTypeDbNameToMapIndex(String name) { + switch (name) { + case ALLOWED_NETWORK_TYPES_TEXT_USER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER; + case ALLOWED_NETWORK_TYPES_TEXT_POWER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER; + case ALLOWED_NETWORK_TYPES_TEXT_CARRIER: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER; + case ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G: + return TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G; + default: + return INVALID_ALLOWED_NETWORK_TYPES; + } + } + + private String convertAllowedNetworkTypeMapIndexToDbName(int reason) { + switch (reason) { + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER: + return ALLOWED_NETWORK_TYPES_TEXT_USER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER: + return ALLOWED_NETWORK_TYPES_TEXT_POWER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER: + return ALLOWED_NETWORK_TYPES_TEXT_CARRIER; + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G: + return ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G; + default: + return Integer.toString(INVALID_ALLOWED_NETWORK_TYPES); + } + } + private @TelephonyManager.NetworkTypeBitMask long updateAllowedNetworkTypeForCarrierWithCarrierConfig() { long defaultAllowedNetworkTypes = RadioAccessFamily.getRafFromNetworkType( @@ -2496,8 +2528,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } if (!SubscriptionManager.isUsableSubscriptionId(subId) || !mIsAllowedNetworkTypesLoadedFromDb) { - loge("setAllowedNetworkTypes: no sim or network type is not loaded. subId=" - + subId + ", isNetworkTypeLoaded=" + mIsAllowedNetworkTypesLoadedFromDb); + loge("setAllowedNetworkTypes: no sim or network type is not loaded. SubscriptionId: " + + subId + ", isNetworkTypeLoaded" + mIsAllowedNetworkTypesLoadedFromDb); if (response != null) { AsyncResult.forMessage(response, null, new CommandException(CommandException.Error.MISSING_RESOURCE)); @@ -2509,15 +2541,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(reason, networkTypes); mapAsString = mAllowedNetworkTypesForReasons.keySet().stream() - .map(key -> TelephonyManager.allowedNetworkTypesReasonToString(key) + "=" + .map(key -> convertAllowedNetworkTypeMapIndexToDbName(key) + "=" + mAllowedNetworkTypesForReasons.get(key)) .collect(Collectors.joining(",")); } SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, mapAsString); - logd("setAllowedNetworkTypes: subId=" + subId + ", " - + SubscriptionInfoInternal.getPrintableAllowedNetworkTypesForReasons(mapAsString)); + logd("setAllowedNetworkTypes: SubId" + subId + ",setAllowedNetworkTypes " + mapAsString); updateAllowedNetworkTypes(response); notifyAllowedNetworkTypesChanged(reason); diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index 73aa92d5bd..994e8f67fb 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -141,9 +141,9 @@ public class LinkBandwidthEstimator extends Handler { private static final int MAX_ERROR_PERCENT = 100 * 100; private static final String[] AVG_BW_PER_RAT = { "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA:14,14", - "1xRTT:30,30", "EVDO-0:750,48", "EVDO-A:950,550", - "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "EVDO-B:1500,550", - "eHRPD:750,48", "HSPA+:13000,3400", "TD-SCDMA:115,115", + "CDMA - 1xRTT:30,30", "CDMA - EvDo rev. 0:750,48", "CDMA - EvDo rev. A:950,550", + "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "CDMA - EvDo rev. B:1500,550", + "CDMA - eHRPD:750,48", "HSPA+:13000,3400", "TD_SCDMA:115,115", "LTE:30000,15000", "NR_NSA:47000,18000", "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000", "NR_MMWAVE:145000,60000"}; private static final Map> AVG_BW_PER_RAT_MAP = new ArrayMap<>(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 0d097c3c41..0616c144e1 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -55,8 +55,6 @@ import com.android.telephony.Rlog; import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * The class represents a single row of {@link SimInfo} table. All columns (excepts unused columns) @@ -1053,7 +1051,7 @@ public class SubscriptionInfoInternal { * * @return The stripped string. */ - public static String getPrintableId(String id) { + public static String givePrintableId(String id) { String idToPrint = null; if (id != null) { int len = id.length(); @@ -1066,28 +1064,10 @@ public class SubscriptionInfoInternal { return idToPrint; } - /** - * Convert the allowed network types for reasons to readable format. - * - * @param allowedNetworkTypesForReasons The raw value of allowed network types for reasons - * stored in the database. - * - * @return The converted string. - */ - public static String getPrintableAllowedNetworkTypesForReasons( - @NonNull String allowedNetworkTypesForReasons) { - if (TextUtils.isEmpty(allowedNetworkTypesForReasons)) return ""; - return Stream.of(allowedNetworkTypesForReasons.split(",")) - .map(s -> s.substring(0, s.indexOf("=") + 1) - + TelephonyManager.convertNetworkTypeBitmaskToString( - Long.parseLong(s.substring(s.indexOf("=") + 1)))) - .collect(Collectors.joining(", ")); - } - @Override public String toString() { return "[SubscriptionInfoInternal: id=" + mId - + " iccId=" + getPrintableId(mIccId) + + " iccId=" + givePrintableId(mIccId) + " simSlotIndex=" + mSimSlotIndex + " portIndex=" + mPortIndex + " isEmbedded=" + mIsEmbedded @@ -1107,7 +1087,7 @@ public class SubscriptionInfoInternal { + " mnc=" + mMnc + " ehplmns=" + mEhplmns + " hplmns=" + mHplmns - + " cardString=" + getPrintableId(mCardString) + + " cardString=" + givePrintableId(mCardString) + " cardId=" + mCardId + " nativeAccessRules=" + IccUtils.bytesToHexString(mNativeAccessRules) + " carrierConfigAccessRules=" + IccUtils.bytesToHexString( @@ -1125,12 +1105,11 @@ public class SubscriptionInfoInternal { + " wifiCallingModeForRoaming=" + ImsMmTelManager.wifiCallingModeToString(mWifiCallingModeForRoaming) + " enabledMobileDataPolicies=" + mEnabledMobileDataPolicies - + " imsi=" + getPrintableId(mImsi) + + " imsi=" + givePrintableId(mImsi) + " rcsUceEnabled=" + mIsRcsUceEnabled + " crossSimCallingEnabled=" + mIsCrossSimCallingEnabled + " rcsConfig=" + IccUtils.bytesToHexString(mRcsConfig) - + " allowedNetworkTypesForReasons=" - + getPrintableAllowedNetworkTypesForReasons(mAllowedNetworkTypesForReasons) + + " allowedNetworkTypesForReasons=" + mAllowedNetworkTypesForReasons + " deviceToDeviceStatusSharingPreference=" + mDeviceToDeviceStatusSharingPreference + " isVoImsOptInEnabled=" + mIsVoImsOptInEnabled + " deviceToDeviceStatusSharingContacts=" + mDeviceToDeviceStatusSharingContacts -- GitLab From 267781f7bbc46aa5db3d52b8619c0cbe12079228 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Thu, 12 Jan 2023 01:33:13 +0000 Subject: [PATCH 365/656] Add run-time feature flag for work profile. Bug: 265202681 Test: atest FrameworkTelephonyTestCases Change-Id: Iabde9284aae598975dde61bb37285ffd925e5f1e --- .../telephony/SubscriptionController.java | 11 +++- .../telephony/SubscriptionInfoUpdater.java | 37 ++++++++++++++ .../SubscriptionManagerService.java | 51 ++++++++++++++++++- .../telephony/SubscriptionControllerTest.java | 37 +++++--------- .../internal/telephony/TelephonyTest.java | 17 ++++++- .../SubscriptionManagerServiceTest.java | 12 ++--- 6 files changed, 126 insertions(+), 39 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index cd98fb4373..6f741474f5 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -4830,8 +4830,7 @@ public class SubscriptionController extends ISub.Stub { public UserHandle getSubscriptionUserHandle(int subId) { enforceManageSubscriptionUserAssociation("getSubscriptionUserHandle"); - if (!mContext.getResources().getBoolean( - com.android.internal.R.bool.config_enable_get_subscription_user_handle)) { + if (!SubscriptionInfoUpdater.isWorkProfileTelephonyEnabled()) { return null; } @@ -4870,6 +4869,10 @@ public class SubscriptionController extends ISub.Stub { @NonNull UserHandle userHandle) { enforceManageSubscriptionUserAssociation("isSubscriptionAssociatedWithUser"); + if (!SubscriptionInfoUpdater.isWorkProfileTelephonyEnabled()) { + return true; + } + long token = Binder.clearCallingIdentity(); try { // Return true if there are no subscriptions on the device. @@ -4924,6 +4927,10 @@ public class SubscriptionController extends ISub.Stub { return new ArrayList<>(); } + if (!SubscriptionInfoUpdater.isWorkProfileTelephonyEnabled()) { + return subInfoList; + } + List subscriptionsAssociatedWithUser = new ArrayList<>(); List subscriptionsWithNoAssociation = new ArrayList<>(); for (SubscriptionInfo subInfo : subInfoList) { diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index 1681d140b7..5bef2f7f8a 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -37,6 +37,7 @@ import android.os.ParcelUuid; import android.os.PersistableBundle; import android.os.UserHandle; import android.preference.PreferenceManager; +import android.provider.DeviceConfig; import android.service.carrier.CarrierIdentifier; import android.service.euicc.EuiccProfileInfo; import android.service.euicc.EuiccService; @@ -93,6 +94,8 @@ public class SubscriptionInfoUpdater extends Handler { private static final int EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS = 12; private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 13; private static final int EVENT_INACTIVE_SLOT_ICC_STATE_CHANGED = 14; + /** Device config changed. */ + private static final int EVENT_DEVICE_CONFIG_CHANGED = 15; private static final String ICCID_STRING_FOR_NO_SIM = ""; @@ -115,6 +118,10 @@ public class SubscriptionInfoUpdater extends Handler { private SubscriptionManager mSubscriptionManager = null; private EuiccManager mEuiccManager; private Handler mBackgroundHandler; + /** DeviceConfig key for whether work profile telephony feature is enabled. */ + private static final String KEY_ENABLE_WORK_PROFILE_TELEPHONY = "enable_work_profile_telephony"; + /** {@code true} if the work profile telephony feature is enabled otherwise {@code false}. */ + private static boolean mIsWorkProfileTelephonyEnabled = false; // The current foreground user ID. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -175,6 +182,16 @@ public class SubscriptionInfoUpdater extends Handler { PhoneConfigurationManager.registerForMultiSimConfigChange( this, EVENT_MULTI_SIM_CONFIG_CHANGED, null); + + mIsWorkProfileTelephonyEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, + KEY_ENABLE_WORK_PROFILE_TELEPHONY, false); + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_TELEPHONY, this::post, + properties -> { + if (TextUtils.equals(DeviceConfig.NAMESPACE_TELEPHONY, + properties.getNamespace())) { + sendEmptyMessage(EVENT_DEVICE_CONFIG_CHANGED); + } + }); } private void initializeCarrierApps() { @@ -360,6 +377,18 @@ public class SubscriptionInfoUpdater extends Handler { onMultiSimConfigChanged(); break; + case EVENT_DEVICE_CONFIG_CHANGED: + boolean isWorkProfileTelephonyEnabled = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_TELEPHONY, KEY_ENABLE_WORK_PROFILE_TELEPHONY, + false); + if (isWorkProfileTelephonyEnabled != mIsWorkProfileTelephonyEnabled) { + logd("EVENT_DEVICE_CONFIG_CHANGED: isWorkProfileTelephonyEnabled changed from " + + mIsWorkProfileTelephonyEnabled + " to " + + isWorkProfileTelephonyEnabled); + mIsWorkProfileTelephonyEnabled = isWorkProfileTelephonyEnabled; + } + break; + default: logd("Unknown msg:" + msg.what); } @@ -902,6 +931,14 @@ public class SubscriptionInfoUpdater extends Handler { return sIsSubInfoInitialized; } + /** + * Whether work profile telephony feature is enabled or not. + * return {@code true} if work profile telephony feature is enabled. + */ + public static boolean isWorkProfileTelephonyEnabled() { + return mIsWorkProfileTelephonyEnabled; + } + /** * Updates the cached list of embedded subscription for the eUICC with the given list of card * IDs {@code cardIds}. The step of reading the embedded subscription list from eUICC card is diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index c41e5d019e..0c7f32dcd5 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -41,6 +41,7 @@ import android.os.PersistableBundle; import android.os.RemoteException; import android.os.TelephonyServiceManager; import android.os.UserHandle; +import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Telephony.SimInfo; import android.service.carrier.CarrierIdentifier; @@ -370,6 +371,11 @@ public class SubscriptionManagerService extends ISub.Stub { public void onUiccApplicationsEnabled(int subId) {} } + /** DeviceConfig key for whether work profile telephony feature is enabled. */ + private static final String KEY_ENABLE_WORK_PROFILE_TELEPHONY = "enable_work_profile_telephony"; + /** {@code true} if the work profile telephony feature is enabled otherwise {@code false}. */ + private boolean mIsWorkProfileTelephonyEnabled = false; + /** * The constructor * @@ -453,6 +459,15 @@ public class SubscriptionManagerService extends ISub.Stub { mSimState = new int[mTelephonyManager.getSupportedModemCount()]; Arrays.fill(mSimState, TelephonyManager.SIM_STATE_UNKNOWN); + mIsWorkProfileTelephonyEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, + KEY_ENABLE_WORK_PROFILE_TELEPHONY, false); + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_TELEPHONY, + mHandler::post, properties -> { + if (TextUtils.equals(DeviceConfig.NAMESPACE_TELEPHONY, properties.getNamespace())) { + onDeviceConfigChanged(); + } + }); + // Create a separate thread for subscription database manager. The database will be updated // from a different thread. HandlerThread handlerThread = new HandlerThread(LOG_TAG); @@ -751,6 +766,16 @@ public class SubscriptionManagerService extends ISub.Stub { return iccidList; } + /** + * Enable or disable work profile telephony feature. + * @param isWorkProfileTelephonyEnabled - {@code true} if the work profile telephony feature + * is enabled otherwise {@code false}. + */ + @VisibleForTesting + public void setWorkProfileTelephonyEnabled(boolean isWorkProfileTelephonyEnabled) { + mIsWorkProfileTelephonyEnabled = isWorkProfileTelephonyEnabled; + } + /** * Set the subscription carrier id. * @@ -3409,8 +3434,7 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("getSubscriptionUserHandle", Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); - if (!mContext.getResources().getBoolean( - com.android.internal.R.bool.config_enable_get_subscription_user_handle)) { + if (!mIsWorkProfileTelephonyEnabled) { return null; } @@ -3452,6 +3476,10 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("isSubscriptionAssociatedWithUser", Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); + if (!mIsWorkProfileTelephonyEnabled) { + return true; + } + long token = Binder.clearCallingIdentity(); try { // Return true if there are no subscriptions on the device. @@ -3507,6 +3535,10 @@ public class SubscriptionManagerService extends ISub.Stub { return new ArrayList<>(); } + if (!mIsWorkProfileTelephonyEnabled) { + return subInfoList; + } + List subscriptionsAssociatedWithUser = new ArrayList<>(); List subscriptionsWithNoAssociation = new ArrayList<>(); for (SubscriptionInfo subInfo : subInfoList) { @@ -3650,6 +3682,21 @@ public class SubscriptionManagerService extends ISub.Stub { }); } + /** + * Listener to update cached flag values from DeviceConfig. + */ + private void onDeviceConfigChanged() { + boolean isWorkProfileTelephonyEnabled = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_TELEPHONY, KEY_ENABLE_WORK_PROFILE_TELEPHONY, + false); + if (isWorkProfileTelephonyEnabled != mIsWorkProfileTelephonyEnabled) { + log("onDeviceConfigChanged: isWorkProfileTelephonyEnabled " + + "changed from " + mIsWorkProfileTelephonyEnabled + " to " + + isWorkProfileTelephonyEnabled); + mIsWorkProfileTelephonyEnabled = isWorkProfileTelephonyEnabled; + } + } + /** * Get the calling package(s). * diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index 019a717dfc..3496199630 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -144,6 +144,8 @@ public class SubscriptionControllerTest extends TelephonyTest { replaceInstance(SubscriptionController.class, "sInstance", null, null); replaceInstance(MultiSimSettingController.class, "sInstance", null, mMultiSimSettingControllerMock); + replaceInstance(SubscriptionInfoUpdater.class, "mIsWorkProfileTelephonyEnabled", + null, true); mSubscriptionControllerUT = SubscriptionController.init(mContext); mCallingPackage = mContext.getOpPackageName(); @@ -2141,9 +2143,8 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void setSubscriptionUserHandle_withoutPermission() { + public void setSubscriptionUserHandle_withoutPermission() throws Exception { testInsertSim(); - enableGetSubscriptionUserHandle(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); @@ -2156,9 +2157,8 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void setGetSubscriptionUserHandle_userHandleNull() { + public void setGetSubscriptionUserHandle_userHandleNull() throws Exception { testInsertSim(); - enableGetSubscriptionUserHandle(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); @@ -2171,9 +2171,7 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void setSubscriptionUserHandle_invalidSubId() { - enableGetSubscriptionUserHandle(); - + public void setSubscriptionUserHandle_invalidSubId() throws Exception { assertThrows(IllegalArgumentException.class, () -> mSubscriptionControllerUT.setSubscriptionUserHandle( UserHandle.of(UserHandle.USER_SYSTEM), @@ -2181,9 +2179,8 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void setGetSubscriptionUserHandle_withValidUserHandleAndSubId() { + public void setGetSubscriptionUserHandle_withValidUserHandleAndSubId() throws Exception { testInsertSim(); - enableGetSubscriptionUserHandle(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); @@ -2197,9 +2194,8 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void getSubscriptionUserHandle_withoutPermission() { + public void getSubscriptionUserHandle_withoutPermission() throws Exception { testInsertSim(); - enableGetSubscriptionUserHandle(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); @@ -2211,9 +2207,7 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void getSubscriptionUserHandle_invalidSubId() { - enableGetSubscriptionUserHandle(); - + public void getSubscriptionUserHandle_invalidSubId() throws Exception { assertThrows(IllegalArgumentException.class, () -> mSubscriptionControllerUT.getSubscriptionUserHandle( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)); @@ -2229,7 +2223,7 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void isSubscriptionAssociatedWithUser_noSubscription() { + public void isSubscriptionAssociatedWithUser_noSubscription() throws Exception { // isSubscriptionAssociatedWithUser should return true if there are no active subscriptions. assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(1, UserHandle.of(UserHandle.USER_SYSTEM))).isEqualTo(true); @@ -2248,7 +2242,7 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void isSubscriptionAssociatedWithUser_userAssociatedWithSubscription() { + public void isSubscriptionAssociatedWithUser_userAssociatedWithSubscription() throws Exception { testInsertSim(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); @@ -2263,9 +2257,9 @@ public class SubscriptionControllerTest extends TelephonyTest { } @Test - public void isSubscriptionAssociatedWithUser_userNotAssociatedWithSubscription() { + public void isSubscriptionAssociatedWithUser_userNotAssociatedWithSubscription() + throws Exception { testInsertSim(); - enableGetSubscriptionUserHandle(); /* Get SUB ID */ int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); assertTrue(subIds != null && subIds.length != 0); @@ -2294,11 +2288,4 @@ public class SubscriptionControllerTest extends TelephonyTest { .getSubscriptionInfoListAssociatedWithUser(UserHandle.of(UserHandle.USER_SYSTEM)); assertThat(associatedSubInfoList.size()).isEqualTo(0); } - - private void enableGetSubscriptionUserHandle() { - Resources mResources = mock(Resources.class); - doReturn(true).when(mResources).getBoolean( - eq(com.android.internal.R.bool.config_enable_get_subscription_user_handle)); - doReturn(mResources).when(mContext).getResources(); - } } \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 855548c1f2..fd287871b5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -939,14 +939,17 @@ public abstract class TelephonyTest { private static final String PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED = DeviceConfig.NAMESPACE_PRIVACY + "/" + "device_identifier_access_restrictions_disabled"; + private HashMap mFlags = new HashMap<>(); @Override public Bundle call(String method, String arg, Bundle extras) { + logd("FakeSettingsConfigProvider: call called, method: " + method + + " request: " + arg + ", args=" + extras); + Bundle bundle = new Bundle(); switch (method) { case Settings.CALL_METHOD_GET_CONFIG: { switch (arg) { case PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED: { - Bundle bundle = new Bundle(); bundle.putString( PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED, "0"); @@ -958,6 +961,18 @@ public abstract class TelephonyTest { } break; } + case Settings.CALL_METHOD_LIST_CONFIG: + logd("LIST_config: " + mFlags); + Bundle result = new Bundle(); + result.putSerializable(Settings.NameValueTable.VALUE, mFlags); + return result; + case Settings.CALL_METHOD_SET_ALL_CONFIG: + mFlags = (extras != null) + ? (HashMap) extras.getSerializable(Settings.CALL_METHOD_FLAGS_KEY) + : new HashMap<>(); + bundle.putInt(Settings.KEY_CONFIG_SET_ALL_RETURN, + Settings.SET_ALL_RESULT_SUCCESS); + return bundle; default: fail("Method not expected: " + method); } 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 622a0980a0..d10c9df501 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -150,6 +150,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { SubscriptionManagerServiceCallback.class); ((MockContentResolver) mContext.getContentResolver()).addProvider( Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); + mSubscriptionManagerServiceUT = new SubscriptionManagerService(mContext, Looper.myLooper()); monitorTestableLooper(new TestableLooper(getBackgroundHandler().getLooper())); @@ -171,6 +172,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { setIdentifierAccess(false); setPhoneNumberAccess(PackageManager.PERMISSION_DENIED); + mSubscriptionManagerServiceUT.setWorkProfileTelephonyEnabled(true); + logd("SubscriptionManagerServiceTest -Setup!"); } @@ -246,13 +249,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } - private void enableGetSubscriptionUserHandle() { - Resources mResources = mock(Resources.class); - doReturn(true).when(mResources).getBoolean( - eq(com.android.internal.R.bool.config_enable_get_subscription_user_handle)); - doReturn(mResources).when(mContext).getResources(); - } - @Test public void testAddSubInfo() { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); @@ -940,7 +936,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetGetSubscriptionUserHandle() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); - enableGetSubscriptionUserHandle(); // Should fail without MANAGE_SUBSCRIPTION_USER_ASSOCIATION assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT @@ -974,7 +969,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testIsSubscriptionAssociatedWithUser() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); - enableGetSubscriptionUserHandle(); // Should fail without MANAGE_SUBSCRIPTION_USER_ASSOCIATION assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT -- GitLab From cdb37ffc4069f7e03996168b4f63542fc630a60e Mon Sep 17 00:00:00 2001 From: Jiwon Kim Date: Fri, 2 Dec 2022 16:08:04 +0900 Subject: [PATCH 366/656] Apply TcpBufferSize of CarrierConfig from ConnectingState When creating DataNetwork and triggering SetupDataCall, NetworkRegistration information and DisplayInfo is already prepared and updated at most time. So there's very few chance to update TCP buffer Configuration from CarrierConfig. Consequently, TCP buffer remains with default config and it's not enough to support latest high speed radio tech like NR, and also not proper to support legacy old rat which requires smaller buffer to keep stable data flow. DataConfigManager will fall back to read default TCP buffer size configuration when it fails to read overridden configuration. So no side effect is expected. Bug: 261356610 Test: m Change-Id: I31c19b94029b0d9c82ad87225c0d3d318a93c701 Signed-off-by: Jiwon Kim --- src/java/com/android/internal/telephony/data/DataNetwork.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 2a29432b8b..9ce3952d83 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -917,8 +917,8 @@ public class DataNetwork extends StateMachine { for (int transportType : mAccessNetworksManager.getAvailableTransports()) { mCid.put(transportType, INVALID_CID); } - mTcpBufferSizes = mDataConfigManager.getDefaultTcpConfigString(); mTelephonyDisplayInfo = mPhone.getDisplayInfoController().getTelephonyDisplayInfo(); + mTcpBufferSizes = mDataConfigManager.getTcpConfigString(mTelephonyDisplayInfo); for (TelephonyNetworkRequest networkRequest : networkRequestList) { networkRequest.setAttachedNetwork(DataNetwork.this); -- GitLab From 3c9f76db32c846e8b8426ced513b827e970e7259 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Tue, 24 Jan 2023 05:53:36 +0000 Subject: [PATCH 367/656] Version check correction from HAL_SERVICE_RADIO to HAL_SERVICE_SIM Bug: 266023325 Test: atest frameworks/opt/telephony/tests/telephonytests/src/com/android/internal/telephony Change-Id: I090b7e7a677cccd3a37982eb1d40e5d147412298 --- src/java/com/android/internal/telephony/RIL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index fb23e8330d..70ef2274f5 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -4948,7 +4948,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public boolean canToggleUiccApplicationsEnablement() { return !getRadioServiceProxy(RadioSimProxy.class, null).isEmpty() - && mHalVersion.get(HAL_SERVICE_RADIO).greaterOrEqual(RADIO_HAL_VERSION_1_5); + && mHalVersion.get(HAL_SERVICE_SIM).greaterOrEqual(RADIO_HAL_VERSION_1_5); } @Override -- GitLab From 1fca39b904e18367bf0e03f3b425b1ecda445027 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Wed, 16 Nov 2022 09:31:03 +0000 Subject: [PATCH 368/656] IMPI system API implementation Bug:237347020 Test: atest frameworks/opt/telephony/tests/telephonytests/src/com/android/internal/telephony Change-Id: I65f738054f6066bc6c93b97950c100b049df2575 --- .../telephony/PhoneSubInfoController.java | 28 ++++++++++++ .../telephony/PhoneSubInfoControllerTest.java | 45 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java index cd9b3fe4fc..0dcf221032 100644 --- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java +++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java @@ -352,6 +352,34 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { }); } + /** + * Fetches the IMS private user identity (EF_IMPI) based on subscriptionId. + * + * @param subId subscriptionId + * @return IMPI (IMS private user identity) of type string. + * @throws IllegalArgumentException if the subscriptionId is not valid + * @throws IllegalStateException in case the ISIM hasn’t been loaded. + * @throws SecurityException if the caller does not have the required permission + */ + public String getImsPrivateUserIdentity(int subId, String callingPackage, + String callingFeatureId) { + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + throw new IllegalArgumentException("Invalid SubscriptionID = " + subId); + } + if (!TelephonyPermissions.checkCallingOrSelfUseIccAuthWithDeviceIdentifier(mContext, + callingPackage, callingFeatureId, "getImsPrivateUserIdentity")) { + throw (new SecurityException("No permissions to the caller")); + } + Phone phone = getPhone(subId); + assert phone != null; + IsimRecords isim = phone.getIsimRecords(); + if (isim != null) { + return isim.getIsimImpi(); + } else { + throw new IllegalStateException("ISIM is not loaded"); + } + } + /** * get the Isim Domain based on subId */ diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java index e4c1466127..7bbefca881 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java @@ -23,6 +23,7 @@ import static android.telephony.TelephonyManager.APPTYPE_USIM; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.anyString; @@ -1167,4 +1168,48 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE); assertEquals(refSst, mPhoneSubInfoControllerUT.getSimServiceTable(anyInt(), anyInt())); } + + @Test + public void getPrivateUserIdentity() { + String refImpi = "1234567890@example.com"; + doReturn(mIsimUiccRecords).when(mPhone).getIsimRecords(); + doReturn(refImpi).when(mIsimUiccRecords).getIsimImpi(); + + doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOsMgr).noteOpNoThrow( + eq(AppOpsManager.OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER), anyInt(), eq(TAG), + eq(FEATURE_ID), nullable(String.class)); + + String impi = mPhoneSubInfoControllerUT.getImsPrivateUserIdentity(0, TAG, FEATURE_ID); + assertEquals(refImpi, impi); + } + + @Test + public void getPrivateUserIdentity_NoPermission() { + String refImpi = "1234567890@example.com"; + doReturn(mIsimUiccRecords).when(mPhone).getIsimRecords(); + doReturn(refImpi).when(mIsimUiccRecords).getIsimImpi(); + + try { + mPhoneSubInfoControllerUT.getImsPrivateUserIdentity(0, TAG, FEATURE_ID); + fail(); + } catch (Exception ex) { + assertTrue(ex instanceof SecurityException); + assertTrue(ex.getMessage().contains("No permissions to the caller")); + } + } + + @Test + public void getPrivateUserIdentity_InValidSubIdCheck() { + String refImpi = "1234567890@example.com"; + doReturn(mIsimUiccRecords).when(mPhone).getIsimRecords(); + doReturn(refImpi).when(mIsimUiccRecords).getIsimImpi(); + + try { + mPhoneSubInfoControllerUT.getImsPrivateUserIdentity(-1, TAG, FEATURE_ID); + fail(); + } catch (Exception ex) { + assertTrue(ex instanceof IllegalArgumentException); + assertTrue(ex.getMessage().contains("Invalid SubscriptionID")); + } + } } \ No newline at end of file -- GitLab From d426a1aa13d98eb145f51ee98b6f6d15bdc4793c Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 25 Jan 2023 04:42:15 -0800 Subject: [PATCH 369/656] Cancel timers when transitioning to NR connected Except for when it's NR advanced, then keep the timer the same. Test: atest NetworkTypeControllerTest Bug: 266569242 Change-Id: Idf05d4043f1f1b65e6962c75cf191ea4df37038a --- .../telephony/NetworkTypeController.java | 7 ++ .../telephony/NetworkTypeControllerTest.java | 76 +++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 4fd3054f92..fd9d309191 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -1136,6 +1136,13 @@ public class NetworkTypeController extends StateMachine { resetAllTimers(); } + if (currentState.equals(STATE_CONNECTED) + && !mPrimaryTimerState.equals(STATE_CONNECTED_NR_ADVANCED) + && !mSecondaryTimerState.equals(STATE_CONNECTED_NR_ADVANCED)) { + if (DBG) log("Reset non-NR_advanced timers since state is NR_CONNECTED"); + resetAllTimers(); + } + int rat = getDataNetworkType(); if (!isLte(rat) && rat != TelephonyManager.NETWORK_TYPE_NR) { if (DBG) log("Reset timers since 2G and 3G don't need NR timers."); diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index 74164a2967..29be856bd5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -1155,6 +1155,82 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertFalse(mNetworkTypeController.areAnyTimersActive()); } + @Test + public void testNrTimerResetWhenConnected() throws Exception { + mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, + "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); + mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, + "connected_mmwave,any,30"); + broadcastCarrierConfigs(); + + doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); + mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, + new AsyncResult(null, DataCallResponse.LINK_STATUS_ACTIVE, null)); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); + processAllMessages(); + + assertEquals("not_restricted_rrc_con", getCurrentState().getName()); + assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, + mNetworkTypeController.getOverrideNetworkType()); + + // should trigger 10 second primary timer + doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); + doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(mServiceState).getNrFrequencyRange(); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); + processAllMessages(); + + assertEquals("legacy", getCurrentState().getName()); + assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, + mNetworkTypeController.getOverrideNetworkType()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); + + // rat is NR, should stop timer + NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) + .build(); + doReturn(nri).when(mServiceState).getNetworkRegistrationInfo(anyInt(), anyInt()); + doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); + processAllMessages(); + + assertEquals("connected", getCurrentState().getName()); + assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, + mNetworkTypeController.getOverrideNetworkType()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); + } + + @Test + public void testNrTimerResetWhenConnectedAdvanced() throws Exception { + testTransitionToCurrentStateNrConnectedMmwave(); + mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, + "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); + mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, + "connected_mmwave,any,30"); + broadcastCarrierConfigs(); + + // should trigger 10 second primary timer + doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); + doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(mServiceState).getNrFrequencyRange(); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); + processAllMessages(); + + assertEquals("legacy", getCurrentState().getName()); + assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, + mNetworkTypeController.getOverrideNetworkType()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); + + // not advanced, should not stop timer + doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); + processAllMessages(); + + assertEquals("connected", getCurrentState().getName()); + assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, + mNetworkTypeController.getOverrideNetworkType()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); + } + private void setPhysicalLinkStatus(boolean state) { List lastPhysicalChannelConfigList = new ArrayList<>(); // If PhysicalChannelConfigList is empty, PhysicalLinkStatus is -- GitLab From 5c5b5b217ce6b4ce348a4767c4f2582fd856bf3d Mon Sep 17 00:00:00 2001 From: Ramya Manoharan Date: Tue, 13 Dec 2022 11:40:33 +0000 Subject: [PATCH 370/656] CATService STK SEND_SMS via framework error handling RP_ERRORS and RP_ERROR_CAUSES handling for stk sms sent Test: Run atest, Manually Tested By Sending STK SMS in Device Bug: 243123292 Change-Id: I68ca1dc30c49b7cfd175e0da452cc0c2f34d1715 --- .../internal/telephony/cat/CatService.java | 61 ++++++--- .../telephony/cat/CATServiceTest.java | 127 +++++++++++++++++- 2 files changed, 170 insertions(+), 18 deletions(-) diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java index 31b997fb57..d688b08c15 100644 --- a/src/java/com/android/internal/telephony/cat/CatService.java +++ b/src/java/com/android/internal/telephony/cat/CatService.java @@ -44,6 +44,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; @@ -209,9 +210,8 @@ public class CatService extends Handler implements AppInterface { CatLog.d(this, "Running CAT service on Slotid: " + mSlotId + ". STK app installed:" + mStkAppInstalled); - SmsBroadcastReceiver smsBroadcastReceiver = new SmsBroadcastReceiver(); - mContext.registerReceiver(smsBroadcastReceiver, new IntentFilter(SMS_DELIVERY_ACTION)); - mContext.registerReceiver(smsBroadcastReceiver, new IntentFilter(SMS_SENT_ACTION)); + mContext.registerReceiver(mSmsBroadcastReceiver, new IntentFilter(SMS_DELIVERY_ACTION)); + mContext.registerReceiver(mSmsBroadcastReceiver, new IntentFilter(SMS_SENT_ACTION)); } /** @@ -629,21 +629,49 @@ public class CatService extends Handler implements AppInterface { deliveryPendingIntent, false, 0L, true, true); } - private class SmsBroadcastReceiver extends BroadcastReceiver { + /** + * BroadcastReceiver class to handle error and success cases of + * SEND and DELIVERY pending intents used for sending of STK SMS + */ + @VisibleForTesting + public final BroadcastReceiver mSmsBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { CommandDetails commandDetails = (CommandDetails) intent.getExtra("cmdDetails"); if (intent.getAction().equals(SMS_SENT_ACTION)) { int resultCode = getResultCode(); - switch (resultCode) { - case Activity.RESULT_OK: - break; - default: - //ToDO handle Error cases bug : b/243123292 - CatLog.d(this, "Error sending STK SMS : " + resultCode); - sendTerminalResponse(commandDetails, ResultCode.SMS_RP_ERROR, true, - ResultCode.NETWORK_CRNTLY_UNABLE_TO_PROCESS.value(), null); + ResultCode terminalResponseResultCode = ResultCode.NETWORK_CRNTLY_UNABLE_TO_PROCESS; + CatLog.d(this, "STK SMS errorCode : " + resultCode); + int additionalInfo = 0; + if (resultCode != Activity.RESULT_OK) { + /** + * The Terminal Response Result code is assigned as per Section 12.12.3 + * and 12.12.5 TS 101.267. The Result code SMS_RP_ERROR is added in Ims Case + * and additional information is added as per RP-Cause Values in TS 124.011. + * The Result code NETWORK_CRNTLY_UNABLE_TO_PROCESS is added in non-Ims Case + * and additional information added as per cause values in TS 04.08. + */ + if (intent.hasExtra("ims") && intent.getBooleanExtra("ims", false)) { + terminalResponseResultCode = ResultCode.SMS_RP_ERROR; + //Additional information's 8th bit is 0 as per section 12.12.5 of TS 101.267 + if (intent.hasExtra("errorCode")) { + additionalInfo = (int) intent.getExtra("errorCode"); + if ((additionalInfo & 0x80) != 0) additionalInfo = 0; + } + } else { + //Additional information's 8th bit is 1 as per section 12.12.3 of TS 101.267 + if (intent.hasExtra("errorCode")) { + additionalInfo = (int) intent.getExtra("errorCode"); + additionalInfo |= 0x80; + } + } + CatLog.d(this, "Error delivering STK SMS errorCode : " + additionalInfo + + " terminalResponseResultCode = " + terminalResponseResultCode); + sendTerminalResponse(commandDetails, terminalResponseResultCode, + true, additionalInfo, null); + } else { + CatLog.d(this, " STK SMS sent successfully "); } } if (intent.getAction().equals(SMS_DELIVERY_ACTION)) { @@ -651,16 +679,17 @@ public class CatService extends Handler implements AppInterface { switch (resultCode) { case Activity.RESULT_OK: sendTerminalResponse(commandDetails, ResultCode.OK, false, 0, null); + CatLog.d(this, " STK SMS delivered successfully "); break; default: - //ToDO handle Error cases bug: b/243123292 CatLog.d(this, "Error delivering STK SMS : " + resultCode); - sendTerminalResponse(commandDetails, ResultCode.SMS_RP_ERROR, true, - ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS.value(), null); + sendTerminalResponse(commandDetails, + ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS, false, + 0, null); } } } - } + }; private void broadcastCatCmdIntent(CatCmdMessage cmdMsg) { Intent intent = new Intent(AppInterface.CAT_CMD_ACTION); diff --git a/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java index 6bc31da405..f2c18708ed 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/cat/CATServiceTest.java @@ -24,10 +24,17 @@ import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Intent; +import android.os.UserHandle; +import android.telephony.SmsManager; import android.telephony.SmsMessage; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -35,6 +42,7 @@ import android.testing.TestableLooper; import com.android.internal.telephony.ProxyController; import com.android.internal.telephony.SmsController; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.IccFileHandler; @@ -57,6 +65,10 @@ import java.util.List; @TestableLooper.RunWithLooper public class CATServiceTest extends TelephonyTest { + private static final String SMS_SENT_ACTION = + "com.android.internal.telephony.cat.SMS_SENT_ACTION"; + private static final String SMS_DELIVERY_ACTION = + "com.android.internal.telephony.cat.SMS_DELIVERY_ACTION"; //Mocked Classes @Mock private RilMessageDecoder mRilMessageDecoder; @@ -66,7 +78,6 @@ public class CATServiceTest extends TelephonyTest { private CatService mCatService; private IccCardStatus mIccCardStatus; private IccIoResult mIccIoResult; - private String mData = "D059810301130082028183051353656E64696E672072657175657374202E2E2E0607911989548056780B" + "3051FF05812143F500F6082502700000201115001500BFFF01BA23C2169EA9B02D7A7FBAA0" @@ -74,6 +85,27 @@ public class CATServiceTest extends TelephonyTest { private byte[] mRawdata = IccUtils.hexStringToBytes(mData); private List mCtlvs; + /** + * Terminal Response with result code in last 3 bytes = length + SMS_RP_ERROR(0x35) + * + ErrorCode(= 41) + */ + private String mTerminalResponseForSmsRpError = "81030113000202828183023529"; + + /** + * Terminal Response with result code in last 3 bytes = length + NETWORK_UNABLE_TO_PROCESS(0x21) + * + ErrorCode(= 41 with 8th bit set to 1) + */ + private String mTerminalResponseForNetworkUnableToProcess = "810301130002028281830221A9"; + + /** + * Terminal Response with result code in last 2 bytes = length + * + TERMINAL_UNABLE_TO_PROCESS(0x20) + */ + private String mTerminalResponseForTerminalUnableToProcess = "810301130002028281830120"; + + //Terminal Response with result code(0x00)for delivery success in last 2 bytes + private String mTerminalResponseForDeliverySuccess = "810301130002028281830100"; + public CATServiceTest() { super(); } @@ -109,13 +141,14 @@ public class CATServiceTest extends TelephonyTest { mIccCardStatus.mImsSubscriptionAppIndex = mIccCardStatus.mGsmUmtsSubscriptionAppIndex = -1; mIccIoResult = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes("FF40")); + mSimulatedCommands = mock(SimulatedCommands.class); mSimulatedCommands.setIccIoResultForApduLogicalChannel(mIccIoResult); mUiccProfile = new UiccProfile(mContext, mSimulatedCommands, mIccCardStatus, 0 /* phoneId */, mUiccCard, new Object()); processAllMessages(); logd("Created UiccProfile"); processAllMessages(); - mCatService = CatService.getInstance(mSimulatedCommands, mUiccController.mContext, + mCatService = CatService.getInstance(mSimulatedCommands, mContext, mUiccProfile, mUiccController.getSlotIdFromPhoneId(0)); logd("Created CATService"); createCommandDetails(); @@ -124,12 +157,20 @@ public class CATServiceTest extends TelephonyTest { @After public void tearDown() throws Exception { + mCatService.dispose(); mUiccProfile = null; mCatService = null; mCtlvs = null; mProxyController = null; mRilMessageDecoder = null; mCommandDetails = null; + mContext = null; + mSimulatedCommands = null; + mIccCardStatus = null; + mIccCard = null; + mIccFileHandler = null; + mIccIoResult = null; + mSmsController = null; super.tearDown(); } @@ -189,4 +230,86 @@ public class CATServiceTest extends TelephonyTest { "com.android.internal.telephony"); } + //Create and assign a PendingResult object in BroadcastReceiver with which resultCode is updated + private void setBroadcastReceiverPendingResult(BroadcastReceiver receiver, int resultCode) { + BroadcastReceiver.PendingResult pendingResult = + new BroadcastReceiver.PendingResult(resultCode, + "resultData", + /* resultExtras= */ null, + BroadcastReceiver.PendingResult.TYPE_UNREGISTERED, + /* ordered= */ true, + /* sticky= */ false, + /* token= */ null, + UserHandle.myUserId(), + /* flags= */ 0); + receiver.setPendingResult(pendingResult); + } + + @Test + public void testSendTerminalResponseForSendSuccess() { + setBroadcastReceiverPendingResult(mCatService.mSmsBroadcastReceiver, Activity.RESULT_OK); + Intent intent = new Intent(SMS_SENT_ACTION).putExtra("cmdDetails", mCommandDetails); + intent.putExtra("ims", true); + mContext.sendOrderedBroadcast(intent, null, mCatService.mSmsBroadcastReceiver, null, + Activity.RESULT_OK, null, null); + processAllMessages(); + verify(mSimulatedCommands, never()).sendTerminalResponse( + any(), any()); + } + + @Test + public void testSendTerminalResponseForSendSmsRpError() { + setBroadcastReceiverPendingResult(mCatService.mSmsBroadcastReceiver, + SmsManager.RESULT_ERROR_GENERIC_FAILURE); + Intent intent = new Intent(SMS_SENT_ACTION).putExtra("cmdDetails", mCommandDetails); + intent.putExtra("ims", true); + intent.putExtra("errorCode", 41); + mContext.sendOrderedBroadcast(intent, null, mCatService.mSmsBroadcastReceiver, null, + SmsManager.RESULT_ERROR_GENERIC_FAILURE, null, null); + processAllMessages(); + //Verify if the command is encoded with correct Result byte as per TS 101.267 + verify(mSimulatedCommands, atLeastOnce()).sendTerminalResponse( + eq(mTerminalResponseForSmsRpError), any()); + } + + @Test + public void testSendTerminalResponseForSendSmsNetworkError() { + setBroadcastReceiverPendingResult(mCatService.mSmsBroadcastReceiver, + SmsManager.RESULT_ERROR_GENERIC_FAILURE); + Intent intent = new Intent(SMS_SENT_ACTION).putExtra("cmdDetails", mCommandDetails); + intent.putExtra("ims", false); + intent.putExtra("errorCode", 41); + mContext.sendOrderedBroadcast(intent, null, mCatService.mSmsBroadcastReceiver, null, + SmsManager.RESULT_ERROR_GENERIC_FAILURE, null, null); + processAllMessages(); + //Verify if the command is encoded with correct Result byte as per TS 101.267 + verify(mSimulatedCommands, atLeastOnce()).sendTerminalResponse( + eq(mTerminalResponseForNetworkUnableToProcess), any()); + } + + @Test + public void testSendTerminalResponseForDeliveryFailure() { + setBroadcastReceiverPendingResult(mCatService.mSmsBroadcastReceiver, + SmsManager.RESULT_ERROR_GENERIC_FAILURE); + Intent intent = new Intent(SMS_DELIVERY_ACTION).putExtra("cmdDetails", mCommandDetails); + mContext.sendOrderedBroadcast(intent, null, mCatService.mSmsBroadcastReceiver, null, + SmsManager.RESULT_ERROR_GENERIC_FAILURE, null, null); + processAllMessages(); + //Verify if the command is encoded with correct Result byte as per TS 101.267 + verify(mSimulatedCommands, atLeastOnce()).sendTerminalResponse( + eq(mTerminalResponseForTerminalUnableToProcess), any()); + } + + @Test + public void testSendTerminalResponseForDeliverySuccess() { + setBroadcastReceiverPendingResult(mCatService.mSmsBroadcastReceiver, + Activity.RESULT_OK); + Intent intent = new Intent(SMS_DELIVERY_ACTION).putExtra("cmdDetails", mCommandDetails); + mContext.sendOrderedBroadcast(intent, null, mCatService.mSmsBroadcastReceiver, null, + Activity.RESULT_OK, null, null); + processAllMessages(); + //Verify if the command is encoded with correct Result byte as per TS 101.267 + verify(mSimulatedCommands, atLeastOnce()).sendTerminalResponse( + eq(mTerminalResponseForDeliverySuccess), any()); + } } -- GitLab From 8558c3a8f3edc74ed4df2002939869ecaa1aa9a1 Mon Sep 17 00:00:00 2001 From: Daniel Banta Date: Thu, 26 Jan 2023 03:13:55 +0000 Subject: [PATCH 371/656] Fix DomainSelectionResolver in GsmCdmaPhoneTest.java Test: atest frameworks/opt/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java Bug: 266149976 Change-Id: I6fd3688bf7512e30940c921f39b88b7328ee5b02 --- .../com/android/internal/telephony/GsmCdmaPhoneTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 6f93d087b9..89f9d26308 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -130,6 +130,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { private UiccSlot mUiccSlot; private CommandsInterface mMockCi; private AdnRecordCache adnRecordCache; + private DomainSelectionResolver mDomainSelectionResolver; //mPhoneUnderTest private GsmCdmaPhone mPhoneUT; @@ -169,10 +170,11 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mUiccPort = Mockito.mock(UiccPort.class); mMockCi = Mockito.mock(CommandsInterface.class); adnRecordCache = Mockito.mock(AdnRecordCache.class); + mDomainSelectionResolver = Mockito.mock(DomainSelectionResolver.class); doReturn(false).when(mSST).isDeviceShuttingDown(); doReturn(true).when(mImsManager).isVolteEnabledByPlatform(); - - DomainSelectionResolver.make(mContext, false); + doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported(); + DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver); mPhoneUT = new GsmCdmaPhone(mContext, mSimulatedCommands, mNotifier, true, 0, PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager); @@ -190,6 +192,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void tearDown() throws Exception { mPhoneUT.removeCallbacksAndMessages(null); mPhoneUT = null; + DomainSelectionResolver.setDomainSelectionResolver(null); try { DeviceConfig.setProperties(mPreTestProperties); } catch (DeviceConfig.BadConfigException e) { -- GitLab From 0c368929ff9331cd0d3f634c4ddd0e1077286e69 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 21 Jan 2023 14:32:40 -0800 Subject: [PATCH 372/656] Fixed crash during eSIM activation Adapted the pre-U behavior for returning empty subscription list when callers do not have permissions. Fix: 266299303 Test: Performed eSIM activation and confirmed the crash is gone atest SubscriptionManagerServiceTest to catch the crash case. Change-Id: I91993a8e38606b961cdee54e858d7d882f50e57b --- .../SubscriptionManagerService.java | 21 ++++++++++++------- .../SubscriptionManagerServiceTest.java | 14 ++++++------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 0c7f32dcd5..e81ba3327b 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -100,6 +100,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -1638,8 +1639,6 @@ public class SubscriptionManagerService extends ISub.Stub { * * @return Sorted list of the currently {@link SubscriptionInfo} records available on the * device. - * - * @throws SecurityException if the caller does not have required permissions. */ @Override @NonNull @@ -1659,8 +1658,12 @@ public class SubscriptionManagerService extends ISub.Stub { if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, "getAllSubInfoList")) { - throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " - + "carrier privilege"); + // Ideally we should avoid silent failure, but since this API has already been used by + // many apps and they do not expect the security exception, we return an empty list + // here so it's consistent with pre-U behavior. + loge("getActiveSubscriptionInfoList: " + callingPackage + " does not have enough " + + "permission. Returning empty list here."); + return Collections.emptyList(); } return mSubscriptionDatabaseManager.getAllSubscriptions().stream() @@ -2262,8 +2265,6 @@ public class SubscriptionManagerService extends ISub.Stub { * @param callingFeatureId The feature in the package. * * @return The list of opportunistic subscription info that can be accessed by the callers. - * - * @throws SecurityException if callers do not hold the required permission. */ @Override @NonNull @@ -2283,8 +2284,12 @@ public class SubscriptionManagerService extends ISub.Stub { if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, "getOpportunisticSubscriptions")) { - throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " - + "carrier privilege"); + // Ideally we should avoid silent failure, but since this API has already been used by + // many apps and they do not expect the security exception, we return an empty list + // here so it's consistent with pre-U behavior. + loge("getOpportunisticSubscriptions: " + callingPackage + " does not have enough " + + "permission. Returning empty list here."); + return Collections.emptyList(); } return mSubscriptionDatabaseManager.getAllSubscriptions().stream() 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 d10c9df501..ef51d89512 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -54,7 +54,6 @@ import static org.mockito.ArgumentMatchers.nullable; 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.times; import static org.mockito.Mockito.verify; @@ -65,7 +64,6 @@ import android.app.PropertyInvalidatedCache; import android.compat.testing.PlatformCompatChangeRule; import android.content.Intent; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -660,9 +658,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // Remove MODIFY_PHONE_STATE mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); - // Should fail without READ_PHONE_STATE - assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT - .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE)); + // Should get an empty list without READ_PHONE_STATE. + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); // Grant READ_PHONE_STATE permission for insertion. mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); @@ -1063,9 +1061,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { testSetOpportunistic(); insertSubscription(FAKE_SUBSCRIPTION_INFO2); - // Should fail without READ_PHONE_STATE - assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT - .getOpportunisticSubscriptions(CALLING_PACKAGE, CALLING_FEATURE)); + // Should get an empty list without READ_PHONE_STATE. + assertThat(mSubscriptionManagerServiceUT.getOpportunisticSubscriptions( + CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); -- GitLab From 8e30609ade889777d6628ef7fcd5ef297db090ac Mon Sep 17 00:00:00 2001 From: Azhara Assanova Date: Thu, 26 Jan 2023 18:32:38 +0000 Subject: [PATCH 373/656] Allow mutable implicit PendingIntent Starting from target SDK U, creation of mutable PendingIntents with implicit Intents will be blocked for security reasons. This test creates such an object and fails, so a quick mitigation is to apply a flag PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT that bypasses the above block. The flag is introduced in ag/21018466. Bug: 266799056 Test: atest com.android.internal.telephony.SmsDispatchersControllerTest Change-Id: I94595c7dbc6c61cc36c33b7dda963d7ac7a93f1d --- .../internal/telephony/SmsDispatchersControllerTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java index 427963b10f..b073cd43c3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsDispatchersControllerTest.java @@ -616,7 +616,8 @@ public class SmsDispatchersControllerTest extends TelephonyTest { when(mTelephonyManager.isEmergencyNumber(eq("911"))).thenReturn(true); mSentIntent = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0, - new Intent(ACTION_TEST_SMS_SENT), PendingIntent.FLAG_MUTABLE); + new Intent(ACTION_TEST_SMS_SENT), PendingIntent.FLAG_MUTABLE + | PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT); } private void sendDataWithDomainSelection(@NetworkRegistrationInfo.Domain int domain, -- GitLab From 9834d96218abd3eff628206b4c0a82f6dd33eefe Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 25 Jan 2023 05:14:07 -0800 Subject: [PATCH 374/656] Use new carrier configs for unmetered network types DataNetwork check for whether network types are considered unmetered by carrier configs. Test: atest DataNetworkTest, DataNetworkControllerTest Test: basic manual tests Bug: 253146870 Change-Id: Ibfec3ce636173ee977b1b4c540d08778752cdc30 --- .../com/android/internal/telephony/data/DataNetwork.java | 9 ++++++--- .../telephony/data/DataNetworkControllerTest.java | 2 ++ .../android/internal/telephony/data/DataNetworkTest.java | 3 +++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 9ce3952d83..3bcd7f340e 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -2796,9 +2796,12 @@ public class DataNetwork extends StateMachine { log("updateMeteredAndCongested: mTempNotMeteredSupported changed to " + mTempNotMeteredSupported); } - if ((mDataNetworkController.getUnmeteredOverrideNetworkTypes().contains(networkType) - || isNetworkTypeUnmetered(networkType)) != mTempNotMetered) { - mTempNotMetered = !mTempNotMetered; + boolean isTempNotMetered = mDataConfigManager.isNetworkTypeUnmetered( + mTelephonyDisplayInfo, mPhone.getServiceState()) + && (mDataNetworkController.getUnmeteredOverrideNetworkTypes().contains(networkType) + || isNetworkTypeUnmetered(networkType)); + if (isTempNotMetered != mTempNotMetered) { + mTempNotMetered = isTempNotMetered; changed = true; log("updateMeteredAndCongested: mTempNotMetered changed to " + mTempNotMetered); } 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 801d7e0713..55e32cdc34 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -669,6 +669,8 @@ public class DataNetworkControllerTest extends TelephonyTest { mCarrierConfig.putBoolean(CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, true); + mCarrierConfig.putStringArray(CarrierConfigManager.KEY_UNMETERED_NETWORK_TYPES_STRING_ARRAY, + new String[] {"NR_NSA", "NR_NSA_MMWAVE", "NR_SA", "NR_SA_MMWAVE"}); mCarrierConfig.putIntArray(CarrierConfigManager.KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY, new int[]{TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_1xRTT, 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 135f7718af..16dd7f1439 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -56,6 +56,7 @@ import android.telephony.LteVopsSupportInfo; import android.telephony.NetworkRegistrationInfo; import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; +import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; @@ -337,6 +338,8 @@ public class DataNetworkTest extends TelephonyTest { doReturn(DataNetwork.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR) .when(mDataConfigManager).getBandwidthEstimateSource(); doReturn(true).when(mDataConfigManager).isTempNotMeteredSupportedByCarrier(); + doReturn(true).when(mDataConfigManager).isNetworkTypeUnmetered( + any(TelephonyDisplayInfo.class), any(ServiceState.class)); doReturn(true).when(mDataConfigManager).isImsDelayTearDownEnabled(); doReturn(DEFAULT_MTU).when(mDataConfigManager).getDefaultMtu(); doReturn(FAKE_IMSI).when(mPhone).getSubscriberId(); -- GitLab From 66fa0a9ef12b061f3cce85d7c85db841ab420f16 Mon Sep 17 00:00:00 2001 From: rambowang Date: Tue, 6 Dec 2022 23:26:02 -0600 Subject: [PATCH 375/656] Update UiccProfile with new CarrierConfigManager APIs - Replace carrier config change broadcast receiver with listener - Get subset of carrier config as needed to save memory Bug: 263267340 Test: atest UiccProfileTest Change-Id: I91f97dfb5363133d2928d1f6709bb8a754c4c733 --- .../internal/telephony/uicc/UiccProfile.java | 66 +++++++++++++++---- .../telephony/uicc/UiccProfileTest.java | 21 +++++- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index 7dec239fc1..6d73e58098 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -20,6 +20,7 @@ import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_VERIFICATION_FAILURE; import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_VERIFICATION_SUCCESS; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.usage.UsageStatsManager; @@ -125,6 +126,8 @@ public class UiccProfile extends IccCard { private final int mPhoneId; private final PinStorage mPinStorage; + private final CarrierConfigManager mCarrierConfigManager; + private static final int EVENT_RADIO_OFF_OR_UNAVAILABLE = 1; private static final int EVENT_ICC_LOCKED = 2; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @@ -185,14 +188,19 @@ public class UiccProfile extends IccCard { }; private boolean mUserUnlockReceiverRegistered; - private final BroadcastReceiver mCarrierConfigChangedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARRIER_CONFIG_CHANGED)); - } - } - }; + private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = + new CarrierConfigManager.CarrierConfigChangeListener() { + @Override + public void onCarrierConfigChanged(int logicalSlotIndex, int subscriptionId, + int carrierId, int specificCarrierId) { + if (logicalSlotIndex == mPhoneId) { + log("onCarrierConfigChanged: slotIndex=" + logicalSlotIndex + + ", subId=" + subscriptionId + ", carrierId=" + carrierId); + handleCarrierNameOverride(); + handleSimCountryIsoOverride(); + } + } + }; @VisibleForTesting public final Handler mHandler = new Handler() { @@ -341,9 +349,10 @@ public class UiccProfile extends IccCard { ci.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_UNAVAILABLE, null); resetProperties(); - IntentFilter intentfilter = new IntentFilter(); - intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - c.registerReceiver(mCarrierConfigChangedReceiver, intentfilter); + mCarrierConfigManager = c.getSystemService(CarrierConfigManager.class); + // Listener callback directly handles config change and thus runs on handler thread + mCarrierConfigManager.registerCarrierConfigChangeListener(mHandler::post, + mCarrierConfigChangeListener); } /** @@ -376,7 +385,11 @@ public class UiccProfile extends IccCard { InstallCarrierAppUtils.unregisterPackageInstallReceiver(mContext); mCi.unregisterForOffOrNotAvailable(mHandler); - mContext.unregisterReceiver(mCarrierConfigChangedReceiver); + + if (mCarrierConfigManager != null && mCarrierConfigChangeListener != null) { + mCarrierConfigManager.unregisterCarrierConfigChangeListener( + mCarrierConfigChangeListener); + } if (mCatService != null) mCatService.dispose(); for (UiccCardApplication app : mUiccApplications) { @@ -448,7 +461,15 @@ public class UiccProfile extends IccCard { return; } - PersistableBundle config = configLoader.getConfigForSubId(subId); + PersistableBundle config = + getCarrierConfigSubset( + subId, + CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL, + CarrierConfigManager.KEY_CARRIER_NAME_STRING); + if (config.isEmpty()) { + loge("handleCarrierNameOverride: fail to get carrier configs."); + return; + } boolean preferCcName = config.getBoolean( CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL, false); String ccName = config.getString(CarrierConfigManager.KEY_CARRIER_NAME_STRING); @@ -512,7 +533,13 @@ public class UiccProfile extends IccCard { return; } - PersistableBundle config = configLoader.getConfigForSubId(subId); + PersistableBundle config = + getCarrierConfigSubset( + subId, CarrierConfigManager.KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING); + if (config.isEmpty()) { + loge("handleSimCountryIsoOverride: fail to get carrier configs."); + return; + } String iso = config.getString(CarrierConfigManager.KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING); if (!TextUtils.isEmpty(iso) && !iso.equals(TelephonyManager.getSimCountryIsoForPhone(mPhoneId))) { @@ -1790,6 +1817,17 @@ public class UiccProfile extends IccCard { return null; } + @NonNull + private PersistableBundle getCarrierConfigSubset(int subId, String... keys) { + PersistableBundle bundle = new PersistableBundle(); + try { + bundle = mCarrierConfigManager.getConfigForSubId(subId, keys); + } catch (RuntimeException e) { + loge("CarrierConfigLoader is not available."); + } + return bundle; + } + private static String eventToString(int event) { switch (event) { case EVENT_RADIO_OFF_OR_UNAVAILABLE: return "RADIO_OFF_OR_UNAVAILABLE"; diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java index e139e958e3..63ae88a52d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java @@ -32,8 +32,8 @@ import static org.mockito.Mockito.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -import android.content.Intent; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Message; @@ -41,6 +41,7 @@ import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; +import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -70,6 +71,8 @@ public class UiccProfileTest extends TelephonyTest { } private IccIoResult mIccIoResult; + private PersistableBundle mBundle; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; private static final int UICCPROFILE_CARRIER_PRIVILEGE_LOADED_EVENT = 3; @@ -118,8 +121,18 @@ public class UiccProfileTest extends TelephonyTest { mIccCardStatus.mGsmUmtsSubscriptionAppIndex = -1; mIccIoResult = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes("FF40")); mSimulatedCommands.setIccIoResultForApduLogicalChannel(mIccIoResult); + mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); + + // Capture CarrierConfigChangeListener to emulate the carrier config change notification + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); mUiccProfile = new UiccProfile(mContext, mSimulatedCommands, mIccCardStatus, 0 /* phoneId */, mUiccCard, new Object()); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); + processAllMessages(); logd("Create UiccProfile"); @@ -130,6 +143,7 @@ public class UiccProfileTest extends TelephonyTest { public void tearDown() throws Exception { mUiccProfile = null; mIccIoResult = null; + mBundle = null; super.tearDown(); } @@ -535,8 +549,9 @@ public class UiccProfileTest extends TelephonyTest { carrierConfigBundle.putString(CarrierConfigManager.KEY_CARRIER_NAME_STRING, fakeCarrierName); - // broadcast CARRIER_CONFIG_CHANGED - mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + // send carrier config change + mCarrierConfigChangeListener.onCarrierConfigChanged(mPhone.getPhoneId(), mPhone.getSubId(), + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); // verify that setSimOperatorNameForPhone() is called with fakeCarrierName -- GitLab From 8955f098ab0c8071f5621230f89734b7661bcec8 Mon Sep 17 00:00:00 2001 From: rambowang Date: Tue, 6 Dec 2022 21:52:03 -0600 Subject: [PATCH 376/656] Update EmergencyNumberTracker with new CarrierConfigManager APIs - Replace carrier config change broadcast receiver with listener - Retrieve subset of carrier config as needed to save memory Bug: 263267340 Test: atest EmergencyNumberTrackerTest Change-Id: I7241243c892e5247ed336469bcdae158e337d1a2 --- .../emergency/EmergencyNumberTracker.java | 66 +++++++++++-------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 011a51fca0..4f63dee931 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -22,7 +22,6 @@ import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.res.Resources; import android.os.AsyncResult; import android.os.Environment; @@ -161,10 +160,6 @@ public class EmergencyNumberTracker extends Handler { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - onCarrierConfigChanged(); - return; - } else if (intent.getAction().equals( TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)) { int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY, -1); if (phoneId == mPhone.getPhoneId()) { @@ -191,23 +186,21 @@ public class EmergencyNumberTracker extends Handler { CarrierConfigManager configMgr = (CarrierConfigManager) mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); if (configMgr != null) { - PersistableBundle b = configMgr.getConfigForSubId(mPhone.getSubId()); - if (b != null) { + PersistableBundle b = getCarrierConfigSubset( + CarrierConfigManager.KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY); + if (!b.isEmpty()) { mEmergencyNumberPrefix = b.getStringArray( CarrierConfigManager.KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY); } + + // Callback which directly handle config change should be executed on handler thread + configMgr.registerCarrierConfigChangeListener(this::post, + (slotIndex, subId, carrierId, specificCarrierId) -> + onCarrierConfigUpdated(slotIndex)); } else { loge("CarrierConfigManager is null."); } - // Receive Carrier Config Changes - IntentFilter filter = new IntentFilter( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - // Receive Telephony Network Country Changes - filter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED); - - mPhone.getContext().registerReceiver(mIntentReceiver, filter); - mIsHalVersionLessThan1Dot4 = mPhone.getHalVersion(HAL_SERVICE_VOICE) .lessOrEqual(new HalVersion(1, 3)); } else { @@ -357,24 +350,43 @@ public class EmergencyNumberTracker extends Handler { } } - private void onCarrierConfigChanged() { + private void onCarrierConfigUpdated(int slotIndex) { if (mPhone != null) { - CarrierConfigManager configMgr = (CarrierConfigManager) - mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configMgr != null) { - PersistableBundle b = configMgr.getConfigForSubId(mPhone.getSubId()); - if (b != null) { - String[] emergencyNumberPrefix = b.getStringArray( + if (slotIndex != mPhone.getPhoneId()) return; + + PersistableBundle b = + getCarrierConfigSubset( CarrierConfigManager.KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY); - if (!Arrays.equals(mEmergencyNumberPrefix, emergencyNumberPrefix)) { - this.obtainMessage(EVENT_UPDATE_EMERGENCY_NUMBER_PREFIX, - emergencyNumberPrefix).sendToTarget(); - } + if (!b.isEmpty()) { + String[] emergencyNumberPrefix = + b.getStringArray( + CarrierConfigManager.KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY); + if (!Arrays.equals(mEmergencyNumberPrefix, emergencyNumberPrefix)) { + this.obtainMessage(EVENT_UPDATE_EMERGENCY_NUMBER_PREFIX, emergencyNumberPrefix) + .sendToTarget(); } } } else { - loge("onCarrierConfigChanged mPhone is null."); + loge("onCarrierConfigurationChanged mPhone is null."); + } + } + + @NonNull + private PersistableBundle getCarrierConfigSubset(String key) { + PersistableBundle bundle = new PersistableBundle(); + + if (mPhone != null) { + CarrierConfigManager ccm = + mPhone.getContext().getSystemService(CarrierConfigManager.class); + try { + if (ccm != null) { + bundle = ccm.getConfigForSubId(mPhone.getPhoneId(), key); + } + } catch (RuntimeException e) { + loge("CarrierConfigLoader is not available."); + } } + return bundle; } private String getInitialCountryIso() { -- GitLab From abe47623e0d66e0dbfbe2f577f6b0841cfd852c6 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 27 Jan 2023 13:31:59 -0800 Subject: [PATCH 377/656] Re-enabled two anomaly reports on U Test: Boot up and basic phone testing Change-Id: Ia359879cedfd23457926aa2c352b0f17ba92af87 --- .../com/android/internal/telephony/DisplayInfoController.java | 2 +- src/java/com/android/internal/telephony/NetworkIndication.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/DisplayInfoController.java b/src/java/com/android/internal/telephony/DisplayInfoController.java index 597ae90bd9..567331d459 100644 --- a/src/java/com/android/internal/telephony/DisplayInfoController.java +++ b/src/java/com/android/internal/telephony/DisplayInfoController.java @@ -143,7 +143,7 @@ public class DisplayInfoController extends Handler { } } catch (InvalidArgumentException e) { logel(e.getMessage()); - AnomalyReporter.reportAnomaly(UUID.fromString("3aa92a2c-94ed-46a0-a744-d6b1dfec2a55"), + AnomalyReporter.reportAnomaly(UUID.fromString("3aa92a2c-94ed-46a0-a744-d6b1dfec2a56"), e.getMessage(), mPhone.getCarrierId()); } } diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index 909006ee91..c9f235a491 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -313,7 +313,7 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { || (domain & ~NetworkRegistrationInfo.DOMAIN_CS_PS) != 0 || causeCode < 0 || additionalCauseCode < 0 || (causeCode == Integer.MAX_VALUE && additionalCauseCode == Integer.MAX_VALUE)) { - reportAnomaly(UUID.fromString("f16e5703-6105-4341-9eb3-e68189156eb4"), + reportAnomaly(UUID.fromString("f16e5703-6105-4341-9eb3-e68189156eb5"), "Invalid registrationFailed indication"); mRil.riljLoge("Invalid registrationFailed indication"); -- GitLab From a2406140328f7d6439e9a21ae0dbd5f5f75ad84e Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 26 Jan 2023 23:23:36 -0800 Subject: [PATCH 378/656] Added flag to enable subscription manager service through adb Test: Boot up and basic phone testing Test: adb root && adb shell device_config put telephony enable_subscription_manager_service true && adb shell device_config set_sync_disabled_for_tests persistent && sleep 3 && adb reboot Fix: 266896752 Change-Id: I14ff642402929bcfd39e6c20c50588ef8eec4eed --- src/java/com/android/internal/telephony/Phone.java | 6 +++++- .../android/internal/telephony/PhoneFactory.java | 6 +++++- .../internal/telephony/SubscriptionController.java | 13 +++++++++++++ .../subscription/SubscriptionManagerService.java | 14 ++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index da6382272b..0bc46dd59f 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -42,6 +42,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; import android.preference.PreferenceManager; +import android.provider.DeviceConfig; import android.sysprop.TelephonyProperties; import android.telecom.VideoProfile; import android.telephony.AccessNetworkConstants; @@ -627,8 +628,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // Initialize SMS stats mSmsStats = new SmsStats(this); + // This is a temp flag which will be removed before U AOSP public release. mIsSubscriptionManagerServiceEnabled = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_using_subscription_manager_service); + com.android.internal.R.bool.config_using_subscription_manager_service) + || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, + "enable_subscription_manager_service", false); if (isSubscriptionManagerServiceEnabled()) { mSubscriptionManagerService = SubscriptionManagerService.getInstance(); } diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index c69f84476a..e92660797d 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -34,6 +34,7 @@ import android.os.Build; import android.os.HandlerThread; import android.os.Looper; import android.preference.PreferenceManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.telephony.AnomalyReporter; @@ -124,8 +125,11 @@ public class PhoneFactory { if (!sMadeDefaults) { sContext = context; + // This is a temp flag which will be removed before U AOSP public release. sSubscriptionManagerServiceEnabled = context.getResources().getBoolean( - com.android.internal.R.bool.config_using_subscription_manager_service); + com.android.internal.R.bool.config_using_subscription_manager_service) + || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, + "enable_subscription_manager_service", false); // create the telephony device controller. TelephonyDevController.create(); diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 6f741474f5..bbdba56323 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -79,6 +79,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccController; @@ -403,6 +404,8 @@ public class SubscriptionController extends ISub.Stub { } }); + SubscriptionManager.invalidateSubscriptionManagerServiceEnabledCaches(); + if (DBG) logdl("[SubscriptionController] init by Context"); } @@ -4952,6 +4955,16 @@ public class SubscriptionController extends ISub.Stub { } } + /** + * @return {@code true} if using {@link SubscriptionManagerService} instead of + * {@link SubscriptionController}. + */ + //TODO: Removed before U AOSP public release. + @Override + public boolean isSubscriptionManagerServiceEnabled() { + return false; + } + /** * @hide */ diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index e81ba3327b..b4bfd0b334 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -82,6 +82,7 @@ import com.android.internal.telephony.MccTable; import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.telephony.data.PhoneSwitcher; @@ -542,6 +543,9 @@ public class SubscriptionManagerService extends ISub.Stub { mEuiccController = EuiccController.get(); } }); + + SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); + SubscriptionManager.invalidateSubscriptionManagerServiceEnabledCaches(); } /** @@ -3565,6 +3569,16 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * @return {@code true} if using {@link SubscriptionManagerService} instead of + * {@link SubscriptionController}. + */ + //TODO: Removed before U AOSP public release. + @Override + public boolean isSubscriptionManagerServiceEnabled() { + return true; + } + /** * Register the callback for receiving information from {@link SubscriptionManagerService}. * -- GitLab From ab945ee8a367a61a11e4d05db87f41b1367408da Mon Sep 17 00:00:00 2001 From: sangyun Date: Thu, 12 Jan 2023 07:14:57 +0900 Subject: [PATCH 379/656] Add unsatisfied NetworkRequest if retry networkRequest have been removed. Find the newly added unsatisfied NetworkRequest if NetworkRequests in the DataSetupRetryEntry have already been removed. Bug: 263476941 Test: basic phone testing Test: atest DataNetworkControllerTest Change-Id: I99a304e74020a8c861878b6adf8340b70f1333ae --- .../telephony/data/DataNetworkController.java | 11 ++++ .../data/DataNetworkControllerTest.java | 58 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 39edee359d..8dead5dd8b 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -2660,11 +2660,22 @@ public class DataNetworkController extends Handler { NetworkRequestList requestList = new NetworkRequestList( dataSetupRetryEntry.networkRequestList); requestList.removeIf(request -> !mAllNetworkRequestList.contains(request)); + // Retrieves the newly added unsatisfied NetworkRequest if all NetworkRequests in the + // DataSetupRetryEntry have already been removed. + if (requestList.isEmpty()) { + List groupRequestLists = getGroupedUnsatisfiedNetworkRequests(); + dataSetupRetryEntry.networkRequestList.stream() + .filter(request -> groupRequestLists.stream() + .anyMatch(groupRequestList -> groupRequestList + .get(request.getCapabilities()) != null)) + .forEach(requestList::add); + } if (requestList.isEmpty()) { loge("onDataNetworkSetupRetry: Request list is empty. Abort retry."); dataSetupRetryEntry.setState(DataRetryEntry.RETRY_STATE_CANCELLED); return; } + log("onDataNetworkSetupRetry: Request list:" + requestList); TelephonyNetworkRequest telephonyNetworkRequest = requestList.get(0); int networkCapability = telephonyNetworkRequest.getApnTypeNetworkCapability(); 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 de9d0ef61f..6623fd0099 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -2702,6 +2702,64 @@ public class DataNetworkControllerTest extends TelephonyTest { any(), any(), anyBoolean(), any(Message.class)); } + @Test + public void testSetupDataNetworkRetryFailedNetworkRequestRemovedAndAdded() throws Exception { + mDataNetworkControllerUT.getDataRetryManager() + .registerCallback(mMockedDataRetryManagerCallback); + setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.CONGESTION, + 10000, false); + + TelephonyNetworkRequest firstTnr = createNetworkRequest( + NetworkCapabilities.NET_CAPABILITY_IMS); + TelephonyNetworkRequest secondTnr = createNetworkRequest( + NetworkCapabilities.NET_CAPABILITY_IMS); + + mDataNetworkControllerUT.addNetworkRequest(firstTnr); + processAllMessages(); + + mDataNetworkControllerUT.removeNetworkRequest(firstTnr); + mDataNetworkControllerUT.addNetworkRequest(secondTnr); + processAllFutureMessages(); + + verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), + any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), + any(), any(), anyBoolean(), any(Message.class)); + + ArgumentCaptor retryEntry = + ArgumentCaptor.forClass(DataRetryManager.DataSetupRetryEntry.class); + verify(mMockedDataRetryManagerCallback, times(1)) + .onDataNetworkSetupRetry(retryEntry.capture()); + assertThat(retryEntry.getValue().getState()).isEqualTo( + DataRetryManager.DataRetryEntry.RETRY_STATE_FAILED); + assertThat(retryEntry.getValue().networkRequestList.size()).isEqualTo(1); + assertThat(retryEntry.getValue().networkRequestList.get(0)).isEqualTo(firstTnr); + + DataRetryManager.DataSetupRetryEntry dataSetupRetryEntry = retryEntry.getValue(); + logd("DataSetupRetryEntry:" + dataSetupRetryEntry); + + processAllMessages(); + processAllFutureMessages(); + + setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 1); + logd("Sending TAC_CHANGED event"); + mDataNetworkControllerUT.obtainMessage(25/*EVENT_TAC_CHANGED*/).sendToTarget(); + mDataNetworkControllerUT.getDataRetryManager().obtainMessage(10/*EVENT_TAC_CHANGED*/) + .sendToTarget(); + processAllFutureMessages(); + + // TAC changes should clear the already-scheduled retry and throttling. + assertThat(mDataNetworkControllerUT.getDataRetryManager().isAnySetupRetryScheduled( + mImsCellularDataProfile, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).isFalse(); + + // But DNC should re-evaluate unsatisfied request and setup IMS again. + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_MMTEL); + + verify(mMockedWwanDataServiceManager, times(2)).setupDataCall(anyInt(), + any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), + any(), any(), anyBoolean(), any(Message.class)); + } + @Test public void testSetupDataNetworkPermanentFailure() { setFailedSetupDataResponse(mMockedWwanDataServiceManager, DataFailCause.PROTOCOL_ERRORS, -- GitLab From 7638c935321c7046a6cc5bde60493bc15ed5b631 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 29 Jan 2023 16:35:23 -0800 Subject: [PATCH 380/656] Migrated carrier apps initialization code Moved the carrier apps initialization code from SubscriptionInfoUpdater, which will be removed soon. There is no logic change Fix: 267096646 Test: Boot up test + Basic phone testing + atest FrameworksTelephonyTests Change-Id: I042d0bd77dad016fda442ac789579e32875d10fe --- .../internal/telephony/GsmCdmaPhone.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 2da338b8af..af45417b79 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -34,6 +34,7 @@ import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOI import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.ContentValues; @@ -483,6 +484,10 @@ public class GsmCdmaPhone extends Phone { mCDM = new CarrierKeyDownloadManager(this); mCIM = new CarrierInfoManager(); + + if (isSubscriptionManagerServiceEnabled()) { + initializeCarrierApps(); + } } private void initRatSpecific(int precisePhoneType) { @@ -561,6 +566,31 @@ public class GsmCdmaPhone extends Phone { } } + /** + * Initialize the carrier apps. + */ + private void initializeCarrierApps() { + // Only perform on the default phone. There is no need to do it twice on the DSDS device. + if (mPhoneId != 0) return; + + logd("initializeCarrierApps"); + mContext.registerReceiverForAllUsers(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // Remove this line after testing + if (Intent.ACTION_USER_FOREGROUND.equals(intent.getAction())) { + UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); + // If couldn't get current user ID, guess it's 0. + CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), + TelephonyManager.getDefault(), + userHandle != null ? userHandle.getIdentifier() : 0, mContext); + } + } + }, new IntentFilter(Intent.ACTION_USER_FOREGROUND), null, null); + CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), + TelephonyManager.getDefault(), ActivityManager.getCurrentUser(), mContext); + } + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isPhoneTypeGsm() { return mPrecisePhoneType == PhoneConstants.PHONE_TYPE_GSM; -- GitLab From b70dee8e76bd5f1d4ff56af6c347f7660aba2448 Mon Sep 17 00:00:00 2001 From: Julian Thomassie Date: Wed, 4 Jan 2023 21:53:37 +0000 Subject: [PATCH 381/656] Conclude stats before saving/clearing TelephonyDebugService atoms Fixes: 231615417 Test: atest FrameworksTelephonyTests passes Test: manually triggered saveatoms Change-Id: I03a06c4c91114f17b945300717b1987faced01c1 --- .../internal/telephony/DebugService.java | 8 ++- .../telephony/metrics/MetricsCollector.java | 58 ++++++++++++++----- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/java/com/android/internal/telephony/DebugService.java b/src/java/com/android/internal/telephony/DebugService.java index 5cc730cc4f..3341577d04 100644 --- a/src/java/com/android/internal/telephony/DebugService.java +++ b/src/java/com/android/internal/telephony/DebugService.java @@ -52,13 +52,15 @@ public class DebugService { TelephonyMetrics.getInstance().dump(fd, pw, args); return; case "--saveatoms": - log("Saving atoms.."); - PhoneFactory.getMetricsCollector().getAtomsStorage().flushAtoms(); + if (Build.IS_DEBUGGABLE) { + log("Saving atoms.."); + PhoneFactory.getMetricsCollector().flushAtomsStorage(); + } return; case "--clearatoms": if (Build.IS_DEBUGGABLE) { log("Clearing atoms.."); - PhoneFactory.getMetricsCollector().getAtomsStorage().clearAtoms(); + PhoneFactory.getMetricsCollector().clearAtomsStorage(); } return; } diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 360eda8282..2a438bd315 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -263,6 +263,18 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return mStorage; } + /** Updates duration segments and calls {@link PersistAtomsStorage#flushAtoms()}. */ + public void flushAtomsStorage() { + concludeAll(); + mStorage.flushAtoms(); + } + + /** Updates duration segments and calls {@link PersistAtomsStorage#clearAtoms()}. */ + public void clearAtomsStorage() { + concludeAll(); + mStorage.clearAtoms(); + } + /** * Registers a {@link DataCallSessionStats} which will be pinged for on-going data calls when * data call atoms are pulled. @@ -276,6 +288,34 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { mOngoingDataCallStats.remove(call); } + private void concludeDataCallSessionStats() { + for (DataCallSessionStats stats : mOngoingDataCallStats) { + stats.conclude(); + } + } + + private void concludeImsStats() { + for (Phone phone : getPhonesIfAny()) { + ImsPhone imsPhone = (ImsPhone) phone.getImsPhone(); + if (imsPhone != null) { + imsPhone.getImsStats().conclude(); + } + } + } + + private void concludeServiceStateStats() { + for (Phone phone : getPhonesIfAny()) { + phone.getServiceStateTracker().getServiceStateStats().conclude(); + } + } + + private void concludeAll() { + concludeDataCallSessionStats(); + concludeImsStats(); + concludeServiceStateStats(); + RcsStats.getInstance().concludeSipTransportFeatureTagsStat(); + } + private static int pullSimSlotState(List data) { SimSlotState state; try { @@ -383,10 +423,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { private int pullDataCallSession(List data) { // Include ongoing data call segments - for (DataCallSessionStats stats : mOngoingDataCallStats) { - stats.conclude(); - } - + concludeDataCallSessionStats(); DataCallSession[] dataCallSessions = mStorage.getDataCallSessions(MIN_COOLDOWN_MILLIS); if (dataCallSessions != null) { Arrays.stream(dataCallSessions) @@ -414,10 +451,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { private int pullCellularServiceState(List data) { // Include the latest durations - for (Phone phone : getPhonesIfAny()) { - phone.getServiceStateTracker().getServiceStateStats().conclude(); - } - + concludeServiceStateStats(); CellularServiceState[] persistAtoms = mStorage.getCellularServiceStates(MIN_COOLDOWN_MILLIS); if (persistAtoms != null) { @@ -433,13 +467,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { private int pullImsRegistrationStats(List data) { // Include the latest durations - for (Phone phone : getPhonesIfAny()) { - ImsPhone imsPhone = (ImsPhone) phone.getImsPhone(); - if (imsPhone != null) { - imsPhone.getImsStats().conclude(); - } - } - + concludeImsStats(); ImsRegistrationStats[] persistAtoms = mStorage.getImsRegistrationStats(MIN_COOLDOWN_MILLIS); if (persistAtoms != null) { // list is already shuffled when instances were inserted -- GitLab From d858b758b0205f88b3cac191c5b972002c777788 Mon Sep 17 00:00:00 2001 From: joonhunshin Date: Mon, 30 Jan 2023 10:02:31 +0000 Subject: [PATCH 382/656] Conclude stats before saving/clearing TelephonyDebugService including RCS atoms Bug: 231615417 Test: atest FrameworksTelephonyTests passes Change-Id: I4707251e6b8e915750e980588c25aa6d3ebc36a3 --- .../internal/telephony/metrics/MetricsCollector.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 2a438bd315..634b739111 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -313,7 +313,14 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { concludeDataCallSessionStats(); concludeImsStats(); concludeServiceStateStats(); - RcsStats.getInstance().concludeSipTransportFeatureTagsStat(); + + RcsStats rcsStats = RcsStats.getInstance(); + if (rcsStats != null) { + rcsStats.concludeSipTransportFeatureTagsStat(); + rcsStats.onFlushIncompleteRcsAcsProvisioningStats(); + rcsStats.onFlushIncompleteImsRegistrationServiceDescStats(); + rcsStats.onFlushIncompleteImsRegistrationFeatureTagStats(); + } } private static int pullSimSlotState(List data) { -- GitLab From 4c5a2954fa7fb2f9db08762a99567047bc3c8686 Mon Sep 17 00:00:00 2001 From: Ayush Sharma Date: Mon, 12 Dec 2022 17:00:24 +0000 Subject: [PATCH 383/656] Show switch to managed profile dialog When subscription is asscoiated with managed profile, show an error dialog to switch to managed profile for sending sms/mms. Bug: 258629881 Test: Manual atest com.android.internal.telephony.SmsControllerTest, Change-Id: I0a568d5efc39432c73201090da035cd008d84316 --- .../internal/telephony/SmsController.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index c33dbe2232..1fd4b66b85 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -35,7 +35,6 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.TelephonyServiceManager.ServiceRegisterer; -import android.os.UserHandle; import android.provider.Telephony.Sms.Intents; import android.telephony.CarrierConfigManager; import android.telephony.SmsManager; @@ -46,6 +45,7 @@ import android.telephony.TelephonyManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.subscription.SubscriptionManagerService; +import com.android.internal.telephony.util.TelephonyUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -164,7 +164,9 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - // TODO(b/258629881): Display error dialog. + if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { + TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); + } sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); return; } @@ -261,7 +263,9 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - // TODO(b/258629881): Display error dialog. + if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { + TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); + } sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); return; } @@ -344,7 +348,9 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - // TODO(b/258629881): Display error dialog. + if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { + TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); + } sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); return; } @@ -382,7 +388,9 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - // TODO(b/258629881): Display error dialog. + if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { + TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); + } sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_USER_NOT_ALLOWED); return; } @@ -418,7 +426,9 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - // TODO(b/258629881): Display error dialog. + if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { + TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); + } sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_USER_NOT_ALLOWED); return; } @@ -924,7 +934,9 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - // TODO(b/258629881): Display error dialog. + if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { + TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); + } sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); return; } -- GitLab From 53fc0cc057bbb7523da56559551ccfe9b2921b29 Mon Sep 17 00:00:00 2001 From: Gil Cukierman Date: Thu, 26 Jan 2023 17:11:35 +0000 Subject: [PATCH 384/656] Handle Device Admin Updates to 2G per Phone Instance Problem: A previous implementation (aosp/2371949) honoring the no_cellular_2g restriction operated at the subscription level and was complex and prone to race conditions between subscription loading and carrier configs. This manifested in devices booting without applying the admin policy sometimes. Solution: Move the enforcement of the admin policy into each instance of Phone. Before allowed network types are sent to the modem, a check against the admin policy is performed. If the no_cellular_2g restriction is set, 2g is disabled in the effective bitmap that is passed to the modem. Note that Phone.sendSubscriptionSetting is called by ServiceStateTracker when a new subscription is added so this change is piggy backing off of that call to ensure the admin policy gets enforced on every call. Introduce BroadcastReceiver, TelephonyAdminReceiver, that calls Phone.sendSubscriptionSettings when the relevant 2g admin policy changes. Bug: 266472206 Test: atest TelephonyAdminReceiver Test: atest GsmCdmaPhoneTest Test: Manual testing on cuttlefish with the TestDPC app. Asserted that the 2g admin policy is applied on boot and persisted across reboots. Change-Id: Iaf15dca36c4a1b383d75b65d157578fdeb4ad989 --- .../com/android/internal/telephony/Phone.java | 8 ++ .../telephony/TelephonyAdminReceiver.java | 100 ++++++++++++++++++ .../internal/telephony/GsmCdmaPhoneTest.java | 27 +++++ .../telephony/TelephonyAdminReceiverTest.java | 89 ++++++++++++++++ 4 files changed, 224 insertions(+) create mode 100644 src/java/com/android/internal/telephony/TelephonyAdminReceiver.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/TelephonyAdminReceiverTest.java diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 0bc46dd59f..e2641f4a43 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -280,6 +280,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { public static final String PREF_NULL_CIPHER_AND_INTEGRITY_ENABLED = "pref_null_cipher_and_integrity_enabled"; + private final TelephonyAdminReceiver m2gAdminUpdater; /** * This method is invoked when the Phone exits Emergency Callback Mode. @@ -636,6 +637,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { if (isSubscriptionManagerServiceEnabled()) { mSubscriptionManagerService = SubscriptionManagerService.getInstance(); } + m2gAdminUpdater = new TelephonyAdminReceiver(context, this); if (getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { return; @@ -2324,6 +2326,12 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { if (!mIsCarrierNrSupported) { allowedNetworkTypes &= ~TelephonyManager.NETWORK_TYPE_BITMASK_NR; } + if (m2gAdminUpdater.isCellular2gDisabled()) { + logd("SubId " + getSubId() + + " disabling 2g in getEffectiveAllowedNetworkTypes according to admin user " + + "restriction"); + allowedNetworkTypes &= ~TelephonyManager.NETWORK_CLASS_BITMASK_2G; + } logd("SubId" + getSubId() + ",getEffectiveAllowedNetworkTypes: " + TelephonyManager.convertNetworkTypeBitmaskToString(allowedNetworkTypes)); return allowedNetworkTypes; diff --git a/src/java/com/android/internal/telephony/TelephonyAdminReceiver.java b/src/java/com/android/internal/telephony/TelephonyAdminReceiver.java new file mode 100644 index 0000000000..994405ba9a --- /dev/null +++ b/src/java/com/android/internal/telephony/TelephonyAdminReceiver.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2023 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; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.UserManager; +import android.telephony.Rlog; + +/** + * A BroadcastReceiver for device administration events. + */ +public class TelephonyAdminReceiver extends BroadcastReceiver { + private static final String TAG = "TelephonyAdminReceiver"; + private final Phone mPhone; + // We keep track of the last value to avoid updating when unrelated user restrictions change + private boolean mDisallowCellular2gRestriction = false; + private final Context mContext; + private UserManager mUserManager; + + public TelephonyAdminReceiver(Context context, Phone phone) { + mContext = context; + mPhone = phone; + mUserManager = null; + if (ensureUserManagerExists()) { + mDisallowCellular2gRestriction = mUserManager.hasUserRestriction( + UserManager.DISALLOW_CELLULAR_2G); + } + IntentFilter filter = new IntentFilter(); + filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED); + context.registerReceiver(this, filter); + } + + @Override + public void onReceive(Context context, Intent intent) { + Rlog.d(TAG, "Processing onReceive"); + if (context == null || intent == null) return; + if (!intent.getAction().equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) { + Rlog.d(TAG, "Ignoring unexpected action: " + intent.getAction()); + return; + } + if (!ensureUserManagerExists()) { + return; + } + boolean shouldDisallow2g = mUserManager.hasUserRestriction( + UserManager.DISALLOW_CELLULAR_2G); + + if (shouldDisallow2g != mDisallowCellular2gRestriction) { + Rlog.i(TAG, + "Updating allowed network types with new admin 2g restriction. no_cellular_2g: " + + shouldDisallow2g); + mDisallowCellular2gRestriction = shouldDisallow2g; + mPhone.sendSubscriptionSettings(false); + } else { + Rlog.i(TAG, "Skipping update of allowed network types. Restriction no_cellular_2g " + + "unchanged: " + mDisallowCellular2gRestriction); + } + } + + /** + * Returns the current state of the {@link UserManager#DISALLOW_CELLULAR_2G} user restriction. + */ + public boolean isCellular2gDisabled() { + return mDisallowCellular2gRestriction; + } + + /** + * Tries to resolve the user manager system service. Returns true if successful, false + * otherwise. + */ + private boolean ensureUserManagerExists() { + if (mUserManager == null) { + Rlog.d(TAG, "No user manager. Attempting to resolve one."); + mUserManager = mContext.getSystemService(UserManager.class); + } + if (mUserManager == null) { + Rlog.e(TAG, + "Could not get a user manager instance. All operations will be no-ops until " + + "one is resolved"); + return false; + } + return true; + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 89f9d26308..26ccf79cd5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -63,6 +63,7 @@ import android.os.Handler; import android.os.Message; import android.os.PersistableBundle; import android.os.Process; +import android.os.UserManager; import android.os.WorkSource; import android.preference.PreferenceManager; import android.provider.DeviceConfig; @@ -92,6 +93,7 @@ import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.imsphone.ImsPhone; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.test.SimulatedCommandsVerifier; import com.android.internal.telephony.uicc.AdnRecord; @@ -2685,4 +2687,29 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.handleMessage(message); verify(mSimulatedCommandsVerifier, times(2)).getImei(nullable(Message.class)); } + + @Test + public void testSetAllowedNetworkTypes_admin2gRestrictionHonored() throws Exception { + // circumvent loading/saving to sim db. it's not behavior under test. + TelephonyManager.setupISubForTest(Mockito.mock(SubscriptionManagerService.class)); + TelephonyManager.enableServiceHandleCaching(); + mPhoneUT.loadAllowedNetworksFromSubscriptionDatabase(); + + // 2g is disabled by admin + UserManager userManagerMock = mContext.getSystemService(UserManager.class); + when(userManagerMock.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(true); + mContext.sendBroadcast(new Intent(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)); + + // carrier requests 2g to be enabled + mPhoneUT.setAllowedNetworkTypes(TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER, + TelephonyManager.NETWORK_CLASS_BITMASK_2G, null); + + // Assert that 2g was not passed as an allowed network type to the modem + ArgumentCaptor captureBitMask = ArgumentCaptor.forClass(Integer.class); + // One call for the admin restriction update, another by this test + verify(mSimulatedCommandsVerifier, times(2)).setAllowedNetworkTypesBitmap( + captureBitMask.capture(), + nullable(Message.class)); + assertEquals(0, captureBitMask.getValue() & TelephonyManager.NETWORK_CLASS_BITMASK_2G); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyAdminReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyAdminReceiverTest.java new file mode 100644 index 0000000000..397c8bab4b --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyAdminReceiverTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2023 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; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Intent; +import android.os.UserManager; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class TelephonyAdminReceiverTest extends TelephonyTest { + + private TelephonyAdminReceiver mTelephonyAdminReceiver; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + mTelephonyAdminReceiver = new TelephonyAdminReceiver(mContext, mPhone); + } + + @Test + public void test_nullUserManager() { + mUserManager = null; + TelephonyAdminReceiver telephonyAdminReceiver = new TelephonyAdminReceiver(mContext, + mPhone); + assertFalse(telephonyAdminReceiver.isCellular2gDisabled()); + } + + @Test + public void test_nullIntent_noUpdate() { + assertFalse(mTelephonyAdminReceiver.isCellular2gDisabled()); + + mContext.sendBroadcast(new Intent(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)); + + verify(mPhone, never()).sendSubscriptionSettings(anyBoolean()); + assertFalse(mTelephonyAdminReceiver.isCellular2gDisabled()); + } + + @Test + public void test_userRestrictionsNotChanged_noUpdate() { + assertFalse(mTelephonyAdminReceiver.isCellular2gDisabled()); + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(false); + + mContext.sendBroadcast(new Intent(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)); + + verify(mPhone, never()).sendSubscriptionSettings(anyBoolean()); + assertFalse(mTelephonyAdminReceiver.isCellular2gDisabled()); + } + + @Test + public void test_userRestrictionToggled_shouldUpdate() { + assertFalse(mTelephonyAdminReceiver.isCellular2gDisabled()); + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn( + true).thenReturn(false); + + mContext.sendBroadcast(new Intent(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)); + assertTrue(mTelephonyAdminReceiver.isCellular2gDisabled()); + + mContext.sendBroadcast(new Intent(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)); + assertFalse(mTelephonyAdminReceiver.isCellular2gDisabled()); + verify(mPhone, times(2)).sendSubscriptionSettings(false); + } +} -- GitLab From 24f60d181041068215df205ad1fc9cc06897a043 Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 5 Dec 2022 22:32:16 -0600 Subject: [PATCH 385/656] Update PinStorage with new CarrierConfigManager APIs - Replace carrier config change receiver with listener - Retrieve subset carrier config to save memory Bug: 244087782 Test: atest PinStorageTest Change-Id: I519c66cbae205735ed8a4d39c34557c9a5789cb4 --- .../internal/telephony/uicc/PinStorage.java | 33 ++++++++-------- .../telephony/uicc/PinStorageTest.java | 38 +++++++++++++++---- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/PinStorage.java b/src/java/com/android/internal/telephony/uicc/PinStorage.java index ed16ee4403..acec14e83d 100644 --- a/src/java/com/android/internal/telephony/uicc/PinStorage.java +++ b/src/java/com/android/internal/telephony/uicc/PinStorage.java @@ -132,7 +132,6 @@ public class PinStorage extends Handler { // Events private static final int ICC_CHANGED_EVENT = 1; - private static final int CARRIER_CONFIG_CHANGED_EVENT = 2; private static final int TIMER_EXPIRATION_EVENT = 3; private static final int USER_UNLOCKED_EVENT = 4; private static final int SUPPLY_PIN_COMPLETE = 5; @@ -156,14 +155,11 @@ public class PinStorage extends Handler { private final SparseArray mRamStorage; /** Receiver for the required intents. */ - private final BroadcastReceiver mCarrierConfigChangedReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) { - int slotId = intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, -1); - sendMessage(obtainMessage(CARRIER_CONFIG_CHANGED_EVENT, slotId, 0)); - } else if (TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED.equals(action) + if (TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED.equals(action) || TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED.equals(action)) { int slotId = intent.getIntExtra(PhoneConstants.PHONE_KEY, -1); int state = intent.getIntExtra( @@ -188,11 +184,16 @@ public class PinStorage extends Handler { // Register for necessary intents. IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intentFilter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); intentFilter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); - mContext.registerReceiver(mCarrierConfigChangedReceiver, intentFilter); + mContext.registerReceiver(mBroadcastReceiver, intentFilter); + + CarrierConfigManager ccm = mContext.getSystemService(CarrierConfigManager.class); + // Callback directly handle config change and should be executed in handler thread + ccm.registerCarrierConfigChangeListener(this::post, + (slotIndex, subId, carrierId, specificCarrierId) -> + onCarrierConfigurationChanged(slotIndex)); // Initialize the long term secret key. This needs to be present in all cases: // - if the device is not secure or is locked: key does not require user authentication @@ -560,7 +561,7 @@ public class PinStorage extends Handler { } } - private void onCarrierConfigChanged(int slotId) { + private void onCarrierConfigurationChanged(int slotId) { logv("onCarrierConfigChanged[%d]", slotId); if (!isCacheAllowed(slotId)) { logd("onCarrierConfigChanged[%d] - PIN caching not allowed", slotId); @@ -590,9 +591,6 @@ public class PinStorage extends Handler { case ICC_CHANGED_EVENT: onSimStatusChange(/* slotId= */ msg.arg1, /* state= */ msg.arg2); break; - case CARRIER_CONFIG_CHANGED_EVENT: - onCarrierConfigChanged(/* slotId= */ msg.arg1); - break; case TIMER_EXPIRATION_EVENT: onTimerExpiration(); break; @@ -995,12 +993,15 @@ public class PinStorage extends Handler { mContext.getSystemService(CarrierConfigManager.class); if (configManager != null) { Phone phone = PhoneFactory.getPhone(slotId); - if (phone != null) { - // If an invalid subId is used, this bundle will contain default values. - config = configManager.getConfigForSubId(phone.getSubId()); + try { + // If an invalid subId is used, this bundle will contain default values. + config = configManager.getConfigForSubId(phone.getSubId(), + CarrierConfigManager.KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL); + } catch (RuntimeException e) { + loge("Can't get carrier config subset."); } } - if (config == null) { + if (config == null || config.isEmpty()) { config = CarrierConfigManager.getDefaultConfig(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/PinStorageTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/PinStorageTest.java index a8c74d5db4..ea6c778c86 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/PinStorageTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/PinStorageTest.java @@ -19,8 +19,11 @@ import static com.android.internal.telephony.uicc.IccCardStatus.PinState.PINSTAT import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Intent; @@ -29,6 +32,7 @@ import android.os.WorkSource; import android.preference.PreferenceManager; import android.provider.Settings; import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -44,6 +48,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -58,19 +64,38 @@ public class PinStorageTest extends TelephonyTest { private int mBootCount; private int mSimulatedRebootsCount; private PinStorage mPinStorage; + private PersistableBundle mBundle; + + // mocks + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; private void simulateReboot() { mSimulatedRebootsCount++; Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.BOOT_COUNT, mBootCount + mSimulatedRebootsCount); + createPinStorageAndCaptureListener(); + } + + private void createPinStorageAndCaptureListener() { + // Capture listener to emulate the carrier config change notification used later + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); mPinStorage = new PinStorage(mContext); mPinStorage.mShortTermSecretKeyDurationMinutes = 0; + verify(mCarrierConfigManager, atLeastOnce()).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); } @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + mCarrierConfigChangeListener = Mockito.mock( + CarrierConfigManager.CarrierConfigChangeListener.class); + + mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); // Store boot count, so that correct value can be restored at the end. mBootCount = Settings.Global.getInt( @@ -89,8 +114,7 @@ public class PinStorageTest extends TelephonyTest { when(mKeyguardManager.isDeviceSecure()).thenReturn(false); when(mKeyguardManager.isDeviceLocked()).thenReturn(false); - mPinStorage = new PinStorage(mContext); - mPinStorage.mShortTermSecretKeyDurationMinutes = 0; + createPinStorageAndCaptureListener(); } @After @@ -341,7 +365,7 @@ public class PinStorageTest extends TelephonyTest { PersistableBundle carrierConfigs = new PersistableBundle(); carrierConfigs.putBoolean( CarrierConfigManager.KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL, false); - when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(carrierConfigs); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(carrierConfigs); mPinStorage.storePin("1234", 0); @@ -362,10 +386,10 @@ public class PinStorageTest extends TelephonyTest { PersistableBundle carrierConfigs = new PersistableBundle(); carrierConfigs.putBoolean( CarrierConfigManager.KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL, false); - when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(carrierConfigs); - final Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, 0); - mContext.sendBroadcast(intent); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(carrierConfigs); + mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); int result = mPinStorage.prepareUnattendedReboot(sWorkSource); -- GitLab From b97d340e24fef02cd465e379d557ddcdc66c017d Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Fri, 20 Jan 2023 18:59:23 -0800 Subject: [PATCH 386/656] Support pointing APIs Test: atest SatelliteManagerTest Bug: 266249740 Change-Id: Ib7588ec540046ae85eface8a4eb64424c6e8e620 --- .../com/android/internal/telephony/Phone.java | 63 +++++++++++++++++++ .../com/android/internal/telephony/RIL.java | 24 ++++++- .../android/internal/telephony/RILUtils.java | 40 ++++++++++++ 3 files changed, 125 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 0bc46dd59f..4c13b40f13 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5230,6 +5230,69 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { callback.accept(TelephonyManager.CELL_BROADCAST_RESULT_UNSUPPORTED); } + /** + * Start receiving satellite position updates. + * This can be called by the pointing UI when the user starts pointing to the satellite. + * Modem should continue to report the pointing input as the device or satellite moves. + * + * @param result The Message to send to result of the operation to. + **/ + public void startSatellitePositionUpdates(Message result) { + mCi.startSendingSatellitePointingInfo(result); + } + + /** + * Stop receiving satellite position updates. + * This can be called by the pointing UI when the user stops pointing to the satellite. + * + * @param result The Message to send to result of the operation to. + **/ + public void stopSatellitePositionUpdates(Message result) { + mCi.stopSendingSatellitePointingInfo(result); + } + + /** + * Registers for pointing info changed from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForSatellitePointingInfoChanged(@NonNull Handler h, + int what, @Nullable Object obj) { + mCi.registerForSatellitePointingInfoChanged(h, what, obj); + } + + /** + * Unregisters for pointing info changed from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForSatellitePointingInfoChanged(@NonNull Handler h) { + mCi.unregisterForSatellitePointingInfoChanged(h); + } + + /** + * Registers for messages transfer complete from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForSatelliteMessagesTransferComplete(@NonNull Handler h, + int what, @Nullable Object obj) { + mCi.registerForSatelliteMessagesTransferComplete(h, what, obj); + } + + /** + * Unregisters for messages transfer complete from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForSatelliteMessagesTransferComplete(@NonNull Handler h) { + mCi.unregisterForSatelliteMessagesTransferComplete(h); + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 7db9da5035..206a558b3d 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -6162,7 +6162,17 @@ public class RIL extends BaseCommands implements CommandsInterface { public void startSendingSatellitePointingInfo(Message result) { RadioSatelliteProxy radioSatelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; + if (radioSatelliteProxy.isEmpty()) { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, + "startSendingSatellitePointingInfo: RADIO_NOT_AVAILABLE"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); + result.sendToTarget(); + } + } if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RILRequest rr = obtainRequest(RIL_REQUEST_START_SENDING_SATELLITE_POINTING_INFO, result, mRILDefaultWorkSource); @@ -6200,7 +6210,17 @@ public class RIL extends BaseCommands implements CommandsInterface { public void stopSendingSatellitePointingInfo(Message result) { RadioSatelliteProxy radioSatelliteProxy = getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; + if (radioSatelliteProxy.isEmpty()) { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, + "startSendingSatellitePointingInfo: RADIO_NOT_AVAILABLE"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); + result.sendToTarget(); + } + } if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { RILRequest rr = obtainRequest(RIL_REQUEST_STOP_SENDING_SATELLITE_POINTING_INFO, result, mRILDefaultWorkSource); diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 059bfbb89e..c7a888158f 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -376,6 +376,7 @@ import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsRegistrationImplBase.ImsDeregistrationReason; import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteCapabilities; +import android.telephony.satellite.SatelliteManager; import android.telephony.satellite.stub.SatelliteImplBase; import android.text.TextUtils; import android.util.ArraySet; @@ -5934,6 +5935,7 @@ public class RILUtils { default: return SatelliteImplBase.FEATURE_UNKNOWN; } } + /** * Convert from android.hardware.radio.satellite.PointingInfo to * android.telephony.satellite.stub.PointingInfo @@ -5973,6 +5975,44 @@ public class RILUtils { return halPointingInfo; } + /** + * Convert satellite-related errors from CommandException.Error to + * SatelliteManager.SatelliteServiceResult. + * @param error The satellite error. + * @return The converted SatelliteServiceResult. + */ + @SatelliteManager.SatelliteServiceResult public static int convertToSatelliteError( + CommandException.Error error) { + switch (error) { + case INTERNAL_ERR: + return SatelliteManager.SATELLITE_SERVICE_INTERNAL_ERROR; + case MODEM_ERR: + return SatelliteManager.SATELLITE_SERVICE_MODEM_ERROR; + case SYSTEM_ERR: + return SatelliteManager.SATELLITE_SERVICE_SYSTEM_ERROR; + case INVALID_ARGUMENTS: + return SatelliteManager.SATELLITE_SERVICE_INVALID_ARGUMENTS; + case INVALID_MODEM_STATE: + return SatelliteManager.SATELLITE_SERVICE_INVALID_MODEM_STATE; + case INVALID_SIM_STATE: + return SatelliteManager.SATELLITE_SERVICE_INVALID_SIM_STATE; + case INVALID_STATE: + return SatelliteManager.SATELLITE_SERVICE_INVALID_STATE; + case RADIO_NOT_AVAILABLE: + return SatelliteManager.SATELLITE_SERVICE_NOT_AVAILABLE; + case REQUEST_NOT_SUPPORTED: + return SatelliteManager.SATELLITE_SERVICE_NOT_SUPPORTED; + case REQUEST_RATE_LIMITED: + return SatelliteManager.SATELLITE_SERVICE_RATE_LIMITED; + case NO_MEMORY: + return SatelliteManager.SATELLITE_SERVICE_NO_MEMORY; + case NO_RESOURCES: + return SatelliteManager.SATELLITE_SERVICE_NO_RESOURCES; + default: + return SatelliteManager.SATELLITE_SERVICE_ERROR; + } + } + /** * Converts the call state to HAL IMS call state. * -- GitLab From 8f5c8641f5c57c0bef27f392c0326d5eb116e70d Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 30 Jan 2023 00:09:30 -0800 Subject: [PATCH 387/656] Query embedded subscriptions after user unlock Migrated the old code from SubscriptionInfoUpdater to SubscriptionManagerService. There is no logic change. Fix: 267124129 Test: Basic telephony testing + atest SubscriptionManagerServiceTest Change-Id: If6b4685f3453f0cdcdf61f5d32a45740af28587f --- .../SubscriptionManagerService.java | 31 ++++++++++- .../SubscriptionManagerServiceTest.java | 52 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index b4bfd0b334..47db501071 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -27,8 +27,10 @@ import android.app.PendingIntent; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.os.Binder; @@ -544,6 +546,13 @@ public class SubscriptionManagerService extends ISub.Stub { } }); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateEmbeddedSubscriptions(); + } + }, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); + SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); SubscriptionManager.invalidateSubscriptionManagerServiceEnabledCaches(); } @@ -986,7 +995,7 @@ public class SubscriptionManagerService extends ISub.Stub { for (int cardId : cardIds) { GetEuiccProfileInfoListResult result = mEuiccController .blockingGetEuiccProfileInfoList(cardId); - log("updateEmbeddedSubscriptions: cardId=" + cardId + ", result=" + result); + logl("updateEmbeddedSubscriptions: cardId=" + cardId + ", result=" + result); if (result.getResult() != EuiccService.RESULT_OK) { loge("Failed to get euicc profile info. result=" @@ -1073,6 +1082,26 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Update embedded subscriptions from {@link EuiccController}. + */ + private void updateEmbeddedSubscriptions() { + UiccSlot[] uiccSlots = mUiccController.getUiccSlots(); + if (uiccSlots != null) { + List cardIds = new ArrayList<>(); + for (UiccSlot uiccSlot : uiccSlots) { + if (uiccSlot != null && uiccSlot.isEuicc() && uiccSlot.getUiccCard() != null) { + int cardId = mUiccController.convertToPublicCardId( + uiccSlot.getUiccCard().getCardId()); + cardIds.add(cardId); + } + } + if (!cardIds.isEmpty()) { + updateEmbeddedSubscriptions(cardIds, null); + } + } + } + /** * Check if the SIM application is enabled on the card or not. * 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 ef51d89512..23d94e2717 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -91,6 +91,8 @@ import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; +import com.android.internal.telephony.uicc.UiccCard; +import com.android.internal.telephony.uicc.UiccSlot; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; @@ -126,6 +128,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // mocked private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback; private EuiccController mEuiccController; + private UiccSlot mUiccSlot; + private UiccCard mUiccCard; @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule(); @@ -144,8 +148,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(true).when(mTelephonyManager).isVoiceCapable(); mEuiccController = Mockito.mock(EuiccController.class); replaceInstance(EuiccController.class, "sInstance", null, mEuiccController); + mUiccSlot = Mockito.mock(UiccSlot.class); + mUiccCard = Mockito.mock(UiccCard.class); mMockedSubscriptionManagerServiceCallback = Mockito.mock( SubscriptionManagerServiceCallback.class); + doReturn(mUiccCard).when(mUiccSlot).getUiccCard(); + doReturn(FAKE_ICCID1).when(mUiccCard).getCardId(); + ((MockContentResolver) mContext.getContentResolver()).addProvider( Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); @@ -1686,4 +1695,47 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList( CALLING_PACKAGE, CALLING_FEATURE).isEmpty()).isTrue(); } + + @Test + public void testUserUnlockUpdateEmbeddedSubscriptions() { + doReturn(true).when(mUiccSlot).isEuicc(); + doReturn(1).when(mUiccController).convertToPublicCardId(FAKE_ICCID1); + doReturn(new UiccSlot[]{mUiccSlot}).when(mUiccController).getUiccSlots(); + + EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID1) + .setIccid(FAKE_ICCID1) + .setNickname(FAKE_CARRIER_NAME1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL) + .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC1, FAKE_MNC1, null, 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(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1)); + + mContext.sendBroadcast(new Intent(Intent.ACTION_USER_UNLOCKED)); + processAllMessages(); + + verify(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo.getSubscriptionId()).isEqualTo(1); + assertThat(subInfo.getSimSlotIndex()).isEqualTo(SubscriptionManager.INVALID_SIM_SLOT_INDEX); + assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID1); + assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); + assertThat(subInfo.getDisplayNameSource()).isEqualTo( + SubscriptionManager.NAME_SOURCE_CARRIER); + assertThat(subInfo.getMcc()).isEqualTo(FAKE_MCC1); + assertThat(subInfo.getMnc()).isEqualTo(FAKE_MNC1); + assertThat(subInfo.getProfileClass()).isEqualTo( + SubscriptionManager.PROFILE_CLASS_OPERATIONAL); + assertThat(subInfo.isEmbedded()).isTrue(); + assertThat(subInfo.isRemovableEmbedded()).isFalse(); + assertThat(subInfo.getNativeAccessRules()).isEqualTo(FAKE_NATIVE_ACCESS_RULES1); + } } -- GitLab From 50fe189f378aab9505acd581ad39b2a6ec8f9629 Mon Sep 17 00:00:00 2001 From: Gil Cukierman Date: Tue, 24 Jan 2023 16:59:13 -0500 Subject: [PATCH 388/656] Ensure We Never Serialize Bad allowed_network_types_for_reason Keys Into Sim DB Change the default case to throwing an exception. Better to not silently fail and corrupt the DB. Add test cases for loading network types from the SIM DB, including serialization and deserialization. The cases cover both the existence of bad keys and values in the DB and ensure we ignore those on loadr. and the assurance that we will not write an unknown value into the SIM DB. Bug: 266472206 Test: atest GsmCdmaPhoneTest Test: Manual testing; force a bad value into the sim db and ensure we don't read it back.(adb root; adb shell content query --uri content://telephony/siminfo) Change-Id: I62ae213d75047b8abd0469ee6e12c5d4fa43b539 --- .../com/android/internal/telephony/Phone.java | 10 ++- .../internal/telephony/GsmCdmaPhoneTest.java | 69 +++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index e2641f4a43..457c6fee44 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -2446,7 +2446,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } int key = convertAllowedNetworkTypeDbNameToMapIndex(networkTypesValues[0]); long value = Long.parseLong(networkTypesValues[1]); - if (key != INVALID_ALLOWED_NETWORK_TYPES + if (TelephonyManager.isValidAllowedNetworkTypesReason(key) && value != INVALID_ALLOWED_NETWORK_TYPES) { synchronized (mAllowedNetworkTypesForReasons) { mAllowedNetworkTypesForReasons.put(key, value); @@ -2484,7 +2484,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } } - private String convertAllowedNetworkTypeMapIndexToDbName(int reason) { + private String convertAllowedNetworkTypeMapIndexToDbName( + @TelephonyManager.AllowedNetworkTypesReason int reason) { switch (reason) { case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER: return ALLOWED_NETWORK_TYPES_TEXT_USER; @@ -2495,7 +2496,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G: return ALLOWED_NETWORK_TYPES_TEXT_ENABLE_2G; default: - return Integer.toString(INVALID_ALLOWED_NETWORK_TYPES); + throw new IllegalArgumentException( + "No DB name conversion available for allowed network type reason: " + reason + + ". Did you forget to add an ALLOWED_NETWORK_TYPE_TEXT entry for" + + " a new reason?"); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 26ccf79cd5..b9331b7c80 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -76,6 +76,7 @@ import android.telephony.CellIdentityCdma; import android.telephony.CellIdentityGsm; import android.telephony.LinkCapacityEstimate; import android.telephony.NetworkRegistrationInfo; +import android.telephony.RadioAccessFamily; import android.telephony.ServiceState; import android.telephony.SmsCbMessage; import android.telephony.SubscriptionInfo; @@ -1565,6 +1566,74 @@ public class GsmCdmaPhoneTest extends TelephonyTest { assertEquals(false, mPhoneUT.isAllowedNetworkTypesLoadedFromDb()); } + @Test + public void testLoadAllowedNetworksFromSubscriptionDatabase_allValidData() { + int subId = 1; + doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); + + // 13 == TelephonyManager.NETWORK_TYPE_LTE + // NR_BITMASK == 4096 == 1 << (13 - 1) + String validSerializedNetworkMap = "user=4096,power=4096,carrier=4096,enable_2g=4096"; + doReturn(validSerializedNetworkMap).when(mSubscriptionController).getSubscriptionProperty( + anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); + + assertFalse(mPhoneUT.isAllowedNetworkTypesLoadedFromDb()); + mPhoneUT.loadAllowedNetworksFromSubscriptionDatabase(); + assertTrue(mPhoneUT.isAllowedNetworkTypesLoadedFromDb()); + + for (int i = 0; i < 4; ++i) { + assertEquals(TelephonyManager.NETWORK_TYPE_BITMASK_LTE, + mPhoneUT.getAllowedNetworkTypes(i)); + } + } + + @Test + public void testLoadAllowedNetworksFromSubscriptionDatabase_invalidKeys() { + int subId = 1; + doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); + + // 13 == TelephonyManager.NETWORK_TYPE_LTE + // NR_BITMASK == 4096 == 1 << (13 - 1) + String validSerializedNetworkMap = + "user=4096,power=4096,carrier=4096,enable_2g=4096,-1=4096"; + doReturn(validSerializedNetworkMap).when(mSubscriptionController).getSubscriptionProperty( + anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); + + assertFalse(mPhoneUT.isAllowedNetworkTypesLoadedFromDb()); + mPhoneUT.loadAllowedNetworksFromSubscriptionDatabase(); + assertTrue(mPhoneUT.isAllowedNetworkTypesLoadedFromDb()); + + for (int i = 0; i < 4; ++i) { + assertEquals(TelephonyManager.NETWORK_TYPE_BITMASK_LTE, + mPhoneUT.getAllowedNetworkTypes(i)); + } + } + + @Test + public void testLoadAllowedNetworksFromSubscriptionDatabase_invalidValues() { + int subId = 1; + doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); + + // 19 == TelephonyManager.NETWORK_TYPE_NR + // NR_BITMASK == 524288 == 1 << 19 + String validSerializedNetworkMap = "user=4096,power=4096,carrier=4096,enable_2g=-1"; + doReturn(validSerializedNetworkMap).when(mSubscriptionController).getSubscriptionProperty( + anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); + + mPhoneUT.loadAllowedNetworksFromSubscriptionDatabase(); + + for (int i = 0; i < 3; ++i) { + assertEquals(TelephonyManager.NETWORK_TYPE_BITMASK_LTE, + mPhoneUT.getAllowedNetworkTypes(i)); + } + + long defaultAllowedNetworkTypes = RadioAccessFamily.getRafFromNetworkType( + RILConstants.PREFERRED_NETWORK_MODE); + assertEquals(defaultAllowedNetworkTypes, mPhoneUT.getAllowedNetworkTypes( + TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G)); + + } + /** * Verifies that an emergency call placed on a SIM which does NOT explicitly define a number as * an emergency call will still be placed as an emergency call. -- GitLab From e72b0874d2d66772db59d2795fd1f622f849a910 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Sat, 28 Jan 2023 00:49:47 +0000 Subject: [PATCH 389/656] Add log for triggerEmergencyNetworkScan Bug: 243344927 Test: build and flash Change-Id: Ia13f4e94de915df0c9b9f2cf284d86a3645b046d --- .../com/android/internal/telephony/RIL.java | 4 +- .../android/internal/telephony/RILUtils.java | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 7db9da5035..6f3487efa7 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5545,7 +5545,9 @@ public class RIL extends BaseCommands implements CommandsInterface { mRILDefaultWorkSource); if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + + " networkType=" + RILUtils.accessNetworkTypesToString(accessNetwork) + + ", scanType=" + RILUtils.scanTypeToString(scanType)); } try { diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 059bfbb89e..4990984532 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -4754,6 +4754,47 @@ public class RILUtils { } } + /** Converts the array of network types to readable String array */ + public static @NonNull String accessNetworkTypesToString( + @NonNull @AccessNetworkConstants.RadioAccessNetworkType int[] accessNetworkTypes) { + int length = accessNetworkTypes.length; + StringBuilder sb = new StringBuilder("{"); + if (length > 0) { + sb.append(Arrays.stream(accessNetworkTypes) + .mapToObj(RILUtils::accessNetworkTypeToString) + .collect(Collectors.joining(","))); + } + sb.append("}"); + return sb.toString(); + } + + private static @NonNull String accessNetworkTypeToString( + @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType) { + switch (accessNetworkType) { + case AccessNetworkConstants.AccessNetworkType.UNKNOWN: return "UNKNOWN"; + case AccessNetworkConstants.AccessNetworkType.GERAN: return "GERAN"; + case AccessNetworkConstants.AccessNetworkType.UTRAN: return "UTRAN"; + case AccessNetworkConstants.AccessNetworkType.EUTRAN: return "EUTRAN"; + case AccessNetworkConstants.AccessNetworkType.CDMA2000: return "CDMA2000"; + case AccessNetworkConstants.AccessNetworkType.IWLAN: return "IWLAN"; + case AccessNetworkConstants.AccessNetworkType.NGRAN: return "NGRAN"; + default: return Integer.toString(accessNetworkType); + } + } + + /** Converts scan type to readable String */ + public static @NonNull String scanTypeToString( + @DomainSelectionService.EmergencyScanType int scanType) { + switch (scanType) { + case DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE: + return "LIMITED_SERVICE"; + case DomainSelectionService.SCAN_TYPE_FULL_SERVICE: + return "FULL_SERVICE"; + default: + return "NO_PREFERENCE"; + } + } + /** Convert IMS deregistration reason */ public static @ImsDeregistrationReason int convertHalDeregistrationReason(int reason) { switch (reason) { -- GitLab From fbc24970c56a288321046dd9f446166a9d75f60b Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Tue, 24 Jan 2023 19:05:12 +0000 Subject: [PATCH 390/656] Added getMaxCharPerTextMessage() API. Bug: 260896985 Test: atest CtsTelephonyTestCases Change-Id: Ie42bf3091a4d7b24842c9346f7032e0db0f4ca17 --- src/java/com/android/internal/telephony/Phone.java | 9 +++++++++ src/java/com/android/internal/telephony/RILUtils.java | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index d0ad53ed58..3c7bb44921 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5263,6 +5263,15 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.stopSendingSatellitePointingInfo(result); } + /** + * Get maximum number of characters per text message on satellite. + * @param result - message object which contains maximum characters on success + * and error code on failure. + */ + public void getMaxCharactersPerSatelliteTextMessage(Message result) { + mCi.getMaxCharactersPerSatelliteTextMessage(result); + } + /** * Registers for pointing info changed from satellite modem. * diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 9d17276ca7..364a385c91 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -6026,7 +6026,6 @@ public class RILUtils { CommandException.Error error) { switch (error) { case INTERNAL_ERR: - return SatelliteManager.SATELLITE_SERVICE_INTERNAL_ERROR; case MODEM_ERR: return SatelliteManager.SATELLITE_SERVICE_MODEM_ERROR; case SYSTEM_ERR: -- GitLab From b25144ccd002cfb0c203a33e880f00cccc2b2bc4 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Sun, 20 Nov 2022 16:46:13 +0000 Subject: [PATCH 391/656] IMPU system API implementation Bug: 237347020 Test:atest frameworks/opt/telephony/tests/telephonytests/src/com/android/internal/telephony Change-Id: I9bc81424178fdda70b8ed34229fe81351076ab52 --- .../telephony/PhoneSubInfoController.java | 39 +++++++++ .../telephony/PhoneSubInfoControllerTest.java | 83 +++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java index 0dcf221032..17055a7f47 100644 --- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java +++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java @@ -47,6 +47,9 @@ import com.android.internal.telephony.uicc.UiccCardApplication; import com.android.internal.telephony.uicc.UiccPort; import com.android.telephony.Rlog; +import java.util.ArrayList; +import java.util.List; + public class PhoneSubInfoController extends IPhoneSubInfo.Stub { private static final String TAG = "PhoneSubInfoController"; private static final boolean DBG = true; @@ -410,6 +413,42 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { }); } + /** + * Fetches the ISIM public user identities (EF_IMPU) from UICC based on subId + * + * @param subId subscriptionId + * @param callingPackage package name of the caller + * @param callingFeatureId feature Id of the caller + * @return List of public user identities of type android.net.Uri or empty list if + * EF_IMPU is not available. + * @throws IllegalArgumentException if the subscriptionId is not valid + * @throws IllegalStateException in case the ISIM hasn’t been loaded. + * @throws SecurityException if the caller does not have the required permission + */ + public List getImsPublicUserIdentities(int subId, String callingPackage, + String callingFeatureId) { + if (TelephonyPermissions. + checkCallingOrSelfReadPrivilegedPhoneStatePermissionOrReadPhoneNumber( + mContext, subId, callingPackage, callingFeatureId, "getImsPublicUserIdentities")) { + Phone phone = getPhone(subId); + assert phone != null; + IsimRecords isimRecords = phone.getIsimRecords(); + if (isimRecords != null) { + String[] impus = isimRecords.getIsimImpu(); + List impuList = new ArrayList<>(); + for (String impu : impus) { + if (impu != null && impu.trim().length() > 0) { + impuList.add(Uri.parse(impu)); + } + } + return impuList; + } + throw new IllegalStateException("ISIM is not loaded"); + } else { + throw new IllegalArgumentException("Invalid SubscriptionID = " + subId); + } + } + /** * get the Isim Ist based on subId */ diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java index 7bbefca881..55ead0a43e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java @@ -21,6 +21,7 @@ import static android.telephony.TelephonyManager.APPTYPE_ISIM; import static android.telephony.TelephonyManager.APPTYPE_USIM; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -35,6 +36,7 @@ import android.app.AppOpsManager; import android.app.PropertyInvalidatedCache; import android.content.Context; import android.content.pm.PackageManager; +import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.RemoteException; @@ -52,6 +54,8 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import java.util.List; + public class PhoneSubInfoControllerTest extends TelephonyTest { private static final String FEATURE_ID = "myfeatureId"; private static final String PSI_SMSC_TEL1 = "tel:+91123456789"; @@ -1212,4 +1216,83 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { assertTrue(ex.getMessage().contains("Invalid SubscriptionID")); } } + + @Test + public void getImsPublicUserIdentities() { + String[] refImpuArray = new String[3]; + refImpuArray[0] = "012345678"; + refImpuArray[1] = "sip:test@verify.com"; + refImpuArray[2] = "tel:+91987754324"; + doReturn(mIsimUiccRecords).when(mPhone).getIsimRecords(); + doReturn(refImpuArray).when(mIsimUiccRecords).getIsimImpu(); + + List impuList = mPhoneSubInfoControllerUT.getImsPublicUserIdentities(0, TAG, + FEATURE_ID); + + assertNotNull(impuList); + assertEquals(refImpuArray.length, impuList.size()); + assertEquals(impuList.get(0).toString(), refImpuArray[0]); + assertEquals(impuList.get(1).toString(), refImpuArray[1]); + assertEquals(impuList.get(2).toString(), refImpuArray[2]); + } + + @Test + public void getImsPublicUserIdentities_InvalidImpu() { + String[] refImpuArray = new String[3]; + refImpuArray[0] = null; + refImpuArray[2] = ""; + refImpuArray[2] = "tel:+91987754324"; + doReturn(mIsimUiccRecords).when(mPhone).getIsimRecords(); + doReturn(refImpuArray).when(mIsimUiccRecords).getIsimImpu(); + List impuList = mPhoneSubInfoControllerUT.getImsPublicUserIdentities(0, TAG, + FEATURE_ID); + assertNotNull(impuList); + // Null or Empty string cannot be converted to URI + assertEquals(refImpuArray.length - 2, impuList.size()); + } + + @Test + public void getImsPublicUserIdentities_IsimNotLoadedError() { + doReturn(null).when(mPhone).getIsimRecords(); + + try { + mPhoneSubInfoControllerUT.getImsPublicUserIdentities(0, TAG, FEATURE_ID); + fail(); + } catch (Exception ex) { + assertTrue(ex instanceof IllegalStateException); + assertTrue(ex.getMessage().contains("ISIM is not loaded")); + } + } + + @Test + public void getImsPublicUserIdentities_InValidSubIdCheck() { + try { + mPhoneSubInfoControllerUT.getImsPublicUserIdentities(-1, TAG, FEATURE_ID); + fail(); + } catch (Exception ex) { + assertTrue(ex instanceof IllegalArgumentException); + assertTrue(ex.getMessage().contains("Invalid SubscriptionID")); + } + } + + @Test + public void getImsPublicUserIdentities_NoReadPrivilegedPermission() { + mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); + String[] refImpuArray = new String[3]; + refImpuArray[0] = "012345678"; + refImpuArray[1] = "sip:test@verify.com"; + refImpuArray[2] = "tel:+91987754324"; + doReturn(mIsimUiccRecords).when(mPhone).getIsimRecords(); + doReturn(refImpuArray).when(mIsimUiccRecords).getIsimImpu(); + + List impuList = mPhoneSubInfoControllerUT.getImsPublicUserIdentities(0, TAG, + FEATURE_ID); + + assertNotNull(impuList); + assertEquals(refImpuArray.length, impuList.size()); + assertEquals(impuList.get(0).toString(), refImpuArray[0]); + assertEquals(impuList.get(1).toString(), refImpuArray[1]); + assertEquals(impuList.get(2).toString(), refImpuArray[2]); + mContextFixture.addCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE); + } } \ No newline at end of file -- GitLab From de3bb2f4e38215d6b81cc7fb0ba47cd11f4f86ae Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 5 Dec 2022 11:51:04 -0600 Subject: [PATCH 392/656] Update SignalStrengthController with new CarrierConfigManager APIs - Replace carrier config change receiver with listener which has much lower lagency - Due to a large list of carrier configs are used and the list may change in near future, getConfigForSubId is NOT replaced with subset version. Bug: 263267340 Test: atest SignalStrengthControllerTest Change-Id: Iab2ba44e502bb1134f2db9f3cd95c4a228e69c97 --- .../telephony/SignalStrengthController.java | 35 +++++-------------- .../SignalStrengthControllerTest.java | 25 ++++++++----- 2 files changed, 25 insertions(+), 35 deletions(-) diff --git a/src/java/com/android/internal/telephony/SignalStrengthController.java b/src/java/com/android/internal/telephony/SignalStrengthController.java index 0c32f83c0e..bb8573156a 100644 --- a/src/java/com/android/internal/telephony/SignalStrengthController.java +++ b/src/java/com/android/internal/telephony/SignalStrengthController.java @@ -20,10 +20,7 @@ import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; 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.os.AsyncResult; import android.os.Handler; import android.os.IBinder; @@ -100,7 +97,6 @@ public class SignalStrengthController extends Handler { 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; - private static final int EVENT_CARRIER_CONFIG_CHANGED = 10; @NonNull private final Phone mPhone; @@ -145,20 +141,6 @@ public class SignalStrengthController extends Handler { @NonNull private final LocalLog mLocalLog = new LocalLog(64); - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) { - int phoneId = intent.getExtras().getInt(CarrierConfigManager.EXTRA_SLOT_INDEX); - // Ignore the carrier config changed if the phoneId is not matched. - if (phoneId == mPhone.getPhoneId()) { - sendEmptyMessage(EVENT_CARRIER_CONFIG_CHANGED); - } - } - } - }; - public SignalStrengthController(@NonNull Phone phone) { mPhone = phone; mCi = mPhone.mCi; @@ -168,10 +150,12 @@ public class SignalStrengthController extends Handler { mCi.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); setSignalStrengthDefaultValues(); + CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); mCarrierConfig = getCarrierConfig(); - IntentFilter filter = new IntentFilter(); - filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - mPhone.getContext().registerReceiver(mBroadcastReceiver, filter); + // Callback which directly handle config change should be executed on handler thread + ccm.registerCarrierConfigChangeListener(this::post, + (slotIndex, subId, carrierId, specificCarrierId) -> + onCarrierConfigurationChanged(slotIndex)); } @Override @@ -284,11 +268,6 @@ public class SignalStrengthController extends Handler { break; } - case EVENT_CARRIER_CONFIG_CHANGED: { - onCarrierConfigChanged(); - break; - } - default: log("Unhandled message with number: " + msg.what); break; @@ -1129,7 +1108,9 @@ public class SignalStrengthController extends Handler { return earfcnPairList; } - private void onCarrierConfigChanged() { + private void onCarrierConfigurationChanged(int slotIndex) { + if (slotIndex != mPhone.getPhoneId()) return; + mCarrierConfig = getCarrierConfig(); log("Carrier Config changed."); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java index f72bf98519..b2f118d531 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SignalStrengthControllerTest.java @@ -25,6 +25,7 @@ import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; @@ -34,7 +35,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.content.Intent; import android.os.Handler; import android.os.Message; import android.os.PersistableBundle; @@ -50,6 +50,7 @@ import android.telephony.CellSignalStrengthWcdma; import android.telephony.SignalStrength; import android.telephony.SignalStrengthUpdateRequest; import android.telephony.SignalThresholdInfo; +import android.telephony.TelephonyManager; import android.test.suitebuilder.annotation.MediumTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -94,16 +95,13 @@ public class SignalStrengthControllerTest extends TelephonyTest { private SignalStrengthController mSsc; private PersistableBundle mBundle; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; @Before public void setUp() throws Exception { super.setUp(this.getClass().getSimpleName()); mHandler = Mockito.mock(Handler.class); - when(mPhone.getSubId()).thenReturn(ACTIVE_SUB_ID); - mSsc = new SignalStrengthController(mPhone); - replaceInstance(Handler.class, "mLooper", mHandler, mSsc.getLooper()); - replaceInstance(Phone.class, "mLooper", mPhone, mSsc.getLooper()); // Config a fixed supported RAN/MeasurementTypes to make the test more stable mBundle = mContextFixture.getCarrierConfigBundle(); @@ -153,6 +151,18 @@ public class SignalStrengthControllerTest extends TelephonyTest { 15, /* SIGNAL_STRENGTH_GOOD */ 30 /* SIGNAL_STRENGTH_GREAT */ }); + + // Capture listener to emulate the carrier config change notification used later + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); + mSsc = new SignalStrengthController(mPhone); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); + + replaceInstance(Handler.class, "mLooper", mHandler, mSsc.getLooper()); + replaceInstance(Phone.class, "mLooper", mPhone, mSsc.getLooper()); + processAllMessages(); reset(mSimulatedCommandsVerifier); } @@ -964,9 +974,8 @@ public class SignalStrengthControllerTest extends TelephonyTest { .thenReturn(mockConfigManager); when(mockConfigManager.getConfigForSubId(anyInt())).thenReturn(mBundle); - Intent intent = new Intent().setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, PHONE_ID); - mContext.sendBroadcast(intent); + mCarrierConfigChangeListener.onCarrierConfigChanged(PHONE_ID, ACTIVE_SUB_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); } -- GitLab From e1296ad853b0983e43c88e6e3da4345292df7b96 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 2 Feb 2023 13:19:11 +0000 Subject: [PATCH 393/656] Add log for onSrvccCallNotified Bug: 217654931 Test: build Change-Id: I456de08decaa8e7705fbfc5195668995bb4cf235 --- .../telephony/imsphone/ImsPhoneCallTracker.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index ebd71e743e..77a96d19f6 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -5973,6 +5973,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { @VisibleForTesting public SrvccConnection[] convertToSrvccConnectionInfo(List profileList) { if (mSrvccTypeSupported.isEmpty() || profileList == null || profileList.isEmpty()) { + loge("convertToSrvccConnectionInfo empty list"); return null; } @@ -5981,9 +5982,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { if (isCallProfileSupported(profile)) { addConnection(connList, profile, findConnection(profile.getCallId())); + } else { + logi("convertToSrvccConnectionInfo not supported" + + " state=" + profile.getPreciseCallState()); } } + logi("convertToSrvccConnectionInfo size=" + connList.size()); if (connList.isEmpty()) return null; return connList.toArray(new SrvccConnection[0]); } @@ -6013,9 +6018,12 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } private boolean isCallProfileSupported(SrvccCall profile) { - if (profile == null) return false; + if (profile == null) { + loge("isCallProfileSupported null profile"); + return false; + } - switch(profile.getPreciseCallState()) { + switch (profile.getPreciseCallState()) { case PRECISE_CALL_STATE_ACTIVE: return mSrvccTypeSupported.contains(BASIC_SRVCC_SUPPORT); case PRECISE_CALL_STATE_HOLDING: @@ -6031,6 +6039,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { case PRECISE_CALL_STATE_INCOMING_SETUP: return mSrvccTypeSupported.contains(PREALERTING_SRVCC_SUPPORT); default: + loge("isCallProfileSupported invalid state=" + + profile.getPreciseCallState()); break; } return false; -- GitLab From 64ba97f03ed37ae4a143d475fe9f8e0bd06f75cf Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 3 Feb 2023 09:33:31 -0800 Subject: [PATCH 394/656] Log raw fail cause to metrics Fix: 267531460 Test: Boot up + Basic phone funcationality tests Test: atest FrameworksTelephonyTests Change-Id: I0dc4641dab2bdb64475e83cd130de5cb1ecf6c30 --- .../android/internal/telephony/data/DataNetwork.java | 11 +++++++---- .../telephony/metrics/DataCallSessionStats.java | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 3bcd7f340e..4293ea4f99 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -2446,7 +2446,8 @@ public class DataNetwork extends StateMachine { getDataNetworkType(), apnTypeBitmask, protocol, - mFailCause); + // Log the raw fail cause to avoid large amount of UNKNOWN showing on metrics. + response != null ? response.getCause() : mFailCause); } /** @@ -3263,7 +3264,7 @@ public class DataNetwork extends StateMachine { mDataNetworkCallback.invokeFromExecutor( () -> mDataNetworkCallback.onHandoverFailed(DataNetwork.this, mFailCause, retry, handoverFailureMode)); - trackHandoverFailure(); + trackHandoverFailure(response != null ? response.getCause() : mFailCause); } // No matter handover succeeded or not, transit back to connected state. @@ -3273,13 +3274,15 @@ public class DataNetwork extends StateMachine { /** * Called when handover failed. Record the source and target RAT{@link NetworkType} and the * failure cause {@link android.telephony.DataFailCause}. + * + * @param cause The fail cause. */ - private void trackHandoverFailure() { + private void trackHandoverFailure(int cause) { int sourceRat = getDataNetworkType(); int targetTransport = DataUtils.getTargetTransport(mTransport); int targetRat = getDataNetworkType(targetTransport); - mDataCallSessionStats.onHandoverFailure(mFailCause, sourceRat, targetRat); + mDataCallSessionStats.onHandoverFailure(cause, sourceRat, targetRat); } /** diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java index 83192f9f26..6c711a9e85 100644 --- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java @@ -84,14 +84,14 @@ public class DataCallSessionStats { * @param currentRat The data call current Network Type * @param apnTypeBitmask APN type bitmask * @param protocol Data connection protocol - * @param failureCause failure cause as per android.telephony.DataFailCause + * @param failureCause The raw failure cause from modem/IWLAN data service. */ public synchronized void onSetupDataCallResponse( @Nullable DataCallResponse response, @NetworkType int currentRat, @ApnType int apnTypeBitmask, @ProtocolType int protocol, - @DataFailureCause int failureCause) { + int failureCause) { // there should've been a call to onSetupDataCall to initiate the atom, // so this method is being called out of order -> no metric will be logged if (mDataCallSession == null) { -- GitLab From b96f5086fdd832e312bc33bdb3a36bb42ced3a76 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Sun, 5 Feb 2023 16:44:45 +0000 Subject: [PATCH 395/656] Check mIsWaitingForScanResult before calling cancelEmergencyNetworkScan() onCancel can be called multiple times through other call flow while disposing the connection Bug: 267723171 Test: atest DomainSelectionConnectionTest Change-Id: Ic145b92e6a17c63b3d2c18e64262e23216c75fb5 --- .../domainselection/DomainSelectionConnection.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java index e10c199c83..7f79853e78 100644 --- a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java @@ -341,8 +341,10 @@ public class DomainSelectionConnection { } private void onCancel(boolean resetScan) { - mIsWaitingForScanResult = false; - mPhone.cancelEmergencyNetworkScan(resetScan, null); + if (mIsWaitingForScanResult) { + mIsWaitingForScanResult = false; + mPhone.cancelEmergencyNetworkScan(resetScan, null); + } } /** @@ -390,7 +392,7 @@ public class DomainSelectionConnection { mPhone.unregisterForEmergencyNetworkScan(mHandler); mRegisteredRegistrant = false; } - if (mIsWaitingForScanResult) onCancel(true); + onCancel(true); mController.removeConnection(this); if (mLooper != null) mLooper.quitSafely(); mLooper = null; -- GitLab From b9e264533c7776c879421a2bf2675c8bb4307a1c Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Sun, 5 Feb 2023 14:48:01 -0800 Subject: [PATCH 396/656] Update IRadio module AIDL versions Convert IRadioService#getInterfaceVersion into the corresponding HalVersion for each service/module. Test: atest RILTest, RILE2eTests Bug: 267940733 Change-Id: I4c7c4bf5f2def3b148d85fb1367a5b1d6ba004bb --- .../com/android/internal/telephony/RIL.java | 13 ++++ .../internal/telephony/RadioDataProxy.java | 21 ++---- .../internal/telephony/RadioImsProxy.java | 21 ++---- .../telephony/RadioMessagingProxy.java | 21 ++---- .../internal/telephony/RadioModemProxy.java | 21 ++---- .../internal/telephony/RadioNetworkProxy.java | 24 ++----- .../telephony/RadioSatelliteProxy.java | 65 ++++++++----------- .../internal/telephony/RadioSimProxy.java | 24 ++----- .../internal/telephony/RadioVoiceProxy.java | 21 ++---- 9 files changed, 75 insertions(+), 156 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 1c5b82f929..e6546149b2 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -7216,6 +7216,19 @@ public class RIL extends BaseCommands implements CommandsInterface { return halVersion; } + /** + * Get the HAL version corresponding to the interface version of a IRadioService module. + * @param interfaceVersion The interface version, from IRadioService#getInterfaceVersion(). + * @return The corresponding HalVersion. + */ + public static HalVersion getServiceHalVersion(int interfaceVersion) { + switch (interfaceVersion) { + case 1: return RADIO_HAL_VERSION_2_0; + case 2: return RADIO_HAL_VERSION_2_1; + default: return RADIO_HAL_VERSION_UNKNOWN; + } + } + private static String serviceToString(@HalService int service) { switch (service) { case HAL_SERVICE_RADIO: diff --git a/src/java/com/android/internal/telephony/RadioDataProxy.java b/src/java/com/android/internal/telephony/RadioDataProxy.java index f1105458e1..9671077b0f 100644 --- a/src/java/com/android/internal/telephony/RadioDataProxy.java +++ b/src/java/com/android/internal/telephony/RadioDataProxy.java @@ -49,26 +49,15 @@ public class RadioDataProxy extends RadioServiceProxy { * @return updated HAL version */ public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.data.IRadioData data) { - mHalVersion = halVersion; - mDataProxy = data; - mIsAidl = true; - + HalVersion version = halVersion; try { - HalVersion newHalVersion; - int version = data.getInterfaceVersion(); - switch(version) { - default: - newHalVersion = RIL.RADIO_HAL_VERSION_2_0; - break; - } - Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); - - if (mHalVersion.less(newHalVersion)) { - mHalVersion = newHalVersion; - } + version = RIL.getServiceHalVersion(data.getInterfaceVersion()); } catch (RemoteException e) { Rlog.e(TAG, "setAidl: " + e); } + mHalVersion = version; + mDataProxy = data; + mIsAidl = true; Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); return mHalVersion; diff --git a/src/java/com/android/internal/telephony/RadioImsProxy.java b/src/java/com/android/internal/telephony/RadioImsProxy.java index 3ad1b946f2..cde2e06859 100644 --- a/src/java/com/android/internal/telephony/RadioImsProxy.java +++ b/src/java/com/android/internal/telephony/RadioImsProxy.java @@ -35,26 +35,15 @@ public class RadioImsProxy extends RadioServiceProxy { * @return updated HAL version. */ public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.ims.IRadioIms ims) { - mHalVersion = halVersion; - mImsProxy = ims; - mIsAidl = true; - + HalVersion version = halVersion; try { - HalVersion newHalVersion; - int version = ims.getInterfaceVersion(); - switch(version) { - default: - newHalVersion = RIL.RADIO_HAL_VERSION_2_0; - break; - } - Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); - - if (mHalVersion.less(newHalVersion)) { - mHalVersion = newHalVersion; - } + version = RIL.getServiceHalVersion(ims.getInterfaceVersion()); } catch (RemoteException e) { Rlog.e(TAG, "setAidl: " + e); } + mHalVersion = version; + mImsProxy = ims; + mIsAidl = true; Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); return mHalVersion; diff --git a/src/java/com/android/internal/telephony/RadioMessagingProxy.java b/src/java/com/android/internal/telephony/RadioMessagingProxy.java index 4e9bc8c073..69ccf3612a 100644 --- a/src/java/com/android/internal/telephony/RadioMessagingProxy.java +++ b/src/java/com/android/internal/telephony/RadioMessagingProxy.java @@ -41,26 +41,15 @@ public class RadioMessagingProxy extends RadioServiceProxy { */ public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.messaging.IRadioMessaging messaging) { - mHalVersion = halVersion; - mMessagingProxy = messaging; - mIsAidl = true; - + HalVersion version = halVersion; try { - HalVersion newHalVersion; - int version = messaging.getInterfaceVersion(); - switch(version) { - default: - newHalVersion = RIL.RADIO_HAL_VERSION_2_0; - break; - } - Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); - - if (mHalVersion.less(newHalVersion)) { - mHalVersion = newHalVersion; - } + version = RIL.getServiceHalVersion(messaging.getInterfaceVersion()); } catch (RemoteException e) { Rlog.e(TAG, "setAidl: " + e); } + mHalVersion = version; + mMessagingProxy = messaging; + mIsAidl = true; Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); return mHalVersion; diff --git a/src/java/com/android/internal/telephony/RadioModemProxy.java b/src/java/com/android/internal/telephony/RadioModemProxy.java index 26287510b7..4178293d06 100644 --- a/src/java/com/android/internal/telephony/RadioModemProxy.java +++ b/src/java/com/android/internal/telephony/RadioModemProxy.java @@ -36,26 +36,15 @@ public class RadioModemProxy extends RadioServiceProxy { */ public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.modem.IRadioModem modem) { - mHalVersion = halVersion; - mModemProxy = modem; - mIsAidl = true; - + HalVersion version = halVersion; try { - HalVersion newHalVersion; - int version = modem.getInterfaceVersion(); - switch(version) { - default: - newHalVersion = RIL.RADIO_HAL_VERSION_2_0; - break; - } - Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); - - if (mHalVersion.less(newHalVersion)) { - mHalVersion = newHalVersion; - } + version = RIL.getServiceHalVersion(modem.getInterfaceVersion()); } catch (RemoteException e) { Rlog.e(TAG, "setAidl: " + e); } + mHalVersion = version; + mModemProxy = modem; + mIsAidl = true; Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); return mHalVersion; diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java index 4717ad60d0..246c2e0204 100644 --- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java +++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java @@ -70,29 +70,15 @@ public class RadioNetworkProxy extends RadioServiceProxy { */ public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.network.IRadioNetwork network) { - mHalVersion = halVersion; - mNetworkProxy = network; - mIsAidl = true; - + HalVersion version = halVersion; try { - HalVersion newHalVersion; - int version = network.getInterfaceVersion(); - switch(version) { - case 2: - newHalVersion = RIL.RADIO_HAL_VERSION_2_1; - break; - default: - newHalVersion = RIL.RADIO_HAL_VERSION_2_0; - break; - } - Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); - - if (mHalVersion.less(newHalVersion)) { - mHalVersion = newHalVersion; - } + version = RIL.getServiceHalVersion(network.getInterfaceVersion()); } catch (RemoteException e) { Rlog.e(TAG, "setAidl: " + e); } + mHalVersion = version; + mNetworkProxy = network; + mIsAidl = true; Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); return mHalVersion; diff --git a/src/java/com/android/internal/telephony/RadioSatelliteProxy.java b/src/java/com/android/internal/telephony/RadioSatelliteProxy.java index 1530c1a2ca..6101f3fc6a 100644 --- a/src/java/com/android/internal/telephony/RadioSatelliteProxy.java +++ b/src/java/com/android/internal/telephony/RadioSatelliteProxy.java @@ -25,37 +25,26 @@ import android.telephony.Rlog; */ public class RadioSatelliteProxy extends RadioServiceProxy { private static final String TAG = "RadioSatelliteProxy"; - private volatile android.hardware.radio.satellite.IRadioSatellite mRadioSatelliteProxy = null; + private volatile android.hardware.radio.satellite.IRadioSatellite mSatelliteProxy = null; /** - * Sets IRadioSatellite as the AIDL implementation for RadioSatelliteProxy. + * Sets IRadioSatellite as the AIDL implementation for RadioServiceProxy. * @param halVersion Radio HAL version. - * @param radioSatellite IRadioSatellite implementation. + * @param satellite IRadioSatellite implementation. * * @return updated HAL version. */ public HalVersion setAidl(HalVersion halVersion, - android.hardware.radio.satellite.IRadioSatellite radioSatellite) { - mHalVersion = halVersion; - mRadioSatelliteProxy = radioSatellite; - mIsAidl = true; - + android.hardware.radio.satellite.IRadioSatellite satellite) { + HalVersion version = halVersion; try { - HalVersion newHalVersion; - int version = radioSatellite.getInterfaceVersion(); - switch(version) { - default: - newHalVersion = RIL.RADIO_HAL_VERSION_2_0; - break; - } - Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); - - if (mHalVersion.less(newHalVersion)) { - mHalVersion = newHalVersion; - } + version = RIL.getServiceHalVersion(satellite.getInterfaceVersion()); } catch (RemoteException e) { Rlog.e(TAG, "setAidl: " + e); } + mHalVersion = version; + mSatelliteProxy = satellite; + mIsAidl = true; Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); return mHalVersion; @@ -66,7 +55,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { * @return IRadioSatellite implementation. */ public android.hardware.radio.satellite.IRadioSatellite getAidl() { - return mRadioSatelliteProxy; + return mSatelliteProxy; } /** @@ -75,7 +64,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { @Override public void clear() { super.clear(); - mRadioSatelliteProxy = null; + mSatelliteProxy = null; } /** @@ -84,7 +73,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { */ @Override public boolean isEmpty() { - return mRadioProxy == null && mRadioSatelliteProxy == null; + return mRadioProxy == null && mSatelliteProxy == null; } /** @@ -95,7 +84,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void responseAcknowledgement() throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.responseAcknowledgement(); + mSatelliteProxy.responseAcknowledgement(); } } @@ -107,7 +96,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void getCapabilities(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.getCapabilities(serial); + mSatelliteProxy.getCapabilities(serial); } } @@ -121,7 +110,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void setPower(int serial, boolean on) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.setPower(serial, on); + mSatelliteProxy.setPower(serial, on); } } @@ -133,7 +122,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void getPowerState(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.getPowerState(serial); + mSatelliteProxy.getPowerState(serial); } } @@ -154,7 +143,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { int[] features) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.provisionService(serial, imei, msisdn, imsi, features); + mSatelliteProxy.provisionService(serial, imei, msisdn, imsi, features); } } @@ -167,7 +156,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void addAllowedSatelliteContacts(int serial, String[] contacts) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.addAllowedSatelliteContacts(serial, contacts); + mSatelliteProxy.addAllowedSatelliteContacts(serial, contacts); } } @@ -181,7 +170,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.removeAllowedSatelliteContacts(serial, contacts); + mSatelliteProxy.removeAllowedSatelliteContacts(serial, contacts); } } @@ -198,7 +187,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { double longitude) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.sendMessages(serial, messages, destination, latitude, longitude); + mSatelliteProxy.sendMessages(serial, messages, destination, latitude, longitude); } } @@ -210,7 +199,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void getPendingMessages(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.getPendingMessages(serial); + mSatelliteProxy.getPendingMessages(serial); } } @@ -222,7 +211,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void getSatelliteMode(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.getSatelliteMode(serial); + mSatelliteProxy.getSatelliteMode(serial); } } @@ -236,7 +225,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void setIndicationFilter(int serial, int filterBitmask) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.setIndicationFilter(serial, filterBitmask); + mSatelliteProxy.setIndicationFilter(serial, filterBitmask); } } @@ -248,7 +237,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void startSendingSatellitePointingInfo(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.startSendingSatellitePointingInfo(serial); + mSatelliteProxy.startSendingSatellitePointingInfo(serial); } } @@ -260,7 +249,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void stopSendingSatellitePointingInfo(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.stopSendingSatellitePointingInfo(serial); + mSatelliteProxy.stopSendingSatellitePointingInfo(serial); } } @@ -272,7 +261,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void getMaxCharactersPerTextMessage(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.getMaxCharactersPerTextMessage(serial); + mSatelliteProxy.getMaxCharactersPerTextMessage(serial); } } @@ -284,7 +273,7 @@ public class RadioSatelliteProxy extends RadioServiceProxy { public void getTimeForNextSatelliteVisibility(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { - mRadioSatelliteProxy.getTimeForNextSatelliteVisibility(serial); + mSatelliteProxy.getTimeForNextSatelliteVisibility(serial); } } } diff --git a/src/java/com/android/internal/telephony/RadioSimProxy.java b/src/java/com/android/internal/telephony/RadioSimProxy.java index a305de96af..d945ad3115 100644 --- a/src/java/com/android/internal/telephony/RadioSimProxy.java +++ b/src/java/com/android/internal/telephony/RadioSimProxy.java @@ -45,29 +45,15 @@ public class RadioSimProxy extends RadioServiceProxy { * @return updated HAL version */ public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.sim.IRadioSim sim) { - mHalVersion = halVersion; - mSimProxy = sim; - mIsAidl = true; - + HalVersion version = halVersion; try { - HalVersion newHalVersion; - int version = sim.getInterfaceVersion(); - switch(version) { - case 2: - newHalVersion = RIL.RADIO_HAL_VERSION_2_1; - break; - default: - newHalVersion = RIL.RADIO_HAL_VERSION_2_0; - break; - } - Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); - - if (mHalVersion.less(newHalVersion)) { - mHalVersion = newHalVersion; - } + version = RIL.getServiceHalVersion(sim.getInterfaceVersion()); } catch (RemoteException e) { Rlog.e(TAG, "setAidl: " + e); } + mHalVersion = version; + mSimProxy = sim; + mIsAidl = true; Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); return mHalVersion; diff --git a/src/java/com/android/internal/telephony/RadioVoiceProxy.java b/src/java/com/android/internal/telephony/RadioVoiceProxy.java index 07afaad30e..7f46424485 100644 --- a/src/java/com/android/internal/telephony/RadioVoiceProxy.java +++ b/src/java/com/android/internal/telephony/RadioVoiceProxy.java @@ -40,26 +40,15 @@ public class RadioVoiceProxy extends RadioServiceProxy { */ public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.voice.IRadioVoice voice) { - mHalVersion = halVersion; - mVoiceProxy = voice; - mIsAidl = true; - + HalVersion version = halVersion; try { - HalVersion newHalVersion; - int version = voice.getInterfaceVersion(); - switch(version) { - default: - newHalVersion = RIL.RADIO_HAL_VERSION_2_0; - break; - } - Rlog.d(TAG, "AIDL version=" + version + ", halVersion=" + newHalVersion); - - if (mHalVersion.less(newHalVersion)) { - mHalVersion = newHalVersion; - } + version = RIL.getServiceHalVersion(voice.getInterfaceVersion()); } catch (RemoteException e) { Rlog.e(TAG, "setAidl: " + e); } + mHalVersion = version; + mVoiceProxy = voice; + mIsAidl = true; Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); return mHalVersion; -- GitLab From 99ced03b19f1d968a4481377eebc28473d910414 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Mon, 6 Feb 2023 13:13:34 +0000 Subject: [PATCH 397/656] Add log for SrvccConnection Bug: 217654931 Test: build Change-Id: I4f4800f6c6b67dcbaa976a9bc661b02d42b7aa29 --- .../internal/telephony/SrvccConnection.java | 25 +++++++++++++++++++ .../imsphone/ImsPhoneCallTracker.java | 7 +++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/SrvccConnection.java b/src/java/com/android/internal/telephony/SrvccConnection.java index b831a592cb..f25a15cae2 100644 --- a/src/java/com/android/internal/telephony/SrvccConnection.java +++ b/src/java/com/android/internal/telephony/SrvccConnection.java @@ -32,6 +32,7 @@ import android.text.TextUtils; import com.android.ims.internal.ConferenceParticipant; import com.android.internal.telephony.imsphone.ImsPhoneConnection; +import com.android.telephony.Rlog; /** * Connection information for SRVCC @@ -98,6 +99,7 @@ public class SrvccConnection { } public SrvccConnection(ConferenceParticipant cp, @PreciseCallStates int preciseCallState) { + Rlog.d(TAG, "initialize with ConferenceParticipant"); mState = toCallState(preciseCallState); mIsMT = cp.getCallDirection() == android.telecom.Call.Details.DIRECTION_INCOMING; mNumber = getParticipantAddress(cp.getHandle()); @@ -132,6 +134,7 @@ public class SrvccConnection { // MT call in alerting or prealerting state private void initialize(ImsCallProfile profile) { + Rlog.d(TAG, "initialize with ImsCallProfile"); mIsMT = true; mNumber = profile.getCallExtra(ImsCallProfile.EXTRA_OI); mName = profile.getCallExtra(ImsCallProfile.EXTRA_CNA); @@ -142,6 +145,7 @@ public class SrvccConnection { } private void initialize(ImsPhoneConnection c) { + Rlog.d(TAG, "initialize with ImsPhoneConnection"); if (c.isEmergencyCall()) { mType = CALL_TYPE_EMERGENCY; } @@ -232,4 +236,25 @@ public class SrvccConnection { public int getNamePresentation() { return mNamePresentation; } + + /** + * Build a human representation of a connection instance, suitable for debugging. + * Don't log personal stuff unless in debug mode. + * @return a string representing the internal state of this connection. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(" type:").append(getType()); + sb.append(", state:").append(getState()); + sb.append(", subState:").append(getSubState()); + sb.append(", toneType:").append(getRingbackToneType()); + sb.append(", mpty:").append(isMultiParty()); + sb.append(", incoming:").append(isIncoming()); + sb.append(", numberPresentation:").append(getNumberPresentation()); + sb.append(", number:").append(Rlog.pii(TAG, getNumber())); + sb.append(", namePresentation:").append(getNamePresentation()); + sb.append(", name:").append(Rlog.pii(TAG, getName())); + return sb.toString(); + } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 77a96d19f6..f45bf01587 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -6073,7 +6073,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { if (profile == null) return; int preciseCallState = profile.getPreciseCallState(); - if (!isAlive(preciseCallState)) return; + if (!isAlive(preciseCallState)) { + Rlog.i(LOG_TAG, "addConnection not alive, " + preciseCallState); + return; + } List participants = getConferenceParticipants(c); if (participants != null) { @@ -6083,11 +6086,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { continue; } SrvccConnection srvccConnection = new SrvccConnection(cp, preciseCallState); + Rlog.i(LOG_TAG, "addConnection " + srvccConnection); destList.add(srvccConnection); } } else { SrvccConnection srvccConnection = new SrvccConnection(profile.getImsCallProfile(), c, preciseCallState); + Rlog.i(LOG_TAG, "addConnection " + srvccConnection); destList.add(srvccConnection); } } -- GitLab From 6a2922c9a11378d3efb34eb641a5dfa938d8c75b Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 3 Feb 2023 08:12:00 +0000 Subject: [PATCH 398/656] Add ImsCallProfile.EXTRA_CALL_RAT_TYPE extra to DialArgs This extra informs IMS service that the call should be routed over Wi-Fi. Bug: 267601693 Test: atest GsmCdmaPhoneTest EmergencyCallDomainSelectionConnectionTest Change-Id: Ied151d0c1a8c2be0c4f53aa1c9428c440be83c4c --- .../telephony/GsmCdmaCallTracker.java | 4 +++ .../internal/telephony/GsmCdmaPhone.java | 11 ++++++++ ...mergencyCallDomainSelectionConnection.java | 11 ++++++-- .../imsphone/ImsPhoneCallTracker.java | 5 ++++ .../telephony/GsmCdmaCallTrackerTest.java | 12 ++++++-- .../internal/telephony/GsmCdmaPhoneTest.java | 28 +++++++++++++++++++ ...encyCallDomainSelectionConnectionTest.java | 3 +- .../telephony/imsphone/ImsPhoneTest.java | 6 ++++ 8 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java index 08561d75a0..d76ee199fc 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java +++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java @@ -1839,6 +1839,10 @@ public class GsmCdmaCallTracker extends CallTracker { } private boolean isEmcRetryCause(int causeCode) { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + log("isEmcRetryCause AP based domain selection ignores the cause"); + return false; + } if (causeCode == CallFailCause.EMC_REDIAL_ON_IMS || causeCode == CallFailCause.EMC_REDIAL_ON_VOWIFI) { return true; diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index af45417b79..65347e825d 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -88,6 +88,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.UiccAccessRule; import android.telephony.UssdResponse; +import android.telephony.ims.ImsCallProfile; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -1443,7 +1444,17 @@ public class GsmCdmaPhone extends Phone { // should not reach here loge("dial unexpected Ut domain selection, ignored"); } + } else if (domain == PhoneConstants.DOMAIN_NON_3GPP_PS) { + if (isEmergency) { + useImsForEmergency = true; + extras.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE, + String.valueOf(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)); + } else { + // should not reach here + loge("dial DOMAIN_NON_3GPP_PS should be used only for emergency calls"); + } } + extras.remove(PhoneConstants.EXTRA_DIAL_DOMAIN); } diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java index 8d000f5a23..4cb956e626 100644 --- a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java @@ -22,6 +22,7 @@ import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; import static android.telephony.DomainSelectionService.SELECTOR_TYPE_CALLING; import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; +import static com.android.internal.telephony.PhoneConstants.DOMAIN_NON_3GPP_PS; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; @@ -94,7 +95,7 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne } CompletableFuture future = getCompletableFuture(); - if (future != null) future.complete(DOMAIN_PS); + if (future != null) future.complete(DOMAIN_NON_3GPP_PS); } /** {@inheritDoc} */ @@ -164,7 +165,13 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne + ", current=" + preferredTransport); if (preferredTransport == mPreferredTransportType) { CompletableFuture future = getCompletableFuture(); - if (future != null) future.complete(DOMAIN_PS); + if (future != null) { + if (preferredTransport == TRANSPORT_TYPE_WLAN) { + future.complete(DOMAIN_NON_3GPP_PS); + } else { + future.complete(DOMAIN_PS); + } + } anm.unregisterForQualifiedNetworksChanged(mHandler); } } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 77a96d19f6..f427395bfc 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -2119,6 +2119,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { conn.setPulledDialogId(dialogId); } + if (intentExtras.containsKey(ImsCallProfile.EXTRA_CALL_RAT_TYPE)) { + logi("dialInternal containing EXTRA_CALL_RAT_TYPE, " + + intentExtras.getString(ImsCallProfile.EXTRA_CALL_RAT_TYPE)); + } + // Pack the OEM-specific call extras. profile.mCallExtras.putBundle(ImsCallProfile.EXTRA_OEM_EXTRAS, intentExtras); diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java index f0c43be67c..2fdff9ed7b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java @@ -41,9 +41,7 @@ import android.testing.TestableLooper; import androidx.test.filters.FlakyTest; import com.android.internal.telephony.PhoneInternalInterface.DialArgs; - -import java.io.PrintWriter; -import java.io.StringWriter; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; import org.junit.After; import org.junit.Assert; @@ -53,6 +51,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import java.io.PrintWriter; +import java.io.StringWriter; + @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class GsmCdmaCallTrackerTest extends TelephonyTest { @@ -66,12 +67,16 @@ public class GsmCdmaCallTrackerTest extends TelephonyTest { // Mocked classes private GsmCdmaConnection mConnection; private Handler mHandler; + private DomainSelectionResolver mDomainSelectionResolver; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mConnection = mock(GsmCdmaConnection.class); mHandler = mock(Handler.class); + mDomainSelectionResolver = mock(DomainSelectionResolver.class); + doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported(); + DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver); mSimulatedCommands.setRadioPower(true, null); mPhone.mCi = this.mSimulatedCommands; @@ -86,6 +91,7 @@ public class GsmCdmaCallTrackerTest extends TelephonyTest { @After public void tearDown() throws Exception { mCTUT = null; + DomainSelectionResolver.setDomainSelectionResolver(null); super.tearDown(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index b9331b7c80..b351242b7c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -82,6 +82,7 @@ import android.telephony.SmsCbMessage; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.ims.ImsCallProfile; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; @@ -2311,6 +2312,33 @@ public class GsmCdmaPhoneTest extends TelephonyTest { mPhoneUT.dial(TEST_EMERGENCY_NUMBER, dialArgs); verify(mImsPhone).dial(anyString(), any(PhoneInternalInterface.DialArgs.class)); + + extras = dialArgs.intentExtras; + + assertFalse(extras.containsKey(ImsCallProfile.EXTRA_CALL_RAT_TYPE)); + } + + @Test + public void testDomainSelectionEmergencyCallNon3GppPs() throws CallStateException { + setupEmergencyCallScenario(false /* USE_ONLY_DIALED_SIM_ECC_LIST */, + false /* isEmergencyOnDialedSim */); + + doReturn(false).when(mImsPhone).isImsAvailable(); + + Bundle extras = new Bundle(); + extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, PhoneConstants.DOMAIN_NON_3GPP_PS); + ImsPhone.ImsDialArgs dialArgs = new ImsPhone.ImsDialArgs.Builder() + .setIntentExtras(extras) + .build(); + mPhoneUT.dial(TEST_EMERGENCY_NUMBER, dialArgs); + + verify(mImsPhone).dial(anyString(), any(PhoneInternalInterface.DialArgs.class)); + + extras = dialArgs.intentExtras; + + assertTrue(extras.containsKey(ImsCallProfile.EXTRA_CALL_RAT_TYPE)); + assertEquals(String.valueOf(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN), + extras.getString(ImsCallProfile.EXTRA_CALL_RAT_TYPE)); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java index f646d7e93e..fff77b784c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java @@ -24,6 +24,7 @@ import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS; import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN; +import static com.android.internal.telephony.PhoneConstants.DOMAIN_NON_3GPP_PS; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; @@ -120,7 +121,7 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { mTransportCallback.onWlanSelected(); assertTrue(future.isDone()); - assertEquals((long) DOMAIN_PS, (long) future.get()); + assertEquals((long) DOMAIN_NON_3GPP_PS, (long) future.get()); verify(mEmergencyStateTracker).onEmergencyTransportChanged(MODE_EMERGENCY_WLAN); } 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 3050beb575..59d57e7dc3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -95,6 +95,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.imsphone.ImsPhone.SS; @@ -119,6 +120,7 @@ public class ImsPhoneTest extends TelephonyTest { private ImsPhoneCall mBackgroundCall; private ImsPhoneCall mRingingCall; private Handler mTestHandler; + private DomainSelectionResolver mDomainSelectionResolver; Connection mConnection; ImsUtInterface mImsUtInterface; @@ -144,6 +146,9 @@ public class ImsPhoneTest extends TelephonyTest { mTestHandler = mock(Handler.class); mConnection = mock(Connection.class); mImsUtInterface = mock(ImsUtInterface.class); + mDomainSelectionResolver = mock(DomainSelectionResolver.class); + doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported(); + DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver); mImsCT.mForegroundCall = mForegroundCall; mImsCT.mBackgroundCall = mBackgroundCall; @@ -187,6 +192,7 @@ public class ImsPhoneTest extends TelephonyTest { public void tearDown() throws Exception { mImsPhoneUT = null; mBundle = null; + DomainSelectionResolver.setDomainSelectionResolver(null); super.tearDown(); } -- GitLab From 41426f90deca824975c0fa1205d71a3b44b1fdd8 Mon Sep 17 00:00:00 2001 From: Gil Cukierman Date: Fri, 3 Feb 2023 22:13:40 +0000 Subject: [PATCH 399/656] Fix testInitializationFromDb This test was previously passing without the correct permissions, since it just so happened that the instrumentation target's PhoneFactory wasn't initialized. Instead of relying on the instrumentation context directly, rely on the TelephonyTest ContextFixture, which already handles privileged phone state read permissions, which are expected by the internal telephony framework. Bug: 267186351 Fixes: 267186351 Test: atest GsmCdmaPhoneTest InboundSmsTrackerTest Change-Id: I323d11f84726a403af7af71399ad01d62c52e517 --- .../internal/telephony/InboundSmsTrackerTest.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java index b11b94ea0d..df355ac261 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java @@ -24,8 +24,6 @@ import android.database.Cursor; import android.database.MatrixCursor; import android.test.suitebuilder.annotation.SmallTest; -import androidx.test.InstrumentationRegistry; - import com.android.internal.util.HexDump; import org.junit.After; @@ -34,7 +32,7 @@ import org.junit.Test; import java.util.Arrays; -public class InboundSmsTrackerTest { +public class InboundSmsTrackerTest extends TelephonyTest { InboundSmsTracker mInboundSmsTracker; private static final byte[] FAKE_PDU = new byte[]{1, 2, 3}; @@ -50,7 +48,8 @@ public class InboundSmsTrackerTest { @Before public void setUp() throws Exception { - mInboundSmsTracker = new InboundSmsTracker(InstrumentationRegistry.getContext(), + super.setUp(getClass().getSimpleName()); + mInboundSmsTracker = new InboundSmsTracker(mContext, FAKE_PDU, FAKE_TIMESTAMP, FAKE_DEST_PORT, false, FAKE_ADDRESS, FAKE_DISPLAY_ADDRESS, FAKE_REFERENCE_NUMBER, FAKE_SEQUENCE_NUMBER, FAKE_MESSAGE_COUNT, false, FAKE_MESSAGE_BODY, false /* isClass0 */, FAKE_SUBID, @@ -108,8 +107,7 @@ public class InboundSmsTrackerTest { @SmallTest public void testInitializationFromDb() { Cursor cursor = createFakeCursor(); - mInboundSmsTracker = new InboundSmsTracker(InstrumentationRegistry.getContext(), - cursor, false); + mInboundSmsTracker = new InboundSmsTracker(mContext, cursor, false); cursor.close(); testInitialization(); } -- GitLab From b76e21acf485a3400b5f7ed61615985d59805bb8 Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Mon, 6 Feb 2023 09:51:33 +0000 Subject: [PATCH 400/656] Add sdk check for isSimPortAvailable API modified behavior with ag/20806026 Test: Manually verified on C10 and atest Bug: 240273417 Change-Id: I8f7cb5198f6643af32913607c1effa8bffe717e1 --- .../telephony/euicc/EuiccController.java | 7 ++ .../telephony/euicc/EuiccControllerTest.java | 69 +++++++++++++------ 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java index 8f74a5ba97..67cb981ece 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccController.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java @@ -1951,6 +1951,10 @@ public class EuiccController extends IEuiccController.Stub { @Override public boolean isSimPortAvailable(int cardId, int portIndex, String callingPackage) { mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); + // If calling app is targeted for Android U and beyond, check for other conditions + // to decide the port availability. + boolean shouldCheckConditionsForInactivePort = isCompatChangeEnabled(callingPackage, + EuiccManager.INACTIVE_PORT_AVAILABILITY_CHECK); // In the event that this check is coming from ONS, WRITE_EMBEDDED_SUBSCRIPTIONS will be // required for the case where a port is inactive but could trivially be enabled without // requiring user consent. @@ -1980,6 +1984,9 @@ public class EuiccController extends IEuiccController.Stub { // 3. Caller has carrier privileges on any phone or has // WRITE_EMBEDDED_SUBSCRIPTIONS. The latter covers calls from ONS // which does not have carrier privileges. + if (!shouldCheckConditionsForInactivePort) { + return false; + } boolean hasActiveRemovableNonEuiccSlot = getRemovableNonEuiccSlot() != null && getRemovableNonEuiccSlot().isActive(); boolean hasCarrierPrivileges = mTelephonyManager 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 8e0ad4bab0..fc8dfbfcd4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java @@ -1295,54 +1295,57 @@ public class EuiccControllerTest extends TelephonyTest { } @Test + @EnableCompatChanges({EuiccManager.INACTIVE_PORT_AVAILABILITY_CHECK}) public void testIsSimPortAvailable_invalidCase() { setUiccCardInfos(false, true, true); // assert non euicc card id - assertFalse(mController.isSimPortAvailable(REMOVABLE_CARD_ID, 0, PACKAGE_NAME)); + assertFalse(mController.isSimPortAvailable(REMOVABLE_CARD_ID, 0, TEST_PACKAGE_NAME)); // assert invalid port index - assertFalse(mController.isSimPortAvailable(CARD_ID, 5 /* portIndex */, PACKAGE_NAME)); + assertFalse(mController.isSimPortAvailable(CARD_ID, 5 /* portIndex */, TEST_PACKAGE_NAME)); } @Test + @EnableCompatChanges({EuiccManager.INACTIVE_PORT_AVAILABILITY_CHECK}) public void testIsSimPortAvailable_port_active() throws Exception { setUiccCardInfos(false, true, true); // port has empty iccid - assertTrue(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + assertTrue(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); // Set port is active, has valid iccid(may be boot profile) and UiccProfile is empty setUiccCardInfos(false, true, false); when(mUiccController.getUiccPortForSlot(anyInt(), anyInt())).thenReturn(mUiccPort); when(mUiccPort.getUiccProfile()).thenReturn(mUiccProfile); when(mUiccProfile.isEmptyProfile()).thenReturn(true); - assertTrue(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + assertTrue(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); // port is active, valid iccid, not empty profile but Phone object is null when(mUiccPort.getUiccProfile()).thenReturn(mUiccProfile); when(mUiccProfile.isEmptyProfile()).thenReturn(false); replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); // logicalSlotIndex of port#0 is 1, Phone object should be null - assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); // port is active, valid iccid, not empty profile but no carrier privileges when(mUiccPort.getUiccProfile()).thenReturn(mUiccProfile); when(mUiccProfile.isEmptyProfile()).thenReturn(false); replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone, mPhone}); when(mPhone.getCarrierPrivilegesTracker()).thenReturn(null); - assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); when(mPhone.getCarrierPrivilegesTracker()).thenReturn(mCarrierPrivilegesTracker); - when(mCarrierPrivilegesTracker.getCarrierPrivilegeStatusForPackage(PACKAGE_NAME)) + when(mCarrierPrivilegesTracker.getCarrierPrivilegeStatusForPackage(TEST_PACKAGE_NAME)) .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS); - assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); // port is active, valid iccid, not empty profile and has carrier privileges - when(mCarrierPrivilegesTracker.getCarrierPrivilegeStatusForPackage(PACKAGE_NAME)) + when(mCarrierPrivilegesTracker.getCarrierPrivilegeStatusForPackage(TEST_PACKAGE_NAME)) .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); - assertTrue(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + assertTrue(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); } @Test + @EnableCompatChanges({EuiccManager.INACTIVE_PORT_AVAILABILITY_CHECK}) public void testIsSimPortAvailable_port_inActive() { setUiccCardInfos(false, false, true); when(mUiccController.getUiccSlots()).thenReturn(new UiccSlot[]{mUiccSlot}); @@ -1350,20 +1353,20 @@ public class EuiccControllerTest extends TelephonyTest { // Check getRemovableNonEuiccSlot null case when(mUiccSlot.isEuicc()).thenReturn(true); - assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); // Check getRemovableNonEuiccSlot isActive() false case when(mUiccSlot.isEuicc()).thenReturn(false); when(mUiccSlot.isActive()).thenReturn(false); - assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); // assert false,multisim is not enabled when(mUiccSlot.isEuicc()).thenReturn(false); when(mUiccSlot.isActive()).thenReturn(true); - when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(PACKAGE_NAME)).thenReturn( - TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); + when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(TEST_PACKAGE_NAME)) + .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); when(mTelephonyManager.isMultiSimEnabled()).thenReturn(false); - assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); // assert false, caller does not have carrier privileges setHasWriteEmbeddedPermission(false); @@ -1371,19 +1374,41 @@ public class EuiccControllerTest extends TelephonyTest { when(mUiccSlot.getPortList()).thenReturn(new int[] {0}); when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(anyInt())).thenReturn( new SubscriptionInfo.Builder().build()); - when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(PACKAGE_NAME)).thenReturn( - TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS); - assertFalse(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(TEST_PACKAGE_NAME)) + .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS); + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); // assert true, caller does not have carrier privileges but has write_embedded permission setHasWriteEmbeddedPermission(true); - assertTrue(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + assertTrue(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); // assert true, caller has carrier privileges setHasWriteEmbeddedPermission(false); - when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(PACKAGE_NAME)).thenReturn( - TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); - assertTrue(mController.isSimPortAvailable(CARD_ID, 0, PACKAGE_NAME)); + when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(TEST_PACKAGE_NAME)) + .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); + assertTrue(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); + } + + @Test + @DisableCompatChanges({EuiccManager.INACTIVE_PORT_AVAILABILITY_CHECK}) + public void testIsSimPortAvailable_port_inActive_disable_compactChange() { + setUiccCardInfos(false, false, true); + when(mUiccController.getUiccSlots()).thenReturn(new UiccSlot[]{mUiccSlot}); + when(mUiccSlot.isRemovable()).thenReturn(true); + when(mUiccSlot.isEuicc()).thenReturn(false); + when(mUiccSlot.isActive()).thenReturn(true); + + when(mTelephonyManager.isMultiSimEnabled()).thenReturn(true); + when(mUiccSlot.getPortList()).thenReturn(new int[] {0}); + when(mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(anyInt())).thenReturn( + new SubscriptionInfo.Builder().build()); + when(mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(TEST_PACKAGE_NAME)) + .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS); + setHasWriteEmbeddedPermission(true); + + // Even though all conditions are true, isSimPortAvailable should return false as + // compact change is disabled + assertFalse(mController.isSimPortAvailable(CARD_ID, 0, TEST_PACKAGE_NAME)); } -- GitLab From bc8832aa5f7ec066d3b10d668d887c4bd1082474 Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 6 Feb 2023 18:24:59 -0600 Subject: [PATCH 401/656] Fix phone process crash due to null carrier config Perform null pointer check on the carrier config bundle subset return from CarrierConfigManager#getConfigForSub call to make sure it will not crash the phone process. Bug: 266962389 Test: atest FrameworksTelephonyTests Change-Id: I2f142279d267705fa678e8b632228eef475d7f6f --- .../internal/telephony/data/AccessNetworksManager.java | 4 ++-- .../android/internal/telephony/data/DataServiceManager.java | 4 ++-- .../internal/telephony/emergency/EmergencyNumberTracker.java | 4 ++-- src/java/com/android/internal/telephony/uicc/UiccProfile.java | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java index 2b29fa7ae7..267f70b389 100644 --- a/src/java/com/android/internal/telephony/data/AccessNetworksManager.java +++ b/src/java/com/android/internal/telephony/data/AccessNetworksManager.java @@ -475,7 +475,7 @@ public class AccessNetworksManager extends Handler { b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), CarrierConfigManager .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING); - if (!b.isEmpty()) { + if (b != null && !b.isEmpty()) { // If carrier config overrides it, use the one from carrier config String carrierConfigPackageName = b.getString(CarrierConfigManager .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING); @@ -506,7 +506,7 @@ public class AccessNetworksManager extends Handler { b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), CarrierConfigManager .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING); - if (!b.isEmpty()) { + if (b != null && !b.isEmpty()) { // If carrier config overrides it, use the one from carrier config String carrierConfigClassName = b.getString(CarrierConfigManager .KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_CLASS_OVERRIDE_STRING); diff --git a/src/java/com/android/internal/telephony/data/DataServiceManager.java b/src/java/com/android/internal/telephony/data/DataServiceManager.java index 957b703a90..3141fef8d4 100644 --- a/src/java/com/android/internal/telephony/data/DataServiceManager.java +++ b/src/java/com/android/internal/telephony/data/DataServiceManager.java @@ -630,13 +630,13 @@ public class DataServiceManager extends Handler { @NonNull private PersistableBundle getCarrierConfigSubset(String key) { - PersistableBundle configs = new PersistableBundle(); + PersistableBundle configs = null; try { configs = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), key); } catch (RuntimeException e) { loge("CarrierConfigLoader is not available."); } - return configs; + return configs != null ? configs : new PersistableBundle(); } private void sendCompleteMessage(Message msg, @DataServiceCallback.ResultCode int code) { diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 4f63dee931..d6b7b0b136 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -373,7 +373,7 @@ public class EmergencyNumberTracker extends Handler { @NonNull private PersistableBundle getCarrierConfigSubset(String key) { - PersistableBundle bundle = new PersistableBundle(); + PersistableBundle bundle = null; if (mPhone != null) { CarrierConfigManager ccm = @@ -386,7 +386,7 @@ public class EmergencyNumberTracker extends Handler { loge("CarrierConfigLoader is not available."); } } - return bundle; + return bundle != null ? bundle : new PersistableBundle(); } private String getInitialCountryIso() { diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index 6d73e58098..1d8615b0ee 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -1819,13 +1819,13 @@ public class UiccProfile extends IccCard { @NonNull private PersistableBundle getCarrierConfigSubset(int subId, String... keys) { - PersistableBundle bundle = new PersistableBundle(); + PersistableBundle bundle = null; try { bundle = mCarrierConfigManager.getConfigForSubId(subId, keys); } catch (RuntimeException e) { loge("CarrierConfigLoader is not available."); } - return bundle; + return bundle != null ? bundle : new PersistableBundle(); } private static String eventToString(int event) { -- GitLab From aa4889d07dad0762a4332a9dce97fafb94300783 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 6 Feb 2023 00:25:26 -0800 Subject: [PATCH 402/656] Initialized allowed network types 1. Initialized allowed network types for new subscriptions. 2. Attempts to restore SIM specific settings after SIM loaded. 3. Matched the checkPackage calls with SubscriptionController. Fix: 267981542 Test: Boot up on cuttlefish and check if it camps on LTE. Test: Basic phone functionality tests. Test: atest SubscriptionManagerServiceTest Change-Id: I23db0581dc0ab1663648d6b2b68895dfc9d18be7 --- .../com/android/internal/telephony/Phone.java | 9 +- .../SubscriptionManagerService.java | 119 ++++++++---------- .../internal/telephony/GsmCdmaPhoneTest.java | 1 + .../internal/telephony/TelephonyTest.java | 7 +- .../SubscriptionManagerServiceTest.java | 66 +++++++++- 5 files changed, 124 insertions(+), 78 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 3c7bb44921..0f64dcd52b 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -2484,7 +2484,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } } - private String convertAllowedNetworkTypeMapIndexToDbName( + /** + * Convert the allowed network types reason to string. + * + * @param reason The allowed network types reason. + * + * @return The converted string. + */ + public static String convertAllowedNetworkTypeMapIndexToDbName( @TelephonyManager.AllowedNetworkTypesReason int reason) { switch (reason) { case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER: diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 47db501071..6ecaee6e6a 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -53,6 +53,7 @@ import android.service.euicc.GetEuiccProfileInfoListResult; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; +import android.telephony.RadioAccessFamily; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.DataRoamingMode; @@ -84,6 +85,7 @@ import com.android.internal.telephony.MccTable; import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; @@ -970,6 +972,35 @@ public class SubscriptionManagerService extends ISub.Stub { return TelephonyManager.INVALID_PORT_INDEX; } + /** + * Insert a new subscription into the database. + * + * @param iccId The ICCID. + * @param slotIndex The logical SIM slot index (i.e. phone id). + * @param displayName The display name. + * @param subscriptionType The subscription type. + * + * @return The subscription id. + */ + private int insertSubscriptionInfo(@NonNull String iccId, int slotIndex, + @Nullable String displayName, @SubscriptionType int subscriptionType) { + String defaultAllowNetworkTypes = Phone.convertAllowedNetworkTypeMapIndexToDbName( + TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER) + "=" + + RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE); + SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal.Builder() + .setIccId(iccId) + .setCardString(iccId) + .setSimSlotIndex(slotIndex) + .setType(subscriptionType) + .setIconTint(getColor()) + .setAllowedNetworkTypesForReasons(defaultAllowNetworkTypes); + if (displayName != null) { + builder.setDisplayName(displayName); + } + + return mSubscriptionDatabaseManager.insertSubscriptionInfo(builder.build()); + } + /** * Pull the embedded subscription from {@link EuiccController} for the eUICC with the given list * of card IDs {@code cardIds}. @@ -1016,13 +1047,10 @@ public class SubscriptionManagerService extends ISub.Stub { // The subscription does not exist in the database. Insert a new one here. if (subInfo == null) { - subInfo = new SubscriptionInfoInternal.Builder() - .setIccId(embeddedProfile.getIccid()) - .setIconTint(getColor()) - .build(); - int subId = mSubscriptionDatabaseManager.insertSubscriptionInfo(subInfo); - subInfo = new SubscriptionInfoInternal.Builder(subInfo) - .setId(subId).build(); + int subId = insertSubscriptionInfo(embeddedProfile.getIccid(), + SubscriptionManager.INVALID_SIM_SLOT_INDEX, + null, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + subInfo = mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subId); } int nameSource = subInfo.getDisplayNameSource(); @@ -1224,12 +1252,8 @@ public class SubscriptionManagerService extends ISub.Stub { int subId; if (subInfo == null) { // This is a new SIM card. Insert a new record. - subId = mSubscriptionDatabaseManager.insertSubscriptionInfo( - new SubscriptionInfoInternal.Builder() - .setIccId(iccId) - .setSimSlotIndex(phoneId) - .setIconTint(getColor()) - .build()); + subId = insertSubscriptionInfo(iccId, phoneId, null, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); logl("updateSubscriptions: Inserted a new subscription. subId=" + subId + ", phoneId=" + phoneId); } else { @@ -1308,6 +1332,9 @@ public class SubscriptionManagerService extends ISub.Stub { } else { loge("updateSubscriptions: ICC card is not available."); } + + // Attempt to restore SIM specific settings when SIM is loaded. + mSubscriptionManager.restoreSimSpecificSettingsForIccIdFromBackup(iccId); } } else { log("updateSubscriptions: No ICCID available for phone " + phoneId); @@ -1512,9 +1539,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public List getAllSubInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos // on the subs it has carrier privilege. @@ -1561,9 +1585,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public SubscriptionInfo getActiveSubscriptionInfo(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, "getActiveSubscriptionInfo")) { throw new SecurityException("Need READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or " @@ -1595,9 +1616,6 @@ public class SubscriptionManagerService extends ISub.Stub { @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public SubscriptionInfo getActiveSubscriptionInfoForIccId(@NonNull String iccId, @NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - enforcePermissions("getActiveSubscriptionInfoForIccId", Manifest.permission.READ_PRIVILEGED_PHONE_STATE); @@ -1634,9 +1652,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, @NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - int subId = mSlotIndexToSubId.getOrDefault(slotIndex, SubscriptionManager.INVALID_SUBSCRIPTION_ID); @@ -1682,9 +1697,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public List getActiveSubscriptionInfoList(@NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos // on the subs it has carrier privilege. @@ -1729,9 +1741,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public int getActiveSubInfoCount(@NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub(mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, "getAllSubInfoList")) { @@ -1828,6 +1837,9 @@ public class SubscriptionManagerService extends ISub.Stub { return null; } + // Verify that the callingPackage belongs to the calling UID + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); + return mSubscriptionDatabaseManager.getAllSubscriptions().stream() .map(SubscriptionInfoInternal::toSubscriptionInfo) .filter(subInfo -> mSubscriptionManager @@ -1886,15 +1898,8 @@ public class SubscriptionManagerService extends ISub.Stub { loge("Already a subscription on slot " + slotIndex); return -1; } - int subId = mSubscriptionDatabaseManager.insertSubscriptionInfo( - new SubscriptionInfoInternal.Builder() - .setIccId(iccId) - .setSimSlotIndex(slotIndex) - .setDisplayName(displayName) - .setIconTint(getColor()) - .setType(subscriptionType) - .build() - ); + + int subId = insertSubscriptionInfo(iccId, slotIndex, displayName, subscriptionType); mSlotIndexToSubId.put(slotIndex, subId); } else { // Record already exists. @@ -2142,9 +2147,6 @@ public class SubscriptionManagerService extends ISub.Stub { "carrier privileges", }) public int setOpportunistic(boolean opportunistic, int subId, @NonNull String callingPackage) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( mContext, Binder.getCallingUid(), subId, true, "setOpportunistic", Manifest.permission.MODIFY_PHONE_STATE); @@ -2308,9 +2310,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public List getOpportunisticSubscriptions(@NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - // Check if the caller has READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier // privilege on any active subscription. The carrier app will get full subscription infos // on the subs it has carrier privilege. @@ -2359,9 +2358,6 @@ public class SubscriptionManagerService extends ISub.Stub { @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - // If it doesn't have modify phone state permission, or carrier privilege permission, // a SecurityException will be thrown. If it's due to invalid parameter or internal state, // it will return null. @@ -2436,9 +2432,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public void addSubscriptionsIntoGroup(@NonNull int[] subIdList, @NonNull ParcelUuid groupUuid, @NonNull String callingPackage) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - Objects.requireNonNull(subIdList, "subIdList"); if (subIdList.length == 0) { throw new IllegalArgumentException("Invalid subId list"); @@ -2450,6 +2443,9 @@ public class SubscriptionManagerService extends ISub.Stub { throw new IllegalArgumentException("Invalid groupUuid"); } + // Verify that the callingPackage belongs to the calling UID + mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); + // If it doesn't have modify phone state permission, or carrier privilege permission, // a SecurityException will be thrown. if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -2511,9 +2507,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public List getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid, @NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - // If the calling app neither has carrier privileges nor READ_PHONE_STATE and access to // device identifiers, it will throw a SecurityException. if (CompatChanges.isChangeEnabled(REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID, @@ -2896,9 +2889,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public String getSubscriptionProperty(int subId, @NonNull String columnName, @NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - Objects.requireNonNull(columnName); if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, callingFeatureId, @@ -3254,9 +3244,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public String getPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( mContext, subId, Binder.getCallingUid(), "getPhoneNumber", Manifest.permission.READ_PHONE_NUMBERS, @@ -3316,9 +3303,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public String getPhoneNumberFromFirstAvailableSource(int subId, @NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( mContext, subId, Binder.getCallingUid(), "getPhoneNumberFromFirstAvailableSource", Manifest.permission.READ_PHONE_NUMBERS, @@ -3362,9 +3346,6 @@ public class SubscriptionManagerService extends ISub.Stub { @RequiresPermission("carrier privileges") public void setPhoneNumber(int subId, @PhoneNumberSource int source, @NonNull String number, @NonNull String callingPackage, @Nullable String callingFeatureId) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - if (!TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext, subId)) { throw new SecurityException("setPhoneNumber for CARRIER needs carrier privilege."); } @@ -3402,9 +3383,6 @@ public class SubscriptionManagerService extends ISub.Stub { }) public int setUsageSetting(@UsageSetting int usageSetting, int subId, @NonNull String callingPackage) { - // Verify that the callingPackage belongs to the calling UID - mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage); - TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( mContext, Binder.getCallingUid(), subId, true, "setUsageSetting", Manifest.permission.MODIFY_PHONE_STATE); @@ -3804,6 +3782,7 @@ public class SubscriptionManagerService extends ISub.Stub { @NonNull String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println(SubscriptionManagerService.class.getSimpleName() + ":"); + pw.println("Active modem count=" + mTelephonyManager.getActiveModemCount()); pw.println("Logical SIM slot sub id mapping:"); pw.increaseIndent(); mSlotIndexToSubId.forEach((slotIndex, subId) diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index b9331b7c80..e095f5b5e8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -1167,6 +1167,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @SmallTest public void testGetEmptyIccCard() { doReturn(null).when(mUiccController).getUiccProfileForPhone(anyInt()); + doReturn(null).when(mUiccController).getUiccSlotForPhone(anyInt()); IccCard iccCard = mPhoneUT.getIccCard(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index fd287871b5..45be21bbca 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -184,6 +184,7 @@ public abstract class TelephonyTest { protected ImsPhoneCallTracker mImsCT; protected UiccController mUiccController; protected UiccProfile mUiccProfile; + protected UiccSlot mUiccSlot; protected CallManager mCallManager; protected PhoneNotifier mNotifier; protected TelephonyComponentFactory mTelephonyComponentFactory; @@ -415,6 +416,7 @@ public abstract class TelephonyTest { mImsCT = Mockito.mock(ImsPhoneCallTracker.class); mUiccController = Mockito.mock(UiccController.class); mUiccProfile = Mockito.mock(UiccProfile.class); + mUiccSlot = Mockito.mock(UiccSlot.class); mCallManager = Mockito.mock(CallManager.class); mNotifier = Mockito.mock(PhoneNotifier.class); mTelephonyComponentFactory = Mockito.mock(TelephonyComponentFactory.class); @@ -522,6 +524,8 @@ public abstract class TelephonyTest { mPhone.mCi = mSimulatedCommands; mCT.mCi = mSimulatedCommands; doReturn(mUiccCard).when(mPhone).getUiccCard(); + doReturn(mUiccCard).when(mUiccSlot).getUiccCard(); + doReturn(mUiccCard).when(mUiccController).getUiccCardForPhone(anyInt()); doReturn(mUiccPort).when(mPhone).getUiccPort(); doReturn(mUiccProfile).when(mUiccPort).getUiccProfile(); @@ -662,7 +666,8 @@ public abstract class TelephonyTest { } } }).when(mUiccController).getIccRecords(anyInt(), anyInt()); - doReturn(new UiccSlot[] {}).when(mUiccController).getUiccSlots(); + doReturn(new UiccSlot[] {mUiccSlot}).when(mUiccController).getUiccSlots(); + doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt()); doReturn(mPinStorage).when(mUiccController).getPinStorage(); //UiccCardApplication 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 23d94e2717..feccd40b6a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -24,8 +24,11 @@ import static com.android.internal.telephony.subscription.SubscriptionDatabaseMa import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CONTACT1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CONTACT2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_EHPLMNS1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_HPLMNS1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_IMSI1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MCC1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MCC2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MNC1; @@ -77,8 +80,10 @@ import android.service.carrier.CarrierIdentifier; import android.service.euicc.EuiccProfileInfo; import android.service.euicc.EuiccService; import android.service.euicc.GetEuiccProfileInfoListResult; +import android.telephony.RadioAccessFamily; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.telephony.UiccAccessRule; import android.test.mock.MockContentResolver; import android.testing.AndroidTestingRunner; @@ -86,12 +91,12 @@ import android.testing.TestableLooper; import android.util.Base64; import com.android.internal.telephony.ContextFixture; +import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; -import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccSlot; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; @@ -128,8 +133,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // mocked private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback; private EuiccController mEuiccController; - private UiccSlot mUiccSlot; - private UiccCard mUiccCard; @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule(); @@ -148,12 +151,10 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(true).when(mTelephonyManager).isVoiceCapable(); mEuiccController = Mockito.mock(EuiccController.class); replaceInstance(EuiccController.class, "sInstance", null, mEuiccController); - mUiccSlot = Mockito.mock(UiccSlot.class); - mUiccCard = Mockito.mock(UiccCard.class); mMockedSubscriptionManagerServiceCallback = Mockito.mock( SubscriptionManagerServiceCallback.class); - doReturn(mUiccCard).when(mUiccSlot).getUiccCard(); doReturn(FAKE_ICCID1).when(mUiccCard).getCardId(); + doReturn(FAKE_ICCID1).when(mUiccPort).getIccId(); ((MockContentResolver) mContext.getContentResolver()).addProvider( Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); @@ -1738,4 +1739,57 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfo.isRemovableEmbedded()).isFalse(); assertThat(subInfo.getNativeAccessRules()).isEqualTo(FAKE_NATIVE_ACCESS_RULES1); } + + @Test + public void testInsertNewSim() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + doReturn(FAKE_IMSI1).when(mTelephonyManager).getSubscriberId(); + doReturn(FAKE_MCC1 + FAKE_MNC1).when(mTelephonyManager).getSimOperatorNumeric(anyInt()); + doReturn(FAKE_PHONE_NUMBER1).when(mTelephonyManager).getLine1Number(anyInt()); + doReturn(FAKE_EHPLMNS1.split(",")).when(mSimRecords).getEhplmns(); + doReturn(FAKE_HPLMNS1.split(",")).when(mSimRecords).getPlmnsFromHplmnActRecord(); + doReturn(0).when(mUiccSlot).getPortIndexFromIccId(anyString()); + doReturn(false).when(mUiccSlot).isEuicc(); + doReturn(1).when(mUiccController).convertToPublicCardId(eq(FAKE_ICCID1)); + + mSubscriptionManagerServiceUT.updateSimState( + 0, TelephonyManager.SIM_STATE_READY, null, null); + processAllMessages(); + + mSubscriptionManagerServiceUT.updateSimState( + 0, TelephonyManager.SIM_STATE_LOADED, null, null); + processAllMessages(); + mSubscriptionManagerServiceUT.setCarrierId(1, FAKE_CARRIER_ID1); + mSubscriptionManagerServiceUT.setDisplayNameUsingSrc(FAKE_CARRIER_NAME1, 1, + SubscriptionManager.NAME_SOURCE_SIM_SPN); + mSubscriptionManagerServiceUT.setCarrierName(1, FAKE_CARRIER_NAME1); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo.getSubscriptionId()).isEqualTo(1); + assertThat(subInfo.getSimSlotIndex()).isEqualTo(0); + assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID1); + assertThat(subInfo.getPortIndex()).isEqualTo(0); + assertThat(subInfo.isEmbedded()).isFalse(); + assertThat(subInfo.getCarrierId()).isEqualTo(FAKE_CARRIER_ID1); + assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); + assertThat(subInfo.getDisplayNameSource()).isEqualTo( + SubscriptionManager.NAME_SOURCE_SIM_SPN); + assertThat(subInfo.getCarrierName()).isEqualTo(FAKE_CARRIER_NAME1); + assertThat(subInfo.isOpportunistic()).isFalse(); + assertThat(subInfo.getNumber()).isEqualTo(FAKE_PHONE_NUMBER1); + assertThat(subInfo.getMcc()).isEqualTo(FAKE_MCC1); + assertThat(subInfo.getMnc()).isEqualTo(FAKE_MNC1); + assertThat(subInfo.getEhplmns()).isEqualTo(FAKE_EHPLMNS1); + assertThat(subInfo.getHplmns()).isEqualTo(FAKE_HPLMNS1); + assertThat(subInfo.getCardString()).isEqualTo(FAKE_ICCID1); + assertThat(subInfo.getCardId()).isEqualTo(1); + assertThat(subInfo.getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + assertThat(subInfo.areUiccApplicationsEnabled()).isTrue(); + assertThat(subInfo.getAllowedNetworkTypesForReasons()).isEqualTo("user=" + + RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE)); + } } -- GitLab From 4cbf718411e51e239402c23da2276ea5dd0fa25d Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 7 Feb 2023 11:20:24 +0000 Subject: [PATCH 403/656] Unregister the callback handler on cancelSelection If a user hangs up a call while changing preferred transport type, the result callback causes IllegalStateException by sending message to a Handler on a dead thread. Bug: 266191727 Test: atest EmergencyCallDomainSelectionConnection Change-Id: I68c34839d99f552a255edd716ecd1aa1005167e5 --- .../EmergencyCallDomainSelectionConnection.java | 9 +++++++++ .../EmergencyCallDomainSelectionConnectionTest.java | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java index 4cb956e626..99105205a3 100644 --- a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java @@ -176,6 +176,15 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne } } + /** {@inheritDoc} */ + @Override + public void cancelSelection() { + logi("cancelSelection"); + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + anm.unregisterForQualifiedNetworksChanged(mHandler); + super.cancelSelection(); + } + /** * Returns the attributes required to determine the domain for a telephony service. * diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java index fff77b784c..4a0f627cd1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java @@ -217,4 +217,11 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { verify(mConnectionCallback).onSelectionTerminated(eq(ERROR_UNSPECIFIED)); } + + @Test + @SmallTest + public void testCancelSelection() throws Exception { + mEcDsc.cancelSelection(); + verify(mAnm).unregisterForQualifiedNetworksChanged(any()); + } } -- GitLab From ae5ed0dc13d1874716ed5a578ef063d277fe88ee Mon Sep 17 00:00:00 2001 From: rambowang Date: Tue, 6 Dec 2022 22:45:06 -0600 Subject: [PATCH 404/656] Update ImsPhoneCallTracker with new CarrierConfigManager APIs Replace carrier config change broadcast receiver with listener Bug: 263267340 Test: atest ImsPhoneCallTrackerTest Change-Id: Ifd10745e026a2520f8c2e5ca58036e1e13032e55 --- .../imsphone/ImsPhoneCallTracker.java | 66 ++++++++++++------- .../imsphone/ImsPhoneCallTrackerTest.java | 14 ++-- 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index a170702a4d..1a4d6ba484 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -571,31 +571,35 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } } + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = + new CarrierConfigManager.CarrierConfigChangeListener() { + @Override + public void onCarrierConfigChanged(int slotIndex, int subId, int carrierId, + int specificCarrierId) { + if (mPhone.getPhoneId() != slotIndex) { + log("onReceive: Skipping indication for other phoneId: " + slotIndex); + return; + } + + PersistableBundle carrierConfig = getCarrierConfigBundle(subId); + mCarrierConfigForSubId = new Pair<>(subId, carrierConfig); + if (!mCurrentlyConnectedSubId.isEmpty() + && subId == mCurrentlyConnectedSubId.get()) { + log("onReceive: Applying carrier config for subId: " + subId); + updateCarrierConfiguration(subId, carrierConfig); + } else { + // cache the latest config update until ImsService connects for this subId. + // Once it has connected, startListeningForCalls will apply the config. + log("onReceive: caching carrier config until ImsService connects for " + + "subId: " + subId); + } + } + }; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - int subId = intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - int phoneId = intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_PHONE_INDEX); - if (mPhone.getPhoneId() != phoneId) { - log("onReceive: Skipping indication for other phoneId: " + phoneId); - return; - } - PersistableBundle carrierConfig = getCarrierConfigBundle(subId); - mCarrierConfigForSubId = new Pair<>(subId, carrierConfig); - if (!mCurrentlyConnectedSubId.isEmpty() - && subId == mCurrentlyConnectedSubId.get()) { - log("onReceive: Applying carrier config for subId: " + subId); - updateCarrierConfiguration(subId, carrierConfig); - } else { - // cache the latest config update until ImsService connects for this subId. - // Once it has connected, startListeningForCalls will apply the config. - log("onReceive: caching carrier config until ImsService connects for subId: " - + subId); - } - } else if (TelecomManager.ACTION_DEFAULT_DIALER_CHANGED.equals(intent.getAction())) { + if (TelecomManager.ACTION_DEFAULT_DIALER_CHANGED.equals(intent.getAction())) { mDefaultDialerUid.set(getPackageUid(context, intent.getStringExtra( TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME))); } @@ -1251,10 +1255,20 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mMetrics = TelephonyMetrics.getInstance(); IntentFilter intentfilter = new IntentFilter(); - intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intentfilter.addAction(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED); mPhone.getContext().registerReceiver(mReceiver, intentfilter); - updateCarrierConfiguration(mPhone.getSubId(), getCarrierConfigBundle(mPhone.getSubId())); + + CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); + // Callback of listener directly access global states which are limited on main thread. + // The callback can only be executed on main thread. + if (ccm != null) { + ccm.registerCarrierConfigChangeListener( + mPhone.getContext().getMainExecutor(), mCarrierConfigChangeListener); + updateCarrierConfiguration( + mPhone.getSubId(), getCarrierConfigBundle(mPhone.getSubId())); + } else { + loge("CarrierConfigManager is not available."); + } mSettingsCallback = new DataSettingsManager.DataSettingsManagerCallback(this::post) { @Override @@ -1515,6 +1529,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { clearDisconnected(); mPhone.getContext().unregisterReceiver(mReceiver); + CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); + if (ccm != null && mCarrierConfigChangeListener != null) { + ccm.unregisterCarrierConfigChangeListener(mCarrierConfigChangeListener); + } mPhone.getDefaultPhone().getDataSettingsManager().unregisterCallback(mSettingsCallback); mImsManagerConnector.disconnect(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index e0bfcd7af3..911d3b63c9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -70,7 +70,6 @@ import static org.mockito.Mockito.when; import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.NetworkStats; @@ -173,6 +172,7 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { private ImsPhoneCallTracker.ConnectorFactory mConnectorFactory; private CommandsInterface mMockCi; private DomainSelectionResolver mDomainSelectionResolver; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; private final Executor mExecutor = Runnable::run; @@ -278,7 +278,13 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { DomainSelectionResolver.setDomainSelectionResolver(mDomainSelectionResolver); doReturn(false).when(mDomainSelectionResolver).isDomainSelectionSupported(); + // Capture CarrierConfigChangeListener to emulate the carrier config change notification + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); mCTUT = new ImsPhoneCallTracker(mImsPhone, mConnectorFactory, Runnable::run); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); mCTUT.setDataEnabled(true); final ArgumentCaptor vtDataUsageProviderCaptor = @@ -2606,10 +2612,8 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { } private void sendCarrierConfigChanged() { - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - mBroadcastReceiver.onReceive(mContext, intent); + mCarrierConfigChangeListener.onCarrierConfigChanged(mPhone.getPhoneId(), mPhone.getSubId(), + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); } -- GitLab From a4950431b069ee90cca873cd91a3375b5d25fe69 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 8 Feb 2023 01:02:10 -0800 Subject: [PATCH 405/656] Support group disabled bit correctly Port the group disabled logic from SubscriptionController to SubscriptionManagerService. Fix: 268300938 Test: Boot up test and basic phone funcationality tests Test: atest SubscriptionManagerServiceTest Change-Id: I577dd4ec13d053f52e388456a9639a6e6bd3b736 --- .../SubscriptionDatabaseManager.java | 40 +++++++++++++++---- .../SubscriptionManagerService.java | 31 ++++++++++++++ .../SubscriptionManagerServiceTest.java | 31 ++++++++++---- 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 665ba97321..7c72c305bb 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -1221,8 +1221,8 @@ public class SubscriptionDatabaseManager extends Handler { try { SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get(subId); if (subInfoCache == null) { - throw new IllegalArgumentException("Subscription doesn't exist. subId=" + subId - + ", columnName=cardId"); + throw new IllegalArgumentException("setCardId: Subscription doesn't exist. subId=" + + subId); } mAllSubscriptionInfoInternalCache.put(subId, new SubscriptionInfoInternal.Builder(subInfoCache) @@ -1763,6 +1763,36 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal.Builder::setSatelliteEnabled); } + /** + * Set whether group of the subscription is disabled. This is only useful if it's a grouped + * opportunistic subscription. In this case, if all primary (non-opportunistic) + * subscriptions in the group are deactivated (unplugged pSIM or deactivated eSIM profile), + * we should disable this opportunistic subscription. + * + * @param subId Subscription id. + * @param isGroupDisabled if group of the subscription is disabled. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setGroupDisabled(int subId, boolean isGroupDisabled) { + // group disabled does not have a corresponding SimInfo column. So we only update the cache. + + // Grab the write lock so no other threads can read or write the cache. + mReadWriteLock.writeLock().lock(); + try { + SubscriptionInfoInternal subInfoCache = mAllSubscriptionInfoInternalCache.get(subId); + if (subInfoCache == null) { + throw new IllegalArgumentException("setGroupDisabled: Subscription doesn't exist. " + + "subId=" + subId); + } + mAllSubscriptionInfoInternalCache.put(subId, + new SubscriptionInfoInternal.Builder(subInfoCache) + .setGroupDisabled(isGroupDisabled).build()); + } finally { + mReadWriteLock.writeLock().unlock(); + } + } + /** * Load the entire database into the cache. */ @@ -2004,12 +2034,6 @@ public class SubscriptionDatabaseManager extends Handler { } } - /** - * @return {@code true} if the database has been loaded into the cache. - */ - public boolean isDatabaseLoaded() { - return mDatabaseLoaded; - } /** * Log debug messages. * diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 6ecaee6e6a..29f781e88d 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -921,6 +921,7 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SIM_SLOT_INDEX); mSlotIndexToSubId.remove(simSlotIndex); }); + updateGroupDisabled(); } /** @@ -1346,6 +1347,7 @@ public class SubscriptionManagerService extends ISub.Stub { MultiSimSettingController.getInstance().notifyAllSubscriptionLoaded(); } + updateGroupDisabled(); updateDefaultSubId(); } @@ -1489,6 +1491,8 @@ public class SubscriptionManagerService extends ISub.Stub { } } + updateGroupDisabled(); + final int preferredUsageSetting = config.getInt( CarrierConfigManager.KEY_CELLULAR_USAGE_SETTING_INT, SubscriptionManager.USAGE_SETTING_UNKNOWN); @@ -1900,6 +1904,7 @@ public class SubscriptionManagerService extends ISub.Stub { } int subId = insertSubscriptionInfo(iccId, slotIndex, displayName, subscriptionType); + updateGroupDisabled(); mSlotIndexToSubId.put(slotIndex, subId); } else { // Record already exists. @@ -2214,6 +2219,7 @@ public class SubscriptionManagerService extends ISub.Stub { mSubscriptionDatabaseManager.setGroupUuid(subId, uuidString); mSubscriptionDatabaseManager.setGroupOwner(subId, callingPackage); } + updateGroupDisabled(); MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUUID); return groupUUID; @@ -2405,6 +2411,8 @@ public class SubscriptionManagerService extends ISub.Stub { subInfo.getSubscriptionId(), callingPackage); } } + + updateGroupDisabled(); } finally { Binder.restoreCallingIdentity(identity); } @@ -2464,6 +2472,7 @@ public class SubscriptionManagerService extends ISub.Stub { mSubscriptionDatabaseManager.setGroupOwner(subId, callingPackage); } + updateGroupDisabled(); MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUuid); logl("addSubscriptionsIntoGroup: add subs " + Arrays.toString(subIdList) + " to the group."); @@ -3734,6 +3743,28 @@ public class SubscriptionManagerService extends ISub.Stub { Binder.getCallingUid())); } + /** + * Update the {@link SubscriptionInfo#isGroupDisabled()} bit for the opportunistic + * subscriptions. + * + * If all primary (non-opportunistic) subscriptions in the group are deactivated + * (unplugged pSIM or deactivated eSIM profile), we should disable this opportunistic + * subscriptions. + */ + @VisibleForTesting + public void updateGroupDisabled() { + List activeSubscriptions = getActiveSubscriptionInfoList( + mContext.getOpPackageName(), mContext.getFeatureId()); + for (SubscriptionInfo oppSubInfo : getOpportunisticSubscriptions( + mContext.getOpPackageName(), mContext.getFeatureId())) { + boolean groupDisabled = activeSubscriptions.stream() + .noneMatch(subInfo -> !subInfo.isOpportunistic() + && Objects.equals(oppSubInfo.getGroupUuid(), subInfo.getGroupUuid())); + mSubscriptionDatabaseManager.setGroupDisabled( + oppSubInfo.getSubscriptionId(), groupDisabled); + } + } + /** * Log debug messages. * 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 feccd40b6a..e620b51709 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -88,6 +88,7 @@ import android.telephony.UiccAccessRule; import android.test.mock.MockContentResolver; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.ArraySet; import android.util.Base64; import com.android.internal.telephony.ContextFixture; @@ -134,6 +135,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback; private EuiccController mEuiccController; + private Set mActiveSubs = new ArraySet<>(); + @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule(); @@ -156,6 +159,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(FAKE_ICCID1).when(mUiccCard).getCardId(); doReturn(FAKE_ICCID1).when(mUiccPort).getIccId(); + doReturn(new int[0]).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); + ((MockContentResolver) mContext.getContentResolver()).addProvider( Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); @@ -250,6 +255,15 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(subId)); Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); + + if (subInfo.getSimSlotIndex() >= 0) { + mActiveSubs.add(subId); + } else { + mActiveSubs.remove(subId); + } + + doReturn(mActiveSubs.stream().mapToInt(i->i).toArray()).when(mSubscriptionManager) + .getCompleteActiveSubscriptionIdList(); return subId; } catch (Exception e) { fail("Failed to insert subscription. e=" + e); @@ -373,7 +387,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testGetAllSubInfoList() { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); - doReturn(new int[]{1, 2}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); @@ -442,8 +455,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test @EnableCompatChanges({SubscriptionManagerService.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) public void testGetSubscriptionsInGroup() { - doReturn(new int[]{1, 2}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); - insertSubscription(FAKE_SUBSCRIPTION_INFO1); SubscriptionInfoInternal anotherSubInfo = new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO2) @@ -659,7 +670,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testGetActiveSubscriptionInfoList() { - doReturn(new int[]{1}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); // Grant MODIFY_PHONE_STATE permission for insertion. mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); insertSubscription(FAKE_SUBSCRIPTION_INFO1); @@ -837,7 +847,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testGetActiveSubInfoCount() { - doReturn(new int[]{1, 2}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); @@ -1003,7 +1012,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetUsageSetting() { - doReturn(new int[]{1}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); insertSubscription(FAKE_SUBSCRIPTION_INFO1); // Should fail without MODIFY_PHONE_STATE @@ -1048,7 +1056,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetOpportunistic() { - doReturn(new int[]{1}).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); insertSubscription(FAKE_SUBSCRIPTION_INFO1); // Should fail without MODIFY_PHONE_STATE @@ -1792,4 +1799,14 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfo.getAllowedNetworkTypesForReasons()).isEqualTo("user=" + RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE)); } + + @Test + public void testGroupDisable() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO2) + .setGroupUuid(FAKE_UUID1).build()); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isGroupDisabled()) + .isFalse(); + } } -- GitLab From 31f764682d2c648cf9be18ebf907dd72fb7240ff Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Wed, 1 Feb 2023 10:58:13 +0000 Subject: [PATCH 406/656] Renaming of KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT Renaming KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT to KEY_SMS_MAX_RETRY_OVER_IMS_COUNT_INT Bug: b/266675272 Test: mm build, atest ImsSmsDispatcherTest Change-Id: I7ef01913babfe69ed7a05d0e2f2fe6fd6da1bb76 --- .../com/android/internal/telephony/ImsSmsDispatcher.java | 2 +- .../android/internal/telephony/ImsSmsDispatcherTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java index e0529e12e3..90885fe6e3 100644 --- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java +++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java @@ -496,7 +496,7 @@ public class ImsSmsDispatcher extends SMSDispatcher { if (carrierConfig != null) { retryCountOverIms = carrierConfig.getInt( - CarrierConfigManager.ImsSms.KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT); + CarrierConfigManager.ImsSms.KEY_SMS_MAX_RETRY_OVER_IMS_COUNT_INT); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java index 6ffceaf0c1..f9cac53659 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java @@ -244,7 +244,7 @@ public class ImsSmsDispatcherTest extends TelephonyTest { .KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT, 2000); mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms - .KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT, 3); + .KEY_SMS_MAX_RETRY_OVER_IMS_COUNT_INT, 3); mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms .KEY_SMS_MAX_RETRY_COUNT_INT, 3); mTrackerData.put("pdu", com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(null, @@ -368,7 +368,7 @@ public class ImsSmsDispatcherTest extends TelephonyTest { .KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT, 2000); mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms - .KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT, 3); + .KEY_SMS_MAX_RETRY_OVER_IMS_COUNT_INT, 3); mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms .KEY_SMS_MAX_RETRY_COUNT_INT, 3); when(mImsManager.getSmsFormat()).thenReturn(SmsMessage.FORMAT_3GPP); @@ -404,7 +404,7 @@ public class ImsSmsDispatcherTest extends TelephonyTest { .KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT, 3000); mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms - .KEY_SMS_MAX_RETRY_COUNT_OVER_IMS_INT, 2); + .KEY_SMS_MAX_RETRY_OVER_IMS_COUNT_INT, 2); mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms .KEY_SMS_MAX_RETRY_COUNT_INT, 3); when(mImsManager.getSmsFormat()).thenReturn(SmsMessage.FORMAT_3GPP); -- GitLab From 3867a2b70151b1b76a00113a4e3db4c19c8a4ae1 Mon Sep 17 00:00:00 2001 From: rambowang Date: Wed, 8 Feb 2023 13:13:59 -0600 Subject: [PATCH 407/656] Update telephony lib components to remove dupplication CarrierConfigManager.getCarrierConfigSubset is introduced to remove the repetitive private methods in system components. Bug: 263267340 Test: FrameworksTelephonyTests Change-Id: Iddde4ef4c5736c02065b8c749a674a95555f5ec8 --- .../telephony/CarrierPrivilegesTracker.java | 17 +++--------- .../telephony/data/DataServiceManager.java | 19 +++++--------- .../emergency/EmergencyNumberTracker.java | 26 +++++-------------- .../internal/telephony/uicc/PinStorage.java | 16 +++++------- .../internal/telephony/uicc/UiccProfile.java | 19 +++----------- 5 files changed, 26 insertions(+), 71 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index b9c45c45b4..0fda1f2007 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -124,13 +124,6 @@ public class CarrierPrivilegesTracker extends Handler { | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS; - /** - * All carrier config keys used in this class should list here in alphabetical order. - */ - private static final String[] CARRIER_CONFIG_KEYS = { - KEY_CARRIER_CERTIFICATE_STRING_ARRAY, - }; - /** * Action to register a Registrant with this Tracker. * obj: Registrant that will be notified of Carrier Privileged UID changes. @@ -469,13 +462,9 @@ public class CarrierPrivilegesTracker extends Handler { @NonNull private List getCarrierConfigRules(int subId) { - PersistableBundle carrierConfigs = null; - try { - carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId, CARRIER_CONFIG_KEYS); - } catch (RuntimeException e) { - mLocalLog.log("CarrierConfigLoader is not available, try it later."); - } - + PersistableBundle carrierConfigs = + CarrierConfigManager.getCarrierConfigSubset( + mContext, subId, KEY_CARRIER_CERTIFICATE_STRING_ARRAY); // CarrierConfigManager#isConfigForIdentifiedCarrier can handle null or empty bundle if (!mCarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) { return Collections.EMPTY_LIST; diff --git a/src/java/com/android/internal/telephony/data/DataServiceManager.java b/src/java/com/android/internal/telephony/data/DataServiceManager.java index 3141fef8d4..2733aff3ae 100644 --- a/src/java/com/android/internal/telephony/data/DataServiceManager.java +++ b/src/java/com/android/internal/telephony/data/DataServiceManager.java @@ -571,7 +571,9 @@ public class DataServiceManager extends Handler { // Read package name from resource overlay packageName = mPhone.getContext().getResources().getString(resourceId); - PersistableBundle b = getCarrierConfigSubset(carrierConfig); + PersistableBundle b = + CarrierConfigManager.getCarrierConfigSubset( + mPhone.getContext(), mPhone.getSubId(), carrierConfig); if (!b.isEmpty() && !TextUtils.isEmpty(b.getString(carrierConfig))) { // If carrier config overrides it, use the one from carrier config packageName = b.getString(carrierConfig, packageName); @@ -619,7 +621,9 @@ public class DataServiceManager extends Handler { // Read package name from resource overlay className = mPhone.getContext().getResources().getString(resourceId); - PersistableBundle b = getCarrierConfigSubset(carrierConfig); + PersistableBundle b = + CarrierConfigManager.getCarrierConfigSubset( + mPhone.getContext(), mPhone.getSubId(), carrierConfig); if (!b.isEmpty() && !TextUtils.isEmpty(b.getString(carrierConfig))) { // If carrier config overrides it, use the one from carrier config className = b.getString(carrierConfig, className); @@ -628,17 +632,6 @@ public class DataServiceManager extends Handler { return className; } - @NonNull - private PersistableBundle getCarrierConfigSubset(String key) { - PersistableBundle configs = null; - try { - configs = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), key); - } catch (RuntimeException e) { - loge("CarrierConfigLoader is not available."); - } - return configs != null ? configs : new PersistableBundle(); - } - private void sendCompleteMessage(Message msg, @DataServiceCallback.ResultCode int code) { if (msg != null) { msg.arg1 = code; diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index d6b7b0b136..8c8dff2fe2 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -186,7 +186,9 @@ public class EmergencyNumberTracker extends Handler { CarrierConfigManager configMgr = (CarrierConfigManager) mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); if (configMgr != null) { - PersistableBundle b = getCarrierConfigSubset( + PersistableBundle b = CarrierConfigManager.getCarrierConfigSubset( + mPhone.getContext(), + mPhoneId, CarrierConfigManager.KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY); if (!b.isEmpty()) { mEmergencyNumberPrefix = b.getStringArray( @@ -355,7 +357,9 @@ public class EmergencyNumberTracker extends Handler { if (slotIndex != mPhone.getPhoneId()) return; PersistableBundle b = - getCarrierConfigSubset( + CarrierConfigManager.getCarrierConfigSubset( + mPhone.getContext(), + mPhone.getPhoneId(), CarrierConfigManager.KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY); if (!b.isEmpty()) { String[] emergencyNumberPrefix = @@ -371,24 +375,6 @@ public class EmergencyNumberTracker extends Handler { } } - @NonNull - private PersistableBundle getCarrierConfigSubset(String key) { - PersistableBundle bundle = null; - - if (mPhone != null) { - CarrierConfigManager ccm = - mPhone.getContext().getSystemService(CarrierConfigManager.class); - try { - if (ccm != null) { - bundle = ccm.getConfigForSubId(mPhone.getPhoneId(), key); - } - } catch (RuntimeException e) { - loge("CarrierConfigLoader is not available."); - } - } - return bundle != null ? bundle : new PersistableBundle(); - } - private String getInitialCountryIso() { if (mPhone != null) { ServiceStateTracker sst = mPhone.getServiceStateTracker(); diff --git a/src/java/com/android/internal/telephony/uicc/PinStorage.java b/src/java/com/android/internal/telephony/uicc/PinStorage.java index acec14e83d..18bf666847 100644 --- a/src/java/com/android/internal/telephony/uicc/PinStorage.java +++ b/src/java/com/android/internal/telephony/uicc/PinStorage.java @@ -991,15 +991,13 @@ public class PinStorage extends Handler { PersistableBundle config = null; CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class); - if (configManager != null) { - Phone phone = PhoneFactory.getPhone(slotId); - try { - // If an invalid subId is used, this bundle will contain default values. - config = configManager.getConfigForSubId(phone.getSubId(), - CarrierConfigManager.KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL); - } catch (RuntimeException e) { - loge("Can't get carrier config subset."); - } + Phone phone = PhoneFactory.getPhone(slotId); + if (configManager != null && phone != null) { + config = + CarrierConfigManager.getCarrierConfigSubset( + mContext, + phone.getSubId(), + CarrierConfigManager.KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL); } if (config == null || config.isEmpty()) { config = CarrierConfigManager.getDefaultConfig(); diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index 1d8615b0ee..c27fff16e3 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -20,7 +20,6 @@ import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_VERIFICATION_FAILURE; import static com.android.internal.telephony.TelephonyStatsLog.PIN_STORAGE_EVENT__EVENT__PIN_VERIFICATION_SUCCESS; -import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.usage.UsageStatsManager; @@ -462,7 +461,8 @@ public class UiccProfile extends IccCard { } PersistableBundle config = - getCarrierConfigSubset( + CarrierConfigManager.getCarrierConfigSubset( + mContext, subId, CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL, CarrierConfigManager.KEY_CARRIER_NAME_STRING); @@ -534,8 +534,8 @@ public class UiccProfile extends IccCard { } PersistableBundle config = - getCarrierConfigSubset( - subId, CarrierConfigManager.KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING); + CarrierConfigManager.getCarrierConfigSubset( + mContext, subId, CarrierConfigManager.KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING); if (config.isEmpty()) { loge("handleSimCountryIsoOverride: fail to get carrier configs."); return; @@ -1817,17 +1817,6 @@ public class UiccProfile extends IccCard { return null; } - @NonNull - private PersistableBundle getCarrierConfigSubset(int subId, String... keys) { - PersistableBundle bundle = null; - try { - bundle = mCarrierConfigManager.getConfigForSubId(subId, keys); - } catch (RuntimeException e) { - loge("CarrierConfigLoader is not available."); - } - return bundle != null ? bundle : new PersistableBundle(); - } - private static String eventToString(int event) { switch (event) { case EVENT_RADIO_OFF_OR_UNAVAILABLE: return "RADIO_OFF_OR_UNAVAILABLE"; -- GitLab From d7c5a44790cf35c6443b2b9874bffa99a75a042d Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Wed, 1 Feb 2023 11:12:16 -0800 Subject: [PATCH 408/656] Support satellite provision APIs Bug: 266013384 Test: atest android.telephony.cts.SatelliteManagerTest Change-Id: I2bb0f153efdc3b0a9308422696615d1d419ac9f2 --- .../internal/telephony/CommandException.java | 34 ++++++++++- .../com/android/internal/telephony/Phone.java | 54 ++++++++++++++++ .../android/internal/telephony/RILUtils.java | 61 ++++++++++++++++--- .../telephony/SatelliteIndication.java | 4 +- 4 files changed, 143 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandException.java b/src/java/com/android/internal/telephony/CommandException.java index 72bb6a36f5..6b6d84f0e8 100644 --- a/src/java/com/android/internal/telephony/CommandException.java +++ b/src/java/com/android/internal/telephony/CommandException.java @@ -131,6 +131,17 @@ public class CommandException extends RuntimeException { BLOCKED_DUE_TO_CALL, RF_HARDWARE_ISSUE, NO_RF_CALIBRATION_INFO, + ENCODING_NOT_SUPPORTED, + FEATURE_NOT_SUPPORTED, + INVALID_CONTACT, + MODEM_INCOMPATIBLE, + NETWORK_TIMEOUT, + NO_SATELLITE_SIGNAL, + NOT_SUFFICIENT_ACCOUNT_BALANCE, + RADIO_TECHNOLOGY_NOT_SUPPORTED, + SUBSCRIBER_NOT_AUTHORIZED, + SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL, + UNIDENTIFIED_SUBSCRIBER } @UnsupportedAppUsage @@ -341,7 +352,28 @@ public class CommandException extends RuntimeException { return new CommandException(Error.RF_HARDWARE_ISSUE); case RILConstants.NO_RF_CALIBRATION_INFO: return new CommandException(Error.NO_RF_CALIBRATION_INFO); - + case RILConstants.ENCODING_NOT_SUPPORTED: + return new CommandException(Error.ENCODING_NOT_SUPPORTED); + case RILConstants.FEATURE_NOT_SUPPORTED: + return new CommandException(Error.FEATURE_NOT_SUPPORTED); + case RILConstants.INVALID_CONTACT: + return new CommandException(Error.INVALID_CONTACT); + case RILConstants.MODEM_INCOMPATIBLE: + return new CommandException(Error.MODEM_INCOMPATIBLE); + case RILConstants.NETWORK_TIMEOUT: + return new CommandException(Error.NETWORK_TIMEOUT); + case RILConstants.NO_SATELLITE_SIGNAL: + return new CommandException(Error.NO_SATELLITE_SIGNAL); + case RILConstants.NOT_SUFFICIENT_ACCOUNT_BALANCE: + return new CommandException(Error.NOT_SUFFICIENT_ACCOUNT_BALANCE); + case RILConstants.RADIO_TECHNOLOGY_NOT_SUPPORTED: + return new CommandException(Error.RADIO_TECHNOLOGY_NOT_SUPPORTED); + case RILConstants.SUBSCRIBER_NOT_AUTHORIZED: + return new CommandException(Error.SUBSCRIBER_NOT_AUTHORIZED); + case RILConstants.SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL: + return new CommandException(Error.SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL); + case RILConstants.UNIDENTIFIED_SUBSCRIBER: + return new CommandException(Error.UNIDENTIFIED_SUBSCRIBER); default: Rlog.e("GSM", "Unrecognized RIL errno " + ril_errno); return new CommandException(Error.INVALID_RESPONSE); diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 0f64dcd52b..715c0399fe 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5321,6 +5321,60 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.unregisterForSatelliteMessagesTransferComplete(h); } + /** + * Provision the subscription with a satellite provider. This is needed to register the + * subscription if the provider allows dynamic registration. + * + * @param result Callback message to receive the result. + * @param imei IMEI of the SIM associated with the satellite modem. + * @param msisdn MSISDN of the SIM associated with the satellite modem. + * @param imsi IMSI of the SIM associated with the satellite modem. + * @param features List of features to be provisioned. + */ + public void provisionSatelliteService(Message result, String imei, String msisdn, String imsi, + int[] features) { + mCi.provisionSatelliteService(result, imei, msisdn, imsi, features); + } + + /** + * Cancel the ongoing provision satellite request of a subscription. + * + * @param result Callback message to receive the result. + * @param imsi IMSI of the subscription whose provision request will be cancelled. + */ + public void cancelProvisionSatelliteService(Message result, String imsi) { + //TODO (b/266126070): add implementation. + } + + /** + * Register for a satellite provision state changed event. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForSatelliteProvisionStateChanged(Handler h, int what, Object obj) { + mCi.registerForSatelliteProvisionStateChanged(h, what, obj); + } + + /** + * Unregister for a satellite provision state changed event. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForSatelliteProvisionStateChanged(Handler h) { + mCi.unregisterForSatelliteProvisionStateChanged(h); + } + + /** + * Get the list of provisioned satellite features. + * + * @param result Callback message to receive the result. + */ + public void getProvisionedSatelliteFeatures(Message result) { + //TODO (b/266126070): add implementation. + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 364a385c91..bf3fa8c706 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -6026,10 +6026,11 @@ public class RILUtils { CommandException.Error error) { switch (error) { case INTERNAL_ERR: - case MODEM_ERR: return SatelliteManager.SATELLITE_SERVICE_MODEM_ERROR; + case MODEM_ERR: + return SatelliteManager.SATELLITE_SERVICE_UNEXPECTED_MODEM_RESPONSE; case SYSTEM_ERR: - return SatelliteManager.SATELLITE_SERVICE_SYSTEM_ERROR; + return SatelliteManager.SATELLITE_SERVICE_RIL_ERROR; case INVALID_ARGUMENTS: return SatelliteManager.SATELLITE_SERVICE_INVALID_ARGUMENTS; case INVALID_MODEM_STATE: @@ -6037,17 +6038,63 @@ public class RILUtils { case INVALID_SIM_STATE: return SatelliteManager.SATELLITE_SERVICE_INVALID_SIM_STATE; case INVALID_STATE: - return SatelliteManager.SATELLITE_SERVICE_INVALID_STATE; + return SatelliteManager.SATELLITE_SERVICE_INVALID_RIL_STATE; case RADIO_NOT_AVAILABLE: - return SatelliteManager.SATELLITE_SERVICE_NOT_AVAILABLE; + return SatelliteManager.SATELLITE_SERVICE_RADIO_NOT_AVAILABLE; case REQUEST_NOT_SUPPORTED: - return SatelliteManager.SATELLITE_SERVICE_NOT_SUPPORTED; + return SatelliteManager.SATELLITE_SERVICE_REQUEST_NOT_SUPPORTED; case REQUEST_RATE_LIMITED: - return SatelliteManager.SATELLITE_SERVICE_RATE_LIMITED; + return SatelliteManager.SATELLITE_SERVICE_REQUEST_RATE_LIMITED; case NO_MEMORY: - return SatelliteManager.SATELLITE_SERVICE_NO_MEMORY; + //fallthrough to NO_RESOURCES case NO_RESOURCES: return SatelliteManager.SATELLITE_SERVICE_NO_RESOURCES; + case NETWORK_ERR: + return SatelliteManager.SATELLITE_SERVICE_NETWORK_ERROR; + case NETWORK_NOT_READY: + return SatelliteManager.SATELLITE_SERVICE_NETWORK_NOT_READY; + case NETWORK_REJECT: + return SatelliteManager.SATELLITE_SERVICE_SERVER_REJECT; + case NETWORK_TIMEOUT: + return SatelliteManager.SATELLITE_SERVICE_NETWORK_TIMEOUT; + case NO_NETWORK_FOUND: + //fallthrough to NO_SATELLITE_SIGNAL + case NO_SATELLITE_SIGNAL: + return SatelliteManager.SATELLITE_SERVICE_NO_SATELLITE_SIGNAL; + case ABORTED: + return SatelliteManager.SATELLITE_SERVICE_REQUEST_ABORTED; + case ACCESS_BARRED: + return SatelliteManager.SATELLITE_SERVICE_ACCESS_BARRED; + case FEATURE_NOT_SUPPORTED: + return SatelliteManager.SATELLITE_SERVICE_FEATURE_NOT_SUPPORTED; + case MODEM_INCOMPATIBLE: + return SatelliteManager.SATELLITE_SERVICE_MODEM_INCOMPATIBLE; + case NO_SUBSCRIPTION: + return SatelliteManager.SATELLITE_SERVICE_NO_SUBSCRIPTION; + case OPERATION_NOT_ALLOWED: + return SatelliteManager.SATELLITE_SERVICE_OPERATION_NOT_ALLOWED; + case RADIO_TECHNOLOGY_NOT_SUPPORTED: + return SatelliteManager.SATELLITE_SERVICE_RADIO_TECHNOLOGY_NOT_SUPPORTED; + case SIM_ABSENT: + return SatelliteManager.SATELLITE_SERVICE_SIM_ABSENT; + case SIM_BUSY: + return SatelliteManager.SATELLITE_SERVICE_SIM_BUSY; + case SIM_ERR: + return SatelliteManager.SATELLITE_SERVICE_SIM_ERR; + case SIM_FULL: + return SatelliteManager.SATELLITE_SERVICE_SIM_FULL; + case SUBSCRIBER_NOT_AUTHORIZED: + return SatelliteManager.SATELLITE_SERVICE_SUBSCRIBER_NOT_AUTHORIZED; + case ENCODING_NOT_SUPPORTED: + return SatelliteManager.SATELLITE_SERVICE_ENCODING_NOT_SUPPORTED; + case INVALID_CONTACT: + return SatelliteManager.SATELLITE_SERVICE_INVALID_CONTACT; + case NOT_SUFFICIENT_ACCOUNT_BALANCE: + return SatelliteManager.SATELLITE_SERVICE_NOT_SUFFICIENT_ACCOUNT_BALANCE; + case SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL: + return SatelliteManager.SATELLITE_SERVICE_SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL; + case UNIDENTIFIED_SUBSCRIBER: + return SatelliteManager.SATELLITE_SERVICE_UNIDENTIFIED_SUBSCRIBER; default: return SatelliteManager.SATELLITE_SERVICE_ERROR; } diff --git a/src/java/com/android/internal/telephony/SatelliteIndication.java b/src/java/com/android/internal/telephony/SatelliteIndication.java index 9b1b0e5180..9ebff587bd 100644 --- a/src/java/com/android/internal/telephony/SatelliteIndication.java +++ b/src/java/com/android/internal/telephony/SatelliteIndication.java @@ -172,8 +172,8 @@ public class SatelliteIndication extends IRadioSatelliteIndication.Stub { if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED); if (mRil.mSatelliteProvisionStateChangedRegistrants != null) { - mRil.mSatelliteProvisionStateChangedRegistrants.notifyRegistrants( - new AsyncResult(null, RILUtils.convertHalSatelliteFeatures(features), null)); + mRil.mSatelliteProvisionStateChangedRegistrants.notifyRegistrants(new AsyncResult( + provisioned, RILUtils.convertHalSatelliteFeatures(features), null)); } } } -- GitLab From 1b9586822557d7820976533536de6cbf9fc232c7 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 1 Feb 2023 23:48:10 -0800 Subject: [PATCH 409/656] Add support for satellite service APIs Test: atest SatelliteManagerTest Bug: 262819557 Change-Id: Ide465406773ac58cb532445f5f5f81f9649dc3c4 --- .../internal/telephony/CommandsInterface.java | 7 ++++ .../com/android/internal/telephony/Phone.java | 33 +++++++++++++++++++ .../com/android/internal/telephony/RIL.java | 14 ++++++++ 3 files changed, 54 insertions(+) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 915465f1ae..abd8a62c98 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -3049,6 +3049,13 @@ public interface CommandsInterface { */ default void getSatellitePowerState(Message result) {} + /** + * Check whether satellite modem is supported by the device. + * + * @param result Message that will be sent back to the requester + */ + default void isSatelliteSupported(Message result) {} + /** * Provision the subscription with a satellite provider. This is needed to register the * subscription if the provider allows dynamic registration. diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 3c7bb44921..6123a27c59 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5272,6 +5272,39 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.getMaxCharactersPerSatelliteTextMessage(result); } + /** + * Power on or off the satellite modem. + * @param result The Message to send the result of the operation to. + * @param powerOn {@code true} to power on the satellite modem and {@code false} to power off. + */ + public void setSatellitePower(Message result, boolean powerOn) { + mCi.setSatellitePower(result, powerOn); + } + + /** + * Check whether the satellite modem is powered on. + * @param result The Message to send the result of the operation to. + */ + public void isSatellitePowerOn(Message result) { + mCi.getSatellitePowerState(result); + } + + /** + * Check whether the satellite service is supported on the device. + * @param result The Message to send the result of the operation to. + */ + public void isSatelliteSupported(Message result) { + mCi.isSatelliteSupported(result); + } + + /** + * Get the satellite capabilities. + * @param result The Message to send the result of the operation to. + */ + public void getSatelliteCapabilities(Message result) { + mCi.getSatelliteCapabilities(result); + } + /** * Registers for pointing info changed from satellite modem. * diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 1c5b82f929..616706a760 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -6154,6 +6154,20 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * Check whether satellite modem is supported by the device. + * + * @param result Message that will be sent back to the requester. + */ + @Override + public void isSatelliteSupported(Message result) { + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + /** * User started pointing to the satellite. Modem should continue to update the ponting input * as user moves device. -- GitLab From 3aeb9f0db39daf156e0fb87c6a910b6f51c3d909 Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Thu, 9 Feb 2023 07:30:41 +0000 Subject: [PATCH 410/656] Add new API for iccCloseLogicalChannel to pass isEs10 information. When a common logical channel ID is opened over 2 or more LSIs(including command port LSI), there is an ambiguity in closing the logical channel. To resolve the ambiguity, pass isEs10 information about whether the logical channel was opened to send ES10 commands or not. Test: Build Bug: 268496310 Change-Id: Ie9dc36810d72a0c85037eff6b97e76b2cc1fe49a --- src/java/com/android/internal/telephony/SimResponse.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/java/com/android/internal/telephony/SimResponse.java b/src/java/com/android/internal/telephony/SimResponse.java index 55524865cc..1e1dbe5371 100644 --- a/src/java/com/android/internal/telephony/SimResponse.java +++ b/src/java/com/android/internal/telephony/SimResponse.java @@ -233,6 +233,13 @@ public class SimResponse extends IRadioSimResponse.Stub { RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); } + /** + * @param responseInfo Response info struct containing response type, serial no. and error + */ + public void iccCloseLogicalChannelWithSessionInfoResponse(RadioResponseInfo responseInfo) { + RadioResponse.responseVoid(HAL_SERVICE_SIM, mRil, responseInfo); + } + /** * @param responseInfo Response info struct containing response type, serial no. and error * @param iccIo ICC IO operation response as defined by IccIoResult -- GitLab From 9eb55811fd37bd3084aee9824809d0bc2f34162c Mon Sep 17 00:00:00 2001 From: rambowang Date: Tue, 6 Dec 2022 09:32:36 -0600 Subject: [PATCH 411/656] Update RatRatcheter with new CarrierConfigManager APIs - Replace carrier config change broadcast receiver with listener which has better performance - Retrieve subset of carrier configs as needed to save memory Bug: 244087782 Test: atest RatRatcheterTest ServiceStateTrackerTest Change-Id: I1c07e553692ae94a32199cdd052aac24cfa05d75 --- .../internal/telephony/RatRatcheter.java | 42 +++++-------------- .../telephony/DisplayInfoControllerTest.java | 2 + .../internal/telephony/RatRatcheterTest.java | 9 ++++ .../telephony/ServiceStateTrackerTest.java | 3 ++ 4 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/java/com/android/internal/telephony/RatRatcheter.java b/src/java/com/android/internal/telephony/RatRatcheter.java index 24a8ac5eff..bea2c2a15d 100644 --- a/src/java/com/android/internal/telephony/RatRatcheter.java +++ b/src/java/com/android/internal/telephony/RatRatcheter.java @@ -16,13 +16,7 @@ package com.android.internal.telephony; import android.annotation.NonNull; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; import android.os.PersistableBundle; -import android.os.UserHandle; import android.telephony.AccessNetworkConstants; import android.telephony.Annotation.NetworkType; import android.telephony.CarrierConfigManager; @@ -80,16 +74,11 @@ public class RatRatcheter { /** Constructor */ public RatRatcheter(Phone phone) { mPhone = phone; - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - try { - Context contextAsUser = phone.getContext().createPackageContextAsUser( - phone.getContext().getPackageName(), 0, UserHandle.ALL); - contextAsUser.registerReceiver(mConfigChangedReceiver, - intentFilter, null /* broadcastPermission */, null); - } catch (PackageManager.NameNotFoundException e) { - Rlog.e(LOG_TAG, "Package name not found: " + e.getMessage()); + CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); + if (ccm != null) { + ccm.registerCarrierConfigChangeListener( + mPhone.getContext().getMainExecutor(), + (slotIndex, subId, carrierId, specificCarrierId) -> resetRatFamilyMap()); } resetRatFamilyMap(); } @@ -183,25 +172,16 @@ public class RatRatcheter { } } - private BroadcastReceiver mConfigChangedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) { - resetRatFamilyMap(); - } - } - }; - private void resetRatFamilyMap() { synchronized(mRatFamilyMap) { mRatFamilyMap.clear(); - final CarrierConfigManager configManager = (CarrierConfigManager) - mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager == null) return; - PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId()); - if (b == null) return; + PersistableBundle b = + CarrierConfigManager.getCarrierConfigSubset( + mPhone.getContext(), + mPhone.getSubId(), + CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES); + if (b == null || b.isEmpty()) return; // Reads an array of strings, eg: // ["GPRS, EDGE", "EVDO, EVDO_A, EVDO_B", "HSPA, HSDPA, HSUPA, HSPAP"] diff --git a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java index fa00362c1e..7bbdb84b05 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java @@ -49,6 +49,7 @@ import org.junit.runner.RunWith; import org.mockito.Mockito; import java.util.Collections; +import java.util.concurrent.Executor; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -90,6 +91,7 @@ public class DisplayInfoControllerTest extends TelephonyTest { logd("DisplayInfoControllerTest setup!"); super.setUp(getClass().getSimpleName()); + doReturn((Executor) Runnable::run).when(mContext).getMainExecutor(); mSstHandler = new ServiceStateTrackerTestHandler(getClass().getSimpleName()); mSstHandler.start(); waitUntilReady(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/RatRatcheterTest.java b/tests/telephonytests/src/com/android/internal/telephony/RatRatcheterTest.java index 6cbb1da758..45acc40436 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/RatRatcheterTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/RatRatcheterTest.java @@ -18,6 +18,11 @@ package com.android.internal.telephony; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + import android.os.PersistableBundle; import android.telephony.AccessNetworkConstants; import android.telephony.CarrierConfigManager; @@ -31,6 +36,7 @@ import org.junit.Before; import org.junit.Test; import java.util.Arrays; +import java.util.concurrent.Executor; /** Tests for RatRatcheter. */ public class RatRatcheterTest extends TelephonyTest { @@ -41,6 +47,7 @@ public class RatRatcheterTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + doReturn((Executor) Runnable::run).when(mContext).getMainExecutor(); mServiceState = new ServiceState(); } @@ -135,6 +142,7 @@ public class RatRatcheterTest extends TelephonyTest { ServiceState newSS = new ServiceState(); mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); mBundle.putStringArray(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, new String[]{"14,19"}); @@ -153,6 +161,7 @@ public class RatRatcheterTest extends TelephonyTest { ServiceState newSS = new ServiceState(); mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); mBundle.putStringArray(CarrierConfigManager.KEY_RATCHET_RAT_FAMILIES, new String[]{}); setNetworkRegistrationInfo(oldSS, TelephonyManager.NETWORK_TYPE_LTE_CA); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index e6a3ac7b60..3e55d41798 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -112,6 +112,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.concurrent.Executor; public class ServiceStateTrackerTest extends TelephonyTest { // Mocked classes @@ -229,6 +230,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { mSubInfo = Mockito.mock(SubscriptionInfo.class); mServiceStateStats = Mockito.mock(ServiceStateStats.class); + doReturn((Executor) Runnable::run).when(mContext).getMainExecutor(); mContextFixture.putResource(R.string.config_wwan_network_service_package, "com.android.phone"); mContextFixture.putResource(R.string.config_wlan_network_service_package, @@ -242,6 +244,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { replaceInstance(ProxyController.class, "sProxyController", null, mProxyController); mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); mBundle.putStringArray( CarrierConfigManager.KEY_ROAMING_OPERATOR_STRING_ARRAY, new String[]{"123456"}); -- GitLab From 8e4c65eebb341c0abbdca81616ee956e4b47a5ed Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 5 Dec 2022 20:42:23 -0600 Subject: [PATCH 412/656] Update NetworkRegistrationManager with new CarrierConfigManager APIs Improve NetworkRegistrationManager performance by - Replacing carrier config change broadcast receiver with listener which has much smaller lagency - Retrieving subset of carrier configs to save memory Bug: 263267340 Test: atest ServiceStateTrackerTest Change-Id: I39a11d3e08379d1a7fd512b5f5648a9699f862ef --- .../telephony/NetworkRegistrationManager.java | 63 +++++++------------ .../telephony/ServiceStateTrackerTest.java | 1 + 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkRegistrationManager.java b/src/java/com/android/internal/telephony/NetworkRegistrationManager.java index 3535678a30..91cd4ec070 100644 --- a/src/java/com/android/internal/telephony/NetworkRegistrationManager.java +++ b/src/java/com/android/internal/telephony/NetworkRegistrationManager.java @@ -16,13 +16,10 @@ package com.android.internal.telephony; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.ServiceConnection; -import android.content.pm.PackageManager; import android.os.AsyncResult; import android.os.Handler; import android.os.IBinder; @@ -30,7 +27,6 @@ import android.os.Message; import android.os.PersistableBundle; import android.os.RegistrantList; import android.os.RemoteException; -import android.os.UserHandle; import android.telephony.AccessNetworkConstants; import android.telephony.AccessNetworkConstants.TransportType; import android.telephony.CarrierConfigManager; @@ -58,9 +54,6 @@ public class NetworkRegistrationManager extends Handler { private final int mTransportType; private final Phone mPhone; - - private final CarrierConfigManager mCarrierConfigManager; - // Registrants who listens registration state change callback from this class. private final RegistrantList mRegStateChangeRegistrants = new RegistrantList(); @@ -72,22 +65,6 @@ public class NetworkRegistrationManager extends Handler { private NetworkServiceConnection mServiceConnection; - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action) - && mPhone.getPhoneId() == intent.getIntExtra( - CarrierConfigManager.EXTRA_SLOT_INDEX, 0)) { - // 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. - logd("Carrier config changed. Try to bind network service."); - sendEmptyMessage(EVENT_BIND_NETWORK_SERVICE); - } - } - }; - public NetworkRegistrationManager(@TransportType int transportType, Phone phone) { mTransportType = transportType; mPhone = phone; @@ -96,19 +73,20 @@ public class NetworkRegistrationManager extends Handler { ? "C" : "I") + "-" + mPhone.getPhoneId(); mTag = "NRM" + tagSuffix; - mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService( - Context.CARRIER_CONFIG_SERVICE); + CarrierConfigManager ccm = phone.getContext().getSystemService(CarrierConfigManager.class); + // Callback directly calls rebindService and should be executed in handler thread + ccm.registerCarrierConfigChangeListener( + this::post, + (slotIndex, subId, carrierId, specificCarrierId) -> { + if (slotIndex == phone.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. + logd("Carrier config changed. Try to bind network service."); + rebindService(); + } + }); - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - try { - Context contextAsUser = phone.getContext().createPackageContextAsUser( - phone.getContext().getPackageName(), 0, UserHandle.ALL); - contextAsUser.registerReceiver(mBroadcastReceiver, intentFilter, - null /* broadcastPermission */, null); - } catch (PackageManager.NameNotFoundException e) { - loge("Package name not found: " + e.getMessage()); - } PhoneConfigurationManager.registerForMultiSimConfigChange( this, EVENT_BIND_NETWORK_SERVICE, null); @@ -333,9 +311,10 @@ public class NetworkRegistrationManager extends Handler { // Read package name from resource overlay packageName = mPhone.getContext().getResources().getString(resourceId); - PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { + PersistableBundle b = + CarrierConfigManager.getCarrierConfigSubset( + mPhone.getContext(), mPhone.getSubId(), carrierConfig); + if (!b.isEmpty() && !TextUtils.isEmpty(b.getString(carrierConfig))) { // If carrier config overrides it, use the one from carrier config packageName = b.getString(carrierConfig, packageName); } @@ -367,15 +346,17 @@ public class NetworkRegistrationManager extends Handler { // Read class name from resource overlay className = mPhone.getContext().getResources().getString(resourceId); - PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - if (b != null && !TextUtils.isEmpty(b.getString(carrierConfig))) { + PersistableBundle b = + CarrierConfigManager.getCarrierConfigSubset( + mPhone.getContext(), mPhone.getSubId(), carrierConfig); + if (!b.isEmpty() && !TextUtils.isEmpty(b.getString(carrierConfig))) { // If carrier config overrides it, use the one from carrier config className = b.getString(carrierConfig, className); } return className; } + private void logd(String msg) { Rlog.d(mTag, msg); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index e6a3ac7b60..e70257830b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -242,6 +242,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { replaceInstance(ProxyController.class, "sProxyController", null, mProxyController); mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); mBundle.putStringArray( CarrierConfigManager.KEY_ROAMING_OPERATOR_STRING_ARRAY, new String[]{"123456"}); -- GitLab From 843bc1a1d3138f257c7c1e54bf0f566eae08cf7a Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 9 Feb 2023 15:48:25 -0800 Subject: [PATCH 413/656] Reregister for IMS radio tech change for new sub Starting T, the IMS callback no longer ties to the life of the MmTelFeature associated with the phoneId, but instead, whenever the subscription changes, IMS cleanup the MmTelFeatureConnection that is managing this callback, so the callback that was registered here becomes unregistered. The fix is to re-register callback when user insert new sub. Fix: 262249679 Test: Manual removed and re-inserted pSIM and eSIM, reviewed log to confirm registered correctly. Placed voice call and internet browsing. Change-Id: I8d99ecce7f0622875462973efd78bc04a92e1311 --- .../com/android/internal/telephony/data/PhoneSwitcher.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index fe63ada5a8..2ac9777701 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -697,7 +697,7 @@ public class PhoneSwitcher extends Handler { public void handleMessage(Message msg) { switch (msg.what) { case EVENT_SUBSCRIPTION_CHANGED: { - onEvaluate(REQUESTS_UNCHANGED, "subChanged"); + onEvaluate(REQUESTS_UNCHANGED, "subscription changed"); break; } case EVENT_SERVICE_STATE_CHANGED: { @@ -1346,6 +1346,10 @@ public class PhoneSwitcher extends Handler { mAutoSelectedDataSubId = DEFAULT_SUBSCRIPTION_ID; } mPhoneSubscriptions[i] = sub; + // Listen to IMS radio tech change for new sub + if (SubscriptionManager.isValidSubscriptionId(sub)) { + registerForImsRadioTechChange(mContext, i); + } diffDetected = true; } } -- GitLab From ac89075a476013620ccb1595f4e8e53407d68911 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 9 Feb 2023 16:20:10 -0800 Subject: [PATCH 414/656] Fixed the flaky tests by deleting them The test relying on static values, which can be intefered by other tests. If other tests initialize the phone factory earlier, then this test would fail. Fix: 268188416 Test: atest FrameworksTelephonyTests Change-Id: I1473b2bff46c3ed882f15664435c6488164bd167 --- .../internal/telephony/PhoneFactoryTest.java | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/PhoneFactoryTest.java diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneFactoryTest.java deleted file mode 100644 index d1aea0334c..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneFactoryTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony; - -import static org.junit.Assert.fail; - -import android.test.suitebuilder.annotation.SmallTest; - -import org.junit.Test; - -public class PhoneFactoryTest { - @Test - @SmallTest - public void testBeforeMakePhone() { - try { - PhoneFactory.getDefaultPhone(); - fail("Expecting IllegalStateException"); - } catch (IllegalStateException e) { - } - - try { - PhoneFactory.getPhone(0); - fail("Expecting IllegalStateException"); - } catch (IllegalStateException e) { - } - - try { - PhoneFactory.getPhones(); - fail("Expecting IllegalStateException"); - } catch (IllegalStateException e) { - } - - try { - PhoneFactory.getNetworkFactory(0); - fail("Expecting IllegalStateException"); - } catch (IllegalStateException e) { - } - } - - //todo: add test for makeDefaultPhone(). will need some refactoring in PhoneFactory. -} -- GitLab From 5d2397d195570fee25122065dfa42db254281ab9 Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 5 Dec 2022 16:24:20 -0600 Subject: [PATCH 415/656] Update CarrierServiceStateTracker with new CarrierConfigManager APIs Improve the performance of CarrierServiceStateTracker by: - Replacing the carrier config change broadcast receiver with listener which has much lower lagency. - Retrieving subset (instead of all) of carrier config to consume less memory Bug: 263267340 Test: atest CarrierServiceStateTrackerTest Change-Id: If81ff78fcc07a3ac53181ab70c2e9e40274dd112 --- .../telephony/CarrierServiceStateTracker.java | 65 ++++++++++--------- .../CarrierServiceStateTrackerTest.java | 21 ++++-- .../telephony/DisplayInfoControllerTest.java | 2 + .../telephony/ServiceStateTrackerTest.java | 3 + 4 files changed, 57 insertions(+), 34 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java index 9fa26cca7d..db1e8f5a70 100644 --- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java @@ -19,10 +19,8 @@ package com.android.internal.telephony; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.res.Resources; import android.os.Handler; import android.os.HandlerExecutor; @@ -102,8 +100,34 @@ public class CarrierServiceStateTracker extends Handler { this.mSST = sst; mTelephonyManager = mPhone.getContext().getSystemService( TelephonyManager.class).createForSubscriptionId(mPhone.getSubId()); - phone.getContext().registerReceiver(mBroadcastReceiver, new IntentFilter( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); + ccm.registerCarrierConfigChangeListener( + mPhone.getContext().getMainExecutor(), + (slotIndex, subId, carrierId, specificCarrierId) -> { + if (slotIndex != mPhone.getPhoneId()) return; + + Rlog.d(LOG_TAG, "onCarrierConfigChanged: slotIndex=" + slotIndex + + ", subId=" + subId + ", carrierId=" + carrierId); + + // Only get carrier configs used for EmergencyNetworkNotification + // and PrefNetworkNotification + PersistableBundle b = + CarrierConfigManager.getCarrierConfigSubset( + mPhone.getContext(), + mPhone.getSubId(), + CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT, + CarrierConfigManager + .KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT); + if (b.isEmpty()) return; + + for (Map.Entry entry : + mNotificationTypeMap.entrySet()) { + NotificationType notificationType = entry.getValue(); + notificationType.setDelay(b); + } + handleConfigChanges(); + }); + // Listen for subscriber changes SubscriptionManager.from(mPhone.getContext()).addOnSubscriptionsChangedListener( new OnSubscriptionsChangedListener(this.getLooper()) { @@ -246,7 +270,7 @@ public class CarrierServiceStateTracker extends Handler { TelephonyManager tm = ((TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE)).createForSubscriptionId(mPhone.getSubId()); - boolean isCarrierConfigEnabled = isCarrierConfigEnableNr(context); + boolean isCarrierConfigEnabled = isCarrierConfigEnableNr(); boolean isRadioAccessFamilySupported = checkSupportedBitmask( tm.getSupportedRadioAccessFamily(), TelephonyManager.NETWORK_TYPE_BITMASK_NR); boolean isNrNetworkTypeAllowed = checkSupportedBitmask( @@ -261,15 +285,13 @@ public class CarrierServiceStateTracker extends Handler { return (isCarrierConfigEnabled && isRadioAccessFamilySupported && isNrNetworkTypeAllowed); } - private boolean isCarrierConfigEnableNr(Context context) { - CarrierConfigManager carrierConfigManager = (CarrierConfigManager) - context.getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (carrierConfigManager == null) { - Rlog.e(LOG_TAG, "isCarrierConfigEnableNr: CarrierConfigManager is null"); - return false; - } - PersistableBundle config = carrierConfigManager.getConfigForSubId(mPhone.getSubId()); - if (config == null) { + private boolean isCarrierConfigEnableNr() { + PersistableBundle config = + CarrierConfigManager.getCarrierConfigSubset( + mPhone.getContext(), + mPhone.getSubId(), + CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); + if (config.isEmpty()) { Rlog.e(LOG_TAG, "isCarrierConfigEnableNr: Cannot get config " + mPhone.getSubId()); return false; } @@ -348,21 +370,6 @@ public class CarrierServiceStateTracker extends Handler { return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); } - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - CarrierConfigManager carrierConfigManager = (CarrierConfigManager) - context.getSystemService(Context.CARRIER_CONFIG_SERVICE); - PersistableBundle b = carrierConfigManager.getConfigForSubId(mPhone.getSubId()); - - for (Map.Entry entry : mNotificationTypeMap.entrySet()) { - NotificationType notificationType = entry.getValue(); - notificationType.setDelay(b); - } - handleConfigChanges(); - } - }; - /** * Post a notification to the NotificationManager for changing network type. */ diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java index 07cf0b9521..fadbff185c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; @@ -28,7 +29,6 @@ import static org.mockito.Mockito.when; import android.app.Notification; import android.app.NotificationManager; import android.content.Context; -import android.content.Intent; import android.os.Message; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -43,9 +43,11 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.MockitoAnnotations; import java.util.Map; +import java.util.concurrent.Executor; /** * Unit tests for {@link com.android.internal.telephony.CarrierServiceStateTracker}. @@ -57,6 +59,7 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest { private CarrierServiceStateTracker mSpyCarrierSST; private CarrierServiceStateTracker mCarrierSST; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; private static final int SUB_ID = 1; @@ -68,10 +71,18 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest { MockitoAnnotations.initMocks(this); logd(LOG_TAG + "Setup!"); super.setUp(getClass().getSimpleName()); + doReturn((Executor) Runnable::run).when(mContext).getMainExecutor(); mBundle = mContextFixture.getCarrierConfigBundle(); when(mPhone.getSubId()).thenReturn(SUB_ID); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); + // Capture listener to emulate the carrier config change notification used later + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); mCarrierSST = new CarrierServiceStateTracker(mPhone, mSST); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); mSpyCarrierSST = spy(mCarrierSST); mNotificationManager = (NotificationManager) mContext.getSystemService( @@ -140,8 +151,8 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest { @SmallTest public void testSendPrefNetworkNotification() { logd(LOG_TAG + ":testSendPrefNetworkNotification()"); - Intent intent = new Intent().setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - mContext.sendBroadcast(intent); + mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */, SUB_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); Map notificationTypeMap = @@ -190,8 +201,8 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest { @SmallTest public void testSendEmergencyNetworkNotification() { logd(LOG_TAG + ":testSendEmergencyNetworkNotification()"); - Intent intent = new Intent().setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - mContext.sendBroadcast(intent); + mCarrierConfigChangeListener.onCarrierConfigChanged(0 /* slotIndex */, SUB_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); Map notificationTypeMap = diff --git a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java index fa00362c1e..7bbdb84b05 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java @@ -49,6 +49,7 @@ import org.junit.runner.RunWith; import org.mockito.Mockito; import java.util.Collections; +import java.util.concurrent.Executor; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -90,6 +91,7 @@ public class DisplayInfoControllerTest extends TelephonyTest { logd("DisplayInfoControllerTest setup!"); super.setUp(getClass().getSimpleName()); + doReturn((Executor) Runnable::run).when(mContext).getMainExecutor(); mSstHandler = new ServiceStateTrackerTestHandler(getClass().getSimpleName()); mSstHandler.start(); waitUntilReady(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index e6a3ac7b60..3e55d41798 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -112,6 +112,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.concurrent.Executor; public class ServiceStateTrackerTest extends TelephonyTest { // Mocked classes @@ -229,6 +230,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { mSubInfo = Mockito.mock(SubscriptionInfo.class); mServiceStateStats = Mockito.mock(ServiceStateStats.class); + doReturn((Executor) Runnable::run).when(mContext).getMainExecutor(); mContextFixture.putResource(R.string.config_wwan_network_service_package, "com.android.phone"); mContextFixture.putResource(R.string.config_wlan_network_service_package, @@ -242,6 +244,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { replaceInstance(ProxyController.class, "sProxyController", null, mProxyController); mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); mBundle.putStringArray( CarrierConfigManager.KEY_ROAMING_OPERATOR_STRING_ARRAY, new String[]{"123456"}); -- GitLab From 8bfc8040b448f6825b30cfc36ad0e8b2a0d4ab6a Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 5 Dec 2022 13:25:26 -0600 Subject: [PATCH 416/656] Update CallWaitingController with new CarrierConfigManager APIs - Replace carrier config change broadcast receiver with listener which has much lower lagency - Retrieve subset of carrier config and avoid passing the whole config bundle as parameter to reduce memory consumption Bug: 263267340 Test: atest CallWaitingControllerTest Change-Id: I4964afb2433d43f032e74fce3ec85421a488cccb --- .../telephony/CallWaitingController.java | 77 ++++++++----------- .../telephony/CallWaitingControllerTest.java | 33 +++++--- 2 files changed, 54 insertions(+), 56 deletions(-) diff --git a/src/java/com/android/internal/telephony/CallWaitingController.java b/src/java/com/android/internal/telephony/CallWaitingController.java index 4940eb62b2..49940fc65d 100644 --- a/src/java/com/android/internal/telephony/CallWaitingController.java +++ b/src/java/com/android/internal/telephony/CallWaitingController.java @@ -30,13 +30,9 @@ import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NON import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; import android.annotation.Nullable; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.AsyncResult; -import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.PersistableBundle; @@ -68,7 +64,6 @@ public class CallWaitingController extends Handler { private static final int EVENT_SET_CALL_WAITING_DONE = 1; private static final int EVENT_GET_CALL_WAITING_DONE = 2; private static final int EVENT_REGISTERED_TO_NETWORK = 3; - private static final int EVENT_CARRIER_CONFIG_CHANGED = 4; // Class to pack mOnComplete object passed by the caller private static class Cw { @@ -92,32 +87,9 @@ public class CallWaitingController extends Handler { @VisibleForTesting public static final String KEY_CS_SYNC = "cs_sync"; - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent == null) { - return; - } - if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { - Bundle bundle = intent.getExtras(); - if (bundle == null) { - return; - } - int slotId = bundle.getInt(CarrierConfigManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_PHONE_INDEX); - - if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - loge("onReceive ACTION_CARRIER_CONFIG_CHANGED invalid slotId " - + slotId); - return; - } - - if (slotId == mPhone.getPhoneId()) { - sendEmptyMessage(EVENT_CARRIER_CONFIG_CHANGED); - } - } - } - }; + private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = + (slotIndex, subId, carrierId, specificCarrierId) -> onCarrierConfigurationChanged( + slotIndex); private boolean mSupportedByImsService = false; private boolean mValidSubscription = false; @@ -144,8 +116,13 @@ public class CallWaitingController extends Handler { } private void initialize() { - mContext.registerReceiver(mReceiver, new IntentFilter( - CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + CarrierConfigManager ccm = mContext.getSystemService(CarrierConfigManager.class); + if (ccm != null) { + // Callback directly handle carrier config change should be executed in handler thread + ccm.registerCarrierConfigChangeListener(this::post, mCarrierConfigChangeListener); + } else { + loge("CarrierConfigLoader is not available."); + } int phoneId = mPhone.getPhoneId(); int subId = mPhone.getSubId(); @@ -284,9 +261,6 @@ public class CallWaitingController extends Handler { case EVENT_REGISTERED_TO_NETWORK: onRegisteredToNetwork(); break; - case EVENT_CARRIER_CONFIG_CHANGED: - onCarrierConfigChanged(); - break; default: break; } @@ -453,7 +427,9 @@ public class CallWaitingController extends Handler { obtainMessage(EVENT_GET_CALL_WAITING_DONE)); } - private synchronized void onCarrierConfigChanged() { + private synchronized void onCarrierConfigurationChanged(int slotIndex) { + if (slotIndex != mPhone.getPhoneId()) return; + int subId = mPhone.getSubId(); if (!SubscriptionManager.isValidSubscriptionId(subId)) { logi("onCarrierConfigChanged invalid subId=" + subId); @@ -463,10 +439,9 @@ public class CallWaitingController extends Handler { return; } - CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class); - PersistableBundle b = configManager.getConfigForSubId(subId); - - updateCarrierConfig(subId, b, false); + if (!updateCarrierConfig(subId, false /* ignoreSavedState */)) { + return; + } logi("onCarrierConfigChanged cs_enabled=" + mCsEnabled); @@ -479,12 +454,20 @@ public class CallWaitingController extends Handler { /** * @param ignoreSavedState only used for test + * @return true when succeeded. */ @VisibleForTesting - public void updateCarrierConfig(int subId, PersistableBundle b, boolean ignoreSavedState) { + public boolean updateCarrierConfig(int subId, boolean ignoreSavedState) { mValidSubscription = true; - if (b == null) return; + PersistableBundle b = + CarrierConfigManager.getCarrierConfigSubset( + mContext, + subId, + KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY, + KEY_TERMINAL_BASED_CALL_WAITING_SYNC_TYPE_INT, + KEY_TERMINAL_BASED_CALL_WAITING_DEFAULT_ENABLED_BOOL); + if (b.isEmpty()) return false; boolean supportsTerminalBased = false; int[] services = b.getIntArray(KEY_UT_TERMINAL_BASED_SERVICES_INT_ARRAY); @@ -527,6 +510,7 @@ public class CallWaitingController extends Handler { } updateState(desiredState, syncPreference, ignoreSavedState); + return true; } private void updateState(int state) { @@ -645,9 +629,12 @@ public class CallWaitingController extends Handler { if (supported) { initialize(); - onCarrierConfigChanged(); + onCarrierConfigurationChanged(mPhone.getPhoneId()); } else { - mContext.unregisterReceiver(mReceiver); + CarrierConfigManager ccm = mContext.getSystemService(CarrierConfigManager.class); + if (ccm != null && mCarrierConfigChangeListener != null) { + ccm.unregisterCarrierConfigChangeListener(mCarrierConfigChangeListener); + } updateState(TERMINAL_BASED_NOT_SUPPORTED); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java index 18d054d2dc..eb18adb6a7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CallWaitingControllerTest.java @@ -40,8 +40,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; import android.content.Context; import android.content.SharedPreferences; @@ -94,7 +96,8 @@ public class CallWaitingControllerTest extends TelephonyTest { public void testSetTerminalBasedCallWaitingSupported() { mCWC.setTerminalBasedCallWaitingSupported(true); PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); - mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(bundle); + mCWC.updateCarrierConfig(FAKE_SUB_ID, true); assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); @@ -111,7 +114,7 @@ public class CallWaitingControllerTest extends TelephonyTest { setPreference(mPhone.getPhoneId(), FAKE_SUB_ID, TERMINAL_BASED_ACTIVATED, CALL_WAITING_SYNC_NONE); PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); - doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); + doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt(), any()); mCWC.setTerminalBasedCallWaitingSupported(true); assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); @@ -127,7 +130,7 @@ public class CallWaitingControllerTest extends TelephonyTest { mCWC.setTerminalBasedCallWaitingSupported(false); bundle = getConfigBundle(false, CALL_WAITING_SYNC_NONE, false); - doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt()); + doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(anyInt(), any()); mCWC.setTerminalBasedCallWaitingSupported(true); assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_SUPPORTED); @@ -139,13 +142,15 @@ public class CallWaitingControllerTest extends TelephonyTest { public void testCarrierConfigChanged() { mCWC.setTerminalBasedCallWaitingSupported(true); PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); - mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(bundle); + mCWC.updateCarrierConfig(FAKE_SUB_ID, true); assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); bundle = getConfigBundle(false, CALL_WAITING_SYNC_NONE, true); - mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, false); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(bundle); + mCWC.updateCarrierConfig(FAKE_SUB_ID, false); assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_NOT_SUPPORTED); assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_NOT_SUPPORTED); @@ -179,7 +184,8 @@ public class CallWaitingControllerTest extends TelephonyTest { mCWC.setTerminalBasedCallWaitingSupported(true); PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); - mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(bundle); + mCWC.updateCarrierConfig(FAKE_SUB_ID, true); mHandler = new GetTestHandler(); @@ -216,7 +222,8 @@ public class CallWaitingControllerTest extends TelephonyTest { mCWC.setTerminalBasedCallWaitingSupported(true); PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_NONE, true); - mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(bundle); + mCWC.updateCarrierConfig(FAKE_SUB_ID, true); assertTrue(mCWC.setCallWaiting(true, SERVICE_CLASS_VOICE, null)); assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); @@ -247,7 +254,8 @@ public class CallWaitingControllerTest extends TelephonyTest { TERMINAL_BASED_ACTIVATED, CALL_WAITING_SYNC_USER_CHANGE); mCWC.setTerminalBasedCallWaitingSupported(true); PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_USER_CHANGE, true); - mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(bundle); + mCWC.updateCarrierConfig(FAKE_SUB_ID, true); assertTrue(mCWC.getTerminalBasedCallWaitingState(false) == TERMINAL_BASED_ACTIVATED); assertTrue(mCWC.getTerminalBasedCallWaitingState(true) == TERMINAL_BASED_ACTIVATED); @@ -303,7 +311,8 @@ public class CallWaitingControllerTest extends TelephonyTest { TERMINAL_BASED_NOT_ACTIVATED, CALL_WAITING_SYNC_FIRST_POWER_UP); mCWC.setTerminalBasedCallWaitingSupported(true); PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_FIRST_POWER_UP, true); - mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(bundle); + mCWC.updateCarrierConfig(FAKE_SUB_ID, true); assertFalse(mCWC.getSyncState()); mCWC.notifyRegisteredToNetwork(); @@ -320,7 +329,8 @@ public class CallWaitingControllerTest extends TelephonyTest { TERMINAL_BASED_NOT_ACTIVATED, CALL_WAITING_SYNC_FIRST_CHANGE); mCWC.setTerminalBasedCallWaitingSupported(true); PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_FIRST_CHANGE, true); - mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(bundle); + mCWC.updateCarrierConfig(FAKE_SUB_ID, true); mCWC.setImsRegistrationState(false); assertFalse(mCWC.getSyncState()); @@ -359,7 +369,8 @@ public class CallWaitingControllerTest extends TelephonyTest { TERMINAL_BASED_ACTIVATED, CALL_WAITING_SYNC_IMS_ONLY); mCWC.setTerminalBasedCallWaitingSupported(true); PersistableBundle bundle = getConfigBundle(true, CALL_WAITING_SYNC_IMS_ONLY, true); - mCWC.updateCarrierConfig(FAKE_SUB_ID, bundle, true); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(bundle); + mCWC.updateCarrierConfig(FAKE_SUB_ID, true); mSimulatedCommands.setCallWaiting(false, SERVICE_CLASS_VOICE, null); -- GitLab From 5858165ffe37041d8b73037a596f2f752e8e4472 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 9 Feb 2023 22:08:00 -0800 Subject: [PATCH 417/656] Add log to anomaly report Test: able to place voice call Change-Id: If3cdfa8a4b1ee2fff9752134ac6000d4ed0708bf --- .../internal/telephony/NetworkIndication.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index c9f235a491..b64d8bfa03 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -26,6 +26,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_REGISTRATION_FAILED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESTRICTED_STATE_CHANGED; @@ -316,13 +317,22 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { reportAnomaly(UUID.fromString("f16e5703-6105-4341-9eb3-e68189156eb5"), "Invalid registrationFailed indication"); - mRil.riljLoge("Invalid registrationFailed indication"); + mRil.riljLoge("Invalid registrationFailed indication (ci is null)=" + (ci == null) + + " (chosenPlmn is empty)=" + TextUtils.isEmpty(chosenPlmn) + + " (is CS/PS)=" + ((domain & NetworkRegistrationInfo.DOMAIN_CS_PS) == 0) + + " (only CS/PS)=" + ((domain & ~NetworkRegistrationInfo.DOMAIN_CS_PS) != 0) + + " (causeCode)=" + causeCode + + " (additionalCauseCode)=" + additionalCauseCode); return; } + RegistrationFailedEvent registrationFailedEvent = new RegistrationFailedEvent( + ci, chosenPlmn, domain, causeCode, additionalCauseCode); + if (mRil.isLogOrTrace()) { + mRil.unsljLogMore(RIL_UNSOL_REGISTRATION_FAILED, registrationFailedEvent.toString()); + } mRil.mRegistrationFailedRegistrant.notifyRegistrant( - new AsyncResult(null, new RegistrationFailedEvent( - ci, chosenPlmn, domain, causeCode, additionalCauseCode), null)); + new AsyncResult(null, registrationFailedEvent, null)); } /** -- GitLab From 208de22e31754cedc579645941f181122d8c35d5 Mon Sep 17 00:00:00 2001 From: rambowang Date: Wed, 8 Feb 2023 21:03:53 -0600 Subject: [PATCH 418/656] DataNetwork: replace deprecated carrier privileges listener with public API This CL updates DataNetwork to use public methods TelephonyManager# [un]registerCarrierPrivilegesCallback to replace the deprecated methods CarrierPrivilegesTracker#[un]registerCarrierPrivilegesListener which will be removed soon after cleaning up all callers. Bug: 211658797 Test: atest FrameworksTelephonyTests Change-Id: I76f9e39b5db97538a37094f2ed1ebbbebc3d512c --- .../telephony/CarrierPrivilegesTracker.java | 10 +++---- .../internal/telephony/data/DataNetwork.java | 26 ++++++++++++++++--- .../telephony/data/DataNetworkTest.java | 5 ++-- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index 0fda1f2007..8ee2b44023 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -847,20 +847,20 @@ public class CarrierPrivilegesTracker extends Handler { *

After being registered, the Registrant will be notified with the current Carrier * Privileged UIDs for this Phone. * - * @deprecated Use {@link TelephonyManager#addCarrierPrivilegesListener} instead, which also - * provides package names + * @deprecated Use {@link TelephonyManager#registerCarrierPrivilegesCallback} instead, which + * also provides package names *

TODO(b/211658797) migrate callers, then delete all Registrant logic from CPT */ @Deprecated - public void registerCarrierPrivilegesListener(@NonNull Handler h, int what, - @Nullable Object obj) { + public void registerCarrierPrivilegesListener( + @NonNull Handler h, int what, @Nullable Object obj) { sendMessage(obtainMessage(ACTION_REGISTER_LISTENER, new Registrant(h, what, obj))); } /** * Unregisters the given listener with this tracker. * - * @deprecated Use {@link TelephonyManager#removeCarrierPrivilegesListener} instead + * @deprecated Use {@link TelephonyManager#unregisterCarrierPrivilegesCallback} instead *

TODO(b/211658797) migrate callers, then delete all Registrant logic from CPT */ @Deprecated diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 4293ea4f99..1ba3d67ac6 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -680,6 +680,9 @@ public class DataNetwork extends StateMachine { */ private @NonNull int[] mAdministratorUids = new int[0]; + /** Carrier privileges callback to monitor administrator UID change. */ + private @Nullable TelephonyManager.CarrierPrivilegesCallback mCarrierPrivilegesCallback; + /** * Carrier service package uid. This UID will not change through the life cycle of data network. */ @@ -1048,8 +1051,22 @@ public class DataNetwork extends StateMachine { mDataServiceManagers.get(transport) .registerForDataCallListChanged(getHandler(), EVENT_DATA_STATE_CHANGED); } - mPhone.getCarrierPrivilegesTracker().registerCarrierPrivilegesListener(getHandler(), - EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED, null); + + mCarrierPrivilegesCallback = + (Set privilegedPackageNames, Set privilegedUids) -> { + log("onCarrierPrivilegesChanged, Uids=" + privilegedUids.toString()); + Message message = obtainMessage(EVENT_CARRIER_PRIVILEGED_UIDS_CHANGED); + AsyncResult.forMessage( + message, + privilegedUids.stream().mapToInt(i -> i).toArray(), + null /* ex */); + message.sendToTarget(); + }; + TelephonyManager tm = mPhone.getContext().getSystemService(TelephonyManager.class); + if (tm != null) { + tm.registerCarrierPrivilegesCallback( + mPhone.getPhoneId(), getHandler()::post, mCarrierPrivilegesCallback); + } mPhone.getServiceStateTracker().registerForCssIndicatorChanged( getHandler(), EVENT_CSS_INDICATOR_CHANGED, null); @@ -1083,7 +1100,10 @@ public class DataNetwork extends StateMachine { mPhone.getCallTracker().unregisterForVoiceCallEnded(getHandler()); mPhone.getServiceStateTracker().unregisterForCssIndicatorChanged(getHandler()); - mPhone.getCarrierPrivilegesTracker().unregisterCarrierPrivilegesListener(getHandler()); + TelephonyManager tm = mPhone.getContext().getSystemService(TelephonyManager.class); + if (tm != null && mCarrierPrivilegesCallback != null) { + tm.unregisterCarrierPrivilegesCallback(mCarrierPrivilegesCallback); + } for (int transport : mAccessNetworksManager.getAvailableTransports()) { mDataServiceManagers.get(transport) .unregisterForDataCallListChanged(getHandler()); 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 d074376b09..bb437eb828 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -1130,8 +1130,7 @@ public class DataNetworkTest extends TelephonyTest { any(Handler.class), anyInt()); verify(mMockedWlanDataServiceManager).registerForDataCallListChanged( any(Handler.class), anyInt()); - verify(mCarrierPrivilegesTracker).registerCarrierPrivilegesListener(any(Handler.class), - anyInt(), eq(null)); + verify(mTelephonyManager).registerCarrierPrivilegesCallback(anyInt(), any(), any()); verify(mLinkBandwidthEstimator).registerCallback( any(LinkBandwidthEstimatorCallback.class)); verify(mSimulatedCommandsVerifier).registerForNattKeepaliveStatus(any(Handler.class), @@ -1154,7 +1153,7 @@ public class DataNetworkTest extends TelephonyTest { verify(mDisplayInfoController).unregisterForTelephonyDisplayInfoChanged(any(Handler.class)); verify(mMockedWwanDataServiceManager).unregisterForDataCallListChanged(any(Handler.class)); verify(mMockedWlanDataServiceManager).unregisterForDataCallListChanged(any(Handler.class)); - verify(mCarrierPrivilegesTracker).unregisterCarrierPrivilegesListener(any(Handler.class)); + verify(mTelephonyManager).unregisterCarrierPrivilegesCallback(any()); verify(mLinkBandwidthEstimator).unregisterCallback( any(LinkBandwidthEstimatorCallback.class)); verify(mSimulatedCommandsVerifier).unregisterForNattKeepaliveStatus(any(Handler.class)); -- GitLab From 5e346bcb2ae2a14e9cdf9fa4fcac841b3b489efa Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 10 Feb 2023 11:58:30 -0800 Subject: [PATCH 419/656] Fixed crash in getPhoneNumber getPhoneNumber used to return empty string when passed in subscription id is invalid. Adapted the behavior to avoid clients crash. Fix: 268535693 Test: *#*#4646#*#* without SIM inserted Test: atest SubscriptionManagerServiceTest Change-Id: Ifae48a1d358892797dd51b84baf923d1b4321dba --- .../subscription/SubscriptionManagerService.java | 8 +++----- .../SubscriptionManagerServiceTest.java | 13 +++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 29f781e88d..9d65e6b0cd 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -3234,15 +3234,12 @@ public class SubscriptionManagerService extends ISub.Stub { * * @return The phone number, or an empty string if not available. * - * @throws IllegalArgumentException if {@code source} or {@code subId} is invalid. + * @throws IllegalArgumentException if {@code source} is invalid. * @throws SecurityException if the caller doesn't have permissions required. * * @see SubscriptionManager#PHONE_NUMBER_SOURCE_UICC * @see SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER * @see SubscriptionManager#PHONE_NUMBER_SOURCE_IMS - * - * @throws IllegalArgumentException if {@code subId} is invalid. - * @throws SecurityException if callers do not hold the required permission. */ @Override @NonNull @@ -3264,7 +3261,8 @@ public class SubscriptionManagerService extends ISub.Stub { .getSubscriptionInfoInternal(subId); if (subInfo == null) { - throw new IllegalArgumentException("Invalid sub id " + subId); + loge("Invalid sub id " + subId + ", callingPackage=" + callingPackage); + return ""; } try { 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 e620b51709..b0eafbf690 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -1809,4 +1809,17 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isGroupDisabled()) .isFalse(); } + + @Test + public void testGetPhoneNumber() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + testSetPhoneNumber(); + assertThat(mSubscriptionManagerServiceUT.getPhoneNumber(1, + SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, CALLING_PACKAGE, CALLING_FEATURE)) + .isEqualTo(FAKE_PHONE_NUMBER2); + assertThat(mSubscriptionManagerServiceUT.getPhoneNumber( + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, CALLING_PACKAGE, CALLING_FEATURE)) + .isEmpty(); + } } -- GitLab From b4d1e427206a0a7086547c43decc61449320967f Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Fri, 10 Feb 2023 17:40:00 -0800 Subject: [PATCH 420/656] Use udpated satellite error codes Bug: 266013384 Test: atest android.telephony.cts.SatelliteManagerTest Change-Id: Ib0eb172b669cdf9db973681b29d1dfceb944f89a --- .../com/android/internal/telephony/RIL.java | 5 ++ .../android/internal/telephony/RILUtils.java | 71 +++++-------------- 2 files changed, 22 insertions(+), 54 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 1211f1706e..52dfda556b 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -6166,6 +6166,11 @@ public class RIL extends BaseCommands implements CommandsInterface { CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); result.sendToTarget(); } + /** + * TODO: when adding implementation of this method, we need to return successful result + * with satellite support set to false if radioSatelliteProxy.isEmpty() is true or + * mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0) is false. + */ } /** diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index bf3fa8c706..5cb97b1a94 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -6022,81 +6022,44 @@ public class RILUtils { * @param error The satellite error. * @return The converted SatelliteServiceResult. */ - @SatelliteManager.SatelliteServiceResult public static int convertToSatelliteError( + @SatelliteManager.SatelliteError + public static int convertToSatelliteError( CommandException.Error error) { switch (error) { case INTERNAL_ERR: - return SatelliteManager.SATELLITE_SERVICE_MODEM_ERROR; + //fallthrough to SYSTEM_ERR case MODEM_ERR: - return SatelliteManager.SATELLITE_SERVICE_UNEXPECTED_MODEM_RESPONSE; + //fallthrough to SYSTEM_ERR case SYSTEM_ERR: - return SatelliteManager.SATELLITE_SERVICE_RIL_ERROR; + return SatelliteManager.SATELLITE_MODEM_ERROR; case INVALID_ARGUMENTS: - return SatelliteManager.SATELLITE_SERVICE_INVALID_ARGUMENTS; + return SatelliteManager.SATELLITE_INVALID_ARGUMENTS; case INVALID_MODEM_STATE: - return SatelliteManager.SATELLITE_SERVICE_INVALID_MODEM_STATE; - case INVALID_SIM_STATE: - return SatelliteManager.SATELLITE_SERVICE_INVALID_SIM_STATE; - case INVALID_STATE: - return SatelliteManager.SATELLITE_SERVICE_INVALID_RIL_STATE; + return SatelliteManager.SATELLITE_INVALID_MODEM_STATE; case RADIO_NOT_AVAILABLE: - return SatelliteManager.SATELLITE_SERVICE_RADIO_NOT_AVAILABLE; + return SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE; case REQUEST_NOT_SUPPORTED: - return SatelliteManager.SATELLITE_SERVICE_REQUEST_NOT_SUPPORTED; - case REQUEST_RATE_LIMITED: - return SatelliteManager.SATELLITE_SERVICE_REQUEST_RATE_LIMITED; + return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED; case NO_MEMORY: //fallthrough to NO_RESOURCES case NO_RESOURCES: - return SatelliteManager.SATELLITE_SERVICE_NO_RESOURCES; + return SatelliteManager.SATELLITE_NO_RESOURCES; case NETWORK_ERR: - return SatelliteManager.SATELLITE_SERVICE_NETWORK_ERROR; - case NETWORK_NOT_READY: - return SatelliteManager.SATELLITE_SERVICE_NETWORK_NOT_READY; - case NETWORK_REJECT: - return SatelliteManager.SATELLITE_SERVICE_SERVER_REJECT; + return SatelliteManager.SATELLITE_NETWORK_ERROR; case NETWORK_TIMEOUT: - return SatelliteManager.SATELLITE_SERVICE_NETWORK_TIMEOUT; + return SatelliteManager.SATELLITE_NETWORK_TIMEOUT; case NO_NETWORK_FOUND: //fallthrough to NO_SATELLITE_SIGNAL case NO_SATELLITE_SIGNAL: - return SatelliteManager.SATELLITE_SERVICE_NO_SATELLITE_SIGNAL; + return SatelliteManager.SATELLITE_NOT_REACHABLE; case ABORTED: - return SatelliteManager.SATELLITE_SERVICE_REQUEST_ABORTED; + return SatelliteManager.SATELLITE_REQUEST_ABORTED; case ACCESS_BARRED: - return SatelliteManager.SATELLITE_SERVICE_ACCESS_BARRED; - case FEATURE_NOT_SUPPORTED: - return SatelliteManager.SATELLITE_SERVICE_FEATURE_NOT_SUPPORTED; - case MODEM_INCOMPATIBLE: - return SatelliteManager.SATELLITE_SERVICE_MODEM_INCOMPATIBLE; - case NO_SUBSCRIPTION: - return SatelliteManager.SATELLITE_SERVICE_NO_SUBSCRIPTION; - case OPERATION_NOT_ALLOWED: - return SatelliteManager.SATELLITE_SERVICE_OPERATION_NOT_ALLOWED; - case RADIO_TECHNOLOGY_NOT_SUPPORTED: - return SatelliteManager.SATELLITE_SERVICE_RADIO_TECHNOLOGY_NOT_SUPPORTED; - case SIM_ABSENT: - return SatelliteManager.SATELLITE_SERVICE_SIM_ABSENT; - case SIM_BUSY: - return SatelliteManager.SATELLITE_SERVICE_SIM_BUSY; - case SIM_ERR: - return SatelliteManager.SATELLITE_SERVICE_SIM_ERR; - case SIM_FULL: - return SatelliteManager.SATELLITE_SERVICE_SIM_FULL; + return SatelliteManager.SATELLITE_ACCESS_BARRED; case SUBSCRIBER_NOT_AUTHORIZED: - return SatelliteManager.SATELLITE_SERVICE_SUBSCRIBER_NOT_AUTHORIZED; - case ENCODING_NOT_SUPPORTED: - return SatelliteManager.SATELLITE_SERVICE_ENCODING_NOT_SUPPORTED; - case INVALID_CONTACT: - return SatelliteManager.SATELLITE_SERVICE_INVALID_CONTACT; - case NOT_SUFFICIENT_ACCOUNT_BALANCE: - return SatelliteManager.SATELLITE_SERVICE_NOT_SUFFICIENT_ACCOUNT_BALANCE; - case SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL: - return SatelliteManager.SATELLITE_SERVICE_SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL; - case UNIDENTIFIED_SUBSCRIBER: - return SatelliteManager.SATELLITE_SERVICE_UNIDENTIFIED_SUBSCRIBER; + return SatelliteManager.SATELLITE_NOT_AUTHORIZED; default: - return SatelliteManager.SATELLITE_SERVICE_ERROR; + return SatelliteManager.SATELLITE_ERROR; } } -- GitLab From b905c7c94a859a50bc1fa80043f2a917ed15958d Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Sat, 11 Feb 2023 23:30:27 -0800 Subject: [PATCH 421/656] Update Phone for satellite API change Test: atest SatelliteManagerTest Bug: 268791334 Change-Id: I51143fb627a2c90778a761a5be3f4de3260ec32b --- src/java/com/android/internal/telephony/Phone.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 4b03dad389..bf18164c99 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5359,14 +5359,15 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * subscription if the provider allows dynamic registration. * * @param result Callback message to receive the result. + * @param token The security token of the device/subscription to be provisioned. * @param imei IMEI of the SIM associated with the satellite modem. * @param msisdn MSISDN of the SIM associated with the satellite modem. * @param imsi IMSI of the SIM associated with the satellite modem. - * @param features List of features to be provisioned. */ - public void provisionSatelliteService(Message result, String imei, String msisdn, String imsi, - int[] features) { - mCi.provisionSatelliteService(result, imei, msisdn, imsi, features); + public void provisionSatelliteService(Message result, String token, String imei, String msisdn, + String imsi) { + // TODO: update parameters in HAL + // mCi.provisionSatelliteService(result, token, imei, msisdn, imsi); } /** -- GitLab From 4a745bd66265ee4098b2d32d0458745218b8fd9b Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Wed, 8 Feb 2023 23:05:54 +0000 Subject: [PATCH 422/656] Added Satellite Messaging APIs. The following apis are added in this CL: - registerForSatelliteStateChange() - unregisterForSatelliteStateChange() - registerForSatelliteDatagram() - unregisterForSatelliteDatagram() - getPendingSatelliteDatagrams() Bug: 260896985 Test: atest SatelliteManagerTest Change-Id: Iba46e8f453faa7d6f75802c71f8309e3c14e22a2 --- .../com/android/internal/telephony/Phone.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index bf18164c99..d11af9165c 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5409,6 +5409,77 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { //TODO (b/266126070): add implementation. } + /** + * Registers for satellite state change from satellite modem. + * + * @param h - Handler for notification message. + * @param what - User-defined message code. + * @param obj - User object. + */ + public void registerForSatelliteModemStateChange(@NonNull Handler h, int what, + @Nullable Object obj) { + mCi.registerForSatelliteModeChanged(h, what, obj); + } + + /** + * Unregisters for satellite state changes from satellite modem. + * + * @param h - Handler to be removed from registrant list. + */ + public void unregisterForSatelliteModemStateChange(@NonNull Handler h) { + mCi.unregisterForSatelliteModeChanged(h); + } + + /** + * Registers for pending message count info from satellite modem. + * + * @param h - Handler for notification message. + * @param what - User-defined message code. + * @param obj - User object. + */ + public void registerForPendingMessageCount(@NonNull Handler h, int what, @Nullable Object obj) { + mCi.registerForPendingSatelliteMessageCount(h, what, obj); + } + + /** + * Unregisters for pending message count info from satellite modem. + * + * @param h - Handler to be removed from registrant list. + */ + public void unregisterForPendingMessageCount(@NonNull Handler h) { + mCi.unregisterForPendingSatelliteMessageCount(h); + } + + /** + * Register to receive incoming datagrams over satellite. + * + * @param h - Handler for notification message. + * @param what - User-defined message code. + * @param obj - User object. + */ + public void registerForNewSatelliteDatagram(@NonNull Handler h, int what, + @Nullable Object obj) { + //mCi.registerForNewSatelliteDatagram(h, what, obj); + } + + + /** + * Unregister to stop receiving incoming datagrams over satellite. + * + * @param h - Handler to be removed from registrant list. + */ + public void unregisterForNewSatelliteDatagram(@NonNull Handler h) { + //mCi.unregisterForNewSatelliteDatagram(h); + } + + /** + * Poll pending satellite datagrams over satellite. + * @param result - message object which informs if the request is successful or not. + */ + public void pollPendingSatelliteDatagrams(Message result) { + //mCi.pollPendingSatelliteDatagrams(result); + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); -- GitLab From 33763725e53271266d080742f35ca446befa5c97 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Mon, 13 Feb 2023 09:24:01 -0800 Subject: [PATCH 423/656] Update deprovisionSatelliteService API in Phone Bug: 266013384 Test: atest android.telephony.cts.SatelliteManagerTest Change-Id: I60595206467ab7c268a1a73cca07d15cb68dcb86 --- .../com/android/internal/telephony/Phone.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index bf18164c99..6576a998cb 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5355,28 +5355,29 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * Provision the subscription with a satellite provider. This is needed to register the - * subscription if the provider allows dynamic registration. + * Provision the subscription with a satellite provider. + * This is needed to register the device/subscription if the provider allows dynamic + * registration. * * @param result Callback message to receive the result. - * @param token The security token of the device/subscription to be provisioned. - * @param imei IMEI of the SIM associated with the satellite modem. - * @param msisdn MSISDN of the SIM associated with the satellite modem. - * @param imsi IMSI of the SIM associated with the satellite modem. + * @param token The token of the device/subscription to be provisioned. */ - public void provisionSatelliteService(Message result, String token, String imei, String msisdn, - String imsi) { + public void provisionSatelliteService(Message result, String token) { // TODO: update parameters in HAL - // mCi.provisionSatelliteService(result, token, imei, msisdn, imsi); + // mCi.provisionSatelliteService(result, token); } /** - * Cancel the ongoing provision satellite request of a subscription. + * Deprovision the device/subscription with a satellite provider. + * This is needed to unregister the device/subscription if the provider allows dynamic + * registration. + * If provisioning is in progress for the given SIM, cancel the request. + * If there is no request in progress, deprovision the given SIM. * * @param result Callback message to receive the result. - * @param imsi IMSI of the subscription whose provision request will be cancelled. + * @param token The token of the device/subscription to be deprovisioned. */ - public void cancelProvisionSatelliteService(Message result, String imsi) { + public void deprovisionSatelliteService(Message result, String token) { //TODO (b/266126070): add implementation. } -- GitLab From 068f6171917a16d24b479f5f0ea6bbf98bd8a6a0 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 13 Feb 2023 12:46:13 -0800 Subject: [PATCH 424/656] Delayed registering as a system service Register the service after subscription database manager is created. Fix: 269089007 Test: v2/pixel-health-guard/device-boot-health-check-extra Change-Id: I7db87800e2d9e1f78b0ede17d92b9197a2d319a2 --- .../subscription/SubscriptionManagerService.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 9d65e6b0cd..7029dd4a04 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -404,14 +404,6 @@ public class SubscriptionManagerService extends ISub.Stub { mBackgroundHandler = new Handler(backgroundThread.getLooper()); - TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer(); - if (subscriptionServiceRegisterer.get() == null) { - subscriptionServiceRegisterer.register(this); - } - mDefaultVoiceSubId = new WatchedInt(Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, SubscriptionManager.INVALID_SUBSCRIPTION_ID)) { @@ -539,6 +531,14 @@ public class SubscriptionManagerService extends ISub.Stub { updateDefaultSubId(); + TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = + TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getSubscriptionServiceRegisterer(); + if (subscriptionServiceRegisterer.get() == null) { + subscriptionServiceRegisterer.register(this); + } + mHandler.post(() -> { // EuiccController is created after SubscriptionManagerService. So we need to get // the instance later in the handler. -- GitLab From ca09538cba3158d780e7e3036bc2e5818ccab2c6 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Thu, 9 Feb 2023 22:11:45 +0000 Subject: [PATCH 425/656] Added send satellite datagram. Bug: 260896985 Test: atest SatelliteManagerTest Change-Id: I7438ce6a35137f31c430863bebbb3becfe545d72 --- src/java/com/android/internal/telephony/Phone.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index d11af9165c..b5229329d3 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -73,6 +73,7 @@ import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.RegistrationManager; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; +import android.telephony.satellite.SatelliteDatagram; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; @@ -5480,6 +5481,15 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { //mCi.pollPendingSatelliteDatagrams(result); } + /** + * Send datagram over satellite. + * @param result - message object which informs if the request is successful or not + * @param datagram - datagram to send over satellite + */ + public void sendSatelliteDatagram(Message result, SatelliteDatagram datagram) { + //mCi.sendSatelliteDatagram(result, datagram, longitude, latitude); + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); -- GitLab From ca2f8f26029f190348dd4064015aead7b5dfd878 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sun, 12 Feb 2023 23:31:08 -0800 Subject: [PATCH 426/656] Correctly support restoring SIM specific settings After restoring the data, we need to update the subscription database cache. Fix: 269062965 Test: atest android.telephony.cts.SubscriptionManagerTest#testRestoreAllSimSpecificSettingsFromBackup Test: Boot up + Basic phone functionality tests Change-Id: Ie9ba6ed493f73a8597fb5eb4dceb61e9a0c440d1 --- .../telephony/SubscriptionController.java | 34 ++++++ .../telephony/SubscriptionInfoUpdater.java | 6 +- .../SubscriptionDatabaseManager.java | 109 ++++++++++++------ .../SubscriptionManagerService.java | 60 +++++++++- .../SubscriptionInfoUpdaterTest.java | 7 ++ .../SubscriptionDatabaseManagerTest.java | 18 +-- .../SubscriptionManagerServiceTest.java | 11 +- 7 files changed, 184 insertions(+), 61 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index bbdba56323..d359eafcf1 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -26,6 +26,7 @@ import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.app.AppOpsManager; import android.app.PendingIntent; import android.app.compat.CompatChanges; @@ -43,6 +44,7 @@ import android.database.Cursor; import android.net.Uri; import android.os.Binder; import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -4965,6 +4967,38 @@ public class SubscriptionController extends ISub.Stub { return false; } + /** + * Called during setup wizard restore flow to attempt to restore the backed up sim-specific + * configs to device for all existing SIMs in the subscription database {@link SimInfo}. + * Internally, it will store the backup data in an internal file. This file will persist on + * device for device's lifetime and will be used later on when a SIM is inserted to restore that + * specific SIM's settings. End result is subscription database is modified to match any backed + * up configs for the appropriate inserted SIMs. + * + *

+ * The {@link Uri} {@link SubscriptionManager#SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is + * notified if any {@link SimInfo} entry is updated as the result of this method call. + * + * @param data with the sim specific configs to be backed up. + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @Override + public void restoreAllSimSpecificSettingsFromBackup(@NonNull byte[] data) { + enforceModifyPhoneState("restoreAllSimSpecificSettingsFromBackup"); + + long token = Binder.clearCallingIdentity(); + try { + Bundle bundle = new Bundle(); + bundle.putByteArray(SubscriptionManager.KEY_SIM_SPECIFIC_SETTINGS_DATA, data); + mContext.getContentResolver().call( + SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, + SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, + null, bundle); + } finally { + Binder.restoreCallingIdentity(token); + } + } + /** * @hide */ diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index 5bef2f7f8a..95144fdd9d 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -717,8 +717,10 @@ public class SubscriptionInfoUpdater extends Handler { } private void restoreSimSpecificSettingsForPhone(int phoneId) { - SubscriptionManager subManager = SubscriptionManager.from(sContext); - subManager.restoreSimSpecificSettingsForIccIdFromBackup(sIccId[phoneId]); + sContext.getContentResolver().call( + SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, + SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, + sIccId[phoneId], null); } private void updateCarrierServices(int phoneId, String simState) { diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 7c72c305bb..99fb3432b5 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -505,8 +505,9 @@ public class SubscriptionDatabaseManager extends Handler { private final Map mAllSubscriptionInfoInternalCache = new HashMap<>(16); - /** Whether database has been loaded into the cache after boot up. */ - private boolean mDatabaseLoaded = false; + /** Whether database has been initialized after boot up. */ + @GuardedBy("mDatabaseInitialized") + private Boolean mDatabaseInitialized = false; /** * This is the callback used for listening events from {@link SubscriptionDatabaseManager}. @@ -542,9 +543,9 @@ public class SubscriptionDatabaseManager extends Handler { } /** - * Called when database has been loaded into the cache. + * Called when database has been initialized. */ - public abstract void onDatabaseLoaded(); + public abstract void onInitialized(); /** * Called when subscription changed. @@ -578,7 +579,7 @@ public class SubscriptionDatabaseManager extends Handler { mUiccController = UiccController.getInstance(); mAsyncMode = mContext.getResources().getBoolean( com.android.internal.R.bool.config_subscription_database_async_update); - loadFromDatabase(); + initializeDatabase(); } /** @@ -757,9 +758,12 @@ public class SubscriptionDatabaseManager extends Handler { + "insert. subInfo=" + subInfo); } - if (!mDatabaseLoaded) { - throw new IllegalStateException("Database has not been loaded. Can't insert new " - + "record at this point."); + synchronized (mDatabaseInitialized) { + if (!mDatabaseInitialized) { + throw new IllegalStateException( + "Database has not been initialized. Can't insert new " + + "record at this point."); + } } int subId; @@ -826,10 +830,12 @@ public class SubscriptionDatabaseManager extends Handler { private int updateDatabase(int subId, @NonNull ContentValues contentValues) { logv("updateDatabase: prepare to update sub " + subId); - if (!mDatabaseLoaded) { - logel("updateDatabase: Database has not been loaded. Can't update database at this " - + "point. contentValues=" + contentValues); - return 0; + synchronized (mDatabaseInitialized) { + if (!mDatabaseInitialized) { + logel("updateDatabase: Database has not been initialized. Can't update database at " + + "this point. contentValues=" + contentValues); + return 0; + } } if (mAsyncMode) { @@ -1794,39 +1800,68 @@ public class SubscriptionDatabaseManager extends Handler { } /** - * Load the entire database into the cache. + * Reload the database from content provider to the cache. */ - private void loadFromDatabase() { - // Perform the task in the handler thread. - Runnable r = () -> { - try (Cursor cursor = mContext.getContentResolver().query( - SimInfo.CONTENT_URI, null, null, null, null)) { - mReadWriteLock.writeLock().lock(); - try { - mAllSubscriptionInfoInternalCache.clear(); - while (cursor != null && cursor.moveToNext()) { - SubscriptionInfoInternal subInfo = createSubscriptionInfoFromCursor(cursor); - if (subInfo != null) { - mAllSubscriptionInfoInternalCache - .put(subInfo.getSubscriptionId(), subInfo); - } + public void reloadDatabase() { + if (mAsyncMode) { + post(this::loadDatabaseInternal); + } else { + loadDatabaseInternal(); + } + } + + /** + * Load the database from content provider to the cache. + */ + private void loadDatabaseInternal() { + logl("loadDatabaseInternal"); + try (Cursor cursor = mContext.getContentResolver().query( + SimInfo.CONTENT_URI, null, null, null, null)) { + mReadWriteLock.writeLock().lock(); + try { + Map newAllSubscriptionInfoInternalCache = + new HashMap<>(); + while (cursor != null && cursor.moveToNext()) { + SubscriptionInfoInternal subInfo = createSubscriptionInfoFromCursor(cursor); + newAllSubscriptionInfoInternalCache.put(subInfo.getSubscriptionId(), subInfo); + if (!Objects.equals(mAllSubscriptionInfoInternalCache + .get(subInfo.getSubscriptionId()), subInfo)) { + mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged( + subInfo.getSubscriptionId())); } - mDatabaseLoaded = true; - mCallback.invokeFromExecutor(mCallback::onDatabaseLoaded); - log("Loaded " + mAllSubscriptionInfoInternalCache.size() - + " records from the subscription database."); - } finally { - mReadWriteLock.writeLock().unlock(); } + + mAllSubscriptionInfoInternalCache.clear(); + mAllSubscriptionInfoInternalCache.putAll(newAllSubscriptionInfoInternalCache); + + logl("Loaded " + mAllSubscriptionInfoInternalCache.size() + + " records from the subscription database."); + } finally { + mReadWriteLock.writeLock().unlock(); } - }; + } + } + /** + * Initialize the database cache. Load the entire database into the cache. + */ + private void initializeDatabase() { if (mAsyncMode) { // Load the database asynchronously. - post(r); + post(() -> { + synchronized (mDatabaseInitialized) { + loadDatabaseInternal(); + mDatabaseInitialized = true; + mCallback.invokeFromExecutor(mCallback::onInitialized); + } + }); } else { // Load the database synchronously. - r.run(); + synchronized (mDatabaseInitialized) { + loadDatabaseInternal(); + mDatabaseInitialized = true; + mCallback.invokeFromExecutor(mCallback::onInitialized); + } } } @@ -1837,7 +1872,7 @@ public class SubscriptionDatabaseManager extends Handler { * * @return The subscription info from a single database record. */ - @Nullable + @NonNull private SubscriptionInfoInternal createSubscriptionInfoFromCursor(@NonNull Cursor cursor) { SubscriptionInfoInternal.Builder builder = new SubscriptionInfoInternal.Builder(); int id = cursor.getInt(cursor.getColumnIndexOrThrow( diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 9d65e6b0cd..4c9cf2c5cd 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -33,13 +33,16 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.net.Uri; import android.os.Binder; import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.ParcelUuid; import android.os.PersistableBundle; +import android.os.Process; import android.os.RemoteException; import android.os.TelephonyServiceManager; import android.os.UserHandle; @@ -221,7 +224,7 @@ public class SubscriptionManagerService extends ISub.Stub { /** Local log for most important debug messages. */ @NonNull - private final LocalLog mLocalLog = new LocalLog(128); + private final LocalLog mLocalLog = new LocalLog(256); /** The subscription database manager. */ @NonNull @@ -484,8 +487,8 @@ public class SubscriptionManagerService extends ISub.Stub { * Called when database has been loaded into the cache. */ @Override - public void onDatabaseLoaded() { - log("Subscription database has been loaded."); + public void onInitialized() { + log("Subscription database has been initialized."); for (int phoneId = 0; phoneId < mTelephonyManager.getActiveModemCount() ; phoneId++) { markSubscriptionsInactive(phoneId); @@ -557,6 +560,7 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); SubscriptionManager.invalidateSubscriptionManagerServiceEnabledCaches(); + logl("created"); } /** @@ -1335,7 +1339,11 @@ public class SubscriptionManagerService extends ISub.Stub { } // Attempt to restore SIM specific settings when SIM is loaded. - mSubscriptionManager.restoreSimSpecificSettingsForIccIdFromBackup(iccId); + mContext.getContentResolver().call( + SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, + SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, + iccId, null); + mSubscriptionDatabaseManager.reloadDatabase(); } } else { log("updateSubscriptions: No ICCID available for phone " + phoneId); @@ -2854,7 +2862,7 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { logl("setSubscriptionProperty: subId=" + subId + ", columnName=" + columnName - + ", value=" + value); + + ", value=" + value + ", calling package=" + getCallingPackage()); if (!SimInfo.getAllColumns().contains(columnName)) { throw new IllegalArgumentException("Invalid column name " + columnName); @@ -3486,7 +3494,7 @@ public class SubscriptionManagerService extends ISub.Stub { * @param subscriptionId the subId of the subscription * @param userHandle user handle of the user * @return {@code true} if subscription is associated with user - * {code true} if there are no subscriptions on device + * {@code true} if there are no subscriptions on device * else {@code false} if subscription is not associated with user. * * @throws SecurityException if the caller doesn't have permissions required. @@ -3593,6 +3601,42 @@ public class SubscriptionManagerService extends ISub.Stub { return true; } + /** + * Called during setup wizard restore flow to attempt to restore the backed up sim-specific + * configs to device for all existing SIMs in the subscription database {@link SimInfo}. + * Internally, it will store the backup data in an internal file. This file will persist on + * device for device's lifetime and will be used later on when a SIM is inserted to restore that + * specific SIM's settings. End result is subscription database is modified to match any backed + * up configs for the appropriate inserted SIMs. + * + *

+ * The {@link Uri} {@link SubscriptionManager#SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is + * notified if any {@link SimInfo} entry is updated as the result of this method call. + * + * @param data with the sim specific configs to be backed up. + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @Override + public void restoreAllSimSpecificSettingsFromBackup(@NonNull byte[] data) { + enforcePermissions("restoreAllSimSpecificSettingsFromBackup", + Manifest.permission.MODIFY_PHONE_STATE); + + long token = Binder.clearCallingIdentity(); + try { + Bundle bundle = new Bundle(); + bundle.putByteArray(SubscriptionManager.KEY_SIM_SPECIFIC_SETTINGS_DATA, data); + logl("restoreAllSimSpecificSettingsFromBackup"); + mContext.getContentResolver().call( + SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, + SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, + null, bundle); + // After restoring, we need to reload the content provider into the cache. + mSubscriptionDatabaseManager.reloadDatabase(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + /** * Register the callback for receiving information from {@link SubscriptionManagerService}. * @@ -3737,6 +3781,10 @@ public class SubscriptionManagerService extends ISub.Stub { */ @NonNull private String getCallingPackage() { + if (Binder.getCallingUid() == Process.PHONE_UID) { + // Too many packages running with phone uid. Just return one here. + return "com.android.phone"; + } return Arrays.toString(mContext.getPackageManager().getPackagesForUid( Binder.getCallingUid())); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java index 868b53a8cc..905b39378f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java @@ -33,6 +33,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.Nullable; import android.content.ContentProvider; import android.content.ContentValues; import android.content.Context; @@ -40,6 +41,7 @@ import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.UserInfo; import android.net.Uri; +import android.os.Bundle; import android.os.Looper; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -107,6 +109,11 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return mContentProvider.update(uri, values, selection, selectionArgs); } + + @Override + public Bundle call(String method, @Nullable String args, @Nullable Bundle bundle) { + return new Bundle(); + } } @Before 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 f49f3dbb20..d0431e41bb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -30,11 +30,13 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; +import android.os.Bundle; import android.os.Looper; import android.provider.Telephony; import android.provider.Telephony.SimInfo; @@ -56,7 +58,6 @@ import org.junit.runner.RunWith; import org.mockito.Mockito; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; @@ -343,13 +344,11 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { mDatabase.add(values); return ContentUris.withAppendedId(SimInfo.CONTENT_URI, subId); } - } - private void loadFromDatabase() throws Exception { - Method method = SubscriptionDatabaseManager.class.getDeclaredMethod("loadFromDatabase"); - method.setAccessible(true); - method.invoke(mDatabaseManagerUT); - processAllMessages(); + @Override + public Bundle call(String method, @Nullable String args, @Nullable Bundle bundle) { + return new Bundle(); + } } @Before @@ -365,6 +364,7 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { ((MockContentResolver) mContext.getContentResolver()).addProvider( Telephony.Carriers.CONTENT_URI.getAuthority(), mSubscriptionProvider); + doReturn(1).when(mUiccController).convertToPublicCardId(eq(FAKE_ICCID1)); doReturn(2).when(mUiccController).convertToPublicCardId(eq(FAKE_ICCID2)); mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper(), @@ -389,7 +389,9 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .that(mDatabaseManagerUT.getSubscriptionInfoInternal(subId)).isEqualTo(subInfo); // Load subscription info from the database. - loadFromDatabase(); + mDatabaseManagerUT.reloadDatabase(); + processAllMessages(); + // Verify the database value is same as the inserted one. assertWithMessage("Subscription info database value is different.") .that(mDatabaseManagerUT.getSubscriptionInfoInternal(subId)).isEqualTo(subInfo); 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 b0eafbf690..3b7d6b91e6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -229,12 +229,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { SubscriptionDatabaseManager sdbm = (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT); - Class[] cArgs = new Class[1]; - cArgs[0] = SubscriptionInfoInternal.class; - Method method = SubscriptionDatabaseManager.class.getDeclaredMethod( - "insertSubscriptionInfo", cArgs); - method.setAccessible(true); - int subId = (int) method.invoke(sdbm, subInfo); + int subId = sdbm.insertSubscriptionInfo(subInfo); // Insertion is sync, but the onSubscriptionChanged callback is handled by the handler. processAllMessages(); @@ -244,11 +239,11 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); field.setAccessible(true); Object map = field.get(mSubscriptionManagerServiceUT); - cArgs = new Class[2]; + Class[] cArgs = new Class[2]; cArgs[0] = Object.class; cArgs[1] = Object.class; - method = WatchedMapClass.getDeclaredMethod("put", cArgs); + Method method = WatchedMapClass.getDeclaredMethod("put", cArgs); method.setAccessible(true); method.invoke(map, subInfo.getSimSlotIndex(), subId); mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); -- GitLab From ccb767c8a380bc52be7d55f4a66ddf5c5d1066c0 Mon Sep 17 00:00:00 2001 From: Willy Hu Date: Sat, 11 Feb 2023 00:23:31 +0800 Subject: [PATCH 427/656] [DSRM] Fix the metrics wrong duration - add back start time when data stall happen first time - add the unit test for this case, ensure the start time not zero. Bug: 260166714 Test: Manual test passed. See the correct time in log. Change-Id: Ia33e05eadc2e96a1b2b78c488af4efcb9811065e --- .../data/DataStallRecoveryManager.java | 5 ++++- .../data/DataStallRecoveryManagerTest.java | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index 6632c67cb3..df3ab57460 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -158,7 +158,8 @@ public class DataStallRecoveryManager extends Handler { /** Whether the result of last action(RADIO_RESTART) reported. */ private boolean mLastActionReported; /** The real time for data stall start. */ - private @ElapsedRealtimeLong long mDataStallStartMs; + @VisibleForTesting + public @ElapsedRealtimeLong long mDataStallStartMs; /** Last data stall recovery action. */ private @RecoveryAction int mLastAction; /** Last radio power state. */ @@ -607,6 +608,8 @@ public class DataStallRecoveryManager extends Handler { isLogNeeded = true; mDataStalled = true; isFirstDataStall = true; + mDataStallStartMs = SystemClock.elapsedRealtime(); + logl("data stall: start time = " + DataUtils.elapsedTimeToString(mDataStallStartMs)); } else if (!mLastActionReported) { // When the first validation status appears, enter this block. isLogNeeded = true; diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java index a8290affec..25284413a9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java @@ -350,4 +350,23 @@ public class DataStallRecoveryManagerTest extends TelephonyTest { assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(0); } } + + @Test + public void testStartTimeNotZero() throws Exception { + sendOnInternetDataNetworkCallback(false); + doReturn(mSignalStrength).when(mPhone).getSignalStrength(); + doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); + + logd("Sending validation failed callback"); + sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_NOT_VALID); + processAllFutureMessages(); + + for (int i = 0; i < 2; i++) { + sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_NOT_VALID); + logd("Sending validation failed callback"); + processAllMessages(); + moveTimeForward(101); + } + assertThat(mDataStallRecoveryManager.mDataStallStartMs != 0).isTrue(); + } } -- GitLab From 5475c166505b8f8e3f74247fd92890e2d4228cfa Mon Sep 17 00:00:00 2001 From: Shuaihui Ren Date: Wed, 9 Nov 2022 16:14:00 +0800 Subject: [PATCH 428/656] Correct the value of cookie The cookie in EVENT_AIDL_PROXY_DEAD is used to check if the death notification should be ignored. The cookie object is passed by reference which causes the msg.obj.get() always equal to mServiceCookies.get(aidlService).get() when handling EVENT_AIDL_PROXY_DEAD. So pass the long type value of cookie in EVENT_AIDL_PROXY_DEAD message. And since the service is RADIO_SERVICE when handling EVENT_RADIO_PROXY_DEAD, the cookie of RADIO_SERVICE should be used for linkToDeath() when radio version is less than 2.0. Bug: 258390132 Test: Manual test by force killing RILD Change-Id: I7087f01fb56a611c21a2f976b05b85f67dafa50b --- src/java/com/android/internal/telephony/RIL.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index e6546149b2..6d442335f7 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -387,11 +387,11 @@ public class RIL extends BaseCommands implements CommandsInterface { case EVENT_AIDL_PROXY_DEAD: int aidlService = msg.arg1; - AtomicLong obj = (AtomicLong) msg.obj; - riljLog("handleMessage: EVENT_AIDL_PROXY_DEAD cookie = " + msg.obj + long msgCookie = (long) msg.obj; + riljLog("handleMessage: EVENT_AIDL_PROXY_DEAD cookie = " + msgCookie + ", service = " + serviceToString(aidlService) + ", cookie = " + mServiceCookies.get(aidlService)); - if (obj.get() == mServiceCookies.get(aidlService).get()) { + if (msgCookie == mServiceCookies.get(aidlService).get()) { mIsRadioProxyInitialized = false; resetProxyAndRequestList(aidlService); } @@ -473,7 +473,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void binderDied() { riljLog("Service " + serviceToString(mService) + " has died."); mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_AIDL_PROXY_DEAD, mService, - 0 /* ignored arg2 */, mServiceCookies.get(mService))); + 0 /* ignored arg2 */, mServiceCookies.get(mService).get())); unlinkToDeath(); } } @@ -1072,7 +1072,7 @@ public class RIL extends BaseCommands implements CommandsInterface { if (!mIsRadioProxyInitialized) { mIsRadioProxyInitialized = true; serviceProxy.getHidl().linkToDeath(mRadioProxyDeathRecipient, - mServiceCookies.get(service).incrementAndGet()); + mServiceCookies.get(HAL_SERVICE_RADIO).incrementAndGet()); serviceProxy.getHidl().setResponseFunctions( mRadioResponse, mRadioIndication); } -- GitLab From 8110b7e5468f6cc500bff30b0c127e3d5b390f45 Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Fri, 10 Feb 2023 04:27:39 +0000 Subject: [PATCH 429/656] Integrate new iccCloseLogicalChannelWithSessionInfo AIDL changes to framework. Test: Manually verified profile download/enable on C10 and atest FrameworksTelephonyTests Bug: 268496310 Change-Id: I21c74b58528d97fbebf9a227dda76da7d665eb2b --- .../internal/telephony/CommandsInterface.java | 18 ++++++++++++++++++ .../com/android/internal/telephony/RIL.java | 10 +++++++--- .../internal/telephony/RadioSimProxy.java | 17 +++++++++++++++-- .../imsphone/ImsPhoneCommandInterface.java | 3 +++ .../apdu/CloseLogicalChannelInvocation.java | 5 ++++- .../internal/telephony/SimulatedCommands.java | 5 +++++ .../telephony/SimulatedCommandsVerifier.java | 5 +++++ .../uicc/euicc/apdu/ApduSenderTest.java | 2 +- .../uicc/euicc/apdu/LogicalChannelMocker.java | 3 ++- 9 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index abd8a62c98..344fb6b35c 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2115,11 +2115,29 @@ public interface CommandsInterface { * * Input parameters equivalent to TS 27.007 AT+CCHC command. * + * Starting with Android U, use {@link #iccCloseLogicalChannel(int, boolean, Message)}} + * API to close the logical channel if the channel was opened to perform ES10 operations. + * * @param channel Channel id. Id of the channel to be closed. * @param response Callback message. */ public void iccCloseLogicalChannel(int channel, Message response); + /** + * Close a previously opened logical channel to the SIM. + * + * Input parameters equivalent to TS 27.007 AT+CCHC command. + * + * Per spec SGP.22 V3.0, ES10 commands needs to be sent over command port of MEP-A. In order + * to close proper logical channel, should pass information about whether the logical channel + * was opened for sending ES10 commands or not. + * + * @param channel Channel id. Id of the channel to be closed. + * @param isEs10 Whether the logical channel is opened to perform ES10 operations. + * @param response Callback message. + */ + public void iccCloseLogicalChannel(int channel, boolean isEs10, Message response); + /** * Exchange APDUs with the SIM on a logical channel. * diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 52dfda556b..86ae80006a 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -4122,6 +4122,11 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void iccCloseLogicalChannel(int channel, Message result) { + iccCloseLogicalChannel(channel, false, result); + } + + @Override + public void iccCloseLogicalChannel(int channel, boolean isEs10, Message result) { RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); if (!simProxy.isEmpty()) { RILRequest rr = obtainRequest(RIL_REQUEST_SIM_CLOSE_CHANNEL, result, @@ -4129,11 +4134,10 @@ public class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOGD) { riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) - + " channel = " + channel); + + " channel = " + channel + " isEs10 = " + isEs10); } - try { - simProxy.iccCloseLogicalChannel(rr.mSerial, channel); + simProxy.iccCloseLogicalChannel(rr.mSerial, channel, isEs10); } catch (RemoteException | RuntimeException e) { handleRadioProxyExceptionForRR(HAL_SERVICE_SIM, "iccCloseLogicalChannel", e); } diff --git a/src/java/com/android/internal/telephony/RadioSimProxy.java b/src/java/com/android/internal/telephony/RadioSimProxy.java index d945ad3115..d9aba9c44d 100644 --- a/src/java/com/android/internal/telephony/RadioSimProxy.java +++ b/src/java/com/android/internal/telephony/RadioSimProxy.java @@ -272,14 +272,27 @@ public class RadioSimProxy extends RadioServiceProxy { } /** - * Call IRadioSim#iccCloseLogicalChannel + * Call IRadioSim#iccCloseLogicalChannelWithSessionInfo * @param serial Serial number of request * @param channelId Channel ID of the channel to be closed + * @param isEs10 Whether the logical channel is opened for performing ES10 operations. * @throws RemoteException */ - public void iccCloseLogicalChannel(int serial, int channelId) throws RemoteException { + public void iccCloseLogicalChannel(int serial, + int channelId, boolean isEs10) throws RemoteException { if (isEmpty()) return; if (isAidl()) { + if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_2_1)) { + // TODO: [MEP-A1] Use iccCloseLogicalChannelWithSessionInfo API once vendor + // changes are completed. + //android.hardware.radio.sim.SessionInfo info = + // new android.hardware.radio.sim.SessionInfo(); + //info.sessionId = channelId; + //info.isEs10 = isEs10; + //mSimProxy.iccCloseLogicalChannelWithSessionInfo(serial, info); + mSimProxy.iccCloseLogicalChannel(serial, channelId); + return; + } mSimProxy.iccCloseLogicalChannel(serial, channelId); } else { mRadioProxy.iccCloseLogicalChannel(serial, channelId); diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java index 33e78f63f7..f89a31e2b3 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java @@ -609,6 +609,9 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface @Override public void iccCloseLogicalChannel(int channel, Message response) {} + @Override + public void iccCloseLogicalChannel(int channel, boolean isEs10, Message response) {} + @Override public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, int p3, String data, diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/CloseLogicalChannelInvocation.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/CloseLogicalChannelInvocation.java index 82ddb80d8e..a69977b8f8 100644 --- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/CloseLogicalChannelInvocation.java +++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/CloseLogicalChannelInvocation.java @@ -43,7 +43,10 @@ class CloseLogicalChannelInvocation extends AsyncMessageInvocation Date: Mon, 13 Feb 2023 13:46:00 -0800 Subject: [PATCH 430/656] Support new and updated satellite APIs Test: atest SatelliteManagerTest Bug: 268791334 Change-Id: Ie41a70a4ff6d24336960ec25a615a587ec54a320 --- .../internal/telephony/CommandsInterface.java | 9 +++- .../com/android/internal/telephony/Phone.java | 49 ++++++++++++------- .../com/android/internal/telephony/RIL.java | 19 +++++++ .../android/internal/telephony/RILUtils.java | 42 +--------------- .../telephony/SatelliteIndication.java | 5 +- 5 files changed, 63 insertions(+), 61 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index abd8a62c98..e4b0394023 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -3146,7 +3146,14 @@ public interface CommandsInterface { default void getMaxCharactersPerSatelliteTextMessage(Message result) {} /** - * Get time for next visibility of satellite. + * Get whether satellite communication is allowed for the current location. + * + * @param result Message that will be sent back to the requester. + */ + default void isSatelliteCommunicationAllowedForCurrentLocation(Message result) {} + + /** + * Get the time after which the satellite will next be visible. * * @param result Message that will be sent back to the requester. */ diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index fc206ab514..87db33bd8b 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5273,8 +5273,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Get maximum number of characters per text message on satellite. - * @param result - message object which contains maximum characters on success - * and error code on failure. + * @param result The Message to send the result of the operation to. */ public void getMaxCharactersPerSatelliteTextMessage(Message result) { mCi.getMaxCharactersPerSatelliteTextMessage(result); @@ -5414,9 +5413,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Registers for satellite state change from satellite modem. * - * @param h - Handler for notification message. - * @param what - User-defined message code. - * @param obj - User object. + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. */ public void registerForSatelliteModemStateChange(@NonNull Handler h, int what, @Nullable Object obj) { @@ -5426,7 +5425,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Unregisters for satellite state changes from satellite modem. * - * @param h - Handler to be removed from registrant list. + * @param h Handler to be removed from registrant list. */ public void unregisterForSatelliteModemStateChange(@NonNull Handler h) { mCi.unregisterForSatelliteModeChanged(h); @@ -5435,9 +5434,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Registers for pending message count info from satellite modem. * - * @param h - Handler for notification message. - * @param what - User-defined message code. - * @param obj - User object. + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. */ public void registerForPendingMessageCount(@NonNull Handler h, int what, @Nullable Object obj) { mCi.registerForPendingSatelliteMessageCount(h, what, obj); @@ -5446,7 +5445,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Unregisters for pending message count info from satellite modem. * - * @param h - Handler to be removed from registrant list. + * @param h Handler to be removed from registrant list. */ public void unregisterForPendingMessageCount(@NonNull Handler h) { mCi.unregisterForPendingSatelliteMessageCount(h); @@ -5455,9 +5454,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Register to receive incoming datagrams over satellite. * - * @param h - Handler for notification message. - * @param what - User-defined message code. - * @param obj - User object. + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. */ public void registerForNewSatelliteDatagram(@NonNull Handler h, int what, @Nullable Object obj) { @@ -5468,7 +5467,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Unregister to stop receiving incoming datagrams over satellite. * - * @param h - Handler to be removed from registrant list. + * @param h Handler to be removed from registrant list. */ public void unregisterForNewSatelliteDatagram(@NonNull Handler h) { //mCi.unregisterForNewSatelliteDatagram(h); @@ -5476,7 +5475,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Poll pending satellite datagrams over satellite. - * @param result - message object which informs if the request is successful or not. + * @param result The Message to send the result of the operation to. */ public void pollPendingSatelliteDatagrams(Message result) { //mCi.pollPendingSatelliteDatagrams(result); @@ -5484,13 +5483,29 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { /** * Send datagram over satellite. - * @param result - message object which informs if the request is successful or not - * @param datagram - datagram to send over satellite + * @param result The Message to send the result of the operation to. + * @param datagram Datagram to send over satellite. */ public void sendSatelliteDatagram(Message result, SatelliteDatagram datagram) { //mCi.sendSatelliteDatagram(result, datagram, longitude, latitude); } + /** + * Check whether satellite communication is allowed for the current location. + * @param result The Message to send the result of the operation to. + */ + public void isSatelliteCommunicationAllowedForCurrentLocation(Message result) { + mCi.isSatelliteCommunicationAllowedForCurrentLocation(result); + } + + /** + * Get the time after which the satellite will next be visible. + * @param result The Message to send the result of the operation to. + */ + public void requestTimeForNextSatelliteVisibility(Message result) { + mCi.getTimeForNextSatelliteVisibility(result); + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 52dfda556b..84bc2e90fd 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -6308,6 +6308,25 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * Get whether satellite communication is allowed for the current location + * + * @param result Message that will be sent back to the requester. + */ + @Override + public void isSatelliteCommunicationAllowedForCurrentLocation(Message result) { + // TODO: link to HAL implementation + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, + "stopSendingSatellitePointingInfo: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + /** * Get time for next visibility of satellite. * diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 5cb97b1a94..9c0acc1a03 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -377,7 +377,6 @@ import android.telephony.ims.stub.ImsRegistrationImplBase.ImsDeregistrationReaso import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteManager; -import android.telephony.satellite.stub.SatelliteImplBase; import android.text.TextUtils; import android.util.ArraySet; import android.util.SparseArray; @@ -5946,35 +5945,8 @@ public class RILUtils { supportedRadioTechnologies.add(technology); } } - - Set supportedFeatures = new HashSet<>(); - if (capabilities.supportedFeatures != null - && capabilities.supportedFeatures.length > 0) { - for (int feature : capabilities.supportedFeatures) { - supportedFeatures.add(feature); - } - } return new SatelliteCapabilities(supportedRadioTechnologies, capabilities.isAlwaysOn, - capabilities.needsPointingToSatellite, supportedFeatures, - capabilities.needsSeparateSimProfile); - } - - /** - * Convert from android.hardware.radio.satellite.Feature to - * android.telephony.satellite.stub.SatelliteImplBase.Feature - */ - public static int convertHalSatelliteFeature(int feature) { - switch (feature) { - case android.hardware.radio.satellite.SatelliteFeature.SOS_SMS: - return SatelliteImplBase.FEATURE_SOS_SMS; - case android.hardware.radio.satellite.SatelliteFeature.EMERGENCY_SMS: - return SatelliteImplBase.FEATURE_EMERGENCY_SMS; - case android.hardware.radio.satellite.SatelliteFeature.SMS: - return SatelliteImplBase.FEATURE_SMS; - case android.hardware.radio.satellite.SatelliteFeature.LOCATION_SHARING: - return SatelliteImplBase.FEATURE_LOCATION_SHARING; - default: return SatelliteImplBase.FEATURE_UNKNOWN; - } + capabilities.needsPointingToSatellite, capabilities.needsSeparateSimProfile); } /** @@ -5988,18 +5960,6 @@ public class RILUtils { pointingInfo.antennaPitchDegrees, pointingInfo.antennaRollDegrees); } - /** - * Convert array of android.hardware.radio.satellite.Feature to - * array of android.telephony.satellite.stub.SatelliteImplBase.Feature - */ - public static int[] convertHalSatelliteFeatures(int[] features) { - int[] convertedFeatrures = new int[features.length]; - for (int i = 0; i < features.length; i++) { - convertedFeatrures[i] = convertHalSatelliteFeature(features[i]); - } - return convertedFeatrures; - } - /** * Convert from android.telephony.satellite.stub.PointingInfo to * android.hardware.radio.satellite.PointingInfo diff --git a/src/java/com/android/internal/telephony/SatelliteIndication.java b/src/java/com/android/internal/telephony/SatelliteIndication.java index 9ebff587bd..6975489692 100644 --- a/src/java/com/android/internal/telephony/SatelliteIndication.java +++ b/src/java/com/android/internal/telephony/SatelliteIndication.java @@ -167,13 +167,14 @@ public class SatelliteIndication extends IRadioSatelliteIndication.Stub { * @param features List of Feature whose provision state has changed. */ public void onProvisionStateChanged(int indicationType, boolean provisioned, int[] features) { + // TODO: remove features and update AsyncResult mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED); if (mRil.mSatelliteProvisionStateChangedRegistrants != null) { - mRil.mSatelliteProvisionStateChangedRegistrants.notifyRegistrants(new AsyncResult( - provisioned, RILUtils.convertHalSatelliteFeatures(features), null)); + mRil.mSatelliteProvisionStateChangedRegistrants.notifyRegistrants( + new AsyncResult(provisioned, null, null)); } } } -- GitLab From 39da6f5024058e2c181e2b2507da2f9f07b30fe5 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Mon, 13 Feb 2023 22:08:35 +0000 Subject: [PATCH 431/656] Cleanup Satellite Messaging APIs. Bug: 260896985 Test: atest SatelliteManagerTest Change-Id: Ia398bd99d08f9145569505929a69e135d117cbd9 --- src/java/com/android/internal/telephony/Phone.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 87db33bd8b..26726df28b 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5432,22 +5432,23 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * Registers for pending message count info from satellite modem. + * Registers for pending datagram count info from satellite modem. * * @param h Handler for notification message. * @param what User-defined message code. * @param obj User object. */ - public void registerForPendingMessageCount(@NonNull Handler h, int what, @Nullable Object obj) { + public void registerForPendingDatagramCount(@NonNull Handler h, int what, + @Nullable Object obj) { mCi.registerForPendingSatelliteMessageCount(h, what, obj); } /** - * Unregisters for pending message count info from satellite modem. + * Unregisters for pending datagram count info from satellite modem. * * @param h Handler to be removed from registrant list. */ - public void unregisterForPendingMessageCount(@NonNull Handler h) { + public void unregisterForPendingDatagramCount(@NonNull Handler h) { mCi.unregisterForPendingSatelliteMessageCount(h); } @@ -5474,7 +5475,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * Poll pending satellite datagrams over satellite. + * Poll pending datagrams over satellite. * @param result The Message to send the result of the operation to. */ public void pollPendingSatelliteDatagrams(Message result) { -- GitLab From b52dc2f2ab86b7a40c2533d765b883b47a4ea815 Mon Sep 17 00:00:00 2001 From: rambowang Date: Thu, 9 Feb 2023 14:16:26 -0600 Subject: [PATCH 432/656] CarrierPrivilegesTracker: Remove [un]registerCarrierPrivilegesListener The interfaces have been deprecated and replaced by public APIs TelephonyManager#[un]registerCarrierPrivilegesCallback in TM release. All the callers of the old interfaces have been updated. It's time to throughly clean up the old interfaces to keep code healthy. Bug: 224871263 Test: atest FrameworksTelephonyTest Change-Id: Ia3b2542226b3c5701c2a3939daceacc01fcba2a2 --- .../telephony/CarrierPrivilegesTracker.java | 81 ------------ .../CarrierPrivilegesTrackerTest.java | 118 ------------------ 2 files changed, 199 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index 8ee2b44023..5a541d1197 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -49,8 +49,6 @@ import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.Process; -import android.os.Registrant; -import android.os.RegistrantList; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; @@ -64,7 +62,6 @@ import android.telephony.UiccAccessRule; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.IntArray; import android.util.LocalLog; import android.util.Pair; @@ -124,18 +121,6 @@ public class CarrierPrivilegesTracker extends Handler { | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS; - /** - * Action to register a Registrant with this Tracker. - * obj: Registrant that will be notified of Carrier Privileged UID changes. - */ - private static final int ACTION_REGISTER_LISTENER = 1; - - /** - * Action to unregister a Registrant with this Tracker. - * obj: Handler used by the Registrant that will be removed. - */ - private static final int ACTION_UNREGISTER_LISTENER = 2; - /** * Action for tracking when the Phone's SIM state changes. * arg1: slotId that this Action applies to @@ -186,7 +171,6 @@ public class CarrierPrivilegesTracker extends Handler { private final TelephonyRegistryManager mTelephonyRegistryManager; @NonNull private final LocalLog mLocalLog = new LocalLog(64); - @NonNull private final RegistrantList mRegistrantList = new RegistrantList(); // Stores rules for Carrier Config-loaded rules @NonNull private final List mCarrierConfigRules = new ArrayList<>(); // Stores rules for SIM-loaded rules. @@ -378,14 +362,6 @@ public class CarrierPrivilegesTracker extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { - case ACTION_REGISTER_LISTENER: { - handleRegisterListener((Registrant) msg.obj); - break; - } - case ACTION_UNREGISTER_LISTENER: { - handleUnregisterListener((Handler) msg.obj); - break; - } case ACTION_SIM_STATE_UPDATED: { handleSimStateChanged(msg.arg1, msg.arg2); break; @@ -424,23 +400,6 @@ public class CarrierPrivilegesTracker extends Handler { } } - private void handleRegisterListener(@NonNull Registrant registrant) { - mRegistrantList.add(registrant); - mPrivilegedPackageInfoLock.readLock().lock(); - try { - // Old registrant callback still takes int[] as parameter, need conversion here - int[] uids = intSetToArray(mPrivilegedPackageInfo.mUids); - registrant.notifyResult( - Arrays.copyOf(uids, uids.length)); - } finally { - mPrivilegedPackageInfoLock.readLock().unlock(); - } - } - - private void handleUnregisterListener(@NonNull Handler handler) { - mRegistrantList.remove(handler); - } - private void handleCarrierConfigUpdated(int subId, int slotIndex) { if (slotIndex != mPhone.getPhoneId()) return; @@ -703,12 +662,6 @@ public class CarrierPrivilegesTracker extends Handler { mPrivilegedPackageInfoLock.readLock().lock(); try { - // The obsoleted callback only care about UIDs - if (carrierPrivilegesUidsChanged) { - int[] uids = intSetToArray(mPrivilegedPackageInfo.mUids); - mRegistrantList.notifyResult(Arrays.copyOf(uids, uids.length)); - } - if (carrierPrivilegesPackageNamesChanged || carrierPrivilegesUidsChanged) { mTelephonyRegistryManager.notifyCarrierPrivilegesChanged( mPhone.getPhoneId(), @@ -841,33 +794,6 @@ public class CarrierPrivilegesTracker extends Handler { pw.println("mClearUiccRulesUptimeMillis: " + mClearUiccRulesUptimeMillis); } - /** - * Registers the given Registrant with this tracker. - * - *

After being registered, the Registrant will be notified with the current Carrier - * Privileged UIDs for this Phone. - * - * @deprecated Use {@link TelephonyManager#registerCarrierPrivilegesCallback} instead, which - * also provides package names - *

TODO(b/211658797) migrate callers, then delete all Registrant logic from CPT - */ - @Deprecated - public void registerCarrierPrivilegesListener( - @NonNull Handler h, int what, @Nullable Object obj) { - sendMessage(obtainMessage(ACTION_REGISTER_LISTENER, new Registrant(h, what, obj))); - } - - /** - * Unregisters the given listener with this tracker. - * - * @deprecated Use {@link TelephonyManager#unregisterCarrierPrivilegesCallback} instead - *

TODO(b/211658797) migrate callers, then delete all Registrant logic from CPT - */ - @Deprecated - public void unregisterCarrierPrivilegesListener(@NonNull Handler handler) { - sendMessage(obtainMessage(ACTION_UNREGISTER_LISTENER, handler)); - } - /** * Set test carrier privilege rules which will override the actual rules on both Carrier Config * and SIM. @@ -1058,11 +984,4 @@ public class CarrierPrivilegesTracker extends Handler { ? new Pair<>(null, Process.INVALID_UID) : new Pair<>(carrierServicePackageName, getPackageUid(carrierServicePackageName)); } - - @NonNull - private static int[] intSetToArray(@NonNull Set intSet) { - IntArray converter = new IntArray(intSet.size()); - intSet.forEach(converter::add); - return converter.toArray(); - } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java index 96c46b3f92..c32a4c5459 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java @@ -28,10 +28,8 @@ import static android.telephony.TelephonyManager.SIM_STATE_LOADED; import static android.telephony.TelephonyManager.SIM_STATE_NOT_READY; import static android.telephony.TelephonyManager.SIM_STATE_READY; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; @@ -42,7 +40,6 @@ import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.annotation.Nullable; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageInfo; @@ -53,9 +50,6 @@ import android.content.pm.ServiceInfo; import android.content.pm.Signature; import android.content.pm.UserInfo; import android.net.Uri; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; import android.os.PersistableBundle; import android.os.Process; import android.service.carrier.CarrierService; @@ -89,7 +83,6 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class CarrierPrivilegesTrackerTest extends TelephonyTest { - private static final int REGISTRANT_WHAT = 1; private static final int PHONE_ID = 2; private static final int PHONE_ID_INCORRECT = 3; private static final int SUB_ID = 4; @@ -128,7 +121,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS; private PersistableBundle mCarrierConfigs; - private CarrierPrivilegesTrackerTestHandler mHandler; private CarrierPrivilegesTracker mCarrierPrivilegesTracker; private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; @@ -141,7 +133,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { when(mPhone.getSubId()).thenReturn(SUB_ID); mCarrierConfigs = new PersistableBundle(); - mHandler = new CarrierPrivilegesTrackerTestHandler(); // set mock behavior so CarrierPrivilegeTracker initializes with no privileged UIDs setupCarrierConfigRules(); @@ -151,7 +142,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { @After public void tearDown() throws Exception { - mHandler = null; mCarrierPrivilegesTracker = null; mCarrierConfigs = null; super.tearDown(); @@ -230,9 +220,7 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); mTestableLooper.processAllMessages(); - cpt.registerCarrierPrivilegesListener(mHandler, REGISTRANT_WHAT, null); mTestableLooper.processAllMessages(); - mHandler.reset(); return cpt; } @@ -256,29 +244,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mCarrierPrivilegesTracker = createCarrierPrivilegesTracker(); } - private class CarrierPrivilegesTrackerTestHandler extends Handler { - public int[] privilegedUids; - public int numUidUpdates; - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case REGISTRANT_WHAT: - AsyncResult asyncResult = (AsyncResult) msg.obj; - privilegedUids = (int[]) asyncResult.result; - numUidUpdates++; - break; - default: - fail("Unexpected msg received. what=" + msg.what); - } - } - - void reset() { - privilegedUids = null; - numUidUpdates = 0; - } - } - private void verifyCurrentState(Set expectedPackageNames, int[] expectedUids) { assertEquals( expectedPackageNames, mCarrierPrivilegesTracker.getPackagesWithCarrierPrivileges()); @@ -294,11 +259,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { } } - private void verifyRegistrantUpdates(@Nullable int[] expectedUids, int expectedUidUpdates) { - assertArrayEquals(expectedUids, mHandler.privilegedUids); - assertEquals(expectedUidUpdates, mHandler.numUidUpdates); - } - private void verifyCarrierPrivilegesChangedUpdates( List, Set>> expectedUpdates) { if (expectedUpdates.isEmpty()) { @@ -333,56 +293,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { } } - @Test - public void testRegisterListener() throws Exception { - mCarrierPrivilegesTracker = createCarrierPrivilegesTracker(); - // mHandler registered in createCarrierPrivilegesTracker(), so reset it - mHandler = new CarrierPrivilegesTrackerTestHandler(); - - mCarrierPrivilegesTracker.registerCarrierPrivilegesListener( - mHandler, REGISTRANT_WHAT, null); - mTestableLooper.processAllMessages(); - - // No updates triggered, but the registrant gets an empty update. - verifyCurrentState(Set.of(), new int[0]); - verifyRegistrantUpdates(new int[0] /* expectedUids */, 1 /* expectedUidUpdates */); - verifyCarrierPrivilegesChangedUpdates(List.of()); - } - - @Test - public void testUnregisterListener() throws Exception { - // Start with privileges. Verify no updates received after clearing UIDs. - setupCarrierPrivilegesTrackerWithCarrierConfigUids(); - // mHandler registered in createCarrierPrivilegesTracker(), so reset it - mHandler = new CarrierPrivilegesTrackerTestHandler(); - - mCarrierPrivilegesTracker.registerCarrierPrivilegesListener( - mHandler, REGISTRANT_WHAT, null); - mTestableLooper.processAllMessages(); - - verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(PRIVILEGED_UIDS /* expectedUids */, 1 /* expectedUidUpdates */); - verifyCarrierPrivilegesChangedUpdates( - List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); - mHandler.reset(); - reset(mTelephonyRegistryManager); - - mCarrierPrivilegesTracker.unregisterCarrierPrivilegesListener(mHandler); - mTestableLooper.processAllMessages(); - - verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(null /* expectedUids */, 0 /* expectedUidUpdates */); - verifyCarrierPrivilegesChangedUpdates(List.of()); - - // Clear UIDs - sendCarrierConfigChanged(INVALID_SUBSCRIPTION_ID, PHONE_ID); - mTestableLooper.processAllMessages(); - - verifyCurrentState(Set.of(), new int[0]); - verifyRegistrantUpdates(null /* expectedUids */, 0 /* expectedUidUpdates */); - verifyCarrierPrivilegesChangedUpdates(List.of(new Pair<>(Set.of(), Set.of()))); - } - @Test public void testCarrierConfigUpdated() throws Exception { // Start with packages installed and no certs @@ -397,7 +307,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(PRIVILEGED_UIDS, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } @@ -411,7 +320,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(null /* expectedUids */, 0 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } @@ -425,7 +333,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(), new int[0]); - verifyRegistrantUpdates(new int[0] /* expectedUids */, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of( new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET), @@ -445,7 +352,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(), new int[0]); - verifyRegistrantUpdates(new int[0] /* expectedUids */, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates(List.of(new Pair<>(Set.of(), Set.of()))); } @@ -465,7 +371,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(PACKAGE_1), new int[] {UID_1}); - verifyRegistrantUpdates(new int[] {UID_1}, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(PACKAGE_1), Set.of(UID_1)))); @@ -478,7 +383,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(PRIVILEGED_UIDS, 2 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } @@ -497,7 +401,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(PRIVILEGED_UIDS, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } @@ -516,7 +419,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(PRIVILEGED_UIDS, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } @@ -532,7 +434,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(), new int[0]); - verifyRegistrantUpdates(new int[0], 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of( new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET), @@ -550,7 +451,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(null /* expectedUids */, 0 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } @@ -573,7 +473,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // Check again, the carrier privileges should be emptied verifyCurrentState(Set.of(), new int[0]); - verifyRegistrantUpdates(new int[0], 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of( new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET), @@ -602,7 +501,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // verify all carrier privileges should remain, no CP change notified verifyCurrentState(Set.of(PACKAGE_1, PACKAGE_2), new int[]{UID_1, UID_2}); - verifyRegistrantUpdates(null /* expectedUidUpdates */, 0 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates(List.of()); } @@ -623,7 +521,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // verify the carrier privileges should be emptied verifyCurrentState(Set.of(), new int[0]); - verifyRegistrantUpdates(new int[0], 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(), Set.of()))); } @@ -645,7 +542,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // verify the carrier privileges should be emptied verifyCurrentState(Set.of(), new int[0]); - verifyRegistrantUpdates(new int[0], 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(), Set.of()))); } @@ -672,7 +568,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // Carrier privileges should be updated and CP change should be notified verifyCurrentState(Set.of(PACKAGE_1), new int[] {UID_1}); - verifyRegistrantUpdates(new int[] {UID_1}, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(PACKAGE_1), Set.of(UID_1)))); } @@ -732,7 +627,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(PACKAGE_1), new int[] {UID_1}); - verifyRegistrantUpdates(new int[] {UID_1}, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(PACKAGE_1), Set.of(UID_1)))); @@ -746,7 +640,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(PRIVILEGED_UIDS, 2 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } @@ -763,7 +656,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(PACKAGE_1), new int[] {UID_1}); - verifyRegistrantUpdates(new int[] {UID_1}, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(PACKAGE_1), Set.of(UID_1)))); } @@ -783,7 +675,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(PACKAGE_1), PRIVILEGED_UIDS); - verifyRegistrantUpdates(PRIVILEGED_UIDS, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(PACKAGE_1), PRIVILEGED_UIDS_SET))); } @@ -804,7 +695,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(PACKAGE_1), PRIVILEGED_UIDS); - verifyRegistrantUpdates(PRIVILEGED_UIDS, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(PACKAGE_1), PRIVILEGED_UIDS_SET))); } @@ -829,7 +719,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(PACKAGE_2), new int[] {UID_2}); - verifyRegistrantUpdates(new int[] {UID_2}, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(PACKAGE_2), Set.of(UID_2)))); } @@ -853,7 +742,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(PACKAGE_2), new int[] {UID_2}); - verifyRegistrantUpdates(new int[] {UID_2}, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(PACKAGE_2), Set.of(UID_2)))); } @@ -872,7 +760,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(PACKAGE_2), new int[] {UID_2}); - verifyRegistrantUpdates(new int[] {UID_2}, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(Set.of(PACKAGE_2), Set.of(UID_2)))); } @@ -887,7 +774,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { mTestableLooper.processAllMessages(); verifyCurrentState(Set.of(), new int[0]); - verifyRegistrantUpdates(null /* expectedUidUpdates */, 0 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates(List.of()); } @@ -943,7 +829,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // Expect no package will have privilege at last verifyCurrentState(Set.of(), new int[0]); - verifyRegistrantUpdates(new int[0], 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of( new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET), @@ -955,7 +840,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // Expect all privileges from Carrier Config come back verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(PRIVILEGED_UIDS, 2 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } @@ -971,7 +855,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // Expect only PACKAGE_3 will have privilege at last verifyCurrentState(Set.of(PACKAGE_3), new int[]{UID_3}); - verifyRegistrantUpdates(new int[]{UID_3}, 1 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of( new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET), @@ -984,7 +867,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { // Expect all privileges from UICC come back verifyCurrentState(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS); - verifyRegistrantUpdates(PRIVILEGED_UIDS, 2 /* expectedUidUpdates */); verifyCarrierPrivilegesChangedUpdates( List.of(new Pair<>(PRIVILEGED_PACKAGES, PRIVILEGED_UIDS_SET))); } -- GitLab From c5daef5b412468ed67435f3ec9245e1fbdf83f86 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 8 Feb 2023 03:09:19 -0800 Subject: [PATCH 433/656] Create SatelliteServiceController and SateliteServiceConnection Test: manual boot up and verify Bug: 261131816 Change-Id: Ie53510cd40b759ba9c4d68018b96b53dd57c64b7 --- .../internal/telephony/CommandsInterface.java | 2 +- .../com/android/internal/telephony/Phone.java | 2 +- .../telephony/SatelliteIndication.java | 6 +- .../internal/telephony/SatelliteResponse.java | 5 +- .../satellite/SatelliteServiceController.java | 185 ++++++++++++++++++ 5 files changed, 190 insertions(+), 10 deletions(-) create mode 100644 src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 4b4a25dd8e..dbb7c80f3b 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -3171,7 +3171,7 @@ public interface CommandsInterface { default void isSatelliteCommunicationAllowedForCurrentLocation(Message result) {} /** - * Get the time after which the satellite will next be visible. + * Get the time after which the satellite will be visible. * * @param result Message that will be sent back to the requester. */ diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 87db33bd8b..94983552eb 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5499,7 +5499,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * Get the time after which the satellite will next be visible. + * Get the time after which the satellite will be visible. * @param result The Message to send the result of the operation to. */ public void requestTimeForNextSatelliteVisibility(Message result) { diff --git a/src/java/com/android/internal/telephony/SatelliteIndication.java b/src/java/com/android/internal/telephony/SatelliteIndication.java index 6975489692..3d08fdf425 100644 --- a/src/java/com/android/internal/telephony/SatelliteIndication.java +++ b/src/java/com/android/internal/telephony/SatelliteIndication.java @@ -28,7 +28,6 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_RA import android.hardware.radio.satellite.IRadioSatelliteIndication; import android.os.AsyncResult; -import android.telephony.satellite.stub.SatelliteImplBase; /** * Interface declaring unsolicited radio indications for Satellite APIs. @@ -129,7 +128,7 @@ public class SatelliteIndication extends IRadioSatelliteIndication.Stub { * @param indicationType Type of radio indication * @param mode The current mode of the satellite modem. */ - public void onSatelliteModeChanged(int indicationType, @SatelliteImplBase.Mode int mode) { + public void onSatelliteModeChanged(int indicationType, int mode) { mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_MODE_CHANGED); @@ -146,8 +145,7 @@ public class SatelliteIndication extends IRadioSatelliteIndication.Stub { * @param indicationType Type of radio indication * @param technology The current technology of the satellite modem. */ - public void onSatelliteRadioTechnologyChanged(int indicationType, - @SatelliteImplBase.NTRadioTechnology int technology) { + public void onSatelliteRadioTechnologyChanged(int indicationType, int technology) { mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED); diff --git a/src/java/com/android/internal/telephony/SatelliteResponse.java b/src/java/com/android/internal/telephony/SatelliteResponse.java index e33f38bbde..559691b9d9 100644 --- a/src/java/com/android/internal/telephony/SatelliteResponse.java +++ b/src/java/com/android/internal/telephony/SatelliteResponse.java @@ -22,7 +22,6 @@ import android.hardware.radio.RadioError; import android.hardware.radio.RadioResponseInfo; import android.hardware.radio.satellite.IRadioSatelliteResponse; import android.telephony.satellite.SatelliteCapabilities; -import android.telephony.satellite.stub.SatelliteImplBase; /** * Interface declaring response functions to solicited radio requests for Satellite APIs. @@ -145,9 +144,7 @@ public class SatelliteResponse extends IRadioSatelliteResponse.Stub { * @param mode Current Mode of the satellite modem. * @param technology The current technology of the satellite modem. */ - public void getSatelliteModeResponse( - RadioResponseInfo responseInfo, @SatelliteImplBase.Mode int mode, - @SatelliteImplBase.NTRadioTechnology int technology) { + public void getSatelliteModeResponse(RadioResponseInfo responseInfo, int mode, int technology) { RILRequest rr = mRil.processResponse(HAL_SERVICE_SATELLITE, responseInfo); if (rr != null) { diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java new file mode 100644 index 0000000000..3121dea8ed --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2023 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.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.Looper; +import android.telephony.Rlog; +import android.telephony.satellite.stub.ISatellite; +import android.telephony.satellite.stub.SatelliteService; +import android.text.TextUtils; + +import com.android.internal.telephony.ExponentialBackoff; + +/** + * Satellite service controller to manage connections with the satellite service. + */ +public class SatelliteServiceController { + private static final String TAG = "SatelliteServiceController"; + private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds + private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute + private static final int REBIND_MULTIPLIER = 2; + + @NonNull private static SatelliteServiceController sInstance; + @NonNull private final Context mContext; + @NonNull private final ExponentialBackoff mExponentialBackoff; + @NonNull private final Object mLock = new Object(); + @Nullable private ISatellite mSatelliteService; + @Nullable private SatelliteServiceConnection mSatelliteServiceConnection; + private boolean mIsBound; + + /** + * @return The singleton instance of SatelliteServiceController. + */ + public static SatelliteServiceController getInstance() { + if (sInstance == null) { + loge("SatelliteServiceController was not yet initialized."); + } + return sInstance; + } + + /** + * Create the SatelliteServiceController singleton instance. + * @param context The Context to use to create the SatelliteServiceController. + */ + public static void make(@NonNull Context context) { + if (sInstance == null) { + sInstance = new SatelliteServiceController(context, Looper.getMainLooper()); + } + } + + /** + * Create a SatelliteServiceController to manage connections to the SatelliteService. + * + * @param context The Context for the SatelliteServiceController. + * @param looper The Looper to run binding retry on. + */ + private SatelliteServiceController(@NonNull Context context, @NonNull Looper looper) { + mContext = context; + mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, + REBIND_MULTIPLIER, looper, () -> { + synchronized (mLock) { + if (mIsBound) { + return; + } + bindService(); + } + }); + mExponentialBackoff.start(); + logd("Created SatelliteServiceController. Attempting to bind to SatelliteService."); + bindService(); + } + + /** + * Get the SatelliteService interface, if it exists. + * + * @return The bound ISatellite, or {@code null} if it is not yet connected. + */ + @Nullable public ISatellite getService() { + return mSatelliteService; + } + + @NonNull private String getSatellitePackageName() { + return TextUtils.emptyIfNull(mContext.getResources().getString( + com.android.internal.R.string.config_satellite_service_package)); + } + + private void bindService() { + String packageName = getSatellitePackageName(); + if (TextUtils.isEmpty(packageName)) { + loge("Unable to bind to the satellite service because the package is undefined."); + // Since the package name comes from static device configs, stop retry because + // rebind will continue to fail without a valid package name. + mExponentialBackoff.stop(); + return; + } + Intent intent = new Intent(SatelliteService.SERVICE_INTERFACE); + intent.setPackage(packageName); + + mSatelliteServiceConnection = new SatelliteServiceConnection(); + try { + boolean success = mContext.bindService( + intent, mSatelliteServiceConnection, Context.BIND_AUTO_CREATE); + if (success) { + logd("Successfully bound to the satellite service."); + } else { + mExponentialBackoff.notifyFailed(); + loge("Error binding to the satellite service. Retrying in " + + mExponentialBackoff.getCurrentDelay() + " ms."); + } + } catch (Exception e) { + mExponentialBackoff.notifyFailed(); + loge("Exception binding to the satellite service. Retrying in " + + mExponentialBackoff.getCurrentDelay() + " ms. Exception: " + e); + } + } + + private void unbindService() { + resetService(); + mContext.unbindService(mSatelliteServiceConnection); + mSatelliteServiceConnection = null; + } + + private void resetService() { + // TODO: clean up any listeners and return failed for pending callbacks + mSatelliteService = null; + } + + private class SatelliteServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + logd("onServiceConnected: ComponentName=" + name); + synchronized (mLock) { + mIsBound = true; + } + mSatelliteService = ISatellite.Stub.asInterface(service); + mExponentialBackoff.stop(); + // TODO: register any listeners + } + + @Override + public void onServiceDisconnected(ComponentName name) { + loge("onServiceDisconnected: Waiting for reconnect."); + // Since we are still technically bound, clear the service and wait for reconnect. + resetService(); + } + + @Override + public void onBindingDied(ComponentName name) { + loge("onBindingDied: Unbinding and rebinding service."); + synchronized (mLock) { + mIsBound = false; + } + unbindService(); + mExponentialBackoff.start(); + } + } + + private static void logd(@NonNull String log) { + Rlog.d(TAG, log); + } + + private static void loge(@NonNull String log) { + Rlog.e(TAG, log); + } +} -- GitLab From 48f005f9acf3cf5c5d554a3a4ea6eff3b37e5b43 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Thu, 19 Jan 2023 09:06:42 +0000 Subject: [PATCH 434/656] Added new API to notify ECBM and SCBM status Bug: b/260533540 Test: atest CtsTelephonyTestCases:TelephonyCallbackTest, TelephonyRegistryTest Change-Id: I4d8198a257f8524123016621b56006276b593ae9 --- .../telephony/DefaultPhoneNotifier.java | 14 +++++++++++++ .../com/android/internal/telephony/Phone.java | 20 +++++++++++++++++++ .../internal/telephony/PhoneNotifier.java | 9 +++++++++ .../telephony/TelephonyRegistryTest.java | 2 ++ 4 files changed, 45 insertions(+) diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java index 8eafeba0d4..e5a5c8fd88 100644 --- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -33,6 +33,8 @@ import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager.DataEnabledReason; +import android.telephony.TelephonyManager.EmergencyCallbackModeStopReason; +import android.telephony.TelephonyManager.EmergencyCallbackModeType; import android.telephony.TelephonyRegistryManager; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsCallSession; @@ -284,6 +286,18 @@ public class DefaultPhoneNotifier implements PhoneNotifier { sender.getSubId(), linkCapacityEstimateList); } + @Override + public void notifyCallbackModeStarted(Phone sender, @EmergencyCallbackModeType int type) { + mTelephonyRegistryMgr.notifyCallBackModeStarted(sender.getPhoneId(), + sender.getSubId(), type); + } + + @Override + public void notifyCallbackModeStopped(Phone sender, @EmergencyCallbackModeType int type, + @EmergencyCallbackModeStopReason int reason) { + mTelephonyRegistryMgr.notifyCallbackModeStopped(sender.getPhoneId(), + sender.getSubId(), type, reason); + } /** * Convert the {@link Call.State} enum into the PreciseCallState.PRECISE_CALL_STATE_* constants * for the public API. diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 87db33bd8b..dd4be0fb41 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5506,6 +5506,26 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.getTimeForNextSatelliteVisibility(result); } + /** + * Start callback mode + * @param type for callback mode entry. + */ + public void startCallbackMode(@TelephonyManager.EmergencyCallbackModeType int type) { + Rlog.d(LOG_TAG, "startCallbackMode:type=" + type); + mNotifier.notifyCallbackModeStarted(this, type); + } + + /** + * Stop callback mode + * @param type for callback mode exit. + * @param reason for stopping callback mode. + */ + public void stopCallbackMode(@TelephonyManager.EmergencyCallbackModeType int type, + @TelephonyManager.EmergencyCallbackModeStopReason int reason) { + Rlog.d(LOG_TAG, "stopCallbackMode:type=" + type + ", reason=" + reason); + mNotifier.notifyCallbackModeStopped(this, type, reason); + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java index 2a439a304f..20d6702f9d 100644 --- a/src/java/com/android/internal/telephony/PhoneNotifier.java +++ b/src/java/com/android/internal/telephony/PhoneNotifier.java @@ -32,6 +32,8 @@ import android.telephony.PreciseDataConnectionState; import android.telephony.ServiceState; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager.DataEnabledReason; +import android.telephony.TelephonyManager.EmergencyCallbackModeStopReason; +import android.telephony.TelephonyManager.EmergencyCallbackModeType; import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.MediaQualityStatus; @@ -140,4 +142,11 @@ public interface PhoneNotifier { /** Notify link capacity estimate has changed. */ void notifyLinkCapacityEstimateChanged(Phone sender, List linkCapacityEstimateList); + + /** Notify callback mode started. */ + void notifyCallbackModeStarted(Phone sender, @EmergencyCallbackModeType int type); + + /** Notify callback mode stopped. */ + void notifyCallbackModeStopped(Phone sender, @EmergencyCallbackModeType int type, + @EmergencyCallbackModeStopReason int reason); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java index 71c677315e..2b4d8013e5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java @@ -157,6 +157,8 @@ public class TelephonyRegistryTest extends TelephonyTest { TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED); READ_PRIVILEGED_PHONE_STATE_EVENTS.add( TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED); + READ_PRIVILEGED_PHONE_STATE_EVENTS.add( + TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED); } // All events contribute to TelephonyRegistry#isActiveEmergencySessionPermissionRequired -- GitLab From 14385296237ef6f28e96b31db83647d990277d2c Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 14 Feb 2023 18:18:13 -0800 Subject: [PATCH 435/656] Fixed eSIM deletion issue Fixed tje issue that eSIM cannot be deleted from settings. The problem is that the deleted eSIM looks like inactive eSIM in the database. Fixed by marking the removed eSIM as removed pSIM, which is the pre-U behavior. Fix: 269229150 Test: Boot up + basic phone functionality Test: atest SubscriptionManagerServiceTest Test: Manually deleted eSIM from Settings page and saw it removed. Change-Id: Ib40aa8294dd10433b6a68b4f793d8c00ab66d9c0 --- .../SubscriptionManagerService.java | 17 ++++++++ .../SubscriptionManagerServiceTest.java | 41 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 9b871f28d7..e30d61318c 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1027,6 +1027,7 @@ public class SubscriptionManagerService extends ISub.Stub { return; } + Set embeddedSubs = new ArraySet<>(); log("updateEmbeddedSubscriptions: start to get euicc profiles."); for (int cardId : cardIds) { GetEuiccProfileInfoListResult result = mEuiccController @@ -1103,11 +1104,27 @@ public class SubscriptionManagerService extends ISub.Stub { builder.setCardString(mUiccController.convertToCardString(cardId)); } + embeddedSubs.add(subInfo.getSubscriptionId()); subInfo = builder.build(); log("updateEmbeddedSubscriptions: update subscription " + subInfo); mSubscriptionDatabaseManager.updateSubscription(subInfo); } } + + // embeddedSubs contains all the existing embedded subs queried from EuiccManager, + // including active or inactive. If there are any embedded subscription in the database + // that is not in embeddedSubs, mark them as non-embedded. These were deleted embedded + // subscriptions, so we treated them as non-embedded (pre-U behavior) and they don't + // show up in Settings SIM page. + mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isEmbedded) + .filter(subInfo -> !embeddedSubs.contains(subInfo.getSubscriptionId())) + .forEach(subInfo -> { + logl("updateEmbeddedSubscriptions: Mark the deleted sub " + + subInfo.getSubscriptionId() + " as non-embedded."); + mSubscriptionDatabaseManager.setEmbedded( + subInfo.getSubscriptionId(), false); + }); }); log("updateEmbeddedSubscriptions: Finished embedded subscription update."); if (callback != null) { 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 3b7d6b91e6..b1e87ad9a9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -1817,4 +1817,45 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, CALLING_PACKAGE, CALLING_FEATURE)) .isEmpty(); } + + @Test + public void testDeleteEsim() { + // pSIM + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + + EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID1) + .setIccid(FAKE_ICCID1) + .setNickname(FAKE_CARRIER_NAME1) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL) + .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC1, FAKE_MNC1, null, 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(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1)); + + mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); + processAllMessages(); + + // Now we should have two subscriptions in the database. One for pSIM, one for eSIM. + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1).isEmbedded()).isFalse(); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isEmbedded()).isTrue(); + + // Delete the eSIM. blockingGetEuiccProfileInfoList will return an empty list. + result = new GetEuiccProfileInfoListResult( + EuiccService.RESULT_OK, new EuiccProfileInfo[0], false); + doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); + + mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); + processAllMessages(); + + // The original pSIM is still pSIM + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1).isEmbedded()).isFalse(); + // The original eSIM becomes removed pSIM ¯\_(ツ)_/¯ + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isEmbedded()).isFalse(); + } } -- GitLab From 6d9f445536ccb67c90c48bee1b8bd47862db3460 Mon Sep 17 00:00:00 2001 From: virkumar Date: Tue, 14 Feb 2023 10:26:48 +0000 Subject: [PATCH 436/656] Allow of messageRef (TP-MR) increment/save/update logic at Framework based on device config when config_stk_sms_send_support is set to false - modem to manage increment and saving of messageRef(TP-MR) value along with updating value to SIM card. when config_stk_sms_send_support is set to true - framework increments/updates an saves messageRef(TP-MR) value along with updating value to SIM card. Test: Multipart and normal SMS on live NW over CS and IMS, Unit Test. Bug: 265245128 Change-Id: I964189f49205106af1b9aafab8e3e579bc5bf9d4 --- .../internal/telephony/SMSDispatcher.java | 32 +++++++++++++++++-- .../telephony/ImsSmsDispatcherTest.java | 28 +++++++++++++--- .../telephony/gsm/GsmSmsDispatcherTest.java | 12 +++++-- 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 808761b24b..6db35595f3 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -42,6 +42,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; import android.database.ContentObserver; import android.net.Uri; import android.os.AsyncResult; @@ -513,17 +514,42 @@ public abstract class SMSDispatcher extends Handler { } /** - * Returns the next TP message Reference value incremented by 1 for every sms sent . - * once a max of 255 is reached TP message Reference is reset to 0. + * Returns the next TP message Reference value incremented by 1 for every sms sent . + * once a max of 255 is reached TP message Reference is reset to 0. * - * @return messageRef TP message Reference value + * @return messageRef TP message Reference value */ public int nextMessageRef() { + if (!isMessageRefIncrementViaTelephony()) { + return 0; + } + mMessageRef = (mMessageRef + 1) % 256; updateTPMessageReference(); return mMessageRef; } + /** + * As modem is using the last used TP-MR value present in SIM card, increment of + * messageRef(TP-MR) value should be prevented (config_stk_sms_send_support set to false) + * at telephony framework. In future, config_stk_sms_send_support flag will be enabled + * so that messageRef(TP-MR) increment will be done at framework side only. + * + * TODO:- Need to have new flag to control writing TP-MR value to SIM or shared prefrence. + */ + public boolean isMessageRefIncrementViaTelephony() { + boolean isMessageRefIncrementEnabled = false; + try { + isMessageRefIncrementEnabled = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_stk_sms_send_support); + } catch (NotFoundException e) { + Rlog.e(TAG, "isMessageRefIncrementViaTelephony NotFoundException Exception"); + } + + Rlog.i(TAG, "bool.config_stk_sms_send_support= " + isMessageRefIncrementEnabled); + return isMessageRefIncrementEnabled; + } + /** * Use the carrier messaging service to send a data or text SMS. */ diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java index f9cac53659..1c44772d88 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSmsDispatcherTest.java @@ -322,7 +322,10 @@ public class ImsSmsDispatcherTest extends TelephonyTest { @Test public void testSendSmswithMessageRef() throws Exception { int token = mImsSmsDispatcher.mNextToken.get(); - int messageRef = mImsSmsDispatcher.nextMessageRef() + 1; + int messageRef = mImsSmsDispatcher.nextMessageRef(); + if (mImsSmsDispatcher.isMessageRefIncrementViaTelephony()) { + messageRef += 1; + } when(mImsManager.getSmsFormat()).thenReturn(SmsMessage.FORMAT_3GPP); when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM); @@ -338,7 +341,10 @@ public class ImsSmsDispatcherTest extends TelephonyTest { @Test public void testFallbackGsmRetrywithMessageRef() throws Exception { int token = mImsSmsDispatcher.mNextToken.get(); - int messageRef = mImsSmsDispatcher.nextMessageRef() + 1; + int messageRef = mImsSmsDispatcher.nextMessageRef(); + if (mImsSmsDispatcher.isMessageRefIncrementViaTelephony()) { + messageRef += 1; + } when(mImsManager.getSmsFormat()).thenReturn(SmsMessage.FORMAT_3GPP); when(mPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_GSM); @@ -357,13 +363,21 @@ public class ImsSmsDispatcherTest extends TelephonyTest { ArgumentCaptor captor = ArgumentCaptor.forClass(SMSDispatcher.SmsTracker.class); verify(mSmsDispatchersController).sendRetrySms(captor.capture()); - assertTrue(messageRef + 1 == captor.getValue().mMessageRef); + if (mImsSmsDispatcher.isMessageRefIncrementViaTelephony()) { + assertTrue(messageRef + 1 == captor.getValue().mMessageRef); + } else { + assertTrue(messageRef == captor.getValue().mMessageRef); + } } @Test public void testErrorImsRetrywithMessageRef() throws Exception { int token = mImsSmsDispatcher.mNextToken.get(); - int messageRef = mImsSmsDispatcher.nextMessageRef() + 1; + int messageRef = mImsSmsDispatcher.nextMessageRef(); + if (mImsSmsDispatcher.isMessageRefIncrementViaTelephony()) { + messageRef += 1; + } + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms .KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT, 2000); @@ -399,7 +413,11 @@ public class ImsSmsDispatcherTest extends TelephonyTest { @Test public void testErrorImsRetrywithRetryConfig() throws Exception { int token = mImsSmsDispatcher.mNextToken.get(); - int messageRef = mImsSmsDispatcher.nextMessageRef() + 1; + int messageRef = mImsSmsDispatcher.nextMessageRef(); + if (mImsSmsDispatcher.isMessageRefIncrementViaTelephony()) { + messageRef += 1; + } + mContextFixture.getCarrierConfigBundle().putInt(CarrierConfigManager.ImsSms .KEY_SMS_OVER_IMS_SEND_RETRY_DELAY_MILLIS_INT, 3000); diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java index 523c9bb78d..53f42e9b3f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java @@ -519,7 +519,11 @@ public class GsmSmsDispatcherTest extends TelephonyTest { @Test public void testSendTextWithMessageRef() throws Exception { - int messageRef = mGsmSmsDispatcher.nextMessageRef() + 1; + int messageRef = mGsmSmsDispatcher.nextMessageRef(); + if (mGsmSmsDispatcher.isMessageRefIncrementViaTelephony()) { + messageRef += 1; + } + mGsmSmsDispatcher.sendText("111", "222" /*scAddr*/, TAG, null, null, null, null, false, -1, false, -1, false, 0L); @@ -536,7 +540,11 @@ public class GsmSmsDispatcherTest extends TelephonyTest { parts.add("segment1"); parts.add("segment2"); parts.add("segment3"); - int messageRef = mGsmSmsDispatcher.nextMessageRef() + parts.size(); + + int messageRef = mGsmSmsDispatcher.nextMessageRef(); + if (mGsmSmsDispatcher.isMessageRefIncrementViaTelephony()) { + messageRef += parts.size(); + } mGsmSmsDispatcher.sendMultipartText("6501002000" /*destAddr*/, "222" /*scAddr*/, parts, null, null, null, null, false, -1, false, -1, 0L); waitForMs(150); -- GitLab From b2edd25ca0edc113ee1bac4f1cda33075330b3d3 Mon Sep 17 00:00:00 2001 From: Sungcheol Ahn Date: Wed, 15 Feb 2023 04:37:27 +0000 Subject: [PATCH 437/656] Make Emergency call notification not swipeable Make the emergency call notification not swipeable. For Emergency call notification, it will not be dismissed from the swipe like Clear All button. Note TCD-BEAR-REQ-012296(VF spec R04-2023) - Customers get a notification windows every time the UE contacts the ePDG. Bug: b/267650444 Test: manual Change-Id: Ia5ca001ce73e226628d4d46493017d13de024406 --- .../android/internal/telephony/CarrierServiceStateTracker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java index 9fa26cca7d..a5780aefd3 100644 --- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java @@ -591,7 +591,7 @@ public class CarrierServiceStateTracker extends Handler { .setContentTitle(title) .setStyle(new Notification.BigTextStyle().bigText(details)) .setContentText(details) - .setFlag(Notification.FLAG_NO_CLEAR, true) + .setOngoing(true) .setChannelId(NotificationChannelController.CHANNEL_ID_WFC); } } -- GitLab From af43adb2273209457ad0b48cd1add3aa8c43b584 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 15 Feb 2023 12:16:40 -0800 Subject: [PATCH 438/656] Added log to print slot/sub mapping Fix: 269493080 Test: Boot up and exam bugreport Change-Id: Idc002e211ed40165e0bfb817c95279a8fcfdb10c --- .../SubscriptionManagerService.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 9b871f28d7..0049696894 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -926,6 +926,7 @@ public class SubscriptionManagerService extends ISub.Stub { mSlotIndexToSubId.remove(simSlotIndex); }); updateGroupDisabled(); + logl("markSubscriptionsInactive: " + slotMappingToString()); } /** @@ -1272,6 +1273,7 @@ public class SubscriptionManagerService extends ISub.Stub { mSlotIndexToSubId.put(phoneId, subId); // Update the SIM slot index. This will make the subscription active. mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId); + logl("updateSubscriptions: " + slotMappingToString()); } // Update the card id. @@ -1348,6 +1350,7 @@ public class SubscriptionManagerService extends ISub.Stub { } else { log("updateSubscriptions: No ICCID available for phone " + phoneId); mSlotIndexToSubId.remove(phoneId); + logl("updateSubscriptions: " + slotMappingToString()); } if (areAllSubscriptionsLoaded()) { @@ -1914,6 +1917,7 @@ public class SubscriptionManagerService extends ISub.Stub { int subId = insertSubscriptionInfo(iccId, slotIndex, displayName, subscriptionType); updateGroupDisabled(); mSlotIndexToSubId.put(slotIndex, subId); + logl("addSubInfo: " + slotMappingToString()); } else { // Record already exists. loge("Subscription record already existed."); @@ -3811,6 +3815,16 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * @return The logical SIM slot/sub mapping to string. + */ + @NonNull + private String slotMappingToString() { + return mSlotIndexToSubId.entrySet().stream() + .map(e -> "Slot " + e.getKey() + ": subId=" + e.getValue()) + .collect(Collectors.joining(", ")); + } + /** * Log debug messages. * @@ -3865,6 +3879,12 @@ public class SubscriptionManagerService extends ISub.Stub { mSlotIndexToSubId.forEach((slotIndex, subId) -> pw.println("Logical SIM slot " + slotIndex + ": subId=" + subId)); pw.decreaseIndent(); + pw.println("ICCID:"); + pw.increaseIndent(); + for (int i = 0; i < mTelephonyManager.getActiveModemCount(); i++) { + pw.println("slot " + i + ": " + getIccId(i)); + } + pw.decreaseIndent(); pw.println(); pw.println("defaultSubId=" + getDefaultSubId()); pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId()); -- GitLab From fe9e15875227727fb6b893bd98789af3d4662fb0 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 15 Feb 2023 01:58:53 -0800 Subject: [PATCH 439/656] Send requests and return responses from satellite service Create helper methods in SatelliteServiceController that will send requests and responses between the caller and the satellite service. Also resolve pending comments from previous CLs. Test: atest SatelliteManagerTest Bug: 261131816 Change-Id: I3daead22ee82e0da9cbaf55e1473740953499619 --- .../satellite/SatelliteServiceController.java | 694 +++++++++++++++++- 1 file changed, 689 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java index 3121dea8ed..21e820f8fd 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java @@ -22,14 +22,30 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.os.AsyncResult; +import android.os.Binder; import android.os.IBinder; import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; import android.telephony.Rlog; +import android.telephony.satellite.SatelliteCapabilities; +import android.telephony.satellite.SatelliteDatagram; +import android.telephony.satellite.SatelliteManager; +import android.telephony.satellite.SatelliteManager.SatelliteException; import android.telephony.satellite.stub.ISatellite; +import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer; +import android.telephony.satellite.stub.SatelliteError; +import android.telephony.satellite.stub.SatelliteModemState; import android.telephony.satellite.stub.SatelliteService; import android.text.TextUtils; import com.android.internal.telephony.ExponentialBackoff; +import com.android.internal.telephony.IBooleanConsumer; +import com.android.internal.telephony.IIntegerConsumer; + +import java.util.Arrays; +import java.util.stream.Collectors; /** * Satellite service controller to manage connections with the satellite service. @@ -47,6 +63,7 @@ public class SatelliteServiceController { @Nullable private ISatellite mSatelliteService; @Nullable private SatelliteServiceConnection mSatelliteServiceConnection; private boolean mIsBound; + private boolean mIsBinding; /** * @return The singleton instance of SatelliteServiceController. @@ -79,11 +96,18 @@ public class SatelliteServiceController { mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, REBIND_MULTIPLIER, looper, () -> { synchronized (mLock) { - if (mIsBound) { + if ((mIsBound && mSatelliteService != null) || mIsBinding) { return; } - bindService(); } + if (mSatelliteServiceConnection != null) { + synchronized (mLock) { + mIsBound = false; + mIsBinding = false; + } + unbindService(); + } + bindService(); }); mExponentialBackoff.start(); logd("Created SatelliteServiceController. Attempting to bind to SatelliteService."); @@ -105,11 +129,18 @@ public class SatelliteServiceController { } private void bindService() { + synchronized (mLock) { + if (mIsBinding || mIsBound) return; + mIsBinding = true; + } String packageName = getSatellitePackageName(); if (TextUtils.isEmpty(packageName)) { loge("Unable to bind to the satellite service because the package is undefined."); // Since the package name comes from static device configs, stop retry because // rebind will continue to fail without a valid package name. + synchronized (mLock) { + mIsBinding = false; + } mExponentialBackoff.stop(); return; } @@ -123,11 +154,17 @@ public class SatelliteServiceController { if (success) { logd("Successfully bound to the satellite service."); } else { + synchronized (mLock) { + mIsBinding = false; + } mExponentialBackoff.notifyFailed(); loge("Error binding to the satellite service. Retrying in " + mExponentialBackoff.getCurrentDelay() + " ms."); } } catch (Exception e) { + synchronized (mLock) { + mIsBinding = false; + } mExponentialBackoff.notifyFailed(); loge("Exception binding to the satellite service. Retrying in " + mExponentialBackoff.getCurrentDelay() + " ms. Exception: " + e); @@ -135,12 +172,12 @@ public class SatelliteServiceController { } private void unbindService() { - resetService(); + disconnectSatelliteService(); mContext.unbindService(mSatelliteServiceConnection); mSatelliteServiceConnection = null; } - private void resetService() { + private void disconnectSatelliteService() { // TODO: clean up any listeners and return failed for pending callbacks mSatelliteService = null; } @@ -151,6 +188,7 @@ public class SatelliteServiceController { logd("onServiceConnected: ComponentName=" + name); synchronized (mLock) { mIsBound = true; + mIsBinding = false; } mSatelliteService = ISatellite.Stub.asInterface(service); mExponentialBackoff.stop(); @@ -160,8 +198,11 @@ public class SatelliteServiceController { @Override public void onServiceDisconnected(ComponentName name) { loge("onServiceDisconnected: Waiting for reconnect."); + synchronized (mLock) { + mIsBinding = false; + } // Since we are still technically bound, clear the service and wait for reconnect. - resetService(); + disconnectSatelliteService(); } @Override @@ -169,12 +210,655 @@ public class SatelliteServiceController { loge("onBindingDied: Unbinding and rebinding service."); synchronized (mLock) { mIsBound = false; + mIsBinding = false; } unbindService(); mExponentialBackoff.start(); } } + /** + * Register the callback interface with satellite service. + * + * @param message The Message to send to result of the operation to. + */ + public void setSatelliteListener(@NonNull Message message) { + // TODO: implement and add listener to param + } + + /** + * Enable or disable the satellite service listening mode. + * Listening mode allows the satellite service to listen for incoming pages. + * + * @param enable True to enable satellite listening mode and false to disable. + * @param message The Message to send to result of the operation to. + */ + public void setSatelliteListeningEnabled(boolean enable, @NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.setSatelliteListeningEnabled(enable, new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("setSatelliteListeningEnabled: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("setSatelliteListeningEnabled: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("setSatelliteListeningEnabled: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Request to enable or disable the satellite modem. If the satellite modem is enabled, + * this will also disable the cellular modem, and if the satellite modem is disabled, + * this will also re-enable the cellular modem. + * + * @param enable True to enable the satellite modem and false to disable. + * @param message The Message to send to result of the operation to. + */ + public void requestSatelliteEnabled(boolean enable, @NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestSatelliteEnabled(enable, new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("setSatelliteEnabled: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("setSatelliteEnabled: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("setSatelliteEnabled: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Request to get whether the satellite modem is enabled. + * + * @param message The Message to send to result of the operation to. + */ + public void requestIsSatelliteEnabled(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestIsSatelliteEnabled(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("requestIsSatelliteEnabled: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }, new IBooleanConsumer.Stub() { + @Override + public void accept(boolean result) { + // Convert for compatibility with SatelliteResponse + // TODO: This should just report result instead. + int[] enabled = new int[] {result ? 1 : 0}; + logd("requestIsSatelliteEnabled: " + Arrays.toString(enabled)); + Binder.withCleanCallingIdentity(() -> sendMessageWithResult( + message, enabled, SatelliteManager.SATELLITE_ERROR_NONE)); + } + }); + } catch (RemoteException e) { + loge("requestIsSatelliteEnabled: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("requestIsSatelliteEnabled: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Request to get whether the satellite service is supported on the device. + * + * @param message The Message to send to result of the operation to. + */ + public void requestIsSatelliteSupported(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestIsSatelliteSupported(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("requestIsSatelliteSupported: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }, new IBooleanConsumer.Stub() { + @Override + public void accept(boolean result) { + // Convert for compatibility with SatelliteResponse + // TODO: This should just report result instead. + int[] supported = new int[] {result ? 1 : 0}; + logd("requestIsSatelliteSupported: " + Arrays.toString(supported)); + Binder.withCleanCallingIdentity(() -> sendMessageWithResult( + message, supported, SatelliteManager.SATELLITE_ERROR_NONE)); + } + }); + } catch (RemoteException e) { + loge("requestIsSatelliteSupported: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("requestIsSatelliteSupported: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Request to get the SatelliteCapabilities of the satellite service. + * + * @param message The Message to send to result of the operation to. + */ + public void requestSatelliteCapabilities(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestSatelliteCapabilities(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("requestSatelliteCapabilities: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }, new ISatelliteCapabilitiesConsumer.Stub() { + @Override + public void accept(android.telephony.satellite.stub.SatelliteCapabilities + result) { + SatelliteCapabilities capabilities = fromSatelliteCapabilities(result); + logd("requestSatelliteCapabilities: " + capabilities); + Binder.withCleanCallingIdentity(() -> sendMessageWithResult( + message, capabilities, SatelliteManager.SATELLITE_ERROR_NONE)); + } + }); + } catch (RemoteException e) { + loge("requestSatelliteCapabilities: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("requestSatelliteCapabilities: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * User started pointing to the satellite. + * The satellite service should report the satellite pointing info via + * ISatelliteListener#onSatellitePointingInfoChanged as the user device/satellite moves. + * + * @param message The Message to send to result of the operation to. + */ + public void startSendingSatellitePointingInfo(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.startSendingSatellitePointingInfo(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("startSendingSatellitePointingInfo: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("startSendingSatellitePointingInfo: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("startSendingSatellitePointingInfo: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * User stopped pointing to the satellite. + * The satellite service should stop reporting satellite pointing info to the framework. + * + * @param message The Message to send to result of the operation to. + */ + public void stopSendingSatellitePointingInfo(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.stopSendingSatellitePointingInfo(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("stopSendingSatellitePointingInfo: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("stopSendingSatellitePointingInfo: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("stopSendingSatellitePointingInfo: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Request to get the maximum number of characters per MO text message on satellite. + * + * @param message The Message to send to result of the operation to. + */ + public void requestMaxCharactersPerMOTextMessage(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestMaxCharactersPerMOTextMessage(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("requestMaxCharactersPerMOTextMessage: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }, new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + // Convert for compatibility with SatelliteResponse + // TODO: This should just report result instead. + int[] maxCharacters = new int[] {result}; + logd("requestMaxCharactersPerMOTextMessage: " + + Arrays.toString(maxCharacters)); + Binder.withCleanCallingIdentity(() -> sendMessageWithResult( + message, maxCharacters, SatelliteManager.SATELLITE_ERROR_NONE)); + } + }); + } catch (RemoteException e) { + loge("requestMaxCharactersPerMOTextMessage: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("requestMaxCharactersPerMOTextMessage: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Provision the device with a satellite provider. + * This is needed if the provider allows dynamic registration. + * Once provisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report true. + * + * @param token The token to be used as a unique identifier for provisioning with satellite + * gateway. + * @param message The Message to send to result of the operation to. + */ + public void provisionSatelliteService(@NonNull String token, @NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.provisionSatelliteService(token, new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("provisionSatelliteService: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("provisionSatelliteService: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("provisionSatelliteService: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Deprovision the device with the satellite provider. + * This is needed if the provider allows dynamic registration. + * Once deprovisioned, ISatelliteListener#onSatelliteProvisionStateChanged should report false. + * + * @param token The token of the device/subscription to be deprovisioned. + * @param message The Message to send to result of the operation to. + */ + public void deprovisionSatelliteService(@NonNull String token, @NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.deprovisionSatelliteService(token, new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("deprovisionSatelliteService: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("deprovisionSatelliteService: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("deprovisionSatelliteService: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Request to get whether this device is provisioned with a satellite provider. + * + * @param message The Message to send to result of the operation to. + */ + public void requestIsSatelliteProvisioned(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestIsSatelliteProvisioned(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("requestIsSatelliteProvisioned: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }, new IBooleanConsumer.Stub() { + @Override + public void accept(boolean result) { + // Convert for compatibility with SatelliteResponse + // TODO: This should just report result instead. + int[] provisioned = new int[] {result ? 1 : 0}; + logd("requestIsSatelliteProvisioned: " + Arrays.toString(provisioned)); + Binder.withCleanCallingIdentity(() -> sendMessageWithResult( + message, provisioned, SatelliteManager.SATELLITE_ERROR_NONE)); + } + }); + } catch (RemoteException e) { + loge("requestIsSatelliteProvisioned: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("requestIsSatelliteProvisioned: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Poll the pending datagrams. + * The satellite service should report the new datagrams via ISatelliteListener#onNewDatagrams. + * + * @param message The Message to send to result of the operation to. + */ + public void pollPendingSatelliteDatagrams(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.pollPendingSatelliteDatagrams(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("pollPendingSatelliteDatagrams: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("pollPendingSatelliteDatagrams: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("pollPendingSatelliteDatagrams: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Send datagram over satellite. + * Once sent, the satellite service should report whether the operation was successful via + * SatelliteListener#onDatagramsDelivered. + * + * @param datagram Datagram to send in byte format. + * @param isEmergency Whether this is an emergency datagram. + * @param message The Message to send to result of the operation to. + */ + public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency, + @NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.sendSatelliteDatagram(toSatelliteDatagram(datagram), isEmergency, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("sendSatelliteDatagram: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); + } catch (RemoteException e) { + loge("sendSatelliteDatagram: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("sendSatelliteDatagram: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Request the current satellite modem state. + * The satellite service should report the current satellite modem state via + * ISatelliteListener#onSatelliteModemStateChanged. + * + * @param message The Message to send to result of the operation to. + */ + public void requestSatelliteModemState(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestSatelliteModemState(new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("requestSatelliteModemState: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }, new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + // Convert SatelliteModemState from service to frameworks definition. + int modemState = fromSatelliteModemState(result); + logd("requestSatelliteModemState: " + modemState); + Binder.withCleanCallingIdentity(() -> sendMessageWithResult( + message, modemState, SatelliteManager.SATELLITE_ERROR_NONE)); + } + }); + } catch (RemoteException e) { + loge("requestSatelliteModemState: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("requestSatelliteModemState: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Request to get whether satellite communication is allowed for the current location. + * + * @param message The Message to send to result of the operation to. + */ + public void requestIsSatelliteCommunicationAllowedForCurrentLocation(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestIsSatelliteCommunicationAllowedForCurrentLocation( + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("requestIsSatelliteCommunicationAllowedForCurrentLocation: " + + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }, new IBooleanConsumer.Stub() { + @Override + public void accept(boolean result) { + // Convert for compatibility with SatelliteResponse + // TODO: This should just report result instead. + int[] allowed = new int[] {result ? 1 : 0}; + logd("requestIsSatelliteCommunicationAllowedForCurrentLocation: " + + Arrays.toString(allowed)); + Binder.withCleanCallingIdentity(() -> sendMessageWithResult( + message, allowed, SatelliteManager.SATELLITE_ERROR_NONE)); + } + }); + } catch (RemoteException e) { + loge("requestIsSatelliteCommunicationAllowedForCurrentLocation: RemoteException " + + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("requestIsSatelliteCommunicationAllowedForCurrentLocation: " + + "Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + /** + * Request to get the time after which the satellite will be visible. This is an int + * representing the duration in seconds after which the satellite will be visible. + * This will return 0 if the satellite is currently visible. + * + * @param message The Message to send to result of the operation to. + */ + public void requestTimeForNextSatelliteVisibility(@NonNull Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.requestTimeForNextSatelliteVisibility( + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = fromSatelliteError(result); + logd("requestTimeForNextSatelliteVisibility: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }, new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + // Convert for compatibility with SatelliteResponse + // TODO: This should just report result instead. + int[] time = new int[] {result}; + logd("requestTimeForNextSatelliteVisibility: " + + Arrays.toString(time)); + Binder.withCleanCallingIdentity(() -> sendMessageWithResult( + message, time, SatelliteManager.SATELLITE_ERROR_NONE)); + } + }); + } catch (RemoteException e) { + loge("requestTimeForNextSatelliteVisibility: RemoteException " + e); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } else { + loge("requestTimeForNextSatelliteVisibility: Satellite service is unavailable."); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } + } + + private static void sendMessageWithResult(@NonNull Message message, @Nullable Object result, + @SatelliteManager.SatelliteError int error) { + AsyncResult.forMessage(message, result, new SatelliteException(error)); + message.sendToTarget(); + } + + @SatelliteManager.SatelliteError private static int fromSatelliteError(int error) { + switch (error) { + case SatelliteError.ERROR_NONE: + return SatelliteManager.SATELLITE_ERROR_NONE; + case SatelliteError.SATELLITE_ERROR: + return SatelliteManager.SATELLITE_ERROR; + case SatelliteError.SERVER_ERROR: + return SatelliteManager.SATELLITE_SERVER_ERROR; + case SatelliteError.SERVICE_ERROR: + return SatelliteManager.SATELLITE_SERVICE_ERROR; + case SatelliteError.MODEM_ERROR: + return SatelliteManager.SATELLITE_MODEM_ERROR; + case SatelliteError.NETWORK_ERROR: + return SatelliteManager.SATELLITE_NETWORK_ERROR; + case SatelliteError.INVALID_TELEPHONY_STATE: + return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + case SatelliteError.INVALID_MODEM_STATE: + return SatelliteManager.SATELLITE_INVALID_MODEM_STATE; + case SatelliteError.INVALID_ARGUMENTS: + return SatelliteManager.SATELLITE_INVALID_ARGUMENTS; + case SatelliteError.REQUEST_FAILED: + return SatelliteManager.SATELLITE_REQUEST_FAILED; + case SatelliteError.RADIO_NOT_AVAILABLE: + return SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE; + case SatelliteError.REQUEST_NOT_SUPPORTED: + return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED; + case SatelliteError.NO_RESOURCES: + return SatelliteManager.SATELLITE_NO_RESOURCES; + case SatelliteError.SERVICE_NOT_PROVISIONED: + return SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED; + case SatelliteError.SERVICE_PROVISION_IN_PROGRESS: + return SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS; + case SatelliteError.REQUEST_ABORTED: + return SatelliteManager.SATELLITE_REQUEST_ABORTED; + case SatelliteError.SATELLITE_ACCESS_BARRED: + return SatelliteManager.SATELLITE_ACCESS_BARRED; + case SatelliteError.NETWORK_TIMEOUT: + return SatelliteManager.SATELLITE_NETWORK_TIMEOUT; + case SatelliteError.SATELLITE_NOT_REACHABLE: + return SatelliteManager.SATELLITE_NOT_REACHABLE; + case SatelliteError.NOT_AUTHORIZED: + return SatelliteManager.SATELLITE_NOT_AUTHORIZED; + } + loge("Received invalid satellite service error: " + error); + return SatelliteManager.SATELLITE_SERVICE_ERROR; + } + + @SatelliteManager.SatelliteModemState private static int fromSatelliteModemState( + int modemState) { + switch (modemState) { + case SatelliteModemState.SATELLITE_MODEM_STATE_IDLE: + return SatelliteManager.SATELLITE_MODEM_STATE_IDLE; + case SatelliteModemState.SATELLITE_MODEM_STATE_LISTENING: + return SatelliteManager.SATELLITE_MODEM_STATE_LISTENING; + case SatelliteModemState.SATELLITE_MODEM_STATE_MESSAGE_TRANSFERRING: + return SatelliteManager.SATELLITE_MODEM_STATE_MESSAGE_TRANSFERRING; + case SatelliteModemState.SATELLITE_MODEM_STATE_OFF: + return SatelliteManager.SATELLITE_MODEM_STATE_OFF; + } + // TODO: create and return SATELLITE_MODEM_STATE_UNKNOWN + loge("Received invalid modem state: " + modemState); + return SatelliteManager.SATELLITE_MODEM_STATE_OFF; + } + + @Nullable private static SatelliteCapabilities fromSatelliteCapabilities( + @Nullable android.telephony.satellite.stub.SatelliteCapabilities capabilities) { + if (capabilities == null) return null; + return new SatelliteCapabilities( + Arrays.stream(capabilities.supportedRadioTechnologies) + .boxed().collect(Collectors.toSet()), + capabilities.isAlwaysOn, + capabilities.needsPointingToSatellite, + capabilities.needsSeparateSimProfile); + } + + @Nullable private static android.telephony.satellite.stub.SatelliteDatagram toSatelliteDatagram( + @Nullable SatelliteDatagram datagram) { + android.telephony.satellite.stub.SatelliteDatagram converted = + new android.telephony.satellite.stub.SatelliteDatagram(); + converted.data = datagram.getSatelliteDatagram(); + return converted; + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } -- GitLab From b7378c4f907f2b87a23900ebc1885f67c2040153 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Wed, 15 Feb 2023 16:37:04 -0800 Subject: [PATCH 440/656] Rename some satellite APIs Bug: 269334950 Test: atest android.telephony.cts.SatelliteManagerTest Change-Id: Ia09453c84a1788d56048f7faa33216db50cf0c46 --- src/java/com/android/internal/telephony/Phone.java | 10 ++++++---- .../satellite/SatelliteServiceController.java | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 4a715b558d..e962b20eb8 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5334,23 +5334,25 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * Registers for messages transfer complete from satellite modem. + * Registers for datagrams delivered events from satellite modem. * * @param h Handler for notification message. * @param what User-defined message code. * @param obj User object. */ - public void registerForSatelliteMessagesTransferComplete(@NonNull Handler h, + public void registerForSatelliteDatagramsDelivered(@NonNull Handler h, int what, @Nullable Object obj) { + //TODO: Rename CommandsInterface and other modules when updating HAL APIs. mCi.registerForSatelliteMessagesTransferComplete(h, what, obj); } /** - * Unregisters for messages transfer complete from satellite modem. + * Unregisters for datagrams delivered events from satellite modem. * * @param h Handler to be removed from the registrant list. */ - public void unregisterForSatelliteMessagesTransferComplete(@NonNull Handler h) { + public void unregisterForSatelliteDatagramsDelivered(@NonNull Handler h) { + //TODO: Rename CommandsInterface and other modules when updating HAL APIs. mCi.unregisterForSatelliteMessagesTransferComplete(h); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java index 21e820f8fd..7978be69f9 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java @@ -831,7 +831,7 @@ public class SatelliteServiceController { case SatelliteModemState.SATELLITE_MODEM_STATE_LISTENING: return SatelliteManager.SATELLITE_MODEM_STATE_LISTENING; case SatelliteModemState.SATELLITE_MODEM_STATE_MESSAGE_TRANSFERRING: - return SatelliteManager.SATELLITE_MODEM_STATE_MESSAGE_TRANSFERRING; + return SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; case SatelliteModemState.SATELLITE_MODEM_STATE_OFF: return SatelliteManager.SATELLITE_MODEM_STATE_OFF; } -- GitLab From d3ea82ea765ba2aa18a41cc31c0f8dd2639fa7bb Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Wed, 15 Feb 2023 21:14:07 +0000 Subject: [PATCH 441/656] print redacted iccid, eid in user build only Also add additional log info for debugging purpose. Bug: 268997052 Test: Manual verification of log Change-Id: Ie7a7ec04e82ce728342ff883409b7b0f26defdac --- .../internal/telephony/SubscriptionController.java | 6 ++++-- .../internal/telephony/SubscriptionInfoUpdater.java | 3 ++- .../subscription/SubscriptionManagerService.java | 2 +- .../internal/telephony/uicc/IccSimPortInfo.java | 5 ++++- .../android/internal/telephony/uicc/UiccCard.java | 3 ++- .../internal/telephony/uicc/UiccController.java | 13 ++++++++++++- .../android/internal/telephony/uicc/UiccPort.java | 2 ++ .../android/internal/telephony/uicc/UiccSlot.java | 2 +- 8 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index d359eafcf1..e886742343 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -828,13 +828,15 @@ public class SubscriptionController extends ISub.Stub { if (iccId.equals(si.getIccId())) { if (DBG) logd("[getActiveSubInfoUsingIccId]+ iccId=" - + Rlog.pii(LOG_TAG, iccId) + " subInfo=" + si); + + SubscriptionInfo.givePrintableIccid(iccId) + + " subInfo=" + si); return si; } } } if (DBG) { - logd("[getActiveSubInfoUsingIccId]+ iccId=" + Rlog.pii(LOG_TAG, iccId) + logd("[getActiveSubInfoUsingIccId]+ iccId=" + + SubscriptionInfo.givePrintableIccid(iccId) + " subList=" + subList + " subInfo=null"); } } finally { diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index 95144fdd9d..3b0c822419 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -852,7 +852,8 @@ public class SubscriptionInfoUpdater extends Handler { // If SIM is not absent, insert new record or update existing record. if (!ICCID_STRING_FOR_NO_SIM.equals(sIccId[phoneId]) && sIccId[phoneId] != null) { logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: " - + Rlog.pii(LOG_TAG, sIccId[phoneId]) + ", phoneId:" + phoneId); + + SubscriptionInfo.givePrintableIccid(sIccId[phoneId]) + + ", phoneId:" + phoneId); mSubscriptionManager.addSubscriptionInfoRecord(sIccId[phoneId], phoneId); } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 082472464a..04494e25ea 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -3899,7 +3899,7 @@ public class SubscriptionManagerService extends ISub.Stub { pw.println("ICCID:"); pw.increaseIndent(); for (int i = 0; i < mTelephonyManager.getActiveModemCount(); i++) { - pw.println("slot " + i + ": " + getIccId(i)); + pw.println("slot " + i + ": " + SubscriptionInfo.givePrintableIccid(getIccId(i))); } pw.decreaseIndent(); pw.println(); diff --git a/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java b/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java index 7197fc8f23..9a5e10d984 100644 --- a/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java +++ b/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.uicc; +import android.telephony.SubscriptionInfo; import android.text.TextUtils; import java.util.Objects; @@ -49,7 +50,9 @@ public class IccSimPortInfo { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("{").append("logicalSlotIndex=").append(mLogicalSlotIndex).append(",") + sb.append("{").append("iccid=") + .append(SubscriptionInfo.givePrintableIccid(mIccId)).append(",") + .append("logicalSlotIndex=").append(mLogicalSlotIndex).append(",") .append("portActive=").append(mPortActive) .append("}"); return sb.toString(); diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java index 67f120fd54..7459e729fd 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCard.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java @@ -27,6 +27,7 @@ import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.IccSlotStatus.MultipleEnabledProfilesMode; import com.android.internal.telephony.uicc.euicc.EuiccCard; import com.android.internal.telephony.uicc.euicc.EuiccPort; +import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -221,7 +222,7 @@ public class UiccCard { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("UiccCard:"); pw.println(" mCardState=" + mCardState); - pw.println(" mCardId=" + Rlog.pii(LOG_TAG, mCardId)); + pw.println(" mCardId=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mCardId)); pw.println(" mNumberOfPorts=" + mUiccPorts.size()); pw.println( "mIsSupportsMultipleEnabledProfiles=" + mIsSupportsMultipleEnabledProfiles); pw.println(); diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 4d87a3f18c..98c22a5547 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -40,6 +40,7 @@ import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.SimState; @@ -67,6 +68,7 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.euicc.EuiccCard; +import com.android.internal.telephony.util.ArrayUtils; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -76,6 +78,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import java.util.stream.IntStream; /** @@ -1791,6 +1794,14 @@ public class UiccController extends Handler { sLocalLog.log(data); } + private List getPrintableCardStrings() { + if (!ArrayUtils.isEmpty(mCardStrings)) { + return mCardStrings.stream().map(SubscriptionInfo::givePrintableIccid).collect( + Collectors.toList()); + } + return mCardStrings; + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("UiccController: " + this); pw.println(" mContext=" + mContext); @@ -1805,7 +1816,7 @@ public class UiccController extends Handler { pw.println(" mIsCdmaSupported=" + isCdmaSupported(mContext)); pw.println(" mHasBuiltInEuicc=" + mHasBuiltInEuicc); pw.println(" mHasActiveBuiltInEuicc=" + mHasActiveBuiltInEuicc); - pw.println(" mCardStrings=" + Rlog.pii(LOG_TAG, mCardStrings)); + pw.println(" mCardStrings=" + getPrintableCardStrings()); pw.println(" mDefaultEuiccCardId=" + mDefaultEuiccCardId); pw.println(" mPhoneIdToSlotId=" + Arrays.toString(mPhoneIdToSlotId)); pw.println(" mUseRemovableEsimAsDefault=" + mUseRemovableEsimAsDefault); diff --git a/src/java/com/android/internal/telephony/uicc/UiccPort.java b/src/java/com/android/internal/telephony/uicc/UiccPort.java index ab00cab33f..0152dda088 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccPort.java +++ b/src/java/com/android/internal/telephony/uicc/UiccPort.java @@ -21,6 +21,7 @@ import android.content.Context; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; +import android.telephony.SubscriptionInfo; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -362,6 +363,7 @@ public class UiccPort { pw.println(" this=" + this); pw.println(" mPortIdx=" + mPortIdx); pw.println(" mCi=" + mCi); + pw.println(" mIccid=" + SubscriptionInfo.givePrintableIccid(mIccid)); pw.println(" mPhoneId=" + mPhoneId); pw.println(" mPhysicalSlotIndex=" + mPhysicalSlotIndex); synchronized (mOpenChannelRecords) { diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index a49a7d3c24..62971d252c 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -666,7 +666,7 @@ public class UiccSlot extends Handler { + isMultipleEnabledProfileSupported()); pw.println(" mIsRemovable=" + mIsRemovable); pw.println(" mLastRadioState=" + mLastRadioState); - pw.println(" mIccIds=" + Rlog.pii(TAG, getPrintableIccIds())); + pw.println(" mIccIds=" + getPrintableIccIds()); pw.println(" mPortIdxToPhoneId=" + mPortIdxToPhoneId); pw.println(" mEid=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mEid)); pw.println(" mCardState=" + mCardState); -- GitLab From 55ad74c1786d91fbd00b003c8bd5c9ee93bbe0f4 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 16 Feb 2023 01:45:43 -0800 Subject: [PATCH 442/656] Fixed eSIM switch issue When switching between eSIM profile, there will not be SIM absent event. We need to mark the previous active subscription inactive to prevent both old and new subscriptions active. Fix: 269429990 Test: atest SubscriptionManagerServiceTest Test: Basic phone functionality test Change-Id: I9ca6562659a426dbf5ba324118b9f4bb14512f3b --- .../SubscriptionDatabaseManager.java | 3 + .../SubscriptionManagerService.java | 14 +++- .../SubscriptionDatabaseManagerTest.java | 2 + .../SubscriptionManagerServiceTest.java | 65 ++++++++++++++++--- 4 files changed, 73 insertions(+), 11 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 99fb3432b5..2e5b9b6385 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -729,6 +729,7 @@ public class SubscriptionDatabaseManager extends Handler { if (uri != null && uri.getLastPathSegment() != null) { int subId = Integer.parseInt(uri.getLastPathSegment()); if (SubscriptionManager.isValidSubscriptionId(subId)) { + logv("insertNewRecordIntoDatabaseSync: contentValues=" + contentValues); logl("insertNewRecordIntoDatabaseSync: Successfully added subscription. subId=" + uri.getLastPathSegment()); return subId; @@ -1836,6 +1837,8 @@ public class SubscriptionDatabaseManager extends Handler { logl("Loaded " + mAllSubscriptionInfoInternalCache.size() + " records from the subscription database."); + mAllSubscriptionInfoInternalCache.forEach( + (subId, subInfo) -> log(" " + subInfo.toString())); } finally { mReadWriteLock.writeLock().unlock(); } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 082472464a..8bf03aa1af 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -923,7 +923,6 @@ public class SubscriptionManagerService extends ISub.Stub { .forEach(subInfo -> { mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), SubscriptionManager.INVALID_SIM_SLOT_INDEX); - mSlotIndexToSubId.remove(simSlotIndex); }); updateGroupDisabled(); logl("markSubscriptionsInactive: " + slotMappingToString()); @@ -1268,6 +1267,19 @@ public class SubscriptionManagerService extends ISub.Stub { } String iccId = getIccId(phoneId); + log("updateSubscriptions: Found iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + + " on phone " + phoneId); + + // For eSIM switching, SIM absent will not happen. Below is to exam if we find ICCID + // mismatch on the SIM slot, we need to mark all subscriptions on that logical slot invalid + // first. The correct subscription will be assigned the correct slot later. + if (mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .anyMatch(subInfo -> subInfo.getSimSlotIndex() == phoneId + && !iccId.equals(subInfo.getIccId()))) { + log("updateSubscriptions: iccId changed for phone " + phoneId); + markSubscriptionsInactive(phoneId); + } + if (!TextUtils.isEmpty(iccId)) { // Check if the subscription already existed. SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager 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 d0431e41bb..d3b8ab37bc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -355,6 +355,8 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionDatabaseManagerTest +Setup!"); super.setUp(getClass().getSimpleName()); + mContextFixture.putBooleanResource(com.android.internal.R.bool + .config_subscription_database_async_update, true); mSubscriptionDatabaseManagerCallback = Mockito.mock(SubscriptionDatabaseManagerCallback.class); doAnswer(invocation -> { 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 b1e87ad9a9..5eca02b6c8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -144,7 +144,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionManagerServiceTest +Setup!"); super.setUp(getClass().getSimpleName()); - + mContextFixture.putBooleanResource(com.android.internal.R.bool + .config_subscription_database_async_update, true); mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[0]); mContextFixture.addSystemFeature(PackageManager.FEATURE_TELEPHONY_EUICC); @@ -158,6 +159,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { SubscriptionManagerServiceCallback.class); doReturn(FAKE_ICCID1).when(mUiccCard).getCardId(); doReturn(FAKE_ICCID1).when(mUiccPort).getIccId(); + doReturn(true).when(mUiccSlot).isActive(); doReturn(new int[0]).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); @@ -167,6 +169,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mSubscriptionManagerServiceUT = new SubscriptionManagerService(mContext, Looper.myLooper()); monitorTestableLooper(new TestableLooper(getBackgroundHandler().getLooper())); + monitorTestableLooper(new TestableLooper(getSubscriptionDatabaseManager().getLooper())); doAnswer(invocation -> { ((Runnable) invocation.getArguments()[0]).run(); @@ -211,6 +214,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { return (Handler) field.get(mSubscriptionManagerServiceUT); } + private SubscriptionDatabaseManager getSubscriptionDatabaseManager() throws Exception { + Field field = SubscriptionManagerService.class.getDeclaredField( + "mSubscriptionDatabaseManager"); + field.setAccessible(true); + return (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT); + } + /** * Insert the subscription info to the database. * @@ -222,21 +232,14 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); subInfo = new SubscriptionInfoInternal.Builder(subInfo) .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID).build(); - - Field field = SubscriptionManagerService.class.getDeclaredField( - "mSubscriptionDatabaseManager"); - field.setAccessible(true); - SubscriptionDatabaseManager sdbm = - (SubscriptionDatabaseManager) field.get(mSubscriptionManagerServiceUT); - - int subId = sdbm.insertSubscriptionInfo(subInfo); + int subId = getSubscriptionDatabaseManager().insertSubscriptionInfo(subInfo); // Insertion is sync, but the onSubscriptionChanged callback is handled by the handler. processAllMessages(); Class WatchedMapClass = Class.forName("com.android.internal.telephony.subscription" + ".SubscriptionManagerService$WatchedMap"); - field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); + Field field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); field.setAccessible(true); Object map = field.get(mSubscriptionManagerServiceUT); Class[] cArgs = new Class[2]; @@ -1858,4 +1861,46 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // The original eSIM becomes removed pSIM ¯\_(ツ)_/¯ assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isEmbedded()).isFalse(); } + + @Test + public void testEsimSwitch() { + setIdentifierAccess(true); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID2) + .setIccid(FAKE_ICCID2) + .setNickname(FAKE_CARRIER_NAME2) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL) + .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC2, FAKE_MNC2, null, null, null, + null, FAKE_CARRIER_ID2, FAKE_CARRIER_ID2)) + .setUiccAccessRule(Arrays.asList(UiccAccessRule.decodeRules( + FAKE_NATIVE_ACCESS_RULES2))) + .build(); + + GetEuiccProfileInfoListResult result = new GetEuiccProfileInfoListResult( + EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo1}, false); + doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); + doReturn(FAKE_ICCID2).when(mUiccCard).getCardId(); + doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(1)); + doReturn(FAKE_ICCID2).when(mUiccPort).getIccId(); + + mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); + processAllMessages(); + + mSubscriptionManagerServiceUT.updateSimState( + 0, TelephonyManager.SIM_STATE_READY, null, null); + processAllMessages(); + + mSubscriptionManagerServiceUT.updateSimState( + 0, TelephonyManager.SIM_STATE_LOADED, null, null); + processAllMessages(); + + List subInfoList = mSubscriptionManagerServiceUT + .getActiveSubscriptionInfoList(CALLING_PACKAGE, CALLING_FEATURE); + + assertThat(subInfoList).hasSize(1); + assertThat(subInfoList.get(0).isActive()).isTrue(); + assertThat(subInfoList.get(0).getIccId()).isEqualTo(FAKE_ICCID2); + } } -- GitLab From f29fa9056fc263d8444c5b9c4841cf98fa3ef237 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 26 May 2022 12:43:15 -0700 Subject: [PATCH 443/656] Report an Anomaly for missing RegDenied Reason Add an anomaly report to detect when reg is reported as denied, but there is no reason associated with the reg denied state. Used a new UUID for U. Bug: 232255564 Test: compilation Change-Id: Ib2e2853c39a74700233e3411b4f1c5cc037f6e66 --- .../telephony/CellularNetworkService.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java index bd47d3d399..9cbd7a6174 100644 --- a/src/java/com/android/internal/telephony/CellularNetworkService.java +++ b/src/java/com/android/internal/telephony/CellularNetworkService.java @@ -504,6 +504,14 @@ public class CellularNetworkService extends NetworkService { final String rplmn = regResult.registeredPlmn; final int reasonForDenial = regResult.reasonForDenial; + if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_DENIED + && reasonForDenial + == android.hardware.radio.network.RegistrationFailCause.NONE) { + AnomalyReporter.reportAnomaly( + UUID.fromString("62ed270f-e139-418a-a427-8bcc1bca8f21"), + "RIL Missing Reg Fail Reason", mPhone.getCarrierId()); + } + int networkType = ServiceState.rilRadioTechnologyToNetworkType(regResult.rat); if (networkType == TelephonyManager.NETWORK_TYPE_LTE_CA) { networkType = TelephonyManager.NETWORK_TYPE_LTE; @@ -606,6 +614,14 @@ public class CellularNetworkService extends NetworkService { networkType = getNetworkTypeForCellIdentity(networkType, cellIdentity, mPhone.getCarrierId()); + if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_DENIED + && reasonForDenial + == android.hardware.radio.network.RegistrationFailCause.NONE) { + AnomalyReporter.reportAnomaly( + UUID.fromString("62ed270f-e139-418a-a427-8bcc1bca8f21"), + "RIL Missing Reg Fail Reason", mPhone.getCarrierId()); + } + // Conditional parameters for specific RANs boolean cssSupported = false; int roamingIndicator = 0; -- GitLab From dac5e8a10669da0ba23353c5099f94068c7f8382 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Fri, 3 Feb 2023 16:50:46 -0800 Subject: [PATCH 444/656] Don't clear throttling when network disconnects Before the change, the throttle entries are cleared without notifying onThrottleStatusChanged via callback. Because the decision of unthrotting should only be made by modem, the fix keeps the throttle status even when network disconnects. Also removed isAnySetupRetryScheduled(). The method in fact only checks for modem demanded retry, which is already covered by isDataProfileThrottled(). Fix: 254480678 Test: placed voice call + internet browsing Change-Id: Id52f036fb006286411dfc53690f6b5c36e635649 --- .../telephony/data/DataNetworkController.java | 12 +++--- .../telephony/data/DataRetryManager.java | 41 ++++++------------- .../data/DataNetworkControllerTest.java | 33 ++++++++++++++- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 9f2720cecc..2290a1ba35 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -1618,13 +1618,11 @@ public class DataNetworkController extends Handler { reason.isConditionBased()); if (dataProfile == null) { evaluation.addDataDisallowedReason(DataDisallowedReason.NO_SUITABLE_DATA_PROFILE); - } else if (reason == DataEvaluationReason.NEW_REQUEST - && (mDataRetryManager.isAnySetupRetryScheduled(dataProfile, transport) - || mDataRetryManager.isSimilarNetworkRequestRetryScheduled( - networkRequest, transport))) { - // If this is a new request, check if there is any retry already scheduled. For all - // other evaluation reasons, since they are all condition changes, so if there is any - // retry scheduled, we still want to go ahead and setup the data network. + } else if (// Check for new requests if we already self-scheduled(as opposed to modem + // demanded) retry for similar requests. + reason == DataEvaluationReason.NEW_REQUEST + && mDataRetryManager.isSimilarNetworkRequestRetryScheduled( + networkRequest, transport)) { evaluation.addDataDisallowedReason(DataDisallowedReason.RETRY_SCHEDULED); } else if (mDataRetryManager.isDataProfileThrottled(dataProfile, transport)) { evaluation.addDataDisallowedReason(DataDisallowedReason.DATA_THROTTLED); diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index c2b3b9ae3b..638faa5f67 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -1427,15 +1427,20 @@ public class DataRetryManager extends Handler { @TransportType int transport, @ElapsedRealtimeLong long expirationTime) { DataThrottlingEntry entry = new DataThrottlingEntry(dataProfile, networkRequestList, dataNetwork, transport, retryType, expirationTime); - if (mDataThrottlingEntries.size() >= MAXIMUM_HISTORICAL_ENTRIES) { - mDataThrottlingEntries.remove(0); - } - - // Remove previous entry that contains the same data profile. + // Remove previous entry that contains the same data profile. Therefore it should always + // contain at maximum all the distinct data profiles of the current subscription. mDataThrottlingEntries.removeIf( throttlingEntry -> dataProfile.equals(throttlingEntry.dataProfile)); - + if (mDataThrottlingEntries.size() >= MAXIMUM_HISTORICAL_ENTRIES) { + // If we don't see the anomaly report after U release, we should remove this check for + // the commented reason above. + AnomalyReporter.reportAnomaly( + UUID.fromString("24fd4d46-1d0f-4b13-b7d6-7bad70b8289b"), + "DataRetryManager throttling more than 100 data profiles", + mPhone.getCarrierId()); + mDataThrottlingEntries.remove(0); + } logl("Add throttling entry " + entry); mDataThrottlingEntries.add(entry); @@ -1470,11 +1475,11 @@ public class DataRetryManager extends Handler { * When this is set, {@code dataProfile} must be {@code null}. * @param transport The transport that this unthrottling request is on. * @param remove Whether to remove unthrottled entries from the list of entries. - * @param retry Whether schedule data setup retry after unthrottling. + * @param retry Whether schedule retry after unthrottling. */ private void onDataProfileUnthrottled(@Nullable DataProfile dataProfile, @Nullable String apn, @TransportType int transport, boolean remove, boolean retry) { - log("onDataProfileUnthrottled: data profile=" + dataProfile + ", apn=" + apn + log("onDataProfileUnthrottled: dataProfile=" + dataProfile + ", apn=" + apn + ", transport=" + AccessNetworkConstants.transportTypeToString(transport) + ", remove=" + remove); @@ -1486,7 +1491,6 @@ public class DataRetryManager extends Handler { // equal to the data profiles kept in data profile manager (due to some fields missing // in DataProfileInfo.aidl), so we need to get the equivalent data profile from data // profile manager. - log("onDataProfileUnthrottled: dataProfile=" + dataProfile); Stream stream = mDataThrottlingEntries.stream(); stream = stream.filter(entry -> entry.expirationTimeMillis > now); if (dataProfile.getApnSetting() != null) { @@ -1641,23 +1645,6 @@ public class DataRetryManager extends Handler { return false; } - /** - * Check if there is any data setup retry scheduled with specified data profile. - * - * @param dataProfile The data profile to retry. - * @param transport The transport that the request is on. - * @return {@code true} if there is retry scheduled for this data profile. - */ - public boolean isAnySetupRetryScheduled(@NonNull DataProfile dataProfile, - @TransportType int transport) { - return mDataRetryEntries.stream() - .filter(DataSetupRetryEntry.class::isInstance) - .map(DataSetupRetryEntry.class::cast) - .anyMatch(entry -> entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED - && dataProfile.equals(entry.dataProfile) - && entry.transport == transport); - } - /** * Check if a specific data profile is explicitly throttled by the network. * @@ -1693,13 +1680,11 @@ public class DataRetryManager extends Handler { && ((DataHandoverRetryEntry) entry).dataNetwork == dataNetwork && entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED) .forEach(entry -> entry.setState(DataRetryEntry.RETRY_STATE_CANCELLED)); - mDataThrottlingEntries.removeIf(entry -> entry.dataNetwork == dataNetwork); } /** * Check if there is any data handover retry scheduled. * - * * @param dataNetwork The network network to retry handover. * @return {@code true} if there is retry scheduled for this network capability. */ 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 b0fa7dfd3b..5b609411aa 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -2769,7 +2769,7 @@ public class DataNetworkControllerTest extends TelephonyTest { processAllFutureMessages(); // TAC changes should clear the already-scheduled retry and throttling. - assertThat(mDataNetworkControllerUT.getDataRetryManager().isAnySetupRetryScheduled( + assertThat(mDataNetworkControllerUT.getDataRetryManager().isDataProfileThrottled( mImsCellularDataProfile, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).isFalse(); // But DNC should re-evaluate unsatisfied request and setup IMS again. @@ -2873,6 +2873,35 @@ public class DataNetworkControllerTest extends TelephonyTest { .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); } + @Test + public void testHandoverDataNetworkNetworkSuggestedRetryTimerDataThrottled() throws Exception { + testSetupImsDataNetwork(); + + DataNetwork network = getDataNetworks().get(0); + setFailedSetupDataResponse(mMockedWlanDataServiceManager, + DataFailCause.HANDOVER_FAILED, 10000, true); + updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + + // Verify retry scheduled on this network + assertThat(mDataNetworkControllerUT.getDataRetryManager() + .isAnyHandoverRetryScheduled(network)).isTrue(); + // Verify the data profile is throttled on WLAN + assertThat(mDataNetworkControllerUT.getDataRetryManager().isDataProfileThrottled( + network.getDataProfile(), AccessNetworkConstants.TRANSPORT_TYPE_WLAN)).isTrue(); + + // Test even if network disconnected, the throttle status should remain + network.tearDown(DataNetwork.TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED); + processAllFutureMessages(); + + // 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 public void testTacChangesClearThrottlingAndRetryHappens() throws Exception { testSetupDataNetworkNetworkSuggestedRetryTimerDataThrottled(); @@ -2886,7 +2915,7 @@ public class DataNetworkControllerTest extends TelephonyTest { processAllFutureMessages(); // TAC changes should clear the already-scheduled retry and throttling. - assertThat(mDataNetworkControllerUT.getDataRetryManager().isAnySetupRetryScheduled( + assertThat(mDataNetworkControllerUT.getDataRetryManager().isDataProfileThrottled( mImsCellularDataProfile, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)).isFalse(); // But DNC should re-evaluate unsatisfied request and setup IMS again. -- GitLab From 2dd0df64695710b464fc73a452fb2f52cc3f7044 Mon Sep 17 00:00:00 2001 From: Avinash Malipatil Date: Fri, 23 Dec 2022 08:36:11 +0000 Subject: [PATCH 445/656] Compare domain selection results based on flag and trigger bug report if results are not same. Bug: 263552148 Test: Manual call testing Change-Id: I29def5611f1e410f7d8bbabaf347f014371462b4 --- .../internal/telephony/GsmCdmaPhone.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 65347e825d..a0649aaef5 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -16,7 +16,10 @@ package com.android.internal.telephony; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS_PS; import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_UNKNOWN; import static com.android.internal.telephony.CommandException.Error.GENERIC_FAILURE; import static com.android.internal.telephony.CommandException.Error.SIM_BUSY; @@ -72,6 +75,7 @@ import android.telecom.VideoProfile; import android.telephony.AccessNetworkConstants.TransportType; import android.telephony.Annotation.DataActivityType; import android.telephony.Annotation.RadioPowerState; +import android.telephony.AnomalyReporter; import android.telephony.BarringInfo; import android.telephony.CarrierConfigManager; import android.telephony.CellBroadcastIdRange; @@ -140,6 +144,7 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.UUID; import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1428,6 +1433,24 @@ public class GsmCdmaPhone extends Phone { && (isWpsCall ? allowWpsOverIms : true); Bundle extras = dialArgs.intentExtras; + if (extras != null && extras.containsKey(PhoneConstants.EXTRA_COMPARE_DOMAIN)) { + int domain = extras.getInt(PhoneConstants.EXTRA_DIAL_DOMAIN); + if (!isEmergency && (!isMmiCode || isPotentialUssdCode)) { + if ((domain == DOMAIN_PS && !useImsForCall) + || (domain == DOMAIN_CS && useImsForCall) + || domain == DOMAIN_UNKNOWN || domain == DOMAIN_CS_PS) { + loge("[Anomaly] legacy-useImsForCall:" + useImsForCall + + ", NCDS-domain:" + domain); + + AnomalyReporter.reportAnomaly( + UUID.fromString("bfae6c2e-ca2f-4121-b167-9cad26a3b353"), + "Domain selection results don't match. useImsForCall:" + + useImsForCall + ", NCDS-domain:" + domain); + } + } + extras.remove(PhoneConstants.EXTRA_COMPARE_DOMAIN); + } + // Only when the domain selection service is supported, EXTRA_DIAL_DOMAIN extra shall exist. if (extras != null && extras.containsKey(PhoneConstants.EXTRA_DIAL_DOMAIN)) { int domain = extras.getInt(PhoneConstants.EXTRA_DIAL_DOMAIN); -- GitLab From 49c5dff50896b6e3cce57048cfb1f5e977630e89 Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Fri, 17 Feb 2023 02:53:55 +0000 Subject: [PATCH 446/656] Temporarily ignore tests Temporarily disable tests to allow enabling telephony tests in presubmit. Bug: 269535969 Test: atest FrameworksTelephonyTests Merged-In: Id2855842bb9fe0a6a3adf944cb10e5a0985a2fda Change-Id: Id2855842bb9fe0a6a3adf944cb10e5a0985a2fda (cherry picked from commit 5c860ae7401eb99551f0b05704090b05ef9a4156) --- .../internal/telephony/gsm/GsmInboundSmsHandlerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java index 7a516404f8..67e344ef61 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java @@ -72,6 +72,7 @@ import com.android.internal.util.StateMachine; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -478,6 +479,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { @Test @MediumTest + @Ignore("b/269535969") public void testClass0Sms() { transitionFromStartupToIdle(); -- GitLab From 1c7f1cac1d7c66c79c5b499d07dbdcf41ab3401e Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Thu, 16 Feb 2023 04:02:48 +0000 Subject: [PATCH 447/656] Added datagramId in satellite datagram apis. The following changes are made in this CL: - Added datagramId paramater in sendSatelliteDatagram() - Added datagramId, datagramReceiverAck callback in onSatelliteDatagram() Bug: 260896985 Test: atest SatelliteManagerTest Change-Id: Ibc8e066cd882ae9312c8b234e2a9ef064de690cc --- src/java/com/android/internal/telephony/Phone.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index e962b20eb8..28c0207cb6 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5490,7 +5490,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @param datagram Datagram to send over satellite. */ public void sendSatelliteDatagram(Message result, SatelliteDatagram datagram) { - //mCi.sendSatelliteDatagram(result, datagram, longitude, latitude); + //mCi.sendSatelliteDatagram(result, datagram); } /** -- GitLab From 50cf7900e869e75830fc5ecad99e7e571938faf2 Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Thu, 16 Feb 2023 19:16:31 +0000 Subject: [PATCH 448/656] Remove overloaded iccCloseLogicalChannel and iccTransmitApduLogicalChannel from CommandInterface Keep only one API along with extra isEs10 parameter. Test: Manually verified on C10, atest FrameworksTelephonyTests and atest CtsStatsdAtomHostTestCases:TelephonyStatsTests Bug: 268496310 Change-Id: I6235d9a370eb8063c886b351d0f40a8d0b4f00ff Merged-In: I6235d9a370eb8063c886b351d0f40a8d0b4f00ff (cherry picked from commit a5a7816ded47af2646b28d72c5f3362332ef09aa) --- .../internal/telephony/CommandsInterface.java | 33 --------- .../com/android/internal/telephony/RIL.java | 11 --- .../imsphone/ImsPhoneCommandInterface.java | 8 --- .../uicc/UiccCarrierPrivilegeRules.java | 8 +-- .../internal/telephony/uicc/UiccPkcs15.java | 8 +-- .../internal/telephony/uicc/UiccPort.java | 10 +-- .../internal/telephony/uicc/UiccProfile.java | 10 +-- .../android/internal/telephony/RILTest.java | 2 +- .../internal/telephony/SimulatedCommands.java | 20 ++---- .../telephony/SimulatedCommandsVerifier.java | 11 --- .../uicc/UiccCarrierPrivilegeRulesTest.java | 72 +++++++++---------- .../internal/telephony/uicc/UiccPortTest.java | 2 +- .../telephony/uicc/UiccProfileTest.java | 3 +- .../uicc/euicc/apdu/LogicalChannelMocker.java | 11 --- 14 files changed, 62 insertions(+), 147 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index dbb7c80f3b..7314ccb823 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2110,19 +2110,6 @@ public interface CommandsInterface { */ public void iccOpenLogicalChannel(String AID, int p2, Message response); - /** - * Close a previously opened logical channel to the SIM. - * - * Input parameters equivalent to TS 27.007 AT+CCHC command. - * - * Starting with Android U, use {@link #iccCloseLogicalChannel(int, boolean, Message)}} - * API to close the logical channel if the channel was opened to perform ES10 operations. - * - * @param channel Channel id. Id of the channel to be closed. - * @param response Callback message. - */ - public void iccCloseLogicalChannel(int channel, Message response); - /** * Close a previously opened logical channel to the SIM. * @@ -2138,26 +2125,6 @@ public interface CommandsInterface { */ public void iccCloseLogicalChannel(int channel, boolean isEs10, Message response); - /** - * Exchange APDUs with the SIM on a logical channel. - * - * Input parameters equivalent to TS 27.007 AT+CGLA command. - * - * @param channel Channel id of the channel to use for communication. Has to - * be greater than zero. - * @param cla Class of the APDU command. - * @param instruction Instruction of the APDU command. - * @param p1 P1 value of the APDU command. - * @param p2 P2 value of the APDU command. - * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU - * is sent to the SIM. - * @param data Data to be sent with the APDU. - * @param response Callback message. response.obj.userObj will be - * an IccIoResult on success. - */ - public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, - int p1, int p2, int p3, String data, Message response); - /** * Exchange APDUs with the SIM on a logical channel. * diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index f972f85c0c..5f29a4810c 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -4120,11 +4120,6 @@ public class RIL extends BaseCommands implements CommandsInterface { } } - @Override - public void iccCloseLogicalChannel(int channel, Message result) { - iccCloseLogicalChannel(channel, false, result); - } - @Override public void iccCloseLogicalChannel(int channel, boolean isEs10, Message result) { RadioSimProxy simProxy = getRadioServiceProxy(RadioSimProxy.class, result); @@ -4144,12 +4139,6 @@ public class RIL extends BaseCommands implements CommandsInterface { } } - @Override - public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, - int p3, String data, Message result) { - iccTransmitApduLogicalChannel(channel, cla, instruction, p1, p2, p3, data, false, result); - } - @Override public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, int p3, String data, boolean isEs10Command, Message result) { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java index f89a31e2b3..71257636ef 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java @@ -606,17 +606,9 @@ class ImsPhoneCommandInterface extends BaseCommands implements CommandsInterface @Override public void iccOpenLogicalChannel(String AID, int p2, Message response) {} - @Override - public void iccCloseLogicalChannel(int channel, Message response) {} - @Override public void iccCloseLogicalChannel(int channel, boolean isEs10, Message response) {} - @Override - public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, - int p1, int p2, int p3, String data, - Message response) {} - @Override public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, int p3, String data, diff --git a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java index 7d87e5f1f5..0c88e0baa7 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java @@ -426,8 +426,8 @@ public class UiccCarrierPrivilegeRules extends Handler { if (ar.exception == null && ar.result != null) { mChannelId = ((int[]) ar.result)[0]; mUiccProfile.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2, P3, - DATA, obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, mChannelId, - mAIDInUse)); + DATA, false /*isEs10Command*/, obtainMessage( + EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, mChannelId, mAIDInUse)); } else { if (shouldRetry(ar, mRetryCount)) { log("should retry"); @@ -483,7 +483,7 @@ public class UiccCarrierPrivilegeRules extends Handler { } } else { mUiccProfile.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, - P1, P2_EXTENDED_DATA, P3, DATA, + P1, P2_EXTENDED_DATA, P3, DATA, false /*isEs10Command*/, obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, mChannelId, mAIDInUse)); break; @@ -518,7 +518,7 @@ public class UiccCarrierPrivilegeRules extends Handler { } } - mUiccProfile.iccCloseLogicalChannel(mChannelId, obtainMessage( + mUiccProfile.iccCloseLogicalChannel(mChannelId, false /*isEs10*/, obtainMessage( EVENT_CLOSE_LOGICAL_CHANNEL_DONE, 0, mAIDInUse)); mChannelId = -1; break; diff --git a/src/java/com/android/internal/telephony/uicc/UiccPkcs15.java b/src/java/com/android/internal/telephony/uicc/UiccPkcs15.java index 9543908e71..be045c4c92 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccPkcs15.java +++ b/src/java/com/android/internal/telephony/uicc/UiccPkcs15.java @@ -81,7 +81,7 @@ public class UiccPkcs15 extends Handler { private void selectFile() { if (mChannelId >= 0) { mUiccProfile.iccTransmitApduLogicalChannel(mChannelId, 0x00, 0xA4, 0x00, 0x04, 0x02, - mFileId, obtainMessage(EVENT_SELECT_FILE_DONE)); + mFileId, false /*isEs10Command*/, obtainMessage(EVENT_SELECT_FILE_DONE)); } else { log("EF based"); } @@ -90,7 +90,7 @@ public class UiccPkcs15 extends Handler { private void readBinary() { if (mChannelId >=0 ) { mUiccProfile.iccTransmitApduLogicalChannel(mChannelId, 0x00, 0xB0, 0x00, 0x00, 0x00, - "", obtainMessage(EVENT_READ_BINARY_DONE)); + "", false /*isEs10Command*/, obtainMessage(EVENT_READ_BINARY_DONE)); } else { log("EF based"); } @@ -281,8 +281,8 @@ public class UiccPkcs15 extends Handler { private void cleanUp() { log("cleanUp"); if (mChannelId >= 0) { - mUiccProfile.iccCloseLogicalChannel(mChannelId, obtainMessage( - EVENT_CLOSE_LOGICAL_CHANNEL_DONE)); + mUiccProfile.iccCloseLogicalChannel(mChannelId, false /*isEs10*/, + obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE)); mChannelId = -1; } mLoadedCallback.sendToTarget(); diff --git a/src/java/com/android/internal/telephony/uicc/UiccPort.java b/src/java/com/android/internal/telephony/uicc/UiccPort.java index 0152dda088..1f22aa1c42 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccPort.java +++ b/src/java/com/android/internal/telephony/uicc/UiccPort.java @@ -216,12 +216,12 @@ public class UiccPort { /** * Exposes {@link CommandsInterface#iccCloseLogicalChannel} * @deprecated Please use - * {@link UiccProfile#iccCloseLogicalChannel(int, Message)} instead. + * {@link UiccProfile#iccCloseLogicalChannel(int, boolean, Message)} instead. */ @Deprecated public void iccCloseLogicalChannel(int channel, Message response) { if (mUiccProfile != null) { - mUiccProfile.iccCloseLogicalChannel(channel, response); + mUiccProfile.iccCloseLogicalChannel(channel, false /*isEs10*/, response); } else { loge("iccCloseLogicalChannel Failed!"); } @@ -230,15 +230,15 @@ public class UiccPort { /** * Exposes {@link CommandsInterface#iccTransmitApduLogicalChannel} * @deprecated Please use {@link - * UiccProfile#iccTransmitApduLogicalChannel(int, int, int, int, int, int, String, Message)} - * instead. + * UiccProfile#iccTransmitApduLogicalChannel(int, int, int, int, int, int, String, + * boolean, Message)} instead. */ @Deprecated public void iccTransmitApduLogicalChannel(int channel, int cla, int command, int p1, int p2, int p3, String data, Message response) { if (mUiccProfile != null) { mUiccProfile.iccTransmitApduLogicalChannel(channel, cla, command, p1, p2, p3, - data, response); + data, false /*isEs10Command*/, response); } else { loge("iccTransmitApduLogicalChannel Failed!"); } diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index c27fff16e3..e4a9b5c4ba 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -1633,9 +1633,9 @@ public class UiccProfile extends IccCard { /** * Exposes {@link CommandsInterface#iccCloseLogicalChannel} */ - public void iccCloseLogicalChannel(int channel, Message response) { + public void iccCloseLogicalChannel(int channel, boolean isEs10, Message response) { logWithLocalLog("iccCloseLogicalChannel: " + channel); - mCi.iccCloseLogicalChannel(channel, + mCi.iccCloseLogicalChannel(channel, isEs10, mHandler.obtainMessage(EVENT_CLOSE_LOGICAL_CHANNEL_DONE, response)); } @@ -1643,9 +1643,9 @@ public class UiccProfile extends IccCard { * Exposes {@link CommandsInterface#iccTransmitApduLogicalChannel} */ public void iccTransmitApduLogicalChannel(int channel, int cla, int command, - int p1, int p2, int p3, String data, Message response) { - mCi.iccTransmitApduLogicalChannel(channel, cla, command, p1, p2, p3, - data, mHandler.obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response)); + int p1, int p2, int p3, String data, boolean isEs10Command, Message response) { + mCi.iccTransmitApduLogicalChannel(channel, cla, command, p1, p2, p3, data, isEs10Command, + mHandler.obtainMessage(EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE, response)); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java index f5c09ca935..2396d1dcc5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java @@ -1281,7 +1281,7 @@ public class RILTest extends TelephonyTest { @Test public void testIccCloseLogicalChannel() throws Exception { int channel = 1; - mRILUnderTest.iccCloseLogicalChannel(channel, obtainMessage()); + mRILUnderTest.iccCloseLogicalChannel(channel, false, obtainMessage()); verify(mRadioProxy).iccCloseLogicalChannel(mSerialNumberCaptor.capture(), eq(channel)); verifyRILResponse( mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_SIM_CLOSE_CHANNEL); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index 6da56f33f4..4bc59848f9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -68,7 +68,6 @@ import com.android.internal.telephony.RILUtils; import com.android.internal.telephony.RadioCapability; import com.android.internal.telephony.SmsResponse; import com.android.internal.telephony.SrvccConnection; -import com.android.internal.telephony.test.SimulatedCommandsVerifier; import com.android.internal.telephony.UUSInfo; import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; @@ -2165,11 +2164,6 @@ public class SimulatedCommands extends BaseCommands resultSuccess(response, result); } - @Override - public void iccCloseLogicalChannel(int channel, Message response) { - unimplemented(response); - } - @Override public void iccCloseLogicalChannel(int channel, boolean isEs10, Message response) { unimplemented(response); @@ -2177,22 +2171,16 @@ public class SimulatedCommands extends BaseCommands @Override public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, - int p1, int p2, int p3, String data, - Message response) { + int p1, int p2, int p3, String data, boolean isEs10Command, Message response) { SimulatedCommandsVerifier.getInstance().iccTransmitApduLogicalChannel(channel, cla, - instruction, p1, p2, p3, data, response); - if(mIccIoResultForApduLogicalChannel!=null) { + instruction, p1, p2, p3, data, isEs10Command, response); + if (mIccIoResultForApduLogicalChannel != null) { resultSuccess(response, mIccIoResultForApduLogicalChannel); - }else { + } else { resultFail(response, null, new RuntimeException("IccIoResult not set")); } } - @Override - public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, - int p1, int p2, int p3, String data, boolean isEs10Command, Message response) { - } - @Override public void iccTransmitApduBasicChannel(int cla, int instruction, int p1, int p2, int p3, String data, Message response) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java index 66ce6bea1f..4d1c104251 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java @@ -1303,22 +1303,11 @@ public class SimulatedCommandsVerifier implements CommandsInterface { } - @Override - public void iccCloseLogicalChannel(int channel, Message response) { - - } - @Override public void iccCloseLogicalChannel(int channel, boolean isEs10, Message response) { } - @Override - public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, - int p2, int p3, String data, Message response) { - - } - @Override public void iccTransmitApduLogicalChannel(int channel, int cla, int instruction, int p1, int p2, int p3, String data, diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java index 3deb501b8c..143d7c9872 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java @@ -85,7 +85,7 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[7]; + Message message = (Message) invocation.getArguments()[8]; IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString)); AsyncResult ar = new AsyncResult(null, iir, null); message.obj = ar; @@ -93,16 +93,16 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { return null; } }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(), - anyInt(), anyInt(), anyString(), any(Message.class)); + anyInt(), anyInt(), anyString(), eq(false) /*isEs10Command*/, any(Message.class)); doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[1]; + Message message = (Message) invocation.getArguments()[2]; message.sendToTarget(); return null; } - }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), any(Message.class)); + }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), eq(false), any(Message.class)); mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccProfile, null); processAllMessages(); @@ -327,7 +327,7 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[7]; + Message message = (Message) invocation.getArguments()[8]; IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString)); AsyncResult ar = new AsyncResult(null, iir, null); message.obj = ar; @@ -335,16 +335,16 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { return null; } }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(), - anyInt(), anyInt(), anyString(), any(Message.class)); + anyInt(), anyInt(), anyString(), eq(false) /*isEs10Command*/, any(Message.class)); doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[1]; + Message message = (Message) invocation.getArguments()[2]; message.sendToTarget(); return null; } - }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), any(Message.class)); + }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), eq(false), any(Message.class)); mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccProfile, null); @@ -388,7 +388,7 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[7]; + Message message = (Message) invocation.getArguments()[8]; IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString)); AsyncResult ar = new AsyncResult(null, iir, null); message.obj = ar; @@ -396,16 +396,16 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { return null; } }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(), - anyInt(), anyInt(), anyString(), any(Message.class)); + anyInt(), anyInt(), anyString(), eq(false) /*isEs10Command*/, any(Message.class)); doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[1]; + Message message = (Message) invocation.getArguments()[2]; message.sendToTarget(); return null; } - }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), any(Message.class)); + }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), eq(false), any(Message.class)); mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccProfile, null); processAllMessages(); @@ -445,7 +445,7 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[7]; + Message message = (Message) invocation.getArguments()[8]; IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString)); AsyncResult ar = new AsyncResult(null, iir, null); message.obj = ar; @@ -453,16 +453,16 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { return null; } }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(), - anyInt(), anyInt(), anyString(), any(Message.class)); + anyInt(), anyInt(), anyString(), eq(false /*isEs10Command*/), any(Message.class)); doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[1]; + Message message = (Message) invocation.getArguments()[2]; message.sendToTarget(); return null; } - }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), any(Message.class)); + }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), eq(false), any(Message.class)); mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccProfile, null); processAllMessages(); @@ -509,11 +509,11 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[1]; + Message message = (Message) invocation.getArguments()[2]; message.sendToTarget(); return null; } - }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), any(Message.class)); + }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), eq(false), any(Message.class)); mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccProfile, null); processAllMessages(); @@ -569,14 +569,14 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { @Override public Void answer(InvocationOnMock invocation) throws Throwable { currentFileId.set((String) invocation.getArguments()[6]); - Message message = (Message) invocation.getArguments()[7]; + Message message = (Message) invocation.getArguments()[8]; AsyncResult ar = new AsyncResult(null, new int[]{2}, null); message.obj = ar; message.sendToTarget(); return null; } }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xA4), eq(0x00), - eq(0x04), eq(0x02), anyString(), any(Message.class)); + eq(0x04), eq(0x02), anyString(), eq(false /*isEs10Command*/), any(Message.class)); // Read binary - since params are identical across files, we need to keep track of which // file was selected most recently and give back that content. @@ -597,7 +597,7 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[7]; + Message message = (Message) invocation.getArguments()[8]; IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(binaryContent.get(currentFileId.get()))); @@ -607,16 +607,16 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { return null; } }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xB0), eq(0x00), - eq(0x00), eq(0x00), eq(""), any(Message.class)); + eq(0x00), eq(0x00), eq(""), eq(false /*isEs10Command*/), any(Message.class)); doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[1]; + Message message = (Message) invocation.getArguments()[2]; message.sendToTarget(); return null; } - }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), any(Message.class)); + }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), eq(false), any(Message.class)); mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccProfile, null); processAllMessages(); @@ -667,14 +667,14 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { @Override public Void answer(InvocationOnMock invocation) throws Throwable { currentFileId.set((String) invocation.getArguments()[6]); - Message message = (Message) invocation.getArguments()[7]; + Message message = (Message) invocation.getArguments()[8]; AsyncResult ar = new AsyncResult(null, new int[]{2}, null); message.obj = ar; message.sendToTarget(); return null; } }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xA4), eq(0x00), - eq(0x04), eq(0x02), anyString(), any(Message.class)); + eq(0x04), eq(0x02), anyString(), eq(false /*isEs10Command*/), any(Message.class)); // Read binary - since params are identical across files, we need to keep track of which // file was selected most recently and give back that content. @@ -690,7 +690,7 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[7]; + Message message = (Message) invocation.getArguments()[8]; IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(binaryContent.get(currentFileId.get()))); @@ -700,16 +700,16 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { return null; } }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), eq(0x00), eq(0xB0), eq(0x00), - eq(0x00), eq(0x00), eq(""), any(Message.class)); + eq(0x00), eq(0x00), eq(""), eq(false /*isEs10Command*/), any(Message.class)); doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[1]; + Message message = (Message) invocation.getArguments()[2]; message.sendToTarget(); return null; } - }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), any(Message.class)); + }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), eq(false), any(Message.class)); mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccProfile, null); processAllMessages(); @@ -766,7 +766,7 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[7]; + Message message = (Message) invocation.getArguments()[8]; IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString1)); AsyncResult ar = new AsyncResult(null, iir, null); @@ -775,12 +775,12 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { return null; } }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(), - eq(P2), anyInt(), anyString(), any(Message.class)); + eq(P2), anyInt(), anyString(), eq(false), any(Message.class)); doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[7]; + Message message = (Message) invocation.getArguments()[8]; IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString2)); AsyncResult ar = new AsyncResult(null, iir, null); @@ -789,16 +789,16 @@ public class UiccCarrierPrivilegeRulesTest extends TelephonyTest { return null; } }).when(mUiccProfile).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(), - eq(P2_EXTENDED_DATA), anyInt(), anyString(), any(Message.class)); + eq(P2_EXTENDED_DATA), anyInt(), anyString(), eq(false), any(Message.class)); doAnswer(new Answer() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { - Message message = (Message) invocation.getArguments()[1]; + Message message = (Message) invocation.getArguments()[2]; message.sendToTarget(); return null; } - }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), any(Message.class)); + }).when(mUiccProfile).iccCloseLogicalChannel(anyInt(), eq(false), any(Message.class)); mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(mUiccProfile, null); processAllMessages(); 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 bddb0441ba..14e95f103e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccPortTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccPortTest.java @@ -140,7 +140,7 @@ public class UiccPortTest extends TelephonyTest { record = mUiccPort.getOpenLogicalChannelRecord(CHANNEL_ID); assertThat(record).isNull(); - verify(mUiccProfile).iccCloseLogicalChannel(eq(CHANNEL_ID), eq(null)); + verify(mUiccProfile).iccCloseLogicalChannel(eq(CHANNEL_ID), eq(false), eq(null)); } private IccLogicalChannelRequest getIccLogicalChannelRequest() { diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java index 63ae88a52d..f035714600 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; @@ -226,7 +227,7 @@ public class UiccProfileTest extends TelephonyTest { anyInt(), isA(Message.class)); verify(mSimulatedCommandsVerifier, times(2)).iccTransmitApduLogicalChannel( anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyString(), - isA(Message.class) + anyBoolean(), isA(Message.class) ); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/LogicalChannelMocker.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/LogicalChannelMocker.java index 3471e2c16b..27f743fc0f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/LogicalChannelMocker.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/LogicalChannelMocker.java @@ -65,17 +65,6 @@ public final class LogicalChannelMocker { public static void mockSendToLogicalChannel(CommandsInterface mockCi, int channel, Object... responseObjects) { ArgumentCaptor response = ArgumentCaptor.forClass(Message.class); - doAnswer(new Answer() { - private int mIndex = 0; - - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - Object responseObject = responseObjects[mIndex++]; - mockIccTransmitApduLogicalChannelResponse(response, responseObject); - return null; - } - }).when(mockCi).iccTransmitApduLogicalChannel(eq(channel), anyInt(), anyInt(), anyInt(), - anyInt(), anyInt(), anyString(), response.capture()); doAnswer(new Answer() { private int mIndex = 0; -- GitLab From a274cb8f88444454377b211b0db1c648152ad0de Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Wed, 15 Feb 2023 19:21:21 +0000 Subject: [PATCH 449/656] Clean up usage of multiple MEP flags in uicc module. Bug: 262449536 Test: Manual verification C10P10 and atest FrameworksTelephonyTests Change-Id: I254e498d4bf3988d4e9570d0065204cda87f4a3e --- .../telephony/uicc/IccSlotStatus.java | 4 ++ .../internal/telephony/uicc/UiccCard.java | 14 ++----- .../internal/telephony/uicc/UiccSlot.java | 39 +++++++++++++------ .../telephony/uicc/euicc/EuiccCard.java | 13 +++---- .../telephony/uicc/euicc/EuiccPort.java | 21 ++++------ .../internal/telephony/uicc/UiccCardTest.java | 2 +- .../internal/telephony/uicc/UiccSlotTest.java | 12 +++++- .../uicc/UiccStateChangedLauncherTest.java | 2 +- .../telephony/uicc/euicc/EuiccCardTest.java | 7 ++-- .../telephony/uicc/euicc/EuiccPortTest.java | 12 +++--- 10 files changed, 70 insertions(+), 56 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/IccSlotStatus.java b/src/java/com/android/internal/telephony/uicc/IccSlotStatus.java index 3bbef23518..8e55f7c55d 100644 --- a/src/java/com/android/internal/telephony/uicc/IccSlotStatus.java +++ b/src/java/com/android/internal/telephony/uicc/IccSlotStatus.java @@ -58,6 +58,10 @@ public class IccSlotStatus { public boolean isMepA1Mode() { return this == MEP_A1; } + + public boolean isMepMode() { + return this != NONE; + } } public IccCardStatus.CardState cardState; diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java index 7459e729fd..856bc995e5 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCard.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java @@ -52,19 +52,16 @@ public class UiccCard { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private CardState mCardState; protected String mCardId; - protected boolean mIsSupportsMultipleEnabledProfiles; protected MultipleEnabledProfilesMode mSupportedMepMode; protected LinkedHashMap mUiccPorts = new LinkedHashMap<>(); private HashMap mPhoneIdToPortIdx = new HashMap<>(); public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, - boolean isSupportsMultipleEnabledProfiles, MultipleEnabledProfilesMode supportedMepMode) { if (DBG) log("Creating"); mCardState = ics.mCardState; mLock = lock; - mIsSupportsMultipleEnabledProfiles = isSupportsMultipleEnabledProfiles; mSupportedMepMode = supportedMepMode; update(c, ci, ics, phoneId); } @@ -115,7 +112,7 @@ public class UiccCard { if (port == null) { if (this instanceof EuiccCard) { port = new EuiccPort(c, ci, ics, phoneId, mLock, this, - mIsSupportsMultipleEnabledProfiles, mSupportedMepMode); // eSim + mSupportedMepMode); // eSim } else { port = new UiccPort(c, ci, ics, phoneId, mLock, this); // pSim } @@ -149,15 +146,12 @@ public class UiccCard { /** - * Updates MEP(Multiple Enabled Profile) support and supported mode flags. + * Updates MEP(Multiple Enabled Profile) supported mode flag. * *

If IccSlotStatus comes later, the number of ports reported is only known after the * UiccCard creation which will impact UICC MEP capability. */ - public void updateSupportMepProperties(boolean supported, - MultipleEnabledProfilesMode supportedMepMode) { - // TODO(b/262449536): Handle with single MEP flag to avoid inconsistency. - mIsSupportsMultipleEnabledProfiles = supported; + public void updateSupportedMepMode(MultipleEnabledProfilesMode supportedMepMode) { mSupportedMepMode = supportedMepMode; } @@ -224,7 +218,7 @@ public class UiccCard { pw.println(" mCardState=" + mCardState); pw.println(" mCardId=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mCardId)); pw.println(" mNumberOfPorts=" + mUiccPorts.size()); - pw.println( "mIsSupportsMultipleEnabledProfiles=" + mIsSupportsMultipleEnabledProfiles); + pw.println(" mSupportedMepMode=" + mSupportedMepMode); pw.println(); for (UiccPort uiccPort : mUiccPorts.values()) { uiccPort.dump(fd, pw, args); diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index 62971d252c..94d3fda4b9 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -33,6 +33,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.Log; import android.view.WindowManager; import com.android.internal.R; @@ -123,7 +124,7 @@ public class UiccSlot extends Handler { mIsRemovable = isSlotRemovable(slotIndex); // Update supported MEP mode in IccCardStatus if the CardState is present. if (ics.mCardState.isCardPresent()) { - mSupportedMepMode = ics.mSupportedMepMode; + updateSupportedMepMode(ics.mSupportedMepMode); } int radioState = ci.getRadioState(); @@ -160,7 +161,7 @@ public class UiccSlot extends Handler { if (!mIsEuicc) { // Uicc does not support MEP, passing false by default. - mUiccCard = new UiccCard(mContext, ci, ics, phoneId, mLock, false, + mUiccCard = new UiccCard(mContext, ci, ics, phoneId, mLock, MultipleEnabledProfilesMode.NONE); } else { // The EID should be reported with the card status, but in case it's not we want @@ -171,7 +172,7 @@ public class UiccSlot extends Handler { } if (mUiccCard == null) { mUiccCard = new EuiccCard(mContext, ci, ics, phoneId, mLock, - isMultipleEnabledProfileSupported(), getSupportedMepMode()); + getSupportedMepMode()); } else { // In MEP case, UiccCard instance is already created, just call update API. // UiccPort initialization is handled inside UiccCard. @@ -196,7 +197,6 @@ public class UiccSlot extends Handler { parseAtr(iss.atr); mEid = iss.eid; mIsRemovable = isSlotRemovable(slotIndex); - mSupportedMepMode = iss.mSupportedMepMode; for (int i = 0; i < simPortInfos.length; i++) { int phoneId = iss.mSimPortInfos[i].mLogicalSlotIndex; @@ -248,11 +248,28 @@ public class UiccSlot extends Handler { mPortIdxToPhoneId.put(i, simPortInfos[i].mPortActive ? simPortInfos[i].mLogicalSlotIndex : INVALID_PHONE_ID); } - // Since the MEP capability is related with number ports reported, thus need to + updateSupportedMepMode(iss.mSupportedMepMode); + // Since the MEP capability is related to supported MEP mode, thus need to // update the flag after UiccCard creation. if (mUiccCard != null) { - mUiccCard.updateSupportMepProperties(isMultipleEnabledProfileSupported(), - getSupportedMepMode()); + mUiccCard.updateSupportedMepMode(getSupportedMepMode()); + } + } + } + + private void updateSupportedMepMode(MultipleEnabledProfilesMode mode) { + mSupportedMepMode = mode; + // If SupportedMepMode is MultipleEnabledProfilesMode.NONE, validate ATR and + // num of ports to handle backward compatibility for < RADIO_HAL_VERSION_2_1. + if (mode == MultipleEnabledProfilesMode.NONE) { + // Even ATR suggest UICC supports multiple enabled profiles, MEP can be disabled per + // carrier restrictions, so checking the real number of ports reported from modem is + // necessary. + if (mPortIdxToPhoneId.size() > 1 + && mAtr != null && mAtr.isMultipleEnabledProfilesSupported()) { + // Set MEP-B mode in case if modem sends wrong mode even though supports MEP. + Log.i(TAG, "Modem does not send proper supported MEP mode or older HAL version"); + mSupportedMepMode = MultipleEnabledProfilesMode.MEP_B; } } } @@ -326,11 +343,9 @@ public class UiccSlot extends Handler { /* Returns true if multiple enabled profiles are supported */ public boolean isMultipleEnabledProfileSupported() { - // even ATR suggest UICC supports multiple enabled profiles, MEP can be disabled per - // carrier restrictions, so checking the real number of ports reported from modem is - // necessary. - return mPortIdxToPhoneId.size() > 1 && mAtr != null && - mAtr.isMultipleEnabledProfilesSupported(); + synchronized (mLock) { + return mSupportedMepMode.isMepMode(); + } } private boolean absentStateUpdateNeeded(CardState oldState, int portIndex) { diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java index 0d98e185f9..8dbbe6605b 100644 --- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java +++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java @@ -44,9 +44,8 @@ public class EuiccCard extends UiccCard { private RegistrantList mEidReadyRegistrants; public EuiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, - boolean isSupportsMultipleEnabledProfiles, MultipleEnabledProfilesMode supportedMepMode) { - super(c, ci, ics, phoneId, lock, isSupportsMultipleEnabledProfiles, supportedMepMode); + super(c, ci, ics, phoneId, lock, supportedMepMode); if (TextUtils.isEmpty(ics.eid)) { loge("no eid given in constructor for phone " + phoneId); loadEidAndNotifyRegistrants(); @@ -57,19 +56,17 @@ public class EuiccCard extends UiccCard { } /** - * Updates MEP(Multiple Enabled Profile) support flag. + * Updates MEP(Multiple Enabled Profile) supported mode flag. * *

If IccSlotStatus comes later, the number of ports reported is only known after the - * UiccCard creation which will impact UICC MEP capability. + * UiccCard creation which will impact UICC MEP capability in case of old HAL version. */ @Override - public void updateSupportMepProperties(boolean supported, - MultipleEnabledProfilesMode supportedMepMode) { - mIsSupportsMultipleEnabledProfiles = supported; + public void updateSupportedMepMode(MultipleEnabledProfilesMode supportedMepMode) { mSupportedMepMode = supportedMepMode; for (UiccPort port : mUiccPorts.values()) { if (port instanceof EuiccPort) { - ((EuiccPort) port).updateSupportMepProperties(supported, supportedMepMode); + ((EuiccPort) port).updateSupportedMepMode(supportedMepMode); } else { loge("eUICC card has non-euicc port object:" + port.toString()); } diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java index 3dd260ecac..8dca5f4927 100644 --- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java +++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java @@ -126,12 +126,10 @@ public class EuiccPort extends UiccPort { private EuiccSpecVersion mSpecVersion; private volatile String mEid; @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - public boolean mIsSupportsMultipleEnabledProfiles; - private MultipleEnabledProfilesMode mSupportedMepMode; + public MultipleEnabledProfilesMode mSupportedMepMode; public EuiccPort(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock, - UiccCard card, boolean isSupportsMultipleEnabledProfiles, - MultipleEnabledProfilesMode supportedMepMode) { + UiccCard card, MultipleEnabledProfilesMode supportedMepMode) { super(c, ci, ics, phoneId, lock, card); // TODO: Set supportExtendedApdu based on ATR. mApduSender = new ApduSender(ci, ISD_R_AID, false /* supportExtendedApdu */); @@ -141,7 +139,6 @@ public class EuiccPort extends UiccPort { mEid = ics.eid; mCardId = ics.eid; } - mIsSupportsMultipleEnabledProfiles = isSupportsMultipleEnabledProfiles; mSupportedMepMode = supportedMepMode; } @@ -170,13 +167,11 @@ public class EuiccPort extends UiccPort { } /** - * Updates MEP(Multiple Enabled Profile) support and mode flags. + * Updates MEP(Multiple Enabled Profile) supported mode flag. * The flag can be updated after the port creation. */ - public void updateSupportMepProperties(boolean supported, - MultipleEnabledProfilesMode supportedMepMode) { - logd("updateSupportMultipleEnabledProfile"); - mIsSupportsMultipleEnabledProfiles = supported; + public void updateSupportedMepMode(MultipleEnabledProfilesMode supportedMepMode) { + logd("updateSupportedMepMode"); mSupportedMepMode = supportedMepMode; } @@ -188,7 +183,7 @@ public class EuiccPort extends UiccPort { * @since 1.1.0 [GSMA SGP.22] */ public void getAllProfiles(AsyncResultCallback callback, Handler handler) { - byte[] profileTags = mIsSupportsMultipleEnabledProfiles ? Tags.EUICC_PROFILE_MEP_TAGS + byte[] profileTags = mSupportedMepMode.isMepMode() ? Tags.EUICC_PROFILE_MEP_TAGS : Tags.EUICC_PROFILE_TAGS; sendApdu( newRequestProvider((RequestBuilder requestBuilder) -> @@ -230,7 +225,7 @@ public class EuiccPort extends UiccPort { */ public final void getProfile(String iccid, AsyncResultCallback callback, Handler handler) { - byte[] profileTags = mIsSupportsMultipleEnabledProfiles ? Tags.EUICC_PROFILE_MEP_TAGS + byte[] profileTags = mSupportedMepMode.isMepMode() ? Tags.EUICC_PROFILE_MEP_TAGS : Tags.EUICC_PROFILE_TAGS; sendApdu( newRequestProvider((RequestBuilder requestBuilder) -> @@ -1432,6 +1427,6 @@ public class EuiccPort extends UiccPort { super.dump(fd, pw, args); pw.println("EuiccPort:"); pw.println(" mEid=" + mEid); - pw.println(" mIsSupportsMultipleEnabledProfiles=" + mIsSupportsMultipleEnabledProfiles); + pw.println(" mSupportedMepMode=" + mSupportedMepMode); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java index 0ed112d39d..951c8d1eef 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java @@ -61,7 +61,7 @@ public class UiccCardTest extends TelephonyTest { mIccIoResult = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes("FF40")); mSimulatedCommands.setIccIoResultForApduLogicalChannel(mIccIoResult); mUiccCard = new UiccCard(mContext, mSimulatedCommands, mIccCardStatus, 0 /* phoneId */, - new Object(), false, IccSlotStatus.MultipleEnabledProfilesMode.NONE); + new Object(), IccSlotStatus.MultipleEnabledProfilesMode.NONE); processAllMessages(); logd("create UiccCard"); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java index 6aab7ad9d0..719fd8ddc0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java @@ -554,8 +554,18 @@ public class UiccSlotTest extends TelephonyTest { mUiccSlot.update(null, iss, 0 /* slotIndex */); // assert on updated values - assertFalse(mUiccSlot.isMultipleEnabledProfileSupported()); + assertTrue(mUiccSlot.isMultipleEnabledProfileSupported()); assertEquals(IccSlotStatus.MultipleEnabledProfilesMode.MEP_A1, mUiccSlot.getSupportedMepMode()); + + //update port info and MEP mode to test HAL version 2.0 + iss.mSimPortInfos = new IccSimPortInfo[] {simPortInfo1, simPortInfo2}; + iss.setMultipleEnabledProfilesMode(0); // Set MEP mode to NONE(assume modem sends) + + // update port info and MEP mode + mUiccSlot.update(null, iss, 0 /* slotIndex */); + assertTrue(mUiccSlot.isMultipleEnabledProfileSupported()); + assertEquals(IccSlotStatus.MultipleEnabledProfilesMode.MEP_B, + mUiccSlot.getSupportedMepMode()); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java index aa0b0d9652..7e51badd40 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java @@ -99,7 +99,7 @@ public class UiccStateChangedLauncherTest extends TelephonyTest { // The first broadcast should be sent after initialization. UiccCard card = new UiccCard(mContext, mSimulatedCommands, - makeCardStatus(CardState.CARDSTATE_PRESENT), 0 /* phoneId */, new Object(), false, + makeCardStatus(CardState.CARDSTATE_PRESENT), 0 /* phoneId */, new Object(), IccSlotStatus.MultipleEnabledProfilesMode.NONE); when(UiccController.getInstance().getUiccCardForPhone(0)).thenReturn(card); uiccLauncher.handleMessage(msg); diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java index c5eff90634..b6dd7bd2d0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java @@ -96,8 +96,7 @@ public class EuiccCardTest extends TelephonyTest { mEuiccCard = new EuiccCard(mContext, mMockCi, mMockIccCardStatus, - 0 /* phoneId */, new Object(), false, - IccSlotStatus.MultipleEnabledProfilesMode.NONE) { + 0 /* phoneId */, new Object(), IccSlotStatus.MultipleEnabledProfilesMode.NONE) { @Override protected void loadEidAndNotifyRegistrants() {} @@ -136,7 +135,7 @@ public class EuiccCardTest extends TelephonyTest { public void testPassEidInConstructor() { mMockIccCardStatus.eid = "1A2B3C4D"; mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi, - mMockIccCardStatus, 0 /* phoneId */, new Object(), false, + mMockIccCardStatus, 0 /* phoneId */, new Object(), IccSlotStatus.MultipleEnabledProfilesMode.NONE); final int eventEidReady = 0; @@ -158,7 +157,7 @@ public class EuiccCardTest extends TelephonyTest { int channel = mockLogicalChannelResponses("BF3E065A041A2B3C4D9000"); mHandler.post(() -> { mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi, - mMockIccCardStatus, 0 /* phoneId */, new Object(), false, + mMockIccCardStatus, 0 /* phoneId */, new Object(), IccSlotStatus.MultipleEnabledProfilesMode.NONE); }); processAllMessages(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccPortTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccPortTest.java index 2f8c19e96d..d140ca880e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccPortTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccPortTest.java @@ -51,6 +51,7 @@ import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.IccSlotPortMapping; import com.android.internal.telephony.uicc.IccSlotStatus; +import com.android.internal.telephony.uicc.IccSlotStatus.MultipleEnabledProfilesMode; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.asn1.Asn1Node; import com.android.internal.telephony.uicc.asn1.InvalidAsn1DataException; @@ -120,7 +121,7 @@ public class EuiccPortTest extends TelephonyTest { mMockIccCardStatus.mSlotPortMapping = new IccSlotPortMapping(); mEuiccPort = new EuiccPort(mContext, mMockCi, mMockIccCardStatus, - 0 /* phoneId */, new Object(), mEuiccCard, false, + 0 /* phoneId */, new Object(), mEuiccCard, IccSlotStatus.MultipleEnabledProfilesMode.NONE) { @Override protected byte[] getDeviceId() { @@ -174,7 +175,7 @@ public class EuiccPortTest extends TelephonyTest { "BF2D14A012E3105A0A896700000000004523019F7001019000"); ResultCaptor resultCaptor = new ResultCaptor<>(); - mEuiccPort.mIsSupportsMultipleEnabledProfiles = true; // MEP capable + mEuiccPort.mSupportedMepMode = MultipleEnabledProfilesMode.MEP_B; // MEP capable mEuiccPort.getAllProfiles(resultCaptor, mHandler); processAllMessages(); @@ -209,7 +210,7 @@ public class EuiccPortTest extends TelephonyTest { "BF2D18A016E3145A0A896700000000004523019F7001009F2401019000"); ResultCaptor resultCaptor = new ResultCaptor<>(); - mEuiccPort.mIsSupportsMultipleEnabledProfiles = true; // MEP capable + mEuiccPort.mSupportedMepMode = MultipleEnabledProfilesMode.MEP_B; // MEP capable mEuiccPort.getAllProfiles(resultCaptor, mHandler); processAllMessages(); @@ -231,7 +232,7 @@ public class EuiccPortTest extends TelephonyTest { "BF2D14A012E3105A0A896700000000004523FF9F7001009000"); ResultCaptor resultCaptor = new ResultCaptor<>(); - mEuiccPort.mIsSupportsMultipleEnabledProfiles = true; // MEP capable + mEuiccPort.mSupportedMepMode = MultipleEnabledProfilesMode.MEP_B; // MEP capable mEuiccPort.getAllProfiles(resultCaptor, mHandler); processAllMessages(); @@ -383,8 +384,7 @@ public class EuiccPortTest extends TelephonyTest { ResultCaptor resultCaptor = new ResultCaptor<>(); mMockIccCardStatus.mSlotPortMapping.mPortIndex = 1; - mEuiccPort.updateSupportMepProperties(true, - IccSlotStatus.MultipleEnabledProfilesMode.MEP_A1); + mEuiccPort.updateSupportedMepMode(MultipleEnabledProfilesMode.MEP_A1); mEuiccPort.update(mContext, mMockCi, mMockIccCardStatus, mEuiccCard); mEuiccPort.switchToProfile("98760000000000543210", true, resultCaptor, mHandler); processAllMessages(); -- GitLab From c6fba02c9ac85c95b1e1f45d75fbe5cf5bbd6ed3 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 15 Feb 2023 17:50:59 -0800 Subject: [PATCH 450/656] Support satellite service indications SatelliteServiceController will register a listener to the satellite service. When the service sends callbacks to the listener, notify the registrants with the results. Also create a util file to handle conversions between types defined in the service and the framework. Test: atest SatelliteManagerTest Bug: 261131816 Change-Id: I608057ff240e42e1a1e43487c571f550ec4b8297 --- .../com/android/internal/telephony/Phone.java | 29 +- .../telephony/SatelliteIndication.java | 9 +- .../satellite/SatelliteServiceController.java | 450 ++++++++++++------ .../satellite/SatelliteServiceUtils.java | 210 ++++++++ 4 files changed, 547 insertions(+), 151 deletions(-) create mode 100644 src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 28c0207cb6..c063fde861 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5319,8 +5319,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @param what User-defined message code. * @param obj User object. */ - public void registerForSatellitePointingInfoChanged(@NonNull Handler h, + public void registerForSatellitePositionInfoChanged(@NonNull Handler h, int what, @Nullable Object obj) { + //TODO: Rename CommandsInterface and other modules when updating HAL APIs. mCi.registerForSatellitePointingInfoChanged(h, what, obj); } @@ -5329,7 +5330,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * * @param h Handler to be removed from the registrant list. */ - public void unregisterForSatellitePointingInfoChanged(@NonNull Handler h) { + public void unregisterForSatellitePositionInfoChanged(@NonNull Handler h) { + //TODO: Rename CommandsInterface and other modules when updating HAL APIs. mCi.unregisterForSatellitePointingInfoChanged(h); } @@ -5342,7 +5344,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ public void registerForSatelliteDatagramsDelivered(@NonNull Handler h, int what, @Nullable Object obj) { - //TODO: Rename CommandsInterface and other modules when updating HAL APIs. + //TODO: Remove. mCi.registerForSatelliteMessagesTransferComplete(h, what, obj); } @@ -5352,7 +5354,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @param h Handler to be removed from the registrant list. */ public void unregisterForSatelliteDatagramsDelivered(@NonNull Handler h) { - //TODO: Rename CommandsInterface and other modules when updating HAL APIs. + //TODO: Remove. mCi.unregisterForSatelliteMessagesTransferComplete(h); } @@ -5413,23 +5415,23 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * Registers for satellite state change from satellite modem. + * Registers for satellite state changed from satellite modem. * * @param h Handler for notification message. * @param what User-defined message code. * @param obj User object. */ - public void registerForSatelliteModemStateChange(@NonNull Handler h, int what, + public void registerForSatelliteModemStateChanged(@NonNull Handler h, int what, @Nullable Object obj) { mCi.registerForSatelliteModeChanged(h, what, obj); } /** - * Unregisters for satellite state changes from satellite modem. + * Unregisters for satellite state changed from satellite modem. * * @param h Handler to be removed from registrant list. */ - public void unregisterForSatelliteModemStateChange(@NonNull Handler h) { + public void unregisterForSatelliteModemStateChanged(@NonNull Handler h) { mCi.unregisterForSatelliteModeChanged(h); } @@ -5461,19 +5463,20 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * @param what User-defined message code. * @param obj User object. */ - public void registerForNewSatelliteDatagram(@NonNull Handler h, int what, + public void registerForSatelliteDatagramsReceived(@NonNull Handler h, int what, @Nullable Object obj) { - //mCi.registerForNewSatelliteDatagram(h, what, obj); + // TODO: rename + mCi.registerForNewSatelliteMessages(h, what, obj); } - /** * Unregister to stop receiving incoming datagrams over satellite. * * @param h Handler to be removed from registrant list. */ - public void unregisterForNewSatelliteDatagram(@NonNull Handler h) { - //mCi.unregisterForNewSatelliteDatagram(h); + public void unregisterForSatelliteDatagramsReceived(@NonNull Handler h) { + // TODO: rename + mCi.unregisterForNewSatelliteMessages(h); } /** diff --git a/src/java/com/android/internal/telephony/SatelliteIndication.java b/src/java/com/android/internal/telephony/SatelliteIndication.java index 3d08fdf425..62fc0b43ec 100644 --- a/src/java/com/android/internal/telephony/SatelliteIndication.java +++ b/src/java/com/android/internal/telephony/SatelliteIndication.java @@ -28,6 +28,8 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_RA import android.hardware.radio.satellite.IRadioSatelliteIndication; import android.os.AsyncResult; +import android.telephony.satellite.SatelliteDatagram; +import android.util.Pair; /** * Interface declaring unsolicited radio indications for Satellite APIs. @@ -78,8 +80,13 @@ public class SatelliteIndication extends IRadioSatelliteIndication.Stub { if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_NEW_SATELLITE_MESSAGES); if (mRil.mNewSatelliteMessagesRegistrants != null) { + SatelliteDatagram[] datagrams = new SatelliteDatagram[messages.length]; + for (int i = 0; i < messages.length; i++) { + datagrams[i] = new SatelliteDatagram(messages[i].getBytes()); + } + // TODO: support pendingCount properly mRil.mNewSatelliteMessagesRegistrants.notifyRegistrants( - new AsyncResult(null, messages, null)); + new AsyncResult(null, new Pair<>(datagrams, messages.length), null)); } } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java index 7978be69f9..6a5f067223 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java @@ -24,9 +24,11 @@ import android.content.Intent; import android.content.ServiceConnection; import android.os.AsyncResult; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.RegistrantList; import android.os.RemoteException; import android.telephony.Rlog; import android.telephony.satellite.SatelliteCapabilities; @@ -35,17 +37,17 @@ import android.telephony.satellite.SatelliteManager; import android.telephony.satellite.SatelliteManager.SatelliteException; import android.telephony.satellite.stub.ISatellite; import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer; -import android.telephony.satellite.stub.SatelliteError; -import android.telephony.satellite.stub.SatelliteModemState; +import android.telephony.satellite.stub.ISatelliteListener; import android.telephony.satellite.stub.SatelliteService; import android.text.TextUtils; +import android.util.Pair; import com.android.internal.telephony.ExponentialBackoff; import com.android.internal.telephony.IBooleanConsumer; import com.android.internal.telephony.IIntegerConsumer; import java.util.Arrays; -import java.util.stream.Collectors; +import java.util.function.Consumer; /** * Satellite service controller to manage connections with the satellite service. @@ -65,6 +67,79 @@ public class SatelliteServiceController { private boolean mIsBound; private boolean mIsBinding; + @NonNull private final RegistrantList mSatelliteProvisionStateChangedRegistrants = + new RegistrantList(); + @NonNull private final RegistrantList mSatellitePositionInfoChangedRegistrants = + new RegistrantList(); + @NonNull private final RegistrantList mDatagramTransferStateChangedRegistrants = + new RegistrantList(); + @NonNull private final RegistrantList mSatelliteModemStateChangedRegistrants = + new RegistrantList(); + @NonNull private final RegistrantList mPendingDatagramCountRegistrants = new RegistrantList(); + @NonNull private final RegistrantList mSatelliteDatagramsReceivedRegistrants = + new RegistrantList(); + @NonNull private final RegistrantList mSatelliteRadioTechnologyChangedRegistrants = + new RegistrantList(); + + private boolean mIsSatelliteDemoModeEnabled = false; + + @NonNull private final ISatelliteListener mListener = new ISatelliteListener.Stub() { + @Override + public void onSatelliteProvisionStateChanged(boolean provisioned) { + mSatelliteProvisionStateChangedRegistrants.notifyResult(provisioned); + } + + @Override + public void onSatelliteDatagramsReceived( + android.telephony.satellite.stub.SatelliteDatagram[] datagrams, int pendingCount) { + mSatelliteDatagramsReceivedRegistrants.notifyResult(new Pair<>( + SatelliteServiceUtils.fromSatelliteDatagrams(datagrams), pendingCount)); + } + + @Override + public void onPendingDatagramCount(int count) { + mPendingDatagramCountRegistrants.notifyResult(count); + } + + @Override + public void onSatellitePositionChanged( + android.telephony.satellite.stub.PointingInfo pointingInfo) { + mSatellitePositionInfoChangedRegistrants.notifyResult( + SatelliteServiceUtils.fromPointingInfo(pointingInfo)); + } + + @Override + public void onSatelliteModemStateChanged(int state) { + mSatelliteModemStateChangedRegistrants.notifyResult( + SatelliteServiceUtils.fromSatelliteModemState(state)); + int datagramTransferState = SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN; + switch (state) { + case SatelliteManager.SATELLITE_MODEM_STATE_IDLE: + datagramTransferState = SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; + break; + case SatelliteManager.SATELLITE_MODEM_STATE_LISTENING: + datagramTransferState = + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING; + break; + case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING: + datagramTransferState = + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING; + break; + case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING: + datagramTransferState = + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RETRYING; + } + // TODO: properly notify the rest of the datagram transfer state changed parameters + mDatagramTransferStateChangedRegistrants.notifyResult(datagramTransferState); + } + + @Override + public void onSatelliteRadioTechnologyChanged(int technology) { + mSatelliteRadioTechnologyChangedRegistrants.notifyResult( + SatelliteServiceUtils.fromSatelliteRadioTechnology(technology)); + } + }; + /** * @return The singleton instance of SatelliteServiceController. */ @@ -192,7 +267,21 @@ public class SatelliteServiceController { } mSatelliteService = ISatellite.Stub.asInterface(service); mExponentialBackoff.stop(); - // TODO: register any listeners + try { + mSatelliteService.setSatelliteListener(mListener, new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = SatelliteServiceUtils.fromSatelliteError(result); + if (error != SatelliteManager.SATELLITE_ERROR_NONE) { + // TODO: Retry setSatelliteListener + } + logd("setSatelliteListener: " + error); + } + }); + } catch (RemoteException e) { + // TODO: Retry setSatelliteListener + logd("setSatelliteListener: RemoteException " + e); + } } @Override @@ -218,43 +307,217 @@ public class SatelliteServiceController { } /** - * Register the callback interface with satellite service. + * Registers for the satellite provision state changed. * - * @param message The Message to send to result of the operation to. + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForSatelliteProvisionStateChanged( + @NonNull Handler h, int what, @Nullable Object obj) { + mSatelliteProvisionStateChangedRegistrants.add(h, what, obj); + } + + /** + * Unregisters for the satellite provision state changed. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForSatelliteProvisionStateChanged(@NonNull Handler h) { + mSatelliteProvisionStateChangedRegistrants.remove(h); + } + + /** + * Registers for satellite position info changed from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForSatellitePositionInfoChanged( + @NonNull Handler h, int what, @Nullable Object obj) { + mSatellitePositionInfoChangedRegistrants.add(h, what, obj); + } + + /** + * Unregisters for satellite position info changed from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForSatellitePositionInfoChanged(@NonNull Handler h) { + mSatellitePositionInfoChangedRegistrants.remove(h); + } + + /** + * Registers for datagram transfer state changed. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForDatagramTransferStateChanged( + @NonNull Handler h, int what, @Nullable Object obj) { + mDatagramTransferStateChangedRegistrants.add(h, what, obj); + } + + /** + * Unregisters for datagram transfer state changed. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForDatagramTransferStateChanged(@NonNull Handler h) { + mDatagramTransferStateChangedRegistrants.remove(h); + } + + /** + * Registers for modem state changed from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForSatelliteModemStateChanged( + @NonNull Handler h, int what, @Nullable Object obj) { + mSatelliteModemStateChangedRegistrants.add(h, what, obj); + } + + /** + * Unregisters for modem state changed from satellite modem. + * + * @param h Handler to be removed from the registrant list. */ - public void setSatelliteListener(@NonNull Message message) { - // TODO: implement and add listener to param + public void unregisterForSatelliteModemStateChanged(@NonNull Handler h) { + mSatelliteModemStateChangedRegistrants.remove(h); } /** - * Enable or disable the satellite service listening mode. + * Registers for pending datagram count from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForPendingDatagramCount( + @NonNull Handler h, int what, @Nullable Object obj) { + mPendingDatagramCountRegistrants.add(h, what, obj); + } + + /** + * Unregisters for pending datagram count from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForPendingDatagramCount(@NonNull Handler h) { + mPendingDatagramCountRegistrants.remove(h); + } + + /** + * Registers for new datagrams received from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForSatelliteDatagramsReceived( + @NonNull Handler h, int what, @Nullable Object obj) { + mSatelliteDatagramsReceivedRegistrants.add(h, what, obj); + } + + /** + * Unregisters for new datagrams received from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForSatelliteDatagramsReceived(@NonNull Handler h) { + mSatelliteDatagramsReceivedRegistrants.remove(h); + } + + /** + * Registers for satellite radio technology changed from satellite modem. + * + * @param h Handler for notification message. + * @param what User-defined message code. + * @param obj User object. + */ + public void registerForSatelliteRadioTechnologyChanged( + @NonNull Handler h, int what, @Nullable Object obj) { + mSatelliteRadioTechnologyChangedRegistrants.add(h, what, obj); + } + + /** + * Unregisters for satellite radio technology changed from satellite modem. + * + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForSatelliteRadioTechnologyChanged(@NonNull Handler h) { + mSatelliteRadioTechnologyChangedRegistrants.remove(h); + } + + /** + * Request to enable or disable the satellite service listening mode. * Listening mode allows the satellite service to listen for incoming pages. * * @param enable True to enable satellite listening mode and false to disable. * @param message The Message to send to result of the operation to. */ - public void setSatelliteListeningEnabled(boolean enable, @NonNull Message message) { + public void requestSatelliteListeningEnabled(boolean enable, @NonNull Message message) { if (mSatelliteService != null) { try { - mSatelliteService.setSatelliteListeningEnabled(enable, new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - int error = fromSatelliteError(result); - logd("setSatelliteListeningEnabled: " + error); - Binder.withCleanCallingIdentity(() -> - sendMessageWithResult(message, null, error)); - } - }); + mSatelliteService.requestSatelliteListeningEnabled( + enable, mIsSatelliteDemoModeEnabled, new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = SatelliteServiceUtils.fromSatelliteError(result); + logd("requestSatelliteListeningEnabled: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); } catch (RemoteException e) { - loge("setSatelliteListeningEnabled: RemoteException " + e); + loge("requestSatelliteListeningEnabled: RemoteException " + e); sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); } } else { - loge("setSatelliteListeningEnabled: Satellite service is unavailable."); + loge("requestSatelliteListeningEnabled: Satellite service is unavailable."); sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); } } + /** + * Request to enable or disable the satellite service demo mode. + * + * @param enable {@code true} to enable satellite demo mode and {@code false} to disable. + * @return The error code of the request. + */ + @SatelliteManager.SatelliteError public int requestSatelliteDemoModeEnabled(boolean enable) { + if (mSatelliteService != null) { + logd("requestSatelliteDemoModeEnabled: " + enable); + mIsSatelliteDemoModeEnabled = enable; + return SatelliteManager.SATELLITE_ERROR_NONE; + } else { + loge("requestSatelliteDemoModeEnabled: Satellite service is unavailable."); + return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED; + } + } + + /** + * Request to get whether the satellite service demo mode is enabled. + * + * @param callback The callback to accept whether the satellite demo mode is enabled. + * @return The error code of the request. + */ + @SatelliteManager.SatelliteError public int requestIsSatelliteDemoModeEnabled( + @NonNull Consumer callback) { + if (mSatelliteService != null) { + logd("requestIsSatelliteDemoModeEnabled: " + mIsSatelliteDemoModeEnabled); + callback.accept(mIsSatelliteDemoModeEnabled); + return SatelliteManager.SATELLITE_ERROR_NONE; + } else { + loge("requestIsSatelliteDemoModeEnabled: Satellite service is unavailable."); + return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED; + } + } + /** * Request to enable or disable the satellite modem. If the satellite modem is enabled, * this will also disable the cellular modem, and if the satellite modem is disabled, @@ -269,7 +532,7 @@ public class SatelliteServiceController { mSatelliteService.requestSatelliteEnabled(enable, new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("setSatelliteEnabled: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -296,7 +559,7 @@ public class SatelliteServiceController { mSatelliteService.requestIsSatelliteEnabled(new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("requestIsSatelliteEnabled: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -333,7 +596,7 @@ public class SatelliteServiceController { mSatelliteService.requestIsSatelliteSupported(new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("requestIsSatelliteSupported: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -341,12 +604,9 @@ public class SatelliteServiceController { }, new IBooleanConsumer.Stub() { @Override public void accept(boolean result) { - // Convert for compatibility with SatelliteResponse - // TODO: This should just report result instead. - int[] supported = new int[] {result ? 1 : 0}; - logd("requestIsSatelliteSupported: " + Arrays.toString(supported)); + logd("requestIsSatelliteSupported: " + result); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( - message, supported, SatelliteManager.SATELLITE_ERROR_NONE)); + message, result, SatelliteManager.SATELLITE_ERROR_NONE)); } }); } catch (RemoteException e) { @@ -370,7 +630,7 @@ public class SatelliteServiceController { mSatelliteService.requestSatelliteCapabilities(new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("requestSatelliteCapabilities: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -379,7 +639,8 @@ public class SatelliteServiceController { @Override public void accept(android.telephony.satellite.stub.SatelliteCapabilities result) { - SatelliteCapabilities capabilities = fromSatelliteCapabilities(result); + SatelliteCapabilities capabilities = + SatelliteServiceUtils.fromSatelliteCapabilities(result); logd("requestSatelliteCapabilities: " + capabilities); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( message, capabilities, SatelliteManager.SATELLITE_ERROR_NONE)); @@ -398,7 +659,7 @@ public class SatelliteServiceController { /** * User started pointing to the satellite. * The satellite service should report the satellite pointing info via - * ISatelliteListener#onSatellitePointingInfoChanged as the user device/satellite moves. + * ISatelliteListener#onSatellitePositionChanged as the user device/satellite moves. * * @param message The Message to send to result of the operation to. */ @@ -408,7 +669,7 @@ public class SatelliteServiceController { mSatelliteService.startSendingSatellitePointingInfo(new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("startSendingSatellitePointingInfo: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -436,7 +697,7 @@ public class SatelliteServiceController { mSatelliteService.stopSendingSatellitePointingInfo(new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("stopSendingSatellitePointingInfo: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -463,7 +724,7 @@ public class SatelliteServiceController { mSatelliteService.requestMaxCharactersPerMOTextMessage(new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("requestMaxCharactersPerMOTextMessage: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -505,7 +766,7 @@ public class SatelliteServiceController { mSatelliteService.provisionSatelliteService(token, new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("provisionSatelliteService: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -535,7 +796,7 @@ public class SatelliteServiceController { mSatelliteService.deprovisionSatelliteService(token, new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("deprovisionSatelliteService: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -562,7 +823,7 @@ public class SatelliteServiceController { mSatelliteService.requestIsSatelliteProvisioned(new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("requestIsSatelliteProvisioned: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -589,8 +850,9 @@ public class SatelliteServiceController { } /** - * Poll the pending datagrams. - * The satellite service should report the new datagrams via ISatelliteListener#onNewDatagrams. + * Poll the pending datagrams to be received over satellite. + * The satellite service should check if there are any pending datagrams to be received over + * satellite and report them via ISatelliteListener#onSatelliteDatagramsReceived. * * @param message The Message to send to result of the operation to. */ @@ -600,7 +862,7 @@ public class SatelliteServiceController { mSatelliteService.pollPendingSatelliteDatagrams(new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("pollPendingSatelliteDatagrams: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -618,8 +880,6 @@ public class SatelliteServiceController { /** * Send datagram over satellite. - * Once sent, the satellite service should report whether the operation was successful via - * SatelliteListener#onDatagramsDelivered. * * @param datagram Datagram to send in byte format. * @param isEmergency Whether this is an emergency datagram. @@ -629,11 +889,13 @@ public class SatelliteServiceController { @NonNull Message message) { if (mSatelliteService != null) { try { - mSatelliteService.sendSatelliteDatagram(toSatelliteDatagram(datagram), isEmergency, + mSatelliteService.sendSatelliteDatagram( + SatelliteServiceUtils.toSatelliteDatagram(datagram), + mIsSatelliteDemoModeEnabled, isEmergency, new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("sendSatelliteDatagram: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -662,7 +924,7 @@ public class SatelliteServiceController { mSatelliteService.requestSatelliteModemState(new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("requestSatelliteModemState: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -671,7 +933,7 @@ public class SatelliteServiceController { @Override public void accept(int result) { // Convert SatelliteModemState from service to frameworks definition. - int modemState = fromSatelliteModemState(result); + int modemState = SatelliteServiceUtils.fromSatelliteModemState(result); logd("requestSatelliteModemState: " + modemState); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( message, modemState, SatelliteManager.SATELLITE_ERROR_NONE)); @@ -699,7 +961,7 @@ public class SatelliteServiceController { new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("requestIsSatelliteCommunicationAllowedForCurrentLocation: " + error); Binder.withCleanCallingIdentity(() -> @@ -708,13 +970,10 @@ public class SatelliteServiceController { }, new IBooleanConsumer.Stub() { @Override public void accept(boolean result) { - // Convert for compatibility with SatelliteResponse - // TODO: This should just report result instead. - int[] allowed = new int[] {result ? 1 : 0}; logd("requestIsSatelliteCommunicationAllowedForCurrentLocation: " - + Arrays.toString(allowed)); + + result); Binder.withCleanCallingIdentity(() -> sendMessageWithResult( - message, allowed, SatelliteManager.SATELLITE_ERROR_NONE)); + message, result, SatelliteManager.SATELLITE_ERROR_NONE)); } }); } catch (RemoteException e) { @@ -743,7 +1002,7 @@ public class SatelliteServiceController { new IIntegerConsumer.Stub() { @Override public void accept(int result) { - int error = fromSatelliteError(result); + int error = SatelliteServiceUtils.fromSatelliteError(result); logd("requestTimeForNextSatelliteVisibility: " + error); Binder.withCleanCallingIdentity(() -> sendMessageWithResult(message, null, error)); @@ -776,89 +1035,6 @@ public class SatelliteServiceController { message.sendToTarget(); } - @SatelliteManager.SatelliteError private static int fromSatelliteError(int error) { - switch (error) { - case SatelliteError.ERROR_NONE: - return SatelliteManager.SATELLITE_ERROR_NONE; - case SatelliteError.SATELLITE_ERROR: - return SatelliteManager.SATELLITE_ERROR; - case SatelliteError.SERVER_ERROR: - return SatelliteManager.SATELLITE_SERVER_ERROR; - case SatelliteError.SERVICE_ERROR: - return SatelliteManager.SATELLITE_SERVICE_ERROR; - case SatelliteError.MODEM_ERROR: - return SatelliteManager.SATELLITE_MODEM_ERROR; - case SatelliteError.NETWORK_ERROR: - return SatelliteManager.SATELLITE_NETWORK_ERROR; - case SatelliteError.INVALID_TELEPHONY_STATE: - return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - case SatelliteError.INVALID_MODEM_STATE: - return SatelliteManager.SATELLITE_INVALID_MODEM_STATE; - case SatelliteError.INVALID_ARGUMENTS: - return SatelliteManager.SATELLITE_INVALID_ARGUMENTS; - case SatelliteError.REQUEST_FAILED: - return SatelliteManager.SATELLITE_REQUEST_FAILED; - case SatelliteError.RADIO_NOT_AVAILABLE: - return SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE; - case SatelliteError.REQUEST_NOT_SUPPORTED: - return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED; - case SatelliteError.NO_RESOURCES: - return SatelliteManager.SATELLITE_NO_RESOURCES; - case SatelliteError.SERVICE_NOT_PROVISIONED: - return SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED; - case SatelliteError.SERVICE_PROVISION_IN_PROGRESS: - return SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS; - case SatelliteError.REQUEST_ABORTED: - return SatelliteManager.SATELLITE_REQUEST_ABORTED; - case SatelliteError.SATELLITE_ACCESS_BARRED: - return SatelliteManager.SATELLITE_ACCESS_BARRED; - case SatelliteError.NETWORK_TIMEOUT: - return SatelliteManager.SATELLITE_NETWORK_TIMEOUT; - case SatelliteError.SATELLITE_NOT_REACHABLE: - return SatelliteManager.SATELLITE_NOT_REACHABLE; - case SatelliteError.NOT_AUTHORIZED: - return SatelliteManager.SATELLITE_NOT_AUTHORIZED; - } - loge("Received invalid satellite service error: " + error); - return SatelliteManager.SATELLITE_SERVICE_ERROR; - } - - @SatelliteManager.SatelliteModemState private static int fromSatelliteModemState( - int modemState) { - switch (modemState) { - case SatelliteModemState.SATELLITE_MODEM_STATE_IDLE: - return SatelliteManager.SATELLITE_MODEM_STATE_IDLE; - case SatelliteModemState.SATELLITE_MODEM_STATE_LISTENING: - return SatelliteManager.SATELLITE_MODEM_STATE_LISTENING; - case SatelliteModemState.SATELLITE_MODEM_STATE_MESSAGE_TRANSFERRING: - return SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; - case SatelliteModemState.SATELLITE_MODEM_STATE_OFF: - return SatelliteManager.SATELLITE_MODEM_STATE_OFF; - } - // TODO: create and return SATELLITE_MODEM_STATE_UNKNOWN - loge("Received invalid modem state: " + modemState); - return SatelliteManager.SATELLITE_MODEM_STATE_OFF; - } - - @Nullable private static SatelliteCapabilities fromSatelliteCapabilities( - @Nullable android.telephony.satellite.stub.SatelliteCapabilities capabilities) { - if (capabilities == null) return null; - return new SatelliteCapabilities( - Arrays.stream(capabilities.supportedRadioTechnologies) - .boxed().collect(Collectors.toSet()), - capabilities.isAlwaysOn, - capabilities.needsPointingToSatellite, - capabilities.needsSeparateSimProfile); - } - - @Nullable private static android.telephony.satellite.stub.SatelliteDatagram toSatelliteDatagram( - @Nullable SatelliteDatagram datagram) { - android.telephony.satellite.stub.SatelliteDatagram converted = - new android.telephony.satellite.stub.SatelliteDatagram(); - converted.data = datagram.getSatelliteDatagram(); - return converted; - } - private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java new file mode 100644 index 0000000000..bdf031421c --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2023 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.NonNull; +import android.annotation.Nullable; +import android.telephony.Rlog; +import android.telephony.satellite.PointingInfo; +import android.telephony.satellite.SatelliteCapabilities; +import android.telephony.satellite.SatelliteDatagram; +import android.telephony.satellite.SatelliteManager; +import android.telephony.satellite.stub.NTRadioTechnology; +import android.telephony.satellite.stub.SatelliteError; +import android.telephony.satellite.stub.SatelliteModemState; + +import java.util.Arrays; +import java.util.stream.Collectors; + +/** + * Utils class for satellite service <-> framework conversions + */ +public class SatelliteServiceUtils { + private static final String TAG = "SatelliteServiceUtils"; + + /** + * Convert radio technology from service definition to framework definition. + * @param radioTechnology The NTRadioTechnology from the satellite service. + * @return The converted NTRadioTechnology for the framework. + */ + @SatelliteManager.NTRadioTechnology + public static int fromSatelliteRadioTechnology(int radioTechnology) { + switch (radioTechnology) { + case NTRadioTechnology.NB_IOT_NTN: + return SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN; + case NTRadioTechnology.NR_NTN: + return SatelliteManager.NT_RADIO_TECHNOLOGY_NR_NTN; + case NTRadioTechnology.EMTC_NTN: + return SatelliteManager.NT_RADIO_TECHNOLOGY_EMTC_NTN; + case NTRadioTechnology.PROPRIETARY: + return SatelliteManager.NT_RADIO_TECHNOLOGY_PROPRIETARY; + default: + loge("Received invalid radio technology: " + radioTechnology); + return SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN; + } + } + + /** + * Convert satellite error from service definition to framework definition. + * @param error The SatelliteError from the satellite service. + * @return The converted SatelliteError for the framework. + */ + @SatelliteManager.SatelliteError public static int fromSatelliteError(int error) { + switch (error) { + case SatelliteError.ERROR_NONE: + return SatelliteManager.SATELLITE_ERROR_NONE; + case SatelliteError.SATELLITE_ERROR: + return SatelliteManager.SATELLITE_ERROR; + case SatelliteError.SERVER_ERROR: + return SatelliteManager.SATELLITE_SERVER_ERROR; + case SatelliteError.SERVICE_ERROR: + return SatelliteManager.SATELLITE_SERVICE_ERROR; + case SatelliteError.MODEM_ERROR: + return SatelliteManager.SATELLITE_MODEM_ERROR; + case SatelliteError.NETWORK_ERROR: + return SatelliteManager.SATELLITE_NETWORK_ERROR; + case SatelliteError.INVALID_TELEPHONY_STATE: + return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + case SatelliteError.INVALID_MODEM_STATE: + return SatelliteManager.SATELLITE_INVALID_MODEM_STATE; + case SatelliteError.INVALID_ARGUMENTS: + return SatelliteManager.SATELLITE_INVALID_ARGUMENTS; + case SatelliteError.REQUEST_FAILED: + return SatelliteManager.SATELLITE_REQUEST_FAILED; + case SatelliteError.RADIO_NOT_AVAILABLE: + return SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE; + case SatelliteError.REQUEST_NOT_SUPPORTED: + return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED; + case SatelliteError.NO_RESOURCES: + return SatelliteManager.SATELLITE_NO_RESOURCES; + case SatelliteError.SERVICE_NOT_PROVISIONED: + return SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED; + case SatelliteError.SERVICE_PROVISION_IN_PROGRESS: + return SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS; + case SatelliteError.REQUEST_ABORTED: + return SatelliteManager.SATELLITE_REQUEST_ABORTED; + case SatelliteError.SATELLITE_ACCESS_BARRED: + return SatelliteManager.SATELLITE_ACCESS_BARRED; + case SatelliteError.NETWORK_TIMEOUT: + return SatelliteManager.SATELLITE_NETWORK_TIMEOUT; + case SatelliteError.SATELLITE_NOT_REACHABLE: + return SatelliteManager.SATELLITE_NOT_REACHABLE; + case SatelliteError.NOT_AUTHORIZED: + return SatelliteManager.SATELLITE_NOT_AUTHORIZED; + } + loge("Received invalid satellite service error: " + error); + return SatelliteManager.SATELLITE_SERVICE_ERROR; + } + + /** + * Convert satellite modem state from service definition to framework definition. + * @param modemState The SatelliteModemState from the satellite service. + * @return The converted SatelliteModemState for the framework. + */ + @SatelliteManager.SatelliteModemState + public static int fromSatelliteModemState(int modemState) { + switch (modemState) { + case SatelliteModemState.SATELLITE_MODEM_STATE_IDLE: + return SatelliteManager.SATELLITE_MODEM_STATE_IDLE; + case SatelliteModemState.SATELLITE_MODEM_STATE_LISTENING: + return SatelliteManager.SATELLITE_MODEM_STATE_LISTENING; + case SatelliteModemState.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING: + return SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; + case SatelliteModemState.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING: + return SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING; + case SatelliteModemState.SATELLITE_MODEM_STATE_OFF: + return SatelliteManager.SATELLITE_MODEM_STATE_OFF; + default: + loge("Received invalid modem state: " + modemState); + return SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; + } + } + + /** + * Convert SatelliteCapabilities from service definition to framework definition. + * @param capabilities The SatelliteCapabilities from the satellite service. + * @return The converted SatelliteCapabilities for the framework. + */ + @Nullable public static SatelliteCapabilities fromSatelliteCapabilities( + @Nullable android.telephony.satellite.stub.SatelliteCapabilities capabilities) { + if (capabilities == null) return null; + int[] radioTechnologies = capabilities.supportedRadioTechnologies == null + ? new int[0] : capabilities.supportedRadioTechnologies; + return new SatelliteCapabilities( + Arrays.stream(radioTechnologies) + .map(SatelliteServiceUtils::fromSatelliteRadioTechnology) + .boxed().collect(Collectors.toSet()), + capabilities.isAlwaysOn, + capabilities.needsPointingToSatellite, + capabilities.needsSeparateSimProfile); + } + + /** + * Convert PointingInfo from service definition to framework definition. + * @param pointingInfo The PointingInfo from the satellite service. + * @return The converted PointingInfo for the framework. + */ + @Nullable public static PointingInfo fromPointingInfo( + android.telephony.satellite.stub.PointingInfo pointingInfo) { + if (pointingInfo == null) return null; + return new PointingInfo(pointingInfo.satelliteAzimuth, pointingInfo.satelliteElevation, + pointingInfo.antennaAzimuth, pointingInfo.antennaPitch, pointingInfo.antennaRoll); + } + + /** + * Convert SatelliteDatagram from service definition to framework definition. + * @param datagram The SatelliteDatagram from the satellite service. + * @return The converted SatelliteDatagram for the framework. + */ + @Nullable public static SatelliteDatagram fromSatelliteDatagram( + android.telephony.satellite.stub.SatelliteDatagram datagram) { + if (datagram == null) return null; + byte[] data = datagram.data == null ? new byte[0] : datagram.data; + return new SatelliteDatagram(data); + } + + /** + * Convert SatelliteDatagram[] from service definition to framework definition. + * @param datagrams The SatelliteDatagram[] from the satellite service. + * @return The converted SatelliteDatagram[] for the framework. + */ + @Nullable public static SatelliteDatagram[] fromSatelliteDatagrams( + android.telephony.satellite.stub.SatelliteDatagram[] datagrams) { + SatelliteDatagram[] array = new SatelliteDatagram[datagrams.length]; + for (int i = 0; i < datagrams.length; i++) { + array[i] = fromSatelliteDatagram(datagrams[i]); + } + return array; + } + + /** + * Convert SatelliteDatagram from framework definition to service definition. + * @param datagram The SatelliteDatagram from the framework. + * @return The converted SatelliteDatagram for the satellite service. + */ + @Nullable public static android.telephony.satellite.stub.SatelliteDatagram toSatelliteDatagram( + @Nullable SatelliteDatagram datagram) { + android.telephony.satellite.stub.SatelliteDatagram converted = + new android.telephony.satellite.stub.SatelliteDatagram(); + converted.data = datagram.getSatelliteDatagram(); + return converted; + } + + private static void loge(@NonNull String log) { + Rlog.e(TAG, log); + } +} -- GitLab From 6931c9eb8bb0333d031929eda9762cfd00c0859e Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 17 Feb 2023 23:08:56 -0800 Subject: [PATCH 451/656] Migrated unit test to the new subscription manager Bug: 268654362 Test: atest FrameworksTelephonyTests Change-Id: I355103117c0ad00bb6c6192c3f4c6585fbaf10a8 --- .../telephony/MultiSimSettingController.java | 1 + .../internal/telephony/ConnectionTest.java | 3 +- .../internal/telephony/GsmCdmaPhoneTest.java | 71 ++- .../telephony/IccSmsInterfaceManagerTest.java | 16 +- .../MultiSimSettingControllerTest.java | 590 ++++++++---------- .../PhoneConfigurationManagerTest.java | 47 +- .../telephony/PhoneSubInfoControllerTest.java | 4 + .../telephony/ProxyControllerTest.java | 4 - .../telephony/ServiceStateTrackerTest.java | 11 + .../telephony/SubscriptionControllerTest.java | 2 +- .../SubscriptionInfoUpdaterTest.java | 1 + .../internal/telephony/TelephonyTest.java | 34 +- .../data/CellularNetworkValidatorTest.java | 3 + .../data/DataNetworkControllerTest.java | 7 + .../data/DataSettingsManagerTest.java | 12 +- .../telephony/data/PhoneSwitcherTest.java | 83 ++- .../emergency/EmergencyNumberTrackerTest.java | 39 +- .../telephony/gsm/GsmSmsDispatcherTest.java | 7 +- .../imsphone/ImsPhoneCallTrackerTest.java | 4 + .../telephony/imsphone/ImsPhoneTest.java | 64 +- .../telephony/metrics/PerSimStatusTest.java | 65 ++ .../SubscriptionManagerServiceTest.java | 1 + .../telephony/uicc/UiccProfileTest.java | 7 + .../internal/telephony/uicc/UiccSlotTest.java | 51 +- 24 files changed, 707 insertions(+), 420 deletions(-) diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index f188ceb1e1..7e87b5fa2a 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -814,6 +814,7 @@ public class MultiSimSettingController extends Handler { @TelephonyManager.DefaultSubscriptionSelectType int simSelectDialogType = getSimSelectDialogType( change, dataSelected, voiceSelected, smsSelected); + log("sendSubChangeNotificationIfNeeded: simSelectDialogType=" + simSelectDialogType); SimCombinationWarningParams simCombinationParams = getSimCombinationWarningParams(change); if (simSelectDialogType != EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE diff --git a/tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java index 39491613a1..0bce5cbd07 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ConnectionTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.when; import android.os.Handler; import android.os.Looper; + import com.android.internal.telephony.emergency.EmergencyNumberTracker; import org.junit.After; @@ -42,7 +43,6 @@ public class ConnectionTest extends TelephonyTest { // Mocked classes protected Call mCall; - protected GsmCdmaPhone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. protected EmergencyNumberTracker mEmergencyNumberTracker2; protected Connection.PhoneFactoryProxy mPhoneFactoryProxy; protected Connection mTestConnection; @@ -127,7 +127,6 @@ public class ConnectionTest extends TelephonyTest { doReturn(mPhone).when(mCT).getPhone(); replaceInstance(Handler.class, "mLooper", mCT, Looper.getMainLooper()); - mPhone2 = mock(GsmCdmaPhone.class); mEmergencyNumberTracker2 = mock(EmergencyNumberTracker.class); doReturn(mEmergencyNumberTracker2).when(mPhone2).getEmergencyNumberTracker(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index b893398617..793e3aa760 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -79,7 +79,6 @@ import android.telephony.NetworkRegistrationInfo; import android.telephony.RadioAccessFamily; import android.telephony.ServiceState; import android.telephony.SmsCbMessage; -import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.ims.ImsCallProfile; @@ -95,6 +94,7 @@ import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.imsphone.ImsPhone; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.test.SimulatedCommandsVerifier; @@ -1099,12 +1099,15 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // invalid subId doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionController). getSubId(anyInt()); + doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionManagerService) + .getSubId(anyInt()); assertEquals(false, mPhoneUT.getCallForwardingIndicator()); // valid subId, sharedPreference not present int subId1 = 0; int subId2 = 1; doReturn(subId1).when(mSubscriptionController).getSubId(anyInt()); + doReturn(subId1).when(mSubscriptionManagerService).getSubId(anyInt()); assertEquals(false, mPhoneUT.getCallForwardingIndicator()); // old sharedPreference present @@ -1127,6 +1130,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // check for another subId doReturn(subId2).when(mSubscriptionController).getSubId(anyInt()); + doReturn(subId2).when(mSubscriptionManagerService).getSubId(anyInt()); assertEquals(false, mPhoneUT.getCallForwardingIndicator()); // set value for the new subId in sharedPreference @@ -1136,6 +1140,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // switching back to previous subId, stored value should still be available doReturn(subId1).when(mSubscriptionController).getSubId(anyInt()); + doReturn(subId1).when(mSubscriptionManagerService).getSubId(anyInt()); assertEquals(true, mPhoneUT.getCallForwardingIndicator()); // cleanup @@ -1295,6 +1300,8 @@ public class GsmCdmaPhoneTest extends TelephonyTest { Message.obtain(mPhoneUT, EVENT_UICC_APPS_ENABLEMENT_STATUS_CHANGED, new AsyncResult(null, true, null)).sendToTarget(); processAllMessages(); + + verify(mSubscriptionManagerService, never()).getAllSubInfoList(anyString(), anyString()); verify(mSubscriptionController, never()).getSubInfoForIccId(any()); // Have IccId defined. But expected value and current value are the same. So no RIL command @@ -1303,7 +1310,12 @@ public class GsmCdmaPhoneTest extends TelephonyTest { doReturn(iccId).when(mUiccSlot).getIccId(anyInt()); Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget(); processAllMessages(); - verify(mSubscriptionController).getSubInfoForIccId(iccId); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService).getAllSubInfoList(anyString(), + nullable(String.class)); + } else { + verify(mSubscriptionController).getSubInfoForIccId(iccId); + } verify(mMockCi, never()).enableUiccApplications(anyBoolean(), any()); } @@ -1475,6 +1487,8 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void testEventCarrierConfigChanged() { doReturn(null).when(mSubscriptionController).getSubscriptionProperty(anyInt(), eq(SubscriptionManager.NR_ADVANCED_CALLING_ENABLED)); + doReturn(null).when(mSubscriptionManagerService).getSubscriptionProperty(anyInt(), + eq(SubscriptionManager.NR_ADVANCED_CALLING_ENABLED), anyString(), anyString()); mPhoneUT.mCi = mMockCi; mPhoneUT.sendMessage(mPhoneUT.obtainMessage(Phone.EVENT_CARRIER_CONFIG_CHANGED)); @@ -1544,9 +1558,12 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void testLoadAllowedNetworksFromSubscriptionDatabase_loadTheNullValue_isLoadedTrue() { int subId = 1; doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); + doReturn(subId).when(mSubscriptionManagerService).getSubId(anyInt()); doReturn(null).when(mSubscriptionController).getSubscriptionProperty(anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); + doReturn(null).when(mSubscriptionManagerService).getSubscriptionProperty(anyInt(), + eq(SubscriptionManager.ALLOWED_NETWORK_TYPES), anyString(), anyString()); mPhoneUT.loadAllowedNetworksFromSubscriptionDatabase(); @@ -1558,10 +1575,13 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void testLoadAllowedNetworksFromSubscriptionDatabase_subIdNotValid_isLoadedFalse() { int subId = -1; doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); + doReturn(subId).when(mSubscriptionManagerService).getSubId(anyInt()); when(mSubscriptionController.getSubscriptionProperty(anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES))).thenReturn(null); - + when(mSubscriptionManagerService.getSubscriptionProperty(anyInt(), + eq(SubscriptionManager.ALLOWED_NETWORK_TYPES), anyString(), anyString())) + .thenReturn(null); mPhoneUT.loadAllowedNetworksFromSubscriptionDatabase(); @@ -1572,12 +1592,18 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void testLoadAllowedNetworksFromSubscriptionDatabase_allValidData() { int subId = 1; doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); + doReturn(subId).when(mSubscriptionManagerService).getSubId(anyInt()); // 13 == TelephonyManager.NETWORK_TYPE_LTE // NR_BITMASK == 4096 == 1 << (13 - 1) String validSerializedNetworkMap = "user=4096,power=4096,carrier=4096,enable_2g=4096"; doReturn(validSerializedNetworkMap).when(mSubscriptionController).getSubscriptionProperty( anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); + SubscriptionInfoInternal si = new SubscriptionInfoInternal.Builder() + .setId(1) + .setAllowedNetworkTypesForReasons(validSerializedNetworkMap) + .build(); + doReturn(si).when(mSubscriptionManagerService).getSubscriptionInfoInternal(eq(1)); assertFalse(mPhoneUT.isAllowedNetworkTypesLoadedFromDb()); mPhoneUT.loadAllowedNetworksFromSubscriptionDatabase(); @@ -1593,6 +1619,7 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void testLoadAllowedNetworksFromSubscriptionDatabase_invalidKeys() { int subId = 1; doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); + doReturn(subId).when(mSubscriptionManagerService).getSubId(anyInt()); // 13 == TelephonyManager.NETWORK_TYPE_LTE // NR_BITMASK == 4096 == 1 << (13 - 1) @@ -1600,6 +1627,11 @@ public class GsmCdmaPhoneTest extends TelephonyTest { "user=4096,power=4096,carrier=4096,enable_2g=4096,-1=4096"; doReturn(validSerializedNetworkMap).when(mSubscriptionController).getSubscriptionProperty( anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); + SubscriptionInfoInternal si = new SubscriptionInfoInternal.Builder() + .setId(1) + .setAllowedNetworkTypesForReasons(validSerializedNetworkMap) + .build(); + doReturn(si).when(mSubscriptionManagerService).getSubscriptionInfoInternal(eq(1)); assertFalse(mPhoneUT.isAllowedNetworkTypesLoadedFromDb()); mPhoneUT.loadAllowedNetworksFromSubscriptionDatabase(); @@ -1615,12 +1647,18 @@ public class GsmCdmaPhoneTest extends TelephonyTest { public void testLoadAllowedNetworksFromSubscriptionDatabase_invalidValues() { int subId = 1; doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); + doReturn(subId).when(mSubscriptionManagerService).getSubId(anyInt()); // 19 == TelephonyManager.NETWORK_TYPE_NR // NR_BITMASK == 524288 == 1 << 19 String validSerializedNetworkMap = "user=4096,power=4096,carrier=4096,enable_2g=-1"; doReturn(validSerializedNetworkMap).when(mSubscriptionController).getSubscriptionProperty( anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); + SubscriptionInfoInternal si = new SubscriptionInfoInternal.Builder() + .setId(1) + .setAllowedNetworkTypesForReasons(validSerializedNetworkMap) + .build(); + doReturn(si).when(mSubscriptionManagerService).getSubscriptionInfoInternal(eq(1)); mPhoneUT.loadAllowedNetworksFromSubscriptionDatabase(); @@ -1767,8 +1805,9 @@ public class GsmCdmaPhoneTest extends TelephonyTest { } - private SubscriptionInfo makeSubscriptionInfo(boolean isOpportunistic, int usageSetting) { - return new SubscriptionInfo.Builder() + private SubscriptionInfoInternal makeSubscriptionInfoInternal( + boolean isOpportunistic, int usageSetting) { + return new SubscriptionInfoInternal.Builder() .setId(1) .setIccId("xxxxxxxxx") .setSimSlotIndex(1) @@ -1779,8 +1818,8 @@ public class GsmCdmaPhoneTest extends TelephonyTest { .setMcc("001") .setMnc("01") .setCountryIso("us") - .setEmbedded(true) - .setOpportunistic(isOpportunistic) + .setEmbedded(1) + .setOpportunistic(isOpportunistic ? 1 : 0) .setCarrierId(1) .setProfileClass(SubscriptionManager.PROFILE_CLASS_PROVISIONING) .setUsageSetting(usageSetting) @@ -1793,10 +1832,12 @@ public class GsmCdmaPhoneTest extends TelephonyTest { setupUsageSettingResources(); mPhoneUT.mCi = mMockCi; - final SubscriptionInfo si = makeSubscriptionInfo( + final SubscriptionInfoInternal si = makeSubscriptionInfoInternal( false, SubscriptionManager.USAGE_SETTING_DATA_CENTRIC); - doReturn(si).when(mSubscriptionController).getSubscriptionInfo(anyInt()); + doReturn(si.toSubscriptionInfo()).when(mSubscriptionController) + .getSubscriptionInfo(anyInt()); + doReturn(si).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); mPhoneUT.updateUsageSetting(); processAllMessages(); @@ -1817,9 +1858,11 @@ public class GsmCdmaPhoneTest extends TelephonyTest { setupUsageSettingResources(); mPhoneUT.mCi = mMockCi; - final SubscriptionInfo si = makeSubscriptionInfo( + final SubscriptionInfoInternal si = makeSubscriptionInfoInternal( true, SubscriptionManager.USAGE_SETTING_DEFAULT); - doReturn(si).when(mSubscriptionController).getSubscriptionInfo(anyInt()); + doReturn(si.toSubscriptionInfo()).when(mSubscriptionController) + .getSubscriptionInfo(anyInt()); + doReturn(si).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); mPhoneUT.updateUsageSetting(); processAllMessages(); @@ -1840,11 +1883,13 @@ public class GsmCdmaPhoneTest extends TelephonyTest { setupUsageSettingResources(); mPhoneUT.mCi = mMockCi; - final SubscriptionInfo si = makeSubscriptionInfo( + final SubscriptionInfoInternal si = makeSubscriptionInfoInternal( false, SubscriptionManager.USAGE_SETTING_DEFAULT); assertNotNull(si); - doReturn(si).when(mSubscriptionController).getSubscriptionInfo(anyInt()); + doReturn(si.toSubscriptionInfo()).when(mSubscriptionController) + .getSubscriptionInfo(anyInt()); + doReturn(si).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); mPhoneUT.updateUsageSetting(); processAllMessages(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/IccSmsInterfaceManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/IccSmsInterfaceManagerTest.java index dc24683405..4012e98cae 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/IccSmsInterfaceManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/IccSmsInterfaceManagerTest.java @@ -18,13 +18,6 @@ package com.android.internal.telephony; import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; -import android.os.AsyncResult; -import android.os.Message; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import androidx.test.filters.SmallTest; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -34,6 +27,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.os.AsyncResult; +import android.os.Message; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + import com.android.internal.telephony.emergency.EmergencyNumberTracker; import org.junit.After; @@ -53,7 +53,6 @@ public class IccSmsInterfaceManagerTest extends TelephonyTest { // Mocked classes private SmsPermissions mMockSmsPermissions; - protected GsmCdmaPhone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. protected EmergencyNumberTracker mEmergencyNumberTracker2; protected IccSmsInterfaceManager.PhoneFactoryProxy mPhoneFactoryProxy; @@ -67,7 +66,6 @@ public class IccSmsInterfaceManagerTest extends TelephonyTest { mPhoneFactoryProxy = mock(IccSmsInterfaceManager.PhoneFactoryProxy.class); mIccSmsInterfaceManager.setPhoneFactoryProxy(mPhoneFactoryProxy); - mPhone2 = mock(GsmCdmaPhone.class); mEmergencyNumberTracker2 = mock(EmergencyNumberTracker.class); doReturn(mEmergencyNumberTracker2).when(mPhone2).getEmergencyNumberTracker(); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index f5d617ee2a..3c1b159561 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -34,6 +34,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -57,6 +58,7 @@ import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; import com.android.internal.telephony.data.DataSettingsManager; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import org.junit.After; import org.junit.Assert; @@ -84,64 +86,74 @@ public class MultiSimSettingControllerTest extends TelephonyTest { private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; // Mocked classes - private SubscriptionController mSubControllerMock; - private ISub mMockedIsub; private Phone mPhoneMock1; private Phone mPhoneMock2; private DataSettingsManager mDataSettingsManagerMock1; private DataSettingsManager mDataSettingsManagerMock2; private CommandsInterface mMockCi; - private final SubscriptionInfo mSubInfo1 = new SubscriptionInfo.Builder() - .setId(1) - .setIccId("subInfo1 IccId") - .setSimSlotIndex(0) - .setDisplayName("T-mobile") - .setCarrierName("T-mobile") - .setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) - .setIconTint(255) - .setNumber("12345") - .setMcc("310") - .setMnc("260") - .setCountryIso("us") - .build(); - - private SubscriptionInfo mSubInfo2 = new SubscriptionInfo.Builder(mSubInfo1) - .setId(2) - .setIccId("subInfo2 IccId") - .setGroupUuid(mGroupUuid1.toString()) - .build(); - - private SubscriptionInfo mSubInfo3 = new SubscriptionInfo.Builder(mSubInfo1) - .setId(3) - .setIccId("subInfo3 IccId") - .setGroupUuid(mGroupUuid1.toString()) - .build(); - - private SubscriptionInfo mSubInfo4 = new SubscriptionInfo.Builder(mSubInfo1) - .setId(4) - .setIccId("subInfo4 IccId") - .setGroupUuid(mGroupUuid1.toString()) - .build(); + private final SubscriptionInfoInternal[] mSubInfo = new SubscriptionInfoInternal[10]; + + private void initializeSubs() { + mSubInfo[1] = new SubscriptionInfoInternal.Builder() + .setId(1) + .setIccId("subInfo1 IccId") + .setSimSlotIndex(0) + .setDisplayName("T-mobile") + .setCarrierName("T-mobile") + .setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER) + .setIconTint(255) + .setNumber("12345") + .setMcc("310") + .setMnc("260") + .setCountryIso("us") + .build(); + + mSubInfo[2] = new SubscriptionInfoInternal.Builder(mSubInfo[1]) + .setId(2) + .setIccId("subInfo2 IccId") + .setSimSlotIndex(1) + .setGroupUuid(mGroupUuid1.toString()) + .build(); + + mSubInfo[3] = new SubscriptionInfoInternal.Builder(mSubInfo[1]) + .setId(3) + .setIccId("subInfo3 IccId") + .setSimSlotIndex(-1) + .setGroupUuid(mGroupUuid1.toString()) + .build(); + + mSubInfo[4] = new SubscriptionInfoInternal.Builder( + mSubInfo[1]) + .setId(4) + .setIccId("subInfo4 IccId") + .setSimSlotIndex(-1) + .setGroupUuid(mGroupUuid1.toString()) + .build(); + } + + private void setSimSlotIndex(int subId, int simSlotIndex) { + mSubInfo[subId] = new SubscriptionInfoInternal.Builder(mSubInfo[subId]) + .setSimSlotIndex(simSlotIndex).build(); + } private void sendCarrierConfigChanged(int phoneId, int subId) { mCarrierConfigChangeListener.onCarrierConfigChanged(phoneId, subId, TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); } - @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); - mSubControllerMock = mock(SubscriptionController.class); + enableSubscriptionManagerService(true); + initializeSubs(); mPhoneMock1 = mock(Phone.class); mPhoneMock2 = mock(Phone.class); mDataSettingsManagerMock1 = mock(DataSettingsManager.class); mDataSettingsManagerMock2 = mock(DataSettingsManager.class); mMockCi = mock(CommandsInterface.class); - mMockedIsub = mock(ISub.class); - doReturn(mMockedIsub).when(mIBinder).queryLocalInterface(anyString()); + doReturn(mSubscriptionManagerService).when(mIBinder).queryLocalInterface(anyString()); doReturn(mPhone).when(mPhone).getImsPhone(); mServiceManagerMockedServices.put("isub", mIBinder); @@ -151,53 +163,92 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Sub 1 is in slot 0; sub 2 is in slot 1. doReturn(DUAL_SIM).when(mTelephonyManager).getPhoneCount(); doReturn(DUAL_SIM).when(mTelephonyManager).getActiveModemCount(); - doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(1).when(mMockedIsub).getDefaultDataSubId(); - doReturn(1).when(mSubControllerMock).getDefaultVoiceSubId(); - doReturn(1).when(mMockedIsub).getDefaultVoiceSubId(); - doReturn(1).when(mSubControllerMock).getDefaultSmsSubId(); - doReturn(1).when(mMockedIsub).getDefaultSmsSubId(); - doReturn(true).when(mSubControllerMock).isActiveSubId(1); - doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(0).build()) - .when(mSubControllerMock).getSubscriptionInfo(1); - doReturn(true).when(mSubControllerMock).isActiveSubId(2); - doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(1).build()) - .when(mSubControllerMock).getSubscriptionInfo(2); - doReturn(0).when(mSubControllerMock).getPhoneId(1); - doReturn(0).when(mMockedIsub).getPhoneId(1); - doReturn(1).when(mSubControllerMock).getPhoneId(2); - doReturn(1).when(mMockedIsub).getPhoneId(2); - doReturn(true).when(mSubControllerMock).isOpportunistic(5); - doReturn(new SubscriptionInfo.Builder().setId(5).setSimSlotIndex(1).setOpportunistic(true) - .build()).when(mSubControllerMock).getSubscriptionInfo(5); - doReturn(1).when(mPhoneMock1).getSubId(); - doReturn(2).when(mPhoneMock2).getSubId(); + doReturn(1).when(mSubscriptionManagerService).getDefaultDataSubId(); + doReturn(1).when(mSubscriptionManagerService).getDefaultVoiceSubId(); + doReturn(1).when(mSubscriptionManagerService).getDefaultSmsSubId(); mPhoneMock1.mCi = mSimulatedCommands; mPhoneMock2.mCi = mSimulatedCommands; - List infoList = Arrays.asList(mSubInfo1, mSubInfo2); - doReturn(infoList).when(mSubControllerMock) - .getActiveSubscriptionInfoList(anyString(), nullable(String.class)); - doReturn(new int[]{1, 2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); mPhones = new Phone[] {mPhoneMock1, mPhoneMock2}; doReturn(mDataSettingsManagerMock1).when(mPhoneMock1).getDataSettingsManager(); doReturn(mDataSettingsManagerMock2).when(mPhoneMock2).getDataSettingsManager(); - doReturn(Arrays.asList(mSubInfo1)).when(mSubControllerMock).getSubInfo( - eq(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 1), any()); - doReturn(Arrays.asList(mSubInfo2)).when(mSubControllerMock).getSubInfo( - eq(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2), any()); - doReturn(Arrays.asList(mSubInfo3)).when(mSubControllerMock).getSubInfo( - eq(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 3), any()); - doReturn(Arrays.asList(mSubInfo4)).when(mSubControllerMock).getSubInfo( - eq(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 4), any()); + doAnswer(invocation -> { + final int subId = (int) invocation.getArguments()[0]; + if (subId < 0 || subId >= mSubInfo.length) return null; + return mSubInfo[subId].toSubscriptionInfo(); + }).when(mSubscriptionManagerService).getSubscriptionInfo(anyInt()); + + doAnswer(invocation -> { + final int subId = (int) invocation.getArguments()[0]; + if (subId < 0 || subId >= mSubInfo.length) return null; + return mSubInfo[subId]; + }).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + + doAnswer(invocation -> { + List subscriptionInfoList = new ArrayList<>(); + for (int i = 1; i < mSubInfo.length; i++) { + if (mSubInfo[i] != null && mSubInfo[i].isActive()) { + subscriptionInfoList.add(mSubInfo[i].toSubscriptionInfo()); + } + } + return subscriptionInfoList; + }).when(mSubscriptionManagerService).getActiveSubscriptionInfoList( + anyString(), nullable(String.class)); + + doAnswer(invocation -> { + final boolean visibleOnly = (boolean) invocation.getArguments()[0]; + List subIdList = new ArrayList<>(); + for (int i = 1; i < mSubInfo.length; i++) { + if (mSubInfo[i] != null && mSubInfo[i].isActive() + && (!visibleOnly || mSubInfo[i].isVisible())) { + subIdList.add(i); + } + } + return subIdList.stream().mapToInt(i -> i).toArray(); + }).when(mSubscriptionManagerService).getActiveSubIdList(anyBoolean()); + + doAnswer(invocation -> { + final String uuid = (String) invocation.getArguments()[1]; + List subscriptionInfoList = new ArrayList<>(); + for (int i = 1; i < mSubInfo.length; i++) { + if (mSubInfo[i] != null && mSubInfo[i].getGroupUuid().equals(uuid)) { + subscriptionInfoList.add(mSubInfo[i].toSubscriptionInfo()); + } + } + return subscriptionInfoList; + }).when(mSubscriptionManagerService).getSubscriptionsInGroup( + any(), anyString(), nullable(String.class)); + + doAnswer(invocation -> { + final int subId = (int) invocation.getArguments()[0]; + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + return SubscriptionManager.INVALID_PHONE_INDEX; + } + if (mSubInfo[subId] == null) return SubscriptionManager.INVALID_PHONE_INDEX; + return mSubInfo[subId].getSimSlotIndex(); + }).when(mSubscriptionManagerService).getPhoneId(anyInt()); + + doAnswer(invocation -> { + for (int i = 1; i < mSubInfo.length; i++) { + if (mSubInfo[i] != null && mSubInfo[i].getSimSlotIndex() == 0) return i; + } + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + }).when(mPhoneMock1).getSubId(); + + doAnswer(invocation -> { + for (int i = 1; i < mSubInfo.length; i++) { + if (mSubInfo[i] != null && mSubInfo[i].getSimSlotIndex() == 1) return i; + } + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + }).when(mPhoneMock2).getSubId(); replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); - replaceInstance(SubscriptionController.class, "sInstance", null, mSubControllerMock); // Capture listener to emulate the carrier config change notification used later ArgumentCaptor listenerArgumentCaptor = ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); - mMultiSimSettingControllerUT = new MultiSimSettingController(mContext, mSubControllerMock); + mMultiSimSettingControllerUT = new MultiSimSettingController( + mContext, mSubscriptionController); processAllMessages(); verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); @@ -213,43 +264,38 @@ public class MultiSimSettingControllerTest extends TelephonyTest { super.tearDown(); } + private void markSubscriptionInactive(int subId) { + setSimSlotIndex(subId, SubscriptionManager.INVALID_SIM_SLOT_INDEX); + } + @Test @SmallTest public void testSubInfoChangeBeforeAllSubReady() throws Exception { - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubControllerMock) + doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionManagerService) .getDefaultDataSubId(); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubControllerMock) + doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionManagerService) .getDefaultVoiceSubId(); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubControllerMock) + doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionManagerService) .getDefaultSmsSubId(); // Mark sub 2 as inactive. - doReturn(false).when(mSubControllerMock).isActiveSubId(2); - doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(2); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(2); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId(); - List infoList = Arrays.asList(mSubInfo1); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{1}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); + markSubscriptionInactive(2); // Mark subscription ready as false. The below sub info change should be ignored. mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); processAllMessages(); - verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); - verify(mSubControllerMock, never()).setDefaultVoiceSubId(anyInt()); - verify(mSubControllerMock, never()).setDefaultSmsSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultDataSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultVoiceSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultSmsSubId(anyInt()); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); sendCarrierConfigChanged(0, 1); processAllMessages(); // Sub 1 should be default sub silently. - verify(mSubControllerMock).setDefaultDataSubId(1); - verify(mSubControllerMock).setDefaultVoiceSubId(1); - verify(mSubControllerMock).setDefaultSmsSubId(1); + verify(mSubscriptionManagerService).setDefaultDataSubId(1); + verify(mSubscriptionManagerService).setDefaultVoiceSubId(1); + verify(mSubscriptionManagerService).setDefaultSmsSubId(1); verifyDismissIntentSent(); } @@ -261,12 +307,12 @@ public class MultiSimSettingControllerTest extends TelephonyTest { processAllMessages(); // Ensure all subscription loaded only updates state once - clearInvocations(mSubControllerMock); + clearInvocations(mSubscriptionManagerService); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); processAllMessages(); - verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); - verify(mSubControllerMock, never()).setDefaultVoiceSubId(anyInt()); - verify(mSubControllerMock, never()).setDefaultSmsSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultDataSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultVoiceSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultSmsSubId(anyInt()); // Notify radio unavailable. replaceInstance(BaseCommands.class, "mState", mSimulatedCommands, @@ -275,62 +321,42 @@ public class MultiSimSettingControllerTest extends TelephonyTest { MultiSimSettingController.EVENT_RADIO_STATE_CHANGED).sendToTarget(); // Mark all subs as inactive. - doReturn(false).when(mSubControllerMock).isActiveSubId(1); - doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(1); - doReturn(false).when(mSubControllerMock).isActiveSubId(2); - doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(2); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(1); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(1); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(2); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock1).getSubId(); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId(); - List infoList = new ArrayList<>(); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); - clearInvocations(mSubControllerMock); + markSubscriptionInactive(1); + markSubscriptionInactive(2); + clearInvocations(mSubscriptionManagerService); // The below sub info change should be ignored. mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); processAllMessages(); - verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); - verify(mSubControllerMock, never()).setDefaultVoiceSubId(anyInt()); - verify(mSubControllerMock, never()).setDefaultSmsSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultDataSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultVoiceSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultSmsSubId(anyInt()); // Send all sub ready notification mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); processAllMessages(); // Everything should be set to invalid since nothing is active. - verify(mSubControllerMock).setDefaultDataSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - verify(mSubControllerMock) + verify(mSubscriptionManagerService).setDefaultDataSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + verify(mSubscriptionManagerService) .setDefaultVoiceSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - verify(mSubControllerMock).setDefaultSmsSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); + verify(mSubscriptionManagerService).setDefaultSmsSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); } @Test @SmallTest public void testSingleActiveDsds() throws Exception { - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubControllerMock) + doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionManagerService) .getDefaultDataSubId(); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubControllerMock) + doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionManagerService) .getDefaultVoiceSubId(); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubControllerMock) + doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionManagerService) .getDefaultSmsSubId(); // Mark sub 2 as inactive. - doReturn(false).when(mSubControllerMock).isActiveSubId(2); - doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(2); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId(); - List infoList = Arrays.asList(mSubInfo1); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{1}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); + markSubscriptionInactive(2); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); sendCarrierConfigChanged(0, 1); @@ -340,30 +366,17 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Sub 1 should be default sub silently. // Sub 1 switches to sub 2 in the same slot. - doReturn(false).when(mSubControllerMock).isActiveSubId(1); - doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(1); - doReturn(true).when(mSubControllerMock).isActiveSubId(2); - doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(0).build()) - .when(mSubControllerMock).getSubscriptionInfo(2); - doReturn(0).when(mSubControllerMock).getPhoneId(2); - doReturn(0).when(mMockedIsub).getPhoneId(2); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(1); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(1); - doReturn(2).when(mPhoneMock1).getSubId(); - infoList = Arrays.asList(mSubInfo2); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); + markSubscriptionInactive(1); + setSimSlotIndex(2, 0); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); sendCarrierConfigChanged(0, 2); processAllMessages(); // Sub 1 should be default sub silently. - verify(mSubControllerMock).setDefaultDataSubId(2); - verify(mSubControllerMock).setDefaultVoiceSubId(2); - verify(mSubControllerMock).setDefaultSmsSubId(2); + verify(mSubscriptionManagerService).setDefaultDataSubId(2); + verify(mSubscriptionManagerService).setDefaultVoiceSubId(2); + verify(mSubscriptionManagerService).setDefaultSmsSubId(2); verifyDismissIntentSent(); } @@ -371,40 +384,23 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @SmallTest public void testActivatingSecondSub() throws Exception { // Mark sub 2 as inactive. - doReturn(false).when(mSubControllerMock).isActiveSubId(2); - doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(2); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(1); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock2).getSubId(); - List infoList = Arrays.asList(mSubInfo1); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{1}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); + markSubscriptionInactive(2); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); sendCarrierConfigChanged(0, 1); processAllMessages(); // Sub 1 should be default sub silently. - verify(mSubControllerMock).setDefaultDataSubId(1); - verify(mSubControllerMock).setDefaultVoiceSubId(1); - verify(mSubControllerMock).setDefaultSmsSubId(1); + verify(mSubscriptionManagerService).setDefaultDataSubId(1); + verify(mSubscriptionManagerService).setDefaultVoiceSubId(1); + verify(mSubscriptionManagerService).setDefaultSmsSubId(1); verifyDismissIntentSent(); // Mark sub 2 as active in phone[1]. - clearInvocations(mSubControllerMock); + setSimSlotIndex(2, 1); + clearInvocations(mSubscriptionManagerService); clearInvocations(mContext); - doReturn(true).when(mSubControllerMock).isActiveSubId(2); - doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(1).build()) - .when(mSubControllerMock).getSubscriptionInfo(2); - doReturn(1).when(mSubControllerMock).getPhoneId(2); - doReturn(1).when(mMockedIsub).getPhoneId(2); - doReturn(2).when(mPhoneMock2).getSubId(); - infoList = Arrays.asList(mSubInfo1, mSubInfo2); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{1, 2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); + mSubInfo[2] = new SubscriptionInfoInternal.Builder().setId(2).setSimSlotIndex(1).build(); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); sendCarrierConfigChanged(1, 2); @@ -419,20 +415,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { clearInvocations(mContext); // Switch from sub 2 to sub 3 in phone[1]. This should again trigger default data selection // dialog. - doReturn(false).when(mSubControllerMock).isActiveSubId(2); - doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(2); - doReturn(true).when(mSubControllerMock).isActiveSubId(3); - doReturn(new SubscriptionInfo.Builder().setId(3).setSimSlotIndex(1).build()) - .when(mSubControllerMock).getSubscriptionInfo(3); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(2); - doReturn(1).when(mSubControllerMock).getPhoneId(3); - doReturn(3).when(mPhoneMock2).getSubId(); - infoList = Arrays.asList(mSubInfo1, mSubInfo3); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{1, 3}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); + markSubscriptionInactive(2); + setSimSlotIndex(3, 1); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); sendCarrierConfigChanged(1, 3); @@ -461,37 +445,32 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Enable on non-default sub should trigger setDefaultDataSubId. mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); processAllMessages(); - verify(mSubControllerMock).setDefaultDataSubId(2); + verify(mSubscriptionManagerService).setDefaultDataSubId(2); // Changing default data to sub 2 should trigger disabling data on sub 1. - doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(2).when(mMockedIsub).getDefaultDataSubId(); + doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); verify(mDataSettingsManagerMock1).setDataEnabled( TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); - doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(1).when(mSubControllerMock).getDefaultSmsSubId(); - doReturn(2).when(mSubControllerMock).getDefaultVoiceSubId(); + doReturn(1).when(mSubscriptionManagerService).getDefaultDataSubId(); + doReturn(1).when(mSubscriptionManagerService).getDefaultSmsSubId(); + doReturn(2).when(mSubscriptionManagerService).getDefaultVoiceSubId(); // Taking out SIM 1. - clearInvocations(mSubControllerMock); - doReturn(false).when(mSubControllerMock).isActiveSubId(1); - doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(1); - List infoList = Arrays.asList(mSubInfo2); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); + clearInvocations(mSubscriptionManagerService); + markSubscriptionInactive(1); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); processAllMessages(); sendCarrierConfigChanged(1, SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); - verify(mSubControllerMock).setDefaultDataSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - verify(mSubControllerMock).setDefaultSmsSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - verify(mSubControllerMock, never()).setDefaultVoiceSubId(anyInt()); + verify(mSubscriptionManagerService).setDefaultDataSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + verify(mSubscriptionManagerService).setDefaultSmsSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + verify(mSubscriptionManagerService, never()).setDefaultVoiceSubId(anyInt()); // Verify intent sent to select sub 2 as default for all types. Intent intent = captureBroadcastIntent(); @@ -505,8 +484,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @SmallTest public void testSimpleDsdsFirstBoot() throws Exception { // at first boot default is not set - doReturn(-1).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(-1).when(mMockedIsub).getDefaultDataSubId(); + doReturn(-1).when(mSubscriptionManagerService).getDefaultDataSubId(); doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); @@ -530,8 +508,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { intent.getIntExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE, -1)); // Setting default data should not trigger any more setDataEnabled(). - doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(2).when(mMockedIsub).getDefaultDataSubId(); + doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); + doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); verify(mDataSettingsManagerMock1, times(1)) @@ -544,8 +522,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @SmallTest public void testSimpleDsdsInSuW() throws Exception { // at first boot default is not set - doReturn(-1).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(-1).when(mMockedIsub).getDefaultDataSubId(); + doReturn(-1).when(mSubscriptionManagerService).getDefaultDataSubId(); doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); @@ -573,7 +550,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Test @SmallTest public void testDsdsGrouping() throws Exception { - doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); + doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); doReturn(false).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 2, true); @@ -584,13 +561,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { processAllMessages(); // Create subscription grouping. - doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); - doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(3); - doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(4); - mSubInfo2 = new SubscriptionInfo.Builder(mSubInfo2).setSimSlotIndex(1).build(); - mSubInfo3 = new SubscriptionInfo.Builder(mSubInfo3).setSimSlotIndex(-1).build(); - mSubInfo4 = new SubscriptionInfo.Builder(mSubInfo4).setSimSlotIndex(-1).build(); - doReturn(Arrays.asList(mSubInfo2, mSubInfo3, mSubInfo4)).when(mSubControllerMock) + doReturn(Arrays.asList(mSubInfo[2].toSubscriptionInfo(), mSubInfo[3].toSubscriptionInfo(), + mSubInfo[4].toSubscriptionInfo())).when(mSubscriptionManagerService) .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); @@ -603,13 +575,12 @@ public class MultiSimSettingControllerTest extends TelephonyTest { mContext, Settings.Global.DATA_ROAMING, 3, true)); assertFalse(GlobalSettingsHelper.getBoolean( mContext, Settings.Global.DATA_ROAMING, 4, true)); - verify(mSubControllerMock).setDataRoaming(/*enable*/0, /*subId*/2); + verify(mSubscriptionManagerService).setDataRoaming(/*enable*/0, /*subId*/2); // No user selection needed, no intent should be sent. verify(mContext, never()).sendBroadcast(any()); // Making sub 1 default data sub should result in disabling data on sub 2, 3, 4. - doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(1).when(mMockedIsub).getDefaultDataSubId(); + doReturn(1).when(mSubscriptionManagerService).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyDefaultDataSubChanged(); processAllMessages(); verify(mDataSettingsManagerMock2).setDataEnabled( @@ -625,25 +596,20 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Switch within group (from sub 2 to sub 3). // Default data and default sms should become subscription 3. - clearInvocations(mSubControllerMock); - doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(2).when(mMockedIsub).getDefaultDataSubId(); - doReturn(2).when(mSubControllerMock).getDefaultSmsSubId(); - doReturn(2).when(mMockedIsub).getDefaultSmsSubId(); - doReturn(1).when(mSubControllerMock).getDefaultVoiceSubId(); - doReturn(1).when(mMockedIsub).getDefaultVoiceSubId(); - List infoList = Arrays.asList(mSubInfo1, mSubInfo3); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{1, 3}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); + clearInvocations(mSubscriptionManagerService); + doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); + doReturn(2).when(mSubscriptionManagerService).getDefaultSmsSubId(); + doReturn(1).when(mSubscriptionManagerService).getDefaultVoiceSubId(); + setSimSlotIndex(3, 1); + markSubscriptionInactive(2); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); sendCarrierConfigChanged(1, 3); processAllMessages(); - verify(mSubControllerMock).setDefaultDataSubId(3); - verify(mSubControllerMock).setDefaultSmsSubId(3); - verify(mSubControllerMock, never()).setDefaultVoiceSubId(anyInt()); + verify(mSubscriptionManagerService).setDefaultDataSubId(3); + verify(mSubscriptionManagerService).setDefaultSmsSubId(3); + verify(mSubscriptionManagerService, never()).setDefaultVoiceSubId(anyInt()); // No user selection needed, no intent should be sent. verify(mContext, never()).sendBroadcast(any()); } @@ -651,10 +617,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Test @SmallTest public void testCbrs() throws Exception { - replaceInstance(SubscriptionInfo.class, "mIsOpportunistic", mSubInfo1, true); - doReturn(true).when(mSubControllerMock).isOpportunistic(1); - doReturn(new SubscriptionInfo.Builder(mSubInfo1).setOpportunistic(true).build()) - .when(mSubControllerMock).getSubscriptionInfo(1); + mSubInfo[1] = new SubscriptionInfoInternal.Builder(mSubInfo[1]).setOpportunistic(1).build(); + doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.DATA_ROAMING, 2, false); @@ -665,25 +629,24 @@ public class MultiSimSettingControllerTest extends TelephonyTest { sendCarrierConfigChanged(0, 1); sendCarrierConfigChanged(1, 2); processAllMessages(); - verify(mSubControllerMock).setDefaultDataSubId(2); + verify(mSubscriptionManagerService).setDefaultDataSubId(2); verify(mDataSettingsManagerMock1, never()).setDataEnabled( anyInt(), anyBoolean(), anyString()); verifyDismissIntentSent(); - clearInvocations(mSubControllerMock); + clearInvocations(mSubscriptionManagerService); clearInvocations(mDataSettingsManagerMock1); clearInvocations(mDataSettingsManagerMock2); - doReturn(2).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(2).when(mMockedIsub).getDefaultDataSubId(); + doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); // Toggle data on sub 1 or sub 2. Nothing should happen as they are independent. mMultiSimSettingControllerUT.notifyUserDataEnabled(1, false); mMultiSimSettingControllerUT.notifyUserDataEnabled(1, true); processAllMessages(); - verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultDataSubId(anyInt()); mMultiSimSettingControllerUT.notifyUserDataEnabled(2, false); mMultiSimSettingControllerUT.notifyUserDataEnabled(2, true); processAllMessages(); - verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultDataSubId(anyInt()); verify(mDataSettingsManagerMock1, never()).setDataEnabled( eq(TelephonyManager.DATA_ENABLED_REASON_USER), anyBoolean(), anyString()); verify(mDataSettingsManagerMock2, never()).setDataEnabled( @@ -701,11 +664,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @SmallTest public void testGroupedCbrs() throws Exception { // Mark sub 1 as opportunistic. - replaceInstance(SubscriptionInfo.class, "mIsOpportunistic", mSubInfo1, true); - replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); - doReturn(true).when(mSubControllerMock).isOpportunistic(1); - doReturn(new SubscriptionInfo.Builder(mSubInfo1).setOpportunistic(true).build()) - .when(mSubControllerMock).getSubscriptionInfo(1); + mSubInfo[1] = new SubscriptionInfoInternal.Builder(mSubInfo[1]) + .setOpportunistic(1).setGroupUuid(mGroupUuid1.toString()).build(); // Make opportunistic sub 1 and sub 2 data enabled. doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); @@ -716,13 +676,14 @@ public class MultiSimSettingControllerTest extends TelephonyTest { sendCarrierConfigChanged(0, 1); sendCarrierConfigChanged(1, 2); processAllMessages(); - verify(mSubControllerMock).setDefaultDataSubId(2); + verify(mSubscriptionManagerService).setDefaultDataSubId(2); // Mark sub 2 as data off. doReturn(false).when(mPhoneMock2).isUserDataEnabled(); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 2, false); // Group sub 1 with sub 2. - doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock) + doReturn(Arrays.asList(mSubInfo[1].toSubscriptionInfo(), mSubInfo[2].toSubscriptionInfo())) + .when(mSubscriptionManagerService) .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); @@ -746,11 +707,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @SmallTest public void testGroupedPrimaryRemoved() throws Exception { // Create subscription grouping of subs 1 and 2. - replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); - doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(1); - doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); - doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock) - .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); + mSubInfo[1] = new SubscriptionInfoInternal.Builder(mSubInfo[1]) + .setGroupUuid(mGroupUuid1.toString()).build(); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); @@ -759,28 +717,19 @@ public class MultiSimSettingControllerTest extends TelephonyTest { processAllMessages(); // Defaults not touched, sub 1 is already default. - verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultDataSubId(anyInt()); // Take out SIM 1. - clearInvocations(mSubControllerMock); - doReturn(false).when(mSubControllerMock).isActiveSubId(1); - doReturn(new SubscriptionInfo.Builder().setId(1).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(1); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(1); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(1); - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mPhoneMock1).getSubId(); - List infoList = Arrays.asList(mSubInfo2); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{2}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); + clearInvocations(mSubscriptionManagerService); + markSubscriptionInactive(1); mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); sendCarrierConfigChanged(0, SubscriptionManager.INVALID_SUBSCRIPTION_ID); processAllMessages(); // Sub 2 should be made the default sub silently. - verify(mSubControllerMock).setDefaultDataSubId(2); - verify(mSubControllerMock).setDefaultVoiceSubId(2); - verify(mSubControllerMock).setDefaultSmsSubId(2); + verify(mSubscriptionManagerService).setDefaultDataSubId(2); + verify(mSubscriptionManagerService).setDefaultVoiceSubId(2); + verify(mSubscriptionManagerService).setDefaultSmsSubId(2); verifyDismissIntentSent(); } @@ -793,8 +742,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Test @SmallTest public void testGroupedPrimarySubscriptions() throws Exception { - doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(1).when(mMockedIsub).getDefaultDataSubId(); + doReturn(1).when(mSubscriptionManagerService).getDefaultDataSubId(); doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(false).when(mPhoneMock2).isUserDataEnabled(); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 1, true); @@ -805,9 +753,11 @@ public class MultiSimSettingControllerTest extends TelephonyTest { processAllMessages(); // Create subscription grouping. - replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); - doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock) - .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); + mSubInfo[1] = new SubscriptionInfoInternal.Builder(mSubInfo[1]) + .setGroupUuid(mGroupUuid1.toString()).build(); + doReturn(Arrays.asList(mSubInfo[1].toSubscriptionInfo(), mSubInfo[2].toSubscriptionInfo())) + .when(mSubscriptionManagerService).getSubscriptionsInGroup(any(), anyString(), + nullable(String.class)); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // This should result in setting sync. @@ -815,7 +765,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { true, PHONE_PACKAGE); assertFalse(GlobalSettingsHelper.getBoolean( mContext, Settings.Global.DATA_ROAMING, 2, true)); - verify(mSubControllerMock).setDataRoaming(/*enable*/0, /*subId*/1); + verify(mSubscriptionManagerService).setDataRoaming(/*enable*/0, /*subId*/1); // Turning off user data on sub 1. doReturn(false).when(mPhoneMock1).isUserDataEnabled(); @@ -830,6 +780,8 @@ public class MultiSimSettingControllerTest extends TelephonyTest { public void testCarrierConfigLoading() throws Exception { doReturn(true).when(mPhoneMock1).isUserDataEnabled(); doReturn(true).when(mPhoneMock2).isUserDataEnabled(); + mSubInfo[2] = new SubscriptionInfoInternal.Builder(mSubInfo[2]).setGroupUuid("").build(); + mSubInfo[3] = new SubscriptionInfoInternal.Builder(mSubInfo[3]).setGroupUuid("").build(); // Sub 2 should have mobile data off, but it shouldn't happen until carrier configs are // loaded on both subscriptions. mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); @@ -846,22 +798,9 @@ public class MultiSimSettingControllerTest extends TelephonyTest { TelephonyManager.DATA_ENABLED_REASON_USER, false, PHONE_PACKAGE); // Switch from sub 2 to sub 3 in phone[1]. - clearInvocations(mSubControllerMock); - doReturn(false).when(mSubControllerMock).isActiveSubId(2); - doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(2); - doReturn(true).when(mSubControllerMock).isActiveSubId(3); - doReturn(new SubscriptionInfo.Builder().setId(3).setSimSlotIndex(1).build()) - .when(mSubControllerMock).getSubscriptionInfo(3); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mMockedIsub).getPhoneId(2); - doReturn(1).when(mSubControllerMock).getPhoneId(3); - doReturn(1).when(mMockedIsub).getPhoneId(3); - doReturn(3).when(mPhoneMock2).getSubId(); - List infoList = Arrays.asList(mSubInfo1, mSubInfo3); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{1, 3}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); + clearInvocations(mSubscriptionManagerService); + markSubscriptionInactive(2); + setSimSlotIndex(3, 1); // Nothing should happen until carrier config change is notified on sub 3. mMultiSimSettingControllerUT.notifySubscriptionInfoChanged(); @@ -882,26 +821,14 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // b/146446143 public void testGroupChangeOnInactiveSub_shouldNotMarkAsDefaultDataSub() throws Exception { // Make sub1 and sub3 as active sub. - doReturn(false).when(mSubControllerMock).isActiveSubId(2); - doReturn(new SubscriptionInfo.Builder().setId(2).setSimSlotIndex(-1).build()) - .when(mSubControllerMock).getSubscriptionInfo(2); - doReturn(true).when(mSubControllerMock).isActiveSubId(3); - doReturn(new SubscriptionInfo.Builder().setId(3).setSimSlotIndex(1).build()) - .when(mSubControllerMock).getSubscriptionInfo(3); - doReturn(SubscriptionManager.INVALID_PHONE_INDEX).when(mSubControllerMock).getPhoneId(2); - doReturn(1).when(mSubControllerMock).getPhoneId(3); - doReturn(1).when(mMockedIsub).getPhoneId(3); - doReturn(3).when(mPhoneMock2).getSubId(); - List infoList = Arrays.asList(mSubInfo1, mSubInfo3); - doReturn(infoList).when(mSubControllerMock).getActiveSubscriptionInfoList(anyString(), - nullable(String.class)); - doReturn(new int[]{1, 3}).when(mSubControllerMock).getActiveSubIdList(anyBoolean()); - doReturn(Arrays.asList(mSubInfo2, mSubInfo3, mSubInfo4)).when(mSubControllerMock) + markSubscriptionInactive(2); + setSimSlotIndex(3, 1); + doReturn(Arrays.asList(mSubInfo[2].toSubscriptionInfo(), mSubInfo[3].toSubscriptionInfo(), + mSubInfo[4].toSubscriptionInfo())).when(mSubscriptionManagerService) .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); // Sub 3 and sub 2's mobile data are enabled, and sub 3 is the default data sub. - doReturn(3).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(3).when(mMockedIsub).getDefaultDataSubId(); + doReturn(3).when(mSubscriptionManagerService).getDefaultDataSubId(); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 1, false); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 2, true); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 3, true); @@ -915,13 +842,12 @@ public class MultiSimSettingControllerTest extends TelephonyTest { processAllMessages(); // Mark sub3 as oppt and notify grouping - doReturn(true).when(mSubControllerMock).isOpportunistic(3); - doReturn(new SubscriptionInfo.Builder().setId(3).setSimSlotIndex(0).setOpportunistic(true) - .build()).when(mSubControllerMock).getSubscriptionInfo(3); + mSubInfo[3] = new SubscriptionInfoInternal.Builder(mSubInfo[3]).setOpportunistic(1).build(); + setSimSlotIndex(3, 0); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // Shouldn't mark sub 2 as default data, as sub 2 is in active. - verify(mSubControllerMock, never()).setDefaultDataSubId(2); + verify(mSubscriptionManagerService, never()).setDefaultDataSubId(2); } @Test @@ -943,8 +869,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Still notify carrier config without specifying subId2, but this time subController // and CarrierConfigManager have subId 2 active and ready. - doReturn(2).when(mSubControllerMock).getSubId(1); - doReturn(2).when(mMockedIsub).getSubId(1); + doReturn(2).when(mSubscriptionManagerService).getSubId(1); CarrierConfigManager cm = (CarrierConfigManager) mContext.getSystemService( mContext.CARRIER_CONFIG_SERVICE); doReturn(new PersistableBundle()).when(cm).getConfigForSubId(2); @@ -995,15 +920,14 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Test @SmallTest public void testVoiceDataSmsAutoFallback() throws Exception { - doReturn(1).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(1).when(mMockedIsub).getDefaultDataSubId(); + doReturn(1).when(mSubscriptionManagerService).getDefaultDataSubId(); mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded(); sendCarrierConfigChanged(0, 1); sendCarrierConfigChanged(2, 2); processAllMessages(); - verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); - verify(mSubControllerMock, never()).getActiveSubInfoCountMax(); - doReturn(2).when(mSubControllerMock).getActiveSubInfoCountMax(); + verify(mSubscriptionManagerService, never()).setDefaultDataSubId(anyInt()); + verify(mSubscriptionManagerService, never()).getActiveSubInfoCountMax(); + doReturn(2).when(mSubscriptionManagerService).getActiveSubInfoCountMax(); mPhoneMock1.mCi = mMockCi; mPhoneMock2.mCi = mMockCi; doReturn(TelephonyManager.RADIO_POWER_ON).when(mMockCi).getRadioState(); @@ -1018,38 +942,36 @@ public class MultiSimSettingControllerTest extends TelephonyTest { sendCarrierConfigChanged(0, 1); sendCarrierConfigChanged(1, 2); processAllMessages(); - verify(mSubControllerMock).getActiveSubInfoCountMax(); - verify(mSubControllerMock).setDefaultDataSubId(anyInt()); + verify(mSubscriptionManagerService).getActiveSubInfoCountMax(); + verify(mSubscriptionManagerService).setDefaultDataSubId(anyInt()); } @Test public void onSubscriptionGroupChanged_hasActiveSubNotPartOfGroup() { // sub1 and sub2 are active subs already // Create a subscription group with only sub2 - doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); - doReturn(Arrays.asList(mSubInfo2)).when(mSubControllerMock) + doReturn(Arrays.asList(mSubInfo[2].toSubscriptionInfo())).when(mSubscriptionManagerService) .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // Default data is not modified as sub1 is active sub not part of this groupUuid - verify(mSubControllerMock, never()).setDefaultDataSubId(anyInt()); + verify(mSubscriptionManagerService, never()).setDefaultDataSubId(anyInt()); } @Test public void onSubscriptionGroupChanged_allActiveSubArePartOfGroup() throws Exception { - doReturn(3).when(mSubControllerMock).getDefaultDataSubId(); - doReturn(3).when(mMockedIsub).getDefaultDataSubId(); + doReturn(3).when(mSubscriptionManagerService).getDefaultDataSubId(); // Create subscription grouping of subs 1 and 2. - replaceInstance(SubscriptionInfo.class, "mGroupUuid", mSubInfo1, mGroupUuid1); - doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(1); - doReturn(mGroupUuid1).when(mSubControllerMock).getGroupUuid(2); + mSubInfo[1] = new SubscriptionInfoInternal.Builder(mSubInfo[1]) + .setGroupUuid(mGroupUuid1.toString()).build(); GlobalSettingsHelper.setBoolean(mContext, Settings.Global.MOBILE_DATA, 1, true); - doReturn(Arrays.asList(mSubInfo1, mSubInfo2)).when(mSubControllerMock) + doReturn(Arrays.asList(mSubInfo[1].toSubscriptionInfo(), mSubInfo[2].toSubscriptionInfo())) + .when(mSubscriptionManagerService) .getSubscriptionsInGroup(any(), anyString(), nullable(String.class)); mMultiSimSettingControllerUT.notifySubscriptionGroupChanged(mGroupUuid1); processAllMessages(); // Default data is set to sub1 - verify(mSubControllerMock).setDefaultDataSubId(1); + verify(mSubscriptionManagerService).syncGroupedSetting(1); } -} \ No newline at end of file +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java index 81b9ff1531..ca0de9cc0b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java @@ -220,9 +220,17 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { // Verify clearSubInfoRecord() and onSlotActiveStatusChange() are called for second phone, // and not for the first one - verify(mSubscriptionController).clearSubInfoRecord(1); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService).markSubscriptionsInactive(1); + } else { + verify(mSubscriptionController).clearSubInfoRecord(1); + } verify(mMockCi1).onSlotActiveStatusChange(anyBoolean()); - verify(mSubscriptionController, never()).clearSubInfoRecord(0); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService, never()).markSubscriptionsInactive(0); + } else { + verify(mSubscriptionController, never()).clearSubInfoRecord(0); + } verify(mMockCi0, never()).onSlotActiveStatusChange(anyBoolean()); // Verify onPhoneRemoved() gets called on MultiSimSettingController phone @@ -250,28 +258,47 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { ex.) object.set( 2 ) --> next call to object.get() will return 2 */ - // setup mocks for VOICE mSubscriptionController. getter/setter + // setup mocks for VOICE mSubscriptionManagerService. getter/setter doAnswer(invocation -> { Integer value = (Integer) invocation.getArguments()[0]; Mockito.when(mSubscriptionController.getDefaultVoiceSubId()).thenReturn(value); return null; }).when(mSubscriptionController).setDefaultVoiceSubId(anyInt()); + doAnswer(invocation -> { + Integer value = (Integer) invocation.getArguments()[0]; + Mockito.when(mSubscriptionManagerService.getDefaultVoiceSubId()).thenReturn(value); + return null; + }).when(mSubscriptionManagerService).setDefaultVoiceSubId(anyInt()); + + // start off the phone stat with 1 active sim. reset values for new test. init(1); - mSubscriptionController.setDefaultVoiceSubId(startingDefaultSubscriptionId); - - // assert the mSubscriptionController registers the change - assertEquals(startingDefaultSubscriptionId, mSubscriptionController.getDefaultVoiceSubId()); + if (isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService.setDefaultVoiceSubId(startingDefaultSubscriptionId); + assertEquals(startingDefaultSubscriptionId, + mSubscriptionManagerService.getDefaultVoiceSubId()); + } else { + mSubscriptionController.setDefaultVoiceSubId(startingDefaultSubscriptionId); + assertEquals(startingDefaultSubscriptionId, + mSubscriptionController.getDefaultVoiceSubId()); + } // Perform the switch to DSDS mode and ensure all existing checks are not altered testSwitchFromSingleToDualSimModeNoReboot(); // VOICE check - assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID /* No CALL Preference value */, - mSubscriptionController.getDefaultVoiceSubId()); // Now, when the user goes to - // place a CALL, they will be prompted on which sim to use. + if (isSubscriptionManagerServiceEnabled()) { + assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID /* No CALL Preference value */, + mSubscriptionManagerService.getDefaultVoiceSubId()); + // Now, when the user goes to place a CALL, they will be prompted on which sim to use. + } else { + assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID /* No CALL Preference value */, + mSubscriptionController.getDefaultVoiceSubId()); + // Now, when the user goes to place a CALL, they will be prompted on which sim to use. + } + } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java index 55ead0a43e..0669517d9d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java @@ -78,11 +78,15 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { /* mPhone -> PhoneId: 0 -> SubId:0 mSecondPhone -> PhoneId:1 -> SubId: 1*/ doReturn(0).when(mSubscriptionController).getPhoneId(eq(0)); + doReturn(0).when(mSubscriptionManagerService).getPhoneId(eq(0)); doReturn(1).when(mSubscriptionController).getPhoneId(eq(1)); + doReturn(1).when(mSubscriptionManagerService).getPhoneId(eq(1)); doReturn(2).when(mTelephonyManager).getPhoneCount(); doReturn(2).when(mTelephonyManager).getActiveModemCount(); doReturn(true).when(mSubscriptionController).isActiveSubId(0, TAG, FEATURE_ID); + doReturn(true).when(mSubscriptionManagerService).isActiveSubId(0, TAG, FEATURE_ID); doReturn(true).when(mSubscriptionController).isActiveSubId(1, TAG, FEATURE_ID); + doReturn(true).when(mSubscriptionManagerService).isActiveSubId(1, TAG, FEATURE_ID); doReturn(new int[]{0, 1}).when(mSubscriptionManager) .getCompleteActiveSubscriptionIdList(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java index 21514efac9..c0d497d98b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java @@ -26,7 +26,6 @@ import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.os.AsyncResult; @@ -47,14 +46,11 @@ import org.mockito.ArgumentCaptor; @TestableLooper.RunWithLooper public class ProxyControllerTest extends TelephonyTest { // Mocked classes - Phone mPhone2; - ProxyController mProxyController; @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); - mPhone2 = mock(Phone.class); replaceInstance(ProxyController.class, "sProxyController", null, null); mProxyController = ProxyController.getInstance(mContext); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 3e55d41798..6d4b131eab 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -95,6 +95,7 @@ import com.android.internal.R; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.metrics.ServiceStateStats; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.uicc.IccCardApplicationStatus; import com.android.internal.telephony.uicc.IccRecords; @@ -121,6 +122,8 @@ public class ServiceStateTrackerTest extends TelephonyTest { private NetworkService mIwlanNetworkService; private INetworkService.Stub mIwlanNetworkServiceStub; private SubscriptionInfo mSubInfo; + + private SubscriptionInfoInternal mSubInfoInternal; private ServiceStateStats mServiceStateStats; private CellularNetworkService mCellularNetworkService; @@ -228,8 +231,13 @@ public class ServiceStateTrackerTest extends TelephonyTest { mIwlanNetworkService = Mockito.mock(NetworkService.class); mIwlanNetworkServiceStub = Mockito.mock(INetworkService.Stub.class); mSubInfo = Mockito.mock(SubscriptionInfo.class); + mSubInfoInternal = new SubscriptionInfoInternal.Builder().setId(1).build(); mServiceStateStats = Mockito.mock(ServiceStateStats.class); + mContextFixture.putResource(R.string.kg_text_message_separator, " \u2014 "); + + doReturn(mSubInfoInternal).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(anyInt()); doReturn((Executor) Runnable::run).when(mContext).getMainExecutor(); mContextFixture.putResource(R.string.config_wwan_network_service_package, "com.android.phone"); @@ -1658,6 +1666,9 @@ public class ServiceStateTrackerTest extends TelephonyTest { int otherSubId = 2; sst.mSubId = otherSubId; doReturn(subId).when(mSubInfo).getSubscriptionId(); + doReturn(new SubscriptionInfoInternal.Builder().setId(2).setOpportunistic(1) + .setGroupUuid("fb767ff3-a395-4a53-bb17-3f853ae0eb87").build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); final NotificationManager nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java index 3496199630..28c3187589 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java @@ -50,7 +50,6 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -125,6 +124,7 @@ public class SubscriptionControllerTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + enableSubscriptionManagerService(false); mUiccSlot = mock(UiccSlot.class); mTelephonyRegistryMock = mock(ITelephonyRegistry.Stub.class); mMultiSimSettingControllerMock = mock(MultiSimSettingController.class); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java index 905b39378f..32fb56ecb1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java @@ -119,6 +119,7 @@ public class SubscriptionInfoUpdaterTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); + enableSubscriptionManagerService(false); mUserInfo = mock(UserInfo.class); mSubInfo = mock(SubscriptionInfo.class); mContentProvider = mock(ContentProvider.class); diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 45be21bbca..6ca2729137 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -114,6 +114,7 @@ import com.android.internal.telephony.metrics.PersistAtomsStorage; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.SmsStats; import com.android.internal.telephony.metrics.VoiceCallSessionStats; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.test.SimulatedCommandsVerifier; import com.android.internal.telephony.uicc.IccCardStatus; @@ -177,6 +178,7 @@ public abstract class TelephonyTest { // Mocked classes protected GsmCdmaPhone mPhone; + protected GsmCdmaPhone mPhone2; protected ImsPhone mImsPhone; protected ServiceStateTracker mSST; protected EmergencyNumberTracker mEmergencyNumberTracker; @@ -202,6 +204,7 @@ public abstract class TelephonyTest { protected ImsCall mImsCall; protected ImsEcbm mImsEcbm; protected SubscriptionController mSubscriptionController; + protected SubscriptionManagerService mSubscriptionManagerService; protected ServiceState mServiceState; protected IPackageManager.Stub mMockPackageManager; protected LegacyPermissionManagerService mMockLegacyPermissionManager; @@ -409,6 +412,7 @@ public abstract class TelephonyTest { TAG = tag; enableStrictMode(); mPhone = Mockito.mock(GsmCdmaPhone.class); + mPhone2 = Mockito.mock(GsmCdmaPhone.class); mImsPhone = Mockito.mock(ImsPhone.class); mSST = Mockito.mock(ServiceStateTracker.class); mEmergencyNumberTracker = Mockito.mock(EmergencyNumberTracker.class); @@ -434,6 +438,7 @@ public abstract class TelephonyTest { mImsCall = Mockito.mock(ImsCall.class); mImsEcbm = Mockito.mock(ImsEcbm.class); mSubscriptionController = Mockito.mock(SubscriptionController.class); + mSubscriptionManagerService = Mockito.mock(SubscriptionManagerService.class); mServiceState = Mockito.mock(ServiceState.class); mMockPackageManager = Mockito.mock(IPackageManager.Stub.class); mMockLegacyPermissionManager = Mockito.mock(LegacyPermissionManagerService.class); @@ -521,6 +526,8 @@ public abstract class TelephonyTest { Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); + enableSubscriptionManagerService(true); + mPhone.mCi = mSimulatedCommands; mCT.mCi = mSimulatedCommands; doReturn(mUiccCard).when(mPhone).getUiccCard(); @@ -814,6 +821,8 @@ public abstract class TelephonyTest { replaceInstance(UiccController.class, "mInstance", null, mUiccController); replaceInstance(CdmaSubscriptionSourceManager.class, "sInstance", null, mCdmaSSM); replaceInstance(SubscriptionController.class, "sInstance", null, mSubscriptionController); + replaceInstance(SubscriptionManagerService.class, "sInstance", null, + mSubscriptionManagerService); replaceInstance(ProxyController.class, "sProxyController", null, mProxyController); replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, mPhoneSwitcher); replaceInstance(ActivityManager.class, "IActivityManagerSingleton", null, @@ -845,8 +854,11 @@ public abstract class TelephonyTest { new CommandsInterface[] {mSimulatedCommands}); replaceInstance(PhoneFactory.class, "sMetricsCollector", null, mMetricsCollector); - assertNotNull("Failed to set up SubscriptionController singleton", - SubscriptionController.getInstance()); + if (!isSubscriptionManagerServiceEnabled()) { + assertNotNull("Failed to set up SubscriptionController singleton", + SubscriptionController.getInstance()); + } + setReady(false); // create default TestableLooper for test and add to list of monitored loopers mTestableLooper = TestableLooper.get(TelephonyTest.this); @@ -1262,4 +1274,22 @@ public abstract class TelephonyTest { } } } + + protected void enableSubscriptionManagerService(boolean enabled) throws Exception { + if (enabled) { + mServiceManagerMockedServices.put("isub", mSubscriptionManagerService); + doReturn(mSubscriptionManagerService).when(mIBinder) + .queryLocalInterface(anyString()); + } + replaceInstance(PhoneFactory.class, "sSubscriptionManagerServiceEnabled", null, enabled); + mContextFixture.putBooleanResource(com.android.internal.R.bool + .config_using_subscription_manager_service, enabled); + doReturn(enabled).when(mPhone).isSubscriptionManagerServiceEnabled(); + doReturn(enabled).when(mPhone2).isSubscriptionManagerServiceEnabled(); + doReturn(enabled).when(mImsPhone).isSubscriptionManagerServiceEnabled(); + } + + protected boolean isSubscriptionManagerServiceEnabled() { + return mPhone.isSubscriptionManagerServiceEnabled(); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java index 3773756dcc..76a3d0a12b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java @@ -48,6 +48,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import org.junit.After; import org.junit.Before; @@ -77,6 +78,8 @@ public class CellularNetworkValidatorTest extends TelephonyTest { .getCurrentPhoneCapability(); mValidatorUT = new CellularNetworkValidator(mContext); doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); + doReturn(new SubscriptionInfoInternal.Builder().setSimSlotIndex(0).setId(1).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); processAllMessages(); setCacheTtlInCarrierConfig(5000); } 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 5b609411aa..f7d80e5ab8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -114,6 +114,7 @@ import com.android.internal.telephony.data.DataNetworkController.HandoverRule; import com.android.internal.telephony.data.DataRetryManager.DataRetryManagerCallback; import com.android.internal.telephony.data.LinkBandwidthEstimator.LinkBandwidthEstimatorCallback; import com.android.internal.telephony.ims.ImsResolver; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import org.junit.After; import org.junit.Before; @@ -731,6 +732,8 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn("").when(mSubscriptionController).getEnabledMobileDataPolicies(anyInt()); doReturn(true).when(mSubscriptionController).setEnabledMobileDataPolicies( anyInt(), anyString()); + doReturn(new SubscriptionInfoInternal.Builder().setId(1).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); List infoList = new ArrayList<>(); infoList.add(mMockSubInfo); @@ -738,7 +741,9 @@ public class DataNetworkControllerTest extends TelephonyTest { any(), any(), any()); doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); doReturn(0).when(mSubscriptionController).getPhoneId(1); + doReturn(0).when(mSubscriptionManagerService).getPhoneId(1); doReturn(1).when(mSubscriptionController).getPhoneId(2); + doReturn(1).when(mSubscriptionManagerService).getPhoneId(2); for (int transport : new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN}) { @@ -1669,6 +1674,7 @@ public class DataNetworkControllerTest extends TelephonyTest { public void testIsDataEnabledOverriddenForApnDataDuringCall() throws Exception { doReturn(1).when(mPhone).getSubId(); doReturn(2).when(mSubscriptionController).getDefaultDataSubId(); + doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); // Data disabled mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( TelephonyManager.DATA_ENABLED_REASON_USER, false, mContext.getOpPackageName()); @@ -1711,6 +1717,7 @@ public class DataNetworkControllerTest extends TelephonyTest { Phone phone2 = Mockito.mock(Phone.class); replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, phone2}); doReturn(2).when(mSubscriptionController).getDefaultDataSubId(); + doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); // Data disabled on nonDDS mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java index 4984879752..7a1aecaa82 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java @@ -34,6 +34,7 @@ import android.testing.TestableLooper; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import org.junit.After; import org.junit.Before; @@ -66,6 +67,8 @@ public class DataSettingsManagerTest extends TelephonyTest { doReturn("").when(mSubscriptionController).getEnabledMobileDataPolicies(anyInt()); doReturn(true).when(mSubscriptionController).setEnabledMobileDataPolicies( anyInt(), anyString()); + doReturn(new SubscriptionInfoInternal.Builder().setId(1).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); mDataSettingsManagerUT = new DataSettingsManager(mPhone, mDataNetworkController, Looper.myLooper(), mMockedDataSettingsManagerCallback); @@ -105,8 +108,13 @@ public class DataSettingsManagerTest extends TelephonyTest { processAllMessages(); ArgumentCaptor stringArgumentCaptor = ArgumentCaptor.forClass(String.class); - verify(mSubscriptionController, times(2)) - .setEnabledMobileDataPolicies(anyInt(), stringArgumentCaptor.capture()); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService, times(2)) + .setEnabledMobileDataPolicies(anyInt(), stringArgumentCaptor.capture()); + } else { + verify(mSubscriptionController, times(2)) + .setEnabledMobileDataPolicies(anyInt(), stringArgumentCaptor.capture()); + } assertEquals("1,2", stringArgumentCaptor.getValue()); } 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 5ff51b6e56..1047be5fef 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -80,6 +80,7 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import org.junit.After; import org.junit.Before; @@ -108,7 +109,6 @@ public class PhoneSwitcherTest extends TelephonyTest { CompletableFuture mFuturePhone; private CommandsInterface mCommandsInterface0; private CommandsInterface mCommandsInterface1; - private Phone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. private ServiceStateTracker mSST2; private Phone mImsPhone; private DataSettingsManager mDataSettingsManager2; @@ -144,7 +144,6 @@ public class PhoneSwitcherTest extends TelephonyTest { mFuturePhone = mock(CompletableFuture.class); mCommandsInterface0 = mock(CommandsInterface.class); mCommandsInterface1 = mock(CommandsInterface.class); - mPhone2 = mock(Phone.class); // mPhone as phone 1 is already defined in TelephonyTest. mSST2 = mock(ServiceStateTracker.class); mImsPhone = mock(Phone.class); mDataSettingsManager2 = mock(DataSettingsManager.class); @@ -595,6 +594,7 @@ public class PhoneSwitcherTest extends TelephonyTest { SubscriptionInfo mockedInfo = mock(SubscriptionInfo.class); doReturn(false).when(mockedInfo).isOpportunistic(); doReturn(mockedInfo).when(mSubscriptionController).getSubscriptionInfo(anyInt()); + doReturn(mockedInfo).when(mSubscriptionManagerService).getSubscriptionInfo(anyInt()); initialize(); // Phone 0 has sub 1, phone 1 has sub 2. // Sub 1 is default data sub. @@ -604,22 +604,36 @@ public class PhoneSwitcherTest extends TelephonyTest { testAutoSwitchToSecondarySucceed(); clearInvocations(mSubscriptionController); + clearInvocations(mSubscriptionManagerService); Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(1, null, null)) .sendToTarget(); processAllMessages(); - verify(mSubscriptionController).getSubscriptionInfo(2); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService).getSubscriptionInfo(2); + } else { + verify(mSubscriptionController).getSubscriptionInfo(2); + } // switch back to primary clearInvocations(mSubscriptionController); + clearInvocations(mSubscriptionManagerService); Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(0, null, null)) .sendToTarget(); processAllMessages(); - verify(mSubscriptionController, never()).getSubscriptionInfo(1); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService, never()).getSubscriptionInfo(1); + } else { + verify(mSubscriptionController, never()).getSubscriptionInfo(1); + } Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(1, null, null)) .sendToTarget(); processAllMessages(); - verify(mSubscriptionController, never()).getSubscriptionInfo(2); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService, never()).getSubscriptionInfo(2); + } else { + verify(mSubscriptionController, never()).getSubscriptionInfo(2); + } } /** @@ -719,6 +733,9 @@ public class PhoneSwitcherTest extends TelephonyTest { setDefaultDataSubId(1); doReturn(true).when(mSubscriptionController).isOpportunistic(2); + doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService + .getSubscriptionInfoInternal(2)).setOpportunistic(1).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2); // Notify phoneSwitcher about default data sub and default network request. addInternetNetworkRequest(null, 50); @@ -763,6 +780,7 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(1, 2); // single visible sub, as the other one is CBRS doReturn(new int[1]).when(mSubscriptionController).getActiveSubIdList(true); + doReturn(new int[1]).when(mSubscriptionManagerService).getActiveSubIdList(true); setDefaultDataSubId(1); // Notify phoneSwitcher about default data sub and default network request. @@ -819,6 +837,7 @@ public class PhoneSwitcherTest extends TelephonyTest { clearInvocations(mCellularNetworkValidator); doReturn(new int[1]).when(mSubscriptionController).getActiveSubIdList(true); + doReturn(new int[1]).when(mSubscriptionManagerService).getActiveSubIdList(true); prepareIdealAutoSwitchCondition(); processAllFutureMessages(); @@ -872,6 +891,10 @@ public class PhoneSwitcherTest extends TelephonyTest { // Set sub 2 as preferred sub should make phone 1 preferredDataModem doReturn(true).when(mSubscriptionController).isOpportunistic(2); + doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService + .getSubscriptionInfoInternal(2)).setOpportunistic(1).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, null); processAllMessages(); mPhoneSwitcherUT.mValidationCallback.onNetworkAvailable(null, 2); @@ -938,6 +961,10 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); + doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService + .getSubscriptionInfoInternal(2)).setOpportunistic(1).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2); + // Phone 0 (sub 1) should be activated as it has default data sub. assertEquals(0, mPhoneSwitcherUT.getPreferredDataPhoneId()); @@ -1495,6 +1522,10 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(0, 1); setSlotIndexToSubId(1, 2); + doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService + .getSubscriptionInfoInternal(2)).setOpportunistic(1).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2); + // Switch to primary before a primary is selected/inactive. setDefaultDataSubId(-1); mPhoneSwitcherUT.trySetOpportunisticDataSubscription( @@ -1647,6 +1678,10 @@ public class PhoneSwitcherTest extends TelephonyTest { // Initialization done. doReturn(true).when(mSubscriptionController).isOpportunistic(2); + doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService + .getSubscriptionInfoInternal(2)).setOpportunistic(1).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, mSetOpptDataCallback1); processAllMessages(); verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), @@ -1685,6 +1720,10 @@ public class PhoneSwitcherTest extends TelephonyTest { // Initialization done. doReturn(true).when(mSubscriptionController).isOpportunistic(2); + doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService + .getSubscriptionInfoInternal(2)).setOpportunistic(1).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2); + mPhoneSwitcherUT.trySetOpportunisticDataSubscription(2, false, mSetOpptDataCallback1); processAllMessages(); verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), @@ -1733,6 +1772,8 @@ public class PhoneSwitcherTest extends TelephonyTest { clearInvocations(mMockRadioConfig); doReturn(mSubscriptionInfo).when(mSubscriptionController) .getActiveSubscriptionInfoForSimSlotIndex(eq(0), any(), any()); + doReturn(mSubscriptionInfo).when(mSubscriptionManagerService) + .getActiveSubscriptionInfoForSimSlotIndex(eq(0), any(), any()); doReturn(true).when(mSubscriptionInfo).areUiccApplicationsEnabled(); doReturn(mIccCard).when(mPhone).getIccCard(); doReturn(true).when(mIccCard).isEmptyProfile(); @@ -2028,10 +2069,13 @@ public class PhoneSwitcherTest extends TelephonyTest { */ private void initializeSubControllerMock() throws Exception { doReturn(mDefaultDataSub).when(mSubscriptionController).getDefaultDataSubId(); + doReturn(mDefaultDataSub).when(mSubscriptionManagerService).getDefaultDataSubId(); doReturn(mDefaultDataSub).when(mMockedIsub).getDefaultDataSubId(); doReturn(0).when(mSubscriptionController).getPhoneId(1); + doReturn(0).when(mSubscriptionManagerService).getPhoneId(1); doReturn(0).when(mMockedIsub).getPhoneId(1); doReturn(1).when(mSubscriptionController).getPhoneId(2); + doReturn(1).when(mSubscriptionManagerService).getPhoneId(2); doReturn(1).when(mMockedIsub).getPhoneId(2); doAnswer(invocation -> { int phoneId = (int) invocation.getArguments()[0]; @@ -2055,6 +2099,17 @@ public class PhoneSwitcherTest extends TelephonyTest { } }).when(mMockedIsub).getSubId(anyInt()); + doAnswer(invocation -> { + int phoneId = (int) invocation.getArguments()[0]; + if (phoneId == SubscriptionManager.INVALID_PHONE_INDEX) { + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) { + return mSlotIndexToSubId[0][0]; + } else { + return mSlotIndexToSubId[phoneId][0]; + } + }).when(mSubscriptionManagerService).getSubId(anyInt()); + doAnswer(invocation -> { int subId = (int) invocation.getArguments()[0]; @@ -2065,14 +2120,30 @@ public class PhoneSwitcherTest extends TelephonyTest { } return false; }).when(mSubscriptionController).isActiveSubId(anyInt()); + + doAnswer(invocation -> { + int subId = (int) invocation.getArguments()[0]; + + if (!SubscriptionManager.isUsableSubIdValue(subId)) return null; + + int slotIndex = -1; + for (int i = 0; i < mSlotIndexToSubId.length; i++) { + if (mSlotIndexToSubId[i][0] == subId) slotIndex = i; + } + return new SubscriptionInfoInternal.Builder() + .setSimSlotIndex(slotIndex).setId(subId).build(); + }).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + doReturn(new int[mSlotIndexToSubId.length]).when(mSubscriptionController) .getActiveSubIdList(true); + doReturn(new int[mSlotIndexToSubId.length]).when(mSubscriptionManagerService) + .getActiveSubIdList(true); } private void setDefaultDataSubId(int defaultDataSub) throws Exception { mDefaultDataSub = defaultDataSub; doReturn(mDefaultDataSub).when(mSubscriptionController).getDefaultDataSubId(); - doReturn(mDefaultDataSub).when(mMockedIsub).getDefaultDataSubId(); + doReturn(mDefaultDataSub).when(mSubscriptionManagerService).getDefaultDataSubId(); if (defaultDataSub == 1) { doReturn(true).when(mPhone).isUserDataEnabled(); doReturn(false).when(mPhone2).isUserDataEnabled(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index c2d0b40e9e..38f96d1bc1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -21,6 +21,7 @@ import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; @@ -102,13 +103,12 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private static final String OTA_EMERGENCY_NUMBER_ADDRESS = "98765"; private static final int SUB_ID_PHONE_1 = 1; private static final int SUB_ID_PHONE_2 = 2; - private static final int VALID_SLOT_INDEX_VALID_1 = 1; - private static final int VALID_SLOT_INDEX_VALID_2 = 2; + private static final int VALID_SLOT_INDEX_VALID_1 = 0; + private static final int VALID_SLOT_INDEX_VALID_2 = 1; private static final int INVALID_SLOT_INDEX_VALID = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - private ParcelFileDescriptor mOtaPracelFileDescriptor = null; + private ParcelFileDescriptor mOtaParcelFileDescriptor = null; // Mocked classes private SubscriptionController mSubControllerMock; - private Phone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest. // mEmergencyNumberTrackerMock for mPhone private EmergencyNumberTracker mEmergencyNumberTrackerMock; @@ -130,7 +130,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mShortNumberInfo = mock(ShortNumberInfo.class); mSubControllerMock = mock(SubscriptionController.class); - mPhone2 = mock(Phone.class); mContext = InstrumentationRegistry.getTargetContext(); mMockContext = mock(Context.class); mResources = mock(Resources.class); @@ -173,10 +172,10 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { mEmergencyNumberTrackerMock2 = null; mEmergencyNumberListTestSample.clear(); mEmergencyNumberListTestSample = null; - if (mOtaPracelFileDescriptor != null) { + if (mOtaParcelFileDescriptor != null) { try { - mOtaPracelFileDescriptor.close(); - mOtaPracelFileDescriptor = null; + mOtaParcelFileDescriptor.close(); + mOtaParcelFileDescriptor = null; } catch (IOException e) { logd("Failed to close emergency number db file folder for testing " + e.toString()); } @@ -242,11 +241,11 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { File file = new File(Environment.getExternalStorageDirectory(), LOCAL_DOWNLOAD_DIRECTORY + "/" + EMERGENCY_NUMBER_DB_OTA_FILE); try { - mOtaPracelFileDescriptor = ParcelFileDescriptor.open( + mOtaParcelFileDescriptor = ParcelFileDescriptor.open( file, ParcelFileDescriptor.MODE_READ_ONLY); emergencyNumberTrackerMock.obtainMessage( EmergencyNumberTracker.EVENT_OVERRIDE_OTA_EMERGENCY_NUMBER_DB_FILE_PATH, - mOtaPracelFileDescriptor).sendToTarget(); + mOtaParcelFileDescriptor).sendToTarget(); logd("Changed emergency number db file folder for testing "); } catch (FileNotFoundException e) { logd("Failed to open emergency number db file folder for testing " + e.toString()); @@ -333,6 +332,10 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { eq(SUB_ID_PHONE_1)); doReturn(VALID_SLOT_INDEX_VALID_2).when(mSubControllerMock).getSlotIndex( eq(SUB_ID_PHONE_2)); + doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubscriptionManagerService).getSlotIndex( + eq(SUB_ID_PHONE_1)); + doReturn(VALID_SLOT_INDEX_VALID_2).when(mSubscriptionManagerService).getSlotIndex( + eq(SUB_ID_PHONE_2)); assertFalse(mEmergencyNumberTrackerMock.isSimAbsent()); // One sim slot is active; the other one is not active @@ -340,6 +343,10 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { eq(SUB_ID_PHONE_1)); doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( eq(SUB_ID_PHONE_2)); + doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubscriptionManagerService).getSlotIndex( + eq(SUB_ID_PHONE_1)); + doReturn(INVALID_SLOT_INDEX_VALID).when(mSubscriptionManagerService).getSlotIndex( + eq(SUB_ID_PHONE_2)); assertFalse(mEmergencyNumberTrackerMock.isSimAbsent()); // Both sim slots are not active @@ -347,6 +354,8 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { eq(SUB_ID_PHONE_1)); doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( eq(SUB_ID_PHONE_2)); + doReturn(INVALID_SLOT_INDEX_VALID).when(mSubscriptionManagerService).getSlotIndex( + anyInt()); assertTrue(mEmergencyNumberTrackerMock.isSimAbsent()); } @@ -407,6 +416,8 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { eq(SUB_ID_PHONE_1)); doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( eq(SUB_ID_PHONE_2)); + doReturn(INVALID_SLOT_INDEX_VALID).when(mSubscriptionManagerService).getSlotIndex( + anyInt()); assertTrue(mEmergencyNumberTrackerMock.isSimAbsent()); sendEmptyEmergencyNumberListFromRadio(mEmergencyNumberTrackerMock); @@ -447,12 +458,20 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { eq(SUB_ID_PHONE_1)); doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( eq(SUB_ID_PHONE_2)); + doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubscriptionManagerService).getSlotIndex( + eq(SUB_ID_PHONE_1)); + doReturn(INVALID_SLOT_INDEX_VALID).when(mSubscriptionManagerService).getSlotIndex( + eq(SUB_ID_PHONE_2)); } else { //both slots active doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubControllerMock).getSlotIndex( eq(SUB_ID_PHONE_1)); doReturn(VALID_SLOT_INDEX_VALID_2).when(mSubControllerMock).getSlotIndex( eq(SUB_ID_PHONE_2)); + doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubscriptionManagerService).getSlotIndex( + eq(SUB_ID_PHONE_1)); + doReturn(VALID_SLOT_INDEX_VALID_2).when(mSubscriptionManagerService).getSlotIndex( + eq(SUB_ID_PHONE_2)); } assertFalse(mEmergencyNumberTrackerMock.isSimAbsent()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java index 53f42e9b3f..477a1fa1a0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java @@ -566,7 +566,12 @@ public class GsmSmsDispatcherTest extends TelephonyTest { doReturn(mIsimUiccRecords).when(mPhone).getIccRecords(); Message msg = mGsmSmsDispatcher.obtainMessage(17); mPhone.getIccRecords().setSmssTpmrValue(-1, msg); - SubscriptionController.getInstance().updateMessageRef(mPhone.getSubId(), -1); + if (isSubscriptionManagerServiceEnabled()) { + mSubscriptionManagerService.setLastUsedTPMessageReference(mPhone.getSubId(), -1); + } else { + SubscriptionController.getInstance().updateMessageRef(mPhone.getSubId(), -1); + } + mGsmSmsDispatcher.sendText("111", "222" /*scAddr*/, TAG, null, null, null, null, false, -1, false, -1, false, 0L); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 911d3b63c9..41890e9409 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -127,6 +127,7 @@ import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.d2d.RtpTransport; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker.VtDataUsageProvider; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import org.junit.After; import org.junit.Assert; @@ -241,6 +242,9 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { mContextFixture.addSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS); mDomainSelectionResolver = mock(DomainSelectionResolver.class); + doReturn(new SubscriptionInfoInternal.Builder().setSimSlotIndex(0).setId(1).build()) + .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); + doAnswer(invocation -> { mMmTelListener = (MmTelFeature.Listener) invocation.getArguments()[0]; return null; 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 59d57e7dc3..ffa29ae662 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -41,6 +41,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyChar; import static org.mockito.Matchers.anyInt; @@ -98,6 +99,7 @@ import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.imsphone.ImsPhone.SS; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import org.junit.After; import org.junit.Before; @@ -955,6 +957,9 @@ public class ImsPhoneTest extends TelephonyTest { SubscriptionInfo subInfo = mock(SubscriptionInfo.class); doReturn("gb").when(subInfo).getCountryIso(); doReturn(subInfo).when(mSubscriptionController).getSubscriptionInfo(subId); + doReturn(new SubscriptionInfoInternal.Builder().setId(subId).setSimSlotIndex(0) + .setCountryIso("gb").build()).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(subId); // 1. Two valid phone number; 1st is set. Uri[] associatedUris = new Uri[] { @@ -963,8 +968,12 @@ public class ImsPhoneTest extends TelephonyTest { }; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - verify(mSubscriptionController).setSubscriptionProperty( - subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, "+447539447777"); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService).setNumberFromIms(subId, "+447539447777"); + } else { + verify(mSubscriptionController).setSubscriptionProperty( + subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, "+447539447777"); + } // 2. 1st invalid and 2nd valid: 2nd is set. associatedUris = new Uri[] { @@ -973,8 +982,12 @@ public class ImsPhoneTest extends TelephonyTest { }; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - verify(mSubscriptionController).setSubscriptionProperty( - subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, "+447539446666"); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService).setNumberFromIms(subId, "+447539446666"); + } else { + verify(mSubscriptionController).setSubscriptionProperty( + subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, "+447539446666"); + } // 3. 1st sip-uri is not phone number and 2nd valid: 2nd is set. associatedUris = new Uri[] { @@ -984,8 +997,12 @@ public class ImsPhoneTest extends TelephonyTest { }; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - verify(mSubscriptionController).setSubscriptionProperty( - subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, "+447539446677"); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService).setNumberFromIms(subId, "+447539446677"); + } else { + verify(mSubscriptionController).setSubscriptionProperty( + subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, "+447539446677"); + } // Clean up mContextFixture.addCallingOrSelfPermission(""); @@ -1001,6 +1018,9 @@ public class ImsPhoneTest extends TelephonyTest { SubscriptionInfo subInfo = mock(SubscriptionInfo.class); doReturn("gb").when(subInfo).getCountryIso(); doReturn(subInfo).when(mSubscriptionController).getSubscriptionInfo(subId); + doReturn(new SubscriptionInfoInternal.Builder().setId(subId).setSimSlotIndex(0) + .setCountryIso("gb").build()).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(0); // 1. No valid phone number; do not set Uri[] associatedUris = new Uri[] { @@ -1009,28 +1029,44 @@ public class ImsPhoneTest extends TelephonyTest { }; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - verify(mSubscriptionController, never()).setSubscriptionProperty( - anyInt(), any(), any()); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); + } else { + verify(mSubscriptionController, never()).setSubscriptionProperty( + anyInt(), any(), any()); + } // 2. no URI; do not set associatedUris = new Uri[] {}; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - verify(mSubscriptionController, never()).setSubscriptionProperty( - anyInt(), any(), any()); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); + } else { + verify(mSubscriptionController, never()).setSubscriptionProperty( + anyInt(), any(), any()); + } // 3. null URI; do not set associatedUris = new Uri[] { null }; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - verify(mSubscriptionController, never()).setSubscriptionProperty( - anyInt(), any(), any()); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); + } else { + verify(mSubscriptionController, never()).setSubscriptionProperty( + anyInt(), any(), any()); + } // 4. null pointer; do not set mImsPhoneUT.setPhoneNumberForSourceIms(null); - verify(mSubscriptionController, never()).setSubscriptionProperty( - anyInt(), any(), any()); + if (isSubscriptionManagerServiceEnabled()) { + verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); + } else { + verify(mSubscriptionController, never()).setSubscriptionProperty( + anyInt(), any(), any()); + } // Clean up mContextFixture.addCallingOrSelfPermission(""); diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java index 12a5828985..10151b8b0b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java @@ -45,6 +45,8 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.UiccSlot; import org.junit.After; @@ -84,15 +86,28 @@ public class PerSimStatusTest extends TelephonyTest { doReturn("6506953210") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); + doReturn("6506953210") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); doReturn("") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); + doReturn("") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); doReturn("+16506953210") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); + doReturn("+16506953210") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); SubscriptionInfo subscriptionInfo1 = mock(SubscriptionInfo.class); doReturn("us").when(subscriptionInfo1).getCountryIso(); doReturn(subscriptionInfo1).when(mSubscriptionController).getSubscriptionInfo(1); + doReturn(new SubscriptionInfoInternal.Builder().setId(1).setSimSlotIndex(0) + .setCountryIso("us").build()).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(1); + ImsManager imsManager = mContext.getSystemService(ImsManager.class); ImsMmTelManager imsMmTelManager1 = mock(ImsMmTelManager.class); doReturn(imsMmTelManager1).when(imsManager).getImsMmTelManager(1); @@ -126,15 +141,28 @@ public class PerSimStatusTest extends TelephonyTest { doReturn("0123") .when(mSubscriptionController) .getPhoneNumber(2, PHONE_NUMBER_SOURCE_UICC, null, null); + doReturn("0123") + .when(mSubscriptionManagerService) + .getPhoneNumber(2, PHONE_NUMBER_SOURCE_UICC, null, null); doReturn("16506950123") .when(mSubscriptionController) .getPhoneNumber(2, PHONE_NUMBER_SOURCE_CARRIER, null, null); + doReturn("16506950123") + .when(mSubscriptionManagerService) + .getPhoneNumber(2, PHONE_NUMBER_SOURCE_CARRIER, null, null); doReturn("+16506950123") .when(mSubscriptionController) .getPhoneNumber(2, PHONE_NUMBER_SOURCE_IMS, null, null); + doReturn("+16506950123") + .when(mSubscriptionManagerService) + .getPhoneNumber(2, PHONE_NUMBER_SOURCE_IMS, null, null); SubscriptionInfo subscriptionInfo2 = mock(SubscriptionInfo.class); doReturn("us").when(subscriptionInfo2).getCountryIso(); doReturn(subscriptionInfo2).when(mSubscriptionController).getSubscriptionInfo(2); + doReturn(new SubscriptionInfoInternal.Builder().setId(2).setSimSlotIndex(1) + .setCountryIso("us").build()).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(2); + ImsMmTelManager imsMmTelManager2 = mock(ImsMmTelManager.class); doReturn(imsMmTelManager2).when(imsManager).getImsMmTelManager(2); doReturn(true).when(imsMmTelManager2).isAdvancedCallingSettingEnabled(); @@ -206,6 +234,7 @@ public class PerSimStatusTest extends TelephonyTest { @SmallTest public void onPullAtom_perSimStatus_noSubscriptionController() throws Exception { replaceInstance(SubscriptionController.class, "sInstance", null, null); + replaceInstance(SubscriptionManagerService.class, "sInstance", null, null); PerSimStatus perSimStatus = PerSimStatus.getCurrentState(mPhone); @@ -221,15 +250,27 @@ public class PerSimStatusTest extends TelephonyTest { doReturn("6506953210") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); + doReturn("6506953210") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); doReturn("") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); + doReturn("") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); doReturn("+16506953210") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); + doReturn("+16506953210") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class); doReturn("us").when(subscriptionInfo).getCountryIso(); doReturn(subscriptionInfo).when(mSubscriptionController).getSubscriptionInfo(1); + doReturn(new SubscriptionInfoInternal.Builder().setId(1).setSimSlotIndex(0) + .setCountryIso("us").build()).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(1); doReturn(null).when(mContext).getSystemService(ImsManager.class); doReturn(1L) .when(mPhone) @@ -276,15 +317,27 @@ public class PerSimStatusTest extends TelephonyTest { doReturn("6506953210") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); + doReturn("6506953210") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); doReturn("") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); + doReturn("") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); doReturn("+16506953210") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); + doReturn("+16506953210") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class); doReturn("us").when(subscriptionInfo).getCountryIso(); doReturn(subscriptionInfo).when(mSubscriptionController).getSubscriptionInfo(1); + doReturn(new SubscriptionInfoInternal.Builder().setId(1).setSimSlotIndex(0) + .setCountryIso("us").build()).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(1); ImsManager imsManager = mContext.getSystemService(ImsManager.class); doThrow(new IllegalArgumentException()).when(imsManager).getImsMmTelManager(1); doReturn(false).when(mPhone).getDataRoamingEnabled(); @@ -333,15 +386,27 @@ public class PerSimStatusTest extends TelephonyTest { doReturn("6506953210") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); + doReturn("6506953210") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); doReturn("") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); + doReturn("") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); doReturn("+16506953210") .when(mSubscriptionController) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); + doReturn("+16506953210") + .when(mSubscriptionManagerService) + .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class); doReturn("us").when(subscriptionInfo).getCountryIso(); doReturn(subscriptionInfo).when(mSubscriptionController).getSubscriptionInfo(1); + doReturn(new SubscriptionInfoInternal.Builder().setId(1).setSimSlotIndex(0) + .setCountryIso("us").build()).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(1); doReturn(null).when(mContext).getSystemService(ImsManager.class); doReturn(1L) .when(mPhone) 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 5eca02b6c8..ceb507519b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -144,6 +144,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionManagerServiceTest +Setup!"); super.setUp(getClass().getSimpleName()); + enableSubscriptionManagerService(true); mContextFixture.putBooleanResource(com.android.internal.R.bool .config_subscription_database_async_update, true); mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[0]); diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java index f035714600..95f0cd65a5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java @@ -52,6 +52,7 @@ import com.android.internal.telephony.ISub; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.cat.CatService; +import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState; import org.junit.After; @@ -579,6 +580,9 @@ public class UiccProfileTest extends TelephonyTest { doReturn(false).when(mSubscriptionController) .checkPhoneIdAndIccIdMatch(anyInt(), anyString()); + doReturn(new SubscriptionInfoInternal.Builder().setSimSlotIndex(0).setId(1) + .setIccId("98765").build()).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(anyInt()); mUiccProfile.setOperatorBrandOverride(fakeBrand); String brandInSharedPreference = mContext.getSharedPreferences("file name", 0) .getString("operator_branding_" + fakeIccId, null); @@ -586,6 +590,9 @@ public class UiccProfileTest extends TelephonyTest { doReturn(true).when(mSubscriptionController) .checkPhoneIdAndIccIdMatch(anyInt(), anyString()); + doReturn(new SubscriptionInfoInternal.Builder().setSimSlotIndex(0).setId(1) + .setIccId(fakeIccId).build()).when(mSubscriptionManagerService) + .getSubscriptionInfoInternal(anyInt()); mUiccProfile.setOperatorBrandOverride(fakeBrand); brandInSharedPreference = mContext.getSharedPreferences("file name", 0) .getString("operator_branding_" + fakeIccId, null); diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java index 719fd8ddc0..8672b45e3e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java @@ -158,8 +158,12 @@ public class UiccSlotTest extends TelephonyTest { assertTrue(mUiccSlot.isActive()); assertNull(mUiccSlot.getUiccCard()); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + if (isSubscriptionManagerServiceEnabled()) { + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + } else { + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + } } @Test @@ -380,8 +384,12 @@ public class UiccSlotTest extends TelephonyTest { // Make sure when received CARDSTATE_ABSENT state in the first time, mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + if (isSubscriptionManagerServiceEnabled()) { + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + } else { + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + } assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); } @@ -414,8 +422,15 @@ public class UiccSlotTest extends TelephonyTest { assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); // assert that we tried to update subscriptions - verify(mSubInfoRecordUpdater).updateInternalIccStateForInactivePort( - activeIss.mSimPortInfos[0].mLogicalSlotIndex, inactiveIss.mSimPortInfos[0].mIccId); + if (isSubscriptionManagerServiceEnabled()) { + verify(mUiccController).updateSimStateForInactivePort( + activeIss.mSimPortInfos[0].mLogicalSlotIndex, + inactiveIss.mSimPortInfos[0].mIccId); + } else { + verify(mSubInfoRecordUpdater).updateInternalIccStateForInactivePort( + activeIss.mSimPortInfos[0].mLogicalSlotIndex, + inactiveIss.mSimPortInfos[0].mIccId); + } } @Test @@ -438,8 +453,12 @@ public class UiccSlotTest extends TelephonyTest { // state is sent to SubscriptionInfoUpdater. mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + if (isSubscriptionManagerServiceEnabled()) { + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + } else { + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + } verify(mUiccProfile).dispose(); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); @@ -463,8 +482,12 @@ public class UiccSlotTest extends TelephonyTest { mUiccSlot.onRadioStateUnavailable(phoneId); // Verify that UNKNOWN state is sent to SubscriptionInfoUpdater in this case. - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null, phoneId); + if (isSubscriptionManagerServiceEnabled()) { + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.UNKNOWN, null); + } else { + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null, phoneId); + } assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); @@ -473,8 +496,12 @@ public class UiccSlotTest extends TelephonyTest { mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); // Verify that ABSENT state is sent to SubscriptionInfoUpdater in this case. - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + if (isSubscriptionManagerServiceEnabled()) { + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); + } else { + verify(mSubInfoRecordUpdater).updateInternalIccState( + IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); + } assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); } -- GitLab From fb38004c5fa88cf8cb56f21ff3f2a24dc2f4aac5 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 20 Feb 2023 00:08:48 -0800 Subject: [PATCH 452/656] Added unit tests for SubscriptionManagerService Bug: 269988889 Test: atest SubscriptionManagerServiceTest Change-Id: If146f3ddff4c22113c8d31b5a94a15895be89ad2 --- .../SubscriptionManagerServiceTest.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) 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 5eca02b6c8..76b3ae24e4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -111,11 +111,15 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.io.StringWriter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.Set; +import java.util.concurrent.CountDownLatch; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -552,6 +556,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.setDefaultVoiceSubId(1); + assertThat(mSubscriptionManagerServiceUT.getDefaultVoiceSubId()).isEqualTo(1); assertThat(Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION)).isEqualTo(1); @@ -593,6 +598,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.setDefaultDataSubId(1); + assertThat(mSubscriptionManagerServiceUT.getDefaultDataSubId()).isEqualTo(1); assertThat(Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION)).isEqualTo(1); @@ -632,6 +638,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); mSubscriptionManagerServiceUT.setDefaultSmsSubId(1); + assertThat(mSubscriptionManagerServiceUT.getDefaultSmsSubId()).isEqualTo(1); assertThat(Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION)).isEqualTo(1); @@ -1766,6 +1773,11 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mSubscriptionManagerServiceUT.updateSimState( 0, TelephonyManager.SIM_STATE_LOADED, null, null); processAllMessages(); + + assertThat(mSubscriptionManagerServiceUT.getSubId(0)).isEqualTo(1); + assertThat(mSubscriptionManagerServiceUT.getSlotIndex(1)).isEqualTo(0); + assertThat(mSubscriptionManagerServiceUT.getPhoneId(1)).isEqualTo(0); + mSubscriptionManagerServiceUT.setCarrierId(1, FAKE_CARRIER_ID1); mSubscriptionManagerServiceUT.setDisplayNameUsingSrc(FAKE_CARRIER_NAME1, 1, SubscriptionManager.NAME_SOURCE_SIM_SPN); @@ -1903,4 +1915,53 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfoList.get(0).isActive()).isTrue(); assertThat(subInfoList.get(0).getIccId()).isEqualTo(FAKE_ICCID2); } + + @Test + public void testDump() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + final StringWriter stringWriter = new StringWriter(); + mSubscriptionManagerServiceUT.dump(new FileDescriptor(), new PrintWriter(stringWriter), + null); + assertThat(stringWriter.toString().length()).isGreaterThan(0); + } + + @Test + public void testOnSubscriptionChanged() { + CountDownLatch latch = new CountDownLatch(1); + SubscriptionManagerServiceCallback callback = + new SubscriptionManagerServiceCallback(Runnable::run) { + @Override + public void onSubscriptionChanged(int subId) { + latch.countDown(); + logd("testOnSubscriptionChanged: onSubscriptionChanged"); + } + }; + mSubscriptionManagerServiceUT.registerCallback(callback); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + processAllMessages(); + assertThat(latch.getCount()).isEqualTo(0); + } + + @Test + public void testOnUiccApplicationsEnabled() { + CountDownLatch latch = new CountDownLatch(1); + SubscriptionManagerServiceCallback callback = + new SubscriptionManagerServiceCallback(Runnable::run) { + @Override + public void onUiccApplicationsEnabled(int subId) { + latch.countDown(); + logd("testOnSubscriptionChanged: onUiccApplicationsEnabled"); + } + }; + mSubscriptionManagerServiceUT.registerCallback(callback); + int subId = insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + mSubscriptionManagerServiceUT.setUiccApplicationsEnabled(false, subId); + processAllMessages(); + assertThat(latch.getCount()).isEqualTo(0); + } } -- GitLab From 3e2a347609b376752df0fb3fa08299b2d148d0ed Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 20 Feb 2023 21:17:51 -0800 Subject: [PATCH 453/656] Cleaned up the usage of SubscriptionManger.getSubId Cleaned up the old APIs and replaced with the new APIs. Bug: 270094276 Test: Boot up + Basic phone funcationality tests Change-Id: Ie68cc64241516852044bd7ea7afcdbff5b4a315f --- .../android/internal/telephony/SubscriptionController.java | 1 - .../telephony/subscription/SubscriptionManagerService.java | 5 ----- 2 files changed, 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index e886742343..3466b990ed 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -2631,7 +2631,6 @@ public class SubscriptionController extends ISub.Stub { * @deprecated */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Override @Deprecated public int[] getSubIds(int slotIndex) { if (VDBG) printStackTrace("[getSubId]+ slotIndex=" + slotIndex); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 701f6b3c9b..351e85920e 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -2632,11 +2632,6 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.INVALID_SUBSCRIPTION_ID); } - @Override - public int[] getSubIds(int slotIndex) { - return new int[]{getSubId(slotIndex)}; - } - /** * Update default sub id. */ -- GitLab From c4691fe1af1a52b3b8c35c85544ec38e070ba6f3 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 16 Feb 2023 03:04:54 -0800 Subject: [PATCH 454/656] Enhanced subscription database manager logs Fix: 269493080 Test: Boot up and exame the bugreport Change-Id: I53d9c8d2994b12a1f9d85f4515e20a223ac636a4 --- .../SubscriptionDatabaseManager.java | 34 ++++++++++++++----- .../SubscriptionManagerService.java | 2 ++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 2e5b9b6385..aa3ecf6f40 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -506,8 +506,8 @@ public class SubscriptionDatabaseManager extends Handler { new HashMap<>(16); /** Whether database has been initialized after boot up. */ - @GuardedBy("mDatabaseInitialized") - private Boolean mDatabaseInitialized = false; + @GuardedBy("this") + private boolean mDatabaseInitialized = false; /** * This is the callback used for listening events from {@link SubscriptionDatabaseManager}. @@ -759,7 +759,7 @@ public class SubscriptionDatabaseManager extends Handler { + "insert. subInfo=" + subInfo); } - synchronized (mDatabaseInitialized) { + synchronized (this) { if (!mDatabaseInitialized) { throw new IllegalStateException( "Database has not been initialized. Can't insert new " @@ -831,7 +831,7 @@ public class SubscriptionDatabaseManager extends Handler { private int updateDatabase(int subId, @NonNull ContentValues contentValues) { logv("updateDatabase: prepare to update sub " + subId); - synchronized (mDatabaseInitialized) { + synchronized (this) { if (!mDatabaseInitialized) { logel("updateDatabase: Database has not been initialized. Can't update database at " + "this point. contentValues=" + contentValues); @@ -1852,7 +1852,7 @@ public class SubscriptionDatabaseManager extends Handler { if (mAsyncMode) { // Load the database asynchronously. post(() -> { - synchronized (mDatabaseInitialized) { + synchronized (this) { loadDatabaseInternal(); mDatabaseInitialized = true; mCallback.invokeFromExecutor(mCallback::onInitialized); @@ -1860,7 +1860,7 @@ public class SubscriptionDatabaseManager extends Handler { }); } else { // Load the database synchronously. - synchronized (mDatabaseInitialized) { + synchronized (this) { loadDatabaseInternal(); mDatabaseInitialized = true; mCallback.invokeFromExecutor(mCallback::onInitialized); @@ -2120,7 +2120,7 @@ public class SubscriptionDatabaseManager extends Handler { } /** - * Dump the state of {@link SubscriptionManagerService}. + * Dump the state of {@link SubscriptionDatabaseManager}. * * @param fd File descriptor * @param printWriter Print writer @@ -2129,11 +2129,27 @@ public class SubscriptionDatabaseManager extends Handler { public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter printWriter, @NonNull String[] args) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); - pw.println(SubscriptionManagerService.class.getSimpleName() + ":"); + pw.println(SubscriptionDatabaseManager.class.getSimpleName() + ":"); pw.increaseIndent(); pw.println("All subscriptions:"); pw.increaseIndent(); - mAllSubscriptionInfoInternalCache.forEach((subId, subInfo) -> pw.println(subInfo)); + mReadWriteLock.readLock().lock(); + try { + mAllSubscriptionInfoInternalCache.forEach((subId, subInfo) -> pw.println(subInfo)); + } finally { + mReadWriteLock.readLock().unlock(); + } + pw.decreaseIndent(); + pw.println(); + pw.println("mAsyncMode=" + mAsyncMode); + synchronized (this) { + pw.println("mDatabaseInitialized=" + mDatabaseInitialized); + } + pw.println("mReadWriteLock=" + mReadWriteLock); + pw.println(); + pw.println("Local log:"); + pw.increaseIndent(); + mLocalLog.dump(fd, printWriter, args); pw.decreaseIndent(); pw.decreaseIndent(); } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 701f6b3c9b..862b919a96 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -3972,5 +3972,7 @@ public class SubscriptionManagerService extends ISub.Stub { mLocalLog.dump(fd, pw, args); pw.decreaseIndent(); pw.decreaseIndent(); + pw.println(); + mSubscriptionDatabaseManager.dump(fd, pw, args); } } -- GitLab From 04120adf03027528cbb5ae9b5103a4b4732d1d7c Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 5 Dec 2022 17:16:10 -0600 Subject: [PATCH 455/656] Update CarrierSignalAgent with new CarrierConfigManager APIs Improve the performance of CarrierSignalAgent by: - Replacing carrier config change broadcast receiver with listener which has much lower lagency. - Retrieving subset carrier configs as needed to save memory Bug: 244087782 Test: atest CarrierSignalAgentTest Change-Id: I7df0840f9645a2d0462ab13d6bb083dbbcfac3a8 Merged-In: I7df0840f9645a2d0462ab13d6bb083dbbcfac3a8 (cherry picked from commit 16e659fdd442fca1dc76c172eeb740153655ec9a) --- .../telephony/CarrierSignalAgent.java | 97 +++++++++---------- .../telephony/CarrierSignalAgentTest.java | 46 ++++++--- 2 files changed, 81 insertions(+), 62 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierSignalAgent.java b/src/java/com/android/internal/telephony/CarrierSignalAgent.java index 8509c5eae0..3250cef0d0 100644 --- a/src/java/com/android/internal/telephony/CarrierSignalAgent.java +++ b/src/java/com/android/internal/telephony/CarrierSignalAgent.java @@ -20,11 +20,8 @@ import static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL import android.annotation.Nullable; import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.Network; @@ -125,25 +122,21 @@ public class CarrierSignalAgent extends Handler { private final LocalLog mErrorLocalLog = new LocalLog(16); - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (DBG) log("CarrierSignalAgent receiver action: " + action); - if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - loadCarrierConfig(); - } - } - }; - private ConnectivityManager.NetworkCallback mNetworkCallback; /** Constructor */ public CarrierSignalAgent(Phone phone) { mPhone = phone; + CarrierConfigManager carrierConfigManager = mPhone.getContext().getSystemService( + CarrierConfigManager.class); loadCarrierConfig(); - // reload configurations on CARRIER_CONFIG_CHANGED - mPhone.getContext().registerReceiver(mReceiver, - new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + carrierConfigManager.registerCarrierConfigChangeListener( + mPhone.getContext().getMainExecutor(), + (slotIndex, subId, carrierId, specificCarrierId) -> { + if (slotIndex == mPhone.getPhoneId()) { + loadCarrierConfig(); + } + }); mPhone.getCarrierActionAgent().registerForCarrierAction( CarrierActionAgent.CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS, this, EVENT_REGISTER_DEFAULT_NETWORK_AVAIL, null, false); @@ -205,45 +198,47 @@ public class CarrierSignalAgent extends Handler { * load carrier config and cached the results into a hashMap action -> array list of components. */ private void loadCarrierConfig() { - CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext() - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - PersistableBundle b = null; - if (configManager != null) { - b = configManager.getConfigForSubId(mPhone.getSubId()); + PersistableBundle b = + CarrierConfigManager.getCarrierConfigSubset( + mPhone.getContext(), + mPhone.getSubId(), + KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY, + KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY); + if (b.isEmpty()) { + return; } - if (b != null) { - synchronized (mCachedWakeSignalConfigs) { - log("Loading carrier config: " + KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY); - Map> config = parseAndCache( - b.getStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY)); - // In some rare cases, up-to-date config could be fetched with delay and all signals - // have already been delivered the receivers from the default carrier config. - // To handle this raciness, we should notify those receivers (from old configs) - // and reset carrier actions. This should be done before cached Config got purged - // and written with the up-to-date value, Otherwise those receivers from the - // old config might lingers without properly clean-up. - if (!mCachedWakeSignalConfigs.isEmpty() - && !config.equals(mCachedWakeSignalConfigs)) { - if (VDBG) log("carrier config changed, reset receivers from old config"); - mPhone.getCarrierActionAgent().sendEmptyMessage( - CarrierActionAgent.CARRIER_ACTION_RESET); - } - mCachedWakeSignalConfigs = config; + + synchronized (mCachedWakeSignalConfigs) { + log("Loading carrier config: " + KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY); + Map> config = parseAndCache( + b.getStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY)); + // In some rare cases, up-to-date config could be fetched with delay and all signals + // have already been delivered the receivers from the default carrier config. + // To handle this raciness, we should notify those receivers (from old configs) + // and reset carrier actions. This should be done before cached Config got purged + // and written with the up-to-date value, Otherwise those receivers from the + // old config might lingers without properly clean-up. + if (!mCachedWakeSignalConfigs.isEmpty() + && !config.equals(mCachedWakeSignalConfigs)) { + if (VDBG) log("carrier config changed, reset receivers from old config"); + mPhone.getCarrierActionAgent().sendEmptyMessage( + CarrierActionAgent.CARRIER_ACTION_RESET); } + mCachedWakeSignalConfigs = config; + } - synchronized (mCachedNoWakeSignalConfigs) { - log("Loading carrier config: " - + KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY); - Map> config = parseAndCache( - b.getStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY)); - if (!mCachedNoWakeSignalConfigs.isEmpty() - && !config.equals(mCachedNoWakeSignalConfigs)) { - if (VDBG) log("carrier config changed, reset receivers from old config"); - mPhone.getCarrierActionAgent().sendEmptyMessage( - CarrierActionAgent.CARRIER_ACTION_RESET); - } - mCachedNoWakeSignalConfigs = config; + synchronized (mCachedNoWakeSignalConfigs) { + log("Loading carrier config: " + + KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY); + Map> config = parseAndCache( + b.getStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY)); + if (!mCachedNoWakeSignalConfigs.isEmpty() + && !config.equals(mCachedNoWakeSignalConfigs)) { + if (VDBG) log("carrier config changed, reset receivers from old config"); + mPhone.getCarrierActionAgent().sendEmptyMessage( + CarrierActionAgent.CARRIER_ACTION_RESET); } + mCachedNoWakeSignalConfigs = config; } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java index e070b06247..4dfadd240a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java @@ -61,6 +61,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Map; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.function.Function; import java.util.stream.Collectors; @@ -70,6 +71,8 @@ public class CarrierSignalAgentTest extends TelephonyTest { private CarrierSignalAgent mCarrierSignalAgentUT; private PersistableBundle mBundle; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; + private static final String PCO_RECEIVER = "pak/PCO_RECEIVER"; private static final String DC_ERROR_RECEIVER = "pak/DC_ERROR_RECEIVER"; private static final String LEGACY_RECEIVER = "old.pkg/LEGACY_RECEIVER"; @@ -103,6 +106,7 @@ public class CarrierSignalAgentTest extends TelephonyTest { FAKE_DEFAULT_NETWORK_INTENT.putExtra( TelephonyManager.EXTRA_DEFAULT_NETWORK_AVAILABLE, true); } + private static final int PHONE_ID = 0; // Mocked classes ResolveInfo mResolveInfo; @@ -112,8 +116,17 @@ public class CarrierSignalAgentTest extends TelephonyTest { logd("CarrierSignalAgentTest +Setup!"); super.setUp(getClass().getSimpleName()); mResolveInfo = mock(ResolveInfo.class); + doReturn((Executor) Runnable::run).when(mContext).getMainExecutor(); mBundle = mContextFixture.getCarrierConfigBundle(); + when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); + + // Capture listener to emulate the carrier config change notification used later + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); mCarrierSignalAgentUT = new CarrierSignalAgent(mPhone); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); ComponentName legacyReceiverComponent = ComponentName.unflattenFromString(LEGACY_RECEIVER); ApplicationInfo fakeLegacyApplicationInfo = new ApplicationInfo(); @@ -159,9 +172,10 @@ public class CarrierSignalAgentTest extends TelephonyTest { verify(mContext, times(count)).sendBroadcast(mCaptorIntent.capture()); // Trigger carrier config reloading - mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + mCarrierConfigChangeListener.onCarrierConfigChanged(PHONE_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); - count++; // Verify no broadcast has been sent due to no manifest receivers mCarrierSignalAgentUT.notifyCarrierSignalReceivers(intent); @@ -208,14 +222,16 @@ public class CarrierSignalAgentTest extends TelephonyTest { }); // Trigger carrier config reloading - mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + mCarrierConfigChangeListener.onCarrierConfigChanged(PHONE_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); // Verify broadcast has been sent to two different registered manifest receivers doReturn(new ArrayList<>(Arrays.asList(mResolveInfo))) .when(mPackageManager).queryBroadcastReceivers((Intent) any(), anyInt()); - int broadcastCount = 1; + int broadcastCount = 0; { mCarrierSignalAgentUT.notifyCarrierSignalReceivers(new Intent(FAKE_PCO_INTENT)); broadcastCount++; @@ -325,9 +341,10 @@ public class CarrierSignalAgentTest extends TelephonyTest { verify(mContext, times(count)).sendBroadcast(mCaptorIntent.capture()); // Trigger carrier config reloading - mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + mCarrierConfigChangeListener.onCarrierConfigChanged(PHONE_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); - count++; // Verify broadcast has been sent to registered components mCarrierSignalAgentUT.notifyCarrierSignalReceivers(intent); @@ -362,9 +379,10 @@ public class CarrierSignalAgentTest extends TelephonyTest { argThat(o -> Objects.equals(o.getAction(), ACTION_CARRIER_SIGNAL_PCO_VALUE)), anyInt()); - mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + mCarrierConfigChangeListener.onCarrierConfigChanged(PHONE_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); - count++; // Wake signal for PAK_PCO_RECEIVER mCarrierSignalAgentUT.notifyCarrierSignalReceivers( @@ -417,7 +435,9 @@ public class CarrierSignalAgentTest extends TelephonyTest { CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY, new String[]{ PCO_RECEIVER + ":" + ACTION_CARRIER_SIGNAL_PCO_VALUE + "," + ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED }); - mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + mCarrierConfigChangeListener.onCarrierConfigChanged(PHONE_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); // verify no reset action on initial config load verify(mCarrierActionAgent, times(0)).sendMessageAtTime(any(Message.class), anyLong()); @@ -427,7 +447,9 @@ public class CarrierSignalAgentTest extends TelephonyTest { CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY, new String[]{ PCO_RECEIVER + ":" + ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED + "," + ACTION_CARRIER_SIGNAL_PCO_VALUE}); - mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + mCarrierConfigChangeListener.onCarrierConfigChanged(PHONE_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); // verify no reset action for the same config (different order) verify(mCarrierActionAgent, times(0)).sendMessageAtTime(any(Message.class), anyLong()); @@ -437,7 +459,9 @@ public class CarrierSignalAgentTest extends TelephonyTest { CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY, new String[]{ DC_ERROR_RECEIVER + ":" + ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED + "," + ACTION_CARRIER_SIGNAL_PCO_VALUE}); - mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + mCarrierConfigChangeListener.onCarrierConfigChanged(PHONE_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); processAllMessages(); // verify there is no reset action ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); -- GitLab From 4a2d019295a41c1b14ea0a46ede8dfadca1ef98f Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Tue, 21 Feb 2023 13:53:41 -0800 Subject: [PATCH 456/656] register intent receiver for country change -this code was removed by mistake in ag/20657717 -added test Bug: 269676510 Test: atest EmergencyNumberTrackerTest Change-Id: I82d4eeba5dce48d2e5d8445b2e4456c6627b348a --- .../emergency/EmergencyNumberTracker.java | 9 +++++++- .../emergency/EmergencyNumberTrackerTest.java | 23 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 8c8dff2fe2..61f8aa3d51 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Resources; import android.os.AsyncResult; import android.os.Environment; @@ -199,6 +200,12 @@ public class EmergencyNumberTracker extends Handler { configMgr.registerCarrierConfigChangeListener(this::post, (slotIndex, subId, carrierId, specificCarrierId) -> onCarrierConfigUpdated(slotIndex)); + + //register country change listener + IntentFilter filter = new IntentFilter( + TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED); + mPhone.getContext().registerReceiver(mIntentReceiver, filter); + } else { loge("CarrierConfigManager is null."); } @@ -544,7 +551,7 @@ public class EmergencyNumberTracker extends Handler { readInputStreamToByteArray(gzipInputStream)); assetsDatabaseVersion = allEccMessages.revision; logd(countryIso + " asset emergency database is loaded. Ver: " + assetsDatabaseVersion - + " Phone Id: " + mPhone.getPhoneId()); + + " Phone Id: " + mPhone.getPhoneId() + " countryIso: " + countryIso); for (ProtobufEccData.CountryInfo countryEccInfo : allEccMessages.countries) { if (countryEccInfo.isoCode.equals(countryIso.toUpperCase(Locale.ROOT))) { for (ProtobufEccData.EccInfo eccInfo : countryEccInfo.eccs) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index 38f96d1bc1..5a197b78ad 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -24,18 +24,26 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import org.mockito.ArgumentCaptor; + +import android.content.IntentFilter; import android.content.Context; +import android.content.ContextWrapper; import android.content.res.AssetManager; import android.content.res.Resources; import android.os.AsyncResult; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.telephony.emergency.EmergencyNumber; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -130,7 +138,8 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mShortNumberInfo = mock(ShortNumberInfo.class); mSubControllerMock = mock(SubscriptionController.class); - mContext = InstrumentationRegistry.getTargetContext(); + + mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()); mMockContext = mock(Context.class); mResources = mock(Resources.class); @@ -366,6 +375,18 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { mEmergencyNumberTrackerMock.getRadioEmergencyNumberList()); } + @Test + public void testRegistrationForCountryChangeIntent() throws Exception { + EmergencyNumberTracker localEmergencyNumberTracker; + Context spyContext = spy(mContext); + doReturn(spyContext).when(mPhone).getContext(); + ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(IntentFilter.class); + + localEmergencyNumberTracker = new EmergencyNumberTracker(mPhone, mSimulatedCommands); + verify(spyContext, times(1)).registerReceiver(any(), intentCaptor.capture()); + IntentFilter ifilter = intentCaptor.getValue(); + assertTrue(ifilter.hasAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)); + } @Test public void testUpdateEmergencyCountryIso() throws Exception { sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock); -- GitLab From fab2e799c60d217d8f1bc1d71b6f004cf6ee1f42 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Tue, 21 Feb 2023 21:40:38 +0000 Subject: [PATCH 457/656] Update sendSatelliteDatagram API. The following changes are made in this CL: - Added needFullScreenPointingUI boolean as parameter in sendSatelliteDatagram() - Updated satellite datagram state enum. Bug: 267826133 Test: atest SatelliteManagerTest Change-Id: I00fb07f1af8c2746a1cc5297c16350a13a13310c --- src/java/com/android/internal/telephony/Phone.java | 5 ++++- .../telephony/satellite/SatelliteServiceController.java | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index c063fde861..a7f3fdcd8d 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5491,8 +5491,11 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * Send datagram over satellite. * @param result The Message to send the result of the operation to. * @param datagram Datagram to send over satellite. + * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in + * full screen mode. */ - public void sendSatelliteDatagram(Message result, SatelliteDatagram datagram) { + public void sendSatelliteDatagram(Message result, SatelliteDatagram datagram, + boolean needFullScreenPointingUI) { //mCi.sendSatelliteDatagram(result, datagram); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java index 6a5f067223..719c09499d 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java @@ -883,10 +883,12 @@ public class SatelliteServiceController { * * @param datagram Datagram to send in byte format. * @param isEmergency Whether this is an emergency datagram. + * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in + * full screen mode. * @param message The Message to send to result of the operation to. */ public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency, - @NonNull Message message) { + boolean needFullScreenPointingUI, @NonNull Message message) { if (mSatelliteService != null) { try { mSatelliteService.sendSatelliteDatagram( -- GitLab From 343b2e99b9756377bf50d08ccbd248208314f7a0 Mon Sep 17 00:00:00 2001 From: rambowang Date: Tue, 6 Dec 2022 10:36:02 -0600 Subject: [PATCH 458/656] Update ServiceStateTracker with new CarrierConfigManager APIs Replace carrier config change broadcast receiver with listener which has better performance. Due to a large list of carrir configs are used and the list may change in the near future, this CL doesn't replace getConfigForForSub with subset retrieval one. Bug: 263267340 Test: atest ServiceStateTrackerTest DisplayInfoControllerTest Change-Id: I852ccc7e6e0cd8c6c96087ca4667be8956ea54b7 Merged-In: I852ccc7e6e0cd8c6c96087ca4667be8956ea54b7 (cherry picked from commit fb108dc9e340787615a6081f2209a69f8294fb2b) --- .../telephony/ServiceStateTracker.java | 30 ++++++++------- .../telephony/DisplayInfoControllerTest.java | 38 ++++++++++--------- .../telephony/ServiceStateTrackerTest.java | 34 ++++++++++------- 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 9dd21629aa..7a4c0a7d82 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -279,7 +279,6 @@ public class ServiceStateTracker extends Handler { protected static final int EVENT_RADIO_POWER_OFF_DONE = 54; protected static final int EVENT_PHYSICAL_CHANNEL_CONFIG = 55; protected static final int EVENT_CELL_LOCATION_RESPONSE = 56; - protected static final int EVENT_CARRIER_CONFIG_CHANGED = 57; private static final int EVENT_POLL_STATE_REQUEST = 58; // Timeout event used when delaying radio power off to wait for IMS deregistration to happen. private static final int EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT = 62; @@ -557,13 +556,7 @@ public class ServiceStateTracker extends Handler { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { - int phoneId = intent.getExtras().getInt(CarrierConfigManager.EXTRA_SLOT_INDEX); - // Ignore the carrier config changed if the phoneId is not matched. - if (phoneId == mPhone.getPhoneId()) { - sendEmptyMessage(EVENT_CARRIER_CONFIG_CHANGED); - } - } else if (action.equals(Intent.ACTION_LOCALE_CHANGED)) { + if (action.equals(Intent.ACTION_LOCALE_CHANGED)) { // Update emergency string or operator name, polling service state. pollState(); } else if (action.equals(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)) { @@ -576,6 +569,10 @@ public class ServiceStateTracker extends Handler { } }; + private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = + (slotIndex, subId, carrierId, specificCarrierId) -> + onCarrierConfigurationChanged(slotIndex); + //CDMA // Min values used to by getOtasp() public static final String UNACTIVATED_MIN2_VALUE = "000000"; @@ -662,7 +659,11 @@ public class ServiceStateTracker extends Handler { mSubscriptionManager.addOnSubscriptionsChangedListener( new android.os.HandlerExecutor(this), mOnSubscriptionsChangedListener); mRestrictedState = new RestrictedState(); + mCarrierConfig = getCarrierConfig(); + CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); + // Callback which directly handle config change should be executed in handler thread + ccm.registerCarrierConfigChangeListener(this::post, mCarrierConfigChangeListener); mAccessNetworksManager = mPhone.getAccessNetworksManager(); mOutOfServiceSS = new ServiceState(); @@ -701,7 +702,6 @@ public class ServiceStateTracker extends Handler { Context context = mPhone.getContext(); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_LOCALE_CHANGED); - filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED); context.registerReceiver(mIntentReceiver, filter); @@ -862,6 +862,10 @@ public class ServiceStateTracker extends Handler { mPhone.getCarrierActionAgent().unregisterForCarrierAction(this, CARRIER_ACTION_SET_RADIO_ENABLED); mPhone.getContext().unregisterReceiver(mIntentReceiver); + CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); + if (ccm != null && mCarrierConfigChangeListener != null) { + ccm.unregisterCarrierConfigChangeListener(mCarrierConfigChangeListener); + } if (mCSST != null) { mCSST.dispose(); mCSST = null; @@ -1730,10 +1734,6 @@ public class ServiceStateTracker extends Handler { rspRspMsg.sendToTarget(); break; - case EVENT_CARRIER_CONFIG_CHANGED: - onCarrierConfigChanged(); - break; - case EVENT_POLL_STATE_REQUEST: pollStateInternal(false); break; @@ -5055,7 +5055,9 @@ public class ServiceStateTracker extends Handler { } } - private void onCarrierConfigChanged() { + private void onCarrierConfigurationChanged(int slotIndex) { + if (slotIndex != mPhone.getPhoneId()) return; + mCarrierConfig = getCarrierConfig(); log("CarrierConfigChange " + mCarrierConfig); diff --git a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java index 7bbdb84b05..f729b800cd 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java @@ -18,13 +18,12 @@ package com.android.internal.telephony; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; -import android.content.Context; -import android.content.Intent; import android.os.AsyncResult; import android.os.HandlerThread; import android.os.PersistableBundle; @@ -36,6 +35,7 @@ import android.telephony.CellIdentityLte; import android.telephony.LteVopsSupportInfo; import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; @@ -46,7 +46,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; +import org.mockito.ArgumentCaptor; import java.util.Collections; import java.util.concurrent.Executor; @@ -66,6 +66,7 @@ public class DisplayInfoControllerTest extends TelephonyTest { private ServiceStateTrackerTestHandler mSstHandler; private SignalStrengthController mSsc; private PersistableBundle mBundle; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; private class ServiceStateTrackerTestHandler extends HandlerThread { private ServiceStateTrackerTestHandler(String name) { @@ -80,7 +81,16 @@ public class DisplayInfoControllerTest extends TelephonyTest { doReturn(NUMERIC).when(mTelephonyManager).getSimOperatorNumericForPhone(eq(PHONE_ID)); doReturn(NETWORK).when(mTelephonyManager).getSimOperatorNameForPhone(eq(PHONE_ID)); + // Capture listener registered for ServiceStateTracker to emulate the carrier config + // change notification used later. In this test, it's the second one. The first one + // comes from RatRatcheter. + ArgumentCaptor + listenerArgumentCaptor = ArgumentCaptor.forClass( + CarrierConfigManager.CarrierConfigChangeListener.class); mSst = new ServiceStateTracker(mPhone, mSimulatedCommands); + verify(mCarrierConfigManager, atLeast(2)).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(1); doReturn(mSst).when(mPhone).getServiceStateTracker(); setReady(true); } @@ -92,6 +102,7 @@ public class DisplayInfoControllerTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); doReturn((Executor) Runnable::run).when(mContext).getMainExecutor(); + mBundle = mContextFixture.getCarrierConfigBundle(); mSstHandler = new ServiceStateTrackerTestHandler(getClass().getSimpleName()); mSstHandler.start(); waitUntilReady(); @@ -106,18 +117,14 @@ public class DisplayInfoControllerTest extends TelephonyTest { mSstHandler.join(); mSstHandler = null; mBundle = null; + mCarrierConfigChangeListener = null; super.tearDown(); } private void sendCarrierConfigUpdate() { - CarrierConfigManager mockConfigManager = Mockito.mock(CarrierConfigManager.class); - when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) - .thenReturn(mockConfigManager); - when(mockConfigManager.getConfigForSubId(anyInt())).thenReturn(mBundle); - - Intent intent = new Intent().setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, PHONE_ID); - mContext.sendBroadcast(intent); + mCarrierConfigChangeListener.onCarrierConfigChanged(PHONE_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, TelephonyManager.UNKNOWN_CARRIER_ID, + TelephonyManager.UNKNOWN_CARRIER_ID); waitForLastHandlerAction(mSstHandler.getThreadHandler()); } @@ -174,7 +181,6 @@ public class DisplayInfoControllerTest extends TelephonyTest { public void testIsRoamingOverride_NonRoamingOperator() { doReturn(true).when(mPhone).isPhoneTypeGsm(); - mBundle = mContextFixture.getCarrierConfigBundle(); mBundle.putStringArray( CarrierConfigManager.KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, new String[] {NUMERIC}); sendCarrierConfigUpdate(); @@ -196,7 +202,6 @@ public class DisplayInfoControllerTest extends TelephonyTest { public void testIsRoamingOverride_ForceHomeNetwork() { doReturn(true).when(mPhone).isPhoneTypeGsm(); - mBundle = mContextFixture.getCarrierConfigBundle(); mBundle.putBoolean(CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL, true); sendCarrierConfigUpdate(); @@ -217,7 +222,6 @@ public class DisplayInfoControllerTest extends TelephonyTest { public void testIsRoamingOverride_RoamingOperator() { doReturn(true).when(mPhone).isPhoneTypeGsm(); - mBundle = mContextFixture.getCarrierConfigBundle(); mBundle.putStringArray( CarrierConfigManager.KEY_ROAMING_OPERATOR_STRING_ARRAY, new String[] {"60101"}); sendCarrierConfigUpdate(); @@ -239,7 +243,6 @@ public class DisplayInfoControllerTest extends TelephonyTest { public void testIsRoamingOverride_NonRoamingGsmOperator() { doReturn(true).when(mPhone).isPhoneTypeGsm(); - mBundle = mContextFixture.getCarrierConfigBundle(); mBundle.putStringArray( CarrierConfigManager.KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, new String[] {NUMERIC}); @@ -262,7 +265,6 @@ public class DisplayInfoControllerTest extends TelephonyTest { public void testIsRoamingOverride_RoamingGsmOperator() { doReturn(true).when(mPhone).isPhoneTypeGsm(); - mBundle = mContextFixture.getCarrierConfigBundle(); mBundle.putStringArray( CarrierConfigManager.KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, new String[] {NUMERIC}); sendCarrierConfigUpdate(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 6d4b131eab..5350b768cd 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -127,6 +127,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { private ServiceStateStats mServiceStateStats; private CellularNetworkService mCellularNetworkService; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; // SST now delegates all signal strength operations to SSC // Add Mock SSC as the dependency to avoid NPE @@ -184,7 +185,18 @@ public class ServiceStateTrackerTest extends TelephonyTest { mSsc = new SignalStrengthController(mPhone); doReturn(mSsc).when(mPhone).getSignalStrengthController(); + // Capture listener registered for ServiceStateTracker to emulate the carrier config + // change notification used later. In this test, it's the third one. The first one + // comes from RatRatcheter and the second one comes from SignalStrengthController. + ArgumentCaptor + listenerArgumentCaptor = + ArgumentCaptor.forClass( + CarrierConfigManager.CarrierConfigChangeListener.class); sst = new ServiceStateTracker(mPhone, mSimulatedCommands); + verify(mCarrierConfigManager, atLeast(3)).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(2); + sst.setServiceStateStats(mServiceStateStats); doReturn(sst).when(mPhone).getServiceStateTracker(); setReady(true); @@ -253,6 +265,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { replaceInstance(ProxyController.class, "sProxyController", null, mProxyController); mBundle = mContextFixture.getCarrierConfigBundle(); when(mCarrierConfigManager.getConfigForSubId(anyInt(), any())).thenReturn(mBundle); + when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mBundle); mBundle.putStringArray( CarrierConfigManager.KEY_ROAMING_OPERATOR_STRING_ARRAY, new String[]{"123456"}); @@ -355,9 +368,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { 30 /* SIGNAL_STRENGTH_GREAT */ }); - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, 0); - mContext.sendBroadcast(intent); + sendCarrierConfigUpdate(PHONE_ID); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); logd("ServiceStateTrackerTest -Setup!"); @@ -826,15 +837,10 @@ public class ServiceStateTrackerTest extends TelephonyTest { verify(mPhone, times(1)).notifyServiceStateChanged(any(ServiceState.class)); } - private void sendCarrierConfigUpdate() { - CarrierConfigManager mockConfigManager = Mockito.mock(CarrierConfigManager.class); - when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) - .thenReturn(mockConfigManager); - when(mockConfigManager.getConfigForSubId(anyInt())).thenReturn(mBundle); - - Intent intent = new Intent().setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, PHONE_ID); - mContext.sendBroadcast(intent); + private void sendCarrierConfigUpdate(int phoneId) { + mCarrierConfigChangeListener.onCarrierConfigChanged(phoneId, + SubscriptionManager.INVALID_SUBSCRIPTION_ID, + TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); } @@ -2869,7 +2875,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { public void testUpdateSpnDisplay_spnEmptyAndWifiCallingEnabled_showPlmnOnly() { // set empty service provider name mBundle.putString(CarrierConfigManager.KEY_CARRIER_NAME_STRING, ""); - sendCarrierConfigUpdate(); + sendCarrierConfigUpdate(PHONE_ID); // GSM phone doReturn(true).when(mPhone).isPhoneTypeGsm(); @@ -2949,7 +2955,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { public void testUpdateSpnDisplayLegacy_WlanServiceNoWifiCalling_displayOOS() { mBundle.putBoolean( CarrierConfigManager.KEY_ENABLE_CARRIER_DISPLAY_NAME_RESOLVER_BOOL, false); - sendCarrierConfigUpdate(); + sendCarrierConfigUpdate(PHONE_ID); // GSM phone doReturn(true).when(mPhone).isPhoneTypeGsm(); -- GitLab From fd88b38f2d882d53ea86f27674c0f48ce053d905 Mon Sep 17 00:00:00 2001 From: rambowang Date: Mon, 12 Dec 2022 22:08:48 -0600 Subject: [PATCH 459/656] Update NetworkTypeController with new CarrierConfigManager APIs Improve performance of NetworkTypeController by replacing carrier config change broadcast receiver with listener Bug: 263267340 Test: atest NetworkTypeControllerTest Change-Id: I10150b0b55c64299ab130dc6c6027d267db4c003 Merged-In: I10150b0b55c64299ab130dc6c6027d267db4c003 (cherry picked from commit 3d339b92971651bdeaf832449310b8e645baddac) --- .../telephony/NetworkTypeController.java | 29 ++++--- .../telephony/NetworkTypeControllerTest.java | 82 ++++++++++--------- 2 files changed, 64 insertions(+), 47 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 81a386bbb9..7bc765920b 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -32,7 +32,6 @@ import android.telephony.CarrierConfigManager; import android.telephony.NetworkRegistrationInfo; import android.telephony.PhysicalChannelConfig; import android.telephony.ServiceState; -import android.telephony.SubscriptionManager; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.telephony.data.DataCallResponse; @@ -134,14 +133,6 @@ public class NetworkTypeController extends StateMachine { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { - case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: - if (intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_PHONE_INDEX) == mPhone.getPhoneId() - && !intent.getBooleanExtra( - CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, false)) { - sendMessage(EVENT_CARRIER_CONFIG_CHANGED); - } - break; case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED: sendMessage(EVENT_DEVICE_IDLE_MODE_CHANGED); break; @@ -149,6 +140,19 @@ public class NetworkTypeController extends StateMachine { } }; + private final @NonNull CarrierConfigManager.CarrierConfigChangeListener + mCarrierConfigChangeListener = + new CarrierConfigManager.CarrierConfigChangeListener() { + @Override + public void onCarrierConfigChanged(int slotIndex, int subId, int carrierId, + int specificCarrierId) { + // CarrierConfigChangeListener wouldn't send notification on device unlock + if (slotIndex == mPhone.getPhoneId()) { + sendMessage(EVENT_CARRIER_CONFIG_CHANGED); + } + } + }; + private @NonNull Map mOverrideTimerRules = new HashMap<>(); private @NonNull String mLteEnhancedPattern = ""; private @Annotation.OverrideNetworkType int mOverrideNetworkType; @@ -250,9 +254,10 @@ public class NetworkTypeController extends StateMachine { mPhone.getDeviceStateMonitor().registerForPhysicalChannelConfigNotifChanged(getHandler(), EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED, null); IntentFilter filter = new IntentFilter(); - filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); + CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); + ccm.registerCarrierConfigChangeListener(Runnable::run, mCarrierConfigChangeListener); } private void unRegisterForAllEvents() { @@ -261,6 +266,10 @@ public class NetworkTypeController extends StateMachine { mPhone.getServiceStateTracker().unregisterForServiceStateChanged(getHandler()); mPhone.getDeviceStateMonitor().unregisterForPhysicalChannelConfigNotifChanged(getHandler()); mPhone.getContext().unregisterReceiver(mIntentReceiver); + CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); + if (mCarrierConfigChangeListener != null) { + ccm.unregisterCarrierConfigChangeListener(mCarrierConfigChangeListener); + } } private void parseCarrierConfigs() { diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index 2a839eef50..ff696fc0a3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -20,12 +20,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import android.content.Context; -import android.content.Intent; import android.os.AsyncResult; import android.os.Handler; import android.os.IPowerManager; @@ -63,6 +63,7 @@ import java.util.List; public class NetworkTypeControllerTest extends TelephonyTest { private NetworkTypeController mNetworkTypeController; private PersistableBundle mBundle; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; private IState getCurrentState() throws Exception { Method method = StateMachine.class.getDeclaredMethod("getCurrentState"); @@ -76,11 +77,12 @@ public class NetworkTypeControllerTest extends TelephonyTest { method.invoke(mNetworkTypeController); } - private void broadcastCarrierConfigs() { - Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); - intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, mPhone.getSubId()); - intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); - mContext.sendBroadcast(intent); + private void sendCarrierConfigChanged() { + if (mCarrierConfigChangeListener != null) { + mCarrierConfigChangeListener.onCarrierConfigChanged(mPhone.getPhoneId(), + mPhone.getSubId(), TelephonyManager.UNKNOWN_CARRIER_ID, + TelephonyManager.UNKNOWN_CARRIER_ID); + } processAllMessages(); } @@ -92,7 +94,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { "connected_mmwave:5G_Plus,connected:5G,not_restricted_rrc_idle:5G," + "not_restricted_rrc_con:5G"); mBundle.putInt(CarrierConfigManager.KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); replaceInstance(Handler.class, "mLooper", mDisplayInfoController, Looper.myLooper()); doReturn(RadioAccessFamily.getRafFromNetworkType( @@ -101,8 +103,14 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); doReturn(new int[] {0}).when(mServiceState).getCellBandwidths(); + // Capture listener to emulate the carrier config change notification used later + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); processAllMessages(); + verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), + listenerArgumentCaptor.capture()); + mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0); } @After @@ -214,7 +222,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn("test_patternShowAdvanced").when(mServiceState).getOperatorAlphaLongRaw(); mBundle.putString(CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, ".*_patternShowAdvanced"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); updateOverrideNetworkType(); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO, mNetworkTypeController.getOverrideNetworkType()); @@ -287,7 +295,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); @@ -316,7 +324,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); @@ -336,7 +344,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); processAllMessages(); assertEquals("DefaultState", getCurrentState().getName()); @@ -384,7 +392,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { List lastPhysicalChannelConfigList = new ArrayList<>(); lastPhysicalChannelConfigList.add(physicalChannelConfig); doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); @@ -407,7 +415,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { List lastPhysicalChannelConfigList = new ArrayList<>(); lastPhysicalChannelConfigList.add(physicalChannelConfig); doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); @@ -420,7 +428,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("DefaultState", getCurrentState().getName()); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); @@ -434,7 +442,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); ArgumentCaptor dataNetworkControllerCallbackCaptor = ArgumentCaptor.forClass(DataNetworkControllerCallback.class); @@ -453,7 +461,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF00); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); ArgumentCaptor dataNetworkControllerCallbackCaptor = ArgumentCaptor.forClass(DataNetworkControllerCallback.class); @@ -472,7 +480,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); ArgumentCaptor dataNetworkControllerCallbackCaptor = ArgumentCaptor.forClass(DataNetworkControllerCallback.class); @@ -563,7 +571,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); processAllMessages(); testTransitionToCurrentStateNrConnectedMmwave(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); @@ -597,7 +605,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { mBundle = mContextFixture.getCarrierConfigBundle(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING, "connected_mmwave:5G_Plus,connected:5G"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); // Transition to LTE connected state doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); @@ -625,7 +633,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { mBundle = mContextFixture.getCarrierConfigBundle(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING, "connected_mmwave:5G_Plus,connected:5G"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); // Transition to idle state doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); @@ -682,7 +690,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); mNetworkTypeController = new NetworkTypeController(mPhone, mDisplayInfoController); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); processAllMessages(); testTransitionToCurrentStateLteConnected_usingUserDataForRrcDetection(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); @@ -741,7 +749,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, @@ -772,7 +780,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); IPowerManager powerManager = mock(IPowerManager.class); PowerManager pm = new PowerManager(mContext, powerManager, mock(IThermalService.class), @@ -801,7 +809,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, @@ -837,7 +845,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, @@ -867,7 +875,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); assertEquals("connected_mmwave", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, @@ -899,7 +907,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); assertEquals("connected_mmwave", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, @@ -937,7 +945,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "connected,any,30"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, @@ -980,7 +988,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "connected,any,30"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); assertEquals("connected", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA, @@ -1029,7 +1037,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "connected_mmwave,any,30"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); assertEquals("connected_mmwave", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, @@ -1073,7 +1081,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "connected_mmwave,any,30"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); assertEquals("connected_mmwave", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, @@ -1122,7 +1130,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "connected_mmwave,any,30"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); assertEquals("connected_mmwave", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, @@ -1160,7 +1168,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "connected_mmwave,any,30"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(mServiceState).getNrState(); mNetworkTypeController.sendMessage(4 /* EVENT_PHYSICAL_LINK_STATUS_CHANGED */, @@ -1206,7 +1214,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, "connected_mmwave,any,30"); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); // should trigger 10 second primary timer doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); @@ -1254,7 +1262,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); doReturn(new int[] {19999}).when(mServiceState).getCellBandwidths(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); @@ -1268,7 +1276,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); doReturn(new int[] {20001}).when(mServiceState).getCellBandwidths(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED */); processAllMessages(); @@ -1282,7 +1290,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); mBundle.putBoolean(CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL, false); - broadcastCarrierConfigs(); + sendCarrierConfigChanged(); mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); processAllMessages(); -- GitLab From 7e3747cc6338a7b53de2626eaf39cc5528393037 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Fri, 17 Feb 2023 21:26:24 +0000 Subject: [PATCH 460/656] Updated SatelliteModemInterface. The following changes are made in this CL: - SatelliteServiceController name is changed to SatelliteModemInterface - The decision to use satellite service or phone object is moved from PhoneInterfaceManager to SatelliteModemInterface. - Added new files in satellite module. Bug: 269637555 Test: atest SatelliteManagerTest Change-Id: Ica48001988ce3e60edc27e8a73e8293e4402e302 --- .../satellite/DatagramController.java | 80 + .../satellite/DatagramDispatcher.java | 72 + .../telephony/satellite/DatagramReceiver.java | 74 + .../satellite/PointingAppController.java | 79 + .../satellite/SatelliteController.java | 1975 +++++++++++++++++ ...ller.java => SatelliteModemInterface.java} | 84 +- .../satellite/SatelliteSessionController.java | 80 + 7 files changed, 2390 insertions(+), 54 deletions(-) create mode 100644 src/java/com/android/internal/telephony/satellite/DatagramController.java create mode 100644 src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java create mode 100644 src/java/com/android/internal/telephony/satellite/DatagramReceiver.java create mode 100644 src/java/com/android/internal/telephony/satellite/PointingAppController.java create mode 100644 src/java/com/android/internal/telephony/satellite/SatelliteController.java rename src/java/com/android/internal/telephony/satellite/{SatelliteServiceController.java => SatelliteModemInterface.java} (94%) create mode 100644 src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java new file mode 100644 index 0000000000..e4e6eba9ed --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023 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.NonNull; +import android.content.Context; +import android.os.Looper; +import android.telephony.Rlog; + +/** + * Datagram controller used for sending and receiving satellite datagrams. + */ +public class DatagramController { + private static final String TAG = "DatagramController"; + + @NonNull private static DatagramController sInstance; + @NonNull private final Context mContext; + @NonNull private final DatagramDispatcher mDatagramDispatcher; + @NonNull private final DatagramReceiver mDatagramReceiver; + + /** + * @return The singleton instance of DatagramController. + */ + public static DatagramController getInstance() { + if (sInstance == null) { + loge("DatagramController was not yet initialized."); + } + return sInstance; + } + + /** + * Create the DatagramController singleton instance. + * @param context The Context to use to create the DatagramController. + * @return The singleton instance of DatagramController. + */ + public static DatagramController make(@NonNull Context context) { + if (sInstance == null) { + sInstance = new DatagramController(context); + } + return sInstance; + } + + /** + * Create a DatagramController to send and receive satellite datagrams. + * + * @param context The Context for the DatagramController. + */ + private DatagramController(@NonNull Context context) { + mContext = context; + // Create the DatagramDispatcher singleton, + // which is used to send satellite datagrams. + mDatagramDispatcher = DatagramDispatcher.make(mContext); + + // Create the DatagramReceiver singleton, + // which is used to receive satellite datagrams. + mDatagramReceiver = DatagramReceiver.make(mContext); + } + + private static void logd(@NonNull String log) { + Rlog.d(TAG, log); + } + + private static void loge(@NonNull String log) { + Rlog.e(TAG, log); + } +} diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java new file mode 100644 index 0000000000..d070ca0189 --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2023 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.NonNull; +import android.content.Context; +import android.os.Looper; +import android.telephony.Rlog; + +/** + * Datagram dispatcher used to send satellite datagrams. + */ +public class DatagramDispatcher { + private static final String TAG = "DatagramDispatcher"; + + @NonNull + private static DatagramDispatcher sInstance; + @NonNull private final Context mContext; + + /** + * @return The singleton instance of DatagramDispatcher. + */ + public static DatagramDispatcher getInstance() { + if (sInstance == null) { + loge("DatagramDispatcher was not yet initialized."); + } + return sInstance; + } + + /** + * Create the DatagramDispatcher singleton instance. + * @param context The Context to use to create the DatagramDispatcher. + * @return The singleton instance of DatagramDispatcher. + */ + public static DatagramDispatcher make(@NonNull Context context) { + if (sInstance == null) { + sInstance = new DatagramDispatcher(context); + } + return sInstance; + } + + /** + * Create a DatagramDispatcher to send satellite datagrams. + * + * @param context The Context for the DatagramDispatcher. + */ + private DatagramDispatcher(@NonNull Context context) { + mContext = context; + } + + private static void logd(@NonNull String log) { + Rlog.d(TAG, log); + } + + private static void loge(@NonNull String log) { + Rlog.e(TAG, log); + } +} diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java new file mode 100644 index 0000000000..e8fadf4c07 --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023 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.NonNull; +import android.content.Context; +import android.os.Looper; +import android.telephony.Rlog; + +/** + * Datagram receiver used to receive satellite datagrams and then, + * deliver received datagrams to messaging apps. + */ +public class DatagramReceiver { + private static final String TAG = "DatagramReceiver"; + + @NonNull + private static DatagramReceiver sInstance; + @NonNull private final Context mContext; + + /** + * @return The singleton instance of DatagramReceiver. + */ + public static DatagramReceiver getInstance() { + if (sInstance == null) { + loge("DatagramReceiver was not yet initialized."); + } + return sInstance; + } + + /** + * Create the DatagramReceiver singleton instance. + * @param context The Context to use to create the DatagramReceiver. + * @return The singleton instance of DatagramReceiver. + */ + public static DatagramReceiver make(@NonNull Context context) { + if (sInstance == null) { + sInstance = new DatagramReceiver(context); + } + return sInstance; + } + + /** + * Create a DatagramReceiver to received satellite datagrams. + * The received datagrams will be delivered to respective messaging apps. + * + * @param context The Context for the DatagramReceiver. + */ + private DatagramReceiver(@NonNull Context context) { + mContext = context; + } + + private static void logd(@NonNull String log) { + Rlog.d(TAG, log); + } + + private static void loge(@NonNull String log) { + Rlog.e(TAG, log); + } +} diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java new file mode 100644 index 0000000000..a255b9fbe9 --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2023 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.NonNull; +import android.content.Context; +import android.os.Looper; +import android.telephony.Rlog; + +/** + * PointingApp controller to manage interactions with PointingUI app. + */ +public class PointingAppController { + private static final String TAG = "PointingAppController"; + + @NonNull + private static PointingAppController sInstance; + @NonNull private final Context mContext; + + /** + * @return The singleton instance of PointingAppController. + */ + public static PointingAppController getInstance() { + if (sInstance == null) { + loge("PointingAppController was not yet initialized."); + } + return sInstance; + } + + /** + * Create the PointingAppController singleton instance. + * @param context The Context to use to create the PointingAppController. + * @return The singleton instance of PointingAppController. + */ + public static PointingAppController make(@NonNull Context context) { + if (sInstance == null) { + sInstance = new PointingAppController(context); + } + return sInstance; + } + + /** + * Create a PointingAppController to manage interactions with PointingUI app. + * + * @param context The Context for the PointingUIController. + */ + private PointingAppController(@NonNull Context context) { + mContext = context; + } + + private static void logd(@NonNull String log) { + Rlog.d(TAG, log); + } + + private static void loge(@NonNull String log) { + Rlog.e(TAG, log); + } + + /** + * TODO: The following needs to be added in this class: + * - SatellitePositionUpdateHandler + * - startPointingUI + * - check if pointingUI crashes - then restart it + */ +} diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java new file mode 100644 index 0000000000..465e312520 --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -0,0 +1,1975 @@ +/* + * Copyright (C) 2023 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.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.AsyncResult; +import android.os.Binder; +import android.os.Bundle; +import android.os.CancellationSignal; +import android.os.Handler; +import android.os.IBinder; +import android.os.ICancellationSignal; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.os.ResultReceiver; +import android.telephony.Rlog; +import android.telephony.SubscriptionManager; +import android.telephony.satellite.ISatelliteDatagramCallback; +import android.telephony.satellite.ISatelliteDatagramReceiverAck; +import android.telephony.satellite.ISatellitePositionUpdateCallback; +import android.telephony.satellite.ISatelliteProvisionStateCallback; +import android.telephony.satellite.ISatelliteStateCallback; +import android.telephony.satellite.PointingInfo; +import android.telephony.satellite.SatelliteCapabilities; +import android.telephony.satellite.SatelliteDatagram; +import android.telephony.satellite.SatelliteManager; +import android.util.Log; +import android.util.Pair; + +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.IIntegerConsumer; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.RILUtils; +import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.subscription.SubscriptionManagerService; +import com.android.internal.util.FunctionalUtils; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +/** + * Satellite controller is the backend service of + * {@link android.telephony.satellite.SatelliteManager}. + */ +public class SatelliteController extends Handler { + private static final String TAG = "SatelliteController"; + /** Whether enabling verbose debugging message or not. */ + private static final boolean DBG = false; + + /** Message codes used in handleMessage() */ + private static final int CMD_START_SATELLITE_POSITION_UPDATES = 1; + private static final int EVENT_START_SATELLITE_POSITION_UPDATES_DONE = 2; + private static final int CMD_STOP_SATELLITE_POSITION_UPDATES = 3; + private static final int EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE = 4; + private static final int CMD_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG = 5; + private static final int EVENT_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG_DONE = 6; + private static final int CMD_PROVISION_SATELLITE_SERVICE = 7; + private static final int EVENT_PROVISION_SATELLITE_SERVICE_DONE = 8; + private static final int CMD_DEPROVISION_SATELLITE_SERVICE = 9; + private static final int EVENT_DEPROVISION_SATELLITE_SERVICE_DONE = 10; + private static final int CMD_SET_SATELLITE_ENABLED = 11; + private static final int EVENT_SET_SATELLITE_ENABLED_DONE = 12; + private static final int CMD_IS_SATELLITE_ENABLED = 13; + private static final int EVENT_IS_SATELLITE_ENABLED_DONE = 14; + private static final int CMD_IS_SATELLITE_SUPPORTED = 15; + private static final int EVENT_IS_SATELLITE_SUPPORTED_DONE = 16; + private static final int CMD_GET_SATELLITE_CAPABILITIES = 17; + private static final int EVENT_GET_SATELLITE_CAPABILITIES_DONE = 18; + private static final int CMD_POLL_PENDING_SATELLITE_DATAGRAMS = 19; + private static final int EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE = 20; + private static final int CMD_SEND_SATELLITE_DATAGRAM = 21; + private static final int EVENT_SEND_SATELLITE_DATAGRAM_DONE = 22; + private static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 23; + private static final int EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE = 24; + private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 25; + private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 26; + + @NonNull private static SatelliteController sInstance; + @NonNull private final Context mContext; + @NonNull private final SatelliteModemInterface mSatelliteModemInterface; + @NonNull private final SatelliteSessionController mSatelliteSessionController; + @NonNull private final PointingAppController mPointingAppController; + @NonNull private final DatagramController mDatagramController; + + + /** + * Map key: subId, value: callback to get error code of the provision request. + */ + private final ConcurrentHashMap> mSatelliteProvisionCallbacks = + new ConcurrentHashMap<>(); + /** + * Map key: subId, value: SatellitePositionUpdateHandler to notify registrants. + */ + private final ConcurrentHashMap + mSatellitePositionUpdateHandlers = new ConcurrentHashMap<>(); + /** + * Map key: subId, value: SatelliteProvisionStateChangedHandler to notify registrants. + */ + private final ConcurrentHashMap + mSatelliteProvisionStateChangedHandlers = new ConcurrentHashMap<>(); + + /** + * Map key: subId, value: SatelliteStateListenerHandler to notify registrants. + */ + private final ConcurrentHashMap + mSatelliteStateListenerHandlers = new ConcurrentHashMap<>(); + + /** + * Map key: subId, value: SatelliteDatagramListenerHandler to notify registrants. + */ + private final ConcurrentHashMap + mSatelliteDatagramListenerHandlers = new ConcurrentHashMap<>(); + + private Boolean mIsSatelliteSupported = null; + private final Object mIsSatelliteSupportedLock = new Object(); + private final ResultReceiver mSatelliteSupportedReceiver; + private boolean mIsSatelliteDemoModeEnabled = false; + + /** + * @return The singleton instance of SatelliteController. + */ + public static SatelliteController getInstance() { + if (sInstance == null) { + loge("SatelliteController was not yet initialized."); + } + return sInstance; + } + + /** + * Create the SatelliteController singleton instance. + * @param context The Context to use to create the SatelliteController. + */ + public static void make(@NonNull Context context) { + if (sInstance == null) { + sInstance = new SatelliteController(context); + } + } + + /** + * Create a SatelliteController to act as a backend service of + * {@link android.telephony.satellite.SatelliteManager} + * + * @param context The Context for the SatelliteController. + */ + private SatelliteController(@NonNull Context context) { + super(context.getMainLooper()); + mContext = context; + + // Create the SatelliteModemInterface singleton, which is used to manage connections + // to the satellite service and HAL interface. + mSatelliteModemInterface = SatelliteModemInterface.make(mContext); + + // Create the SatelliteSessionController singleton, + // which is used to manage all the data during a satellite session. + mSatelliteSessionController = SatelliteSessionController.make(mContext); + + // Create the PointingUIController singleton, + // which is used to manage interactions with PointingUI app. + mPointingAppController = PointingAppController.make(mContext); + + // Create the DatagramController singleton, + // which is used to send and receive satellite datagrams. + mDatagramController = DatagramController.make(mContext); + + mSatelliteSupportedReceiver = new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE + && resultData.containsKey(SatelliteManager.KEY_SATELLITE_SUPPORTED)) { + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = resultData.getBoolean( + SatelliteManager.KEY_SATELLITE_SUPPORTED); + } + } else { + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = null; + } + } + } + }; + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mSatelliteSupportedReceiver); + } + + private void internalInit() { + + } + + private static final class SatelliteControllerHandlerRequest { + /** The argument to use for the request */ + public @NonNull Object argument; + /** The caller needs to specify the phone to be used for the request */ + public @NonNull Phone phone; + /** The result of the request that is run on the main thread */ + public @Nullable Object result; + + SatelliteControllerHandlerRequest(Object argument, Phone phone) { + this.argument = argument; + this.phone = phone; + } + } + + private static final class ProvisionSatelliteServiceArgument { + public @NonNull String token; + public @NonNull Consumer callback; + public int subId; + + ProvisionSatelliteServiceArgument(String token, Consumer callback, int subId) { + this.token = token; + this.callback = callback; + this.subId = subId; + } + } + + private static final class SendSatelliteDatagramArgument { + public long datagramId; + + public @SatelliteManager.DatagramType int datagramType; + public @NonNull SatelliteDatagram datagram; + public boolean needFullScreenPointingUI; + public @NonNull ResultReceiver result; + + SendSatelliteDatagramArgument(long datagramId, + @SatelliteManager.DatagramType int datagramType, + SatelliteDatagram datagram, boolean needFullScreenPointingUI, + ResultReceiver result) { + this.datagramId = datagramId; + this.datagramType = datagramType; + this.datagram = datagram; + this.needFullScreenPointingUI = needFullScreenPointingUI; + this.result = result; + } + } + + private static final class SatellitePositionUpdateArgument { + public @NonNull Consumer errorCallback; + public @NonNull ISatellitePositionUpdateCallback callback; + public int subId; + + SatellitePositionUpdateArgument(Consumer errorCallback, + ISatellitePositionUpdateCallback callback, int subId) { + this.errorCallback = errorCallback; + this.callback = callback; + this.subId = subId; + } + } + + private static final class SatellitePositionUpdateHandler extends Handler { + public static final int EVENT_POSITION_INFO_CHANGED = 1; + public static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 2; + + private final ConcurrentHashMap mListeners; + SatellitePositionUpdateHandler(Looper looper) { + super(looper); + mListeners = new ConcurrentHashMap<>(); + } + + public void addListener(ISatellitePositionUpdateCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatellitePositionUpdateCallback listener) { + mListeners.remove(listener.asBinder()); + } + + public boolean hasListeners() { + return !mListeners.isEmpty(); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_POSITION_INFO_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + PointingInfo pointingInfo = (PointingInfo) ar.result; + mListeners.values().forEach(listener -> { + try { + listener.onSatellitePositionChanged(pointingInfo); + } catch (RemoteException e) { + logd("EVENT_POSITION_INFO_CHANGED RemoteException: " + e); + } + }); + break; + } + case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + int result = (int) ar.result; + mListeners.values().forEach(listener -> { + try { + // TODO: process and return the rest of the values correctly + listener.onDatagramTransferStateChanged(result, 0, 0, 0); + } catch (RemoteException e) { + logd("EVENT_DATAGRAM_TRANSFER_STATE_CHANGED RemoteException: " + e); + } + }); + break; + } + default: + loge("SatellitePositionUpdateHandler unknown event: " + msg.what); + } + } + } + + private static final class SatelliteProvisionStateChangedHandler extends Handler { + public static final int EVENT_PROVISION_STATE_CHANGED = 1; + + private final ConcurrentHashMap mListeners; + private final int mSubId; + + SatelliteProvisionStateChangedHandler(Looper looper, int subId) { + super(looper); + mListeners = new ConcurrentHashMap<>(); + mSubId = subId; + } + + public void addListener(ISatelliteProvisionStateCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatelliteProvisionStateCallback listener) { + mListeners.remove(listener.asBinder()); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_PROVISION_STATE_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + boolean provisioned = (boolean) ar.userObj; + logd("Received EVENT_PROVISION_STATE_CHANGED for subId=" + mSubId + + ", provisioned=" + provisioned); + mListeners.values().forEach(listener -> { + try { + listener.onSatelliteProvisionStateChanged(provisioned); + } catch (RemoteException e) { + logd("EVENT_PROVISION_STATE_CHANGED RemoteException: " + e); + } + }); + + setSatelliteProvisioned(provisioned); + /** + * TODO: Take bugreport if provisioned is true and user did not initiate the + * provision procedure for the corresponding subscription. + */ + break; + } + default: + loge("SatelliteProvisionStateChangedHandler unknown event: " + msg.what); + } + } + + private void setSatelliteProvisioned(boolean isProvisioned) { + if (mSubId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + SubscriptionManager.setSubscriptionProperty( + mSubId, SubscriptionManager.SATELLITE_ENABLED, isProvisioned ? "1" : "0"); + } else { + //TODO (b/267826133): set via SatelliteController. + } + } + } + + private static final class SatelliteStateListenerHandler extends Handler { + public static final int EVENT_SATELLITE_MODEM_STATE_CHANGE = 1; + public static final int EVENT_PENDING_DATAGRAM_COUNT = 2; + + private final ConcurrentHashMap mListeners; + private final int mSubId; + + SatelliteStateListenerHandler(Looper looper, int subId) { + super(looper); + mSubId = subId; + mListeners = new ConcurrentHashMap<>(); + } + + public void addListener(ISatelliteStateCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatelliteStateCallback listener) { + mListeners.remove(listener.asBinder()); + } + + public boolean hasListeners() { + return !mListeners.isEmpty(); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_SATELLITE_MODEM_STATE_CHANGE : { + AsyncResult ar = (AsyncResult) msg.obj; + int state = (int) ar.result; + logd("Received EVENT_SATELLITE_MODEM_STATE_CHANGE for subId=" + mSubId + + ", state=" + state); + mListeners.values().forEach(listener -> { + try { + listener.onSatelliteModemStateChanged(state); + } catch (RemoteException e) { + logd("EVENT_SATELLITE_MODEM_STATE_CHANGE RemoteException: " + e); + } + }); + break; + } + case EVENT_PENDING_DATAGRAM_COUNT: { + AsyncResult ar = (AsyncResult) msg.obj; + int count = (int) ar.result; + logd("Received EVENT_PENDING_DATAGRAM_COUNT for subId=" + mSubId + + ", count=" + count); + mListeners.values().forEach(listener -> { + try { + listener.onPendingDatagramCount(count); + } catch (RemoteException e) { + logd("EVENT_PENDING_DATAGRAM_COUNT RemoteException: " + e); + } + }); + break; + } + default: + loge("SatelliteStateListenerHandler unknown event: " + msg.what); + } + } + } + + /** Callback used by datagram receiver app to send ack back to Telephony. */ + private static final ISatelliteDatagramReceiverAck.Stub mDatagramReceiverAck = + new ISatelliteDatagramReceiverAck.Stub() { + /** + * This callback will be used by datagram receiver app to send ack back to + * Telephony. If the callback is not received within five minutes, + * then Telephony will resend the datagram again. + * + * @param datagramId An id that uniquely identifies datagram + * received by satellite datagram receiver app. + * This should match with datagramId passed in + * {@link android.telephony.satellite.SatelliteDatagramCallback + * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, + * ISatelliteDatagramReceiverAck)} + * Upon receiving the ack, Telephony will remove the datagram from + * the persistent memory. + */ + public void acknowledgeSatelliteDatagramReceived(long datagramId) { + // TODO (b/269637555): remove from db. + } + }; + + private static final class SatelliteDatagramListenerHandler extends Handler { + public static final int EVENT_SATELLITE_DATAGRAMS_RECEIVED = 1; + + private final ConcurrentHashMap mListeners; + private final int mSubId; + + SatelliteDatagramListenerHandler(Looper looper, int subId) { + super(looper); + mSubId = subId; + mListeners = new ConcurrentHashMap<>(); + } + + public void addListener(ISatelliteDatagramCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatelliteDatagramCallback listener) { + mListeners.remove(listener.asBinder()); + } + + public boolean hasListeners() { + return !mListeners.isEmpty(); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_SATELLITE_DATAGRAMS_RECEIVED: { + AsyncResult ar = (AsyncResult) msg.obj; + Pair result = + (Pair) ar.result; + SatelliteDatagram[] satelliteDatagrams = result.first; + int pendingCount = result.second; + + logd("Received EVENT_SATELLITE_DATAGRAMS_RECEIVED for subId=" + mSubId); + mListeners.values().forEach(listener -> { + try { + for (int i = 0; i < satelliteDatagrams.length; i++) { + // TODO (b/269637555): wait for ack and retry after 5mins + listener.onSatelliteDatagramReceived( + // TODO: create a new datagramId every time + i, satelliteDatagrams[i], pendingCount, + // TODO: create a new instance of ack that will resend + mDatagramReceiverAck); + } + } catch (RemoteException e) { + logd("EVENT_SATELLITE_DATAGRAMS_RECEIVED RemoteException: " + e); + } + }); + break; + } + default: + loge("SatelliteDatagramListenerHandler unknown event: " + msg.what); + } + } + } + + @Override + public void handleMessage(Message msg) { + SatelliteControllerHandlerRequest request; + Message onCompleted; + AsyncResult ar; + + switch(msg.what) { + case CMD_START_SATELLITE_POSITION_UPDATES: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = + obtainMessage(EVENT_START_SATELLITE_POSITION_UPDATES_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.startSendingSatellitePointingInfo(onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.startSatellitePositionUpdates(onCompleted); + } else { + loge("startSatellitePositionUpdates: No phone object"); + SatellitePositionUpdateArgument arg = + (SatellitePositionUpdateArgument) request.argument; + arg.errorCallback.accept( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + } + break; + } + + case EVENT_START_SATELLITE_POSITION_UPDATES_DONE: { + handleStartSatellitePositionUpdatesDone((AsyncResult) msg.obj); + break; + } + + case CMD_STOP_SATELLITE_POSITION_UPDATES: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = + obtainMessage(EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.stopSendingSatellitePointingInfo(onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.stopSatellitePositionUpdates(onCompleted); + } else { + loge("stopSatellitePositionUpdates: No phone object"); + ((Consumer) request.argument).accept( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + } + break; + } + + case EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = getSatelliteError(ar, "stopSatellitePositionUpdates", false); + ((Consumer) request.argument).accept(error); + break; + } + + case CMD_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = + obtainMessage(EVENT_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface + .requestMaxCharactersPerMOTextMessage(onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.getMaxCharactersPerSatelliteTextMessage(onCompleted); + } else { + loge("getMaxCharactersPerSatelliteTextMessage: No phone object"); + ((ResultReceiver) request.argument).send( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + } + break; + } + + case EVENT_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = + getSatelliteError(ar, "getMaxCharactersPerSatelliteTextMessage", true); + Bundle bundle = new Bundle(); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + int maxCharLimit = ((int[]) ar.result)[0]; + if (DBG) logd("getMaxCharactersPerSatelliteTextMessage: " + maxCharLimit); + bundle.putInt(SatelliteManager.KEY_MAX_CHARACTERS_PER_SATELLITE_TEXT, + maxCharLimit); + } + ((ResultReceiver) request.argument).send(error, bundle); + break; + } + + case CMD_PROVISION_SATELLITE_SERVICE: { + request = (SatelliteControllerHandlerRequest) msg.obj; + ProvisionSatelliteServiceArgument argument = + (ProvisionSatelliteServiceArgument) request.argument; + if (mSatelliteProvisionCallbacks.containsKey(argument.subId)) { + argument.callback.accept( + SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS); + notifyRequester(request); + break; + } + mSatelliteProvisionCallbacks.put(argument.subId, argument.callback); + onCompleted = obtainMessage(EVENT_PROVISION_SATELLITE_SERVICE_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface + .provisionSatelliteService(argument.token, onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.provisionSatelliteService(onCompleted, argument.token); + } else { + loge("provisionSatelliteService: No phone object"); + argument.callback.accept( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + notifyRequester(request); + } + break; + } + + case EVENT_PROVISION_SATELLITE_SERVICE_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int errorCode = getSatelliteError(ar, "provisionSatelliteService", false); + handleEventProvisionSatelliteServiceDone( + (ProvisionSatelliteServiceArgument) request.argument, errorCode); + notifyRequester(request); + break; + } + + case CMD_DEPROVISION_SATELLITE_SERVICE: { + request = (SatelliteControllerHandlerRequest) msg.obj; + ProvisionSatelliteServiceArgument argument = + (ProvisionSatelliteServiceArgument) request.argument; + onCompleted = obtainMessage(EVENT_DEPROVISION_SATELLITE_SERVICE_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface + .deprovisionSatelliteService(argument.token, onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.deprovisionSatelliteService(onCompleted, argument.token); + } else { + loge("deprovisionSatelliteService: No phone object"); + if (argument.callback != null) { + argument.callback.accept( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + } + } + break; + } + + case EVENT_DEPROVISION_SATELLITE_SERVICE_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int errorCode = getSatelliteError(ar, "deprovisionSatelliteService", false); + handleEventDeprovisionSatelliteServiceDone( + (ProvisionSatelliteServiceArgument) request.argument, errorCode); + break; + } + + case CMD_SET_SATELLITE_ENABLED: { + request = (SatelliteControllerHandlerRequest) msg.obj; + Pair> argument = + (Pair>) request.argument; + onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface + .requestSatelliteEnabled(argument.first, onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.setSatellitePower(onCompleted, argument.first); + } else { + loge("requestSatelliteEnabled: No phone object"); + argument.second.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + } + break; + } + + case EVENT_SET_SATELLITE_ENABLED_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + Pair> argument = + (Pair>) request.argument; + int error = getSatelliteError(ar, "setSatelliteEnabled", false); + argument.second.accept(error); + break; + } + + case CMD_IS_SATELLITE_ENABLED: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = obtainMessage(EVENT_IS_SATELLITE_ENABLED_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.requestIsSatelliteEnabled(onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.isSatellitePowerOn(onCompleted); + } else { + loge("isSatelliteEnabled: No phone object"); + ((ResultReceiver) request.argument).send( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + } + break; + } + + case EVENT_IS_SATELLITE_ENABLED_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = getSatelliteError(ar, "isSatelliteEnabled", true); + Bundle bundle = new Bundle(); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + boolean enabled = ((int[]) ar.result)[0] == 1; + if (DBG) logd("isSatelliteEnabled: " + enabled); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled); + } + ((ResultReceiver) request.argument).send(error, bundle); + break; + } + + case CMD_IS_SATELLITE_SUPPORTED: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = obtainMessage(EVENT_IS_SATELLITE_SUPPORTED_DONE, request); + + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.requestIsSatelliteSupported(onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.isSatelliteSupported(onCompleted); + } else { + loge("isSatelliteSupported: No phone object"); + ((ResultReceiver) request.argument).send( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + } + break; + } + + case EVENT_IS_SATELLITE_SUPPORTED_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = getSatelliteError(ar, "isSatelliteSupported", true); + Bundle bundle = new Bundle(); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + boolean supported = (boolean) ar.result; + if (DBG) logd("isSatelliteSupported: " + supported); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported); + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = supported; + } + } else { + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = null; + } + } + ((ResultReceiver) request.argument).send(error, bundle); + break; + } + + case CMD_GET_SATELLITE_CAPABILITIES: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = obtainMessage(EVENT_GET_SATELLITE_CAPABILITIES_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.requestSatelliteCapabilities(onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.getSatelliteCapabilities(onCompleted); + } else { + loge("getSatelliteCapabilities: No phone object"); + ((ResultReceiver) request.argument).send( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + } + break; + } + + case EVENT_GET_SATELLITE_CAPABILITIES_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = getSatelliteError(ar, "getSatelliteCapabilities", true); + Bundle bundle = new Bundle(); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + SatelliteCapabilities capabilities = (SatelliteCapabilities) ar.result; + if (DBG) logd("getSatelliteCapabilities: " + capabilities); + bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, + capabilities); + } + ((ResultReceiver) request.argument).send(error, bundle); + break; + } + + case CMD_POLL_PENDING_SATELLITE_DATAGRAMS: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = + obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.pollPendingSatelliteDatagrams(onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.pollPendingSatelliteDatagrams(onCompleted); + } else { + loge("pollPendingSatelliteDatagrams: No phone object"); + ((Consumer) request.argument).accept( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + } + break; + } + + case EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = getSatelliteError(ar, "pollPendingSatelliteDatagrams", false); + ((Consumer) request.argument).accept(error); + break; + } + + case CMD_SEND_SATELLITE_DATAGRAM: { + request = (SatelliteControllerHandlerRequest) msg.obj; + SendSatelliteDatagramArgument argument = + (SendSatelliteDatagramArgument) request.argument; + onCompleted = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.sendSatelliteDatagram( + argument.datagram, + argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, + argument.needFullScreenPointingUI, onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.sendSatelliteDatagram(onCompleted, argument.datagram, + argument.needFullScreenPointingUI); + } else { + loge("sendSatelliteDatagram: No phone object"); + argument.result.send( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + } + break; + } + + case EVENT_SEND_SATELLITE_DATAGRAM_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = getSatelliteError(ar, "sendSatelliteDatagram", false); + SendSatelliteDatagramArgument argument = + (SendSatelliteDatagramArgument) request.argument; + Bundle bundle = new Bundle(); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + bundle.putLong(SatelliteManager.KEY_SEND_SATELLITE_DATAGRAM, + argument.datagramId); + } + argument.result.send(error, bundle); + break; + } + + case CMD_IS_SATELLITE_COMMUNICATION_ALLOWED: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = + obtainMessage(EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface + .requestIsSatelliteCommunicationAllowedForCurrentLocation( + onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.isSatelliteCommunicationAllowedForCurrentLocation(onCompleted); + } else { + loge("isSatelliteCommunicationAllowedForCurrentLocation: No phone object"); + ((ResultReceiver) request.argument).send( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + } + break; + } + + case EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = getSatelliteError( + ar, "isSatelliteCommunicationAllowedForCurrentLocation", true); + Bundle bundle = new Bundle(); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + boolean communicationAllowed = (boolean) ar.result; + if (DBG) { + logd("isSatelliteCommunicationAllowedForCurrentLocation: " + + communicationAllowed); + } + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED, + communicationAllowed); + } + ((ResultReceiver) request.argument).send(error, bundle); + break; + } + + case CMD_GET_TIME_SATELLITE_NEXT_VISIBLE: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = obtainMessage(EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE, + request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface + .requestTimeForNextSatelliteVisibility(onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.requestTimeForNextSatelliteVisibility(onCompleted); + } else { + loge("requestTimeForNextSatelliteVisibility: No phone object"); + ((ResultReceiver) request.argument).send( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + } + break; + } + + case EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = + getSatelliteError(ar, "requestTimeForNextSatelliteVisibility", true); + Bundle bundle = new Bundle(); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + int nextVisibilityDuration = ((int[]) ar.result)[0]; + if (DBG) { + logd("requestTimeForNextSatelliteVisibility: " + nextVisibilityDuration); + } + bundle.putInt(SatelliteManager.KEY_SATELLITE_NEXT_VISIBILITY, + nextVisibilityDuration); + } + ((ResultReceiver) request.argument).send(error, bundle); + break; + } + + default: + Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " + + msg.what); + break; + } + } + + private void notifyRequester(SatelliteControllerHandlerRequest request) { + synchronized (request) { + request.notifyAll(); + } + } + + /** + * Request to enable or disable the satellite modem. If the satellite modem is enabled, this + * will also disable the cellular modem, and if the satellite modem is disabled, this will also + * re-enable the cellular modem. + * + * @param subId The subId of the subscription to set satellite enabled for. + * @param enable {@code true} to enable the satellite modem and {@code false} to disable. + * @param callback The callback to get the error code of the request. + */ + public void requestSatelliteEnabled( + int subId, boolean enable, @NonNull IIntegerConsumer callback) { + Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); + if (!isSatelliteSupported()) { + result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); + return; + } + + Phone phone = getPhoneOrDefault(validSubId, "requestSatelliteEnabled"); + Pair> arg = new Pair<>(enable, result); + sendRequestAsync(CMD_SET_SATELLITE_ENABLED, arg, phone); + } + + /** + * Request to get whether the satellite modem is enabled. + * + * @param subId The subId of the subscription to check whether satellite is enabled for. + * @param result The result receiver that returns whether the satellite modem is enabled + * if the request is successful or an error code if the request failed. + */ + public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) { + if (!isSatelliteSupported()) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + return; + } + + Phone phone = getPhoneOrDefault(validSubId, "requestIsSatelliteEnabled"); + sendRequest(CMD_IS_SATELLITE_ENABLED, result, phone); + } + + /** + * Request to enable or disable the satellite service demo mode. + * + * @param subId The subId of the subscription to set the satellite demo mode enabled for. + * @param enable {@code true} to enable the satellite demo mode and {@code false} to disable. + * @param callback The callback to get the error code of the request. + */ + public void requestSatelliteDemoModeEnabled( + int subId, boolean enable, @NonNull IIntegerConsumer callback) { + Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); + if (!isSatelliteSupported()) { + result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); + return; + } + + mIsSatelliteDemoModeEnabled = enable; + result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + } + + /** + * Request to get whether the satellite service demo mode is enabled. + * + * @param subId The subId of the subscription to check whether the satellite demo mode + * is enabled for. + * @param result The result receiver that returns whether the satellite demo mode is enabled + * if the request is successful or an error code if the request failed. + */ + public void requestIsSatelliteDemoModeEnabled(int subId, @NonNull ResultReceiver result) { + if (!isSatelliteSupported()) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + return; + } + + final Bundle bundle = new Bundle(); + bundle.putBoolean(SatelliteManager.KEY_DEMO_MODE_ENABLED, mIsSatelliteDemoModeEnabled); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + } + + /** + * Request to get whether the satellite service is supported on the device. + * + * @param subId The subId of the subscription to check satellite service support for. + * @param result The result receiver that returns whether the satellite service is supported on + * the device if the request is successful or an error code if the request failed. + */ + public void requestIsSatelliteSupported(int subId, @NonNull ResultReceiver result) { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported != null) { + /* We have already successfully queried the satellite modem. */ + Bundle bundle = new Bundle(); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, mIsSatelliteSupported); + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, bundle); + return; + } + } + + final int validSubId = getValidSatelliteSubId(subId); + Phone phone = getPhoneOrDefault(validSubId, "requestIsSatelliteSupported"); + sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, phone); + } + + /** + * Request to get the {@link SatelliteCapabilities} of the satellite service. + * + * @param subId The subId of the subscription to get the satellite capabilities for. + * @param result The result receiver that returns the {@link SatelliteCapabilities} + * if the request is successful or an error code if the request failed. + */ + public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) { + if (!isSatelliteSupported()) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + Phone phone = getPhoneOrDefault(validSubId, "requestSatelliteCapabilities"); + sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, phone); + } + + /** + * Start receiving satellite position updates. + * This can be called by the pointing UI when the user starts pointing to the satellite. + * Modem should continue to report the pointing input as the device or satellite moves. + * + * @param subId The subId of the subscription to start satellite position updates for. + * @param errorCallback The callback to get the error code of the request. + * @param callback The callback to notify of changes in satellite position. + */ + public void startSatellitePositionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, + @NonNull ISatellitePositionUpdateCallback callback) { + Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); + if (!isSatelliteSupported()) { + result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); + return; + } + + Phone phone = getPhoneOrDefault(validSubId, "startSatellitePositionUpdates"); + SatellitePositionUpdateHandler handler = mSatellitePositionUpdateHandlers.get(validSubId); + if (handler != null) { + handler.addListener(callback); + return; + } else { + handler = new SatellitePositionUpdateHandler(Looper.getMainLooper()); + handler.addListener(callback); + mSatellitePositionUpdateHandlers.put(validSubId, handler); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatellitePositionInfoChanged(handler, + SatellitePositionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + mSatelliteModemInterface.registerForDatagramTransferStateChanged(handler, + SatellitePositionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, null); + } else { + phone.registerForSatellitePositionInfoChanged(handler, + SatellitePositionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + // TODO: registerForDatagramTransferStateChanged through SatelliteController + } + } + + sendRequestAsync(CMD_START_SATELLITE_POSITION_UPDATES, + new SatellitePositionUpdateArgument(result, callback, validSubId), phone); + } + + /** + * Stop receiving satellite position updates. + * This can be called by the pointing UI when the user stops pointing to the satellite. + * + * @param subId The subId of the subscription to stop satellite position updates for. + * @param errorCallback The callback to get the error code of the request. + * @param callback The callback that was passed to {@link + * #startSatellitePositionUpdates(int, IIntegerConsumer, ISatellitePositionUpdateCallback)} + */ + public void stopSatellitePositionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, + @NonNull ISatellitePositionUpdateCallback callback) { + Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); + if (!isSatelliteSupported()) { + result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); + return; + } + + Phone phone = getPhoneOrDefault(validSubId, "stopSatellitePositionUpdates"); + SatellitePositionUpdateHandler handler = mSatellitePositionUpdateHandlers.get(validSubId); + if (handler != null) { + handler.removeListener(callback); + + if (handler.hasListeners()) { + /** + * TODO (b/269194948): If the calling apps crash, the handler will always have some + * listener. That is, we will not request modem to stop position update and + * cleaning our resources. We need to monitor the calling apps and clean up the + * resources when the apps die. We need to this for other satellite callbacks + * as well. + */ + result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + return; + } + + mSatellitePositionUpdateHandlers.remove(validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.unregisterForSatellitePositionInfoChanged(handler); + mSatelliteModemInterface.unregisterForDatagramTransferStateChanged(handler); + } else { + if (phone == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + phone.unregisterForSatellitePositionInfoChanged(handler); + // TODO: unregisterForDatagramTransferStateChanged through SatelliteController + } + } + + /** + * Even if handler is null - which means there are not any listeners, the command to stop + * satellite position updates sent to the modem might have failed. The callers might want to + * retry sending the command. Thus, we always need to send this command to the modem. + */ + sendRequestAsync(CMD_STOP_SATELLITE_POSITION_UPDATES, result, phone); + } + + /** + * Request to get the maximum number of bytes per datagram that can be sent to satellite. + * + * @param subId The subId of the subscription to get the maximum number of characters for. + * @param result The result receiver that returns the maximum number of bytes per datagram + * message on satellite if the request is successful or an error code + * if the request failed. + */ + public void requestMaxSizePerSendingDatagram(int subId, + @NonNull ResultReceiver result) { + if (!isSatelliteSupported()) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + return; + } + + Phone phone = getPhoneOrDefault(validSubId, "requestMaxSizePerSendingDatagram"); + sendRequestAsync(CMD_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG, result, phone); + } + + /** + * Register the subscription with a satellite provider. + * This is needed to register the subscription if the provider allows dynamic registration. + * + * @param subId The subId of the subscription to be provisioned. + * @param token The token to be used as a unique identifier for provisioning with satellite + * gateway. + * @param callback The callback to get the error code of the request. + * + * @return The signal transport used by the caller to cancel the provision request, + * or {@code null} if the request failed. + */ + @Nullable public ICancellationSignal provisionSatelliteService(int subId, + @NonNull String token, @NonNull IIntegerConsumer callback) { + Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); + if (!isSatelliteSupported()) { + result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); + return null; + } + + final int validSubId = getValidSatelliteSubId(subId); + Phone phone = getPhoneOrDefault(validSubId, "provisionSatelliteService"); + + if (mSatelliteProvisionCallbacks.containsKey(validSubId)) { + result.accept(SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS); + return null; + } + + if (isSatelliteProvisioned(validSubId)) { + result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + return null; + } + + sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE, + new ProvisionSatelliteServiceArgument(token, result, validSubId), phone); + + ICancellationSignal cancelTransport = CancellationSignal.createTransport(); + CancellationSignal.fromTransport(cancelTransport).setOnCancelListener(() -> { + sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, + new ProvisionSatelliteServiceArgument(token, null, validSubId), + phone); + }); + return cancelTransport; + } + + /** + * Unregister the device/subscription with the satellite provider. + * This is needed if the provider allows dynamic registration. Once deprovisioned, + * {@link android.telephony.satellite.SatelliteProvisionStateCallback + * #onSatelliteProvisionStateChanged(boolean)} + * should report as deprovisioned. + * + * @param subId The subId of the subscription to be deprovisioned. + * @param token The token of the device/subscription to be deprovisioned. + * @param callback The callback to get the error code of the request. + */ + public void deprovisionSatelliteService(int subId, + @NonNull String token, @NonNull IIntegerConsumer callback) { + Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); + if (!isSatelliteSupported()) { + result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + return; + } + + Phone phone = getPhoneOrDefault(validSubId, "deprovisionSatelliteService"); + sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, + new ProvisionSatelliteServiceArgument(token, result, validSubId), phone); + } + + /** + * Registers for the satellite provision state changed. + * + * @param subId The subId of the subscription to register for provision state changed. + * @param callback The callback to handle the satellite provision state changed event. + * + * @return The {@link SatelliteManager.SatelliteError} result of the operation. + */ + @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId, + @NonNull ISatelliteProvisionStateCallback callback) { + return registerForSatelliteProvisionStateChangedInternal(subId, callback); + } + + /** + * Unregisters for the satellite provision state changed. + * If callback was not registered before, the request will be ignored. + * + * @param subId The subId of the subscription to unregister for provision state changed. + * @param callback The callback that was passed to + * {@link #registerForSatelliteProvisionStateChanged(int, ISatelliteProvisionStateCallback)}. + */ + public void unregisterForSatelliteProvisionStateChanged( + int subId, @NonNull ISatelliteProvisionStateCallback callback) { + final int validSubId = getValidSatelliteSubId(subId); + SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = + mSatelliteProvisionStateChangedHandlers.get(validSubId); + if (satelliteProvisionStateChangedHandler != null) { + satelliteProvisionStateChangedHandler.removeListener(callback); + } + } + + /** + * Request to get whether the device is provisioned with a satellite provider. + * + * @param subId The subId of the subscription to get whether the device is provisioned for. + * @param result The result receiver that returns whether the device is provisioned with a + * satellite provider if the request is successful or an error code if the + * request failed. + */ + public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) { + if (!isSatelliteSupported()) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + Bundle bundle = new Bundle(); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, + isSatelliteProvisioned(validSubId)); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + } + + /** + * Registers for modem state changed from satellite modem. + * + * @param subId The subId of the subscription to register for satellite modem state changed. + * @param callback The callback to handle the satellite modem state changed event. + * + * @return The {@link SatelliteManager.SatelliteError} result of the operation. + */ + @SatelliteManager.SatelliteError public int registerForSatelliteModemStateChanged(int subId, + @NonNull ISatelliteStateCallback callback) { + final int validSubId = getValidSatelliteSubId(subId); + Phone phone = getPhoneOrDefault( + validSubId, "registerForSatelliteModemStateChanged"); + + SatelliteStateListenerHandler satelliteStateListenerHandler = + mSatelliteStateListenerHandlers.get(validSubId); + if (satelliteStateListenerHandler == null) { + satelliteStateListenerHandler = new SatelliteStateListenerHandler( + Looper.getMainLooper(), validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatelliteModemStateChanged( + satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); + mSatelliteModemInterface.registerForPendingDatagramCount( + satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAM_COUNT, null); + } else { + phone.registerForSatelliteModemStateChanged(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); + phone.registerForPendingDatagramCount(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAM_COUNT, null); + } + } + + satelliteStateListenerHandler.addListener(callback); + mSatelliteStateListenerHandlers.put(validSubId, satelliteStateListenerHandler); + return SatelliteManager.SATELLITE_ERROR_NONE; + } + + /** + * Unregisters for modem state changed from satellite modem. + * If callback was not registered before, the request will be ignored. + * + * @param subId The subId of the subscription to unregister for satellite modem state changed. + * @param callback The callback that was passed to + * {@link #registerForSatelliteModemStateChanged(int, ISatelliteStateCallback)}. + */ + public void unregisterForSatelliteModemStateChanged(int subId, + @NonNull ISatelliteStateCallback callback) { + final int validSubId = getValidSatelliteSubId(subId); + SatelliteStateListenerHandler handler = mSatelliteStateListenerHandlers.get(validSubId); + if (handler != null) { + handler.removeListener(callback); + if (!handler.hasListeners()) { + mSatelliteStateListenerHandlers.remove(validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.unregisterForSatelliteModemStateChanged(handler); + mSatelliteModemInterface.unregisterForPendingDatagramCount(handler); + } else { + Phone phone = getPhoneOrDefault( + validSubId, "unregisterForSatelliteModemStateChanged"); + if (phone != null) { + phone.unregisterForSatelliteModemStateChanged(handler); + phone.unregisterForPendingDatagramCount(handler); + } + } + } + } + } + + /** + * Register to receive incoming datagrams over satellite. + * + * @param subId The subId of the subscription to register for incoming satellite datagrams. + * @param datagramType datagram type indicating whether the datagram is of type + * SOS_SMS or LOCATION_SHARING. + * @param callback The callback to handle incoming datagrams over satellite. + * + * @return The {@link SatelliteManager.SatelliteError} result of the operation. + */ + @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId, + @SatelliteManager.DatagramType int datagramType, + @NonNull ISatelliteDatagramCallback callback) { + if (!isSatelliteSupported()) { + return SatelliteManager.SATELLITE_NOT_SUPPORTED; + } + + final int validSubId = getValidSatelliteSubId(subId); + Phone phone = getPhoneOrDefault(validSubId, "registerForSatelliteDatagram"); + + SatelliteDatagramListenerHandler satelliteDatagramListenerHandler = + mSatelliteDatagramListenerHandlers.get(validSubId); + if (satelliteDatagramListenerHandler == null) { + satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler( + Looper.getMainLooper(), validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatelliteDatagramsReceived( + satelliteDatagramListenerHandler, + SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAMS_RECEIVED, null); + } else { + phone.registerForSatelliteDatagramsReceived(satelliteDatagramListenerHandler, + SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAMS_RECEIVED, null); + } + } + + satelliteDatagramListenerHandler.addListener(callback); + mSatelliteDatagramListenerHandlers.put(validSubId, satelliteDatagramListenerHandler); + return SatelliteManager.SATELLITE_ERROR_NONE; + } + + /** + * Unregister to stop receiving incoming datagrams over satellite. + * If callback was not registered before, the request will be ignored. + * + * @param subId The subId of the subscription to unregister for incoming satellite datagrams. + * @param callback The callback that was passed to + * {@link #registerForSatelliteDatagram(int, int, ISatelliteDatagramCallback)}. + */ + public void unregisterForSatelliteDatagram(int subId, + @NonNull ISatelliteDatagramCallback callback) { + final int validSubId = getValidSatelliteSubId(subId); + SatelliteDatagramListenerHandler handler = + mSatelliteDatagramListenerHandlers.get(validSubId); + if (handler != null) { + handler.removeListener(callback); + + if (!handler.hasListeners()) { + mSatelliteDatagramListenerHandlers.remove(validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.unregisterForSatelliteDatagramsReceived(handler); + } else { + Phone phone = getPhoneOrDefault(validSubId, + "unregisterForSatelliteDatagram"); + if (phone != null) { + phone.unregisterForSatelliteDatagramsReceived(handler); + } + } + } + } + } + + /** + * Poll pending satellite datagrams over satellite. + * + * This method requests modem to check if there are any pending datagrams to be received over + * satellite. If there are any incoming datagrams, they will be received via + * {@link android.telephony.satellite.SatelliteDatagramCallback + * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ISatelliteDatagramReceiverAck)} + * + * @param subId The subId of the subscription used for receiving datagrams. + * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. + */ + public void pollPendingSatelliteDatagrams(int subId, IIntegerConsumer callback) { + Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); + return; + } + + Phone phone = getPhoneOrDefault(validSubId, "pollPendingSatelliteDatagrams"); + sendRequestAsync(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, result, phone); + } + + /** + * Send datagram over satellite. + * + * Gateway encodes SOS message or location sharing message into a datagram and passes it as + * input to this method. Datagram received here will be passed down to modem without any + * encoding or encryption. + * + * @param subId The subId of the subscription to send satellite datagrams for. + * @param datagramId An id that uniquely identifies datagram requested to be sent. + * @param datagramType datagram type indicating whether the datagram is of type + * SOS_SMS or LOCATION_SHARING. + * @param datagram encoded gateway datagram which is encrypted by the caller. + * Datagram will be passed down to modem without any encoding or encryption. + * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in + * full screen mode. + * @param result The result receiver that returns datagramId if datagram is sent successfully + * or {@link SatelliteManager.SatelliteError} of the request if it is failed. + */ + public void sendSatelliteDatagram(int subId, long datagramId, + @SatelliteManager.DatagramType int datagramType, SatelliteDatagram datagram, + boolean needFullScreenPointingUI, @NonNull ResultReceiver result) { + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + return; + } + + Phone phone = getPhoneOrDefault(validSubId, "sendSatelliteDatagram"); + // TODO: check if we need to start PointingUI. + sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, + new SendSatelliteDatagramArgument(datagramId, datagramType, datagram, + needFullScreenPointingUI, result), phone); + } + + /** + * Request to get whether satellite communication is allowed for the current location. + * + * @param subId The subId of the subscription to check whether satellite communication is + * allowed for the current location for. + * @param result The result receiver that returns whether satellite communication is allowed + * for the current location if the request is successful or an error code + * if the request failed. + */ + public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, + @NonNull ResultReceiver result) { + if (!isSatelliteSupported()) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + return; + } + + Phone phone = getPhoneOrDefault(validSubId, + "requestIsSatelliteCommunicationAllowedForCurrentLocation"); + sendRequest(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, phone); + } + + /** + * Request to get the time after which the satellite will be visible + * + * @param subId The subId to get the time after which the satellite will be visible for. + * @param result The result receiver that returns the time after which the satellite will + * be visible if the request is successful or an error code if the request failed. + */ + public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) { + if (!isSatelliteSupported()) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + return; + } + + final int validSubId = getValidSatelliteSubId(subId); + if (!isSatelliteProvisioned(validSubId)) { + result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + return; + } + + Phone phone = getPhoneOrDefault(validSubId, "requestTimeForNextSatelliteVisibility"); + sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); + } + private void handleEventProvisionSatelliteServiceDone( + @NonNull ProvisionSatelliteServiceArgument arg, + @SatelliteManager.SatelliteError int result) { + logd("handleEventProvisionSatelliteServiceDone: result=" + + result + ", subId=" + arg.subId); + + Consumer callback = mSatelliteProvisionCallbacks.remove(arg.subId); + if (callback == null) { + loge("handleEventProvisionSatelliteServiceDone: callback is null for subId=" + + arg.subId); + return; + } + callback.accept(result); + + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + setSatelliteProvisioned(arg.subId, true); + } + + /** + * We need to update satellite provision status in SubscriptionController + * or SatelliteController. + * TODO (b/267826133) we need to do this for all subscriptions on the device. + */ + registerForSatelliteProvisionStateChangedInternal(arg.subId, null); + } + + public boolean isSatelliteDemoModeEnabled() { + return mIsSatelliteDemoModeEnabled; + } + + private void handleEventDeprovisionSatelliteServiceDone( + @NonNull ProvisionSatelliteServiceArgument arg, + @SatelliteManager.SatelliteError int result) { + if (arg == null) { + loge("handleEventDeprovisionSatelliteServiceDone: arg is null"); + return; + } + logd("handleEventDeprovisionSatelliteServiceDone: result=" + + result + ", subId=" + arg.subId); + + if (arg.callback != null) { + arg.callback.accept(result); + } + + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + setSatelliteProvisioned(arg.subId, false); + } + } + + /** + * Registers for the satellite provision state changed. + * + * @param subId The subId of the subscription associated with the satellite service. + * @param callback The callback to handle the satellite provision state changed event. + * + * @return The {@link SatelliteManager.SatelliteError} result of the operation. + */ + @SatelliteManager.SatelliteError private int registerForSatelliteProvisionStateChangedInternal( + int subId, @Nullable ISatelliteProvisionStateCallback callback) { + if (!isSatelliteSupported()) { + return SatelliteManager.SATELLITE_NOT_SUPPORTED; + } + + final int validSubId = getValidSatelliteSubId(subId); + Phone phone = getPhoneOrDefault(validSubId, "registerForSatelliteProvisionStateChanged"); + + SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = + mSatelliteProvisionStateChangedHandlers.get(validSubId); + if (satelliteProvisionStateChangedHandler == null) { + satelliteProvisionStateChangedHandler = new SatelliteProvisionStateChangedHandler( + Looper.getMainLooper(), validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( + satelliteProvisionStateChangedHandler, + SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); + } else { + phone.registerForSatelliteProvisionStateChanged( + satelliteProvisionStateChangedHandler, + SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); + } + } + + if (callback != null) { + satelliteProvisionStateChangedHandler.addListener(callback); + } + mSatelliteProvisionStateChangedHandlers.put( + validSubId, satelliteProvisionStateChangedHandler); + return SatelliteManager.SATELLITE_ERROR_NONE; + } + + private void handleStartSatellitePositionUpdatesDone(@NonNull AsyncResult ar) { + SatelliteControllerHandlerRequest request = (SatelliteControllerHandlerRequest) ar.userObj; + SatellitePositionUpdateArgument arg = (SatellitePositionUpdateArgument) request.argument; + int errorCode = getSatelliteError( + ar, "handleStartSatellitePositionUpdatesDone", false); + arg.errorCallback.accept(errorCode); + + if (errorCode != SatelliteManager.SATELLITE_ERROR_NONE) { + /** + * We need to remove the callback from our listener list since the caller might not call + * {@link #stopSatellitePositionUpdates(int, IIntegerConsumer, ISatellitePositionUpdateCallback)} + * to unregister the callback in case of failure. + */ + SatellitePositionUpdateHandler handler = + mSatellitePositionUpdateHandlers.get(arg.subId); + if (handler != null) { + handler.removeListener(arg.callback); + + if (!handler.hasListeners()) { + mSatellitePositionUpdateHandlers.remove(arg.subId); + + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.unregisterForSatellitePositionInfoChanged( + handler); + mSatelliteModemInterface.unregisterForDatagramTransferStateChanged( + handler); + } else { + Phone phone = request.phone; + if (phone == null) { + loge("handleStartSatellitePositionUpdatesDone: phone is null"); + } else { + phone.unregisterForSatellitePositionInfoChanged(handler); + // TODO: unregisterForDatagramTransferStateChanged through + // SatelliteController + } + } + } + } + } + } + + /** + * Set satellite provisioned for a subscription or the device. + * + * The permission {@link android.Manifest.permission#MODIFY_PHONE_STATE} will be enforced by + * {@link SubscriptionController} when setting satellite enabled for an active subscription. + * Otherwise, {@link android.Manifest.permission#SATELLITE_COMMUNICATION} will be enforced. + */ + private synchronized void setSatelliteProvisioned(int subId, boolean isEnabled) { + if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + SubscriptionManager.setSubscriptionProperty( + subId, SubscriptionManager.SATELLITE_ENABLED, isEnabled ? "1" : "0"); + } else { + //TODO (b/267826133): set via SatelliteController + } + } + + + /** + * If we have not successfully queried the satellite modem for its satellite service support, + * we will retry the query one more time. Otherwise, we will return the queried result. + */ + private boolean isSatelliteSupported() { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported != null) { + /* We have already successfully queried the satellite modem. */ + return mIsSatelliteSupported; + } + } + /** + * We have not successfully checked whether the modem supports satellite service. + * Thus, we need to retry it now. + */ + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mSatelliteSupportedReceiver); + return false; + } + + /** + * Posts the specified command to be executed on the main thread and returns immediately. + * + * @param command command to be executed on the main thread + * @param argument additional parameters required to perform of the operation + * @param phone phone object used to perform the operation. + */ + private void sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone) { + SatelliteControllerHandlerRequest request = new SatelliteControllerHandlerRequest( + argument, phone); + Message msg = this.obtainMessage(command, request); + msg.sendToTarget(); + } + + /** + * Posts the specified command to be executed on the main thread. As this is a synchronous + * request, it waits until the request is complete and then return the result. + * + * @param command command to be executed on the main thread + * @param argument additional parameters required to perform of the operation + * @param phone phone object used to perform the operation. + * @return result of the operation + */ + private @Nullable Object sendRequest(int command, @NonNull Object argument, + @Nullable Phone phone) { + if (Looper.myLooper() == this.getLooper()) { + throw new RuntimeException("This method will deadlock if called from the main thread"); + } + + SatelliteControllerHandlerRequest request = new SatelliteControllerHandlerRequest( + argument, phone); + Message msg = this.obtainMessage(command, request); + msg.sendToTarget(); + + synchronized (request) { + while(request.result == null) { + try { + request.wait(); + } catch (InterruptedException e) { + // Do nothing, go back and wait until the request is complete. + } + } + } + return request.result; + } + + /** + * Return phone associated with this subscription or default phone. + * + * @param subId The subscription id. + * @param caller caller name to include in the error message. + * @return phone associated with this subscription or default phone. + */ + private Phone getPhoneOrDefault(int subId, String caller) { + Phone phone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId)); + if (phone == null) { + loge(caller + " called with invalid subId: " + subId + + ". Retrying with default subscription."); + phone = PhoneFactory.getPhone(SubscriptionManager + .getPhoneId(PhoneFactory.getDefaultSubscription())); + } + + if (phone == null) { + loge(caller + " called with invalid default subId: " + subId + + ". Retrying with default phone."); + phone = PhoneFactory.getDefaultPhone(); + } + + if (phone == null) { + loge(caller + " failed with no phone object."); + } + return phone; + } + + /** + * Get valid subscription id for satellite communication. + * + * @param subId The subscription id. + * @return input subId if the subscription is active else return default subscription id. + */ + private int getValidSatelliteSubId(int subId) { + final long identity = Binder.clearCallingIdentity(); + try { + boolean isActive; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId, + mContext.getOpPackageName(), mContext.getAttributionTag()); + } else { + isActive = SubscriptionController.getInstance().isActiveSubId(subId, + mContext.getOpPackageName(), mContext.getAttributionTag()); + } + + if (isActive) { + return subId; + } + } finally { + Binder.restoreCallingIdentity(identity); + } + if (DBG) logd("getValidSatelliteSubId: use DEFAULT_SUBSCRIPTION_ID for subId=" + subId); + return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; + } + + /** + * Get the {@link SatelliteManager.SatelliteError} from the provided result. + * + * @param ar AsyncResult used to determine the error code. + * @param caller The satellite request. + * @param checkResult Whether to check if the result exists. + * + * @return The {@link SatelliteManager.SatelliteError} error code from the request. + */ + @SatelliteManager.SatelliteError private int getSatelliteError(@NonNull AsyncResult ar, + @NonNull String caller, boolean checkResult) { + int errorCode; + if (ar.exception == null) { + errorCode = SatelliteManager.SATELLITE_ERROR_NONE; + if (checkResult && ar.result == null) { + loge(caller + ": result is null"); + errorCode = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } + } else { + errorCode = SatelliteManager.SATELLITE_ERROR; + if (ar.exception instanceof CommandException) { + CommandException.Error error = + ((CommandException) (ar.exception)).getCommandError(); + errorCode = RILUtils.convertToSatelliteError(error); + loge(caller + " CommandException: " + ar.exception); + } else { + loge(caller + " unknown exception: " + ar.exception); + } + } + logd(caller + " error: " + errorCode); + return errorCode; + } + + /** + * Check if satellite is provisioned for a subscription on the device. + * @param subId The subscription id. + * @return true if satellite is provisioned on the given subscription else return false. + */ + private boolean isSatelliteProvisioned(int subId) { + final long identity = Binder.clearCallingIdentity(); + try { + if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + String strResult = null; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + strResult = SubscriptionManagerService.getInstance() + .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED, + mContext.getOpPackageName(), mContext.getAttributionTag()); + } else { + strResult = SubscriptionController.getInstance() + .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED); + } + + if (strResult != null) { + int intResult = Integer.parseInt(strResult); + return (intResult == 1); + } + } else { + //TODO (b/267826133): check via SatelliteController + } + } finally { + Binder.restoreCallingIdentity(identity); + } + return false; + } + + private static void logd(@NonNull String log) { + Rlog.d(TAG, log); + } + + private static void loge(@NonNull String log) { + Rlog.e(TAG, log); + } +} + diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java similarity index 94% rename from src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java rename to src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 719c09499d..8827e67dc2 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -45,23 +45,28 @@ import android.util.Pair; import com.android.internal.telephony.ExponentialBackoff; import com.android.internal.telephony.IBooleanConsumer; import com.android.internal.telephony.IIntegerConsumer; +import com.android.internal.telephony.Phone; import java.util.Arrays; import java.util.function.Consumer; /** - * Satellite service controller to manage connections with the satellite service. + * Satellite modem interface to manage connections with the satellite service and HAL interface. */ -public class SatelliteServiceController { - private static final String TAG = "SatelliteServiceController"; +public class SatelliteModemInterface { + private static final String TAG = "SatelliteModemInterface"; private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute private static final int REBIND_MULTIPLIER = 2; - @NonNull private static SatelliteServiceController sInstance; + @NonNull private static SatelliteModemInterface sInstance; @NonNull private final Context mContext; @NonNull private final ExponentialBackoff mExponentialBackoff; @NonNull private final Object mLock = new Object(); + /** + * {@code true} to use the vendor satellite service and {@code false} to use the HAL. + */ + private final boolean mIsSatelliteServiceSupported = false; @Nullable private ISatellite mSatelliteService; @Nullable private SatelliteServiceConnection mSatelliteServiceConnection; private boolean mIsBound; @@ -81,8 +86,6 @@ public class SatelliteServiceController { @NonNull private final RegistrantList mSatelliteRadioTechnologyChangedRegistrants = new RegistrantList(); - private boolean mIsSatelliteDemoModeEnabled = false; - @NonNull private final ISatelliteListener mListener = new ISatelliteListener.Stub() { @Override public void onSatelliteProvisionStateChanged(boolean provisioned) { @@ -141,32 +144,34 @@ public class SatelliteServiceController { }; /** - * @return The singleton instance of SatelliteServiceController. + * @return The singleton instance of SatelliteModemInterface. */ - public static SatelliteServiceController getInstance() { + public static SatelliteModemInterface getInstance() { if (sInstance == null) { - loge("SatelliteServiceController was not yet initialized."); + loge("SatelliteModemInterface was not yet initialized."); } return sInstance; } /** - * Create the SatelliteServiceController singleton instance. - * @param context The Context to use to create the SatelliteServiceController. + * Create the SatelliteModemInterface singleton instance. + * @param context The Context to use to create the SatelliteModemInterface. + * @return The singleton instance of SatelliteModemInterface. */ - public static void make(@NonNull Context context) { + public static SatelliteModemInterface make(@NonNull Context context) { if (sInstance == null) { - sInstance = new SatelliteServiceController(context, Looper.getMainLooper()); + sInstance = new SatelliteModemInterface(context, Looper.getMainLooper()); } + return sInstance; } /** - * Create a SatelliteServiceController to manage connections to the SatelliteService. + * Create a SatelliteModemInterface to manage connections to the SatelliteService. * - * @param context The Context for the SatelliteServiceController. + * @param context The Context for the SatelliteModemInterface. * @param looper The Looper to run binding retry on. */ - private SatelliteServiceController(@NonNull Context context, @NonNull Looper looper) { + private SatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { mContext = context; mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, REBIND_MULTIPLIER, looper, () -> { @@ -185,7 +190,7 @@ public class SatelliteServiceController { bindService(); }); mExponentialBackoff.start(); - logd("Created SatelliteServiceController. Attempting to bind to SatelliteService."); + logd("Created SatelliteModemInterface. Attempting to bind to SatelliteService."); bindService(); } @@ -464,7 +469,8 @@ public class SatelliteServiceController { if (mSatelliteService != null) { try { mSatelliteService.requestSatelliteListeningEnabled( - enable, mIsSatelliteDemoModeEnabled, new IIntegerConsumer.Stub() { + enable, SatelliteController.getInstance().isSatelliteDemoModeEnabled(), + new IIntegerConsumer.Stub() { @Override public void accept(int result) { int error = SatelliteServiceUtils.fromSatelliteError(result); @@ -483,41 +489,6 @@ public class SatelliteServiceController { } } - /** - * Request to enable or disable the satellite service demo mode. - * - * @param enable {@code true} to enable satellite demo mode and {@code false} to disable. - * @return The error code of the request. - */ - @SatelliteManager.SatelliteError public int requestSatelliteDemoModeEnabled(boolean enable) { - if (mSatelliteService != null) { - logd("requestSatelliteDemoModeEnabled: " + enable); - mIsSatelliteDemoModeEnabled = enable; - return SatelliteManager.SATELLITE_ERROR_NONE; - } else { - loge("requestSatelliteDemoModeEnabled: Satellite service is unavailable."); - return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED; - } - } - - /** - * Request to get whether the satellite service demo mode is enabled. - * - * @param callback The callback to accept whether the satellite demo mode is enabled. - * @return The error code of the request. - */ - @SatelliteManager.SatelliteError public int requestIsSatelliteDemoModeEnabled( - @NonNull Consumer callback) { - if (mSatelliteService != null) { - logd("requestIsSatelliteDemoModeEnabled: " + mIsSatelliteDemoModeEnabled); - callback.accept(mIsSatelliteDemoModeEnabled); - return SatelliteManager.SATELLITE_ERROR_NONE; - } else { - loge("requestIsSatelliteDemoModeEnabled: Satellite service is unavailable."); - return SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED; - } - } - /** * Request to enable or disable the satellite modem. If the satellite modem is enabled, * this will also disable the cellular modem, and if the satellite modem is disabled, @@ -893,7 +864,7 @@ public class SatelliteServiceController { try { mSatelliteService.sendSatelliteDatagram( SatelliteServiceUtils.toSatelliteDatagram(datagram), - mIsSatelliteDemoModeEnabled, isEmergency, + SatelliteController.getInstance().isSatelliteDemoModeEnabled(), isEmergency, new IIntegerConsumer.Stub() { @Override public void accept(int result) { @@ -1031,6 +1002,11 @@ public class SatelliteServiceController { } } + public boolean isSatelliteServiceSupported() { + // TODO: update this method + return mIsSatelliteServiceSupported; + } + private static void sendMessageWithResult(@NonNull Message message, @Nullable Object result, @SatelliteManager.SatelliteError int error) { AsyncResult.forMessage(message, result, new SatelliteException(error)); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java new file mode 100644 index 0000000000..98b9cad85f --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023 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.NonNull; +import android.content.Context; +import android.os.Looper; +import android.telephony.Rlog; + +/** + * Satellite session controller to manage all the data during a satellite session. + */ +public class SatelliteSessionController { + private static final String TAG = "SatelliteSessionController"; + + @NonNull private static SatelliteSessionController sInstance; + @NonNull private final Context mContext; + + /** + * @return The singleton instance of SatelliteSessionController. + */ + public static SatelliteSessionController getInstance() { + if (sInstance == null) { + loge("SatelliteSessionController was not yet initialized."); + } + return sInstance; + } + + /** + * Create the SatelliteSessionController singleton instance. + * @param context The Context to use to create the SatelliteSessionController. + * @return The singleton instance of SatelliteSessionController. + */ + public static SatelliteSessionController make(@NonNull Context context) { + if (sInstance == null) { + sInstance = new SatelliteSessionController(context); + } + return sInstance; + } + + /** + * Create a SatelliteSessionController to manage satellite session. + * + * @param context The Context for the SatelliteSessionController. + */ + private SatelliteSessionController(@NonNull Context context) { + mContext = context; + } + + private static void logd(@NonNull String log) { + Rlog.d(TAG, log); + } + + private static void loge(@NonNull String log) { + Rlog.e(TAG, log); + } + + /** + * TODO: The following needs to be added in this class: + *- SatelliteStateListenerHandler + * Things to add in future: + * - state machine + * - This class should be aware of who turned on satellite mode etc + * - voting controller + */ +} -- GitLab From e8e7302e66e66f2665a19c72d98f1f3b8b7c4934 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 19 Jan 2023 18:00:45 -0800 Subject: [PATCH 461/656] Delay IMS teardown till VoPS call ends The change is to delay tear down an active VoPS call when a. allow extensive lingering network type when handover to CSFB b. allow temporary mismatch of IMS preferred transport The change also make sure tear down IMS network after call ended if it was delayed torn down. Fix: 263668080 Fix: 245666094 Bug: 262300348 Test: Normal voice call + Placed WFC on APM mode and observe de-reg as expected when force call drop by turn OFF wifi and reviewd log Change-Id: I5a3e4ff5d5ea7669452346d7249ea705ec4376a3 --- .../telephony/data/DataConfigManager.java | 5 +- .../telephony/data/DataEvaluation.java | 8 +- .../internal/telephony/data/DataNetwork.java | 8 +- .../telephony/data/DataNetworkController.java | 104 +++++++++++------ .../telephony/data/DataRetryManager.java | 18 +++ .../data/DataNetworkControllerTest.java | 106 +++++++++++++----- .../telephony/data/DataNetworkTest.java | 1 - 7 files changed, 183 insertions(+), 67 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index 731aac75f3..24397d6239 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -1006,7 +1006,7 @@ public class DataConfigManager extends Handler { * @return {@code true} if tearing down IMS data network should be delayed until the voice call * ends. */ - public boolean isImsDelayTearDownEnabled() { + public boolean isImsDelayTearDownUntilVoiceCallEndEnabled() { return mCarrierConfig.getBoolean( CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL); } @@ -1368,7 +1368,8 @@ public class DataConfigManager extends Handler { + shouldPersistIwlanDataNetworksWhenDataServiceRestarted()); pw.println("Bandwidth estimation source=" + mResources.getString( com.android.internal.R.string.config_bandwidthEstimateSource)); - pw.println("isDelayTearDownImsEnabled=" + isImsDelayTearDownEnabled()); + pw.println("isImsDelayTearDownUntilVoiceCallEndEnabled=" + + isImsDelayTearDownUntilVoiceCallEndEnabled()); pw.println("isEnhancedIwlanHandoverCheckEnabled=" + isEnhancedIwlanHandoverCheckEnabled()); pw.println("isTetheringProfileDisabledForRoaming=" + isTetheringProfileDisabledForRoaming()); diff --git a/src/java/com/android/internal/telephony/data/DataEvaluation.java b/src/java/com/android/internal/telephony/data/DataEvaluation.java index 0af68374a7..cc46caa873 100644 --- a/src/java/com/android/internal/telephony/data/DataEvaluation.java +++ b/src/java/com/android/internal/telephony/data/DataEvaluation.java @@ -321,7 +321,9 @@ public class DataEvaluation { /** Only one data network is allowed at one time. */ ONLY_ALLOWED_SINGLE_NETWORK(true), /** Data enabled settings are not ready. */ - DATA_SETTINGS_NOT_READY(true); + DATA_SETTINGS_NOT_READY(true), + /** Handover max retry stopped but network is not on the preferred transport. */ + HANDOVER_RETRY_STOPPED(true); private final boolean mIsHardReason; @@ -359,6 +361,10 @@ public class DataEvaluation { * The normal reason. This is the most common case. */ NORMAL, + /** + * Data is allowed because an ongoing VoPS call depends on this network + */ + IN_VOICE_CALL, /** * The network brought up by this network request is unmetered. Should allowed no matter * the user enables or disables data. diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 1ba3d67ac6..97930bdb9d 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -54,6 +54,7 @@ import android.telephony.Annotation.NetCapability; import android.telephony.Annotation.NetworkType; import android.telephony.Annotation.ValidationStatus; import android.telephony.AnomalyReporter; +import android.telephony.CarrierConfigManager; import android.telephony.DataFailCause; import android.telephony.DataSpecificRegistrationInfo; import android.telephony.LinkCapacityEstimate; @@ -2590,11 +2591,12 @@ public class DataNetwork extends StateMachine { } /** - * @return {@code true} if this is an IMS network and tear down should be delayed until call - * ends on this data network. + * @return {@code true} if we shall delay tear down this network because an active voice call is + * relying on it and + * {@link CarrierConfigManager#KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL} is enabled. */ public boolean shouldDelayImsTearDownDueToInCall() { - return mDataConfigManager.isImsDelayTearDownEnabled() + return mDataConfigManager.isImsDelayTearDownUntilVoiceCallEndEnabled() && mNetworkCapabilities != null && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL) && mPhone.getImsPhone() != null diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 2290a1ba35..872292f01e 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -894,24 +894,7 @@ public class DataNetworkController extends Handler { public void onDataNetworkHandoverRetryStopped( @NonNull DataNetwork dataNetwork) { Objects.requireNonNull(dataNetwork); - int preferredTransport = mAccessNetworksManager - .getPreferredTransportByNetworkCapability( - dataNetwork.getApnTypeNetworkCapability()); - if (dataNetwork.getTransport() == preferredTransport) { - log("onDataNetworkHandoverRetryStopped: " + dataNetwork + " is already " - + "on the preferred transport " - + AccessNetworkConstants.transportTypeToString( - preferredTransport)); - return; - } - if (dataNetwork.shouldDelayImsTearDownDueToInCall()) { - log("onDataNetworkHandoverRetryStopped: Delay IMS tear down until call " - + "ends. " + dataNetwork); - return; - } - - tearDownGracefully(dataNetwork, - DataNetwork.TEAR_DOWN_REASON_HANDOVER_FAILED); + DataNetworkController.this.onDataNetworkHandoverRetryStopped(dataNetwork); } }); mImsManager = mPhone.getContext().getSystemService(ImsManager.class); @@ -1747,15 +1730,20 @@ public class DataNetworkController extends Handler { } } - boolean isMmtel = false; - // If the data network is IMS that supports voice call, and has MMTEL request (client - // specified VoPS is required.) - if (dataNetwork.getAttachedNetworkRequestList().get( - new int[]{NetworkCapabilities.NET_CAPABILITY_MMTEL}) != null) { - // When reaching here, it means the network supports MMTEL, and also has MMTEL request - // attached to it. - isMmtel = true; - if (!dataNetwork.shouldDelayImsTearDownDueToInCall()) { + boolean vopsIsRequired = dataNetwork.hasNetworkCapabilityInNetworkRequests( + NetworkCapabilities.NET_CAPABILITY_MMTEL); + + // Check an active call relying on this network and config for "delay tear down due to vops + // call" is enabled. + if (dataNetwork.shouldDelayImsTearDownDueToInCall()) { + if (vopsIsRequired) { + log("Ignored VoPS check due to delay IMS tear down until call ends."); + } + } else { + // Reach here means we should ignore active calls even if there are any. + + // Check if VoPS requirement is met. + if (vopsIsRequired) { if (dataNetwork.getTransport() == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { NetworkRegistrationInfo nri = mServiceState.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, @@ -1770,8 +1758,15 @@ public class DataNetworkController extends Handler { } } } - } else { - log("Ignored VoPS check due to delay IMS tear down until call ends."); + } + + // Check if handover retry stopped and preferred transport still not matched. + int preferredTransport = mAccessNetworksManager + .getPreferredTransportByNetworkCapability( + dataNetwork.getApnTypeNetworkCapability()); + if (preferredTransport != dataNetwork.getTransport() + && mDataRetryManager.isDataNetworkHandoverRetryStopped(dataNetwork)) { + evaluation.addDataDisallowedReason(DataDisallowedReason.HANDOVER_RETRY_STOPPED); } } @@ -1802,9 +1797,7 @@ public class DataNetworkController extends Handler { // Sometimes network temporarily OOS and network type becomes UNKNOWN. We don't // tear down network in that case. if (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN - && !dataProfile.getApnSetting().canSupportLingeringNetworkType(networkType) - // delay IMS tear down if SRVCC in progress - && !(isMmtel && mIsSrvccHandoverInProcess)) { + && !dataProfile.getApnSetting().canSupportLingeringNetworkType(networkType)) { log("networkType=" + TelephonyManager.getNetworkTypeName(networkType) + ", networkTypeBitmask=" + TelephonyManager.convertNetworkTypeBitmaskToString( @@ -1866,6 +1859,15 @@ public class DataNetworkController extends Handler { } } + // Check if we allow additional lingering for active VoPS call network if + // a. this network is SRVCC handover in progress + // or b. "delay tear down due to active VoPS call" is enabled + boolean isInSrvcc = vopsIsRequired && mIsSrvccHandoverInProcess; + if (evaluation.containsOnly(DataDisallowedReason.DATA_NETWORK_TYPE_NOT_ALLOWED) + && (dataNetwork.shouldDelayImsTearDownDueToInCall() || isInSrvcc)) { + evaluation.addDataAllowedReason(DataAllowedReason.IN_VOICE_CALL); + } + log("Evaluated " + dataNetwork + ", " + evaluation); return evaluation; } @@ -2058,6 +2060,8 @@ public class DataNetworkController extends Handler { return DataNetwork.TEAR_DOWN_REASON_VOPS_NOT_SUPPORTED; case ONLY_ALLOWED_SINGLE_NETWORK: return DataNetwork.TEAR_DOWN_REASON_ONLY_ALLOWED_SINGLE_NETWORK; + case HANDOVER_RETRY_STOPPED: + return DataNetwork.TEAR_DOWN_REASON_HANDOVER_FAILED; } } return DataNetwork.TEAR_DOWN_REASON_NONE; @@ -2767,6 +2771,32 @@ public class DataNetworkController extends Handler { tryHandoverDataNetwork(dataNetwork, preferredTransport, dataHandoverRetryEntry); } + /** + * Called when data network reached max handover retry count. + * + * @param dataNetwork The data network. + */ + private void onDataNetworkHandoverRetryStopped(@NonNull DataNetwork dataNetwork) { + int preferredTransport = mAccessNetworksManager + .getPreferredTransportByNetworkCapability( + dataNetwork.getApnTypeNetworkCapability()); + if (dataNetwork.getTransport() == preferredTransport) { + log("onDataNetworkHandoverRetryStopped: " + dataNetwork + " is already " + + "on the preferred transport " + + AccessNetworkConstants.transportTypeToString( + preferredTransport)); + return; + } + if (dataNetwork.shouldDelayImsTearDownDueToInCall()) { + log("onDataNetworkHandoverRetryStopped: Delay IMS tear down until call " + + "ends. " + dataNetwork); + return; + } + + tearDownGracefully(dataNetwork, + DataNetwork.TEAR_DOWN_REASON_HANDOVER_FAILED); + } + /** * Called when data network validation status changed. * @@ -3103,6 +3133,16 @@ public class DataNetworkController extends Handler { logl("Start handover " + dataNetwork + " to " + AccessNetworkConstants.transportTypeToString(targetTransport)); dataNetwork.startHandover(targetTransport, dataHandoverRetryEntry); + } else if (dataEvaluation.containsOnly(DataDisallowedReason.NOT_IN_SERVICE) + && dataNetwork.shouldDelayImsTearDownDueToInCall()) { + // We try to preserve voice call in the case of temporary preferred transport mismatch + if (dataHandoverRetryEntry != null) { + dataHandoverRetryEntry.setState(DataRetryEntry.RETRY_STATE_FAILED); + } + mDataRetryManager.evaluateDataHandoverRetry(dataNetwork, + DataFailCause.HANDOVER_FAILED, + DataCallResponse.RETRY_DURATION_UNDEFINED /* retry mills */); + logl("tryHandoverDataNetwork: Scheduled retry due to in voice call and target OOS"); } else if (dataEvaluation.containsAny(DataDisallowedReason.NOT_ALLOWED_BY_POLICY, DataDisallowedReason.NOT_IN_SERVICE, DataDisallowedReason.VOPS_NOT_SUPPORTED)) { diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index 638faa5f67..9e2e3b12e6 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -1298,6 +1298,24 @@ public class DataRetryManager extends Handler { } } + /** + * @param dataNetwork The data network to check. + * @return {@code true} if the data network had failed the maximum number of attempts for + * handover according to any retry rules. + */ + public boolean isDataNetworkHandoverRetryStopped(@NonNull DataNetwork dataNetwork) { + // Matching the rule in configured order. + for (DataHandoverRetryRule retryRule : mDataHandoverRetryRuleList) { + int failedCount = getRetryFailedCount(dataNetwork, retryRule); + if (failedCount == retryRule.getMaxRetries()) { + log("Data handover retry failed for " + failedCount + " times. Stopped " + + "handover retry."); + return true; + } + } + return false; + } + /** Cancel all retries and throttling entries. */ private void onReset(@RetryResetReason int reason) { logl("Remove all retry and throttling entries, reason=" + resetReasonToString(reason)); 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 f7d80e5ab8..1283cc6850 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -2455,6 +2455,7 @@ public class DataNetworkControllerTest extends TelephonyTest { public void testHandoverDataNetworkRetryReachedMaximum() throws Exception { testSetupImsDataNetwork(); + // 1. Normal case setFailedSetupDataResponse(mMockedWlanDataServiceManager, DataFailCause.HANDOVER_FAILED, -1, true); updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, @@ -2475,6 +2476,30 @@ public class DataNetworkControllerTest extends TelephonyTest { verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); + + // 2. Active VoPS call, should delay tear down + doReturn(PhoneConstants.State.RINGING).when(mCT).getState(); + mCarrierConfig.putBoolean(CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, + true); + carrierConfigChanged(); + + setFailedSetupDataResponse(mMockedWwanDataServiceManager, + DataFailCause.HANDOVER_FAILED, -1, true); + updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + processAllFutureMessages(); + + // Verify the network wasn't torn down + verify(mMockedWlanDataServiceManager, never()).deactivateDataCall(anyInt(), + eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); + + // Verify tear down after call ends + doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); + mDataNetworkControllerUT.obtainMessage(18/*EVENT_VOICE_CALL_ENDED*/).sendToTarget(); + processAllFutureMessages(); + + verify(mMockedWlanDataServiceManager).deactivateDataCall(anyInt(), + eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); } @Test @@ -3567,38 +3592,63 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testHandoverDataNetworkOos() throws Exception { - ServiceState ss = new ServiceState(); - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_IWLAN) - .setRegistrationState( - NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING) - .setDomain(NetworkRegistrationInfo.DOMAIN_PS) - .build()); - - ss.addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() - .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME) - .setDomain(NetworkRegistrationInfo.DOMAIN_CS) - .build()); - processServiceStateRegStateForTest(ss); - doReturn(ss).when(mSST).getServiceState(); - doReturn(ss).when(mPhone).getServiceState(); + // Config delay IMS tear down enabled + mCarrierConfig.putBoolean(CarrierConfigManager.KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, + true); + carrierConfigChanged(); - mDataNetworkControllerUT.obtainMessage(17/*EVENT_SERVICE_STATE_CHANGED*/).sendToTarget(); - processAllMessages(); + // VoPS supported + DataSpecificRegistrationInfo dsri = new DataSpecificRegistrationInfo.Builder(8) + .setNrAvailable(true) + .setEnDcAvailable(true) + .setVopsSupportInfo(new LteVopsSupportInfo( + LteVopsSupportInfo.LTE_STATUS_SUPPORTED, + LteVopsSupportInfo.LTE_STATUS_SUPPORTED)) + .build(); + serviceStateChanged(TelephonyManager.NETWORK_TYPE_LTE, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME /*data*/, + NetworkRegistrationInfo.REGISTRATION_STATE_HOME /*voice*/, + NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING /*iwlan*/, + dsri); testSetupImsDataNetwork(); + DataNetwork dataNetwork = getDataNetworks().get(0); + + // 1. Active VoPS call, mock target IWLAN OOS, should schedule retry + doReturn(PhoneConstants.State.RINGING).when(mCT).getState(); updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + // Process DRM event to schedule retry + processAllMessages(); + + // Verify scheduled new handover retry + assertTrue(mDataNetworkControllerUT.getDataRetryManager() + .isAnyHandoverRetryScheduled(dataNetwork)); + // Verify the network wasn't torn down + verify(mMockedWwanDataServiceManager, never()).deactivateDataCall(anyInt(), + eq(DataService.REQUEST_REASON_NORMAL), any(Message.class)); + + // Get the scheduled retry + Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries"); + field.setAccessible(true); + DataRetryManager.DataHandoverRetryEntry dataRetryEntry = + (DataRetryManager.DataHandoverRetryEntry) ((List) + field.get(mDataNetworkControllerUT.getDataRetryManager())).get(0); + + // Process the retry + moveTimeForward(1000 /*The retry delay of the first attempt*/); + processAllMessages(); + + // Verify the previous retry is set to FAILED + assertEquals(DataRetryManager.DataRetryEntry.RETRY_STATE_FAILED, dataRetryEntry.getState()); + // Verify a new retry is scheduled + assertTrue(mDataNetworkControllerUT.getDataRetryManager() + .isAnyHandoverRetryScheduled(dataNetwork)); + + // 2. Normal case (call ended), should tear down + doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); + mDataNetworkControllerUT.obtainMessage(18/*EVENT_VOICE_CALL_ENDED*/).sendToTarget(); + processAllFutureMessages(); // Verify that handover is not performed. verify(mMockedWlanDataServiceManager, never()).setupDataCall(anyInt(), @@ -3606,7 +3656,7 @@ public class DataNetworkControllerTest extends TelephonyTest { eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), any(), anyBoolean(), any(Message.class)); - // IMS network should be torn down. + // Verify IMS network should be torn down. verifyAllDataDisconnected(); } 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 bb437eb828..82708d2630 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -340,7 +340,6 @@ public class DataNetworkTest extends TelephonyTest { doReturn(true).when(mDataConfigManager).isTempNotMeteredSupportedByCarrier(); doReturn(true).when(mDataConfigManager).isNetworkTypeUnmetered( any(TelephonyDisplayInfo.class), any(ServiceState.class)); - doReturn(true).when(mDataConfigManager).isImsDelayTearDownEnabled(); doReturn(DEFAULT_MTU).when(mDataConfigManager).getDefaultMtu(); doReturn(FAKE_IMSI).when(mPhone).getSubscriberId(); doReturn(true).when(mDataNetworkController) -- GitLab From b06b862b43bc270683959543761fe08578edae78 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 21 Feb 2023 20:38:46 -0800 Subject: [PATCH 462/656] Fixed port index not updated on inactive eSIM The port index should be set to -1 when an embedded subscription is inactive. Also fixed the debug messages in the dump. Fix: 270177138 Test: Manually activate/deactivate eSIM Test: atest SubscriptionManagerServiceTest Change-Id: I8567714c87c8ca6ee313ead2119264c2a038e116 --- .../SubscriptionDatabaseManager.java | 18 +-- .../SubscriptionManagerService.java | 118 +++++++++++------- .../internal/telephony/uicc/PinStorage.java | 18 +-- .../internal/telephony/uicc/UiccCard.java | 18 ++- .../telephony/uicc/UiccCardApplication.java | 56 ++++----- .../uicc/UiccCarrierPrivilegeRules.java | 16 ++- .../telephony/uicc/UiccController.java | 45 ++++--- .../internal/telephony/uicc/UiccPort.java | 20 +-- .../internal/telephony/uicc/UiccProfile.java | 48 +++---- .../internal/telephony/uicc/UiccSlot.java | 39 +++--- .../telephony/uicc/euicc/EuiccCard.java | 12 +- .../telephony/uicc/euicc/EuiccPort.java | 12 +- .../SubscriptionManagerServiceTest.java | 86 +++++++++++-- 13 files changed, 313 insertions(+), 193 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index aa3ecf6f40..263fbe545c 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -1815,13 +1815,14 @@ public class SubscriptionDatabaseManager extends Handler { * Load the database from content provider to the cache. */ private void loadDatabaseInternal() { - logl("loadDatabaseInternal"); + log("loadDatabaseInternal"); try (Cursor cursor = mContext.getContentResolver().query( SimInfo.CONTENT_URI, null, null, null, null)) { mReadWriteLock.writeLock().lock(); try { Map newAllSubscriptionInfoInternalCache = new HashMap<>(); + boolean changed = false; while (cursor != null && cursor.moveToNext()) { SubscriptionInfoInternal subInfo = createSubscriptionInfoFromCursor(cursor); newAllSubscriptionInfoInternalCache.put(subInfo.getSubscriptionId(), subInfo); @@ -1829,16 +1830,19 @@ public class SubscriptionDatabaseManager extends Handler { .get(subInfo.getSubscriptionId()), subInfo)) { mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged( subInfo.getSubscriptionId())); + changed = true; } } - mAllSubscriptionInfoInternalCache.clear(); - mAllSubscriptionInfoInternalCache.putAll(newAllSubscriptionInfoInternalCache); + if (changed) { + mAllSubscriptionInfoInternalCache.clear(); + mAllSubscriptionInfoInternalCache.putAll(newAllSubscriptionInfoInternalCache); - logl("Loaded " + mAllSubscriptionInfoInternalCache.size() - + " records from the subscription database."); - mAllSubscriptionInfoInternalCache.forEach( - (subId, subInfo) -> log(" " + subInfo.toString())); + logl("Loaded " + mAllSubscriptionInfoInternalCache.size() + + " records from the subscription database."); + mAllSubscriptionInfoInternalCache.forEach( + (subId, subInfo) -> log(" " + subInfo.toString())); + } } finally { mReadWriteLock.writeLock().unlock(); } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 246446f18d..6867ed8c60 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -392,6 +392,7 @@ public class SubscriptionManagerService extends ISub.Stub { * @param looper The looper for the handler. */ public SubscriptionManagerService(@NonNull Context context, @NonNull Looper looper) { + logl("Created SubscriptionManagerService"); sInstance = this; mContext = context; mTelephonyManager = context.getSystemService(TelephonyManager.class); @@ -551,16 +552,16 @@ public class SubscriptionManagerService extends ISub.Stub { } }); + SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); + SubscriptionManager.invalidateSubscriptionManagerServiceEnabledCaches(); + mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { updateEmbeddedSubscriptions(); } }, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); - - SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); - SubscriptionManager.invalidateSubscriptionManagerServiceEnabledCaches(); - logl("created"); + logl("Registered iSub service"); } /** @@ -923,9 +924,11 @@ public class SubscriptionManagerService extends ISub.Stub { .forEach(subInfo -> { mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), SubscriptionManager.INVALID_SIM_SLOT_INDEX); + mSubscriptionDatabaseManager.setPortIndex(subInfo.getSubscriptionId(), + TelephonyManager.INVALID_PORT_INDEX); }); updateGroupDisabled(); - logl("markSubscriptionsInactive: " + slotMappingToString()); + logl("markSubscriptionsInactive: current mapping " + slotMappingToString()); } /** @@ -961,17 +964,19 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Get the embedded profile port index by ICCID. + * Get the port index by ICCID. * * @param iccId The ICCID. * @return The port index. */ - private int getEmbeddedProfilePortIndex(String iccId) { - UiccSlot[] slots = UiccController.getInstance().getUiccSlots(); + private int getPortIndex(@NonNull String iccId) { + UiccSlot[] slots = mUiccController.getUiccSlots(); for (UiccSlot slot : slots) { - if (slot != null && slot.isEuicc() - && slot.getPortIndexFromIccId(iccId) != TelephonyManager.INVALID_PORT_INDEX) { - return slot.getPortIndexFromIccId(iccId); + if (slot != null) { + int portIndex = slot.getPortIndexFromIccId(iccId); + if (portIndex != TelephonyManager.INVALID_PORT_INDEX) { + return portIndex; + } } } return TelephonyManager.INVALID_PORT_INDEX; @@ -1029,6 +1034,13 @@ public class SubscriptionManagerService extends ISub.Stub { Set embeddedSubs = new ArraySet<>(); log("updateEmbeddedSubscriptions: start to get euicc profiles."); + + for (UiccSlot slot : mUiccController.getUiccSlots()) { + if (slot != null) { + log(" " + slot.toString()); + } + } + for (int cardId : cardIds) { GetEuiccProfileInfoListResult result = mEuiccController .blockingGetEuiccProfileInfoList(cardId); @@ -1080,7 +1092,7 @@ public class SubscriptionManagerService extends ISub.Stub { builder.setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER); } builder.setProfileClass(embeddedProfile.getProfileClass()); - builder.setPortIndex(getEmbeddedProfilePortIndex(embeddedProfile.getIccid())); + builder.setPortIndex(getPortIndex(embeddedProfile.getIccid())); CarrierIdentifier cid = embeddedProfile.getCarrierIdentifier(); if (cid != null) { @@ -1221,7 +1233,7 @@ public class SubscriptionManagerService extends ISub.Stub { } if (mSimState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN) { - log("areAllSubscriptionsLoaded: SIM state is still unknown."); + log("areAllSubscriptionsLoaded: SIM " + phoneId + " state is still unknown."); return false; } } @@ -1230,20 +1242,26 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Update the subscriptions on the logical SIM slot index (i.e. phone id). + * Update the subscription on the logical SIM slot index (i.e. phone id). * * @param phoneId The phone id (i.e. Logical SIM slot index) */ - private void updateSubscriptions(int phoneId) { + private void updateSubscription(int phoneId) { int simState = mSimState[phoneId]; - log("updateSubscriptions: phoneId=" + phoneId + ", simState=" + log("updateSubscription: phoneId=" + phoneId + ", simState=" + TelephonyManager.simStateToString(simState)); + for (UiccSlot slot : mUiccController.getUiccSlots()) { + if (slot != null) { + log(" " + slot.toString()); + } + } + if (simState == TelephonyManager.SIM_STATE_ABSENT) { if (mSlotIndexToSubId.containsKey(phoneId)) { int subId = mSlotIndexToSubId.get(phoneId); // Re-enable the SIM when it's removed, so it will be in enabled state when it gets // re-inserted again. (pre-U behavior) - log("updateSubscriptions: Re-enable Uicc application on sub " + subId); + log("updateSubscription: Re-enable Uicc application on sub " + subId); mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, true); // When sim is absent, set the port index to invalid port index. (pre-U behavior) mSubscriptionDatabaseManager.setPortIndex(subId, @@ -1255,45 +1273,49 @@ public class SubscriptionManagerService extends ISub.Stub { // final state. IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); if (!iccCard.isEmptyProfile() && areUiccAppsEnabledOnCard(phoneId)) { - log("updateSubscriptions: SIM_STATE_NOT_READY is not a final state. Will update " + log("updateSubscription: SIM_STATE_NOT_READY is not a final state. Will update " + "subscription later."); return; } if (!areUiccAppsEnabledOnCard(phoneId)) { - logl("updateSubscriptions: UICC app disabled on slot " + phoneId); + logl("updateSubscription: UICC app disabled on slot " + phoneId); markSubscriptionsInactive(phoneId); } } String iccId = getIccId(phoneId); - log("updateSubscriptions: Found iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + log("updateSubscription: Found iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + " on phone " + phoneId); // For eSIM switching, SIM absent will not happen. Below is to exam if we find ICCID - // mismatch on the SIM slot, we need to mark all subscriptions on that logical slot invalid - // first. The correct subscription will be assigned the correct slot later. - if (mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .anyMatch(subInfo -> subInfo.getSimSlotIndex() == phoneId - && !iccId.equals(subInfo.getIccId()))) { - log("updateSubscriptions: iccId changed for phone " + phoneId); + // mismatch on the SIM slot. If that's the case, we need to mark all subscriptions on that + // logical slot invalid first. The correct subscription will be assigned the correct slot + // later. + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager.getAllSubscriptions() + .stream() + .filter(sub -> sub.getSimSlotIndex() == phoneId && !iccId.equals(sub.getIccId())) + .findFirst() + .orElse(null); + if (subInfo != null) { + log("updateSubscription: Found previous active sub " + subInfo.getSubscriptionId() + + " that doesn't match current iccid on slot " + phoneId + "."); markSubscriptionsInactive(phoneId); } if (!TextUtils.isEmpty(iccId)) { // Check if the subscription already existed. - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager - .getSubscriptionInfoInternalByIccId(iccId); + subInfo = mSubscriptionDatabaseManager.getSubscriptionInfoInternalByIccId(iccId); int subId; if (subInfo == null) { // This is a new SIM card. Insert a new record. subId = insertSubscriptionInfo(iccId, phoneId, null, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - logl("updateSubscriptions: Inserted a new subscription. subId=" + subId + logl("updateSubscription: Inserted a new subscription. subId=" + subId + ", phoneId=" + phoneId); } else { subId = subInfo.getSubscriptionId(); - log("updateSubscriptions: Found existing subscription. subId= " + subId + log("updateSubscription: Found existing subscription. subId= " + subId + ", phoneId=" + phoneId); } @@ -1302,7 +1324,7 @@ public class SubscriptionManagerService extends ISub.Stub { mSlotIndexToSubId.put(phoneId, subId); // Update the SIM slot index. This will make the subscription active. mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId); - logl("updateSubscriptions: " + slotMappingToString()); + logl("updateSubscription: current mapping " + slotMappingToString()); } // Update the card id. @@ -1315,11 +1337,7 @@ public class SubscriptionManagerService extends ISub.Stub { } // Update the port index. - UiccSlot slot = mUiccController.getUiccSlotForPhone(phoneId); - if (slot != null && !slot.isEuicc()) { - int portIndex = slot.getPortIndexFromIccId(iccId); - mSubscriptionDatabaseManager.setPortIndex(subId, portIndex); - } + mSubscriptionDatabaseManager.setPortIndex(subId, getPortIndex(iccId)); if (simState == TelephonyManager.SIM_STATE_LOADED) { String mccMnc = mTelephonyManager.getSimOperatorNumeric(subId); @@ -1329,7 +1347,7 @@ public class SubscriptionManagerService extends ISub.Stub { } setMccMnc(subId, mccMnc); } else { - loge("updateSubscriptions: mcc/mnc is empty"); + loge("updateSubscription: mcc/mnc is empty"); } String iso = TelephonyManager.getSimCountryIsoForPhone(phoneId); @@ -1337,7 +1355,7 @@ public class SubscriptionManagerService extends ISub.Stub { if (!TextUtils.isEmpty(iso)) { setCountryIso(subId, iso); } else { - loge("updateSubscriptions: sim country iso is null"); + loge("updateSubscription: sim country iso is null"); } String msisdn = mTelephonyManager.getLine1Number(subId); @@ -1363,10 +1381,10 @@ public class SubscriptionManagerService extends ISub.Stub { mSubscriptionDatabaseManager.setHplmns(subId, hplmns); } } else { - loge("updateSubscriptions: ICC records are not available."); + loge("updateSubscription: ICC records are not available."); } } else { - loge("updateSubscriptions: ICC card is not available."); + loge("updateSubscription: ICC card is not available."); } // Attempt to restore SIM specific settings when SIM is loaded. @@ -1374,12 +1392,16 @@ public class SubscriptionManagerService extends ISub.Stub { SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, iccId, null); + log("Reload the database."); mSubscriptionDatabaseManager.reloadDatabase(); } + + log("updateSubscription: " + mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId)); } else { - log("updateSubscriptions: No ICCID available for phone " + phoneId); + log("updateSubscription: No ICCID available for phone " + phoneId); mSlotIndexToSubId.remove(phoneId); - logl("updateSubscriptions: " + slotMappingToString()); + logl("updateSubscription: current mapping " + slotMappingToString()); } if (areAllSubscriptionsLoaded()) { @@ -1946,7 +1968,7 @@ public class SubscriptionManagerService extends ISub.Stub { int subId = insertSubscriptionInfo(iccId, slotIndex, displayName, subscriptionType); updateGroupDisabled(); mSlotIndexToSubId.put(slotIndex, subId); - logl("addSubInfo: " + slotMappingToString()); + logl("addSubInfo: current mapping " + slotMappingToString()); } else { // Record already exists. loge("Subscription record already existed."); @@ -3741,7 +3763,7 @@ public class SubscriptionManagerService extends ISub.Stub { // active again. (pre-U behavior) mSubscriptionDatabaseManager.setUiccApplicationsEnabled( mSlotIndexToSubId.get(slotIndex), true); - updateSubscriptions(slotIndex); + updateSubscription(slotIndex); } }); } @@ -3773,7 +3795,7 @@ public class SubscriptionManagerService extends ISub.Stub { case TelephonyManager.SIM_STATE_CARD_IO_ERROR: case TelephonyManager.SIM_STATE_LOADED: case TelephonyManager.SIM_STATE_NOT_READY: - updateSubscriptions(slotIndex); + updateSubscription(slotIndex); break; case TelephonyManager.SIM_STATE_CARD_RESTRICTED: default: @@ -3844,9 +3866,9 @@ public class SubscriptionManagerService extends ISub.Stub { */ @NonNull private String slotMappingToString() { - return mSlotIndexToSubId.entrySet().stream() - .map(e -> "Slot " + e.getKey() + ": subId=" + e.getValue()) - .collect(Collectors.joining(", ")); + return "[" + mSlotIndexToSubId.entrySet().stream() + .map(e -> "slot " + e.getKey() + ": subId=" + e.getValue()) + .collect(Collectors.joining(", ")) + "]"; } /** diff --git a/src/java/com/android/internal/telephony/uicc/PinStorage.java b/src/java/com/android/internal/telephony/uicc/PinStorage.java index 87fb4ab295..23769ad32d 100644 --- a/src/java/com/android/internal/telephony/uicc/PinStorage.java +++ b/src/java/com/android/internal/telephony/uicc/PinStorage.java @@ -55,6 +55,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.SimState; import android.util.Base64; +import android.util.IndentingPrintWriter; import android.util.SparseArray; import com.android.internal.R; @@ -1209,16 +1210,18 @@ public class PinStorage extends Handler { Rlog.e(TAG, msg, tr); } - void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("PinStorage:"); - pw.println(" mIsDeviceSecure=" + mIsDeviceSecure); - pw.println(" mIsDeviceLocked=" + mIsDeviceLocked); - pw.println(" isLongTermSecretKey=" + (boolean) (mLongTermSecretKey != null)); - pw.println(" isShortTermSecretKey=" + (boolean) (mShortTermSecretKey != null)); - pw.println(" isCacheAllowedByDevice=" + isCacheAllowedByDevice()); + pw.increaseIndent(); + pw.println("mIsDeviceSecure=" + mIsDeviceSecure); + pw.println("mIsDeviceLocked=" + mIsDeviceLocked); + pw.println("isLongTermSecretKey=" + (boolean) (mLongTermSecretKey != null)); + pw.println("isShortTermSecretKey=" + (boolean) (mShortTermSecretKey != null)); + pw.println("isCacheAllowedByDevice=" + isCacheAllowedByDevice()); int slotCount = getSlotCount(); for (int i = 0; i < slotCount; i++) { - pw.println(" isCacheAllowedByCarrier[" + i + "]=" + isCacheAllowedByCarrier(i)); + pw.println("isCacheAllowedByCarrier[" + i + "]=" + isCacheAllowedByCarrier(i)); } if (VDBG) { SparseArray storedPins = loadPinInformation(); @@ -1226,5 +1229,6 @@ public class PinStorage extends Handler { pw.println(" pin=" + storedPins.valueAt(i).toString()); } } + pw.decreaseIndent(); } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java index 856bc995e5..6ed3a795af 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCard.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java @@ -21,6 +21,7 @@ import android.content.Context; import android.os.Build; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.IndentingPrintWriter; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.uicc.IccCardStatus.CardState; @@ -213,15 +214,20 @@ public class UiccCard { Rlog.e(LOG_TAG, msg); } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("UiccCard:"); - pw.println(" mCardState=" + mCardState); - pw.println(" mCardId=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mCardId)); - pw.println(" mNumberOfPorts=" + mUiccPorts.size()); - pw.println(" mSupportedMepMode=" + mSupportedMepMode); - pw.println(); + pw.increaseIndent(); + pw.println("mCardState=" + mCardState); + pw.println("mCardId=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mCardId)); + pw.println("mNumberOfPorts=" + mUiccPorts.size()); + pw.println("mSupportedMepMode=" + mSupportedMepMode); + pw.println("mUiccPorts= size=" + mUiccPorts.size()); + pw.increaseIndent(); for (UiccPort uiccPort : mUiccPorts.values()) { uiccPort.dump(fd, pw, args); } + pw.decreaseIndent(); + pw.decreaseIndent(); } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java index 9454adef0a..08573b96f1 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java @@ -24,6 +24,7 @@ import android.os.Handler; import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; +import android.util.IndentingPrintWriter; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; @@ -984,40 +985,27 @@ public class UiccCardApplication { Rlog.e(LOG_TAG, msg); } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("UiccCardApplication: " + this); - pw.println(" mUiccProfile=" + mUiccProfile); - pw.println(" mAppState=" + mAppState); - pw.println(" mAppType=" + mAppType); - pw.println(" mPersoSubState=" + mPersoSubState); - pw.println(" mAid=" + mAid); - pw.println(" mAppLabel=" + mAppLabel); - pw.println(" mPin1Replaced=" + mPin1Replaced); - pw.println(" mPin1State=" + mPin1State); - pw.println(" mPin2State=" + mPin2State); - pw.println(" mIccFdnEnabled=" + mIccFdnEnabled); - pw.println(" mDesiredFdnEnabled=" + mDesiredFdnEnabled); - pw.println(" mIccLockEnabled=" + mIccLockEnabled); - pw.println(" mDesiredPinLocked=" + mDesiredPinLocked); - pw.println(" mCi=" + mCi); - pw.println(" mIccRecords=" + mIccRecords); - pw.println(" mIccFh=" + mIccFh); - pw.println(" mDestroyed=" + mDestroyed); - pw.println(" mReadyRegistrants: size=" + mReadyRegistrants.size()); - for (int i = 0; i < mReadyRegistrants.size(); i++) { - pw.println(" mReadyRegistrants[" + i + "]=" - + ((Registrant)mReadyRegistrants.get(i)).getHandler()); - } - pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size()); - for (int i = 0; i < mPinLockedRegistrants.size(); i++) { - pw.println(" mPinLockedRegistrants[" + i + "]=" - + ((Registrant)mPinLockedRegistrants.get(i)).getHandler()); - } - pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size()); - for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) { - pw.println(" mNetworkLockedRegistrants[" + i + "]=" - + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler()); - } + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.println("UiccCardApplication: "); + pw.increaseIndent(); + pw.println("mUiccProfile=" + mUiccProfile); + pw.println("mAppState=" + mAppState); + pw.println("mAppType=" + mAppType); + pw.println("mPersoSubState=" + mPersoSubState); + pw.println("mAid=" + mAid); + pw.println("mAppLabel=" + mAppLabel); + pw.println("mPin1Replaced=" + mPin1Replaced); + pw.println("mPin1State=" + mPin1State); + pw.println("mPin2State=" + mPin2State); + pw.println("mIccFdnEnabled=" + mIccFdnEnabled); + pw.println("mDesiredFdnEnabled=" + mDesiredFdnEnabled); + pw.println("mIccLockEnabled=" + mIccLockEnabled); + pw.println("mDesiredPinLocked=" + mDesiredPinLocked); + pw.println("mIccRecords=" + mIccRecords); + pw.println("mIccFh=" + mIccFh); + pw.println("mDestroyed=" + mDestroyed); + pw.decreaseIndent(); pw.flush(); } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java index 0c88e0baa7..596ccf62bb 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java @@ -28,6 +28,7 @@ import android.os.Message; import android.telephony.TelephonyManager; import android.telephony.UiccAccessRule; import android.text.TextUtils; +import android.util.IndentingPrintWriter; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; @@ -693,16 +694,20 @@ public class UiccCarrierPrivilegeRules extends Handler { /** * Dumps info to Dumpsys - useful for debugging. */ - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("UiccCarrierPrivilegeRules: " + this); - pw.println(" mState=" + getStateString(mState.get())); - pw.println(" mStatusMessage="); + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.println("UiccCarrierPrivilegeRules:"); + pw.increaseIndent(); + pw.println("mState=" + getStateString(mState.get())); + pw.println("mStatusMessage="); mStatusMessage.dump(fd, pw, args); if (mAccessRules != null) { - pw.println(" mAccessRules: "); + pw.println("mAccessRules: "); + pw.increaseIndent(); for (UiccAccessRule ar : mAccessRules) { pw.println(" rule='" + ar + "'"); } + pw.decreaseIndent(); } else { pw.println(" mAccessRules: null"); } @@ -712,6 +717,7 @@ public class UiccCarrierPrivilegeRules extends Handler { } else { pw.println(" mUiccPkcs15: null"); } + pw.decreaseIndent(); pw.flush(); } diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 98c22a5547..93ae88318f 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -34,7 +34,6 @@ import android.os.AsyncResult; import android.os.Build; import android.os.Handler; import android.os.Message; -import android.os.Registrant; import android.os.RegistrantList; import android.preference.PreferenceManager; import android.sysprop.TelephonyProperties; @@ -49,6 +48,7 @@ import android.telephony.UiccPortInfo; import android.telephony.UiccSlotMapping; import android.telephony.data.ApnSetting; import android.text.TextUtils; +import android.util.IndentingPrintWriter; import android.util.LocalLog; import android.util.Log; @@ -1802,35 +1802,32 @@ public class UiccController extends Handler { return mCardStrings; } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("UiccController: " + this); - pw.println(" mContext=" + mContext); - pw.println(" mInstance=" + mInstance); - pw.println(" mIccChangedRegistrants: size=" + mIccChangedRegistrants.size()); - for (int i = 0; i < mIccChangedRegistrants.size(); i++) { - pw.println(" mIccChangedRegistrants[" + i + "]=" - + ((Registrant)mIccChangedRegistrants.get(i)).getHandler()); - } - pw.println(); - pw.flush(); - pw.println(" mIsCdmaSupported=" + isCdmaSupported(mContext)); - pw.println(" mHasBuiltInEuicc=" + mHasBuiltInEuicc); - pw.println(" mHasActiveBuiltInEuicc=" + mHasActiveBuiltInEuicc); - pw.println(" mCardStrings=" + getPrintableCardStrings()); - pw.println(" mDefaultEuiccCardId=" + mDefaultEuiccCardId); - pw.println(" mPhoneIdToSlotId=" + Arrays.toString(mPhoneIdToSlotId)); - pw.println(" mUseRemovableEsimAsDefault=" + mUseRemovableEsimAsDefault); - pw.println(" mUiccSlots: size=" + mUiccSlots.length); + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.println("mIsCdmaSupported=" + isCdmaSupported(mContext)); + pw.println("mHasBuiltInEuicc=" + mHasBuiltInEuicc); + pw.println("mHasActiveBuiltInEuicc=" + mHasActiveBuiltInEuicc); + pw.println("mCardStrings=" + getPrintableCardStrings()); + pw.println("mDefaultEuiccCardId=" + mDefaultEuiccCardId); + pw.println("mPhoneIdToSlotId=" + Arrays.toString(mPhoneIdToSlotId)); + pw.println("mUseRemovableEsimAsDefault=" + mUseRemovableEsimAsDefault); + pw.println("mUiccSlots: size=" + mUiccSlots.length); + pw.increaseIndent(); for (int i = 0; i < mUiccSlots.length; i++) { if (mUiccSlots[i] == null) { - pw.println(" mUiccSlots[" + i + "]=null"); + pw.println("mUiccSlots[" + i + "]=null"); } else { - pw.println(" mUiccSlots[" + i + "]=" + mUiccSlots[i]); + pw.println("mUiccSlots[" + i + "]:"); + pw.increaseIndent(); mUiccSlots[i].dump(fd, pw, args); + pw.decreaseIndent(); } } - pw.println(" sLocalLog= "); - sLocalLog.dump(fd, pw, args); + pw.decreaseIndent(); + pw.println(); + pw.println("sLocalLog= "); + pw.increaseIndent(); mPinStorage.dump(fd, pw, args); + sLocalLog.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 1f22aa1c42..fc33c6ee92 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccPort.java +++ b/src/java/com/android/internal/telephony/uicc/UiccPort.java @@ -22,6 +22,7 @@ import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.telephony.SubscriptionInfo; +import android.util.IndentingPrintWriter; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -358,18 +359,19 @@ public class UiccPort { Rlog.e(LOG_TAG, msg); } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("UiccPort:"); - pw.println(" this=" + this); - pw.println(" mPortIdx=" + mPortIdx); - pw.println(" mCi=" + mCi); - pw.println(" mIccid=" + SubscriptionInfo.givePrintableIccid(mIccid)); - pw.println(" mPhoneId=" + mPhoneId); - pw.println(" mPhysicalSlotIndex=" + mPhysicalSlotIndex); + pw.increaseIndent(); + pw.println("mPortIdx=" + mPortIdx); + pw.println("mCi=" + mCi); + pw.println("mIccid=" + SubscriptionInfo.givePrintableIccid(mIccid)); + pw.println("mPhoneId=" + mPhoneId); + pw.println("mPhysicalSlotIndex=" + mPhysicalSlotIndex); synchronized (mOpenChannelRecords) { - pw.println(" mOpenChannelRecords=" + mOpenChannelRecords); + pw.println("mOpenChannelRecords=" + mOpenChannelRecords); } - pw.println(); + pw.println("mUiccProfile"); if (mUiccProfile != null) { mUiccProfile.dump(fd, pw, args); } diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index e4a9b5c4ba..d2f9b39b21 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -51,6 +51,7 @@ import android.telephony.UiccAccessRule; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.IndentingPrintWriter; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CarrierAppUtils; @@ -1879,27 +1880,29 @@ public class UiccProfile extends IccCard { /** * Dump */ - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("UiccProfile:"); - pw.println(" mCi=" + mCi); - pw.println(" mCatService=" + mCatService); + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.increaseIndent(); + pw.println("mCatService=" + mCatService); for (int i = 0; i < mOperatorBrandOverrideRegistrants.size(); i++) { - pw.println(" mOperatorBrandOverrideRegistrants[" + i + "]=" + pw.println("mOperatorBrandOverrideRegistrants[" + i + "]=" + ((Registrant) mOperatorBrandOverrideRegistrants.get(i)).getHandler()); } - pw.println(" mUniversalPinState=" + mUniversalPinState); - pw.println(" mGsmUmtsSubscriptionAppIndex=" + mGsmUmtsSubscriptionAppIndex); - pw.println(" mCdmaSubscriptionAppIndex=" + mCdmaSubscriptionAppIndex); - pw.println(" mImsSubscriptionAppIndex=" + mImsSubscriptionAppIndex); - pw.println(" mUiccApplications: length=" + mUiccApplications.length); + pw.println("mUniversalPinState=" + mUniversalPinState); + pw.println("mGsmUmtsSubscriptionAppIndex=" + mGsmUmtsSubscriptionAppIndex); + pw.println("mCdmaSubscriptionAppIndex=" + mCdmaSubscriptionAppIndex); + pw.println("mImsSubscriptionAppIndex=" + mImsSubscriptionAppIndex); + pw.println("mUiccApplications: length=" + mUiccApplications.length); + pw.increaseIndent(); for (int i = 0; i < mUiccApplications.length; i++) { if (mUiccApplications[i] == null) { - pw.println(" mUiccApplications[" + i + "]=" + null); + pw.println("mUiccApplications[" + i + "]=" + null); } else { - pw.println(" mUiccApplications[" + i + "]=" + pw.println("mUiccApplications[" + i + "]=" + mUiccApplications[i].getType() + " " + mUiccApplications[i]); } } + pw.decreaseIndent(); pw.println(); // Print details of all applications for (UiccCardApplication app : mUiccApplications) { @@ -1920,28 +1923,31 @@ public class UiccProfile extends IccCard { } // Print UiccCarrierPrivilegeRules and registrants. if (mCarrierPrivilegeRules == null) { - pw.println(" mCarrierPrivilegeRules: null"); + pw.println("mCarrierPrivilegeRules: null"); } else { - pw.println(" mCarrierPrivilegeRules: " + mCarrierPrivilegeRules); + pw.println("mCarrierPrivilegeRules: "); + pw.increaseIndent(); mCarrierPrivilegeRules.dump(fd, pw, args); + pw.decreaseIndent(); } if (mTestOverrideCarrierPrivilegeRules != null) { - pw.println(" mTestOverrideCarrierPrivilegeRules: " + pw.println("mTestOverrideCarrierPrivilegeRules: " + mTestOverrideCarrierPrivilegeRules); mTestOverrideCarrierPrivilegeRules.dump(fd, pw, args); } pw.flush(); - pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size()); + pw.println("mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size()); for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) { pw.println(" mNetworkLockedRegistrants[" + i + "]=" + ((Registrant) mNetworkLockedRegistrants.get(i)).getHandler()); } - pw.println(" mCurrentAppType=" + mCurrentAppType); - pw.println(" mUiccCard=" + mUiccCard); - pw.println(" mUiccApplication=" + mUiccApplication); - pw.println(" mIccRecords=" + mIccRecords); - pw.println(" mExternalState=" + mExternalState); + pw.println("mCurrentAppType=" + mCurrentAppType); + pw.println("mUiccCard=" + mUiccCard); + pw.println("mUiccApplication=" + mUiccApplication); + pw.println("mIccRecords=" + mIccRecords); + pw.println("mExternalState=" + mExternalState); + pw.decreaseIndent(); pw.flush(); } } diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index 94d3fda4b9..d29990811b 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -33,6 +33,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.IndentingPrintWriter; import android.util.Log; import android.view.WindowManager; @@ -673,26 +674,34 @@ public class UiccSlot extends Handler { /** * Dump */ - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("UiccSlot:"); - pw.println(" mActive=" + mActive); - pw.println(" mIsEuicc=" + mIsEuicc); - pw.println(" isEuiccSupportsMultipleEnabledProfiles=" - + isMultipleEnabledProfileSupported()); - pw.println(" mIsRemovable=" + mIsRemovable); - pw.println(" mLastRadioState=" + mLastRadioState); - pw.println(" mIccIds=" + getPrintableIccIds()); - pw.println(" mPortIdxToPhoneId=" + mPortIdxToPhoneId); - pw.println(" mEid=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mEid)); - pw.println(" mCardState=" + mCardState); - pw.println(" mSupportedMepMode=" + mSupportedMepMode); + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.println("mActive=" + mActive); + pw.println("mIsEuicc=" + mIsEuicc); + pw.println("isEuiccSupportsMultipleEnabledProfiles=" + isMultipleEnabledProfileSupported()); + pw.println("mIsRemovable=" + mIsRemovable); + pw.println("mLastRadioState=" + mLastRadioState); + pw.println("mIccIds=" + getPrintableIccIds()); + pw.println("mPortIdxToPhoneId=" + mPortIdxToPhoneId); + pw.println("mEid=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mEid)); + pw.println("mCardState=" + mCardState); + pw.println("mSupportedMepMode=" + mSupportedMepMode); if (mUiccCard != null) { - pw.println(" mUiccCard=" + mUiccCard); + pw.println("mUiccCard="); mUiccCard.dump(fd, pw, args); } else { - pw.println(" mUiccCard=null"); + pw.println("mUiccCard=null"); } pw.println(); pw.flush(); } + + @NonNull + @Override + public String toString() { + return "[UiccSlot: mActive=" + mActive + ", mIccId=" + getPrintableIccIds() + ", mIsEuicc=" + + mIsEuicc + ", MEP=" + isMultipleEnabledProfileSupported() + ", mPortIdxToPhoneId=" + + mPortIdxToPhoneId + ", mEid=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mEid) + + ", mCardState=" + mCardState + " mSupportedMepMode=" + mSupportedMepMode + "]"; + } } diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java index 8dbbe6605b..698fbc834c 100644 --- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java +++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java @@ -16,6 +16,7 @@ package com.android.internal.telephony.uicc.euicc; +import android.annotation.NonNull; import android.content.Context; import android.os.AsyncResult; import android.os.Handler; @@ -23,6 +24,7 @@ import android.os.Registrant; import android.os.RegistrantList; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.IndentingPrintWriter; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; @@ -176,10 +178,14 @@ public class EuiccCard extends UiccCard { } } + @NonNull @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - super.dump(fd, pw, args); + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + super.dump(fd, printWriter, args); + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("EuiccCard:"); - pw.println(" mEid=" + mEid); + pw.increaseIndent(); + pw.println("mEid=" + mEid); + pw.decreaseIndent(); } } diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java index 8dca5f4927..4c86373108 100644 --- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java +++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java @@ -28,6 +28,7 @@ import android.telephony.euicc.EuiccCardManager; import android.telephony.euicc.EuiccNotification; import android.telephony.euicc.EuiccRulesAuthTable; import android.text.TextUtils; +import android.util.IndentingPrintWriter; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; @@ -1423,10 +1424,13 @@ public class EuiccPort extends UiccPort { } @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - super.dump(fd, pw, args); + public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { + super.dump(fd, printWriter, args); + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("EuiccPort:"); - pw.println(" mEid=" + mEid); - pw.println(" mSupportedMepMode=" + mSupportedMepMode); + pw.increaseIndent(); + pw.println("mEid=" + mEid); + pw.println("mSupportedMepMode=" + mSupportedMepMode); + pw.decreaseIndent(); } } 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 16c09faac6..765a62e93e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -16,7 +16,6 @@ package com.android.internal.telephony.subscription; -import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_ID2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CARRIER_NAME1; @@ -92,6 +91,8 @@ import android.util.ArraySet; import android.util.Base64; import com.android.internal.telephony.ContextFixture; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyTest; @@ -114,6 +115,7 @@ import org.mockito.Mockito; import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.StringWriter; +import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; @@ -149,6 +151,14 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { logd("SubscriptionManagerServiceTest +Setup!"); super.setUp(getClass().getSimpleName()); enableSubscriptionManagerService(true); + + // Dual-SIM configuration + mPhones = new Phone[] {mPhone, mPhone2}; + replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); + doReturn(2).when(mTelephonyManager).getActiveModemCount(); + doReturn(2).when(mTelephonyManager).getSupportedModemCount(); + doReturn(mUiccProfile).when(mPhone2).getIccCard(); + mContextFixture.putBooleanResource(com.android.internal.R.bool .config_subscription_database_async_update, true); mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[0]); @@ -182,8 +192,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { }).when(mMockedSubscriptionManagerServiceCallback).invokeFromExecutor(any(Runnable.class)); mSubscriptionManagerServiceUT.registerCallback(mMockedSubscriptionManagerServiceCallback); - // Database loading is on a different thread. Need to wait a bit. - waitForMs(100); processAllFutureMessages(); // Revoke all permissions. @@ -227,7 +235,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { } /** - * Insert the subscription info to the database. + * Insert the subscription info to the database. This is an instant insertion method. For real + * insertion sequence please use {@link #testInsertNewSim()}. * * @param subInfo The subscription to be inserted. * @return The new sub id. @@ -251,9 +260,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { cArgs[0] = Object.class; cArgs[1] = Object.class; - Method method = WatchedMapClass.getDeclaredMethod("put", cArgs); - method.setAccessible(true); - method.invoke(map, subInfo.getSimSlotIndex(), subId); + if (subInfo.getSimSlotIndex() >= 0) { + // Change the slot -> subId mapping + Method method = WatchedMapClass.getDeclaredMethod("put", cArgs); + method.setAccessible(true); + method.invoke(map, subInfo.getSimSlotIndex(), subId); + } + mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(subId)); @@ -261,6 +274,12 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { if (subInfo.getSimSlotIndex() >= 0) { mActiveSubs.add(subId); + + // Change the SIM state + field = SubscriptionManagerService.class.getDeclaredField("mSimState"); + field.setAccessible(true); + Object array = field.get(mSubscriptionManagerServiceUT); + Array.set(array, subInfo.getSimSlotIndex(), TelephonyManager.SIM_STATE_LOADED); } else { mActiveSubs.remove(subId); } @@ -763,6 +782,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(2)); doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1)); doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(2)); + doReturn(TelephonyManager.INVALID_PORT_INDEX).when(mUiccSlot) + .getPortIndexFromIccId(anyString()); mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1, 2), null); processAllMessages(); @@ -771,6 +792,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { .getSubscriptionInfoInternal(1); assertThat(subInfo.getSubscriptionId()).isEqualTo(1); assertThat(subInfo.getSimSlotIndex()).isEqualTo(SubscriptionManager.INVALID_SIM_SLOT_INDEX); + assertThat(subInfo.getPortIndex()).isEqualTo(TelephonyManager.INVALID_PORT_INDEX); assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID1); assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); assertThat(subInfo.getDisplayNameSource()).isEqualTo( @@ -786,6 +808,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { subInfo = mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2); assertThat(subInfo.getSubscriptionId()).isEqualTo(2); assertThat(subInfo.getSimSlotIndex()).isEqualTo(SubscriptionManager.INVALID_SIM_SLOT_INDEX); + assertThat(subInfo.getPortIndex()).isEqualTo(TelephonyManager.INVALID_PORT_INDEX); assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID2); assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_CARRIER_NAME2); assertThat(subInfo.getDisplayNameSource()).isEqualTo( @@ -942,7 +965,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThrows(IllegalArgumentException.class, () -> mSubscriptionManagerServiceUT .getEnabledSubscriptionId(SubscriptionManager.INVALID_SIM_SLOT_INDEX)); - doReturn(2).when(mTelephonyManager).getActiveModemCount(); assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(0)).isEqualTo(1); assertThat(mSubscriptionManagerServiceUT.getEnabledSubscriptionId(1)).isEqualTo( SubscriptionManager.INVALID_SUBSCRIPTION_ID); @@ -1715,6 +1737,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(true).when(mUiccSlot).isEuicc(); doReturn(1).when(mUiccController).convertToPublicCardId(FAKE_ICCID1); doReturn(new UiccSlot[]{mUiccSlot}).when(mUiccController).getUiccSlots(); + doReturn(TelephonyManager.INVALID_PORT_INDEX).when(mUiccSlot) + .getPortIndexFromIccId(anyString()); EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID1) .setIccid(FAKE_ICCID1) @@ -1740,6 +1764,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { .getSubscriptionInfoInternal(1); assertThat(subInfo.getSubscriptionId()).isEqualTo(1); assertThat(subInfo.getSimSlotIndex()).isEqualTo(SubscriptionManager.INVALID_SIM_SLOT_INDEX); + assertThat(subInfo.getPortIndex()).isEqualTo(TelephonyManager.INVALID_PORT_INDEX); assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID1); assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); assertThat(subInfo.getDisplayNameSource()).isEqualTo( @@ -1836,9 +1861,12 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testDeleteEsim() { - // pSIM - insertSubscription(FAKE_SUBSCRIPTION_INFO2); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + // pSIM with ICCID2 + insertSubscription(new SubscriptionInfoInternal.Builder(FAKE_SUBSCRIPTION_INFO2) + .setSimSlotIndex(0).build()); + // eSIM with ICCID1 EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID1) .setIccid(FAKE_ICCID1) .setNickname(FAKE_CARRIER_NAME1) @@ -1857,6 +1885,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); processAllMessages(); + mSubscriptionManagerServiceUT.updateSimState( + 1, TelephonyManager.SIM_STATE_READY, null, null); + + mSubscriptionManagerServiceUT.updateSimState( + 1, TelephonyManager.SIM_STATE_LOADED, null, null); + processAllMessages(); + // Now we should have two subscriptions in the database. One for pSIM, one for eSIM. assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1).isEmbedded()).isFalse(); assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isEmbedded()).isTrue(); @@ -1865,14 +1900,20 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { result = new GetEuiccProfileInfoListResult( EuiccService.RESULT_OK, new EuiccProfileInfo[0], false); doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); + doReturn("").when(mUiccPort).getIccId(); mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); + mSubscriptionManagerServiceUT.updateSimState( + 1, TelephonyManager.SIM_STATE_NOT_READY, null, null); + processAllMessages(); // The original pSIM is still pSIM assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1).isEmbedded()).isFalse(); // The original eSIM becomes removed pSIM ¯\_(ツ)_/¯ assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isEmbedded()).isFalse(); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).getPortIndex()) + .isEqualTo(TelephonyManager.INVALID_PORT_INDEX); } @Test @@ -1914,7 +1955,14 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfoList).hasSize(1); assertThat(subInfoList.get(0).isActive()).isTrue(); + assertThat(subInfoList.get(0).getSubscriptionId()).isEqualTo(2); assertThat(subInfoList.get(0).getIccId()).isEqualTo(FAKE_ICCID2); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo.getSimSlotIndex()).isEqualTo( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + assertThat(subInfo.getPortIndex()).isEqualTo(TelephonyManager.INVALID_PORT_INDEX); } @Test @@ -1965,4 +2013,22 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { processAllMessages(); assertThat(latch.getCount()).isEqualTo(0); } + + @Test + public void testDeactivatePsim() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + testInsertNewSim(); + + mSubscriptionManagerServiceUT.setUiccApplicationsEnabled(false, 1); + mSubscriptionManagerServiceUT.updateSimState( + 0, TelephonyManager.SIM_STATE_NOT_READY, null, null); + + processAllMessages(); + assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty(); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo.isActive()).isFalse(); + assertThat(subInfo.areUiccApplicationsEnabled()).isFalse(); + } } -- GitLab From 892b5f7b9d8bf5700ece15831ba69839397679b4 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 23 Feb 2023 07:58:37 +0000 Subject: [PATCH 463/656] Add onWlanSelected(boolean) and onDomainSelected(int,boolean) If IMS PDN is used for emergency services, don't try to change the preferred transport type of ePDN. Bug: 270333880 Test: atest EmergencyCallDomainSelectionConnectionTest Change-Id: I0af0b840f0251d4958eccb0498571310ce0050be --- .../DomainSelectionConnection.java | 32 ++++++++++++++++--- ...mergencyCallDomainSelectionConnection.java | 23 +++++++------ ...encyCallDomainSelectionConnectionTest.java | 6 ++-- ...rmalCallDomainSelectionConnectionTest.java | 6 ++-- 4 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java index 7f79853e78..9a75b43aa4 100644 --- a/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/DomainSelectionConnection.java @@ -79,8 +79,8 @@ public class DomainSelectionConnection { } @Override - public void onWlanSelected() { - DomainSelectionConnection.this.onWlanSelected(); + public void onWlanSelected(boolean useEmergencyPdn) { + DomainSelectionConnection.this.onWlanSelected(useEmergencyPdn); } @Override @@ -128,8 +128,9 @@ public class DomainSelectionConnection { } @Override - public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) { - DomainSelectionConnection.this.onDomainSelected(domain); + public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain, + boolean useEmergencyPdn) { + DomainSelectionConnection.this.onDomainSelected(domain, useEmergencyPdn); } @Override @@ -286,6 +287,16 @@ public class DomainSelectionConnection { // Can be overridden. } + /** + * Notifies that WLAN transport has been selected. + * + * @param useEmergencyPdn Indicates whether Wi-Fi emergency services use emergency PDN or not. + */ + public void onWlanSelected(boolean useEmergencyPdn) { + // Can be overridden. + onWlanSelected(); + } + /** * Notifies that WWAN transport has been selected. */ @@ -324,6 +335,7 @@ public class DomainSelectionConnection { /** * Notifies the domain selected. + * * @param domain The selected domain. */ public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) { @@ -332,6 +344,18 @@ public class DomainSelectionConnection { future.complete(domain); } + /** + * Notifies the domain selected. + * + * @param domain The selected domain. + * @param useEmergencyPdn Indicates whether emergency services use emergency PDN or not. + */ + public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain, + boolean useEmergencyPdn) { + // Can be overridden if required + onDomainSelected(domain); + } + /** * Notifies that the emergency network scan is canceled. */ diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java index 99105205a3..5808c17e37 100644 --- a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java @@ -84,14 +84,16 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne /** {@inheritDoc} */ @Override - public void onWlanSelected() { + public void onWlanSelected(boolean useEmergencyPdn) { mEmergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WLAN); - AccessNetworksManager anm = mPhone.getAccessNetworksManager(); - int transportType = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); - logi("onWlanSelected curTransportType=" + transportType); - if (transportType != TRANSPORT_TYPE_WLAN) { - changePreferredTransport(TRANSPORT_TYPE_WLAN); - return; + if (useEmergencyPdn) { + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + int transportType = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); + logi("onWlanSelected curTransportType=" + transportType); + if (transportType != TRANSPORT_TYPE_WLAN) { + changePreferredTransport(TRANSPORT_TYPE_WLAN); + return; + } } CompletableFuture future = getCompletableFuture(); @@ -112,8 +114,9 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne /** {@inheritDoc} */ @Override - public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) { - if (domain == DOMAIN_PS) { + public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain, + boolean useEmergencyPdn) { + if (domain == DOMAIN_PS && useEmergencyPdn) { AccessNetworksManager anm = mPhone.getAccessNetworksManager(); int transportType = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); logi("onDomainSelected curTransportType=" + transportType); @@ -122,7 +125,7 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne return; } } - super.onDomainSelected(domain); + super.onDomainSelected(domain, useEmergencyPdn); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java index 4a0f627cd1..e8b0d433f5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java @@ -118,7 +118,7 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { verify(mDomainSelectionController).selectDomain(any(), any()); - mTransportCallback.onWlanSelected(); + mTransportCallback.onWlanSelected(true); assertTrue(future.isDone()); assertEquals((long) DOMAIN_NON_3GPP_PS, (long) future.get()); @@ -156,7 +156,7 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { assertFalse(future.isDone()); verify(mEmergencyStateTracker).onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); - wwanCallback.onDomainSelected(DOMAIN_CS); + wwanCallback.onDomainSelected(DOMAIN_CS, false); assertTrue(future.isDone()); assertEquals((long) DOMAIN_CS, (long) future.get()); @@ -193,7 +193,7 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { assertFalse(future.isDone()); verify(mEmergencyStateTracker).onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); - wwanCallback.onDomainSelected(DOMAIN_PS); + wwanCallback.onDomainSelected(DOMAIN_PS, true); assertTrue(future.isDone()); assertEquals((long) DOMAIN_PS, (long) future.get()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java index 1db2c99918..0403232c4e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/NormalCallDomainSelectionConnectionTest.java @@ -101,7 +101,7 @@ public class NormalCallDomainSelectionConnectionTest extends TelephonyTest { verify(mMockDomainSelectionController).selectDomain(any(), any()); - mTransportCallback.onWlanSelected(); + mTransportCallback.onWlanSelected(false); assertTrue(future.isDone()); assertEquals((long) DOMAIN_PS, (long) future.get()); @@ -126,7 +126,7 @@ public class NormalCallDomainSelectionConnectionTest extends TelephonyTest { WwanSelectorCallback wwanCallback = mTransportCallback.onWwanSelected(); assertFalse(future.isDone()); - wwanCallback.onDomainSelected(DOMAIN_CS); + wwanCallback.onDomainSelected(DOMAIN_CS, false); assertTrue(future.isDone()); assertEquals((long) DOMAIN_CS, (long) future.get()); @@ -151,7 +151,7 @@ public class NormalCallDomainSelectionConnectionTest extends TelephonyTest { WwanSelectorCallback wwanCallback = mTransportCallback.onWwanSelected(); assertFalse(future.isDone()); - wwanCallback.onDomainSelected(DOMAIN_PS); + wwanCallback.onDomainSelected(DOMAIN_PS, false); assertTrue(future.isDone()); assertEquals((long) DOMAIN_PS, (long) future.get()); -- GitLab From a00f910b607ed3acd78a74f8717b4b5d6cb50444 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 23 Feb 2023 23:11:05 -0800 Subject: [PATCH 464/656] Fix isDataEnabledOverriddenForApn Overriden is true if it's been overriden by ANY mobile data policies. Test: voice call + internet browsing Change-Id: I09ea65a7c3616448720afc176a08bb5397d4212d --- .../telephony/data/DataSettingsManager.java | 4 ++-- .../telephony/data/DataNetworkControllerTest.java | 13 ++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index 014c2bbc15..96ec81910c 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -757,7 +757,7 @@ public class DataSettingsManager extends Handler { // mobile data policy : data during call if (isMobileDataPolicyEnabled(TelephonyManager .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL)) { - overridden = isNonDds && mPhone.getState() != PhoneConstants.State.IDLE; + overridden = overridden || isNonDds && mPhone.getState() != PhoneConstants.State.IDLE; } // mobile data policy : auto data switch @@ -776,7 +776,7 @@ public class DataSettingsManager extends Handler { if (defaultDataPhone == null) { loge("isDataEnabledOverriddenForApn: unexpected defaultDataPhone is null"); } else { - overridden = isNonDds && defaultDataPhone.isUserDataEnabled(); + overridden = overridden || isNonDds && defaultDataPhone.isUserDataEnabled(); } } return overridden; 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 f7d80e5ab8..ee62850a4e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -1746,9 +1746,20 @@ public class DataNetworkControllerTest extends TelephonyTest { // Verify internet connection verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); - // Disable auto data switch mobile policy + // Disable auto data switch mobile policy, but enabled data during call mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager .MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, false); + mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager + .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL, true); + doReturn(PhoneConstants.State.RINGING).when(phone2).getState(); + processAllMessages(); + + // Verify internet connection + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_INTERNET); + + // Disable data during call + mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager + .MOBILE_DATA_POLICY_DATA_ON_NON_DEFAULT_DURING_VOICE_CALL, false); processAllMessages(); // Verify no internet connection -- GitLab From 55a9ca6dae07a841c5fab5724cd3c790b5336835 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Fri, 3 Feb 2023 11:31:23 -0600 Subject: [PATCH 465/656] Reset cell broadcast config cache on radio off or sub changed The cell broadcast config may be dropped by modem when radio off or subscription changed. In this case, the cache will be reset to make sure the config will be set again when the api is called by the cell broadcast module. Bug: 266702656 Test: atest com.android.internal.telephony.GsmCdmaPhoneTest Test: manual Change-Id: I241a84aa6f23dcf16e958b6a01e649e6232e4722 --- .../telephony/CellBroadcastConfigTracker.java | 73 ++- .../internal/telephony/GsmCdmaPhone.java | 3 +- .../com/android/internal/telephony/Phone.java | 3 +- .../CellBroadcastConfigTrackerTest.java | 496 ++++++++++++++++++ .../internal/telephony/GsmCdmaPhoneTest.java | 376 ------------- .../internal/telephony/SimulatedCommands.java | 12 +- 6 files changed, 573 insertions(+), 390 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java diff --git a/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java b/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java index 32cfdfeb48..ad1bb8bd6f 100644 --- a/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java +++ b/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java @@ -20,9 +20,11 @@ import android.annotation.NonNull; import android.os.AsyncResult; import android.os.Build; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Message; import android.telephony.CellBroadcastIdRange; import android.telephony.SmsCbMessage; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.internal.annotations.VisibleForTesting; @@ -46,6 +48,8 @@ public final class CellBroadcastConfigTracker extends StateMachine { private static final int EVENT_REQUEST = 1; private static final int EVENT_CONFIGURATION_DONE = 2; private static final int EVENT_ACTIVATION_DONE = 3; + private static final int EVENT_RADIO_OFF = 4; + private static final int EVENT_SUBSCRIPTION_CHANGED = 5; private static final int SMS_CB_CODE_SCHEME_MIN = 0; private static final int SMS_CB_CODE_SCHEME_MAX = 255; @@ -55,7 +59,16 @@ public final class CellBroadcastConfigTracker extends StateMachine { // Cache of current cell broadcast id ranges of 3gpp2 private List mCbRanges3gpp2 = new CopyOnWriteArrayList<>(); private Phone mPhone; - + @VisibleForTesting + public int mSubId; + @VisibleForTesting + public final SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener = + new SubscriptionManager.OnSubscriptionsChangedListener() { + @Override + public void onSubscriptionsChanged() { + sendMessage(EVENT_SUBSCRIPTION_CHANGED); + } + }; /** * The class is to present the request to set cell broadcast id ranges @@ -98,6 +111,40 @@ public final class CellBroadcastConfigTracker extends StateMachine { } } + /** + * The default state. + */ + private class DefaultState extends State { + @Override + public boolean processMessage(Message msg) { + boolean retVal = HANDLED; + if (DBG) { + logd("DefaultState message:" + msg.what); + } + switch (msg.what) { + case EVENT_RADIO_OFF: + resetConfig(); + break; + case EVENT_SUBSCRIPTION_CHANGED: + int subId = mPhone.getSubId(); + if (mSubId != subId) { + log("SubId changed from " + mSubId + " to " + subId); + mSubId = subId; + resetConfig(); + } + break; + default: + log("unexpected message!"); + break; + + } + + return retVal; + } + } + + private DefaultState mDefaultState = new DefaultState(); + /* * The idle state which does not have ongoing radio request. */ @@ -335,12 +382,19 @@ public final class CellBroadcastConfigTracker extends StateMachine { private void init(Phone phone) { logd("init"); mPhone = phone; - - addState(mIdleState); - addState(mGsmConfiguringState); - addState(mGsmActivatingState); - addState(mCdmaConfiguringState); - addState(mCdmaActivatingState); + mSubId = mPhone.getSubId(); + + mPhone.registerForRadioOffOrNotAvailable(getHandler(), EVENT_RADIO_OFF, null); + mPhone.getContext().getSystemService(SubscriptionManager.class) + .addOnSubscriptionsChangedListener(new HandlerExecutor(getHandler()), + mSubChangedListener); + + addState(mDefaultState); + addState(mIdleState, mDefaultState); + addState(mGsmConfiguringState, mDefaultState); + addState(mGsmActivatingState, mDefaultState); + addState(mCdmaConfiguringState, mDefaultState); + addState(mCdmaActivatingState, mDefaultState); setInitialState(mIdleState); } @@ -413,6 +467,11 @@ public final class CellBroadcastConfigTracker extends StateMachine { return newRanges; } + private void resetConfig() { + mCbRanges3gpp.clear(); + mCbRanges3gpp2.clear(); + } + private void setGsmConfig(List ranges, Request request) { if (DBG) { logd("setGsmConfig with " + ranges); diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index a0649aaef5..877709e127 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -247,7 +247,8 @@ public class GsmCdmaPhone extends Phone { private String mVmNumber; private int mImeiType = IMEI_TYPE_UNKNOWN; - CellBroadcastConfigTracker mCellBroadcastConfigTracker = + @VisibleForTesting + public CellBroadcastConfigTracker mCellBroadcastConfigTracker = CellBroadcastConfigTracker.make(this, null); private boolean mIsNullCipherAndIntegritySupported = false; diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 28c0207cb6..dffd848e83 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -183,7 +183,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { protected static final int EVENT_RADIO_ON = 5; protected static final int EVENT_GET_BASEBAND_VERSION_DONE = 6; protected static final int EVENT_USSD = 7; - protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 8; + @VisibleForTesting + public static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 8; private static final int EVENT_GET_SIM_STATUS_DONE = 11; protected static final int EVENT_SET_CALL_FORWARD_DONE = 12; protected static final int EVENT_GET_CALL_FORWARD_DONE = 13; diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java new file mode 100644 index 0000000000..1b3a940559 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java @@ -0,0 +1,496 @@ +/* + * Copyright (C) 2023 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; + +import static com.android.internal.telephony.CellBroadcastConfigTracker.mergeRangesAsNeeded; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.os.AsyncResult; +import android.os.Message; +import android.telephony.CellBroadcastIdRange; +import android.telephony.SmsCbMessage; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; +import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public final class CellBroadcastConfigTrackerTest extends TelephonyTest { + + private CommandsInterface mSpyCi; + private CellBroadcastConfigTracker mTracker; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + mSpyCi = spy(mSimulatedCommands); + mPhone = new GsmCdmaPhone(mContext, mSpyCi, mNotifier, true, 0, + PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager); + mTracker = CellBroadcastConfigTracker.make(mPhone, mPhone); + mPhone.mCellBroadcastConfigTracker = mTracker; + processAllMessages(); + } + + @After + public void tearDown() throws Exception { + mPhone.removeCallbacksAndMessages(null); + mPhone = null; + super.tearDown(); + } + + @Test + public void testSetCellBroadcastIdRangesSuccess() throws Exception { + final int[][] channelValues = { + {0, 999}, {1000, 1003}, {1004, 0x0FFF}, {0x1000, 0x10FF}, {0x1100, 0x112F}, + {0x1130, 0x1900}, {0x1901, 0x9FFF}, {0xA000, 0xFFFE}, {0xFFFF, 0xFFFF}}; + List ranges = new ArrayList<>(); + for (int i = 0; i < channelValues.length; i++) { + ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + SmsCbMessage.MESSAGE_FORMAT_3GPP, i > 0 ? true : false)); + } + + List gsmConfigs = new ArrayList<>(); + gsmConfigs.add(new SmsBroadcastConfigInfo(0, 999, 0, 255, false)); + gsmConfigs.add(new SmsBroadcastConfigInfo(1000, 0xFFFF, 0, 255, true)); + + ArgumentCaptor gsmCaptor = ArgumentCaptor.forClass( + SmsBroadcastConfigInfo[].class); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + + mockCommandInterface(); + + mPhone.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); + processAllMessages(); + + verify(mSpyCi, times(1)).setGsmBroadcastConfig(gsmCaptor.capture(), msgCaptor.capture()); + List gsmArgs = Arrays.asList( + (SmsBroadcastConfigInfo[]) gsmCaptor.getValue()); + assertEquals(gsmConfigs, gsmArgs); + + Message msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(1)).setGsmBroadcastActivation(eq(true), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, never()).setCdmaBroadcastConfig(any(), any()); + verify(mSpyCi, never()).setCdmaBroadcastActivation(anyBoolean(), any()); + + assertEquals(mPhone.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); + + //Verify to set cdma config and activate, but no more for gsm as no change + for (int i = 0; i < channelValues.length; i++) { + ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + SmsCbMessage.MESSAGE_FORMAT_3GPP2, i > 0 ? true : false)); + } + List cdmaConfigs = new ArrayList<>(); + cdmaConfigs.add(new CdmaSmsBroadcastConfigInfo(0, 999, 1, false)); + cdmaConfigs.add(new CdmaSmsBroadcastConfigInfo(1000, 0xFFFF, 1, true)); + ArgumentCaptor cdmaCaptor = ArgumentCaptor.forClass( + CdmaSmsBroadcastConfigInfo[].class); + + mPhone.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); + processAllMessages(); + + verify(mSpyCi, times(1)).setGsmBroadcastConfig(any(), any()); + verify(mSpyCi, times(1)).setCdmaBroadcastConfig(cdmaCaptor.capture(), msgCaptor.capture()); + List cdmaArgs = Arrays.asList( + (CdmaSmsBroadcastConfigInfo[]) cdmaCaptor.getValue()); + assertEquals(cdmaConfigs, cdmaArgs); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(1)).setGsmBroadcastActivation(anyBoolean(), any()); + verify(mSpyCi, times(1)).setCdmaBroadcastActivation(eq(true), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + assertEquals(mPhone.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); + + // Verify not to set cdma or gsm config as the config is not changed + mPhone.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); + processAllMessages(); + + verify(mSpyCi, times(1)).setCdmaBroadcastConfig(any(), any()); + verify(mSpyCi, times(1)).setCdmaBroadcastActivation(anyBoolean(), any()); + verify(mSpyCi, times(1)).setGsmBroadcastConfig(any(), any()); + verify(mSpyCi, times(1)).setGsmBroadcastActivation(anyBoolean(), any()); + + assertEquals(mPhone.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); + + // Verify to reset ranges with empty ranges list + mPhone.setCellBroadcastIdRanges(new ArrayList<>(), r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); + + processAllMessages(); + + verify(mSpyCi, times(2)).setGsmBroadcastConfig(gsmCaptor.capture(), msgCaptor.capture()); + assertEquals(0, ((SmsBroadcastConfigInfo[]) gsmCaptor.getValue()).length); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + // Verify to deavtivate gsm broadcast on empty ranges + verify(mSpyCi, times(1)).setGsmBroadcastActivation(eq(false), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(2)).setCdmaBroadcastConfig(cdmaCaptor.capture(), msgCaptor.capture()); + assertEquals(0, ((CdmaSmsBroadcastConfigInfo[]) cdmaCaptor.getValue()).length); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + // Verify to deavtivate cdma broadcast on empty ranges + verify(mSpyCi, times(1)).setCdmaBroadcastActivation(eq(false), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + assertTrue(mPhone.getCellBroadcastIdRanges().isEmpty()); + + //Verify to set gsm and cdma config then activate again + mPhone.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); + + processAllMessages(); + + verify(mSpyCi, times(3)).setGsmBroadcastConfig(gsmCaptor.capture(), msgCaptor.capture()); + gsmArgs = Arrays.asList((SmsBroadcastConfigInfo[]) gsmCaptor.getValue()); + assertEquals(gsmConfigs, gsmArgs); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(2)).setGsmBroadcastActivation(eq(true), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(3)).setCdmaBroadcastConfig(cdmaCaptor.capture(), msgCaptor.capture()); + cdmaArgs = Arrays.asList((CdmaSmsBroadcastConfigInfo[]) cdmaCaptor.getValue()); + assertEquals(cdmaConfigs, cdmaArgs); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(2)).setCdmaBroadcastActivation(eq(true), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + assertEquals(mPhone.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); + } + + @Test + public void testSetCellBroadcastIdRangesFailure() throws Exception { + List ranges = new ArrayList<>(); + + // Verify to throw exception for invalid ranges + ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); + ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, false)); + + assertThrows(IllegalArgumentException.class, + () -> mPhone.setCellBroadcastIdRanges(ranges, r -> {})); + + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + ranges.clear(); + ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); + ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP2, true)); + + mockCommandInterface(); + + // Verify the result on setGsmBroadcastConfig failure + mPhone.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_CONFIG == r)); + processAllMessages(); + + verify(mSpyCi, times(1)).setGsmBroadcastConfig(any(), msgCaptor.capture()); + + Message msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg).exception = new RuntimeException(); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(0)).setGsmBroadcastActivation(anyBoolean(), any()); + verify(mSpyCi, times(0)).setCdmaBroadcastConfig(any(), any()); + verify(mSpyCi, times(0)).setCdmaBroadcastActivation(anyBoolean(), any()); + assertTrue(mPhone.getCellBroadcastIdRanges().isEmpty()); + + // Verify the result on setGsmBroadcastActivation failure + mPhone.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_ACTIVATION == r)); + processAllMessages(); + + verify(mSpyCi, times(2)).setGsmBroadcastConfig(any(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(1)).setGsmBroadcastActivation(anyBoolean(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg).exception = new RuntimeException(); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(0)).setCdmaBroadcastConfig(any(), any()); + verify(mSpyCi, times(0)).setCdmaBroadcastActivation(anyBoolean(), any()); + assertTrue(mPhone.getCellBroadcastIdRanges().isEmpty()); + + // Verify the result on setCdmaBroadcastConfig failure + mPhone.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_CONFIG == r)); + processAllMessages(); + + verify(mSpyCi, times(3)).setGsmBroadcastConfig(any(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(2)).setGsmBroadcastActivation(anyBoolean(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(1)).setCdmaBroadcastConfig(any(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg).exception = new RuntimeException(); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(0)).setCdmaBroadcastActivation(anyBoolean(), any()); + + List ranges3gpp = new ArrayList<>(); + ranges3gpp.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); + + assertEquals(mPhone.getCellBroadcastIdRanges(), ranges3gpp); + + // Verify the result on setCdmaBroadcastActivation failure + mPhone.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_FAIL_ACTIVATION == r)); + processAllMessages(); + + // Verify no more calls as there is no change of ranges for 3gpp + verify(mSpyCi, times(3)).setGsmBroadcastConfig(any(), any()); + verify(mSpyCi, times(2)).setGsmBroadcastActivation(anyBoolean(), any()); + verify(mSpyCi, times(2)).setCdmaBroadcastConfig(any(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + processAllMessages(); + + verify(mSpyCi, times(1)).setCdmaBroadcastActivation(anyBoolean(), msgCaptor.capture()); + + msg = msgCaptor.getValue(); + assertNotNull(msg); + AsyncResult.forMessage(msg).exception = new RuntimeException(); + msg.sendToTarget(); + processAllMessages(); + + assertEquals(mPhone.getCellBroadcastIdRanges(), ranges3gpp); + } + + @Test + public void testClearCellBroadcastConfigOnRadioOff() { + List ranges = new ArrayList<>(); + ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); + + mPhone.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); + processAllMessages(); + + assertEquals(mPhone.getCellBroadcastIdRanges(), ranges); + + mPhone.sendEmptyMessage(Phone.EVENT_RADIO_OFF_OR_NOT_AVAILABLE); + processAllMessages(); + + // Verify the config is reset + assertTrue(mPhone.getCellBroadcastIdRanges().isEmpty()); + } + + @Test + public void testClearCellBroadcastConfigOnSubscriptionChanged() { + List ranges = new ArrayList<>(); + ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); + + mPhone.setCellBroadcastIdRanges(ranges, r -> assertTrue( + TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); + processAllMessages(); + + assertEquals(mPhone.getCellBroadcastIdRanges(), ranges); + + mTracker.mSubChangedListener.onSubscriptionsChanged(); + processAllMessages(); + + // Verify the config is not reset when the sub id is not changed + assertEquals(mPhone.getCellBroadcastIdRanges(), ranges); + + mTracker.mSubId = mTracker.mSubId % SubscriptionManager.DEFAULT_SUBSCRIPTION_ID + 1; + + mTracker.mSubChangedListener.onSubscriptionsChanged(); + processAllMessages(); + + // Verify the config is reset when the sub id is changed + assertTrue(mPhone.getCellBroadcastIdRanges().isEmpty()); + } + + @Test + public void testMergeCellBroadcastIdRangesAsNeeded() { + final int[][] channelValues = { + {0, 999}, {1000, 1003}, {1004, 0x0FFF}, {0x1000, 0x10FF}, {0x1100, 0x112F}, + {0x1130, 0x1900}, {0x1901, 0x9FFF}, {0xA000, 0xFFFE}, {0xFFFF, 0xFFFF}}; + final int[] typeValues = { + SmsCbMessage.MESSAGE_FORMAT_3GPP, SmsCbMessage.MESSAGE_FORMAT_3GPP2}; + final boolean[] enabledValues = {true, false}; + + List ranges = new ArrayList<>(); + for (int i = 0; i < channelValues.length; i++) { + ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + typeValues[0], enabledValues[0])); + } + + ranges = mergeRangesAsNeeded(ranges); + + assertEquals(1, ranges.size()); + assertEquals(ranges.get(0).getStartId(), channelValues[0][0]); + assertEquals(ranges.get(0).getEndId(), channelValues[channelValues.length - 1][0]); + + // Verify not to merge the ranges with different types. + ranges.clear(); + for (int i = 0; i < channelValues.length; i++) { + ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + typeValues[0], enabledValues[0])); + ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + typeValues[1], enabledValues[0])); + } + + ranges = mergeRangesAsNeeded(ranges); + + assertEquals(2, ranges.size()); + assertEquals(ranges.get(0).getStartId(), channelValues[0][0]); + assertEquals(ranges.get(0).getEndId(), channelValues[channelValues.length - 1][0]); + assertEquals(ranges.get(1).getStartId(), channelValues[0][0]); + assertEquals(ranges.get(1).getEndId(), channelValues[channelValues.length - 1][0]); + assertTrue(ranges.get(0).getType() != ranges.get(1).getType()); + + // Verify to throw IllegalArgumentException if the same range is enabled and disabled + // in the range list. + final List ranges2 = new ArrayList<>(); + for (int i = 0; i < channelValues.length; i++) { + ranges2.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + typeValues[0], enabledValues[0])); + ranges2.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], + typeValues[0], enabledValues[1])); + } + + assertThrows(IllegalArgumentException.class, () -> + mergeRangesAsNeeded(ranges2)); + } + + private void mockCommandInterface() { + doNothing().when(mSpyCi).setGsmBroadcastConfig(any(), any()); + doNothing().when(mSpyCi).setGsmBroadcastActivation(anyBoolean(), any()); + doNothing().when(mSpyCi).setCdmaBroadcastConfig(any(), any()); + doNothing().when(mSpyCi).setCdmaBroadcastActivation(anyBoolean(), any()); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 793e3aa760..493033c490 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -16,7 +16,6 @@ package com.android.internal.telephony; -import static com.android.internal.telephony.CellBroadcastConfigTracker.mergeRangesAsNeeded; import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; import static com.android.internal.telephony.Phone.EVENT_ICC_CHANGED; @@ -33,7 +32,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -70,7 +68,6 @@ import android.provider.DeviceConfig; import android.telecom.VideoProfile; import android.telephony.AccessNetworkConstants; import android.telephony.CarrierConfigManager; -import android.telephony.CellBroadcastIdRange; import android.telephony.CellIdentity; import android.telephony.CellIdentityCdma; import android.telephony.CellIdentityGsm; @@ -78,7 +75,6 @@ import android.telephony.LinkCapacityEstimate; import android.telephony.NetworkRegistrationInfo; import android.telephony.RadioAccessFamily; import android.telephony.ServiceState; -import android.telephony.SmsCbMessage; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.ims.ImsCallProfile; @@ -90,9 +86,7 @@ import android.util.Log; import androidx.test.filters.FlakyTest; -import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; import com.android.internal.telephony.domainselection.DomainSelectionResolver; -import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; @@ -120,7 +114,6 @@ import org.mockito.InOrder; import org.mockito.Mockito; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; @RunWith(AndroidTestingRunner.class) @@ -2428,375 +2421,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { verify(mImsPhone).dial(eq("1234567890"), any(PhoneInternalInterface.DialArgs.class)); } - @Test - @SmallTest - public void testSetCellBroadcastIdRangesSuccess() throws Exception { - final int[][] channelValues = { - {0, 999}, {1000, 1003}, {1004, 0x0FFF}, {0x1000, 0x10FF}, {0x1100, 0x112F}, - {0x1130, 0x1900}, {0x1901, 0x9FFF}, {0xA000, 0xFFFE}, {0xFFFF, 0xFFFF}}; - List ranges = new ArrayList<>(); - for (int i = 0; i < channelValues.length; i++) { - ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], - SmsCbMessage.MESSAGE_FORMAT_3GPP, i > 0 ? true : false)); - } - - List gsmConfigs = new ArrayList<>(); - gsmConfigs.add(new SmsBroadcastConfigInfo(0, 999, 0, 255, false)); - gsmConfigs.add(new SmsBroadcastConfigInfo(1000, 0xFFFF, 0, 255, true)); - - ArgumentCaptor gsmCaptor = ArgumentCaptor.forClass( - SmsBroadcastConfigInfo[].class); - ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); - - mPhoneUT.mCi = mMockCi; - - mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); - waitForMs(100); - - verify(mMockCi, times(1)).setGsmBroadcastConfig(gsmCaptor.capture(), msgCaptor.capture()); - List gsmArgs = Arrays.asList( - (SmsBroadcastConfigInfo[]) gsmCaptor.getValue()); - assertEquals(gsmConfigs, gsmArgs); - - Message msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(1)).setGsmBroadcastActivation(eq(true), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, never()).setCdmaBroadcastConfig(any(), any()); - verify(mMockCi, never()).setCdmaBroadcastActivation(anyBoolean(), any()); - - assertEquals(mPhoneUT.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); - - //Verify to set cdma config and activate, but no more for gsm as no change - for (int i = 0; i < channelValues.length; i++) { - ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], - SmsCbMessage.MESSAGE_FORMAT_3GPP2, i > 0 ? true : false)); - } - List cdmaConfigs = new ArrayList<>(); - cdmaConfigs.add(new CdmaSmsBroadcastConfigInfo(0, 999, 1, false)); - cdmaConfigs.add(new CdmaSmsBroadcastConfigInfo(1000, 0xFFFF, 1, true)); - ArgumentCaptor cdmaCaptor = ArgumentCaptor.forClass( - CdmaSmsBroadcastConfigInfo[].class); - - mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); - waitForMs(100); - - verify(mMockCi, times(1)).setGsmBroadcastConfig(any(), any()); - verify(mMockCi, times(1)).setCdmaBroadcastConfig(cdmaCaptor.capture(), msgCaptor.capture()); - List cdmaArgs = Arrays.asList( - (CdmaSmsBroadcastConfigInfo[]) cdmaCaptor.getValue()); - assertEquals(cdmaConfigs, cdmaArgs); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(1)).setGsmBroadcastActivation(anyBoolean(), any()); - verify(mMockCi, times(1)).setCdmaBroadcastActivation(eq(true), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - assertEquals(mPhoneUT.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); - - // Verify not to set cdma or gsm config as the config is not changed - mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); - waitForMs(100); - - verify(mMockCi, times(1)).setCdmaBroadcastConfig(any(), any()); - verify(mMockCi, times(1)).setCdmaBroadcastActivation(anyBoolean(), any()); - verify(mMockCi, times(1)).setGsmBroadcastConfig(any(), any()); - verify(mMockCi, times(1)).setGsmBroadcastActivation(anyBoolean(), any()); - - assertEquals(mPhoneUT.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); - - // Verify to reset ranges with empty ranges list - mPhoneUT.setCellBroadcastIdRanges(new ArrayList<>(), r -> assertTrue( - TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); - - waitForMs(100); - - verify(mMockCi, times(2)).setGsmBroadcastConfig(gsmCaptor.capture(), msgCaptor.capture()); - assertEquals(0, ((SmsBroadcastConfigInfo[]) gsmCaptor.getValue()).length); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - // Verify to deavtivate gsm broadcast on empty ranges - verify(mMockCi, times(1)).setGsmBroadcastActivation(eq(false), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(2)).setCdmaBroadcastConfig(cdmaCaptor.capture(), msgCaptor.capture()); - assertEquals(0, ((CdmaSmsBroadcastConfigInfo[]) cdmaCaptor.getValue()).length); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - processAllMessages(); - waitForMs(100); - - // Verify to deavtivate cdma broadcast on empty ranges - verify(mMockCi, times(1)).setCdmaBroadcastActivation(eq(false), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - processAllMessages(); - waitForMs(100); - - assertTrue(mPhoneUT.getCellBroadcastIdRanges().isEmpty()); - - //Verify to set gsm and cdma config then activate again - mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELL_BROADCAST_RESULT_SUCCESS == r)); - - waitForMs(100); - - verify(mMockCi, times(3)).setGsmBroadcastConfig(gsmCaptor.capture(), msgCaptor.capture()); - gsmArgs = Arrays.asList((SmsBroadcastConfigInfo[]) gsmCaptor.getValue()); - assertEquals(gsmConfigs, gsmArgs); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(2)).setGsmBroadcastActivation(eq(true), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(3)).setCdmaBroadcastConfig(cdmaCaptor.capture(), msgCaptor.capture()); - cdmaArgs = Arrays.asList((CdmaSmsBroadcastConfigInfo[]) cdmaCaptor.getValue()); - assertEquals(cdmaConfigs, cdmaArgs); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(2)).setCdmaBroadcastActivation(eq(true), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - assertEquals(mPhoneUT.getCellBroadcastIdRanges(), mergeRangesAsNeeded(ranges)); - } - - @Test - @SmallTest - public void testSetCellBroadcastIdRangesFailure() throws Exception { - List ranges = new ArrayList<>(); - - // Verify to throw exception for invalid ranges - ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); - ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, false)); - - assertThrows(IllegalArgumentException.class, - () -> mPhoneUT.setCellBroadcastIdRanges(ranges, r -> {})); - - ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); - ranges.clear(); - ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); - ranges.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP2, true)); - mPhoneUT.mCi = mMockCi; - - // Verify the result on setGsmBroadcastConfig failure - mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELL_BROADCAST_RESULT_FAIL_CONFIG == r)); - waitForMs(100); - - verify(mMockCi, times(1)).setGsmBroadcastConfig(any(), msgCaptor.capture()); - - Message msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg).exception = new RuntimeException(); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(0)).setGsmBroadcastActivation(anyBoolean(), any()); - verify(mMockCi, times(0)).setCdmaBroadcastConfig(any(), any()); - verify(mMockCi, times(0)).setCdmaBroadcastActivation(anyBoolean(), any()); - assertTrue(mPhoneUT.getCellBroadcastIdRanges().isEmpty()); - - // Verify the result on setGsmBroadcastActivation failure - mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELL_BROADCAST_RESULT_FAIL_ACTIVATION == r)); - waitForMs(100); - - verify(mMockCi, times(2)).setGsmBroadcastConfig(any(), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(1)).setGsmBroadcastActivation(anyBoolean(), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg).exception = new RuntimeException(); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(0)).setCdmaBroadcastConfig(any(), any()); - verify(mMockCi, times(0)).setCdmaBroadcastActivation(anyBoolean(), any()); - assertTrue(mPhoneUT.getCellBroadcastIdRanges().isEmpty()); - - // Verify the result on setCdmaBroadcastConfig failure - mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELL_BROADCAST_RESULT_FAIL_CONFIG == r)); - waitForMs(100); - - verify(mMockCi, times(3)).setGsmBroadcastConfig(any(), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(2)).setGsmBroadcastActivation(anyBoolean(), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(1)).setCdmaBroadcastConfig(any(), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg).exception = new RuntimeException(); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(0)).setCdmaBroadcastActivation(anyBoolean(), any()); - - List ranges3gpp = new ArrayList<>(); - ranges3gpp.add(new CellBroadcastIdRange(0, 999, SmsCbMessage.MESSAGE_FORMAT_3GPP, true)); - - assertEquals(mPhoneUT.getCellBroadcastIdRanges(), ranges3gpp); - - // Verify the result on setCdmaBroadcastActivation failure - mPhoneUT.setCellBroadcastIdRanges(ranges, r -> assertTrue( - TelephonyManager.CELL_BROADCAST_RESULT_FAIL_ACTIVATION == r)); - waitForMs(200); - - // Verify no more calls as there is no change of ranges for 3gpp - verify(mMockCi, times(3)).setGsmBroadcastConfig(any(), any()); - verify(mMockCi, times(2)).setGsmBroadcastActivation(anyBoolean(), any()); - verify(mMockCi, times(2)).setCdmaBroadcastConfig(any(), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg); - msg.sendToTarget(); - waitForMs(100); - - verify(mMockCi, times(1)).setCdmaBroadcastActivation(anyBoolean(), msgCaptor.capture()); - - msg = msgCaptor.getValue(); - assertNotNull(msg); - AsyncResult.forMessage(msg).exception = new RuntimeException(); - msg.sendToTarget(); - waitForMs(100); - - assertEquals(mPhoneUT.getCellBroadcastIdRanges(), ranges3gpp); - } - - @Test - @SmallTest - public void testMergeCellBroadcastIdRangesAsNeeded() { - final int[][] channelValues = { - {0, 999}, {1000, 1003}, {1004, 0x0FFF}, {0x1000, 0x10FF}, {0x1100, 0x112F}, - {0x1130, 0x1900}, {0x1901, 0x9FFF}, {0xA000, 0xFFFE}, {0xFFFF, 0xFFFF}}; - final int[] typeValues = { - SmsCbMessage.MESSAGE_FORMAT_3GPP, SmsCbMessage.MESSAGE_FORMAT_3GPP2}; - final boolean[] enabledValues = {true, false}; - - List ranges = new ArrayList<>(); - for (int i = 0; i < channelValues.length; i++) { - ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], - typeValues[0], enabledValues[0])); - } - - ranges = mergeRangesAsNeeded(ranges); - - assertEquals(ranges.size(), 1); - assertEquals(ranges.get(0).getStartId(), channelValues[0][0]); - assertEquals(ranges.get(0).getEndId(), channelValues[channelValues.length - 1][0]); - - // Verify not to merge the ranges with different types. - ranges.clear(); - for (int i = 0; i < channelValues.length; i++) { - ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], - typeValues[0], enabledValues[0])); - ranges.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], - typeValues[1], enabledValues[0])); - } - - ranges = mergeRangesAsNeeded(ranges); - - assertEquals(ranges.size(), 2); - assertEquals(ranges.get(0).getStartId(), channelValues[0][0]); - assertEquals(ranges.get(0).getEndId(), channelValues[channelValues.length - 1][0]); - assertEquals(ranges.get(1).getStartId(), channelValues[0][0]); - assertEquals(ranges.get(1).getEndId(), channelValues[channelValues.length - 1][0]); - assertTrue(ranges.get(0).getType() != ranges.get(1).getType()); - - // Verify to throw IllegalArgumentException if the same range is enabled and disabled - // in the range list. - final List ranges2 = new ArrayList<>(); - for (int i = 0; i < channelValues.length; i++) { - ranges2.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], - typeValues[0], enabledValues[0])); - ranges2.add(new CellBroadcastIdRange(channelValues[i][0], channelValues[i][1], - typeValues[0], enabledValues[1])); - } - - assertThrows(IllegalArgumentException.class, () -> - mergeRangesAsNeeded(ranges2)); - } - @Test public void getImeiType_primary() { Message message = mPhoneUT.obtainMessage(Phone.EVENT_GET_DEVICE_IMEI_DONE); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index 4bc59848f9..bbea09a4ba 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -1921,8 +1921,8 @@ public class SimulatedCommands extends BaseCommands @Override public void setCdmaBroadcastActivation(boolean activate, Message response) { - unimplemented(response); - + SimulatedCommandsVerifier.getInstance().setCdmaBroadcastActivation(activate, response); + resultSuccess(response, null); } @Override @@ -1933,7 +1933,8 @@ public class SimulatedCommands extends BaseCommands @Override public void setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs, Message response) { - unimplemented(response); + SimulatedCommandsVerifier.getInstance().setCdmaBroadcastConfig(configs, response); + resultSuccess(response, null); } public void forceDataDormancy(Message response) { @@ -1943,7 +1944,8 @@ public class SimulatedCommands extends BaseCommands @Override public void setGsmBroadcastActivation(boolean activate, Message response) { - unimplemented(response); + SimulatedCommandsVerifier.getInstance().setGsmBroadcastActivation(activate, response); + resultSuccess(response, null); } @@ -1951,7 +1953,7 @@ public class SimulatedCommands extends BaseCommands public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) { SimulatedCommandsVerifier.getInstance().setGsmBroadcastConfig(config, response); if (mSendSetGsmBroadcastConfigResponse) { - unimplemented(response); + resultSuccess(response, null); } } -- GitLab From c5f03b5979a6a92e0245c97eb7223a61d11c836a Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Fri, 24 Feb 2023 17:27:45 +0000 Subject: [PATCH 466/656] Resolve NPE caused in SatelliteController Bug: 267826133 Test: Basic sanity, making calls and sending SMS Change-Id: I7433aedea14041584782f47e550ceef4ba6b9ac2 --- .../internal/telephony/satellite/SatelliteController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 465e312520..10b0a68fdd 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -196,8 +196,8 @@ public class SatelliteController extends Handler { } } }; - requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - mSatelliteSupportedReceiver); + //requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + // mSatelliteSupportedReceiver); } private void internalInit() { -- GitLab From 85b23e82025bc978730711e34243079e6a0c6f38 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 24 Feb 2023 14:46:02 -0800 Subject: [PATCH 467/656] Fixed phone number showed in bugreport Protected phone numbers with Rlog.pii. Fix: 257116872 Test: Boot up and collect bugreport to check phone number not printed. Change-Id: If99f08732928714eb097c54727ec15462dbbde9d --- .../telephony/subscription/SubscriptionInfoInternal.java | 4 ++-- .../telephony/subscription/SubscriptionManagerService.java | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 0616c144e1..30c0e42733 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -1113,8 +1113,8 @@ public class SubscriptionInfoInternal { + " deviceToDeviceStatusSharingPreference=" + mDeviceToDeviceStatusSharingPreference + " isVoImsOptInEnabled=" + mIsVoImsOptInEnabled + " deviceToDeviceStatusSharingContacts=" + mDeviceToDeviceStatusSharingContacts - + " numberFromCarrier=" + mNumberFromCarrier - + " numberFromIms=" + mNumberFromIms + + " numberFromCarrier=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumberFromCarrier) + + " numberFromIms=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, mNumberFromIms) + " userId=" + mUserId + " isSatelliteEnabled=" + mIsSatelliteEnabled + " isGroupDisabled=" + mIsGroupDisabled diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 6867ed8c60..e181f29507 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -102,6 +102,7 @@ import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.uicc.UiccPort; import com.android.internal.telephony.uicc.UiccSlot; import com.android.internal.telephony.util.ArrayUtils; +import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; import java.io.FileDescriptor; @@ -2155,7 +2156,8 @@ public class SubscriptionManagerService extends ISub.Stub { @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public int setDisplayNumber(@NonNull String number, int subId) { enforcePermissions("setDisplayNumber", Manifest.permission.MODIFY_PHONE_STATE); - logl("setDisplayNumber: subId=" + subId + ", number=" + number + logl("setDisplayNumber: subId=" + subId + ", number=" + + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, number) + ", calling package=" + getCallingPackage()); // Now that all security checks passes, perform the operation as ourselves. final long identity = Binder.clearCallingIdentity(); -- GitLab From 807ffbdcc1f37d44ec07e348995526e284d4521c Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Fri, 24 Feb 2023 15:25:12 -0800 Subject: [PATCH 468/656] Fix hanging telephony tests atest FrameworksTelephonyTests would hang because cleanup wasn't handled properly by some tests. Make sure all classes that extend TelephonyTest also call super.tearDown() in their @After method. Test: atest FrameworksTelephonyTests (results are printed) Bug: 266748137 Change-Id: I26cb2ec15abd2ef392d39be5a03759b36ce293f2 --- .../android/internal/telephony/InboundSmsTrackerTest.java | 3 ++- .../internal/telephony/TelephonyAdminReceiverTest.java | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java index df355ac261..d251cf5f0e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java @@ -57,8 +57,9 @@ public class InboundSmsTrackerTest extends TelephonyTest { } @After - public void tearDown() { + public void tearDown() throws Exception { mInboundSmsTracker = null; + super.tearDown(); } public static MatrixCursor createFakeCursor() { diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyAdminReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyAdminReceiverTest.java index 397c8bab4b..118daa5545 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyAdminReceiverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyAdminReceiverTest.java @@ -29,6 +29,7 @@ import android.os.UserManager; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -44,6 +45,11 @@ public class TelephonyAdminReceiverTest extends TelephonyTest { mTelephonyAdminReceiver = new TelephonyAdminReceiver(mContext, mPhone); } + @After + public void tearDown() throws Exception { + super.tearDown(); + } + @Test public void test_nullUserManager() { mUserManager = null; -- GitLab From a83418ca1b8bc10473ca8fb8ef83a672b95ea0ab Mon Sep 17 00:00:00 2001 From: Sooraj Sasindran Date: Fri, 24 Feb 2023 14:45:04 -0800 Subject: [PATCH 469/656] Update satellite modem transfer states Update satellite modem transfer states to include seperate end state for sending and receiving Bug: 269637555 Test: cts and system boot up Change-Id: I9e741641f4f01fcfc67e8bd452167437473b59ea --- .../telephony/satellite/SatelliteModemInterface.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 8827e67dc2..ecf6cb0ff3 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -45,10 +45,8 @@ import android.util.Pair; import com.android.internal.telephony.ExponentialBackoff; import com.android.internal.telephony.IBooleanConsumer; import com.android.internal.telephony.IIntegerConsumer; -import com.android.internal.telephony.Phone; import java.util.Arrays; -import java.util.function.Consumer; /** * Satellite modem interface to manage connections with the satellite service and HAL interface. @@ -129,8 +127,8 @@ public class SatelliteModemInterface { SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING; break; case SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING: - datagramTransferState = - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RETRYING; + // keep previous state as this could be retrying sending or receiving + break; } // TODO: properly notify the rest of the datagram transfer state changed parameters mDatagramTransferStateChangedRegistrants.notifyResult(datagramTransferState); -- GitLab From 1354f6e852caa7870b61a0f0d42cc647ea14422d Mon Sep 17 00:00:00 2001 From: Hyunho Date: Fri, 24 Feb 2023 10:29:09 +0000 Subject: [PATCH 470/656] Fixed NPE problem in UiccCard Calling getCardId API before setting the UiccPort map results in the NPE problem. When the getCardId API is called, it checks to see if the UiccPort map has a value. Bug: b/270655428 Test: atest UiccCardTest Change-Id: I734d6f4fd9d3d88fb8c91c0a69e8c325c9fc50b6 --- src/java/com/android/internal/telephony/uicc/UiccCard.java | 7 +++++-- .../com/android/internal/telephony/uicc/UiccCardTest.java | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java index 6ed3a795af..960a166c49 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCard.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java @@ -171,8 +171,11 @@ public class UiccCard { if (!TextUtils.isEmpty(mCardId)) { return mCardId; } else { - UiccProfile uiccProfile = mUiccPorts.get(TelephonyManager.DEFAULT_PORT_INDEX) - .getUiccProfile(); + UiccPort uiccPort = mUiccPorts.get(TelephonyManager.DEFAULT_PORT_INDEX); + if (uiccPort == null) { + return null; + } + UiccProfile uiccProfile = uiccPort.getUiccProfile(); return uiccProfile == null ? null : uiccProfile.getIccId(); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java index 951c8d1eef..e4fabc5a71 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java @@ -97,4 +97,10 @@ public class UiccCardTest extends TelephonyTest { assertNull(mUiccCard.getUiccPort(INVALID_PORT_ID)); assertNotNull(mUiccCard.getUiccPort(TelephonyManager.DEFAULT_PORT_INDEX)); } + + @Test + @SmallTest + public void testGetCardId() { + assertNull(mUiccCard.getCardId()); + } } -- GitLab From a6354b20efc59b824bcbd2f64123dfb670f15a43 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Sat, 25 Feb 2023 02:33:00 -0800 Subject: [PATCH 471/656] Update satellite APIs for modem implementation Test: atest SatelliteManagerTest Bug: 270534472 Change-Id: I8e6a7771bbaf1a182940af8fd35392883161bb37 --- .../telephony/SatelliteIndication.java | 8 ++--- .../satellite/SatelliteController.java | 32 ++++++++++++------- .../satellite/SatelliteModemInterface.java | 26 ++++++--------- .../satellite/SatelliteServiceUtils.java | 16 ++-------- 4 files changed, 35 insertions(+), 47 deletions(-) diff --git a/src/java/com/android/internal/telephony/SatelliteIndication.java b/src/java/com/android/internal/telephony/SatelliteIndication.java index 62fc0b43ec..2e561c3dac 100644 --- a/src/java/com/android/internal/telephony/SatelliteIndication.java +++ b/src/java/com/android/internal/telephony/SatelliteIndication.java @@ -80,13 +80,11 @@ public class SatelliteIndication extends IRadioSatelliteIndication.Stub { if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_NEW_SATELLITE_MESSAGES); if (mRil.mNewSatelliteMessagesRegistrants != null) { - SatelliteDatagram[] datagrams = new SatelliteDatagram[messages.length]; for (int i = 0; i < messages.length; i++) { - datagrams[i] = new SatelliteDatagram(messages[i].getBytes()); + SatelliteDatagram datagram = new SatelliteDatagram(messages[i].getBytes()); + mRil.mNewSatelliteMessagesRegistrants.notifyRegistrants( + new AsyncResult(null, new Pair<>(datagram, messages.length - i - 1), null)); } - // TODO: support pendingCount properly - mRil.mNewSatelliteMessagesRegistrants.notifyRegistrants( - new AsyncResult(null, new Pair<>(datagrams, messages.length), null)); } } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 10b0a68fdd..c500de521a 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -218,6 +218,16 @@ public class SatelliteController extends Handler { } } + private static final class RequestSatelliteEnabledArgument { + public boolean enabled; + public @NonNull Consumer callback; + + RequestSatelliteEnabledArgument(boolean enabled, Consumer callback) { + this.enabled = enabled; + this.callback = callback; + } + } + private static final class ProvisionSatelliteServiceArgument { public @NonNull String token; public @NonNull Consumer callback; @@ -687,20 +697,19 @@ public class SatelliteController extends Handler { case CMD_SET_SATELLITE_ENABLED: { request = (SatelliteControllerHandlerRequest) msg.obj; - Pair> argument = - (Pair>) request.argument; + RequestSatelliteEnabledArgument argument = + (RequestSatelliteEnabledArgument) request.argument; onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request); if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface - .requestSatelliteEnabled(argument.first, onCompleted); + mSatelliteModemInterface.requestSatelliteEnabled(argument.enabled, onCompleted); break; } Phone phone = request.phone; if (phone != null) { - phone.setSatellitePower(onCompleted, argument.first); + phone.setSatellitePower(onCompleted, argument.enabled); } else { loge("requestSatelliteEnabled: No phone object"); - argument.second.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); } break; } @@ -708,10 +717,11 @@ public class SatelliteController extends Handler { case EVENT_SET_SATELLITE_ENABLED_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - Pair> argument = - (Pair>) request.argument; + RequestSatelliteEnabledArgument argument = + (RequestSatelliteEnabledArgument) request.argument; int error = getSatelliteError(ar, "setSatelliteEnabled", false); - argument.second.accept(error); + argument.callback.accept(error); + // TODO: if error is ERROR_NONE, request satellite capabilities break; } @@ -1001,8 +1011,8 @@ public class SatelliteController extends Handler { } Phone phone = getPhoneOrDefault(validSubId, "requestSatelliteEnabled"); - Pair> arg = new Pair<>(enable, result); - sendRequestAsync(CMD_SET_SATELLITE_ENABLED, arg, phone); + sendRequestAsync(CMD_SET_SATELLITE_ENABLED, + new RequestSatelliteEnabledArgument(enable, result), phone); } /** diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 8827e67dc2..909c908d8e 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -45,10 +45,8 @@ import android.util.Pair; import com.android.internal.telephony.ExponentialBackoff; import com.android.internal.telephony.IBooleanConsumer; import com.android.internal.telephony.IIntegerConsumer; -import com.android.internal.telephony.Phone; import java.util.Arrays; -import java.util.function.Consumer; /** * Satellite modem interface to manage connections with the satellite service and HAL interface. @@ -93,10 +91,10 @@ public class SatelliteModemInterface { } @Override - public void onSatelliteDatagramsReceived( - android.telephony.satellite.stub.SatelliteDatagram[] datagrams, int pendingCount) { + public void onSatelliteDatagramReceived( + android.telephony.satellite.stub.SatelliteDatagram datagram, int pendingCount) { mSatelliteDatagramsReceivedRegistrants.notifyResult(new Pair<>( - SatelliteServiceUtils.fromSatelliteDatagrams(datagrams), pendingCount)); + SatelliteServiceUtils.fromSatelliteDatagram(datagram), pendingCount)); } @Override @@ -273,16 +271,7 @@ public class SatelliteModemInterface { mSatelliteService = ISatellite.Stub.asInterface(service); mExponentialBackoff.stop(); try { - mSatelliteService.setSatelliteListener(mListener, new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - int error = SatelliteServiceUtils.fromSatelliteError(result); - if (error != SatelliteManager.SATELLITE_ERROR_NONE) { - // TODO: Retry setSatelliteListener - } - logd("setSatelliteListener: " + error); - } - }); + mSatelliteService.setSatelliteListener(mListener); } catch (RemoteException e) { // TODO: Retry setSatelliteListener logd("setSatelliteListener: RemoteException " + e); @@ -463,14 +452,17 @@ public class SatelliteModemInterface { * Listening mode allows the satellite service to listen for incoming pages. * * @param enable True to enable satellite listening mode and false to disable. + * @param timeout How long the satellite modem should wait for the next incoming page before + * disabling listening mode. * @param message The Message to send to result of the operation to. */ - public void requestSatelliteListeningEnabled(boolean enable, @NonNull Message message) { + public void requestSatelliteListeningEnabled(boolean enable, int timeout, + @NonNull Message message) { if (mSatelliteService != null) { try { mSatelliteService.requestSatelliteListeningEnabled( enable, SatelliteController.getInstance().isSatelliteDemoModeEnabled(), - new IIntegerConsumer.Stub() { + timeout, new IIntegerConsumer.Stub() { @Override public void accept(int result) { int error = SatelliteServiceUtils.fromSatelliteError(result); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java index bdf031421c..130fb872b1 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java @@ -128,6 +128,8 @@ public class SatelliteServiceUtils { return SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING; case SatelliteModemState.SATELLITE_MODEM_STATE_OFF: return SatelliteManager.SATELLITE_MODEM_STATE_OFF; + case SatelliteModemState.SATELLITE_MODEM_STATE_UNAVAILABLE: + return SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; default: loge("Received invalid modem state: " + modemState); return SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; @@ -177,20 +179,6 @@ public class SatelliteServiceUtils { return new SatelliteDatagram(data); } - /** - * Convert SatelliteDatagram[] from service definition to framework definition. - * @param datagrams The SatelliteDatagram[] from the satellite service. - * @return The converted SatelliteDatagram[] for the framework. - */ - @Nullable public static SatelliteDatagram[] fromSatelliteDatagrams( - android.telephony.satellite.stub.SatelliteDatagram[] datagrams) { - SatelliteDatagram[] array = new SatelliteDatagram[datagrams.length]; - for (int i = 0; i < datagrams.length; i++) { - array[i] = fromSatelliteDatagram(datagrams[i]); - } - return array; - } - /** * Convert SatelliteDatagram from framework definition to service definition. * @param datagram The SatelliteDatagram from the framework. -- GitLab From f61a4aacabf5b3aab27abffaf56c11672f344791 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Mon, 27 Feb 2023 22:50:18 +0000 Subject: [PATCH 472/656] Do not register event until entering the state Register the event when entering the state, and unregister when exiting the state to avoid the event coming unexpectly due to the timing issue among different threads. Bug: 270912888 Bug: 271009884 Test: manually to kill phone process and check no crash Test: atest com.android.internal.telephony.CellBroadcastConfigTrackerTest Change-Id: I56545895dc5a1ddefce8df607f6d53bfe4696833 --- .../telephony/CellBroadcastConfigTracker.java | 27 +++++++++++++----- .../internal/telephony/GsmCdmaPhone.java | 2 +- .../CellBroadcastConfigTrackerTest.java | 28 ++++++++++++++++++- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java b/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java index ad1bb8bd6f..82d44096a8 100644 --- a/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java +++ b/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java @@ -115,6 +115,21 @@ public final class CellBroadcastConfigTracker extends StateMachine { * The default state. */ private class DefaultState extends State { + @Override + public void enter() { + mPhone.registerForRadioOffOrNotAvailable(getHandler(), EVENT_RADIO_OFF, null); + mPhone.getContext().getSystemService(SubscriptionManager.class) + .addOnSubscriptionsChangedListener(new HandlerExecutor(getHandler()), + mSubChangedListener); + } + + @Override + public void exit() { + mPhone.unregisterForRadioOffOrNotAvailable(getHandler()); + mPhone.getContext().getSystemService(SubscriptionManager.class) + .removeOnSubscriptionsChangedListener(mSubChangedListener); + } + @Override public boolean processMessage(Message msg) { boolean retVal = HANDLED; @@ -384,11 +399,6 @@ public final class CellBroadcastConfigTracker extends StateMachine { mPhone = phone; mSubId = mPhone.getSubId(); - mPhone.registerForRadioOffOrNotAvailable(getHandler(), EVENT_RADIO_OFF, null); - mPhone.getContext().getSystemService(SubscriptionManager.class) - .addOnSubscriptionsChangedListener(new HandlerExecutor(getHandler()), - mSubChangedListener); - addState(mDefaultState); addState(mIdleState, mDefaultState); addState(mGsmConfiguringState, mDefaultState); @@ -401,11 +411,14 @@ public final class CellBroadcastConfigTracker extends StateMachine { /** * create a CellBroadcastConfigTracker instance for the phone */ - public static CellBroadcastConfigTracker make(Phone phone, Handler handler) { + public static CellBroadcastConfigTracker make(Phone phone, Handler handler, + boolean shouldStart) { CellBroadcastConfigTracker tracker = handler == null ? new CellBroadcastConfigTracker(phone) : new CellBroadcastConfigTracker(phone, handler); - tracker.start(); + if (shouldStart) { + tracker.start(); + } return tracker; } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 877709e127..1e02aa8a33 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -249,7 +249,7 @@ public class GsmCdmaPhone extends Phone { @VisibleForTesting public CellBroadcastConfigTracker mCellBroadcastConfigTracker = - CellBroadcastConfigTracker.make(this, null); + CellBroadcastConfigTracker.make(this, null, true); private boolean mIsNullCipherAndIntegritySupported = false; diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java index 1b3a940559..40be490587 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; @@ -66,7 +67,7 @@ public final class CellBroadcastConfigTrackerTest extends TelephonyTest { mSpyCi = spy(mSimulatedCommands); mPhone = new GsmCdmaPhone(mContext, mSpyCi, mNotifier, true, 0, PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager); - mTracker = CellBroadcastConfigTracker.make(mPhone, mPhone); + mTracker = CellBroadcastConfigTracker.make(mPhone, mPhone, true); mPhone.mCellBroadcastConfigTracker = mTracker; processAllMessages(); } @@ -487,6 +488,31 @@ public final class CellBroadcastConfigTrackerTest extends TelephonyTest { mergeRangesAsNeeded(ranges2)); } + @Test + public void testMakeCellBroadcastConfigTracker() { + Phone phone = spy(mPhone); + CellBroadcastConfigTracker tracker = CellBroadcastConfigTracker.make(phone, phone, false); + processAllMessages(); + + verify(phone, never()).registerForRadioOffOrNotAvailable(any(), anyInt(), any()); + verify(mSubscriptionManager, never()).addOnSubscriptionsChangedListener( + any(), eq(tracker.mSubChangedListener)); + + tracker.start(); + processAllMessages(); + + verify(phone, times(1)).registerForRadioOffOrNotAvailable(any(), anyInt(), any()); + verify(mSubscriptionManager, times(1)).addOnSubscriptionsChangedListener( + any(), eq(tracker.mSubChangedListener)); + + tracker = CellBroadcastConfigTracker.make(phone, phone, true); + processAllMessages(); + + verify(phone, times(2)).registerForRadioOffOrNotAvailable(any(), anyInt(), any()); + verify(mSubscriptionManager, times(1)).addOnSubscriptionsChangedListener( + any(), eq(tracker.mSubChangedListener)); + } + private void mockCommandInterface() { doNothing().when(mSpyCi).setGsmBroadcastConfig(any(), any()); doNothing().when(mSpyCi).setGsmBroadcastActivation(anyBoolean(), any()); -- GitLab From 2254430c85509274e1c6820828fdc0ce2d475f00 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Mon, 27 Feb 2023 22:50:18 +0000 Subject: [PATCH 473/656] Do not register event until entering the state Register the event when entering the state, and unregister when exiting the state to avoid the event coming unexpectly due to the timing issue among different threads. Bug: 270912888 Bug: 271009884 Test: manually to kill phone process and check no crash Test: atest com.android.internal.telephony.CellBroadcastConfigTrackerTest Change-Id: I56545895dc5a1ddefce8df607f6d53bfe4696833 (cherry picked from commit f61a4aacabf5b3aab27abffaf56c11672f344791) Merged-In: I56545895dc5a1ddefce8df607f6d53bfe4696833 --- .../telephony/CellBroadcastConfigTracker.java | 27 +++++++++++++----- .../internal/telephony/GsmCdmaPhone.java | 2 +- .../CellBroadcastConfigTrackerTest.java | 28 ++++++++++++++++++- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java b/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java index ad1bb8bd6f..82d44096a8 100644 --- a/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java +++ b/src/java/com/android/internal/telephony/CellBroadcastConfigTracker.java @@ -115,6 +115,21 @@ public final class CellBroadcastConfigTracker extends StateMachine { * The default state. */ private class DefaultState extends State { + @Override + public void enter() { + mPhone.registerForRadioOffOrNotAvailable(getHandler(), EVENT_RADIO_OFF, null); + mPhone.getContext().getSystemService(SubscriptionManager.class) + .addOnSubscriptionsChangedListener(new HandlerExecutor(getHandler()), + mSubChangedListener); + } + + @Override + public void exit() { + mPhone.unregisterForRadioOffOrNotAvailable(getHandler()); + mPhone.getContext().getSystemService(SubscriptionManager.class) + .removeOnSubscriptionsChangedListener(mSubChangedListener); + } + @Override public boolean processMessage(Message msg) { boolean retVal = HANDLED; @@ -384,11 +399,6 @@ public final class CellBroadcastConfigTracker extends StateMachine { mPhone = phone; mSubId = mPhone.getSubId(); - mPhone.registerForRadioOffOrNotAvailable(getHandler(), EVENT_RADIO_OFF, null); - mPhone.getContext().getSystemService(SubscriptionManager.class) - .addOnSubscriptionsChangedListener(new HandlerExecutor(getHandler()), - mSubChangedListener); - addState(mDefaultState); addState(mIdleState, mDefaultState); addState(mGsmConfiguringState, mDefaultState); @@ -401,11 +411,14 @@ public final class CellBroadcastConfigTracker extends StateMachine { /** * create a CellBroadcastConfigTracker instance for the phone */ - public static CellBroadcastConfigTracker make(Phone phone, Handler handler) { + public static CellBroadcastConfigTracker make(Phone phone, Handler handler, + boolean shouldStart) { CellBroadcastConfigTracker tracker = handler == null ? new CellBroadcastConfigTracker(phone) : new CellBroadcastConfigTracker(phone, handler); - tracker.start(); + if (shouldStart) { + tracker.start(); + } return tracker; } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 877709e127..1e02aa8a33 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -249,7 +249,7 @@ public class GsmCdmaPhone extends Phone { @VisibleForTesting public CellBroadcastConfigTracker mCellBroadcastConfigTracker = - CellBroadcastConfigTracker.make(this, null); + CellBroadcastConfigTracker.make(this, null, true); private boolean mIsNullCipherAndIntegritySupported = false; diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java index 1b3a940559..40be490587 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CellBroadcastConfigTrackerTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; @@ -66,7 +67,7 @@ public final class CellBroadcastConfigTrackerTest extends TelephonyTest { mSpyCi = spy(mSimulatedCommands); mPhone = new GsmCdmaPhone(mContext, mSpyCi, mNotifier, true, 0, PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager); - mTracker = CellBroadcastConfigTracker.make(mPhone, mPhone); + mTracker = CellBroadcastConfigTracker.make(mPhone, mPhone, true); mPhone.mCellBroadcastConfigTracker = mTracker; processAllMessages(); } @@ -487,6 +488,31 @@ public final class CellBroadcastConfigTrackerTest extends TelephonyTest { mergeRangesAsNeeded(ranges2)); } + @Test + public void testMakeCellBroadcastConfigTracker() { + Phone phone = spy(mPhone); + CellBroadcastConfigTracker tracker = CellBroadcastConfigTracker.make(phone, phone, false); + processAllMessages(); + + verify(phone, never()).registerForRadioOffOrNotAvailable(any(), anyInt(), any()); + verify(mSubscriptionManager, never()).addOnSubscriptionsChangedListener( + any(), eq(tracker.mSubChangedListener)); + + tracker.start(); + processAllMessages(); + + verify(phone, times(1)).registerForRadioOffOrNotAvailable(any(), anyInt(), any()); + verify(mSubscriptionManager, times(1)).addOnSubscriptionsChangedListener( + any(), eq(tracker.mSubChangedListener)); + + tracker = CellBroadcastConfigTracker.make(phone, phone, true); + processAllMessages(); + + verify(phone, times(2)).registerForRadioOffOrNotAvailable(any(), anyInt(), any()); + verify(mSubscriptionManager, times(1)).addOnSubscriptionsChangedListener( + any(), eq(tracker.mSubChangedListener)); + } + private void mockCommandInterface() { doNothing().when(mSpyCi).setGsmBroadcastConfig(any(), any()); doNothing().when(mSpyCi).setGsmBroadcastActivation(anyBoolean(), any()); -- GitLab From e110a458e4331fa247bc146cab5883ae8328acde Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Thu, 23 Feb 2023 20:44:00 +0000 Subject: [PATCH 474/656] Update SCO messaging pipeline. The following things are moved from SatelliteController to DatagramReciver: - SatelliteDatagramListenerHandler: stores incoming datagrams in DB and deletes from DB after receiving ack. - mDatagramReceiverAck - registerForSatelliteDatagram - unregisterForSatelliteDatagram - pollPendingSatelliteDatagrams The following things are moved from SatelliteController to DatagramDispatcher: - sendSatelliteDatagram: prioritizes sending emergency datagrams over non-emergency datagrams The following methods are moved from SatelliteController to SatelliteServiceUtils: - getSatelliteError() - getPhoneOrDefault() Bug: 269637555 Test: atest SatelliteManagerTest, Basic sanity - flashed build on cheetah-userdebug: making calls and sending sms is working Change-Id: I919b2d603d71015d079a8ed2f61e7158b54cd89a --- .../satellite/DatagramController.java | 79 +++- .../satellite/DatagramDispatcher.java | 236 ++++++++++- .../telephony/satellite/DatagramReceiver.java | 313 ++++++++++++++- .../satellite/SatelliteController.java | 375 +++--------------- .../satellite/SatelliteModemInterface.java | 11 +- .../satellite/SatelliteServiceUtils.java | 54 +++ 6 files changed, 729 insertions(+), 339 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index e4e6eba9ed..9639897e8e 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -17,9 +17,16 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; -import android.os.Looper; +import android.os.Message; +import android.os.ResultReceiver; import android.telephony.Rlog; +import android.telephony.satellite.ISatelliteDatagramCallback; +import android.telephony.satellite.SatelliteDatagram; +import android.telephony.satellite.SatelliteManager; + +import com.android.internal.telephony.Phone; /** * Datagram controller used for sending and receiving satellite datagrams. @@ -70,6 +77,76 @@ public class DatagramController { mDatagramReceiver = DatagramReceiver.make(mContext); } + /** + * Register to receive incoming datagrams over satellite. + * + * @param subId The subId of the subscription to register for incoming satellite datagrams. + * @param datagramType datagram type indicating whether the datagram is of type + * SOS_SMS or LOCATION_SHARING. + * @param callback The callback to handle incoming datagrams over satellite. + * + * @return The {@link SatelliteManager.SatelliteError} result of the operation. + */ + @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId, + @SatelliteManager.DatagramType int datagramType, + @NonNull ISatelliteDatagramCallback callback) { + return mDatagramReceiver.registerForSatelliteDatagram(subId, datagramType, callback); + } + + /** + * Unregister to stop receiving incoming datagrams over satellite. + * If callback was not registered before, the request will be ignored. + * + * @param subId The subId of the subscription to unregister for incoming satellite datagrams. + * @param callback The callback that was passed to + * {@link #registerForSatelliteDatagram(int, int, ISatelliteDatagramCallback)}. + */ + public void unregisterForSatelliteDatagram(int subId, + @NonNull ISatelliteDatagramCallback callback) { + mDatagramReceiver.unregisterForSatelliteDatagram(subId, callback); + } + + /** + * Poll pending satellite datagrams over satellite. + * + * This method requests modem to check if there are any pending datagrams to be received over + * satellite. If there are any incoming datagrams, they will be received via + * {@link android.telephony.satellite.SatelliteDatagramCallback + * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ISatelliteDatagramReceiverAck)} + * + */ + public void pollPendingSatelliteDatagrams(@NonNull Message message, @Nullable Phone phone) { + // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING + mDatagramReceiver.pollPendingSatelliteDatagrams(message, phone); + } + + /** + * Send datagram over satellite. + * + * Gateway encodes SOS message or location sharing message into a datagram and passes it as + * input to this method. Datagram received here will be passed down to modem without any + * encoding or encryption. + * + * @param datagramId An id that uniquely identifies datagram requested to be sent. + * @param datagramType datagram type indicating whether the datagram is of type + * SOS_SMS or LOCATION_SHARING. + * @param datagram encoded gateway datagram which is encrypted by the caller. + * Datagram will be passed down to modem without any encoding or encryption. + * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in + * full screen mode. + * @param isSatelliteDemoModeEnabled True if satellite demo mode is enabled + * @param result The result receiver that returns datagramId if datagram is sent successfully + * or {@link SatelliteManager.SatelliteError} of the request if it is failed. + */ + public void sendSatelliteDatagram(long datagramId, + @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, + boolean needFullScreenPointingUI, boolean isSatelliteDemoModeEnabled, + @NonNull ResultReceiver result) { + // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING + mDatagramDispatcher.sendSatelliteDatagram(datagramId, datagramType, datagram, + needFullScreenPointingUI, isSatelliteDemoModeEnabled, result); + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index d070ca0189..551893feea 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -17,29 +17,56 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; -import android.os.Looper; +import android.os.AsyncResult; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.ResultReceiver; import android.telephony.Rlog; +import android.telephony.satellite.SatelliteDatagram; +import android.telephony.satellite.SatelliteManager; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.telephony.Phone; + +import java.util.LinkedHashMap; +import java.util.Map.Entry; +import java.util.Set; /** * Datagram dispatcher used to send satellite datagrams. */ -public class DatagramDispatcher { +public class DatagramDispatcher extends Handler { private static final String TAG = "DatagramDispatcher"; - @NonNull - private static DatagramDispatcher sInstance; + private static final int CMD_SEND_SATELLITE_DATAGRAM = 1; + private static final int EVENT_SEND_SATELLITE_DATAGRAM_DONE = 2; + + @NonNull private static DatagramDispatcher sInstance; @NonNull private final Context mContext; + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private boolean mSendingDatagramInProgress; + /** - * @return The singleton instance of DatagramDispatcher. + * Map key: datagramId, value: SendSatelliteDatagramArgument to retry sending emergency + * datagrams. */ - public static DatagramDispatcher getInstance() { - if (sInstance == null) { - loge("DatagramDispatcher was not yet initialized."); - } - return sInstance; - } + @GuardedBy("mLock") + private final LinkedHashMap + mPendingEmergencyDatagramsMap = new LinkedHashMap<>(); + + /** + * Map key: datagramId, value: SendSatelliteDatagramArgument to retry sending non-emergency + * datagrams. + */ + @GuardedBy("mLock") + private final LinkedHashMap + mPendingNonEmergencyDatagramsMap = new LinkedHashMap<>(); /** * Create the DatagramDispatcher singleton instance. @@ -59,7 +86,192 @@ public class DatagramDispatcher { * @param context The Context for the DatagramDispatcher. */ private DatagramDispatcher(@NonNull Context context) { + super(context.getMainLooper()); mContext = context; + synchronized (mLock) { + mSendingDatagramInProgress = false; + } + } + + private static final class DatagramDispatcherHandlerRequest { + /** The argument to use for the request */ + public @NonNull Object argument; + /** The caller needs to specify the phone to be used for the request */ + public @NonNull Phone phone; + /** The result of the request that is run on the main thread */ + public @Nullable Object result; + + DatagramDispatcherHandlerRequest(Object argument, Phone phone) { + this.argument = argument; + this.phone = phone; + } + } + + private static final class SendSatelliteDatagramArgument { + public long datagramId; + public @SatelliteManager.DatagramType int datagramType; + public @NonNull SatelliteDatagram datagram; + public boolean needFullScreenPointingUI; + public boolean isSatelliteDemoModeEnabled; + public @NonNull ResultReceiver result; + + SendSatelliteDatagramArgument(long datagramId, + @SatelliteManager.DatagramType int datagramType, + SatelliteDatagram datagram, boolean needFullScreenPointingUI, + boolean isSatelliteDemoModeEnabled, ResultReceiver result) { + this.datagramId = datagramId; + this.datagramType = datagramType; + this.datagram = datagram; + this.needFullScreenPointingUI = needFullScreenPointingUI; + this.isSatelliteDemoModeEnabled = isSatelliteDemoModeEnabled; + this.result = result; + } + } + + @Override + public void handleMessage(Message msg) { + DatagramDispatcherHandlerRequest request; + Message onCompleted; + AsyncResult ar; + + switch(msg.what) { + case CMD_SEND_SATELLITE_DATAGRAM: { + request = (DatagramDispatcherHandlerRequest) msg.obj; + SendSatelliteDatagramArgument argument = + (SendSatelliteDatagramArgument) request.argument; + onCompleted = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request); + if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + SatelliteModemInterface.getInstance().sendSatelliteDatagram(argument.datagram, + argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, + argument.needFullScreenPointingUI, argument.isSatelliteDemoModeEnabled, + onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.sendSatelliteDatagram(onCompleted, argument.datagram, + argument.needFullScreenPointingUI); + } else { + loge("sendSatelliteDatagram: No phone object"); + argument.result.send( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + } + break; + } + + case EVENT_SEND_SATELLITE_DATAGRAM_DONE: { + ar = (AsyncResult) msg.obj; + request = (DatagramDispatcherHandlerRequest) ar.userObj; + int error = SatelliteServiceUtils.getSatelliteError(ar, + "sendSatelliteDatagram", false); + SendSatelliteDatagramArgument argument = + (SendSatelliteDatagramArgument) request.argument; + synchronized (mLock) { + mSendingDatagramInProgress = false; + } + Bundle bundle = new Bundle(); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS + bundle.putLong(SatelliteManager.KEY_SEND_SATELLITE_DATAGRAM, + argument.datagramId); + synchronized (mLock) { + if (argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { + mPendingEmergencyDatagramsMap.remove(argument.datagramId); + } else { + mPendingNonEmergencyDatagramsMap.remove(argument.datagramId); + } + } + sendPendingDatagrams(); + } else { + // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED. + // TODO: send error code for all pending messages + } + argument.result.send(error, bundle); + break; + } + + default: + logw("DatagramDispatcherHandler: unexpected message code: " + msg.what); + break; + } + } + + /** + * Send datagram over satellite. + * + * Gateway encodes SOS message or location sharing message into a datagram and passes it as + * input to this method. Datagram received here will be passed down to modem without any + * encoding or encryption. + * + * @param datagramId An id that uniquely identifies datagram requested to be sent. + * @param datagramType datagram type indicating whether the datagram is of type + * SOS_SMS or LOCATION_SHARING. + * @param datagram encoded gateway datagram which is encrypted by the caller. + * Datagram will be passed down to modem without any encoding or encryption. + * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in + * full screen mode. + * @param isSatelliteDemoModeEnabled True if satellite demo mode is enabled + * @param result The result receiver that returns datagramId if datagram is sent successfully + * or {@link SatelliteManager.SatelliteError} of the request if it is failed. + */ + public void sendSatelliteDatagram(long datagramId, + @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, + boolean needFullScreenPointingUI, boolean isSatelliteDemoModeEnabled, + @NonNull ResultReceiver result) { + Phone phone = SatelliteServiceUtils.getPhone(); + + SendSatelliteDatagramArgument datagramArgs = new SendSatelliteDatagramArgument(datagramId, + datagramType, datagram, needFullScreenPointingUI, isSatelliteDemoModeEnabled, + result); + + synchronized (mLock) { + if (datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { + mPendingEmergencyDatagramsMap.put(datagramId, datagramArgs); + } else { + mPendingNonEmergencyDatagramsMap.put(datagramId, datagramArgs); + } + + if (!mSendingDatagramInProgress) { + mSendingDatagramInProgress = true; + sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArgs, phone); + } + } + } + + /** + * Send pending satellite datagrams. Emergency datagrams are given priority over + * non-emergency datagrams. + */ + private void sendPendingDatagrams() { + Phone phone = SatelliteServiceUtils.getPhone(); + Set> pendingDatagram = null; + synchronized (mLock) { + if (!mSendingDatagramInProgress && !mPendingEmergencyDatagramsMap.isEmpty()) { + pendingDatagram = mPendingEmergencyDatagramsMap.entrySet(); + } else if (!mSendingDatagramInProgress && !mPendingNonEmergencyDatagramsMap.isEmpty()) { + pendingDatagram = mPendingNonEmergencyDatagramsMap.entrySet(); + } + + if ((pendingDatagram != null) && pendingDatagram.iterator().hasNext()) { + mSendingDatagramInProgress = true; + sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, + pendingDatagram.iterator().next().getValue(), phone); + } + } + } + + /** + * Posts the specified command to be executed on the main thread and returns immediately. + * + * @param command command to be executed on the main thread + * @param argument additional parameters required to perform of the operation + * @param phone phone object used to perform the operation. + */ + private void sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone) { + DatagramDispatcherHandlerRequest request = new DatagramDispatcherHandlerRequest( + argument, phone); + Message msg = this.obtainMessage(command, request); + msg.sendToTarget(); } private static void logd(@NonNull String log) { @@ -69,4 +281,6 @@ public class DatagramDispatcher { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } + + private static void logw(@NonNull String log) { Rlog.w(TAG, log); } } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index e8fadf4c07..34587c675c 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -17,9 +17,33 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.content.ContentValues; import android.content.Context; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.net.Uri; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.provider.Telephony; import android.telephony.Rlog; +import android.telephony.satellite.ISatelliteDatagramCallback; +import android.telephony.satellite.ISatelliteDatagramReceiverAck; +import android.telephony.satellite.SatelliteDatagram; +import android.telephony.satellite.SatelliteManager; +import android.util.Pair; + +import com.android.internal.telephony.Phone; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; /** * Datagram receiver used to receive satellite datagrams and then, @@ -27,20 +51,29 @@ import android.telephony.Rlog; */ public class DatagramReceiver { private static final String TAG = "DatagramReceiver"; + /** File used to store shared preferences related to satellite. */ + private static final String SATELLITE_SHARED_PREF = "satellite_shared_pref"; + /** Key used to read/write satellite datagramId in shared preferences. */ + private static final String SATELLITE_DATAGRAM_ID_KEY = "satellite_datagram_id_key"; + + private static final long MAX_DATAGRAM_ID = (long) Math.pow(2, 16); + private static AtomicLong mNextDatagramId = new AtomicLong(0); - @NonNull - private static DatagramReceiver sInstance; + @NonNull private static DatagramReceiver sInstance; @NonNull private final Context mContext; + @NonNull private final ContentResolver mContentResolver; + @NonNull private SharedPreferences mSharedPreferences = null; /** - * @return The singleton instance of DatagramReceiver. + * The background handler to perform database operations. This is running on a separate thread. */ - public static DatagramReceiver getInstance() { - if (sInstance == null) { - loge("DatagramReceiver was not yet initialized."); - } - return sInstance; - } + @NonNull private final Handler mBackgroundHandler; + + /** + * Map key: subId, value: SatelliteDatagramListenerHandler to notify registrants. + */ + private final ConcurrentHashMap + mSatelliteDatagramListenerHandlers = new ConcurrentHashMap<>(); /** * Create the DatagramReceiver singleton instance. @@ -62,6 +95,266 @@ public class DatagramReceiver { */ private DatagramReceiver(@NonNull Context context) { mContext = context; + mContentResolver = context.getContentResolver(); + + HandlerThread backgroundThread = new HandlerThread(TAG); + backgroundThread.start(); + mBackgroundHandler = new Handler(backgroundThread.getLooper()); + try { + mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, + Context.MODE_PRIVATE); + } catch (Exception e) { + loge("Cannot get default shared preferences:" + e); + } + + if ((mSharedPreferences != null) && + (!mSharedPreferences.contains(SATELLITE_DATAGRAM_ID_KEY))) { + mSharedPreferences.edit().putLong(SATELLITE_DATAGRAM_ID_KEY, mNextDatagramId.get()) + .commit(); + } + } + + /** Callback used by datagram receiver app to send ack back to Telephony. */ + private static final ISatelliteDatagramReceiverAck.Stub mDatagramReceiverAck = + new ISatelliteDatagramReceiverAck.Stub() { + /** + * This callback will be used by datagram receiver app to send ack back to + * Telephony. If the callback is not received within five minutes, + * then Telephony will resend the datagram again. + * + * @param datagramId An id that uniquely identifies datagram + * received by satellite datagram receiver app. + * This should match with datagramId passed in + * {@link android.telephony.satellite.SatelliteDatagramCallback + * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, + * ISatelliteDatagramReceiverAck)} + * Upon receiving the ack, Telephony will remove the datagram from + * the persistent memory. + */ + public void acknowledgeSatelliteDatagramReceived(long datagramId) { + // TODO: make this handler non-static + logd("acknowledgeSatelliteDatagramReceived: datagramId=" + datagramId); + sInstance.mBackgroundHandler.post(() -> { + sInstance.deleteDatagram(datagramId); + }); + } + }; + + /** + * Listeners are updated about incoming datagrams using a backgroundThread. + */ + private static final class SatelliteDatagramListenerHandler extends Handler { + public static final int EVENT_SATELLITE_DATAGRAM_RECEIVED = 1; + + @NonNull private final ConcurrentHashMap mListeners; + private final int mSubId; + + SatelliteDatagramListenerHandler(@NonNull Looper looper, int subId) { + super(looper); + mSubId = subId; + mListeners = new ConcurrentHashMap<>(); + } + + public void addListener(ISatelliteDatagramCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatelliteDatagramCallback listener) { + mListeners.remove(listener.asBinder()); + } + + public boolean hasListeners() { + return !mListeners.isEmpty(); + } + + private long getDatagramId() { + long datagramId = 0; + if (sInstance.mSharedPreferences == null) { + try { + // Try to recreate if it is null + sInstance.mSharedPreferences = sInstance.mContext + .getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); + } catch (Exception e) { + loge("Cannot get default shared preferences:" + e); + } + } + + if (sInstance.mSharedPreferences != null) { + long prevDatagramId = sInstance.mSharedPreferences + .getLong(SATELLITE_DATAGRAM_ID_KEY, mNextDatagramId.get()); + datagramId = (prevDatagramId + 1) % MAX_DATAGRAM_ID; + mNextDatagramId.set(datagramId); + sInstance.mSharedPreferences.edit().putLong(SATELLITE_DATAGRAM_ID_KEY, datagramId) + .commit(); + } else { + loge("Shared preferences is null - returning default datagramId"); + datagramId = mNextDatagramId.getAndUpdate(n -> ((n + 1) % MAX_DATAGRAM_ID)); + } + + return datagramId; + } + + private void insertDatagram(long datagramId, SatelliteDatagram datagram) { + ContentValues contentValues = new ContentValues(); + contentValues.put( + Telephony.SatelliteDatagrams.COLUMN_UNIQUE_KEY_DATAGRAM_ID, datagramId); + contentValues.put( + Telephony.SatelliteDatagrams.COLUMN_DATAGRAM, datagram.getSatelliteDatagram()); + Uri uri = sInstance.mContentResolver.insert(Telephony.SatelliteDatagrams.CONTENT_URI, + contentValues); + if (uri == null) { + loge("Cannot insert datagram with datagramId: " + datagramId); + } else { + logd("Inserted datagram with datagramId: " + datagramId); + } + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_SATELLITE_DATAGRAM_RECEIVED: { + AsyncResult ar = (AsyncResult) msg.obj; + Pair result = + (Pair) ar.result; + SatelliteDatagram satelliteDatagram = result.first; + int pendingCount = result.second; + // TODO: update receivePendingCount to listeners using + // onDatagramTransferStateChanged + + long datagramId = getDatagramId(); + insertDatagram(datagramId, satelliteDatagram); + logd("Received EVENT_SATELLITE_DATAGRAM_RECEIVED for subId=" + mSubId); + mListeners.values().forEach(listener -> { + try { + // TODO (b/269637555): wait for ack and retry after 5mins + listener.onSatelliteDatagramReceived( + datagramId, satelliteDatagram, pendingCount, + mDatagramReceiverAck); + } catch (RemoteException e) { + logd("EVENT_SATELLITE_DATAGRAM_RECEIVED RemoteException: " + e); + } + }); + break; + } + default: + loge("SatelliteDatagramListenerHandler unknown event: " + msg.what); + } + } + } + + /** + * Register to receive incoming datagrams over satellite. + * + * @param subId The subId of the subscription to register for incoming satellite datagrams. + * @param datagramType datagram type indicating whether the datagram is of type + * SOS_SMS or LOCATION_SHARING. + * @param callback The callback to handle incoming datagrams over satellite. + * + * @return The {@link SatelliteManager.SatelliteError} result of the operation. + */ + @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId, + @SatelliteManager.DatagramType int datagramType, + @NonNull ISatelliteDatagramCallback callback) { + if (!SatelliteController.getInstance().isSatelliteSupported()) { + return SatelliteManager.SATELLITE_NOT_SUPPORTED; + } + + final int validSubId = SatelliteController.getInstance().getValidSatelliteSubId(subId); + SatelliteDatagramListenerHandler satelliteDatagramListenerHandler = + mSatelliteDatagramListenerHandlers.get(validSubId); + if (satelliteDatagramListenerHandler == null) { + satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler( + mBackgroundHandler.getLooper(), validSubId); + if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + // TODO: remove this as SatelliteModemInterface can register for incoming datagrams + // on boot up itself. + SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived( + satelliteDatagramListenerHandler, + SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null); + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + phone.registerForSatelliteDatagramsReceived(satelliteDatagramListenerHandler, + SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null); + } + } + + satelliteDatagramListenerHandler.addListener(callback); + mSatelliteDatagramListenerHandlers.put(validSubId, satelliteDatagramListenerHandler); + return SatelliteManager.SATELLITE_ERROR_NONE; + } + + /** + * Unregister to stop receiving incoming datagrams over satellite. + * If callback was not registered before, the request will be ignored. + * + * @param subId The subId of the subscription to unregister for incoming satellite datagrams. + * @param callback The callback that was passed to + * {@link #registerForSatelliteDatagram(int, int, ISatelliteDatagramCallback)}. + */ + public void unregisterForSatelliteDatagram(int subId, + @NonNull ISatelliteDatagramCallback callback) { + final int validSubId = SatelliteController.getInstance() + .getValidSatelliteSubId(subId); + SatelliteDatagramListenerHandler handler = + mSatelliteDatagramListenerHandlers.get(validSubId); + if (handler != null) { + handler.removeListener(callback); + + if (!handler.hasListeners()) { + mSatelliteDatagramListenerHandlers.remove(validSubId); + if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + SatelliteModemInterface.getInstance() + .unregisterForSatelliteDatagramsReceived(handler); + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone != null) { + phone.unregisterForSatelliteDatagramsReceived(handler); + } + } + } + } + } + + /** + * Poll pending satellite datagrams over satellite. + * + * This method requests modem to check if there are any pending datagrams to be received over + * satellite. If there are any incoming datagrams, they will be received via + * {@link android.telephony.satellite.SatelliteDatagramCallback + * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ISatelliteDatagramReceiverAck)} + */ + public void pollPendingSatelliteDatagrams(@NonNull Message message, @Nullable Phone phone) { + if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + SatelliteModemInterface.getInstance().pollPendingSatelliteDatagrams(message); + return; + } + + if (phone != null) { + phone.pollPendingSatelliteDatagrams(message); + } else { + loge("pollPendingSatelliteDatagrams: No phone object"); + AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); + message.sendToTarget(); + } + } + + private void deleteDatagram(long datagramId) { + String whereClause = (Telephony.SatelliteDatagrams.COLUMN_UNIQUE_KEY_DATAGRAM_ID + + "=" + datagramId); + Cursor cursor = mContentResolver.query(Telephony.SatelliteDatagrams.CONTENT_URI, + null, whereClause, null, null); + if ((cursor != null) && (cursor.getCount() == 1)) { + int numRowsDeleted = sInstance.mContentResolver.delete( + Telephony.SatelliteDatagrams.CONTENT_URI, whereClause, null); + if (numRowsDeleted == 0) { + loge("Cannot delete datagram with datagramId: " + datagramId); + } else { + logd("Deleted datagram with datagramId: " + datagramId); + } + } else { + loge("Datagram with datagramId: " + datagramId + " is not present in DB."); + } } private static void logd(@NonNull String log) { @@ -71,4 +364,6 @@ public class DatagramReceiver { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } + + // TODO: An api change - do not pass the binder from Telephony to Applications } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index c500de521a..2b6de07d0c 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -33,7 +33,6 @@ import android.os.ResultReceiver; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.satellite.ISatelliteDatagramCallback; -import android.telephony.satellite.ISatelliteDatagramReceiverAck; import android.telephony.satellite.ISatellitePositionUpdateCallback; import android.telephony.satellite.ISatelliteProvisionStateCallback; import android.telephony.satellite.ISatelliteStateCallback; @@ -86,12 +85,10 @@ public class SatelliteController extends Handler { private static final int EVENT_GET_SATELLITE_CAPABILITIES_DONE = 18; private static final int CMD_POLL_PENDING_SATELLITE_DATAGRAMS = 19; private static final int EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE = 20; - private static final int CMD_SEND_SATELLITE_DATAGRAM = 21; - private static final int EVENT_SEND_SATELLITE_DATAGRAM_DONE = 22; - private static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 23; - private static final int EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE = 24; - private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 25; - private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 26; + private static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 21; + private static final int EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE = 22; + private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 23; + private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 24; @NonNull private static SatelliteController sInstance; @NonNull private final Context mContext; @@ -123,16 +120,10 @@ public class SatelliteController extends Handler { private final ConcurrentHashMap mSatelliteStateListenerHandlers = new ConcurrentHashMap<>(); - /** - * Map key: subId, value: SatelliteDatagramListenerHandler to notify registrants. - */ - private final ConcurrentHashMap - mSatelliteDatagramListenerHandlers = new ConcurrentHashMap<>(); - private Boolean mIsSatelliteSupported = null; private final Object mIsSatelliteSupportedLock = new Object(); private final ResultReceiver mSatelliteSupportedReceiver; - private boolean mIsSatelliteDemoModeEnabled = false; + private static boolean mIsSatelliteDemoModeEnabled = false; /** * @return The singleton instance of SatelliteController. @@ -240,26 +231,6 @@ public class SatelliteController extends Handler { } } - private static final class SendSatelliteDatagramArgument { - public long datagramId; - - public @SatelliteManager.DatagramType int datagramType; - public @NonNull SatelliteDatagram datagram; - public boolean needFullScreenPointingUI; - public @NonNull ResultReceiver result; - - SendSatelliteDatagramArgument(long datagramId, - @SatelliteManager.DatagramType int datagramType, - SatelliteDatagram datagram, boolean needFullScreenPointingUI, - ResultReceiver result) { - this.datagramId = datagramId; - this.datagramType = datagramType; - this.datagram = datagram; - this.needFullScreenPointingUI = needFullScreenPointingUI; - this.result = result; - } - } - private static final class SatellitePositionUpdateArgument { public @NonNull Consumer errorCallback; public @NonNull ISatellitePositionUpdateCallback callback; @@ -434,6 +405,13 @@ public class SatelliteController extends Handler { int count = (int) ar.result; logd("Received EVENT_PENDING_DATAGRAM_COUNT for subId=" + mSubId + ", count=" + count); + + if (count == 0) { + // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_RECEIVE_NONE + } else { + // TODO: update receivePendingCount + } + mListeners.values().forEach(listener -> { try { listener.onPendingDatagramCount(count); @@ -449,85 +427,6 @@ public class SatelliteController extends Handler { } } - /** Callback used by datagram receiver app to send ack back to Telephony. */ - private static final ISatelliteDatagramReceiverAck.Stub mDatagramReceiverAck = - new ISatelliteDatagramReceiverAck.Stub() { - /** - * This callback will be used by datagram receiver app to send ack back to - * Telephony. If the callback is not received within five minutes, - * then Telephony will resend the datagram again. - * - * @param datagramId An id that uniquely identifies datagram - * received by satellite datagram receiver app. - * This should match with datagramId passed in - * {@link android.telephony.satellite.SatelliteDatagramCallback - * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, - * ISatelliteDatagramReceiverAck)} - * Upon receiving the ack, Telephony will remove the datagram from - * the persistent memory. - */ - public void acknowledgeSatelliteDatagramReceived(long datagramId) { - // TODO (b/269637555): remove from db. - } - }; - - private static final class SatelliteDatagramListenerHandler extends Handler { - public static final int EVENT_SATELLITE_DATAGRAMS_RECEIVED = 1; - - private final ConcurrentHashMap mListeners; - private final int mSubId; - - SatelliteDatagramListenerHandler(Looper looper, int subId) { - super(looper); - mSubId = subId; - mListeners = new ConcurrentHashMap<>(); - } - - public void addListener(ISatelliteDatagramCallback listener) { - mListeners.put(listener.asBinder(), listener); - } - - public void removeListener(ISatelliteDatagramCallback listener) { - mListeners.remove(listener.asBinder()); - } - - public boolean hasListeners() { - return !mListeners.isEmpty(); - } - - @Override - public void handleMessage(@NonNull Message msg) { - switch (msg.what) { - case EVENT_SATELLITE_DATAGRAMS_RECEIVED: { - AsyncResult ar = (AsyncResult) msg.obj; - Pair result = - (Pair) ar.result; - SatelliteDatagram[] satelliteDatagrams = result.first; - int pendingCount = result.second; - - logd("Received EVENT_SATELLITE_DATAGRAMS_RECEIVED for subId=" + mSubId); - mListeners.values().forEach(listener -> { - try { - for (int i = 0; i < satelliteDatagrams.length; i++) { - // TODO (b/269637555): wait for ack and retry after 5mins - listener.onSatelliteDatagramReceived( - // TODO: create a new datagramId every time - i, satelliteDatagrams[i], pendingCount, - // TODO: create a new instance of ack that will resend - mDatagramReceiverAck); - } - } catch (RemoteException e) { - logd("EVENT_SATELLITE_DATAGRAMS_RECEIVED RemoteException: " + e); - } - }); - break; - } - default: - loge("SatelliteDatagramListenerHandler unknown event: " + msg.what); - } - } - } - @Override public void handleMessage(Message msg) { SatelliteControllerHandlerRequest request; @@ -583,7 +482,8 @@ public class SatelliteController extends Handler { case EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = getSatelliteError(ar, "stopSatellitePositionUpdates", false); + int error = SatelliteServiceUtils.getSatelliteError(ar, + "stopSatellitePositionUpdates", false); ((Consumer) request.argument).accept(error); break; } @@ -611,8 +511,8 @@ public class SatelliteController extends Handler { case EVENT_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = - getSatelliteError(ar, "getMaxCharactersPerSatelliteTextMessage", true); + int error = SatelliteServiceUtils.getSatelliteError(ar, + "getMaxCharactersPerSatelliteTextMessage", true); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { int maxCharLimit = ((int[]) ar.result)[0]; @@ -656,7 +556,8 @@ public class SatelliteController extends Handler { case EVENT_PROVISION_SATELLITE_SERVICE_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int errorCode = getSatelliteError(ar, "provisionSatelliteService", false); + int errorCode = SatelliteServiceUtils.getSatelliteError(ar, + "provisionSatelliteService", false); handleEventProvisionSatelliteServiceDone( (ProvisionSatelliteServiceArgument) request.argument, errorCode); notifyRequester(request); @@ -689,7 +590,8 @@ public class SatelliteController extends Handler { case EVENT_DEPROVISION_SATELLITE_SERVICE_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int errorCode = getSatelliteError(ar, "deprovisionSatelliteService", false); + int errorCode = SatelliteServiceUtils.getSatelliteError(ar, + "deprovisionSatelliteService", false); handleEventDeprovisionSatelliteServiceDone( (ProvisionSatelliteServiceArgument) request.argument, errorCode); break; @@ -719,7 +621,8 @@ public class SatelliteController extends Handler { request = (SatelliteControllerHandlerRequest) ar.userObj; RequestSatelliteEnabledArgument argument = (RequestSatelliteEnabledArgument) request.argument; - int error = getSatelliteError(ar, "setSatelliteEnabled", false); + int error = SatelliteServiceUtils.getSatelliteError(ar, + "setSatelliteEnabled", false); argument.callback.accept(error); // TODO: if error is ERROR_NONE, request satellite capabilities break; @@ -746,7 +649,8 @@ public class SatelliteController extends Handler { case EVENT_IS_SATELLITE_ENABLED_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = getSatelliteError(ar, "isSatelliteEnabled", true); + int error = SatelliteServiceUtils.getSatelliteError(ar, + "isSatelliteEnabled", true); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { boolean enabled = ((int[]) ar.result)[0] == 1; @@ -779,7 +683,8 @@ public class SatelliteController extends Handler { case EVENT_IS_SATELLITE_SUPPORTED_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = getSatelliteError(ar, "isSatelliteSupported", true); + int error = SatelliteServiceUtils.getSatelliteError(ar, + "isSatelliteSupported", true); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { boolean supported = (boolean) ar.result; @@ -818,7 +723,8 @@ public class SatelliteController extends Handler { case EVENT_GET_SATELLITE_CAPABILITIES_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = getSatelliteError(ar, "getSatelliteCapabilities", true); + int error = SatelliteServiceUtils.getSatelliteError(ar, + "getSatelliteCapabilities", true); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { SatelliteCapabilities capabilities = (SatelliteCapabilities) ar.result; @@ -834,68 +740,19 @@ public class SatelliteController extends Handler { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.pollPendingSatelliteDatagrams(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.pollPendingSatelliteDatagrams(onCompleted); - } else { - loge("pollPendingSatelliteDatagrams: No phone object"); - ((Consumer) request.argument).accept( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - } + mDatagramController.pollPendingSatelliteDatagrams(onCompleted, request.phone); break; } case EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = getSatelliteError(ar, "pollPendingSatelliteDatagrams", false); + int error = SatelliteServiceUtils.getSatelliteError(ar, + "pollPendingSatelliteDatagrams", false); ((Consumer) request.argument).accept(error); break; } - case CMD_SEND_SATELLITE_DATAGRAM: { - request = (SatelliteControllerHandlerRequest) msg.obj; - SendSatelliteDatagramArgument argument = - (SendSatelliteDatagramArgument) request.argument; - onCompleted = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.sendSatelliteDatagram( - argument.datagram, - argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, - argument.needFullScreenPointingUI, onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.sendSatelliteDatagram(onCompleted, argument.datagram, - argument.needFullScreenPointingUI); - } else { - loge("sendSatelliteDatagram: No phone object"); - argument.result.send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } - break; - } - - case EVENT_SEND_SATELLITE_DATAGRAM_DONE: { - ar = (AsyncResult) msg.obj; - request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = getSatelliteError(ar, "sendSatelliteDatagram", false); - SendSatelliteDatagramArgument argument = - (SendSatelliteDatagramArgument) request.argument; - Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - bundle.putLong(SatelliteManager.KEY_SEND_SATELLITE_DATAGRAM, - argument.datagramId); - } - argument.result.send(error, bundle); - break; - } - case CMD_IS_SATELLITE_COMMUNICATION_ALLOWED: { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = @@ -920,8 +777,8 @@ public class SatelliteController extends Handler { case EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = getSatelliteError( - ar, "isSatelliteCommunicationAllowedForCurrentLocation", true); + int error = SatelliteServiceUtils.getSatelliteError(ar, + "isSatelliteCommunicationAllowedForCurrentLocation", true); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { boolean communicationAllowed = (boolean) ar.result; @@ -959,8 +816,8 @@ public class SatelliteController extends Handler { case EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = - getSatelliteError(ar, "requestTimeForNextSatelliteVisibility", true); + int error = SatelliteServiceUtils.getSatelliteError(ar, + "requestTimeForNextSatelliteVisibility", true); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { int nextVisibilityDuration = ((int[]) ar.result)[0]; @@ -1010,7 +867,7 @@ public class SatelliteController extends Handler { return; } - Phone phone = getPhoneOrDefault(validSubId, "requestSatelliteEnabled"); + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_SET_SATELLITE_ENABLED, new RequestSatelliteEnabledArgument(enable, result), phone); } @@ -1034,7 +891,7 @@ public class SatelliteController extends Handler { return; } - Phone phone = getPhoneOrDefault(validSubId, "requestIsSatelliteEnabled"); + Phone phone = SatelliteServiceUtils.getPhone(); sendRequest(CMD_IS_SATELLITE_ENABLED, result, phone); } @@ -1107,7 +964,7 @@ public class SatelliteController extends Handler { } final int validSubId = getValidSatelliteSubId(subId); - Phone phone = getPhoneOrDefault(validSubId, "requestIsSatelliteSupported"); + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, phone); } @@ -1125,7 +982,7 @@ public class SatelliteController extends Handler { } final int validSubId = getValidSatelliteSubId(subId); - Phone phone = getPhoneOrDefault(validSubId, "requestSatelliteCapabilities"); + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, phone); } @@ -1152,7 +1009,7 @@ public class SatelliteController extends Handler { return; } - Phone phone = getPhoneOrDefault(validSubId, "startSatellitePositionUpdates"); + Phone phone = SatelliteServiceUtils.getPhone(); SatellitePositionUpdateHandler handler = mSatellitePositionUpdateHandlers.get(validSubId); if (handler != null) { handler.addListener(callback); @@ -1200,7 +1057,7 @@ public class SatelliteController extends Handler { return; } - Phone phone = getPhoneOrDefault(validSubId, "stopSatellitePositionUpdates"); + Phone phone = SatelliteServiceUtils.getPhone(); SatellitePositionUpdateHandler handler = mSatellitePositionUpdateHandlers.get(validSubId); if (handler != null) { handler.removeListener(callback); @@ -1260,7 +1117,7 @@ public class SatelliteController extends Handler { return; } - Phone phone = getPhoneOrDefault(validSubId, "requestMaxSizePerSendingDatagram"); + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG, result, phone); } @@ -1285,7 +1142,7 @@ public class SatelliteController extends Handler { } final int validSubId = getValidSatelliteSubId(subId); - Phone phone = getPhoneOrDefault(validSubId, "provisionSatelliteService"); + Phone phone = SatelliteServiceUtils.getPhone(); if (mSatelliteProvisionCallbacks.containsKey(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS); @@ -1334,7 +1191,7 @@ public class SatelliteController extends Handler { return; } - Phone phone = getPhoneOrDefault(validSubId, "deprovisionSatelliteService"); + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, result, validSubId), phone); } @@ -1402,8 +1259,7 @@ public class SatelliteController extends Handler { @SatelliteManager.SatelliteError public int registerForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { final int validSubId = getValidSatelliteSubId(subId); - Phone phone = getPhoneOrDefault( - validSubId, "registerForSatelliteModemStateChanged"); + Phone phone = SatelliteServiceUtils.getPhone(); SatelliteStateListenerHandler satelliteStateListenerHandler = mSatelliteStateListenerHandlers.get(validSubId); @@ -1450,8 +1306,7 @@ public class SatelliteController extends Handler { mSatelliteModemInterface.unregisterForSatelliteModemStateChanged(handler); mSatelliteModemInterface.unregisterForPendingDatagramCount(handler); } else { - Phone phone = getPhoneOrDefault( - validSubId, "unregisterForSatelliteModemStateChanged"); + Phone phone = SatelliteServiceUtils.getPhone(); if (phone != null) { phone.unregisterForSatelliteModemStateChanged(handler); phone.unregisterForPendingDatagramCount(handler); @@ -1474,31 +1329,7 @@ public class SatelliteController extends Handler { @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, @NonNull ISatelliteDatagramCallback callback) { - if (!isSatelliteSupported()) { - return SatelliteManager.SATELLITE_NOT_SUPPORTED; - } - - final int validSubId = getValidSatelliteSubId(subId); - Phone phone = getPhoneOrDefault(validSubId, "registerForSatelliteDatagram"); - - SatelliteDatagramListenerHandler satelliteDatagramListenerHandler = - mSatelliteDatagramListenerHandlers.get(validSubId); - if (satelliteDatagramListenerHandler == null) { - satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler( - Looper.getMainLooper(), validSubId); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.registerForSatelliteDatagramsReceived( - satelliteDatagramListenerHandler, - SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAMS_RECEIVED, null); - } else { - phone.registerForSatelliteDatagramsReceived(satelliteDatagramListenerHandler, - SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAMS_RECEIVED, null); - } - } - - satelliteDatagramListenerHandler.addListener(callback); - mSatelliteDatagramListenerHandlers.put(validSubId, satelliteDatagramListenerHandler); - return SatelliteManager.SATELLITE_ERROR_NONE; + return mDatagramController.registerForSatelliteDatagram(subId, datagramType, callback); } /** @@ -1511,25 +1342,7 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback) { - final int validSubId = getValidSatelliteSubId(subId); - SatelliteDatagramListenerHandler handler = - mSatelliteDatagramListenerHandlers.get(validSubId); - if (handler != null) { - handler.removeListener(callback); - - if (!handler.hasListeners()) { - mSatelliteDatagramListenerHandlers.remove(validSubId); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.unregisterForSatelliteDatagramsReceived(handler); - } else { - Phone phone = getPhoneOrDefault(validSubId, - "unregisterForSatelliteDatagram"); - if (phone != null) { - phone.unregisterForSatelliteDatagramsReceived(handler); - } - } - } - } + mDatagramController.unregisterForSatelliteDatagram(subId, callback); } /** @@ -1552,8 +1365,9 @@ public class SatelliteController extends Handler { return; } - Phone phone = getPhoneOrDefault(validSubId, "pollPendingSatelliteDatagrams"); + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, result, phone); + // TODO: return pending datagram count } /** @@ -1583,11 +1397,9 @@ public class SatelliteController extends Handler { return; } - Phone phone = getPhoneOrDefault(validSubId, "sendSatelliteDatagram"); // TODO: check if we need to start PointingUI. - sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, - new SendSatelliteDatagramArgument(datagramId, datagramType, datagram, - needFullScreenPointingUI, result), phone); + mDatagramController.sendSatelliteDatagram(datagramId, datagramType, datagram, + needFullScreenPointingUI, mIsSatelliteDemoModeEnabled, result); } /** @@ -1612,8 +1424,7 @@ public class SatelliteController extends Handler { return; } - Phone phone = getPhoneOrDefault(validSubId, - "requestIsSatelliteCommunicationAllowedForCurrentLocation"); + Phone phone = SatelliteServiceUtils.getPhone(); sendRequest(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, phone); } @@ -1636,7 +1447,7 @@ public class SatelliteController extends Handler { return; } - Phone phone = getPhoneOrDefault(validSubId, "requestTimeForNextSatelliteVisibility"); + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); } private void handleEventProvisionSatelliteServiceDone( @@ -1665,10 +1476,6 @@ public class SatelliteController extends Handler { registerForSatelliteProvisionStateChangedInternal(arg.subId, null); } - public boolean isSatelliteDemoModeEnabled() { - return mIsSatelliteDemoModeEnabled; - } - private void handleEventDeprovisionSatelliteServiceDone( @NonNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteError int result) { @@ -1703,7 +1510,7 @@ public class SatelliteController extends Handler { } final int validSubId = getValidSatelliteSubId(subId); - Phone phone = getPhoneOrDefault(validSubId, "registerForSatelliteProvisionStateChanged"); + Phone phone = SatelliteServiceUtils.getPhone(); SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = mSatelliteProvisionStateChangedHandlers.get(validSubId); @@ -1732,8 +1539,8 @@ public class SatelliteController extends Handler { private void handleStartSatellitePositionUpdatesDone(@NonNull AsyncResult ar) { SatelliteControllerHandlerRequest request = (SatelliteControllerHandlerRequest) ar.userObj; SatellitePositionUpdateArgument arg = (SatellitePositionUpdateArgument) request.argument; - int errorCode = getSatelliteError( - ar, "handleStartSatellitePositionUpdatesDone", false); + int errorCode = SatelliteServiceUtils.getSatelliteError(ar, + "handleStartSatellitePositionUpdatesDone", false); arg.errorCallback.accept(errorCode); if (errorCode != SatelliteManager.SATELLITE_ERROR_NONE) { @@ -1791,7 +1598,7 @@ public class SatelliteController extends Handler { * If we have not successfully queried the satellite modem for its satellite service support, * we will retry the query one more time. Otherwise, we will return the queried result. */ - private boolean isSatelliteSupported() { + public boolean isSatelliteSupported() { synchronized (mIsSatelliteSupportedLock) { if (mIsSatelliteSupported != null) { /* We have already successfully queried the satellite modem. */ @@ -1853,41 +1660,14 @@ public class SatelliteController extends Handler { return request.result; } - /** - * Return phone associated with this subscription or default phone. - * - * @param subId The subscription id. - * @param caller caller name to include in the error message. - * @return phone associated with this subscription or default phone. - */ - private Phone getPhoneOrDefault(int subId, String caller) { - Phone phone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId)); - if (phone == null) { - loge(caller + " called with invalid subId: " + subId - + ". Retrying with default subscription."); - phone = PhoneFactory.getPhone(SubscriptionManager - .getPhoneId(PhoneFactory.getDefaultSubscription())); - } - - if (phone == null) { - loge(caller + " called with invalid default subId: " + subId - + ". Retrying with default phone."); - phone = PhoneFactory.getDefaultPhone(); - } - - if (phone == null) { - loge(caller + " failed with no phone object."); - } - return phone; - } - /** * Get valid subscription id for satellite communication. * * @param subId The subscription id. * @return input subId if the subscription is active else return default subscription id. */ - private int getValidSatelliteSubId(int subId) { + public int getValidSatelliteSubId(int subId) { + // TODO: move this method to SatelliteServiceUtils final long identity = Binder.clearCallingIdentity(); try { boolean isActive; @@ -1909,45 +1689,12 @@ public class SatelliteController extends Handler { return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; } - /** - * Get the {@link SatelliteManager.SatelliteError} from the provided result. - * - * @param ar AsyncResult used to determine the error code. - * @param caller The satellite request. - * @param checkResult Whether to check if the result exists. - * - * @return The {@link SatelliteManager.SatelliteError} error code from the request. - */ - @SatelliteManager.SatelliteError private int getSatelliteError(@NonNull AsyncResult ar, - @NonNull String caller, boolean checkResult) { - int errorCode; - if (ar.exception == null) { - errorCode = SatelliteManager.SATELLITE_ERROR_NONE; - if (checkResult && ar.result == null) { - loge(caller + ": result is null"); - errorCode = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } - } else { - errorCode = SatelliteManager.SATELLITE_ERROR; - if (ar.exception instanceof CommandException) { - CommandException.Error error = - ((CommandException) (ar.exception)).getCommandError(); - errorCode = RILUtils.convertToSatelliteError(error); - loge(caller + " CommandException: " + ar.exception); - } else { - loge(caller + " unknown exception: " + ar.exception); - } - } - logd(caller + " error: " + errorCode); - return errorCode; - } - /** * Check if satellite is provisioned for a subscription on the device. * @param subId The subscription id. * @return true if satellite is provisioned on the given subscription else return false. */ - private boolean isSatelliteProvisioned(int subId) { + public boolean isSatelliteProvisioned(int subId) { final long identity = Binder.clearCallingIdentity(); try { if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 6b7fc10941..91f720cf70 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -454,14 +454,15 @@ public class SatelliteModemInterface { * @param enable True to enable satellite listening mode and false to disable. * @param timeout How long the satellite modem should wait for the next incoming page before * disabling listening mode. + * @param isSatelliteDemoModeEnabled True if satellite demo mode is enabled * @param message The Message to send to result of the operation to. */ public void requestSatelliteListeningEnabled(boolean enable, int timeout, - @NonNull Message message) { + boolean isSatelliteDemoModeEnabled, @NonNull Message message) { if (mSatelliteService != null) { try { mSatelliteService.requestSatelliteListeningEnabled( - enable, SatelliteController.getInstance().isSatelliteDemoModeEnabled(), + enable, isSatelliteDemoModeEnabled, timeout, new IIntegerConsumer.Stub() { @Override public void accept(int result) { @@ -848,15 +849,17 @@ public class SatelliteModemInterface { * @param isEmergency Whether this is an emergency datagram. * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in * full screen mode. + * @param isSatelliteDemoModeEnabled True if satellite demo mode is enabled * @param message The Message to send to result of the operation to. */ public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency, - boolean needFullScreenPointingUI, @NonNull Message message) { + boolean needFullScreenPointingUI, boolean isSatelliteDemoModeEnabled, + @NonNull Message message) { if (mSatelliteService != null) { try { mSatelliteService.sendSatelliteDatagram( SatelliteServiceUtils.toSatelliteDatagram(datagram), - SatelliteController.getInstance().isSatelliteDemoModeEnabled(), isEmergency, + isSatelliteDemoModeEnabled, isEmergency, new IIntegerConsumer.Stub() { @Override public void accept(int result) { diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java index 130fb872b1..6e45300f6e 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java @@ -18,7 +18,9 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.AsyncResult; import android.telephony.Rlog; +import android.telephony.SubscriptionManager; import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; @@ -27,6 +29,11 @@ import android.telephony.satellite.stub.NTRadioTechnology; import android.telephony.satellite.stub.SatelliteError; import android.telephony.satellite.stub.SatelliteModemState; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.RILUtils; + import java.util.Arrays; import java.util.stream.Collectors; @@ -192,6 +199,53 @@ public class SatelliteServiceUtils { return converted; } + /** + * Get the {@link SatelliteManager.SatelliteError} from the provided result. + * + * @param ar AsyncResult used to determine the error code. + * @param caller The satellite request. + * @param checkResult Whether to check if the result exists. + * + * @return The {@link SatelliteManager.SatelliteError} error code from the request. + */ + @SatelliteManager.SatelliteError public static int getSatelliteError(@NonNull AsyncResult ar, + @NonNull String caller, boolean checkResult) { + int errorCode; + if (ar.exception == null) { + errorCode = SatelliteManager.SATELLITE_ERROR_NONE; + if (checkResult && ar.result == null) { + // TODO: Move this out of this method. + loge(caller + ": result is null"); + errorCode = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } + } else { + errorCode = SatelliteManager.SATELLITE_ERROR; + if (ar.exception instanceof CommandException) { + CommandException.Error error = + ((CommandException) (ar.exception)).getCommandError(); + errorCode = RILUtils.convertToSatelliteError(error); + loge(caller + " CommandException: " + ar.exception); + } else { + loge(caller + " unknown exception: " + ar.exception); + } + } + logd(caller + " error: " + errorCode); + return errorCode; + } + + /** + * Return phone associated with phoneId 0. + * + * @return phone associated with phoneId 0 or {@code null} if it doesn't exist. + */ + public static @Nullable Phone getPhone() { + return PhoneFactory.getPhone(0); + } + + private static void logd(@NonNull String log) { + Rlog.d(TAG, log); + } + private static void loge(@NonNull String log) { Rlog.e(TAG, log); } -- GitLab From 259e249819c734a053ab94882cdb21c154cdf61a Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Fri, 24 Feb 2023 03:43:00 +0000 Subject: [PATCH 475/656] Moving APIs to PointingAppController Moving Pointing related Apis and Handlers to PointingAppController Bug: b/268467786 Test: atest SatelliteManagerTest, Basic sanity - flashed build on panther-userdebug: making calls and sending sms is working Change-Id: Idcbce1de4193cf3f7da8c72e28eebf2dcb071d67 --- .../satellite/PointingAppController.java | 231 +++++++++++++++++- .../satellite/SatelliteController.java | 206 +++------------- 2 files changed, 268 insertions(+), 169 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java index a255b9fbe9..94fcde0ee9 100644 --- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -17,9 +17,25 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; +import android.content.Intent; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.IBinder; import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; import android.telephony.Rlog; +import android.telephony.satellite.ISatellitePositionUpdateCallback; +import android.telephony.satellite.PointingInfo; +import android.telephony.satellite.SatelliteManager; +import android.text.TextUtils; + +import com.android.internal.telephony.Phone; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; /** * PointingApp controller to manage interactions with PointingUI app. @@ -30,6 +46,13 @@ public class PointingAppController { @NonNull private static PointingAppController sInstance; @NonNull private final Context mContext; + private boolean mStartedSatellitePositionUpdates; + + /** + * Map key: subId, value: SatellitePositionUpdateHandler to notify registrants. + */ + private final ConcurrentHashMap + mSatellitePositionUpdateHandlers = new ConcurrentHashMap<>(); /** * @return The singleton instance of PointingAppController. @@ -60,6 +83,211 @@ public class PointingAppController { */ private PointingAppController(@NonNull Context context) { mContext = context; + mStartedSatellitePositionUpdates = false; + } + + /** + * set the flag mStartedSatellitePositionUpdates to true or false based on the state of + * position updates + * @param startedSatellitePositionUpdates boolean to set the flag + */ + public void setStartedSatellitePositionUpdates(boolean startedSatellitePositionUpdates) { + mStartedSatellitePositionUpdates = startedSatellitePositionUpdates; + } + + private static final class SatellitePositionUpdateHandler extends Handler { + public static final int EVENT_POSITION_INFO_CHANGED = 1; + public static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 2; + + private final ConcurrentHashMap mListeners; + SatellitePositionUpdateHandler(Looper looper) { + super(looper); + mListeners = new ConcurrentHashMap<>(); + } + + public void addListener(ISatellitePositionUpdateCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatellitePositionUpdateCallback listener) { + mListeners.remove(listener.asBinder()); + } + + public boolean hasListeners() { + return !mListeners.isEmpty(); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_POSITION_INFO_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + PointingInfo pointingInfo = (PointingInfo) ar.result; + mListeners.values().forEach(listener -> { + try { + listener.onSatellitePositionChanged(pointingInfo); + } catch (RemoteException e) { + logd("EVENT_POSITION_INFO_CHANGED RemoteException: " + e); + } + }); + break; + } + case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + int result = (int) ar.result; + mListeners.values().forEach(listener -> { + try { + // TODO: process and return the rest of the values correctly + listener.onDatagramTransferStateChanged(result, 0, 0, 0); + } catch (RemoteException e) { + logd("EVENT_DATAGRAM_TRANSFER_STATE_CHANGED RemoteException: " + e); + } + }); + break; + } + default: + loge("SatellitePositionUpdateHandler unknown event: " + msg.what); + } + } + } + + /** + * register to start receiving Updates on Satellite Position and Datagram transfer state + * @param subId The subId of the subscription to register for receiving the updates. + * @param callback The callback to notify of changes in satellite position. + * @param phone The Phone Object to unregister for receiving the updates + */ + public void registerForSatellitePositionUpdates(int subId, + ISatellitePositionUpdateCallback callback, Phone phone) { + SatellitePositionUpdateHandler handler = mSatellitePositionUpdateHandlers.get(subId); + if (handler != null) { + handler.addListener(callback); + return; + } else { + handler = new SatellitePositionUpdateHandler(Looper.getMainLooper()); + handler.addListener(callback); + mSatellitePositionUpdateHandlers.put(subId, handler); + if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged( + handler, SatellitePositionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + /** + * TODO: Need to remove this call, Datagram transfer state should come from the + * DatagramController based upon Transfer state. + * Modem won't be able to provide this info + */ + SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged( + handler, + SatellitePositionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, null); + } else { + phone.registerForSatellitePositionInfoChanged(handler, + SatellitePositionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + // TODO: registerForDatagramTransferStateChanged through SatelliteController + } + } + } + + /** + * Unregister to stop receiving Updates on Satellite Position and Datagram transfer state + * If the callback was not registered before, it is ignored + * @param subId The subId of the subscription to unregister for receiving the updates. + * @param result The callback to get the error code in case of failure + * @param callback The callback that was passed to + * * {@link registerForSatellitePositionUpdateEvents} + * @param phone The Phone Object to unregister for receiving the updates + */ + public void unregisterForSatellitePositionUpdates(int subId, Consumer result, + ISatellitePositionUpdateCallback callback, Phone phone) { + SatellitePositionUpdateHandler handler = mSatellitePositionUpdateHandlers.get(subId); + if (handler != null) { + handler.removeListener(callback); + + if (handler.hasListeners()) { + /** + * TODO (b/269194948): If the calling apps crash, the handler will always have some + * listener. That is, we will not request modem to stop position update and + * cleaning our resources. We need to monitor the calling apps and clean up the + * resources when the apps die. We need to do this for other satellite callbacks + * as well. + */ + result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + return; + } + + mSatellitePositionUpdateHandlers.remove(subId); + if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + SatelliteModemInterface.getInstance().unregisterForSatellitePositionInfoChanged( + handler); + SatelliteModemInterface.getInstance().unregisterForDatagramTransferStateChanged( + handler); + } else { + if (phone == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + phone.unregisterForSatellitePositionInfoChanged(handler); + // TODO: unregisterForDatagramTransferStateChanged through SatelliteController + } + } + } + + /** + * Start receiving satellite position updates. + * This can be called by the pointing UI when the user starts pointing to the satellite. + * Modem should continue to report the pointing input as the device or satellite moves. + * The Position updates will be received via + * {@link android.telephony.satellite.SatellitePositionUpdateCallback#onSatellitePositionChanged( + * pointingInfo)} + */ + public void startSatellitePositionUpdates(@NonNull Message message, @Nullable Phone phone) { + if (mStartedSatellitePositionUpdates) { + logd("startSatellitePositionUpdates: already started"); + return; + } + if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + SatelliteModemInterface.getInstance().startSendingSatellitePointingInfo(message); + mStartedSatellitePositionUpdates = true; + return; + } + if (phone != null) { + phone.startSatellitePositionUpdates(message); + mStartedSatellitePositionUpdates = true; + } else { + loge("startSatellitePositionUpdates: No phone object"); + AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); + message.sendToTarget(); + } + } + + /** + * Stop receiving satellite position updates. + * This can be called by the pointing UI when the user stops pointing to the satellite. + */ + public void stopSatellitePositionUpdates(@NonNull Message message, @Nullable Phone phone) { + if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + SatelliteModemInterface.getInstance().stopSendingSatellitePointingInfo(message); + return; + } + if (phone != null) { + phone.stopSatellitePositionUpdates(message); + } else { + loge("startSatellitePositionUpdates: No phone object"); + AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); + message.sendToTarget(); + } + } + + /** + * Check if Pointing is needed and Launch Pointing UI + * @param needFullScreenPointingUI if pointing UI has to be launchd with Full screen + */ + public void startPointingUI(boolean needFullScreenPointingUI) { + String packageName = TextUtils.emptyIfNull(mContext.getResources() + .getString(com.android.internal.R.string.config_pointing_ui_package)); + Intent launchIntent = mContext.getPackageManager().getLaunchIntentForPackage(packageName); + launchIntent.putExtra("needFullScreen", needFullScreenPointingUI); + mContext.startActivity(launchIntent); } private static void logd(@NonNull String log) { @@ -69,11 +297,8 @@ public class PointingAppController { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } - /** * TODO: The following needs to be added in this class: - * - SatellitePositionUpdateHandler - * - startPointingUI * - check if pointingUI crashes - then restart it */ } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 2b6de07d0c..6e90efd14f 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -36,7 +36,6 @@ import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.ISatellitePositionUpdateCallback; import android.telephony.satellite.ISatelliteProvisionStateCallback; import android.telephony.satellite.ISatelliteStateCallback; -import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; @@ -65,6 +64,7 @@ public class SatelliteController extends Handler { private static final boolean DBG = false; /** Message codes used in handleMessage() */ + //TODO: Move the Commands and events related to position updates to PointingAppController private static final int CMD_START_SATELLITE_POSITION_UPDATES = 1; private static final int EVENT_START_SATELLITE_POSITION_UPDATES_DONE = 2; private static final int CMD_STOP_SATELLITE_POSITION_UPDATES = 3; @@ -103,11 +103,7 @@ public class SatelliteController extends Handler { */ private final ConcurrentHashMap> mSatelliteProvisionCallbacks = new ConcurrentHashMap<>(); - /** - * Map key: subId, value: SatellitePositionUpdateHandler to notify registrants. - */ - private final ConcurrentHashMap - mSatellitePositionUpdateHandlers = new ConcurrentHashMap<>(); + /** * Map key: subId, value: SatelliteProvisionStateChangedHandler to notify registrants. */ @@ -123,7 +119,9 @@ public class SatelliteController extends Handler { private Boolean mIsSatelliteSupported = null; private final Object mIsSatelliteSupportedLock = new Object(); private final ResultReceiver mSatelliteSupportedReceiver; - private static boolean mIsSatelliteDemoModeEnabled = false; + private boolean mIsSatelliteDemoModeEnabled = false; + private boolean mNeedsSatellitePointing = false; + private final Object mNeedsSatellitePointingLock = new Object(); /** * @return The singleton instance of SatelliteController. @@ -187,6 +185,7 @@ public class SatelliteController extends Handler { } } }; + //TODO: reenable below code //requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, // mSatelliteSupportedReceiver); } @@ -231,7 +230,11 @@ public class SatelliteController extends Handler { } } - private static final class SatellitePositionUpdateArgument { + + /** + * Arguments to send to SatellitePositionUpdate registrants + */ + public static final class SatellitePositionUpdateArgument { public @NonNull Consumer errorCallback; public @NonNull ISatellitePositionUpdateCallback callback; public int subId; @@ -244,62 +247,6 @@ public class SatelliteController extends Handler { } } - private static final class SatellitePositionUpdateHandler extends Handler { - public static final int EVENT_POSITION_INFO_CHANGED = 1; - public static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 2; - - private final ConcurrentHashMap mListeners; - SatellitePositionUpdateHandler(Looper looper) { - super(looper); - mListeners = new ConcurrentHashMap<>(); - } - - public void addListener(ISatellitePositionUpdateCallback listener) { - mListeners.put(listener.asBinder(), listener); - } - - public void removeListener(ISatellitePositionUpdateCallback listener) { - mListeners.remove(listener.asBinder()); - } - - public boolean hasListeners() { - return !mListeners.isEmpty(); - } - - @Override - public void handleMessage(@NonNull Message msg) { - switch (msg.what) { - case EVENT_POSITION_INFO_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - PointingInfo pointingInfo = (PointingInfo) ar.result; - mListeners.values().forEach(listener -> { - try { - listener.onSatellitePositionChanged(pointingInfo); - } catch (RemoteException e) { - logd("EVENT_POSITION_INFO_CHANGED RemoteException: " + e); - } - }); - break; - } - case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - int result = (int) ar.result; - mListeners.values().forEach(listener -> { - try { - // TODO: process and return the rest of the values correctly - listener.onDatagramTransferStateChanged(result, 0, 0, 0); - } catch (RemoteException e) { - logd("EVENT_DATAGRAM_TRANSFER_STATE_CHANGED RemoteException: " + e); - } - }); - break; - } - default: - loge("SatellitePositionUpdateHandler unknown event: " + msg.what); - } - } - } - private static final class SatelliteProvisionStateChangedHandler extends Handler { public static final int EVENT_PROVISION_STATE_CHANGED = 1; @@ -438,20 +385,7 @@ public class SatelliteController extends Handler { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_START_SATELLITE_POSITION_UPDATES_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.startSendingSatellitePointingInfo(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.startSatellitePositionUpdates(onCompleted); - } else { - loge("startSatellitePositionUpdates: No phone object"); - SatellitePositionUpdateArgument arg = - (SatellitePositionUpdateArgument) request.argument; - arg.errorCallback.accept( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - } + mPointingAppController.startSatellitePositionUpdates(onCompleted, request.phone); break; } @@ -464,18 +398,7 @@ public class SatelliteController extends Handler { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = obtainMessage(EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.stopSendingSatellitePointingInfo(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.stopSatellitePositionUpdates(onCompleted); - } else { - loge("stopSatellitePositionUpdates: No phone object"); - ((Consumer) request.argument).accept( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - } + mPointingAppController.stopSatellitePositionUpdates(onCompleted, request.phone); break; } @@ -623,6 +546,15 @@ public class SatelliteController extends Handler { (RequestSatelliteEnabledArgument) request.argument; int error = SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled", false); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + /** + * TODO: check if Satellite is Acquired. + * Also need to call requestSatelliteCapabilities() if Satellite is enabled + */ + if (mNeedsSatellitePointing) { + mPointingAppController.startPointingUI(false); + } + } argument.callback.accept(error); // TODO: if error is ERROR_NONE, request satellite capabilities break; @@ -728,6 +660,9 @@ public class SatelliteController extends Handler { Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { SatelliteCapabilities capabilities = (SatelliteCapabilities) ar.result; + synchronized (mNeedsSatellitePointingLock) { + mNeedsSatellitePointing = capabilities.needsPointingToSatellite(); + } if (DBG) logd("getSatelliteCapabilities: " + capabilities); bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, capabilities); @@ -1010,26 +945,7 @@ public class SatelliteController extends Handler { } Phone phone = SatelliteServiceUtils.getPhone(); - SatellitePositionUpdateHandler handler = mSatellitePositionUpdateHandlers.get(validSubId); - if (handler != null) { - handler.addListener(callback); - return; - } else { - handler = new SatellitePositionUpdateHandler(Looper.getMainLooper()); - handler.addListener(callback); - mSatellitePositionUpdateHandlers.put(validSubId, handler); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.registerForSatellitePositionInfoChanged(handler, - SatellitePositionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); - mSatelliteModemInterface.registerForDatagramTransferStateChanged(handler, - SatellitePositionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, null); - } else { - phone.registerForSatellitePositionInfoChanged(handler, - SatellitePositionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); - // TODO: registerForDatagramTransferStateChanged through SatelliteController - } - } - + mPointingAppController.registerForSatellitePositionUpdates(validSubId, callback, phone); sendRequestAsync(CMD_START_SATELLITE_POSITION_UPDATES, new SatellitePositionUpdateArgument(result, callback, validSubId), phone); } @@ -1058,36 +974,8 @@ public class SatelliteController extends Handler { } Phone phone = SatelliteServiceUtils.getPhone(); - SatellitePositionUpdateHandler handler = mSatellitePositionUpdateHandlers.get(validSubId); - if (handler != null) { - handler.removeListener(callback); - - if (handler.hasListeners()) { - /** - * TODO (b/269194948): If the calling apps crash, the handler will always have some - * listener. That is, we will not request modem to stop position update and - * cleaning our resources. We need to monitor the calling apps and clean up the - * resources when the apps die. We need to this for other satellite callbacks - * as well. - */ - result.accept(SatelliteManager.SATELLITE_ERROR_NONE); - return; - } - - mSatellitePositionUpdateHandlers.remove(validSubId); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.unregisterForSatellitePositionInfoChanged(handler); - mSatelliteModemInterface.unregisterForDatagramTransferStateChanged(handler); - } else { - if (phone == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - phone.unregisterForSatellitePositionInfoChanged(handler); - // TODO: unregisterForDatagramTransferStateChanged through SatelliteController - } - } - + mPointingAppController.unregisterForSatellitePositionUpdates( + validSubId, result, callback, phone); /** * Even if handler is null - which means there are not any listeners, the command to stop * satellite position updates sent to the modem might have failed. The callers might want to @@ -1397,7 +1285,13 @@ public class SatelliteController extends Handler { return; } - // TODO: check if we need to start PointingUI. + /** + * TODO: check if Satellite is Acquired. Also need to call requestSatelliteCapabilities() + * when Satellite is enabled + */ + if (mNeedsSatellitePointing) { + mPointingAppController.startPointingUI(needFullScreenPointingUI); + } mDatagramController.sendSatelliteDatagram(datagramId, datagramType, datagram, needFullScreenPointingUI, mIsSatelliteDemoModeEnabled, result); } @@ -1544,36 +1438,16 @@ public class SatelliteController extends Handler { arg.errorCallback.accept(errorCode); if (errorCode != SatelliteManager.SATELLITE_ERROR_NONE) { + mPointingAppController.setStartedSatellitePositionUpdates(false); /** * We need to remove the callback from our listener list since the caller might not call * {@link #stopSatellitePositionUpdates(int, IIntegerConsumer, ISatellitePositionUpdateCallback)} * to unregister the callback in case of failure. */ - SatellitePositionUpdateHandler handler = - mSatellitePositionUpdateHandlers.get(arg.subId); - if (handler != null) { - handler.removeListener(arg.callback); - - if (!handler.hasListeners()) { - mSatellitePositionUpdateHandlers.remove(arg.subId); - - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.unregisterForSatellitePositionInfoChanged( - handler); - mSatelliteModemInterface.unregisterForDatagramTransferStateChanged( - handler); - } else { - Phone phone = request.phone; - if (phone == null) { - loge("handleStartSatellitePositionUpdatesDone: phone is null"); - } else { - phone.unregisterForSatellitePositionInfoChanged(handler); - // TODO: unregisterForDatagramTransferStateChanged through - // SatelliteController - } - } - } - } + mPointingAppController.unregisterForSatellitePositionUpdates(arg.subId, + arg.errorCallback, arg.callback, request.phone); + } else { + mPointingAppController.setStartedSatellitePositionUpdates(true); } } -- GitLab From e8089e9684effe48753e98c110eb08c5445000dd Mon Sep 17 00:00:00 2001 From: rambowang Date: Tue, 28 Feb 2023 19:52:53 -0600 Subject: [PATCH 476/656] Fix phone process crash due to NPE in DataNetwork This CL calls StateMachine#sendMessage instead of Message#sendToTarget to avoid the NPE when the handler of the message is null. The StateMachine handler could be null when e.g. it has quit. In this case, calling Message#sendToTarget will cause NPE and crash the phone process. StateMachine#sendMessage has protected against the case to avoid the NPE when handler is null. Bug: 270902239 Test: atest DataNetworkTest Change-Id: Ida123e2b493cb70b005b2ac47843d7c6d6f14656 Merged-In: Ida123e2b493cb70b005b2ac47843d7c6d6f14656 (cherry picked from commit a731f41291d7da374a60c65706dbb9040b7f9132) --- src/java/com/android/internal/telephony/data/DataNetwork.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 97930bdb9d..ce46f10114 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -1061,7 +1061,7 @@ public class DataNetwork extends StateMachine { message, privilegedUids.stream().mapToInt(i -> i).toArray(), null /* ex */); - message.sendToTarget(); + sendMessage(message); }; TelephonyManager tm = mPhone.getContext().getSystemService(TelephonyManager.class); if (tm != null) { -- GitLab From e763635e573334a53c827512b9416d8e163b02c6 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Wed, 1 Mar 2023 14:29:48 -0800 Subject: [PATCH 477/656] Handle RIL errors properly Separate out RemoteException and RuntimeException so the latter throws a SYSTEM_ERR instead of setting the radio to unavailable. If the radio proxy does not exist, return REQUEST_NOT_SUPPORTED so the onComplete message is sent instead of hanging Test: atest RILTest Bug: 231996546 Change-Id: I62e0593e6ff338f43b889287143b54137e47599d --- src/java/com/android/internal/telephony/RIL.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 2d64a44732..5977e11778 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -2178,8 +2178,21 @@ public class RIL extends BaseCommands implements CommandsInterface { dataProxy.setupDataCall(rr.mSerial, mPhoneId, accessNetworkType, dataProfile, isRoaming, allowRoaming, reason, linkProperties, pduSessionId, sliceInfo, trafficDescriptor, matchAllRuleAllowed); - } catch (RemoteException | RuntimeException e) { + } catch (RemoteException e) { handleRadioProxyExceptionForRR(HAL_SERVICE_DATA, "setupDataCall", e); + } catch (RuntimeException e) { + riljLoge("setupDataCall RuntimeException: " + e); + int error = RadioError.SYSTEM_ERR; + int responseType = RadioResponseType.SOLICITED; + processResponseInternal(HAL_SERVICE_DATA, rr.mSerial, error, responseType); + processResponseDoneInternal(rr, error, responseType, null); + } + } else { + riljLoge("setupDataCall: DataProxy is empty"); + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); + result.sendToTarget(); } } } -- GitLab From ed05066b672033b26f17f9e4d77ac37415e0ee6e Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 27 Feb 2023 13:38:04 -0800 Subject: [PATCH 478/656] Fix NPE in LinkBandwidthEstimator Rearrange the null check protections and make a number of small safety and readability improvements to reduce the changes of another bug like this. Bug: 270831206 Test: atest LinkBandwidthEstimatorTest #regression-test Change-Id: Ib4f37db0cd5a5ca83e8fea10a8e76d902d1065d4 --- .../data/LinkBandwidthEstimator.java | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index 994e8f67fb..5ceb5e46e1 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -41,12 +41,14 @@ import android.telephony.CellIdentityLte; import android.telephony.CellIdentityNr; import android.telephony.CellIdentityTdscdma; import android.telephony.CellIdentityWcdma; +import android.telephony.CellInfo; import android.telephony.ModemActivityInfo; import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.LocalLog; @@ -95,6 +97,9 @@ public class LinkBandwidthEstimator extends Handler { @VisibleForTesting static final int MSG_DATA_REG_STATE_OR_RAT_CHANGED = 9; + @VisibleForTesting + static final int UNKNOWN_TAC = CellInfo.UNAVAILABLE; + // TODO: move the following parameters to xml file private static final int TRAFFIC_STATS_POLL_INTERVAL_MS = 1_000; private static final int MODEM_POLL_MIN_INTERVAL_MS = 5_000; @@ -178,7 +183,7 @@ public class LinkBandwidthEstimator extends Handler { private int mSignalLevel; private int mDataRat = TelephonyManager.NETWORK_TYPE_UNKNOWN; private int mTac; - private String mPlmn = UNKNOWN_PLMN; + @NonNull private String mPlmn = UNKNOWN_PLMN; private NetworkCapabilities mNetworkCapabilities; private NetworkBandwidth mPlaceholderNetwork; private long mFilterUpdateTimeMs; @@ -1029,22 +1034,28 @@ public class LinkBandwidthEstimator extends Handler { } private boolean updateDataRatCellIdentityBandwidth() { - boolean updatedPlmn = false; - CellIdentity cellIdentity = mPhone.getCurrentCellIdentity(); - mTac = getTac(cellIdentity); + final ServiceState ss = mPhone.getServiceState(); + final CellIdentity cellIdentity = mPhone.getCurrentCellIdentity(); + + boolean hasChanged = false; String plmn; - if (mPhone.getServiceState().getOperatorNumeric() != null) { - plmn = mPhone.getServiceState().getOperatorNumeric(); + // Why does updating the TAC not result in hasChanged == true? + // Legacy behavior is currently being preserved for now, but it might very + // well be incorrect. The TAC is part of the network key. This is very fishy. + mTac = getTac(cellIdentity); + + /* ss should always be non-null */ + if (!TextUtils.isEmpty(ss.getOperatorNumeric())) { + plmn = ss.getOperatorNumeric(); + } else if (cellIdentity != null && !TextUtils.isEmpty(cellIdentity.getPlmn())) { + plmn = cellIdentity.getPlmn(); } else { - if (cellIdentity.getPlmn() != null) { - plmn = cellIdentity.getPlmn(); - } else { - plmn = UNKNOWN_PLMN; - } + plmn = UNKNOWN_PLMN; } - if (mPlmn == null || !plmn.equals(mPlmn)) { - updatedPlmn = true; + + if (!mPlmn.equals(plmn)) { + hasChanged = true; mPlmn = plmn; } @@ -1053,20 +1064,19 @@ public class LinkBandwidthEstimator extends Handler { if (nri != null) { int dataRat = nri.getAccessNetworkTechnology(); if (dataRat != mDataRat) { - updatedRat = true; + hasChanged = true; mDataRat = dataRat; updateStaticBwValue(mDataRat); updateByteCountThr(); } } - boolean updatedPlmnOrRat = updatedPlmn || updatedRat; - if (updatedPlmnOrRat) { + if (hasChanged) { resetBandwidthFilter(); updateTxRxBandwidthFilterSendToDataConnection(); mLastPlmnOrRatChangeTimeMs = mTelephonyFacade.getElapsedSinceBootMillis(); } - return updatedPlmnOrRat; + return hasChanged; } private int getTac(@NonNull CellIdentity cellIdentity) { @@ -1085,7 +1095,7 @@ public class LinkBandwidthEstimator extends Handler { if (cellIdentity instanceof CellIdentityGsm) { return ((CellIdentityGsm) cellIdentity).getLac(); } - return 0; + return UNKNOWN_TAC; } private class TelephonyCallbackImpl extends TelephonyCallback implements @@ -1110,16 +1120,17 @@ public class LinkBandwidthEstimator extends Handler { mLocalLog.log(msg); } - @VisibleForTesting - static final int UNKNOWN_TAC = -1; // Map with NetworkKey as the key and NetworkBandwidth as the value. // NetworkKey is specified by the PLMN, data RAT and TAC of network. // NetworkBandwidth represents the bandwidth related stats of each network. private final Map mNetworkMap = new ArrayMap<>(); + private static class NetworkKey { + private final String mPlmn; private final String mDataRat; private final int mTac; + NetworkKey(String plmn, int tac, String dataRat) { mPlmn = plmn; mTac = tac; @@ -1156,15 +1167,15 @@ public class LinkBandwidthEstimator extends Handler { } @NonNull - private NetworkBandwidth lookupNetwork(String plmn, String dataRat) { + private NetworkBandwidth lookupNetwork(@NonNull String plmn, String dataRat) { return lookupNetwork(plmn, UNKNOWN_TAC, dataRat); } /** Look up NetworkBandwidth and create a new one if it doesn't exist */ @VisibleForTesting @NonNull - public NetworkBandwidth lookupNetwork(String plmn, int tac, String dataRat) { - if (plmn == null || dataRat.equals( + public NetworkBandwidth lookupNetwork(@NonNull String plmn, int tac, String dataRat) { + if (dataRat.equals( TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_UNKNOWN))) { return mPlaceholderNetwork; } @@ -1180,7 +1191,9 @@ public class LinkBandwidthEstimator extends Handler { /** A class holding link bandwidth related stats */ @VisibleForTesting public class NetworkBandwidth { + private final String mKey; + NetworkBandwidth(String key) { mKey = key; } @@ -1276,5 +1289,4 @@ public class LinkBandwidthEstimator extends Handler { pw.println(); pw.flush(); } - } -- GitLab From e673216519c46daccb2ee1bba2ecafb449cdd409 Mon Sep 17 00:00:00 2001 From: rambowang Date: Wed, 1 Mar 2023 10:22:18 -0600 Subject: [PATCH 479/656] Fix the bug that phoneId is used to get carrier config All carrier config retrieval APIs accept subId as input. The usage in EmergencyNumberTracker passed the phoneId by mistake. All other CLs are also scanned to make sure no similar mistake. Bug: 271199418 Test: atest EmergencyNumberTrackerTest Test: Manual test according the test steps in the bug Change-Id: I4f63c1803acfdeee179694de6d5acab3f67b5d48 --- .../emergency/EmergencyNumberTracker.java | 4 +- .../emergency/EmergencyNumberTrackerTest.java | 50 +++++++++++++++++-- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 61f8aa3d51..6f8eaff543 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -189,7 +189,7 @@ public class EmergencyNumberTracker extends Handler { if (configMgr != null) { PersistableBundle b = CarrierConfigManager.getCarrierConfigSubset( mPhone.getContext(), - mPhoneId, + mPhone.getSubId(), CarrierConfigManager.KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY); if (!b.isEmpty()) { mEmergencyNumberPrefix = b.getStringArray( @@ -366,7 +366,7 @@ public class EmergencyNumberTracker extends Handler { PersistableBundle b = CarrierConfigManager.getCarrierConfigSubset( mPhone.getContext(), - mPhone.getPhoneId(), + mPhone.getSubId(), CarrierConfigManager.KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY); if (!b.isEmpty()) { String[] emergencyNumberPrefix = diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index 5a197b78ad..96efad7742 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -22,9 +22,9 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -32,16 +32,16 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import org.mockito.ArgumentCaptor; - -import android.content.IntentFilter; import android.content.Context; import android.content.ContextWrapper; +import android.content.IntentFilter; import android.content.res.AssetManager; import android.content.res.Resources; import android.os.AsyncResult; import android.os.Environment; import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.emergency.EmergencyNumber; @@ -62,6 +62,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; + import java.io.BufferedInputStream; import java.io.File; @@ -117,6 +119,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private ParcelFileDescriptor mOtaParcelFileDescriptor = null; // Mocked classes private SubscriptionController mSubControllerMock; + private CarrierConfigManager mCarrierConfigManagerMock; // mEmergencyNumberTrackerMock for mPhone private EmergencyNumberTracker mEmergencyNumberTrackerMock; @@ -138,6 +141,7 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); mShortNumberInfo = mock(ShortNumberInfo.class); mSubControllerMock = mock(SubscriptionController.class); + mCarrierConfigManagerMock = mock(CarrierConfigManager.class); mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()); mMockContext = mock(Context.class); @@ -872,4 +876,42 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { assertEquals(resultToVerify, resultFromRadio); } + + @Test + public void testOverridingEmergencyNumberPrefixCarrierConfig() throws Exception { + // Capture CarrierConfigChangeListener to emulate the carrier config change notification + doReturn(mMockContext).when(mPhone).getContext(); + doReturn(Context.CARRIER_CONFIG_SERVICE) + .when(mMockContext) + .getSystemService(CarrierConfigManager.class); + doReturn(mCarrierConfigManagerMock) + .when(mMockContext) + .getSystemService(eq(Context.CARRIER_CONFIG_SERVICE)); + ArgumentCaptor listenerArgumentCaptor = + ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); + EmergencyNumberTracker localEmergencyNumberTracker = + new EmergencyNumberTracker(mPhone, mSimulatedCommands); + verify(mCarrierConfigManagerMock) + .registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); + CarrierConfigManager.CarrierConfigChangeListener carrierConfigChangeListener = + listenerArgumentCaptor.getAllValues().get(0); + + assertFalse(localEmergencyNumberTracker.isEmergencyNumber("*272911")); + + PersistableBundle bundle = new PersistableBundle(); + bundle.putStringArray( + CarrierConfigManager.KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, + new String[] {"*272"}); + doReturn(bundle) + .when(mCarrierConfigManagerMock) + .getConfigForSubId(eq(SUB_ID_PHONE_1), any()); + carrierConfigChangeListener.onCarrierConfigChanged( + mPhone.getPhoneId(), + mPhone.getSubId(), + TelephonyManager.UNKNOWN_CARRIER_ID, + TelephonyManager.UNKNOWN_CARRIER_ID); + processAllMessages(); + + assertTrue(localEmergencyNumberTracker.isEmergencyNumber("*272911")); + } } -- GitLab From bff6937efb88ffe0b5fe07d98c74ff0846fbbb84 Mon Sep 17 00:00:00 2001 From: Hwangoo Park Date: Thu, 2 Mar 2023 02:18:57 +0000 Subject: [PATCH 480/656] Update EmergencyStateTracker to cover emergency SMS and edge cases This CL contains the followings: - Adds emergency SMS APIs: startEmergencySms/endSms - Covers some edge cases: - Waits for ongoing call/SMS before the emergency mode is exited if an emergency call/SMS ends while another emergency call/SMS is in progress on the same phone. - Basically, an emergency call will be handled with priority, and if an emergency call/SMS starts on the same or different phone sequentially, it will be processed with a proper manner by canceling and proceeding or returning the result immediately. Bug: 267220850 Test: atest EmergencyStateTrackerTest Test: manual (verify emergency call/SMS start/end with test emergency number) Change-Id: I46980424ce735df149fcc6166f24785a060d6bc0 --- .../emergency/EmergencyStateTracker.java | 671 +++++++--- .../emergency/EmergencyStateTrackerTest.java | 1077 +++++++++++++++-- 2 files changed, 1511 insertions(+), 237 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java index 5b667db69b..6e2e32dd89 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java @@ -20,6 +20,7 @@ import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_E import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_NONE; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; +import android.annotation.IntDef; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; @@ -34,6 +35,7 @@ import android.os.PowerManager; import android.os.UserHandle; import android.provider.Settings; import android.sysprop.TelephonyProperties; +import android.telephony.Annotation.DisconnectCauses; import android.telephony.CarrierConfigManager; import android.telephony.DisconnectCause; import android.telephony.EmergencyRegResult; @@ -41,6 +43,8 @@ import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.emergency.EmergencyNumber; +import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Call; @@ -52,8 +56,10 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.telephony.Rlog; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Arrays; -import java.util.HashSet; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -75,32 +81,56 @@ public class EmergencyStateTracker { /** Default Emergency Callback Mode exit timeout value. */ private static final long DEFAULT_ECM_EXIT_TIMEOUT_MS = 300000; + /** The emergency types used when setting the emergency mode on modem. */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "EMERGENCY_TYPE_", + value = { + EMERGENCY_TYPE_CALL, + EMERGENCY_TYPE_SMS}) + public @interface EmergencyType {} + + /** Indicates the emergency type is call. */ + public static final int EMERGENCY_TYPE_CALL = 1; + /** Indicates the emergency type is SMS. */ + public static final int EMERGENCY_TYPE_SMS = 2; + private static EmergencyStateTracker INSTANCE = null; - private final long mEcmExitTimeoutMs; private final Context mContext; private final CarrierConfigManager mConfigManager; private final Handler mHandler; private final boolean mIsSuplDdsSwitchRequiredForEmergencyCall; - /** Tracks emergency calls by callId that have reached {@link Call.State#ACTIVE}.*/ - private final Set mActiveEmergencyCalls = new HashSet<>(); private final PowerManager.WakeLock mWakeLock; - + private RadioOnHelper mRadioOnHelper; @EmergencyConstants.EmergencyMode private int mEmergencyMode = MODE_EMERGENCY_NONE; - private Phone mPhone; - private RadioOnHelper mRadioOnHelper; - private CompletableFuture mOnCompleted = null; - // Domain of the active emergency call. Assuming here that there will only be one domain active. - private int mEmergencyCallDomain = -1; + private boolean mWasEmergencyModeSetOnModem; private EmergencyRegResult mLastEmergencyRegResult; - private boolean mIsInEmergencyCall = false; - private boolean mIsTestEmergencyNumber = false; - private boolean mIsPhoneInEcmState = false; - private Runnable mOnEcmExitCompleteRunnable = null; + private boolean mIsEmergencyModeInProgress; + private boolean mIsEmergencyCallStartedDuringEmergencySms; + /** For emergency calls */ + private final long mEcmExitTimeoutMs; // A runnable which is used to automatically exit from Ecm after a period of time. private final Runnable mExitEcmRunnable = this::exitEmergencyCallbackMode; + // Tracks emergency calls by callId that have reached {@link Call.State#ACTIVE}. + private final Set mActiveEmergencyCalls = new ArraySet<>(); + private Phone mPhone; + // Tracks ongoing emergency callId to handle a second emergency call + private String mOngoingCallId; + // Domain of the active emergency call. Assuming here that there will only be one domain active. + private int mEmergencyCallDomain = NetworkRegistrationInfo.DOMAIN_UNKNOWN; + private CompletableFuture mCallEmergencyModeFuture; + private boolean mIsInEmergencyCall; + private boolean mIsInEcm; + private boolean mIsTestEmergencyNumber; + private Runnable mOnEcmExitCompleteRunnable; + + /** For emergency SMS */ + private final Set mOngoingEmergencySmsIds = new ArraySet<>(); + private Phone mSmsPhone; + private CompletableFuture mSmsEmergencyModeFuture; + private boolean mIsTestEmergencyNumberForSms; /** * Listens for Emergency Callback Mode state change intents @@ -187,37 +217,101 @@ public class EmergencyStateTracker { @Override public void handleMessage(Message msg) { - AsyncResult ar; - switch (msg.what) { - case MSG_SET_EMERGENCY_MODE_DONE: - Rlog.v(TAG, "MSG_SET_EMERGENCY_MODE_DONE"); - ar = (AsyncResult) msg.obj; - if (ar.exception == null) { - mLastEmergencyRegResult = (EmergencyRegResult) ar.result; - } else { - Rlog.w(TAG, "LastEmergencyRegResult not set. AsyncResult.exception: " - + ar.exception); + case MSG_SET_EMERGENCY_MODE_DONE: { + AsyncResult ar = (AsyncResult) msg.obj; + Integer emergencyType = (Integer) ar.userObj; + Rlog.v(TAG, "MSG_SET_EMERGENCY_MODE_DONE for " + + emergencyTypeToString(emergencyType)); + if (ar.exception == null) { + mLastEmergencyRegResult = (EmergencyRegResult) ar.result; + } else { + mLastEmergencyRegResult = null; + Rlog.w(TAG, "LastEmergencyRegResult not set. AsyncResult.exception: " + + ar.exception); + } + setEmergencyModeInProgress(false); + + if (emergencyType == EMERGENCY_TYPE_CALL) { + setIsInEmergencyCall(true); + completeEmergencyMode(emergencyType); + + // Case 1) When the emergency call is setting the emergency mode and + // the emergency SMS is being sent, completes the SMS future also. + // Case 2) When the emergency SMS is setting the emergency mode and + // the emergency call is beint started, the SMS request is cancelled and + // the call request will be handled. + if (mSmsPhone != null) { + completeEmergencyMode(EMERGENCY_TYPE_SMS); + } + } else if (emergencyType == EMERGENCY_TYPE_SMS) { + if (mPhone != null && mSmsPhone != null) { + // Clear call phone temporarily to exit the emergency mode + // if the emergency call is started. + if (mIsEmergencyCallStartedDuringEmergencySms) { + Phone phone = mPhone; + mPhone = null; + exitEmergencyMode(mSmsPhone, emergencyType); + // Restore call phone for further use. + mPhone = phone; + + if (!isSamePhone(mPhone, mSmsPhone)) { + completeEmergencyMode(emergencyType, + DisconnectCause.OUTGOING_EMERGENCY_CALL_PLACED); + } + } else { + completeEmergencyMode(emergencyType); + } + break; + } else { + completeEmergencyMode(emergencyType); + } + + if (mIsEmergencyCallStartedDuringEmergencySms) { + mIsEmergencyCallStartedDuringEmergencySms = false; + turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL, + mIsTestEmergencyNumber); + } + } + break; } - setIsInEmergencyCall(true); - mOnCompleted.complete(DisconnectCause.NOT_DISCONNECTED); - break; - - case MSG_EXIT_EMERGENCY_MODE_DONE: - Rlog.v(TAG, "MSG_EXIT_EMERGENCY_MODE_DONE"); - setIsInEmergencyCall(false); - if (mOnEcmExitCompleteRunnable != null) { - mOnEcmExitCompleteRunnable.run(); - mOnEcmExitCompleteRunnable = null; + case MSG_EXIT_EMERGENCY_MODE_DONE: { + AsyncResult ar = (AsyncResult) msg.obj; + Integer emergencyType = (Integer) ar.userObj; + Rlog.v(TAG, "MSG_EXIT_EMERGENCY_MODE_DONE for " + + emergencyTypeToString(emergencyType)); + setEmergencyModeInProgress(false); + + if (emergencyType == EMERGENCY_TYPE_CALL) { + setIsInEmergencyCall(false); + if (mOnEcmExitCompleteRunnable != null) { + mOnEcmExitCompleteRunnable.run(); + mOnEcmExitCompleteRunnable = null; + } + } else if (emergencyType == EMERGENCY_TYPE_SMS) { + if (mIsEmergencyCallStartedDuringEmergencySms) { + mIsEmergencyCallStartedDuringEmergencySms = false; + turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL, + mIsTestEmergencyNumber); + } + } + break; } - break; - - case MSG_SET_EMERGENCY_CALLBACK_MODE_DONE: - Rlog.v(TAG, "MSG_SET_EMERGENCY_CALLBACK_MODE_DONE"); - break; - - default: - break; + case MSG_SET_EMERGENCY_CALLBACK_MODE_DONE: { + AsyncResult ar = (AsyncResult) msg.obj; + Integer emergencyType = (Integer) ar.userObj; + Rlog.v(TAG, "MSG_SET_EMERGENCY_CALLBACK_MODE_DONE for " + + emergencyTypeToString(emergencyType)); + setEmergencyModeInProgress(false); + // When the emergency callback mode is in progress and the emergency SMS is + // started, it needs to be completed here for the emergency SMS. + if (mSmsPhone != null) { + completeEmergencyMode(EMERGENCY_TYPE_SMS); + } + break; + } + default: + break; } } } @@ -266,7 +360,7 @@ public class EmergencyStateTracker { // Register receiver for ECM exit. IntentFilter filter = new IntentFilter(); filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); - context.registerReceiver(mEcmExitReceiver, filter); + context.registerReceiver(mEcmExitReceiver, filter, null, mHandler); mTelephonyManagerProxy = new TelephonyManagerProxyImpl(context); } @@ -300,7 +394,7 @@ public class EmergencyStateTracker { mConfigManager = context.getSystemService(CarrierConfigManager.class); IntentFilter filter = new IntentFilter(); filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); - context.registerReceiver(mEcmExitReceiver, filter); + context.registerReceiver(mEcmExitReceiver, filter, null, mHandler); } /** @@ -315,63 +409,103 @@ public class EmergencyStateTracker { * @return a {@code CompletableFuture} that results in {@code DisconnectCause.NOT_DISCONNECTED} * if emergency call successfully started. */ - public CompletableFuture startEmergencyCall(Phone phone, String callId, - boolean isTestEmergencyNumber) { - Rlog.i(TAG, "startEmergencyCall for callId:" + callId); + public CompletableFuture startEmergencyCall(@NonNull Phone phone, + @NonNull String callId, boolean isTestEmergencyNumber) { + Rlog.i(TAG, "startEmergencyCall: phoneId=" + phone.getPhoneId() + ", callId=" + callId); if (mPhone != null) { - Rlog.e(TAG, "startEmergencyCall failed. Existing emergency call in progress."); // Create new future to return as to not interfere with any uncompleted futures. - CompletableFuture future = new CompletableFuture<>(); - future.complete(DisconnectCause.ERROR_UNSPECIFIED); - return future; + // Case1) When 2nd emergency call is initiated during an active call on the same phone. + // Case2) While the device is in ECBM, an emergency call is initiated on the same phone. + if (isSamePhone(mPhone, phone) && (!mActiveEmergencyCalls.isEmpty() || isInEcm())) { + mOngoingCallId = callId; + mIsTestEmergencyNumber = isTestEmergencyNumber; + return CompletableFuture.completedFuture(DisconnectCause.NOT_DISCONNECTED); + } + + Rlog.e(TAG, "startEmergencyCall failed. Existing emergency call in progress."); + return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED); + } + + mCallEmergencyModeFuture = new CompletableFuture<>(); + + if (mSmsPhone != null) { + mIsEmergencyCallStartedDuringEmergencySms = true; + // Case1) While exiting the emergency mode on the other phone, + // the emergency mode for this call will be restarted after the exit complete. + // Case2) While entering the emergency mode on the other phone, + // exit the emergency mode when receiving the result of setting the emergency mode and + // the emergency mode for this call will be restarted after the exit complete. + if (isInEmergencyMode() && !isEmergencyModeInProgress()) { + exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS); + } + + mPhone = phone; + mOngoingCallId = callId; + mIsTestEmergencyNumber = isTestEmergencyNumber; + return mCallEmergencyModeFuture; } + mPhone = phone; + mOngoingCallId = callId; mIsTestEmergencyNumber = isTestEmergencyNumber; - mLastEmergencyRegResult = null; - mOnCompleted = new CompletableFuture<>(); + turnOnRadioAndSwitchDds(mPhone, EMERGENCY_TYPE_CALL, mIsTestEmergencyNumber); + return mCallEmergencyModeFuture; + } - final boolean isAirplaneModeOn = isAirplaneModeOn(mContext); - boolean needToTurnOnRadio = !isRadioOn() || isAirplaneModeOn; + /** + * Ends emergency call. + * + *

+ * Enter ECM only once all active emergency calls have ended. If a call never reached + * {@link Call.State#ACTIVE}, then no need to enter ECM. + * + * @param callId the call id on which to end the emergency call. + */ + public void endCall(@NonNull String callId) { + boolean wasActive = mActiveEmergencyCalls.remove(callId); - if (needToTurnOnRadio) { - if (mRadioOnHelper == null) { - mRadioOnHelper = new RadioOnHelper(mContext); - } + if (Objects.equals(mOngoingCallId, callId)) { + mOngoingCallId = null; + } - mRadioOnHelper.triggerRadioOnAndListen(new RadioOnStateListener.Callback() { - @Override - public void onComplete(RadioOnStateListener listener, boolean isRadioReady) { - if (!isRadioReady) { - // Could not turn radio on - Rlog.e(TAG, "Failed to turn on radio."); - mOnCompleted.complete(DisconnectCause.POWER_OFF); - // If call setup fails, then move to MODE_EMERGENCY_NONE. - exitEmergencyMode(); - } else { - delayDialAndSetEmergencyMode(phone); - } - } + if (wasActive && mActiveEmergencyCalls.isEmpty() + && isEmergencyCallbackModeSupported()) { + enterEmergencyCallbackMode(); - @Override - public boolean isOkToCall(Phone phone, int serviceState) { - // We currently only look to make sure that the radio is on before dialing. We - // should be able to make emergency calls at any time after the radio has been - // powered on and isn't in the UNAVAILABLE state, even if it is reporting the - // OUT_OF_SERVICE state. - return phone.getServiceStateTracker().isRadioOn(); + if (mOngoingCallId == null) { + mIsEmergencyCallStartedDuringEmergencySms = false; + mCallEmergencyModeFuture = null; + } + } else if (mOngoingCallId == null) { + if (isInEcm()) { + mIsEmergencyCallStartedDuringEmergencySms = false; + mCallEmergencyModeFuture = null; + // If the emergency call was initiated during the emergency callback mode, + // the emergency callback mode should be restored when the emergency call is ended. + if (mActiveEmergencyCalls.isEmpty()) { + setEmergencyMode(mPhone, EMERGENCY_TYPE_CALL, MODE_EMERGENCY_CALLBACK, + MSG_SET_EMERGENCY_CALLBACK_MODE_DONE); } - }, !isTestEmergencyNumber, phone, isTestEmergencyNumber); - } else { - delayDialAndSetEmergencyMode(phone); + } else { + exitEmergencyMode(mPhone, EMERGENCY_TYPE_CALL); + clearEmergencyCallInfo(); + } } + } - return mOnCompleted; + private void clearEmergencyCallInfo() { + mEmergencyCallDomain = NetworkRegistrationInfo.DOMAIN_UNKNOWN; + mIsTestEmergencyNumber = false; + mIsEmergencyCallStartedDuringEmergencySms = false; + mCallEmergencyModeFuture = null; + mOngoingCallId = null; + mPhone = null; } - private void delayDialAndSetEmergencyMode(Phone phone) { - delayDialForDdsSwitch(phone, result -> { - Rlog.i(TAG, "delayDialForDdsSwitch: result = " + result); + private void switchDdsAndSetEmergencyMode(Phone phone, @EmergencyType int emergencyType) { + switchDdsDelayed(phone, result -> { + Rlog.i(TAG, "switchDdsDelayed: result = " + result); if (!result) { // DDS Switch timed out/failed, but continue with call as it may still succeed. Rlog.e(TAG, "DDS Switch failed."); @@ -381,27 +515,35 @@ public class EmergencyStateTracker { // only API that can receive it before starting domain selection. Once domain selection // is finished, the actual emergency mode will be set when onEmergencyTransportChanged() // is called. - setEmergencyMode(MODE_EMERGENCY_WWAN, MSG_SET_EMERGENCY_MODE_DONE); + setEmergencyMode(phone, emergencyType, MODE_EMERGENCY_WWAN, + MSG_SET_EMERGENCY_MODE_DONE); }); } /** * Triggers modem to set new emergency mode. * + * @param phone the {@code Phone} to set the emergency mode on modem. + * @param emergencyType the emergency type to identify an emergency call or SMS. * @param mode the new emergency mode. * @param msg the message to be sent once mode has been set. */ - private void setEmergencyMode(@EmergencyConstants.EmergencyMode int mode, int msg) { - Rlog.i(TAG, "setEmergencyMode from " + mEmergencyMode + " to " + mode); + private void setEmergencyMode(Phone phone, @EmergencyType int emergencyType, + @EmergencyConstants.EmergencyMode int mode, int msg) { + Rlog.i(TAG, "setEmergencyMode from " + mEmergencyMode + " to " + mode + " for " + + emergencyTypeToString(emergencyType)); if (mEmergencyMode == mode) { return; } mEmergencyMode = mode; + setEmergencyModeInProgress(true); - Message m = mHandler.obtainMessage(msg); - if (mIsTestEmergencyNumber) { - Rlog.d(TAG, "IsTestEmergencyNumber true. Skipping setting emergency mode on modem."); + Message m = mHandler.obtainMessage(msg, Integer.valueOf(emergencyType)); + if ((mIsTestEmergencyNumber && emergencyType == EMERGENCY_TYPE_CALL) + || (mIsTestEmergencyNumberForSms && emergencyType == EMERGENCY_TYPE_SMS)) { + Rlog.d(TAG, "TestEmergencyNumber for " + emergencyTypeToString(emergencyType) + + ": Skipping setting emergency mode on modem."); // Send back a response for the command, but with null information AsyncResult.forMessage(m, null, null); // Ensure that we do not accidentally block indefinitely when trying to validate test @@ -409,16 +551,65 @@ public class EmergencyStateTracker { m.sendToTarget(); return; } - mPhone.setEmergencyMode(mode, mHandler.obtainMessage(msg)); + + mWasEmergencyModeSetOnModem = true; + phone.setEmergencyMode(mode, m); + } + + private void completeEmergencyMode(@EmergencyType int emergencyType) { + completeEmergencyMode(emergencyType, DisconnectCause.NOT_DISCONNECTED); + } + + private void completeEmergencyMode(@EmergencyType int emergencyType, + @DisconnectCauses int result) { + if (emergencyType == EMERGENCY_TYPE_CALL) { + if (mCallEmergencyModeFuture != null && !mCallEmergencyModeFuture.isDone()) { + mCallEmergencyModeFuture.complete(result); + } + + if (result != DisconnectCause.NOT_DISCONNECTED) { + clearEmergencyCallInfo(); + } + } else if (emergencyType == EMERGENCY_TYPE_SMS) { + if (mSmsEmergencyModeFuture != null && !mSmsEmergencyModeFuture.isDone()) { + mSmsEmergencyModeFuture.complete(result); + } + + if (result != DisconnectCause.NOT_DISCONNECTED) { + clearEmergencySmsInfo(); + } + } + } + + /** + * Checks if the device is currently in the emergency mode or not. + */ + @VisibleForTesting + public boolean isInEmergencyMode() { + return mEmergencyMode != MODE_EMERGENCY_NONE; + } + + /** + * Sets the flag to inidicate whether setting the emergency mode on modem is in progress or not. + */ + private void setEmergencyModeInProgress(boolean isEmergencyModeInProgress) { + mIsEmergencyModeInProgress = isEmergencyModeInProgress; + } + + /** + * Checks whether setting the emergency mode on modem is in progress or not. + */ + private boolean isEmergencyModeInProgress() { + return mIsEmergencyModeInProgress; } /** * Notifies external app listeners of emergency mode changes. * - * @param callActive whether there is an active emergency call. + * @param isInEmergencyCall a flag to indicate whether there is an active emergency call. */ - private void setIsInEmergencyCall(boolean callActive) { - mIsInEmergencyCall = callActive; + private void setIsInEmergencyCall(boolean isInEmergencyCall) { + mIsInEmergencyCall = isInEmergencyCall; } /** @@ -432,36 +623,48 @@ public class EmergencyStateTracker { /** * Triggers modem to exit emergency mode. + * + * @param phone the {@code Phone} to exit the emergency mode. + * @param emergencyType the emergency type to identify an emergency call or SMS. */ - private void exitEmergencyMode() { - Rlog.i(TAG, "exitEmergencyMode"); + private void exitEmergencyMode(Phone phone, @EmergencyType int emergencyType) { + Rlog.i(TAG, "exitEmergencyMode for " + emergencyTypeToString(emergencyType)); - if (mEmergencyMode != MODE_EMERGENCY_NONE) { - mEmergencyMode = MODE_EMERGENCY_NONE; - mPhone.exitEmergencyMode(mHandler.obtainMessage(MSG_EXIT_EMERGENCY_MODE_DONE)); + if (emergencyType == EMERGENCY_TYPE_CALL) { + if (mSmsPhone != null && isSamePhone(phone, mSmsPhone)) { + // Waits for exiting the emergency mode until the emergency SMS is ended. + Rlog.i(TAG, "exitEmergencyMode: waits for emergency SMS end."); + setIsInEmergencyCall(false); + return; + } + } else if (emergencyType == EMERGENCY_TYPE_SMS) { + if (mPhone != null && isSamePhone(phone, mPhone)) { + // Waits for exiting the emergency mode until the emergency call is ended. + Rlog.i(TAG, "exitEmergencyMode: waits for emergency call end."); + return; + } } - mPhone = null; - } - /** - * Ends emergency call. - * - *

- * Enter ECM only once all active emergency calls have ended. If a call never reached - * {@link Call.State#ACTIVE}, then no need to enter ECM. - * - * @param callId the call id on which to end the emergency call. - */ - public void endCall(String callId) { - boolean wasActive = mActiveEmergencyCalls.remove(callId); - if (mIsTestEmergencyNumber - || (wasActive && emergencyCallbackModeSupported() - && mActiveEmergencyCalls.isEmpty())) { - enterEmergencyCallbackMode(); - } else { - exitEmergencyMode(); - mEmergencyCallDomain = -1; + if (mEmergencyMode == MODE_EMERGENCY_NONE) { + return; + } + mEmergencyMode = MODE_EMERGENCY_NONE; + setEmergencyModeInProgress(true); + + Message m = mHandler.obtainMessage( + MSG_EXIT_EMERGENCY_MODE_DONE, Integer.valueOf(emergencyType)); + if (!mWasEmergencyModeSetOnModem) { + Rlog.d(TAG, "Emergency mode was not set on modem: Skipping exiting emergency mode."); + // Send back a response for the command, but with null information + AsyncResult.forMessage(m, null, null); + // Ensure that we do not accidentally block indefinitely when trying to validate + // the exit condition. + m.sendToTarget(); + return; } + + mWasEmergencyModeSetOnModem = false; + phone.exitEmergencyMode(m); } /** Returns last {@link EmergencyRegResult} as set by {@code setEmergencyMode()}. */ @@ -475,7 +678,38 @@ public class EmergencyStateTracker { * @param mode the new emergency mode */ public void onEmergencyTransportChanged(@EmergencyConstants.EmergencyMode int mode) { - setEmergencyMode(mode, MSG_SET_EMERGENCY_MODE_DONE); + // The phone for call is prioritized. + if (mPhone != null && mOngoingCallId != null) { + onEmergencyTransportChanged(EMERGENCY_TYPE_CALL, mode); + } else if (mSmsPhone != null) { + onEmergencyTransportChanged(EMERGENCY_TYPE_SMS, mode); + } + } + + /** + * Handles emergency transport change by setting new emergency mode. + * + * @param emergencyType the emergency type to identify an emergency call or SMS + * @param mode the new emergency mode + */ + public void onEmergencyTransportChanged(@EmergencyType int emergencyType, + @EmergencyConstants.EmergencyMode int mode) { + if (mHandler.getLooper().isCurrentThread()) { + Phone phone = null; + if (emergencyType == EMERGENCY_TYPE_CALL) { + phone = mPhone; + } else if (emergencyType == EMERGENCY_TYPE_SMS) { + phone = mSmsPhone; + } + + if (phone != null) { + setEmergencyMode(phone, emergencyType, mode, MSG_SET_EMERGENCY_MODE_DONE); + } + } else { + mHandler.post(() -> { + onEmergencyTransportChanged(emergencyType, mode); + }); + } } /** @@ -523,7 +757,7 @@ public class EmergencyStateTracker { /** * Returns {@code true} if device and carrier support emergency callback mode. */ - private boolean emergencyCallbackModeSupported() { + private boolean isEmergencyCallbackModeSupported() { return getConfig(mPhone.getSubId(), CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, DEFAULT_EMERGENCY_CALLBACK_MODE_SUPPORTED); @@ -551,7 +785,8 @@ public class EmergencyStateTracker { } // Set emergency mode on modem. - setEmergencyMode(MODE_EMERGENCY_CALLBACK, MSG_SET_EMERGENCY_CALLBACK_MODE_DONE); + setEmergencyMode(mPhone, EMERGENCY_TYPE_CALL, MODE_EMERGENCY_CALLBACK, + MSG_SET_EMERGENCY_CALLBACK_MODE_DONE); // Post this runnable so we will automatically exit if no one invokes // exitEmergencyCallbackMode() directly. @@ -560,7 +795,7 @@ public class EmergencyStateTracker { mHandler.postDelayed(mExitEcmRunnable, delayInMillis); // We don't want to go to sleep while in ECM. - if (mWakeLock != null) mWakeLock.acquire(mEcmExitTimeoutMs); + if (mWakeLock != null) mWakeLock.acquire(delayInMillis); } } @@ -568,11 +803,9 @@ public class EmergencyStateTracker { * Exits emergency callback mode and notifies relevant listeners. */ public void exitEmergencyCallbackMode() { - Rlog.d(TAG, "ecit ECBM"); + Rlog.d(TAG, "exit ECBM"); // Remove pending exit ECM runnable, if any. mHandler.removeCallbacks(mExitEcmRunnable); - mEmergencyCallDomain = -1; - mIsTestEmergencyNumber = false; if (isInEcm()) { setIsInEcm(false); @@ -582,16 +815,26 @@ public class EmergencyStateTracker { // Release wakeLock. if (mWakeLock != null && mWakeLock.isHeld()) { - mWakeLock.release(); + try { + mWakeLock.release(); + } catch (Exception e) { + // Ignore the exception if the system has already released this WakeLock. + Rlog.d(TAG, "WakeLock already released: " + e.toString()); + } } + GsmCdmaPhone gsmCdmaPhone = (GsmCdmaPhone) mPhone; // Send intents that ECM has changed. sendEmergencyCallbackModeChange(); - ((GsmCdmaPhone) mPhone).notifyEmergencyCallRegistrants(false); + gsmCdmaPhone.notifyEmergencyCallRegistrants(false); // Exit emergency mode on modem. - exitEmergencyMode(); + exitEmergencyMode(gsmCdmaPhone, EMERGENCY_TYPE_CALL); } + + mEmergencyCallDomain = NetworkRegistrationInfo.DOMAIN_UNKNOWN; + mIsTestEmergencyNumber = false; + mPhone = null; } /** @@ -622,14 +865,16 @@ public class EmergencyStateTracker { * receive an incoming call from the emergency operator. */ public boolean isInEcm() { - return mIsPhoneInEcmState; + return mIsInEcm; } /** * Sets the emergency callback mode state. + * + * @param isInEcm {@code true} if currently in emergency callback mode, {@code false} otherwise. */ private void setIsInEcm(boolean isInEcm) { - mIsPhoneInEcmState = isInEcm; + mIsInEcm = isInEcm; } /** @@ -650,6 +895,92 @@ public class EmergencyStateTracker { && mEmergencyCallDomain == NetworkRegistrationInfo.DOMAIN_CS && isInEcm(); } + /** + * Starts the process of an emergency SMS. + * + * @param phone the {@code Phone} on which to process the emergency SMS. + * @param smsId the SMS id on which to process the emergency SMS. + * @param isTestEmergencyNumber whether this is a test emergency number. + * @return A {@code CompletableFuture} that results in {@code DisconnectCause.NOT_DISCONNECTED} + * if the emergency SMS is successfully started. + */ + public CompletableFuture startEmergencySms(@NonNull Phone phone, @NonNull String smsId, + boolean isTestEmergencyNumber) { + Rlog.i(TAG, "startEmergencySms: phoneId=" + phone.getPhoneId() + ", smsId=" + smsId); + + // When an emergency call is in progress, it checks whether an emergency call is already in + // progress on the different phone. + if (mPhone != null && !isSamePhone(mPhone, phone)) { + Rlog.e(TAG, "Emergency call is in progress on the other slot."); + return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED); + } + + // When an emergency SMS is in progress, it checks whether an emergency SMS is already in + // progress on the different phone. + if (mSmsPhone != null && !isSamePhone(mSmsPhone, phone)) { + Rlog.e(TAG, "Emergency SMS is in progress on the other slot."); + return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED); + } + + // When the previous emergency SMS is not completed yet, + // this new request will not be allowed. + if (mSmsPhone != null && isInEmergencyMode() && isEmergencyModeInProgress()) { + Rlog.e(TAG, "Existing emergency SMS is in progress."); + return CompletableFuture.completedFuture(DisconnectCause.ERROR_UNSPECIFIED); + } + + mSmsPhone = phone; + mIsTestEmergencyNumberForSms = isTestEmergencyNumber; + mOngoingEmergencySmsIds.add(smsId); + + // When the emergency mode is already set by the previous emergency call or SMS, + // completes the future immediately. + if (isInEmergencyMode() && !isEmergencyModeInProgress()) { + return CompletableFuture.completedFuture(DisconnectCause.NOT_DISCONNECTED); + } + + mSmsEmergencyModeFuture = new CompletableFuture<>(); + if (!isInEmergencyMode()) { + setEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS, MODE_EMERGENCY_WWAN, + MSG_SET_EMERGENCY_MODE_DONE); + } + return mSmsEmergencyModeFuture; + } + + /** + * Ends an emergency SMS. + * This should be called once an emergency SMS is sent. + * + * @param smsId the SMS id on which to end the emergency SMS. + * @param emergencyNumber the emergency number which was used for the emergency SMS. + */ + public void endSms(@NonNull String smsId, EmergencyNumber emergencyNumber) { + mOngoingEmergencySmsIds.remove(smsId); + + // If the outgoing emergency SMSs are empty, we can try to exit the emergency mode. + if (mOngoingEmergencySmsIds.isEmpty()) { + if (isInEcm()) { + // When the emergency mode is not in MODE_EMERGENCY_CALLBACK, + // it needs to notify the emergency callback mode to modem. + if (mActiveEmergencyCalls.isEmpty() && mOngoingCallId == null) { + setEmergencyMode(mPhone, EMERGENCY_TYPE_CALL, MODE_EMERGENCY_CALLBACK, + MSG_SET_EMERGENCY_CALLBACK_MODE_DONE); + } + } else { + exitEmergencyMode(mSmsPhone, EMERGENCY_TYPE_SMS); + } + + clearEmergencySmsInfo(); + } + } + + private void clearEmergencySmsInfo() { + mOngoingEmergencySmsIds.clear(); + mIsTestEmergencyNumberForSms = false; + mSmsEmergencyModeFuture = null; + mSmsPhone = null; + } + /** * Returns {@code true} if any phones from PhoneFactory have radio on. */ @@ -669,6 +1000,59 @@ public class EmergencyStateTracker { Settings.Global.AIRPLANE_MODE_ON, 0) > 0; } + /** + * Ensures that the radio is switched on and that DDS is switched for emergency call/SMS. + * + *

+ * Once radio is on and DDS switched, must call setEmergencyMode() before completing the future + * and selecting emergency domain. EmergencyRegResult is required to determine domain and + * setEmergencyMode() is the only API that can receive it before starting domain selection. + * Once domain selection is finished, the actual emergency mode will be set when + * onEmergencyTransportChanged() is called. + * + * @param phone the {@code Phone} for the emergency call/SMS. + * @param emergencyType the emergency type to identify an emergency call or SMS. + * @param isTestEmergencyNumber a flag to inidicate whether the emergency call/SMS uses the test + * emergency number. + */ + private void turnOnRadioAndSwitchDds(Phone phone, @EmergencyType int emergencyType, + boolean isTestEmergencyNumber) { + final boolean isAirplaneModeOn = isAirplaneModeOn(mContext); + boolean needToTurnOnRadio = !isRadioOn() || isAirplaneModeOn; + + if (needToTurnOnRadio) { + Rlog.i(TAG, "turnOnRadioAndSwitchDds: phoneId=" + phone.getPhoneId() + " for " + + emergencyTypeToString(emergencyType)); + if (mRadioOnHelper == null) { + mRadioOnHelper = new RadioOnHelper(mContext); + } + + mRadioOnHelper.triggerRadioOnAndListen(new RadioOnStateListener.Callback() { + @Override + public void onComplete(RadioOnStateListener listener, boolean isRadioReady) { + if (!isRadioReady) { + // Could not turn radio on + Rlog.e(TAG, "Failed to turn on radio."); + completeEmergencyMode(emergencyType, DisconnectCause.POWER_OFF); + } else { + switchDdsAndSetEmergencyMode(phone, emergencyType); + } + } + + @Override + public boolean isOkToCall(Phone phone, int serviceState) { + // We currently only look to make sure that the radio is on before dialing. We + // should be able to make emergency calls at any time after the radio has been + // powered on and isn't in the UNAVAILABLE state, even if it is reporting the + // OUT_OF_SERVICE state. + return phone.getServiceStateTracker().isRadioOn(); + } + }, !isTestEmergencyNumber, phone, isTestEmergencyNumber); + } else { + switchDdsAndSetEmergencyMode(phone, emergencyType); + } + } + /** * If needed, block until the default data is switched for outgoing emergency call, or * timeout expires. @@ -679,7 +1063,7 @@ public class EmergencyStateTracker { * successfully or {@code false} if the operation timed out/failed. */ @VisibleForTesting - public void delayDialForDdsSwitch(Phone phone, Consumer completeConsumer) { + public void switchDdsDelayed(Phone phone, Consumer completeConsumer) { if (phone == null) { // Do not block indefinitely. completeConsumer.accept(false); @@ -694,9 +1078,9 @@ public class EmergencyStateTracker { mHandler.postDelayed(() -> timeout.complete(false), DEFAULT_DATA_SWITCH_TIMEOUT_MS); // Also ensure that the Consumer is completed on the main thread. CompletableFuture unused = future.acceptEitherAsync(timeout, completeConsumer, - phone.getContext().getMainExecutor()); + mHandler::post); } catch (Exception e) { - Rlog.w(TAG, "delayDialForDdsSwitch - exception= " + e.getMessage()); + Rlog.w(TAG, "switchDdsDelayed - exception= " + e.getMessage()); } } @@ -815,4 +1199,19 @@ public class EmergencyStateTracker { return ServiceState.STATE_IN_SERVICE == phone.getServiceState().getState() || phone.getServiceState().isEmergencyOnly(); } + + /** + * Checks whether both {@code Phone}s are same or not. + */ + private static boolean isSamePhone(Phone p1, Phone p2) { + return p1 != null && p2 != null && (p1.getPhoneId() == p2.getPhoneId()); + } + + private static String emergencyTypeToString(@EmergencyType int emergencyType) { + switch (emergencyType) { + case EMERGENCY_TYPE_CALL: return "CALL"; + case EMERGENCY_TYPE_SMS: return "SMS"; + default: return "UNKNOWN"; + } + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java index 213bd6eeff..aab7063043 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java @@ -16,7 +16,12 @@ package com.android.internal.telephony.emergency; +import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_CS_PS; +import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME; + import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_CALLBACK; +import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WLAN; import static com.android.internal.telephony.emergency.EmergencyConstants.MODE_EMERGENCY_WWAN; import static org.junit.Assert.assertEquals; @@ -28,12 +33,13 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -81,9 +87,13 @@ import java.util.function.Consumer; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class EmergencyStateTrackerTest extends TelephonyTest { - private static final String TEST_CALL_ID = "TC@TEST1"; + private static final String TEST_CALL_ID_2 = "TC@TEST2"; + private static final String TEST_SMS_ID = "1111"; + private static final String TEST_SMS_ID_2 = "2222"; private static final long TEST_ECM_EXIT_TIMEOUT_MS = 500; + private static final EmergencyRegResult E_REG_RESULT = new EmergencyRegResult( + EUTRAN, REGISTRATION_STATE_HOME, DOMAIN_CS_PS, true, true, 0, 1, "001", "01", "US"); @Mock EmergencyStateTracker.PhoneFactoryProxy mPhoneFactoryProxy; @Mock EmergencyStateTracker.PhoneSwitcherProxy mPhoneSwitcherProxy; @@ -136,19 +146,10 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Create test Phones and set radio off Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */, false /* isRadioOn */); - CarrierConfigManager cfgManager = (CarrierConfigManager) mContext - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( - CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, - null); - cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( - CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, - CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY); - cfgManager.getConfigForSubId(testPhone.getSubId()) - .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "150"); + setConfigForDdsSwitch(testPhone, null, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY, "150"); // Spy is used to capture consumer in delayDialForDdsSwitch EmergencyStateTracker spyEst = spy(emergencyStateTracker); - CompletableFuture unused = spyEst.startEmergencyCall(testPhone, TEST_CALL_ID, false); @@ -165,8 +166,8 @@ public class EmergencyStateTrackerTest extends TelephonyTest { callback.getValue().onComplete(null, true); ArgumentCaptor> completeConsumer = ArgumentCaptor .forClass(Consumer.class); - verify(spyEst).delayDialForDdsSwitch(eq(testPhone), completeConsumer.capture()); - verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(0) /* phoneId */ , + verify(spyEst).switchDdsDelayed(eq(testPhone), completeConsumer.capture()); + verify(mPhoneSwitcher).overrideDefaultDataForEmergency(eq(testPhone.getPhoneId()), eq(150) /* extensionTime */, any()); // After dds switch completes successfully, set emergency mode completeConsumer.getValue().accept(true); @@ -213,16 +214,8 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Create test Phones and set radio on Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */, true /* isRadioOn */); - CarrierConfigManager cfgManager = (CarrierConfigManager) mContext - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( - CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, - null); - cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( - CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, - CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK); - cfgManager.getConfigForSubId(testPhone.getSubId()) - .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"); + setConfigForDdsSwitch(testPhone, null, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK, "0"); CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); @@ -246,16 +239,8 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Create test Phones Phone testPhone = setupTestPhoneForEmergencyCall(false /* isRoaming */, true /* isRadioOn */); - CarrierConfigManager cfgManager = (CarrierConfigManager) mContext - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( - CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, - null); - cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( - CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, - CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY); - cfgManager.getConfigForSubId(testPhone.getSubId()) - .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"); + setConfigForDdsSwitch(testPhone, null, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY, "0"); CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); @@ -276,16 +261,8 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Create test Phones Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, true /* isRadioOn */); - CarrierConfigManager cfgManager = (CarrierConfigManager) mContext - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( - CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, - null); - cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( - CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, - CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY); - cfgManager.getConfigForSubId(testPhone.getSubId()) - .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"); + setConfigForDdsSwitch(testPhone, null, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_DP_ONLY, "0"); CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); @@ -310,18 +287,9 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Setup voice roaming scenario String testRoamingOperator = "001001"; testPhone.getServiceState().setOperatorName("TestTel", "TestTel", testRoamingOperator); - String[] roamingPlmns = new String[1]; - roamingPlmns[0] = testRoamingOperator; - CarrierConfigManager cfgManager = (CarrierConfigManager) mContext - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( - CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, - roamingPlmns); - cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( - CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, - CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK); - cfgManager.getConfigForSubId(testPhone.getSubId()) - .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"); + String[] roamingPlmns = new String[] { testRoamingOperator }; + setConfigForDdsSwitch(testPhone, roamingPlmns, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK, "0"); CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); @@ -347,18 +315,9 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Setup voice roaming scenario String testRoamingOperator = "001001"; testPhone.getServiceState().setOperatorName("TestTel", "TestTel", testRoamingOperator); - String[] roamingPlmns = new String[1]; - roamingPlmns[0] = testRoamingOperator; - CarrierConfigManager cfgManager = (CarrierConfigManager) mContext - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - cfgManager.getConfigForSubId(testPhone.getSubId()).putStringArray( - CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, - roamingPlmns); - cfgManager.getConfigForSubId(testPhone.getSubId()).putInt( - CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, - CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK); - cfgManager.getConfigForSubId(testPhone.getSubId()) - .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, "0"); + String[] roamingPlmns = new String[] { testRoamingOperator }; + setConfigForDdsSwitch(testPhone, roamingPlmns, + CarrierConfigManager.Gps.SUPL_EMERGENCY_MODE_TYPE_CP_FALLBACK, "0"); CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); @@ -381,6 +340,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Create test Phone Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, true /* isRadioOn */); + setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT); // Call startEmergencyCall() to set testPhone CompletableFuture future = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); @@ -389,18 +349,12 @@ public class EmergencyStateTrackerTest extends TelephonyTest { assertEquals((Integer) result, (Integer) DisconnectCause.NOT_DISCONNECTED); }); assertFalse(emergencyStateTracker.isInEmergencyCall()); - Handler handler = emergencyStateTracker.getHandler(); - Message msg = new Message(); - EmergencyRegResult regResult = new EmergencyRegResult(0, 0, 0, true, false, 0, 1, "testMcc", - "testMnc", "testIso"); - AsyncResult ar = new AsyncResult(msg, regResult, null); - msg.obj = ar; - msg.what = EmergencyStateTracker.MSG_SET_EMERGENCY_MODE_DONE; - handler.handleMessage(msg); + processAllMessages(); assertTrue(emergencyStateTracker.isInEmergencyCall()); - assertTrue(emergencyStateTracker.getEmergencyRegResult().equals(regResult)); + assertTrue(emergencyStateTracker.getEmergencyRegResult().equals(E_REG_RESULT)); + verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); } /** @@ -415,24 +369,21 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Create test Phone Phone testPhone = setupTestPhoneForEmergencyCall(true /* isRoaming */, true /* isRadioOn */); + setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(testPhone); // Call startEmergencyCall() to set testPhone CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); - Handler handler = emergencyStateTracker.getHandler(); - Message msg = new Message(); - EmergencyRegResult regResult = new EmergencyRegResult(0, 0, 0, true, false, 0, 1, "testMcc", - "testMnc", "testIso"); - AsyncResult ar = new AsyncResult(msg, regResult, null); - msg.obj = ar; - // Send message to set isInEmergencyCall to true - msg.what = EmergencyStateTracker.MSG_SET_EMERGENCY_MODE_DONE; - handler.handleMessage(msg); + processAllMessages(); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); - msg.what = EmergencyStateTracker.MSG_EXIT_EMERGENCY_MODE_DONE; - handler.handleMessage(msg); + emergencyStateTracker.endCall(TEST_CALL_ID); + processAllMessages(); assertFalse(emergencyStateTracker.isInEmergencyCall()); + verify(testPhone).exitEmergencyMode(any(Message.class)); } /** @@ -531,7 +482,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { */ @Test @SmallTest - public void onEmergencyTransportChanged_setsEmergencyMode() { + public void onEmergencyTransportChanged_setEmergencyMode() { EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); // Create test Phones @@ -541,7 +492,8 @@ public class EmergencyStateTrackerTest extends TelephonyTest { CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); - emergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + emergencyStateTracker.onEmergencyTransportChanged( + EmergencyStateTracker.EMERGENCY_TYPE_CALL, MODE_EMERGENCY_WWAN); verify(testPhone).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any()); } @@ -565,10 +517,8 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Set call to ACTIVE emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); // Set ecm as supported - CarrierConfigManager cfgManager = (CarrierConfigManager) mContext - .getSystemService(Context.CARRIER_CONFIG_SERVICE); - cfgManager.getConfigForSubId(testPhone.getSubId()).putBoolean( - CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, true); + setEcmSupportedConfig(testPhone, true); + assertFalse(emergencyStateTracker.isInEcm()); emergencyStateTracker.endCall(TEST_CALL_ID); @@ -622,6 +572,8 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Create test Phone Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(testPhone); CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); // Set call to ACTIVE @@ -629,12 +581,17 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Set ecm as supported setEcmSupportedConfig(testPhone, /* ecmSupported= */ true); + processAllMessages(); + emergencyStateTracker.endCall(TEST_CALL_ID); assertTrue(emergencyStateTracker.isInEcm()); + + processAllFutureMessages(); + // Verify exitEmergencyMode() is called after timeout - verify(testPhone, timeout(TEST_ECM_EXIT_TIMEOUT_MS + 1000).times(1)) - .exitEmergencyMode(any()); + verify(testPhone).exitEmergencyMode(any(Message.class)); + assertFalse(emergencyStateTracker.isInEmergencyMode()); } /** @@ -650,9 +607,12 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Create test Phone Phone testPhone = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(testPhone, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(testPhone); // Start emergency call then enter ECM CompletableFuture unused = emergencyStateTracker.startEmergencyCall(testPhone, TEST_CALL_ID, false); + processAllMessages(); // Set call to ACTIVE emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); emergencyStateTracker.onEmergencyCallDomainUpdated( @@ -661,12 +621,15 @@ public class EmergencyStateTrackerTest extends TelephonyTest { setEcmSupportedConfig(testPhone, /* ecmSupported= */ true); // End call to enter ECM emergencyStateTracker.endCall(TEST_CALL_ID); + processAllMessages(); + // verify ecbm states are correct assertTrue(emergencyStateTracker.isInEcm()); assertTrue(emergencyStateTracker.isInImsEcm()); assertFalse(emergencyStateTracker.isInCdmaEcm()); emergencyStateTracker.exitEmergencyCallbackMode(); + processAllFutureMessages(); // Ensure ECBM states are all correctly false after we exit. assertFalse(emergencyStateTracker.isInEcm()); @@ -682,14 +645,886 @@ public class EmergencyStateTrackerTest extends TelephonyTest { assertFalse(capturedIntents.get(1) .getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)); // Verify exitEmergencyMode() is called only once - verify(testPhone, timeout(TEST_ECM_EXIT_TIMEOUT_MS + 1000).times(1)) - .exitEmergencyMode(any()); + verify(testPhone).exitEmergencyMode(any(Message.class)); + } + + @Test + @SmallTest + public void testOnEmergencyTransportChangedUsingDifferentThread() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(() -> { + emergencyStateTracker.onEmergencyTransportChanged( + EmergencyStateTracker.EMERGENCY_TYPE_CALL, MODE_EMERGENCY_WWAN); + }); + processAllMessages(); + + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any()); + } + + @Test + @SmallTest + public void testStartEmergencyCallWithTestEmergencyNumber() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + CompletableFuture future = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, true); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + verify(phone0, never()).setEmergencyMode(anyInt(), any(Message.class)); + } + + @Test + @SmallTest + public void testStartEmergencyCallDuringActiveCall() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + // First active call + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + + // Second starting call + CompletableFuture future = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID_2, false); + + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + } + + @Test + @SmallTest + public void testStartEmergencyCallInEcm() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + setEcmSupportedConfig(phone0, true); + + // First active call + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + emergencyStateTracker.endCall(TEST_CALL_ID); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEcm()); + + // Second emergency call started. + CompletableFuture future = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID_2, false); + + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + } + + @Test + @SmallTest + public void testStartEmergencyCallUsingDifferenPhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + + // First emergency call + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + // Second emergency call + Phone phone1 = getPhone(1); + CompletableFuture future = emergencyStateTracker.startEmergencyCall(phone1, + TEST_CALL_ID_2, false); + + // Returns DisconnectCause#ERROR_UNSPECIFIED immediately. + assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), + Integer.valueOf(DisconnectCause.ERROR_UNSPECIFIED)); + } + + @Test + @SmallTest + public void testEndCallInEcm() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + setEcmSupportedConfig(phone0, true); + + // First active call + CompletableFuture future = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + emergencyStateTracker.endCall(TEST_CALL_ID); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + + // Second emergency call started. + future = emergencyStateTracker.startEmergencyCall(phone0, TEST_CALL_ID_2, false); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + emergencyStateTracker.onEmergencyTransportChanged( + EmergencyStateTracker.EMERGENCY_TYPE_CALL, MODE_EMERGENCY_WLAN); + emergencyStateTracker.endCall(TEST_CALL_ID_2); + processAllMessages(); + + // At this time, ECM is still running so still in ECM. + assertTrue(emergencyStateTracker.isInEmergencyMode()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WLAN), any(Message.class)); + verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class)); + verify(phone0, never()).exitEmergencyMode(any(Message.class)); + } + + @Test + @SmallTest + public void testStartEmergencySms() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ false, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + assertTrue(emergencyStateTracker.getEmergencyRegResult().equals(E_REG_RESULT)); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + } + + @Test + @SmallTest + public void testEndSms() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ false, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + assertTrue(emergencyStateTracker.getEmergencyRegResult().equals(E_REG_RESULT)); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + + verify(phone0).exitEmergencyMode(any(Message.class)); + assertFalse(emergencyStateTracker.isInEmergencyMode()); + } + + @Test + @SmallTest + public void testStartEmergencySmsWithTransportChange() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ false, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + emergencyStateTracker.onEmergencyTransportChanged( + EmergencyStateTracker.EMERGENCY_TYPE_SMS, MODE_EMERGENCY_WLAN); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.getEmergencyRegResult().equals(E_REG_RESULT)); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WLAN), any(Message.class)); + } + + @Test + @SmallTest + public void testStartEmergencySmsWithTestEmergencyNumber() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ false, + /* isRadioOn= */ true); + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, true); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + verify(phone0, never()).setEmergencyMode(anyInt(), any(Message.class)); + } + + @Test + @SmallTest + public void testStartEmergencySmsWhileSmsBeingSent() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ false, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + CompletableFuture unused = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID_2, false); + + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + } + + @Test + @SmallTest + public void testStartEmergencySmsWhileEmergencyModeBeingSet() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ false, + /* isRadioOn= */ true); + CompletableFuture unused = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID_2, false); + + // Returns DisconnectCause#ERROR_UNSPECIFIED immediately. + assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), + Integer.valueOf(DisconnectCause.ERROR_UNSPECIFIED)); + } + + @Test + @SmallTest + public void testStartEmergencySmsWhileEcmInProgress() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + setEcmSupportedConfig(phone0, true); + // Emergency call is ended and the emergency callback is entered. + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertTrue(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + + // Emergency SMS is being started. + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + + assertFalse(future.isDone()); + + // Completes the emergency mode setting - MODE_EMERGENCY_CALLBACK + processAllMessages(); + + verify(phone0, times(2)).setEmergencyMode(anyInt(), any(Message.class)); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + } + + @Test + @SmallTest + public void testStartEmergencySmsUsingDifferentPhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ false, + /* isRadioOn= */ true); + CompletableFuture unused = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + + Phone phone1 = getPhone(1); + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone1, + TEST_SMS_ID_2, false); + + // Returns DisconnectCause#ERROR_UNSPECIFIED immediately. + assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), + Integer.valueOf(DisconnectCause.ERROR_UNSPECIFIED)); + } + + @Test + @SmallTest + public void testStartEmergencyCallActiveAndSmsOnSamePhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + // Emergency call is in active. + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + + // Emergency SMS is being started. + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + } + + @Test + @SmallTest + public void testStartEmergencyCallInProgressAndSmsOnSamePhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + // Emergency call is in progress. + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Message.class); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), msgCaptor.capture()); + + // Emergency SMS is being started. + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + + assertFalse(future.isDone()); + + Message msg = msgCaptor.getValue(); + AsyncResult.forMessage(msg, E_REG_RESULT, null); + msg.sendToTarget(); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyCall()); + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + } + + @Test + @SmallTest + public void testStartEmergencySmsActiveAndCallOnSamePhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(phone0); + // Emergency SMS is in active. + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + // Emergency call is being started. + future = emergencyStateTracker.startEmergencyCall(phone0, TEST_CALL_ID, false); + processAllMessages(); + + verify(phone0).exitEmergencyMode(any(Message.class)); + verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + } + + @Test + @SmallTest + public void testStartEmergencySmsInProgressAndCallOnSamePhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForExitEmergencyMode(phone0); + // Emergency SMS is in progress. + CompletableFuture smsFuture = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + ArgumentCaptor smsCaptor = ArgumentCaptor.forClass(Message.class); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), smsCaptor.capture()); + + // Emergency call is being started. + CompletableFuture callFuture = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + + assertFalse(smsFuture.isDone()); + assertFalse(callFuture.isDone()); + + // Response message for setEmergencyMode by SMS. + Message msg = smsCaptor.getValue(); + AsyncResult.forMessage(msg, E_REG_RESULT, null); + msg.sendToTarget(); + processAllMessages(); + + // Exit emergency mode and set the emergency mode again by the call when the exit result + // is received for obtaining the latest EmergencyRegResult. + verify(phone0).exitEmergencyMode(any(Message.class)); + ArgumentCaptor callCaptor = ArgumentCaptor.forClass(Message.class); + verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), callCaptor.capture()); + + // Response message for setEmergencyMode by call. + msg = callCaptor.getAllValues().get(1); + AsyncResult.forMessage(msg, E_REG_RESULT, null); + msg.sendToTarget(); + processAllMessages(); + + // Expect: DisconnectCause#NOT_DISCONNECTED + assertEquals(smsFuture.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(callFuture.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + } + + @Test + @SmallTest + public void testStartEmergencyCallAndSmsOnDifferentPhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + // Emergency call is in active. + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + + // Emergency SMS is being started using the different phone. + Phone phone1 = getPhone(1); + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone1, + TEST_SMS_ID, false); + + // Returns DisconnectCause#ERROR_UNSPECIFIED immediately. + assertEquals(future.getNow(DisconnectCause.NOT_DISCONNECTED), + Integer.valueOf(DisconnectCause.ERROR_UNSPECIFIED)); + } + + @Test + @SmallTest + public void testStartEmergencySmsActiveAndCallOnDifferentPhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(phone0); + // Emergency SMS is in active. + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + // Emergency call is being started using the different phone. + Phone phone1 = getPhone(1); + setUpAsyncResultForSetEmergencyMode(phone1, E_REG_RESULT); + future = emergencyStateTracker.startEmergencyCall(phone1, TEST_CALL_ID, false); + processAllMessages(); + + verify(phone0).exitEmergencyMode(any(Message.class)); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + verify(phone1).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + } + + @Test + @SmallTest + public void testStartEmergencySmsInProgressAndCallOnDifferentPhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForExitEmergencyMode(phone0); + // Emergency SMS is in progress. + CompletableFuture smsFuture = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + ArgumentCaptor smsCaptor = ArgumentCaptor.forClass(Message.class); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), smsCaptor.capture()); + + // Emergency call is being started using the different phone. + Phone phone1 = getPhone(1); + CompletableFuture callFuture = emergencyStateTracker.startEmergencyCall(phone1, + TEST_CALL_ID, false); + + assertFalse(smsFuture.isDone()); + assertFalse(callFuture.isDone()); + + // Response message for setEmergencyMode by SMS. + Message msg = smsCaptor.getValue(); + AsyncResult.forMessage(msg, E_REG_RESULT, null); + msg.sendToTarget(); + processAllMessages(); + + // Exit emergency mode and set the emergency mode again by the call when the exit result + // is received for obtaining the latest EmergencyRegResult. + verify(phone0).exitEmergencyMode(any(Message.class)); + ArgumentCaptor callCaptor = ArgumentCaptor.forClass(Message.class); + verify(phone1).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), callCaptor.capture()); + + // Response message for setEmergencyMode by call. + msg = callCaptor.getValue(); + AsyncResult.forMessage(msg, E_REG_RESULT, null); + msg.sendToTarget(); + processAllMessages(); + + // Expect: DisconnectCause#OUTGOING_EMERGENCY_CALL_PLACED + assertEquals(smsFuture.getNow(DisconnectCause.NOT_DISCONNECTED), + Integer.valueOf(DisconnectCause.OUTGOING_EMERGENCY_CALL_PLACED)); + // Expect: DisconnectCause#NOT_DISCONNECTED. + assertEquals(callFuture.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + } + + @Test + @SmallTest + public void testExitEmergencyModeCallAndSmsOnSamePhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(phone0); + setEcmSupportedConfig(phone0, false); + // Emergency call is in active. + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + + // Emergency SMS is being started. + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + + emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + processAllMessages(); + + assertFalse(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).exitEmergencyMode(any(Message.class)); + } + + @Test + @SmallTest + public void testExitEmergencyModeSmsAndCallOnSamePhone() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(phone0); + setEcmSupportedConfig(phone0, false); + // Emergency call is in active. + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + + // Emergency SMS is being started. + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + + emergencyStateTracker.endCall(TEST_CALL_ID); + processAllMessages(); + + assertFalse(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).exitEmergencyMode(any(Message.class)); + } + + @Test + @SmallTest + public void testExitEmergencyModeCallAndSmsOnSamePhoneWhenEcmSupported() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(phone0); + setEcmSupportedConfig(phone0, true); + // Emergency call is in active. + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + + // Emergency SMS is being started. + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + emergencyStateTracker.endCall(TEST_CALL_ID); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + + emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + processAllMessages(); + + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class)); + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + + // ECM timeout. + processAllFutureMessages(); + + assertFalse(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).exitEmergencyMode(any(Message.class)); + } + + @Test + @SmallTest + public void testExitEmergencyModeCallAndSmsOnSamePhoneWhenEcmSupportedAndModeChanged() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(phone0); + setEcmSupportedConfig(phone0, true); + // Emergency call is in active. + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + + // Emergency SMS is being started. + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + emergencyStateTracker.endCall(TEST_CALL_ID); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + + emergencyStateTracker.onEmergencyTransportChanged( + EmergencyStateTracker.EMERGENCY_TYPE_SMS, MODE_EMERGENCY_WWAN); + emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + processAllMessages(); + + // Enter emergency callback mode and emergency mode changed by SMS end. + verify(phone0, times(2)).setEmergencyMode(eq(MODE_EMERGENCY_CALLBACK), any(Message.class)); + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + + // ECM timeout. + processAllFutureMessages(); + + assertFalse(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).exitEmergencyMode(any(Message.class)); + } + + @Test + @SmallTest + public void testExitEmergencyModeSmsAndCallOnSamePhoneWhenEcmSupported() { + EmergencyStateTracker emergencyStateTracker = setupEmergencyStateTracker( + /* isSuplDdsSwitchRequiredForEmergencyCall= */ true); + Phone phone0 = setupTestPhoneForEmergencyCall(/* isRoaming= */ true, + /* isRadioOn= */ true); + setUpAsyncResultForSetEmergencyMode(phone0, E_REG_RESULT); + setUpAsyncResultForExitEmergencyMode(phone0); + setEcmSupportedConfig(phone0, true); + // Emergency call is in active. + CompletableFuture unused = emergencyStateTracker.startEmergencyCall(phone0, + TEST_CALL_ID, false); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).setEmergencyMode(eq(MODE_EMERGENCY_WWAN), any(Message.class)); + + emergencyStateTracker.onEmergencyCallStateChanged(Call.State.ACTIVE, TEST_CALL_ID); + + // Emergency SMS is being started. + CompletableFuture future = emergencyStateTracker.startEmergencySms(phone0, + TEST_SMS_ID, false); + + // Returns DisconnectCause#NOT_DISCONNECTED immediately. + assertEquals(future.getNow(DisconnectCause.ERROR_UNSPECIFIED), + Integer.valueOf(DisconnectCause.NOT_DISCONNECTED)); + + emergencyStateTracker.endSms(TEST_SMS_ID, getTestEmergencyNumber()); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + + emergencyStateTracker.endCall(TEST_CALL_ID); + processAllMessages(); + + assertTrue(emergencyStateTracker.isInEmergencyMode()); + assertTrue(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + + // ECM timeout. + processAllFutureMessages(); + + assertFalse(emergencyStateTracker.isInEmergencyMode()); + assertFalse(emergencyStateTracker.isInEcm()); + assertFalse(emergencyStateTracker.isInEmergencyCall()); + verify(phone0).exitEmergencyMode(any(Message.class)); } private EmergencyStateTracker setupEmergencyStateTracker( boolean isSuplDdsSwitchRequiredForEmergencyCall) { doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher(); - return new EmergencyStateTracker(mContext, Looper.getMainLooper(), + doNothing().when(mPhoneSwitcher).overrideDefaultDataForEmergency( + anyInt(), anyInt(), any()); + return new EmergencyStateTracker(mContext, mTestableLooper.getLooper(), isSuplDdsSwitchRequiredForEmergencyCall, mPhoneFactoryProxy, mPhoneSwitcherProxy, mTelephonyManagerProxy, mRadioOnHelper, TEST_ECM_EXIT_TIMEOUT_MS); } @@ -711,8 +1546,13 @@ public class EmergencyStateTrackerTest extends TelephonyTest { return testPhone0; } + private Phone getPhone(int phoneId) { + Phone[] phones = mPhoneFactoryProxy.getPhones(); + return phones[phoneId]; + } + private Phone makeTestPhone(int phoneId, int serviceState, boolean isEmergencyOnly) { - Phone phone = mock(GsmCdmaPhone.class); + GsmCdmaPhone phone = mock(GsmCdmaPhone.class); ServiceState testServiceState = new ServiceState(); testServiceState.setState(serviceState); testServiceState.setEmergencyOnly(isEmergencyOnly); @@ -725,6 +1565,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Initialize the phone as a CDMA phone for now for ease of testing ECBM. // Tests can individually override this to GSM if required for the test. doReturn(PhoneConstants.PHONE_TYPE_CDMA).when(phone).getPhoneType(); + doNothing().when(phone).notifyEmergencyCallRegistrants(anyBoolean()); return phone; } @@ -735,4 +1576,38 @@ public class EmergencyStateTrackerTest extends TelephonyTest { CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALLBACK_MODE_SUPPORTED_BOOL, ecmSupported); } + + private void setConfigForDdsSwitch(Phone phone, String[] roaminPlmns, + int suplEmergencyModeType, String esExtensionSec) { + CarrierConfigManager cfgManager = (CarrierConfigManager) mContext + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + cfgManager.getConfigForSubId(phone.getSubId()).putStringArray( + CarrierConfigManager.Gps.KEY_ES_SUPL_DATA_PLANE_ONLY_ROAMING_PLMN_STRING_ARRAY, + roaminPlmns); + cfgManager.getConfigForSubId(phone.getSubId()).putInt( + CarrierConfigManager.Gps.KEY_ES_SUPL_CONTROL_PLANE_SUPPORT_INT, + suplEmergencyModeType); + cfgManager.getConfigForSubId(phone.getSubId()) + .putString(CarrierConfigManager.Gps.KEY_ES_EXTENSION_SEC_STRING, esExtensionSec); + } + + private void setUpAsyncResultForSetEmergencyMode(Phone phone, EmergencyRegResult regResult) { + doAnswer((invocation) -> { + Object[] args = invocation.getArguments(); + final Message msg = (Message) args[1]; + AsyncResult.forMessage(msg, regResult, null); + msg.sendToTarget(); + return null; + }).when(phone).setEmergencyMode(anyInt(), any(Message.class)); + } + + private void setUpAsyncResultForExitEmergencyMode(Phone phone) { + doAnswer((invocation) -> { + Object[] args = invocation.getArguments(); + final Message msg = (Message) args[0]; + AsyncResult.forMessage(msg, null, null); + msg.sendToTarget(); + return null; + }).when(phone).exitEmergencyMode(any(Message.class)); + } } \ No newline at end of file -- GitLab From b4847f51c216074b196d550d4c91da24093a06e3 Mon Sep 17 00:00:00 2001 From: Hwangoo Park Date: Thu, 2 Mar 2023 04:20:09 +0000 Subject: [PATCH 481/656] Add emergency type(call/sms) onEmergencyTransportChanged This change is added to distinguish the emergency type (call/sms) when the onEmergencyTransportChanged method calls so that EmergencyStateTracker changes the correct emergency transport for each emergency type. Bug: 267220850 Test: atest EmergencyCallDomainSelectionConnectionTest Test: atest EmergencySmsDomainSelectionConnectionTest Change-Id: If6f4c1375bb8aa55fd5fc739cf6e09f25b0b1713 --- ...mergencyCallDomainSelectionConnection.java | 6 +++-- ...EmergencySmsDomainSelectionConnection.java | 6 +++-- .../emergency/EmergencyStateTracker.java | 14 ------------ ...encyCallDomainSelectionConnectionTest.java | 9 +++++--- ...gencySmsDomainSelectionConnectionTest.java | 22 +++++++++++++++---- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java index 5808c17e37..5f3c3b69e9 100644 --- a/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnection.java @@ -85,7 +85,8 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne /** {@inheritDoc} */ @Override public void onWlanSelected(boolean useEmergencyPdn) { - mEmergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WLAN); + mEmergencyStateTracker.onEmergencyTransportChanged( + EmergencyStateTracker.EMERGENCY_TYPE_CALL, MODE_EMERGENCY_WLAN); if (useEmergencyPdn) { AccessNetworksManager anm = mPhone.getAccessNetworksManager(); int transportType = anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY); @@ -103,7 +104,8 @@ public class EmergencyCallDomainSelectionConnection extends DomainSelectionConne /** {@inheritDoc} */ @Override public void onWwanSelected() { - mEmergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + mEmergencyStateTracker.onEmergencyTransportChanged( + EmergencyStateTracker.EMERGENCY_TYPE_CALL, MODE_EMERGENCY_WWAN); } /** {@inheritDoc} */ diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java index bf8cccafd9..067d761886 100644 --- a/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java @@ -60,7 +60,8 @@ public class EmergencySmsDomainSelectionConnection extends SmsDomainSelectionCon return; } - mEmergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WLAN); + mEmergencyStateTracker.onEmergencyTransportChanged( + EmergencyStateTracker.EMERGENCY_TYPE_SMS, MODE_EMERGENCY_WLAN); // Change the transport type if the current preferred transport type for an emergency // is not {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}. @@ -79,7 +80,8 @@ public class EmergencySmsDomainSelectionConnection extends SmsDomainSelectionCon @Override public void onWwanSelected() { - mEmergencyStateTracker.onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + mEmergencyStateTracker.onEmergencyTransportChanged( + EmergencyStateTracker.EMERGENCY_TYPE_SMS, MODE_EMERGENCY_WWAN); } @Override diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java index 6e2e32dd89..b5a886be82 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java @@ -672,20 +672,6 @@ public class EmergencyStateTracker { return mLastEmergencyRegResult; } - /** - * Handles emergency transport change by setting new emergency mode. - * - * @param mode the new emergency mode - */ - public void onEmergencyTransportChanged(@EmergencyConstants.EmergencyMode int mode) { - // The phone for call is prioritized. - if (mPhone != null && mOngoingCallId != null) { - onEmergencyTransportChanged(EMERGENCY_TYPE_CALL, mode); - } else if (mSmsPhone != null) { - onEmergencyTransportChanged(EMERGENCY_TYPE_SMS, mode); - } - } - /** * Handles emergency transport change by setting new emergency mode. * diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java index e8b0d433f5..0c64b82072 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencyCallDomainSelectionConnectionTest.java @@ -122,7 +122,8 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { assertTrue(future.isDone()); assertEquals((long) DOMAIN_NON_3GPP_PS, (long) future.get()); - verify(mEmergencyStateTracker).onEmergencyTransportChanged(MODE_EMERGENCY_WLAN); + verify(mEmergencyStateTracker).onEmergencyTransportChanged( + eq(EmergencyStateTracker.EMERGENCY_TYPE_CALL), eq(MODE_EMERGENCY_WLAN)); } @Test @@ -154,7 +155,8 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { wwanCallback = mTransportCallback.onWwanSelected(); assertFalse(future.isDone()); - verify(mEmergencyStateTracker).onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + verify(mEmergencyStateTracker).onEmergencyTransportChanged( + eq(EmergencyStateTracker.EMERGENCY_TYPE_CALL), eq(MODE_EMERGENCY_WWAN)); wwanCallback.onDomainSelected(DOMAIN_CS, false); @@ -191,7 +193,8 @@ public class EmergencyCallDomainSelectionConnectionTest extends TelephonyTest { wwanCallback = mTransportCallback.onWwanSelected(); assertFalse(future.isDone()); - verify(mEmergencyStateTracker).onEmergencyTransportChanged(MODE_EMERGENCY_WWAN); + verify(mEmergencyStateTracker).onEmergencyTransportChanged( + eq(EmergencyStateTracker.EMERGENCY_TYPE_CALL), eq(MODE_EMERGENCY_WWAN)); wwanCallback.onDomainSelected(DOMAIN_PS, true); diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java index ff951d566b..f4a743e4a9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java @@ -108,6 +108,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnWlanSelected() throws Exception { when(mAnm.getPreferredTransport(anyInt())) .thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); @@ -121,11 +122,13 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { processAllMessages(); assertTrue(future.isDone()); - verify(mEmergencyStateTracker).onEmergencyTransportChanged(eq(MODE_EMERGENCY_WLAN)); + verify(mEmergencyStateTracker).onEmergencyTransportChanged( + eq(EmergencyStateTracker.EMERGENCY_TYPE_SMS), eq(MODE_EMERGENCY_WLAN)); } @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnWlanSelectedWithDifferentTransportType() throws Exception { when(mAnm.getPreferredTransport(anyInt())).thenReturn( AccessNetworkConstants.TRANSPORT_TYPE_WWAN, @@ -141,7 +144,8 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Integer.class); - verify(mEmergencyStateTracker).onEmergencyTransportChanged(eq(MODE_EMERGENCY_WLAN)); + verify(mEmergencyStateTracker).onEmergencyTransportChanged( + eq(EmergencyStateTracker.EMERGENCY_TYPE_SMS), eq(MODE_EMERGENCY_WLAN)); verify(mAnm).registerForQualifiedNetworksChanged( handlerCaptor.capture(), msgCaptor.capture()); verify(mPhone).notifyEmergencyDomainSelected( @@ -158,6 +162,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnWlanSelectedWithDifferentTransportTypeWhilePreferredTransportChanged() throws Exception { when(mAnm.getPreferredTransport(anyInt())).thenReturn( @@ -178,7 +183,8 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(Integer.class); - verify(mEmergencyStateTracker).onEmergencyTransportChanged(eq(MODE_EMERGENCY_WLAN)); + verify(mEmergencyStateTracker).onEmergencyTransportChanged( + eq(EmergencyStateTracker.EMERGENCY_TYPE_SMS), eq(MODE_EMERGENCY_WLAN)); verify(mAnm).registerForQualifiedNetworksChanged( handlerCaptor.capture(), msgCaptor.capture()); verify(mPhone).notifyEmergencyDomainSelected( @@ -198,11 +204,13 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { public void testOnWwanSelected() throws Exception { mDsConnection.onWwanSelected(); - verify(mEmergencyStateTracker).onEmergencyTransportChanged(eq(MODE_EMERGENCY_WWAN)); + verify(mEmergencyStateTracker).onEmergencyTransportChanged( + eq(EmergencyStateTracker.EMERGENCY_TYPE_SMS), eq(MODE_EMERGENCY_WWAN)); } @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnDomainSelectedPs() throws Exception { when(mAnm.getPreferredTransport(anyInt())) .thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); @@ -220,6 +228,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnDomainSelectedPsWithDifferentTransportType() throws Exception { when(mAnm.getPreferredTransport(anyInt())).thenReturn( AccessNetworkConstants.TRANSPORT_TYPE_WLAN, @@ -251,6 +260,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnDomainSelectedPsWithDifferentTransportTypeAndNotChanged() throws Exception { when(mAnm.getPreferredTransport(anyInt())).thenReturn( AccessNetworkConstants.TRANSPORT_TYPE_WLAN, @@ -282,6 +292,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnDomainSelectedPsWithDifferentTransportTypeWhilePreferredTransportChanged() throws Exception { when(mAnm.getPreferredTransport(anyInt())).thenReturn( @@ -318,6 +329,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnDomainSelectedCs() throws Exception { when(mAnm.getPreferredTransport(anyInt())) .thenReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN); @@ -335,6 +347,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testFinishSelection() throws Exception { when(mAnm.getPreferredTransport(anyInt())).thenReturn( AccessNetworkConstants.TRANSPORT_TYPE_WLAN, @@ -365,6 +378,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testFinishSelectionAfterDomainSelectionCompleted() throws Exception { when(mAnm.getPreferredTransport(anyInt())).thenReturn( AccessNetworkConstants.TRANSPORT_TYPE_WLAN, -- GitLab From 6d0a5032b10933e3bcfa4185abb2d32312a8f631 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 2 Mar 2023 13:46:12 -0800 Subject: [PATCH 482/656] Fixed building the incorrect phone account using iccid Phone account has switched to subId after ag/17240597. Making the corresponding changes. Bug: 268399273 Test: Basic phone functionality tests Change-Id: I73d346d168b7b1f218cb845783bacae60b84a224 --- .../internal/telephony/MissedIncomingCallSmsFilter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java b/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java index 5932f9ed0c..e8b81968b1 100644 --- a/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java +++ b/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java @@ -228,10 +228,10 @@ public class MissedIncomingCallSmsFilter { return false; } - // Create phone account. The logic is copied from PhoneUtils.makePstnPhoneAccountHandle. + // Create phone account. The logic is copied from PhoneUtils.makePstnPhoneAccountHandleWithId. private static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) { return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT, - String.valueOf(phone.getFullIccSerialNumber())); + String.valueOf(phone.getSubId()), phone.getUserHandle()); } /** -- GitLab From fdd94b8caed396860a4f03b4848972ce586de418 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Sun, 26 Feb 2023 11:57:19 -0800 Subject: [PATCH 483/656] Fix minor bugs with calling APIs through vendor satellite service Return null instead of SatelliteException if the error is ERROR_NONE Handle SatelliteException properly to get the error code Test: atest SatelliteManagerTest E2E with vendor satellite service Bug: 270868171 Change-Id: I8d141c3223a7f6ab3c46ad16cc34a81f8be5468b --- .../telephony/satellite/SatelliteModemInterface.java | 6 ++++-- .../telephony/satellite/SatelliteServiceUtils.java | 7 ++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 91f720cf70..168f42ede8 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -998,13 +998,15 @@ public class SatelliteModemInterface { } public boolean isSatelliteServiceSupported() { - // TODO: update this method + // TODO: update this method to check a device config instead return mIsSatelliteServiceSupported; } private static void sendMessageWithResult(@NonNull Message message, @Nullable Object result, @SatelliteManager.SatelliteError int error) { - AsyncResult.forMessage(message, result, new SatelliteException(error)); + SatelliteException exception = error == SatelliteManager.SATELLITE_ERROR_NONE + ? null : new SatelliteException(error); + AsyncResult.forMessage(message, result, exception); message.sendToTarget(); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java index 6e45300f6e..09749066ef 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.AsyncResult; import android.telephony.Rlog; -import android.telephony.SubscriptionManager; import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; @@ -221,10 +220,12 @@ public class SatelliteServiceUtils { } else { errorCode = SatelliteManager.SATELLITE_ERROR; if (ar.exception instanceof CommandException) { - CommandException.Error error = - ((CommandException) (ar.exception)).getCommandError(); + CommandException.Error error = ((CommandException) ar.exception).getCommandError(); errorCode = RILUtils.convertToSatelliteError(error); loge(caller + " CommandException: " + ar.exception); + } else if (ar.exception instanceof SatelliteManager.SatelliteException) { + errorCode = ((SatelliteManager.SatelliteException) ar.exception).getErrorCode(); + loge(caller + " SatelliteException: " + ar.exception); } else { loge(caller + " unknown exception: " + ar.exception); } -- GitLab From 144da62e148608b1eec033cb5197e78cb9196d4a Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 2 Mar 2023 14:50:03 -0800 Subject: [PATCH 484/656] Fixed crash when LPA is not available The embedded subscription result could be null when LPA is not available on AOSP devices. Bug: 271349925 Test: v2/android-aosp-tests/device-boot-health-check-extra on aosp_panther-userdebug Test: Basic phone functionality tests Change-Id: I3a7cbcdadf30660b73611d13e1fdd8d2cc781f01 --- .../subscription/SubscriptionManagerService.java | 9 +++++++-- .../SubscriptionManagerServiceTest.java | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index e181f29507..7f3c23fd04 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1025,7 +1025,7 @@ public class SubscriptionManagerService extends ISub.Stub { mBackgroundHandler.post(() -> { // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but // they are filtered out of list calls as long as EuiccManager.isEnabled returns false). - if (mEuiccManager == null || !mEuiccManager.isEnabled()) { + if (mEuiccManager == null || !mEuiccManager.isEnabled() || mEuiccController == null) { loge("updateEmbeddedSubscriptions: eUICC not enabled"); if (callback != null) { callback.run(); @@ -1038,7 +1038,7 @@ public class SubscriptionManagerService extends ISub.Stub { for (UiccSlot slot : mUiccController.getUiccSlots()) { if (slot != null) { - log(" " + slot.toString()); + log(" " + slot); } } @@ -1046,6 +1046,11 @@ public class SubscriptionManagerService extends ISub.Stub { GetEuiccProfileInfoListResult result = mEuiccController .blockingGetEuiccProfileInfoList(cardId); logl("updateEmbeddedSubscriptions: cardId=" + cardId + ", result=" + result); + if (result == null) { + //TODO: Add back-off retry in the future if needed. + loge("Failed to get euicc profiles."); + continue; + } if (result.getResult() != EuiccService.RESULT_OK) { loge("Failed to get euicc profile info. result=" 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 765a62e93e..ae4bc4a493 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -822,6 +822,21 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfo.getNativeAccessRules()).isEqualTo(FAKE_NATIVE_ACCESS_RULES2); } + @Test + public void testUpdateEmbeddedSubscriptionsNullResult() { + // Grant READ_PHONE_STATE permission. + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); + + doReturn(null).when(mEuiccController).blockingGetEuiccProfileInfoList(anyInt()); + + mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1, 2), null); + processAllMessages(); + + List subInfoList = mSubscriptionManagerServiceUT + .getAllSubInfoList(CALLING_PACKAGE, CALLING_FEATURE); + assertThat(subInfoList).isEmpty(); + } + @Test public void testGetActiveSubscriptionInfo() { insertSubscription(FAKE_SUBSCRIPTION_INFO1); -- GitLab From 973d9769db41909ae09f898295592a92e016c1fc Mon Sep 17 00:00:00 2001 From: Hyunho Date: Wed, 22 Feb 2023 13:26:36 +0000 Subject: [PATCH 485/656] Fix a potential issue with the state machine of EuiccConnector When the service is dies, the binder is disconnected and the state is transition to the Disconnected state. If the service is not restarted for a period of time afterward, it will transition to the Available state. Fixed an issue that prevented service_connected from being handled if the service is restarted in the Available state Bug: b/270110619 Test: atest EuiccConnectorTest Change-Id: Idef5dfb024f6c7ad82b29060d58d549d99531182 Merged-In: Idef5dfb024f6c7ad82b29060d58d549d99531182 --- .../telephony/euicc/EuiccConnector.java | 9 ++++++- .../telephony/euicc/EuiccConnectorTest.java | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/euicc/EuiccConnector.java b/src/java/com/android/internal/telephony/euicc/EuiccConnector.java index 7d46a9ac78..ef19b9ad10 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccConnector.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccConnector.java @@ -101,7 +101,8 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { * true or onServiceDisconnected is called (and no package change has occurred which should * force us to reestablish the binding). */ - private static final int BIND_TIMEOUT_MILLIS = 30000; + @VisibleForTesting + static final int BIND_TIMEOUT_MILLIS = 30000; /** * Maximum amount of idle time to hold the binding while in {@link ConnectedState}. After this, @@ -556,6 +557,11 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { callback); } + @VisibleForTesting + public final IEuiccService getBinder() { + return mEuiccService; + } + /** * State in which no EuiccService is available. * @@ -693,6 +699,7 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { } return HANDLED; } else if (message.what == CMD_CONNECT_TIMEOUT) { + unbind(); transitionTo(mAvailableState); return HANDLED; } else if (isEuiccCommand(message.what)) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java index 93c914227e..d4850c814f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccConnectorTest.java @@ -17,6 +17,7 @@ package com.android.internal.telephony.euicc; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -354,6 +355,29 @@ public class EuiccConnectorTest extends TelephonyTest { assertEquals(mConnector.mAvailableState, mConnector.getCurrentState()); } + @Test + public void testConnectedState_serviceDisconnected() throws Exception { + // Kick off the asynchronous command. + prepareEuiccApp(true /* hasPermission */, true /* requiresBindPermission */, + true /* hasPriority */); + mConnector = new EuiccConnector(mContext, mLooper.getLooper()); + mConnector.getEid(CARD_ID, new EuiccConnector.GetEidCommandCallback() { + @Override public void onGetEidComplete(String eid) {} + @Override public void onEuiccServiceUnavailable() {} + }); + mLooper.dispatchAll(); + assertEquals(mConnector.mConnectedState, mConnector.getCurrentState()); + // Now, pretend the remote process died. + mConnector.onServiceDisconnected(null /* name */); + mLooper.dispatchAll(); + assertEquals(mConnector.mDisconnectedState, mConnector.getCurrentState()); + // After binder timeout, should now drop back to available state. + mLooper.moveTimeForward(EuiccConnector.BIND_TIMEOUT_MILLIS); + mLooper.dispatchAll(); + assertEquals(mConnector.mAvailableState, mConnector.getCurrentState()); + assertNull(mConnector.getBinder()); + } + private void prepareEuiccApp( boolean hasPermission, boolean requiresBindPermission, boolean hasPriority) { when(mPackageManager.checkPermission( -- GitLab From 9bbe74bae08fc0854d847b74036f9b5a55f977b4 Mon Sep 17 00:00:00 2001 From: Hwangoo Park Date: Fri, 3 Mar 2023 09:13:45 +0000 Subject: [PATCH 486/656] Ignore ECBM enter/exit event on Phone when domain selection supports Basically, the ImsService/modem should not be sending the ECBM enter event when domain selection is enabled. However, if the ImsService/modem sends the ECBM enter event, the framework may malfunction. In order to avoid this unexpected behavior, the existing implementation for ECBM enter/exit event handling will be ignored on ImsPhone/GsmCdmaPhone when domain selection is enabled. Instead, this ECBM enter/exit event will be handled by the EmergencyStateTracker when domain selection is enabled. Bug: 270674175 Test: atest GsmCdmaPhoneTest, ImsPhoneTest Change-Id: I589bc27046e1b1633548e0f13c5c9efed88922aa --- .../internal/telephony/GsmCdmaPhone.java | 31 ++++-- .../internal/telephony/imsphone/ImsPhone.java | 8 ++ .../internal/telephony/GsmCdmaPhoneTest.java | 95 +++++++++++++++++++ .../telephony/imsphone/ImsPhoneTest.java | 15 +++ 4 files changed, 142 insertions(+), 7 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 1e02aa8a33..87e88b4be9 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -106,6 +106,7 @@ import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.domainselection.DomainSelectionResolver; import com.android.internal.telephony.emergency.EmergencyNumberTracker; +import com.android.internal.telephony.emergency.EmergencyStateTracker; import com.android.internal.telephony.gsm.GsmMmiCode; import com.android.internal.telephony.gsm.SsData; import com.android.internal.telephony.gsm.SuppServiceNotification; @@ -517,8 +518,12 @@ public class GsmCdmaPhone extends Phone { // This is needed to handle phone process crashes mIsPhoneInEcmState = getInEcmMode(); if (mIsPhoneInEcmState) { - // Send a message which will invoke handleExitEmergencyCallbackMode - mCi.exitEmergencyCallbackMode(null); + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + EmergencyStateTracker.getInstance().exitEmergencyCallbackMode(); + } else { + // Send a message which will invoke handleExitEmergencyCallbackMode + mCi.exitEmergencyCallbackMode(null); + } } mCi.setPhoneType(PhoneConstants.PHONE_TYPE_CDMA); @@ -3135,12 +3140,16 @@ public class GsmCdmaPhone extends Phone { logd("Event EVENT_MODEM_RESET Received" + " isInEcm = " + isInEcm() + " isPhoneTypeGsm = " + isPhoneTypeGsm() + " mImsPhone = " + mImsPhone); if (isInEcm()) { - if (isPhoneTypeGsm()) { - if (mImsPhone != null) { - mImsPhone.handleExitEmergencyCallbackMode(); - } + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + EmergencyStateTracker.getInstance().exitEmergencyCallbackMode(); } else { - handleExitEmergencyCallbackMode(msg); + if (isPhoneTypeGsm()) { + if (mImsPhone != null) { + mImsPhone.handleExitEmergencyCallbackMode(); + } + } else { + handleExitEmergencyCallbackMode(msg); + } } } } @@ -3913,6 +3922,10 @@ public class GsmCdmaPhone extends Phone { //CDMA private void handleEnterEmergencyCallbackMode(Message msg) { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + Rlog.d(LOG_TAG, "DomainSelection enabled: ignore ECBM enter event."); + return; + } if (DBG) { Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode, isInEcm()=" + isInEcm()); @@ -3936,6 +3949,10 @@ public class GsmCdmaPhone extends Phone { //CDMA private void handleExitEmergencyCallbackMode(Message msg) { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + Rlog.d(LOG_TAG, "DomainSelection enabled: ignore ECBM exit event."); + return; + } AsyncResult ar = (AsyncResult)msg.obj; if (DBG) { Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , isInEcm=" diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 282cc388cf..0283499cab 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -2059,6 +2059,10 @@ public class ImsPhone extends ImsPhoneBase { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private void handleEnterEmergencyCallbackMode() { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + logd("DomainSelection enabled: ignore ECBM enter event."); + return; + } if (DBG) logd("handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= " + isInEcm()); // if phone is not in Ecm mode, and it's changed to Ecm mode if (!isInEcm()) { @@ -2080,6 +2084,10 @@ public class ImsPhone extends ImsPhoneBase { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Override protected void handleExitEmergencyCallbackMode() { + if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { + logd("DomainSelection enabled: ignore ECBM exit event."); + return; + } if (DBG) logd("handleExitEmergencyCallbackMode: mIsPhoneInEcmState = " + isInEcm()); if (isInEcm()) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 493033c490..2849445e54 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -87,6 +87,7 @@ import android.util.Log; import androidx.test.filters.FlakyTest; import com.android.internal.telephony.domainselection.DomainSelectionResolver; +import com.android.internal.telephony.emergency.EmergencyStateTracker; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; @@ -2479,4 +2480,98 @@ public class GsmCdmaPhoneTest extends TelephonyTest { nullable(Message.class)); assertEquals(0, captureBitMask.getValue() & TelephonyManager.NETWORK_CLASS_BITMASK_2G); } + + @Test + @SmallTest + public void testEcbm() throws Exception { + assertFalse(mPhoneUT.isInEcm()); + + mPhoneUT.handleMessage(mPhoneUT.obtainMessage( + GsmCdmaPhone.EVENT_EMERGENCY_CALLBACK_MODE_ENTER)); + + assertTrue(mPhoneUT.isInEcm()); + verifyEcbmIntentWasSent(1 /*times*/, true /*inEcm*/); + // verify that wakeLock is acquired in ECM + assertTrue(mPhoneUT.getWakeLock().isHeld()); + + boolean isTestingEmergencyCallbackMode = true; + replaceInstance(GsmCdmaPhone.class, "mIsTestingEmergencyCallbackMode", mPhoneUT, + isTestingEmergencyCallbackMode); + mPhoneUT.exitEmergencyCallbackMode(); + processAllMessages(); + + assertFalse(mPhoneUT.isInEcm()); + verifyEcbmIntentWasSent(2/*times*/, false /*inEcm*/); + // verify wakeLock released + assertFalse(mPhoneUT.getWakeLock().isHeld()); + } + + private void verifyEcbmIntentWasSent(int times, boolean isInEcm) throws Exception { + // verify ACTION_EMERGENCY_CALLBACK_MODE_CHANGED + ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mContext, atLeast(times)).sendStickyBroadcastAsUser(intentArgumentCaptor.capture(), + any()); + + Intent intent = intentArgumentCaptor.getValue(); + assertNotNull(intent); + assertEquals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED, intent.getAction()); + assertEquals(isInEcm, intent.getBooleanExtra( + TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)); + } + + @Test + @SmallTest + public void testEcbmWhenDomainSelectionEnabled() throws Exception { + DomainSelectionResolver dsResolver = Mockito.mock(DomainSelectionResolver.class); + doReturn(true).when(dsResolver).isDomainSelectionSupported(); + DomainSelectionResolver.setDomainSelectionResolver(dsResolver); + + mPhoneUT.handleMessage(mPhoneUT.obtainMessage( + GsmCdmaPhone.EVENT_EMERGENCY_CALLBACK_MODE_ENTER)); + + boolean isTestingEmergencyCallbackMode = true; + replaceInstance(GsmCdmaPhone.class, "mIsTestingEmergencyCallbackMode", mPhoneUT, + isTestingEmergencyCallbackMode); + mPhoneUT.exitEmergencyCallbackMode(); + processAllMessages(); + + verify(mContext, never()).sendStickyBroadcastAsUser(any(), any()); + } + + @Test + @SmallTest + public void testEcbmOnModemResetForNonGsmPhone() throws Exception { + switchToCdma(); + assertFalse(mPhoneUT.isInEcm()); + + mPhoneUT.handleMessage(mPhoneUT.obtainMessage( + GsmCdmaPhone.EVENT_EMERGENCY_CALLBACK_MODE_ENTER)); + + assertTrue(mPhoneUT.isInEcm()); + + Message m = mPhoneUT.obtainMessage(GsmCdmaPhone.EVENT_MODEM_RESET); + AsyncResult.forMessage(m); + mPhoneUT.handleMessage(m); + + assertFalse(mPhoneUT.isInEcm()); + verifyEcbmIntentWasSent(2 /*times*/, false /*inEcm*/); + } + + @Test + @SmallTest + public void testEcbmOnModemResetWhenDomainSelectionEnabled() throws Exception { + DomainSelectionResolver dsResolver = Mockito.mock(DomainSelectionResolver.class); + doReturn(true).when(dsResolver).isDomainSelectionSupported(); + DomainSelectionResolver.setDomainSelectionResolver(dsResolver); + + EmergencyStateTracker est = Mockito.mock(EmergencyStateTracker.class); + doReturn(true).when(est).isInEcm(); + replaceInstance(EmergencyStateTracker.class, "INSTANCE", null, est); + + GsmCdmaPhone spyPhone = spy(mPhoneUT); + doReturn(true).when(spyPhone).isInEcm(); + mPhoneUT.handleMessage(mPhoneUT.obtainMessage(GsmCdmaPhone.EVENT_MODEM_RESET)); + + verify(est).exitEmergencyCallbackMode(); + } } 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 ffa29ae662..483a74b18c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -646,6 +646,21 @@ public class ImsPhoneTest extends TelephonyTest { TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)); } + @Test + @SmallTest + public void testEcbmWhenDomainSelectionEnabled() { + DomainSelectionResolver dsResolver = mock(DomainSelectionResolver.class); + doReturn(true).when(dsResolver).isDomainSelectionSupported(); + DomainSelectionResolver.setDomainSelectionResolver(dsResolver); + + ImsEcbmStateListener imsEcbmStateListener = mImsPhoneUT.getImsEcbmStateListener(); + imsEcbmStateListener.onECBMEntered(); + imsEcbmStateListener.onECBMExited(); + + verify(mPhone, never()).setIsInEcm(anyBoolean()); + verify(mContext, never()).sendStickyBroadcastAsUser(any(), any()); + } + @Test @SmallTest public void testProcessDisconnectReason() throws Exception { -- GitLab From 87e95239ecd4e3c2ef593d3dae2fc054cf55a7a9 Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Tue, 31 Jan 2023 02:21:15 +0000 Subject: [PATCH 487/656] Separate the executor for the ServiceConnection of ImsServiceController separate the executor of ServiceConnection for ImsServiceController from the binder thread to prevent potential ANR cases Bug: 227221941 Test: ImsServiceTest / E2E call regression test 271378397 Test: atest ImsServiceControllerTest Change-Id: I9ca39033cffe10e633f1fbf371c3e399d950c16c --- .../telephony/ims/ImsServiceController.java | 70 ++++++++++++++----- .../ims/ImsServiceControllerCompatTest.java | 4 ++ .../ims/ImsServiceControllerTest.java | 20 ++++-- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceController.java b/src/java/com/android/internal/telephony/ims/ImsServiceController.java index 357215884c..6af7a08a4c 100644 --- a/src/java/com/android/internal/telephony/ims/ImsServiceController.java +++ b/src/java/com/android/internal/telephony/ims/ImsServiceController.java @@ -85,14 +85,49 @@ public class ImsServiceController { @Override public void onServiceConnected(ComponentName name, IBinder service) { + if (mHandler.getLooper().isCurrentThread()) { + onServiceConnectedInternal(name, service); + } else { + mHandler.post(() -> onServiceConnectedInternal(name, service)); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + if (mHandler.getLooper().isCurrentThread()) { + onServiceDisconnectedInternal(name); + } else { + mHandler.post(() -> onServiceDisconnectedInternal(name)); + } + } + + @Override + public void onBindingDied(ComponentName name) { + if (mHandler.getLooper().isCurrentThread()) { + onBindingDiedInternal(name); + } else { + mHandler.post(() -> onBindingDiedInternal(name)); + } + } + + @Override + public void onNullBinding(ComponentName name) { + if (mHandler.getLooper().isCurrentThread()) { + onNullBindingInternal(name); + } else { + mHandler.post(() -> onNullBindingInternal(name)); + } + } + + private void onServiceConnectedInternal(ComponentName name, IBinder service) { synchronized (mLock) { mBackoff.stop(); mIsBound = true; mIsBinding = false; try { - mLocalLog.log("onServiceConnected"); - Log.d(LOG_TAG, "ImsService(" + name + "): onServiceConnected with binder: " - + service); + mLocalLog.log("onServiceConnectedInternal"); + Log.d(LOG_TAG, "ImsService(" + name + + "): onServiceConnectedInternal with binder: " + service); setServiceController(service); notifyImsServiceReady(); retrieveStaticImsServiceCapabilities(); @@ -118,20 +153,18 @@ public class ImsServiceController { } } - @Override - public void onServiceDisconnected(ComponentName name) { + private void onServiceDisconnectedInternal(ComponentName name) { synchronized (mLock) { mIsBinding = false; cleanupConnection(); } - mLocalLog.log("onServiceDisconnected"); - Log.w(LOG_TAG, "ImsService(" + name + "): onServiceDisconnected. Waiting..."); + mLocalLog.log("onServiceDisconnectedInternal"); + Log.w(LOG_TAG, "ImsService(" + name + "): onServiceDisconnectedInternal. Waiting..."); // Service disconnected, but we are still technically bound. Waiting for reconnect. checkAndReportAnomaly(name); } - @Override - public void onBindingDied(ComponentName name) { + private void onBindingDiedInternal(ComponentName name) { mIsServiceConnectionDead = true; synchronized (mLock) { mIsBinding = false; @@ -141,15 +174,15 @@ public class ImsServiceController { unbindService(); startDelayedRebindToService(); } - Log.w(LOG_TAG, "ImsService(" + name + "): onBindingDied. Starting rebind..."); - mLocalLog.log("onBindingDied, retrying in " + mBackoff.getCurrentDelay() + " mS"); + Log.w(LOG_TAG, "ImsService(" + name + "): onBindingDiedInternal. Starting rebind..."); + mLocalLog.log("onBindingDiedInternal, retrying in " + + mBackoff.getCurrentDelay() + " mS"); } - @Override - public void onNullBinding(ComponentName name) { - Log.w(LOG_TAG, "ImsService(" + name + "): onNullBinding. Is service dead = " + private void onNullBindingInternal(ComponentName name) { + Log.w(LOG_TAG, "ImsService(" + name + "): onNullBindingInternal. Is service dead = " + mIsServiceConnectionDead); - mLocalLog.log("onNullBinding, is service dead = " + mIsServiceConnectionDead); + mLocalLog.log("onNullBindingInternal, is service dead = " + mIsServiceConnectionDead); // onNullBinding will happen after onBindingDied. In this case, we should not // permanently unbind and instead let the automatic rebind occur. if (mIsServiceConnectionDead) return; @@ -230,6 +263,7 @@ public class ImsServiceController { private static final boolean ENFORCE_SINGLE_SERVICE_FOR_SIP_TRANSPORT = false; private final ComponentName mComponentName; private final HandlerThread mHandlerThread = new HandlerThread("ImsServiceControllerHandler"); + private final Handler mHandler; private final LegacyPermissionManager mPermissionManager; private ImsFeatureBinderRepository mRepo; private ImsServiceControllerCallbacks mCallbacks; @@ -324,11 +358,12 @@ public class ImsServiceController { mComponentName = componentName; mCallbacks = callbacks; mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); mBackoff = new ExponentialBackoff( mRebindRetry.getStartDelay(), mRebindRetry.getMaximumDelay(), 2, /* multiplier */ - mHandlerThread.getLooper(), + mHandler, mRestartImsServiceRunnable); mPermissionManager = (LegacyPermissionManager) mContext.getSystemService( Context.LEGACY_PERMISSION_SERVICE); @@ -352,6 +387,7 @@ public class ImsServiceController { mContext = context; mComponentName = componentName; mCallbacks = callbacks; + mHandler = handler; mBackoff = new ExponentialBackoff( rebindRetry.getStartDelay(), rebindRetry.getMaximumDelay(), @@ -915,7 +951,7 @@ public class ImsServiceController { return; } ChangedPackages curChangedPackages = - mPackageManager.getChangedPackages(mLastSequenceNumber); + mPackageManager.getChangedPackages(mLastSequenceNumber); if (curChangedPackages != null) { mLastSequenceNumber = curChangedPackages.getSequenceNumber(); List packagesNames = curChangedPackages.getPackageNames(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerCompatTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerCompatTest.java index b80c6b066e..4a3ceaad16 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerCompatTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerCompatTest.java @@ -140,6 +140,8 @@ public class ImsServiceControllerCompatTest extends ImsTestBase { SparseIntArray slotIdToSubIdMap = new SparseIntArray(); slotIdToSubIdMap.put(SLOT_0, SUB_1); ServiceConnection conn = bindAndConnectService(slotIdToSubIdMap); + long delay = mTestImsServiceController.getRebindDelay(); + waitForHandlerActionDelayed(mHandler, delay, 2 * delay); // add the MMTelFeature verify(mMockServiceControllerBinder).createMMTelFeature(SLOT_0); verify(mMockServiceControllerBinder).addFeatureStatusCallback(eq(SLOT_0), @@ -149,6 +151,8 @@ public class ImsServiceControllerCompatTest extends ImsTestBase { validateMmTelFeatureContainerExists(SLOT_0); // Remove the feature conn.onBindingDied(mTestComponentName); + delay = REBIND_RETRY.getStartDelay(); + waitForHandlerActionDelayed(mHandler, delay, 2 * delay); verify(mMmTelCompatAdapterSpy).onFeatureRemoved(); verify(mMockServiceControllerBinder).removeImsFeature(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL)); 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 113829f88b..adfc4a3833 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java @@ -634,6 +634,8 @@ public class ImsServiceControllerTest extends ImsTestBase { conn.onServiceDisconnected(mTestComponentName); + long delay = mTestImsServiceController.getRebindDelay(); + waitForHandlerActionDelayed(mHandler, delay, 2 * delay); verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL), eq(mTestImsServiceController)); verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS), @@ -660,6 +662,8 @@ public class ImsServiceControllerTest extends ImsTestBase { conn.onServiceDisconnected(mTestComponentName); + long delay = mTestImsServiceController.getRebindDelay(); + waitForHandlerActionDelayed(mHandler, delay, 2 * delay); verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL), eq(mTestImsServiceController)); verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS), @@ -762,6 +766,8 @@ public class ImsServiceControllerTest extends ImsTestBase { conn.onBindingDied(null /*null*/); + long delay = REBIND_RETRY.getStartDelay(); + waitForHandlerActionDelayed(mHandler, delay, 2 * delay); verify(mMockContext).unbindService(eq(conn)); verify(mMockCallbacks).imsServiceFeatureRemoved(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL), eq(mTestImsServiceController)); @@ -787,6 +793,8 @@ public class ImsServiceControllerTest extends ImsTestBase { slotIdToSubIdMap.put(SLOT_0, SUB_2); bindAndNullServiceError(testFeatures, slotIdToSubIdMap.clone()); + long delay = mTestImsServiceController.getRebindDelay(); + waitForHandlerActionDelayed(mHandler, delay, 2 * delay); verify(mMockCallbacks, never()).imsServiceFeatureCreated(anyInt(), anyInt(), eq(mTestImsServiceController)); verify(mMockCallbacks).imsServiceBindPermanentError(eq(mTestComponentName)); @@ -1304,7 +1312,7 @@ public class ImsServiceControllerTest extends ImsTestBase { conn.onBindingDied(null /*null*/); - long delay = mTestImsServiceController.getRebindDelay(); + long delay = REBIND_RETRY.getStartDelay(); waitForHandlerActionDelayed(mHandler, delay, 2 * delay); // The service should autobind after rebind event occurs verify(mMockContext, times(2)).bindService(any(), any(), anyInt()); @@ -1330,7 +1338,7 @@ public class ImsServiceControllerTest extends ImsTestBase { // null binding should be ignored in this case. conn.onNullBinding(null); - long delay = mTestImsServiceController.getRebindDelay(); + long delay = REBIND_RETRY.getStartDelay(); waitForHandlerActionDelayed(mHandler, delay, 2 * delay); // The service should autobind after rebind event occurs verify(mMockContext, times(2)).bindService(any(), any(), anyInt()); @@ -1398,10 +1406,11 @@ public class ImsServiceControllerTest extends ImsTestBase { slotIdToSubIdMap.put(SLOT_0, SUB_2); ServiceConnection conn = bindAndConnectService(testFeatures, slotIdToSubIdMap.clone()); conn.onBindingDied(null /*null*/); - mTestImsServiceController.bind(testFeatures, slotIdToSubIdMap.clone()); - long delay = mTestImsServiceController.getRebindDelay(); + long delay = REBIND_RETRY.getStartDelay(); waitForHandlerActionDelayed(mHandler, delay, 2 * delay); + mTestImsServiceController.bind(testFeatures, slotIdToSubIdMap.clone()); + // Should only see two binds, not three from the auto rebind that occurs. verify(mMockContext, times(2)).bindService(any(), any(), anyInt()); } @@ -1481,6 +1490,9 @@ public class ImsServiceControllerTest extends ImsTestBase { IImsServiceController.Stub controllerStub = mock(IImsServiceController.Stub.class); when(controllerStub.queryLocalInterface(any())).thenReturn(mMockServiceControllerBinder); connection.onServiceConnected(mTestComponentName, controllerStub); + + long delay = mTestImsServiceController.getRebindDelay(); + waitForHandlerActionDelayed(mHandler, delay, 2 * delay); return connection; } -- GitLab From 2a4358874c26474a71bc8e0f79e1784ca3d6530c Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Thu, 23 Feb 2023 13:15:35 -0800 Subject: [PATCH 488/656] Add a new module SatelliteSOSMessageRecommender Bug: 268542899 Test: manually triggered emergency call on live network, add SatelliteSOSMessageRecommenderTest. Change-Id: I5e3245730d263abc85a0de0a5ddcef222de0a2f5 --- .../satellite/SatelliteController.java | 89 +-- .../SatelliteSOSMessageRecommender.java | 410 ++++++++++++ .../SatelliteSOSMessageRecommenderTest.java | 596 ++++++++++++++++++ 3 files changed, 1041 insertions(+), 54 deletions(-) create mode 100644 src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 6e90efd14f..0c305d6890 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -40,13 +40,11 @@ import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.util.Log; -import android.util.Pair; -import com.android.internal.telephony.CommandException; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.RILUtils; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; @@ -149,7 +147,8 @@ public class SatelliteController extends Handler { * * @param context The Context for the SatelliteController. */ - private SatelliteController(@NonNull Context context) { + @VisibleForTesting + protected SatelliteController(@NonNull Context context) { super(context.getMainLooper()); mContext = context; @@ -1094,7 +1093,35 @@ public class SatelliteController extends Handler { */ @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId, @NonNull ISatelliteProvisionStateCallback callback) { - return registerForSatelliteProvisionStateChangedInternal(subId, callback); + if (!isSatelliteSupported()) { + return SatelliteManager.SATELLITE_NOT_SUPPORTED; + } + + final int validSubId = getValidSatelliteSubId(subId); + Phone phone = SatelliteServiceUtils.getPhone(); + + SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = + mSatelliteProvisionStateChangedHandlers.get(validSubId); + if (satelliteProvisionStateChangedHandler == null) { + satelliteProvisionStateChangedHandler = new SatelliteProvisionStateChangedHandler( + Looper.getMainLooper(), validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( + satelliteProvisionStateChangedHandler, + SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); + } else { + phone.registerForSatelliteProvisionStateChanged( + satelliteProvisionStateChangedHandler, + SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); + } + } + + if (callback != null) { + satelliteProvisionStateChangedHandler.addListener(callback); + } + mSatelliteProvisionStateChangedHandlers.put( + validSubId, satelliteProvisionStateChangedHandler); + return SatelliteManager.SATELLITE_ERROR_NONE; } /** @@ -1312,12 +1339,6 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); - if (!isSatelliteProvisioned(validSubId)) { - result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); - return; - } - Phone phone = SatelliteServiceUtils.getPhone(); sendRequest(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, phone); } @@ -1367,7 +1388,7 @@ public class SatelliteController extends Handler { * or SatelliteController. * TODO (b/267826133) we need to do this for all subscriptions on the device. */ - registerForSatelliteProvisionStateChangedInternal(arg.subId, null); + registerForSatelliteProvisionStateChanged(arg.subId, null); } private void handleEventDeprovisionSatelliteServiceDone( @@ -1389,47 +1410,6 @@ public class SatelliteController extends Handler { } } - /** - * Registers for the satellite provision state changed. - * - * @param subId The subId of the subscription associated with the satellite service. - * @param callback The callback to handle the satellite provision state changed event. - * - * @return The {@link SatelliteManager.SatelliteError} result of the operation. - */ - @SatelliteManager.SatelliteError private int registerForSatelliteProvisionStateChangedInternal( - int subId, @Nullable ISatelliteProvisionStateCallback callback) { - if (!isSatelliteSupported()) { - return SatelliteManager.SATELLITE_NOT_SUPPORTED; - } - - final int validSubId = getValidSatelliteSubId(subId); - Phone phone = SatelliteServiceUtils.getPhone(); - - SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = - mSatelliteProvisionStateChangedHandlers.get(validSubId); - if (satelliteProvisionStateChangedHandler == null) { - satelliteProvisionStateChangedHandler = new SatelliteProvisionStateChangedHandler( - Looper.getMainLooper(), validSubId); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( - satelliteProvisionStateChangedHandler, - SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); - } else { - phone.registerForSatelliteProvisionStateChanged( - satelliteProvisionStateChangedHandler, - SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); - } - } - - if (callback != null) { - satelliteProvisionStateChangedHandler.addListener(callback); - } - mSatelliteProvisionStateChangedHandlers.put( - validSubId, satelliteProvisionStateChangedHandler); - return SatelliteManager.SATELLITE_ERROR_NONE; - } - private void handleStartSatellitePositionUpdatesDone(@NonNull AsyncResult ar) { SatelliteControllerHandlerRequest request = (SatelliteControllerHandlerRequest) ar.userObj; SatellitePositionUpdateArgument arg = (SatellitePositionUpdateArgument) request.argument; @@ -1568,7 +1548,8 @@ public class SatelliteController extends Handler { * @param subId The subscription id. * @return true if satellite is provisioned on the given subscription else return false. */ - public boolean isSatelliteProvisioned(int subId) { + @VisibleForTesting + protected boolean isSatelliteProvisioned(int subId) { final long identity = Binder.clearCallingIdentity(); try { if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java new file mode 100644 index 0000000000..a1bd99ec72 --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2023 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 static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_ERROR_NONE; + +import android.annotation.NonNull; +import android.os.AsyncResult; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ResultReceiver; +import android.provider.DeviceConfig; +import android.telecom.Call; +import android.telecom.Connection; +import android.telephony.Rlog; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.ImsRegistrationAttributes; +import android.telephony.ims.RegistrationManager; +import android.telephony.satellite.ISatelliteProvisionStateCallback; +import android.util.Pair; + +import com.android.ims.ImsException; +import com.android.ims.ImsManager; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.Phone; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * This module is responsible for monitoring the cellular service state and IMS registration state + * during an emergency call and notify Dialer when Telephony is not able to find any network and + * the call likely will not get connected so that Dialer will prompt the user if they would like to + * switch to satellite messaging. + */ +public class SatelliteSOSMessageRecommender extends Handler { + private static final String TAG = "SatelliteSOSMessageRecommender"; + + /** + * Device config for the timeout duration in milliseconds to determine whether to recommend + * Dialer to show the SOS button to users. + *

+ * The timer is started when there is an ongoing emergency call, and the IMS is not registered, + * and cellular service is not available. When the timer expires, SatelliteSOSMessageRecommender + * will send the event EVENT_DISPLAY_SOS_MESSAGE to Dialer, which will then prompt user to + * switch to using satellite SOS messaging. + */ + public static final String EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = + "emergency_call_to_sos_msg_hysteresis_timeout_millis"; + /** + * The default value of {@link #EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS} when it is + * not provided in the device config. + */ + public static final long DEFAULT_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 20000; + + private static final int EVENT_EMERGENCY_CALL_STARTED = 1; + protected static final int EVENT_CELLULAR_SERVICE_STATE_CHANGED = 2; + private static final int EVENT_IMS_REGISTRATION_STATE_CHANGED = 3; + protected static final int EVENT_TIME_OUT = 4; + private static final int EVENT_SATELLITE_PROVISIONED_STATE_CHANGED = 5; + private static final int EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED = 6; + + @NonNull + private final SatelliteController mSatelliteController; + private ImsManager mImsManager; + + private Connection mEmergencyConnection = null; + /* The phone used for emergency call */ + private Phone mPhone = null; + private final ISatelliteProvisionStateCallback mISatelliteProvisionStateCallback; + @ServiceState.RegState + private AtomicInteger mCellularServiceState = new AtomicInteger(); + private AtomicBoolean mIsImsRegistered = new AtomicBoolean(); + private AtomicBoolean mIsSatelliteAllowedInCurrentLocation = new AtomicBoolean(); + private final ResultReceiver mReceiverForRequestIsSatelliteAllowedForCurrentLocation; + private final long mTimeoutMillis; + protected int mCountOfTimerStarted = 0; + + private RegistrationManager.RegistrationCallback mImsRegistrationCallback = + new RegistrationManager.RegistrationCallback() { + @Override + public void onRegistered(ImsRegistrationAttributes attributes) { + sendMessage(obtainMessage(EVENT_IMS_REGISTRATION_STATE_CHANGED, true)); + } + + @Override + public void onUnregistered(ImsReasonInfo info) { + sendMessage(obtainMessage(EVENT_IMS_REGISTRATION_STATE_CHANGED, false)); + } + }; + + /** + * Create an instance of SatelliteSOSMessageRecommender. + * + * @param looper The looper used with the handler of this class. + */ + public SatelliteSOSMessageRecommender(@NonNull Looper looper) { + this(looper, SatelliteController.getInstance(), null, + getEmergencyCallToSosMsgHysteresisTimeoutMillis()); + } + + /** + * Create an instance of SatelliteSOSMessageRecommender. This constructor should be used in + * only unit tests. + * + * @param looper The looper used with the handler of this class. + * @param satelliteController The SatelliteController singleton instance. + * @param imsManager The ImsManager instance associated with the phone, which is used for making + * the emergency call. This argument is not null only in unit tests. + * @param timeoutMillis The timeout duration of the timer. + */ + @VisibleForTesting + protected SatelliteSOSMessageRecommender(@NonNull Looper looper, + @NonNull SatelliteController satelliteController, ImsManager imsManager, + long timeoutMillis) { + super(looper); + mSatelliteController = satelliteController; + mImsManager = imsManager; + mTimeoutMillis = timeoutMillis; + mISatelliteProvisionStateCallback = new ISatelliteProvisionStateCallback.Stub() { + @Override + public void onSatelliteProvisionStateChanged(boolean provisioned) { + logd("onSatelliteProvisionStateChanged: provisioned=" + provisioned); + sendMessage(obtainMessage(EVENT_SATELLITE_PROVISIONED_STATE_CHANGED, provisioned)); + } + }; + mReceiverForRequestIsSatelliteAllowedForCurrentLocation = new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) { + boolean isSatelliteCommunicationAllowed = + resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED); + mIsSatelliteAllowedInCurrentLocation.set(isSatelliteCommunicationAllowed); + if (!isSatelliteCommunicationAllowed) { + logd("Satellite is not allowed for current location."); + cleanUpResources(); + } + } else { + loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist."); + mIsSatelliteAllowedInCurrentLocation.set(false); + cleanUpResources(); + } + } else { + loge("requestIsSatelliteCommunicationAllowedForCurrentLocation() resultCode=" + + resultCode); + mIsSatelliteAllowedInCurrentLocation.set(false); + cleanUpResources(); + } + } + }; + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_EMERGENCY_CALL_STARTED: + handleEmergencyCallStartedEvent((Pair) msg.obj); + break; + case EVENT_TIME_OUT: + handleTimeoutEvent(); + break; + case EVENT_SATELLITE_PROVISIONED_STATE_CHANGED: + handleSatelliteProvisionStateChangedEvent((boolean) msg.obj); + break; + case EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED: + handleEmergencyCallConnectionStateChangedEvent((Pair) msg.obj); + break; + case EVENT_IMS_REGISTRATION_STATE_CHANGED: + handleImsRegistrationStateChangedEvent((boolean) msg.obj); + break; + case EVENT_CELLULAR_SERVICE_STATE_CHANGED: + AsyncResult ar = (AsyncResult) msg.obj; + handleCellularServiceStateChangedEvent((ServiceState) ar.result); + break; + default: + logd("handleMessage: unexpected message code: " + msg.what); + break; + } + } + + /** + * Inform SatelliteSOSMessageRecommender that an emergency call has just started. + * + * @param connection The connection created by TelephonyConnectionService for the emergency + * call. + * @param phone The phone used for the emergency call. + */ + public void onEmergencyCallStarted(@NonNull Connection connection, @NonNull Phone phone) { + if (!mSatelliteController.isSatelliteSupported()) { + logd("onEmergencyCallStarted: satellite is not supported"); + return; + } + Pair argument = new Pair<>(connection, phone); + sendMessage(obtainMessage(EVENT_EMERGENCY_CALL_STARTED, argument)); + } + + /** + * Inform SatelliteSOSMessageRecommender that the state of the emergency call connection has + * changed. + * + * @param callId The ID of the emergency call. + * @param state The connection state of the emergency call. + */ + public void onEmergencyCallConnectionStateChanged( + String callId, @Connection.ConnectionState int state) { + Pair argument = new Pair<>(callId, state); + sendMessage(obtainMessage(EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED, argument)); + } + + private void handleEmergencyCallStartedEvent(@NonNull Pair arg) { + mSatelliteController.requestIsSatelliteCommunicationAllowedForCurrentLocation( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mReceiverForRequestIsSatelliteAllowedForCurrentLocation); + if (mPhone != null) { + logd("handleEmergencyCallStartedEvent: new emergency call started while there is " + + " an ongoing call"); + unregisterForInterestedStateChangedEvents(mPhone); + } + mPhone = arg.second; + mEmergencyConnection = arg.first; + mCellularServiceState.set(mPhone.getServiceState().getState()); + mIsImsRegistered.set(mPhone.isImsRegistered()); + handleStateChangedEventForHysteresisTimer(); + registerForInterestedStateChangedEvents(mPhone); + } + + private void handleSatelliteProvisionStateChangedEvent(boolean provisioned) { + if (!provisioned) { + cleanUpResources(); + } + } + + private void handleTimeoutEvent() { + boolean isDialerNotified = false; + if (!mIsImsRegistered.get() && !isCellularAvailable() + && mIsSatelliteAllowedInCurrentLocation.get() + && mSatelliteController.isSatelliteProvisioned( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) + && shouldTrackCall(mEmergencyConnection.getState())) { + logd("handleTimeoutEvent: Sending EVENT_DISPLAY_SOS_MESSAGE to Dialer..."); + mEmergencyConnection.sendConnectionEvent(Call.EVENT_DISPLAY_SOS_MESSAGE, null); + isDialerNotified = true; + } + reportMetrics(isDialerNotified); + cleanUpResources(); + } + + private void handleEmergencyCallConnectionStateChangedEvent( + @NonNull Pair arg) { + if (mEmergencyConnection == null) { + // Either the call was not created or the timer already timed out. + return; + } + + String callId = arg.first; + int state = arg.second; + if (!mEmergencyConnection.getTelecomCallId().equals(callId)) { + loge("handleEmergencyCallConnectionStateChangedEvent: unexpected state changed event " + + ", mEmergencyConnection=" + mEmergencyConnection + ", callId=" + callId + + ", state=" + state); + /** + * TelephonyConnectionService sent us a connection state changed event for a call that + * we're not tracking. There must be some unexpected things happened in + * TelephonyConnectionService. Thus, we need to clean up the resources. + */ + cleanUpResources(); + return; + } + + if (!shouldTrackCall(state)) { + reportMetrics(false); + cleanUpResources(); + } + } + + private void handleImsRegistrationStateChangedEvent(boolean registered) { + if (registered != mIsImsRegistered.get()) { + mIsImsRegistered.set(registered); + handleStateChangedEventForHysteresisTimer(); + } + } + + private void handleCellularServiceStateChangedEvent(@NonNull ServiceState serviceState) { + int state = serviceState.getState(); + if (mCellularServiceState.get() != state) { + mCellularServiceState.set(state); + handleStateChangedEventForHysteresisTimer(); + } + } + + private void reportMetrics(boolean isDialerNotified) { + /** + * TODO: We need to report the following info + * - Whether the Dialer is notified with the event DISPLAY_SOS_MESSAGE (isDialerNotified). + * - Number of times the timer is started (mCountOfTimerStarted). + * - Whether IMS is registered (mIsImsRegistered). + * - The cellular service state (mCellularServiceState). + */ + } + + private void cleanUpResources() { + stopTimer(); + if (mPhone != null) { + unregisterForInterestedStateChangedEvents(mPhone); + mPhone = null; + } + mEmergencyConnection = null; + mCountOfTimerStarted = 0; + } + + private void registerForInterestedStateChangedEvents(@NonNull Phone phone) { + mSatelliteController.registerForSatelliteProvisionStateChanged( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mISatelliteProvisionStateCallback); + phone.registerForServiceStateChanged(this, EVENT_CELLULAR_SERVICE_STATE_CHANGED, null); + registerForImsRegistrationStateChanged(phone); + } + + private void registerForImsRegistrationStateChanged(@NonNull Phone phone) { + ImsManager imsManager = (mImsManager != null) ? mImsManager : ImsManager.getInstance( + phone.getContext(), phone.getPhoneId()); + try { + imsManager.addRegistrationCallback(mImsRegistrationCallback, this::post); + } catch (ImsException ex) { + loge("registerForImsRegistrationStateChanged: ex=" + ex); + } + } + + private void unregisterForInterestedStateChangedEvents(@NonNull Phone phone) { + mSatelliteController.unregisterForSatelliteProvisionStateChanged( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mISatelliteProvisionStateCallback); + phone.unregisterForServiceStateChanged(this); + unregisterForImsRegistrationStateChanged(phone); + } + + private void unregisterForImsRegistrationStateChanged(@NonNull Phone phone) { + ImsManager imsManager = (mImsManager != null) ? mImsManager : ImsManager.getInstance( + phone.getContext(), phone.getPhoneId()); + imsManager.removeRegistrationListener(mImsRegistrationCallback); + } + + private boolean isCellularAvailable() { + return (mCellularServiceState.get() == ServiceState.STATE_IN_SERVICE + || mCellularServiceState.get() == ServiceState.STATE_EMERGENCY_ONLY); + } + + private void handleStateChangedEventForHysteresisTimer() { + if (!mIsImsRegistered.get() && !isCellularAvailable()) { + startTimer(); + } else { + stopTimer(); + } + } + + private void startTimer() { + if (hasMessages(EVENT_TIME_OUT)) { + return; + } + sendMessageDelayed(obtainMessage(EVENT_TIME_OUT), mTimeoutMillis); + mCountOfTimerStarted++; + } + + private void stopTimer() { + removeMessages(EVENT_TIME_OUT); + } + + private static long getEmergencyCallToSosMsgHysteresisTimeoutMillis() { + return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, + EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS, + DEFAULT_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + } + + private boolean shouldTrackCall(int connectionState) { + /** + * An active connection state means both parties are connected to the call and can actively + * communicate. A disconnected connection state means the emergency call has ended. In both + * cases, we don't need to track the call anymore. + */ + return (connectionState != Connection.STATE_ACTIVE + && connectionState != Connection.STATE_DISCONNECTED); + } + + private static void logd(@NonNull String log) { + Rlog.d(TAG, log); + } + + private static void loge(@NonNull String log) { + Rlog.e(TAG, log); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java new file mode 100644 index 0000000000..ea788bcad5 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java @@ -0,0 +1,596 @@ +/* + * Copyright (C) 2023 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.annotation.NonNull; +import android.content.Context; +import android.content.res.Resources; +import android.os.AsyncResult; +import android.os.Bundle; +import android.os.Looper; +import android.os.RemoteException; +import android.os.ResultReceiver; +import android.telecom.Call; +import android.telecom.Connection; +import android.telephony.BinderCacheManager; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.ims.RegistrationManager; +import android.telephony.satellite.ISatelliteProvisionStateCallback; +import android.telephony.satellite.SatelliteManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.Log; + +import com.android.ims.ImsException; +import com.android.ims.ImsManager; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; + +/** + * Unit tests for SatelliteSOSMessageRecommender + */ +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { + private static final String TAG = "SatelliteSOSMessageRecommenderTest"; + private static final long TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 500; + private static final long EVENT_PROCESSING_TIME_MILLIS = 100; + private static final int PHONE_ID = 0; + private static final String CALL_ID = "CALL_ID"; + private static final String WRONG_CALL_ID = "WRONG_CALL_ID"; + private TestSatelliteController mTestSatelliteController; + private TestImsManager mTestImsManager; + + @Mock + private Context mMockContext; + @Mock + private Resources mResources; + @Mock + private ImsManager.MmTelFeatureConnectionFactory mMmTelFeatureConnectionFactory; + private TestConnection mTestConnection; + private TestSOSMessageRecommender mTestSOSMessageRecommender; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + MockitoAnnotations.initMocks(this); + + when(mMockContext.getMainLooper()).thenReturn(Looper.getMainLooper()); + when(mMockContext.getResources()).thenReturn(mResources); + when(mResources.getString(com.android.internal.R.string.config_satellite_service_package)) + .thenReturn(""); + mTestSatelliteController = new TestSatelliteController(mMockContext); + mTestImsManager = new TestImsManager( + mMockContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null); + mTestConnection = new TestConnection(CALL_ID); + when(mPhone.getServiceState()).thenReturn(mServiceState); + mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.getMainLooper(), + mTestSatelliteController, mTestImsManager, + TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); + when(mPhone.isImsRegistered()).thenReturn(false); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testTimeoutBeforeEmergencyCallEnd() { + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + + waitFor(EVENT_PROCESSING_TIME_MILLIS); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + + // Wait for the timeout to expires + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + } + + @Test + public void testStopTrackingCallBeforeTimeout_ConnectionActive() { + testStopTrackingCallBeforeTimeout(Connection.STATE_ACTIVE); + } + + @Test + public void testStopTrackingCallBeforeTimeout_ConnectionDisconnected() { + testStopTrackingCallBeforeTimeout(Connection.STATE_DISCONNECTED); + } + + @Test + public void testImsRegistrationStateChangedBeforeTimeout() { + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertTrue(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + + mTestImsManager.sendImsRegistrationStateChangedEvent(true); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); + + mTestImsManager.sendImsRegistrationStateChangedEvent(false); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); + + // Wait for the timeout to expires + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + + assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); + } + + @Test + public void testSatelliteProvisionStateChangedBeforeTimeout() { + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertTrue(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + + mTestSatelliteController.sendProvisionStateChangedEvent( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + assertTrue(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 2, 2, 2); + + mTestSatelliteController.sendProvisionStateChangedEvent( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); + + // Wait for the timeout to expires + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + + assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertUnregisterForStateChangedEventsTriggered(mPhone, 2, 2, 2); + } + + @Test + public void testEmergencyCallRedialBeforeTimeout() { + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertTrue(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + + Phone newPhone = Mockito.mock(Phone.class); + when(newPhone.getServiceState()).thenReturn(mServiceState); + when(newPhone.isImsRegistered()).thenReturn(false); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, newPhone); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertTrue(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + /** + * Since {@link SatelliteSOSMessageRecommender} always uses + * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} when registering for provision state + * changed events with {@link SatelliteController}, registerForProvisionCount does + * not depend on Phone. + *

+ * Since we use a single mocked ImsManager instance, registerForImsCount does not depend on + * Phone. + */ + assertRegisterForStateChangedEventsTriggered(newPhone, 2, 2, 1); + + // Wait for the timeout to expires + long timeoutMillis = TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS + - EVENT_PROCESSING_TIME_MILLIS; + waitFor(timeoutMillis > 0 ? timeoutMillis : 0); + + assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + /** + * Since {@link SatelliteSOSMessageRecommender} always uses + * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} when unregistering for provision + * state changed events with {@link SatelliteController}, unregisterForProvisionCount does + * not depend on Phone. + *

+ * Since we use a single mocked ImsManager instance, unregisterForImsCount does not depend + * on Phone. + */ + assertUnregisterForStateChangedEventsTriggered(newPhone, 2, 2, 1); + assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); + } + + @Test + public void testCellularServiceStateChangedBeforeTimeout_InServiceToOutOfService() { + testCellularServiceStateChangedBeforeTimeout( + ServiceState.STATE_IN_SERVICE, ServiceState.STATE_OUT_OF_SERVICE); + } + + @Test + public void testCellularServiceStateChangedBeforeTimeout_InServiceToPowerOff() { + testCellularServiceStateChangedBeforeTimeout( + ServiceState.STATE_IN_SERVICE, ServiceState.STATE_POWER_OFF); + } + + @Test + public void testCellularServiceStateChangedBeforeTimeout_EmergencyOnlyToOutOfService() { + testCellularServiceStateChangedBeforeTimeout( + ServiceState.STATE_EMERGENCY_ONLY, ServiceState.STATE_OUT_OF_SERVICE); + } + + @Test + public void testCellularServiceStateChangedBeforeTimeout_EmergencyOnlyToPowerOff() { + testCellularServiceStateChangedBeforeTimeout( + ServiceState.STATE_EMERGENCY_ONLY, ServiceState.STATE_POWER_OFF); + } + + @Test + public void testOnEmergencyCallConnectionStateChangedWithWrongCallId() { + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertTrue(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + + mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged( + WRONG_CALL_ID, Connection.STATE_ACTIVE); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + } + + @Test + public void testSatelliteNotAllowedInCurrentLocation() { + mTestSatelliteController.setIsSatelliteCommunicationAllowed(false); + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + /** + * We should have registered for the state change events abd started the timer when + * receiving the event onEmergencyCallStarted. After getting the callback for the result of + * the request requestIsSatelliteCommunicationAllowedForCurrentLocation, the resources + * should be cleaned up. + */ + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + } + + private void testStopTrackingCallBeforeTimeout( + @Connection.ConnectionState int connectionState) { + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertTrue(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + + mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(CALL_ID, connectionState); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + } + + private void testCellularServiceStateChangedBeforeTimeout( + @ServiceState.RegState int availableServiceState, + @ServiceState.RegState int unavailableServiceState) { + mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertTrue(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + + mTestSOSMessageRecommender.sendServiceStateChangedEvent(availableServiceState); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertFalse(mTestSOSMessageRecommender.isTimerStarted()); + assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); + assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); + + mTestSOSMessageRecommender.sendServiceStateChangedEvent(unavailableServiceState); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); + + // Wait for the timeout to expires + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + + assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); + assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); + assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); + } + + private void assertRegisterForStateChangedEventsTriggered( + Phone phone, int registerForProvisionCount, int registerForImsCount, + int registerForCellularCount) { + assertEquals(registerForProvisionCount, + mTestSatelliteController.getRegisterForSatelliteProvisionStateChangedCalls()); + assertEquals(registerForImsCount, mTestImsManager.getAddRegistrationCallbackCalls()); + verify(phone, times(registerForCellularCount)) + .registerForServiceStateChanged(any(), anyInt(), any()); + } + + private void assertUnregisterForStateChangedEventsTriggered( + Phone phone, int unregisterForProvisionCount, int unregisterForImsCount, + int unregisterForCellularCount) { + assertEquals(unregisterForProvisionCount, + mTestSatelliteController.getUnregisterForSatelliteProvisionStateChangedCalls()); + assertEquals(unregisterForImsCount, mTestImsManager.getRemoveRegistrationListenerCalls()); + verify(phone, times(unregisterForCellularCount)).unregisterForServiceStateChanged(any()); + } + + private static void waitFor(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ex) { + Log.e(TAG, "Thread.sleep() ex=" + ex); + } + } + + private static class TestSatelliteController extends SatelliteController { + + private static final String TAG = "TestSatelliteController"; + private final Map> + mProvisionStateChangedCallbacks; + private int mRegisterForSatelliteProvisionStateChangedCalls = 0; + private int mUnregisterForSatelliteProvisionStateChangedCalls = 0; + private final Map mSatelliteProvisionStates; + private boolean mIsSatelliteCommunicationAllowed = true; + + /** + * Create a SatelliteController to act as a backend service of + * {@link SatelliteManager} + * + * @param context The Context for the SatelliteController. + */ + protected TestSatelliteController(Context context) { + super(context); + mProvisionStateChangedCallbacks = new HashMap<>(); + mSatelliteProvisionStates = new HashMap<>(); + mSatelliteProvisionStates.put(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); + } + + @Override + public boolean isSatelliteProvisioned(int subId) { + Boolean provisioned = mSatelliteProvisionStates.get(subId); + return (provisioned != null) ? provisioned : false; + } + + @Override + public boolean isSatelliteSupported() { + return true; + } + + @Override + @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged( + int subId, @NonNull ISatelliteProvisionStateCallback callback) { + mRegisterForSatelliteProvisionStateChangedCalls++; + Set perSubscriptionCallbacks = + mProvisionStateChangedCallbacks.getOrDefault(subId, new HashSet<>()); + perSubscriptionCallbacks.add(callback); + mProvisionStateChangedCallbacks.put(subId, perSubscriptionCallbacks); + return SatelliteManager.SATELLITE_ERROR_NONE; + } + + @Override + public void unregisterForSatelliteProvisionStateChanged( + int subId, @NonNull ISatelliteProvisionStateCallback callback) { + mUnregisterForSatelliteProvisionStateChangedCalls++; + Set perSubscriptionCallbacks = + mProvisionStateChangedCallbacks.get(subId); + if (perSubscriptionCallbacks != null) { + perSubscriptionCallbacks.remove(callback); + } + } + + @Override + public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, + @NonNull ResultReceiver result) { + Bundle bundle = new Bundle(); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED, + mIsSatelliteCommunicationAllowed); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + } + + public void setIsSatelliteCommunicationAllowed(boolean allowed) { + mIsSatelliteCommunicationAllowed = allowed; + } + + public int getRegisterForSatelliteProvisionStateChangedCalls() { + return mRegisterForSatelliteProvisionStateChangedCalls; + } + + public int getUnregisterForSatelliteProvisionStateChangedCalls() { + return mUnregisterForSatelliteProvisionStateChangedCalls; + } + + public void sendProvisionStateChangedEvent(int subId, boolean provisioned) { + mSatelliteProvisionStates.put(subId, provisioned); + Set perSubscriptionCallbacks = + mProvisionStateChangedCallbacks.get(subId); + if (perSubscriptionCallbacks != null) { + for (ISatelliteProvisionStateCallback callback : perSubscriptionCallbacks) { + try { + callback.onSatelliteProvisionStateChanged(provisioned); + } catch (RemoteException ex) { + Log.e(TAG, "sendProvisionStateChangedEvent: ex=" + ex); + } + } + } + } + } + + private static class TestImsManager extends ImsManager { + + private final Set mCallbacks; + private int mAddRegistrationCallbackCalls = 0; + private int mRemoveRegistrationListenerCalls = 0; + + /** + * Used for testing only to inject dependencies. + */ + TestImsManager(Context context, int phoneId, MmTelFeatureConnectionFactory factory, + SubscriptionManagerProxy subManagerProxy, SettingsProxy settingsProxy, + BinderCacheManager binderCacheManager) { + super(context, phoneId, factory, subManagerProxy, settingsProxy, binderCacheManager); + mCallbacks = new HashSet<>(); + } + + @Override + public void addRegistrationCallback(RegistrationManager.RegistrationCallback callback, + Executor executor) + throws ImsException { + mAddRegistrationCallbackCalls++; + + if (callback == null) { + throw new NullPointerException("registration callback can't be null"); + } + if (executor == null) { + throw new NullPointerException("registration executor can't be null"); + } + + callback.setExecutor(executor); + mCallbacks.add(callback); + } + + @Override + public void removeRegistrationListener(RegistrationManager.RegistrationCallback callback) { + mRemoveRegistrationListenerCalls++; + + if (callback == null) { + throw new NullPointerException("registration callback can't be null"); + } + mCallbacks.remove(callback); + } + + public int getAddRegistrationCallbackCalls() { + return mAddRegistrationCallbackCalls; + } + + public int getRemoveRegistrationListenerCalls() { + return mRemoveRegistrationListenerCalls; + } + + public void sendImsRegistrationStateChangedEvent(boolean registered) { + if (registered) { + for (RegistrationManager.RegistrationCallback callback : mCallbacks) { + callback.onRegistered(null); + } + } else { + for (RegistrationManager.RegistrationCallback callback : mCallbacks) { + callback.onUnregistered(null); + } + } + } + } + + private static class TestSOSMessageRecommender extends SatelliteSOSMessageRecommender { + + /** + * Create an instance of SatelliteSOSMessageRecommender. + * + * @param looper The looper used with the handler of this class. + * @param satelliteController The SatelliteController singleton instance. + * @param imsManager The ImsManager instance associated with the phone, which is + * used for making the emergency call. This argument is not + * null only in unit tests. + * @param timeoutMillis The timeout duration of the timer. + */ + TestSOSMessageRecommender(Looper looper, SatelliteController satelliteController, + ImsManager imsManager, long timeoutMillis) { + super(looper, satelliteController, imsManager, timeoutMillis); + } + + public boolean isTimerStarted() { + return hasMessages(EVENT_TIME_OUT); + } + + public int getCountOfTimerStarted() { + return mCountOfTimerStarted; + } + + public void sendServiceStateChangedEvent(@ServiceState.RegState int state) { + ServiceState serviceState = new ServiceState(); + serviceState.setState(state); + sendMessage(obtainMessage(EVENT_CELLULAR_SERVICE_STATE_CHANGED, + new AsyncResult(null, serviceState, null))); + } + } + + private static class TestConnection extends Connection { + private final Set mSentEvents; + TestConnection(String callId) { + setTelecomCallId(callId); + mSentEvents = new HashSet<>(); + } + + @Override + public void sendConnectionEvent(String event, Bundle extras) { + mSentEvents.add(event); + } + + public boolean isEventSent(String event) { + return mSentEvents.contains(event); + } + } +} -- GitLab From 0e85b8c33737e0ecbe0b92f01e79647131169f9b Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Wed, 1 Mar 2023 03:58:40 +0000 Subject: [PATCH 489/656] DO NOT MERGE Revert "Add SatelliteProxy" Revert submission 20583557-Satellite APIs Reason for revert: We need to revert these changes for U Reverted changes: /q/submissionid:20583557-Satellite+APIs Bug: 271297374 Test: Call and SMS/MMS with live network. atest TelephonyManagerTestOnMockModem atest VtsHalRadioTargetTest atest com.android.cellbroadcastreceiver.compliancetests.CellBroadcastConfigTest atest android.telephony.cts.TelephonyManagerTest atest android.telephony.cts.SatelliteManagerTest Change-Id: I586a1f6a01468cb80a9547ebb4559591c97ae335 --- Android.bp | 1 - .../internal/telephony/CommandException.java | 33 -- .../android/internal/telephony/MockModem.java | 34 -- .../com/android/internal/telephony/RIL.java | 521 +++--------------- .../android/internal/telephony/RILUtils.java | 115 ---- .../telephony/RadioSatelliteProxy.java | 279 ---------- .../telephony/SatelliteIndication.java | 183 ------ .../internal/telephony/SatelliteResponse.java | 217 -------- 8 files changed, 74 insertions(+), 1309 deletions(-) delete mode 100644 src/java/com/android/internal/telephony/RadioSatelliteProxy.java delete mode 100644 src/java/com/android/internal/telephony/SatelliteIndication.java delete mode 100644 src/java/com/android/internal/telephony/SatelliteResponse.java diff --git a/Android.bp b/Android.bp index 502763505e..4097571eb5 100644 --- a/Android.bp +++ b/Android.bp @@ -90,7 +90,6 @@ java_library { "android.hardware.radio.modem-V2-java", "android.hardware.radio.network-V2-java", "android.hardware.radio.sim-V2-java", - "android.hardware.radio.satellite-V1-java", "android.hardware.radio.voice-V2-java", "voip-common", "ims-common", diff --git a/src/java/com/android/internal/telephony/CommandException.java b/src/java/com/android/internal/telephony/CommandException.java index 6b6d84f0e8..e068c1cbff 100644 --- a/src/java/com/android/internal/telephony/CommandException.java +++ b/src/java/com/android/internal/telephony/CommandException.java @@ -131,17 +131,6 @@ public class CommandException extends RuntimeException { BLOCKED_DUE_TO_CALL, RF_HARDWARE_ISSUE, NO_RF_CALIBRATION_INFO, - ENCODING_NOT_SUPPORTED, - FEATURE_NOT_SUPPORTED, - INVALID_CONTACT, - MODEM_INCOMPATIBLE, - NETWORK_TIMEOUT, - NO_SATELLITE_SIGNAL, - NOT_SUFFICIENT_ACCOUNT_BALANCE, - RADIO_TECHNOLOGY_NOT_SUPPORTED, - SUBSCRIBER_NOT_AUTHORIZED, - SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL, - UNIDENTIFIED_SUBSCRIBER } @UnsupportedAppUsage @@ -352,28 +341,6 @@ public class CommandException extends RuntimeException { return new CommandException(Error.RF_HARDWARE_ISSUE); case RILConstants.NO_RF_CALIBRATION_INFO: return new CommandException(Error.NO_RF_CALIBRATION_INFO); - case RILConstants.ENCODING_NOT_SUPPORTED: - return new CommandException(Error.ENCODING_NOT_SUPPORTED); - case RILConstants.FEATURE_NOT_SUPPORTED: - return new CommandException(Error.FEATURE_NOT_SUPPORTED); - case RILConstants.INVALID_CONTACT: - return new CommandException(Error.INVALID_CONTACT); - case RILConstants.MODEM_INCOMPATIBLE: - return new CommandException(Error.MODEM_INCOMPATIBLE); - case RILConstants.NETWORK_TIMEOUT: - return new CommandException(Error.NETWORK_TIMEOUT); - case RILConstants.NO_SATELLITE_SIGNAL: - return new CommandException(Error.NO_SATELLITE_SIGNAL); - case RILConstants.NOT_SUFFICIENT_ACCOUNT_BALANCE: - return new CommandException(Error.NOT_SUFFICIENT_ACCOUNT_BALANCE); - case RILConstants.RADIO_TECHNOLOGY_NOT_SUPPORTED: - return new CommandException(Error.RADIO_TECHNOLOGY_NOT_SUPPORTED); - case RILConstants.SUBSCRIBER_NOT_AUTHORIZED: - return new CommandException(Error.SUBSCRIBER_NOT_AUTHORIZED); - case RILConstants.SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL: - return new CommandException(Error.SWITCHED_FROM_SATELLITE_TO_TERRESTRIAL); - case RILConstants.UNIDENTIFIED_SUBSCRIBER: - return new CommandException(Error.UNIDENTIFIED_SUBSCRIBER); default: Rlog.e("GSM", "Unrecognized RIL errno " + ril_errno); return new CommandException(Error.INVALID_RESPONSE); diff --git a/src/java/com/android/internal/telephony/MockModem.java b/src/java/com/android/internal/telephony/MockModem.java index 83417c53a5..a20e74818f 100644 --- a/src/java/com/android/internal/telephony/MockModem.java +++ b/src/java/com/android/internal/telephony/MockModem.java @@ -21,7 +21,6 @@ import static android.telephony.TelephonyManager.HAL_SERVICE_IMS; import static android.telephony.TelephonyManager.HAL_SERVICE_MESSAGING; import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; -import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE; import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; @@ -45,8 +44,6 @@ public class MockModem { private static final String BIND_IRADIOVOICE = "android.telephony.mockmodem.iradiovoice"; private static final String BIND_IRADIOIMS = "android.telephony.mockmodem.iradioims"; private static final String BIND_IRADIOCONFIG = "android.telephony.mockmodem.iradioconfig"; - private static final String BIND_IRADIOSATELLITE = - "android.telephony.mockmodem.iradiosatellite"; private static final String PHONE_ID = "phone_id"; private static final byte DEFAULT_PHONE_ID = 0x00; @@ -68,7 +65,6 @@ public class MockModem { private IBinder mVoiceBinder; private IBinder mImsBinder; private IBinder mConfigBinder; - private IBinder mSatelliteBinder; private ServiceConnection mModemServiceConnection; private ServiceConnection mSimServiceConnection; private ServiceConnection mMessagingServiceConnection; @@ -77,7 +73,6 @@ public class MockModem { private ServiceConnection mVoiceServiceConnection; private ServiceConnection mImsServiceConnection; private ServiceConnection mConfigServiceConnection; - private ServiceConnection mSatelliteServiceConnection; private byte mPhoneId; private String mTag; @@ -120,8 +115,6 @@ public class MockModem { mVoiceBinder = binder; } else if (mService == HAL_SERVICE_IMS) { mImsBinder = binder; - } else if (mService == HAL_SERVICE_SATELLITE) { - mSatelliteBinder = binder; } else if (mService == RADIOCONFIG_SERVICE) { mConfigBinder = binder; } @@ -145,8 +138,6 @@ public class MockModem { mVoiceBinder = null; } else if (mService == HAL_SERVICE_IMS) { mImsBinder = null; - } else if (mService == HAL_SERVICE_SATELLITE) { - mSatelliteBinder = null; } else if (mService == RADIOCONFIG_SERVICE) { mConfigBinder = null; } @@ -188,8 +179,6 @@ public class MockModem { return mVoiceBinder; case HAL_SERVICE_IMS: return mImsBinder; - case HAL_SERVICE_SATELLITE: - return mSatelliteBinder; case RADIOCONFIG_SERVICE: return mConfigBinder; default: @@ -317,20 +306,6 @@ public class MockModem { } else { Rlog.d(TAG, "IRadio Ims is bound"); } - } else if (service == HAL_SERVICE_SATELLITE) { - if (mSatelliteBinder == null) { - mSatelliteServiceConnection = new MockModemConnection(HAL_SERVICE_SATELLITE); - - boolean status = - bindModuleToMockModemService( - mPhoneId, BIND_IRADIOSATELLITE, mSatelliteServiceConnection); - if (!status) { - Rlog.d(TAG, "IRadio Satellite bind fail"); - mSatelliteServiceConnection = null; - } - } else { - Rlog.d(TAG, "IRadio Satellite is bound"); - } } } @@ -393,13 +368,6 @@ public class MockModem { mImsBinder = null; Rlog.d(TAG, "unbind IRadio Ims"); } - } else if (service == HAL_SERVICE_SATELLITE) { - if (mSatelliteServiceConnection != null) { - mContext.unbindService(mSatelliteServiceConnection); - mSatelliteServiceConnection = null; - mSatelliteBinder = null; - Rlog.d(TAG, "unbind IRadio Satellite"); - } } } @@ -423,8 +391,6 @@ public class MockModem { return "voice"; case HAL_SERVICE_IMS: return "ims"; - case HAL_SERVICE_SATELLITE: - return "satellite"; case RADIOCONFIG_SERVICE: return "config"; default: diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 2d64a44732..54e44e663f 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -22,7 +22,6 @@ import static android.telephony.TelephonyManager.HAL_SERVICE_MESSAGING; import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM; import static android.telephony.TelephonyManager.HAL_SERVICE_NETWORK; import static android.telephony.TelephonyManager.HAL_SERVICE_RADIO; -import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE; import static android.telephony.TelephonyManager.HAL_SERVICE_SIM; import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; @@ -227,7 +226,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public static final int MIN_SERVICE_IDX = HAL_SERVICE_RADIO; - public static final int MAX_SERVICE_IDX = HAL_SERVICE_SATELLITE; + public static final int MAX_SERVICE_IDX = HAL_SERVICE_IMS; /** * An array of sets that records if services are disabled in the HAL for a specific phone ID @@ -262,8 +261,6 @@ public class RIL extends BaseCommands implements CommandsInterface { private ModemIndication mModemIndication; private NetworkResponse mNetworkResponse; private NetworkIndication mNetworkIndication; - private SatelliteResponse mSatelliteResponse; - private SatelliteIndication mSatelliteIndication; private SimResponse mSimResponse; private SimIndication mSimIndication; private VoiceResponse mVoiceResponse; @@ -746,7 +743,7 @@ public class RIL extends BaseCommands implements CommandsInterface { /** * Returns a {@link RadioDataProxy}, {@link RadioMessagingProxy}, {@link RadioModemProxy}, * {@link RadioNetworkProxy}, {@link RadioSimProxy}, {@link RadioVoiceProxy}, - * {@link RadioImsProxy}, {@link RadioSatelliteProxy}, or null if the service is not available. + * {@link RadioImsProxy}, or null if the service is not available. */ @NonNull public T getRadioServiceProxy(Class serviceClass, @@ -772,9 +769,6 @@ public class RIL extends BaseCommands implements CommandsInterface { if (serviceClass == RadioImsProxy.class) { return (T) getRadioServiceProxy(HAL_SERVICE_IMS, result); } - if (serviceClass == RadioSatelliteProxy.class) { - return (T) getRadioServiceProxy(HAL_SERVICE_SATELLITE, result); - } riljLoge("getRadioServiceProxy: unrecognized " + serviceClass); return null; } @@ -918,21 +912,6 @@ public class RIL extends BaseCommands implements CommandsInterface { .asInterface(binder))); } break; - case HAL_SERVICE_SATELLITE: - if (mMockModem == null) { - binder = ServiceManager.waitForDeclaredService( - android.hardware.radio.satellite.IRadioSatellite.DESCRIPTOR - + "/" + HIDL_SERVICE_NAME[mPhoneId]); - } else { - binder = mMockModem.getServiceBinder(HAL_SERVICE_SATELLITE); - } - if (binder != null) { - mHalVersion.put(service, ((RadioSatelliteProxy) serviceProxy).setAidl( - mHalVersion.get(service), - android.hardware.radio.satellite.IRadioSatellite.Stub - .asInterface(binder))); - } - break; } if (serviceProxy.isEmpty() @@ -1057,12 +1036,6 @@ public class RIL extends BaseCommands implements CommandsInterface { ((RadioImsProxy) serviceProxy).getAidl().setResponseFunctions( mImsResponse, mImsIndication); break; - case HAL_SERVICE_SATELLITE: - mDeathRecipients.get(service).linkToDeath( - ((RadioSatelliteProxy) serviceProxy).getAidl().asBinder()); - ((RadioSatelliteProxy) serviceProxy).getAidl().setResponseFunctions( - mSatelliteResponse, mSatelliteIndication); - break; } } else { if (mHalVersion.get(service) @@ -1177,8 +1150,6 @@ public class RIL extends BaseCommands implements CommandsInterface { mModemIndication = new ModemIndication(this); mNetworkResponse = new NetworkResponse(this); mNetworkIndication = new NetworkIndication(this); - mSatelliteResponse = new SatelliteResponse(this); - mSatelliteIndication = new SatelliteIndication(this); mSimResponse = new SimResponse(this); mSimIndication = new SimIndication(this); mVoiceResponse = new VoiceResponse(this); @@ -1213,7 +1184,6 @@ public class RIL extends BaseCommands implements CommandsInterface { mServiceProxies.put(HAL_SERVICE_SIM, new RadioSimProxy()); mServiceProxies.put(HAL_SERVICE_VOICE, new RadioVoiceProxy()); mServiceProxies.put(HAL_SERVICE_IMS, new RadioImsProxy()); - mServiceProxies.put(HAL_SERVICE_SATELLITE, new RadioSatelliteProxy()); } else { mServiceProxies = proxies; } @@ -1296,9 +1266,6 @@ public class RIL extends BaseCommands implements CommandsInterface { case HAL_SERVICE_IMS: serviceName = android.hardware.radio.ims.IRadioIms.DESCRIPTOR; break; - case HAL_SERVICE_SATELLITE: - serviceName = android.hardware.radio.satellite.IRadioSatellite.DESCRIPTOR; - break; } if (!serviceName.equals("") @@ -5768,33 +5735,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void getSatelliteCapabilities(Message result) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_SATELLITE_CAPABILITIES, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.getCapabilities(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - HAL_SERVICE_SATELLITE, "getSatelliteCapabilities", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "getSatelliteCapabilities: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -5807,32 +5752,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void setSatellitePower(Message result, boolean on) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_SATELLITE_POWER, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.setPower(rr.mSerial, on); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, "setSatellitePower", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setSatellitePower: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -5843,32 +5767,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void getSatellitePowerState(Message result) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_SATELLITE_POWER, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.getPowerState(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, "getSatellitePowerState", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "getSatellitePowerState: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -5885,33 +5788,11 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void provisionSatelliteService( Message result, String imei, String msisdn, String imsi, int[] features) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_PROVISION_SATELLITE_SERVICE, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.provisionService(rr.mSerial, imei, msisdn, imsi, features); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - HAL_SERVICE_SATELLITE, "provisionSatelliteService", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "provisionSatelliteService: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -5924,33 +5805,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void addAllowedSatelliteContacts(Message result, String[] contacts) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_ADD_ALLOWED_SATELLITE_CONTACTS, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.addAllowedSatelliteContacts(rr.mSerial, contacts); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, - "addAllowedSatelliteContacts", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "addAllowedSatelliteContacts: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -5963,33 +5822,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void removeAllowedSatelliteContacts(Message result, String[] contacts) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_REMOVE_ALLOWED_SATELLITE_CONTACTS, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.removeAllowedSatelliteContacts(rr.mSerial, contacts); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, - "removeAllowedSatelliteContacts", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "removeAllowedSatelliteContacts: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -6005,33 +5842,11 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void sendSatelliteMessages(Message result, String[] messages, String destination, double latitude, double longitude) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest( - RIL_REQUEST_SEND_SATELLITE_MESSAGES, result, mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.sendMessages(rr.mSerial, messages, destination, latitude, - longitude); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, "sendSatelliteMessages", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "sendSatelliteMessages: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -6042,33 +5857,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void getPendingSatelliteMessages(Message result) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_PENDING_SATELLITE_MESSAGES, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.getPendingMessages(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR( - HAL_SERVICE_SATELLITE, "getPendingSatelliteMessages", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "getPendingSatelliteMessages: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -6079,32 +5872,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void getSatelliteMode(Message result) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_SATELLITE_MODE, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.getSatelliteMode(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, "getSatelliteMode", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "getSatelliteMode: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -6117,33 +5889,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void setSatelliteIndicationFilter(Message result, int filterBitmask) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_SET_SATELLITE_INDICATION_FILTER, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.setIndicationFilter(rr.mSerial, filterBitmask); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, - "setSatelliteIndicationFilter", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, "setSatelliteIndicationFilter: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -6154,16 +5904,12 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void isSatelliteSupported(Message result) { + // Satellite HAL APIs are not supported before Android V. if (result != null) { AsyncResult.forMessage(result, null, CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); result.sendToTarget(); } - /** - * TODO: when adding implementation of this method, we need to return successful result - * with satellite support set to false if radioSatelliteProxy.isEmpty() is true or - * mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0) is false. - */ } /** @@ -6174,44 +5920,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void startSendingSatellitePointingInfo(Message result) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, - "startSendingSatellitePointingInfo: RADIO_NOT_AVAILABLE"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); - result.sendToTarget(); - } - } - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_START_SENDING_SATELLITE_POINTING_INFO, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.startSendingSatellitePointingInfo(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, - "startSendingSatellitePointingInfo", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, - "startSendingSatellitePointingInfo: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -6222,44 +5935,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void stopSendingSatellitePointingInfo(Message result) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, - "startSendingSatellitePointingInfo: RADIO_NOT_AVAILABLE"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); - result.sendToTarget(); - } - } - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_STOP_SENDING_SATELLITE_POINTING_INFO, result, - mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.stopSendingSatellitePointingInfo(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, - "stopSendingSatellitePointingInfo", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, - "stopSendingSatellitePointingInfo: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -6270,34 +5950,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void getMaxCharactersPerSatelliteTextMessage(Message result) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE, - result, mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.getMaxCharactersPerTextMessage(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, - "getMaxCharactersPerSatelliteTextMessage", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, - "getMaxCharactersPerSatelliteTextMessage: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -6308,11 +5965,7 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void isSatelliteCommunicationAllowedForCurrentLocation(Message result) { - // TODO: link to HAL implementation - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, - "stopSendingSatellitePointingInfo: REQUEST_NOT_SUPPORTED"); - } + // Satellite HAL APIs are not supported before Android V. if (result != null) { AsyncResult.forMessage(result, null, CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); @@ -6327,34 +5980,11 @@ public class RIL extends BaseCommands implements CommandsInterface { */ @Override public void getTimeForNextSatelliteVisibility(Message result) { - RadioSatelliteProxy radioSatelliteProxy = - getRadioServiceProxy(RadioSatelliteProxy.class, result); - if (radioSatelliteProxy.isEmpty()) return; - if (mHalVersion.get(HAL_SERVICE_SATELLITE).greaterOrEqual(RADIO_HAL_VERSION_2_0)) { - RILRequest rr = obtainRequest(RIL_REQUEST_GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY, - result, mRILDefaultWorkSource); - - if (RILJ_LOGD) { - // Do not log function arg for privacy - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); - } - - try { - radioSatelliteProxy.getTimeForNextSatelliteVisibility(rr.mSerial); - } catch (RemoteException | RuntimeException e) { - handleRadioProxyExceptionForRR(HAL_SERVICE_SATELLITE, - "getTimeForNextSatelliteVisibility", e); - } - } else { - if (RILJ_LOGD) { - Rlog.d(RILJ_LOG_TAG, - "getTimeForNextSatelliteVisibility: REQUEST_NOT_SUPPORTED"); - } - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); } } @@ -7148,7 +6778,6 @@ public class RIL extends BaseCommands implements CommandsInterface { pw.println(" " + mServiceProxies.get(HAL_SERVICE_SIM)); pw.println(" " + mServiceProxies.get(HAL_SERVICE_VOICE)); pw.println(" " + mServiceProxies.get(HAL_SERVICE_IMS)); - pw.println(" " + mServiceProxies.get(HAL_SERVICE_SATELLITE)); pw.println(" mWakeLock=" + mWakeLock); pw.println(" mWakeLockTimeout=" + mWakeLockTimeout); synchronized (mRequestList) { @@ -7278,8 +6907,6 @@ public class RIL extends BaseCommands implements CommandsInterface { return "VOICE"; case HAL_SERVICE_IMS: return "IMS"; - case HAL_SERVICE_SATELLITE: - return "SATELLITE"; default: return "UNKNOWN:" + service; } diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 9c0acc1a03..207668e7f2 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -25,7 +25,6 @@ import static android.telephony.TelephonyManager.CAPABILITY_THERMAL_MITIGATION_D import static android.telephony.TelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ADD_ALLOWED_SATELLITE_CONTACTS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ALLOCATE_PDU_SESSION_ID; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ALLOW_DATA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ANSWER; @@ -91,17 +90,12 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_HARDWA import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMEI; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMEISV; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMSI; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MODEM_STATUS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_MUTE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_NEIGHBORING_CELL_IDS; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PENDING_SATELLITE_MESSAGES; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PHONE_CAPABILITY; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_RADIO_CAPABILITY; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SATELLITE_CAPABILITIES; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SATELLITE_MODE; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SATELLITE_POWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_PHONEBOOK_CAPACITY; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_PHONEBOOK_RECORDS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_STATUS; @@ -109,7 +103,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLICIN import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLOT_STATUS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SMSC_ADDRESS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_USAGE_SETTING; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GSM_BROADCAST_ACTIVATION; @@ -133,7 +126,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_NV_WRITE_I import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OEM_HOOK_RAW; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OEM_HOOK_STRINGS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_OPERATOR; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PROVISION_SATELLITE_SERVICE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_PULL_LCEDATA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_AVAILABLE_NETWORKS; @@ -145,14 +137,12 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_NETW import static com.android.internal.telephony.RILConstants.RIL_REQUEST_QUERY_TTY_MODE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RELEASE_PDU_SESSION_ID; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REMOVE_ALLOWED_SATELLITE_CONTACTS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REPORT_SMS_MEMORY_STATUS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RESET_RADIO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SCREEN_STATE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_ANBR_QUERY; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_DEVICE_STATE; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SATELLITE_MESSAGES; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_USSD; @@ -182,8 +172,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_NULL_C import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_DATA_MODEM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_RADIO_CAPABILITY; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SATELLITE_INDICATION_FILTER; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SATELLITE_POWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SIM_CARD_POWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SMSC_ADDRESS; @@ -209,7 +197,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_IMS_ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_KEEPALIVE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_LCE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_NETWORK_SCAN; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_START_SENDING_SATELLITE_POINTING_INFO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_GET_PROFILE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND; @@ -220,7 +207,6 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_IMS_T import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_KEEPALIVE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_LCE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_NETWORK_SCAN; -import static com.android.internal.telephony.RILConstants.RIL_REQUEST_STOP_SENDING_SATELLITE_POINTING_INFO; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN; @@ -255,7 +241,6 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_KEEPALIVE_ST import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NEW_SATELLITE_MESSAGES; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NOTIFY_ANBR; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_OEM_HOOK_RAW; @@ -263,7 +248,6 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_SS; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD_REQUEST; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PCO_DATA; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RADIO_CAPABILITY; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_REGISTRATION_FAILED; @@ -283,11 +267,6 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_SIM import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESTRICTED_STATE_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RIL_CONNECTED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RINGBACK_TONE; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MODE_CHANGED; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIGNAL_STRENGTH; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIM_REFRESH; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIM_SMS_STORAGE_FULL; @@ -374,8 +353,6 @@ import android.telephony.ims.feature.ConnectionFailureInfo; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsRegistrationImplBase.ImsDeregistrationReason; -import android.telephony.satellite.PointingInfo; -import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteManager; import android.text.TextUtils; import android.util.ArraySet; @@ -5366,34 +5343,6 @@ public class RILUtils { return "SET_N1_MODE_ENABLED"; case RIL_REQUEST_IS_N1_MODE_ENABLED: return "IS_N1_MODE_ENABLED"; - case RIL_REQUEST_GET_SATELLITE_CAPABILITIES: - return "GET_SATELLITE_CAPABILITIES"; - case RIL_REQUEST_SET_SATELLITE_POWER: - return "SET_SATELLITE_POWER"; - case RIL_REQUEST_GET_SATELLITE_POWER: - return "GET_SATELLITE_POWER"; - case RIL_REQUEST_PROVISION_SATELLITE_SERVICE: - return "PROVISION_SATELLITE_SERVICE"; - case RIL_REQUEST_ADD_ALLOWED_SATELLITE_CONTACTS: - return "ADD_ALLOWED_SATELLITE_CONTACTS"; - case RIL_REQUEST_REMOVE_ALLOWED_SATELLITE_CONTACTS: - return "REMOVE_ALLOWED_SATELLITE_CONTACTS"; - case RIL_REQUEST_SEND_SATELLITE_MESSAGES: - return "SEND_SATELLITE_MESSAGES"; - case RIL_REQUEST_GET_PENDING_SATELLITE_MESSAGES: - return "GET_PENDING_SATELLITE_MESSAGES"; - case RIL_REQUEST_GET_SATELLITE_MODE: - return "GET_SATELLITE_MODE"; - case RIL_REQUEST_SET_SATELLITE_INDICATION_FILTER: - return "SET_SATELLITE_INDICATION_FILTER"; - case RIL_REQUEST_START_SENDING_SATELLITE_POINTING_INFO: - return "START_SENDING_SATELLITE_POINTING_INFO"; - case RIL_REQUEST_STOP_SENDING_SATELLITE_POINTING_INFO: - return "STOP_SENDING_SATELLITE_POINTING_INFO"; - case RIL_REQUEST_GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE: - return "GET_MAX_CHARACTERS_PER_SATELLITE_TEXT_MESSAGE"; - case RIL_REQUEST_GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY: - return "GET_TIME_FOR_NEXT_SATELLITE_VISIBILITY"; default: return ""; } @@ -5534,20 +5483,6 @@ public class RILUtils { return "UNSOL_NOTIFY_ANBR"; case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION: return "UNSOL_TRIGGER_IMS_DEREGISTRATION"; - case RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT: - return "UNSOL_PENDING_SATELLITE_MESSAGE_COUNT"; - case RIL_UNSOL_NEW_SATELLITE_MESSAGES: - return "UNSOL_NEW_SATELLITE_MESSAGES"; - case RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE: - return "UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE"; - case RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED: - return "UNSOL_SATELLITE_POINTING_INFO_CHANGED"; - case RIL_UNSOL_SATELLITE_MODE_CHANGED: - return "UNSOL_SATELLITE_MODE_CHANGED"; - case RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED: - return "UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED"; - case RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED: - return "UNSOL_SATELLITE_PROVISION_STATE_CHANGED"; default: return ""; } @@ -5932,50 +5867,6 @@ public class RILUtils { return halInfos; } - /** - * Convert android.hardware.radio.satellite.SatelliteCapabilities to - * android.telephony.satellite.SatelliteCapabilities - */ - public static SatelliteCapabilities convertHalSatelliteCapabilities( - android.hardware.radio.satellite.SatelliteCapabilities capabilities) { - Set supportedRadioTechnologies = new HashSet<>(); - if (capabilities.supportedRadioTechnologies != null - && capabilities.supportedRadioTechnologies.length > 0) { - for (int technology : capabilities.supportedRadioTechnologies) { - supportedRadioTechnologies.add(technology); - } - } - return new SatelliteCapabilities(supportedRadioTechnologies, capabilities.isAlwaysOn, - capabilities.needsPointingToSatellite, capabilities.needsSeparateSimProfile); - } - - /** - * Convert from android.hardware.radio.satellite.PointingInfo to - * android.telephony.satellite.stub.PointingInfo - */ - public static PointingInfo convertHalSatellitePointingInfo( - android.hardware.radio.satellite.PointingInfo pointingInfo) { - return new PointingInfo(pointingInfo.satelliteAzimuthDegrees, - pointingInfo.satelliteElevationDegrees, pointingInfo.antennaAzimuthDegrees, - pointingInfo.antennaPitchDegrees, pointingInfo.antennaRollDegrees); - } - - /** - * Convert from android.telephony.satellite.stub.PointingInfo to - * android.hardware.radio.satellite.PointingInfo - */ - public static android.hardware.radio.satellite.PointingInfo convertToHalSatellitePointingInfo( - PointingInfo pointingInfo) { - android.hardware.radio.satellite.PointingInfo halPointingInfo = - new android.hardware.radio.satellite.PointingInfo(); - halPointingInfo.satelliteAzimuthDegrees = pointingInfo.getSatelliteAzimuthDegrees(); - halPointingInfo.satelliteElevationDegrees = pointingInfo.getSatelliteElevationDegrees(); - halPointingInfo.antennaAzimuthDegrees = pointingInfo.getAntennaAzimuthDegrees(); - halPointingInfo.antennaPitchDegrees = pointingInfo.getAntennaPitchDegrees(); - halPointingInfo.antennaRollDegrees = pointingInfo.getAntennaRollDegrees(); - return halPointingInfo; - } - /** * Convert satellite-related errors from CommandException.Error to * SatelliteManager.SatelliteServiceResult. @@ -6006,18 +5897,12 @@ public class RILUtils { return SatelliteManager.SATELLITE_NO_RESOURCES; case NETWORK_ERR: return SatelliteManager.SATELLITE_NETWORK_ERROR; - case NETWORK_TIMEOUT: - return SatelliteManager.SATELLITE_NETWORK_TIMEOUT; case NO_NETWORK_FOUND: - //fallthrough to NO_SATELLITE_SIGNAL - case NO_SATELLITE_SIGNAL: return SatelliteManager.SATELLITE_NOT_REACHABLE; case ABORTED: return SatelliteManager.SATELLITE_REQUEST_ABORTED; case ACCESS_BARRED: return SatelliteManager.SATELLITE_ACCESS_BARRED; - case SUBSCRIBER_NOT_AUTHORIZED: - return SatelliteManager.SATELLITE_NOT_AUTHORIZED; default: return SatelliteManager.SATELLITE_ERROR; } diff --git a/src/java/com/android/internal/telephony/RadioSatelliteProxy.java b/src/java/com/android/internal/telephony/RadioSatelliteProxy.java deleted file mode 100644 index 6101f3fc6a..0000000000 --- a/src/java/com/android/internal/telephony/RadioSatelliteProxy.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import android.os.RemoteException; -import android.telephony.Rlog; - -/** - * A holder for IRadioSatellite. - * Use getAidl to get IRadioSatellite and call the AIDL implementations of the HAL APIs. - */ -public class RadioSatelliteProxy extends RadioServiceProxy { - private static final String TAG = "RadioSatelliteProxy"; - private volatile android.hardware.radio.satellite.IRadioSatellite mSatelliteProxy = null; - - /** - * Sets IRadioSatellite as the AIDL implementation for RadioServiceProxy. - * @param halVersion Radio HAL version. - * @param satellite IRadioSatellite implementation. - * - * @return updated HAL version. - */ - public HalVersion setAidl(HalVersion halVersion, - android.hardware.radio.satellite.IRadioSatellite satellite) { - HalVersion version = halVersion; - try { - version = RIL.getServiceHalVersion(satellite.getInterfaceVersion()); - } catch (RemoteException e) { - Rlog.e(TAG, "setAidl: " + e); - } - mHalVersion = version; - mSatelliteProxy = satellite; - mIsAidl = true; - - Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); - return mHalVersion; - } - - /** - * Gets the AIDL implementation of RadioSatelliteProxy. - * @return IRadioSatellite implementation. - */ - public android.hardware.radio.satellite.IRadioSatellite getAidl() { - return mSatelliteProxy; - } - - /** - * Resets RadioSatelliteProxy. - */ - @Override - public void clear() { - super.clear(); - mSatelliteProxy = null; - } - - /** - * Checks whether a IRadioSatellite implementation exists. - * @return true if there is neither a HIDL nor AIDL implementation. - */ - @Override - public boolean isEmpty() { - return mRadioProxy == null && mSatelliteProxy == null; - } - - /** - * Call IRadioSatellite#responseAcknowledgement - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - @Override - public void responseAcknowledgement() throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.responseAcknowledgement(); - } - } - - /** - * Call IRadioSatellite#getCapabilities - * @param serial Serial number of request. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void getCapabilities(int serial) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.getCapabilities(serial); - } - } - - /** - * Call IRadioSatellite#setPower - * @param serial Serial number of request. - * @param on True for turning on. - * False for turning off. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void setPower(int serial, boolean on) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.setPower(serial, on); - } - } - - /** - * Call IRadioSatellite#getPowerState - * @param serial Serial number of request. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void getPowerState(int serial) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.getPowerState(serial); - } - } - - /** - * Call IRadioSatellite#provisionService - * @param serial Serial number of request. - * @param imei IMEI of the SIM associated with the satellite modem. - * @param msisdn MSISDN of the SIM associated with the satellite modem. - * @param imsi IMSI of the SIM associated with the satellite modem. - * @param features List of features to be provisioned. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void provisionService( - int serial, - String imei, - String msisdn, - String imsi, - int[] features) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.provisionService(serial, imei, msisdn, imsi, features); - } - } - - /** - * Call IRadioSatellite#addAllowedSatelliteContacts - * @param serial Serial number of request. - * @param contacts List of allowed contacts to be added. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void addAllowedSatelliteContacts(int serial, String[] contacts) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.addAllowedSatelliteContacts(serial, contacts); - } - } - - /** - * Call IRadioSatellite#removeAllowedSatelliteContacts - * @param serial Serial number of request. - * @param contacts List of allowed contacts to be removed. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void removeAllowedSatelliteContacts(int serial, String[] contacts) - throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.removeAllowedSatelliteContacts(serial, contacts); - } - } - - /** - * Call IRadioSatellite#sendMessages - * @param serial Serial number of request. - * @param messages List of messages in text format to be sent. - * @param destination The recipient of the message. - * @param latitude The current latitude of the device. - * @param longitude The current longitude of the device - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void sendMessages(int serial, String[] messages, String destination, double latitude, - double longitude) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.sendMessages(serial, messages, destination, latitude, longitude); - } - } - - /** - * Call IRadioSatellite#getPendingMessages - * @param serial Serial number of request. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void getPendingMessages(int serial) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.getPendingMessages(serial); - } - } - - /** - * Call IRadioSatellite#getSatelliteMode - * @param serial Serial number of request. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void getSatelliteMode(int serial) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.getSatelliteMode(serial); - } - } - - /** - * Call IRadioSatellite#setIndicationFilter - * @param serial Serial number of request. - * @param filterBitmask The filter identifying what type of indication framework want to - * receive from modem. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void setIndicationFilter(int serial, int filterBitmask) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.setIndicationFilter(serial, filterBitmask); - } - } - - /** - * Call IRadioSatellite#startSendingSatellitePointingInfo - * @param serial Serial number of request. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void startSendingSatellitePointingInfo(int serial) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.startSendingSatellitePointingInfo(serial); - } - } - - /** - * Call IRadioSatellite#stopSendingSatellitePointingInfo - * @param serial Serial number of request. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void stopSendingSatellitePointingInfo(int serial) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.stopSendingSatellitePointingInfo(serial); - } - } - - /** - * Call IRadioSatellite#getMaxCharactersPerTextMessage - * @param serial Serial number of request. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void getMaxCharactersPerTextMessage(int serial) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.getMaxCharactersPerTextMessage(serial); - } - } - - /** - * Call IRadioSatellite#getTimeForNextSatelliteVisibility - * @param serial Serial number of request. - * @throws RemoteException Throws RemoteException when RadioSatellite service is not available. - */ - public void getTimeForNextSatelliteVisibility(int serial) throws RemoteException { - if (isEmpty()) return; - if (isAidl()) { - mSatelliteProxy.getTimeForNextSatelliteVisibility(serial); - } - } -} diff --git a/src/java/com/android/internal/telephony/SatelliteIndication.java b/src/java/com/android/internal/telephony/SatelliteIndication.java deleted file mode 100644 index 2e561c3dac..0000000000 --- a/src/java/com/android/internal/telephony/SatelliteIndication.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2022 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; - -import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE; - -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NEW_SATELLITE_MESSAGES; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_MODE_CHANGED; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED; -import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED; - -import android.hardware.radio.satellite.IRadioSatelliteIndication; -import android.os.AsyncResult; -import android.telephony.satellite.SatelliteDatagram; -import android.util.Pair; - -/** - * Interface declaring unsolicited radio indications for Satellite APIs. - */ -public class SatelliteIndication extends IRadioSatelliteIndication.Stub { - private final RIL mRil; - - public SatelliteIndication(RIL ril) { - mRil = ril; - } - - @Override - public String getInterfaceHash() { - return IRadioSatelliteIndication.HASH; - } - - @Override - public int getInterfaceVersion() { - return IRadioSatelliteIndication.VERSION; - } - - /** - * Indicates that satellite has pending messages for the device to be pulled. - * - * @param indicationType Type of radio indication - * @param count Number of pending messages. - */ - public void onPendingMessageCount(int indicationType, int count) { - mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); - - if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_PENDING_SATELLITE_MESSAGE_COUNT); - - if (mRil.mPendingSatelliteMessageCountRegistrants != null) { - mRil.mPendingSatelliteMessageCountRegistrants.notifyRegistrants( - new AsyncResult(null, count, null)); - } - } - - /** - * Indicates new message received on device. - * - * @param indicationType Type of radio indication - * @param messages List of new messages received. - */ - public void onNewMessages(int indicationType, String[] messages) { - mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); - - if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_NEW_SATELLITE_MESSAGES); - - if (mRil.mNewSatelliteMessagesRegistrants != null) { - for (int i = 0; i < messages.length; i++) { - SatelliteDatagram datagram = new SatelliteDatagram(messages[i].getBytes()); - mRil.mNewSatelliteMessagesRegistrants.notifyRegistrants( - new AsyncResult(null, new Pair<>(datagram, messages.length - i - 1), null)); - } - } - } - - /** - * Confirms that ongoing message transfer is complete. - * - * @param indicationType Type of radio indication - * @param complete True mean the transfer is complete. - * False means the transfer is not complete. - */ - public void onMessagesTransferComplete(int indicationType, boolean complete) { - mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); - - if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_MESSAGES_TRANSFER_COMPLETE); - - if (mRil.mSatelliteMessagesTransferCompleteRegistrants != null) { - mRil.mSatelliteMessagesTransferCompleteRegistrants.notifyRegistrants( - new AsyncResult(null, complete, null)); - } - } - - /** - * Indicate that satellite Pointing input has changed. - * - * @param indicationType Type of radio indication - * @param pointingInfo The current pointing info. - */ - public void onSatellitePointingInfoChanged(int indicationType, - android.hardware.radio.satellite.PointingInfo pointingInfo) { - mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); - - if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_POINTING_INFO_CHANGED); - - if (mRil.mSatellitePointingInfoChangedRegistrants != null) { - mRil.mSatellitePointingInfoChangedRegistrants.notifyRegistrants( - new AsyncResult( - null, - RILUtils.convertHalSatellitePointingInfo(pointingInfo), - null)); - } - } - - /** - * Indicate that satellite mode has changed. - * - * @param indicationType Type of radio indication - * @param mode The current mode of the satellite modem. - */ - public void onSatelliteModeChanged(int indicationType, int mode) { - mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); - - if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_MODE_CHANGED); - - if (mRil.mSatelliteModeChangedRegistrants != null) { - mRil.mSatelliteModeChangedRegistrants.notifyRegistrants( - new AsyncResult(null, mode, null)); - } - } - - /** - * Indicate that satellite radio technology has changed. - * - * @param indicationType Type of radio indication - * @param technology The current technology of the satellite modem. - */ - public void onSatelliteRadioTechnologyChanged(int indicationType, int technology) { - mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); - - if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_RADIO_TECHNOLOGY_CHANGED); - - if (mRil.mSatelliteRadioTechnologyChangedRegistrants != null) { - mRil.mSatelliteRadioTechnologyChangedRegistrants.notifyRegistrants( - new AsyncResult(null, technology, null)); - } - } - - /** - * Indicate that satellite provision state has changed. - * - * @param indicationType Type of radio indication - * @param provisioned True means the service is provisioned. - * False means the service is not provisioned. - * @param features List of Feature whose provision state has changed. - */ - public void onProvisionStateChanged(int indicationType, boolean provisioned, int[] features) { - // TODO: remove features and update AsyncResult - mRil.processIndication(HAL_SERVICE_SATELLITE, indicationType); - - if (mRil.isLogOrTrace()) mRil.unsljLog(RIL_UNSOL_SATELLITE_PROVISION_STATE_CHANGED); - - if (mRil.mSatelliteProvisionStateChangedRegistrants != null) { - mRil.mSatelliteProvisionStateChangedRegistrants.notifyRegistrants( - new AsyncResult(provisioned, null, null)); - } - } -} diff --git a/src/java/com/android/internal/telephony/SatelliteResponse.java b/src/java/com/android/internal/telephony/SatelliteResponse.java deleted file mode 100644 index 559691b9d9..0000000000 --- a/src/java/com/android/internal/telephony/SatelliteResponse.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import static android.telephony.TelephonyManager.HAL_SERVICE_SATELLITE; - -import android.hardware.radio.RadioError; -import android.hardware.radio.RadioResponseInfo; -import android.hardware.radio.satellite.IRadioSatelliteResponse; -import android.telephony.satellite.SatelliteCapabilities; - -/** - * Interface declaring response functions to solicited radio requests for Satellite APIs. - */ -public class SatelliteResponse extends IRadioSatelliteResponse.Stub { - private final RIL mRil; - - public SatelliteResponse(RIL ril) { - mRil = ril; - } - - /** - * Acknowledge the receipt of radio request sent to the vendor. This must be sent only for - * radio request which take long time to respond. - * For more details, refer https://source.android.com/devices/tech/connect/ril.html - * @param serial Serial no. of the request whose acknowledgement is sent. - */ - public void acknowledgeRequest(int serial) { - mRil.processRequestAck(serial); - } - /** - * Response of the request getCapabilities. - * - * @param responseInfo Response info struct containing serial no. and error - * @param capabilities List of capabilities that the satellite modem supports. - */ - public void getCapabilitiesResponse(RadioResponseInfo responseInfo, - android.hardware.radio.satellite.SatelliteCapabilities capabilities) { - RILRequest rr = mRil.processResponse(HAL_SERVICE_SATELLITE, responseInfo); - - if (rr != null) { - SatelliteCapabilities convertedSatelliteCapabilities = - RILUtils.convertHalSatelliteCapabilities(capabilities); - if (responseInfo.error == RadioError.NONE) { - RadioResponse.sendMessageResponse(rr.mResult, convertedSatelliteCapabilities); - } - mRil.processResponseDone(rr, responseInfo, convertedSatelliteCapabilities); - } - } - - /** - * Response of the request setPower. - * - * @param responseInfo Response info struct containing serial no. and error - */ - public void setPowerResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); - } - - /** - * Response of the request getPowerState. - * - * @param responseInfo Response info struct containing serial no. and error - * @param on True means the modem is ON. - * False means the modem is OFF. - */ - public void getPowerStateResponse(RadioResponseInfo responseInfo, boolean on) { - RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, on ? 1 : 0); - } - - /** - * Response of the request provisionService. - * - * @param responseInfo Response info struct containing serial no. and error - * @param provisioned True means the service is provisioned. - * False means the service is not provisioned. - */ - public void provisionServiceResponse(RadioResponseInfo responseInfo, boolean provisioned) { - RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, provisioned ? 1 : 0); - } - - /** - * Response of the request addAllowedSatelliteContacts. - * - * @param responseInfo Response info struct containing serial no. and error - */ - public void addAllowedSatelliteContactsResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); - } - - /** - * Response of the request removeAllowedSatelliteContacts. - * - * @param responseInfo Response info struct containing serial no. and error - */ - public void removeAllowedSatelliteContactsResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); - } - - /** - * Response of the request sendMessages. - * - * @param responseInfo Response info struct containing serial no. and error - */ - public void sendMessagesResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); - } - - /** - * Response of the request getPendingMessages. - * - * @param responseInfo Response info struct containing serial no. and error - * @param messages List of pending messages received. - */ - public void getPendingMessagesResponse(RadioResponseInfo responseInfo, String[] messages) { - RILRequest rr = mRil.processResponse(HAL_SERVICE_SATELLITE, responseInfo); - - if (rr != null) { - if (responseInfo.error == RadioError.NONE) { - RadioResponse.sendMessageResponse(rr.mResult, messages); - } - mRil.processResponseDone(rr, responseInfo, messages); - } - } - - /** - * Response of the request getSatelliteMode. - * - * @param responseInfo Response info struct containing serial no. and error - * @param mode Current Mode of the satellite modem. - * @param technology The current technology of the satellite modem. - */ - public void getSatelliteModeResponse(RadioResponseInfo responseInfo, int mode, int technology) { - RILRequest rr = mRil.processResponse(HAL_SERVICE_SATELLITE, responseInfo); - - if (rr != null) { - int[] ret = new int[]{mode, technology}; - if (responseInfo.error == RadioError.NONE) { - RadioResponse.sendMessageResponse(rr.mResult, ret); - } - mRil.processResponseDone(rr, responseInfo, ret); - } - } - - /** - * Response of the request setIndicationFilter. - * - * @param responseInfo Response info struct containing serial no. and error - */ - public void setIndicationFilterResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); - } - - /** - * Response of the request startSendingSatellitePointingInfo. - * - * @param responseInfo Response info struct containing serial no. and error - */ - public void startSendingSatellitePointingInfoResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); - } - - /** - * Response of the request stopSendingSatellitePointingInfo. - * - * @param responseInfo Response info struct containing serial no. and error - */ - public void stopSendingSatellitePointingInfoResponse(RadioResponseInfo responseInfo) { - RadioResponse.responseVoid(HAL_SERVICE_SATELLITE, mRil, responseInfo); - } - - /** - * Response of the request getMaxCharactersPerTextMessage. - * - * @param responseInfo Response info struct containing serial no. and error - * @param charLimit Maximum number of characters in a text message that can be sent. - */ - public void getMaxCharactersPerTextMessageResponse( - RadioResponseInfo responseInfo, int charLimit) { - RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, charLimit); - } - - /** - * Response of the request getTimeForNextSatelliteVisibility. - * - * @param responseInfo Response info struct containing serial no. and error - * @param timeInSeconds The duration in seconds after which the satellite will be visible. - */ - public void getTimeForNextSatelliteVisibilityResponse( - RadioResponseInfo responseInfo, int timeInSeconds) { - RadioResponse.responseInts(HAL_SERVICE_SATELLITE, mRil, responseInfo, timeInSeconds); - } - - @Override - public String getInterfaceHash() { - return IRadioSatelliteResponse.HASH; - } - - @Override - public int getInterfaceVersion() { - return IRadioSatelliteResponse.VERSION; - } -} -- GitLab From bf320efe5390a9d16f3e9c41c651ed6e1987eeb7 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Mon, 6 Mar 2023 13:38:25 -0800 Subject: [PATCH 490/656] Broadcast Locale to all users Previously the locale is only broadcasted to user admin, so it doesn't work on auto or wear(user 10) Fix: 268208929 Test: the previously failed test now pass Change-Id: Ib1ff087095175d7254df89de3be5a394626c8bdd --- src/java/com/android/internal/telephony/LocaleTracker.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java index 31d6686484..de854fa7ca 100644 --- a/src/java/com/android/internal/telephony/LocaleTracker.java +++ b/src/java/com/android/internal/telephony/LocaleTracker.java @@ -30,6 +30,7 @@ import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.UserHandle; import android.sysprop.TelephonyProperties; import android.telephony.CellInfo; import android.telephony.ServiceState; @@ -558,7 +559,7 @@ public class LocaleTracker extends Handler { intent.putExtra(TelephonyManager.EXTRA_LAST_KNOWN_NETWORK_COUNTRY, getLastKnownCountryIso()); SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); - mPhone.getContext().sendBroadcast(intent); + mPhone.getContext().sendBroadcastAsUser(intent, UserHandle.ALL); } // Pass the geographical country information to the telephony time zone detection code. -- GitLab From 561596267be42857b72a692aa7eb0d1d464583ef Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Wed, 1 Mar 2023 17:24:35 -0800 Subject: [PATCH 491/656] Use carrier config to exempt data switch ping test Ping test validation can be exempt if device uses RF allocation. The config was for CBRS, now it's extended for auto data switch pre-switch validation as well. Fix: 268077711 Test: fake auto switch condition and confirm switch takes place Change-Id: I4faf081dbfdec25efb86f6a3e1dc06425a9149ae --- .../telephony/data/DataConfigManager.java | 19 ++++++ .../telephony/data/PhoneSwitcher.java | 43 ++++++++++--- .../telephony/data/PhoneSwitcherTest.java | 60 ++++++++++++++++--- 3 files changed, 106 insertions(+), 16 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index 731aac75f3..b858c94201 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -319,6 +319,8 @@ public class DataConfigManager extends Handler { private @NonNull final List mHandoverRuleList = new ArrayList<>(); /** {@code True} keep IMS network in case of moving to non VOPS area; {@code false} otherwise.*/ private boolean mShouldKeepNetworkUpInNonVops = false; + /** {@code True} requires ping test before switching preferred modem; {@code false} otherwise.*/ + private boolean mPingTestBeforeDataSwitch = true; /** * Constructor @@ -472,6 +474,7 @@ public class DataConfigManager extends Handler { updateMeteredApnTypes(); updateSingleDataNetworkTypeAndCapabilityExemption(); updateVopsConfig(); + updateDataSwitchConfig(); updateUnmeteredNetworkTypes(); updateBandwidths(); updateTcpBuffers(); @@ -692,6 +695,16 @@ public class DataConfigManager extends Handler { } } + /** + * Update preferred modem switch(opportunistic network or visible subscription) carrier config. + */ + private void updateDataSwitchConfig() { + synchronized (this) { + mPingTestBeforeDataSwitch = mCarrierConfig.getBoolean(CarrierConfigManager + .KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL, true); + } + } + /** * @return The list of {@link NetworkType} that only supports single data networks */ @@ -712,6 +725,11 @@ public class DataConfigManager extends Handler { return mShouldKeepNetworkUpInNonVops; } + /** {@code True} keep IMS network in case of moving to non VOPS area; {@code false} otherwise.*/ + public boolean requirePingTestBeforeDataSwitch() { + return mPingTestBeforeDataSwitch; + } + /** * @return Whether {@link NetworkCapabilities#NET_CAPABILITY_TEMPORARILY_NOT_METERED} * is supported by the carrier. @@ -1344,6 +1362,7 @@ public class DataConfigManager extends Handler { .stream().map(DataUtils::networkCapabilityToString) .collect(Collectors.joining(","))); pw.println("mShouldKeepNetworkUpInNoVops=" + mShouldKeepNetworkUpInNonVops); + pw.println("mPingTestBeforeDataSwitch=" + mPingTestBeforeDataSwitch); pw.println("Unmetered network types=" + String.join(",", mUnmeteredNetworkTypes)); pw.println("Roaming unmetered network types=" + String.join(",", mRoamingUnmeteredNetworkTypes)); diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 2ac9777701..0af51ec724 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -298,12 +298,18 @@ public class PhoneSwitcher extends Handler { @Override public void onDeviceConfigChanged() { log("onDeviceConfigChanged"); - PhoneSwitcher.this.updateConfig(); + PhoneSwitcher.this.updateDeviceConfig(); + } + + @Override + public void onCarrierConfigChanged() { + log("onCarrierConfigChanged"); + PhoneSwitcher.this.updateCarrierConfig(); } }; private static final int EVENT_PRIMARY_DATA_SUB_CHANGED = 101; - protected static final int EVENT_SUBSCRIPTION_CHANGED = 102; + protected static final int EVENT_SUBSCRIPTION_CHANGED = 102; private static final int EVENT_REQUEST_NETWORK = 103; private static final int EVENT_RELEASE_NETWORK = 104; // ECBM has started/ended. If we just ended an emergency call and mEmergencyOverride is not @@ -361,6 +367,12 @@ public class PhoneSwitcher extends Handler { private List> mCurrentDdsSwitchFailure; + /** + * {@code true} if requires ping test before switching preferred data modem; otherwise, switch + * even if ping test fails. + */ + private boolean mRequirePingTestBeforeDataSwitch = true; + /** * Time threshold in ms to define a internet connection status to be stable(e.g. out of service, * in service, wifi is the default active network.etc), while -1 indicates auto switch @@ -932,15 +944,15 @@ public class PhoneSwitcher extends Handler { if (phone != null) { DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); dataConfig.registerCallback(mDataConfigManagerCallback); - updateConfig(); + updateDeviceConfig(); sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); } } /** - * Update data config. + * Update device config. */ - private void updateConfig() { + private void updateDeviceConfig() { Phone phone = getPhoneBySubId(mPrimaryDataSubId); if (phone != null) { DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); @@ -951,6 +963,17 @@ public class PhoneSwitcher extends Handler { } } + /** + * Update carrier config. + */ + private void updateCarrierConfig() { + Phone phone = getPhoneBySubId(mPrimaryDataSubId); + if (phone != null) { + DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); + mRequirePingTestBeforeDataSwitch = dataConfig.requirePingTestBeforeDataSwitch(); + } + } + private synchronized void onMultiSimConfigChanged(int activeModemCount) { // No change. if (mActiveModemCount == activeModemCount) return; @@ -1158,7 +1181,7 @@ public class PhoneSwitcher extends Handler { int candidateSubId = getAutoSwitchTargetSubIdIfExists(); if (candidateSubId != INVALID_SUBSCRIPTION_ID) { - startAutoDataSwitchStabilityCheck(candidateSubId, true); + startAutoDataSwitchStabilityCheck(candidateSubId, mRequirePingTestBeforeDataSwitch); } else { cancelPendingAutoDataSwitch(); } @@ -1193,7 +1216,8 @@ public class PhoneSwitcher extends Handler { if (isInService(mPhoneStates[primaryPhoneId])) { // primary becomes available - startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, true); + startAutoDataSwitchStabilityCheck(DEFAULT_SUBSCRIPTION_ID, + mRequirePingTestBeforeDataSwitch); return; } @@ -2067,8 +2091,8 @@ public class PhoneSwitcher extends Handler { * @param reason The switching reason. */ private void logDataSwitchEvent(int subId, int state, int reason) { - logl("Data switch event. subId=" + subId + ", state=" + switchStateToString(state) - + ", reason=" + switchReasonToString(reason)); + logl("Data switch state=" + switchStateToString(state) + " due to reason=" + + switchReasonToString(reason) + " on subId " + subId); DataSwitch dataSwitch = new DataSwitch(); dataSwitch.state = state; dataSwitch.reason = reason; @@ -2141,6 +2165,7 @@ public class PhoneSwitcher extends Handler { pw.println("mAutoDataSwitchAvailabilityStabilityTimeThreshold=" + mAutoDataSwitchAvailabilityStabilityTimeThreshold); pw.println("mAutoDataSwitchValidationMaxRetry=" + mAutoDataSwitchValidationMaxRetry); + pw.println("mRequirePingTestBeforeDataSwitch=" + mRequirePingTestBeforeDataSwitch); pw.println("mLastSwitchPreferredDataReason=" + switchReasonToString(mLastSwitchPreferredDataReason)); pw.println("mDisplayedAutoSwitchNotification=" + mDisplayedAutoSwitchNotification); 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 1047be5fef..21197180cb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -131,6 +131,7 @@ public class PhoneSwitcherTest extends TelephonyTest { private Messenger mNetworkProviderMessenger = null; private Map mDataSettingsManagerCallbacks; + private DataConfigManager.DataConfigManagerCallback mDataConfigManagerCallback; private int mDefaultDataSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private int[][] mSlotIndexToSubId; private boolean[] mDataAllowed; @@ -562,7 +563,7 @@ public class PhoneSwitcherTest extends TelephonyTest { @Test @SmallTest - public void testAutoDataSwitchRetry() throws Exception { + public void testAutoDataSwitch_retry() throws Exception { initialize(); // Phone 0 has sub 1, phone 1 has sub 2. // Sub 1 is default data sub. @@ -590,7 +591,7 @@ public class PhoneSwitcherTest extends TelephonyTest { @Test @SmallTest - public void testAutoDataSwitchSetNotification() throws Exception { + public void testAutoDataSwitch_setNotification() throws Exception { SubscriptionInfo mockedInfo = mock(SubscriptionInfo.class); doReturn(false).when(mockedInfo).isOpportunistic(); doReturn(mockedInfo).when(mSubscriptionController).getSubscriptionInfo(anyInt()); @@ -636,6 +637,41 @@ public class PhoneSwitcherTest extends TelephonyTest { } } + @Test + @SmallTest + public void testAutoDataSwitch_exemptPingTest() throws Exception { + initialize(); + // Phone 0 has sub 1, phone 1 has sub 2. + // Sub 1 is default data sub. + setSlotIndexToSubId(0, 1); + setSlotIndexToSubId(1, 2); + setDefaultDataSubId(1); + + doReturn(false).when(mDataConfigManager).requirePingTestBeforeDataSwitch(); + mDataConfigManagerCallback.onCarrierConfigChanged(); + + //1. Attempting to switch to nDDS, switch even if validation failed + prepareIdealAutoSwitchCondition(); + processAllFutureMessages(); + + verify(mCellularNetworkValidator).validate(eq(2), anyLong(), eq(false), + eq(mPhoneSwitcherUT.mValidationCallback)); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 2); + processAllMessages(); + + assertEquals(2, mPhoneSwitcherUT.getActiveDataSubId()); // switch succeeds + + //2. Attempting to switch back to DDS, switch even if validation failed + serviceStateChanged(0, NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); + processAllFutureMessages(); + verify(mCellularNetworkValidator).validate(eq(1), anyLong(), eq(false), + eq(mPhoneSwitcherUT.mValidationCallback)); + mPhoneSwitcherUT.mValidationCallback.onValidationDone(false, 1); + processAllMessages(); + + assertEquals(1, mPhoneSwitcherUT.getActiveDataSubId()); // switch succeeds + } + /** * Test a multi-sim case with limited active phones: * - lose default via default sub change @@ -1964,7 +2000,6 @@ public class PhoneSwitcherTest extends TelephonyTest { initializeConnManagerMock(); mPhoneSwitcherUT = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper()); - processAllMessages(); Field field = PhoneSwitcher.class.getDeclaredField("mDataSettingsManagerCallbacks"); field.setAccessible(true); @@ -1972,11 +2007,22 @@ public class PhoneSwitcherTest extends TelephonyTest { (Map) field.get(mPhoneSwitcherUT); - int deviceConfigValue = 10000; - field = PhoneSwitcher.class.getDeclaredField( - "mAutoDataSwitchAvailabilityStabilityTimeThreshold"); + field = PhoneSwitcher.class.getDeclaredField("mDataConfigManagerCallback"); field.setAccessible(true); - field.setInt(mPhoneSwitcherUT, deviceConfigValue); + mDataConfigManagerCallback = + (DataConfigManager.DataConfigManagerCallback) field.get(mPhoneSwitcherUT); + + doReturn(mDataNetworkController).when(mPhone).getDataNetworkController(); + doReturn(mDataConfigManager).when(mDataNetworkController).getDataConfigManager(); + doReturn(1000L).when(mDataConfigManager) + .getAutoDataSwitchAvailabilityStabilityTimeThreshold(); + doReturn(7).when(mDataConfigManager).getAutoDataSwitchValidationMaxRetry(); + doReturn(true).when(mDataConfigManager).requirePingTestBeforeDataSwitch(); + + mDataConfigManagerCallback.onCarrierConfigChanged(); + mDataConfigManagerCallback.onDeviceConfigChanged(); + + processAllMessages(); verify(mTelephonyRegistryManager).addOnSubscriptionsChangedListener(any(), any()); } -- GitLab From a8e12b27bfd9f6493b61eae1cb6a6de3451d3c6f Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 3 Feb 2023 22:24:07 +0000 Subject: [PATCH 492/656] Only use SIM certificates for determining Carrier Provisioning package This change closes a loophole potentially introduced during the migration of carrier config packages to CarrierPrivilegesTracker, where any carrier privileged application could be marked as a carrier provisioning service, which would potentially allow chaining of certificates and associated privileges infinitely. Bug: 267809568 Test: atest CarrierPrivilegesTrackerTest Change-Id: I16a80428c378a3c555722ca0349e4047d84abe10 Merged-In: I16a80428c378a3c555722ca0349e4047d84abe10 (cherry picked from commit 5f2cc3b87dbc1aeb5350ad624fe4f5068eaf2f3a) --- .../telephony/CarrierPrivilegesTracker.java | 48 ++++++++++++------- .../CarrierPrivilegesTrackerTest.java | 33 ++++++++----- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index 5a541d1197..5fed36f9aa 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -101,6 +101,10 @@ public class CarrierPrivilegesTracker extends Handler { private static final String SHA_1 = "SHA-1"; private static final String SHA_256 = "SHA-256"; + private static final int PACKAGE_NOT_PRIVILEGED = 0; + private static final int PACKAGE_PRIVILEGED_FROM_CARRIER_CONFIG = 1; + private static final int PACKAGE_PRIVILEGED_FROM_SIM = 2; + // TODO(b/232273884): Turn feature on when find solution to handle the inter-carriers switching /** * Time delay to clear UICC rules after UICC is gone. @@ -686,23 +690,35 @@ public class CarrierPrivilegesTracker extends Handler { @NonNull private PrivilegedPackageInfo getCurrentPrivilegedPackagesForAllUsers() { + Set carrierServiceEligiblePackages = new ArraySet<>(); Set privilegedPackageNames = new ArraySet<>(); Set privilegedUids = new ArraySet<>(); for (Map.Entry> e : mInstalledPackageCerts.entrySet()) { - if (isPackagePrivileged(e.getKey(), e.getValue())) { - privilegedPackageNames.add(e.getKey()); - privilegedUids.addAll(getUidsForPackage(e.getKey(), /* invalidateCache= */ false)); + final int priv = getPackagePrivilegedStatus(e.getKey(), e.getValue()); + switch (priv) { + case PACKAGE_PRIVILEGED_FROM_SIM: + carrierServiceEligiblePackages.add(e.getKey()); + // fallthrough + case PACKAGE_PRIVILEGED_FROM_CARRIER_CONFIG: + privilegedPackageNames.add(e.getKey()); + privilegedUids.addAll( + getUidsForPackage(e.getKey(), /* invalidateCache= */ false)); } } - return new PrivilegedPackageInfo(privilegedPackageNames, privilegedUids, - getCarrierService(privilegedPackageNames)); + + return new PrivilegedPackageInfo( + privilegedPackageNames, + privilegedUids, + getCarrierService(carrierServiceEligiblePackages)); } /** - * Returns true iff there is an overlap between the provided certificate hashes and the - * certificate hashes stored in mTestOverrideRules, mCarrierConfigRules and mUiccRules. + * Returns the privilege status of the provided package. + * + *

Returned privilege status depends on whether a package matches the certificates from + * carrier config, from test overrides or from certificates stored on the SIM. */ - private boolean isPackagePrivileged(@NonNull String pkgName, @NonNull Set certs) { + private int getPackagePrivilegedStatus(@NonNull String pkgName, @NonNull Set certs) { // Double-nested for loops, but each collection should contain at most 2 elements in nearly // every case. // TODO(b/184382310) find a way to speed this up @@ -711,23 +727,23 @@ public class CarrierPrivilegesTracker extends Handler { if (mTestOverrideRules != null) { for (UiccAccessRule rule : mTestOverrideRules) { if (rule.matches(cert, pkgName)) { - return true; + return PACKAGE_PRIVILEGED_FROM_SIM; } } } else { - for (UiccAccessRule rule : mCarrierConfigRules) { + for (UiccAccessRule rule : mUiccRules) { if (rule.matches(cert, pkgName)) { - return true; + return PACKAGE_PRIVILEGED_FROM_SIM; } } - for (UiccAccessRule rule : mUiccRules) { + for (UiccAccessRule rule : mCarrierConfigRules) { if (rule.matches(cert, pkgName)) { - return true; + return PACKAGE_PRIVILEGED_FROM_CARRIER_CONFIG; } } } } - return false; + return PACKAGE_NOT_PRIVILEGED; } @NonNull @@ -969,13 +985,13 @@ public class CarrierPrivilegesTracker extends Handler { } @NonNull - private Pair getCarrierService(@NonNull Set privilegedPackageNames) { + private Pair getCarrierService(@NonNull Set simPrivilegedPackages) { List carrierServiceResolveInfos = mPackageManager.queryIntentServices( new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), /* flags= */ 0); String carrierServicePackageName = null; for (ResolveInfo resolveInfo : carrierServiceResolveInfos) { String packageName = getPackageName(resolveInfo); - if (privilegedPackageNames.contains(packageName)) { + if (simPrivilegedPackages.contains(packageName)) { carrierServicePackageName = packageName; break; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java index c32a4c5459..66632f321b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java @@ -780,7 +780,7 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { @Test public void testPackageDisabledAndThenEnabled() throws Exception { // Start with certs and packages installed - setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1))); + setupSimLoadedRules(ruleWithHashOnly(getHash(CERT_1))); setupInstalledPackages( new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1), new PackageCertInfo(PACKAGE_2, CERT_2, USER_1, UID_2)); @@ -919,9 +919,12 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { } @Test - public void testGetCarrierService_haveCarrierServiceWithCarrierPrivileges() throws Exception { - // Only packages with CERT_1 have carrier privileges - setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1))); + public void testGetCarrierService_haveCarrierServiceWithSimCarrierPrivileges() + throws Exception { + // Package 1 has SIM loaded rules, making it eligible for carrier service bindings + setupSimLoadedRules(ruleWithHashOnly(getHash(CERT_1))); + // Package 2 has only carrier-config based rules, which is insufficient for carrier services + setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_2))); // Setup all odd packages privileged, even packages not setupInstalledPackages( new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1), @@ -948,7 +951,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { assertEquals(PACKAGE_1, carrierServicePackageName); assertEquals(UID_1, carrierServiceUid); - reset(mPackageManager); // Get CS again carrierServicePackageName = mCarrierPrivilegesTracker.getCarrierServicePackageName(); @@ -959,27 +961,32 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { verify(mPackageManager, never()).queryIntentServices(any(), anyInt()); assertEquals(PACKAGE_1, carrierServicePackageName); assertEquals(UID_1, carrierServiceUid); - } @Test - public void testGetCarrierService_haveCarrierServiceWithNoCarrierPrivileges() throws Exception { - // Only packages with CERT_1 have carrier privileges - setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1))); + public void testGetCarrierService_haveCarrierServiceWithoutSimCarrierPrivileges() + throws Exception { + // Package 1 has no carrier privileges, package 2 has carrier-config based privileges, but + // no matching certificate on the SIM. + setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_2))); // Setup all odd packages privileged, even packages not setupInstalledPackages( new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1), new PackageCertInfo(PACKAGE_2, CERT_2, USER_1, UID_2), new PackageCertInfo(PACKAGE_3, CERT_1, USER_1, UID_1)); - // One declared CarrierService which has no carrier privileges - ResolveInfo noPrivilegeService = new ResolveInfoBuilder().setService(PACKAGE_2).build(); + // Two declared CarrierService, only PACKAGE_1 has carrier privileges + ResolveInfo service1 = new ResolveInfoBuilder().setService(PACKAGE_1).build(); + ResolveInfo service2 = new ResolveInfoBuilder().setService(PACKAGE_2).build(); // Use doReturn instead of when/thenReturn which has NPE with unknown reason - doReturn(List.of(noPrivilegeService)).when( - mPackageManager).queryIntentServices(any(), anyInt()); + doReturn(List.of(service1, service2)) + .when(mPackageManager) + .queryIntentServices(any(), anyInt()); when(mPackageManager.getPackageUid(eq(PACKAGE_1), anyInt())).thenReturn(UID_1); when(mPackageManager.getPackageUid(eq(PACKAGE_2), anyInt())).thenReturn(UID_2); when(mPackageManager.getPackageUid(eq(PACKAGE_3), anyInt())).thenReturn(UID_1); + // Verify that neither carrier service (no privileges, or carrier-config based privileges) + // are accepted. mCarrierPrivilegesTracker = createCarrierPrivilegesTracker(); String carrierServicePackageName = mCarrierPrivilegesTracker.getCarrierServicePackageName(); int carrierServiceUid = mCarrierPrivilegesTracker.getCarrierServicePackageUid(); -- GitLab From 9879101d877c88b5bac6cf1133e5549849378839 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 3 Feb 2023 23:18:33 +0000 Subject: [PATCH 493/656] Add ability to override carrier service package This change introduces a Carrier Service Package override, requiring MODIFY_PHONE_STATE, ensuring that CTS can export a CarrierService, and set itself as the carrier service. The requirement for the application to also be carrier-privileged still stands, but omits the SIM-certificate-match requirement, instead allowing carrierConfig based certificates + carrier service package override as a sufficient gate (which critically need to both be doable with the CTS Shell permission identity) Bug: 266904760 Test: Manually tested with a demo CTS build, will be used for Core Networking CTS tests Change-Id: Idcaaff8c9c3ed67b93bc23237de841219a5be7d7 Merged-In: Idcaaff8c9c3ed67b93bc23237de841219a5be7d7 (cherry picked from commit 7d9c790f22075d94accc5474cfc0ba258605c3b5) --- .../telephony/CarrierPrivilegesTracker.java | 49 ++++++++++- .../CarrierPrivilegesTrackerTest.java | 84 +++++++++++++++++++ 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java index 5fed36f9aa..ab7ebc42d7 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -104,6 +104,7 @@ public class CarrierPrivilegesTracker extends Handler { private static final int PACKAGE_NOT_PRIVILEGED = 0; private static final int PACKAGE_PRIVILEGED_FROM_CARRIER_CONFIG = 1; private static final int PACKAGE_PRIVILEGED_FROM_SIM = 2; + private static final int PACKAGE_PRIVILEGED_FROM_CARRIER_SERVICE_TEST_OVERRIDE = 3; // TODO(b/232273884): Turn feature on when find solution to handle the inter-carriers switching /** @@ -166,6 +167,14 @@ public class CarrierPrivilegesTracker extends Handler { */ private static final int ACTION_UICC_ACCESS_RULES_LOADED = 10; + /** + * Action to set the test override rule through {@link + * TelephonyManager#setCarrierServicePackageOverride}. + * + *

obj: String of the carrierServicePackage from method setCarrierServicePackageOverride. + */ + private static final int ACTION_SET_TEST_OVERRIDE_CARRIER_SERVICE_PACKAGE = 11; + private final Context mContext; private final Phone mPhone; private final PackageManager mPackageManager; @@ -184,6 +193,7 @@ public class CarrierPrivilegesTracker extends Handler { // - Empty list indicates test override to simulate no rules (CC and UICC rules are ignored) // - Non-empty list indicates test override with specific rules (CC and UICC rules are ignored) @Nullable private List mTestOverrideRules = null; + @Nullable private String mTestOverrideCarrierServicePackage = null; // Map of PackageName -> Certificate hashes for that Package @NonNull private final Map> mInstalledPackageCerts = new ArrayMap<>(); // Map of PackageName -> UIDs for that Package @@ -397,6 +407,11 @@ public class CarrierPrivilegesTracker extends Handler { handleUiccAccessRulesLoaded(); break; } + case ACTION_SET_TEST_OVERRIDE_CARRIER_SERVICE_PACKAGE: { + String carrierServicePackage = (String) msg.obj; + handleSetTestOverrideCarrierServicePackage(carrierServicePackage); + break; + } default: { Rlog.e(TAG, "Received unknown msg type: " + msg.what); break; @@ -697,6 +712,7 @@ public class CarrierPrivilegesTracker extends Handler { final int priv = getPackagePrivilegedStatus(e.getKey(), e.getValue()); switch (priv) { case PACKAGE_PRIVILEGED_FROM_SIM: + case PACKAGE_PRIVILEGED_FROM_CARRIER_SERVICE_TEST_OVERRIDE: // fallthrough carrierServiceEligiblePackages.add(e.getKey()); // fallthrough case PACKAGE_PRIVILEGED_FROM_CARRIER_CONFIG: @@ -738,7 +754,9 @@ public class CarrierPrivilegesTracker extends Handler { } for (UiccAccessRule rule : mCarrierConfigRules) { if (rule.matches(cert, pkgName)) { - return PACKAGE_PRIVILEGED_FROM_CARRIER_CONFIG; + return pkgName.equals(mTestOverrideCarrierServicePackage) + ? PACKAGE_PRIVILEGED_FROM_CARRIER_SERVICE_TEST_OVERRIDE + : PACKAGE_PRIVILEGED_FROM_CARRIER_CONFIG; } } } @@ -823,6 +841,30 @@ public class CarrierPrivilegesTracker extends Handler { sendMessage(obtainMessage(ACTION_SET_TEST_OVERRIDE_RULE, carrierPrivilegeRules)); } + /** + * Override the carrier provisioning package, if it exists. + * + *

This API is to be used ONLY for testing, and requires the provided package to be carrier + * privileged. While this override is set, ONLY the specified package will be considered + * eligible to be bound as the carrier provisioning package, and any existing bindings will be + * terminated. + * + * @param carrierServicePackage the package to be used as the overridden carrier service + * package, or {@code null} to reset override + * @see TelephonyManager#setCarrierServicePackageOverride + */ + public void setTestOverrideCarrierServicePackage(@Nullable String carrierServicePackage) { + sendMessage(obtainMessage( + ACTION_SET_TEST_OVERRIDE_CARRIER_SERVICE_PACKAGE, carrierServicePackage)); + } + + private void handleSetTestOverrideCarrierServicePackage( + @Nullable String carrierServicePackage) { + mTestOverrideCarrierServicePackage = carrierServicePackage; + refreshInstalledPackageCache(); + maybeUpdatePrivilegedPackagesAndNotifyRegistrants(); + } + private void handleSetTestOverrideRules(@Nullable String carrierPrivilegeRules) { if (carrierPrivilegeRules == null) { mTestOverrideRules = null; @@ -991,6 +1033,11 @@ public class CarrierPrivilegesTracker extends Handler { String carrierServicePackageName = null; for (ResolveInfo resolveInfo : carrierServiceResolveInfos) { String packageName = getPackageName(resolveInfo); + if (mTestOverrideCarrierServicePackage != null + && !mTestOverrideCarrierServicePackage.equals(packageName)) { + continue; + } + if (simPrivilegedPackages.contains(packageName)) { carrierServicePackageName = packageName; break; diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java index 66632f321b..06b63a2ee8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java @@ -1024,6 +1024,90 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { verify(mPackageManager).queryIntentServices(any(), anyInt()); } + @Test + public void testSetCarrierServiceOverride_noCarrierPrivileges() throws Exception { + // Setup one package, without a matching cert to grant carrier privileges + setupInstalledPackages(new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1)); + ResolveInfo carrierService = new ResolveInfoBuilder().setService(PACKAGE_1).build(); + + doReturn(List.of(carrierService)) + .when(mPackageManager) + .queryIntentServices(any(), anyInt()); + when(mPackageManager.getPackageUid(eq(PACKAGE_1), anyInt())).thenReturn(UID_1); + + // Set override, and verify the carrier service package was not set due to a lack of a + // matching cert. + mCarrierPrivilegesTracker = createCarrierPrivilegesTracker(); + mCarrierPrivilegesTracker.setTestOverrideCarrierServicePackage(PACKAGE_1); + mTestableLooper.processAllMessages(); + + assertNull(mCarrierPrivilegesTracker.getCarrierServicePackageName()); + assertEquals(Process.INVALID_UID, mCarrierPrivilegesTracker.getCarrierServicePackageUid()); + } + + @Test + public void testSetCarrierServiceOverride_withCarrierConfigCarrierPrivileges() + throws Exception { + // Setup two packages with matching carrier config certificates + setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1))); + setupInstalledPackages( + new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1), + new PackageCertInfo(PACKAGE_2, CERT_1, USER_1, UID_2)); + ResolveInfo service1 = new ResolveInfoBuilder().setService(PACKAGE_1).build(); + ResolveInfo service2 = new ResolveInfoBuilder().setService(PACKAGE_2).build(); + + doReturn(List.of(service1, service2)) + .when(mPackageManager) + .queryIntentServices(any(), anyInt()); + when(mPackageManager.getPackageUid(eq(PACKAGE_1), anyInt())).thenReturn(UID_1); + when(mPackageManager.getPackageUid(eq(PACKAGE_2), anyInt())).thenReturn(UID_2); + + mCarrierPrivilegesTracker = createCarrierPrivilegesTracker(); + + // Set override, and verify the carrier service package was truly set. + mCarrierPrivilegesTracker.setTestOverrideCarrierServicePackage(PACKAGE_1); + mTestableLooper.processAllMessages(); + + assertEquals(PACKAGE_1, mCarrierPrivilegesTracker.getCarrierServicePackageName()); + assertEquals(UID_1, mCarrierPrivilegesTracker.getCarrierServicePackageUid()); + + // Set other package as override, and verify the carrier service package was truly set. + mCarrierPrivilegesTracker.setTestOverrideCarrierServicePackage(PACKAGE_2); + mTestableLooper.processAllMessages(); + + assertEquals(PACKAGE_2, mCarrierPrivilegesTracker.getCarrierServicePackageName()); + assertEquals(UID_2, mCarrierPrivilegesTracker.getCarrierServicePackageUid()); + + // Clear override, and verify that everything went back to null. + mCarrierPrivilegesTracker.setTestOverrideCarrierServicePackage(null); + mTestableLooper.processAllMessages(); + + assertNull(mCarrierPrivilegesTracker.getCarrierServicePackageName()); + assertEquals(Process.INVALID_UID, mCarrierPrivilegesTracker.getCarrierServicePackageUid()); + } + + @Test + public void testSetCarrierServiceOverride_invalidPackage() throws Exception { + // Setup one package, without a matching cert to grant carrier privileges + setupCarrierConfigRules(carrierConfigRuleString(getHash(CERT_1))); + setupInstalledPackages(new PackageCertInfo(PACKAGE_1, CERT_1, USER_1, UID_1)); + ResolveInfo carrierService = new ResolveInfoBuilder().setService(PACKAGE_1).build(); + + doReturn(List.of(carrierService)) + .when(mPackageManager) + .queryIntentServices(any(), anyInt()); + when(mPackageManager.getPackageUid(eq(PACKAGE_1), anyInt())).thenReturn(UID_1); + + // Set override, and expect that an invalid package name would not be selected as the + // carrier config service. + mCarrierPrivilegesTracker = createCarrierPrivilegesTracker(); + mCarrierPrivilegesTracker.setTestOverrideCarrierServicePackage("invalid.package"); + mTestableLooper.processAllMessages(); + + assertNull(mCarrierPrivilegesTracker.getCarrierServicePackageName()); + assertEquals(Process.INVALID_UID, mCarrierPrivilegesTracker.getCarrierServicePackageUid()); + } + private void sendCarrierConfigChanged(int subId, int phoneId) { mCarrierConfigChangeListener.onCarrierConfigChanged(phoneId, subId, TelephonyManager.UNKNOWN_CARRIER_ID, TelephonyManager.UNKNOWN_CARRIER_ID); -- GitLab From 4390b135b9256d51ec6546622271d672fd90cbf9 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Mon, 6 Mar 2023 16:02:08 -0800 Subject: [PATCH 494/656] Read auto data switch config from res Migrate auto data switch config from server side device config to res overlay. Test: confirmed the auto data switch works, reviewed log to confirm the config is populated Bug: 244064524 Change-Id: I0ee2b94518267e63624c4834ab669dd446055cbf --- .../telephony/data/DataConfigManager.java | 36 ++++--------------- .../telephony/data/PhoneSwitcher.java | 28 ++++----------- 2 files changed, 13 insertions(+), 51 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index 8d4331d962..315c1dee4c 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -72,12 +72,6 @@ public class DataConfigManager extends Handler { /** The default timeout in ms for data network stuck in a transit state. */ private static final int DEFAULT_NETWORK_TRANSIT_STATE_TIMEOUT_MS = 300000; - /** Default time threshold in ms to define a internet connection status to be stable. */ - public static int DEFAULT_AUTO_DATA_SWITCH_STABILITY_TIME_MS = 10000; - - /** The max number of retries when a pre-switching validation fails. */ - public static int DEFAULT_AUTO_DATA_SWITCH_MAX_RETRY = 7; - /** Event for carrier config changed. */ private static final int EVENT_CARRIER_CONFIG_CHANGED = 1; @@ -268,18 +262,6 @@ public class DataConfigManager extends Handler { */ private boolean mIsApnConfigAnomalyReportEnabled; - /** - * Time threshold in ms to define a internet connection status to be stable(e.g. out of service, - * in service, wifi is the default active network.etc), while -1 indicates auto switch feature - * disabled. - */ - private long mAutoDataSwitchAvailabilityStabilityTimeThreshold; - - /** - * The maximum number of retries when a pre-switching validation fails. - */ - private int mAutoDataSwitchValidationMaxRetry; - private @NonNull final Phone mPhone; private @NonNull final String mLogTag; @@ -440,12 +422,6 @@ public class DataConfigManager extends Handler { KEY_ANOMALY_NETWORK_HANDOVER_TIMEOUT, DEFAULT_NETWORK_TRANSIT_STATE_TIMEOUT_MS); mIsApnConfigAnomalyReportEnabled = properties.getBoolean( KEY_ANOMALY_APN_CONFIG_ENABLED, false); - mAutoDataSwitchAvailabilityStabilityTimeThreshold = properties.getInt( - KEY_AUTO_DATA_SWITCH_AVAILABILITY_STABILITY_TIME_THRESHOLD, - DEFAULT_AUTO_DATA_SWITCH_STABILITY_TIME_MS); - mAutoDataSwitchValidationMaxRetry = properties.getInt( - KEY_AUTO_DATA_SWITCH_VALIDATION_MAX_RETRY, - DEFAULT_AUTO_DATA_SWITCH_MAX_RETRY); } /** @@ -957,7 +933,8 @@ public class DataConfigManager extends Handler { * @return The maximum number of retries when a validation for switching failed. */ public int getAutoDataSwitchValidationMaxRetry() { - return mAutoDataSwitchValidationMaxRetry; + return mResources.getInteger(com.android.internal.R.integer + .auto_data_switch_validation_max_retry); } /** @@ -966,7 +943,8 @@ public class DataConfigManager extends Handler { * auto switch feature disabled. */ public long getAutoDataSwitchAvailabilityStabilityTimeThreshold() { - return mAutoDataSwitchAvailabilityStabilityTimeThreshold; + return mResources.getInteger(com.android.internal.R.integer + .auto_data_switch_availability_stability_time_threshold_millis); } /** @@ -1349,9 +1327,9 @@ public class DataConfigManager extends Handler { pw.println("mNetworkDisconnectingTimeout=" + mNetworkDisconnectingTimeout); pw.println("mNetworkHandoverTimeout=" + mNetworkHandoverTimeout); pw.println("mIsApnConfigAnomalyReportEnabled=" + mIsApnConfigAnomalyReportEnabled); - pw.println("mAutoDataSwitchAvailabilityStabilityTimeThreshold=" - + mAutoDataSwitchAvailabilityStabilityTimeThreshold); - pw.println("mAutoDataSwitchValidationMaxRetry=" + mAutoDataSwitchValidationMaxRetry); + pw.println("getAutoDataSwitchAvailabilityStabilityTimeThreshold=" + + getAutoDataSwitchAvailabilityStabilityTimeThreshold()); + pw.println("getAutoDataSwitchValidationMaxRetry=" + getAutoDataSwitchValidationMaxRetry()); pw.println("Metered APN types=" + mMeteredApnTypes.stream() .map(ApnSetting::getApnTypeString).collect(Collectors.joining(","))); pw.println("Roaming metered APN types=" + mRoamingMeteredApnTypes.stream() diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 0af51ec724..1a0ddbe136 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -295,11 +295,6 @@ public class PhoneSwitcher extends Handler { /** Data config manager callback for updating device config. **/ private final DataConfigManager.DataConfigManagerCallback mDataConfigManagerCallback = new DataConfigManager.DataConfigManagerCallback(this::post) { - @Override - public void onDeviceConfigChanged() { - log("onDeviceConfigChanged"); - PhoneSwitcher.this.updateDeviceConfig(); - } @Override public void onCarrierConfigChanged() { @@ -383,8 +378,7 @@ public class PhoneSwitcher extends Handler { /** * The maximum number of retries when a validation for switching failed. */ - private int mAutoDataSwitchValidationMaxRetry = - DataConfigManager.DEFAULT_AUTO_DATA_SWITCH_MAX_RETRY; + private int mAutoDataSwitchValidationMaxRetry; /** Data settings manager callback. Key is the phone id. */ private final @NonNull Map mDataSettingsManagerCallbacks = @@ -937,25 +931,26 @@ public class PhoneSwitcher extends Handler { } /** - * Register for device config change on the primary data phone. + * Register for config change on the primary data phone. */ private void registerConfigChange() { Phone phone = getPhoneBySubId(mPrimaryDataSubId); if (phone != null) { DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); dataConfig.registerCallback(mDataConfigManagerCallback); - updateDeviceConfig(); + updateCarrierConfig(); sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); } } /** - * Update device config. + * Update carrier config. */ - private void updateDeviceConfig() { + private void updateCarrierConfig() { Phone phone = getPhoneBySubId(mPrimaryDataSubId); if (phone != null) { DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); + mRequirePingTestBeforeDataSwitch = dataConfig.requirePingTestBeforeDataSwitch(); mAutoDataSwitchAvailabilityStabilityTimeThreshold = dataConfig.getAutoDataSwitchAvailabilityStabilityTimeThreshold(); mAutoDataSwitchValidationMaxRetry = @@ -963,17 +958,6 @@ public class PhoneSwitcher extends Handler { } } - /** - * Update carrier config. - */ - private void updateCarrierConfig() { - Phone phone = getPhoneBySubId(mPrimaryDataSubId); - if (phone != null) { - DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); - mRequirePingTestBeforeDataSwitch = dataConfig.requirePingTestBeforeDataSwitch(); - } - } - private synchronized void onMultiSimConfigChanged(int activeModemCount) { // No change. if (mActiveModemCount == activeModemCount) return; -- GitLab From 2034e08120caeab4d9b78f4a9e5d08a3e7c262f3 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 21 Feb 2023 23:30:48 -0800 Subject: [PATCH 495/656] Cleaned up the deprecated APIs Bug: 270094276 Test: Basic phone funcationality tests Change-Id: If3bcaee5c9426f79024bcbcee10aceff120811f8 --- .../internal/telephony/CarrierInfoManager.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/CarrierInfoManager.java b/src/java/com/android/internal/telephony/CarrierInfoManager.java index 3e2baa5a99..863db93ad5 100644 --- a/src/java/com/android/internal/telephony/CarrierInfoManager.java +++ b/src/java/com/android/internal/telephony/CarrierInfoManager.java @@ -287,16 +287,17 @@ public class CarrierInfoManager { return; } mLastAccessResetCarrierKey = now; - int[] subIds = context.getSystemService(SubscriptionManager.class) - .getSubscriptionIds(mPhoneId); - if (subIds == null || subIds.length < 1) { + + int subId = SubscriptionManager.getSubscriptionId(mPhoneId); + if (!SubscriptionManager.isValidSubscriptionId(subId)) { Log.e(LOG_TAG, "Could not reset carrier keys, subscription for mPhoneId=" + mPhoneId); return; } + final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class) - .createForSubscriptionId(subIds[0]); + .createForSubscriptionId(subId); int carrierId = telephonyManager.getSimCarrierId(); - deleteCarrierInfoForImsiEncryption(context, subIds[0], carrierId); + deleteCarrierInfoForImsiEncryption(context, subId, carrierId); Intent resetIntent = new Intent(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD); SubscriptionManager.putPhoneIdAndSubIdExtra(resetIntent, mPhoneId); context.sendBroadcastAsUser(resetIntent, UserHandle.ALL); -- GitLab From 44c880e166c836d75f07d4574a635e491fb0461a Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Tue, 6 Dec 2022 07:26:48 +0000 Subject: [PATCH 496/656] flaky error fix in SimRecordsTest file Bug: 256282468 Test: Atest Verification done Change-Id: Ieffba54a06cd69b8a8557889ba1e76cff7804539 (cherry picked from commit 249f322c004492eceea933436e45ed3317937ac7) --- .../telephony/uicc/SIMRecordsTest.java | 331 ++++++++++-------- 1 file changed, 181 insertions(+), 150 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java index 79cd6a44de..e109ebb475 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/SIMRecordsTest.java @@ -34,6 +34,7 @@ import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.os.test.TestLooper; +import android.util.Log; import androidx.test.runner.AndroidJUnit4; @@ -47,13 +48,13 @@ import com.android.telephony.Rlog; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -65,6 +66,7 @@ public class SIMRecordsTest extends TelephonyTest { private static final List EMPTY_FPLMN_LIST = new ArrayList<>(); private static final int EF_SIZE = 12; private static final int MAX_NUM_FPLMN = 4; + private static final int SET_VOICE_MAIL_TIMEOUT = 1000; // Mocked classes private IccFileHandler mFhMock; @@ -724,45 +726,36 @@ public class SIMRecordsTest extends TelephonyTest { } @Test - @Ignore("b/256282468") public void testSetVoiceMailNumber() throws InterruptedException { - String voiceMailNumber = "1234567890"; String alphaTag = "Voicemail"; final CountDownLatch latch = new CountDownLatch(2); - doAnswer( - invocation -> { - int[] result = new int[3]; - result[0] = 32; - result[1] = 32; - result[2] = 1; - Rlog.d("SIMRecordsTest", "Executing the test invocation1"); - Message response = invocation.getArgument(2); - AsyncResult.forMessage(response, result, null); - response.sendToTarget(); - latch.countDown(); - return null; - }) - .when(mFhMock) - .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); - - doAnswer( - invocation -> { - int[] result = new int[3]; - result[0] = 32; - result[1] = 32; - result[2] = 1; - Rlog.d("SIMRecordsTest", "Executing the test invocation2"); - Message response = invocation.getArgument(5); - AsyncResult.forMessage(response, result, null); - response.sendToTarget(); - latch.countDown(); - return null; - }) - .when(mFhMock) - .updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), - eq(null), any(Message.class)); - + doAnswer(invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the first invocation"); + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }).when(mFhMock).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + doAnswer(invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the second invocation"); + Message response = invocation.getArgument(5); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }).when(mFhMock).updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), + eq(null), any(Message.class)); mSIMRecordsUT.setMailboxIndex(1); Message message = Message.obtain(mTestHandler); @@ -770,53 +763,54 @@ public class SIMRecordsTest extends TelephonyTest { latch.await(5, TimeUnit.SECONDS); mTestLooper.startAutoDispatch(); verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); - verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), - anyInt(), any(byte[].class), eq(null), any(Message.class)); + verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), anyInt(), + any(byte[].class), eq(null), any(Message.class)); + waitUntilConditionIsTrueOrTimeout(new Condition() { + @Override + public Object expected() { + return true; + } + @Override + public Object actual() { + return mSIMRecordsUT.getVoiceMailNumber() != null; + } + }); assertEquals(voiceMailNumber, mSIMRecordsUT.getVoiceMailNumber()); assertEquals(alphaTag, mSIMRecordsUT.getVoiceMailAlphaTag()); } @Test - @Ignore("b/256282468") public void testSetVoiceMailNumberBigAlphatag() throws InterruptedException { - String voiceMailNumber = "1234567890"; String alphaTag = "VoicemailAlphaTag-VoicemailAlphaTag"; final CountDownLatch latch = new CountDownLatch(2); - doAnswer( - invocation -> { - int[] result = new int[3]; - result[0] = 32; - result[1] = 32; - result[2] = 1; - Rlog.d("SIMRecordsTest", "Executing the test invocation1"); - Message response = invocation.getArgument(2); - AsyncResult.forMessage(response, result, null); - response.sendToTarget(); - latch.countDown(); - return null; - }) - .when(mFhMock) - .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); - - doAnswer( - invocation -> { - int[] result = new int[3]; - result[0] = 32; - result[1] = 32; - result[2] = 1; - Rlog.d("SIMRecordsTest", "Executing the test invocation2"); - Message response = invocation.getArgument(5); - AsyncResult.forMessage(response, result, null); - response.sendToTarget(); - latch.countDown(); - return null; - }) - .when(mFhMock) - .updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), - eq(null), any(Message.class)); - + doAnswer(invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the first invocation"); + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }).when(mFhMock).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + doAnswer(invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the second invocation"); + Message response = invocation.getArgument(5); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }).when(mFhMock).updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), + eq(null), any(Message.class)); mSIMRecordsUT.setMailboxIndex(1); Message message = Message.obtain(mTestHandler); @@ -824,109 +818,112 @@ public class SIMRecordsTest extends TelephonyTest { latch.await(8, TimeUnit.SECONDS); mTestLooper.startAutoDispatch(); verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); - verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), - anyInt(), any(byte[].class), eq(null), any(Message.class)); - + verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), anyInt(), + any(byte[].class), eq(null), any(Message.class)); //if attempt to save bugAlphatag which sim don't support so we will make it null + waitUntilConditionIsTrueOrTimeout(new Condition() { + @Override + public Object expected() { + return true; + } + + @Override + public Object actual() { + return mSIMRecordsUT.getVoiceMailNumber() != null; + } + }); assertEquals(null, mSIMRecordsUT.getVoiceMailAlphaTag()); assertEquals(voiceMailNumber, mSIMRecordsUT.getVoiceMailNumber()); } @Test - @Ignore("b/256282468") public void testSetVoiceMailNumberUtf16Alphatag() throws InterruptedException { - String voiceMailNumber = "1234567890"; String alphaTag = "หมายเลขข้อความเสียง"; // Messagerie vocale final CountDownLatch latch = new CountDownLatch(2); - doAnswer( - invocation -> { - int[] result = new int[3]; - result[0] = 32; - result[1] = 32; - result[2] = 1; - Rlog.d("SIMRecordsTest", "Executing the test invocation1"); - Message response = invocation.getArgument(2); - AsyncResult.forMessage(response, result, null); - response.sendToTarget(); - latch.countDown(); - return null; - }) - .when(mFhMock) - .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); - - doAnswer( - invocation -> { - int[] result = new int[3]; - result[0] = 32; - result[1] = 32; - result[2] = 1; - Rlog.d("SIMRecordsTest", "Executing the test invocation2"); - Message response = invocation.getArgument(5); - AsyncResult.forMessage(response, result, null); - response.sendToTarget(); - latch.countDown(); - return null; - }) - .when(mFhMock) - .updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), - eq(null), any(Message.class)); - + doAnswer(invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the first invocation"); + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }).when(mFhMock).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + doAnswer(invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the second invocation"); + Message response = invocation.getArgument(5); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }).when(mFhMock).updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), + eq(null), any(Message.class)); mSIMRecordsUT.setMailboxIndex(1); Message message = Message.obtain(mTestHandler); mSIMRecordsUT.setVoiceMailNumber(alphaTag, voiceMailNumber, message); latch.await(5, TimeUnit.SECONDS); + mTestLooper.startAutoDispatch(); verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); - verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), - anyInt(), any(byte[].class), eq(null), any(Message.class)); + verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), anyInt(), + any(byte[].class), eq(null), any(Message.class)); + waitUntilConditionIsTrueOrTimeout(new Condition() { + @Override + public Object expected() { + return true; + } + @Override + public Object actual() { + return mSIMRecordsUT.getVoiceMailNumber() != null; + } + }); assertEquals(voiceMailNumber, mSIMRecordsUT.getVoiceMailNumber()); //if attempt to save bugAlphatag which sim don't support so we will make it null assertEquals(null, mSIMRecordsUT.getVoiceMailAlphaTag()); } @Test - @Ignore("b/256282468") public void testSetVoiceMailNullNumber() throws InterruptedException { - String voiceMailNumber = null; String alphaTag = "VoicemailAlphaTag"; // Messagerie vocale final CountDownLatch latch = new CountDownLatch(2); - doAnswer( - invocation -> { - int[] result = new int[3]; - result[0] = 32; - result[1] = 32; - result[2] = 1; - Rlog.d("SIMRecordsTest", "Executing the test invocation1"); - Message response = invocation.getArgument(2); - AsyncResult.forMessage(response, result, null); - response.sendToTarget(); - latch.countDown(); - return null; - }) - .when(mFhMock) - .getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); - - doAnswer( - invocation -> { - int[] result = new int[3]; - result[0] = 32; - result[1] = 32; - result[2] = 1; - Rlog.d("SIMRecordsTest", "Executing the test invocation2"); - Message response = invocation.getArgument(5); - AsyncResult.forMessage(response, result, null); - response.sendToTarget(); - latch.countDown(); - return null; - }) - .when(mFhMock) - .updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), - eq(null), any(Message.class)); - + doAnswer(invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the first invocation"); + Message response = invocation.getArgument(2); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }).when(mFhMock).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); + + doAnswer(invocation -> { + int[] result = new int[3]; + result[0] = 32; + result[1] = 32; + result[2] = 1; + Rlog.d("SIMRecordsTest", "Executing the second invocation"); + Message response = invocation.getArgument(5); + AsyncResult.forMessage(response, result, null); + response.sendToTarget(); + latch.countDown(); + return null; + }).when(mFhMock).updateEFLinearFixed(anyInt(), eq(null), anyInt(), any(byte[].class), + eq(null), any(Message.class)); mSIMRecordsUT.setMailboxIndex(1); Message message = Message.obtain(mTestHandler); @@ -934,10 +931,44 @@ public class SIMRecordsTest extends TelephonyTest { latch.await(5, TimeUnit.SECONDS); mTestLooper.startAutoDispatch(); verify(mFhMock, times(1)).getEFLinearRecordSize(anyInt(), isNull(), any(Message.class)); - verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), - anyInt(), any(byte[].class), eq(null), any(Message.class)); + verify(mFhMock, times(1)).updateEFLinearFixed(anyInt(), eq(null), anyInt(), + any(byte[].class), eq(null), any(Message.class)); + waitUntilConditionIsTrueOrTimeout(new Condition() { + @Override + public Object expected() { + return true; + } + @Override + public Object actual() { + return mSIMRecordsUT.getVoiceMailAlphaTag() != null; + } + }); assertEquals(null, mSIMRecordsUT.getVoiceMailNumber()); assertEquals(alphaTag, mSIMRecordsUT.getVoiceMailAlphaTag()); } + + public interface Condition { + Object expected(); + + Object actual(); + } + + protected void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (Exception e) { + Log.d(TAG, "InterruptedException"); + } + } + + protected void waitUntilConditionIsTrueOrTimeout(Condition condition) { + final long start = System.currentTimeMillis(); + while (!Objects.equals(condition.expected(), condition.actual()) + && System.currentTimeMillis() - start + < (long) SIMRecordsTest.SET_VOICE_MAIL_TIMEOUT) { + sleep(50); + } + assertEquals("Service Unbound", condition.expected(), condition.actual()); + } } -- GitLab From b22ae91267d6dca055301e49024b52c1a911d0a6 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Sat, 4 Mar 2023 16:44:05 +0000 Subject: [PATCH 497/656] Load the FDN records when the USIM initializes and the SIM refreshes Bug: 267116389 Bug: 271397128 Test: atest verified also verified manually Change-Id: I7762a681298e504a71f90838e8f98209879192f1 --- .../internal/telephony/uicc/SIMRecords.java | 20 +++++++++++++++++++ .../telephony/uicc/UiccCardApplication.java | 3 +++ 2 files changed, 23 insertions(+) diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index 49292b04b4..6fd86c5d9a 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -191,6 +191,7 @@ public class SIMRecords extends IccRecords { private static final int EVENT_SET_FPLMN_DONE = 43 + SIM_RECORD_EVENT_BASE; protected static final int EVENT_GET_SMSS_RECORD_DONE = 46 + SIM_RECORD_EVENT_BASE; protected static final int EVENT_GET_PSISMSC_DONE = 47 + SIM_RECORD_EVENT_BASE; + protected static final int EVENT_GET_FDN_DONE = 48 + SIM_RECORD_EVENT_BASE; // ***** Constructor @@ -296,6 +297,7 @@ public class SIMRecords extends IccRecords { private int getExtFromEf(int ef) { int ext; switch (ef) { + case EF_FDN: return EF_EXT2; case EF_MSISDN: /* For USIM apps use EXT5. (TS 31.102 Section 4.2.37) */ if (mParentApp.getType() == AppType.APPTYPE_USIM) { @@ -1358,6 +1360,15 @@ public class SIMRecords extends IccRecords { } break; + case EVENT_GET_FDN_DONE: + ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + loge("Failed to read USIM EF_FDN field error=" + ar.exception); + } else { + log("EF_FDN read successfully"); + } + break; + default: super.handleMessage(msg); // IccRecords handles generic record load responses } @@ -2183,6 +2194,15 @@ public class SIMRecords extends IccRecords { log("[CSP] Value Added Service Group (0xC0), not found!"); } + public void loadFdnRecords() { + if (mParentApp != null && mParentApp.getIccFdnEnabled() + && mParentApp.getIccFdnAvailable()) { + log("Loading FdnRecords"); + mAdnCache.requestLoadAllAdnLike(IccConstants.EF_FDN, getExtFromEf(IccConstants.EF_FDN), + obtainMessage(EVENT_GET_FDN_DONE)); + } + } + @VisibleForTesting public void setMailboxIndex(int mailboxIndex) { mMailboxIndex = mailboxIndex; diff --git a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java index 08573b96f1..4eaf7a6e83 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java @@ -270,6 +270,9 @@ public class UiccCardApplication { } else { loge("Bogus facility lock response"); } + if (mIccFdnEnabled && mIccFdnAvailable) { + ((SIMRecords) mIccRecords).loadFdnRecords(); + } } } -- GitLab From 082ae25ee69c64b6f8aa48d1a8f2ed999b305af4 Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Fri, 17 Feb 2023 08:54:56 +0000 Subject: [PATCH 498/656] allowsBackgroundActivityStarts checking checks the BroadcastOptions option to confirm whether it allows Background activity to start Bug: 269535969, 269760622 Test: atest FrameworksTelephonyTests Change-Id: Ia2f46b5d35e61098ec5a83a1c5707b52ee590bbe (cherry picked from commit 755eed2fb0b1b3cdca51365e330c83733c3de7c3) --- .../internal/telephony/gsm/GsmInboundSmsHandlerTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java index 67e344ef61..3c045e0195 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java @@ -36,6 +36,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.BroadcastOptions; import android.app.Notification; import android.app.NotificationManager; import android.content.BroadcastReceiver; @@ -278,8 +279,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { assertEquals("WaitingState", getCurrentState().getName()); if (allowBgActivityStarts) { Bundle broadcastOptions = mContextFixture.getLastBroadcastOptions(); - assertTrue(broadcastOptions - .getBoolean("android:broadcast.allowBackgroundActivityStarts")); + BroadcastOptions brOptions = new BroadcastOptions(broadcastOptions); + assertTrue(brOptions.allowsBackgroundActivityStarts()); } mContextFixture.sendBroadcastToOrderedBroadcastReceivers(); -- GitLab From c5ef3d283b43730bc39a9aa7de4570c206376750 Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Tue, 7 Mar 2023 08:43:37 +0000 Subject: [PATCH 499/656] Re-enabling the test after the fix for testClass0Sms Fix provided in ag/21806845 which checks the BroadcastOptions Bug: 269760622 Test: atest FrameworksTelephonyTests Change-Id: I73ab9c0e94218d887cb4b21836dfeead8772c174 --- .../internal/telephony/gsm/GsmInboundSmsHandlerTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java index 3c045e0195..c261afe8a6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java @@ -73,7 +73,6 @@ import com.android.internal.util.StateMachine; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -480,7 +479,6 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { @Test @MediumTest - @Ignore("b/269535969") public void testClass0Sms() { transitionFromStartupToIdle(); -- GitLab From ea37a15e851df0ecf1d0e251c141abcb29d83c4d Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Fri, 3 Mar 2023 10:19:20 +0000 Subject: [PATCH 500/656] Update Bluetooth and Wifi based on Satellite Mode - Satellite mode Enabled: Disable BT and Wifi - Satellite mode Disabled: Reset BT and Wifi BUG: b/271541445 Test: atest SatelliteControllerTest, Flashed the changes to Panther Device and verified the logic Change-Id: I452fb7bacd0ab4f02b6a695237aa5eb90cbeb58e --- .../satellite/SatelliteController.java | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 0c305d6890..0c50f350a1 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -18,7 +18,10 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; import android.annotation.Nullable; +import android.bluetooth.BluetoothAdapter; import android.content.Context; +import android.content.Intent; +import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Binder; import android.os.Bundle; @@ -95,7 +98,10 @@ public class SatelliteController extends Handler { @NonNull private final PointingAppController mPointingAppController; @NonNull private final DatagramController mDatagramController; - + BluetoothAdapter mBluetoothAdapter = null; + WifiManager mWifiManager = null; + boolean mDisabledBTFlag = false; + boolean mDisabledWifiFlag = false; /** * Map key: subId, value: callback to get error code of the provision request. */ @@ -524,6 +530,24 @@ public class SatelliteController extends Handler { RequestSatelliteEnabledArgument argument = (RequestSatelliteEnabledArgument) request.argument; onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request); + if (argument.enabled) { + if (mBluetoothAdapter == null) { + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + } + if (mWifiManager == null) { + mWifiManager = mContext.getSystemService(WifiManager.class); + } + if (mBluetoothAdapter.isEnabled()) { + if (DBG) logd("disabling Bluetooth"); + mBluetoothAdapter.disable(); + mDisabledBTFlag = true; + } + if (mWifiManager.isWifiEnabled()) { + if (DBG) logd("disabling Wifi"); + mWifiManager.setWifiEnabled(false); + mDisabledWifiFlag = true; + } + } if (mSatelliteModemInterface.isSatelliteServiceSupported()) { mSatelliteModemInterface.requestSatelliteEnabled(argument.enabled, onCompleted); break; @@ -546,6 +570,22 @@ public class SatelliteController extends Handler { int error = SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled", false); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (!argument.enabled) { + if (mBluetoothAdapter == null) { + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + } + if (mWifiManager == null) { + mWifiManager = mContext.getSystemService(WifiManager.class); + } + if (!mBluetoothAdapter.isEnabled() && mDisabledBTFlag) { + if (DBG) logd("Enabling Bluetooth"); + mBluetoothAdapter.enable(); + } + if (!mWifiManager.isWifiEnabled() && mDisabledWifiFlag) { + if (DBG) logd("Enabling Wifi"); + mWifiManager.setWifiEnabled(true); + } + } /** * TODO: check if Satellite is Acquired. * Also need to call requestSatelliteCapabilities() if Satellite is enabled -- GitLab From 84cb092611efdf4d14f794a38d35ef3779c3331a Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Wed, 1 Mar 2023 19:14:00 +0000 Subject: [PATCH 501/656] Cleanup satellite messaging pipeline. The following changes are made in this CL: SatelliteController: - sendSatelliteDatagram(): Removed datagramId and replaced OutcomeReceiver with IIntegerConsumer DatagramDispatcher: - send error to all pending datagrams if sending one datagram fails. DatagramReceiver: - Make DatagramReceiverAck non-static and created a new object every time. - Added config for datagram receiver ack timeout(default=5minutes). - wait for ack and retry sending datagram to listener after timeout. - Replaced ISatelliteDatagramReceiverAck.aidl with ILongConsumer.aidl SatelliteServiceUtils: - Moved getValidSatelltieSubId() from SatelliteController to SatelliteServiceUtils Bug: 269637555 Test: atest SatelliteManagerTest, Basic sanity - flashed build on raven-userdebug: making calls and sending sms is working, atest FrameworkTelephonyTests Change-Id: I8ae049a76ef9d064dc8dac839554f6441a1ab330 --- .../satellite/DatagramController.java | 34 +-- .../satellite/DatagramDispatcher.java | 96 +++++--- .../telephony/satellite/DatagramReceiver.java | 208 +++++++++++------ .../satellite/SatelliteController.java | 217 +++++++++--------- .../satellite/SatelliteServiceUtils.java | 41 +++- .../SatelliteSOSMessageRecommenderTest.java | 7 +- 6 files changed, 362 insertions(+), 241 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 9639897e8e..06addda899 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -19,8 +19,8 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.os.Looper; import android.os.Message; -import android.os.ResultReceiver; import android.telephony.Rlog; import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.SatelliteDatagram; @@ -28,6 +28,8 @@ import android.telephony.satellite.SatelliteManager; import com.android.internal.telephony.Phone; +import java.util.function.Consumer; + /** * Datagram controller used for sending and receiving satellite datagrams. */ @@ -38,6 +40,7 @@ public class DatagramController { @NonNull private final Context mContext; @NonNull private final DatagramDispatcher mDatagramDispatcher; @NonNull private final DatagramReceiver mDatagramReceiver; + public static final long MAX_DATAGRAM_ID = (long) Math.pow(2, 16); /** * @return The singleton instance of DatagramController. @@ -52,11 +55,12 @@ public class DatagramController { /** * Create the DatagramController singleton instance. * @param context The Context to use to create the DatagramController. + * @param looper The looper for the handler. * @return The singleton instance of DatagramController. */ - public static DatagramController make(@NonNull Context context) { + public static DatagramController make(@NonNull Context context, @NonNull Looper looper) { if (sInstance == null) { - sInstance = new DatagramController(context); + sInstance = new DatagramController(context, looper); } return sInstance; } @@ -65,16 +69,17 @@ public class DatagramController { * Create a DatagramController to send and receive satellite datagrams. * * @param context The Context for the DatagramController. + * @param looper The looper for the handler. */ - private DatagramController(@NonNull Context context) { + private DatagramController(@NonNull Context context, @NonNull Looper looper) { mContext = context; // Create the DatagramDispatcher singleton, // which is used to send satellite datagrams. - mDatagramDispatcher = DatagramDispatcher.make(mContext); + mDatagramDispatcher = DatagramDispatcher.make(mContext, looper); // Create the DatagramReceiver singleton, // which is used to receive satellite datagrams. - mDatagramReceiver = DatagramReceiver.make(mContext); + mDatagramReceiver = DatagramReceiver.make(mContext, looper); } /** @@ -112,7 +117,7 @@ public class DatagramController { * This method requests modem to check if there are any pending datagrams to be received over * satellite. If there are any incoming datagrams, they will be received via * {@link android.telephony.satellite.SatelliteDatagramCallback - * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ISatelliteDatagramReceiverAck)} + * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ILongConsumer)} * */ public void pollPendingSatelliteDatagrams(@NonNull Message message, @Nullable Phone phone) { @@ -127,7 +132,6 @@ public class DatagramController { * input to this method. Datagram received here will be passed down to modem without any * encoding or encryption. * - * @param datagramId An id that uniquely identifies datagram requested to be sent. * @param datagramType datagram type indicating whether the datagram is of type * SOS_SMS or LOCATION_SHARING. * @param datagram encoded gateway datagram which is encrypted by the caller. @@ -135,16 +139,14 @@ public class DatagramController { * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in * full screen mode. * @param isSatelliteDemoModeEnabled True if satellite demo mode is enabled - * @param result The result receiver that returns datagramId if datagram is sent successfully - * or {@link SatelliteManager.SatelliteError} of the request if it is failed. + * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ - public void sendSatelliteDatagram(long datagramId, - @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, - boolean needFullScreenPointingUI, boolean isSatelliteDemoModeEnabled, - @NonNull ResultReceiver result) { + public void sendSatelliteDatagram(@SatelliteManager.DatagramType int datagramType, + @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, + boolean isSatelliteDemoModeEnabled, @NonNull Consumer callback) { // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING - mDatagramDispatcher.sendSatelliteDatagram(datagramId, datagramType, datagram, - needFullScreenPointingUI, isSatelliteDemoModeEnabled, result); + mDatagramDispatcher.sendSatelliteDatagram(datagramType, datagram, + needFullScreenPointingUI, isSatelliteDemoModeEnabled, callback); } private static void logd(@NonNull String log) { diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index 551893feea..ef7c8dd5d2 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -20,10 +20,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.os.AsyncResult; -import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.Message; -import android.os.ResultReceiver; import android.telephony.Rlog; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; @@ -34,6 +33,8 @@ import com.android.internal.telephony.Phone; import java.util.LinkedHashMap; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; /** * Datagram dispatcher used to send satellite datagrams. @@ -47,6 +48,8 @@ public class DatagramDispatcher extends Handler { @NonNull private static DatagramDispatcher sInstance; @NonNull private final Context mContext; + private static AtomicLong mNextDatagramId = new AtomicLong(0); + private final Object mLock = new Object(); @GuardedBy("mLock") @@ -71,11 +74,12 @@ public class DatagramDispatcher extends Handler { /** * Create the DatagramDispatcher singleton instance. * @param context The Context to use to create the DatagramDispatcher. + * @param looper The looper for the handler. * @return The singleton instance of DatagramDispatcher. */ - public static DatagramDispatcher make(@NonNull Context context) { + public static DatagramDispatcher make(@NonNull Context context, @NonNull Looper looper) { if (sInstance == null) { - sInstance = new DatagramDispatcher(context); + sInstance = new DatagramDispatcher(context, looper); } return sInstance; } @@ -84,9 +88,10 @@ public class DatagramDispatcher extends Handler { * Create a DatagramDispatcher to send satellite datagrams. * * @param context The Context for the DatagramDispatcher. + * @param looper The looper for the handler. */ - private DatagramDispatcher(@NonNull Context context) { - super(context.getMainLooper()); + private DatagramDispatcher(@NonNull Context context, @NonNull Looper looper) { + super(looper); mContext = context; synchronized (mLock) { mSendingDatagramInProgress = false; @@ -113,18 +118,18 @@ public class DatagramDispatcher extends Handler { public @NonNull SatelliteDatagram datagram; public boolean needFullScreenPointingUI; public boolean isSatelliteDemoModeEnabled; - public @NonNull ResultReceiver result; + public @NonNull Consumer callback; SendSatelliteDatagramArgument(long datagramId, @SatelliteManager.DatagramType int datagramType, - SatelliteDatagram datagram, boolean needFullScreenPointingUI, - boolean isSatelliteDemoModeEnabled, ResultReceiver result) { + @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, + boolean isSatelliteDemoModeEnabled, @NonNull Consumer callback) { this.datagramId = datagramId; this.datagramType = datagramType; this.datagram = datagram; this.needFullScreenPointingUI = needFullScreenPointingUI; this.isSatelliteDemoModeEnabled = isSatelliteDemoModeEnabled; - this.result = result; + this.callback = callback; } } @@ -153,8 +158,7 @@ public class DatagramDispatcher extends Handler { argument.needFullScreenPointingUI); } else { loge("sendSatelliteDatagram: No phone object"); - argument.result.send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); } break; } @@ -162,31 +166,34 @@ public class DatagramDispatcher extends Handler { case EVENT_SEND_SATELLITE_DATAGRAM_DONE: { ar = (AsyncResult) msg.obj; request = (DatagramDispatcherHandlerRequest) ar.userObj; - int error = SatelliteServiceUtils.getSatelliteError(ar, - "sendSatelliteDatagram", false); + int error = SatelliteServiceUtils.getSatelliteError(ar, "sendSatelliteDatagram"); SendSatelliteDatagramArgument argument = (SendSatelliteDatagramArgument) request.argument; + synchronized (mLock) { mSendingDatagramInProgress = false; } - Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS - bundle.putLong(SatelliteManager.KEY_SEND_SATELLITE_DATAGRAM, - argument.datagramId); - synchronized (mLock) { - if (argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { - mPendingEmergencyDatagramsMap.remove(argument.datagramId); - } else { - mPendingNonEmergencyDatagramsMap.remove(argument.datagramId); - } + + // Send response for current datagram + argument.callback.accept(error); + synchronized (mLock) { + if (argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { + mPendingEmergencyDatagramsMap.remove(argument.datagramId); + } else { + mPendingNonEmergencyDatagramsMap.remove(argument.datagramId); } + } + + // Handle pending datagrams + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { sendPendingDatagrams(); } else { // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED. - // TODO: send error code for all pending messages + sendErrorCodeAndCleanupPendingDatagrams(mPendingEmergencyDatagramsMap, + SatelliteManager.SATELLITE_REQUEST_ABORTED); + sendErrorCodeAndCleanupPendingDatagrams(mPendingNonEmergencyDatagramsMap, + SatelliteManager.SATELLITE_REQUEST_ABORTED); } - argument.result.send(error, bundle); break; } @@ -203,7 +210,6 @@ public class DatagramDispatcher extends Handler { * input to this method. Datagram received here will be passed down to modem without any * encoding or encryption. * - * @param datagramId An id that uniquely identifies datagram requested to be sent. * @param datagramType datagram type indicating whether the datagram is of type * SOS_SMS or LOCATION_SHARING. * @param datagram encoded gateway datagram which is encrypted by the caller. @@ -211,18 +217,18 @@ public class DatagramDispatcher extends Handler { * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in * full screen mode. * @param isSatelliteDemoModeEnabled True if satellite demo mode is enabled - * @param result The result receiver that returns datagramId if datagram is sent successfully - * or {@link SatelliteManager.SatelliteError} of the request if it is failed. + * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ - public void sendSatelliteDatagram(long datagramId, - @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, - boolean needFullScreenPointingUI, boolean isSatelliteDemoModeEnabled, - @NonNull ResultReceiver result) { + public void sendSatelliteDatagram(@SatelliteManager.DatagramType int datagramType, + @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, + boolean isSatelliteDemoModeEnabled, @NonNull Consumer callback) { Phone phone = SatelliteServiceUtils.getPhone(); + long datagramId = mNextDatagramId.getAndUpdate( + n -> ((n + 1) % DatagramController.MAX_DATAGRAM_ID)); SendSatelliteDatagramArgument datagramArgs = new SendSatelliteDatagramArgument(datagramId, datagramType, datagram, needFullScreenPointingUI, isSatelliteDemoModeEnabled, - result); + callback); synchronized (mLock) { if (datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { @@ -260,6 +266,26 @@ public class DatagramDispatcher extends Handler { } } + /** + * Send error code to all the pending datagrams + * @param errorCode error code to be returned. + */ + private void sendErrorCodeAndCleanupPendingDatagrams( + LinkedHashMap pendingDatagramsMap, + @SatelliteManager.SatelliteError int errorCode) { + synchronized (mLock) { + // Send error code to all the pending datagrams + for (Entry entry : + pendingDatagramsMap.entrySet()) { + SendSatelliteDatagramArgument argument = entry.getValue(); + argument.callback.accept(errorCode); + } + + // Clear pending datagram maps + pendingDatagramsMap.clear(); + } + } + /** * Posts the specified command to be executed on the main thread and returns immediately. * diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 34587c675c..d144d3bb1a 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -34,15 +34,15 @@ import android.os.RemoteException; import android.provider.Telephony; import android.telephony.Rlog; import android.telephony.satellite.ISatelliteDatagramCallback; -import android.telephony.satellite.ISatelliteDatagramReceiverAck; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.util.Pair; +import com.android.internal.R; +import com.android.internal.telephony.ILongConsumer; import com.android.internal.telephony.Phone; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** @@ -55,8 +55,6 @@ public class DatagramReceiver { private static final String SATELLITE_SHARED_PREF = "satellite_shared_pref"; /** Key used to read/write satellite datagramId in shared preferences. */ private static final String SATELLITE_DATAGRAM_ID_KEY = "satellite_datagram_id_key"; - - private static final long MAX_DATAGRAM_ID = (long) Math.pow(2, 16); private static AtomicLong mNextDatagramId = new AtomicLong(0); @NonNull private static DatagramReceiver sInstance; @@ -78,11 +76,12 @@ public class DatagramReceiver { /** * Create the DatagramReceiver singleton instance. * @param context The Context to use to create the DatagramReceiver. + * @param looper The looper for the handler. * @return The singleton instance of DatagramReceiver. */ - public static DatagramReceiver make(@NonNull Context context) { + public static DatagramReceiver make(@NonNull Context context, @NonNull Looper looper) { if (sInstance == null) { - sInstance = new DatagramReceiver(context); + sInstance = new DatagramReceiver(context, looper); } return sInstance; } @@ -92,19 +91,20 @@ public class DatagramReceiver { * The received datagrams will be delivered to respective messaging apps. * * @param context The Context for the DatagramReceiver. + * @param looper The looper for the handler. */ - private DatagramReceiver(@NonNull Context context) { + private DatagramReceiver(@NonNull Context context, @NonNull Looper looper) { mContext = context; mContentResolver = context.getContentResolver(); HandlerThread backgroundThread = new HandlerThread(TAG); backgroundThread.start(); - mBackgroundHandler = new Handler(backgroundThread.getLooper()); + mBackgroundHandler = new Handler(looper); try { mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); } catch (Exception e) { - loge("Cannot get default shared preferences:" + e); + loge("Cannot get default shared preferences: " + e); } if ((mSharedPreferences != null) && @@ -114,52 +114,54 @@ public class DatagramReceiver { } } - /** Callback used by datagram receiver app to send ack back to Telephony. */ - private static final ISatelliteDatagramReceiverAck.Stub mDatagramReceiverAck = - new ISatelliteDatagramReceiverAck.Stub() { - /** - * This callback will be used by datagram receiver app to send ack back to - * Telephony. If the callback is not received within five minutes, - * then Telephony will resend the datagram again. - * - * @param datagramId An id that uniquely identifies datagram - * received by satellite datagram receiver app. - * This should match with datagramId passed in - * {@link android.telephony.satellite.SatelliteDatagramCallback - * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, - * ISatelliteDatagramReceiverAck)} - * Upon receiving the ack, Telephony will remove the datagram from - * the persistent memory. - */ - public void acknowledgeSatelliteDatagramReceived(long datagramId) { - // TODO: make this handler non-static - logd("acknowledgeSatelliteDatagramReceived: datagramId=" + datagramId); - sInstance.mBackgroundHandler.post(() -> { - sInstance.deleteDatagram(datagramId); - }); - } - }; - /** * Listeners are updated about incoming datagrams using a backgroundThread. */ private static final class SatelliteDatagramListenerHandler extends Handler { public static final int EVENT_SATELLITE_DATAGRAM_RECEIVED = 1; + public static final int EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM = 2; + public static final int EVENT_RECEIVED_ACK = 3; @NonNull private final ConcurrentHashMap mListeners; private final int mSubId; + private static final class DatagramRetryArgument { + public long datagramId; + @NonNull public SatelliteDatagram datagram; + public int pendingCount; + @NonNull public ISatelliteDatagramCallback listener; + + DatagramRetryArgument(long datagramId, @NonNull SatelliteDatagram datagram, + int pendingCount, @NonNull ISatelliteDatagramCallback listener) { + this.datagramId = datagramId; + this.datagram = datagram; + this.pendingCount = pendingCount; + this.listener = listener; + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + if (other == null || getClass() != other.getClass()) return false; + DatagramRetryArgument that = (DatagramRetryArgument) other; + return datagramId == that.datagramId + && datagram.equals(that.datagram) + && pendingCount == that.pendingCount + && listener.equals(that.listener); + } + } + SatelliteDatagramListenerHandler(@NonNull Looper looper, int subId) { super(looper); mSubId = subId; mListeners = new ConcurrentHashMap<>(); } - public void addListener(ISatelliteDatagramCallback listener) { + public void addListener(@NonNull ISatelliteDatagramCallback listener) { mListeners.put(listener.asBinder(), listener); } - public void removeListener(ISatelliteDatagramCallback listener) { + public void removeListener(@NonNull ISatelliteDatagramCallback listener) { mListeners.remove(listener.asBinder()); } @@ -167,6 +169,11 @@ public class DatagramReceiver { return !mListeners.isEmpty(); } + private int getTimeoutToReceiveAck() { + return sInstance.mContext.getResources().getInteger( + R.integer.config_timeout_to_receive_delivered_ack_millis); + } + private long getDatagramId() { long datagramId = 0; if (sInstance.mSharedPreferences == null) { @@ -175,26 +182,27 @@ public class DatagramReceiver { sInstance.mSharedPreferences = sInstance.mContext .getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); } catch (Exception e) { - loge("Cannot get default shared preferences:" + e); + loge("Cannot get default shared preferences: " + e); } } if (sInstance.mSharedPreferences != null) { long prevDatagramId = sInstance.mSharedPreferences .getLong(SATELLITE_DATAGRAM_ID_KEY, mNextDatagramId.get()); - datagramId = (prevDatagramId + 1) % MAX_DATAGRAM_ID; + datagramId = (prevDatagramId + 1) % DatagramController.MAX_DATAGRAM_ID; mNextDatagramId.set(datagramId); sInstance.mSharedPreferences.edit().putLong(SATELLITE_DATAGRAM_ID_KEY, datagramId) .commit(); } else { loge("Shared preferences is null - returning default datagramId"); - datagramId = mNextDatagramId.getAndUpdate(n -> ((n + 1) % MAX_DATAGRAM_ID)); + datagramId = mNextDatagramId.getAndUpdate( + n -> ((n + 1) % DatagramController.MAX_DATAGRAM_ID)); } return datagramId; } - private void insertDatagram(long datagramId, SatelliteDatagram datagram) { + private void insertDatagram(long datagramId, @NonNull SatelliteDatagram datagram) { ContentValues contentValues = new ContentValues(); contentValues.put( Telephony.SatelliteDatagrams.COLUMN_UNIQUE_KEY_DATAGRAM_ID, datagramId); @@ -209,6 +217,61 @@ public class DatagramReceiver { } } + private void deleteDatagram(long datagramId) { + String whereClause = (Telephony.SatelliteDatagrams.COLUMN_UNIQUE_KEY_DATAGRAM_ID + + "=" + datagramId); + Cursor cursor = sInstance.mContentResolver.query( + Telephony.SatelliteDatagrams.CONTENT_URI, + null, whereClause, null, null); + if ((cursor != null) && (cursor.getCount() == 1)) { + int numRowsDeleted = sInstance.mContentResolver.delete( + Telephony.SatelliteDatagrams.CONTENT_URI, whereClause, null); + if (numRowsDeleted == 0) { + loge("Cannot delete datagram with datagramId: " + datagramId); + } else { + logd("Deleted datagram with datagramId: " + datagramId); + } + } else { + loge("Datagram with datagramId: " + datagramId + " is not present in DB."); + } + } + + private void onSatelliteDatagramReceived(@NonNull DatagramRetryArgument argument) { + try { + argument.listener.onSatelliteDatagramReceived(argument.datagramId, + argument.datagram, argument.pendingCount, + new ILongConsumer.Stub() { + /** + * This callback will be used by datagram receiver app + * to send ack back to Telephony. If the callback is not + * received within five minutes, then Telephony will + * resend the datagram again. + * + * @param datagramId An id that uniquely identifies + * datagram received by satellite + * datagram receiver app. This should + * match with datagramId passed in + * {@link android.telephony.satellite + * .SatelliteDatagramCallback + * #onSatelliteDatagramReceived(long, + * SatelliteDatagram, int, + * ISatelliteDatagramReceiverAck)} + * Upon receiving the ack, Telephony + * will remove the datagram from + * the persistent memory. + */ + @Override + public void accept(long datagramId) { + logd("acknowledgeSatelliteDatagramReceived: " + + "datagramId=" + datagramId); + sendMessage(obtainMessage(EVENT_RECEIVED_ACK, argument)); + } + }); + } catch (RemoteException e) { + logd("EVENT_SATELLITE_DATAGRAM_RECEIVED RemoteException: " + e); + } + } + @Override public void handleMessage(@NonNull Message msg) { switch (msg.what) { @@ -222,20 +285,34 @@ public class DatagramReceiver { // onDatagramTransferStateChanged long datagramId = getDatagramId(); - insertDatagram(datagramId, satelliteDatagram); - logd("Received EVENT_SATELLITE_DATAGRAM_RECEIVED for subId=" + mSubId); - mListeners.values().forEach(listener -> { - try { - // TODO (b/269637555): wait for ack and retry after 5mins - listener.onSatelliteDatagramReceived( - datagramId, satelliteDatagram, pendingCount, - mDatagramReceiverAck); - } catch (RemoteException e) { - logd("EVENT_SATELLITE_DATAGRAM_RECEIVED RemoteException: " + e); - } - }); + insertDatagram(datagramId, satelliteDatagram); + logd("Received EVENT_SATELLITE_DATAGRAM_RECEIVED for subId=" + mSubId); + mListeners.values().forEach(listener -> { + DatagramRetryArgument argument = new DatagramRetryArgument(datagramId, + satelliteDatagram, pendingCount, listener); + onSatelliteDatagramReceived(argument); + // wait for ack and retry after the timeout specified. + sendMessageDelayed(obtainMessage(EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM, + argument), getTimeoutToReceiveAck()); + }); + break; + } + + case EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM: { + DatagramRetryArgument argument = (DatagramRetryArgument) msg.obj; + logd("Received EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM datagramId:" + + argument.datagramId); + onSatelliteDatagramReceived(argument); break; } + + case EVENT_RECEIVED_ACK: { + DatagramRetryArgument argument = (DatagramRetryArgument) msg.obj; + logd("Received EVENT_RECEIVED_ACK datagramId:" + argument.datagramId); + removeMessages(EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM, argument); + deleteDatagram(argument.datagramId); + } + default: loge("SatelliteDatagramListenerHandler unknown event: " + msg.what); } @@ -259,7 +336,7 @@ public class DatagramReceiver { return SatelliteManager.SATELLITE_NOT_SUPPORTED; } - final int validSubId = SatelliteController.getInstance().getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); SatelliteDatagramListenerHandler satelliteDatagramListenerHandler = mSatelliteDatagramListenerHandlers.get(validSubId); if (satelliteDatagramListenerHandler == null) { @@ -293,8 +370,7 @@ public class DatagramReceiver { */ public void unregisterForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback) { - final int validSubId = SatelliteController.getInstance() - .getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); SatelliteDatagramListenerHandler handler = mSatelliteDatagramListenerHandlers.get(validSubId); if (handler != null) { @@ -321,7 +397,7 @@ public class DatagramReceiver { * This method requests modem to check if there are any pending datagrams to be received over * satellite. If there are any incoming datagrams, they will be received via * {@link android.telephony.satellite.SatelliteDatagramCallback - * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ISatelliteDatagramReceiverAck)} + * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ILongConsumer)} */ public void pollPendingSatelliteDatagrams(@NonNull Message message, @Nullable Phone phone) { if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { @@ -339,24 +415,6 @@ public class DatagramReceiver { } } - private void deleteDatagram(long datagramId) { - String whereClause = (Telephony.SatelliteDatagrams.COLUMN_UNIQUE_KEY_DATAGRAM_ID - + "=" + datagramId); - Cursor cursor = mContentResolver.query(Telephony.SatelliteDatagrams.CONTENT_URI, - null, whereClause, null, null); - if ((cursor != null) && (cursor.getCount() == 1)) { - int numRowsDeleted = sInstance.mContentResolver.delete( - Telephony.SatelliteDatagrams.CONTENT_URI, whereClause, null); - if (numRowsDeleted == 0) { - loge("Cannot delete datagram with datagramId: " + datagramId); - } else { - logd("Deleted datagram with datagramId: " + datagramId); - } - } else { - loge("Datagram with datagramId: " + datagramId + " is not present in DB."); - } - } - private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 0c305d6890..b0d511ee55 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -24,6 +24,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.Looper; @@ -41,6 +42,7 @@ import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.util.Log; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; @@ -137,7 +139,9 @@ public class SatelliteController extends Handler { */ public static void make(@NonNull Context context) { if (sInstance == null) { - sInstance = new SatelliteController(context); + HandlerThread satelliteThread = new HandlerThread(TAG); + satelliteThread.start(); + sInstance = new SatelliteController(context, satelliteThread.getLooper()); } } @@ -146,10 +150,11 @@ public class SatelliteController extends Handler { * {@link android.telephony.satellite.SatelliteManager} * * @param context The Context for the SatelliteController. + * @param looper The looper for the handler. It does not run on main thread. */ @VisibleForTesting - protected SatelliteController(@NonNull Context context) { - super(context.getMainLooper()); + protected SatelliteController(@NonNull Context context, @NonNull Looper looper) { + super(looper); mContext = context; // Create the SatelliteModemInterface singleton, which is used to manage connections @@ -166,7 +171,7 @@ public class SatelliteController extends Handler { // Create the DatagramController singleton, // which is used to send and receive satellite datagrams. - mDatagramController = DatagramController.make(mContext); + mDatagramController = DatagramController.make(mContext, looper); mSatelliteSupportedReceiver = new ResultReceiver(this) { @Override @@ -405,7 +410,7 @@ public class SatelliteController extends Handler { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, - "stopSatellitePositionUpdates", false); + "stopSatellitePositionUpdates"); ((Consumer) request.argument).accept(error); break; } @@ -434,13 +439,18 @@ public class SatelliteController extends Handler { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, - "getMaxCharactersPerSatelliteTextMessage", true); + "getMaxCharactersPerSatelliteTextMessage"); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - int maxCharLimit = ((int[]) ar.result)[0]; - if (DBG) logd("getMaxCharactersPerSatelliteTextMessage: " + maxCharLimit); - bundle.putInt(SatelliteManager.KEY_MAX_CHARACTERS_PER_SATELLITE_TEXT, - maxCharLimit); + if (ar.result == null) { + loge("getMaxCharactersPerSatelliteTextMessage: result is null"); + error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } else { + int maxCharLimit = ((int[]) ar.result)[0]; + if (DBG) logd("getMaxCharactersPerSatelliteTextMessage: " + maxCharLimit); + bundle.putInt(SatelliteManager.KEY_MAX_CHARACTERS_PER_SATELLITE_TEXT, + maxCharLimit); + } } ((ResultReceiver) request.argument).send(error, bundle); break; @@ -479,7 +489,7 @@ public class SatelliteController extends Handler { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; int errorCode = SatelliteServiceUtils.getSatelliteError(ar, - "provisionSatelliteService", false); + "provisionSatelliteService"); handleEventProvisionSatelliteServiceDone( (ProvisionSatelliteServiceArgument) request.argument, errorCode); notifyRequester(request); @@ -513,7 +523,7 @@ public class SatelliteController extends Handler { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; int errorCode = SatelliteServiceUtils.getSatelliteError(ar, - "deprovisionSatelliteService", false); + "deprovisionSatelliteService"); handleEventDeprovisionSatelliteServiceDone( (ProvisionSatelliteServiceArgument) request.argument, errorCode); break; @@ -543,8 +553,7 @@ public class SatelliteController extends Handler { request = (SatelliteControllerHandlerRequest) ar.userObj; RequestSatelliteEnabledArgument argument = (RequestSatelliteEnabledArgument) request.argument; - int error = SatelliteServiceUtils.getSatelliteError(ar, - "setSatelliteEnabled", false); + int error = SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled"); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { /** * TODO: check if Satellite is Acquired. @@ -581,12 +590,17 @@ public class SatelliteController extends Handler { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, - "isSatelliteEnabled", true); + "isSatelliteEnabled"); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - boolean enabled = ((int[]) ar.result)[0] == 1; - if (DBG) logd("isSatelliteEnabled: " + enabled); - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled); + if (ar.result == null) { + loge("isSatelliteEnabled: result is null"); + error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } else { + boolean enabled = ((int[]) ar.result)[0] == 1; + if (DBG) logd("isSatelliteEnabled: " + enabled); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled); + } } ((ResultReceiver) request.argument).send(error, bundle); break; @@ -614,15 +628,19 @@ public class SatelliteController extends Handler { case EVENT_IS_SATELLITE_SUPPORTED_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = SatelliteServiceUtils.getSatelliteError(ar, - "isSatelliteSupported", true); + int error = SatelliteServiceUtils.getSatelliteError(ar, "isSatelliteSupported"); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - boolean supported = (boolean) ar.result; - if (DBG) logd("isSatelliteSupported: " + supported); - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported); - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = supported; + if (ar.result == null) { + loge("isSatelliteSupported: result is null"); + error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } else { + boolean supported = (boolean) ar.result; + if (DBG) logd("isSatelliteSupported: " + supported); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported); + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = supported; + } } } else { synchronized (mIsSatelliteSupportedLock) { @@ -655,16 +673,21 @@ public class SatelliteController extends Handler { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, - "getSatelliteCapabilities", true); + "getSatelliteCapabilities"); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - SatelliteCapabilities capabilities = (SatelliteCapabilities) ar.result; - synchronized (mNeedsSatellitePointingLock) { - mNeedsSatellitePointing = capabilities.needsPointingToSatellite(); + if (ar.result == null) { + loge("getSatelliteCapabilities: result is null"); + error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } else { + SatelliteCapabilities capabilities = (SatelliteCapabilities) ar.result; + synchronized (mNeedsSatellitePointingLock) { + mNeedsSatellitePointing = capabilities.needsPointingToSatellite(); + } + if (DBG) logd("getSatelliteCapabilities: " + capabilities); + bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, + capabilities); } - if (DBG) logd("getSatelliteCapabilities: " + capabilities); - bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, - capabilities); } ((ResultReceiver) request.argument).send(error, bundle); break; @@ -682,7 +705,7 @@ public class SatelliteController extends Handler { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, - "pollPendingSatelliteDatagrams", false); + "pollPendingSatelliteDatagrams"); ((Consumer) request.argument).accept(error); break; } @@ -712,16 +735,21 @@ public class SatelliteController extends Handler { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, - "isSatelliteCommunicationAllowedForCurrentLocation", true); + "isSatelliteCommunicationAllowedForCurrentLocation"); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - boolean communicationAllowed = (boolean) ar.result; - if (DBG) { - logd("isSatelliteCommunicationAllowedForCurrentLocation: " - + communicationAllowed); + if (ar.result == null) { + loge("isSatelliteCommunicationAllowedForCurrentLocation: result is null"); + error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } else { + boolean communicationAllowed = (boolean) ar.result; + if (DBG) { + logd("isSatelliteCommunicationAllowedForCurrentLocation: " + + communicationAllowed); + } + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED, + communicationAllowed); } - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED, - communicationAllowed); } ((ResultReceiver) request.argument).send(error, bundle); break; @@ -751,15 +779,21 @@ public class SatelliteController extends Handler { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, - "requestTimeForNextSatelliteVisibility", true); + "requestTimeForNextSatelliteVisibility"); Bundle bundle = new Bundle(); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - int nextVisibilityDuration = ((int[]) ar.result)[0]; - if (DBG) { - logd("requestTimeForNextSatelliteVisibility: " + nextVisibilityDuration); + if (ar.result == null) { + loge("requestTimeForNextSatelliteVisibility: result is null"); + error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } else { + int nextVisibilityDuration = ((int[]) ar.result)[0]; + if (DBG) { + logd("requestTimeForNextSatelliteVisibility: " + + nextVisibilityDuration); + } + bundle.putInt(SatelliteManager.KEY_SATELLITE_NEXT_VISIBILITY, + nextVisibilityDuration); } - bundle.putInt(SatelliteManager.KEY_SATELLITE_NEXT_VISIBILITY, - nextVisibilityDuration); } ((ResultReceiver) request.argument).send(error, bundle); break; @@ -795,7 +829,8 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + // TODO: clean up this dependency on subId + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; @@ -819,7 +854,7 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; @@ -844,7 +879,7 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; @@ -868,7 +903,7 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; @@ -897,7 +932,7 @@ public class SatelliteController extends Handler { } } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, phone); } @@ -915,7 +950,7 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, phone); } @@ -937,7 +972,7 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; @@ -966,7 +1001,7 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; @@ -998,7 +1033,7 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; @@ -1028,7 +1063,7 @@ public class SatelliteController extends Handler { return null; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); Phone phone = SatelliteServiceUtils.getPhone(); if (mSatelliteProvisionCallbacks.containsKey(validSubId)) { @@ -1072,7 +1107,7 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; @@ -1097,7 +1132,7 @@ public class SatelliteController extends Handler { return SatelliteManager.SATELLITE_NOT_SUPPORTED; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); Phone phone = SatelliteServiceUtils.getPhone(); SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = @@ -1134,7 +1169,7 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback) { - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = mSatelliteProvisionStateChangedHandlers.get(validSubId); if (satelliteProvisionStateChangedHandler != null) { @@ -1156,7 +1191,7 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, isSatelliteProvisioned(validSubId)); @@ -1173,7 +1208,7 @@ public class SatelliteController extends Handler { */ @SatelliteManager.SatelliteError public int registerForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); Phone phone = SatelliteServiceUtils.getPhone(); SatelliteStateListenerHandler satelliteStateListenerHandler = @@ -1211,7 +1246,7 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); SatelliteStateListenerHandler handler = mSatelliteStateListenerHandlers.get(validSubId); if (handler != null) { handler.removeListener(callback); @@ -1266,15 +1301,16 @@ public class SatelliteController extends Handler { * This method requests modem to check if there are any pending datagrams to be received over * satellite. If there are any incoming datagrams, they will be received via * {@link android.telephony.satellite.SatelliteDatagramCallback - * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ISatelliteDatagramReceiverAck)} + * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ILongConsumer)} * * @param subId The subId of the subscription used for receiving datagrams. * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ - public void pollPendingSatelliteDatagrams(int subId, IIntegerConsumer callback) { + public void pollPendingSatelliteDatagrams(int subId, @NonNull IIntegerConsumer callback) { + // TODO: return pending datagram count on success Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; @@ -1293,22 +1329,22 @@ public class SatelliteController extends Handler { * encoding or encryption. * * @param subId The subId of the subscription to send satellite datagrams for. - * @param datagramId An id that uniquely identifies datagram requested to be sent. * @param datagramType datagram type indicating whether the datagram is of type * SOS_SMS or LOCATION_SHARING. * @param datagram encoded gateway datagram which is encrypted by the caller. * Datagram will be passed down to modem without any encoding or encryption. * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in * full screen mode. - * @param result The result receiver that returns datagramId if datagram is sent successfully - * or {@link SatelliteManager.SatelliteError} of the request if it is failed. + * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ - public void sendSatelliteDatagram(int subId, long datagramId, - @SatelliteManager.DatagramType int datagramType, SatelliteDatagram datagram, - boolean needFullScreenPointingUI, @NonNull ResultReceiver result) { - final int validSubId = getValidSatelliteSubId(subId); + public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, + SatelliteDatagram datagram, boolean needFullScreenPointingUI, + @NonNull IIntegerConsumer callback) { + Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); + + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { - result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } @@ -1319,7 +1355,7 @@ public class SatelliteController extends Handler { if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(needFullScreenPointingUI); } - mDatagramController.sendSatelliteDatagram(datagramId, datagramType, datagram, + mDatagramController.sendSatelliteDatagram(datagramType, datagram, needFullScreenPointingUI, mIsSatelliteDemoModeEnabled, result); } @@ -1356,7 +1392,7 @@ public class SatelliteController extends Handler { return; } - final int validSubId = getValidSatelliteSubId(subId); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); if (!isSatelliteProvisioned(validSubId)) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; @@ -1414,7 +1450,7 @@ public class SatelliteController extends Handler { SatelliteControllerHandlerRequest request = (SatelliteControllerHandlerRequest) ar.userObj; SatellitePositionUpdateArgument arg = (SatellitePositionUpdateArgument) request.argument; int errorCode = SatelliteServiceUtils.getSatelliteError(ar, - "handleStartSatellitePositionUpdatesDone", false); + "handleStartSatellitePositionUpdatesDone"); arg.errorCallback.accept(errorCode); if (errorCode != SatelliteManager.SATELLITE_ERROR_NONE) { @@ -1514,35 +1550,6 @@ public class SatelliteController extends Handler { return request.result; } - /** - * Get valid subscription id for satellite communication. - * - * @param subId The subscription id. - * @return input subId if the subscription is active else return default subscription id. - */ - public int getValidSatelliteSubId(int subId) { - // TODO: move this method to SatelliteServiceUtils - final long identity = Binder.clearCallingIdentity(); - try { - boolean isActive; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId, - mContext.getOpPackageName(), mContext.getAttributionTag()); - } else { - isActive = SubscriptionController.getInstance().isActiveSubId(subId, - mContext.getOpPackageName(), mContext.getAttributionTag()); - } - - if (isActive) { - return subId; - } - } finally { - Binder.restoreCallingIdentity(identity); - } - if (DBG) logd("getValidSatelliteSubId: use DEFAULT_SUBSCRIPTION_ID for subId=" + subId); - return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; - } - /** * Check if satellite is provisioned for a subscription on the device. * @param subId The subscription id. diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java index 09749066ef..a30dd54bc5 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java @@ -18,8 +18,11 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Context; import android.os.AsyncResult; +import android.os.Binder; import android.telephony.Rlog; +import android.telephony.SubscriptionManager; import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; @@ -32,6 +35,8 @@ import com.android.internal.telephony.CommandException; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RILUtils; +import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import java.util.Arrays; import java.util.stream.Collectors; @@ -203,20 +208,14 @@ public class SatelliteServiceUtils { * * @param ar AsyncResult used to determine the error code. * @param caller The satellite request. - * @param checkResult Whether to check if the result exists. * * @return The {@link SatelliteManager.SatelliteError} error code from the request. */ @SatelliteManager.SatelliteError public static int getSatelliteError(@NonNull AsyncResult ar, - @NonNull String caller, boolean checkResult) { + @NonNull String caller) { int errorCode; if (ar.exception == null) { errorCode = SatelliteManager.SATELLITE_ERROR_NONE; - if (checkResult && ar.result == null) { - // TODO: Move this out of this method. - loge(caller + ": result is null"); - errorCode = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } } else { errorCode = SatelliteManager.SATELLITE_ERROR; if (ar.exception instanceof CommandException) { @@ -234,6 +233,34 @@ public class SatelliteServiceUtils { return errorCode; } + /** + * Get valid subscription id for satellite communication. + * + * @param subId The subscription id. + * @return input subId if the subscription is active else return default subscription id. + */ + public static int getValidSatelliteSubId(int subId, @NonNull Context context) { + final long identity = Binder.clearCallingIdentity(); + try { + boolean isActive; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId, + context.getOpPackageName(), context.getAttributionTag()); + } else { + isActive = SubscriptionController.getInstance().isActiveSubId(subId, + context.getOpPackageName(), context.getAttributionTag()); + } + + if (isActive) { + return subId; + } + } finally { + Binder.restoreCallingIdentity(identity); + } + logd("getValidSatelliteSubId: use DEFAULT_SUBSCRIPTION_ID for subId=" + subId); + return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; + } + /** * Return phone associated with phoneId 0. * diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java index ea788bcad5..103156cd44 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java @@ -97,7 +97,8 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { when(mMockContext.getResources()).thenReturn(mResources); when(mResources.getString(com.android.internal.R.string.config_satellite_service_package)) .thenReturn(""); - mTestSatelliteController = new TestSatelliteController(mMockContext); + mTestSatelliteController = new TestSatelliteController(mMockContext, + Looper.getMainLooper()); mTestImsManager = new TestImsManager( mMockContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null); mTestConnection = new TestConnection(CALL_ID); @@ -403,8 +404,8 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { * * @param context The Context for the SatelliteController. */ - protected TestSatelliteController(Context context) { - super(context); + protected TestSatelliteController(Context context, Looper looper) { + super(context, looper); mProvisionStateChangedCallbacks = new HashMap<>(); mSatelliteProvisionStates = new HashMap<>(); mSatelliteProvisionStates.put(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); -- GitLab From 5b956f07ae8b2a87de72c973099cc9facb43e240 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 7 Mar 2023 16:56:41 -0800 Subject: [PATCH 502/656] Force update override network type before timer When data RAT changes from LTE -> NR but the state is no longer NR advanced, we don't update the override network type if a timer is active. For this scenario, manually update the override network type to be NONE to prevent a mismatch between the data rat and override network type. Test: atest NetworkTypeControllerTest Bug: 269163800 Change-Id: I686fa530814d522ed0b1216c63baf21e1fd00cba --- .../telephony/NetworkTypeController.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 7bc765920b..f94ff26bb8 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -997,6 +997,13 @@ public class NetworkTypeController extends StateMachine { // Update in case the override network type changed updateOverrideNetworkType(); } else { + if (rat == TelephonyManager.NETWORK_TYPE_NR && mOverrideNetworkType + != TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) { + // manually override network type after data rat changes since + // timer will prevent it from being updated + mOverrideNetworkType = + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE; + } transitionWithTimerTo(mNrConnectedState); } } else if (isLte(rat) && isNrNotRestricted()) { @@ -1140,19 +1147,17 @@ public class NetworkTypeController extends StateMachine { if (currentState.equals(STATE_CONNECTED_NR_ADVANCED)) { if (DBG) log("Reset timers since state is NR_ADVANCED."); resetAllTimers(); - } - - if (currentState.equals(STATE_CONNECTED) + } else if (currentState.equals(STATE_CONNECTED) && !mPrimaryTimerState.equals(STATE_CONNECTED_NR_ADVANCED) && !mSecondaryTimerState.equals(STATE_CONNECTED_NR_ADVANCED)) { - if (DBG) log("Reset non-NR_advanced timers since state is NR_CONNECTED"); - resetAllTimers(); - } - - int rat = getDataNetworkType(); - if (!isLte(rat) && rat != TelephonyManager.NETWORK_TYPE_NR) { - if (DBG) log("Reset timers since 2G and 3G don't need NR timers."); + if (DBG) log("Reset non-NR_ADVANCED timers since state is NR_CONNECTED"); resetAllTimers(); + } else { + int rat = getDataNetworkType(); + if (!isLte(rat) && rat != TelephonyManager.NETWORK_TYPE_NR) { + if (DBG) log("Reset timers since 2G and 3G don't need NR timers."); + resetAllTimers(); + } } } } -- GitLab From 4b4b766056d119c69fdd72904cc109b48de583fe Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 2 Mar 2023 13:46:12 -0800 Subject: [PATCH 503/656] Fixed building the incorrect phone account using iccid Phone account has switched to subId after ag/17240597. Making the corresponding changes. Bug: 268399273 Test: Basic phone functionality tests Change-Id: I73d346d168b7b1f218cb845783bacae60b84a224 (cherry picked from commit on googleplex-android-review.googlesource.com host: 6d0a5032b10933e3bcfa4185abb2d32312a8f631) Merged-In: I73d346d168b7b1f218cb845783bacae60b84a224 --- .../internal/telephony/MissedIncomingCallSmsFilter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java b/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java index 5932f9ed0c..e8b81968b1 100644 --- a/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java +++ b/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java @@ -228,10 +228,10 @@ public class MissedIncomingCallSmsFilter { return false; } - // Create phone account. The logic is copied from PhoneUtils.makePstnPhoneAccountHandle. + // Create phone account. The logic is copied from PhoneUtils.makePstnPhoneAccountHandleWithId. private static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) { return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT, - String.valueOf(phone.getFullIccSerialNumber())); + String.valueOf(phone.getSubId()), phone.getUserHandle()); } /** -- GitLab From 38b15c29abddd9fcfe5d6a2f91ab124c1f525dea Mon Sep 17 00:00:00 2001 From: Hwangoo Park Date: Wed, 8 Mar 2023 02:52:19 +0000 Subject: [PATCH 504/656] Use "useEmergencyPdn" flag for emergency SMS This flag was introduced to check whether IMS PDN should be used for PS emergency services. If IMS PDN is used for an emergency SMS, the domain selection should not try to change the preferred transport type for emergency service. If true, the preferred transport type for emergency service will be requested to the QualifiedNetworksService when the transport type needs to be changed. Otherwise, the preferred transport type will not be requested to that component even if the transport type needs to be changed. Bug: 270333880 Test: atest SmsDomainSelectionConnectionTest, EmergencySmsDomainSelectionConnectionTest Test: manual (verify normal/emergency SMS on device) Change-Id: I252f8e7aeb990cc62757a9f5efd40cb341e1ef49 --- ...EmergencySmsDomainSelectionConnection.java | 45 ++++++++---- ...gencySmsDomainSelectionConnectionTest.java | 70 +++++++++++++++---- .../SmsDomainSelectionConnectionTest.java | 5 ++ 3 files changed, 93 insertions(+), 27 deletions(-) diff --git a/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java b/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java index 067d761886..efcdf116e4 100644 --- a/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java +++ b/src/java/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnection.java @@ -52,8 +52,14 @@ public class EmergencySmsDomainSelectionConnection extends SmsDomainSelectionCon mEmergencyStateTracker = tracker; } + /** + * Notifies that WLAN transport has been selected. + * + * @param useEmergencyPdn A flag specifying whether Wi-Fi emergency service uses emergency PDN + * or not. + */ @Override - public void onWlanSelected() { + public void onWlanSelected(boolean useEmergencyPdn) { synchronized (mLock) { if (mPreferredTransportType != AccessNetworkConstants.TRANSPORT_TYPE_INVALID) { logi("Domain selection completion is in progress"); @@ -63,18 +69,20 @@ public class EmergencySmsDomainSelectionConnection extends SmsDomainSelectionCon mEmergencyStateTracker.onEmergencyTransportChanged( EmergencyStateTracker.EMERGENCY_TYPE_SMS, MODE_EMERGENCY_WLAN); - // Change the transport type if the current preferred transport type for an emergency - // is not {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}. - AccessNetworksManager anm = mPhone.getAccessNetworksManager(); - if (anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY) - != AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { - changePreferredTransport(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - // The {@link #onDomainSlected()} will be called after the preferred transport - // is successfully changed and notified from the {@link AccessNetworksManager}. - return; + if (useEmergencyPdn) { + // Change the transport type if the current preferred transport type for + // an emergency is not {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}. + AccessNetworksManager anm = mPhone.getAccessNetworksManager(); + if (anm.getPreferredTransport(ApnSetting.TYPE_EMERGENCY) + != AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { + changePreferredTransport(AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + // The {@link #onDomainSlected()} will be called after the preferred transport + // is successfully changed and notified from the {@link AccessNetworksManager}. + return; + } } - super.onWlanSelected(); + super.onWlanSelected(useEmergencyPdn); } } @@ -84,15 +92,22 @@ public class EmergencySmsDomainSelectionConnection extends SmsDomainSelectionCon EmergencyStateTracker.EMERGENCY_TYPE_SMS, MODE_EMERGENCY_WWAN); } + /** + * Notifies the domain selected. + * + * @param domain The selected domain. + * @param useEmergencyPdn A flag specifying whether emergency service uses emergency PDN or not. + */ @Override - public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain) { + public void onDomainSelected(@NetworkRegistrationInfo.Domain int domain, + boolean useEmergencyPdn) { synchronized (mLock) { if (mPreferredTransportType != AccessNetworkConstants.TRANSPORT_TYPE_INVALID) { logi("Domain selection completion is in progress"); return; } - if (domain == NetworkRegistrationInfo.DOMAIN_PS) { + if (useEmergencyPdn && domain == NetworkRegistrationInfo.DOMAIN_PS) { // Change the transport type if the current preferred transport type for // an emergency is not {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}. AccessNetworksManager anm = mPhone.getAccessNetworksManager(); @@ -105,7 +120,7 @@ public class EmergencySmsDomainSelectionConnection extends SmsDomainSelectionCon } } - super.onDomainSelected(domain); + super.onDomainSelected(domain, useEmergencyPdn); } } @@ -131,7 +146,7 @@ public class EmergencySmsDomainSelectionConnection extends SmsDomainSelectionCon synchronized (mLock) { if (preferredTransportType == mPreferredTransportType) { mPreferredTransportType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; - super.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + super.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, true); anm.unregisterForQualifiedNetworksChanged(mHandler); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java index f4a743e4a9..25ccecbebc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/EmergencySmsDomainSelectionConnectionTest.java @@ -118,7 +118,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); }, mHandler::post); - mDsConnection.onWlanSelected(); + mDsConnection.onWlanSelected(true); processAllMessages(); assertTrue(future.isDone()); @@ -139,7 +139,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); }, mHandler::post); - mDsConnection.onWlanSelected(); + mDsConnection.onWlanSelected(true); processAllMessages(); ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); @@ -160,6 +160,30 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { verify(mAnm).unregisterForQualifiedNetworksChanged(any(Handler.class)); } + @Test + @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") + public void testOnWlanSelectedWithDifferentTransportTypeAndImsPdn() throws Exception { + when(mAnm.getPreferredTransport(anyInt())).thenReturn( + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onWlanSelected(false); + processAllMessages(); + + verify(mEmergencyStateTracker).onEmergencyTransportChanged( + eq(EmergencyStateTracker.EMERGENCY_TYPE_SMS), eq(MODE_EMERGENCY_WLAN)); + verify(mAnm, never()).registerForQualifiedNetworksChanged(any(Handler.class), anyInt()); + verify(mPhone, never()).notifyEmergencyDomainSelected(anyInt()); + + assertTrue(future.isDone()); + } + @Test @SmallTest @SuppressWarnings("FutureReturnValueIgnored") @@ -174,11 +198,11 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); }, mHandler::post); - mDsConnection.onWlanSelected(); + mDsConnection.onWlanSelected(true); // When onWlanSelected() is called again, // it will be ignored because the change of preferred transport is in progress. // => onEmergencyTransportChanged() is called only once. - mDsConnection.onWlanSelected(); + mDsConnection.onWlanSelected(true); processAllMessages(); ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); @@ -220,7 +244,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); }, mHandler::post); - mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, true); processAllMessages(); assertTrue(future.isDone()); @@ -239,7 +263,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); }, mHandler::post); - mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, true); processAllMessages(); ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); @@ -258,6 +282,28 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { verify(mAnm).unregisterForQualifiedNetworksChanged(any(Handler.class)); } + @Test + @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") + public void testOnDomainSelectedPsWithDifferentTransportTypeAndImsPdn() throws Exception { + when(mAnm.getPreferredTransport(anyInt())).thenReturn( + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + CompletableFuture future = + mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); + future.thenAcceptAsync((domain) -> { + assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); + }, mHandler::post); + + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, false); + processAllMessages(); + + verify(mAnm, never()).registerForQualifiedNetworksChanged(any(Handler.class), anyInt()); + verify(mPhone, never()).notifyEmergencyDomainSelected(anyInt()); + + assertTrue(future.isDone()); + } + @Test @SmallTest @SuppressWarnings("FutureReturnValueIgnored") @@ -271,7 +317,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); }, mHandler::post); - mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, true); processAllMessages(); ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); @@ -304,11 +350,11 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); }, mHandler::post); - mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, true); // When onDomainSelected() is called again with the different domain, // it will be ignored because the change of preferred transport is in progress. // => The domain selection result is DOMAIN_PS. - mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_CS); + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_CS, false); processAllMessages(); ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); @@ -339,7 +385,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_CS), domain); }, mHandler::post); - mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_CS); + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_CS, false); processAllMessages(); assertTrue(future.isDone()); @@ -358,7 +404,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); }, mHandler::post); - mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, true); processAllMessages(); ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); @@ -389,7 +435,7 @@ public class EmergencySmsDomainSelectionConnectionTest extends TelephonyTest { assertEquals(Integer.valueOf(NetworkRegistrationInfo.DOMAIN_PS), domain); }, mHandler::post); - mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS); + mDsConnection.onDomainSelected(NetworkRegistrationInfo.DOMAIN_PS, true); processAllMessages(); ArgumentCaptor handlerCaptor = ArgumentCaptor.forClass(Handler.class); diff --git a/tests/telephonytests/src/com/android/internal/telephony/domainselection/SmsDomainSelectionConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/domainselection/SmsDomainSelectionConnectionTest.java index 77d836721d..e4afa79495 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/domainselection/SmsDomainSelectionConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/domainselection/SmsDomainSelectionConnectionTest.java @@ -112,6 +112,7 @@ public class SmsDomainSelectionConnectionTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnWlanSelected() throws Exception { setUpTestableLooper(); CompletableFuture future = @@ -139,6 +140,7 @@ public class SmsDomainSelectionConnectionTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnDomainSelectedPs() throws Exception { setUpTestableLooper(); CompletableFuture future = @@ -155,6 +157,7 @@ public class SmsDomainSelectionConnectionTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testOnDomainSelectedCs() throws Exception { setUpTestableLooper(); CompletableFuture future = @@ -171,6 +174,7 @@ public class SmsDomainSelectionConnectionTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testFinishSelection() throws Exception { setUpTestableLooper(); CompletableFuture future = @@ -188,6 +192,7 @@ public class SmsDomainSelectionConnectionTest { @Test @SmallTest + @SuppressWarnings("FutureReturnValueIgnored") public void testCancelSelection() throws Exception { CompletableFuture future = mDsConnection.requestDomainSelection(mDsAttr, mDscCallback); -- GitLab From cd4ae07af920383a8286a167058310fcc6e5d0bd Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 8 Mar 2023 13:49:16 -0800 Subject: [PATCH 505/656] Gracefully handle subscription id not existing case When subscription id does not exist in the database, use null as the user handle. Fix: 265859569 Test: atest GsmCdmaPhoneTest Change-Id: Ic667fd66b7b667807898707d4318af0cbc09756e --- .../com/android/internal/telephony/Phone.java | 20 ++++++++++++++----- .../internal/telephony/GsmCdmaPhoneTest.java | 15 ++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 1dbe8ddc9f..9f2513a4e5 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5160,14 +5160,24 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { } /** - * @return UserHandle from phone sub id, or null if subscription is invalid. + * @return User handle associated with the phone's subscription id. {@code null} if subscription + * is invalid or not found. */ + @Nullable public UserHandle getUserHandle() { - SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class); int subId = getSubId(); - return subManager.isValidSubscriptionId(subId) - ? subManager.getSubscriptionUserHandle(subId) - : null; + + UserHandle userHandle = null; + try { + SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class); + if (subManager != null) { + userHandle = subManager.getSubscriptionUserHandle(subId); + } + } catch (IllegalArgumentException ex) { + loge("getUserHandle: ex=" + ex); + } + + return userHandle; } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index 2849445e54..a0c9cd375d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -61,6 +61,7 @@ import android.os.Handler; import android.os.Message; import android.os.PersistableBundle; import android.os.Process; +import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; import android.preference.PreferenceManager; @@ -2574,4 +2575,18 @@ public class GsmCdmaPhoneTest extends TelephonyTest { verify(est).exitEmergencyCallbackMode(); } + + @Test + public void testGetUserHandle() { + UserHandle userHandle = new UserHandle(123); + doReturn(userHandle).when(mSubscriptionManager).getSubscriptionUserHandle(anyInt()); + assertEquals(userHandle, mPhoneUT.getUserHandle()); + + doReturn(null).when(mSubscriptionManager).getSubscriptionUserHandle(anyInt()); + assertNull(mPhoneUT.getUserHandle()); + + doThrow(IllegalArgumentException.class).when(mSubscriptionManager) + .getSubscriptionUserHandle(anyInt()); + assertNull(mPhoneUT.getUserHandle()); + } } -- GitLab From 531d3f055bfbad77fe4c27b2284c2cb9e2279822 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 7 Mar 2023 09:52:04 -0800 Subject: [PATCH 506/656] Fixed phone number not seen on about page Made format phone number utility method case insensitive. Fix: 271753491 Test: Verified on settings->about->phone number Test: atest android.telephony.cts.PhoneNumberUtilsTest Test: atest com.android.internal.telephony.PhoneNumberUtilsTest Change-Id: I61dce7786ed2c58f226676100ffb17d44a15bc48 --- .../telephony/PhoneNumberUtilsTest.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java index dd59e28f3e..2f3bbf713f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java @@ -562,6 +562,17 @@ public class PhoneNumberUtilsTest { assertEquals("800-GOOG-114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US")); } + @Test + public void testFormatNumber_lowerCase() { + assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "us")); + assertEquals("223-4567", PhoneNumberUtils.formatNumber("2234567", "us")); + assertEquals("011 86 10 8888 0000", + PhoneNumberUtils.formatNumber("011861088880000", "us")); + assertEquals("010 8888 0000", PhoneNumberUtils.formatNumber("01088880000", "cn")); + // formatNumber doesn't format alpha numbers, but keep them as they are. + assertEquals("800-GOOG-114", PhoneNumberUtils.formatNumber("800-GOOG-114", "us")); + } + /** * Tests ability to format phone numbers from Japan using the international format when the * current country is not Japan. @@ -570,6 +581,9 @@ public class PhoneNumberUtilsTest { @Test public void testFormatJapanInternational() { assertEquals("+81 90-6657-1180", PhoneNumberUtils.formatNumber("+819066571180", "US")); + + // Again with lower case country code + assertEquals("+81 90-6657-1180", PhoneNumberUtils.formatNumber("+819066571180", "us")); } /** @@ -582,8 +596,15 @@ public class PhoneNumberUtilsTest { assertEquals("090-6657-0660", PhoneNumberUtils.formatNumber("09066570660", "JP")); assertEquals("090-6657-1180", PhoneNumberUtils.formatNumber("+819066571180", "JP")); + // Again with lower case country code + assertEquals("090-6657-0660", PhoneNumberUtils.formatNumber("09066570660", "jp")); + assertEquals("090-6657-1180", PhoneNumberUtils.formatNumber("+819066571180", "jp")); + + // US number should still be internationally formatted assertEquals("+1 650-555-1212", PhoneNumberUtils.formatNumber("+16505551212", "JP")); + // Again with lower case country code + assertEquals("+1 650-555-1212", PhoneNumberUtils.formatNumber("+16505551212", "jp")); } @SmallTest @@ -600,6 +621,20 @@ public class PhoneNumberUtilsTest { assertEquals("**650 2910000", PhoneNumberUtils.formatNumber("**650 2910000", "US")); } + // Same as testFormatNumber_LeadingStarAndHash but using lower case country code. + @Test + public void testFormatNumber_LeadingStarAndHash_countryCodeLowerCase() { + // Numbers with a leading '*' or '#' should be left unchanged. + assertEquals("*650 2910000", PhoneNumberUtils.formatNumber("*650 2910000", "us")); + assertEquals("#650 2910000", PhoneNumberUtils.formatNumber("#650 2910000", "us")); + assertEquals("*#650 2910000", PhoneNumberUtils.formatNumber("*#650 2910000", "us")); + assertEquals("#*650 2910000", PhoneNumberUtils.formatNumber("#*650 2910000", "us")); + assertEquals("#650*2910000", PhoneNumberUtils.formatNumber("#650*2910000", "us")); + assertEquals("#650*2910000", PhoneNumberUtils.formatNumber("#650*2910000", "us")); + assertEquals("##650 2910000", PhoneNumberUtils.formatNumber("##650 2910000", "us")); + assertEquals("**650 2910000", PhoneNumberUtils.formatNumber("**650 2910000", "us")); + } + @SmallTest @Test public void testNormalizeNumber() { @@ -641,6 +676,38 @@ public class PhoneNumberUtilsTest { PhoneNumberUtils.formatNumber("011861088880000", "", "GB")); } + // Same as testFormatDailabeNumber but using lower case country code. + @Test + public void testFormatDailabeNumber_countryCodeLowerCase() { + // Using the phoneNumberE164's country code + assertEquals("(650) 291-0000", + PhoneNumberUtils.formatNumber("6502910000", "+16502910000", "cn")); + // Using the default country code for a phone number containing the IDD + assertEquals("011 86 10 8888 0000", + PhoneNumberUtils.formatNumber("011861088880000", "+861088880000", "us")); + assertEquals("00 86 10 8888 0000", + PhoneNumberUtils.formatNumber("00861088880000", "+861088880000", "gb")); + assertEquals("+86 10 8888 0000", + PhoneNumberUtils.formatNumber("+861088880000", "+861088880000", "gb")); + // Wrong default country, so no formatting is done + assertEquals("011861088880000", + PhoneNumberUtils.formatNumber("011861088880000", "+861088880000", "gb")); + // The phoneNumberE164 is null + assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("6502910000", null, "us")); + // The given number has a country code. + assertEquals("+1 650-291-0000", PhoneNumberUtils.formatNumber("+16502910000", null, "cn")); + // The given number was formatted. + assertEquals("650-291-0000", PhoneNumberUtils.formatNumber("650-291-0000", null, "us")); + // A valid Polish number should be formatted. + assertEquals("506 128 687", PhoneNumberUtils.formatNumber("506128687", null, "pl")); + // An invalid Polish number should be left as it is. Note Poland doesn't use '0' as a + // national prefix; therefore, the leading '0' makes the number invalid. + assertEquals("0506128687", PhoneNumberUtils.formatNumber("0506128687", null, "pl")); + // Wrong default country, so no formatting is done + assertEquals("011861088880000", + PhoneNumberUtils.formatNumber("011861088880000", "", "gb")); + } + @FlakyTest @Test @Ignore @@ -740,6 +807,22 @@ public class PhoneNumberUtilsTest { assertFalse(PhoneNumberUtils.isInternationalNumber("011-613-966-94916", "AU")); } + // Same as testIsInternational but using lower case country code. + @Test + public void testIsInternational_countryCodeLowerCase() { + assertFalse(PhoneNumberUtils.isInternationalNumber("", "us")); + assertFalse(PhoneNumberUtils.isInternationalNumber(null, "us")); + assertFalse(PhoneNumberUtils.isInternationalNumber("+16505551212", "us")); + assertTrue(PhoneNumberUtils.isInternationalNumber("+16505551212", "uk")); + assertTrue(PhoneNumberUtils.isInternationalNumber("+16505551212", "jp")); + assertTrue(PhoneNumberUtils.isInternationalNumber("+86 10 8888 0000", "us")); + assertTrue(PhoneNumberUtils.isInternationalNumber("001-541-754-3010", "de")); + assertFalse(PhoneNumberUtils.isInternationalNumber("001-541-754-3010", "us")); + assertTrue(PhoneNumberUtils.isInternationalNumber("01161396694916", "us")); + assertTrue(PhoneNumberUtils.isInternationalNumber("011-613-966-94916", "us")); + assertFalse(PhoneNumberUtils.isInternationalNumber("011-613-966-94916", "au")); + } + @SmallTest @Test public void testIsUriNumber() { -- GitLab From 46de4f8d19330daa0a3ee81e0ec71a7477f06529 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Wed, 8 Mar 2023 10:38:54 -0800 Subject: [PATCH 507/656] Enhance IMS/RCS graceful tear down The enhancement is to track which specific network where the IMS/RCS registration took place, so that we only wait for dereg delay for those networks. Without this change, if APM is on, we'll always wait for an extra delay for a network that's requested by IMS/RCS service but irrelevant to registration. Also skip retry upon network disconnected if we're in the middle of tearing down all networks(mPendingTearDownAllNetworks). Fix: 271215877 Test: Turn on APM under Wifi and observe the internet network immediatly disconnected Change-Id: Ic6c608cf00dbff5e44c424d2704ecf5fc9681817 --- .../telephony/data/DataNetworkController.java | 83 ++++++++++++------- .../data/DataNetworkControllerTest.java | 66 ++++++++++----- 2 files changed, 97 insertions(+), 52 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index ddd90c441e..b18ba3323b 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -77,6 +77,7 @@ import android.util.IndentingPrintWriter; import android.util.LocalLog; import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; @@ -325,8 +326,11 @@ public class DataNetworkController extends Handler { */ private final @NonNull SparseArray mImsStateCallbacks = new SparseArray<>(); - /** Registered IMS features. Unregistered IMS features are removed from the set. */ - private final @NonNull Set mRegisteredImsFeatures = new ArraySet<>(); + /** + * The transport on which IMS features are registered. Key is the IMS feature, value is the + * transport. Unregistered IMS features are removed from the set. + */ + private final @NonNull SparseIntArray mRegisteredImsFeaturesTransport = new SparseIntArray(2); /** IMS feature package names. Key is the IMS feature, value is the package name. */ private final @NonNull SparseArray mImsFeaturePackageName = new SparseArray<>(); @@ -2191,17 +2195,18 @@ public class DataNetworkController extends Handler { RegistrationManager.RegistrationCallback callback = new RegistrationManager.RegistrationCallback() { @Override - public void onRegistered(ImsRegistrationAttributes attributes) { + public void onRegistered(@NonNull ImsRegistrationAttributes attributes) { log("IMS " + DataUtils.imsFeatureToString(imsFeature) + " registered. Attributes=" + attributes); - mRegisteredImsFeatures.add(imsFeature); + mRegisteredImsFeaturesTransport.put( + imsFeature, attributes.getTransportType()); } @Override public void onUnregistered(ImsReasonInfo info) { log("IMS " + DataUtils.imsFeatureToString(imsFeature) + " deregistered. Info=" + info); - mRegisteredImsFeatures.remove(imsFeature); + mRegisteredImsFeaturesTransport.delete(imsFeature); evaluatePendingImsDeregDataNetworks(); } }; @@ -2886,6 +2891,16 @@ public class DataNetworkController extends Handler { mImsDataNetworkState = TelephonyManager.DATA_DISCONNECTED; } + if (!mPendingTearDownAllNetworks) { + // Immediately reestablish on target transport if network was torn down due to policy + long delayMillis = tearDownReason == DataNetwork.TEAR_DOWN_REASON_HANDOVER_NOT_ALLOWED + ? 0 : mDataConfigManager.getRetrySetupAfterDisconnectMillis(); + // Sometimes network was unsolicitedly reported lost for reasons. We should re-evaluate + // and see if data network can be re-established again. + sendMessageDelayed(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, + DataEvaluationReason.RETRY_AFTER_DISCONNECTED), delayMillis); + } + if (mAnyDataNetworkExisting && mDataNetworkList.isEmpty()) { log("All data networks disconnected now."); mPendingTearDownAllNetworks = false; @@ -2893,14 +2908,6 @@ public class DataNetworkController extends Handler { mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor( () -> callback.onAnyDataNetworkExistingChanged(mAnyDataNetworkExisting))); } - - // Immediately reestablish on target transport if network was torn down due to policy - long delayMillis = tearDownReason == DataNetwork.TEAR_DOWN_REASON_HANDOVER_NOT_ALLOWED - ? 0 : mDataConfigManager.getRetrySetupAfterDisconnectMillis(); - // Sometimes network was unsolicitedly reported lost for reasons. We should re-evaluate - // and see if data network can be re-established again. - sendMessageDelayed(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, - DataEvaluationReason.RETRY_AFTER_DISCONNECTED), delayMillis); } /** @@ -3620,22 +3627,23 @@ public class DataNetworkController extends Handler { } /** - * Check if the data network is safe to tear down at this moment. + * Check if the data network is safe to tear down at this moment. A network is considered safe + * to tear down if No IMS/RCS registration is relying on it. We infer a network is Not safe to + * tear down if 1) the network is on the transport where the IMS/RCS feature registration + * took place, and 2) the network has requests originated from the IMS/RCS service. * * @param dataNetwork The data network. - * @return {@code true} if the data network is safe to tear down. {@code false} indicates this - * data network has requests originated from the IMS/RCS service and IMS/RCS is not - * de-registered yet. + * @return {@code true} if the data network is safe to tear down; {@code false} otherwise. */ private boolean isSafeToTearDown(@NonNull DataNetwork dataNetwork) { for (int imsFeature : SUPPORTED_IMS_FEATURES) { - String imsFeaturePackage = mImsFeaturePackageName.get(imsFeature); - if (imsFeaturePackage != null) { - if (dataNetwork.getAttachedNetworkRequestList() + int registeredOnTransport = mRegisteredImsFeaturesTransport.get(imsFeature, + AccessNetworkConstants.TRANSPORT_TYPE_INVALID); + if (dataNetwork.getTransport() == registeredOnTransport) { + String imsFeaturePackage = mImsFeaturePackageName.get(imsFeature); + if (imsFeaturePackage != null && dataNetwork.getAttachedNetworkRequestList() .hasNetworkRequestsFromPackage(imsFeaturePackage)) { - if (mRegisteredImsFeatures.contains(imsFeature)) { - return false; - } + return false; } } } @@ -3659,13 +3667,19 @@ public class DataNetworkController extends Handler { private void tearDownGracefully(@NonNull DataNetwork dataNetwork, @TearDownReason int reason) { long deregDelay = mDataConfigManager.getImsDeregistrationDelay(); if (isImsGracefulTearDownSupported() && !isSafeToTearDown(dataNetwork)) { + int mmtelTransport = mRegisteredImsFeaturesTransport.get(ImsFeature.FEATURE_MMTEL, + AccessNetworkConstants.TRANSPORT_TYPE_INVALID); + int rcsTransport = mRegisteredImsFeaturesTransport.get(ImsFeature.FEATURE_RCS, + AccessNetworkConstants.TRANSPORT_TYPE_INVALID); log("tearDownGracefully: Not safe to tear down " + dataNetwork + " at this point. Wait for IMS de-registration or timeout. MMTEL=" - + (mRegisteredImsFeatures.contains(ImsFeature.FEATURE_MMTEL) - ? "registered" : "not registered") + + (mmtelTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID + ? "registered on " + AccessNetworkConstants.transportTypeToString( + mmtelTransport) : "not registered") + ", RCS=" - + (mRegisteredImsFeatures.contains(ImsFeature.FEATURE_RCS) - ? "registered" : "not registered") + + (rcsTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID + ? "registered on " + AccessNetworkConstants.transportTypeToString( + rcsTransport) : "not registered") ); Runnable runnable = dataNetwork.tearDownWhenConditionMet(reason, deregDelay); if (runnable != null) { @@ -3778,13 +3792,18 @@ public class DataNetworkController extends Handler { pw.println(networkRequest); } pw.decreaseIndent(); - + int mmtelTransport = mRegisteredImsFeaturesTransport.get(ImsFeature.FEATURE_MMTEL, + AccessNetworkConstants.TRANSPORT_TYPE_INVALID); + int rcsTransport = mRegisteredImsFeaturesTransport.get(ImsFeature.FEATURE_RCS, + AccessNetworkConstants.TRANSPORT_TYPE_INVALID); pw.println("IMS features registration state: MMTEL=" - + (mRegisteredImsFeatures.contains(ImsFeature.FEATURE_MMTEL) - ? "registered" : "not registered") + + (mmtelTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID + ? "registered on " + AccessNetworkConstants.transportTypeToString( + mmtelTransport) : "not registered") + ", RCS=" - + (mRegisteredImsFeatures.contains(ImsFeature.FEATURE_RCS) - ? "registered" : "not registered")); + + (rcsTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID + ? "registered on " + AccessNetworkConstants.transportTypeToString( + rcsTransport) : "not registered")); pw.println("mServiceState=" + mServiceState); pw.println("mPsRestricted=" + mPsRestricted); pw.println("mAnyDataNetworkExisting=" + mAnyDataNetworkExisting); 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 de1056392f..0dded1247a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -480,13 +480,14 @@ public class DataNetworkControllerTest extends TelephonyTest { processAllMessages(); } - private void setImsRegistered(boolean registered) { + private void setImsRegistered(boolean registered, + @ImsRegistrationImplBase.ImsRegistrationTech int regTech) { if (registered) { final ArraySet features = new ArraySet<>(); features.add("feature1"); features.add("feature2"); - ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder( - ImsRegistrationImplBase.REGISTRATION_TECH_LTE).setFeatureTags(features).build(); + ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(regTech) + .setFeatureTags(features).build(); mMmtelRegCallback.onRegistered(attr); } else { @@ -495,13 +496,14 @@ public class DataNetworkControllerTest extends TelephonyTest { } } - private void setRcsRegistered(boolean registered) { + private void setRcsRegistered(boolean registered, + @ImsRegistrationImplBase.ImsRegistrationTech int regTech) { if (registered) { final ArraySet features = new ArraySet<>(); features.add("feature1"); features.add("feature2"); - ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder( - ImsRegistrationImplBase.REGISTRATION_TECH_LTE).setFeatureTags(features).build(); + ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(regTech) + .setFeatureTags(features).build(); mRcsRegCallback.onRegistered(attr); } else { @@ -3459,9 +3461,14 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testImsGracefulTearDown() throws Exception { - setImsRegistered(true); - setRcsRegistered(true); + setImsRegistered(true, ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); + setRcsRegistered(true, ImsRegistrationImplBase.REGISTRATION_TECH_LTE); + // IMS preferred on Wifi + updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + + // IMS service requests an IMS network, expects the network on IWLAN. NetworkCapabilities netCaps = new NetworkCapabilities(); netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); netCaps.setRequestorPackageName(FAKE_MMTEL_PACKAGE); @@ -3471,34 +3478,53 @@ public class DataNetworkControllerTest extends TelephonyTest { TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest( nativeNetworkRequest, mPhone); + mDataNetworkControllerUT.addNetworkRequest(networkRequest); + setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 2/*cid*/); + + // IMS service requests an internet network, expects the network on WWAN. + netCaps = new NetworkCapabilities(); + netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + netCaps.setRequestorPackageName(FAKE_MMTEL_PACKAGE); + + nativeNetworkRequest = new NetworkRequest(netCaps, + ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); + networkRequest = new TelephonyNetworkRequest( + nativeNetworkRequest, mPhone); + mDataNetworkControllerUT.addNetworkRequest(networkRequest); processAllMessages(); Mockito.clearInvocations(mPhone); - // SIM removal - mDataNetworkControllerUT.obtainMessage(9/*EVENT_SIM_STATE_CHANGED*/, - TelephonyManager.SIM_STATE_ABSENT, 0).sendToTarget(); + List networks = getDataNetworks(); + assertEquals(2, networks.size()); + + // Turn on APM mode. + mDataNetworkControllerUT.onTearDownAllDataNetworks(DataNetwork + .TEAR_DOWN_REASON_AIRPLANE_MODE_ON); processAllMessages(); - // Make sure data network enters disconnecting state - ArgumentCaptor pdcsCaptor = - ArgumentCaptor.forClass(PreciseDataConnectionState.class); - verify(mPhone).notifyDataConnection(pdcsCaptor.capture()); - PreciseDataConnectionState pdcs = pdcsCaptor.getValue(); - assertThat(pdcs.getState()).isEqualTo(TelephonyManager.DATA_DISCONNECTING); + // Expect the network on WWAN immediately disconnected because IMS registration is on IWLAN. + assertEquals(1, networks.size()); + DataNetwork network = networks.get(0); + // Expect the network on IWLAN enters disconnecting state as part of waiting for dereg. + assertTrue(network.getNetworkCapabilities().hasCapability(NetworkCapabilities + .NET_CAPABILITY_IMS)); + assertTrue(network.isDisconnecting()); // IMS de-registered. Now data network is safe to be torn down. Mockito.clearInvocations(mPhone); - setImsRegistered(false); - setRcsRegistered(false); + setImsRegistered(false, ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); + setRcsRegistered(false, ImsRegistrationImplBase.REGISTRATION_TECH_LTE); processAllMessages(); // All data should be disconnected. verifyAllDataDisconnected(); verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); + ArgumentCaptor pdcsCaptor = + ArgumentCaptor.forClass(PreciseDataConnectionState.class); verify(mPhone).notifyDataConnection(pdcsCaptor.capture()); - pdcs = pdcsCaptor.getValue(); + PreciseDataConnectionState pdcs = pdcsCaptor.getValue(); assertThat(pdcs.getState()).isEqualTo(TelephonyManager.DATA_DISCONNECTED); } -- GitLab From 381dccc731809913a39dfa7cefb6c7ff8a1ce027 Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Wed, 15 Feb 2023 13:10:15 +0000 Subject: [PATCH 508/656] [ProxyController]Wake Lock Issue during setRadioCapability error case -Avoid ignoring the session at onStartRadioCapabilityResponse() when there is exception -Avoid ignoring the session at onFinishRadioCapabilityResponse() when there is exception Bug: 269174024 Test: build,device & atest Change-Id: Ia7162d9c50461600b8a8d8b9b0febbf0f6a7a52c (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:98ea73acea86fb34a7ff1e58bc59205651696f61) Merged-In: Ia7162d9c50461600b8a8d8b9b0febbf0f6a7a52c --- .../internal/telephony/ProxyController.java | 44 ++++-- .../telephony/ProxyControllerTest.java | 136 +++++++++++++++++- 2 files changed, 163 insertions(+), 17 deletions(-) diff --git a/src/java/com/android/internal/telephony/ProxyController.java b/src/java/com/android/internal/telephony/ProxyController.java index 498953c6e0..ed9982e565 100644 --- a/src/java/com/android/internal/telephony/ProxyController.java +++ b/src/java/com/android/internal/telephony/ProxyController.java @@ -47,8 +47,10 @@ public class ProxyController { @VisibleForTesting static final int EVENT_START_RC_RESPONSE = 2; private static final int EVENT_APPLY_RC_RESPONSE = 3; - private static final int EVENT_FINISH_RC_RESPONSE = 4; - private static final int EVENT_TIMEOUT = 5; + @VisibleForTesting + public static final int EVENT_FINISH_RC_RESPONSE = 4; + @VisibleForTesting + public static final int EVENT_TIMEOUT = 5; @VisibleForTesting public static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 6; @@ -212,6 +214,7 @@ public class ProxyController { clearTransaction(); // Keep a wake lock until we finish radio capability changed + logd("Acquiring wake lock for setting radio capability"); mWakeLock.acquire(); return doSetRadioCapabilities(rafs); @@ -357,19 +360,25 @@ public class ProxyController { } } RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; - if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { + // Added exception condition to continue to mark as transaction fail case. + // Checking session validity during exception is not valid + if (ar.exception == null + && ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId))) { logd("onStartRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId + " rc=" + rc); return; } mRadioAccessFamilyStatusCounter--; - int id = rc.getPhoneId(); + //rc.getPhoneId() moved to avoid Null Pointer Exception, since when exception occurs + //its expected rc is null. if (ar.exception != null) { - logd("onStartRadioCapabilityResponse: Error response session=" + rc.getSession()); - logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=FAIL"); - mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; + logd("onStartRadioCapabilityResponse got exception=" + ar.exception); + //mSetRadioAccessFamilyStatus will be set anyway to SET_RC_STATUS_FAIL + // if either of them fail at issueFinish() method below,i.e. both phone id count + // is set to SET_RC_STATUS_FAIL. mTransactionFailed = true; } else { + int id = rc.getPhoneId(); logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=STARTED"); mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_STARTED; } @@ -481,13 +490,20 @@ public class ProxyController { * @param msg obj field isa RadioCapability */ void onFinishRadioCapabilityResponse(Message msg) { - RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; - if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { - logd("onFinishRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId - + " rc=" + rc); - return; - } synchronized (mSetRadioAccessFamilyStatus) { + AsyncResult ar = (AsyncResult) msg.obj; + RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; + // Added exception condition on finish to continue to revert if exception occurred. + // Checking session validity during exception is not valid + if (ar.exception == null + && ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId))) { + logd("onFinishRadioCapabilityResponse: Ignore session=" + + mRadioCapabilitySessionId + " rc=" + rc); + return; + } + if (ar.exception != null) { + logd("onFinishRadioCapabilityResponse got exception=" + ar.exception); + } logd(" onFinishRadioCapabilityResponse mRadioAccessFamilyStatusCounter=" + mRadioAccessFamilyStatusCounter); mRadioAccessFamilyStatusCounter--; @@ -575,7 +591,6 @@ public class ProxyController { clearTransaction(); } else { intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_FAILED); - // now revert. mTransactionFailed = false; RadioAccessFamily[] rafs = new RadioAccessFamily[mPhones.length]; @@ -602,6 +617,7 @@ public class ProxyController { } if (isWakeLockHeld()) { + logd("clearTransaction:checking wakelock held and releasing"); mWakeLock.release(); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java index c0d497d98b..65ab66494d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ProxyControllerTest.java @@ -19,10 +19,13 @@ package com.android.internal.telephony; import static android.telephony.RadioAccessFamily.RAF_GSM; import static android.telephony.RadioAccessFamily.RAF_LTE; +import static com.android.internal.telephony.ProxyController.EVENT_FINISH_RC_RESPONSE; import static com.android.internal.telephony.ProxyController.EVENT_MULTI_SIM_CONFIG_CHANGED; import static com.android.internal.telephony.ProxyController.EVENT_START_RC_RESPONSE; +import static com.android.internal.telephony.ProxyController.EVENT_TIMEOUT; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; @@ -97,12 +100,139 @@ public class ProxyControllerTest extends TelephonyTest { rafs[1] = new RadioAccessFamily(1, RAF_GSM | RAF_LTE); mProxyController.setRadioCapability(rafs); - Message.obtain(mProxyController.mHandler, EVENT_START_RC_RESPONSE, - new AsyncResult(null, null, - new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED))) + Message.obtain( + mProxyController.mHandler, + EVENT_START_RC_RESPONSE, + new AsyncResult( + null, + null, + new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED))) .sendToTarget(); processAllMessages(); assertFalse(mProxyController.isWakeLockHeld()); } + + @Test + @SmallTest + public void testWithNonPermanentExceptionOnRCResponse_WithExceptionOnFinishResponse() + throws Exception { + int activeModemCount = 2; + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone, mPhone2}); + doReturn(activeModemCount).when(mTelephonyManager).getPhoneCount(); + doReturn(RAF_GSM | RAF_LTE).when(mPhone).getRadioAccessFamily(); + doReturn(RAF_GSM).when(mPhone2).getRadioAccessFamily(); + + Message.obtain(mProxyController.mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED).sendToTarget(); + processAllMessages(); + verify(mPhone2).registerForRadioCapabilityChanged(any(), anyInt(), any()); + + RadioAccessFamily[] rafs = new RadioAccessFamily[activeModemCount]; + rafs[0] = new RadioAccessFamily(0, RAF_GSM); + rafs[1] = new RadioAccessFamily(1, RAF_GSM | RAF_LTE); + mProxyController.setRadioCapability(rafs); + + Message.obtain( + mProxyController.mHandler, + EVENT_START_RC_RESPONSE, + new AsyncResult( + null, + null, + new CommandException(CommandException.Error.RADIO_NOT_AVAILABLE))) + .sendToTarget(); + processAllMessages(); + assertTrue(mProxyController.isWakeLockHeld()); + onFinishResponseWithException(); + } + + @Test + @SmallTest + public void testWithNonPermanentExceptionOnRCResponse_WithoutExceptionOnFinishResponse() + throws Exception { + int activeModemCount = 2; + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone, mPhone2}); + doReturn(activeModemCount).when(mTelephonyManager).getPhoneCount(); + doReturn(RAF_GSM | RAF_LTE).when(mPhone).getRadioAccessFamily(); + doReturn(RAF_GSM).when(mPhone2).getRadioAccessFamily(); + + Message.obtain(mProxyController.mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED).sendToTarget(); + processAllMessages(); + verify(mPhone2).registerForRadioCapabilityChanged(any(), anyInt(), any()); + + RadioAccessFamily[] rafs = new RadioAccessFamily[activeModemCount]; + rafs[0] = new RadioAccessFamily(0, RAF_GSM); + rafs[1] = new RadioAccessFamily(1, RAF_GSM | RAF_LTE); + mProxyController.setRadioCapability(rafs); + + Message.obtain( + mProxyController.mHandler, + EVENT_START_RC_RESPONSE, + new AsyncResult(null, null, null)) + .sendToTarget(); + processAllMessages(); + assertTrue(mProxyController.isWakeLockHeld()); + onFinishResponseWithoutException(); + } + + @Test + @SmallTest + public void testOnRCResponseTimeout_WithExceptionOnFinishResponse() throws Exception { + int activeModemCount = 2; + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone, mPhone2}); + doReturn(activeModemCount).when(mTelephonyManager).getPhoneCount(); + doReturn(RAF_GSM | RAF_LTE).when(mPhone).getRadioAccessFamily(); + doReturn(RAF_GSM).when(mPhone2).getRadioAccessFamily(); + + Message.obtain(mProxyController.mHandler, EVENT_MULTI_SIM_CONFIG_CHANGED).sendToTarget(); + processAllMessages(); + verify(mPhone2).registerForRadioCapabilityChanged(any(), anyInt(), any()); + + RadioAccessFamily[] rafs = new RadioAccessFamily[activeModemCount]; + rafs[0] = new RadioAccessFamily(0, RAF_GSM); + rafs[1] = new RadioAccessFamily(1, RAF_GSM | RAF_LTE); + mProxyController.setRadioCapability(rafs); + + Message.obtain( + mProxyController.mHandler, + EVENT_TIMEOUT, + new AsyncResult( + null, + null, + new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED))) + .sendToTarget(); + processAllMessages(); + onFinishResponseWithException(); + } + + private void onFinishResponseWithException() throws Exception { + replaceInstance( + ProxyController.class, "mRadioAccessFamilyStatusCounter", mProxyController, 1); + replaceInstance(ProxyController.class, "mTransactionFailed", mProxyController, true); + Message.obtain( + mProxyController.mHandler, + EVENT_FINISH_RC_RESPONSE, + new AsyncResult( + null, + null, + new CommandException(CommandException.Error.REQUEST_NOT_SUPPORTED))) + .sendToTarget(); + processAllMessages(); + assertTrue(mProxyController.isWakeLockHeld()); + } + + private void onFinishResponseWithoutException() throws Exception { + replaceInstance( + ProxyController.class, "mRadioAccessFamilyStatusCounter", mProxyController, 1); + replaceInstance(ProxyController.class, "mTransactionFailed", mProxyController, false); + replaceInstance( + ProxyController.class, "mRadioCapabilitySessionId", mProxyController, 123456); + Message.obtain( + mProxyController.mHandler, + EVENT_FINISH_RC_RESPONSE, + new AsyncResult( + null, new RadioCapability(0, 123456, 0, 0, "test_modem", 0), null)) + .sendToTarget(); + processAllMessages(); + assertFalse(mProxyController.isWakeLockHeld()); + } } -- GitLab From a9dc8b5027c667bc75b3fc55409c8eceb4e15707 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 9 Mar 2023 10:49:26 -0800 Subject: [PATCH 509/656] Changed the log tag Changed the log tag to avoid collision of other modules. Test: Build Fix: 272534174 Change-Id: I6e24c289abbe4a77f9afdf7f3d7b0c81388f9b8e --- .../telephony/subscription/SubscriptionDatabaseManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 263fbe545c..bc17f50cf9 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -81,7 +81,7 @@ import java.util.stream.Collectors; * to the database should go through {@link SubscriptionManagerService}. */ public class SubscriptionDatabaseManager extends Handler { - private static final String LOG_TAG = "SDM"; + private static final String LOG_TAG = "SDMGR"; /** Whether enabling verbose debugging message or not. */ private static final boolean VDBG = false; -- GitLab From 2444b3c6df39040ca701f1e389a8e1dd81d35c52 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 9 Mar 2023 14:58:43 -0800 Subject: [PATCH 510/656] Fixed remote SIM removal not working When remote SIM is removed, it should be also removed from the slot/sub mapping table. Fix: 271902906 Test: atest SubscriptionManagerServiceTest Test: Basic phone functionality tests Change-Id: I547024e1390fbc868bc7460bef1f19025a4d1cc5 --- .../SubscriptionManagerService.java | 18 ++++--- .../SubscriptionDatabaseManagerTest.java | 3 ++ .../SubscriptionManagerServiceTest.java | 48 +++++++++++++++++-- 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 7f3c23fd04..6d82c14abd 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -233,7 +233,7 @@ public class SubscriptionManagerService extends ISub.Stub { /** The slot index subscription id map. Key is the slot index, and the value is sub id. */ @NonNull - private final WatchedMap mSlotIndexToSubId = new WatchedMap<>(); + private final SubscriptionMap mSlotIndexToSubId = new SubscriptionMap<>(); /** Subscription manager service callbacks. */ @NonNull @@ -264,9 +264,10 @@ public class SubscriptionManagerService extends ISub.Stub { private final int[] mSimState; /** - * Watched map that automatically invalidate cache in {@link SubscriptionManager}. + * Slot index/subscription map that automatically invalidate cache in + * {@link SubscriptionManager}. */ - private static class WatchedMap extends ConcurrentHashMap { + private static class SubscriptionMap extends ConcurrentHashMap { @Override public void clear() { super.clear(); @@ -1946,10 +1947,11 @@ public class SubscriptionManagerService extends ISub.Stub { @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public int addSubInfo(@NonNull String iccId, @NonNull String displayName, int slotIndex, @SubscriptionType int subscriptionType) { - log("addSubInfo: iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + ", slotIndex=" - + slotIndex + ", displayName=" + displayName + ", type=" - + SubscriptionManager.subscriptionTypeToString(subscriptionType)); enforcePermissions("addSubInfo", Manifest.permission.MODIFY_PHONE_STATE); + logl("addSubInfo: iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + ", slotIndex=" + + slotIndex + ", displayName=" + displayName + ", type=" + + SubscriptionManager.subscriptionTypeToString(subscriptionType) + ", " + + getCallingPackage()); // Now that all security checks passes, perform the operation as ourselves. final long identity = Binder.clearCallingIdentity(); @@ -2004,6 +2006,9 @@ public class SubscriptionManagerService extends ISub.Stub { public int removeSubInfo(@NonNull String uniqueId, int subscriptionType) { enforcePermissions("removeSubInfo", Manifest.permission.MODIFY_PHONE_STATE); + logl("removeSubInfo: uniqueId=" + SubscriptionInfo.givePrintableIccid(uniqueId) + ", " + + SubscriptionManager.subscriptionTypeToString(subscriptionType) + ", " + + getCallingPackage()); final long identity = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager @@ -2016,6 +2021,7 @@ public class SubscriptionManagerService extends ISub.Stub { loge("The subscription type does not match."); return -1; } + mSlotIndexToSubId.remove(subInfo.getSimSlotIndex()); mSubscriptionDatabaseManager.removeSubscriptionInfo(subInfo.getSubscriptionId()); return 0; } finally { 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 d3b8ab37bc..4ad29b52c0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -114,6 +114,9 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { static final int FAKE_USER_ID1 = 10; static final int FAKE_USER_ID2 = 11; + static final String FAKE_MAC_ADDRESS1 = "DC:E5:5B:38:7D:40"; + static final String FAKE_MAC_ADDRESS2 = "DC:B5:4F:47:F3:4C"; + static final SubscriptionInfoInternal FAKE_SUBSCRIPTION_INFO1 = new SubscriptionInfoInternal.Builder() .setId(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 ae4bc4a493..9be52f8707 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -28,6 +28,8 @@ import static com.android.internal.telephony.subscription.SubscriptionDatabaseMa import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_IMSI1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MAC_ADDRESS1; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MAC_ADDRESS2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MCC1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MCC2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_MNC1; @@ -251,8 +253,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // Insertion is sync, but the onSubscriptionChanged callback is handled by the handler. processAllMessages(); - Class WatchedMapClass = Class.forName("com.android.internal.telephony.subscription" - + ".SubscriptionManagerService$WatchedMap"); + Class SubscriptionMapClass = Class.forName( + "com.android.internal.telephony.subscription" + + ".SubscriptionManagerService$SubscriptionMap"); Field field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); field.setAccessible(true); Object map = field.get(mSubscriptionManagerServiceUT); @@ -262,7 +265,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { if (subInfo.getSimSlotIndex() >= 0) { // Change the slot -> subId mapping - Method method = WatchedMapClass.getDeclaredMethod("put", cArgs); + Method method = SubscriptionMapClass.getDeclaredMethod("put", cArgs); method.setAccessible(true); method.invoke(map, subInfo.getSimSlotIndex(), subId); } @@ -1745,6 +1748,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList( CALLING_PACKAGE, CALLING_FEATURE).isEmpty()).isTrue(); + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); } @Test @@ -2046,4 +2051,41 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfo.isActive()).isFalse(); assertThat(subInfo.areUiccApplicationsEnabled()).isFalse(); } + + @Test + public void testRemoteSim() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + + mSubscriptionManagerServiceUT.addSubInfo(FAKE_MAC_ADDRESS1, FAKE_CARRIER_NAME1, + 0, SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); + processAllMessages(); + + verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo.getIccId()).isEqualTo(FAKE_MAC_ADDRESS1); + assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_CARRIER_NAME1); + assertThat(subInfo.getSimSlotIndex()).isEqualTo(0); + assertThat(subInfo.getSubscriptionType()).isEqualTo( + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); + + assertThat(mSubscriptionManagerServiceUT.removeSubInfo(FAKE_MAC_ADDRESS1, + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM)).isEqualTo(0); + assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList( + CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); + assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty(); + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); + + setIdentifierAccess(true); + mSubscriptionManagerServiceUT.addSubInfo(FAKE_MAC_ADDRESS2, FAKE_CARRIER_NAME2, + 0, SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); + assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isNotEmpty(); + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE)).isNotEmpty(); + assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE).get(0).getIccId()).isEqualTo(FAKE_MAC_ADDRESS2); + } } -- GitLab From f0e973d9db2b5631c6379b81cd97d59321513d75 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 10 Mar 2023 20:51:23 -0800 Subject: [PATCH 511/656] Moved UICC application enabled callback Moved UICC application enabled callback triggering logic from SubscriptionDatabaseManager to SubscriptionManagerService. Bug: 271642122 Test: Turn on/off SIM through UX many times and did not see issues. Test: atest SubscriptionManagerServiceTest Change-Id: I89d1d6a1decc774f84a44a6ba97d45253e5a1bc9 --- .../internal/telephony/GsmCdmaPhone.java | 5 ++- .../SubscriptionDatabaseManager.java | 16 --------- .../SubscriptionManagerService.java | 34 ++++++++----------- .../SubscriptionManagerServiceTest.java | 14 ++++++-- 4 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 87e88b4be9..1ff3593dcb 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -373,7 +373,7 @@ public class GsmCdmaPhone extends Phone { mSubscriptionManagerService.registerCallback(new SubscriptionManagerServiceCallback( this::post) { @Override - public void onUiccApplicationsEnabled(int subId) { + public void onUiccApplicationsEnabledChanged(int subId) { reapplyUiccAppsEnablementIfNeeded(ENABLE_UICC_APPS_MAX_RETRIES); } }); @@ -4471,6 +4471,7 @@ public class GsmCdmaPhone extends Phone { " mTelecomVoiceServiceStateOverride=" + mTelecomVoiceServiceStateOverride + "(" + ServiceState.rilServiceStateToString(mTelecomVoiceServiceStateOverride) + ")"); + pw.println(" mUiccApplicationsEnabled=" + mUiccApplicationsEnabled); pw.flush(); try { mCallWaitingController.dump(pw); @@ -4883,6 +4884,8 @@ public class GsmCdmaPhone extends Phone { // If no card is present or we don't have mUiccApplicationsEnabled yet, do nothing. if (slot == null || slot.getCardState() != IccCardStatus.CardState.CARDSTATE_PRESENT || mUiccApplicationsEnabled == null) { + loge("reapplyUiccAppsEnablementIfNeeded: slot state=" + + (slot != null ? slot.getCardState() : null)); return; } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index bc17f50cf9..dfc94cd5a8 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -553,14 +553,6 @@ public class SubscriptionDatabaseManager extends Handler { * @param subId The subscription id. */ public abstract void onSubscriptionChanged(int subId); - - /** - * Called when {@link SubscriptionInfoInternal#areUiccApplicationsEnabled()} - * changed. - * - * @param subId The subscription id. - */ - public abstract void onUiccApplicationsEnabled(int subId); } /** @@ -918,10 +910,6 @@ public class SubscriptionDatabaseManager extends Handler { mAllSubscriptionInfoInternalCache.put(id, builder.build()); mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); - if (columnName.equals(SimInfo.COLUMN_UICC_APPLICATIONS_ENABLED)) { - mCallback.invokeFromExecutor(() - -> mCallback.onUiccApplicationsEnabled(subId)); - } } } } @@ -956,10 +944,6 @@ public class SubscriptionDatabaseManager extends Handler { if (updateDatabase(subId, createDeltaContentValues(oldSubInfo, newSubInfo)) > 0) { mAllSubscriptionInfoInternalCache.put(subId, newSubInfo); mCallback.invokeFromExecutor(() -> mCallback.onSubscriptionChanged(subId)); - if (oldSubInfo.areUiccApplicationsEnabled() - != newSubInfo.areUiccApplicationsEnabled()) { - mCallback.invokeFromExecutor(() -> mCallback.onUiccApplicationsEnabled(subId)); - } } } finally { mReadWriteLock.writeLock().unlock(); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 7f3c23fd04..467ca32c1e 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -378,7 +378,7 @@ public class SubscriptionManagerService extends ISub.Stub { * * @param subId The subscription id. */ - public void onUiccApplicationsEnabled(int subId) {} + public void onUiccApplicationsEnabledChanged(int subId) {} } /** DeviceConfig key for whether work profile telephony feature is enabled. */ @@ -514,23 +514,6 @@ public class SubscriptionManagerService extends ISub.Stub { && telephonyRegistryManager != null) { telephonyRegistryManager.notifyOpportunisticSubscriptionInfoChanged(); } - - // TODO: Call TelephonyMetrics.updateActiveSubscriptionInfoList when active - // subscription changes. - } - - /** - * Called when {@link SubscriptionInfoInternal#areUiccApplicationsEnabled()} - * changed. - * - * @param subId The subscription id. - */ - @Override - public void onUiccApplicationsEnabled(int subId) { - log("onUiccApplicationsEnabled: subId=" + subId); - mSubscriptionManagerServiceCallbacks.forEach( - callback -> callback.invokeFromExecutor( - () -> callback.onUiccApplicationsEnabled(subId))); } }); @@ -3193,7 +3176,20 @@ public class SubscriptionManagerService extends ISub.Stub { final long identity = Binder.clearCallingIdentity(); try { - mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, enabled); + + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId); + if (subInfo == null) { + throw new IllegalArgumentException("setUiccApplicationsEnabled: Subscription " + + "doesn't exist. subId=" + subId); + } + + if (subInfo.areUiccApplicationsEnabled() != enabled) { + mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, enabled); + mSubscriptionManagerServiceCallbacks.forEach( + callback -> callback.invokeFromExecutor( + () -> callback.onUiccApplicationsEnabledChanged(subId))); + } } finally { Binder.restoreCallingIdentity(identity); } 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 ae4bc4a493..2809c75197 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -56,6 +56,7 @@ import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -1256,11 +1257,20 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mSubscriptionManagerServiceUT.setUiccApplicationsEnabled(false, 1); processAllMessages(); verify(mMockedSubscriptionManagerServiceCallback).onSubscriptionChanged(eq(1)); + verify(mMockedSubscriptionManagerServiceCallback).onUiccApplicationsEnabledChanged(eq(1)); SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT .getSubscriptionInfoInternal(1); assertThat(subInfo).isNotNull(); assertThat(subInfo.areUiccApplicationsEnabled()).isFalse(); + + Mockito.clearInvocations(mMockedSubscriptionManagerServiceCallback); + mSubscriptionManagerServiceUT.setUiccApplicationsEnabled(false, 1); + processAllMessages(); + + verify(mMockedSubscriptionManagerServiceCallback, never()).onSubscriptionChanged(eq(1)); + verify(mMockedSubscriptionManagerServiceCallback, never()) + .onUiccApplicationsEnabledChanged(eq(1)); } @Test @@ -2015,9 +2025,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { SubscriptionManagerServiceCallback callback = new SubscriptionManagerServiceCallback(Runnable::run) { @Override - public void onUiccApplicationsEnabled(int subId) { + public void onUiccApplicationsEnabledChanged(int subId) { latch.countDown(); - logd("testOnSubscriptionChanged: onUiccApplicationsEnabled"); + logd("testOnSubscriptionChanged: onUiccApplicationsEnabledChanged"); } }; mSubscriptionManagerServiceUT.registerCallback(callback); -- GitLab From 7b74471ccc901c639a0a04bca464c0dd0b806d88 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 11 Mar 2023 16:55:32 -0800 Subject: [PATCH 512/656] Added unit tests Added unit tests for SubscriptionDatabaseManager and SubscriptionManagerService Bug: 272989110 Test: atest SubscriptionDatabaseManagerTest SubscriptionManagerServiceTest Change-Id: I8752aea9d1f792a5cbbbbd5d2ca7424f731c6320 --- .../SubscriptionManagerService.java | 17 ++-- .../SubscriptionDatabaseManagerTest.java | 36 +++++++ .../SubscriptionManagerServiceTest.java | 95 +++++++++++++++++-- 3 files changed, 127 insertions(+), 21 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 22f72e91e3..24237cb122 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -266,8 +266,12 @@ public class SubscriptionManagerService extends ISub.Stub { /** * Slot index/subscription map that automatically invalidate cache in * {@link SubscriptionManager}. + * + * @param The type of the key. + * @param The type of the value. */ - private static class SubscriptionMap extends ConcurrentHashMap { + @VisibleForTesting + public static class SubscriptionMap extends ConcurrentHashMap { @Override public void clear() { super.clear(); @@ -2989,7 +2993,7 @@ public class SubscriptionManagerService extends ISub.Stub { + columnName); } } catch (IllegalArgumentException e) { - logv("getSubscriptionProperty: Invalid subId " + subId + ", columnName=" + columnName); + loge("getSubscriptionProperty: Invalid subId " + subId + ", columnName=" + columnName); return null; } finally { Binder.restoreCallingIdentity(token); @@ -3898,15 +3902,6 @@ public class SubscriptionManagerService extends ISub.Stub { Rlog.e(LOG_TAG, s); } - /** - * Log verbose messages. - * - * @param s debug messages. - */ - private void logv(@NonNull String s) { - if (VDBG) Rlog.v(LOG_TAG, s); - } - /** * Log debug messages and also log into the local log. * 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 4ad29b52c0..d23c96bee2 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -63,6 +63,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -1673,4 +1675,38 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(3)).isNull(); verify(mSubscriptionDatabaseManagerCallback).onSubscriptionChanged(eq(3)); } + + @Test + public void testCallback() { + CountDownLatch latch = new CountDownLatch(2); + Executor executor = Runnable::run; + SubscriptionDatabaseManagerCallback callback = + new SubscriptionDatabaseManagerCallback(executor) { + @Override + public void onInitialized() { + latch.countDown(); + logd("onInitialized"); + } + + @Override + public void onSubscriptionChanged(int subId) { + latch.countDown(); + logd("onSubscriptionChanged"); + } + }; + assertThat(callback.getExecutor()).isEqualTo(executor); + mDatabaseManagerUT = new SubscriptionDatabaseManager(mContext, Looper.myLooper(), callback); + processAllMessages(); + + assertThat(latch.getCount()).isEqualTo(1); + + mDatabaseManagerUT.insertSubscriptionInfo( + new SubscriptionInfoInternal.Builder() + .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID) + .setIccId(FAKE_ICCID1) + .setSimSlotIndex(0) + .build()); + processAllMessages(); + assertThat(latch.getCount()).isEqualTo(0); + } } 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 5244b31064..2a355f599d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -102,6 +102,7 @@ import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; +import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionMap; import com.android.internal.telephony.uicc.UiccSlot; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; @@ -120,11 +121,11 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Array; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -134,6 +135,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { private static final String CALLING_FEATURE = "calling_feature"; + private static final String GROUP_UUID = "6adbc864-691c-45dc-b698-8fc9a2176fae"; + private SubscriptionManagerService mSubscriptionManagerServiceUT; private final SubscriptionProvider mSubscriptionProvider = new SubscriptionProvider(); @@ -254,21 +257,17 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { // Insertion is sync, but the onSubscriptionChanged callback is handled by the handler. processAllMessages(); - Class SubscriptionMapClass = Class.forName( - "com.android.internal.telephony.subscription" - + ".SubscriptionManagerService$SubscriptionMap"); Field field = SubscriptionManagerService.class.getDeclaredField("mSlotIndexToSubId"); field.setAccessible(true); - Object map = field.get(mSubscriptionManagerServiceUT); + SubscriptionMap map = (SubscriptionMap) + field.get(mSubscriptionManagerServiceUT); Class[] cArgs = new Class[2]; cArgs[0] = Object.class; cArgs[1] = Object.class; if (subInfo.getSimSlotIndex() >= 0) { // Change the slot -> subId mapping - Method method = SubscriptionMapClass.getDeclaredMethod("put", cArgs); - method.setAccessible(true); - method.invoke(map, subInfo.getSimSlotIndex(), subId); + map.put(subInfo.getSimSlotIndex(), subId); } mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); @@ -1171,7 +1170,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); - ParcelUuid newUuid = ParcelUuid.fromString("6adbc864-691c-45dc-b698-8fc9a2176fae"); + ParcelUuid newUuid = ParcelUuid.fromString(GROUP_UUID); String newOwner = "new owner"; // Should fail without MODIFY_PHONE_STATE assertThrows(SecurityException.class, () -> mSubscriptionManagerServiceUT @@ -2027,14 +2026,16 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testOnUiccApplicationsEnabled() { CountDownLatch latch = new CountDownLatch(1); + Executor executor = Runnable::run; SubscriptionManagerServiceCallback callback = - new SubscriptionManagerServiceCallback(Runnable::run) { + new SubscriptionManagerServiceCallback(executor) { @Override public void onUiccApplicationsEnabledChanged(int subId) { latch.countDown(); logd("testOnSubscriptionChanged: onUiccApplicationsEnabledChanged"); } }; + assertThat(callback.getExecutor()).isEqualTo(executor); mSubscriptionManagerServiceUT.registerCallback(callback); int subId = insertSubscription(FAKE_SUBSCRIPTION_INFO1); @@ -2042,6 +2043,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mSubscriptionManagerServiceUT.setUiccApplicationsEnabled(false, subId); processAllMessages(); assertThat(latch.getCount()).isEqualTo(0); + + mSubscriptionManagerServiceUT.unregisterCallback(callback); + // without override. Nothing should happen. + callback = new SubscriptionManagerServiceCallback(Runnable::run); + mSubscriptionManagerServiceUT.registerCallback(callback); + mSubscriptionManagerServiceUT.setUiccApplicationsEnabled(true, subId); + processAllMessages(); } @Test @@ -2098,4 +2106,71 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.getActiveSubscriptionInfoList( CALLING_PACKAGE, CALLING_FEATURE).get(0).getIccId()).isEqualTo(FAKE_MAC_ADDRESS2); } + + @Test + public void testRemoveSubscriptionsFromGroup() { + testAddSubscriptionsIntoGroup(); + + mContextFixture.removeCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + assertThrows(SecurityException.class, () + -> mSubscriptionManagerServiceUT.removeSubscriptionsFromGroup(new int[]{2}, + ParcelUuid.fromString(GROUP_UUID), CALLING_PACKAGE)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + assertThrows(IllegalArgumentException.class, () + -> mSubscriptionManagerServiceUT.removeSubscriptionsFromGroup(new int[]{3}, + ParcelUuid.fromString(GROUP_UUID), CALLING_PACKAGE)); + + assertThrows(IllegalArgumentException.class, () + -> mSubscriptionManagerServiceUT.removeSubscriptionsFromGroup(new int[]{2}, + ParcelUuid.fromString("55911c5b-83ed-419d-8f9b-4e027cf09305"), CALLING_PACKAGE)); + + mSubscriptionManagerServiceUT.removeSubscriptionsFromGroup(new int[]{2}, + ParcelUuid.fromString(GROUP_UUID), CALLING_PACKAGE); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(2); + assertThat(subInfo.getGroupUuid()).isEmpty(); + assertThat(subInfo.getGroupOwner()).isEmpty(); + } + + @Test + public void testUpdateSimStateForInactivePort() { + testSetUiccApplicationsEnabled(); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + mSubscriptionManagerServiceUT.updateSimStateForInactivePort(0); + processAllMessages(); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo.areUiccApplicationsEnabled()).isTrue(); + } + + @Test + public void testRestoreAllSimSpecificSettingsFromBackup() { + assertThrows(SecurityException.class, () + -> mSubscriptionManagerServiceUT.restoreAllSimSpecificSettingsFromBackup( + new byte[0])); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + + // TODO: Briefly copy the logic from TelephonyProvider to + // SubscriptionDatabaseManagerTest.SubscriptionProvider + mSubscriptionManagerServiceUT.restoreAllSimSpecificSettingsFromBackup( + new byte[0]); + } + + @Test + public void testSubscriptionMap() { + SubscriptionMap map = new SubscriptionMap<>(); + map.put(1, 1); + assertThat(map.get(1)).isEqualTo(1); + map.put(0, 2); + assertThat(map.get(0)).isEqualTo(2); + map.remove(1); + assertThat(map.get(1)).isNull(); + map.clear(); + assertThat(map).hasSize(0); + } } -- GitLab From b7353008b79de17322f7d75aa45f69895367927e Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 11 Mar 2023 19:36:02 -0800 Subject: [PATCH 513/656] Renamed the id printing method Renamed the id printing method, which is not only for iccid. Also improved the test coverage. Bug: 272989110 Test: atest SubscriptionDatabaseManagerTest Test: Basic phone functionality Change-Id: I25d34e829e879e0b1283cd756f6e34ebacbd45d2 --- .../internal/telephony/SubscriptionController.java | 6 +++--- .../internal/telephony/SubscriptionInfoUpdater.java | 2 +- .../subscription/SubscriptionInfoInternal.java | 6 +++--- .../subscription/SubscriptionManagerService.java | 8 ++++---- .../internal/telephony/uicc/IccCardStatus.java | 2 +- .../android/internal/telephony/uicc/IccRecords.java | 4 ++-- .../internal/telephony/uicc/IccSimPortInfo.java | 2 +- .../android/internal/telephony/uicc/RuimRecords.java | 2 +- .../android/internal/telephony/uicc/SIMRecords.java | 2 +- .../internal/telephony/uicc/UiccController.java | 2 +- .../android/internal/telephony/uicc/UiccPort.java | 2 +- .../android/internal/telephony/uicc/UiccProfile.java | 2 +- .../android/internal/telephony/uicc/UiccSlot.java | 2 +- .../internal/telephony/uicc/euicc/EuiccPort.java | 4 ++-- .../SubscriptionDatabaseManagerTest.java | 12 ++++++++++++ .../subscription/SubscriptionInfoInternalTest.java | 1 + 16 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index 3466b990ed..a88fd0bb86 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -828,7 +828,7 @@ public class SubscriptionController extends ISub.Stub { if (iccId.equals(si.getIccId())) { if (DBG) logd("[getActiveSubInfoUsingIccId]+ iccId=" - + SubscriptionInfo.givePrintableIccid(iccId) + + SubscriptionInfo.getPrintableId(iccId) + " subInfo=" + si); return si; } @@ -836,7 +836,7 @@ public class SubscriptionController extends ISub.Stub { } if (DBG) { logd("[getActiveSubInfoUsingIccId]+ iccId=" - + SubscriptionInfo.givePrintableIccid(iccId) + + SubscriptionInfo.getPrintableId(iccId) + " subList=" + subList + " subInfo=null"); } } finally { @@ -1330,7 +1330,7 @@ public class SubscriptionController extends ISub.Stub { if (DBG) { String iccIdStr = uniqueId; if (!isSubscriptionForRemoteSim(subscriptionType)) { - iccIdStr = SubscriptionInfo.givePrintableIccid(uniqueId); + iccIdStr = SubscriptionInfo.getPrintableId(uniqueId); } logdl("[addSubInfoRecord]+ iccid: " + iccIdStr + ", slotIndex: " + slotIndex diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java index 3b0c822419..48d2a8e02f 100644 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java @@ -852,7 +852,7 @@ public class SubscriptionInfoUpdater extends Handler { // If SIM is not absent, insert new record or update existing record. if (!ICCID_STRING_FOR_NO_SIM.equals(sIccId[phoneId]) && sIccId[phoneId] != null) { logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: " - + SubscriptionInfo.givePrintableIccid(sIccId[phoneId]) + + SubscriptionInfo.getPrintableId(sIccId[phoneId]) + ", phoneId:" + phoneId); mSubscriptionManager.addSubscriptionInfoRecord(sIccId[phoneId], phoneId); } diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 30c0e42733..9fcb453215 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -1067,7 +1067,7 @@ public class SubscriptionInfoInternal { @Override public String toString() { return "[SubscriptionInfoInternal: id=" + mId - + " iccId=" + givePrintableId(mIccId) + + " iccId=" + SubscriptionInfo.getPrintableId(mIccId) + " simSlotIndex=" + mSimSlotIndex + " portIndex=" + mPortIndex + " isEmbedded=" + mIsEmbedded @@ -1087,7 +1087,7 @@ public class SubscriptionInfoInternal { + " mnc=" + mMnc + " ehplmns=" + mEhplmns + " hplmns=" + mHplmns - + " cardString=" + givePrintableId(mCardString) + + " cardString=" + SubscriptionInfo.getPrintableId(mCardString) + " cardId=" + mCardId + " nativeAccessRules=" + IccUtils.bytesToHexString(mNativeAccessRules) + " carrierConfigAccessRules=" + IccUtils.bytesToHexString( @@ -1105,7 +1105,7 @@ public class SubscriptionInfoInternal { + " wifiCallingModeForRoaming=" + ImsMmTelManager.wifiCallingModeToString(mWifiCallingModeForRoaming) + " enabledMobileDataPolicies=" + mEnabledMobileDataPolicies - + " imsi=" + givePrintableId(mImsi) + + " imsi=" + SubscriptionInfo.getPrintableId(mImsi) + " rcsUceEnabled=" + mIsRcsUceEnabled + " crossSimCallingEnabled=" + mIsCrossSimCallingEnabled + " rcsConfig=" + IccUtils.bytesToHexString(mRcsConfig) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 24237cb122..18f0f89731 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1279,7 +1279,7 @@ public class SubscriptionManagerService extends ISub.Stub { } String iccId = getIccId(phoneId); - log("updateSubscription: Found iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + log("updateSubscription: Found iccId=" + SubscriptionInfo.getPrintableId(iccId) + " on phone " + phoneId); // For eSIM switching, SIM absent will not happen. Below is to exam if we find ICCID @@ -1935,7 +1935,7 @@ public class SubscriptionManagerService extends ISub.Stub { public int addSubInfo(@NonNull String iccId, @NonNull String displayName, int slotIndex, @SubscriptionType int subscriptionType) { enforcePermissions("addSubInfo", Manifest.permission.MODIFY_PHONE_STATE); - logl("addSubInfo: iccId=" + SubscriptionInfo.givePrintableIccid(iccId) + ", slotIndex=" + logl("addSubInfo: iccId=" + SubscriptionInfo.getPrintableId(iccId) + ", slotIndex=" + slotIndex + ", displayName=" + displayName + ", type=" + SubscriptionManager.subscriptionTypeToString(subscriptionType) + ", " + getCallingPackage()); @@ -1993,7 +1993,7 @@ public class SubscriptionManagerService extends ISub.Stub { public int removeSubInfo(@NonNull String uniqueId, int subscriptionType) { enforcePermissions("removeSubInfo", Manifest.permission.MODIFY_PHONE_STATE); - logl("removeSubInfo: uniqueId=" + SubscriptionInfo.givePrintableIccid(uniqueId) + ", " + logl("removeSubInfo: uniqueId=" + SubscriptionInfo.getPrintableId(uniqueId) + ", " + SubscriptionManager.subscriptionTypeToString(subscriptionType) + ", " + getCallingPackage()); final long identity = Binder.clearCallingIdentity(); @@ -3932,7 +3932,7 @@ public class SubscriptionManagerService extends ISub.Stub { pw.println("ICCID:"); pw.increaseIndent(); for (int i = 0; i < mTelephonyManager.getActiveModemCount(); i++) { - pw.println("slot " + i + ": " + SubscriptionInfo.givePrintableIccid(getIccId(i))); + pw.println("slot " + i + ": " + SubscriptionInfo.getPrintableId(getIccId(i))); } pw.decreaseIndent(); pw.println(); diff --git a/src/java/com/android/internal/telephony/uicc/IccCardStatus.java b/src/java/com/android/internal/telephony/uicc/IccCardStatus.java index e2cc9e9632..f0d949dca1 100644 --- a/src/java/com/android/internal/telephony/uicc/IccCardStatus.java +++ b/src/java/com/android/internal/telephony/uicc/IccCardStatus.java @@ -197,7 +197,7 @@ public class IccCardStatus { } sb.append(",atr=").append(atr); - sb.append(",iccid=").append(SubscriptionInfo.givePrintableIccid(iccid)); + sb.append(",iccid=").append(SubscriptionInfo.getPrintableId(iccid)); sb.append(",eid=").append(Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, eid)); sb.append(",SupportedMepMode=").append(mSupportedMepMode); sb.append(",SlotPortMapping=").append(mSlotPortMapping); diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java index da112b166e..fa00b16ca8 100644 --- a/src/java/com/android/internal/telephony/uicc/IccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java @@ -269,7 +269,7 @@ public abstract class IccRecords extends Handler implements IccConstants { @Override public String toString() { - String iccIdToPrint = SubscriptionInfo.givePrintableIccid(mFullIccId); + String iccIdToPrint = SubscriptionInfo.getPrintableId(mFullIccId); return "mDestroyed=" + mDestroyed + " mContext=" + mContext + " mCi=" + mCi @@ -1428,7 +1428,7 @@ public abstract class IccRecords extends Handler implements IccConstants { pw.println(" mRecordsToLoad=" + mRecordsToLoad); pw.println(" mRdnCache=" + mAdnCache); - String iccIdToPrint = SubscriptionInfo.givePrintableIccid(mFullIccId); + String iccIdToPrint = SubscriptionInfo.getPrintableId(mFullIccId); pw.println(" iccid=" + iccIdToPrint); pw.println(" mMsisdn=" + Rlog.pii(VDBG, mMsisdn)); pw.println(" mMsisdnTag=" + mMsisdnTag); diff --git a/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java b/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java index 9a5e10d984..4164a1e1ce 100644 --- a/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java +++ b/src/java/com/android/internal/telephony/uicc/IccSimPortInfo.java @@ -51,7 +51,7 @@ public class IccSimPortInfo { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("{").append("iccid=") - .append(SubscriptionInfo.givePrintableIccid(mIccId)).append(",") + .append(SubscriptionInfo.getPrintableId(mIccId)).append(",") .append("logicalSlotIndex=").append(mLogicalSlotIndex).append(",") .append("portActive=").append(mPortActive) .append("}"); diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java index 041b5dde62..48a4430118 100644 --- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java +++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java @@ -690,7 +690,7 @@ public class RuimRecords extends IccRecords { mIccId = IccUtils.bcdToString(data, 0, data.length); mFullIccId = IccUtils.bchToString(data, 0, data.length); - log("iccid: " + SubscriptionInfo.givePrintableIccid(mFullIccId)); + log("iccid: " + SubscriptionInfo.getPrintableId(mFullIccId)); break; diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index 6fd86c5d9a..daf7842a9e 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -859,7 +859,7 @@ public class SIMRecords extends IccRecords { mIccId = IccUtils.bcdToString(data, 0, data.length); mFullIccId = IccUtils.bchToString(data, 0, data.length); - log("iccid: " + SubscriptionInfo.givePrintableIccid(mFullIccId)); + log("iccid: " + SubscriptionInfo.getPrintableId(mFullIccId)); break; case EVENT_GET_AD_DONE: diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 93ae88318f..c4ac8bf924 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -1796,7 +1796,7 @@ public class UiccController extends Handler { private List getPrintableCardStrings() { if (!ArrayUtils.isEmpty(mCardStrings)) { - return mCardStrings.stream().map(SubscriptionInfo::givePrintableIccid).collect( + return mCardStrings.stream().map(SubscriptionInfo::getPrintableId).collect( Collectors.toList()); } return mCardStrings; diff --git a/src/java/com/android/internal/telephony/uicc/UiccPort.java b/src/java/com/android/internal/telephony/uicc/UiccPort.java index fc33c6ee92..d89eab1d86 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccPort.java +++ b/src/java/com/android/internal/telephony/uicc/UiccPort.java @@ -365,7 +365,7 @@ public class UiccPort { pw.increaseIndent(); pw.println("mPortIdx=" + mPortIdx); pw.println("mCi=" + mCi); - pw.println("mIccid=" + SubscriptionInfo.givePrintableIccid(mIccid)); + pw.println("mIccid=" + SubscriptionInfo.getPrintableId(mIccid)); pw.println("mPhoneId=" + mPhoneId); pw.println("mPhysicalSlotIndex=" + mPhysicalSlotIndex); synchronized (mOpenChannelRecords) { diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index d2f9b39b21..debdaabc7f 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -1740,7 +1740,7 @@ public class UiccProfile extends IccCard { */ public boolean setOperatorBrandOverride(String brand) { log("setOperatorBrandOverride: " + brand); - log("current iccId: " + SubscriptionInfo.givePrintableIccid(getIccId())); + log("current iccId: " + SubscriptionInfo.getPrintableId(getIccId())); String iccId = getIccId(); if (TextUtils.isEmpty(iccId)) { diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index d29990811b..8564f01e96 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -667,7 +667,7 @@ public class UiccSlot extends Handler { private Map getPrintableIccIds() { Map printableIccIds = mIccIds.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, - e -> SubscriptionInfo.givePrintableIccid(e.getValue()))); + e -> SubscriptionInfo.getPrintableId(e.getValue()))); return printableIccIds; } diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java index 4c86373108..3bd66f8d87 100644 --- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java +++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java @@ -282,7 +282,7 @@ public class EuiccPort extends UiccPort { return null; case CODE_PROFILE_NOT_IN_EXPECTED_STATE: logd("Profile is already disabled, iccid: " - + SubscriptionInfo.givePrintableIccid(iccid)); + + SubscriptionInfo.getPrintableId(iccid)); return null; default: throw new EuiccCardErrorException( @@ -330,7 +330,7 @@ public class EuiccPort extends UiccPort { return null; case CODE_PROFILE_NOT_IN_EXPECTED_STATE: logd("Profile is already enabled, iccid: " - + SubscriptionInfo.givePrintableIccid(iccid)); + + SubscriptionInfo.getPrintableId(iccid)); return null; default: throw new EuiccCardErrorException( 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 d23c96bee2..72603feeed 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -912,6 +912,8 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, 1); assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getEnhanced4GModeEnabled()) .isEqualTo(1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).isEnhanced4GModeEnabled()) + .isTrue(); } @Test @@ -933,6 +935,8 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_VT_IMS_ENABLED, 1); assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getVideoTelephonyEnabled()) .isEqualTo(1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).isVideoTelephonyEnabled()) + .isTrue(); } @Test @@ -1049,6 +1053,8 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_VOIMS_OPT_IN_STATUS, 1); assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) .getVoImsOptInEnabled()).isEqualTo(1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).isVoImsOptInEnabled()) + .isTrue(); } @@ -1299,6 +1305,8 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_IMS_RCS_UCE_ENABLED, 1); assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getRcsUceEnabled()) .isEqualTo(1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).isRcsUceEnabled()) + .isTrue(); } @Test @@ -1321,6 +1329,8 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CROSS_SIM_CALLING_ENABLED, 1); assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).getCrossSimCallingEnabled()) .isEqualTo(1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1).isCrossSimCallingEnabled()) + .isTrue(); } @Test @@ -1422,6 +1432,8 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { 1, SimInfo.COLUMN_NR_ADVANCED_CALLING_ENABLED, 1); assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) .getNrAdvancedCallingEnabled()).isEqualTo(1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .isNrAdvancedCallingEnabled()).isTrue(); } @Test diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java index 0b5217da5b..898901a8a9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java @@ -194,6 +194,7 @@ public class SubscriptionInfoInternalTest { public void testEquals() { SubscriptionInfoInternal another = new SubscriptionInfoInternal.Builder(mSubInfo).build(); assertThat(another).isEqualTo(mSubInfo); + assertThat(another.hashCode()).isEqualTo(mSubInfo.hashCode()); } @Test -- GitLab From 879c32fe0deef1863784695d8b11eef02e8942ea Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Fri, 10 Mar 2023 18:04:53 +0000 Subject: [PATCH 514/656] Data enabled check on attached NetworkRequest Data enabled check on first attached NetworkRequest when evaluate DataNetwork. Bug: 268176386 Test: atest FrameworksTelephonyTests Change-Id: Iedee7cbce6f991aeda4f31026e9bc68f0a0f65fd --- .../telephony/data/DataNetworkController.java | 12 ++++-------- .../telephony/data/DataNetworkControllerTest.java | 8 ++++++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index b18ba3323b..aef47a4847 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -1775,10 +1775,7 @@ public class DataNetworkController extends Handler { } // Check if data is disabled - boolean dataDisabled = false; - if (!mDataSettingsManager.isDataEnabled()) { - dataDisabled = true; - } + boolean dataDisabled = !mDataSettingsManager.isDataEnabled(); // Check if data roaming is disabled if (mServiceState.getDataRoaming() && !mDataSettingsManager.isDataRoamingEnabled()) { @@ -1793,10 +1790,9 @@ public class DataNetworkController extends Handler { DataProfile dataProfile = dataNetwork.getDataProfile(); if (dataProfile.getApnSetting() != null) { // Check if data is disabled for the APN type - dataDisabled = !mDataSettingsManager.isDataEnabled(DataUtils - .networkCapabilityToApnType(DataUtils - .getHighestPriorityNetworkCapabilityFromDataProfile( - mDataConfigManager, dataProfile))); + dataDisabled = !mDataSettingsManager.isDataEnabled( + DataUtils.networkCapabilityToApnType( + dataNetwork.getApnTypeNetworkCapability())); // Sometimes network temporarily OOS and network type becomes UNKNOWN. We don't // tear down network in that case. 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 0dded1247a..70bde17849 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -1639,6 +1639,14 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); + mDataNetworkControllerUT.obtainMessage(16 /*EVENT_REEVALUATE_EXISTING_DATA_NETWORKS*/, + DataEvaluation.DataEvaluationReason.DATA_SERVICE_STATE_CHANGED).sendToTarget(); + + processAllFutureMessages(); + + // Make sure IMS network is not torn down + verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_MMS); + // Remove MMS data enabled override mDataNetworkControllerUT.getDataSettingsManager().setMobileDataPolicy(TelephonyManager .MOBILE_DATA_POLICY_MMS_ALWAYS_ALLOWED, false); -- GitLab From e9bc0883136ed740014128a7f81a0cc662992d4b Mon Sep 17 00:00:00 2001 From: virkumar Date: Thu, 9 Mar 2023 10:03:32 +0000 Subject: [PATCH 515/656] Send UNHELD event to connection after SRVCC complets In mid call SRVCC case send UNHELD event so that in 3G after call resumed by remote UI will be updated. Test: MO call mid call SRVCC with Anritsu. Bug: 237372330 Change-Id: I5dba0a9c768109ca28fb7878726ae8f50748f223 --- .../telephony/imsphone/ImsPhoneCall.java | 9 ++++++ .../imsphone/ImsPhoneCallTracker.java | 6 ++-- .../imsphone/ImsPhoneConnection.java | 29 +++++++++++++++++++ .../telephony/imsphone/ImsPhoneCallTest.java | 20 +++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java index 7a6adce8af..eaa6ab6700 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java @@ -469,6 +469,15 @@ public class ImsPhoneCall extends Call { return mIsRingbackTonePlaying; } + public void maybeClearRemotelyHeldStatus() { + for (Connection conn : getConnections()) { + ImsPhoneConnection c = (ImsPhoneConnection) conn; + if (c.isHeldByRemote()) { + c.setRemotelyUnheld(); + } + } + } + private void takeOver(ImsPhoneCall that) { copyConnectionFrom(that); mState = that.mState; diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 1a4d6ba484..c567574145 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -4041,7 +4041,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mPhone.stopOnHoldTone(conn); mOnHoldToneStarted = false; } - conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_REMOTELY_UNHELD, null); + conn.setRemotelyUnheld(); mImsCallInfoTracker.updateImsCallStatus(conn, false, true); } @@ -4722,6 +4722,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // If the dialing call had ringback, ensure it stops now, // otherwise it'll keep playing afer the SRVCC completes. mForegroundCall.maybeStopRingback(); + mForegroundCall.maybeClearRemotelyHeldStatus(); + mBackgroundCall.maybeClearRemotelyHeldStatus(); resetState(); transferHandoverConnections(mForegroundCall); @@ -5822,7 +5824,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mOnHoldToneStarted = true; mOnHoldToneId = System.identityHashCode(conn); } - conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_REMOTELY_HELD, null); + conn.setRemotelyHeld(); mImsCallInfoTracker.updateImsCallStatus(conn, true, false); boolean useVideoPauseWorkaround = mPhone.getContext().getResources().getBoolean( diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java index 581b6fff8b..b10c457d96 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java @@ -152,6 +152,11 @@ public class ImsPhoneConnection extends Connection implements */ private ImsReasonInfo mImsReasonInfo; + /** + * Used to indicate that this call is held by remote party. + */ + private boolean mIsHeldByRemote = false; + //***** Event Constants private static final int EVENT_DTMF_DONE = 1; private static final int EVENT_PAUSE_DONE = 2; @@ -1591,6 +1596,30 @@ public class ImsPhoneConnection extends Connection implements onConnectionEvent(android.telecom.Connection.EVENT_MERGE_COMPLETE, null); } + /** + * Mark the call is held by remote party and inform to the UI. + */ + public void setRemotelyHeld() { + mIsHeldByRemote = true; + onConnectionEvent(android.telecom.Connection.EVENT_CALL_REMOTELY_HELD, null); + } + + /** + * Mark the call is Unheld by remote party and inform to the UI. + */ + public void setRemotelyUnheld() { + mIsHeldByRemote = false; + onConnectionEvent(android.telecom.Connection.EVENT_CALL_REMOTELY_UNHELD, null); + } + + /** + * @return whether the remote party is holding the call. + */ + public boolean isHeldByRemote() { + Rlog.i(LOG_TAG, "isHeldByRemote=" + mIsHeldByRemote); + return mIsHeldByRemote; + } + public void changeToPausedState() { int newVideoState = getVideoState() | VideoProfile.STATE_PAUSED; Rlog.i(LOG_TAG, "ImsPhoneConnection: changeToPausedState - setting paused bit; " diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java index 13748e8ef3..c4bb8641b5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTest.java @@ -317,4 +317,24 @@ public class ImsPhoneCallTest extends TelephonyTest { fail("Exception unexpected"); } } + + @Test + public void testMaybeClearRemotelyHeldStatus() { + mImsCallUT.attach(mConnection1, Call.State.ACTIVE); + when(mConnection1.isHeldByRemote()).thenReturn(true); + mImsCallUT.maybeClearRemotelyHeldStatus(); + verify(mConnection1, times(1)).setRemotelyUnheld(); + + mImsCallUT.attach(mConnection2, Call.State.ACTIVE); + when(mConnection2.isHeldByRemote()).thenReturn(true); + mImsCallUT.maybeClearRemotelyHeldStatus(); + verify(mConnection1, times(2)).setRemotelyUnheld(); + verify(mConnection2, times(1)).setRemotelyUnheld(); + + when(mConnection1.isHeldByRemote()).thenReturn(false); + when(mConnection2.isHeldByRemote()).thenReturn(false); + mImsCallUT.maybeClearRemotelyHeldStatus(); + verify(mConnection1, times(2)).setRemotelyUnheld(); + verify(mConnection2, times(1)).setRemotelyUnheld(); + } } -- GitLab From bb96639330c9bc85b69fa2f5481c6fa3f2b8d944 Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Sat, 4 Mar 2023 17:25:32 +0000 Subject: [PATCH 516/656] [Telephony]Pre-submit test Failures at ServiceStateTrackerTest - testRegisterForVoiceRegStateOrRatChange() - testRegAndInvalidRegForNetworkAttached() - testLocaleTrackerUpdateWithIWLANInService() - testSetCsNormalNotifications() - testSetCsEmergencyNotifications() - testSetCsNotifications() - testSetPsNotifications() - testGetCombinedRegState() - testUpdatePhoneType() testUpdateSpnDisplay_spnNotEmptyAndCrossSimCallingEnabled_showSpnOnly() - testUpdateSpnDisplay_spnNotEmptyAndWifiCallingEnabled_showSpnOnly() Bug: 261268475 Test: atest FrameworksTelephonyTests Change-Id: Ic876e106fa9340851bb6eafa4d65ddbac03c6206 --- .../internal/telephony/RatRatcheter.java | 13 +++- .../telephony/ServiceStateTrackerTest.java | 60 +++++++++++++++---- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/java/com/android/internal/telephony/RatRatcheter.java b/src/java/com/android/internal/telephony/RatRatcheter.java index bea2c2a15d..aff62ae41f 100644 --- a/src/java/com/android/internal/telephony/RatRatcheter.java +++ b/src/java/com/android/internal/telephony/RatRatcheter.java @@ -141,15 +141,24 @@ public class RatRatcheter { synchronized (mRatFamilyMap) { // Either the two technologies are the same or their families must be non-null // and the same. + // To Fix Missing Null check + if (ss1.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN) == null + || ss2.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN) == null) { + return false; + } + int dataRat1 = ServiceState.networkTypeToRilRadioTechnology( ss1.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + AccessNetworkConstants.TRANSPORT_TYPE_WWAN) .getAccessNetworkTechnology()); int dataRat2 = ServiceState.networkTypeToRilRadioTechnology( ss2.getNetworkRegistrationInfo(NetworkRegistrationInfo.DOMAIN_PS, - AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + AccessNetworkConstants.TRANSPORT_TYPE_WWAN) .getAccessNetworkTechnology()); + // The api getAccessNetworkTechnology@NetworkRegistrationInfo always returns LTE though // data rat is LTE CA. Because it uses mIsUsingCarrierAggregation to indicate whether // it is LTE CA or not. However, we need its actual data rat to check if they are the diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 5350b768cd..3b6499c5f3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -303,6 +303,11 @@ public class ServiceStateTrackerTest extends TelephonyTest { waitUntilReady(); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + // Voice radio tech change will always trigger an update of + // phone object irrespective of this config + mContextFixture.putBooleanResource( + com.android.internal.R.bool.config_switch_phone_on_voice_reg_state_change, false); + // Override SPN related resource mContextFixture.putResource( com.android.internal.R.string.lockscreen_carrier_default, @@ -916,13 +921,15 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @MediumTest public void testUpdatePhoneType() { + String brandOverride = "spn from brand override"; + doReturn(brandOverride).when(mUiccProfile).getOperatorBrandOverride(); doReturn(false).when(mPhone).isPhoneTypeGsm(); doReturn(true).when(mPhone).isPhoneTypeCdmaLte(); doReturn(CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM).when(mCdmaSSM). getCdmaSubscriptionSource(); - logd("Calling updatePhoneType"); // switch to CDMA + logd("Calling updatePhoneType"); sst.updatePhoneType(); ArgumentCaptor integerArgumentCaptor = ArgumentCaptor.forClass(Integer.class); @@ -967,7 +974,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { mSimulatedCommands.setVoiceRegState(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); mSimulatedCommands.setDataRegState(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); mSimulatedCommands.notifyNetworkStateChanged(); - waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); // verify if registered handler has message posted to it @@ -1149,7 +1155,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { mSimulatedCommands.notifyNetworkStateChanged(); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); - // verify if registered handler has message posted to it ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong()); @@ -1273,7 +1278,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @MediumTest - public void testRegisterForVoiceRegStateOrRatChange() { + public void testRegisterForVoiceRegStateOrRatChange() throws Exception { NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder() .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) .setDomain(NetworkRegistrationInfo.DOMAIN_CS) @@ -1281,14 +1286,17 @@ public class ServiceStateTrackerTest extends TelephonyTest { .build(); sst.mSS.addNetworkRegistrationInfo(nri); + sst.mSS.setState(ServiceState.STATE_IN_SERVICE); sst.registerForVoiceRegStateOrRatChanged(mTestHandler, EVENT_VOICE_RAT_CHANGED, null); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); // Verify if message was posted to handler and value of result ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); - verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong()); + verify(mTestHandler) + .sendMessageAtTime(messageArgumentCaptor.capture(), anyLong()); assertEquals(EVENT_VOICE_RAT_CHANGED, messageArgumentCaptor.getValue().what); + assertEquals(new Pair(ServiceState.STATE_IN_SERVICE, ServiceState.RIL_RADIO_TECHNOLOGY_LTE), ((AsyncResult)messageArgumentCaptor.getValue().obj).result); @@ -1383,6 +1391,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { mSimulatedCommands.setDataRegState(NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); mSimulatedCommands.notifyNetworkStateChanged(); + waitForDelayedHandlerAction(mSSTTestHandler.getThreadHandler(), 500, 200); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); // verify if registered handler has message posted to it @@ -1534,7 +1543,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @SmallTest - public void testSetPsNotifications() { + public void testSetPsNotifications() throws Exception { int subId = 1; sst.mSubId = subId; doReturn(subId).when(mSubInfo).getSubscriptionId(); @@ -1552,6 +1561,9 @@ public class ServiceStateTrackerTest extends TelephonyTest { when(mockResources.getDrawable(anyInt(), any())).thenReturn(mockDrawable); mContextFixture.putResource(com.android.internal.R.string.RestrictedOnDataTitle, "test1"); + // Make sure getState() condition returns in service, without this at logs at times found to + // be out of service + sst.mSS.setState(ServiceState.STATE_IN_SERVICE); sst.setNotification(ServiceStateTracker.PS_ENABLED); ArgumentCaptor notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); @@ -1567,7 +1579,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @SmallTest - public void testSetCsNotifications() { + public void testSetCsNotifications() throws Exception { int subId = 1; sst.mSubId = subId; doReturn(subId).when(mSubInfo).getSubscriptionId(); @@ -1585,6 +1597,9 @@ public class ServiceStateTrackerTest extends TelephonyTest { mContextFixture.putResource(com.android.internal.R.string.RestrictedOnAllVoiceTitle, "test2"); + // Make sure getState() condition returns in service, without this at logs at times found to + // be out of service + sst.mSS.setState(ServiceState.STATE_IN_SERVICE); sst.setNotification(ServiceStateTracker.CS_ENABLED); ArgumentCaptor notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); @@ -1600,7 +1615,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @SmallTest - public void testSetCsNormalNotifications() { + public void testSetCsNormalNotifications() throws Exception { int subId = 1; sst.mSubId = subId; doReturn(subId).when(mSubInfo).getSubscriptionId(); @@ -1617,6 +1632,9 @@ public class ServiceStateTrackerTest extends TelephonyTest { when(mockResources.getDrawable(anyInt(), any())).thenReturn(mockDrawable); mContextFixture.putResource(com.android.internal.R.string.RestrictedOnNormalTitle, "test3"); + // Make sure getState() condition returns in service, without this at logs at times found to + // be out of service + sst.mSS.setState(ServiceState.STATE_IN_SERVICE); sst.setNotification(ServiceStateTracker.CS_NORMAL_ENABLED); ArgumentCaptor notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); @@ -1632,7 +1650,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test @SmallTest - public void testSetCsEmergencyNotifications() { + public void testSetCsEmergencyNotifications() throws Exception { int subId = 1; sst.mSubId = subId; doReturn(subId).when(mSubInfo).getSubscriptionId(); @@ -1650,6 +1668,9 @@ public class ServiceStateTrackerTest extends TelephonyTest { mContextFixture.putResource(com.android.internal.R.string.RestrictedOnEmergencyTitle, "test4"); + // Make sure mIsEmergencyOnly should be true, when setNotification notification type is + // CS_EMERGENCY_ENABLED notification + sst.mSS.setEmergencyOnly(true); sst.setNotification(ServiceStateTracker.CS_EMERGENCY_ENABLED); ArgumentCaptor notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class); @@ -2428,6 +2449,9 @@ public class ServiceStateTrackerTest extends TelephonyTest { public void testLocaleTrackerUpdateWithIWLANInService() { // 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); changeRegStateWithIwlanOperatorNumeric(NetworkRegistrationInfo.REGISTRATION_STATE_HOME, TelephonyManager.NETWORK_TYPE_LTE, NetworkRegistrationInfo.REGISTRATION_STATE_HOME, OpNamesResult, true); @@ -2811,13 +2835,20 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test public void testUpdateSpnDisplay_spnNotEmptyAndCrossSimCallingEnabled_showSpnOnly() { // GSM phone - doReturn(true).when(mPhone).isPhoneTypeGsm(); + final CellIdentityLte cellIdentityLte = + new CellIdentityLte(1, 1, 5, 1, new int[] {1, 2}, 5000, "001", "01", "test", + "tst", Collections.emptyList(), null); // In Service ServiceState ss = new ServiceState(); ss.setVoiceRegState(ServiceState.STATE_IN_SERVICE); ss.setDataRegState(ServiceState.STATE_IN_SERVICE); + //To By Pass RatRacheter + ss.addNetworkRegistrationInfo(makeNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + cellIdentityLte, true)); sst.mSS = ss; // cross-sim-calling is enable @@ -2846,11 +2877,19 @@ public class ServiceStateTrackerTest extends TelephonyTest { public void testUpdateSpnDisplay_spnNotEmptyAndWifiCallingEnabled_showSpnOnly() { // GSM phone doReturn(true).when(mPhone).isPhoneTypeGsm(); + final CellIdentityLte cellIdentityLte = + new CellIdentityLte(1, 1, 5, 1, new int[] {1, 2}, 5000, "001", "01", "test", + "tst", Collections.emptyList(), null); // In Service ServiceState ss = new ServiceState(); ss.setVoiceRegState(ServiceState.STATE_IN_SERVICE); ss.setDataRegState(ServiceState.STATE_IN_SERVICE); + //To By Pass RatRacheter + ss.addNetworkRegistrationInfo(makeNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + cellIdentityLte, true)); sst.mSS = ss; // wifi-calling is enabled @@ -3087,6 +3126,7 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test public void testGetCombinedRegState() { doReturn(mImsPhone).when(mPhone).getImsPhone(); + doReturn(true).when(mPhone).isPhoneTypeGsm(); // If voice/data out of service, return out of service. doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState(); -- GitLab From e32fa0172f3761dda53f798c9d231a3a82ae54d1 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 9 Mar 2023 22:58:50 -0800 Subject: [PATCH 517/656] Update satellite implementation based on updated APIs Test: atest SatelliteManagerTest Bug: 261053569 Change-Id: Ia83a9304ad40dd124dafad3fbf34c9ea2b308c51 Merged-In: Ia83a9304ad40dd124dafad3fbf34c9ea2b308c51 --- .../satellite/DatagramController.java | 12 +- .../satellite/DatagramDispatcher.java | 13 +- .../telephony/satellite/DatagramReceiver.java | 5 +- .../satellite/PointingAppController.java | 103 +++--- .../satellite/SatelliteController.java | 322 ++++++------------ .../satellite/SatelliteModemInterface.java | 139 ++------ .../satellite/SatelliteServiceUtils.java | 7 +- 7 files changed, 208 insertions(+), 393 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 06addda899..ab226880bd 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -86,16 +86,13 @@ public class DatagramController { * Register to receive incoming datagrams over satellite. * * @param subId The subId of the subscription to register for incoming satellite datagrams. - * @param datagramType datagram type indicating whether the datagram is of type - * SOS_SMS or LOCATION_SHARING. * @param callback The callback to handle incoming datagrams over satellite. * * @return The {@link SatelliteManager.SatelliteError} result of the operation. */ @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId, - @SatelliteManager.DatagramType int datagramType, @NonNull ISatelliteDatagramCallback callback) { - return mDatagramReceiver.registerForSatelliteDatagram(subId, datagramType, callback); + return mDatagramReceiver.registerForSatelliteDatagram(subId, callback); } /** @@ -104,7 +101,7 @@ public class DatagramController { * * @param subId The subId of the subscription to unregister for incoming satellite datagrams. * @param callback The callback that was passed to - * {@link #registerForSatelliteDatagram(int, int, ISatelliteDatagramCallback)}. + * {@link #registerForSatelliteDatagram(int, ISatelliteDatagramCallback)}. */ public void unregisterForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback) { @@ -138,15 +135,14 @@ public class DatagramController { * Datagram will be passed down to modem without any encoding or encryption. * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in * full screen mode. - * @param isSatelliteDemoModeEnabled True if satellite demo mode is enabled * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ public void sendSatelliteDatagram(@SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, - boolean isSatelliteDemoModeEnabled, @NonNull Consumer callback) { + @NonNull Consumer callback) { // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING mDatagramDispatcher.sendSatelliteDatagram(datagramType, datagram, - needFullScreenPointingUI, isSatelliteDemoModeEnabled, callback); + needFullScreenPointingUI, callback); } private static void logd(@NonNull String log) { diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index ef7c8dd5d2..c0c7777750 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -117,18 +117,16 @@ public class DatagramDispatcher extends Handler { public @SatelliteManager.DatagramType int datagramType; public @NonNull SatelliteDatagram datagram; public boolean needFullScreenPointingUI; - public boolean isSatelliteDemoModeEnabled; public @NonNull Consumer callback; SendSatelliteDatagramArgument(long datagramId, @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, - boolean isSatelliteDemoModeEnabled, @NonNull Consumer callback) { + @NonNull Consumer callback) { this.datagramId = datagramId; this.datagramType = datagramType; this.datagram = datagram; this.needFullScreenPointingUI = needFullScreenPointingUI; - this.isSatelliteDemoModeEnabled = isSatelliteDemoModeEnabled; this.callback = callback; } } @@ -148,8 +146,7 @@ public class DatagramDispatcher extends Handler { if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { SatelliteModemInterface.getInstance().sendSatelliteDatagram(argument.datagram, argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, - argument.needFullScreenPointingUI, argument.isSatelliteDemoModeEnabled, - onCompleted); + argument.needFullScreenPointingUI, onCompleted); break; } Phone phone = request.phone; @@ -216,19 +213,17 @@ public class DatagramDispatcher extends Handler { * Datagram will be passed down to modem without any encoding or encryption. * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in * full screen mode. - * @param isSatelliteDemoModeEnabled True if satellite demo mode is enabled * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ public void sendSatelliteDatagram(@SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, - boolean isSatelliteDemoModeEnabled, @NonNull Consumer callback) { + @NonNull Consumer callback) { Phone phone = SatelliteServiceUtils.getPhone(); long datagramId = mNextDatagramId.getAndUpdate( n -> ((n + 1) % DatagramController.MAX_DATAGRAM_ID)); SendSatelliteDatagramArgument datagramArgs = new SendSatelliteDatagramArgument(datagramId, - datagramType, datagram, needFullScreenPointingUI, isSatelliteDemoModeEnabled, - callback); + datagramType, datagram, needFullScreenPointingUI, callback); synchronized (mLock) { if (datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index d144d3bb1a..541a6f1788 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -323,14 +323,11 @@ public class DatagramReceiver { * Register to receive incoming datagrams over satellite. * * @param subId The subId of the subscription to register for incoming satellite datagrams. - * @param datagramType datagram type indicating whether the datagram is of type - * SOS_SMS or LOCATION_SHARING. * @param callback The callback to handle incoming datagrams over satellite. * * @return The {@link SatelliteManager.SatelliteError} result of the operation. */ @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId, - @SatelliteManager.DatagramType int datagramType, @NonNull ISatelliteDatagramCallback callback) { if (!SatelliteController.getInstance().isSatelliteSupported()) { return SatelliteManager.SATELLITE_NOT_SUPPORTED; @@ -366,7 +363,7 @@ public class DatagramReceiver { * * @param subId The subId of the subscription to unregister for incoming satellite datagrams. * @param callback The callback that was passed to - * {@link #registerForSatelliteDatagram(int, int, ISatelliteDatagramCallback)}. + * {@link #registerForSatelliteDatagram(int, ISatelliteDatagramCallback)}. */ public void unregisterForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback) { diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java index 94fcde0ee9..2041d4ee83 100644 --- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -27,7 +27,7 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.telephony.Rlog; -import android.telephony.satellite.ISatellitePositionUpdateCallback; +import android.telephony.satellite.ISatelliteTransmissionUpdateCallback; import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteManager; import android.text.TextUtils; @@ -46,13 +46,13 @@ public class PointingAppController { @NonNull private static PointingAppController sInstance; @NonNull private final Context mContext; - private boolean mStartedSatellitePositionUpdates; + private boolean mStartedSatelliteTransmissionUpdates; /** - * Map key: subId, value: SatellitePositionUpdateHandler to notify registrants. + * Map key: subId, value: SatelliteTransmissionUpdateHandler to notify registrants. */ - private final ConcurrentHashMap - mSatellitePositionUpdateHandlers = new ConcurrentHashMap<>(); + private final ConcurrentHashMap + mSatelliteTransmissionUpdateHandlers = new ConcurrentHashMap<>(); /** * @return The singleton instance of PointingAppController. @@ -83,33 +83,34 @@ public class PointingAppController { */ private PointingAppController(@NonNull Context context) { mContext = context; - mStartedSatellitePositionUpdates = false; + mStartedSatelliteTransmissionUpdates = false; } /** - * set the flag mStartedSatellitePositionUpdates to true or false based on the state of - * position updates - * @param startedSatellitePositionUpdates boolean to set the flag + * Set the flag mStartedSatelliteTransmissionUpdates to true or false based on the state of + * transmission updates + * @param startedSatelliteTransmissionUpdates boolean to set the flag */ - public void setStartedSatellitePositionUpdates(boolean startedSatellitePositionUpdates) { - mStartedSatellitePositionUpdates = startedSatellitePositionUpdates; + public void setStartedSatelliteTransmissionUpdates( + boolean startedSatelliteTransmissionUpdates) { + mStartedSatelliteTransmissionUpdates = startedSatelliteTransmissionUpdates; } - private static final class SatellitePositionUpdateHandler extends Handler { + private static final class SatelliteTransmissionUpdateHandler extends Handler { public static final int EVENT_POSITION_INFO_CHANGED = 1; public static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 2; - private final ConcurrentHashMap mListeners; - SatellitePositionUpdateHandler(Looper looper) { + private final ConcurrentHashMap mListeners; + SatelliteTransmissionUpdateHandler(Looper looper) { super(looper); mListeners = new ConcurrentHashMap<>(); } - public void addListener(ISatellitePositionUpdateCallback listener) { + public void addListener(ISatelliteTransmissionUpdateCallback listener) { mListeners.put(listener.asBinder(), listener); } - public void removeListener(ISatellitePositionUpdateCallback listener) { + public void removeListener(ISatelliteTransmissionUpdateCallback listener) { mListeners.remove(listener.asBinder()); } @@ -146,30 +147,32 @@ public class PointingAppController { break; } default: - loge("SatellitePositionUpdateHandler unknown event: " + msg.what); + loge("SatelliteTransmissionUpdateHandler unknown event: " + msg.what); } } } /** - * register to start receiving Updates on Satellite Position and Datagram transfer state + * Register to start receiving updates for satellite position and datagram transfer state * @param subId The subId of the subscription to register for receiving the updates. - * @param callback The callback to notify of changes in satellite position. - * @param phone The Phone Object to unregister for receiving the updates + * @param callback The callback to notify of satellite transmission updates. + * @param phone The Phone object to unregister for receiving the updates. */ - public void registerForSatellitePositionUpdates(int subId, - ISatellitePositionUpdateCallback callback, Phone phone) { - SatellitePositionUpdateHandler handler = mSatellitePositionUpdateHandlers.get(subId); + public void registerForSatelliteTransmissionUpdates(int subId, + ISatelliteTransmissionUpdateCallback callback, Phone phone) { + SatelliteTransmissionUpdateHandler handler = + mSatelliteTransmissionUpdateHandlers.get(subId); if (handler != null) { handler.addListener(callback); return; } else { - handler = new SatellitePositionUpdateHandler(Looper.getMainLooper()); + handler = new SatelliteTransmissionUpdateHandler(Looper.getMainLooper()); handler.addListener(callback); - mSatellitePositionUpdateHandlers.put(subId, handler); + mSatelliteTransmissionUpdateHandlers.put(subId, handler); if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged( - handler, SatellitePositionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, + null); /** * TODO: Need to remove this call, Datagram transfer state should come from the * DatagramController based upon Transfer state. @@ -177,27 +180,29 @@ public class PointingAppController { */ SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged( handler, - SatellitePositionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, null); + SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, + null); } else { phone.registerForSatellitePositionInfoChanged(handler, - SatellitePositionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); // TODO: registerForDatagramTransferStateChanged through SatelliteController } } } /** - * Unregister to stop receiving Updates on Satellite Position and Datagram transfer state + * Unregister to stop receiving updates on satellite position and datagram transfer state * If the callback was not registered before, it is ignored * @param subId The subId of the subscription to unregister for receiving the updates. * @param result The callback to get the error code in case of failure - * @param callback The callback that was passed to - * * {@link registerForSatellitePositionUpdateEvents} - * @param phone The Phone Object to unregister for receiving the updates + * @param callback The callback that was passed to {@link + * #registerForSatelliteTransmissionUpdates(int, ISatelliteTransmissionUpdateCallback, Phone)}. + * @param phone The Phone object to unregister for receiving the updates */ - public void unregisterForSatellitePositionUpdates(int subId, Consumer result, - ISatellitePositionUpdateCallback callback, Phone phone) { - SatellitePositionUpdateHandler handler = mSatellitePositionUpdateHandlers.get(subId); + public void unregisterForSatelliteTransmissionUpdates(int subId, Consumer result, + ISatelliteTransmissionUpdateCallback callback, Phone phone) { + SatelliteTransmissionUpdateHandler handler = + mSatelliteTransmissionUpdateHandlers.get(subId); if (handler != null) { handler.removeListener(callback); @@ -213,7 +218,7 @@ public class PointingAppController { return; } - mSatellitePositionUpdateHandlers.remove(subId); + mSatelliteTransmissionUpdateHandlers.remove(subId); if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { SatelliteModemInterface.getInstance().unregisterForSatellitePositionInfoChanged( handler); @@ -231,28 +236,28 @@ public class PointingAppController { } /** - * Start receiving satellite position updates. + * Start receiving satellite trasmission updates. * This can be called by the pointing UI when the user starts pointing to the satellite. * Modem should continue to report the pointing input as the device or satellite moves. - * The Position updates will be received via - * {@link android.telephony.satellite.SatellitePositionUpdateCallback#onSatellitePositionChanged( - * pointingInfo)} + * The transmission updates will be received via + * {@link android.telephony.satellite.SatelliteTransmissionUpdateCallback + * #onSatellitePositionChanged(pointingInfo)}. */ - public void startSatellitePositionUpdates(@NonNull Message message, @Nullable Phone phone) { - if (mStartedSatellitePositionUpdates) { - logd("startSatellitePositionUpdates: already started"); + public void startSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) { + if (mStartedSatelliteTransmissionUpdates) { + logd("startSatelliteTransmissionUpdates: already started"); return; } if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { SatelliteModemInterface.getInstance().startSendingSatellitePointingInfo(message); - mStartedSatellitePositionUpdates = true; + mStartedSatelliteTransmissionUpdates = true; return; } if (phone != null) { phone.startSatellitePositionUpdates(message); - mStartedSatellitePositionUpdates = true; + mStartedSatelliteTransmissionUpdates = true; } else { - loge("startSatellitePositionUpdates: No phone object"); + loge("startSatelliteTransmissionUpdates: No phone object"); AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); message.sendToTarget(); @@ -260,10 +265,10 @@ public class PointingAppController { } /** - * Stop receiving satellite position updates. + * Stop receiving satellite transmission updates. * This can be called by the pointing UI when the user stops pointing to the satellite. */ - public void stopSatellitePositionUpdates(@NonNull Message message, @Nullable Phone phone) { + public void stopSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) { if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { SatelliteModemInterface.getInstance().stopSendingSatellitePointingInfo(message); return; @@ -271,7 +276,7 @@ public class PointingAppController { if (phone != null) { phone.stopSatellitePositionUpdates(message); } else { - loge("startSatellitePositionUpdates: No phone object"); + loge("startSatelliteTransmissionUpdates: No phone object"); AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); message.sendToTarget(); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 09a8cb7b60..5a1d1832db 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothAdapter; import android.content.Context; -import android.content.Intent; import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Binder; @@ -37,9 +36,9 @@ import android.os.ResultReceiver; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.satellite.ISatelliteDatagramCallback; -import android.telephony.satellite.ISatellitePositionUpdateCallback; import android.telephony.satellite.ISatelliteProvisionStateCallback; import android.telephony.satellite.ISatelliteStateCallback; +import android.telephony.satellite.ISatelliteTransmissionUpdateCallback; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; @@ -68,12 +67,10 @@ public class SatelliteController extends Handler { /** Message codes used in handleMessage() */ //TODO: Move the Commands and events related to position updates to PointingAppController - private static final int CMD_START_SATELLITE_POSITION_UPDATES = 1; - private static final int EVENT_START_SATELLITE_POSITION_UPDATES_DONE = 2; - private static final int CMD_STOP_SATELLITE_POSITION_UPDATES = 3; - private static final int EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE = 4; - private static final int CMD_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG = 5; - private static final int EVENT_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG_DONE = 6; + private static final int CMD_START_SATELLITE_TRANSMISSION_UPDATES = 1; + private static final int EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE = 2; + private static final int CMD_STOP_SATELLITE_TRANSMISSION_UPDATES = 3; + private static final int EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE = 4; private static final int CMD_PROVISION_SATELLITE_SERVICE = 7; private static final int EVENT_PROVISION_SATELLITE_SERVICE_DONE = 8; private static final int CMD_DEPROVISION_SATELLITE_SERVICE = 9; @@ -125,7 +122,7 @@ public class SatelliteController extends Handler { private Boolean mIsSatelliteSupported = null; private final Object mIsSatelliteSupportedLock = new Object(); private final ResultReceiver mSatelliteSupportedReceiver; - private boolean mIsSatelliteDemoModeEnabled = false; + private boolean mIsDemoModeEnabled = false; private boolean mNeedsSatellitePointing = false; private final Object mNeedsSatellitePointingLock = new Object(); @@ -219,38 +216,43 @@ public class SatelliteController extends Handler { } private static final class RequestSatelliteEnabledArgument { - public boolean enabled; - public @NonNull Consumer callback; - - RequestSatelliteEnabledArgument(boolean enabled, Consumer callback) { - this.enabled = enabled; + public boolean enableSatellite; + public boolean enableDemoMode; + @NonNull public Consumer callback; + + RequestSatelliteEnabledArgument(boolean enableSatellite, boolean enableDemoMode, + Consumer callback) { + this.enableSatellite = enableSatellite; + this.enableDemoMode = enableDemoMode; this.callback = callback; } } private static final class ProvisionSatelliteServiceArgument { - public @NonNull String token; - public @NonNull Consumer callback; + @NonNull public String token; + @NonNull public String regionId; + @NonNull public Consumer callback; public int subId; - ProvisionSatelliteServiceArgument(String token, Consumer callback, int subId) { + ProvisionSatelliteServiceArgument(String token, String regionId, Consumer callback, + int subId) { this.token = token; + this.regionId = regionId; this.callback = callback; this.subId = subId; } } - /** - * Arguments to send to SatellitePositionUpdate registrants + * Arguments to send to SatelliteTransmissionUpdate registrants */ - public static final class SatellitePositionUpdateArgument { - public @NonNull Consumer errorCallback; - public @NonNull ISatellitePositionUpdateCallback callback; + public static final class SatelliteTransmissionUpdateArgument { + @NonNull public Consumer errorCallback; + @NonNull public ISatelliteTransmissionUpdateCallback callback; public int subId; - SatellitePositionUpdateArgument(Consumer errorCallback, - ISatellitePositionUpdateCallback callback, int subId) { + SatelliteTransmissionUpdateArgument(Consumer errorCallback, + ISatelliteTransmissionUpdateCallback callback, int subId) { this.errorCallback = errorCallback; this.callback = callback; this.subId = subId; @@ -317,7 +319,7 @@ public class SatelliteController extends Handler { private static final class SatelliteStateListenerHandler extends Handler { public static final int EVENT_SATELLITE_MODEM_STATE_CHANGE = 1; - public static final int EVENT_PENDING_DATAGRAM_COUNT = 2; + public static final int EVENT_PENDING_DATAGRAMS = 2; private final ConcurrentHashMap mListeners; private final int mSubId; @@ -357,25 +359,9 @@ public class SatelliteController extends Handler { }); break; } - case EVENT_PENDING_DATAGRAM_COUNT: { - AsyncResult ar = (AsyncResult) msg.obj; - int count = (int) ar.result; - logd("Received EVENT_PENDING_DATAGRAM_COUNT for subId=" + mSubId - + ", count=" + count); - - if (count == 0) { - // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_RECEIVE_NONE - } else { - // TODO: update receivePendingCount - } - - mListeners.values().forEach(listener -> { - try { - listener.onPendingDatagramCount(count); - } catch (RemoteException e) { - logd("EVENT_PENDING_DATAGRAM_COUNT RemoteException: " + e); - } - }); + case EVENT_PENDING_DATAGRAMS: { + logd("Received EVENT_PENDING_DATAGRAMS for subId=" + mSubId); + // TODO: call pollPendingSatelliteDatagrams break; } default: @@ -391,77 +377,37 @@ public class SatelliteController extends Handler { AsyncResult ar; switch(msg.what) { - case CMD_START_SATELLITE_POSITION_UPDATES: { + case CMD_START_SATELLITE_TRANSMISSION_UPDATES: { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = - obtainMessage(EVENT_START_SATELLITE_POSITION_UPDATES_DONE, request); - mPointingAppController.startSatellitePositionUpdates(onCompleted, request.phone); + obtainMessage(EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE, request); + mPointingAppController.startSatelliteTransmissionUpdates(onCompleted, + request.phone); break; } - case EVENT_START_SATELLITE_POSITION_UPDATES_DONE: { - handleStartSatellitePositionUpdatesDone((AsyncResult) msg.obj); + case EVENT_START_SATELLITE_TRANSMISSION_UPDATES_DONE: { + handleStartSatelliteTransmissionUpdatesDone((AsyncResult) msg.obj); break; } - case CMD_STOP_SATELLITE_POSITION_UPDATES: { + case CMD_STOP_SATELLITE_TRANSMISSION_UPDATES: { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = - obtainMessage(EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE, request); - mPointingAppController.stopSatellitePositionUpdates(onCompleted, request.phone); + obtainMessage(EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE, request); + mPointingAppController.stopSatelliteTransmissionUpdates(onCompleted, request.phone); break; } - case EVENT_STOP_SATELLITE_POSITION_UPDATES_DONE: { + case EVENT_STOP_SATELLITE_TRANSMISSION_UPDATES_DONE: { ar = (AsyncResult) msg.obj; request = (SatelliteControllerHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, - "stopSatellitePositionUpdates"); + "stopSatelliteTransmissionUpdates"); ((Consumer) request.argument).accept(error); break; } - case CMD_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG: { - request = (SatelliteControllerHandlerRequest) msg.obj; - onCompleted = - obtainMessage(EVENT_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface - .requestMaxCharactersPerMOTextMessage(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.getMaxCharactersPerSatelliteTextMessage(onCompleted); - } else { - loge("getMaxCharactersPerSatelliteTextMessage: No phone object"); - ((ResultReceiver) request.argument).send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } - break; - } - - case EVENT_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG_DONE: { - ar = (AsyncResult) msg.obj; - request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = SatelliteServiceUtils.getSatelliteError(ar, - "getMaxCharactersPerSatelliteTextMessage"); - Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - if (ar.result == null) { - loge("getMaxCharactersPerSatelliteTextMessage: result is null"); - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } else { - int maxCharLimit = ((int[]) ar.result)[0]; - if (DBG) logd("getMaxCharactersPerSatelliteTextMessage: " + maxCharLimit); - bundle.putInt(SatelliteManager.KEY_MAX_CHARACTERS_PER_SATELLITE_TEXT, - maxCharLimit); - } - } - ((ResultReceiver) request.argument).send(error, bundle); - break; - } - case CMD_PROVISION_SATELLITE_SERVICE: { request = (SatelliteControllerHandlerRequest) msg.obj; ProvisionSatelliteServiceArgument argument = @@ -475,8 +421,8 @@ public class SatelliteController extends Handler { mSatelliteProvisionCallbacks.put(argument.subId, argument.callback); onCompleted = obtainMessage(EVENT_PROVISION_SATELLITE_SERVICE_DONE, request); if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface - .provisionSatelliteService(argument.token, onCompleted); + mSatelliteModemInterface.provisionSatelliteService(argument.token, + argument.regionId, onCompleted); break; } Phone phone = request.phone; @@ -484,8 +430,7 @@ public class SatelliteController extends Handler { phone.provisionSatelliteService(onCompleted, argument.token); } else { loge("provisionSatelliteService: No phone object"); - argument.callback.accept( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); notifyRequester(request); } break; @@ -540,7 +485,7 @@ public class SatelliteController extends Handler { RequestSatelliteEnabledArgument argument = (RequestSatelliteEnabledArgument) request.argument; onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request); - if (argument.enabled) { + if (argument.enableSatellite) { if (mBluetoothAdapter == null) { mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } @@ -559,12 +504,13 @@ public class SatelliteController extends Handler { } } if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.requestSatelliteEnabled(argument.enabled, onCompleted); + mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite, + argument.enableDemoMode, onCompleted); break; } Phone phone = request.phone; if (phone != null) { - phone.setSatellitePower(onCompleted, argument.enabled); + phone.setSatellitePower(onCompleted, argument.enableSatellite); } else { loge("requestSatelliteEnabled: No phone object"); argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); @@ -579,7 +525,7 @@ public class SatelliteController extends Handler { (RequestSatelliteEnabledArgument) request.argument; int error = SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled"); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - if (!argument.enabled) { + if (!argument.enableSatellite) { if (mBluetoothAdapter == null) { mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } @@ -602,6 +548,7 @@ public class SatelliteController extends Handler { if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(false); } + mIsDemoModeEnabled = argument.enableDemoMode; } argument.callback.accept(error); // TODO: if error is ERROR_NONE, request satellite capabilities @@ -722,7 +669,7 @@ public class SatelliteController extends Handler { } else { SatelliteCapabilities capabilities = (SatelliteCapabilities) ar.result; synchronized (mNeedsSatellitePointingLock) { - mNeedsSatellitePointing = capabilities.needsPointingToSatellite(); + mNeedsSatellitePointing = capabilities.isPointingRequired(); } if (DBG) logd("getSatelliteCapabilities: " + capabilities); bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, @@ -853,16 +800,18 @@ public class SatelliteController extends Handler { } /** - * Request to enable or disable the satellite modem. If the satellite modem is enabled, this - * will also disable the cellular modem, and if the satellite modem is disabled, this will also - * re-enable the cellular modem. + * Request to enable or disable the satellite modem and demo mode. If the satellite modem is + * enabled, this will also disable the cellular modem, and if the satellite modem is disabled, + * this will also re-enable the cellular modem. * * @param subId The subId of the subscription to set satellite enabled for. - * @param enable {@code true} to enable the satellite modem and {@code false} to disable. + * @param enableSatellite {@code true} to enable the satellite modem and + * {@code false} to disable. + * @param enableDemoMode {@code true} to enable demo mode and {@code false} to disable. * @param callback The callback to get the error code of the request. */ - public void requestSatelliteEnabled( - int subId, boolean enable, @NonNull IIntegerConsumer callback) { + public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode, + @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); @@ -878,7 +827,8 @@ public class SatelliteController extends Handler { Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_SET_SATELLITE_ENABLED, - new RequestSatelliteEnabledArgument(enable, result), phone); + new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result), + phone); } /** @@ -904,31 +854,6 @@ public class SatelliteController extends Handler { sendRequest(CMD_IS_SATELLITE_ENABLED, result, phone); } - /** - * Request to enable or disable the satellite service demo mode. - * - * @param subId The subId of the subscription to set the satellite demo mode enabled for. - * @param enable {@code true} to enable the satellite demo mode and {@code false} to disable. - * @param callback The callback to get the error code of the request. - */ - public void requestSatelliteDemoModeEnabled( - int subId, boolean enable, @NonNull IIntegerConsumer callback) { - Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - if (!isSatelliteSupported()) { - result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); - return; - } - - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { - result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); - return; - } - - mIsSatelliteDemoModeEnabled = enable; - result.accept(SatelliteManager.SATELLITE_ERROR_NONE); - } - /** * Request to get whether the satellite service demo mode is enabled. * @@ -937,7 +862,7 @@ public class SatelliteController extends Handler { * @param result The result receiver that returns whether the satellite demo mode is enabled * if the request is successful or an error code if the request failed. */ - public void requestIsSatelliteDemoModeEnabled(int subId, @NonNull ResultReceiver result) { + public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) { if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; @@ -950,7 +875,7 @@ public class SatelliteController extends Handler { } final Bundle bundle = new Bundle(); - bundle.putBoolean(SatelliteManager.KEY_DEMO_MODE_ENABLED, mIsSatelliteDemoModeEnabled); + bundle.putBoolean(SatelliteManager.KEY_DEMO_MODE_ENABLED, mIsDemoModeEnabled); result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); } @@ -972,7 +897,6 @@ public class SatelliteController extends Handler { } } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, phone); } @@ -990,22 +914,22 @@ public class SatelliteController extends Handler { return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, phone); } /** - * Start receiving satellite position updates. + * Start receiving satellite transmission updates. * This can be called by the pointing UI when the user starts pointing to the satellite. * Modem should continue to report the pointing input as the device or satellite moves. * - * @param subId The subId of the subscription to start satellite position updates for. + * @param subId The subId of the subscription to start satellite transmission updates for. * @param errorCallback The callback to get the error code of the request. - * @param callback The callback to notify of changes in satellite position. + * @param callback The callback to notify of satellite transmission updates. */ - public void startSatellitePositionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, - @NonNull ISatellitePositionUpdateCallback callback) { + public void startSatelliteTransmissionUpdates(int subId, + @NonNull IIntegerConsumer errorCallback, + @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); @@ -1019,22 +943,22 @@ public class SatelliteController extends Handler { } Phone phone = SatelliteServiceUtils.getPhone(); - mPointingAppController.registerForSatellitePositionUpdates(validSubId, callback, phone); - sendRequestAsync(CMD_START_SATELLITE_POSITION_UPDATES, - new SatellitePositionUpdateArgument(result, callback, validSubId), phone); + mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback, phone); + sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES, + new SatelliteTransmissionUpdateArgument(result, callback, validSubId), phone); } /** - * Stop receiving satellite position updates. + * Stop receiving satellite transmission updates. * This can be called by the pointing UI when the user stops pointing to the satellite. * - * @param subId The subId of the subscription to stop satellite position updates for. + * @param subId The subId of the subscription to stop satellite transmission updates for. * @param errorCallback The callback to get the error code of the request. - * @param callback The callback that was passed to {@link - * #startSatellitePositionUpdates(int, IIntegerConsumer, ISatellitePositionUpdateCallback)} + * @param callback The callback that was passed to {@link #startSatelliteTransmissionUpdates( + * int, IIntegerConsumer, ISatelliteTransmissionUpdateCallback)}. */ - public void stopSatellitePositionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, - @NonNull ISatellitePositionUpdateCallback callback) { + public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, + @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); @@ -1048,39 +972,13 @@ public class SatelliteController extends Handler { } Phone phone = SatelliteServiceUtils.getPhone(); - mPointingAppController.unregisterForSatellitePositionUpdates( + mPointingAppController.unregisterForSatelliteTransmissionUpdates( validSubId, result, callback, phone); - /** - * Even if handler is null - which means there are not any listeners, the command to stop - * satellite position updates sent to the modem might have failed. The callers might want to - * retry sending the command. Thus, we always need to send this command to the modem. - */ - sendRequestAsync(CMD_STOP_SATELLITE_POSITION_UPDATES, result, phone); - } - - /** - * Request to get the maximum number of bytes per datagram that can be sent to satellite. - * - * @param subId The subId of the subscription to get the maximum number of characters for. - * @param result The result receiver that returns the maximum number of bytes per datagram - * message on satellite if the request is successful or an error code - * if the request failed. - */ - public void requestMaxSizePerSendingDatagram(int subId, - @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); - return; - } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { - result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); - return; - } - - Phone phone = SatelliteServiceUtils.getPhone(); - sendRequestAsync(CMD_GET_MAX_CHAR_PER_SATELLITE_TEXT_MSG, result, phone); + // Even if handler is null - which means there are no listeners, the modem command to stop + // satellite transmission updates might have failed. The callers might want to retry + // sending the command. Thus, we always need to send this command to the modem. + sendRequestAsync(CMD_STOP_SATELLITE_TRANSMISSION_UPDATES, result, phone); } /** @@ -1090,13 +988,14 @@ public class SatelliteController extends Handler { * @param subId The subId of the subscription to be provisioned. * @param token The token to be used as a unique identifier for provisioning with satellite * gateway. + * @param regionId The region ID for the device's current location. * @param callback The callback to get the error code of the request. * * @return The signal transport used by the caller to cancel the provision request, * or {@code null} if the request failed. */ @Nullable public ICancellationSignal provisionSatelliteService(int subId, - @NonNull String token, @NonNull IIntegerConsumer callback) { + @NonNull String token, @NonNull String regionId, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); @@ -1117,12 +1016,12 @@ public class SatelliteController extends Handler { } sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE, - new ProvisionSatelliteServiceArgument(token, result, validSubId), phone); + new ProvisionSatelliteServiceArgument(token, regionId, result, validSubId), phone); ICancellationSignal cancelTransport = CancellationSignal.createTransport(); CancellationSignal.fromTransport(cancelTransport).setOnCancelListener(() -> { sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, - new ProvisionSatelliteServiceArgument(token, null, validSubId), + new ProvisionSatelliteServiceArgument(token, regionId, null, validSubId), phone); }); return cancelTransport; @@ -1155,7 +1054,7 @@ public class SatelliteController extends Handler { Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, - new ProvisionSatelliteServiceArgument(token, result, validSubId), phone); + new ProvisionSatelliteServiceArgument(token, null, result, validSubId), phone); } /** @@ -1260,14 +1159,13 @@ public class SatelliteController extends Handler { mSatelliteModemInterface.registerForSatelliteModemStateChanged( satelliteStateListenerHandler, SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); - mSatelliteModemInterface.registerForPendingDatagramCount( - satelliteStateListenerHandler, - SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAM_COUNT, null); + mSatelliteModemInterface.registerForPendingDatagrams(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); } else { phone.registerForSatelliteModemStateChanged(satelliteStateListenerHandler, SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); phone.registerForPendingDatagramCount(satelliteStateListenerHandler, - SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAM_COUNT, null); + SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); } } @@ -1294,7 +1192,7 @@ public class SatelliteController extends Handler { mSatelliteStateListenerHandlers.remove(validSubId); if (mSatelliteModemInterface.isSatelliteServiceSupported()) { mSatelliteModemInterface.unregisterForSatelliteModemStateChanged(handler); - mSatelliteModemInterface.unregisterForPendingDatagramCount(handler); + mSatelliteModemInterface.unregisterForPendingDatagrams(handler); } else { Phone phone = SatelliteServiceUtils.getPhone(); if (phone != null) { @@ -1310,16 +1208,13 @@ public class SatelliteController extends Handler { * Register to receive incoming datagrams over satellite. * * @param subId The subId of the subscription to register for incoming satellite datagrams. - * @param datagramType datagram type indicating whether the datagram is of type - * SOS_SMS or LOCATION_SHARING. * @param callback The callback to handle incoming datagrams over satellite. * * @return The {@link SatelliteManager.SatelliteError} result of the operation. */ @SatelliteManager.SatelliteError public int registerForSatelliteDatagram(int subId, - @SatelliteManager.DatagramType int datagramType, @NonNull ISatelliteDatagramCallback callback) { - return mDatagramController.registerForSatelliteDatagram(subId, datagramType, callback); + return mDatagramController.registerForSatelliteDatagram(subId, callback); } /** @@ -1328,7 +1223,7 @@ public class SatelliteController extends Handler { * * @param subId The subId of the subscription to unregister for incoming satellite datagrams. * @param callback The callback that was passed to - * {@link #registerForSatelliteDatagram(int, int, ISatelliteDatagramCallback)}. + * {@link #registerForSatelliteDatagram(int, ISatelliteDatagramCallback)}. */ public void unregisterForSatelliteDatagram(int subId, @NonNull ISatelliteDatagramCallback callback) { @@ -1395,8 +1290,8 @@ public class SatelliteController extends Handler { if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(needFullScreenPointingUI); } - mDatagramController.sendSatelliteDatagram(datagramType, datagram, - needFullScreenPointingUI, mIsSatelliteDemoModeEnabled, result); + mDatagramController.sendSatelliteDatagram(datagramType, datagram, needFullScreenPointingUI, + result); } /** @@ -1420,7 +1315,7 @@ public class SatelliteController extends Handler { } /** - * Request to get the time after which the satellite will be visible + * Request to get the time after which the satellite will be visible. * * @param subId The subId to get the time after which the satellite will be visible for. * @param result The result receiver that returns the time after which the satellite will @@ -1441,6 +1336,7 @@ public class SatelliteController extends Handler { Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); } + private void handleEventProvisionSatelliteServiceDone( @NonNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteError int result) { @@ -1486,24 +1382,22 @@ public class SatelliteController extends Handler { } } - private void handleStartSatellitePositionUpdatesDone(@NonNull AsyncResult ar) { + private void handleStartSatelliteTransmissionUpdatesDone(@NonNull AsyncResult ar) { SatelliteControllerHandlerRequest request = (SatelliteControllerHandlerRequest) ar.userObj; - SatellitePositionUpdateArgument arg = (SatellitePositionUpdateArgument) request.argument; + SatelliteTransmissionUpdateArgument arg = + (SatelliteTransmissionUpdateArgument) request.argument; int errorCode = SatelliteServiceUtils.getSatelliteError(ar, - "handleStartSatellitePositionUpdatesDone"); + "handleStartSatelliteTransmissionUpdatesDone"); arg.errorCallback.accept(errorCode); if (errorCode != SatelliteManager.SATELLITE_ERROR_NONE) { - mPointingAppController.setStartedSatellitePositionUpdates(false); - /** - * We need to remove the callback from our listener list since the caller might not call - * {@link #stopSatellitePositionUpdates(int, IIntegerConsumer, ISatellitePositionUpdateCallback)} - * to unregister the callback in case of failure. - */ - mPointingAppController.unregisterForSatellitePositionUpdates(arg.subId, + mPointingAppController.setStartedSatelliteTransmissionUpdates(false); + // We need to remove the callback from our listener list since the caller might not call + // stopSatelliteTransmissionUpdates to unregister the callback in case of failure. + mPointingAppController.unregisterForSatelliteTransmissionUpdates(arg.subId, arg.errorCallback, arg.callback, request.phone); } else { - mPointingAppController.setStartedSatellitePositionUpdates(true); + mPointingAppController.setStartedSatelliteTransmissionUpdates(true); } } @@ -1523,7 +1417,6 @@ public class SatelliteController extends Handler { } } - /** * If we have not successfully queried the satellite modem for its satellite service support, * we will retry the query one more time. Otherwise, we will return the queried result. @@ -1631,4 +1524,3 @@ public class SatelliteController extends Handler { Rlog.e(TAG, log); } } - diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 168f42ede8..00be71dc93 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -78,11 +78,9 @@ public class SatelliteModemInterface { new RegistrantList(); @NonNull private final RegistrantList mSatelliteModemStateChangedRegistrants = new RegistrantList(); - @NonNull private final RegistrantList mPendingDatagramCountRegistrants = new RegistrantList(); + @NonNull private final RegistrantList mPendingDatagramsRegistrants = new RegistrantList(); @NonNull private final RegistrantList mSatelliteDatagramsReceivedRegistrants = new RegistrantList(); - @NonNull private final RegistrantList mSatelliteRadioTechnologyChangedRegistrants = - new RegistrantList(); @NonNull private final ISatelliteListener mListener = new ISatelliteListener.Stub() { @Override @@ -98,8 +96,8 @@ public class SatelliteModemInterface { } @Override - public void onPendingDatagramCount(int count) { - mPendingDatagramCountRegistrants.notifyResult(count); + public void onPendingDatagrams() { + mPendingDatagramsRegistrants.notifyResult(null); } @Override @@ -133,12 +131,6 @@ public class SatelliteModemInterface { // TODO: properly notify the rest of the datagram transfer state changed parameters mDatagramTransferStateChangedRegistrants.notifyResult(datagramTransferState); } - - @Override - public void onSatelliteRadioTechnologyChanged(int technology) { - mSatelliteRadioTechnologyChangedRegistrants.notifyResult( - SatelliteServiceUtils.fromSatelliteRadioTechnology(technology)); - } }; /** @@ -385,24 +377,23 @@ public class SatelliteModemInterface { } /** - * Registers for pending datagram count from satellite modem. + * Registers for pending datagrams indication from satellite modem. * * @param h Handler for notification message. * @param what User-defined message code. * @param obj User object. */ - public void registerForPendingDatagramCount( - @NonNull Handler h, int what, @Nullable Object obj) { - mPendingDatagramCountRegistrants.add(h, what, obj); + public void registerForPendingDatagrams(@NonNull Handler h, int what, @Nullable Object obj) { + mPendingDatagramsRegistrants.add(h, what, obj); } /** - * Unregisters for pending datagram count from satellite modem. + * Unregisters for pending datagrams indication from satellite modem. * * @param h Handler to be removed from the registrant list. */ - public void unregisterForPendingDatagramCount(@NonNull Handler h) { - mPendingDatagramCountRegistrants.remove(h); + public void unregisterForPendingDatagrams(@NonNull Handler h) { + mPendingDatagramsRegistrants.remove(h); } /** @@ -426,27 +417,6 @@ public class SatelliteModemInterface { mSatelliteDatagramsReceivedRegistrants.remove(h); } - /** - * Registers for satellite radio technology changed from satellite modem. - * - * @param h Handler for notification message. - * @param what User-defined message code. - * @param obj User object. - */ - public void registerForSatelliteRadioTechnologyChanged( - @NonNull Handler h, int what, @Nullable Object obj) { - mSatelliteRadioTechnologyChangedRegistrants.add(h, what, obj); - } - - /** - * Unregisters for satellite radio technology changed from satellite modem. - * - * @param h Handler to be removed from the registrant list. - */ - public void unregisterForSatelliteRadioTechnologyChanged(@NonNull Handler h) { - mSatelliteRadioTechnologyChangedRegistrants.remove(h); - } - /** * Request to enable or disable the satellite service listening mode. * Listening mode allows the satellite service to listen for incoming pages. @@ -454,16 +424,14 @@ public class SatelliteModemInterface { * @param enable True to enable satellite listening mode and false to disable. * @param timeout How long the satellite modem should wait for the next incoming page before * disabling listening mode. - * @param isSatelliteDemoModeEnabled True if satellite demo mode is enabled * @param message The Message to send to result of the operation to. */ public void requestSatelliteListeningEnabled(boolean enable, int timeout, - boolean isSatelliteDemoModeEnabled, @NonNull Message message) { + @NonNull Message message) { if (mSatelliteService != null) { try { - mSatelliteService.requestSatelliteListeningEnabled( - enable, isSatelliteDemoModeEnabled, - timeout, new IIntegerConsumer.Stub() { + mSatelliteService.requestSatelliteListeningEnabled(enable, timeout, + new IIntegerConsumer.Stub() { @Override public void accept(int result) { int error = SatelliteServiceUtils.fromSatelliteError(result); @@ -483,17 +451,20 @@ public class SatelliteModemInterface { } /** - * Request to enable or disable the satellite modem. If the satellite modem is enabled, - * this will also disable the cellular modem, and if the satellite modem is disabled, - * this will also re-enable the cellular modem. + * Request to enable or disable the satellite modem and demo mode. If the satellite modem + * is enabled, this may also disable the cellular modem, and if the satellite modem is disabled, + * this may also re-enable the cellular modem. * - * @param enable True to enable the satellite modem and false to disable. + * @param enableSatellite True to enable the satellite modem and false to disable. + * @param enableDemoMode True to enable demo mode and false to disable. * @param message The Message to send to result of the operation to. */ - public void requestSatelliteEnabled(boolean enable, @NonNull Message message) { + public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, + @NonNull Message message) { if (mSatelliteService != null) { try { - mSatelliteService.requestSatelliteEnabled(enable, new IIntegerConsumer.Stub() { + mSatelliteService.requestSatelliteEnabled(enableSatellite, enableDemoMode, + new IIntegerConsumer.Stub() { @Override public void accept(int result) { int error = SatelliteServiceUtils.fromSatelliteError(result); @@ -677,44 +648,6 @@ public class SatelliteModemInterface { } } - /** - * Request to get the maximum number of characters per MO text message on satellite. - * - * @param message The Message to send to result of the operation to. - */ - public void requestMaxCharactersPerMOTextMessage(@NonNull Message message) { - if (mSatelliteService != null) { - try { - mSatelliteService.requestMaxCharactersPerMOTextMessage(new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - int error = SatelliteServiceUtils.fromSatelliteError(result); - logd("requestMaxCharactersPerMOTextMessage: " + error); - Binder.withCleanCallingIdentity(() -> - sendMessageWithResult(message, null, error)); - } - }, new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - // Convert for compatibility with SatelliteResponse - // TODO: This should just report result instead. - int[] maxCharacters = new int[] {result}; - logd("requestMaxCharactersPerMOTextMessage: " - + Arrays.toString(maxCharacters)); - Binder.withCleanCallingIdentity(() -> sendMessageWithResult( - message, maxCharacters, SatelliteManager.SATELLITE_ERROR_NONE)); - } - }); - } catch (RemoteException e) { - loge("requestMaxCharactersPerMOTextMessage: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); - } - } else { - loge("requestMaxCharactersPerMOTextMessage: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); - } - } - /** * Provision the device with a satellite provider. * This is needed if the provider allows dynamic registration. @@ -722,20 +655,23 @@ public class SatelliteModemInterface { * * @param token The token to be used as a unique identifier for provisioning with satellite * gateway. + * @param regionId The region ID for the device's current location. * @param message The Message to send to result of the operation to. */ - public void provisionSatelliteService(@NonNull String token, @NonNull Message message) { + public void provisionSatelliteService(@NonNull String token, @NonNull String regionId, + @NonNull Message message) { if (mSatelliteService != null) { try { - mSatelliteService.provisionSatelliteService(token, new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - int error = SatelliteServiceUtils.fromSatelliteError(result); - logd("provisionSatelliteService: " + error); - Binder.withCleanCallingIdentity(() -> - sendMessageWithResult(message, null, error)); - } - }); + mSatelliteService.provisionSatelliteService(token, regionId, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = SatelliteServiceUtils.fromSatelliteError(result); + logd("provisionSatelliteService: " + error); + Binder.withCleanCallingIdentity(() -> + sendMessageWithResult(message, null, error)); + } + }); } catch (RemoteException e) { loge("provisionSatelliteService: RemoteException " + e); sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); @@ -849,17 +785,14 @@ public class SatelliteModemInterface { * @param isEmergency Whether this is an emergency datagram. * @param needFullScreenPointingUI this is used to indicate pointingUI app to open in * full screen mode. - * @param isSatelliteDemoModeEnabled True if satellite demo mode is enabled * @param message The Message to send to result of the operation to. */ public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency, - boolean needFullScreenPointingUI, boolean isSatelliteDemoModeEnabled, - @NonNull Message message) { + boolean needFullScreenPointingUI, @NonNull Message message) { if (mSatelliteService != null) { try { mSatelliteService.sendSatelliteDatagram( - SatelliteServiceUtils.toSatelliteDatagram(datagram), - isSatelliteDemoModeEnabled, isEmergency, + SatelliteServiceUtils.toSatelliteDatagram(datagram), isEmergency, new IIntegerConsumer.Stub() { @Override public void accept(int result) { diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java index a30dd54bc5..2ed35b32f8 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java @@ -161,9 +161,7 @@ public class SatelliteServiceUtils { Arrays.stream(radioTechnologies) .map(SatelliteServiceUtils::fromSatelliteRadioTechnology) .boxed().collect(Collectors.toSet()), - capabilities.isAlwaysOn, - capabilities.needsPointingToSatellite, - capabilities.needsSeparateSimProfile); + capabilities.isPointingRequired, capabilities.maxBytesPerOutgoingDatagram); } /** @@ -174,8 +172,7 @@ public class SatelliteServiceUtils { @Nullable public static PointingInfo fromPointingInfo( android.telephony.satellite.stub.PointingInfo pointingInfo) { if (pointingInfo == null) return null; - return new PointingInfo(pointingInfo.satelliteAzimuth, pointingInfo.satelliteElevation, - pointingInfo.antennaAzimuth, pointingInfo.antennaPitch, pointingInfo.antennaRoll); + return new PointingInfo(pointingInfo.satelliteAzimuth, pointingInfo.satelliteElevation); } /** -- GitLab From 8dce8371eff59b352923e90c216fa38808e77482 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Wed, 8 Mar 2023 02:12:01 +0000 Subject: [PATCH 518/656] Disable Satellite Mode when Radio State becomes OFF - Listen to Radio state and Disable Satellite Mode BUG: b/272427922 Test: atest SatelliteController, Tested Manually in panther-userdebug binary Change-Id: I76beabef35b278006a56aab82b1f6610c91d51f1 --- .../satellite/SatelliteController.java | 62 ++++++++++++++----- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 5a1d1832db..22da55051c 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -35,6 +35,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.telephony.Rlog; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.ISatelliteProvisionStateCallback; import android.telephony.satellite.ISatelliteStateCallback; @@ -46,6 +47,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; @@ -89,6 +91,7 @@ public class SatelliteController extends Handler { private static final int EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE = 22; private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 23; private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 24; + private static final int EVENT_RADIO_STATE_CHANGED = 25; @NonNull private static SatelliteController sInstance; @NonNull private final Context mContext; @@ -96,6 +99,7 @@ public class SatelliteController extends Handler { @NonNull private final SatelliteSessionController mSatelliteSessionController; @NonNull private final PointingAppController mPointingAppController; @NonNull private final DatagramController mDatagramController; + private final CommandsInterface mCi; BluetoothAdapter mBluetoothAdapter = null; WifiManager mWifiManager = null; @@ -159,7 +163,8 @@ public class SatelliteController extends Handler { protected SatelliteController(@NonNull Context context, @NonNull Looper looper) { super(looper); mContext = context; - + Phone phone = SatelliteServiceUtils.getPhone(); + mCi = phone.mCi; // Create the SatelliteModemInterface singleton, which is used to manage connections // to the satellite service and HAL interface. mSatelliteModemInterface = SatelliteModemInterface.make(mContext); @@ -195,6 +200,7 @@ public class SatelliteController extends Handler { //TODO: reenable below code //requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, // mSatelliteSupportedReceiver); + mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); } private void internalInit() { @@ -482,9 +488,9 @@ public class SatelliteController extends Handler { case CMD_SET_SATELLITE_ENABLED: { request = (SatelliteControllerHandlerRequest) msg.obj; + //To be moved to EVENT_SET_SATELLITE_ENABLED_DONE RequestSatelliteEnabledArgument argument = (RequestSatelliteEnabledArgument) request.argument; - onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request); if (argument.enableSatellite) { if (mBluetoothAdapter == null) { mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); @@ -503,18 +509,7 @@ public class SatelliteController extends Handler { mDisabledWifiFlag = true; } } - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite, - argument.enableDemoMode, onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.setSatellitePower(onCompleted, argument.enableSatellite); - } else { - loge("requestSatelliteEnabled: No phone object"); - argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - } + handleSatelliteEnabled(request); break; } @@ -786,6 +781,27 @@ public class SatelliteController extends Handler { break; } + case EVENT_RADIO_STATE_CHANGED: { + if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF + || mCi.getRadioState() == TelephonyManager.RADIO_POWER_UNAVAILABLE) { + logd("Radio State Changed to " + mCi.getRadioState()); + IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + loge("Failed to Disable Satellite Mode, Error: " + result); + } + }; + Phone phone = SatelliteServiceUtils.getPhone(); + Consumer result = FunctionalUtils + .ignoreRemoteException(errorCallback::accept); + RequestSatelliteEnabledArgument message = + new RequestSatelliteEnabledArgument(false, false, result); + request = new SatelliteControllerHandlerRequest(message, phone); + handleSatelliteEnabled(request); + break; + } + } + default: Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " + msg.what); @@ -1516,6 +1532,24 @@ public class SatelliteController extends Handler { return false; } + private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) { + RequestSatelliteEnabledArgument argument = + (RequestSatelliteEnabledArgument) request.argument; + Message onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite, + argument.enableDemoMode, onCompleted); + return; + } + Phone phone = request.phone; + if (phone != null) { + phone.setSatellitePower(onCompleted, argument.enableSatellite); + } else { + loge("requestSatelliteEnabled: No phone object"); + argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + } + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } -- GitLab From 2936844811e4f28afcfab96d3f15393de3e73e85 Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Tue, 14 Mar 2023 07:33:25 +0000 Subject: [PATCH 519/656] [MEP] Enable iccCloseLogicalChannelWithSessionInfo API Modem changes to support the API are merged, hence enabling the API for Radio HAL V2.1 Test: Verified on Radio HAL V2.1 supported device Bug: 268496310 Change-Id: I3044400682666e6a4fef0337c442ad255ca82d29 --- .../android/internal/telephony/RadioSimProxy.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/RadioSimProxy.java b/src/java/com/android/internal/telephony/RadioSimProxy.java index d9aba9c44d..7c8ee7b6ea 100644 --- a/src/java/com/android/internal/telephony/RadioSimProxy.java +++ b/src/java/com/android/internal/telephony/RadioSimProxy.java @@ -283,14 +283,11 @@ public class RadioSimProxy extends RadioServiceProxy { if (isEmpty()) return; if (isAidl()) { if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_2_1)) { - // TODO: [MEP-A1] Use iccCloseLogicalChannelWithSessionInfo API once vendor - // changes are completed. - //android.hardware.radio.sim.SessionInfo info = - // new android.hardware.radio.sim.SessionInfo(); - //info.sessionId = channelId; - //info.isEs10 = isEs10; - //mSimProxy.iccCloseLogicalChannelWithSessionInfo(serial, info); - mSimProxy.iccCloseLogicalChannel(serial, channelId); + android.hardware.radio.sim.SessionInfo info = + new android.hardware.radio.sim.SessionInfo(); + info.sessionId = channelId; + info.isEs10 = isEs10; + mSimProxy.iccCloseLogicalChannelWithSessionInfo(serial, info); return; } mSimProxy.iccCloseLogicalChannel(serial, channelId); -- GitLab From a5a88295831266d253558481f3ec21497395f093 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 14 Mar 2023 19:52:43 -0700 Subject: [PATCH 520/656] Always update SPN upon locale changed Fix: 265900643 Test: local reproduced the issue and verified fix Change-Id: I0fe5fcc7c188dbe3b34cc54cc801d72884bb44cd --- .../com/android/internal/telephony/ServiceStateTracker.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 36ac1e2859..2593e6b67d 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -558,8 +558,12 @@ public class ServiceStateTracker extends Handler { public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action.equals(Intent.ACTION_LOCALE_CHANGED)) { + log("ACTION_LOCALE_CHANGED"); // Update emergency string or operator name, polling service state. pollState(); + // Depends on modem, ServiceState is not necessarily updated, so make sure updating + // SPN. + updateSpnDisplay(); } else if (action.equals(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)) { String lastKnownNetworkCountry = intent.getStringExtra( TelephonyManager.EXTRA_LAST_KNOWN_NETWORK_COUNTRY); -- GitLab From d6fb910b75301069f71066aefda26cc0cd23c993 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Fri, 10 Mar 2023 14:03:54 -0800 Subject: [PATCH 521/656] Allow non-preferred internet networks We allow internet networks that're Not using the preferred data profile if a) the network has capability that the preferred network cannot satisfy or b) the network type environment changed and we need to update the preferred data profile to align with the environment. Without this change, above networks will be torn down due to DATA_PROFILE_NOT_PREFERRED upon any network evaluations. Fix: 248346348 Fix: 273620310 Test: reproduce the issue and confirm the fix Change-Id: I26ab868e6ac97a4bb089f76085523e030ba039fe --- .../telephony/data/DataNetworkController.java | 13 +- .../telephony/data/DataProfileManager.java | 68 ++++---- .../data/DataStallRecoveryManager.java | 3 +- .../telephony/metrics/ServiceStateStats.java | 4 +- .../data/DataNetworkControllerTest.java | 147 +++++++++++++++--- .../data/DataProfileManagerTest.java | 91 +++++++++-- .../data/DataStallRecoveryManagerTest.java | 3 +- 7 files changed, 257 insertions(+), 72 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index b18ba3323b..c03834060d 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -556,10 +556,10 @@ public class DataNetworkController extends Handler { /** * Called when internet data network is connected. * - * @param dataProfiles The data profiles of the connected internet data network. It should - * be only one in most of the cases. + * @param internetNetworks The connected internet data network. It should be only one in + * most of the cases. */ - public void onInternetDataNetworkConnected(@NonNull List dataProfiles) {} + public void onInternetDataNetworkConnected(@NonNull List internetNetworks) {} /** * Called when data network is connected. @@ -1828,7 +1828,8 @@ public class DataNetworkController extends Handler { // If users switch preferred profile in APN editor, we need to tear down network. if (dataNetwork.isInternetSupported() && !mDataProfileManager.isDataProfilePreferred(dataProfile) - && mDataProfileManager.isAnyPreferredDataProfileExisting()) { + && mDataProfileManager.canPreferredDataProfileSatisfy( + dataNetwork.getAttachedNetworkRequestList())) { evaluation.addDataDisallowedReason(DataDisallowedReason.DATA_PROFILE_NOT_PREFERRED); } @@ -3454,9 +3455,7 @@ public class DataNetworkController extends Handler { && mInternetDataNetworkState == TelephonyManager.DATA_DISCONNECTED) { mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor( () -> callback.onInternetDataNetworkConnected( - allConnectedInternetDataNetworks.stream() - .map(DataNetwork::getDataProfile) - .collect(Collectors.toList())))); + allConnectedInternetDataNetworks))); } else if (dataNetworkState == TelephonyManager.DATA_DISCONNECTED && mInternetDataNetworkState == TelephonyManager.DATA_CONNECTED) { mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor( diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java index 2cf1452909..37f0de0a8a 100644 --- a/src/java/com/android/internal/telephony/data/DataProfileManager.java +++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java @@ -167,8 +167,8 @@ public class DataProfileManager extends Handler { new DataNetworkControllerCallback(this::post) { @Override public void onInternetDataNetworkConnected( - @NonNull List dataProfiles) { - DataProfileManager.this.onInternetDataNetworkConnected(dataProfiles); + @NonNull List internetNetworks) { + DataProfileManager.this.onInternetDataNetworkConnected(internetNetworks); } }); mDataConfigManager.registerCallback(new DataConfigManagerCallback(this::post) { @@ -404,24 +404,37 @@ public class DataProfileManager extends Handler { /** * Called when internet data is connected. * - * @param dataProfiles The connected internet data networks' profiles. + * @param internetNetworks The connected internet data networks. */ - private void onInternetDataNetworkConnected(@NonNull List dataProfiles) { - // Most of the cases there should be only one, but in case there are multiple, choose the - // one which has longest life cycle. - DataProfile dataProfile = dataProfiles.stream() - .max(Comparator.comparingLong(DataProfile::getLastSetupTimestamp).reversed()) - .orElse(null); + private void onInternetDataNetworkConnected(@NonNull List internetNetworks) { + DataProfile defaultProfile = null; + if (internetNetworks.size() == 1) { + // Most of the cases there should be only one. + defaultProfile = internetNetworks.get(0).getDataProfile(); + } else if (internetNetworks.size() > 1) { + // but in case there are multiple, find the default internet network, and choose the + // one which has longest life cycle. + logv("onInternetDataNetworkConnected: mPreferredDataProfile=" + mPreferredDataProfile + + " internetNetworks=" + internetNetworks); + defaultProfile = internetNetworks.stream() + .filter(network -> mPreferredDataProfile == null + || canPreferredDataProfileSatisfy( + network.getAttachedNetworkRequestList())) + .map(DataNetwork::getDataProfile) + .min(Comparator.comparingLong(DataProfile::getLastSetupTimestamp)) + .orElse(null); + } // Update a working internet data profile as a future candidate for preferred data profile // after APNs are reset to default - mLastInternetDataProfile = dataProfile; + mLastInternetDataProfile = defaultProfile; - // If there is no preferred data profile, then we should use one of the data profiles, - // which is good for internet, as the preferred data profile. - if (mPreferredDataProfile != null) return; + // 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 + // profile so that this network won't be torn down in future network evaluations. + if (defaultProfile == null || defaultProfile.equals(mPreferredDataProfile)) return; // Save the preferred data profile into database. - setPreferredDataProfile(dataProfile); + setPreferredDataProfile(defaultProfile); updateDataProfiles(ONLY_UPDATE_IA_IF_CHANGED); } @@ -475,7 +488,7 @@ public class DataProfileManager extends Handler { * the preferred data profile from database. */ private void setPreferredDataProfile(@Nullable DataProfile dataProfile) { - log("setPreferredDataProfile: " + dataProfile); + logl("setPreferredDataProfile: " + dataProfile); String subId = Long.toString(mPhone.getSubId()); Uri uri = Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_URI, subId); @@ -773,6 +786,18 @@ public class DataProfileManager extends Handler { return areDataProfilesSharingApn(dataProfile, mPreferredDataProfile); } + /** + * @param networkRequests The required network requests + * @return {@code true} if we currently have a preferred data profile that's capable of + * satisfying the required network requests; {@code false} if we have no preferred, or the + * preferred cannot satisfy the required requests. + */ + public boolean canPreferredDataProfileSatisfy( + @NonNull DataNetworkController.NetworkRequestList networkRequests) { + return mPreferredDataProfile != null && networkRequests.stream() + .allMatch(request -> request.canBeSatisfiedBy(mPreferredDataProfile)); + } + /** * Check if there is tethering data profile for certain network type. * @@ -794,18 +819,6 @@ public class DataProfileManager extends Handler { return getDataProfileForNetworkRequest(networkRequest, networkType, true) != null; } - /** - * Check if any preferred data profile exists. - * - * @return {@code true} if any preferred data profile exists - */ - public boolean isAnyPreferredDataProfileExisting() { - for (DataProfile dataProfile : mAllDataProfiles) { - if (dataProfile.isPreferred()) return true; - } - return false; - } - /** * Dedupe the similar data profiles. */ @@ -1111,6 +1124,7 @@ public class DataProfileManager extends Handler { 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("Initial attach data profile=" + mInitialAttachDataProfile); pw.println("isTetheringDataProfileExisting=" + isTetheringDataProfileExisting( TelephonyManager.NETWORK_TYPE_LTE)); diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index df3ab57460..8bf9e55f1b 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -32,7 +32,6 @@ import android.telephony.Annotation.ValidationStatus; import android.telephony.CellSignalStrength; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; -import android.telephony.data.DataProfile; import android.util.IndentingPrintWriter; import android.util.LocalLog; @@ -265,7 +264,7 @@ public class DataStallRecoveryManager extends Handler { @Override public void onInternetDataNetworkConnected( - @NonNull List dataProfiles) { + @NonNull List internetNetworks) { mIsInternetNetworkConnected = true; logl("onInternetDataNetworkConnected"); } diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java index 5b78685701..7c63dec3a3 100644 --- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java +++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java @@ -30,12 +30,12 @@ import android.telephony.Annotation.NetworkType; import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.TelephonyManager; -import android.telephony.data.DataProfile; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.data.DataNetwork; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; import com.android.internal.telephony.imsphone.ImsPhone; @@ -93,7 +93,7 @@ public class ServiceStateStats extends DataNetworkControllerCallback { } /** Updates service state when internet pdn gets connected. */ - public void onInternetDataNetworkConnected(@NonNull List dataProfiles) { + public void onInternetDataNetworkConnected(@NonNull List internetNetworks) { onInternetDataNetworkChanged(true); } 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 0dded1247a..6e422606dd 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -144,6 +144,12 @@ public class DataNetworkControllerTest extends TelephonyTest { private static final String FAKE_MMTEL_PACKAGE = "fake.mmtel.package"; private static final String FAKE_RCS_PACKAGE = "fake.rcs.package"; + // Events + private static final int EVENT_SIM_STATE_CHANGED = 9; + private static final int EVENT_REEVALUATE_EXISTING_DATA_NETWORKS = 16; + private static final int EVENT_VOICE_CALL_ENDED = 18; + private static final int EVENT_SUBSCRIPTION_OVERRIDE = 23; + // Mocked classes private PhoneSwitcher mMockedPhoneSwitcher; protected ISub mMockedIsub; @@ -230,6 +236,36 @@ public class DataNetworkControllerTest extends TelephonyTest { .setPreferred(false) .build(); + // Created to test preferred data profiles that apply to different network types + private final DataProfile mGeneralPurposeDataProfileAlternative = new DataProfile.Builder() + .setApnSetting(new ApnSetting.Builder() + .setId(2161) + .setOperatorNumeric("12345") + .setEntryName("internet_supl_mms_apn") + .setApnName("internet_supl_mms_apn") + .setUser("user") + .setPassword("passwd") + .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL + | ApnSetting.TYPE_MMS) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .setCarrierEnabled(true) + .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | TelephonyManager.NETWORK_TYPE_BITMASK_NR + | TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN + | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT)) + .setLingeringNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_LTE + | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT + | TelephonyManager.NETWORK_TYPE_BITMASK_UMTS + | TelephonyManager.NETWORK_TYPE_BITMASK_NR)) + .setProfileId(4321) + .setMaxConns(321) + .setWaitTime(456) + .setMaxConnsTime(789) + .build()) + .setPreferred(false) + .build(); + private final DataProfile mImsCellularDataProfile = new DataProfile.Builder() .setApnSetting(new ApnSetting.Builder() .setId(2164) @@ -321,7 +357,7 @@ public class DataNetworkControllerTest extends TelephonyTest { .setApnName("dun_apn") .setUser("user") .setPassword("passwd") - .setApnTypeBitmask(ApnSetting.TYPE_DUN) + .setApnTypeBitmask(ApnSetting.TYPE_DUN | ApnSetting.TYPE_DEFAULT) .setProtocol(ApnSetting.PROTOCOL_IPV6) .setRoamingProtocol(ApnSetting.PROTOCOL_IP) .setCarrierEnabled(true) @@ -836,7 +872,8 @@ public class DataNetworkControllerTest extends TelephonyTest { linkBandwidthEstimatorCallbackCaptor.capture()); mLinkBandwidthEstimatorCallback = linkBandwidthEstimatorCallbackCaptor.getValue(); - List profiles = List.of(mGeneralPurposeDataProfile, mImsCellularDataProfile, + List profiles = List.of(mGeneralPurposeDataProfile, + mGeneralPurposeDataProfileAlternative, mImsCellularDataProfile, mImsIwlanDataProfile, mEmergencyDataProfile, mFotaDataProfile, mTetheringDataProfile); @@ -889,7 +926,6 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(anyInt()); - doReturn(true).when(mDataProfileManager).isDataProfilePreferred(any(DataProfile.class)); doAnswer(invocation -> { ((Runnable) invocation.getArguments()[0]).run(); @@ -903,7 +939,7 @@ public class DataNetworkControllerTest extends TelephonyTest { mDataNetworkControllerUT.registerDataNetworkControllerCallback( mMockedDataNetworkControllerCallback); - mDataNetworkControllerUT.obtainMessage(9/*EVENT_SIM_STATE_CHANGED*/, + mDataNetworkControllerUT.obtainMessage(EVENT_SIM_STATE_CHANGED, 10/*SIM_STATE_LOADED*/, 0).sendToTarget(); mDataNetworkControllerUT.obtainMessage(8/*EVENT_DATA_SERVICE_BINDING_CHANGED*/, new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, true, null)) @@ -1259,7 +1295,7 @@ public class DataNetworkControllerTest extends TelephonyTest { public void testSimRemovalDataTearDown() throws Exception { testSetupDataNetwork(); - mDataNetworkControllerUT.obtainMessage(9/*EVENT_SIM_STATE_CHANGED*/, + mDataNetworkControllerUT.obtainMessage(EVENT_SIM_STATE_CHANGED, TelephonyManager.SIM_STATE_ABSENT, 0).sendToTarget(); processAllMessages(); verifyAllDataDisconnected(); @@ -1273,7 +1309,7 @@ public class DataNetworkControllerTest extends TelephonyTest { Mockito.clearInvocations(mMockedDataNetworkControllerCallback); // Insert the SIM again. - mDataNetworkControllerUT.obtainMessage(9/*EVENT_SIM_STATE_CHANGED*/, + mDataNetworkControllerUT.obtainMessage(EVENT_SIM_STATE_CHANGED, TelephonyManager.SIM_STATE_LOADED, 0).sendToTarget(); processAllMessages(); @@ -1482,7 +1518,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Call ended. doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); - mDataNetworkControllerUT.obtainMessage(18/*EVENT_VOICE_CALL_ENDED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_VOICE_CALL_ENDED).sendToTarget(); processAllMessages(); // It should have no internet setup at the beginning. @@ -1952,7 +1988,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Set 5G unmetered congestedNetworkTypes.add(TelephonyManager.NETWORK_TYPE_NR); - mDataNetworkControllerUT.obtainMessage(23/*EVENT_SUBSCRIPTION_OVERRIDE*/, + mDataNetworkControllerUT.obtainMessage(EVENT_SUBSCRIPTION_OVERRIDE, NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED, NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED, new int[]{TelephonyManager.NETWORK_TYPE_NR}).sendToTarget(); @@ -1974,7 +2010,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Set all network types metered congestedNetworkTypes.clear(); - mDataNetworkControllerUT.obtainMessage(23/*EVENT_SUBSCRIPTION_OVERRIDE*/, + mDataNetworkControllerUT.obtainMessage(EVENT_SUBSCRIPTION_OVERRIDE, NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED, 0, TelephonyManager.getAllNetworkTypes()).sendToTarget(); dataNetwork.sendMessage(16/*EVENT_SUBSCRIPTION_PLAN_OVERRIDE*/); @@ -1994,7 +2030,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Set 5G unmetered unmeteredNetworkTypes.add(TelephonyManager.NETWORK_TYPE_NR); - mDataNetworkControllerUT.obtainMessage(23/*EVENT_SUBSCRIPTION_OVERRIDE*/, + mDataNetworkControllerUT.obtainMessage(EVENT_SUBSCRIPTION_OVERRIDE, NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED, NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED, new int[]{TelephonyManager.NETWORK_TYPE_NR}).sendToTarget(); @@ -2018,7 +2054,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Set all network types metered unmeteredNetworkTypes.clear(); - mDataNetworkControllerUT.obtainMessage(23/*EVENT_SUBSCRIPTION_OVERRIDE*/, + mDataNetworkControllerUT.obtainMessage(EVENT_SUBSCRIPTION_OVERRIDE, NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED, 0, TelephonyManager.getAllNetworkTypes()).sendToTarget(); dataNetwork.sendMessage(16/*EVENT_SUBSCRIPTION_PLAN_OVERRIDE*/); @@ -2113,7 +2149,7 @@ public class DataNetworkControllerTest extends TelephonyTest { NetworkCapabilities.NET_CAPABILITY_MMTEL); // Both internet and IMS should be retained after network re-evaluation - mDataNetworkControllerUT.obtainMessage(16/*EVENT_REEVALUATE_EXISTING_DATA_NETWORKS*/) + mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) .sendToTarget(); processAllMessages(); @@ -2133,7 +2169,7 @@ public class DataNetworkControllerTest extends TelephonyTest { NetworkCapabilities.NET_CAPABILITY_MMTEL); // Both internet and IMS should be retained after network re-evaluation - mDataNetworkControllerUT.obtainMessage(16/*EVENT_REEVALUATE_EXISTING_DATA_NETWORKS*/) + mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) .sendToTarget(); processAllMessages(); @@ -2508,7 +2544,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Verify tear down after call ends doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); - mDataNetworkControllerUT.obtainMessage(18/*EVENT_VOICE_CALL_ENDED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_VOICE_CALL_ENDED).sendToTarget(); processAllFutureMessages(); verify(mMockedWlanDataServiceManager).deactivateDataCall(anyInt(), @@ -2837,8 +2873,8 @@ public class DataNetworkControllerTest extends TelephonyTest { // There should be only one attempt, and no retry should happen because it's a permanent // failure. verify(mMockedWwanDataServiceManager, times(1)).setupDataCall(anyInt(), - any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), - any(), any(), anyBoolean(), any(Message.class)); + eq(mGeneralPurposeDataProfile), anyBoolean(), anyBoolean(), anyInt(), any(), + anyInt(), any(), any(), anyBoolean(), any(Message.class)); Mockito.clearInvocations(mMockedWwanDataServiceManager); mDataNetworkControllerUT.addNetworkRequest( @@ -3170,6 +3206,73 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyAllDataDisconnected(); } + @Test + public void testSetPreferredDataProfileMultiInternetDataProfile() throws Exception { + // No preferred data profile in the beginning + doReturn(false).when(mDataProfileManager).canPreferredDataProfileSatisfy( + any(NetworkRequestList.class)); + + testSetupDataNetwork(); + + // Verify this network still alive after evaluation + mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) + .sendToTarget(); + processAllMessages(); + + verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); + + // Network connected, became preferred data profile + doAnswer(invocation -> { + NetworkRequestList networkRequests = + (NetworkRequestList) invocation.getArguments()[0]; + return networkRequests.stream() + .allMatch(request -> request.canBeSatisfiedBy(mGeneralPurposeDataProfile)); + }).when(mDataProfileManager).canPreferredDataProfileSatisfy( + any(NetworkRequestList.class)); + doReturn(true).when(mDataProfileManager) + .isDataProfilePreferred(mGeneralPurposeDataProfile); + + // 1. Test DUN | DEFAULT data profile is compatible with preferred default internet + mDataNetworkControllerUT.addNetworkRequest( + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_DUN)); + setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 2); + processAllMessages(); + + // Verify both DUN and preferred default network are alive + verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); + verifyConnectedNetworkHasDataProfile(mTetheringDataProfile); + + // Verify this network still alive after evaluation + mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) + .sendToTarget(); + processAllMessages(); + + verifyConnectedNetworkHasDataProfile(mGeneralPurposeDataProfile); + verifyConnectedNetworkHasDataProfile(mTetheringDataProfile); + + // 2. Test tear down when user changes preferred data profile + doAnswer(invocation -> { + NetworkRequestList networkRequests = + (NetworkRequestList) invocation.getArguments()[0]; + return networkRequests.stream() + .allMatch(request -> request.canBeSatisfiedBy( + mGeneralPurposeDataProfileAlternative)); + }).when(mDataProfileManager).canPreferredDataProfileSatisfy( + any(NetworkRequestList.class)); + doReturn(true).when(mDataProfileManager) + .isDataProfilePreferred(mGeneralPurposeDataProfileAlternative); + doReturn(false).when(mDataProfileManager) + .isDataProfilePreferred(mGeneralPurposeDataProfile); + + mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) + .sendToTarget(); + processAllMessages(); + + List dataNetworks = getDataNetworks(); + assertThat(dataNetworks).hasSize(1); + verifyConnectedNetworkHasDataProfile(mTetheringDataProfile); + } + @Test public void testDataDisableNotAllowingBringingUpTetheringNetwork() throws Exception { // User data disabled @@ -3429,11 +3532,11 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_DUN); mDataNetworkControllerUT.addNetworkRequest( - createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); + createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)); processAllFutureMessages(); // Lower priority network should not trump the higher priority network. verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_DUN); - verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_ENTERPRISE); // Now send a higher priority network request TelephonyNetworkRequest fotaRequest = createNetworkRequest( @@ -3684,7 +3787,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // 2. Normal case (call ended), should tear down doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); - mDataNetworkControllerUT.obtainMessage(18/*EVENT_VOICE_CALL_ENDED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_VOICE_CALL_ENDED).sendToTarget(); processAllFutureMessages(); // Verify that handover is not performed. @@ -4061,7 +4164,7 @@ public class DataNetworkControllerTest extends TelephonyTest { mCarrierConfig.putBoolean(CarrierConfigManager.Ims.KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, false); carrierConfigChanged(); - mDataNetworkControllerUT.obtainMessage(16/*EVENT_REEVALUATE_EXISTING_DATA_NETWORKS*/) + mDataNetworkControllerUT.obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS) .sendToTarget(); processAllMessages(); @@ -4111,7 +4214,7 @@ public class DataNetworkControllerTest extends TelephonyTest { // Call ends doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); - mDataNetworkControllerUT.obtainMessage(18/*EVENT_VOICE_CALL_ENDED*/).sendToTarget(); + mDataNetworkControllerUT.obtainMessage(EVENT_VOICE_CALL_ENDED).sendToTarget(); processAllMessages(); verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); @@ -4131,7 +4234,7 @@ public class DataNetworkControllerTest extends TelephonyTest { testSetupDataNetwork(); - mDataNetworkControllerUT.obtainMessage(9/*EVENT_SIM_STATE_CHANGED*/, + mDataNetworkControllerUT.obtainMessage(EVENT_SIM_STATE_CHANGED, TelephonyManager.SIM_STATE_ABSENT, 0).sendToTarget(); processAllMessages(); verifyAllDataDisconnected(); 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 1fbe386e11..43f65e21c4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java @@ -75,6 +75,7 @@ import java.util.stream.Collectors; @TestableLooper.RunWithLooper public class DataProfileManagerTest extends TelephonyTest { private static final String GENERAL_PURPOSE_APN = "GP_APN"; + private static final String GENERAL_PURPOSE_APN_LEGACY_RAT = "GP_APN_RAT"; private static final String GENERAL_PURPOSE_APN1 = "GP_APN1"; private static final String IMS_APN = "IMS_APN"; private static final String TETHERING_APN = "DUN_APN"; @@ -170,6 +171,41 @@ public class DataProfileManagerTest extends TelephonyTest { -1, // skip_464xlat 0 // always_on }, + // default internet data profile for RAT CDMA, to test update preferred data profile + new Object[]{ + 9, // id + PLMN, // numeric + GENERAL_PURPOSE_APN_LEGACY_RAT, // name + GENERAL_PURPOSE_APN_LEGACY_RAT, // apn + "", // proxy + "", // port + "", // mmsc + "", // mmsproxy + "", // mmsport + "", // user + "", // password + -1, // authtype + "default,supl,mms,ia", // types + "IPV4V6", // protocol + "IPV4V6", // roaming_protocol + 1, // carrier_enabled + 0, // profile_id + 1, // modem_cognitive + 0, // max_conns + 0, // wait_time + 0, // max_conns_time + 0, // mtu + 1280, // mtu_v4 + 1280, // mtu_v6 + "", // mvno_type + "", // mnvo_match_data + TelephonyManager.NETWORK_TYPE_BITMASK_CDMA, // network_type_bitmask + 0, // lingering_network_type_bitmask + DEFAULT_APN_SET_ID, // apn_set_id + -1, // carrier_id + -1, // skip_464xlat + 0 // always_on + }, new Object[]{ 2, // id PLMN, // numeric @@ -777,13 +813,51 @@ public class DataProfileManagerTest extends TelephonyTest { assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); dataProfile.setPreferred(true); - mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(dataProfile)); + DataNetwork internetNetwork = Mockito.mock(DataNetwork.class); + doReturn(dataProfile).when(internetNetwork).getDataProfile(); + doReturn(new DataNetworkController.NetworkRequestList(List.of(tnr))) + .when(internetNetwork).getAttachedNetworkRequestList(); + mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(internetNetwork)); processAllMessages(); - // See if the same one can be returned. + // Test See if the same one can be returned. dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); + assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); + + // Test Another default internet network connected due to RAT changed. Verify the preferred + // data profile is updated. + DataProfile legacyRatDataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + tnr, TelephonyManager.NETWORK_TYPE_CDMA, false); + DataNetwork legacyRatInternetNetwork = Mockito.mock(DataNetwork.class); + doReturn(legacyRatDataProfile).when(legacyRatInternetNetwork).getDataProfile(); + doReturn(new DataNetworkController.NetworkRequestList(List.of(tnr))) + .when(legacyRatInternetNetwork).getAttachedNetworkRequestList(); + mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of( + // Because internetNetwork is torn down due to network type mismatch + legacyRatInternetNetwork)); + processAllMessages(); + + assertThat(mDataProfileManagerUT.isDataProfilePreferred(legacyRatDataProfile)).isTrue(); + + // Test Another supl default internet network temporarily connected. Verify preferred + // doesn't change. + TelephonyNetworkRequest suplTnr = new TelephonyNetworkRequest( + new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL) + .build(), mPhone); + DataProfile suplDataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + suplTnr, TelephonyManager.NETWORK_TYPE_LTE, false); + DataNetwork suplInternetNetwork = Mockito.mock(DataNetwork.class); + doReturn(suplDataProfile).when(suplInternetNetwork).getDataProfile(); + doReturn(new DataNetworkController.NetworkRequestList(List.of(suplTnr))) + .when(suplInternetNetwork).getAttachedNetworkRequestList(); + mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of( + legacyRatInternetNetwork, suplInternetNetwork)); + processAllMessages(); + + assertThat(mDataProfileManagerUT.isDataProfilePreferred(legacyRatDataProfile)).isTrue(); } @Test @@ -1065,11 +1139,12 @@ public class DataProfileManagerTest extends TelephonyTest { tnr, TelephonyManager.NETWORK_TYPE_LTE, false); assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime()); - mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(dataProfile)); + DataNetwork internetNetwork = Mockito.mock(DataNetwork.class); + doReturn(dataProfile).when(internetNetwork).getDataProfile(); + mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(internetNetwork)); processAllMessages(); // After internet connected, preferred APN should be set - assertThat(mDataProfileManagerUT.isAnyPreferredDataProfileExisting()).isTrue(); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); // APN reset @@ -1078,7 +1153,6 @@ public class DataProfileManagerTest extends TelephonyTest { processAllMessages(); // preferred APN should set to be the last data profile that succeeded for internet setup - assertThat(mDataProfileManagerUT.isAnyPreferredDataProfileExisting()).isTrue(); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); // Test user selected a bad data profile, expects to adopt the last data profile that @@ -1088,7 +1162,6 @@ public class DataProfileManagerTest extends TelephonyTest { mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget(); processAllMessages(); - assertThat(mDataProfileManagerUT.isAnyPreferredDataProfileExisting()).isTrue(); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isFalse(); // APN reset, preferred APN should set to be the last data profile that succeeded for @@ -1097,11 +1170,10 @@ public class DataProfileManagerTest extends TelephonyTest { mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget(); processAllMessages(); - assertThat(mDataProfileManagerUT.isAnyPreferredDataProfileExisting()).isTrue(); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue(); // Test removed data profile(user created after reset) shouldn't show up - mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(dataProfile)); + mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(internetNetwork)); processAllMessages(); //APN reset and removed GENERAL_PURPOSE_APN from APN DB mPreferredApnId = -1; @@ -1110,7 +1182,6 @@ public class DataProfileManagerTest extends TelephonyTest { processAllMessages(); // There should be no preferred APN after APN reset because last working profile is removed - assertThat(mDataProfileManagerUT.isAnyPreferredDataProfileExisting()).isFalse(); assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isFalse(); // restore mApnSettingContentProvider @@ -1194,7 +1265,7 @@ public class DataProfileManagerTest extends TelephonyTest { } @Test - public void testDataProfileCompatibility() throws Exception { + public void testDataProfileCompatibility() { DataProfile enterpriseDataProfile = new DataProfile.Builder() .setTrafficDescriptor(new TrafficDescriptor(null, new TrafficDescriptor.OsAppId(TrafficDescriptor.OsAppId.ANDROID_OS_ID, diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java index 25284413a9..6781ce3ae7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java @@ -29,7 +29,6 @@ import static org.mockito.Mockito.verify; import android.net.NetworkAgent; import android.telephony.Annotation.ValidationStatus; import android.telephony.CarrierConfigManager; -import android.telephony.data.DataProfile; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -117,7 +116,7 @@ public class DataStallRecoveryManagerTest extends TelephonyTest { dataNetworkControllerCallbackCaptor.getValue(); if (isConnected) { - List dataprofile = new ArrayList(); + List dataprofile = new ArrayList<>(); dataNetworkControllerCallback.onInternetDataNetworkConnected(dataprofile); } else { dataNetworkControllerCallback.onInternetDataNetworkDisconnected(); -- GitLab From 1078247cba23580f0e98f15b9cbd8730caa86980 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 14 Mar 2023 20:22:08 -0700 Subject: [PATCH 522/656] Fixed data activity not updated We should always update data activity when there is a change. Fix: 273620126 Test: atest LinkBandwidthEstimatorTest#testDataActivity Change-Id: I96b6e93bb20adb470250887cd175bbfce14ac032 --- .../data/LinkBandwidthEstimator.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index 5ceb5e46e1..c04698b76b 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -458,6 +458,23 @@ public class LinkBandwidthEstimator extends Handler { long txBytesDelta = mobileTxBytes - mLastMobileTxBytes; long rxBytesDelta = mobileRxBytes - mLastMobileRxBytes; + int dataActivity; + if (txBytesDelta > 0 && rxBytesDelta > 0) { + dataActivity = TelephonyManager.DATA_ACTIVITY_INOUT; + } else if (rxBytesDelta > 0) { + dataActivity = TelephonyManager.DATA_ACTIVITY_IN; + } else if (txBytesDelta > 0) { + dataActivity = TelephonyManager.DATA_ACTIVITY_OUT; + } else { + dataActivity = TelephonyManager.DATA_ACTIVITY_NONE; + } + + if (mDataActivity != dataActivity) { + mDataActivity = dataActivity; + mLinkBandwidthEstimatorCallbacks.forEach(callback -> callback.invokeFromExecutor( + () -> callback.onDataActivityChanged(dataActivity))); + } + // Schedule the next traffic stats poll sendEmptyMessageDelayed(MSG_TRAFFIC_STATS_POLL, TRAFFIC_STATS_POLL_INTERVAL_MS); @@ -506,23 +523,6 @@ public class LinkBandwidthEstimator extends Handler { return; } - int dataActivity; - if (txBytesDelta > 0 && rxBytesDelta > 0) { - dataActivity = TelephonyManager.DATA_ACTIVITY_INOUT; - } else if (rxBytesDelta > 0) { - dataActivity = TelephonyManager.DATA_ACTIVITY_IN; - } else if (txBytesDelta > 0) { - dataActivity = TelephonyManager.DATA_ACTIVITY_OUT; - } else { - dataActivity = TelephonyManager.DATA_ACTIVITY_NONE; - } - - if (mDataActivity != dataActivity) { - mDataActivity = dataActivity; - mLinkBandwidthEstimatorCallbacks.forEach(callback -> callback.invokeFromExecutor( - () -> callback.onDataActivityChanged(dataActivity))); - } - long timeSinceLastFilterUpdateMs = currTimeMs - mFilterUpdateTimeMs; // Update filter if (timeSinceLastFilterUpdateMs >= FILTER_UPDATE_MAX_INTERVAL_MS) { -- GitLab From fd3cb8352c995c671d6ff1a925f87f1961b052bf Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Fri, 10 Mar 2023 14:49:58 -0800 Subject: [PATCH 523/656] Add implementation of SatelliteSessionController MUST_SLEEP in the unit test. Bug: 269194948 Test: Test call/SMS with live network. atest com.android.internal.telephony.satellite.SatelliteSessionControllerTest atest android.telephony.cts.SatelliteManagerTest Change-Id: Ie8d2faa050cc44c8a825ac0b6e615eafa00b39e2 --- .../satellite/SatelliteController.java | 134 +++-- .../satellite/SatelliteModemInterface.java | 35 +- .../satellite/SatelliteSessionController.java | 422 +++++++++++++++- .../SatelliteSessionControllerTest.java | 468 ++++++++++++++++++ 4 files changed, 988 insertions(+), 71 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 22da55051c..2c85ac225e 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -45,7 +45,6 @@ import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.util.Log; - import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IIntegerConsumer; @@ -96,7 +95,7 @@ public class SatelliteController extends Handler { @NonNull private static SatelliteController sInstance; @NonNull private final Context mContext; @NonNull private final SatelliteModemInterface mSatelliteModemInterface; - @NonNull private final SatelliteSessionController mSatelliteSessionController; + @NonNull private SatelliteSessionController mSatelliteSessionController; @NonNull private final PointingAppController mPointingAppController; @NonNull private final DatagramController mDatagramController; private final CommandsInterface mCi; @@ -127,6 +126,9 @@ public class SatelliteController extends Handler { private final Object mIsSatelliteSupportedLock = new Object(); private final ResultReceiver mSatelliteSupportedReceiver; private boolean mIsDemoModeEnabled = false; + private Boolean mIsSatelliteEnabled = null; + private final Object mIsSatelliteEnabledLock = new Object(); + private final ResultReceiver mSatelliteEnabledReceiver; private boolean mNeedsSatellitePointing = false; private final Object mNeedsSatellitePointingLock = new Object(); @@ -159,7 +161,7 @@ public class SatelliteController extends Handler { * @param context The Context for the SatelliteController. * @param looper The looper for the handler. It does not run on main thread. */ - @VisibleForTesting + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected SatelliteController(@NonNull Context context, @NonNull Looper looper) { super(looper); mContext = context; @@ -169,10 +171,6 @@ public class SatelliteController extends Handler { // to the satellite service and HAL interface. mSatelliteModemInterface = SatelliteModemInterface.make(mContext); - // Create the SatelliteSessionController singleton, - // which is used to manage all the data during a satellite session. - mSatelliteSessionController = SatelliteSessionController.make(mContext); - // Create the PointingUIController singleton, // which is used to manage interactions with PointingUI app. mPointingAppController = PointingAppController.make(mContext); @@ -181,22 +179,8 @@ public class SatelliteController extends Handler { // which is used to send and receive satellite datagrams. mDatagramController = DatagramController.make(mContext, looper); - mSatelliteSupportedReceiver = new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE - && resultData.containsKey(SatelliteManager.KEY_SATELLITE_SUPPORTED)) { - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = resultData.getBoolean( - SatelliteManager.KEY_SATELLITE_SUPPORTED); - } - } else { - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = null; - } - } - } - }; + mSatelliteEnabledReceiver = createSatelliteEnabledResultReceiver(); + mSatelliteSupportedReceiver = createSatelliteSupportedResultReceiver(looper); //TODO: reenable below code //requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, // mSatelliteSupportedReceiver); @@ -356,13 +340,6 @@ public class SatelliteController extends Handler { int state = (int) ar.result; logd("Received EVENT_SATELLITE_MODEM_STATE_CHANGE for subId=" + mSubId + ", state=" + state); - mListeners.values().forEach(listener -> { - try { - listener.onSatelliteModemStateChanged(state); - } catch (RemoteException e) { - logd("EVENT_SATELLITE_MODEM_STATE_CHANGE RemoteException: " + e); - } - }); break; } case EVENT_PENDING_DATAGRAMS: { @@ -544,6 +521,8 @@ public class SatelliteController extends Handler { mPointingAppController.startPointingUI(false); } mIsDemoModeEnabled = argument.enableDemoMode; + updateSatelliteEnabledState( + argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); } argument.callback.accept(error); // TODO: if error is ERROR_NONE, request satellite capabilities @@ -624,10 +603,6 @@ public class SatelliteController extends Handler { mIsSatelliteSupported = supported; } } - } else { - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = null; - } } ((ResultReceiver) request.argument).send(error, bundle); break; @@ -866,8 +841,17 @@ public class SatelliteController extends Handler { return; } - Phone phone = SatelliteServiceUtils.getPhone(); - sendRequest(CMD_IS_SATELLITE_ENABLED, result, phone); + synchronized (mIsSatelliteEnabledLock) { + if (mIsSatelliteEnabled != null) { + /* We have already successfully queried the satellite modem. */ + Bundle bundle = new Bundle(); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, mIsSatelliteEnabled); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + return; + } + } + + sendRequest(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); } /** @@ -908,13 +892,12 @@ public class SatelliteController extends Handler { /* We have already successfully queried the satellite modem. */ Bundle bundle = new Bundle(); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, mIsSatelliteSupported); - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, bundle); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); return; } } - Phone phone = SatelliteServiceUtils.getPhone(); - sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, phone); + sendRequestAsync(CMD_IS_SATELLITE_SUPPORTED, result, SatelliteServiceUtils.getPhone()); } /** @@ -1163,9 +1146,15 @@ public class SatelliteController extends Handler { */ @SatelliteManager.SatelliteError public int registerForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - Phone phone = SatelliteServiceUtils.getPhone(); + if (mSatelliteSessionController != null) { + mSatelliteSessionController.registerForSatelliteModemStateChanged(callback); + } else { + loge("registerForSatelliteModemStateChanged: mSatelliteSessionController" + + " is not initialized yet"); + return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); SatelliteStateListenerHandler satelliteStateListenerHandler = mSatelliteStateListenerHandlers.get(validSubId); if (satelliteStateListenerHandler == null) { @@ -1178,6 +1167,12 @@ public class SatelliteController extends Handler { mSatelliteModemInterface.registerForPendingDatagrams(satelliteStateListenerHandler, SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone == null) { + loge("registerForSatelliteModemStateChanged: satellite phone is " + + "not initialized yet"); + return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } phone.registerForSatelliteModemStateChanged(satelliteStateListenerHandler, SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); phone.registerForPendingDatagramCount(satelliteStateListenerHandler, @@ -1218,6 +1213,13 @@ public class SatelliteController extends Handler { } } } + + if (mSatelliteSessionController != null) { + mSatelliteSessionController.unregisterForSatelliteModemStateChanged(callback); + } else { + loge("registerForSatelliteModemStateChanged: mSatelliteSessionController" + + " is not initialized yet"); + } } /** @@ -1504,7 +1506,7 @@ public class SatelliteController extends Handler { * @param subId The subscription id. * @return true if satellite is provisioned on the given subscription else return false. */ - @VisibleForTesting + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected boolean isSatelliteProvisioned(int subId) { final long identity = Binder.clearCallingIdentity(); try { @@ -1538,7 +1540,7 @@ public class SatelliteController extends Handler { Message onCompleted = obtainMessage(EVENT_SET_SATELLITE_ENABLED_DONE, request); if (mSatelliteModemInterface.isSatelliteServiceSupported()) { mSatelliteModemInterface.requestSatelliteEnabled(argument.enableSatellite, - argument.enableDemoMode, onCompleted); + argument.enableDemoMode, onCompleted); return; } Phone phone = request.phone; @@ -1550,6 +1552,52 @@ public class SatelliteController extends Handler { } } + private ResultReceiver createSatelliteSupportedResultReceiver(@NonNull Looper looper) { + return new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE + && resultData.containsKey(SatelliteManager.KEY_SATELLITE_SUPPORTED)) { + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = resultData.getBoolean( + SatelliteManager.KEY_SATELLITE_SUPPORTED); + } + } + mSatelliteSessionController = SatelliteSessionController.make(mContext, looper, + mIsSatelliteSupported != null ? mIsSatelliteSupported : false); + if (mIsSatelliteSupported != null && mIsSatelliteSupported) { + requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mSatelliteEnabledReceiver); + } + } + }; + } + + private ResultReceiver createSatelliteEnabledResultReceiver() { + return new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE + && resultData.containsKey(SatelliteManager.KEY_SATELLITE_ENABLED)) { + updateSatelliteEnabledState(resultData.getBoolean( + SatelliteManager.KEY_SATELLITE_ENABLED), + "SatelliteEnabledResultReceiver.onReceiveResult"); + } + } + }; + } + + private void updateSatelliteEnabledState(boolean enabled, String caller) { + synchronized (mIsSatelliteEnabledLock) { + mIsSatelliteEnabled = enabled; + } + if (mSatelliteSessionController != null) { + mSatelliteSessionController.onSatelliteEnabledStateChanged(enabled); + } else { + loge(caller + ": mSatelliteSessionController is not initialized yet"); + } + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 00be71dc93..311cee393f 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -42,6 +42,7 @@ import android.telephony.satellite.stub.SatelliteService; import android.text.TextUtils; import android.util.Pair; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ExponentialBackoff; import com.android.internal.telephony.IBooleanConsumer; import com.android.internal.telephony.IIntegerConsumer; @@ -59,7 +60,8 @@ public class SatelliteModemInterface { @NonNull private static SatelliteModemInterface sInstance; @NonNull private final Context mContext; - @NonNull private final ExponentialBackoff mExponentialBackoff; + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + @NonNull protected final ExponentialBackoff mExponentialBackoff; @NonNull private final Object mLock = new Object(); /** * {@code true} to use the vendor satellite service and {@code false} to use the HAL. @@ -161,7 +163,8 @@ public class SatelliteModemInterface { * @param context The Context for the SatelliteModemInterface. * @param looper The Looper to run binding retry on. */ - private SatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected SatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { mContext = context; mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, REBIND_MULTIPLIER, looper, () -> { @@ -198,7 +201,8 @@ public class SatelliteModemInterface { com.android.internal.R.string.config_satellite_service_package)); } - private void bindService() { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected void bindService() { synchronized (mLock) { if (mIsBinding || mIsBound) return; mIsBinding = true; @@ -241,7 +245,8 @@ public class SatelliteModemInterface { } } - private void unbindService() { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected void unbindService() { disconnectSatelliteService(); mContext.unbindService(mSatelliteServiceConnection); mSatelliteServiceConnection = null; @@ -427,7 +432,7 @@ public class SatelliteModemInterface { * @param message The Message to send to result of the operation to. */ public void requestSatelliteListeningEnabled(boolean enable, int timeout, - @NonNull Message message) { + @Nullable Message message) { if (mSatelliteService != null) { try { mSatelliteService.requestSatelliteListeningEnabled(enable, timeout, @@ -436,17 +441,26 @@ public class SatelliteModemInterface { public void accept(int result) { int error = SatelliteServiceUtils.fromSatelliteError(result); logd("requestSatelliteListeningEnabled: " + error); - Binder.withCleanCallingIdentity(() -> - sendMessageWithResult(message, null, error)); + Binder.withCleanCallingIdentity(() -> { + if (message != null) { + sendMessageWithResult(message, null, error); + } + }); } }); } catch (RemoteException e) { loge("requestSatelliteListeningEnabled: RemoteException " + e); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + if (message != null) { + sendMessageWithResult( + message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } } } else { loge("requestSatelliteListeningEnabled: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + if (message != null) { + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + } } } @@ -935,7 +949,8 @@ public class SatelliteModemInterface { return mIsSatelliteServiceSupported; } - private static void sendMessageWithResult(@NonNull Message message, @Nullable Object result, + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected static void sendMessageWithResult(@NonNull Message message, @Nullable Object result, @SatelliteManager.SatelliteError int error) { SatelliteException exception = error == SatelliteManager.SATELLITE_ERROR_NONE ? null : new SatelliteException(error); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index 98b9cad85f..be252f4dcc 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -16,38 +16,107 @@ package com.android.internal.telephony.satellite; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS; + import android.annotation.NonNull; import android.content.Context; +import android.os.IBinder; import android.os.Looper; -import android.telephony.Rlog; +import android.os.Message; +import android.os.RemoteException; +import android.provider.DeviceConfig; +import android.telephony.satellite.ISatelliteStateCallback; +import android.telephony.satellite.SatelliteManager; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; /** - * Satellite session controller to manage all the data during a satellite session. + * This module is responsible for managing session state transition and inform listeners of modem + * state changed events accordingly. */ -public class SatelliteSessionController { +public class SatelliteSessionController extends StateMachine { private static final String TAG = "SatelliteSessionController"; + private static final boolean DBG = true; + + /** + * The time duration in millis that the satellite will stay at listening mode to wait for the + * next incoming page before disabling listening mode when transitioning from sending mode. + */ + public static final String SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS = + "satellite_stay_at_listening_from_sending_millis"; + /** + * The default value of {@link #SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS}. + */ + public static final long DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS = 180000; + /** + * The time duration in millis that the satellite will stay at listening mode to wait for the + * next incoming page before disabling listening mode when transitioning from receiving mode. + */ + public static final String SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS = + "satellite_stay_at_listening_from_receiving_millis"; + /** + * The default value of {@link #SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS} + */ + public static final long DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS = 30000; + + private static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 1; + private static final int EVENT_LISTENING_TIMER_TIMEOUT = 2; + private static final int EVENT_SATELLITE_ENABLED_STATE_CHANGED = 3; @NonNull private static SatelliteSessionController sInstance; + @NonNull private final Context mContext; + @NonNull private final SatelliteModemInterface mSatelliteModemInterface; + @NonNull private final UnavailableState mUnavailableState = new UnavailableState(); + @NonNull private final PowerOffState mPowerOffState = new PowerOffState(); + @NonNull private final IdleState mIdleState = new IdleState(); + @NonNull private final TransferringState mTransferringState = new TransferringState(); + @NonNull private final ListeningState mListeningState = new ListeningState(); + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected AtomicBoolean mIsSendingTriggeredDuringTransferringState; + private final long mSatelliteStayAtListeningFromSendingMillis; + private final long mSatelliteStayAtListeningFromReceivingMillis; + private final ConcurrentHashMap mListeners; /** * @return The singleton instance of SatelliteSessionController. */ public static SatelliteSessionController getInstance() { if (sInstance == null) { - loge("SatelliteSessionController was not yet initialized."); + Log.e(TAG, "SatelliteSessionController was not yet initialized."); } return sInstance; } /** * Create the SatelliteSessionController singleton instance. - * @param context The Context to use to create the SatelliteSessionController. + * + * @param context The Context for the SatelliteSessionController. + * @param looper The looper associated with the handler of this class. + * @param isSatelliteSupported Whether satellite is supported on the device. * @return The singleton instance of SatelliteSessionController. */ - public static SatelliteSessionController make(@NonNull Context context) { + public static SatelliteSessionController make( + @NonNull Context context, @NonNull Looper looper, boolean isSatelliteSupported) { if (sInstance == null) { - sInstance = new SatelliteSessionController(context); + sInstance = new SatelliteSessionController(context, looper, isSatelliteSupported, + SatelliteModemInterface.getInstance(), + getSatelliteStayAtListeningFromSendingMillis(), + getSatelliteStayAtListeningFromReceivingMillis()); } return sInstance; } @@ -56,25 +125,342 @@ public class SatelliteSessionController { * Create a SatelliteSessionController to manage satellite session. * * @param context The Context for the SatelliteSessionController. + * @param looper The looper associated with the handler of this class. + * @param isSatelliteSupported Whether satellite is supported on the device. + * @param satelliteModemInterface The singleton of SatelliteModemInterface. + * @param satelliteStayAtListeningFromSendingMillis The duration to stay at listening mode when + * transitioning from sending mode. + * @param satelliteStayAtListeningFromReceivingMillis The duration to stay at listening mode + * when transitioning from receiving mode. */ - private SatelliteSessionController(@NonNull Context context) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected SatelliteSessionController(@NonNull Context context, @NonNull Looper looper, + boolean isSatelliteSupported, + @NonNull SatelliteModemInterface satelliteModemInterface, + long satelliteStayAtListeningFromSendingMillis, + long satelliteStayAtListeningFromReceivingMillis) { + super(TAG, looper); + mContext = context; + mSatelliteModemInterface = satelliteModemInterface; + mSatelliteStayAtListeningFromSendingMillis = satelliteStayAtListeningFromSendingMillis; + mSatelliteStayAtListeningFromReceivingMillis = satelliteStayAtListeningFromReceivingMillis; + mListeners = new ConcurrentHashMap<>(); + mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false); + + addState(mUnavailableState); + addState(mPowerOffState); + addState(mIdleState); + addState(mTransferringState); + addState(mListeningState, mTransferringState); + setInitialState(isSatelliteSupported); + start(); + } + + /** + * {@link DatagramController} uses this function to notify {@link SatelliteSessionController} + * that its datagram transfer state has changed. + * + * @param sendState The current datagram send state of {@link DatagramController}. + * @param receiveState The current datagram receive state of {@link DatagramController}. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void onDatagramTransferStateChanged( + @SatelliteManager.SatelliteDatagramTransferState int sendState, + @SatelliteManager.SatelliteDatagramTransferState int receiveState) { + sendMessage(EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, + new DatagramTransferState(sendState, receiveState)); + if (sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING) { + mIsSendingTriggeredDuringTransferringState.set(true); + } + } + + /** + * {@link SatelliteController} uses this function to notify {@link SatelliteSessionController} + * that the satellite enabled state has changed. + * + * @param enabled {@code true} means enabled and {@code false} means disabled. + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void onSatelliteEnabledStateChanged(boolean enabled) { + sendMessage(EVENT_SATELLITE_ENABLED_STATE_CHANGED, enabled); + } + + /** + * Registers for modem state changed from satellite modem. + * + * @param callback The callback to handle the satellite modem state changed event. + */ + public void registerForSatelliteModemStateChanged(@NonNull ISatelliteStateCallback callback) { + mListeners.put(callback.asBinder(), callback); + } + + /** + * Unregisters for modem state changed from satellite modem. + * If callback was not registered before, the request will be ignored. + * + * @param callback The callback that was passed to + * {@link #registerForSatelliteModemStateChanged(ISatelliteStateCallback)}. + */ + public void unregisterForSatelliteModemStateChanged(@NonNull ISatelliteStateCallback callback) { + mListeners.remove(callback.asBinder()); + } + + private static class DatagramTransferState { + @SatelliteManager.SatelliteDatagramTransferState public int sendState; + @SatelliteManager.SatelliteDatagramTransferState public int receiveState; + + DatagramTransferState(@SatelliteManager.SatelliteDatagramTransferState int sendState, + @SatelliteManager.SatelliteDatagramTransferState int receiveState) { + this.sendState = sendState; + this.receiveState = receiveState; + } + } + + private class UnavailableState extends State { + @Override + public void enter() { + if (DBG) logd("Entering UnavailableState"); + } + + @Override + public boolean processMessage(Message msg) { + loge("UnavailableState: receive msg " + getWhatToString(msg.what) + " unexpectedly"); + return HANDLED; + } } - private static void logd(@NonNull String log) { - Rlog.d(TAG, log); + private class PowerOffState extends State { + @Override + public void enter() { + if (DBG) logd("Entering PowerOffState"); + mIsSendingTriggeredDuringTransferringState.set(false); + notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_OFF); + } + + @Override + public boolean processMessage(Message msg) { + if (DBG) log("PowerOffState: processing " + getWhatToString(msg.what)); + switch (msg.what) { + case EVENT_SATELLITE_ENABLED_STATE_CHANGED: + handleSatelliteEnabledStateChanged((boolean) msg.obj); + break; + } + // Ignore all unexpected events. + return HANDLED; + } + + private void handleSatelliteEnabledStateChanged(boolean on) { + if (on) { + transitionTo(mIdleState); + } else { + loge("PowerOffState: Unexpected satellite radio powered-off state changed event"); + } + } + } + + private class IdleState extends State { + @Override + public void enter() { + if (DBG) logd("Entering IdleState"); + mIsSendingTriggeredDuringTransferringState.set(false); + notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + } + + @Override + public boolean processMessage(Message msg) { + if (DBG) log("IdleState: processing " + getWhatToString(msg.what)); + switch (msg.what) { + case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: + handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj); + break; + case EVENT_SATELLITE_ENABLED_STATE_CHANGED: + handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "IdleState"); + break; + } + // Ignore all unexpected events. + return HANDLED; + } + + private void handleEventDatagramTransferStateChanged( + @NonNull DatagramTransferState datagramTransferState) { + if ((datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING) + || (datagramTransferState.receiveState + == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING)) { + transitionTo(mTransferringState); + } + } } - private static void loge(@NonNull String log) { - Rlog.e(TAG, log); + private class TransferringState extends State { + @Override + public void enter() { + if (DBG) logd("Entering TransferringState"); + notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + } + + @Override + public boolean processMessage(Message msg) { + if (DBG) log("TransferringState: processing " + getWhatToString(msg.what)); + switch (msg.what) { + case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: + handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj); + return HANDLED; + case EVENT_SATELLITE_ENABLED_STATE_CHANGED: + handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "TransferringState"); + break; + } + // Ignore all unexpected events. + return HANDLED; + } + + private void handleEventDatagramTransferStateChanged( + @NonNull DatagramTransferState datagramTransferState) { + if (isSending(datagramTransferState.sendState) || isReceiving( + datagramTransferState.receiveState)) { + // Stay at transferring state. + } else if ((datagramTransferState.sendState + == SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED) + || (datagramTransferState.receiveState + == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED)) { + transitionTo(mIdleState); + } else { + transitionTo(mListeningState); + } + } + } + + private class ListeningState extends State { + @Override + public void enter() { + if (DBG) logd("Entering TransferringState"); + + long timeoutMillis = updateListeningMode(true); + sendMessageDelayed(EVENT_LISTENING_TIMER_TIMEOUT, timeoutMillis); + mIsSendingTriggeredDuringTransferringState.set(false); + notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_LISTENING); + } + + @Override + public void exit() { + removeMessages(EVENT_LISTENING_TIMER_TIMEOUT); + updateListeningMode(false); + } + + @Override + public boolean processMessage(Message msg) { + if (DBG) log("ListeningState: processing " + getWhatToString(msg.what)); + switch (msg.what) { + case EVENT_LISTENING_TIMER_TIMEOUT: + transitionTo(mIdleState); + break; + case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: + handleEventDatagramTransferStateChanged((DatagramTransferState) msg.obj); + break; + case EVENT_SATELLITE_ENABLED_STATE_CHANGED: + handleSatelliteEnabledStateChanged(!(boolean) msg.obj, "ListeningState"); + break; + } + // Ignore all unexpected events. + return HANDLED; + } + + private long updateListeningMode(boolean enabled) { + long timeoutMillis; + if (mIsSendingTriggeredDuringTransferringState.get()) { + timeoutMillis = mSatelliteStayAtListeningFromSendingMillis; + } else { + timeoutMillis = mSatelliteStayAtListeningFromReceivingMillis; + } + mSatelliteModemInterface.requestSatelliteListeningEnabled( + enabled, (int) timeoutMillis, null); + return timeoutMillis; + } + + private void handleEventDatagramTransferStateChanged( + @NonNull DatagramTransferState datagramTransferState) { + if (datagramTransferState.sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING + || datagramTransferState.receiveState + == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING) { + transitionTo(mTransferringState); + } + } } /** - * TODO: The following needs to be added in this class: - *- SatelliteStateListenerHandler - * Things to add in future: - * - state machine - * - This class should be aware of who turned on satellite mode etc - * - voting controller + * @return the string for msg.what */ + @Override + protected String getWhatToString(int what) { + String whatString; + switch (what) { + case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: + whatString = "EVENT_DATAGRAM_TRANSFER_STATE_CHANGED"; + break; + case EVENT_LISTENING_TIMER_TIMEOUT: + whatString = "EVENT_LISTENING_TIMER_TIMEOUT"; + break; + case EVENT_SATELLITE_ENABLED_STATE_CHANGED: + whatString = "EVENT_SATELLITE_ENABLED_STATE_CHANGED"; + break; + default: + whatString = "UNKNOWN EVENT " + what; + } + return whatString; + } + + private void setInitialState(boolean isSatelliteSupported) { + if (isSatelliteSupported) { + setInitialState(mPowerOffState); + } else { + setInitialState(mUnavailableState); + } + } + + private void notifyStateChangedEvent(@SatelliteManager.SatelliteModemState int state) { + List toBeRemoved = new ArrayList<>(); + mListeners.values().forEach(listener -> { + try { + listener.onSatelliteModemStateChanged(state); + } catch (RemoteException e) { + logd("notifyStateChangedEvent RemoteException: " + e); + toBeRemoved.add(listener); + } + }); + + toBeRemoved.forEach(listener -> { + mListeners.remove(listener.asBinder()); + }); + } + + private void handleSatelliteEnabledStateChanged(boolean off, String caller) { + if (off) { + transitionTo(mPowerOffState); + } else { + loge(caller + ": Unexpected satellite radio powered-on state changed event"); + } + } + + private boolean isSending(@SatelliteManager.SatelliteDatagramTransferState int sendState) { + return (sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING + || sendState == SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS); + } + + private boolean isReceiving(@SatelliteManager.SatelliteDatagramTransferState int receiveState) { + return (receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING + || receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS + || receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE); + } + + private static long getSatelliteStayAtListeningFromSendingMillis() { + return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, + SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS, + DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS); + } + + private static long getSatelliteStayAtListeningFromReceivingMillis() { + return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, + SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS, + DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java new file mode 100644 index 0000000000..2b030421d3 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2023 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 static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING; +import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.Looper; +import android.os.Message; +import android.telephony.satellite.ISatelliteStateCallback; +import android.telephony.satellite.SatelliteManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.Log; + +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Unit tests for SatelliteSessionController + */ +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class SatelliteSessionControllerTest extends TelephonyTest { + private static final String TAG = "SatelliteSessionControllerTest"; + private static final long TEST_SATELLITE_STAY_AT_LISTENING_MILLIS = 200; + private static final long EVENT_PROCESSING_TIME_MILLIS = 100; + + private static final String STATE_UNAVAILABLE = "UnavailableState"; + private static final String STATE_POWER_OFF = "PowerOffState"; + private static final String STATE_IDLE = "IdleState"; + private static final String STATE_TRANSFERRING = "TransferringState"; + private static final String STATE_LISTENING = "ListeningState"; + + private TestSatelliteModemInterface mSatelliteModemInterface; + private TestSatelliteSessionController mTestSatelliteSessionController; + private TestSatelliteStateCallback mTestSatelliteStateCallback; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + MockitoAnnotations.initMocks(this); + + mSatelliteModemInterface = new TestSatelliteModemInterface( + mContext, Looper.getMainLooper()); + mTestSatelliteSessionController = new TestSatelliteSessionController(mContext, + Looper.getMainLooper(), true, mSatelliteModemInterface, + TEST_SATELLITE_STAY_AT_LISTENING_MILLIS, + TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + + mTestSatelliteStateCallback = new TestSatelliteStateCallback(); + mTestSatelliteSessionController.registerForSatelliteModemStateChanged( + mTestSatelliteStateCallback); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testInitialState() { + /** + * Since satellite is not supported, SatelliteSessionController should move to UNAVAILABLE + * state. + */ + TestSatelliteSessionController sessionController1 = new TestSatelliteSessionController( + mContext, Looper.getMainLooper(), false, + mSatelliteModemInterface, 100, 100); + assertNotNull(sessionController1); + assertEquals(STATE_UNAVAILABLE, sessionController1.getCurrentStateName()); + + /** + * Since satellite is supported, SatelliteSessionController should move to POWER_OFF state. + */ + TestSatelliteSessionController sessionController2 = new TestSatelliteSessionController( + mContext, Looper.getMainLooper(), true, + mSatelliteModemInterface, 100, 100); + assertNotNull(sessionController2); + assertEquals(STATE_POWER_OFF, sessionController2.getCurrentStateName()); + } + + @Test + public void testUnavailableState() throws Exception { + /** + * Since satellite is not supported, SatelliteSessionController should move to UNAVAILABLE + * state. + */ + TestSatelliteSessionController sessionController = new TestSatelliteSessionController( + mContext, Looper.getMainLooper(), false, + mSatelliteModemInterface, 100, 100); + assertNotNull(sessionController); + assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); + + /** + * SatelliteSessionController should stay at UNAVAILABLE state even after it receives the + * satellite radio powered-on state changed event. + */ + sessionController.onSatelliteEnabledStateChanged(true); + waitFor(EVENT_PROCESSING_TIME_MILLIS); + assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); + } + + @Test + public void testStateTransition() { + /** + * Since satellite is supported, SatelliteSessionController should move to POWER_OFF state. + */ + assertNotNull(mTestSatelliteSessionController); + assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName()); + + // Power on the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + + // SatelliteSessionController should move to IDLE state after the modem is powered on. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Power off the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); + + // SatelliteSessionController should move back to POWER_OFF state. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); + assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Power on the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + + // SatelliteSessionController should move to IDLE state after radio is turned on. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Start sending datagrams + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + + // SatelliteSessionController should move to TRANSFERRING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Sending datagrams failed + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + + // SatelliteSessionController should move to IDLE state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Start sending datagrams again + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + + // SatelliteSessionController should move to TRANSFERRING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Sending datagrams is successful and done. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + + // SatelliteSessionController should move to LISTENING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_LISTENING); + assertEquals(STATE_LISTENING, mTestSatelliteSessionController.getCurrentStateName()); + assertEquals(1, mSatelliteModemInterface.getListeningEnabledCount()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Start receiving datagrams + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + + // SatelliteSessionController should move to TRANSFERRING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertEquals(1, mSatelliteModemInterface.getListeningDisabledCount()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Receiving datagrams is successful and done. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + + // SatelliteSessionController should move to LISTENING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_LISTENING); + assertEquals(STATE_LISTENING, mTestSatelliteSessionController.getCurrentStateName()); + assertEquals(2, mSatelliteModemInterface.getListeningEnabledCount()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Start receiving datagrams again + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + + // SatelliteSessionController should move to TRANSFERRING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertEquals(2, mSatelliteModemInterface.getListeningDisabledCount()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Receiving datagrams failed. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); + + // SatelliteSessionController should move to IDLE state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Start receiving datagrams again + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + + // SatelliteSessionController should move to TRANSFERRING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Receiving datagrams is successful and done. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + + // SatelliteSessionController should move to LISTENING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_LISTENING); + assertEquals(STATE_LISTENING, mTestSatelliteSessionController.getCurrentStateName()); + assertEquals(3, mSatelliteModemInterface.getListeningEnabledCount()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Wait for timeout + waitFor(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); + + // SatelliteSessionController should move to IDLE state after timeout + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + assertEquals(STATE_IDLE, mTestSatelliteSessionController.getCurrentStateName()); + assertEquals(3, mSatelliteModemInterface.getListeningDisabledCount()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Start receiving datagrams again + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + + // SatelliteSessionController should move to TRANSFERRING state. + assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, + SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Start sending datagrams + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + + // SatelliteSessionController should stay at TRANSFERRING state. + assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Receiving datagrams failed. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); + + // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE + // state. + assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Start receiving datagrams again. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + + // SatelliteSessionController should stay at TRANSFERRING state. + assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Sending datagrams failed. + mTestSatelliteSessionController.onDatagramTransferStateChanged( + SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + + // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE + // state. + assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); + assertEquals(STATE_TRANSFERRING, mTestSatelliteSessionController.getCurrentStateName()); + assertTrue(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + + // Power off the modem. + mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); + + // SatelliteSessionController should move to POWER_OFF state. + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); + assertEquals(STATE_POWER_OFF, mTestSatelliteSessionController.getCurrentStateName()); + assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); + } + + private static class TestSatelliteModemInterface extends SatelliteModemInterface { + private final AtomicInteger mListeningEnabledCount = new AtomicInteger(0); + private final AtomicInteger mListeningDisabledCount = new AtomicInteger(0); + + TestSatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { + super(context, looper); + mExponentialBackoff.stop(); + } + + @Override + protected void bindService() { + logd("TestSatelliteModemInterface: bindService"); + } + + @Override + protected void unbindService() { + logd("TestSatelliteModemInterface: unbindService"); + } + + @Override + public void requestSatelliteListeningEnabled(boolean enable, int timeout, + @Nullable Message message) { + if (enable) mListeningEnabledCount.incrementAndGet(); + else mListeningDisabledCount.incrementAndGet(); + } + + public int getListeningEnabledCount() { + return mListeningEnabledCount.get(); + } + + public int getListeningDisabledCount() { + return mListeningDisabledCount.get(); + } + } + + private static class TestSatelliteSessionController extends SatelliteSessionController { + TestSatelliteSessionController(Context context, Looper looper, boolean isSatelliteSupported, + SatelliteModemInterface satelliteModemInterface, + long satelliteStayAtListeningFromSendingMillis, + long satelliteStayAtListeningFromReceivingMillis) { + super(context, looper, isSatelliteSupported, satelliteModemInterface, + satelliteStayAtListeningFromSendingMillis, + satelliteStayAtListeningFromReceivingMillis); + } + + public String getCurrentStateName() { + return getCurrentState().getName(); + } + + public boolean isSendingTriggeredDuringTransferringState() { + return mIsSendingTriggeredDuringTransferringState.get(); + } + } + + private static class TestSatelliteStateCallback extends ISatelliteStateCallback.Stub { + private final AtomicInteger mModemState = new AtomicInteger( + SatelliteManager.SATELLITE_MODEM_STATE_OFF); + private final Semaphore mSemaphore = new Semaphore(0); + + @Override + public void onSatelliteModemStateChanged(int state) { + logd("onSatelliteModemStateChanged: state=" + state); + mModemState.set(state); + try { + mSemaphore.release(); + } catch (Exception ex) { + logd("onSatelliteModemStateChanged: Got exception, ex=" + ex); + } + } + + public boolean waitUntilResult() { + try { + if (!mSemaphore.tryAcquire(EVENT_PROCESSING_TIME_MILLIS, TimeUnit.MILLISECONDS)) { + logd("Timeout to receive onSatelliteModemStateChanged"); + return false; + } + return true; + } catch (Exception ex) { + logd("onSatelliteModemStateChanged: Got exception=" + ex); + return false; + } + } + + public int getModemState() { + return mModemState.get(); + } + } + + private static void waitFor(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ex) { + Log.e(TAG, "Thread.sleep() ex=" + ex); + } + } + + private static void assertSuccessfulModemStateChangedCallback( + TestSatelliteStateCallback callback, + @SatelliteManager.SatelliteModemState int expectedModemState) { + boolean successful = callback.waitUntilResult(); + assertTrue(successful); + assertEquals(expectedModemState, callback.getModemState()); + } + + private static void assertModemStateChangedCallbackNotCalled( + TestSatelliteStateCallback callback) { + boolean successful = callback.waitUntilResult(); + assertFalse(successful); + } +} -- GitLab From e176f656d4b65a7b19e38420a5f0eec6d48206a2 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Wed, 15 Mar 2023 16:42:05 -0700 Subject: [PATCH 524/656] Check transport for setup retry Without the change, the setup failures on both transports are counted towards the max retry quota. After the change, the max retry quota applies to transport respectively. Fix: 257319583 Test: voice call + data browsing Change-Id: I2fb8ad6ce74aeb716b7190b19c1c87b46db464d4 --- .../internal/telephony/data/DataRetryManager.java | 13 ++++++++----- .../telephony/data/DataRetryManagerTest.java | 10 ++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index 9e2e3b12e6..23621132dd 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -1189,13 +1189,14 @@ public class DataRetryManager extends Handler { return; } - int failedCount = getRetryFailedCount(capability, retryRule); + int failedCount = getRetryFailedCount(capability, retryRule, transport); log("For capability " + DataUtils.networkCapabilityToString(capability) + ", found matching rule " + retryRule + ", failed count=" + failedCount); if (failedCount == retryRule.getMaxRetries()) { - log("Data retry failed for " + failedCount + " times. Stopped " - + "timer-based data retry for " + log("Data retry failed for " + failedCount + " times on " + + AccessNetworkConstants.transportTypeToString(transport) + + ". Stopped timer-based data retry for " + DataUtils.networkCapabilityToString(capability) + ". Condition-based retry will still happen when condition " + "changes."); @@ -1368,16 +1369,18 @@ public class DataRetryManager extends Handler { * * @param networkCapability The network capability to check. * @param dataRetryRule The data retry rule. + * @param transport The transport on which setup failure has occurred. * @return The failed count since last successful data setup. */ private int getRetryFailedCount(@NetCapability int networkCapability, - @NonNull DataSetupRetryRule dataRetryRule) { + @NonNull DataSetupRetryRule dataRetryRule, @TransportType int transport) { int count = 0; for (int i = mDataRetryEntries.size() - 1; i >= 0; i--) { if (mDataRetryEntries.get(i) instanceof DataSetupRetryEntry) { DataSetupRetryEntry entry = (DataSetupRetryEntry) mDataRetryEntries.get(i); // count towards the last succeeded data setup. - if (entry.setupRetryType == DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS) { + if (entry.setupRetryType == DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS + && entry.transport == transport) { if (entry.networkRequestList.isEmpty()) { String msg = "Invalid data retry entry detected"; logl(msg); 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 769a920620..e846bc2525 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java @@ -587,6 +587,16 @@ public class DataRetryManagerTest extends TelephonyTest { // Verify there is no retry. verify(mDataRetryManagerCallbackMock, never()) .onDataNetworkSetupRetry(any(DataSetupRetryEntry.class)); + + // 4th failed on a different transport and retry. + mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile1, + AccessNetworkConstants.TRANSPORT_TYPE_WLAN, networkRequestList, 123, + DataCallResponse.RETRY_DURATION_UNDEFINED); + processAllFutureMessages(); + + // Verify retry occurs + verify(mDataRetryManagerCallbackMock) + .onDataNetworkSetupRetry(any(DataSetupRetryEntry.class)); } @Test -- GitLab From 06bdaec95192f3ffaac69811ede96565eb1858d3 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Tue, 7 Mar 2023 22:12:09 +0000 Subject: [PATCH 525/656] Update datagram transfer state. The following changes are made in this CL: DatagramDispatcher: updates DatagramController about datagram send status. - Datagram transfer state is initially set to SENDING when sendSatelliteDatagram() is called, then: -- State changes to SEND_FAILED on error -- State changes to SEND_SUCCESS if one datagram is sent successfully -- State Changes to IDLE if pendingDatagramCount is 0 DatagramReceiver: updates DatagramController about datagram receive status. - Datagram transfer state is initially set to RECEIVING when pollPendngSatelliteDatagrams() is called, then: -- State changes to RECEIVE_NONE if pendingCount is 0 and received datagram is null -- State changes to RECEIVE_SUCCESS if received datagram is not null -- State changes to IDLE if pending count is 0 DatagramController: - Stores all the variables needed to update onSendDatagramStateChanged(), onReceiveDatagramStateChanged() and calls PointingAppController where there is change in datagram transfer state. Bug: 269637555 Test: atest SatelliteManagerTest, Flashed build on raven-userdebug: calls and SMS are working. Change-Id: Iabb4c805380b0303c922b154817824758fad9dba --- .../satellite/DatagramController.java | 107 +++++- .../satellite/DatagramDispatcher.java | 169 +++++++--- .../telephony/satellite/DatagramReceiver.java | 192 +++++++++-- .../satellite/PointingAppController.java | 84 ++++- .../satellite/SatelliteController.java | 48 +-- .../satellite/DatagramDispatcherTest.java | 273 ++++++++++++++++ .../satellite/DatagramReceiverTest.java | 305 ++++++++++++++++++ .../satellite/FakeSatelliteProvider.java | 98 ++++++ 8 files changed, 1146 insertions(+), 130 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/satellite/FakeSatelliteProvider.java diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index ab226880bd..56ee8a6588 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -17,17 +17,13 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.Context; import android.os.Looper; -import android.os.Message; import android.telephony.Rlog; import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; -import com.android.internal.telephony.Phone; - import java.util.function.Consumer; /** @@ -38,10 +34,24 @@ public class DatagramController { @NonNull private static DatagramController sInstance; @NonNull private final Context mContext; + @NonNull private final PointingAppController mPointingAppController; @NonNull private final DatagramDispatcher mDatagramDispatcher; @NonNull private final DatagramReceiver mDatagramReceiver; public static final long MAX_DATAGRAM_ID = (long) Math.pow(2, 16); + /** Variables used to update onSendDatagramStateChanged(). */ + private int mSendSubId; + private int mSendDatagramTransferState = + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN; + private int mSendPendingCount = 0; + private int mSendErrorCode = SatelliteManager.SATELLITE_ERROR_NONE; + /** Variables used to update onReceiveDatagramStateChanged(). */ + private int mReceiveSubId; + private int mReceiveDatagramTransferState = + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN; + private int mReceivePendingCount = 0; + private int mReceiveErrorCode = SatelliteManager.SATELLITE_ERROR_NONE; + /** * @return The singleton instance of DatagramController. */ @@ -56,11 +66,14 @@ public class DatagramController { * Create the DatagramController singleton instance. * @param context The Context to use to create the DatagramController. * @param looper The looper for the handler. + * @param pointingAppController PointingAppController is used to update + * PointingApp about datagram transfer state changes. * @return The singleton instance of DatagramController. */ - public static DatagramController make(@NonNull Context context, @NonNull Looper looper) { + public static DatagramController make(@NonNull Context context, @NonNull Looper looper, + @NonNull PointingAppController pointingAppController) { if (sInstance == null) { - sInstance = new DatagramController(context, looper); + sInstance = new DatagramController(context, looper, pointingAppController); } return sInstance; } @@ -69,17 +82,22 @@ public class DatagramController { * Create a DatagramController to send and receive satellite datagrams. * * @param context The Context for the DatagramController. - * @param looper The looper for the handler. + * @param looper The looper for the handler + * @param pointingAppController PointingAppController is used to update PointingApp + * about datagram transfer state changes. */ - private DatagramController(@NonNull Context context, @NonNull Looper looper) { + private DatagramController(@NonNull Context context, @NonNull Looper looper, + @NonNull PointingAppController pointingAppController) { mContext = context; + mPointingAppController = pointingAppController; + // Create the DatagramDispatcher singleton, // which is used to send satellite datagrams. - mDatagramDispatcher = DatagramDispatcher.make(mContext, looper); + mDatagramDispatcher = DatagramDispatcher.make(mContext, looper, this); // Create the DatagramReceiver singleton, // which is used to receive satellite datagrams. - mDatagramReceiver = DatagramReceiver.make(mContext, looper); + mDatagramReceiver = DatagramReceiver.make(mContext, looper, this); } /** @@ -116,10 +134,11 @@ public class DatagramController { * {@link android.telephony.satellite.SatelliteDatagramCallback * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ILongConsumer)} * + * @param subId The subId of the subscription used for receiving datagrams. + * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ - public void pollPendingSatelliteDatagrams(@NonNull Message message, @Nullable Phone phone) { - // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING - mDatagramReceiver.pollPendingSatelliteDatagrams(message, phone); + public void pollPendingSatelliteDatagrams(int subId, @NonNull Consumer callback) { + mDatagramReceiver.pollPendingSatelliteDatagrams(subId, callback); } /** @@ -129,6 +148,7 @@ public class DatagramController { * input to this method. Datagram received here will be passed down to modem without any * encoding or encryption. * + * @param subId The subId of the subscription to send satellite datagrams for. * @param datagramType datagram type indicating whether the datagram is of type * SOS_SMS or LOCATION_SHARING. * @param datagram encoded gateway datagram which is encrypted by the caller. @@ -137,14 +157,69 @@ public class DatagramController { * full screen mode. * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ - public void sendSatelliteDatagram(@SatelliteManager.DatagramType int datagramType, + public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull Consumer callback) { - // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING - mDatagramDispatcher.sendSatelliteDatagram(datagramType, datagram, + mDatagramDispatcher.sendSatelliteDatagram(subId, datagramType, datagram, needFullScreenPointingUI, callback); } + /** + * Update send status to {@link PointingAppController}. + * + * @param subId The subId of the subscription to send satellite datagrams for + * @param datagramTransferState The new send datagram transfer state. + * @param sendPendingCount number of datagrams that are currently being sent + * @param errorCode If datagram transfer failed, the reason for failure. + */ + public void updateSendStatus(int subId, + @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, + int sendPendingCount, int errorCode) { + logd("updateSendStatus" + + " subId: " + subId + + " datagramTransferState: " + datagramTransferState + + " sendPendingCount: " + sendPendingCount + " errorCode: " + errorCode); + + mSendSubId = subId; + mSendDatagramTransferState = datagramTransferState; + mSendPendingCount = sendPendingCount; + mSendErrorCode = errorCode; + mPointingAppController.updateSendDatagramTransferState(subId, datagramTransferState, + sendPendingCount, errorCode); + } + + /** + * Update receive status to {@link PointingAppController}. + * + * @param subId The subId of the subscription used to receive datagrams + * @param datagramTransferState The new receive datagram transfer state. + * @param receivePendingCount The number of datagrams that are currently pending to be received. + * @param errorCode If datagram transfer failed, the reason for failure. + */ + public void updateReceiveStatus(int subId, + @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, + int receivePendingCount, int errorCode) { + logd("updateReceiveStatus" + + " subId: " + subId + + " datagramTransferState: " + datagramTransferState + + " receivePendingCount: " + receivePendingCount + " errorCode: " + errorCode); + + mReceiveSubId = subId; + mReceiveDatagramTransferState = datagramTransferState; + mReceivePendingCount = receivePendingCount; + mReceiveErrorCode = errorCode; + mPointingAppController.updateReceiveDatagramTransferState(subId, datagramTransferState, + receivePendingCount, errorCode); + } + + /** + * Return receive pending datagram count + * @return receive pending datagram count. + */ + public int getReceivePendingCount() { + return mReceivePendingCount; + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index c0c7777750..bfe1f0b391 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -28,6 +28,7 @@ import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import java.util.LinkedHashMap; @@ -47,6 +48,7 @@ public class DatagramDispatcher extends Handler { @NonNull private static DatagramDispatcher sInstance; @NonNull private final Context mContext; + @NonNull private final DatagramController mDatagramController; private static AtomicLong mNextDatagramId = new AtomicLong(0); @@ -75,11 +77,13 @@ public class DatagramDispatcher extends Handler { * Create the DatagramDispatcher singleton instance. * @param context The Context to use to create the DatagramDispatcher. * @param looper The looper for the handler. + * @param datagramController DatagramController which is used to update datagram transfer state. * @return The singleton instance of DatagramDispatcher. */ - public static DatagramDispatcher make(@NonNull Context context, @NonNull Looper looper) { + public static DatagramDispatcher make(@NonNull Context context, @NonNull Looper looper, + @NonNull DatagramController datagramController) { if (sInstance == null) { - sInstance = new DatagramDispatcher(context, looper); + sInstance = new DatagramDispatcher(context, looper, datagramController); } return sInstance; } @@ -89,10 +93,14 @@ public class DatagramDispatcher extends Handler { * * @param context The Context for the DatagramDispatcher. * @param looper The looper for the handler. + * @param datagramController DatagramController which is used to update datagram transfer state. */ - private DatagramDispatcher(@NonNull Context context, @NonNull Looper looper) { + private DatagramDispatcher(@NonNull Context context, @NonNull Looper looper, + @NonNull DatagramController datagramController) { super(looper); mContext = context; + mDatagramController = datagramController; + synchronized (mLock) { mSendingDatagramInProgress = false; } @@ -113,16 +121,18 @@ public class DatagramDispatcher extends Handler { } private static final class SendSatelliteDatagramArgument { + public int subId; public long datagramId; public @SatelliteManager.DatagramType int datagramType; public @NonNull SatelliteDatagram datagram; public boolean needFullScreenPointingUI; public @NonNull Consumer callback; - SendSatelliteDatagramArgument(long datagramId, + SendSatelliteDatagramArgument(int subId, long datagramId, @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull Consumer callback) { + this.subId = subId; this.datagramId = datagramId; this.datagramType = datagramType; this.datagram = datagram; @@ -139,16 +149,19 @@ public class DatagramDispatcher extends Handler { switch(msg.what) { case CMD_SEND_SATELLITE_DATAGRAM: { + logd("CMD_SEND_SATELLITE_DATAGRAM"); request = (DatagramDispatcherHandlerRequest) msg.obj; SendSatelliteDatagramArgument argument = (SendSatelliteDatagramArgument) request.argument; onCompleted = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request); + if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { SatelliteModemInterface.getInstance().sendSatelliteDatagram(argument.datagram, argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, argument.needFullScreenPointingUI, onCompleted); break; } + Phone phone = request.phone; if (phone != null) { phone.sendSatelliteDatagram(onCompleted, argument.datagram, @@ -156,6 +169,19 @@ public class DatagramDispatcher extends Handler { } else { loge("sendSatelliteDatagram: No phone object"); argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + + synchronized (mLock) { + // Remove current datagram from pending map + if (argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { + mPendingEmergencyDatagramsMap.remove(argument.datagramId); + } else { + mPendingNonEmergencyDatagramsMap.remove(argument.datagramId); + } + + // Abort sending all the pending datagrams + abortSendingPendingDatagrams(argument.subId, + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + } } break; } @@ -166,30 +192,38 @@ public class DatagramDispatcher extends Handler { int error = SatelliteServiceUtils.getSatelliteError(ar, "sendSatelliteDatagram"); SendSatelliteDatagramArgument argument = (SendSatelliteDatagramArgument) request.argument; + logd("EVENT_SEND_SATELLITE_DATAGRAM_DONE error: " + error); synchronized (mLock) { mSendingDatagramInProgress = false; - } - // Send response for current datagram - argument.callback.accept(error); - synchronized (mLock) { + // Send response for current datagram and remove it from pending map. + argument.callback.accept(error); if (argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { mPendingEmergencyDatagramsMap.remove(argument.datagramId); } else { mPendingNonEmergencyDatagramsMap.remove(argument.datagramId); } - } - // Handle pending datagrams - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - sendPendingDatagrams(); - } else { - // TODO: set modemTransferState = SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED. - sendErrorCodeAndCleanupPendingDatagrams(mPendingEmergencyDatagramsMap, - SatelliteManager.SATELLITE_REQUEST_ABORTED); - sendErrorCodeAndCleanupPendingDatagrams(mPendingNonEmergencyDatagramsMap, - SatelliteManager.SATELLITE_REQUEST_ABORTED); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + // Update send status for current datagram + mDatagramController.updateSendStatus(argument.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS, + getPendingDatagramCount(), error); + + if (getPendingDatagramCount() != 0) { + // Send pending datagrams + sendPendingDatagrams(); + } else { + mDatagramController.updateSendStatus(argument.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + getPendingDatagramCount(), + SatelliteManager.SATELLITE_ERROR_NONE); + } + } else { + // Abort sending all the pending datagrams + abortSendingPendingDatagrams(argument.subId, error); + } } break; } @@ -207,6 +241,7 @@ public class DatagramDispatcher extends Handler { * input to this method. Datagram received here will be passed down to modem without any * encoding or encryption. * + * @param subId The subId of the subscription to send satellite datagrams for. * @param datagramType datagram type indicating whether the datagram is of type * SOS_SMS or LOCATION_SHARING. * @param datagram encoded gateway datagram which is encrypted by the caller. @@ -215,15 +250,16 @@ public class DatagramDispatcher extends Handler { * full screen mode. * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ - public void sendSatelliteDatagram(@SatelliteManager.DatagramType int datagramType, + public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull Consumer callback) { Phone phone = SatelliteServiceUtils.getPhone(); long datagramId = mNextDatagramId.getAndUpdate( n -> ((n + 1) % DatagramController.MAX_DATAGRAM_ID)); - SendSatelliteDatagramArgument datagramArgs = new SendSatelliteDatagramArgument(datagramId, - datagramType, datagram, needFullScreenPointingUI, callback); + + SendSatelliteDatagramArgument datagramArgs = new SendSatelliteDatagramArgument(subId, + datagramId, datagramType, datagram, needFullScreenPointingUI, callback); synchronized (mLock) { if (datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { @@ -235,6 +271,9 @@ public class DatagramDispatcher extends Handler { if (!mSendingDatagramInProgress) { mSendingDatagramInProgress = true; sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArgs, phone); + mDatagramController.updateSendStatus(subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, + getPendingDatagramCount(), SatelliteManager.SATELLITE_ERROR_NONE); } } } @@ -243,21 +282,25 @@ public class DatagramDispatcher extends Handler { * Send pending satellite datagrams. Emergency datagrams are given priority over * non-emergency datagrams. */ + @GuardedBy("mLock") private void sendPendingDatagrams() { + logd("sendPendingDatagrams()"); Phone phone = SatelliteServiceUtils.getPhone(); Set> pendingDatagram = null; - synchronized (mLock) { - if (!mSendingDatagramInProgress && !mPendingEmergencyDatagramsMap.isEmpty()) { - pendingDatagram = mPendingEmergencyDatagramsMap.entrySet(); - } else if (!mSendingDatagramInProgress && !mPendingNonEmergencyDatagramsMap.isEmpty()) { - pendingDatagram = mPendingNonEmergencyDatagramsMap.entrySet(); - } + if (!mSendingDatagramInProgress && !mPendingEmergencyDatagramsMap.isEmpty()) { + pendingDatagram = mPendingEmergencyDatagramsMap.entrySet(); + } else if (!mSendingDatagramInProgress && !mPendingNonEmergencyDatagramsMap.isEmpty()) { + pendingDatagram = mPendingNonEmergencyDatagramsMap.entrySet(); + } - if ((pendingDatagram != null) && pendingDatagram.iterator().hasNext()) { - mSendingDatagramInProgress = true; - sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, - pendingDatagram.iterator().next().getValue(), phone); - } + if ((pendingDatagram != null) && pendingDatagram.iterator().hasNext()) { + mSendingDatagramInProgress = true; + SendSatelliteDatagramArgument datagramArg = + pendingDatagram.iterator().next().getValue(); + sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArg, phone); + mDatagramController.updateSendStatus(datagramArg.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, + getPendingDatagramCount(), SatelliteManager.SATELLITE_ERROR_NONE); } } @@ -265,20 +308,56 @@ public class DatagramDispatcher extends Handler { * Send error code to all the pending datagrams * @param errorCode error code to be returned. */ + @GuardedBy("mLock") private void sendErrorCodeAndCleanupPendingDatagrams( LinkedHashMap pendingDatagramsMap, @SatelliteManager.SatelliteError int errorCode) { - synchronized (mLock) { - // Send error code to all the pending datagrams - for (Entry entry : - pendingDatagramsMap.entrySet()) { - SendSatelliteDatagramArgument argument = entry.getValue(); - argument.callback.accept(errorCode); - } + if (pendingDatagramsMap.size() == 0) { + return; + } - // Clear pending datagram maps - pendingDatagramsMap.clear(); + // Send error code to all the pending datagrams + for (Entry entry : + pendingDatagramsMap.entrySet()) { + SendSatelliteDatagramArgument argument = entry.getValue(); + argument.callback.accept(errorCode); } + + // Clear pending datagram maps + pendingDatagramsMap.clear(); + } + + /** + * Abort sending all the pending datagrams. + * + * @param subId the subId of the subscription used to send datagram + * @param error error that resulted in abort. + */ + @GuardedBy("mLock") + private void abortSendingPendingDatagrams(int subId, + @SatelliteManager.SatelliteError int error) { + logd("abortSendingPendingDatagrams()"); + sendErrorCodeAndCleanupPendingDatagrams(mPendingEmergencyDatagramsMap, + SatelliteManager.SATELLITE_REQUEST_ABORTED); + sendErrorCodeAndCleanupPendingDatagrams(mPendingNonEmergencyDatagramsMap, + SatelliteManager.SATELLITE_REQUEST_ABORTED); + + // Update send status + mDatagramController.updateSendStatus(subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + getPendingDatagramCount(), error); + mDatagramController.updateSendStatus(subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + getPendingDatagramCount(), SatelliteManager.SATELLITE_ERROR_NONE); + } + + /** + * Return pending datagram count + * @return pending datagram count + */ + @GuardedBy("mLock") + private int getPendingDatagramCount() { + return mPendingEmergencyDatagramsMap.size() + mPendingNonEmergencyDatagramsMap.size(); } /** @@ -295,6 +374,14 @@ public class DatagramDispatcher extends Handler { msg.sendToTarget(); } + /** + * Destroys this DatagramDispatcher. Used for tearing down static resources during testing. + */ + @VisibleForTesting + public void destroy() { + sInstance = null; + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 541a6f1788..dec642402d 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -39,18 +39,24 @@ import android.telephony.satellite.SatelliteManager; import android.util.Pair; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ILongConsumer; import com.android.internal.telephony.Phone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; /** * Datagram receiver used to receive satellite datagrams and then, * deliver received datagrams to messaging apps. */ -public class DatagramReceiver { +public class DatagramReceiver extends Handler { private static final String TAG = "DatagramReceiver"; + + private static final int CMD_POLL_PENDING_SATELLITE_DATAGRAMS = 1; + private static final int EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE = 2; + /** File used to store shared preferences related to satellite. */ private static final String SATELLITE_SHARED_PREF = "satellite_shared_pref"; /** Key used to read/write satellite datagramId in shared preferences. */ @@ -61,6 +67,7 @@ public class DatagramReceiver { @NonNull private final Context mContext; @NonNull private final ContentResolver mContentResolver; @NonNull private SharedPreferences mSharedPreferences = null; + @NonNull private final DatagramController mDatagramController; /** * The background handler to perform database operations. This is running on a separate thread. @@ -77,11 +84,13 @@ public class DatagramReceiver { * Create the DatagramReceiver singleton instance. * @param context The Context to use to create the DatagramReceiver. * @param looper The looper for the handler. + * @param datagramController DatagramController which is used to update datagram transfer state. * @return The singleton instance of DatagramReceiver. */ - public static DatagramReceiver make(@NonNull Context context, @NonNull Looper looper) { + public static DatagramReceiver make(@NonNull Context context, @NonNull Looper looper, + @NonNull DatagramController datagramController) { if (sInstance == null) { - sInstance = new DatagramReceiver(context, looper); + sInstance = new DatagramReceiver(context, looper, datagramController); } return sInstance; } @@ -92,10 +101,14 @@ public class DatagramReceiver { * * @param context The Context for the DatagramReceiver. * @param looper The looper for the handler. + * @param datagramController DatagramController which is used to update datagram transfer state. */ - private DatagramReceiver(@NonNull Context context, @NonNull Looper looper) { + private DatagramReceiver(@NonNull Context context, @NonNull Looper looper, + @NonNull DatagramController datagramController) { + super(looper); mContext = context; mContentResolver = context.getContentResolver(); + mDatagramController = datagramController; HandlerThread backgroundThread = new HandlerThread(TAG); backgroundThread.start(); @@ -114,10 +127,28 @@ public class DatagramReceiver { } } + private static final class DatagramReceiverHandlerRequest { + /** The argument to use for the request */ + public @NonNull Object argument; + /** The caller needs to specify the phone to be used for the request */ + public @NonNull Phone phone; + /** The subId of the subscription used for the request. */ + public int subId; + /** The result of the request that is run on the main thread */ + public @Nullable Object result; + + DatagramReceiverHandlerRequest(Object argument, Phone phone, int subId) { + this.argument = argument; + this.phone = phone; + this.subId = subId; + } + } + /** * Listeners are updated about incoming datagrams using a backgroundThread. */ - private static final class SatelliteDatagramListenerHandler extends Handler { + @VisibleForTesting + public static final class SatelliteDatagramListenerHandler extends Handler { public static final int EVENT_SATELLITE_DATAGRAM_RECEIVED = 1; public static final int EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM = 2; public static final int EVENT_RECEIVED_ACK = 3; @@ -151,7 +182,8 @@ public class DatagramReceiver { } } - SatelliteDatagramListenerHandler(@NonNull Looper looper, int subId) { + @VisibleForTesting + public SatelliteDatagramListenerHandler(@NonNull Looper looper, int subId) { super(looper); mSubId = subId; mListeners = new ConcurrentHashMap<>(); @@ -281,20 +313,37 @@ public class DatagramReceiver { (Pair) ar.result; SatelliteDatagram satelliteDatagram = result.first; int pendingCount = result.second; - // TODO: update receivePendingCount to listeners using - // onDatagramTransferStateChanged - - long datagramId = getDatagramId(); - insertDatagram(datagramId, satelliteDatagram); - logd("Received EVENT_SATELLITE_DATAGRAM_RECEIVED for subId=" + mSubId); - mListeners.values().forEach(listener -> { - DatagramRetryArgument argument = new DatagramRetryArgument(datagramId, - satelliteDatagram, pendingCount, listener); - onSatelliteDatagramReceived(argument); - // wait for ack and retry after the timeout specified. - sendMessageDelayed(obtainMessage(EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM, - argument), getTimeoutToReceiveAck()); - }); + logd("Received EVENT_SATELLITE_DATAGRAM_RECEIVED for subId=" + mSubId + + " pendingCount:" + pendingCount); + + if (pendingCount == 0 && satelliteDatagram == null) { + sInstance.mDatagramController.updateReceiveStatus(mSubId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE, + 0, SatelliteManager.SATELLITE_ERROR_NONE); + } else if (satelliteDatagram != null) { + sInstance.mDatagramController.updateReceiveStatus(mSubId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, + pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); + + long datagramId = getDatagramId(); + insertDatagram(datagramId, satelliteDatagram); + + mListeners.values().forEach(listener -> { + DatagramRetryArgument argument = new DatagramRetryArgument(datagramId, + satelliteDatagram, pendingCount, listener); + onSatelliteDatagramReceived(argument); + // wait for ack and retry after the timeout specified. + sendMessageDelayed( + obtainMessage(EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM, + argument), getTimeoutToReceiveAck()); + }); + } + + if (pendingCount == 0) { + sInstance.mDatagramController.updateReceiveStatus(mSubId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); + } break; } @@ -319,6 +368,62 @@ public class DatagramReceiver { } } + @Override + public void handleMessage(Message msg) { + DatagramReceiverHandlerRequest request; + Message onCompleted; + AsyncResult ar; + + switch(msg.what) { + case CMD_POLL_PENDING_SATELLITE_DATAGRAMS: { + request = (DatagramReceiverHandlerRequest) msg.obj; + onCompleted = + obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, request); + + if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + SatelliteModemInterface.getInstance() + .pollPendingSatelliteDatagrams(onCompleted); + break; + } + + Phone phone = request.phone; + if (phone != null) { + phone.pollPendingSatelliteDatagrams(onCompleted); + } else { + loge("pollPendingSatelliteDatagrams: No phone object"); + ((Consumer) request.argument) + .accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + mDatagramController.updateReceiveStatus(request.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, + mDatagramController.getReceivePendingCount(), + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + + mDatagramController.updateReceiveStatus(request.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + mDatagramController.getReceivePendingCount(), + SatelliteManager.SATELLITE_ERROR_NONE); + } + break; + } + + case EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE: { + ar = (AsyncResult) msg.obj; + request = (DatagramReceiverHandlerRequest) ar.userObj; + int error = SatelliteServiceUtils.getSatelliteError(ar, + "pollPendingSatelliteDatagrams"); + ((Consumer) request.argument).accept(error); + logd("EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE error: " + error); + + if (error != SatelliteManager.SATELLITE_ERROR_NONE) { + mDatagramController.updateReceiveStatus(request.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, + mDatagramController.getReceivePendingCount(), error); + } + break; + } + } + } + /** * Register to receive incoming datagrams over satellite. * @@ -395,21 +500,42 @@ public class DatagramReceiver { * satellite. If there are any incoming datagrams, they will be received via * {@link android.telephony.satellite.SatelliteDatagramCallback * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ILongConsumer)} + * + * @param subId The subId of the subscription used for receiving datagrams. + * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ - public void pollPendingSatelliteDatagrams(@NonNull Message message, @Nullable Phone phone) { - if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { - SatelliteModemInterface.getInstance().pollPendingSatelliteDatagrams(message); - return; - } + public void pollPendingSatelliteDatagrams(int subId, @NonNull Consumer callback) { + mDatagramController.updateReceiveStatus(subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING, + mDatagramController.getReceivePendingCount(), + SatelliteManager.SATELLITE_ERROR_NONE); + + Phone phone = SatelliteServiceUtils.getPhone(); + sendRequestAsync(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, callback, phone, subId); + } - if (phone != null) { - phone.pollPendingSatelliteDatagrams(message); - } else { - loge("pollPendingSatelliteDatagrams: No phone object"); - AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); - message.sendToTarget(); - } + /** + * Posts the specified command to be executed on the main thread and returns immediately. + * + * @param command command to be executed on the main thread + * @param argument additional parameters required to perform of the operation + * @param phone phone object used to perform the operation + * @param subId The subId of the subscription used for the request. + */ + private void sendRequestAsync(int command, @NonNull Object argument, @Nullable Phone phone, + int subId) { + DatagramReceiverHandlerRequest request = new DatagramReceiverHandlerRequest( + argument, phone, subId); + Message msg = this.obtainMessage(command, request); + msg.sendToTarget(); + } + + /** + * Destroys this DatagramDispatcher. Used for tearing down static resources during testing. + */ + @VisibleForTesting + public void destroy() { + sInstance = null; } private static void logd(@NonNull String log) { diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java index 2041d4ee83..c37d1a05ba 100644 --- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -96,9 +96,24 @@ public class PointingAppController { mStartedSatelliteTransmissionUpdates = startedSatelliteTransmissionUpdates; } + private static final class DatagramTransferStateHandlerRequest { + public int datagramTransferState; + public int pendingCount; + public int errorCode; + + DatagramTransferStateHandlerRequest(int datagramTransferState, int pendingCount, + int errorCode) { + this.datagramTransferState = datagramTransferState; + this.pendingCount = pendingCount; + this.errorCode = errorCode; + } + } + + private static final class SatelliteTransmissionUpdateHandler extends Handler { public static final int EVENT_POSITION_INFO_CHANGED = 1; - public static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 2; + public static final int EVENT_SEND_DATAGRAM_STATE_CHANGED = 2; + public static final int EVENT_RECEIVE_DATAGRAM_STATE_CHANGED = 3; private final ConcurrentHashMap mListeners; SatelliteTransmissionUpdateHandler(Looper looper) { @@ -133,19 +148,35 @@ public class PointingAppController { }); break; } - case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - int result = (int) ar.result; + + case EVENT_SEND_DATAGRAM_STATE_CHANGED: { + DatagramTransferStateHandlerRequest request = + (DatagramTransferStateHandlerRequest) msg.obj; mListeners.values().forEach(listener -> { try { - // TODO: process and return the rest of the values correctly - listener.onDatagramTransferStateChanged(result, 0, 0, 0); + listener.onSendDatagramStateChanged(request.datagramTransferState, + request.pendingCount, request.errorCode); } catch (RemoteException e) { - logd("EVENT_DATAGRAM_TRANSFER_STATE_CHANGED RemoteException: " + e); + logd("EVENT_SEND_DATAGRAM_STATE_CHANGED RemoteException: " + e); } }); break; } + + case EVENT_RECEIVE_DATAGRAM_STATE_CHANGED: { + DatagramTransferStateHandlerRequest request = + (DatagramTransferStateHandlerRequest) msg.obj; + mListeners.values().forEach(listener -> { + try { + listener.onReceiveDatagramStateChanged(request.datagramTransferState, + request.pendingCount, request.errorCode); + } catch (RemoteException e) { + logd("EVENT_RECEIVE_DATAGRAM_STATE_CHANGED RemoteException: " + e); + } + }); + break; + } + default: loge("SatelliteTransmissionUpdateHandler unknown event: " + msg.what); } @@ -180,8 +211,7 @@ public class PointingAppController { */ SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged( handler, - SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, - null); + SatelliteTransmissionUpdateHandler.EVENT_SEND_DATAGRAM_STATE_CHANGED, null); } else { phone.registerForSatellitePositionInfoChanged(handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); @@ -295,6 +325,42 @@ public class PointingAppController { mContext.startActivity(launchIntent); } + public void updateSendDatagramTransferState(int subId, + @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, + int sendPendingCount, int errorCode) { + DatagramTransferStateHandlerRequest request = new DatagramTransferStateHandlerRequest( + datagramTransferState, sendPendingCount, errorCode); + SatelliteTransmissionUpdateHandler handler = + mSatelliteTransmissionUpdateHandlers.get(subId); + + if (handler != null) { + Message msg = handler.obtainMessage( + SatelliteTransmissionUpdateHandler.EVENT_SEND_DATAGRAM_STATE_CHANGED, + request); + msg.sendToTarget(); + } else { + loge("SatelliteTransmissionUpdateHandler not found for subId: " + subId); + } + } + + public void updateReceiveDatagramTransferState(int subId, + @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, + int receivePendingCount, int errorCode) { + DatagramTransferStateHandlerRequest request = new DatagramTransferStateHandlerRequest( + datagramTransferState, receivePendingCount, errorCode); + SatelliteTransmissionUpdateHandler handler = + mSatelliteTransmissionUpdateHandlers.get(subId); + + if (handler != null) { + Message msg = handler.obtainMessage( + SatelliteTransmissionUpdateHandler.EVENT_RECEIVE_DATAGRAM_STATE_CHANGED, + request); + msg.sendToTarget(); + } else { + loge(" SatelliteTransmissionUpdateHandler not found for subId: " + subId); + } + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 22da55051c..4c3944fd70 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -85,13 +85,11 @@ public class SatelliteController extends Handler { private static final int EVENT_IS_SATELLITE_SUPPORTED_DONE = 16; private static final int CMD_GET_SATELLITE_CAPABILITIES = 17; private static final int EVENT_GET_SATELLITE_CAPABILITIES_DONE = 18; - private static final int CMD_POLL_PENDING_SATELLITE_DATAGRAMS = 19; - private static final int EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE = 20; - private static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 21; - private static final int EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE = 22; - private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 23; - private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 24; - private static final int EVENT_RADIO_STATE_CHANGED = 25; + private static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 19; + private static final int EVENT_IS_SATELLITE_COMMUNICATION_ALLOWED_DONE = 20; + private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 21; + private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 22; + private static final int EVENT_RADIO_STATE_CHANGED = 23; @NonNull private static SatelliteController sInstance; @NonNull private final Context mContext; @@ -179,7 +177,7 @@ public class SatelliteController extends Handler { // Create the DatagramController singleton, // which is used to send and receive satellite datagrams. - mDatagramController = DatagramController.make(mContext, looper); + mDatagramController = DatagramController.make(mContext, looper, mPointingAppController); mSatelliteSupportedReceiver = new ResultReceiver(this) { @Override @@ -367,7 +365,13 @@ public class SatelliteController extends Handler { } case EVENT_PENDING_DATAGRAMS: { logd("Received EVENT_PENDING_DATAGRAMS for subId=" + mSubId); - // TODO: call pollPendingSatelliteDatagrams + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("pollPendingSatelliteDatagram result: " + result); + } + }; + sInstance.pollPendingSatelliteDatagrams(mSubId, internalCallback); break; } default: @@ -675,23 +679,6 @@ public class SatelliteController extends Handler { break; } - case CMD_POLL_PENDING_SATELLITE_DATAGRAMS: { - request = (SatelliteControllerHandlerRequest) msg.obj; - onCompleted = - obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, request); - mDatagramController.pollPendingSatelliteDatagrams(onCompleted, request.phone); - break; - } - - case EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE: { - ar = (AsyncResult) msg.obj; - request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = SatelliteServiceUtils.getSatelliteError(ar, - "pollPendingSatelliteDatagrams"); - ((Consumer) request.argument).accept(error); - break; - } - case CMD_IS_SATELLITE_COMMUNICATION_ALLOWED: { request = (SatelliteControllerHandlerRequest) msg.obj; onCompleted = @@ -1267,9 +1254,7 @@ public class SatelliteController extends Handler { return; } - Phone phone = SatelliteServiceUtils.getPhone(); - sendRequestAsync(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, result, phone); - // TODO: return pending datagram count + mDatagramController.pollPendingSatelliteDatagrams(subId, result); } /** @@ -1306,8 +1291,9 @@ public class SatelliteController extends Handler { if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(needFullScreenPointingUI); } - mDatagramController.sendSatelliteDatagram(datagramType, datagram, needFullScreenPointingUI, - result); + + mDatagramController.sendSatelliteDatagram(validSubId, datagramType, datagram, + needFullScreenPointingUI, result); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java new file mode 100644 index 0000000000..730b871ff7 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2023 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 static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.os.AsyncResult; +import android.os.Looper; +import android.os.Message; +import android.telephony.satellite.SatelliteDatagram; +import android.telephony.satellite.SatelliteManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.LinkedBlockingQueue; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DatagramDispatcherTest extends TelephonyTest { + private static final String TAG = "DatagramDispatcherTest"; + private static final int SUB_ID = 0; + private static final int DATAGRAM_TYPE1 = SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE; + private static final int DATAGRAM_TYPE2 = SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING; + private static final String TEST_MESSAGE = "This is a test datagram message"; + + private DatagramDispatcher mDatagramDispatcherUT; + + @Mock private DatagramController mMockDatagramController; + @Mock private SatelliteModemInterface mMockSatelliteModemInterface; + + /** Variables required to send datagram in the unit tests. */ + LinkedBlockingQueue mResultListener; + SatelliteDatagram mDatagram; + InOrder mInOrder; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + MockitoAnnotations.initMocks(this); + logd(TAG + " Setup!"); + + replaceInstance(DatagramController.class, "sInstance", null, + mMockDatagramController); + replaceInstance(SatelliteModemInterface.class, "sInstance", null, + mMockSatelliteModemInterface); + + mDatagramDispatcherUT = DatagramDispatcher.make(mContext, Looper.myLooper(), + mMockDatagramController); + + mResultListener = new LinkedBlockingQueue<>(1); + mDatagram = new SatelliteDatagram(TEST_MESSAGE.getBytes()); + mInOrder = inOrder(mMockDatagramController); + } + + @After + public void tearDown() throws Exception { + logd(TAG + " tearDown"); + mDatagramDispatcherUT.destroy(); + mDatagramDispatcherUT = null; + mResultListener = null; + mDatagram = null; + mInOrder = null; + super.tearDown(); + } + + @Test + public void testSendSatelliteDatagram_usingSatelliteModemInterface_success() throws Exception { + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[3]; + + mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, + new AsyncResult(message.obj, null, null)) + .sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class), + anyBoolean(), anyBoolean(), any(Message.class)); + + mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + true, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + verifyNoMoreInteractions(mMockDatagramController); + + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + } + + @Test + public void testSendSatelliteDatagram_usingSatelliteModemInterface_failure() throws Exception { + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[3]; + + mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, + new AsyncResult(message.obj, null, + new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_SERVICE_ERROR))) + .sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class), + anyBoolean(), anyBoolean(), any(Message.class)); + + mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram, + true, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(0), + eq(SatelliteManager.SATELLITE_SERVICE_ERROR)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + verifyNoMoreInteractions(mMockDatagramController); + + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_SERVICE_ERROR); + } + + @Test + public void testSendSatelliteDatagram_usingCommandsInterface_phoneNull() throws Exception { + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {null}); + + mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + true, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(0), + eq(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + verifyNoMoreInteractions(mMockDatagramController); + + assertThat(mResultListener.peek()) + .isEqualTo(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + } + + @Test + public void testSendSatelliteDatagram_usingCommandsInterface_success() throws Exception { + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + + mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, + new AsyncResult(message.obj, null, null)) + .sendToTarget(); + return null; + }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class), + anyBoolean()); + + mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram, + true, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + verifyNoMoreInteractions(mMockDatagramController); + + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + } + + @Test + public void testSendSatelliteDatagram_usingCommandsInterface_failure() throws Exception { + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + + mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, + new AsyncResult(message.obj, null, + new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_SERVICE_ERROR))) + .sendToTarget(); + return null; + }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class), + anyBoolean()); + + mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + true, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), eq(0), + eq(SatelliteManager.SATELLITE_SERVICE_ERROR)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + verifyNoMoreInteractions(mMockDatagramController); + + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_SERVICE_ERROR); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java new file mode 100644 index 0000000000..67fcd1ee1a --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2023 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.provider.Telephony; +import android.test.mock.MockContentResolver; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.inOrder; + +import android.os.AsyncResult; +import android.os.Looper; +import android.os.Message; +import android.telephony.satellite.SatelliteDatagram; +import android.telephony.satellite.SatelliteManager; +import android.util.Pair; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.LinkedBlockingQueue; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class DatagramReceiverTest extends TelephonyTest { + private static final String TAG = "DatagramReceiverTest"; + private static final int SUB_ID = 0; + private static final String TEST_MESSAGE = "This is a test datagram message"; + + private DatagramReceiver mDatagramReceiverUT; + private DatagramReceiver.SatelliteDatagramListenerHandler mSatelliteDatagramListenerHandler; + + @Mock private DatagramController mMockDatagramController; + @Mock private SatelliteModemInterface mMockSatelliteModemInterface; + + + /** Variables required to receive datagrams in the unit tests. */ + LinkedBlockingQueue mResultListener; + SatelliteDatagram mDatagram; + InOrder mInOrder; + private FakeSatelliteProvider mFakeSatelliteProvider; + private MockContentResolver mMockContentResolver; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + MockitoAnnotations.initMocks(this); + logd(TAG + " Setup!"); + + // Setup mock satellite provider DB. + mFakeSatelliteProvider = new FakeSatelliteProvider(); + mMockContentResolver = new MockContentResolver(); + mMockContentResolver.addProvider( + Telephony.SatelliteDatagrams.PROVIDER_NAME, mFakeSatelliteProvider); + doReturn(mMockContentResolver).when(mContext).getContentResolver(); + + replaceInstance(DatagramController.class, "sInstance", null, + mMockDatagramController); + replaceInstance(SatelliteModemInterface.class, "sInstance", null, + mMockSatelliteModemInterface); + + mDatagramReceiverUT = DatagramReceiver.make(mContext, Looper.myLooper(), + mMockDatagramController); + mSatelliteDatagramListenerHandler = new DatagramReceiver.SatelliteDatagramListenerHandler( + Looper.myLooper(), SUB_ID); + + mResultListener = new LinkedBlockingQueue<>(1); + mDatagram = new SatelliteDatagram(TEST_MESSAGE.getBytes()); + mInOrder = inOrder(mMockDatagramController); + + processAllMessages(); + } + + @After + public void tearDown() throws Exception { + logd(TAG + " tearDown"); + mDatagramReceiverUT.destroy(); + mDatagramReceiverUT = null; + mResultListener = null; + mDatagram = null; + mInOrder = null; + super.tearDown(); + } + + @Test + public void testPollPendingSatelliteDatagrams_usingSatelliteModemInterface_success() + throws Exception { + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + + mDatagramReceiverUT.obtainMessage(2 /*EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE*/, + new AsyncResult(message.obj, null, null)) + .sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).pollPendingSatelliteDatagrams(any(Message.class)); + + mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + } + + @Test + public void testPollPendingSatelliteDatagrams_usingSatelliteModemInterface_failure() + throws Exception { + doReturn(true).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + + mDatagramReceiverUT.obtainMessage(2 /*EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE*/, + new AsyncResult(message.obj, null, + new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_SERVICE_ERROR))) + .sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).pollPendingSatelliteDatagrams(any(Message.class)); + + mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), + eq(0), eq(SatelliteManager.SATELLITE_SERVICE_ERROR)); + + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_SERVICE_ERROR); + } + + @Test + public void testPollPendingSatelliteDatagrams_usingCommandsInterface_phoneNull() + throws Exception { + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {null}); + + mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), + eq(0), eq(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), + eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + + assertThat(mResultListener.peek()) + .isEqualTo(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + } + + @Test + public void testPollPendingSatelliteDatagrams_usingCommandsInterface_success() + throws Exception { + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + + mDatagramReceiverUT.obtainMessage(2 /*EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE*/, + new AsyncResult(message.obj, null, null)) + .sendToTarget(); + return null; + }).when(mPhone).pollPendingSatelliteDatagrams(any(Message.class)); + + mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + } + + @Test + public void testPollPendingSatelliteDatagrams_usingCommandsInterface_failure() + throws Exception { + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + + mDatagramReceiverUT.obtainMessage(2 /*EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE*/, + new AsyncResult(message.obj, null, + new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_SERVICE_ERROR))) + .sendToTarget(); + return null; + }).when(mPhone).pollPendingSatelliteDatagrams(any(Message.class)); + + mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), + eq(0), eq(SatelliteManager.SATELLITE_SERVICE_ERROR)); + + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_SERVICE_ERROR); + } + + @Test + public void testSatelliteDatagramReceived_receiveNone() { + mSatelliteDatagramListenerHandler.obtainMessage(1 /*EVENT_SATELLITE_DATAGRAM_RECEIVED*/, + new AsyncResult(null, new Pair<>(null, 0), null)) + .sendToTarget(); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE), + eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), + eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + } + + @Test + public void testSatelliteDatagramReceived_success_zeroPendingCount() { + mSatelliteDatagramListenerHandler.obtainMessage(1 /*EVENT_SATELLITE_DATAGRAM_RECEIVED*/, + new AsyncResult(null, new Pair<>(mDatagram, 0), null)) + .sendToTarget(); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS), + eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), + eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + } + + @Test + public void testSatelliteDatagramReceived_success_nonZeroPendingCount() { + mSatelliteDatagramListenerHandler.obtainMessage(1 /*EVENT_SATELLITE_DATAGRAM_RECEIVED*/, + new AsyncResult(null, new Pair<>(mDatagram, 10), null)) + .sendToTarget(); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS), + eq(10), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/FakeSatelliteProvider.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/FakeSatelliteProvider.java new file mode 100644 index 0000000000..637b48505c --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/FakeSatelliteProvider.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2023 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.content.ContentUris; +import android.content.ContentValues; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.net.Uri; +import android.os.Bundle; +import android.provider.Telephony; +import android.test.mock.MockContentProvider; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; + +public class FakeSatelliteProvider extends MockContentProvider { + private static final String TAG = "FakeSatelliteProvider"; + + private InMemorySatelliteProviderDbHelper mDbHelper = new InMemorySatelliteProviderDbHelper(); + + private class InMemorySatelliteProviderDbHelper extends SQLiteOpenHelper { + + InMemorySatelliteProviderDbHelper() { + super(InstrumentationRegistry.getTargetContext(), + null, // db file name is null for in-memory db + null, // CursorFactory is null by default + 1); // db version is no-op for tests + Log.d(TAG, "InMemorySatelliteProviderDbHelper creating in-memory database"); + } + public static String getStringForDatagramTableCreation(String tableName) { + return "CREATE TABLE " + tableName + "(" + + Telephony.SatelliteDatagrams.COLUMN_UNIQUE_KEY_DATAGRAM_ID + + " INTEGER PRIMARY KEY," + + Telephony.SatelliteDatagrams.COLUMN_DATAGRAM + " BLOB DEFAULT ''" + + ");"; + } + + @Override + public void onCreate(SQLiteDatabase db) { + Log.d(TAG, "InMemoryTelephonyProviderDbHelper onCreate:" + + " creating satellite incoming datagram table"); + db.execSQL(getStringForDatagramTableCreation(Telephony.SatelliteDatagrams.TABLE_NAME)); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + // Do nothing. + } + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + Log.d(TAG, "insert. values=" + values); + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + long id = db.insert(Telephony.SatelliteDatagrams.TABLE_NAME, null, values); + return ContentUris.withAppendedId(Telephony.SatelliteDatagrams.CONTENT_URI, id); + } + + @Override + public synchronized int delete(Uri url, String where, String[] whereArgs) { + return mDbHelper.getWritableDatabase() + .delete(Telephony.SatelliteDatagrams.TABLE_NAME, where, whereArgs); + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return mDbHelper.getReadableDatabase().query(Telephony.SatelliteDatagrams.TABLE_NAME, + projection, selection, selectionArgs, null, null, sortOrder); + } + + @Override + public Bundle call(String method, String request, Bundle args) { + return null; + } + + @Override + public final int update(Uri uri, ContentValues values, String where, String[] selectionArgs) { + // Do nothing. + return 0; + } +} -- GitLab From c588593f75620018cffd26f29a01ac42a32f0fd9 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Mon, 13 Mar 2023 21:31:20 -0700 Subject: [PATCH 526/656] RIL handle AIDL binder died for all services at the same time Test: atest RILTest, manual basic tests Test: manual kill RIL and verify no race condition Bug: 272160769 Change-Id: Ic606ebeac65ee8e5f68f7307c0b993f30a2f379f Merged-In: Ic606ebeac65ee8e5f68f7307c0b993f30a2f379f --- .../com/android/internal/telephony/RIL.java | 58 +++++++++++++------ .../android/internal/telephony/RILUtils.java | 3 + 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 8aff93b6ba..ef66ecd8d0 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -385,12 +385,15 @@ public class RIL extends BaseCommands implements CommandsInterface { 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()) { + riljLog("handleMessage: EVENT_AIDL_PROXY_DEAD cookie = " + msgCookie + + ", service = " + serviceToString(aidlService) + ", cookie = " + + mServiceCookies.get(aidlService)); mIsRadioProxyInitialized = false; resetProxyAndRequestList(aidlService); + } else { + riljLog("Ignore stale EVENT_AIDL_PROXY_DEAD for service " + + serviceToString(aidlService)); } break; } @@ -435,9 +438,8 @@ public class RIL extends BaseCommands implements CommandsInterface { 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)); + mRilHandler.sendMessageAtFrontOfQueue(mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD, + HAL_SERVICE_RADIO, 0 /* ignored arg2 */, cookie)); } } @@ -469,8 +471,14 @@ public class RIL extends BaseCommands implements CommandsInterface { @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 (!mRilHandler.hasMessages(EVENT_AIDL_PROXY_DEAD)) { + mRilHandler.sendMessageAtFrontOfQueue(mRilHandler.obtainMessage( + EVENT_AIDL_PROXY_DEAD, mService, 0 /* ignored arg2 */, + mServiceCookies.get(mService).get())); + } else { + riljLog("Not sending redundant EVENT_AIDL_PROXY_DEAD for service " + + serviceToString(mService)); + } unlinkToDeath(); } } @@ -479,14 +487,19 @@ public class RIL extends BaseCommands implements CommandsInterface { if (service == HAL_SERVICE_RADIO) { mRadioProxy = null; } else { - mServiceProxies.get(service).clear(); + 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(); + } } - // 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(); @@ -496,7 +509,15 @@ public class RIL extends BaseCommands implements CommandsInterface { if (service == HAL_SERVICE_RADIO) { getRadioProxy(null); } else { - getRadioServiceProxy(service, null); + 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, null); + } } } @@ -781,8 +802,7 @@ public class RIL extends BaseCommands implements CommandsInterface { @NonNull public synchronized RadioServiceProxy getRadioServiceProxy(int service, Message result) { if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return mServiceProxies.get(service); - if ((service >= HAL_SERVICE_IMS) - && !isRadioServiceSupported(service)) { + if ((service >= HAL_SERVICE_IMS) && !isRadioServiceSupported(service)) { return mServiceProxies.get(service); } if (!mIsCellularSupported) { @@ -1784,7 +1804,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = obtainRequest(RIL_REQUEST_GET_IMSI, result, mRILDefaultWorkSource); if (RILJ_LOGD) { - riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + riljLog(rr.serialString() + ">" + RILUtils.requestToString(rr.mRequest) + " aid = " + aid); } try { @@ -6418,7 +6438,7 @@ public class RIL extends BaseCommands implements CommandsInterface { synchronized (mWakeLock) { if (mWakeLockCount == 0 && !mWakeLock.isHeld()) return false; Rlog.d(RILJ_LOG_TAG, "NOTE: mWakeLockCount is " + mWakeLockCount - + "at time of clearing"); + + " at time of clearing"); mWakeLockCount = 0; mWakeLock.release(); mClientWakelockTracker.stopTrackingAll(); diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 207668e7f2..564d40072d 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -59,6 +59,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DATA_REGIS import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE_DATA_CALL; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DELETE_SMS_ON_SIM; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEVICE_IDENTITY; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEVICE_IMEI; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DIAL; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DTMF; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DTMF_START; @@ -5257,6 +5258,8 @@ public class RILUtils { return "GET_SIM_PHONEBOOK_RECORDS"; case RIL_REQUEST_UPDATE_SIM_PHONEBOOK_RECORD: return "UPDATE_SIM_PHONEBOOK_RECORD"; + case RIL_REQUEST_DEVICE_IMEI: + return "DEVICE_IMEI"; case RIL_REQUEST_GET_SLOT_STATUS: return "GET_SLOT_STATUS"; case RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING: -- GitLab From 09abd70f333dc5b978305b0da4b6da1d53f806fa Mon Sep 17 00:00:00 2001 From: Ayush Sharma Date: Wed, 15 Feb 2023 22:13:33 +0000 Subject: [PATCH 527/656] Fix VVM: Use user handle associated with SIM Bug: 265159622 Test: NA Change-Id: Id71cebdca889f62a2418a59beef6adb4ca09ce8b --- .../telephony/VisualVoicemailSmsFilter.java | 17 ++++++++++++++--- .../telephony/VisualVoicemailSmsFilterTest.java | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java index 0b1065160e..e3748110b4 100644 --- a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java +++ b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.os.UserHandle; import android.provider.VoicemailContract; import android.telecom.PhoneAccountHandle; import android.telephony.PhoneNumberUtils; @@ -60,7 +61,7 @@ public class VisualVoicemailSmsFilter { /** * Convert the subId to a {@link PhoneAccountHandle} */ - PhoneAccountHandle fromSubId(int subId); + PhoneAccountHandle fromSubId(int subId, Context context); } private static final String TAG = "VvmSmsFilter"; @@ -77,7 +78,7 @@ public class VisualVoicemailSmsFilter { new PhoneAccountHandleConverter() { @Override - public PhoneAccountHandle fromSubId(int subId) { + public PhoneAccountHandle fromSubId(int subId, Context context) { if (!SubscriptionManager.isValidSubscriptionId(subId)) { return null; } @@ -85,6 +86,15 @@ public class VisualVoicemailSmsFilter { if (phoneId == SubscriptionManager.INVALID_PHONE_INDEX) { return null; } + SubscriptionManager subscriptionManager = + (SubscriptionManager) context.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + UserHandle userHandle = subscriptionManager.getSubscriptionUserHandle(subId); + if (userHandle != null) { + return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT, + Integer.toString(PhoneFactory.getPhone(phoneId).getSubId()), + userHandle); + } return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT, Integer.toString(PhoneFactory.getPhone(phoneId).getSubId())); } @@ -138,7 +148,8 @@ public class VisualVoicemailSmsFilter { return false; } - PhoneAccountHandle phoneAccountHandle = sPhoneAccountHandleConverter.fromSubId(subId); + PhoneAccountHandle phoneAccountHandle = sPhoneAccountHandleConverter.fromSubId(subId, + context); if (phoneAccountHandle == null) { Log.e(TAG, "Unable to convert subId " + subId + " to PhoneAccountHandle"); diff --git a/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java b/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java index f09c94e191..9f763371f7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java @@ -96,7 +96,7 @@ public class VisualVoicemailSmsFilterTest extends TestCase { VisualVoicemailSmsFilter.setPhoneAccountHandleConverterForTest( new PhoneAccountHandleConverter() { @Override - public PhoneAccountHandle fromSubId(int subId) { + public PhoneAccountHandle fromSubId(int subId, Context context) { return new PhoneAccountHandle( new ComponentName("com.android.internal.telephony", "VisualVoicemailSmsFilterTest"), "foo"); -- GitLab From 99c550b2adfad2d41bbf3093e28fefd0aee8e366 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Fri, 10 Mar 2023 02:49:43 +0000 Subject: [PATCH 528/656] Save the Bluetooth and Wifi state in Persistent Memory - restore bluetooth and Wifi state from Persistent Memory BUG: b/271541445 Test: atest SatelliteControllerTest, Implementation tested panther-userdebug binary Change-Id: I68e8f44d78127ff348c852dd8fba5d28b7e54c84 --- .../telephony/satellite/DatagramReceiver.java | 10 +- .../satellite/SatelliteController.java | 117 ++++++++++++------ 2 files changed, 85 insertions(+), 42 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index dec642402d..82b3867deb 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -57,8 +57,6 @@ public class DatagramReceiver extends Handler { private static final int CMD_POLL_PENDING_SATELLITE_DATAGRAMS = 1; private static final int EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE = 2; - /** File used to store shared preferences related to satellite. */ - private static final String SATELLITE_SHARED_PREF = "satellite_shared_pref"; /** Key used to read/write satellite datagramId in shared preferences. */ private static final String SATELLITE_DATAGRAM_ID_KEY = "satellite_datagram_id_key"; private static AtomicLong mNextDatagramId = new AtomicLong(0); @@ -114,8 +112,9 @@ public class DatagramReceiver extends Handler { backgroundThread.start(); mBackgroundHandler = new Handler(looper); try { - mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, - Context.MODE_PRIVATE); + mSharedPreferences = + mContext.getSharedPreferences(SatelliteController.SATELLITE_SHARED_PREF, + Context.MODE_PRIVATE); } catch (Exception e) { loge("Cannot get default shared preferences: " + e); } @@ -212,7 +211,8 @@ public class DatagramReceiver extends Handler { try { // Try to recreate if it is null sInstance.mSharedPreferences = sInstance.mContext - .getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); + .getSharedPreferences(SatelliteController.SATELLITE_SHARED_PREF, + Context.MODE_PRIVATE); } catch (Exception e) { loge("Cannot get default shared preferences: " + e); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index bbad2e5116..ca76d16c2a 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothAdapter; import android.content.Context; +import android.content.SharedPreferences; import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Binder; @@ -65,6 +66,9 @@ public class SatelliteController extends Handler { private static final String TAG = "SatelliteController"; /** Whether enabling verbose debugging message or not. */ private static final boolean DBG = false; + /** File used to store shared preferences related to satellite. */ + public static final String SATELLITE_SHARED_PREF = "satellite_shared_pref"; + /** Message codes used in handleMessage() */ //TODO: Move the Commands and events related to position updates to PointingAppController @@ -96,10 +100,14 @@ public class SatelliteController extends Handler { @NonNull private SatelliteSessionController mSatelliteSessionController; @NonNull private final PointingAppController mPointingAppController; @NonNull private final DatagramController mDatagramController; + private SharedPreferences mSharedPreferences = null; private final CommandsInterface mCi; BluetoothAdapter mBluetoothAdapter = null; WifiManager mWifiManager = null; + /** Shared preference key to store the existing state of Bluetooth and Wifi*/ + private static final String KEY_BLUETOOTH_DISABLED_BY_SCO = "bluetooth_disabled_by_sco"; + private static final String KEY_WIFI_DISABLED_BY_SCO = "wifi_disabled_by_sco"; boolean mDisabledBTFlag = false; boolean mDisabledWifiFlag = false; /** @@ -183,6 +191,27 @@ public class SatelliteController extends Handler { //requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, // mSatelliteSupportedReceiver); mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); + + try { + mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, + Context.MODE_PRIVATE); + } catch (Exception e) { + loge("Cannot get default shared preferences: " + e); + } + //if BT and Wifi was already disabled by Satellite Controller, reset + if ((mSharedPreferences != null) && + (mSharedPreferences.contains(KEY_BLUETOOTH_DISABLED_BY_SCO) || + mSharedPreferences.contains(KEY_WIFI_DISABLED_BY_SCO))) { + /** + * read the flag from shared preference to check if the Bluetooth and Wifi was disabled + * by Satellite Controller + */ + mDisabledBTFlag = mSharedPreferences + .getBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, false); + mDisabledWifiFlag = mSharedPreferences + .getBoolean(KEY_WIFI_DISABLED_BY_SCO, false); + checkAndEnableBluetoothWifiState(); + } } private void internalInit() { @@ -469,27 +498,6 @@ public class SatelliteController extends Handler { case CMD_SET_SATELLITE_ENABLED: { request = (SatelliteControllerHandlerRequest) msg.obj; - //To be moved to EVENT_SET_SATELLITE_ENABLED_DONE - RequestSatelliteEnabledArgument argument = - (RequestSatelliteEnabledArgument) request.argument; - if (argument.enableSatellite) { - if (mBluetoothAdapter == null) { - mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - } - if (mWifiManager == null) { - mWifiManager = mContext.getSystemService(WifiManager.class); - } - if (mBluetoothAdapter.isEnabled()) { - if (DBG) logd("disabling Bluetooth"); - mBluetoothAdapter.disable(); - mDisabledBTFlag = true; - } - if (mWifiManager.isWifiEnabled()) { - if (DBG) logd("disabling Wifi"); - mWifiManager.setWifiEnabled(false); - mDisabledWifiFlag = true; - } - } handleSatelliteEnabled(request); break; } @@ -501,21 +509,12 @@ public class SatelliteController extends Handler { (RequestSatelliteEnabledArgument) request.argument; int error = SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled"); if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - if (!argument.enableSatellite) { - if (mBluetoothAdapter == null) { - mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - } - if (mWifiManager == null) { - mWifiManager = mContext.getSystemService(WifiManager.class); - } - if (!mBluetoothAdapter.isEnabled() && mDisabledBTFlag) { - if (DBG) logd("Enabling Bluetooth"); - mBluetoothAdapter.enable(); - } - if (!mWifiManager.isWifiEnabled() && mDisabledWifiFlag) { - if (DBG) logd("Enabling Wifi"); - mWifiManager.setWifiEnabled(true); - } + if (argument.enableSatellite) { + //If satellite mode is enabled successfully, disable Bluetooth and wifi + disableBluetoothWifiState();; + } else { + //Disabled satellite mode, Reset BT and Wifi if previously changed here + checkAndEnableBluetoothWifiState(); } /** * TODO: check if Satellite is Acquired. @@ -760,8 +759,8 @@ public class SatelliteController extends Handler { new RequestSatelliteEnabledArgument(false, false, result); request = new SatelliteControllerHandlerRequest(message, phone); handleSatelliteEnabled(request); - break; } + break; } default: @@ -1584,6 +1583,50 @@ public class SatelliteController extends Handler { } } + private void disableBluetoothWifiState() { + if (mBluetoothAdapter == null) { + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + } + if (mWifiManager == null) { + mWifiManager = mContext.getSystemService(WifiManager.class); + } + if (mBluetoothAdapter.isEnabled()) { + if (DBG) logd("disabling Bluetooth"); + //Set the Flag to indicate that Bluetooth is disabled by Satellite Controller + mSharedPreferences.edit().putBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, true) + .apply(); + mBluetoothAdapter.disable(); + } + if (mWifiManager.isWifiEnabled()) { + if (DBG) logd("disabling Wifi"); + //Set the Flag to indicate that Wifi is disabled by Satellite Controller + mSharedPreferences.edit().putBoolean(KEY_WIFI_DISABLED_BY_SCO, true) + .apply(); + mWifiManager.setWifiEnabled(false); + } + } + + private void checkAndEnableBluetoothWifiState() { + if (mBluetoothAdapter == null) { + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + } + if (mWifiManager == null) { + mWifiManager = mContext.getSystemService(WifiManager.class); + } + if (!mBluetoothAdapter.isEnabled() && mDisabledBTFlag) { + if (DBG) logd("Enabling Bluetooth"); + mBluetoothAdapter.enable(); + mSharedPreferences.edit().putBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, false) + .apply(); + } + if (!mWifiManager.isWifiEnabled() && mDisabledWifiFlag) { + if (DBG) logd("Enabling Wifi"); + mWifiManager.setWifiEnabled(true); + mSharedPreferences.edit().putBoolean(KEY_WIFI_DISABLED_BY_SCO, false) + .apply(); + } + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } -- GitLab From 1ff1d1fa8c9cd7db9bd93e097b99a7975a2febed Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 16 Mar 2023 20:12:44 -0700 Subject: [PATCH 529/656] Fixed incorrect profile shown on Settings The default boot profile on eSIM can be reported by the modem during boot up. It has 0 applications and the SIM state is always NOT_READY. Fixed by not pulling iccid from UiccController when SIM is in NOT_READY state. This is essentially the same logic as ag/5656809. Fix: 271340832 Test: activated eSIM on Pixel 5 and verified the boot profile subscription was not shown on Settings. Test: atest SubscriptionManagerServiceTest Change-Id: I6b7123a4bc00981f7bc0904153872f1b960983c0 --- .../SubscriptionManagerService.java | 209 +++++++++--------- .../SubscriptionManagerServiceTest.java | 10 + 2 files changed, 116 insertions(+), 103 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 18f0f89731..93f4db8a96 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1246,7 +1246,7 @@ public class SubscriptionManagerService extends ISub.Stub { + TelephonyManager.simStateToString(simState)); for (UiccSlot slot : mUiccController.getUiccSlots()) { if (slot != null) { - log(" " + slot.toString()); + log(" " + slot); } } @@ -1266,6 +1266,7 @@ public class SubscriptionManagerService extends ISub.Stub { // Check if this is the final state. Only update the subscription if NOT_READY is a // final state. IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); + if (iccCard.isEmptyProfile()) log("updateSubscription: iccCard has empty profile."); if (!iccCard.isEmptyProfile() && areUiccAppsEnabledOnCard(phoneId)) { log("updateSubscription: SIM_STATE_NOT_READY is not a final state. Will update " + "subscription later."); @@ -1276,126 +1277,128 @@ public class SubscriptionManagerService extends ISub.Stub { logl("updateSubscription: UICC app disabled on slot " + phoneId); markSubscriptionsInactive(phoneId); } - } - - String iccId = getIccId(phoneId); - log("updateSubscription: Found iccId=" + SubscriptionInfo.getPrintableId(iccId) - + " on phone " + phoneId); - - // For eSIM switching, SIM absent will not happen. Below is to exam if we find ICCID - // mismatch on the SIM slot. If that's the case, we need to mark all subscriptions on that - // logical slot invalid first. The correct subscription will be assigned the correct slot - // later. - SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager.getAllSubscriptions() - .stream() - .filter(sub -> sub.getSimSlotIndex() == phoneId && !iccId.equals(sub.getIccId())) - .findFirst() - .orElse(null); - if (subInfo != null) { - log("updateSubscription: Found previous active sub " + subInfo.getSubscriptionId() - + " that doesn't match current iccid on slot " + phoneId + "."); - markSubscriptionsInactive(phoneId); - } - - if (!TextUtils.isEmpty(iccId)) { - // Check if the subscription already existed. - subInfo = mSubscriptionDatabaseManager.getSubscriptionInfoInternalByIccId(iccId); - int subId; - if (subInfo == null) { - // This is a new SIM card. Insert a new record. - subId = insertSubscriptionInfo(iccId, phoneId, null, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - logl("updateSubscription: Inserted a new subscription. subId=" + subId - + ", phoneId=" + phoneId); - } else { - subId = subInfo.getSubscriptionId(); - log("updateSubscription: Found existing subscription. subId= " + subId - + ", phoneId=" + phoneId); - } - - subInfo = mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subId); - if (subInfo != null && subInfo.areUiccApplicationsEnabled()) { - mSlotIndexToSubId.put(phoneId, subId); - // Update the SIM slot index. This will make the subscription active. - mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId); - logl("updateSubscription: current mapping " + slotMappingToString()); + } else { + String iccId = getIccId(phoneId); + log("updateSubscription: Found iccId=" + SubscriptionInfo.getPrintableId(iccId) + + " on phone " + phoneId); + + // For eSIM switching, SIM absent will not happen. Below is to exam if we find ICCID + // mismatch on the SIM slot. If that's the case, we need to mark all subscriptions on + // that logical slot invalid first. The correct subscription will be assigned the + // correct slot later. + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager.getAllSubscriptions() + .stream() + .filter(sub -> sub.getSimSlotIndex() == phoneId && !iccId.equals( + sub.getIccId())) + .findFirst() + .orElse(null); + if (subInfo != null) { + log("updateSubscription: Found previous active sub " + subInfo.getSubscriptionId() + + " that doesn't match current iccid on slot " + phoneId + "."); + markSubscriptionsInactive(phoneId); } - // Update the card id. - UiccCard card = mUiccController.getUiccCardForPhone(phoneId); - if (card != null) { - String cardId = card.getCardId(); - if (cardId != null) { - mSubscriptionDatabaseManager.setCardString(subId, cardId); + if (!TextUtils.isEmpty(iccId)) { + // Check if the subscription already existed. + subInfo = mSubscriptionDatabaseManager.getSubscriptionInfoInternalByIccId(iccId); + int subId; + if (subInfo == null) { + // This is a new SIM card. Insert a new record. + subId = insertSubscriptionInfo(iccId, phoneId, null, + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + logl("updateSubscription: Inserted a new subscription. subId=" + subId + + ", phoneId=" + phoneId); + } else { + subId = subInfo.getSubscriptionId(); + log("updateSubscription: Found existing subscription. subId= " + subId + + ", phoneId=" + phoneId); } - } - // Update the port index. - mSubscriptionDatabaseManager.setPortIndex(subId, getPortIndex(iccId)); + subInfo = mSubscriptionDatabaseManager.getSubscriptionInfoInternal(subId); + if (subInfo != null && subInfo.areUiccApplicationsEnabled()) { + mSlotIndexToSubId.put(phoneId, subId); + // Update the SIM slot index. This will make the subscription active. + mSubscriptionDatabaseManager.setSimSlotIndex(subId, phoneId); + logl("updateSubscription: current mapping " + slotMappingToString()); + } - if (simState == TelephonyManager.SIM_STATE_LOADED) { - String mccMnc = mTelephonyManager.getSimOperatorNumeric(subId); - if (!TextUtils.isEmpty(mccMnc)) { - if (subId == getDefaultSubId()) { - MccTable.updateMccMncConfiguration(mContext, mccMnc); + // Update the card id. + UiccCard card = mUiccController.getUiccCardForPhone(phoneId); + if (card != null) { + String cardId = card.getCardId(); + if (cardId != null) { + mSubscriptionDatabaseManager.setCardString(subId, cardId); } - setMccMnc(subId, mccMnc); - } else { - loge("updateSubscription: mcc/mnc is empty"); } - String iso = TelephonyManager.getSimCountryIsoForPhone(phoneId); + // Update the port index. + mSubscriptionDatabaseManager.setPortIndex(subId, getPortIndex(iccId)); - if (!TextUtils.isEmpty(iso)) { - setCountryIso(subId, iso); - } else { - loge("updateSubscription: sim country iso is null"); - } + if (simState == TelephonyManager.SIM_STATE_LOADED) { + String mccMnc = mTelephonyManager.getSimOperatorNumeric(subId); + if (!TextUtils.isEmpty(mccMnc)) { + if (subId == getDefaultSubId()) { + MccTable.updateMccMncConfiguration(mContext, mccMnc); + } + setMccMnc(subId, mccMnc); + } else { + loge("updateSubscription: mcc/mnc is empty"); + } - String msisdn = mTelephonyManager.getLine1Number(subId); - if (!TextUtils.isEmpty(msisdn)) { - setDisplayNumber(msisdn, subId); - } + String iso = TelephonyManager.getSimCountryIsoForPhone(phoneId); - String imsi = mTelephonyManager.createForSubscriptionId(subId).getSubscriberId(); - if (imsi != null) { - mSubscriptionDatabaseManager.setImsi(subId, imsi); - } + if (!TextUtils.isEmpty(iso)) { + setCountryIso(subId, iso); + } else { + loge("updateSubscription: sim country iso is null"); + } - IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); - if (iccCard != null) { - IccRecords records = iccCard.getIccRecords(); - if (records != null) { - String[] ehplmns = records.getEhplmns(); - if (ehplmns != null) { - mSubscriptionDatabaseManager.setEhplmns(subId, ehplmns); - } - String[] hplmns = records.getPlmnsFromHplmnActRecord(); - if (hplmns != null) { - mSubscriptionDatabaseManager.setHplmns(subId, hplmns); + String msisdn = mTelephonyManager.getLine1Number(subId); + if (!TextUtils.isEmpty(msisdn)) { + setDisplayNumber(msisdn, subId); + } + + String imsi = mTelephonyManager.createForSubscriptionId( + subId).getSubscriberId(); + if (imsi != null) { + mSubscriptionDatabaseManager.setImsi(subId, imsi); + } + + IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); + if (iccCard != null) { + IccRecords records = iccCard.getIccRecords(); + if (records != null) { + String[] ehplmns = records.getEhplmns(); + if (ehplmns != null) { + mSubscriptionDatabaseManager.setEhplmns(subId, ehplmns); + } + String[] hplmns = records.getPlmnsFromHplmnActRecord(); + if (hplmns != null) { + mSubscriptionDatabaseManager.setHplmns(subId, hplmns); + } + } else { + loge("updateSubscription: ICC records are not available."); } } else { - loge("updateSubscription: ICC records are not available."); + loge("updateSubscription: ICC card is not available."); } - } else { - loge("updateSubscription: ICC card is not available."); + + // Attempt to restore SIM specific settings when SIM is loaded. + mContext.getContentResolver().call( + SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, + SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, + iccId, null); + log("Reload the database."); + mSubscriptionDatabaseManager.reloadDatabase(); } - // Attempt to restore SIM specific settings when SIM is loaded. - mContext.getContentResolver().call( - SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, - SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, - iccId, null); - log("Reload the database."); - mSubscriptionDatabaseManager.reloadDatabase(); + log("updateSubscription: " + mSubscriptionDatabaseManager + .getSubscriptionInfoInternal(subId)); + } else { + log("updateSubscription: No ICCID available for phone " + phoneId); + mSlotIndexToSubId.remove(phoneId); + logl("updateSubscription: current mapping " + slotMappingToString()); } - - log("updateSubscription: " + mSubscriptionDatabaseManager - .getSubscriptionInfoInternal(subId)); - } else { - log("updateSubscription: No ICCID available for phone " + phoneId); - mSlotIndexToSubId.remove(phoneId); - logl("updateSubscription: current mapping " + slotMappingToString()); } if (areAllSubscriptionsLoaded()) { 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 2a355f599d..a75f7594b1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -2173,4 +2173,14 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { map.clear(); assertThat(map).hasSize(0); } + + @Test + public void testSimNotReady() { + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + mSubscriptionManagerServiceUT.updateSimState( + 0, TelephonyManager.SIM_STATE_NOT_READY, null, null); + processAllMessages(); + + assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty(); + } } -- GitLab From f956a710c6cd4f1a9e76c7e21aa8bc9260ab34bc Mon Sep 17 00:00:00 2001 From: sangyun Date: Fri, 17 Mar 2023 06:46:52 +0900 Subject: [PATCH 530/656] Modified to validate number of phones in scheduled retry The scheduled retry has the target phone ID in the message. If the number of phones decreases before the schedule is fired, validating the phone ID in the message is required before run retry. Bug: 273755617 Test: atest FrameworksTelephonyTests Change-Id: Ib429fdbd691b8dd80f04726cad7feebd914bc810 --- .../telephony/data/PhoneSwitcher.java | 3 ++ .../telephony/data/PhoneSwitcherTest.java | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 1a0ddbe136..c9dc04e66c 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -846,6 +846,9 @@ public class PhoneSwitcher extends Handler { } case EVENT_MODEM_COMMAND_RETRY: { int phoneId = (int) msg.obj; + if (mActiveModemCount <= phoneId) { + break; + } if (isPhoneIdValidForRetry(phoneId)) { logl("EVENT_MODEM_COMMAND_RETRY: resend modem command on phone " + phoneId); sendRilCommands(phoneId); 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 21197180cb..307a61ad84 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -1831,6 +1831,36 @@ public class PhoneSwitcherTest extends TelephonyTest { verify(mMockRadioConfig, times(1)).setPreferredDataModem(eq(0), any()); } + @Test + public void testScheduledRetryWhileMultiSimConfigChange() throws Exception { + doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported(); + initialize(); + + // Phone 0 has sub 1, phone 1 has sub 2. + // Sub 1 is default data sub. + setSlotIndexToSubId(0, 1); + setSlotIndexToSubId(1, 2); + + // for EVENT_MODEM_COMMAND_RETRY + AsyncResult res = new AsyncResult( + 1, null, new CommandException(CommandException.Error.GENERIC_FAILURE)); + Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, res).sendToTarget(); + processAllMessages(); + + // reduce count of phone + setNumPhones(1, 1); + AsyncResult result = new AsyncResult(null, 1, null); + Message.obtain(mPhoneSwitcherUT, EVENT_MULTI_SIM_CONFIG_CHANGED, result).sendToTarget(); + processAllMessages(); + + // fire retries + moveTimeForward(5000); + processAllMessages(); + + verify(mCommandsInterface0, never()).setDataAllowed(anyBoolean(), any()); + verify(mCommandsInterface1, never()).setDataAllowed(anyBoolean(), any()); + } + /* Private utility methods start here */ private void prepareIdealAutoSwitchCondition() { -- GitLab From 0f42111ffc09cd0b96b6513f28bd9e85318b10da Mon Sep 17 00:00:00 2001 From: sparvathy Date: Wed, 8 Mar 2023 06:54:35 +0000 Subject: [PATCH 531/656] Removed codes related to hal version specific Cleaned up all handling that was specific to hal version 1.3 and less, To make it generic handling. Bug: 272188299 Test: atest EmergencyNumberTrackerTest, EC call Change-Id: Iff8f1a3a43d06474942e05cabf2d31ec3029603a Merged-In: Iff8f1a3a43d06474942e05cabf2d31ec3029603a --- .../emergency/EmergencyNumberTracker.java | 78 ------------------- .../emergency/EmergencyNumberTrackerTest.java | 44 ----------- 2 files changed, 122 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 6f8eaff543..715fc098e0 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -16,9 +16,6 @@ package com.android.internal.telephony.emergency; -import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; - -import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -30,7 +27,6 @@ import android.os.Handler; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; -import android.os.SystemProperties; import android.telephony.CarrierConfigManager; import android.telephony.CellIdentity; import android.telephony.PhoneNumberUtils; @@ -47,7 +43,6 @@ import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.HalVersion; import com.android.internal.telephony.LocaleTracker; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; @@ -110,7 +105,6 @@ public class EmergencyNumberTracker extends Handler { private String mCountryIso; private String mLastKnownEmergencyCountryIso = ""; private int mCurrentDatabaseVersion = INVALID_DATABASE_VERSION; - private boolean mIsHalVersionLessThan1Dot4 = false; private Resources mResources = null; /** * Used for storing all specific mnc's along with the list of emergency numbers @@ -209,9 +203,6 @@ public class EmergencyNumberTracker extends Handler { } else { loge("CarrierConfigManager is null."); } - - mIsHalVersionLessThan1Dot4 = mPhone.getHalVersion(HAL_SERVICE_VOICE) - .lessOrEqual(new HalVersion(1, 3)); } else { loge("mPhone is null."); } @@ -1025,9 +1016,6 @@ public class EmergencyNumberTracker extends Handler { private List getEmergencyNumberListFromEccList() { List emergencyNumberList = new ArrayList<>(); - if (mIsHalVersionLessThan1Dot4) { - emergencyNumberList.addAll(getEmergencyNumberListFromEccListForHalv1_3()); - } String emergencyNumbers = ((isSimAbsent()) ? "112,911,000,08,110,118,119,999" : "112,911"); for (String emergencyNum : emergencyNumbers.split(",")) { emergencyNumberList.add(getLabeledEmergencyNumberForEcclist(emergencyNum)); @@ -1039,37 +1027,6 @@ public class EmergencyNumberTracker extends Handler { return emergencyNumberList; } - private String getEmergencyNumberListForHalv1_3() { - int slotId; - if (mPhone.isSubscriptionManagerServiceEnabled()) { - slotId = SubscriptionManagerService.getInstance().getSlotIndex(mPhone.getSubId()); - } else { - slotId = SubscriptionController.getInstance().getSlotIndex(mPhone.getSubId()); - } - - String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); - String emergencyNumbers = SystemProperties.get(ecclist, ""); - - if (TextUtils.isEmpty(emergencyNumbers)) { - // then read-only ecclist property since old RIL only uses this - emergencyNumbers = SystemProperties.get("ro.ril.ecclist"); - } - logd(ecclist + " emergencyNumbers: " + emergencyNumbers); - return emergencyNumbers; - } - - private List getEmergencyNumberListFromEccListForHalv1_3() { - List emergencyNumberList = new ArrayList<>(); - String emergencyNumbers = getEmergencyNumberListForHalv1_3(); - - if (!TextUtils.isEmpty(emergencyNumbers)) { - for (String emergencyNum : emergencyNumbers.split(",")) { - emergencyNumberList.add(getLabeledEmergencyNumberForEcclist(emergencyNum)); - } - } - return emergencyNumberList; - } - private List getEmergencyNumberListWithPrefix( List emergencyNumberList) { List emergencyNumberListWithPrefix = new ArrayList<>(); @@ -1167,14 +1124,6 @@ public class EmergencyNumberTracker extends Handler { String countryIso = getLastKnownEmergencyCountryIso(); logd("country:" + countryIso); - if (mIsHalVersionLessThan1Dot4) { - emergencyNumbers = getEmergencyNumberListForHalv1_3(); - - if (!TextUtils.isEmpty(emergencyNumbers)) { - return isEmergencyNumberFromEccListForHalv1_3(number, emergencyNumbers); - } - } - logd("System property doesn't provide any emergency numbers." + " Use embedded logic for determining ones."); @@ -1215,25 +1164,6 @@ public class EmergencyNumberTracker extends Handler { return false; } - private boolean isEmergencyNumberFromEccListForHalv1_3(@NonNull String number, - @NonNull String emergencyNumbers) { - // searches through the comma-separated list for a match, - // return true if one is found. - for (String emergencyNum : emergencyNumbers.split(",")) { - if (number.equals(emergencyNum)) { - return true; - } else { - for (String prefix : mEmergencyNumberPrefix) { - if (number.equals(prefix + emergencyNum)) { - return true; - } - } - } - } - // no matches found against the list! - return false; - } - /** * Execute command for updating emergency number for test mode. */ @@ -1369,9 +1299,6 @@ public class EmergencyNumberTracker extends Handler { */ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); - ipw.println(" Hal Version:" + mPhone.getHalVersion(HAL_SERVICE_VOICE)); - ipw.println(" ========================================= "); - ipw.println(" Country Iso:" + getEmergencyCountryIso()); ipw.println(" ========================================= "); @@ -1408,11 +1335,6 @@ public class EmergencyNumberTracker extends Handler { ipw.decreaseIndent(); ipw.println(" ========================================= "); - if (mIsHalVersionLessThan1Dot4) { - getEmergencyNumberListForHalv1_3(); - ipw.println(" ========================================= "); - } - ipw.println("Emergency Number List for Phone" + "(" + mPhone.getPhoneId() + ")"); ipw.increaseIndent(); ipw.println(getEmergencyNumberList()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index 96efad7742..aa68d1ddd8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -16,8 +16,6 @@ package com.android.internal.telephony.emergency; -import static android.telephony.TelephonyManager.HAL_SERVICE_VOICE; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -50,7 +48,6 @@ import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; -import com.android.internal.telephony.HalVersion; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; @@ -150,12 +147,10 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { doReturn(mContext).when(mPhone).getContext(); doReturn(0).when(mPhone).getPhoneId(); doReturn(SUB_ID_PHONE_1).when(mPhone).getSubId(); - doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(HAL_SERVICE_VOICE); doReturn(mContext).when(mPhone2).getContext(); doReturn(1).when(mPhone2).getPhoneId(); doReturn(SUB_ID_PHONE_2).when(mPhone2).getSubId(); - doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(HAL_SERVICE_VOICE); initializeEmergencyNumberListTestSamples(); mEmergencyNumberTrackerMock = new EmergencyNumberTracker(mPhone, mSimulatedCommands); @@ -429,10 +424,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { @Test public void testIsEmergencyNumber_FallbackToShortNumberXml_NoSims() throws Exception { - // Set up the Hal version as 1.4 - doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(HAL_SERVICE_VOICE); - doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(HAL_SERVICE_VOICE); - setDsdsPhones(); replaceInstance(SubscriptionController.class, "sInstance", null, mSubControllerMock); @@ -469,10 +460,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { } private void testIsEmergencyNumber_NoFallbackToShortNumberXml(int numSims) throws Exception { - // Set up the Hal version as 1.4 - doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(HAL_SERVICE_VOICE); - doReturn(new HalVersion(1, 4)).when(mPhone2).getHalVersion(HAL_SERVICE_VOICE); - assertTrue((numSims > 0 && numSims < 3)); setDsdsPhones(); replaceInstance(SubscriptionController.class, "sInstance", null, mSubControllerMock); @@ -547,34 +534,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { assertTrue(mEmergencyNumberTrackerMock2.getEmergencyCountryIso().equals("us")); } - /** - * In 1.3 or less HAL. we should not use database number. - */ - @Test - public void testUsingEmergencyNumberDatabaseWheneverHal_1_3() { - doReturn(new HalVersion(1, 3)).when(mPhone).getHalVersion(HAL_SERVICE_VOICE); - doReturn(mMockContext).when(mPhone).getContext(); - doReturn(mResources).when(mMockContext).getResources(); - doReturn(true).when(mResources).getBoolean( - com.android.internal.R.bool.ignore_emergency_number_routing_from_db); - - EmergencyNumberTracker emergencyNumberTracker = new EmergencyNumberTracker( - mPhone, mSimulatedCommands); - - sendEmergencyNumberPrefix(emergencyNumberTracker); - emergencyNumberTracker.updateEmergencyCountryIsoAllPhones("us"); - processAllMessages(); - - boolean hasDatabaseNumber = false; - for (EmergencyNumber number : emergencyNumberTracker.getEmergencyNumberList()) { - if (number.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE)) { - hasDatabaseNumber = true; - break; - } - } - assertFalse(hasDatabaseNumber); - } - /** * In 1.4 or above HAL, we should use database number. */ @@ -813,9 +772,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { */ @Test public void testOtaEmergencyNumberDatabase() { - // Set up the Hal version as 1.4 to apply emergency number database - doReturn(new HalVersion(1, 4)).when(mPhone).getHalVersion(HAL_SERVICE_VOICE); - sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock); mEmergencyNumberTrackerMock.updateEmergencyCountryIsoAllPhones(""); processAllMessages(); -- GitLab From a5dc2dac1c055160999a74d117f186fd579f47b1 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 17 Mar 2023 11:40:43 -0700 Subject: [PATCH 532/656] Do not crash SubscriptionManager clients To be consistent with many other subscription manager APIs, do not crash the clients when service is not available. Fix: 269726553 Test: atest SubscriptionManagerTest Change-Id: I96266e586bb75b8c98775514d7be57a1f0e410ea --- .../telephony/subscription/SubscriptionManagerService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 18f0f89731..ac6544bfb7 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -3561,7 +3561,6 @@ public class SubscriptionManagerService extends ISub.Stub { * else {@code false} if subscription is not associated with user. * * @throws SecurityException if the caller doesn't have permissions required. - * @throws IllegalStateException if subscription service is not available. * */ @Override @@ -3612,7 +3611,6 @@ public class SubscriptionManagerService extends ISub.Stub { * @return list of subscriptionInfo associated with the user. * * @throws SecurityException if the caller doesn't have permissions required. - * @throws IllegalStateException if subscription service is not available. * */ @Override -- GitLab From 281d737896ad59eabbc827e89287e73ddb9f8317 Mon Sep 17 00:00:00 2001 From: Ayush Sharma Date: Fri, 17 Mar 2023 16:18:27 +0000 Subject: [PATCH 533/656] [API] Don't show error for non sms app Show "Switch to managed profile" dialog only in case of when message is initiated from an SMS app in personal profile(and SIM user is associated with managed profile). We should not show this dialog in non SMS app case, as it may give strange experience as seen in attached bug. Bug: 268211439 Test: NA Change-Id: I619c4884669c0ffea0a86fd3eebcd1dee9248d56 --- .../internal/telephony/SmsController.java | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 1fd4b66b85..4915e25871 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -164,9 +164,8 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { - TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); - } + TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, + Binder.getCallingUid(), callingPackage); sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); return; } @@ -263,9 +262,8 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { - TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); - } + TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, + Binder.getCallingUid(), callingPackage); sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); return; } @@ -348,9 +346,8 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { - TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); - } + TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, + Binder.getCallingUid(), callingPackage); sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); return; } @@ -388,9 +385,8 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { - TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); - } + TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, + Binder.getCallingUid(), callingPackage); sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_USER_NOT_ALLOWED); return; } @@ -426,9 +422,8 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { - TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); - } + TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, + Binder.getCallingUid(), callingPackage); sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_USER_NOT_ALLOWED); return; } @@ -934,9 +929,8 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle())) { - if (TelephonyUtils.isUidForeground(mContext, Binder.getCallingUid())) { - TelephonyUtils.showErrorIfSubscriptionAssociatedWithManagedProfile(mContext, subId); - } + TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, + Binder.getCallingUid(), callingPackage); sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); return; } -- GitLab From dfcbce2081ed3a50af62ef81fd6b5aa4b73434ab Mon Sep 17 00:00:00 2001 From: Willy Hu Date: Fri, 10 Mar 2023 17:40:52 +0800 Subject: [PATCH 534/656] [DSRM] Store the duration of current action - Add one more parameter to save the duration of current action - Calculate the duration of current recovery action Bug: 272415977 Test: Manual test passed. Change-Id: Id41cdb64699dfc907ac5e22fedd6705a964d0dca --- .../data/DataStallRecoveryManager.java | 21 +++++++++++++++++-- .../metrics/DataStallRecoveryStats.java | 6 ++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index df3ab57460..f5b60e1de2 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -176,6 +176,8 @@ public class DataStallRecoveryManager extends Handler { private boolean mIsAttemptedAllSteps; /** Whether internet network connected. */ private boolean mIsInternetNetworkConnected; + /** The durations for current recovery action */ + private @ElapsedRealtimeLong long mTimeElapsedOfCurrentAction; /** The array for the timers between recovery actions. */ private @NonNull long[] mDataStallRecoveryDelayMillisArray; @@ -468,6 +470,15 @@ public class DataStallRecoveryManager extends Handler { return (SystemClock.elapsedRealtime() - mTimeLastRecoveryStartMs); } + /** + * Get duration time for current recovery action. + * + * @return the time duration for current recovery action. + */ + private long getDurationOfCurrentRecoveryMs() { + return (SystemClock.elapsedRealtime() - mTimeElapsedOfCurrentAction); + } + /** * Broadcast intent when data stall occurred. * @@ -595,6 +606,7 @@ public class DataStallRecoveryManager extends Handler { private void setNetworkValidationState(boolean isValid) { boolean isLogNeeded = false; int timeDuration = 0; + int timeDurationOfCurrentAction = 0; boolean isFirstDataStall = false; boolean isFirstValidationAfterDoRecovery = false; @RecoveredReason int reason = getRecoveredReason(isValid); @@ -627,9 +639,11 @@ public class DataStallRecoveryManager extends Handler { } if (isLogNeeded) { + timeDurationOfCurrentAction = + (isFirstDataStall == true ? 0 : (int) getDurationOfCurrentRecoveryMs()); DataStallRecoveryStats.onDataStallEvent( mLastAction, mPhone, isValid, timeDuration, reason, - isFirstValidationAfterDoRecovery); + isFirstValidationAfterDoRecovery, timeDurationOfCurrentAction); logl( "data stall: " + (isFirstDataStall == true ? "start" : isValid == false ? "in process" : "end") @@ -642,7 +656,9 @@ public class DataStallRecoveryManager extends Handler { + ", isFirstValidationAfterDoRecovery=" + isFirstValidationAfterDoRecovery + ", TimeDuration=" - + timeDuration); + + timeDuration + + ", TimeDurationForCurrentRecoveryAction=" + + timeDurationOfCurrentAction); } } @@ -693,6 +709,7 @@ public class DataStallRecoveryManager extends Handler { mLastActionReported = false; broadcastDataStallDetected(recoveryAction); mNetworkCheckTimerStarted = false; + mTimeElapsedOfCurrentAction = SystemClock.elapsedRealtime(); switch (recoveryAction) { case RECOVERY_ACTION_GET_DATA_CALL_LIST: diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java index c0be456f6b..9ad775f30e 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -62,7 +62,8 @@ public class DataStallRecoveryStats { boolean isRecovered, int durationMillis, @DataStallRecoveryManager.RecoveredReason int reason, - boolean isFirstValidation) { + boolean isFirstValidation, + int durationMillisOfCurrentAction) { if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { phone = phone.getDefaultPhone(); } @@ -131,7 +132,8 @@ public class DataStallRecoveryStats { otherNetworkRegState, phoneNetworkRegState, isFirstValidation, - phoneId); + phoneId, + durationMillisOfCurrentAction); } /** Returns the RAT used for data (including IWLAN). */ -- GitLab From 7eb859ff81c03ffb453b59d709a3365a1ae1c1c8 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Mon, 20 Mar 2023 16:48:39 +0000 Subject: [PATCH 535/656] Null safety check to avoid NPE in rare thread sync issue. Bug: 272637077 Test: atest verified Change-Id: Ib765ed0d6c5dc04e479c2bcc96e9f83a9e8fa96d --- src/java/com/android/internal/telephony/cat/CatService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java index f2c692d073..c56bbef365 100644 --- a/src/java/com/android/internal/telephony/cat/CatService.java +++ b/src/java/com/android/internal/telephony/cat/CatService.java @@ -1010,7 +1010,11 @@ public class CatService extends Handler implements AppInterface { } } } - mMsgDecoder.sendStartDecodingMessageParams(new RilMessage(msg.what, data)); + if (mMsgDecoder != null) { + mMsgDecoder.sendStartDecodingMessageParams(new RilMessage(msg.what, data)); + } else { + CatLog.e(this, "Error in handleMessage (" + msg.what + ") mMsgDecoder is NULL"); + } break; case MSG_ID_CALL_SETUP: mMsgDecoder.sendStartDecodingMessageParams(new RilMessage(msg.what, null)); -- GitLab From 8a42ac4e3bdb218ac8351d356d4bd7580e9195df Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Wed, 8 Mar 2023 16:44:56 +0000 Subject: [PATCH 536/656] Fixed the smscAddress API permission validation BUG: 268588506 BUG: 269708461 Test: atest android.telephony.cts.SmsManagerTest#testGetSetSmscAddress and verified manually sms and Mms. Change-Id: I9436a1abda681a4c0b1fb7635dcb1837e2b6b40e --- .../telephony/IccSmsInterfaceManager.java | 2 ++ .../telephony/SmsDispatchersController.java | 14 +++----- .../internal/telephony/SmsPermissions.java | 33 +++++++++++-------- .../telephony/SmsPermissionsTest.java | 2 +- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java index cdcf344223..2d7763179c 100644 --- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java +++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java @@ -908,6 +908,7 @@ public class IccSmsInterfaceManager { public String getSmscAddressFromIccEf(String callingPackage) { if (!mSmsPermissions.checkCallingOrSelfCanGetSmscAddress( callingPackage, "getSmscAddressFromIccEf")) { + loge("Caller do not have permission to call GetSmscAddress"); return null; } enforceNotOnHandlerThread("getSmscAddressFromIccEf"); @@ -929,6 +930,7 @@ public class IccSmsInterfaceManager { public boolean setSmscAddressOnIccEf(String callingPackage, String smsc) { if (!mSmsPermissions.checkCallingOrSelfCanSetSmscAddress( callingPackage, "setSmscAddressOnIccEf")) { + loge("Caller do not have permission to call SetSmscAddress"); return false; } enforceNotOnHandlerThread("setSmscAddressOnIccEf"); diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java index e434801c97..8150e4705e 100644 --- a/src/java/com/android/internal/telephony/SmsDispatchersController.java +++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java @@ -45,6 +45,7 @@ import android.telephony.ServiceState; import android.telephony.SmsManager; import android.telephony.SmsMessage; import android.telephony.TelephonyManager; +import android.text.TextUtils; import com.android.ims.ImsManager; import com.android.internal.annotations.VisibleForTesting; @@ -459,12 +460,7 @@ public class SmsDispatchersController extends Handler { private String getSmscAddressFromUSIM(String callingPkg) { IccSmsInterfaceManager iccSmsIntMgr = mPhone.getIccSmsInterfaceManager(); if (iccSmsIntMgr != null) { - long identity = Binder.clearCallingIdentity(); - try { - return iccSmsIntMgr.getSmscAddressFromIccEf(callingPkg); - } finally { - Binder.restoreCallingIdentity(identity); - } + return iccSmsIntMgr.getSmscAddressFromIccEf(callingPkg); } else { Rlog.d(TAG, "getSmscAddressFromIccEf iccSmsIntMgr is null"); } @@ -1303,7 +1299,7 @@ public class SmsDispatchersController extends Handler { */ protected void sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm) { - if (scAddr == null) { + if (TextUtils.isEmpty(scAddr)) { scAddr = getSmscAddressFromUSIM(callingPackage); } @@ -1542,7 +1538,7 @@ public class SmsDispatchersController extends Handler { PendingIntent deliveryIntent, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId, boolean skipShortCodeCheck) { - if (scAddr == null) { + if (TextUtils.isEmpty(scAddr)) { scAddr = getSmscAddressFromUSIM(callingPkg); } @@ -1691,7 +1687,7 @@ public class SmsDispatchersController extends Handler { ArrayList deliveryIntents, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, long messageId) { - if (scAddr == null) { + if (TextUtils.isEmpty(scAddr)) { scAddr = getSmscAddressFromUSIM(callingPkg); } diff --git a/src/java/com/android/internal/telephony/SmsPermissions.java b/src/java/com/android/internal/telephony/SmsPermissions.java index f6af69dbb2..529eea02c1 100644 --- a/src/java/com/android/internal/telephony/SmsPermissions.java +++ b/src/java/com/android/internal/telephony/SmsPermissions.java @@ -135,17 +135,18 @@ public class SmsPermissions { public boolean checkCallingOrSelfCanGetSmscAddress(String callingPackage, String message) { // Allow it to the default SMS app always. boolean isDefaultSmsPackage; + int callerUid = Binder.getCallingUid(); final long identity = Binder.clearCallingIdentity(); try { - isDefaultSmsPackage = isCallerDefaultSmsPackage(callingPackage); + isDefaultSmsPackage = isCallerDefaultSmsPackage(callingPackage, callerUid); } finally { Binder.restoreCallingIdentity(identity); } - if (!isDefaultSmsPackage) { - TelephonyPermissions - .enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege( - mContext, mPhone.getSubId(), message); + Rlog.d(LOG_TAG, "Caller is not a default SMS application"); + TelephonyPermissions. + enforceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege( + mContext, mPhone.getSubId(), message); } return true; } @@ -162,25 +163,26 @@ public class SmsPermissions { public boolean checkCallingOrSelfCanSetSmscAddress(String callingPackage, String message) { // Allow it to the default SMS app always. boolean isDefaultSmsPackage; + int callerUid = Binder.getCallingUid(); final long identity = Binder.clearCallingIdentity(); try { - isDefaultSmsPackage = isCallerDefaultSmsPackage(callingPackage); + isDefaultSmsPackage = isCallerDefaultSmsPackage(callingPackage, callerUid); } finally { Binder.restoreCallingIdentity(identity); } - if (!isDefaultSmsPackage) { + Rlog.d(LOG_TAG, "Caller is not a default SMS application"); // Allow it with MODIFY_PHONE_STATE or Carrier Privileges - TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege( - mContext, mPhone.getSubId(), message); + TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mContext, + mPhone.getSubId(), message); } return true; } /** Check if a package is default SMS app. */ @VisibleForTesting - public boolean isCallerDefaultSmsPackage(String packageName) { - if (packageNameMatchesCallingUid(packageName)) { + public boolean isCallerDefaultSmsPackage(String packageName, int callerUid) { + if (packageNameMatchesCallingUid(packageName, callerUid)) { UserHandle userHandle = TelephonyUtils.getSubscriptionUserHandle(mContext, mPhone.getSubId()); return SmsApplication.isDefaultSmsApplicationAsUser(mContext, packageName, userHandle); @@ -188,16 +190,21 @@ public class SmsPermissions { return false; } + @VisibleForTesting + public boolean packageNameMatchesCallingUid(String packageName) { + return packageNameMatchesCallingUid(packageName, Binder.getCallingUid()); + } + /** * Check if the passed in packageName belongs to the calling uid. * @param packageName name of the package to check * @return true if package belongs to calling uid, false otherwise */ @VisibleForTesting - public boolean packageNameMatchesCallingUid(String packageName) { + public boolean packageNameMatchesCallingUid(String packageName, int callerUid) { try { ((AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE)) - .checkPackage(Binder.getCallingUid(), packageName); + .checkPackage(callerUid, packageName); // If checkPackage doesn't throw an exception then we are the given package return true; } catch (SecurityException e) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsPermissionsTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsPermissionsTest.java index 2a7f35b04b..5057eea9e3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsPermissionsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsPermissionsTest.java @@ -78,7 +78,7 @@ public class SmsPermissionsTest extends TelephonyTest { } @Override - public boolean isCallerDefaultSmsPackage(String packageName) { + public boolean isCallerDefaultSmsPackage(String packageName, int uid) { return mCallerIsDefaultSmsPackage; } }; -- GitLab From 31a7d6ca97647ec7f0bdf9fbaff9c90246fe107a Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Thu, 16 Mar 2023 11:37:47 -0700 Subject: [PATCH 537/656] Read vendor satellite service support from resource config Bug: 273555341 Test: atest android.telephony.cts.SatelliteManagerTest Change-Id: Ie2a321ca504f953904b69e97d3fca128f11b601d --- .../telephony/satellite/SatelliteModemInterface.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 311cee393f..cf2fc8593b 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -42,6 +42,7 @@ import android.telephony.satellite.stub.SatelliteService; import android.text.TextUtils; import android.util.Pair; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ExponentialBackoff; import com.android.internal.telephony.IBooleanConsumer; @@ -54,6 +55,7 @@ import java.util.Arrays; */ public class SatelliteModemInterface { private static final String TAG = "SatelliteModemInterface"; + private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute private static final int REBIND_MULTIPLIER = 2; @@ -66,7 +68,7 @@ public class SatelliteModemInterface { /** * {@code true} to use the vendor satellite service and {@code false} to use the HAL. */ - private final boolean mIsSatelliteServiceSupported = false; + private final boolean mIsSatelliteServiceSupported; @Nullable private ISatellite mSatelliteService; @Nullable private SatelliteServiceConnection mSatelliteServiceConnection; private boolean mIsBound; @@ -166,6 +168,7 @@ public class SatelliteModemInterface { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected SatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { mContext = context; + mIsSatelliteServiceSupported = getSatelliteServiceSupport(); mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, REBIND_MULTIPLIER, looper, () -> { synchronized (mLock) { @@ -198,7 +201,11 @@ public class SatelliteModemInterface { @NonNull private String getSatellitePackageName() { return TextUtils.emptyIfNull(mContext.getResources().getString( - com.android.internal.R.string.config_satellite_service_package)); + R.string.config_satellite_service_package)); + } + + private boolean getSatelliteServiceSupport() { + return !TextUtils.isEmpty(getSatellitePackageName()); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @@ -945,7 +952,6 @@ public class SatelliteModemInterface { } public boolean isSatelliteServiceSupported() { - // TODO: update this method to check a device config instead return mIsSatelliteServiceSupported; } -- GitLab From 89bc2e2fbd988f693911aa079849e7b7601c131f Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Fri, 10 Feb 2023 03:03:44 +0000 Subject: [PATCH 538/656] [Satellite] framework side implementatation for satellite service metrics Bug: 270860124 Test: atest PersistAtomsStorageTest, SatelliteStatsTest Test: e2e call / sms / mms regression test with pixel Merged-In: I5c63068ed80de03222cf1cc43e21a00daf8acbfd Change-Id: I5c63068ed80de03222cf1cc43e21a00daf8acbfd --- proto/src/persist_atoms.proto | 92 +- .../telephony/metrics/MetricsCollector.java | 189 +++- .../metrics/PersistAtomsStorage.java | 286 +++++- .../telephony/metrics/SatelliteStats.java | 905 +++++++++++++++++ .../metrics/PersistAtomsStorageTest.java | 929 ++++++++++++++++-- .../telephony/metrics/SatelliteStatsTest.java | 242 +++++ 6 files changed, 2579 insertions(+), 64 deletions(-) create mode 100644 src/java/com/android/internal/telephony/metrics/SatelliteStats.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index 30ad097851..9d83c25cf1 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -23,7 +23,7 @@ option java_outer_classname = "PersistAtomsProto"; // 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: 53 +// Next id: 70 message PersistAtoms { /* Aggregated RAT usage during the call. */ repeated VoiceCallRatUsage voice_call_rat_usage = 1; @@ -189,6 +189,42 @@ message PersistAtoms { /* Number of time the user toggled the data switch feature since the last collection. */ optional int32 auto_data_switch_toggle_count = 55; + + /** Snapshot of satellite controller. */ + repeated SatelliteController satellite_controller = 58; + + /* Timestamp of last satellite_controller pull. */ + optional int64 satellite_controller_pull_timestamp_millis = 59; + + /** Snapshot of satellite controller. */ + repeated SatelliteSession satellite_session = 60; + + /* Timestamp of last satellite_controller pull. */ + optional int64 satellite_session_pull_timestamp_millis = 61; + + /** Snapshot of satellite incoming datagram. */ + repeated SatelliteIncomingDatagram satellite_incoming_datagram = 62; + + /* Timestamp of last satellite_incoming_datagram pull. */ + optional int64 satellite_incoming_datagram_pull_timestamp_millis = 63; + + /** Snapshot of satellite outgoing datagram. */ + repeated SatelliteOutgoingDatagram satellite_outgoing_datagram = 64; + + /* Timestamp of last satellite_outgoing_datagram pull. */ + optional int64 satellite_outgoing_datagram_pull_timestamp_millis = 65; + + /** Snapshot of satellite provision datagram. */ + repeated SatelliteProvision satellite_provision = 66; + + /* Timestamp of last satellite_provision pull. */ + optional int64 satellite_provision_pull_timestamp_millis = 67; + + /** Snapshot of satellite SOS message recommender. */ + repeated SatelliteSosMessageRecommender satellite_sos_message_recommender = 68; + + /* Timestamp of last satellite_sos_message_recommender pull. */ + optional int64 satellite_sos_message_recommender_pull_timestamp_millis = 69; } // The canonical versions of the following enums live in: @@ -538,3 +574,57 @@ message OutgoingShortCodeSms { optional int32 xml_version = 2; optional int32 short_code_sms_count = 3; } + +message SatelliteController { + optional int32 count_of_satellite_service_enablements_success = 1; + optional int32 count_of_satellite_service_enablements_fail = 2; + optional int32 count_of_outgoing_datagram_success = 3; + optional int32 count_of_outgoing_datagram_fail = 4; + optional int32 count_of_incoming_datagram_success = 5; + optional int32 count_of_incoming_datagram_fail = 6; + optional int32 count_of_datagram_type_sos_sms_success = 7; + optional int32 count_of_datagram_type_sos_sms_fail = 8; + optional int32 count_of_datagram_type_location_sharing_success = 9; + optional int32 count_of_datagram_type_location_sharing_fail = 10; + optional int32 count_of_provision_success = 11; + optional int32 count_of_provision_fail = 12; + optional int32 count_of_deprovision_success = 13; + optional int32 count_of_deprovision_fail = 14; + optional int32 total_service_uptime_sec = 15; + optional int32 total_battery_consumption_percent = 16; + optional int32 total_battery_charged_time_sec = 17; +} + +message SatelliteSession { + optional int32 satellite_service_initialization_result = 1; + optional int32 satellite_technology = 2; + optional int32 count = 3; +} + +message SatelliteIncomingDatagram { + optional int32 result_code = 1; + optional int32 datagram_size_bytes = 2; + optional int64 datagram_transfer_time_millis = 3; +} + +message SatelliteOutgoingDatagram { + optional int32 datagram_type = 1; + optional int32 result_code = 2; + optional int32 datagram_size_bytes = 3; + optional int64 datagram_transfer_time_millis = 4; +} + +message SatelliteProvision { + optional int32 result_code = 1; + optional int32 provisioning_time_sec = 2; + optional bool is_provision_request = 3; + optional bool is_canceled = 4; +} + +message SatelliteSosMessageRecommender { + optional bool is_display_sos_message_sent = 1; + optional int32 count_of_timer_started = 2; + optional bool is_ims_registered = 3; + optional int32 cellular_service_state = 4; + optional int32 count = 5; +} diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 634b739111..f5cd1e26d9 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -35,6 +35,12 @@ import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS; 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_CONTROLLER; +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; +import static com.android.internal.telephony.TelephonyStatsLog.SATELLITE_SESSION; +import static com.android.internal.telephony.TelephonyStatsLog.SATELLITE_SOS_MESSAGE_RECOMMENDER; import static com.android.internal.telephony.TelephonyStatsLog.SIM_SLOT_STATE; import static com.android.internal.telephony.TelephonyStatsLog.SIP_DELEGATE_STATS; import static com.android.internal.telephony.TelephonyStatsLog.SIP_MESSAGE_RESPONSE; @@ -75,6 +81,12 @@ import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms; 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.SatelliteController; +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.nano.PersistAtomsProto.SipDelegateStats; import com.android.internal.telephony.nano.PersistAtomsProto.SipMessageResponse; import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportFeatureTagStats; @@ -176,6 +188,12 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { registerAtom(GBA_EVENT); registerAtom(PER_SIM_STATUS); registerAtom(OUTGOING_SHORT_CODE_SMS); + registerAtom(SATELLITE_CONTROLLER); + registerAtom(SATELLITE_SESSION); + registerAtom(SATELLITE_INCOMING_DATAGRAM); + registerAtom(SATELLITE_OUTGOING_DATAGRAM); + registerAtom(SATELLITE_PROVISION); + registerAtom(SATELLITE_SOS_MESSAGE_RECOMMENDER); Rlog.d(TAG, "registered"); } else { Rlog.e(TAG, "could not get StatsManager, atoms not registered"); @@ -252,6 +270,18 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return pullPerSimStatus(data); case OUTGOING_SHORT_CODE_SMS: return pullOutgoingShortCodeSms(data); + case SATELLITE_CONTROLLER: + return pullSatelliteController(data); + case SATELLITE_SESSION: + return pullSatelliteSession(data); + case SATELLITE_INCOMING_DATAGRAM: + return pullSatelliteIncomingDatagram(data); + case SATELLITE_OUTGOING_DATAGRAM: + return pullSatelliteOutgoingDatagram(data); + case SATELLITE_PROVISION: + return pullSatelliteProvision(data); + case SATELLITE_SOS_MESSAGE_RECOMMENDER: + return pullSatelliteSosMessageRecommender(data); default: Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag)); return StatsManager.PULL_SKIP; @@ -309,11 +339,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } } - private void concludeAll() { - concludeDataCallSessionStats(); - concludeImsStats(); - concludeServiceStateStats(); - + private void concludeRcsStats() { RcsStats rcsStats = RcsStats.getInstance(); if (rcsStats != null) { rcsStats.concludeSipTransportFeatureTagsStat(); @@ -323,6 +349,13 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } } + private void concludeAll() { + concludeDataCallSessionStats(); + concludeImsStats(); + concludeServiceStateStats(); + concludeRcsStats(); + } + private static int pullSimSlotState(List data) { SimSlotState state; try { @@ -750,6 +783,86 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } } + private int pullSatelliteController(List data) { + SatelliteController[] controllerAtoms = + mStorage.getSatelliteControllerStats(MIN_COOLDOWN_MILLIS); + if (controllerAtoms != null) { + Arrays.stream(controllerAtoms) + .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); + return StatsManager.PULL_SUCCESS; + } else { + Rlog.w(TAG, "SATELLITE_CONTROLLER pull too frequent, skipping"); + return StatsManager.PULL_SKIP; + } + } + + private int pullSatelliteSession(List data) { + SatelliteSession[] sessionAtoms = + mStorage.getSatelliteSessionStats(MIN_COOLDOWN_MILLIS); + if (sessionAtoms != null) { + Arrays.stream(sessionAtoms) + .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); + return StatsManager.PULL_SUCCESS; + } else { + Rlog.w(TAG, "SATELLITE_SESSION pull too frequent, skipping"); + return StatsManager.PULL_SKIP; + } + } + + private int pullSatelliteIncomingDatagram(List data) { + SatelliteIncomingDatagram[] incomingDatagramAtoms = + mStorage.getSatelliteIncomingDatagramStats(MIN_COOLDOWN_MILLIS); + if (incomingDatagramAtoms != null) { + Arrays.stream(incomingDatagramAtoms) + .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); + return StatsManager.PULL_SUCCESS; + } else { + Rlog.w(TAG, "SATELLITE_INCOMING_DATAGRAM pull too frequent, skipping"); + return StatsManager.PULL_SKIP; + } + } + + + private int pullSatelliteOutgoingDatagram(List data) { + SatelliteOutgoingDatagram[] outgoingDatagramAtoms = + mStorage.getSatelliteOutgoingDatagramStats(MIN_COOLDOWN_MILLIS); + if (outgoingDatagramAtoms != null) { + Arrays.stream(outgoingDatagramAtoms) + .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); + return StatsManager.PULL_SUCCESS; + } else { + Rlog.w(TAG, "SATELLITE_OUTGOING_DATAGRAM pull too frequent, skipping"); + return StatsManager.PULL_SKIP; + } + } + + + private int pullSatelliteProvision(List data) { + SatelliteProvision[] provisionAtoms = + mStorage.getSatelliteProvisionStats(MIN_COOLDOWN_MILLIS); + if (provisionAtoms != null) { + Arrays.stream(provisionAtoms) + .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); + return StatsManager.PULL_SUCCESS; + } else { + Rlog.w(TAG, "SATELLITE_PROVISION pull too frequent, skipping"); + return StatsManager.PULL_SKIP; + } + } + + private int pullSatelliteSosMessageRecommender(List data) { + SatelliteSosMessageRecommender[] sosMessageRecommenderAtoms = + mStorage.getSatelliteSosMessageRecommenderStats(MIN_COOLDOWN_MILLIS); + if (sosMessageRecommenderAtoms != null) { + Arrays.stream(sosMessageRecommenderAtoms) + .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom))); + return StatsManager.PULL_SUCCESS; + } else { + Rlog.w(TAG, "SATELLITE_SOS_MESSAGE_RECOMMENDER 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, @@ -1099,6 +1212,72 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { shortCodeSms.shortCodeSmsCount); } + private static StatsEvent buildStatsEvent(SatelliteController satelliteController) { + return TelephonyStatsLog.buildStatsEvent( + SATELLITE_CONTROLLER, + satelliteController.countOfSatelliteServiceEnablementsSuccess, + satelliteController.countOfSatelliteServiceEnablementsFail, + satelliteController.countOfOutgoingDatagramSuccess, + satelliteController.countOfOutgoingDatagramFail, + satelliteController.countOfIncomingDatagramSuccess, + satelliteController.countOfIncomingDatagramFail, + satelliteController.countOfDatagramTypeSosSmsSuccess, + satelliteController.countOfDatagramTypeSosSmsFail, + satelliteController.countOfDatagramTypeLocationSharingSuccess, + satelliteController.countOfDatagramTypeLocationSharingFail, + satelliteController.countOfProvisionSuccess, + satelliteController.countOfProvisionFail, + satelliteController.countOfDeprovisionSuccess, + satelliteController.countOfDeprovisionFail, + satelliteController.totalServiceUptimeSec, + satelliteController.totalBatteryConsumptionPercent, + satelliteController.totalBatteryChargedTimeSec); + } + + private static StatsEvent buildStatsEvent(SatelliteSession satelliteSession) { + return TelephonyStatsLog.buildStatsEvent( + SATELLITE_SESSION, + satelliteSession.satelliteServiceInitializationResult, + satelliteSession.satelliteTechnology, + satelliteSession.count); + } + + private static StatsEvent buildStatsEvent(SatelliteIncomingDatagram stats) { + return TelephonyStatsLog.buildStatsEvent( + SATELLITE_INCOMING_DATAGRAM, + stats.resultCode, + stats.datagramSizeBytes, + stats.datagramTransferTimeMillis); + } + + private static StatsEvent buildStatsEvent(SatelliteOutgoingDatagram stats) { + return TelephonyStatsLog.buildStatsEvent( + SATELLITE_OUTGOING_DATAGRAM, + stats.datagramType, + stats.resultCode, + stats.datagramSizeBytes, + stats.datagramTransferTimeMillis); + } + + private static StatsEvent buildStatsEvent(SatelliteProvision stats) { + return TelephonyStatsLog.buildStatsEvent( + SATELLITE_PROVISION, + stats.resultCode, + stats.provisioningTimeSec, + stats.isProvisionRequest, + stats.isCanceled); + } + + private static StatsEvent buildStatsEvent(SatelliteSosMessageRecommender stats) { + return TelephonyStatsLog.buildStatsEvent( + SATELLITE_SOS_MESSAGE_RECOMMENDER, + stats.isDisplaySosMessageSent, + stats.countOfTimerStarted, + stats.isImsRegistered, + stats.cellularServiceState, + stats.count); + } + /** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */ private static Phone[] getPhonesIfAny() { try { diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java index f92071f8e8..13ba91b269 100644 --- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java +++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java @@ -48,6 +48,12 @@ import com.android.internal.telephony.nano.PersistAtomsProto.PersistAtoms; 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.SatelliteController; +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.nano.PersistAtomsProto.SipDelegateStats; import com.android.internal.telephony.nano.PersistAtomsProto.SipMessageResponse; import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportFeatureTagStats; @@ -160,10 +166,13 @@ public class PersistAtomsStorage { /** Maximum number of GBA Event to store between pulls. */ private final int mMaxNumGbaEventStats; - - /** Maximum number of outgoing short code sms to store between pulls. */ + /** Maximum number of outgoing short code sms to store between pulls. */ private final int mMaxOutgoingShortCodeSms; + /** Maximum number of Satellite relevant stats to store between pulls. */ + private final int mMaxNumSatelliteStats; + private final int mMaxNumSatelliteControllerStats = 1; + /** Stores persist atoms and persist states of the puller. */ @VisibleForTesting protected PersistAtoms mAtoms; @@ -213,6 +222,7 @@ public class PersistAtomsStorage { mMaxNumPresenceNotifyEventStats = 10; mMaxNumGbaEventStats = 5; mMaxOutgoingShortCodeSms = 5; + mMaxNumSatelliteStats = 5; } else { mMaxNumVoiceCallSessions = 50; mMaxNumSms = 25; @@ -236,6 +246,7 @@ public class PersistAtomsStorage { mMaxNumPresenceNotifyEventStats = 50; mMaxNumGbaEventStats = 10; mMaxOutgoingShortCodeSms = 10; + mMaxNumSatelliteStats = 15; } mAtoms = loadAtomsFromFile(); @@ -682,6 +693,101 @@ public class PersistAtomsStorage { saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS); } + /** Adds a new {@link SatelliteController} to the storage. */ + public synchronized void addSatelliteControllerStats(SatelliteController stats) { + // SatelliteController is a single data point + SatelliteController[] atomArray = mAtoms.satelliteController; + if (atomArray == null || atomArray.length == 0) { + atomArray = new SatelliteController[] {new SatelliteController()}; + } + + SatelliteController atom = atomArray[0]; + atom.countOfSatelliteServiceEnablementsSuccess + += stats.countOfSatelliteServiceEnablementsSuccess; + atom.countOfSatelliteServiceEnablementsFail + += stats.countOfSatelliteServiceEnablementsFail; + atom.countOfOutgoingDatagramSuccess + += stats.countOfOutgoingDatagramSuccess; + atom.countOfOutgoingDatagramFail + += stats.countOfOutgoingDatagramFail; + atom.countOfIncomingDatagramSuccess + += stats.countOfIncomingDatagramSuccess; + atom.countOfIncomingDatagramFail + += stats.countOfIncomingDatagramFail; + atom.countOfDatagramTypeSosSmsSuccess + += stats.countOfDatagramTypeSosSmsSuccess; + atom.countOfDatagramTypeSosSmsFail + += stats.countOfDatagramTypeSosSmsFail; + atom.countOfDatagramTypeLocationSharingSuccess + += stats.countOfDatagramTypeLocationSharingSuccess; + atom.countOfDatagramTypeLocationSharingFail + += stats.countOfDatagramTypeLocationSharingFail; + atom.countOfProvisionSuccess + += stats.countOfProvisionSuccess; + atom.countOfProvisionFail + += stats.countOfProvisionFail; + atom.countOfDeprovisionSuccess + += stats.countOfDeprovisionSuccess; + atom.countOfDeprovisionFail + += stats.countOfDeprovisionFail; + atom.totalServiceUptimeSec + += stats.totalServiceUptimeSec; + atom.totalBatteryConsumptionPercent + += stats.totalBatteryConsumptionPercent; + atom.totalBatteryChargedTimeSec + += stats.totalBatteryChargedTimeSec; + + mAtoms.satelliteController = atomArray; + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS); + } + + /** Adds a new {@link SatelliteSession} to the storage. */ + public synchronized void addSatelliteSessionStats(SatelliteSession stats) { + SatelliteSession existingStats = find(stats); + if (existingStats != null) { + existingStats.count += 1; + } else { + mAtoms.satelliteSession = + insertAtRandomPlace(mAtoms.satelliteSession, stats, mMaxNumSatelliteStats); + } + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS); + } + + /** Adds a new {@link SatelliteIncomingDatagram} to the storage. */ + public synchronized void addSatelliteIncomingDatagramStats(SatelliteIncomingDatagram stats) { + mAtoms.satelliteIncomingDatagram = + insertAtRandomPlace(mAtoms.satelliteIncomingDatagram, stats, mMaxNumSatelliteStats); + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS); + } + + /** Adds a new {@link SatelliteOutgoingDatagram} to the storage. */ + public synchronized void addSatelliteOutgoingDatagramStats(SatelliteOutgoingDatagram stats) { + mAtoms.satelliteOutgoingDatagram = + insertAtRandomPlace(mAtoms.satelliteOutgoingDatagram, stats, mMaxNumSatelliteStats); + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS); + } + + /** Adds a new {@link SatelliteProvision} to the storage. */ + public synchronized void addSatelliteProvisionStats(SatelliteProvision stats) { + mAtoms.satelliteProvision = + insertAtRandomPlace(mAtoms.satelliteProvision, stats, mMaxNumSatelliteStats); + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS); + } + + /** Adds a new {@link SatelliteSosMessageRecommender} to the storage. */ + public synchronized void addSatelliteSosMessageRecommenderStats( + SatelliteSosMessageRecommender stats) { + SatelliteSosMessageRecommender existingStats = find(stats); + if (existingStats != null) { + existingStats.count += 1; + } else { + mAtoms.satelliteSosMessageRecommender = + insertAtRandomPlace(mAtoms.satelliteSosMessageRecommender, 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}. @@ -1229,6 +1335,117 @@ public class PersistAtomsStorage { } } + /** + * Returns and clears the {@link SatelliteController} stats if last pulled longer than {@code + * minIntervalMillis} ago, otherwise returns {@code null}. + */ + @Nullable + public synchronized SatelliteController[] getSatelliteControllerStats(long minIntervalMillis) { + if (getWallTimeMillis() - mAtoms.satelliteControllerPullTimestampMillis + > minIntervalMillis) { + mAtoms.satelliteControllerPullTimestampMillis = getWallTimeMillis(); + SatelliteController[] statsArray = mAtoms.satelliteController; + mAtoms.satelliteController = new SatelliteController[0]; + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS); + return statsArray; + } else { + return null; + } + } + + /** + * Returns and clears the {@link SatelliteSession} stats if last pulled longer than {@code + * minIntervalMillis} ago, otherwise returns {@code null}. + */ + @Nullable + public synchronized SatelliteSession[] getSatelliteSessionStats(long minIntervalMillis) { + if (getWallTimeMillis() - mAtoms.satelliteSessionPullTimestampMillis + > minIntervalMillis) { + mAtoms.satelliteSessionPullTimestampMillis = getWallTimeMillis(); + SatelliteSession[] statsArray = mAtoms.satelliteSession; + mAtoms.satelliteSession = new SatelliteSession[0]; + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS); + return statsArray; + } else { + return null; + } + } + + /** + * Returns and clears the {@link SatelliteIncomingDatagram} stats if last pulled longer than + * {@code minIntervalMillis} ago, otherwise returns {@code null}. + */ + @Nullable + public synchronized SatelliteIncomingDatagram[] getSatelliteIncomingDatagramStats( + long minIntervalMillis) { + if (getWallTimeMillis() - mAtoms.satelliteIncomingDatagramPullTimestampMillis + > minIntervalMillis) { + mAtoms.satelliteIncomingDatagramPullTimestampMillis = getWallTimeMillis(); + SatelliteIncomingDatagram[] statsArray = mAtoms.satelliteIncomingDatagram; + mAtoms.satelliteIncomingDatagram = new SatelliteIncomingDatagram[0]; + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS); + return statsArray; + } else { + return null; + } + } + + /** + * Returns and clears the {@link SatelliteOutgoingDatagram} stats if last pulled longer than + * {@code minIntervalMillis} ago, otherwise returns {@code null}. + */ + @Nullable + public synchronized SatelliteOutgoingDatagram[] getSatelliteOutgoingDatagramStats( + long minIntervalMillis) { + if (getWallTimeMillis() - mAtoms.satelliteOutgoingDatagramPullTimestampMillis + > minIntervalMillis) { + mAtoms.satelliteOutgoingDatagramPullTimestampMillis = getWallTimeMillis(); + SatelliteOutgoingDatagram[] statsArray = mAtoms.satelliteOutgoingDatagram; + mAtoms.satelliteOutgoingDatagram = new SatelliteOutgoingDatagram[0]; + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS); + return statsArray; + } else { + return null; + } + } + + /** + * Returns and clears the {@link SatelliteProvision} stats if last pulled longer than {@code + * minIntervalMillis} ago, otherwise returns {@code null}. + */ + @Nullable + public synchronized SatelliteProvision[] getSatelliteProvisionStats(long minIntervalMillis) { + if (getWallTimeMillis() - mAtoms.satelliteProvisionPullTimestampMillis + > minIntervalMillis) { + mAtoms.satelliteProvisionPullTimestampMillis = getWallTimeMillis(); + SatelliteProvision[] statsArray = mAtoms.satelliteProvision; + mAtoms.satelliteProvision = new SatelliteProvision[0]; + saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS); + return statsArray; + } else { + return null; + } + } + + /** + * Returns and clears the {@link SatelliteSosMessageRecommender} stats if last pulled longer + * than {@code minIntervalMillis} ago, otherwise returns {@code null}. + */ + @Nullable + public synchronized SatelliteSosMessageRecommender[] getSatelliteSosMessageRecommenderStats( + long minIntervalMillis) { + if (getWallTimeMillis() - mAtoms.satelliteSosMessageRecommenderPullTimestampMillis + > minIntervalMillis) { + mAtoms.satelliteProvisionPullTimestampMillis = getWallTimeMillis(); + SatelliteSosMessageRecommender[] statsArray = mAtoms.satelliteSosMessageRecommender; + mAtoms.satelliteSosMessageRecommender = new SatelliteSosMessageRecommender[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); @@ -1366,6 +1583,19 @@ public class PersistAtomsStorage { ); atoms.outgoingShortCodeSms = sanitizeAtoms(atoms.outgoingShortCodeSms, OutgoingShortCodeSms.class, mMaxOutgoingShortCodeSms); + atoms.satelliteController = sanitizeAtoms(atoms.satelliteController, + SatelliteController.class, mMaxNumSatelliteControllerStats); + atoms.satelliteSession = sanitizeAtoms(atoms.satelliteSession, + SatelliteSession.class, mMaxNumSatelliteStats); + atoms.satelliteIncomingDatagram = sanitizeAtoms(atoms.satelliteIncomingDatagram, + SatelliteIncomingDatagram.class, mMaxNumSatelliteStats); + atoms.satelliteOutgoingDatagram = sanitizeAtoms(atoms.satelliteOutgoingDatagram, + SatelliteOutgoingDatagram.class, mMaxNumSatelliteStats); + atoms.satelliteProvision = sanitizeAtoms(atoms.satelliteProvision, + SatelliteProvision.class, mMaxNumSatelliteStats); + atoms.satelliteSosMessageRecommender = sanitizeAtoms( + atoms.satelliteSosMessageRecommender, SatelliteSosMessageRecommender.class, + mMaxNumSatelliteStats); // out of caution, sanitize also the timestamps atoms.voiceCallRatUsagePullTimestampMillis = @@ -1416,7 +1646,18 @@ public class PersistAtomsStorage { sanitizeTimestamp(atoms.gbaEventPullTimestampMillis); atoms.outgoingShortCodeSmsPullTimestampMillis = sanitizeTimestamp(atoms.outgoingShortCodeSmsPullTimestampMillis); - + atoms.satelliteControllerPullTimestampMillis = + sanitizeTimestamp(atoms.satelliteControllerPullTimestampMillis); + atoms.satelliteSessionPullTimestampMillis = + sanitizeTimestamp(atoms.satelliteSessionPullTimestampMillis); + atoms.satelliteIncomingDatagramPullTimestampMillis = + sanitizeTimestamp(atoms.satelliteIncomingDatagramPullTimestampMillis); + atoms.satelliteOutgoingDatagramPullTimestampMillis = + sanitizeTimestamp(atoms.satelliteOutgoingDatagramPullTimestampMillis); + atoms.satelliteProvisionPullTimestampMillis = + sanitizeTimestamp(atoms.satelliteProvisionPullTimestampMillis); + atoms.satelliteSosMessageRecommenderPullTimestampMillis = + sanitizeTimestamp(atoms.satelliteSosMessageRecommenderPullTimestampMillis); return atoms; } catch (NoSuchFileException e) { Rlog.d(TAG, "PersistAtoms file not found"); @@ -1798,6 +2039,39 @@ public class PersistAtomsStorage { return null; } + /** + * Returns SatelliteOutgoingDatagram atom that has same values or {@code null} + * if it does not exist. + */ + private @Nullable SatelliteSession find( + SatelliteSession key) { + for (SatelliteSession stats : mAtoms.satelliteSession) { + if (stats.satelliteServiceInitializationResult + == key.satelliteServiceInitializationResult + && stats.satelliteTechnology == key.satelliteTechnology) { + return stats; + } + } + return null; + } + + /** + * Returns SatelliteOutgoingDatagram atom that has same values or {@code null} + * if it does not exist. + */ + private @Nullable SatelliteSosMessageRecommender find( + SatelliteSosMessageRecommender key) { + for (SatelliteSosMessageRecommender stats : mAtoms.satelliteSosMessageRecommender) { + if (stats.isDisplaySosMessageSent == key.isDisplaySosMessageSent + && stats.countOfTimerStarted == key.countOfTimerStarted + && stats.isImsRegistered == key.isImsRegistered + && stats.cellularServiceState == key.cellularServiceState) { + return stats; + } + } + return null; + } + /** * Inserts a new element in a random position in an array with a maximum size. * @@ -2044,6 +2318,12 @@ public class PersistAtomsStorage { atoms.presenceNotifyEventPullTimestampMillis = currentTime; atoms.gbaEventPullTimestampMillis = currentTime; atoms.outgoingShortCodeSmsPullTimestampMillis = currentTime; + atoms.satelliteControllerPullTimestampMillis = currentTime; + atoms.satelliteSessionPullTimestampMillis = currentTime; + atoms.satelliteIncomingDatagramPullTimestampMillis = currentTime; + atoms.satelliteOutgoingDatagramPullTimestampMillis = currentTime; + atoms.satelliteProvisionPullTimestampMillis = currentTime; + atoms.satelliteSosMessageRecommenderPullTimestampMillis = 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 new file mode 100644 index 0000000000..7ff370c252 --- /dev/null +++ b/src/java/com/android/internal/telephony/metrics/SatelliteStats.java @@ -0,0 +1,905 @@ +/* + * Copyright (C) 2023 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 com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteController; +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.telephony.Rlog; + +/** Tracks Satellite metrics for each phone */ +public class SatelliteStats { + private static final String TAG = SatelliteStats.class.getSimpleName(); + + private final PersistAtomsStorage mAtomsStorage = + PhoneFactory.getMetricsCollector().getAtomsStorage(); + + private static SatelliteStats sInstance = null; + + /** Gets the instance of SatelliteStats */ + public static SatelliteStats getInstance() { + if (sInstance == null) { + Rlog.d(TAG, "SatelliteStats created."); + synchronized (SatelliteStats.class) { + sInstance = new SatelliteStats(); + } + } + return sInstance; + } + + /** + * A data class to contain whole component of {@link SatelliteController) atom. + * Refer to {@link #onSatelliteControllerMetrics(SatelliteControllerParams)}. + */ + public class SatelliteControllerParams { + private final int mCountOfSatelliteServiceEnablementsSuccess; + private final int mCountOfSatelliteServiceEnablementsFail; + private final int mCountOfOutgoingDatagramSuccess; + private final int mCountOfOutgoingDatagramFail; + private final int mCountOfIncomingDatagramSuccess; + private final int mCountOfIncomingDatagramFail; + private final int mCountOfDatagramTypeSosSmsSuccess; + private final int mCountOfDatagramTypeSosSmsFail; + private final int mCountOfDatagramTypeLocationSharingSuccess; + private final int mCountOfDatagramTypeLocationSharingFail; + private final int mCountOfProvisionSuccess; + private final int mCountOfProvisionFail; + private final int mCountOfDeprovisionSuccess; + private final int mCountOfDeprovisionFail; + private final int mTotalServiceUptimeSec; + private final int mTotalBatteryConsumptionPercent; + private final int mTotalBatteryChargedTimeSec; + + private SatelliteControllerParams(Builder builder) { + this.mCountOfSatelliteServiceEnablementsSuccess = + builder.mCountOfSatelliteServiceEnablementsSuccess; + this.mCountOfSatelliteServiceEnablementsFail = + builder.mCountOfSatelliteServiceEnablementsFail; + this.mCountOfOutgoingDatagramSuccess = builder.mCountOfOutgoingDatagramSuccess; + this.mCountOfOutgoingDatagramFail = builder.mCountOfOutgoingDatagramFail; + this.mCountOfIncomingDatagramSuccess = builder.mCountOfIncomingDatagramSuccess; + this.mCountOfIncomingDatagramFail = builder.mCountOfIncomingDatagramFail; + this.mCountOfDatagramTypeSosSmsSuccess = builder.mCountOfDatagramTypeSosSmsSuccess; + this.mCountOfDatagramTypeSosSmsFail = builder.mCountOfDatagramTypeSosSmsFail; + this.mCountOfDatagramTypeLocationSharingSuccess = + builder.mCountOfDatagramTypeLocationSharingSuccess; + this.mCountOfDatagramTypeLocationSharingFail = + builder.mCountOfDatagramTypeLocationSharingFail; + this.mCountOfProvisionSuccess = builder.mCountOfProvisionSuccess; + this.mCountOfProvisionFail = builder.mCountOfProvisionFail; + this.mCountOfDeprovisionSuccess = builder.mCountOfDeprovisionSuccess; + this.mCountOfDeprovisionFail = builder.mCountOfDeprovisionFail; + this.mTotalServiceUptimeSec = builder.mTotalServiceUptimeSec; + this.mTotalBatteryConsumptionPercent = builder.mTotalBatteryConsumptionPercent; + this.mTotalBatteryChargedTimeSec = builder.mTotalBatteryChargedTimeSec; + } + + public int getCountOfSatelliteServiceEnablementsSuccess() { + return mCountOfSatelliteServiceEnablementsSuccess; + } + + public int getCountOfSatelliteServiceEnablementsFail() { + return mCountOfSatelliteServiceEnablementsFail; + } + + public int getCountOfOutgoingDatagramSuccess() { + return mCountOfOutgoingDatagramSuccess; + } + + public int getCountOfOutgoingDatagramFail() { + return mCountOfOutgoingDatagramFail; + } + + public int getCountOfIncomingDatagramSuccess() { + return mCountOfIncomingDatagramSuccess; + } + + public int getCountOfIncomingDatagramFail() { + return mCountOfIncomingDatagramFail; + } + + public int getCountOfDatagramTypeSosSmsSuccess() { + return mCountOfDatagramTypeSosSmsSuccess; + } + + public int getCountOfDatagramTypeSosSmsFail() { + return mCountOfDatagramTypeSosSmsFail; + } + + public int getCountOfDatagramTypeLocationSharingSuccess() { + return mCountOfDatagramTypeLocationSharingSuccess; + } + + public int getCountOfDatagramTypeLocationSharingFail() { + return mCountOfDatagramTypeLocationSharingFail; + } + + public int getCountOfProvisionSuccess() { + return mCountOfProvisionSuccess; + } + + public int getCountOfProvisionFail() { + return mCountOfProvisionFail; + } + + public int getCountOfDeprovisionSuccess() { + return mCountOfDeprovisionSuccess; + } + + public int getCountOfDeprovisionFail() { + return mCountOfDeprovisionFail; + } + + public int getTotalServiceUptimeSec() { + return mTotalServiceUptimeSec; + } + + public int getTotalBatteryConsumptionPercent() { + return mTotalBatteryConsumptionPercent; + } + + public int getTotalBatteryChargedTimeSec() { + return mTotalBatteryChargedTimeSec; + } + + /** + * A builder class to create {@link SatelliteControllerParams} data structure class + */ + public static class Builder { + private int mCountOfSatelliteServiceEnablementsSuccess = 0; + private int mCountOfSatelliteServiceEnablementsFail = 0; + private int mCountOfOutgoingDatagramSuccess = 0; + private int mCountOfOutgoingDatagramFail = 0; + private int mCountOfIncomingDatagramSuccess = 0; + private int mCountOfIncomingDatagramFail = 0; + private int mCountOfDatagramTypeSosSmsSuccess = 0; + private int mCountOfDatagramTypeSosSmsFail = 0; + private int mCountOfDatagramTypeLocationSharingSuccess = 0; + private int mCountOfDatagramTypeLocationSharingFail = 0; + private int mCountOfProvisionSuccess; + private int mCountOfProvisionFail; + private int mCountOfDeprovisionSuccess; + private int mCountOfDeprovisionFail; + private int mTotalServiceUptimeSec = 0; + private int mTotalBatteryConsumptionPercent = 0; + private int mTotalBatteryChargedTimeSec = 0; + + /** + * Sets countOfSatelliteServiceEnablementsSuccess value of {@link SatelliteController} + * atom then returns Builder class + */ + public Builder setCountOfSatelliteServiceEnablementsSuccess( + int countOfSatelliteServiceEnablementsSuccess) { + this.mCountOfSatelliteServiceEnablementsSuccess = + countOfSatelliteServiceEnablementsSuccess; + return this; + } + + /** + * Sets countOfSatelliteServiceEnablementsFail value of {@link SatelliteController} atom + * then returns Builder class + */ + public Builder setCountOfSatelliteServiceEnablementsFail( + int countOfSatelliteServiceEnablementsFail) { + this.mCountOfSatelliteServiceEnablementsFail = + countOfSatelliteServiceEnablementsFail; + return this; + } + + /** + * Sets countOfOutgoingDatagramSuccess value of {@link SatelliteController} atom then + * returns Builder class + */ + public Builder setCountOfOutgoingDatagramSuccess(int countOfOutgoingDatagramSuccess) { + this.mCountOfOutgoingDatagramSuccess = countOfOutgoingDatagramSuccess; + return this; + } + + /** + * Sets countOfOutgoingDatagramFail value of {@link SatelliteController} atom then + * returns Builder class + */ + public Builder setCountOfOutgoingDatagramFail(int countOfOutgoingDatagramFail) { + this.mCountOfOutgoingDatagramFail = countOfOutgoingDatagramFail; + return this; + } + + /** + * Sets countOfIncomingDatagramSuccess value of {@link SatelliteController} atom then + * returns Builder class + */ + public Builder setCountOfIncomingDatagramSuccess(int countOfIncomingDatagramSuccess) { + this.mCountOfIncomingDatagramSuccess = countOfIncomingDatagramSuccess; + return this; + } + + /** + * Sets countOfIncomingDatagramFail value of {@link SatelliteController} atom then + * returns Builder class + */ + public Builder setCountOfIncomingDatagramFail(int countOfIncomingDatagramFail) { + this.mCountOfIncomingDatagramFail = countOfIncomingDatagramFail; + return this; + } + + /** + * Sets countOfDatagramTypeSosSmsSuccess value of {@link SatelliteController} atom then + * returns Builder class + */ + public Builder setCountOfDatagramTypeSosSmsSuccess( + int countOfDatagramTypeSosSmsSuccess) { + this.mCountOfDatagramTypeSosSmsSuccess = countOfDatagramTypeSosSmsSuccess; + return this; + } + + /** + * Sets countOfDatagramTypeSosSmsFail value of {@link SatelliteController} atom then + * returns Builder class + */ + public Builder setCountOfDatagramTypeSosSmsFail(int countOfDatagramTypeSosSmsFail) { + this.mCountOfDatagramTypeSosSmsFail = countOfDatagramTypeSosSmsFail; + return this; + } + + /** + * Sets countOfDatagramTypeLocationSharingSuccess value of {@link SatelliteController} + * atom then returns Builder class + */ + public Builder setCountOfDatagramTypeLocationSharingSuccess( + int countOfDatagramTypeLocationSharingSuccess) { + this.mCountOfDatagramTypeLocationSharingSuccess = + countOfDatagramTypeLocationSharingSuccess; + return this; + } + + /** + * Sets countOfDatagramTypeLocationSharingFail value of {@link SatelliteController} + * atom then returns Builder class + */ + public Builder setCountOfDatagramTypeLocationSharingFail( + int countOfDatagramTypeLocationSharingFail) { + this.mCountOfDatagramTypeLocationSharingFail = + countOfDatagramTypeLocationSharingFail; + return this; + } + + /** + * Sets countOfProvisionSuccess value of {@link SatelliteController} + * atom then returns Builder class + */ + public Builder setCountOfProvisionSuccess(int countOfProvisionSuccess) { + this.mCountOfProvisionSuccess = countOfProvisionSuccess; + return this; + } + + /** + * Sets countOfProvisionFail value of {@link SatelliteController} + * atom then returns Builder class + */ + public Builder setCountOfProvisionFail(int countOfProvisionFail) { + this.mCountOfProvisionFail = countOfProvisionFail; + return this; + } + + /** + * Sets countOfDeprovisionSuccess value of {@link SatelliteController} + * atom then returns Builder class + */ + public Builder setCountOfDeprovisionSuccess(int countOfDeprovisionSuccess) { + this.mCountOfDeprovisionSuccess = countOfDeprovisionSuccess; + return this; + } + + /** + * Sets countOfDeprovisionSuccess value of {@link SatelliteController} + * atom then returns Builder class + */ + public Builder setCountOfDeprovisionFail(int countOfDeprovisionFail) { + this.mCountOfDeprovisionFail = countOfDeprovisionFail; + return this; + } + + /** + * Sets totalServiceUptimeSec value of {@link SatelliteController} atom then + * returns Builder class + */ + public Builder setTotalServiceUptimeSec(int totalServiceUptimeSec) { + this.mTotalServiceUptimeSec = totalServiceUptimeSec; + return this; + } + + /** + * Sets totalBatteryConsumptionPercent value of {@link SatelliteController} atom then + * returns Builder class + */ + public Builder setTotalBatteryConsumptionPercent(int totalBatteryConsumptionPercent) { + this.mTotalBatteryConsumptionPercent = totalBatteryConsumptionPercent; + return this; + } + + /** + * Sets totalBatteryChargedTimeSec value of {@link SatelliteController} atom then + * returns Builder class + */ + public Builder setTotalBatteryChargedTimeSec(int totalBatteryChargedTimeSec) { + this.mTotalBatteryChargedTimeSec = totalBatteryChargedTimeSec; + return this; + } + + /** + * Returns ControllerParams, which contains whole component of + * {@link SatelliteController} atom + */ + public SatelliteControllerParams build() { + return new SatelliteStats() + .new SatelliteControllerParams(this); + } + } + + @Override + public String toString() { + return "ControllerParams(" + + ", countOfSatelliteServiceEnablementsSuccess=" + + mCountOfSatelliteServiceEnablementsSuccess + + ", countOfSatelliteServiceEnablementsFail=" + + mCountOfSatelliteServiceEnablementsFail + + ", countOfOutgoingDatagramSuccess=" + mCountOfOutgoingDatagramSuccess + + ", countOfOutgoingDatagramFail=" + mCountOfOutgoingDatagramFail + + ", countOfIncomingDatagramSuccess=" + mCountOfIncomingDatagramSuccess + + ", countOfIncomingDatagramFail=" + mCountOfIncomingDatagramFail + + ", countOfDatagramTypeSosSms=" + mCountOfDatagramTypeSosSmsSuccess + + ", countOfDatagramTypeSosSms=" + mCountOfDatagramTypeSosSmsFail + + ", countOfDatagramTypeLocationSharing=" + + mCountOfDatagramTypeLocationSharingSuccess + + ", countOfDatagramTypeLocationSharing=" + + mCountOfDatagramTypeLocationSharingFail + + ", serviceUptimeSec=" + mTotalServiceUptimeSec + + ", batteryConsumptionPercent=" + mTotalBatteryConsumptionPercent + + ", batteryChargedTimeSec=" + mTotalBatteryChargedTimeSec + + ")"; + } + } + + /** + * A data class to contain whole component of {@link SatelliteSession) atom. + * Refer to {@link #onSatelliteSessionMetrics(SatelliteSessionParams)}. + */ + public class SatelliteSessionParams { + private final int mSatelliteServiceInitializationResult; + private final int mSatelliteTechnology; + + private SatelliteSessionParams(Builder builder) { + this.mSatelliteServiceInitializationResult = + builder.mSatelliteServiceInitializationResult; + this.mSatelliteTechnology = builder.mSatelliteTechnology; + } + + public int getSatelliteServiceInitializationResult() { + return mSatelliteServiceInitializationResult; + } + + public int getSatelliteTechnology() { + return mSatelliteTechnology; + } + + /** + * A builder class to create {@link SatelliteSessionParams} data structure class + */ + public static class Builder { + private int mSatelliteServiceInitializationResult = -1; + private int mSatelliteTechnology = -1; + + /** + * Sets satelliteServiceInitializationResult value of {@link SatelliteSession} + * atom then returns Builder class + */ + public Builder setSatelliteServiceInitializationResult( + int satelliteServiceInitializationResult) { + this.mSatelliteServiceInitializationResult = satelliteServiceInitializationResult; + return this; + } + + /** + * Sets satelliteTechnology value of {@link SatelliteSession} atoms then + * returns Builder class + */ + public Builder setSatelliteTechnology(int satelliteTechnology) { + this.mSatelliteTechnology = satelliteTechnology; + return this; + } + + /** + * Returns SessionParams, which contains whole component of + * {@link SatelliteSession} atom + */ + public SatelliteSessionParams build() { + return new SatelliteStats() + .new SatelliteSessionParams(this); + } + } + + @Override + public String toString() { + return "SessionParams(" + + ", satelliteServiceInitializationResult=" + + mSatelliteServiceInitializationResult + + ", satelliteTechnology=" + mSatelliteTechnology + + ")"; + } + } + + /** + * A data class to contain whole component of {@link SatelliteIncomingDatagram} atom. + * Refer to {@link #onSatelliteIncomingDatagramMetrics(SatelliteIncomingDatagramParams)}. + */ + public class SatelliteIncomingDatagramParams { + private final int mResultCode; + private final int mDatagramSizeBytes; + private final long mDatagramTransferTimeMillis; + + private SatelliteIncomingDatagramParams(Builder builder) { + this.mResultCode = builder.mResultCode; + this.mDatagramSizeBytes = builder.mDatagramSizeBytes; + this.mDatagramTransferTimeMillis = builder.mDatagramTransferTimeMillis; + } + + public int getResultCode() { + return mResultCode; + } + + public int getDatagramSizeBytes() { + return mDatagramSizeBytes; + } + + public long getDatagramTransferTimeMillis() { + return mDatagramTransferTimeMillis; + } + + /** + * A builder class to create {@link SatelliteIncomingDatagramParams} data structure class + */ + public static class Builder { + private int mResultCode = -1; + private int mDatagramSizeBytes = -1; + private long mDatagramTransferTimeMillis = -1; + + /** + * Sets resultCode value of {@link SatelliteIncomingDatagram} atom + * then returns Builder class + */ + public Builder setResultCode(int resultCode) { + this.mResultCode = resultCode; + return this; + } + + /** + * Sets datagramSizeBytes value of {@link SatelliteIncomingDatagram} atom + * then returns Builder class + */ + public Builder setDatagramSizeBytes(int datagramSizeBytes) { + this.mDatagramSizeBytes = datagramSizeBytes; + return this; + } + + /** + * Sets datagramTransferTimeMillis value of {@link SatelliteIncomingDatagram} atom + * then returns Builder class + */ + public Builder setDatagramTransferTimeMillis(long datagramTransferTimeMillis) { + this.mDatagramTransferTimeMillis = datagramTransferTimeMillis; + return this; + } + + /** + * Returns IncomingDatagramParams, which contains whole component of + * {@link SatelliteIncomingDatagram} atom + */ + public SatelliteIncomingDatagramParams build() { + return new SatelliteStats() + .new SatelliteIncomingDatagramParams(Builder.this); + } + } + + @Override + public String toString() { + return "IncomingDatagramParams(" + + ", resultCode=" + mResultCode + + ", datagramSizeBytes=" + mDatagramSizeBytes + + ", datagramTransferTimeMillis=" + mDatagramTransferTimeMillis + ")"; + } + } + + /** + * A data class to contain whole component of {@link SatelliteOutgoingDatagram} atom. + * Refer to {@link #onSatelliteOutgoingDatagramMetrics(SatelliteOutgoingDatagramParams)}. + */ + public class SatelliteOutgoingDatagramParams { + private final int mDatagramType; + private final int mResultCode; + private final int mDatagramSizeBytes; + private final long mDatagramTransferTimeMillis; + + private SatelliteOutgoingDatagramParams(Builder builder) { + this.mDatagramType = builder.mDatagramType; + this.mResultCode = builder.mResultCode; + this.mDatagramSizeBytes = builder.mDatagramSizeBytes; + this.mDatagramTransferTimeMillis = builder.mDatagramTransferTimeMillis; + } + + public int getDatagramType() { + return mDatagramType; + } + + public int getResultCode() { + return mResultCode; + } + + public int getDatagramSizeBytes() { + return mDatagramSizeBytes; + } + + public long getDatagramTransferTimeMillis() { + return mDatagramTransferTimeMillis; + } + + /** + * A builder class to create {@link SatelliteOutgoingDatagramParams} data structure class + */ + public static class Builder { + private int mDatagramType = -1; + private int mResultCode = -1; + private int mDatagramSizeBytes = -1; + private long mDatagramTransferTimeMillis = -1; + + /** + * Sets datagramType value of {@link SatelliteOutgoingDatagram} atom + * then returns Builder class + */ + public Builder setDatagramType(int datagramType) { + this.mDatagramType = datagramType; + return this; + } + + /** + * Sets resultCode value of {@link SatelliteOutgoingDatagram} atom + * then returns Builder class + */ + public Builder setResultCode(int resultCode) { + this.mResultCode = resultCode; + return this; + } + + /** + * Sets datagramSizeBytes value of {@link SatelliteOutgoingDatagram} atom + * then returns Builder class + */ + public Builder setDatagramSizeBytes(int datagramSizeBytes) { + this.mDatagramSizeBytes = datagramSizeBytes; + return this; + } + + /** + * Sets datagramTransferTimeMillis value of {@link SatelliteOutgoingDatagram} atom + * then returns Builder class + */ + public Builder setDatagramTransferTimeMillis(long datagramTransferTimeMillis) { + this.mDatagramTransferTimeMillis = datagramTransferTimeMillis; + return this; + } + + /** + * Returns OutgoingDatagramParams, which contains whole component of + * {@link SatelliteOutgoingDatagram} atom + */ + public SatelliteOutgoingDatagramParams build() { + return new SatelliteStats() + .new SatelliteOutgoingDatagramParams(Builder.this); + } + } + + @Override + public String toString() { + return "OutgoingDatagramParams(" + + "datagramType=" + mDatagramType + + ", resultCode=" + mResultCode + + ", datagramSizeBytes=" + mDatagramSizeBytes + + ", datagramTransferTimeMillis=" + mDatagramTransferTimeMillis + ")"; + } + } + + /** + * A data class to contain whole component of {@link SatelliteProvision} atom. + * Refer to {@link #onSatelliteProvisionMetrics(SatelliteProvisionParams)}. + */ + public class SatelliteProvisionParams { + private final int mResultCode; + private final int mProvisioningTimeSec; + private final boolean mIsProvisionRequest; + private final boolean mIsCanceled; + + private SatelliteProvisionParams(Builder builder) { + this.mResultCode = builder.mResultCode; + this.mProvisioningTimeSec = builder.mProvisioningTimeSec; + this.mIsProvisionRequest = builder.mIsProvisionRequest; + this.mIsCanceled = builder.mIsCanceled; + } + + public int getResultCode() { + return mResultCode; + } + + public int getProvisioningTimeSec() { + return mProvisioningTimeSec; + } + + public boolean getIsProvisionRequest() { + return mIsProvisionRequest; + } + + public boolean getIsCanceled() { + return mIsCanceled; + } + + /** + * A builder class to create {@link SatelliteProvisionParams} data structure class + */ + public static class Builder { + private int mResultCode = -1; + private int mProvisioningTimeSec = -1; + private boolean mIsProvisionRequest = false; + private boolean mIsCanceled = false; + + /** + * Sets resultCode value of {@link SatelliteProvision} atom + * then returns Builder class + */ + public Builder setResultCode(int resultCode) { + this.mResultCode = resultCode; + return this; + } + + /** + * Sets provisioningTimeSec value of {@link SatelliteProvision} atom + * then returns Builder class + */ + public Builder setProvisioningTimeSec(int provisioningTimeSec) { + this.mProvisioningTimeSec = provisioningTimeSec; + return this; + } + + /** + * Sets isProvisionRequest value of {@link SatelliteProvision} atom + * then returns Builder class + */ + public Builder setIsProvisionRequest(boolean isProvisionRequest) { + this.mIsProvisionRequest = isProvisionRequest; + return this; + } + + /** + * Sets isCanceled value of {@link SatelliteProvision} atom + * then returns Builder class + */ + public Builder setIsCanceled(boolean isCanceled) { + this.mIsCanceled = isCanceled; + return this; + } + + /** + * Returns ProvisionParams, which contains whole component of + * {@link SatelliteProvision} atom + */ + public SatelliteProvisionParams build() { + return new SatelliteStats() + .new SatelliteProvisionParams(Builder.this); + } + } + + @Override + public String toString() { + return "ProvisionParams(" + + "resultCode=" + mResultCode + + ", provisioningTimeSec=" + mProvisioningTimeSec + + ", isProvisionRequest=" + mIsProvisionRequest + + ", isCanceled" + mIsCanceled + ")"; + } + } + + /** + * A data class to contain whole component of {@link SatelliteSosMessageRecommender} atom. + * Refer to {@link #onSatelliteSosMessageRecommender(SatelliteSosMessageRecommenderParams)}. + */ + public class SatelliteSosMessageRecommenderParams { + private final boolean mIsDisplaySosMessageSent; + private final int mCountOfTimerStarted; + private final boolean mIsImsRegistered; + private final int mCellularServiceState; + + private SatelliteSosMessageRecommenderParams(Builder builder) { + this.mIsDisplaySosMessageSent = builder.mIsDisplaySosMessageSent; + this.mCountOfTimerStarted = builder.mCountOfTimerStarted; + this.mIsImsRegistered = builder.mIsImsRegistered; + this.mCellularServiceState = builder.mCellularServiceState; + } + + public boolean isDisplaySosMessageSent() { + return mIsDisplaySosMessageSent; + } + + public int getCountOfTimerStarted() { + return mCountOfTimerStarted; + } + + public boolean isImsRegistered() { + return mIsImsRegistered; + } + + public int getCellularServiceState() { + return mCellularServiceState; + } + + /** + * A builder class to create {@link SatelliteProvisionParams} data structure class + */ + public static class Builder { + private boolean mIsDisplaySosMessageSent = false; + private int mCountOfTimerStarted = -1; + private boolean mIsImsRegistered = false; + private int mCellularServiceState = -1; + + /** + * Sets resultCode value of {@link SatelliteSosMessageRecommender} atom + * then returns Builder class + */ + public Builder setDisplaySosMessageSent( + boolean isDisplaySosMessageSent) { + this.mIsDisplaySosMessageSent = isDisplaySosMessageSent; + return this; + } + + /** + * Sets countOfTimerIsStarted value of {@link SatelliteSosMessageRecommender} atom + * then returns Builder class + */ + public Builder setCountOfTimerStarted(int countOfTimerStarted) { + this.mCountOfTimerStarted = countOfTimerStarted; + return this; + } + + /** + * Sets isImsRegistered value of {@link SatelliteSosMessageRecommender} atom + * then returns Builder class + */ + public Builder setImsRegistered(boolean isImsRegistered) { + this.mIsImsRegistered = isImsRegistered; + return this; + } + + /** + * Sets cellularServiceState value of {@link SatelliteSosMessageRecommender} atom + * then returns Builder class + */ + public Builder setCellularServiceState(int cellularServiceState) { + this.mCellularServiceState = cellularServiceState; + return this; + } + + /** + * Returns SosMessageRecommenderParams, which contains whole component of + * {@link SatelliteSosMessageRecommenderParams} atom + */ + public SatelliteSosMessageRecommenderParams build() { + return new SatelliteStats() + .new SatelliteSosMessageRecommenderParams(Builder.this); + } + } + + @Override + public String toString() { + return "SosMessageRecommenderParams(" + + "isDisplaySosMessageSent=" + mIsDisplaySosMessageSent + + ", countOfTimerStarted=" + mCountOfTimerStarted + + ", isImsRegistered=" + mIsImsRegistered + + ", cellularServiceState=" + mCellularServiceState + ")"; + } + } + + /** Create a new atom or update an existing atom for SatelliteController metrics */ + public synchronized void onSatelliteControllerMetrics(SatelliteControllerParams param) { + SatelliteController proto = new SatelliteController(); + proto.countOfSatelliteServiceEnablementsSuccess = + param.getCountOfSatelliteServiceEnablementsSuccess(); + proto.countOfSatelliteServiceEnablementsFail = + param.getCountOfSatelliteServiceEnablementsFail(); + proto.countOfOutgoingDatagramSuccess = param.getCountOfOutgoingDatagramSuccess(); + proto.countOfOutgoingDatagramFail = param.getCountOfOutgoingDatagramFail(); + proto.countOfIncomingDatagramSuccess = param.getCountOfIncomingDatagramSuccess(); + proto.countOfIncomingDatagramFail = param.getCountOfIncomingDatagramFail(); + proto.countOfDatagramTypeSosSmsSuccess = param.getCountOfDatagramTypeSosSmsSuccess(); + proto.countOfDatagramTypeSosSmsFail = param.getCountOfDatagramTypeSosSmsFail(); + proto.countOfDatagramTypeLocationSharingSuccess = + param.getCountOfDatagramTypeLocationSharingSuccess(); + proto.countOfDatagramTypeLocationSharingFail = + param.getCountOfDatagramTypeLocationSharingFail(); + proto.countOfProvisionSuccess = param.getCountOfProvisionSuccess(); + proto.countOfProvisionFail = param.getCountOfProvisionFail(); + proto.countOfDeprovisionSuccess = param.getCountOfDeprovisionSuccess(); + proto.countOfDeprovisionFail = param.getCountOfDeprovisionFail(); + proto.totalServiceUptimeSec = param.getTotalServiceUptimeSec(); + proto.totalBatteryConsumptionPercent = param.getTotalBatteryConsumptionPercent(); + proto.totalBatteryChargedTimeSec = param.getTotalBatteryChargedTimeSec(); + + mAtomsStorage.addSatelliteControllerStats(proto); + } + + /** Create a new atom or update an existing atom for SatelliteSession metrics */ + public synchronized void onSatelliteSessionMetrics(SatelliteSessionParams param) { + SatelliteSession proto = new SatelliteSession(); + proto.satelliteServiceInitializationResult = + param.getSatelliteServiceInitializationResult(); + proto.satelliteTechnology = param.getSatelliteTechnology(); + proto.count = 1; + mAtomsStorage.addSatelliteSessionStats(proto); + } + + /** Create a new atom for SatelliteIncomingDatagram metrics */ + public synchronized void onSatelliteIncomingDatagramMetrics( + SatelliteIncomingDatagramParams param) { + SatelliteIncomingDatagram proto = new SatelliteIncomingDatagram(); + proto.resultCode = param.getResultCode(); + proto.datagramSizeBytes = param.getDatagramSizeBytes(); + proto.datagramTransferTimeMillis = param.getDatagramTransferTimeMillis(); + mAtomsStorage.addSatelliteIncomingDatagramStats(proto); + } + + /** Create a new atom for SatelliteOutgoingDatagram metrics */ + public synchronized void onSatelliteOutgoingDatagramMetrics( + SatelliteOutgoingDatagramParams param) { + SatelliteOutgoingDatagram proto = new SatelliteOutgoingDatagram(); + proto.datagramType = param.getDatagramType(); + proto.resultCode = param.getResultCode(); + proto.datagramSizeBytes = param.getDatagramSizeBytes(); + proto.datagramTransferTimeMillis = param.getDatagramTransferTimeMillis(); + mAtomsStorage.addSatelliteOutgoingDatagramStats(proto); + } + + /** Create a new atom for SatelliteProvision metrics */ + public synchronized void onSatelliteProvisionMetrics(SatelliteProvisionParams param) { + SatelliteProvision proto = new SatelliteProvision(); + proto.resultCode = param.getResultCode(); + proto.provisioningTimeSec = param.getProvisioningTimeSec(); + proto.isProvisionRequest = param.getIsProvisionRequest(); + proto.isCanceled = param.getIsCanceled(); + mAtomsStorage.addSatelliteProvisionStats(proto); + } + + /** Create a new atom or update an existing atom for SatelliteSosMessageRecommender metrics */ + public synchronized void onSatelliteSosMessageRecommender( + SatelliteSosMessageRecommenderParams param) { + SatelliteSosMessageRecommender proto = new SatelliteSosMessageRecommender(); + proto.isDisplaySosMessageSent = param.isDisplaySosMessageSent(); + proto.countOfTimerStarted = param.getCountOfTimerStarted(); + proto.isImsRegistered = param.isImsRegistered(); + proto.cellularServiceState = param.getCellularServiceState(); + proto.count = 1; + mAtomsStorage.addSatelliteSosMessageRecommenderStats(proto); + } +} 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 be2257beeb..3307813d74 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java @@ -44,12 +44,12 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; import android.annotation.Nullable; import android.content.Context; import android.os.Build; import android.telephony.DisconnectCause; +import android.telephony.SatelliteProtoEnums; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.TelephonyProtoEnums; @@ -74,6 +74,12 @@ import com.android.internal.telephony.nano.PersistAtomsProto.PersistAtoms; 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.SatelliteController; +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.nano.PersistAtomsProto.SipDelegateStats; import com.android.internal.telephony.nano.PersistAtomsProto.SipMessageResponse; import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportFeatureTagStats; @@ -142,7 +148,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { private CellularDataServiceSwitch mServiceSwitch1Proto; private CellularDataServiceSwitch mServiceSwitch2Proto; - // service states for slot 0 and 1 + // Service states for slot 0 and 1 private CellularServiceState mServiceState1Proto; private CellularServiceState mServiceState2Proto; private CellularServiceState mServiceState3Proto; @@ -230,6 +236,30 @@ public class PersistAtomsStorageTest extends TelephonyTest { private OutgoingShortCodeSms mOutgoingShortCodeSms2; private OutgoingShortCodeSms[] mOutgoingShortCodeSms; + private SatelliteController mSatelliteController1; + private SatelliteController mSatelliteController2; + private SatelliteController[] mSatelliteControllers; + + private SatelliteSession mSatelliteSession1; + private SatelliteSession mSatelliteSession2; + private SatelliteSession[] mSatelliteSessions; + + private SatelliteIncomingDatagram mSatelliteIncomingDatagram1; + private SatelliteIncomingDatagram mSatelliteIncomingDatagram2; + private SatelliteIncomingDatagram[] mSatelliteIncomingDatagrams; + + private SatelliteOutgoingDatagram mSatelliteOutgoingDatagram1; + private SatelliteOutgoingDatagram mSatelliteOutgoingDatagram2; + private SatelliteOutgoingDatagram[] mSatelliteOutgoingDatagrams; + + private SatelliteProvision mSatelliteProvision1; + private SatelliteProvision mSatelliteProvision2; + private SatelliteProvision[] mSatelliteProvisions; + + private SatelliteSosMessageRecommender mSatelliteSosMessageRecommender1; + private SatelliteSosMessageRecommender mSatelliteSosMessageRecommender2; + private SatelliteSosMessageRecommender[] mSatelliteSosMessageRecommenders; + private void makeTestData() { // MO call with SRVCC (LTE to UMTS) mCall1Proto = new VoiceCallSession(); @@ -878,6 +908,145 @@ public class PersistAtomsStorageTest extends TelephonyTest { mOutgoingShortCodeSms = new OutgoingShortCodeSms[] {mOutgoingShortCodeSms1, mOutgoingShortCodeSms2}; + + generateTestSatelliteData(); + } + + private void generateTestSatelliteData() { + mSatelliteController1 = new SatelliteController(); + mSatelliteController1.countOfSatelliteServiceEnablementsSuccess = 2; + mSatelliteController1.countOfSatelliteServiceEnablementsFail = 0; + mSatelliteController1.countOfOutgoingDatagramSuccess = 8; + mSatelliteController1.countOfOutgoingDatagramFail = 9; + mSatelliteController1.countOfIncomingDatagramSuccess = 10; + mSatelliteController1.countOfIncomingDatagramFail = 11; + mSatelliteController1.countOfDatagramTypeSosSmsSuccess = 5; + mSatelliteController1.countOfDatagramTypeSosSmsFail = 5; + mSatelliteController1.countOfDatagramTypeLocationSharingSuccess = 6; + mSatelliteController1.countOfDatagramTypeLocationSharingFail = 6; + mSatelliteController1.countOfProvisionSuccess = 3; + mSatelliteController1.countOfProvisionFail = 4; + mSatelliteController1.countOfDeprovisionSuccess = 5; + mSatelliteController1.countOfDeprovisionFail = 6; + mSatelliteController1.totalServiceUptimeSec = 60 * 60 * 24 * 7; + mSatelliteController1.totalBatteryConsumptionPercent = 7; + mSatelliteController1.totalBatteryChargedTimeSec = 60 * 60 * 3 * 1; + + mSatelliteController2 = new SatelliteController(); + mSatelliteController2.countOfSatelliteServiceEnablementsSuccess = 2 + 1; + mSatelliteController2.countOfSatelliteServiceEnablementsFail = 0 + 1; + mSatelliteController2.countOfOutgoingDatagramSuccess = 8 + 1; + mSatelliteController2.countOfOutgoingDatagramFail = 9 + 1; + mSatelliteController2.countOfIncomingDatagramSuccess = 10 + 1; + mSatelliteController2.countOfIncomingDatagramFail = 11 + 1; + mSatelliteController2.countOfDatagramTypeSosSmsSuccess = 5 + 1; + mSatelliteController2.countOfDatagramTypeSosSmsFail = 5 + 1; + mSatelliteController2.countOfDatagramTypeLocationSharingSuccess = 6 + 1; + mSatelliteController2.countOfDatagramTypeLocationSharingFail = 6 + 1; + mSatelliteController2.countOfProvisionSuccess = 13; + mSatelliteController2.countOfProvisionFail = 14; + mSatelliteController2.countOfDeprovisionSuccess = 15; + mSatelliteController2.countOfDeprovisionFail = 16; + mSatelliteController2.totalServiceUptimeSec = 60 * 60 * 12; + mSatelliteController2.totalBatteryConsumptionPercent = 14; + mSatelliteController1.totalBatteryChargedTimeSec = 60 * 60 * 3; + + // SatelliteController atom has one data point + mSatelliteControllers = + new SatelliteController[] { + mSatelliteController1 + }; + + mSatelliteSession1 = new SatelliteSession(); + mSatelliteSession1.satelliteServiceInitializationResult = + SatelliteProtoEnums.SATELLITE_ERROR_NONE; + mSatelliteSession1.satelliteTechnology = + SatelliteProtoEnums.NT_RADIO_TECHNOLOGY_PROPRIETARY; + mSatelliteSession1.count = 1; + + mSatelliteSession2 = new SatelliteSession(); + mSatelliteSession2.satelliteServiceInitializationResult = + SatelliteProtoEnums.SATELLITE_MODEM_ERROR; + mSatelliteSession2.satelliteTechnology = + SatelliteProtoEnums.NT_RADIO_TECHNOLOGY_NB_IOT_NTN; + mSatelliteSession2.count = 1; + + mSatelliteSessions = + new SatelliteSession[] { + mSatelliteSession1, mSatelliteSession2 + }; + + mSatelliteIncomingDatagram1 = new SatelliteIncomingDatagram(); + mSatelliteIncomingDatagram1.resultCode = SatelliteProtoEnums.SATELLITE_ERROR_NONE; + mSatelliteIncomingDatagram1.datagramSizeBytes = 1 * 1024; + mSatelliteIncomingDatagram1.datagramTransferTimeMillis = 3 * 1000; + + mSatelliteIncomingDatagram2 = new SatelliteIncomingDatagram(); + mSatelliteIncomingDatagram2.resultCode = SatelliteProtoEnums.SATELLITE_MODEM_ERROR; + mSatelliteIncomingDatagram2.datagramSizeBytes = 512; + mSatelliteIncomingDatagram2.datagramTransferTimeMillis = 1 * 1000; + + mSatelliteIncomingDatagrams = + new SatelliteIncomingDatagram[] { + mSatelliteIncomingDatagram1, mSatelliteIncomingDatagram2 + }; + + mSatelliteOutgoingDatagram1 = new SatelliteOutgoingDatagram(); + mSatelliteOutgoingDatagram1.datagramType = + SatelliteProtoEnums.DATAGRAM_TYPE_LOCATION_SHARING; + mSatelliteOutgoingDatagram1.resultCode = SatelliteProtoEnums.SATELLITE_ERROR_NONE; + mSatelliteOutgoingDatagram1.datagramSizeBytes = 1 * 1024; + mSatelliteOutgoingDatagram1.datagramTransferTimeMillis = 3 * 1000; + + mSatelliteOutgoingDatagram2 = new SatelliteOutgoingDatagram(); + mSatelliteOutgoingDatagram2.datagramType = + SatelliteProtoEnums.DATAGRAM_TYPE_SOS_MESSAGE; + mSatelliteOutgoingDatagram2.resultCode = SatelliteProtoEnums.SATELLITE_MODEM_ERROR; + mSatelliteOutgoingDatagram2.datagramSizeBytes = 512; + mSatelliteOutgoingDatagram2.datagramTransferTimeMillis = 1 * 1000; + + mSatelliteOutgoingDatagrams = + new SatelliteOutgoingDatagram[] { + mSatelliteOutgoingDatagram1, mSatelliteOutgoingDatagram2 + }; + + mSatelliteProvision1 = new SatelliteProvision(); + mSatelliteProvision1.resultCode = SatelliteProtoEnums.SATELLITE_ERROR_NONE; + mSatelliteProvision1.provisioningTimeSec = 3 * 60; + mSatelliteProvision1.isProvisionRequest = true; + mSatelliteProvision1.isCanceled = false; + + mSatelliteProvision2 = new SatelliteProvision(); + mSatelliteProvision2.resultCode = SatelliteProtoEnums.SATELLITE_SERVICE_NOT_PROVISIONED; + mSatelliteProvision2.provisioningTimeSec = 0; + mSatelliteProvision2.isProvisionRequest = false; + mSatelliteProvision2.isCanceled = true; + + mSatelliteProvisions = + new SatelliteProvision[] { + mSatelliteProvision1, mSatelliteProvision2 + }; + + mSatelliteSosMessageRecommender1 = new SatelliteSosMessageRecommender(); + mSatelliteSosMessageRecommender1.isDisplaySosMessageSent = true; + mSatelliteSosMessageRecommender1.countOfTimerStarted = 5; + mSatelliteSosMessageRecommender1.isImsRegistered = false; + mSatelliteSosMessageRecommender1.cellularServiceState = + TelephonyProtoEnums.SERVICE_STATE_OUT_OF_SERVICE; + mSatelliteSosMessageRecommender1.count = 1; + + mSatelliteSosMessageRecommender2 = new SatelliteSosMessageRecommender(); + mSatelliteSosMessageRecommender2.isDisplaySosMessageSent = false; + mSatelliteSosMessageRecommender2.countOfTimerStarted = 3; + mSatelliteSosMessageRecommender2.isImsRegistered = true; + mSatelliteSosMessageRecommender2.cellularServiceState = + TelephonyProtoEnums.SERVICE_STATE_POWER_OFF; + mSatelliteSosMessageRecommender2.count = 1; + + mSatelliteSosMessageRecommenders = + new SatelliteSosMessageRecommender[] { + mSatelliteSosMessageRecommender1, mSatelliteSosMessageRecommender2 + }; } private static class TestablePersistAtomsStorage extends PersistAtomsStorage { @@ -1019,6 +1188,24 @@ public class PersistAtomsStorageTest extends TelephonyTest { mOutgoingShortCodeSms1 = null; mOutgoingShortCodeSms2 = null; mOutgoingShortCodeSms = null; + mSatelliteController1 = null; + mSatelliteController2 = null; + mSatelliteControllers = null; + mSatelliteSession1 = null; + mSatelliteSession2 = null; + mSatelliteSessions = null; + mSatelliteIncomingDatagram1 = null; + mSatelliteIncomingDatagram2 = null; + mSatelliteIncomingDatagrams = null; + mSatelliteOutgoingDatagram1 = null; + mSatelliteOutgoingDatagram2 = null; + mSatelliteOutgoingDatagrams = null; + mSatelliteProvision1 = null; + mSatelliteProvision2 = null; + mSatelliteProvisions = null; + mSatelliteSosMessageRecommender1 = null; + mSatelliteSosMessageRecommender2 = null; + mSatelliteSosMessageRecommenders = null; super.tearDown(); } @@ -1248,7 +1435,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum VoiceCallRatUsage[] voiceCallRatUsage = mPersistAtomsStorage.getVoiceCallRatUsages(100L); - // should be denied + // Should be denied assertNull(voiceCallRatUsage); } @@ -1266,7 +1453,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.getAtomsProto().voiceCallSessionPullTimestampMillis; VoiceCallSession[] voiceCallSession = mPersistAtomsStorage.getVoiceCallSessions(50L); - // first set of results should equal to file contents, second should be empty, corresponding + // First set of results should equal to file contents, second should be empty, corresponding // pull timestamp should be updated and saved, other fields should be unaffected assertProtoArrayEquals(mVoiceCallRatUsages, voiceCallRatUsage1); assertProtoArrayIsEmpty(voiceCallRatUsage2); @@ -1297,7 +1484,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum VoiceCallSession[] voiceCallSession = mPersistAtomsStorage.getVoiceCallSessions(100L); - // should be denied + // Should be denied assertNull(voiceCallSession); } @@ -1315,7 +1502,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.getAtomsProto().voiceCallRatUsagePullTimestampMillis; VoiceCallRatUsage[] voiceCallRatUsage = mPersistAtomsStorage.getVoiceCallRatUsages(50L); - // first set of results should equal to file contents, second should be empty, corresponding + // First set of results should equal to file contents, second should be empty, corresponding // pull timestamp should be updated and saved, other fields should be unaffected assertProtoArrayEquals(mVoiceCallSessions, voiceCallSession1); assertProtoArrayIsEmpty(voiceCallSession2); @@ -1347,7 +1534,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mServiceState1Proto, mServiceSwitch1Proto); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); CellularServiceState[] serviceStates = mPersistAtomsStorage.getCellularServiceStates(0L); CellularDataServiceSwitch[] serviceSwitches = @@ -1370,7 +1557,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mServiceState2Proto, mServiceSwitch2Proto); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); CellularServiceState[] serviceStates = mPersistAtomsStorage.getCellularServiceStates(0L); CellularDataServiceSwitch[] serviceSwitches = @@ -1464,7 +1651,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { CellularDataServiceSwitch[] serviceSwitches = mPersistAtomsStorage.getCellularDataServiceSwitches(100L); - // should be denied + // Should be denied assertNull(serviceSwitches); } @@ -1481,7 +1668,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { CellularDataServiceSwitch[] serviceSwitches2 = mPersistAtomsStorage.getCellularDataServiceSwitches(50L); - // first set of results should equal to file contents, second should be empty, corresponding + // First set of results should equal to file contents, second should be empty, corresponding // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder( new CellularDataServiceSwitch[] {mServiceSwitch1Proto, mServiceSwitch2Proto}, @@ -1509,7 +1696,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum CellularServiceState[] serviceStates = mPersistAtomsStorage.getCellularServiceStates(100L); - // should be denied + // Should be denied assertNull(serviceStates); } @@ -1524,7 +1711,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.incTimeMillis(100L); CellularServiceState[] serviceStates2 = mPersistAtomsStorage.getCellularServiceStates(50L); - // first set of results should equal to file contents, second should be empty, corresponding + // First set of results should equal to file contents, second should be empty, corresponding // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder( new CellularServiceState[] { @@ -1558,7 +1745,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addImsRegistrationStats(copyOf(mImsRegistrationStatsLte0)); mPersistAtomsStorage.incTimeMillis(DAY_IN_MILLIS); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); ImsRegistrationStats[] regStats = mPersistAtomsStorage.getImsRegistrationStats(0L); assertProtoArrayEquals(new ImsRegistrationStats[] {mImsRegistrationStatsLte0}, regStats); @@ -1574,7 +1761,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addImsRegistrationStats(copyOf(mImsRegistrationStatsWifi0)); mPersistAtomsStorage.incTimeMillis(DAY_IN_MILLIS); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); ImsRegistrationStats[] regStats = mPersistAtomsStorage.getImsRegistrationStats(0L); assertProtoArrayEqualsIgnoringOrder( @@ -1646,7 +1833,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addImsRegistrationTermination(mImsRegistrationTerminationLte); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); ImsRegistrationTermination[] terminations = mPersistAtomsStorage.getImsRegistrationTerminations(0L); @@ -1664,7 +1851,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addImsRegistrationTermination(mImsRegistrationTerminationWifi); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); ImsRegistrationTermination[] terminations = mPersistAtomsStorage.getImsRegistrationTerminations(0L); @@ -1729,7 +1916,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum ImsRegistrationStats[] stats = mPersistAtomsStorage.getImsRegistrationStats(100L); - // should be denied + // Should be denied assertNull(stats); } @@ -1744,7 +1931,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.incTimeMillis(100L); ImsRegistrationStats[] stats2 = mPersistAtomsStorage.getImsRegistrationStats(50L); - // first set of results should equal to file contents, second should be empty, corresponding + // First set of results should equal to file contents, second should be empty, corresponding // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder( new ImsRegistrationStats[] { @@ -1775,7 +1962,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { ImsRegistrationTermination[] terminations = mPersistAtomsStorage.getImsRegistrationTerminations(100L); - // should be denied + // Should be denied assertNull(terminations); } @@ -1792,7 +1979,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { ImsRegistrationTermination[] terminations2 = mPersistAtomsStorage.getImsRegistrationTerminations(50L); - // first set of results should equal to file contents, second should be empty, corresponding + // First set of results should equal to file contents, second should be empty, corresponding // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder( new ImsRegistrationTermination[] { @@ -1957,7 +2144,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { ImsRegistrationFeatureTagStats[] result = mPersistAtomsStorage.getImsRegistrationFeatureTagStats(100L); - // should be denied + // Should be denied assertNull(result); } @@ -1974,7 +2161,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { ImsRegistrationFeatureTagStats[] statses2 = mPersistAtomsStorage.getImsRegistrationFeatureTagStats(50L); - // first results of get should have two atoms, second should be empty + // First results of get should have two atoms, second should be empty // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder(mImsRegistrationFeatureTagStatses, statses1); assertProtoArrayEquals(new ImsRegistrationFeatureTagStats[0], statses2); @@ -2024,13 +2211,13 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); - // store 11 same atoms, but only 1 atoms stored with count 11 + // Store 11 same atoms, but only 1 atoms stored with count 11 for (int i = 0; i < 11; i++) { mPersistAtomsStorage .addRcsClientProvisioningStats(mRcsClientProvisioningStats1Proto); mPersistAtomsStorage.incTimeMillis(100L); } - // store 1 different atom and count 1 + // Store 1 different atom and count 1 mPersistAtomsStorage .addRcsClientProvisioningStats(mRcsClientProvisioningStats2Proto); @@ -2039,7 +2226,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { RcsClientProvisioningStats[] result = mPersistAtomsStorage.getRcsClientProvisioningStats(0L); - // first atom has count 11, the other has 1 + // First atom has count 11, the other has 1 assertHasStatsAndCount(result, mRcsClientProvisioningStats1Proto, 11); assertHasStatsAndCount(result, mRcsClientProvisioningStats2Proto, 1); } @@ -2054,7 +2241,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { RcsClientProvisioningStats[] result = mPersistAtomsStorage.getRcsClientProvisioningStats(100L); - // should be denied + // Should be denied assertNull(result); } @@ -2071,7 +2258,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { RcsClientProvisioningStats[] statses2 = mPersistAtomsStorage.getRcsClientProvisioningStats(50L); - // first results of get should have two atoms, second should be empty + // First results of get should have two atoms, second should be empty // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder(mRcsClientProvisioningStatses, statses1); assertProtoArrayEquals(new RcsClientProvisioningStats[0], statses2); @@ -2123,8 +2310,8 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); - // store 5 same atoms (1Proto), but only 1 atoms stored with count 5, total time 2000L * 5 - // store 5 same atoms (2Proto), but only 1 atoms stored with count 5, total time 2000L * 5 + // Store 5 same atoms (1Proto), but only 1 atoms stored with count 5, total time 2000L * 5 + // Store 5 same atoms (2Proto), but only 1 atoms stored with count 5, total time 2000L * 5 for (int i = 0; i < maxCount; i++) { mPersistAtomsStorage @@ -2162,7 +2349,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { RcsAcsProvisioningStats[] result = mPersistAtomsStorage.getRcsAcsProvisioningStats(100L); - // should be denied + // Should be denied assertNull(result); } @@ -2179,7 +2366,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { RcsAcsProvisioningStats[] statses2 = mPersistAtomsStorage.getRcsAcsProvisioningStats(DAY_IN_MILLIS - HOUR_IN_MILLIS); - // first results of get should have two atoms, second should be empty + // First results of get should have two atoms, second should be empty // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder(mRcsAcsProvisioningStatses, statses1); assertProtoArrayEquals(new RcsAcsProvisioningStats[0], statses2); @@ -2205,7 +2392,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addImsRegistrationServiceDescStats(mImsRegistrationServiceIm); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); ImsRegistrationServiceDescStats[] outputs = mPersistAtomsStorage.getImsRegistrationServiceDescStats(0L); @@ -2223,7 +2410,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addImsRegistrationServiceDescStats(mImsRegistrationServiceFt); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); ImsRegistrationServiceDescStats[] output = mPersistAtomsStorage.getImsRegistrationServiceDescStats(0L); @@ -2270,7 +2457,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { ImsRegistrationServiceDescStats[] output = mPersistAtomsStorage.getImsRegistrationServiceDescStats(100L); - // should be denied + // Should be denied assertNull(output); } @@ -2287,7 +2474,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { ImsRegistrationServiceDescStats[] output2 = mPersistAtomsStorage.getImsRegistrationServiceDescStats(50L); - // first set of results should equal to file contents, second should be empty, corresponding + // First set of results should equal to file contents, second should be empty, corresponding // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder( new ImsRegistrationServiceDescStats[] { @@ -2458,7 +2645,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addImsDedicatedBearerListenerEvent(mImsDedicatedBearerListenerEvent1); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); ImsDedicatedBearerListenerEvent[] outputs = mPersistAtomsStorage.getImsDedicatedBearerListenerEvent(0L); @@ -2476,7 +2663,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addImsDedicatedBearerListenerEvent(mImsDedicatedBearerListenerEvent2); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); ImsDedicatedBearerListenerEvent[] output = mPersistAtomsStorage.getImsDedicatedBearerListenerEvent(0L); @@ -2517,7 +2704,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addImsDedicatedBearerEvent(mImsDedicatedBearerEvent1); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); ImsDedicatedBearerEvent[] outputs = mPersistAtomsStorage.getImsDedicatedBearerEvent(0L); @@ -2535,7 +2722,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addImsDedicatedBearerEvent(mImsDedicatedBearerEvent2); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); ImsDedicatedBearerEvent[] output = mPersistAtomsStorage.getImsDedicatedBearerEvent(0L); @@ -2610,7 +2797,6 @@ public class PersistAtomsStorageTest extends TelephonyTest { mImsDedicatedBearerEvent2, newStats}, stats); } - @Test @SmallTest public void addUceEventStats_emptyProto() throws Exception { @@ -2619,7 +2805,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addUceEventStats(mUceEventStats1); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); UceEventStats[] outputs = mPersistAtomsStorage.getUceEventStats(0L); assertProtoArrayEquals( @@ -2636,7 +2822,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addUceEventStats(mUceEventStats2); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); UceEventStats[] output = mPersistAtomsStorage.getUceEventStats(0L); assertProtoArrayEqualsIgnoringOrder( @@ -2710,7 +2896,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.addPresenceNotifyEvent(mPresenceNotifyEvent2); mPersistAtomsStorage.incTimeMillis(100L); - // service state and service switch should be added successfully + // Service state and service switch should be added successfully verifyCurrentStateSavedToFileOnce(); PresenceNotifyEvent[] output = mPersistAtomsStorage.getPresenceNotifyEvent(0L); assertProtoArrayEqualsIgnoringOrder( @@ -2726,7 +2912,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum PresenceNotifyEvent[] output = mPersistAtomsStorage.getPresenceNotifyEvent(100L); - // should be denied + // Should be denied assertNull(output); } @@ -2741,7 +2927,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.incTimeMillis(100L); PresenceNotifyEvent[] output2 = mPersistAtomsStorage.getPresenceNotifyEvent(50L); - // first set of results should equal to file contents, second should be empty, corresponding + // First set of results should equal to file contents, second should be empty, corresponding // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder( new PresenceNotifyEvent[] {mPresenceNotifyEvent1, mPresenceNotifyEvent2}, output1); @@ -2868,7 +3054,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { SipTransportFeatureTagStats[] outputs = mPersistAtomsStorage.getSipTransportFeatureTagStats(100L); - // should be denied + // Should be denied assertNull(outputs); } @@ -2887,7 +3073,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { SipTransportFeatureTagStats[] output2 = mPersistAtomsStorage.getSipTransportFeatureTagStats(50L); - // first set of results should equal to file contents, second should be empty, corresponding + // First set of results should equal to file contents, second should be empty, corresponding // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder( new SipTransportFeatureTagStats[] { @@ -3010,7 +3196,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum SipDelegateStats[] outputs = mPersistAtomsStorage.getSipDelegateStats(100L); - // should be denied + // Should be denied assertNull(outputs); } @@ -3027,7 +3213,7 @@ public class PersistAtomsStorageTest extends TelephonyTest { mPersistAtomsStorage.incTimeMillis(100L); SipDelegateStats[] output2 = mPersistAtomsStorage.getSipDelegateStats(50L); - // first set of results should equal to file contents, second should be empty, corresponding + // First set of results should equal to file contents, second should be empty, corresponding // pull timestamp should be updated and saved assertProtoArrayEqualsIgnoringOrder( new SipDelegateStats[] { @@ -3153,18 +3339,18 @@ public class PersistAtomsStorageTest extends TelephonyTest { createEmptyTestFile(); mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); - // store 11 same atoms, but only 1 atoms stored with count 11 + // Store 11 same atoms, but only 1 atoms stored with count 11 for (int i = 0; i < 11; i++) { mPersistAtomsStorage.addSipMessageResponse(mSipMessageResponse1); mPersistAtomsStorage.incTimeMillis(100L); } - // store 1 different atom and count 1 + // Store 1 different atom and count 1 mPersistAtomsStorage.addSipMessageResponse(mSipMessageResponse2); verifyCurrentStateSavedToFileOnce(); SipMessageResponse[] result = mPersistAtomsStorage.getSipMessageResponse(0L); - // first atom has count 11, the other has 1 + // First atom has count 11, the other has 1 assertHasStats(result, mSipMessageResponse1, 11); assertHasStats(result, mSipMessageResponse2, 1); } @@ -3222,18 +3408,18 @@ public class PersistAtomsStorageTest extends TelephonyTest { createEmptyTestFile(); mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); - // store 11 same atoms, but only 1 atoms stored with count 11 + // Store 11 same atoms, but only 1 atoms stored with count 11 for (int i = 0; i < 11; i++) { mPersistAtomsStorage.addCompleteSipTransportSession(mSipTransportSession1); mPersistAtomsStorage.incTimeMillis(100L); } - // store 1 different atom and count 1 + // Store 1 different atom and count 1 mPersistAtomsStorage.addCompleteSipTransportSession(mSipTransportSession2); verifyCurrentStateSavedToFileOnce(); SipTransportSession[] result = mPersistAtomsStorage.getSipTransportSession(0L); - // first atom has count 11, the other has 1 + // First atom has count 11, the other has 1 assertHasStats(result, mSipTransportSession1, 11); assertHasStats(result, mSipTransportSession2, 1); } @@ -3535,6 +3721,484 @@ public class PersistAtomsStorageTest extends TelephonyTest { inOrder.verifyNoMoreInteractions(); } + @Test + public void addSatelliteControllerStats_emptyProto() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteControllerStats(mSatelliteController1); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteController[] output = + mPersistAtomsStorage.getSatelliteControllerStats(0L); + assertProtoArrayEquals( + new SatelliteController[] {mSatelliteController1}, output); + } + + @Test + public void addSatelliteControllerStats_withExistingEntries() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteControllerStats(mSatelliteController1); + mPersistAtomsStorage.addSatelliteControllerStats(mSatelliteController2); + mPersistAtomsStorage.incTimeMillis(100L); + + SatelliteController expected = new SatelliteController(); + expected.countOfSatelliteServiceEnablementsSuccess = + mSatelliteController1.countOfSatelliteServiceEnablementsSuccess + + mSatelliteController2.countOfSatelliteServiceEnablementsSuccess; + expected.countOfSatelliteServiceEnablementsFail = + mSatelliteController1.countOfSatelliteServiceEnablementsFail + + mSatelliteController2.countOfSatelliteServiceEnablementsFail; + expected.countOfOutgoingDatagramSuccess = + mSatelliteController1.countOfOutgoingDatagramSuccess + + mSatelliteController2.countOfOutgoingDatagramSuccess; + expected.countOfOutgoingDatagramFail = + mSatelliteController1.countOfOutgoingDatagramFail + + mSatelliteController2.countOfOutgoingDatagramFail; + expected.countOfIncomingDatagramSuccess = + mSatelliteController1.countOfIncomingDatagramSuccess + + mSatelliteController2.countOfIncomingDatagramSuccess; + expected.countOfIncomingDatagramFail = + mSatelliteController1.countOfIncomingDatagramFail + + mSatelliteController2.countOfIncomingDatagramFail; + expected.countOfDatagramTypeSosSmsSuccess = + mSatelliteController1.countOfDatagramTypeSosSmsSuccess + + mSatelliteController2.countOfDatagramTypeSosSmsSuccess; + expected.countOfDatagramTypeSosSmsFail = + mSatelliteController1.countOfDatagramTypeSosSmsFail + + mSatelliteController2.countOfDatagramTypeSosSmsFail; + expected.countOfDatagramTypeLocationSharingSuccess = + mSatelliteController1.countOfDatagramTypeLocationSharingSuccess + + mSatelliteController2.countOfDatagramTypeLocationSharingSuccess; + expected.countOfDatagramTypeLocationSharingFail = + mSatelliteController1.countOfDatagramTypeLocationSharingFail + + mSatelliteController2.countOfDatagramTypeLocationSharingFail; + expected.countOfProvisionSuccess = + mSatelliteController1.countOfProvisionSuccess + + mSatelliteController2.countOfProvisionSuccess; + expected.countOfProvisionFail = + mSatelliteController1.countOfProvisionFail + + mSatelliteController2.countOfProvisionFail; + expected.countOfDeprovisionSuccess = + mSatelliteController1.countOfDeprovisionSuccess + + mSatelliteController2.countOfDeprovisionSuccess; + expected.countOfDeprovisionFail = + mSatelliteController1.countOfDeprovisionFail + + mSatelliteController2.countOfDeprovisionFail; + expected.totalServiceUptimeSec = + mSatelliteController1.totalServiceUptimeSec + + mSatelliteController2.totalServiceUptimeSec; + expected.totalBatteryConsumptionPercent = + mSatelliteController1.totalBatteryConsumptionPercent + + mSatelliteController2.totalBatteryConsumptionPercent; + expected.totalBatteryChargedTimeSec = + mSatelliteController1.totalBatteryChargedTimeSec + + mSatelliteController2.totalBatteryChargedTimeSec; + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteController[] output = + mPersistAtomsStorage.getSatelliteControllerStats(0L); + assertHasStats(output, expected); + } + + @Test + public void getSatelliteControllerStats_tooFrequent() throws Exception { + createTestFile(START_TIME_MILLIS); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum + SatelliteController[] output = + mPersistAtomsStorage.getSatelliteControllerStats(100L); + + // Should be denied + assertNull(output); + } + + @Test + public void addSatelliteSessionStats_emptyProto() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteSessionStats( + mSatelliteSession1); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteSession[] output = + mPersistAtomsStorage.getSatelliteSessionStats(0L); + assertProtoArrayEquals( + new SatelliteSession[] {mSatelliteSession1}, output); + } + + @Test + public void addSatelliteSessionStats_withExistingEntries() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteSessionStats( + mSatelliteSession1); + mPersistAtomsStorage.addSatelliteSessionStats( + mSatelliteSession2); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteSession[] output = + mPersistAtomsStorage.getSatelliteSessionStats(0L); + assertProtoArrayEqualsIgnoringOrder( + new SatelliteSession[] { + mSatelliteSession1, mSatelliteSession2}, + output); + } + + @Test + public void addSatelliteSessionStats_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 + .addSatelliteSessionStats( + copyOf(mSatelliteSession1)); + mPersistAtomsStorage.incTimeMillis(100L); + } + + // Store 1 different atom + mPersistAtomsStorage + .addSatelliteSessionStats(mSatelliteSession2); + + verifyCurrentStateSavedToFileOnce(); + + SatelliteSession[] result = + mPersistAtomsStorage.getSatelliteSessionStats(0L); + + // First atom has count 16, the other has 1 + assertHasStatsAndCount(result, mSatelliteSession1, 16); + assertHasStatsAndCount(result, mSatelliteSession2, 1); + + } + + @Test + public void getSatelliteSessionStats_tooFrequent() throws Exception { + createTestFile(START_TIME_MILLIS); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum + SatelliteSession[] output = + mPersistAtomsStorage.getSatelliteSessionStats(100L); + + // Should be denied + assertNull(output); + } + + + + @Test + public void addSatelliteIncomingDatagramStats_emptyProto() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteIncomingDatagramStats(mSatelliteIncomingDatagram1); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteIncomingDatagram[] output = + mPersistAtomsStorage.getSatelliteIncomingDatagramStats(0L); + assertProtoArrayEquals( + new SatelliteIncomingDatagram[] {mSatelliteIncomingDatagram1}, output); + } + + @Test + public void addSatelliteIncomingDatagramStats_withExistingEntries() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteIncomingDatagramStats(mSatelliteIncomingDatagram1); + mPersistAtomsStorage.addSatelliteIncomingDatagramStats(mSatelliteIncomingDatagram2); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteIncomingDatagram[] output = + mPersistAtomsStorage.getSatelliteIncomingDatagramStats(0L); + assertProtoArrayEqualsIgnoringOrder( + new SatelliteIncomingDatagram[] { + mSatelliteIncomingDatagram1, mSatelliteIncomingDatagram2}, output); + } + + @Test + public void addSatelliteIncomingDatagramStats_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 + .addSatelliteIncomingDatagramStats(copyOf(mSatelliteIncomingDatagram1)); + mPersistAtomsStorage.incTimeMillis(100L); + } + + // Store 1 different atom + mPersistAtomsStorage + .addSatelliteIncomingDatagramStats(mSatelliteIncomingDatagram2); + + verifyCurrentStateSavedToFileOnce(); + + SatelliteIncomingDatagram[] result = + mPersistAtomsStorage.getSatelliteIncomingDatagramStats(0L); + + // First atom has count 14, the other has 1 + assertHasStatsAndCount(result, mSatelliteIncomingDatagram1, 14); + assertHasStatsAndCount(result, mSatelliteIncomingDatagram2, 1); + + } + + @Test + public void getSatelliteIncomingDatagramStats_tooFrequent() throws Exception { + createTestFile(START_TIME_MILLIS); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum + SatelliteIncomingDatagram[] output = + mPersistAtomsStorage.getSatelliteIncomingDatagramStats(100L); + + // Should be denied + assertNull(output); + } + + @Test + public void addSatelliteOutgoingDatagramStats_emptyProto() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteOutgoingDatagramStats(mSatelliteOutgoingDatagram1); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteOutgoingDatagram[] output = + mPersistAtomsStorage.getSatelliteOutgoingDatagramStats(0L); + assertProtoArrayEquals( + new SatelliteOutgoingDatagram[] {mSatelliteOutgoingDatagram1}, output); + } + + @Test + public void addSatelliteOutgoingDatagramStats_withExistingEntries() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteOutgoingDatagramStats(mSatelliteOutgoingDatagram1); + mPersistAtomsStorage.addSatelliteOutgoingDatagramStats(mSatelliteOutgoingDatagram2); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteOutgoingDatagram[] output = + mPersistAtomsStorage.getSatelliteOutgoingDatagramStats(0L); + assertProtoArrayEqualsIgnoringOrder( + new SatelliteOutgoingDatagram[] { + mSatelliteOutgoingDatagram1, mSatelliteOutgoingDatagram2}, output); + } + + @Test + public void addSatelliteOutgoingDatagramStats_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 + .addSatelliteOutgoingDatagramStats(copyOf(mSatelliteOutgoingDatagram1)); + mPersistAtomsStorage.incTimeMillis(100L); + } + + // Store 1 different atom + mPersistAtomsStorage + .addSatelliteOutgoingDatagramStats(mSatelliteOutgoingDatagram2); + + verifyCurrentStateSavedToFileOnce(); + + SatelliteOutgoingDatagram[] result = + mPersistAtomsStorage.getSatelliteOutgoingDatagramStats(0L); + + // First atom has count 14, the other has 1 + assertHasStatsAndCount(result, mSatelliteOutgoingDatagram1, 14); + assertHasStatsAndCount(result, mSatelliteOutgoingDatagram2, 1); + + } + + @Test + public void getSatelliteOutgoingDatagramStats_tooFrequent() throws Exception { + createTestFile(START_TIME_MILLIS); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum + SatelliteOutgoingDatagram[] output = + mPersistAtomsStorage.getSatelliteOutgoingDatagramStats(100L); + + // Should be denied + assertNull(output); + } + + @Test + public void addSatelliteProvisionStats_emptyProto() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteProvisionStats(mSatelliteProvision1); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteProvision[] output = + mPersistAtomsStorage.getSatelliteProvisionStats(0L); + assertProtoArrayEquals( + new SatelliteProvision[] {mSatelliteProvision1}, output); + } + + @Test + public void addSatelliteProvisionStats_withExistingEntries() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteProvisionStats(mSatelliteProvision1); + mPersistAtomsStorage.addSatelliteProvisionStats(mSatelliteProvision2); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteProvision[] output = + mPersistAtomsStorage.getSatelliteProvisionStats(0L); + assertProtoArrayEqualsIgnoringOrder( + new SatelliteProvision[] { + mSatelliteProvision1, mSatelliteProvision2}, output); + } + + @Test + public void addSatelliteProvisionStats_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 + .addSatelliteProvisionStats(copyOf(mSatelliteProvision1)); + mPersistAtomsStorage.incTimeMillis(100L); + } + + // Store 1 different atom + mPersistAtomsStorage + .addSatelliteProvisionStats(mSatelliteProvision2); + + verifyCurrentStateSavedToFileOnce(); + + SatelliteProvision[] result = + mPersistAtomsStorage.getSatelliteProvisionStats(0L); + + // First atom has count 14, the other has 1 + assertHasStatsAndCount(result, mSatelliteProvision1, 14); + assertHasStatsAndCount(result, mSatelliteProvision2, 1); + + } + + @Test + public void getSatelliteProvisionStats_tooFrequent() throws Exception { + createTestFile(START_TIME_MILLIS); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum + SatelliteProvision[] output = + mPersistAtomsStorage.getSatelliteProvisionStats(100L); + + // Should be denied + assertNull(output); + } + + @Test + public void addSatelliteSosMessageRecommenderStats_emptyProto() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteSosMessageRecommenderStats( + mSatelliteSosMessageRecommender1); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteSosMessageRecommender[] output = + mPersistAtomsStorage.getSatelliteSosMessageRecommenderStats(0L); + assertProtoArrayEquals( + new SatelliteSosMessageRecommender[] {mSatelliteSosMessageRecommender1}, output); + } + + @Test + public void addSatelliteSosMessageRecommenderStats_withExistingEntries() throws Exception { + createEmptyTestFile(); + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.addSatelliteSosMessageRecommenderStats( + mSatelliteSosMessageRecommender1); + mPersistAtomsStorage.addSatelliteSosMessageRecommenderStats( + mSatelliteSosMessageRecommender2); + mPersistAtomsStorage.incTimeMillis(100L); + + // Service state and service switch should be added successfully + verifyCurrentStateSavedToFileOnce(); + SatelliteSosMessageRecommender[] output = + mPersistAtomsStorage.getSatelliteSosMessageRecommenderStats(0L); + assertProtoArrayEqualsIgnoringOrder( + new SatelliteSosMessageRecommender[] { + mSatelliteSosMessageRecommender1, mSatelliteSosMessageRecommender2}, + output); + } + + @Test + public void addSatelliteSosMessageRecommenderStats_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 + .addSatelliteSosMessageRecommenderStats( + copyOf(mSatelliteSosMessageRecommender1)); + mPersistAtomsStorage.incTimeMillis(100L); + } + + // Store 1 different atom + mPersistAtomsStorage + .addSatelliteSosMessageRecommenderStats(mSatelliteSosMessageRecommender2); + + verifyCurrentStateSavedToFileOnce(); + + SatelliteSosMessageRecommender[] result = + mPersistAtomsStorage.getSatelliteSosMessageRecommenderStats(0L); + + // First atom has count 16, the other has 1 + assertHasStatsAndCount(result, mSatelliteSosMessageRecommender1, 16); + assertHasStatsAndCount(result, mSatelliteSosMessageRecommender2, 1); + + } + + @Test + public void getSatelliteSosMessageRecommenderStats_tooFrequent() throws Exception { + createTestFile(START_TIME_MILLIS); + + mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext); + mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum + SatelliteSosMessageRecommender[] output = + mPersistAtomsStorage.getSatelliteSosMessageRecommenderStats(100L); + + // Should be denied + assertNull(output); + } + @Test @SmallTest public void clearAtoms() throws Exception { @@ -3608,6 +4272,18 @@ public class PersistAtomsStorageTest extends TelephonyTest { atoms.sipTransportSession = mSipTransportSession; atoms.outgoingShortCodeSms = mOutgoingShortCodeSms; atoms.outgoingShortCodeSmsPullTimestampMillis = lastPullTimeMillis; + atoms.satelliteController = mSatelliteControllers; + atoms.satelliteControllerPullTimestampMillis = lastPullTimeMillis; + atoms.satelliteSession = mSatelliteSessions; + atoms.satelliteSessionPullTimestampMillis = lastPullTimeMillis; + atoms.satelliteIncomingDatagram = mSatelliteIncomingDatagrams; + atoms.satelliteIncomingDatagramPullTimestampMillis = lastPullTimeMillis; + atoms.satelliteOutgoingDatagram = mSatelliteOutgoingDatagrams; + atoms.satelliteOutgoingDatagramPullTimestampMillis = lastPullTimeMillis; + atoms.satelliteProvision = mSatelliteProvisions; + atoms.satelliteProvisionPullTimestampMillis = lastPullTimeMillis; + atoms.satelliteSosMessageRecommender = mSatelliteSosMessageRecommenders; + atoms.satelliteSosMessageRecommenderPullTimestampMillis = lastPullTimeMillis; FileOutputStream stream = new FileOutputStream(mTestFile); stream.write(PersistAtoms.toByteArray(atoms)); stream.close(); @@ -3731,6 +4407,36 @@ public class PersistAtomsStorageTest extends TelephonyTest { return OutgoingShortCodeSms.parseFrom(MessageNano.toByteArray(source)); } + private static SatelliteController copyOf(SatelliteController source) + throws Exception { + return SatelliteController.parseFrom(MessageNano.toByteArray(source)); + } + + private static SatelliteSession copyOf(SatelliteSession source) + throws Exception { + return SatelliteSession.parseFrom(MessageNano.toByteArray(source)); + } + + private static SatelliteIncomingDatagram copyOf(SatelliteIncomingDatagram source) + throws Exception { + return SatelliteIncomingDatagram.parseFrom(MessageNano.toByteArray(source)); + } + + private static SatelliteOutgoingDatagram copyOf(SatelliteOutgoingDatagram source) + throws Exception { + return SatelliteOutgoingDatagram.parseFrom(MessageNano.toByteArray(source)); + } + + private static SatelliteProvision copyOf(SatelliteProvision source) + throws Exception { + return SatelliteProvision.parseFrom(MessageNano.toByteArray(source)); + } + + private static SatelliteSosMessageRecommender copyOf(SatelliteSosMessageRecommender source) + throws Exception { + return SatelliteSosMessageRecommender.parseFrom(MessageNano.toByteArray(source)); + } + private void assertAllPullTimestampEquals(long timestamp) { assertEquals( timestamp, @@ -3876,6 +4582,119 @@ public class PersistAtomsStorageTest extends TelephonyTest { assertEquals(expectedCount, actualCount); } + private static void assertHasStats( + SatelliteController[] tested, + @Nullable SatelliteController expectedStats) { + assertNotNull(tested); + assertEquals(tested[0].countOfSatelliteServiceEnablementsSuccess, + expectedStats.countOfSatelliteServiceEnablementsSuccess); + assertEquals(tested[0].countOfSatelliteServiceEnablementsFail, + expectedStats.countOfSatelliteServiceEnablementsFail); + assertEquals(tested[0].countOfOutgoingDatagramSuccess, + expectedStats.countOfOutgoingDatagramSuccess); + assertEquals(tested[0].countOfOutgoingDatagramFail, + expectedStats.countOfOutgoingDatagramFail); + assertEquals(tested[0].countOfIncomingDatagramSuccess, + expectedStats.countOfIncomingDatagramSuccess); + assertEquals(tested[0].countOfIncomingDatagramFail, + expectedStats.countOfIncomingDatagramFail); + assertEquals(tested[0].countOfDatagramTypeSosSmsSuccess, + expectedStats.countOfDatagramTypeSosSmsSuccess); + assertEquals(tested[0].countOfDatagramTypeSosSmsFail, + expectedStats.countOfDatagramTypeSosSmsFail); + assertEquals(tested[0].countOfDatagramTypeLocationSharingSuccess, + expectedStats.countOfDatagramTypeLocationSharingSuccess); + assertEquals(tested[0].countOfDatagramTypeLocationSharingFail, + expectedStats.countOfDatagramTypeLocationSharingFail); + assertEquals(tested[0].totalServiceUptimeSec, + expectedStats.totalServiceUptimeSec); + assertEquals(tested[0].totalBatteryConsumptionPercent, + expectedStats.totalBatteryConsumptionPercent); + assertEquals(tested[0].totalBatteryChargedTimeSec, + expectedStats.totalBatteryChargedTimeSec); + } + + private static void assertHasStatsAndCount( + SatelliteSession[] tested, + @Nullable SatelliteSession expectedStats, int expectedCount) { + assertNotNull(tested); + int actualCount = 0; + for (SatelliteSession stats : tested) { + if (stats.satelliteServiceInitializationResult + == expectedStats.satelliteServiceInitializationResult + && stats.satelliteTechnology == expectedStats.satelliteTechnology) { + actualCount = stats.count; + } + } + assertEquals(expectedCount, actualCount); + } + + private static void assertHasStatsAndCount( + SatelliteIncomingDatagram[] tested, + @Nullable SatelliteIncomingDatagram expectedStats, int expectedCount) { + assertNotNull(tested); + int actualCount = 0; + for (SatelliteIncomingDatagram stats : tested) { + if (stats.resultCode == expectedStats.resultCode + && stats.datagramSizeBytes == expectedStats.datagramSizeBytes + && stats.datagramTransferTimeMillis + == expectedStats.datagramTransferTimeMillis) { + actualCount++; + } + } + assertEquals(expectedCount, actualCount); + } + + private static void assertHasStatsAndCount( + SatelliteOutgoingDatagram[] tested, + @Nullable SatelliteOutgoingDatagram expectedStats, int expectedCount) { + assertNotNull(tested); + int actualCount = 0; + for (SatelliteOutgoingDatagram stats : tested) { + if (stats.datagramType == expectedStats.datagramType + && stats.resultCode == expectedStats.resultCode + && stats.datagramSizeBytes == expectedStats.datagramSizeBytes + && stats.datagramTransferTimeMillis + == expectedStats.datagramTransferTimeMillis) { + actualCount++; + } + } + assertEquals(expectedCount, actualCount); + } + + private static void assertHasStatsAndCount( + SatelliteProvision[] tested, + @Nullable SatelliteProvision expectedStats, int expectedCount) { + assertNotNull(tested); + int actualCount = 0; + for (SatelliteProvision stats : tested) { + if (stats.resultCode == expectedStats.resultCode + && stats.provisioningTimeSec == expectedStats.provisioningTimeSec + && stats.isProvisionRequest == expectedStats.isProvisionRequest + && stats.isCanceled == expectedStats.isCanceled) { + actualCount++; + } + } + assertEquals(expectedCount, actualCount); + } + + private static void assertHasStatsAndCount( + SatelliteSosMessageRecommender[] tested, + @Nullable SatelliteSosMessageRecommender expectedStats, int expectedCount) { + assertNotNull(tested); + int actualCount = 0; + for (SatelliteSosMessageRecommender stats : tested) { + if (stats.isDisplaySosMessageSent + == expectedStats.isDisplaySosMessageSent + && stats.countOfTimerStarted == expectedStats.countOfTimerStarted + && stats.isImsRegistered == expectedStats.isImsRegistered + && stats.cellularServiceState == expectedStats.cellularServiceState) { + actualCount = stats.count; + } + } + assertEquals(expectedCount, actualCount); + } + private static void assertHasStatsAndCountDuration( RcsAcsProvisioningStats[] statses, @Nullable RcsAcsProvisioningStats expectedStats, int count, long duration) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java new file mode 100644 index 0000000000..22032ae88a --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2023 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.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import android.telephony.SatelliteProtoEnums; +import android.telephony.TelephonyProtoEnums; + +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.nano.PersistAtomsProto.SatelliteController; +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 org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +public class SatelliteStatsTest extends TelephonyTest { + private static final String TAG = SatelliteStatsTest.class.getSimpleName(); + + private TestableSatelliteStats mSatelliteStats; + + private class TestableSatelliteStats extends SatelliteStats { + TestableSatelliteStats() { + super(); + } + } + + @Before + public void setup() throws Exception { + super.setUp(getClass().getSimpleName()); + + mSatelliteStats = new TestableSatelliteStats(); + } + + @After + public void tearDown() throws Exception { + mSatelliteStats = null; + super.tearDown(); + } + + @Test + public void onSatelliteControllerMetrics_withAtoms() throws Exception { + SatelliteStats.SatelliteControllerParams param = + new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfSatelliteServiceEnablementsSuccess(2) + .setCountOfSatelliteServiceEnablementsFail(2) + .setCountOfOutgoingDatagramSuccess(8) + .setCountOfOutgoingDatagramFail(9) + .setCountOfIncomingDatagramSuccess(10) + .setCountOfIncomingDatagramFail(11) + .setCountOfDatagramTypeSosSmsSuccess(5) + .setCountOfDatagramTypeSosSmsFail(5) + .setCountOfDatagramTypeLocationSharingSuccess(6) + .setCountOfDatagramTypeLocationSharingFail(6) + .setCountOfProvisionSuccess(3) + .setCountOfProvisionFail(4) + .setCountOfDeprovisionSuccess(5) + .setCountOfDeprovisionFail(6) + .setTotalServiceUptimeSec(60 * 60 * 24 * 7) + .setTotalBatteryConsumptionPercent(7) + .setTotalBatteryChargedTimeSec(60 * 60 * 3) + .build(); + + mSatelliteStats.onSatelliteControllerMetrics(param); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(SatelliteController.class); + verify(mPersistAtomsStorage).addSatelliteControllerStats(captor.capture()); + SatelliteController stats = captor.getValue(); + assertEquals(param.getCountOfSatelliteServiceEnablementsSuccess(), + stats.countOfSatelliteServiceEnablementsSuccess); + assertEquals(param.getCountOfSatelliteServiceEnablementsFail(), + stats.countOfSatelliteServiceEnablementsFail); + assertEquals(param.getCountOfOutgoingDatagramSuccess(), + stats.countOfOutgoingDatagramSuccess); + assertEquals(param.getCountOfOutgoingDatagramFail(), + stats.countOfOutgoingDatagramFail); + assertEquals(param.getCountOfIncomingDatagramSuccess(), + stats.countOfIncomingDatagramSuccess); + assertEquals(param.getCountOfIncomingDatagramFail(), + stats.countOfIncomingDatagramFail); + assertEquals(param.getCountOfDatagramTypeSosSmsSuccess(), + stats.countOfDatagramTypeSosSmsSuccess); + assertEquals(param.getCountOfDatagramTypeSosSmsFail(), + stats.countOfDatagramTypeSosSmsFail); + assertEquals(param.getCountOfDatagramTypeLocationSharingSuccess(), + stats.countOfDatagramTypeLocationSharingSuccess); + assertEquals(param.getCountOfDatagramTypeLocationSharingFail(), + stats.countOfDatagramTypeLocationSharingFail); + assertEquals(param.getCountOfProvisionSuccess(), + stats.countOfProvisionSuccess); + assertEquals(param.getCountOfProvisionFail(), + stats.countOfProvisionFail); + assertEquals(param.getCountOfDeprovisionSuccess(), + stats.countOfDeprovisionSuccess); + assertEquals(param.getCountOfDeprovisionFail(), + stats.countOfDeprovisionFail); + assertEquals(param.getTotalServiceUptimeSec(), + stats.totalServiceUptimeSec); + assertEquals(param.getTotalBatteryConsumptionPercent(), + stats.totalBatteryConsumptionPercent); + assertEquals(param.getTotalBatteryChargedTimeSec(), + stats.totalBatteryChargedTimeSec); + + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + public void onSatelliteSessionMetrics_withAtoms() throws Exception { + SatelliteStats.SatelliteSessionParams param = + new SatelliteStats.SatelliteSessionParams.Builder() + .setSatelliteServiceInitializationResult( + SatelliteProtoEnums.SATELLITE_ERROR_NONE) + .setSatelliteTechnology(SatelliteProtoEnums.NT_RADIO_TECHNOLOGY_PROPRIETARY) + .build(); + + mSatelliteStats.onSatelliteSessionMetrics(param); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(SatelliteSession.class); + verify(mPersistAtomsStorage).addSatelliteSessionStats(captor.capture()); + SatelliteSession stats = captor.getValue(); + assertEquals(param.getSatelliteServiceInitializationResult(), + stats.satelliteServiceInitializationResult); + assertEquals(param.getSatelliteTechnology(), stats.satelliteTechnology); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + public void onSatelliteIncomingDatagramMetrics_withAtoms() throws Exception { + SatelliteStats.SatelliteIncomingDatagramParams param = + new SatelliteStats.SatelliteIncomingDatagramParams.Builder() + .setResultCode(SatelliteProtoEnums.SATELLITE_ERROR_NONE) + .setDatagramSizeBytes(1 * 1024) + .setDatagramTransferTimeMillis(3 * 1000) + .build(); + + mSatelliteStats.onSatelliteIncomingDatagramMetrics(param); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(SatelliteIncomingDatagram.class); + verify(mPersistAtomsStorage).addSatelliteIncomingDatagramStats(captor.capture()); + SatelliteIncomingDatagram stats = captor.getValue(); + assertEquals(param.getResultCode(), stats.resultCode); + assertEquals(param.getDatagramSizeBytes(), stats.datagramSizeBytes); + assertEquals(param.getDatagramTransferTimeMillis(), stats.datagramTransferTimeMillis); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + public void onSatelliteOutgoingDatagramMetrics_withAtoms() throws Exception { + SatelliteStats.SatelliteOutgoingDatagramParams param = + new SatelliteStats.SatelliteOutgoingDatagramParams.Builder() + .setDatagramType(SatelliteProtoEnums.DATAGRAM_TYPE_LOCATION_SHARING) + .setResultCode(SatelliteProtoEnums.SATELLITE_ERROR_NONE) + .setDatagramSizeBytes(1 * 1024) + .setDatagramTransferTimeMillis(3 * 1000) + .build(); + + mSatelliteStats.onSatelliteOutgoingDatagramMetrics(param); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(SatelliteOutgoingDatagram.class); + verify(mPersistAtomsStorage).addSatelliteOutgoingDatagramStats(captor.capture()); + SatelliteOutgoingDatagram stats = captor.getValue(); + assertEquals(param.getDatagramType(), stats.datagramType); + assertEquals(param.getResultCode(), stats.resultCode); + assertEquals(param.getDatagramSizeBytes(), stats.datagramSizeBytes); + assertEquals(param.getDatagramTransferTimeMillis(), stats.datagramTransferTimeMillis); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + public void onSatelliteProvisionMetrics_withAtoms() throws Exception { + SatelliteStats.SatelliteProvisionParams param = + new SatelliteStats.SatelliteProvisionParams.Builder() + .setResultCode(SatelliteProtoEnums.SATELLITE_SERVICE_PROVISION_IN_PROGRESS) + .setProvisioningTimeSec(5 * 1000) + .setIsProvisionRequest(true) + .setIsCanceled(false) + .build(); + + mSatelliteStats.onSatelliteProvisionMetrics(param); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(SatelliteProvision.class); + verify(mPersistAtomsStorage).addSatelliteProvisionStats(captor.capture()); + SatelliteProvision stats = captor.getValue(); + assertEquals(param.getResultCode(), stats.resultCode); + assertEquals(param.getProvisioningTimeSec(), stats.provisioningTimeSec); + assertEquals(param.getIsProvisionRequest(), stats.isProvisionRequest); + assertEquals(param.getIsCanceled(), stats.isCanceled); + + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + public void onSatelliteSosMessageRecommenderMetrics_withAtoms() throws Exception { + SatelliteStats.SatelliteSosMessageRecommenderParams param = + new SatelliteStats.SatelliteSosMessageRecommenderParams.Builder() + .setDisplaySosMessageSent(true) + .setCountOfTimerStarted(5) + .setImsRegistered(false) + .setCellularServiceState(TelephonyProtoEnums.SERVICE_STATE_OUT_OF_SERVICE) + .build(); + + mSatelliteStats.onSatelliteSosMessageRecommender(param); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(SatelliteSosMessageRecommender.class); + verify(mPersistAtomsStorage).addSatelliteSosMessageRecommenderStats(captor.capture()); + SatelliteSosMessageRecommender stats = captor.getValue(); + assertEquals(param.isDisplaySosMessageSent(), + stats.isDisplaySosMessageSent); + assertEquals(param.getCountOfTimerStarted(), stats.countOfTimerStarted); + assertEquals(param.isImsRegistered(), stats.isImsRegistered); + assertEquals(param.getCellularServiceState(), stats.cellularServiceState); + verifyNoMoreInteractions(mPersistAtomsStorage); + } +} -- GitLab From 39ec979702967d3f7e13ada0bb785cc41d73c56f Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 14 Mar 2023 20:14:47 -0700 Subject: [PATCH 539/656] Use AlarmManager to schedule long retry The limitation with handler message is that they extremely delayed when device is in (light) doze mode, even when it enters the maintenance window. The experiment suggests that delay occurrs for timer longer than 1 minute, therefore this change uses AlarmManager to schedule longer retries. Fix: 271037454 Test: Reproduced the issue and confirmed the fix by experiment Change-Id: I676ecd9e593d7e774993cb941ecf1791034fa148 --- .../telephony/data/DataRetryManager.java | 85 +++++++++++++++++-- .../internal/telephony/ContextFixture.java | 2 + .../internal/telephony/TelephonyTest.java | 9 +- .../data/DataNetworkControllerTest.java | 5 +- .../telephony/data/DataRetryManagerTest.java | 47 +++++++++- 5 files changed, 135 insertions(+), 13 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index 9e2e3b12e6..c4b04cad87 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -21,6 +21,12 @@ import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.net.NetworkCapabilities; import android.os.AsyncResult; import android.os.Handler; @@ -72,6 +78,11 @@ import java.util.stream.Stream; public class DataRetryManager extends Handler { private static final boolean VDBG = false; + /** Intent of Alarm Manager for long retry timer. */ + private static final String ACTION_RETRY = "com.android.internal.telephony.data.ACTION_RETRY"; + /** The extra key for the hashcode of the retry entry for Alarm Manager. */ + private static final String ACTION_RETRY_EXTRA_HASHCODE = "extra_retry_hashcode"; + /** Event for data setup retry. */ private static final int EVENT_DATA_SETUP_RETRY = 3; @@ -98,6 +109,12 @@ public class DataRetryManager extends Handler { /** The maximum entries to preserve. */ private static final int MAXIMUM_HISTORICAL_ENTRIES = 100; + /** + * The threshold of retry timer, longer than or equal to which we use alarm manager to schedule + * instead of handler. + */ + private static final long RETRY_LONG_DELAY_TIMER_THRESHOLD_MILLIS = TimeUnit + .MINUTES.toMillis(1); @IntDef(prefix = {"RESET_REASON_"}, value = { @@ -143,6 +160,9 @@ public class DataRetryManager extends Handler { /** Local log. */ private final @NonNull LocalLog mLocalLog = new LocalLog(128); + /** Alarm Manager used to schedule long set up or handover retries. */ + private final @NonNull AlarmManager mAlarmManager; + /** * The data retry callback. This is only used to notify {@link DataNetworkController} to retry * setup data network. @@ -952,6 +972,8 @@ public class DataRetryManager extends Handler { mDataServiceManagers = dataServiceManagers; mDataConfigManager = dataNetworkController.getDataConfigManager(); mDataProfileManager = dataNetworkController.getDataProfileManager(); + mAlarmManager = mPhone.getContext().getSystemService(AlarmManager.class); + mDataConfigManager.registerCallback(new DataConfigManagerCallback(this::post) { @Override public void onCarrierConfigChanged() { @@ -996,6 +1018,19 @@ public class DataRetryManager extends Handler { mRil.registerForOn(this, EVENT_RADIO_ON, null); mRil.registerForModemReset(this, EVENT_MODEM_RESET, null); + // Register intent of alarm manager for long retry timer + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_RETRY); + mPhone.getContext().registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_RETRY.equals(intent.getAction())) { + DataRetryManager.this.onAlarmIntentRetry( + intent.getIntExtra(ACTION_RETRY_EXTRA_HASHCODE, -1 /*Bad hashcode*/)); + } + } + }, intentFilter); + if (mDataConfigManager.shouldResetDataThrottlingWhenTacChanges()) { mPhone.getServiceStateTracker().registerForAreaCodeChanged(this, EVENT_TAC_CHANGED, null); @@ -1409,20 +1444,50 @@ public class DataRetryManager extends Handler { * @param dataRetryEntry The data retry entry. */ private void schedule(@NonNull DataRetryEntry dataRetryEntry) { - logl("Scheduled data retry: " + dataRetryEntry); + logl("Scheduled data retry " + dataRetryEntry + + " hashcode=" + dataRetryEntry.hashCode()); mDataRetryEntries.add(dataRetryEntry); if (mDataRetryEntries.size() >= MAXIMUM_HISTORICAL_ENTRIES) { // Discard the oldest retry entry. mDataRetryEntries.remove(0); } - // Using delayed message instead of alarm manager to schedule data retry is intentional. - // When the device enters doze mode, the handler message might be extremely delayed than the - // original scheduled time. There is no need to wake up the device to perform data retry in - // that case. - sendMessageDelayed(obtainMessage(dataRetryEntry instanceof DataSetupRetryEntry - ? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY, dataRetryEntry), - dataRetryEntry.retryDelayMillis); + // When the device is in doze mode, the handler message might be extremely delayed because + // handler uses relative system time(not counting sleep) which is inaccurate even when we + // enter the maintenance window. + // Therefore, we use alarm manager when we need to schedule long timers. + if (dataRetryEntry.retryDelayMillis <= RETRY_LONG_DELAY_TIMER_THRESHOLD_MILLIS) { + sendMessageDelayed(obtainMessage(dataRetryEntry instanceof DataSetupRetryEntry + ? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY, dataRetryEntry), + dataRetryEntry.retryDelayMillis); + } else { + Intent intent = new Intent(ACTION_RETRY); + intent.putExtra(ACTION_RETRY_EXTRA_HASHCODE, dataRetryEntry.hashCode()); + // No need to wake up the device at the exact time, the retry can wait util next time + // the device wake up to save power. + mAlarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, + dataRetryEntry.retryElapsedTime, + PendingIntent.getBroadcast(mPhone.getContext(), + dataRetryEntry.hashCode() /*Unique identifier of this retry attempt*/, + intent, + PendingIntent.FLAG_IMMUTABLE)); + } + } + + /** + * Called when it's time to retry scheduled by Alarm Manager. + * @param retryHashcode The hashcode is the unique identifier of which retry entry to retry. + */ + private void onAlarmIntentRetry(int retryHashcode) { + DataRetryEntry dataRetryEntry = mDataRetryEntries.stream() + .filter(entry -> entry.hashCode() == retryHashcode) + .findAny() + .orElse(null); + logl("onAlarmIntentRetry: found " + dataRetryEntry + " with hashcode " + retryHashcode); + if (dataRetryEntry != null) { + sendMessage(obtainMessage(dataRetryEntry instanceof DataSetupRetryEntry + ? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY, dataRetryEntry)); + } } /** @@ -1636,12 +1701,14 @@ public class DataRetryManager extends Handler { */ public boolean isSimilarNetworkRequestRetryScheduled( @NonNull TelephonyNetworkRequest networkRequest, @TransportType int transport) { + long now = SystemClock.elapsedRealtime(); for (int i = mDataRetryEntries.size() - 1; i >= 0; i--) { if (mDataRetryEntries.get(i) instanceof DataSetupRetryEntry) { DataSetupRetryEntry entry = (DataSetupRetryEntry) mDataRetryEntries.get(i); if (entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED && entry.setupRetryType - == DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS) { + == DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS + && entry.retryElapsedTime > now) { if (entry.networkRequestList.isEmpty()) { String msg = "Invalid data retry entry detected"; logl(msg); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java index 760fc88a25..ea19b62625 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java @@ -356,6 +356,8 @@ public class ContextFixture implements TestFixture { return Context.POWER_SERVICE; } else if (serviceClass == EuiccManager.class) { return Context.EUICC_SERVICE; + } else if (serviceClass == AlarmManager.class) { + return Context.ALARM_SERVICE; } return super.getSystemServiceName(serviceClass); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 6ca2729137..7c7c12a22e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -716,7 +716,14 @@ public abstract class TelephonyTest { doReturn(mPhone).when(mInboundSmsHandler).getPhone(); doReturn(mImsCallProfile).when(mImsCall).getCallProfile(); doReturn(mIBinder).when(mIIntentSender).asBinder(); - doReturn(mIIntentSender).when(mIActivityManager).getIntentSenderWithFeature(anyInt(), + doAnswer(invocation -> { + Intent[] intents = invocation.getArgument(6); + if (intents != null && intents.length > 0) { + doReturn(intents[0]).when(mIActivityManager) + .getIntentForIntentSender(mIIntentSender); + } + return mIIntentSender; + }).when(mIActivityManager).getIntentSenderWithFeature(anyInt(), nullable(String.class), nullable(String.class), nullable(IBinder.class), nullable(String.class), anyInt(), nullable(Intent[].class), nullable(String[].class), anyInt(), nullable(Bundle.class), anyInt()); 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 0dded1247a..3d004d0caa 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -2663,8 +2663,9 @@ public class DataNetworkControllerTest extends TelephonyTest { createNetworkRequest(NetworkCapabilities.NET_CAPABILITY_INTERNET)); processAllFutureMessages(); - // Should retried 20 times, which is the maximum based on the retry config rules. - verify(mMockedWwanDataServiceManager, times(21)).setupDataCall(anyInt(), + // The first 8 retries are short timers that scheduled by handler, future retries are + // scheduled by intent and require more complex mock, so we only verify the first 8 here. + verify(mMockedWwanDataServiceManager, times(9)).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), any(Message.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 769a920620..36c9e77745 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java @@ -24,12 +24,17 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.Intent; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.AsyncResult; @@ -130,6 +135,7 @@ public class DataRetryManagerTest extends TelephonyTest { .build(); // Mocked classes + private AlarmManager mAlarmManager; private DataRetryManagerCallback mDataRetryManagerCallbackMock; private DataRetryManager mDataRetryManagerUT; @@ -147,6 +153,7 @@ public class DataRetryManagerTest extends TelephonyTest { ((Runnable) invocation.getArguments()[0]).run(); return null; }).when(mDataRetryManagerCallbackMock).invokeFromExecutor(any(Runnable.class)); + mAlarmManager = Mockito.mock(AlarmManager.class); SparseArray mockedDataServiceManagers = new SparseArray<>(); mockedDataServiceManagers.put(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, mMockedWwanDataServiceManager); @@ -166,6 +173,8 @@ public class DataRetryManagerTest extends TelephonyTest { dataNetworkControllerCallbackCaptor.capture()); mDataNetworkControllerCallback = dataNetworkControllerCallbackCaptor.getValue(); + replaceInstance(DataRetryManager.class, "mAlarmManager", + mDataRetryManagerUT, mAlarmManager); logd("DataRetryManagerTest -Setup!"); } @@ -497,7 +506,6 @@ public class DataRetryManagerTest extends TelephonyTest { processAllMessages(); NetworkRequest request = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build(); TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); @@ -739,6 +747,43 @@ public class DataRetryManagerTest extends TelephonyTest { assertThat(rule.getRetryIntervalsMillis()).containsExactly(5000L); } + @Test + public void testDataRetryLongTimer() { + // Rule requires a long timer + DataSetupRetryRule retryRule = new DataSetupRetryRule( + "capabilities=internet, retry_interval=120000, maximum_retries=2"); + doReturn(Collections.singletonList(retryRule)).when(mDataConfigManager) + .getDataSetupRetryRules(); + mDataConfigManagerCallback.onCarrierConfigChanged(); + processAllMessages(); + + NetworkRequest request = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(); + TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone); + DataNetworkController.NetworkRequestList + networkRequestList = new DataNetworkController.NetworkRequestList(tnr); + mDataRetryManagerUT.evaluateDataSetupRetry(mDataProfile1, + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, networkRequestList, 2253, + DataCallResponse.RETRY_DURATION_UNDEFINED); + processAllFutureMessages(); + + // Verify scheduled via Alarm Manager + ArgumentCaptor pendingIntentArgumentCaptor = + ArgumentCaptor.forClass(PendingIntent.class); + verify(mAlarmManager).setAndAllowWhileIdle(anyInt(), anyLong(), + pendingIntentArgumentCaptor.capture()); + + // Verify starts retry attempt after receiving intent + PendingIntent pendingIntent = pendingIntentArgumentCaptor.getValue(); + Intent intent = pendingIntent.getIntent(); + mContext.sendBroadcast(intent); + processAllFutureMessages(); + + verify(mDataRetryManagerCallbackMock) + .onDataNetworkSetupRetry(any(DataSetupRetryEntry.class)); + } + @Test public void testDataHandoverRetryInvalidRulesFromString() { assertThrows(IllegalArgumentException.class, -- GitLab From a0302591a11e92f39c561d84624186b8732c07e4 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Wed, 22 Mar 2023 13:28:11 -0700 Subject: [PATCH 540/656] Use res overlay to exempt auto data switch ping test Fix: 268077711 Test: basic calling + data browsing Change-Id: I4797d0d8cb5d85cb46daf4b002a3b086e168551d --- .../telephony/data/DataConfigManager.java | 23 +++++-------------- .../telephony/data/PhoneSwitcher.java | 2 +- .../telephony/data/PhoneSwitcherTest.java | 4 ++-- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java index 315c1dee4c..78450a81ed 100644 --- a/src/java/com/android/internal/telephony/data/DataConfigManager.java +++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java @@ -301,8 +301,6 @@ public class DataConfigManager extends Handler { private @NonNull final List mHandoverRuleList = new ArrayList<>(); /** {@code True} keep IMS network in case of moving to non VOPS area; {@code false} otherwise.*/ private boolean mShouldKeepNetworkUpInNonVops = false; - /** {@code True} requires ping test before switching preferred modem; {@code false} otherwise.*/ - private boolean mPingTestBeforeDataSwitch = true; /** * Constructor @@ -450,7 +448,6 @@ public class DataConfigManager extends Handler { updateMeteredApnTypes(); updateSingleDataNetworkTypeAndCapabilityExemption(); updateVopsConfig(); - updateDataSwitchConfig(); updateUnmeteredNetworkTypes(); updateBandwidths(); updateTcpBuffers(); @@ -671,16 +668,6 @@ public class DataConfigManager extends Handler { } } - /** - * Update preferred modem switch(opportunistic network or visible subscription) carrier config. - */ - private void updateDataSwitchConfig() { - synchronized (this) { - mPingTestBeforeDataSwitch = mCarrierConfig.getBoolean(CarrierConfigManager - .KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL, true); - } - } - /** * @return The list of {@link NetworkType} that only supports single data networks */ @@ -701,9 +688,10 @@ public class DataConfigManager extends Handler { return mShouldKeepNetworkUpInNonVops; } - /** {@code True} keep IMS network in case of moving to non VOPS area; {@code false} otherwise.*/ - public boolean requirePingTestBeforeDataSwitch() { - return mPingTestBeforeDataSwitch; + /** {@code True} requires ping test to pass on the target slot before switching to it.*/ + public boolean isPingTestBeforeAutoDataSwitchRequired() { + return mResources.getBoolean(com.android.internal.R.bool + .auto_data_switch_ping_test_before_switch); } /** @@ -1340,7 +1328,8 @@ public class DataConfigManager extends Handler { .stream().map(DataUtils::networkCapabilityToString) .collect(Collectors.joining(","))); pw.println("mShouldKeepNetworkUpInNoVops=" + mShouldKeepNetworkUpInNonVops); - pw.println("mPingTestBeforeDataSwitch=" + mPingTestBeforeDataSwitch); + pw.println("isPingTestBeforeAutoDataSwitchRequired=" + + isPingTestBeforeAutoDataSwitchRequired()); pw.println("Unmetered network types=" + String.join(",", mUnmeteredNetworkTypes)); pw.println("Roaming unmetered network types=" + String.join(",", mRoamingUnmeteredNetworkTypes)); diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 1a0ddbe136..fbcd27f020 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -950,7 +950,7 @@ public class PhoneSwitcher extends Handler { Phone phone = getPhoneBySubId(mPrimaryDataSubId); if (phone != null) { DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); - mRequirePingTestBeforeDataSwitch = dataConfig.requirePingTestBeforeDataSwitch(); + mRequirePingTestBeforeDataSwitch = dataConfig.isPingTestBeforeAutoDataSwitchRequired(); mAutoDataSwitchAvailabilityStabilityTimeThreshold = dataConfig.getAutoDataSwitchAvailabilityStabilityTimeThreshold(); mAutoDataSwitchValidationMaxRetry = 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 21197180cb..9e689113fa 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -647,7 +647,7 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); - doReturn(false).when(mDataConfigManager).requirePingTestBeforeDataSwitch(); + doReturn(false).when(mDataConfigManager).isPingTestBeforeAutoDataSwitchRequired(); mDataConfigManagerCallback.onCarrierConfigChanged(); //1. Attempting to switch to nDDS, switch even if validation failed @@ -2017,7 +2017,7 @@ public class PhoneSwitcherTest extends TelephonyTest { doReturn(1000L).when(mDataConfigManager) .getAutoDataSwitchAvailabilityStabilityTimeThreshold(); doReturn(7).when(mDataConfigManager).getAutoDataSwitchValidationMaxRetry(); - doReturn(true).when(mDataConfigManager).requirePingTestBeforeDataSwitch(); + doReturn(true).when(mDataConfigManager).isPingTestBeforeAutoDataSwitchRequired(); mDataConfigManagerCallback.onCarrierConfigChanged(); mDataConfigManagerCallback.onDeviceConfigChanged(); -- GitLab From 238f50b0f7590afe61537e7d03536c62f7d75472 Mon Sep 17 00:00:00 2001 From: sandeepjs Date: Tue, 7 Mar 2023 10:54:37 +0000 Subject: [PATCH 541/656] Adding Anamoly report to detect invalid portIndex Adding Anomaly report to detect invalid portIndex in the active subscriptions. Test: Manual Bug: 263789560 Change-Id: I100409fc9feddbd06addb7cbf860e0f5627b5c7f --- .../subscription/SubscriptionManagerService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 7f3c23fd04..aa9728afbe 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -55,6 +55,7 @@ import android.service.euicc.EuiccService; import android.service.euicc.GetEuiccProfileInfoListResult; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; +import android.telephony.AnomalyReporter; import android.telephony.CarrierConfigManager; import android.telephony.RadioAccessFamily; import android.telephony.SubscriptionInfo; @@ -1143,6 +1144,19 @@ public class SubscriptionManagerService extends ISub.Stub { mSubscriptionDatabaseManager.setEmbedded( subInfo.getSubscriptionId(), false); }); + if (mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .anyMatch(subInfo -> subInfo.isEmbedded() + && subInfo.isActive() + && subInfo.getPortIndex() + == TelephonyManager.INVALID_PORT_INDEX + && mSimState[subInfo.getSimSlotIndex()] + == TelephonyManager.SIM_STATE_LOADED)) { + //Report Anomaly if invalid portIndex is updated in Active subscriptions + AnomalyReporter.reportAnomaly( + UUID.fromString("38fdf63c-3bd9-4fc2-ad33-a20246a32fa7"), + "SubscriptionManagerService: Found Invalid portIndex" + + " in active subscriptions"); + } }); log("updateEmbeddedSubscriptions: Finished embedded subscription update."); if (callback != null) { -- GitLab From 092f5f329ff4134fc7a74af9f84a822371db4341 Mon Sep 17 00:00:00 2001 From: joonhunshin Date: Wed, 15 Feb 2023 10:05:35 +0000 Subject: [PATCH 542/656] Add the resetIms interface between framework and ImsService. Add the resetIms interface between framework and ImsService. Bug: b/268251541 Test: atest ImsEnablementTrackerTest Test: 1. AT&T activated, Fi deactivated 2. AT&T activated, Fi activated 3. AT&T deactivated, Fi activated 4. AT&T activated, Fi activated 5. repeat from step 1 Merged-In: I673da788e9fcaf20b494f45d308d0456981b9e92 Change-Id: I673da788e9fcaf20b494f45d308d0456981b9e92 (cherry picked from commit ce241f2c1ea17324ccf3acb8e9f0da8d51809bfb) --- .../telephony/ims/ImsEnablementTracker.java | 477 +++++++++------ .../ims/ImsEnablementTrackerTest.java | 555 +++++++++++++----- 2 files changed, 701 insertions(+), 331 deletions(-) diff --git a/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java b/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java index 732478de98..e54561f15d 100644 --- a/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java +++ b/src/java/com/android/internal/telephony/ims/ImsEnablementTracker.java @@ -22,11 +22,13 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.telephony.SubscriptionManager; import android.telephony.ims.aidl.IImsServiceController; import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -36,35 +38,38 @@ import java.util.Map; /** * This class will abstract away all the new enablement logic and take the reset/enable/disable * IMS commands as inputs. - * The IMS commands will call enableIms or disableIms to match the enablement state only when - * it changes. + * The IMS commands will call enableIms, disableIms or resetIms to match the enablement state only + * when it changes. */ public class ImsEnablementTracker { private static final String LOG_TAG = "ImsEnablementTracker"; - private static final long REQUEST_THROTTLE_TIME_MS = 1 * 1000; // 1 seconds + private static final long REQUEST_THROTTLE_TIME_MS = 3 * 1000L; // 3 seconds private static final int COMMAND_NONE_MSG = 0; // Indicate that the enableIms command has been received. - private static final int COMMAND_ENABLE_MSG = 1; + @VisibleForTesting + public static final int COMMAND_ENABLE_MSG = 1; // Indicate that the disableIms command has been received. - private static final int COMMAND_DISABLE_MSG = 2; + @VisibleForTesting + public static final int COMMAND_DISABLE_MSG = 2; // Indicate that the resetIms command has been received. private static final int COMMAND_RESET_MSG = 3; // Indicate that the internal enable message with delay has been received. - @VisibleForTesting - protected static final int COMMAND_ENABLING_DONE = 4; + private static final int COMMAND_ENABLING_DONE = 4; // Indicate that the internal disable message with delay has been received. - @VisibleForTesting - protected static final int COMMAND_DISABLING_DONE = 5; + private static final int COMMAND_DISABLING_DONE = 5; // Indicate that the internal reset message with delay has been received. @VisibleForTesting - protected static final int COMMAND_RESETTING_DONE = 6; + public static final int COMMAND_RESETTING_DONE = 6; // The ImsServiceController binder is connected. private static final int COMMAND_CONNECTED_MSG = 7; // The ImsServiceController binder is disconnected. private static final int COMMAND_DISCONNECTED_MSG = 8; // The subId is changed to INVALID_SUBSCRIPTION_ID. private static final int COMMAND_INVALID_SUBID_MSG = 9; + // Indicate that the internal post reset message with delay has been received. + @VisibleForTesting + public static final int COMMAND_POST_RESETTING_DONE = 10; private static final Map EVENT_DESCRIPTION = new HashMap<>(); static { @@ -95,6 +100,9 @@ public class ImsEnablementTracker { @VisibleForTesting protected static final int STATE_IMS_RESETTING = 6; + @VisibleForTesting + protected static final int STATE_IMS_POSTRESETTING = 7; + protected final Object mLock = new Object(); private IImsServiceController mIImsServiceController; private long mLastImsOperationTimeMs = 0L; @@ -105,14 +113,16 @@ public class ImsEnablementTracker { private final int mState; /** - * Provides Ims Enablement Tracker State Machine responsible for ims enable/disable command - * interactions with Ims service controller binder. - * The enable/disable/reset ims commands have a time interval of at least 1 second between + * Provides Ims Enablement Tracker State Machine responsible for ims enable/disable/reset + * command interactions with Ims service controller binder. + * The enable/disable/reset ims commands have a time interval of at least + * {@link ImsEnablementTracker#REQUEST_THROTTLE_TIME_MS} second between * processing each command. * For example, the enableIms command is received and the binder's enableIms is called. * After that, if the disableIms command is received, the binder's disableIms will be - * called after 1 second. - * A time of 1 second uses {@link Handler#sendMessageDelayed(Message, long)}, + * called after {@link ImsEnablementTracker#REQUEST_THROTTLE_TIME_MS} second. + * A time of {@link ImsEnablementTracker#REQUEST_THROTTLE_TIME_MS} will be used + * {@link Handler#sendMessageDelayed(Message, long)}, * and the enabled, disabled and reset states are responsible for waiting for * that delay message. */ @@ -122,29 +132,35 @@ public class ImsEnablementTracker { */ @VisibleForTesting public final Default mDefault; + /** * Indicates that {@link IImsServiceController#enableIms(int, int)} has been called and * waiting for an ims commands. * Common transitions are to * {@link #mDisabling} state when the disable command is received - * or {@link #mResetting} state when the reset command is received. + * or {@link #mResetting} state when the reset command is received * or {@link #mDisconnected} if the binder is disconnected. */ @VisibleForTesting public final Enabled mEnabled; + /** - * Indicates that the state waiting for a disableIms message. + * Indicates that the state waiting for the throttle time to elapse before calling + * {@link IImsServiceController#disableIms(int, int)}. * Common transitions are to * {@link #mEnabled} when the enable command is received. * or {@link #mResetting} when the reset command is received. - * or {@link #mDisabled} the previous binder API call has passed 1 second, and if + * or {@link #mDisabled} the previous binder API call has passed + * {@link ImsEnablementTracker#REQUEST_THROTTLE_TIME_MS} second, and if * {@link IImsServiceController#disableIms(int, int)} called. * or {@link #mDisabling} received a disableIms message and the previous binder API call - * has not passed 1 second.Then send a disableIms message with delay. + * has not passed {@link ImsEnablementTracker#REQUEST_THROTTLE_TIME_MS} second. + * Then send a disableIms message with delay. * or {@link #mDisconnected} if the binder is disconnected. */ @VisibleForTesting public final Disabling mDisabling; + /** * Indicates that {@link IImsServiceController#disableIms(int, int)} has been called and * waiting for an ims commands. @@ -154,31 +170,47 @@ public class ImsEnablementTracker { */ @VisibleForTesting public final Disabled mDisabled; + /** - * Indicates that the state waiting for an enableIms message. + * Indicates that the state waiting for the throttle time to elapse before calling + * {@link IImsServiceController#enableIms(int, int)}. * Common transitions are to - * {@link #mEnabled} the previous binder API call has passed 1 second, and + * {@link #mEnabled} the previous binder API call has passed + * {@link ImsEnablementTracker#REQUEST_THROTTLE_TIME_MS} second, and * {@link IImsServiceController#enableIms(int, int)} called. * or {@link #mDisabled} when the disable command is received. * or {@link #mEnabling} received an enableIms message and the previous binder API call - * has not passed 1 second.Then send an enableIms message with delay. + * has not passed {@link ImsEnablementTracker#REQUEST_THROTTLE_TIME_MS} second. + * Then send an enableIms message with delay. * or {@link #mDisconnected} if the binder is disconnected. */ @VisibleForTesting public final Enabling mEnabling; + /** - * Indicates that the state waiting for a resetIms message. + * Indicates that the state waiting for the throttle time to elapse before calling + * {@link IImsServiceController#resetIms(int, int)}. * Common transitions are to - * {@link #mDisabling} state when the disable command is received - * or {@link #mResetting} received a resetIms message and the previous binder API call - * has not passed 1 second.Then send a resetIms message with delay. - * or {@link #mEnabling} when the resetIms message is received and if - * {@link IImsServiceController#disableIms(int, int)} call is successful. And send an enable - * message with delay. + * {@link #mPostResetting} state to call either enableIms or disableIms after calling + * {@link IImsServiceController#resetIms(int, int)} * or {@link #mDisconnected} if the binder is disconnected. */ @VisibleForTesting public final Resetting mResetting; + + /** + * Indicates that the state waiting after resetIms for the throttle time to elapse before + * calling {@link IImsServiceController#enableIms(int, int)} or + * {@link IImsServiceController#disableIms(int, int)}. + * Common transitions are to + * {@link #mEnabled} state when the disable command is received, + * {@link #mDisabled} state when the enable command is received after calling + * {@link IImsServiceController#enableIms(int, int)}, + * {@link IImsServiceController#disableIms(int, int)} + * or {@link #mDisconnected} if the binder is disconnected. + */ + public final PostResetting mPostResetting; + /** * Indicates that {@link IImsServiceController} has not been set. * Common transition is to @@ -188,16 +220,17 @@ public class ImsEnablementTracker { * or {@link #mEnabling} If the enable command is received while the binder is * disconnected */ - @VisibleForTesting - public final Disconnected mDisconnected; - @VisibleForTesting - public int mSlotId; - @VisibleForTesting - public int mSubId; + private final Disconnected mDisconnected; + private int mSlotId; + private int mSubId; private final int mPhoneId; + private IState mPreviousState; + + private int mLastMsg = COMMAND_NONE_MSG; + ImsEnablementTrackerStateMachine(String name, Looper looper, int state, int slotId) { super(name, looper); mPhoneId = slotId; @@ -208,6 +241,7 @@ public class ImsEnablementTracker { mEnabling = new Enabling(); mResetting = new Resetting(); mDisconnected = new Disconnected(); + mPostResetting = new PostResetting(); addState(mDefault); addState(mEnabled); @@ -216,8 +250,10 @@ public class ImsEnablementTracker { addState(mEnabling); addState(mResetting); addState(mDisconnected); + addState(mPostResetting); setInitialState(getState(state)); + mPreviousState = getState(state); } public void clearAllMessage() { @@ -228,6 +264,7 @@ public class ImsEnablementTracker { removeMessages(COMMAND_ENABLING_DONE); removeMessages(COMMAND_DISABLING_DONE); removeMessages(COMMAND_RESETTING_DONE); + removeMessages(COMMAND_POST_RESETTING_DONE); } public void serviceBinderConnected() { @@ -242,26 +279,40 @@ public class ImsEnablementTracker { @VisibleForTesting public boolean isState(int state) { - if (state == mDefault.mStateNo) { - return (getCurrentState() == mDefault) ? true : false; - } else if (state == mEnabled.mStateNo) { - return (getCurrentState() == mEnabled) ? true : false; - } else if (state == mDisabling.mStateNo) { - return (getCurrentState() == mDisabling) ? true : false; - } else if (state == mDisabled.mStateNo) { - return (getCurrentState() == mDisabled) ? true : false; - } else if (state == mEnabling.mStateNo) { - return (getCurrentState() == mEnabling) ? true : false; - } else if (state == mResetting.mStateNo) { - return (getCurrentState() == mResetting) ? true : false; + State expect = null; + switch (state) { + case Default.STATE_NO: + expect = mDefault; + break; + case Enabled.STATE_NO: + expect = mEnabled; + break; + case Disabling.STATE_NO: + expect = mDisabling; + break; + case Disabled.STATE_NO: + expect = mDisabled; + break; + case Enabling.STATE_NO: + expect = mEnabling; + break; + case Resetting.STATE_NO: + expect = mResetting; + break; + case Disconnected.STATE_NO: + expect = mDisconnected; + break; + case PostResetting.STATE_NO: + expect = mPostResetting; + break; + default: + break; } - return false; + return (getCurrentState() == expect) ? true : false; } private State getState(int state) { switch (state) { - case ImsEnablementTracker.STATE_IMS_DEFAULT: - return mDefault; case ImsEnablementTracker.STATE_IMS_ENABLED: return mEnabled; case ImsEnablementTracker.STATE_IMS_DISABLING: @@ -272,42 +323,61 @@ public class ImsEnablementTracker { return mEnabling; case ImsEnablementTracker.STATE_IMS_RESETTING: return mResetting; - default: + case ImsEnablementTracker.STATE_IMS_DISCONNECTED: return mDisconnected; + case ImsEnablementTracker.STATE_IMS_POSTRESETTING: + return mPostResetting; + default: + return mDefault; } } + private void handleInvalidSubIdMessage() { + clearAllMessage(); + transitionState(mDefault); + } + + private void transitionState(State state) { + mPreviousState = getCurrentState(); + transitionTo(state); + } + class Default extends State { - public int mStateNo = STATE_IMS_DEFAULT; - @Override - public void enter() { - Log.d(LOG_TAG, "Default state:enter"); - } + private static final int STATE_NO = STATE_IMS_DEFAULT; @Override - public void exit() { - Log.d(LOG_TAG, "Default state:exit"); + public void enter() { + Log.d(LOG_TAG, "[" + mPhoneId + "]Default state:enter"); + mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @Override public boolean processMessage(Message message) { Log.d(LOG_TAG, "[" + mPhoneId + "]Default state:processMessage. msg.what=" + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); + switch (message.what) { // When enableIms() is called, enableIms of binder is call and the state // change to the enabled state. case COMMAND_ENABLE_MSG: sendEnableIms(message.arg1, message.arg2); - transitionTo(mEnabled); + transitionState(mEnabled); return HANDLED; // When disableIms() is called, disableIms of binder is call and the state // change to the disabled state. case COMMAND_DISABLE_MSG: sendDisableIms(message.arg1, message.arg2); - transitionTo(mDisabled); + transitionState(mDisabled); + return HANDLED; + // When resetIms() is called, change to the resetting state to call enableIms + // after calling resetIms of binder. + case COMMAND_RESET_MSG: + mSlotId = message.arg1; + mSubId = message.arg2; + transitionState(mResetting); return HANDLED; case COMMAND_DISCONNECTED_MSG: - transitionTo(mDisconnected); + transitionState(mDisconnected); return HANDLED; default: return NOT_HANDLED; @@ -316,38 +386,36 @@ public class ImsEnablementTracker { } class Enabled extends State { - public int mStateNo = STATE_IMS_ENABLED; - @Override - public void enter() { - Log.d(LOG_TAG, "Enabled state:enter"); - } + private static final int STATE_NO = STATE_IMS_ENABLED; @Override - public void exit() { - Log.d(LOG_TAG, "Enabled state:exit"); + public void enter() { + Log.d(LOG_TAG, "[" + mPhoneId + "]Enabled state:enter"); } @Override public boolean processMessage(Message message) { Log.d(LOG_TAG, "[" + mPhoneId + "]Enabled state:processMessage. msg.what=" + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); - mSlotId = message.arg1; - mSubId = message.arg2; + switch (message.what) { // the disableIms() is called. case COMMAND_DISABLE_MSG: - transitionTo(mDisabling); + mSlotId = message.arg1; + mSubId = message.arg2; + transitionState(mDisabling); return HANDLED; // the resetIms() is called. case COMMAND_RESET_MSG: - transitionTo(mResetting); + mSlotId = message.arg1; + mSubId = message.arg2; + transitionState(mResetting); return HANDLED; case COMMAND_DISCONNECTED_MSG: - transitionTo(mDisconnected); + transitionState(mDisconnected); return HANDLED; case COMMAND_INVALID_SUBID_MSG: - clearAllMessage(); - transitionTo(mDefault); + handleInvalidSubIdMessage(); return HANDLED; default: return NOT_HANDLED; @@ -356,51 +424,55 @@ public class ImsEnablementTracker { } class Disabling extends State { - public int mStateNo = STATE_IMS_DISABLING; + private static final int STATE_NO = STATE_IMS_DISABLING; + @Override public void enter() { - Log.d(LOG_TAG, "Disabling state:enter"); + Log.d(LOG_TAG, "[" + mPhoneId + "]Disabling state:enter"); sendMessageDelayed(COMMAND_DISABLING_DONE, mSlotId, mSubId, getRemainThrottleTime()); } - @Override - public void exit() { - Log.d(LOG_TAG, "Disabling state:exit"); - } - @Override public boolean processMessage(Message message) { Log.d(LOG_TAG, "[" + mPhoneId + "]Disabling state:processMessage. msg.what=" + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); - mSlotId = message.arg1; - mSubId = message.arg2; + switch (message.what) { - // In the enabled state, disableIms() is called, but the throttle timer has - // not expired, so a delay_disable message is sent. - // At this point enableIms() was called, so it cancels the message and just - // changes the state to the enabled. case COMMAND_ENABLE_MSG: + mSlotId = message.arg1; + mSubId = message.arg2; clearAllMessage(); - transitionTo(mEnabled); + if (mPreviousState == mResetting) { + // if we are moving from Resetting -> Disabling and receive + // the COMMAND_ENABLE_MSG, we need to send the enableIms command, + // so move to Enabling state. + transitionState(mEnabling); + } else { + // When moving from Enabled -> Disabling and we receive an ENABLE_MSG, + // we can move straight back to Enabled state because we have not sent + // the disableIms command to IMS yet. + transitionState(mEnabled); + } return HANDLED; case COMMAND_DISABLING_DONE: // If the disable command is received before disableIms is processed, // it will be ignored because the disable command processing is in progress. removeMessages(COMMAND_DISABLE_MSG); - sendDisableIms(mSlotId, mSubId); - transitionTo(mDisabled); + sendDisableIms(message.arg1, message.arg2); + transitionState(mDisabled); return HANDLED; case COMMAND_RESET_MSG: + mSlotId = message.arg1; + mSubId = message.arg2; clearAllMessage(); - transitionTo(mResetting); + transitionState(mResetting); return HANDLED; case COMMAND_DISCONNECTED_MSG: - transitionTo(mDisconnected); + transitionState(mDisconnected); return HANDLED; case COMMAND_INVALID_SUBID_MSG: - clearAllMessage(); - transitionTo(mDefault); + handleInvalidSubIdMessage(); return HANDLED; default: return NOT_HANDLED; @@ -409,33 +481,34 @@ public class ImsEnablementTracker { } class Disabled extends State { - public int mStateNo = STATE_IMS_DISABLED; - @Override - public void enter() { - Log.d(LOG_TAG, "Disabled state:enter"); - } + private static final int STATE_NO = STATE_IMS_DISABLED; @Override - public void exit() { - Log.d(LOG_TAG, "Disabled state:exit"); + public void enter() { + Log.d(LOG_TAG, "[" + mPhoneId + "]Disabled state:enter"); } @Override public boolean processMessage(Message message) { Log.d(LOG_TAG, "[" + mPhoneId + "]Disabled state:processMessage. msg.what=" + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); - mSlotId = message.arg1; - mSubId = message.arg2; + switch (message.what) { case COMMAND_ENABLE_MSG: - transitionTo(mEnabling); + mSlotId = message.arg1; + mSubId = message.arg2; + transitionState(mEnabling); + return HANDLED; + case COMMAND_RESET_MSG: + mSlotId = message.arg1; + mSubId = message.arg2; + transitionState(mResetting); return HANDLED; case COMMAND_DISCONNECTED_MSG: - transitionTo(mDisconnected); + transitionState(mDisconnected); return HANDLED; case COMMAND_INVALID_SUBID_MSG: - clearAllMessage(); - transitionTo(mDefault); + handleInvalidSubIdMessage(); return HANDLED; default: return NOT_HANDLED; @@ -444,42 +517,50 @@ public class ImsEnablementTracker { } class Enabling extends State { - public int mStateNo = STATE_IMS_ENABLING; + private static final int STATE_NO = STATE_IMS_ENABLING; + @Override public void enter() { - Log.d(LOG_TAG, "Enabling state:enter"); + Log.d(LOG_TAG, "[" + mPhoneId + "]Enabling state:enter"); sendMessageDelayed(COMMAND_ENABLING_DONE, mSlotId, mSubId, getRemainThrottleTime()); } - @Override - public void exit() { - Log.d(LOG_TAG, "Enabling state:exit"); - } - @Override public boolean processMessage(Message message) { Log.d(LOG_TAG, "[" + mPhoneId + "]Enabling state:processMessage. msg.what=" + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); - mSlotId = message.arg1; - mSubId = message.arg2; + switch (message.what) { + // Enabling state comes from Resetting and disableIms() is called. + // In this case disableIms() of binder should be called. + // When enabling state comes from disabled, just change state to the disabled. case COMMAND_DISABLE_MSG: + mSlotId = message.arg1; + mSubId = message.arg2; clearAllMessage(); - transitionTo(mDisabled); + if (mPreviousState == mResetting) { + transitionState(mDisabling); + } else { + transitionState(mDisabled); + } + return HANDLED; + case COMMAND_RESET_MSG: + mSlotId = message.arg1; + mSubId = message.arg2; + transitionState(mResetting); return HANDLED; case COMMAND_ENABLING_DONE: // If the enable command is received before enableIms is processed, // it will be ignored because the enable command processing is in progress. removeMessages(COMMAND_ENABLE_MSG); sendEnableIms(message.arg1, message.arg2); - transitionTo(mEnabled); + transitionState(mEnabled); return HANDLED; case COMMAND_DISCONNECTED_MSG: - transitionTo(mDisconnected); + transitionState(mDisconnected); return HANDLED; case COMMAND_INVALID_SUBID_MSG: - clearAllMessage(); - transitionTo(mDefault); + handleInvalidSubIdMessage(); return HANDLED; default: return NOT_HANDLED; @@ -488,43 +569,41 @@ public class ImsEnablementTracker { } class Resetting extends State { - public int mStateNo = STATE_IMS_RESETTING; + private static final int STATE_NO = STATE_IMS_RESETTING; + @Override public void enter() { - Log.d(LOG_TAG, "Resetting state:enter"); + Log.d(LOG_TAG, "[" + mPhoneId + "]Resetting state:enter"); sendMessageDelayed(COMMAND_RESETTING_DONE, mSlotId, mSubId, getRemainThrottleTime()); } - @Override - public void exit() { - Log.d(LOG_TAG, "Resetting state:exit"); - } - @Override public boolean processMessage(Message message) { Log.d(LOG_TAG, "[" + mPhoneId + "]Resetting state:processMessage. msg.what=" + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); - mSlotId = message.arg1; - mSubId = message.arg2; + switch (message.what) { case COMMAND_DISABLE_MSG: - clearAllMessage(); - transitionTo(mDisabling); + mLastMsg = COMMAND_DISABLE_MSG; + return HANDLED; + case COMMAND_ENABLE_MSG: + mLastMsg = COMMAND_ENABLE_MSG; return HANDLED; case COMMAND_RESETTING_DONE: + mSlotId = message.arg1; + mSubId = message.arg2; // If the reset command is received before disableIms is processed, // it will be ignored because the reset command processing is in progress. removeMessages(COMMAND_RESET_MSG); - sendDisableIms(mSlotId, mSubId); - transitionTo(mEnabling); + sendResetIms(mSlotId, mSubId); + transitionState(mPostResetting); return HANDLED; case COMMAND_DISCONNECTED_MSG: - transitionTo(mDisconnected); + transitionState(mDisconnected); return HANDLED; case COMMAND_INVALID_SUBID_MSG: - clearAllMessage(); - transitionTo(mDefault); + handleInvalidSubIdMessage(); return HANDLED; default: return NOT_HANDLED; @@ -533,30 +612,28 @@ public class ImsEnablementTracker { } class Disconnected extends State { - public int mStateNo = STATE_IMS_DISCONNECTED; + private static final int STATE_NO = STATE_IMS_DISCONNECTED; + private int mLastMsg = COMMAND_NONE_MSG; + @Override public void enter() { - Log.d(LOG_TAG, "Disconnected state:enter"); + Log.d(LOG_TAG, "[" + mPhoneId + "]Disconnected state:enter"); clearAllMessage(); } - @Override - public void exit() { - Log.d(LOG_TAG, "Disconnected state:exit"); - mLastMsg = COMMAND_NONE_MSG; - } - @Override public boolean processMessage(Message message) { Log.d(LOG_TAG, "[" + mPhoneId + "]Disconnected state:processMessage. msg.what=" + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); + switch (message.what) { case COMMAND_CONNECTED_MSG: clearAllMessage(); - transitionTo(mDefault); + transitionState(mDefault); if (mLastMsg != COMMAND_NONE_MSG) { sendMessageDelayed(mLastMsg, mSlotId, mSubId, 0); + mLastMsg = COMMAND_NONE_MSG; } return HANDLED; case COMMAND_ENABLE_MSG: @@ -571,6 +648,65 @@ public class ImsEnablementTracker { } } } + + class PostResetting extends State { + private static final int STATE_NO = STATE_IMS_POSTRESETTING; + + @Override + public void enter() { + Log.d(LOG_TAG, "[" + mPhoneId + "]PostResetting state:enter"); + sendMessageDelayed(COMMAND_POST_RESETTING_DONE, mSlotId, mSubId, + getRemainThrottleTime()); + } + + @Override + public void exit() { + mLastMsg = COMMAND_NONE_MSG; + } + + @Override + public boolean processMessage(Message message) { + Log.d(LOG_TAG, "[" + mPhoneId + "]PostResetting state:processMessage. msg.what=" + + EVENT_DESCRIPTION.get(message.what) + ",component:" + mComponentName); + + switch (message.what) { + case COMMAND_POST_RESETTING_DONE: + mSlotId = message.arg1; + mSubId = message.arg2; + if (mLastMsg == COMMAND_DISABLE_MSG) { + sendDisableIms(mSlotId, mSubId); + transitionState(mDisabled); + } else { + // if mLastMsg is COMMAND_NONE_MSG or COMMAND_ENABLE_MSG + sendEnableIms(mSlotId, mSubId); + transitionState(mEnabled); + } + return HANDLED; + case COMMAND_ENABLE_MSG: + case COMMAND_DISABLE_MSG: + mLastMsg = message.what; + mSlotId = message.arg1; + mSubId = message.arg2; + return HANDLED; + case COMMAND_RESET_MSG: + // when resetIms() called again, skip to call + // IImsServiceController.resetIms(slotId, subId), but after throttle time + // IImsServiceController.enableIms(slotId, subId) should be called. + mLastMsg = COMMAND_ENABLE_MSG; + mSlotId = message.arg1; + mSubId = message.arg2; + return HANDLED; + case COMMAND_DISCONNECTED_MSG: + transitionState(mDisconnected); + return HANDLED; + case COMMAND_INVALID_SUBID_MSG: + handleInvalidSubIdMessage(); + return HANDLED; + default: + return NOT_HANDLED; + } + } + } } public ImsEnablementTracker(Looper looper, ComponentName componentName) { @@ -589,12 +725,8 @@ public class ImsEnablementTracker { mLooper = looper; mState = state; mComponentName = null; - ImsEnablementTrackerStateMachine enablementStateMachine = null; - for (int i = 0; i < numSlots; i++) { - enablementStateMachine = new ImsEnablementTrackerStateMachine("ImsEnablementTracker", - mLooper, mState, i); - mStateMachines.put(i, enablementStateMachine); - } + + setNumOfSlots(numSlots); } /** @@ -625,15 +757,6 @@ public class ImsEnablementTracker { } } - /** - * This API is for testing purposes only and is used to start a state machine. - */ - @VisibleForTesting - public void startStateMachineAsConnected(int slotId) { - mStateMachines.get(slotId).start(); - mStateMachines.get(slotId).sendMessage(COMMAND_CONNECTED_MSG); - } - @VisibleForTesting public Handler getHandler(int slotId) { return mStateMachines.get(slotId).getHandler(); @@ -696,8 +819,9 @@ public class ImsEnablementTracker { } /** - * Notify ImsService to disable IMS for the framework if current state is enabled. - * And notify ImsService back to enable IMS for the framework. + * Notify ImsService to reset IMS for the framework. This will trigger ImsService to perform + * de-registration and release all resource. After that, if enaleIms is called, the ImsService + * performs registration and appropriate initialization to bring up all ImsFeatures. * @param slotId slot id * @param subId subscription id */ @@ -736,7 +860,6 @@ public class ImsEnablementTracker { } } - @VisibleForTesting protected long getLastOperationTimeMillis() { return mLastImsOperationTimeMs; } @@ -749,10 +872,12 @@ public class ImsEnablementTracker { public long getRemainThrottleTime() { long remainTime = REQUEST_THROTTLE_TIME_MS - (System.currentTimeMillis() - getLastOperationTimeMillis()); - Log.d(LOG_TAG, "getRemainThrottleTime:" + remainTime); + if (remainTime < 0) { - return 0; + remainTime = 0L; } + Log.d(LOG_TAG, "getRemainThrottleTime:" + remainTime); + return remainTime; } @@ -787,8 +912,8 @@ public class ImsEnablementTracker { try { synchronized (mLock) { if (isServiceControllerAvailable()) { - Log.d(LOG_TAG, "[" + slotId + "][" + subId + "]sendDisableIms," - + "componentName[" + mComponentName + "]"); + Log.d(LOG_TAG, "[" + slotId + "][" + subId + "]sendDisableIms" + + " componentName[" + mComponentName + "]"); mIImsServiceController.disableIms(slotId, subId); mLastImsOperationTimeMs = System.currentTimeMillis(); } @@ -797,4 +922,18 @@ public class ImsEnablementTracker { Log.w(LOG_TAG, "Couldn't disable IMS: " + e.getMessage()); } } + + private void sendResetIms(int slotId, int subId) { + try { + synchronized (mLock) { + if (isServiceControllerAvailable()) { + Log.d(LOG_TAG, "[" + slotId + "][" + subId + "]sendResetIms"); + mIImsServiceController.resetIms(slotId, subId); + mLastImsOperationTimeMs = System.currentTimeMillis(); + } + } + } catch (RemoteException e) { + Log.w(LOG_TAG, "Couldn't reset IMS: " + e.getMessage()); + } + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java index b3b9052281..c6f45d9387 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsEnablementTrackerTest.java @@ -16,6 +16,10 @@ package com.android.internal.telephony.ims; +import static com.android.internal.telephony.ims.ImsEnablementTracker.COMMAND_DISABLE_MSG; +import static com.android.internal.telephony.ims.ImsEnablementTracker.COMMAND_ENABLE_MSG; +import static com.android.internal.telephony.ims.ImsEnablementTracker.COMMAND_RESETTING_DONE; + import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; @@ -45,12 +49,19 @@ import org.mockito.Mock; @RunWith(AndroidJUnit4.class) public class ImsEnablementTrackerTest extends ImsTestBase { + // default timeout values(millisecond) for handler working + private static final int DEFAULT_TIMEOUT = 100; + + // default delay values(millisecond) for handler working + private static final int DEFAULT_DELAY = 150; + private static final int SLOT_1 = 0; private static final int SUB_1 = 11; private static final int SLOT_2 = 1; private static final int SUB_2 = 22; - private static final long TEST_REQUEST_THROTTLE_TIME_MS = 1000L; + private static final long TEST_REQUEST_THROTTLE_TIME_MS = 3000L; + // Mocked classes @Mock IImsServiceController mMockServiceControllerBinder; @@ -58,20 +69,20 @@ public class ImsEnablementTrackerTest extends ImsTestBase { private TestableImsEnablementTracker mTracker; private Handler mHandler; + private static long sLastImsOperationTimeMs = 0L; + private static class TestableImsEnablementTracker extends ImsEnablementTracker { - private long mLastImsOperationTimeMs = 0L; + private ImsEnablementTrackerTest mOwner; + TestableImsEnablementTracker(Looper looper, IImsServiceController controller, int state, - int numSlots) { + int numSlots, ImsEnablementTrackerTest owner) { super(looper, controller, state, numSlots); + mOwner = owner; } @Override protected long getLastOperationTimeMillis() { - return mLastImsOperationTimeMs; - } - - private void setLastOperationTimeMillis(long timeMills) { - mLastImsOperationTimeMs = timeMills; + return ImsEnablementTrackerTest.sLastImsOperationTimeMs; } } @@ -86,6 +97,7 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void tearDown() throws Exception { // Make sure the handler is empty before finishing the test. waitForHandlerAction(mHandler, TEST_REQUEST_THROTTLE_TIME_MS); + mTracker = null; super.tearDown(); } @@ -95,14 +107,14 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandInDefaultState() throws RemoteException { // Verify that when the enable command is received in the Default state and enableIms // is called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT, 1, 0); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @@ -112,14 +124,14 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInDefaultState() throws RemoteException { // Verify that when the disable command is received in the Default state and disableIms // is called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT, 1, 0); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @@ -128,31 +140,34 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @Test public void testResetCommandInDefaultState() throws RemoteException { // Verify that when reset command is received in the Default state, it should be ignored. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT, 1, 0); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.resetIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); - verifyZeroInteractions(mMockServiceControllerBinder); - assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DEFAULT)); + waitForHandler(mHandler); + + verify(mMockServiceControllerBinder).resetIms(eq(SLOT_1), eq(SUB_1)); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @Test public void testEnableCommandInEnabledState() throws RemoteException { // Verify that received the enable command is not handle in the Enabled state, - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED, 1, 0); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), - mTracker.getRemainThrottleTime() + 100); + waitForHandler(mHandler); + verify(mMockServiceControllerBinder, never()).enableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @@ -162,14 +177,14 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInEnabledState() throws RemoteException { // Verify that when the disable command is received in the Enabled state and disableIms // is called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED, 1, 0); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @@ -179,20 +194,20 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testResetCommandInEnabledState() throws RemoteException { // Verify that when the reset command is received in the Enabled state and disableIms // and enableIms are called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED, 1, 0); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.resetIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); - verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); - // The disableIms was called. So set the last operation time to current. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + waitForHandler(mHandler); + verify(mMockServiceControllerBinder).resetIms(eq(SLOT_1), eq(SUB_1)); + waitForHandlerActionDelayed(mHandler, TEST_REQUEST_THROTTLE_TIME_MS, - TEST_REQUEST_THROTTLE_TIME_MS + 100); - verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); + TEST_REQUEST_THROTTLE_TIME_MS + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @@ -200,14 +215,15 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @Test public void testDisableCommandInDisabledState() throws RemoteException { // Verify that when disable command is received in the Disabled state, it should be ignored. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); + verifyZeroInteractions(mMockServiceControllerBinder); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @@ -217,14 +233,14 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandInDisabledState() throws RemoteException { // Verify that when the enable command is received in the Disabled state and enableIms // is called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED, 1, 0); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @@ -234,18 +250,16 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandWithoutTimeoutInDisableState() throws RemoteException { // Verify that when the enable command is received in the Disabled state. After throttle // time expired, the enableIms is called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); - // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); - // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + waitForHandler(mHandler); mTracker.enableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), - mTracker.getRemainThrottleTime() + 100); + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @@ -254,32 +268,37 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @Test public void testResetCommandInDisabledState() throws RemoteException { // Verify that the reset command is received in the Disabled state and it`s not handled. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED, 1, 0); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.resetIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); - verifyZeroInteractions(mMockServiceControllerBinder); - assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); + waitForHandler(mHandler); + verify(mMockServiceControllerBinder).resetIms(eq(SLOT_1), eq(SUB_1)); + + // The disableIms was called. So set the last operation time to current. + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @Test public void testEnableCommandInDisablingState() throws RemoteException { // Verify that when enable command is received in the Disabling state, it should be ignored. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLING); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLING, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); - // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); + verifyZeroInteractions(mMockServiceControllerBinder); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @@ -289,14 +308,13 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisablingMessageInDisablingState() throws RemoteException { // Verify that when the internal disable message is received in the Disabling state and // disableIms is called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLING); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLING, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); - // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mTracker.startStateMachineAsConnected(SLOT_1); waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), - mTracker.getRemainThrottleTime() + 100); + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + verify(mMockServiceControllerBinder).disableIms(anyInt(), anyInt()); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @@ -306,23 +324,24 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testResetCommandInDisablingState() throws RemoteException { // Verify when the reset command is received in the Disabling state the disableIms and // enableIms are called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLING); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLING, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); - // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.resetIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), - mTracker.getRemainThrottleTime() + 100); - verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder).resetIms(eq(SLOT_1), eq(SUB_1)); + // The disableIms was called. So set the last operation time to current. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), - mTracker.getRemainThrottleTime() + 100); - verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @@ -331,11 +350,12 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnablingMessageInEnablingState() throws RemoteException { // Verify that when the internal enable message is received in the Enabling state and // enableIms is called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLING); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLING, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); - waitForHandlerActionDelayed(mHandler, 100, 150); verify(mMockServiceControllerBinder).enableIms(anyInt(), anyInt()); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @@ -345,16 +365,15 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInEnablingState() throws RemoteException { // Verify that when the disable command is received in the Enabling state and // clear pending message and disableIms is not called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLING); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLING, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); - // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @@ -363,18 +382,25 @@ public class ImsEnablementTrackerTest extends ImsTestBase { @Test public void testResetCommandWithEnablingState() throws RemoteException { // Verify that when reset command is received in the Enabling state, it should be ignored. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLING); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLING, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); - // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.resetIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); - verifyZeroInteractions(mMockServiceControllerBinder); - assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLING)); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder).resetIms(eq(SLOT_1), eq(SUB_1)); + + // The disableIms was called. So set the last operation time to current. + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @SmallTest @@ -382,16 +408,15 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandInResettingState() throws RemoteException { // Verify that when the enable command is received in the Resetting state and // enableIms is not called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); - // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); + verifyZeroInteractions(mMockServiceControllerBinder); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_RESETTING)); } @@ -401,19 +426,17 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testDisableCommandInResettingState() throws RemoteException { // Verify that when the disable command is received in the Resetting state and // disableIms is called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); - // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); - mTracker.startStateMachineAsConnected(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), - mTracker.getRemainThrottleTime() + 100); - verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); - assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); + waitForHandler(mHandler); + + verifyZeroInteractions(mMockServiceControllerBinder); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_RESETTING)); } @SmallTest @@ -421,84 +444,203 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testResettingMessageInResettingState() throws RemoteException { // Verify that when the internal reset message is received in the Resetting state and // disableIms and enableIms are called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); - // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); - verify(mMockServiceControllerBinder).disableIms(anyInt(), anyInt()); + // Wait for the throttle time. + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder).resetIms(anyInt(), anyInt()); + // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), - mTracker.getRemainThrottleTime() + 100); - verify(mMockServiceControllerBinder).enableIms(anyInt(), anyInt()); + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), anyInt()); + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), anyInt()); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testDisableEnableMessageInResettingState() throws RemoteException { + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING, 1, + System.currentTimeMillis()); + mHandler = mTracker.getHandler(SLOT_1); + // Wait for a while for the state machine to be ready. + waitForHandler(mHandler); + + // Simulation. + // In Resetting state, disableIms() called before doing resetIms(). + // After doing resetIms(), during the throttle time(before doing disableIms()), + // enableIms() called. Finally skip disableIms() and do enableIms(). + mHandler.removeMessages(COMMAND_RESETTING_DONE); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_DISABLE_MSG, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_RESETTING_DONE, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_ENABLE_MSG, SLOT_1, SUB_1)); + + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).resetIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), anyInt()); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } + @SmallTest + @Test + public void testEnableDisableMessageInResettingState() throws RemoteException { + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING, 1, + System.currentTimeMillis()); + mHandler = mTracker.getHandler(SLOT_1); + // Wait for a while for the state machine to be ready. + waitForHandler(mHandler); + + // Simulation. + // In Resetting state, enableIms() called before doing resetIms(). + // After doing resetIms(), during the throttle time(before doing enableIms()), + // disableIms() called. Finally skip enableIms() and do disableIms(). + mHandler.removeMessages(COMMAND_RESETTING_DONE); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_ENABLE_MSG, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_RESETTING_DONE, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_DISABLE_MSG, SLOT_1, SUB_1)); + + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).resetIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, times(1)).disableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); + } + + @SmallTest + @Test + public void testRepeatEnableMessageInResettingState() throws RemoteException { + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING, 1, + System.currentTimeMillis()); + mHandler = mTracker.getHandler(SLOT_1); + // Wait for a while for the state machine to be ready. + waitForHandler(mHandler); + + // Simulation. + // In Resetting state, enableIms(), disableIms() are called repeatedly. + // After doing resetIms(), latest enableIms() should perform. + mHandler.removeMessages(COMMAND_RESETTING_DONE); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_RESETTING_DONE, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_DISABLE_MSG, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_ENABLE_MSG, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_DISABLE_MSG, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_ENABLE_MSG, SLOT_1, SUB_1)); + + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).resetIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testRepeatDisableMessageInResettingState() throws RemoteException { + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_RESETTING, 1, + System.currentTimeMillis()); + mHandler = mTracker.getHandler(SLOT_1); + // Wait for a while for the state machine to be ready. + waitForHandler(mHandler); + + // Simulation. + // In Resetting state, enableIms(), disableIms() are called repeatedly. + // After doing resetIms(), latest disableIms() should perform. + mHandler.removeMessages(COMMAND_RESETTING_DONE); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_RESETTING_DONE, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_ENABLE_MSG, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_DISABLE_MSG, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_ENABLE_MSG, SLOT_1, SUB_1)); + mHandler.sendMessage(mHandler.obtainMessage(COMMAND_DISABLE_MSG, SLOT_1, SUB_1)); + + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).resetIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, times(1)).disableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).enableIms(eq(SLOT_1), eq(SUB_1)); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); + } + @SmallTest @Test public void testConsecutiveCommandInEnabledState() throws RemoteException { - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + sLastImsOperationTimeMs = System.currentTimeMillis(); mTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLING)); mTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); mTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLING)); + mTracker.disableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), - mTracker.getRemainThrottleTime() + 100); + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + verify(mMockServiceControllerBinder, times(1)).disableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).resetIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); } @SmallTest @Test public void testConsecutiveCommandInDisabledState() throws RemoteException { - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DISABLED, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); // Set the last operation time to current to verify the message with delay. - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + sLastImsOperationTimeMs = System.currentTimeMillis(); mTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLING)); mTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); mTracker.resetIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); - assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); + waitForHandler(mHandler); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_RESETTING)); mTracker.disableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); mTracker.enableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), - mTracker.getRemainThrottleTime() + 100); + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @@ -508,18 +650,18 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testSubIdChangeToInvalidAndEnableCommand() throws RemoteException { // Verify that when the enable command is received in the Default state and enableIms // is called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_ENABLED, 1, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); mTracker.subIdChangedToInvalid(SLOT_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DEFAULT)); mTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } @@ -529,53 +671,142 @@ public class ImsEnablementTrackerTest extends ImsTestBase { public void testEnableCommandWithDifferentSlotId() throws RemoteException { // Verify that when the enable command is received in the Default state and enableIms // is called. - mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT, 2); - mTracker.startStateMachineAsConnected(SLOT_1); + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_DEFAULT, 2, + System.currentTimeMillis()); mHandler = mTracker.getHandler(SLOT_1); - mTracker.startStateMachineAsConnected(SLOT_2); Handler handlerForSlot2 = mTracker.getHandler(SLOT_2); // Wait for a while for the state machine to be ready. - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); + waitForHandler(handlerForSlot2); mTracker.enableIms(SLOT_1, SUB_1); - waitForHandlerActionDelayed(mHandler, 100, 150); + waitForHandler(mHandler); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); assertTrue(mTracker.isState(SLOT_2, mTracker.STATE_IMS_DEFAULT)); mTracker.enableIms(SLOT_2, SUB_2); - waitForHandlerActionDelayed(handlerForSlot2, 100, 150); + waitForHandler(handlerForSlot2); + verify(mMockServiceControllerBinder).enableIms(eq(SLOT_2), eq(SUB_2)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); assertTrue(mTracker.isState(SLOT_2, mTracker.STATE_IMS_ENABLED)); mTracker.setNumOfSlots(1); - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + sLastImsOperationTimeMs = System.currentTimeMillis(); mTracker.disableIms(SLOT_1, SUB_1); waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), - mTracker.getRemainThrottleTime() + 100); + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_1), eq(SUB_1)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); mTracker.setNumOfSlots(2); - mTracker.setLastOperationTimeMillis(System.currentTimeMillis()); + sLastImsOperationTimeMs = System.currentTimeMillis(); mTracker.disableIms(SLOT_2, SUB_2); - waitForHandlerActionDelayed(handlerForSlot2, 100, 150); + waitForHandler(handlerForSlot2); + verify(mMockServiceControllerBinder).disableIms(eq(SLOT_2), eq(SUB_2)); assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); assertTrue(mTracker.isState(SLOT_2, mTracker.STATE_IMS_DISABLED)); } - private TestableImsEnablementTracker createTracker(IImsServiceController binder, int state) { - TestableImsEnablementTracker tracker = new TestableImsEnablementTracker( - Looper.getMainLooper(), binder, state, 1); - return tracker; + @SmallTest + @Test + public void testEnableCommandInPostResettingState() throws RemoteException { + // Verify that when the enable/disable commands are received in the PostResetting state + // and final enableIms is called. + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_POSTRESETTING, 1, + System.currentTimeMillis()); + mHandler = mTracker.getHandler(SLOT_1); + // Wait for a while for the state machine to be ready. + waitForHandler(mHandler); + + // to confirm the slotId, subId for COMMAND_POST_RESETTING_DONE + mHandler.removeMessages(mTracker.COMMAND_POST_RESETTING_DONE); + mHandler.sendMessageDelayed(mHandler.obtainMessage(mTracker.COMMAND_POST_RESETTING_DONE, + SLOT_1, SUB_1), mTracker.getRemainThrottleTime()); + + mTracker.enableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), anyInt()); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); + } + + @SmallTest + @Test + public void testDisableCommandInPostResettingState() throws RemoteException { + // Verify that when the enable/disable commands are received in the PostResetting state + // and final disableIms is called. + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_POSTRESETTING, 1, + System.currentTimeMillis()); + mHandler = mTracker.getHandler(SLOT_1); + // Wait for a while for the state machine to be ready. + waitForHandler(mHandler); + + // to confirm the slotId, subId for COMMAND_POST_RESETTING_DONE + mHandler.removeMessages(mTracker.COMMAND_POST_RESETTING_DONE); + mHandler.sendMessageDelayed(mHandler.obtainMessage(mTracker.COMMAND_POST_RESETTING_DONE, + SLOT_1, SUB_1), mTracker.getRemainThrottleTime()); + + mTracker.disableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); + mTracker.disableIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).disableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).enableIms(eq(SLOT_1), anyInt()); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_DISABLED)); + } + + @SmallTest + @Test + public void testResetCommandInPostResettingState() throws RemoteException { + // Verify that when the enable/disable/reset commands are received in the PostResetting + // state and final enableIms is called without calling resetIms again. + mTracker = createTracker(mMockServiceControllerBinder, mTracker.STATE_IMS_POSTRESETTING, 1, + System.currentTimeMillis()); + mHandler = mTracker.getHandler(SLOT_1); + // Wait for a while for the state machine to be ready. + waitForHandler(mHandler); + + // to confirm the slotId, subId for COMMAND_POST_RESETTING_DONE + mHandler.removeMessages(mTracker.COMMAND_POST_RESETTING_DONE); + mHandler.sendMessageDelayed(mHandler.obtainMessage(mTracker.COMMAND_POST_RESETTING_DONE, + SLOT_1, SUB_1), mTracker.getRemainThrottleTime()); + + mTracker.disableIms(SLOT_1, SUB_1); + mTracker.enableIms(SLOT_1, SUB_1); + mTracker.resetIms(SLOT_1, SUB_1); + waitForHandlerActionDelayed(mHandler, mTracker.getRemainThrottleTime(), + mTracker.getRemainThrottleTime() + DEFAULT_DELAY); + + verify(mMockServiceControllerBinder, times(1)).enableIms(eq(SLOT_1), eq(SUB_1)); + verify(mMockServiceControllerBinder, never()).disableIms(eq(SLOT_1), anyInt()); + verify(mMockServiceControllerBinder, never()).resetIms(eq(SLOT_1), anyInt()); + assertTrue(mTracker.isState(SLOT_1, mTracker.STATE_IMS_ENABLED)); } private TestableImsEnablementTracker createTracker(IImsServiceController binder, int state, - int numSlots) { + int numSlots, long initLastOperationTime) { + sLastImsOperationTimeMs = initLastOperationTime; TestableImsEnablementTracker tracker = new TestableImsEnablementTracker( - Looper.getMainLooper(), binder, state, numSlots); + Looper.getMainLooper(), binder, state, numSlots, this); return tracker; } + + private void waitForHandler(Handler h) { + waitForHandlerActionDelayed(h, DEFAULT_TIMEOUT, DEFAULT_DELAY); + } } -- GitLab From 3273c57779707c0fd18a1bb3b6124f0738f61b22 Mon Sep 17 00:00:00 2001 From: Manish Dungriyal Date: Wed, 15 Feb 2023 12:41:43 +0000 Subject: [PATCH 543/656] Log atoms for emergency Collectig metrics for consolidated emergency numbers updated in framework and dialed emergency number, Bug: 233263956 Test: m statsd_testdrive Change-Id: I5f4c53cbdb4796f57d75b11855093a9d9b384022 Merged-In: I5f4c53cbdb4796f57d75b11855093a9d9b384022 (cherry picked from commit 8de15f93556e7b78262de67262597848d1818d26) --- proto/src/persist_atoms.proto | 41 +++++ .../emergency/EmergencyNumberTracker.java | 33 +++- .../metrics/EmergencyNumberStats.java | 173 ++++++++++++++++++ .../telephony/metrics/MetricsCollector.java | 38 +++- 4 files changed, 279 insertions(+), 6 deletions(-) create mode 100644 src/java/com/android/internal/telephony/metrics/EmergencyNumberStats.java diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index 9d83c25cf1..aa784dd5c1 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -225,6 +225,12 @@ message PersistAtoms { /* Timestamp of last satellite_sos_message_recommender pull. */ optional int64 satellite_sos_message_recommender_pull_timestamp_millis = 69; + + /* Consolidated emergency numbers list information. */ + repeated EmergencyNumbersInfo emergency_numbers_info = 56; + + /* Timestamp of last emergency number pull. */ + optional int64 emergency_number_pull_timestamp_millis = 57; } // The canonical versions of the following enums live in: @@ -628,3 +634,38 @@ message SatelliteSosMessageRecommender { optional int32 cellular_service_state = 4; optional int32 count = 5; } + +message EmergencyNumbersInfo { + enum ServiceCategory { + EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED = 0; + EMERGENCY_SERVICE_CATEGORY_POLICE = 1; + EMERGENCY_SERVICE_CATEGORY_AMBULANCE = 2; + EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE = 3; + EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD = 4; + EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE = 5; + EMERGENCY_SERVICE_CATEGORY_MIEC = 6; + EMERGENCY_SERVICE_CATEGORY_AIEC = 7; + } + enum Source { + EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING = 0; + EMERGENCY_NUMBER_SOURCE_SIM = 1; + EMERGENCY_NUMBER_SOURCE_DATABASE = 2; + EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 3; + EMERGENCY_NUMBER_SOURCE_DEFAULT = 4; + } + enum CallRoute { + EMERGENCY_CALL_ROUTE_UNKNOWN = 0; + EMERGENCY_CALL_ROUTE_EMERGENCY = 1; + EMERGENCY_CALL_ROUTE_NORMAL = 2; + } + optional bool is_db_version_ignored = 1; + optional int32 asset_version = 2; + optional int32 ota_version = 3; + optional string number = 4; + optional string country_iso = 5; + optional string mnc = 6; + optional CallRoute route = 7; + repeated string urns = 8; + repeated ServiceCategory service_categories = 9; + repeated Source sources = 10; +} diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 715fc098e0..831278e4d4 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -49,7 +49,9 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.metrics.EmergencyNumberStats; import com.android.internal.telephony.metrics.TelephonyMetrics; +import com.android.internal.telephony.nano.PersistAtomsProto; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.IndentingPrintWriter; import com.android.phone.ecc.nano.ProtobufEccData; @@ -105,6 +107,7 @@ public class EmergencyNumberTracker extends Handler { private String mCountryIso; private String mLastKnownEmergencyCountryIso = ""; private int mCurrentDatabaseVersion = INVALID_DATABASE_VERSION; + private int mCurrentOtaDatabaseVersion = INVALID_DATABASE_VERSION; private Resources mResources = null; /** * Used for storing all specific mnc's along with the list of emergency numbers @@ -563,20 +566,20 @@ public class EmergencyNumberTracker extends Handler { } // Cache OTA emergency number database - int otaDatabaseVersion = cacheOtaEmergencyNumberDatabase(); + mCurrentOtaDatabaseVersion = cacheOtaEmergencyNumberDatabase(); // Use a valid database that has higher version. - if (otaDatabaseVersion == INVALID_DATABASE_VERSION + if (mCurrentOtaDatabaseVersion == INVALID_DATABASE_VERSION && assetsDatabaseVersion == INVALID_DATABASE_VERSION) { loge("No database available. Phone Id: " + mPhone.getPhoneId()); - } else if (assetsDatabaseVersion > otaDatabaseVersion) { + } else if (assetsDatabaseVersion > mCurrentOtaDatabaseVersion) { logd("Using Asset Emergency database. Version: " + assetsDatabaseVersion); mCurrentDatabaseVersion = assetsDatabaseVersion; mEmergencyNumberListFromDatabase = updatedAssetEmergencyNumberList; mNormalRoutedNumbers.clear(); mNormalRoutedNumbers = assetNormalRoutedNumbers; } else { - logd("Using Ota Emergency database. Version: " + otaDatabaseVersion); + logd("Using Ota Emergency database. Version: " + mCurrentOtaDatabaseVersion); } } @@ -716,7 +719,8 @@ public class EmergencyNumberTracker extends Handler { private void updateOtaEmergencyNumberListDatabaseAndNotify() { logd("updateOtaEmergencyNumberListDatabaseAndNotify():" + " receiving Emegency Number database OTA update"); - if (cacheOtaEmergencyNumberDatabase() != INVALID_DATABASE_VERSION) { + mCurrentOtaDatabaseVersion = cacheOtaEmergencyNumberDatabase(); + if (mCurrentOtaDatabaseVersion != INVALID_DATABASE_VERSION) { writeUpdatedEmergencyNumberListMetrics(mEmergencyNumberListFromDatabase); if (!DBG) { mEmergencyNumberListDatabaseLocalLog.log( @@ -1000,6 +1004,10 @@ public class EmergencyNumberTracker extends Handler { return mCurrentDatabaseVersion; } + public int getEmergencyNumberOtaDbVersion() { + return mCurrentOtaDatabaseVersion; + } + private synchronized void updateEmergencyCountryIso(String countryIso) { mCountryIso = countryIso; if (!TextUtils.isEmpty(mCountryIso)) { @@ -1290,6 +1298,21 @@ public class EmergencyNumberTracker extends Handler { return false; } + /** + * Captures the consolidated emergency numbers list and returns the array of + * {@link PersistAtomsProto.EmergencyNumber}. + */ + public PersistAtomsProto.EmergencyNumbersInfo[] getEmergencyNumbersProtoArray() { + int otaVersion = Math.max(0, getEmergencyNumberOtaDbVersion()); + int assetVersion = Math.max(0, getEmergencyNumberDbVersion()); + boolean isDbRoutingIgnored = shouldEmergencyNumberRoutingFromDbBeIgnored(); + List emergencyNumberList = getEmergencyNumberList(); + logd("log emergency number list=" + emergencyNumberList + " for otaVersion=" + otaVersion + + ", assetVersion=" + assetVersion + ", isDbRoutingIgnored=" + isDbRoutingIgnored); + return EmergencyNumberStats.getInstance().convertEmergencyNumbersListToProto( + emergencyNumberList, assetVersion, otaVersion, isDbRoutingIgnored); + } + /** * Dump Emergency Number List info in the tracking * diff --git a/src/java/com/android/internal/telephony/metrics/EmergencyNumberStats.java b/src/java/com/android/internal/telephony/metrics/EmergencyNumberStats.java new file mode 100644 index 0000000000..2867b46206 --- /dev/null +++ b/src/java/com/android/internal/telephony/metrics/EmergencyNumberStats.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2023 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 com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_EMERGENCY; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_NORMAL; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_UNKNOWN; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_AIEC; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_AMBULANCE; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MIEC; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_POLICE; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_DATABASE; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_DEFAULT; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_SIM; + +import android.telephony.emergency.EmergencyNumber; +import android.util.SparseIntArray; + +import com.android.internal.telephony.nano.PersistAtomsProto; + +import java.util.ArrayList; +import java.util.List; + +/** + * EmergencyStats logs the atoms for consolidated emergency number list in framework. It also logs + * the details of a dialed emergency number. To avoid repeated information this class stores the + * emergency numbers list in map and verifies the information for duplicacy before logging it. Note: + * This locally stored information will erase on process restart scenarios (like reboot, crash, + * etc.). + */ +public class EmergencyNumberStats { + + private static final String TAG = EmergencyNumberStats.class.getSimpleName(); + private static final SparseIntArray sRoutesMap; + private static final SparseIntArray sServiceCategoriesMap; + private static final SparseIntArray sSourcesMap; + private static EmergencyNumberStats sInstance; + + static { + sRoutesMap = new SparseIntArray() { + { + put(EmergencyNumber.EMERGENCY_CALL_ROUTING_EMERGENCY, + EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_EMERGENCY); + put(EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL, + EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_NORMAL); + put(EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN, + EMERGENCY_NUMBERS_INFO__ROUTE__EMERGENCY_CALL_ROUTE_UNKNOWN); + } + }; + + sServiceCategoriesMap = new SparseIntArray() { + { + put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED, + EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED); + put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, + EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_POLICE); + put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AMBULANCE, + EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_AMBULANCE); + put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE, + EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE); + put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD, + EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MARINE_GUARD); + put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE, + EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MOUNTAIN_RESCUE); + put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_MIEC, + EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_MIEC); + put(EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_AIEC, + EMERGENCY_NUMBERS_INFO__SERVICE_CATEGORIES__EMERGENCY_SERVICE_CATEGORY_AIEC); + } + }; + + sSourcesMap = new SparseIntArray() { + { + put(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, + EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING); + put(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_SIM, + EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_SIM); + put(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE, + EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_DATABASE); + put(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG, + EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG); + put(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DEFAULT, + EMERGENCY_NUMBERS_INFO__SOURCES__EMERGENCY_NUMBER_SOURCE_DEFAULT); + } + }; + } + + private EmergencyNumberStats() { + } + + /** Static method to provide singleton instance for EmergencyNumberStats. */ + public static EmergencyNumberStats getInstance() { + if (sInstance == null) { + sInstance = new EmergencyNumberStats(); + } + return sInstance; + } + + /** + * It converts the {@link android.telephony.emergency.EmergencyNumber} to + * {@link PersistAtomsProto.EmergencyNumber} for + * logging the EmergencyNumber atoms with pulled event. + * + * @param emergencyNumberList android.telephony.EmergencyNumber list + * @param assetVersion assert version + * @param otaVersion ota version + * @param isDbRoutingIgnored flag that defines if routing is ignored through database. + */ + public PersistAtomsProto.EmergencyNumbersInfo[] convertEmergencyNumbersListToProto( + List emergencyNumberList, int assetVersion, int otaVersion, + boolean isDbRoutingIgnored) { + List numberProtoList = new ArrayList<>(); + for (EmergencyNumber number : emergencyNumberList) { + numberProtoList.add(convertEmergencyNumberToProto(number, assetVersion, otaVersion, + isDbRoutingIgnored)); + } + return numberProtoList.toArray(new PersistAtomsProto.EmergencyNumbersInfo[0]); + } + + private PersistAtomsProto.EmergencyNumbersInfo convertEmergencyNumberToProto( + EmergencyNumber number, int assetVer, int otaVer, boolean isDbRoutingIgnored) { + String dialNumber = number.getNumber(); + PersistAtomsProto.EmergencyNumbersInfo emergencyNumber = + new PersistAtomsProto.EmergencyNumbersInfo(); + emergencyNumber.isDbVersionIgnored = isDbRoutingIgnored; + emergencyNumber.assetVersion = assetVer; + emergencyNumber.otaVersion = otaVer; + emergencyNumber.number = dialNumber; + emergencyNumber.countryIso = number.getCountryIso(); + emergencyNumber.mnc = number.getMnc(); + emergencyNumber.route = sRoutesMap.get(number.getEmergencyCallRouting()); + emergencyNumber.urns = number.getEmergencyUrns().toArray(new String[0]); + emergencyNumber.serviceCategories = getMappedServiceCategories( + number.getEmergencyServiceCategories()); + emergencyNumber.sources = getMappedSources(number.getEmergencyNumberSources()); + return emergencyNumber; + } + + private int[] getMappedServiceCategories(List serviceCategories) { + if (serviceCategories == null || serviceCategories.isEmpty()) { + return null; + } + return serviceCategories.stream().map(sServiceCategoriesMap::get).mapToInt( + Integer::intValue).toArray(); + } + + private int[] getMappedSources(List sources) { + if (sources == null || sources.isEmpty()) { + return null; + } + return sources.stream().map(sSourcesMap::get).mapToInt(Integer::intValue).toArray(); + } +} diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index f5cd1e26d9..0e68224335 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -21,6 +21,7 @@ import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_DATA_SER 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.DEVICE_TELEPHONY_PROPERTIES; +import static com.android.internal.telephony.TelephonyStatsLog.EMERGENCY_NUMBERS_INFO; import static com.android.internal.telephony.TelephonyStatsLog.GBA_EVENT; import static com.android.internal.telephony.TelephonyStatsLog.IMS_DEDICATED_BEARER_EVENT; import static com.android.internal.telephony.TelephonyStatsLog.IMS_DEDICATED_BEARER_LISTENER_EVENT; @@ -63,10 +64,12 @@ 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.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsPhone; 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.EmergencyNumbersInfo; import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent; import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent; import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerListenerEvent; @@ -154,7 +157,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { /** Allows dependency injection. Used during unit tests. */ @VisibleForTesting public MetricsCollector(Context context, - PersistAtomsStorage storage) { + PersistAtomsStorage storage) { mStorage = storage; mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER); if (mStatsManager != null) { @@ -194,6 +197,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { registerAtom(SATELLITE_OUTGOING_DATAGRAM); registerAtom(SATELLITE_PROVISION); registerAtom(SATELLITE_SOS_MESSAGE_RECOMMENDER); + registerAtom(EMERGENCY_NUMBERS_INFO); Rlog.d(TAG, "registered"); } else { Rlog.e(TAG, "could not get StatsManager, atoms not registered"); @@ -282,6 +286,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return pullSatelliteProvision(data); case SATELLITE_SOS_MESSAGE_RECOMMENDER: return pullSatelliteSosMessageRecommender(data); + case EMERGENCY_NUMBERS_INFO: + return pullEmergencyNumbersInfo(data); default: Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag)); return StatsManager.PULL_SKIP; @@ -863,6 +869,21 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } } + private int pullEmergencyNumbersInfo(List data) { + boolean isDataLogged = false; + for (Phone phone : getPhonesIfAny()) { + if (phone != null) { + EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker(); + if (tracker != null) { + EmergencyNumbersInfo[] numList = tracker.getEmergencyNumbersProtoArray(); + Arrays.stream(numList).forEach(number -> data.add(buildStatsEvent(number))); + isDataLogged = true; + } + } + } + return isDataLogged ? StatsManager.PULL_SUCCESS : StatsManager.PULL_SKIP; + } + /** Registers a pulled atom ID {@code atomId}. */ private void registerAtom(int atomId) { mStatsManager.setPullAtomCallback(atomId, /* metadata= */ null, @@ -1278,6 +1299,21 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { stats.count); } + private static StatsEvent buildStatsEvent(EmergencyNumbersInfo emergencyNumber) { + return TelephonyStatsLog.buildStatsEvent( + EMERGENCY_NUMBERS_INFO, + emergencyNumber.isDbVersionIgnored, + emergencyNumber.assetVersion, + emergencyNumber.otaVersion, + emergencyNumber.number, + emergencyNumber.countryIso, + emergencyNumber.mnc, + emergencyNumber.route, + emergencyNumber.urns, + emergencyNumber.serviceCategories, + emergencyNumber.sources); + } + /** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */ private static Phone[] getPhonesIfAny() { try { -- GitLab From f98119103e9404396d1c0f1a7d7b6d5dd8fec18a Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Mon, 27 Feb 2023 22:27:25 +0000 Subject: [PATCH 544/656] Skip subscription-user association check for emergency sms. Bug: 270340388 Test: Manually sending/receiving SMS/MMS, atest com.android.providers.telephony.SmsProviderTest, atest com.android.providers.telephony.MmsProviderTest, atest com.android.providers.telephony.ProviderUtilTest, atest CtsTelephonyProviderTestCases, atest CtsTelephonyTestCases Change-Id: Ic6cfb76f5ef474576ad12186c4ce0dcfe7ab2983 --- .../android/internal/telephony/SmsController.java | 12 ++++++------ .../subscription/SubscriptionManagerService.java | 1 + .../internal/telephony/TelephonyPermissionsTest.java | 10 ++++++++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 4915e25871..071dbda9b6 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -163,7 +163,7 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, - Binder.getCallingUserHandle())) { + Binder.getCallingUserHandle(), destAddr)) { TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, Binder.getCallingUid(), callingPackage); sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); @@ -261,7 +261,7 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, - Binder.getCallingUserHandle())) { + Binder.getCallingUserHandle(), destAddr)) { TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, Binder.getCallingUid(), callingPackage); sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); @@ -345,7 +345,7 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, - Binder.getCallingUserHandle())) { + Binder.getCallingUserHandle(), destAddr)) { TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, Binder.getCallingUid(), callingPackage); sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); @@ -384,7 +384,7 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, - Binder.getCallingUserHandle())) { + Binder.getCallingUserHandle(), destAddr)) { TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, Binder.getCallingUid(), callingPackage); sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_USER_NOT_ALLOWED); @@ -421,7 +421,7 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, - Binder.getCallingUserHandle())) { + Binder.getCallingUserHandle(), destAddr)) { TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, Binder.getCallingUid(), callingPackage); sendErrorInPendingIntents(sentIntents, SmsManager.RESULT_USER_NOT_ALLOWED); @@ -928,7 +928,7 @@ public class SmsController extends ISmsImplBase { // Check if user is associated with the subscription if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, - Binder.getCallingUserHandle())) { + Binder.getCallingUserHandle(), number)) { TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, Binder.getCallingUid(), callingPackage); sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_USER_NOT_ALLOWED); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 55727aa373..74e5e799b0 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -3545,6 +3545,7 @@ public class SubscriptionManagerService extends ISub.Stub { } UserHandle userHandle = UserHandle.of(subInfo.getUserId()); + log("getSubscriptionUserHandle subId = " + subId + " userHandle = " + userHandle); if (userHandle.getIdentifier() == UserHandle.USER_NULL) { return null; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java index 0e6e2f7f42..a053c56131 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java @@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -37,6 +38,7 @@ import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.ServiceManager; +import android.os.UserHandle; import android.permission.LegacyPermissionManager; import android.provider.DeviceConfig; import android.provider.Settings; @@ -530,6 +532,14 @@ public class TelephonyPermissionsTest { } } + @Test + public void testCheckSubscriptionAssociatedWithUser_emergencyNumber() { + doReturn(true).when(mTelephonyManagerMock).isEmergencyNumber(anyString()); + + assertTrue(TelephonyPermissions.checkSubscriptionAssociatedWithUser(mMockContext, SUB_ID, + UserHandle.SYSTEM, "911")); + } + // Put mMockTelephony into service cache so that TELEPHONY_SUPPLIER will get it. private void setTelephonyMockAsService() throws Exception { when(mMockTelephonyBinder.queryLocalInterface(anyString())).thenReturn(mMockTelephony); -- GitLab From 07f37619d5909010a0bc1602ed022debd2c9e31a Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 23 Mar 2023 17:59:06 -0700 Subject: [PATCH 545/656] Fixed getAccessibleSubscriptionInfoList returns the non-embedded sub getAccessibleSubscriptionInfoList should only return accessible embedded subscriptions. Fix: 272337651 Test: atest SubscriptionManagerServiceTest Test: Basic phone funcationality tests Change-Id: I9758f8b05f03935e375297cca2874790ae2f2f94 --- .../SubscriptionManagerService.java | 4 ++-- .../SubscriptionManagerServiceTest.java | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 55727aa373..9cd69ef85d 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1905,8 +1905,8 @@ public class SubscriptionManagerService extends ISub.Stub { return mSubscriptionDatabaseManager.getAllSubscriptions().stream() .map(SubscriptionInfoInternal::toSubscriptionInfo) - .filter(subInfo -> mSubscriptionManager - .canManageSubscription(subInfo, callingPackage)) + .filter(subInfo -> subInfo.isEmbedded() + && mSubscriptionManager.canManageSubscription(subInfo, callingPackage)) .sorted(Comparator.comparing(SubscriptionInfo::getSimSlotIndex) .thenComparing(SubscriptionInfo::getSubscriptionId)) .collect(Collectors.toList()); 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 a75f7594b1..51e760a053 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -941,21 +941,33 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testGetAccessibleSubscriptionInfoList() { + doReturn(true).when(mEuiccManager).isEnabled(); + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + + doReturn(true).when(mSubscriptionManager).canManageSubscription( + any(SubscriptionInfo.class), eq(CALLING_PACKAGE)); + // FAKE_SUBSCRIPTION_INFO2 is a not eSIM. So the list should be empty. + assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( + CALLING_PACKAGE)).isEmpty(); + insertSubscription(FAKE_SUBSCRIPTION_INFO1); doReturn(false).when(mEuiccManager).isEnabled(); assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( CALLING_PACKAGE)).isNull(); + doReturn(false).when(mSubscriptionManager).canManageSubscription( + any(SubscriptionInfo.class), eq(CALLING_PACKAGE)); + doReturn(true).when(mEuiccManager).isEnabled(); assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( CALLING_PACKAGE)).isEmpty(); doReturn(true).when(mSubscriptionManager).canManageSubscription( - eq(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo()), eq(CALLING_PACKAGE)); - + any(SubscriptionInfo.class), eq(CALLING_PACKAGE)); assertThat(mSubscriptionManagerServiceUT.getAccessibleSubscriptionInfoList( - CALLING_PACKAGE)).isEqualTo(List.of(FAKE_SUBSCRIPTION_INFO1.toSubscriptionInfo())); + CALLING_PACKAGE)).isEqualTo(List.of(new SubscriptionInfoInternal.Builder( + FAKE_SUBSCRIPTION_INFO1).setId(2).build().toSubscriptionInfo())); } @Test -- GitLab From f4db7d942013e019be681fc7075724f19f8538ee Mon Sep 17 00:00:00 2001 From: Aswin Sankar Date: Thu, 23 Mar 2023 23:24:12 -0700 Subject: [PATCH 546/656] Initialize maxActiveVoiceSubscriptions to maxActiveInternetData MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - maxActiveData defines how many logical modems can have internet PDN connections simultaneously. For L+L DSDS modem it’s 1, and for DSDA modem it’s 2. - Since PhoneCapability.aidl does not have a dedicated field for maxActiveVoiceSubscriptions, this is a reasonable default. Test: Boot up device and confirm PhoneCapability values Fix: 254926322 Change-Id: I21f7aa58a0c97e66365cfb3b84871d28ba85d22c --- src/java/com/android/internal/telephony/RILUtils.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 207668e7f2..6d728f98dc 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -4610,12 +4610,14 @@ public class RILUtils { public static PhoneCapability convertHalPhoneCapability(int[] deviceNrCapabilities, Object o) { int maxActiveVoiceCalls = 0; int maxActiveData = 0; + int maxActiveInternetData = 0; boolean validationBeforeSwitchSupported = false; List logicalModemList = new ArrayList<>(); if (o instanceof android.hardware.radio.config.PhoneCapability) { final android.hardware.radio.config.PhoneCapability phoneCapability = (android.hardware.radio.config.PhoneCapability) o; maxActiveData = phoneCapability.maxActiveData; + maxActiveInternetData = phoneCapability.maxActiveInternetData; validationBeforeSwitchSupported = phoneCapability.isInternetLingeringSupported; for (int modemId : phoneCapability.logicalModemIds) { logicalModemList.add(new ModemInfo(modemId)); @@ -4624,13 +4626,16 @@ public class RILUtils { final android.hardware.radio.config.V1_1.PhoneCapability phoneCapability = (android.hardware.radio.config.V1_1.PhoneCapability) o; maxActiveData = phoneCapability.maxActiveData; + maxActiveInternetData = phoneCapability.maxActiveInternetData; validationBeforeSwitchSupported = phoneCapability.isInternetLingeringSupported; for (android.hardware.radio.config.V1_1.ModemInfo modemInfo : phoneCapability.logicalModemList) { logicalModemList.add(new ModemInfo(modemInfo.modemId)); } } - maxActiveVoiceCalls = maxActiveData; + // maxActiveInternetData defines how many logical modems can have internet PDN connections + // simultaneously. For L+L DSDS modem it’s 1, and for DSDA modem it’s 2. + maxActiveVoiceCalls = maxActiveInternetData; return new PhoneCapability(maxActiveVoiceCalls, maxActiveData, logicalModemList, validationBeforeSwitchSupported, deviceNrCapabilities); } -- GitLab From 1a8a14cd584f286b17763469a6f4b760f64939c4 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Fri, 24 Mar 2023 12:32:28 +0000 Subject: [PATCH 547/656] Remove AnomalyReporter code AnomalyReporter is called if UiccSlotInfo is null when getting slot id using card id. UiccSlotInfo will be set in the array by the number of slots and set the value of UiccSlotInfo in the array when the slot_status_done occur. If that value is read before slot_status_done, the array will not be null but its value may be. In this case, return the slot id as an invalid_slot_index, so we remove the AnomalyReporter we were using. Bug: b/260469451 Test: atest EuiccConnectorTest Change-Id: I726d374e679a77898a86a189c1e223459accc511 --- .../com/android/internal/telephony/euicc/EuiccConnector.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/euicc/EuiccConnector.java b/src/java/com/android/internal/telephony/euicc/EuiccConnector.java index ef19b9ad10..c417a34c54 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccConnector.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccConnector.java @@ -1073,9 +1073,8 @@ public class EuiccConnector extends StateMachine implements ServiceConnection { for (int slotIndex = 0; slotIndex < slotInfos.length; slotIndex++) { // Report Anomaly in case UiccSlotInfo is not. if (slotInfos[slotIndex] == null) { - AnomalyReporter.reportAnomaly( - UUID.fromString("4195b83d-6cee-4999-a02f-d0b9f7079b9d"), - "EuiccConnector: Found UiccSlotInfo Null object."); + Log.i(TAG, "No UiccSlotInfo found for slotIndex: " + slotIndex); + return SubscriptionManager.INVALID_SIM_SLOT_INDEX; } String retrievedCardId = slotInfos[slotIndex] != null ? slotInfos[slotIndex].getCardId() : null; -- GitLab From 8190b3918fa000044969134674c153c2b2cfe18a Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Mon, 6 Mar 2023 13:27:03 +0000 Subject: [PATCH 548/656] add datagram log to satellite metrics currently initil version for testing and get right position to capture Bug: 271819233 Test: build test Change-Id: I03a2be179f2eb306bf8bb454654a7e2883e34867 --- .../satellite/DatagramController.java | 1 + .../satellite/DatagramDispatcher.java | 47 ++++++++++++++++++- .../telephony/satellite/DatagramReceiver.java | 41 +++++++++++++++- 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 56ee8a6588..2fda0221af 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -38,6 +38,7 @@ public class DatagramController { @NonNull private final DatagramDispatcher mDatagramDispatcher; @NonNull private final DatagramReceiver mDatagramReceiver; public static final long MAX_DATAGRAM_ID = (long) Math.pow(2, 16); + public static final int ROUNDING_UNIT = 10; /** Variables used to update onSendDatagramStateChanged(). */ private int mSendSubId; diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index bfe1f0b391..618269c776 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.satellite; +import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -30,6 +32,7 @@ import android.telephony.satellite.SatelliteManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.metrics.SatelliteStats; import java.util.LinkedHashMap; import java.util.Map.Entry; @@ -127,6 +130,7 @@ public class DatagramDispatcher extends Handler { public @NonNull SatelliteDatagram datagram; public boolean needFullScreenPointingUI; public @NonNull Consumer callback; + public long datagramStartTime; SendSatelliteDatagramArgument(int subId, long datagramId, @SatelliteManager.DatagramType int datagramType, @@ -139,6 +143,23 @@ public class DatagramDispatcher extends Handler { this.needFullScreenPointingUI = needFullScreenPointingUI; this.callback = callback; } + + /** returns the size of outgoing SMS, rounded by 10 bytes */ + public int getDatagramRoundedSizeBytes() { + if (datagram.getSatelliteDatagram() != null) { + int sizeBytes = datagram.getSatelliteDatagram().length; + // rounded by ROUNDING_UNIT + return (int) (Math.round((double) sizeBytes / ROUNDING_UNIT) * ROUNDING_UNIT); + } else { + return 0; + } + } + + /** sets the start time at datagram is sent out */ + public void setDatagramStartTime() { + datagramStartTime = + datagramStartTime == 0 ? System.currentTimeMillis() : datagramStartTime; + } } @Override @@ -169,6 +190,9 @@ public class DatagramDispatcher extends Handler { } else { loge("sendSatelliteDatagram: No phone object"); argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + // report phone == null case + reportSendDatagramCompleted(argument, + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); synchronized (mLock) { // Remove current datagram from pending map @@ -193,6 +217,8 @@ public class DatagramDispatcher extends Handler { SendSatelliteDatagramArgument argument = (SendSatelliteDatagramArgument) request.argument; logd("EVENT_SEND_SATELLITE_DATAGRAM_DONE error: " + error); + // log metrics about the outgoing datagram + reportSendDatagramCompleted(argument, error); synchronized (mLock) { mSendingDatagramInProgress = false; @@ -258,8 +284,9 @@ public class DatagramDispatcher extends Handler { long datagramId = mNextDatagramId.getAndUpdate( n -> ((n + 1) % DatagramController.MAX_DATAGRAM_ID)); - SendSatelliteDatagramArgument datagramArgs = new SendSatelliteDatagramArgument(subId, - datagramId, datagramType, datagram, needFullScreenPointingUI, callback); + SendSatelliteDatagramArgument datagramArgs = + new SendSatelliteDatagramArgument(subId, datagramId, datagramType, datagram, + needFullScreenPointingUI, callback); synchronized (mLock) { if (datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { @@ -270,6 +297,7 @@ public class DatagramDispatcher extends Handler { if (!mSendingDatagramInProgress) { mSendingDatagramInProgress = true; + datagramArgs.setDatagramStartTime(); sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArgs, phone); mDatagramController.updateSendStatus(subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, @@ -297,6 +325,8 @@ public class DatagramDispatcher extends Handler { mSendingDatagramInProgress = true; SendSatelliteDatagramArgument datagramArg = pendingDatagram.iterator().next().getValue(); + // Sets the trigger time for getting pending datagrams + datagramArg.setDatagramStartTime(); sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArg, phone); mDatagramController.updateSendStatus(datagramArg.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, @@ -321,6 +351,7 @@ public class DatagramDispatcher extends Handler { pendingDatagramsMap.entrySet()) { SendSatelliteDatagramArgument argument = entry.getValue(); argument.callback.accept(errorCode); + reportSendDatagramCompleted(argument, errorCode); } // Clear pending datagram maps @@ -374,6 +405,18 @@ public class DatagramDispatcher extends Handler { msg.sendToTarget(); } + private void reportSendDatagramCompleted(@NonNull SendSatelliteDatagramArgument argument, + @NonNull @SatelliteManager.SatelliteError int resultCode) { + SatelliteStats.getInstance().onSatelliteOutgoingDatagramMetrics( + new SatelliteStats.SatelliteOutgoingDatagramParams.Builder() + .setDatagramType(argument.datagramType) + .setResultCode(resultCode) + .setDatagramSizeBytes(argument.getDatagramRoundedSizeBytes()) + .setDatagramTransferTimeMillis( + System.currentTimeMillis() - argument.datagramStartTime) + .build()); + } + /** * Destroys this DatagramDispatcher. Used for tearing down static resources during testing. */ diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 82b3867deb..d7b96bc335 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.satellite; +import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT; + import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ContentResolver; @@ -42,6 +44,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ILongConsumer; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.metrics.SatelliteStats; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; @@ -67,6 +70,8 @@ public class DatagramReceiver extends Handler { @NonNull private SharedPreferences mSharedPreferences = null; @NonNull private final DatagramController mDatagramController; + private long mDatagramTransferStartTime = 0; + /** * The background handler to perform database operations. This is running on a separate thread. */ @@ -344,6 +349,10 @@ public class DatagramReceiver extends Handler { SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); } + + // Send the captured data about incoming datagram to metric + sInstance.reportMetrics( + satelliteDatagram, SatelliteManager.SATELLITE_ERROR_NONE); break; } @@ -374,7 +383,7 @@ public class DatagramReceiver extends Handler { Message onCompleted; AsyncResult ar; - switch(msg.what) { + switch (msg.what) { case CMD_POLL_PENDING_SATELLITE_DATAGRAMS: { request = (DatagramReceiverHandlerRequest) msg.obj; onCompleted = @@ -402,6 +411,9 @@ public class DatagramReceiver extends Handler { SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, mDatagramController.getReceivePendingCount(), SatelliteManager.SATELLITE_ERROR_NONE); + + // report not able to poll pending datagrams + reportMetrics(null, SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); } break; } @@ -418,6 +430,7 @@ public class DatagramReceiver extends Handler { mDatagramController.updateReceiveStatus(request.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, mDatagramController.getReceivePendingCount(), error); + reportMetrics(null, error); } break; } @@ -510,6 +523,7 @@ public class DatagramReceiver extends Handler { mDatagramController.getReceivePendingCount(), SatelliteManager.SATELLITE_ERROR_NONE); + mDatagramTransferStartTime = System.currentTimeMillis(); Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, callback, phone, subId); } @@ -530,6 +544,31 @@ public class DatagramReceiver extends Handler { msg.sendToTarget(); } + /** Report incoming datagram related metrics */ + private void reportMetrics(@Nullable SatelliteDatagram satelliteDatagram, + @NonNull @SatelliteManager.SatelliteError int resultCode) { + int datagramSizeRoundedBytes = -1; + int datagramTransferTime = 0; + + if (satelliteDatagram != null) { + if (satelliteDatagram.getSatelliteDatagram() != null) { + int sizeBytes = satelliteDatagram.getSatelliteDatagram().length; + // rounded by 10 bytes + datagramSizeRoundedBytes = + (int) (Math.round((double) sizeBytes / ROUNDING_UNIT) * ROUNDING_UNIT); + } + datagramTransferTime = (int) (System.currentTimeMillis() - mDatagramTransferStartTime); + mDatagramTransferStartTime = 0; + } + + SatelliteStats.getInstance().onSatelliteIncomingDatagramMetrics( + new SatelliteStats.SatelliteIncomingDatagramParams.Builder() + .setResultCode(resultCode) + .setDatagramSizeBytes(datagramSizeRoundedBytes) + .setDatagramTransferTimeMillis(datagramTransferTime) + .build()); + } + /** * Destroys this DatagramDispatcher. Used for tearing down static resources during testing. */ -- GitLab From 4cead2d5eeb8bc787b913dae71c7d17402de9969 Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Wed, 8 Mar 2023 07:43:38 +0000 Subject: [PATCH 549/656] Add metric info for SOS message recommender currently initial version for testing and get right position to capture Bug: 266016321 Test: emergency dialer emulation test on pixel Change-Id: Ieba624136a7eb34f7a9e55989321024edd26f1b2 --- .../SatelliteSOSMessageRecommender.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java index a1bd99ec72..b6593130a6 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java @@ -42,6 +42,7 @@ import com.android.ims.ImsException; import com.android.ims.ImsManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.metrics.SatelliteStats; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -262,7 +263,7 @@ public class SatelliteSOSMessageRecommender extends Handler { mEmergencyConnection.sendConnectionEvent(Call.EVENT_DISPLAY_SOS_MESSAGE, null); isDialerNotified = true; } - reportMetrics(isDialerNotified); + reportEsosRecommenderDecision(isDialerNotified); cleanUpResources(); } @@ -289,7 +290,7 @@ public class SatelliteSOSMessageRecommender extends Handler { } if (!shouldTrackCall(state)) { - reportMetrics(false); + reportEsosRecommenderDecision(false); cleanUpResources(); } } @@ -309,14 +310,14 @@ public class SatelliteSOSMessageRecommender extends Handler { } } - private void reportMetrics(boolean isDialerNotified) { - /** - * TODO: We need to report the following info - * - Whether the Dialer is notified with the event DISPLAY_SOS_MESSAGE (isDialerNotified). - * - Number of times the timer is started (mCountOfTimerStarted). - * - Whether IMS is registered (mIsImsRegistered). - * - The cellular service state (mCellularServiceState). - */ + private void reportEsosRecommenderDecision(boolean isDialerNotified) { + SatelliteStats.getInstance().onSatelliteSosMessageRecommender( + new SatelliteStats.SatelliteSosMessageRecommenderParams.Builder() + .setDisplaySosMessageSent(isDialerNotified) + .setCountOfTimerStarted(mCountOfTimerStarted) + .setImsRegistered(mIsImsRegistered.get()) + .setCellularServiceState(mCellularServiceState.get()) + .build()); } private void cleanUpResources() { -- GitLab From 3482449fcb78247930ece000296439046578d6cd Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Thu, 16 Mar 2023 15:04:04 -0700 Subject: [PATCH 550/656] Cache satellite service states and restructure callback register handling in SatelliteController Bug: 274136093 Test: Call/SMS/MMS with live network. atest com.android.internal.telephony.satellite.SatelliteSOSMessageRecommenderTest atest com.android.internal.telephony.satellite.SatelliteSessionControllerTest atest android.telephony.cts.SatelliteManagerTest Change-Id: I86c61cdc3fafeadfbd9a355a730cb2f498006518 --- .../internal/telephony/CommandsInterface.java | 7 + .../com/android/internal/telephony/Phone.java | 8 + .../com/android/internal/telephony/RIL.java | 15 + .../satellite/DatagramController.java | 13 + .../telephony/satellite/DatagramReceiver.java | 4 - .../satellite/PointingAppController.java | 56 +- .../satellite/SatelliteController.java | 862 ++++++++++-------- .../satellite/SatelliteModemInterface.java | 13 +- .../SatelliteSOSMessageRecommender.java | 3 +- .../satellite/SatelliteSessionController.java | 18 +- .../SatelliteSOSMessageRecommenderTest.java | 79 +- .../SatelliteSessionControllerTest.java | 59 +- 12 files changed, 667 insertions(+), 470 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 7314ccb823..439b19b019 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -3034,6 +3034,13 @@ public interface CommandsInterface { */ default void getSatellitePowerState(Message result) {} + /** + * Get satellite provision state. + * + * @param result Message that will be sent back to the requester + */ + default void getSatelliteProvisionState(Message result) {} + /** * Check whether satellite modem is supported by the device. * diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 9f2513a4e5..34f1c51c4e 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5315,6 +5315,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.isSatelliteSupported(result); } + /** + * Check whether the satellite modem is provisioned. + * @param result The Message to send the result of the operation to. + */ + public void isSatelliteProvisioned(Message result) { + mCi.getSatelliteProvisionState(result); + } + /** * Get the satellite capabilities. * @param result The Message to send the result of the operation to. diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 8aff93b6ba..3987fb9986 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5788,6 +5788,21 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * Get satellite provision state. + * + * @param result Message that will be sent back to the requester + */ + @Override + public void getSatelliteProvisionState(Message result) { + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + /** * Provision the subscription with a satellite provider. This is needed to register the * subscription if the provider allows dynamic registration. diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 56ee8a6588..d339cd11af 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -186,6 +186,7 @@ public class DatagramController { mSendErrorCode = errorCode; mPointingAppController.updateSendDatagramTransferState(subId, datagramTransferState, sendPendingCount, errorCode); + notifyDatagramTransferStateChangedToSessionController(); } /** @@ -210,6 +211,7 @@ public class DatagramController { mReceiveErrorCode = errorCode; mPointingAppController.updateReceiveDatagramTransferState(subId, datagramTransferState, receivePendingCount, errorCode); + notifyDatagramTransferStateChangedToSessionController(); } /** @@ -220,6 +222,17 @@ public class DatagramController { return mReceivePendingCount; } + private void notifyDatagramTransferStateChangedToSessionController() { + SatelliteSessionController sessionController = SatelliteSessionController.getInstance(); + if (sessionController == null) { + loge("notifyDatagramTransferStateChangeToSessionController: SatelliteSessionController" + + " is not initialized yet"); + } else { + sessionController.onDatagramTransferStateChanged( + mSendDatagramTransferState, mReceiveDatagramTransferState); + } + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 82b3867deb..117f32de86 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -445,8 +445,6 @@ public class DatagramReceiver extends Handler { satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler( mBackgroundHandler.getLooper(), validSubId); if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { - // TODO: remove this as SatelliteModemInterface can register for incoming datagrams - // on boot up itself. SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived( satelliteDatagramListenerHandler, SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null); @@ -545,6 +543,4 @@ public class DatagramReceiver extends Handler { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } - - // TODO: An api change - do not pass the binder from Telephony to Applications } diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java index c37d1a05ba..dcfbe1f513 100644 --- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -34,6 +34,8 @@ import android.text.TextUtils; import com.android.internal.telephony.Phone; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -114,6 +116,7 @@ public class PointingAppController { public static final int EVENT_POSITION_INFO_CHANGED = 1; public static final int EVENT_SEND_DATAGRAM_STATE_CHANGED = 2; public static final int EVENT_RECEIVE_DATAGRAM_STATE_CHANGED = 3; + public static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 4; private final ConcurrentHashMap mListeners; SatelliteTransmissionUpdateHandler(Looper looper) { @@ -139,41 +142,64 @@ public class PointingAppController { case EVENT_POSITION_INFO_CHANGED: { AsyncResult ar = (AsyncResult) msg.obj; PointingInfo pointingInfo = (PointingInfo) ar.result; + List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onSatellitePositionChanged(pointingInfo); } catch (RemoteException e) { logd("EVENT_POSITION_INFO_CHANGED RemoteException: " + e); + toBeRemoved.add(listener.asBinder()); } }); + toBeRemoved.forEach(listener -> { + mListeners.remove(listener); + }); + break; + } + + case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + logd("Receive EVENT_DATAGRAM_TRANSFER_STATE_CHANGED state=" + (int) ar.result); break; } case EVENT_SEND_DATAGRAM_STATE_CHANGED: { + logd("Received EVENT_SEND_DATAGRAM_STATE_CHANGED"); DatagramTransferStateHandlerRequest request = (DatagramTransferStateHandlerRequest) msg.obj; + List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onSendDatagramStateChanged(request.datagramTransferState, request.pendingCount, request.errorCode); } catch (RemoteException e) { logd("EVENT_SEND_DATAGRAM_STATE_CHANGED RemoteException: " + e); + toBeRemoved.add(listener.asBinder()); } }); + toBeRemoved.forEach(listener -> { + mListeners.remove(listener); + }); break; } case EVENT_RECEIVE_DATAGRAM_STATE_CHANGED: { + logd("Received EVENT_RECEIVE_DATAGRAM_STATE_CHANGED"); DatagramTransferStateHandlerRequest request = (DatagramTransferStateHandlerRequest) msg.obj; + List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onReceiveDatagramStateChanged(request.datagramTransferState, request.pendingCount, request.errorCode); } catch (RemoteException e) { logd("EVENT_RECEIVE_DATAGRAM_STATE_CHANGED RemoteException: " + e); + toBeRemoved.add(listener.asBinder()); } }); + toBeRemoved.forEach(listener -> { + mListeners.remove(listener); + }); break; } @@ -204,18 +230,13 @@ public class PointingAppController { SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged( handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); - /** - * TODO: Need to remove this call, Datagram transfer state should come from the - * DatagramController based upon Transfer state. - * Modem won't be able to provide this info - */ SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged( handler, - SatelliteTransmissionUpdateHandler.EVENT_SEND_DATAGRAM_STATE_CHANGED, null); + SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, + null); } else { phone.registerForSatellitePositionInfoChanged(handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); - // TODO: registerForDatagramTransferStateChanged through SatelliteController } } } @@ -237,13 +258,6 @@ public class PointingAppController { handler.removeListener(callback); if (handler.hasListeners()) { - /** - * TODO (b/269194948): If the calling apps crash, the handler will always have some - * listener. That is, we will not request modem to stop position update and - * cleaning our resources. We need to monitor the calling apps and clean up the - * resources when the apps die. We need to do this for other satellite callbacks - * as well. - */ result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; } @@ -260,7 +274,6 @@ public class PointingAppController { return; } phone.unregisterForSatellitePositionInfoChanged(handler); - // TODO: unregisterForDatagramTransferStateChanged through SatelliteController } } } @@ -276,6 +289,9 @@ public class PointingAppController { public void startSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) { if (mStartedSatelliteTransmissionUpdates) { logd("startSatelliteTransmissionUpdates: already started"); + AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_ERROR_NONE)); + message.sendToTarget(); return; } if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { @@ -320,7 +336,17 @@ public class PointingAppController { public void startPointingUI(boolean needFullScreenPointingUI) { String packageName = TextUtils.emptyIfNull(mContext.getResources() .getString(com.android.internal.R.string.config_pointing_ui_package)); + if (TextUtils.isEmpty(packageName)) { + logd("startPointingUI: config_pointing_ui_package is not set. Ignore the request"); + return; + } + Intent launchIntent = mContext.getPackageManager().getLaunchIntentForPackage(packageName); + if (launchIntent == null) { + loge("startPointingUI: launchIntent is null"); + return; + } + launchIntent.putExtra("needFullScreen", needFullScreenPointingUI); mContext.startActivity(launchIntent); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index ca76d16c2a..8d1b9223e0 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -23,7 +23,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.net.wifi.WifiManager; import android.os.AsyncResult; -import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; @@ -50,12 +49,12 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionController; -import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** @@ -93,6 +92,11 @@ public class SatelliteController extends Handler { private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 21; private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 22; private static final int EVENT_RADIO_STATE_CHANGED = 23; + private static final int CMD_IS_SATELLITE_PROVISIONED = 24; + private static final int EVENT_IS_SATELLITE_PROVISIONED_DONE = 25; + private static final int EVENT_SATELLITE_PROVISION_STATE_CHANGED = 26; + private static final int EVENT_PENDING_DATAGRAMS = 27; + private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 28; @NonNull private static SatelliteController sInstance; @NonNull private final Context mContext; @@ -110,6 +114,18 @@ public class SatelliteController extends Handler { private static final String KEY_WIFI_DISABLED_BY_SCO = "wifi_disabled_by_sco"; boolean mDisabledBTFlag = false; boolean mDisabledWifiFlag = false; + private final AtomicBoolean mRegisteredForProvisionStateChangedWithSatelliteService = + new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForProvisionStateChangedWithPhone = + new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForPendingDatagramCountWithSatelliteService = + new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForPendingDatagramCountWithPhone = + new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService = + new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithPhone = + new AtomicBoolean(false); /** * Map key: subId, value: callback to get error code of the provision request. */ @@ -117,24 +133,20 @@ public class SatelliteController extends Handler { new ConcurrentHashMap<>(); /** - * Map key: subId, value: SatelliteProvisionStateChangedHandler to notify registrants. + * Map key: binder of the callback, value: callback to receive provision state changed events. */ - private final ConcurrentHashMap - mSatelliteProvisionStateChangedHandlers = new ConcurrentHashMap<>(); - - /** - * Map key: subId, value: SatelliteStateListenerHandler to notify registrants. - */ - private final ConcurrentHashMap - mSatelliteStateListenerHandlers = new ConcurrentHashMap<>(); + private final ConcurrentHashMap + mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>(); private Boolean mIsSatelliteSupported = null; private final Object mIsSatelliteSupportedLock = new Object(); - private final ResultReceiver mSatelliteSupportedReceiver; private boolean mIsDemoModeEnabled = false; private Boolean mIsSatelliteEnabled = null; private final Object mIsSatelliteEnabledLock = new Object(); - private final ResultReceiver mSatelliteEnabledReceiver; + private Boolean mIsSatelliteProvisioned = null; + private final Object mIsSatelliteProvisionedLock = new Object(); + private SatelliteCapabilities mSatelliteCapabilities; + private final Object mSatelliteCapabilitiesLock = new Object(); private boolean mNeedsSatellitePointing = false; private final Object mNeedsSatellitePointingLock = new Object(); @@ -175,7 +187,7 @@ public class SatelliteController extends Handler { mCi = phone.mCi; // Create the SatelliteModemInterface singleton, which is used to manage connections // to the satellite service and HAL interface. - mSatelliteModemInterface = SatelliteModemInterface.make(mContext); + mSatelliteModemInterface = SatelliteModemInterface.make(mContext, this); // Create the PointingUIController singleton, // which is used to manage interactions with PointingUI app. @@ -185,13 +197,17 @@ public class SatelliteController extends Handler { // which is used to send and receive satellite datagrams. mDatagramController = DatagramController.make(mContext, looper, mPointingAppController); - mSatelliteEnabledReceiver = createSatelliteEnabledResultReceiver(); - mSatelliteSupportedReceiver = createSatelliteSupportedResultReceiver(looper); - //TODO: reenable below code - //requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - // mSatelliteSupportedReceiver); + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteSupported: resultCode=" + resultCode); + } + }); mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); - + registerForSatelliteProvisionStateChanged(); + registerForPendingDatagramCount(); + registerForSatelliteModemStateChanged(); try { mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); @@ -276,116 +292,6 @@ public class SatelliteController extends Handler { } } - private static final class SatelliteProvisionStateChangedHandler extends Handler { - public static final int EVENT_PROVISION_STATE_CHANGED = 1; - - private final ConcurrentHashMap mListeners; - private final int mSubId; - - SatelliteProvisionStateChangedHandler(Looper looper, int subId) { - super(looper); - mListeners = new ConcurrentHashMap<>(); - mSubId = subId; - } - - public void addListener(ISatelliteProvisionStateCallback listener) { - mListeners.put(listener.asBinder(), listener); - } - - public void removeListener(ISatelliteProvisionStateCallback listener) { - mListeners.remove(listener.asBinder()); - } - - @Override - public void handleMessage(@NonNull Message msg) { - switch (msg.what) { - case EVENT_PROVISION_STATE_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - boolean provisioned = (boolean) ar.userObj; - logd("Received EVENT_PROVISION_STATE_CHANGED for subId=" + mSubId - + ", provisioned=" + provisioned); - mListeners.values().forEach(listener -> { - try { - listener.onSatelliteProvisionStateChanged(provisioned); - } catch (RemoteException e) { - logd("EVENT_PROVISION_STATE_CHANGED RemoteException: " + e); - } - }); - - setSatelliteProvisioned(provisioned); - /** - * TODO: Take bugreport if provisioned is true and user did not initiate the - * provision procedure for the corresponding subscription. - */ - break; - } - default: - loge("SatelliteProvisionStateChangedHandler unknown event: " + msg.what); - } - } - - private void setSatelliteProvisioned(boolean isProvisioned) { - if (mSubId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - SubscriptionManager.setSubscriptionProperty( - mSubId, SubscriptionManager.SATELLITE_ENABLED, isProvisioned ? "1" : "0"); - } else { - //TODO (b/267826133): set via SatelliteController. - } - } - } - - private static final class SatelliteStateListenerHandler extends Handler { - public static final int EVENT_SATELLITE_MODEM_STATE_CHANGE = 1; - public static final int EVENT_PENDING_DATAGRAMS = 2; - - private final ConcurrentHashMap mListeners; - private final int mSubId; - - SatelliteStateListenerHandler(Looper looper, int subId) { - super(looper); - mSubId = subId; - mListeners = new ConcurrentHashMap<>(); - } - - public void addListener(ISatelliteStateCallback listener) { - mListeners.put(listener.asBinder(), listener); - } - - public void removeListener(ISatelliteStateCallback listener) { - mListeners.remove(listener.asBinder()); - } - - public boolean hasListeners() { - return !mListeners.isEmpty(); - } - - @Override - public void handleMessage(@NonNull Message msg) { - switch (msg.what) { - case EVENT_SATELLITE_MODEM_STATE_CHANGE : { - AsyncResult ar = (AsyncResult) msg.obj; - int state = (int) ar.result; - logd("Received EVENT_SATELLITE_MODEM_STATE_CHANGE for subId=" + mSubId - + ", state=" + state); - break; - } - case EVENT_PENDING_DATAGRAMS: { - logd("Received EVENT_PENDING_DATAGRAMS for subId=" + mSubId); - IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - logd("pollPendingSatelliteDatagram result: " + result); - } - }; - sInstance.pollPendingSatelliteDatagrams(mSubId, internalCallback); - break; - } - default: - loge("SatelliteStateListenerHandler unknown event: " + msg.what); - } - } - } - @Override public void handleMessage(Message msg) { SatelliteControllerHandlerRequest request; @@ -517,8 +423,7 @@ public class SatelliteController extends Handler { checkAndEnableBluetoothWifiState(); } /** - * TODO: check if Satellite is Acquired. - * Also need to call requestSatelliteCapabilities() if Satellite is enabled + * TODO for NTN-based satellites: Check if satellite is acquired. */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(false); @@ -528,7 +433,6 @@ public class SatelliteController extends Handler { argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); } argument.callback.accept(error); - // TODO: if error is ERROR_NONE, request satellite capabilities break; } @@ -564,6 +468,7 @@ public class SatelliteController extends Handler { boolean enabled = ((int[]) ar.result)[0] == 1; if (DBG) logd("isSatelliteEnabled: " + enabled); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled); + updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE"); } } ((ResultReceiver) request.argument).send(error, bundle); @@ -602,9 +507,7 @@ public class SatelliteController extends Handler { boolean supported = (boolean) ar.result; if (DBG) logd("isSatelliteSupported: " + supported); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported); - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = supported; - } + updateSatelliteSupportedState(supported); } } ((ResultReceiver) request.argument).send(error, bundle); @@ -647,6 +550,9 @@ public class SatelliteController extends Handler { if (DBG) logd("getSatelliteCapabilities: " + capabilities); bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, capabilities); + synchronized (mSatelliteCapabilitiesLock) { + mSatelliteCapabilities = capabilities; + } } } ((ResultReceiver) request.argument).send(error, bundle); @@ -759,10 +665,101 @@ public class SatelliteController extends Handler { new RequestSatelliteEnabledArgument(false, false, result); request = new SatelliteControllerHandlerRequest(message, phone); handleSatelliteEnabled(request); + } else { + if (!mSatelliteModemInterface.isSatelliteServiceSupported()) { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported == null) { + ResultReceiver receiver = new ResultReceiver(this) { + @Override + protected void onReceiveResult( + int resultCode, Bundle resultData) { + logd("requestIsSatelliteSupported: resultCode=" + + resultCode); + } + }; + requestIsSatelliteSupported( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); + } + } + } else { + logd("EVENT_RADIO_STATE_CHANGED: Satellite vendor service is supported." + + " Ignored the event"); + } } break; } + case CMD_IS_SATELLITE_PROVISIONED: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = obtainMessage(EVENT_IS_SATELLITE_PROVISIONED_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.isSatelliteProvisioned(onCompleted); + } else { + loge("isSatelliteProvisioned: No phone object"); + ((ResultReceiver) request.argument).send( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + } + break; + } + + case EVENT_IS_SATELLITE_PROVISIONED_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = SatelliteServiceUtils.getSatelliteError(ar, + "isSatelliteProvisioned"); + Bundle bundle = new Bundle(); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (ar.result == null) { + loge("isSatelliteProvisioned: result is null"); + error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } else { + boolean provisioned = ((int[]) ar.result)[0] == 1; + if (DBG) logd("isSatelliteProvisioned: " + provisioned); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, provisioned); + synchronized (mIsSatelliteProvisionedLock) { + mIsSatelliteProvisioned = provisioned; + } + } + } + ((ResultReceiver) request.argument).send(error, bundle); + break; + } + + case EVENT_SATELLITE_PROVISION_STATE_CHANGED: + ar = (AsyncResult) msg.obj; + if (ar.result == null) { + loge("EVENT_SATELLITE_PROVISION_STATE_CHANGED: result is null"); + } else { + handleEventSatelliteProvisionStateChanged((boolean) ar.result); + } + break; + + case EVENT_PENDING_DATAGRAMS: + logd("Received EVENT_PENDING_DATAGRAMS"); + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("pollPendingSatelliteDatagram result: " + result); + } + }; + pollPendingSatelliteDatagrams( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, internalCallback); + break; + + case EVENT_SATELLITE_MODEM_STATE_CHANGED: + ar = (AsyncResult) msg.obj; + if (ar.result == null) { + loge("EVENT_SATELLITE_MODEM_STATE_CHANGED: result is null"); + } else { + handleEventSatelliteModemStateChanged((int) ar.result); + } + break; + default: Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " + msg.what); @@ -790,22 +787,29 @@ public class SatelliteController extends Handler { public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteSupported) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - // TODO: clean up this dependency on subId - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } - Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_SET_SATELLITE_ENABLED, new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result), - phone); + SatelliteServiceUtils.getPhone()); } /** @@ -816,14 +820,13 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); return; } - - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { - result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + if (!satelliteSupported) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } @@ -837,7 +840,7 @@ public class SatelliteController extends Handler { } } - sendRequest(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); + sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); } /** @@ -849,13 +852,22 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteSupported) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteProvisioned) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -894,13 +906,27 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteSupported) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - Phone phone = SatelliteServiceUtils.getPhone(); - sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, phone); + synchronized (mSatelliteCapabilitiesLock) { + if (mSatelliteCapabilities != null) { + Bundle bundle = new Bundle(); + bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, + mSatelliteCapabilities); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + return; + } + } + + sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, SatelliteServiceUtils.getPhone()); } /** @@ -916,18 +942,28 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteSupported) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } Phone phone = SatelliteServiceUtils.getPhone(); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback, phone); sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES, new SatelliteTransmissionUpdateArgument(result, callback, validSubId), phone); @@ -945,18 +981,28 @@ public class SatelliteController extends Handler { public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteSupported) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } Phone phone = SatelliteServiceUtils.getPhone(); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.unregisterForSatelliteTransmissionUpdates( validSubId, result, callback, phone); @@ -982,24 +1028,29 @@ public class SatelliteController extends Handler { @Nullable public ICancellationSignal provisionSatelliteService(int subId, @NonNull String token, @NonNull String regionId, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return null; + } + if (!satelliteSupported) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return null; } final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - Phone phone = SatelliteServiceUtils.getPhone(); - if (mSatelliteProvisionCallbacks.containsKey(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS); return null; } - if (isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned != null && satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return null; } + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, regionId, result, validSubId), phone); @@ -1026,18 +1077,28 @@ public class SatelliteController extends Handler { public void deprovisionSatelliteService(int subId, @NonNull String token, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteSupported) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; } Phone phone = SatelliteServiceUtils.getPhone(); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, null, result, validSubId), phone); } @@ -1052,34 +1113,15 @@ public class SatelliteController extends Handler { */ @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId, @NonNull ISatelliteProvisionStateCallback callback) { - if (!isSatelliteSupported()) { - return SatelliteManager.SATELLITE_NOT_SUPPORTED; + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; } - - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - Phone phone = SatelliteServiceUtils.getPhone(); - - SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = - mSatelliteProvisionStateChangedHandlers.get(validSubId); - if (satelliteProvisionStateChangedHandler == null) { - satelliteProvisionStateChangedHandler = new SatelliteProvisionStateChangedHandler( - Looper.getMainLooper(), validSubId); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( - satelliteProvisionStateChangedHandler, - SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); - } else { - phone.registerForSatelliteProvisionStateChanged( - satelliteProvisionStateChangedHandler, - SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); - } + if (!satelliteSupported) { + return SatelliteManager.SATELLITE_NOT_SUPPORTED; } - if (callback != null) { - satelliteProvisionStateChangedHandler.addListener(callback); - } - mSatelliteProvisionStateChangedHandlers.put( - validSubId, satelliteProvisionStateChangedHandler); + mSatelliteProvisionStateChangedListeners.put(callback.asBinder(), callback); return SatelliteManager.SATELLITE_ERROR_NONE; } @@ -1093,12 +1135,7 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback) { - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = - mSatelliteProvisionStateChangedHandlers.get(validSubId); - if (satelliteProvisionStateChangedHandler != null) { - satelliteProvisionStateChangedHandler.removeListener(callback); - } + mSatelliteProvisionStateChangedListeners.remove(callback.asBinder()); } /** @@ -1110,16 +1147,27 @@ public class SatelliteController extends Handler { * request failed. */ public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteSupported) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - Bundle bundle = new Bundle(); - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, - isSatelliteProvisioned(validSubId)); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + synchronized (mIsSatelliteProvisionedLock) { + if (mIsSatelliteProvisioned != null) { + Bundle bundle = new Bundle(); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, + mIsSatelliteProvisioned); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + return; + } + } + + sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, SatelliteServiceUtils.getPhone()); } /** @@ -1139,35 +1187,6 @@ public class SatelliteController extends Handler { + " is not initialized yet"); return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; } - - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - SatelliteStateListenerHandler satelliteStateListenerHandler = - mSatelliteStateListenerHandlers.get(validSubId); - if (satelliteStateListenerHandler == null) { - satelliteStateListenerHandler = new SatelliteStateListenerHandler( - Looper.getMainLooper(), validSubId); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.registerForSatelliteModemStateChanged( - satelliteStateListenerHandler, - SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); - mSatelliteModemInterface.registerForPendingDatagrams(satelliteStateListenerHandler, - SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForSatelliteModemStateChanged: satellite phone is " - + "not initialized yet"); - return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } - phone.registerForSatelliteModemStateChanged(satelliteStateListenerHandler, - SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); - phone.registerForPendingDatagramCount(satelliteStateListenerHandler, - SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); - } - } - - satelliteStateListenerHandler.addListener(callback); - mSatelliteStateListenerHandlers.put(validSubId, satelliteStateListenerHandler); return SatelliteManager.SATELLITE_ERROR_NONE; } @@ -1181,25 +1200,6 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - SatelliteStateListenerHandler handler = mSatelliteStateListenerHandlers.get(validSubId); - if (handler != null) { - handler.removeListener(callback); - if (!handler.hasListeners()) { - mSatelliteStateListenerHandlers.remove(validSubId); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.unregisterForSatelliteModemStateChanged(handler); - mSatelliteModemInterface.unregisterForPendingDatagrams(handler); - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone != null) { - phone.unregisterForSatelliteModemStateChanged(handler); - phone.unregisterForPendingDatagramCount(handler); - } - } - } - } - if (mSatelliteSessionController != null) { mSatelliteSessionController.unregisterForSatelliteModemStateChanged(callback); } else { @@ -1246,16 +1246,20 @@ public class SatelliteController extends Handler { * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ public void pollPendingSatelliteDatagrams(int subId, @NonNull IIntegerConsumer callback) { - // TODO: return pending datagram count on success Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } - mDatagramController.pollPendingSatelliteDatagrams(subId, result); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + mDatagramController.pollPendingSatelliteDatagrams(validSubId, result); } /** @@ -1279,20 +1283,24 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } /** - * TODO: check if Satellite is Acquired. Also need to call requestSatelliteCapabilities() - * when Satellite is enabled + * TODO for NTN-based satellites: Check if satellite is acquired. */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(needFullScreenPointingUI); } + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mDatagramController.sendSatelliteDatagram(validSubId, datagramType, datagram, needFullScreenPointingUI, result); } @@ -1308,13 +1316,18 @@ public class SatelliteController extends Handler { */ public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteSupported) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - Phone phone = SatelliteServiceUtils.getPhone(); - sendRequest(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, phone); + sendRequestAsync( + CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, SatelliteServiceUtils.getPhone()); } /** @@ -1325,13 +1338,22 @@ public class SatelliteController extends Handler { * be visible if the request is successful or an error code if the request failed. */ public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteSupported) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteProvisioned) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -1340,6 +1362,61 @@ public class SatelliteController extends Handler { sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); } + /** + * If we have not successfully queried the satellite modem for its satellite service support, + * we will retry the query one more time. Otherwise, we will return the cached result. + */ + public Boolean isSatelliteSupported() { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported != null) { + /* We have already successfully queried the satellite modem. */ + return mIsSatelliteSupported; + } + } + /** + * We have not successfully checked whether the modem supports satellite service. + * Thus, we need to retry it now. + */ + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteSupported: resultCode=" + resultCode); + } + }); + return null; + } + + /** + * This function is used by {@link SatelliteModemInterface} to notify + * {@link SatelliteController} that the satellite vendor service was just connected. + *

+ * {@link SatelliteController} will send requests to satellite modem to check whether it support + * satellite, whether it is powered on, and whether it is provisioned. + * {@link SatelliteController} will use these cached values to serve requests from its clients. + */ + void onSatelliteServiceConnected() { + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported == null) { + ResultReceiver receiver = new ResultReceiver(this) { + @Override + protected void onReceiveResult( + int resultCode, Bundle resultData) { + logd("requestIsSatelliteSupported: resultCode=" + + resultCode); + } + }; + requestIsSatelliteSupported( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); + } + } + } else { + logd("onSatelliteServiceConnected: Satellite vendor service is not supported." + + " Ignored the event"); + } + } + private void handleEventProvisionSatelliteServiceDone( @NonNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteError int result) { @@ -1353,17 +1430,6 @@ public class SatelliteController extends Handler { return; } callback.accept(result); - - if (result == SatelliteManager.SATELLITE_ERROR_NONE) { - setSatelliteProvisioned(arg.subId, true); - } - - /** - * We need to update satellite provision status in SubscriptionController - * or SatelliteController. - * TODO (b/267826133) we need to do this for all subscriptions on the device. - */ - registerForSatelliteProvisionStateChanged(arg.subId, null); } private void handleEventDeprovisionSatelliteServiceDone( @@ -1379,10 +1445,6 @@ public class SatelliteController extends Handler { if (arg.callback != null) { arg.callback.accept(result); } - - if (result == SatelliteManager.SATELLITE_ERROR_NONE) { - setSatelliteProvisioned(arg.subId, false); - } } private void handleStartSatelliteTransmissionUpdatesDone(@NonNull AsyncResult ar) { @@ -1404,42 +1466,6 @@ public class SatelliteController extends Handler { } } - /** - * Set satellite provisioned for a subscription or the device. - * - * The permission {@link android.Manifest.permission#MODIFY_PHONE_STATE} will be enforced by - * {@link SubscriptionController} when setting satellite enabled for an active subscription. - * Otherwise, {@link android.Manifest.permission#SATELLITE_COMMUNICATION} will be enforced. - */ - private synchronized void setSatelliteProvisioned(int subId, boolean isEnabled) { - if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - SubscriptionManager.setSubscriptionProperty( - subId, SubscriptionManager.SATELLITE_ENABLED, isEnabled ? "1" : "0"); - } else { - //TODO (b/267826133): set via SatelliteController - } - } - - /** - * If we have not successfully queried the satellite modem for its satellite service support, - * we will retry the query one more time. Otherwise, we will return the queried result. - */ - public boolean isSatelliteSupported() { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported != null) { - /* We have already successfully queried the satellite modem. */ - return mIsSatelliteSupported; - } - } - /** - * We have not successfully checked whether the modem supports satellite service. - * Thus, we need to retry it now. - */ - requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - mSatelliteSupportedReceiver); - return false; - } - /** * Posts the specified command to be executed on the main thread and returns immediately. * @@ -1488,35 +1514,24 @@ public class SatelliteController extends Handler { /** * Check if satellite is provisioned for a subscription on the device. - * @param subId The subscription id. * @return true if satellite is provisioned on the given subscription else return false. */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - protected boolean isSatelliteProvisioned(int subId) { - final long identity = Binder.clearCallingIdentity(); - try { - if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - String strResult = null; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - strResult = SubscriptionManagerService.getInstance() - .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED, - mContext.getOpPackageName(), mContext.getAttributionTag()); - } else { - strResult = SubscriptionController.getInstance() - .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED); - } - - if (strResult != null) { - int intResult = Integer.parseInt(strResult); - return (intResult == 1); - } - } else { - //TODO (b/267826133): check via SatelliteController + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected Boolean isSatelliteProvisioned() { + synchronized (mIsSatelliteProvisionedLock) { + if (mIsSatelliteProvisioned != null) { + return mIsSatelliteProvisioned; } - } finally { - Binder.restoreCallingIdentity(identity); } - return false; + + requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); + } + }); + return null; } private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) { @@ -1537,39 +1552,39 @@ public class SatelliteController extends Handler { } } - private ResultReceiver createSatelliteSupportedResultReceiver(@NonNull Looper looper) { - return new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE - && resultData.containsKey(SatelliteManager.KEY_SATELLITE_SUPPORTED)) { - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = resultData.getBoolean( - SatelliteManager.KEY_SATELLITE_SUPPORTED); - } - } - mSatelliteSessionController = SatelliteSessionController.make(mContext, looper, - mIsSatelliteSupported != null ? mIsSatelliteSupported : false); - if (mIsSatelliteSupported != null && mIsSatelliteSupported) { - requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - mSatelliteEnabledReceiver); - } - } - }; - } + private void updateSatelliteSupportedState(boolean supported) { + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = supported; + } + mSatelliteSessionController = SatelliteSessionController.make( + mContext, getLooper(), supported); + if (supported) { + registerForSatelliteProvisionStateChanged(); + registerForPendingDatagramCount(); + registerForSatelliteModemStateChanged(); - private ResultReceiver createSatelliteEnabledResultReceiver() { - return new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE - && resultData.containsKey(SatelliteManager.KEY_SATELLITE_ENABLED)) { - updateSatelliteEnabledState(resultData.getBoolean( - SatelliteManager.KEY_SATELLITE_ENABLED), - "SatelliteEnabledResultReceiver.onReceiveResult"); - } - } - }; + requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteEnabled: resultCode=" + resultCode); + } + }); + requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); + } + }); + requestSatelliteCapabilities(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestSatelliteCapabilities: resultCode=" + resultCode); + } + }); + } } private void updateSatelliteEnabledState(boolean enabled, String caller) { @@ -1617,13 +1632,102 @@ public class SatelliteController extends Handler { if (DBG) logd("Enabling Bluetooth"); mBluetoothAdapter.enable(); mSharedPreferences.edit().putBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, false) - .apply(); + .apply(); } if (!mWifiManager.isWifiEnabled() && mDisabledWifiFlag) { if (DBG) logd("Enabling Wifi"); mWifiManager.setWifiEnabled(true); mSharedPreferences.edit().putBoolean(KEY_WIFI_DISABLED_BY_SCO, false) - .apply(); + .apply(); + } + } + + private void registerForSatelliteProvisionStateChanged() { + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + if (!mRegisteredForProvisionStateChangedWithSatelliteService.get()) { + mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( + this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); + mRegisteredForProvisionStateChangedWithSatelliteService.set(true); + } + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone == null) { + loge("registerForSatelliteProvisionStateChanged: phone is null"); + } else if (!mRegisteredForProvisionStateChangedWithPhone.get()) { + phone.registerForSatelliteProvisionStateChanged( + this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); + mRegisteredForProvisionStateChangedWithPhone.set(true); + } + } + } + + private void registerForPendingDatagramCount() { + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + if (!mRegisteredForPendingDatagramCountWithSatelliteService.get()) { + mSatelliteModemInterface.registerForPendingDatagrams( + this, EVENT_PENDING_DATAGRAMS, null); + mRegisteredForPendingDatagramCountWithSatelliteService.set(true); + } + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone == null) { + loge("registerForPendingDatagramCount: satellite phone is " + + "not initialized yet"); + } else if (!mRegisteredForPendingDatagramCountWithPhone.get()) { + phone.registerForPendingDatagramCount(this, EVENT_PENDING_DATAGRAMS, null); + mRegisteredForPendingDatagramCountWithPhone.set(true); + } + } + } + + private void registerForSatelliteModemStateChanged() { + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + if (!mRegisteredForSatelliteModemStateChangedWithSatelliteService.get()) { + mSatelliteModemInterface.registerForSatelliteModemStateChanged( + this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); + mRegisteredForSatelliteModemStateChangedWithSatelliteService.set(true); + } + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone == null) { + loge("registerForSatelliteModemStateChanged: satellite phone is " + + "not initialized yet"); + } else if (!mRegisteredForSatelliteModemStateChangedWithPhone.get()) { + phone.registerForSatelliteModemStateChanged( + this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); + mRegisteredForSatelliteModemStateChangedWithPhone.set(true); + } + } + } + + private void handleEventSatelliteProvisionStateChanged(boolean provisioned) { + logd("handleSatelliteProvisionStateChangedEvent: provisioned=" + provisioned); + + synchronized (mIsSatelliteProvisionedLock) { + mIsSatelliteProvisioned = provisioned; + } + + List toBeRemoved = new ArrayList<>(); + mSatelliteProvisionStateChangedListeners.values().forEach(listener -> { + try { + listener.onSatelliteProvisionStateChanged(provisioned); + } catch (RemoteException e) { + logd("handleSatelliteProvisionStateChangedEvent RemoteException: " + e); + toBeRemoved.add(listener); + } + }); + toBeRemoved.forEach(listener -> { + mSatelliteProvisionStateChangedListeners.remove(listener.asBinder()); + }); + } + + private void handleEventSatelliteModemStateChanged( + @SatelliteManager.SatelliteModemState int state) { + logd("handleEventSatelliteModemStateChanged: state=" + state); + if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF + || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { + updateSatelliteEnabledState( + false, "handleEventSatelliteModemStateChanged"); } } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index cf2fc8593b..8657529183 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -65,6 +65,7 @@ public class SatelliteModemInterface { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @NonNull protected final ExponentialBackoff mExponentialBackoff; @NonNull private final Object mLock = new Object(); + @NonNull private final SatelliteController mSatelliteController; /** * {@code true} to use the vendor satellite service and {@code false} to use the HAL. */ @@ -150,11 +151,14 @@ public class SatelliteModemInterface { /** * Create the SatelliteModemInterface singleton instance. * @param context The Context to use to create the SatelliteModemInterface. + * @param satelliteController The singleton instance of SatelliteController. * @return The singleton instance of SatelliteModemInterface. */ - public static SatelliteModemInterface make(@NonNull Context context) { + public static SatelliteModemInterface make(@NonNull Context context, + SatelliteController satelliteController) { if (sInstance == null) { - sInstance = new SatelliteModemInterface(context, Looper.getMainLooper()); + sInstance = new SatelliteModemInterface( + context, satelliteController, Looper.getMainLooper()); } return sInstance; } @@ -166,9 +170,11 @@ public class SatelliteModemInterface { * @param looper The Looper to run binding retry on. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - protected SatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { + protected SatelliteModemInterface(@NonNull Context context, + SatelliteController satelliteController, @NonNull Looper looper) { mContext = context; mIsSatelliteServiceSupported = getSatelliteServiceSupport(); + mSatelliteController = satelliteController; mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, REBIND_MULTIPLIER, looper, () -> { synchronized (mLock) { @@ -280,6 +286,7 @@ public class SatelliteModemInterface { // TODO: Retry setSatelliteListener logd("setSatelliteListener: RemoteException " + e); } + mSatelliteController.onSatelliteServiceConnected(); } @Override diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java index a1bd99ec72..1eeb5a21db 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java @@ -255,8 +255,7 @@ public class SatelliteSOSMessageRecommender extends Handler { boolean isDialerNotified = false; if (!mIsImsRegistered.get() && !isCellularAvailable() && mIsSatelliteAllowedInCurrentLocation.get() - && mSatelliteController.isSatelliteProvisioned( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) + && mSatelliteController.isSatelliteProvisioned() && shouldTrackCall(mEmergencyConnection.getState())) { logd("handleTimeoutEvent: Sending EVENT_DISPLAY_SOS_MESSAGE to Dialer..."); mEmergencyConnection.sendConnectionEvent(Call.EVENT_DISPLAY_SOS_MESSAGE, null); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index be252f4dcc..5ec69d68cf 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -91,6 +91,7 @@ public class SatelliteSessionController extends StateMachine { private final long mSatelliteStayAtListeningFromSendingMillis; private final long mSatelliteStayAtListeningFromReceivingMillis; private final ConcurrentHashMap mListeners; + @SatelliteManager.SatelliteModemState private int mCurrentState; /** * @return The singleton instance of SatelliteSessionController. @@ -147,6 +148,7 @@ public class SatelliteSessionController extends StateMachine { mSatelliteStayAtListeningFromReceivingMillis = satelliteStayAtListeningFromReceivingMillis; mListeners = new ConcurrentHashMap<>(); mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; addState(mUnavailableState); addState(mPowerOffState); @@ -192,7 +194,12 @@ public class SatelliteSessionController extends StateMachine { * @param callback The callback to handle the satellite modem state changed event. */ public void registerForSatelliteModemStateChanged(@NonNull ISatelliteStateCallback callback) { - mListeners.put(callback.asBinder(), callback); + try { + callback.onSatelliteModemStateChanged(mCurrentState); + mListeners.put(callback.asBinder(), callback); + } catch (RemoteException ex) { + loge("registerForSatelliteModemStateChanged: Got RemoteException ex=" + ex); + } } /** @@ -221,6 +228,7 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering UnavailableState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; } @Override @@ -234,6 +242,7 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering PowerOffState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_OFF; mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @@ -253,8 +262,6 @@ public class SatelliteSessionController extends StateMachine { private void handleSatelliteEnabledStateChanged(boolean on) { if (on) { transitionTo(mIdleState); - } else { - loge("PowerOffState: Unexpected satellite radio powered-off state changed event"); } } } @@ -263,6 +270,7 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering IdleState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE; mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE); } @@ -296,6 +304,7 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering TransferringState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); } @@ -333,8 +342,9 @@ public class SatelliteSessionController extends StateMachine { private class ListeningState extends State { @Override public void enter() { - if (DBG) logd("Entering TransferringState"); + if (DBG) logd("Entering ListeningState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_LISTENING; long timeoutMillis = updateListeningMode(true); sendMessageDelayed(EVENT_LISTENING_TIMER_TIMEOUT, timeoutMillis); mIsSendingTriggeredDuringTransferringState.set(false); diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java index 103156cd44..6aca800edd 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java @@ -93,17 +93,17 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); - when(mMockContext.getMainLooper()).thenReturn(Looper.getMainLooper()); + when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper()); when(mMockContext.getResources()).thenReturn(mResources); when(mResources.getString(com.android.internal.R.string.config_satellite_service_package)) .thenReturn(""); mTestSatelliteController = new TestSatelliteController(mMockContext, - Looper.getMainLooper()); + Looper.myLooper()); mTestImsManager = new TestImsManager( mMockContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null); mTestConnection = new TestConnection(CALL_ID); when(mPhone.getServiceState()).thenReturn(mServiceState); - mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.getMainLooper(), + mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.myLooper(), mTestSatelliteController, mTestImsManager, TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); @@ -118,12 +118,12 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testTimeoutBeforeEmergencyCallEnd() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); @@ -143,14 +143,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testImsRegistrationStateChangedBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestImsManager.sendImsRegistrationStateChangedEvent(true); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -158,11 +158,12 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); mTestImsManager.sendImsRegistrationStateChangedEvent(false); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); @@ -172,7 +173,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testSatelliteProvisionStateChangedBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -180,14 +181,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mTestSatelliteController.sendProvisionStateChangedEvent( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 2, 2, 2); @@ -196,7 +197,8 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); // Wait for the timeout to expires - waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -207,7 +209,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testEmergencyCallRedialBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -217,7 +219,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { when(newPhone.getServiceState()).thenReturn(mServiceState); when(newPhone.isImsRegistered()).thenReturn(false); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, newPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); @@ -234,9 +236,8 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertRegisterForStateChangedEventsTriggered(newPhone, 2, 2, 1); // Wait for the timeout to expires - long timeoutMillis = TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS - - EVENT_PROCESSING_TIME_MILLIS; - waitFor(timeoutMillis > 0 ? timeoutMillis : 0); + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); /** @@ -279,7 +280,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testOnEmergencyCallConnectionStateChangedWithWrongCallId() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -287,7 +288,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged( WRONG_CALL_ID, Connection.STATE_ACTIVE); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -299,7 +300,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { public void testSatelliteNotAllowedInCurrentLocation() { mTestSatelliteController.setIsSatelliteCommunicationAllowed(false); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); /** * We should have registered for the state change events abd started the timer when @@ -316,14 +317,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { private void testStopTrackingCallBeforeTimeout( @Connection.ConnectionState int connectionState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(CALL_ID, connectionState); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -335,14 +336,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @ServiceState.RegState int availableServiceState, @ServiceState.RegState int unavailableServiceState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.sendServiceStateChangedEvent(availableServiceState); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -350,11 +351,12 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); mTestSOSMessageRecommender.sendServiceStateChangedEvent(unavailableServiceState); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); @@ -380,14 +382,6 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { verify(phone, times(unregisterForCellularCount)).unregisterForServiceStateChanged(any()); } - private static void waitFor(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException ex) { - Log.e(TAG, "Thread.sleep() ex=" + ex); - } - } - private static class TestSatelliteController extends SatelliteController { private static final String TAG = "TestSatelliteController"; @@ -395,7 +389,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mProvisionStateChangedCallbacks; private int mRegisterForSatelliteProvisionStateChangedCalls = 0; private int mUnregisterForSatelliteProvisionStateChangedCalls = 0; - private final Map mSatelliteProvisionStates; + private boolean mIsSatelliteProvisioned = true; private boolean mIsSatelliteCommunicationAllowed = true; /** @@ -407,18 +401,15 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { protected TestSatelliteController(Context context, Looper looper) { super(context, looper); mProvisionStateChangedCallbacks = new HashMap<>(); - mSatelliteProvisionStates = new HashMap<>(); - mSatelliteProvisionStates.put(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); } @Override - public boolean isSatelliteProvisioned(int subId) { - Boolean provisioned = mSatelliteProvisionStates.get(subId); - return (provisioned != null) ? provisioned : false; + public Boolean isSatelliteProvisioned() { + return mIsSatelliteProvisioned; } @Override - public boolean isSatelliteSupported() { + public Boolean isSatelliteSupported() { return true; } @@ -466,7 +457,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { } public void sendProvisionStateChangedEvent(int subId, boolean provisioned) { - mSatelliteProvisionStates.put(subId, provisioned); + mIsSatelliteProvisioned = provisioned; Set perSubscriptionCallbacks = mProvisionStateChangedCallbacks.get(subId); if (perSubscriptionCallbacks != null) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java index 2b030421d3..3ccf512211 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java @@ -36,7 +36,6 @@ import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.SatelliteManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.util.Log; import com.android.internal.telephony.TelephonyTest; @@ -44,6 +43,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.Semaphore; @@ -70,22 +70,27 @@ public class SatelliteSessionControllerTest extends TelephonyTest { private TestSatelliteSessionController mTestSatelliteSessionController; private TestSatelliteStateCallback mTestSatelliteStateCallback; + @Mock + private SatelliteController mSatelliteController; + @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); mSatelliteModemInterface = new TestSatelliteModemInterface( - mContext, Looper.getMainLooper()); + mContext, mSatelliteController, Looper.myLooper()); mTestSatelliteSessionController = new TestSatelliteSessionController(mContext, - Looper.getMainLooper(), true, mSatelliteModemInterface, + Looper.myLooper(), true, mSatelliteModemInterface, TEST_SATELLITE_STAY_AT_LISTENING_MILLIS, TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); mTestSatelliteStateCallback = new TestSatelliteStateCallback(); mTestSatelliteSessionController.registerForSatelliteModemStateChanged( mTestSatelliteStateCallback); + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @After @@ -100,18 +105,20 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController1 = new TestSatelliteSessionController( - mContext, Looper.getMainLooper(), false, + mContext, Looper.myLooper(), false, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController1); + processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController1.getCurrentStateName()); /** * Since satellite is supported, SatelliteSessionController should move to POWER_OFF state. */ TestSatelliteSessionController sessionController2 = new TestSatelliteSessionController( - mContext, Looper.getMainLooper(), true, + mContext, Looper.myLooper(), true, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController2); + processAllMessages(); assertEquals(STATE_POWER_OFF, sessionController2.getCurrentStateName()); } @@ -122,9 +129,10 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController = new TestSatelliteSessionController( - mContext, Looper.getMainLooper(), false, + mContext, Looper.myLooper(), false, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController); + processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); /** @@ -132,7 +140,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * satellite radio powered-on state changed event. */ sessionController.onSatelliteEnabledStateChanged(true); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); } @@ -146,6 +154,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power on the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + processAllMessages(); // SatelliteSessionController should move to IDLE state after the modem is powered on. assertSuccessfulModemStateChangedCallback( @@ -155,6 +164,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power off the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); + processAllMessages(); // SatelliteSessionController should move back to POWER_OFF state. assertSuccessfulModemStateChangedCallback( @@ -164,6 +174,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power on the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + processAllMessages(); // SatelliteSessionController should move to IDLE state after radio is turned on. assertSuccessfulModemStateChangedCallback( @@ -174,6 +185,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Start sending datagrams mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -185,6 +197,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to IDLE state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -196,6 +209,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -207,6 +221,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -219,6 +234,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -230,6 +246,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Receiving datagrams is successful and done. mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -242,6 +259,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -254,6 +272,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); + processAllMessages(); // SatelliteSessionController should move to IDLE state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -265,6 +284,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -275,6 +295,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Receiving datagrams is successful and done. mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -284,7 +305,8 @@ public class SatelliteSessionControllerTest extends TelephonyTest { assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); // Wait for timeout - waitFor(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); + moveTimeForward(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); + processAllMessages(); // SatelliteSessionController should move to IDLE state after timeout assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -297,6 +319,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -308,6 +331,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state. assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); @@ -318,6 +342,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); + processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE // state. @@ -329,6 +354,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state. assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); @@ -339,6 +365,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE // state. @@ -348,6 +375,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power off the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); + processAllMessages(); // SatelliteSessionController should move to POWER_OFF state. assertSuccessfulModemStateChangedCallback( @@ -360,8 +388,9 @@ public class SatelliteSessionControllerTest extends TelephonyTest { private final AtomicInteger mListeningEnabledCount = new AtomicInteger(0); private final AtomicInteger mListeningDisabledCount = new AtomicInteger(0); - TestSatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { - super(context, looper); + TestSatelliteModemInterface(@NonNull Context context, + SatelliteController satelliteController, @NonNull Looper looper) { + super(context, satelliteController, looper); mExponentialBackoff.stop(); } @@ -444,14 +473,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { } } - private static void waitFor(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException ex) { - Log.e(TAG, "Thread.sleep() ex=" + ex); - } - } - private static void assertSuccessfulModemStateChangedCallback( TestSatelliteStateCallback callback, @SatelliteManager.SatelliteModemState int expectedModemState) { -- GitLab From 743f183c97d93008b3b94ea3cb410076912487cd Mon Sep 17 00:00:00 2001 From: Sooraj Sasindran Date: Fri, 24 Mar 2023 16:58:09 -0700 Subject: [PATCH 551/656] get smsc with phone identitiy to send message Get smsc with phone identitiy to send message to fill sms packet. No need to use caller privileges here as the intention is to get it if caller passed null. This will avoid throwing security exception for apps with only SMS permission for not having read privileged permission. Bug: 274708908 Test: NoReceiveSmsPermissionTest Change-Id: I4ba49166d4872e53fdc6fee0c1a5d7eab1be84c8 --- .../telephony/SmsDispatchersController.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java index 8150e4705e..d2dfcacdfb 100644 --- a/src/java/com/android/internal/telephony/SmsDispatchersController.java +++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java @@ -457,12 +457,17 @@ public class SmsDispatchersController extends Handler { } } - private String getSmscAddressFromUSIM(String callingPkg) { - IccSmsInterfaceManager iccSmsIntMgr = mPhone.getIccSmsInterfaceManager(); - if (iccSmsIntMgr != null) { - return iccSmsIntMgr.getSmscAddressFromIccEf(callingPkg); - } else { - Rlog.d(TAG, "getSmscAddressFromIccEf iccSmsIntMgr is null"); + private String getSmscAddressFromUSIMWithPhoneIdentity(String callingPkg) { + final long identity = Binder.clearCallingIdentity(); + try { + IccSmsInterfaceManager iccSmsIntMgr = mPhone.getIccSmsInterfaceManager(); + if (iccSmsIntMgr != null) { + return iccSmsIntMgr.getSmscAddressFromIccEf(callingPkg); + } else { + Rlog.d(TAG, "getSmscAddressFromIccEf iccSmsIntMgr is null"); + } + } finally { + Binder.restoreCallingIdentity(identity); } return null; } @@ -1300,7 +1305,7 @@ public class SmsDispatchersController extends Handler { protected void sendData(String callingPackage, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm) { if (TextUtils.isEmpty(scAddr)) { - scAddr = getSmscAddressFromUSIM(callingPackage); + scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPackage); } if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { @@ -1539,7 +1544,7 @@ public class SmsDispatchersController extends Handler { int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId, boolean skipShortCodeCheck) { if (TextUtils.isEmpty(scAddr)) { - scAddr = getSmscAddressFromUSIM(callingPkg); + scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg); } if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { @@ -1688,7 +1693,7 @@ public class SmsDispatchersController extends Handler { boolean persistMessage, int priority, boolean expectMore, int validityPeriod, long messageId) { if (TextUtils.isEmpty(scAddr)) { - scAddr = getSmscAddressFromUSIM(callingPkg); + scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg); } if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) { -- GitLab From bd273e5a00dc4f851488b36c224a942a4bcf3c78 Mon Sep 17 00:00:00 2001 From: Grant Menke Date: Thu, 23 Mar 2023 13:27:18 -0700 Subject: [PATCH 552/656] Ensure MERGE_COMPLETE connection event propagates for IMS conferences. The connection event MERGE_COMPLETE was not propgating nor getting logged to the dumpsys as it was being invoked after the original calls had been diconnected in favor of the conference call and thus the listeners were removed at that point. This change ensures the MERGE_COMPLETE connection event properly propagates and logs to the dumpsys before both the original background call and foreground call are disconnected in favor of the conference call for IMS conferences. Bug: 265187856 Test: Manually create IMS conference call. Ensure MERGE_COMPLETE logs to the dumpsys for each of the original calls at time of merge. Change-Id: I2f3b9759c987434afa837863a9cebab16521fb55 --- .../internal/telephony/imsphone/ImsPhoneCallTracker.java | 6 ++++++ .../internal/telephony/imsphone/ImsPhoneConnection.java | 1 - .../telephony/imsphone/ImsPhoneCallTrackerTest.java | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index c567574145..688fa62318 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -3700,6 +3700,12 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { cause = DisconnectCause.IMS_MERGED_SUCCESSFULLY; } + // Ensure the background call is correctly marked as MERGE_COMPLETE before it is + // disconnected as part of the IMS merge conference process: + if (cause == DisconnectCause.IMS_MERGED_SUCCESSFULLY && conn != null) { + conn.onConnectionEvent(android.telecom.Connection.EVENT_MERGE_COMPLETE, null); + } + EmergencyNumberTracker emergencyNumberTracker = null; EmergencyNumber num = null; diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java index b10c457d96..b984d84e9e 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java @@ -1593,7 +1593,6 @@ public class ImsPhoneConnection extends Connection implements */ public void handleMergeComplete() { mIsMergeInProcess = false; - onConnectionEvent(android.telecom.Connection.EVENT_MERGE_COMPLETE, null); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 41890e9409..97d6ba20b6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -1666,7 +1666,9 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { } }); ImsCall call = connection.getImsCall(); - call.getListener().onCallMerged(call, null, false); + call.getListener().onCallTerminated( + call, new ImsReasonInfo( + ImsReasonInfo.CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE, 0)); assertTrue(result[0]); } -- GitLab From 7503f4f34aee34f7a5f38c588234a7f91746a588 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Mon, 27 Mar 2023 21:20:30 +0000 Subject: [PATCH 553/656] Revert "Cache satellite service states and restructure callback ..." Revert submission 22148859-Cache satellite states Reason for revert: cause regression b/275274229 Reverted changes: /q/submissionid:22148859-Cache+satellite+states Change-Id: I1cacc082e574d58b922751d0106961b833f1d87a --- .../internal/telephony/CommandsInterface.java | 7 - .../com/android/internal/telephony/Phone.java | 8 - .../com/android/internal/telephony/RIL.java | 15 - .../satellite/DatagramController.java | 13 - .../telephony/satellite/DatagramReceiver.java | 4 + .../satellite/PointingAppController.java | 56 +- .../satellite/SatelliteController.java | 862 ++++++++---------- .../satellite/SatelliteModemInterface.java | 13 +- .../SatelliteSOSMessageRecommender.java | 3 +- .../satellite/SatelliteSessionController.java | 18 +- .../SatelliteSOSMessageRecommenderTest.java | 79 +- .../SatelliteSessionControllerTest.java | 59 +- 12 files changed, 470 insertions(+), 667 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 439b19b019..7314ccb823 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -3034,13 +3034,6 @@ public interface CommandsInterface { */ default void getSatellitePowerState(Message result) {} - /** - * Get satellite provision state. - * - * @param result Message that will be sent back to the requester - */ - default void getSatelliteProvisionState(Message result) {} - /** * Check whether satellite modem is supported by the device. * diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 34f1c51c4e..9f2513a4e5 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5315,14 +5315,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.isSatelliteSupported(result); } - /** - * Check whether the satellite modem is provisioned. - * @param result The Message to send the result of the operation to. - */ - public void isSatelliteProvisioned(Message result) { - mCi.getSatelliteProvisionState(result); - } - /** * Get the satellite capabilities. * @param result The Message to send the result of the operation to. diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 3987fb9986..8aff93b6ba 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5788,21 +5788,6 @@ public class RIL extends BaseCommands implements CommandsInterface { } } - /** - * Get satellite provision state. - * - * @param result Message that will be sent back to the requester - */ - @Override - public void getSatelliteProvisionState(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } - /** * Provision the subscription with a satellite provider. This is needed to register the * subscription if the provider allows dynamic registration. diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index d339cd11af..56ee8a6588 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -186,7 +186,6 @@ public class DatagramController { mSendErrorCode = errorCode; mPointingAppController.updateSendDatagramTransferState(subId, datagramTransferState, sendPendingCount, errorCode); - notifyDatagramTransferStateChangedToSessionController(); } /** @@ -211,7 +210,6 @@ public class DatagramController { mReceiveErrorCode = errorCode; mPointingAppController.updateReceiveDatagramTransferState(subId, datagramTransferState, receivePendingCount, errorCode); - notifyDatagramTransferStateChangedToSessionController(); } /** @@ -222,17 +220,6 @@ public class DatagramController { return mReceivePendingCount; } - private void notifyDatagramTransferStateChangedToSessionController() { - SatelliteSessionController sessionController = SatelliteSessionController.getInstance(); - if (sessionController == null) { - loge("notifyDatagramTransferStateChangeToSessionController: SatelliteSessionController" - + " is not initialized yet"); - } else { - sessionController.onDatagramTransferStateChanged( - mSendDatagramTransferState, mReceiveDatagramTransferState); - } - } - private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 117f32de86..82b3867deb 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -445,6 +445,8 @@ public class DatagramReceiver extends Handler { satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler( mBackgroundHandler.getLooper(), validSubId); if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + // TODO: remove this as SatelliteModemInterface can register for incoming datagrams + // on boot up itself. SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived( satelliteDatagramListenerHandler, SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null); @@ -543,4 +545,6 @@ public class DatagramReceiver extends Handler { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } + + // TODO: An api change - do not pass the binder from Telephony to Applications } diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java index dcfbe1f513..c37d1a05ba 100644 --- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -34,8 +34,6 @@ import android.text.TextUtils; import com.android.internal.telephony.Phone; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -116,7 +114,6 @@ public class PointingAppController { public static final int EVENT_POSITION_INFO_CHANGED = 1; public static final int EVENT_SEND_DATAGRAM_STATE_CHANGED = 2; public static final int EVENT_RECEIVE_DATAGRAM_STATE_CHANGED = 3; - public static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 4; private final ConcurrentHashMap mListeners; SatelliteTransmissionUpdateHandler(Looper looper) { @@ -142,64 +139,41 @@ public class PointingAppController { case EVENT_POSITION_INFO_CHANGED: { AsyncResult ar = (AsyncResult) msg.obj; PointingInfo pointingInfo = (PointingInfo) ar.result; - List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onSatellitePositionChanged(pointingInfo); } catch (RemoteException e) { logd("EVENT_POSITION_INFO_CHANGED RemoteException: " + e); - toBeRemoved.add(listener.asBinder()); } }); - toBeRemoved.forEach(listener -> { - mListeners.remove(listener); - }); - break; - } - - case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - logd("Receive EVENT_DATAGRAM_TRANSFER_STATE_CHANGED state=" + (int) ar.result); break; } case EVENT_SEND_DATAGRAM_STATE_CHANGED: { - logd("Received EVENT_SEND_DATAGRAM_STATE_CHANGED"); DatagramTransferStateHandlerRequest request = (DatagramTransferStateHandlerRequest) msg.obj; - List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onSendDatagramStateChanged(request.datagramTransferState, request.pendingCount, request.errorCode); } catch (RemoteException e) { logd("EVENT_SEND_DATAGRAM_STATE_CHANGED RemoteException: " + e); - toBeRemoved.add(listener.asBinder()); } }); - toBeRemoved.forEach(listener -> { - mListeners.remove(listener); - }); break; } case EVENT_RECEIVE_DATAGRAM_STATE_CHANGED: { - logd("Received EVENT_RECEIVE_DATAGRAM_STATE_CHANGED"); DatagramTransferStateHandlerRequest request = (DatagramTransferStateHandlerRequest) msg.obj; - List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onReceiveDatagramStateChanged(request.datagramTransferState, request.pendingCount, request.errorCode); } catch (RemoteException e) { logd("EVENT_RECEIVE_DATAGRAM_STATE_CHANGED RemoteException: " + e); - toBeRemoved.add(listener.asBinder()); } }); - toBeRemoved.forEach(listener -> { - mListeners.remove(listener); - }); break; } @@ -230,13 +204,18 @@ public class PointingAppController { SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged( handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + /** + * TODO: Need to remove this call, Datagram transfer state should come from the + * DatagramController based upon Transfer state. + * Modem won't be able to provide this info + */ SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged( handler, - SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, - null); + SatelliteTransmissionUpdateHandler.EVENT_SEND_DATAGRAM_STATE_CHANGED, null); } else { phone.registerForSatellitePositionInfoChanged(handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + // TODO: registerForDatagramTransferStateChanged through SatelliteController } } } @@ -258,6 +237,13 @@ public class PointingAppController { handler.removeListener(callback); if (handler.hasListeners()) { + /** + * TODO (b/269194948): If the calling apps crash, the handler will always have some + * listener. That is, we will not request modem to stop position update and + * cleaning our resources. We need to monitor the calling apps and clean up the + * resources when the apps die. We need to do this for other satellite callbacks + * as well. + */ result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; } @@ -274,6 +260,7 @@ public class PointingAppController { return; } phone.unregisterForSatellitePositionInfoChanged(handler); + // TODO: unregisterForDatagramTransferStateChanged through SatelliteController } } } @@ -289,9 +276,6 @@ public class PointingAppController { public void startSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) { if (mStartedSatelliteTransmissionUpdates) { logd("startSatelliteTransmissionUpdates: already started"); - AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_ERROR_NONE)); - message.sendToTarget(); return; } if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { @@ -336,17 +320,7 @@ public class PointingAppController { public void startPointingUI(boolean needFullScreenPointingUI) { String packageName = TextUtils.emptyIfNull(mContext.getResources() .getString(com.android.internal.R.string.config_pointing_ui_package)); - if (TextUtils.isEmpty(packageName)) { - logd("startPointingUI: config_pointing_ui_package is not set. Ignore the request"); - return; - } - Intent launchIntent = mContext.getPackageManager().getLaunchIntentForPackage(packageName); - if (launchIntent == null) { - loge("startPointingUI: launchIntent is null"); - return; - } - launchIntent.putExtra("needFullScreen", needFullScreenPointingUI); mContext.startActivity(launchIntent); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 8d1b9223e0..ca76d16c2a 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.net.wifi.WifiManager; import android.os.AsyncResult; +import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; @@ -49,12 +50,12 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** @@ -92,11 +93,6 @@ public class SatelliteController extends Handler { private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 21; private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 22; private static final int EVENT_RADIO_STATE_CHANGED = 23; - private static final int CMD_IS_SATELLITE_PROVISIONED = 24; - private static final int EVENT_IS_SATELLITE_PROVISIONED_DONE = 25; - private static final int EVENT_SATELLITE_PROVISION_STATE_CHANGED = 26; - private static final int EVENT_PENDING_DATAGRAMS = 27; - private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 28; @NonNull private static SatelliteController sInstance; @NonNull private final Context mContext; @@ -114,18 +110,6 @@ public class SatelliteController extends Handler { private static final String KEY_WIFI_DISABLED_BY_SCO = "wifi_disabled_by_sco"; boolean mDisabledBTFlag = false; boolean mDisabledWifiFlag = false; - private final AtomicBoolean mRegisteredForProvisionStateChangedWithSatelliteService = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForProvisionStateChangedWithPhone = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForPendingDatagramCountWithSatelliteService = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForPendingDatagramCountWithPhone = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithPhone = - new AtomicBoolean(false); /** * Map key: subId, value: callback to get error code of the provision request. */ @@ -133,20 +117,24 @@ public class SatelliteController extends Handler { new ConcurrentHashMap<>(); /** - * Map key: binder of the callback, value: callback to receive provision state changed events. + * Map key: subId, value: SatelliteProvisionStateChangedHandler to notify registrants. */ - private final ConcurrentHashMap - mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>(); + private final ConcurrentHashMap + mSatelliteProvisionStateChangedHandlers = new ConcurrentHashMap<>(); + + /** + * Map key: subId, value: SatelliteStateListenerHandler to notify registrants. + */ + private final ConcurrentHashMap + mSatelliteStateListenerHandlers = new ConcurrentHashMap<>(); private Boolean mIsSatelliteSupported = null; private final Object mIsSatelliteSupportedLock = new Object(); + private final ResultReceiver mSatelliteSupportedReceiver; private boolean mIsDemoModeEnabled = false; private Boolean mIsSatelliteEnabled = null; private final Object mIsSatelliteEnabledLock = new Object(); - private Boolean mIsSatelliteProvisioned = null; - private final Object mIsSatelliteProvisionedLock = new Object(); - private SatelliteCapabilities mSatelliteCapabilities; - private final Object mSatelliteCapabilitiesLock = new Object(); + private final ResultReceiver mSatelliteEnabledReceiver; private boolean mNeedsSatellitePointing = false; private final Object mNeedsSatellitePointingLock = new Object(); @@ -187,7 +175,7 @@ public class SatelliteController extends Handler { mCi = phone.mCi; // Create the SatelliteModemInterface singleton, which is used to manage connections // to the satellite service and HAL interface. - mSatelliteModemInterface = SatelliteModemInterface.make(mContext, this); + mSatelliteModemInterface = SatelliteModemInterface.make(mContext); // Create the PointingUIController singleton, // which is used to manage interactions with PointingUI app. @@ -197,17 +185,13 @@ public class SatelliteController extends Handler { // which is used to send and receive satellite datagrams. mDatagramController = DatagramController.make(mContext, looper, mPointingAppController); - requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" + resultCode); - } - }); + mSatelliteEnabledReceiver = createSatelliteEnabledResultReceiver(); + mSatelliteSupportedReceiver = createSatelliteSupportedResultReceiver(looper); + //TODO: reenable below code + //requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + // mSatelliteSupportedReceiver); mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); - registerForSatelliteProvisionStateChanged(); - registerForPendingDatagramCount(); - registerForSatelliteModemStateChanged(); + try { mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); @@ -292,6 +276,116 @@ public class SatelliteController extends Handler { } } + private static final class SatelliteProvisionStateChangedHandler extends Handler { + public static final int EVENT_PROVISION_STATE_CHANGED = 1; + + private final ConcurrentHashMap mListeners; + private final int mSubId; + + SatelliteProvisionStateChangedHandler(Looper looper, int subId) { + super(looper); + mListeners = new ConcurrentHashMap<>(); + mSubId = subId; + } + + public void addListener(ISatelliteProvisionStateCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatelliteProvisionStateCallback listener) { + mListeners.remove(listener.asBinder()); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_PROVISION_STATE_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + boolean provisioned = (boolean) ar.userObj; + logd("Received EVENT_PROVISION_STATE_CHANGED for subId=" + mSubId + + ", provisioned=" + provisioned); + mListeners.values().forEach(listener -> { + try { + listener.onSatelliteProvisionStateChanged(provisioned); + } catch (RemoteException e) { + logd("EVENT_PROVISION_STATE_CHANGED RemoteException: " + e); + } + }); + + setSatelliteProvisioned(provisioned); + /** + * TODO: Take bugreport if provisioned is true and user did not initiate the + * provision procedure for the corresponding subscription. + */ + break; + } + default: + loge("SatelliteProvisionStateChangedHandler unknown event: " + msg.what); + } + } + + private void setSatelliteProvisioned(boolean isProvisioned) { + if (mSubId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + SubscriptionManager.setSubscriptionProperty( + mSubId, SubscriptionManager.SATELLITE_ENABLED, isProvisioned ? "1" : "0"); + } else { + //TODO (b/267826133): set via SatelliteController. + } + } + } + + private static final class SatelliteStateListenerHandler extends Handler { + public static final int EVENT_SATELLITE_MODEM_STATE_CHANGE = 1; + public static final int EVENT_PENDING_DATAGRAMS = 2; + + private final ConcurrentHashMap mListeners; + private final int mSubId; + + SatelliteStateListenerHandler(Looper looper, int subId) { + super(looper); + mSubId = subId; + mListeners = new ConcurrentHashMap<>(); + } + + public void addListener(ISatelliteStateCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatelliteStateCallback listener) { + mListeners.remove(listener.asBinder()); + } + + public boolean hasListeners() { + return !mListeners.isEmpty(); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_SATELLITE_MODEM_STATE_CHANGE : { + AsyncResult ar = (AsyncResult) msg.obj; + int state = (int) ar.result; + logd("Received EVENT_SATELLITE_MODEM_STATE_CHANGE for subId=" + mSubId + + ", state=" + state); + break; + } + case EVENT_PENDING_DATAGRAMS: { + logd("Received EVENT_PENDING_DATAGRAMS for subId=" + mSubId); + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("pollPendingSatelliteDatagram result: " + result); + } + }; + sInstance.pollPendingSatelliteDatagrams(mSubId, internalCallback); + break; + } + default: + loge("SatelliteStateListenerHandler unknown event: " + msg.what); + } + } + } + @Override public void handleMessage(Message msg) { SatelliteControllerHandlerRequest request; @@ -423,7 +517,8 @@ public class SatelliteController extends Handler { checkAndEnableBluetoothWifiState(); } /** - * TODO for NTN-based satellites: Check if satellite is acquired. + * TODO: check if Satellite is Acquired. + * Also need to call requestSatelliteCapabilities() if Satellite is enabled */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(false); @@ -433,6 +528,7 @@ public class SatelliteController extends Handler { argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); } argument.callback.accept(error); + // TODO: if error is ERROR_NONE, request satellite capabilities break; } @@ -468,7 +564,6 @@ public class SatelliteController extends Handler { boolean enabled = ((int[]) ar.result)[0] == 1; if (DBG) logd("isSatelliteEnabled: " + enabled); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled); - updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE"); } } ((ResultReceiver) request.argument).send(error, bundle); @@ -507,7 +602,9 @@ public class SatelliteController extends Handler { boolean supported = (boolean) ar.result; if (DBG) logd("isSatelliteSupported: " + supported); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported); - updateSatelliteSupportedState(supported); + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = supported; + } } } ((ResultReceiver) request.argument).send(error, bundle); @@ -550,9 +647,6 @@ public class SatelliteController extends Handler { if (DBG) logd("getSatelliteCapabilities: " + capabilities); bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, capabilities); - synchronized (mSatelliteCapabilitiesLock) { - mSatelliteCapabilities = capabilities; - } } } ((ResultReceiver) request.argument).send(error, bundle); @@ -665,101 +759,10 @@ public class SatelliteController extends Handler { new RequestSatelliteEnabledArgument(false, false, result); request = new SatelliteControllerHandlerRequest(message, phone); handleSatelliteEnabled(request); - } else { - if (!mSatelliteModemInterface.isSatelliteServiceSupported()) { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported == null) { - ResultReceiver receiver = new ResultReceiver(this) { - @Override - protected void onReceiveResult( - int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" - + resultCode); - } - }; - requestIsSatelliteSupported( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); - } - } - } else { - logd("EVENT_RADIO_STATE_CHANGED: Satellite vendor service is supported." - + " Ignored the event"); - } } break; } - case CMD_IS_SATELLITE_PROVISIONED: { - request = (SatelliteControllerHandlerRequest) msg.obj; - onCompleted = obtainMessage(EVENT_IS_SATELLITE_PROVISIONED_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.isSatelliteProvisioned(onCompleted); - } else { - loge("isSatelliteProvisioned: No phone object"); - ((ResultReceiver) request.argument).send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } - break; - } - - case EVENT_IS_SATELLITE_PROVISIONED_DONE: { - ar = (AsyncResult) msg.obj; - request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = SatelliteServiceUtils.getSatelliteError(ar, - "isSatelliteProvisioned"); - Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - if (ar.result == null) { - loge("isSatelliteProvisioned: result is null"); - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } else { - boolean provisioned = ((int[]) ar.result)[0] == 1; - if (DBG) logd("isSatelliteProvisioned: " + provisioned); - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, provisioned); - synchronized (mIsSatelliteProvisionedLock) { - mIsSatelliteProvisioned = provisioned; - } - } - } - ((ResultReceiver) request.argument).send(error, bundle); - break; - } - - case EVENT_SATELLITE_PROVISION_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - if (ar.result == null) { - loge("EVENT_SATELLITE_PROVISION_STATE_CHANGED: result is null"); - } else { - handleEventSatelliteProvisionStateChanged((boolean) ar.result); - } - break; - - case EVENT_PENDING_DATAGRAMS: - logd("Received EVENT_PENDING_DATAGRAMS"); - IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - logd("pollPendingSatelliteDatagram result: " + result); - } - }; - pollPendingSatelliteDatagrams( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, internalCallback); - break; - - case EVENT_SATELLITE_MODEM_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - if (ar.result == null) { - loge("EVENT_SATELLITE_MODEM_STATE_CHANGED: result is null"); - } else { - handleEventSatelliteModemStateChanged((int) ar.result); - } - break; - default: Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " + msg.what); @@ -787,29 +790,22 @@ public class SatelliteController extends Handler { public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + // TODO: clean up this dependency on subId + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_SET_SATELLITE_ENABLED, new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result), - SatelliteServiceUtils.getPhone()); + phone); } /** @@ -820,13 +816,14 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + if (!isSatelliteSupported()) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - if (!satelliteSupported) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { + result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -840,7 +837,7 @@ public class SatelliteController extends Handler { } } - sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); + sendRequest(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); } /** @@ -852,22 +849,13 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -906,27 +894,13 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - synchronized (mSatelliteCapabilitiesLock) { - if (mSatelliteCapabilities != null) { - Bundle bundle = new Bundle(); - bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, - mSatelliteCapabilities); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); - return; - } - } - - sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, SatelliteServiceUtils.getPhone()); + Phone phone = SatelliteServiceUtils.getPhone(); + sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, phone); } /** @@ -942,28 +916,18 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } Phone phone = SatelliteServiceUtils.getPhone(); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback, phone); sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES, new SatelliteTransmissionUpdateArgument(result, callback, validSubId), phone); @@ -981,28 +945,18 @@ public class SatelliteController extends Handler { public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } Phone phone = SatelliteServiceUtils.getPhone(); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.unregisterForSatelliteTransmissionUpdates( validSubId, result, callback, phone); @@ -1028,29 +982,24 @@ public class SatelliteController extends Handler { @Nullable public ICancellationSignal provisionSatelliteService(int subId, @NonNull String token, @NonNull String regionId, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return null; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return null; } final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + Phone phone = SatelliteServiceUtils.getPhone(); + if (mSatelliteProvisionCallbacks.containsKey(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS); return null; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned != null && satelliteProvisioned) { + if (isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return null; } - Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, regionId, result, validSubId), phone); @@ -1077,28 +1026,18 @@ public class SatelliteController extends Handler { public void deprovisionSatelliteService(int subId, @NonNull String token, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; } Phone phone = SatelliteServiceUtils.getPhone(); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, null, result, validSubId), phone); } @@ -1113,15 +1052,34 @@ public class SatelliteController extends Handler { */ @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId, @NonNull ISatelliteProvisionStateCallback callback) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { return SatelliteManager.SATELLITE_NOT_SUPPORTED; } - mSatelliteProvisionStateChangedListeners.put(callback.asBinder(), callback); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + Phone phone = SatelliteServiceUtils.getPhone(); + + SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = + mSatelliteProvisionStateChangedHandlers.get(validSubId); + if (satelliteProvisionStateChangedHandler == null) { + satelliteProvisionStateChangedHandler = new SatelliteProvisionStateChangedHandler( + Looper.getMainLooper(), validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( + satelliteProvisionStateChangedHandler, + SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); + } else { + phone.registerForSatelliteProvisionStateChanged( + satelliteProvisionStateChangedHandler, + SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); + } + } + + if (callback != null) { + satelliteProvisionStateChangedHandler.addListener(callback); + } + mSatelliteProvisionStateChangedHandlers.put( + validSubId, satelliteProvisionStateChangedHandler); return SatelliteManager.SATELLITE_ERROR_NONE; } @@ -1135,7 +1093,12 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback) { - mSatelliteProvisionStateChangedListeners.remove(callback.asBinder()); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = + mSatelliteProvisionStateChangedHandlers.get(validSubId); + if (satelliteProvisionStateChangedHandler != null) { + satelliteProvisionStateChangedHandler.removeListener(callback); + } } /** @@ -1147,27 +1110,16 @@ public class SatelliteController extends Handler { * request failed. */ public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - synchronized (mIsSatelliteProvisionedLock) { - if (mIsSatelliteProvisioned != null) { - Bundle bundle = new Bundle(); - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, - mIsSatelliteProvisioned); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); - return; - } - } - - sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, SatelliteServiceUtils.getPhone()); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + Bundle bundle = new Bundle(); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, + isSatelliteProvisioned(validSubId)); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); } /** @@ -1187,6 +1139,35 @@ public class SatelliteController extends Handler { + " is not initialized yet"); return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; } + + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + SatelliteStateListenerHandler satelliteStateListenerHandler = + mSatelliteStateListenerHandlers.get(validSubId); + if (satelliteStateListenerHandler == null) { + satelliteStateListenerHandler = new SatelliteStateListenerHandler( + Looper.getMainLooper(), validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatelliteModemStateChanged( + satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); + mSatelliteModemInterface.registerForPendingDatagrams(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone == null) { + loge("registerForSatelliteModemStateChanged: satellite phone is " + + "not initialized yet"); + return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } + phone.registerForSatelliteModemStateChanged(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); + phone.registerForPendingDatagramCount(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); + } + } + + satelliteStateListenerHandler.addListener(callback); + mSatelliteStateListenerHandlers.put(validSubId, satelliteStateListenerHandler); return SatelliteManager.SATELLITE_ERROR_NONE; } @@ -1200,6 +1181,25 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + SatelliteStateListenerHandler handler = mSatelliteStateListenerHandlers.get(validSubId); + if (handler != null) { + handler.removeListener(callback); + if (!handler.hasListeners()) { + mSatelliteStateListenerHandlers.remove(validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.unregisterForSatelliteModemStateChanged(handler); + mSatelliteModemInterface.unregisterForPendingDatagrams(handler); + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone != null) { + phone.unregisterForSatelliteModemStateChanged(handler); + phone.unregisterForPendingDatagramCount(handler); + } + } + } + } + if (mSatelliteSessionController != null) { mSatelliteSessionController.unregisterForSatelliteModemStateChanged(callback); } else { @@ -1246,20 +1246,16 @@ public class SatelliteController extends Handler { * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ public void pollPendingSatelliteDatagrams(int subId, @NonNull IIntegerConsumer callback) { + // TODO: return pending datagram count on success Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - mDatagramController.pollPendingSatelliteDatagrams(validSubId, result); + mDatagramController.pollPendingSatelliteDatagrams(subId, result); } /** @@ -1283,24 +1279,20 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } /** - * TODO for NTN-based satellites: Check if satellite is acquired. + * TODO: check if Satellite is Acquired. Also need to call requestSatelliteCapabilities() + * when Satellite is enabled */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(needFullScreenPointingUI); } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mDatagramController.sendSatelliteDatagram(validSubId, datagramType, datagram, needFullScreenPointingUI, result); } @@ -1316,18 +1308,13 @@ public class SatelliteController extends Handler { */ public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - sendRequestAsync( - CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, SatelliteServiceUtils.getPhone()); + Phone phone = SatelliteServiceUtils.getPhone(); + sendRequest(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, phone); } /** @@ -1338,22 +1325,13 @@ public class SatelliteController extends Handler { * be visible if the request is successful or an error code if the request failed. */ public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -1362,61 +1340,6 @@ public class SatelliteController extends Handler { sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); } - /** - * If we have not successfully queried the satellite modem for its satellite service support, - * we will retry the query one more time. Otherwise, we will return the cached result. - */ - public Boolean isSatelliteSupported() { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported != null) { - /* We have already successfully queried the satellite modem. */ - return mIsSatelliteSupported; - } - } - /** - * We have not successfully checked whether the modem supports satellite service. - * Thus, we need to retry it now. - */ - requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" + resultCode); - } - }); - return null; - } - - /** - * This function is used by {@link SatelliteModemInterface} to notify - * {@link SatelliteController} that the satellite vendor service was just connected. - *

- * {@link SatelliteController} will send requests to satellite modem to check whether it support - * satellite, whether it is powered on, and whether it is provisioned. - * {@link SatelliteController} will use these cached values to serve requests from its clients. - */ - void onSatelliteServiceConnected() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported == null) { - ResultReceiver receiver = new ResultReceiver(this) { - @Override - protected void onReceiveResult( - int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" - + resultCode); - } - }; - requestIsSatelliteSupported( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); - } - } - } else { - logd("onSatelliteServiceConnected: Satellite vendor service is not supported." - + " Ignored the event"); - } - } - private void handleEventProvisionSatelliteServiceDone( @NonNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteError int result) { @@ -1430,6 +1353,17 @@ public class SatelliteController extends Handler { return; } callback.accept(result); + + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + setSatelliteProvisioned(arg.subId, true); + } + + /** + * We need to update satellite provision status in SubscriptionController + * or SatelliteController. + * TODO (b/267826133) we need to do this for all subscriptions on the device. + */ + registerForSatelliteProvisionStateChanged(arg.subId, null); } private void handleEventDeprovisionSatelliteServiceDone( @@ -1445,6 +1379,10 @@ public class SatelliteController extends Handler { if (arg.callback != null) { arg.callback.accept(result); } + + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + setSatelliteProvisioned(arg.subId, false); + } } private void handleStartSatelliteTransmissionUpdatesDone(@NonNull AsyncResult ar) { @@ -1466,6 +1404,42 @@ public class SatelliteController extends Handler { } } + /** + * Set satellite provisioned for a subscription or the device. + * + * The permission {@link android.Manifest.permission#MODIFY_PHONE_STATE} will be enforced by + * {@link SubscriptionController} when setting satellite enabled for an active subscription. + * Otherwise, {@link android.Manifest.permission#SATELLITE_COMMUNICATION} will be enforced. + */ + private synchronized void setSatelliteProvisioned(int subId, boolean isEnabled) { + if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + SubscriptionManager.setSubscriptionProperty( + subId, SubscriptionManager.SATELLITE_ENABLED, isEnabled ? "1" : "0"); + } else { + //TODO (b/267826133): set via SatelliteController + } + } + + /** + * If we have not successfully queried the satellite modem for its satellite service support, + * we will retry the query one more time. Otherwise, we will return the queried result. + */ + public boolean isSatelliteSupported() { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported != null) { + /* We have already successfully queried the satellite modem. */ + return mIsSatelliteSupported; + } + } + /** + * We have not successfully checked whether the modem supports satellite service. + * Thus, we need to retry it now. + */ + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mSatelliteSupportedReceiver); + return false; + } + /** * Posts the specified command to be executed on the main thread and returns immediately. * @@ -1514,24 +1488,35 @@ public class SatelliteController extends Handler { /** * Check if satellite is provisioned for a subscription on the device. + * @param subId The subscription id. * @return true if satellite is provisioned on the given subscription else return false. */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected Boolean isSatelliteProvisioned() { - synchronized (mIsSatelliteProvisionedLock) { - if (mIsSatelliteProvisioned != null) { - return mIsSatelliteProvisioned; + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected boolean isSatelliteProvisioned(int subId) { + final long identity = Binder.clearCallingIdentity(); + try { + if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + String strResult = null; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + strResult = SubscriptionManagerService.getInstance() + .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED, + mContext.getOpPackageName(), mContext.getAttributionTag()); + } else { + strResult = SubscriptionController.getInstance() + .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED); + } + + if (strResult != null) { + int intResult = Integer.parseInt(strResult); + return (intResult == 1); + } + } else { + //TODO (b/267826133): check via SatelliteController } + } finally { + Binder.restoreCallingIdentity(identity); } - - requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); - } - }); - return null; + return false; } private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) { @@ -1552,39 +1537,39 @@ public class SatelliteController extends Handler { } } - private void updateSatelliteSupportedState(boolean supported) { - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = supported; - } - mSatelliteSessionController = SatelliteSessionController.make( - mContext, getLooper(), supported); - if (supported) { - registerForSatelliteProvisionStateChanged(); - registerForPendingDatagramCount(); - registerForSatelliteModemStateChanged(); + private ResultReceiver createSatelliteSupportedResultReceiver(@NonNull Looper looper) { + return new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE + && resultData.containsKey(SatelliteManager.KEY_SATELLITE_SUPPORTED)) { + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = resultData.getBoolean( + SatelliteManager.KEY_SATELLITE_SUPPORTED); + } + } + mSatelliteSessionController = SatelliteSessionController.make(mContext, looper, + mIsSatelliteSupported != null ? mIsSatelliteSupported : false); + if (mIsSatelliteSupported != null && mIsSatelliteSupported) { + requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mSatelliteEnabledReceiver); + } + } + }; + } - requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteEnabled: resultCode=" + resultCode); - } - }); - requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); - } - }); - requestSatelliteCapabilities(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestSatelliteCapabilities: resultCode=" + resultCode); - } - }); - } + private ResultReceiver createSatelliteEnabledResultReceiver() { + return new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE + && resultData.containsKey(SatelliteManager.KEY_SATELLITE_ENABLED)) { + updateSatelliteEnabledState(resultData.getBoolean( + SatelliteManager.KEY_SATELLITE_ENABLED), + "SatelliteEnabledResultReceiver.onReceiveResult"); + } + } + }; } private void updateSatelliteEnabledState(boolean enabled, String caller) { @@ -1632,102 +1617,13 @@ public class SatelliteController extends Handler { if (DBG) logd("Enabling Bluetooth"); mBluetoothAdapter.enable(); mSharedPreferences.edit().putBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, false) - .apply(); + .apply(); } if (!mWifiManager.isWifiEnabled() && mDisabledWifiFlag) { if (DBG) logd("Enabling Wifi"); mWifiManager.setWifiEnabled(true); mSharedPreferences.edit().putBoolean(KEY_WIFI_DISABLED_BY_SCO, false) - .apply(); - } - } - - private void registerForSatelliteProvisionStateChanged() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - if (!mRegisteredForProvisionStateChangedWithSatelliteService.get()) { - mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( - this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); - mRegisteredForProvisionStateChangedWithSatelliteService.set(true); - } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForSatelliteProvisionStateChanged: phone is null"); - } else if (!mRegisteredForProvisionStateChangedWithPhone.get()) { - phone.registerForSatelliteProvisionStateChanged( - this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); - mRegisteredForProvisionStateChangedWithPhone.set(true); - } - } - } - - private void registerForPendingDatagramCount() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - if (!mRegisteredForPendingDatagramCountWithSatelliteService.get()) { - mSatelliteModemInterface.registerForPendingDatagrams( - this, EVENT_PENDING_DATAGRAMS, null); - mRegisteredForPendingDatagramCountWithSatelliteService.set(true); - } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForPendingDatagramCount: satellite phone is " - + "not initialized yet"); - } else if (!mRegisteredForPendingDatagramCountWithPhone.get()) { - phone.registerForPendingDatagramCount(this, EVENT_PENDING_DATAGRAMS, null); - mRegisteredForPendingDatagramCountWithPhone.set(true); - } - } - } - - private void registerForSatelliteModemStateChanged() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - if (!mRegisteredForSatelliteModemStateChangedWithSatelliteService.get()) { - mSatelliteModemInterface.registerForSatelliteModemStateChanged( - this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); - mRegisteredForSatelliteModemStateChangedWithSatelliteService.set(true); - } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForSatelliteModemStateChanged: satellite phone is " - + "not initialized yet"); - } else if (!mRegisteredForSatelliteModemStateChangedWithPhone.get()) { - phone.registerForSatelliteModemStateChanged( - this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); - mRegisteredForSatelliteModemStateChangedWithPhone.set(true); - } - } - } - - private void handleEventSatelliteProvisionStateChanged(boolean provisioned) { - logd("handleSatelliteProvisionStateChangedEvent: provisioned=" + provisioned); - - synchronized (mIsSatelliteProvisionedLock) { - mIsSatelliteProvisioned = provisioned; - } - - List toBeRemoved = new ArrayList<>(); - mSatelliteProvisionStateChangedListeners.values().forEach(listener -> { - try { - listener.onSatelliteProvisionStateChanged(provisioned); - } catch (RemoteException e) { - logd("handleSatelliteProvisionStateChangedEvent RemoteException: " + e); - toBeRemoved.add(listener); - } - }); - toBeRemoved.forEach(listener -> { - mSatelliteProvisionStateChangedListeners.remove(listener.asBinder()); - }); - } - - private void handleEventSatelliteModemStateChanged( - @SatelliteManager.SatelliteModemState int state) { - logd("handleEventSatelliteModemStateChanged: state=" + state); - if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF - || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { - updateSatelliteEnabledState( - false, "handleEventSatelliteModemStateChanged"); + .apply(); } } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 8657529183..cf2fc8593b 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -65,7 +65,6 @@ public class SatelliteModemInterface { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @NonNull protected final ExponentialBackoff mExponentialBackoff; @NonNull private final Object mLock = new Object(); - @NonNull private final SatelliteController mSatelliteController; /** * {@code true} to use the vendor satellite service and {@code false} to use the HAL. */ @@ -151,14 +150,11 @@ public class SatelliteModemInterface { /** * Create the SatelliteModemInterface singleton instance. * @param context The Context to use to create the SatelliteModemInterface. - * @param satelliteController The singleton instance of SatelliteController. * @return The singleton instance of SatelliteModemInterface. */ - public static SatelliteModemInterface make(@NonNull Context context, - SatelliteController satelliteController) { + public static SatelliteModemInterface make(@NonNull Context context) { if (sInstance == null) { - sInstance = new SatelliteModemInterface( - context, satelliteController, Looper.getMainLooper()); + sInstance = new SatelliteModemInterface(context, Looper.getMainLooper()); } return sInstance; } @@ -170,11 +166,9 @@ public class SatelliteModemInterface { * @param looper The Looper to run binding retry on. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - protected SatelliteModemInterface(@NonNull Context context, - SatelliteController satelliteController, @NonNull Looper looper) { + protected SatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { mContext = context; mIsSatelliteServiceSupported = getSatelliteServiceSupport(); - mSatelliteController = satelliteController; mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, REBIND_MULTIPLIER, looper, () -> { synchronized (mLock) { @@ -286,7 +280,6 @@ public class SatelliteModemInterface { // TODO: Retry setSatelliteListener logd("setSatelliteListener: RemoteException " + e); } - mSatelliteController.onSatelliteServiceConnected(); } @Override diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java index 1eeb5a21db..a1bd99ec72 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java @@ -255,7 +255,8 @@ public class SatelliteSOSMessageRecommender extends Handler { boolean isDialerNotified = false; if (!mIsImsRegistered.get() && !isCellularAvailable() && mIsSatelliteAllowedInCurrentLocation.get() - && mSatelliteController.isSatelliteProvisioned() + && mSatelliteController.isSatelliteProvisioned( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) && shouldTrackCall(mEmergencyConnection.getState())) { logd("handleTimeoutEvent: Sending EVENT_DISPLAY_SOS_MESSAGE to Dialer..."); mEmergencyConnection.sendConnectionEvent(Call.EVENT_DISPLAY_SOS_MESSAGE, null); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index 5ec69d68cf..be252f4dcc 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -91,7 +91,6 @@ public class SatelliteSessionController extends StateMachine { private final long mSatelliteStayAtListeningFromSendingMillis; private final long mSatelliteStayAtListeningFromReceivingMillis; private final ConcurrentHashMap mListeners; - @SatelliteManager.SatelliteModemState private int mCurrentState; /** * @return The singleton instance of SatelliteSessionController. @@ -148,7 +147,6 @@ public class SatelliteSessionController extends StateMachine { mSatelliteStayAtListeningFromReceivingMillis = satelliteStayAtListeningFromReceivingMillis; mListeners = new ConcurrentHashMap<>(); mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; addState(mUnavailableState); addState(mPowerOffState); @@ -194,12 +192,7 @@ public class SatelliteSessionController extends StateMachine { * @param callback The callback to handle the satellite modem state changed event. */ public void registerForSatelliteModemStateChanged(@NonNull ISatelliteStateCallback callback) { - try { - callback.onSatelliteModemStateChanged(mCurrentState); - mListeners.put(callback.asBinder(), callback); - } catch (RemoteException ex) { - loge("registerForSatelliteModemStateChanged: Got RemoteException ex=" + ex); - } + mListeners.put(callback.asBinder(), callback); } /** @@ -228,7 +221,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering UnavailableState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; } @Override @@ -242,7 +234,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering PowerOffState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_OFF; mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @@ -262,6 +253,8 @@ public class SatelliteSessionController extends StateMachine { private void handleSatelliteEnabledStateChanged(boolean on) { if (on) { transitionTo(mIdleState); + } else { + loge("PowerOffState: Unexpected satellite radio powered-off state changed event"); } } } @@ -270,7 +263,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering IdleState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE; mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE); } @@ -304,7 +296,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering TransferringState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); } @@ -342,9 +333,8 @@ public class SatelliteSessionController extends StateMachine { private class ListeningState extends State { @Override public void enter() { - if (DBG) logd("Entering ListeningState"); + if (DBG) logd("Entering TransferringState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_LISTENING; long timeoutMillis = updateListeningMode(true); sendMessageDelayed(EVENT_LISTENING_TIMER_TIMEOUT, timeoutMillis); mIsSendingTriggeredDuringTransferringState.set(false); diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java index 6aca800edd..103156cd44 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java @@ -93,17 +93,17 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); - when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper()); + when(mMockContext.getMainLooper()).thenReturn(Looper.getMainLooper()); when(mMockContext.getResources()).thenReturn(mResources); when(mResources.getString(com.android.internal.R.string.config_satellite_service_package)) .thenReturn(""); mTestSatelliteController = new TestSatelliteController(mMockContext, - Looper.myLooper()); + Looper.getMainLooper()); mTestImsManager = new TestImsManager( mMockContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null); mTestConnection = new TestConnection(CALL_ID); when(mPhone.getServiceState()).thenReturn(mServiceState); - mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.myLooper(), + mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.getMainLooper(), mTestSatelliteController, mTestImsManager, TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); @@ -118,12 +118,12 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testTimeoutBeforeEmergencyCallEnd() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); @@ -143,14 +143,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testImsRegistrationStateChangedBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestImsManager.sendImsRegistrationStateChangedEvent(true); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -158,12 +158,11 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); mTestImsManager.sendImsRegistrationStateChangedEvent(false); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); @@ -173,7 +172,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testSatelliteProvisionStateChangedBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -181,14 +180,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mTestSatelliteController.sendProvisionStateChangedEvent( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 2, 2, 2); @@ -197,8 +196,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -209,7 +207,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testEmergencyCallRedialBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -219,7 +217,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { when(newPhone.getServiceState()).thenReturn(mServiceState); when(newPhone.isImsRegistered()).thenReturn(false); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, newPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); @@ -236,8 +234,9 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertRegisterForStateChangedEventsTriggered(newPhone, 2, 2, 1); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + long timeoutMillis = TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS + - EVENT_PROCESSING_TIME_MILLIS; + waitFor(timeoutMillis > 0 ? timeoutMillis : 0); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); /** @@ -280,7 +279,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testOnEmergencyCallConnectionStateChangedWithWrongCallId() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -288,7 +287,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged( WRONG_CALL_ID, Connection.STATE_ACTIVE); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -300,7 +299,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { public void testSatelliteNotAllowedInCurrentLocation() { mTestSatelliteController.setIsSatelliteCommunicationAllowed(false); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); /** * We should have registered for the state change events abd started the timer when @@ -317,14 +316,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { private void testStopTrackingCallBeforeTimeout( @Connection.ConnectionState int connectionState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(CALL_ID, connectionState); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -336,14 +335,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @ServiceState.RegState int availableServiceState, @ServiceState.RegState int unavailableServiceState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.sendServiceStateChangedEvent(availableServiceState); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -351,12 +350,11 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); mTestSOSMessageRecommender.sendServiceStateChangedEvent(unavailableServiceState); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); @@ -382,6 +380,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { verify(phone, times(unregisterForCellularCount)).unregisterForServiceStateChanged(any()); } + private static void waitFor(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ex) { + Log.e(TAG, "Thread.sleep() ex=" + ex); + } + } + private static class TestSatelliteController extends SatelliteController { private static final String TAG = "TestSatelliteController"; @@ -389,7 +395,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mProvisionStateChangedCallbacks; private int mRegisterForSatelliteProvisionStateChangedCalls = 0; private int mUnregisterForSatelliteProvisionStateChangedCalls = 0; - private boolean mIsSatelliteProvisioned = true; + private final Map mSatelliteProvisionStates; private boolean mIsSatelliteCommunicationAllowed = true; /** @@ -401,15 +407,18 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { protected TestSatelliteController(Context context, Looper looper) { super(context, looper); mProvisionStateChangedCallbacks = new HashMap<>(); + mSatelliteProvisionStates = new HashMap<>(); + mSatelliteProvisionStates.put(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); } @Override - public Boolean isSatelliteProvisioned() { - return mIsSatelliteProvisioned; + public boolean isSatelliteProvisioned(int subId) { + Boolean provisioned = mSatelliteProvisionStates.get(subId); + return (provisioned != null) ? provisioned : false; } @Override - public Boolean isSatelliteSupported() { + public boolean isSatelliteSupported() { return true; } @@ -457,7 +466,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { } public void sendProvisionStateChangedEvent(int subId, boolean provisioned) { - mIsSatelliteProvisioned = provisioned; + mSatelliteProvisionStates.put(subId, provisioned); Set perSubscriptionCallbacks = mProvisionStateChangedCallbacks.get(subId); if (perSubscriptionCallbacks != null) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java index 3ccf512211..2b030421d3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java @@ -36,6 +36,7 @@ import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.SatelliteManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.Log; import com.android.internal.telephony.TelephonyTest; @@ -43,7 +44,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.Semaphore; @@ -70,27 +70,22 @@ public class SatelliteSessionControllerTest extends TelephonyTest { private TestSatelliteSessionController mTestSatelliteSessionController; private TestSatelliteStateCallback mTestSatelliteStateCallback; - @Mock - private SatelliteController mSatelliteController; - @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); mSatelliteModemInterface = new TestSatelliteModemInterface( - mContext, mSatelliteController, Looper.myLooper()); + mContext, Looper.getMainLooper()); mTestSatelliteSessionController = new TestSatelliteSessionController(mContext, - Looper.myLooper(), true, mSatelliteModemInterface, + Looper.getMainLooper(), true, mSatelliteModemInterface, TEST_SATELLITE_STAY_AT_LISTENING_MILLIS, TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); mTestSatelliteStateCallback = new TestSatelliteStateCallback(); mTestSatelliteSessionController.registerForSatelliteModemStateChanged( mTestSatelliteStateCallback); - assertSuccessfulModemStateChangedCallback( - mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @After @@ -105,20 +100,18 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController1 = new TestSatelliteSessionController( - mContext, Looper.myLooper(), false, + mContext, Looper.getMainLooper(), false, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController1); - processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController1.getCurrentStateName()); /** * Since satellite is supported, SatelliteSessionController should move to POWER_OFF state. */ TestSatelliteSessionController sessionController2 = new TestSatelliteSessionController( - mContext, Looper.myLooper(), true, + mContext, Looper.getMainLooper(), true, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController2); - processAllMessages(); assertEquals(STATE_POWER_OFF, sessionController2.getCurrentStateName()); } @@ -129,10 +122,9 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController = new TestSatelliteSessionController( - mContext, Looper.myLooper(), false, + mContext, Looper.getMainLooper(), false, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController); - processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); /** @@ -140,7 +132,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * satellite radio powered-on state changed event. */ sessionController.onSatelliteEnabledStateChanged(true); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); } @@ -154,7 +146,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power on the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); - processAllMessages(); // SatelliteSessionController should move to IDLE state after the modem is powered on. assertSuccessfulModemStateChangedCallback( @@ -164,7 +155,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power off the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); - processAllMessages(); // SatelliteSessionController should move back to POWER_OFF state. assertSuccessfulModemStateChangedCallback( @@ -174,7 +164,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power on the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); - processAllMessages(); // SatelliteSessionController should move to IDLE state after radio is turned on. assertSuccessfulModemStateChangedCallback( @@ -185,7 +174,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Start sending datagrams mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -197,7 +185,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to IDLE state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -209,7 +196,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -221,7 +207,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -234,7 +219,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -246,7 +230,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Receiving datagrams is successful and done. mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -259,7 +242,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -272,7 +254,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); - processAllMessages(); // SatelliteSessionController should move to IDLE state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -284,7 +265,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -295,7 +275,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Receiving datagrams is successful and done. mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -305,8 +284,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); // Wait for timeout - moveTimeForward(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); - processAllMessages(); + waitFor(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); // SatelliteSessionController should move to IDLE state after timeout assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -319,7 +297,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -331,7 +308,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state. assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); @@ -342,7 +318,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE // state. @@ -354,7 +329,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state. assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); @@ -365,7 +339,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE // state. @@ -375,7 +348,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power off the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); - processAllMessages(); // SatelliteSessionController should move to POWER_OFF state. assertSuccessfulModemStateChangedCallback( @@ -388,9 +360,8 @@ public class SatelliteSessionControllerTest extends TelephonyTest { private final AtomicInteger mListeningEnabledCount = new AtomicInteger(0); private final AtomicInteger mListeningDisabledCount = new AtomicInteger(0); - TestSatelliteModemInterface(@NonNull Context context, - SatelliteController satelliteController, @NonNull Looper looper) { - super(context, satelliteController, looper); + TestSatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { + super(context, looper); mExponentialBackoff.stop(); } @@ -473,6 +444,14 @@ public class SatelliteSessionControllerTest extends TelephonyTest { } } + private static void waitFor(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ex) { + Log.e(TAG, "Thread.sleep() ex=" + ex); + } + } + private static void assertSuccessfulModemStateChangedCallback( TestSatelliteStateCallback callback, @SatelliteManager.SatelliteModemState int expectedModemState) { -- GitLab From 07cf75036b32bc99fa96ae0c6126ec67b46b1813 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Mon, 27 Mar 2023 21:20:30 +0000 Subject: [PATCH 554/656] Revert "Cache satellite service states and restructure callback ..." Revert submission 22148859-Cache satellite states Reason for revert: cause regression b/275274229 Reverted changes: /q/submissionid:22148859-Cache+satellite+states (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:7503f4f34aee34f7a5f38c588234a7f91746a588) Merged-In: I1cacc082e574d58b922751d0106961b833f1d87a Change-Id: I1cacc082e574d58b922751d0106961b833f1d87a --- .../internal/telephony/CommandsInterface.java | 7 - .../com/android/internal/telephony/Phone.java | 8 - .../com/android/internal/telephony/RIL.java | 15 - .../satellite/DatagramController.java | 13 - .../telephony/satellite/DatagramReceiver.java | 4 + .../satellite/PointingAppController.java | 56 +- .../satellite/SatelliteController.java | 862 ++++++++---------- .../satellite/SatelliteModemInterface.java | 13 +- .../SatelliteSOSMessageRecommender.java | 3 +- .../satellite/SatelliteSessionController.java | 18 +- .../SatelliteSOSMessageRecommenderTest.java | 79 +- .../SatelliteSessionControllerTest.java | 59 +- 12 files changed, 470 insertions(+), 667 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 439b19b019..7314ccb823 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -3034,13 +3034,6 @@ public interface CommandsInterface { */ default void getSatellitePowerState(Message result) {} - /** - * Get satellite provision state. - * - * @param result Message that will be sent back to the requester - */ - default void getSatelliteProvisionState(Message result) {} - /** * Check whether satellite modem is supported by the device. * diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 34f1c51c4e..9f2513a4e5 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5315,14 +5315,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.isSatelliteSupported(result); } - /** - * Check whether the satellite modem is provisioned. - * @param result The Message to send the result of the operation to. - */ - public void isSatelliteProvisioned(Message result) { - mCi.getSatelliteProvisionState(result); - } - /** * Get the satellite capabilities. * @param result The Message to send the result of the operation to. diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 3987fb9986..8aff93b6ba 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5788,21 +5788,6 @@ public class RIL extends BaseCommands implements CommandsInterface { } } - /** - * Get satellite provision state. - * - * @param result Message that will be sent back to the requester - */ - @Override - public void getSatelliteProvisionState(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } - /** * Provision the subscription with a satellite provider. This is needed to register the * subscription if the provider allows dynamic registration. diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index d339cd11af..56ee8a6588 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -186,7 +186,6 @@ public class DatagramController { mSendErrorCode = errorCode; mPointingAppController.updateSendDatagramTransferState(subId, datagramTransferState, sendPendingCount, errorCode); - notifyDatagramTransferStateChangedToSessionController(); } /** @@ -211,7 +210,6 @@ public class DatagramController { mReceiveErrorCode = errorCode; mPointingAppController.updateReceiveDatagramTransferState(subId, datagramTransferState, receivePendingCount, errorCode); - notifyDatagramTransferStateChangedToSessionController(); } /** @@ -222,17 +220,6 @@ public class DatagramController { return mReceivePendingCount; } - private void notifyDatagramTransferStateChangedToSessionController() { - SatelliteSessionController sessionController = SatelliteSessionController.getInstance(); - if (sessionController == null) { - loge("notifyDatagramTransferStateChangeToSessionController: SatelliteSessionController" - + " is not initialized yet"); - } else { - sessionController.onDatagramTransferStateChanged( - mSendDatagramTransferState, mReceiveDatagramTransferState); - } - } - private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 117f32de86..82b3867deb 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -445,6 +445,8 @@ public class DatagramReceiver extends Handler { satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler( mBackgroundHandler.getLooper(), validSubId); if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + // TODO: remove this as SatelliteModemInterface can register for incoming datagrams + // on boot up itself. SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived( satelliteDatagramListenerHandler, SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null); @@ -543,4 +545,6 @@ public class DatagramReceiver extends Handler { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } + + // TODO: An api change - do not pass the binder from Telephony to Applications } diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java index dcfbe1f513..c37d1a05ba 100644 --- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -34,8 +34,6 @@ import android.text.TextUtils; import com.android.internal.telephony.Phone; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -116,7 +114,6 @@ public class PointingAppController { public static final int EVENT_POSITION_INFO_CHANGED = 1; public static final int EVENT_SEND_DATAGRAM_STATE_CHANGED = 2; public static final int EVENT_RECEIVE_DATAGRAM_STATE_CHANGED = 3; - public static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 4; private final ConcurrentHashMap mListeners; SatelliteTransmissionUpdateHandler(Looper looper) { @@ -142,64 +139,41 @@ public class PointingAppController { case EVENT_POSITION_INFO_CHANGED: { AsyncResult ar = (AsyncResult) msg.obj; PointingInfo pointingInfo = (PointingInfo) ar.result; - List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onSatellitePositionChanged(pointingInfo); } catch (RemoteException e) { logd("EVENT_POSITION_INFO_CHANGED RemoteException: " + e); - toBeRemoved.add(listener.asBinder()); } }); - toBeRemoved.forEach(listener -> { - mListeners.remove(listener); - }); - break; - } - - case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - logd("Receive EVENT_DATAGRAM_TRANSFER_STATE_CHANGED state=" + (int) ar.result); break; } case EVENT_SEND_DATAGRAM_STATE_CHANGED: { - logd("Received EVENT_SEND_DATAGRAM_STATE_CHANGED"); DatagramTransferStateHandlerRequest request = (DatagramTransferStateHandlerRequest) msg.obj; - List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onSendDatagramStateChanged(request.datagramTransferState, request.pendingCount, request.errorCode); } catch (RemoteException e) { logd("EVENT_SEND_DATAGRAM_STATE_CHANGED RemoteException: " + e); - toBeRemoved.add(listener.asBinder()); } }); - toBeRemoved.forEach(listener -> { - mListeners.remove(listener); - }); break; } case EVENT_RECEIVE_DATAGRAM_STATE_CHANGED: { - logd("Received EVENT_RECEIVE_DATAGRAM_STATE_CHANGED"); DatagramTransferStateHandlerRequest request = (DatagramTransferStateHandlerRequest) msg.obj; - List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onReceiveDatagramStateChanged(request.datagramTransferState, request.pendingCount, request.errorCode); } catch (RemoteException e) { logd("EVENT_RECEIVE_DATAGRAM_STATE_CHANGED RemoteException: " + e); - toBeRemoved.add(listener.asBinder()); } }); - toBeRemoved.forEach(listener -> { - mListeners.remove(listener); - }); break; } @@ -230,13 +204,18 @@ public class PointingAppController { SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged( handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + /** + * TODO: Need to remove this call, Datagram transfer state should come from the + * DatagramController based upon Transfer state. + * Modem won't be able to provide this info + */ SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged( handler, - SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, - null); + SatelliteTransmissionUpdateHandler.EVENT_SEND_DATAGRAM_STATE_CHANGED, null); } else { phone.registerForSatellitePositionInfoChanged(handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + // TODO: registerForDatagramTransferStateChanged through SatelliteController } } } @@ -258,6 +237,13 @@ public class PointingAppController { handler.removeListener(callback); if (handler.hasListeners()) { + /** + * TODO (b/269194948): If the calling apps crash, the handler will always have some + * listener. That is, we will not request modem to stop position update and + * cleaning our resources. We need to monitor the calling apps and clean up the + * resources when the apps die. We need to do this for other satellite callbacks + * as well. + */ result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; } @@ -274,6 +260,7 @@ public class PointingAppController { return; } phone.unregisterForSatellitePositionInfoChanged(handler); + // TODO: unregisterForDatagramTransferStateChanged through SatelliteController } } } @@ -289,9 +276,6 @@ public class PointingAppController { public void startSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) { if (mStartedSatelliteTransmissionUpdates) { logd("startSatelliteTransmissionUpdates: already started"); - AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_ERROR_NONE)); - message.sendToTarget(); return; } if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { @@ -336,17 +320,7 @@ public class PointingAppController { public void startPointingUI(boolean needFullScreenPointingUI) { String packageName = TextUtils.emptyIfNull(mContext.getResources() .getString(com.android.internal.R.string.config_pointing_ui_package)); - if (TextUtils.isEmpty(packageName)) { - logd("startPointingUI: config_pointing_ui_package is not set. Ignore the request"); - return; - } - Intent launchIntent = mContext.getPackageManager().getLaunchIntentForPackage(packageName); - if (launchIntent == null) { - loge("startPointingUI: launchIntent is null"); - return; - } - launchIntent.putExtra("needFullScreen", needFullScreenPointingUI); mContext.startActivity(launchIntent); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 8d1b9223e0..ca76d16c2a 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.net.wifi.WifiManager; import android.os.AsyncResult; +import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; @@ -49,12 +50,12 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** @@ -92,11 +93,6 @@ public class SatelliteController extends Handler { private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 21; private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 22; private static final int EVENT_RADIO_STATE_CHANGED = 23; - private static final int CMD_IS_SATELLITE_PROVISIONED = 24; - private static final int EVENT_IS_SATELLITE_PROVISIONED_DONE = 25; - private static final int EVENT_SATELLITE_PROVISION_STATE_CHANGED = 26; - private static final int EVENT_PENDING_DATAGRAMS = 27; - private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 28; @NonNull private static SatelliteController sInstance; @NonNull private final Context mContext; @@ -114,18 +110,6 @@ public class SatelliteController extends Handler { private static final String KEY_WIFI_DISABLED_BY_SCO = "wifi_disabled_by_sco"; boolean mDisabledBTFlag = false; boolean mDisabledWifiFlag = false; - private final AtomicBoolean mRegisteredForProvisionStateChangedWithSatelliteService = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForProvisionStateChangedWithPhone = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForPendingDatagramCountWithSatelliteService = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForPendingDatagramCountWithPhone = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithPhone = - new AtomicBoolean(false); /** * Map key: subId, value: callback to get error code of the provision request. */ @@ -133,20 +117,24 @@ public class SatelliteController extends Handler { new ConcurrentHashMap<>(); /** - * Map key: binder of the callback, value: callback to receive provision state changed events. + * Map key: subId, value: SatelliteProvisionStateChangedHandler to notify registrants. */ - private final ConcurrentHashMap - mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>(); + private final ConcurrentHashMap + mSatelliteProvisionStateChangedHandlers = new ConcurrentHashMap<>(); + + /** + * Map key: subId, value: SatelliteStateListenerHandler to notify registrants. + */ + private final ConcurrentHashMap + mSatelliteStateListenerHandlers = new ConcurrentHashMap<>(); private Boolean mIsSatelliteSupported = null; private final Object mIsSatelliteSupportedLock = new Object(); + private final ResultReceiver mSatelliteSupportedReceiver; private boolean mIsDemoModeEnabled = false; private Boolean mIsSatelliteEnabled = null; private final Object mIsSatelliteEnabledLock = new Object(); - private Boolean mIsSatelliteProvisioned = null; - private final Object mIsSatelliteProvisionedLock = new Object(); - private SatelliteCapabilities mSatelliteCapabilities; - private final Object mSatelliteCapabilitiesLock = new Object(); + private final ResultReceiver mSatelliteEnabledReceiver; private boolean mNeedsSatellitePointing = false; private final Object mNeedsSatellitePointingLock = new Object(); @@ -187,7 +175,7 @@ public class SatelliteController extends Handler { mCi = phone.mCi; // Create the SatelliteModemInterface singleton, which is used to manage connections // to the satellite service and HAL interface. - mSatelliteModemInterface = SatelliteModemInterface.make(mContext, this); + mSatelliteModemInterface = SatelliteModemInterface.make(mContext); // Create the PointingUIController singleton, // which is used to manage interactions with PointingUI app. @@ -197,17 +185,13 @@ public class SatelliteController extends Handler { // which is used to send and receive satellite datagrams. mDatagramController = DatagramController.make(mContext, looper, mPointingAppController); - requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" + resultCode); - } - }); + mSatelliteEnabledReceiver = createSatelliteEnabledResultReceiver(); + mSatelliteSupportedReceiver = createSatelliteSupportedResultReceiver(looper); + //TODO: reenable below code + //requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + // mSatelliteSupportedReceiver); mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); - registerForSatelliteProvisionStateChanged(); - registerForPendingDatagramCount(); - registerForSatelliteModemStateChanged(); + try { mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); @@ -292,6 +276,116 @@ public class SatelliteController extends Handler { } } + private static final class SatelliteProvisionStateChangedHandler extends Handler { + public static final int EVENT_PROVISION_STATE_CHANGED = 1; + + private final ConcurrentHashMap mListeners; + private final int mSubId; + + SatelliteProvisionStateChangedHandler(Looper looper, int subId) { + super(looper); + mListeners = new ConcurrentHashMap<>(); + mSubId = subId; + } + + public void addListener(ISatelliteProvisionStateCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatelliteProvisionStateCallback listener) { + mListeners.remove(listener.asBinder()); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_PROVISION_STATE_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + boolean provisioned = (boolean) ar.userObj; + logd("Received EVENT_PROVISION_STATE_CHANGED for subId=" + mSubId + + ", provisioned=" + provisioned); + mListeners.values().forEach(listener -> { + try { + listener.onSatelliteProvisionStateChanged(provisioned); + } catch (RemoteException e) { + logd("EVENT_PROVISION_STATE_CHANGED RemoteException: " + e); + } + }); + + setSatelliteProvisioned(provisioned); + /** + * TODO: Take bugreport if provisioned is true and user did not initiate the + * provision procedure for the corresponding subscription. + */ + break; + } + default: + loge("SatelliteProvisionStateChangedHandler unknown event: " + msg.what); + } + } + + private void setSatelliteProvisioned(boolean isProvisioned) { + if (mSubId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + SubscriptionManager.setSubscriptionProperty( + mSubId, SubscriptionManager.SATELLITE_ENABLED, isProvisioned ? "1" : "0"); + } else { + //TODO (b/267826133): set via SatelliteController. + } + } + } + + private static final class SatelliteStateListenerHandler extends Handler { + public static final int EVENT_SATELLITE_MODEM_STATE_CHANGE = 1; + public static final int EVENT_PENDING_DATAGRAMS = 2; + + private final ConcurrentHashMap mListeners; + private final int mSubId; + + SatelliteStateListenerHandler(Looper looper, int subId) { + super(looper); + mSubId = subId; + mListeners = new ConcurrentHashMap<>(); + } + + public void addListener(ISatelliteStateCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatelliteStateCallback listener) { + mListeners.remove(listener.asBinder()); + } + + public boolean hasListeners() { + return !mListeners.isEmpty(); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_SATELLITE_MODEM_STATE_CHANGE : { + AsyncResult ar = (AsyncResult) msg.obj; + int state = (int) ar.result; + logd("Received EVENT_SATELLITE_MODEM_STATE_CHANGE for subId=" + mSubId + + ", state=" + state); + break; + } + case EVENT_PENDING_DATAGRAMS: { + logd("Received EVENT_PENDING_DATAGRAMS for subId=" + mSubId); + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("pollPendingSatelliteDatagram result: " + result); + } + }; + sInstance.pollPendingSatelliteDatagrams(mSubId, internalCallback); + break; + } + default: + loge("SatelliteStateListenerHandler unknown event: " + msg.what); + } + } + } + @Override public void handleMessage(Message msg) { SatelliteControllerHandlerRequest request; @@ -423,7 +517,8 @@ public class SatelliteController extends Handler { checkAndEnableBluetoothWifiState(); } /** - * TODO for NTN-based satellites: Check if satellite is acquired. + * TODO: check if Satellite is Acquired. + * Also need to call requestSatelliteCapabilities() if Satellite is enabled */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(false); @@ -433,6 +528,7 @@ public class SatelliteController extends Handler { argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); } argument.callback.accept(error); + // TODO: if error is ERROR_NONE, request satellite capabilities break; } @@ -468,7 +564,6 @@ public class SatelliteController extends Handler { boolean enabled = ((int[]) ar.result)[0] == 1; if (DBG) logd("isSatelliteEnabled: " + enabled); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled); - updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE"); } } ((ResultReceiver) request.argument).send(error, bundle); @@ -507,7 +602,9 @@ public class SatelliteController extends Handler { boolean supported = (boolean) ar.result; if (DBG) logd("isSatelliteSupported: " + supported); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported); - updateSatelliteSupportedState(supported); + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = supported; + } } } ((ResultReceiver) request.argument).send(error, bundle); @@ -550,9 +647,6 @@ public class SatelliteController extends Handler { if (DBG) logd("getSatelliteCapabilities: " + capabilities); bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, capabilities); - synchronized (mSatelliteCapabilitiesLock) { - mSatelliteCapabilities = capabilities; - } } } ((ResultReceiver) request.argument).send(error, bundle); @@ -665,101 +759,10 @@ public class SatelliteController extends Handler { new RequestSatelliteEnabledArgument(false, false, result); request = new SatelliteControllerHandlerRequest(message, phone); handleSatelliteEnabled(request); - } else { - if (!mSatelliteModemInterface.isSatelliteServiceSupported()) { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported == null) { - ResultReceiver receiver = new ResultReceiver(this) { - @Override - protected void onReceiveResult( - int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" - + resultCode); - } - }; - requestIsSatelliteSupported( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); - } - } - } else { - logd("EVENT_RADIO_STATE_CHANGED: Satellite vendor service is supported." - + " Ignored the event"); - } } break; } - case CMD_IS_SATELLITE_PROVISIONED: { - request = (SatelliteControllerHandlerRequest) msg.obj; - onCompleted = obtainMessage(EVENT_IS_SATELLITE_PROVISIONED_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.isSatelliteProvisioned(onCompleted); - } else { - loge("isSatelliteProvisioned: No phone object"); - ((ResultReceiver) request.argument).send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } - break; - } - - case EVENT_IS_SATELLITE_PROVISIONED_DONE: { - ar = (AsyncResult) msg.obj; - request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = SatelliteServiceUtils.getSatelliteError(ar, - "isSatelliteProvisioned"); - Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - if (ar.result == null) { - loge("isSatelliteProvisioned: result is null"); - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } else { - boolean provisioned = ((int[]) ar.result)[0] == 1; - if (DBG) logd("isSatelliteProvisioned: " + provisioned); - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, provisioned); - synchronized (mIsSatelliteProvisionedLock) { - mIsSatelliteProvisioned = provisioned; - } - } - } - ((ResultReceiver) request.argument).send(error, bundle); - break; - } - - case EVENT_SATELLITE_PROVISION_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - if (ar.result == null) { - loge("EVENT_SATELLITE_PROVISION_STATE_CHANGED: result is null"); - } else { - handleEventSatelliteProvisionStateChanged((boolean) ar.result); - } - break; - - case EVENT_PENDING_DATAGRAMS: - logd("Received EVENT_PENDING_DATAGRAMS"); - IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - logd("pollPendingSatelliteDatagram result: " + result); - } - }; - pollPendingSatelliteDatagrams( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, internalCallback); - break; - - case EVENT_SATELLITE_MODEM_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - if (ar.result == null) { - loge("EVENT_SATELLITE_MODEM_STATE_CHANGED: result is null"); - } else { - handleEventSatelliteModemStateChanged((int) ar.result); - } - break; - default: Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " + msg.what); @@ -787,29 +790,22 @@ public class SatelliteController extends Handler { public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + // TODO: clean up this dependency on subId + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_SET_SATELLITE_ENABLED, new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result), - SatelliteServiceUtils.getPhone()); + phone); } /** @@ -820,13 +816,14 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + if (!isSatelliteSupported()) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - if (!satelliteSupported) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { + result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -840,7 +837,7 @@ public class SatelliteController extends Handler { } } - sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); + sendRequest(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); } /** @@ -852,22 +849,13 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -906,27 +894,13 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - synchronized (mSatelliteCapabilitiesLock) { - if (mSatelliteCapabilities != null) { - Bundle bundle = new Bundle(); - bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, - mSatelliteCapabilities); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); - return; - } - } - - sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, SatelliteServiceUtils.getPhone()); + Phone phone = SatelliteServiceUtils.getPhone(); + sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, phone); } /** @@ -942,28 +916,18 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } Phone phone = SatelliteServiceUtils.getPhone(); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback, phone); sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES, new SatelliteTransmissionUpdateArgument(result, callback, validSubId), phone); @@ -981,28 +945,18 @@ public class SatelliteController extends Handler { public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } Phone phone = SatelliteServiceUtils.getPhone(); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.unregisterForSatelliteTransmissionUpdates( validSubId, result, callback, phone); @@ -1028,29 +982,24 @@ public class SatelliteController extends Handler { @Nullable public ICancellationSignal provisionSatelliteService(int subId, @NonNull String token, @NonNull String regionId, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return null; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return null; } final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + Phone phone = SatelliteServiceUtils.getPhone(); + if (mSatelliteProvisionCallbacks.containsKey(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS); return null; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned != null && satelliteProvisioned) { + if (isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return null; } - Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, regionId, result, validSubId), phone); @@ -1077,28 +1026,18 @@ public class SatelliteController extends Handler { public void deprovisionSatelliteService(int subId, @NonNull String token, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; } Phone phone = SatelliteServiceUtils.getPhone(); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, null, result, validSubId), phone); } @@ -1113,15 +1052,34 @@ public class SatelliteController extends Handler { */ @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId, @NonNull ISatelliteProvisionStateCallback callback) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { return SatelliteManager.SATELLITE_NOT_SUPPORTED; } - mSatelliteProvisionStateChangedListeners.put(callback.asBinder(), callback); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + Phone phone = SatelliteServiceUtils.getPhone(); + + SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = + mSatelliteProvisionStateChangedHandlers.get(validSubId); + if (satelliteProvisionStateChangedHandler == null) { + satelliteProvisionStateChangedHandler = new SatelliteProvisionStateChangedHandler( + Looper.getMainLooper(), validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( + satelliteProvisionStateChangedHandler, + SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); + } else { + phone.registerForSatelliteProvisionStateChanged( + satelliteProvisionStateChangedHandler, + SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); + } + } + + if (callback != null) { + satelliteProvisionStateChangedHandler.addListener(callback); + } + mSatelliteProvisionStateChangedHandlers.put( + validSubId, satelliteProvisionStateChangedHandler); return SatelliteManager.SATELLITE_ERROR_NONE; } @@ -1135,7 +1093,12 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback) { - mSatelliteProvisionStateChangedListeners.remove(callback.asBinder()); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = + mSatelliteProvisionStateChangedHandlers.get(validSubId); + if (satelliteProvisionStateChangedHandler != null) { + satelliteProvisionStateChangedHandler.removeListener(callback); + } } /** @@ -1147,27 +1110,16 @@ public class SatelliteController extends Handler { * request failed. */ public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - synchronized (mIsSatelliteProvisionedLock) { - if (mIsSatelliteProvisioned != null) { - Bundle bundle = new Bundle(); - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, - mIsSatelliteProvisioned); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); - return; - } - } - - sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, SatelliteServiceUtils.getPhone()); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + Bundle bundle = new Bundle(); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, + isSatelliteProvisioned(validSubId)); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); } /** @@ -1187,6 +1139,35 @@ public class SatelliteController extends Handler { + " is not initialized yet"); return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; } + + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + SatelliteStateListenerHandler satelliteStateListenerHandler = + mSatelliteStateListenerHandlers.get(validSubId); + if (satelliteStateListenerHandler == null) { + satelliteStateListenerHandler = new SatelliteStateListenerHandler( + Looper.getMainLooper(), validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatelliteModemStateChanged( + satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); + mSatelliteModemInterface.registerForPendingDatagrams(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone == null) { + loge("registerForSatelliteModemStateChanged: satellite phone is " + + "not initialized yet"); + return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } + phone.registerForSatelliteModemStateChanged(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); + phone.registerForPendingDatagramCount(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); + } + } + + satelliteStateListenerHandler.addListener(callback); + mSatelliteStateListenerHandlers.put(validSubId, satelliteStateListenerHandler); return SatelliteManager.SATELLITE_ERROR_NONE; } @@ -1200,6 +1181,25 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + SatelliteStateListenerHandler handler = mSatelliteStateListenerHandlers.get(validSubId); + if (handler != null) { + handler.removeListener(callback); + if (!handler.hasListeners()) { + mSatelliteStateListenerHandlers.remove(validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.unregisterForSatelliteModemStateChanged(handler); + mSatelliteModemInterface.unregisterForPendingDatagrams(handler); + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone != null) { + phone.unregisterForSatelliteModemStateChanged(handler); + phone.unregisterForPendingDatagramCount(handler); + } + } + } + } + if (mSatelliteSessionController != null) { mSatelliteSessionController.unregisterForSatelliteModemStateChanged(callback); } else { @@ -1246,20 +1246,16 @@ public class SatelliteController extends Handler { * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ public void pollPendingSatelliteDatagrams(int subId, @NonNull IIntegerConsumer callback) { + // TODO: return pending datagram count on success Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - mDatagramController.pollPendingSatelliteDatagrams(validSubId, result); + mDatagramController.pollPendingSatelliteDatagrams(subId, result); } /** @@ -1283,24 +1279,20 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } /** - * TODO for NTN-based satellites: Check if satellite is acquired. + * TODO: check if Satellite is Acquired. Also need to call requestSatelliteCapabilities() + * when Satellite is enabled */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(needFullScreenPointingUI); } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mDatagramController.sendSatelliteDatagram(validSubId, datagramType, datagram, needFullScreenPointingUI, result); } @@ -1316,18 +1308,13 @@ public class SatelliteController extends Handler { */ public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - sendRequestAsync( - CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, SatelliteServiceUtils.getPhone()); + Phone phone = SatelliteServiceUtils.getPhone(); + sendRequest(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, phone); } /** @@ -1338,22 +1325,13 @@ public class SatelliteController extends Handler { * be visible if the request is successful or an error code if the request failed. */ public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -1362,61 +1340,6 @@ public class SatelliteController extends Handler { sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); } - /** - * If we have not successfully queried the satellite modem for its satellite service support, - * we will retry the query one more time. Otherwise, we will return the cached result. - */ - public Boolean isSatelliteSupported() { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported != null) { - /* We have already successfully queried the satellite modem. */ - return mIsSatelliteSupported; - } - } - /** - * We have not successfully checked whether the modem supports satellite service. - * Thus, we need to retry it now. - */ - requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" + resultCode); - } - }); - return null; - } - - /** - * This function is used by {@link SatelliteModemInterface} to notify - * {@link SatelliteController} that the satellite vendor service was just connected. - *

- * {@link SatelliteController} will send requests to satellite modem to check whether it support - * satellite, whether it is powered on, and whether it is provisioned. - * {@link SatelliteController} will use these cached values to serve requests from its clients. - */ - void onSatelliteServiceConnected() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported == null) { - ResultReceiver receiver = new ResultReceiver(this) { - @Override - protected void onReceiveResult( - int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" - + resultCode); - } - }; - requestIsSatelliteSupported( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); - } - } - } else { - logd("onSatelliteServiceConnected: Satellite vendor service is not supported." - + " Ignored the event"); - } - } - private void handleEventProvisionSatelliteServiceDone( @NonNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteError int result) { @@ -1430,6 +1353,17 @@ public class SatelliteController extends Handler { return; } callback.accept(result); + + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + setSatelliteProvisioned(arg.subId, true); + } + + /** + * We need to update satellite provision status in SubscriptionController + * or SatelliteController. + * TODO (b/267826133) we need to do this for all subscriptions on the device. + */ + registerForSatelliteProvisionStateChanged(arg.subId, null); } private void handleEventDeprovisionSatelliteServiceDone( @@ -1445,6 +1379,10 @@ public class SatelliteController extends Handler { if (arg.callback != null) { arg.callback.accept(result); } + + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + setSatelliteProvisioned(arg.subId, false); + } } private void handleStartSatelliteTransmissionUpdatesDone(@NonNull AsyncResult ar) { @@ -1466,6 +1404,42 @@ public class SatelliteController extends Handler { } } + /** + * Set satellite provisioned for a subscription or the device. + * + * The permission {@link android.Manifest.permission#MODIFY_PHONE_STATE} will be enforced by + * {@link SubscriptionController} when setting satellite enabled for an active subscription. + * Otherwise, {@link android.Manifest.permission#SATELLITE_COMMUNICATION} will be enforced. + */ + private synchronized void setSatelliteProvisioned(int subId, boolean isEnabled) { + if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + SubscriptionManager.setSubscriptionProperty( + subId, SubscriptionManager.SATELLITE_ENABLED, isEnabled ? "1" : "0"); + } else { + //TODO (b/267826133): set via SatelliteController + } + } + + /** + * If we have not successfully queried the satellite modem for its satellite service support, + * we will retry the query one more time. Otherwise, we will return the queried result. + */ + public boolean isSatelliteSupported() { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported != null) { + /* We have already successfully queried the satellite modem. */ + return mIsSatelliteSupported; + } + } + /** + * We have not successfully checked whether the modem supports satellite service. + * Thus, we need to retry it now. + */ + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mSatelliteSupportedReceiver); + return false; + } + /** * Posts the specified command to be executed on the main thread and returns immediately. * @@ -1514,24 +1488,35 @@ public class SatelliteController extends Handler { /** * Check if satellite is provisioned for a subscription on the device. + * @param subId The subscription id. * @return true if satellite is provisioned on the given subscription else return false. */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected Boolean isSatelliteProvisioned() { - synchronized (mIsSatelliteProvisionedLock) { - if (mIsSatelliteProvisioned != null) { - return mIsSatelliteProvisioned; + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected boolean isSatelliteProvisioned(int subId) { + final long identity = Binder.clearCallingIdentity(); + try { + if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + String strResult = null; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + strResult = SubscriptionManagerService.getInstance() + .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED, + mContext.getOpPackageName(), mContext.getAttributionTag()); + } else { + strResult = SubscriptionController.getInstance() + .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED); + } + + if (strResult != null) { + int intResult = Integer.parseInt(strResult); + return (intResult == 1); + } + } else { + //TODO (b/267826133): check via SatelliteController } + } finally { + Binder.restoreCallingIdentity(identity); } - - requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); - } - }); - return null; + return false; } private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) { @@ -1552,39 +1537,39 @@ public class SatelliteController extends Handler { } } - private void updateSatelliteSupportedState(boolean supported) { - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = supported; - } - mSatelliteSessionController = SatelliteSessionController.make( - mContext, getLooper(), supported); - if (supported) { - registerForSatelliteProvisionStateChanged(); - registerForPendingDatagramCount(); - registerForSatelliteModemStateChanged(); + private ResultReceiver createSatelliteSupportedResultReceiver(@NonNull Looper looper) { + return new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE + && resultData.containsKey(SatelliteManager.KEY_SATELLITE_SUPPORTED)) { + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = resultData.getBoolean( + SatelliteManager.KEY_SATELLITE_SUPPORTED); + } + } + mSatelliteSessionController = SatelliteSessionController.make(mContext, looper, + mIsSatelliteSupported != null ? mIsSatelliteSupported : false); + if (mIsSatelliteSupported != null && mIsSatelliteSupported) { + requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mSatelliteEnabledReceiver); + } + } + }; + } - requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteEnabled: resultCode=" + resultCode); - } - }); - requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); - } - }); - requestSatelliteCapabilities(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestSatelliteCapabilities: resultCode=" + resultCode); - } - }); - } + private ResultReceiver createSatelliteEnabledResultReceiver() { + return new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE + && resultData.containsKey(SatelliteManager.KEY_SATELLITE_ENABLED)) { + updateSatelliteEnabledState(resultData.getBoolean( + SatelliteManager.KEY_SATELLITE_ENABLED), + "SatelliteEnabledResultReceiver.onReceiveResult"); + } + } + }; } private void updateSatelliteEnabledState(boolean enabled, String caller) { @@ -1632,102 +1617,13 @@ public class SatelliteController extends Handler { if (DBG) logd("Enabling Bluetooth"); mBluetoothAdapter.enable(); mSharedPreferences.edit().putBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, false) - .apply(); + .apply(); } if (!mWifiManager.isWifiEnabled() && mDisabledWifiFlag) { if (DBG) logd("Enabling Wifi"); mWifiManager.setWifiEnabled(true); mSharedPreferences.edit().putBoolean(KEY_WIFI_DISABLED_BY_SCO, false) - .apply(); - } - } - - private void registerForSatelliteProvisionStateChanged() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - if (!mRegisteredForProvisionStateChangedWithSatelliteService.get()) { - mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( - this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); - mRegisteredForProvisionStateChangedWithSatelliteService.set(true); - } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForSatelliteProvisionStateChanged: phone is null"); - } else if (!mRegisteredForProvisionStateChangedWithPhone.get()) { - phone.registerForSatelliteProvisionStateChanged( - this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); - mRegisteredForProvisionStateChangedWithPhone.set(true); - } - } - } - - private void registerForPendingDatagramCount() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - if (!mRegisteredForPendingDatagramCountWithSatelliteService.get()) { - mSatelliteModemInterface.registerForPendingDatagrams( - this, EVENT_PENDING_DATAGRAMS, null); - mRegisteredForPendingDatagramCountWithSatelliteService.set(true); - } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForPendingDatagramCount: satellite phone is " - + "not initialized yet"); - } else if (!mRegisteredForPendingDatagramCountWithPhone.get()) { - phone.registerForPendingDatagramCount(this, EVENT_PENDING_DATAGRAMS, null); - mRegisteredForPendingDatagramCountWithPhone.set(true); - } - } - } - - private void registerForSatelliteModemStateChanged() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - if (!mRegisteredForSatelliteModemStateChangedWithSatelliteService.get()) { - mSatelliteModemInterface.registerForSatelliteModemStateChanged( - this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); - mRegisteredForSatelliteModemStateChangedWithSatelliteService.set(true); - } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForSatelliteModemStateChanged: satellite phone is " - + "not initialized yet"); - } else if (!mRegisteredForSatelliteModemStateChangedWithPhone.get()) { - phone.registerForSatelliteModemStateChanged( - this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); - mRegisteredForSatelliteModemStateChangedWithPhone.set(true); - } - } - } - - private void handleEventSatelliteProvisionStateChanged(boolean provisioned) { - logd("handleSatelliteProvisionStateChangedEvent: provisioned=" + provisioned); - - synchronized (mIsSatelliteProvisionedLock) { - mIsSatelliteProvisioned = provisioned; - } - - List toBeRemoved = new ArrayList<>(); - mSatelliteProvisionStateChangedListeners.values().forEach(listener -> { - try { - listener.onSatelliteProvisionStateChanged(provisioned); - } catch (RemoteException e) { - logd("handleSatelliteProvisionStateChangedEvent RemoteException: " + e); - toBeRemoved.add(listener); - } - }); - toBeRemoved.forEach(listener -> { - mSatelliteProvisionStateChangedListeners.remove(listener.asBinder()); - }); - } - - private void handleEventSatelliteModemStateChanged( - @SatelliteManager.SatelliteModemState int state) { - logd("handleEventSatelliteModemStateChanged: state=" + state); - if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF - || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { - updateSatelliteEnabledState( - false, "handleEventSatelliteModemStateChanged"); + .apply(); } } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 8657529183..cf2fc8593b 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -65,7 +65,6 @@ public class SatelliteModemInterface { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @NonNull protected final ExponentialBackoff mExponentialBackoff; @NonNull private final Object mLock = new Object(); - @NonNull private final SatelliteController mSatelliteController; /** * {@code true} to use the vendor satellite service and {@code false} to use the HAL. */ @@ -151,14 +150,11 @@ public class SatelliteModemInterface { /** * Create the SatelliteModemInterface singleton instance. * @param context The Context to use to create the SatelliteModemInterface. - * @param satelliteController The singleton instance of SatelliteController. * @return The singleton instance of SatelliteModemInterface. */ - public static SatelliteModemInterface make(@NonNull Context context, - SatelliteController satelliteController) { + public static SatelliteModemInterface make(@NonNull Context context) { if (sInstance == null) { - sInstance = new SatelliteModemInterface( - context, satelliteController, Looper.getMainLooper()); + sInstance = new SatelliteModemInterface(context, Looper.getMainLooper()); } return sInstance; } @@ -170,11 +166,9 @@ public class SatelliteModemInterface { * @param looper The Looper to run binding retry on. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - protected SatelliteModemInterface(@NonNull Context context, - SatelliteController satelliteController, @NonNull Looper looper) { + protected SatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { mContext = context; mIsSatelliteServiceSupported = getSatelliteServiceSupport(); - mSatelliteController = satelliteController; mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, REBIND_MULTIPLIER, looper, () -> { synchronized (mLock) { @@ -286,7 +280,6 @@ public class SatelliteModemInterface { // TODO: Retry setSatelliteListener logd("setSatelliteListener: RemoteException " + e); } - mSatelliteController.onSatelliteServiceConnected(); } @Override diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java index 1eeb5a21db..a1bd99ec72 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java @@ -255,7 +255,8 @@ public class SatelliteSOSMessageRecommender extends Handler { boolean isDialerNotified = false; if (!mIsImsRegistered.get() && !isCellularAvailable() && mIsSatelliteAllowedInCurrentLocation.get() - && mSatelliteController.isSatelliteProvisioned() + && mSatelliteController.isSatelliteProvisioned( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) && shouldTrackCall(mEmergencyConnection.getState())) { logd("handleTimeoutEvent: Sending EVENT_DISPLAY_SOS_MESSAGE to Dialer..."); mEmergencyConnection.sendConnectionEvent(Call.EVENT_DISPLAY_SOS_MESSAGE, null); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index 5ec69d68cf..be252f4dcc 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -91,7 +91,6 @@ public class SatelliteSessionController extends StateMachine { private final long mSatelliteStayAtListeningFromSendingMillis; private final long mSatelliteStayAtListeningFromReceivingMillis; private final ConcurrentHashMap mListeners; - @SatelliteManager.SatelliteModemState private int mCurrentState; /** * @return The singleton instance of SatelliteSessionController. @@ -148,7 +147,6 @@ public class SatelliteSessionController extends StateMachine { mSatelliteStayAtListeningFromReceivingMillis = satelliteStayAtListeningFromReceivingMillis; mListeners = new ConcurrentHashMap<>(); mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; addState(mUnavailableState); addState(mPowerOffState); @@ -194,12 +192,7 @@ public class SatelliteSessionController extends StateMachine { * @param callback The callback to handle the satellite modem state changed event. */ public void registerForSatelliteModemStateChanged(@NonNull ISatelliteStateCallback callback) { - try { - callback.onSatelliteModemStateChanged(mCurrentState); - mListeners.put(callback.asBinder(), callback); - } catch (RemoteException ex) { - loge("registerForSatelliteModemStateChanged: Got RemoteException ex=" + ex); - } + mListeners.put(callback.asBinder(), callback); } /** @@ -228,7 +221,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering UnavailableState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; } @Override @@ -242,7 +234,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering PowerOffState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_OFF; mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @@ -262,6 +253,8 @@ public class SatelliteSessionController extends StateMachine { private void handleSatelliteEnabledStateChanged(boolean on) { if (on) { transitionTo(mIdleState); + } else { + loge("PowerOffState: Unexpected satellite radio powered-off state changed event"); } } } @@ -270,7 +263,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering IdleState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE; mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE); } @@ -304,7 +296,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering TransferringState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); } @@ -342,9 +333,8 @@ public class SatelliteSessionController extends StateMachine { private class ListeningState extends State { @Override public void enter() { - if (DBG) logd("Entering ListeningState"); + if (DBG) logd("Entering TransferringState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_LISTENING; long timeoutMillis = updateListeningMode(true); sendMessageDelayed(EVENT_LISTENING_TIMER_TIMEOUT, timeoutMillis); mIsSendingTriggeredDuringTransferringState.set(false); diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java index 6aca800edd..103156cd44 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java @@ -93,17 +93,17 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); - when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper()); + when(mMockContext.getMainLooper()).thenReturn(Looper.getMainLooper()); when(mMockContext.getResources()).thenReturn(mResources); when(mResources.getString(com.android.internal.R.string.config_satellite_service_package)) .thenReturn(""); mTestSatelliteController = new TestSatelliteController(mMockContext, - Looper.myLooper()); + Looper.getMainLooper()); mTestImsManager = new TestImsManager( mMockContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null); mTestConnection = new TestConnection(CALL_ID); when(mPhone.getServiceState()).thenReturn(mServiceState); - mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.myLooper(), + mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.getMainLooper(), mTestSatelliteController, mTestImsManager, TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); @@ -118,12 +118,12 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testTimeoutBeforeEmergencyCallEnd() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); @@ -143,14 +143,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testImsRegistrationStateChangedBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestImsManager.sendImsRegistrationStateChangedEvent(true); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -158,12 +158,11 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); mTestImsManager.sendImsRegistrationStateChangedEvent(false); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); @@ -173,7 +172,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testSatelliteProvisionStateChangedBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -181,14 +180,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mTestSatelliteController.sendProvisionStateChangedEvent( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 2, 2, 2); @@ -197,8 +196,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -209,7 +207,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testEmergencyCallRedialBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -219,7 +217,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { when(newPhone.getServiceState()).thenReturn(mServiceState); when(newPhone.isImsRegistered()).thenReturn(false); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, newPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); @@ -236,8 +234,9 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertRegisterForStateChangedEventsTriggered(newPhone, 2, 2, 1); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + long timeoutMillis = TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS + - EVENT_PROCESSING_TIME_MILLIS; + waitFor(timeoutMillis > 0 ? timeoutMillis : 0); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); /** @@ -280,7 +279,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testOnEmergencyCallConnectionStateChangedWithWrongCallId() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -288,7 +287,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged( WRONG_CALL_ID, Connection.STATE_ACTIVE); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -300,7 +299,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { public void testSatelliteNotAllowedInCurrentLocation() { mTestSatelliteController.setIsSatelliteCommunicationAllowed(false); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); /** * We should have registered for the state change events abd started the timer when @@ -317,14 +316,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { private void testStopTrackingCallBeforeTimeout( @Connection.ConnectionState int connectionState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(CALL_ID, connectionState); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -336,14 +335,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @ServiceState.RegState int availableServiceState, @ServiceState.RegState int unavailableServiceState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.sendServiceStateChangedEvent(availableServiceState); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -351,12 +350,11 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); mTestSOSMessageRecommender.sendServiceStateChangedEvent(unavailableServiceState); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); @@ -382,6 +380,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { verify(phone, times(unregisterForCellularCount)).unregisterForServiceStateChanged(any()); } + private static void waitFor(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ex) { + Log.e(TAG, "Thread.sleep() ex=" + ex); + } + } + private static class TestSatelliteController extends SatelliteController { private static final String TAG = "TestSatelliteController"; @@ -389,7 +395,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mProvisionStateChangedCallbacks; private int mRegisterForSatelliteProvisionStateChangedCalls = 0; private int mUnregisterForSatelliteProvisionStateChangedCalls = 0; - private boolean mIsSatelliteProvisioned = true; + private final Map mSatelliteProvisionStates; private boolean mIsSatelliteCommunicationAllowed = true; /** @@ -401,15 +407,18 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { protected TestSatelliteController(Context context, Looper looper) { super(context, looper); mProvisionStateChangedCallbacks = new HashMap<>(); + mSatelliteProvisionStates = new HashMap<>(); + mSatelliteProvisionStates.put(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); } @Override - public Boolean isSatelliteProvisioned() { - return mIsSatelliteProvisioned; + public boolean isSatelliteProvisioned(int subId) { + Boolean provisioned = mSatelliteProvisionStates.get(subId); + return (provisioned != null) ? provisioned : false; } @Override - public Boolean isSatelliteSupported() { + public boolean isSatelliteSupported() { return true; } @@ -457,7 +466,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { } public void sendProvisionStateChangedEvent(int subId, boolean provisioned) { - mIsSatelliteProvisioned = provisioned; + mSatelliteProvisionStates.put(subId, provisioned); Set perSubscriptionCallbacks = mProvisionStateChangedCallbacks.get(subId); if (perSubscriptionCallbacks != null) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java index 3ccf512211..2b030421d3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java @@ -36,6 +36,7 @@ import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.SatelliteManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.Log; import com.android.internal.telephony.TelephonyTest; @@ -43,7 +44,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.Semaphore; @@ -70,27 +70,22 @@ public class SatelliteSessionControllerTest extends TelephonyTest { private TestSatelliteSessionController mTestSatelliteSessionController; private TestSatelliteStateCallback mTestSatelliteStateCallback; - @Mock - private SatelliteController mSatelliteController; - @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); mSatelliteModemInterface = new TestSatelliteModemInterface( - mContext, mSatelliteController, Looper.myLooper()); + mContext, Looper.getMainLooper()); mTestSatelliteSessionController = new TestSatelliteSessionController(mContext, - Looper.myLooper(), true, mSatelliteModemInterface, + Looper.getMainLooper(), true, mSatelliteModemInterface, TEST_SATELLITE_STAY_AT_LISTENING_MILLIS, TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); mTestSatelliteStateCallback = new TestSatelliteStateCallback(); mTestSatelliteSessionController.registerForSatelliteModemStateChanged( mTestSatelliteStateCallback); - assertSuccessfulModemStateChangedCallback( - mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @After @@ -105,20 +100,18 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController1 = new TestSatelliteSessionController( - mContext, Looper.myLooper(), false, + mContext, Looper.getMainLooper(), false, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController1); - processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController1.getCurrentStateName()); /** * Since satellite is supported, SatelliteSessionController should move to POWER_OFF state. */ TestSatelliteSessionController sessionController2 = new TestSatelliteSessionController( - mContext, Looper.myLooper(), true, + mContext, Looper.getMainLooper(), true, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController2); - processAllMessages(); assertEquals(STATE_POWER_OFF, sessionController2.getCurrentStateName()); } @@ -129,10 +122,9 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController = new TestSatelliteSessionController( - mContext, Looper.myLooper(), false, + mContext, Looper.getMainLooper(), false, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController); - processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); /** @@ -140,7 +132,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * satellite radio powered-on state changed event. */ sessionController.onSatelliteEnabledStateChanged(true); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); } @@ -154,7 +146,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power on the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); - processAllMessages(); // SatelliteSessionController should move to IDLE state after the modem is powered on. assertSuccessfulModemStateChangedCallback( @@ -164,7 +155,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power off the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); - processAllMessages(); // SatelliteSessionController should move back to POWER_OFF state. assertSuccessfulModemStateChangedCallback( @@ -174,7 +164,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power on the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); - processAllMessages(); // SatelliteSessionController should move to IDLE state after radio is turned on. assertSuccessfulModemStateChangedCallback( @@ -185,7 +174,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Start sending datagrams mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -197,7 +185,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to IDLE state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -209,7 +196,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -221,7 +207,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -234,7 +219,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -246,7 +230,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Receiving datagrams is successful and done. mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -259,7 +242,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -272,7 +254,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); - processAllMessages(); // SatelliteSessionController should move to IDLE state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -284,7 +265,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -295,7 +275,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Receiving datagrams is successful and done. mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -305,8 +284,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); // Wait for timeout - moveTimeForward(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); - processAllMessages(); + waitFor(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); // SatelliteSessionController should move to IDLE state after timeout assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -319,7 +297,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -331,7 +308,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state. assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); @@ -342,7 +318,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE // state. @@ -354,7 +329,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state. assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); @@ -365,7 +339,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE // state. @@ -375,7 +348,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power off the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); - processAllMessages(); // SatelliteSessionController should move to POWER_OFF state. assertSuccessfulModemStateChangedCallback( @@ -388,9 +360,8 @@ public class SatelliteSessionControllerTest extends TelephonyTest { private final AtomicInteger mListeningEnabledCount = new AtomicInteger(0); private final AtomicInteger mListeningDisabledCount = new AtomicInteger(0); - TestSatelliteModemInterface(@NonNull Context context, - SatelliteController satelliteController, @NonNull Looper looper) { - super(context, satelliteController, looper); + TestSatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { + super(context, looper); mExponentialBackoff.stop(); } @@ -473,6 +444,14 @@ public class SatelliteSessionControllerTest extends TelephonyTest { } } + private static void waitFor(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ex) { + Log.e(TAG, "Thread.sleep() ex=" + ex); + } + } + private static void assertSuccessfulModemStateChangedCallback( TestSatelliteStateCallback callback, @SatelliteManager.SatelliteModemState int expectedModemState) { -- GitLab From 0f97dee76f4eb10522fe437d73cca994a9cde6da Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Mon, 27 Mar 2023 21:20:30 +0000 Subject: [PATCH 555/656] Revert "Cache satellite service states and restructure callback ..." Revert submission 22148859-Cache satellite states Reason for revert: cause regression b/275274229 Reverted changes: /q/submissionid:22148859-Cache+satellite+states (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:7503f4f34aee34f7a5f38c588234a7f91746a588) Merged-In: I1cacc082e574d58b922751d0106961b833f1d87a Change-Id: I1cacc082e574d58b922751d0106961b833f1d87a --- .../internal/telephony/CommandsInterface.java | 7 - .../com/android/internal/telephony/Phone.java | 8 - .../com/android/internal/telephony/RIL.java | 15 - .../satellite/DatagramController.java | 13 - .../telephony/satellite/DatagramReceiver.java | 4 + .../satellite/PointingAppController.java | 56 +- .../satellite/SatelliteController.java | 862 ++++++++---------- .../satellite/SatelliteModemInterface.java | 13 +- .../SatelliteSOSMessageRecommender.java | 3 +- .../satellite/SatelliteSessionController.java | 18 +- .../SatelliteSOSMessageRecommenderTest.java | 79 +- .../SatelliteSessionControllerTest.java | 59 +- 12 files changed, 470 insertions(+), 667 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 439b19b019..7314ccb823 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -3034,13 +3034,6 @@ public interface CommandsInterface { */ default void getSatellitePowerState(Message result) {} - /** - * Get satellite provision state. - * - * @param result Message that will be sent back to the requester - */ - default void getSatelliteProvisionState(Message result) {} - /** * Check whether satellite modem is supported by the device. * diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 34f1c51c4e..9f2513a4e5 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5315,14 +5315,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.isSatelliteSupported(result); } - /** - * Check whether the satellite modem is provisioned. - * @param result The Message to send the result of the operation to. - */ - public void isSatelliteProvisioned(Message result) { - mCi.getSatelliteProvisionState(result); - } - /** * Get the satellite capabilities. * @param result The Message to send the result of the operation to. diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 3987fb9986..8aff93b6ba 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5788,21 +5788,6 @@ public class RIL extends BaseCommands implements CommandsInterface { } } - /** - * Get satellite provision state. - * - * @param result Message that will be sent back to the requester - */ - @Override - public void getSatelliteProvisionState(Message result) { - // Satellite HAL APIs are not supported before Android V. - if (result != null) { - AsyncResult.forMessage(result, null, - CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); - result.sendToTarget(); - } - } - /** * Provision the subscription with a satellite provider. This is needed to register the * subscription if the provider allows dynamic registration. diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index d339cd11af..56ee8a6588 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -186,7 +186,6 @@ public class DatagramController { mSendErrorCode = errorCode; mPointingAppController.updateSendDatagramTransferState(subId, datagramTransferState, sendPendingCount, errorCode); - notifyDatagramTransferStateChangedToSessionController(); } /** @@ -211,7 +210,6 @@ public class DatagramController { mReceiveErrorCode = errorCode; mPointingAppController.updateReceiveDatagramTransferState(subId, datagramTransferState, receivePendingCount, errorCode); - notifyDatagramTransferStateChangedToSessionController(); } /** @@ -222,17 +220,6 @@ public class DatagramController { return mReceivePendingCount; } - private void notifyDatagramTransferStateChangedToSessionController() { - SatelliteSessionController sessionController = SatelliteSessionController.getInstance(); - if (sessionController == null) { - loge("notifyDatagramTransferStateChangeToSessionController: SatelliteSessionController" - + " is not initialized yet"); - } else { - sessionController.onDatagramTransferStateChanged( - mSendDatagramTransferState, mReceiveDatagramTransferState); - } - } - private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 117f32de86..82b3867deb 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -445,6 +445,8 @@ public class DatagramReceiver extends Handler { satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler( mBackgroundHandler.getLooper(), validSubId); if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { + // TODO: remove this as SatelliteModemInterface can register for incoming datagrams + // on boot up itself. SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived( satelliteDatagramListenerHandler, SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null); @@ -543,4 +545,6 @@ public class DatagramReceiver extends Handler { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } + + // TODO: An api change - do not pass the binder from Telephony to Applications } diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java index dcfbe1f513..c37d1a05ba 100644 --- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -34,8 +34,6 @@ import android.text.TextUtils; import com.android.internal.telephony.Phone; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -116,7 +114,6 @@ public class PointingAppController { public static final int EVENT_POSITION_INFO_CHANGED = 1; public static final int EVENT_SEND_DATAGRAM_STATE_CHANGED = 2; public static final int EVENT_RECEIVE_DATAGRAM_STATE_CHANGED = 3; - public static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 4; private final ConcurrentHashMap mListeners; SatelliteTransmissionUpdateHandler(Looper looper) { @@ -142,64 +139,41 @@ public class PointingAppController { case EVENT_POSITION_INFO_CHANGED: { AsyncResult ar = (AsyncResult) msg.obj; PointingInfo pointingInfo = (PointingInfo) ar.result; - List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onSatellitePositionChanged(pointingInfo); } catch (RemoteException e) { logd("EVENT_POSITION_INFO_CHANGED RemoteException: " + e); - toBeRemoved.add(listener.asBinder()); } }); - toBeRemoved.forEach(listener -> { - mListeners.remove(listener); - }); - break; - } - - case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - logd("Receive EVENT_DATAGRAM_TRANSFER_STATE_CHANGED state=" + (int) ar.result); break; } case EVENT_SEND_DATAGRAM_STATE_CHANGED: { - logd("Received EVENT_SEND_DATAGRAM_STATE_CHANGED"); DatagramTransferStateHandlerRequest request = (DatagramTransferStateHandlerRequest) msg.obj; - List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onSendDatagramStateChanged(request.datagramTransferState, request.pendingCount, request.errorCode); } catch (RemoteException e) { logd("EVENT_SEND_DATAGRAM_STATE_CHANGED RemoteException: " + e); - toBeRemoved.add(listener.asBinder()); } }); - toBeRemoved.forEach(listener -> { - mListeners.remove(listener); - }); break; } case EVENT_RECEIVE_DATAGRAM_STATE_CHANGED: { - logd("Received EVENT_RECEIVE_DATAGRAM_STATE_CHANGED"); DatagramTransferStateHandlerRequest request = (DatagramTransferStateHandlerRequest) msg.obj; - List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onReceiveDatagramStateChanged(request.datagramTransferState, request.pendingCount, request.errorCode); } catch (RemoteException e) { logd("EVENT_RECEIVE_DATAGRAM_STATE_CHANGED RemoteException: " + e); - toBeRemoved.add(listener.asBinder()); } }); - toBeRemoved.forEach(listener -> { - mListeners.remove(listener); - }); break; } @@ -230,13 +204,18 @@ public class PointingAppController { SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged( handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + /** + * TODO: Need to remove this call, Datagram transfer state should come from the + * DatagramController based upon Transfer state. + * Modem won't be able to provide this info + */ SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged( handler, - SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, - null); + SatelliteTransmissionUpdateHandler.EVENT_SEND_DATAGRAM_STATE_CHANGED, null); } else { phone.registerForSatellitePositionInfoChanged(handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); + // TODO: registerForDatagramTransferStateChanged through SatelliteController } } } @@ -258,6 +237,13 @@ public class PointingAppController { handler.removeListener(callback); if (handler.hasListeners()) { + /** + * TODO (b/269194948): If the calling apps crash, the handler will always have some + * listener. That is, we will not request modem to stop position update and + * cleaning our resources. We need to monitor the calling apps and clean up the + * resources when the apps die. We need to do this for other satellite callbacks + * as well. + */ result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; } @@ -274,6 +260,7 @@ public class PointingAppController { return; } phone.unregisterForSatellitePositionInfoChanged(handler); + // TODO: unregisterForDatagramTransferStateChanged through SatelliteController } } } @@ -289,9 +276,6 @@ public class PointingAppController { public void startSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) { if (mStartedSatelliteTransmissionUpdates) { logd("startSatelliteTransmissionUpdates: already started"); - AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( - SatelliteManager.SATELLITE_ERROR_NONE)); - message.sendToTarget(); return; } if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { @@ -336,17 +320,7 @@ public class PointingAppController { public void startPointingUI(boolean needFullScreenPointingUI) { String packageName = TextUtils.emptyIfNull(mContext.getResources() .getString(com.android.internal.R.string.config_pointing_ui_package)); - if (TextUtils.isEmpty(packageName)) { - logd("startPointingUI: config_pointing_ui_package is not set. Ignore the request"); - return; - } - Intent launchIntent = mContext.getPackageManager().getLaunchIntentForPackage(packageName); - if (launchIntent == null) { - loge("startPointingUI: launchIntent is null"); - return; - } - launchIntent.putExtra("needFullScreen", needFullScreenPointingUI); mContext.startActivity(launchIntent); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 8d1b9223e0..ca76d16c2a 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.net.wifi.WifiManager; import android.os.AsyncResult; +import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; @@ -49,12 +50,12 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** @@ -92,11 +93,6 @@ public class SatelliteController extends Handler { private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 21; private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 22; private static final int EVENT_RADIO_STATE_CHANGED = 23; - private static final int CMD_IS_SATELLITE_PROVISIONED = 24; - private static final int EVENT_IS_SATELLITE_PROVISIONED_DONE = 25; - private static final int EVENT_SATELLITE_PROVISION_STATE_CHANGED = 26; - private static final int EVENT_PENDING_DATAGRAMS = 27; - private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 28; @NonNull private static SatelliteController sInstance; @NonNull private final Context mContext; @@ -114,18 +110,6 @@ public class SatelliteController extends Handler { private static final String KEY_WIFI_DISABLED_BY_SCO = "wifi_disabled_by_sco"; boolean mDisabledBTFlag = false; boolean mDisabledWifiFlag = false; - private final AtomicBoolean mRegisteredForProvisionStateChangedWithSatelliteService = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForProvisionStateChangedWithPhone = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForPendingDatagramCountWithSatelliteService = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForPendingDatagramCountWithPhone = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService = - new AtomicBoolean(false); - private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithPhone = - new AtomicBoolean(false); /** * Map key: subId, value: callback to get error code of the provision request. */ @@ -133,20 +117,24 @@ public class SatelliteController extends Handler { new ConcurrentHashMap<>(); /** - * Map key: binder of the callback, value: callback to receive provision state changed events. + * Map key: subId, value: SatelliteProvisionStateChangedHandler to notify registrants. */ - private final ConcurrentHashMap - mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>(); + private final ConcurrentHashMap + mSatelliteProvisionStateChangedHandlers = new ConcurrentHashMap<>(); + + /** + * Map key: subId, value: SatelliteStateListenerHandler to notify registrants. + */ + private final ConcurrentHashMap + mSatelliteStateListenerHandlers = new ConcurrentHashMap<>(); private Boolean mIsSatelliteSupported = null; private final Object mIsSatelliteSupportedLock = new Object(); + private final ResultReceiver mSatelliteSupportedReceiver; private boolean mIsDemoModeEnabled = false; private Boolean mIsSatelliteEnabled = null; private final Object mIsSatelliteEnabledLock = new Object(); - private Boolean mIsSatelliteProvisioned = null; - private final Object mIsSatelliteProvisionedLock = new Object(); - private SatelliteCapabilities mSatelliteCapabilities; - private final Object mSatelliteCapabilitiesLock = new Object(); + private final ResultReceiver mSatelliteEnabledReceiver; private boolean mNeedsSatellitePointing = false; private final Object mNeedsSatellitePointingLock = new Object(); @@ -187,7 +175,7 @@ public class SatelliteController extends Handler { mCi = phone.mCi; // Create the SatelliteModemInterface singleton, which is used to manage connections // to the satellite service and HAL interface. - mSatelliteModemInterface = SatelliteModemInterface.make(mContext, this); + mSatelliteModemInterface = SatelliteModemInterface.make(mContext); // Create the PointingUIController singleton, // which is used to manage interactions with PointingUI app. @@ -197,17 +185,13 @@ public class SatelliteController extends Handler { // which is used to send and receive satellite datagrams. mDatagramController = DatagramController.make(mContext, looper, mPointingAppController); - requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" + resultCode); - } - }); + mSatelliteEnabledReceiver = createSatelliteEnabledResultReceiver(); + mSatelliteSupportedReceiver = createSatelliteSupportedResultReceiver(looper); + //TODO: reenable below code + //requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + // mSatelliteSupportedReceiver); mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); - registerForSatelliteProvisionStateChanged(); - registerForPendingDatagramCount(); - registerForSatelliteModemStateChanged(); + try { mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); @@ -292,6 +276,116 @@ public class SatelliteController extends Handler { } } + private static final class SatelliteProvisionStateChangedHandler extends Handler { + public static final int EVENT_PROVISION_STATE_CHANGED = 1; + + private final ConcurrentHashMap mListeners; + private final int mSubId; + + SatelliteProvisionStateChangedHandler(Looper looper, int subId) { + super(looper); + mListeners = new ConcurrentHashMap<>(); + mSubId = subId; + } + + public void addListener(ISatelliteProvisionStateCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatelliteProvisionStateCallback listener) { + mListeners.remove(listener.asBinder()); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_PROVISION_STATE_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + boolean provisioned = (boolean) ar.userObj; + logd("Received EVENT_PROVISION_STATE_CHANGED for subId=" + mSubId + + ", provisioned=" + provisioned); + mListeners.values().forEach(listener -> { + try { + listener.onSatelliteProvisionStateChanged(provisioned); + } catch (RemoteException e) { + logd("EVENT_PROVISION_STATE_CHANGED RemoteException: " + e); + } + }); + + setSatelliteProvisioned(provisioned); + /** + * TODO: Take bugreport if provisioned is true and user did not initiate the + * provision procedure for the corresponding subscription. + */ + break; + } + default: + loge("SatelliteProvisionStateChangedHandler unknown event: " + msg.what); + } + } + + private void setSatelliteProvisioned(boolean isProvisioned) { + if (mSubId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + SubscriptionManager.setSubscriptionProperty( + mSubId, SubscriptionManager.SATELLITE_ENABLED, isProvisioned ? "1" : "0"); + } else { + //TODO (b/267826133): set via SatelliteController. + } + } + } + + private static final class SatelliteStateListenerHandler extends Handler { + public static final int EVENT_SATELLITE_MODEM_STATE_CHANGE = 1; + public static final int EVENT_PENDING_DATAGRAMS = 2; + + private final ConcurrentHashMap mListeners; + private final int mSubId; + + SatelliteStateListenerHandler(Looper looper, int subId) { + super(looper); + mSubId = subId; + mListeners = new ConcurrentHashMap<>(); + } + + public void addListener(ISatelliteStateCallback listener) { + mListeners.put(listener.asBinder(), listener); + } + + public void removeListener(ISatelliteStateCallback listener) { + mListeners.remove(listener.asBinder()); + } + + public boolean hasListeners() { + return !mListeners.isEmpty(); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case EVENT_SATELLITE_MODEM_STATE_CHANGE : { + AsyncResult ar = (AsyncResult) msg.obj; + int state = (int) ar.result; + logd("Received EVENT_SATELLITE_MODEM_STATE_CHANGE for subId=" + mSubId + + ", state=" + state); + break; + } + case EVENT_PENDING_DATAGRAMS: { + logd("Received EVENT_PENDING_DATAGRAMS for subId=" + mSubId); + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("pollPendingSatelliteDatagram result: " + result); + } + }; + sInstance.pollPendingSatelliteDatagrams(mSubId, internalCallback); + break; + } + default: + loge("SatelliteStateListenerHandler unknown event: " + msg.what); + } + } + } + @Override public void handleMessage(Message msg) { SatelliteControllerHandlerRequest request; @@ -423,7 +517,8 @@ public class SatelliteController extends Handler { checkAndEnableBluetoothWifiState(); } /** - * TODO for NTN-based satellites: Check if satellite is acquired. + * TODO: check if Satellite is Acquired. + * Also need to call requestSatelliteCapabilities() if Satellite is enabled */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(false); @@ -433,6 +528,7 @@ public class SatelliteController extends Handler { argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); } argument.callback.accept(error); + // TODO: if error is ERROR_NONE, request satellite capabilities break; } @@ -468,7 +564,6 @@ public class SatelliteController extends Handler { boolean enabled = ((int[]) ar.result)[0] == 1; if (DBG) logd("isSatelliteEnabled: " + enabled); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled); - updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE"); } } ((ResultReceiver) request.argument).send(error, bundle); @@ -507,7 +602,9 @@ public class SatelliteController extends Handler { boolean supported = (boolean) ar.result; if (DBG) logd("isSatelliteSupported: " + supported); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported); - updateSatelliteSupportedState(supported); + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = supported; + } } } ((ResultReceiver) request.argument).send(error, bundle); @@ -550,9 +647,6 @@ public class SatelliteController extends Handler { if (DBG) logd("getSatelliteCapabilities: " + capabilities); bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, capabilities); - synchronized (mSatelliteCapabilitiesLock) { - mSatelliteCapabilities = capabilities; - } } } ((ResultReceiver) request.argument).send(error, bundle); @@ -665,101 +759,10 @@ public class SatelliteController extends Handler { new RequestSatelliteEnabledArgument(false, false, result); request = new SatelliteControllerHandlerRequest(message, phone); handleSatelliteEnabled(request); - } else { - if (!mSatelliteModemInterface.isSatelliteServiceSupported()) { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported == null) { - ResultReceiver receiver = new ResultReceiver(this) { - @Override - protected void onReceiveResult( - int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" - + resultCode); - } - }; - requestIsSatelliteSupported( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); - } - } - } else { - logd("EVENT_RADIO_STATE_CHANGED: Satellite vendor service is supported." - + " Ignored the event"); - } } break; } - case CMD_IS_SATELLITE_PROVISIONED: { - request = (SatelliteControllerHandlerRequest) msg.obj; - onCompleted = obtainMessage(EVENT_IS_SATELLITE_PROVISIONED_DONE, request); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted); - break; - } - Phone phone = request.phone; - if (phone != null) { - phone.isSatelliteProvisioned(onCompleted); - } else { - loge("isSatelliteProvisioned: No phone object"); - ((ResultReceiver) request.argument).send( - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - } - break; - } - - case EVENT_IS_SATELLITE_PROVISIONED_DONE: { - ar = (AsyncResult) msg.obj; - request = (SatelliteControllerHandlerRequest) ar.userObj; - int error = SatelliteServiceUtils.getSatelliteError(ar, - "isSatelliteProvisioned"); - Bundle bundle = new Bundle(); - if (error == SatelliteManager.SATELLITE_ERROR_NONE) { - if (ar.result == null) { - loge("isSatelliteProvisioned: result is null"); - error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } else { - boolean provisioned = ((int[]) ar.result)[0] == 1; - if (DBG) logd("isSatelliteProvisioned: " + provisioned); - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, provisioned); - synchronized (mIsSatelliteProvisionedLock) { - mIsSatelliteProvisioned = provisioned; - } - } - } - ((ResultReceiver) request.argument).send(error, bundle); - break; - } - - case EVENT_SATELLITE_PROVISION_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - if (ar.result == null) { - loge("EVENT_SATELLITE_PROVISION_STATE_CHANGED: result is null"); - } else { - handleEventSatelliteProvisionStateChanged((boolean) ar.result); - } - break; - - case EVENT_PENDING_DATAGRAMS: - logd("Received EVENT_PENDING_DATAGRAMS"); - IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - logd("pollPendingSatelliteDatagram result: " + result); - } - }; - pollPendingSatelliteDatagrams( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, internalCallback); - break; - - case EVENT_SATELLITE_MODEM_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - if (ar.result == null) { - loge("EVENT_SATELLITE_MODEM_STATE_CHANGED: result is null"); - } else { - handleEventSatelliteModemStateChanged((int) ar.result); - } - break; - default: Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " + msg.what); @@ -787,29 +790,22 @@ public class SatelliteController extends Handler { public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + // TODO: clean up this dependency on subId + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_SET_SATELLITE_ENABLED, new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result), - SatelliteServiceUtils.getPhone()); + phone); } /** @@ -820,13 +816,14 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + if (!isSatelliteSupported()) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - if (!satelliteSupported) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { + result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -840,7 +837,7 @@ public class SatelliteController extends Handler { } } - sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); + sendRequest(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); } /** @@ -852,22 +849,13 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -906,27 +894,13 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - synchronized (mSatelliteCapabilitiesLock) { - if (mSatelliteCapabilities != null) { - Bundle bundle = new Bundle(); - bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, - mSatelliteCapabilities); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); - return; - } - } - - sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, SatelliteServiceUtils.getPhone()); + Phone phone = SatelliteServiceUtils.getPhone(); + sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, phone); } /** @@ -942,28 +916,18 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } Phone phone = SatelliteServiceUtils.getPhone(); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback, phone); sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES, new SatelliteTransmissionUpdateArgument(result, callback, validSubId), phone); @@ -981,28 +945,18 @@ public class SatelliteController extends Handler { public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } Phone phone = SatelliteServiceUtils.getPhone(); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.unregisterForSatelliteTransmissionUpdates( validSubId, result, callback, phone); @@ -1028,29 +982,24 @@ public class SatelliteController extends Handler { @Nullable public ICancellationSignal provisionSatelliteService(int subId, @NonNull String token, @NonNull String regionId, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return null; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return null; } final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + Phone phone = SatelliteServiceUtils.getPhone(); + if (mSatelliteProvisionCallbacks.containsKey(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS); return null; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned != null && satelliteProvisioned) { + if (isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return null; } - Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, regionId, result, validSubId), phone); @@ -1077,28 +1026,18 @@ public class SatelliteController extends Handler { public void deprovisionSatelliteService(int subId, @NonNull String token, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; } Phone phone = SatelliteServiceUtils.getPhone(); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, null, result, validSubId), phone); } @@ -1113,15 +1052,34 @@ public class SatelliteController extends Handler { */ @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId, @NonNull ISatelliteProvisionStateCallback callback) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { return SatelliteManager.SATELLITE_NOT_SUPPORTED; } - mSatelliteProvisionStateChangedListeners.put(callback.asBinder(), callback); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + Phone phone = SatelliteServiceUtils.getPhone(); + + SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = + mSatelliteProvisionStateChangedHandlers.get(validSubId); + if (satelliteProvisionStateChangedHandler == null) { + satelliteProvisionStateChangedHandler = new SatelliteProvisionStateChangedHandler( + Looper.getMainLooper(), validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( + satelliteProvisionStateChangedHandler, + SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); + } else { + phone.registerForSatelliteProvisionStateChanged( + satelliteProvisionStateChangedHandler, + SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); + } + } + + if (callback != null) { + satelliteProvisionStateChangedHandler.addListener(callback); + } + mSatelliteProvisionStateChangedHandlers.put( + validSubId, satelliteProvisionStateChangedHandler); return SatelliteManager.SATELLITE_ERROR_NONE; } @@ -1135,7 +1093,12 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback) { - mSatelliteProvisionStateChangedListeners.remove(callback.asBinder()); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = + mSatelliteProvisionStateChangedHandlers.get(validSubId); + if (satelliteProvisionStateChangedHandler != null) { + satelliteProvisionStateChangedHandler.removeListener(callback); + } } /** @@ -1147,27 +1110,16 @@ public class SatelliteController extends Handler { * request failed. */ public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - synchronized (mIsSatelliteProvisionedLock) { - if (mIsSatelliteProvisioned != null) { - Bundle bundle = new Bundle(); - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, - mIsSatelliteProvisioned); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); - return; - } - } - - sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, SatelliteServiceUtils.getPhone()); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + Bundle bundle = new Bundle(); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, + isSatelliteProvisioned(validSubId)); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); } /** @@ -1187,6 +1139,35 @@ public class SatelliteController extends Handler { + " is not initialized yet"); return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; } + + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + SatelliteStateListenerHandler satelliteStateListenerHandler = + mSatelliteStateListenerHandlers.get(validSubId); + if (satelliteStateListenerHandler == null) { + satelliteStateListenerHandler = new SatelliteStateListenerHandler( + Looper.getMainLooper(), validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.registerForSatelliteModemStateChanged( + satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); + mSatelliteModemInterface.registerForPendingDatagrams(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone == null) { + loge("registerForSatelliteModemStateChanged: satellite phone is " + + "not initialized yet"); + return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } + phone.registerForSatelliteModemStateChanged(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); + phone.registerForPendingDatagramCount(satelliteStateListenerHandler, + SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); + } + } + + satelliteStateListenerHandler.addListener(callback); + mSatelliteStateListenerHandlers.put(validSubId, satelliteStateListenerHandler); return SatelliteManager.SATELLITE_ERROR_NONE; } @@ -1200,6 +1181,25 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + SatelliteStateListenerHandler handler = mSatelliteStateListenerHandlers.get(validSubId); + if (handler != null) { + handler.removeListener(callback); + if (!handler.hasListeners()) { + mSatelliteStateListenerHandlers.remove(validSubId); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.unregisterForSatelliteModemStateChanged(handler); + mSatelliteModemInterface.unregisterForPendingDatagrams(handler); + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone != null) { + phone.unregisterForSatelliteModemStateChanged(handler); + phone.unregisterForPendingDatagramCount(handler); + } + } + } + } + if (mSatelliteSessionController != null) { mSatelliteSessionController.unregisterForSatelliteModemStateChanged(callback); } else { @@ -1246,20 +1246,16 @@ public class SatelliteController extends Handler { * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ public void pollPendingSatelliteDatagrams(int subId, @NonNull IIntegerConsumer callback) { + // TODO: return pending datagram count on success Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - mDatagramController.pollPendingSatelliteDatagrams(validSubId, result); + mDatagramController.pollPendingSatelliteDatagrams(subId, result); } /** @@ -1283,24 +1279,20 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } /** - * TODO for NTN-based satellites: Check if satellite is acquired. + * TODO: check if Satellite is Acquired. Also need to call requestSatelliteCapabilities() + * when Satellite is enabled */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(needFullScreenPointingUI); } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mDatagramController.sendSatelliteDatagram(validSubId, datagramType, datagram, needFullScreenPointingUI, result); } @@ -1316,18 +1308,13 @@ public class SatelliteController extends Handler { */ public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - sendRequestAsync( - CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, SatelliteServiceUtils.getPhone()); + Phone phone = SatelliteServiceUtils.getPhone(); + sendRequest(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, phone); } /** @@ -1338,22 +1325,13 @@ public class SatelliteController extends Handler { * be visible if the request is successful or an error code if the request failed. */ public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); - if (satelliteSupported == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteSupported) { + if (!isSatelliteSupported()) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - Boolean satelliteProvisioned = isSatelliteProvisioned(); - if (satelliteProvisioned == null) { - result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); - return; - } - if (!satelliteProvisioned) { + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + if (!isSatelliteProvisioned(validSubId)) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -1362,61 +1340,6 @@ public class SatelliteController extends Handler { sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); } - /** - * If we have not successfully queried the satellite modem for its satellite service support, - * we will retry the query one more time. Otherwise, we will return the cached result. - */ - public Boolean isSatelliteSupported() { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported != null) { - /* We have already successfully queried the satellite modem. */ - return mIsSatelliteSupported; - } - } - /** - * We have not successfully checked whether the modem supports satellite service. - * Thus, we need to retry it now. - */ - requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" + resultCode); - } - }); - return null; - } - - /** - * This function is used by {@link SatelliteModemInterface} to notify - * {@link SatelliteController} that the satellite vendor service was just connected. - *

- * {@link SatelliteController} will send requests to satellite modem to check whether it support - * satellite, whether it is powered on, and whether it is provisioned. - * {@link SatelliteController} will use these cached values to serve requests from its clients. - */ - void onSatelliteServiceConnected() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported == null) { - ResultReceiver receiver = new ResultReceiver(this) { - @Override - protected void onReceiveResult( - int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" - + resultCode); - } - }; - requestIsSatelliteSupported( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); - } - } - } else { - logd("onSatelliteServiceConnected: Satellite vendor service is not supported." - + " Ignored the event"); - } - } - private void handleEventProvisionSatelliteServiceDone( @NonNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteError int result) { @@ -1430,6 +1353,17 @@ public class SatelliteController extends Handler { return; } callback.accept(result); + + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + setSatelliteProvisioned(arg.subId, true); + } + + /** + * We need to update satellite provision status in SubscriptionController + * or SatelliteController. + * TODO (b/267826133) we need to do this for all subscriptions on the device. + */ + registerForSatelliteProvisionStateChanged(arg.subId, null); } private void handleEventDeprovisionSatelliteServiceDone( @@ -1445,6 +1379,10 @@ public class SatelliteController extends Handler { if (arg.callback != null) { arg.callback.accept(result); } + + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + setSatelliteProvisioned(arg.subId, false); + } } private void handleStartSatelliteTransmissionUpdatesDone(@NonNull AsyncResult ar) { @@ -1466,6 +1404,42 @@ public class SatelliteController extends Handler { } } + /** + * Set satellite provisioned for a subscription or the device. + * + * The permission {@link android.Manifest.permission#MODIFY_PHONE_STATE} will be enforced by + * {@link SubscriptionController} when setting satellite enabled for an active subscription. + * Otherwise, {@link android.Manifest.permission#SATELLITE_COMMUNICATION} will be enforced. + */ + private synchronized void setSatelliteProvisioned(int subId, boolean isEnabled) { + if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + SubscriptionManager.setSubscriptionProperty( + subId, SubscriptionManager.SATELLITE_ENABLED, isEnabled ? "1" : "0"); + } else { + //TODO (b/267826133): set via SatelliteController + } + } + + /** + * If we have not successfully queried the satellite modem for its satellite service support, + * we will retry the query one more time. Otherwise, we will return the queried result. + */ + public boolean isSatelliteSupported() { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported != null) { + /* We have already successfully queried the satellite modem. */ + return mIsSatelliteSupported; + } + } + /** + * We have not successfully checked whether the modem supports satellite service. + * Thus, we need to retry it now. + */ + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mSatelliteSupportedReceiver); + return false; + } + /** * Posts the specified command to be executed on the main thread and returns immediately. * @@ -1514,24 +1488,35 @@ public class SatelliteController extends Handler { /** * Check if satellite is provisioned for a subscription on the device. + * @param subId The subscription id. * @return true if satellite is provisioned on the given subscription else return false. */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - protected Boolean isSatelliteProvisioned() { - synchronized (mIsSatelliteProvisionedLock) { - if (mIsSatelliteProvisioned != null) { - return mIsSatelliteProvisioned; + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected boolean isSatelliteProvisioned(int subId) { + final long identity = Binder.clearCallingIdentity(); + try { + if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + String strResult = null; + if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { + strResult = SubscriptionManagerService.getInstance() + .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED, + mContext.getOpPackageName(), mContext.getAttributionTag()); + } else { + strResult = SubscriptionController.getInstance() + .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED); + } + + if (strResult != null) { + int intResult = Integer.parseInt(strResult); + return (intResult == 1); + } + } else { + //TODO (b/267826133): check via SatelliteController } + } finally { + Binder.restoreCallingIdentity(identity); } - - requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); - } - }); - return null; + return false; } private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) { @@ -1552,39 +1537,39 @@ public class SatelliteController extends Handler { } } - private void updateSatelliteSupportedState(boolean supported) { - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = supported; - } - mSatelliteSessionController = SatelliteSessionController.make( - mContext, getLooper(), supported); - if (supported) { - registerForSatelliteProvisionStateChanged(); - registerForPendingDatagramCount(); - registerForSatelliteModemStateChanged(); + private ResultReceiver createSatelliteSupportedResultReceiver(@NonNull Looper looper) { + return new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE + && resultData.containsKey(SatelliteManager.KEY_SATELLITE_SUPPORTED)) { + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = resultData.getBoolean( + SatelliteManager.KEY_SATELLITE_SUPPORTED); + } + } + mSatelliteSessionController = SatelliteSessionController.make(mContext, looper, + mIsSatelliteSupported != null ? mIsSatelliteSupported : false); + if (mIsSatelliteSupported != null && mIsSatelliteSupported) { + requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mSatelliteEnabledReceiver); + } + } + }; + } - requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteEnabled: resultCode=" + resultCode); - } - }); - requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); - } - }); - requestSatelliteCapabilities(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestSatelliteCapabilities: resultCode=" + resultCode); - } - }); - } + private ResultReceiver createSatelliteEnabledResultReceiver() { + return new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE + && resultData.containsKey(SatelliteManager.KEY_SATELLITE_ENABLED)) { + updateSatelliteEnabledState(resultData.getBoolean( + SatelliteManager.KEY_SATELLITE_ENABLED), + "SatelliteEnabledResultReceiver.onReceiveResult"); + } + } + }; } private void updateSatelliteEnabledState(boolean enabled, String caller) { @@ -1632,102 +1617,13 @@ public class SatelliteController extends Handler { if (DBG) logd("Enabling Bluetooth"); mBluetoothAdapter.enable(); mSharedPreferences.edit().putBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, false) - .apply(); + .apply(); } if (!mWifiManager.isWifiEnabled() && mDisabledWifiFlag) { if (DBG) logd("Enabling Wifi"); mWifiManager.setWifiEnabled(true); mSharedPreferences.edit().putBoolean(KEY_WIFI_DISABLED_BY_SCO, false) - .apply(); - } - } - - private void registerForSatelliteProvisionStateChanged() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - if (!mRegisteredForProvisionStateChangedWithSatelliteService.get()) { - mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( - this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); - mRegisteredForProvisionStateChangedWithSatelliteService.set(true); - } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForSatelliteProvisionStateChanged: phone is null"); - } else if (!mRegisteredForProvisionStateChangedWithPhone.get()) { - phone.registerForSatelliteProvisionStateChanged( - this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); - mRegisteredForProvisionStateChangedWithPhone.set(true); - } - } - } - - private void registerForPendingDatagramCount() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - if (!mRegisteredForPendingDatagramCountWithSatelliteService.get()) { - mSatelliteModemInterface.registerForPendingDatagrams( - this, EVENT_PENDING_DATAGRAMS, null); - mRegisteredForPendingDatagramCountWithSatelliteService.set(true); - } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForPendingDatagramCount: satellite phone is " - + "not initialized yet"); - } else if (!mRegisteredForPendingDatagramCountWithPhone.get()) { - phone.registerForPendingDatagramCount(this, EVENT_PENDING_DATAGRAMS, null); - mRegisteredForPendingDatagramCountWithPhone.set(true); - } - } - } - - private void registerForSatelliteModemStateChanged() { - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - if (!mRegisteredForSatelliteModemStateChangedWithSatelliteService.get()) { - mSatelliteModemInterface.registerForSatelliteModemStateChanged( - this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); - mRegisteredForSatelliteModemStateChangedWithSatelliteService.set(true); - } - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForSatelliteModemStateChanged: satellite phone is " - + "not initialized yet"); - } else if (!mRegisteredForSatelliteModemStateChangedWithPhone.get()) { - phone.registerForSatelliteModemStateChanged( - this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); - mRegisteredForSatelliteModemStateChangedWithPhone.set(true); - } - } - } - - private void handleEventSatelliteProvisionStateChanged(boolean provisioned) { - logd("handleSatelliteProvisionStateChangedEvent: provisioned=" + provisioned); - - synchronized (mIsSatelliteProvisionedLock) { - mIsSatelliteProvisioned = provisioned; - } - - List toBeRemoved = new ArrayList<>(); - mSatelliteProvisionStateChangedListeners.values().forEach(listener -> { - try { - listener.onSatelliteProvisionStateChanged(provisioned); - } catch (RemoteException e) { - logd("handleSatelliteProvisionStateChangedEvent RemoteException: " + e); - toBeRemoved.add(listener); - } - }); - toBeRemoved.forEach(listener -> { - mSatelliteProvisionStateChangedListeners.remove(listener.asBinder()); - }); - } - - private void handleEventSatelliteModemStateChanged( - @SatelliteManager.SatelliteModemState int state) { - logd("handleEventSatelliteModemStateChanged: state=" + state); - if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF - || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { - updateSatelliteEnabledState( - false, "handleEventSatelliteModemStateChanged"); + .apply(); } } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 8657529183..cf2fc8593b 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -65,7 +65,6 @@ public class SatelliteModemInterface { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @NonNull protected final ExponentialBackoff mExponentialBackoff; @NonNull private final Object mLock = new Object(); - @NonNull private final SatelliteController mSatelliteController; /** * {@code true} to use the vendor satellite service and {@code false} to use the HAL. */ @@ -151,14 +150,11 @@ public class SatelliteModemInterface { /** * Create the SatelliteModemInterface singleton instance. * @param context The Context to use to create the SatelliteModemInterface. - * @param satelliteController The singleton instance of SatelliteController. * @return The singleton instance of SatelliteModemInterface. */ - public static SatelliteModemInterface make(@NonNull Context context, - SatelliteController satelliteController) { + public static SatelliteModemInterface make(@NonNull Context context) { if (sInstance == null) { - sInstance = new SatelliteModemInterface( - context, satelliteController, Looper.getMainLooper()); + sInstance = new SatelliteModemInterface(context, Looper.getMainLooper()); } return sInstance; } @@ -170,11 +166,9 @@ public class SatelliteModemInterface { * @param looper The Looper to run binding retry on. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - protected SatelliteModemInterface(@NonNull Context context, - SatelliteController satelliteController, @NonNull Looper looper) { + protected SatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { mContext = context; mIsSatelliteServiceSupported = getSatelliteServiceSupport(); - mSatelliteController = satelliteController; mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, REBIND_MULTIPLIER, looper, () -> { synchronized (mLock) { @@ -286,7 +280,6 @@ public class SatelliteModemInterface { // TODO: Retry setSatelliteListener logd("setSatelliteListener: RemoteException " + e); } - mSatelliteController.onSatelliteServiceConnected(); } @Override diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java index 1eeb5a21db..a1bd99ec72 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java @@ -255,7 +255,8 @@ public class SatelliteSOSMessageRecommender extends Handler { boolean isDialerNotified = false; if (!mIsImsRegistered.get() && !isCellularAvailable() && mIsSatelliteAllowedInCurrentLocation.get() - && mSatelliteController.isSatelliteProvisioned() + && mSatelliteController.isSatelliteProvisioned( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) && shouldTrackCall(mEmergencyConnection.getState())) { logd("handleTimeoutEvent: Sending EVENT_DISPLAY_SOS_MESSAGE to Dialer..."); mEmergencyConnection.sendConnectionEvent(Call.EVENT_DISPLAY_SOS_MESSAGE, null); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index 5ec69d68cf..be252f4dcc 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -91,7 +91,6 @@ public class SatelliteSessionController extends StateMachine { private final long mSatelliteStayAtListeningFromSendingMillis; private final long mSatelliteStayAtListeningFromReceivingMillis; private final ConcurrentHashMap mListeners; - @SatelliteManager.SatelliteModemState private int mCurrentState; /** * @return The singleton instance of SatelliteSessionController. @@ -148,7 +147,6 @@ public class SatelliteSessionController extends StateMachine { mSatelliteStayAtListeningFromReceivingMillis = satelliteStayAtListeningFromReceivingMillis; mListeners = new ConcurrentHashMap<>(); mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; addState(mUnavailableState); addState(mPowerOffState); @@ -194,12 +192,7 @@ public class SatelliteSessionController extends StateMachine { * @param callback The callback to handle the satellite modem state changed event. */ public void registerForSatelliteModemStateChanged(@NonNull ISatelliteStateCallback callback) { - try { - callback.onSatelliteModemStateChanged(mCurrentState); - mListeners.put(callback.asBinder(), callback); - } catch (RemoteException ex) { - loge("registerForSatelliteModemStateChanged: Got RemoteException ex=" + ex); - } + mListeners.put(callback.asBinder(), callback); } /** @@ -228,7 +221,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering UnavailableState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; } @Override @@ -242,7 +234,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering PowerOffState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_OFF; mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @@ -262,6 +253,8 @@ public class SatelliteSessionController extends StateMachine { private void handleSatelliteEnabledStateChanged(boolean on) { if (on) { transitionTo(mIdleState); + } else { + loge("PowerOffState: Unexpected satellite radio powered-off state changed event"); } } } @@ -270,7 +263,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering IdleState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE; mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE); } @@ -304,7 +296,6 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering TransferringState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); } @@ -342,9 +333,8 @@ public class SatelliteSessionController extends StateMachine { private class ListeningState extends State { @Override public void enter() { - if (DBG) logd("Entering ListeningState"); + if (DBG) logd("Entering TransferringState"); - mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_LISTENING; long timeoutMillis = updateListeningMode(true); sendMessageDelayed(EVENT_LISTENING_TIMER_TIMEOUT, timeoutMillis); mIsSendingTriggeredDuringTransferringState.set(false); diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java index 6aca800edd..103156cd44 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java @@ -93,17 +93,17 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); - when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper()); + when(mMockContext.getMainLooper()).thenReturn(Looper.getMainLooper()); when(mMockContext.getResources()).thenReturn(mResources); when(mResources.getString(com.android.internal.R.string.config_satellite_service_package)) .thenReturn(""); mTestSatelliteController = new TestSatelliteController(mMockContext, - Looper.myLooper()); + Looper.getMainLooper()); mTestImsManager = new TestImsManager( mMockContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null); mTestConnection = new TestConnection(CALL_ID); when(mPhone.getServiceState()).thenReturn(mServiceState); - mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.myLooper(), + mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.getMainLooper(), mTestSatelliteController, mTestImsManager, TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); @@ -118,12 +118,12 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testTimeoutBeforeEmergencyCallEnd() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); @@ -143,14 +143,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testImsRegistrationStateChangedBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestImsManager.sendImsRegistrationStateChangedEvent(true); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -158,12 +158,11 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); mTestImsManager.sendImsRegistrationStateChangedEvent(false); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); @@ -173,7 +172,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testSatelliteProvisionStateChangedBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -181,14 +180,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mTestSatelliteController.sendProvisionStateChangedEvent( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 2, 2, 2); @@ -197,8 +196,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -209,7 +207,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testEmergencyCallRedialBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -219,7 +217,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { when(newPhone.getServiceState()).thenReturn(mServiceState); when(newPhone.isImsRegistered()).thenReturn(false); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, newPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); @@ -236,8 +234,9 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertRegisterForStateChangedEventsTriggered(newPhone, 2, 2, 1); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + long timeoutMillis = TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS + - EVENT_PROCESSING_TIME_MILLIS; + waitFor(timeoutMillis > 0 ? timeoutMillis : 0); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); /** @@ -280,7 +279,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testOnEmergencyCallConnectionStateChangedWithWrongCallId() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -288,7 +287,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged( WRONG_CALL_ID, Connection.STATE_ACTIVE); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -300,7 +299,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { public void testSatelliteNotAllowedInCurrentLocation() { mTestSatelliteController.setIsSatelliteCommunicationAllowed(false); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); /** * We should have registered for the state change events abd started the timer when @@ -317,14 +316,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { private void testStopTrackingCallBeforeTimeout( @Connection.ConnectionState int connectionState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(CALL_ID, connectionState); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -336,14 +335,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @ServiceState.RegState int availableServiceState, @ServiceState.RegState int unavailableServiceState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.sendServiceStateChangedEvent(availableServiceState); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -351,12 +350,11 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); mTestSOSMessageRecommender.sendServiceStateChangedEvent(unavailableServiceState); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); - processAllMessages(); + waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); @@ -382,6 +380,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { verify(phone, times(unregisterForCellularCount)).unregisterForServiceStateChanged(any()); } + private static void waitFor(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ex) { + Log.e(TAG, "Thread.sleep() ex=" + ex); + } + } + private static class TestSatelliteController extends SatelliteController { private static final String TAG = "TestSatelliteController"; @@ -389,7 +395,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mProvisionStateChangedCallbacks; private int mRegisterForSatelliteProvisionStateChangedCalls = 0; private int mUnregisterForSatelliteProvisionStateChangedCalls = 0; - private boolean mIsSatelliteProvisioned = true; + private final Map mSatelliteProvisionStates; private boolean mIsSatelliteCommunicationAllowed = true; /** @@ -401,15 +407,18 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { protected TestSatelliteController(Context context, Looper looper) { super(context, looper); mProvisionStateChangedCallbacks = new HashMap<>(); + mSatelliteProvisionStates = new HashMap<>(); + mSatelliteProvisionStates.put(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); } @Override - public Boolean isSatelliteProvisioned() { - return mIsSatelliteProvisioned; + public boolean isSatelliteProvisioned(int subId) { + Boolean provisioned = mSatelliteProvisionStates.get(subId); + return (provisioned != null) ? provisioned : false; } @Override - public Boolean isSatelliteSupported() { + public boolean isSatelliteSupported() { return true; } @@ -457,7 +466,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { } public void sendProvisionStateChangedEvent(int subId, boolean provisioned) { - mIsSatelliteProvisioned = provisioned; + mSatelliteProvisionStates.put(subId, provisioned); Set perSubscriptionCallbacks = mProvisionStateChangedCallbacks.get(subId); if (perSubscriptionCallbacks != null) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java index 3ccf512211..2b030421d3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java @@ -36,6 +36,7 @@ import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.SatelliteManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.Log; import com.android.internal.telephony.TelephonyTest; @@ -43,7 +44,6 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.Semaphore; @@ -70,27 +70,22 @@ public class SatelliteSessionControllerTest extends TelephonyTest { private TestSatelliteSessionController mTestSatelliteSessionController; private TestSatelliteStateCallback mTestSatelliteStateCallback; - @Mock - private SatelliteController mSatelliteController; - @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); mSatelliteModemInterface = new TestSatelliteModemInterface( - mContext, mSatelliteController, Looper.myLooper()); + mContext, Looper.getMainLooper()); mTestSatelliteSessionController = new TestSatelliteSessionController(mContext, - Looper.myLooper(), true, mSatelliteModemInterface, + Looper.getMainLooper(), true, mSatelliteModemInterface, TEST_SATELLITE_STAY_AT_LISTENING_MILLIS, TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); mTestSatelliteStateCallback = new TestSatelliteStateCallback(); mTestSatelliteSessionController.registerForSatelliteModemStateChanged( mTestSatelliteStateCallback); - assertSuccessfulModemStateChangedCallback( - mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @After @@ -105,20 +100,18 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController1 = new TestSatelliteSessionController( - mContext, Looper.myLooper(), false, + mContext, Looper.getMainLooper(), false, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController1); - processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController1.getCurrentStateName()); /** * Since satellite is supported, SatelliteSessionController should move to POWER_OFF state. */ TestSatelliteSessionController sessionController2 = new TestSatelliteSessionController( - mContext, Looper.myLooper(), true, + mContext, Looper.getMainLooper(), true, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController2); - processAllMessages(); assertEquals(STATE_POWER_OFF, sessionController2.getCurrentStateName()); } @@ -129,10 +122,9 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController = new TestSatelliteSessionController( - mContext, Looper.myLooper(), false, + mContext, Looper.getMainLooper(), false, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController); - processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); /** @@ -140,7 +132,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * satellite radio powered-on state changed event. */ sessionController.onSatelliteEnabledStateChanged(true); - processAllMessages(); + waitFor(EVENT_PROCESSING_TIME_MILLIS); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); } @@ -154,7 +146,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power on the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); - processAllMessages(); // SatelliteSessionController should move to IDLE state after the modem is powered on. assertSuccessfulModemStateChangedCallback( @@ -164,7 +155,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power off the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); - processAllMessages(); // SatelliteSessionController should move back to POWER_OFF state. assertSuccessfulModemStateChangedCallback( @@ -174,7 +164,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power on the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); - processAllMessages(); // SatelliteSessionController should move to IDLE state after radio is turned on. assertSuccessfulModemStateChangedCallback( @@ -185,7 +174,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Start sending datagrams mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -197,7 +185,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to IDLE state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -209,7 +196,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -221,7 +207,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -234,7 +219,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -246,7 +230,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Receiving datagrams is successful and done. mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -259,7 +242,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -272,7 +254,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); - processAllMessages(); // SatelliteSessionController should move to IDLE state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -284,7 +265,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -295,7 +275,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Receiving datagrams is successful and done. mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); - processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -305,8 +284,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); // Wait for timeout - moveTimeForward(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); - processAllMessages(); + waitFor(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); // SatelliteSessionController should move to IDLE state after timeout assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -319,7 +297,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -331,7 +308,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state. assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); @@ -342,7 +318,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE // state. @@ -354,7 +329,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state. assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); @@ -365,7 +339,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); - processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE // state. @@ -375,7 +348,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power off the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); - processAllMessages(); // SatelliteSessionController should move to POWER_OFF state. assertSuccessfulModemStateChangedCallback( @@ -388,9 +360,8 @@ public class SatelliteSessionControllerTest extends TelephonyTest { private final AtomicInteger mListeningEnabledCount = new AtomicInteger(0); private final AtomicInteger mListeningDisabledCount = new AtomicInteger(0); - TestSatelliteModemInterface(@NonNull Context context, - SatelliteController satelliteController, @NonNull Looper looper) { - super(context, satelliteController, looper); + TestSatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { + super(context, looper); mExponentialBackoff.stop(); } @@ -473,6 +444,14 @@ public class SatelliteSessionControllerTest extends TelephonyTest { } } + private static void waitFor(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ex) { + Log.e(TAG, "Thread.sleep() ex=" + ex); + } + } + private static void assertSuccessfulModemStateChangedCallback( TestSatelliteStateCallback callback, @SatelliteManager.SatelliteModemState int expectedModemState) { -- GitLab From b3cb26219778055652f62642d5c6e0c0e416e36c Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Tue, 28 Mar 2023 06:39:41 +0000 Subject: [PATCH 556/656] [Telephony]Unit test support for Apn Id removal at ApnSetting Bug: 271734479 Test: atest FrameworkTelephonyTests Change-Id: I16fb1e95ee505500fb9e9d8c062a3b341af6a0e4 --- .../telephony/data/ApnSettingTest.java | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java index b6d77e952e..f480805cf5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java @@ -205,9 +205,11 @@ public class ApnSettingTest extends TelephonyTest { Field[] fields = ApnSetting.class.getDeclaredFields(); for (Field f : fields) { int modifiers = f.getModifiers(); - if (Modifier.isStatic(modifiers) || !Modifier.isFinal(modifiers)) { + if (Modifier.isStatic(modifiers) || !Modifier.isFinal(modifiers) + || "mId".equals(f.getName())) { continue; } + f.setAccessible(true); ApnSetting testApn = null; if (int.class.equals(f.getType())) { @@ -378,4 +380,52 @@ public class ApnSettingTest extends TelephonyTest { .build(); assertEquals("proxy.mobile.att.net", apn3.getMmsProxyAddressAsString()); } + + @Test + public void testApnProfileEqualsWithoutID() { + ApnSetting apn1 = new ApnSetting.Builder() + .setId(1234) + .setOperatorNumeric("310260") + .setEntryName("ims") + .setApnName("ims") + .setApnTypeBitmask(ApnSetting.TYPE_IMS) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IPV6) + .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_EDGE + | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS)) + .setMtuV4(1440) + .setCarrierEnabled(true) + .build(); + + ApnSetting apn2 = new ApnSetting.Builder() + .setId(1235) + .setOperatorNumeric("310260") + .setEntryName("ims") + .setApnName("ims") + .setApnTypeBitmask(ApnSetting.TYPE_IMS) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IPV6) + .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_EDGE + | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS)) + .setMtuV4(1440) + .setCarrierEnabled(true) + .build(); + + ApnSetting apn3 = new ApnSetting.Builder() + .setId(1234) + .setOperatorNumeric("310260") + .setEntryName("ims") + .setApnName("ims2") + .setApnTypeBitmask(ApnSetting.TYPE_IMS) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IPV6) + .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_EDGE + | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS)) + .setMtuV4(1440) + .setCarrierEnabled(true) + .build(); + + assertTrue(apn1.equals(apn2)); + assertFalse(apn1.equals(apn3)); + } } -- GitLab From c32f4471aa8cb031a656bf156831065be73e6b43 Mon Sep 17 00:00:00 2001 From: Jonggeon Kim Date: Wed, 25 Jan 2023 00:16:29 +0000 Subject: [PATCH 557/656] NR SA disabling for Wifi call HO Enables or Disables NR-SA mode temporarily under certain conditions where WFC is established or IMS is registered over WiFi in order to improve the delay or voice mute issue when the handover from ePDG to NR is not supported in UE or network. Bug: 265109622 Test: atest FrameworksTelephonyTests:ImsNrSaModeHandlerTest Change-Id: I2995408fad309c2e55933eeb32dfca8cdf225a52 --- .../telephony/TelephonyComponentFactory.java | 9 + .../imsphone/ImsNrSaModeHandler.java | 354 ++++++++++++++++ .../internal/telephony/imsphone/ImsPhone.java | 9 + .../internal/telephony/SimulatedCommands.java | 21 + .../internal/telephony/TelephonyTest.java | 5 + .../imsphone/ImsNrSaModeHandlerTest.java | 383 ++++++++++++++++++ 6 files changed, 781 insertions(+) create mode 100644 src/java/com/android/internal/telephony/imsphone/ImsNrSaModeHandler.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsNrSaModeHandlerTest.java diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java index 08c02e2ea9..d74b2b9f88 100644 --- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java +++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java @@ -41,6 +41,7 @@ import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; +import com.android.internal.telephony.imsphone.ImsNrSaModeHandler; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.nitz.NitzStateMachineImpl; @@ -385,6 +386,14 @@ public class TelephonyComponentFactory { return new ImsExternalCallTracker(imsPhone, imsPhone.getContext().getMainExecutor()); } + /** + * Create an ImsNrSaModeHandler. + */ + public ImsNrSaModeHandler makeImsNrSaModeHandler(ImsPhone imsPhone) { + + return new ImsNrSaModeHandler(imsPhone, imsPhone.getLooper()); + } + /** * Create an AppSmsManager for per-app SMS message. */ diff --git a/src/java/com/android/internal/telephony/imsphone/ImsNrSaModeHandler.java b/src/java/com/android/internal/telephony/imsphone/ImsNrSaModeHandler.java new file mode 100644 index 0000000000..b54a97371a --- /dev/null +++ b/src/java/com/android/internal/telephony/imsphone/ImsNrSaModeHandler.java @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2023 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.imsphone; + +import static android.telephony.CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA; +import static android.telephony.CarrierConfigManager.Ims.KEY_SA_DISABLE_POLICY_INT; +import static android.telephony.CarrierConfigManager.Ims.NrSaDisablePolicy; +import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_NONE; +import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_VOWIFI_REGISTERED; +import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED; +import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED; +import static android.telephony.CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY; +import static android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech; +import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.Call; + +import java.util.Arrays; +import java.util.Set; + +/** + * Enables or Disables NR-SA mode temporarily under certain conditions where WFC is established or + * IMS is registered over WiFi in order to improve the delay or voice mute issue when the handover + * from ePDG to NR is not supported in UE or network. + */ +public class ImsNrSaModeHandler extends Handler{ + + public static final String TAG = "ImsNrSaModeHandler"; + public static final String MMTEL_FEATURE_TAG = + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\""; + + private static final int MSG_PRECISE_CALL_STATE_CHANGED = 101; + private static final int MSG_REQUEST_IS_VONR_ENABLED = 102; + private static final int MSG_RESULT_IS_VONR_ENABLED = 103; + + private final @NonNull ImsPhone mPhone; + private @Nullable CarrierConfigManager mCarrierConfigManager; + + private @NrSaDisablePolicy int mNrSaDisablePolicy; + private boolean mIsNrSaDisabledForWfc; + private boolean mIsVowifiRegistered; + private boolean mIsInImsCall; + private boolean mIsNrSaSupported; + + private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = + (slotIndex, subId, carrierId, specificCarrierId) -> setNrSaDisablePolicy(subId); + + public ImsNrSaModeHandler(@NonNull ImsPhone phone, Looper looper) { + super(looper); + mPhone = phone; + mCarrierConfigManager = (CarrierConfigManager) mPhone.getContext() + .getSystemService(Context.CARRIER_CONFIG_SERVICE); + + registerForCarrierConfigChanges(); + } + + /** + * Performs any cleanup required before the ImsNrSaModeHandler is destroyed. + */ + public void tearDown() { + unregisterForCarrierConfigChanges(); + unregisterForPreciseCallStateChanges(); + + if (isNrSaDisabledForWfc()) { + setNrSaMode(true); + } + } + + /** + * Based on changed VoWiFi reg state and call state, handles NR SA mode if needed. + * It is including handover case. + * + * @param imsRadioTech The current registered RAT. + */ + public void onImsRegistered( + @ImsRegistrationTech int imsRadioTech, @NonNull Set featureTags) { + if (mNrSaDisablePolicy == SA_DISABLE_POLICY_NONE) { + return; + } + + Log.d(TAG, "onImsRegistered: ImsRegistrationTech = " + imsRadioTech); + + boolean isVowifiRegChanged = false; + + if (isVowifiRegistered() && imsRadioTech != REGISTRATION_TECH_IWLAN) { + setVowifiRegStatus(false); + isVowifiRegChanged = true; + } else if (!isVowifiRegistered() && imsRadioTech == REGISTRATION_TECH_IWLAN + && featureTags.contains(MMTEL_FEATURE_TAG)) { + setVowifiRegStatus(true); + isVowifiRegChanged = true; + } + + if (isVowifiRegChanged) { + if (mNrSaDisablePolicy == SA_DISABLE_POLICY_VOWIFI_REGISTERED) { + setNrSaMode(!isVowifiRegistered()); + } else if ((mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED + || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) + && isImsCallOngoing()) { + if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { + requestIsVonrEnabled(!isVowifiRegistered()); + return; + } + + setNrSaMode(!isVowifiRegistered()); + } + } + } + + /** + * Based on changed VoWiFi reg state and call state, handles NR SA mode if needed. + * + * @param imsRadioTech The current un-registered RAT. + */ + public void onImsUnregistered( + @ImsRegistrationTech int imsRadioTech) { + if (mNrSaDisablePolicy == SA_DISABLE_POLICY_NONE + || imsRadioTech != REGISTRATION_TECH_IWLAN || !isVowifiRegistered()) { + return; + } + + Log.d(TAG, "onImsUnregistered : ImsRegistrationTech = " + imsRadioTech); + + setVowifiRegStatus(false); + + if (mNrSaDisablePolicy == SA_DISABLE_POLICY_VOWIFI_REGISTERED) { + setNrSaMode(true); + } else if ((mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED + || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) + && isImsCallOngoing()) { + if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { + requestIsVonrEnabled(true); + return; + } + + setNrSaMode(true); + } + } + + /** + * Based on changed precise call state and VoWiFi reg state, handles NR SA mode if needed. + */ + public void onPreciseCallStateChanged() { + Log.d(TAG, "onPreciseCallStateChanged : foreground state = " + + mPhone.getForegroundCall().getState() + ", background state = " + + mPhone.getBackgroundCall().getState()); + + boolean isImsCallStatusChanged = false; + + if (isImsCallJustEstablished()) { + setImsCallStatus(true); + isImsCallStatusChanged = true; + } else if (isImsCallJustTerminated()) { + setImsCallStatus(false); + isImsCallStatusChanged = true; + } + + if (isVowifiRegistered() && isImsCallStatusChanged) { + if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { + requestIsVonrEnabled(!isImsCallOngoing()); + return; + } + + setNrSaMode(!isImsCallOngoing()); + } + } + + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch (msg.what) { + case MSG_PRECISE_CALL_STATE_CHANGED : + onPreciseCallStateChanged(); + break; + case MSG_REQUEST_IS_VONR_ENABLED : + Log.d(TAG, "request isVoNrEnabled"); + mPhone.getDefaultPhone().mCi.isVoNrEnabled( + obtainMessage(MSG_RESULT_IS_VONR_ENABLED, msg.obj), null); + break; + case MSG_RESULT_IS_VONR_ENABLED : + ar = (AsyncResult) msg.obj; + + if (ar.result != null) { + boolean vonrEnabled = ((Boolean) ar.result).booleanValue(); + + Log.d(TAG, "result isVoNrEnabled = " + vonrEnabled); + if (!vonrEnabled) { + setNrSaMode(((Boolean) ar.userObj).booleanValue()); + } + } + + ar = null; + break; + default : + break; + } + } + + /** + * Registers for precise call state changes. + */ + private void registerForPreciseCallStateChanges() { + mPhone.registerForPreciseCallStateChanged(this, MSG_PRECISE_CALL_STATE_CHANGED, null); + } + + /** + * Unregisters for precise call state changes. + */ + private void unregisterForPreciseCallStateChanges() { + mPhone.unregisterForPreciseCallStateChanged(this); + } + + /** + * Registers for carrier config changes. + */ + private void registerForCarrierConfigChanges() { + if (mCarrierConfigManager != null) { + mCarrierConfigManager.registerCarrierConfigChangeListener( + this::post, mCarrierConfigChangeListener); + } + } + + /** + * Unregisters for carrier config changes. + */ + private void unregisterForCarrierConfigChanges() { + if (mCarrierConfigManager != null) { + mCarrierConfigManager.unregisterCarrierConfigChangeListener( + mCarrierConfigChangeListener); + } + } + + private void setNrSaDisablePolicy(int subId) { + if (mPhone.getSubId() == subId && mCarrierConfigManager != null) { + PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), + KEY_SA_DISABLE_POLICY_INT, KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); + mNrSaDisablePolicy = bundle.getInt(KEY_SA_DISABLE_POLICY_INT); + mIsNrSaSupported = Arrays.stream( + bundle.getIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY)).anyMatch( + value -> value == CARRIER_NR_AVAILABILITY_SA); + + Log.d(TAG, "setNrSaDisablePolicy : NrSaDisablePolicy = " + + mNrSaDisablePolicy + ", IsNrSaSupported = " + mIsNrSaSupported); + + if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED + || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED) { + registerForPreciseCallStateChanges(); + } else { + unregisterForPreciseCallStateChanges(); + } + } + } + + private void requestIsVonrEnabled(boolean onOrOff) { + Message msg = obtainMessage(MSG_REQUEST_IS_VONR_ENABLED, onOrOff); + msg.sendToTarget(); + } + + private void setNrSaMode(boolean onOrOff) { + if (mIsNrSaSupported) { + mPhone.getDefaultPhone().mCi.setN1ModeEnabled(onOrOff, null); + Log.i(TAG, "setNrSaMode : " + onOrOff); + + setNrSaDisabledForWfc(!onOrOff); + } + } + + /** + * Sets VoWiFi reg status. + */ + @VisibleForTesting + public void setVowifiRegStatus(boolean registered) { + Log.d(TAG, "setVowifiRegStatus : " + registered); + mIsVowifiRegistered = registered; + } + + /** + * Sets IMS call status + */ + @VisibleForTesting + public void setImsCallStatus(boolean inImsCall) { + Log.d(TAG, "setImsCallStatus : " + inImsCall); + mIsInImsCall = inImsCall; + } + + @VisibleForTesting + public boolean isVowifiRegistered() { + return mIsVowifiRegistered; + } + + @VisibleForTesting + public boolean isImsCallOngoing() { + return mIsInImsCall; + } + + @VisibleForTesting + public boolean isNrSaDisabledForWfc() { + return mIsNrSaDisabledForWfc; + } + + @VisibleForTesting + public void setNrSaDisabledForWfc(boolean disabled) { + mIsNrSaDisabledForWfc = disabled; + } + + private boolean isImsCallJustEstablished() { + if (!isImsCallOngoing()) { + if ((mPhone.getForegroundCall().getState() == Call.State.ACTIVE) + || (mPhone.getBackgroundCall().getState() == Call.State.ACTIVE)) { + Log.d(TAG, "isImsCallJustEstablished"); + return true; + } + } + + return false; + } + + private boolean isImsCallJustTerminated() { + if (isImsCallOngoing() && (!mPhone.getForegroundCall().getState().isAlive() + && !mPhone.getBackgroundCall().getState().isAlive())) { + Log.d(TAG, "isImsCallJustTerminated"); + return true; + } + + return false; + } +} diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 0283499cab..e454fa33cc 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -265,6 +265,7 @@ public class ImsPhone extends ImsPhoneBase { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) ImsPhoneCallTracker mCT; ImsExternalCallTracker mExternalCallTracker; + ImsNrSaModeHandler mImsNrSaModeHandler; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private ArrayList mPendingMMIs = new ArrayList(); @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -475,6 +476,10 @@ public class ImsPhone extends ImsPhoneBase { TelephonyComponentFactory.getInstance() .inject(ImsExternalCallTracker.class.getName()) .makeImsExternalCallTracker(this); + mImsNrSaModeHandler = + TelephonyComponentFactory.getInstance() + .inject(ImsNrSaModeHandler.class.getName()) + .makeImsNrSaModeHandler(this); mCT = TelephonyComponentFactory.getInstance().inject(ImsPhoneCallTracker.class.getName()) .makeImsPhoneCallTracker(this); mCT.registerPhoneStateListener(mExternalCallTracker); @@ -522,6 +527,7 @@ public class ImsPhone extends ImsPhoneBase { //super.dispose(); mPendingMMIs.clear(); mExternalCallTracker.tearDown(); + mImsNrSaModeHandler.tearDown(); mCT.unregisterPhoneStateListener(mExternalCallTracker); mCT.unregisterForVoiceCallEnded(this); mCT.dispose(); @@ -2473,6 +2479,8 @@ public class ImsPhone extends ImsPhoneBase { getDefaultPhone().setImsRegistrationState(true); mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.CONNECTED, null); mImsStats.onImsRegistered(imsRadioTech); + mImsNrSaModeHandler.onImsRegistered( + attributes.getRegistrationTechnology(), attributes.getFeatureTags()); updateImsRegistrationInfo(REGISTRATION_STATE_REGISTERED, attributes.getRegistrationTechnology(), SUGGESTED_ACTION_NONE); } @@ -2509,6 +2517,7 @@ public class ImsPhone extends ImsPhoneBase { mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.DISCONNECTED, imsReasonInfo); mImsStats.onImsUnregistered(imsReasonInfo); + mImsNrSaModeHandler.onImsUnregistered(imsRadioTech); mImsRegistrationTech = REGISTRATION_TECH_NONE; int suggestedModemAction = SUGGESTED_ACTION_NONE; if (imsReasonInfo.getCode() == ImsReasonInfo.CODE_REGISTRATION_ERROR) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index bbea09a4ba..2f51ec9ba0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -196,6 +196,9 @@ public class SimulatedCommands extends BaseCommands private int[] mImsRegistrationInfo = new int[4]; + private boolean mN1ModeEnabled = false; + private boolean mVonrEnabled = false; + //***** Constructor public SimulatedCommands() { @@ -2611,4 +2614,22 @@ public class SimulatedCommands extends BaseCommands public int[] getImsRegistrationInfo() { return mImsRegistrationInfo; } + + @Override + public void setN1ModeEnabled(boolean enable, Message result) { + mN1ModeEnabled = enable; + } + + public boolean isN1ModeEnabled() { + return mN1ModeEnabled; + } + + @Override + public void isVoNrEnabled(Message message, WorkSource workSource) { + resultSuccess(message, (Object) mVonrEnabled); + } + + public void setVonrEnabled(boolean vonrEnable) { + mVonrEnabled = vonrEnable; + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 6ca2729137..0a8893288f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -106,6 +106,7 @@ import com.android.internal.telephony.data.LinkBandwidthEstimator; import com.android.internal.telephony.data.PhoneSwitcher; import com.android.internal.telephony.emergency.EmergencyNumberTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; +import com.android.internal.telephony.imsphone.ImsNrSaModeHandler; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.metrics.ImsStats; @@ -232,6 +233,7 @@ public abstract class TelephonyTest { protected CarrierSignalAgent mCarrierSignalAgent; protected CarrierActionAgent mCarrierActionAgent; protected ImsExternalCallTracker mImsExternalCallTracker; + protected ImsNrSaModeHandler mImsNrSaModeHandler; protected AppSmsManager mAppSmsManager; protected IccSmsInterfaceManager mIccSmsInterfaceManager; protected SmsDispatchersController mSmsDispatchersController; @@ -466,6 +468,7 @@ public abstract class TelephonyTest { mCarrierSignalAgent = Mockito.mock(CarrierSignalAgent.class); mCarrierActionAgent = Mockito.mock(CarrierActionAgent.class); mImsExternalCallTracker = Mockito.mock(ImsExternalCallTracker.class); + mImsNrSaModeHandler = Mockito.mock(ImsNrSaModeHandler.class); mAppSmsManager = Mockito.mock(AppSmsManager.class); mIccSmsInterfaceManager = Mockito.mock(IccSmsInterfaceManager.class); mSmsDispatchersController = Mockito.mock(SmsDispatchersController.class); @@ -585,6 +588,8 @@ public abstract class TelephonyTest { anyInt(), nullable(Object.class)); doReturn(mImsExternalCallTracker).when(mTelephonyComponentFactory) .makeImsExternalCallTracker(nullable(ImsPhone.class)); + doReturn(mImsNrSaModeHandler).when(mTelephonyComponentFactory) + .makeImsNrSaModeHandler(nullable(ImsPhone.class)); doReturn(mAppSmsManager).when(mTelephonyComponentFactory) .makeAppSmsManager(nullable(Context.class)); doReturn(mCarrierSignalAgent).when(mTelephonyComponentFactory) diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsNrSaModeHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsNrSaModeHandlerTest.java new file mode 100644 index 0000000000..217dfb8eaf --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsNrSaModeHandlerTest.java @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2023 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.imsphone; + +import static android.telephony.CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA; +import static android.telephony.CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA; +import static android.telephony.CarrierConfigManager.Ims.KEY_SA_DISABLE_POLICY_INT; +import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_NONE; +import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_VOWIFI_REGISTERED; +import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED; +import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED; +import static android.telephony.CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY; +import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; +import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.os.Handler; +import android.telephony.CarrierConfigManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.ArraySet; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.TelephonyTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.Set; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public final class ImsNrSaModeHandlerTest extends TelephonyTest{ + @Captor ArgumentCaptor + mCarrierConfigChangeListenerCaptor; + @Captor ArgumentCaptor mPreciseCallStateHandlerCaptor; + + private ImsNrSaModeHandler mTestImsNrSaModeHandler; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; + private Handler mPreciseCallStateHandler; + + @Mock private ImsPhoneCall mForegroundCall; + @Mock private ImsPhoneCall mBackgroundCall; + private Call.State mActiveState = ImsPhoneCall.State.ACTIVE; + private Call.State mIdleState = ImsPhoneCall.State.IDLE; + + private int mAnyInt = 0; + private final Set mFeatureTags = + new ArraySet(Arrays.asList(ImsNrSaModeHandler.MMTEL_FEATURE_TAG)); + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + MockitoAnnotations.initMocks(this); + + mTestImsNrSaModeHandler = new ImsNrSaModeHandler(mImsPhone, mTestableLooper.getLooper()); + + verify(mCarrierConfigManager).registerCarrierConfigChangeListener( + any(), mCarrierConfigChangeListenerCaptor.capture()); + + mCarrierConfigChangeListener = mCarrierConfigChangeListenerCaptor.getValue(); + + doReturn(mAnyInt).when(mImsPhone).getSubId(); + doReturn(mContextFixture.getCarrierConfigBundle()).when(mCarrierConfigManager) + .getConfigForSubId(anyInt(), any()); + doReturn(mPhone).when(mImsPhone).getDefaultPhone(); + + doReturn(mForegroundCall).when(mImsPhone).getForegroundCall(); + doReturn(mBackgroundCall).when(mImsPhone).getBackgroundCall(); + + doReturn(mActiveState).when(mForegroundCall).getState(); + doReturn(mActiveState).when(mBackgroundCall).getState(); + } + + @After + public void tearDown() throws Exception { + mTestImsNrSaModeHandler = null; + super.tearDown(); + } + + @Test + public void testTearDown() { + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED); + mContextFixture.getCarrierConfigBundle().putIntArray( + KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + verify(mImsPhone).registerForPreciseCallStateChanged( + mPreciseCallStateHandlerCaptor.capture(), anyInt(), any()); + mPreciseCallStateHandler = mPreciseCallStateHandlerCaptor.getValue(); + + mSimulatedCommands.setN1ModeEnabled(false, null); + mTestImsNrSaModeHandler.setNrSaDisabledForWfc(true); + + mTestImsNrSaModeHandler.tearDown(); + + verify(mCarrierConfigManager).unregisterCarrierConfigChangeListener(any()); + verify(mImsPhone).unregisterForPreciseCallStateChanged(mPreciseCallStateHandler); + assertTrue(mSimulatedCommands.isN1ModeEnabled()); + } + + @Test + public void testOnImsRegisteredWithSaDisablePolicyNone() { + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_NONE); + mContextFixture.getCarrierConfigBundle().putIntArray( + KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + mTestImsNrSaModeHandler.setVowifiRegStatus(false); + + mTestImsNrSaModeHandler.onImsRegistered(REGISTRATION_TECH_IWLAN, mFeatureTags); + + assertFalse(mTestImsNrSaModeHandler.isVowifiRegistered()); + } + + @Test + public void testOnImsRegisteredWithSaDisablePolicyWfcEstablished() { + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED); + mContextFixture.getCarrierConfigBundle().putIntArray( + KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + verify(mImsPhone).registerForPreciseCallStateChanged(any(), anyInt(), any()); + + mSimulatedCommands.setN1ModeEnabled(false, null); + mTestImsNrSaModeHandler.setVowifiRegStatus(true); + mTestImsNrSaModeHandler.setImsCallStatus(true); + + mTestImsNrSaModeHandler.onImsRegistered(REGISTRATION_TECH_NONE, mFeatureTags); + + assertFalse(mTestImsNrSaModeHandler.isVowifiRegistered()); + assertTrue(mSimulatedCommands.isN1ModeEnabled()); + } + + @Test + public void testOnImsRegisteredWithSaDisablePolicyWfcEstablishedWithVonrDisabled() { + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED); + mContextFixture.getCarrierConfigBundle().putIntArray( + KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + verify(mImsPhone).registerForPreciseCallStateChanged(any(), anyInt(), any()); + + mSimulatedCommands.setN1ModeEnabled(true, null); + mTestImsNrSaModeHandler.setVowifiRegStatus(false); + mTestImsNrSaModeHandler.setImsCallStatus(true); + mSimulatedCommands.setVonrEnabled(true); + + mTestImsNrSaModeHandler.onImsRegistered(REGISTRATION_TECH_IWLAN, mFeatureTags); + processAllMessages(); + + assertTrue(mTestImsNrSaModeHandler.isVowifiRegistered()); + assertTrue(mSimulatedCommands.isN1ModeEnabled()); + + mSimulatedCommands.setN1ModeEnabled(true, null); + mTestImsNrSaModeHandler.setVowifiRegStatus(false); + mTestImsNrSaModeHandler.setImsCallStatus(true); + mSimulatedCommands.setVonrEnabled(false); + + mTestImsNrSaModeHandler.onImsRegistered(REGISTRATION_TECH_IWLAN, mFeatureTags); + processAllMessages(); + + assertTrue(mTestImsNrSaModeHandler.isVowifiRegistered()); + assertFalse(mSimulatedCommands.isN1ModeEnabled()); + + mSimulatedCommands.setN1ModeEnabled(true, null); + mTestImsNrSaModeHandler.setVowifiRegStatus(false); + mTestImsNrSaModeHandler.setImsCallStatus(true); + mSimulatedCommands.setVonrEnabled(false); + + mFeatureTags.remove(ImsNrSaModeHandler.MMTEL_FEATURE_TAG); + mTestImsNrSaModeHandler.onImsRegistered(REGISTRATION_TECH_IWLAN, mFeatureTags); + processAllMessages(); + + assertFalse(mTestImsNrSaModeHandler.isVowifiRegistered()); + assertTrue(mSimulatedCommands.isN1ModeEnabled()); + + mSimulatedCommands.setN1ModeEnabled(true, null); + mTestImsNrSaModeHandler.setVowifiRegStatus(false); + mTestImsNrSaModeHandler.setImsCallStatus(true); + mSimulatedCommands.setVonrEnabled(false); + + mFeatureTags.add(ImsNrSaModeHandler.MMTEL_FEATURE_TAG); + mTestImsNrSaModeHandler.onImsRegistered(REGISTRATION_TECH_IWLAN, mFeatureTags); + processAllMessages(); + + assertTrue(mTestImsNrSaModeHandler.isVowifiRegistered()); + assertFalse(mSimulatedCommands.isN1ModeEnabled()); + } + + @Test + public void testOnImsRegisteredWithSaDisablePolicyVowifiRegistered() { + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_VOWIFI_REGISTERED); + mContextFixture.getCarrierConfigBundle().putIntArray( + KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + mSimulatedCommands.setN1ModeEnabled(true, null); + mTestImsNrSaModeHandler.setVowifiRegStatus(false); + + mTestImsNrSaModeHandler.onImsRegistered(REGISTRATION_TECH_IWLAN, mFeatureTags); + + assertTrue(mTestImsNrSaModeHandler.isVowifiRegistered()); + assertFalse(mSimulatedCommands.isN1ModeEnabled()); + + mSimulatedCommands.setN1ModeEnabled(false, null); + mTestImsNrSaModeHandler.setVowifiRegStatus(true); + + mTestImsNrSaModeHandler.onImsRegistered(REGISTRATION_TECH_NONE, mFeatureTags); + + assertFalse(mTestImsNrSaModeHandler.isVowifiRegistered()); + assertTrue(mSimulatedCommands.isN1ModeEnabled()); + } + + @Test + public void testOnImsUnregisteredDoNothingIfNotVowifiRegNoti() { + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_VOWIFI_REGISTERED); + mContextFixture.getCarrierConfigBundle().putIntArray( + KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + mTestImsNrSaModeHandler.setVowifiRegStatus(true); + + mTestImsNrSaModeHandler.onImsUnregistered(REGISTRATION_TECH_NONE); + + assertTrue(mTestImsNrSaModeHandler.isVowifiRegistered()); + } + + @Test + public void testOnImsUnregisteredWithSaDisablePolicyVowifiRegistered() { + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_VOWIFI_REGISTERED); + mContextFixture.getCarrierConfigBundle().putIntArray( + KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + mSimulatedCommands.setN1ModeEnabled(false, null); + mTestImsNrSaModeHandler.setVowifiRegStatus(true); + + mTestImsNrSaModeHandler.onImsUnregistered(REGISTRATION_TECH_IWLAN); + + assertFalse(mTestImsNrSaModeHandler.isVowifiRegistered()); + assertTrue(mSimulatedCommands.isN1ModeEnabled()); + + mSimulatedCommands.setN1ModeEnabled(false, null); + mTestImsNrSaModeHandler.setVowifiRegStatus(true); + + mTestImsNrSaModeHandler.onImsUnregistered(REGISTRATION_TECH_NONE); + + assertTrue(mTestImsNrSaModeHandler.isVowifiRegistered()); + assertFalse(mSimulatedCommands.isN1ModeEnabled()); + } + + @Test + public void testOnPreciseCallStateChangedWithSaDisablePolicyWfcEstablished() { + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED); + mContextFixture.getCarrierConfigBundle().putIntArray( + KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + verify(mImsPhone).registerForPreciseCallStateChanged( + mPreciseCallStateHandlerCaptor.capture(), anyInt(), any()); + mPreciseCallStateHandler = mPreciseCallStateHandlerCaptor.getValue(); + + mTestImsNrSaModeHandler.setVowifiRegStatus(true); + mSimulatedCommands.setN1ModeEnabled(true, null); + + mPreciseCallStateHandler.handleMessage(mPreciseCallStateHandler.obtainMessage(101)); + + assertTrue(mTestImsNrSaModeHandler.isImsCallOngoing()); + assertFalse(mSimulatedCommands.isN1ModeEnabled()); + + mTestImsNrSaModeHandler.setVowifiRegStatus(false); + mSimulatedCommands.setN1ModeEnabled(true, null); + + doReturn(mActiveState).when(mForegroundCall).getState(); + doReturn(mActiveState).when(mBackgroundCall).getState(); + mPreciseCallStateHandler.handleMessage(mPreciseCallStateHandler.obtainMessage(101)); + + assertTrue(mTestImsNrSaModeHandler.isImsCallOngoing()); + assertTrue(mSimulatedCommands.isN1ModeEnabled()); + + mTestImsNrSaModeHandler.setVowifiRegStatus(false); + mTestImsNrSaModeHandler.setImsCallStatus(false); + mSimulatedCommands.setN1ModeEnabled(true, null); + + doReturn(mIdleState).when(mForegroundCall).getState(); + doReturn(mIdleState).when(mBackgroundCall).getState(); + mPreciseCallStateHandler.handleMessage(mPreciseCallStateHandler.obtainMessage(101)); + + assertFalse(mTestImsNrSaModeHandler.isImsCallOngoing()); + assertTrue(mSimulatedCommands.isN1ModeEnabled()); + + mTestImsNrSaModeHandler.setVowifiRegStatus(true); + mTestImsNrSaModeHandler.setImsCallStatus(true); + mSimulatedCommands.setN1ModeEnabled(false, null); + mPreciseCallStateHandler.handleMessage(mPreciseCallStateHandler.obtainMessage(101)); + + assertFalse(mTestImsNrSaModeHandler.isImsCallOngoing()); + assertTrue(mSimulatedCommands.isN1ModeEnabled()); + } + + @Test + public void testUnregisterForPreciseCallStateChangeIfNeeded() { + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED); + mContextFixture.getCarrierConfigBundle().putIntArray( + KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + verify(mImsPhone).registerForPreciseCallStateChanged( + mPreciseCallStateHandlerCaptor.capture(), anyInt(), any()); + mPreciseCallStateHandler = mPreciseCallStateHandlerCaptor.getValue(); + + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_VOWIFI_REGISTERED); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + verify(mImsPhone).unregisterForPreciseCallStateChanged(mPreciseCallStateHandler); + } + + @Test + public void testNrSaModeIsNotHandledWhenNotSupported() { + mContextFixture.getCarrierConfigBundle().putInt( + KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED); + mContextFixture.getCarrierConfigBundle().putIntArray( + KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_NSA}); + + mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); + + mSimulatedCommands.setN1ModeEnabled(false, null); + mTestImsNrSaModeHandler.setVowifiRegStatus(true); + + mTestImsNrSaModeHandler.onImsRegistered(REGISTRATION_TECH_NONE, mFeatureTags); + + assertFalse(mTestImsNrSaModeHandler.isVowifiRegistered()); + assertFalse(mSimulatedCommands.isN1ModeEnabled()); + } +} -- GitLab From 5e7ddc672280478ca8b41d71b9d8659ad24157a7 Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Fri, 10 Feb 2023 03:03:44 +0000 Subject: [PATCH 558/656] add report satellite controller/provision metrics reporting satellite controller atom parameter count for successful/failed service enablement count for successful/failed outgoing/incoming datagrams count for successful/failed SOS sms count for successful/failed location sharing count for successful/failed provision/deprovision total service up time total battery consumption percent while satellite (modem) is on total time when battery is being charged reporting satellite provision atom parameter provision result code time to process provisioning whether provision/deprovision is requested canceled Bug: 271792323 Test: flash and device test for controller parameter passing Change-Id: Iddf9ffc0f0cb32b8792a5825b13173c87f629e2a --- .../satellite/DatagramDispatcher.java | 9 + .../telephony/satellite/DatagramReceiver.java | 11 +- .../satellite/SatelliteController.java | 56 ++- .../metrics/ControllerMetricsStats.java | 327 ++++++++++++++++++ .../metrics/ProvisionMetricsStats.java | 110 ++++++ 5 files changed, 511 insertions(+), 2 deletions(-) create mode 100644 src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java create mode 100644 src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index 618269c776..439c97f8d4 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -33,6 +33,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.metrics.SatelliteStats; +import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import java.util.LinkedHashMap; import java.util.Map.Entry; @@ -52,6 +53,7 @@ public class DatagramDispatcher extends Handler { @NonNull private static DatagramDispatcher sInstance; @NonNull private final Context mContext; @NonNull private final DatagramController mDatagramController; + @NonNull private final ControllerMetricsStats mControllerMetricsStats; private static AtomicLong mNextDatagramId = new AtomicLong(0); @@ -103,6 +105,7 @@ public class DatagramDispatcher extends Handler { super(looper); mContext = context; mDatagramController = datagramController; + mControllerMetricsStats = ControllerMetricsStats.getInstance(); synchronized (mLock) { mSendingDatagramInProgress = false; @@ -236,6 +239,8 @@ public class DatagramDispatcher extends Handler { mDatagramController.updateSendStatus(argument.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS, getPendingDatagramCount(), error); + mControllerMetricsStats.reportOutgoingDatagramSuccessCount( + argument.datagramType); if (getPendingDatagramCount() != 0) { // Send pending datagrams @@ -245,10 +250,13 @@ public class DatagramDispatcher extends Handler { SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, getPendingDatagramCount(), SatelliteManager.SATELLITE_ERROR_NONE); + } } else { // Abort sending all the pending datagrams abortSendingPendingDatagrams(argument.subId, error); + mControllerMetricsStats.reportOutgoingDatagramFailCount( + argument.datagramType); } } break; @@ -352,6 +360,7 @@ public class DatagramDispatcher extends Handler { SendSatelliteDatagramArgument argument = entry.getValue(); argument.callback.accept(errorCode); reportSendDatagramCompleted(argument, errorCode); + mControllerMetricsStats.reportOutgoingDatagramFailCount(argument.datagramType); } // Clear pending datagram maps diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index d7b96bc335..cfb9dfdcf7 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -45,6 +45,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ILongConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.metrics.SatelliteStats; +import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; @@ -69,6 +70,7 @@ public class DatagramReceiver extends Handler { @NonNull private final ContentResolver mContentResolver; @NonNull private SharedPreferences mSharedPreferences = null; @NonNull private final DatagramController mDatagramController; + @NonNull private final ControllerMetricsStats mControllerMetricsStats; private long mDatagramTransferStartTime = 0; @@ -112,6 +114,7 @@ public class DatagramReceiver extends Handler { mContext = context; mContentResolver = context.getContentResolver(); mDatagramController = datagramController; + mControllerMetricsStats = ControllerMetricsStats.getInstance(); HandlerThread backgroundThread = new HandlerThread(TAG); backgroundThread.start(); @@ -342,6 +345,9 @@ public class DatagramReceiver extends Handler { obtainMessage(EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM, argument), getTimeoutToReceiveAck()); }); + + sInstance.mControllerMetricsStats.reportIncomingDatagramCount( + SatelliteManager.SATELLITE_ERROR_NONE); } if (pendingCount == 0) { @@ -412,8 +418,9 @@ public class DatagramReceiver extends Handler { mDatagramController.getReceivePendingCount(), SatelliteManager.SATELLITE_ERROR_NONE); - // report not able to poll pending datagrams reportMetrics(null, SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + mControllerMetricsStats.reportIncomingDatagramCount( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); } break; } @@ -430,7 +437,9 @@ public class DatagramReceiver extends Handler { mDatagramController.updateReceiveStatus(request.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, mDatagramController.getReceivePendingCount(), error); + reportMetrics(null, error); + mControllerMetricsStats.reportIncomingDatagramCount(error); } break; } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index ca76d16c2a..1d59eb8887 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -52,6 +52,8 @@ import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; +import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; @@ -100,6 +102,8 @@ public class SatelliteController extends Handler { @NonNull private SatelliteSessionController mSatelliteSessionController; @NonNull private final PointingAppController mPointingAppController; @NonNull private final DatagramController mDatagramController; + @NonNull private final ControllerMetricsStats mControllerMetricsStats; + @NonNull private final ProvisionMetricsStats mProvisionMetricsStats; private SharedPreferences mSharedPreferences = null; private final CommandsInterface mCi; @@ -170,6 +174,7 @@ public class SatelliteController extends Handler { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected SatelliteController(@NonNull Context context, @NonNull Looper looper) { super(looper); + mContext = context; Phone phone = SatelliteServiceUtils.getPhone(); mCi = phone.mCi; @@ -181,6 +186,12 @@ public class SatelliteController extends Handler { // which is used to manage interactions with PointingUI app. mPointingAppController = PointingAppController.make(mContext); + // Create the SatelliteControllerMetrics to report controller metrics + // should be called before making DatagramController + loge("mControllerMetricsStats = ControllerMetricsStats.make(mContext);"); + mControllerMetricsStats = ControllerMetricsStats.make(mContext); + mProvisionMetricsStats = ProvisionMetricsStats.getOrCreateInstance(); + // Create the DatagramController singleton, // which is used to send and receive satellite datagrams. mDatagramController = DatagramController.make(mContext, looper, mPointingAppController); @@ -436,6 +447,8 @@ public class SatelliteController extends Handler { } mSatelliteProvisionCallbacks.put(argument.subId, argument.callback); onCompleted = obtainMessage(EVENT_PROVISION_SATELLITE_SERVICE_DONE, request); + // Log the current time for provision triggered + mProvisionMetricsStats.setProvisioningStartTime(); if (mSatelliteModemInterface.isSatelliteServiceSupported()) { mSatelliteModemInterface.provisionSatelliteService(argument.token, argument.regionId, onCompleted); @@ -448,6 +461,11 @@ public class SatelliteController extends Handler { loge("provisionSatelliteService: No phone object"); argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); notifyRequester(request); + mProvisionMetricsStats + .setResultCode(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE) + .reportProvisionMetrics(); + mControllerMetricsStats.reportProvisionCount( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); } break; } @@ -468,6 +486,9 @@ public class SatelliteController extends Handler { ProvisionSatelliteServiceArgument argument = (ProvisionSatelliteServiceArgument) request.argument; onCompleted = obtainMessage(EVENT_DEPROVISION_SATELLITE_SERVICE_DONE, request); + if (argument.callback != null) { + mProvisionMetricsStats.setProvisioningStartTime(); + } if (mSatelliteModemInterface.isSatelliteServiceSupported()) { mSatelliteModemInterface .deprovisionSatelliteService(argument.token, onCompleted); @@ -481,6 +502,11 @@ public class SatelliteController extends Handler { if (argument.callback != null) { argument.callback.accept( SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + mProvisionMetricsStats + .setResultCode(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE) + .reportProvisionMetrics(); + mControllerMetricsStats.reportDeprovisionCount( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); } } break; @@ -511,7 +537,7 @@ public class SatelliteController extends Handler { if (error == SatelliteManager.SATELLITE_ERROR_NONE) { if (argument.enableSatellite) { //If satellite mode is enabled successfully, disable Bluetooth and wifi - disableBluetoothWifiState();; + disableBluetoothWifiState(); } else { //Disabled satellite mode, Reset BT and Wifi if previously changed here checkAndEnableBluetoothWifiState(); @@ -529,6 +555,17 @@ public class SatelliteController extends Handler { } argument.callback.accept(error); // TODO: if error is ERROR_NONE, request satellite capabilities + + if (argument.enableSatellite) { + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + mControllerMetricsStats.onSatelliteEnabled(); + mControllerMetricsStats.reportServiceEnablementSuccessCount(); + } else { + mControllerMetricsStats.reportServiceEnablementFailCount(); + } + } else { + mControllerMetricsStats.onSatelliteDisabled(); + } break; } @@ -564,6 +601,7 @@ public class SatelliteController extends Handler { boolean enabled = ((int[]) ar.result)[0] == 1; if (DBG) logd("isSatelliteEnabled: " + enabled); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled); + updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE"); } } ((ResultReceiver) request.argument).send(error, bundle); @@ -1008,6 +1046,7 @@ public class SatelliteController extends Handler { sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, regionId, null, validSubId), phone); + mProvisionMetricsStats.setIsCanceled(true); }); return cancelTransport; } @@ -1350,6 +1389,12 @@ public class SatelliteController extends Handler { if (callback == null) { loge("handleEventProvisionSatelliteServiceDone: callback is null for subId=" + arg.subId); + mProvisionMetricsStats + .setResultCode(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE) + .setIsProvisionRequest(true) + .reportProvisionMetrics(); + mControllerMetricsStats.reportProvisionCount( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); return; } callback.accept(result); @@ -1364,6 +1409,11 @@ public class SatelliteController extends Handler { * TODO (b/267826133) we need to do this for all subscriptions on the device. */ registerForSatelliteProvisionStateChanged(arg.subId, null); + + mProvisionMetricsStats.setResultCode(result) + .setIsProvisionRequest(true) + .reportProvisionMetrics(); + mControllerMetricsStats.reportProvisionCount(result); } private void handleEventDeprovisionSatelliteServiceDone( @@ -1378,6 +1428,10 @@ public class SatelliteController extends Handler { if (arg.callback != null) { arg.callback.accept(result); + mProvisionMetricsStats.setResultCode(result) + .setIsProvisionRequest(false) + .reportProvisionMetrics(); + mControllerMetricsStats.reportDeprovisionCount(result); } if (result == SatelliteManager.SATELLITE_ERROR_NONE) { diff --git a/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java new file mode 100644 index 0000000000..d735cf2db7 --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2023 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.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.BatteryManager; +import android.telephony.satellite.SatelliteManager; +import android.util.Log; + +import com.android.internal.telephony.metrics.SatelliteStats; + +/** + * Stats to log to satellite metrics + */ +public class ControllerMetricsStats { + private static final int ADD_COUNT = 1; + private static final String TAG = ControllerMetricsStats.class.getSimpleName(); + private static final boolean DBG = false; + + private static ControllerMetricsStats sInstance; + + private final Context mContext; + private final SatelliteStats mSatelliteStats; + + private long mSatelliteOnTimeMillis; + private int mBatteryLevelWhenServiceOn; + private Boolean mIsSatelliteModemOn = null; + private Boolean mIsBatteryCharged = null; + private int mBatteryChargedStartTimeSec; + private int mTotalBatteryChargeTimeSec; + + /** + * @return The singleton instance of ControllerMetricsStats. + */ + public static ControllerMetricsStats getInstance() { + if (sInstance == null) { + loge("ControllerMetricsStats was not yet initialized."); + } + return sInstance; + } + + /** + * Create the ControllerMetricsStats singleton instance. + * + * @param context The Context for the ControllerMetricsStats. + * @return The singleton instance of ControllerMetricsStats. + */ + public static ControllerMetricsStats make(@NonNull Context context) { + if (sInstance == null) { + sInstance = new ControllerMetricsStats(context); + } + return sInstance; + } + + /** + * Create the ControllerMetricsStats to manage metrics report for + * {@link SatelliteStats.SatelliteControllerParams} + * @param context The Context for the ControllerMetricsStats. + */ + ControllerMetricsStats(@NonNull Context context) { + mContext = context; + mSatelliteStats = SatelliteStats.getInstance(); + } + + + /** Report a counter when an attempt for satellite service on is successfully done */ + public void reportServiceEnablementSuccessCount() { + logd("reportServiceEnablementSuccessCount()"); + mSatelliteStats.onSatelliteControllerMetrics( + new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfSatelliteServiceEnablementsSuccess(ADD_COUNT) + .build()); + } + + /** Report a counter when an attempt for satellite service on is failed */ + public void reportServiceEnablementFailCount() { + logd("reportServiceEnablementSuccessCount()"); + mSatelliteStats.onSatelliteControllerMetrics( + new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfSatelliteServiceEnablementsFail(ADD_COUNT) + .build()); + } + + /** Report a counter when an attempt for outgoing datagram is successfully done */ + public void reportOutgoingDatagramSuccessCount( + @NonNull @SatelliteManager.DatagramType int datagramType) { + SatelliteStats.SatelliteControllerParams controllerParam; + if (datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfOutgoingDatagramSuccess(ADD_COUNT) + .setCountOfDatagramTypeSosSmsSuccess(ADD_COUNT) + .build(); + } else if (datagramType == SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING) { + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfOutgoingDatagramSuccess(ADD_COUNT) + .setCountOfDatagramTypeLocationSharingSuccess(ADD_COUNT) + .build(); + } else { // datagramType == SatelliteManager.DATAGRAM_TYPE_UNKNOWN + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfOutgoingDatagramSuccess(ADD_COUNT) + .build(); + } + logd("reportServiceEnablementSuccessCount(): " + controllerParam); + mSatelliteStats.onSatelliteControllerMetrics(controllerParam); + } + + /** Report a counter when an attempt for outgoing datagram is failed */ + public void reportOutgoingDatagramFailCount( + @NonNull @SatelliteManager.DatagramType int datagramType) { + SatelliteStats.SatelliteControllerParams controllerParam; + if (datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfOutgoingDatagramFail(ADD_COUNT) + .setCountOfDatagramTypeSosSmsFail(ADD_COUNT) + .build(); + } else if (datagramType == SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING) { + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfOutgoingDatagramFail(ADD_COUNT) + .setCountOfDatagramTypeLocationSharingFail(ADD_COUNT) + .build(); + } else { // datagramType == SatelliteManager.DATAGRAM_TYPE_UNKNOWN + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfOutgoingDatagramFail(ADD_COUNT) + .build(); + } + logd("reportOutgoingDatagramFailCount(): " + controllerParam); + mSatelliteStats.onSatelliteControllerMetrics(controllerParam); + } + + /** Report a counter when an attempt for incoming datagram is failed */ + public void reportIncomingDatagramCount( + @NonNull @SatelliteManager.SatelliteError int result) { + SatelliteStats.SatelliteControllerParams controllerParam; + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfIncomingDatagramSuccess(ADD_COUNT) + .build(); + } else { + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfIncomingDatagramFail(ADD_COUNT) + .build(); + } + logd("reportIncomingDatagramCount(): " + controllerParam); + mSatelliteStats.onSatelliteControllerMetrics(controllerParam); + } + + /** Report a counter when an attempt for de-provision is success or not */ + public void reportProvisionCount(@NonNull @SatelliteManager.SatelliteError int result) { + SatelliteStats.SatelliteControllerParams controllerParam; + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfProvisionSuccess(ADD_COUNT) + .build(); + } else { + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfProvisionFail(ADD_COUNT) + .build(); + } + logd("reportProvisionCount(): " + controllerParam); + mSatelliteStats.onSatelliteControllerMetrics(controllerParam); + } + + /** Report a counter when an attempt for de-provision is success or not */ + public void reportDeprovisionCount(@NonNull @SatelliteManager.SatelliteError int result) { + SatelliteStats.SatelliteControllerParams controllerParam; + if (result == SatelliteManager.SATELLITE_ERROR_NONE) { + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfDeprovisionSuccess(ADD_COUNT) + .build(); + } else { + controllerParam = new SatelliteStats.SatelliteControllerParams.Builder() + .setCountOfDeprovisionFail(ADD_COUNT) + .build(); + } + logd("reportDeprovisionCount(): " + controllerParam); + mSatelliteStats.onSatelliteControllerMetrics(controllerParam); + } + + /** Return the total service up time for satellite service */ + private int captureTotalServiceUpTimeSec() { + long totalTimeMillis = System.currentTimeMillis() - mSatelliteOnTimeMillis; + mSatelliteOnTimeMillis = 0; + return (int) (totalTimeMillis / 1000); + } + + /** Return the total battery charge time while satellite service is on */ + private int captureTotalBatteryChargeTimeSec() { + int totalTime = mTotalBatteryChargeTimeSec; + mTotalBatteryChargeTimeSec = 0; + return totalTime; + } + + /** Capture the satellite service on time and register battery monitor */ + public void onSatelliteEnabled() { + if (!mIsSatelliteModemOn) { + mIsSatelliteModemOn = true; + + startCaptureBatteryLevel(mContext); + + // log the timestamp of the satellite modem power on + mSatelliteOnTimeMillis = System.currentTimeMillis(); + + // register broadcast receiver for monitoring battery status change + IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); + + logd("register BatteryStatusReceiver"); + mContext.registerReceiver(mBatteryStatusReceiver, filter); + } + } + + /** Capture the satellite service off time and de-register battery monitor */ + public void onSatelliteDisabled() { + if (mIsSatelliteModemOn) { + mIsSatelliteModemOn = false; + + logd("unregister BatteryStatusReceiver"); + mContext.unregisterReceiver(mBatteryStatusReceiver); + + int totalServiceUpTime = captureTotalServiceUpTimeSec(); + int batteryConsumptionPercent = captureTotalBatteryConsumptionPercent(mContext); + int totalBatteryChargeTime = captureTotalBatteryChargeTimeSec(); + + // report metrics about service up time and battery + SatelliteStats.SatelliteControllerParams controllerParam = + new SatelliteStats.SatelliteControllerParams.Builder() + .setTotalServiceUptimeSec(totalServiceUpTime) + .setTotalBatteryConsumptionPercent(batteryConsumptionPercent) + .setTotalBatteryChargedTimeSec(totalBatteryChargeTime) + .build(); + logd("onSatelliteDisabled(): " + controllerParam); + mSatelliteStats.onSatelliteControllerMetrics(controllerParam); + } + } + + /** Log the total battery charging time when satellite service is on */ + public void updateSatelliteBatteryChargeTime(boolean isCharged) { + logd("updateSatelliteBatteryChargeTime(" + isCharged + ")"); + // update only when the charge state has changed + if (mIsBatteryCharged == null || isCharged != mIsBatteryCharged) { + mIsBatteryCharged = isCharged; + + // When charged, log the start time of battery charging + if (isCharged) { + mBatteryChargedStartTimeSec = (int) (System.currentTimeMillis() / 1000); + // When discharged, log the accumulated total battery charging time. + } else { + mTotalBatteryChargeTimeSec += + (int) (System.currentTimeMillis() / 1000) + - mBatteryChargedStartTimeSec; + mBatteryChargedStartTimeSec = 0; + + } + } + } + + /** Capture the battery level when satellite service is on */ + private void startCaptureBatteryLevel(Context context) { + try { + BatteryManager batteryManager = context.getSystemService(BatteryManager.class); + mBatteryLevelWhenServiceOn = + batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); + logd("sBatteryLevelWhenServiceOn = " + mBatteryLevelWhenServiceOn); + } catch (NullPointerException e) { + loge("BatteryManager is null"); + } + } + + /** Capture the total consumption level when service is off */ + private int captureTotalBatteryConsumptionPercent(Context context) { + try { + BatteryManager batteryManager = context.getSystemService(BatteryManager.class); + int currentLevel = + batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); + return Math.max((mBatteryLevelWhenServiceOn - currentLevel), 0); + } catch (NullPointerException e) { + loge("BatteryManager is null"); + return 0; + } + } + + + /** Receives the battery status whether it is in charging or not, update interval is 60 sec. */ + private final BroadcastReceiver mBatteryStatusReceiver = new BroadcastReceiver() { + private long mLastUpdatedTime = 0; + private static final long UPDATE_INTERVAL = 60 * 1000; + + @Override + public void onReceive(Context context, Intent intent) { + long currentTime = System.currentTimeMillis(); + if (currentTime - mLastUpdatedTime > UPDATE_INTERVAL) { + mLastUpdatedTime = currentTime; + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + boolean isCharged = (status == BatteryManager.BATTERY_STATUS_CHARGING); + logd("Battery is charged(" + isCharged + ")"); + updateSatelliteBatteryChargeTime(isCharged); + } + } + }; + + private static void logd(@NonNull String log) { + if (DBG) { + Log.d(TAG, log); + } + } + + private static void loge(@NonNull String log) { + Log.e(TAG, log); + } +} diff --git a/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java new file mode 100644 index 0000000000..38696aabe2 --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/metrics/ProvisionMetricsStats.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2023 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.satellite.SatelliteManager; +import android.util.Log; + +import com.android.internal.telephony.metrics.SatelliteStats; + +/** + * Stats to log to satellite metrics + */ +public class ProvisionMetricsStats { + private static final String TAG = ProvisionMetricsStats.class.getSimpleName(); + private static final boolean DBG = false; + + private static ProvisionMetricsStats sInstance = null; + + public static final int INVALID_TIME = -1; + + private int mResultCode; + private int mProvisioningStartTimeSec; + private boolean mIsProvisionRequest; + private boolean mIsCanceled; + + private ProvisionMetricsStats() { + initializeProvisionParams(); + } + + /** + * Returns the Singleton instance of ProvisionMetricsStats 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 ProvisionMetricsStats + */ + public static ProvisionMetricsStats getOrCreateInstance() { + if (sInstance == null) { + logd("Create new ProvisionMetricsStats."); + sInstance = new ProvisionMetricsStats(); + } + return sInstance; + } + + /** Sets the resultCode for provision metrics */ + public ProvisionMetricsStats setResultCode(@SatelliteManager.SatelliteError int error) { + mResultCode = error; + return this; + } + + /** Sets the start time of provisioning */ + public void setProvisioningStartTime() { + mProvisioningStartTimeSec = (int) (System.currentTimeMillis() / 1000); + } + + /** Sets the isProvisionRequest to indicate whether provision or de-provision */ + public ProvisionMetricsStats setIsProvisionRequest(boolean isProvisionRequest) { + mIsProvisionRequest = isProvisionRequest; + return this; + } + + /** Sets the isCanceled to know whether the provision is canceled */ + public ProvisionMetricsStats setIsCanceled(boolean isCanceled) { + mIsCanceled = isCanceled; + return this; + } + + /** Report the provision metrics atoms to PersistAtomsStorage in telephony */ + public void reportProvisionMetrics() { + SatelliteStats.SatelliteProvisionParams provisionParams = + new SatelliteStats.SatelliteProvisionParams.Builder() + .setResultCode(mResultCode) + .setProvisioningTimeSec((int) + (System.currentTimeMillis() / 1000) - mProvisioningStartTimeSec) + .setIsProvisionRequest(mIsProvisionRequest) + .setIsCanceled(mIsCanceled) + .build(); + SatelliteStats.getInstance().onSatelliteProvisionMetrics(provisionParams); + logd(provisionParams.toString()); + initializeProvisionParams(); + } + + private void initializeProvisionParams() { + mResultCode = -1; + mProvisioningStartTimeSec = INVALID_TIME; + mIsProvisionRequest = false; + mIsCanceled = false; + } + + private static void logd(@NonNull String log) { + if (DBG) { + Log.d(TAG, log); + } + } +} -- GitLab From f947553d8a3094b48f3b985bf42b449f18623a06 Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Wed, 22 Mar 2023 16:41:16 +0000 Subject: [PATCH 559/656] add unit test for satellite controller metrics stats class unit test for satellite controller metrics Bug: 271792323 Test: atest ControllerMetricsStatsteset Change-Id: I232673f30a37e1cb9918571ee4bc07a619a7798e --- .../metrics/ControllerMetricsStats.java | 79 ++- .../satellite/ControllerMetricsStatsTest.java | 607 ++++++++++++++++++ 2 files changed, 668 insertions(+), 18 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/satellite/ControllerMetricsStatsTest.java diff --git a/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java index d735cf2db7..7a1de7cfdb 100644 --- a/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java +++ b/src/java/com/android/internal/telephony/satellite/metrics/ControllerMetricsStats.java @@ -25,6 +25,7 @@ import android.os.BatteryManager; import android.telephony.satellite.SatelliteManager; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.metrics.SatelliteStats; /** @@ -38,11 +39,11 @@ public class ControllerMetricsStats { private static ControllerMetricsStats sInstance; private final Context mContext; - private final SatelliteStats mSatelliteStats; + private SatelliteStats mSatelliteStats; private long mSatelliteOnTimeMillis; private int mBatteryLevelWhenServiceOn; - private Boolean mIsSatelliteModemOn = null; + private boolean mIsSatelliteModemOn; private Boolean mIsBatteryCharged = null; private int mBatteryChargedStartTimeSec; private int mTotalBatteryChargeTimeSec; @@ -70,6 +71,22 @@ public class ControllerMetricsStats { return sInstance; } + /** + * Create the ControllerMetricsStats singleton instance, testing purpose only. + * + * @param context The Context for the ControllerMetricsStats. + * @param satelliteStats SatelliteStats instance to test + * @return The singleton instance of ControllerMetricsStats. + */ + @VisibleForTesting + public static ControllerMetricsStats make(@NonNull Context context, + @NonNull SatelliteStats satelliteStats) { + if (sInstance == null) { + sInstance = new ControllerMetricsStats(context, satelliteStats); + } + return sInstance; + } + /** * Create the ControllerMetricsStats to manage metrics report for * {@link SatelliteStats.SatelliteControllerParams} @@ -80,6 +97,20 @@ public class ControllerMetricsStats { mSatelliteStats = SatelliteStats.getInstance(); } + /** + * Create the ControllerMetricsStats to manage metrics report for + * {@link SatelliteStats.SatelliteControllerParams} + * + * @param context The Context for the ControllerMetricsStats. + * @param satelliteStats SatelliteStats object used for testing purpose + */ + @VisibleForTesting + protected ControllerMetricsStats(@NonNull Context context, + @NonNull SatelliteStats satelliteStats) { + mContext = context; + mSatelliteStats = satelliteStats; + } + /** Report a counter when an attempt for satellite service on is successfully done */ public void reportServiceEnablementSuccessCount() { @@ -195,14 +226,16 @@ public class ControllerMetricsStats { } /** Return the total service up time for satellite service */ - private int captureTotalServiceUpTimeSec() { - long totalTimeMillis = System.currentTimeMillis() - mSatelliteOnTimeMillis; + @VisibleForTesting + public int captureTotalServiceUpTimeSec() { + long totalTimeMillis = getCurrentTime() - mSatelliteOnTimeMillis; mSatelliteOnTimeMillis = 0; return (int) (totalTimeMillis / 1000); } /** Return the total battery charge time while satellite service is on */ - private int captureTotalBatteryChargeTimeSec() { + @VisibleForTesting + public int captureTotalBatteryChargeTimeSec() { int totalTime = mTotalBatteryChargeTimeSec; mTotalBatteryChargeTimeSec = 0; return totalTime; @@ -210,13 +243,13 @@ public class ControllerMetricsStats { /** Capture the satellite service on time and register battery monitor */ public void onSatelliteEnabled() { - if (!mIsSatelliteModemOn) { + if (!isSatelliteModemOn()) { mIsSatelliteModemOn = true; - startCaptureBatteryLevel(mContext); + startCaptureBatteryLevel(); // log the timestamp of the satellite modem power on - mSatelliteOnTimeMillis = System.currentTimeMillis(); + mSatelliteOnTimeMillis = getCurrentTime(); // register broadcast receiver for monitoring battery status change IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); @@ -228,7 +261,7 @@ public class ControllerMetricsStats { /** Capture the satellite service off time and de-register battery monitor */ public void onSatelliteDisabled() { - if (mIsSatelliteModemOn) { + if (isSatelliteModemOn()) { mIsSatelliteModemOn = false; logd("unregister BatteryStatusReceiver"); @@ -251,7 +284,7 @@ public class ControllerMetricsStats { } /** Log the total battery charging time when satellite service is on */ - public void updateSatelliteBatteryChargeTime(boolean isCharged) { + private void updateSatelliteBatteryChargeTime(boolean isCharged) { logd("updateSatelliteBatteryChargeTime(" + isCharged + ")"); // update only when the charge state has changed if (mIsBatteryCharged == null || isCharged != mIsBatteryCharged) { @@ -259,22 +292,22 @@ public class ControllerMetricsStats { // When charged, log the start time of battery charging if (isCharged) { - mBatteryChargedStartTimeSec = (int) (System.currentTimeMillis() / 1000); + mBatteryChargedStartTimeSec = (int) (getCurrentTime() / 1000); // When discharged, log the accumulated total battery charging time. } else { mTotalBatteryChargeTimeSec += - (int) (System.currentTimeMillis() / 1000) + (int) (getCurrentTime() / 1000) - mBatteryChargedStartTimeSec; mBatteryChargedStartTimeSec = 0; - } } } /** Capture the battery level when satellite service is on */ - private void startCaptureBatteryLevel(Context context) { + @VisibleForTesting + public void startCaptureBatteryLevel() { try { - BatteryManager batteryManager = context.getSystemService(BatteryManager.class); + BatteryManager batteryManager = mContext.getSystemService(BatteryManager.class); mBatteryLevelWhenServiceOn = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); logd("sBatteryLevelWhenServiceOn = " + mBatteryLevelWhenServiceOn); @@ -284,7 +317,8 @@ public class ControllerMetricsStats { } /** Capture the total consumption level when service is off */ - private int captureTotalBatteryConsumptionPercent(Context context) { + @VisibleForTesting + public int captureTotalBatteryConsumptionPercent(Context context) { try { BatteryManager batteryManager = context.getSystemService(BatteryManager.class); int currentLevel = @@ -296,7 +330,6 @@ public class ControllerMetricsStats { } } - /** Receives the battery status whether it is in charging or not, update interval is 60 sec. */ private final BroadcastReceiver mBatteryStatusReceiver = new BroadcastReceiver() { private long mLastUpdatedTime = 0; @@ -304,7 +337,7 @@ public class ControllerMetricsStats { @Override public void onReceive(Context context, Intent intent) { - long currentTime = System.currentTimeMillis(); + long currentTime = getCurrentTime(); if (currentTime - mLastUpdatedTime > UPDATE_INTERVAL) { mLastUpdatedTime = currentTime; int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); @@ -315,6 +348,16 @@ public class ControllerMetricsStats { } }; + @VisibleForTesting + public boolean isSatelliteModemOn() { + return mIsSatelliteModemOn; + } + + @VisibleForTesting + public long getCurrentTime() { + return System.currentTimeMillis(); + } + private static void logd(@NonNull String log) { if (DBG) { Log.d(TAG, log); diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/ControllerMetricsStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/ControllerMetricsStatsTest.java new file mode 100644 index 0000000000..baa00c156c --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/ControllerMetricsStatsTest.java @@ -0,0 +1,607 @@ +/* + * Copyright (C) 2023 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 static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.telephony.satellite.SatelliteManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.metrics.SatelliteStats; +import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; +import com.android.telephony.Rlog; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class ControllerMetricsStatsTest extends TelephonyTest { + private static final String TAG = "ControllerMetricsStatsTest"; + + private static final long MODEM_ENABLED_TIME = 1000L; + + private TestControllerMetricsStats mControllerMetricsStatsUT; + private TestSatelliteStats mTestStats; + + @Mock private Context mMockContext; + @Spy private ControllerMetricsStats mSpyControllerMetricsStats; + @Mock private SatelliteStats mMockSatelliteStats; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + Rlog.d(TAG, "setUp()"); + mTestStats = new TestSatelliteStats(); + mControllerMetricsStatsUT = + new TestControllerMetricsStats(mMockContext, mTestStats); + mMockContext = mock(Context.class); + mMockSatelliteStats = mock(SatelliteStats.class); + mSpyControllerMetricsStats = + Mockito.spy(ControllerMetricsStats.make(mMockContext, mMockSatelliteStats)); + } + + @After + public void tearDown() throws Exception { + Rlog.d(TAG, "tearDown()"); + mTestStats = null; + mControllerMetricsStatsUT = null; + mMockSatelliteStats = null; + mSpyControllerMetricsStats = null; + super.tearDown(); + } + + @Test + public void testReportServiceEnablementSuccessCount() { + mTestStats.initializeParams(); + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportServiceEnablementSuccessCount(); + } + assertEquals(10, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + } + + @Test + public void testReportServiceEnablementFailCount() { + mTestStats.initializeParams(); + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportServiceEnablementFailCount(); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(10, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + } + + @Test + public void testReportOutgoingDatagramSuccessCount() { + mTestStats.initializeParams(); + int datagramType = SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportOutgoingDatagramSuccessCount(datagramType); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(10, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(10, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + + datagramType = SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportOutgoingDatagramSuccessCount(datagramType); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(10, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(10, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + + datagramType = SatelliteManager.DATAGRAM_TYPE_UNKNOWN; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportOutgoingDatagramSuccessCount(datagramType); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(10, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + } + + @Test + public void reportOutgoingDatagramFailCount() { + mTestStats.initializeParams(); + int datagramType = SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportOutgoingDatagramFailCount(datagramType); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(10, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(10, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + + datagramType = SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportOutgoingDatagramFailCount(datagramType); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(10, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(10, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + + datagramType = SatelliteManager.DATAGRAM_TYPE_UNKNOWN; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportOutgoingDatagramFailCount(datagramType); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(10, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + } + + @Test + public void testReportIncomingDatagramCount() { + mTestStats.initializeParams(); + + int result = SatelliteManager.SATELLITE_ERROR_NONE; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportIncomingDatagramCount(result); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(10, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + + result = SatelliteManager.SATELLITE_SERVER_ERROR; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportIncomingDatagramCount(result); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(10, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + + result = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportIncomingDatagramCount(result); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(10, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + } + + @Test + public void testReportProvisionCount() { + mTestStats.initializeParams(); + + int result = SatelliteManager.SATELLITE_ERROR_NONE; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportProvisionCount(result); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(10, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + + result = SatelliteManager.SATELLITE_SERVER_ERROR; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportProvisionCount(result); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(10, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + + result = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportProvisionCount(result); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(10, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + } + + @Test + public void testReportDeprovisionCount() { + mTestStats.initializeParams(); + + int result = SatelliteManager.SATELLITE_ERROR_NONE; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportDeprovisionCount(result); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(10, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(0, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + + result = SatelliteManager.SATELLITE_SERVER_ERROR; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportDeprovisionCount(result); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(10, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + + result = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + for (int i = 0; i < 10; i++) { + mControllerMetricsStatsUT.reportDeprovisionCount(result); + } + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsSuccess); + assertEquals(0, mTestStats.mCountOfSatelliteServiceEnablementsFail); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfOutgoingDatagramFail); + assertEquals(0, mTestStats.mCountOfIncomingDatagramSuccess); + assertEquals(0, mTestStats.mCountOfIncomingDatagramFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeSosSmsFail); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingSuccess); + assertEquals(0, mTestStats.mCountOfDatagramTypeLocationSharingFail); + assertEquals(0, mTestStats.mCountOfProvisionSuccess); + assertEquals(0, mTestStats.mCountOfProvisionFail); + assertEquals(0, mTestStats.mCountOfDeprovisionSuccess); + assertEquals(10, mTestStats.mCountOfDeprovisionFail); + assertEquals(0, mTestStats.mTotalServiceUptimeSec); + assertEquals(0, mTestStats.mTotalBatteryConsumptionPercent); + assertEquals(0, mTestStats.mTotalBatteryChargedTimeSec); + mTestStats.initializeParams(); + } + + @Test + public void testOnSatelliteEnabled() { + // set precondition + doReturn(false).when(mSpyControllerMetricsStats).isSatelliteModemOn(); + + doNothing().when(mSpyControllerMetricsStats).startCaptureBatteryLevel(); + doReturn(MODEM_ENABLED_TIME).when(mSpyControllerMetricsStats).getCurrentTime(); + + // test object + mSpyControllerMetricsStats.onSatelliteEnabled(); + + // verification + verify(mSpyControllerMetricsStats).startCaptureBatteryLevel(); + verify(mSpyControllerMetricsStats).getCurrentTime(); + } + + @Test + public void testOnSatelliteDisabled() { + // set precondition + doNothing().when(mMockSatelliteStats).onSatelliteControllerMetrics(any()); + + doReturn(true).when(mSpyControllerMetricsStats).isSatelliteModemOn(); + + doReturn(0).when(mSpyControllerMetricsStats).captureTotalServiceUpTimeSec(); + doReturn(0).when(mSpyControllerMetricsStats).captureTotalBatteryConsumptionPercent(any()); + doReturn(0).when(mSpyControllerMetricsStats).captureTotalBatteryChargeTimeSec(); + + // test object + mSpyControllerMetricsStats.onSatelliteDisabled(); + + // verification + verify(mSpyControllerMetricsStats).captureTotalServiceUpTimeSec(); + verify(mSpyControllerMetricsStats).captureTotalBatteryConsumptionPercent(any()); + verify(mSpyControllerMetricsStats).captureTotalBatteryChargeTimeSec(); + } + + static class TestControllerMetricsStats extends ControllerMetricsStats { + TestControllerMetricsStats(Context context, SatelliteStats satelliteStats) { + super(context, satelliteStats); + } + } + + static class TestSatelliteStats extends SatelliteStats { + public int mCountOfSatelliteServiceEnablementsSuccess; + public int mCountOfSatelliteServiceEnablementsFail; + public int mCountOfOutgoingDatagramSuccess; + public int mCountOfOutgoingDatagramFail; + public int mCountOfIncomingDatagramSuccess; + public int mCountOfIncomingDatagramFail; + public int mCountOfDatagramTypeSosSmsSuccess; + public int mCountOfDatagramTypeSosSmsFail; + public int mCountOfDatagramTypeLocationSharingSuccess; + public int mCountOfDatagramTypeLocationSharingFail; + public int mCountOfProvisionSuccess; + public int mCountOfProvisionFail; + public int mCountOfDeprovisionSuccess; + public int mCountOfDeprovisionFail; + public int mTotalServiceUptimeSec; + public int mTotalBatteryConsumptionPercent; + public int mTotalBatteryChargedTimeSec; + + @Override + public synchronized void onSatelliteControllerMetrics(SatelliteControllerParams param) { + mCountOfSatelliteServiceEnablementsSuccess += + param.getCountOfSatelliteServiceEnablementsSuccess(); + mCountOfSatelliteServiceEnablementsFail += + param.getCountOfSatelliteServiceEnablementsFail(); + mCountOfOutgoingDatagramSuccess += param.getCountOfOutgoingDatagramSuccess(); + mCountOfOutgoingDatagramFail += param.getCountOfOutgoingDatagramFail(); + mCountOfIncomingDatagramSuccess += param.getCountOfIncomingDatagramSuccess(); + mCountOfIncomingDatagramFail += param.getCountOfIncomingDatagramFail(); + mCountOfDatagramTypeSosSmsSuccess += param.getCountOfDatagramTypeSosSmsSuccess(); + mCountOfDatagramTypeSosSmsFail += param.getCountOfDatagramTypeSosSmsFail(); + mCountOfDatagramTypeLocationSharingSuccess += + param.getCountOfDatagramTypeLocationSharingSuccess(); + mCountOfDatagramTypeLocationSharingFail += + param.getCountOfDatagramTypeLocationSharingFail(); + mCountOfProvisionSuccess += param.getCountOfProvisionSuccess(); + mCountOfProvisionFail += param.getCountOfProvisionFail(); + mCountOfDeprovisionSuccess += param.getCountOfDeprovisionSuccess(); + mCountOfDeprovisionFail += param.getCountOfDeprovisionFail(); + mTotalServiceUptimeSec += param.getTotalServiceUptimeSec(); + mTotalBatteryConsumptionPercent += param.getTotalBatteryConsumptionPercent(); + mTotalBatteryChargedTimeSec += param.getTotalBatteryChargedTimeSec(); + } + + public void initializeParams() { + mCountOfSatelliteServiceEnablementsSuccess = 0; + mCountOfSatelliteServiceEnablementsFail = 0; + mCountOfOutgoingDatagramSuccess = 0; + mCountOfOutgoingDatagramFail = 0; + mCountOfIncomingDatagramSuccess = 0; + mCountOfIncomingDatagramFail = 0; + mCountOfDatagramTypeSosSmsSuccess = 0; + mCountOfDatagramTypeSosSmsFail = 0; + mCountOfDatagramTypeLocationSharingSuccess = 0; + mCountOfDatagramTypeLocationSharingFail = 0; + mCountOfProvisionSuccess = 0; + mCountOfProvisionFail = 0; + mCountOfDeprovisionSuccess = 0; + mCountOfDeprovisionFail = 0; + mTotalServiceUptimeSec = 0; + mTotalBatteryConsumptionPercent = 0; + mTotalBatteryChargedTimeSec = 0; + } + } +} -- GitLab From 436ed6ad58807dee6b85bf0c62520fdcd73b3737 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 28 Mar 2023 15:23:01 -0700 Subject: [PATCH 560/656] Read device resource on bootup Since some resource config are per device(versus per sub), we can read those value on device bootup before waiting for any sub specific events. Fix: 275421272 Test: verify values are populated before selecting default data Change-Id: I7767927b3e777d0a53016f976c87e8db22b7670b --- .../telephony/data/PhoneSwitcher.java | 62 +++++++------------ .../telephony/data/PhoneSwitcherTest.java | 34 +++++----- 2 files changed, 36 insertions(+), 60 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index 68dcfc2dc0..c51f09f1d4 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -292,17 +292,6 @@ public class PhoneSwitcher extends Handler { private ISetOpportunisticDataCallback mSetOpptSubCallback; - /** Data config manager callback for updating device config. **/ - private final DataConfigManager.DataConfigManagerCallback mDataConfigManagerCallback = - new DataConfigManager.DataConfigManagerCallback(this::post) { - - @Override - public void onCarrierConfigChanged() { - log("onCarrierConfigChanged"); - PhoneSwitcher.this.updateCarrierConfig(); - } - }; - private static final int EVENT_PRIMARY_DATA_SUB_CHANGED = 101; protected static final int EVENT_SUBSCRIPTION_CHANGED = 102; private static final int EVENT_REQUEST_NETWORK = 103; @@ -589,6 +578,8 @@ public class PhoneSwitcher extends Handler { PhoneFactory.getPhone(0).mCi.registerForOn(this, EVENT_RADIO_ON, null); } + readDeviceResourceConfig(); + TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) context.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); telephonyRegistryManager.addOnSubscriptionsChangedListener( @@ -914,51 +905,40 @@ public class PhoneSwitcher extends Handler { break; } case EVENT_PROCESS_SIM_STATE_CHANGE: { - int slotIndex = (int) msg.arg1; - int simState = (int) msg.arg2; + int slotIndex = msg.arg1; + int simState = msg.arg2; if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { logl("EVENT_PROCESS_SIM_STATE_CHANGE: skip processing due to invalid slotId: " + slotIndex); - } else if (mCurrentDdsSwitchFailure.get(slotIndex).contains( + } else if (TelephonyManager.SIM_STATE_LOADED == simState) { + if (mCurrentDdsSwitchFailure.get(slotIndex).contains( CommandException.Error.INVALID_SIM_STATE) && (TelephonyManager.SIM_STATE_LOADED == simState) && isSimApplicationReady(slotIndex)) { - sendRilCommands(slotIndex); + sendRilCommands(slotIndex); + } + // SIM loaded after subscriptions slot mapping are done. Evaluate for auto + // data switch. + sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); } - - registerConfigChange(); break; } } } /** - * Register for config change on the primary data phone. + * Read the default device config from any default phone because the resource config are per + * device. No need to register callback for the same reason. */ - private void registerConfigChange() { - Phone phone = getPhoneBySubId(mPrimaryDataSubId); - if (phone != null) { - DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); - dataConfig.registerCallback(mDataConfigManagerCallback); - updateCarrierConfig(); - sendEmptyMessage(EVENT_EVALUATE_AUTO_SWITCH); - } - } - - /** - * Update carrier config. - */ - private void updateCarrierConfig() { - Phone phone = getPhoneBySubId(mPrimaryDataSubId); - if (phone != null) { - DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); - mRequirePingTestBeforeDataSwitch = dataConfig.isPingTestBeforeAutoDataSwitchRequired(); - mAutoDataSwitchAvailabilityStabilityTimeThreshold = - dataConfig.getAutoDataSwitchAvailabilityStabilityTimeThreshold(); - mAutoDataSwitchValidationMaxRetry = - dataConfig.getAutoDataSwitchValidationMaxRetry(); - } + private void readDeviceResourceConfig() { + Phone phone = PhoneFactory.getDefaultPhone(); + DataConfigManager dataConfig = phone.getDataNetworkController().getDataConfigManager(); + mRequirePingTestBeforeDataSwitch = dataConfig.isPingTestBeforeAutoDataSwitchRequired(); + mAutoDataSwitchAvailabilityStabilityTimeThreshold = + dataConfig.getAutoDataSwitchAvailabilityStabilityTimeThreshold(); + mAutoDataSwitchValidationMaxRetry = + dataConfig.getAutoDataSwitchValidationMaxRetry(); } private synchronized void onMultiSimConfigChanged(int activeModemCount) { 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 9e689ddadf..45c285c602 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -131,7 +131,6 @@ public class PhoneSwitcherTest extends TelephonyTest { private Messenger mNetworkProviderMessenger = null; private Map mDataSettingsManagerCallbacks; - private DataConfigManager.DataConfigManagerCallback mDataConfigManagerCallback; private int mDefaultDataSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private int[][] mSlotIndexToSubId; private boolean[] mDataAllowed; @@ -641,15 +640,17 @@ public class PhoneSwitcherTest extends TelephonyTest { @SmallTest public void testAutoDataSwitch_exemptPingTest() throws Exception { initialize(); + // Change resource overlay + doReturn(false).when(mDataConfigManager).isPingTestBeforeAutoDataSwitchRequired(); + mPhoneSwitcherUT = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper()); + processAllMessages(); + // Phone 0 has sub 1, phone 1 has sub 2. // Sub 1 is default data sub. setSlotIndexToSubId(0, 1); setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); - doReturn(false).when(mDataConfigManager).isPingTestBeforeAutoDataSwitchRequired(); - mDataConfigManagerCallback.onCarrierConfigChanged(); - //1. Attempting to switch to nDDS, switch even if validation failed prepareIdealAutoSwitchCondition(); processAllFutureMessages(); @@ -2028,6 +2029,7 @@ public class PhoneSwitcherTest extends TelephonyTest { initializeCommandInterfacesMock(); initializeTelRegistryMock(); initializeConnManagerMock(); + initializeConfigMock(); mPhoneSwitcherUT = new PhoneSwitcher(mMaxDataAttachModemCount, mContext, Looper.myLooper()); @@ -2037,21 +2039,6 @@ public class PhoneSwitcherTest extends TelephonyTest { (Map) field.get(mPhoneSwitcherUT); - field = PhoneSwitcher.class.getDeclaredField("mDataConfigManagerCallback"); - field.setAccessible(true); - mDataConfigManagerCallback = - (DataConfigManager.DataConfigManagerCallback) field.get(mPhoneSwitcherUT); - - doReturn(mDataNetworkController).when(mPhone).getDataNetworkController(); - doReturn(mDataConfigManager).when(mDataNetworkController).getDataConfigManager(); - doReturn(1000L).when(mDataConfigManager) - .getAutoDataSwitchAvailabilityStabilityTimeThreshold(); - doReturn(7).when(mDataConfigManager).getAutoDataSwitchValidationMaxRetry(); - doReturn(true).when(mDataConfigManager).isPingTestBeforeAutoDataSwitchRequired(); - - mDataConfigManagerCallback.onCarrierConfigChanged(); - mDataConfigManagerCallback.onDeviceConfigChanged(); - processAllMessages(); verify(mTelephonyRegistryManager).addOnSubscriptionsChangedListener(any(), any()); @@ -2216,6 +2203,15 @@ public class PhoneSwitcherTest extends TelephonyTest { .getActiveSubIdList(true); } + private void initializeConfigMock() { + doReturn(mDataNetworkController).when(mPhone).getDataNetworkController(); + doReturn(mDataConfigManager).when(mDataNetworkController).getDataConfigManager(); + doReturn(1000L).when(mDataConfigManager) + .getAutoDataSwitchAvailabilityStabilityTimeThreshold(); + doReturn(7).when(mDataConfigManager).getAutoDataSwitchValidationMaxRetry(); + doReturn(true).when(mDataConfigManager).isPingTestBeforeAutoDataSwitchRequired(); + } + private void setDefaultDataSubId(int defaultDataSub) throws Exception { mDefaultDataSub = defaultDataSub; doReturn(mDefaultDataSub).when(mSubscriptionController).getDefaultDataSubId(); -- GitLab From 43948567dd89d666869bd10a162fef0e135aea3a Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Sun, 26 Mar 2023 08:00:05 +0000 Subject: [PATCH 561/656] [Telephony_Stability]Fix ArithmeticException at LinkBandwidthEstimator Divide by zero exception found at calculateErrorPercent(). Bug: 275185931 Test: build & atest Change-Id: I657e674cec3b5fa45e787b21a18ceeffcbb36e34 --- .../android/internal/telephony/data/LinkBandwidthEstimator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java index c04698b76b..5ed12aadec 100644 --- a/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java +++ b/src/java/com/android/internal/telephony/data/LinkBandwidthEstimator.java @@ -678,7 +678,7 @@ public class LinkBandwidthEstimator extends Handler { return; } int linkBandwidthKbps = (int) linkBandwidthLongKbps; - mBwSampleValid = true; + mBwSampleValid = linkBandwidthKbps > 0; mBwSampleKbps = linkBandwidthKbps; String dataRatName = getDataRatName(mDataRat); -- GitLab From f492ad2b127fded9b8e9f0386f3c3e86bdec11fb Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 28 Mar 2023 22:50:45 -0700 Subject: [PATCH 562/656] Removed the obsolete code Removed the incomplete APIs and re-directed to the similar APIs. Fix: 262591408 Test: atest SubscriptionManagerTest Change-Id: Ifbd767085e4567320e45bd480f7a7fc711c7d68a --- .../internal/telephony/SubscriptionController.java | 10 +++------- .../subscription/SubscriptionManagerService.java | 13 +------------ 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java index a88fd0bb86..ad2fd74014 100644 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ b/src/java/com/android/internal/telephony/SubscriptionController.java @@ -2484,9 +2484,8 @@ public class SubscriptionController extends ISub.Stub { /** * Set uicc applications being enabled or disabled. * @param enabled whether uicc applications are enabled or disabled. - * @return the number of records updated */ - public int setUiccApplicationsEnabled(boolean enabled, int subId) { + public void setUiccApplicationsEnabled(boolean enabled, int subId) { if (DBG) logd("[setUiccApplicationsEnabled]+ enabled:" + enabled + " subId:" + subId); enforceModifyPhoneState("setUiccApplicationsEnabled"); @@ -2496,16 +2495,14 @@ public class SubscriptionController extends ISub.Stub { ContentValues value = new ContentValues(1); value.put(SubscriptionManager.UICC_APPLICATIONS_ENABLED, enabled); - int result = mContext.getContentResolver().update( - SubscriptionManager.getUriForSubscriptionId(subId), value, null, null); + mContext.getContentResolver().update(SubscriptionManager.getUriForSubscriptionId(subId), + value, null, null); // Refresh the Cache of Active Subscription Info List refreshCachedActiveSubscriptionInfoList(); notifyUiccAppsEnableChanged(); notifySubscriptionInfoChanged(); - - return result; } finally { Binder.restoreCallingIdentity(identity); } @@ -4040,7 +4037,6 @@ public class SubscriptionController extends ISub.Stub { * @return true if success, false if fails or the further action is * needed hence it's redirected to Euicc. */ - @Override public boolean setSubscriptionEnabled(boolean enable, int subId) { enforceModifyPhoneState("setSubscriptionEnabled"); diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 85fe9ed5a0..8fdfabc0d4 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -3017,14 +3017,6 @@ public class SubscriptionManagerService extends ISub.Stub { } } - @Override - public boolean setSubscriptionEnabled(boolean enable, int subId) { - enforcePermissions("setSubscriptionEnabled", Manifest.permission.MODIFY_PHONE_STATE); - - - return true; - } - /** * Check if a subscription is active. * @@ -3188,14 +3180,12 @@ public class SubscriptionManagerService extends ISub.Stub { * @param enabled whether uicc applications are enabled or disabled. * @param subId which subscription to operate on. * - * @return the number of records updated. - * * @throws IllegalArgumentException if the subscription does not exist. * @throws SecurityException if callers do not hold the required permission. */ @Override @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) - public int setUiccApplicationsEnabled(boolean enabled, int subId) { + public void setUiccApplicationsEnabled(boolean enabled, int subId) { enforcePermissions("setUiccApplicationsEnabled", Manifest.permission.MODIFY_PHONE_STATE); logl("setUiccApplicationsEnabled: subId=" + subId + ", enabled=" + enabled @@ -3220,7 +3210,6 @@ public class SubscriptionManagerService extends ISub.Stub { } finally { Binder.restoreCallingIdentity(identity); } - return 1; } /** -- GitLab From 17378ae7bd9bfbf0e58d975fdc5e57cb130abc26 Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Mon, 13 Mar 2023 05:51:06 +0000 Subject: [PATCH 563/656] add satellite session log to satellite metrics currently initial version for testing and feedback Bug: 271819233 Test: build test Change-Id: Ib101ee081972a1b233ba6515551771ef4bdd7951 --- .../satellite/SatelliteController.java | 5 + .../metrics/SessionMetricsStats.java | 97 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 1d59eb8887..4a882b021b 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -54,6 +54,7 @@ import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; +import com.android.internal.telephony.satellite.metrics.SessionMetricsStats; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; @@ -563,6 +564,10 @@ public class SatelliteController extends Handler { } else { mControllerMetricsStats.reportServiceEnablementFailCount(); } + SessionMetricsStats.getInstance() + .setInitializationResult(error) + .setRadioTechnology(SatelliteManager.NT_RADIO_TECHNOLOGY_PROPRIETARY) + .reportSessionMetrics(); } else { mControllerMetricsStats.onSatelliteDisabled(); } diff --git a/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java b/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java new file mode 100644 index 0000000000..776ba640b5 --- /dev/null +++ b/src/java/com/android/internal/telephony/satellite/metrics/SessionMetricsStats.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2023 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.satellite.SatelliteManager; +import android.util.Log; + +import com.android.internal.telephony.metrics.SatelliteStats; + +/** + * Stats to log to satellite session metrics + */ +public class SessionMetricsStats { + private static final String TAG = SessionMetricsStats.class.getSimpleName(); + private static final boolean DBG = false; + + private static SessionMetricsStats sInstance = null; + private @SatelliteManager.SatelliteError int mInitializationResult; + private @SatelliteManager.NTRadioTechnology int mRadioTechnology; + + private SessionMetricsStats() { + initializeSessionMetricsParam(); + } + + /** + * Returns the Singleton instance of SessionMetricsStats 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 SessionMetricsStats + */ + public static SessionMetricsStats getInstance() { + if (sInstance == null) { + loge("create new SessionMetricsStats."); + sInstance = new SessionMetricsStats(); + } + return sInstance; + } + + /** Sets the satellite initialization result */ + public SessionMetricsStats setInitializationResult( + @SatelliteManager.SatelliteError int result) { + logd("setInitializationResult(" + result + ")"); + mInitializationResult = result; + return this; + } + + /** Sets the satellite ratio technology */ + public SessionMetricsStats setRadioTechnology( + @SatelliteManager.NTRadioTechnology int radioTechnology) { + logd("setRadioTechnology(" + radioTechnology + ")"); + mRadioTechnology = radioTechnology; + return this; + } + + /** Report the session metrics atoms to PersistAtomsStorage in telephony */ + public void reportSessionMetrics() { + SatelliteStats.SatelliteSessionParams sessionParams = + new SatelliteStats.SatelliteSessionParams.Builder() + .setSatelliteServiceInitializationResult(mInitializationResult) + .setSatelliteTechnology(mRadioTechnology) + .build(); + logd(sessionParams.toString()); + SatelliteStats.getInstance().onSatelliteSessionMetrics(sessionParams); + initializeSessionMetricsParam(); + } + + private void initializeSessionMetricsParam() { + mInitializationResult = SatelliteManager.SATELLITE_ERROR_NONE; + mRadioTechnology = SatelliteManager.NT_RADIO_TECHNOLOGY_UNKNOWN; + } + + private static void logd(@NonNull String log) { + if (DBG) { + Log.d(TAG, log); + } + } + + private static void loge(@NonNull String log) { + Log.e(TAG, log); + } +} -- GitLab From 7569ad7ed9682bebe1938fb3d9eb1c8e3aa26798 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Wed, 29 Mar 2023 23:48:18 +0000 Subject: [PATCH 564/656] Close cursor after DB operations. Bug: 275716615 Test: atest DatagramReceiverTest, Flashed build on raven-userdebug: calls and SMS are working. Change-Id: If20141062efe376b0fd4faae0d4a07ad677e4a01 --- .../telephony/satellite/DatagramReceiver.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index cfb9dfdcf7..c8401d255c 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -25,6 +25,7 @@ import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; +import android.database.SQLException; import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; @@ -260,19 +261,22 @@ public class DatagramReceiver extends Handler { private void deleteDatagram(long datagramId) { String whereClause = (Telephony.SatelliteDatagrams.COLUMN_UNIQUE_KEY_DATAGRAM_ID + "=" + datagramId); - Cursor cursor = sInstance.mContentResolver.query( + try (Cursor cursor = sInstance.mContentResolver.query( Telephony.SatelliteDatagrams.CONTENT_URI, - null, whereClause, null, null); - if ((cursor != null) && (cursor.getCount() == 1)) { - int numRowsDeleted = sInstance.mContentResolver.delete( - Telephony.SatelliteDatagrams.CONTENT_URI, whereClause, null); - if (numRowsDeleted == 0) { - loge("Cannot delete datagram with datagramId: " + datagramId); + null, whereClause, null, null)) { + if ((cursor != null) && (cursor.getCount() == 1)) { + int numRowsDeleted = sInstance.mContentResolver.delete( + Telephony.SatelliteDatagrams.CONTENT_URI, whereClause, null); + if (numRowsDeleted == 0) { + loge("Cannot delete datagram with datagramId: " + datagramId); + } else { + logd("Deleted datagram with datagramId: " + datagramId); + } } else { - logd("Deleted datagram with datagramId: " + datagramId); + loge("Datagram with datagramId: " + datagramId + " is not present in DB."); } - } else { - loge("Datagram with datagramId: " + datagramId + " is not present in DB."); + } catch(SQLException e) { + loge("deleteDatagram SQLException e:" + e); } } -- GitLab From cb2ee091e4636e9cb3f83953da81c1d9e17b52fb Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Tue, 28 Mar 2023 02:21:33 +0000 Subject: [PATCH 565/656] Revert "Revert "Cache satellite service states and restructure c..." Test: Emergency call, normal call, SMS, MMS with live network. atest com.android.internal.telephony.satellite.SatelliteSessionControllerTest atest com.android.internal.telephony.satellite.SatelliteSOSMessageRecommenderTest atest android.telephony.cts.SatelliteManagerTest Revert submission 22297768-revert-22148859-Cache satellite states-DHPRVFQMUT Reason for revert: resubmit the original feature - caching satellite states Reverted changes: /q/submissionid:22297768-revert-22148859-Cache+satellite+states-DHPRVFQMUT Change-Id: I357095967abbefe66954f31cb285c3cbaa08b98c --- .../internal/telephony/CommandsInterface.java | 7 + .../com/android/internal/telephony/Phone.java | 8 + .../com/android/internal/telephony/RIL.java | 15 + .../satellite/DatagramController.java | 13 + .../telephony/satellite/DatagramReceiver.java | 4 - .../satellite/PointingAppController.java | 56 +- .../satellite/SatelliteController.java | 866 ++++++++++-------- .../satellite/SatelliteModemInterface.java | 13 +- .../SatelliteSOSMessageRecommender.java | 3 +- .../satellite/SatelliteSessionController.java | 18 +- .../SatelliteSOSMessageRecommenderTest.java | 79 +- .../SatelliteSessionControllerTest.java | 59 +- 12 files changed, 666 insertions(+), 475 deletions(-) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 7314ccb823..439b19b019 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -3034,6 +3034,13 @@ public interface CommandsInterface { */ default void getSatellitePowerState(Message result) {} + /** + * Get satellite provision state. + * + * @param result Message that will be sent back to the requester + */ + default void getSatelliteProvisionState(Message result) {} + /** * Check whether satellite modem is supported by the device. * diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 9f2513a4e5..34f1c51c4e 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -5315,6 +5315,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mCi.isSatelliteSupported(result); } + /** + * Check whether the satellite modem is provisioned. + * @param result The Message to send the result of the operation to. + */ + public void isSatelliteProvisioned(Message result) { + mCi.getSatelliteProvisionState(result); + } + /** * Get the satellite capabilities. * @param result The Message to send the result of the operation to. diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 8aff93b6ba..3987fb9986 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5788,6 +5788,21 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * Get satellite provision state. + * + * @param result Message that will be sent back to the requester + */ + @Override + public void getSatelliteProvisionState(Message result) { + // Satellite HAL APIs are not supported before Android V. + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + /** * Provision the subscription with a satellite provider. This is needed to register the * subscription if the provider allows dynamic registration. diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 2fda0221af..21c03d683d 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -187,6 +187,7 @@ public class DatagramController { mSendErrorCode = errorCode; mPointingAppController.updateSendDatagramTransferState(subId, datagramTransferState, sendPendingCount, errorCode); + notifyDatagramTransferStateChangedToSessionController(); } /** @@ -211,6 +212,7 @@ public class DatagramController { mReceiveErrorCode = errorCode; mPointingAppController.updateReceiveDatagramTransferState(subId, datagramTransferState, receivePendingCount, errorCode); + notifyDatagramTransferStateChangedToSessionController(); } /** @@ -221,6 +223,17 @@ public class DatagramController { return mReceivePendingCount; } + private void notifyDatagramTransferStateChangedToSessionController() { + SatelliteSessionController sessionController = SatelliteSessionController.getInstance(); + if (sessionController == null) { + loge("notifyDatagramTransferStateChangeToSessionController: SatelliteSessionController" + + " is not initialized yet"); + } else { + sessionController.onDatagramTransferStateChanged( + mSendDatagramTransferState, mReceiveDatagramTransferState); + } + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index cfb9dfdcf7..02d7751e0c 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -467,8 +467,6 @@ public class DatagramReceiver extends Handler { satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler( mBackgroundHandler.getLooper(), validSubId); if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { - // TODO: remove this as SatelliteModemInterface can register for incoming datagrams - // on boot up itself. SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived( satelliteDatagramListenerHandler, SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, null); @@ -593,6 +591,4 @@ public class DatagramReceiver extends Handler { private static void loge(@NonNull String log) { Rlog.e(TAG, log); } - - // TODO: An api change - do not pass the binder from Telephony to Applications } diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java index c37d1a05ba..dcfbe1f513 100644 --- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -34,6 +34,8 @@ import android.text.TextUtils; import com.android.internal.telephony.Phone; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -114,6 +116,7 @@ public class PointingAppController { public static final int EVENT_POSITION_INFO_CHANGED = 1; public static final int EVENT_SEND_DATAGRAM_STATE_CHANGED = 2; public static final int EVENT_RECEIVE_DATAGRAM_STATE_CHANGED = 3; + public static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 4; private final ConcurrentHashMap mListeners; SatelliteTransmissionUpdateHandler(Looper looper) { @@ -139,41 +142,64 @@ public class PointingAppController { case EVENT_POSITION_INFO_CHANGED: { AsyncResult ar = (AsyncResult) msg.obj; PointingInfo pointingInfo = (PointingInfo) ar.result; + List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onSatellitePositionChanged(pointingInfo); } catch (RemoteException e) { logd("EVENT_POSITION_INFO_CHANGED RemoteException: " + e); + toBeRemoved.add(listener.asBinder()); } }); + toBeRemoved.forEach(listener -> { + mListeners.remove(listener); + }); + break; + } + + case EVENT_DATAGRAM_TRANSFER_STATE_CHANGED: { + AsyncResult ar = (AsyncResult) msg.obj; + logd("Receive EVENT_DATAGRAM_TRANSFER_STATE_CHANGED state=" + (int) ar.result); break; } case EVENT_SEND_DATAGRAM_STATE_CHANGED: { + logd("Received EVENT_SEND_DATAGRAM_STATE_CHANGED"); DatagramTransferStateHandlerRequest request = (DatagramTransferStateHandlerRequest) msg.obj; + List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onSendDatagramStateChanged(request.datagramTransferState, request.pendingCount, request.errorCode); } catch (RemoteException e) { logd("EVENT_SEND_DATAGRAM_STATE_CHANGED RemoteException: " + e); + toBeRemoved.add(listener.asBinder()); } }); + toBeRemoved.forEach(listener -> { + mListeners.remove(listener); + }); break; } case EVENT_RECEIVE_DATAGRAM_STATE_CHANGED: { + logd("Received EVENT_RECEIVE_DATAGRAM_STATE_CHANGED"); DatagramTransferStateHandlerRequest request = (DatagramTransferStateHandlerRequest) msg.obj; + List toBeRemoved = new ArrayList<>(); mListeners.values().forEach(listener -> { try { listener.onReceiveDatagramStateChanged(request.datagramTransferState, request.pendingCount, request.errorCode); } catch (RemoteException e) { logd("EVENT_RECEIVE_DATAGRAM_STATE_CHANGED RemoteException: " + e); + toBeRemoved.add(listener.asBinder()); } }); + toBeRemoved.forEach(listener -> { + mListeners.remove(listener); + }); break; } @@ -204,18 +230,13 @@ public class PointingAppController { SatelliteModemInterface.getInstance().registerForSatellitePositionInfoChanged( handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); - /** - * TODO: Need to remove this call, Datagram transfer state should come from the - * DatagramController based upon Transfer state. - * Modem won't be able to provide this info - */ SatelliteModemInterface.getInstance().registerForDatagramTransferStateChanged( handler, - SatelliteTransmissionUpdateHandler.EVENT_SEND_DATAGRAM_STATE_CHANGED, null); + SatelliteTransmissionUpdateHandler.EVENT_DATAGRAM_TRANSFER_STATE_CHANGED, + null); } else { phone.registerForSatellitePositionInfoChanged(handler, SatelliteTransmissionUpdateHandler.EVENT_POSITION_INFO_CHANGED, null); - // TODO: registerForDatagramTransferStateChanged through SatelliteController } } } @@ -237,13 +258,6 @@ public class PointingAppController { handler.removeListener(callback); if (handler.hasListeners()) { - /** - * TODO (b/269194948): If the calling apps crash, the handler will always have some - * listener. That is, we will not request modem to stop position update and - * cleaning our resources. We need to monitor the calling apps and clean up the - * resources when the apps die. We need to do this for other satellite callbacks - * as well. - */ result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; } @@ -260,7 +274,6 @@ public class PointingAppController { return; } phone.unregisterForSatellitePositionInfoChanged(handler); - // TODO: unregisterForDatagramTransferStateChanged through SatelliteController } } } @@ -276,6 +289,9 @@ public class PointingAppController { public void startSatelliteTransmissionUpdates(@NonNull Message message, @Nullable Phone phone) { if (mStartedSatelliteTransmissionUpdates) { logd("startSatelliteTransmissionUpdates: already started"); + AsyncResult.forMessage(message, null, new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_ERROR_NONE)); + message.sendToTarget(); return; } if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { @@ -320,7 +336,17 @@ public class PointingAppController { public void startPointingUI(boolean needFullScreenPointingUI) { String packageName = TextUtils.emptyIfNull(mContext.getResources() .getString(com.android.internal.R.string.config_pointing_ui_package)); + if (TextUtils.isEmpty(packageName)) { + logd("startPointingUI: config_pointing_ui_package is not set. Ignore the request"); + return; + } + Intent launchIntent = mContext.getPackageManager().getLaunchIntentForPackage(packageName); + if (launchIntent == null) { + loge("startPointingUI: launchIntent is null"); + return; + } + launchIntent.putExtra("needFullScreen", needFullScreenPointingUI); mContext.startActivity(launchIntent); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 4a882b021b..fe9a1028eb 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -23,7 +23,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.net.wifi.WifiManager; import android.os.AsyncResult; -import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; @@ -50,15 +49,15 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; import com.android.internal.telephony.satellite.metrics.SessionMetricsStats; -import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.util.FunctionalUtils; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** @@ -96,6 +95,11 @@ public class SatelliteController extends Handler { private static final int CMD_GET_TIME_SATELLITE_NEXT_VISIBLE = 21; private static final int EVENT_GET_TIME_SATELLITE_NEXT_VISIBLE_DONE = 22; private static final int EVENT_RADIO_STATE_CHANGED = 23; + private static final int CMD_IS_SATELLITE_PROVISIONED = 24; + private static final int EVENT_IS_SATELLITE_PROVISIONED_DONE = 25; + private static final int EVENT_SATELLITE_PROVISION_STATE_CHANGED = 26; + private static final int EVENT_PENDING_DATAGRAMS = 27; + private static final int EVENT_SATELLITE_MODEM_STATE_CHANGED = 28; @NonNull private static SatelliteController sInstance; @NonNull private final Context mContext; @@ -115,6 +119,18 @@ public class SatelliteController extends Handler { private static final String KEY_WIFI_DISABLED_BY_SCO = "wifi_disabled_by_sco"; boolean mDisabledBTFlag = false; boolean mDisabledWifiFlag = false; + private final AtomicBoolean mRegisteredForProvisionStateChangedWithSatelliteService = + new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForProvisionStateChangedWithPhone = + new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForPendingDatagramCountWithSatelliteService = + new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForPendingDatagramCountWithPhone = + new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService = + new AtomicBoolean(false); + private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithPhone = + new AtomicBoolean(false); /** * Map key: subId, value: callback to get error code of the provision request. */ @@ -122,24 +138,20 @@ public class SatelliteController extends Handler { new ConcurrentHashMap<>(); /** - * Map key: subId, value: SatelliteProvisionStateChangedHandler to notify registrants. + * Map key: binder of the callback, value: callback to receive provision state changed events. */ - private final ConcurrentHashMap - mSatelliteProvisionStateChangedHandlers = new ConcurrentHashMap<>(); - - /** - * Map key: subId, value: SatelliteStateListenerHandler to notify registrants. - */ - private final ConcurrentHashMap - mSatelliteStateListenerHandlers = new ConcurrentHashMap<>(); + private final ConcurrentHashMap + mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>(); private Boolean mIsSatelliteSupported = null; private final Object mIsSatelliteSupportedLock = new Object(); - private final ResultReceiver mSatelliteSupportedReceiver; private boolean mIsDemoModeEnabled = false; private Boolean mIsSatelliteEnabled = null; private final Object mIsSatelliteEnabledLock = new Object(); - private final ResultReceiver mSatelliteEnabledReceiver; + private Boolean mIsSatelliteProvisioned = null; + private final Object mIsSatelliteProvisionedLock = new Object(); + private SatelliteCapabilities mSatelliteCapabilities; + private final Object mSatelliteCapabilitiesLock = new Object(); private boolean mNeedsSatellitePointing = false; private final Object mNeedsSatellitePointingLock = new Object(); @@ -181,7 +193,7 @@ public class SatelliteController extends Handler { mCi = phone.mCi; // Create the SatelliteModemInterface singleton, which is used to manage connections // to the satellite service and HAL interface. - mSatelliteModemInterface = SatelliteModemInterface.make(mContext); + mSatelliteModemInterface = SatelliteModemInterface.make(mContext, this); // Create the PointingUIController singleton, // which is used to manage interactions with PointingUI app. @@ -197,13 +209,17 @@ public class SatelliteController extends Handler { // which is used to send and receive satellite datagrams. mDatagramController = DatagramController.make(mContext, looper, mPointingAppController); - mSatelliteEnabledReceiver = createSatelliteEnabledResultReceiver(); - mSatelliteSupportedReceiver = createSatelliteSupportedResultReceiver(looper); - //TODO: reenable below code - //requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - // mSatelliteSupportedReceiver); + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteSupported: resultCode=" + resultCode); + } + }); mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); - + registerForSatelliteProvisionStateChanged(); + registerForPendingDatagramCount(); + registerForSatelliteModemStateChanged(); try { mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); @@ -288,116 +304,6 @@ public class SatelliteController extends Handler { } } - private static final class SatelliteProvisionStateChangedHandler extends Handler { - public static final int EVENT_PROVISION_STATE_CHANGED = 1; - - private final ConcurrentHashMap mListeners; - private final int mSubId; - - SatelliteProvisionStateChangedHandler(Looper looper, int subId) { - super(looper); - mListeners = new ConcurrentHashMap<>(); - mSubId = subId; - } - - public void addListener(ISatelliteProvisionStateCallback listener) { - mListeners.put(listener.asBinder(), listener); - } - - public void removeListener(ISatelliteProvisionStateCallback listener) { - mListeners.remove(listener.asBinder()); - } - - @Override - public void handleMessage(@NonNull Message msg) { - switch (msg.what) { - case EVENT_PROVISION_STATE_CHANGED: { - AsyncResult ar = (AsyncResult) msg.obj; - boolean provisioned = (boolean) ar.userObj; - logd("Received EVENT_PROVISION_STATE_CHANGED for subId=" + mSubId - + ", provisioned=" + provisioned); - mListeners.values().forEach(listener -> { - try { - listener.onSatelliteProvisionStateChanged(provisioned); - } catch (RemoteException e) { - logd("EVENT_PROVISION_STATE_CHANGED RemoteException: " + e); - } - }); - - setSatelliteProvisioned(provisioned); - /** - * TODO: Take bugreport if provisioned is true and user did not initiate the - * provision procedure for the corresponding subscription. - */ - break; - } - default: - loge("SatelliteProvisionStateChangedHandler unknown event: " + msg.what); - } - } - - private void setSatelliteProvisioned(boolean isProvisioned) { - if (mSubId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - SubscriptionManager.setSubscriptionProperty( - mSubId, SubscriptionManager.SATELLITE_ENABLED, isProvisioned ? "1" : "0"); - } else { - //TODO (b/267826133): set via SatelliteController. - } - } - } - - private static final class SatelliteStateListenerHandler extends Handler { - public static final int EVENT_SATELLITE_MODEM_STATE_CHANGE = 1; - public static final int EVENT_PENDING_DATAGRAMS = 2; - - private final ConcurrentHashMap mListeners; - private final int mSubId; - - SatelliteStateListenerHandler(Looper looper, int subId) { - super(looper); - mSubId = subId; - mListeners = new ConcurrentHashMap<>(); - } - - public void addListener(ISatelliteStateCallback listener) { - mListeners.put(listener.asBinder(), listener); - } - - public void removeListener(ISatelliteStateCallback listener) { - mListeners.remove(listener.asBinder()); - } - - public boolean hasListeners() { - return !mListeners.isEmpty(); - } - - @Override - public void handleMessage(@NonNull Message msg) { - switch (msg.what) { - case EVENT_SATELLITE_MODEM_STATE_CHANGE : { - AsyncResult ar = (AsyncResult) msg.obj; - int state = (int) ar.result; - logd("Received EVENT_SATELLITE_MODEM_STATE_CHANGE for subId=" + mSubId - + ", state=" + state); - break; - } - case EVENT_PENDING_DATAGRAMS: { - logd("Received EVENT_PENDING_DATAGRAMS for subId=" + mSubId); - IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { - @Override - public void accept(int result) { - logd("pollPendingSatelliteDatagram result: " + result); - } - }; - sInstance.pollPendingSatelliteDatagrams(mSubId, internalCallback); - break; - } - default: - loge("SatelliteStateListenerHandler unknown event: " + msg.what); - } - } - } - @Override public void handleMessage(Message msg) { SatelliteControllerHandlerRequest request; @@ -544,8 +450,7 @@ public class SatelliteController extends Handler { checkAndEnableBluetoothWifiState(); } /** - * TODO: check if Satellite is Acquired. - * Also need to call requestSatelliteCapabilities() if Satellite is enabled + * TODO for NTN-based satellites: Check if satellite is acquired. */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(false); @@ -555,7 +460,6 @@ public class SatelliteController extends Handler { argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); } argument.callback.accept(error); - // TODO: if error is ERROR_NONE, request satellite capabilities if (argument.enableSatellite) { if (error == SatelliteManager.SATELLITE_ERROR_NONE) { @@ -645,9 +549,7 @@ public class SatelliteController extends Handler { boolean supported = (boolean) ar.result; if (DBG) logd("isSatelliteSupported: " + supported); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported); - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = supported; - } + updateSatelliteSupportedState(supported); } } ((ResultReceiver) request.argument).send(error, bundle); @@ -690,6 +592,9 @@ public class SatelliteController extends Handler { if (DBG) logd("getSatelliteCapabilities: " + capabilities); bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, capabilities); + synchronized (mSatelliteCapabilitiesLock) { + mSatelliteCapabilities = capabilities; + } } } ((ResultReceiver) request.argument).send(error, bundle); @@ -802,10 +707,101 @@ public class SatelliteController extends Handler { new RequestSatelliteEnabledArgument(false, false, result); request = new SatelliteControllerHandlerRequest(message, phone); handleSatelliteEnabled(request); + } else { + if (!mSatelliteModemInterface.isSatelliteServiceSupported()) { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported == null) { + ResultReceiver receiver = new ResultReceiver(this) { + @Override + protected void onReceiveResult( + int resultCode, Bundle resultData) { + logd("requestIsSatelliteSupported: resultCode=" + + resultCode); + } + }; + requestIsSatelliteSupported( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); + } + } + } else { + logd("EVENT_RADIO_STATE_CHANGED: Satellite vendor service is supported." + + " Ignored the event"); + } } break; } + case CMD_IS_SATELLITE_PROVISIONED: { + request = (SatelliteControllerHandlerRequest) msg.obj; + onCompleted = obtainMessage(EVENT_IS_SATELLITE_PROVISIONED_DONE, request); + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + mSatelliteModemInterface.requestIsSatelliteProvisioned(onCompleted); + break; + } + Phone phone = request.phone; + if (phone != null) { + phone.isSatelliteProvisioned(onCompleted); + } else { + loge("isSatelliteProvisioned: No phone object"); + ((ResultReceiver) request.argument).send( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + } + break; + } + + case EVENT_IS_SATELLITE_PROVISIONED_DONE: { + ar = (AsyncResult) msg.obj; + request = (SatelliteControllerHandlerRequest) ar.userObj; + int error = SatelliteServiceUtils.getSatelliteError(ar, + "isSatelliteProvisioned"); + Bundle bundle = new Bundle(); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { + if (ar.result == null) { + loge("isSatelliteProvisioned: result is null"); + error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } else { + boolean provisioned = ((int[]) ar.result)[0] == 1; + if (DBG) logd("isSatelliteProvisioned: " + provisioned); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, provisioned); + synchronized (mIsSatelliteProvisionedLock) { + mIsSatelliteProvisioned = provisioned; + } + } + } + ((ResultReceiver) request.argument).send(error, bundle); + break; + } + + case EVENT_SATELLITE_PROVISION_STATE_CHANGED: + ar = (AsyncResult) msg.obj; + if (ar.result == null) { + loge("EVENT_SATELLITE_PROVISION_STATE_CHANGED: result is null"); + } else { + handleEventSatelliteProvisionStateChanged((boolean) ar.result); + } + break; + + case EVENT_PENDING_DATAGRAMS: + logd("Received EVENT_PENDING_DATAGRAMS"); + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("pollPendingSatelliteDatagram result: " + result); + } + }; + pollPendingSatelliteDatagrams( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, internalCallback); + break; + + case EVENT_SATELLITE_MODEM_STATE_CHANGED: + ar = (AsyncResult) msg.obj; + if (ar.result == null) { + loge("EVENT_SATELLITE_MODEM_STATE_CHANGED: result is null"); + } else { + handleEventSatelliteModemStateChanged((int) ar.result); + } + break; + default: Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " + msg.what); @@ -833,22 +829,29 @@ public class SatelliteController extends Handler { public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteSupported) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - // TODO: clean up this dependency on subId - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } - Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_SET_SATELLITE_ENABLED, new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result), - phone); + SatelliteServiceUtils.getPhone()); } /** @@ -859,14 +862,13 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { - result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); return; } - - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { - result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); + if (!satelliteSupported) { + result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } @@ -880,7 +882,7 @@ public class SatelliteController extends Handler { } } - sendRequest(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); + sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); } /** @@ -892,13 +894,22 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteSupported) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteProvisioned) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -937,13 +948,27 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteSupported) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - Phone phone = SatelliteServiceUtils.getPhone(); - sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, phone); + synchronized (mSatelliteCapabilitiesLock) { + if (mSatelliteCapabilities != null) { + Bundle bundle = new Bundle(); + bundle.putParcelable(SatelliteManager.KEY_SATELLITE_CAPABILITIES, + mSatelliteCapabilities); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + return; + } + } + + sendRequestAsync(CMD_GET_SATELLITE_CAPABILITIES, result, SatelliteServiceUtils.getPhone()); } /** @@ -959,18 +984,28 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteSupported) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } Phone phone = SatelliteServiceUtils.getPhone(); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.registerForSatelliteTransmissionUpdates(validSubId, callback, phone); sendRequestAsync(CMD_START_SATELLITE_TRANSMISSION_UPDATES, new SatelliteTransmissionUpdateArgument(result, callback, validSubId), phone); @@ -988,18 +1023,28 @@ public class SatelliteController extends Handler { public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteSupported) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } Phone phone = SatelliteServiceUtils.getPhone(); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mPointingAppController.unregisterForSatelliteTransmissionUpdates( validSubId, result, callback, phone); @@ -1025,24 +1070,29 @@ public class SatelliteController extends Handler { @Nullable public ICancellationSignal provisionSatelliteService(int subId, @NonNull String token, @NonNull String regionId, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return null; + } + if (!satelliteSupported) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return null; } final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - Phone phone = SatelliteServiceUtils.getPhone(); - if (mSatelliteProvisionCallbacks.containsKey(validSubId)) { result.accept(SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS); return null; } - if (isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned != null && satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return null; } + Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, regionId, result, validSubId), phone); @@ -1070,18 +1120,28 @@ public class SatelliteController extends Handler { public void deprovisionSatelliteService(int subId, @NonNull String token, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteSupported) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_ERROR_NONE); return; } Phone phone = SatelliteServiceUtils.getPhone(); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, new ProvisionSatelliteServiceArgument(token, null, result, validSubId), phone); } @@ -1096,34 +1156,15 @@ public class SatelliteController extends Handler { */ @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId, @NonNull ISatelliteProvisionStateCallback callback) { - if (!isSatelliteSupported()) { - return SatelliteManager.SATELLITE_NOT_SUPPORTED; + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; } - - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - Phone phone = SatelliteServiceUtils.getPhone(); - - SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = - mSatelliteProvisionStateChangedHandlers.get(validSubId); - if (satelliteProvisionStateChangedHandler == null) { - satelliteProvisionStateChangedHandler = new SatelliteProvisionStateChangedHandler( - Looper.getMainLooper(), validSubId); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( - satelliteProvisionStateChangedHandler, - SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); - } else { - phone.registerForSatelliteProvisionStateChanged( - satelliteProvisionStateChangedHandler, - SatelliteProvisionStateChangedHandler.EVENT_PROVISION_STATE_CHANGED, null); - } + if (!satelliteSupported) { + return SatelliteManager.SATELLITE_NOT_SUPPORTED; } - if (callback != null) { - satelliteProvisionStateChangedHandler.addListener(callback); - } - mSatelliteProvisionStateChangedHandlers.put( - validSubId, satelliteProvisionStateChangedHandler); + mSatelliteProvisionStateChangedListeners.put(callback.asBinder(), callback); return SatelliteManager.SATELLITE_ERROR_NONE; } @@ -1137,12 +1178,7 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteProvisionStateChanged( int subId, @NonNull ISatelliteProvisionStateCallback callback) { - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - SatelliteProvisionStateChangedHandler satelliteProvisionStateChangedHandler = - mSatelliteProvisionStateChangedHandlers.get(validSubId); - if (satelliteProvisionStateChangedHandler != null) { - satelliteProvisionStateChangedHandler.removeListener(callback); - } + mSatelliteProvisionStateChangedListeners.remove(callback.asBinder()); } /** @@ -1154,16 +1190,27 @@ public class SatelliteController extends Handler { * request failed. */ public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteSupported) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - Bundle bundle = new Bundle(); - bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, - isSatelliteProvisioned(validSubId)); - result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + synchronized (mIsSatelliteProvisionedLock) { + if (mIsSatelliteProvisioned != null) { + Bundle bundle = new Bundle(); + bundle.putBoolean(SatelliteManager.KEY_SATELLITE_PROVISIONED, + mIsSatelliteProvisioned); + result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); + return; + } + } + + sendRequestAsync(CMD_IS_SATELLITE_PROVISIONED, result, SatelliteServiceUtils.getPhone()); } /** @@ -1183,35 +1230,6 @@ public class SatelliteController extends Handler { + " is not initialized yet"); return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; } - - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - SatelliteStateListenerHandler satelliteStateListenerHandler = - mSatelliteStateListenerHandlers.get(validSubId); - if (satelliteStateListenerHandler == null) { - satelliteStateListenerHandler = new SatelliteStateListenerHandler( - Looper.getMainLooper(), validSubId); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.registerForSatelliteModemStateChanged( - satelliteStateListenerHandler, - SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); - mSatelliteModemInterface.registerForPendingDatagrams(satelliteStateListenerHandler, - SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone == null) { - loge("registerForSatelliteModemStateChanged: satellite phone is " - + "not initialized yet"); - return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; - } - phone.registerForSatelliteModemStateChanged(satelliteStateListenerHandler, - SatelliteStateListenerHandler.EVENT_SATELLITE_MODEM_STATE_CHANGE, null); - phone.registerForPendingDatagramCount(satelliteStateListenerHandler, - SatelliteStateListenerHandler.EVENT_PENDING_DATAGRAMS, null); - } - } - - satelliteStateListenerHandler.addListener(callback); - mSatelliteStateListenerHandlers.put(validSubId, satelliteStateListenerHandler); return SatelliteManager.SATELLITE_ERROR_NONE; } @@ -1225,25 +1243,6 @@ public class SatelliteController extends Handler { */ public void unregisterForSatelliteModemStateChanged(int subId, @NonNull ISatelliteStateCallback callback) { - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - SatelliteStateListenerHandler handler = mSatelliteStateListenerHandlers.get(validSubId); - if (handler != null) { - handler.removeListener(callback); - if (!handler.hasListeners()) { - mSatelliteStateListenerHandlers.remove(validSubId); - if (mSatelliteModemInterface.isSatelliteServiceSupported()) { - mSatelliteModemInterface.unregisterForSatelliteModemStateChanged(handler); - mSatelliteModemInterface.unregisterForPendingDatagrams(handler); - } else { - Phone phone = SatelliteServiceUtils.getPhone(); - if (phone != null) { - phone.unregisterForSatelliteModemStateChanged(handler); - phone.unregisterForPendingDatagramCount(handler); - } - } - } - } - if (mSatelliteSessionController != null) { mSatelliteSessionController.unregisterForSatelliteModemStateChanged(callback); } else { @@ -1290,16 +1289,20 @@ public class SatelliteController extends Handler { * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ public void pollPendingSatelliteDatagrams(int subId, @NonNull IIntegerConsumer callback) { - // TODO: return pending datagram count on success Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } - mDatagramController.pollPendingSatelliteDatagrams(subId, result); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); + mDatagramController.pollPendingSatelliteDatagrams(validSubId, result); } /** @@ -1323,20 +1326,24 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + return; + } + if (!satelliteProvisioned) { result.accept(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED); return; } /** - * TODO: check if Satellite is Acquired. Also need to call requestSatelliteCapabilities() - * when Satellite is enabled + * TODO for NTN-based satellites: Check if satellite is acquired. */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(needFullScreenPointingUI); } + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); mDatagramController.sendSatelliteDatagram(validSubId, datagramType, datagram, needFullScreenPointingUI, result); } @@ -1352,13 +1359,18 @@ public class SatelliteController extends Handler { */ public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteSupported) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - Phone phone = SatelliteServiceUtils.getPhone(); - sendRequest(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, phone); + sendRequestAsync( + CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, result, SatelliteServiceUtils.getPhone()); } /** @@ -1369,13 +1381,22 @@ public class SatelliteController extends Handler { * be visible if the request is successful or an error code if the request failed. */ public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) { - if (!isSatelliteSupported()) { + Boolean satelliteSupported = isSatelliteSupported(); + if (satelliteSupported == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteSupported) { result.send(SatelliteManager.SATELLITE_NOT_SUPPORTED, null); return; } - final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId(subId, mContext); - if (!isSatelliteProvisioned(validSubId)) { + Boolean satelliteProvisioned = isSatelliteProvisioned(); + if (satelliteProvisioned == null) { + result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); + return; + } + if (!satelliteProvisioned) { result.send(SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED, null); return; } @@ -1384,6 +1405,61 @@ public class SatelliteController extends Handler { sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); } + /** + * If we have not successfully queried the satellite modem for its satellite service support, + * we will retry the query one more time. Otherwise, we will return the cached result. + */ + public Boolean isSatelliteSupported() { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported != null) { + /* We have already successfully queried the satellite modem. */ + return mIsSatelliteSupported; + } + } + /** + * We have not successfully checked whether the modem supports satellite service. + * Thus, we need to retry it now. + */ + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteSupported: resultCode=" + resultCode); + } + }); + return null; + } + + /** + * This function is used by {@link SatelliteModemInterface} to notify + * {@link SatelliteController} that the satellite vendor service was just connected. + *

+ * {@link SatelliteController} will send requests to satellite modem to check whether it support + * satellite, whether it is powered on, and whether it is provisioned. + * {@link SatelliteController} will use these cached values to serve requests from its clients. + */ + void onSatelliteServiceConnected() { + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported == null) { + ResultReceiver receiver = new ResultReceiver(this) { + @Override + protected void onReceiveResult( + int resultCode, Bundle resultData) { + logd("requestIsSatelliteSupported: resultCode=" + + resultCode); + } + }; + requestIsSatelliteSupported( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); + } + } + } else { + logd("onSatelliteServiceConnected: Satellite vendor service is not supported." + + " Ignored the event"); + } + } + private void handleEventProvisionSatelliteServiceDone( @NonNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteError int result) { @@ -1403,22 +1479,6 @@ public class SatelliteController extends Handler { return; } callback.accept(result); - - if (result == SatelliteManager.SATELLITE_ERROR_NONE) { - setSatelliteProvisioned(arg.subId, true); - } - - /** - * We need to update satellite provision status in SubscriptionController - * or SatelliteController. - * TODO (b/267826133) we need to do this for all subscriptions on the device. - */ - registerForSatelliteProvisionStateChanged(arg.subId, null); - - mProvisionMetricsStats.setResultCode(result) - .setIsProvisionRequest(true) - .reportProvisionMetrics(); - mControllerMetricsStats.reportProvisionCount(result); } private void handleEventDeprovisionSatelliteServiceDone( @@ -1438,10 +1498,6 @@ public class SatelliteController extends Handler { .reportProvisionMetrics(); mControllerMetricsStats.reportDeprovisionCount(result); } - - if (result == SatelliteManager.SATELLITE_ERROR_NONE) { - setSatelliteProvisioned(arg.subId, false); - } } private void handleStartSatelliteTransmissionUpdatesDone(@NonNull AsyncResult ar) { @@ -1463,42 +1519,6 @@ public class SatelliteController extends Handler { } } - /** - * Set satellite provisioned for a subscription or the device. - * - * The permission {@link android.Manifest.permission#MODIFY_PHONE_STATE} will be enforced by - * {@link SubscriptionController} when setting satellite enabled for an active subscription. - * Otherwise, {@link android.Manifest.permission#SATELLITE_COMMUNICATION} will be enforced. - */ - private synchronized void setSatelliteProvisioned(int subId, boolean isEnabled) { - if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - SubscriptionManager.setSubscriptionProperty( - subId, SubscriptionManager.SATELLITE_ENABLED, isEnabled ? "1" : "0"); - } else { - //TODO (b/267826133): set via SatelliteController - } - } - - /** - * If we have not successfully queried the satellite modem for its satellite service support, - * we will retry the query one more time. Otherwise, we will return the queried result. - */ - public boolean isSatelliteSupported() { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported != null) { - /* We have already successfully queried the satellite modem. */ - return mIsSatelliteSupported; - } - } - /** - * We have not successfully checked whether the modem supports satellite service. - * Thus, we need to retry it now. - */ - requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - mSatelliteSupportedReceiver); - return false; - } - /** * Posts the specified command to be executed on the main thread and returns immediately. * @@ -1547,35 +1567,24 @@ public class SatelliteController extends Handler { /** * Check if satellite is provisioned for a subscription on the device. - * @param subId The subscription id. * @return true if satellite is provisioned on the given subscription else return false. */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - protected boolean isSatelliteProvisioned(int subId) { - final long identity = Binder.clearCallingIdentity(); - try { - if (subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - String strResult = null; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - strResult = SubscriptionManagerService.getInstance() - .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED, - mContext.getOpPackageName(), mContext.getAttributionTag()); - } else { - strResult = SubscriptionController.getInstance() - .getSubscriptionProperty(subId, SubscriptionManager.SATELLITE_ENABLED); - } - - if (strResult != null) { - int intResult = Integer.parseInt(strResult); - return (intResult == 1); - } - } else { - //TODO (b/267826133): check via SatelliteController + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected Boolean isSatelliteProvisioned() { + synchronized (mIsSatelliteProvisionedLock) { + if (mIsSatelliteProvisioned != null) { + return mIsSatelliteProvisioned; } - } finally { - Binder.restoreCallingIdentity(identity); } - return false; + + requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); + } + }); + return null; } private void handleSatelliteEnabled(SatelliteControllerHandlerRequest request) { @@ -1596,39 +1605,39 @@ public class SatelliteController extends Handler { } } - private ResultReceiver createSatelliteSupportedResultReceiver(@NonNull Looper looper) { - return new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE - && resultData.containsKey(SatelliteManager.KEY_SATELLITE_SUPPORTED)) { - synchronized (mIsSatelliteSupportedLock) { - mIsSatelliteSupported = resultData.getBoolean( - SatelliteManager.KEY_SATELLITE_SUPPORTED); - } - } - mSatelliteSessionController = SatelliteSessionController.make(mContext, looper, - mIsSatelliteSupported != null ? mIsSatelliteSupported : false); - if (mIsSatelliteSupported != null && mIsSatelliteSupported) { - requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - mSatelliteEnabledReceiver); - } - } - }; - } + private void updateSatelliteSupportedState(boolean supported) { + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = supported; + } + mSatelliteSessionController = SatelliteSessionController.make( + mContext, getLooper(), supported); + if (supported) { + registerForSatelliteProvisionStateChanged(); + registerForPendingDatagramCount(); + registerForSatelliteModemStateChanged(); - private ResultReceiver createSatelliteEnabledResultReceiver() { - return new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == SatelliteManager.SATELLITE_ERROR_NONE - && resultData.containsKey(SatelliteManager.KEY_SATELLITE_ENABLED)) { - updateSatelliteEnabledState(resultData.getBoolean( - SatelliteManager.KEY_SATELLITE_ENABLED), - "SatelliteEnabledResultReceiver.onReceiveResult"); - } - } - }; + requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteEnabled: resultCode=" + resultCode); + } + }); + requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); + } + }); + requestSatelliteCapabilities(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestSatelliteCapabilities: resultCode=" + resultCode); + } + }); + } } private void updateSatelliteEnabledState(boolean enabled, String caller) { @@ -1676,13 +1685,102 @@ public class SatelliteController extends Handler { if (DBG) logd("Enabling Bluetooth"); mBluetoothAdapter.enable(); mSharedPreferences.edit().putBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, false) - .apply(); + .apply(); } if (!mWifiManager.isWifiEnabled() && mDisabledWifiFlag) { if (DBG) logd("Enabling Wifi"); mWifiManager.setWifiEnabled(true); mSharedPreferences.edit().putBoolean(KEY_WIFI_DISABLED_BY_SCO, false) - .apply(); + .apply(); + } + } + + private void registerForSatelliteProvisionStateChanged() { + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + if (!mRegisteredForProvisionStateChangedWithSatelliteService.get()) { + mSatelliteModemInterface.registerForSatelliteProvisionStateChanged( + this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); + mRegisteredForProvisionStateChangedWithSatelliteService.set(true); + } + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone == null) { + loge("registerForSatelliteProvisionStateChanged: phone is null"); + } else if (!mRegisteredForProvisionStateChangedWithPhone.get()) { + phone.registerForSatelliteProvisionStateChanged( + this, EVENT_SATELLITE_PROVISION_STATE_CHANGED, null); + mRegisteredForProvisionStateChangedWithPhone.set(true); + } + } + } + + private void registerForPendingDatagramCount() { + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + if (!mRegisteredForPendingDatagramCountWithSatelliteService.get()) { + mSatelliteModemInterface.registerForPendingDatagrams( + this, EVENT_PENDING_DATAGRAMS, null); + mRegisteredForPendingDatagramCountWithSatelliteService.set(true); + } + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone == null) { + loge("registerForPendingDatagramCount: satellite phone is " + + "not initialized yet"); + } else if (!mRegisteredForPendingDatagramCountWithPhone.get()) { + phone.registerForPendingDatagramCount(this, EVENT_PENDING_DATAGRAMS, null); + mRegisteredForPendingDatagramCountWithPhone.set(true); + } + } + } + + private void registerForSatelliteModemStateChanged() { + if (mSatelliteModemInterface.isSatelliteServiceSupported()) { + if (!mRegisteredForSatelliteModemStateChangedWithSatelliteService.get()) { + mSatelliteModemInterface.registerForSatelliteModemStateChanged( + this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); + mRegisteredForSatelliteModemStateChangedWithSatelliteService.set(true); + } + } else { + Phone phone = SatelliteServiceUtils.getPhone(); + if (phone == null) { + loge("registerForSatelliteModemStateChanged: satellite phone is " + + "not initialized yet"); + } else if (!mRegisteredForSatelliteModemStateChangedWithPhone.get()) { + phone.registerForSatelliteModemStateChanged( + this, EVENT_SATELLITE_MODEM_STATE_CHANGED, null); + mRegisteredForSatelliteModemStateChangedWithPhone.set(true); + } + } + } + + private void handleEventSatelliteProvisionStateChanged(boolean provisioned) { + logd("handleSatelliteProvisionStateChangedEvent: provisioned=" + provisioned); + + synchronized (mIsSatelliteProvisionedLock) { + mIsSatelliteProvisioned = provisioned; + } + + List toBeRemoved = new ArrayList<>(); + mSatelliteProvisionStateChangedListeners.values().forEach(listener -> { + try { + listener.onSatelliteProvisionStateChanged(provisioned); + } catch (RemoteException e) { + logd("handleSatelliteProvisionStateChangedEvent RemoteException: " + e); + toBeRemoved.add(listener); + } + }); + toBeRemoved.forEach(listener -> { + mSatelliteProvisionStateChangedListeners.remove(listener.asBinder()); + }); + } + + private void handleEventSatelliteModemStateChanged( + @SatelliteManager.SatelliteModemState int state) { + logd("handleEventSatelliteModemStateChanged: state=" + state); + if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF + || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { + updateSatelliteEnabledState( + false, "handleEventSatelliteModemStateChanged"); } } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index cf2fc8593b..8657529183 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -65,6 +65,7 @@ public class SatelliteModemInterface { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @NonNull protected final ExponentialBackoff mExponentialBackoff; @NonNull private final Object mLock = new Object(); + @NonNull private final SatelliteController mSatelliteController; /** * {@code true} to use the vendor satellite service and {@code false} to use the HAL. */ @@ -150,11 +151,14 @@ public class SatelliteModemInterface { /** * Create the SatelliteModemInterface singleton instance. * @param context The Context to use to create the SatelliteModemInterface. + * @param satelliteController The singleton instance of SatelliteController. * @return The singleton instance of SatelliteModemInterface. */ - public static SatelliteModemInterface make(@NonNull Context context) { + public static SatelliteModemInterface make(@NonNull Context context, + SatelliteController satelliteController) { if (sInstance == null) { - sInstance = new SatelliteModemInterface(context, Looper.getMainLooper()); + sInstance = new SatelliteModemInterface( + context, satelliteController, Looper.getMainLooper()); } return sInstance; } @@ -166,9 +170,11 @@ public class SatelliteModemInterface { * @param looper The Looper to run binding retry on. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - protected SatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { + protected SatelliteModemInterface(@NonNull Context context, + SatelliteController satelliteController, @NonNull Looper looper) { mContext = context; mIsSatelliteServiceSupported = getSatelliteServiceSupport(); + mSatelliteController = satelliteController; mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, REBIND_MULTIPLIER, looper, () -> { synchronized (mLock) { @@ -280,6 +286,7 @@ public class SatelliteModemInterface { // TODO: Retry setSatelliteListener logd("setSatelliteListener: RemoteException " + e); } + mSatelliteController.onSatelliteServiceConnected(); } @Override diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java index a1bd99ec72..1eeb5a21db 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java @@ -255,8 +255,7 @@ public class SatelliteSOSMessageRecommender extends Handler { boolean isDialerNotified = false; if (!mIsImsRegistered.get() && !isCellularAvailable() && mIsSatelliteAllowedInCurrentLocation.get() - && mSatelliteController.isSatelliteProvisioned( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) + && mSatelliteController.isSatelliteProvisioned() && shouldTrackCall(mEmergencyConnection.getState())) { logd("handleTimeoutEvent: Sending EVENT_DISPLAY_SOS_MESSAGE to Dialer..."); mEmergencyConnection.sendConnectionEvent(Call.EVENT_DISPLAY_SOS_MESSAGE, null); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index be252f4dcc..5ec69d68cf 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -91,6 +91,7 @@ public class SatelliteSessionController extends StateMachine { private final long mSatelliteStayAtListeningFromSendingMillis; private final long mSatelliteStayAtListeningFromReceivingMillis; private final ConcurrentHashMap mListeners; + @SatelliteManager.SatelliteModemState private int mCurrentState; /** * @return The singleton instance of SatelliteSessionController. @@ -147,6 +148,7 @@ public class SatelliteSessionController extends StateMachine { mSatelliteStayAtListeningFromReceivingMillis = satelliteStayAtListeningFromReceivingMillis; mListeners = new ConcurrentHashMap<>(); mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; addState(mUnavailableState); addState(mPowerOffState); @@ -192,7 +194,12 @@ public class SatelliteSessionController extends StateMachine { * @param callback The callback to handle the satellite modem state changed event. */ public void registerForSatelliteModemStateChanged(@NonNull ISatelliteStateCallback callback) { - mListeners.put(callback.asBinder(), callback); + try { + callback.onSatelliteModemStateChanged(mCurrentState); + mListeners.put(callback.asBinder(), callback); + } catch (RemoteException ex) { + loge("registerForSatelliteModemStateChanged: Got RemoteException ex=" + ex); + } } /** @@ -221,6 +228,7 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering UnavailableState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; } @Override @@ -234,6 +242,7 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering PowerOffState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_OFF; mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @@ -253,8 +262,6 @@ public class SatelliteSessionController extends StateMachine { private void handleSatelliteEnabledStateChanged(boolean on) { if (on) { transitionTo(mIdleState); - } else { - loge("PowerOffState: Unexpected satellite radio powered-off state changed event"); } } } @@ -263,6 +270,7 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering IdleState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE; mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE); } @@ -296,6 +304,7 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering TransferringState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING; notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING); } @@ -333,8 +342,9 @@ public class SatelliteSessionController extends StateMachine { private class ListeningState extends State { @Override public void enter() { - if (DBG) logd("Entering TransferringState"); + if (DBG) logd("Entering ListeningState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_LISTENING; long timeoutMillis = updateListeningMode(true); sendMessageDelayed(EVENT_LISTENING_TIMER_TIMEOUT, timeoutMillis); mIsSendingTriggeredDuringTransferringState.set(false); diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java index 103156cd44..6aca800edd 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java @@ -93,17 +93,17 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); - when(mMockContext.getMainLooper()).thenReturn(Looper.getMainLooper()); + when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper()); when(mMockContext.getResources()).thenReturn(mResources); when(mResources.getString(com.android.internal.R.string.config_satellite_service_package)) .thenReturn(""); mTestSatelliteController = new TestSatelliteController(mMockContext, - Looper.getMainLooper()); + Looper.myLooper()); mTestImsManager = new TestImsManager( mMockContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null); mTestConnection = new TestConnection(CALL_ID); when(mPhone.getServiceState()).thenReturn(mServiceState); - mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.getMainLooper(), + mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.myLooper(), mTestSatelliteController, mTestImsManager, TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE); @@ -118,12 +118,12 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testTimeoutBeforeEmergencyCallEnd() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); @@ -143,14 +143,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testImsRegistrationStateChangedBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestImsManager.sendImsRegistrationStateChangedEvent(true); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -158,11 +158,12 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); mTestImsManager.sendImsRegistrationStateChangedEvent(false); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); @@ -172,7 +173,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testSatelliteProvisionStateChangedBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -180,14 +181,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mTestSatelliteController.sendProvisionStateChangedEvent( SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 2, 2, 2); @@ -196,7 +197,8 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); // Wait for the timeout to expires - waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -207,7 +209,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testEmergencyCallRedialBeforeTimeout() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -217,7 +219,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { when(newPhone.getServiceState()).thenReturn(mServiceState); when(newPhone.isImsRegistered()).thenReturn(false); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, newPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); @@ -234,9 +236,8 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertRegisterForStateChangedEventsTriggered(newPhone, 2, 2, 1); // Wait for the timeout to expires - long timeoutMillis = TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS - - EVENT_PROCESSING_TIME_MILLIS; - waitFor(timeoutMillis > 0 ? timeoutMillis : 0); + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); /** @@ -279,7 +280,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @Test public void testOnEmergencyCallConnectionStateChangedWithWrongCallId() { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); @@ -287,7 +288,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged( WRONG_CALL_ID, Connection.STATE_ACTIVE); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -299,7 +300,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { public void testSatelliteNotAllowedInCurrentLocation() { mTestSatelliteController.setIsSatelliteCommunicationAllowed(false); mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); /** * We should have registered for the state change events abd started the timer when @@ -316,14 +317,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { private void testStopTrackingCallBeforeTimeout( @Connection.ConnectionState int connectionState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(CALL_ID, connectionState); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -335,14 +336,14 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { @ServiceState.RegState int availableServiceState, @ServiceState.RegState int unavailableServiceState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertTrue(mTestSOSMessageRecommender.isTimerStarted()); assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted()); assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); mTestSOSMessageRecommender.sendServiceStateChangedEvent(availableServiceState); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertFalse(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertFalse(mTestSOSMessageRecommender.isTimerStarted()); @@ -350,11 +351,12 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0); mTestSOSMessageRecommender.sendServiceStateChangedEvent(unavailableServiceState); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted()); // Wait for the timeout to expires - waitFor(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + processAllMessages(); assertTrue(mTestConnection.isEventSent(Call.EVENT_DISPLAY_SOS_MESSAGE)); assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); @@ -380,14 +382,6 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { verify(phone, times(unregisterForCellularCount)).unregisterForServiceStateChanged(any()); } - private static void waitFor(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException ex) { - Log.e(TAG, "Thread.sleep() ex=" + ex); - } - } - private static class TestSatelliteController extends SatelliteController { private static final String TAG = "TestSatelliteController"; @@ -395,7 +389,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { mProvisionStateChangedCallbacks; private int mRegisterForSatelliteProvisionStateChangedCalls = 0; private int mUnregisterForSatelliteProvisionStateChangedCalls = 0; - private final Map mSatelliteProvisionStates; + private boolean mIsSatelliteProvisioned = true; private boolean mIsSatelliteCommunicationAllowed = true; /** @@ -407,18 +401,15 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { protected TestSatelliteController(Context context, Looper looper) { super(context, looper); mProvisionStateChangedCallbacks = new HashMap<>(); - mSatelliteProvisionStates = new HashMap<>(); - mSatelliteProvisionStates.put(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true); } @Override - public boolean isSatelliteProvisioned(int subId) { - Boolean provisioned = mSatelliteProvisionStates.get(subId); - return (provisioned != null) ? provisioned : false; + public Boolean isSatelliteProvisioned() { + return mIsSatelliteProvisioned; } @Override - public boolean isSatelliteSupported() { + public Boolean isSatelliteSupported() { return true; } @@ -466,7 +457,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { } public void sendProvisionStateChangedEvent(int subId, boolean provisioned) { - mSatelliteProvisionStates.put(subId, provisioned); + mIsSatelliteProvisioned = provisioned; Set perSubscriptionCallbacks = mProvisionStateChangedCallbacks.get(subId); if (perSubscriptionCallbacks != null) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java index 2b030421d3..3ccf512211 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSessionControllerTest.java @@ -36,7 +36,6 @@ import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.SatelliteManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.util.Log; import com.android.internal.telephony.TelephonyTest; @@ -44,6 +43,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.Semaphore; @@ -70,22 +70,27 @@ public class SatelliteSessionControllerTest extends TelephonyTest { private TestSatelliteSessionController mTestSatelliteSessionController; private TestSatelliteStateCallback mTestSatelliteStateCallback; + @Mock + private SatelliteController mSatelliteController; + @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); mSatelliteModemInterface = new TestSatelliteModemInterface( - mContext, Looper.getMainLooper()); + mContext, mSatelliteController, Looper.myLooper()); mTestSatelliteSessionController = new TestSatelliteSessionController(mContext, - Looper.getMainLooper(), true, mSatelliteModemInterface, + Looper.myLooper(), true, mSatelliteModemInterface, TEST_SATELLITE_STAY_AT_LISTENING_MILLIS, TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); mTestSatelliteStateCallback = new TestSatelliteStateCallback(); mTestSatelliteSessionController.registerForSatelliteModemStateChanged( mTestSatelliteStateCallback); + assertSuccessfulModemStateChangedCallback( + mTestSatelliteStateCallback, SatelliteManager.SATELLITE_MODEM_STATE_OFF); } @After @@ -100,18 +105,20 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController1 = new TestSatelliteSessionController( - mContext, Looper.getMainLooper(), false, + mContext, Looper.myLooper(), false, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController1); + processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController1.getCurrentStateName()); /** * Since satellite is supported, SatelliteSessionController should move to POWER_OFF state. */ TestSatelliteSessionController sessionController2 = new TestSatelliteSessionController( - mContext, Looper.getMainLooper(), true, + mContext, Looper.myLooper(), true, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController2); + processAllMessages(); assertEquals(STATE_POWER_OFF, sessionController2.getCurrentStateName()); } @@ -122,9 +129,10 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * state. */ TestSatelliteSessionController sessionController = new TestSatelliteSessionController( - mContext, Looper.getMainLooper(), false, + mContext, Looper.myLooper(), false, mSatelliteModemInterface, 100, 100); assertNotNull(sessionController); + processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); /** @@ -132,7 +140,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { * satellite radio powered-on state changed event. */ sessionController.onSatelliteEnabledStateChanged(true); - waitFor(EVENT_PROCESSING_TIME_MILLIS); + processAllMessages(); assertEquals(STATE_UNAVAILABLE, sessionController.getCurrentStateName()); } @@ -146,6 +154,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power on the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + processAllMessages(); // SatelliteSessionController should move to IDLE state after the modem is powered on. assertSuccessfulModemStateChangedCallback( @@ -155,6 +164,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power off the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); + processAllMessages(); // SatelliteSessionController should move back to POWER_OFF state. assertSuccessfulModemStateChangedCallback( @@ -164,6 +174,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power on the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(true); + processAllMessages(); // SatelliteSessionController should move to IDLE state after radio is turned on. assertSuccessfulModemStateChangedCallback( @@ -174,6 +185,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Start sending datagrams mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -185,6 +197,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to IDLE state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -196,6 +209,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -207,6 +221,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -219,6 +234,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -230,6 +246,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Receiving datagrams is successful and done. mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -242,6 +259,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -254,6 +272,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); + processAllMessages(); // SatelliteSessionController should move to IDLE state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -265,6 +284,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -275,6 +295,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Receiving datagrams is successful and done. mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE); + processAllMessages(); // SatelliteSessionController should move to LISTENING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -284,7 +305,8 @@ public class SatelliteSessionControllerTest extends TelephonyTest { assertFalse(mTestSatelliteSessionController.isSendingTriggeredDuringTransferringState()); // Wait for timeout - waitFor(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); + moveTimeForward(TEST_SATELLITE_STAY_AT_LISTENING_MILLIS); + processAllMessages(); // SatelliteSessionController should move to IDLE state after timeout assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -297,6 +319,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should move to TRANSFERRING state. assertSuccessfulModemStateChangedCallback(mTestSatelliteStateCallback, @@ -308,6 +331,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state. assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); @@ -318,6 +342,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED); + processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE // state. @@ -329,6 +354,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state. assertModemStateChangedCallbackNotCalled(mTestSatelliteStateCallback); @@ -339,6 +365,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { mTestSatelliteSessionController.onDatagramTransferStateChanged( SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + processAllMessages(); // SatelliteSessionController should stay at TRANSFERRING state instead of moving to IDLE // state. @@ -348,6 +375,7 @@ public class SatelliteSessionControllerTest extends TelephonyTest { // Power off the modem. mTestSatelliteSessionController.onSatelliteEnabledStateChanged(false); + processAllMessages(); // SatelliteSessionController should move to POWER_OFF state. assertSuccessfulModemStateChangedCallback( @@ -360,8 +388,9 @@ public class SatelliteSessionControllerTest extends TelephonyTest { private final AtomicInteger mListeningEnabledCount = new AtomicInteger(0); private final AtomicInteger mListeningDisabledCount = new AtomicInteger(0); - TestSatelliteModemInterface(@NonNull Context context, @NonNull Looper looper) { - super(context, looper); + TestSatelliteModemInterface(@NonNull Context context, + SatelliteController satelliteController, @NonNull Looper looper) { + super(context, satelliteController, looper); mExponentialBackoff.stop(); } @@ -444,14 +473,6 @@ public class SatelliteSessionControllerTest extends TelephonyTest { } } - private static void waitFor(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException ex) { - Log.e(TAG, "Thread.sleep() ex=" + ex); - } - } - private static void assertSuccessfulModemStateChangedCallback( TestSatelliteStateCallback callback, @SatelliteManager.SatelliteModemState int expectedModemState) { -- GitLab From 93c001b81de81be8eb4807f991c5f1a112c2501c Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Wed, 29 Mar 2023 14:08:35 -0700 Subject: [PATCH 566/656] Change return type of isSatelliteSupported from Boolean to boolean Bug: 274136093 Test: Emergency/normal call, SMS, MMS with live network. atest com.android.internal.telephony.satellite.SatelliteSOSMessageRecommenderTest atest com.android.internal.telephony.satellite.SatelliteSessionControllerTest atest android.telephony.cts.SatelliteManagerTest Change-Id: I78aa245b0656cf994b21c449ba0e4e7f5058364b --- .../satellite/SatelliteController.java | 86 +++++++++++-------- .../satellite/SatelliteModemInterface.java | 3 +- .../satellite/SatelliteSessionController.java | 9 ++ .../SatelliteSOSMessageRecommenderTest.java | 18 +++- 4 files changed, 75 insertions(+), 41 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index fe9a1028eb..dde94351a4 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -185,7 +185,7 @@ public class SatelliteController extends Handler { * @param looper The looper for the handler. It does not run on main thread. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - protected SatelliteController(@NonNull Context context, @NonNull Looper looper) { + public SatelliteController(@NonNull Context context, @NonNull Looper looper) { super(looper); mContext = context; @@ -512,6 +512,8 @@ public class SatelliteController extends Handler { bundle.putBoolean(SatelliteManager.KEY_SATELLITE_ENABLED, enabled); updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE"); } + } else if (error == SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED) { + updateSatelliteSupportedState(false); } ((ResultReceiver) request.argument).send(error, bundle); break; @@ -829,7 +831,7 @@ public class SatelliteController extends Handler { public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); return; @@ -862,7 +864,7 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsSatelliteEnabled(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); return; @@ -894,7 +896,7 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestIsDemoModeEnabled(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); return; @@ -948,7 +950,7 @@ public class SatelliteController extends Handler { * if the request is successful or an error code if the request failed. */ public void requestSatelliteCapabilities(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); return; @@ -984,7 +986,7 @@ public class SatelliteController extends Handler { @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); return; @@ -1023,7 +1025,7 @@ public class SatelliteController extends Handler { public void stopSatelliteTransmissionUpdates(int subId, @NonNull IIntegerConsumer errorCallback, @NonNull ISatelliteTransmissionUpdateCallback callback) { Consumer result = FunctionalUtils.ignoreRemoteException(errorCallback::accept); - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); return; @@ -1070,7 +1072,7 @@ public class SatelliteController extends Handler { @Nullable public ICancellationSignal provisionSatelliteService(int subId, @NonNull String token, @NonNull String regionId, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); return null; @@ -1120,7 +1122,7 @@ public class SatelliteController extends Handler { public void deprovisionSatelliteService(int subId, @NonNull String token, @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); return; @@ -1156,7 +1158,7 @@ public class SatelliteController extends Handler { */ @SatelliteManager.SatelliteError public int registerForSatelliteProvisionStateChanged(int subId, @NonNull ISatelliteProvisionStateCallback callback) { - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { return SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; } @@ -1190,7 +1192,7 @@ public class SatelliteController extends Handler { * request failed. */ public void requestIsSatelliteProvisioned(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); return; @@ -1359,7 +1361,7 @@ public class SatelliteController extends Handler { */ public void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); return; @@ -1381,7 +1383,7 @@ public class SatelliteController extends Handler { * be visible if the request is successful or an error code if the request failed. */ public void requestTimeForNextSatelliteVisibility(int subId, @NonNull ResultReceiver result) { - Boolean satelliteSupported = isSatelliteSupported(); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.send(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE, null); return; @@ -1405,31 +1407,6 @@ public class SatelliteController extends Handler { sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); } - /** - * If we have not successfully queried the satellite modem for its satellite service support, - * we will retry the query one more time. Otherwise, we will return the cached result. - */ - public Boolean isSatelliteSupported() { - synchronized (mIsSatelliteSupportedLock) { - if (mIsSatelliteSupported != null) { - /* We have already successfully queried the satellite modem. */ - return mIsSatelliteSupported; - } - } - /** - * We have not successfully checked whether the modem supports satellite service. - * Thus, we need to retry it now. - */ - requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteSupported: resultCode=" + resultCode); - } - }); - return null; - } - /** * This function is used by {@link SatelliteModemInterface} to notify * {@link SatelliteController} that the satellite vendor service was just connected. @@ -1460,6 +1437,39 @@ public class SatelliteController extends Handler { } } + /** + * @return {@code true} is satellite is supported on the device, {@code false} otherwise. + */ + public boolean isSatelliteSupported() { + Boolean supported = isSatelliteSupportedInternal(); + return (supported != null ? supported : false); + } + + /** + * If we have not successfully queried the satellite modem for its satellite service support, + * we will retry the query one more time. Otherwise, we will return the cached result. + */ + private Boolean isSatelliteSupportedInternal() { + synchronized (mIsSatelliteSupportedLock) { + if (mIsSatelliteSupported != null) { + /* We have already successfully queried the satellite modem. */ + return mIsSatelliteSupported; + } + } + /** + * We have not successfully checked whether the modem supports satellite service. + * Thus, we need to retry it now. + */ + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteSupported: resultCode=" + resultCode); + } + }); + return null; + } + private void handleEventProvisionSatelliteServiceDone( @NonNull ProvisionSatelliteServiceArgument arg, @SatelliteManager.SatelliteError int result) { diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 8657529183..b59292b332 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -578,7 +578,8 @@ public class SatelliteModemInterface { } } else { loge("requestIsSatelliteSupported: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult( + message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index 5ec69d68cf..98bd4c29b5 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -31,6 +31,7 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.provider.DeviceConfig; +import android.telephony.Rlog; import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.SatelliteManager; import android.util.Log; @@ -92,6 +93,7 @@ public class SatelliteSessionController extends StateMachine { private final long mSatelliteStayAtListeningFromReceivingMillis; private final ConcurrentHashMap mListeners; @SatelliteManager.SatelliteModemState private int mCurrentState; + final boolean mIsSatelliteSupported; /** * @return The singleton instance of SatelliteSessionController. @@ -118,6 +120,12 @@ public class SatelliteSessionController extends StateMachine { SatelliteModemInterface.getInstance(), getSatelliteStayAtListeningFromSendingMillis(), getSatelliteStayAtListeningFromReceivingMillis()); + } else { + if (isSatelliteSupported != sInstance.mIsSatelliteSupported) { + Rlog.e(TAG, "New satellite support state " + isSatelliteSupported + + " is different from existing state " + sInstance.mIsSatelliteSupported + + ". Ignore the new state."); + } } return sInstance; } @@ -149,6 +157,7 @@ public class SatelliteSessionController extends StateMachine { mListeners = new ConcurrentHashMap<>(); mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false); mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; + mIsSatelliteSupported = isSatelliteSupported; addState(mUnavailableState); addState(mPowerOffState); diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java index 6aca800edd..418d0aaede 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java @@ -72,7 +72,6 @@ import java.util.concurrent.Executor; public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { private static final String TAG = "SatelliteSOSMessageRecommenderTest"; private static final long TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 500; - private static final long EVENT_PROCESSING_TIME_MILLIS = 100; private static final int PHONE_ID = 0; private static final String CALL_ID = "CALL_ID"; private static final String WRONG_CALL_ID = "WRONG_CALL_ID"; @@ -314,6 +313,21 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1); } + @Test + public void testOnEmergencyCallStarted() { + SatelliteController satelliteController = new SatelliteController( + mMockContext, Looper.myLooper()); + TestSOSMessageRecommender testSOSMessageRecommender = new TestSOSMessageRecommender( + Looper.myLooper(), + satelliteController, mTestImsManager, + TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS); + testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); + processAllMessages(); + + assertFalse(testSOSMessageRecommender.isTimerStarted()); + assertEquals(0, testSOSMessageRecommender.getCountOfTimerStarted()); + } + private void testStopTrackingCallBeforeTimeout( @Connection.ConnectionState int connectionState) { mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone); @@ -409,7 +423,7 @@ public class SatelliteSOSMessageRecommenderTest extends TelephonyTest { } @Override - public Boolean isSatelliteSupported() { + public boolean isSatelliteSupported() { return true; } -- GitLab From e130ecafaf56686bd86ad2520fb723987aedc8a1 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 28 Mar 2023 21:46:19 -0700 Subject: [PATCH 567/656] Broadcast subId upon service initialized Bug: 274346711 Test: verify the broadcast in log Change-Id: Ifea042359646423e2b4b2a753096d9582651fa43 --- .../SubscriptionManagerService.java | 43 ++++++++++++------- .../SubscriptionManagerServiceTest.java | 21 +++++++-- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 85fe9ed5a0..ea73fb8ad4 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -523,6 +523,13 @@ public class SubscriptionManagerService extends ISub.Stub { } }); + // Broadcast sub Id on service initialized. + broadcastSubId(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED, + getDefaultDataSubId()); + broadcastSubId(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED, + getDefaultVoiceSubId()); + broadcastSubId(SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED, + getDefaultSmsSubId()); updateDefaultSubId(); TelephonyServiceManager.ServiceRegisterer subscriptionServiceRegisterer = @@ -2704,7 +2711,7 @@ public class SubscriptionManagerService extends ISub.Stub { Intent intent = new Intent(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId, subId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); } } @@ -2774,11 +2781,8 @@ public class SubscriptionManagerService extends ISub.Stub { if (mDefaultDataSubId.set(subId)) { MultiSimSettingController.getInstance().notifyDefaultDataSubChanged(); - Intent intent = new Intent( - TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - SubscriptionManager.putSubscriptionIdExtra(intent, subId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + broadcastSubId(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED, + subId); updateDefaultSubId(); } @@ -2814,11 +2818,8 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { if (mDefaultVoiceSubId.set(subId)) { - Intent intent = new Intent( - TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - SubscriptionManager.putSubscriptionIdExtra(intent, subId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + broadcastSubId(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED, + subId); PhoneAccountHandle newHandle = subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID ? null : mTelephonyManager.getPhoneAccountHandleForSubscriptionId(subId); @@ -2863,11 +2864,8 @@ public class SubscriptionManagerService extends ISub.Stub { final long token = Binder.clearCallingIdentity(); try { if (mDefaultSmsSubId.set(subId)) { - Intent intent = new Intent( - SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - SubscriptionManager.putSubscriptionIdExtra(intent, subId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + broadcastSubId(SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED, + subId); } } finally { @@ -2875,6 +2873,19 @@ public class SubscriptionManagerService extends ISub.Stub { } } + /** + * Broadcast a sub Id with the given action. + * @param action The intent action. + * @param newSubId The sub Id to broadcast. + */ + private void broadcastSubId(@NonNull String action, int newSubId) { + Intent intent = new Intent(action); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + SubscriptionManager.putSubscriptionIdExtra(intent, newSubId); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + log("broadcastSubId action: " + action + " subId= " + newSubId); + } + /** * Get the active subscription id list. * 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 51e760a053..3d0ce6ae97 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -55,6 +55,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -296,6 +297,17 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } + @Test + public void testBroadcastOnInitialization() { + ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); + verify(mContext, times(3)).sendBroadcastAsUser( + captorIntent.capture(), eq(UserHandle.ALL)); + assertThat(captorIntent.getAllValues().stream().map(Intent::getAction).toList()) + .containsExactly(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED, + TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED, + SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED); + } + @Test public void testAddSubInfo() { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); @@ -567,6 +579,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetDefaultVoiceSubId() throws Exception { + clearInvocations(mContext); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); @@ -584,7 +597,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION)).isEqualTo(1); ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); - verify(mContext, times(2)).sendStickyBroadcastAsUser( + verify(mContext, times(2)).sendBroadcastAsUser( captorIntent.capture(), eq(UserHandle.ALL)); Intent intent = captorIntent.getAllValues().get(0); @@ -608,6 +621,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetDefaultDataSubId() throws Exception { + clearInvocations(mContext); doReturn(false).when(mTelephonyManager).isVoiceCapable(); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); @@ -626,7 +640,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION)).isEqualTo(1); ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); - verify(mContext, times(2)).sendStickyBroadcastAsUser( + verify(mContext, times(2)).sendBroadcastAsUser( captorIntent.capture(), eq(UserHandle.ALL)); Intent intent = captorIntent.getAllValues().get(0); @@ -650,6 +664,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { @Test public void testSetDefaultSmsSubId() throws Exception { + clearInvocations(mContext); insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); @@ -666,7 +681,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION)).isEqualTo(1); ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); - verify(mContext).sendStickyBroadcastAsUser(captorIntent.capture(), eq(UserHandle.ALL)); + verify(mContext).sendBroadcastAsUser(captorIntent.capture(), eq(UserHandle.ALL)); Intent intent = captorIntent.getValue(); assertThat(intent.getAction()).isEqualTo( -- GitLab From 09e6ba44641c7a60e46a4d3462d1596ed2b5b52a Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 30 Mar 2023 13:52:32 -0700 Subject: [PATCH 568/656] Fixed inactive SIM removal not updated issue When removal an inactive SIM, the settings page was not updated properly. Also it's still inactive after re-insertion. Fixed by properly enabling the UICC application bit in the subscription when SIM is removal. Test: Manually deactivate the SIM and remove it. Test: atest SubscriptionManagerServiceTest Fix: 275048938 Change-Id: I84864f5b402941755a59dc1065f62aecd7af0056 --- .../SubscriptionManagerService.java | 26 +++++++++----- .../SubscriptionManagerServiceTest.java | 36 +++++++++++++++++++ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 8fdfabc0d4..3336e3568b 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1265,15 +1265,25 @@ public class SubscriptionManagerService extends ISub.Stub { } if (simState == TelephonyManager.SIM_STATE_ABSENT) { + // Re-enable the pSIM when it's removed, so it will be in enabled state when it gets + // re-inserted again. (pre-U behavior) + List iccIds = getIccIdsOfInsertedPhysicalSims(); + mSubscriptionDatabaseManager.getAllSubscriptions().stream() + // All the removed pSIMs (Note this could include some erased eSIM that has + // embedded bit removed). + .filter(subInfo -> !iccIds.contains(subInfo.getIccId()) + && !subInfo.isEmbedded()) + .forEach(subInfo -> { + int subId = subInfo.getSubscriptionId(); + log("updateSubscription: Re-enable Uicc application on sub " + subId); + mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, true); + // When sim is absent, set the port index to invalid port index. + // (pre-U behavior) + mSubscriptionDatabaseManager.setPortIndex(subId, + TelephonyManager.INVALID_PORT_INDEX); + }); + if (mSlotIndexToSubId.containsKey(phoneId)) { - int subId = mSlotIndexToSubId.get(phoneId); - // Re-enable the SIM when it's removed, so it will be in enabled state when it gets - // re-inserted again. (pre-U behavior) - log("updateSubscription: Re-enable Uicc application on sub " + subId); - mSubscriptionDatabaseManager.setUiccApplicationsEnabled(subId, true); - // When sim is absent, set the port index to invalid port index. (pre-U behavior) - mSubscriptionDatabaseManager.setPortIndex(subId, - TelephonyManager.INVALID_PORT_INDEX); markSubscriptionsInactive(phoneId); } } else if (simState == TelephonyManager.SIM_STATE_NOT_READY) { 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 51e760a053..a521bb9b9a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -103,6 +103,7 @@ import com.android.internal.telephony.euicc.EuiccController; import com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.SubscriptionProvider; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionMap; +import com.android.internal.telephony.uicc.IccCardStatus; import com.android.internal.telephony.uicc.UiccSlot; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; @@ -2195,4 +2196,39 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty(); } + + @Test + public void testInactiveSimRemoval() { + insertSubscription(FAKE_SUBSCRIPTION_INFO2); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + doReturn(FAKE_ICCID2).when(mUiccSlot).getIccId(0); + doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mUiccSlot).getCardState(); + + mSubscriptionManagerServiceUT.setUiccApplicationsEnabled(false, 1); + mSubscriptionManagerServiceUT.updateSimState( + 1, TelephonyManager.SIM_STATE_NOT_READY, null, null); + processAllMessages(); + + assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty(); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1) + .areUiccApplicationsEnabled()).isFalse(); + assertThat(mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE)).hasSize(1); + + // Now remove the SIM + doReturn(null).when(mUiccSlot).getIccId(0); + doReturn(IccCardStatus.CardState.CARDSTATE_ABSENT).when(mUiccSlot).getCardState(); + mSubscriptionManagerServiceUT.updateSimState( + 1, TelephonyManager.SIM_STATE_ABSENT, null, null); + processAllMessages(); + + assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty(); + // UICC should be re-enabled again for next re-insertion. + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1) + .areUiccApplicationsEnabled()).isTrue(); + assertThat(mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList( + CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); + } } -- GitLab From d449f565d394cbe51027f958338ed3ea94ac13fa Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Fri, 31 Mar 2023 06:21:18 +0000 Subject: [PATCH 569/656] Wrong subscription is getting cleared during slot switch If SLOT_STATUS is the last event, updateSimStateForInactivePort is getting called with wrong logical slot index which is already mapping to different slot-port pair. Tested use cases: 1. SS: pSIM <-> eSIM 2. DSDS: P+E <-> E+E Test: Manually verified on C10 Bug: 254388181 Change-Id: I2ba09ac3564b56b86a00308bd8da6e517ac1718a --- src/java/com/android/internal/telephony/uicc/UiccSlot.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index 8564f01e96..7f9936561e 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -373,6 +373,9 @@ public class UiccSlot extends Handler { } // no card present in the slot now; dispose port and then card if needed. disposeUiccCardIfNeeded(false /* sim state is not unknown */, portIndex); + // If SLOT_STATUS is the last event, wrong subscription is getting invalidate during + // slot switch event. To avoid it, reset the phoneId corresponding to the portIndex. + mPortIdxToPhoneId.put(portIndex, INVALID_PHONE_ID); mLastRadioState.put(portIndex, TelephonyManager.RADIO_POWER_UNAVAILABLE); } -- GitLab From 782c14eda6593c2e580e16120f746c83e554601a Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Fri, 24 Mar 2023 21:28:41 -0700 Subject: [PATCH 570/656] Add functionality to update satellite service package Bug: 274777761 Test: Call/SMS/MMS with live network. atest android.telephony.cts.SatelliteManagerTest atest android.telephony.satellite.cts.SatelliteManagerTestOnMockService Change-Id: I599ddffe02d21f1e6f6010c23241c13056b193d9 Merged-In: I599ddffe02d21f1e6f6010c23241c13056b193d9 --- .../telephony/satellite/DatagramReceiver.java | 5 ++ .../satellite/SatelliteController.java | 30 ++++++++++- .../satellite/SatelliteModemInterface.java | 54 +++++++++++++++++-- 3 files changed, 85 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 0ffffb3846..8ff96de0f9 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -442,6 +442,11 @@ public class DatagramReceiver extends Handler { SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, mDatagramController.getReceivePendingCount(), error); + mDatagramController.updateReceiveStatus(request.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + mDatagramController.getReceivePendingCount(), + SatelliteManager.SATELLITE_ERROR_NONE); + reportMetrics(null, error); mControllerMetricsStats.reportIncomingDatagramCount(error); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index dde94351a4..4107ad9cb4 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -201,7 +201,6 @@ public class SatelliteController extends Handler { // Create the SatelliteControllerMetrics to report controller metrics // should be called before making DatagramController - loge("mControllerMetricsStats = ControllerMetricsStats.make(mContext);"); mControllerMetricsStats = ControllerMetricsStats.make(mContext); mProvisionMetricsStats = ProvisionMetricsStats.getOrCreateInstance(); @@ -1407,6 +1406,35 @@ public class SatelliteController extends Handler { sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); } + /** + * This API can be used by only CTS to update satellite vendor service package name. + * + * @param servicePackageName The package name of the satellite vendor service. + * @return {@code true} if the satellite vendor service is set successfully, + * {@code false} otherwise. + */ + public boolean setSatelliteServicePackageName(@Nullable String servicePackageName) { + boolean result = mSatelliteModemInterface.setSatelliteServicePackageName( + servicePackageName); + if (result && (servicePackageName == null || servicePackageName.equals("null"))) { + /** + * mIsSatelliteSupported is set to true when running SatelliteManagerTestOnMockService. + * We need to set it to the actual state of the device. + */ + synchronized (mIsSatelliteSupportedLock) { + mIsSatelliteSupported = null; + } + ResultReceiver receiver = new ResultReceiver(this) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + logd("requestIsSatelliteSupported: resultCode=" + resultCode); + } + }; + requestIsSatelliteSupported(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, receiver); + } + return result; + } + /** * This function is used by {@link SatelliteModemInterface} to notify * {@link SatelliteController} that the satellite vendor service was just connected. diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index b59292b332..673e1c4523 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -24,12 +24,14 @@ import android.content.Intent; import android.content.ServiceConnection; import android.os.AsyncResult; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RegistrantList; import android.os.RemoteException; +import android.os.SystemProperties; import android.telephony.Rlog; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; @@ -55,7 +57,8 @@ import java.util.Arrays; */ public class SatelliteModemInterface { private static final String TAG = "SatelliteModemInterface"; - + private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; + private static final boolean DEBUG = !"user".equals(Build.TYPE); private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute private static final int REBIND_MULTIPLIER = 2; @@ -69,9 +72,10 @@ public class SatelliteModemInterface { /** * {@code true} to use the vendor satellite service and {@code false} to use the HAL. */ - private final boolean mIsSatelliteServiceSupported; + private boolean mIsSatelliteServiceSupported; @Nullable private ISatellite mSatelliteService; @Nullable private SatelliteServiceConnection mSatelliteServiceConnection; + @NonNull private String mVendorSatellitePackageName = ""; private boolean mIsBound; private boolean mIsBinding; @@ -133,7 +137,6 @@ public class SatelliteModemInterface { // keep previous state as this could be retrying sending or receiving break; } - // TODO: properly notify the rest of the datagram transfer state changed parameters mDatagramTransferStateChangedRegistrants.notifyResult(datagramTransferState); } }; @@ -206,6 +209,9 @@ public class SatelliteModemInterface { } @NonNull private String getSatellitePackageName() { + if (!TextUtils.isEmpty(mVendorSatellitePackageName)) { + return mVendorSatellitePackageName; + } return TextUtils.emptyIfNull(mContext.getResources().getString( R.string.config_satellite_service_package)); } @@ -235,6 +241,7 @@ public class SatelliteModemInterface { intent.setPackage(packageName); mSatelliteServiceConnection = new SatelliteServiceConnection(); + logd("Binding to " + packageName); try { boolean success = mContext.bindService( intent, mSatelliteServiceConnection, Context.BIND_AUTO_CREATE); @@ -963,6 +970,43 @@ public class SatelliteModemInterface { return mIsSatelliteServiceSupported; } + /** + * This API can be used by only CTS to update satellite vendor service package name. + * + * @param servicePackageName The package name of the satellite vendor service. + * @return {@code true} if the satellite vendor service is set successfully, + * {@code false} otherwise. + */ + boolean setSatelliteServicePackageName(@Nullable String servicePackageName) { + if (!shouldAllowModifyingSatelliteServicePackageName()) { + loge("setSatelliteServicePackageName: modifying satellite service package name " + + "is not allowed"); + return false; + } + + logd("setSatelliteServicePackageName: config_satellite_service_package is " + + "updated, new packageName=" + servicePackageName); + mExponentialBackoff.stop(); + if (mSatelliteServiceConnection != null) { + synchronized (mLock) { + mIsBound = false; + mIsBinding = false; + } + unbindService(); + } + + if (servicePackageName == null || servicePackageName.equals("null")) { + mVendorSatellitePackageName = ""; + } else { + mVendorSatellitePackageName = servicePackageName; + } + mIsSatelliteServiceSupported = getSatelliteServiceSupport(); + bindService(); + mExponentialBackoff.start(); + + return true; + } + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected static void sendMessageWithResult(@NonNull Message message, @Nullable Object result, @SatelliteManager.SatelliteError int error) { @@ -972,6 +1016,10 @@ public class SatelliteModemInterface { message.sendToTarget(); } + private boolean shouldAllowModifyingSatelliteServicePackageName() { + return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } -- GitLab From 46599f827167a663a9ca505cdc13e0cb9f3382f1 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Thu, 30 Mar 2023 01:40:14 +0000 Subject: [PATCH 571/656] Allow cellular modem scanning while satellite mode is on. - Adding a new Api to allow cellular modem while satellite mode is on BUG: b/276291624 Test: Test: Call/SMS with live network. atest QcomSatelliteServiceTest atest SatelliteSessionControllerTest atest android.telephony.cts.SatelliteManagerTest Change-Id: I5e26165a90c28988518939a193796684cd83ec70 --- .../satellite/SatelliteModemInterface.java | 38 +++++++++++++++++++ .../satellite/SatelliteSessionController.java | 10 +++++ 2 files changed, 48 insertions(+) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index cf2fc8593b..60bd8422fc 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -471,6 +471,44 @@ public class SatelliteModemInterface { } } + /** + * Allow cellular modem scanning while satellite mode is on. + * @param enabled {@code true} to enable cellular modem while satellite mode is on + * and {@code false} to disable + * @param message The Message to send to result of the operation to. + */ + public void enableCellularModemWhileSatelliteModeIsOn(boolean enabled, + @Nullable Message message) { + if (mSatelliteService != null) { + try { + mSatelliteService.enableCellularModemWhileSatelliteModeIsOn(enabled, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + int error = SatelliteServiceUtils.fromSatelliteError(result); + logd("enableCellularModemWhileSatelliteModeIsOn: " + error); + Binder.withCleanCallingIdentity(() -> { + if (message != null) { + sendMessageWithResult(message, null, error); + } + }); + } + }); + } catch (RemoteException e) { + loge("enableCellularModemWhileSatelliteModeIsOn: RemoteException " + e); + if (message != null) { + sendMessageWithResult( + message, null, SatelliteManager.SATELLITE_SERVICE_ERROR); + } + } + } else { + loge("enableCellularModemWhileSatelliteModeIsOn: Satellite service is unavailable."); + if (message != null) { + sendMessageWithResult(message, null, + SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); + } + } + } /** * Request to enable or disable the satellite modem and demo mode. If the satellite modem * is enabled, this may also disable the cellular modem, and if the satellite modem is disabled, diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index be252f4dcc..238d8e4a75 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -26,6 +26,7 @@ import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TR import android.annotation.NonNull; import android.content.Context; +import android.os.AsyncResult; import android.os.IBinder; import android.os.Looper; import android.os.Message; @@ -265,6 +266,8 @@ public class SatelliteSessionController extends StateMachine { if (DBG) logd("Entering IdleState"); mIsSendingTriggeredDuringTransferringState.set(false); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + //Disable Cellular Modem + mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(false, null); } @Override @@ -290,6 +293,13 @@ public class SatelliteSessionController extends StateMachine { transitionTo(mTransferringState); } } + + @Override + public void exit() { + if (DBG) logd("Exiting IdleState"); + //Enable Cellular Modem + mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(true, null); + } } private class TransferringState extends State { -- GitLab From 87a7992c5c1d317ef59b98db8da8f9de54880790 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Tue, 28 Mar 2023 22:00:17 +0000 Subject: [PATCH 572/656] DO NOT MERGE Changed provisionData type from string to byte[]. Bug: 275270448 Test: atest SatelliteManagerTest Change-Id: Id3d1616102ca34b5f7702c7c98a618d5ea6e0255 --- .../satellite/SatelliteController.java | 25 +++++++++++-------- .../satellite/SatelliteModemInterface.java | 6 ++--- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 4a882b021b..114bd0355d 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -259,14 +259,14 @@ public class SatelliteController extends Handler { private static final class ProvisionSatelliteServiceArgument { @NonNull public String token; - @NonNull public String regionId; + @NonNull public byte[] provisionData; @NonNull public Consumer callback; public int subId; - ProvisionSatelliteServiceArgument(String token, String regionId, Consumer callback, - int subId) { + ProvisionSatelliteServiceArgument(String token, byte[] provisionData, + Consumer callback, int subId) { this.token = token; - this.regionId = regionId; + this.provisionData = provisionData; this.callback = callback; this.subId = subId; } @@ -452,7 +452,7 @@ public class SatelliteController extends Handler { mProvisionMetricsStats.setProvisioningStartTime(); if (mSatelliteModemInterface.isSatelliteServiceSupported()) { mSatelliteModemInterface.provisionSatelliteService(argument.token, - argument.regionId, onCompleted); + argument.provisionData, onCompleted); break; } Phone phone = request.phone; @@ -1016,14 +1016,15 @@ public class SatelliteController extends Handler { * @param subId The subId of the subscription to be provisioned. * @param token The token to be used as a unique identifier for provisioning with satellite * gateway. - * @param regionId The region ID for the device's current location. + * @param provisionData Data from the provisioning app that can be used by provisioning server * @param callback The callback to get the error code of the request. * * @return The signal transport used by the caller to cancel the provision request, * or {@code null} if the request failed. */ @Nullable public ICancellationSignal provisionSatelliteService(int subId, - @NonNull String token, @NonNull String regionId, @NonNull IIntegerConsumer callback) { + @NonNull String token, @NonNull byte[] provisionData, + @NonNull IIntegerConsumer callback) { Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); if (!isSatelliteSupported()) { result.accept(SatelliteManager.SATELLITE_NOT_SUPPORTED); @@ -1044,13 +1045,14 @@ public class SatelliteController extends Handler { } sendRequestAsync(CMD_PROVISION_SATELLITE_SERVICE, - new ProvisionSatelliteServiceArgument(token, regionId, result, validSubId), phone); + new ProvisionSatelliteServiceArgument(token, provisionData, result, validSubId), + phone); ICancellationSignal cancelTransport = CancellationSignal.createTransport(); CancellationSignal.fromTransport(cancelTransport).setOnCancelListener(() -> { sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, - new ProvisionSatelliteServiceArgument(token, regionId, null, validSubId), - phone); + new ProvisionSatelliteServiceArgument(token, provisionData, null, + validSubId), phone); mProvisionMetricsStats.setIsCanceled(true); }); return cancelTransport; @@ -1083,7 +1085,8 @@ public class SatelliteController extends Handler { Phone phone = SatelliteServiceUtils.getPhone(); sendRequestAsync(CMD_DEPROVISION_SATELLITE_SERVICE, - new ProvisionSatelliteServiceArgument(token, null, result, validSubId), phone); + new ProvisionSatelliteServiceArgument(token, null, result, validSubId), + phone); } /** diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index cf2fc8593b..bd9859c0a6 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -676,14 +676,14 @@ public class SatelliteModemInterface { * * @param token The token to be used as a unique identifier for provisioning with satellite * gateway. - * @param regionId The region ID for the device's current location. + * @param provisionData Data from the provisioning app that can be used by provisioning server * @param message The Message to send to result of the operation to. */ - public void provisionSatelliteService(@NonNull String token, @NonNull String regionId, + public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData, @NonNull Message message) { if (mSatelliteService != null) { try { - mSatelliteService.provisionSatelliteService(token, regionId, + mSatelliteService.provisionSatelliteService(token, provisionData, new IIntegerConsumer.Stub() { @Override public void accept(int result) { -- GitLab From 850a1d54a1c282cadee20466c624104f0f0a3d5c Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Tue, 28 Mar 2023 20:28:04 +0000 Subject: [PATCH 573/656] DO NOT MERGE Change ILongConsumer to Consumer for onSatelliteDatagramReceived api. Bug: 275270448 Test: atest SatelliteManagerTest Change-Id: Ib71b4c76b4678f5a58cbff3ea596143aacb95738 --- .../satellite/DatagramController.java | 4 +- .../telephony/satellite/DatagramReceiver.java | 48 +++++++------------ .../satellite/SatelliteController.java | 4 +- 3 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 2fda0221af..3341595f46 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -132,8 +132,8 @@ public class DatagramController { * * This method requests modem to check if there are any pending datagrams to be received over * satellite. If there are any incoming datagrams, they will be received via - * {@link android.telephony.satellite.SatelliteDatagramCallback - * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ILongConsumer)} + * {@link android.telephony.satellite.SatelliteDatagramCallback#onSatelliteDatagramReceived( + * long, SatelliteDatagram, int, Consumer)} * * @param subId The subId of the subscription used for receiving datagrams. * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index c8401d255c..3ef9888165 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -43,7 +43,7 @@ import android.util.Pair; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.ILongConsumer; +import com.android.internal.telephony.IVoidConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.metrics.SatelliteStats; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; @@ -282,35 +282,23 @@ public class DatagramReceiver extends Handler { private void onSatelliteDatagramReceived(@NonNull DatagramRetryArgument argument) { try { + IVoidConsumer internalAck = new IVoidConsumer.Stub() { + /** + * This callback will be used by datagram receiver app + * to send ack back to Telephony. If the callback is not + * received within five minutes, then Telephony will + * resend the datagram again. + */ + @Override + public void accept() { + logd("acknowledgeSatelliteDatagramReceived: " + + "datagramId=" + argument.datagramId); + sendMessage(obtainMessage(EVENT_RECEIVED_ACK, argument)); + } + }; + argument.listener.onSatelliteDatagramReceived(argument.datagramId, - argument.datagram, argument.pendingCount, - new ILongConsumer.Stub() { - /** - * This callback will be used by datagram receiver app - * to send ack back to Telephony. If the callback is not - * received within five minutes, then Telephony will - * resend the datagram again. - * - * @param datagramId An id that uniquely identifies - * datagram received by satellite - * datagram receiver app. This should - * match with datagramId passed in - * {@link android.telephony.satellite - * .SatelliteDatagramCallback - * #onSatelliteDatagramReceived(long, - * SatelliteDatagram, int, - * ISatelliteDatagramReceiverAck)} - * Upon receiving the ack, Telephony - * will remove the datagram from - * the persistent memory. - */ - @Override - public void accept(long datagramId) { - logd("acknowledgeSatelliteDatagramReceived: " - + "datagramId=" + datagramId); - sendMessage(obtainMessage(EVENT_RECEIVED_ACK, argument)); - } - }); + argument.datagram, argument.pendingCount, internalAck); } catch (RemoteException e) { logd("EVENT_SATELLITE_DATAGRAM_RECEIVED RemoteException: " + e); } @@ -525,7 +513,7 @@ public class DatagramReceiver extends Handler { * This method requests modem to check if there are any pending datagrams to be received over * satellite. If there are any incoming datagrams, they will be received via * {@link android.telephony.satellite.SatelliteDatagramCallback - * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ILongConsumer)} + * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, Consumer)} * * @param subId The subId of the subscription used for receiving datagrams. * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 4a882b021b..9e68d2247b 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -1283,8 +1283,8 @@ public class SatelliteController extends Handler { * * This method requests modem to check if there are any pending datagrams to be received over * satellite. If there are any incoming datagrams, they will be received via - * {@link android.telephony.satellite.SatelliteDatagramCallback - * #onSatelliteDatagramReceived(long, SatelliteDatagram, int, ILongConsumer)} + * {@link android.telephony.satellite.SatelliteDatagramCallback#onSatelliteDatagramReceived( + * long, SatelliteDatagram, int, Consumer)} * * @param subId The subId of the subscription used for receiving datagrams. * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. -- GitLab From 1f936285588c2fea6978379567f4038e958ce0f5 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Sat, 1 Apr 2023 16:43:25 -0700 Subject: [PATCH 574/656] Support legacy cell broadcast fields Supported legacy cell broadcast settings in subscription manager. Fix: 273343840 Test: atest SubscriptionManagerServiceTest SubscriptionDatabaseManagerTest SubscriptionDatabaseManagerTest Change-Id: I76c0667651214df432b71a2d43acdcff4b2fac85 --- .../SubscriptionDatabaseManager.java | 282 ++++++++++- .../SubscriptionInfoInternal.java | 465 ++++++++++++++++-- .../SubscriptionManagerService.java | 12 + .../SubscriptionDatabaseManagerTest.java | 312 ++++++++++++ .../SubscriptionInfoInternalTest.java | 24 + 5 files changed, 1043 insertions(+), 52 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index dfc94cd5a8..38c2b1fb00 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -147,6 +147,42 @@ public class SubscriptionDatabaseManager extends Handler { new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_IS_REMOVABLE, SubscriptionInfoInternal::getRemovableEmbedded), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT, + SubscriptionInfoInternal::getCellBroadcastExtremeThreatAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT, + SubscriptionInfoInternal::getCellBroadcastSevereThreatAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_AMBER_ALERT, + SubscriptionInfoInternal::getCellBroadcastAmberAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_EMERGENCY_ALERT, + SubscriptionInfoInternal::getCellBroadcastEmergencyAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_ALERT_SOUND_DURATION, + SubscriptionInfoInternal::getCellBroadcastAlertSoundDuration), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL, + SubscriptionInfoInternal::getCellBroadcastAlertReminderInterval), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_ALERT_VIBRATE, + SubscriptionInfoInternal::getCellBroadcastAlertVibrationEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_ALERT_SPEECH, + SubscriptionInfoInternal::getCellBroadcastAlertSpeechEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_ETWS_TEST_ALERT, + SubscriptionInfoInternal::getCellBroadcastEtwsTestAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_CHANNEL_50_ALERT, + SubscriptionInfoInternal::getCellBroadcastAreaInfoMessageEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_CMAS_TEST_ALERT, + SubscriptionInfoInternal::getCellBroadcastTestAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_OPT_OUT_DIALOG, + SubscriptionInfoInternal::getCellBroadcastOptOutDialogEnabled), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, SubscriptionInfoInternal::getEnhanced4GModeEnabled), @@ -266,6 +302,42 @@ public class SubscriptionDatabaseManager extends Handler { new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_IS_REMOVABLE, SubscriptionDatabaseManager::setRemovableEmbedded), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT, + SubscriptionDatabaseManager::setCellBroadcastExtremeThreatAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT, + SubscriptionDatabaseManager::setCellBroadcastSevereThreatAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_AMBER_ALERT, + SubscriptionDatabaseManager::setCellBroadcastAmberAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_EMERGENCY_ALERT, + SubscriptionDatabaseManager::setCellBroadcastEmergencyAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_ALERT_SOUND_DURATION, + SubscriptionDatabaseManager::setCellBroadcastAlertSoundDuration), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL, + SubscriptionDatabaseManager::setCellBroadcastAlertReminderInterval), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_ALERT_VIBRATE, + SubscriptionDatabaseManager::setCellBroadcastAlertVibrationEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_ALERT_SPEECH, + SubscriptionDatabaseManager::setCellBroadcastAlertSpeechEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_ETWS_TEST_ALERT, + SubscriptionDatabaseManager::setCellBroadcastEtwsTestAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_CHANNEL_50_ALERT, + SubscriptionDatabaseManager::setCellBroadcastAreaInfoMessageEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_CMAS_TEST_ALERT, + SubscriptionDatabaseManager::setCellBroadcastTestAlertEnabled), + new AbstractMap.SimpleImmutableEntry<>( + SimInfo.COLUMN_CB_OPT_OUT_DIALOG, + SubscriptionDatabaseManager::setCellBroadcastOptOutDialogEnabled), new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, SubscriptionDatabaseManager::setEnhanced4GModeEnabled), @@ -449,18 +521,6 @@ public class SubscriptionDatabaseManager extends Handler { SimInfo.COLUMN_MCC, SimInfo.COLUMN_MNC, SimInfo.COLUMN_SIM_PROVISIONING_STATUS, - SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT, - SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT, - SimInfo.COLUMN_CB_AMBER_ALERT, - SimInfo.COLUMN_CB_EMERGENCY_ALERT, - SimInfo.COLUMN_CB_ALERT_SOUND_DURATION, - SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL, - SimInfo.COLUMN_CB_ALERT_VIBRATE, - SimInfo.COLUMN_CB_ALERT_SPEECH, - SimInfo.COLUMN_CB_ETWS_TEST_ALERT, - SimInfo.COLUMN_CB_CHANNEL_50_ALERT, - SimInfo.COLUMN_CB_CMAS_TEST_ALERT, - SimInfo.COLUMN_CB_OPT_OUT_DIALOG, SimInfo.COLUMN_IS_METERED, SimInfo.COLUMN_DATA_ENABLED_OVERRIDE_RULES, SimInfo.COLUMN_ALLOWED_NETWORK_TYPES @@ -1287,6 +1347,180 @@ public class SubscriptionDatabaseManager extends Handler { SubscriptionInfoInternal.Builder::setRemovableEmbedded); } + /** + * Set whether cell broadcast extreme threat alert is enabled by the user or not. + * + * @param subId Subscription id. + * @param isExtremeThreatAlertEnabled whether cell broadcast extreme threat alert is enabled by + * the user or not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastExtremeThreatAlertEnabled(int subId, + int isExtremeThreatAlertEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT, + isExtremeThreatAlertEnabled, + SubscriptionInfoInternal.Builder::setCellBroadcastExtremeThreatAlertEnabled); + } + + /** + * Set whether cell broadcast severe threat alert is enabled by the user or not. + * + * @param subId Subscription id. + * @param isSevereThreatAlertEnabled whether cell broadcast severe threat alert is enabled by + * the user or not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastSevereThreatAlertEnabled(int subId, + int isSevereThreatAlertEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT, + isSevereThreatAlertEnabled, + SubscriptionInfoInternal.Builder::setCellBroadcastSevereThreatAlertEnabled); + } + + /** + * Set whether cell broadcast amber alert is enabled by the user or not. + * + * @param subId Subscription id. + * @param isAmberAlertEnabled whether cell broadcast amber alert is enabled by + * the user or not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastAmberAlertEnabled(int subId, int isAmberAlertEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_AMBER_ALERT, isAmberAlertEnabled, + SubscriptionInfoInternal.Builder::setCellBroadcastAmberAlertEnabled); + } + + /** + * Set whether cell broadcast emergency alert is enabled by the user or not. + * + * @param subId Subscription id. + * @param isEmergencyAlertEnabled whether cell broadcast emergency alert is enabled by + * the user or not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastEmergencyAlertEnabled(int subId, + int isEmergencyAlertEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_EMERGENCY_ALERT, + isEmergencyAlertEnabled, + SubscriptionInfoInternal.Builder::setCellBroadcastEmergencyAlertEnabled); + } + + /** + * Set cell broadcast alert sound duration. + * + * @param subId Subscription id. + * @param alertSoundDuration Alert sound duration in seconds. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastAlertSoundDuration(int subId, int alertSoundDuration) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_SOUND_DURATION, + alertSoundDuration, + SubscriptionInfoInternal.Builder::setCellBroadcastAlertSoundDuration); + } + + /** + * Set cell broadcast alert reminder interval. + * + * @param subId Subscription id. + * @param reminderInterval Alert reminder interval in milliseconds. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastAlertReminderInterval(int subId, int reminderInterval) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL, + reminderInterval, + SubscriptionInfoInternal.Builder::setCellBroadcastAlertReminderInterval); + } + + /** + * Set whether cell broadcast alert vibration is enabled by the user or not. + * + * @param subId Subscription id. + * @param isAlertVibrationEnabled whether cell broadcast alert vibration is enabled by the user + * or not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastAlertVibrationEnabled(int subId, int isAlertVibrationEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_VIBRATE, isAlertVibrationEnabled, + SubscriptionInfoInternal.Builder::setCellBroadcastAlertVibrationEnabled); + } + + /** + * Set whether cell broadcast alert speech is enabled by the user or not. + * + * @param subId Subscription id. + * @param isAlertSpeechEnabled whether cell broadcast alert speech is enabled by the user or + * not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastAlertSpeechEnabled(int subId, int isAlertSpeechEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ALERT_SPEECH, isAlertSpeechEnabled, + SubscriptionInfoInternal.Builder::setCellBroadcastAlertSpeechEnabled); + } + + /** + * Set whether ETWS test alert is enabled by the user or not. + * + * @param subId Subscription id. + * @param isEtwsTestAlertEnabled whether cell broadcast ETWS test alert is enabled by the user + * or not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastEtwsTestAlertEnabled(int subId, int isEtwsTestAlertEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_ETWS_TEST_ALERT, + isEtwsTestAlertEnabled, + SubscriptionInfoInternal.Builder::setCellBroadcastEtwsTestAlertEnabled); + } + + /** + * Set whether area info message is enabled by the user or not. + * + * @param subId Subscription id. + * @param isAreaInfoMessageEnabled whether cell broadcast area info message is enabled by the + * user or not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastAreaInfoMessageEnabled(int subId, int isAreaInfoMessageEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_CHANNEL_50_ALERT, + isAreaInfoMessageEnabled, + SubscriptionInfoInternal.Builder::setCellBroadcastAreaInfoMessageEnabled); + } + + /** + * Set whether cell broadcast test alert is enabled by the user or not. + * + * @param subId Subscription id. + * @param isTestAlertEnabled whether cell broadcast test alert is enabled by the user or not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastTestAlertEnabled(int subId, int isTestAlertEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_CMAS_TEST_ALERT, isTestAlertEnabled, + SubscriptionInfoInternal.Builder::setCellBroadcastTestAlertEnabled); + } + + /** + * Set whether cell broadcast opt-out dialog should be shown or not. + * + * @param subId Subscription id. + * @param isOptOutDialogEnabled whether cell broadcast opt-out dialog should be shown or not. + * + * @throws IllegalArgumentException if the subscription does not exist. + */ + public void setCellBroadcastOptOutDialogEnabled(int subId, int isOptOutDialogEnabled) { + writeDatabaseAndCacheHelper(subId, SimInfo.COLUMN_CB_OPT_OUT_DIALOG, isOptOutDialogEnabled, + SubscriptionInfoInternal.Builder::setCellBroadcastOptOutDialogEnabled); + } + /** * Set whether enhanced 4G mode is enabled by the user or not. * @@ -1921,6 +2155,30 @@ public class SubscriptionDatabaseManager extends Handler { builder.setCardId(publicCardId) .setRemovableEmbedded(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_IS_REMOVABLE))) + .setCellBroadcastExtremeThreatAlertEnabled(cursor.getInt(cursor + .getColumnIndexOrThrow(SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT))) + .setCellBroadcastSevereThreatAlertEnabled(cursor.getInt(cursor + .getColumnIndexOrThrow(SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT))) + .setCellBroadcastAmberAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CB_AMBER_ALERT))) + .setCellBroadcastEmergencyAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CB_EMERGENCY_ALERT))) + .setCellBroadcastAlertSoundDuration(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CB_ALERT_SOUND_DURATION))) + .setCellBroadcastAlertReminderInterval(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL))) + .setCellBroadcastAlertVibrationEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CB_ALERT_VIBRATE))) + .setCellBroadcastAlertSpeechEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CB_ALERT_SPEECH))) + .setCellBroadcastEtwsTestAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CB_ETWS_TEST_ALERT))) + .setCellBroadcastAreaInfoMessageEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CB_CHANNEL_50_ALERT))) + .setCellBroadcastTestAlertEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CB_CMAS_TEST_ALERT))) + .setCellBroadcastOptOutDialogEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( + SimInfo.COLUMN_CB_OPT_OUT_DIALOG))) .setEnhanced4GModeEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED))) .setVideoTelephonyEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java index 9fcb453215..b917698998 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionInfoInternal.java @@ -190,6 +190,66 @@ public class SubscriptionInfoInternal { */ private final int mIsRemovableEmbedded; + /** + * Whether cell broadcast extreme threat alert is enabled by the user or not. + */ + private int mIsExtremeThreatAlertEnabled; + + /** + * Whether cell broadcast severe threat alert is enabled by the user or not. + */ + private int mIsSevereThreatAlertEnabled; + + /** + * Whether cell broadcast amber alert is enabled by the user or not. + */ + private int mIsAmberAlertEnabled; + + /** + * Whether cell broadcast emergency alert is enabled by the user or not. + */ + private int mIsEmergencyAlertEnabled; + + /** + * Cell broadcast alert sound duration in seconds. + */ + private int mAlertSoundDuration; + + /** + * Cell broadcast alert reminder interval in minutes. + */ + private int mReminderInterval; + + /** + * Whether cell broadcast alert vibration is enabled by the user or not. + */ + private int mIsAlertVibrationEnabled; + + /** + * Whether cell broadcast alert speech is enabled by the user or not. + */ + private int mIsAlertSpeechEnabled; + + /** + * Whether ETWS test alert is enabled by the user or not. + */ + private int mIsEtwsTestAlertEnabled; + + /** + * Whether area info message is enabled by the user or not. + */ + private int mIsAreaInfoMessageEnabled; + + /** + * Whether cell broadcast test alert is enabled by the user or not. + */ + private int mIsTestAlertEnabled; + + /** + * Whether cell broadcast opt-out dialog should be shown or not. + */ + private int mIsOptOutDialogEnabled; + /** * Whether enhanced 4G mode is enabled by the user or not. It is intended to use integer to fit * the database format. @@ -420,6 +480,18 @@ public class SubscriptionInfoInternal { this.mNativeAccessRules = builder.mNativeAccessRules; this.mCarrierConfigAccessRules = builder.mCarrierConfigAccessRules; this.mIsRemovableEmbedded = builder.mIsRemovableEmbedded; + this.mIsExtremeThreatAlertEnabled = builder.mIsExtremeThreatAlertEnabled; + this.mIsSevereThreatAlertEnabled = builder.mIsSevereThreatAlertEnabled; + this.mIsAmberAlertEnabled = builder.mIsAmberAlertEnabled; + this.mIsEmergencyAlertEnabled = builder.mIsEmergencyAlertEnabled; + this.mAlertSoundDuration = builder.mAlertSoundDuration; + this.mReminderInterval = builder.mReminderInterval; + this.mIsAlertVibrationEnabled = builder.mIsAlertVibrationEnabled; + this.mIsAlertSpeechEnabled = builder.mIsAlertSpeechEnabled; + this.mIsEtwsTestAlertEnabled = builder.mIsEtwsTestAlertEnabled; + this.mIsAreaInfoMessageEnabled = builder.mIsAreaInfoMessageEnabled; + this.mIsTestAlertEnabled = builder.mIsTestAlertEnabled; + this.mIsOptOutDialogEnabled = builder.mIsOptOutDialogEnabled; this.mIsEnhanced4GModeEnabled = builder.mIsEnhanced4GModeEnabled; this.mIsVideoTelephonyEnabled = builder.mIsVideoTelephonyEnabled; this.mIsWifiCallingEnabled = builder.mIsWifiCallingEnabled; @@ -618,8 +690,8 @@ public class SubscriptionInfoInternal { } /** - * @return {@code 1} if an embedded subscription is on a removable card. Such subscriptions are - * marked inaccessible as soon as the current card is removed. Otherwise, they will remain + * @return {@code true} if an embedded subscription is on a removable card. Such subscriptions + * are marked inaccessible as soon as the current card is removed. Otherwise, they will remain * accessible unless explicitly deleted. Only meaningful when {@link #getEmbedded()} is 1. */ public boolean isRemovableEmbedded() { @@ -635,6 +707,90 @@ public class SubscriptionInfoInternal { return mIsRemovableEmbedded; } + /** + * @return {@code 1} if cell broadcast extreme threat alert is enabled by the user. + */ + public int getCellBroadcastExtremeThreatAlertEnabled() { + return mIsExtremeThreatAlertEnabled; + } + + /** + * @return {@code 1} if cell broadcast amber alert is enabled by the user. + */ + public int getCellBroadcastSevereThreatAlertEnabled() { + return mIsSevereThreatAlertEnabled; + } + + /** + * @return {@code 1} if cell broadcast emergency alert is enabled by the user. + */ + public int getCellBroadcastAmberAlertEnabled() { + return mIsAmberAlertEnabled; + } + + /** + * @return {@code 1} if cell broadcast emergency alert is enabled by the user. + */ + public int getCellBroadcastEmergencyAlertEnabled() { + return mIsEmergencyAlertEnabled; + } + + /** + * @return {@code 1} if cell broadcast alert sound duration in seconds. + */ + public int getCellBroadcastAlertSoundDuration() { + return mAlertSoundDuration; + } + + /** + * @return Cell broadcast alert reminder interval in minutes. + */ + public int getCellBroadcastAlertReminderInterval() { + return mReminderInterval; + } + + /** + * @return {@code 1} if cell broadcast alert vibration is enabled by the user. + */ + public int getCellBroadcastAlertVibrationEnabled() { + return mIsAlertVibrationEnabled; + } + + /** + * @return {@code 1} if cell broadcast alert speech is enabled by the user. + */ + public int getCellBroadcastAlertSpeechEnabled() { + return mIsAlertSpeechEnabled; + } + + /** + * @return {@code 1} if ETWS test alert is enabled by the user. + */ + public int getCellBroadcastEtwsTestAlertEnabled() { + return mIsEtwsTestAlertEnabled; + } + + /** + * @return {@code 1} if area info message is enabled by the user. + */ + public int getCellBroadcastAreaInfoMessageEnabled() { + return mIsAreaInfoMessageEnabled; + } + + /** + * @return {@code 1} if cell broadcast test alert is enabled by the user. + */ + public int getCellBroadcastTestAlertEnabled() { + return mIsTestAlertEnabled; + } + + /** + * @return {@code 1} if cell broadcast opt-out dialog should be shown. + */ + public int getCellBroadcastOptOutDialogEnabled() { + return mIsOptOutDialogEnabled; + } + /** * @return {@code true} if enhanced 4G mode is enabled by the user or not. */ @@ -1044,26 +1200,6 @@ public class SubscriptionInfoInternal { .build(); } - /** - * Get ID stripped PII information on user build. - * - * @param id The PII id. - * - * @return The stripped string. - */ - public static String givePrintableId(String id) { - String idToPrint = null; - if (id != null) { - int len = id.length(); - if (len > 6 && !TelephonyUtils.IS_DEBUGGABLE) { - idToPrint = id.substring(0, len - 6) + Rlog.pii(false, id.substring(len - 6)); - } else { - idToPrint = id; - } - } - return idToPrint; - } - @Override public String toString() { return "[SubscriptionInfoInternal: id=" + mId @@ -1130,6 +1266,16 @@ public class SubscriptionInfoInternal { && mDisplayNameSource == that.mDisplayNameSource && mIconTint == that.mIconTint && mDataRoaming == that.mDataRoaming && mIsEmbedded == that.mIsEmbedded && mIsRemovableEmbedded == that.mIsRemovableEmbedded + && mIsExtremeThreatAlertEnabled == that.mIsExtremeThreatAlertEnabled + && mIsSevereThreatAlertEnabled == that.mIsSevereThreatAlertEnabled + && mIsAmberAlertEnabled == that.mIsAmberAlertEnabled + && mIsEmergencyAlertEnabled == that.mIsEmergencyAlertEnabled + && mAlertSoundDuration == that.mAlertSoundDuration + && mReminderInterval == that.mReminderInterval + && mIsAlertVibrationEnabled == that.mIsAlertVibrationEnabled + && mIsAlertSpeechEnabled == that.mIsAlertSpeechEnabled + && mIsEtwsTestAlertEnabled == that.mIsEtwsTestAlertEnabled + && mIsAreaInfoMessageEnabled == that.mIsAreaInfoMessageEnabled && mIsEnhanced4GModeEnabled == that.mIsEnhanced4GModeEnabled && mIsVideoTelephonyEnabled == that.mIsVideoTelephonyEnabled && mIsWifiCallingEnabled == that.mIsWifiCallingEnabled @@ -1147,31 +1293,33 @@ public class SubscriptionInfoInternal { && mIsNrAdvancedCallingEnabled == that.mIsNrAdvancedCallingEnabled && mPortIndex == that.mPortIndex && mUsageSetting == that.mUsageSetting && mLastUsedTPMessageReference == that.mLastUsedTPMessageReference - && mUserId == that.mUserId && mCardId == that.mCardId - && mIsGroupDisabled == that.mIsGroupDisabled && mIccId.equals(that.mIccId) - && mDisplayName.equals(that.mDisplayName) && mCarrierName.equals(that.mCarrierName) - && mNumber.equals(that.mNumber) && mMcc.equals(that.mMcc) && mMnc.equals(that.mMnc) - && mEhplmns.equals(that.mEhplmns) && mHplmns.equals(that.mHplmns) - && mCardString.equals( - that.mCardString) && Arrays.equals(mNativeAccessRules, - that.mNativeAccessRules) && Arrays.equals(mCarrierConfigAccessRules, - that.mCarrierConfigAccessRules) && mGroupUuid.equals(that.mGroupUuid) - && mCountryIso.equals(that.mCountryIso) && mGroupOwner.equals(that.mGroupOwner) - && mEnabledMobileDataPolicies.equals(that.mEnabledMobileDataPolicies) - && mImsi.equals( - that.mImsi) && Arrays.equals(mRcsConfig, that.mRcsConfig) - && mAllowedNetworkTypesForReasons.equals(that.mAllowedNetworkTypesForReasons) - && mDeviceToDeviceStatusSharingContacts.equals( + && mUserId == that.mUserId && mIsSatelliteEnabled == that.mIsSatelliteEnabled + && mCardId == that.mCardId && mIsGroupDisabled == that.mIsGroupDisabled + && mIccId.equals(that.mIccId) && mDisplayName.equals(that.mDisplayName) + && mCarrierName.equals(that.mCarrierName) && mNumber.equals(that.mNumber) + && mMcc.equals(that.mMcc) && mMnc.equals(that.mMnc) && mEhplmns.equals( + that.mEhplmns) + && mHplmns.equals(that.mHplmns) && mCardString.equals(that.mCardString) + && Arrays.equals(mNativeAccessRules, that.mNativeAccessRules) + && Arrays.equals(mCarrierConfigAccessRules, that.mCarrierConfigAccessRules) + && mGroupUuid.equals(that.mGroupUuid) && mCountryIso.equals(that.mCountryIso) + && mGroupOwner.equals(that.mGroupOwner) && mEnabledMobileDataPolicies.equals( + that.mEnabledMobileDataPolicies) && mImsi.equals(that.mImsi) && Arrays.equals( + mRcsConfig, that.mRcsConfig) && mAllowedNetworkTypesForReasons.equals( + that.mAllowedNetworkTypesForReasons) && mDeviceToDeviceStatusSharingContacts.equals( that.mDeviceToDeviceStatusSharingContacts) && mNumberFromCarrier.equals( - that.mNumberFromCarrier) && mNumberFromIms.equals(that.mNumberFromIms) - && mIsSatelliteEnabled == that.mIsSatelliteEnabled; + that.mNumberFromCarrier) && mNumberFromIms.equals(that.mNumberFromIms); } @Override public int hashCode() { int result = Objects.hash(mId, mIccId, mSimSlotIndex, mDisplayName, mCarrierName, mDisplayNameSource, mIconTint, mNumber, mDataRoaming, mMcc, mMnc, mEhplmns, mHplmns, - mIsEmbedded, mCardString, mIsRemovableEmbedded, mIsEnhanced4GModeEnabled, + mIsEmbedded, mCardString, mIsRemovableEmbedded, mIsExtremeThreatAlertEnabled, + mIsSevereThreatAlertEnabled, mIsAmberAlertEnabled, mIsEmergencyAlertEnabled, + mAlertSoundDuration, mReminderInterval, mIsAlertVibrationEnabled, + mIsAlertSpeechEnabled, + mIsEtwsTestAlertEnabled, mIsAreaInfoMessageEnabled, mIsEnhanced4GModeEnabled, mIsVideoTelephonyEnabled, mIsWifiCallingEnabled, mWifiCallingMode, mWifiCallingModeForRoaming, mIsWifiCallingEnabledForRoaming, mIsOpportunistic, mGroupUuid, mCountryIso, mCarrierId, mProfileClass, mType, mGroupOwner, @@ -1305,6 +1453,66 @@ public class SubscriptionInfoInternal { */ private int mIsRemovableEmbedded = 0; + /** + * Whether cell broadcast extreme threat alert is enabled by the user or not. + */ + private int mIsExtremeThreatAlertEnabled = 1; + + /** + * Whether cell broadcast severe threat alert is enabled by the user or not. + */ + private int mIsSevereThreatAlertEnabled = 1; + + /** + * Whether cell broadcast amber alert is enabled by the user or not. + */ + private int mIsAmberAlertEnabled = 1; + + /** + * Whether cell broadcast emergency alert is enabled by the user or not. + */ + private int mIsEmergencyAlertEnabled = 1; + + /** + * Cell broadcast alert sound duration in seconds. + */ + private int mAlertSoundDuration = 4; + + /** + * Cell broadcast alert reminder interval in minutes. + */ + private int mReminderInterval = 0; + + /** + * Whether cell broadcast alert vibration is enabled by the user or not. + */ + private int mIsAlertVibrationEnabled = 1; + + /** + * Whether cell broadcast alert speech is enabled by the user or not. + */ + private int mIsAlertSpeechEnabled = 1; + + /** + * Whether ETWS test alert is enabled by the user or not. + */ + private int mIsEtwsTestAlertEnabled = 0; + + /** + * Whether area info message is enabled by the user or not. + */ + private int mIsAreaInfoMessageEnabled = 1; + + /** + * Whether cell broadcast test alert is enabled by the user or not. + */ + private int mIsTestAlertEnabled = 0; + + /** + * Whether cell broadcast opt-out dialog should be shown or not. + */ + private int mIsOptOutDialogEnabled = 1; + /** * Whether enhanced 4G mode is enabled by the user or not. */ @@ -1528,6 +1736,18 @@ public class SubscriptionInfoInternal { mNativeAccessRules = info.mNativeAccessRules; mCarrierConfigAccessRules = info.mCarrierConfigAccessRules; mIsRemovableEmbedded = info.mIsRemovableEmbedded; + mIsExtremeThreatAlertEnabled = info.mIsExtremeThreatAlertEnabled; + mIsSevereThreatAlertEnabled = info.mIsSevereThreatAlertEnabled; + mIsAmberAlertEnabled = info.mIsAmberAlertEnabled; + mIsEmergencyAlertEnabled = info.mIsEmergencyAlertEnabled; + mAlertSoundDuration = info.mAlertSoundDuration; + mReminderInterval = info.mReminderInterval; + mIsAlertVibrationEnabled = info.mIsAlertVibrationEnabled; + mIsAlertSpeechEnabled = info.mIsAlertSpeechEnabled; + mIsEtwsTestAlertEnabled = info.mIsEtwsTestAlertEnabled; + mIsAreaInfoMessageEnabled = info.mIsAreaInfoMessageEnabled; + mIsTestAlertEnabled = info.mIsTestAlertEnabled; + mIsOptOutDialogEnabled = info.mIsOptOutDialogEnabled; mIsEnhanced4GModeEnabled = info.mIsEnhanced4GModeEnabled; mIsVideoTelephonyEnabled = info.mIsVideoTelephonyEnabled; mIsWifiCallingEnabled = info.mIsWifiCallingEnabled; @@ -1858,6 +2078,171 @@ public class SubscriptionInfoInternal { return this; } + /** + * Set whether cell broadcast extreme threat alert is enabled by the user or not. + * + * @param isExtremeThreatAlertEnabled whether cell broadcast extreme threat alert is enabled + * by the user or not. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastExtremeThreatAlertEnabled(int isExtremeThreatAlertEnabled) { + mIsExtremeThreatAlertEnabled = isExtremeThreatAlertEnabled; + return this; + } + + /** + * Set whether cell broadcast severe threat alert is enabled by the user or not. + * + * @param isSevereThreatAlertEnabled whether cell broadcast severe threat alert is enabled + * by the user or not. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastSevereThreatAlertEnabled(int isSevereThreatAlertEnabled) { + mIsSevereThreatAlertEnabled = isSevereThreatAlertEnabled; + return this; + } + + /** + * Set whether cell broadcast amber alert is enabled by the user or not. + * + * @param isAmberAlertEnabled whether cell broadcast amber alert is enabled by the user or + * not. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastAmberAlertEnabled(int isAmberAlertEnabled) { + mIsAmberAlertEnabled = isAmberAlertEnabled; + return this; + } + + /** + * Set whether cell broadcast emergency alert is enabled by the user or not. + * + * @param isEmergencyAlertEnabled whether cell broadcast emergency alert is enabled by the + * user or not. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastEmergencyAlertEnabled(int isEmergencyAlertEnabled) { + mIsEmergencyAlertEnabled = isEmergencyAlertEnabled; + return this; + } + + /** + * Set cell broadcast alert sound duration. + * + * @param alertSoundDuration Alert sound duration in seconds. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastAlertSoundDuration(int alertSoundDuration) { + mAlertSoundDuration = alertSoundDuration; + return this; + } + + /** + * Set cell broadcast alert reminder interval in minutes. + * + * @param reminderInterval Alert reminder interval in minutes. + * + * @return The builder. + */ + public Builder setCellBroadcastAlertReminderInterval(int reminderInterval) { + mReminderInterval = reminderInterval; + return this; + } + + /** + * Set whether cell broadcast alert vibration is enabled by the user or not. + * + * @param isAlertVibrationEnabled whether cell broadcast alert vibration is enabled by the + * user or not. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastAlertVibrationEnabled(int isAlertVibrationEnabled) { + mIsAlertVibrationEnabled = isAlertVibrationEnabled; + return this; + } + + /** + * Set whether cell broadcast alert speech is enabled by the user or not. + * + * @param isAlertSpeechEnabled whether cell broadcast alert speech is enabled by the user or + * not. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastAlertSpeechEnabled(int isAlertSpeechEnabled) { + mIsAlertSpeechEnabled = isAlertSpeechEnabled; + return this; + } + + /** + * Set whether ETWS test alert is enabled by the user or not. + * + * @param isEtwsTestAlertEnabled whether cell broadcast ETWS test alert is enabled by the + * user or not. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastEtwsTestAlertEnabled(int isEtwsTestAlertEnabled) { + mIsEtwsTestAlertEnabled = isEtwsTestAlertEnabled; + return this; + } + + /** + * Set whether area info message is enabled by the user or not. + * + * @param isAreaInfoMessageEnabled whether cell broadcast area info message is enabled by + * the user or not. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastAreaInfoMessageEnabled(int isAreaInfoMessageEnabled) { + mIsAreaInfoMessageEnabled = isAreaInfoMessageEnabled; + return this; + } + + /** + * Set whether cell broadcast test alert is enabled by the user or not. + * + * @param isTestAlertEnabled whether cell broadcast test alert is enabled by the user or + * not. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastTestAlertEnabled(int isTestAlertEnabled) { + mIsTestAlertEnabled = isTestAlertEnabled; + return this; + } + + /** + * Set whether cell broadcast opt-out dialog should be shown or not. + * + * @param isOptOutDialogEnabled whether cell broadcast opt-out dialog should be shown or + * not. + * + * @return The builder. + */ + @NonNull + public Builder setCellBroadcastOptOutDialogEnabled(int isOptOutDialogEnabled) { + mIsOptOutDialogEnabled = isOptOutDialogEnabled; + return this; + } + /** * Set whether enhanced 4G mode is enabled by the user or not. * diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 159a11c8a1..1f49b57bf1 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -146,6 +146,18 @@ public class SubscriptionManagerService extends ISub.Stub { * that requires higher permission to access. */ private static final Set DIRECT_ACCESS_SUBSCRIPTION_COLUMNS = Set.of( + SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT, + SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT, + SimInfo.COLUMN_CB_AMBER_ALERT, + SimInfo.COLUMN_CB_EMERGENCY_ALERT, + SimInfo.COLUMN_CB_ALERT_SOUND_DURATION, + SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL, + SimInfo.COLUMN_CB_ALERT_VIBRATE, + SimInfo.COLUMN_CB_ALERT_SPEECH, + SimInfo.COLUMN_CB_ETWS_TEST_ALERT, + SimInfo.COLUMN_CB_CHANNEL_50_ALERT, + SimInfo.COLUMN_CB_CMAS_TEST_ALERT, + SimInfo.COLUMN_CB_OPT_OUT_DIALOG, SimInfo.COLUMN_ENHANCED_4G_MODE_ENABLED, SimInfo.COLUMN_VT_IMS_ENABLED, SimInfo.COLUMN_WFC_IMS_ENABLED, 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 72603feeed..3a19b1bb59 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -140,6 +140,18 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setNativeAccessRules(FAKE_NATIVE_ACCESS_RULES1) .setCarrierConfigAccessRules(FAKE_CARRIER_CONFIG_ACCESS_RULES1) .setRemovableEmbedded(0) + .setCellBroadcastExtremeThreatAlertEnabled(1) + .setCellBroadcastSevereThreatAlertEnabled(1) + .setCellBroadcastAmberAlertEnabled(1) + .setCellBroadcastEmergencyAlertEnabled(1) + .setCellBroadcastAlertSoundDuration(4) + .setCellBroadcastAlertReminderInterval(1) + .setCellBroadcastAlertVibrationEnabled(1) + .setCellBroadcastAlertSpeechEnabled(1) + .setCellBroadcastEtwsTestAlertEnabled(1) + .setCellBroadcastAreaInfoMessageEnabled(1) + .setCellBroadcastTestAlertEnabled(1) + .setCellBroadcastOptOutDialogEnabled(1) .setEnhanced4GModeEnabled(1) .setVideoTelephonyEnabled(1) .setWifiCallingEnabled(1) @@ -196,6 +208,18 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .setNativeAccessRules(FAKE_NATIVE_ACCESS_RULES2) .setCarrierConfigAccessRules(FAKE_CARRIER_CONFIG_ACCESS_RULES2) .setRemovableEmbedded(1) + .setCellBroadcastExtremeThreatAlertEnabled(0) + .setCellBroadcastSevereThreatAlertEnabled(0) + .setCellBroadcastAmberAlertEnabled(0) + .setCellBroadcastEmergencyAlertEnabled(0) + .setCellBroadcastAlertSoundDuration(0) + .setCellBroadcastAlertReminderInterval(0) + .setCellBroadcastAlertVibrationEnabled(0) + .setCellBroadcastAlertSpeechEnabled(0) + .setCellBroadcastEtwsTestAlertEnabled(0) + .setCellBroadcastAreaInfoMessageEnabled(0) + .setCellBroadcastTestAlertEnabled(0) + .setCellBroadcastOptOutDialogEnabled(0) .setEnhanced4GModeEnabled(0) .setVideoTelephonyEnabled(0) .setWifiCallingEnabled(0) @@ -893,6 +917,294 @@ public class SubscriptionDatabaseManagerTest extends TelephonyTest { .isEqualTo(0); } + @Test + public void testUpdateCellBroadcastExtremeThreatAlertEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastExtremeThreatAlertEnabled(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastExtremeThreatAlertEnabled( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastExtremeThreatAlertEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_EXTREME_THREAT_ALERT, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastExtremeThreatAlertEnabled()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastSevereThreatAlertEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastSevereThreatAlertEnabled(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastSevereThreatAlertEnabled( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastSevereThreatAlertEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_SEVERE_THREAT_ALERT, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastSevereThreatAlertEnabled()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastAmberAlertEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastAmberAlertEnabled(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastAmberAlertEnabled( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastAmberAlertEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_AMBER_ALERT)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_AMBER_ALERT, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastAmberAlertEnabled()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastEmergencyAlertEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastEmergencyAlertEnabled(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastEmergencyAlertEnabled( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastEmergencyAlertEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_EMERGENCY_ALERT)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_EMERGENCY_ALERT, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastEmergencyAlertEnabled()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastAlertSoundDuration() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastAlertSoundDuration(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastAlertSoundDuration( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastAlertSoundDuration(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_ALERT_SOUND_DURATION)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_ALERT_SOUND_DURATION, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastAlertSoundDuration()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastAlertReminderInterval() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastAlertReminderInterval(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastAlertReminderInterval( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastAlertReminderInterval(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_ALERT_REMINDER_INTERVAL, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastAlertReminderInterval()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastAlertVibrationEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastAlertVibrationEnabled(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastAlertVibrationEnabled( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastAlertVibrationEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_ALERT_VIBRATE)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_ALERT_VIBRATE, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastAlertVibrationEnabled()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastAlertSpeechEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastAlertSpeechEnabled(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastAlertSpeechEnabled( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastAlertSpeechEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_ALERT_SPEECH)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_ALERT_SPEECH, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastAlertSpeechEnabled()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastEtwsTestAlertEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastEtwsTestAlertEnabled(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastEtwsTestAlertEnabled( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastEtwsTestAlertEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_ETWS_TEST_ALERT)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_ETWS_TEST_ALERT, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastEtwsTestAlertEnabled()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastAreaInfoMessageEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastAreaInfoMessageEnabled(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastAreaInfoMessageEnabled( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastAreaInfoMessageEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_CHANNEL_50_ALERT)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_CHANNEL_50_ALERT, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastAreaInfoMessageEnabled()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastTestAlertEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastTestAlertEnabled(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastTestAlertEnabled( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastTestAlertEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_CMAS_TEST_ALERT)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_CMAS_TEST_ALERT, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastTestAlertEnabled()).isEqualTo(1); + } + + @Test + public void testUpdateCellBroadcastOptOutDialogEnabled() throws Exception { + // exception is expected if there is nothing in the database. + assertThrows(IllegalArgumentException.class, + () -> mDatabaseManagerUT.setCellBroadcastOptOutDialogEnabled(1, 1)); + + SubscriptionInfoInternal subInfo = insertSubscriptionAndVerify(FAKE_SUBSCRIPTION_INFO1); + mDatabaseManagerUT.setCellBroadcastOptOutDialogEnabled( + subInfo.getSubscriptionId(), 0); + processAllMessages(); + + subInfo = new SubscriptionInfoInternal.Builder(subInfo) + .setCellBroadcastOptOutDialogEnabled(0).build(); + verifySubscription(subInfo); + verify(mSubscriptionDatabaseManagerCallback, times(2)).onSubscriptionChanged(eq(1)); + + assertThat(mDatabaseManagerUT.getSubscriptionProperty( + 1, SimInfo.COLUMN_CB_OPT_OUT_DIALOG)) + .isEqualTo(0); + mDatabaseManagerUT.setSubscriptionProperty(1, SimInfo.COLUMN_CB_OPT_OUT_DIALOG, 1); + assertThat(mDatabaseManagerUT.getSubscriptionInfoInternal(1) + .getCellBroadcastOptOutDialogEnabled()).isEqualTo(1); + } + @Test public void testUpdateEnhanced4GModeEnabled() throws Exception { // exception is expected if there is nothing in the database. diff --git a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java index 898901a8a9..e03256bb7a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionInfoInternalTest.java @@ -53,6 +53,18 @@ public class SubscriptionInfoInternalTest { .setCarrierConfigAccessRules(SubscriptionDatabaseManagerTest .FAKE_CARRIER_CONFIG_ACCESS_RULES1) .setRemovableEmbedded(0) + .setCellBroadcastExtremeThreatAlertEnabled(1) + .setCellBroadcastSevereThreatAlertEnabled(1) + .setCellBroadcastAmberAlertEnabled(1) + .setCellBroadcastEmergencyAlertEnabled(1) + .setCellBroadcastAlertSoundDuration(4) + .setCellBroadcastAlertReminderInterval(1) + .setCellBroadcastAlertVibrationEnabled(1) + .setCellBroadcastAlertSpeechEnabled(1) + .setCellBroadcastEtwsTestAlertEnabled(1) + .setCellBroadcastAreaInfoMessageEnabled(1) + .setCellBroadcastTestAlertEnabled(1) + .setCellBroadcastOptOutDialogEnabled(1) .setEnhanced4GModeEnabled(1) .setVideoTelephonyEnabled(1) .setWifiCallingEnabled(1) @@ -145,6 +157,18 @@ public class SubscriptionInfoInternalTest { assertThat(mSubInfo.getCarrierConfigAccessRules()).isEqualTo(SubscriptionDatabaseManagerTest .FAKE_CARRIER_CONFIG_ACCESS_RULES1); assertThat(mSubInfo.getRemovableEmbedded()).isEqualTo(0); + assertThat(mSubInfo.getCellBroadcastExtremeThreatAlertEnabled()).isEqualTo(1); + assertThat(mSubInfo.getCellBroadcastSevereThreatAlertEnabled()).isEqualTo(1); + assertThat(mSubInfo.getCellBroadcastAmberAlertEnabled()).isEqualTo(1); + assertThat(mSubInfo.getCellBroadcastEmergencyAlertEnabled()).isEqualTo(1); + assertThat(mSubInfo.getCellBroadcastAlertSoundDuration()).isEqualTo(4); + assertThat(mSubInfo.getCellBroadcastAlertReminderInterval()).isEqualTo(1); + assertThat(mSubInfo.getCellBroadcastAlertVibrationEnabled()).isEqualTo(1); + assertThat(mSubInfo.getCellBroadcastAlertSpeechEnabled()).isEqualTo(1); + assertThat(mSubInfo.getCellBroadcastEtwsTestAlertEnabled()).isEqualTo(1); + assertThat(mSubInfo.getCellBroadcastAreaInfoMessageEnabled()).isEqualTo(1); + assertThat(mSubInfo.getCellBroadcastTestAlertEnabled()).isEqualTo(1); + assertThat(mSubInfo.getCellBroadcastOptOutDialogEnabled()).isEqualTo(1); assertThat(mSubInfo.getEnhanced4GModeEnabled()).isEqualTo(1); assertThat(mSubInfo.getVideoTelephonyEnabled()).isEqualTo(1); assertThat(mSubInfo.getWifiCallingEnabled()).isEqualTo(1); -- GitLab From 4e70b668725881196b87ddac804632359339728a Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Mon, 3 Apr 2023 10:56:08 -0700 Subject: [PATCH 575/656] Clear cached states when ending SatelliteManagerTestOnMockService Bug: 276668803 Test: Run the following tests atest android.telephony.satellite.cts.SatelliteManagerTest -c atest android.telephony.satellite.cts.SatelliteManagerTestOnMockService -c Change-Id: Iee97c881efd55e94d52e89e98620cfbecd903e9b --- .../telephony/satellite/SatelliteController.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 5bcfc46bfe..af6d25f764 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -1421,12 +1421,22 @@ public class SatelliteController extends Handler { servicePackageName); if (result && (servicePackageName == null || servicePackageName.equals("null"))) { /** - * mIsSatelliteSupported is set to true when running SatelliteManagerTestOnMockService. - * We need to set it to the actual state of the device. + * Cached states like mIsSatelliteSupported and mIsSatelliteProvisioned are set to true + * when running SatelliteManagerTestOnMockService. We need to reset them to the actual + * states of the device. */ synchronized (mIsSatelliteSupportedLock) { mIsSatelliteSupported = null; } + synchronized (mIsSatelliteProvisionedLock) { + mIsSatelliteProvisioned = null; + } + synchronized (mIsSatelliteEnabledLock) { + mIsSatelliteEnabled = null; + } + synchronized (mSatelliteCapabilitiesLock) { + mSatelliteCapabilities = null; + } ResultReceiver receiver = new ResultReceiver(this) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { -- GitLab From b507272f5952e0e42b5d85ddc046f22b88146d08 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Mon, 3 Apr 2023 18:38:51 +0000 Subject: [PATCH 576/656] Close DB file after running unit tests. Bug: 276527828 Test: atest SatelliteProviderTest Change-Id: I189a909a769cb808ac415021dd7ed72b36d1e633 --- .../internal/telephony/satellite/DatagramReceiverTest.java | 1 + .../internal/telephony/satellite/FakeSatelliteProvider.java | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java index 67fcd1ee1a..9a67a698a8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java @@ -104,6 +104,7 @@ public class DatagramReceiverTest extends TelephonyTest { @After public void tearDown() throws Exception { logd(TAG + " tearDown"); + mFakeSatelliteProvider.shutdown(); mDatagramReceiverUT.destroy(); mDatagramReceiverUT = null; mResultListener = null; diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/FakeSatelliteProvider.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/FakeSatelliteProvider.java index 637b48505c..b0c6a819d3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/FakeSatelliteProvider.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/FakeSatelliteProvider.java @@ -95,4 +95,9 @@ public class FakeSatelliteProvider extends MockContentProvider { // Do nothing. return 0; } + + @Override + public void shutdown() { + mDbHelper.close(); + } } -- GitLab From 3f6f5dc58dde47ac6447b67f613cff9818689d03 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Mon, 27 Mar 2023 16:22:00 -0700 Subject: [PATCH 577/656] Use tearDown reason in dataCall metrics Test: voice call+data browsing Bug: 219585426 Change-Id: Iebd20f0d2044a0d7d0b6a478eab2cc4062bb8b6e --- .../internal/telephony/data/DataNetwork.java | 2 +- .../metrics/DataCallSessionStats.java | 32 ++++--------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index ce46f10114..16504c52a5 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -2586,7 +2586,7 @@ public class DataNetwork extends StateMachine { reason == TEAR_DOWN_REASON_AIRPLANE_MODE_ON ? DataService.REQUEST_REASON_SHUTDOWN : DataService.REQUEST_REASON_NORMAL, obtainMessage(EVENT_DEACTIVATE_DATA_NETWORK_RESPONSE)); - mDataCallSessionStats.setDeactivateDataCallReason(DataService.REQUEST_REASON_NORMAL); + mDataCallSessionStats.setDeactivateDataCallReason(reason); mInvokedDataDeactivation = true; } diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java index 6c711a9e85..21ec32ed9b 100644 --- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java @@ -16,10 +16,6 @@ package com.android.internal.telephony.metrics; -import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION__DEACTIVATE_REASON__DEACTIVATE_REASON_HANDOVER; -import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION__DEACTIVATE_REASON__DEACTIVATE_REASON_NORMAL; -import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION__DEACTIVATE_REASON__DEACTIVATE_REASON_RADIO_OFF; -import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION__DEACTIVATE_REASON__DEACTIVATE_REASON_UNKNOWN; import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION__IP_TYPE__APN_PROTOCOL_IPV4; import android.annotation.Nullable; @@ -36,13 +32,13 @@ import android.telephony.data.ApnSetting; import android.telephony.data.ApnSetting.ProtocolType; import android.telephony.data.DataCallResponse; import android.telephony.data.DataService; -import android.telephony.data.DataService.DeactivateDataReason; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SubscriptionController; +import com.android.internal.telephony.data.DataNetwork; import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; @@ -128,33 +124,17 @@ public class DataCallSessionStats { /** * Updates the dataCall atom when data call is deactivated. * - * @param reason Deactivate reason + * @param reason Tear down reason */ - public synchronized void setDeactivateDataCallReason(@DeactivateDataReason int reason) { + public synchronized void setDeactivateDataCallReason(@DataNetwork.TearDownReason int reason) { // there should've been another call to initiate the atom, // so this method is being called out of order -> no metric will be logged if (mDataCallSession == null) { loge("setDeactivateDataCallReason: no DataCallSession atom has been initiated."); return; } - switch (reason) { - case DataService.REQUEST_REASON_NORMAL: - mDataCallSession.deactivateReason = - DATA_CALL_SESSION__DEACTIVATE_REASON__DEACTIVATE_REASON_NORMAL; - break; - case DataService.REQUEST_REASON_SHUTDOWN: - mDataCallSession.deactivateReason = - DATA_CALL_SESSION__DEACTIVATE_REASON__DEACTIVATE_REASON_RADIO_OFF; - break; - case DataService.REQUEST_REASON_HANDOVER: - mDataCallSession.deactivateReason = - DATA_CALL_SESSION__DEACTIVATE_REASON__DEACTIVATE_REASON_HANDOVER; - break; - default: - mDataCallSession.deactivateReason = - DATA_CALL_SESSION__DEACTIVATE_REASON__DEACTIVATE_REASON_UNKNOWN; - break; - } + // Skip the pre-U enum. See enum DataDeactivateReasonEnum in enums.proto + mDataCallSession.deactivateReason = reason + DataService.REQUEST_REASON_HANDOVER + 1; } /** @@ -333,7 +313,7 @@ public class DataCallSessionStats { proto.setupFailed = false; proto.failureCause = DataFailCause.NONE; proto.suggestedRetryMillis = 0; - proto.deactivateReason = DATA_CALL_SESSION__DEACTIVATE_REASON__DEACTIVATE_REASON_UNKNOWN; + proto.deactivateReason = DataNetwork.TEAR_DOWN_REASON_NONE; proto.durationMinutes = 0; proto.ongoing = true; proto.handoverFailureCauses = new int[0]; -- GitLab From fc0b85666feb7e6949302d15ee77a977013c47c8 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 4 Apr 2023 15:46:55 -0700 Subject: [PATCH 578/656] Fixed eSIM subscription disappeared Fixed an issue that after eSIM profile update failed, the original eSIM subscription got marked as non-embedded so it disappeared from settings. Fix: 276707965 Test: atest SubscriptionManagerServiceTest Test: Basic phone functionality tests Change-Id: I77dfddf70022e4337298c6fe183879c0150b9f57 --- .../SubscriptionManagerService.java | 63 +++++++++++-------- .../SubscriptionManagerServiceTest.java | 48 ++++++++++++-- 2 files changed, 81 insertions(+), 30 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 1f49b57bf1..204cda00ab 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1050,6 +1050,9 @@ public class SubscriptionManagerService extends ISub.Stub { } } + // The flag indicating getting successful result from EuiccController. + boolean isProfileUpdateSuccessful = false; + for (int cardId : cardIds) { GetEuiccProfileInfoListResult result = mEuiccController .blockingGetEuiccProfileInfoList(cardId); @@ -1066,6 +1069,8 @@ public class SubscriptionManagerService extends ISub.Stub { continue; } + isProfileUpdateSuccessful = true; + if (result.getProfiles() == null || result.getProfiles().isEmpty()) { loge("No profiles returned."); continue; @@ -1137,32 +1142,38 @@ public class SubscriptionManagerService extends ISub.Stub { } } - // embeddedSubs contains all the existing embedded subs queried from EuiccManager, - // including active or inactive. If there are any embedded subscription in the database - // that is not in embeddedSubs, mark them as non-embedded. These were deleted embedded - // subscriptions, so we treated them as non-embedded (pre-U behavior) and they don't - // show up in Settings SIM page. - mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(SubscriptionInfoInternal::isEmbedded) - .filter(subInfo -> !embeddedSubs.contains(subInfo.getSubscriptionId())) - .forEach(subInfo -> { - logl("updateEmbeddedSubscriptions: Mark the deleted sub " - + subInfo.getSubscriptionId() + " as non-embedded."); - mSubscriptionDatabaseManager.setEmbedded( - subInfo.getSubscriptionId(), false); - }); - if (mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .anyMatch(subInfo -> subInfo.isEmbedded() - && subInfo.isActive() - && subInfo.getPortIndex() - == TelephonyManager.INVALID_PORT_INDEX - && mSimState[subInfo.getSimSlotIndex()] - == TelephonyManager.SIM_STATE_LOADED)) { - //Report Anomaly if invalid portIndex is updated in Active subscriptions - AnomalyReporter.reportAnomaly( - UUID.fromString("38fdf63c-3bd9-4fc2-ad33-a20246a32fa7"), - "SubscriptionManagerService: Found Invalid portIndex" - + " in active subscriptions"); + // Marked the previous embedded subscriptions non-embedded if the latest profiles do + // not include them anymore. + if (isProfileUpdateSuccessful) { + // embeddedSubs contains all the existing embedded subs queried from EuiccManager, + // including active or inactive. If there are any embedded subscription in the + // database that is not in embeddedSubs, mark them as non-embedded. These were + // deleted embedded subscriptions, so we treated them as non-embedded (pre-U + // behavior) and they don't show up in Settings SIM page. + mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isEmbedded) + .filter(subInfo -> !embeddedSubs.contains(subInfo.getSubscriptionId())) + .forEach(subInfo -> { + logl("updateEmbeddedSubscriptions: Mark the deleted sub " + + subInfo.getSubscriptionId() + " as non-embedded."); + mSubscriptionDatabaseManager.setEmbedded( + subInfo.getSubscriptionId(), false); + }); + if (mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .anyMatch(subInfo -> subInfo.isEmbedded() + && subInfo.isActive() + && subInfo.getPortIndex() + == TelephonyManager.INVALID_PORT_INDEX + && mSimState[subInfo.getSimSlotIndex()] + == TelephonyManager.SIM_STATE_LOADED)) { + //Report Anomaly if invalid portIndex is updated in Active subscriptions + AnomalyReporter.reportAnomaly( + UUID.fromString("38fdf63c-3bd9-4fc2-ad33-a20246a32fa7"), + "SubscriptionManagerService: Found Invalid portIndex" + + " in active subscriptions"); + } + } else { + loge("The eSIM profiles update was not successful."); } }); log("updateEmbeddedSubscriptions: Finished embedded subscription update."); 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 cbab5b56ab..2674e1d2ba 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -183,6 +183,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(FAKE_ICCID1).when(mUiccCard).getCardId(); doReturn(FAKE_ICCID1).when(mUiccPort).getIccId(); doReturn(true).when(mUiccSlot).isActive(); + doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1)); + doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(2)); doReturn(new int[0]).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); @@ -799,8 +801,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { result = new GetEuiccProfileInfoListResult(EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo2}, false); doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(2)); - doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1)); - doReturn(FAKE_ICCID2).when(mUiccController).convertToCardString(eq(2)); doReturn(TelephonyManager.INVALID_PORT_INDEX).when(mUiccSlot) .getPortIndexFromIccId(anyString()); @@ -1810,7 +1810,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { GetEuiccProfileInfoListResult result = new GetEuiccProfileInfoListResult( EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo1}, false); doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); - doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1)); mContext.sendBroadcast(new Intent(Intent.ACTION_USER_UNLOCKED)); processAllMessages(); @@ -1937,7 +1936,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { GetEuiccProfileInfoListResult result = new GetEuiccProfileInfoListResult( EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo1}, false); doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); - doReturn(FAKE_ICCID1).when(mUiccController).convertToCardString(eq(1)); mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); processAllMessages(); @@ -2246,4 +2244,46 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.getAvailableSubscriptionInfoList( CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); } + + @Test + public void testEmbeddedProfilesUpdateFailed() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + GetEuiccProfileInfoListResult result = new GetEuiccProfileInfoListResult( + EuiccService.RESULT_MUST_DEACTIVATE_SIM, null, false); + doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); + + mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); + processAllMessages(); + + // The existing subscription should not be altered if the previous update failed. + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(1)) + .isEqualTo(FAKE_SUBSCRIPTION_INFO1); + + EuiccProfileInfo profileInfo = new EuiccProfileInfo.Builder(FAKE_ICCID2) + .setIccid(FAKE_ICCID2) + .setNickname(FAKE_CARRIER_NAME2) + .setProfileClass(SubscriptionManager.PROFILE_CLASS_OPERATIONAL) + .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC2, FAKE_MNC2, null, 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[]{profileInfo}, false); + doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); + + // Update for the 2nd time. + mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); + processAllMessages(); + + // The previous subscription should be marked as non-embedded. + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(1).isEmbedded()) + .isEqualTo(false); + + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).getIccId()) + .isEqualTo(FAKE_ICCID2); + assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isEmbedded()) + .isEqualTo(true); + } } -- GitLab From df0a2d91a5b901170bc0182a1f6a20b9fea15709 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Tue, 4 Apr 2023 03:32:09 +0000 Subject: [PATCH 579/656] Modified to check the Modem version for getImei Bug: 274497949 Test: verified atest RILTest Change-Id: Ie9c7265b8bec0c5bf0eed3d14607aa4a6416ff39 Merged-In: Ie9c7265b8bec0c5bf0eed3d14607aa4a6416ff39 --- src/java/com/android/internal/telephony/RIL.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 3987fb9986..dafb0dac15 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -3737,7 +3737,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void getImei(Message result) { RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); if (!modemProxy.isEmpty() && - mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + mHalVersion.get(HAL_SERVICE_MODEM).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_DEVICE_IMEI, result, mRILDefaultWorkSource); -- GitLab From 10d6af1894028ebab5eff59a4257e73994537dbb Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Thu, 6 Apr 2023 21:10:37 -0700 Subject: [PATCH 580/656] Support updating satellite listening timeout duration from CTS Bug: 276762737 Test: Call/SMS/MMS with live network. atest android.telephony.satellite.cts.SatelliteManagerTestOnMockService atest android.telephony.satellite.cts.SatelliteManagerTest Change-Id: Ia2bbec5f52c0cee87785bafeb640a1708a074ada --- .../satellite/SatelliteController.java | 24 ++++++++--- .../satellite/SatelliteSessionController.java | 41 +++++++++++++++++-- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index af6d25f764..975eb22758 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -1419,12 +1419,8 @@ public class SatelliteController extends Handler { public boolean setSatelliteServicePackageName(@Nullable String servicePackageName) { boolean result = mSatelliteModemInterface.setSatelliteServicePackageName( servicePackageName); - if (result && (servicePackageName == null || servicePackageName.equals("null"))) { - /** - * Cached states like mIsSatelliteSupported and mIsSatelliteProvisioned are set to true - * when running SatelliteManagerTestOnMockService. We need to reset them to the actual - * states of the device. - */ + if (result) { + // Cached states need to be cleared whenever switching satellite vendor services. synchronized (mIsSatelliteSupportedLock) { mIsSatelliteSupported = null; } @@ -1448,6 +1444,22 @@ public class SatelliteController extends Handler { return result; } + /** + * This API can be used by only CTS to update the timeout duration in milliseconds that + * satellite should stay at listening mode to wait for the next incoming page before disabling + * listening mode. + * + * @param timeoutMillis The timeout duration in millisecond. + * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. + */ + public boolean setSatelliteListeningTimeoutDuration(long timeoutMillis) { + if (mSatelliteSessionController == null) { + loge("mSatelliteSessionController is not initialized yet"); + return false; + } + return mSatelliteSessionController.setSatelliteListeningTimeoutDuration(timeoutMillis); + } + /** * This function is used by {@link SatelliteModemInterface} to notify * {@link SatelliteController} that the satellite vendor service was just connected. diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index eabb769a5e..ea7681b0cd 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -26,11 +26,12 @@ import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TR import android.annotation.NonNull; import android.content.Context; -import android.os.AsyncResult; +import android.os.Build; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.SystemProperties; import android.provider.DeviceConfig; import android.telephony.Rlog; import android.telephony.satellite.ISatelliteStateCallback; @@ -53,6 +54,8 @@ import java.util.concurrent.atomic.AtomicBoolean; public class SatelliteSessionController extends StateMachine { private static final String TAG = "SatelliteSessionController"; private static final boolean DBG = true; + private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; + private static final boolean DEBUG = !"user".equals(Build.TYPE); /** * The time duration in millis that the satellite will stay at listening mode to wait for the @@ -90,8 +93,8 @@ public class SatelliteSessionController extends StateMachine { @NonNull private final ListeningState mListeningState = new ListeningState(); @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected AtomicBoolean mIsSendingTriggeredDuringTransferringState; - private final long mSatelliteStayAtListeningFromSendingMillis; - private final long mSatelliteStayAtListeningFromReceivingMillis; + private long mSatelliteStayAtListeningFromSendingMillis; + private long mSatelliteStayAtListeningFromReceivingMillis; private final ConcurrentHashMap mListeners; @SatelliteManager.SatelliteModemState private int mCurrentState; final boolean mIsSatelliteSupported; @@ -223,6 +226,34 @@ public class SatelliteSessionController extends StateMachine { mListeners.remove(callback.asBinder()); } + /** + * This API can be used by only CTS to update the timeout duration in milliseconds that + * satellite should stay at listening mode to wait for the next incoming page before disabling + * listening mode. + * + * @param timeoutMillis The timeout duration in millisecond. + * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. + */ + boolean setSatelliteListeningTimeoutDuration(long timeoutMillis) { + if (!isMockModemAllowed()) { + loge("Updating listening timeout duration is not allowed"); + return false; + } + + logd("setSatelliteListeningTimeoutDuration: timeoutMillis=" + timeoutMillis); + if (timeoutMillis == 0) { + mSatelliteStayAtListeningFromSendingMillis = + getSatelliteStayAtListeningFromSendingMillis(); + mSatelliteStayAtListeningFromReceivingMillis = + getSatelliteStayAtListeningFromReceivingMillis(); + } else { + mSatelliteStayAtListeningFromSendingMillis = timeoutMillis; + mSatelliteStayAtListeningFromReceivingMillis = timeoutMillis; + } + + return true; + } + private static class DatagramTransferState { @SatelliteManager.SatelliteDatagramTransferState public int sendState; @SatelliteManager.SatelliteDatagramTransferState public int receiveState; @@ -481,6 +512,10 @@ public class SatelliteSessionController extends StateMachine { || receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE); } + private boolean isMockModemAllowed() { + return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); + } + private static long getSatelliteStayAtListeningFromSendingMillis() { return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS, -- GitLab From c8818f07d0e2010ba16f3777f5036565154e2f22 Mon Sep 17 00:00:00 2001 From: Jonggeon Kim Date: Fri, 7 Apr 2023 09:01:26 +0000 Subject: [PATCH 581/656] Sync with carrier config naming changing Sync with carrier config naming changing Bug: 265109622 Test: atest FrameworksTelephonyTests Change-Id: I75b33248ac3f44f4392a6f8b040f9008b8fb02f6 --- .../imsphone/ImsNrSaModeHandler.java | 41 ++++++++++--------- .../imsphone/ImsNrSaModeHandlerTest.java | 33 +++++++-------- 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsNrSaModeHandler.java b/src/java/com/android/internal/telephony/imsphone/ImsNrSaModeHandler.java index b54a97371a..3dedde83be 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsNrSaModeHandler.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsNrSaModeHandler.java @@ -17,12 +17,12 @@ package com.android.internal.telephony.imsphone; import static android.telephony.CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA; -import static android.telephony.CarrierConfigManager.Ims.KEY_SA_DISABLE_POLICY_INT; +import static android.telephony.CarrierConfigManager.Ims.KEY_NR_SA_DISABLE_POLICY_INT; +import static android.telephony.CarrierConfigManager.Ims.NR_SA_DISABLE_POLICY_NONE; +import static android.telephony.CarrierConfigManager.Ims.NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED; +import static android.telephony.CarrierConfigManager.Ims.NR_SA_DISABLE_POLICY_WFC_ESTABLISHED; +import static android.telephony.CarrierConfigManager.Ims.NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED; import static android.telephony.CarrierConfigManager.Ims.NrSaDisablePolicy; -import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_NONE; -import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_VOWIFI_REGISTERED; -import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED; -import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED; import static android.telephony.CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY; import static android.telephony.ims.stub.ImsRegistrationImplBase.ImsRegistrationTech; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; @@ -100,7 +100,7 @@ public class ImsNrSaModeHandler extends Handler{ */ public void onImsRegistered( @ImsRegistrationTech int imsRadioTech, @NonNull Set featureTags) { - if (mNrSaDisablePolicy == SA_DISABLE_POLICY_NONE) { + if (mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_NONE) { return; } @@ -118,12 +118,13 @@ public class ImsNrSaModeHandler extends Handler{ } if (isVowifiRegChanged) { - if (mNrSaDisablePolicy == SA_DISABLE_POLICY_VOWIFI_REGISTERED) { + if (mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED) { setNrSaMode(!isVowifiRegistered()); - } else if ((mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED - || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) + } else if ((mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_WFC_ESTABLISHED + || mNrSaDisablePolicy + == NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) && isImsCallOngoing()) { - if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { + if (mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { requestIsVonrEnabled(!isVowifiRegistered()); return; } @@ -140,7 +141,7 @@ public class ImsNrSaModeHandler extends Handler{ */ public void onImsUnregistered( @ImsRegistrationTech int imsRadioTech) { - if (mNrSaDisablePolicy == SA_DISABLE_POLICY_NONE + if (mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_NONE || imsRadioTech != REGISTRATION_TECH_IWLAN || !isVowifiRegistered()) { return; } @@ -149,12 +150,12 @@ public class ImsNrSaModeHandler extends Handler{ setVowifiRegStatus(false); - if (mNrSaDisablePolicy == SA_DISABLE_POLICY_VOWIFI_REGISTERED) { + if (mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED) { setNrSaMode(true); - } else if ((mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED - || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) + } else if ((mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_WFC_ESTABLISHED + || mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) && isImsCallOngoing()) { - if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { + if (mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { requestIsVonrEnabled(true); return; } @@ -182,7 +183,7 @@ public class ImsNrSaModeHandler extends Handler{ } if (isVowifiRegistered() && isImsCallStatusChanged) { - if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { + if (mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED) { requestIsVonrEnabled(!isImsCallOngoing()); return; } @@ -260,8 +261,8 @@ public class ImsNrSaModeHandler extends Handler{ private void setNrSaDisablePolicy(int subId) { if (mPhone.getSubId() == subId && mCarrierConfigManager != null) { PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId(), - KEY_SA_DISABLE_POLICY_INT, KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); - mNrSaDisablePolicy = bundle.getInt(KEY_SA_DISABLE_POLICY_INT); + KEY_NR_SA_DISABLE_POLICY_INT, KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); + mNrSaDisablePolicy = bundle.getInt(KEY_NR_SA_DISABLE_POLICY_INT); mIsNrSaSupported = Arrays.stream( bundle.getIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY)).anyMatch( value -> value == CARRIER_NR_AVAILABILITY_SA); @@ -269,8 +270,8 @@ public class ImsNrSaModeHandler extends Handler{ Log.d(TAG, "setNrSaDisablePolicy : NrSaDisablePolicy = " + mNrSaDisablePolicy + ", IsNrSaSupported = " + mIsNrSaSupported); - if (mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED - || mNrSaDisablePolicy == SA_DISABLE_POLICY_WFC_ESTABLISHED) { + if (mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED + || mNrSaDisablePolicy == NR_SA_DISABLE_POLICY_WFC_ESTABLISHED) { registerForPreciseCallStateChanges(); } else { unregisterForPreciseCallStateChanges(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsNrSaModeHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsNrSaModeHandlerTest.java index 217dfb8eaf..7d6557dc3c 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsNrSaModeHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsNrSaModeHandlerTest.java @@ -18,11 +18,11 @@ package com.android.internal.telephony.imsphone; import static android.telephony.CarrierConfigManager.CARRIER_NR_AVAILABILITY_NSA; import static android.telephony.CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA; -import static android.telephony.CarrierConfigManager.Ims.KEY_SA_DISABLE_POLICY_INT; -import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_NONE; -import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_VOWIFI_REGISTERED; -import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED; -import static android.telephony.CarrierConfigManager.Ims.SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED; +import static android.telephony.CarrierConfigManager.Ims.KEY_NR_SA_DISABLE_POLICY_INT; +import static android.telephony.CarrierConfigManager.Ims.NR_SA_DISABLE_POLICY_NONE; +import static android.telephony.CarrierConfigManager.Ims.NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED; +import static android.telephony.CarrierConfigManager.Ims.NR_SA_DISABLE_POLICY_WFC_ESTABLISHED; +import static android.telephony.CarrierConfigManager.Ims.NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED; import static android.telephony.CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; @@ -108,7 +108,7 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ @Test public void testTearDown() { mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED); + KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_WFC_ESTABLISHED); mContextFixture.getCarrierConfigBundle().putIntArray( KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); @@ -131,7 +131,7 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ @Test public void testOnImsRegisteredWithSaDisablePolicyNone() { mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_NONE); + KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_NONE); mContextFixture.getCarrierConfigBundle().putIntArray( KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); @@ -147,7 +147,7 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ @Test public void testOnImsRegisteredWithSaDisablePolicyWfcEstablished() { mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED); + KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_WFC_ESTABLISHED); mContextFixture.getCarrierConfigBundle().putIntArray( KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); @@ -168,7 +168,8 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ @Test public void testOnImsRegisteredWithSaDisablePolicyWfcEstablishedWithVonrDisabled() { mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED); + KEY_NR_SA_DISABLE_POLICY_INT, + NR_SA_DISABLE_POLICY_WFC_ESTABLISHED_WHEN_VONR_DISABLED); mContextFixture.getCarrierConfigBundle().putIntArray( KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); @@ -226,7 +227,7 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ @Test public void testOnImsRegisteredWithSaDisablePolicyVowifiRegistered() { mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_VOWIFI_REGISTERED); + KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED); mContextFixture.getCarrierConfigBundle().putIntArray( KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); @@ -252,7 +253,7 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ @Test public void testOnImsUnregisteredDoNothingIfNotVowifiRegNoti() { mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_VOWIFI_REGISTERED); + KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED); mContextFixture.getCarrierConfigBundle().putIntArray( KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); @@ -268,7 +269,7 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ @Test public void testOnImsUnregisteredWithSaDisablePolicyVowifiRegistered() { mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_VOWIFI_REGISTERED); + KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED); mContextFixture.getCarrierConfigBundle().putIntArray( KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); @@ -294,7 +295,7 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ @Test public void testOnPreciseCallStateChangedWithSaDisablePolicyWfcEstablished() { mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED); + KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_WFC_ESTABLISHED); mContextFixture.getCarrierConfigBundle().putIntArray( KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); @@ -345,7 +346,7 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ @Test public void testUnregisterForPreciseCallStateChangeIfNeeded() { mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED); + KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_WFC_ESTABLISHED); mContextFixture.getCarrierConfigBundle().putIntArray( KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_SA}); @@ -356,7 +357,7 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ mPreciseCallStateHandler = mPreciseCallStateHandlerCaptor.getValue(); mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_VOWIFI_REGISTERED); + KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_VOWIFI_REGISTERED); mCarrierConfigChangeListener.onCarrierConfigChanged(mAnyInt, mAnyInt, mAnyInt, mAnyInt); @@ -366,7 +367,7 @@ public final class ImsNrSaModeHandlerTest extends TelephonyTest{ @Test public void testNrSaModeIsNotHandledWhenNotSupported() { mContextFixture.getCarrierConfigBundle().putInt( - KEY_SA_DISABLE_POLICY_INT, SA_DISABLE_POLICY_WFC_ESTABLISHED); + KEY_NR_SA_DISABLE_POLICY_INT, NR_SA_DISABLE_POLICY_WFC_ESTABLISHED); mContextFixture.getCarrierConfigBundle().putIntArray( KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, new int[]{CARRIER_NR_AVAILABILITY_NSA}); -- GitLab From 3c199c211f8d51c9459c19b7cfd4cd87b60fe612 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Thu, 6 Apr 2023 19:56:50 -0700 Subject: [PATCH 582/656] Use proper satellite error codes Bug: 277277221 Test: Call/SMS/MMS. atest android.telephony.satellite.cts.SatelliteManagerTestOnMockService atest android.telephony.satellite.cts.SatelliteManagerTest Change-Id: I60a4cdb68d2cf04eb0e004bb2dfe9a8e370c0176 --- .../satellite/SatelliteModemInterface.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 1cad3b5d59..4d5e75de81 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -480,7 +480,7 @@ public class SatelliteModemInterface { loge("requestSatelliteListeningEnabled: Satellite service is unavailable."); if (message != null) { sendMessageWithResult(message, null, - SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } } @@ -552,7 +552,7 @@ public class SatelliteModemInterface { } } else { loge("setSatelliteEnabled: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -589,7 +589,7 @@ public class SatelliteModemInterface { } } else { loge("requestIsSatelliteEnabled: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -661,7 +661,7 @@ public class SatelliteModemInterface { } } else { loge("requestSatelliteCapabilities: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -690,7 +690,7 @@ public class SatelliteModemInterface { } } else { loge("startSendingSatellitePointingInfo: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -718,7 +718,7 @@ public class SatelliteModemInterface { } } else { loge("stopSendingSatellitePointingInfo: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -752,7 +752,7 @@ public class SatelliteModemInterface { } } else { loge("provisionSatelliteService: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -782,7 +782,7 @@ public class SatelliteModemInterface { } } else { loge("deprovisionSatelliteService: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -819,7 +819,7 @@ public class SatelliteModemInterface { } } else { loge("requestIsSatelliteProvisioned: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -848,7 +848,7 @@ public class SatelliteModemInterface { } } else { loge("pollPendingSatelliteDatagrams: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -882,7 +882,7 @@ public class SatelliteModemInterface { } } else { loge("sendSatelliteDatagram: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -920,7 +920,7 @@ public class SatelliteModemInterface { } } else { loge("requestSatelliteModemState: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -959,7 +959,7 @@ public class SatelliteModemInterface { } else { loge("requestIsSatelliteCommunicationAllowedForCurrentLocation: " + "Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } @@ -1000,7 +1000,7 @@ public class SatelliteModemInterface { } } else { loge("requestTimeForNextSatelliteVisibility: Satellite service is unavailable."); - sendMessageWithResult(message, null, SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED); + sendMessageWithResult(message, null, SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE); } } -- GitLab From 4b141ef038a8b4e98be27099d1938fc57425386e Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Mon, 10 Apr 2023 01:11:47 +0000 Subject: [PATCH 583/656] Enable cellular scanning when in Idle state - Cellular scanning is enabled when modem state is in Idle state Bug: b/277521632 Test: atest QcomSatelliteServiceTest atest SatelliteSessionControllerTest atest android.telephony.satellite.cts.SatelliteManagerTestOnMockService Change-Id: I5cdd3fbcd6036196bf59e8b117061ea6982da5cc --- .../telephony/satellite/SatelliteSessionController.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index ea7681b0cd..bb8a5af78a 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -313,9 +313,9 @@ public class SatelliteSessionController extends StateMachine { if (DBG) logd("Entering IdleState"); mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_IDLE; mIsSendingTriggeredDuringTransferringState.set(false); + //Enable Cellular Modem scanning + mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(true, null); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_IDLE); - //Disable Cellular Modem - mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(false, null); } @Override @@ -345,8 +345,8 @@ public class SatelliteSessionController extends StateMachine { @Override public void exit() { if (DBG) logd("Exiting IdleState"); - //Enable Cellular Modem - mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(true, null); + //Disable Cellular Modem Scanning + mSatelliteModemInterface.enableCellularModemWhileSatelliteModeIsOn(false, null); } } -- GitLab From 0bfdbaff5a8388764889d49fdcdb2acae40f1df7 Mon Sep 17 00:00:00 2001 From: Sergio Rodriguez Orama Date: Mon, 10 Apr 2023 17:14:08 +0000 Subject: [PATCH 584/656] Revert "[MEP] Enable iccCloseLogicalChannelWithSessionInfo API" This reverts commit 2936844811e4f28afcfab96d3f15393de3e73e85. Reason for revert: b/274860626 Change-Id: Ib5dda2efb1a07313f98dd03e4e71e4df3f865519 --- .../android/internal/telephony/RadioSimProxy.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/RadioSimProxy.java b/src/java/com/android/internal/telephony/RadioSimProxy.java index 7c8ee7b6ea..d9aba9c44d 100644 --- a/src/java/com/android/internal/telephony/RadioSimProxy.java +++ b/src/java/com/android/internal/telephony/RadioSimProxy.java @@ -283,11 +283,14 @@ public class RadioSimProxy extends RadioServiceProxy { if (isEmpty()) return; if (isAidl()) { if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_2_1)) { - android.hardware.radio.sim.SessionInfo info = - new android.hardware.radio.sim.SessionInfo(); - info.sessionId = channelId; - info.isEs10 = isEs10; - mSimProxy.iccCloseLogicalChannelWithSessionInfo(serial, info); + // TODO: [MEP-A1] Use iccCloseLogicalChannelWithSessionInfo API once vendor + // changes are completed. + //android.hardware.radio.sim.SessionInfo info = + // new android.hardware.radio.sim.SessionInfo(); + //info.sessionId = channelId; + //info.isEs10 = isEs10; + //mSimProxy.iccCloseLogicalChannelWithSessionInfo(serial, info); + mSimProxy.iccCloseLogicalChannel(serial, channelId); return; } mSimProxy.iccCloseLogicalChannel(serial, channelId); -- GitLab From 6aeea996df6d1338b85a99175f88d659ea152ab6 Mon Sep 17 00:00:00 2001 From: Saloni Date: Tue, 28 Mar 2023 16:06:08 +0000 Subject: [PATCH 585/656] Added Changes relates to AntennaPosition Bug: 275577029 Test: atest SatelliteCapabilitiesTest, atest AntennaPositionTest, atest AntennaDirectionTest Flashed on raven, sms and calls are working Change-Id: I2f85929fe9900e4ed509ee42d9ef50226e305843 Merged-In: I2f85929fe9900e4ed509ee42d9ef50226e305843 --- .../satellite/SatelliteServiceUtils.java | 17 ++- .../satellite/AntennaDirectionTest.java | 52 +++++++ .../satellite/AntennaPositionTest.java | 60 ++++++++ .../satellite/SatelliteCapabilitiesTest.java | 134 ++++++++++++++++++ 4 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/satellite/AntennaDirectionTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/satellite/AntennaPositionTest.java create mode 100644 tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteCapabilitiesTest.java diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java index 2ed35b32f8..e5e0620405 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java @@ -23,6 +23,7 @@ import android.os.AsyncResult; import android.os.Binder; import android.telephony.Rlog; import android.telephony.SubscriptionManager; +import android.telephony.satellite.AntennaPosition; import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; @@ -39,6 +40,8 @@ import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.subscription.SubscriptionManagerService; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.stream.Collectors; /** @@ -157,11 +160,23 @@ public class SatelliteServiceUtils { if (capabilities == null) return null; int[] radioTechnologies = capabilities.supportedRadioTechnologies == null ? new int[0] : capabilities.supportedRadioTechnologies; + + Map antennaPositionMap = new HashMap<>(); + int[] antennaPositionKeys = capabilities.antennaPositionKeys; + AntennaPosition[] antennaPositionValues = capabilities.antennaPositionValues; + if (antennaPositionKeys != null && antennaPositionValues != null && + antennaPositionKeys.length == antennaPositionValues.length) { + for(int i = 0; i < antennaPositionKeys.length; i++) { + antennaPositionMap.put(antennaPositionKeys[i], antennaPositionValues[i]); + } + } + return new SatelliteCapabilities( Arrays.stream(radioTechnologies) .map(SatelliteServiceUtils::fromSatelliteRadioTechnology) .boxed().collect(Collectors.toSet()), - capabilities.isPointingRequired, capabilities.maxBytesPerOutgoingDatagram); + capabilities.isPointingRequired, capabilities.maxBytesPerOutgoingDatagram, + antennaPositionMap); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/AntennaDirectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/AntennaDirectionTest.java new file mode 100644 index 0000000000..6a91d95651 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/AntennaDirectionTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 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 static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.os.Parcel; +import android.telephony.satellite.AntennaDirection; + +import org.junit.Test; + +public class AntennaDirectionTest { + + @Test + public void testParcel() { + AntennaDirection antennaDirection = new AntennaDirection(1, 2, 3); + + Parcel p = Parcel.obtain(); + antennaDirection.writeToParcel(p, 0); + p.setDataPosition(0); + + AntennaDirection fromParcel = AntennaDirection.CREATOR.createFromParcel(p); + assertThat(antennaDirection).isEqualTo(fromParcel); + } + + @Test + public void testEquals() { + AntennaDirection antennaDirection1 = new AntennaDirection(1.12f, 1.13f, 1.14f); + AntennaDirection antennaDirection2 = new AntennaDirection(1.12f, 1.13f, 1.14f); + assertEquals(antennaDirection1, antennaDirection2); + + AntennaDirection antennaDirection3 = new AntennaDirection(1.121f, 1.131f, 1.141f); + assertNotEquals(antennaDirection1, antennaDirection3); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/AntennaPositionTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/AntennaPositionTest.java new file mode 100644 index 0000000000..919ab83f40 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/AntennaPositionTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2023 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 static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.os.Parcel; +import android.telephony.satellite.AntennaDirection; +import android.telephony.satellite.AntennaPosition; +import android.telephony.satellite.SatelliteManager; + +import org.junit.Test; + +public class AntennaPositionTest { + + private AntennaDirection mAntennaDirection = new AntennaDirection(1,1,1); + + @Test + public void testParcel() { + AntennaPosition antennaPosition = new AntennaPosition(mAntennaDirection, + SatelliteManager.DEVICE_HOLD_POSITION_PORTRAIT); + + Parcel p = Parcel.obtain(); + antennaPosition.writeToParcel(p, 0); + p.setDataPosition(0); + + AntennaPosition fromParcel = AntennaPosition.CREATOR.createFromParcel(p); + assertThat(antennaPosition).isEqualTo(fromParcel); + } + + @Test + public void testEquals() { + AntennaPosition antennaPosition1 = new AntennaPosition(mAntennaDirection, + SatelliteManager.DEVICE_HOLD_POSITION_PORTRAIT); + AntennaPosition antennaPosition2 = new AntennaPosition(mAntennaDirection, + SatelliteManager.DEVICE_HOLD_POSITION_PORTRAIT); + assertEquals(antennaPosition1, antennaPosition2); + + AntennaPosition antennaPosition3 = new AntennaPosition(mAntennaDirection, + SatelliteManager.DEVICE_HOLD_POSITION_LANDSCAPE_LEFT); + assertNotEquals(antennaPosition1, antennaPosition3); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteCapabilitiesTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteCapabilitiesTest.java new file mode 100644 index 0000000000..29473c9787 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteCapabilitiesTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2023 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 static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.os.Parcel; +import android.telephony.satellite.AntennaDirection; +import android.telephony.satellite.AntennaPosition; +import android.telephony.satellite.SatelliteCapabilities; +import android.telephony.satellite.SatelliteManager; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class SatelliteCapabilitiesTest { + + private AntennaDirection mAntennaDirection = new AntennaDirection(1,1,1); + + @Test + public void testParcel() { + Set satelliteRadioTechnologies = new HashSet<>(); + satelliteRadioTechnologies.add(SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN); + satelliteRadioTechnologies.add(SatelliteManager.NT_RADIO_TECHNOLOGY_NR_NTN); + + Map antennaPositionMap = new HashMap<>(); + AntennaPosition antennaPosition = new AntennaPosition(mAntennaDirection, + SatelliteManager.DEVICE_HOLD_POSITION_PORTRAIT); + antennaPositionMap.put(SatelliteManager.DISPLAY_MODE_OPENED, antennaPosition); + + SatelliteCapabilities capabilities = new SatelliteCapabilities(satelliteRadioTechnologies, + true, 10, antennaPositionMap); + + Parcel p = Parcel.obtain(); + capabilities.writeToParcel(p, 0); + p.setDataPosition(0); + + SatelliteCapabilities fromParcel = SatelliteCapabilities.CREATOR.createFromParcel(p); + assertThat(capabilities).isEqualTo(fromParcel); + } + + @Test + public void testParcel_emptySatelliteRadioTechnologies() { + Set satelliteRadioTechnologies = new HashSet<>(); + + Map antennaPositionMap = new HashMap<>(); + AntennaPosition antennaPosition1 = new AntennaPosition(mAntennaDirection, + SatelliteManager.DEVICE_HOLD_POSITION_PORTRAIT); + AntennaPosition antennaPosition2 = new AntennaPosition(mAntennaDirection, + SatelliteManager.DEVICE_HOLD_POSITION_LANDSCAPE_LEFT); + antennaPositionMap.put(SatelliteManager.DISPLAY_MODE_OPENED, antennaPosition1); + antennaPositionMap.put(SatelliteManager.DISPLAY_MODE_CLOSED, antennaPosition2); + + SatelliteCapabilities capabilities = new SatelliteCapabilities(satelliteRadioTechnologies, + false, 100, antennaPositionMap); + + Parcel p = Parcel.obtain(); + capabilities.writeToParcel(p, 0); + p.setDataPosition(0); + + SatelliteCapabilities fromParcel = SatelliteCapabilities.CREATOR.createFromParcel(p); + assertThat(capabilities).isEqualTo(fromParcel); + } + + + @Test + public void testParcel_emptyAntennaPosition() { + Set satelliteRadioTechnologies = new HashSet<>(); + satelliteRadioTechnologies.add(SatelliteManager.NT_RADIO_TECHNOLOGY_EMTC_NTN); + + SatelliteCapabilities capabilities = new SatelliteCapabilities(satelliteRadioTechnologies, + true, 0, new HashMap<>()); + + Parcel p = Parcel.obtain(); + capabilities.writeToParcel(p, 0); + p.setDataPosition(0); + + SatelliteCapabilities fromParcel = SatelliteCapabilities.CREATOR.createFromParcel(p); + assertThat(capabilities).isEqualTo(fromParcel); + } + + @Test + public void testEquals() { + Set satelliteRadioTechnologies = new HashSet<>(); + satelliteRadioTechnologies.add(SatelliteManager.NT_RADIO_TECHNOLOGY_NB_IOT_NTN); + satelliteRadioTechnologies.add(SatelliteManager.NT_RADIO_TECHNOLOGY_NR_NTN); + + AntennaPosition antennaPosition1 = new AntennaPosition(mAntennaDirection, + SatelliteManager.DEVICE_HOLD_POSITION_PORTRAIT); + AntennaPosition antennaPosition2 = new AntennaPosition(mAntennaDirection, + SatelliteManager.DEVICE_HOLD_POSITION_LANDSCAPE_LEFT); + + Map antennaPositionMap1 = new HashMap<>(); + antennaPositionMap1.put(SatelliteManager.DISPLAY_MODE_OPENED, antennaPosition1); + antennaPositionMap1.put(SatelliteManager.DISPLAY_MODE_CLOSED, antennaPosition2); + + SatelliteCapabilities satelliteCapabilities1 = + new SatelliteCapabilities(satelliteRadioTechnologies, true, 10, + antennaPositionMap1); + SatelliteCapabilities satelliteCapabilities2 = + new SatelliteCapabilities(satelliteRadioTechnologies, true, 10, + antennaPositionMap1); + assertEquals(satelliteCapabilities1, satelliteCapabilities2); + + Map antennaPositionMap2 = new HashMap<>(); + antennaPositionMap2.put(SatelliteManager.DISPLAY_MODE_CLOSED, antennaPosition1); + antennaPositionMap2.put(SatelliteManager.DISPLAY_MODE_OPENED, antennaPosition2); + satelliteCapabilities2 = + new SatelliteCapabilities(satelliteRadioTechnologies, true, 10, + antennaPositionMap2); + assertNotEquals(satelliteCapabilities1, satelliteCapabilities2); + } +} -- GitLab From 9f08bae4543160792dfc5317544e35cc58783bb9 Mon Sep 17 00:00:00 2001 From: Kiwon Park Date: Fri, 3 Feb 2023 12:54:13 -0800 Subject: [PATCH 586/656] Collect VoNR enabled metrics Bug: 232140817 Test: inspect atoms Change-Id: Ib938ecfb4d4dfd111cac19fcf0ec251d0a41becf Merged-In: Ib938ecfb4d4dfd111cac19fcf0ec251d0a41becf --- .../telephony/metrics/MetricsCollector.java | 3 ++- .../telephony/metrics/PerSimStatus.java | 20 +++++++++++++++++-- .../telephony/metrics/PerSimStatusTest.java | 9 +++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 0e68224335..7546124697 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -769,7 +769,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { perSimStatus.pin1Enabled, // isPin1Enabled perSimStatus.minimumVoltageClass, // simVoltageClass perSimStatus.userModifiedApnTypes, // userModifiedApnTypeBitmask - perSimStatus.unmeteredNetworks); // unmeteredNetworks + perSimStatus.unmeteredNetworks, // unmeteredNetworks + perSimStatus.vonrEnabled); // vonrEnabled data.add(statsEvent); result = StatsManager.PULL_SUCCESS; } diff --git a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java index 0b5581515f..ba43a8426d 100644 --- a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java +++ b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java @@ -76,6 +76,7 @@ public class PerSimStatus { public final int minimumVoltageClass; public final int userModifiedApnTypes; public final long unmeteredNetworks; + public final boolean vonrEnabled; /** Returns the current sim status of the given {@link Phone}. */ @Nullable @@ -107,7 +108,8 @@ public class PerSimStatus { iccCard == null ? false : iccCard.getIccLockEnabled(), getMinimumVoltageClass(phone), getUserModifiedApnTypes(phone), - persistAtomsStorage.getUnmeteredNetworks(phone.getPhoneId(), carrierId)); + persistAtomsStorage.getUnmeteredNetworks(phone.getPhoneId(), carrierId), + isVonrEnabled(phone)); } private PerSimStatus( @@ -126,7 +128,8 @@ public class PerSimStatus { boolean pin1Enabled, int minimumVoltageClass, int userModifiedApnTypes, - long unmeteredNetworks) { + long unmeteredNetworks, + boolean vonrEnabled) { this.carrierId = carrierId; this.phoneNumberSourceUicc = phoneNumberSourceUicc; this.phoneNumberSourceCarrier = phoneNumberSourceCarrier; @@ -143,6 +146,7 @@ public class PerSimStatus { this.minimumVoltageClass = minimumVoltageClass; this.userModifiedApnTypes = userModifiedApnTypes; this.unmeteredNetworks = unmeteredNetworks; + this.vonrEnabled = vonrEnabled; } @Nullable @@ -295,4 +299,16 @@ public class PerSimStatus { return bitmask; } } + + /** Returns true if VoNR is enabled */ + private static boolean isVonrEnabled(Phone phone) { + TelephonyManager telephonyManager = + phone.getContext() + .getSystemService(TelephonyManager.class); + if (telephonyManager == null) { + return false; + } + telephonyManager = telephonyManager.createForSubscriptionId(phone.getSubId()); + return telephonyManager.isVoNrEnabled(); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java index 10151b8b0b..6dbe6075a3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java @@ -133,6 +133,7 @@ public class PerSimStatusTest extends TelephonyTest { doReturn(UiccSlot.VOLTAGE_CLASS_A).when(uiccSlot1).getMinimumVoltageClass(); doReturn(uiccSlot1).when(mUiccController).getUiccSlotForPhone(0); doReturn(NETWORK_TYPE_BITMASK_GSM).when(mPersistAtomsStorage).getUnmeteredNetworks(0, 100); + doReturn(false).when(mTelephonyManager).isVoNrEnabled(); // phone 1 setup doReturn(mContext).when(mSecondPhone).getContext(); doReturn(1).when(mSecondPhone).getPhoneId(); @@ -210,6 +211,7 @@ public class PerSimStatusTest extends TelephonyTest { PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_A, perSimStatus1.minimumVoltageClass); assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus1.unmeteredNetworks); + assertEquals(false, perSimStatus1.vonrEnabled); assertEquals(101, perSimStatus2.carrierId); assertEquals(1, perSimStatus2.phoneNumberSourceUicc); assertEquals(2, perSimStatus2.phoneNumberSourceCarrier); @@ -228,6 +230,7 @@ public class PerSimStatusTest extends TelephonyTest { PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_B, perSimStatus2.minimumVoltageClass); assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus2.unmeteredNetworks); + assertEquals(false, perSimStatus2.vonrEnabled); } @Test @@ -286,6 +289,7 @@ public class PerSimStatusTest extends TelephonyTest { doReturn(UiccSlot.VOLTAGE_CLASS_A).when(uiccSlot1).getMinimumVoltageClass(); doReturn(uiccSlot1).when(mUiccController).getUiccSlotForPhone(0); doReturn(NETWORK_TYPE_BITMASK_GSM).when(mPersistAtomsStorage).getUnmeteredNetworks(0, 100); + doReturn(true).when(mTelephonyManager).isVoNrEnabled(); PerSimStatus perSimStatus = PerSimStatus.getCurrentState(mPhone); @@ -306,6 +310,7 @@ public class PerSimStatusTest extends TelephonyTest { PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_A, perSimStatus.minimumVoltageClass); assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus.unmeteredNetworks); + assertEquals(true, perSimStatus.vonrEnabled); } @Test @@ -355,6 +360,7 @@ public class PerSimStatusTest extends TelephonyTest { doReturn(UiccSlot.VOLTAGE_CLASS_A).when(uiccSlot1).getMinimumVoltageClass(); doReturn(uiccSlot1).when(mUiccController).getUiccSlotForPhone(0); doReturn(NETWORK_TYPE_BITMASK_GSM).when(mPersistAtomsStorage).getUnmeteredNetworks(0, 100); + doReturn(true).when(mTelephonyManager).isVoNrEnabled(); PerSimStatus perSimStatus = PerSimStatus.getCurrentState(mPhone); @@ -375,6 +381,7 @@ public class PerSimStatusTest extends TelephonyTest { PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_A, perSimStatus.minimumVoltageClass); assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus.unmeteredNetworks); + assertEquals(true, perSimStatus.vonrEnabled); } @Test @@ -420,6 +427,7 @@ public class PerSimStatusTest extends TelephonyTest { doReturn(iccCard).when(mPhone).getIccCard(); doReturn(null).when(mUiccController).getUiccSlotForPhone(0); doReturn(NETWORK_TYPE_BITMASK_GSM).when(mPersistAtomsStorage).getUnmeteredNetworks(0, 100); + doReturn(true).when(mTelephonyManager).isVoNrEnabled(); PerSimStatus perSimStatus = PerSimStatus.getCurrentState(mPhone); @@ -440,5 +448,6 @@ public class PerSimStatusTest extends TelephonyTest { PER_SIM_STATUS__SIM_VOLTAGE_CLASS__VOLTAGE_CLASS_UNKNOWN, perSimStatus.minimumVoltageClass); assertEquals(NETWORK_TYPE_BITMASK_GSM, perSimStatus.unmeteredNetworks); + assertEquals(true, perSimStatus.vonrEnabled); } } -- GitLab From 3a684751dc2ea384436e71747bef6ec263822334 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Thu, 6 Apr 2023 16:42:59 +0000 Subject: [PATCH 587/656] Feature support for SMS to misscall notification Fix of sms patterns to match the missed call received sms. Fix of single and multiple missed call notification. Bug: 144068181 Test: atest verified and Manually verified single, multiple and other calls by overriding Airtel-IN carrierConfig. Change-Id: Ica687f118270e6361845aab20c6e79d11b0dd3cf --- .../MissedIncomingCallSmsFilter.java | 146 +++++++++++------- 1 file changed, 87 insertions(+), 59 deletions(-) diff --git a/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java b/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java index e8b81968b1..a6bd7a4f80 100644 --- a/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java +++ b/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java @@ -23,12 +23,14 @@ import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.os.PersistableBundle; +import android.os.UserHandle; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; import android.telephony.Rlog; import android.telephony.SmsMessage; +import android.telephony.SubscriptionManager; import android.text.TextUtils; import java.time.Instant; @@ -152,9 +154,6 @@ public class MissedIncomingCallSmsFilter { * @return {@code true} if the SMS message has been processed as a missed incoming call SMS. */ private boolean processSms(@NonNull SmsMessage message) { - long missedCallTime = 0; - String callerId = null; - String[] smsPatterns = mCarrierConfig.getStringArray(CarrierConfigManager .KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY); if (smsPatterns == null || smsPatterns.length == 0) { @@ -162,76 +161,105 @@ public class MissedIncomingCallSmsFilter { return false; } - for (String smsPattern : smsPatterns) { - Pattern pattern; - try { - pattern = Pattern.compile(smsPattern, Pattern.DOTALL | Pattern.UNIX_LINES); - } catch (PatternSyntaxException e) { - Rlog.w(TAG, "Configuration error. Unexpected missed incoming call sms " - + "pattern: " + smsPattern + ", e=" + e); - continue; - } - - Matcher matcher = pattern.matcher(message.getMessageBody()); - String year = null, month = null, day = null, hour = null, minute = null; - if (matcher.find()) { - try { - month = matcher.group(SMS_MONTH_TAG); - day = matcher.group(SMS_DAY_TAG); - hour = matcher.group(SMS_HOUR_TAG); - minute = matcher.group(SMS_MINUTE_TAG); - if (VDBG) { - Rlog.v(TAG, "month=" + month + ", day=" + day + ", hour=" + hour - + ", minute=" + minute); + boolean result = false; + String[] missedCallMsgs = splitTheMultipleCalls(message.getMessageBody()); + if (missedCallMsgs != null && missedCallMsgs.length > 0) { + for (String parsedMsg : missedCallMsgs) { + long missedCallTime = 0; + String callerId = null; + for (String smsPattern : smsPatterns) { + Pattern pattern; + try { + pattern = Pattern.compile(smsPattern, Pattern.DOTALL | Pattern.UNIX_LINES); + } catch (PatternSyntaxException e) { + Rlog.w(TAG, "Configuration error. Unexpected missed incoming call sms " + + "pattern: " + smsPattern + ", e=" + e); + continue; } - } catch (IllegalArgumentException e) { - if (VDBG) { - Rlog.v(TAG, "One of the critical date field is missing. Using the " - + "current time for missed incoming call."); - } - missedCallTime = System.currentTimeMillis(); - } - // Year is an optional field. - try { - year = matcher.group(SMS_YEAR_TAG); - } catch (IllegalArgumentException e) { - if (VDBG) Rlog.v(TAG, "Year is missing."); - } - - try { - if (missedCallTime == 0) { - missedCallTime = getEpochTime(year, month, day, hour, minute); - if (missedCallTime == 0) { - Rlog.e(TAG, "Can't get the time. Use the current time."); + Matcher matcher = pattern.matcher(parsedMsg); + String year = null, month = null, day = null, hour = null, minute = null; + if (matcher.find()) { + try { + month = matcher.group(SMS_MONTH_TAG); + day = matcher.group(SMS_DAY_TAG); + hour = matcher.group(SMS_HOUR_TAG); + minute = matcher.group(SMS_MINUTE_TAG); + if (VDBG) { + Rlog.v(TAG, "month=" + month + ", day=" + day + ", hour=" + hour + + ", minute=" + minute); + } + } catch (IllegalArgumentException e) { + if (VDBG) { + Rlog.v(TAG, "One of the critical date field is missing. Using the " + + "current time for missed incoming call."); + } missedCallTime = System.currentTimeMillis(); } - } - if (VDBG) Rlog.v(TAG, "missedCallTime=" + missedCallTime); - } catch (Exception e) { - Rlog.e(TAG, "Can't get the time for missed incoming call"); - } + // Year is an optional field. + try { + year = matcher.group(SMS_YEAR_TAG); + } catch (IllegalArgumentException e) { + if (VDBG) Rlog.v(TAG, "Year is missing."); + } - try { - callerId = matcher.group(SMS_CALLER_ID_TAG); - if (VDBG) Rlog.v(TAG, "caller id=" + callerId); - } catch (IllegalArgumentException e) { - Rlog.d(TAG, "Caller id is not provided or can't be parsed."); + try { + if (missedCallTime == 0) { + missedCallTime = getEpochTime(year, month, day, hour, minute); + if (missedCallTime == 0) { + Rlog.e(TAG, "Can't get the time. Use the current time."); + missedCallTime = System.currentTimeMillis(); + } + } + + if (VDBG) Rlog.v(TAG, "missedCallTime=" + missedCallTime); + } catch (Exception e) { + Rlog.e(TAG, "Can't get the time for missed incoming call"); + } + + try { + callerId = matcher.group(SMS_CALLER_ID_TAG); + if (VDBG) Rlog.v(TAG, "caller id=" + callerId); + } catch (IllegalArgumentException e) { + Rlog.d(TAG, "Caller id is not provided or can't be parsed."); + } + createMissedIncomingCallEvent(missedCallTime, callerId); + result = true; + break; + } } - createMissedIncomingCallEvent(missedCallTime, callerId); - return true; } } + if (!result) { + Rlog.d(TAG, "SMS did not match any missed incoming call SMS pattern."); + } + return result; + } - Rlog.d(TAG, "SMS did not match any missed incoming call SMS pattern."); - return false; + private String[] splitTheMultipleCalls(String messageBody) { + String[] messages = null; + if (messageBody != null) { + messages = messageBody.split("\\n" + "\\n"); + Rlog.d(TAG, + "splitTheMultipleCalls no of calls = " + ((messages != null) ? messages.length + : 0)); + } + return messages; } // Create phone account. The logic is copied from PhoneUtils.makePstnPhoneAccountHandleWithId. - private static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) { + private PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) { + SubscriptionManager subscriptionManager = + (SubscriptionManager) phone.getContext().getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + UserHandle userHandle = subscriptionManager.getSubscriptionUserHandle(phone.getSubId()); + if (userHandle != null) { + return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT, + String.valueOf(phone.getSubId()), userHandle); + } return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT, - String.valueOf(phone.getSubId()), phone.getUserHandle()); + String.valueOf(phone.getSubId())); } /** -- GitLab From fb1aedc02485449af9e8314ba3b7733ea6e98687 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Tue, 11 Apr 2023 17:20:54 -0700 Subject: [PATCH 588/656] Update logs for RIL requests and responses Test: atest RILTest Bug: 276703840 Change-Id: Ifce463d32453999088197324d1705447b4fd9441 Merged-In: Ifce463d32453999088197324d1705447b4fd9441 --- src/java/com/android/internal/telephony/RILUtils.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index 01dd59b93f..bd70e92d40 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -271,6 +271,7 @@ import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RINGBACK_TON import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIGNAL_STRENGTH; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIM_REFRESH; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIM_SMS_STORAGE_FULL; +import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SLICING_CONFIG_CHANGED; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SRVCC_STATE_NOTIFY; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_CALL_SETUP; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_STK_CC_ALPHA_NOTIFY; @@ -5265,6 +5266,7 @@ public class RILUtils { return "UPDATE_SIM_PHONEBOOK_RECORD"; case RIL_REQUEST_DEVICE_IMEI: return "DEVICE_IMEI"; + /* The following requests are not defined in RIL.h */ case RIL_REQUEST_GET_SLOT_STATUS: return "GET_SLOT_STATUS"; case RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING: @@ -5471,6 +5473,9 @@ public class RILUtils { return "UNSOL_RESPONSE_SIM_PHONEBOOK_CHANGED"; case RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED: return "UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED"; + case RIL_UNSOL_SLICING_CONFIG_CHANGED: + return "UNSOL_SLICING_CONFIG_CHANGED"; + /* The follow unsols are not defined in RIL.h */ case RIL_UNSOL_ICC_SLOT_STATUS: return "UNSOL_ICC_SLOT_STATUS"; case RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG: @@ -5485,14 +5490,14 @@ public class RILUtils { return "UNSOL_BARRING_INFO_CHANGED"; case RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT: return "UNSOL_EMERGENCY_NETWORK_SCAN_RESULT"; + case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION: + return "UNSOL_TRIGGER_IMS_DEREGISTRATION"; case RIL_UNSOL_CONNECTION_SETUP_FAILURE: return "UNSOL_CONNECTION_SETUP_FAILURE"; case RIL_UNSOL_NOTIFY_ANBR: return "UNSOL_NOTIFY_ANBR"; - case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION: - return "UNSOL_TRIGGER_IMS_DEREGISTRATION"; default: - return ""; + return ""; } } -- GitLab From fbb6f784709728a7b3cadbe16d3463b33b5ba774 Mon Sep 17 00:00:00 2001 From: Pranav Madapurmath Date: Tue, 11 Apr 2023 21:18:26 +0000 Subject: [PATCH 589/656] Fix quick response not sending via work profile. Telecom calls into SmsController to send the SMS message over the work sim. However, the calling user is always User 0, which results in the message failing to send since the work sim is not associated with the primary profile. To reduce the scope of impact to other APIs, we will bypass the validation check only in SmsController#sendTextForSubscriber if the calling user has granted the INTERACT_ACROSS_USERS_FULL permission. Adding log (debug level) to track when validation is bypassed. Fixes: 275115413 Test: Manual (can see that the text message was sent to caller) Change-Id: Ie992df943b452c85aebc816b0c85145426c24201 --- .../internal/telephony/SmsController.java | 7 +++- .../internal/telephony/SmsControllerTest.java | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index 071dbda9b6..f1a69f4b5a 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -260,7 +260,12 @@ public class SmsController extends ISmsImplBase { } // Check if user is associated with the subscription - if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, + boolean crossUserFullGranted = mContext.checkCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) == PERMISSION_GRANTED; + Rlog.d(LOG_TAG, "sendTextForSubscriber: caller has INTERACT_ACROSS_USERS_FULL? " + + crossUserFullGranted); + if (!crossUserFullGranted + && !TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId, Binder.getCallingUserHandle(), destAddr)) { TelephonyUtils.showSwitchToManagedProfileDialogIfAppropriate(mContext, subId, Binder.getCallingUid(), callingPackage); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java index ab2907664a..09c4173fd5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SmsControllerTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.content.pm.PackageManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -207,4 +208,35 @@ public class SmsControllerTest extends TelephonyTest { .sendText(mCallingPackage, "1234", null, "text", null, null, false, 0L, true); } + @Test + public void sendTextForSubscriberTest_InteractAcrossUsers() { + int subId = 1; + // Sending text to subscriber should not fail when the caller has the + // INTERACT_ACROSS_USERS_FULL permission. + doReturn(false).when(mSubscriptionManager) + .isSubscriptionAssociatedWithUser(eq(subId), any()); + doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission( + eq(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)); + + mSmsControllerUT.sendTextForSubscriber(subId, mCallingPackage, null, "1234", + null, "text", null, null, false, 0L, true, true); + verify(mIccSmsInterfaceManager, Mockito.times(1)) + .sendText(mCallingPackage, "1234", null, "text", null, null, false, 0L, true); + } + + @Test + public void sendTextForSubscriberTestFail() { + int subId = 1; + // Sending text to subscriber should fail when the caller does not have the + // INTERACT_ACROSS_USERS_FULL permission and is not associated with the subscription. + doReturn(false).when(mSubscriptionManager) + .isSubscriptionAssociatedWithUser(eq(subId), any()); + doReturn(PackageManager.PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission( + eq(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)); + + mSmsControllerUT.sendTextForSubscriber(subId, mCallingPackage, null, "1234", + null, "text", null, null, false, 0L, true, true); + verify(mIccSmsInterfaceManager, Mockito.times(0)) + .sendText(mCallingPackage, "1234", null, "text", null, null, false, 0L, true); + } } \ No newline at end of file -- GitLab From e20f8b9496d471c0d2da978d7004ce988db0ffd7 Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Wed, 12 Apr 2023 22:34:17 +0000 Subject: [PATCH 590/656] Fixed port index is not updated when iccid is active but slot is inactive Set proper port index if iccid is present in the SLOT_STATUS event Bug: 274847836 Test: Manually verified switching between E+E<->P+E in DSDS and E<->P in SS Test: atest SubscriptionManagerServiceTest, atest FrameworksTelephonyTests Change-Id: I57cf260bbd73fa390be1e24a18591104111d9b4f --- .../SubscriptionManagerService.java | 20 ++++++++++++++++--- .../telephony/uicc/UiccController.java | 2 +- .../SubscriptionManagerServiceTest.java | 6 ++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 204cda00ab..bee0aff810 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -933,8 +933,10 @@ public class SubscriptionManagerService extends ISub.Stub { .forEach(subInfo -> { mSubscriptionDatabaseManager.setSimSlotIndex(subInfo.getSubscriptionId(), SubscriptionManager.INVALID_SIM_SLOT_INDEX); + // Sometime even though slot-port is inactive, proper iccid will be present, + // hence retry the port index from UiccSlot. (Pre-U behavior) mSubscriptionDatabaseManager.setPortIndex(subInfo.getSubscriptionId(), - TelephonyManager.INVALID_PORT_INDEX); + getPortIndex(subInfo.getIccId())); }); updateGroupDisabled(); logl("markSubscriptionsInactive: current mapping " + slotMappingToString()); @@ -3813,11 +3815,12 @@ public class SubscriptionManagerService extends ISub.Stub { } /** - * Called when eSIM becomes inactive. + * Called when SIM becomes inactive. * * @param slotIndex The logical SIM slot index. + * @param iccId iccId of the SIM in inactivate slot */ - public void updateSimStateForInactivePort(int slotIndex) { + public void updateSimStateForInactivePort(int slotIndex, String iccId) { mHandler.post(() -> { logl("updateSimStateForInactivePort: slotIndex=" + slotIndex); if (mSlotIndexToSubId.containsKey(slotIndex)) { @@ -3827,6 +3830,17 @@ public class SubscriptionManagerService extends ISub.Stub { mSlotIndexToSubId.get(slotIndex), true); updateSubscription(slotIndex); } + if (!TextUtils.isEmpty(iccId)) { + // When port is inactive, sometimes valid iccid is present in the slot status, + // hence update the portIndex. (Pre-U behavior) + SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager + .getSubscriptionInfoInternalByIccId(IccUtils.stripTrailingFs(iccId)); + if (subInfo != null) { + mSubscriptionDatabaseManager.setPortIndex(subInfo.getSubscriptionId(), + getPortIndex(iccId)); + } + } + }); } diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 8cdf943f7d..a10c81079d 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -790,7 +790,7 @@ public class UiccController extends Handler { IccCardConstants.State.ABSENT.toString()); } - SubscriptionManagerService.getInstance().updateSimStateForInactivePort(phoneId); + SubscriptionManagerService.getInstance().updateSimStateForInactivePort(phoneId, iccId); }); } 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 2674e1d2ba..d247900bd3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -1956,6 +1956,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { EuiccService.RESULT_OK, new EuiccProfileInfo[0], false); doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); doReturn("").when(mUiccPort).getIccId(); + doReturn(TelephonyManager.INVALID_PORT_INDEX) + .when(mUiccSlot).getPortIndexFromIccId(anyString()); mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1), null); mSubscriptionManagerServiceUT.updateSimState( @@ -2017,7 +2019,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { .getSubscriptionInfoInternal(1); assertThat(subInfo.getSimSlotIndex()).isEqualTo( SubscriptionManager.INVALID_SUBSCRIPTION_ID); - assertThat(subInfo.getPortIndex()).isEqualTo(TelephonyManager.INVALID_PORT_INDEX); + assertThat(subInfo.getPortIndex()).isEqualTo(TelephonyManager.DEFAULT_PORT_INDEX); } @Test @@ -2166,7 +2168,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { testSetUiccApplicationsEnabled(); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - mSubscriptionManagerServiceUT.updateSimStateForInactivePort(0); + mSubscriptionManagerServiceUT.updateSimStateForInactivePort(0, null); processAllMessages(); SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT -- GitLab From 9b652c7ca4cb3a17efbcbdc6c8b197e5cad1200d Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Thu, 13 Apr 2023 04:36:54 +0000 Subject: [PATCH 591/656] Update datagram transfer states internally first and then send updates to clients. Bug: 275670811 Test: atest DatagramDispatcherTest, atest DatagramReceiverTest atest CtsTelephonyTestCases:android.telephony.satellite.cts Flashed build on raven-userdebug: calls and sms are working Change-Id: I5dc5df43663299580a35e7517b19b44fa24332d3 --- .../satellite/DatagramController.java | 4 +- .../satellite/DatagramDispatcher.java | 59 +++++++++++-------- .../telephony/satellite/DatagramReceiver.java | 19 +++--- 3 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index fac24e3f3b..8eca0728b3 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -185,9 +185,9 @@ public class DatagramController { mSendDatagramTransferState = datagramTransferState; mSendPendingCount = sendPendingCount; mSendErrorCode = errorCode; + notifyDatagramTransferStateChangedToSessionController(); mPointingAppController.updateSendDatagramTransferState(subId, datagramTransferState, sendPendingCount, errorCode); - notifyDatagramTransferStateChangedToSessionController(); } /** @@ -210,9 +210,9 @@ public class DatagramController { mReceiveDatagramTransferState = datagramTransferState; mReceivePendingCount = receivePendingCount; mReceiveErrorCode = errorCode; + notifyDatagramTransferStateChangedToSessionController(); mPointingAppController.updateReceiveDatagramTransferState(subId, datagramTransferState, receivePendingCount, errorCode); - notifyDatagramTransferStateChangedToSessionController(); } /** diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index 439c97f8d4..262f8ee5aa 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -192,11 +192,6 @@ public class DatagramDispatcher extends Handler { argument.needFullScreenPointingUI); } else { loge("sendSatelliteDatagram: No phone object"); - argument.callback.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - // report phone == null case - reportSendDatagramCompleted(argument, - SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); - synchronized (mLock) { // Remove current datagram from pending map if (argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { @@ -205,6 +200,21 @@ public class DatagramDispatcher extends Handler { mPendingNonEmergencyDatagramsMap.remove(argument.datagramId); } + // Update send status + mDatagramController.updateSendStatus(argument.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + getPendingDatagramCount(), + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + mDatagramController.updateSendStatus(argument.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + 0, SatelliteManager.SATELLITE_ERROR_NONE); + + // report phone == null case + reportSendDatagramCompleted(argument, + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + argument.callback.accept( + SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + // Abort sending all the pending datagrams abortSendingPendingDatagrams(argument.subId, SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); @@ -226,8 +236,7 @@ public class DatagramDispatcher extends Handler { synchronized (mLock) { mSendingDatagramInProgress = false; - // Send response for current datagram and remove it from pending map. - argument.callback.accept(error); + // Remove current datagram from pending map. if (argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { mPendingEmergencyDatagramsMap.remove(argument.datagramId); } else { @@ -242,21 +251,33 @@ public class DatagramDispatcher extends Handler { mControllerMetricsStats.reportOutgoingDatagramSuccessCount( argument.datagramType); - if (getPendingDatagramCount() != 0) { + if (getPendingDatagramCount() > 0) { + // Send response for current datagram + argument.callback.accept(error); // Send pending datagrams sendPendingDatagrams(); } else { mDatagramController.updateSendStatus(argument.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, - getPendingDatagramCount(), - SatelliteManager.SATELLITE_ERROR_NONE); - + 0, SatelliteManager.SATELLITE_ERROR_NONE); + // Send response for current datagram + argument.callback.accept(error); } } else { + // Update send status + mDatagramController.updateSendStatus(argument.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + getPendingDatagramCount(), error); + mDatagramController.updateSendStatus(argument.subId, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + 0, SatelliteManager.SATELLITE_ERROR_NONE); + // Send response for current datagram + // after updating datagram transfer state internally. + argument.callback.accept(error); // Abort sending all the pending datagrams - abortSendingPendingDatagrams(argument.subId, error); mControllerMetricsStats.reportOutgoingDatagramFailCount( argument.datagramType); + abortSendingPendingDatagrams(argument.subId, error); } } break; @@ -306,10 +327,10 @@ public class DatagramDispatcher extends Handler { if (!mSendingDatagramInProgress) { mSendingDatagramInProgress = true; datagramArgs.setDatagramStartTime(); - sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArgs, phone); mDatagramController.updateSendStatus(subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, getPendingDatagramCount(), SatelliteManager.SATELLITE_ERROR_NONE); + sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArgs, phone); } } } @@ -335,10 +356,10 @@ public class DatagramDispatcher extends Handler { pendingDatagram.iterator().next().getValue(); // Sets the trigger time for getting pending datagrams datagramArg.setDatagramStartTime(); - sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArg, phone); mDatagramController.updateSendStatus(datagramArg.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING, getPendingDatagramCount(), SatelliteManager.SATELLITE_ERROR_NONE); + sendRequestAsync(CMD_SEND_SATELLITE_DATAGRAM, datagramArg, phone); } } @@ -358,9 +379,9 @@ public class DatagramDispatcher extends Handler { for (Entry entry : pendingDatagramsMap.entrySet()) { SendSatelliteDatagramArgument argument = entry.getValue(); - argument.callback.accept(errorCode); reportSendDatagramCompleted(argument, errorCode); mControllerMetricsStats.reportOutgoingDatagramFailCount(argument.datagramType); + argument.callback.accept(errorCode); } // Clear pending datagram maps @@ -381,14 +402,6 @@ public class DatagramDispatcher extends Handler { SatelliteManager.SATELLITE_REQUEST_ABORTED); sendErrorCodeAndCleanupPendingDatagrams(mPendingNonEmergencyDatagramsMap, SatelliteManager.SATELLITE_REQUEST_ABORTED); - - // Update send status - mDatagramController.updateSendStatus(subId, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, - getPendingDatagramCount(), error); - mDatagramController.updateSendStatus(subId, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, - getPendingDatagramCount(), SatelliteManager.SATELLITE_ERROR_NONE); } /** diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 306a7c91d3..d857c46b9f 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -75,10 +75,7 @@ public class DatagramReceiver extends Handler { private long mDatagramTransferStartTime = 0; - /** - * The background handler to perform database operations. This is running on a separate thread. - */ - @NonNull private final Handler mBackgroundHandler; + @NonNull private final Looper mLooper; /** * Map key: subId, value: SatelliteDatagramListenerHandler to notify registrants. @@ -113,13 +110,11 @@ public class DatagramReceiver extends Handler { @NonNull DatagramController datagramController) { super(looper); mContext = context; + mLooper = looper; mContentResolver = context.getContentResolver(); mDatagramController = datagramController; mControllerMetricsStats = ControllerMetricsStats.getInstance(); - HandlerThread backgroundThread = new HandlerThread(TAG); - backgroundThread.start(); - mBackgroundHandler = new Handler(looper); try { mSharedPreferences = mContext.getSharedPreferences(SatelliteController.SATELLITE_SHARED_PREF, @@ -398,8 +393,6 @@ public class DatagramReceiver extends Handler { phone.pollPendingSatelliteDatagrams(onCompleted); } else { loge("pollPendingSatelliteDatagrams: No phone object"); - ((Consumer) request.argument) - .accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); mDatagramController.updateReceiveStatus(request.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, mDatagramController.getReceivePendingCount(), @@ -413,6 +406,9 @@ public class DatagramReceiver extends Handler { reportMetrics(null, SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); mControllerMetricsStats.reportIncomingDatagramCount( SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + // Send response for current request + ((Consumer) request.argument) + .accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); } break; } @@ -422,7 +418,6 @@ public class DatagramReceiver extends Handler { request = (DatagramReceiverHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, "pollPendingSatelliteDatagrams"); - ((Consumer) request.argument).accept(error); logd("EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE error: " + error); if (error != SatelliteManager.SATELLITE_ERROR_NONE) { @@ -438,6 +433,8 @@ public class DatagramReceiver extends Handler { reportMetrics(null, error); mControllerMetricsStats.reportIncomingDatagramCount(error); } + // Send response for current request + ((Consumer) request.argument).accept(error); break; } } @@ -462,7 +459,7 @@ public class DatagramReceiver extends Handler { mSatelliteDatagramListenerHandlers.get(validSubId); if (satelliteDatagramListenerHandler == null) { satelliteDatagramListenerHandler = new SatelliteDatagramListenerHandler( - mBackgroundHandler.getLooper(), validSubId); + mLooper, validSubId); if (SatelliteModemInterface.getInstance().isSatelliteServiceSupported()) { SatelliteModemInterface.getInstance().registerForSatelliteDatagramsReceived( satelliteDatagramListenerHandler, -- GitLab From 2a899fd3f1bcccb47ed5d0925776ea093e011171 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 13 Apr 2023 14:56:18 +0000 Subject: [PATCH 592/656] Copy eccCategory member when cloning ImsDialArgs Bug: 270101950 Test: atest ImsPhoneTest#testImsDialArgsBuilderFromForAlternateService Change-Id: Ibdd71bf9ccbafdeeb066ef4ece73bbcdda0883e7 --- .../internal/telephony/imsphone/ImsPhone.java | 1 + .../internal/telephony/imsphone/ImsPhoneTest.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index e454fa33cc..b36707db71 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -196,6 +196,7 @@ public class ImsPhone extends ImsPhoneBase { return new ImsDialArgs.Builder() .setUusInfo(dialArgs.uusInfo) .setIsEmergency(dialArgs.isEmergency) + .setEccCategory(dialArgs.eccCategory) .setVideoState(dialArgs.videoState) .setIntentExtras(dialArgs.intentExtras) .setRttTextStream(((ImsDialArgs)dialArgs).rttTextStream) 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 483a74b18c..0134eceedc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -1410,6 +1410,21 @@ public class ImsPhoneTest extends TelephonyTest { assertTrue(regInfo[0] == 1 && regInfo[1] == 1 && regInfo[2] == 1); } + @Test + @SmallTest + public void testImsDialArgsBuilderFromForAlternateService() { + ImsPhone.ImsDialArgs dialArgs = new ImsPhone.ImsDialArgs.Builder() + .setIsEmergency(true) + .setEccCategory(2) + .build(); + + ImsPhone.ImsDialArgs copiedDialArgs = + ImsPhone.ImsDialArgs.Builder.from(dialArgs).build(); + + assertTrue(copiedDialArgs.isEmergency); + assertEquals(2, copiedDialArgs.eccCategory); + } + private ServiceState getServiceStateDataAndVoice(int rat, int regState, boolean isRoaming) { ServiceState ss = new ServiceState(); ss.setStateOutOfService(); -- GitLab From d86ed7b6359ce7937a8c9c9d7df5c05ee7fa4707 Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Thu, 13 Apr 2023 09:24:37 +0000 Subject: [PATCH 593/656] [Telephony]Fix ACTION_SERVICE_PROVIDERS_UPDATED posting issue @ ServiceStateTracker - Initialise mSubId after updateSpnDisplay() Bug: 276371799 Test: atest FrameworkTelephonyTests Change-Id: Ib5381ed0197192539296b5d073036b791fb3e9da --- .../telephony/ServiceStateTracker.java | 107 +++++++++--------- 1 file changed, 51 insertions(+), 56 deletions(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 2593e6b67d..a18a3c92d8 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -384,7 +384,6 @@ public class ServiceStateTracker extends Handler { // If not, then the subId has changed, so we need to remember the old subId, // even if the new subId is invalid (likely). mPrevSubId = mSubId; - mSubId = curSubId; // Update voicemail count and notify message waiting changed regardless of // whether the new subId is valid. This is an exception to the general logic @@ -393,72 +392,70 @@ public class ServiceStateTracker extends Handler { // which seems desirable. mPhone.updateVoiceMail(); - if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { + if (!SubscriptionManager.isValidSubscriptionId(curSubId)) { if (SubscriptionManager.isValidSubscriptionId(mPrevSubId)) { // just went from valid to invalid subId, so notify phone state listeners // with final broadcast mPhone.notifyServiceStateChangedForSubId(mOutOfServiceSS, ServiceStateTracker.this.mPrevSubId); } - // If the new subscription ID isn't valid, then we don't need to do all the - // UI updating, so we're done. - return; - } + } else { + Context context = mPhone.getContext(); - Context context = mPhone.getContext(); + mPhone.notifyPhoneStateChanged(); - mPhone.notifyPhoneStateChanged(); + if (!SubscriptionManager.isValidSubscriptionId(mPrevSubId)) { + // just went from invalid to valid subId, so notify with current service + // state in case our service state was never broadcasted (we don't notify + // service states when the subId is invalid) + mPhone.notifyServiceStateChanged(mPhone.getServiceState()); + } - if (!SubscriptionManager.isValidSubscriptionId(mPrevSubId)) { - // just went from invalid to valid subId, so notify with current service - // state in case our service state was never broadcasted (we don't notify - // service states when the subId is invalid) - mPhone.notifyServiceStateChanged(mPhone.getServiceState()); - } + boolean restoreSelection = !context.getResources().getBoolean( + com.android.internal.R.bool.skip_restoring_network_selection); + mPhone.sendSubscriptionSettings(restoreSelection); - boolean restoreSelection = !context.getResources().getBoolean( - com.android.internal.R.bool.skip_restoring_network_selection); - mPhone.sendSubscriptionSettings(restoreSelection); + setDataNetworkTypeForPhone(mSS.getRilDataRadioTechnology()); - setDataNetworkTypeForPhone(mSS.getRilDataRadioTechnology()); + if (mSpnUpdatePending) { + mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), mCurShowPlmn, + mCurPlmn, mCurShowSpn, mCurSpn); + mSpnUpdatePending = false; + } - if (mSpnUpdatePending) { - mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), mCurShowPlmn, - mCurPlmn, mCurShowSpn, mCurSpn); - mSpnUpdatePending = false; - } + // Remove old network selection sharedPreferences since SP key names are now + // changed to include subId. This will be done only once when upgrading from an + // older build that did not include subId in the names. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences( + context); + String oldNetworkSelection = sp.getString( + Phone.NETWORK_SELECTION_KEY, ""); + String oldNetworkSelectionName = sp.getString( + Phone.NETWORK_SELECTION_NAME_KEY, ""); + String oldNetworkSelectionShort = sp.getString( + Phone.NETWORK_SELECTION_SHORT_KEY, ""); + if (!TextUtils.isEmpty(oldNetworkSelection) + || !TextUtils.isEmpty(oldNetworkSelectionName) + || !TextUtils.isEmpty(oldNetworkSelectionShort)) { + SharedPreferences.Editor editor = sp.edit(); + editor.putString(Phone.NETWORK_SELECTION_KEY + curSubId, + oldNetworkSelection); + editor.putString(Phone.NETWORK_SELECTION_NAME_KEY + curSubId, + oldNetworkSelectionName); + editor.putString(Phone.NETWORK_SELECTION_SHORT_KEY + curSubId, + oldNetworkSelectionShort); + editor.remove(Phone.NETWORK_SELECTION_KEY); + editor.remove(Phone.NETWORK_SELECTION_NAME_KEY); + editor.remove(Phone.NETWORK_SELECTION_SHORT_KEY); + editor.commit(); + } - // Remove old network selection sharedPreferences since SP key names are now - // changed to include subId. This will be done only once when upgrading from an - // older build that did not include subId in the names. - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences( - context); - String oldNetworkSelection = sp.getString( - Phone.NETWORK_SELECTION_KEY, ""); - String oldNetworkSelectionName = sp.getString( - Phone.NETWORK_SELECTION_NAME_KEY, ""); - String oldNetworkSelectionShort = sp.getString( - Phone.NETWORK_SELECTION_SHORT_KEY, ""); - if (!TextUtils.isEmpty(oldNetworkSelection) - || !TextUtils.isEmpty(oldNetworkSelectionName) - || !TextUtils.isEmpty(oldNetworkSelectionShort)) { - SharedPreferences.Editor editor = sp.edit(); - editor.putString(Phone.NETWORK_SELECTION_KEY + mSubId, - oldNetworkSelection); - editor.putString(Phone.NETWORK_SELECTION_NAME_KEY + mSubId, - oldNetworkSelectionName); - editor.putString(Phone.NETWORK_SELECTION_SHORT_KEY + mSubId, - oldNetworkSelectionShort); - editor.remove(Phone.NETWORK_SELECTION_KEY); - editor.remove(Phone.NETWORK_SELECTION_NAME_KEY); - editor.remove(Phone.NETWORK_SELECTION_SHORT_KEY); - editor.commit(); + // Once sub id becomes valid, we need to update the service provider name + // displayed on the UI again. The old SPN update intents sent to + // MobileSignalController earlier were actually ignored due to invalid sub id. + updateSpnDisplay(); } - - // Once sub id becomes valid, we need to update the service provider name - // displayed on the UI again. The old SPN update intents sent to - // MobileSignalController earlier were actually ignored due to invalid sub id. - updateSpnDisplay(); + mSubId = curSubId; } }; @@ -2771,7 +2768,7 @@ public class ServiceStateTracker extends Handler { private void notifySpnDisplayUpdate(CarrierDisplayNameData data) { int subId = mPhone.getSubId(); - // Update ACTION_SERVICE_PROVIDERS_UPDATED IFF any value changes + // Update ACTION_SERVICE_PROVIDERS_UPDATED if any value changes if (mSubId != subId || data.shouldShowPlmn() != mCurShowPlmn || data.shouldShowSpn() != mCurShowSpn @@ -2815,8 +2812,6 @@ public class ServiceStateTracker extends Handler { } } } - - mSubId = subId; mCurShowSpn = data.shouldShowSpn(); mCurShowPlmn = data.shouldShowPlmn(); mCurSpn = data.getSpn(); -- GitLab From cbd03b1739900fff5a953c25bf1170e91eda779c Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 13 Apr 2023 12:00:54 -0700 Subject: [PATCH 594/656] Fixed inactive pSIM not shown in settings When the device is configured in e+e mode, the user does not have a chance to enable the inserted pSIM from Settings. Fixed by inserting the subscription from the inactive SIM. Fix: 271386059 Test: atest SubscriptionManagerServiceTest Test: Manually enabled e+e and inserted a physical SIM Change-Id: I36126c16cbe21b7288ee7974b3ccf826c9393f0f --- .../SubscriptionManagerService.java | 37 ++++++++++++++----- .../telephony/uicc/UiccController.java | 3 +- .../SubscriptionDatabaseManagerTest.java | 2 + .../SubscriptionManagerServiceTest.java | 23 +++++++++++- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index bee0aff810..752d4b6e72 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1019,7 +1019,12 @@ public class SubscriptionManagerService extends ISub.Stub { builder.setDisplayName(displayName); } - return mSubscriptionDatabaseManager.insertSubscriptionInfo(builder.build()); + int subId = mSubscriptionDatabaseManager.insertSubscriptionInfo(builder.build()); + logl("insertSubscriptionInfo: Inserted a new subscription. subId=" + subId + + ", slotIndex=" + slotIndex + ", iccId=" + SubscriptionInfo.getPrintableId(iccId) + + ", displayName=" + displayName + ", type=" + + SubscriptionManager.subscriptionTypeToString(subscriptionType)); + return subId; } /** @@ -1362,8 +1367,6 @@ public class SubscriptionManagerService extends ISub.Stub { // This is a new SIM card. Insert a new record. subId = insertSubscriptionInfo(iccId, phoneId, null, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - logl("updateSubscription: Inserted a new subscription. subId=" + subId - + ", phoneId=" + phoneId); } else { subId = subInfo.getSubscriptionId(); log("updateSubscription: Found existing subscription. subId= " + subId @@ -3818,14 +3821,15 @@ public class SubscriptionManagerService extends ISub.Stub { * Called when SIM becomes inactive. * * @param slotIndex The logical SIM slot index. - * @param iccId iccId of the SIM in inactivate slot + * @param iccId iccId of the SIM in inactivate slot. */ - public void updateSimStateForInactivePort(int slotIndex, String iccId) { + public void updateSimStateForInactivePort(int slotIndex, @NonNull String iccId) { mHandler.post(() -> { - logl("updateSimStateForInactivePort: slotIndex=" + slotIndex); + logl("updateSimStateForInactivePort: slotIndex=" + slotIndex + ", iccId=" + + SubscriptionInfo.getPrintableId(iccId)); if (mSlotIndexToSubId.containsKey(slotIndex)) { // Re-enable the UICC application , so it will be in enabled state when it becomes - // active again. (pre-U behavior) + // active again. (Pre-U behavior) mSubscriptionDatabaseManager.setUiccApplicationsEnabled( mSlotIndexToSubId.get(slotIndex), true); updateSubscription(slotIndex); @@ -3835,12 +3839,25 @@ public class SubscriptionManagerService extends ISub.Stub { // hence update the portIndex. (Pre-U behavior) SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager .getSubscriptionInfoInternalByIccId(IccUtils.stripTrailingFs(iccId)); + int subId; if (subInfo != null) { - mSubscriptionDatabaseManager.setPortIndex(subInfo.getSubscriptionId(), - getPortIndex(iccId)); + subId = subInfo.getSubscriptionId(); + log("updateSimStateForInactivePort: Found existing subscription. subId=" + + subId); + } else { + // If iccId is new, add a subscription record in the database so it can be + // activated later. (Pre-U behavior) + subId = insertSubscriptionInfo(IccUtils.stripTrailingFs(iccId), + SubscriptionManager.INVALID_SIM_SLOT_INDEX, + mContext.getResources().getString(R.string.default_card_name), + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + log("updateSimStateForInactivePort: Insert a new subscription for inactive SIM." + + " subId=" + subId); + } + if (SubscriptionManager.isValidSubscriptionId(subId)) { + mSubscriptionDatabaseManager.setPortIndex(subId, getPortIndex(iccId)); } } - }); } diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index a10c81079d..9d31f02fb0 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -790,7 +790,8 @@ public class UiccController extends Handler { IccCardConstants.State.ABSENT.toString()); } - SubscriptionManagerService.getInstance().updateSimStateForInactivePort(phoneId, iccId); + SubscriptionManagerService.getInstance().updateSimStateForInactivePort(phoneId, + TextUtils.emptyIfNull(iccId)); }); } 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 3a19b1bb59..fcc5439879 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -69,6 +69,8 @@ import java.util.concurrent.Executor; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class SubscriptionDatabaseManagerTest extends TelephonyTest { + + static final String FAKE_DEFAULT_CARD_NAME = "CARD NAME"; static final String FAKE_ICCID1 = "123456"; static final String FAKE_ICCID2 = "456789"; static final String FAKE_PHONE_NUMBER1 = "6502530000"; 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 d247900bd3..1453091322 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -23,6 +23,7 @@ import static com.android.internal.telephony.subscription.SubscriptionDatabaseMa import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CONTACT1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_CONTACT2; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_COUNTRY_CODE2; +import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_DEFAULT_CARD_NAME; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_EHPLMNS1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_HPLMNS1; import static com.android.internal.telephony.subscription.SubscriptionDatabaseManagerTest.FAKE_ICCID1; @@ -166,6 +167,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { doReturn(2).when(mTelephonyManager).getActiveModemCount(); doReturn(2).when(mTelephonyManager).getSupportedModemCount(); doReturn(mUiccProfile).when(mPhone2).getIccCard(); + doReturn(new UiccSlot[]{mUiccSlot}).when(mUiccController).getUiccSlots(); mContextFixture.putBooleanResource(com.android.internal.R.bool .config_subscription_database_async_update, true); @@ -1793,7 +1795,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { public void testUserUnlockUpdateEmbeddedSubscriptions() { doReturn(true).when(mUiccSlot).isEuicc(); doReturn(1).when(mUiccController).convertToPublicCardId(FAKE_ICCID1); - doReturn(new UiccSlot[]{mUiccSlot}).when(mUiccController).getUiccSlots(); doReturn(TelephonyManager.INVALID_PORT_INDEX).when(mUiccSlot) .getPortIndexFromIccId(anyString()); @@ -2176,6 +2177,26 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(subInfo.areUiccApplicationsEnabled()).isTrue(); } + @Test + public void testInactiveSimInserted() { + mContextFixture.putResource(com.android.internal.R.string.default_card_name, + FAKE_DEFAULT_CARD_NAME); + + doReturn(0).when(mUiccSlot).getPortIndexFromIccId(eq(FAKE_ICCID1)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + mSubscriptionManagerServiceUT.updateSimStateForInactivePort(-1, FAKE_ICCID1); + processAllMessages(); + + // Make sure the inactive SIM's information was inserted. + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo.getSimSlotIndex()).isEqualTo(SubscriptionManager.INVALID_SIM_SLOT_INDEX); + assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID1); + assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_DEFAULT_CARD_NAME); + assertThat(subInfo.getPortIndex()).isEqualTo(0); + } + @Test public void testRestoreAllSimSpecificSettingsFromBackup() { assertThrows(SecurityException.class, () -- GitLab From 3f0d05ce550edfb7cad5fd77918ef99cb60c5091 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Wed, 5 Apr 2023 18:04:06 -0700 Subject: [PATCH 595/656] Keep satellite gateway service alive during a session Bug: 275633844 Test: Call/SMS/MMS with live network. Wil add a mock satellite gate service for testing in CTS. atest android.telephony.cts.SatelliteManagerTest atest com.android.internal.telephony.satellite.SatelliteSessionControllerTest Change-Id: I8e1ce8e9b3af675d350a14ae950b81506988436e --- .../satellite/SatelliteController.java | 16 ++ .../satellite/SatelliteSessionController.java | 182 ++++++++++++++++++ 2 files changed, 198 insertions(+) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 975eb22758..3dbd5d729d 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -1460,6 +1460,22 @@ public class SatelliteController extends Handler { return mSatelliteSessionController.setSatelliteListeningTimeoutDuration(timeoutMillis); } + /** + * This API can be used by only CTS to update satellite gateway service package name. + * + * @param servicePackageName The package name of the satellite gateway service. + * @return {@code true} if the satellite gateway service is set successfully, + * {@code false} otherwise. + */ + public boolean setSatelliteGatewayServicePackageName(@Nullable String servicePackageName) { + if (mSatelliteSessionController == null) { + loge("mSatelliteSessionController is not initialized yet"); + return false; + } + return mSatelliteSessionController.setSatelliteGatewayServicePackageName( + servicePackageName); + } + /** * This function is used by {@link SatelliteModemInterface} to notify * {@link SatelliteController} that the satellite vendor service was just connected. diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index bb8a5af78a..7259abb436 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -25,7 +25,11 @@ import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TR import static android.telephony.satellite.SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; import android.os.Build; import android.os.IBinder; import android.os.Looper; @@ -36,9 +40,14 @@ import android.provider.DeviceConfig; import android.telephony.Rlog; import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.SatelliteManager; +import android.telephony.satellite.stub.ISatelliteGateway; +import android.telephony.satellite.stub.SatelliteGatewayService; +import android.text.TextUtils; import android.util.Log; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.ExponentialBackoff; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -82,6 +91,18 @@ public class SatelliteSessionController extends StateMachine { private static final int EVENT_LISTENING_TIMER_TIMEOUT = 2; private static final int EVENT_SATELLITE_ENABLED_STATE_CHANGED = 3; + private static final long REBIND_INITIAL_DELAY = 2 * 1000; // 2 seconds + private static final long REBIND_MAXIMUM_DELAY = 64 * 1000; // 1 minute + private static final int REBIND_MULTIPLIER = 2; + @NonNull private final ExponentialBackoff mExponentialBackoff; + @NonNull private final Object mLock = new Object(); + @Nullable + private ISatelliteGateway mSatelliteGatewayService; + private String mSatelliteGatewayServicePackageName = ""; + @Nullable private SatelliteGatewayServiceConnection mSatelliteGatewayServiceConnection; + private boolean mIsBound; + private boolean mIsBinding; + @NonNull private static SatelliteSessionController sInstance; @NonNull private final Context mContext; @@ -162,6 +183,22 @@ public class SatelliteSessionController extends StateMachine { mIsSendingTriggeredDuringTransferringState = new AtomicBoolean(false); mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN; mIsSatelliteSupported = isSatelliteSupported; + mExponentialBackoff = new ExponentialBackoff(REBIND_INITIAL_DELAY, REBIND_MAXIMUM_DELAY, + REBIND_MULTIPLIER, looper, () -> { + synchronized (mLock) { + if ((mIsBound && mSatelliteGatewayService != null) || mIsBinding) { + return; + } + } + if (mSatelliteGatewayServiceConnection != null) { + synchronized (mLock) { + mIsBound = false; + mIsBinding = false; + } + unbindService(); + } + bindService(); + }); addState(mUnavailableState); addState(mPowerOffState); @@ -254,6 +291,40 @@ public class SatelliteSessionController extends StateMachine { return true; } + /** + * This API can be used by only CTS to update satellite gateway service package name. + * + * @param servicePackageName The package name of the satellite gateway service. + * @return {@code true} if the satellite gateway service is set successfully, + * {@code false} otherwise. + */ + boolean setSatelliteGatewayServicePackageName(@Nullable String servicePackageName) { + if (!isMockModemAllowed()) { + loge("setSatelliteGatewayServicePackageName: modifying satellite gateway service " + + "package name is not allowed"); + return false; + } + + logd("setSatelliteGatewayServicePackageName: config_satellite_gateway_service_package is " + + "updated, new packageName=" + servicePackageName); + + if (servicePackageName == null || servicePackageName.equals("null")) { + mSatelliteGatewayServicePackageName = ""; + } else { + mSatelliteGatewayServicePackageName = servicePackageName; + } + + if (mSatelliteGatewayServiceConnection != null) { + synchronized (mLock) { + mIsBound = false; + mIsBinding = false; + } + unbindService(); + bindService(); + } + return true; + } + private static class DatagramTransferState { @SatelliteManager.SatelliteDatagramTransferState public int sendState; @SatelliteManager.SatelliteDatagramTransferState public int receiveState; @@ -283,11 +354,20 @@ public class SatelliteSessionController extends StateMachine { @Override public void enter() { if (DBG) logd("Entering PowerOffState"); + mCurrentState = SatelliteManager.SATELLITE_MODEM_STATE_OFF; mIsSendingTriggeredDuringTransferringState.set(false); + unbindService(); notifyStateChangedEvent(SatelliteManager.SATELLITE_MODEM_STATE_OFF); } + @Override + public void exit() { + if (DBG) logd("Exiting PowerOffState"); + logd("Attempting to bind to SatelliteGatewayService."); + bindService(); + } + @Override public boolean processMessage(Message msg) { if (DBG) log("PowerOffState: processing " + getWhatToString(msg.what)); @@ -512,6 +592,108 @@ public class SatelliteSessionController extends StateMachine { || receiveState == SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE); } + @NonNull + private String getSatelliteGatewayPackageName() { + if (!TextUtils.isEmpty(mSatelliteGatewayServicePackageName)) { + return mSatelliteGatewayServicePackageName; + } + return TextUtils.emptyIfNull(mContext.getResources().getString( + R.string.config_satellite_gateway_service_package)); + } + + private void bindService() { + synchronized (mLock) { + if (mIsBinding || mIsBound) return; + mIsBinding = true; + } + mExponentialBackoff.start(); + + String packageName = getSatelliteGatewayPackageName(); + if (TextUtils.isEmpty(packageName)) { + loge("Unable to bind to the satellite gateway service because the package is" + + " undefined."); + // Since the package name comes from static device configs, stop retry because + // rebind will continue to fail without a valid package name. + synchronized (mLock) { + mIsBinding = false; + } + mExponentialBackoff.stop(); + return; + } + Intent intent = new Intent(SatelliteGatewayService.SERVICE_INTERFACE); + intent.setPackage(packageName); + + mSatelliteGatewayServiceConnection = new SatelliteGatewayServiceConnection(); + try { + boolean success = mContext.bindService( + intent, mSatelliteGatewayServiceConnection, Context.BIND_AUTO_CREATE); + if (success) { + logd("Successfully bound to the satellite gateway service."); + } else { + synchronized (mLock) { + mIsBinding = false; + } + mExponentialBackoff.notifyFailed(); + loge("Error binding to the satellite gateway service. Retrying in " + + mExponentialBackoff.getCurrentDelay() + " ms."); + } + } catch (Exception e) { + synchronized (mLock) { + mIsBinding = false; + } + mExponentialBackoff.notifyFailed(); + loge("Exception binding to the satellite gateway service. Retrying in " + + mExponentialBackoff.getCurrentDelay() + " ms. Exception: " + e); + } + } + + private void unbindService() { + logd("unbindService"); + mExponentialBackoff.stop(); + mSatelliteGatewayService = null; + synchronized (mLock) { + mIsBinding = false; + mIsBound = false; + } + if (mSatelliteGatewayServiceConnection != null) { + mContext.unbindService(mSatelliteGatewayServiceConnection); + mSatelliteGatewayServiceConnection = null; + } + } + private class SatelliteGatewayServiceConnection implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + logd("onServiceConnected: ComponentName=" + name); + synchronized (mLock) { + mIsBound = true; + mIsBinding = false; + } + mSatelliteGatewayService = ISatelliteGateway.Stub.asInterface(service); + mExponentialBackoff.stop(); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + loge("onServiceDisconnected: Waiting for reconnect."); + synchronized (mLock) { + mIsBinding = false; + mIsBound = false; + } + mSatelliteGatewayService = null; + } + + @Override + public void onBindingDied(ComponentName name) { + loge("onBindingDied: Unbinding and rebinding service."); + synchronized (mLock) { + mIsBound = false; + mIsBinding = false; + } + unbindService(); + mExponentialBackoff.start(); + } + } + private boolean isMockModemAllowed() { return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); } -- GitLab From 0ea76dcd12162b2a09ba1332d17d24e335dbd22e Mon Sep 17 00:00:00 2001 From: Willy Hu Date: Thu, 6 Apr 2023 10:39:00 +0800 Subject: [PATCH 596/656] [DSRM] Improve the current action duration - update the elapsed time when device really doRecovery() for each action Bug: 275500989 Test: Manual test passed. Change-Id: I9fb751cebf107795454433b17b10aa82a0fe1817 --- .../internal/telephony/data/DataStallRecoveryManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index 8907143607..8c4e2877af 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -639,7 +639,10 @@ public class DataStallRecoveryManager extends Handler { if (isLogNeeded) { timeDurationOfCurrentAction = - (isFirstDataStall == true ? 0 : (int) getDurationOfCurrentRecoveryMs()); + ((getRecoveryAction() > RECOVERY_ACTION_GET_DATA_CALL_LIST + && !mIsAttemptedAllSteps) + || mLastAction == RECOVERY_ACTION_RESET_MODEM) + ? (int) getDurationOfCurrentRecoveryMs() : 0; DataStallRecoveryStats.onDataStallEvent( mLastAction, mPhone, isValid, timeDuration, reason, isFirstValidationAfterDoRecovery, timeDurationOfCurrentAction); -- GitLab From 051dd681b68ada16d2323de9903b92f0fd569254 Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Sat, 15 Apr 2023 16:53:49 +0000 Subject: [PATCH 597/656] Add mock class to avoid Null Point Exception Null point exception happend when DatagramDispatcherTest/ReceiverTest were called ControllerMetricsStats class does not exist for unit test because it is created from SatelliteController Bug: 278323102 Test: atest DatagramDispatcherTest DatagramReceiverTest Change-Id: I91fb0fc786882fbd827d0b16f0e78bba8e3fae5c --- .../internal/telephony/satellite/DatagramDispatcherTest.java | 4 ++++ .../internal/telephony/satellite/DatagramReceiverTest.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java index 730b871ff7..f9d87a80cc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java @@ -37,6 +37,7 @@ import android.testing.TestableLooper; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import org.junit.After; import org.junit.Before; @@ -61,6 +62,7 @@ public class DatagramDispatcherTest extends TelephonyTest { @Mock private DatagramController mMockDatagramController; @Mock private SatelliteModemInterface mMockSatelliteModemInterface; + @Mock private ControllerMetricsStats mMockControllerMetricsStats; /** Variables required to send datagram in the unit tests. */ LinkedBlockingQueue mResultListener; @@ -77,6 +79,8 @@ public class DatagramDispatcherTest extends TelephonyTest { mMockDatagramController); replaceInstance(SatelliteModemInterface.class, "sInstance", null, mMockSatelliteModemInterface); + replaceInstance(ControllerMetricsStats.class, "sInstance", null, + mMockControllerMetricsStats); mDatagramDispatcherUT = DatagramDispatcher.make(mContext, Looper.myLooper(), mMockDatagramController); diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java index 9a67a698a8..c33b11d610 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java @@ -39,6 +39,7 @@ import android.util.Pair; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import org.junit.After; import org.junit.Before; @@ -62,6 +63,7 @@ public class DatagramReceiverTest extends TelephonyTest { @Mock private DatagramController mMockDatagramController; @Mock private SatelliteModemInterface mMockSatelliteModemInterface; + @Mock private ControllerMetricsStats mMockControllerMetricsStats; /** Variables required to receive datagrams in the unit tests. */ @@ -88,6 +90,8 @@ public class DatagramReceiverTest extends TelephonyTest { mMockDatagramController); replaceInstance(SatelliteModemInterface.class, "sInstance", null, mMockSatelliteModemInterface); + replaceInstance(ControllerMetricsStats.class, "sInstance", null, + mMockControllerMetricsStats); mDatagramReceiverUT = DatagramReceiver.make(mContext, Looper.myLooper(), mMockDatagramController); -- GitLab From e5033b775fc1529b9621cc28c9f19ad832e4856d Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 17 Apr 2023 10:26:17 -0700 Subject: [PATCH 598/656] Fixed incorrect card name shown up The card name "CARD %d" is shown in settings. Fixed by appending the subscription id to the display name. Fix: 278570149 Test: atest SubscriptionManagerServiceTest Change-Id: Icf96e90da21544c1549b8a16fb9579ba0fcbf5d1 --- .../telephony/subscription/SubscriptionManagerService.java | 5 +++-- .../subscription/SubscriptionDatabaseManagerTest.java | 2 +- .../subscription/SubscriptionManagerServiceTest.java | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 752d4b6e72..ca9550ed71 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -3848,9 +3848,10 @@ public class SubscriptionManagerService extends ISub.Stub { // If iccId is new, add a subscription record in the database so it can be // activated later. (Pre-U behavior) subId = insertSubscriptionInfo(IccUtils.stripTrailingFs(iccId), - SubscriptionManager.INVALID_SIM_SLOT_INDEX, - mContext.getResources().getString(R.string.default_card_name), + SubscriptionManager.INVALID_SIM_SLOT_INDEX, "", SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); + mSubscriptionDatabaseManager.setDisplayName(subId, + mContext.getResources().getString(R.string.default_card_name, subId)); log("updateSimStateForInactivePort: Insert a new subscription for inactive SIM." + " subId=" + subId); } 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 fcc5439879..9898353178 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionDatabaseManagerTest.java @@ -70,7 +70,7 @@ import java.util.concurrent.Executor; @TestableLooper.RunWithLooper public class SubscriptionDatabaseManagerTest extends TelephonyTest { - static final String FAKE_DEFAULT_CARD_NAME = "CARD NAME"; + 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"; 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 1453091322..7a4ed8906d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -2193,7 +2193,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { .getSubscriptionInfoInternal(1); assertThat(subInfo.getSimSlotIndex()).isEqualTo(SubscriptionManager.INVALID_SIM_SLOT_INDEX); assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID1); - assertThat(subInfo.getDisplayName()).isEqualTo(FAKE_DEFAULT_CARD_NAME); + assertThat(subInfo.getDisplayName()).isEqualTo("CARD 1"); assertThat(subInfo.getPortIndex()).isEqualTo(0); } -- GitLab From 5ae62451859828c9f162228d9004d072ce3ba5d1 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Tue, 4 Apr 2023 23:13:39 +0000 Subject: [PATCH 599/656] Delete datagram from DB after receiving ack from all listeners. Bug: 260896985 Test: atest SatelliteManagerTest, Flashed build on raven-userdebug: calls and SMS are working. Change-Id: Id28d0e29e586c0dc0385ef4d819e971afcd483a6 --- .../telephony/satellite/DatagramReceiver.java | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index d857c46b9f..a47b16b50b 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -43,10 +43,12 @@ import android.util.Pair; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.IVoidConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.metrics.SatelliteStats; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; +import com.android.internal.util.FunctionalUtils; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; @@ -74,8 +76,7 @@ public class DatagramReceiver extends Handler { @NonNull private final ControllerMetricsStats mControllerMetricsStats; private long mDatagramTransferStartTime = 0; - - @NonNull private final Looper mLooper; + @NonNull private final Looper mLooper; /** * Map key: subId, value: SatelliteDatagramListenerHandler to notify registrants. @@ -83,6 +84,15 @@ public class DatagramReceiver extends Handler { private final ConcurrentHashMap mSatelliteDatagramListenerHandlers = new ConcurrentHashMap<>(); + /** + * Map key: DatagramId, value: pendingAckCount + * This map is used to track number of listeners that are yet to send ack for a particular + * datagram. + */ + private final ConcurrentHashMap + mPendingAckCountHashMap = new ConcurrentHashMap<>(); + + /** * Create the DatagramReceiver singleton instance. * @param context The Context to use to create the DatagramReceiver. @@ -204,6 +214,10 @@ public class DatagramReceiver extends Handler { return !mListeners.isEmpty(); } + public int getNumOfListeners() { + return mListeners.size(); + } + private int getTimeoutToReceiveAck() { return sInstance.mContext.getResources().getInteger( R.integer.config_timeout_to_receive_delivered_ack_millis); @@ -321,6 +335,7 @@ public class DatagramReceiver extends Handler { pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); long datagramId = getDatagramId(); + sInstance.mPendingAckCountHashMap.put(datagramId, getNumOfListeners()); insertDatagram(datagramId, satelliteDatagram); mListeners.values().forEach(listener -> { @@ -337,10 +352,21 @@ public class DatagramReceiver extends Handler { SatelliteManager.SATELLITE_ERROR_NONE); } - if (pendingCount == 0) { + if (pendingCount <= 0) { sInstance.mDatagramController.updateReceiveStatus(mSubId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); + } else { + // Poll for pending datagrams + IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("pollPendingSatelliteDatagram result: " + result); + } + }; + Consumer callback = FunctionalUtils.ignoreRemoteException( + internalCallback::accept); + sInstance.pollPendingSatelliteDatagrams(mSubId, callback); } // Send the captured data about incoming datagram to metric @@ -359,9 +385,18 @@ public class DatagramReceiver extends Handler { case EVENT_RECEIVED_ACK: { DatagramRetryArgument argument = (DatagramRetryArgument) msg.obj; + int pendingAckCount = sInstance.mPendingAckCountHashMap + .get(argument.datagramId); + pendingAckCount -= 1; + sInstance.mPendingAckCountHashMap.put(argument.datagramId, pendingAckCount); logd("Received EVENT_RECEIVED_ACK datagramId:" + argument.datagramId); removeMessages(EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM, argument); - deleteDatagram(argument.datagramId); + + if (pendingAckCount <= 0) { + // Delete datagram from DB after receiving ack from all listeners + deleteDatagram(argument.datagramId); + sInstance.mPendingAckCountHashMap.remove(argument.datagramId); + } } default: -- GitLab From b7f0e1032ff4ad6c9ce9daa6ef9b26f9b027f356 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 17 Apr 2023 12:58:41 -0700 Subject: [PATCH 600/656] Fixed dump not gated by permission Fix: 278217014 Test: atest android.security.cts.ServicePermissionsTest#testDumpProtected Change-Id: I2a63d653fb539e5fbe8c5a0cf74bb5e4225d5593 --- .../SubscriptionManagerService.java | 156 +++++++++--------- .../SubscriptionManagerServiceTest.java | 7 +- 2 files changed, 88 insertions(+), 75 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 752d4b6e72..6c1045b5da 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -4001,79 +4001,87 @@ public class SubscriptionManagerService extends ISub.Stub { */ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter printWriter, @NonNull String[] args) { - IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); - pw.println(SubscriptionManagerService.class.getSimpleName() + ":"); - pw.println("Active modem count=" + mTelephonyManager.getActiveModemCount()); - pw.println("Logical SIM slot sub id mapping:"); - pw.increaseIndent(); - mSlotIndexToSubId.forEach((slotIndex, subId) - -> pw.println("Logical SIM slot " + slotIndex + ": subId=" + subId)); - pw.decreaseIndent(); - pw.println("ICCID:"); - pw.increaseIndent(); - for (int i = 0; i < mTelephonyManager.getActiveModemCount(); i++) { - pw.println("slot " + i + ": " + SubscriptionInfo.getPrintableId(getIccId(i))); - } - pw.decreaseIndent(); - pw.println(); - pw.println("defaultSubId=" + getDefaultSubId()); - pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId()); - pw.println("defaultDataSubId=" + getDefaultDataSubId()); - pw.println("activeDataSubId=" + getActiveDataSubscriptionId()); - pw.println("defaultSmsSubId=" + getDefaultSmsSubId()); - pw.println("areAllSubscriptionsLoaded=" + areAllSubscriptionsLoaded()); - pw.println(); - for (int i = 0; i < mSimState.length; i++) { - pw.println("mSimState[" + i + "]=" + TelephonyManager.simStateToString(mSimState[i])); - } - - pw.println(); - pw.println("Active subscriptions:"); - pw.increaseIndent(); - mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(SubscriptionInfoInternal::isActive).forEach(pw::println); - pw.decreaseIndent(); - - pw.println(); - pw.println("All subscriptions:"); - pw.increaseIndent(); - mSubscriptionDatabaseManager.getAllSubscriptions().forEach(pw::println); - pw.decreaseIndent(); - pw.println(); - - pw.print("Embedded subscriptions: ["); - pw.println(mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(SubscriptionInfoInternal::isEmbedded) - .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) - .collect(Collectors.joining(", ")) + "]"); - - pw.print("Opportunistic subscriptions: ["); - pw.println(mSubscriptionDatabaseManager.getAllSubscriptions().stream() - .filter(SubscriptionInfoInternal::isOpportunistic) - .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) - .collect(Collectors.joining(", ")) + "]"); - - pw.print("getAvailableSubscriptionInfoList: ["); - pw.println(getAvailableSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getFeatureId()).stream() - .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) - .collect(Collectors.joining(", ")) + "]"); - - pw.print("getSelectableSubscriptionInfoList: ["); - pw.println(mSubscriptionManager.getSelectableSubscriptionInfoList().stream() - .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) - .collect(Collectors.joining(", ")) + "]"); - - if (mEuiccManager != null) { - pw.println("Euicc enabled=" + mEuiccManager.isEnabled()); - } - pw.println(); - pw.println("Local log:"); - pw.increaseIndent(); - mLocalLog.dump(fd, pw, args); - pw.decreaseIndent(); - pw.decreaseIndent(); - pw.println(); - mSubscriptionDatabaseManager.dump(fd, pw, args); + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, + "Requires android.Manifest.permission.DUMP"); + final long token = Binder.clearCallingIdentity(); + try { + IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); + pw.println(SubscriptionManagerService.class.getSimpleName() + ":"); + pw.println("Active modem count=" + mTelephonyManager.getActiveModemCount()); + pw.println("Logical SIM slot sub id mapping:"); + pw.increaseIndent(); + mSlotIndexToSubId.forEach((slotIndex, subId) + -> pw.println("Logical SIM slot " + slotIndex + ": subId=" + subId)); + pw.decreaseIndent(); + pw.println("ICCID:"); + pw.increaseIndent(); + for (int i = 0; i < mTelephonyManager.getActiveModemCount(); i++) { + pw.println("slot " + i + ": " + SubscriptionInfo.getPrintableId(getIccId(i))); + } + pw.decreaseIndent(); + pw.println(); + pw.println("defaultSubId=" + getDefaultSubId()); + pw.println("defaultVoiceSubId=" + getDefaultVoiceSubId()); + pw.println("defaultDataSubId=" + getDefaultDataSubId()); + pw.println("activeDataSubId=" + getActiveDataSubscriptionId()); + pw.println("defaultSmsSubId=" + getDefaultSmsSubId()); + pw.println("areAllSubscriptionsLoaded=" + areAllSubscriptionsLoaded()); + pw.println(); + for (int i = 0; i < mSimState.length; i++) { + pw.println("mSimState[" + i + "]=" + + TelephonyManager.simStateToString(mSimState[i])); + } + + pw.println(); + pw.println("Active subscriptions:"); + pw.increaseIndent(); + mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isActive).forEach(pw::println); + pw.decreaseIndent(); + + pw.println(); + pw.println("All subscriptions:"); + pw.increaseIndent(); + mSubscriptionDatabaseManager.getAllSubscriptions().forEach(pw::println); + pw.decreaseIndent(); + pw.println(); + + pw.print("Embedded subscriptions: ["); + pw.println(mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isEmbedded) + .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) + .collect(Collectors.joining(", ")) + "]"); + + pw.print("Opportunistic subscriptions: ["); + pw.println(mSubscriptionDatabaseManager.getAllSubscriptions().stream() + .filter(SubscriptionInfoInternal::isOpportunistic) + .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) + .collect(Collectors.joining(", ")) + "]"); + + pw.print("getAvailableSubscriptionInfoList: ["); + pw.println(getAvailableSubscriptionInfoList( + mContext.getOpPackageName(), mContext.getFeatureId()).stream() + .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) + .collect(Collectors.joining(", ")) + "]"); + + pw.print("getSelectableSubscriptionInfoList: ["); + pw.println(mSubscriptionManager.getSelectableSubscriptionInfoList().stream() + .map(subInfo -> String.valueOf(subInfo.getSubscriptionId())) + .collect(Collectors.joining(", ")) + "]"); + + if (mEuiccManager != null) { + pw.println("Euicc enabled=" + mEuiccManager.isEnabled()); + } + pw.println(); + pw.println("Local log:"); + pw.increaseIndent(); + mLocalLog.dump(fd, pw, args); + pw.decreaseIndent(); + pw.decreaseIndent(); + pw.println(); + mSubscriptionDatabaseManager.dump(fd, pw, args); + } finally { + Binder.restoreCallingIdentity(token); + } } } 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 1453091322..2761e8c66a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -2028,8 +2028,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { insertSubscription(FAKE_SUBSCRIPTION_INFO1); insertSubscription(FAKE_SUBSCRIPTION_INFO2); - mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); final StringWriter stringWriter = new StringWriter(); + assertThrows(SecurityException.class, () + -> mSubscriptionManagerServiceUT.dump(new FileDescriptor(), + new PrintWriter(stringWriter), null)); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.DUMP); + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); mSubscriptionManagerServiceUT.dump(new FileDescriptor(), new PrintWriter(stringWriter), null); assertThat(stringWriter.toString().length()).isGreaterThan(0); -- GitLab From 6013308c5ce5e39e9fa78acd57965d6929c3d94c Mon Sep 17 00:00:00 2001 From: sangyun Date: Mon, 17 Apr 2023 10:41:14 +0900 Subject: [PATCH 601/656] Check if preferred on IWLAN was changed in ServiceState. The IwlanPreferred was obtained in the process of polling in SST. but there was no changes notify even when the IwlanPreferred is changed by alone. Bug: 268446053 Test: atest FrameworksTelephonyTests Change-Id: I09522dc8ddc48123a22eeeb50a50faa6a384c78f --- .../telephony/ServiceStateTracker.java | 28 ++++++++++++++++ .../telephony/ServiceStateTrackerTest.java | 33 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 2593e6b67d..299d81d349 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -92,6 +92,7 @@ import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.cdnr.CarrierDisplayNameData; import com.android.internal.telephony.cdnr.CarrierDisplayNameResolver; import com.android.internal.telephony.data.AccessNetworksManager; +import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback; import com.android.internal.telephony.data.DataNetwork; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; import com.android.internal.telephony.imsphone.ImsPhone; @@ -625,6 +626,12 @@ public class ServiceStateTracker extends Handler { */ private DataNetworkControllerCallback mDataDisconnectedCallback; + /** + * AccessNetworksManagerCallback is used for preferred on the IWLAN when preferred transport + * type changed in AccessNetworksManager. + */ + private AccessNetworksManagerCallback mAccessNetworksManagerCallback = null; + public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) { mNitzState = TelephonyComponentFactory.getInstance() .inject(NitzStateMachine.class.getName()) @@ -737,6 +744,23 @@ public class ServiceStateTracker extends Handler { } } }; + + mAccessNetworksManagerCallback = new AccessNetworksManagerCallback(this::post) { + @Override + public void onPreferredTransportChanged(int networkCapability) { + // Check if preferred on IWLAN was changed in ServiceState. + boolean isIwlanPreferred = mAccessNetworksManager.isAnyApnOnIwlan(); + if (mSS.isIwlanPreferred() != isIwlanPreferred) { + log("onPreferredTransportChanged: IwlanPreferred is changed to " + + isIwlanPreferred); + mSS.setIwlanPreferred(isIwlanPreferred); + mPhone.notifyServiceStateChanged(mPhone.getServiceState()); + } + } + }; + if (mAccessNetworksManagerCallback != null) { + mAccessNetworksManager.registerCallback(mAccessNetworksManagerCallback); + } } @VisibleForTesting @@ -875,6 +899,10 @@ public class ServiceStateTracker extends Handler { mCSST.dispose(); mCSST = null; } + if (mAccessNetworksManagerCallback != null) { + mAccessNetworksManager.unregisterCallback(mAccessNetworksManagerCallback); + mAccessNetworksManagerCallback = null; + } } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 3b6499c5f3..489ef15f1b 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -93,6 +93,7 @@ import androidx.test.filters.FlakyTest; import com.android.internal.R; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; +import com.android.internal.telephony.data.AccessNetworksManager; import com.android.internal.telephony.data.DataNetworkController; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; @@ -107,6 +108,7 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; @@ -3166,4 +3168,35 @@ public class ServiceStateTrackerTest extends TelephonyTest { doReturn(ServiceState.STATE_EMERGENCY_ONLY).when(mServiceState).getState(); assertEquals(ServiceState.STATE_EMERGENCY_ONLY, sst.getCombinedRegState(mServiceState)); } + + + @Test + public void testOnChangingPreferredOnIwlan() throws Exception { + Field callbackField = + ServiceStateTracker.class.getDeclaredField("mAccessNetworksManagerCallback"); + callbackField.setAccessible(true); + AccessNetworksManager.AccessNetworksManagerCallback accessNetworksManagerCallback = + (AccessNetworksManager.AccessNetworksManagerCallback) callbackField.get(sst); + + when(mAccessNetworksManager.isAnyApnOnIwlan()).thenReturn(false); + + // Start state: Cell data only LTE + IWLAN + CellIdentityLte cellIdentity = + new CellIdentityLte(1, 1, 5, 1, new int[] {1, 2}, 5000, "001", "01", "test", + "tst", Collections.emptyList(), null); + changeRegStateWithIwlan( + // WWAN + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, cellIdentity, + TelephonyManager.NETWORK_TYPE_UNKNOWN, TelephonyManager.NETWORK_TYPE_LTE, + // WLAN + NetworkRegistrationInfo.REGISTRATION_STATE_HOME, + TelephonyManager.NETWORK_TYPE_IWLAN); + assertFalse(sst.mSS.isIwlanPreferred()); + + when(mAccessNetworksManager.isAnyApnOnIwlan()).thenReturn(true); + accessNetworksManagerCallback.onPreferredTransportChanged(0); + waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); + + assertTrue(sst.mSS.isIwlanPreferred()); + } } -- GitLab From c97b4ba264d18da106fe00c4d5c726ce8bb340c1 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 14 Apr 2023 08:36:23 -0700 Subject: [PATCH 602/656] Remove legacy subscription code Removed SubscriptionController and SubscriptionInfoUpdater, which have been replaced by SubscriptionManagerService. Test: atest FrameworksTelephonyTests Test: Basic phone functionality tests Fix: 276816827 Change-Id: Ia00b3d6206c60247c7f642bb720bdd8c5ea26af2 --- OWNERS | 6 - README.txt | 2 +- .../internal/telephony/CarrierResolver.java | 11 +- .../internal/telephony/GsmCdmaPhone.java | 69 +- .../telephony/MultiSimSettingController.java | 404 +- .../telephony/NetworkScanRequestTracker.java | 9 +- .../com/android/internal/telephony/Phone.java | 67 +- .../telephony/PhoneConfigurationManager.java | 15 +- .../internal/telephony/PhoneFactory.java | 94 +- .../telephony/PhoneSubInfoController.java | 22 +- .../internal/telephony/SMSDispatcher.java | 20 +- .../telephony/ServiceStateTracker.java | 57 +- .../telephony/SignalStrengthController.java | 13 +- .../telephony/SmsBroadcastUndelivered.java | 11 +- .../internal/telephony/SmsController.java | 27 +- .../telephony/SubscriptionController.java | 5036 ----------------- .../telephony/SubscriptionInfoUpdater.java | 1396 ----- .../telephony/TelephonyComponentFactory.java | 20 +- .../telephony/UiccPhoneBookController.java | 7 +- .../internal/telephony/cat/CatService.java | 15 +- .../data/CellularNetworkValidator.java | 35 +- .../telephony/data/DataSettingsManager.java | 80 +- .../telephony/data/PhoneSwitcher.java | 102 +- .../emergency/EmergencyNumberTracker.java | 8 +- .../telephony/euicc/EuiccCardController.java | 32 +- .../telephony/euicc/EuiccController.java | 13 +- .../internal/telephony/imsphone/ImsPhone.java | 37 +- .../imsphone/ImsPhoneCallTracker.java | 21 +- .../metrics/DataCallSessionStats.java | 21 +- .../metrics/DataStallRecoveryStats.java | 11 +- .../telephony/metrics/PerSimStatus.java | 51 +- .../satellite/SatelliteServiceUtils.java | 11 +- .../SubscriptionDatabaseManager.java | 1 - .../SubscriptionManagerService.java | 30 +- .../internal/telephony/uicc/RuimRecords.java | 1 - .../telephony/uicc/UiccController.java | 33 - .../internal/telephony/uicc/UiccProfile.java | 83 +- .../internal/telephony/uicc/UiccSlot.java | 29 +- .../internal/telephony/GsmCdmaPhoneTest.java | 37 +- .../MultiSimSettingControllerTest.java | 7 +- .../PhoneConfigurationManagerTest.java | 43 +- .../telephony/PhoneSubInfoControllerTest.java | 8 - .../telephony/ServiceStateTrackerTest.java | 9 - .../telephony/SubscriptionControllerTest.java | 2291 -------- .../SubscriptionInfoUpdaterTest.java | 1123 ---- .../telephony/TelephonyRegistryTest.java | 5 +- .../internal/telephony/TelephonyTest.java | 35 +- .../data/CellularNetworkValidatorTest.java | 1 - .../data/DataNetworkControllerTest.java | 14 +- .../data/DataSettingsManagerTest.java | 13 +- .../data/DataStallRecoveryManagerTest.java | 13 +- .../telephony/data/PhoneSwitcherTest.java | 61 +- .../data/TelephonyNetworkFactoryTest.java | 8 +- .../emergency/EmergencyNumberTrackerTest.java | 32 - .../telephony/gsm/GsmSmsDispatcherTest.java | 7 +- .../imsphone/ImsPhoneCallTrackerTest.java | 13 - .../telephony/imsphone/ImsPhoneTest.java | 52 +- .../telephony/metrics/PerSimStatusTest.java | 54 +- .../SubscriptionManagerServiceTest.java | 7 +- .../telephony/uicc/UiccProfileTest.java | 7 - .../internal/telephony/uicc/UiccSlotTest.java | 52 +- 61 files changed, 387 insertions(+), 11405 deletions(-) delete mode 100644 src/java/com/android/internal/telephony/SubscriptionController.java delete mode 100644 src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java delete mode 100644 tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java diff --git a/OWNERS b/OWNERS index c7cafda968..a061cf0fb5 100644 --- a/OWNERS +++ b/OWNERS @@ -17,12 +17,6 @@ tjstuart@google.com tnd@google.com xiaotonj@google.com -# Temporarily reduced the owner during refactoring -per-file SubscriptionController.java=set noparent -per-file SubscriptionController.java=jackyu@google.com,amruthr@google.com -per-file SubscriptionInfoUpdater.java=set noparent -per-file SubscriptionInfoUpdater.java=jackyu@google.com,amruthr@google.com - diff --git a/README.txt b/README.txt index 9e40b7713d..1a44beb9e0 100644 --- a/README.txt +++ b/README.txt @@ -15,7 +15,7 @@ We define several AIDL interfaces in frameworks/base/telephony/ which we implement in this directory and packages/services/Telephony. This IPC scheme allows us to run public API code in the calling process, while the telephony-related code runs in the privileged com.android.phone process. Such -implementations include PhoneInterfaceManager, SubscriptionController and +implementations include PhoneInterfaceManager, SubscriptionManagerService and others. The declaration of the com.android.phone process is in diff --git a/src/java/com/android/internal/telephony/CarrierResolver.java b/src/java/com/android/internal/telephony/CarrierResolver.java index 4036cd9aae..8a9b3e38d6 100644 --- a/src/java/com/android/internal/telephony/CarrierResolver.java +++ b/src/java/com/android/internal/telephony/CarrierResolver.java @@ -193,14 +193,14 @@ public class CarrierResolver extends Handler { } /** - * This is triggered from SubscriptionInfoUpdater after sim state change. + * This is triggered from UiccController after sim state change. * The sequence of sim loading would be * 1. OnSubscriptionsChangedListener * 2. ACTION_SIM_STATE_CHANGED/ACTION_SIM_CARD_STATE_CHANGED * /ACTION_SIM_APPLICATION_STATE_CHANGED * 3. ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED * - * For SIM refresh either reset or init refresh type, SubscriptionInfoUpdater will re-trigger + * For SIM refresh either reset or init refresh type, UiccController will re-trigger * carrier identification with sim loaded state. Framework today silently handle single file * refresh type. * TODO: check fileId from single file refresh, if the refresh file is IMSI, gid1 or other @@ -549,12 +549,7 @@ public class CarrierResolver extends Handler { // subscriptioninfo db to make sure we have correct carrier id set. if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId()) && !isSimOverride) { // only persist carrier id to simInfo db when subId is valid. - if (mPhone.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().setCarrierId(mPhone.getSubId(), - mCarrierId); - } else { - SubscriptionController.getInstance().setCarrierId(mCarrierId, mPhone.getSubId()); - } + SubscriptionManagerService.getInstance().setCarrierId(mPhone.getSubId(), mCarrierId); } } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 1ff3593dcb..2c2b6e632a 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -369,18 +369,13 @@ public class GsmCdmaPhone extends Phone { mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, null); mSST.getServiceStateStats().registerDataNetworkControllerCallback(); - if (isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService.registerCallback(new SubscriptionManagerServiceCallback( - this::post) { - @Override - public void onUiccApplicationsEnabledChanged(int subId) { - reapplyUiccAppsEnablementIfNeeded(ENABLE_UICC_APPS_MAX_RETRIES); - } - }); - } else { - SubscriptionController.getInstance().registerForUiccAppsEnabled(this, - EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false); - } + mSubscriptionManagerService.registerCallback(new SubscriptionManagerServiceCallback( + this::post) { + @Override + public void onUiccApplicationsEnabledChanged(int subId) { + reapplyUiccAppsEnablementIfNeeded(ENABLE_UICC_APPS_MAX_RETRIES); + } + }); mLinkBandwidthEstimator = mTelephonyComponentFactory .inject(LinkBandwidthEstimator.class.getName()) @@ -493,9 +488,7 @@ public class GsmCdmaPhone extends Phone { mCDM = new CarrierKeyDownloadManager(this); mCIM = new CarrierInfoManager(); - if (isSubscriptionManagerServiceEnabled()) { - initializeCarrierApps(); - } + initializeCarrierApps(); } private void initRatSpecific(int precisePhoneType) { @@ -546,11 +539,7 @@ public class GsmCdmaPhone extends Phone { logd("update icc_operator_numeric=" + operatorNumeric); tm.setSimOperatorNumericForPhone(mPhoneId, operatorNumeric); - if (isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService.setMccMnc(getSubId(), operatorNumeric); - } else { - SubscriptionController.getInstance().setMccMnc(operatorNumeric, getSubId()); - } + mSubscriptionManagerService.setMccMnc(getSubId(), operatorNumeric); // Sets iso country property by retrieving from build-time system property String iso = ""; @@ -562,11 +551,7 @@ public class GsmCdmaPhone extends Phone { logd("init: set 'gsm.sim.operator.iso-country' to iso=" + iso); tm.setSimCountryIsoForPhone(mPhoneId, iso); - if (isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService.setCountryIso(getSubId(), iso); - } else { - SubscriptionController.getInstance().setCountryIso(iso, getSubId()); - } + mSubscriptionManagerService.setCountryIso(getSubId(), iso); // Updates MCC MNC device configuration information logd("update mccmnc=" + operatorNumeric); @@ -4898,18 +4883,12 @@ public class GsmCdmaPhone extends Phone { return; } - SubscriptionInfo info; - if (isSubscriptionManagerServiceEnabled()) { - info = mSubscriptionManagerService - .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) - .stream() - .filter(subInfo -> subInfo.getIccId().equals(IccUtils.stripTrailingFs(iccId))) - .findFirst() - .orElse(null); - } else { - info = SubscriptionController.getInstance().getSubInfoForIccId( - IccUtils.stripTrailingFs(iccId)); - } + SubscriptionInfo info = mSubscriptionManagerService + .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) + .stream() + .filter(subInfo -> subInfo.getIccId().equals(IccUtils.stripTrailingFs(iccId))) + .findFirst() + .orElse(null); logd("reapplyUiccAppsEnablementIfNeeded: retries=" + retries + ", subInfo=" + info); @@ -5014,18 +4993,10 @@ public class GsmCdmaPhone extends Phone { config.getBoolean(CarrierConfigManager.KEY_VONR_ON_BY_DEFAULT_BOOL); int setting = -1; - if (isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = mSubscriptionManagerService - .getSubscriptionInfoInternal(getSubId()); - if (subInfo != null) { - setting = subInfo.getNrAdvancedCallingEnabled(); - } - } else { - String result = SubscriptionController.getInstance().getSubscriptionProperty( - getSubId(), SubscriptionManager.NR_ADVANCED_CALLING_ENABLED); - if (result != null) { - setting = Integer.parseInt(result); - } + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(getSubId()); + if (subInfo != null) { + setting = subInfo.getNrAdvancedCallingEnabled(); } logd("VoNR setting from telephony.db:" diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java index 7e87b5fa2a..0acae4b56d 100644 --- a/src/java/com/android/internal/telephony/MultiSimSettingController.java +++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java @@ -120,7 +120,6 @@ public class MultiSimSettingController extends Handler { private static final int PRIMARY_SUB_REMOVED_IN_GROUP = 7; protected final Context mContext; - protected final SubscriptionController mSubController; private final SubscriptionManagerService mSubscriptionManagerService; // Keep a record of active primary (non-opportunistic) subscription list. @@ -129,12 +128,7 @@ public class MultiSimSettingController extends Handler { /** The singleton instance. */ protected static MultiSimSettingController sInstance = null; - // This will be set true when handling EVENT_ALL_SUBSCRIPTIONS_LOADED. The reason of keeping - // a local variable instead of calling SubscriptionInfoUpdater#isSubInfoInitialized is, there - // might be a race condition that we receive EVENT_SUBSCRIPTION_INFO_CHANGED first, then - // EVENT_ALL_SUBSCRIPTIONS_LOADED. And calling SubscriptionInfoUpdater#isSubInfoInitialized - // will make us handle EVENT_SUBSCRIPTION_INFO_CHANGED unexpectedly and causing us to believe - // the SIMs are newly inserted instead of being initialized. + // This will be set true when handling EVENT_ALL_SUBSCRIPTIONS_LOADED. private boolean mSubInfoInitialized = false; // mInitialHandling is to make sure we don't always ask user to re-select data SIM after reboot. @@ -206,10 +200,10 @@ public class MultiSimSettingController extends Handler { /** * Init instance of MultiSimSettingController. */ - public static MultiSimSettingController init(Context context, SubscriptionController sc) { + public static MultiSimSettingController init(Context context) { synchronized (MultiSimSettingController.class) { if (sInstance == null) { - sInstance = new MultiSimSettingController(context, sc); + sInstance = new MultiSimSettingController(context); } else { Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance); } @@ -218,9 +212,8 @@ public class MultiSimSettingController extends Handler { } @VisibleForTesting - public MultiSimSettingController(Context context, SubscriptionController sc) { + public MultiSimSettingController(Context context) { mContext = context; - mSubController = sc; mSubscriptionManagerService = SubscriptionManagerService.getInstance(); // Initialize mCarrierConfigLoadedSubIds and register to listen to carrier config change. @@ -346,26 +339,15 @@ public class MultiSimSettingController extends Handler { // Make sure MOBILE_DATA of subscriptions in same group are synced. setUserDataEnabledForGroup(subId, enable); - SubscriptionInfo subInfo = null; - int defaultDataSubId; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId); - defaultDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); - } else { - subInfo = mSubController.getSubscriptionInfo(subId); - defaultDataSubId = mSubController.getDefaultDataSubId(); - } + SubscriptionInfo subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId); + int defaultDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); // If user is enabling a non-default non-opportunistic subscription, make it default. if (defaultDataSubId != subId && subInfo != null && !subInfo.isOpportunistic() && enable && subInfo.isActive() && setDefaultData) { android.provider.Settings.Global.putInt(mContext.getContentResolver(), SETTING_USER_PREF_DATA_SUB, subId); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService.setDefaultDataSubId(subId); - } else { - mSubController.setDefaultDataSubId(subId); - } + mSubscriptionManagerService.setDefaultDataSubId(subId); } } @@ -376,13 +358,8 @@ public class MultiSimSettingController extends Handler { if (DBG) log("onRoamingDataEnabled"); setRoamingDataEnabledForGroup(subId, enable); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - // Also inform SubscriptionController as it keeps another copy of user setting. - mSubscriptionManagerService.setDataRoaming(enable ? 1 : 0, subId); - } else { - // Also inform SubscriptionController as it keeps another copy of user setting. - mSubController.setDataRoaming(enable ? 1 : 0, subId); - } + // Also inform SubscriptionManagerService as it keeps another copy of user setting. + mSubscriptionManagerService.setDataRoaming(enable ? 1 : 0, subId); } /** @@ -457,12 +434,7 @@ public class MultiSimSettingController extends Handler { */ @VisibleForTesting public boolean isCarrierConfigLoadedForAllSub() { - int[] activeSubIds; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - activeSubIds = mSubscriptionManagerService.getActiveSubIdList(false); - } else { - activeSubIds = mSubController.getActiveSubIdList(false); - } + int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(false); for (int activeSubId : activeSubIds) { boolean isLoaded = false; for (int configLoadedSub : mCarrierConfigLoadedSubIds) { @@ -529,17 +501,9 @@ public class MultiSimSettingController extends Handler { private void onSubscriptionGroupChanged(ParcelUuid groupUuid) { if (DBG) log("onSubscriptionGroupChanged"); - List infoList; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - infoList = mSubscriptionManagerService.getSubscriptionsInGroup( - groupUuid, mContext.getOpPackageName(), mContext.getAttributionTag()); - if (infoList == null || infoList.isEmpty()) return; - - } else { - infoList = mSubController.getSubscriptionsInGroup( - groupUuid, mContext.getOpPackageName(), mContext.getAttributionTag()); - if (infoList == null || infoList.isEmpty()) return; - } + List infoList = mSubscriptionManagerService.getSubscriptionsInGroup( + groupUuid, mContext.getOpPackageName(), mContext.getAttributionTag()); + if (infoList == null || infoList.isEmpty()) return; // Get a reference subscription to copy settings from. // TODO: the reference sub should be passed in from external caller. @@ -564,14 +528,9 @@ public class MultiSimSettingController extends Handler { mContext, Settings.Global.MOBILE_DATA, INVALID_SUBSCRIPTION_ID, enable); } boolean setDefaultData = true; - List activeSubList; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - activeSubList = mSubscriptionManagerService.getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - } else { - activeSubList = mSubController.getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - } + List activeSubList = mSubscriptionManagerService + .getActiveSubscriptionInfoList(mContext.getOpPackageName(), + mContext.getAttributionTag()); for (SubscriptionInfo activeInfo : activeSubList) { if (!(groupUuid.equals(activeInfo.getGroupUuid()))) { // Do not set refSubId as defaultDataSubId if there are other active @@ -594,12 +553,7 @@ public class MultiSimSettingController extends Handler { onRoamingDataEnabled(refSubId, enable); } - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService.syncGroupedSetting(refSubId); - } else { - // Sync settings in subscription database.. - mSubController.syncGroupedSetting(refSubId); - } + mSubscriptionManagerService.syncGroupedSetting(refSubId); } /** @@ -621,34 +575,20 @@ public class MultiSimSettingController extends Handler { if (!isReadyToReevaluate()) return; - List activeSubInfos; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - activeSubInfos = mSubscriptionManagerService.getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - - if (ArrayUtils.isEmpty(activeSubInfos)) { - mPrimarySubList.clear(); - if (DBG) log("updateDefaults: No active sub. Setting default to INVALID sub."); - mSubscriptionManagerService.setDefaultDataSubId( - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mSubscriptionManagerService.setDefaultVoiceSubId( - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mSubscriptionManagerService.setDefaultSmsSubId( - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - return; - } - } else { - activeSubInfos = mSubController.getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - - if (ArrayUtils.isEmpty(activeSubInfos)) { - mPrimarySubList.clear(); - if (DBG) log("updateDefaultValues: No active sub. Setting default to INVALID sub."); - mSubController.setDefaultDataSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mSubController.setDefaultVoiceSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mSubController.setDefaultSmsSubId(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - return; - } + List activeSubInfos = mSubscriptionManagerService + .getActiveSubscriptionInfoList(mContext.getOpPackageName(), + mContext.getAttributionTag()); + + if (ArrayUtils.isEmpty(activeSubInfos)) { + mPrimarySubList.clear(); + if (DBG) log("updateDefaults: No active sub. Setting default to INVALID sub."); + mSubscriptionManagerService.setDefaultDataSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mSubscriptionManagerService.setDefaultVoiceSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mSubscriptionManagerService.setDefaultSmsSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + return; } int change = updatePrimarySubListAndGetChangeType(activeSubInfos); @@ -665,15 +605,9 @@ public class MultiSimSettingController extends Handler { .getActiveModemCount() == 1)) { int subId = mPrimarySubList.get(0); if (DBG) log("updateDefaultValues: to only primary sub " + subId); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService.setDefaultDataSubId(subId); - mSubscriptionManagerService.setDefaultVoiceSubId(subId); - mSubscriptionManagerService.setDefaultSmsSubId(subId); - } else { - mSubController.setDefaultDataSubId(subId); - mSubController.setDefaultVoiceSubId(subId); - mSubController.setDefaultSmsSubId(subId); - } + mSubscriptionManagerService.setDefaultDataSubId(subId); + mSubscriptionManagerService.setDefaultVoiceSubId(subId); + mSubscriptionManagerService.setDefaultSmsSubId(subId); sendDefaultSubConfirmedNotification(subId); return; } @@ -682,45 +616,24 @@ public class MultiSimSettingController extends Handler { boolean dataSelected, voiceSelected, smsSelected; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - // Update default data subscription. - if (DBG) log("updateDefaultValues: Update default data subscription"); - dataSelected = updateDefaultValue(mPrimarySubList, - mSubscriptionManagerService.getDefaultDataSubId(), - mSubscriptionManagerService::setDefaultDataSubId); - - // Update default voice subscription. - if (DBG) log("updateDefaultValues: Update default voice subscription"); - voiceSelected = updateDefaultValue(mPrimarySubList, - mSubscriptionManagerService.getDefaultVoiceSubId(), - mSubscriptionManagerService::setDefaultVoiceSubId); - - // Update default sms subscription. - if (DBG) log("updateDefaultValues: Update default sms subscription"); - smsSelected = updateDefaultValue(mPrimarySubList, - mSubscriptionManagerService.getDefaultSmsSubId(), - mSubscriptionManagerService::setDefaultSmsSubId, - mIsAskEverytimeSupportedForSms); - } else { - // Update default data subscription. - if (DBG) log("updateDefaultValues: Update default data subscription"); - dataSelected = updateDefaultValue(mPrimarySubList, - mSubController.getDefaultDataSubId(), - mSubController::setDefaultDataSubId); - - // Update default voice subscription. - if (DBG) log("updateDefaultValues: Update default voice subscription"); - voiceSelected = updateDefaultValue(mPrimarySubList, - mSubController.getDefaultVoiceSubId(), - mSubController::setDefaultVoiceSubId); - - // Update default sms subscription. - if (DBG) log("updateDefaultValues: Update default sms subscription"); - smsSelected = updateDefaultValue(mPrimarySubList, - mSubController.getDefaultSmsSubId(), - mSubController::setDefaultSmsSubId, - mIsAskEverytimeSupportedForSms); - } + // Update default data subscription. + if (DBG) log("updateDefaultValues: Update default data subscription"); + dataSelected = updateDefaultValue(mPrimarySubList, + mSubscriptionManagerService.getDefaultDataSubId(), + mSubscriptionManagerService::setDefaultDataSubId); + + // Update default voice subscription. + if (DBG) log("updateDefaultValues: Update default voice subscription"); + voiceSelected = updateDefaultValue(mPrimarySubList, + mSubscriptionManagerService.getDefaultVoiceSubId(), + mSubscriptionManagerService::setDefaultVoiceSubId); + + // Update default sms subscription. + if (DBG) log("updateDefaultValues: Update default sms subscription"); + smsSelected = updateDefaultValue(mPrimarySubList, + mSubscriptionManagerService.getDefaultSmsSubId(), + mSubscriptionManagerService::setDefaultSmsSubId, + mIsAskEverytimeSupportedForSms); boolean autoFallbackEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_voice_data_sms_auto_fallback); @@ -771,12 +684,7 @@ public class MultiSimSettingController extends Handler { // any previous primary subscription becomes inactive, we consider it for (int subId : prevPrimarySubList) { if (mPrimarySubList.contains(subId)) continue; - SubscriptionInfo subInfo = null; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId); - } else { - subInfo = mSubController.getSubscriptionInfo(subId); - } + SubscriptionInfo subInfo = mSubscriptionManagerService.getSubscriptionInfo(subId); if (subInfo == null || !subInfo.isActive()) { for (int currentSubId : mPrimarySubList) { @@ -890,16 +798,10 @@ public class MultiSimSettingController extends Handler { if (phone != null && phone.isCdmaSubscriptionAppPresent()) { cdmaPhoneCount++; String simName = null; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = mSubscriptionManagerService - .getSubscriptionInfoInternal(subId); - if (subInfo != null) { - simName = subInfo.getDisplayName(); - } - } else { - simName = mSubController.getActiveSubscriptionInfo( - subId, mContext.getOpPackageName(), mContext.getAttributionTag()) - .getDisplayName().toString(); + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + if (subInfo != null) { + simName = subInfo.getDisplayName(); } if (TextUtils.isEmpty(simName)) { // Fall back to carrier name. @@ -925,22 +827,12 @@ public class MultiSimSettingController extends Handler { protected void disableDataForNonDefaultNonOpportunisticSubscriptions() { if (!isReadyToReevaluate()) return; - int defaultDataSub; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - defaultDataSub = mSubscriptionManagerService.getDefaultDataSubId(); - } else { - defaultDataSub = mSubController.getDefaultDataSubId(); - } + int defaultDataSub = mSubscriptionManagerService.getDefaultDataSubId(); for (Phone phone : PhoneFactory.getPhones()) { - boolean isOpportunistic; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = mSubscriptionManagerService - .getSubscriptionInfoInternal(phone.getSubId()); - isOpportunistic = subInfo != null && subInfo.isOpportunistic(); - } else { - isOpportunistic = mSubController.isOpportunistic(phone.getSubId()); - } + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(phone.getSubId()); + boolean isOpportunistic = subInfo != null && subInfo.isOpportunistic(); if (phone.getSubId() != defaultDataSub && SubscriptionManager.isValidSubscriptionId(phone.getSubId()) && !isOpportunistic @@ -959,19 +851,13 @@ public class MultiSimSettingController extends Handler { || !SubscriptionManager.isUsableSubscriptionId(subId2)) return false; if (subId1 == subId2) return true; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo1 = - mSubscriptionManagerService.getSubscriptionInfoInternal(subId1); - SubscriptionInfoInternal subInfo2 = - mSubscriptionManagerService.getSubscriptionInfoInternal(subId2); - return subInfo1 != null && subInfo2 != null - && !TextUtils.isEmpty(subInfo1.getGroupUuid()) - && subInfo1.getGroupUuid().equals(subInfo2.getGroupUuid()); - } else { - ParcelUuid groupUuid1 = mSubController.getGroupUuid(subId1); - ParcelUuid groupUuid2 = mSubController.getGroupUuid(subId2); - return groupUuid1 != null && groupUuid1.equals(groupUuid2); - } + SubscriptionInfoInternal subInfo1 = + mSubscriptionManagerService.getSubscriptionInfoInternal(subId1); + SubscriptionInfoInternal subInfo2 = + mSubscriptionManagerService.getSubscriptionInfoInternal(subId2); + return subInfo1 != null && subInfo2 != null + && !TextUtils.isEmpty(subInfo1.getGroupUuid()) + && subInfo1.getGroupUuid().equals(subInfo2.getGroupUuid()); } /** @@ -981,17 +867,11 @@ public class MultiSimSettingController extends Handler { protected void setUserDataEnabledForGroup(int subId, boolean enable) { log("setUserDataEnabledForGroup subId " + subId + " enable " + enable); List infoList = null; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = mSubscriptionManagerService - .getSubscriptionInfoInternal(subId); - if (subInfo != null && !subInfo.getGroupUuid().isEmpty()) { - infoList = mSubscriptionManagerService.getSubscriptionsInGroup( - ParcelUuid.fromString(subInfo.getGroupUuid()), mContext.getOpPackageName(), - mContext.getAttributionTag()); - } - } else { - infoList = mSubController.getSubscriptionsInGroup( - mSubController.getGroupUuid(subId), mContext.getOpPackageName(), + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + if (subInfo != null && !subInfo.getGroupUuid().isEmpty()) { + infoList = mSubscriptionManagerService.getSubscriptionsInGroup( + ParcelUuid.fromString(subInfo.getGroupUuid()), mContext.getOpPackageName(), mContext.getAttributionTag()); } @@ -1002,13 +882,8 @@ public class MultiSimSettingController extends Handler { // TODO: simplify when setUserDataEnabled becomes singleton if (info.isActive()) { // For active subscription, call setUserDataEnabled through DataSettingsManager. - Phone phone; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - phone = PhoneFactory.getPhone(mSubscriptionManagerService - .getPhoneId(currentSubId)); - } else { - phone = PhoneFactory.getPhone(mSubController.getPhoneId(currentSubId)); - } + Phone phone = PhoneFactory.getPhone(mSubscriptionManagerService + .getPhoneId(currentSubId)); // If enable is true and it's not opportunistic subscription, we don't enable it, // as there can't be two if (phone != null) { @@ -1029,19 +904,12 @@ public class MultiSimSettingController extends Handler { * are synced. */ private void setRoamingDataEnabledForGroup(int subId, boolean enable) { - List infoList; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = mSubscriptionManagerService - .getSubscriptionInfoInternal(subId); - if (subInfo == null || subInfo.getGroupUuid().isEmpty()) return; - infoList = SubscriptionManagerService.getInstance().getSubscriptionsInGroup( - ParcelUuid.fromString(subInfo.getGroupUuid()), mContext.getOpPackageName(), - mContext.getAttributionTag()); - } else { - infoList = SubscriptionController.getInstance().getSubscriptionsInGroup( - mSubController.getGroupUuid(subId), mContext.getOpPackageName(), - mContext.getAttributionTag()); - } + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + if (subInfo == null || subInfo.getGroupUuid().isEmpty()) return; + List infoList = SubscriptionManagerService.getInstance() + .getSubscriptionsInGroup(ParcelUuid.fromString(subInfo.getGroupUuid()), + mContext.getOpPackageName(), mContext.getAttributionTag()); if (infoList == null) return; for (SubscriptionInfo info : infoList) { @@ -1094,19 +962,10 @@ public class MultiSimSettingController extends Handler { // subscription gets deactivated or removed, we need to automatically disable the grouped // opportunistic subscription, which will be marked isGroupDisabled as true by SubController. private void deactivateGroupedOpportunisticSubscriptionIfNeeded() { - if (!SubscriptionInfoUpdater.isSubInfoInitialized()) return; - - List opptSubList; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - opptSubList = mSubscriptionManagerService.getAllSubInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()).stream() - .filter(SubscriptionInfo::isOpportunistic) - .collect(Collectors.toList()); - - } else { - opptSubList = mSubController.getOpportunisticSubscriptions( - mContext.getOpPackageName(), mContext.getAttributionTag()); - } + List opptSubList = mSubscriptionManagerService.getAllSubInfoList( + mContext.getOpPackageName(), mContext.getAttributionTag()).stream() + .filter(SubscriptionInfo::isOpportunistic) + .collect(Collectors.toList()); if (ArrayUtils.isEmpty(opptSubList)) return; @@ -1142,101 +1001,54 @@ public class MultiSimSettingController extends Handler { // would be selected as preferred voice/data/sms SIM. private void updateUserPreferences(List primarySubList, boolean dataSelected, boolean voiceSelected, boolean smsSelected) { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - - // In Single SIM case or if there are no activated subs available, no need to update. - // EXIT. - if ((primarySubList.isEmpty()) || (mSubscriptionManagerService - .getActiveSubInfoCountMax() == 1)) { - return; - } - - if (!isRadioAvailableOnAllSubs()) { - log("Radio is in Invalid state, Ignore Updating User Preference!!!"); - return; - } - final int defaultDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); - - if (DBG) { - log("updateUserPreferences: dds = " + defaultDataSubId + " voice = " - + mSubscriptionManagerService.getDefaultVoiceSubId() - + " sms = " + mSubscriptionManagerService.getDefaultSmsSubId()); - } - - int autoDefaultSubId = primarySubList.get(0); - - if ((primarySubList.size() == 1) && !smsSelected) { - mSubscriptionManagerService.setDefaultSmsSubId(autoDefaultSubId); - } - - if ((primarySubList.size() == 1) && !voiceSelected) { - mSubscriptionManagerService.setDefaultVoiceSubId(autoDefaultSubId); - } - - int userPrefDataSubId = getUserPrefDataSubIdFromDB(); - - log("User pref subId = " + userPrefDataSubId + " current dds " + defaultDataSubId - + " next active subId " + autoDefaultSubId); - - // If earlier user selected DDS is now available, set that as DDS subId. - if (primarySubList.contains(userPrefDataSubId) - && SubscriptionManager.isValidSubscriptionId(userPrefDataSubId) - && (defaultDataSubId != userPrefDataSubId)) { - mSubscriptionManagerService.setDefaultDataSubId(userPrefDataSubId); - } else if (!dataSelected) { - mSubscriptionManagerService.setDefaultDataSubId(autoDefaultSubId); - } - - if (DBG) { - log("updateUserPreferences: after dds = " - + mSubscriptionManagerService.getDefaultDataSubId() + " voice = " - + mSubscriptionManagerService.getDefaultVoiceSubId() + " sms = " - + mSubscriptionManagerService.getDefaultSmsSubId()); - } + // In Single SIM case or if there are no activated subs available, no need to update. + // EXIT. + if ((primarySubList.isEmpty()) || (mSubscriptionManagerService + .getActiveSubInfoCountMax() == 1)) { return; } - // In Single SIM case or if there are no activated subs available, no need to update. EXIT. - if ((primarySubList.isEmpty()) || (mSubController.getActiveSubInfoCountMax() == 1)) return; if (!isRadioAvailableOnAllSubs()) { log("Radio is in Invalid state, Ignore Updating User Preference!!!"); return; } - final int defaultDataSubId = mSubController.getDefaultDataSubId(); + final int defaultDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); - if (DBG) log("updateUserPreferences: dds = " + defaultDataSubId + " voice = " - + mSubController.getDefaultVoiceSubId() + - " sms = " + mSubController.getDefaultSmsSubId()); + if (DBG) { + log("updateUserPreferences: dds = " + defaultDataSubId + " voice = " + + mSubscriptionManagerService.getDefaultVoiceSubId() + + " sms = " + mSubscriptionManagerService.getDefaultSmsSubId()); + } int autoDefaultSubId = primarySubList.get(0); if ((primarySubList.size() == 1) && !smsSelected) { - mSubController.setDefaultSmsSubId(autoDefaultSubId); + mSubscriptionManagerService.setDefaultSmsSubId(autoDefaultSubId); } if ((primarySubList.size() == 1) && !voiceSelected) { - mSubController.setDefaultVoiceSubId(autoDefaultSubId); + mSubscriptionManagerService.setDefaultVoiceSubId(autoDefaultSubId); } int userPrefDataSubId = getUserPrefDataSubIdFromDB(); - if (DBG) log("User pref subId = " + userPrefDataSubId + " current dds " + defaultDataSubId - + " next active subId " + autoDefaultSubId); + log("User pref subId = " + userPrefDataSubId + " current dds " + defaultDataSubId + + " next active subId " + autoDefaultSubId); // If earlier user selected DDS is now available, set that as DDS subId. - if (primarySubList.contains(userPrefDataSubId) && - SubscriptionManager.isValidSubscriptionId(userPrefDataSubId) && - (defaultDataSubId != userPrefDataSubId)) { - mSubController.setDefaultDataSubId(userPrefDataSubId); + if (primarySubList.contains(userPrefDataSubId) + && SubscriptionManager.isValidSubscriptionId(userPrefDataSubId) + && (defaultDataSubId != userPrefDataSubId)) { + mSubscriptionManagerService.setDefaultDataSubId(userPrefDataSubId); } else if (!dataSelected) { - mSubController.setDefaultDataSubId(autoDefaultSubId); + mSubscriptionManagerService.setDefaultDataSubId(autoDefaultSubId); } - if (DBG) { - log("updateUserPreferences: after dds = " + mSubController.getDefaultDataSubId() - + " voice = " + mSubController.getDefaultVoiceSubId() + " sms = " - + mSubController.getDefaultSmsSubId()); + log("updateUserPreferences: after dds = " + + mSubscriptionManagerService.getDefaultDataSubId() + " voice = " + + mSubscriptionManagerService.getDefaultVoiceSubId() + " sms = " + + mSubscriptionManagerService.getDefaultSmsSubId()); } } diff --git a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java index b15dc594b3..25dd01a50e 100644 --- a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java +++ b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java @@ -197,14 +197,7 @@ public final class NetworkScanRequestTracker { public static Set getAllowedMccMncsForLocationRestrictedScan(Context context) { final long token = Binder.clearCallingIdentity(); try { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - return SubscriptionManagerService.getInstance() - .getAvailableSubscriptionInfoList(context.getOpPackageName(), - context.getAttributionTag()).stream() - .flatMap(NetworkScanRequestTracker::getAllowableMccMncsFromSubscriptionInfo) - .collect(Collectors.toSet()); - } - return SubscriptionController.getInstance() + return SubscriptionManagerService.getInstance() .getAvailableSubscriptionInfoList(context.getOpPackageName(), context.getAttributionTag()).stream() .flatMap(NetworkScanRequestTracker::getAllowableMccMncsFromSubscriptionInfo) diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 34f1c51c4e..599f2b281a 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -42,7 +42,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; import android.preference.PreferenceManager; -import android.provider.DeviceConfig; import android.sysprop.TelephonyProperties; import android.telecom.VideoProfile; import android.telephony.AccessNetworkConstants; @@ -381,12 +380,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private int mUsageSettingFromModem = SubscriptionManager.USAGE_SETTING_UNKNOWN; private boolean mIsUsageSettingSupported = true; - /** - * {@code true} if the new SubscriptionManagerService is enabled, otherwise the old - * SubscriptionController is used. - */ - private boolean mIsSubscriptionManagerServiceEnabled = false; - //IMS /** * {@link CallStateException} message text used to indicate that an IMS call has failed because @@ -631,14 +624,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { // Initialize SMS stats mSmsStats = new SmsStats(this); - // This is a temp flag which will be removed before U AOSP public release. - mIsSubscriptionManagerServiceEnabled = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_using_subscription_manager_service) - || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, - "enable_subscription_manager_service", false); - if (isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService = SubscriptionManagerService.getInstance(); - } + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); m2gAdminUpdater = new TelephonyAdminReceiver(context, this); if (getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { @@ -2410,21 +2396,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ public void loadAllowedNetworksFromSubscriptionDatabase() { String result = null; - if (isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = mSubscriptionManagerService - .getSubscriptionInfoInternal(getSubId()); - if (subInfo != null) { - result = subInfo.getAllowedNetworkTypesForReasons(); - } - } else { - // Try to load ALLOWED_NETWORK_TYPES from SIMINFO. - if (SubscriptionController.getInstance() == null) { - return; - } - - result = SubscriptionController.getInstance().getSubscriptionProperty( - getSubId(), - SubscriptionManager.ALLOWED_NETWORK_TYPES); + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(getSubId()); + if (subInfo != null) { + result = subInfo.getAllowedNetworkTypesForReasons(); } // After fw load network type from DB, do unlock if subId is valid. @@ -4119,17 +4094,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { */ @UnsupportedAppUsage public int getSubId() { - if (isSubscriptionManagerServiceEnabled()) { - return mSubscriptionManagerService.getSubId(mPhoneId); - } - if (SubscriptionController.getInstance() == null) { - // TODO b/78359408 getInstance sometimes returns null in Treehugger tests, which causes - // flakiness. Even though we haven't seen this crash in the wild we should keep this - // check in until we've figured out the root cause. - Rlog.e(LOG_TAG, "SubscriptionController.getInstance = null! Returning default subId"); - return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; - } - return SubscriptionController.getInstance().getSubId(mPhoneId); + return mSubscriptionManagerService.getSubId(mPhoneId); } /** @@ -4445,14 +4410,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private int getResolvedUsageSetting(int subId) { SubscriptionInfo subInfo = null; - if (isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfoInternal = mSubscriptionManagerService - .getSubscriptionInfoInternal(subId); - if (subInfoInternal != null) { - subInfo = subInfoInternal.toSubscriptionInfo(); - } - } else { - subInfo = SubscriptionController.getInstance().getSubscriptionInfo(subId); + SubscriptionInfoInternal subInfoInternal = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + if (subInfoInternal != null) { + subInfo = subInfoInternal.toSubscriptionInfo(); } if (subInfo == null @@ -5151,14 +5112,6 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return mTelephonyTester; } - /** - * @return {@code true} if the new {@link SubscriptionManagerService} is enabled, otherwise the - * old {@link SubscriptionController} is used. - */ - public boolean isSubscriptionManagerServiceEnabled() { - return mIsSubscriptionManagerServiceEnabled; - } - /** * @return User handle associated with the phone's subscription id. {@code null} if subscription * is invalid or not found. diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java index 6f428724c1..8b9582419e 100644 --- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java +++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java @@ -385,11 +385,7 @@ public class PhoneConfigurationManager { // eg if we are going from 2 phones to 1 phone, we need to deregister RIL for the // second phone. This loop does nothing if numOfActiveModems is increasing. for (int phoneId = numOfActiveModems; phoneId < oldNumOfActiveModems; phoneId++) { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().markSubscriptionsInactive(phoneId); - } else { - SubscriptionController.getInstance().clearSubInfoRecord(phoneId); - } + SubscriptionManagerService.getInstance().markSubscriptionsInactive(phoneId); subInfoCleared = true; mPhones[phoneId].mCi.onSlotActiveStatusChange( SubscriptionManager.isValidPhoneId(phoneId)); @@ -423,13 +419,8 @@ public class PhoneConfigurationManager { + "setting VOICE & SMS subId to -1 (No Preference)"); //Set the default VOICE subId to -1 ("No Preference") - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().setDefaultVoiceSubId( - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - } else { - SubscriptionController.getInstance().setDefaultVoiceSubId( - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - } + SubscriptionManagerService.getInstance().setDefaultVoiceSubId( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); //TODO:: Set the default SMS sub to "No Preference". Tracking this bug (b/227386042) } else { diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java index e92660797d..57a375b9b4 100644 --- a/src/java/com/android/internal/telephony/PhoneFactory.java +++ b/src/java/com/android/internal/telephony/PhoneFactory.java @@ -31,10 +31,8 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.LocalServerSocket; import android.os.Build; -import android.os.HandlerThread; import android.os.Looper; import android.preference.PreferenceManager; -import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.telephony.AnomalyReporter; @@ -89,8 +87,6 @@ public class PhoneFactory { private static @Nullable EuiccCardController sEuiccCardController; private static SubscriptionManagerService sSubscriptionManagerService; - static private SubscriptionInfoUpdater sSubInfoRecordUpdater = null; - @UnsupportedAppUsage static private boolean sMadeDefaults = false; @UnsupportedAppUsage @@ -107,8 +103,6 @@ public class PhoneFactory { private static MetricsCollector sMetricsCollector; private static RadioInterfaceCapabilityController sRadioHalCapabilities; - private static boolean sSubscriptionManagerServiceEnabled = false; - //***** Class Methods public static void makeDefaultPhones(Context context) { @@ -125,12 +119,6 @@ public class PhoneFactory { if (!sMadeDefaults) { sContext = context; - // This is a temp flag which will be removed before U AOSP public release. - sSubscriptionManagerServiceEnabled = context.getResources().getBoolean( - com.android.internal.R.bool.config_using_subscription_manager_service) - || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, - "enable_subscription_manager_service", false); - // create the telephony device controller. TelephonyDevController.create(); @@ -208,24 +196,12 @@ public class PhoneFactory { // call getInstance() sUiccController = UiccController.make(context); - - if (isSubscriptionManagerServiceEnabled()) { - Rlog.i(LOG_TAG, "Creating SubscriptionManagerService"); - sSubscriptionManagerService = new SubscriptionManagerService(context, - Looper.myLooper()); - } else { - Rlog.i(LOG_TAG, "Creating SubscriptionController"); - TelephonyComponentFactory.getInstance().inject(SubscriptionController.class - .getName()).initSubscriptionController(context); - } - - SubscriptionController sc = null; - if (!isSubscriptionManagerServiceEnabled()) { - sc = SubscriptionController.getInstance(); - } + Rlog.i(LOG_TAG, "Creating SubscriptionManagerService"); + sSubscriptionManagerService = new SubscriptionManagerService(context, + Looper.myLooper()); TelephonyComponentFactory.getInstance().inject(MultiSimSettingController.class. - getName()).initMultiSimSettingController(context, sc); + getName()).initMultiSimSettingController(context); if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY_EUICC)) { @@ -257,16 +233,6 @@ public class PhoneFactory { sMadeDefaults = true; - if (!isSubscriptionManagerServiceEnabled()) { - Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater "); - HandlerThread pfhandlerThread = new HandlerThread("PhoneFactoryHandlerThread"); - pfhandlerThread.start(); - sSubInfoRecordUpdater = TelephonyComponentFactory.getInstance().inject( - SubscriptionInfoUpdater.class.getName()) - .makeSubscriptionInfoUpdater(pfhandlerThread.getLooper(), context, - SubscriptionController.getInstance()); - } - // Only bring up IMS if the device supports having an IMS stack. if (context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY_IMS)) { @@ -305,14 +271,6 @@ public class PhoneFactory { } } - /** - * @return {@code true} if the new {@link SubscriptionManagerService} is enabled, otherwise the - * old {@link SubscriptionController} is used. - */ - public static boolean isSubscriptionManagerServiceEnabled() { - return sSubscriptionManagerServiceEnabled; - } - /** * Upon single SIM to dual SIM switch or vice versa, we dynamically allocate or de-allocate * Phone and CommandInterface objects. @@ -412,10 +370,6 @@ public class PhoneFactory { } } - public static SubscriptionInfoUpdater getSubscriptionInfoUpdater() { - return sSubInfoRecordUpdater; - } - /** * Get the network factory associated with a given phone ID. * @param phoneId the phone id @@ -452,7 +406,6 @@ public class PhoneFactory { * @param phoneId The phone's id. * @return the preferred network mode bitmask that should be set. */ - // TODO: Fix when we "properly" have TelephonyDevController/SubscriptionController .. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static int calculatePreferredNetworkType(int phoneId) { if (getPhone(phoneId) == null) { @@ -469,10 +422,7 @@ public class PhoneFactory { /* Gets the default subscription */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static int getDefaultSubscription() { - if (isSubscriptionManagerServiceEnabled()) { - return SubscriptionManagerService.getInstance().getDefaultSubId(); - } - return SubscriptionController.getInstance().getDefaultSubId(); + return SubscriptionManagerService.getInstance().getDefaultSubId(); } /* Returns User SMS Prompt property, enabled or not */ @@ -500,19 +450,7 @@ public class PhoneFactory { } /** - * Request a refresh of the embedded subscription list. - * - * @param cardId the card ID of the eUICC. - * @param callback Optional callback to execute after the refresh completes. Must terminate - * quickly as it will be called from SubscriptionInfoUpdater's handler thread. - */ - public static void requestEmbeddedSubscriptionInfoListRefresh( - int cardId, @Nullable Runnable callback) { - sSubInfoRecordUpdater.requestEmbeddedSubscriptionInfoListRefresh(cardId, callback); - } - - /** - * Get a the SmsController. + * Get the instance of {@link SmsController}. */ public static SmsController getSmsController() { synchronized (sLockProxyPhones) { @@ -615,26 +553,6 @@ public class PhoneFactory { pw.decreaseIndent(); pw.println("++++++++++++++++++++++++++++++++"); - if (!isSubscriptionManagerServiceEnabled()) { - pw.println("SubscriptionController:"); - pw.increaseIndent(); - try { - SubscriptionController.getInstance().dump(fd, pw, args); - } catch (Exception e) { - e.printStackTrace(); - } - pw.flush(); - pw.decreaseIndent(); - pw.println("++++++++++++++++++++++++++++++++"); - - pw.println("SubInfoRecordUpdater:"); - pw.increaseIndent(); - try { - sSubInfoRecordUpdater.dump(fd, pw, args); - } catch (Exception e) { - e.printStackTrace(); - } - } pw.flush(); pw.decreaseIndent(); pw.println("++++++++++++++++++++++++++++++++"); diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java index 17055a7f47..d30a73c705 100644 --- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java +++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java @@ -159,13 +159,8 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { long identity = Binder.clearCallingIdentity(); boolean isActive; try { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId, - callingPackage, callingFeatureId); - } else { - isActive = SubscriptionController.getInstance().isActiveSubId(subId, callingPackage, - callingFeatureId); - } + isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId, + callingPackage, callingFeatureId); } finally { Binder.restoreCallingIdentity(identity); } @@ -179,15 +174,12 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { } identity = Binder.clearCallingIdentity(); try { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfoInternal(subId); - if (subInfo != null && !TextUtils.isEmpty(subInfo.getImsi())) { - return subInfo.getImsi(); - } - return null; + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(subId); + if (subInfo != null && !TextUtils.isEmpty(subInfo.getImsi())) { + return subInfo.getImsi(); } - return SubscriptionController.getInstance().getImsiPrivileged(subId); + return null; } finally { Binder.restoreCallingIdentity(identity); } diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java index 6db35595f3..a78242ad5a 100644 --- a/src/java/com/android/internal/telephony/SMSDispatcher.java +++ b/src/java/com/android/internal/telephony/SMSDispatcher.java @@ -447,14 +447,10 @@ public abstract class SMSDispatcher extends Handler { */ mMessageRef = getTpmrValueFromSIM(); if (mMessageRef == -1) { - if (mPhone.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfoInternal(msg.arg1); - if (subInfo != null) { - mMessageRef = subInfo.getLastUsedTPMessageReference(); - } - } else { - mMessageRef = SubscriptionController.getInstance().getMessageRef(msg.arg1); + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(msg.arg1); + if (subInfo != null) { + mMessageRef = subInfo.getLastUsedTPMessageReference(); } } break; @@ -477,12 +473,8 @@ public abstract class SMSDispatcher extends Handler { updateSIMLastTPMRValue(mMessageRef); final long identity = Binder.clearCallingIdentity(); try { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance() - .setLastUsedTPMessageReference(getSubId(), mMessageRef); - } else { - SubscriptionController.getInstance().updateMessageRef(getSubId(), mMessageRef); - } + SubscriptionManagerService.getInstance() + .setLastUsedTPMessageReference(getSubId(), mMessageRef); } catch (SecurityException e) { Rlog.e(TAG, "Security Exception caused on messageRef updation to DB " + e.getMessage()); } finally { diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index a18a3c92d8..e3bbe9e8e6 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -71,7 +71,6 @@ import android.telephony.PhysicalChannelConfig; import android.telephony.RadioAccessFamily; import android.telephony.ServiceState; import android.telephony.ServiceState.RilRadioTechnology; -import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; @@ -325,8 +324,6 @@ public class ServiceStateTracker extends Handler { private boolean mDeviceShuttingDown = false; /** Keep track of SPN display rules, so we only broadcast intent if something changes. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private boolean mSpnUpdatePending = false; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private String mCurSpn = null; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private String mCurDataSpn = null; @@ -345,8 +342,6 @@ public class ServiceStateTracker extends Handler { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private SubscriptionManager mSubscriptionManager; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private SubscriptionController mSubscriptionController; private SubscriptionManagerService mSubscriptionManagerService; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private final SstSubscriptionsChangedListener mOnSubscriptionsChangedListener = @@ -417,12 +412,6 @@ public class ServiceStateTracker extends Handler { setDataNetworkTypeForPhone(mSS.getRilDataRadioTechnology()); - if (mSpnUpdatePending) { - mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), mCurShowPlmn, - mCurPlmn, mCurShowSpn, mCurSpn); - mSpnUpdatePending = false; - } - // Remove old network selection sharedPreferences since SP key names are now // changed to include subId. This will be done only once when upgrading from an // older build that did not include subId in the names. @@ -651,12 +640,7 @@ public class ServiceStateTracker extends Handler { mCi.registerForCellInfoList(this, EVENT_UNSOL_CELL_INFO_LIST, null); mCi.registerForPhysicalChannelConfiguration(this, EVENT_PHYSICAL_CHANNEL_CONFIG, null); - if (mPhone.isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService = SubscriptionManagerService.getInstance(); - } else { - mSubscriptionController = SubscriptionController.getInstance(); - } - + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); mSubscriptionManager = SubscriptionManager.from(phone.getContext()); mSubscriptionManager.addOnSubscriptionsChangedListener( new android.os.HandlerExecutor(this), mOnSubscriptionsChangedListener); @@ -2798,18 +2782,10 @@ public class ServiceStateTracker extends Handler { SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL); - if (mPhone.isSubscriptionManagerServiceEnabled()) { - if (SubscriptionManager.isValidSubscriptionId(subId)) { - mSubscriptionManagerService.setCarrierName(subId, TextUtils.emptyIfNull( - getCarrierName(data.shouldShowPlmn(), data.getPlmn(), - data.shouldShowSpn(), data.getSpn()))); - } - } else { - if (!mSubscriptionController.setPlmnSpn(mPhone.getPhoneId(), - data.shouldShowPlmn(), data.getPlmn(), data.shouldShowSpn(), - data.getSpn())) { - mSpnUpdatePending = true; - } + if (SubscriptionManager.isValidSubscriptionId(subId)) { + mSubscriptionManagerService.setCarrierName(subId, TextUtils.emptyIfNull( + getCarrierName(data.shouldShowPlmn(), data.getPlmn(), + data.shouldShowSpn(), data.getSpn()))); } } mCurShowSpn = data.shouldShowSpn(); @@ -4528,23 +4504,11 @@ public class ServiceStateTracker extends Handler { } Context context = mPhone.getContext(); - if (mPhone.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = mSubscriptionManagerService - .getSubscriptionInfoInternal(mPhone.getSubId()); - if (subInfo == null || !subInfo.isVisible()) { - log("cannot setNotification on invisible subid mSubId=" + mSubId); - return; - } - } else { - SubscriptionInfo info = mSubscriptionController - .getActiveSubscriptionInfo(mPhone.getSubId(), context.getOpPackageName(), - context.getAttributionTag()); - - //if subscription is part of a group and non-primary, suppress all notifications - if (info == null || (info.isOpportunistic() && info.getGroupUuid() != null)) { - log("cannot setNotification on invisible subid mSubId=" + mSubId); - return; - } + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(mPhone.getSubId()); + if (subInfo == null || !subInfo.isVisible()) { + log("cannot setNotification on invisible subid mSubId=" + mSubId); + return; } // Needed because sprout RIL sends these when they shouldn't? @@ -5334,7 +5298,6 @@ public class ServiceStateTracker extends Handler { + hasMessages(EVENT_POWER_OFF_RADIO_IMS_DEREG_TIMEOUT)); pw.println(" mRadioPowerOffReasons=" + mRadioPowerOffReasons); pw.println(" mDeviceShuttingDown=" + mDeviceShuttingDown); - pw.println(" mSpnUpdatePending=" + mSpnUpdatePending); pw.println(" mCellInfoMinIntervalMs=" + mCellInfoMinIntervalMs); pw.println(" mEriManager=" + mEriManager); diff --git a/src/java/com/android/internal/telephony/SignalStrengthController.java b/src/java/com/android/internal/telephony/SignalStrengthController.java index bb8573156a..59f7333660 100644 --- a/src/java/com/android/internal/telephony/SignalStrengthController.java +++ b/src/java/com/android/internal/telephony/SignalStrengthController.java @@ -339,16 +339,9 @@ public class SignalStrengthController extends Handler { || (curTime - mSignalStrengthUpdatedTime > SIGNAL_STRENGTH_REFRESH_THRESHOLD_IN_MS); if (!isStale) return false; - List subInfoList; - if (mPhone.isSubscriptionManagerServiceEnabled()) { - subInfoList = SubscriptionManagerService.getInstance().getActiveSubscriptionInfoList( - mPhone.getContext().getOpPackageName(), - mPhone.getContext().getAttributionTag()); - } else { - subInfoList = SubscriptionController.getInstance() - .getActiveSubscriptionInfoList(mPhone.getContext().getOpPackageName(), - mPhone.getContext().getAttributionTag()); - } + List subInfoList = SubscriptionManagerService.getInstance() + .getActiveSubscriptionInfoList(mPhone.getContext().getOpPackageName(), + mPhone.getContext().getAttributionTag()); if (!ArrayUtils.isEmpty(subInfoList)) { for (SubscriptionInfo info : subInfoList) { diff --git a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java index 2f3995853c..ecd62765a1 100644 --- a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java +++ b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java @@ -260,15 +260,8 @@ public class SmsBroadcastUndelivered { * Send tracker to appropriate (3GPP or 3GPP2) inbound SMS handler for broadcast. */ private static void broadcastSms(InboundSmsTracker tracker) { - InboundSmsHandler handler; int subId = tracker.getSubId(); - int phoneId; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - phoneId = SubscriptionManagerService.getInstance().getPhoneId(subId); - } else { - // TODO consider other subs in this subId's group as well - phoneId = SubscriptionController.getInstance().getPhoneId(subId); - } + int phoneId = SubscriptionManagerService.getInstance().getPhoneId(subId); if (!SubscriptionManager.isValidPhoneId(phoneId)) { Rlog.e(TAG, "broadcastSms: ignoring message; no phone found for subId " + subId); return; @@ -279,7 +272,7 @@ public class SmsBroadcastUndelivered { + " phoneId " + phoneId); return; } - handler = phone.getInboundSmsHandler(tracker.is3gpp2()); + InboundSmsHandler handler = phone.getInboundSmsHandler(tracker.is3gpp2()); if (handler != null) { handler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_SMS, tracker); } else { diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java index f1a69f4b5a..97161f85b8 100644 --- a/src/java/com/android/internal/telephony/SmsController.java +++ b/src/java/com/android/internal/telephony/SmsController.java @@ -618,32 +618,19 @@ public class SmsController extends ISmsImplBase { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Override public int getPreferredSmsSubscription() { - int defaultSubId; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - // If there is a default, choose that one. - defaultSubId = SubscriptionManagerService.getInstance().getDefaultSmsSubId(); - } else { - // If there is a default, choose that one. - defaultSubId = SubscriptionController.getInstance().getDefaultSmsSubId(); - } + // If there is a default, choose that one. + int defaultSubId = SubscriptionManagerService.getInstance().getDefaultSmsSubId(); + if (SubscriptionManager.isValidSubscriptionId(defaultSubId)) { return defaultSubId; } // No default, if there is only one sub active, choose that as the "preferred" sub id. long token = Binder.clearCallingIdentity(); try { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - int[] activeSubs = SubscriptionManagerService.getInstance() - .getActiveSubIdList(true /*visibleOnly*/); - if (activeSubs.length == 1) { - return activeSubs[0]; - } - } else { - int[] activeSubs = SubscriptionController.getInstance() - .getActiveSubIdList(true /*visibleOnly*/); - if (activeSubs.length == 1) { - return activeSubs[0]; - } + int[] activeSubs = SubscriptionManagerService.getInstance() + .getActiveSubIdList(true /*visibleOnly*/); + if (activeSubs.length == 1) { + return activeSubs[0]; } } finally { Binder.restoreCallingIdentity(token); diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java deleted file mode 100644 index ad2fd74014..0000000000 --- a/src/java/com/android/internal/telephony/SubscriptionController.java +++ /dev/null @@ -1,5036 +0,0 @@ -/* -* Copyright (C) 2014 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.android.internal.telephony; - -import static android.Manifest.permission.READ_PHONE_NUMBERS; -import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; -import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.telephony.TelephonyManager.MULTISIM_ALLOWED; -import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION; -import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT; - -import android.Manifest; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.app.AppOpsManager; -import android.app.PendingIntent; -import android.app.compat.CompatChanges; -import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledSince; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.database.ContentObserver; -import android.database.Cursor; -import android.net.Uri; -import android.os.Binder; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.ParcelUuid; -import android.os.PersistableBundle; -import android.os.RegistrantList; -import android.os.RemoteException; -import android.os.TelephonyServiceManager.ServiceRegisterer; -import android.os.UserHandle; -import android.provider.Settings; -import android.provider.Telephony.SimInfo; -import android.telecom.PhoneAccountHandle; -import android.telecom.TelecomManager; -import android.telephony.AnomalyReporter; -import android.telephony.CarrierConfigManager; -import android.telephony.RadioAccessFamily; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.SubscriptionManager.SimDisplayNameSource; -import android.telephony.SubscriptionManager.UsageSetting; -import android.telephony.TelephonyFrameworkInitializer; -import android.telephony.TelephonyManager; -import android.telephony.TelephonyRegistryManager; -import android.telephony.UiccAccessRule; -import android.telephony.UiccPortInfo; -import android.telephony.UiccSlotInfo; -import android.telephony.UiccSlotMapping; -import android.telephony.euicc.EuiccManager; -import android.text.TextUtils; -import android.util.EventLog; -import android.util.LocalLog; -import android.util.Log; - -import com.android.ims.ImsManager; -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.data.PhoneSwitcher; -import com.android.internal.telephony.metrics.TelephonyMetrics; -import com.android.internal.telephony.subscription.SubscriptionManagerService; -import com.android.internal.telephony.uicc.IccUtils; -import com.android.internal.telephony.uicc.UiccCard; -import com.android.internal.telephony.uicc.UiccController; -import com.android.internal.telephony.uicc.UiccProfile; -import com.android.internal.telephony.uicc.UiccSlot; -import com.android.internal.telephony.util.ArrayUtils; -import com.android.internal.telephony.util.TelephonyUtils; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; - -/** - * Implementation of the ISub interface. - * - * Any setters which take subId, slotIndex or phoneId as a parameter will throw an exception if the - * parameter equals the corresponding INVALID_XXX_ID or DEFAULT_XXX_ID. - * - * All getters will lookup the corresponding default if the parameter is DEFAULT_XXX_ID. Ie calling - * getPhoneId(DEFAULT_SUB_ID) will return the same as getPhoneId(getDefaultSubId()). - * - * Finally, any getters which perform the mapping between subscriptions, slots and phones will - * return the corresponding INVALID_XXX_ID if the parameter is INVALID_XXX_ID. All other getters - * will fail and return the appropriate error value. Ie calling - * getSlotIndex(INVALID_SUBSCRIPTION_ID) will return INVALID_SIM_SLOT_INDEX and calling - * getSubInfoForSubscriber(INVALID_SUBSCRIPTION_ID) will return null. - * - */ -public class SubscriptionController extends ISub.Stub { - private static final String LOG_TAG = "SubscriptionController"; - private static final boolean DBG = false; - private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); - private static final boolean DBG_CACHE = false; - private static final int DEPRECATED_SETTING = -1; - private static final ParcelUuid INVALID_GROUP_UUID = - ParcelUuid.fromString(CarrierConfigManager.REMOVE_GROUP_UUID_STRING); - private final LocalLog mLocalLog = new LocalLog(128); - private static final int SUB_ID_FOUND = 1; - private static final int NO_ENTRY_FOR_SLOT_INDEX = -1; - private static final int SUB_ID_NOT_IN_SLOT = -2; - - // Lock that both mCacheActiveSubInfoList and mCacheOpportunisticSubInfoList use. - private Object mSubInfoListLock = new Object(); - - /* The Cache of Active SubInfoRecord(s) list of currently in use SubInfoRecord(s) */ - private final List mCacheActiveSubInfoList = new ArrayList<>(); - - /* Similar to mCacheActiveSubInfoList but only caching opportunistic subscriptions. */ - private List mCacheOpportunisticSubInfoList = new ArrayList<>(); - private AtomicBoolean mOpptSubInfoListChangedDirtyBit = new AtomicBoolean(); - - private static final Comparator SUBSCRIPTION_INFO_COMPARATOR = - (arg0, arg1) -> { - // Primary sort key on SimSlotIndex - int flag = arg0.getSimSlotIndex() - arg1.getSimSlotIndex(); - if (flag == 0) { - // Secondary sort on SubscriptionId - return arg0.getSubscriptionId() - arg1.getSubscriptionId(); - } - return flag; - }; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - protected final Object mLock = new Object(); - - /** The singleton instance. */ - protected static SubscriptionController sInstance = null; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - protected Context mContext; - protected TelephonyManager mTelephonyManager; - protected UiccController mUiccController; - - /** - * Apps targeting on Android T and beyond will get exception if there is no access to device - * identifiers nor has carrier privileges when calling - * SubscriptionManager#getSubscriptionsInGroup. - */ - @ChangeId - @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) - public static final long REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID = 213902861L; - - private AppOpsManager mAppOps; - - // Each slot can have multiple subs. - private static class WatchedSlotIndexToSubIds { - private final Map> mSlotIndexToSubIds = - new ConcurrentHashMap<>(); - - public void clear() { - mSlotIndexToSubIds.clear(); - invalidateDefaultSubIdCaches(); - invalidateSlotIndexCaches(); - } - - public Set>> entrySet() { - return mSlotIndexToSubIds.entrySet(); - } - - // Force all updates to data structure through wrapper. - public ArrayList getCopy(int slotIndex) { - ArrayList subIdList = mSlotIndexToSubIds.get(slotIndex); - if (subIdList == null) { - return null; - } - - return new ArrayList<>(subIdList); - } - - public void put(int slotIndex, ArrayList value) { - mSlotIndexToSubIds.put(slotIndex, value); - invalidateDefaultSubIdCaches(); - invalidateSlotIndexCaches(); - } - - public void remove(int slotIndex) { - mSlotIndexToSubIds.remove(slotIndex); - invalidateDefaultSubIdCaches(); - invalidateSlotIndexCaches(); - } - - public int size() { - return mSlotIndexToSubIds.size(); - } - - @VisibleForTesting - public Map> getMap() { - return mSlotIndexToSubIds; - } - - public int removeFromSubIdList(int slotIndex, int subId) { - ArrayList subIdList = mSlotIndexToSubIds.get(slotIndex); - if (subIdList == null) { - return NO_ENTRY_FOR_SLOT_INDEX; - } else { - if (subIdList.contains(subId)) { - subIdList.remove(new Integer(subId)); - if (subIdList.isEmpty()) { - mSlotIndexToSubIds.remove(slotIndex); - } - invalidateDefaultSubIdCaches(); - invalidateSlotIndexCaches(); - return SUB_ID_FOUND; - } else { - return SUB_ID_NOT_IN_SLOT; - } - } - } - - public void addToSubIdList(int slotIndex, Integer value) { - ArrayList subIdList = mSlotIndexToSubIds.get(slotIndex); - if (subIdList == null) { - subIdList = new ArrayList(); - subIdList.add(value); - mSlotIndexToSubIds.put(slotIndex, subIdList); - } else { - subIdList.add(value); - } - invalidateDefaultSubIdCaches(); - invalidateSlotIndexCaches(); - } - - public void clearSubIdList(int slotIndex) { - ArrayList subIdList = mSlotIndexToSubIds.get(slotIndex); - if (subIdList != null) { - subIdList.clear(); - invalidateDefaultSubIdCaches(); - invalidateSlotIndexCaches(); - } - } - } - - public static class WatchedInt { - private int mValue; - - public WatchedInt(int initialValue) { - mValue = initialValue; - } - - public int get() { - return mValue; - } - - public void set(int newValue) { - mValue = newValue; - } - } - - private final WatchedSlotIndexToSubIds mSlotIndexToSubIds = new WatchedSlotIndexToSubIds(); - - private final WatchedInt mDefaultFallbackSubId = - new WatchedInt(SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - @Override - public void set(int newValue) { - super.set(newValue); - invalidateDefaultSubIdCaches(); - invalidateSlotIndexCaches(); - } - }; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private static int mDefaultPhoneId = SubscriptionManager.DEFAULT_PHONE_INDEX; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int[] colorArr; - private long mLastISubServiceRegTime; - private RegistrantList mUiccAppsEnableChangeRegList = new RegistrantList(); - - // The properties that should be shared and synced across grouped subscriptions. - private static final Set GROUP_SHARING_PROPERTIES = new HashSet<>(Arrays.asList( - SubscriptionManager.ENHANCED_4G_MODE_ENABLED, - SubscriptionManager.VT_IMS_ENABLED, - SubscriptionManager.WFC_IMS_ENABLED, - SubscriptionManager.WFC_IMS_MODE, - SubscriptionManager.WFC_IMS_ROAMING_MODE, - SubscriptionManager.WFC_IMS_ROAMING_ENABLED, - SubscriptionManager.DATA_ROAMING, - SubscriptionManager.DISPLAY_NAME, - SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES, - SubscriptionManager.UICC_APPLICATIONS_ENABLED, - SubscriptionManager.IMS_RCS_UCE_ENABLED, - SubscriptionManager.CROSS_SIM_CALLING_ENABLED, - SubscriptionManager.NR_ADVANCED_CALLING_ENABLED, - SubscriptionManager.USER_HANDLE - )); - - public static SubscriptionController init(Context c) { - synchronized (SubscriptionController.class) { - if (sInstance == null) { - sInstance = new SubscriptionController(c); - } else { - Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance); - } - return sInstance; - } - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static SubscriptionController getInstance() { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - throw new RuntimeException("getInstance should not be called."); - } - if (sInstance == null) { - Log.wtf(LOG_TAG, "getInstance null"); - } - - return sInstance; - } - - protected SubscriptionController(Context c) { - internalInit(c); - migrateImsSettings(); - } - - protected void internalInit(Context c) { - mContext = c; - mTelephonyManager = TelephonyManager.from(mContext); - - try { - mUiccController = UiccController.getInstance(); - } catch(RuntimeException ex) { - throw new RuntimeException( - "UiccController has to be initialised before SubscriptionController init"); - } - - mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE); - - ServiceRegisterer subscriptionServiceRegisterer = TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer(); - if (subscriptionServiceRegisterer.get() == null) { - subscriptionServiceRegisterer.register(this); - mLastISubServiceRegTime = System.currentTimeMillis(); - } - - // clear SLOT_INDEX for all subs - clearSlotIndexForSubInfoRecords(); - - // Cache Setting values - cacheSettingValues(); - - // Initial invalidate activates caching. - invalidateDefaultSubIdCaches(); - invalidateDefaultDataSubIdCaches(); - invalidateDefaultSmsSubIdCaches(); - invalidateActiveDataSubIdCaches(); - invalidateSlotIndexCaches(); - - mContext.getContentResolver().registerContentObserver( - SubscriptionManager.SIM_INFO_SUW_RESTORE_CONTENT_URI, false, - new ContentObserver(new Handler()) { - @Override - public void onChange(boolean selfChange, Uri uri) { - if (uri.equals(SubscriptionManager.SIM_INFO_SUW_RESTORE_CONTENT_URI)) { - refreshCachedActiveSubscriptionInfoList(); - notifySubscriptionInfoChanged(); - - SubscriptionManager subManager = SubscriptionManager.from(mContext); - for (SubscriptionInfo subInfo : getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag())) { - if (SubscriptionController.getInstance() - .isActiveSubId(subInfo.getSubscriptionId())) { - ImsManager imsManager = ImsManager.getInstance(mContext, - subInfo.getSimSlotIndex()); - imsManager.updateImsServiceConfig(); - } - } - } - } - }); - - SubscriptionManager.invalidateSubscriptionManagerServiceEnabledCaches(); - - if (DBG) logdl("[SubscriptionController] init by Context"); - } - - /** - * Should only be triggered once. - */ - public void notifySubInfoReady() { - // broadcast default subId. - sendDefaultChangedBroadcast(SubscriptionManager.getDefaultSubscriptionId()); - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private boolean isSubInfoReady() { - return SubscriptionInfoUpdater.isSubInfoInitialized(); - } - - /** - * This function marks SIM_SLOT_INDEX as INVALID for all subscriptions in the database. This - * should be done as part of initialization. - * - * TODO: SIM_SLOT_INDEX is based on current state and should not even be persisted in the - * database. - */ - private void clearSlotIndexForSubInfoRecords() { - if (mContext == null) { - logel("[clearSlotIndexForSubInfoRecords] TelephonyManager or mContext is null"); - return; - } - - // Update all subscriptions in simInfo db with invalid slot index - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.SIM_SLOT_INDEX, SubscriptionManager.INVALID_SIM_SLOT_INDEX); - mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value, null, null); - } - - /** - * Cache the Settings values by reading these values from Setting from disk to prevent disk I/O - * access during the API calling. This is based on an assumption that the Settings system will - * itself cache this value after the first read and thus only the first read after boot will - * access the disk. - */ - private void cacheSettingValues() { - Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - - Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - - Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - protected void enforceModifyPhoneState(String message) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE, message); - } - - private void enforceReadPrivilegedPhoneState(String message) { - mContext.enforceCallingOrSelfPermission( - Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message); - } - - private void enforceManageSubscriptionUserAssociation(String message) { - mContext.enforceCallingOrSelfPermission( - Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION, message); - } - - /** - * Returns whether the {@code callingPackage} has access to subscriber identifiers on the - * specified {@code subId} using the provided {@code message} in any resulting - * SecurityException. - */ - private boolean hasSubscriberIdentifierAccess(int subId, String callingPackage, - String callingFeatureId, String message, boolean reportFailure) { - try { - return TelephonyPermissions.checkCallingOrSelfReadSubscriberIdentifiers(mContext, subId, - callingPackage, callingFeatureId, message, reportFailure); - } catch (SecurityException e) { - // A SecurityException indicates that the calling package is targeting at least the - // minimum level that enforces identifier access restrictions and the new access - // requirements are not met. - return false; - } - } - - /** - * Returns whether the {@code callingPackage} has access to the phone number on the specified - * {@code subId} using the provided {@code message} in any resulting SecurityException. - */ - private boolean hasPhoneNumberAccess(int subId, String callingPackage, String callingFeatureId, - String message) { - try { - return TelephonyPermissions.checkCallingOrSelfReadPhoneNumber(mContext, subId, - callingPackage, callingFeatureId, message); - } catch (SecurityException e) { - return false; - } - } - - /** - * Notify the changed of subscription info. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void notifySubscriptionInfoChanged() { - TelephonyRegistryManager trm = - (TelephonyRegistryManager) - mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); - if (DBG) logd("notifySubscriptionInfoChanged:"); - trm.notifySubscriptionInfoChanged(); - - MultiSimSettingController.getInstance().notifySubscriptionInfoChanged(); - TelephonyMetrics metrics = TelephonyMetrics.getInstance(); - List subInfos; - synchronized (mSubInfoListLock) { - subInfos = new ArrayList<>(mCacheActiveSubInfoList); - } - - if (mOpptSubInfoListChangedDirtyBit.getAndSet(false)) { - notifyOpportunisticSubscriptionInfoChanged(); - } - metrics.updateActiveSubscriptionInfoList(subInfos); - } - - /** - * New SubInfoRecord instance and fill in detail info - * @param cursor The database cursor - * @return the query result of desired SubInfoRecord - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private SubscriptionInfo getSubInfoRecord(Cursor cursor) { - SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder(); - int id = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID)); - builder.setId(id) - .setIccId(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.ICC_ID))) - .setSimSlotIndex(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.SIM_SLOT_INDEX))) - .setDisplayName(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.DISPLAY_NAME))) - .setCarrierName(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.CARRIER_NAME))) - .setDisplayNameSource(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.NAME_SOURCE))) - .setIconTint(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.HUE))) - .setDataRoaming(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.DATA_ROAMING))) - .setMcc(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.MCC_STRING))) - .setMnc(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.MNC_STRING))); - - String ehplmnsRaw = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.EHPLMNS)); - String hplmnsRaw = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.HPLMNS)); - String[] ehplmns = ehplmnsRaw == null ? null : ehplmnsRaw.split(","); - String[] hplmns = hplmnsRaw == null ? null : hplmnsRaw.split(","); - - builder.setEhplmns(ehplmns).setHplmns(hplmns); - - - // CARD_ID is the private ICCID/EID string, also known as the card string - String cardString = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.CARD_ID)); - builder.setCardString(cardString); - // publicCardId is the publicly exposed int card ID - int publicCardId = mUiccController.convertToPublicCardId(cardString); - builder.setCardId(publicCardId); - - builder.setCountryIso(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.ISO_COUNTRY_CODE))) - .setCarrierId(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.CARRIER_ID))); - - boolean isEmbedded = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.IS_EMBEDDED)) == 1; - builder.setEmbedded(isEmbedded); - if (isEmbedded) { - builder.setNativeAccessRules(UiccAccessRule.decodeRules(cursor.getBlob( - cursor.getColumnIndexOrThrow(SubscriptionManager.ACCESS_RULES)))); - } - - builder.setCarrierConfigAccessRules(UiccAccessRule.decodeRules(cursor.getBlob( - cursor.getColumnIndexOrThrow( - SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS)))) - .setOpportunistic(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.IS_OPPORTUNISTIC)) == 1) - .setGroupUuid(cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.GROUP_UUID))) - .setProfileClass(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.PROFILE_CLASS))) - .setPortIndex(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.PORT_INDEX))) - .setType(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.SUBSCRIPTION_TYPE))) - .setGroupOwner(getOptionalStringFromCursor(cursor, SubscriptionManager.GROUP_OWNER, - /*defaultVal*/ null)) - .setUiccApplicationsEnabled(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.UICC_APPLICATIONS_ENABLED)) == 1) - .setUsageSetting(cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.USAGE_SETTING))); - - // If line1number has been set to a different number, use it instead. - String number = cursor.getString(cursor.getColumnIndexOrThrow( - SubscriptionManager.NUMBER)); - String line1Number = mTelephonyManager.getLine1Number(id); - if (!TextUtils.isEmpty(line1Number) && !line1Number.equals(number)) { - number = line1Number; - } - builder.setNumber(number); - - // FIXME(b/210771052): constructing a complete SubscriptionInfo requires a port index, - // but the port index isn't available here. Should it actually be part of SubscriptionInfo? - - return builder.build(); - } - - private String getOptionalStringFromCursor(Cursor cursor, String column, String defaultVal) { - // Return defaultVal if the column doesn't exist. - int columnIndex = cursor.getColumnIndex(column); - return (columnIndex == -1) ? defaultVal : cursor.getString(columnIndex); - } - - /** - * Get a subscription that matches IccId. - * @return null if there isn't a match, or subscription info if there is one. - */ - public SubscriptionInfo getSubInfoForIccId(String iccId) { - List info = getSubInfo( - SubscriptionManager.ICC_ID + "=\'" + iccId + "\'", null); - if (info == null || info.size() == 0) return null; - // Should be at most one subscription with the iccid. - return info.get(0); - } - - /** - * Query SubInfoRecord(s) from subinfo database - * @param selection A filter declaring which rows to return - * @param queryKey query key content - * @return Array list of queried result from database - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public List getSubInfo(String selection, Object queryKey) { - if (VDBG) logd("selection:" + selection + ", querykey: " + queryKey); - String[] selectionArgs = null; - if (queryKey != null) { - selectionArgs = new String[] {queryKey.toString()}; - } - ArrayList subList = null; - Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, - null, selection, selectionArgs, null); - try { - if (cursor != null) { - while (cursor.moveToNext()) { - SubscriptionInfo subInfo = getSubInfoRecord(cursor); - if (subInfo != null) { - if (subList == null) { - subList = new ArrayList(); - } - subList.add(subInfo); - } - } - } else { - if (DBG) logd("Query fail"); - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - - return subList; - } - - /** - * Find unused color to be set for new SubInfoRecord - * @param callingPackage The package making the IPC. - * @param callingFeatureId The feature in the package - * @return RGB integer value of color - */ - private int getUnusedColor(String callingPackage, String callingFeatureId) { - List availableSubInfos = getActiveSubscriptionInfoList(callingPackage, - callingFeatureId); - colorArr = mContext.getResources().getIntArray(com.android.internal.R.array.sim_colors); - int colorIdx = 0; - - if (availableSubInfos != null) { - for (int i = 0; i < colorArr.length; i++) { - int j; - for (j = 0; j < availableSubInfos.size(); j++) { - if (colorArr[i] == availableSubInfos.get(j).getIconTint()) { - break; - } - } - if (j == availableSubInfos.size()) { - return colorArr[i]; - } - } - colorIdx = availableSubInfos.size() % colorArr.length; - } - return colorArr[colorIdx]; - } - - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public SubscriptionInfo getActiveSubscriptionInfo(int subId, String callingPackage) { - return getActiveSubscriptionInfo(subId, callingPackage, null); - } - - /** - * Get the active SubscriptionInfo with the subId key - * @param subId The unique SubscriptionInfo key in database - * @param callingPackage The package making the IPC. - * @param callingFeatureId The feature in the package - * @return SubscriptionInfo, maybe null if its not active - */ - @Override - public SubscriptionInfo getActiveSubscriptionInfo(int subId, String callingPackage, - String callingFeatureId) { - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, - callingFeatureId, "getActiveSubscriptionInfo")) { - return null; - } - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - List subList; - try { - subList = getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - } finally { - Binder.restoreCallingIdentity(identity); - } - if (subList != null) { - for (SubscriptionInfo si : subList) { - if (si.getSubscriptionId() == subId) { - if (VDBG) { - logd("[getActiveSubscriptionInfo]+ subId=" + subId + " subInfo=" + si); - } - return conditionallyRemoveIdentifiers(si, callingPackage, callingFeatureId, - "getActiveSubscriptionInfo"); - } - } - } - if (DBG) { - logd("[getActiveSubscriptionInfo]- subId=" + subId - + " subList=" + subList + " subInfo=null"); - } - - return null; - } - - /** - * Get a single subscription info record for a given subscription. - * - * @param subId the subId to query. - * - * @hide - */ - public SubscriptionInfo getSubscriptionInfo(int subId) { - synchronized (mSubInfoListLock) { - // check cache for active subscriptions first, before querying db - for (SubscriptionInfo subInfo : mCacheActiveSubInfoList) { - if (subInfo.getSubscriptionId() == subId) { - return subInfo; - } - } - - // check cache for opportunistic subscriptions too, before querying db - for (SubscriptionInfo subInfo : mCacheOpportunisticSubInfoList) { - if (subInfo.getSubscriptionId() == subId) { - return subInfo; - } - } - } - - List subInfoList = getSubInfo( - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + subId, null); - if (subInfoList == null || subInfoList.isEmpty()) return null; - return subInfoList.get(0); - } - - /** - * Get the active SubscriptionInfo associated with the iccId - * @param iccId the IccId of SIM card - * @param callingPackage The package making the IPC. - * @param callingFeatureId The feature in the package - * @return SubscriptionInfo, maybe null if its not active - */ - @Override - public SubscriptionInfo getActiveSubscriptionInfoForIccId(String iccId, String callingPackage, - String callingFeatureId) { - enforceReadPrivilegedPhoneState("getActiveSubscriptionInfoForIccId"); - return getActiveSubscriptionInfoForIccIdInternal(iccId); - } - - /** - * Get the active SubscriptionInfo associated with the given iccId. The caller *must* perform - * permission checks when using this method. - */ - private SubscriptionInfo getActiveSubscriptionInfoForIccIdInternal(String iccId) { - if (iccId == null) { - return null; - } - - final long identity = Binder.clearCallingIdentity(); - try { - List subList = getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - if (subList != null) { - for (SubscriptionInfo si : subList) { - if (iccId.equals(si.getIccId())) { - if (DBG) - logd("[getActiveSubInfoUsingIccId]+ iccId=" - + SubscriptionInfo.getPrintableId(iccId) - + " subInfo=" + si); - return si; - } - } - } - if (DBG) { - logd("[getActiveSubInfoUsingIccId]+ iccId=" - + SubscriptionInfo.getPrintableId(iccId) - + " subList=" + subList + " subInfo=null"); - } - } finally { - Binder.restoreCallingIdentity(identity); - } - - return null; - } - - /** - * Get the active SubscriptionInfo associated with the slotIndex. - * This API does not return details on Remote-SIM subscriptions. - * @param slotIndex the slot which the subscription is inserted - * @param callingPackage The package making the IPC. - * @param callingFeatureId The feature in the package - * @return SubscriptionInfo, null for Remote-SIMs or non-active slotIndex. - */ - @Override - public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex, - String callingPackage, String callingFeatureId) { - Phone phone = PhoneFactory.getPhone(slotIndex); - if (phone == null) { - if (DBG) { - loge("[getActiveSubscriptionInfoForSimSlotIndex] no phone, slotIndex=" + slotIndex); - } - return null; - } - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( - mContext, phone.getSubId(), callingPackage, callingFeatureId, - "getActiveSubscriptionInfoForSimSlotIndex")) { - return null; - } - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - List subList; - try { - subList = getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - } finally { - Binder.restoreCallingIdentity(identity); - } - if (subList != null) { - for (SubscriptionInfo si : subList) { - if (si.getSimSlotIndex() == slotIndex) { - if (DBG) { - logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIndex=" - + slotIndex + " subId=" + si); - } else { - logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIndex=" - + slotIndex + " subId=" + conditionallyRemoveIdentifiers(si, false, - false)); - } - return conditionallyRemoveIdentifiers(si, callingPackage, callingFeatureId, - "getActiveSubscriptionInfoForSimSlotIndex"); - } - } - if (DBG) { - logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIndex=" + slotIndex - + " subId=null"); - } - } else { - if (DBG) { - logd("[getActiveSubscriptionInfoForSimSlotIndex]+ subList=null"); - } - } - - - return null; - } - - /** - * @param callingPackage The package making the IPC. - * @param callingFeatureId The feature in the package - * @return List of all SubscriptionInfo records in database, - * include those that were inserted before, maybe empty but not null. - * @hide - */ - @Override - public List getAllSubInfoList(String callingPackage, - String callingFeatureId) { - return getAllSubInfoList(callingPackage, callingFeatureId, false); - } - - /** - * @param callingPackage The package making the IPC. - * @param callingFeatureId The feature in the package - * @param skipConditionallyRemoveIdentifier if set, skip removing identifier conditionally - * @return List of all SubscriptionInfo records in database, - * include those that were inserted before, maybe empty but not null. - * @hide - */ - public List getAllSubInfoList(String callingPackage, - String callingFeatureId, boolean skipConditionallyRemoveIdentifier) { - if (VDBG) logd("[getAllSubInfoList]+"); - - // This API isn't public, so no need to provide a valid subscription ID - we're not worried - // about carrier-privileged callers not having access. - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( - mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, - callingFeatureId, "getAllSubInfoList")) { - return null; - } - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - List subList; - try { - subList = getSubInfo(null, null); - } finally { - Binder.restoreCallingIdentity(identity); - } - if (subList != null && !skipConditionallyRemoveIdentifier) { - if (VDBG) logd("[getAllSubInfoList]- " + subList.size() + " infos return"); - subList = subList.stream().map( - subscriptionInfo -> conditionallyRemoveIdentifiers(subscriptionInfo, - callingPackage, callingFeatureId, "getAllSubInfoList")) - .collect(Collectors.toList()); - } else { - if (VDBG) logd("[getAllSubInfoList]- no info return"); - } - return subList; - } - - private List makeCacheListCopyWithLock(List cacheSubList) { - synchronized (mSubInfoListLock) { - return new ArrayList<>(cacheSubList); - } - } - - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public List getActiveSubscriptionInfoList(String callingPackage) { - return getSubscriptionInfoListFromCacheHelper(callingPackage, null, - makeCacheListCopyWithLock(mCacheActiveSubInfoList)); - } - - /** - * Get the SubInfoRecord(s) of the currently active SIM(s) - which include both local - * and remote SIMs. - * @param callingPackage The package making the IPC. - * @param callingFeatureId The feature in the package - * @return Array list of currently inserted SubInfoRecord(s) - */ - @Override - public List getActiveSubscriptionInfoList(String callingPackage, - String callingFeatureId) { - return getSubscriptionInfoListFromCacheHelper(callingPackage, callingFeatureId, - makeCacheListCopyWithLock(mCacheActiveSubInfoList)); - } - - /** - * Refresh the cache of SubInfoRecord(s) of the currently available SIM(s) - including - * local & remote SIMs. - */ - @VisibleForTesting // For mockito to mock this method - public void refreshCachedActiveSubscriptionInfoList() { - boolean opptSubListChanged; - - List activeSubscriptionInfoList = getSubInfo( - SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR " - + SubscriptionManager.SUBSCRIPTION_TYPE + "=" - + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM, - null); - - synchronized (mSubInfoListLock) { - if (activeSubscriptionInfoList != null) { - // Log when active sub info changes. - if (mCacheActiveSubInfoList.size() != activeSubscriptionInfoList.size() - || !mCacheActiveSubInfoList.containsAll(activeSubscriptionInfoList)) { - logdl("Active subscription info list changed. " + activeSubscriptionInfoList); - } - - mCacheActiveSubInfoList.clear(); - activeSubscriptionInfoList.sort(SUBSCRIPTION_INFO_COMPARATOR); - mCacheActiveSubInfoList.addAll(activeSubscriptionInfoList); - } else { - logd("activeSubscriptionInfoList is null."); - mCacheActiveSubInfoList.clear(); - } - if (DBG_CACHE) { - if (!mCacheActiveSubInfoList.isEmpty()) { - for (SubscriptionInfo si : mCacheActiveSubInfoList) { - logd("[refreshCachedActiveSubscriptionInfoList] Setting Cached info=" - + si); - } - } else { - logdl("[refreshCachedActiveSubscriptionInfoList]- no info return"); - } - } - } - - // Refresh cached opportunistic sub list and detect whether it's changed. - refreshCachedOpportunisticSubscriptionInfoList(); - } - - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int getActiveSubInfoCount(String callingPackage) { - return getActiveSubInfoCount(callingPackage, null); - } - - /** - * Get the SUB count of active SUB(s) - * @param callingPackage The package making the IPC. - * @param callingFeatureId The feature in the package. - * @return active SIM count - */ - @Override - public int getActiveSubInfoCount(String callingPackage, String callingFeatureId) { - // Let getActiveSubscriptionInfoList perform permission checks / filtering. - List records = getActiveSubscriptionInfoList(callingPackage, - callingFeatureId); - if (records == null) { - if (VDBG) logd("[getActiveSubInfoCount] records null"); - return 0; - } - if (VDBG) logd("[getActiveSubInfoCount]- count: " + records.size()); - return records.size(); - } - - /** - * Get the SUB count of all SUB(s) in SubscriptoinInfo database - * @param callingPackage The package making the IPC. - * @param callingFeatureId The feature in the package - * @return all SIM count in database, include what was inserted before - */ - public int getAllSubInfoCount(String callingPackage, String callingFeatureId) { - if (DBG) logd("[getAllSubInfoCount]+"); - - // This API isn't public, so no need to provide a valid subscription ID - we're not worried - // about carrier-privileged callers not having access. - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState( - mContext, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, - callingFeatureId, "getAllSubInfoCount")) { - return 0; - } - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, - null, null, null, null); - try { - if (cursor != null) { - int count = cursor.getCount(); - if (DBG) logd("[getAllSubInfoCount]- " + count + " SUB(s) in DB"); - return count; - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - if (DBG) logd("[getAllSubInfoCount]- no SUB in DB"); - - return 0; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * @return the maximum number of local subscriptions this device will support at any one time. - */ - @Override - public int getActiveSubInfoCountMax() { - // FIXME: This valid now but change to use TelephonyDevController in the future - return mTelephonyManager.getSimCount(); - } - - @Override - public List getAvailableSubscriptionInfoList(String callingPackage, - String callingFeatureId) { - try { - enforceReadPrivilegedPhoneState("getAvailableSubscriptionInfoList"); - } catch (SecurityException e) { - try { - mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE, null); - // If caller doesn't have READ_PRIVILEGED_PHONE_STATE permission but only - // has READ_PHONE_STATE permission, log this event. - EventLog.writeEvent(0x534e4554, "185235454", Binder.getCallingUid()); - } catch (SecurityException ex) { - // Ignore - } - throw new SecurityException("Need READ_PRIVILEGED_PHONE_STATE to call " - + " getAvailableSubscriptionInfoList"); - } - - // Now that all security checks pass, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - String selection = SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR " - + SubscriptionManager.SUBSCRIPTION_TYPE + "=" - + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM; - - EuiccManager euiccManager = - (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE); - if (euiccManager.isEnabled()) { - selection += " OR " + SubscriptionManager.IS_EMBEDDED + "=1"; - } - - // Available eSIM profiles are reported by EuiccManager. However for physical SIMs if - // they are in inactive slot or programmatically disabled, they are still considered - // available. In this case we get their iccid from slot info and include their - // subscriptionInfos. - List iccIds = getIccIdsOfInsertedPhysicalSims(); - - if (!iccIds.isEmpty()) { - selection += " OR (" + getSelectionForIccIdList(iccIds.toArray(new String[0])) - + ")"; - } - - List subList = getSubInfo(selection, null /* queryKey */); - - if (subList != null) { - subList.sort(SUBSCRIPTION_INFO_COMPARATOR); - - if (VDBG) logdl("[getAvailableSubInfoList]- " + subList.size() + " infos return"); - } else { - if (DBG) logdl("[getAvailableSubInfoList]- no info return"); - } - - return subList; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - private List getIccIdsOfInsertedPhysicalSims() { - List ret = new ArrayList<>(); - UiccSlot[] uiccSlots = UiccController.getInstance().getUiccSlots(); - if (uiccSlots == null) return ret; - - for (UiccSlot uiccSlot : uiccSlots) { - if (uiccSlot != null && uiccSlot.getCardState() != null - && uiccSlot.getCardState().isCardPresent() - && !uiccSlot.isEuicc()) { - // Non euicc slots will have single port, so use default port index. - String iccId = uiccSlot.getIccId(TelephonyManager.DEFAULT_PORT_INDEX); - if (!TextUtils.isEmpty(iccId)) { - ret.add(IccUtils.stripTrailingFs(iccId)); - } - } - } - - return ret; - } - - @Override - public List getAccessibleSubscriptionInfoList(String callingPackage) { - EuiccManager euiccManager = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE); - if (!euiccManager.isEnabled()) { - if (DBG) { - logdl("[getAccessibleSubInfoList] Embedded subscriptions are disabled"); - } - return null; - } - - // Verify that the given package belongs to the calling UID. - mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); - - // Perform the operation as ourselves. If the caller cannot read phone state, they may still - // have carrier privileges per the subscription metadata, so we always need to make the - // query and then filter the results. - final long identity = Binder.clearCallingIdentity(); - List subList; - try { - subList = getSubInfo(SubscriptionManager.IS_EMBEDDED + "=1", null); - } finally { - Binder.restoreCallingIdentity(identity); - } - - if (subList == null) { - if (DBG) logdl("[getAccessibleSubInfoList] No info returned"); - return null; - } - - // Filter the list to only include subscriptions which the (restored) caller can manage. - List filteredList = subList.stream() - .filter(subscriptionInfo -> - subscriptionInfo.canManageSubscription(mContext, callingPackage)) - .sorted(SUBSCRIPTION_INFO_COMPARATOR) - .collect(Collectors.toList()); - if (VDBG) { - logdl("[getAccessibleSubInfoList] " + filteredList.size() + " infos returned"); - } - return filteredList; - } - - /** - * Return the list of subscriptions in the database which are either: - *

    - *
  • Embedded (but see note about {@code includeNonRemovableSubscriptions}, or - *
  • In the given list of current embedded ICCIDs (which may not yet be in the database, or - * which may not currently be marked as embedded). - *
- * - *

NOTE: This is not accessible to external processes, so it does not need a permission - * check. It is only intended for use by {@link SubscriptionInfoUpdater}. - * - * @param embeddedIccids all ICCIDs of available embedded subscriptions. This is used to surface - * entries for profiles which had been previously deleted. - * @param isEuiccRemovable whether the current ICCID is removable. Non-removable subscriptions - * will only be returned if the current ICCID is not removable; otherwise, they are left - * alone (not returned here unless in the embeddedIccids list) under the assumption that - * they will still be accessible when the eUICC containing them is activated. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public List getSubscriptionInfoListForEmbeddedSubscriptionUpdate( - String[] embeddedIccids, boolean isEuiccRemovable) { - StringBuilder whereClause = new StringBuilder(); - whereClause.append("(").append(SubscriptionManager.IS_EMBEDDED).append("=1"); - if (isEuiccRemovable) { - // Current eUICC is removable, so don't return non-removable subscriptions (which would - // be deleted), as these are expected to still be present on a different, non-removable - // eUICC. - whereClause.append(" AND ").append(SubscriptionManager.IS_REMOVABLE).append("=1"); - } - // Else, return both removable and non-removable subscriptions. This is expected to delete - // all removable subscriptions, which is desired as they may not be accessible. - - whereClause.append(") OR ").append(SubscriptionManager.ICC_ID).append(" IN ("); - // ICCIDs are validated to contain only numbers when passed in, and come from a trusted - // app, so no need to escape. - for (int i = 0; i < embeddedIccids.length; i++) { - if (i > 0) { - whereClause.append(","); - } - whereClause.append("'").append(embeddedIccids[i]).append("'"); - } - whereClause.append(")"); - - List list = getSubInfo(whereClause.toString(), null); - if (list == null) { - return Collections.emptyList(); - } - return list; - } - - @Override - public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) { - mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, - "requestEmbeddedSubscriptionInfoListRefresh"); - long token = Binder.clearCallingIdentity(); - try { - PhoneFactory.requestEmbeddedSubscriptionInfoListRefresh(cardId, null /* callback */); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Asynchronously refresh the embedded subscription info list for the embedded card has the - * given card id {@code cardId}. - * - * @param callback Optional callback to execute after the refresh completes. Must terminate - * quickly as it will be called from SubscriptionInfoUpdater's handler thread. - */ - // No permission check needed as this is not exposed via AIDL. - public void requestEmbeddedSubscriptionInfoListRefresh( - int cardId, @Nullable Runnable callback) { - PhoneFactory.requestEmbeddedSubscriptionInfoListRefresh(cardId, callback); - } - - /** - * Asynchronously refresh the embedded subscription info list for the embedded card has the - * default card id return by {@link TelephonyManager#getCardIdForDefaultEuicc()}. - * - * @param callback Optional callback to execute after the refresh completes. Must terminate - * quickly as it will be called from SubscriptionInfoUpdater's handler thread. - */ - // No permission check needed as this is not exposed via AIDL. - public void requestEmbeddedSubscriptionInfoListRefresh(@Nullable Runnable callback) { - PhoneFactory.requestEmbeddedSubscriptionInfoListRefresh( - mTelephonyManager.getCardIdForDefaultEuicc(), callback); - } - - /** - * Add a new subscription info record, if needed. - * @param uniqueId This is the unique identifier for the subscription within the specific - * subscription type. - * @param displayName human-readable name of the device the subscription corresponds to. - * @param slotIndex value for {@link SubscriptionManager#SIM_SLOT_INDEX} - * @param subscriptionType the type of subscription to be added. - * @return 0 if success, < 0 on error. - */ - @Override - public int addSubInfo(String uniqueId, String displayName, int slotIndex, - int subscriptionType) { - if (DBG) { - String iccIdStr = uniqueId; - if (!isSubscriptionForRemoteSim(subscriptionType)) { - iccIdStr = SubscriptionInfo.getPrintableId(uniqueId); - } - logdl("[addSubInfoRecord]+ iccid: " + iccIdStr - + ", slotIndex: " + slotIndex - + ", subscriptionType: " + subscriptionType); - } - - enforceModifyPhoneState("addSubInfo"); - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - if (uniqueId == null) { - if (DBG) logdl("[addSubInfo]- null iccId"); - return -1; - } - - ContentResolver resolver = mContext.getContentResolver(); - String selection = SubscriptionManager.ICC_ID + "=?"; - String[] args; - if (isSubscriptionForRemoteSim(subscriptionType)) { - PackageManager packageManager = mContext.getPackageManager(); - if (!packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { - logel("[addSubInfo] Remote SIM can only be added when FEATURE_AUTOMOTIVE" - + " is supported"); - return -1; - } - selection += " AND " + SubscriptionManager.SUBSCRIPTION_TYPE + "=?"; - args = new String[]{uniqueId, Integer.toString(subscriptionType)}; - } else { - selection += " OR " + SubscriptionManager.ICC_ID + "=?"; - args = new String[]{uniqueId, IccUtils.getDecimalSubstring(uniqueId)}; - } - Cursor cursor = resolver.query(SubscriptionManager.CONTENT_URI, - new String[]{SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID, - SubscriptionManager.SIM_SLOT_INDEX, SubscriptionManager.NAME_SOURCE, - SubscriptionManager.ICC_ID, SubscriptionManager.CARD_ID, - SubscriptionManager.PORT_INDEX}, - selection, args, null); - - boolean setDisplayName = false; - try { - boolean recordsDoNotExist = (cursor == null || !cursor.moveToFirst()); - if (isSubscriptionForRemoteSim(subscriptionType)) { - if (recordsDoNotExist) { - // create a Subscription record - slotIndex = SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB; - Uri uri = insertEmptySubInfoRecord(uniqueId, displayName, - slotIndex, subscriptionType); - if (DBG) logd("[addSubInfoRecord] New record created: " + uri); - } else { - if (DBG) logdl("[addSubInfoRecord] Record already exists"); - } - } else { // Handle Local SIM devices - if (recordsDoNotExist) { - setDisplayName = true; - Uri uri = insertEmptySubInfoRecord(uniqueId, slotIndex); - if (DBG) logdl("[addSubInfoRecord] New record created: " + uri); - } else { // there are matching records in the database for the given ICC_ID - int subId = cursor.getInt(0); - int oldSimInfoId = cursor.getInt(1); - int nameSource = cursor.getInt(2); - String oldIccId = cursor.getString(3); - String oldCardId = cursor.getString(4); - int oldPortIndex = cursor.getInt(5); - ContentValues value = new ContentValues(); - - if (slotIndex != oldSimInfoId) { - value.put(SubscriptionManager.SIM_SLOT_INDEX, slotIndex); - } - - if (oldIccId != null && oldIccId.length() < uniqueId.length() - && (oldIccId.equals(IccUtils.getDecimalSubstring(uniqueId)))) { - value.put(SubscriptionManager.ICC_ID, uniqueId); - } - - UiccCard card = mUiccController.getUiccCardForPhone(slotIndex); - if (card != null) { - String cardId = card.getCardId(); - if (cardId != null && cardId != oldCardId) { - value.put(SubscriptionManager.CARD_ID, cardId); - } - } - - //update portIndex for pSim - UiccSlot slot = mUiccController.getUiccSlotForPhone(slotIndex); - if (slot != null && !slot.isEuicc()) { - int portIndex = slot.getPortIndexFromIccId(uniqueId); - if (portIndex != oldPortIndex) { - value.put(SubscriptionManager.PORT_INDEX, portIndex); - } - } - - if (value.size() > 0) { - resolver.update(SubscriptionManager.getUriForSubscriptionId(subId), - value, null, null); - } - - if (DBG) logdl("[addSubInfoRecord] Record already exists"); - } - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - - selection = SubscriptionManager.SIM_SLOT_INDEX + "=?"; - args = new String[] {String.valueOf(slotIndex)}; - if (isSubscriptionForRemoteSim(subscriptionType)) { - selection = SubscriptionManager.ICC_ID + "=? AND " - + SubscriptionManager.SUBSCRIPTION_TYPE + "=?"; - args = new String[]{uniqueId, Integer.toString(subscriptionType)}; - } - cursor = resolver.query(SubscriptionManager.CONTENT_URI, null, - selection, args, null); - try { - if (cursor != null && cursor.moveToFirst()) { - do { - int subId = cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID)); - // If sSlotIndexToSubIds already has the same subId for a slotIndex/phoneId, - // do not add it. - if (addToSubIdList(slotIndex, subId, subscriptionType)) { - // TODO While two subs active, if user deactivats first - // one, need to update the default subId with second one. - - // FIXME: Currently we assume phoneId == slotIndex which in the future - // may not be true, for instance with multiple subs per slot. - // But is true at the moment. - int subIdCountMax = getActiveSubInfoCountMax(); - int defaultSubId = getDefaultSubId(); - if (DBG) { - logdl("[addSubInfoRecord]" - + " mSlotIndexToSubIds.size=" + mSlotIndexToSubIds.size() - + " slotIndex=" + slotIndex + " subId=" + subId - + " defaultSubId=" + defaultSubId - + " simCount=" + subIdCountMax); - } - - // Set the default sub if not set or if single sim device - if (!isSubscriptionForRemoteSim(subscriptionType)) { - if (!SubscriptionManager.isValidSubscriptionId(defaultSubId) - || subIdCountMax == 1 - || mDefaultFallbackSubId.get() == - SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - logdl("setting default fallback subid to " + subId); - setDefaultFallbackSubId(subId, subscriptionType); - } - // If single sim device, set this subscription as the default for - // everything - if (subIdCountMax == 1) { - if (DBG) { - logdl("[addSubInfoRecord] one sim set defaults to subId=" - + subId); - } - setDefaultDataSubId(subId); - setDefaultSmsSubId(subId); - setDefaultVoiceSubId(subId); - } - } else { - updateDefaultSubIdsIfNeeded(subId, subscriptionType); - } - } else { - if (DBG) { - logdl("[addSubInfoRecord] current SubId is already known, " - + "IGNORE"); - } - } - if (DBG) { - logdl("[addSubInfoRecord] hashmap(" + slotIndex + "," + subId + ")"); - } - } while (cursor.moveToNext()); - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - - // Refresh the Cache of Active Subscription Info List. This should be done after - // updating sSlotIndexToSubIds which is done through addToSubIdList() above. - refreshCachedActiveSubscriptionInfoList(); - - if (isSubscriptionForRemoteSim(subscriptionType)) { - notifySubscriptionInfoChanged(); - } else { // Handle Local SIM devices - // Set Display name after sub id is set above so as to get valid simCarrierName - int subId = getSubId(slotIndex); - if (!SubscriptionManager.isValidSubscriptionId(subId)) { - if (DBG) { - logdl("[addSubInfoRecord]- getSubId failed invalid subId = " + subId); - } - return -1; - } - if (setDisplayName) { - String simCarrierName = mTelephonyManager.getSimOperatorName(subId); - String nameToSet; - - if (!TextUtils.isEmpty(simCarrierName)) { - nameToSet = simCarrierName; - } else { - Resources r = Resources.getSystem(); - nameToSet = r.getString(R.string.default_card_name, (slotIndex + 1)); - } - ContentValues value = new ContentValues(); - value.put(SubscriptionManager.DISPLAY_NAME, nameToSet); - resolver.update(SubscriptionManager.getUriForSubscriptionId(subId), value, - null, null); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - if (DBG) logdl("[addSubInfoRecord] sim name = " + nameToSet); - } - - if (DBG) logdl("[addSubInfoRecord]- info size=" + mSlotIndexToSubIds.size()); - } - - } finally { - Binder.restoreCallingIdentity(identity); - } - return 0; - } - - private void updateDefaultSubIdsIfNeeded(int newDefault, int subscriptionType) { - if (DBG) { - logdl("[updateDefaultSubIdsIfNeeded] newDefault=" + newDefault - + ", subscriptionType=" + subscriptionType); - } - // Set the default ot new value only if the current default is invalid. - if (!isActiveSubscriptionId(getDefaultSubId())) { - // current default is not valid anylonger. set a new default - if (DBG) { - logdl("[updateDefaultSubIdsIfNeeded] set sDefaultFallbackSubId=" + newDefault); - } - setDefaultFallbackSubId(newDefault, subscriptionType); - } - - int value = getDefaultSmsSubId(); - if (!isActiveSubscriptionId(value)) { - // current default is not valid. set it to the given newDefault value - setDefaultSmsSubId(newDefault); - } - value = getDefaultDataSubId(); - if (!isActiveSubscriptionId(value)) { - setDefaultDataSubId(newDefault); - } - value = getDefaultVoiceSubId(); - if (!isActiveSubscriptionId(value)) { - setDefaultVoiceSubId(newDefault); - } - } - - /** - * This method returns true if the given subId is among the list of currently active - * subscriptions. - */ - private boolean isActiveSubscriptionId(int subId) { - if (!SubscriptionManager.isValidSubscriptionId(subId)) return false; - ArrayList subIdList = getActiveSubIdArrayList(); - if (subIdList.isEmpty()) return false; - return subIdList.contains(new Integer(subId)); - } - - /* - * Delete subscription info record for the given device. - * @param uniqueId This is the unique identifier for the subscription within the specific - * subscription type. - * @param subscriptionType the type of subscription to be removed - * @return 0 if success, < 0 on error. - */ - @Override - public int removeSubInfo(String uniqueId, int subscriptionType) { - enforceModifyPhoneState("removeSubInfo"); - if (DBG) { - logd("[removeSubInfo] uniqueId: " + uniqueId - + ", subscriptionType: " + subscriptionType); - } - - // validate the given info - does it exist in the active subscription list - int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - int slotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - synchronized (mSubInfoListLock) { - for (SubscriptionInfo info : mCacheActiveSubInfoList) { - if ((info.getSubscriptionType() == subscriptionType) - && info.getIccId().equalsIgnoreCase(uniqueId)) { - subId = info.getSubscriptionId(); - slotIndex = info.getSimSlotIndex(); - break; - } - } - } - if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - if (DBG) { - logd("Invalid subscription details: subscriptionType = " + subscriptionType - + ", uniqueId = " + uniqueId); - } - return -1; - } - - if (DBG) logd("removing the subid : " + subId); - - // Now that all security checks passes, perform the operation as ourselves. - int result = 0; - final long identity = Binder.clearCallingIdentity(); - try { - ContentResolver resolver = mContext.getContentResolver(); - result = resolver.delete(SubscriptionManager.CONTENT_URI, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=? AND " - + SubscriptionManager.SUBSCRIPTION_TYPE + "=?", - new String[]{Integer.toString(subId), Integer.toString(subscriptionType)}); - if (result != 1) { - if (DBG) { - logd("found NO subscription to remove with subscriptionType = " - + subscriptionType + ", uniqueId = " + uniqueId); - } - return -1; - } - refreshCachedActiveSubscriptionInfoList(); - result = mSlotIndexToSubIds.removeFromSubIdList(slotIndex, subId); - if (result == NO_ENTRY_FOR_SLOT_INDEX) { - loge("sSlotIndexToSubIds has no entry for slotIndex = " + slotIndex); - } else if (result == SUB_ID_NOT_IN_SLOT) { - loge("sSlotIndexToSubIds has no subid: " + subId + ", in index: " + slotIndex); - } - - // Since a subscription is removed, if this one is set as default for any setting, - // set some other subid as the default. - int newDefault = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - SubscriptionInfo info = null; - final List records = getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - if (!records.isEmpty()) { - // yes, we have more subscriptions. pick the first one. - // FIXME do we need a policy to figure out which one is to be next default - info = records.get(0); - } - updateDefaultSubIdsIfNeeded(info.getSubscriptionId(), info.getSubscriptionType()); - - notifySubscriptionInfoChanged(); - } finally { - Binder.restoreCallingIdentity(identity); - } - return result; - } - - /** - * Clear an subscriptionInfo to subinfo database if needed by updating slot index to invalid. - * @param slotIndex the slot which the SIM is removed - */ - public void clearSubInfoRecord(int slotIndex) { - if (DBG) logdl("[clearSubInfoRecord]+ iccId:" + " slotIndex:" + slotIndex); - - // update simInfo db with invalid slot index - ContentResolver resolver = mContext.getContentResolver(); - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.SIM_SLOT_INDEX, SubscriptionManager.INVALID_SIM_SLOT_INDEX); - String where = "(" + SubscriptionManager.SIM_SLOT_INDEX + "=" + slotIndex + ")"; - resolver.update(SubscriptionManager.CONTENT_URI, value, where, null); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - boolean isFallBackRefreshRequired = false; - if (mDefaultFallbackSubId.get() > SubscriptionManager.INVALID_SUBSCRIPTION_ID && - mSlotIndexToSubIds.getCopy(slotIndex) != null && - mSlotIndexToSubIds.getCopy(slotIndex).contains(mDefaultFallbackSubId.get())) { - isFallBackRefreshRequired = true; - } - mSlotIndexToSubIds.remove(slotIndex); - // set mDefaultFallbackSubId to invalid in case mSlotIndexToSubIds do not have any entries - if (mSlotIndexToSubIds.size() ==0 ) { - mDefaultFallbackSubId.set(SubscriptionManager.INVALID_SUBSCRIPTION_ID); - } else if (isFallBackRefreshRequired) { - // set mDefaultFallbackSubId to valid subId from mSlotIndexToSubIds - for (int index = 0; index < getActiveSubIdArrayList().size(); index ++) { - int subId = getActiveSubIdArrayList().get(index); - if (subId > SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - mDefaultFallbackSubId.set(subId); - break; - } - } - } - } - - /** - * Insert an empty SubInfo record into the database. - * - *

NOTE: This is not accessible to external processes, so it does not need a permission - * check. It is only intended for use by {@link SubscriptionInfoUpdater}. If there is a - * subscription record exist with the same ICCID, no new empty record will be created. - * - * @return the URL of the newly created row. Return null if no new empty record is - * created. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - @Nullable - public Uri insertEmptySubInfoRecord(String iccId, int slotIndex) { - if (getSubInfoForIccId(iccId) != null) { - loge("insertEmptySubInfoRecord: Found existing record by ICCID. Do not create a " - + "new empty entry."); - return null; - } - return insertEmptySubInfoRecord(iccId, null, slotIndex, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - } - - Uri insertEmptySubInfoRecord(String uniqueId, String displayName, int slotIndex, - int subscriptionType) { - ContentResolver resolver = mContext.getContentResolver(); - ContentValues value = new ContentValues(); - value.put(SubscriptionManager.ICC_ID, uniqueId); - int color = getUnusedColor(mContext.getOpPackageName(), mContext.getAttributionTag()); - // default SIM color differs between slots - value.put(SubscriptionManager.HUE, color); - value.put(SubscriptionManager.SIM_SLOT_INDEX, slotIndex); - value.put(SubscriptionManager.CARRIER_NAME, ""); - value.put(SubscriptionManager.CARD_ID, uniqueId); - value.put(SubscriptionManager.SUBSCRIPTION_TYPE, subscriptionType); - if (!TextUtils.isEmpty(displayName)) { - value.put(SubscriptionManager.DISPLAY_NAME, displayName); - } - if (!isSubscriptionForRemoteSim(subscriptionType)) { - UiccCard card = mUiccController.getUiccCardForPhone(slotIndex); - if (card != null) { - String cardId = card.getCardId(); - if (cardId != null) { - value.put(SubscriptionManager.CARD_ID, cardId); - } - } - UiccSlot slot = mUiccController.getUiccSlotForPhone(slotIndex); - if (slot != null) { - value.put(SubscriptionManager.PORT_INDEX, slot.getPortIndexFromIccId(uniqueId)); - } - } - value.put(SubscriptionManager.ALLOWED_NETWORK_TYPES, - "user=" + RadioAccessFamily.getRafFromNetworkType( - RILConstants.PREFERRED_NETWORK_MODE)); - - value.put(SubscriptionManager.USAGE_SETTING, - SubscriptionManager.USAGE_SETTING_UNKNOWN); - - Uri uri = resolver.insert(SubscriptionManager.CONTENT_URI, value); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - return uri; - } - - /** - * Generate and set carrier text based on input parameters - * @param showPlmn flag to indicate if plmn should be included in carrier text - * @param plmn plmn to be included in carrier text - * @param showSpn flag to indicate if spn should be included in carrier text - * @param spn spn to be included in carrier text - * @return true if carrier text is set, false otherwise - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean setPlmnSpn(int slotIndex, boolean showPlmn, String plmn, boolean showSpn, - String spn) { - synchronized (mLock) { - int subId = getSubId(slotIndex); - if (mContext.getPackageManager().resolveContentProvider( - SubscriptionManager.CONTENT_URI.getAuthority(), 0) == null || - !SubscriptionManager.isValidSubscriptionId(subId)) { - // No place to store this info. Notify registrants of the change anyway as they - // might retrieve the SPN/PLMN text from the SST sticky broadcast. - // TODO: This can be removed once SubscriptionController is not running on devices - // that don't need it, such as TVs. - if (DBG) logd("[setPlmnSpn] No valid subscription to store info"); - notifySubscriptionInfoChanged(); - return false; - } - String carrierText = ""; - if (showPlmn) { - carrierText = plmn; - if (showSpn) { - // Need to show both plmn and spn if both are not same. - if(!Objects.equals(spn, plmn)) { - String separator = mContext.getString( - com.android.internal.R.string.kg_text_message_separator).toString(); - carrierText = new StringBuilder().append(carrierText).append(separator) - .append(spn).toString(); - } - } - } else if (showSpn) { - carrierText = spn; - } - setCarrierText(carrierText, subId); - return true; - } - } - - /** - * Set carrier text by simInfo index - * @param text new carrier text - * @param subId the unique SubInfoRecord index in database - * @return the number of records updated - */ - private int setCarrierText(String text, int subId) { - if (DBG) logd("[setCarrierText]+ text:" + text + " subId:" + subId); - - enforceModifyPhoneState("setCarrierText"); - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - boolean update = true; - int result = 0; - SubscriptionInfo subInfo = getSubscriptionInfo(subId); - if (subInfo != null) { - update = !TextUtils.equals(text, subInfo.getCarrierName()); - } - if (update) { - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.CARRIER_NAME, text); - - result = mContext.getContentResolver().update( - SubscriptionManager.getUriForSubscriptionId(subId), value, null, null); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - notifySubscriptionInfoChanged(); - } else { - if (DBG) logd("[setCarrierText]: no value update"); - } - return result; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Set SIM color tint by simInfo index - * - * @param subId the unique SubInfoRecord index in database - * @param tint the tint color of the SIM - * - * @return the number of records updated - */ - @Override - public int setIconTint(int subId, int tint) { - if (DBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId); - - enforceModifyPhoneState("setIconTint"); - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - validateSubId(subId); - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.HUE, tint); - if (DBG) logd("[setIconTint]- tint:" + tint + " set"); - - int result = mContext.getContentResolver().update( - SubscriptionManager.getUriForSubscriptionId(subId), value, null, null); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - notifySubscriptionInfoChanged(); - - return result; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * This is only for internal use and the returned priority is arbitrary. The idea is to give a - * higher value to name source that has higher priority to override other name sources. - * @param nameSource Source of display name - * @return int representing the priority. Higher value means higher priority. - */ - public static int getNameSourcePriority(@SimDisplayNameSource int nameSource) { - int index = Arrays.asList( - SubscriptionManager.NAME_SOURCE_CARRIER_ID, - SubscriptionManager.NAME_SOURCE_SIM_PNN, - SubscriptionManager.NAME_SOURCE_SIM_SPN, - SubscriptionManager.NAME_SOURCE_CARRIER, - SubscriptionManager.NAME_SOURCE_USER_INPUT // user has highest priority. - ).indexOf(nameSource); - return (index < 0) ? 0 : index; - } - - /** - * Validate whether the NAME_SOURCE_SIM_PNN, NAME_SOURCE_SIM_SPN and - * NAME_SOURCE_CARRIER exist or not. - */ - @VisibleForTesting - public boolean isExistingNameSourceStillValid(SubscriptionInfo subInfo) { - - int subId = subInfo.getSubscriptionId(); - int phoneId = getPhoneId(subInfo.getSubscriptionId()); - - Phone phone = PhoneFactory.getPhone(phoneId); - if (phone == null) { - return true; - } - - String spn; - - switch (subInfo.getDisplayNameSource()) { - case SubscriptionManager.NAME_SOURCE_SIM_PNN: - String pnn = phone.getPlmn(); - return !TextUtils.isEmpty(pnn); - case SubscriptionManager.NAME_SOURCE_SIM_SPN: - spn = getServiceProviderName(phoneId); - return !TextUtils.isEmpty(spn); - case SubscriptionManager.NAME_SOURCE_CARRIER: - // Can not validate eSIM since it should not override with a lower priority source - // if the name is actually coming from eSIM and not from carrier config. - if (subInfo.isEmbedded()) { - return true; - } - CarrierConfigManager configLoader = - mContext.getSystemService(CarrierConfigManager.class); - PersistableBundle config = - configLoader.getConfigForSubId(subId); - if (config == null) { - return true; - } - boolean isCarrierNameOverride = config.getBoolean( - CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL, false); - String carrierName = config.getString( - CarrierConfigManager.KEY_CARRIER_NAME_STRING); - spn = getServiceProviderName(phoneId); - return isCarrierNameOverride - || (TextUtils.isEmpty(spn) && !TextUtils.isEmpty(carrierName)); - case SubscriptionManager.NAME_SOURCE_CARRIER_ID: - case SubscriptionManager.NAME_SOURCE_USER_INPUT: - return true; - } - return false; - } - - @VisibleForTesting - public String getServiceProviderName(int phoneId) { - UiccProfile profile = mUiccController.getUiccProfileForPhone(phoneId); - if (profile == null) { - return null; - } - return profile.getServiceProviderName(); - } - - /** - * Set display name by simInfo index with name source - * @param displayName the display name of SIM card - * @param subId the unique SubInfoRecord index in database - * @param nameSource SIM display name source - * @return the number of records updated - */ - @Override - public int setDisplayNameUsingSrc(String displayName, int subId, - @SimDisplayNameSource int nameSource) { - if (DBG) { - logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId - + " nameSource:" + nameSource); - } - - enforceModifyPhoneState("setDisplayNameUsingSrc"); - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - validateSubId(subId); - List allSubInfo = getSubInfo(null, null); - // if there is no sub in the db, return 0 since subId does not exist in db - if (allSubInfo == null || allSubInfo.isEmpty()) return 0; - for (SubscriptionInfo subInfo : allSubInfo) { - int subInfoNameSource = subInfo.getDisplayNameSource(); - boolean isHigherPriority = (getNameSourcePriority(subInfoNameSource) - > getNameSourcePriority(nameSource)); - boolean isEqualPriorityAndName = (getNameSourcePriority(subInfoNameSource) - == getNameSourcePriority(nameSource)) - && (TextUtils.equals(displayName, subInfo.getDisplayName())); - if (subInfo.getSubscriptionId() == subId - && isExistingNameSourceStillValid(subInfo) - && (isHigherPriority || isEqualPriorityAndName)) { - logd("Name source " + subInfoNameSource + "'s priority " - + getNameSourcePriority(subInfoNameSource) + " is greater than " - + "name source " + nameSource + "'s priority " - + getNameSourcePriority(nameSource) + ", return now."); - return 0; - } - } - String nameToSet; - if (TextUtils.isEmpty(displayName) || displayName.trim().length() == 0) { - nameToSet = mTelephonyManager.getSimOperatorName(subId); - if (TextUtils.isEmpty(nameToSet)) { - if (nameSource == SubscriptionManager.NAME_SOURCE_USER_INPUT - && SubscriptionManager.isValidSlotIndex(getSlotIndex(subId))) { - Resources r = Resources.getSystem(); - nameToSet = r.getString(R.string.default_card_name, - (getSlotIndex(subId) + 1)); - } else { - nameToSet = mContext.getString(SubscriptionManager.DEFAULT_NAME_RES); - } - } - } else { - nameToSet = displayName; - } - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.DISPLAY_NAME, nameToSet); - if (nameSource >= SubscriptionManager.NAME_SOURCE_CARRIER_ID) { - if (DBG) logd("Set nameSource=" + nameSource); - value.put(SubscriptionManager.NAME_SOURCE, nameSource); - } - if (DBG) logd("[setDisplayName]- mDisplayName:" + nameToSet + " set"); - - // Update the nickname on the eUICC chip if it's an embedded subscription. - SubscriptionInfo sub = getSubscriptionInfo(subId); - if (sub != null && sub.isEmbedded()) { - // Ignore the result. - int cardId = sub.getCardId(); - if (DBG) logd("Updating embedded sub nickname on cardId: " + cardId); - EuiccManager euiccManager = ((EuiccManager) - mContext.getSystemService(Context.EUICC_SERVICE)).createForCardId(cardId); - euiccManager.updateSubscriptionNickname(subId, displayName, - // This PendingIntent simply fulfills the requirement to pass in a callback; - // we don't care about the result (hence 0 requestCode and no action - // specified on the intent). - PendingIntent.getService( - mContext, 0 /* requestCode */, new Intent(), - PendingIntent.FLAG_IMMUTABLE /* flags */)); - } - - int result = updateDatabase(value, subId, true); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - notifySubscriptionInfoChanged(); - - return result; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Set phone number by subId - * @param number the phone number of the SIM - * @param subId the unique SubInfoRecord index in database - * @return the number of records updated - */ - @Override - public int setDisplayNumber(String number, int subId) { - if (DBG) logd("[setDisplayNumber]+ subId:" + subId); - - enforceModifyPhoneState("setDisplayNumber"); - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - validateSubId(subId); - int result = 0; - int phoneId = getPhoneId(subId); - - if (number == null || phoneId < 0 || - phoneId >= mTelephonyManager.getPhoneCount()) { - if (DBG) logd("[setDisplayNumber]- fail"); - return -1; - } - boolean update = true; - SubscriptionInfo subInfo = getSubscriptionInfo(subId); - if (subInfo != null) { - update = !TextUtils.equals(subInfo.getNumber(), number); - } - if (update) { - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.NUMBER, number); - - // This function had a call to update number on the SIM (Phone.setLine1Number()) but - // that was removed as there doesn't seem to be a reason for that. If it is added - // back, watch out for deadlocks. - result = mContext.getContentResolver().update( - SubscriptionManager.getUriForSubscriptionId(subId), value, null, null); - if (DBG) logd("[setDisplayNumber]- update result :" + result); - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - notifySubscriptionInfoChanged(); - } else { - if (DBG) logd("[setDisplayNumber]: no value update"); - } - return result; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Set the EHPLMNs and HPLMNs associated with the subscription. - */ - public void setAssociatedPlmns(String[] ehplmns, String[] hplmns, int subId) { - if (DBG) logd("[setAssociatedPlmns]+ subId:" + subId); - - validateSubId(subId); - int phoneId = getPhoneId(subId); - - if (phoneId < 0 || phoneId >= mTelephonyManager.getPhoneCount()) { - if (DBG) logd("[setAssociatedPlmns]- fail"); - return; - } - - // remove trailing empty strings which will also get stripped from - // SubscriptionInfo.getEhplmns() and SubscriptionInfo.getHplmns() - String formattedEhplmns = ehplmns == null ? "" : - Arrays.stream(ehplmns).filter(s -> s != null && !s.isEmpty()) - .collect(Collectors.joining(",")); - String formattedHplmns = hplmns == null ? "" : - Arrays.stream(hplmns).filter(s -> s != null && !s.isEmpty()) - .collect(Collectors.joining(",")); - boolean noChange = false; - SubscriptionInfo subInfo = getSubscriptionInfo(subId); - if (subInfo != null) { - noChange = (ehplmns == null && subInfo.getEhplmns().isEmpty()) - || String.join(",", subInfo.getEhplmns()).equals(formattedEhplmns); - noChange = noChange && (hplmns == null && subInfo.getHplmns().isEmpty()) - || String.join(",", subInfo.getHplmns()).equals(formattedHplmns); - } - if (!noChange) { - ContentValues value = new ContentValues(2); - value.put(SubscriptionManager.EHPLMNS, formattedEhplmns); - value.put(SubscriptionManager.HPLMNS, formattedHplmns); - - int count = mContext.getContentResolver().update( - SubscriptionManager.getUriForSubscriptionId(subId), value, null, null); - if (DBG) logd("[setAssociatedPlmns]- update result :" + count); - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - notifySubscriptionInfoChanged(); - } else { - if (DBG) logd("[setAssociatedPlmns]+ subId:" + subId + "no value update"); - } - } - - /** - * Set data roaming by simInfo index - * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming - * @param subId the unique SubInfoRecord index in database - * @return the number of records updated - */ - @Override - public int setDataRoaming(int roaming, int subId) { - if (DBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId); - - enforceModifyPhoneState("setDataRoaming"); - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - validateSubId(subId); - if (roaming < 0) { - if (DBG) logd("[setDataRoaming]- fail"); - return -1; - } - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.DATA_ROAMING, roaming); - if (DBG) logd("[setDataRoaming]- roaming:" + roaming + " set"); - - int result = updateDatabase(value, subId, true); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - notifySubscriptionInfoChanged(); - - return result; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Set device to device status sharing preference - * @param sharing the sharing preference to set - * @param subId - * @return the number of records updated - */ - @Override - public int setDeviceToDeviceStatusSharing(int sharing, int subId) { - if (DBG) logd("[setDeviceToDeviceStatusSharing]- sharing:" + sharing + " subId:" + subId); - - enforceModifyPhoneState("setDeviceToDeviceStatusSharing"); - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - validateSubId(subId); - if (sharing < 0) { - if (DBG) logd("[setDeviceToDeviceStatusSharing]- fail"); - return -1; - } - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.D2D_STATUS_SHARING, sharing); - if (DBG) logd("[setDeviceToDeviceStatusSharing]- sharing:" + sharing + " set"); - - int result = updateDatabase(value, subId, true); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - notifySubscriptionInfoChanged(); - - return result; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Set contacts that allow device to device status sharing. - * @param contacts contacts to set - * @param subscriptionId - * @return the number of records updated - */ - @Override - public int setDeviceToDeviceStatusSharingContacts(String contacts, int subscriptionId) { - if (DBG) { - logd("[setDeviceToDeviceStatusSharingContacts]- contacts:" + contacts - + " subId:" + subscriptionId); - } - - enforceModifyPhoneState("setDeviceToDeviceStatusSharingContacts"); - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - validateSubId(subscriptionId); - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.D2D_STATUS_SHARING_SELECTED_CONTACTS, contacts); - if (DBG) { - logd("[setDeviceToDeviceStatusSharingContacts]- contacts:" + contacts - + " set"); - } - - int result = updateDatabase(value, subscriptionId, true); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - notifySubscriptionInfoChanged(); - - return result; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - public void syncGroupedSetting(int refSubId) { - logd("syncGroupedSetting"); - try (Cursor cursor = mContext.getContentResolver().query( - SubscriptionManager.CONTENT_URI, null, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=?", - new String[] {String.valueOf(refSubId)}, null)) { - if (cursor == null || !cursor.moveToFirst()) { - logd("[syncGroupedSetting] failed. Can't find refSubId " + refSubId); - return; - } - - ContentValues values = new ContentValues(GROUP_SHARING_PROPERTIES.size()); - for (String propKey : GROUP_SHARING_PROPERTIES) { - copyDataFromCursorToContentValue(propKey, cursor, values); - } - updateDatabase(values, refSubId, true); - } - } - - private void copyDataFromCursorToContentValue(String propKey, Cursor cursor, - ContentValues values) { - int columnIndex = cursor.getColumnIndex(propKey); - if (columnIndex == -1) { - logd("[copyDataFromCursorToContentValue] can't find column " + propKey); - return; - } - - switch (propKey) { - case SubscriptionManager.ENHANCED_4G_MODE_ENABLED: - case SubscriptionManager.VT_IMS_ENABLED: - case SubscriptionManager.WFC_IMS_ENABLED: - case SubscriptionManager.WFC_IMS_MODE: - case SubscriptionManager.WFC_IMS_ROAMING_MODE: - case SubscriptionManager.WFC_IMS_ROAMING_ENABLED: - case SubscriptionManager.DATA_ROAMING: - case SubscriptionManager.IMS_RCS_UCE_ENABLED: - case SubscriptionManager.CROSS_SIM_CALLING_ENABLED: - case SubscriptionManager.NR_ADVANCED_CALLING_ENABLED: - case SubscriptionManager.USER_HANDLE: - values.put(propKey, cursor.getInt(columnIndex)); - break; - case SubscriptionManager.DISPLAY_NAME: - case SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES: - values.put(propKey, cursor.getString(columnIndex)); - break; - default: - loge("[copyDataFromCursorToContentValue] invalid propKey " + propKey); - } - } - - // TODO: replace all updates with this helper method. - private int updateDatabase(ContentValues value, int subId, boolean updateEntireGroup) { - List infoList = getSubscriptionsInGroup(getGroupUuid(subId), - mContext.getOpPackageName(), mContext.getAttributionTag()); - if (!updateEntireGroup || infoList == null || infoList.size() == 0) { - // Only update specified subscriptions. - return mContext.getContentResolver().update( - SubscriptionManager.getUriForSubscriptionId(subId), value, null, null); - } else { - // Update all subscriptions in the same group. - int[] subIdList = new int[infoList.size()]; - for (int i = 0; i < infoList.size(); i++) { - subIdList[i] = infoList.get(i).getSubscriptionId(); - } - return mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, - value, getSelectionForSubIdList(subIdList), null); - } - } - - /** - * Set carrier id by subId - * @param carrierId the subscription carrier id. - * @param subId the unique SubInfoRecord index in database - * @return the number of records updated - * - * @see TelephonyManager#getSimCarrierId() - */ - public int setCarrierId(int carrierId, int subId) { - if (DBG) logd("[setCarrierId]+ carrierId:" + carrierId + " subId:" + subId); - - enforceModifyPhoneState("setCarrierId"); - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - validateSubId(subId); - int result = 0; - boolean update = true; - SubscriptionInfo subInfo = getSubscriptionInfo(subId); - if (subInfo != null) { - update = subInfo.getCarrierId() != carrierId; - } - if (update) { - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.CARRIER_ID, carrierId); - result = mContext.getContentResolver().update( - SubscriptionManager.getUriForSubscriptionId(subId), value, null, null); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - notifySubscriptionInfoChanged(); - } else { - if (DBG) logd("[setCarrierId]: no value update"); - } - return result; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Set MCC/MNC by subscription ID - * @param mccMnc MCC/MNC associated with the subscription - * @param subId the unique SubInfoRecord index in database - * @return the number of records updated - */ - public int setMccMnc(String mccMnc, int subId) { - String mccString = mccMnc.substring(0, 3); - String mncString = mccMnc.substring(3); - int mcc = 0; - int mnc = 0; - try { - mcc = Integer.parseInt(mccString); - mnc = Integer.parseInt(mncString); - } catch (NumberFormatException e) { - loge("[setMccMnc] - couldn't parse mcc/mnc: " + mccMnc); - } - SubscriptionInfo subInfo = getSubscriptionInfo(subId); - // check if there are any update - boolean update = true; - if (subInfo != null) { - update = (subInfo.getMcc() != mcc) || (subInfo.getMnc() != mnc) - || !mccString.equals(subInfo.getMccString()) - || !mncString.equals(subInfo.getMncString()); - } - int result = 0; - if (update) { - ContentValues value = new ContentValues(4); - value.put(SubscriptionManager.MCC, mcc); - value.put(SubscriptionManager.MNC, mnc); - value.put(SubscriptionManager.MCC_STRING, mccString); - value.put(SubscriptionManager.MNC_STRING, mncString); - - result = mContext.getContentResolver().update( - SubscriptionManager.getUriForSubscriptionId(subId), value, null, null); - if (DBG) logd("[setMccMnc]+ mcc/mnc:" + mcc + "/" + mnc + " subId:" + subId); - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - notifySubscriptionInfoChanged(); - } else { - if (DBG) logd("[setMccMnc] - no values update"); - } - return result; - } - - /** - * Scrub given IMSI on production builds. - */ - private String scrubImsi(String imsi) { - if (Build.IS_ENG) { - return imsi; - } else if (imsi != null) { - return imsi.substring(0, Math.min(6, imsi.length())) + "..."; - } else { - return "null"; - } - } - - /** - * Set IMSI by subscription ID - * @param imsi IMSI (International Mobile Subscriber Identity) - * @return the number of records updated - */ - public int setImsi(String imsi, int subId) { - if (DBG) logd("[setImsi]+ imsi:" + scrubImsi(imsi) + " subId:" + subId); - boolean update = true; - int result = 0; - SubscriptionInfo subInfo = getSubscriptionInfo(subId); - if (subInfo != null) { - update = !TextUtils.equals(getImsiPrivileged(subId),imsi); - } - - if (update) { - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.IMSI, imsi); - result = mContext.getContentResolver().update( - SubscriptionManager.getUriForSubscriptionId(subId), value, null, null); - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - notifySubscriptionInfoChanged(); - } else { - if (DBG) logd("[setImsi]: no value update"); - } - return result; - } - - /** - * Set uicc applications being enabled or disabled. - * @param enabled whether uicc applications are enabled or disabled. - */ - public void setUiccApplicationsEnabled(boolean enabled, int subId) { - if (DBG) logd("[setUiccApplicationsEnabled]+ enabled:" + enabled + " subId:" + subId); - - enforceModifyPhoneState("setUiccApplicationsEnabled"); - - long identity = Binder.clearCallingIdentity(); - try { - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.UICC_APPLICATIONS_ENABLED, enabled); - - mContext.getContentResolver().update(SubscriptionManager.getUriForSubscriptionId(subId), - value, null, null); - - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - notifyUiccAppsEnableChanged(); - notifySubscriptionInfoChanged(); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Register to change of uicc applications enablement changes. - * @param notifyNow whether to notify target upon registration. - */ - public void registerForUiccAppsEnabled(Handler handler, int what, Object object, - boolean notifyNow) { - mUiccAppsEnableChangeRegList.addUnique(handler, what, object); - if (notifyNow) { - handler.obtainMessage(what, object).sendToTarget(); - } - } - - /** - * Unregister to change of uicc applications enablement changes. - */ - public void unregisterForUiccAppsEnabled(Handler handler) { - mUiccAppsEnableChangeRegList.remove(handler); - } - - private void notifyUiccAppsEnableChanged() { - mUiccAppsEnableChangeRegList.notifyRegistrants(); - } - - /** - * Get IMSI by subscription ID - * For active subIds, this will always return the corresponding imsi - * For inactive subIds, once they are activated once, even if they are deactivated at the time - * of calling this function, the corresponding imsi will be returned - * When calling this method, the permission check should have already been done to allow - * only privileged read - * - * @return imsi - */ - public String getImsiPrivileged(int subId) { - try (Cursor cursor = mContext.getContentResolver().query( - SubscriptionManager.CONTENT_URI, null, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=?", - new String[] {String.valueOf(subId)}, null)) { - String imsi = null; - if (cursor != null) { - if (cursor.moveToNext()) { - imsi = getOptionalStringFromCursor(cursor, SubscriptionManager.IMSI, - /*defaultVal*/ null); - } - } else { - logd("getImsiPrivileged: failed to retrieve imsi."); - } - - return imsi; - } - } - - /** - * Set ISO country code by subscription ID - * @param iso iso country code associated with the subscription - * @param subId the unique SubInfoRecord index in database - * @return the number of records updated - */ - public int setCountryIso(String iso, int subId) { - if (DBG) logd("[setCountryIso]+ iso:" + iso + " subId:" + subId); - boolean update = true; - int result = 0; - SubscriptionInfo subInfo = getSubscriptionInfo(subId); - if (subInfo != null) { - update = !TextUtils.equals(subInfo.getCountryIso(), iso); - } - if (update) { - ContentValues value = new ContentValues(); - value.put(SubscriptionManager.ISO_COUNTRY_CODE, iso); - - result = mContext.getContentResolver().update( - SubscriptionManager.getUriForSubscriptionId(subId), value, null, null); - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - notifySubscriptionInfoChanged(); - } else { - if (DBG) logd("[setCountryIso]: no value update"); - } - return result; - } - - @Override - public int getSlotIndex(int subId) { - if (VDBG) printStackTrace("[getSlotIndex] subId=" + subId); - - if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - subId = getDefaultSubId(); - } - if (!SubscriptionManager.isValidSubscriptionId(subId)) { - if (DBG) logd("[getSlotIndex]- subId invalid"); - return SubscriptionManager.INVALID_SIM_SLOT_INDEX; - } - - int size = mSlotIndexToSubIds.size(); - - if (size == 0) { - if (DBG) logd("[getSlotIndex]- size == 0, return SIM_NOT_INSERTED instead"); - return SubscriptionManager.SIM_NOT_INSERTED; - } - - for (Entry> entry : mSlotIndexToSubIds.entrySet()) { - int sim = entry.getKey(); - ArrayList subs = entry.getValue(); - - if (subs != null && subs.contains(subId)) { - if (VDBG) logv("[getSlotIndex]- return = " + sim); - return sim; - } - } - - if (DBG) logd("[getSlotIndex]- return fail"); - return SubscriptionManager.INVALID_SIM_SLOT_INDEX; - } - - /** - * Return the subIds for specified slot Id. - * @deprecated - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Deprecated - public int[] getSubIds(int slotIndex) { - if (VDBG) printStackTrace("[getSubId]+ slotIndex=" + slotIndex); - - // Map default slotIndex to the current default subId. - // TODO: Not used anywhere sp consider deleting as it's somewhat nebulous - // as a slot maybe used for multiple different type of "connections" - // such as: voice, data and sms. But we're doing the best we can and using - // getDefaultSubId which makes a best guess. - if (slotIndex == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) { - slotIndex = getSlotIndex(getDefaultSubId()); - if (VDBG) logd("[getSubId] map default slotIndex=" + slotIndex); - } - - // Check that we have a valid slotIndex or the slotIndex is for a remote SIM (remote SIM - // uses special slot index that may be invalid otherwise) - if (!SubscriptionManager.isValidSlotIndex(slotIndex) - && slotIndex != SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB) { - if (DBG) logd("[getSubId]- invalid slotIndex=" + slotIndex); - return null; - } - - // Check if we've got any SubscriptionInfo records using slotIndexToSubId as a surrogate. - int size = mSlotIndexToSubIds.size(); - if (size == 0) { - if (VDBG) { - logd("[getSubId]- sSlotIndexToSubIds.size == 0, return null slotIndex=" - + slotIndex); - } - return null; - } - - // Convert ArrayList to array - ArrayList subIds = mSlotIndexToSubIds.getCopy(slotIndex); - if (subIds != null && subIds.size() > 0) { - int[] subIdArr = new int[subIds.size()]; - for (int i = 0; i < subIds.size(); i++) { - subIdArr[i] = subIds.get(i); - } - if (VDBG) logd("[getSubId]- subIdArr=" + Arrays.toString(subIdArr)); - return subIdArr; - } else { - if (DBG) logd("[getSubId]- numSubIds == 0, return null slotIndex=" + slotIndex); - return null; - } - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Override - public int getPhoneId(int subId) { - if (VDBG) printStackTrace("[getPhoneId] subId=" + subId); - int phoneId; - - if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - subId = getDefaultSubId(); - if (DBG) logd("[getPhoneId] asked for default subId=" + subId); - } - - if (!SubscriptionManager.isValidSubscriptionId(subId)) { - if (VDBG) { - logdl("[getPhoneId]- invalid subId return=" - + SubscriptionManager.INVALID_PHONE_INDEX); - } - return SubscriptionManager.INVALID_PHONE_INDEX; - } - - int size = mSlotIndexToSubIds.size(); - if (size == 0) { - phoneId = mDefaultPhoneId; - if (VDBG) logdl("[getPhoneId]- no sims, returning default phoneId=" + phoneId); - return phoneId; - } - - // FIXME: Assumes phoneId == slotIndex - for (Entry> entry: mSlotIndexToSubIds.entrySet()) { - int sim = entry.getKey(); - ArrayList subs = entry.getValue(); - - if (subs != null && subs.contains(subId)) { - if (VDBG) logdl("[getPhoneId]- found subId=" + subId + " phoneId=" + sim); - return sim; - } - } - - phoneId = mDefaultPhoneId; - if (VDBG) { - logd("[getPhoneId]- subId=" + subId + " not found return default phoneId=" + phoneId); - } - return phoneId; - - } - - /** - * @return the number of records cleared - */ - public int clearSubInfo() { - enforceModifyPhoneState("clearSubInfo"); - - // Now that all security checks passes, perform the operation as ourselves. - final long identity = Binder.clearCallingIdentity(); - try { - int size = mSlotIndexToSubIds.size(); - - if (size == 0) { - if (DBG) logdl("[clearSubInfo]- no simInfo size=" + size); - return 0; - } - - mSlotIndexToSubIds.clear(); - if (DBG) logdl("[clearSubInfo]- clear size=" + size); - return size; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - private void logvl(String msg) { - logv(msg); - mLocalLog.log(msg); - } - - private void logv(String msg) { - Rlog.v(LOG_TAG, msg); - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - protected void logdl(String msg) { - logd(msg); - mLocalLog.log(msg); - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private void logd(String msg) { - Rlog.d(LOG_TAG, msg); - } - - private void logel(String msg) { - loge(msg); - mLocalLog.log(msg); - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private void loge(String msg) { - Rlog.e(LOG_TAG, msg); - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Override - public int getDefaultSubId() { - int subId; - boolean isVoiceCapable = mTelephonyManager.isVoiceCapable(); - if (isVoiceCapable) { - subId = getDefaultVoiceSubId(); - if (VDBG) logdl("[getDefaultSubId] isVoiceCapable subId=" + subId); - } else { - subId = getDefaultDataSubId(); - if (VDBG) logdl("[getDefaultSubId] NOT VoiceCapable subId=" + subId); - } - if (!isActiveSubId(subId)) { - subId = mDefaultFallbackSubId.get(); - if (VDBG) logdl("[getDefaultSubId] NOT active use fall back subId=" + subId); - } - if (VDBG) logv("[getDefaultSubId]- value = " + subId); - return subId; - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Override - public void setDefaultSmsSubId(int subId) { - enforceModifyPhoneState("setDefaultSmsSubId"); - - if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - throw new RuntimeException("setDefaultSmsSubId called with DEFAULT_SUB_ID"); - } - if (DBG) logdl("[setDefaultSmsSubId] subId=" + subId); - setGlobalSetting(Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, subId); - broadcastDefaultSmsSubIdChanged(subId); - } - - private void broadcastDefaultSmsSubIdChanged(int subId) { - // Broadcast an Intent for default sms sub change - if (DBG) logdl("[broadcastDefaultSmsSubIdChanged] subId=" + subId); - Intent intent = new Intent(SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - SubscriptionManager.putSubscriptionIdExtra(intent, subId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Override - public int getDefaultSmsSubId() { - int subId = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (VDBG) logd("[getDefaultSmsSubId] subId=" + subId); - return subId; - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Override - public void setDefaultVoiceSubId(int subId) { - enforceModifyPhoneState("setDefaultVoiceSubId"); - - if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - throw new RuntimeException("setDefaultVoiceSubId called with DEFAULT_SUB_ID"); - } - - logdl("[setDefaultVoiceSubId] subId=" + subId); - - int previousDefaultSub = getDefaultSubId(); - - setGlobalSetting(Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, subId); - broadcastDefaultVoiceSubIdChanged(subId); - - PhoneAccountHandle newHandle = - subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID - ? null : mTelephonyManager.getPhoneAccountHandleForSubscriptionId( - subId); - - TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); - - telecomManager.setUserSelectedOutgoingPhoneAccount(newHandle); - logd("[setDefaultVoiceSubId] requesting change to phoneAccountHandle=" + newHandle); - - if (previousDefaultSub != getDefaultSubId()) { - sendDefaultChangedBroadcast(getDefaultSubId()); - logd(String.format("[setDefaultVoiceSubId] change to subId=%d", getDefaultSubId())); - } else { - logd(String.format("[setDefaultVoiceSubId] default subId not changed. subId=%d", - previousDefaultSub)); - } - } - - /** - * Broadcast intent of ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED. - * @hide - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - public void broadcastDefaultVoiceSubIdChanged(int subId) { - // Broadcast an Intent for default voice sub change - if (DBG) logdl("[broadcastDefaultVoiceSubIdChanged] subId=" + subId); - Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - SubscriptionManager.putSubscriptionIdExtra(intent, subId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Override - public int getDefaultVoiceSubId() { - int subId = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (VDBG) logd("[getDefaultVoiceSubId] subId=" + subId); - return subId; - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Override - public int getDefaultDataSubId() { - int subId = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (VDBG) logd("[getDefaultDataSubId] subId=" + subId); - return subId; - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Override - public void setDefaultDataSubId(int subId) { - enforceModifyPhoneState("setDefaultDataSubId"); - - final long identity = Binder.clearCallingIdentity(); - try { - if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - throw new RuntimeException("setDefaultDataSubId called with DEFAULT_SUB_ID"); - } - - ProxyController proxyController = ProxyController.getInstance(); - int len = TelephonyManager.from(mContext).getActiveModemCount(); - logdl("[setDefaultDataSubId] num phones=" + len + ", subId=" + subId); - - if (SubscriptionManager.isValidSubscriptionId(subId)) { - // Only re-map modems if the new default data sub is valid - RadioAccessFamily[] rafs = new RadioAccessFamily[len]; - boolean atLeastOneMatch = false; - for (int phoneId = 0; phoneId < len; phoneId++) { - Phone phone = PhoneFactory.getPhone(phoneId); - int raf; - int id = phone.getSubId(); - if (id == subId) { - // TODO Handle the general case of N modems and M subscriptions. - raf = proxyController.getMaxRafSupported(); - atLeastOneMatch = true; - } else { - // TODO Handle the general case of N modems and M subscriptions. - raf = proxyController.getMinRafSupported(); - } - logdl("[setDefaultDataSubId] phoneId=" + phoneId + " subId=" + id + " RAF=" - + raf); - rafs[phoneId] = new RadioAccessFamily(phoneId, raf); - } - if (atLeastOneMatch) { - proxyController.setRadioCapability(rafs); - } else { - if (DBG) logdl("[setDefaultDataSubId] no valid subId's found - not updating."); - } - } - - int previousDefaultSub = getDefaultSubId(); - setGlobalSetting(Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, subId); - MultiSimSettingController.getInstance().notifyDefaultDataSubChanged(); - broadcastDefaultDataSubIdChanged(subId); - if (previousDefaultSub != getDefaultSubId()) { - sendDefaultChangedBroadcast(getDefaultSubId()); - } - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private void broadcastDefaultDataSubIdChanged(int subId) { - // Broadcast an Intent for default data sub change - if (DBG) logdl("[broadcastDefaultDataSubIdChanged] subId=" + subId); - Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - SubscriptionManager.putSubscriptionIdExtra(intent, subId); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - /* Sets the default subscription. If only one sub is active that - * sub is set as default subId. If two or more sub's are active - * the first sub is set as default subscription - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - protected void setDefaultFallbackSubId(int subId, int subscriptionType) { - if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - throw new RuntimeException("setDefaultSubId called with DEFAULT_SUB_ID"); - } - if (DBG) { - logdl("[setDefaultFallbackSubId] subId=" + subId + ", subscriptionType=" - + subscriptionType); - } - int previousDefaultSub = getDefaultSubId(); - if (isSubscriptionForRemoteSim(subscriptionType)) { - mDefaultFallbackSubId.set(subId); - return; - } - if (SubscriptionManager.isValidSubscriptionId(subId)) { - int phoneId = getPhoneId(subId); - if (phoneId >= 0 && (phoneId < mTelephonyManager.getPhoneCount() - || mTelephonyManager.getSimCount() == 1)) { - if (DBG) logdl("[setDefaultFallbackSubId] set sDefaultFallbackSubId=" + subId); - mDefaultFallbackSubId.set(subId); - // Update MCC MNC device configuration information - String defaultMccMnc = mTelephonyManager.getSimOperatorNumericForPhone(phoneId); - MccTable.updateMccMncConfiguration(mContext, defaultMccMnc); - } else { - if (DBG) { - logdl("[setDefaultFallbackSubId] not set invalid phoneId=" + phoneId - + " subId=" + subId); - } - } - } - if (previousDefaultSub != getDefaultSubId()) { - sendDefaultChangedBroadcast(getDefaultSubId()); - } - } - - public void sendDefaultChangedBroadcast(int subId) { - // Broadcast an Intent for default sub change - int phoneId = SubscriptionManager.getPhoneId(subId); - Intent intent = new Intent(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId, subId); - if (DBG) { - logdl("[sendDefaultChangedBroadcast] broadcast default subId changed phoneId=" - + phoneId + " subId=" + subId); - } - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } - - /** - * Whether a subscription is opportunistic or not. - */ - public boolean isOpportunistic(int subId) { - SubscriptionInfo info = getActiveSubscriptionInfo(subId, mContext.getOpPackageName(), - mContext.getAttributionTag()); - return (info != null) && info.isOpportunistic(); - } - - // FIXME: We need we should not be assuming phoneId == slotIndex as it will not be true - // when there are multiple subscriptions per sim and probably for other reasons. - public int getSubId(int phoneId) { - int[] subIds = getSubIds(phoneId); - if (subIds == null || subIds.length == 0) { - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; - } - return subIds[0]; - } - - /** Must be public for access from instrumentation tests. */ - @VisibleForTesting - public List getSubInfoUsingSlotIndexPrivileged(int slotIndex) { - if (DBG) logd("[getSubInfoUsingSlotIndexPrivileged]+ slotIndex:" + slotIndex); - if (slotIndex == SubscriptionManager.DEFAULT_SIM_SLOT_INDEX) { - slotIndex = getSlotIndex(getDefaultSubId()); - } - if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { - if (DBG) logd("[getSubInfoUsingSlotIndexPrivileged]- invalid slotIndex"); - return null; - } - - Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, - null, SubscriptionManager.SIM_SLOT_INDEX + "=?", - new String[]{String.valueOf(slotIndex)}, null); - ArrayList subList = null; - try { - if (cursor != null) { - while (cursor.moveToNext()) { - SubscriptionInfo subInfo = getSubInfoRecord(cursor); - if (subInfo != null) { - if (subList == null) { - subList = new ArrayList(); - } - subList.add(subInfo); - } - } - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - if (DBG) logd("[getSubInfoUsingSlotIndex]- null info return"); - - return subList; - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private void validateSubId(int subId) { - if (DBG) logd("validateSubId subId: " + subId); - if (!SubscriptionManager.isValidSubscriptionId(subId)) { - throw new IllegalArgumentException("Invalid sub id passed as parameter"); - } else if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - throw new IllegalArgumentException("Default sub id passed as parameter"); - } - } - - private synchronized ArrayList getActiveSubIdArrayList() { - // Clone the sub id list so it can't change out from under us while iterating - List>> simInfoList = - new ArrayList<>(mSlotIndexToSubIds.entrySet()); - - // Put the set of sub ids in slot index order - Collections.sort(simInfoList, (x, y) -> x.getKey().compareTo(y.getKey())); - - // Collect the sub ids for each slot in turn - ArrayList allSubs = new ArrayList<>(); - for (Entry> slot : simInfoList) { - allSubs.addAll(slot.getValue()); - } - return allSubs; - } - - private boolean isSubscriptionVisible(int subId) { - synchronized (mSubInfoListLock) { - for (SubscriptionInfo info : mCacheOpportunisticSubInfoList) { - if (info.getSubscriptionId() == subId) { - // If group UUID is null, it's stand alone opportunistic profile. So it's - // visible. Otherwise, it's bundled opportunistic profile, and is not visible. - return info.getGroupUuid() == null; - } - } - } - - return true; - } - - /** - * @return the list of subId's that are active, is never null but the length maybe 0. - */ - @Override - public int[] getActiveSubIdList(boolean visibleOnly) { - enforceReadPrivilegedPhoneState("getActiveSubIdList"); - - final long token = Binder.clearCallingIdentity(); - try { - List allSubs = getActiveSubIdArrayList(); - - if (visibleOnly) { - // Grouped opportunistic subscriptions should be hidden. - allSubs = allSubs.stream().filter(subId -> isSubscriptionVisible(subId)) - .collect(Collectors.toList()); - } - - int[] subIdArr = new int[allSubs.size()]; - int i = 0; - for (int sub : allSubs) { - subIdArr[i] = sub; - i++; - } - - if (VDBG) { - logdl("[getActiveSubIdList] allSubs=" + allSubs + " subIdArr.length=" - + subIdArr.length); - } - return subIdArr; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public boolean isActiveSubId(int subId, String callingPackage, String callingFeatureId) { - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage, - callingFeatureId, "isActiveSubId")) { - throw new SecurityException("Requires READ_PHONE_STATE permission."); - } - final long identity = Binder.clearCallingIdentity(); - try { - return isActiveSubId(subId); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Deprecated // This should be moved into isActiveSubId(int, String) - public boolean isActiveSubId(int subId) { - boolean retVal = SubscriptionManager.isValidSubscriptionId(subId) - && getActiveSubIdArrayList().contains(subId); - - if (VDBG) logdl("[isActiveSubId]- " + retVal); - return retVal; - } - - /** - * Store properties associated with SubscriptionInfo in database - * @param subId Subscription Id of Subscription - * @param propKey Column name in database associated with SubscriptionInfo - * @param propValue Value to store in DB for particular subId & column name - * - * @return number of rows updated. - * @hide - */ - @Override - public int setSubscriptionProperty(int subId, String propKey, String propValue) { - enforceModifyPhoneState("setSubscriptionProperty"); - final long token = Binder.clearCallingIdentity(); - - try { - validateSubId(subId); - ContentResolver resolver = mContext.getContentResolver(); - int result = setSubscriptionPropertyIntoContentResolver( - subId, propKey, propValue, resolver); - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - - return result; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private int setSubscriptionPropertyIntoContentResolver( - int subId, String propKey, String propValue, ContentResolver resolver) { - ContentValues value = new ContentValues(); - boolean updateEntireGroup = GROUP_SHARING_PROPERTIES.contains(propKey); - switch (propKey) { - case SubscriptionManager.CB_EXTREME_THREAT_ALERT: - case SubscriptionManager.CB_SEVERE_THREAT_ALERT: - case SubscriptionManager.CB_AMBER_ALERT: - case SubscriptionManager.CB_EMERGENCY_ALERT: - case SubscriptionManager.CB_ALERT_SOUND_DURATION: - case SubscriptionManager.CB_ALERT_REMINDER_INTERVAL: - case SubscriptionManager.CB_ALERT_VIBRATE: - case SubscriptionManager.CB_ALERT_SPEECH: - case SubscriptionManager.CB_ETWS_TEST_ALERT: - case SubscriptionManager.CB_CHANNEL_50_ALERT: - case SubscriptionManager.CB_CMAS_TEST_ALERT: - case SubscriptionManager.CB_OPT_OUT_DIALOG: - case SubscriptionManager.ENHANCED_4G_MODE_ENABLED: - case SubscriptionManager.IS_OPPORTUNISTIC: - case SubscriptionManager.VT_IMS_ENABLED: - case SubscriptionManager.WFC_IMS_ENABLED: - case SubscriptionManager.WFC_IMS_MODE: - case SubscriptionManager.WFC_IMS_ROAMING_MODE: - case SubscriptionManager.WFC_IMS_ROAMING_ENABLED: - case SubscriptionManager.IMS_RCS_UCE_ENABLED: - case SubscriptionManager.CROSS_SIM_CALLING_ENABLED: - case SubscriptionManager.VOIMS_OPT_IN_STATUS: - case SubscriptionManager.NR_ADVANCED_CALLING_ENABLED: - case SubscriptionManager.USAGE_SETTING: - case SubscriptionManager.USER_HANDLE: - case SubscriptionManager.SATELLITE_ENABLED: - value.put(propKey, Integer.parseInt(propValue)); - break; - case SubscriptionManager.ALLOWED_NETWORK_TYPES: - case SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER: - case SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS: - value.put(propKey, propValue); - break; - default: - if (DBG) logd("Invalid column name"); - break; - } - - return updateDatabase(value, subId, updateEntireGroup); - } - - /** - * Get properties associated with SubscriptionInfo from database - * - * @param subId Subscription Id of Subscription - * @param propKey Column name in SubscriptionInfo database - * @return Value associated with subId and propKey column in database - */ - @Override - public String getSubscriptionProperty(int subId, String propKey, String callingPackage, - String callingFeatureId) { - switch (propKey) { - case SubscriptionManager.GROUP_UUID: - if (mContext.checkCallingOrSelfPermission( - Manifest.permission.READ_PRIVILEGED_PHONE_STATE) != PERMISSION_GRANTED) { - EventLog.writeEvent(0x534e4554, "213457638", Binder.getCallingUid()); - return null; - } - break; - default: - if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, - callingPackage, callingFeatureId, "getSubscriptionProperty")) { - return null; - } - } - - final long identity = Binder.clearCallingIdentity(); - try { - return getSubscriptionProperty(subId, propKey); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Get properties associated with SubscriptionInfo from database. Note this is the version - * without permission check for telephony internal use only. - * - * @param subId Subscription Id of Subscription - * @param propKey Column name in SubscriptionInfo database - * @return Value associated with subId and propKey column in database - */ - public String getSubscriptionProperty(int subId, String propKey) { - String resultValue = null; - try (Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, - new String[]{propKey}, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=?", - new String[]{subId + ""}, null)) { - if (cursor != null) { - if (cursor.moveToFirst()) { - switch (propKey) { - case SubscriptionManager.CB_EXTREME_THREAT_ALERT: - case SubscriptionManager.CB_SEVERE_THREAT_ALERT: - case SubscriptionManager.CB_AMBER_ALERT: - case SubscriptionManager.CB_EMERGENCY_ALERT: - case SubscriptionManager.CB_ALERT_SOUND_DURATION: - case SubscriptionManager.CB_ALERT_REMINDER_INTERVAL: - case SubscriptionManager.CB_ALERT_VIBRATE: - case SubscriptionManager.CB_ALERT_SPEECH: - case SubscriptionManager.CB_ETWS_TEST_ALERT: - case SubscriptionManager.CB_CHANNEL_50_ALERT: - case SubscriptionManager.CB_CMAS_TEST_ALERT: - case SubscriptionManager.CB_OPT_OUT_DIALOG: - case SubscriptionManager.ENHANCED_4G_MODE_ENABLED: - case SubscriptionManager.VT_IMS_ENABLED: - case SubscriptionManager.WFC_IMS_ENABLED: - case SubscriptionManager.WFC_IMS_MODE: - case SubscriptionManager.WFC_IMS_ROAMING_MODE: - case SubscriptionManager.WFC_IMS_ROAMING_ENABLED: - case SubscriptionManager.IMS_RCS_UCE_ENABLED: - case SubscriptionManager.CROSS_SIM_CALLING_ENABLED: - case SubscriptionManager.IS_OPPORTUNISTIC: - case SubscriptionManager.GROUP_UUID: - case SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES: - case SubscriptionManager.ALLOWED_NETWORK_TYPES: - case SubscriptionManager.D2D_STATUS_SHARING: - case SubscriptionManager.VOIMS_OPT_IN_STATUS: - case SubscriptionManager.D2D_STATUS_SHARING_SELECTED_CONTACTS: - case SubscriptionManager.NR_ADVANCED_CALLING_ENABLED: - case SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER: - case SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS: - case SubscriptionManager.USAGE_SETTING: - case SubscriptionManager.USER_HANDLE: - case SubscriptionManager.SATELLITE_ENABLED: - resultValue = cursor.getString(0); - break; - default: - if(DBG) logd("Invalid column name"); - break; - } - } else { - if(DBG) logd("Valid row not present in db"); - } - } else { - if(DBG) logd("Query failed"); - } - } - - if (DBG) logd("getSubscriptionProperty Query value = " + resultValue); - return resultValue; - } - - private void printStackTrace(String msg) { - RuntimeException re = new RuntimeException(); - logd("StackTrace - " + msg); - StackTraceElement[] st = re.getStackTrace(); - boolean first = true; - for (StackTraceElement ste : st) { - if (first) { - first = false; - } else { - logd(ste.toString()); - } - } - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, - "Requires DUMP"); - final long token = Binder.clearCallingIdentity(); - try { - pw.println("SubscriptionController:"); - pw.println(" mLastISubServiceRegTime=" + mLastISubServiceRegTime); - pw.println(" defaultSubId=" + getDefaultSubId()); - pw.println(" defaultDataSubId=" + getDefaultDataSubId()); - pw.println(" defaultVoiceSubId=" + getDefaultVoiceSubId()); - pw.println(" defaultSmsSubId=" + getDefaultSmsSubId()); - pw.println(" defaultVoicePhoneId=" + SubscriptionManager.getDefaultVoicePhoneId()); - pw.flush(); - - for (Entry> entry : mSlotIndexToSubIds.entrySet()) { - pw.println(" sSlotIndexToSubId[" + entry.getKey() + "]: subIds=" + entry); - } - pw.flush(); - pw.println("++++++++++++++++++++++++++++++++"); - - List sirl = getActiveSubscriptionInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - if (sirl != null) { - pw.println(" ActiveSubInfoList:"); - for (SubscriptionInfo entry : sirl) { - pw.println(" " + entry.toString()); - } - } else { - pw.println(" ActiveSubInfoList: is null"); - } - pw.flush(); - pw.println("++++++++++++++++++++++++++++++++"); - - sirl = getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()); - if (sirl != null) { - pw.println(" AllSubInfoList:"); - for (SubscriptionInfo entry : sirl) { - pw.println(" " + entry.toString()); - } - } else { - pw.println(" AllSubInfoList: is null"); - } - pw.flush(); - pw.println("++++++++++++++++++++++++++++++++"); - - mLocalLog.dump(fd, pw, args); - pw.flush(); - pw.println("++++++++++++++++++++++++++++++++"); - pw.flush(); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Migrating Ims settings from global setting to subscription DB, if not already done. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - public void migrateImsSettings() { - migrateImsSettingHelper( - Settings.Global.ENHANCED_4G_MODE_ENABLED, - SubscriptionManager.ENHANCED_4G_MODE_ENABLED); - migrateImsSettingHelper( - Settings.Global.VT_IMS_ENABLED, - SubscriptionManager.VT_IMS_ENABLED); - migrateImsSettingHelper( - Settings.Global.WFC_IMS_ENABLED, - SubscriptionManager.WFC_IMS_ENABLED); - migrateImsSettingHelper( - Settings.Global.WFC_IMS_MODE, - SubscriptionManager.WFC_IMS_MODE); - migrateImsSettingHelper( - Settings.Global.WFC_IMS_ROAMING_MODE, - SubscriptionManager.WFC_IMS_ROAMING_MODE); - migrateImsSettingHelper( - Settings.Global.WFC_IMS_ROAMING_ENABLED, - SubscriptionManager.WFC_IMS_ROAMING_ENABLED); - } - - private void migrateImsSettingHelper(String settingGlobal, String subscriptionProperty) { - ContentResolver resolver = mContext.getContentResolver(); - int defaultSubId = getDefaultVoiceSubId(); - if (defaultSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - return; - } - try { - int prevSetting = Settings.Global.getInt(resolver, settingGlobal); - - if (prevSetting != DEPRECATED_SETTING) { - // Write previous setting into Subscription DB. - setSubscriptionPropertyIntoContentResolver(defaultSubId, subscriptionProperty, - Integer.toString(prevSetting), resolver); - // Write global setting value with DEPRECATED_SETTING making sure - // migration only happen once. - Settings.Global.putInt(resolver, settingGlobal, DEPRECATED_SETTING); - } - } catch (Settings.SettingNotFoundException e) { - } - } - - /** - * Set whether a subscription is opportunistic. - * - * Throws SecurityException if doesn't have required permission. - * - * @param opportunistic whether it’s opportunistic subscription. - * @param subId the unique SubscriptionInfo index in database - * @param callingPackage The package making the IPC. - * @return the number of records updated - */ - @Override - public int setOpportunistic(boolean opportunistic, int subId, String callingPackage) { - try { - TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege( - mContext, subId, callingPackage); - } catch (SecurityException e) { - // The subscription may be inactive eSIM profile. If so, check the access rule in - // database. - enforceCarrierPrivilegeOnInactiveSub(subId, callingPackage, - "Caller requires permission on sub " + subId); - } - - long token = Binder.clearCallingIdentity(); - try { - int ret = setSubscriptionProperty(subId, SubscriptionManager.IS_OPPORTUNISTIC, - String.valueOf(opportunistic ? 1 : 0)); - if (ret != 0) notifySubscriptionInfoChanged(); - return ret; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Get subscription info from database, and check whether caller has carrier privilege - * permission with it. If checking fails, throws SecurityException. - */ - private void enforceCarrierPrivilegeOnInactiveSub(int subId, String callingPackage, - String message) { - mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); - - SubscriptionManager subManager = (SubscriptionManager) - mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); - - List subInfo; - long token = Binder.clearCallingIdentity(); - try { - subInfo = getSubInfo( - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + subId, null); - } finally { - Binder.restoreCallingIdentity(token); - } - - try { - if (!isActiveSubId(subId) && subInfo != null && subInfo.size() == 1 - && subManager.canManageSubscription(subInfo.get(0), callingPackage)) { - return; - } - throw new SecurityException(message); - } catch (IllegalArgumentException e) { - // canManageSubscription will throw IllegalArgumentException if sub is not embedded - // or package name is unknown. In this case, we also see it as permission check failure - // and throw a SecurityException. - throw new SecurityException(message); - } - } - - @Override - public void setPreferredDataSubscriptionId(int subId, boolean needValidation, - ISetOpportunisticDataCallback callback) { - enforceModifyPhoneState("setPreferredDataSubscriptionId"); - final long token = Binder.clearCallingIdentity(); - - try { - PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); - if (phoneSwitcher == null) { - logd("Set preferred data sub: phoneSwitcher is null."); - AnomalyReporter.reportAnomaly( - UUID.fromString("a73fe57f-4178-4bc3-a7ae-9d7354939274"), - "Set preferred data sub: phoneSwitcher is null."); - if (callback != null) { - try { - callback.onComplete(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION); - } catch (RemoteException exception) { - logd("RemoteException " + exception); - } - } - return; - } - - phoneSwitcher.trySetOpportunisticDataSubscription(subId, needValidation, callback); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public int getPreferredDataSubscriptionId() { - enforceReadPrivilegedPhoneState("getPreferredDataSubscriptionId"); - final long token = Binder.clearCallingIdentity(); - - try { - PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); - if (phoneSwitcher == null) { - AnomalyReporter.reportAnomaly( - UUID.fromString("e72747ab-d0aa-4b0e-9dd5-cb99365c6d58"), - "Get preferred data sub: phoneSwitcher is null."); - return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; - } - - return phoneSwitcher.getAutoSelectedDataSubId(); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public List getOpportunisticSubscriptions(String callingPackage, - String callingFeatureId) { - return getSubscriptionInfoListFromCacheHelper(callingPackage, callingFeatureId, - makeCacheListCopyWithLock(mCacheOpportunisticSubInfoList)); - } - - /** - * Inform SubscriptionManager that subscriptions in the list are bundled - * as a group. Typically it's a primary subscription and an opportunistic - * subscription. It should only affect multi-SIM scenarios where primary - * and opportunistic subscriptions can be activated together. - * Being in the same group means they might be activated or deactivated - * together, some of them may be invisible to the users, etc. - * - * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} - * permission or had carrier privilege permission on the subscriptions: - * {@link TelephonyManager#hasCarrierPrivileges(int)} or - * {@link SubscriptionManager#canManageSubscription(SubscriptionInfo)} - * - * @throws SecurityException if the caller doesn't meet the requirements - * outlined above. - * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist. - * - * @param subIdList list of subId that will be in the same group - * @return groupUUID a UUID assigned to the subscription group. It returns - * null if fails. - * - */ - @Override - public ParcelUuid createSubscriptionGroup(int[] subIdList, String callingPackage) { - if (subIdList == null || subIdList.length == 0) { - throw new IllegalArgumentException("Invalid subIdList " + Arrays.toString(subIdList)); - } - - // Makes sure calling package matches caller UID. - mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); - // If it doesn't have modify phone state permission, or carrier privilege permission, - // a SecurityException will be thrown. - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - != PERMISSION_GRANTED && !checkCarrierPrivilegeOnSubList( - subIdList, callingPackage)) { - throw new SecurityException("CreateSubscriptionGroup needs MODIFY_PHONE_STATE or" - + " carrier privilege permission on all specified subscriptions"); - } - - long identity = Binder.clearCallingIdentity(); - - try { - // Generate a UUID. - ParcelUuid groupUUID = new ParcelUuid(UUID.randomUUID()); - - ContentValues value = new ContentValues(); - value.put(SubscriptionManager.GROUP_UUID, groupUUID.toString()); - value.put(SubscriptionManager.GROUP_OWNER, callingPackage); - int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, - value, getSelectionForSubIdList(subIdList), null); - - if (DBG) logdl("createSubscriptionGroup update DB result: " + result); - - refreshCachedActiveSubscriptionInfoList(); - - notifySubscriptionInfoChanged(); - - MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUUID); - - return groupUUID; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - private String getOwnerPackageOfSubGroup(ParcelUuid groupUuid) { - if (groupUuid == null) return null; - - List infoList = getSubInfo(SubscriptionManager.GROUP_UUID - + "=\'" + groupUuid.toString() + "\'", null); - - return ArrayUtils.isEmpty(infoList) ? null : infoList.get(0).getGroupOwner(); - } - - /** - * @param groupUuid a UUID assigned to the subscription group. - * @param callingPackage the package making the IPC. - * @return if callingPackage has carrier privilege on sublist. - * - */ - public boolean canPackageManageGroup(ParcelUuid groupUuid, String callingPackage) { - if (groupUuid == null) { - throw new IllegalArgumentException("Invalid groupUuid"); - } - - if (TextUtils.isEmpty(callingPackage)) { - throw new IllegalArgumentException("Empty callingPackage"); - } - - List infoList; - - // Getting all subscriptions in the group. - long identity = Binder.clearCallingIdentity(); - try { - infoList = getSubInfo(SubscriptionManager.GROUP_UUID - + "=\'" + groupUuid.toString() + "\'", null); - } finally { - Binder.restoreCallingIdentity(identity); - } - - // If the group does not exist, then by default the UUID is up for grabs so no need to - // restrict management of a group (that someone may be attempting to create). - if (ArrayUtils.isEmpty(infoList)) { - return true; - } - - // If the calling package is the group owner, skip carrier permission check and return - // true as it was done before. - if (callingPackage.equals(infoList.get(0).getGroupOwner())) return true; - - // Check carrier privilege for all subscriptions in the group. - int[] subIdArray = infoList.stream().mapToInt(info -> info.getSubscriptionId()) - .toArray(); - return (checkCarrierPrivilegeOnSubList(subIdArray, callingPackage)); - } - - private int updateGroupOwner(ParcelUuid groupUuid, String groupOwner) { - // If the existing group owner is different from current caller, make caller the new - // owner of all subscriptions in group. - // This is for use-case of: - // 1) Both package1 and package2 has permission (MODIFY_PHONE_STATE or carrier - // privilege permission) of all related subscriptions. - // 2) Package 1 created a group. - // 3) Package 2 wants to add a subscription into it. - // Step 3 should be granted as all operations are permission based. Which means as - // long as the package passes the permission check, it can modify the subscription - // and the group. And package 2 becomes the new group owner as it's the last to pass - // permission checks on all members. - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.GROUP_OWNER, groupOwner); - return mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, - value, SubscriptionManager.GROUP_UUID + "=\"" + groupUuid + "\"", null); - } - - @Override - public void addSubscriptionsIntoGroup(int[] subIdList, ParcelUuid groupUuid, - String callingPackage) { - if (subIdList == null || subIdList.length == 0) { - throw new IllegalArgumentException("Invalid subId list"); - } - - if (groupUuid == null || groupUuid.equals(INVALID_GROUP_UUID)) { - throw new IllegalArgumentException("Invalid groupUuid"); - } - - // Makes sure calling package matches caller UID. - mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); - // If it doesn't have modify phone state permission, or carrier privilege permission, - // a SecurityException will be thrown. - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - != PERMISSION_GRANTED && !(checkCarrierPrivilegeOnSubList(subIdList, callingPackage) - && canPackageManageGroup(groupUuid, callingPackage))) { - throw new SecurityException("Requires MODIFY_PHONE_STATE or carrier privilege" - + " permissions on subscriptions and the group."); - } - - long identity = Binder.clearCallingIdentity(); - - try { - if (DBG) { - logdl("addSubscriptionsIntoGroup sub list " - + Arrays.toString(subIdList) + " into group " + groupUuid); - } - - ContentValues value = new ContentValues(); - value.put(SubscriptionManager.GROUP_UUID, groupUuid.toString()); - int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, - value, getSelectionForSubIdList(subIdList), null); - - if (DBG) logdl("addSubscriptionsIntoGroup update DB result: " + result); - - if (result > 0) { - updateGroupOwner(groupUuid, callingPackage); - refreshCachedActiveSubscriptionInfoList(); - notifySubscriptionInfoChanged(); - MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUuid); - } - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Remove a list of subscriptions from their subscription group. - * See {@link SubscriptionManager#createSubscriptionGroup(List)} for more details. - * - * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} - * permission or had carrier privilege permission on the subscriptions: - * {@link TelephonyManager#hasCarrierPrivileges()} or - * {@link SubscriptionManager#canManageSubscription(SubscriptionInfo)} - * - * @throws SecurityException if the caller doesn't meet the requirements - * outlined above. - * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong - * the specified group. - * - * @param subIdList list of subId that need removing from their groups. - * - */ - public void removeSubscriptionsFromGroup(int[] subIdList, ParcelUuid groupUuid, - String callingPackage) { - if (subIdList == null || subIdList.length == 0) { - return; - } - - // Makes sure calling package matches caller UID. - mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); - // If it doesn't have modify phone state permission, or carrier privilege permission, - // a SecurityException will be thrown. If it's due to invalid parameter or internal state, - // it will return null. - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - != PERMISSION_GRANTED && !(checkCarrierPrivilegeOnSubList(subIdList, callingPackage) - && canPackageManageGroup(groupUuid, callingPackage))) { - throw new SecurityException("removeSubscriptionsFromGroup needs MODIFY_PHONE_STATE or" - + " carrier privilege permission on all specified subscriptions"); - } - - long identity = Binder.clearCallingIdentity(); - - try { - List subInfoList = getSubInfo(getSelectionForSubIdList(subIdList), - null); - for (SubscriptionInfo info : subInfoList) { - if (!groupUuid.equals(info.getGroupUuid())) { - throw new IllegalArgumentException("Subscription " + info.getSubscriptionId() - + " doesn't belong to group " + groupUuid); - } - } - ContentValues value = new ContentValues(); - value.put(SubscriptionManager.GROUP_UUID, (String) null); - value.put(SubscriptionManager.GROUP_OWNER, (String) null); - int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, - value, getSelectionForSubIdList(subIdList), null); - - if (DBG) logdl("removeSubscriptionsFromGroup update DB result: " + result); - - if (result > 0) { - updateGroupOwner(groupUuid, callingPackage); - refreshCachedActiveSubscriptionInfoList(); - notifySubscriptionInfoChanged(); - } - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Helper function to check if the caller has carrier privilege permissions on a list of subId. - * The check can either be processed against access rules on currently active SIM cards, or - * the access rules we keep in our database for currently inactive eSIMs. - * - * @throws IllegalArgumentException if the some subId is invalid or doesn't exist. - * - * @return true if checking passes on all subId, false otherwise. - */ - private boolean checkCarrierPrivilegeOnSubList(int[] subIdList, String callingPackage) { - // Check carrier privilege permission on active subscriptions first. - // If it fails, they could be inactive. So keep them in a HashSet and later check - // access rules in our database. - Set checkSubList = new HashSet<>(); - for (int subId : subIdList) { - if (isActiveSubId(subId)) { - if (!mTelephonyManager.hasCarrierPrivileges(subId)) { - return false; - } - } else { - checkSubList.add(subId); - } - } - - if (checkSubList.isEmpty()) { - return true; - } - - long identity = Binder.clearCallingIdentity(); - - try { - // Check access rules for each sub info. - SubscriptionManager subscriptionManager = (SubscriptionManager) - mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); - List subInfoList = getSubInfo( - getSelectionForSubIdList(subIdList), null); - - // Didn't find all the subscriptions specified in subIdList. - if (subInfoList == null || subInfoList.size() != subIdList.length) { - throw new IllegalArgumentException("Invalid subInfoList."); - } - - for (SubscriptionInfo subInfo : subInfoList) { - if (checkSubList.contains(subInfo.getSubscriptionId())) { - if (subInfo.isEmbedded() && subscriptionManager.canManageSubscription( - subInfo, callingPackage)) { - checkSubList.remove(subInfo.getSubscriptionId()); - } else { - return false; - } - } - } - - return checkSubList.isEmpty(); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Helper function to create selection argument of a list of subId. - * The result should be: "in (subId1, subId2, ...)". - */ - public static String getSelectionForSubIdList(int[] subId) { - StringBuilder selection = new StringBuilder(); - selection.append(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID); - selection.append(" IN ("); - for (int i = 0; i < subId.length - 1; i++) { - selection.append(subId[i] + ", "); - } - selection.append(subId[subId.length - 1]); - selection.append(")"); - - return selection.toString(); - } - - /** - * Helper function to create selection argument of a list of subId. - * The result should be: "in (iccId1, iccId2, ...)". - */ - private String getSelectionForIccIdList(String[] iccIds) { - StringBuilder selection = new StringBuilder(); - selection.append(SubscriptionManager.ICC_ID); - selection.append(" IN ("); - for (int i = 0; i < iccIds.length - 1; i++) { - selection.append("'" + iccIds[i] + "', "); - } - selection.append("'" + iccIds[iccIds.length - 1] + "'"); - selection.append(")"); - - return selection.toString(); - } - - /** - * Get subscriptionInfo list of subscriptions that are in the same group of given subId. - * See {@link #createSubscriptionGroup(int[], String)} for more details. - * - * Caller must have {@link android.Manifest.permission#READ_PHONE_STATE} - * or carrier privilege permission on the subscription. - * {@link TelephonyManager#hasCarrierPrivileges(int)} - * - *

Starting with API level 33, the caller needs READ_PHONE_STATE and access to device - * identifiers to get the list of subscriptions associated with a group UUID. - * This method can be invoked if one of the following requirements is met: - *

    - *
  • If the app has carrier privilege permission. - * {@link TelephonyManager#hasCarrierPrivileges()} - *
  • If the app has {@link android.Manifest.permission#READ_PHONE_STATE} and - * access to device identifiers. - *
- * - * @throws SecurityException if the caller doesn't meet the requirements - * outlined above. - * - * @param groupUuid of which list of subInfo will be returned. - * @return list of subscriptionInfo that belong to the same group, including the given - * subscription itself. It will return an empty list if no subscription belongs to the group. - * - */ - @Override - public List getSubscriptionsInGroup(ParcelUuid groupUuid, - String callingPackage, String callingFeatureId) { - long identity = Binder.clearCallingIdentity(); - List subInfoList; - - try { - // need to bypass removing identifier check because that will remove the subList without - // group id. - subInfoList = getAllSubInfoList(mContext.getOpPackageName(), - mContext.getAttributionTag(), true); - if (groupUuid == null || subInfoList == null || subInfoList.isEmpty()) { - return new ArrayList<>(); - } - } finally { - Binder.restoreCallingIdentity(identity); - } - - // If the calling app neither has carrier privileges nor READ_PHONE_STATE and access to - // device identifiers, it will throw a securityException. - if (CompatChanges.isChangeEnabled( - REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID, Binder.getCallingUid())) { - try { - if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext, - callingPackage, callingFeatureId, "getSubscriptionsInGroup")) { - EventLog.writeEvent(0x534e4554, "213902861", Binder.getCallingUid()); - throw new SecurityException("Need to have carrier privileges or access to " - + "device identifiers to call getSubscriptionsInGroup"); - } - } catch (SecurityException e) { - EventLog.writeEvent(0x534e4554, "213902861", Binder.getCallingUid()); - throw e; - } - } - - return subInfoList.stream().filter(info -> { - if (!groupUuid.equals(info.getGroupUuid())) return false; - int subId = info.getSubscriptionId(); - return TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, - callingPackage, callingFeatureId, "getSubscriptionsInGroup") - || info.canManageSubscription(mContext, callingPackage); - }).map(subscriptionInfo -> conditionallyRemoveIdentifiers(subscriptionInfo, - callingPackage, callingFeatureId, "getSubscriptionsInGroup")) - .collect(Collectors.toList()); - - } - - /** - * Check if the passed in phoneId has a sub that belongs to the same group as the sub - * corresponding to the passed in iccid. - * @param phoneId phone id to check - * @param iccid ICCID to check - * @return true if sub/group is the same, false otherwise - */ - public boolean checkPhoneIdAndIccIdMatch(int phoneId, String iccid) { - int subId = getSubId(phoneId); - if (!SubscriptionManager.isUsableSubIdValue(subId)) return false; - ParcelUuid groupUuid = getGroupUuid(subId); - List subInfoList; - if (groupUuid != null) { - subInfoList = getSubInfo(SubscriptionManager.GROUP_UUID - + "=\'" + groupUuid.toString() + "\'", null); - } else { - subInfoList = getSubInfo(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID - + "=" + subId, null); - } - return subInfoList != null && subInfoList.stream().anyMatch( - subInfo -> IccUtils.stripTrailingFs(subInfo.getIccId()).equals( - IccUtils.stripTrailingFs(iccid))); - } - - public ParcelUuid getGroupUuid(int subId) { - ParcelUuid groupUuid; - List subInfo = getSubInfo(SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID - + "=" + subId, null); - if (subInfo == null || subInfo.size() == 0) { - groupUuid = null; - } else { - groupUuid = subInfo.get(0).getGroupUuid(); - } - - return groupUuid; - } - - - /** - * Enable/Disable a subscription - * @param enable true if enabling, false if disabling - * @param subId the unique SubInfoRecord index in database - * - * @return true if success, false if fails or the further action is - * needed hence it's redirected to Euicc. - */ - public boolean setSubscriptionEnabled(boolean enable, int subId) { - enforceModifyPhoneState("setSubscriptionEnabled"); - - final long identity = Binder.clearCallingIdentity(); - try { - logd("setSubscriptionEnabled" + (enable ? " enable " : " disable ") - + " subId " + subId); - - // Error checking. - if (!SubscriptionManager.isUsableSubscriptionId(subId)) { - throw new IllegalArgumentException( - "setSubscriptionEnabled not usable subId " + subId); - } - - // Nothing to do if it's already active or inactive. - if (enable == isActiveSubscriptionId(subId)) return true; - - SubscriptionInfo info = SubscriptionController.getInstance() - .getAllSubInfoList(mContext.getOpPackageName(), mContext.getAttributionTag()) - .stream() - .filter(subInfo -> subInfo.getSubscriptionId() == subId) - .findFirst() - .get(); - - if (info == null) { - logd("setSubscriptionEnabled subId " + subId + " doesn't exist."); - return false; - } - - // TODO: make sure after slot mapping, we enable the uicc applications for the - // subscription we are enabling. - if (info.isEmbedded()) { - return enableEmbeddedSubscription(info, enable); - } else { - return enablePhysicalSubscription(info, enable); - } - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - private boolean enableEmbeddedSubscription(SubscriptionInfo info, boolean enable) { - // We need to send intents to Euicc for operations: - - // 1) In single SIM mode, turning on a eSIM subscription while pSIM is the active slot. - // Euicc will ask user to switch to DSDS if supported or to confirm SIM slot - // switching. - // 2) In DSDS mode, turning on / off an eSIM profile. Euicc can ask user whether - // to turn on DSDS, or whether to switch from current active eSIM profile to it, or - // to simply show a progress dialog. - // 3) In future, similar operations on triple SIM devices. - enableSubscriptionOverEuiccManager(info.getSubscriptionId(), enable, - SubscriptionManager.INVALID_SIM_SLOT_INDEX); - // returning false to indicate state is not changed. If changed, a subscriptionInfo - // change will be filed separately. - return false; - - // TODO: uncomment or clean up if we decide whether to support standalone CBRS for Q. - // subId = enable ? subId : SubscriptionManager.INVALID_SUBSCRIPTION_ID; - // updateEnabledSubscriptionGlobalSetting(subId, physicalSlotIndex); - } - - private boolean enablePhysicalSubscription(SubscriptionInfo info, boolean enable) { - if (info == null || !SubscriptionManager.isValidSubscriptionId(info.getSubscriptionId())) { - return false; - } - - int subId = info.getSubscriptionId(); - - UiccSlotInfo slotInfo = null; - int physicalSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - UiccSlotInfo[] slotsInfo = mTelephonyManager.getUiccSlotsInfo(); - if (slotsInfo == null) return false; - for (int i = 0; i < slotsInfo.length; i++) { - UiccSlotInfo curSlotInfo = slotsInfo[i]; - if (curSlotInfo.getCardStateInfo() == CARD_STATE_INFO_PRESENT) { - if (TextUtils.equals(IccUtils.stripTrailingFs(curSlotInfo.getCardId()), - IccUtils.stripTrailingFs(info.getCardString()))) { - slotInfo = curSlotInfo; - physicalSlotIndex = i; - break; - } - } - } - - // Can't find the existing SIM. - if (slotInfo == null) { - loge("Can't find the existing SIM."); - return false; - } - - // this for physical slot which has only one port - if (enable && !slotInfo.getPorts().stream().findFirst().get().isActive()) { - // We need to send intents to Euicc if we are turning on an inactive slot. - // Euicc will decide whether to ask user to switch to DSDS, or change SIM - // slot mapping. - EuiccManager euiccManager = - (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE); - if (euiccManager != null && euiccManager.isEnabled()) { - enableSubscriptionOverEuiccManager(subId, enable, physicalSlotIndex); - } else { - // Enable / disable uicc applications. - if (!info.areUiccApplicationsEnabled()) setUiccApplicationsEnabled(enable, subId); - // If euiccManager is not enabled, we try to switch to DSDS if possible, - // or switch slot if not. - if (mTelephonyManager.isMultiSimSupported() == MULTISIM_ALLOWED) { - PhoneConfigurationManager.getInstance().switchMultiSimConfig( - mTelephonyManager.getSupportedModemCount()); - } else { - List slotMapping = new ArrayList<>(); - // As this is single sim mode, set port index to 0 and logical slot index is 0 - slotMapping.add(new UiccSlotMapping(TelephonyManager.DEFAULT_PORT_INDEX, - physicalSlotIndex, 0)); - UiccController.getInstance().switchSlots(slotMapping, null); - } - } - return true; - } else { - // Enable / disable uicc applications. - setUiccApplicationsEnabled(enable, subId); - return true; - } - } - - private void enableSubscriptionOverEuiccManager(int subId, boolean enable, - int physicalSlotIndex) { - logdl("enableSubscriptionOverEuiccManager" + (enable ? " enable " : " disable ") - + "subId " + subId + " on slotIndex " + physicalSlotIndex); - Intent intent = new Intent(EuiccManager.ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(EuiccManager.EXTRA_SUBSCRIPTION_ID, subId); - intent.putExtra(EuiccManager.EXTRA_ENABLE_SUBSCRIPTION, enable); - if (physicalSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - intent.putExtra(EuiccManager.EXTRA_PHYSICAL_SLOT_ID, physicalSlotIndex); - } - mContext.startActivity(intent); - } - - private void updateEnabledSubscriptionGlobalSetting(int subId, int physicalSlotIndex) { - // Write the value which subscription is enabled into global setting. - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT + physicalSlotIndex, subId); - } - - private void updateModemStackEnabledGlobalSetting(boolean enabled, int physicalSlotIndex) { - // Write the whether a modem stack is disabled into global setting. - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT - + physicalSlotIndex, enabled ? 1 : 0); - } - - private int getPhysicalSlotIndexFromLogicalSlotIndex(int logicalSlotIndex) { - int physicalSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX; - UiccSlotInfo[] slotInfos = mTelephonyManager.getUiccSlotsInfo(); - for (int i = 0; i < slotInfos.length; i++) { - for (UiccPortInfo portInfo : slotInfos[i].getPorts()) { - if (portInfo.getLogicalSlotIndex() == logicalSlotIndex) { - physicalSlotIndex = i; - break; - } - } - } - - return physicalSlotIndex; - } - - @Override - public boolean isSubscriptionEnabled(int subId) { - // TODO: b/123314365 support multi-eSIM and removable eSIM. - enforceReadPrivilegedPhoneState("isSubscriptionEnabled"); - - long identity = Binder.clearCallingIdentity(); - try { - // Error checking. - if (!SubscriptionManager.isUsableSubscriptionId(subId)) { - throw new IllegalArgumentException( - "isSubscriptionEnabled not usable subId " + subId); - } - - List infoList = getSubInfo( - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + subId, null); - if (infoList == null || infoList.isEmpty()) { - // Subscription doesn't exist. - return false; - } - - boolean isEmbedded = infoList.get(0).isEmbedded(); - - if (isEmbedded) { - return isActiveSubId(subId); - } else { - // For pSIM, we also need to check if modem is disabled or not. - return isActiveSubId(subId) && PhoneConfigurationManager.getInstance() - .getPhoneStatus(PhoneFactory.getPhone(getPhoneId(subId))); - } - - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public int getEnabledSubscriptionId(int logicalSlotIndex) { - // TODO: b/123314365 support multi-eSIM and removable eSIM. - enforceReadPrivilegedPhoneState("getEnabledSubscriptionId"); - - long identity = Binder.clearCallingIdentity(); - try { - if (!SubscriptionManager.isValidPhoneId(logicalSlotIndex)) { - throw new IllegalArgumentException( - "getEnabledSubscriptionId with invalid logicalSlotIndex " - + logicalSlotIndex); - } - - // Getting and validating the physicalSlotIndex. - int physicalSlotIndex = getPhysicalSlotIndexFromLogicalSlotIndex(logicalSlotIndex); - if (physicalSlotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; - } - - // if modem stack is disabled, return INVALID_SUBSCRIPTION_ID without reading - // Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT. - int modemStackEnabled = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MODEM_STACK_ENABLED_FOR_SLOT + physicalSlotIndex, 1); - if (modemStackEnabled != 1) { - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; - } - - int subId; - try { - subId = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT + physicalSlotIndex); - } catch (Settings.SettingNotFoundException e) { - // Value never set. Return whether it's currently active. - subId = getSubId(logicalSlotIndex); - } - - return subId; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Helper function of getOpportunisticSubscriptions and getActiveSubscriptionInfoList. - * They are doing similar things except operating on different cache. - * - * NOTE: the cacheSubList passed in is a *copy* of mCacheActiveSubInfoList or - * mCacheOpportunisticSubInfoList, so mSubInfoListLock is not required to access it. Also, this - * method may modify cacheSubList depending on the permissions the caller has. - */ - private List getSubscriptionInfoListFromCacheHelper( - String callingPackage, String callingFeatureId, List cacheSubList) { - boolean canReadPhoneState = false; - boolean canReadIdentifiers = false; - boolean canReadPhoneNumber = false; - try { - canReadPhoneState = TelephonyPermissions.checkReadPhoneState(mContext, - SubscriptionManager.INVALID_SUBSCRIPTION_ID, Binder.getCallingPid(), - Binder.getCallingUid(), callingPackage, callingFeatureId, - "getSubscriptionInfoList"); - // If the calling package has the READ_PHONE_STATE permission then check if the caller - // also has access to subscriber identifiers and the phone number to ensure that the ICC - // ID and any other unique identifiers are removed if the caller should not have access. - if (canReadPhoneState) { - canReadIdentifiers = hasSubscriberIdentifierAccess( - SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, - callingFeatureId, "getSubscriptionInfoList", false); - canReadPhoneNumber = hasPhoneNumberAccess( - SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, - callingFeatureId, "getSubscriptionInfoList"); - } - } catch (SecurityException e) { - // If a SecurityException is thrown during the READ_PHONE_STATE check then the only way - // to access a subscription is to have carrier privileges for its subId; an app with - // carrier privileges for a subscription is also granted access to all identifiers so - // the identifier and phone number access checks are not required. - } - - if (canReadIdentifiers && canReadPhoneNumber) { - return cacheSubList; - } - // Filter the list to only include subscriptions which the caller can manage. - for (int subIndex = cacheSubList.size() - 1; subIndex >= 0; subIndex--) { - SubscriptionInfo subscriptionInfo = cacheSubList.get(subIndex); - - int subId = subscriptionInfo.getSubscriptionId(); - boolean hasCarrierPrivileges = TelephonyPermissions.checkCarrierPrivilegeForSubId( - mContext, subId); - // If the caller has carrier privileges then they are granted access to all - // identifiers for their subscription. - if (hasCarrierPrivileges) continue; - - cacheSubList.remove(subIndex); - if (canReadPhoneState) { - // The caller does not have carrier privileges for this subId, filter the - // identifiers in the subscription based on the results of the initial - // permission checks. - cacheSubList.add(subIndex, conditionallyRemoveIdentifiers( - subscriptionInfo, canReadIdentifiers, canReadPhoneNumber)); - } - } - return cacheSubList; - } - - /** - * Conditionally removes identifiers from the provided {@code subInfo} if the {@code - * callingPackage} does not meet the access requirements for identifiers and returns the - * potentially modified object.. - * - *

If the caller does not meet the access requirements for identifiers a clone of the - * provided SubscriptionInfo is created and modified to avoid altering SubscriptionInfo objects - * in a cache. - */ - private SubscriptionInfo conditionallyRemoveIdentifiers(SubscriptionInfo subInfo, - String callingPackage, String callingFeatureId, String message) { - SubscriptionInfo result = subInfo; - int subId = subInfo.getSubscriptionId(); - boolean hasIdentifierAccess = hasSubscriberIdentifierAccess(subId, callingPackage, - callingFeatureId, message, true); - boolean hasPhoneNumberAccess = hasPhoneNumberAccess(subId, callingPackage, callingFeatureId, - message); - return conditionallyRemoveIdentifiers(subInfo, hasIdentifierAccess, hasPhoneNumberAccess); - } - - /** - * Conditionally removes identifiers from the provided {@code subInfo} based on if the calling - * package {@code hasIdentifierAccess} and {@code hasPhoneNumberAccess} and returns the - * potentially modified object. - * - *

If the caller specifies the package does not have identifier or phone number access - * a clone of the provided SubscriptionInfo is created and modified to avoid altering - * SubscriptionInfo objects in a cache. - */ - private SubscriptionInfo conditionallyRemoveIdentifiers(SubscriptionInfo subInfo, - boolean hasIdentifierAccess, boolean hasPhoneNumberAccess) { - if (hasIdentifierAccess && hasPhoneNumberAccess) { - return subInfo; - } - SubscriptionInfo.Builder result = new SubscriptionInfo.Builder(subInfo); - if (!hasIdentifierAccess) { - result.setIccId(null); - result.setCardString(null); - result.setGroupUuid(null); - } - if (!hasPhoneNumberAccess) { - result.setNumber(null); - } - return result.build(); - } - - private synchronized boolean addToSubIdList(int slotIndex, int subId, int subscriptionType) { - ArrayList subIdsList = mSlotIndexToSubIds.getCopy(slotIndex); - if (subIdsList == null) { - subIdsList = new ArrayList<>(); - mSlotIndexToSubIds.put(slotIndex, subIdsList); - } - - // add the given subId unless it already exists - if (subIdsList.contains(subId)) { - logdl("slotIndex, subId combo already exists in the map. Not adding it again."); - return false; - } - if (isSubscriptionForRemoteSim(subscriptionType)) { - // For Remote SIM subscriptions, a slot can have multiple subscriptions. - mSlotIndexToSubIds.addToSubIdList(slotIndex, subId); - } else { - // for all other types of subscriptions, a slot can have only one subscription at a time - mSlotIndexToSubIds.clearSubIdList(slotIndex); - mSlotIndexToSubIds.addToSubIdList(slotIndex, subId); - } - - - // Remove the slot from sSlotIndexToSubIds if it has the same sub id with the added slot - for (Entry> entry : mSlotIndexToSubIds.entrySet()) { - if (entry.getKey() != slotIndex && entry.getValue() != null - && entry.getValue().contains(subId)) { - logdl("addToSubIdList - remove " + entry.getKey()); - mSlotIndexToSubIds.remove(entry.getKey()); - } - } - - if (DBG) logdl("slotIndex, subId combo is added to the map."); - return true; - } - - private boolean isSubscriptionForRemoteSim(int subscriptionType) { - return subscriptionType == SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM; - } - - /** - * This is only for testing - * @hide - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - public Map> getSlotIndexToSubIdsMap() { - return mSlotIndexToSubIds.getMap(); - } - - private void notifyOpportunisticSubscriptionInfoChanged() { - TelephonyRegistryManager trm = - (TelephonyRegistryManager) - mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); - if (DBG) logd("notifyOpptSubscriptionInfoChanged:"); - trm.notifyOpportunisticSubscriptionInfoChanged(); - } - - private void refreshCachedOpportunisticSubscriptionInfoList() { - synchronized (mSubInfoListLock) { - List subList = getSubInfo( - SubscriptionManager.IS_OPPORTUNISTIC + "=1 AND (" - + SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR " - + SubscriptionManager.IS_EMBEDDED + "=1)", null); - List oldOpptCachedList = mCacheOpportunisticSubInfoList; - - if (subList != null) { - subList.sort(SUBSCRIPTION_INFO_COMPARATOR); - } else { - subList = new ArrayList<>(); - } - - mCacheOpportunisticSubInfoList = subList; - - for (int i = 0; i < mCacheOpportunisticSubInfoList.size(); i++) { - SubscriptionInfo info = mCacheOpportunisticSubInfoList.get(i); - if (shouldDisableSubGroup(info.getGroupUuid())) { - SubscriptionInfo.Builder builder = new SubscriptionInfo.Builder(info); - builder.setGroupDisabled(true); - mCacheOpportunisticSubInfoList.set(i, builder.build()); - } - } - - if (DBG_CACHE) { - if (!mCacheOpportunisticSubInfoList.isEmpty()) { - for (SubscriptionInfo si : mCacheOpportunisticSubInfoList) { - logd("[refreshCachedOpportunisticSubscriptionInfoList] Setting Cached " - + "info=" + si); - } - } else { - logdl("[refreshCachedOpportunisticSubscriptionInfoList]- no info return"); - } - } - - if (!oldOpptCachedList.equals(mCacheOpportunisticSubInfoList)) { - mOpptSubInfoListChangedDirtyBit.set(true); - } - } - } - - private boolean shouldDisableSubGroup(ParcelUuid groupUuid) { - if (groupUuid == null) return false; - - synchronized (mSubInfoListLock) { - for (SubscriptionInfo activeInfo : mCacheActiveSubInfoList) { - if (!activeInfo.isOpportunistic() && groupUuid.equals(activeInfo.getGroupUuid())) { - return false; - } - } - } - - return true; - } - - /** - * Set enabled mobile data policies. - * - * @param subId Subscription index - * @param policies Mobile data policies in string format. - * See {@link TelephonyManager.MobileDataPolicy} for details. - * @return {@code true} if settings changed, otherwise {@code false}. - */ - public boolean setEnabledMobileDataPolicies(int subId, @NonNull String policies) { - if (DBG) logd("[setEnabledMobileDataPolicies]+ policies:" + policies + " subId:" + subId); - - validateSubId(subId); - ContentValues value = new ContentValues(1); - value.put(SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES, policies); - - boolean result = updateDatabase(value, subId, true) > 0; - - if (result) { - // Refresh the Cache of Active Subscription Info List - refreshCachedActiveSubscriptionInfoList(); - notifySubscriptionInfoChanged(); - } - - return result; - } - - /** - * Get enabled mobile data policies. - * - * @param subId Subscription index - * @return Enabled mobile data policies joined by "," (ie. "1,2") or an empty string if no - * policies are enabled. - */ - @NonNull - public String getEnabledMobileDataPolicies(int subId) { - return TelephonyUtils.emptyIfNull(getSubscriptionProperty(subId, - SubscriptionManager.ENABLED_MOBILE_DATA_POLICIES)); - } - - /** - * Get active data subscription id. - * - * @return Active data subscription id - * - * @hide - */ - @Override - public int getActiveDataSubscriptionId() { - final long token = Binder.clearCallingIdentity(); - - try { - PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance(); - if (phoneSwitcher != null) { - int activeDataSubId = phoneSwitcher.getActiveDataSubId(); - if (SubscriptionManager.isUsableSubscriptionId(activeDataSubId)) { - return activeDataSubId; - } - } - // If phone switcher isn't ready, or active data sub id is not available, use default - // sub id from settings. - return getDefaultDataSubId(); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Whether it's supported to disable / re-enable a subscription on a physical (non-euicc) SIM. - */ - @Override - public boolean canDisablePhysicalSubscription() { - enforceReadPrivilegedPhoneState("canToggleUiccApplicationsEnablement"); - - final long identity = Binder.clearCallingIdentity(); - try { - Phone phone = PhoneFactory.getDefaultPhone(); - return phone != null && phone.canDisablePhysicalSubscription(); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /* - * Returns the phone number for the given {@code subId} and {@code source}, - * or an empty string if not available. - */ - @Override - public String getPhoneNumber(int subId, int source, - String callingPackage, String callingFeatureId) { - TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( - mContext, subId, Binder.getCallingUid(), "getPhoneNumber", - READ_PHONE_NUMBERS, READ_PRIVILEGED_PHONE_STATE); - - final long identity = Binder.clearCallingIdentity(); - try { - String number = getPhoneNumber(subId, source); - return number == null ? "" : number; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /* - * Returns the phone number for the given {@code subId} or an empty string if not available. - * - *

Built up on getPhoneNumber(int subId, int source) this API picks the 1st available - * source based on a priority order. - */ - @Override - public String getPhoneNumberFromFirstAvailableSource(int subId, - String callingPackage, String callingFeatureId) { - TelephonyPermissions.enforceAnyPermissionGrantedOrCarrierPrivileges( - mContext, subId, Binder.getCallingUid(), "getPhoneNumberFromFirstAvailableSource", - READ_PHONE_NUMBERS, READ_PRIVILEGED_PHONE_STATE); - - final long identity = Binder.clearCallingIdentity(); - try { - String numberFromCarrier = getPhoneNumber( - subId, SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER); - if (!TextUtils.isEmpty(numberFromCarrier)) { - return numberFromCarrier; - } - String numberFromUicc = getPhoneNumber( - subId, SubscriptionManager.PHONE_NUMBER_SOURCE_UICC); - if (!TextUtils.isEmpty(numberFromUicc)) { - return numberFromUicc; - } - String numberFromIms = getPhoneNumber( - subId, SubscriptionManager.PHONE_NUMBER_SOURCE_IMS); - if (!TextUtils.isEmpty(numberFromIms)) { - return numberFromIms; - } - return ""; - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - // Internal helper method for implementing getPhoneNumber() API. - @Nullable - private String getPhoneNumber(int subId, int source) { - if (source == SubscriptionManager.PHONE_NUMBER_SOURCE_UICC) { - Phone phone = PhoneFactory.getPhone(getPhoneId(subId)); - return phone != null ? phone.getLine1Number() : null; - } - if (source == SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER) { - return getSubscriptionProperty(subId, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER); - } - if (source == SubscriptionManager.PHONE_NUMBER_SOURCE_IMS) { - return getSubscriptionProperty(subId, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS); - } - throw new IllegalArgumentException("setPhoneNumber doesn't accept source " + source); - } - - /** - * Sets the phone number for the given {@code subId}. - * - *

The only accepted {@code source} is {@link - * SubscriptionManager#PHONE_NUMBER_SOURCE_CARRIER}. - */ - @Override - public void setPhoneNumber(int subId, int source, String number, - String callingPackage, String callingFeatureId) { - if (source != SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER) { - throw new IllegalArgumentException("setPhoneNumber doesn't accept source " + source); - } - if (!TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext, subId)) { - throw new SecurityException("setPhoneNumber for CARRIER needs carrier privilege"); - } - if (number == null) { - throw new NullPointerException("invalid number null"); - } - - final long identity = Binder.clearCallingIdentity(); - try { - setSubscriptionProperty(subId, SimInfo.COLUMN_PHONE_NUMBER_SOURCE_CARRIER, number); - } finally { - Binder.restoreCallingIdentity(identity); - } - } - - /** - * Set the Usage Setting for this subscription. - * - * @param usageSetting the cellular usage setting - * @param subId the unique SubscriptionInfo index in database - * @param callingPackage the package making the IPC - * @return the number of records updated - * - * @throws SecurityException if doesn't have required permission. - */ - @Override - public int setUsageSetting(@UsageSetting int usageSetting, int subId, String callingPackage) { - try { - TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege( - mContext, subId, callingPackage); - } catch (SecurityException e) { - enforceCarrierPrivilegeOnInactiveSub(subId, callingPackage, - "Caller requires permission on sub " + subId); - } - - if (usageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT - || usageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { - throw new IllegalArgumentException("setUsageSetting: Invalid usage setting: " - + usageSetting); - } - - final long token = Binder.clearCallingIdentity(); - int ret; - try { - ret = setSubscriptionProperty(subId, SubscriptionManager.USAGE_SETTING, - String.valueOf(usageSetting)); - - // ret is the number of records updated in the DB, which should always be 1. - // TODO(b/205027930): move this check prior to the database mutation request - if (ret != 1) throw new IllegalArgumentException( - "Invalid SubscriptionId for setUsageSetting"); - } finally { - Binder.restoreCallingIdentity(token); - // FIXME(b/205726099) return void - } - return ret; - } - - /** - * Querying last used TP - MessageRef for particular subId from SIMInfo table. - * @return messageRef - */ - public int getMessageRef(int subId) { - try (Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, - new String[]{SubscriptionManager.TP_MESSAGE_REF}, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=\"" + subId - + "\"", null, null)) { - try { - if (cursor != null && cursor.moveToFirst()) { - do { - return cursor.getInt(cursor.getColumnIndexOrThrow( - SubscriptionManager.TP_MESSAGE_REF)); - } while (cursor.moveToNext()); - } else { - if (DBG) logd("Valid row not present in db"); - } - } catch (Exception e) { - if (DBG) logd("Query failed " + e.getMessage()); - } finally { - if (cursor != null) { - cursor.close(); - } - } - } - return -1; - } - - /** - * Update the TP - Message Reference value for every SMS Sent - * @param messageRef - * @param subId - */ - public void updateMessageRef(int subId, int messageRef) { - TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege( - mContext, subId, mContext.getOpPackageName()); - - if (mContext == null) { - logel("[updateMessageRef] mContext is null"); - return; - } - try { - if (SubscriptionManager.CONTENT_URI != null) { - ContentValues values = new ContentValues(1); - values.put(SubscriptionManager.TP_MESSAGE_REF, messageRef); - mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, values, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=\"" + subId - + "\"", null); - } else { - if (DBG) logd("TP - Message reference value not updated to DB"); - } - } finally { - if (DBG) logd("TP - Message reference updated to DB Successfully :" + messageRef); - } - } - - /** - * Set UserHandle for this subscription - * - * @param userHandle the userHandle associated with the subscription - * Pass {@code null} user handle to clear the association - * @param subId the unique SubscriptionInfo index in database - * @return the number of records updated. - * - * @throws SecurityException if doesn't have required permission. - * @throws IllegalArgumentException if subId is invalid. - */ - @Override - public int setSubscriptionUserHandle(@Nullable UserHandle userHandle, int subId) { - enforceManageSubscriptionUserAssociation("setSubscriptionUserHandle"); - - if (userHandle == null) { - userHandle = UserHandle.of(UserHandle.USER_NULL); - } - - long token = Binder.clearCallingIdentity(); - try { - int ret = setSubscriptionProperty(subId, SubscriptionManager.USER_HANDLE, - String.valueOf(userHandle.getIdentifier())); - // ret is the number of records updated in the DB - if (ret != 0) { - notifySubscriptionInfoChanged(); - } else { - throw new IllegalArgumentException("[setSubscriptionUserHandle]: Invalid subId: " - + subId); - } - return ret; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Get UserHandle of this subscription. - * - * @param subId the unique SubscriptionInfo index in database - * @return userHandle associated with this subscription - * or {@code null} if subscription is not associated with any user. - * - * @throws SecurityException if doesn't have required permission. - * @throws IllegalArgumentException if subId is invalid. - */ - @Override - @Nullable - public UserHandle getSubscriptionUserHandle(int subId) { - enforceManageSubscriptionUserAssociation("getSubscriptionUserHandle"); - - if (!SubscriptionInfoUpdater.isWorkProfileTelephonyEnabled()) { - return null; - } - - long token = Binder.clearCallingIdentity(); - try { - String userHandleStr = getSubscriptionProperty(subId, SubscriptionManager.USER_HANDLE); - if (userHandleStr == null) { - throw new IllegalArgumentException("[getSubscriptionUserHandle]: Invalid subId: " - + subId); - } - UserHandle userHandle = UserHandle.of(Integer.parseInt(userHandleStr)); - if (userHandle.getIdentifier() == UserHandle.USER_NULL) { - return null; - } - return userHandle; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Check if subscription and user are associated with each other. - * - * @param subscriptionId the subId of the subscription - * @param userHandle user handle of the user - * @return {@code true} if subscription is associated with user - * {code true} if there are no subscriptions on device - * else {@code false} if subscription is not associated with user. - * - * @throws SecurityException if the caller doesn't have permissions required. - * @throws IllegalStateException if subscription service is not available. - * - */ - @Override - public boolean isSubscriptionAssociatedWithUser(int subscriptionId, - @NonNull UserHandle userHandle) { - enforceManageSubscriptionUserAssociation("isSubscriptionAssociatedWithUser"); - - if (!SubscriptionInfoUpdater.isWorkProfileTelephonyEnabled()) { - return true; - } - - long token = Binder.clearCallingIdentity(); - try { - // Return true if there are no subscriptions on the device. - List subInfoList = getAllSubInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - if (subInfoList == null || subInfoList.isEmpty()) { - return true; - } - - // Get list of subscriptions associated with this user. - List associatedSubscriptionsList = - getSubscriptionInfoListAssociatedWithUser(userHandle); - if (associatedSubscriptionsList.isEmpty()) { - return false; - } - - // Return true if required subscription is present in associated subscriptions list. - for (SubscriptionInfo subInfo: associatedSubscriptionsList) { - if (subInfo.getSubscriptionId() == subscriptionId){ - return true; - } - } - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * Get list of subscriptions associated with user. - * - * If user handle is associated with some subscriptions, return subscriptionsAssociatedWithUser - * else return all the subscriptions which are not associated with any user. - * - * @param userHandle user handle of the user - * @return list of subscriptionInfo associated with the user. - * - * @throws SecurityException if the caller doesn't have permissions required. - * @throws IllegalStateException if subscription service is not available. - * - */ - @Override - public @NonNull List getSubscriptionInfoListAssociatedWithUser( - @NonNull UserHandle userHandle) { - enforceManageSubscriptionUserAssociation("getActiveSubscriptionInfoListAssociatedWithUser"); - - long token = Binder.clearCallingIdentity(); - try { - List subInfoList = getAllSubInfoList( - mContext.getOpPackageName(), mContext.getAttributionTag()); - if (subInfoList == null || subInfoList.isEmpty()) { - return new ArrayList<>(); - } - - if (!SubscriptionInfoUpdater.isWorkProfileTelephonyEnabled()) { - return subInfoList; - } - - List subscriptionsAssociatedWithUser = new ArrayList<>(); - List subscriptionsWithNoAssociation = new ArrayList<>(); - for (SubscriptionInfo subInfo : subInfoList) { - int subId = subInfo.getSubscriptionId(); - UserHandle subIdUserHandle = getSubscriptionUserHandle(subId); - if (userHandle.equals(subIdUserHandle)) { - // Store subscriptions whose user handle matches with required user handle. - subscriptionsAssociatedWithUser.add(subInfo); - } else if (subIdUserHandle == null) { - // Store subscriptions whose user handle is set to null. - subscriptionsWithNoAssociation.add(subInfo); - } - } - - return subscriptionsAssociatedWithUser.isEmpty() ? - subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * @return {@code true} if using {@link SubscriptionManagerService} instead of - * {@link SubscriptionController}. - */ - //TODO: Removed before U AOSP public release. - @Override - public boolean isSubscriptionManagerServiceEnabled() { - return false; - } - - /** - * Called during setup wizard restore flow to attempt to restore the backed up sim-specific - * configs to device for all existing SIMs in the subscription database {@link SimInfo}. - * Internally, it will store the backup data in an internal file. This file will persist on - * device for device's lifetime and will be used later on when a SIM is inserted to restore that - * specific SIM's settings. End result is subscription database is modified to match any backed - * up configs for the appropriate inserted SIMs. - * - *

- * The {@link Uri} {@link SubscriptionManager#SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI} is - * notified if any {@link SimInfo} entry is updated as the result of this method call. - * - * @param data with the sim specific configs to be backed up. - */ - @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) - @Override - public void restoreAllSimSpecificSettingsFromBackup(@NonNull byte[] data) { - enforceModifyPhoneState("restoreAllSimSpecificSettingsFromBackup"); - - long token = Binder.clearCallingIdentity(); - try { - Bundle bundle = new Bundle(); - bundle.putByteArray(SubscriptionManager.KEY_SIM_SPECIFIC_SETTINGS_DATA, data); - mContext.getContentResolver().call( - SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, - SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, - null, bundle); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - /** - * @hide - */ - private void setGlobalSetting(String name, int value) { - Settings.Global.putInt(mContext.getContentResolver(), name, value); - if (TextUtils.equals(name, Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION)) { - invalidateDefaultDataSubIdCaches(); - invalidateActiveDataSubIdCaches(); - invalidateDefaultSubIdCaches(); - invalidateSlotIndexCaches(); - } else if (TextUtils.equals(name, Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION)) { - invalidateDefaultSubIdCaches(); - invalidateSlotIndexCaches(); - } else if (TextUtils.equals(name, Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION)) { - invalidateDefaultSmsSubIdCaches(); - } - } - - private static void invalidateDefaultSubIdCaches() { - SubscriptionManager.invalidateDefaultSubIdCaches(); - } - - private static void invalidateDefaultDataSubIdCaches() { - SubscriptionManager.invalidateDefaultDataSubIdCaches(); - } - - private static void invalidateDefaultSmsSubIdCaches() { - SubscriptionManager.invalidateDefaultSmsSubIdCaches(); - } - - private static void invalidateActiveDataSubIdCaches() { - SubscriptionManager.invalidateActiveDataSubIdCaches(); - } - - private static void invalidateSlotIndexCaches() { - SubscriptionManager.invalidateSlotIndexCaches(); - } -} diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java deleted file mode 100644 index 48d2a8e02f..0000000000 --- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +++ /dev/null @@ -1,1396 +0,0 @@ -/* -* Copyright (C) 2014 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package com.android.internal.telephony; - -import android.Manifest; -import android.annotation.Nullable; -import android.app.ActivityManager; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.os.AsyncResult; -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.ParcelUuid; -import android.os.PersistableBundle; -import android.os.UserHandle; -import android.preference.PreferenceManager; -import android.provider.DeviceConfig; -import android.service.carrier.CarrierIdentifier; -import android.service.euicc.EuiccProfileInfo; -import android.service.euicc.EuiccService; -import android.service.euicc.GetEuiccProfileInfoListResult; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.SubscriptionManager.UsageSetting; -import android.telephony.TelephonyManager; -import android.telephony.UiccAccessRule; -import android.telephony.euicc.EuiccManager; -import android.text.TextUtils; -import android.util.Pair; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.euicc.EuiccController; -import com.android.internal.telephony.metrics.TelephonyMetrics; -import com.android.internal.telephony.uicc.IccRecords; -import com.android.internal.telephony.uicc.IccUtils; -import com.android.internal.telephony.uicc.UiccCard; -import com.android.internal.telephony.uicc.UiccController; -import com.android.internal.telephony.uicc.UiccPort; -import com.android.internal.telephony.uicc.UiccSlot; -import com.android.telephony.Rlog; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CopyOnWriteArraySet; - -/** - *@hide - */ -public class SubscriptionInfoUpdater extends Handler { - private static final String LOG_TAG = "SubscriptionInfoUpdater"; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private static final int SUPPORTED_MODEM_COUNT = TelephonyManager.getDefault() - .getSupportedModemCount(); - - private static final boolean DBG = true; - - private static final int EVENT_INVALID = -1; - private static final int EVENT_GET_NETWORK_SELECTION_MODE_DONE = 2; - private static final int EVENT_SIM_LOADED = 3; - private static final int EVENT_SIM_ABSENT = 4; - private static final int EVENT_SIM_LOCKED = 5; - private static final int EVENT_SIM_IO_ERROR = 6; - private static final int EVENT_SIM_UNKNOWN = 7; - private static final int EVENT_SIM_RESTRICTED = 8; - private static final int EVENT_SIM_NOT_READY = 9; - private static final int EVENT_SIM_READY = 10; - private static final int EVENT_SIM_IMSI = 11; - private static final int EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS = 12; - private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 13; - private static final int EVENT_INACTIVE_SLOT_ICC_STATE_CHANGED = 14; - /** Device config changed. */ - private static final int EVENT_DEVICE_CONFIG_CHANGED = 15; - - private static final String ICCID_STRING_FOR_NO_SIM = ""; - - private static final ParcelUuid REMOVE_GROUP_UUID = - ParcelUuid.fromString(CarrierConfigManager.REMOVE_GROUP_UUID_STRING); - - // Key used to read/write the current IMSI. Updated on SIM_STATE_CHANGED - LOADED. - public static final String CURR_SUBID = "curr_subid"; - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private static Context sContext = null; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - - protected static String[] sIccId = new String[SUPPORTED_MODEM_COUNT]; - protected SubscriptionController mSubscriptionController = null; - private static String[] sInactiveIccIds = new String[SUPPORTED_MODEM_COUNT]; - private static int[] sSimCardState = new int[SUPPORTED_MODEM_COUNT]; - private static int[] sSimApplicationState = new int[SUPPORTED_MODEM_COUNT]; - private static boolean sIsSubInfoInitialized = false; - private SubscriptionManager mSubscriptionManager = null; - private EuiccManager mEuiccManager; - private Handler mBackgroundHandler; - /** DeviceConfig key for whether work profile telephony feature is enabled. */ - private static final String KEY_ENABLE_WORK_PROFILE_TELEPHONY = "enable_work_profile_telephony"; - /** {@code true} if the work profile telephony feature is enabled otherwise {@code false}. */ - private static boolean mIsWorkProfileTelephonyEnabled = false; - - // The current foreground user ID. - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int mCurrentlyActiveUserId; - private CarrierServiceBindHelper mCarrierServiceBindHelper; - - private volatile boolean shouldRetryUpdateEmbeddedSubscriptions = false; - private final CopyOnWriteArraySet retryUpdateEmbeddedSubscriptionCards = - new CopyOnWriteArraySet<>(); - private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { - // The LPA may not have been ready before user unlock, and so previous attempts - // to refresh the list of embedded subscriptions may have failed. This retries - // the refresh operation after user unlock. - if (shouldRetryUpdateEmbeddedSubscriptions) { - logd("Retrying refresh embedded subscriptions after user unlock."); - for (int cardId : retryUpdateEmbeddedSubscriptionCards){ - requestEmbeddedSubscriptionInfoListRefresh(cardId, null); - } - retryUpdateEmbeddedSubscriptionCards.clear(); - sContext.unregisterReceiver(mUserUnlockedReceiver); - } - } - } - }; - - /** - * Runnable with a boolean parameter. This is used in - * updateEmbeddedSubscriptions(List cardIds, @Nullable UpdateEmbeddedSubsCallback). - */ - protected interface UpdateEmbeddedSubsCallback { - /** - * Callback of the Runnable. - * @param hasChanges Whether there is any subscription info change. If yes, we need to - * notify the listeners. - */ - void run(boolean hasChanges); - } - - @VisibleForTesting - public SubscriptionInfoUpdater(Looper looper, Context context, SubscriptionController sc) { - logd("Constructor invoked"); - mBackgroundHandler = new Handler(looper); - - sContext = context; - mSubscriptionController = sc; - mSubscriptionManager = SubscriptionManager.from(sContext); - mEuiccManager = (EuiccManager) sContext.getSystemService(Context.EUICC_SERVICE); - - mCarrierServiceBindHelper = new CarrierServiceBindHelper(sContext); - - sContext.registerReceiver( - mUserUnlockedReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED)); - - initializeCarrierApps(); - - PhoneConfigurationManager.registerForMultiSimConfigChange( - this, EVENT_MULTI_SIM_CONFIG_CHANGED, null); - - mIsWorkProfileTelephonyEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, - KEY_ENABLE_WORK_PROFILE_TELEPHONY, false); - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_TELEPHONY, this::post, - properties -> { - if (TextUtils.equals(DeviceConfig.NAMESPACE_TELEPHONY, - properties.getNamespace())) { - sendEmptyMessage(EVENT_DEVICE_CONFIG_CHANGED); - } - }); - } - - private void initializeCarrierApps() { - // Initialize carrier apps: - // -Now (on system startup) - // -Whenever new carrier privilege rules might change (new SIM is loaded) - // -Whenever we switch to a new user - mCurrentlyActiveUserId = 0; - sContext.registerReceiverForAllUsers(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // Remove this line after testing - if (Intent.ACTION_USER_FOREGROUND.equals(intent.getAction())) { - UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); - // If couldn't get current user ID, guess it's 0. - mCurrentlyActiveUserId = userHandle != null ? userHandle.getIdentifier() : 0; - CarrierAppUtils.disableCarrierAppsUntilPrivileged(sContext.getOpPackageName(), - TelephonyManager.getDefault(), mCurrentlyActiveUserId, sContext); - } - } - }, new IntentFilter(Intent.ACTION_USER_FOREGROUND), null, null); - ActivityManager am = (ActivityManager) sContext.getSystemService(Context.ACTIVITY_SERVICE); - mCurrentlyActiveUserId = am.getCurrentUser(); - CarrierAppUtils.disableCarrierAppsUntilPrivileged(sContext.getOpPackageName(), - TelephonyManager.getDefault(), mCurrentlyActiveUserId, sContext); - } - - /** - * Update subscriptions when given a new ICC state. - */ - public void updateInternalIccState(String simStatus, String reason, int phoneId) { - logd("updateInternalIccState to simStatus " + simStatus + " reason " + reason - + " phoneId " + phoneId); - int message = internalIccStateToMessage(simStatus); - if (message != EVENT_INVALID) { - sendMessage(obtainMessage(message, phoneId, 0, reason)); - } - } - - /** - * Update subscriptions if needed when there's a change in inactive port. - * @param prevActivePhoneId is the corresponding phoneId of the port if port was previously - * active. It could be INVALID if it was already inactive. - * @param iccId iccId in that port, if any. - */ - public void updateInternalIccStateForInactivePort(int prevActivePhoneId, String iccId) { - sendMessage(obtainMessage(EVENT_INACTIVE_SLOT_ICC_STATE_CHANGED, prevActivePhoneId, - 0, iccId)); - } - - private int internalIccStateToMessage(String simStatus) { - switch(simStatus) { - case IccCardConstants.INTENT_VALUE_ICC_ABSENT: return EVENT_SIM_ABSENT; - case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN: return EVENT_SIM_UNKNOWN; - case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR: return EVENT_SIM_IO_ERROR; - case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED: return EVENT_SIM_RESTRICTED; - case IccCardConstants.INTENT_VALUE_ICC_NOT_READY: return EVENT_SIM_NOT_READY; - case IccCardConstants.INTENT_VALUE_ICC_LOCKED: return EVENT_SIM_LOCKED; - case IccCardConstants.INTENT_VALUE_ICC_LOADED: return EVENT_SIM_LOADED; - case IccCardConstants.INTENT_VALUE_ICC_READY: return EVENT_SIM_READY; - case IccCardConstants.INTENT_VALUE_ICC_IMSI: return EVENT_SIM_IMSI; - default: - logd("Ignoring simStatus: " + simStatus); - return EVENT_INVALID; - } - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - protected boolean isAllIccIdQueryDone() { - for (int i = 0; i < TelephonyManager.getDefault().getActiveModemCount(); i++) { - UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(i); - int slotId = UiccController.getInstance().getSlotIdFromPhoneId(i); - // When psim card is absent there is no port object even the port state is active. - // We should check the slot state for psim and port state for esim(MEP eUICC). - if (sIccId[i] == null || slot == null || !slot.isActive() - || (slot.isEuicc() && UiccController.getInstance().getUiccPort(i) == null)) { - if (sIccId[i] == null) { - logd("Wait for SIM " + i + " Iccid"); - } else { - logd(String.format("Wait for port corresponding to phone %d to be active, " - + "slotId is %d" + " , portIndex is %d", i, slotId, - slot.getPortIndexFromPhoneId(i))); - } - return false; - } - } - logd("All IccIds query complete"); - - return true; - } - - @Override - public void handleMessage(Message msg) { - List cardIds = new ArrayList<>(); - switch (msg.what) { - case EVENT_GET_NETWORK_SELECTION_MODE_DONE: { - AsyncResult ar = (AsyncResult)msg.obj; - Integer slotId = (Integer)ar.userObj; - if (ar.exception == null && ar.result != null) { - int[] modes = (int[])ar.result; - if (modes[0] == 1) { // Manual mode. - PhoneFactory.getPhone(slotId).setNetworkSelectionModeAutomatic(null); - } - } else { - logd("EVENT_GET_NETWORK_SELECTION_MODE_DONE: error getting network mode."); - } - break; - } - - case EVENT_SIM_LOADED: - handleSimLoaded(msg.arg1); - break; - - case EVENT_SIM_ABSENT: - handleSimAbsent(msg.arg1); - break; - - case EVENT_INACTIVE_SLOT_ICC_STATE_CHANGED: - handleInactivePortIccStateChange(msg.arg1, (String) msg.obj); - break; - - case EVENT_SIM_LOCKED: - handleSimLocked(msg.arg1, (String) msg.obj); - break; - - case EVENT_SIM_UNKNOWN: - broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null); - broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN); - broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN); - updateSubscriptionCarrierId(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN); - updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN); - break; - - case EVENT_SIM_IO_ERROR: - handleSimError(msg.arg1); - break; - - case EVENT_SIM_RESTRICTED: - broadcastSimStateChanged(msg.arg1, - IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED, - IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED); - broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_CARD_RESTRICTED); - broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY); - updateSubscriptionCarrierId(msg.arg1, - IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED); - updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED); - break; - - case EVENT_SIM_READY: - handleSimReady(msg.arg1); - break; - - case EVENT_SIM_IMSI: - broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_IMSI, null); - break; - - case EVENT_SIM_NOT_READY: - // an eUICC with no active subscriptions never becomes ready, so we need to trigger - // the embedded subscriptions update here - cardIds.add(getCardIdFromPhoneId(msg.arg1)); - updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { - if (hasChanges) { - mSubscriptionController.notifySubscriptionInfoChanged(); - } - }); - handleSimNotReady(msg.arg1); - break; - - case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS: - cardIds.add(msg.arg1); - Runnable r = (Runnable) msg.obj; - updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { - if (hasChanges) { - mSubscriptionController.notifySubscriptionInfoChanged(); - } - if (r != null) { - r.run(); - } - }); - break; - - case EVENT_MULTI_SIM_CONFIG_CHANGED: - onMultiSimConfigChanged(); - break; - - case EVENT_DEVICE_CONFIG_CHANGED: - boolean isWorkProfileTelephonyEnabled = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_TELEPHONY, KEY_ENABLE_WORK_PROFILE_TELEPHONY, - false); - if (isWorkProfileTelephonyEnabled != mIsWorkProfileTelephonyEnabled) { - logd("EVENT_DEVICE_CONFIG_CHANGED: isWorkProfileTelephonyEnabled changed from " - + mIsWorkProfileTelephonyEnabled + " to " - + isWorkProfileTelephonyEnabled); - mIsWorkProfileTelephonyEnabled = isWorkProfileTelephonyEnabled; - } - break; - - default: - logd("Unknown msg:" + msg.what); - } - } - - private void onMultiSimConfigChanged() { - int activeModemCount = ((TelephonyManager) sContext.getSystemService( - Context.TELEPHONY_SERVICE)).getActiveModemCount(); - // For inactive modems, reset its states. - for (int phoneId = activeModemCount; phoneId < SUPPORTED_MODEM_COUNT; phoneId++) { - sIccId[phoneId] = null; - sSimCardState[phoneId] = TelephonyManager.SIM_STATE_UNKNOWN; - sSimApplicationState[phoneId] = TelephonyManager.SIM_STATE_UNKNOWN; - } - } - - protected int getCardIdFromPhoneId(int phoneId) { - UiccController uiccController = UiccController.getInstance(); - UiccCard card = uiccController.getUiccCardForPhone(phoneId); - if (card != null) { - return uiccController.convertToPublicCardId(card.getCardId()); - } - return TelephonyManager.UNINITIALIZED_CARD_ID; - } - - void requestEmbeddedSubscriptionInfoListRefresh(int cardId, @Nullable Runnable callback) { - sendMessage(obtainMessage( - EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback)); - } - - protected void handleSimLocked(int phoneId, String reason) { - if (sIccId[phoneId] != null && sIccId[phoneId].equals(ICCID_STRING_FOR_NO_SIM)) { - logd("SIM" + (phoneId + 1) + " hot plug in"); - sIccId[phoneId] = null; - } - - IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); - if (iccCard == null) { - logd("handleSimLocked: IccCard null"); - return; - } - IccRecords records = iccCard.getIccRecords(); - if (records == null) { - logd("handleSimLocked: IccRecords null"); - return; - } - if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) { - logd("handleSimLocked: IccID null"); - return; - } - sIccId[phoneId] = IccUtils.stripTrailingFs(records.getFullIccId()); - - updateSubscriptionInfoByIccId(phoneId, true /* updateEmbeddedSubs */); - - broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOCKED, reason); - broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_PRESENT); - broadcastSimApplicationStateChanged(phoneId, getSimStateFromLockedReason(reason)); - updateSubscriptionCarrierId(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOCKED); - updateCarrierServices(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOCKED); - } - - private static int getSimStateFromLockedReason(String lockedReason) { - switch (lockedReason) { - case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN: - return TelephonyManager.SIM_STATE_PIN_REQUIRED; - case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK: - return TelephonyManager.SIM_STATE_PUK_REQUIRED; - case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK: - return TelephonyManager.SIM_STATE_NETWORK_LOCKED; - case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED: - return TelephonyManager.SIM_STATE_PERM_DISABLED; - default: - Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason); - return TelephonyManager.SIM_STATE_UNKNOWN; - } - } - - protected void handleSimReady(int phoneId) { - List cardIds = new ArrayList<>(); - logd("handleSimReady: phoneId: " + phoneId); - - if (sIccId[phoneId] != null && sIccId[phoneId].equals(ICCID_STRING_FOR_NO_SIM)) { - logd(" SIM" + (phoneId + 1) + " hot plug in"); - sIccId[phoneId] = null; - } - - // ICCID is not available in IccRecords by the time SIM Ready event received - // hence get ICCID from UiccPort. - UiccPort port = UiccController.getInstance().getUiccPort(phoneId); - String iccId = (port == null) ? null : IccUtils.stripTrailingFs(port.getIccId()); - - if (!TextUtils.isEmpty(iccId)) { - sIccId[phoneId] = iccId; - updateSubscriptionInfoByIccId(phoneId, true /* updateEmbeddedSubs */); - } - - cardIds.add(getCardIdFromPhoneId(phoneId)); - updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { - if (hasChanges) { - mSubscriptionController.notifySubscriptionInfoChanged(); - } - }); - broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_READY, null); - broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_PRESENT); - broadcastSimApplicationStateChanged(phoneId, TelephonyManager.SIM_STATE_NOT_READY); - } - - protected void handleSimNotReady(int phoneId) { - logd("handleSimNotReady: phoneId: " + phoneId); - boolean isFinalState = false; - - IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); - boolean uiccAppsDisabled = areUiccAppsDisabledOnCard(phoneId); - if (iccCard.isEmptyProfile() || uiccAppsDisabled) { - if (uiccAppsDisabled) { - UiccPort port = UiccController.getInstance().getUiccPort(phoneId); - String iccId = (port == null) ? null : port.getIccId(); - sInactiveIccIds[phoneId] = IccUtils.stripTrailingFs(iccId); - } - isFinalState = true; - // ICC_NOT_READY is a terminal state for - // 1) It's an empty profile as there's no uicc applications. Or - // 2) Its uicc applications are set to be disabled. - // At this phase, the subscription list is accessible. Treating NOT_READY - // as equivalent to ABSENT, once the rest of the system can handle it. - sIccId[phoneId] = ICCID_STRING_FOR_NO_SIM; - updateSubscriptionInfoByIccId(phoneId, false /* updateEmbeddedSubs */); - } else { - sIccId[phoneId] = null; - } - - broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY, - null); - broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_PRESENT); - broadcastSimApplicationStateChanged(phoneId, TelephonyManager.SIM_STATE_NOT_READY); - if (isFinalState) { - updateCarrierServices(phoneId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY); - } - } - - private boolean areUiccAppsDisabledOnCard(int phoneId) { - // When uicc apps are disabled(supported in IRadio 1.5), we will still get IccId from - // cardStatus (since IRadio 1.2). Amd upon cardStatus change we'll receive another - // handleSimNotReady so this will be evaluated again. - UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); - if (slot == null) return false; - UiccPort port = UiccController.getInstance().getUiccPort(phoneId); - String iccId = (port == null) ? null : port.getIccId(); - if (iccId == null) { - return false; - } - SubscriptionInfo info = - mSubscriptionController.getSubInfoForIccId( - IccUtils.stripTrailingFs(iccId)); - return info != null && !info.areUiccApplicationsEnabled(); - } - - protected void handleSimLoaded(int phoneId) { - logd("handleSimLoaded: phoneId: " + phoneId); - - // The SIM should be loaded at this state, but it is possible in cases such as SIM being - // removed or a refresh RESET that the IccRecords could be null. The right behavior is to - // not broadcast the SIM loaded. - IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); - if (iccCard == null) { // Possibly a race condition. - logd("handleSimLoaded: IccCard null"); - return; - } - IccRecords records = iccCard.getIccRecords(); - if (records == null) { // Possibly a race condition. - logd("handleSimLoaded: IccRecords null"); - return; - } - if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) { - logd("handleSimLoaded: IccID null"); - return; - } - - // Call updateSubscriptionInfoByIccId() only if was not done earlier from SIM READY event - if (sIccId[phoneId] == null) { - sIccId[phoneId] = IccUtils.stripTrailingFs(records.getFullIccId()); - - updateSubscriptionInfoByIccId(phoneId, true /* updateEmbeddedSubs */); - } - - List subscriptionInfos = - mSubscriptionController.getSubInfoUsingSlotIndexPrivileged(phoneId); - if (subscriptionInfos == null || subscriptionInfos.isEmpty()) { - loge("empty subinfo for phoneId: " + phoneId + "could not update ContentResolver"); - } else { - for (SubscriptionInfo sub : subscriptionInfos) { - int subId = sub.getSubscriptionId(); - TelephonyManager tm = (TelephonyManager) - sContext.getSystemService(Context.TELEPHONY_SERVICE); - String operator = tm.getSimOperatorNumeric(subId); - - if (!TextUtils.isEmpty(operator)) { - if (subId == mSubscriptionController.getDefaultSubId()) { - MccTable.updateMccMncConfiguration(sContext, operator); - } - mSubscriptionController.setMccMnc(operator, subId); - } else { - logd("EVENT_RECORDS_LOADED Operator name is null"); - } - - String iso = tm.getSimCountryIsoForPhone(phoneId); - - if (!TextUtils.isEmpty(iso)) { - mSubscriptionController.setCountryIso(iso, subId); - } else { - logd("EVENT_RECORDS_LOADED sim country iso is null"); - } - - String msisdn = tm.getLine1Number(subId); - if (msisdn != null) { - mSubscriptionController.setDisplayNumber(msisdn, subId); - } - - String imsi = tm.createForSubscriptionId(subId).getSubscriberId(); - if (imsi != null) { - mSubscriptionController.setImsi(imsi, subId); - } - - String[] ehplmns = records.getEhplmns(); - String[] hplmns = records.getPlmnsFromHplmnActRecord(); - if (ehplmns != null || hplmns != null) { - mSubscriptionController.setAssociatedPlmns(ehplmns, hplmns, subId); - } - - /* Update preferred network type and network selection mode on SIM change. - * Storing last subId in SharedPreference for now to detect SIM change. - */ - SharedPreferences sp = - PreferenceManager.getDefaultSharedPreferences(sContext); - int storedSubId = sp.getInt(CURR_SUBID + phoneId, -1); - - if (storedSubId != subId) { - // Only support automatic selection mode on SIM change. - PhoneFactory.getPhone(phoneId).getNetworkSelectionMode( - obtainMessage(EVENT_GET_NETWORK_SELECTION_MODE_DONE, - new Integer(phoneId))); - // Update stored subId - SharedPreferences.Editor editor = sp.edit(); - editor.putInt(CURR_SUBID + phoneId, subId); - editor.apply(); - } - } - } - - /** - * The sim loading sequence will be - * 1. OnSubscriptionsChangedListener is called through updateSubscriptionInfoByIccId() - * above. - * 2. ACTION_SIM_STATE_CHANGED/ACTION_SIM_CARD_STATE_CHANGED - * /ACTION_SIM_APPLICATION_STATE_CHANGED - * 3. ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED - * 4. restore sim-specific settings - * 5. ACTION_CARRIER_CONFIG_CHANGED - */ - broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null); - broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_PRESENT); - broadcastSimApplicationStateChanged(phoneId, TelephonyManager.SIM_STATE_LOADED); - updateSubscriptionCarrierId(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED); - /* Sim-specific settings restore depends on knowing both the mccmnc and the carrierId of the - sim which is why it must be done after #updateSubscriptionCarrierId(). It is done before - carrier config update to avoid any race conditions with user settings that depend on - carrier config*/ - restoreSimSpecificSettingsForPhone(phoneId); - updateCarrierServices(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED); - } - - /** - * Calculate the usage setting based on the carrier request. - * - * @param currentUsageSetting the current setting in the subscription DB - * @param preferredUsageSetting provided by the carrier config - * @return the calculated usage setting. - */ - @VisibleForTesting - @UsageSetting public int calculateUsageSetting( - @UsageSetting int currentUsageSetting, @UsageSetting int preferredUsageSetting) { - int defaultUsageSetting; - int[] supportedUsageSettings; - - // Load the resources to provide the device capability - try { - defaultUsageSetting = sContext.getResources().getInteger( - com.android.internal.R.integer.config_default_cellular_usage_setting); - supportedUsageSettings = sContext.getResources().getIntArray( - com.android.internal.R.array.config_supported_cellular_usage_settings); - // If usage settings are not supported, return the default setting, which is UNKNOWN. - if (supportedUsageSettings == null - || supportedUsageSettings.length < 1) return currentUsageSetting; - } catch (Resources.NotFoundException nfe) { - loge("Failed to load usage setting resources!"); - return currentUsageSetting; - } - - // If the current setting is invalid, including the first time the value is set, - // update it to default (this will trigger a change in the DB). - if (currentUsageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT - || currentUsageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { - logd("Updating usage setting for current subscription"); - currentUsageSetting = SubscriptionManager.USAGE_SETTING_DEFAULT; - } - - // Range check the inputs, and on failure, make no changes - if (preferredUsageSetting < SubscriptionManager.USAGE_SETTING_DEFAULT - || preferredUsageSetting > SubscriptionManager.USAGE_SETTING_DATA_CENTRIC) { - loge("Invalid usage setting!" + preferredUsageSetting); - return currentUsageSetting; - } - - // Default is always allowed - if (preferredUsageSetting == SubscriptionManager.USAGE_SETTING_DEFAULT) { - return preferredUsageSetting; - } - - // Forced setting must be explicitly supported - for (int i = 0; i < supportedUsageSettings.length; i++) { - if (preferredUsageSetting == supportedUsageSettings[i]) return preferredUsageSetting; - } - - // If the preferred setting is not possible, just keep the current setting. - return currentUsageSetting; - } - - private void restoreSimSpecificSettingsForPhone(int phoneId) { - sContext.getContentResolver().call( - SubscriptionManager.SIM_INFO_BACKUP_AND_RESTORE_CONTENT_URI, - SubscriptionManager.RESTORE_SIM_SPECIFIC_SETTINGS_METHOD_NAME, - sIccId[phoneId], null); - } - - private void updateCarrierServices(int phoneId, String simState) { - if (!SubscriptionManager.isValidPhoneId(phoneId)) { - logd("Ignore updateCarrierServices request with invalid phoneId " + phoneId); - return; - } - CarrierConfigManager configManager = - (CarrierConfigManager) sContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - configManager.updateConfigForPhoneId(phoneId, simState); - mCarrierServiceBindHelper.updateForPhoneId(phoneId, simState); - } - - private void updateSubscriptionCarrierId(int phoneId, String simState) { - if (PhoneFactory.getPhone(phoneId) != null) { - PhoneFactory.getPhone(phoneId).resolveSubscriptionCarrierId(simState); - } - } - - /** - * PhoneId is the corresponding phoneId of the port if port was previously active. - * It could be INVALID if it was already inactive. - */ - private void handleInactivePortIccStateChange(int phoneId, String iccId) { - if (SubscriptionManager.isValidPhoneId(phoneId)) { - // If phoneId is valid, it means the physical slot was previously active in that - // phoneId. In this case, found the subId and set its phoneId to invalid. - if (sIccId[phoneId] != null && !sIccId[phoneId].equals(ICCID_STRING_FOR_NO_SIM)) { - logd("Slot of SIM" + (phoneId + 1) + " becomes inactive"); - } - cleanSubscriptionInPhone(phoneId, false); - } - if (!TextUtils.isEmpty(iccId)) { - // If iccId is new, add a subscription record in the db. - String strippedIccId = IccUtils.stripTrailingFs(iccId); - if (mSubscriptionController.getSubInfoForIccId(strippedIccId) == null) { - mSubscriptionController.insertEmptySubInfoRecord( - strippedIccId, "CARD", SubscriptionManager.INVALID_PHONE_INDEX, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - } - } - } - - /** - * Clean subscription info when sim state becomes ABSENT. There are 2 scenarios for this: - * 1. SIM is actually removed - * 2. Slot becomes inactive, which results in SIM being treated as ABSENT, but SIM may not - * have been removed. - * @param phoneId phoneId for which the cleanup needs to be done - * @param isSimAbsent boolean to indicate if the SIM is actually ABSENT (case 1 above) - */ - private void cleanSubscriptionInPhone(int phoneId, boolean isSimAbsent) { - if (sInactiveIccIds[phoneId] != null || (isSimAbsent && sIccId[phoneId] != null - && !sIccId[phoneId].equals(ICCID_STRING_FOR_NO_SIM))) { - // When a SIM is unplugged, mark uicc applications enabled. This is to make sure when - // user unplugs and re-inserts the SIM card, we re-enable it. - // In certain cases this can happen before sInactiveIccIds is updated, which is why we - // check for sIccId as well (in case of isSimAbsent). The scenario is: after SIM - // deactivate request is sent to RIL, SIM is removed before SIM state is updated to - // NOT_READY. We do not need to check if this exact scenario is hit, because marking - // uicc applications enabled when SIM is removed should be okay to do regardless. - logd("cleanSubscriptionInPhone: " + phoneId + ", inactive iccid " - + sInactiveIccIds[phoneId]); - if (sInactiveIccIds[phoneId] == null) { - logd("cleanSubscriptionInPhone: " + phoneId + ", isSimAbsent=" + isSimAbsent - + ", iccid=" + sIccId[phoneId]); - } - String iccId = sInactiveIccIds[phoneId] != null - ? sInactiveIccIds[phoneId] : sIccId[phoneId]; - ContentValues value = new ContentValues(); - value.put(SubscriptionManager.UICC_APPLICATIONS_ENABLED, true); - if (isSimAbsent) { - // When sim is absent, set the port index to invalid port index -1; - value.put(SubscriptionManager.PORT_INDEX, TelephonyManager.INVALID_PORT_INDEX); - } - sContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value, - SubscriptionManager.ICC_ID + "=\'" + iccId + "\'", null); - sInactiveIccIds[phoneId] = null; - } - sIccId[phoneId] = ICCID_STRING_FOR_NO_SIM; - updateSubscriptionInfoByIccId(phoneId, true /* updateEmbeddedSubs */); - } - - protected void handleSimAbsent(int phoneId) { - if (!SubscriptionManager.isValidPhoneId(phoneId)) { - logd("handleSimAbsent on invalid phoneId"); - return; - } - if (sIccId[phoneId] != null && !sIccId[phoneId].equals(ICCID_STRING_FOR_NO_SIM)) { - logd("SIM" + (phoneId + 1) + " hot plug out"); - } - cleanSubscriptionInPhone(phoneId, true); - - broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_ABSENT, null); - broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_ABSENT); - broadcastSimApplicationStateChanged(phoneId, TelephonyManager.SIM_STATE_UNKNOWN); - updateSubscriptionCarrierId(phoneId, IccCardConstants.INTENT_VALUE_ICC_ABSENT); - updateCarrierServices(phoneId, IccCardConstants.INTENT_VALUE_ICC_ABSENT); - } - - protected void handleSimError(int phoneId) { - if (sIccId[phoneId] != null && !sIccId[phoneId].equals(ICCID_STRING_FOR_NO_SIM)) { - logd("SIM" + (phoneId + 1) + " Error "); - } - sIccId[phoneId] = ICCID_STRING_FOR_NO_SIM; - updateSubscriptionInfoByIccId(phoneId, true /* updateEmbeddedSubs */); - broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR, - IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); - broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_CARD_IO_ERROR); - broadcastSimApplicationStateChanged(phoneId, TelephonyManager.SIM_STATE_NOT_READY); - updateSubscriptionCarrierId(phoneId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); - updateCarrierServices(phoneId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); - } - - protected synchronized void updateSubscriptionInfoByIccId(int phoneId, - boolean updateEmbeddedSubs) { - logd("updateSubscriptionInfoByIccId:+ Start - phoneId: " + phoneId); - if (!SubscriptionManager.isValidPhoneId(phoneId)) { - loge("[updateSubscriptionInfoByIccId]- invalid phoneId=" + phoneId); - return; - } - logd("updateSubscriptionInfoByIccId: removing subscription info record: phoneId " - + phoneId); - // Clear phoneId only when sim absent is not enough. It's possible to switch SIM profile - // within the same slot. Need to clear the slot index of the previous sub. Thus always clear - // for the changing slot first. - mSubscriptionController.clearSubInfoRecord(phoneId); - - // If SIM is not absent, insert new record or update existing record. - if (!ICCID_STRING_FOR_NO_SIM.equals(sIccId[phoneId]) && sIccId[phoneId] != null) { - logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: " - + SubscriptionInfo.getPrintableId(sIccId[phoneId]) - + ", phoneId:" + phoneId); - mSubscriptionManager.addSubscriptionInfoRecord(sIccId[phoneId], phoneId); - } - - List subInfos = - mSubscriptionController.getSubInfoUsingSlotIndexPrivileged(phoneId); - if (subInfos != null) { - boolean changed = false; - for (int i = 0; i < subInfos.size(); i++) { - SubscriptionInfo temp = subInfos.get(i); - ContentValues value = new ContentValues(1); - - String msisdn = TelephonyManager.getDefault().getLine1Number( - temp.getSubscriptionId()); - - if (!TextUtils.equals(msisdn, temp.getNumber())) { - value.put(SubscriptionManager.NUMBER, msisdn); - sContext.getContentResolver().update(SubscriptionManager - .getUriForSubscriptionId(temp.getSubscriptionId()), value, null, null); - changed = true; - } - } - if (changed) { - // refresh Cached Active Subscription Info List - mSubscriptionController.refreshCachedActiveSubscriptionInfoList(); - } - } - - // TODO investigate if we can update for each slot separately. - if (isAllIccIdQueryDone()) { - // Ensure the modems are mapped correctly - if (mSubscriptionManager.isActiveSubId( - mSubscriptionManager.getDefaultDataSubscriptionId())) { - mSubscriptionManager.setDefaultDataSubId( - mSubscriptionManager.getDefaultDataSubscriptionId()); - } else { - logd("bypass reset default data sub if inactive"); - } - setSubInfoInitialized(); - } - - UiccController uiccController = UiccController.getInstance(); - UiccSlot[] uiccSlots = uiccController.getUiccSlots(); - if (uiccSlots != null && updateEmbeddedSubs) { - List cardIds = new ArrayList<>(); - for (UiccSlot uiccSlot : uiccSlots) { - if (uiccSlot != null && uiccSlot.getUiccCard() != null) { - int cardId = uiccController.convertToPublicCardId( - uiccSlot.getUiccCard().getCardId()); - cardIds.add(cardId); - } - } - updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { - if (hasChanges) { - mSubscriptionController.notifySubscriptionInfoChanged(); - } - if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete"); - }); - } - - mSubscriptionController.notifySubscriptionInfoChanged(); - if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete"); - } - - private void setSubInfoInitialized() { - // Should only be triggered once. - if (!sIsSubInfoInitialized) { - if (DBG) logd("SubInfo Initialized"); - sIsSubInfoInitialized = true; - mSubscriptionController.notifySubInfoReady(); - } - MultiSimSettingController.getInstance().notifyAllSubscriptionLoaded(); - } - - /** - * Whether subscriptions of all SIMs are initialized. - */ - public static boolean isSubInfoInitialized() { - return sIsSubInfoInitialized; - } - - /** - * Whether work profile telephony feature is enabled or not. - * return {@code true} if work profile telephony feature is enabled. - */ - public static boolean isWorkProfileTelephonyEnabled() { - return mIsWorkProfileTelephonyEnabled; - } - - /** - * Updates the cached list of embedded subscription for the eUICC with the given list of card - * IDs {@code cardIds}. The step of reading the embedded subscription list from eUICC card is - * executed in background thread. The callback {@code callback} is executed after the cache is - * refreshed. The callback is executed in main thread. - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) - public void updateEmbeddedSubscriptions(List cardIds, - @Nullable UpdateEmbeddedSubsCallback callback) { - // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but they - // are filtered out of list calls as long as EuiccManager.isEnabled returns false). - if (!mEuiccManager.isEnabled()) { - if (DBG) logd("updateEmbeddedSubscriptions: eUICC not enabled"); - callback.run(false /* hasChanges */); - return; - } - - mBackgroundHandler.post(() -> { - List> results = new ArrayList<>(); - for (int cardId : cardIds) { - GetEuiccProfileInfoListResult result = - EuiccController.get().blockingGetEuiccProfileInfoList(cardId); - if (DBG) logd("blockingGetEuiccProfileInfoList cardId " + cardId); - results.add(Pair.create(cardId, result)); - } - - // The runnable will be executed in the main thread. - this.post(() -> { - boolean hasChanges = false; - for (Pair cardIdAndResult : results) { - if (updateEmbeddedSubscriptionsCache(cardIdAndResult.first, - cardIdAndResult.second)) { - hasChanges = true; - } - } - // The latest state in the main thread may be changed when the callback is - // triggered. - if (callback != null) { - callback.run(hasChanges); - } - }); - }); - } - - /** - * Update the cached list of embedded subscription based on the passed in - * GetEuiccProfileInfoListResult {@code result}. - * - * @return true if changes may have been made. This is not a guarantee that changes were made, - * but notifications about subscription changes may be skipped if this returns false as an - * optimization to avoid spurious notifications. - */ - private boolean updateEmbeddedSubscriptionsCache(int cardId, - GetEuiccProfileInfoListResult result) { - if (DBG) logd("updateEmbeddedSubscriptionsCache"); - - if (result == null) { - if (DBG) logd("updateEmbeddedSubscriptionsCache: IPC to the eUICC controller failed"); - retryUpdateEmbeddedSubscriptionCards.add(cardId); - shouldRetryUpdateEmbeddedSubscriptions = true; - return false; - } - - // If the returned result is not RESULT_OK or the profile list is null, don't update cache. - // Otherwise, update the cache. - final EuiccProfileInfo[] embeddedProfiles; - List list = result.getProfiles(); - if (result.getResult() == EuiccService.RESULT_OK && list != null) { - embeddedProfiles = list.toArray(new EuiccProfileInfo[list.size()]); - if (DBG) { - logd("blockingGetEuiccProfileInfoList: got " + result.getProfiles().size() - + " profiles"); - } - } else { - if (DBG) { - logd("blockingGetEuiccProfileInfoList returns an error. " - + "Result code=" + result.getResult() - + ". Null profile list=" + (result.getProfiles() == null)); - } - return false; - } - - final boolean isRemovable = result.getIsRemovable(); - - final String[] embeddedIccids = new String[embeddedProfiles.length]; - for (int i = 0; i < embeddedProfiles.length; i++) { - embeddedIccids[i] = embeddedProfiles[i].getIccid(); - } - - if (DBG) logd("Get eUICC profile list of size " + embeddedProfiles.length); - - // Note that this only tracks whether we make any writes to the DB. It's possible this will - // be set to true for an update even when the row contents remain exactly unchanged from - // before, since we don't compare against the previous value. Since this is only intended to - // avoid some spurious broadcasts (particularly for users who don't use eSIM at all), this - // is fine. - boolean hasChanges = false; - - // Update or insert records for all embedded subscriptions (except non-removable ones if the - // current eUICC is non-removable, since we assume these are still accessible though not - // returned by the eUICC controller). - List existingSubscriptions = - mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( - embeddedIccids, isRemovable); - ContentResolver contentResolver = sContext.getContentResolver(); - for (EuiccProfileInfo embeddedProfile : embeddedProfiles) { - int index = - findSubscriptionInfoForIccid(existingSubscriptions, embeddedProfile.getIccid()); - int prevCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID; - int nameSource = SubscriptionManager.NAME_SOURCE_CARRIER_ID; - if (index < 0) { - // No existing entry for this ICCID; create an empty one. - mSubscriptionController.insertEmptySubInfoRecord( - embeddedProfile.getIccid(), SubscriptionManager.SIM_NOT_INSERTED); - } else { - nameSource = existingSubscriptions.get(index).getDisplayNameSource(); - prevCarrierId = existingSubscriptions.get(index).getCarrierId(); - existingSubscriptions.remove(index); - } - - if (DBG) { - logd("embeddedProfile " + embeddedProfile + " existing record " - + (index < 0 ? "not found" : "found")); - } - - ContentValues values = new ContentValues(); - values.put(SubscriptionManager.IS_EMBEDDED, 1); - List ruleList = embeddedProfile.getUiccAccessRules(); - boolean isRuleListEmpty = false; - if (ruleList == null || ruleList.size() == 0) { - isRuleListEmpty = true; - } - values.put(SubscriptionManager.ACCESS_RULES, - isRuleListEmpty ? null : UiccAccessRule.encodeRules( - ruleList.toArray(new UiccAccessRule[ruleList.size()]))); - values.put(SubscriptionManager.IS_REMOVABLE, isRemovable); - // override DISPLAY_NAME if the priority of existing nameSource is <= carrier - if (SubscriptionController.getNameSourcePriority(nameSource) - <= SubscriptionController.getNameSourcePriority( - SubscriptionManager.NAME_SOURCE_CARRIER)) { - values.put(SubscriptionManager.DISPLAY_NAME, embeddedProfile.getNickname()); - values.put(SubscriptionManager.NAME_SOURCE, - SubscriptionManager.NAME_SOURCE_CARRIER); - } - values.put(SubscriptionManager.PROFILE_CLASS, embeddedProfile.getProfileClass()); - values.put(SubscriptionManager.PORT_INDEX, - getEmbeddedProfilePortIndex(embeddedProfile.getIccid())); - CarrierIdentifier cid = embeddedProfile.getCarrierIdentifier(); - if (cid != null) { - // Due to the limited subscription information, carrier id identified here might - // not be accurate compared with CarrierResolver. Only update carrier id if there - // is no valid carrier id present. - if (prevCarrierId == TelephonyManager.UNKNOWN_CARRIER_ID) { - values.put(SubscriptionManager.CARRIER_ID, - CarrierResolver.getCarrierIdFromIdentifier(sContext, cid)); - } - String mcc = cid.getMcc(); - String mnc = cid.getMnc(); - values.put(SubscriptionManager.MCC_STRING, mcc); - values.put(SubscriptionManager.MCC, mcc); - values.put(SubscriptionManager.MNC_STRING, mnc); - values.put(SubscriptionManager.MNC, mnc); - } - // If cardId = unsupported or unitialized, we have no reason to update DB. - // Additionally, if the device does not support cardId for default eUICC, the CARD_ID - // field should not contain the EID - UiccController uiccController = UiccController.getInstance(); - if (cardId >= 0 && uiccController.getCardIdForDefaultEuicc() - != TelephonyManager.UNSUPPORTED_CARD_ID) { - values.put(SubscriptionManager.CARD_ID, uiccController.convertToCardString(cardId)); - } - hasChanges = true; - contentResolver.update(SubscriptionManager.CONTENT_URI, values, - SubscriptionManager.ICC_ID + "='" + embeddedProfile.getIccid() + "'", null); - - // refresh Cached Active Subscription Info List - mSubscriptionController.refreshCachedActiveSubscriptionInfoList(); - } - - // Remove all remaining subscriptions which have embedded = true. We set embedded to false - // to ensure they are not returned in the list of embedded subscriptions (but keep them - // around in case the subscription is added back later, which is equivalent to a removable - // SIM being removed and reinserted). - if (!existingSubscriptions.isEmpty()) { - if (DBG) { - logd("Removing existing embedded subscriptions of size" - + existingSubscriptions.size()); - } - List iccidsToRemove = new ArrayList<>(); - for (int i = 0; i < existingSubscriptions.size(); i++) { - SubscriptionInfo info = existingSubscriptions.get(i); - if (info.isEmbedded()) { - if (DBG) logd("Removing embedded subscription of IccId " + info.getIccId()); - iccidsToRemove.add("'" + info.getIccId() + "'"); - } - } - String whereClause = SubscriptionManager.ICC_ID + " IN (" - + TextUtils.join(",", iccidsToRemove) + ")"; - ContentValues values = new ContentValues(); - values.put(SubscriptionManager.IS_EMBEDDED, 0); - hasChanges = true; - contentResolver.update(SubscriptionManager.CONTENT_URI, values, whereClause, null); - - // refresh Cached Active Subscription Info List - mSubscriptionController.refreshCachedActiveSubscriptionInfoList(); - } - - if (DBG) logd("updateEmbeddedSubscriptions done hasChanges=" + hasChanges); - return hasChanges; - } - - private int getEmbeddedProfilePortIndex(String iccId) { - UiccSlot[] slots = UiccController.getInstance().getUiccSlots(); - for (UiccSlot slot : slots) { - if (slot != null && slot.isEuicc() - && slot.getPortIndexFromIccId(iccId) != TelephonyManager.INVALID_PORT_INDEX) { - return slot.getPortIndexFromIccId(iccId); - } - } - return TelephonyManager.INVALID_PORT_INDEX; - } - /** - * Called by CarrierConfigLoader to update the subscription before sending a broadcast. - */ - public void updateSubscriptionByCarrierConfigAndNotifyComplete(int phoneId, - String configPackageName, PersistableBundle config, Message onComplete) { - post(() -> { - updateSubscriptionByCarrierConfig(phoneId, configPackageName, config); - onComplete.sendToTarget(); - }); - } - - private String getDefaultCarrierServicePackageName() { - CarrierConfigManager configManager = - (CarrierConfigManager) sContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - return configManager.getDefaultCarrierServicePackageName(); - } - - private boolean isCarrierServicePackage(int phoneId, String pkgName) { - if (pkgName.equals(getDefaultCarrierServicePackageName())) return false; - - String carrierPackageName = TelephonyManager.from(sContext) - .getCarrierServicePackageNameForLogicalSlot(phoneId); - if (DBG) logd("Carrier service package for subscription = " + carrierPackageName); - return pkgName.equals(carrierPackageName); - } - - /** - * Update the currently active Subscription based on information from CarrierConfig - */ - @VisibleForTesting - public void updateSubscriptionByCarrierConfig( - int phoneId, String configPackageName, PersistableBundle config) { - if (!SubscriptionManager.isValidPhoneId(phoneId) - || TextUtils.isEmpty(configPackageName) || config == null) { - if (DBG) { - logd("In updateSubscriptionByCarrierConfig(): phoneId=" + phoneId - + " configPackageName=" + configPackageName + " config=" - + ((config == null) ? "null" : config.hashCode())); - } - return; - } - - int currentSubId = mSubscriptionController.getSubId(phoneId); - if (!SubscriptionManager.isValidSubscriptionId(currentSubId) - || currentSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { - if (DBG) logd("No subscription is active for phone being updated"); - return; - } - - SubscriptionInfo currentSubInfo = mSubscriptionController.getSubscriptionInfo(currentSubId); - if (currentSubInfo == null) { - loge("Couldn't retrieve subscription info for current subscription"); - return; - } - - ContentValues cv = new ContentValues(); - ParcelUuid groupUuid = null; - - // carrier certificates are not subscription-specific, so we want to load them even if - // this current package is not a CarrierServicePackage - String[] certs = config.getStringArray( - CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY); - UiccAccessRule[] carrierConfigAccessRules = UiccAccessRule.decodeRulesFromCarrierConfig( - certs); - cv.put(SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS, - UiccAccessRule.encodeRules(carrierConfigAccessRules)); - - if (!isCarrierServicePackage(phoneId, configPackageName)) { - loge("Cannot manage subId=" + currentSubId + ", carrierPackage=" + configPackageName); - } else { - boolean isOpportunistic = config.getBoolean( - CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, - currentSubInfo.isOpportunistic()); - if (currentSubInfo.isOpportunistic() != isOpportunistic) { - if (DBG) logd("Set SubId=" + currentSubId + " isOpportunistic=" + isOpportunistic); - cv.put(SubscriptionManager.IS_OPPORTUNISTIC, isOpportunistic ? "1" : "0"); - } - - String groupUuidString = - config.getString(CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, ""); - if (!TextUtils.isEmpty(groupUuidString)) { - try { - // Update via a UUID Structure to ensure consistent formatting - groupUuid = ParcelUuid.fromString(groupUuidString); - if (groupUuid.equals(REMOVE_GROUP_UUID) - && currentSubInfo.getGroupUuid() != null) { - cv.put(SubscriptionManager.GROUP_UUID, (String) null); - if (DBG) logd("Group Removed for" + currentSubId); - } else if (mSubscriptionController.canPackageManageGroup( - groupUuid, configPackageName)) { - cv.put(SubscriptionManager.GROUP_UUID, groupUuid.toString()); - cv.put(SubscriptionManager.GROUP_OWNER, configPackageName); - if (DBG) logd("Group Added for" + currentSubId); - } else { - loge("configPackageName " + configPackageName + " doesn't own grouUuid " - + groupUuid); - } - } catch (IllegalArgumentException e) { - loge("Invalid Group UUID=" + groupUuidString); - } - } - } - - final int preferredUsageSetting = - config.getInt( - CarrierConfigManager.KEY_CELLULAR_USAGE_SETTING_INT, - SubscriptionManager.USAGE_SETTING_UNKNOWN); - - @UsageSetting int newUsageSetting = calculateUsageSetting( - currentSubInfo.getUsageSetting(), - preferredUsageSetting); - - if (newUsageSetting != currentSubInfo.getUsageSetting()) { - cv.put(SubscriptionManager.USAGE_SETTING, newUsageSetting); - if (DBG) { - logd("UsageSetting changed," - + " oldSetting=" + currentSubInfo.getUsageSetting() - + " preferredSetting=" + preferredUsageSetting - + " newSetting=" + newUsageSetting); - } - } else { - if (DBG) { - logd("UsageSetting unchanged," - + " oldSetting=" + currentSubInfo.getUsageSetting() - + " preferredSetting=" + preferredUsageSetting - + " newSetting=" + newUsageSetting); - } - } - - if (cv.size() > 0 && sContext.getContentResolver().update(SubscriptionManager - .getUriForSubscriptionId(currentSubId), cv, null, null) > 0) { - mSubscriptionController.refreshCachedActiveSubscriptionInfoList(); - mSubscriptionController.notifySubscriptionInfoChanged(); - MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUuid); - } - } - - private static int findSubscriptionInfoForIccid(List list, String iccid) { - for (int i = 0; i < list.size(); i++) { - if (TextUtils.equals(iccid, list.get(i).getIccId())) { - return i; - } - } - return -1; - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - protected void broadcastSimStateChanged(int phoneId, String state, String reason) { - // Note: This intent is way deprecated and is only being kept around because there's no - // graceful way to deprecate a sticky broadcast that has a lot of listeners. - // DO NOT add any new extras to this broadcast -- it is not protected by any permissions. - Intent i = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - i.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); - i.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state); - i.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); - SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId); - logd("Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " + reason + - " for phone: " + phoneId); - IntentBroadcaster.getInstance().broadcastStickyIntent(sContext, i, phoneId); - } - - protected void broadcastSimCardStateChanged(int phoneId, int state) { - if (state != sSimCardState[phoneId]) { - sSimCardState[phoneId] = state; - Intent i = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); - i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); - SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId); - // TODO(b/130664115) we manually populate this intent with the slotId. In the future we - // should do a review of whether to make this public - UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); - int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); - i.putExtra(PhoneConstants.SLOT_KEY, slotId); - if (slot != null) { - i.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); - } - logd("Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " - + TelephonyManager.simStateToString(state) + " for phone: " + phoneId - + " slot: " + slotId + " port: " + slot.getPortIndexFromPhoneId(phoneId)); - sContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - TelephonyMetrics.getInstance().updateSimState(phoneId, state); - } - } - - protected void broadcastSimApplicationStateChanged(int phoneId, int state) { - // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY, - // because that's the initial state and a broadcast should be sent only on a transition - // after SIM is PRESENT. The only exception is eSIM boot profile, where NOT_READY is the - // terminal state. - boolean isUnknownToNotReady = - (sSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN - && state == TelephonyManager.SIM_STATE_NOT_READY); - IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard(); - boolean emptyProfile = iccCard != null && iccCard.isEmptyProfile(); - if (state != sSimApplicationState[phoneId] && (!isUnknownToNotReady || emptyProfile)) { - sSimApplicationState[phoneId] = state; - Intent i = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); - i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); - SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId); - // TODO(b/130664115) we populate this intent with the actual slotId. In the future we - // should do a review of whether to make this public - UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId); - int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); - i.putExtra(PhoneConstants.SLOT_KEY, slotId); - if (slot != null) { - i.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId)); - } - logd("Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " - + TelephonyManager.simStateToString(state) + " for phone: " + phoneId - + " slot: " + slotId + "port: " + slot.getPortIndexFromPhoneId(phoneId)); - sContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - TelephonyMetrics.getInstance().updateSimState(phoneId, state); - } - } - - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private static void logd(String message) { - Rlog.d(LOG_TAG, message); - } - - private static void loge(String message) { - Rlog.e(LOG_TAG, message); - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("SubscriptionInfoUpdater:"); - mCarrierServiceBindHelper.dump(fd, pw, args); - } -} diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java index d74b2b9f88..f7f24a27ec 100644 --- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java +++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java @@ -434,10 +434,6 @@ public class TelephonyComponentFactory { telephonyComponentFactory); } - public SubscriptionController initSubscriptionController(Context c) { - return SubscriptionController.init(c); - } - public PhoneSwitcher makePhoneSwitcher(int maxDataAttachModemCount, Context context, Looper looper) { return PhoneSwitcher.make(maxDataAttachModemCount, context, looper); @@ -450,9 +446,14 @@ public class TelephonyComponentFactory { return new DisplayInfoController(phone); } - public MultiSimSettingController initMultiSimSettingController(Context c, - SubscriptionController sc) { - return MultiSimSettingController.init(c, sc); + /** + * Initialize multi sim settings controller. + * + * @param c The context. + * @return The multi sim settings controller instance. + */ + public MultiSimSettingController initMultiSimSettingController(Context c) { + return MultiSimSettingController.init(c); } /** @@ -462,11 +463,6 @@ public class TelephonyComponentFactory { return new SignalStrengthController(phone); } - public SubscriptionInfoUpdater makeSubscriptionInfoUpdater(Looper looper, Context context, - SubscriptionController sc) { - return new SubscriptionInfoUpdater(looper, context, sc); - } - /** * Create a new LinkBandwidthEstimator. */ diff --git a/src/java/com/android/internal/telephony/UiccPhoneBookController.java b/src/java/com/android/internal/telephony/UiccPhoneBookController.java index 8b8457c2b8..96fd20842d 100644 --- a/src/java/com/android/internal/telephony/UiccPhoneBookController.java +++ b/src/java/com/android/internal/telephony/UiccPhoneBookController.java @@ -147,12 +147,7 @@ public class UiccPhoneBookController extends IIccPhoneBook.Stub { private IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(int subId) { - int phoneId; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - phoneId = SubscriptionManagerService.getInstance().getPhoneId(subId); - } else { - phoneId = SubscriptionController.getInstance().getPhoneId(subId); - } + int phoneId = SubscriptionManagerService.getInstance().getPhoneId(subId); try { return PhoneFactory.getPhone(phoneId).getIccPhoneBookInterfaceManager(); } catch (NullPointerException e) { diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java index c56bbef365..fa2b19b9d2 100644 --- a/src/java/com/android/internal/telephony/cat/CatService.java +++ b/src/java/com/android/internal/telephony/cat/CatService.java @@ -47,10 +47,8 @@ import android.telephony.TelephonyManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ProxyController; import com.android.internal.telephony.SmsController; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.IccFileHandler; @@ -966,16 +964,9 @@ public class CatService extends Handler implements AppInterface { //TODO Need to take care for MSIM public static AppInterface getInstance() { int slotId = PhoneConstants.DEFAULT_SLOT_INDEX; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - if (SubscriptionManagerService.getInstance() != null) { - slotId = SubscriptionManagerService.getInstance().getSlotIndex( - SubscriptionManagerService.getInstance().getDefaultSubId()); - } - } else { - SubscriptionController sControl = SubscriptionController.getInstance(); - if (sControl != null) { - slotId = sControl.getSlotIndex(sControl.getDefaultSubId()); - } + if (SubscriptionManagerService.getInstance() != null) { + slotId = SubscriptionManagerService.getInstance().getSlotIndex( + SubscriptionManagerService.getInstance().getDefaultSubId()); } return getInstance(null, null, null, slotId); } diff --git a/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java b/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java index aa830aeea4..c1d1203300 100644 --- a/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java +++ b/src/java/com/android/internal/telephony/data/CellularNetworkValidator.java @@ -40,7 +40,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConfigurationManager; import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; @@ -166,17 +165,9 @@ public class CellularNetworkValidator { private String getValidationNetworkIdentity(int subId) { if (!SubscriptionManager.isUsableSubscriptionId(subId)) return null; - Phone phone; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - if (SubscriptionManagerService.getInstance() == null) return null; - phone = PhoneFactory.getPhone(SubscriptionManagerService.getInstance() - .getPhoneId(subId)); - } else { - SubscriptionController subController = SubscriptionController.getInstance(); - if (subController == null) return null; - phone = PhoneFactory.getPhone(subController.getPhoneId(subId)); - } - + if (SubscriptionManagerService.getInstance() == null) return null; + Phone phone = PhoneFactory.getPhone(SubscriptionManagerService.getInstance() + .getPhoneId(subId)); if (phone == null || phone.getServiceState() == null) return null; NetworkRegistrationInfo regInfo = phone.getServiceState().getNetworkRegistrationInfo( @@ -267,20 +258,12 @@ public class CellularNetworkValidator { // If it's already validating the same subscription, do nothing. if (subId == mSubId) return; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfoInternal(subId); - if (subInfo == null || !subInfo.isActive()) { - logd("Failed to start validation. Inactive subId " + subId); - callback.onValidationDone(false, subId); - return; - } - } else { - if (!SubscriptionController.getInstance().isActiveSubId(subId)) { - logd("Failed to start validation. Inactive subId " + subId); - callback.onValidationDone(false, subId); - return; - } + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(subId); + if (subInfo == null || !subInfo.isActive()) { + logd("Failed to start validation. Inactive subId " + subId); + callback.onValidationDone(false, subId); + return; } if (isValidating()) { diff --git a/src/java/com/android/internal/telephony/data/DataSettingsManager.java b/src/java/com/android/internal/telephony/data/DataSettingsManager.java index 96ec81910c..5178ae4831 100644 --- a/src/java/com/android/internal/telephony/data/DataSettingsManager.java +++ b/src/java/com/android/internal/telephony/data/DataSettingsManager.java @@ -28,7 +28,6 @@ import android.preference.PreferenceManager; import android.provider.Settings; import android.sysprop.TelephonyProperties; import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; import android.telephony.TelephonyManager.MobileDataPolicy; @@ -46,7 +45,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.SettingsObserver; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback; import com.android.internal.telephony.metrics.DeviceTelephonyPropertiesStats; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; @@ -397,16 +395,10 @@ public class DataSettingsManager extends Handler { } private boolean isStandAloneOpportunistic(int subId) { - if (mPhone.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfoInternal(subId); - return subInfo != null && subInfo.isOpportunistic() - && TextUtils.isEmpty(subInfo.getGroupUuid()); - } - SubscriptionInfo info = SubscriptionController.getInstance().getActiveSubscriptionInfo( - subId, mPhone.getContext().getOpPackageName(), - mPhone.getContext().getAttributionTag()); - return (info != null) && info.isOpportunistic() && info.getGroupUuid() == null; + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(subId); + return subInfo != null && subInfo.isOpportunistic() + && TextUtils.isEmpty(subInfo.getGroupUuid()); } /** @@ -585,16 +577,11 @@ public class DataSettingsManager extends Handler { /** Refresh the enabled mobile data policies from Telephony database */ private void refreshEnabledMobileDataPolicy() { - if (mPhone.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfoInternal(mSubId); - if (subInfo != null) { - mEnabledMobileDataPolicy = getMobileDataPolicyEnabled( - subInfo.getEnabledMobileDataPolicies()); - } - } else { - mEnabledMobileDataPolicy = getMobileDataPolicyEnabled(SubscriptionController - .getInstance().getEnabledMobileDataPolicies(mSubId)); + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(mSubId); + if (subInfo != null) { + mEnabledMobileDataPolicy = getMobileDataPolicyEnabled( + subInfo.getEnabledMobileDataPolicies()); } } @@ -635,24 +622,12 @@ public class DataSettingsManager extends Handler { String enabledMobileDataPolicies = mEnabledMobileDataPolicy.stream().map(String::valueOf) .collect(Collectors.joining(",")); - if (mPhone.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().setEnabledMobileDataPolicies(mSubId, - enabledMobileDataPolicies); - logl(TelephonyUtils.mobileDataPolicyToString(mobileDataPolicy) + " changed to " - + enable); - updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_OVERRIDE); - notifyDataEnabledOverrideChanged(enable, mobileDataPolicy); - } else { - if (SubscriptionController.getInstance().setEnabledMobileDataPolicies( - mSubId, enabledMobileDataPolicies)) { - logl(TelephonyUtils.mobileDataPolicyToString(mobileDataPolicy) + " changed to " - + enable); - updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_OVERRIDE); - notifyDataEnabledOverrideChanged(enable, mobileDataPolicy); - } else { - loge("onSetMobileDataPolicy: failed to set " + enabledMobileDataPolicies); - } - } + SubscriptionManagerService.getInstance().setEnabledMobileDataPolicies(mSubId, + enabledMobileDataPolicies); + logl(TelephonyUtils.mobileDataPolicyToString(mobileDataPolicy) + " changed to " + + enable); + updateDataEnabledAndNotify(TelephonyManager.DATA_ENABLED_REASON_OVERRIDE); + notifyDataEnabledOverrideChanged(enable, mobileDataPolicy); } /** @@ -745,14 +720,8 @@ public class DataSettingsManager extends Handler { overridden = apnType == ApnSetting.TYPE_MMS; } - boolean isNonDds; - if (mPhone.isSubscriptionManagerServiceEnabled()) { - isNonDds = mPhone.getSubId() != SubscriptionManagerService.getInstance() - .getDefaultDataSubId(); - } else { - isNonDds = mPhone.getSubId() != SubscriptionController.getInstance() - .getDefaultDataSubId(); - } + boolean isNonDds = mPhone.getSubId() != SubscriptionManagerService.getInstance() + .getDefaultDataSubId(); // mobile data policy : data during call if (isMobileDataPolicyEnabled(TelephonyManager @@ -762,17 +731,10 @@ public class DataSettingsManager extends Handler { // mobile data policy : auto data switch if (isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)) { - Phone defaultDataPhone; - if (mPhone.isSubscriptionManagerServiceEnabled()) { - // check user enabled data on the default data phone - defaultDataPhone = PhoneFactory.getPhone(SubscriptionManagerService.getInstance() - .getPhoneId(SubscriptionManagerService.getInstance() - .getDefaultDataSubId())); - } else { - // check user enabled data on the default data phone - defaultDataPhone = PhoneFactory.getPhone(SubscriptionController.getInstance() - .getPhoneId(SubscriptionController.getInstance().getDefaultDataSubId())); - } + // check user enabled data on the default data phone + Phone defaultDataPhone = PhoneFactory.getPhone(SubscriptionManagerService.getInstance() + .getPhoneId(SubscriptionManagerService.getInstance() + .getDefaultDataSubId())); if (defaultDataPhone == null) { loge("isDataEnabledOverriddenForApn: unexpected defaultDataPhone is null"); } else { diff --git a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java index c51f09f1d4..5e13f6b74e 100644 --- a/src/java/com/android/internal/telephony/data/PhoneSwitcher.java +++ b/src/java/com/android/internal/telephony/data/PhoneSwitcher.java @@ -86,8 +86,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConfigurationManager; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RadioConfig; -import com.android.internal.telephony.SubscriptionController; -import com.android.internal.telephony.SubscriptionController.WatchedInt; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; @@ -97,6 +95,7 @@ import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwi import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; +import com.android.internal.telephony.subscription.SubscriptionManagerService.WatchedInt; import com.android.internal.telephony.util.NotificationChannelController; import com.android.internal.util.IndentingPrintWriter; import com.android.telephony.Rlog; @@ -206,7 +205,6 @@ public class PhoneSwitcher extends Handler { private final @NonNull NetworkRequestList mNetworkRequestList = new NetworkRequestList(); protected final RegistrantList mActivePhoneRegistrants; - protected final SubscriptionController mSubscriptionController; private final SubscriptionManagerService mSubscriptionManagerService; protected final Context mContext; private final LocalLog mLocalLog; @@ -276,14 +274,8 @@ public class PhoneSwitcher extends Handler { protected int mPreferredDataPhoneId = SubscriptionManager.INVALID_PHONE_INDEX; // Subscription ID corresponds to mPreferredDataPhoneId. - protected WatchedInt mPreferredDataSubId = - new WatchedInt(SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - @Override - public void set(int newValue) { - super.set(newValue); - SubscriptionManager.invalidateActiveDataSubIdCaches(); - } - }; + protected WatchedInt mPreferredDataSubId = new WatchedInt( + SubscriptionManager.INVALID_SUBSCRIPTION_ID); // If non-null, An emergency call is about to be started, is ongoing, or has just ended and we // are overriding the DDS. @@ -459,7 +451,6 @@ public class PhoneSwitcher extends Handler { public static PhoneSwitcher make(int maxDataAttachModemCount, Context context, Looper looper) { if (sPhoneSwitcher == null) { sPhoneSwitcher = new PhoneSwitcher(maxDataAttachModemCount, context, looper); - SubscriptionManager.invalidateActiveDataSubIdCaches(); } return sPhoneSwitcher; @@ -526,13 +517,7 @@ public class PhoneSwitcher extends Handler { mMaxDataAttachModemCount = maxActivePhones; mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService = SubscriptionManagerService.getInstance(); - mSubscriptionController = null; - } else { - mSubscriptionController = SubscriptionController.getInstance(); - mSubscriptionManagerService = null; - } + mSubscriptionManagerService = SubscriptionManagerService.getInstance(); mRadioConfig = RadioConfig.getInstance(); mValidator = CellularNetworkValidator.getInstance(); @@ -660,16 +645,9 @@ public class PhoneSwitcher extends Handler { return false; } - SubscriptionInfo info; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - info = mSubscriptionManagerService - .getActiveSubscriptionInfoForSimSlotIndex(slotIndex, - mContext.getOpPackageName(), mContext.getAttributionTag()); - } else { - info = mSubscriptionController - .getActiveSubscriptionInfoForSimSlotIndex(slotIndex, - mContext.getOpPackageName(), null); - } + SubscriptionInfo info = mSubscriptionManagerService + .getActiveSubscriptionInfoForSimSlotIndex(slotIndex, + mContext.getOpPackageName(), mContext.getAttributionTag()); boolean uiccAppsEnabled = info != null && info.areUiccApplicationsEnabled(); IccCard iccCard = PhoneFactory.getPhone(slotIndex).getIccCard(); @@ -1119,16 +1097,9 @@ public class PhoneSwitcher extends Handler { // auto data switch feature is disabled from server if (mAutoDataSwitchAvailabilityStabilityTimeThreshold < 0) return; // check is valid DSDS - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - if (!isActiveSubId(mPrimaryDataSubId) || mSubscriptionManagerService - .getActiveSubIdList(true).length <= 1) { - return; - } - } else { - if (!isActiveSubId(mPrimaryDataSubId) - || mSubscriptionController.getActiveSubIdList(true).length <= 1) { - return; - } + if (!isActiveSubId(mPrimaryDataSubId) || mSubscriptionManagerService + .getActiveSubIdList(true).length <= 1) { + return; } Phone primaryDataPhone = getPhoneBySubId(mPrimaryDataSubId); @@ -1308,12 +1279,7 @@ public class PhoneSwitcher extends Handler { boolean diffDetected = mHalCommandToUse != HAL_COMMAND_PREFERRED_DATA && requestsChanged; // Check if user setting of default non-opportunistic data sub is changed. - int primaryDataSubId; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - primaryDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); - } else { - primaryDataSubId = mSubscriptionController.getDefaultDataSubId(); - } + int primaryDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); if (primaryDataSubId != mPrimaryDataSubId) { sb.append(" mPrimaryDataSubId ").append(mPrimaryDataSubId).append("->") .append(primaryDataSubId); @@ -1588,13 +1554,9 @@ public class PhoneSwitcher extends Handler { } private boolean isActiveSubId(int subId) { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = mSubscriptionManagerService - .getSubscriptionInfoInternal(subId); - return subInfo != null && subInfo.isActive(); - } else { - return mSubscriptionController.isActiveSubId(subId); - } + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + return subInfo != null && subInfo.isActive(); } // This updates mPreferredDataPhoneId which decides which phone should handle default network @@ -1677,11 +1639,7 @@ public class PhoneSwitcher extends Handler { } private Phone getPhoneBySubId(int subId) { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - return findPhoneById(mSubscriptionManagerService.getPhoneId(subId)); - } else { - return findPhoneById(mSubscriptionController.getPhoneId(subId)); - } + return findPhoneById(mSubscriptionManagerService.getPhoneId(subId)); } private Phone findPhoneById(final int phoneId) { @@ -2112,15 +2070,9 @@ public class PhoneSwitcher extends Handler { } pw.println("mPreferredDataPhoneId=" + mPreferredDataPhoneId); pw.println("mPreferredDataSubId=" + mPreferredDataSubId.get()); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - pw.println("DefaultDataSubId=" + mSubscriptionManagerService.getDefaultDataSubId()); - pw.println("DefaultDataPhoneId=" + mSubscriptionManagerService.getPhoneId( - mSubscriptionManagerService.getDefaultDataSubId())); - } else { - pw.println("DefaultDataSubId=" + mSubscriptionController.getDefaultDataSubId()); - pw.println("DefaultDataPhoneId=" + mSubscriptionController.getPhoneId( - mSubscriptionController.getDefaultDataSubId())); - } + pw.println("DefaultDataSubId=" + mSubscriptionManagerService.getDefaultDataSubId()); + pw.println("DefaultDataPhoneId=" + mSubscriptionManagerService.getPhoneId( + mSubscriptionManagerService.getDefaultDataSubId())); pw.println("mPrimaryDataSubId=" + mPrimaryDataSubId); pw.println("mAutoSelectedDataSubId=" + mAutoSelectedDataSubId); pw.println("mIsRegisteredForImsRadioTechChange=" + mIsRegisteredForImsRadioTechChange); @@ -2207,12 +2159,8 @@ public class PhoneSwitcher extends Handler { + switchReasonToString(mLastSwitchPreferredDataReason)); return; } - SubscriptionInfo subInfo; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - subInfo = mSubscriptionManagerService.getSubscriptionInfo(mAutoSelectedDataSubId); - } else { - subInfo = mSubscriptionController.getSubscriptionInfo(mAutoSelectedDataSubId); - } + SubscriptionInfo subInfo = mSubscriptionManagerService + .getSubscriptionInfo(mAutoSelectedDataSubId); if (subInfo == null || subInfo.isOpportunistic()) { loge("displayAutoDataSwitchNotification: mAutoSelectedDataSubId=" + mAutoSelectedDataSubId + " unexpected subInfo " + subInfo); @@ -2251,14 +2199,8 @@ public class PhoneSwitcher extends Handler { } private boolean isPhoneIdValidForRetry(int phoneId) { - int ddsPhoneId; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - ddsPhoneId = mSubscriptionManagerService.getPhoneId( - mSubscriptionManagerService.getDefaultDataSubId()); - } else { - ddsPhoneId = mSubscriptionController.getPhoneId( - mSubscriptionController.getDefaultDataSubId()); - } + int ddsPhoneId = mSubscriptionManagerService.getPhoneId( + mSubscriptionManagerService.getDefaultDataSubId()); if (ddsPhoneId != INVALID_PHONE_INDEX && ddsPhoneId == phoneId) { return true; } else { diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index 831278e4d4..a83569b275 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -48,7 +48,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.metrics.EmergencyNumberStats; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.nano.PersistAtomsProto; @@ -290,12 +289,7 @@ public class EmergencyNumberTracker extends Handler { @VisibleForTesting public boolean isSimAbsent() { for (Phone phone: PhoneFactory.getPhones()) { - int slotId; - if (phone.isSubscriptionManagerServiceEnabled()) { - slotId = SubscriptionManagerService.getInstance().getSlotIndex(phone.getSubId()); - } else { - slotId = SubscriptionController.getInstance().getSlotIndex(phone.getSubId()); - } + int slotId = SubscriptionManagerService.getInstance().getSlotIndex(phone.getSubId()); // If slot id is invalid, it means that there is no sim card. if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { // If there is at least one sim active, sim is not absent; it returns false diff --git a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java index a63ae1d996..2f73c916c6 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java @@ -39,8 +39,6 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccController; @@ -652,14 +650,8 @@ public class EuiccCardController extends IEuiccCardController.Stub { @Override public void onResult(Void result) { Log.i(TAG, "Request subscription info list refresh after delete."); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( - List.of(mUiccController.convertToPublicCardId(cardId)), null); - } else { - SubscriptionController.getInstance() - .requestEmbeddedSubscriptionInfoListRefresh( - mUiccController.convertToPublicCardId(cardId)); - } + SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( + List.of(mUiccController.convertToPublicCardId(cardId)), null); try { callback.onComplete(EuiccCardManager.RESULT_OK); } catch (RemoteException exception) { @@ -709,14 +701,8 @@ public class EuiccCardController extends IEuiccCardController.Stub { @Override public void onResult(Void result) { Log.i(TAG, "Request subscription info list refresh after reset memory."); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( - List.of(mUiccController.convertToPublicCardId(cardId)), null); - } else { - SubscriptionController.getInstance() - .requestEmbeddedSubscriptionInfoListRefresh( - mUiccController.convertToPublicCardId(cardId)); - } + SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( + List.of(mUiccController.convertToPublicCardId(cardId)), null); try { callback.onComplete(EuiccCardManager.RESULT_OK); } catch (RemoteException exception) { @@ -1203,14 +1189,8 @@ public class EuiccCardController extends IEuiccCardController.Stub { @Override public void onResult(byte[] result) { Log.i(TAG, "Request subscription info list refresh after install."); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( - List.of(mUiccController.convertToPublicCardId(cardId)), null); - } else { - SubscriptionController.getInstance() - .requestEmbeddedSubscriptionInfoListRefresh( - mUiccController.convertToPublicCardId(cardId)); - } + SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( + List.of(mUiccController.convertToPublicCardId(cardId)), null); try { callback.onComplete(EuiccCardManager.RESULT_OK, result); } catch (RemoteException exception) { diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java index 67cb981ece..a5b95c35bf 100644 --- a/src/java/com/android/internal/telephony/euicc/EuiccController.java +++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java @@ -59,7 +59,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CarrierPrivilegesTracker; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.IccUtils; @@ -1592,15 +1591,9 @@ public class EuiccController extends IEuiccController.Stub { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public void refreshSubscriptionsAndSendResult( PendingIntent callbackIntent, int resultCode, Intent extrasIntent) { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( - List.of(mTelephonyManager.getCardIdForDefaultEuicc()), - () -> sendResult(callbackIntent, resultCode, extrasIntent)); - } else { - SubscriptionController.getInstance() - .requestEmbeddedSubscriptionInfoListRefresh( - () -> sendResult(callbackIntent, resultCode, extrasIntent)); - } + SubscriptionManagerService.getInstance().updateEmbeddedSubscriptions( + List.of(mTelephonyManager.getCardIdForDefaultEuicc()), + () -> sendResult(callbackIntent, resultCode, extrasIntent)); } /** Dispatch the given callback intent with the given result code and data. */ diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index e454fa33cc..d5ba0f2c7a 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -16,7 +16,6 @@ package com.android.internal.telephony.imsphone; -import static android.provider.Telephony.SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS; import static android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE; import static android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_TITLE; import static android.telephony.ims.RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED; @@ -78,7 +77,6 @@ import android.telephony.CarrierConfigManager; import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; -import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.UssdResponse; @@ -117,7 +115,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneNotifier; import com.android.internal.telephony.ServiceStateTracker; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyComponentFactory; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.domainselection.DomainSelectionResolver; @@ -2548,44 +2545,24 @@ public class ImsPhone extends ImsPhoneBase { int subId = getSubId(); if (!SubscriptionManager.isValidSubscriptionId(subId)) { // Defending b/219080264: - // SubscriptionController.setSubscriptionProperty validates input subId + // SubscriptionManagerService.setSubscriptionProperty validates input subId // so do not proceed if subId invalid. This may be happening because cached // IMS callbacks are sent back to telephony after SIM state changed. return; } - if (isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = mSubscriptionManagerService - .getSubscriptionInfoInternal(subId); - if (subInfo != null) { - phoneNumber = PhoneNumberUtils.formatNumberToE164(phoneNumber, - subInfo.getCountryIso()); - if (phoneNumber == null) { - return; - } - mSubscriptionManagerService.setNumberFromIms(subId, phoneNumber); - } - } else { - SubscriptionController subController = SubscriptionController.getInstance(); - String countryIso = getCountryIso(subController, subId); - // Format the number as one more defense to reject garbage values: - // phoneNumber will become null. - phoneNumber = PhoneNumberUtils.formatNumberToE164(phoneNumber, countryIso); + SubscriptionInfoInternal subInfo = mSubscriptionManagerService + .getSubscriptionInfoInternal(subId); + if (subInfo != null) { + phoneNumber = PhoneNumberUtils.formatNumberToE164(phoneNumber, + subInfo.getCountryIso()); if (phoneNumber == null) { return; } - subController.setSubscriptionProperty(subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, - phoneNumber); + mSubscriptionManagerService.setNumberFromIms(subId, phoneNumber); } } - private static String getCountryIso(SubscriptionController subController, int subId) { - SubscriptionInfo info = subController.getSubscriptionInfo(subId); - String countryIso = info == null ? "" : info.getCountryIso(); - // info.getCountryIso() may return null - return countryIso == null ? "" : countryIso; - } - /** * Finds the phone number from associated URIs. * diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 688fa62318..076464296c 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -143,7 +143,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.SrvccConnection; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.d2d.RtpTransport; import com.android.internal.telephony.data.DataSettingsManager; import com.android.internal.telephony.domainselection.DomainSelectionResolver; @@ -1857,20 +1856,12 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // Check for changes due to carrier config. maybeConfigureRtpHeaderExtensions(); - if (mPhone.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfoInternal(subId); - if (subInfo == null || !subInfo.isActive()) { - loge("updateCarrierConfiguration: skipping notification to ImsService, non" - + "active subId = " + subId); - return; - } - } else { - if (!SubscriptionController.getInstance().isActiveSubId(subId)) { - loge("updateCarrierConfiguration: skipping notification to ImsService, non" - + "active subId = " + subId); - return; - } + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(subId); + if (subInfo == null || !subInfo.isActive()) { + loge("updateCarrierConfiguration: skipping notification to ImsService, non" + + "active subId = " + subId); + return; } Phone defaultPhone = getPhone().getDefaultPhone(); diff --git a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java index 21ec32ed9b..cfa16d0591 100644 --- a/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataCallSessionStats.java @@ -37,7 +37,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.data.DataNetwork; import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; @@ -243,14 +242,8 @@ public class DataCallSessionStats { mDataCallSession.oosAtEnd = getIsOos(); mDataCallSession.ongoing = false; // set if this data call is established for internet on the non-Dds - SubscriptionInfo subInfo; - if (mPhone.isSubscriptionManagerServiceEnabled()) { - subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfo(mPhone.getSubId()); - } else { - subInfo = SubscriptionController.getInstance() - .getSubscriptionInfo(mPhone.getSubId()); - } + SubscriptionInfo subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfo(mPhone.getSubId()); if (mPhone.getSubId() != SubscriptionManager.getDefaultDataSubscriptionId() && ((mDataCallSession.apnTypeBitmask & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) @@ -330,13 +323,9 @@ public class DataCallSessionStats { } private boolean getIsOpportunistic() { - if (mPhone.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfoInternal(mPhone.getSubId()); - return subInfo != null && subInfo.isOpportunistic(); - } - SubscriptionController subController = SubscriptionController.getInstance(); - return subController != null && subController.isOpportunistic(mPhone.getSubId()); + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(mPhone.getSubId()); + return subInfo != null && subInfo.isOpportunistic(); } private boolean getIsOos() { diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java index 9ad775f30e..2f22196f45 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -27,7 +27,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyStatsLog; import com.android.internal.telephony.data.DataStallRecoveryManager; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; @@ -147,12 +146,8 @@ public class DataStallRecoveryStats { } private static boolean getIsOpportunistic(Phone phone) { - if (phone.isSubscriptionManagerServiceEnabled()) { - SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfoInternal(phone.getSubId()); - return subInfo != null && subInfo.isOpportunistic(); - } - SubscriptionController subController = SubscriptionController.getInstance(); - return subController != null && subController.isOpportunistic(phone.getSubId()); + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(phone.getSubId()); + return subInfo != null && subInfo.isOpportunistic(); } } diff --git a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java index 0b5581515f..731ce66801 100644 --- a/src/java/com/android/internal/telephony/metrics/PerSimStatus.java +++ b/src/java/com/android/internal/telephony/metrics/PerSimStatus.java @@ -32,7 +32,6 @@ import android.annotation.Nullable; import android.database.Cursor; import android.net.Uri; import android.provider.Telephony; -import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; @@ -43,14 +42,11 @@ import android.text.TextUtils; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.telephony.uicc.UiccSlot; -import java.util.Optional; - /** Stores the per SIM status. */ public class PerSimStatus { private static final long BITMASK_2G = @@ -175,40 +171,21 @@ public class PerSimStatus { String countryIso = ""; String[] numbersFromAllSources; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - if (SubscriptionManagerService.getInstance() == null) return null; - SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfoInternal(phone.getSubId()); - if (subInfo != null) { - countryIso = subInfo.getCountryIso(); - } - numbersFromAllSources = new String[]{ - SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), - SubscriptionManager.PHONE_NUMBER_SOURCE_UICC, null, null), - SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), - SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, null, null), - SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), - SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, null, null) - }; - } else { - SubscriptionController subscriptionController = SubscriptionController.getInstance(); - if (subscriptionController == null) { - return null; - } - int subId = phone.getSubId(); - countryIso = Optional.ofNullable(subscriptionController.getSubscriptionInfo(subId)) - .map(SubscriptionInfo::getCountryIso) - .orElse(""); - // numbersFromAllSources[] - phone numbers from each sources: - numbersFromAllSources = new String[]{ - subscriptionController.getPhoneNumber(subId, - SubscriptionManager.PHONE_NUMBER_SOURCE_UICC, null, null), // 0 - subscriptionController.getPhoneNumber(subId, - SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, null, null), // 1 - subscriptionController.getPhoneNumber(subId, - SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, null, null), // 2 - }; + if (SubscriptionManagerService.getInstance() == null) return null; + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(phone.getSubId()); + if (subInfo != null) { + countryIso = subInfo.getCountryIso(); } + numbersFromAllSources = new String[]{ + SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), + SubscriptionManager.PHONE_NUMBER_SOURCE_UICC, null, null), + SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), + SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER, null, null), + SubscriptionManagerService.getInstance().getPhoneNumber(phone.getSubId(), + SubscriptionManager.PHONE_NUMBER_SOURCE_IMS, null, null) + }; + int[] numberIds = new int[numbersFromAllSources.length]; // default value 0 for (int i = 0, idForNextUniqueNumber = 1; i < numberIds.length; i++) { if (TextUtils.isEmpty(numbersFromAllSources[i])) { diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java index e5e0620405..f11ca661de 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java @@ -36,7 +36,6 @@ import com.android.internal.telephony.CommandException; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RILUtils; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.subscription.SubscriptionManagerService; import java.util.Arrays; @@ -254,14 +253,8 @@ public class SatelliteServiceUtils { public static int getValidSatelliteSubId(int subId, @NonNull Context context) { final long identity = Binder.clearCallingIdentity(); try { - boolean isActive; - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId, - context.getOpPackageName(), context.getAttributionTag()); - } else { - isActive = SubscriptionController.getInstance().isActiveSubId(subId, - context.getOpPackageName(), context.getAttributionTag()); - } + boolean isActive = SubscriptionManagerService.getInstance().isActiveSubId(subId, + context.getOpPackageName(), context.getAttributionTag()); if (isActive) { return subId; diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java index 38c2b1fb00..b90dc5edf5 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionDatabaseManager.java @@ -91,7 +91,6 @@ public class SubscriptionDatabaseManager extends Handler { /** The mapping from {@link SimInfo} table to {@link SubscriptionInfoInternal} get methods. */ private static final Map> - // TODO: Support SimInfo.COLUMN_CB_XXX which are still used by wear. SUBSCRIPTION_GET_METHOD_MAP = Map.ofEntries( new AbstractMap.SimpleImmutableEntry<>( SimInfo.COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID, diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 752d4b6e72..f2876526e4 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -90,7 +90,6 @@ import com.android.internal.telephony.MultiSimSettingController; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyPermissions; import com.android.internal.telephony.data.PhoneSwitcher; @@ -562,7 +561,6 @@ public class SubscriptionManagerService extends ISub.Stub { }); SubscriptionManager.invalidateSubscriptionManagerServiceCaches(); - SubscriptionManager.invalidateSubscriptionManagerServiceEnabledCaches(); mContext.registerReceiver(new BroadcastReceiver() { @Override @@ -1975,7 +1973,6 @@ public class SubscriptionManagerService extends ISub.Stub { * @see SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh */ @Override - // TODO: Remove this after SubscriptionController is removed. public void requestEmbeddedSubscriptionInfoListRefresh(int cardId) { updateEmbeddedSubscriptions(List.of(cardId), null); } @@ -2044,15 +2041,14 @@ public class SubscriptionManagerService extends ISub.Stub { * subscription type. * @param subscriptionType the type of subscription to be removed. * - * // TODO: Remove this terrible return value once SubscriptionController is removed. - * @return 0 if success, < 0 on error. + * @return {@code true} if succeeded, otherwise {@code false}. * * @throws NullPointerException if {@code uniqueId} is {@code null}. * @throws SecurityException if callers do not hold the required permission. */ @Override @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) - public int removeSubInfo(@NonNull String uniqueId, int subscriptionType) { + public boolean removeSubInfo(@NonNull String uniqueId, int subscriptionType) { enforcePermissions("removeSubInfo", Manifest.permission.MODIFY_PHONE_STATE); logl("removeSubInfo: uniqueId=" + SubscriptionInfo.getPrintableId(uniqueId) + ", " @@ -2064,15 +2060,15 @@ public class SubscriptionManagerService extends ISub.Stub { .getSubscriptionInfoInternalByIccId(uniqueId); if (subInfo == null) { loge("Cannot find subscription with uniqueId " + uniqueId); - return -1; + return false; } if (subInfo.getSubscriptionType() != subscriptionType) { loge("The subscription type does not match."); - return -1; + return false; } mSlotIndexToSubId.remove(subInfo.getSimSlotIndex()); mSubscriptionDatabaseManager.removeSubscriptionInfo(subInfo.getSubscriptionId()); - return 0; + return true; } finally { Binder.restoreCallingIdentity(identity); } @@ -2959,9 +2955,6 @@ public class SubscriptionManagerService extends ISub.Stub { * @param columnName Column name in the database. Note not all fields are supported. * @param value Value to store in the database. * - * // TODO: Remove return value after SubscriptionController is deleted. - * @return always 1 - * * @throws IllegalArgumentException if {@code subscriptionId} is invalid, or the field is not * exposed. * @throws SecurityException if callers do not hold the required permission. @@ -2971,7 +2964,7 @@ public class SubscriptionManagerService extends ISub.Stub { */ @Override @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) - public int setSubscriptionProperty(int subId, @NonNull String columnName, + public void setSubscriptionProperty(int subId, @NonNull String columnName, @NonNull String value) { enforcePermissions("setSubscriptionProperty", Manifest.permission.MODIFY_PHONE_STATE); @@ -2992,7 +2985,6 @@ public class SubscriptionManagerService extends ISub.Stub { } mSubscriptionDatabaseManager.setSubscriptionProperty(subId, columnName, value); - return 1; } finally { Binder.restoreCallingIdentity(token); } @@ -3708,16 +3700,6 @@ public class SubscriptionManagerService extends ISub.Stub { } } - /** - * @return {@code true} if using {@link SubscriptionManagerService} instead of - * {@link SubscriptionController}. - */ - //TODO: Removed before U AOSP public release. - @Override - public boolean isSubscriptionManagerServiceEnabled() { - return true; - } - /** * Called during setup wizard restore flow to attempt to restore the backed up sim-specific * configs to device for all existing SIMs in the subscription database {@link SimInfo}. diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java index 48a4430118..2e490e3f84 100644 --- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java +++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java @@ -817,7 +817,6 @@ public class RuimRecords extends IccRecords { mLoaded.set(true); mRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); - // TODO: The below is hacky since the SubscriptionController may not be ready at this time. if (!TextUtils.isEmpty(mMdn)) { int phoneId = mParentApp.getUiccProfile().getPhoneId(); int subId = SubscriptionManager.getSubscriptionId(phoneId); diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index 9d31f02fb0..b0232670af 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -63,7 +63,6 @@ import com.android.internal.telephony.PhoneConfigurationManager; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RadioConfig; -import com.android.internal.telephony.SubscriptionInfoUpdater; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.subscription.SubscriptionManagerService; @@ -744,38 +743,6 @@ public class UiccController extends Handler { } } - static void updateInternalIccStateForInactivePort( - Context context, int prevActivePhoneId, String iccId) { - if (SubscriptionManager.isValidPhoneId(prevActivePhoneId)) { - // Mark SIM state as ABSENT on previously phoneId. - TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - telephonyManager.setSimStateForPhone(prevActivePhoneId, - IccCardConstants.State.ABSENT.toString()); - } - - SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); - if (subInfoUpdator != null) { - subInfoUpdator.updateInternalIccStateForInactivePort(prevActivePhoneId, iccId); - } else { - Rlog.e(LOG_TAG, "subInfoUpdate is null."); - } - } - - static void updateInternalIccState(Context context, IccCardConstants.State state, String reason, - int phoneId) { - TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - telephonyManager.setSimStateForPhone(phoneId, state.toString()); - - SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater(); - if (subInfoUpdator != null) { - subInfoUpdator.updateInternalIccState(getIccStateIntentString(state), reason, phoneId); - } else { - Rlog.e(LOG_TAG, "subInfoUpdate is null."); - } - } - /** * Update SIM state for the inactive eSIM port. * diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index debdaabc7f..83db022f98 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -63,7 +63,6 @@ import com.android.internal.telephony.MccTable; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyStatsLog; import com.android.internal.telephony.cat.CatService; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; @@ -545,25 +544,15 @@ public class UiccProfile extends IccCard { if (!TextUtils.isEmpty(iso) && !iso.equals(TelephonyManager.getSimCountryIsoForPhone(mPhoneId))) { mTelephonyManager.setSimCountryIsoForPhone(mPhoneId, iso); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().setCountryIso(subId, iso); - } else { - SubscriptionController.getInstance().setCountryIso(iso, subId); - } + SubscriptionManagerService.getInstance().setCountryIso(subId, iso); } } private void updateCarrierNameForSubscription(int subId, int nameSource) { /* update display name with carrier override */ - SubscriptionInfo subInfo; - - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - subInfo = SubscriptionManagerService.getInstance().getActiveSubscriptionInfo(subId, - mContext.getOpPackageName(), mContext.getAttributionTag()); - } else { - subInfo = SubscriptionController.getInstance().getActiveSubscriptionInfo( - subId, mContext.getOpPackageName(), mContext.getAttributionTag()); - } + SubscriptionInfo subInfo = SubscriptionManagerService.getInstance() + .getActiveSubscriptionInfo(subId, mContext.getOpPackageName(), + mContext.getAttributionTag()); if (subInfo == null) { return; @@ -574,13 +563,8 @@ public class UiccProfile extends IccCard { if (!TextUtils.isEmpty(newCarrierName) && !newCarrierName.equals(oldSubName)) { log("sim name[" + mPhoneId + "] = " + newCarrierName); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - SubscriptionManagerService.getInstance().setDisplayNameUsingSrc( - newCarrierName, subId, nameSource); - } else { - SubscriptionController.getInstance().setDisplayNameUsingSrc( - newCarrierName, subId, nameSource); - } + SubscriptionManagerService.getInstance().setDisplayNameUsingSrc( + newCarrierName, subId, nameSource); } } @@ -837,13 +821,8 @@ public class UiccProfile extends IccCard { } log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState); - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - UiccController.getInstance().updateSimState(mPhoneId, mExternalState, - getIccStateReason(mExternalState)); - } else { - UiccController.updateInternalIccState(mContext, mExternalState, - getIccStateReason(mExternalState), mPhoneId); - } + UiccController.getInstance().updateSimState(mPhoneId, mExternalState, + getIccStateReason(mExternalState)); } } @@ -1747,35 +1726,27 @@ public class UiccProfile extends IccCard { return false; } - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - int subId = SubscriptionManager.getSubscriptionId(getPhoneId()); - SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() - .getSubscriptionInfoInternal(subId); - if (subInfo == null) { - loge("setOperatorBrandOverride: Cannot find subscription info for sub " + subId); - return false; - } + int subId = SubscriptionManager.getSubscriptionId(getPhoneId()); + SubscriptionInfoInternal subInfo = SubscriptionManagerService.getInstance() + .getSubscriptionInfoInternal(subId); + if (subInfo == null) { + loge("setOperatorBrandOverride: Cannot find subscription info for sub " + subId); + return false; + } - List subInfos = new ArrayList<>(); - subInfos.add(subInfo.toSubscriptionInfo()); - String groupUuid = subInfo.getGroupUuid(); - if (!TextUtils.isEmpty(groupUuid)) { - subInfos.addAll(SubscriptionManagerService.getInstance() - .getSubscriptionsInGroup(ParcelUuid.fromString(groupUuid), - mContext.getOpPackageName(), mContext.getFeatureId())); - } + List subInfos = new ArrayList<>(); + subInfos.add(subInfo.toSubscriptionInfo()); + String groupUuid = subInfo.getGroupUuid(); + if (!TextUtils.isEmpty(groupUuid)) { + subInfos.addAll(SubscriptionManagerService.getInstance() + .getSubscriptionsInGroup(ParcelUuid.fromString(groupUuid), + mContext.getOpPackageName(), mContext.getFeatureId())); + } - if (subInfos.stream().noneMatch(info -> TextUtils.equals(IccUtils.stripTrailingFs( - info.getIccId()), IccUtils.stripTrailingFs(iccId)))) { - loge("iccId doesn't match current active subId."); - return false; - } - } else { - if (!SubscriptionController.getInstance().checkPhoneIdAndIccIdMatch( - getPhoneId(), iccId)) { - loge("iccId doesn't match current active subId."); - return false; - } + if (subInfos.stream().noneMatch(info -> TextUtils.equals(IccUtils.stripTrailingFs( + info.getIccId()), IccUtils.stripTrailingFs(iccId)))) { + loge("iccId doesn't match current active subId."); + return false; } SharedPreferences.Editor spEditor = diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index 7f9936561e..fbf807c9b2 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -207,15 +207,9 @@ public class UiccSlot extends Handler { if (!iss.mSimPortInfos[i].mPortActive) { // TODO: (b/79432584) evaluate whether should broadcast card state change // even if it's inactive. - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - UiccController.getInstance().updateSimStateForInactivePort( - mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID), - iss.mSimPortInfos[i].mIccId); - } else { - UiccController.updateInternalIccStateForInactivePort(mContext, - mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID), - iss.mSimPortInfos[i].mIccId); - } + UiccController.getInstance().updateSimStateForInactivePort( + mPortIdxToPhoneId.getOrDefault(i, INVALID_PHONE_ID), + iss.mSimPortInfos[i].mIccId); mLastRadioState.put(i, TelephonyManager.RADIO_POWER_UNAVAILABLE); if (mUiccCard != null) { // Dispose the port @@ -364,13 +358,7 @@ public class UiccSlot extends Handler { sendMessage(obtainMessage(EVENT_CARD_REMOVED, null)); } - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - UiccController.getInstance().updateSimState(phoneId, IccCardConstants.State.ABSENT, - null); - } else { - UiccController.updateInternalIccState(mContext, IccCardConstants.State.ABSENT, - null, phoneId); - } + UiccController.getInstance().updateSimState(phoneId, IccCardConstants.State.ABSENT, null); // no card present in the slot now; dispose port and then card if needed. disposeUiccCardIfNeeded(false /* sim state is not unknown */, portIndex); // If SLOT_STATUS is the last event, wrong subscription is getting invalidate during @@ -646,13 +634,8 @@ public class UiccSlot extends Handler { disposeUiccCardIfNeeded(true /* sim state is unknown */, portIndex); if (phoneId != INVALID_PHONE_ID) { - if (PhoneFactory.isSubscriptionManagerServiceEnabled()) { - UiccController.getInstance().updateSimState(phoneId, - IccCardConstants.State.UNKNOWN, null); - } else { - UiccController.updateInternalIccState( - mContext, IccCardConstants.State.UNKNOWN, null, phoneId); - } + UiccController.getInstance().updateSimState(phoneId, + IccCardConstants.State.UNKNOWN, null); } mLastRadioState.put(portIndex, TelephonyManager.RADIO_POWER_UNAVAILABLE); // Reset CardState diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index a0c9cd375d..d970799d3a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -1092,8 +1092,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { getVoiceCallForwardingFlag(); // invalid subId - doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionController). - getSubId(anyInt()); doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID).when(mSubscriptionManagerService) .getSubId(anyInt()); assertEquals(false, mPhoneUT.getCallForwardingIndicator()); @@ -1101,7 +1099,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { // valid subId, sharedPreference not present int subId1 = 0; int subId2 = 1; - doReturn(subId1).when(mSubscriptionController).getSubId(anyInt()); doReturn(subId1).when(mSubscriptionManagerService).getSubId(anyInt()); assertEquals(false, mPhoneUT.getCallForwardingIndicator()); @@ -1124,7 +1121,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { assertEquals(true, mPhoneUT.getCallForwardingIndicator()); // check for another subId - doReturn(subId2).when(mSubscriptionController).getSubId(anyInt()); doReturn(subId2).when(mSubscriptionManagerService).getSubId(anyInt()); assertEquals(false, mPhoneUT.getCallForwardingIndicator()); @@ -1134,7 +1130,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { assertEquals(true, mPhoneUT.getCallForwardingIndicator()); // switching back to previous subId, stored value should still be available - doReturn(subId1).when(mSubscriptionController).getSubId(anyInt()); doReturn(subId1).when(mSubscriptionManagerService).getSubId(anyInt()); assertEquals(true, mPhoneUT.getCallForwardingIndicator()); @@ -1297,7 +1292,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { processAllMessages(); verify(mSubscriptionManagerService, never()).getAllSubInfoList(anyString(), anyString()); - verify(mSubscriptionController, never()).getSubInfoForIccId(any()); // Have IccId defined. But expected value and current value are the same. So no RIL command // should be sent. @@ -1305,12 +1299,8 @@ public class GsmCdmaPhoneTest extends TelephonyTest { doReturn(iccId).when(mUiccSlot).getIccId(anyInt()); Message.obtain(mPhoneUT, EVENT_ICC_CHANGED, null).sendToTarget(); processAllMessages(); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService).getAllSubInfoList(anyString(), - nullable(String.class)); - } else { - verify(mSubscriptionController).getSubInfoForIccId(iccId); - } + verify(mSubscriptionManagerService).getAllSubInfoList(anyString(), + nullable(String.class)); verify(mMockCi, never()).enableUiccApplications(anyBoolean(), any()); } @@ -1480,8 +1470,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @Test public void testEventCarrierConfigChanged() { - doReturn(null).when(mSubscriptionController).getSubscriptionProperty(anyInt(), - eq(SubscriptionManager.NR_ADVANCED_CALLING_ENABLED)); doReturn(null).when(mSubscriptionManagerService).getSubscriptionProperty(anyInt(), eq(SubscriptionManager.NR_ADVANCED_CALLING_ENABLED), anyString(), anyString()); @@ -1552,11 +1540,8 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @SmallTest public void testLoadAllowedNetworksFromSubscriptionDatabase_loadTheNullValue_isLoadedTrue() { int subId = 1; - doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); doReturn(subId).when(mSubscriptionManagerService).getSubId(anyInt()); - doReturn(null).when(mSubscriptionController).getSubscriptionProperty(anyInt(), - eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); doReturn(null).when(mSubscriptionManagerService).getSubscriptionProperty(anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES), anyString(), anyString()); @@ -1569,11 +1554,8 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @SmallTest public void testLoadAllowedNetworksFromSubscriptionDatabase_subIdNotValid_isLoadedFalse() { int subId = -1; - doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); doReturn(subId).when(mSubscriptionManagerService).getSubId(anyInt()); - when(mSubscriptionController.getSubscriptionProperty(anyInt(), - eq(SubscriptionManager.ALLOWED_NETWORK_TYPES))).thenReturn(null); when(mSubscriptionManagerService.getSubscriptionProperty(anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES), anyString(), anyString())) .thenReturn(null); @@ -1586,14 +1568,11 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @Test public void testLoadAllowedNetworksFromSubscriptionDatabase_allValidData() { int subId = 1; - doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); doReturn(subId).when(mSubscriptionManagerService).getSubId(anyInt()); // 13 == TelephonyManager.NETWORK_TYPE_LTE // NR_BITMASK == 4096 == 1 << (13 - 1) String validSerializedNetworkMap = "user=4096,power=4096,carrier=4096,enable_2g=4096"; - doReturn(validSerializedNetworkMap).when(mSubscriptionController).getSubscriptionProperty( - anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); SubscriptionInfoInternal si = new SubscriptionInfoInternal.Builder() .setId(1) .setAllowedNetworkTypesForReasons(validSerializedNetworkMap) @@ -1613,15 +1592,12 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @Test public void testLoadAllowedNetworksFromSubscriptionDatabase_invalidKeys() { int subId = 1; - doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); doReturn(subId).when(mSubscriptionManagerService).getSubId(anyInt()); // 13 == TelephonyManager.NETWORK_TYPE_LTE // NR_BITMASK == 4096 == 1 << (13 - 1) String validSerializedNetworkMap = "user=4096,power=4096,carrier=4096,enable_2g=4096,-1=4096"; - doReturn(validSerializedNetworkMap).when(mSubscriptionController).getSubscriptionProperty( - anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); SubscriptionInfoInternal si = new SubscriptionInfoInternal.Builder() .setId(1) .setAllowedNetworkTypesForReasons(validSerializedNetworkMap) @@ -1641,14 +1617,11 @@ public class GsmCdmaPhoneTest extends TelephonyTest { @Test public void testLoadAllowedNetworksFromSubscriptionDatabase_invalidValues() { int subId = 1; - doReturn(subId).when(mSubscriptionController).getSubId(anyInt()); doReturn(subId).when(mSubscriptionManagerService).getSubId(anyInt()); // 19 == TelephonyManager.NETWORK_TYPE_NR // NR_BITMASK == 524288 == 1 << 19 String validSerializedNetworkMap = "user=4096,power=4096,carrier=4096,enable_2g=-1"; - doReturn(validSerializedNetworkMap).when(mSubscriptionController).getSubscriptionProperty( - anyInt(), eq(SubscriptionManager.ALLOWED_NETWORK_TYPES)); SubscriptionInfoInternal si = new SubscriptionInfoInternal.Builder() .setId(1) .setAllowedNetworkTypesForReasons(validSerializedNetworkMap) @@ -1830,8 +1803,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { final SubscriptionInfoInternal si = makeSubscriptionInfoInternal( false, SubscriptionManager.USAGE_SETTING_DATA_CENTRIC); - doReturn(si.toSubscriptionInfo()).when(mSubscriptionController) - .getSubscriptionInfo(anyInt()); doReturn(si).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); mPhoneUT.updateUsageSetting(); @@ -1855,8 +1826,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { final SubscriptionInfoInternal si = makeSubscriptionInfoInternal( true, SubscriptionManager.USAGE_SETTING_DEFAULT); - doReturn(si.toSubscriptionInfo()).when(mSubscriptionController) - .getSubscriptionInfo(anyInt()); doReturn(si).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); mPhoneUT.updateUsageSetting(); @@ -1882,8 +1851,6 @@ public class GsmCdmaPhoneTest extends TelephonyTest { false, SubscriptionManager.USAGE_SETTING_DEFAULT); assertNotNull(si); - doReturn(si.toSubscriptionInfo()).when(mSubscriptionController) - .getSubscriptionInfo(anyInt()); doReturn(si).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); mPhoneUT.updateUsageSetting(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java index 3c1b159561..f4c19d974a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java @@ -145,7 +145,6 @@ public class MultiSimSettingControllerTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); - enableSubscriptionManagerService(true); initializeSubs(); mPhoneMock1 = mock(Phone.class); mPhoneMock2 = mock(Phone.class); @@ -157,6 +156,9 @@ public class MultiSimSettingControllerTest extends TelephonyTest { doReturn(mPhone).when(mPhone).getImsPhone(); mServiceManagerMockedServices.put("isub", mIBinder); + doReturn(mSubscriptionManagerService).when(mIBinder) + .queryLocalInterface(anyString()); + // Default configuration: // DSDS device. // Sub 1 is the default sub. @@ -247,8 +249,7 @@ public class MultiSimSettingControllerTest extends TelephonyTest { // Capture listener to emulate the carrier config change notification used later ArgumentCaptor listenerArgumentCaptor = ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); - mMultiSimSettingControllerUT = new MultiSimSettingController( - mContext, mSubscriptionController); + mMultiSimSettingControllerUT = new MultiSimSettingController(mContext); processAllMessages(); verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), listenerArgumentCaptor.capture()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java index ca0de9cc0b..700a246815 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneConfigurationManagerTest.java @@ -220,17 +220,9 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { // Verify clearSubInfoRecord() and onSlotActiveStatusChange() are called for second phone, // and not for the first one - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService).markSubscriptionsInactive(1); - } else { - verify(mSubscriptionController).clearSubInfoRecord(1); - } + verify(mSubscriptionManagerService).markSubscriptionsInactive(1); verify(mMockCi1).onSlotActiveStatusChange(anyBoolean()); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService, never()).markSubscriptionsInactive(0); - } else { - verify(mSubscriptionController, never()).clearSubInfoRecord(0); - } + verify(mSubscriptionManagerService, never()).markSubscriptionsInactive(0); verify(mMockCi0, never()).onSlotActiveStatusChange(anyBoolean()); // Verify onPhoneRemoved() gets called on MultiSimSettingController phone @@ -259,12 +251,6 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { */ // setup mocks for VOICE mSubscriptionManagerService. getter/setter - doAnswer(invocation -> { - Integer value = (Integer) invocation.getArguments()[0]; - Mockito.when(mSubscriptionController.getDefaultVoiceSubId()).thenReturn(value); - return null; - }).when(mSubscriptionController).setDefaultVoiceSubId(anyInt()); - doAnswer(invocation -> { Integer value = (Integer) invocation.getArguments()[0]; Mockito.when(mSubscriptionManagerService.getDefaultVoiceSubId()).thenReturn(value); @@ -275,30 +261,17 @@ public class PhoneConfigurationManagerTest extends TelephonyTest { // start off the phone stat with 1 active sim. reset values for new test. init(1); - if (isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService.setDefaultVoiceSubId(startingDefaultSubscriptionId); - assertEquals(startingDefaultSubscriptionId, - mSubscriptionManagerService.getDefaultVoiceSubId()); - } else { - mSubscriptionController.setDefaultVoiceSubId(startingDefaultSubscriptionId); - assertEquals(startingDefaultSubscriptionId, - mSubscriptionController.getDefaultVoiceSubId()); - } + mSubscriptionManagerService.setDefaultVoiceSubId(startingDefaultSubscriptionId); + assertEquals(startingDefaultSubscriptionId, + mSubscriptionManagerService.getDefaultVoiceSubId()); // Perform the switch to DSDS mode and ensure all existing checks are not altered testSwitchFromSingleToDualSimModeNoReboot(); // VOICE check - if (isSubscriptionManagerServiceEnabled()) { - assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID /* No CALL Preference value */, - mSubscriptionManagerService.getDefaultVoiceSubId()); - // Now, when the user goes to place a CALL, they will be prompted on which sim to use. - } else { - assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID /* No CALL Preference value */, - mSubscriptionController.getDefaultVoiceSubId()); - // Now, when the user goes to place a CALL, they will be prompted on which sim to use. - } - + assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID /* No CALL Preference value */, + mSubscriptionManagerService.getDefaultVoiceSubId()); + // Now, when the user goes to place a CALL, they will be prompted on which sim to use. } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java index 0669517d9d..00634a05da 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSubInfoControllerTest.java @@ -27,7 +27,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.anyInt; -import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -77,22 +76,15 @@ public class PhoneSubInfoControllerTest extends TelephonyTest { PropertyInvalidatedCache.disableForTestMode(); /* mPhone -> PhoneId: 0 -> SubId:0 mSecondPhone -> PhoneId:1 -> SubId: 1*/ - doReturn(0).when(mSubscriptionController).getPhoneId(eq(0)); doReturn(0).when(mSubscriptionManagerService).getPhoneId(eq(0)); - doReturn(1).when(mSubscriptionController).getPhoneId(eq(1)); doReturn(1).when(mSubscriptionManagerService).getPhoneId(eq(1)); doReturn(2).when(mTelephonyManager).getPhoneCount(); doReturn(2).when(mTelephonyManager).getActiveModemCount(); - doReturn(true).when(mSubscriptionController).isActiveSubId(0, TAG, FEATURE_ID); doReturn(true).when(mSubscriptionManagerService).isActiveSubId(0, TAG, FEATURE_ID); - doReturn(true).when(mSubscriptionController).isActiveSubId(1, TAG, FEATURE_ID); doReturn(true).when(mSubscriptionManagerService).isActiveSubId(1, TAG, FEATURE_ID); doReturn(new int[]{0, 1}).when(mSubscriptionManager) .getCompleteActiveSubscriptionIdList(); - mServiceManagerMockedServices.put("isub", mSubscriptionController); - doReturn(mSubscriptionController).when(mSubscriptionController) - .queryLocalInterface(anyString()); doReturn(mContext).when(mSecondPhone).getContext(); mAppOsMgr = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 3b6499c5f3..b406f5688e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -1548,9 +1548,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { sst.mSubId = subId; doReturn(subId).when(mSubInfo).getSubscriptionId(); - doReturn(mSubInfo).when(mSubscriptionController).getActiveSubscriptionInfo( - anyInt(), anyString(), nullable(String.class)); - final NotificationManager nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); mContextFixture.putBooleanResource( @@ -1583,8 +1580,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { int subId = 1; sst.mSubId = subId; doReturn(subId).when(mSubInfo).getSubscriptionId(); - doReturn(mSubInfo).when(mSubscriptionController) - .getActiveSubscriptionInfo(anyInt(), anyString(), nullable(String.class)); final NotificationManager nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); @@ -1619,8 +1614,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { int subId = 1; sst.mSubId = subId; doReturn(subId).when(mSubInfo).getSubscriptionId(); - doReturn(mSubInfo).when(mSubscriptionController) - .getActiveSubscriptionInfo(anyInt(), anyString(), nullable(String.class)); final NotificationManager nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); @@ -1654,8 +1647,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { int subId = 1; sst.mSubId = subId; doReturn(subId).when(mSubInfo).getSubscriptionId(); - doReturn(mSubInfo).when(mSubscriptionController) - .getActiveSubscriptionInfo(anyInt(), anyString(), nullable(String.class)); final NotificationManager nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java deleted file mode 100644 index 28c3187589..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java +++ /dev/null @@ -1,2291 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.telephony; - -import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION; - -import static com.android.internal.telephony.SubscriptionController.REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID; -import static com.android.internal.telephony.uicc.IccCardStatus.CardState.CARDSTATE_PRESENT; - -import static com.google.common.truth.Truth.assertThat; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.Manifest; -import android.compat.testing.PlatformCompatChangeRule; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.ParcelUuid; -import android.os.PersistableBundle; -import android.os.UserHandle; -import android.provider.Settings; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.UiccPortInfo; -import android.telephony.UiccSlotInfo; -import android.test.mock.MockContentResolver; - -import androidx.test.filters.FlakyTest; -import androidx.test.filters.SmallTest; - -import com.android.internal.telephony.data.PhoneSwitcher; -import com.android.internal.telephony.uicc.IccCardStatus; -import com.android.internal.telephony.uicc.UiccController; -import com.android.internal.telephony.uicc.UiccSlot; - -import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; -import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TestRule; -import org.mockito.ArgumentCaptor; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -public class SubscriptionControllerTest extends TelephonyTest { - private static final int SINGLE_SIM = 1; - private static final int DUAL_SIM = 2; - private static final int FAKE_SUBID = 123; - private String mCallingPackage; - private String mCallingFeature; - private SubscriptionController mSubscriptionControllerUT; - private MockContentResolver mMockContentResolver; - private FakeTelephonyProvider mFakeTelephonyProvider; - private PersistableBundle mCarrierConfigs; - - // Mocked classes - private UiccSlot mUiccSlot; - private ITelephonyRegistry.Stub mTelephonyRegistryMock; - private MultiSimSettingController mMultiSimSettingControllerMock; - private ISetOpportunisticDataCallback mSetOpptDataCallback; - private Handler mHandler; - private SubscriptionInfo mMockSubscriptionInfo; - - private static final String MAC_ADDRESS_PREFIX = "mac_"; - private static final String DISPLAY_NAME_PREFIX = "my_phone_"; - - private static final String UNAVAILABLE_ICCID = ""; - private static final String UNAVAILABLE_NUMBER = ""; - private static final String DISPLAY_NUMBER = "123456"; - private static final String DISPLAY_NAME = "testing_display_name"; - - @Rule - public TestRule mCompatChangeRule = new PlatformCompatChangeRule(); - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - enableSubscriptionManagerService(false); - mUiccSlot = mock(UiccSlot.class); - mTelephonyRegistryMock = mock(ITelephonyRegistry.Stub.class); - mMultiSimSettingControllerMock = mock(MultiSimSettingController.class); - mSetOpptDataCallback = mock(ISetOpportunisticDataCallback.class); - mHandler = mock(Handler.class); - mMockSubscriptionInfo = mock(SubscriptionInfo.class); - if (Looper.myLooper() == null) { - Looper.prepare(); - } - - doReturn(SINGLE_SIM).when(mTelephonyManager).getSimCount(); - doReturn(SINGLE_SIM).when(mTelephonyManager).getPhoneCount(); - mMockContentResolver = (MockContentResolver) mContext.getContentResolver(); - mFakeTelephonyProvider = new FakeTelephonyProvider(); - mMockContentResolver.addProvider(SubscriptionManager.CONTENT_URI.getAuthority(), - mFakeTelephonyProvider); - replaceInstance(SubscriptionController.class, "sInstance", null, null); - replaceInstance(MultiSimSettingController.class, "sInstance", null, - mMultiSimSettingControllerMock); - replaceInstance(SubscriptionInfoUpdater.class, "mIsWorkProfileTelephonyEnabled", - null, true); - - mSubscriptionControllerUT = SubscriptionController.init(mContext); - mCallingPackage = mContext.getOpPackageName(); - mCallingFeature = mContext.getAttributionTag(); - - doReturn(1).when(mProxyController).getMaxRafSupported(); - - // Carrier Config - mCarrierConfigs = mContextFixture.getCarrierConfigBundle(); - - mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[]{5}); - setupMocksForTelephonyPermissions(Build.VERSION_CODES.R); - } - - @After - public void tearDown() throws Exception { - mContextFixture.addCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - /* Should clear fake content provider and resolver here */ - mContext.getContentResolver().delete(SubscriptionManager.CONTENT_URI, null, null); - - /* Clear sub info in mSubscriptionControllerUT since they will otherwise be persistent - * between each test case. */ - if (mSubscriptionControllerUT != null) { - mSubscriptionControllerUT.clearSubInfo(); - mSubscriptionControllerUT = null; - } - - /* Clear settings for default voice/data/sms sub ID */ - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - - mCallingPackage = null; - mCallingFeature = null; - mMockContentResolver = null; - mFakeTelephonyProvider = null; - mCarrierConfigs = null; - super.tearDown(); - } - - @Test @SmallTest - public void testInsertSim() { - //verify there is no sim inserted in the SubscriptionManager - assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage, - mCallingFeature)); - - int slotID = 0; - //insert one Subscription Info - mSubscriptionControllerUT.addSubInfo("test", null, slotID, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - //verify there is one sim - assertEquals(1, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage, - mCallingFeature)); - - //sanity for slot id and sub id - List mSubList = mSubscriptionControllerUT - .getActiveSubscriptionInfoList(mCallingPackage, mCallingFeature); - assertTrue(mSubList != null && mSubList.size() > 0); - for (int i = 0; i < mSubList.size(); i++) { - assertTrue(SubscriptionManager.isValidSubscriptionId( - mSubList.get(i).getSubscriptionId())); - assertTrue(SubscriptionManager.isValidSlotIndex(mSubList.get(i).getSimSlotIndex())); - } - } - - @Test @SmallTest - public void testUsageSettingProperty() { - testInsertSim(); - /* Get SUB ID */ - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - final int subId = subIds[0]; - - /* Getting, there is no direct getter function for each fields of property */ - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subId, mCallingPackage, mCallingFeature); - - // assertEquals(SubscriptionManager.USAGE_SETTING_UNKNOWN, subInfo.getUsageSetting()); - - assertThrows(IllegalArgumentException.class, - () -> mSubscriptionControllerUT.setUsageSetting( - SubscriptionManager.USAGE_SETTING_UNKNOWN, - subId, - mCallingPackage)); - - assertThrows(IllegalArgumentException.class, - () -> mSubscriptionControllerUT.setUsageSetting( - SubscriptionManager.USAGE_SETTING_DEFAULT, - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - mCallingPackage)); - - mSubscriptionControllerUT.setUsageSetting( - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC, - subId, - mCallingPackage); - - subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subId, mCallingPackage, mCallingFeature); - assertEquals(SubscriptionManager.USAGE_SETTING_DATA_CENTRIC, subInfo.getUsageSetting()); - } - - @Test @SmallTest - public void testChangeSIMProperty() { - int dataRoaming = 1; - int iconTint = 1; - String disName = "TESTING"; - String disNum = "12345"; - boolean isOpportunistic = true; - - testInsertSim(); - /* Get SUB ID */ - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - int subID = subIds[0]; - - /* Getting, there is no direct getter function for each fields of property */ - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subID, mCallingPackage, mCallingFeature); - - /* Setting */ - mSubscriptionControllerUT.setDisplayNameUsingSrc(disName, subID, - SubscriptionManager.NAME_SOURCE_USER_INPUT); - mSubscriptionControllerUT.setDataRoaming(dataRoaming, subID); - mSubscriptionControllerUT.setDisplayNumber(disNum, subID); - mSubscriptionControllerUT.setIconTint(iconTint, subID); - mSubscriptionControllerUT.setOpportunistic(isOpportunistic, subID, mCallingPackage); - - subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subID, mCallingPackage, mCallingFeature); - - assertNotNull(subInfo); - assertEquals(dataRoaming, subInfo.getDataRoaming()); - assertEquals(disName, subInfo.getDisplayName()); - assertEquals(iconTint, subInfo.getIconTint()); - assertEquals(disNum, subInfo.getNumber()); - assertEquals(isOpportunistic, subInfo.isOpportunistic()); - } - - @Test @SmallTest - public void testSetGetDisplayNameSrc() { - testInsertSim(); - - /* Get SUB ID */ - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - int subID = subIds[0]; - - /* Setting */ - String disName = "TESTING"; - int nameSource = SubscriptionManager.NAME_SOURCE_SIM_SPN; - mSubscriptionControllerUT.setDisplayNameUsingSrc(disName, subID, nameSource); - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subID, mCallingPackage, mCallingFeature); - assertNotNull(subInfo); - assertEquals(disName, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getDisplayNameSource()); - } - - private void setSimEmbedded(boolean isEmbedded) throws Exception { - ContentValues values = new ContentValues(); - values.put(SubscriptionManager.IS_EMBEDDED, isEmbedded ? 1 : 0); - mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + getFirstSubId(), - null); - } - - @Test @SmallTest - public void testSetGetDisplayNameSrc_updateNameSourceCarrierWithEmbeddedSim() - throws Exception { - testInsertSim(); - - // Set values of DB - setSimEmbedded(true); - int subId = getFirstSubId(); - int nameSource = SubscriptionManager.NAME_SOURCE_CARRIER; - mSubscriptionControllerUT.setDisplayNameUsingSrc(DISPLAY_NAME, subId, nameSource); - - // Update with new value - String newDisplayName = "display_name_pnn"; - int newNameSource = SubscriptionManager.NAME_SOURCE_SIM_PNN; - - // Save to DB after updated - mSubscriptionControllerUT.setDisplayNameUsingSrc(newDisplayName, subId, newNameSource); - - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subId, mCallingPackage, mCallingFeature); - - assertNotNull(subInfo); - assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getDisplayNameSource()); - } - - @Test @SmallTest - public void testSetGetDisplayNameSrc_updateNameSourceCarrierWithConfigIsNull() - throws Exception { - testInsertSim(); - - // Set values of DB - setSimEmbedded(false); - int subId = getFirstSubId(); - int nameSource = SubscriptionManager.NAME_SOURCE_CARRIER; - mSubscriptionControllerUT.setDisplayNameUsingSrc(DISPLAY_NAME, subId, nameSource); - - // Update with new value - String newDisplayName = "display_name_spn"; - int newNameSource = SubscriptionManager.NAME_SOURCE_SIM_SPN; - when(mCarrierConfigManager.getConfigForSubId(subId)).thenReturn(null); - - // Save to DB after updated - mSubscriptionControllerUT.setDisplayNameUsingSrc(newDisplayName, subId, newNameSource); - - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subId, mCallingPackage, mCallingFeature); - - assertNotNull(subInfo); - assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getDisplayNameSource()); - } - - @Test @SmallTest - public void testSetGetDisplayNameSrc_updateNameSourceCarrierWithCarrierNameOverride() - throws Exception { - testInsertSim(); - - // Set values of DB - setSimEmbedded(false); - int subId = getFirstSubId(); - int nameSource = SubscriptionManager.NAME_SOURCE_CARRIER; - mSubscriptionControllerUT.setDisplayNameUsingSrc(DISPLAY_NAME, subId, nameSource); - - // Update with new value - int newNameSource = SubscriptionManager.NAME_SOURCE_SIM_SPN; - String newDisplayName = "display_name_spn"; - mCarrierConfigs.putBoolean(CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL, true); - - // Save to DB after updated - mSubscriptionControllerUT.setDisplayNameUsingSrc(newDisplayName, subId, newNameSource); - - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subId, mCallingPackage, mCallingFeature); - - assertNotNull(subInfo); - assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getDisplayNameSource()); - } - - @Test @SmallTest - public void testSetGetDisplayNameSrc_updateNameSourceCarrierWithSpnAndCarrierName() - throws Exception { - testInsertSim(); - - // Set values of DB - setSimEmbedded(false); - int subId = getFirstSubId(); - int nameSource = SubscriptionManager.NAME_SOURCE_CARRIER; - mSubscriptionControllerUT.setDisplayNameUsingSrc(DISPLAY_NAME, subId, nameSource); - - // Update with new value - int newNameSource = SubscriptionManager.NAME_SOURCE_SIM_SPN; - String carrierName = "testing_carrier_name"; - String newDisplayName = "display_name_spn"; - when(mUiccController.getUiccProfileForPhone(anyInt())).thenReturn(mUiccProfile); - when(mUiccProfile.getServiceProviderName()).thenReturn(null); - mCarrierConfigs.putBoolean(CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL, false); - mCarrierConfigs.putString(CarrierConfigManager.KEY_CARRIER_NAME_STRING, carrierName); - - // Save to DB after updated - mSubscriptionControllerUT.setDisplayNameUsingSrc(newDisplayName, subId, newNameSource); - - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subId, mCallingPackage, mCallingFeature); - - assertNotNull(subInfo); - assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getDisplayNameSource()); - } - - @Test @SmallTest - public void testSetGetDisplayNameSrc_updateNameSourcePnnToNameSourceCarrierId() - throws Exception { - testInsertSim(); - - // Set values of DB - int subId = getFirstSubId(); - int nameSource = SubscriptionManager.NAME_SOURCE_SIM_PNN; - mSubscriptionControllerUT.setDisplayNameUsingSrc(DISPLAY_NAME, subId, nameSource); - - // Update with new value - String newDisplayName = "display_name_carrier_id"; - int newNameSource = SubscriptionManager.NAME_SOURCE_CARRIER_ID; - when(mPhone.getPlmn()).thenReturn("testing_pnn"); - - // Save to DB after updated - mSubscriptionControllerUT.setDisplayNameUsingSrc(newDisplayName, subId, newNameSource); - - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subId, mCallingPackage, mCallingFeature); - - assertNotNull(subInfo); - assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getDisplayNameSource()); - } - - @Test @SmallTest - public void testSetGetDisplayNameSrc_updateNameSourceUserInputToNameSourceSpn() - throws Exception { - testInsertSim(); - - // Set values of DB - int subId = getFirstSubId(); - int nameSource = SubscriptionManager.NAME_SOURCE_USER_INPUT; - mSubscriptionControllerUT.setDisplayNameUsingSrc(DISPLAY_NAME, subId, nameSource); - - // Update with new value - String newDisplayName = "display_name_spn"; - int newNameSource = SubscriptionManager.NAME_SOURCE_SIM_SPN; - - // Save to DB after updated - mSubscriptionControllerUT.setDisplayNameUsingSrc(newDisplayName, subId, newNameSource); - - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(subId, mCallingPackage, mCallingFeature); - - assertNotNull(subInfo); - assertEquals(DISPLAY_NAME, subInfo.getDisplayName()); - assertEquals(nameSource, subInfo.getDisplayNameSource()); - } - - @Test @SmallTest - public void testIsExistingNameSourceStillValid_pnnIsNotNull_returnTrue() { - when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getDisplayNameSource()) - .thenReturn(SubscriptionManager.NAME_SOURCE_SIM_PNN); - when(mPhone.getPlmn()).thenReturn("testing_pnn"); - - assertTrue(mSubscriptionControllerUT.isExistingNameSourceStillValid(mMockSubscriptionInfo)); - } - - @Test @SmallTest - public void testIsExistingNameSourceStillValid_spnIsNotNull_returnTrue() { - when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getDisplayNameSource()) - .thenReturn(SubscriptionManager.NAME_SOURCE_SIM_SPN); - when(mUiccController.getUiccProfileForPhone(anyInt())).thenReturn(mUiccProfile); - when(mUiccProfile.getServiceProviderName()).thenReturn("testing_spn"); - - assertTrue(mSubscriptionControllerUT.isExistingNameSourceStillValid(mMockSubscriptionInfo)); - } - - @Test @SmallTest - public void testIsExistingNameSourceStillValid_simIsEmbedded_returnTrue() { - when(mMockSubscriptionInfo.isEmbedded()).thenReturn(true); - when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getDisplayNameSource()) - .thenReturn(SubscriptionManager.NAME_SOURCE_CARRIER); - - assertTrue(mSubscriptionControllerUT.isExistingNameSourceStillValid(mMockSubscriptionInfo)); - } - - @Test @SmallTest - public void testIsExistingNameSourceStillValid_carrierConfigIsNull_returnTrue() { - when(mMockSubscriptionInfo.isEmbedded()).thenReturn(false); - when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getDisplayNameSource()) - .thenReturn(SubscriptionManager.NAME_SOURCE_CARRIER); - when(mCarrierConfigManager.getConfigForSubId(FAKE_SUBID)).thenReturn(null); - - assertTrue(mSubscriptionControllerUT.isExistingNameSourceStillValid(mMockSubscriptionInfo)); - } - - @Test @SmallTest - public void testIsExistingNameSourceStillValid_carrierNameOverrideIsTrue_returnTrue() { - when(mMockSubscriptionInfo.isEmbedded()).thenReturn(false); - when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getDisplayNameSource()) - .thenReturn(SubscriptionManager.NAME_SOURCE_CARRIER); - mCarrierConfigs.putBoolean(CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL, true); - - assertTrue(mSubscriptionControllerUT.isExistingNameSourceStillValid(mMockSubscriptionInfo)); - } - - @Test @SmallTest - public void testIsExistingNameSourceStillValid_spnIsNullAndCarrierNameIsNotNull_returnTrue() { - when(mMockSubscriptionInfo.isEmbedded()).thenReturn(false); - when((mMockSubscriptionInfo).getSubscriptionId()).thenReturn(FAKE_SUBID); - when(mMockSubscriptionInfo.getDisplayNameSource()) - .thenReturn(SubscriptionManager.NAME_SOURCE_CARRIER); - when(mUiccController.getUiccProfileForPhone(anyInt())).thenReturn(mUiccProfile); - when(mUiccProfile.getServiceProviderName()).thenReturn(null); - mCarrierConfigs.putBoolean(CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL, false); - mCarrierConfigs.putString(CarrierConfigManager.KEY_CARRIER_NAME_STRING, - "testing_carrier_name"); - - assertTrue(mSubscriptionControllerUT.isExistingNameSourceStillValid(mMockSubscriptionInfo)); - } - - @Test @SmallTest - public void testCleanUpSIM() { - testInsertSim(); - assertFalse(mSubscriptionControllerUT.isActiveSubId(2)); - mSubscriptionControllerUT.clearSubInfo(); - assertFalse(mSubscriptionControllerUT.isActiveSubId(1)); - assertEquals(SubscriptionManager.SIM_NOT_INSERTED, - mSubscriptionControllerUT.getSlotIndex(1)); - } - - @Test @SmallTest - public void testDefaultSubIdOnSingleSimDevice() { - assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID, - mSubscriptionControllerUT.getDefaultDataSubId()); - assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID, - mSubscriptionControllerUT.getDefaultSmsSubId()); - assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID, - mSubscriptionControllerUT.getDefaultSmsSubId()); - /* insert one sim */ - testInsertSim(); - // if support single sim, sms/data/voice default sub should be the same - assertEquals(1, mSubscriptionControllerUT.getDefaultSubId()); - assertEquals(1, mSubscriptionControllerUT.getDefaultDataSubId()); - assertEquals(1, mSubscriptionControllerUT.getDefaultSmsSubId()); - assertEquals(1, mSubscriptionControllerUT.getDefaultVoiceSubId()); - } - - @Test @SmallTest - public void testSetGetMCCMNC() { - testInsertSim(); - String mCcMncVERIZON = "310004"; - mSubscriptionControllerUT.setMccMnc(mCcMncVERIZON, 1); - - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(1, mCallingPackage, mCallingFeature); - assertNotNull(subInfo); - assertEquals(Integer.parseInt(mCcMncVERIZON.substring(0, 3)), subInfo.getMcc()); - assertEquals(Integer.parseInt(mCcMncVERIZON.substring(3)), subInfo.getMnc()); - } - - @Test @SmallTest - public void testSetGetCarrierId() { - testInsertSim(); - int carrierId = 1234; - mSubscriptionControllerUT.setCarrierId(carrierId, 1); - - SubscriptionInfo subInfo = mSubscriptionControllerUT - .getActiveSubscriptionInfo(1, mCallingPackage, mCallingFeature); - assertNotNull(subInfo); - assertEquals(carrierId, subInfo.getCarrierId()); - } - - @Test - @SmallTest - public void testSetDefaultDataSubId() throws Exception { - doReturn(1).when(mPhone).getSubId(); - - mSubscriptionControllerUT.setDefaultDataSubId(1); - - ArgumentCaptor captorIntent = ArgumentCaptor.forClass(Intent.class); - verify(mContext, times(1)).sendStickyBroadcastAsUser( - captorIntent.capture(), eq(UserHandle.ALL)); - - Intent intent = captorIntent.getValue(); - assertEquals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED, intent.getAction()); - - Bundle b = intent.getExtras(); - - assertTrue(b.containsKey(PhoneConstants.SUBSCRIPTION_KEY)); - assertEquals(1, b.getInt(PhoneConstants.SUBSCRIPTION_KEY)); - } - - @Test - @SmallTest - public void testMigrateImsSettings() throws Exception { - testInsertSim(); - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - int subID = subIds[0]; - - // Set default void subId. - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, - subID); - - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.ENHANCED_4G_MODE_ENABLED, - 1); - - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.VT_IMS_ENABLED, - 0); - - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_ENABLED, - 1); - - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_MODE, - 2); - - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_ROAMING_MODE, - 3); - - mSubscriptionControllerUT.migrateImsSettings(); - - // Global settings should be all set. - assertEquals(-1, Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.ENHANCED_4G_MODE_ENABLED)); - - assertEquals(-1, Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.VT_IMS_ENABLED)); - - assertEquals(-1, Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_ENABLED)); - - assertEquals(-1, Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_MODE)); - - assertEquals(-1, Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_ROAMING_MODE)); - - // The values should be migrated to its DB. - assertEquals("1", mSubscriptionControllerUT.getSubscriptionProperty( - subID, - SubscriptionManager.ENHANCED_4G_MODE_ENABLED, - mCallingPackage, - mCallingFeature)); - - assertEquals("0", mSubscriptionControllerUT.getSubscriptionProperty( - subID, - SubscriptionManager.VT_IMS_ENABLED, - mCallingPackage, - mCallingFeature)); - - assertEquals("1", mSubscriptionControllerUT.getSubscriptionProperty( - subID, - SubscriptionManager.WFC_IMS_ENABLED, - mCallingPackage, - mCallingFeature)); - - assertEquals("2", mSubscriptionControllerUT.getSubscriptionProperty( - subID, - SubscriptionManager.WFC_IMS_MODE, - mCallingPackage, - mCallingFeature)); - - assertEquals("3", mSubscriptionControllerUT.getSubscriptionProperty( - subID, - SubscriptionManager.WFC_IMS_ROAMING_MODE, - mCallingPackage, - mCallingFeature)); - } - - @Test - @SmallTest - public void testSkipMigrateImsSettings() throws Exception { - - // Set default invalid subId. - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, - -1); - - int enhanced4gModeEnabled = 1; - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.ENHANCED_4G_MODE_ENABLED, - enhanced4gModeEnabled); - - int vtImsEnabled = 0; - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.VT_IMS_ENABLED, - vtImsEnabled); - - int wfcImsEnabled = 1; - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_ENABLED, - wfcImsEnabled); - - int wfcImsMode = 2; - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_MODE, - wfcImsMode); - - int wfcImsRoamingMode = 3; - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_ROAMING_MODE, - wfcImsRoamingMode); - - mSubscriptionControllerUT.migrateImsSettings(); - - // Migration should be skipped because subId was invalid - assertEquals(enhanced4gModeEnabled, Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.ENHANCED_4G_MODE_ENABLED)); - - assertEquals(vtImsEnabled, Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.VT_IMS_ENABLED)); - - assertEquals(wfcImsEnabled, Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_ENABLED)); - - assertEquals(wfcImsMode, Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_MODE)); - - assertEquals(wfcImsRoamingMode, Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.WFC_IMS_ROAMING_MODE)); - } - - @Test - @SmallTest - public void testOpptSubInfoListChanged() throws Exception { - registerMockTelephonyRegistry(); - verify(mTelephonyRegistryManager, times(0)) - .notifyOpportunisticSubscriptionInfoChanged(); - - testInsertSim(); - mSubscriptionControllerUT.addSubInfo("test2", null, 0, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - // Neither sub1 or sub2 are opportunistic. So getOpportunisticSubscriptions - // should return empty list and no callback triggered. - List opptSubList = mSubscriptionControllerUT - .getOpportunisticSubscriptions(mCallingPackage, mCallingFeature); - - assertTrue(opptSubList.isEmpty()); - verify(mTelephonyRegistryManager, times(0)) - .notifyOpportunisticSubscriptionInfoChanged(); - - // Setting sub2 as opportunistic should trigger callback. - mSubscriptionControllerUT.setOpportunistic(true, 2, mCallingPackage); - - verify(mTelephonyRegistryManager, times(1)) - .notifyOpportunisticSubscriptionInfoChanged(); - opptSubList = mSubscriptionControllerUT - .getOpportunisticSubscriptions(mCallingPackage, mCallingFeature); - assertEquals(1, opptSubList.size()); - assertEquals("test2", opptSubList.get(0).getIccId()); - - // Changing non-opportunistic sub1 shouldn't trigger callback. - mSubscriptionControllerUT.setDisplayNameUsingSrc("DisplayName", 1, - SubscriptionManager.NAME_SOURCE_SIM_SPN); - verify(mTelephonyRegistryManager, times(1)) - .notifyOpportunisticSubscriptionInfoChanged(); - - mSubscriptionControllerUT.setDisplayNameUsingSrc("DisplayName", 2, - SubscriptionManager.NAME_SOURCE_SIM_SPN); - verify(mTelephonyRegistryManager, times(2)) - .notifyOpportunisticSubscriptionInfoChanged(); - } - - @Test @SmallTest - public void testInsertRemoteSim() { - makeThisDeviceMultiSimCapable(); - mContextFixture.addSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); - - // verify there are no sim's in the system. - assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage, - mCallingFeature)); - - addAndVerifyRemoteSimAddition(1, 0); - } - - private void addAndVerifyRemoteSimAddition(int num, int numOfCurrentSubs) { - // Verify the number of current subs in the system - assertEquals(numOfCurrentSubs, - mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage, mCallingFeature)); - - // if there are current subs in the system, get that info - List mSubList; - ArrayList macAddresses = new ArrayList<>(); - ArrayList displayNames = new ArrayList<>(); - if (numOfCurrentSubs > 0) { - mSubList = mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage, - mCallingFeature); - assertNotNull(mSubList); - assertEquals(numOfCurrentSubs, mSubList.size()); - for (SubscriptionInfo info : mSubList) { - assertNotNull(info.getIccId()); - assertNotNull(info.getDisplayName()); - macAddresses.add(info.getIccId()); - displayNames.add(info.getDisplayName().toString()); - } - } - - // To add more subs, we need to create macAddresses + displaynames. - for (int i = 0; i < num; i++) { - macAddresses.add(MAC_ADDRESS_PREFIX + (numOfCurrentSubs + i)); - displayNames.add(DISPLAY_NAME_PREFIX + (numOfCurrentSubs + i)); - } - - // Add subs - one at a time and verify the contents in subscription info data structs - for (int i = 0; i < num; i++) { - int index = numOfCurrentSubs + i; - mSubscriptionControllerUT.addSubInfo(macAddresses.get(index), displayNames.get(index), - SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB, - SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); - - // make sure the subscription is added in SubscriptionController data structs - Map> slotIndexToSubsMap = - mSubscriptionControllerUT.getSlotIndexToSubIdsMap(); - assertNotNull(slotIndexToSubsMap); - // Since All remote sim's go to the same slot index, there should only be one entry - assertEquals(1, slotIndexToSubsMap.size()); - - // get all the subscriptions available. should be what is just added in this method - // PLUS the number of subs that already existed before - int expectedNumOfSubs = numOfCurrentSubs + i + 1; - ArrayList subIdsList = - slotIndexToSubsMap.get(SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB); - assertNotNull(subIdsList); - assertEquals(expectedNumOfSubs, subIdsList.size()); - - // validate slot index, sub id etc - mSubList = mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage, - mCallingFeature); - assertNotNull(mSubList); - assertEquals(expectedNumOfSubs, mSubList.size()); - - // sort on subscription-id which will make sure the previously existing subscriptions - // are in earlier slots in the array - mSubList.sort(SUBSCRIPTION_INFO_COMPARATOR); - - // Verify the subscription data. Skip the verification for the existing subs. - for (int j = numOfCurrentSubs; j < mSubList.size(); j++) { - SubscriptionInfo info = mSubList.get(j); - assertTrue(SubscriptionManager.isValidSubscriptionId(info.getSubscriptionId())); - assertEquals(SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB, - info.getSimSlotIndex()); - assertEquals(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM, - info.getSubscriptionType()); - assertEquals(macAddresses.get(j), info.getIccId()); - assertEquals(displayNames.get(j), info.getDisplayName()); - } - } - } - - private static final Comparator SUBSCRIPTION_INFO_COMPARATOR = - Comparator.comparingInt(o -> o.getSubscriptionId()); - - @Test @SmallTest - public void testInsertMultipleRemoteSims() { - makeThisDeviceMultiSimCapable(); - mContextFixture.addSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); - - // verify that there are no subscription info records - assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage, - mCallingFeature)); - Map> slotIndexToSubsMap = - mSubscriptionControllerUT.getSlotIndexToSubIdsMap(); - assertNotNull(slotIndexToSubsMap); - assertTrue(slotIndexToSubsMap.isEmpty()); - - // Add a few subscriptions - addAndVerifyRemoteSimAddition(4, 0); - } - - @FlakyTest - @Test @SmallTest - public void testDefaultSubIdOnMultiSimDevice() { - makeThisDeviceMultiSimCapable(); - - // Initially, defaults should be -1 - assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID, - mSubscriptionControllerUT.getDefaultDataSubId()); - assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID, - mSubscriptionControllerUT.getDefaultSmsSubId()); - assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID, - mSubscriptionControllerUT.getDefaultSmsSubId()); - - // Insert one Remote-Sim. - testInsertRemoteSim(); - - // defaults should be set to this newly-inserted subscription - assertEquals(1, mSubscriptionControllerUT.getDefaultSubId()); - assertEquals(1, mSubscriptionControllerUT.getDefaultDataSubId()); - assertEquals(1, mSubscriptionControllerUT.getDefaultSmsSubId()); - assertEquals(1, mSubscriptionControllerUT.getDefaultVoiceSubId()); - - // Add a few subscriptions - addAndVerifyRemoteSimAddition(4, 1); - - // defaults should be still be set to the first sub - and unchanged by the addition of - // the above multiple sims. - assertEquals(1, mSubscriptionControllerUT.getDefaultSubId()); - assertEquals(1, mSubscriptionControllerUT.getDefaultDataSubId()); - assertEquals(1, mSubscriptionControllerUT.getDefaultSmsSubId()); - assertEquals(1, mSubscriptionControllerUT.getDefaultVoiceSubId()); - } - - @Test @SmallTest - public void testRemoveSubscription() { - makeThisDeviceMultiSimCapable(); - - /* insert some sims */ - testInsertMultipleRemoteSims(); - assertEquals(1, mSubscriptionControllerUT.getDefaultSubId()); - int[] subIdsArray = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIdsArray.length > 0); - int len = subIdsArray.length; - - // remove the first sim - which also is the default sim. - int result = mSubscriptionControllerUT.removeSubInfo(MAC_ADDRESS_PREFIX + 0, - SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); - - assertTrue(result > 0); - // now check the number of subs left. should be one less than earlier - int[] newSubIdsArray = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(newSubIdsArray.length > 0); - assertEquals(len - 1, newSubIdsArray.length); - - // now check that there is a new default - assertNotSame(1, mSubscriptionControllerUT.getDefaultSubId()); - } - - private void makeThisDeviceMultiSimCapable() { - doReturn(10).when(mTelephonyManager).getSimCount(); - } - - @Test - @SmallTest - public void testSetSubscriptionGroupWithModifyPermission() throws Exception { - testInsertSim(); - mSubscriptionControllerUT.addSubInfo("test2", null, 0, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); - - int[] subIdList = new int[] {1, 2}; - try { - mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, mContext.getOpPackageName()); - fail("createSubscriptionGroup should fail with no permission."); - } catch (SecurityException e) { - // Expected result. - } - - // With modify permission it should succeed. - mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE); - ParcelUuid groupId = mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, mContext.getOpPackageName()); - assertNotEquals(null, groupId); - - // Calling it again should generate a new group ID. - ParcelUuid newGroupId = mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, mContext.getOpPackageName()); - assertNotEquals(null, newGroupId); - assertNotEquals(groupId, newGroupId); - } - - @Test - @SmallTest - public void testGetSubscriptionProperty() throws Exception { - testInsertSim(); - ContentValues values = new ContentValues(); - values.put(SubscriptionManager.GROUP_UUID, 1); - mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 1, null); - - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); - - // should succeed with read phone state permission - String prop = mSubscriptionControllerUT.getSubscriptionProperty(1, - SubscriptionManager.CB_EXTREME_THREAT_ALERT, mContext.getOpPackageName(), - mContext.getAttributionTag()); - - assertNotEquals(null, prop); - - // group UUID requires privileged phone state permission - prop = mSubscriptionControllerUT.getSubscriptionProperty(1, SubscriptionManager.GROUP_UUID, - mContext.getOpPackageName(), mContext.getAttributionTag()); - assertEquals(null, prop); - - // group UUID should succeed once privileged phone state permission is granted - setupReadPrivilegePermission(); - prop = mSubscriptionControllerUT.getSubscriptionProperty(1, SubscriptionManager.GROUP_UUID, - mContext.getOpPackageName(), mContext.getAttributionTag()); - assertNotEquals(null, prop); - } - - @Test - @SmallTest - public void testCreateSubscriptionGroupWithCarrierPrivilegePermission() throws Exception { - testInsertSim(); - // Adding a second profile and mark as embedded. - // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfo("test2", null, 1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - ContentValues values = new ContentValues(); - values.put(SubscriptionManager.IS_EMBEDDED, 1); - mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null); - mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList(); - - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); - - int[] subIdList = new int[] {1, 2}; - // It should fail since it has no permission. - try { - mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, mContext.getOpPackageName()); - fail("createSubscriptionGroup should fail with no permission."); - } catch (SecurityException e) { - // Expected result. - } - - doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1); - try { - mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, mContext.getOpPackageName()); - fail("createSubscriptionGroup should fail with no permission on sub 2."); - } catch (SecurityException e) { - // Expected result. - } - - doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(2); - ParcelUuid groupId = mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, mContext.getOpPackageName()); - assertNotEquals(null, groupId); - - List subInfoList = - mSubscriptionControllerUT.getActiveSubscriptionInfoList(mContext.getOpPackageName(), - mContext.getAttributionTag()); - - // Put sub3 into slot 1 to make sub2 inactive. - mContextFixture.addCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE); - // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfo("test3", null, 1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - mContextFixture.removeCallingOrSelfPermission( - android.Manifest.permission.MODIFY_PHONE_STATE); - // As sub2 is inactive, it will checks carrier privilege against access rules in the db. - doReturn(true).when(mSubscriptionManager).canManageSubscription( - eq(subInfoList.get(1)), anyString()); - - ParcelUuid newGroupId = mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, mContext.getOpPackageName()); - assertNotEquals(null, newGroupId); - assertNotEquals(groupId, newGroupId); - } - - @Test - @SmallTest - @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testAddSubscriptionIntoGroupWithCarrierPrivilegePermission() throws Exception { - testInsertSim(); - // Adding a second profile and mark as embedded. - // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfo("test2", null, 1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - ContentValues values = new ContentValues(); - values.put(SubscriptionManager.IS_EMBEDDED, 1); - mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null); - mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList(); - - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); - - // Create group for sub 1. - int[] subIdList = new int[] {1}; - doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); - doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1); - ParcelUuid groupId = mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, "packageName1"); - - // Try to add sub 2 into group of sub 1. - // Should fail as it doesn't have carrier privilege on sub 2. - try { - mSubscriptionControllerUT.addSubscriptionsIntoGroup( - new int[] {2}, groupId, "packageName1"); - fail("addSubscriptionsIntoGroup should fail with no permission on sub 2."); - } catch (SecurityException e) { - // Expected result. - } - - doReturn(false).when(mTelephonyManager).hasCarrierPrivileges(1); - doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(2); - // Try to add sub 2 into group of sub 1. - // Should fail as it doesn't have carrier privilege on sub 1. - try { - mSubscriptionControllerUT.addSubscriptionsIntoGroup( - new int[] {2}, groupId, "packageName2"); - fail("addSubscriptionsIntoGroup should fail with no permission on the group (sub 1)."); - } catch (SecurityException e) { - // Expected result. - } - - doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1); - mSubscriptionControllerUT.addSubscriptionsIntoGroup(new int[] {2}, groupId, "packageName2"); - List infoList = mSubscriptionControllerUT - .getSubscriptionsInGroup(groupId, "packageName2", "feature2"); - assertEquals(2, infoList.size()); - } - - @Test - @SmallTest - @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testUpdateSubscriptionGroupWithCarrierPrivilegePermission() throws Exception { - testInsertSim(); - // Adding a second profile and mark as embedded. - // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfo("test2", null, 1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - ContentValues values = new ContentValues(); - values.put(SubscriptionManager.IS_EMBEDDED, 1); - mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null); - mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList(); - - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); - - int[] subIdList = new int[] {1}; - - doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); - doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(1); - doReturn(true).when(mTelephonyManager).hasCarrierPrivileges(2); - - ParcelUuid groupId = mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, "packageName1"); - assertNotEquals(null, groupId); - - mSubscriptionControllerUT.addSubscriptionsIntoGroup( - new int[] {2}, groupId, "packageName1"); - List infoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupId, "packageName1", "feature1"); - assertEquals(2, infoList.size()); - assertEquals(1, infoList.get(0).getSubscriptionId()); - assertEquals(2, infoList.get(1).getSubscriptionId()); - - mSubscriptionControllerUT.removeSubscriptionsFromGroup( - new int[] {2}, groupId, "packageName1"); - infoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupId, "packageName1", "feature1"); - assertEquals(1, infoList.size()); - assertEquals(1, infoList.get(0).getSubscriptionId()); - - // Make sub 1 inactive. - mSubscriptionControllerUT.clearSubInfoRecord(0); - - try { - mSubscriptionControllerUT.addSubscriptionsIntoGroup( - new int[] {2}, groupId, "packageName2"); - fail("addSubscriptionsIntoGroup should fail with wrong callingPackage name"); - } catch (SecurityException e) { - // Expected result. - } - - // Adding and removing subscription should still work for packageName1, as it's the group - // owner who created the group earlier.. - mSubscriptionControllerUT.addSubscriptionsIntoGroup( - new int[] {2}, groupId, "packageName1"); - infoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupId, "packageName1", "feature1"); - assertEquals(2, infoList.size()); - assertEquals(1, infoList.get(0).getSubscriptionId()); - assertEquals(2, infoList.get(1).getSubscriptionId()); - - mSubscriptionControllerUT.removeSubscriptionsFromGroup( - new int[] {2}, groupId, "packageName1"); - infoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupId, "packageName1", "feature1"); - assertEquals(1, infoList.size()); - assertEquals(1, infoList.get(0).getSubscriptionId()); - } - - @Test - @SmallTest - public void testDisabledSubscriptionGroup() throws Exception { - registerMockTelephonyRegistry(); - - testInsertSim(); - // Adding a second profile and mark as embedded. - mSubscriptionControllerUT.addSubInfo("test2", null, 0, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - ContentValues values = new ContentValues(); - values.put(SubscriptionManager.IS_EMBEDDED, 1); - values.put(SubscriptionManager.IS_OPPORTUNISTIC, 1); - mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null); - mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList(); - mSubscriptionControllerUT.notifySubscriptionInfoChanged(); - - verify(mTelephonyRegistryManager, times(1)) - .notifyOpportunisticSubscriptionInfoChanged(); - - // Set sub 1 and 2 into same group. - int[] subIdList = new int[] {1, 2}; - ParcelUuid groupId = mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, mContext.getOpPackageName()); - assertNotEquals(null, groupId); - - mSubscriptionControllerUT.notifySubscriptionInfoChanged(); - verify(mTelephonyRegistryManager, times(2)) - .notifyOpportunisticSubscriptionInfoChanged(); - List opptSubList = mSubscriptionControllerUT - .getOpportunisticSubscriptions(mCallingPackage, mCallingFeature); - assertEquals(1, opptSubList.size()); - assertEquals(2, opptSubList.get(0).getSubscriptionId()); - assertEquals(false, opptSubList.get(0).isGroupDisabled()); - - // Unplug SIM 1. This should trigger subscription controller disabling sub 2. - values = new ContentValues(); - values.put(SubscriptionManager.SIM_SLOT_INDEX, -1); - mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 1, null); - mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList(); - mSubscriptionControllerUT.notifySubscriptionInfoChanged(); - - verify(mTelephonyRegistryManager, times(3)) - .notifyOpportunisticSubscriptionInfoChanged(); - opptSubList = mSubscriptionControllerUT.getOpportunisticSubscriptions(mCallingPackage, - mCallingFeature); - assertEquals(1, opptSubList.size()); - assertEquals(2, opptSubList.get(0).getSubscriptionId()); - assertEquals(true, opptSubList.get(0).isGroupDisabled()); - } - - @Test - @SmallTest - @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testSetSubscriptionGroup() throws Exception { - testInsertSim(); - // Adding a second profile and mark as embedded. - mSubscriptionControllerUT.addSubInfo("test2", null, 1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - ContentValues values = new ContentValues(); - values.put(SubscriptionManager.IS_EMBEDDED, 1); - mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values, - SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null); - mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList(); - - assertTrue(mSubscriptionControllerUT.isActiveSubId(1)); - assertTrue(mSubscriptionControllerUT.isActiveSubId(2)); - assertTrue(TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, 1, - mContext.getOpPackageName(), mContext.getAttributionTag(), - "getSubscriptionsInGroup")); - - int[] subIdList = new int[] {1}; - ParcelUuid groupUuid = mSubscriptionControllerUT.createSubscriptionGroup( - subIdList, mContext.getOpPackageName()); - assertNotEquals(null, groupUuid); - - // Sub 1 and sub 2 should be in same group. - doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); - List infoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupUuid, mContext.getOpPackageName(), mContext.getAttributionTag()); - assertNotEquals(null, infoList); - assertEquals(1, infoList.size()); - assertEquals(1, infoList.get(0).getSubscriptionId()); - - subIdList = new int[] {2}; - - mSubscriptionControllerUT.addSubscriptionsIntoGroup( - subIdList, groupUuid, mContext.getOpPackageName()); - infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, - mContext.getOpPackageName(), mContext.getAttributionTag()); - assertEquals(2, infoList.size()); - assertEquals(2, infoList.get(1).getSubscriptionId()); - - // Remove group of sub 1. - subIdList = new int[] {1}; - mSubscriptionControllerUT.removeSubscriptionsFromGroup( - subIdList, groupUuid, mContext.getOpPackageName()); - infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, - mContext.getOpPackageName(), mContext.getAttributionTag()); - assertEquals(1, infoList.size()); - assertEquals(2, infoList.get(0).getSubscriptionId()); - - // Adding sub 1 into a non-existing UUID, which should be granted. - groupUuid = new ParcelUuid(UUID.randomUUID()); - mSubscriptionControllerUT.addSubscriptionsIntoGroup( - subIdList, groupUuid, mContext.getOpPackageName()); - infoList = mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, - mContext.getOpPackageName(), mContext.getAttributionTag()); - assertEquals(1, infoList.size()); - assertEquals(1, infoList.get(0).getSubscriptionId()); - } - - private void registerMockTelephonyRegistry() { - mServiceManagerMockedServices.put("telephony.registry", mTelephonyRegistryMock); - doReturn(mTelephonyRegistryMock).when(mTelephonyRegistryMock) - .queryLocalInterface(anyString()); - } - - @Test - @SmallTest - public void testEnableDisableSubscriptionSanity() throws Exception { - testInsertSim(); - - // Non existing subId. - assertFalse(mSubscriptionControllerUT.isSubscriptionEnabled(2)); - - // Test invalid arguments. - try { - assertFalse(mSubscriptionControllerUT.isSubscriptionEnabled(-1)); - fail("Should throw IllegalArgumentException with invalid subId."); - } catch (IllegalArgumentException exception) { - // Expected. - } - - try { - mSubscriptionControllerUT.getEnabledSubscriptionId(3); - fail("Should throw IllegalArgumentException with invalid subId."); - } catch (IllegalArgumentException exception) { - // Expected. - } - } - - @Test - @SmallTest - public void testGetActiveSubIdList() throws Exception { - // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfo("123", null, 1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 1 - mSubscriptionControllerUT.addSubInfo("456", null, 0, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 2 - - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - // Make sure the return sub ids are sorted by slot index - assertTrue("active sub ids = " + Arrays.toString(subIds), - Arrays.equals(subIds, new int[]{2, 1})); - } - - @Test - public void testGetActiveSubscriptionInfoWithNoPermissions() throws Exception { - // If the calling package does not have the READ_PHONE_STATE permission or carrier - // privileges then getActiveSubscriptionInfo should throw a SecurityException; - testInsertSim(); - setupReadPrivilegePermission(); - int subId = getFirstSubId(); - removeReadPrivilegePermission(); - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - - try { - mSubscriptionControllerUT.getActiveSubscriptionInfo(subId, mCallingPackage, - mCallingFeature); - fail("getActiveSubscriptionInfo should fail when invoked with no permissions"); - } catch (SecurityException expected) { - } - } - - @Test - public void testGetActiveSubscriptionInfoWithReadPhoneState() throws Exception { - // If the calling package only has the READ_PHONE_STATE permission then - // getActiveSubscriptionInfo should still return a result but the ICC ID should not be - // available via getIccId or getCardString. - testInsertSim(); - setupReadPhoneNumbersTest(); - setIdentifierAccess(false); - setupReadPrivilegePermission(); - int subId = getFirstSubId(); - - SubscriptionInfo subscriptionInfo = mSubscriptionControllerUT.getActiveSubscriptionInfo( - subId, mCallingPackage, mCallingFeature); - - assertNotNull(subscriptionInfo); - assertEquals(UNAVAILABLE_ICCID, subscriptionInfo.getIccId()); - assertEquals(UNAVAILABLE_ICCID, subscriptionInfo.getCardString()); - assertEquals(UNAVAILABLE_NUMBER, subscriptionInfo.getNumber()); - } - - @Test - public void testGetActiveSubscriptionWithPhoneNumberAccess() throws Exception { - // If the calling package meets any of the requirements for the - // LegacyPermissionManager#checkPhoneNumberAccess test then the number should be available - // in the SubscriptionInfo. - testInsertSim(); - setupReadPhoneNumbersTest(); - setPhoneNumberAccess(PackageManager.PERMISSION_GRANTED); - setupReadPrivilegePermission(); - int subId = getFirstSubId(); - - SubscriptionInfo subscriptionInfo = mSubscriptionControllerUT.getActiveSubscriptionInfo( - subId, mCallingPackage, mCallingFeature); - - assertNotNull(subscriptionInfo); - assertEquals(DISPLAY_NUMBER, subscriptionInfo.getNumber()); - } - - @Test - public void testGetActiveSubscriptionInfoWithCarrierPrivileges() throws Exception { - // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier - // privileges the ICC ID should be available in the SubscriptionInfo. - testInsertSim(); - setupIdentifierCarrierPrivilegesTest(); - setupReadPrivilegePermission(); - int subId = getFirstSubId(); - - SubscriptionInfo subscriptionInfo = mSubscriptionControllerUT.getActiveSubscriptionInfo( - subId, mCallingPackage, mCallingFeature); - - assertNotNull(subscriptionInfo); - assertTrue(subscriptionInfo.getIccId().length() > 0); - assertTrue(subscriptionInfo.getCardString().length() > 0); - } - - @Test - public void testGetActiveSubscriptionWithPrivilegedPermission() throws Exception { - // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier - // privileges the ICC ID should be available in the SubscriptionInfo. - testInsertSim(); - int subId = getFirstSubId(); - - SubscriptionInfo subscriptionInfo = mSubscriptionControllerUT.getActiveSubscriptionInfo( - subId, mCallingPackage, mCallingFeature); - - assertNotNull(subscriptionInfo); - assertTrue(subscriptionInfo.getIccId().length() > 0); - assertTrue(subscriptionInfo.getCardString().length() > 0); - } - - @Test - public void testGetActiveSubscriptionInfoForSimSlotIndexWithNoPermission() throws Exception { - // If the calling package does not have the READ_PHONE_STATE permission or carrier - // privileges then getActiveSubscriptionInfoForSimSlotIndex should throw a - // SecurityException. - testInsertSim(); - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - - try { - mSubscriptionControllerUT.getActiveSubscriptionInfoForSimSlotIndex(0, mCallingPackage, - mCallingFeature); - fail("getActiveSubscriptionInfoForSimSlotIndex should fail when invoked with no " - + "permissions"); - } catch (SecurityException expected) { - } - } - - @Test - public void testGetActiveSubscriptionInfoForSimSlotIndexWithReadPhoneState() throws Exception { - // If the calling package only has the READ_PHONE_STATE permission then - // getActiveSubscriptionInfoForSimlSlotIndex should still return the SubscriptionInfo but - // the ICC ID should not be available via getIccId or getCardString. - testInsertSim(); - setupReadPhoneNumbersTest(); - setIdentifierAccess(false); - - SubscriptionInfo subscriptionInfo = - mSubscriptionControllerUT.getActiveSubscriptionInfoForSimSlotIndex(0, - mCallingPackage, mCallingFeature); - - assertNotNull(subscriptionInfo); - assertEquals(UNAVAILABLE_ICCID, subscriptionInfo.getIccId()); - assertEquals(UNAVAILABLE_ICCID, subscriptionInfo.getCardString()); - assertEquals(UNAVAILABLE_NUMBER, subscriptionInfo.getNumber()); - } - - @Test - public void testGetActiveSubscriptionInfoForSimSlotIndexWithPhoneNumberAccess() - throws Exception { - // If the calling package meets any of the requirements for the - // LegacyPermissionManager#checkPhoneNumberAccess test then the number should be available - // in the SubscriptionInfo. - testInsertSim(); - setupReadPhoneNumbersTest(); - setPhoneNumberAccess(PackageManager.PERMISSION_GRANTED); - - SubscriptionInfo subscriptionInfo = - mSubscriptionControllerUT.getActiveSubscriptionInfoForSimSlotIndex(0, - mCallingPackage, mCallingFeature); - - assertNotNull(subscriptionInfo); - assertEquals(DISPLAY_NUMBER, subscriptionInfo.getNumber()); - } - - @Test - public void testGetActiveSubscriptionInfoForSimSlotIndexWithCarrierPrivileges() - throws Exception { - // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier - // privileges the ICC ID should be available in the SubscriptionInfo. - testInsertSim(); - setupIdentifierCarrierPrivilegesTest(); - - SubscriptionInfo subscriptionInfo = - mSubscriptionControllerUT.getActiveSubscriptionInfoForSimSlotIndex(0, - mCallingPackage, mCallingFeature); - - assertNotNull(subscriptionInfo); - assertTrue(subscriptionInfo.getIccId().length() > 0); - assertTrue(subscriptionInfo.getCardString().length() > 0); - } - - @Test - public void testGetActiveSubscriptionInfoForSimSlotIndexWithPrivilegedPermission() - throws Exception { - // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier - // privileges the ICC ID should be available in the SubscriptionInfo. - testInsertSim(); - - SubscriptionInfo subscriptionInfo = - mSubscriptionControllerUT.getActiveSubscriptionInfoForSimSlotIndex(0, - mCallingPackage, mCallingFeature); - - assertNotNull(subscriptionInfo); - assertTrue(subscriptionInfo.getIccId().length() > 0); - assertTrue(subscriptionInfo.getCardString().length() > 0); - } - - @Test - public void testGetActiveSubscriptionInfoListWithNoPermission() throws Exception { - // If the calling package does not have the READ_PHONE_STATE permission or carrier - // privileges then getActiveSubscriptionInfoList should return a list with 0 elements. - testInsertSim(); - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - - List subInfoList = - mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage, - mCallingFeature); - - assertNotNull(subInfoList); - assertTrue(subInfoList.size() == 0); - } - - @Test - public void testGetActiveSubscriptionInfoListWithReadPhoneState() throws Exception { - // If the calling package only has the READ_PHONE_STATE permission then - // getActiveSubscriptionInfoList should still return the list of SubscriptionInfo objects - // but the ICC ID should not be available via getIccId or getCardString. - testInsertSim(); - setupReadPhoneNumbersTest(); - setIdentifierAccess(false); - - List subInfoList = - mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage, - mCallingFeature); - - assertTrue(subInfoList.size() > 0); - for (SubscriptionInfo info : subInfoList) { - assertEquals(UNAVAILABLE_ICCID, info.getIccId()); - assertEquals(UNAVAILABLE_ICCID, info.getCardString()); - assertEquals(UNAVAILABLE_NUMBER, info.getNumber()); - } - } - - @Test - public void testGetActiveSubscriptionInfoListWithPhoneNumberAccess() throws Exception { - // If the calling package meets any of the requirements for the - // LegacyPermissionManager#checkPhoneNumberAccess test then the number should be available - // in the SubscriptionInfo. - testInsertSim(); - setupReadPhoneNumbersTest(); - setPhoneNumberAccess(PackageManager.PERMISSION_GRANTED); - - List subInfoList = - mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage, - mCallingFeature); - - assertTrue(subInfoList.size() > 0); - SubscriptionInfo subInfo = subInfoList.get(0); - assertEquals(DISPLAY_NUMBER, subInfo.getNumber()); - } - - @Test - public void testGetActiveSubscriptionInfoListWithCarrierPrivileges() throws Exception { - // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier - // privileges the ICC ID should be available in the SubscriptionInfo objects in the List. - testInsertSim(); - setupIdentifierCarrierPrivilegesTest(); - - List subInfoList = - mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage, - mCallingFeature); - - assertTrue(subInfoList.size() > 0); - for (SubscriptionInfo info : subInfoList) { - assertTrue(info.getIccId().length() > 0); - assertTrue(info.getCardString().length() > 0); - } - } - - @Test - public void testGetActiveSubscriptionInfoListWithCarrierPrivilegesOnOneSubId() - throws Exception { - // If an app does not have the READ_PHONE_STATE permission but has carrier privileges on one - // out of multiple sub IDs then the SubscriptionInfo for that subId should be returned with - // the ICC ID and phone number. - testInsertSim(); - doReturn(2).when(mTelephonyManager).getPhoneCount(); - mSubscriptionControllerUT.addSubInfo("test2", null, 1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - int firstSubId = getFirstSubId(); - int secondSubId = getSubIdAtIndex(1); - mSubscriptionControllerUT.setDisplayNumber(DISPLAY_NUMBER, secondSubId); - setupIdentifierCarrierPrivilegesTest(); - mContextFixture.removeCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); - setCarrierPrivilegesForSubId(false, firstSubId); - setCarrierPrivilegesForSubId(true, secondSubId); - - List subInfoList = - mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage, - mCallingFeature); - - assertEquals(1, subInfoList.size()); - SubscriptionInfo subInfo = subInfoList.get(0); - assertEquals("test2", subInfo.getIccId()); - assertEquals(DISPLAY_NUMBER, subInfo.getNumber()); - } - - @Test - public void testGetActiveSubscriptionInfoListCheckOrder() - throws Exception { - // If an app does not have the READ_PHONE_STATE permission but has carrier privileges on one - // out of multiple sub IDs then the SubscriptionInfo for that subId should be returned with - // the ICC ID and phone number. - testInsertSim(); - doReturn(2).when(mTelephonyManager).getPhoneCount(); - mSubscriptionControllerUT.addSubInfo("test2", null, 1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - int firstSubId = getFirstSubId(); - int secondSubId = getSubIdAtIndex(1); - setupIdentifierCarrierPrivilegesTest(); - setCarrierPrivilegesForSubId(false, firstSubId); - setCarrierPrivilegesForSubId(true, secondSubId); - - List subInfoList = - mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage, - mCallingFeature); - - assertEquals(2, subInfoList.size()); - assertTrue(subInfoList.get(0).getSubscriptionId() < subInfoList.get(1).getSubscriptionId()); - } - - @Test - public void testGetActiveSubscriptionInfoListWithIdentifierAccessWithoutNumberAccess() - throws Exception { - // An app with access to device identifiers may not have access to the device phone number - // (ie an app that passes the device / profile owner check or an app that has been granted - // the device identifiers appop); this test verifies that an app with identifier access - // can read the ICC ID but does not receive the phone number. - testInsertSim(); - setupReadPhoneNumbersTest(); - setIdentifierAccess(true); - - List subInfoList = - mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage, - mCallingFeature); - - assertEquals(1, subInfoList.size()); - SubscriptionInfo subInfo = subInfoList.get(0); - assertEquals("test", subInfo.getIccId()); - assertEquals(UNAVAILABLE_NUMBER, subInfo.getNumber()); - } - - @Test - public void testGetActiveSubscriptionInfoListWithPrivilegedPermission() throws Exception { - // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier - // privileges the ICC ID should be available in the SubscriptionInfo objects in the List. - testInsertSim(); - - List subInfoList = - mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage, - mCallingFeature); - - assertTrue(subInfoList.size() > 0); - for (SubscriptionInfo info : subInfoList) { - assertTrue(info.getIccId().length() > 0); - assertTrue(info.getCardString().length() > 0); - } - } - - @Test - @DisableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testGetSubscriptionsInGroupWithReadPhoneState() throws Exception { - // For backward compatibility test - ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); - setupReadPhoneNumbersTest(); - setIdentifierAccess(false); - - List subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupUuid, mCallingPackage, mCallingFeature); - - assertTrue(subInfoList.size() > 0); - for (SubscriptionInfo info : subInfoList) { - assertEquals(UNAVAILABLE_ICCID, info.getIccId()); - assertEquals(UNAVAILABLE_ICCID, info.getCardString()); - assertEquals(UNAVAILABLE_NUMBER, info.getNumber()); - } - } - - @Test - @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testGetSubscriptionsInGroupWithoutAppropriatePermission() throws Exception { - ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); - - // no permission - setNoPermission(); - try { - mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage, - mCallingFeature); - fail("getSubscriptionsInGroup should fail when invoked with no permissions"); - } catch (SecurityException expected) { - } - - // only has the USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permission - setIdentifierAccess(true); - try { - mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage, - mCallingFeature); - fail("getSubscriptionsInGroup should fail when invoked with no" - + "READ_PHONE_STATE permissions"); - } catch (SecurityException expected) { - } - - // only has the READ_PHONE_STATE permission - setIdentifierAccess(false); - setReadPhoneState(); - try { - mSubscriptionControllerUT.getSubscriptionsInGroup(groupUuid, mCallingPackage, - mCallingFeature); - fail("getSubscriptionsInGroup should fail when invoked with no " - + "USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permissions"); - } catch (SecurityException expected) { - } - } - - @Test - @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testGetSubscriptionsInGroupWithReadDeviceIdentifier() throws Exception { - ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); - setNoPermission(); - setCarrierPrivileges(false); - setIdentifierAccess(true); - setReadPhoneState(); - - List subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupUuid, mCallingPackage, mCallingFeature); - - assertTrue(subInfoList.size() > 0); - for (SubscriptionInfo info : subInfoList) { - assertTrue(info.getIccId().length() > 0); - assertTrue(info.getCardString().length() > 0); - } - } - - private void setNoPermission() { - doThrow(new SecurityException()).when(mContext) - .enforcePermission(anyString(), anyInt(), anyInt(), anyString()); - } - - private void setReadPhoneState() { - doNothing().when(mContext).enforcePermission( - eq(android.Manifest.permission.READ_PHONE_STATE), anyInt(), anyInt(), anyString()); - } - - @Test - @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testGetSubscriptionInGroupWithPhoneNumberAccess() throws Exception { - // If the calling package meets any of the requirements for the - // LegacyPermissionManager#checkPhoneNumberAccess test then the number should be available - // in the SubscriptionInfo. - ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); - setupReadPhoneNumbersTest(); - setPhoneNumberAccess(PackageManager.PERMISSION_GRANTED); - - List subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupUuid, mCallingPackage, mCallingFeature); - - assertTrue(subInfoList.size() > 0); - SubscriptionInfo subInfo = subInfoList.get(0); - assertEquals(DISPLAY_NUMBER, subInfo.getNumber()); - } - - @Test - @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testGetSubscriptionsInGroupWithCarrierPrivileges() throws Exception { - // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier - // privileges the ICC ID should be available in the SubscriptionInfo objects in the List. - ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); - setupIdentifierCarrierPrivilegesTest(); - - List subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupUuid, mCallingPackage, mCallingFeature); - - assertTrue(subInfoList.size() > 0); - for (SubscriptionInfo info : subInfoList) { - assertTrue(info.getIccId().length() > 0); - assertTrue(info.getCardString().length() > 0); - } - } - - @Test - @EnableCompatChanges({REQUIRE_DEVICE_IDENTIFIERS_FOR_GROUP_UUID}) - public void testGetSubscriptionsInGroupWithPrivilegedPermission() throws Exception { - // If the calling package has the READ_PRIVILEGED_PHONE_STATE permission or carrier - // privileges the ICC ID should be available in the SubscriptionInfo objects in the List. - ParcelUuid groupUuid = setupGetSubscriptionsInGroupTest(); - - List subInfoList = mSubscriptionControllerUT.getSubscriptionsInGroup( - groupUuid, mCallingPackage, mCallingFeature); - - assertTrue(subInfoList.size() > 0); - for (SubscriptionInfo info : subInfoList) { - assertTrue(info.getIccId().length() > 0); - assertTrue(info.getCardString().length() > 0); - } - } - - private ParcelUuid setupGetSubscriptionsInGroupTest() throws Exception { - testInsertSim(); - int[] subIdList = new int[]{getFirstSubId()}; - ParcelUuid groupUuid = mSubscriptionControllerUT.createSubscriptionGroup(subIdList, - mCallingPackage); - assertNotNull(groupUuid); - doReturn(subIdList).when(mSubscriptionManager).getCompleteActiveSubscriptionIdList(); - return groupUuid; - } - - private void setupReadPhoneNumbersTest() throws Exception { - mSubscriptionControllerUT.setDisplayNumber(DISPLAY_NUMBER, getFirstSubId()); - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); - setupMocksForTelephonyPermissions(Build.VERSION_CODES.R); - setPhoneNumberAccess(PackageManager.PERMISSION_DENIED); - } - - private void setupIdentifierCarrierPrivilegesTest() throws Exception { - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PHONE_STATE); - setupMocksForTelephonyPermissions(); - setIdentifierAccess(false); - setCarrierPrivileges(true); - } - - private void setupReadPrivilegePermission() throws Exception { - mContextFixture.addCallingOrSelfPermissionToCurrentPermissions( - Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - } - private void removeReadPrivilegePermission() throws Exception { - mContextFixture.removeCallingOrSelfPermission( - Manifest.permission.READ_PRIVILEGED_PHONE_STATE); - } - - private int getFirstSubId() throws Exception { - return getSubIdAtIndex(0); - } - - private int getSubIdAtIndex(int index) throws Exception { - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibileOnly*/false); - assertTrue(subIds != null && subIds.length > index); - return subIds[index]; - } - - @Test - public void testGetEnabledSubscriptionIdSingleSIM() { - // A single SIM device may have logical slot 0 mapped to physical slot 1 - // (i.e. logical slot -1 mapped to physical slot 0) - UiccSlotInfo slot0 = getFakeUiccSlotInfo(false, -1, null); - UiccSlotInfo slot1 = getFakeUiccSlotInfo(true, 0, null); - UiccSlotInfo [] uiccSlotInfos = {slot0, slot1}; - UiccSlot [] uiccSlots = {mUiccSlot, mUiccSlot}; - - doReturn(uiccSlotInfos).when(mTelephonyManager).getUiccSlotsInfo(); - doReturn(uiccSlots).when(mUiccController).getUiccSlots(); - assertEquals(2, UiccController.getInstance().getUiccSlots().length); - - ContentResolver resolver = mContext.getContentResolver(); - // logical 0 should find physical 1, has settings enabled subscription 0 - Settings.Global.putInt(resolver, Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT + 1, 0); - - int enabledSubscription = mSubscriptionControllerUT.getEnabledSubscriptionId(0); - assertEquals(0, enabledSubscription); - } - - @Test - public void testGetEnabledSubscriptionIdDualSIM() { - doReturn(SINGLE_SIM).when(mTelephonyManager).getSimCount(); - doReturn(SINGLE_SIM).when(mTelephonyManager).getPhoneCount(); - doReturn(SINGLE_SIM).when(mTelephonyManager).getActiveModemCount(); - // A dual SIM device may have logical slot 0 mapped to physical slot 0 - // (i.e. logical slot 1 mapped to physical slot 1) - UiccSlotInfo slot0 = getFakeUiccSlotInfo(true, 0, null); - UiccSlotInfo slot1 = getFakeUiccSlotInfo(true, 1, null); - UiccSlotInfo [] uiccSlotInfos = {slot0, slot1}; - UiccSlot [] uiccSlots = {mUiccSlot, mUiccSlot}; - - doReturn(2).when(mTelephonyManager).getPhoneCount(); - doReturn(2).when(mTelephonyManager).getActiveModemCount(); - doReturn(uiccSlotInfos).when(mTelephonyManager).getUiccSlotsInfo(); - doReturn(uiccSlots).when(mUiccController).getUiccSlots(); - assertEquals(2, UiccController.getInstance().getUiccSlots().length); - - ContentResolver resolver = mContext.getContentResolver(); - // logical 0 should find physical 0, has settings enabled subscription 0 - Settings.Global.putInt(resolver, Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT + 0, 0); - Settings.Global.putInt(resolver, Settings.Global.ENABLED_SUBSCRIPTION_FOR_SLOT + 1, 1); - - int enabledSubscription = mSubscriptionControllerUT.getEnabledSubscriptionId(0); - int secondEabledSubscription = mSubscriptionControllerUT.getEnabledSubscriptionId(1); - assertEquals(0, enabledSubscription); - assertEquals(1, secondEabledSubscription); - } - - - private UiccSlotInfo getFakeUiccSlotInfo(boolean active, int logicalSlotIndex, String iccId) { - return getFakeUiccSlotInfo(active, logicalSlotIndex, "fake card Id", iccId); - } - - private UiccSlotInfo getFakeUiccSlotInfo( - boolean active, int logicalSlotIndex, String cardId, String iccId) { - return new UiccSlotInfo(false, cardId, - UiccSlotInfo.CARD_STATE_INFO_PRESENT, true, true, - Collections.singletonList( - new UiccPortInfo(iccId, 0, logicalSlotIndex, active) - )); - } - - @Test - @SmallTest - public void testNameSourcePriority() throws Exception { - assertTrue(mSubscriptionControllerUT.getNameSourcePriority( - SubscriptionManager.NAME_SOURCE_USER_INPUT) - > mSubscriptionControllerUT.getNameSourcePriority( - SubscriptionManager.NAME_SOURCE_CARRIER)); - - assertTrue(mSubscriptionControllerUT.getNameSourcePriority( - SubscriptionManager.NAME_SOURCE_CARRIER) - > mSubscriptionControllerUT.getNameSourcePriority( - SubscriptionManager.NAME_SOURCE_SIM_SPN)); - - assertTrue(mSubscriptionControllerUT.getNameSourcePriority( - SubscriptionManager.NAME_SOURCE_SIM_SPN) - > mSubscriptionControllerUT.getNameSourcePriority( - SubscriptionManager.NAME_SOURCE_SIM_PNN)); - - assertTrue(mSubscriptionControllerUT.getNameSourcePriority( - SubscriptionManager.NAME_SOURCE_SIM_PNN) - > mSubscriptionControllerUT.getNameSourcePriority( - SubscriptionManager.NAME_SOURCE_CARRIER_ID)); - } - - @Test - @SmallTest - public void testGetAvailableSubscriptionList() throws Exception { - // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfo("123", null, 1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 1 - mSubscriptionControllerUT.addSubInfo("456", null, 0, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 2 - - List infoList = mSubscriptionControllerUT - .getAvailableSubscriptionInfoList(mCallingPackage, mCallingFeature); - assertEquals(2, infoList.size()); - assertEquals("456", infoList.get(0).getIccId()); - assertEquals("123", infoList.get(1).getIccId()); - - // Remove "123" from active sim list but have it inserted. - UiccSlot[] uiccSlots = {mUiccSlot}; - IccCardStatus.CardState cardState = CARDSTATE_PRESENT; - doReturn(uiccSlots).when(mUiccController).getUiccSlots(); - doReturn(cardState).when(mUiccSlot).getCardState(); - doReturn("123").when(mUiccSlot).getIccId(0); // default port index - mSubscriptionControllerUT.clearSubInfoRecord(1); - - // Active sub list should return 1 now. - infoList = mSubscriptionControllerUT - .getActiveSubscriptionInfoList(mCallingPackage, mCallingFeature); - assertEquals(1, infoList.size()); - assertEquals("456", infoList.get(0).getIccId()); - - // Available sub list should still return two. - infoList = mSubscriptionControllerUT - .getAvailableSubscriptionInfoList(mCallingPackage, mCallingFeature); - assertEquals(2, infoList.size()); - assertEquals("123", infoList.get(0).getIccId()); - assertEquals("456", infoList.get(1).getIccId()); - } - - @Test - @SmallTest - public void testGetAvailableSubscriptionList_withTrailingF() throws Exception { - // TODO b/123300875 slot index 1 is not expected to be valid - mSubscriptionControllerUT.addSubInfo("123", null, 1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 1 - mSubscriptionControllerUT.addSubInfo("456", null, 0, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); // sub 2 - - // Remove "123" from active sim list but have it inserted. - UiccSlot[] uiccSlots = {mUiccSlot}; - IccCardStatus.CardState cardState = CARDSTATE_PRESENT; - doReturn(uiccSlots).when(mUiccController).getUiccSlots(); - doReturn(cardState).when(mUiccSlot).getCardState(); - // IccId ends with a 'F' which should be ignored and taking into account. - doReturn("123F").when(mUiccSlot).getIccId(0); // default port index - - mSubscriptionControllerUT.clearSubInfoRecord(1); - - // Active sub list should return 1 now. - List infoList = mSubscriptionControllerUT - .getActiveSubscriptionInfoList(mCallingPackage, mCallingFeature); - assertEquals(1, infoList.size()); - assertEquals("456", infoList.get(0).getIccId()); - - // Available sub list should still return two. - infoList = mSubscriptionControllerUT - .getAvailableSubscriptionInfoList(mCallingPackage, mCallingFeature); - assertEquals(2, infoList.size()); - assertEquals("123", infoList.get(0).getIccId()); - assertEquals("456", infoList.get(1).getIccId()); - } - - @Test - @SmallTest - public void testSetPreferredDataSubscriptionId_phoneSwitcherNotInitialized() throws Exception { - replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, null); - - mSubscriptionControllerUT.setPreferredDataSubscriptionId(1, true, mSetOpptDataCallback); - verify(mSetOpptDataCallback).onComplete(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION); - } - - @Test - @SmallTest - public void testGetPreferredDataSubscriptionId_phoneSwitcherNotInitialized() throws Exception { - replaceInstance(PhoneSwitcher.class, "sPhoneSwitcher", null, null); - - assertEquals(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - mSubscriptionControllerUT.getPreferredDataSubscriptionId()); - } - - @Test - public void testSetSubscriptionEnabled_disableActivePsim_cardIdWithTrailingF() { - String iccId = "123F"; - mSubscriptionControllerUT.addSubInfo(iccId, null, 0, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - mSubscriptionControllerUT.registerForUiccAppsEnabled(mHandler, 0, null, false); - UiccSlotInfo slot = getFakeUiccSlotInfo(true, 0, iccId + "FF", iccId); - UiccSlotInfo[] uiccSlotInfos = {slot}; - doReturn(uiccSlotInfos).when(mTelephonyManager).getUiccSlotsInfo(); - - mSubscriptionControllerUT.setSubscriptionEnabled(false, 1); - verify(mHandler).sendMessageAtTime(any(), anyLong()); - assertFalse(mSubscriptionControllerUT.getActiveSubscriptionInfo( - 1, mContext.getOpPackageName(), null).areUiccApplicationsEnabled()); - } - - @Test - @SmallTest - public void testInsertEmptySubInfoRecord_returnsNull_ifRecordExists() { - final String mockedIccid = "123456789"; - final int mockedSlotIndex = 1; - - assertNotNull(mSubscriptionControllerUT.insertEmptySubInfoRecord( - mockedIccid, mockedSlotIndex)); - // Insert second time with the same iccid should result in no-op and return null. - assertNull(mSubscriptionControllerUT.insertEmptySubInfoRecord( - mockedIccid, mockedSlotIndex)); - assertEquals( - 1, - mSubscriptionControllerUT - .getAllSubInfoList(mCallingPackage, mCallingFeature).size()); - } - - @Test - @SmallTest - public void testCheckPhoneIdAndIccIdMatch() { - try { - testSetSubscriptionGroupWithModifyPermission(); - } catch (Exception e) { - fail("Unexpected exception: " + e); - } - - mSubscriptionControllerUT.addSubInfo("test3", null, - SubscriptionManager.INVALID_SIM_SLOT_INDEX, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM); - - assertTrue(mSubscriptionControllerUT.checkPhoneIdAndIccIdMatch(0, "test")); - assertTrue(mSubscriptionControllerUT.checkPhoneIdAndIccIdMatch(0, "test2")); - assertFalse(mSubscriptionControllerUT.checkPhoneIdAndIccIdMatch(0, "test3")); - } - - @Test - @SmallTest - public void testMessageRefDBFetchAndUpdate() throws Exception { - testInsertSim(); - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - final int subId = subIds[0]; - SubscriptionController.getInstance().updateMessageRef(subId, 201); - int messageRef = SubscriptionController.getInstance().getMessageRef(subId); - assertTrue("201 :", messageRef == 201); - } - - @Test - public void setSubscriptionUserHandle_withoutPermission() throws Exception { - testInsertSim(); - /* Get SUB ID */ - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - final int subId = subIds[0]; - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - - assertThrows(SecurityException.class, - () -> mSubscriptionControllerUT.setSubscriptionUserHandle( - UserHandle.of(UserHandle.USER_SYSTEM), subId)); - } - - @Test - public void setGetSubscriptionUserHandle_userHandleNull() throws Exception { - testInsertSim(); - /* Get SUB ID */ - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - final int subId = subIds[0]; - - mSubscriptionControllerUT.setSubscriptionUserHandle(null, subId); - - assertThat(mSubscriptionControllerUT.getSubscriptionUserHandle(subId)) - .isEqualTo(null); - } - - @Test - public void setSubscriptionUserHandle_invalidSubId() throws Exception { - assertThrows(IllegalArgumentException.class, - () -> mSubscriptionControllerUT.setSubscriptionUserHandle( - UserHandle.of(UserHandle.USER_SYSTEM), - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)); - } - - @Test - public void setGetSubscriptionUserHandle_withValidUserHandleAndSubId() throws Exception { - testInsertSim(); - /* Get SUB ID */ - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - final int subId = subIds[0]; - - mSubscriptionControllerUT.setSubscriptionUserHandle( - UserHandle.of(UserHandle.USER_SYSTEM), subId); - - assertThat(mSubscriptionControllerUT.getSubscriptionUserHandle(subId)) - .isEqualTo(UserHandle.of(UserHandle.USER_SYSTEM)); - } - - @Test - public void getSubscriptionUserHandle_withoutPermission() throws Exception { - testInsertSim(); - /* Get SUB ID */ - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - final int subId = subIds[0]; - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - - assertThrows(SecurityException.class, - () -> mSubscriptionControllerUT.getSubscriptionUserHandle(subId)); - } - - @Test - public void getSubscriptionUserHandle_invalidSubId() throws Exception { - assertThrows(IllegalArgumentException.class, - () -> mSubscriptionControllerUT.getSubscriptionUserHandle( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)); - } - - @Test - public void isSubscriptionAssociatedWithUser_withoutPermission() { - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - - assertThrows(SecurityException.class, - () -> mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(1, - UserHandle.of(UserHandle.USER_SYSTEM))); - } - - @Test - public void isSubscriptionAssociatedWithUser_noSubscription() throws Exception { - // isSubscriptionAssociatedWithUser should return true if there are no active subscriptions. - assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(1, - UserHandle.of(UserHandle.USER_SYSTEM))).isEqualTo(true); - } - - @Test - public void isSubscriptionAssociatedWithUser_unknownSubId() { - testInsertSim(); - /* Get SUB ID */ - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - int unknownSubId = 123; - - assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(unknownSubId, - UserHandle.of(UserHandle.USER_SYSTEM))).isEqualTo(false); - } - - @Test - public void isSubscriptionAssociatedWithUser_userAssociatedWithSubscription() throws Exception { - testInsertSim(); - /* Get SUB ID */ - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - final int subId = subIds[0]; - - mSubscriptionControllerUT.setSubscriptionUserHandle( - UserHandle.of(UserHandle.USER_SYSTEM), subId); - - assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(subId, - UserHandle.of(UserHandle.USER_SYSTEM))).isEqualTo(true); - } - - @Test - public void isSubscriptionAssociatedWithUser_userNotAssociatedWithSubscription() - throws Exception { - testInsertSim(); - /* Get SUB ID */ - int[] subIds = mSubscriptionControllerUT.getActiveSubIdList(/*visibleOnly*/false); - assertTrue(subIds != null && subIds.length != 0); - final int subId = subIds[0]; - - mSubscriptionControllerUT.setSubscriptionUserHandle(UserHandle.of(UserHandle.USER_SYSTEM), - subId); - - assertThat(mSubscriptionControllerUT.isSubscriptionAssociatedWithUser(subId, - UserHandle.of(10))).isEqualTo(false); - } - - - @Test - public void getSubscriptionInfoListAssociatedWithUser_withoutPermission() { - mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); - - assertThrows(SecurityException.class, - () -> mSubscriptionControllerUT.getSubscriptionInfoListAssociatedWithUser( - UserHandle.of(UserHandle.USER_SYSTEM))); - } - - @Test - public void getSubscriptionInfoListAssociatedWithUser_noSubscription() { - List associatedSubInfoList = mSubscriptionControllerUT - .getSubscriptionInfoListAssociatedWithUser(UserHandle.of(UserHandle.USER_SYSTEM)); - assertThat(associatedSubInfoList.size()).isEqualTo(0); - } -} \ No newline at end of file diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java deleted file mode 100644 index 32fb56ecb1..0000000000 --- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.telephony; - -import static android.telephony.SubscriptionManager.UICC_APPLICATIONS_ENABLED; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.annotation.Nullable; -import android.content.ContentProvider; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.pm.IPackageManager; -import android.content.pm.UserInfo; -import android.net.Uri; -import android.os.Bundle; -import android.os.Looper; -import android.os.ParcelUuid; -import android.os.PersistableBundle; -import android.service.euicc.EuiccProfileInfo; -import android.service.euicc.EuiccService; -import android.service.euicc.GetEuiccProfileInfoListResult; -import android.telephony.CarrierConfigManager; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.UiccAccessRule; -import android.test.mock.MockContentProvider; -import android.test.mock.MockContentResolver; -import android.test.suitebuilder.annotation.SmallTest; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import com.android.internal.telephony.euicc.EuiccController; -import com.android.internal.telephony.uicc.IccFileHandler; -import com.android.internal.telephony.uicc.IccRecords; -import com.android.internal.telephony.uicc.IccUtils; -import com.android.internal.telephony.uicc.UiccSlot; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; - -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class SubscriptionInfoUpdaterTest extends TelephonyTest { - private static final int FAKE_SUB_ID_1 = 0; - private static final int FAKE_SUB_ID_2 = 1; - private static final int FAKE_CARD_ID = 0; - private static final String FAKE_EID = "89049032000001000000031328322874"; - private static final String FAKE_ICCID_1 = "89012604200000000000"; - private static final String FAKE_MCC_MNC_1 = "123456"; - private static final String FAKE_MCC_MNC_2 = "456789"; - private static final int FAKE_PHONE_ID_1 = 0; - - private SubscriptionInfoUpdater mUpdater; - private IccRecords mIccRecord; - - // Mocked classes - private UserInfo mUserInfo; - private SubscriptionInfo mSubInfo; - private ContentProvider mContentProvider; - private HashMap mSubscriptionContent; - private IccFileHandler mIccFileHandler; - private EuiccController mEuiccController; - private IntentBroadcaster mIntentBroadcaster; - private IPackageManager mPackageManager; - private UiccSlot mUiccSlot; - - /*Custom ContentProvider */ - private class FakeSubscriptionContentProvider extends MockContentProvider { - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return mContentProvider.update(uri, values, selection, selectionArgs); - } - - @Override - public Bundle call(String method, @Nullable String args, @Nullable Bundle bundle) { - return new Bundle(); - } - } - - @Before - public void setUp() throws Exception { - super.setUp(getClass().getSimpleName()); - enableSubscriptionManagerService(false); - mUserInfo = mock(UserInfo.class); - mSubInfo = mock(SubscriptionInfo.class); - mContentProvider = mock(ContentProvider.class); - mSubscriptionContent = mock(HashMap.class); - mIccFileHandler = mock(IccFileHandler.class); - mEuiccController = mock(EuiccController.class); - mIntentBroadcaster = mock(IntentBroadcaster.class); - mPackageManager = mock(IPackageManager.class); - mUiccSlot = mock(UiccSlot.class); - - replaceInstance(SubscriptionInfoUpdater.class, "sIccId", null, new String[1]); - replaceInstance(SubscriptionInfoUpdater.class, "sContext", null, null); - replaceInstance(SubscriptionInfoUpdater.class, "SUPPORTED_MODEM_COUNT", null, 1); - replaceInstance(SubscriptionInfoUpdater.class, "sSimCardState", null, new int[1]); - replaceInstance(SubscriptionInfoUpdater.class, "sSimApplicationState", null, new int[1]); - replaceInstance(SubscriptionInfoUpdater.class, "sIsSubInfoInitialized", null, false); - - replaceInstance(EuiccController.class, "sInstance", null, mEuiccController); - replaceInstance(IntentBroadcaster.class, "sIntentBroadcaster", null, mIntentBroadcaster); - - doReturn(true).when(mUiccSlot).isActive(); - doReturn(mUiccSlot).when(mUiccController).getUiccSlotForPhone(anyInt()); - doReturn(1).when(mTelephonyManager).getSimCount(); - doReturn(1).when(mTelephonyManager).getPhoneCount(); - doReturn(1).when(mTelephonyManager).getActiveModemCount(); - - when(mContentProvider.update(any(), any(), any(), isNull())).thenAnswer( - new Answer() { - @Override - public Integer answer(InvocationOnMock invocation) throws Throwable { - ContentValues values = invocation.getArgument(1); - for (String key : values.keySet()) { - mSubscriptionContent.put(key, values.get(key)); - } - return 1; - } - }); - - doReturn(mUserInfo).when(mIActivityManager).getCurrentUser(); - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(0); - doReturn(new int[]{FAKE_SUB_ID_1}).when(mSubscriptionManager).getActiveSubscriptionIdList(); - ((MockContentResolver) mContext.getContentResolver()).addProvider( - SubscriptionManager.CONTENT_URI.getAuthority(), - new FakeSubscriptionContentProvider()); - doReturn(new int[]{}).when(mSubscriptionController) - .getActiveSubIdList(/*visibleOnly*/false); - mIccRecord = mUiccProfile.getIccRecords(); - - mUpdater = - new SubscriptionInfoUpdater(Looper.myLooper(), mContext, mSubscriptionController); - processAllMessages(); - - assertFalse(mUpdater.isSubInfoInitialized()); - } - - @After - public void tearDown() throws Exception { - mIccRecord = null; - mUpdater = null; - super.tearDown(); - } - - @Test - @SmallTest - public void testSimAbsent() throws Exception { - doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController) - .getSubInfoUsingSlotIndexPrivileged(eq(FAKE_SUB_ID_1)); - doReturn(new int[]{FAKE_SUB_ID_1}).when(mSubscriptionController) - .getActiveSubIdList(/*visibleOnly*/false); - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, FAKE_SUB_ID_1); - - processAllMessages(); - assertTrue(mUpdater.isSubInfoInitialized()); - verify(mSubscriptionController, times(1)).clearSubInfoRecord(eq(FAKE_SUB_ID_1)); - - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_ABSENT)); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - } - - @Test - @SmallTest - public void testSimAbsentAndInactive() throws Exception { - doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController) - .getSubInfoUsingSlotIndexPrivileged(eq(FAKE_SUB_ID_1)); - doReturn(new int[]{FAKE_SUB_ID_1}).when(mSubscriptionController) - .getActiveSubIdList(/*visibleOnly*/false); - mUpdater.updateInternalIccStateForInactivePort(FAKE_SUB_ID_1, null); - - processAllMessages(); - assertTrue(mUpdater.isSubInfoInitialized()); - verify(mSubscriptionController, times(1)).clearSubInfoRecord(eq(FAKE_SUB_ID_1)); - - // Verify that in the special absent and inactive case, we update subscriptions without - // broadcasting SIM state change - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager, times(0)).updateConfigForPhoneId(eq(FAKE_SUB_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_ABSENT)); - verify(mContext, times(0)).sendBroadcast(any(), anyString()); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - } - - @Test - @SmallTest - public void testSimUnknown() throws Exception { - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null, FAKE_SUB_ID_1); - - processAllMessages(); - assertFalse(mUpdater.isSubInfoInitialized()); - verify(mSubscriptionContent, times(0)).put(anyString(), any()); - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_UNKNOWN)); - verify(mSubscriptionController, times(0)).clearSubInfo(); - verify(mSubscriptionController, times(0)).notifySubscriptionInfoChanged(); - } - - @Test - @SmallTest - public void testSimNotReady() throws Exception { - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_PHONE_ID_1); - - processAllMessages(); - assertFalse(mUpdater.isSubInfoInitialized()); - verify(mSubscriptionContent, never()).put(anyString(), any()); - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager, never()).updateConfigForPhoneId(eq(FAKE_PHONE_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY)); - verify(mSubscriptionController, never()).clearSubInfoRecord(FAKE_PHONE_ID_1); - verify(mSubscriptionController, never()).notifySubscriptionInfoChanged(); - } - - @Test - @SmallTest - public void testSimNotReadyEmptyProfile() throws Exception { - doReturn(mIccCard).when(mPhone).getIccCard(); - doReturn(true).when(mIccCard).isEmptyProfile(); - - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_PHONE_ID_1); - - processAllMessages(); - assertTrue(mUpdater.isSubInfoInitialized()); - // Sub info should be cleared and change should be notified. - verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_PHONE_ID_1)); - verify(mSubscriptionController).notifySubscriptionInfoChanged(); - // No new sub should be added. - verify(mSubscriptionManager, never()).addSubscriptionInfoRecord(any(), anyInt()); - verify(mSubscriptionContent, never()).put(anyString(), any()); - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_PHONE_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY)); - } - - @Test - @SmallTest - public void testSimNotReadyDisabledUiccApps() throws Exception { - String iccId = "123456"; - doReturn(mIccCard).when(mPhone).getIccCard(); - doReturn(false).when(mIccCard).isEmptyProfile(); - doReturn(mUiccPort).when(mUiccController).getUiccPort(anyInt()); - doReturn(iccId).when(mUiccPort).getIccId(); - doReturn(mSubInfo).when(mSubscriptionController).getSubInfoForIccId(iccId); - doReturn(false).when(mSubInfo).areUiccApplicationsEnabled(); - - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_PHONE_ID_1); - - processAllMessages(); - assertTrue(mUpdater.isSubInfoInitialized()); - // Sub info should be cleared and change should be notified. - verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_PHONE_ID_1)); - verify(mSubscriptionController).notifySubscriptionInfoChanged(); - // No new sub should be added. - verify(mSubscriptionManager, never()).addSubscriptionInfoRecord(any(), anyInt()); - verify(mSubscriptionContent, never()).put(anyString(), any()); - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_PHONE_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY)); - - // When becomes ABSENT, UICC_APPLICATIONS_ENABLED should be reset to true. - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, FAKE_PHONE_ID_1); - processAllMessages(); - ArgumentCaptor valueCapture = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider).update(eq(SubscriptionManager.CONTENT_URI), valueCapture.capture(), - eq(SubscriptionManager.ICC_ID + "=\'" + iccId + "\'"), eq(null)); - ContentValues contentValues = valueCapture.getValue(); - assertTrue(contentValues != null && contentValues.getAsBoolean( - UICC_APPLICATIONS_ENABLED)); - } - - @Test - @SmallTest - public void testSimRemovedWhileDisablingUiccApps() throws Exception { - loadSim(); - - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, FAKE_SUB_ID_1); - processAllMessages(); - - // UICC_APPLICATIONS_ENABLED should be reset to true. - ArgumentCaptor valueCapture = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider).update(eq(SubscriptionManager.CONTENT_URI), valueCapture.capture(), - eq(SubscriptionManager.ICC_ID + "=\'" + FAKE_ICCID_1 + "\'"), eq(null)); - ContentValues contentValues = valueCapture.getValue(); - assertTrue(contentValues != null && contentValues.getAsBoolean( - UICC_APPLICATIONS_ENABLED)); - } - - @Test - @SmallTest - public void testSimError() throws Exception { - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR, null, FAKE_SUB_ID_1); - - processAllMessages(); - assertTrue(mUpdater.isSubInfoInitialized()); - verify(mSubscriptionContent, times(0)).put(anyString(), any()); - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR)); - verify(mSubscriptionController, times(0)).clearSubInfo(); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - } - - @Test - @SmallTest - public void testWrongSimState() throws Exception { - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_IMSI, null, 2); - - processAllMessages(); - assertFalse(mUpdater.isSubInfoInitialized()); - verify(mSubscriptionContent, times(0)).put(anyString(), any()); - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager, times(0)).updateConfigForPhoneId(eq(2), - eq(IccCardConstants.INTENT_VALUE_ICC_IMSI)); - verify(mSubscriptionController, times(0)).clearSubInfo(); - verify(mSubscriptionController, times(0)).notifySubscriptionInfoChanged(); - } - - private void loadSim() { - doReturn(FAKE_SUB_ID_1).when(mSubInfo).getSubscriptionId(); - doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController) - .getSubInfoUsingSlotIndexPrivileged(eq(FAKE_SUB_ID_1)); - doReturn(FAKE_ICCID_1).when(mIccRecord).getFullIccId(); - doReturn(FAKE_MCC_MNC_1).when(mTelephonyManager).getSimOperatorNumeric(FAKE_SUB_ID_1); - when(mActivityManager.updateMccMncConfiguration(anyString(), anyString())).thenReturn( - true); - - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_LOADED, null, FAKE_SUB_ID_1); - - processAllMessages(); - assertTrue(mUpdater.isSubInfoInitialized()); - - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_LOADED)); - } - - @Test - @SmallTest - public void testSimLoaded() throws Exception { - loadSim(); - - // verify SIM_STATE_CHANGED broadcast. It should be broadcast twice, once for - // READ_PHONE_STATE and once for READ_PRIVILEGED_PHONE_STATE - /* todo: cannot verify as intent is sent using ActivityManagerNative.broadcastStickyIntent() - * uncomment code below when that is fixed - */ - /* ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); - ArgumentCaptor stringArgumentCaptor = ArgumentCaptor.forClass(String.class); - verify(mContext, times(2)).sendBroadcast(intentArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - assertEquals(TelephonyIntents.ACTION_SIM_STATE_CHANGED, - intentArgumentCaptor.getAllValues().get(0).getAction()); - assertEquals(Manifest.permission.READ_PHONE_STATE, - stringArgumentCaptor.getAllValues().get(0)); - assertEquals(TelephonyIntents.ACTION_SIM_STATE_CHANGED, - intentArgumentCaptor.getAllValues().get(1).getAction()); - assertEquals(Manifest.permission.READ_PRIVILEGED_PHONE_STATE, - stringArgumentCaptor.getAllValues().get(1)); */ - - SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext); - verify(mTelephonyManager).getSimOperatorNumeric(FAKE_SUB_ID_1); - verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord( - eq(FAKE_ICCID_1), eq(FAKE_SUB_ID_1)); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - verify(mSubscriptionController, times(1)).setMccMnc(FAKE_MCC_MNC_1, FAKE_SUB_ID_1); - verify(mSubscriptionController, times(0)).clearSubInfo(); - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(FAKE_SUB_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_LOADED)); - - // ACTION_USER_UNLOCKED should trigger another SIM_STATE_CHANGED - Intent intentSimStateChanged = new Intent(Intent.ACTION_USER_UNLOCKED); - mContext.sendBroadcast(intentSimStateChanged); - processAllMessages(); - - // verify SIM_STATE_CHANGED broadcast - /* todo: cannot verify as intent is sent using ActivityManagerNative.broadcastStickyIntent() - * uncomment code below when that is fixed - */ - /* verify(mContext, times(4)).sendBroadcast(intentArgumentCaptor.capture(), - stringArgumentCaptor.capture()); - assertEquals(TelephonyIntents.ACTION_SIM_STATE_CHANGED, - intentArgumentCaptor.getAllValues().get(2).getAction()); - assertEquals(Manifest.permission.READ_PHONE_STATE, - stringArgumentCaptor.getAllValues().get(2)); - assertEquals(TelephonyIntents.ACTION_SIM_STATE_CHANGED, - intentArgumentCaptor.getAllValues().get(3).getAction()); - assertEquals(Manifest.permission.READ_PRIVILEGED_PHONE_STATE, - stringArgumentCaptor.getAllValues().get(3)); */ - } - - @Test - @SmallTest - public void testSimLoadedEmptyOperatorNumeric() throws Exception { - doReturn(FAKE_ICCID_1).when(mIccRecord).getFullIccId(); - // operator numeric is empty - doReturn("").when(mTelephonyManager).getSimOperatorNumeric(FAKE_SUB_ID_1); - doReturn(FAKE_SUB_ID_1).when(mSubInfo).getSubscriptionId(); - doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController) - .getSubInfoUsingSlotIndexPrivileged(eq(FAKE_SUB_ID_1)); - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_LOADED, null, FAKE_SUB_ID_1); - - processAllMessages(); - assertTrue(mUpdater.isSubInfoInitialized()); - SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext); - verify(mTelephonyManager).getSimOperatorNumeric(FAKE_SUB_ID_1); - verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord( - eq(FAKE_ICCID_1), eq(FAKE_SUB_ID_1)); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - verify(mSubscriptionController, times(0)).setMccMnc(anyString(), anyInt()); - verify(mSubscriptionController, times(0)).clearSubInfo(); - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(FAKE_SUB_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_LOADED)); - } - - @Test - @SmallTest - public void testSimLockedWithOutIccId() throws Exception { - /* mock no IccId Info present and try to query IccId - after IccId query, update subscriptionDB */ - doReturn("98106240020000000000").when(mIccRecord).getFullIccId(); - - doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController) - .getSubInfoUsingSlotIndexPrivileged(eq(FAKE_SUB_ID_1)); - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_LOCKED, "TESTING", FAKE_SUB_ID_1); - - processAllMessages(); - assertTrue(mUpdater.isSubInfoInitialized()); - SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext); - verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord( - eq("98106240020000000000"), eq(FAKE_SUB_ID_1)); - - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - verify(mSubscriptionController, times(0)).clearSubInfo(); - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(FAKE_SUB_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_LOCKED)); - } - - @Test - @SmallTest - public void testDualSimLoaded() throws Exception { - // Mock there is two sim cards - replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, mPhone}); - replaceInstance(SubscriptionInfoUpdater.class, "sIccId", null, - new String[]{null, null}); - replaceInstance(SubscriptionInfoUpdater.class, "SUPPORTED_MODEM_COUNT", null, 2); - replaceInstance(SubscriptionInfoUpdater.class, "sSimCardState", null, - new int[]{0, 0}); - replaceInstance(SubscriptionInfoUpdater.class, "sSimApplicationState", null, - new int[]{0, 0}); - - doReturn(new int[]{FAKE_SUB_ID_1, FAKE_SUB_ID_2}).when(mSubscriptionManager) - .getActiveSubscriptionIdList(); - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getPhoneId(eq(FAKE_SUB_ID_1)); - doReturn(FAKE_SUB_ID_2).when(mSubscriptionController).getPhoneId(eq(FAKE_SUB_ID_2)); - doReturn(2).when(mTelephonyManager).getPhoneCount(); - doReturn(2).when(mTelephonyManager).getActiveModemCount(); - when(mActivityManager.updateMccMncConfiguration(anyString(), anyString())).thenReturn( - true); - doReturn(FAKE_MCC_MNC_1).when(mTelephonyManager).getSimOperatorNumeric(eq(FAKE_SUB_ID_1)); - doReturn(FAKE_MCC_MNC_2).when(mTelephonyManager).getSimOperatorNumeric(eq(FAKE_SUB_ID_2)); - verify(mSubscriptionController, times(0)).clearSubInfo(); - doReturn(FAKE_ICCID_1).when(mIccRecord).getFullIccId(); - SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext); - verify(mSubscriptionManager, times(0)).addSubscriptionInfoRecord(anyString(), anyInt()); - verify(mSubscriptionController, times(0)).notifySubscriptionInfoChanged(); - verify(mSubscriptionController, times(0)).setMccMnc(anyString(), anyInt()); - - // Mock sending a sim loaded for SIM 1 - doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController) - .getSubInfoUsingSlotIndexPrivileged(eq(FAKE_SUB_ID_1)); - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_LOADED, null, FAKE_SUB_ID_1); - - processAllMessages(); - verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(anyString(), anyInt()); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - verify(mSubscriptionController, times(1)).setMccMnc(anyString(), anyInt()); - assertFalse(mUpdater.isSubInfoInitialized()); - - // Mock sending a sim loaded for SIM 2 - doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController) - .getSubInfoUsingSlotIndexPrivileged(eq(FAKE_SUB_ID_2)); - doReturn(FAKE_SUB_ID_2).when(mSubInfo).getSubscriptionId(); - doReturn("89012604200000000001").when(mIccRecord).getFullIccId(); - - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_LOADED, null, FAKE_SUB_ID_2); - - processAllMessages(); - verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(eq(FAKE_ICCID_1), - eq(FAKE_SUB_ID_1)); - verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(eq("89012604200000000001"), - eq(FAKE_SUB_ID_2)); - verify(mSubscriptionController, times(1)).setMccMnc(eq(FAKE_MCC_MNC_1), eq(FAKE_SUB_ID_1)); - verify(mSubscriptionController, times(1)).setMccMnc(eq(FAKE_MCC_MNC_2), eq(FAKE_SUB_ID_2)); - verify(mSubscriptionController, times(2)).notifySubscriptionInfoChanged(); - assertTrue(mUpdater.isSubInfoInitialized()); - } - - @Test - @SmallTest - public void testSimLockWithIccId() throws Exception { - // ICCID will be queried even if it is already available - doReturn("98106240020000000000").when(mIccRecord).getFullIccId(); - - replaceInstance(SubscriptionInfoUpdater.class, "sIccId", null, - new String[]{FAKE_ICCID_1}); - - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_LOCKED, "TESTING", FAKE_SUB_ID_1); - - processAllMessages(); - assertTrue(mUpdater.isSubInfoInitialized()); - SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext); - verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord( - anyString(), eq(FAKE_SUB_ID_1)); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - verify(mSubscriptionController, times(0)).clearSubInfo(); - CarrierConfigManager mConfigManager = (CarrierConfigManager) - mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); - /* broadcast is done */ - verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(FAKE_SUB_ID_1), - eq(IccCardConstants.INTENT_VALUE_ICC_LOCKED)); - } - - @Test - @SmallTest - public void testUpdateEmbeddedSubscriptions_listSuccess() throws Exception { - when(mEuiccManager.isEnabled()).thenReturn(true); - when(mEuiccManager.createForCardId(anyInt())).thenReturn(mEuiccManager); - when(mEuiccManager.getEid()).thenReturn(FAKE_EID); - - EuiccProfileInfo[] euiccProfiles = new EuiccProfileInfo[] { - new EuiccProfileInfo("1", null /* accessRules */, null /* nickname */), - new EuiccProfileInfo("3", null /* accessRules */, null /* nickname */), - }; - when(mEuiccController.blockingGetEuiccProfileInfoList(FAKE_CARD_ID)).thenReturn( - new GetEuiccProfileInfoListResult( - EuiccService.RESULT_OK, euiccProfiles, false /* removable */)); - - List subInfoList = new ArrayList<>(); - // 1: not embedded, but has matching iccid with an embedded subscription. - subInfoList.add(new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setIccId("1") - .build()); - // 2: embedded but no longer present. - subInfoList.add(new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setIccId("2") - .setEmbedded(true) - .build()); - - when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( - new String[] { "1", "3"}, false /* removable */)).thenReturn(subInfoList); - - List cardIds = new ArrayList<>(); - cardIds.add(FAKE_CARD_ID); - mUpdater.updateEmbeddedSubscriptions(cardIds, null /* callback */); - processAllMessages(); - - // 3 is new and so a new entry should have been created. - verify(mSubscriptionController).insertEmptySubInfoRecord( - "3", SubscriptionManager.SIM_NOT_INSERTED); - // 1 already existed, so no new entries should be created for it. - verify(mSubscriptionController, times(0)).clearSubInfo(); - verify(mSubscriptionController, never()).insertEmptySubInfoRecord(eq("1"), anyInt()); - - // Info for 1 and 3 should be updated as active embedded subscriptions. - ArgumentCaptor iccid1Values = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider).update(eq(SubscriptionManager.CONTENT_URI), iccid1Values.capture(), - eq(SubscriptionManager.ICC_ID + "='1'"), isNull()); - assertEquals(1, - iccid1Values.getValue().getAsInteger(SubscriptionManager.IS_EMBEDDED).intValue()); - ArgumentCaptor iccid3Values = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider).update(eq(SubscriptionManager.CONTENT_URI), iccid3Values.capture(), - eq(SubscriptionManager.ICC_ID + "='3'"), isNull()); - assertEquals(1, - iccid3Values.getValue().getAsInteger(SubscriptionManager.IS_EMBEDDED).intValue()); - - // 2 should have been removed since it was returned from the cache but was not present - // in the list provided by the LPA. - ArgumentCaptor iccid2Values = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider).update(eq(SubscriptionManager.CONTENT_URI), iccid2Values.capture(), - eq(SubscriptionManager.ICC_ID + " IN ('2')"), isNull()); - assertEquals(0, - iccid2Values.getValue().getAsInteger(SubscriptionManager.IS_EMBEDDED).intValue()); - } - - @Test - @SmallTest - public void testUpdateEmbeddedSubscriptions_listFailure() throws Exception { - when(mEuiccManager.isEnabled()).thenReturn(true); - when(mEuiccController.blockingGetEuiccProfileInfoList(FAKE_CARD_ID)) - .thenReturn(new GetEuiccProfileInfoListResult( - 42, null /* subscriptions */, false /* removable */)); - - List subInfoList = new ArrayList<>(); - // 1: not embedded, but has matching iccid with an embedded subscription. - subInfoList.add(new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setIccId("1") - .build()); - // 2: embedded. - subInfoList.add(new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setIccId("2") - .setEmbedded(true) - .build()); - - when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( - new String[0], false /* removable */)).thenReturn(subInfoList); - - ArrayList cardIds = new ArrayList<>(1); - cardIds.add(FAKE_CARD_ID); - mUpdater.updateEmbeddedSubscriptions(cardIds, null /* callback */); - - // No new entries should be created. - verify(mSubscriptionController, times(0)).clearSubInfo(); - verify(mSubscriptionController, never()).insertEmptySubInfoRecord(anyString(), anyInt()); - - // No existing entries should have been updated. - verify(mContentProvider, never()).update(eq(SubscriptionManager.CONTENT_URI), any(), - any(), isNull()); - } - - @Test - @SmallTest - public void testUpdateEmbeddedSubscriptions_emptyToEmpty() throws Exception { - when(mEuiccManager.isEnabled()).thenReturn(true); - when(mEuiccController.blockingGetEuiccProfileInfoList(FAKE_CARD_ID)) - .thenReturn(new GetEuiccProfileInfoListResult( - 42, null /* subscriptions */, true /* removable */)); - - List subInfoList = new ArrayList<>(); - // 1: not embedded. - subInfoList.add(new SubscriptionInfo.Builder() - .setSimSlotIndex(0) - .setIccId("1") - .build()); - - when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate( - new String[0], false /* removable */)).thenReturn(subInfoList); - - ArrayList cardIds = new ArrayList<>(1); - cardIds.add(FAKE_CARD_ID); - mUpdater.updateEmbeddedSubscriptions(cardIds, null /* callback */); - - // No new entries should be created. - verify(mSubscriptionController, never()).insertEmptySubInfoRecord(anyString(), anyInt()); - - // No existing entries should have been updated. - verify(mContentProvider, never()).update(eq(SubscriptionManager.CONTENT_URI), any(), - any(), isNull()); - } - - @Test - @SmallTest - public void testHexIccIdSuffix() throws Exception { - doReturn(null).when(mSubscriptionController) - .getSubInfoUsingSlotIndexPrivileged(anyInt()); - verify(mSubscriptionController, times(0)).clearSubInfo(); - doReturn("890126042000000000Ff").when(mIccRecord).getFullIccId(); - - // Mock sending a sim loaded for SIM 1 - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_LOADED, "TESTING", FAKE_SUB_ID_1); - - processAllMessages(); - - SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(eq("890126042000000000"), - eq(FAKE_SUB_ID_1)); - verify(mSubscriptionController, times(0)).clearSubInfo(); - } - - PersistableBundle getCarrierConfigForSubInfoUpdate( - boolean isOpportunistic, String groupUuid) { - PersistableBundle p = new PersistableBundle(); - p.putBoolean(CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, isOpportunistic); - p.putString(CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, groupUuid); - return p; - } - - @Test - @SmallTest - public void testUpdateFromCarrierConfigOpportunisticUnchanged() throws Exception { - final int phoneId = mPhone.getPhoneId(); - String carrierPackageName = "FakeCarrierPackageName"; - - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); - doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); - doReturn(carrierPackageName).when(mTelephonyManager) - .getCarrierServicePackageNameForLogicalSlot(eq(phoneId)); - ((MockContentResolver) mContext.getContentResolver()).addProvider( - SubscriptionManager.CONTENT_URI.getAuthority(), - new FakeSubscriptionContentProvider()); - - mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(), - carrierPackageName, new PersistableBundle()); - - //at each call to updateSubscriptionByCarrierConfig, only carrier certs are updated - verify(mContentProvider, times(1)).update(any(), any(), any(), any()); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - verify(mSubscriptionController, times(1)).refreshCachedActiveSubscriptionInfoList(); - } - - @Test - @SmallTest - public void testUpdateFromCarrierConfigOpportunisticSetOpportunistic() throws Exception { - final int phoneId = mPhone.getPhoneId(); - PersistableBundle carrierConfig = getCarrierConfigForSubInfoUpdate( - true, ""); - String carrierPackageName = "FakeCarrierPackageName"; - - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); - doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); - doReturn(false).when(mSubInfo).isOpportunistic(); - doReturn(carrierPackageName).when(mTelephonyManager) - .getCarrierServicePackageNameForLogicalSlot(eq(phoneId)); - ((MockContentResolver) mContext.getContentResolver()).addProvider( - SubscriptionManager.CONTENT_URI.getAuthority(), - new FakeSubscriptionContentProvider()); - - mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(), - carrierPackageName, carrierConfig); - - ArgumentCaptor cvCaptor = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider, times(1)).update( - eq(SubscriptionManager.getUriForSubscriptionId(FAKE_SUB_ID_1)), - cvCaptor.capture(), eq(null), eq(null)); - assertEquals(1, cvCaptor.getValue().getAsInteger( - SubscriptionManager.IS_OPPORTUNISTIC).intValue()); - // 2 updates: isOpportunistic, and carrier certs: - assertEquals(2, cvCaptor.getValue().size()); - verify(mSubscriptionController, times(1)).refreshCachedActiveSubscriptionInfoList(); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - } - - @Test - @SmallTest - public void testOpportunisticSubscriptionNotUnsetWithEmptyConfigKey() throws Exception { - final int phoneId = mPhone.getPhoneId(); - PersistableBundle carrierConfig = new PersistableBundle(); - - String carrierPackageName = "FakeCarrierPackageName"; - - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); - doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); - doReturn(true).when(mSubInfo).isOpportunistic(); - doReturn(carrierPackageName).when(mTelephonyManager) - .getCarrierServicePackageNameForLogicalSlot(eq(phoneId)); - ((MockContentResolver) mContext.getContentResolver()).addProvider( - SubscriptionManager.CONTENT_URI.getAuthority(), - new FakeSubscriptionContentProvider()); - - mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(), - carrierPackageName, carrierConfig); - - ArgumentCaptor cvCaptor = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider, times(1)).update( - eq(SubscriptionManager.getUriForSubscriptionId(FAKE_SUB_ID_1)), - cvCaptor.capture(), eq(null), eq(null)); - // no key is added for the opportunistic bit - assertNull(cvCaptor.getValue().getAsInteger(SubscriptionManager.IS_OPPORTUNISTIC)); - // only carrier certs updated - assertEquals(1, cvCaptor.getValue().size()); - verify(mSubscriptionController, times(1)).refreshCachedActiveSubscriptionInfoList(); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - } - - @Test - @SmallTest - public void testUpdateFromCarrierConfigOpportunisticAddToGroup() throws Exception { - final int phoneId = mPhone.getPhoneId(); - PersistableBundle carrierConfig = getCarrierConfigForSubInfoUpdate( - true, "11111111-2222-3333-4444-555555555555"); - String carrierPackageName = "FakeCarrierPackageName"; - - doReturn(true).when(mSubscriptionController).canPackageManageGroup( - ParcelUuid.fromString("11111111-2222-3333-4444-555555555555"), carrierPackageName); - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); - doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); - doReturn(carrierPackageName).when(mTelephonyManager) - .getCarrierServicePackageNameForLogicalSlot(eq(phoneId)); - ((MockContentResolver) mContext.getContentResolver()).addProvider( - SubscriptionManager.CONTENT_URI.getAuthority(), - new FakeSubscriptionContentProvider()); - - mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(), - carrierPackageName, carrierConfig); - - ArgumentCaptor cvCaptor = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider, times(1)).update( - eq(SubscriptionManager.getUriForSubscriptionId(FAKE_SUB_ID_1)), - cvCaptor.capture(), eq(null), eq(null)); - assertEquals(1, cvCaptor.getValue().getAsInteger( - SubscriptionManager.IS_OPPORTUNISTIC).intValue()); - assertEquals("11111111-2222-3333-4444-555555555555", - cvCaptor.getValue().getAsString(SubscriptionManager.GROUP_UUID)); - assertEquals(carrierPackageName, - cvCaptor.getValue().getAsString(SubscriptionManager.GROUP_OWNER)); - // 4 updates: isOpportunistic, groupUuid, groupOwner, and carrier certs: - assertEquals(4, cvCaptor.getValue().size()); - } - - @Test - @SmallTest - public void testUpdateFromCarrierConfigOpportunisticRemoveFromGroup() throws Exception { - final int phoneId = mPhone.getPhoneId(); - PersistableBundle carrierConfig = getCarrierConfigForSubInfoUpdate( - true, "00000000-0000-0000-0000-000000000000"); - String carrierPackageName = "FakeCarrierPackageName"; - - doReturn(true).when(mSubscriptionController).canPackageManageGroup( - ParcelUuid.fromString("11111111-2222-3333-4444-555555555555"), carrierPackageName); - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); - doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); - doReturn(ParcelUuid.fromString("11111111-2222-3333-4444-555555555555")) - .when(mSubInfo).getGroupUuid(); - doReturn(carrierPackageName).when(mTelephonyManager) - .getCarrierServicePackageNameForLogicalSlot(eq(phoneId)); - ((MockContentResolver) mContext.getContentResolver()).addProvider( - SubscriptionManager.CONTENT_URI.getAuthority(), - new FakeSubscriptionContentProvider()); - - mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(), - carrierPackageName, carrierConfig); - - ArgumentCaptor cvCaptor = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider, times(1)).update( - eq(SubscriptionManager.getUriForSubscriptionId(FAKE_SUB_ID_1)), - cvCaptor.capture(), eq(null), eq(null)); - assertEquals(1, cvCaptor.getValue().getAsInteger( - SubscriptionManager.IS_OPPORTUNISTIC).intValue()); - assertNull(cvCaptor.getValue().getAsString(SubscriptionManager.GROUP_UUID)); - // 3 updates: isOpportunistic, groupUuid, and carrier certs: - assertEquals(3, cvCaptor.getValue().size()); - } - - @Test - @SmallTest - public void testUpdateFromCarrierConfigPreferredUsageSettingDataCentric() throws Exception { - testUpdateFromCarrierConfigPreferredUsageSetting( - SubscriptionManager.USAGE_SETTING_UNKNOWN, - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC, - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC); - } - - @Test - @SmallTest - public void testUpdateFromCarrierConfigPreferredUsageSettingDataCentric2() throws Exception { - testUpdateFromCarrierConfigPreferredUsageSetting( - SubscriptionManager.USAGE_SETTING_DEFAULT, - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC, - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC); - } - - @Test - @SmallTest - public void testUpdateFromCarrierConfigPreferredUsageSettingDefault() throws Exception { - testUpdateFromCarrierConfigPreferredUsageSetting( - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC, - SubscriptionManager.USAGE_SETTING_DEFAULT, - SubscriptionManager.USAGE_SETTING_DEFAULT); - } - - @Test - @SmallTest - public void testUpdateFromCarrierConfigPreferredUsageSettingNoChange() throws Exception { - testUpdateFromCarrierConfigPreferredUsageSetting( - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC, - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC, - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC); - } - - @Test - @SmallTest - public void testUpdateFromCarrierConfigPreferredUsageSettingInvalid() throws Exception { - testUpdateFromCarrierConfigPreferredUsageSetting( - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC, - SubscriptionManager.USAGE_SETTING_UNKNOWN, - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC); - } - - private PersistableBundle getCarrierConfigForSubInfoUpdateUsageSetting( - @SubscriptionManager.UsageSetting int usageSetting) { - PersistableBundle p = new PersistableBundle(); - p.putString(CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, ""); - p.putBoolean(CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false); - p.putInt(CarrierConfigManager.KEY_CELLULAR_USAGE_SETTING_INT, usageSetting); - return p; - } - - private void testUpdateFromCarrierConfigPreferredUsageSetting( - int initialSetting, int requestedSetting, int expectedSetting) throws Exception { - final String carrierPackageName = "FakeCarrierPackageName"; - final int phoneId = mPhone.getPhoneId(); - - // Install fixtures, ensure the test will hit the right code path - doReturn(carrierPackageName).when(mTelephonyManager) - .getCarrierServicePackageNameForLogicalSlot(eq(phoneId)); - ((MockContentResolver) mContext.getContentResolver()).addProvider( - SubscriptionManager.CONTENT_URI.getAuthority(), - new FakeSubscriptionContentProvider()); - - // Setup overlay - setupUsageSettingResources(); - - // Setup subscription - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); - doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); - doReturn(null).when(mSubInfo).getGroupUuid(); - doReturn(false).when(mSubInfo).isOpportunistic(); - doReturn(initialSetting).when(mSubInfo).getUsageSetting(); - - // Get a config bundle for that prefers data centric - PersistableBundle carrierConfig = getCarrierConfigForSubInfoUpdateUsageSetting( - requestedSetting); - - mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(), - carrierPackageName, carrierConfig); - - ArgumentCaptor cvCaptor = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider, times(1)).update( - eq(SubscriptionManager.getUriForSubscriptionId(FAKE_SUB_ID_1)), - cvCaptor.capture(), eq(null), eq(null)); - - if (initialSetting != expectedSetting) { - assertEquals(expectedSetting, - (int) cvCaptor.getValue().getAsInteger(SubscriptionManager.USAGE_SETTING)); - } else { - // If the content value was not set, the captor value will be null - assertNull(cvCaptor.getValue().getAsInteger(SubscriptionManager.USAGE_SETTING)); - } - } - - @Test - @SmallTest - public void testUpdateFromCarrierConfigCarrierCertificates() { - String[] certs = new String[2]; - certs[0] = "d1f1"; - certs[1] = "b5d6"; - - UiccAccessRule[] carrierConfigAccessRules = new UiccAccessRule[certs.length]; - for (int i = 0; i < certs.length; i++) { - carrierConfigAccessRules[i] = new UiccAccessRule( - IccUtils.hexStringToBytes(certs[i]), null, 0); - } - - final int phoneId = mPhone.getPhoneId(); - PersistableBundle carrierConfig = new PersistableBundle(); - carrierConfig.putStringArray( - CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY, certs); - - String carrierPackageName = "FakeCarrierPackageName"; - - doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getSubId(phoneId); - doReturn(mSubInfo).when(mSubscriptionController).getSubscriptionInfo(eq(FAKE_SUB_ID_1)); - doReturn(false).when(mSubInfo).isOpportunistic(); - doReturn(carrierPackageName).when(mTelephonyManager) - .getCarrierServicePackageNameForLogicalSlot(eq(phoneId)); - ((MockContentResolver) mContext.getContentResolver()).addProvider( - SubscriptionManager.CONTENT_URI.getAuthority(), - new FakeSubscriptionContentProvider()); - - mUpdater.updateSubscriptionByCarrierConfig(mPhone.getPhoneId(), - carrierPackageName, carrierConfig); - - ArgumentCaptor cvCaptor = ArgumentCaptor.forClass(ContentValues.class); - verify(mContentProvider, times(1)).update( - eq(SubscriptionManager.getUriForSubscriptionId(FAKE_SUB_ID_1)), - cvCaptor.capture(), eq(null), eq(null)); - assertEquals(carrierConfigAccessRules, UiccAccessRule.decodeRules(cvCaptor.getValue() - .getAsByteArray(SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS))); - assertEquals(1, cvCaptor.getValue().size()); - verify(mSubscriptionController, times(1)).refreshCachedActiveSubscriptionInfoList(); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - } - - @Test - @SmallTest - public void testSimReady() throws Exception { - replaceInstance(SubscriptionInfoUpdater.class, "sIccId", null,new String[]{""}); - doReturn(mUiccPort).when(mUiccController).getUiccPort(anyInt()); - doReturn(FAKE_ICCID_1).when(mUiccPort).getIccId(); - - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_READY, "TESTING", FAKE_SUB_ID_1); - processAllMessages(); - - verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_SUB_ID_1)); - verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord( - eq(FAKE_ICCID_1), eq(FAKE_SUB_ID_1)); - assertTrue(mUpdater.isSubInfoInitialized()); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - } - - @Test - @SmallTest - public void testSimReadyAndLoaded() throws Exception { - replaceInstance(SubscriptionInfoUpdater.class, "sIccId", null,new String[]{""}); - - doReturn(mUiccPort).when(mUiccController).getUiccPort(anyInt()); - doReturn(null).when(mUiccPort).getIccId(); - - mUpdater.updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_READY, "TESTING", FAKE_SUB_ID_1); - processAllMessages(); - - verify(mSubscriptionManager, times(0)).addSubscriptionInfoRecord( - eq(FAKE_ICCID_1), eq(FAKE_SUB_ID_1)); - - loadSim(); - - SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext); - verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord( - eq(FAKE_ICCID_1), eq(FAKE_SUB_ID_1)); - verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged(); - } - - private void setupUsageSettingResources() { - // The most common case, request a voice-centric->data-centric change - mContextFixture.putIntResource( - com.android.internal.R.integer.config_default_cellular_usage_setting, - SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC); - mContextFixture.putIntArrayResource( - com.android.internal.R.array.config_supported_cellular_usage_settings, - new int[]{ - SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC, - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC}); - } - - @Test - @SmallTest - public void testCalculateUsageSetting() throws Exception { - setupUsageSettingResources(); - assertEquals(SubscriptionManager.USAGE_SETTING_DATA_CENTRIC, - mUpdater.calculateUsageSetting( - SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC, - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC)); - - // Test that a voice-centric-only device only allows voice-centric configuration - mContextFixture.putIntArrayResource( - com.android.internal.R.array.config_supported_cellular_usage_settings, - new int[]{SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC}); - - assertEquals(SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC, - mUpdater.calculateUsageSetting( - SubscriptionManager.USAGE_SETTING_VOICE_CENTRIC, - SubscriptionManager.USAGE_SETTING_DATA_CENTRIC)); - } -} diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java index 2b4d8013e5..35a3186046 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java @@ -1315,12 +1315,9 @@ public class TelephonyRegistryTest extends TelephonyTest { final int subId = 1; // Return a slotIndex / phoneId of 0 for subId 1. - doReturn(subId).when(mSubscriptionController).getSubId(phoneId); + doReturn(subId).when(mSubscriptionManagerService).getSubId(phoneId); doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(subId); doReturn(phoneId).when(mMockSubInfo).getSimSlotIndex(); - mServiceManagerMockedServices.put("isub", mSubscriptionController); - doReturn(mSubscriptionController).when(mSubscriptionController) - .queryLocalInterface(anyString()); UserInfo userInfo = new UserInfo(UserHandle.myUserId(), "" /* name */, 0 /* flags */); doReturn(userInfo.id).when(mIActivityManager).getCurrentUserId(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 6d2f3adb0e..5f675127bd 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -16,7 +16,6 @@ package com.android.internal.telephony; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyString; @@ -205,7 +204,6 @@ public abstract class TelephonyTest { protected GsmCdmaCall mGsmCdmaCall; protected ImsCall mImsCall; protected ImsEcbm mImsEcbm; - protected SubscriptionController mSubscriptionController; protected SubscriptionManagerService mSubscriptionManagerService; protected ServiceState mServiceState; protected IPackageManager.Stub mMockPackageManager; @@ -243,7 +241,6 @@ public abstract class TelephonyTest { protected IntentBroadcaster mIntentBroadcaster; protected NitzStateMachine mNitzStateMachine; protected RadioConfig mMockRadioConfig; - protected SubscriptionInfoUpdater mSubInfoRecordUpdater; protected LocaleTracker mLocaleTracker; protected RestrictedState mRestrictedState; protected PhoneConfigurationManager mPhoneConfigurationManager; @@ -441,7 +438,6 @@ public abstract class TelephonyTest { mGsmCdmaCall = Mockito.mock(GsmCdmaCall.class); mImsCall = Mockito.mock(ImsCall.class); mImsEcbm = Mockito.mock(ImsEcbm.class); - mSubscriptionController = Mockito.mock(SubscriptionController.class); mSubscriptionManagerService = Mockito.mock(SubscriptionManagerService.class); mServiceState = Mockito.mock(ServiceState.class); mMockPackageManager = Mockito.mock(IPackageManager.Stub.class); @@ -479,7 +475,6 @@ public abstract class TelephonyTest { mIntentBroadcaster = Mockito.mock(IntentBroadcaster.class); mNitzStateMachine = Mockito.mock(NitzStateMachine.class); mMockRadioConfig = Mockito.mock(RadioConfig.class); - mSubInfoRecordUpdater = Mockito.mock(SubscriptionInfoUpdater.class); mLocaleTracker = Mockito.mock(LocaleTracker.class); mRestrictedState = Mockito.mock(RestrictedState.class); mPhoneConfigurationManager = Mockito.mock(PhoneConfigurationManager.class); @@ -531,7 +526,9 @@ public abstract class TelephonyTest { Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); - enableSubscriptionManagerService(true); + mServiceManagerMockedServices.put("isub", mSubscriptionManagerService); + doReturn(mSubscriptionManagerService).when(mSubscriptionManagerService) + .queryLocalInterface(anyString()); mPhone.mCi = mSimulatedCommands; mCT.mCi = mSimulatedCommands; @@ -835,7 +832,6 @@ public abstract class TelephonyTest { mTelephonyComponentFactory); replaceInstance(UiccController.class, "mInstance", null, mUiccController); replaceInstance(CdmaSubscriptionSourceManager.class, "sInstance", null, mCdmaSSM); - replaceInstance(SubscriptionController.class, "sInstance", null, mSubscriptionController); replaceInstance(SubscriptionManagerService.class, "sInstance", null, mSubscriptionManagerService); replaceInstance(ProxyController.class, "sProxyController", null, mProxyController); @@ -856,7 +852,6 @@ public abstract class TelephonyTest { replaceInstance(PhoneFactory.class, "sMadeDefaults", null, true); replaceInstance(PhoneFactory.class, "sPhone", null, mPhone); replaceInstance(PhoneFactory.class, "sPhones", null, mPhones); - replaceInstance(PhoneFactory.class, "sSubInfoRecordUpdater", null, mSubInfoRecordUpdater); replaceInstance(RadioConfig.class, "sRadioConfig", null, mMockRadioConfig); replaceInstance(PhoneConfigurationManager.class, "sInstance", null, mPhoneConfigurationManager); @@ -864,16 +859,10 @@ public abstract class TelephonyTest { mCellularNetworkValidator); replaceInstance(MultiSimSettingController.class, "sInstance", null, mMultiSimSettingController); - replaceInstance(SubscriptionInfoUpdater.class, "sIsSubInfoInitialized", null, true); replaceInstance(PhoneFactory.class, "sCommandsInterfaces", null, new CommandsInterface[] {mSimulatedCommands}); replaceInstance(PhoneFactory.class, "sMetricsCollector", null, mMetricsCollector); - if (!isSubscriptionManagerServiceEnabled()) { - assertNotNull("Failed to set up SubscriptionController singleton", - SubscriptionController.getInstance()); - } - setReady(false); // create default TestableLooper for test and add to list of monitored loopers mTestableLooper = TestableLooper.get(TelephonyTest.this); @@ -1289,22 +1278,4 @@ public abstract class TelephonyTest { } } } - - protected void enableSubscriptionManagerService(boolean enabled) throws Exception { - if (enabled) { - mServiceManagerMockedServices.put("isub", mSubscriptionManagerService); - doReturn(mSubscriptionManagerService).when(mIBinder) - .queryLocalInterface(anyString()); - } - replaceInstance(PhoneFactory.class, "sSubscriptionManagerServiceEnabled", null, enabled); - mContextFixture.putBooleanResource(com.android.internal.R.bool - .config_using_subscription_manager_service, enabled); - doReturn(enabled).when(mPhone).isSubscriptionManagerServiceEnabled(); - doReturn(enabled).when(mPhone2).isSubscriptionManagerServiceEnabled(); - doReturn(enabled).when(mImsPhone).isSubscriptionManagerServiceEnabled(); - } - - protected boolean isSubscriptionManagerServiceEnabled() { - return mPhone.isSubscriptionManagerServiceEnabled(); - } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java index 76a3d0a12b..428699fd93 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/CellularNetworkValidatorTest.java @@ -77,7 +77,6 @@ public class CellularNetworkValidatorTest extends TelephonyTest { doReturn(CAPABILITY_WITH_VALIDATION_SUPPORTED).when(mPhoneConfigurationManager) .getCurrentPhoneCapability(); mValidatorUT = new CellularNetworkValidator(mContext); - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); doReturn(new SubscriptionInfoInternal.Builder().setSimSlotIndex(0).setId(1).build()) .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); 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 a6d09237f8..62e8ba8108 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -773,20 +773,12 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(true).when(mSST).getPowerStateFromCarrier(); doReturn(true).when(mSST).isConcurrentVoiceAndDataAllowed(); doReturn(PhoneConstants.State.IDLE).when(mCT).getState(); - doReturn("").when(mSubscriptionController).getEnabledMobileDataPolicies(anyInt()); - doReturn(true).when(mSubscriptionController).setEnabledMobileDataPolicies( - anyInt(), anyString()); doReturn(new SubscriptionInfoInternal.Builder().setId(1).build()) .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); List infoList = new ArrayList<>(); infoList.add(mMockSubInfo); - doReturn(infoList).when(mSubscriptionController).getSubscriptionsInGroup( - any(), any(), any()); - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); - doReturn(0).when(mSubscriptionController).getPhoneId(1); doReturn(0).when(mSubscriptionManagerService).getPhoneId(1); - doReturn(1).when(mSubscriptionController).getPhoneId(2); doReturn(1).when(mSubscriptionManagerService).getPhoneId(2); for (int transport : new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, @@ -1629,9 +1621,7 @@ public class DataNetworkControllerTest extends TelephonyTest { boolean isDataEnabled = mDataNetworkControllerUT.getDataSettingsManager().isDataEnabled(); doReturn(mDataNetworkControllerUT.getDataSettingsManager()) .when(mPhone).getDataSettingsManager(); - MultiSimSettingController instance = MultiSimSettingController.getInstance(); - MultiSimSettingController controller = Mockito.spy( - new MultiSimSettingController(mContext, mSubscriptionController)); + MultiSimSettingController controller = Mockito.spy(new MultiSimSettingController(mContext)); doReturn(true).when(controller).isCarrierConfigLoadedForAllSub(); replaceInstance(MultiSimSettingController.class, "sInstance", null, controller); @@ -1725,7 +1715,6 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testIsDataEnabledOverriddenForApnDataDuringCall() throws Exception { doReturn(1).when(mPhone).getSubId(); - doReturn(2).when(mSubscriptionController).getDefaultDataSubId(); doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); // Data disabled mDataNetworkControllerUT.getDataSettingsManager().setDataEnabled( @@ -1768,7 +1757,6 @@ public class DataNetworkControllerTest extends TelephonyTest { // Assume phone2 is the default data phone Phone phone2 = Mockito.mock(Phone.class); replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, phone2}); - doReturn(2).when(mSubscriptionController).getDefaultDataSubId(); doReturn(2).when(mSubscriptionManagerService).getDefaultDataSubId(); // Data disabled on nonDDS diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java index 7a1aecaa82..f7525c1e52 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataSettingsManagerTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -64,9 +63,6 @@ public class DataSettingsManagerTest extends TelephonyTest { mBundle = mContextFixture.getCarrierConfigBundle(); doReturn(true).when(mDataConfigManager).isConfigCarrierSpecific(); - doReturn("").when(mSubscriptionController).getEnabledMobileDataPolicies(anyInt()); - doReturn(true).when(mSubscriptionController).setEnabledMobileDataPolicies( - anyInt(), anyString()); doReturn(new SubscriptionInfoInternal.Builder().setId(1).build()) .when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); @@ -108,13 +104,8 @@ public class DataSettingsManagerTest extends TelephonyTest { processAllMessages(); ArgumentCaptor stringArgumentCaptor = ArgumentCaptor.forClass(String.class); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService, times(2)) - .setEnabledMobileDataPolicies(anyInt(), stringArgumentCaptor.capture()); - } else { - verify(mSubscriptionController, times(2)) - .setEnabledMobileDataPolicies(anyInt(), stringArgumentCaptor.capture()); - } + verify(mSubscriptionManagerService, times(2)) + .setEnabledMobileDataPolicies(anyInt(), stringArgumentCaptor.capture()); assertEquals("1,2", stringArgumentCaptor.getValue()); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java index 6781ce3ae7..35d3b9268a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java @@ -19,7 +19,6 @@ package com.android.internal.telephony.data; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -70,14 +69,10 @@ public class DataStallRecoveryManagerTest extends TelephonyTest { .getDataStallRecoveryShouldSkipArray(); doReturn(true).when(mDataNetworkController).isInternetDataAllowed(); - doAnswer( - invocation -> { - ((Runnable) invocation.getArguments()[0]).run(); - return null; - }) - .when(mDataStallRecoveryManagerCallback) - .invokeFromExecutor(any(Runnable.class)); - doReturn("").when(mSubscriptionController).getEnabledMobileDataPolicies(anyInt()); + doAnswer(invocation -> { + ((Runnable) invocation.getArguments()[0]).run(); + return null; + }).when(mDataStallRecoveryManagerCallback).invokeFromExecutor(any(Runnable.class)); mDataStallRecoveryManager = new DataStallRecoveryManager( 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 45c285c602..bc691f62b8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/PhoneSwitcherTest.java @@ -593,7 +593,6 @@ public class PhoneSwitcherTest extends TelephonyTest { public void testAutoDataSwitch_setNotification() throws Exception { SubscriptionInfo mockedInfo = mock(SubscriptionInfo.class); doReturn(false).when(mockedInfo).isOpportunistic(); - doReturn(mockedInfo).when(mSubscriptionController).getSubscriptionInfo(anyInt()); doReturn(mockedInfo).when(mSubscriptionManagerService).getSubscriptionInfo(anyInt()); initialize(); // Phone 0 has sub 1, phone 1 has sub 2. @@ -603,37 +602,22 @@ public class PhoneSwitcherTest extends TelephonyTest { setDefaultDataSubId(1); testAutoSwitchToSecondarySucceed(); - clearInvocations(mSubscriptionController); clearInvocations(mSubscriptionManagerService); Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(1, null, null)) .sendToTarget(); processAllMessages(); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService).getSubscriptionInfo(2); - } else { - verify(mSubscriptionController).getSubscriptionInfo(2); - } - + verify(mSubscriptionManagerService).getSubscriptionInfo(2); // switch back to primary - clearInvocations(mSubscriptionController); clearInvocations(mSubscriptionManagerService); Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(0, null, null)) .sendToTarget(); processAllMessages(); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService, never()).getSubscriptionInfo(1); - } else { - verify(mSubscriptionController, never()).getSubscriptionInfo(1); - } + verify(mSubscriptionManagerService, never()).getSubscriptionInfo(1); Message.obtain(mPhoneSwitcherUT, EVENT_MODEM_COMMAND_DONE, new AsyncResult(1, null, null)) .sendToTarget(); processAllMessages(); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService, never()).getSubscriptionInfo(2); - } else { - verify(mSubscriptionController, never()).getSubscriptionInfo(2); - } + verify(mSubscriptionManagerService, never()).getSubscriptionInfo(2); } @Test @@ -769,7 +753,6 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(1, 2); setDefaultDataSubId(1); - doReturn(true).when(mSubscriptionController).isOpportunistic(2); doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService .getSubscriptionInfoInternal(2)).setOpportunistic(1).build()) .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2); @@ -816,7 +799,6 @@ public class PhoneSwitcherTest extends TelephonyTest { setSlotIndexToSubId(0, 1); setSlotIndexToSubId(1, 2); // single visible sub, as the other one is CBRS - doReturn(new int[1]).when(mSubscriptionController).getActiveSubIdList(true); doReturn(new int[1]).when(mSubscriptionManagerService).getActiveSubIdList(true); setDefaultDataSubId(1); @@ -873,7 +855,6 @@ public class PhoneSwitcherTest extends TelephonyTest { setDefaultDataSubId(1); clearInvocations(mCellularNetworkValidator); - doReturn(new int[1]).when(mSubscriptionController).getActiveSubIdList(true); doReturn(new int[1]).when(mSubscriptionManagerService).getActiveSubIdList(true); prepareIdealAutoSwitchCondition(); processAllFutureMessages(); @@ -927,7 +908,6 @@ public class PhoneSwitcherTest extends TelephonyTest { new TelephonyNetworkRequest(mmsRequest, mPhone), 1)); // Set sub 2 as preferred sub should make phone 1 preferredDataModem - doReturn(true).when(mSubscriptionController).isOpportunistic(2); doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService .getSubscriptionInfoInternal(2)).setOpportunistic(1).build()) .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2); @@ -989,8 +969,6 @@ public class PhoneSwitcherTest extends TelephonyTest { doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported(); initialize(); - // Mark sub 2 as opportunistic. - doReturn(true).when(mSubscriptionController).isOpportunistic(2); // 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. @@ -1551,8 +1529,6 @@ public class PhoneSwitcherTest extends TelephonyTest { doReturn(true).when(mMockRadioConfig).isSetPreferredDataCommandSupported(); initialize(); - // Mark sub 2 as opportunistic. - doReturn(true).when(mSubscriptionController).isOpportunistic(2); // 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. @@ -1714,7 +1690,6 @@ public class PhoneSwitcherTest extends TelephonyTest { setAllPhonesInactive(); // Initialization done. - doReturn(true).when(mSubscriptionController).isOpportunistic(2); doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService .getSubscriptionInfoInternal(2)).setOpportunistic(1).build()) .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2); @@ -1756,7 +1731,6 @@ public class PhoneSwitcherTest extends TelephonyTest { setAllPhonesInactive(); // Initialization done. - doReturn(true).when(mSubscriptionController).isOpportunistic(2); doReturn(new SubscriptionInfoInternal.Builder(mSubscriptionManagerService .getSubscriptionInfoInternal(2)).setOpportunistic(1).build()) .when(mSubscriptionManagerService).getSubscriptionInfoInternal(2); @@ -1807,8 +1781,6 @@ public class PhoneSwitcherTest extends TelephonyTest { verify(mMockRadioConfig, times(1)).setPreferredDataModem(eq(0), any()); clearInvocations(mMockRadioConfig); - doReturn(mSubscriptionInfo).when(mSubscriptionController) - .getActiveSubscriptionInfoForSimSlotIndex(eq(0), any(), any()); doReturn(mSubscriptionInfo).when(mSubscriptionManagerService) .getActiveSubscriptionInfoForSimSlotIndex(eq(0), any(), any()); doReturn(true).when(mSubscriptionInfo).areUiccApplicationsEnabled(); @@ -2131,25 +2103,12 @@ public class PhoneSwitcherTest extends TelephonyTest { * network requests on PhoneSwitcher. */ private void initializeSubControllerMock() throws Exception { - doReturn(mDefaultDataSub).when(mSubscriptionController).getDefaultDataSubId(); doReturn(mDefaultDataSub).when(mSubscriptionManagerService).getDefaultDataSubId(); doReturn(mDefaultDataSub).when(mMockedIsub).getDefaultDataSubId(); - doReturn(0).when(mSubscriptionController).getPhoneId(1); doReturn(0).when(mSubscriptionManagerService).getPhoneId(1); doReturn(0).when(mMockedIsub).getPhoneId(1); - doReturn(1).when(mSubscriptionController).getPhoneId(2); doReturn(1).when(mSubscriptionManagerService).getPhoneId(2); doReturn(1).when(mMockedIsub).getPhoneId(2); - doAnswer(invocation -> { - int phoneId = (int) invocation.getArguments()[0]; - if (phoneId == SubscriptionManager.INVALID_PHONE_INDEX) { - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; - } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) { - return mSlotIndexToSubId[0][0]; - } else { - return mSlotIndexToSubId[phoneId][0]; - } - }).when(mSubscriptionController).getSubId(anyInt()); doAnswer(invocation -> { int phoneId = (int) invocation.getArguments()[0]; @@ -2173,17 +2132,6 @@ public class PhoneSwitcherTest extends TelephonyTest { } }).when(mSubscriptionManagerService).getSubId(anyInt()); - doAnswer(invocation -> { - int subId = (int) invocation.getArguments()[0]; - - if (!SubscriptionManager.isUsableSubIdValue(subId)) return false; - - for (int i = 0; i < mSlotIndexToSubId.length; i++) { - if (mSlotIndexToSubId[i][0] == subId) return true; - } - return false; - }).when(mSubscriptionController).isActiveSubId(anyInt()); - doAnswer(invocation -> { int subId = (int) invocation.getArguments()[0]; @@ -2197,8 +2145,6 @@ public class PhoneSwitcherTest extends TelephonyTest { .setSimSlotIndex(slotIndex).setId(subId).build(); }).when(mSubscriptionManagerService).getSubscriptionInfoInternal(anyInt()); - doReturn(new int[mSlotIndexToSubId.length]).when(mSubscriptionController) - .getActiveSubIdList(true); doReturn(new int[mSlotIndexToSubId.length]).when(mSubscriptionManagerService) .getActiveSubIdList(true); } @@ -2214,7 +2160,6 @@ public class PhoneSwitcherTest extends TelephonyTest { private void setDefaultDataSubId(int defaultDataSub) throws Exception { mDefaultDataSub = defaultDataSub; - doReturn(mDefaultDataSub).when(mSubscriptionController).getDefaultDataSubId(); doReturn(mDefaultDataSub).when(mSubscriptionManagerService).getDefaultDataSubId(); if (defaultDataSub == 1) { doReturn(true).when(mPhone).isUserDataEnabled(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java index b7e6b59540..5941f062ff 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/TelephonyNetworkFactoryTest.java @@ -212,8 +212,7 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { // test at this time. doAnswer(invocation -> { final NetworkCapabilities capabilitiesFilter = - mTelephonyNetworkFactoryUT.makeNetworkFilter( - mSubscriptionController.getSubId(0)); + mTelephonyNetworkFactoryUT.makeNetworkFilter(mMockedIsub.getSubId(0)); for (final TelephonyNetworkRequest request : mAllNetworkRequestSet) { final int message = request.canBeSatisfiedBy(capabilitiesFilter) ? CMD_REQUEST_NETWORK : CMD_CANCEL_REQUEST; @@ -238,7 +237,6 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { createMockedTelephonyComponents(); doReturn(false).when(mPhoneSwitcher).shouldApplyNetworkRequest(any(), anyInt()); - doReturn(subId).when(mSubscriptionController).getSubId(phoneId); doReturn(subId).when(mMockedIsub).getSubId(phoneId); // fake onSubscriptionChangedListener being triggered. mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( @@ -312,7 +310,6 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { createMockedTelephonyComponents(); - doReturn(subId).when(mSubscriptionController).getSubId(phoneId); doReturn(subId).when(mMockedIsub).getSubId(phoneId); mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); @@ -327,7 +324,6 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { processAllMessages(); assertEquals(1, mNetworkRequestList.size()); - doReturn(altSubId).when(mSubscriptionController).getSubId(altPhoneId); doReturn(altSubId).when(mMockedIsub).getSubId(altPhoneId); processAllMessages(); assertEquals(1, mNetworkRequestList.size()); @@ -343,7 +339,6 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { processAllMessages(); assertEquals(1, mNetworkRequestList.size()); - doReturn(unusedSubId).when(mSubscriptionController).getSubId(phoneId); doReturn(unusedSubId).when(mMockedIsub).getSubId(phoneId); mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); @@ -354,7 +349,6 @@ public class TelephonyNetworkFactoryTest extends TelephonyTest { processAllMessages(); assertEquals(0, mNetworkRequestList.size()); - doReturn(subId).when(mSubscriptionController).getSubId(phoneId); doReturn(subId).when(mMockedIsub).getSubId(phoneId); mTelephonyNetworkFactoryUT.mInternalHandler.sendEmptyMessage( TelephonyNetworkFactory.EVENT_SUBSCRIPTION_CHANGED); diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index aa68d1ddd8..f7ea4b66f9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -50,7 +50,6 @@ import androidx.test.InstrumentationRegistry; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyTest; import com.google.i18n.phonenumbers.ShortNumberInfo; @@ -115,7 +114,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private static final int INVALID_SLOT_INDEX_VALID = SubscriptionManager.INVALID_SIM_SLOT_INDEX; private ParcelFileDescriptor mOtaParcelFileDescriptor = null; // Mocked classes - private SubscriptionController mSubControllerMock; private CarrierConfigManager mCarrierConfigManagerMock; // mEmergencyNumberTrackerMock for mPhone @@ -137,7 +135,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { logd("EmergencyNumberTrackerTest +Setup!"); super.setUp(getClass().getSimpleName()); mShortNumberInfo = mock(ShortNumberInfo.class); - mSubControllerMock = mock(SubscriptionController.class); mCarrierConfigManagerMock = mock(CarrierConfigManager.class); mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()); @@ -333,13 +330,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { @Test public void testIsSimAbsent() throws Exception { setDsdsPhones(); - replaceInstance(SubscriptionController.class, "sInstance", null, mSubControllerMock); - - // Both sim slots are active - doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_1)); - doReturn(VALID_SLOT_INDEX_VALID_2).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_2)); doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubscriptionManagerService).getSlotIndex( eq(SUB_ID_PHONE_1)); doReturn(VALID_SLOT_INDEX_VALID_2).when(mSubscriptionManagerService).getSlotIndex( @@ -347,10 +337,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { assertFalse(mEmergencyNumberTrackerMock.isSimAbsent()); // One sim slot is active; the other one is not active - doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_1)); - doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_2)); doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubscriptionManagerService).getSlotIndex( eq(SUB_ID_PHONE_1)); doReturn(INVALID_SLOT_INDEX_VALID).when(mSubscriptionManagerService).getSlotIndex( @@ -358,10 +344,6 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { assertFalse(mEmergencyNumberTrackerMock.isSimAbsent()); // Both sim slots are not active - doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_1)); - doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_2)); doReturn(INVALID_SLOT_INDEX_VALID).when(mSubscriptionManagerService).getSlotIndex( anyInt()); assertTrue(mEmergencyNumberTrackerMock.isSimAbsent()); @@ -425,13 +407,8 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { @Test public void testIsEmergencyNumber_FallbackToShortNumberXml_NoSims() throws Exception { setDsdsPhones(); - replaceInstance(SubscriptionController.class, "sInstance", null, mSubControllerMock); // Both sim slots are not active - doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_1)); - doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_2)); doReturn(INVALID_SLOT_INDEX_VALID).when(mSubscriptionManagerService).getSlotIndex( anyInt()); assertTrue(mEmergencyNumberTrackerMock.isSimAbsent()); @@ -462,24 +439,15 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { private void testIsEmergencyNumber_NoFallbackToShortNumberXml(int numSims) throws Exception { assertTrue((numSims > 0 && numSims < 3)); setDsdsPhones(); - replaceInstance(SubscriptionController.class, "sInstance", null, mSubControllerMock); if (numSims == 1) { // One sim slot is active; the other one is not active - doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_1)); - doReturn(INVALID_SLOT_INDEX_VALID).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_2)); doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubscriptionManagerService).getSlotIndex( eq(SUB_ID_PHONE_1)); doReturn(INVALID_SLOT_INDEX_VALID).when(mSubscriptionManagerService).getSlotIndex( eq(SUB_ID_PHONE_2)); } else { //both slots active - doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_1)); - doReturn(VALID_SLOT_INDEX_VALID_2).when(mSubControllerMock).getSlotIndex( - eq(SUB_ID_PHONE_2)); doReturn(VALID_SLOT_INDEX_VALID_1).when(mSubscriptionManagerService).getSlotIndex( eq(SUB_ID_PHONE_1)); doReturn(VALID_SLOT_INDEX_VALID_2).when(mSubscriptionManagerService).getSlotIndex( diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java index 477a1fa1a0..8374daaac7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java @@ -66,7 +66,6 @@ import com.android.internal.telephony.ContextFixture; import com.android.internal.telephony.ISub; import com.android.internal.telephony.SMSDispatcher; import com.android.internal.telephony.SmsDispatchersController; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.TelephonyTestUtils; import com.android.internal.telephony.TestApplication; @@ -566,11 +565,7 @@ public class GsmSmsDispatcherTest extends TelephonyTest { doReturn(mIsimUiccRecords).when(mPhone).getIccRecords(); Message msg = mGsmSmsDispatcher.obtainMessage(17); mPhone.getIccRecords().setSmssTpmrValue(-1, msg); - if (isSubscriptionManagerServiceEnabled()) { - mSubscriptionManagerService.setLastUsedTPMessageReference(mPhone.getSubId(), -1); - } else { - SubscriptionController.getInstance().updateMessageRef(mPhone.getSubId(), -1); - } + mSubscriptionManagerService.setLastUsedTPMessageReference(mPhone.getSubId(), -1); mGsmSmsDispatcher.sendText("111", "222" /*scAddr*/, TAG, null, null, null, null, false, -1, false, -1, false, 0L); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 97d6ba20b6..857b6a43e1 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -395,16 +395,11 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { @Test @SmallTest public void testCarrierConfigLoadSubscription() throws Exception { - // Start with there being no subId loaded, so SubscriptionController#isActiveSubId is false - // as part of setup, connectionReady is called, which ends up calling - // updateCarrierConfiguration. Since the carrier config is not report carrier identified - // config, we should not see updateImsServiceConfig called yet. verify(mImsManager, never()).updateImsServiceConfig(); // Send disconnected indication mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); // Receive a subscription loaded and IMS connection ready indication. - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); sendCarrierConfigChanged(); @@ -420,7 +415,6 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { public void testCarrierConfigSentLocked() throws Exception { // move to ImsService unavailable state. mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); @@ -447,7 +441,6 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { verify(mImsManager, never()).updateImsServiceConfig(); // Receive a subscription loaded and IMS connection ready indication. - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); // CarrierConfigLoader has signalled that the carrier config has been applied for a specific @@ -467,7 +460,6 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { public void testCarrierConfigSentBeforeReady() throws Exception { // move to ImsService unavailable state. mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); @@ -488,7 +480,6 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { verify(mImsManager, never()).updateImsServiceConfig(); // Receive a subscription loaded and IMS connection ready indication. - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); // CarrierConfigLoader has signalled that the carrier config has been applied for a specific @@ -512,7 +503,6 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { public void testCarrierConfigSentBeforeReadyAndCrash() throws Exception { // move to ImsService unavailable state. mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); @@ -1886,7 +1876,6 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { @SmallTest public void testConfigureRtpHeaderExtensionTypes() throws Exception { mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL, true); @@ -1917,7 +1906,6 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { @SmallTest public void testRtpButNoSdp() throws Exception { mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); mContextFixture.getCarrierConfigBundle().putBoolean( CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL, true); @@ -1947,7 +1935,6 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { @SmallTest public void testDontConfigureRtpHeaderExtensionTypes() throws Exception { mConnectorListener.connectionUnavailable(FeatureConnector.UNAVAILABLE_REASON_DISCONNECTED); - doReturn(true).when(mSubscriptionController).isActiveSubId(anyInt()); sendCarrierConfigChanged(); ImsPhoneCallTracker.Config config = new ImsPhoneCallTracker.Config(); config.isD2DCommunicationSupported = false; 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 483a74b18c..d90c948c04 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -17,7 +17,6 @@ package com.android.internal.telephony.imsphone; import static android.Manifest.permission.MODIFY_PHONE_STATE; -import static android.provider.Telephony.SimInfo.COLUMN_PHONE_NUMBER_SOURCE_IMS; import static android.telephony.CarrierConfigManager.USSD_OVER_CS_ONLY; import static android.telephony.CarrierConfigManager.USSD_OVER_CS_PREFERRED; import static android.telephony.CarrierConfigManager.USSD_OVER_IMS_ONLY; @@ -971,7 +970,6 @@ public class ImsPhoneTest extends TelephonyTest { doReturn(subId).when(mPhone).getSubId(); SubscriptionInfo subInfo = mock(SubscriptionInfo.class); doReturn("gb").when(subInfo).getCountryIso(); - doReturn(subInfo).when(mSubscriptionController).getSubscriptionInfo(subId); doReturn(new SubscriptionInfoInternal.Builder().setId(subId).setSimSlotIndex(0) .setCountryIso("gb").build()).when(mSubscriptionManagerService) .getSubscriptionInfoInternal(subId); @@ -983,12 +981,7 @@ public class ImsPhoneTest extends TelephonyTest { }; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService).setNumberFromIms(subId, "+447539447777"); - } else { - verify(mSubscriptionController).setSubscriptionProperty( - subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, "+447539447777"); - } + verify(mSubscriptionManagerService).setNumberFromIms(subId, "+447539447777"); // 2. 1st invalid and 2nd valid: 2nd is set. associatedUris = new Uri[] { @@ -997,12 +990,7 @@ public class ImsPhoneTest extends TelephonyTest { }; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService).setNumberFromIms(subId, "+447539446666"); - } else { - verify(mSubscriptionController).setSubscriptionProperty( - subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, "+447539446666"); - } + verify(mSubscriptionManagerService).setNumberFromIms(subId, "+447539446666"); // 3. 1st sip-uri is not phone number and 2nd valid: 2nd is set. associatedUris = new Uri[] { @@ -1012,12 +1000,7 @@ public class ImsPhoneTest extends TelephonyTest { }; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService).setNumberFromIms(subId, "+447539446677"); - } else { - verify(mSubscriptionController).setSubscriptionProperty( - subId, COLUMN_PHONE_NUMBER_SOURCE_IMS, "+447539446677"); - } + verify(mSubscriptionManagerService).setNumberFromIms(subId, "+447539446677"); // Clean up mContextFixture.addCallingOrSelfPermission(""); @@ -1032,7 +1015,6 @@ public class ImsPhoneTest extends TelephonyTest { doReturn(subId).when(mPhone).getSubId(); SubscriptionInfo subInfo = mock(SubscriptionInfo.class); doReturn("gb").when(subInfo).getCountryIso(); - doReturn(subInfo).when(mSubscriptionController).getSubscriptionInfo(subId); doReturn(new SubscriptionInfoInternal.Builder().setId(subId).setSimSlotIndex(0) .setCountryIso("gb").build()).when(mSubscriptionManagerService) .getSubscriptionInfoInternal(0); @@ -1044,44 +1026,24 @@ public class ImsPhoneTest extends TelephonyTest { }; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); - } else { - verify(mSubscriptionController, never()).setSubscriptionProperty( - anyInt(), any(), any()); - } + verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); // 2. no URI; do not set associatedUris = new Uri[] {}; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); - } else { - verify(mSubscriptionController, never()).setSubscriptionProperty( - anyInt(), any(), any()); - } + verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); // 3. null URI; do not set associatedUris = new Uri[] { null }; mImsPhoneUT.setPhoneNumberForSourceIms(associatedUris); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); - } else { - verify(mSubscriptionController, never()).setSubscriptionProperty( - anyInt(), any(), any()); - } + verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); // 4. null pointer; do not set mImsPhoneUT.setPhoneNumberForSourceIms(null); - if (isSubscriptionManagerServiceEnabled()) { - verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); - } else { - verify(mSubscriptionController, never()).setSubscriptionProperty( - anyInt(), any(), any()); - } + verify(mSubscriptionManagerService, never()).setNumberFromIms(anyInt(), anyString()); // Clean up mContextFixture.addCallingOrSelfPermission(""); diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java index 10151b8b0b..04270b6c4a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PerSimStatusTest.java @@ -43,7 +43,6 @@ import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; -import com.android.internal.telephony.SubscriptionController; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.subscription.SubscriptionInfoInternal; import com.android.internal.telephony.subscription.SubscriptionManagerService; @@ -83,27 +82,17 @@ public class PerSimStatusTest extends TelephonyTest { doReturn(0).when(mPhone).getPhoneId(); doReturn(1).when(mPhone).getSubId(); doReturn(100).when(mPhone).getCarrierId(); - doReturn("6506953210") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); doReturn("6506953210") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); - doReturn("") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); doReturn("") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); - doReturn("+16506953210") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); doReturn("+16506953210") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); SubscriptionInfo subscriptionInfo1 = mock(SubscriptionInfo.class); doReturn("us").when(subscriptionInfo1).getCountryIso(); - doReturn(subscriptionInfo1).when(mSubscriptionController).getSubscriptionInfo(1); doReturn(new SubscriptionInfoInternal.Builder().setId(1).setSimSlotIndex(0) .setCountryIso("us").build()).when(mSubscriptionManagerService) .getSubscriptionInfoInternal(1); @@ -138,27 +127,17 @@ public class PerSimStatusTest extends TelephonyTest { doReturn(1).when(mSecondPhone).getPhoneId(); doReturn(2).when(mSecondPhone).getSubId(); doReturn(101).when(mSecondPhone).getCarrierId(); - doReturn("0123") - .when(mSubscriptionController) - .getPhoneNumber(2, PHONE_NUMBER_SOURCE_UICC, null, null); doReturn("0123") .when(mSubscriptionManagerService) .getPhoneNumber(2, PHONE_NUMBER_SOURCE_UICC, null, null); - doReturn("16506950123") - .when(mSubscriptionController) - .getPhoneNumber(2, PHONE_NUMBER_SOURCE_CARRIER, null, null); doReturn("16506950123") .when(mSubscriptionManagerService) .getPhoneNumber(2, PHONE_NUMBER_SOURCE_CARRIER, null, null); - doReturn("+16506950123") - .when(mSubscriptionController) - .getPhoneNumber(2, PHONE_NUMBER_SOURCE_IMS, null, null); doReturn("+16506950123") .when(mSubscriptionManagerService) .getPhoneNumber(2, PHONE_NUMBER_SOURCE_IMS, null, null); SubscriptionInfo subscriptionInfo2 = mock(SubscriptionInfo.class); doReturn("us").when(subscriptionInfo2).getCountryIso(); - doReturn(subscriptionInfo2).when(mSubscriptionController).getSubscriptionInfo(2); doReturn(new SubscriptionInfoInternal.Builder().setId(2).setSimSlotIndex(1) .setCountryIso("us").build()).when(mSubscriptionManagerService) .getSubscriptionInfoInternal(2); @@ -232,8 +211,7 @@ public class PerSimStatusTest extends TelephonyTest { @Test @SmallTest - public void onPullAtom_perSimStatus_noSubscriptionController() throws Exception { - replaceInstance(SubscriptionController.class, "sInstance", null, null); + public void onPullAtom_perSimStatus_noSubscriptionManagerService() throws Exception { replaceInstance(SubscriptionManagerService.class, "sInstance", null, null); PerSimStatus perSimStatus = PerSimStatus.getCurrentState(mPhone); @@ -247,27 +225,17 @@ public class PerSimStatusTest extends TelephonyTest { doReturn(0).when(mPhone).getPhoneId(); doReturn(1).when(mPhone).getSubId(); doReturn(100).when(mPhone).getCarrierId(); - doReturn("6506953210") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); doReturn("6506953210") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); - doReturn("") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); doReturn("") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); - doReturn("+16506953210") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); doReturn("+16506953210") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class); doReturn("us").when(subscriptionInfo).getCountryIso(); - doReturn(subscriptionInfo).when(mSubscriptionController).getSubscriptionInfo(1); doReturn(new SubscriptionInfoInternal.Builder().setId(1).setSimSlotIndex(0) .setCountryIso("us").build()).when(mSubscriptionManagerService) .getSubscriptionInfoInternal(1); @@ -314,27 +282,17 @@ public class PerSimStatusTest extends TelephonyTest { doReturn(0).when(mPhone).getPhoneId(); doReturn(1).when(mPhone).getSubId(); doReturn(100).when(mPhone).getCarrierId(); - doReturn("6506953210") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); doReturn("6506953210") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); - doReturn("") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); doReturn("") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); - doReturn("+16506953210") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); doReturn("+16506953210") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class); doReturn("us").when(subscriptionInfo).getCountryIso(); - doReturn(subscriptionInfo).when(mSubscriptionController).getSubscriptionInfo(1); doReturn(new SubscriptionInfoInternal.Builder().setId(1).setSimSlotIndex(0) .setCountryIso("us").build()).when(mSubscriptionManagerService) .getSubscriptionInfoInternal(1); @@ -383,27 +341,17 @@ public class PerSimStatusTest extends TelephonyTest { doReturn(0).when(mPhone).getPhoneId(); doReturn(1).when(mPhone).getSubId(); doReturn(100).when(mPhone).getCarrierId(); - doReturn("6506953210") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); doReturn("6506953210") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC, null, null); - doReturn("") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); doReturn("") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER, null, null); - doReturn("+16506953210") - .when(mSubscriptionController) - .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); doReturn("+16506953210") .when(mSubscriptionManagerService) .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS, null, null); SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class); doReturn("us").when(subscriptionInfo).getCountryIso(); - doReturn(subscriptionInfo).when(mSubscriptionController).getSubscriptionInfo(1); doReturn(new SubscriptionInfoInternal.Builder().setId(1).setSimSlotIndex(0) .setCountryIso("us").build()).when(mSubscriptionManagerService) .getSubscriptionInfoInternal(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 1453091322..dc8643f4fc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -159,7 +159,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { public void setUp() throws Exception { logd("SubscriptionManagerServiceTest +Setup!"); super.setUp(getClass().getSimpleName()); - enableSubscriptionManagerService(true); // Dual-SIM configuration mPhones = new Phone[] {mPhone, mPhone2}; @@ -1780,9 +1779,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { mContextFixture.addCallingOrSelfPermission(Manifest.permission.MODIFY_PHONE_STATE); assertThat(mSubscriptionManagerServiceUT.removeSubInfo(FAKE_ICCID1, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM)).isEqualTo(0); + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM)).isEqualTo(true); assertThat(mSubscriptionManagerServiceUT.removeSubInfo(FAKE_ICCID2, - SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM)).isEqualTo(0); + SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM)).isEqualTo(true); mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList( @@ -2119,7 +2118,7 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM); assertThat(mSubscriptionManagerServiceUT.removeSubInfo(FAKE_MAC_ADDRESS1, - SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM)).isEqualTo(0); + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM)).isEqualTo(true); assertThat(mSubscriptionManagerServiceUT.getAllSubInfoList( CALLING_PACKAGE, CALLING_FEATURE)).isEmpty(); assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java index 95f0cd65a5..a9034ebec9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java @@ -24,7 +24,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.atLeast; @@ -578,8 +577,6 @@ public class UiccProfileTest extends TelephonyTest { mUiccProfile.getApplicationIndex(0).getIccRecords().mIccId = fakeIccId; - doReturn(false).when(mSubscriptionController) - .checkPhoneIdAndIccIdMatch(anyInt(), anyString()); doReturn(new SubscriptionInfoInternal.Builder().setSimSlotIndex(0).setId(1) .setIccId("98765").build()).when(mSubscriptionManagerService) .getSubscriptionInfoInternal(anyInt()); @@ -588,8 +585,6 @@ public class UiccProfileTest extends TelephonyTest { .getString("operator_branding_" + fakeIccId, null); assertNotEquals(fakeBrand, brandInSharedPreference); - doReturn(true).when(mSubscriptionController) - .checkPhoneIdAndIccIdMatch(anyInt(), anyString()); doReturn(new SubscriptionInfoInternal.Builder().setSimSlotIndex(0).setId(1) .setIccId(fakeIccId).build()).when(mSubscriptionManagerService) .getSubscriptionInfoInternal(anyInt()); @@ -608,8 +603,6 @@ public class UiccProfileTest extends TelephonyTest { mUiccProfile.getApplicationIndex(0).getIccRecords().mIccId = fakeIccId1; doReturn(fakeIccId2).when(mSubscriptionInfo).getIccId(); - doReturn(mSubscriptionInfo).when(mSubscriptionController) - .getActiveSubscriptionInfoForSimSlotIndex(eq(0), any(), any()); mUiccProfile.setOperatorBrandOverride(fakeBrand); String brandInSharedPreference = mContext.getSharedPreferences("file name", 0) diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java index 8672b45e3e..df57262f52 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java @@ -158,12 +158,7 @@ public class UiccSlotTest extends TelephonyTest { assertTrue(mUiccSlot.isActive()); assertNull(mUiccSlot.getUiccCard()); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); - if (isSubscriptionManagerServiceEnabled()) { - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); - } else { - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); - } + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); } @Test @@ -384,12 +379,7 @@ public class UiccSlotTest extends TelephonyTest { // Make sure when received CARDSTATE_ABSENT state in the first time, mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - if (isSubscriptionManagerServiceEnabled()) { - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); - } else { - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); - } + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); } @@ -422,15 +412,9 @@ public class UiccSlotTest extends TelephonyTest { assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); // assert that we tried to update subscriptions - if (isSubscriptionManagerServiceEnabled()) { - verify(mUiccController).updateSimStateForInactivePort( - activeIss.mSimPortInfos[0].mLogicalSlotIndex, - inactiveIss.mSimPortInfos[0].mIccId); - } else { - verify(mSubInfoRecordUpdater).updateInternalIccStateForInactivePort( - activeIss.mSimPortInfos[0].mLogicalSlotIndex, - inactiveIss.mSimPortInfos[0].mIccId); - } + verify(mUiccController).updateSimStateForInactivePort( + activeIss.mSimPortInfos[0].mLogicalSlotIndex, + inactiveIss.mSimPortInfos[0].mIccId); } @Test @@ -449,16 +433,10 @@ public class UiccSlotTest extends TelephonyTest { assertEquals(IccCardStatus.CardState.CARDSTATE_PRESENT, mUiccSlot.getCardState()); assertNotNull(mUiccSlot.getUiccCard()); - // Simulate when SIM is removed, UiccCard and UiccProfile should be disposed and ABSENT - // state is sent to SubscriptionInfoUpdater. + // Simulate when SIM is removed mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - if (isSubscriptionManagerServiceEnabled()) { - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); - } else { - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); - } + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); verify(mUiccProfile).dispose(); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); @@ -481,13 +459,7 @@ public class UiccSlotTest extends TelephonyTest { // radio state unavailable mUiccSlot.onRadioStateUnavailable(phoneId); - // Verify that UNKNOWN state is sent to SubscriptionInfoUpdater in this case. - if (isSubscriptionManagerServiceEnabled()) { - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.UNKNOWN, null); - } else { - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null, phoneId); - } + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.UNKNOWN, null); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); @@ -495,13 +467,7 @@ public class UiccSlotTest extends TelephonyTest { mIccCardStatus.mCardState = CardState.CARDSTATE_ABSENT; mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); - // Verify that ABSENT state is sent to SubscriptionInfoUpdater in this case. - if (isSubscriptionManagerServiceEnabled()) { - verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); - } else { - verify(mSubInfoRecordUpdater).updateInternalIccState( - IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId); - } + verify(mUiccController).updateSimState(phoneId, IccCardConstants.State.ABSENT, null); assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState()); assertNull(mUiccSlot.getUiccCard()); } -- GitLab From 86c5cc371514a7abbd536a72e61c93bb5d34263d Mon Sep 17 00:00:00 2001 From: Sooraj Sasindran Date: Mon, 17 Apr 2023 16:39:30 -0700 Subject: [PATCH 603/656] Enable pointing UI only in enable satellite mode Enable pointing UI only in enable satellite mode Test: build Bug: 278117106 Change-Id: I6254b48ed4e83e49b111fdfce8294098501a48e7 --- .../telephony/satellite/SatelliteController.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 975eb22758..c808fdad99 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -444,16 +444,16 @@ public class SatelliteController extends Handler { if (argument.enableSatellite) { //If satellite mode is enabled successfully, disable Bluetooth and wifi disableBluetoothWifiState(); + /** + * TODO for NTN-based satellites: Check if satellite is acquired. + */ + if (mNeedsSatellitePointing) { + mPointingAppController.startPointingUI(false); + } } else { //Disabled satellite mode, Reset BT and Wifi if previously changed here checkAndEnableBluetoothWifiState(); } - /** - * TODO for NTN-based satellites: Check if satellite is acquired. - */ - if (mNeedsSatellitePointing) { - mPointingAppController.startPointingUI(false); - } mIsDemoModeEnabled = argument.enableDemoMode; updateSatelliteEnabledState( argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); -- GitLab From 33e9c4fe750199e8a45f200cf7cf75ad4aa7cea6 Mon Sep 17 00:00:00 2001 From: qingqi Date: Thu, 13 Apr 2023 01:11:37 +0000 Subject: [PATCH 604/656] Mitigate VoNR/EPSFB metrics issue in T QPR3 Test: atest VoiceCallSessionStatsTest Bug: 277906557 Change-Id: I4ba852fc914367bb9bba3da7ebd9abd96105fd9c --- .../metrics/VoiceCallSessionStats.java | 83 +++++++++++++------ 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java index d700831429..b2227fd8c0 100644 --- a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java +++ b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java @@ -56,6 +56,7 @@ import android.telecom.VideoProfile.VideoState; import android.telephony.Annotation.NetworkType; import android.telephony.AnomalyReporter; import android.telephony.DisconnectCause; +import android.telephony.NetworkRegistrationInfo; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.ims.ImsReasonInfo; @@ -73,6 +74,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneConnection; import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession; import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.AudioCodec; @@ -379,9 +381,8 @@ public class VoiceCallSessionStats { proto.srvccCompleted = true; proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS; // Call RAT may have changed (e.g. IWLAN -> UMTS) due to bearer change - proto.ratAtEnd = - ServiceStateStats.getVoiceRat( - mPhone, mPhone.getServiceState(), proto.bearerAtEnd); + updateRatAtEnd(proto, getVoiceRatWithVoNRFix( + mPhone, mPhone.getServiceState(), proto.bearerAtEnd)); } break; case TelephonyManager.SRVCC_STATE_HANDOVER_FAILED: @@ -436,8 +437,7 @@ public class VoiceCallSessionStats { } int bearer = getBearer(conn); ServiceState serviceState = getServiceState(); - @NetworkType int rat = ServiceStateStats.getVoiceRat(mPhone, serviceState, bearer); - + @NetworkType int rat = getVoiceRatWithVoNRFix(mPhone, serviceState, bearer); VoiceCallSession proto = new VoiceCallSession(); proto.bearerAtStart = bearer; @@ -527,15 +527,7 @@ public class VoiceCallSessionStats { } // Update end RAT - @NetworkType - int rat = ServiceStateStats.getVoiceRat(mPhone, getServiceState(), proto.bearerAtEnd); - if (proto.ratAtEnd != rat) { - proto.ratSwitchCount++; - proto.ratAtEnd = rat; - if (rat != TelephonyManager.NETWORK_TYPE_UNKNOWN) { - proto.lastKnownRat = rat; - } - } + updateRatAtEnd(proto, getVoiceRatWithVoNRFix(mPhone, getServiceState(), proto.bearerAtEnd)); mAtomsStorage.addVoiceCallSession(proto); @@ -597,8 +589,7 @@ public class VoiceCallSessionStats { proto.setupFailed = false; // Track RAT when voice call is connected. ServiceState serviceState = getServiceState(); - proto.ratAtConnected = - ServiceStateStats.getVoiceRat(mPhone, serviceState, proto.bearerAtEnd); + proto.ratAtConnected = getVoiceRatWithVoNRFix(mPhone, serviceState, proto.bearerAtEnd); // Reset list of codecs with the last codec at the present time. In this way, we // track codec quality only after call is connected and not while ringing. resetCodecList(conn); @@ -609,19 +600,14 @@ public class VoiceCallSessionStats { // RAT usage is not broken down by bearer. In case a CS call is made while there is IMS // voice registration, this may be inaccurate (i.e. there could be multiple RAT in use, but // we only pick the most feasible one). - @NetworkType int rat = ServiceStateStats.getVoiceRat(mPhone, state); + @NetworkType int rat = getVoiceRatWithVoNRFix(mPhone, state, + VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_UNKNOWN); mRatUsage.add(mPhone.getCarrierId(), rat, getTimeMillis(), getConnectionIds()); for (int i = 0; i < mCallProtos.size(); i++) { VoiceCallSession proto = mCallProtos.valueAt(i); - rat = ServiceStateStats.getVoiceRat(mPhone, state, proto.bearerAtEnd); - if (proto.ratAtEnd != rat) { - proto.ratSwitchCount++; - proto.ratAtEnd = rat; - if (rat != TelephonyManager.NETWORK_TYPE_UNKNOWN) { - proto.lastKnownRat = rat; - } - } + rat = getVoiceRatWithVoNRFix(mPhone, state, proto.bearerAtEnd); + updateRatAtEnd(proto, rat); proto.bandAtEnd = (rat == TelephonyManager.NETWORK_TYPE_IWLAN) ? 0 : ServiceStateStats.getBand(state); @@ -629,6 +615,16 @@ public class VoiceCallSessionStats { } } + private void updateRatAtEnd(VoiceCallSession proto, @NetworkType int rat) { + if (proto.ratAtEnd != rat) { + proto.ratSwitchCount++; + proto.ratAtEnd = rat; + if (rat != TelephonyManager.NETWORK_TYPE_UNKNOWN) { + proto.lastKnownRat = rat; + } + } + } + private void finishImsCall(int id, ImsReasonInfo reasonInfo, long durationMillis) { VoiceCallSession proto = mCallProtos.get(id); proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS; @@ -695,6 +691,43 @@ public class VoiceCallSessionStats { return mPhone.getSignalStrength().getLevel(); } + /** + * This is a copy of ServiceStateStats.getVoiceRat(Phone, ServiceState, int) with minimum fix + * required for tracking EPSFB correctly. + */ + @VisibleForTesting private static @NetworkType int getVoiceRatWithVoNRFix( + Phone phone, @Nullable ServiceState state, int bearer) { + if (state == null) { + return TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + ImsPhone imsPhone = (ImsPhone) phone.getImsPhone(); + if (bearer != VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS && imsPhone != null) { + @NetworkType int imsVoiceRat = imsPhone.getImsStats().getImsVoiceRadioTech(); + @NetworkType int wwanPsRat = + ServiceStateStats.getRat(state, NetworkRegistrationInfo.DOMAIN_PS); + if (imsVoiceRat != TelephonyManager.NETWORK_TYPE_UNKNOWN) { + // If IMS is registered over WWAN but WWAN PS is not in service, + // fallback to WWAN CS RAT + boolean isImsVoiceRatValid = + (imsVoiceRat == TelephonyManager.NETWORK_TYPE_IWLAN + || wwanPsRat != TelephonyManager.NETWORK_TYPE_UNKNOWN); + if (isImsVoiceRatValid) { + // Fix for VoNR and EPSFB, b/277906557 + @NetworkType int oldRat = ServiceStateStats.getVoiceRat(phone, state, bearer), + rat = imsVoiceRat == TelephonyManager.NETWORK_TYPE_IWLAN + ? imsVoiceRat : wwanPsRat; + logd("getVoiceRatWithVoNRFix: oldRat=%d, newRat=%d", oldRat, rat); + return rat; + } + } + } + if (bearer == VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS) { + return TelephonyManager.NETWORK_TYPE_UNKNOWN; + } else { + return ServiceStateStats.getRat(state, NetworkRegistrationInfo.DOMAIN_CS); + } + } + /** Resets the list of codecs used for the connection with only the codec currently in use. */ private void resetCodecList(Connection conn) { int id = getConnectionId(conn); -- GitLab From ed3997565f5eead2e429ccd3c189139b715d8610 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 14 Apr 2023 08:48:20 +0000 Subject: [PATCH 605/656] Handle emergency registration failure case Bug: 271385715 Test: manual, ATT Pre-cert test LTE-BTR-1-8985 Change-Id: I4dc06e71c863b2bae85be98114885f677a899dd2 --- .../android/internal/telephony/imsphone/ImsPhoneCallTracker.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 688fa62318..3e39ae1b75 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -3555,6 +3555,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // Since onCallInitiating and onCallProgressing reset mPendingMO, // we can't depend on mPendingMO. if ((reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL + || reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED || reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED) && conn != null) { logi("onCallStartFailed eccCategory=" + eccCategory); -- GitLab From 2f48e3d61a8b76c06925ca74bb1706adc406e9b5 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 18 Apr 2023 15:14:17 -0700 Subject: [PATCH 606/656] Fix setPermanentFailed on unthrottle Since the data profile telephony received as part of unthrottle is reconstructed, the proper data profile to be updated is the data profile instance kept by data profile manager. Fix: 278201016 Test: manual phone call + data browsing Change-Id: Ieadf1dab4cc37560cb33d2a8f72feca7d6ab2c14 --- .../telephony/data/DataRetryManager.java | 2 +- .../telephony/data/DataRetryManagerTest.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataRetryManager.java b/src/java/com/android/internal/telephony/data/DataRetryManager.java index b4022070c4..518689a155 100644 --- a/src/java/com/android/internal/telephony/data/DataRetryManager.java +++ b/src/java/com/android/internal/telephony/data/DataRetryManager.java @@ -1580,7 +1580,6 @@ public class DataRetryManager extends Handler { Stream stream = mDataThrottlingEntries.stream(); stream = stream.filter(entry -> entry.expirationTimeMillis > now); if (dataProfile.getApnSetting() != null) { - dataProfile.getApnSetting().setPermanentFailed(false); stream = stream .filter(entry -> entry.dataProfile.getApnSetting() != null) .filter(entry -> entry.dataProfile.getApnSetting().getApnName() @@ -1621,6 +1620,7 @@ public class DataRetryManager extends Handler { 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) 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 f7233ced3f..62e434e47a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java @@ -365,14 +365,28 @@ public class DataRetryManagerTest extends TelephonyTest { .setSetupRetryType(1) .build(); mDataRetryEntries.addAll(List.of(scheduledRetry1, scheduledRetry2)); + // Suppose we set the data profile as permanently failed. + mDataProfile3.getApnSetting().setPermanentFailed(true); + + DataProfile dataProfile3ReconstructedFromModem = new DataProfile.Builder() + .setApnSetting(new ApnSetting.Builder() + .setEntryName("some_fake_ims") + .setApnName("fake_ims") + .setApnTypeBitmask(ApnSetting.TYPE_IMS) + .setProtocol(ApnSetting.PROTOCOL_IPV6) + .setRoamingProtocol(ApnSetting.PROTOCOL_IP) + .build()) + .build(); // unthrottle the data profile, expect previous retries of the same transport is cancelled mDataRetryManagerUT.obtainMessage(6/*EVENT_DATA_PROFILE_UNTHROTTLED*/, - new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, mDataProfile3, null)) + new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + dataProfile3ReconstructedFromModem, null)) .sendToTarget(); processAllMessages(); // check unthrottle + assertThat(mDataProfile3.getApnSetting().getPermanentFailed()).isFalse(); ArgumentCaptor> throttleStatusCaptor = ArgumentCaptor.forClass(List.class); verify(mDataRetryManagerCallbackMock).onThrottleStatusChanged( -- GitLab From 5546020fcdfab05eec1f2b5fa372cfaf9bed70fa Mon Sep 17 00:00:00 2001 From: sangyun Date: Wed, 19 Apr 2023 16:25:15 +0900 Subject: [PATCH 607/656] Avoid to set displayname to null in euicc sub info. Add condition to avoid set null to displayname in the overriding DISPLAY_NAME when priority is lower than the carrier name source. Bug: 278804726 Test: manually set to null in embeddedProfile Change-Id: I89418dac425b350dc45c59a8afad63df903f48ee --- .../SubscriptionManagerService.java | 8 ++- .../SubscriptionManagerServiceTest.java | 58 +++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index 204cda00ab..288e228fab 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1105,9 +1105,11 @@ public class SubscriptionManagerService extends ISub.Stub { builder.setRemovableEmbedded(isRemovable); // override DISPLAY_NAME if the priority of existing nameSource is <= carrier - if (getNameSourcePriority(nameSource) <= getNameSourcePriority( - SubscriptionManager.NAME_SOURCE_CARRIER)) { - builder.setDisplayName(embeddedProfile.getNickname()); + String nickName = embeddedProfile.getNickname(); + if (nickName != null + && getNameSourcePriority(nameSource) <= getNameSourcePriority( + SubscriptionManager.NAME_SOURCE_CARRIER)) { + builder.setDisplayName(nickName); builder.setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER); } builder.setProfileClass(embeddedProfile.getProfileClass()); 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 2674e1d2ba..0b050788ff 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -2286,4 +2286,62 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.getSubscriptionInfo(2).isEmbedded()) .isEqualTo(true); } + + + @Test + public void testNonNullSubInfoBuilderFromEmbeddedProfile() { + EuiccProfileInfo profileInfo1 = new EuiccProfileInfo.Builder(FAKE_ICCID1) + .setIccid(FAKE_ICCID1) //can't build profile with null iccid. + .setNickname(null) //nullable + .setServiceProviderName(null) //nullable + .setProfileName(null) //nullable + .setCarrierIdentifier(null) //nullable + .setUiccAccessRule(null) //nullable + .build(); + + EuiccProfileInfo profileInfo2 = new EuiccProfileInfo.Builder(FAKE_ICCID2) + .setIccid(FAKE_ICCID2) //impossible to build profile with null iccid. + .setNickname(null) //nullable + .setCarrierIdentifier(new CarrierIdentifier(FAKE_MCC2, FAKE_MNC2, null, null, null, + null, FAKE_CARRIER_ID2, FAKE_CARRIER_ID2)) //not allow null mcc/mnc. + .setUiccAccessRule(null) //nullable + .build(); + + GetEuiccProfileInfoListResult result = new GetEuiccProfileInfoListResult( + EuiccService.RESULT_OK, new EuiccProfileInfo[]{profileInfo1}, false); + doReturn(result).when(mEuiccController).blockingGetEuiccProfileInfoList(eq(1)); + 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()); + + mSubscriptionManagerServiceUT.updateEmbeddedSubscriptions(List.of(1, 2), null); + processAllMessages(); + + SubscriptionInfoInternal subInfo = mSubscriptionManagerServiceUT + .getSubscriptionInfoInternal(1); + assertThat(subInfo.getSubscriptionId()).isEqualTo(1); + assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID1); + assertThat(subInfo.getDisplayName()).isEqualTo(""); + assertThat(subInfo.getDisplayNameSource()).isEqualTo( + SubscriptionManager.NAME_SOURCE_UNKNOWN); + assertThat(subInfo.getMcc()).isEqualTo(""); + assertThat(subInfo.getMnc()).isEqualTo(""); + assertThat(subInfo.isEmbedded()).isTrue(); + assertThat(subInfo.isRemovableEmbedded()).isFalse(); + assertThat(subInfo.getNativeAccessRules()).isEqualTo(new byte[]{}); + + subInfo = mSubscriptionManagerServiceUT.getSubscriptionInfoInternal(2); + assertThat(subInfo.getSubscriptionId()).isEqualTo(2); + assertThat(subInfo.getIccId()).isEqualTo(FAKE_ICCID2); + assertThat(subInfo.getDisplayName()).isEqualTo(""); + assertThat(subInfo.getDisplayNameSource()).isEqualTo( + SubscriptionManager.NAME_SOURCE_UNKNOWN); + assertThat(subInfo.getMcc()).isEqualTo(FAKE_MCC2); + assertThat(subInfo.getMnc()).isEqualTo(FAKE_MNC2); + assertThat(subInfo.isEmbedded()).isTrue(); + assertThat(subInfo.isRemovableEmbedded()).isFalse(); + assertThat(subInfo.getNativeAccessRules()).isEqualTo(new byte[]{}); + } } -- GitLab From e1785ca980d4b0ab650b69290d00caf14a55f6e2 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Fri, 31 Mar 2023 17:39:21 +0000 Subject: [PATCH 608/656] Delay dialing normal routing emergency number in airplane mode Bug: 176505665 Test: RadioOnStateListenerTest Change-Id: Ib323348450405a7dec4a2733530ff0eee9fd2317 --- .../emergency/EmergencyStateTracker.java | 9 +- .../telephony/emergency/RadioOnHelper.java | 18 ++- .../emergency/RadioOnStateListener.java | 137 ++++++++++++++++-- .../emergency/EmergencyStateTrackerTest.java | 14 +- .../emergency/RadioOnStateListenerTest.java | 59 ++++++-- 5 files changed, 199 insertions(+), 38 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java index b5a886be82..96cd880882 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyStateTracker.java @@ -1026,14 +1026,19 @@ public class EmergencyStateTracker { } @Override - public boolean isOkToCall(Phone phone, int serviceState) { + public boolean isOkToCall(Phone phone, int serviceState, boolean imsVoiceCapable) { // We currently only look to make sure that the radio is on before dialing. We // should be able to make emergency calls at any time after the radio has been // powered on and isn't in the UNAVAILABLE state, even if it is reporting the // OUT_OF_SERVICE state. return phone.getServiceStateTracker().isRadioOn(); } - }, !isTestEmergencyNumber, phone, isTestEmergencyNumber); + + @Override + public boolean onTimeout(Phone phone, int serviceState, boolean imsVoiceCapable) { + return true; + } + }, !isTestEmergencyNumber, phone, isTestEmergencyNumber, 0); } else { switchDdsAndSetEmergencyMode(phone, emergencyType); } diff --git a/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java b/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java index 827e495f85..43a53c3666 100644 --- a/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java +++ b/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java @@ -82,7 +82,8 @@ public class RadioOnHelper implements RadioOnStateListener.Callback { * and runs on the main looper.) */ public void triggerRadioOnAndListen(RadioOnStateListener.Callback callback, - boolean forEmergencyCall, Phone phoneForEmergencyCall, boolean isTestEmergencyNumber) { + boolean forEmergencyCall, Phone phoneForEmergencyCall, boolean isTestEmergencyNumber, + int emergencyTimeoutIntervalMillis) { setupListeners(); mCallback = callback; mInProgressListeners.clear(); @@ -93,9 +94,11 @@ public class RadioOnHelper implements RadioOnStateListener.Callback { continue; } + int timeoutCallbackInterval = (forEmergencyCall && phone == phoneForEmergencyCall) + ? emergencyTimeoutIntervalMillis : 0; mInProgressListeners.add(mListeners.get(i)); mListeners.get(i).waitForRadioOn(phone, this, forEmergencyCall, forEmergencyCall - && phone == phoneForEmergencyCall); + && phone == phoneForEmergencyCall, timeoutCallbackInterval); } powerOnRadio(forEmergencyCall, phoneForEmergencyCall, isTestEmergencyNumber); } @@ -152,7 +155,14 @@ public class RadioOnHelper implements RadioOnStateListener.Callback { } @Override - public boolean isOkToCall(Phone phone, int serviceState) { - return (mCallback == null) ? false : mCallback.isOkToCall(phone, serviceState); + public boolean isOkToCall(Phone phone, int serviceState, boolean imsVoiceCapable) { + return (mCallback == null) + ? false : mCallback.isOkToCall(phone, serviceState, imsVoiceCapable); + } + + @Override + public boolean onTimeout(Phone phone, int serviceState, boolean imsVoiceCapable) { + return (mCallback == null) + ? false : mCallback.onTimeout(phone, serviceState, imsVoiceCapable); } } diff --git a/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java b/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java index 01eaaa6307..2262346e50 100644 --- a/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java +++ b/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java @@ -42,10 +42,30 @@ public class RadioOnStateListener { void onComplete(RadioOnStateListener listener, boolean isRadioReady); /** - * Given the Phone and the new service state of that phone, return whether or not this phone - * is ok to call. If it is, onComplete will be called shortly after. + * Returns whether or not this phone is ok to call. + * If it is, onComplete will be called shortly after. + * + * @param phone The Phone associated. + * @param serviceState The service state of that phone. + * @param imsVoiceCapable The IMS voice capability of that phone. + * @return {@code true} if this phone is ok to call. Otherwise, {@code false}. */ - boolean isOkToCall(Phone phone, int serviceState); + boolean isOkToCall(Phone phone, int serviceState, boolean imsVoiceCapable); + + /** + * Returns whether or not this phone is ok to call. + * This callback will be called when timeout happens. + * If this returns {@code true}, onComplete will be called shortly after. + * Otherwise, a new timer will be started again to keep waiting for next timeout. + * The timeout interval will be passed to {@link #waitForRadioOn()} when registering + * this callback. + * + * @param phone The Phone associated. + * @param serviceState The service state of that phone. + * @param imsVoiceCapable The IMS voice capability of that phone. + * @return {@code true} if this phone is ok to call. Otherwise, {@code false}. + */ + boolean onTimeout(Phone phone, int serviceState, boolean imsVoiceCapable); } private static final String TAG = "RadioOnStateListener"; @@ -64,6 +84,8 @@ public class RadioOnStateListener { @VisibleForTesting public static final int MSG_RADIO_ON = 4; public static final int MSG_RADIO_OFF_OR_NOT_AVAILABLE = 5; + public static final int MSG_IMS_CAPABILITY_CHANGED = 6; + public static final int MSG_TIMEOUT_ONTIMEOUT_CALLBACK = 7; private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override @@ -77,8 +99,9 @@ public class RadioOnStateListener { (RadioOnStateListener.Callback) args.arg2; boolean forEmergencyCall = (boolean) args.arg3; boolean isSelectedPhoneForEmergencyCall = (boolean) args.arg4; + int onTimeoutCallbackInterval = args.argi1; startSequenceInternal(phone, callback, forEmergencyCall, - isSelectedPhoneForEmergencyCall); + isSelectedPhoneForEmergencyCall, onTimeoutCallbackInterval); } finally { args.recycle(); } @@ -95,6 +118,11 @@ public class RadioOnStateListener { case MSG_RETRY_TIMEOUT: onRetryTimeout(); break; + case MSG_IMS_CAPABILITY_CHANGED: + onImsCapabilityChanged(); + break; + case MSG_TIMEOUT_ONTIMEOUT_CALLBACK: + onTimeoutCallbackTimeout(); default: Rlog.w(TAG, String.format(Locale.getDefault(), "handleMessage: unexpected message: %d.", msg.what)); @@ -110,6 +138,7 @@ public class RadioOnStateListener { // mForEmergencyCall is true. private boolean mSelectedPhoneForEmergencyCall; private int mNumRetriesSoFar; + private int mOnTimeoutCallbackInterval; // the interval between onTimeout callbacks /** * Starts the "wait for radio" sequence. This is the (single) external API of the @@ -126,7 +155,8 @@ public class RadioOnStateListener { * serialized, and runs only on the handler thread.) */ public void waitForRadioOn(Phone phone, Callback callback, - boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) { + boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, + int onTimeoutCallbackInverval) { Rlog.d(TAG, "waitForRadioOn: Phone " + phone.getPhoneId()); if (mPhone != null) { @@ -139,6 +169,7 @@ public class RadioOnStateListener { args.arg2 = callback; args.arg3 = forEmergencyCall; args.arg4 = isSelectedPhoneForEmergencyCall; + args.argi1 = onTimeoutCallbackInverval; mHandler.obtainMessage(MSG_START_SEQUENCE, args).sendToTarget(); } @@ -148,7 +179,8 @@ public class RadioOnStateListener { * @see #waitForRadioOn */ private void startSequenceInternal(Phone phone, Callback callback, - boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) { + boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, + int onTimeoutCallbackInterval) { Rlog.d(TAG, "startSequenceInternal: Phone " + phone.getPhoneId()); // First of all, clean up any state left over from a prior RadioOn call sequence. This @@ -160,6 +192,7 @@ public class RadioOnStateListener { mCallback = callback; mForEmergencyCall = forEmergencyCall; mSelectedPhoneForEmergencyCall = isSelectedPhoneForEmergencyCall; + mOnTimeoutCallbackInterval = onTimeoutCallbackInterval; registerForServiceStateChanged(); // Register for RADIO_OFF to handle cases where emergency call is dialed before @@ -169,6 +202,49 @@ public class RadioOnStateListener { // onServiceStateChanged(). But also, just in case, start a timer to make sure we'll retry // the call even if the SERVICE_STATE_CHANGED event never comes in for some reason. startRetryTimer(); + registerForImsCapabilityChanged(); + startOnTimeoutCallbackTimer(); + } + + private void onImsCapabilityChanged() { + if (mPhone == null) { + return; + } + + boolean imsVoiceCapable = mPhone.isVoiceOverCellularImsEnabled(); + + Rlog.d(TAG, String.format("onImsCapabilityChanged, capable = %s, Phone = %s", + imsVoiceCapable, mPhone.getPhoneId())); + + if (isOkToCall(mPhone.getServiceState().getState(), imsVoiceCapable)) { + Rlog.d(TAG, "onImsCapabilityChanged: ok to call!"); + + onComplete(true); + cleanup(); + } else { + // The IMS capability changed, but we're still not ready to call yet. + Rlog.d(TAG, "onImsCapabilityChanged: not ready to call yet, keep waiting."); + } + } + + private void onTimeoutCallbackTimeout() { + if (mPhone == null) { + return; + } + + if (onTimeout(mPhone.getServiceState().getState(), + mPhone.isVoiceOverCellularImsEnabled())) { + Rlog.d(TAG, "onTimeout: ok to call!"); + + onComplete(true); + cleanup(); + } else if (mNumRetriesSoFar > MAX_NUM_RETRIES) { + Rlog.w(TAG, "onTimeout: Hit MAX_NUM_RETRIES; giving up."); + cleanup(); + } else { + Rlog.d(TAG, "onTimeout: not ready to call yet, keep waiting."); + startOnTimeoutCallbackTimer(); + } } /** @@ -190,7 +266,7 @@ public class RadioOnStateListener { // - STATE_EMERGENCY_ONLY // Only emergency numbers are allowed; currently not used // - STATE_POWER_OFF // Radio is explicitly powered off (airplane mode) - if (isOkToCall(state.getState())) { + if (isOkToCall(state.getState(), mPhone.isVoiceOverCellularImsEnabled())) { // Woo hoo! It's OK to actually place the call. Rlog.d(TAG, "onServiceStateChanged: ok to call!"); @@ -208,7 +284,7 @@ public class RadioOnStateListener { } ServiceState state = mPhone.getServiceState(); Rlog.d(TAG, String.format("onRadioOn, state = %s, Phone = %s", state, mPhone.getPhoneId())); - if (isOkToCall(state.getState())) { + if (isOkToCall(state.getState(), mPhone.isVoiceOverCellularImsEnabled())) { onComplete(true); cleanup(); } else { @@ -219,8 +295,17 @@ public class RadioOnStateListener { /** * Callback to see if it is okay to call yet, given the current conditions. */ - private boolean isOkToCall(int serviceState) { - return (mCallback == null) ? false : mCallback.isOkToCall(mPhone, serviceState); + private boolean isOkToCall(int serviceState, boolean imsVoiceCapable) { + return (mCallback == null) + ? false : mCallback.isOkToCall(mPhone, serviceState, imsVoiceCapable); + } + + /** + * Callback to see if it is okay to call yet, given the current conditions. + */ + private boolean onTimeout(int serviceState, boolean imsVoiceCapable) { + return (mCallback == null) + ? false : mCallback.onTimeout(mPhone, serviceState, imsVoiceCapable); } /** @@ -242,7 +327,7 @@ public class RadioOnStateListener { // call. // - If the radio is still powered off, try powering it on again. - if (isOkToCall(serviceState)) { + if (isOkToCall(serviceState, mPhone.isVoiceOverCellularImsEnabled())) { Rlog.d(TAG, "onRetryTimeout: Radio is on. Cleaning up."); // Woo hoo -- we successfully got out of airplane mode. @@ -256,6 +341,10 @@ public class RadioOnStateListener { Rlog.d(TAG, "mNumRetriesSoFar is now " + mNumRetriesSoFar); if (mNumRetriesSoFar > MAX_NUM_RETRIES) { + if (mHandler.hasMessages(MSG_TIMEOUT_ONTIMEOUT_CALLBACK)) { + Rlog.w(TAG, "Hit MAX_NUM_RETRIES; waiting onTimeout callback"); + return; + } Rlog.w(TAG, "Hit MAX_NUM_RETRIES; giving up."); cleanup(); } else { @@ -295,10 +384,12 @@ public class RadioOnStateListener { unregisterForRadioOff(); unregisterForRadioOn(); cancelRetryTimer(); + unregisterForImsCapabilityChanged(); // Used for unregisterForServiceStateChanged() so we null it out here instead. mPhone = null; mNumRetriesSoFar = 0; + mOnTimeoutCallbackInterval = 0; } private void startRetryTimer() { @@ -351,6 +442,30 @@ public class RadioOnStateListener { mHandler.removeMessages(MSG_RADIO_ON); // Clean up any pending messages too } + private void registerForImsCapabilityChanged() { + unregisterForImsCapabilityChanged(); + mPhone.getServiceStateTracker() + .registerForImsCapabilityChanged(mHandler, MSG_IMS_CAPABILITY_CHANGED, null); + } + + private void unregisterForImsCapabilityChanged() { + if (mPhone != null) { + mPhone.getServiceStateTracker() + .unregisterForImsCapabilityChanged(mHandler); + } + mHandler.removeMessages(MSG_IMS_CAPABILITY_CHANGED); + } + + private void startOnTimeoutCallbackTimer() { + Rlog.d(TAG, "startOnTimeoutCallbackTimer: mOnTimeoutCallbackInterval=" + + mOnTimeoutCallbackInterval); + mHandler.removeMessages(MSG_TIMEOUT_ONTIMEOUT_CALLBACK); + if (mOnTimeoutCallbackInterval > 0) { + mHandler.sendEmptyMessageDelayed(MSG_TIMEOUT_ONTIMEOUT_CALLBACK, + mOnTimeoutCallbackInterval); + } + } + private void onComplete(boolean isRadioReady) { if (mCallback != null) { Callback tempCallback = mCallback; diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java index aab7063043..2a8e4e2ca3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyStateTrackerTest.java @@ -157,11 +157,13 @@ public class EmergencyStateTrackerTest extends TelephonyTest { ArgumentCaptor callback = ArgumentCaptor .forClass(RadioOnStateListener.Callback.class); verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone), - eq(false)); + eq(false), eq(0)); // isOkToCall() should return true once radio is on - assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE)); + assertFalse(callback.getValue() + .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false)); when(mSST.isRadioOn()).thenReturn(true); - assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE)); + assertTrue(callback.getValue() + .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false)); // Once radio on is complete, trigger delay dial callback.getValue().onComplete(null, true); ArgumentCaptor> completeConsumer = ArgumentCaptor @@ -194,7 +196,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { ArgumentCaptor callback = ArgumentCaptor .forClass(RadioOnStateListener.Callback.class); verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone), - eq(false)); + eq(false), eq(0)); // Verify future completes with DisconnectCause.POWER_OFF if radio not ready CompletableFuture unused = future.thenAccept((result) -> { assertEquals((Integer) result, (Integer) DisconnectCause.POWER_OFF); @@ -222,7 +224,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest { // Radio already on so shouldn't trigger this verify(mRadioOnHelper, never()).triggerRadioOnAndListen(any(), anyBoolean(), any(), - anyBoolean()); + anyBoolean(), eq(0)); // Carrier supports control-plane fallback, so no DDS switch verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any()); } @@ -1610,4 +1612,4 @@ public class EmergencyStateTrackerTest extends TelephonyTest { return null; }).when(phone).exitEmergencyMode(any(Message.class)); } -} \ No newline at end of file +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java index 7ba6f01fc4..45263e4308 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java @@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -64,6 +65,7 @@ public class RadioOnStateListenerTest extends TelephonyTest { super.setUp(getClass().getSimpleName()); MockitoAnnotations.initMocks(this); mListener = new RadioOnStateListener(); + doReturn(mSST).when(mMockPhone).getServiceStateTracker(); } @After @@ -83,7 +85,7 @@ public class RadioOnStateListenerTest extends TelephonyTest { @Test public void testRegisterForCallback() { mMockPhone.mCi = mMockCi; - mListener.waitForRadioOn(mMockPhone, mCallback, false, false); + mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0); waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); @@ -96,8 +98,9 @@ public class RadioOnStateListenerTest extends TelephonyTest { } /** - * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returns true, so we are - * expecting {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to + * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returns true, + * so we are expecting + * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to * return true. */ @Test @@ -106,9 +109,10 @@ public class RadioOnStateListenerTest extends TelephonyTest { state.setState(ServiceState.STATE_IN_SERVICE); when(mMockPhone.getServiceState()).thenReturn(state); when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); - when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(true); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())) + .thenReturn(true); mMockPhone.mCi = mMockCi; - mListener.waitForRadioOn(mMockPhone, mCallback, false, false); + mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0); waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED, @@ -121,17 +125,18 @@ public class RadioOnStateListenerTest extends TelephonyTest { /** * We never receive a * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} because - * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returns false. + * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returns false. */ @Test public void testPhoneChangeState_NoOkToCall_Timeout() { ServiceState state = new ServiceState(); state.setState(ServiceState.STATE_OUT_OF_SERVICE); when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); - when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())) + .thenReturn(false); when(mMockPhone.getServiceState()).thenReturn(state); mMockPhone.mCi = mMockCi; - mListener.waitForRadioOn(mMockPhone, mCallback, false, false); + mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0); waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED, @@ -142,8 +147,8 @@ public class RadioOnStateListenerTest extends TelephonyTest { } /** - * Tests {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returning false and - * hitting the max number of retries. This should result in + * Tests {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returning + * false and hitting the max number of retries. This should result in * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} returning * false. */ @@ -153,13 +158,14 @@ public class RadioOnStateListenerTest extends TelephonyTest { state.setState(ServiceState.STATE_POWER_OFF); when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); when(mMockPhone.getServiceState()).thenReturn(state); - when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())) + .thenReturn(false); mListener.setTimeBetweenRetriesMillis(0/* ms */); mListener.setMaxNumRetries(2); // Wait for the timer to expire and check state manually in onRetryTimeout mMockPhone.mCi = mMockCi; - mListener.waitForRadioOn(mMockPhone, mCallback, false, false); + mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0); waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS); verify(mCallback).onComplete(eq(mListener), eq(false)); @@ -172,16 +178,39 @@ public class RadioOnStateListenerTest extends TelephonyTest { state.setState(ServiceState.STATE_POWER_OFF); when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); when(mMockPhone.getServiceState()).thenReturn(state); - when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())) + .thenReturn(false); mListener.setTimeBetweenRetriesMillis(0/* ms */); mListener.setMaxNumRetries(2); // Wait for the timer to expire and check state manually in onRetryTimeout mMockPhone.mCi = mMockCi; - mListener.waitForRadioOn(mMockPhone, mCallback, true, true); + mListener.waitForRadioOn(mMockPhone, mCallback, true, true, 0); waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS ); verify(mCallback).onComplete(eq(mListener), eq(false)); verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(true), eq(true), eq(false)); } -} \ No newline at end of file + + @Test + public void testTimeout_OnTimeoutForEmergency() { + ServiceState state = new ServiceState(); + state.setState(ServiceState.STATE_POWER_OFF); + when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); + when(mMockPhone.getServiceState()).thenReturn(state); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())) + .thenReturn(false); + when(mCallback.onTimeout(eq(mMockPhone), anyInt(), anyBoolean())) + .thenReturn(true); + mListener.setTimeBetweenRetriesMillis(0 /* ms */); + mListener.setMaxNumRetries(1); + + // Wait for the timer to expire and check state manually in onRetryTimeout + mMockPhone.mCi = mMockCi; + mListener.waitForRadioOn(mMockPhone, mCallback, true, true, 100); + waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS); + + verify(mCallback).onTimeout(eq(mMockPhone), anyInt(), anyBoolean()); + verify(mCallback).onComplete(eq(mListener), eq(true)); + } +} -- GitLab From 5d63759bcbb19f7a2dc4967ddf7a2e28d241d0d6 Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Thu, 20 Apr 2023 07:24:53 +0000 Subject: [PATCH 609/656] [MEP] Enable iccCloseLogicalChannelWithSessionInfo API Modem changes to support the API are merged, hence enabling the API for Radio HAL V2.1 Due to CTS test case failure, this change was reverted earlier. Submitting back as the relevant errors are resolved. Test: Manually verified, atest VtsHalRadioTargetTest:PerInstance/RadioSimTest, atest CtsCarrierApiTestCases:android.carrierapi.cts.CarrierApiTest#testIccCloseLogicalChannel Bug: 268496310 Change-Id: I7100ec7ee864d5794f10f0a144d9368da33b04bc --- .../android/internal/telephony/RadioSimProxy.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/RadioSimProxy.java b/src/java/com/android/internal/telephony/RadioSimProxy.java index d9aba9c44d..7c8ee7b6ea 100644 --- a/src/java/com/android/internal/telephony/RadioSimProxy.java +++ b/src/java/com/android/internal/telephony/RadioSimProxy.java @@ -283,14 +283,11 @@ public class RadioSimProxy extends RadioServiceProxy { if (isEmpty()) return; if (isAidl()) { if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_2_1)) { - // TODO: [MEP-A1] Use iccCloseLogicalChannelWithSessionInfo API once vendor - // changes are completed. - //android.hardware.radio.sim.SessionInfo info = - // new android.hardware.radio.sim.SessionInfo(); - //info.sessionId = channelId; - //info.isEs10 = isEs10; - //mSimProxy.iccCloseLogicalChannelWithSessionInfo(serial, info); - mSimProxy.iccCloseLogicalChannel(serial, channelId); + android.hardware.radio.sim.SessionInfo info = + new android.hardware.radio.sim.SessionInfo(); + info.sessionId = channelId; + info.isEs10 = isEs10; + mSimProxy.iccCloseLogicalChannelWithSessionInfo(serial, info); return; } mSimProxy.iccCloseLogicalChannel(serial, channelId); -- GitLab From 39b7d6ad0da5a815cabc6ab10cf0c0321fc1ead1 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Thu, 20 Apr 2023 11:20:59 +0000 Subject: [PATCH 610/656] NTT-Docomo SMS to misscall notification feature support Fix of sms patterns to match the missed call SMS notification. Fix of single and multiple missed call notification parsing. Bug: 144068181 Test: atest verified and Manually verified single, multiple and other calls by overriding Airtel-IN carrierConfig Change-Id: I2c655d428d7b99ad73b929b7e2fff7bf97f83f74 --- .../MissedIncomingCallSmsFilter.java | 154 +++++++++++------- 1 file changed, 91 insertions(+), 63 deletions(-) diff --git a/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java b/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java index 5932f9ed0c..dce65af8b4 100644 --- a/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java +++ b/src/java/com/android/internal/telephony/MissedIncomingCallSmsFilter.java @@ -23,12 +23,14 @@ import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.os.PersistableBundle; +import android.os.UserHandle; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; import android.telephony.Rlog; import android.telephony.SmsMessage; +import android.telephony.SubscriptionManager; import android.text.TextUtils; import java.time.Instant; @@ -152,9 +154,6 @@ public class MissedIncomingCallSmsFilter { * @return {@code true} if the SMS message has been processed as a missed incoming call SMS. */ private boolean processSms(@NonNull SmsMessage message) { - long missedCallTime = 0; - String callerId = null; - String[] smsPatterns = mCarrierConfig.getStringArray(CarrierConfigManager .KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY); if (smsPatterns == null || smsPatterns.length == 0) { @@ -162,76 +161,91 @@ public class MissedIncomingCallSmsFilter { return false; } - for (String smsPattern : smsPatterns) { - Pattern pattern; - try { - pattern = Pattern.compile(smsPattern, Pattern.DOTALL | Pattern.UNIX_LINES); - } catch (PatternSyntaxException e) { - Rlog.w(TAG, "Configuration error. Unexpected missed incoming call sms " - + "pattern: " + smsPattern + ", e=" + e); - continue; - } - - Matcher matcher = pattern.matcher(message.getMessageBody()); - String year = null, month = null, day = null, hour = null, minute = null; - if (matcher.find()) { - try { - month = matcher.group(SMS_MONTH_TAG); - day = matcher.group(SMS_DAY_TAG); - hour = matcher.group(SMS_HOUR_TAG); - minute = matcher.group(SMS_MINUTE_TAG); - if (VDBG) { - Rlog.v(TAG, "month=" + month + ", day=" + day + ", hour=" + hour - + ", minute=" + minute); - } - } catch (IllegalArgumentException e) { - if (VDBG) { - Rlog.v(TAG, "One of the critical date field is missing. Using the " - + "current time for missed incoming call."); + boolean result = false; + String[] missedCallMsgs = splitCalls(message.getMessageBody()); + if (missedCallMsgs != null && missedCallMsgs.length > 0) { + for (String parsedMsg : missedCallMsgs) { + long missedCallTime = 0; + String callerId = null; + for (String smsPattern : smsPatterns) { + Pattern pattern; + try { + pattern = Pattern.compile(smsPattern, Pattern.DOTALL | Pattern.UNIX_LINES); + } catch (PatternSyntaxException e) { + Rlog.w(TAG, "Configuration error. Unexpected missed incoming call sms " + + "pattern: " + smsPattern + ", e=" + e); + continue; } - missedCallTime = System.currentTimeMillis(); - } - - // Year is an optional field. - try { - year = matcher.group(SMS_YEAR_TAG); - } catch (IllegalArgumentException e) { - if (VDBG) Rlog.v(TAG, "Year is missing."); - } - try { - if (missedCallTime == 0) { - missedCallTime = getEpochTime(year, month, day, hour, minute); - if (missedCallTime == 0) { - Rlog.e(TAG, "Can't get the time. Use the current time."); + Matcher matcher = pattern.matcher(parsedMsg); + String year = null, month = null, day = null, hour = null, minute = null; + if (matcher.find()) { + try { + month = matcher.group(SMS_MONTH_TAG); + day = matcher.group(SMS_DAY_TAG); + hour = matcher.group(SMS_HOUR_TAG); + minute = matcher.group(SMS_MINUTE_TAG); + if (VDBG) { + Rlog.v(TAG, "month=" + month + ", day=" + day + ", hour=" + hour + + ", minute=" + minute); + } + } catch (IllegalArgumentException e) { + if (VDBG) { + Rlog.v(TAG, "One of the critical date field is missing. Using the " + + "current time for missed incoming call."); + } missedCallTime = System.currentTimeMillis(); } - } - if (VDBG) Rlog.v(TAG, "missedCallTime=" + missedCallTime); - } catch (Exception e) { - Rlog.e(TAG, "Can't get the time for missed incoming call"); - } + // Year is an optional field. + try { + year = matcher.group(SMS_YEAR_TAG); + } catch (IllegalArgumentException e) { + if (VDBG) Rlog.v(TAG, "Year is missing."); + } - try { - callerId = matcher.group(SMS_CALLER_ID_TAG); - if (VDBG) Rlog.v(TAG, "caller id=" + callerId); - } catch (IllegalArgumentException e) { - Rlog.d(TAG, "Caller id is not provided or can't be parsed."); + try { + if (missedCallTime == 0) { + missedCallTime = getEpochTime(year, month, day, hour, minute); + if (missedCallTime == 0) { + Rlog.e(TAG, "Can't get the time. Use the current time."); + missedCallTime = System.currentTimeMillis(); + } + } + + if (VDBG) Rlog.v(TAG, "missedCallTime=" + missedCallTime); + } catch (Exception e) { + Rlog.e(TAG, "Can't get the time for missed incoming call"); + } + + try { + callerId = matcher.group(SMS_CALLER_ID_TAG); + if (VDBG) Rlog.v(TAG, "caller id=" + callerId); + } catch (IllegalArgumentException e) { + Rlog.d(TAG, "Caller id is not provided or can't be parsed."); + } + createMissedIncomingCallEvent(missedCallTime, callerId); + result = true; + break; + } } - createMissedIncomingCallEvent(missedCallTime, callerId); - return true; } } - - Rlog.d(TAG, "SMS did not match any missed incoming call SMS pattern."); - return false; + if (!result) { + Rlog.d(TAG, "SMS did not match any missed incoming call SMS pattern."); + } + return result; } - // Create phone account. The logic is copied from PhoneUtils.makePstnPhoneAccountHandle. - private static PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) { - return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT, - String.valueOf(phone.getFullIccSerialNumber())); + private String[] splitCalls(String messageBody) { + String[] messages = null; + if (messageBody != null) { + messages = messageBody.split("(\\n|\\s\\n)" + "(\\n|\\s\\n)"); + Rlog.d(TAG, + "splitTheMultipleCalls no of calls = " + ((messages != null) ? messages.length + : 0)); + } + return messages; } /** @@ -260,4 +274,18 @@ public class MissedIncomingCallSmsFilter { tm.addNewIncomingCall(makePstnPhoneAccountHandle(mPhone), bundle); } } -} + + // Create phone account. The logic is copied from PhoneUtils.makePstnPhoneAccountHandle. + private PhoneAccountHandle makePstnPhoneAccountHandle(Phone phone) { + SubscriptionManager subscriptionManager = + (SubscriptionManager) phone.getContext().getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + UserHandle userHandle = subscriptionManager.getSubscriptionUserHandle(phone.getSubId()); + if (userHandle != null) { + return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT, + String.valueOf(phone.getSubId()), userHandle); + } + return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT, + String.valueOf(phone.getSubId())); + } +} \ No newline at end of file -- GitLab From c07ef505b4e5694ac299b35c618e2cf6a2281aaa Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Wed, 19 Apr 2023 21:34:49 -0700 Subject: [PATCH 611/656] Cleaning up resources when satellite vendor service or modem crashes Bug: 278819112 Test: Call/SMS/MMS with live network. atest android.telephony.satellite.cts.SatelliteManagerTestOnMockService atest com.android.internal.telephony.satellite.DatagramReceiverTest atest com.android.internal.telephony.satellite.DatagramDispatcherTest Change-Id: I9811398b7cde331868e00c16b7f0320452a4a536 --- .../satellite/DatagramController.java | 29 +++++++++++ .../satellite/DatagramDispatcher.java | 49 ++++++++++++++++--- .../satellite/SatelliteController.java | 29 ++++++----- 3 files changed, 87 insertions(+), 20 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 8eca0728b3..45d2d0d10d 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.content.Context; import android.os.Looper; import android.telephony.Rlog; +import android.telephony.SubscriptionManager; import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; @@ -223,6 +224,34 @@ public class DatagramController { return mReceivePendingCount; } + /** + * This function is used by {@link SatelliteController} to notify {@link DatagramController} + * that satellite modem state has changed. + * + * @param state Current satellite modem state. + */ + public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { + if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF + || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { + logd("onSatelliteModemStateChanged: cleaning up resources"); + cleanUpResources(); + } + mDatagramDispatcher.onSatelliteModemStateChanged(state); + } + + private void cleanUpResources() { + if (mReceiveDatagramTransferState + == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING) { + updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, + mReceivePendingCount, + SatelliteManager.SATELLITE_REQUEST_ABORTED); + } + updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0, + SatelliteManager.SATELLITE_ERROR_NONE); + } + private void notifyDatagramTransferStateChangedToSessionController() { SatelliteSessionController sessionController = SatelliteSessionController.getInstance(); if (sessionController == null) { diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index 262f8ee5aa..bcbdaaa920 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.telephony.Rlog; +import android.telephony.SubscriptionManager; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; @@ -277,7 +278,8 @@ public class DatagramDispatcher extends Handler { // Abort sending all the pending datagrams mControllerMetricsStats.reportOutgoingDatagramFailCount( argument.datagramType); - abortSendingPendingDatagrams(argument.subId, error); + abortSendingPendingDatagrams(argument.subId, + SatelliteManager.SATELLITE_REQUEST_ABORTED); } } break; @@ -365,6 +367,8 @@ public class DatagramDispatcher extends Handler { /** * Send error code to all the pending datagrams + * + * @param pendingDatagramsMap The pending datagrams map to be cleaned up. * @param errorCode error code to be returned. */ @GuardedBy("mLock") @@ -374,6 +378,7 @@ public class DatagramDispatcher extends Handler { if (pendingDatagramsMap.size() == 0) { return; } + loge("sendErrorCodeAndCleanupPendingDatagrams: cleaning up resources"); // Send error code to all the pending datagrams for (Entry entry : @@ -391,17 +396,15 @@ public class DatagramDispatcher extends Handler { /** * Abort sending all the pending datagrams. * - * @param subId the subId of the subscription used to send datagram - * @param error error that resulted in abort. + * @param subId The subId of the subscription used to send datagram + * @param errorCode The error code that resulted in abort. */ @GuardedBy("mLock") private void abortSendingPendingDatagrams(int subId, - @SatelliteManager.SatelliteError int error) { + @SatelliteManager.SatelliteError int errorCode) { logd("abortSendingPendingDatagrams()"); - sendErrorCodeAndCleanupPendingDatagrams(mPendingEmergencyDatagramsMap, - SatelliteManager.SATELLITE_REQUEST_ABORTED); - sendErrorCodeAndCleanupPendingDatagrams(mPendingNonEmergencyDatagramsMap, - SatelliteManager.SATELLITE_REQUEST_ABORTED); + sendErrorCodeAndCleanupPendingDatagrams(mPendingEmergencyDatagramsMap, errorCode); + sendErrorCodeAndCleanupPendingDatagrams(mPendingNonEmergencyDatagramsMap, errorCode); } /** @@ -447,6 +450,36 @@ public class DatagramDispatcher extends Handler { sInstance = null; } + /** + * This function is used by {@link DatagramController} to notify {@link DatagramDispatcher} + * that satellite modem state has changed. + * + * @param state Current satellite modem state. + */ + public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { + if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF + || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { + logd("onSatelliteModemStateChanged: cleaning up resources"); + cleanUpResources(); + } + } + + private void cleanUpResources() { + synchronized (mLock) { + mSendingDatagramInProgress = false; + if (getPendingDatagramCount() > 0) { + mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + getPendingDatagramCount(), SatelliteManager.SATELLITE_REQUEST_ABORTED); + } + mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + 0, SatelliteManager.SATELLITE_ERROR_NONE); + abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_REQUEST_ABORTED); + } + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index c061ed2be5..830fd5baa4 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -512,7 +512,7 @@ public class SatelliteController extends Handler { updateSatelliteEnabledState(enabled, "EVENT_IS_SATELLITE_ENABLED_DONE"); } } else if (error == SatelliteManager.SATELLITE_REQUEST_NOT_SUPPORTED) { - updateSatelliteSupportedState(false); + updateSatelliteSupportedStateWhenSatelliteServiceConnected(false); } ((ResultReceiver) request.argument).send(error, bundle); break; @@ -550,7 +550,7 @@ public class SatelliteController extends Handler { boolean supported = (boolean) ar.result; if (DBG) logd("isSatelliteSupported: " + supported); bundle.putBoolean(SatelliteManager.KEY_SATELLITE_SUPPORTED, supported); - updateSatelliteSupportedState(supported); + updateSatelliteSupportedStateWhenSatelliteServiceConnected(supported); } } ((ResultReceiver) request.argument).send(error, bundle); @@ -1481,8 +1481,11 @@ public class SatelliteController extends Handler { * {@link SatelliteController} that the satellite vendor service was just connected. *

* {@link SatelliteController} will send requests to satellite modem to check whether it support - * satellite, whether it is powered on, and whether it is provisioned. - * {@link SatelliteController} will use these cached values to serve requests from its clients. + * satellite and whether it is provisioned. {@link SatelliteController} will use these cached + * values to serve requests from its clients. + *

+ * Because satellite vendor service might have just come back from a crash, we need to disable + * the satellite modem so that resources will be cleaned up and internal states will be reset. */ void onSatelliteServiceConnected() { if (mSatelliteModemInterface.isSatelliteServiceSupported()) { @@ -1684,7 +1687,7 @@ public class SatelliteController extends Handler { } } - private void updateSatelliteSupportedState(boolean supported) { + private void updateSatelliteSupportedStateWhenSatelliteServiceConnected(boolean supported) { synchronized (mIsSatelliteSupportedLock) { mIsSatelliteSupported = supported; } @@ -1695,18 +1698,19 @@ public class SatelliteController extends Handler { registerForPendingDatagramCount(); registerForSatelliteModemStateChanged(); - requestIsSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - new ResultReceiver(this) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - logd("requestIsSatelliteEnabled: resultCode=" + resultCode); - } - }); requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, new ResultReceiver(this) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { logd("requestIsSatelliteProvisioned: resultCode=" + resultCode); + requestSatelliteEnabled(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + false, false, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("requestSatelliteEnabled: result=" + result); + } + }); } }); requestSatelliteCapabilities(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, @@ -1861,6 +1865,7 @@ public class SatelliteController extends Handler { updateSatelliteEnabledState( false, "handleEventSatelliteModemStateChanged"); } + mDatagramController.onSatelliteModemStateChanged(state); } private static void logd(@NonNull String log) { -- GitLab From 4302da81fbe3a256160cb15f48dc96f09288e598 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Tue, 18 Apr 2023 16:30:46 -0700 Subject: [PATCH 612/656] Support pointing app based on its class name Bug: 278468074 Test: Call/SMS/MMS with live network. atest android.telephony.satellite.cts.SatelliteManagerTestOnMockService Change-Id: Ie97042c060c8a97bfddeb06aab8917d8f954398b --- .../satellite/PointingAppController.java | 85 +++++++++++++++++-- .../satellite/SatelliteController.java | 13 +++ 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/PointingAppController.java b/src/java/com/android/internal/telephony/satellite/PointingAppController.java index dcfbe1f513..f7f93cf441 100644 --- a/src/java/com/android/internal/telephony/satellite/PointingAppController.java +++ b/src/java/com/android/internal/telephony/satellite/PointingAppController.java @@ -18,20 +18,25 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.AsyncResult; +import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.SystemProperties; import android.telephony.Rlog; import android.telephony.satellite.ISatelliteTransmissionUpdateCallback; import android.telephony.satellite.PointingInfo; import android.telephony.satellite.SatelliteManager; import android.text.TextUtils; +import com.android.internal.R; import com.android.internal.telephony.Phone; import java.util.ArrayList; @@ -44,11 +49,15 @@ import java.util.function.Consumer; */ public class PointingAppController { private static final String TAG = "PointingAppController"; + private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; + private static final boolean DEBUG = !"user".equals(Build.TYPE); @NonNull private static PointingAppController sInstance; @NonNull private final Context mContext; private boolean mStartedSatelliteTransmissionUpdates; + @NonNull private String mPointingUiPackageName = ""; + @NonNull private String mPointingUiClassName = ""; /** * Map key: subId, value: SatelliteTransmissionUpdateHandler to notify registrants. @@ -334,21 +343,32 @@ public class PointingAppController { * @param needFullScreenPointingUI if pointing UI has to be launchd with Full screen */ public void startPointingUI(boolean needFullScreenPointingUI) { - String packageName = TextUtils.emptyIfNull(mContext.getResources() - .getString(com.android.internal.R.string.config_pointing_ui_package)); + String packageName = getPointingUiPackageName(); if (TextUtils.isEmpty(packageName)) { logd("startPointingUI: config_pointing_ui_package is not set. Ignore the request"); return; } - Intent launchIntent = mContext.getPackageManager().getLaunchIntentForPackage(packageName); + Intent launchIntent; + String className = getPointingUiClassName(); + if (!TextUtils.isEmpty(className)) { + launchIntent = new Intent() + .setComponent(new ComponentName(packageName, className)) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } else { + launchIntent = mContext.getPackageManager().getLaunchIntentForPackage(packageName); + } if (launchIntent == null) { loge("startPointingUI: launchIntent is null"); return; } - launchIntent.putExtra("needFullScreen", needFullScreenPointingUI); - mContext.startActivity(launchIntent); + + try { + mContext.startActivity(launchIntent); + } catch (ActivityNotFoundException ex) { + loge("startPointingUI: Pointing UI app activity is not found, ex=" + ex); + } } public void updateSendDatagramTransferState(int subId, @@ -387,6 +407,61 @@ public class PointingAppController { } } + /** + * This API can be used by only CTS to update satellite pointing UI app package and class names. + * + * @param packageName The package name of the satellite pointing UI app. + * @param className The class name of the satellite pointing UI app. + * @return {@code true} if the satellite pointing UI app package and class is set successfully, + * {@code false} otherwise. + */ + boolean setSatellitePointingUiClassName( + @Nullable String packageName, @Nullable String className) { + if (!isMockModemAllowed()) { + loge("setSatellitePointingUiClassName: modifying satellite pointing UI package and " + + "class name is not allowed"); + return false; + } + + logd("setSatellitePointingUiClassName: config_pointing_ui_package is updated, new " + + "packageName=" + packageName + + ", config_pointing_ui_class new className=" + className); + + if (packageName == null || packageName.equals("null")) { + mPointingUiPackageName = ""; + mPointingUiClassName = ""; + } else { + mPointingUiPackageName = packageName; + if (className == null || className.equals("null")) { + mPointingUiClassName = ""; + } else { + mPointingUiClassName = className; + } + } + + return true; + } + + @NonNull private String getPointingUiPackageName() { + if (!TextUtils.isEmpty(mPointingUiPackageName)) { + return mPointingUiPackageName; + } + return TextUtils.emptyIfNull(mContext.getResources().getString( + R.string.config_pointing_ui_package)); + } + + @NonNull private String getPointingUiClassName() { + if (!TextUtils.isEmpty(mPointingUiClassName)) { + return mPointingUiClassName; + } + return TextUtils.emptyIfNull(mContext.getResources().getString( + R.string.config_pointing_ui_class)); + } + + private boolean isMockModemAllowed() { + return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); + } + private static void logd(@NonNull String log) { Rlog.d(TAG, log); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 830fd5baa4..33a4c296a6 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -1476,6 +1476,19 @@ public class SatelliteController extends Handler { servicePackageName); } + /** + * This API can be used by only CTS to update satellite pointing UI app package and class names. + * + * @param packageName The package name of the satellite pointing UI app. + * @param className The class name of the satellite pointing UI app. + * @return {@code true} if the satellite pointing UI app package and class is set successfully, + * {@code false} otherwise. + */ + public boolean setSatellitePointingUiClassName( + @Nullable String packageName, @Nullable String className) { + return mPointingAppController.setSatellitePointingUiClassName(packageName, className); + } + /** * This function is used by {@link SatelliteModemInterface} to notify * {@link SatelliteController} that the satellite vendor service was just connected. -- GitLab From b0e3f9b6de079c150a006aa9cf8faa8afaa5fe9f Mon Sep 17 00:00:00 2001 From: Willy Hu Date: Sun, 23 Apr 2023 03:43:31 +0800 Subject: [PATCH 613/656] [DSRM] Fix the intent permission problem - Add READ_PRIVILEGED_PHONE_STATE Bug: 278098703 Test: Manual test passed. Scone can receive the intent from DSRM. Change-Id: I38dd51ea2bd55a8690c122140a984f1dece31d46 --- .../internal/telephony/data/DataStallRecoveryManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index 8c4e2877af..6c6f06455d 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.data; +import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE; + import android.annotation.CallbackExecutor; import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; @@ -488,7 +490,7 @@ public class DataStallRecoveryManager extends Handler { Intent intent = new Intent(TelephonyManager.ACTION_DATA_STALL_DETECTED); SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); intent.putExtra(TelephonyManager.EXTRA_RECOVERY_ACTION, recoveryAction); - mPhone.getContext().sendBroadcast(intent); + mPhone.getContext().sendBroadcast(intent, READ_PRIVILEGED_PHONE_STATE); } /** Recovery Action: RECOVERY_ACTION_GET_DATA_CALL_LIST */ -- GitLab From 56fd6acbf1b2a0ea9c3f4b069259f9176468b611 Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Thu, 6 Apr 2023 14:55:05 +0000 Subject: [PATCH 614/656] Satellite demo mode : small listening mode Adjust stay timer to 3 seconds during state transition from sending or receiving to listening. Default value for the transition from sending to listening : 180 seconds. Default value for the transition from receiving to listening : 30 seconds Bug: 276058936 Test: Call/SMS/MMS with live network. Test: atest SatelliteSessionControllerTest atest cts.SatelliteManagerTestOnMockService atest cts.SatelliteManagerTest Change-Id: I62495185514ab41d0d9cc363c41e433d4da19f1c --- .../satellite/SatelliteController.java | 1 + .../satellite/SatelliteSessionController.java | 43 ++++++++++++++++--- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 33a4c296a6..c599659958 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -1742,6 +1742,7 @@ public class SatelliteController extends Handler { } if (mSatelliteSessionController != null) { mSatelliteSessionController.onSatelliteEnabledStateChanged(enabled); + mSatelliteSessionController.setDemoMode(mIsDemoModeEnabled); } else { loge(caller + ": mSatelliteSessionController is not initialized yet"); } diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index 7259abb436..d33046d336 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -86,6 +86,11 @@ public class SatelliteSessionController extends StateMachine { * The default value of {@link #SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS} */ public static final long DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS = 30000; + /** + * The default value of {@link #SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS}, + * and {@link #SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS} for demo mode + */ + public static final long DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS = 3000; private static final int EVENT_DATAGRAM_TRANSFER_STATE_CHANGED = 1; private static final int EVENT_LISTENING_TIMER_TIMEOUT = 2; @@ -119,6 +124,7 @@ public class SatelliteSessionController extends StateMachine { private final ConcurrentHashMap mListeners; @SatelliteManager.SatelliteModemState private int mCurrentState; final boolean mIsSatelliteSupported; + private boolean mIsDemoMode = false; /** * @return The singleton instance of SatelliteSessionController. @@ -163,7 +169,7 @@ public class SatelliteSessionController extends StateMachine { * @param isSatelliteSupported Whether satellite is supported on the device. * @param satelliteModemInterface The singleton of SatelliteModemInterface. * @param satelliteStayAtListeningFromSendingMillis The duration to stay at listening mode when - * transitioning from sending mode. + * transitioning from sending mode. * @param satelliteStayAtListeningFromReceivingMillis The duration to stay at listening mode * when transitioning from receiving mode. */ @@ -324,6 +330,21 @@ public class SatelliteSessionController extends StateMachine { } return true; } + /** + * Adjusts listening timeout duration when demo mode is on + * + * @param isDemoMode {@code true} : The listening timeout durations will be set to + * {@link #DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS} + * {@code false} : The listening timeout durations will be restored to + * production mode + */ + void setDemoMode(boolean isDemoMode) { + mIsDemoMode = isDemoMode; + } + + private boolean isDemoMode() { + return mIsDemoMode; + } private static class DatagramTransferState { @SatelliteManager.SatelliteDatagramTransferState public int sendState; @@ -699,14 +720,22 @@ public class SatelliteSessionController extends StateMachine { } private static long getSatelliteStayAtListeningFromSendingMillis() { - return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, - SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS, - DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS); + if (sInstance != null && sInstance.isDemoMode()) { + return DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS; + } else { + return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, + SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS, + DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_SENDING_MILLIS); + } } private static long getSatelliteStayAtListeningFromReceivingMillis() { - return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, - SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS, - DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS); + if (sInstance != null && sInstance.isDemoMode()) { + return DEMO_MODE_SATELLITE_STAY_AT_LISTENING_MILLIS; + } else { + return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY, + SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS, + DEFAULT_SATELLITE_STAY_AT_LISTENING_FROM_RECEIVING_MILLIS); + } } } -- GitLab From 5fe756e42a447c1b9d58bb79ba85a400070cc478 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Mon, 24 Apr 2023 21:27:32 -0700 Subject: [PATCH 615/656] Unregister network scan before deleting Prevent potential race conditions when we receive the results of a network scan after stopping all network scans. Unregister first to ignore new scans and then stop scans Test: atest FrameworksTelephonyTests Test: try manual network scan and basic tests Bug: 277876263 Change-Id: If1accf4303f9938497c73aea33864642ffae2fb9 --- .../internal/telephony/NetworkScanRequestTracker.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java index 25dd01a50e..75675669c1 100644 --- a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java +++ b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java @@ -474,21 +474,21 @@ public final class NetworkScanRequestTracker { notifyMessenger(nsri, notifyMsg, rilErrorToScanError(nsr.scanError), nsr.networkInfos); if (nsr.scanStatus == NetworkScanResult.SCAN_STATUS_COMPLETE) { - deleteScanAndMayNotify(nsri, NetworkScan.SUCCESS, true); nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); + deleteScanAndMayNotify(nsri, NetworkScan.SUCCESS, true); } } else { if (nsr.networkInfos != null) { notifyMessenger(nsri, notifyMsg, rilErrorToScanError(nsr.scanError), nsr.networkInfos); } - deleteScanAndMayNotify(nsri, rilErrorToScanError(nsr.scanError), true); nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); + deleteScanAndMayNotify(nsri, rilErrorToScanError(nsr.scanError), true); } } else { logEmptyResultOrException(ar); - deleteScanAndMayNotify(nsri, NetworkScan.ERROR_RADIO_INTERFACE_ERROR, true); nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); + deleteScanAndMayNotify(nsri, NetworkScan.ERROR_RADIO_INTERFACE_ERROR, true); } } @@ -516,6 +516,7 @@ public final class NetworkScanRequestTracker { Log.e(TAG, "EVENT_STOP_NETWORK_SCAN_DONE: nsri is null"); return; } + nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); if (ar.exception == null && ar.result != null) { deleteScanAndMayNotify(nsri, NetworkScan.SUCCESS, true); } else { @@ -528,7 +529,6 @@ public final class NetworkScanRequestTracker { Log.wtf(TAG, "EVENT_STOP_NETWORK_SCAN_DONE: ar.exception can not be null!"); } } - nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler); } // Interrupts the live scan is the scanId matches the mScanId of the mLiveRequestInfo. -- GitLab From cfcff03e74a2c54da6fa5c10834baa45fc91def7 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Thu, 20 Apr 2023 23:22:46 +0000 Subject: [PATCH 616/656] Remove work profile telephony feature flag Bug: 278143750 Test: atest CtsTelephonyTestCases Test: Basic phone functionality tests: calls, sending sms and data are working fine. Change-Id: Id84ff07b596840974dd9113a3c1bcda3ef08b438 --- .../SubscriptionManagerService.java | 52 ------------------- .../SubscriptionManagerServiceTest.java | 2 - 2 files changed, 54 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index b43fe9f0e4..8f9f5b289c 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -398,11 +398,6 @@ public class SubscriptionManagerService extends ISub.Stub { public void onUiccApplicationsEnabledChanged(int subId) {} } - /** DeviceConfig key for whether work profile telephony feature is enabled. */ - private static final String KEY_ENABLE_WORK_PROFILE_TELEPHONY = "enable_work_profile_telephony"; - /** {@code true} if the work profile telephony feature is enabled otherwise {@code false}. */ - private boolean mIsWorkProfileTelephonyEnabled = false; - /** * The constructor * @@ -479,15 +474,6 @@ public class SubscriptionManagerService extends ISub.Stub { mSimState = new int[mTelephonyManager.getSupportedModemCount()]; Arrays.fill(mSimState, TelephonyManager.SIM_STATE_UNKNOWN); - mIsWorkProfileTelephonyEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, - KEY_ENABLE_WORK_PROFILE_TELEPHONY, false); - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_TELEPHONY, - mHandler::post, properties -> { - if (TextUtils.equals(DeviceConfig.NAMESPACE_TELEPHONY, properties.getNamespace())) { - onDeviceConfigChanged(); - } - }); - // Create a separate thread for subscription database manager. The database will be updated // from a different thread. HandlerThread handlerThread = new HandlerThread(LOG_TAG); @@ -794,16 +780,6 @@ public class SubscriptionManagerService extends ISub.Stub { return iccidList; } - /** - * Enable or disable work profile telephony feature. - * @param isWorkProfileTelephonyEnabled - {@code true} if the work profile telephony feature - * is enabled otherwise {@code false}. - */ - @VisibleForTesting - public void setWorkProfileTelephonyEnabled(boolean isWorkProfileTelephonyEnabled) { - mIsWorkProfileTelephonyEnabled = isWorkProfileTelephonyEnabled; - } - /** * Set the subscription carrier id. * @@ -3576,11 +3552,6 @@ public class SubscriptionManagerService extends ISub.Stub { public UserHandle getSubscriptionUserHandle(int subId) { enforcePermissions("getSubscriptionUserHandle", Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); - - if (!mIsWorkProfileTelephonyEnabled) { - return null; - } - long token = Binder.clearCallingIdentity(); try { SubscriptionInfoInternal subInfo = mSubscriptionDatabaseManager @@ -3619,10 +3590,6 @@ public class SubscriptionManagerService extends ISub.Stub { enforcePermissions("isSubscriptionAssociatedWithUser", Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION); - if (!mIsWorkProfileTelephonyEnabled) { - return true; - } - long token = Binder.clearCallingIdentity(); try { // Return true if there are no subscriptions on the device. @@ -3677,10 +3644,6 @@ public class SubscriptionManagerService extends ISub.Stub { return new ArrayList<>(); } - if (!mIsWorkProfileTelephonyEnabled) { - return subInfoList; - } - List subscriptionsAssociatedWithUser = new ArrayList<>(); List subscriptionsWithNoAssociation = new ArrayList<>(); for (SubscriptionInfo subInfo : subInfoList) { @@ -3887,21 +3850,6 @@ public class SubscriptionManagerService extends ISub.Stub { }); } - /** - * Listener to update cached flag values from DeviceConfig. - */ - private void onDeviceConfigChanged() { - boolean isWorkProfileTelephonyEnabled = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_TELEPHONY, KEY_ENABLE_WORK_PROFILE_TELEPHONY, - false); - if (isWorkProfileTelephonyEnabled != mIsWorkProfileTelephonyEnabled) { - log("onDeviceConfigChanged: isWorkProfileTelephonyEnabled " - + "changed from " + mIsWorkProfileTelephonyEnabled + " to " - + isWorkProfileTelephonyEnabled); - mIsWorkProfileTelephonyEnabled = isWorkProfileTelephonyEnabled; - } - } - /** * Get the calling package(s). * 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 443a48e5ae..c52c6cc401 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -212,8 +212,6 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { setIdentifierAccess(false); setPhoneNumberAccess(PackageManager.PERMISSION_DENIED); - mSubscriptionManagerServiceUT.setWorkProfileTelephonyEnabled(true); - logd("SubscriptionManagerServiceTest -Setup!"); } -- GitLab From ec89bbef869e98778fa1835a17e926a491cff86e Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Tue, 25 Apr 2023 17:38:35 +0000 Subject: [PATCH 617/656] Initial sim state unknown is not updated during cardstate absent event. Test: Manual verification on P21 and P22, atest FrameworksTelephonyTests:UiccSlotTest Bug: 274192269 Change-Id: Ic1abb3a96f8318cff87c7dcae6e19d0c890db139 --- .../internal/telephony/uicc/UiccSlot.java | 4 +++- .../internal/telephony/uicc/UiccSlotTest.java | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java index fbf807c9b2..db10271a2f 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java +++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java @@ -379,13 +379,15 @@ public class UiccSlot extends Handler { } private void disposeUiccCardIfNeeded(boolean isStateUnknown, int portIndex) { - // First dispose UiccPort corresponding to the portIndex if (mUiccCard != null) { + // First dispose UiccPort corresponding to the portIndex mUiccCard.disposePort(portIndex); if (ArrayUtils.isEmpty(mUiccCard.getUiccPortList())) { // No UiccPort objects are found, safe to dispose the card nullifyUiccCard(isStateUnknown); } + } else { + mStateIsUnknown = isStateUnknown; } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java index df57262f52..230f147e32 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java @@ -561,4 +561,22 @@ public class UiccSlotTest extends TelephonyTest { assertEquals(IccSlotStatus.MultipleEnabledProfilesMode.MEP_B, mUiccSlot.getSupportedMepMode()); } + + @Test + @SmallTest + public void testSimStateUnknown() { + int phoneId = 0; + int slotIndex = 0; + // Initially state is unknown + assertTrue(mUiccSlot.isStateUnknown()); + mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_ABSENT; + mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId, slotIndex); + assertNull(mUiccSlot.getUiccCard()); + // As CardState is absent, state should not be unknown + assertFalse(mUiccSlot.isStateUnknown()); + // radio state unavailable + mUiccSlot.onRadioStateUnavailable(phoneId); + // When radio is not available, state is unknown + assertTrue(mUiccSlot.isStateUnknown()); + } } -- GitLab From ed1e802db2a2eeb0eef004f630555adec874783b Mon Sep 17 00:00:00 2001 From: Sooraj Sasindran Date: Tue, 25 Apr 2023 13:25:02 -0700 Subject: [PATCH 618/656] Handle demo mode and apm error scenarios In apm, dont let satellite to be enabled If satellite disabled, consider demo is also disabled If satellite already enabled but different demo mode request, then return fail If enable request same as current state, return success Bug: 279638203 Test: CTS Change-Id: I25942d8dca75dd12b6682d2ba13af6e74093a043 --- .../satellite/SatelliteController.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 33a4c296a6..73acd66b58 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -147,6 +147,7 @@ public class SatelliteController extends Handler { private final Object mIsSatelliteSupportedLock = new Object(); private boolean mIsDemoModeEnabled = false; private Boolean mIsSatelliteEnabled = null; + private boolean mIsRadioOn = false; private final Object mIsSatelliteEnabledLock = new Object(); private Boolean mIsSatelliteProvisioned = null; private final Object mIsSatelliteProvisionedLock = new Object(); @@ -216,6 +217,7 @@ public class SatelliteController extends Handler { } }); mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); + mIsRadioOn = phone.isRadioOn(); registerForSatelliteProvisionStateChanged(); registerForPendingDatagramCount(); registerForSatelliteModemStateChanged(); @@ -694,6 +696,7 @@ public class SatelliteController extends Handler { case EVENT_RADIO_STATE_CHANGED: { if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF || mCi.getRadioState() == TelephonyManager.RADIO_POWER_UNAVAILABLE) { + mIsRadioOn = false; logd("Radio State Changed to " + mCi.getRadioState()); IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() { @Override @@ -709,6 +712,7 @@ public class SatelliteController extends Handler { request = new SatelliteControllerHandlerRequest(message, phone); handleSatelliteEnabled(request); } else { + mIsRadioOn = true; if (!mSatelliteModemInterface.isSatelliteServiceSupported()) { synchronized (mIsSatelliteSupportedLock) { if (mIsSatelliteSupported == null) { @@ -850,6 +854,33 @@ public class SatelliteController extends Handler { return; } + if (enableSatellite) { + if (!mIsRadioOn) { + loge("Radio is not on, can not enable satellite"); + result.accept(SatelliteManager.SATELLITE_INVALID_MODEM_STATE); + return; + } + } else { + /* if disable satellite, always assume demo is also disabled */ + enableDemoMode = false; + } + + if (mIsSatelliteEnabled != null) { + if (mIsSatelliteEnabled == enableSatellite) { + if (enableDemoMode != mIsDemoModeEnabled) { + loge("Received invalid demo mode while satellite session is enabled" + + " enableDemoMode = " + enableDemoMode); + result.accept(SatelliteManager.SATELLITE_INVALID_ARGUMENTS); + return; + } else { + logd("Enable request matches with current state" + + " enableSatellite = " + enableSatellite); + result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + return; + } + } + } + sendRequestAsync(CMD_SET_SATELLITE_ENABLED, new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result), SatelliteServiceUtils.getPhone()); -- GitLab From d62218ee30999944a859548b7bfbd94dcd7f1201 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 25 Apr 2023 22:40:15 +0000 Subject: [PATCH 619/656] Revert "[Telephony]Unit test support for Apn Id removal at ApnSe..." Revert submission 22309362-DUPLICATE_RMNET_ON_PROFILE_CHANGE_FIX Reason for revert: b/276446877, b/277925484, b/277711525, b/277925691, b/278653254 Reverted changes: /q/submissionid:22309362-DUPLICATE_RMNET_ON_PROFILE_CHANGE_FIX Change-Id: I58ed4a9f58ec2a69a9430261b05d4aedf5b9531e --- .../telephony/data/ApnSettingTest.java | 52 +------------------ 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java index f480805cf5..b6d77e952e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java @@ -205,11 +205,9 @@ public class ApnSettingTest extends TelephonyTest { Field[] fields = ApnSetting.class.getDeclaredFields(); for (Field f : fields) { int modifiers = f.getModifiers(); - if (Modifier.isStatic(modifiers) || !Modifier.isFinal(modifiers) - || "mId".equals(f.getName())) { + if (Modifier.isStatic(modifiers) || !Modifier.isFinal(modifiers)) { continue; } - f.setAccessible(true); ApnSetting testApn = null; if (int.class.equals(f.getType())) { @@ -380,52 +378,4 @@ public class ApnSettingTest extends TelephonyTest { .build(); assertEquals("proxy.mobile.att.net", apn3.getMmsProxyAddressAsString()); } - - @Test - public void testApnProfileEqualsWithoutID() { - ApnSetting apn1 = new ApnSetting.Builder() - .setId(1234) - .setOperatorNumeric("310260") - .setEntryName("ims") - .setApnName("ims") - .setApnTypeBitmask(ApnSetting.TYPE_IMS) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IPV6) - .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_EDGE - | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS)) - .setMtuV4(1440) - .setCarrierEnabled(true) - .build(); - - ApnSetting apn2 = new ApnSetting.Builder() - .setId(1235) - .setOperatorNumeric("310260") - .setEntryName("ims") - .setApnName("ims") - .setApnTypeBitmask(ApnSetting.TYPE_IMS) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IPV6) - .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_EDGE - | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS)) - .setMtuV4(1440) - .setCarrierEnabled(true) - .build(); - - ApnSetting apn3 = new ApnSetting.Builder() - .setId(1234) - .setOperatorNumeric("310260") - .setEntryName("ims") - .setApnName("ims2") - .setApnTypeBitmask(ApnSetting.TYPE_IMS) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IPV6) - .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_EDGE - | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS)) - .setMtuV4(1440) - .setCarrierEnabled(true) - .build(); - - assertTrue(apn1.equals(apn2)); - assertFalse(apn1.equals(apn3)); - } } -- GitLab From 9f43670c1193735e2bd37ea09f46baa6b2c2b651 Mon Sep 17 00:00:00 2001 From: Nagendra Prasad Nagarle Basavaraju Date: Sat, 22 Apr 2023 12:43:50 +0000 Subject: [PATCH 620/656] [Telephony]Fix Service State Update notification - On Frequency change or NR Connection status change, NetworkTypeController fails to update override network in telephony display info for system UI. Reason : ServiceStateTracker fails to update Service State change information for registrants, since haschanged value was resetting at Bandwidth settings change check logic. Bug: 274810933 Test: atest FrameworkTelephonyTests, Sanity Test :b/279568131 Change-Id: I33f78eae9130467c0b406e28b83738b70af52456 --- .../telephony/ServiceStateTracker.java | 2 +- .../telephony/ServiceStateTrackerTest.java | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 6e17ec716c..9fb7d439eb 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -1714,7 +1714,7 @@ public class ServiceStateTracker extends Handler { log("Do not ratchet bandwidths since anchor NR cell is different (" + mLastAnchorNrCellId + "->" + anchorNrCellId + ")."); mLastAnchorNrCellId = anchorNrCellId; - hasChanged = !Arrays.equals(mSS.getCellBandwidths(), bandwidths); + hasChanged |= !Arrays.equals(mSS.getCellBandwidths(), bandwidths); mSS.setCellBandwidths(bandwidths); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index d1db934479..280fbcc177 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -2305,6 +2305,42 @@ public class ServiceStateTrackerTest extends TelephonyTest { assertEquals(ServiceState.FREQUENCY_RANGE_MID, sst.mSS.getNrFrequencyRange()); } + @Test + public void testNotifyServiceStateChangedOnPhysicalConfigUpdates() { + mBundle.putBoolean( + CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, + true); + + // LTE Cell with bandwidth = 10000 + CellIdentityLte cellIdentity11 = + new CellIdentityLte(1, 1, 1, 1, new int[] {1, 2}, 10000, "1", "1", "test", + "tst", Collections.emptyList(), null); + + sendRegStateUpdateForLteCellId(cellIdentity11); + + // Notify Service State changed for BandWidth Change + sendPhyChanConfigChange(new int[] {10000, 40000}, TelephonyManager.NETWORK_TYPE_LTE, 1); + verify(mPhone, times(1)).notifyServiceStateChanged(any(ServiceState.class)); + + // Notify Service State changed for NR Connection Status: LTE -> NR + // with context id update + when(mPhone.getDataNetworkController().isInternetNetwork(eq(3))).thenReturn(true); + sendPhyChanConfigChange(new int[] {10000, 40000}, TelephonyManager.NETWORK_TYPE_NR, 1, + new int[][]{{0, 1}, {2, 3}}); + verify(mPhone, times(2)).notifyServiceStateChanged(any(ServiceState.class)); + + // Service State changed is not notified since no change + when(mPhone.getDataNetworkController().isInternetNetwork(eq(3))).thenReturn(true); + sendPhyChanConfigChange(new int[] {10000, 40000}, TelephonyManager.NETWORK_TYPE_NR, 1, + new int[][]{{0, 1}, {2, 3}}); + verify(mPhone, times(2)).notifyServiceStateChanged(any(ServiceState.class)); + + // Notify Service State changed for NR Connection Status: NR -> LTE + when(mPhone.getDataNetworkController().isInternetNetwork(eq(3))).thenReturn(true); + sendPhyChanConfigChange(new int[] {10000, 40000}, TelephonyManager.NETWORK_TYPE_LTE, 1); + verify(mPhone, times(3)).notifyServiceStateChanged(any(ServiceState.class)); + } + @Test public void testPhyChanBandwidthResetsOnOos() { testPhyChanBandwidthRatchetedOnPhyChanBandwidth(); -- GitLab From e34d3a6f7d5908e7f056632270bcd2058e1368e7 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Tue, 25 Apr 2023 22:40:15 +0000 Subject: [PATCH 621/656] Revert "[Telephony]Unit test support for Apn Id removal at ApnSe..." Revert submission 22309362-DUPLICATE_RMNET_ON_PROFILE_CHANGE_FIX Reason for revert: b/276446877, b/277925484, b/277711525, b/277925691, b/278653254 Reverted changes: /q/submissionid:22309362-DUPLICATE_RMNET_ON_PROFILE_CHANGE_FIX (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1852190e7f1e72f101c83eca817d84552cdb0460) Merged-In: I58ed4a9f58ec2a69a9430261b05d4aedf5b9531e Change-Id: I58ed4a9f58ec2a69a9430261b05d4aedf5b9531e --- .../telephony/data/ApnSettingTest.java | 52 +------------------ 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java index f480805cf5..b6d77e952e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/ApnSettingTest.java @@ -205,11 +205,9 @@ public class ApnSettingTest extends TelephonyTest { Field[] fields = ApnSetting.class.getDeclaredFields(); for (Field f : fields) { int modifiers = f.getModifiers(); - if (Modifier.isStatic(modifiers) || !Modifier.isFinal(modifiers) - || "mId".equals(f.getName())) { + if (Modifier.isStatic(modifiers) || !Modifier.isFinal(modifiers)) { continue; } - f.setAccessible(true); ApnSetting testApn = null; if (int.class.equals(f.getType())) { @@ -380,52 +378,4 @@ public class ApnSettingTest extends TelephonyTest { .build(); assertEquals("proxy.mobile.att.net", apn3.getMmsProxyAddressAsString()); } - - @Test - public void testApnProfileEqualsWithoutID() { - ApnSetting apn1 = new ApnSetting.Builder() - .setId(1234) - .setOperatorNumeric("310260") - .setEntryName("ims") - .setApnName("ims") - .setApnTypeBitmask(ApnSetting.TYPE_IMS) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IPV6) - .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_EDGE - | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS)) - .setMtuV4(1440) - .setCarrierEnabled(true) - .build(); - - ApnSetting apn2 = new ApnSetting.Builder() - .setId(1235) - .setOperatorNumeric("310260") - .setEntryName("ims") - .setApnName("ims") - .setApnTypeBitmask(ApnSetting.TYPE_IMS) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IPV6) - .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_EDGE - | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS)) - .setMtuV4(1440) - .setCarrierEnabled(true) - .build(); - - ApnSetting apn3 = new ApnSetting.Builder() - .setId(1234) - .setOperatorNumeric("310260") - .setEntryName("ims") - .setApnName("ims2") - .setApnTypeBitmask(ApnSetting.TYPE_IMS) - .setProtocol(ApnSetting.PROTOCOL_IPV6) - .setRoamingProtocol(ApnSetting.PROTOCOL_IPV6) - .setNetworkTypeBitmask((int) (TelephonyManager.NETWORK_TYPE_BITMASK_EDGE - | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS)) - .setMtuV4(1440) - .setCarrierEnabled(true) - .build(); - - assertTrue(apn1.equals(apn2)); - assertFalse(apn1.equals(apn3)); - } } -- GitLab From 1d15ad5c6efcc2bd4003ae04defce5ca1ab6022b Mon Sep 17 00:00:00 2001 From: sangyun Date: Tue, 25 Apr 2023 15:10:40 +0900 Subject: [PATCH 622/656] Not to report anomaly for the unknown band of PhysicalChannelConfig Since ARFCN cannot be calculated, unknown band cannot be set in PhysicalChannelConfig, modified not to report anomaly. Bug: 278796964 Test: atest FrameworksTelephonyTests & tested on live network Change-Id: I8cfa14b1420e2810ac9a485a8dbc83e90d4541d3 --- .../internal/telephony/NetworkIndication.java | 15 +++++++++++---- .../internal/telephony/RadioIndication.java | 15 +++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java index b64d8bfa03..7f9ff798b3 100644 --- a/src/java/com/android/internal/telephony/NetworkIndication.java +++ b/src/java/com/android/internal/telephony/NetworkIndication.java @@ -149,22 +149,29 @@ public class NetworkIndication extends IRadioNetworkIndication.Stub { try { for (android.hardware.radio.network.PhysicalChannelConfig config : configs) { PhysicalChannelConfig.Builder builder = new PhysicalChannelConfig.Builder(); + int band = PhysicalChannelConfig.BAND_UNKNOWN; switch (config.band.getTag()) { case android.hardware.radio.network.PhysicalChannelConfigBand.geranBand: - builder.setBand(config.band.getGeranBand()); + band = config.band.getGeranBand(); break; case android.hardware.radio.network.PhysicalChannelConfigBand.utranBand: - builder.setBand(config.band.getUtranBand()); + band = config.band.getUtranBand(); break; case android.hardware.radio.network.PhysicalChannelConfigBand.eutranBand: - builder.setBand(config.band.getEutranBand()); + band = config.band.getEutranBand(); break; case android.hardware.radio.network.PhysicalChannelConfigBand.ngranBand: - builder.setBand(config.band.getNgranBand()); + band = config.band.getNgranBand(); break; default: mRil.riljLoge("Unsupported band type " + config.band.getTag()); } + if (band == PhysicalChannelConfig.BAND_UNKNOWN) { + mRil.riljLoge("Unsupported unknown band."); + return; + } else { + builder.setBand(band); + } response.add(builder.setCellConnectionStatus( RILUtils.convertHalCellConnectionStatus(config.status)) .setDownlinkChannelNumber(config.downlinkChannelNumber) diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java index 800511bc55..cef30c63ac 100644 --- a/src/java/com/android/internal/telephony/RadioIndication.java +++ b/src/java/com/android/internal/telephony/RadioIndication.java @@ -1225,22 +1225,29 @@ public class RadioIndication extends IRadioIndication.Stub { android.hardware.radio.V1_6.PhysicalChannelConfig config = (android.hardware.radio.V1_6.PhysicalChannelConfig) obj; PhysicalChannelConfig.Builder builder = new PhysicalChannelConfig.Builder(); + int band = PhysicalChannelConfig.BAND_UNKNOWN; switch (config.band.getDiscriminator()) { case Band.hidl_discriminator.geranBand: - builder.setBand(config.band.geranBand()); + band = config.band.geranBand(); break; case Band.hidl_discriminator.utranBand: - builder.setBand(config.band.utranBand()); + band = config.band.utranBand(); break; case Band.hidl_discriminator.eutranBand: - builder.setBand(config.band.eutranBand()); + band = config.band.eutranBand(); break; case Band.hidl_discriminator.ngranBand: - builder.setBand(config.band.ngranBand()); + band = config.band.ngranBand(); break; default: mRil.riljLoge("Unsupported band " + config.band.getDiscriminator()); } + if (band == PhysicalChannelConfig.BAND_UNKNOWN) { + mRil.riljLoge("Unsupported unknown band."); + return; + } else { + builder.setBand(band); + } response.add(builder.setCellConnectionStatus( RILUtils.convertHalCellConnectionStatus(config.status)) .setDownlinkChannelNumber(config.downlinkChannelNumber) -- GitLab From 3b0bf21049a391b6254213de12d9a3d44663dbe6 Mon Sep 17 00:00:00 2001 From: sangyun Date: Mon, 24 Apr 2023 17:53:28 +0900 Subject: [PATCH 623/656] Use AnomalyReport without carrier ID to avoid deadlock. If physicalChannelConfigsIndication generates AnomalyReport btw creating Phone and PhoneSwitcher in PhoneFactory, AnomalyReport waits on sLockProxyPhones to get a phone, and PhoneSwitcher's hal command waits for the physicalChannelConfigsIndication to finish. Bug: 278796964 Test: atest FrameworksTelephonyTests & tested on live network Change-Id: I85214c4cbc441b47fc6b8627d4edeabdb7b2dda3 --- .../internal/telephony/RadioIndication.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java index 800511bc55..8f090b7748 100644 --- a/src/java/com/android/internal/telephony/RadioIndication.java +++ b/src/java/com/android/internal/telephony/RadioIndication.java @@ -17,7 +17,6 @@ package com.android.internal.telephony; import static android.telephony.TelephonyManager.HAL_SERVICE_RADIO; -import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CALL_RING; import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION; @@ -1133,7 +1132,7 @@ public class RadioIndication extends IRadioIndication.Stub { || (domain & ~NetworkRegistrationInfo.DOMAIN_CS_PS) != 0 || causeCode < 0 || additionalCauseCode < 0 || (causeCode == Integer.MAX_VALUE && additionalCauseCode == Integer.MAX_VALUE)) { - reportAnomaly( + AnomalyReporter.reportAnomaly( UUID.fromString("f16e5703-6105-4341-9eb3-e68189156eb4"), "Invalid registrationFailed indication"); @@ -1159,7 +1158,7 @@ public class RadioIndication extends IRadioIndication.Stub { mRil.processIndication(HAL_SERVICE_RADIO, indicationType); if (cellIdentity == null || barringInfos == null) { - reportAnomaly( + AnomalyReporter.reportAnomaly( UUID.fromString("645b16bb-c930-4c1c-9c5d-568696542e05"), "Invalid barringInfoChanged indication"); @@ -1257,8 +1256,9 @@ public class RadioIndication extends IRadioIndication.Stub { } } } catch (IllegalArgumentException iae) { - reportAnomaly(UUID.fromString("918f0970-9aa9-4bcd-a28e-e49a83fe77d5"), - "RIL reported invalid PCC (HIDL)"); + AnomalyReporter.reportAnomaly( + UUID.fromString("918f0970-9aa9-4bcd-a28e-e49a83fe77d5"), + "RIL reported invalid PCC (HIDL)"); mRil.riljLoge("Invalid PhysicalChannelConfig " + iae); return; } @@ -1342,10 +1342,4 @@ public class RadioIndication extends IRadioIndication.Stub { mRil.mApnUnthrottledRegistrants.notifyRegistrants( new AsyncResult(null, apn, null)); } - - private void reportAnomaly(UUID uuid, String msg) { - Phone phone = mRil.mPhoneId == null ? null : PhoneFactory.getPhone(mRil.mPhoneId); - int carrierId = phone == null ? UNKNOWN_CARRIER_ID : phone.getCarrierId(); - AnomalyReporter.reportAnomaly(uuid, msg, carrierId); - } } -- GitLab From 46dc47d2fabe00e828cf33fcc614793f74a63394 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Wed, 26 Apr 2023 08:33:16 +0000 Subject: [PATCH 624/656] return void when called getImei in case of RadioModemProxy is empty. Bug: 277664197 Test: atest tests/telephonytests/src/com/android/internal/telephony/RILTest.java also manually verified basic functionality Change-Id: I8b5e8269d5cc8f370d99919ca075ed52766903f1 Merged-In: Ifa2b9c396bada2834808719d882b70e487995049 --- src/java/com/android/internal/telephony/RIL.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index dbf3b12bc1..ba54889415 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -3756,8 +3756,13 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void getImei(Message result) { RadioModemProxy modemProxy = getRadioServiceProxy(RadioModemProxy.class, result); - if (!modemProxy.isEmpty() && - mHalVersion.get(HAL_SERVICE_MODEM).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + if (modemProxy.isEmpty()) { + if (RILJ_LOGD) { + Rlog.e(RILJ_LOG_TAG, "getImei: modemProxy is Empty"); + } + return; + } + if (mHalVersion.get(HAL_SERVICE_MODEM).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { RILRequest rr = obtainRequest(RIL_REQUEST_DEVICE_IMEI, result, mRILDefaultWorkSource); -- GitLab From ef5250e87d3908f4271a13d9b91ab0d62126a5a3 Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Sat, 8 Apr 2023 17:20:56 +0000 Subject: [PATCH 625/656] Separate running thread of ImsResolver's handler to prevent ANR The main thread of phone process may be blocked while processing ImsService's binder call as ther is large area of lock sharing Bug: 276881256 Test: entire Ims Unit Test / Ims cts test Test: e2e Ims Call regression Test Change-Id: I1e7423fd15ef4532dbb5f59e53d024a56f074153 --- .../internal/telephony/ims/ImsResolver.java | 11 ++- .../telephony/ims/ImsResolverTest.java | 13 ++- .../internal/telephony/ims/ImsTestBase.java | 89 +++++++++++++++++++ 3 files changed, 110 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java index f5f3ce7d33..49b7e628e1 100644 --- a/src/java/com/android/internal/telephony/ims/ImsResolver.java +++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java @@ -30,6 +30,7 @@ import android.content.pm.ServiceInfo; import android.os.AsyncResult; import android.os.Handler; import android.os.HandlerExecutor; +import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; @@ -130,6 +131,7 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal // Delay between dynamic ImsService queries. private static final int DELAY_DYNAMIC_QUERY_MS = 5000; + private static final HandlerThread sHandlerThread = new HandlerThread(TAG); private static ImsResolver sInstance; @@ -139,9 +141,9 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal public static void make(Context context, String defaultMmTelPackageName, String defaultRcsPackageName, int numSlots, ImsFeatureBinderRepository repo) { if (sInstance == null) { - Looper looper = Looper.getMainLooper(); + sHandlerThread.start(); sInstance = new ImsResolver(context, defaultMmTelPackageName, defaultRcsPackageName, - numSlots, repo, looper); + numSlots, repo, sHandlerThread.getLooper()); } } @@ -630,8 +632,13 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal /** * Needs to be called after the constructor to kick off the process of binding to ImsServices. + * Should be run on the handler thread of ImsResolver */ public void initialize() { + mHandler.post(()-> initializeInternal()); + } + + private void initializeInternal() { mEventLog.log("Initializing"); Log.i(TAG, "Initializing cache."); PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler, 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 02484ce17b..abc231a94f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java @@ -956,7 +956,7 @@ public class ImsResolverTest extends ImsTestBase { carrierFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(1, ImsFeature.FEATURE_RCS)); // Assume that there is a CarrierConfig change that kicks off query to carrier service. sendCarrierConfigChanged(1, 1); - setupDynamicQueryFeatures(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 2); + setupDynamicQueryFeaturesMultiSim(TEST_CARRIER_DEFAULT_NAME, carrierFeatures, 2); verify(carrierController).changeImsServiceFeatures(eq(carrierFeatures), any(SparseIntArray.class)); deviceFeatureSet = convertToHashSet(deviceFeatures, 0); @@ -2021,6 +2021,7 @@ public class ImsResolverTest extends ImsTestBase { */ private void startBindCarrierConfigAlreadySet() { mTestImsResolver.initialize(); + processAllMessages(); ArgumentCaptor receiversCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mMockContext, times(3)).registerReceiver(receiversCaptor.capture(), any()); @@ -2042,6 +2043,7 @@ public class ImsResolverTest extends ImsTestBase { */ private void startBindNoCarrierConfig(int numSlots) { mTestImsResolver.initialize(); + processAllMessages(); ArgumentCaptor receiversCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mMockContext, times(3)).registerReceiver(receiversCaptor.capture(), any()); @@ -2068,6 +2070,15 @@ public class ImsResolverTest extends ImsTestBase { processAllMessages(); } + private void setupDynamicQueryFeaturesMultiSim(ComponentName name, + HashSet features, int times) { + processAllFutureMessages(); + // ensure that startQuery was called + verify(mMockQueryManager, times(times)).startQuery(eq(name), any(String.class)); + mDynamicQueryListener.onComplete(name, features); + processAllMessages(); + } + private void setupDynamicQueryFeaturesFailure(ComponentName name, int times) { processAllMessages(); // ensure that startQuery was called diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsTestBase.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsTestBase.java index 63fcf10e7c..c6b0fa1cc6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsTestBase.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsTestBase.java @@ -21,6 +21,8 @@ import static org.junit.Assert.fail; import android.content.Context; import android.os.Handler; import android.os.Looper; +import android.os.Message; +import android.os.MessageQueue; import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; @@ -29,6 +31,7 @@ import com.android.internal.telephony.TelephonyTest; import org.mockito.MockitoAnnotations; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -38,6 +41,22 @@ import java.util.concurrent.TimeUnit; * Helper class to load Mockito Resources into a test. */ public class ImsTestBase { + private static final Field MESSAGE_QUEUE_FIELD; + private static final Field MESSAGE_WHEN_FIELD; + private static final Field MESSAGE_NEXT_FIELD; + + static { + try { + MESSAGE_QUEUE_FIELD = MessageQueue.class.getDeclaredField("mMessages"); + MESSAGE_QUEUE_FIELD.setAccessible(true); + MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when"); + MESSAGE_WHEN_FIELD.setAccessible(true); + MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next"); + MESSAGE_NEXT_FIELD.setAccessible(true); + } catch (NoSuchFieldException e) { + throw new RuntimeException("Failed to initialize TelephonyTest", e); + } + } protected Context mContext; protected List mTestableLoopers = new ArrayList<>(); @@ -111,6 +130,52 @@ public class ImsTestBase { } } + /** + * @return The longest delay from all the message queues. + */ + private long getLongestDelay() { + long delay = 0; + for (TestableLooper looper : mTestableLoopers) { + MessageQueue queue = looper.getLooper().getQueue(); + try { + Message msg = (Message) MESSAGE_QUEUE_FIELD.get(queue); + while (msg != null) { + delay = Math.max(msg.getWhen(), delay); + msg = (Message) MESSAGE_NEXT_FIELD.get(msg); + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Access failed in TelephonyTest", e); + } + } + return delay; + } + + /** + * @return {@code true} if there are any messages in the queue. + */ + private boolean messagesExist() { + for (TestableLooper looper : mTestableLoopers) { + MessageQueue queue = looper.getLooper().getQueue(); + try { + Message msg = (Message) MESSAGE_QUEUE_FIELD.get(queue); + if (msg != null) return true; + } catch (IllegalAccessException e) { + throw new RuntimeException("Access failed in TelephonyTest", e); + } + } + return false; + } + + /** + * Handle all messages including the delayed messages. + */ + public void processAllFutureMessages() { + while (messagesExist()) { + moveTimeForward(getLongestDelay()); + processAllMessages(); + } + } + /** * Check if there are any messages to be processed in any monitored TestableLooper * Delayed messages to be handled at a later time will be ignored @@ -123,4 +188,28 @@ public class ImsTestBase { } return true; } + + /** + * Effectively moves time forward by reducing the time of all messages + * for all monitored TestableLoopers + * @param milliSeconds number of milliseconds to move time forward by + */ + public void moveTimeForward(long milliSeconds) { + for (TestableLooper looper : mTestableLoopers) { + MessageQueue queue = looper.getLooper().getQueue(); + try { + Message msg = (Message) MESSAGE_QUEUE_FIELD.get(queue); + while (msg != null) { + long updatedWhen = msg.getWhen() - milliSeconds; + if (updatedWhen < 0) { + updatedWhen = 0; + } + MESSAGE_WHEN_FIELD.set(msg, updatedWhen); + msg = (Message) MESSAGE_NEXT_FIELD.get(msg); + } + } catch (IllegalAccessException e) { + throw new RuntimeException("Access failed in TelephonyTest", e); + } + } + } } -- GitLab From 69672b290bbe1700cc7c3eaa1335d4c3f14c47e4 Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Wed, 19 Apr 2023 04:36:09 +0000 Subject: [PATCH 626/656] Satellite demo mode : check message handling In demo mode, if we get a poll pending datagram message, we need to send stored message which is the latest sent datagram Bug: 276058936 Test: atest DatagramDispatcherTest, DatagramReceiverTest Change-Id: I4572a986797b4294be6fe9b77141e9db181815d6 --- .../satellite/DatagramController.java | 44 ++++++++- .../satellite/DatagramDispatcher.java | 14 ++- .../telephony/satellite/DatagramReceiver.java | 53 ++++++++-- .../satellite/SatelliteController.java | 1 + .../satellite/DatagramDispatcherTest.java | 97 +++++++++++++++++++ .../satellite/DatagramReceiverTest.java | 49 +++++++++- 6 files changed, 247 insertions(+), 11 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 45d2d0d10d..041dd0362a 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -25,6 +25,8 @@ import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; +import com.android.internal.annotations.VisibleForTesting; + import java.util.function.Consumer; /** @@ -53,6 +55,8 @@ public class DatagramController { SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN; private int mReceivePendingCount = 0; private int mReceiveErrorCode = SatelliteManager.SATELLITE_ERROR_NONE; + private SatelliteDatagram mDemoModeDatagram; + private boolean mIsDemoMode = false; /** * @return The singleton instance of DatagramController. @@ -88,7 +92,8 @@ public class DatagramController { * @param pointingAppController PointingAppController is used to update PointingApp * about datagram transfer state changes. */ - private DatagramController(@NonNull Context context, @NonNull Looper looper, + @VisibleForTesting + protected DatagramController(@NonNull Context context, @NonNull Looper looper, @NonNull PointingAppController pointingAppController) { mContext = context; mPointingAppController = pointingAppController; @@ -150,6 +155,9 @@ public class DatagramController { * input to this method. Datagram received here will be passed down to modem without any * encoding or encryption. * + * When demo mode is on, save the sent datagram and this datagram will be used as a received + * datagram. + * * @param subId The subId of the subscription to send satellite datagrams for. * @param datagramType datagram type indicating whether the datagram is of type * SOS_SMS or LOCATION_SHARING. @@ -162,6 +170,7 @@ public class DatagramController { public void sendSatelliteDatagram(int subId, @SatelliteManager.DatagramType int datagramType, @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI, @NonNull Consumer callback) { + setDemoModeDatagram(datagramType, datagram); mDatagramDispatcher.sendSatelliteDatagram(subId, datagramType, datagram, needFullScreenPointingUI, callback); } @@ -252,6 +261,39 @@ public class DatagramController { SatelliteManager.SATELLITE_ERROR_NONE); } + /** + * Set variables for {@link DatagramDispatcher} and {@link DatagramReceiver} to run demo mode + * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise. + */ + void setDemoMode(boolean isDemoMode) { + mIsDemoMode = isDemoMode; + mDatagramDispatcher.setDemoMode(isDemoMode); + mDatagramReceiver.setDemoMode(isDemoMode); + + if (!isDemoMode) { + mDemoModeDatagram = null; + } + } + + /** Get the last sent datagram for demo mode */ + @VisibleForTesting + public SatelliteDatagram getDemoModeDatagram() { + return mDemoModeDatagram; + } + + /** + * Set last sent datagram for demo mode + * @param datagramType datagram type, only DATAGRAM_TYPE_SOS_MESSAGE will be saved + * @param datagram datagram The last datagram saved when sendSatelliteDatagramForDemo is called + */ + @VisibleForTesting + protected void setDemoModeDatagram(@SatelliteManager.DatagramType int datagramType, + SatelliteDatagram datagram) { + if (mIsDemoMode && datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { + mDemoModeDatagram = datagram; + } + } + private void notifyDatagramTransferStateChangedToSessionController() { SatelliteSessionController sessionController = SatelliteSessionController.getInstance(); if (sessionController == null) { diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index bcbdaaa920..7c46fb81fd 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -56,6 +56,8 @@ public class DatagramDispatcher extends Handler { @NonNull private final DatagramController mDatagramController; @NonNull private final ControllerMetricsStats mControllerMetricsStats; + private boolean mIsDemoMode = false; + private static AtomicLong mNextDatagramId = new AtomicLong(0); private final Object mLock = new Object(); @@ -101,7 +103,8 @@ public class DatagramDispatcher extends Handler { * @param looper The looper for the handler. * @param datagramController DatagramController which is used to update datagram transfer state. */ - private DatagramDispatcher(@NonNull Context context, @NonNull Looper looper, + @VisibleForTesting + protected DatagramDispatcher(@NonNull Context context, @NonNull Looper looper, @NonNull DatagramController datagramController) { super(looper); mContext = context; @@ -337,6 +340,15 @@ public class DatagramDispatcher extends Handler { } } + /** Set demo mode + * + * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise. + */ + @VisibleForTesting + protected void setDemoMode(boolean isDemoMode) { + mIsDemoMode = isDemoMode; + } + /** * Send pending satellite datagrams. Emergency datagrams are given priority over * non-emergency datagrams. diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index a47b16b50b..bc2904482a 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -29,7 +29,6 @@ import android.database.SQLException; import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; @@ -74,9 +73,10 @@ public class DatagramReceiver extends Handler { @NonNull private SharedPreferences mSharedPreferences = null; @NonNull private final DatagramController mDatagramController; @NonNull private final ControllerMetricsStats mControllerMetricsStats; + @NonNull private final Looper mLooper; private long mDatagramTransferStartTime = 0; - @NonNull private final Looper mLooper; + private boolean mIsDemoMode = false; /** * Map key: subId, value: SatelliteDatagramListenerHandler to notify registrants. @@ -116,7 +116,8 @@ public class DatagramReceiver extends Handler { * @param looper The looper for the handler. * @param datagramController DatagramController which is used to update datagram transfer state. */ - private DatagramReceiver(@NonNull Context context, @NonNull Looper looper, + @VisibleForTesting + protected DatagramReceiver(@NonNull Context context, @NonNull Looper looper, @NonNull DatagramController datagramController) { super(looper); mContext = context; @@ -328,10 +329,10 @@ public class DatagramReceiver extends Handler { if (pendingCount == 0 && satelliteDatagram == null) { sInstance.mDatagramController.updateReceiveStatus(mSubId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE, - 0, SatelliteManager.SATELLITE_ERROR_NONE); + pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); } else if (satelliteDatagram != null) { sInstance.mDatagramController.updateReceiveStatus(mSubId, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS, pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); long datagramId = getDatagramId(); @@ -345,7 +346,7 @@ public class DatagramReceiver extends Handler { // wait for ack and retry after the timeout specified. sendMessageDelayed( obtainMessage(EVENT_RETRY_DELIVERING_RECEIVED_DATAGRAM, - argument), getTimeoutToReceiveAck()); + argument), getTimeoutToReceiveAck()); }); sInstance.mControllerMetricsStats.reportIncomingDatagramCount( @@ -453,8 +454,26 @@ public class DatagramReceiver extends Handler { request = (DatagramReceiverHandlerRequest) ar.userObj; int error = SatelliteServiceUtils.getSatelliteError(ar, "pollPendingSatelliteDatagrams"); - logd("EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE error: " + error); + if (mIsDemoMode && error == SatelliteManager.SATELLITE_ERROR_NONE) { + SatelliteDatagram datagram = mDatagramController.getDemoModeDatagram(); + final int validSubId = SatelliteServiceUtils.getValidSatelliteSubId( + request.subId, mContext); + SatelliteDatagramListenerHandler listenerHandler = + mSatelliteDatagramListenerHandlers.get(validSubId); + if (listenerHandler != null) { + Pair pair = new Pair<>(datagram, 0); + ar = new AsyncResult(null, pair, null); + Message message = listenerHandler.obtainMessage( + SatelliteDatagramListenerHandler.EVENT_SATELLITE_DATAGRAM_RECEIVED, + ar); + listenerHandler.sendMessage(message); + } else { + error = SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; + } + } + + logd("EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE error: " + error); if (error != SatelliteManager.SATELLITE_ERROR_NONE) { mDatagramController.updateReceiveStatus(request.subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, @@ -561,7 +580,16 @@ public class DatagramReceiver extends Handler { mDatagramTransferStartTime = System.currentTimeMillis(); Phone phone = SatelliteServiceUtils.getPhone(); - sendRequestAsync(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, callback, phone, subId); + + if (mIsDemoMode) { + DatagramReceiverHandlerRequest request = new DatagramReceiverHandlerRequest( + callback, phone, subId); + AsyncResult ar = new AsyncResult(request, SatelliteManager.SATELLITE_ERROR_NONE, null); + Message msg = this.obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, ar); + msg.sendToTarget(); + } else { + sendRequestAsync(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, callback, phone, subId); + } } /** @@ -605,6 +633,15 @@ public class DatagramReceiver extends Handler { .build()); } + /** Set demo mode + * + * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise. + */ + @VisibleForTesting + protected void setDemoMode(boolean isDemoMode) { + mIsDemoMode = isDemoMode; + } + /** * Destroys this DatagramDispatcher. Used for tearing down static resources during testing. */ diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 88a484ae15..f5cdcb6c8d 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -457,6 +457,7 @@ public class SatelliteController extends Handler { checkAndEnableBluetoothWifiState(); } mIsDemoModeEnabled = argument.enableDemoMode; + mDatagramController.setDemoMode(mIsDemoModeEnabled); updateSatelliteEnabledState( argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java index f9d87a80cc..332b3d9bc5 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java @@ -26,6 +26,8 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.verifyNoMoreInteractions; +import android.annotation.NonNull; +import android.content.Context; import android.os.AsyncResult; import android.os.Looper; import android.os.Message; @@ -59,8 +61,10 @@ public class DatagramDispatcherTest extends TelephonyTest { private static final String TEST_MESSAGE = "This is a test datagram message"; private DatagramDispatcher mDatagramDispatcherUT; + private TestDatagramDispatcher mTestDemoModeDatagramDispatcher; @Mock private DatagramController mMockDatagramController; + @Mock private DatagramReceiver mMockDatagramReceiver; @Mock private SatelliteModemInterface mMockSatelliteModemInterface; @Mock private ControllerMetricsStats mMockControllerMetricsStats; @@ -77,6 +81,8 @@ public class DatagramDispatcherTest extends TelephonyTest { replaceInstance(DatagramController.class, "sInstance", null, mMockDatagramController); + replaceInstance(DatagramReceiver.class, "sInstance", null, + mMockDatagramReceiver); replaceInstance(SatelliteModemInterface.class, "sInstance", null, mMockSatelliteModemInterface); replaceInstance(ControllerMetricsStats.class, "sInstance", null, @@ -84,6 +90,8 @@ public class DatagramDispatcherTest extends TelephonyTest { mDatagramDispatcherUT = DatagramDispatcher.make(mContext, Looper.myLooper(), mMockDatagramController); + mTestDemoModeDatagramDispatcher = new TestDatagramDispatcher(mContext, Looper.myLooper(), + mMockDatagramController); mResultListener = new LinkedBlockingQueue<>(1); mDatagram = new SatelliteDatagram(TEST_MESSAGE.getBytes()); @@ -95,6 +103,7 @@ public class DatagramDispatcherTest extends TelephonyTest { logd(TAG + " tearDown"); mDatagramDispatcherUT.destroy(); mDatagramDispatcherUT = null; + mTestDemoModeDatagramDispatcher = null; mResultListener = null; mDatagram = null; mInOrder = null; @@ -274,4 +283,92 @@ public class DatagramDispatcherTest extends TelephonyTest { assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_SERVICE_ERROR); } + + @Test + public void testSendSatelliteDatagram_DemoMode_data_type_sos_message() throws Exception { + mTestDemoModeDatagramDispatcher.setDemoMode(true); + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + + mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, + new AsyncResult(message.obj, null, null)) + .sendToTarget(); + return null; + }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class), + anyBoolean()); + + mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + true, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + mTestDemoModeDatagramDispatcher.setDemoMode(false); + } + + @Test + public void testSendSatelliteDatagram_DemoMode_data_type_location_sharing() throws Exception { + mTestDemoModeDatagramDispatcher.setDemoMode(true); + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + + mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, + new AsyncResult(message.obj, null, null)) + .sendToTarget(); + return null; + }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class), + anyBoolean()); + + mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram, + true, mResultListener::offer); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + + mTestDemoModeDatagramDispatcher.setDemoMode(false); + } + + private static class TestDatagramDispatcher extends DatagramDispatcher { + TestDatagramDispatcher(@NonNull Context context, @NonNull Looper looper, + @NonNull DatagramController datagramController) { + super(context, looper, datagramController); + } + + @Override + protected void setDemoMode(boolean isDemoMode) { + super.setDemoMode(isDemoMode); + } + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java index c33b11d610..1be8e03b9f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.satellite; +import android.annotation.NonNull; +import android.content.Context; import android.provider.Telephony; import android.test.mock.MockContentResolver; import android.testing.AndroidTestingRunner; @@ -25,9 +27,14 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.os.AsyncResult; import android.os.Looper; @@ -65,7 +72,6 @@ public class DatagramReceiverTest extends TelephonyTest { @Mock private SatelliteModemInterface mMockSatelliteModemInterface; @Mock private ControllerMetricsStats mMockControllerMetricsStats; - /** Variables required to receive datagrams in the unit tests. */ LinkedBlockingQueue mResultListener; SatelliteDatagram mDatagram; @@ -307,4 +313,45 @@ public class DatagramReceiverTest extends TelephonyTest { eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_SUCCESS), eq(10), eq(SatelliteManager.SATELLITE_ERROR_NONE)); } + + @Test + public void testPollPendingSatelliteDatagrams_DemoMode() throws Exception { + // Checks invalid case only as SatelliteController does not exist in unit test + TestDatagramReceiver testDatagramReceiver = new TestDatagramReceiver( + mContext, Looper.myLooper(), mMockDatagramController); + testDatagramReceiver.setDemoMode(true); + when(mMockDatagramController.getDemoModeDatagram()).thenReturn(mDatagram); + testDatagramReceiver.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); + processAllMessages(); + verify(mMockDatagramController, times(1)).getDemoModeDatagram(); + verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), + anyInt(), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), + anyInt(), + eq(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE)); + verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), + anyInt(), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + assertThat(mResultListener.peek()) + .isEqualTo(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); + } + + private static class TestDatagramReceiver extends DatagramReceiver { + TestDatagramReceiver(@NonNull Context context, @NonNull Looper looper, + @NonNull DatagramController datagramController) { + super(context, looper, datagramController); + } + + @Override + protected void setDemoMode(boolean isDemoMode) { + super.setDemoMode(isDemoMode); + } + } } -- GitLab From 680eba2636072e00c6dcd1a3c7df08d5f4c1ba00 Mon Sep 17 00:00:00 2001 From: Gil Cukierman Date: Fri, 28 Apr 2023 15:36:57 +0000 Subject: [PATCH 627/656] Enable null cipher toggle by default Test: atest GsmCdmaPhoneTest NullAlgorithmsPreferenceController Test: Manual test on multiple real targets and cf Bug: 262063621 Change-Id: Ie0e3beb51492ee49aebd21c00a9dd8e853a83df2 --- src/java/com/android/internal/telephony/GsmCdmaPhone.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 2c2b6e632a..4d4f99f09f 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -5102,7 +5102,7 @@ public class GsmCdmaPhone extends Phone { @Override public void handleNullCipherEnabledChange() { if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_CELLULAR_SECURITY, - TelephonyManager.PROPERTY_ENABLE_NULL_CIPHER_TOGGLE, false)) { + TelephonyManager.PROPERTY_ENABLE_NULL_CIPHER_TOGGLE, true)) { logi("Not handling null cipher update. Feature disabled by DeviceConfig."); return; } -- GitLab From ef2f9f6ff78e63c2a5b0d492838a2cbe54aeaea9 Mon Sep 17 00:00:00 2001 From: yomna Date: Wed, 19 Apr 2023 22:06:24 +0000 Subject: [PATCH 628/656] Add isNullCipherAndIntegrityEnabled to RIL Bug: 237529943 Test: m Change-Id: I64344a8c36898290914c1b76721abc39fd145b17 Merged-In: I1129e21695163535ec77dbafaf60c56c2346c707 --- .../internal/telephony/CommandsInterface.java | 7 ++++ .../com/android/internal/telephony/RIL.java | 35 +++++++++++++++++++ .../android/internal/telephony/RILUtils.java | 3 ++ 3 files changed, 45 insertions(+) diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java index 439b19b019..971e051c5e 100644 --- a/src/java/com/android/internal/telephony/CommandsInterface.java +++ b/src/java/com/android/internal/telephony/CommandsInterface.java @@ -2989,6 +2989,13 @@ public interface CommandsInterface { */ default void setNullCipherAndIntegrityEnabled(boolean enabled, Message result) {} + /** + * Check whether null ciphering and/or null integrity-protected connections are allowed. + * + * @param result Callback message containing the success or failure status. + */ + default void isNullCipherAndIntegrityEnabled(Message result) {} + /** * Notifies the IMS call status to the modem. * diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index dbf3b12bc1..37c1d6a2ce 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -5664,6 +5664,41 @@ public class RIL extends BaseCommands implements CommandsInterface { } } + /** + * Get if null ciphering / null integrity are enabled / disabled. + * + * @param result Callback message containing the success or failure status. + */ + @Override + public void isNullCipherAndIntegrityEnabled(Message result) { + RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class, result); + if (networkProxy.isEmpty()) return; + if (mHalVersion.get(HAL_SERVICE_NETWORK).greaterOrEqual(RADIO_HAL_VERSION_2_1)) { + RILRequest rr = obtainRequest(RIL_REQUEST_IS_NULL_CIPHER_AND_INTEGRITY_ENABLED, result, + mRILDefaultWorkSource); + + if (RILJ_LOGD) { + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)); + } + + try { + networkProxy.isNullCipherAndIntegrityEnabled(rr.mSerial); + } catch (RemoteException | RuntimeException e) { + handleRadioProxyExceptionForRR( + HAL_SERVICE_NETWORK, "isNullCipherAndIntegrityEnabled", e); + } + } else { + if (RILJ_LOGD) { + Rlog.d(RILJ_LOG_TAG, "isNullCipherAndIntegrityEnabled: REQUEST_NOT_SUPPORTED"); + } + if (result != null) { + AsyncResult.forMessage(result, null, + CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); + result.sendToTarget(); + } + } + } + /** * {@inheritDoc} */ diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java index bd70e92d40..9db186fbf8 100644 --- a/src/java/com/android/internal/telephony/RILUtils.java +++ b/src/java/com/android/internal/telephony/RILUtils.java @@ -117,6 +117,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IMS_SEND_S import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ISIM_AUTHENTICATION; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_N1_MODE_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_NR_DUAL_CONNECTIVITY_ENABLED; +import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_NULL_CIPHER_AND_INTEGRITY_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IS_VONR_ENABLED; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_LAST_CALL_FAIL_CAUSE; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE; @@ -5347,6 +5348,8 @@ public class RILUtils { return "TRIGGER_EPS_FALLBACK"; case RIL_REQUEST_SET_NULL_CIPHER_AND_INTEGRITY_ENABLED: return "SET_NULL_CIPHER_AND_INTEGRITY_ENABLED"; + case RIL_REQUEST_IS_NULL_CIPHER_AND_INTEGRITY_ENABLED: + return "IS_NULL_CIPHER_AND_INTEGRITY_ENABLED"; case RIL_REQUEST_UPDATE_IMS_CALL_STATUS: return "UPDATE_IMS_CALL_STATUS"; case RIL_REQUEST_SET_N1_MODE_ENABLED: -- GitLab From b6c017564388d6a6cfd9d6a0b4f1865007841bd3 Mon Sep 17 00:00:00 2001 From: Hakjun Choi Date: Wed, 26 Apr 2023 03:21:46 +0000 Subject: [PATCH 629/656] Satellite demo mode : Simulated sending and receiving Message sending/receive is considered successful when the device is towards satellite within a reasonable margin Bug: 276058936 Test: atest DatagramDispatcherTest, DatagramReceiverTest Test: cts/SatelliteManagerTest, SatelliteManagerTestOnMockService Change-Id: Iaf91810a85f0ade3a8adf0d4963aeea1e21e3f79 --- .../satellite/DatagramController.java | 59 +++++--- .../satellite/DatagramDispatcher.java | 99 ++++++++++++- .../telephony/satellite/DatagramReceiver.java | 132 +++++++++++++++++- .../satellite/SatelliteController.java | 23 ++- .../satellite/DatagramDispatcherTest.java | 67 ++++++++- .../satellite/DatagramReceiverTest.java | 69 ++++++++- 6 files changed, 415 insertions(+), 34 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 041dd0362a..2e6f9a3590 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -18,15 +18,17 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; import android.content.Context; +import android.os.Build; import android.os.Looper; +import android.os.SystemProperties; import android.telephony.Rlog; -import android.telephony.SubscriptionManager; import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import com.android.internal.annotations.VisibleForTesting; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; /** @@ -42,6 +44,9 @@ public class DatagramController { @NonNull private final DatagramReceiver mDatagramReceiver; public static final long MAX_DATAGRAM_ID = (long) Math.pow(2, 16); public static final int ROUNDING_UNIT = 10; + public static final long SATELLITE_ALIGN_TIMEOUT = TimeUnit.SECONDS.toMillis(30); + private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; + private static final boolean DEBUG = !"user".equals(Build.TYPE); /** Variables used to update onSendDatagramStateChanged(). */ private int mSendSubId; @@ -57,6 +62,7 @@ public class DatagramController { private int mReceiveErrorCode = SatelliteManager.SATELLITE_ERROR_NONE; private SatelliteDatagram mDemoModeDatagram; private boolean mIsDemoMode = false; + private long mAlignTimeoutDuration = SATELLITE_ALIGN_TIMEOUT; /** * @return The singleton instance of DatagramController. @@ -240,25 +246,18 @@ public class DatagramController { * @param state Current satellite modem state. */ public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { - if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF - || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { - logd("onSatelliteModemStateChanged: cleaning up resources"); - cleanUpResources(); - } mDatagramDispatcher.onSatelliteModemStateChanged(state); + mDatagramReceiver.onSatelliteModemStateChanged(state); } - private void cleanUpResources() { - if (mReceiveDatagramTransferState - == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING) { - updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, - mReceivePendingCount, - SatelliteManager.SATELLITE_REQUEST_ABORTED); - } - updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0, - SatelliteManager.SATELLITE_ERROR_NONE); + void onDeviceAlignedWithSatellite(boolean isAligned) { + mDatagramDispatcher.onDeviceAlignedWithSatellite(isAligned); + mDatagramReceiver.onDeviceAlignedWithSatellite(isAligned); + } + + boolean isReceivingDatagrams() { + return (mReceiveDatagramTransferState + == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); } /** @@ -294,6 +293,32 @@ public class DatagramController { } } + long getSatelliteAlignedTimeoutDuration() { + return mAlignTimeoutDuration; + } + + /** + * This API can be used by only CTS to update the timeout duration in milliseconds whether + * the device is aligned with the satellite for demo mode + * + * @param timeoutMillis The timeout duration in millisecond. + * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. + */ + boolean setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis) { + if (!isMockModemAllowed()) { + loge("Updating align timeout duration is not allowed"); + return false; + } + + logd("setSatelliteDeviceAlignedTimeoutDuration: timeoutMillis=" + timeoutMillis); + mAlignTimeoutDuration = timeoutMillis; + return true; + } + + private boolean isMockModemAllowed() { + return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)); + } + private void notifyDatagramTransferStateChangedToSessionController() { SatelliteSessionController sessionController = SatelliteSessionController.getInstance(); if (sessionController == null) { diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index 7c46fb81fd..63731e2aa3 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -50,6 +50,7 @@ public class DatagramDispatcher extends Handler { private static final int CMD_SEND_SATELLITE_DATAGRAM = 1; private static final int EVENT_SEND_SATELLITE_DATAGRAM_DONE = 2; + private static final int EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT = 3; @NonNull private static DatagramDispatcher sInstance; @NonNull private final Context mContext; @@ -57,6 +58,8 @@ public class DatagramDispatcher extends Handler { @NonNull private final ControllerMetricsStats mControllerMetricsStats; private boolean mIsDemoMode = false; + private boolean mIsAligned = false; + private DatagramDispatcherHandlerRequest mSendSatelliteDatagramRequest = null; private static AtomicLong mNextDatagramId = new AtomicLong(0); @@ -138,6 +141,7 @@ public class DatagramDispatcher extends Handler { public boolean needFullScreenPointingUI; public @NonNull Consumer callback; public long datagramStartTime; + public boolean skipCheckingSatelliteAligned = false; SendSatelliteDatagramArgument(int subId, long datagramId, @SatelliteManager.DatagramType int datagramType, @@ -233,11 +237,22 @@ public class DatagramDispatcher extends Handler { int error = SatelliteServiceUtils.getSatelliteError(ar, "sendSatelliteDatagram"); SendSatelliteDatagramArgument argument = (SendSatelliteDatagramArgument) request.argument; - logd("EVENT_SEND_SATELLITE_DATAGRAM_DONE error: " + error); - // log metrics about the outgoing datagram - reportSendDatagramCompleted(argument, error); synchronized (mLock) { + if (mIsDemoMode && (error == SatelliteManager.SATELLITE_ERROR_NONE)) { + if (argument.skipCheckingSatelliteAligned) { + logd("Satellite was already aligned. No need to check alignment again"); + } else if (!mIsAligned) { + logd("Satellite is not aligned in demo mode, wait for the alignment."); + startSatelliteAlignedTimer(request); + break; + } + } + + logd("EVENT_SEND_SATELLITE_DATAGRAM_DONE error: " + error); + // log metrics about the outgoing datagram + reportSendDatagramCompleted(argument, error); + mSendingDatagramInProgress = false; // Remove current datagram from pending map. @@ -288,6 +303,11 @@ public class DatagramDispatcher extends Handler { break; } + case EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT: { + handleEventSatelliteAlignedTimeout((DatagramDispatcherHandlerRequest) msg.obj); + break; + } + default: logw("DatagramDispatcherHandler: unexpected message code: " + msg.what); break; @@ -344,11 +364,74 @@ public class DatagramDispatcher extends Handler { * * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise. */ - @VisibleForTesting + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected void setDemoMode(boolean isDemoMode) { mIsDemoMode = isDemoMode; } + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected void onDeviceAlignedWithSatellite(boolean isAligned) { + if (mIsDemoMode) { + synchronized (mLock) { + mIsAligned = isAligned; + if (isAligned) handleEventSatelliteAligned(); + } + } + } + + private void startSatelliteAlignedTimer(@NonNull DatagramDispatcherHandlerRequest request) { + if (isSatelliteAlignedTimerStarted()) { + logd("Satellite aligned timer was already started"); + return; + } + mSendSatelliteDatagramRequest = request; + sendMessageDelayed( + obtainMessage(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT, request), + getSatelliteAlignedTimeoutDuration()); + } + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected long getSatelliteAlignedTimeoutDuration() { + return mDatagramController.getSatelliteAlignedTimeoutDuration(); + } + + private void handleEventSatelliteAligned() { + if (isSatelliteAlignedTimerStarted()) { + stopSatelliteAlignedTimer(); + + if (mSendSatelliteDatagramRequest == null) { + loge("handleEventSatelliteAligned: mSendSatelliteDatagramRequest is null"); + } else { + SendSatelliteDatagramArgument argument = + (SendSatelliteDatagramArgument) mSendSatelliteDatagramRequest.argument; + argument.skipCheckingSatelliteAligned = true; + Message message = obtainMessage( + EVENT_SEND_SATELLITE_DATAGRAM_DONE, mSendSatelliteDatagramRequest); + mSendSatelliteDatagramRequest = null; + AsyncResult.forMessage(message, null, null); + message.sendToTarget(); + } + } + } + + private void handleEventSatelliteAlignedTimeout( + @NonNull DatagramDispatcherHandlerRequest request) { + SatelliteManager.SatelliteException exception = + new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_NOT_REACHABLE); + Message message = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request); + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + } + + private boolean isSatelliteAlignedTimerStarted() { + return hasMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT); + } + + private void stopSatelliteAlignedTimer() { + removeMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT); + } + /** * Send pending satellite datagrams. Emergency datagrams are given priority over * non-emergency datagrams. @@ -480,7 +563,8 @@ public class DatagramDispatcher extends Handler { synchronized (mLock) { mSendingDatagramInProgress = false; if (getPendingDatagramCount() > 0) { - mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + mDatagramController.updateSendStatus( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, getPendingDatagramCount(), SatelliteManager.SATELLITE_REQUEST_ABORTED); } @@ -489,6 +573,11 @@ public class DatagramDispatcher extends Handler { 0, SatelliteManager.SATELLITE_ERROR_NONE); abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, SatelliteManager.SATELLITE_REQUEST_ABORTED); + + stopSatelliteAlignedTimer(); + mIsDemoMode = false; + mSendSatelliteDatagramRequest = null; + mIsAligned = false; } } diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index bc2904482a..1ae771c2e6 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -35,6 +35,7 @@ import android.os.Message; import android.os.RemoteException; import android.provider.Telephony; import android.telephony.Rlog; +import android.telephony.SubscriptionManager; import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; @@ -62,6 +63,7 @@ public class DatagramReceiver extends Handler { private static final int CMD_POLL_PENDING_SATELLITE_DATAGRAMS = 1; private static final int EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE = 2; + private static final int EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT = 3; /** Key used to read/write satellite datagramId in shared preferences. */ private static final String SATELLITE_DATAGRAM_ID_KEY = "satellite_datagram_id_key"; @@ -77,6 +79,9 @@ public class DatagramReceiver extends Handler { private long mDatagramTransferStartTime = 0; private boolean mIsDemoMode = false; + private boolean mIsAligned = false; + private DatagramReceiverHandlerRequest mPollPendingSatelliteDatagramsRequest = null; + private final Object mLock = new Object(); /** * Map key: subId, value: SatelliteDatagramListenerHandler to notify registrants. @@ -491,6 +496,11 @@ public class DatagramReceiver extends Handler { ((Consumer) request.argument).accept(error); break; } + + case EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT: { + handleEventSatelliteAlignedTimeout((DatagramReceiverHandlerRequest) msg.obj); + break; + } } } @@ -577,21 +587,73 @@ public class DatagramReceiver extends Handler { SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING, mDatagramController.getReceivePendingCount(), SatelliteManager.SATELLITE_ERROR_NONE); - mDatagramTransferStartTime = System.currentTimeMillis(); Phone phone = SatelliteServiceUtils.getPhone(); if (mIsDemoMode) { DatagramReceiverHandlerRequest request = new DatagramReceiverHandlerRequest( callback, phone, subId); - AsyncResult ar = new AsyncResult(request, SatelliteManager.SATELLITE_ERROR_NONE, null); - Message msg = this.obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, ar); - msg.sendToTarget(); + synchronized (mLock) { + if (mIsAligned) { + Message msg = obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, + request); + AsyncResult.forMessage(msg, null, null); + msg.sendToTarget(); + } else { + startSatelliteAlignedTimer(request); + } + } } else { sendRequestAsync(CMD_POLL_PENDING_SATELLITE_DATAGRAMS, callback, phone, subId); } } + /** + * This function is used by {@link DatagramController} to notify {@link DatagramReceiver} + * that satellite modem state has changed. + * + * @param state Current satellite modem state. + */ + public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { + if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF + || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { + logd("onSatelliteModemStateChanged: cleaning up resources"); + cleanUpResources(); + } + } + + private void cleanupDemoModeResources() { + if (isSatelliteAlignedTimerStarted()) { + stopSatelliteAlignedTimer(); + if (mPollPendingSatelliteDatagramsRequest == null) { + loge("Satellite aligned timer was started " + + "but mPollPendingSatelliteDatagramsRequest is null"); + } else { + Consumer callback = + (Consumer) mPollPendingSatelliteDatagramsRequest.argument; + callback.accept(SatelliteManager.SATELLITE_REQUEST_ABORTED); + } + } + mIsDemoMode = false; + mPollPendingSatelliteDatagramsRequest = null; + mIsAligned = false; + } + + private void cleanUpResources() { + synchronized (mLock) { + if (mDatagramController.isReceivingDatagrams()) { + mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, + mDatagramController.getReceivePendingCount(), + SatelliteManager.SATELLITE_REQUEST_ABORTED); + } + mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0, + SatelliteManager.SATELLITE_ERROR_NONE); + cleanupDemoModeResources(); + } + } + /** * Posts the specified command to be executed on the main thread and returns immediately. * @@ -637,11 +699,71 @@ public class DatagramReceiver extends Handler { * * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise. */ - @VisibleForTesting + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) protected void setDemoMode(boolean isDemoMode) { mIsDemoMode = isDemoMode; } + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected void onDeviceAlignedWithSatellite(boolean isAligned) { + if (mIsDemoMode) { + synchronized (mLock) { + mIsAligned = isAligned; + if (isAligned) handleEventSatelliteAligned(); + } + } + } + + private void startSatelliteAlignedTimer(DatagramReceiverHandlerRequest request) { + if (isSatelliteAlignedTimerStarted()) { + logd("Satellite aligned timer was already started"); + return; + } + mPollPendingSatelliteDatagramsRequest = request; + sendMessageDelayed( + obtainMessage(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT, request), + getSatelliteAlignedTimeoutDuration()); + } + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected long getSatelliteAlignedTimeoutDuration() { + return mDatagramController.getSatelliteAlignedTimeoutDuration(); + } + + private void handleEventSatelliteAligned() { + if (isSatelliteAlignedTimerStarted()) { + stopSatelliteAlignedTimer(); + + if (mPollPendingSatelliteDatagramsRequest == null) { + loge("handleSatelliteAlignedTimer: mPollPendingSatelliteDatagramsRequest is null"); + } else { + Message message = obtainMessage( + EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, + mPollPendingSatelliteDatagramsRequest); + mPollPendingSatelliteDatagramsRequest = null; + AsyncResult.forMessage(message, null, null); + message.sendToTarget(); + } + } + } + + private void handleEventSatelliteAlignedTimeout(DatagramReceiverHandlerRequest request) { + SatelliteManager.SatelliteException exception = + new SatelliteManager.SatelliteException( + SatelliteManager.SATELLITE_NOT_REACHABLE); + Message message = obtainMessage(EVENT_POLL_PENDING_SATELLITE_DATAGRAMS_DONE, request); + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + } + + private boolean isSatelliteAlignedTimerStarted() { + return hasMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT); + } + + private void stopSatelliteAlignedTimer() { + removeMessages(EVENT_WAIT_FOR_DEVICE_ALIGNMENT_IN_DEMO_MODE_TIMED_OUT); + } + /** * Destroys this DatagramDispatcher. Used for tearing down static resources during testing. */ diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index f5cdcb6c8d..efcfb28b5e 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -702,7 +702,7 @@ public class SatelliteController extends Handler { IIntegerConsumer errorCallback = new IIntegerConsumer.Stub() { @Override public void accept(int result) { - loge("Failed to Disable Satellite Mode, Error: " + result); + logd("RequestSatelliteEnabled: result=" + result); } }; Phone phone = SatelliteServiceUtils.getPhone(); @@ -1441,6 +1441,16 @@ public class SatelliteController extends Handler { sendRequestAsync(CMD_GET_TIME_SATELLITE_NEXT_VISIBLE, result, phone); } + /** + * Inform whether the device is aligned with satellite for demo mode. + * + * @param subId The subId of the subscription. + * @param isAligned {@true} means device is aligned with the satellite, otherwise {@false}. + */ + public void onDeviceAlignedWithSatellite(@NonNull int subId, @NonNull boolean isAligned) { + mDatagramController.onDeviceAlignedWithSatellite(isAligned); + } + /** * This API can be used by only CTS to update satellite vendor service package name. * @@ -1492,6 +1502,17 @@ public class SatelliteController extends Handler { return mSatelliteSessionController.setSatelliteListeningTimeoutDuration(timeoutMillis); } + /** + * This API can be used by only CTS to update the timeout duration in milliseconds whether + * the device is aligned with the satellite for demo mode + * + * @param timeoutMillis The timeout duration in millisecond. + * @return {@code true} if the timeout duration is set successfully, {@code false} otherwise. + */ + public boolean setSatelliteDeviceAlignedTimeoutDuration(long timeoutMillis) { + return mDatagramController.setSatelliteDeviceAlignedTimeoutDuration(timeoutMillis); + } + /** * This API can be used by only CTS to update satellite gateway service package name. * diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java index 332b3d9bc5..a86eb6466d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java @@ -16,10 +16,13 @@ package com.android.internal.telephony.satellite; +import static com.android.internal.telephony.satellite.DatagramController.SATELLITE_ALIGN_TIMEOUT; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -50,6 +53,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -59,6 +63,7 @@ public class DatagramDispatcherTest extends TelephonyTest { private static final int DATAGRAM_TYPE1 = SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE; private static final int DATAGRAM_TYPE2 = SatelliteManager.DATAGRAM_TYPE_LOCATION_SHARING; private static final String TEST_MESSAGE = "This is a test datagram message"; + private static final long TEST_EXPIRE_TIMER_SATELLITE_ALIGN = TimeUnit.SECONDS.toMillis(1); private DatagramDispatcher mDatagramDispatcherUT; private TestDatagramDispatcher mTestDemoModeDatagramDispatcher; @@ -285,8 +290,9 @@ public class DatagramDispatcherTest extends TelephonyTest { } @Test - public void testSendSatelliteDatagram_DemoMode_data_type_sos_message() throws Exception { + public void testSendSatelliteDatagram_DemoMode_Align_Success() throws Exception { mTestDemoModeDatagramDispatcher.setDemoMode(true); + mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(true); doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); doAnswer(invocation -> { @@ -318,6 +324,48 @@ public class DatagramDispatcherTest extends TelephonyTest { eq(SatelliteManager.SATELLITE_ERROR_NONE)); assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_ERROR_NONE); mTestDemoModeDatagramDispatcher.setDemoMode(false); + mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(false); + } + + @Test + public void testSendSatelliteDatagram_DemoMode_Align_failed() throws Exception { + long previousTimer = mTestDemoModeDatagramDispatcher.getSatelliteAlignedTimeoutDuration(); + mTestDemoModeDatagramDispatcher.setDemoMode(true); + mTestDemoModeDatagramDispatcher.setDuration(TEST_EXPIRE_TIMER_SATELLITE_ALIGN); + mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(false); + + doReturn(false).when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone}); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + + mTestDemoModeDatagramDispatcher.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/, + new AsyncResult(message.obj, null, null)) + .sendToTarget(); + return null; + }).when(mPhone).sendSatelliteDatagram(any(Message.class), any(SatelliteDatagram.class), + anyBoolean()); + + mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + true, mResultListener::offer); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + processAllFutureMessages(); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), + anyInt(), eq(SatelliteManager.SATELLITE_NOT_REACHABLE)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), eq(0), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_NOT_REACHABLE); + mTestDemoModeDatagramDispatcher.setDemoMode(false); + mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(false); + mTestDemoModeDatagramDispatcher.setDuration(previousTimer); } @Test @@ -358,9 +406,12 @@ public class DatagramDispatcherTest extends TelephonyTest { eq(SatelliteManager.SATELLITE_ERROR_NONE)); mTestDemoModeDatagramDispatcher.setDemoMode(false); + mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(false); } private static class TestDatagramDispatcher extends DatagramDispatcher { + private long mLong = SATELLITE_ALIGN_TIMEOUT; + TestDatagramDispatcher(@NonNull Context context, @NonNull Looper looper, @NonNull DatagramController datagramController) { super(context, looper, datagramController); @@ -370,5 +421,19 @@ public class DatagramDispatcherTest extends TelephonyTest { protected void setDemoMode(boolean isDemoMode) { super.setDemoMode(isDemoMode); } + + @Override + protected void onDeviceAlignedWithSatellite(boolean isAligned) { + super.onDeviceAlignedWithSatellite(isAligned); + } + + @Override + protected long getSatelliteAlignedTimeoutDuration() { + return mLong; + } + + public void setDuration(long duration) { + mLong = duration; + } } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java index 1be8e03b9f..f6239c4c87 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java @@ -16,6 +16,8 @@ package com.android.internal.telephony.satellite; +import static com.android.internal.telephony.satellite.DatagramController.SATELLITE_ALIGN_TIMEOUT; + import android.annotation.NonNull; import android.content.Context; import android.provider.Telephony; @@ -31,6 +33,7 @@ import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -57,6 +60,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -64,9 +68,11 @@ public class DatagramReceiverTest extends TelephonyTest { private static final String TAG = "DatagramReceiverTest"; private static final int SUB_ID = 0; private static final String TEST_MESSAGE = "This is a test datagram message"; + private static final long TEST_EXPIRE_TIMER_SATELLITE_ALIGN = TimeUnit.SECONDS.toMillis(1); private DatagramReceiver mDatagramReceiverUT; private DatagramReceiver.SatelliteDatagramListenerHandler mSatelliteDatagramListenerHandler; + private TestDatagramReceiver mTestDemoModeDatagramReceiver; @Mock private DatagramController mMockDatagramController; @Mock private SatelliteModemInterface mMockSatelliteModemInterface; @@ -101,6 +107,8 @@ public class DatagramReceiverTest extends TelephonyTest { mDatagramReceiverUT = DatagramReceiver.make(mContext, Looper.myLooper(), mMockDatagramController); + mTestDemoModeDatagramReceiver = new TestDatagramReceiver(mContext, Looper.myLooper(), + mMockDatagramController); mSatelliteDatagramListenerHandler = new DatagramReceiver.SatelliteDatagramListenerHandler( Looper.myLooper(), SUB_ID); @@ -117,6 +125,7 @@ public class DatagramReceiverTest extends TelephonyTest { mFakeSatelliteProvider.shutdown(); mDatagramReceiverUT.destroy(); mDatagramReceiverUT = null; + mTestDemoModeDatagramReceiver = null; mResultListener = null; mDatagram = null; mInOrder = null; @@ -315,13 +324,12 @@ public class DatagramReceiverTest extends TelephonyTest { } @Test - public void testPollPendingSatelliteDatagrams_DemoMode() throws Exception { + public void testPollPendingSatelliteDatagrams_DemoMode_Align_succeed() throws Exception { // Checks invalid case only as SatelliteController does not exist in unit test - TestDatagramReceiver testDatagramReceiver = new TestDatagramReceiver( - mContext, Looper.myLooper(), mMockDatagramController); - testDatagramReceiver.setDemoMode(true); + mTestDemoModeDatagramReceiver.setDemoMode(true); + mTestDemoModeDatagramReceiver.onDeviceAlignedWithSatellite(true); when(mMockDatagramController.getDemoModeDatagram()).thenReturn(mDatagram); - testDatagramReceiver.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); + mTestDemoModeDatagramReceiver.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); processAllMessages(); verify(mMockDatagramController, times(1)).getDemoModeDatagram(); verify(mMockDatagramController) @@ -343,7 +351,44 @@ public class DatagramReceiverTest extends TelephonyTest { .isEqualTo(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); } + @Test + public void testPollPendingSatelliteDatagrams_DemoMode_Align_failed() throws Exception { + // Checks invalid case only as SatelliteController does not exist in unit test + long previousTimer = mTestDemoModeDatagramReceiver.getSatelliteAlignedTimeoutDuration(); + mTestDemoModeDatagramReceiver.setDemoMode(true); + mTestDemoModeDatagramReceiver.setDuration(TEST_EXPIRE_TIMER_SATELLITE_ALIGN); + mTestDemoModeDatagramReceiver.onDeviceAlignedWithSatellite(false); + when(mMockDatagramController.getDemoModeDatagram()).thenReturn(mDatagram); + mTestDemoModeDatagramReceiver.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); + processAllMessages(); + verify(mMockDatagramController, never()).getDemoModeDatagram(); + verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING), + anyInt(), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + processAllFutureMessages(); + verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), + anyInt(), + eq(SatelliteManager.SATELLITE_NOT_REACHABLE)); + verify(mMockDatagramController) + .updateReceiveStatus(eq(SUB_ID), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), + anyInt(), + eq(SatelliteManager.SATELLITE_ERROR_NONE)); + assertThat(mResultListener.peek()) + .isEqualTo(SatelliteManager.SATELLITE_NOT_REACHABLE); + + mTestDemoModeDatagramReceiver.setDemoMode(false); + mTestDemoModeDatagramReceiver.onDeviceAlignedWithSatellite(false); + mTestDemoModeDatagramReceiver.setDuration(previousTimer); + } + private static class TestDatagramReceiver extends DatagramReceiver { + private long mLong = SATELLITE_ALIGN_TIMEOUT; + TestDatagramReceiver(@NonNull Context context, @NonNull Looper looper, @NonNull DatagramController datagramController) { super(context, looper, datagramController); @@ -353,5 +398,19 @@ public class DatagramReceiverTest extends TelephonyTest { protected void setDemoMode(boolean isDemoMode) { super.setDemoMode(isDemoMode); } + + @Override + protected void onDeviceAlignedWithSatellite(boolean isAligned) { + super.onDeviceAlignedWithSatellite(isAligned); + } + + @Override + protected long getSatelliteAlignedTimeoutDuration() { + return mLong; + } + + public void setDuration(long duration) { + mLong = duration; + } } } -- GitLab From 2294e0d5d215b9109cd6b9ee8c33350c1890d76a Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Sun, 30 Apr 2023 18:06:22 -0700 Subject: [PATCH 630/656] Create APIs to check satelite controller enabled and demo mode on Create nonblocking API calls to check whether satellite is enabled and whether satellite demo mode is enabled. Test: manual, CTS, unit tests, verify voice call on live network Bug: 278578254 Change-Id: I5c1f6e7f89bfe5acdb3e0f91c077cbebd227ed1d --- .../satellite/SatelliteController.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index c599659958..975ee83e25 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -886,6 +886,17 @@ public class SatelliteController extends Handler { sendRequestAsync(CMD_IS_SATELLITE_ENABLED, result, SatelliteServiceUtils.getPhone()); } + /** + * Get whether the satellite modem is enabled. + * This will return the cached value instead of querying the satellite modem. + * + * @return {@code true} if the satellite modem is enabled and {@code false} otherwise. + */ + public boolean isSatelliteEnabled() { + if (mIsSatelliteEnabled == null) return false; + return mIsSatelliteEnabled; + } + /** * Request to get whether the satellite service demo mode is enabled. * @@ -920,6 +931,15 @@ public class SatelliteController extends Handler { result.send(SatelliteManager.SATELLITE_ERROR_NONE, bundle); } + /** + * Get whether the satellite service demo mode is enabled. + * + * @return {@code true} if the satellite demo mode is enabled and {@code false} otherwise. + */ + public boolean isDemoModeEnabled() { + return mIsDemoModeEnabled; + } + /** * Request to get whether the satellite service is supported on the device. * -- GitLab From 54ca761763471b9dec88d214bba4c8b7ee5f2206 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 27 Apr 2023 03:45:05 -0700 Subject: [PATCH 631/656] Add satellite modem state logic for calls For emergency calls, turn off the satellite modem and retry. For normal calls, return an error. Test: unit tests, CTS Test: manual verify normal call and fake emergency call Bug: 278578254 Change-Id: I24fc69e18e06f6ad9e64052936f45b909f1990a5 --- .../telephony/emergency/RadioOnHelper.java | 35 ++++++-- .../emergency/RadioOnStateListener.java | 80 +++++++++++++++-- .../internal/telephony/TelephonyTest.java | 4 + .../emergency/RadioOnStateListenerTest.java | 90 +++++++++++++++---- 4 files changed, 178 insertions(+), 31 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java b/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java index 43a53c3666..9c4ebfabe3 100644 --- a/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java +++ b/src/java/com/android/internal/telephony/emergency/RadioOnHelper.java @@ -22,8 +22,10 @@ import android.os.UserHandle; import android.provider.Settings; import android.telephony.TelephonyManager; +import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.satellite.SatelliteController; import com.android.telephony.Rlog; import java.util.ArrayList; @@ -44,7 +46,7 @@ public class RadioOnHelper implements RadioOnStateListener.Callback { private RadioOnStateListener.Callback mCallback; private List mListeners; private List mInProgressListeners; - private boolean mIsRadioOnCallingEnabled; + private boolean mIsRadioReady; public RadioOnHelper(Context context) { mContext = context; @@ -72,9 +74,9 @@ public class RadioOnHelper implements RadioOnStateListener.Callback { * class. * * This method kicks off the following sequence: - * - Power on the radio for each Phone - * - Listen for radio events telling us the radio has come up. - * - Retry if we've gone a significant amount of time without any response from the radio. + * - Power on the radio for each Phone and disable the satellite modem + * - Listen for events telling us the radio has come up or the satellite modem is disabled. + * - Retry if we've gone a significant amount of time without any response. * - Finally, clean up any leftover state. * * This method is safe to call from any thread, since it simply posts a message to the @@ -87,7 +89,7 @@ public class RadioOnHelper implements RadioOnStateListener.Callback { setupListeners(); mCallback = callback; mInProgressListeners.clear(); - mIsRadioOnCallingEnabled = false; + mIsRadioReady = false; for (int i = 0; i < TelephonyManager.from(mContext).getActiveModemCount(); i++) { Phone phone = PhoneFactory.getPhone(i); if (phone == null) { @@ -101,6 +103,9 @@ public class RadioOnHelper implements RadioOnStateListener.Callback { && phone == phoneForEmergencyCall, timeoutCallbackInterval); } powerOnRadio(forEmergencyCall, phoneForEmergencyCall, isTestEmergencyNumber); + if (SatelliteController.getInstance().isSatelliteEnabled()) { + powerOffSatellite(phoneForEmergencyCall); + } } /** @@ -141,16 +146,32 @@ public class RadioOnHelper implements RadioOnStateListener.Callback { } } + /** + * Attempt to power off the satellite modem. We'll eventually get an + * onSatelliteModemStateChanged() callback when the satellite modem is successfully disabled. + */ + private void powerOffSatellite(Phone phoneForEmergencyCall) { + SatelliteController satelliteController = SatelliteController.getInstance(); + satelliteController.requestSatelliteEnabled(phoneForEmergencyCall.getSubId(), + false /* enableSatellite */, false /* enableDemoMode */, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + + } + }); + } + /** * This method is called from multiple Listeners on the Main Looper. Synchronization is not * necessary. */ @Override public void onComplete(RadioOnStateListener listener, boolean isRadioReady) { - mIsRadioOnCallingEnabled |= isRadioReady; + mIsRadioReady |= isRadioReady; mInProgressListeners.remove(listener); if (mCallback != null && mInProgressListeners.isEmpty()) { - mCallback.onComplete(null, mIsRadioOnCallingEnabled); + mCallback.onComplete(null, mIsRadioReady); } } diff --git a/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java b/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java index 2262346e50..d61c146fbe 100644 --- a/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java +++ b/src/java/com/android/internal/telephony/emergency/RadioOnStateListener.java @@ -21,10 +21,14 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.satellite.ISatelliteStateCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; +import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.satellite.SatelliteController; import com.android.telephony.Rlog; import java.util.Locale; @@ -37,7 +41,8 @@ public class RadioOnStateListener { public interface Callback { /** - * Receives the result of the RadioOnStateListener's attempt to turn on the radio. + * Receives the result of the RadioOnStateListener's attempt to turn on the radio + * and turn off the satellite modem. */ void onComplete(RadioOnStateListener listener, boolean isRadioReady); @@ -86,6 +91,8 @@ public class RadioOnStateListener { public static final int MSG_RADIO_OFF_OR_NOT_AVAILABLE = 5; public static final int MSG_IMS_CAPABILITY_CHANGED = 6; public static final int MSG_TIMEOUT_ONTIMEOUT_CALLBACK = 7; + @VisibleForTesting + public static final int MSG_SATELLITE_ENABLED_CHANGED = 8; private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override @@ -123,6 +130,10 @@ public class RadioOnStateListener { break; case MSG_TIMEOUT_ONTIMEOUT_CALLBACK: onTimeoutCallbackTimeout(); + break; + case MSG_SATELLITE_ENABLED_CHANGED: + onSatelliteEnabledChanged(); + break; default: Rlog.w(TAG, String.format(Locale.getDefault(), "handleMessage: unexpected message: %d.", msg.what)); @@ -131,8 +142,17 @@ public class RadioOnStateListener { } }; + private final ISatelliteStateCallback mSatelliteCallback = new ISatelliteStateCallback.Stub() { + @Override + public void onSatelliteModemStateChanged(int state) { + mHandler.obtainMessage(MSG_SATELLITE_ENABLED_CHANGED).sendToTarget(); + } + }; + private Callback mCallback; // The callback to notify upon completion. private Phone mPhone; // The phone that will attempt to place the call. + // SatelliteController instance to check whether satellite has been disabled. + private SatelliteController mSatelliteController; private boolean mForEmergencyCall; // Whether radio is being turned on for emergency call. // Whether this phone is selected to place emergency call. Can be true only if // mForEmergencyCall is true. @@ -146,6 +166,7 @@ public class RadioOnStateListener { * * This method kicks off the following sequence: * - Listen for the service state change event telling us the radio has come up. + * - Listen for the satellite state changed event telling us the satellite service is disabled. * - Retry if we've gone {@link #TIME_BETWEEN_RETRIES_MILLIS} without any response from the * radio. * - Finally, clean up any leftover state. @@ -156,7 +177,7 @@ public class RadioOnStateListener { */ public void waitForRadioOn(Phone phone, Callback callback, boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, - int onTimeoutCallbackInverval) { + int onTimeoutCallbackInterval) { Rlog.d(TAG, "waitForRadioOn: Phone " + phone.getPhoneId()); if (mPhone != null) { @@ -169,7 +190,7 @@ public class RadioOnStateListener { args.arg2 = callback; args.arg3 = forEmergencyCall; args.arg4 = isSelectedPhoneForEmergencyCall; - args.argi1 = onTimeoutCallbackInverval; + args.argi1 = onTimeoutCallbackInterval; mHandler.obtainMessage(MSG_START_SEQUENCE, args).sendToTarget(); } @@ -182,6 +203,7 @@ public class RadioOnStateListener { boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, int onTimeoutCallbackInterval) { Rlog.d(TAG, "startSequenceInternal: Phone " + phone.getPhoneId()); + mSatelliteController = SatelliteController.getInstance(); // First of all, clean up any state left over from a prior RadioOn call sequence. This // ensures that we'll behave sanely if another startTurnOnRadioSequence() comes in while @@ -198,9 +220,14 @@ public class RadioOnStateListener { // Register for RADIO_OFF to handle cases where emergency call is dialed before // we receive UNSOL_RESPONSE_RADIO_STATE_CHANGED with RADIO_OFF. registerForRadioOff(); - // Next step: when the SERVICE_STATE_CHANGED event comes in, we'll retry the call; see - // onServiceStateChanged(). But also, just in case, start a timer to make sure we'll retry - // the call even if the SERVICE_STATE_CHANGED event never comes in for some reason. + if (mSatelliteController.isSatelliteEnabled()) { + // Register for satellite modem state changed to notify when satellite is disabled. + registerForSatelliteEnabledChanged(); + } + // Next step: when the SERVICE_STATE_CHANGED or SATELLITE_ENABLED_CHANGED event comes in, + // we'll retry the call; see onServiceStateChanged() and onSatelliteEnabledChanged(). + // But also, just in case, start a timer to make sure we'll retry the call even if the + // SERVICE_STATE_CHANGED or SATELLITE_ENABLED_CHANGED events never come in for some reason. startRetryTimer(); registerForImsCapabilityChanged(); startOnTimeoutCallbackTimer(); @@ -292,6 +319,19 @@ public class RadioOnStateListener { } } + private void onSatelliteEnabledChanged() { + if (mPhone == null) { + return; + } + if (isOkToCall(mPhone.getServiceState().getState(), + mPhone.isVoiceOverCellularImsEnabled())) { + onComplete(true); + cleanup(); + } else { + Rlog.d(TAG, "onSatelliteEnabledChanged: not ready to call yet, keep waiting."); + } + } + /** * Callback to see if it is okay to call yet, given the current conditions. */ @@ -348,9 +388,20 @@ public class RadioOnStateListener { Rlog.w(TAG, "Hit MAX_NUM_RETRIES; giving up."); cleanup(); } else { - Rlog.d(TAG, "Trying (again) to turn on the radio."); + Rlog.d(TAG, "Trying (again) to turn the radio on and satellite modem off."); mPhone.setRadioPower(true, mForEmergencyCall, mSelectedPhoneForEmergencyCall, false); + if (mSatelliteController.isSatelliteEnabled()) { + mSatelliteController.requestSatelliteEnabled(mPhone.getSubId(), + false /* enableSatellite */, false /* enableDemoMode */, + new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + mHandler.obtainMessage(MSG_SATELLITE_ENABLED_CHANGED) + .sendToTarget(); + } + }); + } startRetryTimer(); } } @@ -383,6 +434,7 @@ public class RadioOnStateListener { unregisterForServiceStateChanged(); unregisterForRadioOff(); unregisterForRadioOn(); + unregisterForSatelliteEnabledChanged(); cancelRetryTimer(); unregisterForImsCapabilityChanged(); @@ -442,6 +494,20 @@ public class RadioOnStateListener { mHandler.removeMessages(MSG_RADIO_ON); // Clean up any pending messages too } + private void registerForSatelliteEnabledChanged() { + mSatelliteController.registerForSatelliteModemStateChanged( + mPhone.getSubId(), mSatelliteCallback); + } + + private void unregisterForSatelliteEnabledChanged() { + int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + if (mPhone != null) { + subId = mPhone.getSubId(); + } + mSatelliteController.unregisterForSatelliteModemStateChanged(subId, mSatelliteCallback); + mHandler.removeMessages(MSG_SATELLITE_ENABLED_CHANGED); + } + private void registerForImsCapabilityChanged() { unregisterForImsCapabilityChanged(); mPhone.getServiceStateTracker() diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 5f675127bd..2f56f2ad90 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -115,6 +115,7 @@ import com.android.internal.telephony.metrics.PersistAtomsStorage; import com.android.internal.telephony.metrics.ServiceStateStats; import com.android.internal.telephony.metrics.SmsStats; import com.android.internal.telephony.metrics.VoiceCallSessionStats; +import com.android.internal.telephony.satellite.SatelliteController; import com.android.internal.telephony.subscription.SubscriptionManagerService; import com.android.internal.telephony.test.SimulatedCommands; import com.android.internal.telephony.test.SimulatedCommandsVerifier; @@ -267,6 +268,7 @@ public abstract class TelephonyTest { protected DataServiceManager mMockedWwanDataServiceManager; protected DataServiceManager mMockedWlanDataServiceManager; protected ServiceStateStats mServiceStateStats; + protected SatelliteController mSatelliteController; // Initialized classes protected ActivityManager mActivityManager; @@ -501,6 +503,7 @@ public abstract class TelephonyTest { mMockedWwanDataServiceManager = Mockito.mock(DataServiceManager.class); mMockedWlanDataServiceManager = Mockito.mock(DataServiceManager.class); mServiceStateStats = Mockito.mock(ServiceStateStats.class); + mSatelliteController = Mockito.mock(SatelliteController.class); TelephonyManager.disableServiceHandleCaching(); PropertyInvalidatedCache.disableForTestMode(); @@ -862,6 +865,7 @@ public abstract class TelephonyTest { replaceInstance(PhoneFactory.class, "sCommandsInterfaces", null, new CommandsInterface[] {mSimulatedCommands}); replaceInstance(PhoneFactory.class, "sMetricsCollector", null, mMetricsCollector); + replaceInstance(SatelliteController.class, "sInstance", null, mSatelliteController); setReady(false); // create default TestableLooper for test and add to list of monitored loopers diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java index 45263e4308..2c5a873f5a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/RadioOnStateListenerTest.java @@ -66,6 +66,7 @@ public class RadioOnStateListenerTest extends TelephonyTest { MockitoAnnotations.initMocks(this); mListener = new RadioOnStateListener(); doReturn(mSST).when(mMockPhone).getServiceStateTracker(); + mMockPhone.mCi = mMockCi; } @After @@ -84,22 +85,38 @@ public class RadioOnStateListenerTest extends TelephonyTest { */ @Test public void testRegisterForCallback() { - mMockPhone.mCi = mMockCi; mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0); waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); verify(mMockPhone).unregisterForServiceStateChanged(any(Handler.class)); + verify(mSatelliteController).unregisterForSatelliteModemStateChanged(anyInt(), any()); verify(mMockPhone).registerForServiceStateChanged(any(Handler.class), eq(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED), isNull()); + verify(mSatelliteController, never()).registerForSatelliteModemStateChanged( + anyInt(), any()); verify(mMockCi).registerForOffOrNotAvailable(any(Handler.class), eq(RadioOnStateListener.MSG_RADIO_OFF_OR_NOT_AVAILABLE), isNull()); } /** - * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returns true, - * so we are expecting + * Ensure that we successfully register for the satellite modem state changed messages. + */ + @Test + public void testRegisterForSatelliteCallback() { + doReturn(true).when(mSatelliteController).isSatelliteEnabled(); + mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0); + + waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); + + verify(mSatelliteController).unregisterForSatelliteModemStateChanged(anyInt(), any()); + verify(mSatelliteController).registerForSatelliteModemStateChanged(anyInt(), any()); + } + + /** + * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returns true after + * service state changes, so we are expecting * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to * return true. */ @@ -109,9 +126,7 @@ public class RadioOnStateListenerTest extends TelephonyTest { state.setState(ServiceState.STATE_IN_SERVICE); when(mMockPhone.getServiceState()).thenReturn(state); when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); - when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())) - .thenReturn(true); - mMockPhone.mCi = mMockCi; + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(true); mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0); waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); @@ -122,6 +137,29 @@ public class RadioOnStateListenerTest extends TelephonyTest { verify(mCallback).onComplete(eq(mListener), eq(true)); } + /** + * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returns true after + * satellite modem state changes, so we are expecting + * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to + * return true. + */ + @Test + public void testSatelliteChangeState_OkToCallTrue() { + ServiceState state = new ServiceState(); + state.setState(ServiceState.STATE_IN_SERVICE); + when(mMockPhone.getServiceState()).thenReturn(state); + when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(true); + mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0); + waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); + + mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SATELLITE_ENABLED_CHANGED) + .sendToTarget(); + + waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); + verify(mCallback).onComplete(eq(mListener), eq(true)); + } + /** * We never receive a * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} because @@ -132,10 +170,8 @@ public class RadioOnStateListenerTest extends TelephonyTest { ServiceState state = new ServiceState(); state.setState(ServiceState.STATE_OUT_OF_SERVICE); when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); - when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())) - .thenReturn(false); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(false); when(mMockPhone.getServiceState()).thenReturn(state); - mMockPhone.mCi = mMockCi; mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0); waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS); @@ -158,18 +194,18 @@ public class RadioOnStateListenerTest extends TelephonyTest { state.setState(ServiceState.STATE_POWER_OFF); when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); when(mMockPhone.getServiceState()).thenReturn(state); - when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())) - .thenReturn(false); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(false); mListener.setTimeBetweenRetriesMillis(0/* ms */); mListener.setMaxNumRetries(2); // Wait for the timer to expire and check state manually in onRetryTimeout - mMockPhone.mCi = mMockCi; mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0); waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS); verify(mCallback).onComplete(eq(mListener), eq(false)); verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(false), eq(false), eq(false)); + verify(mSatelliteController, never()).requestSatelliteEnabled( + anyInt(), eq(false), eq(false), any()); } @Test @@ -178,18 +214,39 @@ public class RadioOnStateListenerTest extends TelephonyTest { state.setState(ServiceState.STATE_POWER_OFF); when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); when(mMockPhone.getServiceState()).thenReturn(state); - when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())) - .thenReturn(false); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(false); mListener.setTimeBetweenRetriesMillis(0/* ms */); mListener.setMaxNumRetries(2); // Wait for the timer to expire and check state manually in onRetryTimeout - mMockPhone.mCi = mMockCi; mListener.waitForRadioOn(mMockPhone, mCallback, true, true, 0); - waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS ); + waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS); verify(mCallback).onComplete(eq(mListener), eq(false)); verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(true), eq(true), eq(false)); + verify(mSatelliteController, never()).requestSatelliteEnabled( + anyInt(), eq(false), eq(false), any()); + } + + @Test + public void testTimeout_RetryFailure_WithSatellite() { + doReturn(true).when(mSatelliteController).isSatelliteEnabled(); + ServiceState state = new ServiceState(); + state.setState(ServiceState.STATE_POWER_OFF); + when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE); + when(mMockPhone.getServiceState()).thenReturn(state); + when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(false); + mListener.setTimeBetweenRetriesMillis(0/* ms */); + mListener.setMaxNumRetries(2); + + // Wait for the timer to expire and check state manually in onRetryTimeout + mListener.waitForRadioOn(mMockPhone, mCallback, true, true, 0); + waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS); + + verify(mCallback).onComplete(eq(mListener), eq(false)); + verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(true), eq(true), eq(false)); + verify(mSatelliteController, times(2)).requestSatelliteEnabled( + anyInt(), eq(false), eq(false), any()); } @Test @@ -206,7 +263,6 @@ public class RadioOnStateListenerTest extends TelephonyTest { mListener.setMaxNumRetries(1); // Wait for the timer to expire and check state manually in onRetryTimeout - mMockPhone.mCi = mMockCi; mListener.waitForRadioOn(mMockPhone, mCallback, true, true, 100); waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS); -- GitLab From 434b61cdb1eb5a084a7c8957f48560b961d4bc46 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Fri, 21 Apr 2023 17:25:09 -0700 Subject: [PATCH 632/656] Migrate set network selection auto from legacy subscription In the legacy subscription flow, upon SIM loaded, if the slot mapping changed, a set network selection auto mode request will be sent to modem. Migrate that logic to the existing flow. Fix: 278517596 Test: voice call + internet browsing + reporter verified fix Change-Id: If54767be505aaaa7c11c33ddb96feaa42cb8ef99 --- .../internal/telephony/GsmCdmaPhone.java | 35 +++++++++++++++++++ .../com/android/internal/telephony/Phone.java | 5 +-- .../telephony/uicc/UiccController.java | 2 +- .../internal/telephony/GsmCdmaPhoneTest.java | 19 ++++++++++ .../internal/telephony/SimulatedCommands.java | 14 ++++++-- 5 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 2c2b6e632a..9f88557dac 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -172,6 +172,8 @@ public class GsmCdmaPhone extends Phone { // Key used to read/write the SIM IMSI used for storing the voice mail private static final String VM_SIM_IMSI = "vm_sim_imsi_key"; /** List of Registrants to receive Supplementary Service Notifications. */ + // Key used to read/write the current sub Id. Updated on SIM loaded. + public static final String CURR_SUBID = "curr_subid"; private RegistrantList mSsnRegistrants = new RegistrantList(); //CDMA @@ -420,6 +422,17 @@ public class GsmCdmaPhone extends Phone { int newPreferredTtyMode = intent.getIntExtra( TelecomManager.EXTRA_TTY_PREFERRED_MODE, TelecomManager.TTY_MODE_OFF); updateUiTtyMode(newPreferredTtyMode); + } else if (TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED.equals(action)) { + if (mPhoneId == intent.getIntExtra( + SubscriptionManager.EXTRA_SLOT_INDEX, + SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { + int simState = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE, + TelephonyManager.SIM_STATE_UNKNOWN); + if (simState == TelephonyManager.SIM_STATE_LOADED + && currentSlotSubIdChanged()) { + setNetworkSelectionModeAutomatic(null); + } + } } } }; @@ -482,6 +495,7 @@ public class GsmCdmaPhone extends Phone { CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED); filter.addAction(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED); + filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); mContext.registerReceiver(mBroadcastReceiver, filter, android.Manifest.permission.MODIFY_PHONE_STATE, null, Context.RECEIVER_EXPORTED); @@ -3541,6 +3555,27 @@ public class GsmCdmaPhone extends Phone { } } + /** + * Check if a different SIM is inserted at this slot from the last time. Storing last subId + * in SharedPreference for now to detect SIM change. + * + * @return {@code true} if current slot mapping changed; {@code false} otherwise. + */ + private boolean currentSlotSubIdChanged() { + SharedPreferences sp = + PreferenceManager.getDefaultSharedPreferences(mContext); + int storedSubId = sp.getInt(CURR_SUBID + mPhoneId, -1); + boolean changed = storedSubId != getSubId(); + if (changed) { + // Update stored subId + SharedPreferences.Editor editor = sp.edit(); + editor.putInt(CURR_SUBID + mPhoneId, getSubId()); + editor.apply(); + } + Rlog.d(LOG_TAG, "currentSlotSubIdChanged: changed=" + changed); + return changed; + } + public UiccCardApplication getUiccCardApplication() { if (isPhoneTypeGsm()) { return mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_3GPP); diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 599f2b281a..4e62d20eb2 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -1437,8 +1437,8 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { @UnsupportedAppUsage public void setNetworkSelectionModeAutomatic(Message response) { Rlog.d(LOG_TAG, "setNetworkSelectionModeAutomatic, querying current mode"); - // we don't want to do this unecesarily - it acutally causes - // the radio to repeate network selection and is costly + // we don't want to do this unnecessarily - it actually causes + // the radio to repeat network selection and is costly // first check if we're already in automatic mode Message msg = obtainMessage(EVENT_CHECK_FOR_NETWORK_AUTOMATIC); msg.obj = response; @@ -1471,6 +1471,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { nsm.operatorAlphaShort = ""; if (doAutomatic) { + Rlog.d(LOG_TAG, "setNetworkSelectionModeAutomatic - set network selection auto"); Message msg = obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm); mCi.setNetworkSelectionModeAutomatic(msg); } else { diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java index b0232670af..566bec24c4 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccController.java +++ b/src/java/com/android/internal/telephony/uicc/UiccController.java @@ -957,7 +957,7 @@ public class UiccController extends Handler { log("updateSimState: phoneId=" + phoneId + ", state=" + state + ", reason=" + reason); if (!SubscriptionManager.isValidPhoneId(phoneId)) { - Rlog.e(LOG_TAG, "updateInternalIccState: Invalid phone id " + phoneId); + Rlog.e(LOG_TAG, "updateSimState: Invalid phone id " + phoneId); return; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java index d970799d3a..c5f20e39a4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java @@ -2556,4 +2556,23 @@ public class GsmCdmaPhoneTest extends TelephonyTest { .getSubscriptionUserHandle(anyInt()); assertNull(mPhoneUT.getUserHandle()); } + + @Test + public void testResetNetworkSelectionModeOnSimSwap() { + // Set current network selection manual mode. + mSimulatedCommands.setNetworkSelectionModeManual("123", 0, null); + clearInvocations(mSimulatedCommandsVerifier); + + // SIM loaded. + Intent simLoadedIntent = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); + simLoadedIntent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, mPhone.getPhoneId()); + simLoadedIntent.putExtra(TelephonyManager.EXTRA_SIM_STATE, + TelephonyManager.SIM_STATE_LOADED); + mContext.sendBroadcast(simLoadedIntent); + + processAllFutureMessages(); + // Verify set network selection mode to be AUTO + verify(mSimulatedCommandsVerifier).getNetworkSelectionMode(any(Message.class)); + verify(mSimulatedCommandsVerifier).setNetworkSelectionModeAutomatic(any(Message.class)); + } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java index 2f51ec9ba0..1e4c9392ae 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java +++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java @@ -1500,12 +1500,17 @@ public class SimulatedCommands extends BaseCommands } @Override - public void setNetworkSelectionModeAutomatic(Message result) {unimplemented(result);} + public void setNetworkSelectionModeAutomatic(Message result) { + SimulatedCommandsVerifier.getInstance().setNetworkSelectionModeAutomatic(result); + mMockNetworkSelectionMode = 0; + } @Override public void exitEmergencyCallbackMode(Message result) {unimplemented(result);} @Override public void setNetworkSelectionModeManual(String operatorNumeric, int ran, Message result) { - unimplemented(result); + SimulatedCommandsVerifier.getInstance().setNetworkSelectionModeManual( + operatorNumeric, ran, result); + mMockNetworkSelectionMode = 1; } /** @@ -1522,10 +1527,13 @@ public class SimulatedCommands extends BaseCommands getNetworkSelectionModeCallCount.incrementAndGet(); int ret[] = new int[1]; - ret[0] = 0; + ret[0] = mMockNetworkSelectionMode; resultSuccess(result, ret); } + /** 0 for automatic selection and a 1 for manual selection. */ + private int mMockNetworkSelectionMode = 0; + private final AtomicInteger getNetworkSelectionModeCallCount = new AtomicInteger(0); @VisibleForTesting -- GitLab From 330ba257e812dbd613ec5dc64bb032facfdec571 Mon Sep 17 00:00:00 2001 From: Muralidhar Reddy Date: Tue, 2 May 2023 07:05:50 +0000 Subject: [PATCH 633/656] Call SubscriptionManagerService#updateEmbeddedSubscriptions API callback once after the embedded subs info update is completed. Test: atest FrameworksTelephonyTests Test: Verified on C10P10 b/276843471#comment13 Bug: 279531290, 276843471 Change-Id: I77d2cf8191129264579793f8a23fd534145a7f63 --- .../subscription/SubscriptionManagerService.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index b43fe9f0e4..b37992b2ac 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -1182,11 +1182,14 @@ public class SubscriptionManagerService extends ISub.Stub { } else { loge("The eSIM profiles update was not successful."); } + log("updateEmbeddedSubscriptions: Finished embedded subscription update."); + // The runnable will be executed in the main thread. Pre Android-U behavior. + mHandler.post(() -> { + if (callback != null) { + callback.run(); + } + }); }); - log("updateEmbeddedSubscriptions: Finished embedded subscription update."); - if (callback != null) { - callback.run(); - } } /** -- GitLab From 3b867a7f76236296d154a87d6e975c826e2fc90a Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Tue, 4 Apr 2023 13:55:03 +0000 Subject: [PATCH 634/656] Updating Satellite Mode Key in Settings - Registering to all radio states - Update Satelllite Mode key, check if all radios are disabled when satellite is enabled Bug: b/277057547 Test: atest SatelliteManagerTest Change-Id: I8b1897ab3e71da75606c0e5c2b20dd0b76cb6217 --- .../satellite/SatelliteController.java | 485 ++++++++++++++---- 1 file changed, 389 insertions(+), 96 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 331d7b26f8..16efb27ab7 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -19,10 +19,18 @@ package com.android.internal.telephony.satellite; import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; +import android.database.ContentObserver; import android.net.wifi.WifiManager; +import android.nfc.NfcAdapter; +import android.nfc.NfcManager; import android.os.AsyncResult; +import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; @@ -33,6 +41,7 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ResultReceiver; +import android.provider.Settings; import android.telephony.Rlog; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -44,7 +53,9 @@ import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.util.Log; +import android.uwb.UwbManager; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IIntegerConsumer; @@ -70,7 +81,9 @@ public class SatelliteController extends Handler { private static final boolean DBG = false; /** File used to store shared preferences related to satellite. */ public static final String SATELLITE_SHARED_PREF = "satellite_shared_pref"; - + /** Value to pass for the setting key SATELLITE_MODE_ENABLED, enabled = 1, disabled = 0 */ + public static final int SATELLITE_MODE_ENABLED_TRUE = 1; + public static final int SATELLITE_MODE_ENABLED_FALSE = 0; /** Message codes used in handleMessage() */ //TODO: Move the Commands and events related to position updates to PointingAppController @@ -111,14 +124,35 @@ public class SatelliteController extends Handler { @NonNull private final ProvisionMetricsStats mProvisionMetricsStats; private SharedPreferences mSharedPreferences = null; private final CommandsInterface mCi; + private ContentResolver mContentResolver = null; + + private final Object mRadioStateLock = new Object(); + + /** Flags to indicate whether the resepective radio is enabled */ + @GuardedBy("mRadioStateLock") + private boolean mBTStateEnabled = false; + @GuardedBy("mRadioStateLock") + private boolean mNfcStateEnabled = false; + @GuardedBy("mRadioStateLock") + private boolean mUwbStateEnabled = false; + @GuardedBy("mRadioStateLock") + private boolean mWifiStateEnabled = false; + + // Flags to indicate that respective radios need to be disabled when satellite is enabled + private boolean mDisableBTOnSatelliteEnabled = false; + private boolean mDisableNFCOnSatelliteEnabled = false; + private boolean mDisableUWBOnSatelliteEnabled = false; + private boolean mDisableWifiOnSatelliteEnabled = false; + + private final Object mSatelliteEnabledRequestLock = new Object(); + @GuardedBy("mSatelliteEnabledRequestLock") + private RequestSatelliteEnabledArgument mSatelliteEnabledRequest = null; + /** Flag to indicate that satellite is enabled successfully + * and waiting for all the radios to be disabled so that success can be sent to callback + */ + @GuardedBy("mSatelliteEnabledRequestLock") + private boolean mWaitingForRadioDisabled = false; - BluetoothAdapter mBluetoothAdapter = null; - WifiManager mWifiManager = null; - /** Shared preference key to store the existing state of Bluetooth and Wifi*/ - private static final String KEY_BLUETOOTH_DISABLED_BY_SCO = "bluetooth_disabled_by_sco"; - private static final String KEY_WIFI_DISABLED_BY_SCO = "wifi_disabled_by_sco"; - boolean mDisabledBTFlag = false; - boolean mDisabledWifiFlag = false; private final AtomicBoolean mRegisteredForProvisionStateChangedWithSatelliteService = new AtomicBoolean(false); private final AtomicBoolean mRegisteredForProvisionStateChangedWithPhone = @@ -142,19 +176,23 @@ public class SatelliteController extends Handler { */ private final ConcurrentHashMap mSatelliteProvisionStateChangedListeners = new ConcurrentHashMap<>(); - - private Boolean mIsSatelliteSupported = null; private final Object mIsSatelliteSupportedLock = new Object(); + @GuardedBy("mIsSatelliteSupportedLock") + private Boolean mIsSatelliteSupported = null; private boolean mIsDemoModeEnabled = false; + private final Object mIsSatelliteEnabledLock = new Object(); + @GuardedBy("mIsSatelliteEnabledLock") private Boolean mIsSatelliteEnabled = null; private boolean mIsRadioOn = false; - private final Object mIsSatelliteEnabledLock = new Object(); - private Boolean mIsSatelliteProvisioned = null; private final Object mIsSatelliteProvisionedLock = new Object(); - private SatelliteCapabilities mSatelliteCapabilities; + @GuardedBy("mIsSatelliteProvisionedLock") + private Boolean mIsSatelliteProvisioned = null; private final Object mSatelliteCapabilitiesLock = new Object(); - private boolean mNeedsSatellitePointing = false; + @GuardedBy("mSatelliteCapabilitiesLock") + private SatelliteCapabilities mSatelliteCapabilities; private final Object mNeedsSatellitePointingLock = new Object(); + @GuardedBy("mNeedsSatellitePointingLock") + private boolean mNeedsSatellitePointing = false; /** * @return The singleton instance of SatelliteController. @@ -221,30 +259,201 @@ public class SatelliteController extends Handler { registerForSatelliteProvisionStateChanged(); registerForPendingDatagramCount(); registerForSatelliteModemStateChanged(); + mContentResolver = mContext.getContentResolver(); + try { mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); } catch (Exception e) { loge("Cannot get default shared preferences: " + e); } - //if BT and Wifi was already disabled by Satellite Controller, reset - if ((mSharedPreferences != null) && - (mSharedPreferences.contains(KEY_BLUETOOTH_DISABLED_BY_SCO) || - mSharedPreferences.contains(KEY_WIFI_DISABLED_BY_SCO))) { - /** - * read the flag from shared preference to check if the Bluetooth and Wifi was disabled - * by Satellite Controller - */ - mDisabledBTFlag = mSharedPreferences - .getBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, false); - mDisabledWifiFlag = mSharedPreferences - .getBoolean(KEY_WIFI_DISABLED_BY_SCO, false); - checkAndEnableBluetoothWifiState(); + + initializeSatelliteModeRadios(); + + ContentObserver satelliteModeRadiosContentObserver = new ContentObserver(this) { + @Override + public void onChange(boolean selfChange) { + initializeSatelliteModeRadios(); + } + }; + if (mContentResolver != null) { + mContentResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.SATELLITE_MODE_RADIOS), + false, satelliteModeRadiosContentObserver); + } + } + + private void initializeSatelliteModeRadios() { + UwbManager uwbManager = mContext.getSystemService(UwbManager.class); + NfcManager nfcManager = mContext.getSystemService(NfcManager.class); + NfcAdapter nfcAdapter = null; + if (nfcManager != null) { + nfcAdapter = nfcManager.getDefaultAdapter(); + } + BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + WifiManager wifiManager = mContext.getSystemService(WifiManager.class); + + if (mContentResolver != null) { + BTWifiNFCStateReceiver bTWifiNFCSateReceiver = new BTWifiNFCStateReceiver(); + UwbAdapterStateCallback uwbAdapterStateCallback = new UwbAdapterStateCallback(); + IntentFilter radioStateIntentFilter = new IntentFilter(); + + synchronized (mRadioStateLock) { + // Initialize radio states to default value + mDisableBTOnSatelliteEnabled = false; + mDisableNFCOnSatelliteEnabled = false; + mDisableWifiOnSatelliteEnabled = false; + mDisableUWBOnSatelliteEnabled = false; + + mBTStateEnabled = false; + mNfcStateEnabled = false; + mWifiStateEnabled = false; + mUwbStateEnabled = false; + + // Read satellite mode radios from settings + String satelliteModeRadios = Settings.Global.getString(mContentResolver, + Settings.Global.SATELLITE_MODE_RADIOS); + logd("Radios To be checked when satellite is on: " + satelliteModeRadios); + + if (satelliteModeRadios.contains(Settings.Global.RADIO_BLUETOOTH) + && bluetoothAdapter != null) { + mDisableBTOnSatelliteEnabled = true; + mBTStateEnabled = bluetoothAdapter.isEnabled(); + radioStateIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); + } + + if (satelliteModeRadios.contains(Settings.Global.RADIO_NFC) + && nfcAdapter != null) { + mDisableNFCOnSatelliteEnabled = true; + mNfcStateEnabled = nfcAdapter.isEnabled(); + radioStateIntentFilter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); + } + + if (satelliteModeRadios.contains(Settings.Global.RADIO_WIFI) + && wifiManager != null) { + mDisableWifiOnSatelliteEnabled = true; + mWifiStateEnabled = wifiManager.isWifiEnabled(); + radioStateIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + } + mContext.registerReceiver(bTWifiNFCSateReceiver, radioStateIntentFilter); + + if (satelliteModeRadios.contains(Settings.Global.RADIO_UWB) + && uwbManager != null) { + mDisableUWBOnSatelliteEnabled = true; + mUwbStateEnabled = uwbManager.isUwbEnabled(); + final long identity = Binder.clearCallingIdentity(); + try { + uwbManager.registerAdapterStateCallback(mContext.getMainExecutor(), + uwbAdapterStateCallback); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + logd("mDisableBTOnSatelliteEnabled: " + mDisableBTOnSatelliteEnabled + + " mDisableNFCOnSatelliteEnabled: " + mDisableNFCOnSatelliteEnabled + + " mDisableWifiOnSatelliteEnabled: " + mDisableWifiOnSatelliteEnabled + + " mDisableUWBOnSatelliteEnabled: " + mDisableUWBOnSatelliteEnabled); + + logd("mBTStateEnabled: " + mBTStateEnabled + + " mNfcStateEnabled: " + mNfcStateEnabled + + " mWifiStateEnabled: " + mWifiStateEnabled + + " mUwbStateEnabled: " + mUwbStateEnabled); + } } } - private void internalInit() { + protected class UwbAdapterStateCallback implements UwbManager.AdapterStateCallback { + + public String toString(int state) { + switch (state) { + case UwbManager.AdapterStateCallback.STATE_DISABLED: + return "Disabled"; + + case UwbManager.AdapterStateCallback.STATE_ENABLED_INACTIVE: + return "Inactive"; + + case UwbManager.AdapterStateCallback.STATE_ENABLED_ACTIVE: + return "Active"; + default: + return ""; + } + } + + @Override + public void onStateChanged(int state, int reason) { + logd("UwbAdapterStateCallback#onStateChanged() called, state = " + toString(state)); + logd("Adapter state changed reason " + String.valueOf(reason)); + synchronized (mRadioStateLock) { + if (state == UwbManager.AdapterStateCallback.STATE_DISABLED) { + mUwbStateEnabled = false; + evaluateToSendSatelliteEnabledSuccess(); + } else { + mUwbStateEnabled = true; + } + logd("mUwbStateEnabled: " + mUwbStateEnabled); + } + } + } + + protected class BTWifiNFCStateReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action == null) { + logd("BTWifiNFCStateReceiver NULL action for intent " + intent); + return; + } + + switch (action) { + case BluetoothAdapter.ACTION_STATE_CHANGED: + int btState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, + BluetoothAdapter.ERROR); + logd("Bluetooth state updated to " + btState); + synchronized (mRadioStateLock) { + if (btState == BluetoothAdapter.STATE_OFF) { + mBTStateEnabled = false; + evaluateToSendSatelliteEnabledSuccess(); + } else if (btState == BluetoothAdapter.STATE_ON) { + mBTStateEnabled = true; + } + logd("mBTStateEnabled: " + mBTStateEnabled); + } + break; + + case NfcAdapter.ACTION_ADAPTER_STATE_CHANGED: + int nfcState = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE, -1); + logd("Nfc state updated to " + nfcState); + synchronized (mRadioStateLock) { + if (nfcState == NfcAdapter.STATE_ON) { + mNfcStateEnabled = true; + } else if (nfcState == NfcAdapter.STATE_OFF) { + mNfcStateEnabled = false; + evaluateToSendSatelliteEnabledSuccess(); + } + logd("mNfcStateEnabled: " + mNfcStateEnabled); + } + break; + + case WifiManager.WIFI_STATE_CHANGED_ACTION: + int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_UNKNOWN); + logd("Wifi state updated to " + wifiState); + synchronized (mRadioStateLock) { + if (wifiState == WifiManager.WIFI_STATE_ENABLED) { + mWifiStateEnabled = true; + } else if (wifiState == WifiManager.WIFI_STATE_DISABLED) { + mWifiStateEnabled = false; + evaluateToSendSatelliteEnabledSuccess(); + } + logd("mWifiStateEnabled: " + mWifiStateEnabled); + } + break; + default: + break; + } + } } private static final class SatelliteControllerHandlerRequest { @@ -442,26 +651,59 @@ public class SatelliteController extends Handler { RequestSatelliteEnabledArgument argument = (RequestSatelliteEnabledArgument) request.argument; int error = SatelliteServiceUtils.getSatelliteError(ar, "setSatelliteEnabled"); + logd("EVENT_SET_SATELLITE_ENABLED_DONE = " + error); + if (error == SatelliteManager.SATELLITE_ERROR_NONE) { if (argument.enableSatellite) { - //If satellite mode is enabled successfully, disable Bluetooth and wifi - disableBluetoothWifiState(); + synchronized (mSatelliteEnabledRequestLock) { + mWaitingForRadioDisabled = true; + } + setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_TRUE); + /** * TODO for NTN-based satellites: Check if satellite is acquired. */ if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(false); } + + evaluateToSendSatelliteEnabledSuccess(); } else { - //Disabled satellite mode, Reset BT and Wifi if previously changed here - checkAndEnableBluetoothWifiState(); + synchronized (mSatelliteEnabledRequestLock) { + if (mSatelliteEnabledRequest != null && + mSatelliteEnabledRequest.enableSatellite == true && + argument.enableSatellite == false && mWaitingForRadioDisabled) { + // Previous mSatelliteEnabledRequest is successful but waiting for + // all radios to be turned off. + mSatelliteEnabledRequest.callback.accept( + SatelliteManager.SATELLITE_ERROR_NONE); + } + } + resetSatelliteEnabledRequest(); + + setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_FALSE); + // If satellite is disabled, send success to callback immediately + argument.callback.accept(error); + setIsDemoModeEnabled(argument.enableDemoMode); + updateSatelliteEnabledState( + argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); } - mIsDemoModeEnabled = argument.enableDemoMode; - mDatagramController.setDemoMode(mIsDemoModeEnabled); - updateSatelliteEnabledState( - argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); + } else { + synchronized (mSatelliteEnabledRequestLock) { + if (mSatelliteEnabledRequest != null && + mSatelliteEnabledRequest.enableSatellite == true && + argument.enableSatellite == false && mWaitingForRadioDisabled) { + // Previous mSatelliteEnabledRequest is successful but waiting for + // all radios to be turned off. + mSatelliteEnabledRequest.callback.accept( + SatelliteManager.SATELLITE_ERROR_NONE); + } + } + resetSatelliteEnabledRequest(); + + // If Satellite enable/disable request returned Error, no need to wait for radio + argument.callback.accept(error); } - argument.callback.accept(error); if (argument.enableSatellite) { if (error == SatelliteManager.SATELLITE_ERROR_NONE) { @@ -834,7 +1076,11 @@ public class SatelliteController extends Handler { */ public void requestSatelliteEnabled(int subId, boolean enableSatellite, boolean enableDemoMode, @NonNull IIntegerConsumer callback) { + logd("requestSatelliteEnabled subId: " + subId + " enableSatellite: " + enableSatellite + + " enableDemoMode: " + enableDemoMode); + Consumer result = FunctionalUtils.ignoreRemoteException(callback::accept); + Boolean satelliteSupported = isSatelliteSupportedInternal(); if (satelliteSupported == null) { result.accept(SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE); @@ -866,25 +1112,53 @@ public class SatelliteController extends Handler { enableDemoMode = false; } - if (mIsSatelliteEnabled != null) { - if (mIsSatelliteEnabled == enableSatellite) { - if (enableDemoMode != mIsDemoModeEnabled) { - loge("Received invalid demo mode while satellite session is enabled" - + " enableDemoMode = " + enableDemoMode); - result.accept(SatelliteManager.SATELLITE_INVALID_ARGUMENTS); - return; - } else { - logd("Enable request matches with current state" - + " enableSatellite = " + enableSatellite); - result.accept(SatelliteManager.SATELLITE_ERROR_NONE); - return; + synchronized (mIsSatelliteEnabledLock) { + if (mIsSatelliteEnabled != null) { + if (mIsSatelliteEnabled == enableSatellite) { + if (enableDemoMode != mIsDemoModeEnabled) { + loge("Received invalid demo mode while satellite session is enabled" + + " enableDemoMode = " + enableDemoMode); + result.accept(SatelliteManager.SATELLITE_INVALID_ARGUMENTS); + return; + } else { + logd("Enable request matches with current state" + + " enableSatellite = " + enableSatellite); + result.accept(SatelliteManager.SATELLITE_ERROR_NONE); + return; + } } } } - sendRequestAsync(CMD_SET_SATELLITE_ENABLED, - new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result), - SatelliteServiceUtils.getPhone()); + RequestSatelliteEnabledArgument request = + new RequestSatelliteEnabledArgument(enableSatellite, enableDemoMode, result); + /** + * Multiple satellite enabled requests are handled as below: + * 1. If there are no ongoing requests, store current request in mSatelliteEnabledRequest + * 2. If there is a ongoing request, then: + * 1. ongoing request = enable, current request = enable: return IN_PROGRESS error + * 2. ongoing request = disable, current request = disable: return IN_PROGRESS error + * 3. ongoing request = disable, current request = enable: return SATELLITE_ERROR error + * 4. ongoing request = enable, current request = disable: send request to modem + */ + synchronized (mSatelliteEnabledRequestLock) { + if (mSatelliteEnabledRequest == null) { + mSatelliteEnabledRequest = request; + } else if (mSatelliteEnabledRequest.enableSatellite == request.enableSatellite) { + logd("requestSatelliteEnabled enableSatellite: " + enableSatellite + + " is already in progress."); + result.accept(SatelliteManager.SATELLITE_REQUEST_IN_PROGRESS); + return; + } else if (mSatelliteEnabledRequest.enableSatellite == false + && request.enableSatellite == true) { + logd("requestSatelliteEnabled enableSatellite: " + enableSatellite + " cannot be " + + "processed. Disable satellite is already in progress."); + result.accept(SatelliteManager.SATELLITE_ERROR); + return; + } + } + + sendRequestAsync(CMD_SET_SATELLITE_ENABLED, request, SatelliteServiceUtils.getPhone()); } /** @@ -1821,50 +2095,6 @@ public class SatelliteController extends Handler { } } - private void disableBluetoothWifiState() { - if (mBluetoothAdapter == null) { - mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - } - if (mWifiManager == null) { - mWifiManager = mContext.getSystemService(WifiManager.class); - } - if (mBluetoothAdapter.isEnabled()) { - if (DBG) logd("disabling Bluetooth"); - //Set the Flag to indicate that Bluetooth is disabled by Satellite Controller - mSharedPreferences.edit().putBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, true) - .apply(); - mBluetoothAdapter.disable(); - } - if (mWifiManager.isWifiEnabled()) { - if (DBG) logd("disabling Wifi"); - //Set the Flag to indicate that Wifi is disabled by Satellite Controller - mSharedPreferences.edit().putBoolean(KEY_WIFI_DISABLED_BY_SCO, true) - .apply(); - mWifiManager.setWifiEnabled(false); - } - } - - private void checkAndEnableBluetoothWifiState() { - if (mBluetoothAdapter == null) { - mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - } - if (mWifiManager == null) { - mWifiManager = mContext.getSystemService(WifiManager.class); - } - if (!mBluetoothAdapter.isEnabled() && mDisabledBTFlag) { - if (DBG) logd("Enabling Bluetooth"); - mBluetoothAdapter.enable(); - mSharedPreferences.edit().putBoolean(KEY_BLUETOOTH_DISABLED_BY_SCO, false) - .apply(); - } - if (!mWifiManager.isWifiEnabled() && mDisabledWifiFlag) { - if (DBG) logd("Enabling Wifi"); - mWifiManager.setWifiEnabled(true); - mSharedPreferences.edit().putBoolean(KEY_WIFI_DISABLED_BY_SCO, false) - .apply(); - } - } - private void registerForSatelliteProvisionStateChanged() { if (mSatelliteModemInterface.isSatelliteServiceSupported()) { if (!mRegisteredForProvisionStateChangedWithSatelliteService.get()) { @@ -1951,9 +2181,72 @@ public class SatelliteController extends Handler { || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { updateSatelliteEnabledState( false, "handleEventSatelliteModemStateChanged"); + cleanUpResources(state); } + mDatagramController.onSatelliteModemStateChanged(state); } + private void setSettingsKeyForSatelliteMode(int val) { + logd("setSettingsKeyForSatelliteMode val: " + val); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.SATELLITE_MODE_ENABLED, val); + } + + private boolean areAllRadiosDisabled() { + synchronized (mRadioStateLock) { + if ((mDisableBTOnSatelliteEnabled && mBTStateEnabled) + || (mDisableNFCOnSatelliteEnabled && mNfcStateEnabled) + || (mDisableWifiOnSatelliteEnabled && mWifiStateEnabled) + || (mDisableUWBOnSatelliteEnabled && mUwbStateEnabled)) { + logd("All radios are not disabled yet."); + return false; + } + logd("All radios are disabled."); + return true; + } + } + + private void evaluateToSendSatelliteEnabledSuccess() { + logd("evaluateToSendSatelliteEnabledSuccess"); + synchronized (mSatelliteEnabledRequestLock) { + if (areAllRadiosDisabled() && (mSatelliteEnabledRequest != null) + && mWaitingForRadioDisabled) { + logd("Sending success to callback that sent enable satellite request"); + setIsDemoModeEnabled(mSatelliteEnabledRequest.enableDemoMode); + updateSatelliteEnabledState(mSatelliteEnabledRequest.enableSatellite, + "EVENT_SET_SATELLITE_ENABLED_DONE"); + mSatelliteEnabledRequest.callback.accept(SatelliteManager.SATELLITE_ERROR_NONE); + mSatelliteEnabledRequest = null; + mWaitingForRadioDisabled = false; + } + } + } + + private void resetSatelliteEnabledRequest() { + logd("resetSatelliteEnabledRequest"); + synchronized (mSatelliteEnabledRequestLock) { + mSatelliteEnabledRequest = null; + mWaitingForRadioDisabled = false; + } + } + + private void cleanUpResources(@SatelliteManager.SatelliteModemState int state) { + logd("cleanUpResources"); + if (state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { + synchronized (mSatelliteEnabledRequestLock) { + if (mSatelliteEnabledRequest != null) { + mSatelliteEnabledRequest.callback.accept( + SatelliteManager.SATELLITE_INVALID_MODEM_STATE); + } + } + resetSatelliteEnabledRequest(); + } + } + + private void setIsDemoModeEnabled(boolean enabled) { + mIsDemoModeEnabled = enabled; + mDatagramController.setDemoMode(mIsDemoModeEnabled); + } private static void logd(@NonNull String log) { Rlog.d(TAG, log); -- GitLab From 27408c67732ededa9fd3a244d06540a249238021 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Fri, 28 Apr 2023 00:20:41 -0700 Subject: [PATCH 635/656] Notify link status changed on connected or disconnected only NetworkTypeController relies on link status changed events to distinguish RRC idle vs connected if it does not use physical channel config indications. If data is unexpectedly disconnected, DN/DNC might not send the link status changed event. When a DataNetwork disconnects, update the link status to make sure we don't miss an INACTIVE state update. When we receive a data call response in connecting state, the link status can be prematurely updated. Update the link status only and defer notifying DNC of the change until the data network is in connected or disconnected state. If the data network is already in connected state, update the link status if it has changed. Test: atest DataNetworkTest, DataNetworkControllerTest Test: manual basic data tests Bug: 279380751 Bug: 276710123 Change-Id: I877b3ed736a0c81b8a0dd692dfdc49a832642ab0 --- .../internal/telephony/data/DataNetwork.java | 17 +++- .../data/DataNetworkControllerTest.java | 11 ++- .../telephony/data/DataNetworkTest.java | 86 +++++++++++++------ 3 files changed, 85 insertions(+), 29 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index 5ce6f339d0..d533933bf2 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -1340,13 +1340,14 @@ public class DataNetwork extends StateMachine { } } - // If we've ever received PCO data before connected, now it's the time to - // process it. + // 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); }); + mDataNetworkCallback.invokeFromExecutor( + () -> mDataNetworkCallback.onLinkStatusChanged(DataNetwork.this, mLinkStatus)); notifyPreciseDataConnectionState(); updateSuspendState(); } @@ -1598,6 +1599,9 @@ public class DataNetwork extends StateMachine { //************************************************************// if (mEverConnected) { + mLinkStatus = DataCallResponse.LINK_STATUS_INACTIVE; + mDataNetworkCallback.invokeFromExecutor(() -> mDataNetworkCallback + .onLinkStatusChanged(DataNetwork.this, mLinkStatus)); mDataNetworkCallback.invokeFromExecutor(() -> mDataNetworkCallback .onDisconnected(DataNetwork.this, mFailCause, mTearDownReason)); if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { @@ -2302,8 +2306,13 @@ public class DataNetwork extends StateMachine { if (mLinkStatus != response.getLinkStatus()) { mLinkStatus = response.getLinkStatus(); log("Link status updated to " + DataUtils.linkStatusToString(mLinkStatus)); - mDataNetworkCallback.invokeFromExecutor( - () -> mDataNetworkCallback.onLinkStatusChanged(DataNetwork.this, mLinkStatus)); + if (isConnected()) { + // If the data network is in a transition state, the link status will be notified + // upon entering connected or disconnected state. If the data network is already + // connected, send the updated link status from the updated data call response. + mDataNetworkCallback.invokeFromExecutor(() -> mDataNetworkCallback + .onLinkStatusChanged(DataNetwork.this, mLinkStatus)); + } } // Set link addresses 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 62e8ba8108..696042e18a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -1299,6 +1299,8 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyAllDataDisconnected(); verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(false)); verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkDisconnected(); + verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( + eq(DataCallResponse.LINK_STATUS_INACTIVE)); } @Test @@ -1461,7 +1463,8 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyAllDataDisconnected(); verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(false)); verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkDisconnected(); - + verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( + eq(DataCallResponse.LINK_STATUS_INACTIVE)); Mockito.clearInvocations(mMockedDataNetworkControllerCallback); // Now RAT changes from GSM to UMTS @@ -2335,6 +2338,8 @@ public class DataNetworkControllerTest extends TelephonyTest { // Verify all data disconnected. verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(false)); + verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( + eq(DataCallResponse.LINK_STATUS_INACTIVE)); // A new data network should be connected on IWLAN List dataNetworkList = getDataNetworks(); @@ -2395,6 +2400,8 @@ public class DataNetworkControllerTest extends TelephonyTest { // Verify all data disconnected. verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(false)); + verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( + eq(DataCallResponse.LINK_STATUS_INACTIVE)); // Should setup a new one instead of handover. verify(mMockedWwanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), @@ -4243,6 +4250,8 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyAllDataDisconnected(); verify(mMockedDataNetworkControllerCallback).onAnyDataNetworkExistingChanged(eq(false)); verify(mMockedDataNetworkControllerCallback).onInternetDataNetworkDisconnected(); + verify(mMockedDataNetworkControllerCallback).onPhysicalLinkStatusChanged( + eq(DataCallResponse.LINK_STATUS_INACTIVE)); } @Test 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 8d9fdf23cc..b85081f1c6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -202,30 +202,8 @@ public class DataNetworkTest extends TelephonyTest { doAnswer(invocation -> { final Message msg = (Message) invocation.getArguments()[10]; - DataCallResponse response = new DataCallResponse.Builder() - .setCause(0) - .setRetryDurationMillis(-1L) - .setId(cid) - .setLinkStatus(2) - .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) - .setInterfaceName("ifname") - .setAddresses(Arrays.asList( - new LinkAddress(InetAddresses.parseNumericAddress(IPV4_ADDRESS), 32), - new LinkAddress(IPV6_ADDRESS + "/64"))) - .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), - InetAddresses.parseNumericAddress("fd00:976a::9"))) - .setGatewayAddresses(Arrays.asList( - InetAddresses.parseNumericAddress("10.0.2.15"), - InetAddresses.parseNumericAddress("fe80::2"))) - .setPcscfAddresses(Arrays.asList( - InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), - InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), - InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) - .setMtuV4(1234) - .setPduSessionId(1) - .setQosBearerSessions(new ArrayList<>()) - .setTrafficDescriptors(tds) - .build(); + DataCallResponse response = createDataCallResponse( + cid, DataCallResponse.LINK_STATUS_ACTIVE, tds); msg.getData().putParcelable("data_call_response", response); msg.arg1 = DataServiceCallback.RESULT_SUCCESS; msg.sendToTarget(); @@ -235,6 +213,34 @@ public class DataNetworkTest extends TelephonyTest { any(Message.class)); } + private DataCallResponse createDataCallResponse(int cid, int linkStatus, + List tds) { + return new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1L) + .setId(cid) + .setLinkStatus(linkStatus) + .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) + .setInterfaceName("ifname") + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(IPV4_ADDRESS), 32), + new LinkAddress(IPV6_ADDRESS + "/64"))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), + InetAddresses.parseNumericAddress("fd00:976a::9"))) + .setGatewayAddresses(Arrays.asList( + InetAddresses.parseNumericAddress("10.0.2.15"), + InetAddresses.parseNumericAddress("fe80::2"))) + .setPcscfAddresses(Arrays.asList( + InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), + InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), + InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) + .setMtuV4(1234) + .setPduSessionId(1) + .setQosBearerSessions(new ArrayList<>()) + .setTrafficDescriptors(tds) + .build(); + } + private void setFailedSetupDataResponse(DataServiceManager dsm, @DataServiceCallback.ResultCode int resultCode) { doAnswer(invocation -> { @@ -1769,4 +1775,36 @@ public class DataNetworkTest extends TelephonyTest { assertThat(mDataNetworkUT.getLinkProperties().getAllAddresses()).containsExactly( InetAddresses.parseNumericAddress(IPV4_ADDRESS)); } + + @Test + public void testLinkStatusUpdate() throws Exception { + setupDataNetwork(); + + // verify link status sent on connected + verify(mDataNetworkCallback).onConnected(eq(mDataNetworkUT)); + verify(mDataNetworkCallback).onLinkStatusChanged(eq(mDataNetworkUT), + eq(DataCallResponse.LINK_STATUS_ACTIVE)); + + // data state updated + DataCallResponse response = createDataCallResponse(123, + DataCallResponse.LINK_STATUS_DORMANT, Collections.emptyList()); + mDataNetworkUT.sendMessage(8 /*EVENT_DATA_STATE_CHANGED*/, new AsyncResult( + AccessNetworkConstants.TRANSPORT_TYPE_WWAN, List.of(response), null)); + processAllMessages(); + + // verify link status sent on data state updated + assertThat(mDataNetworkUT.isConnected()).isTrue(); + verify(mDataNetworkCallback).onLinkStatusChanged(eq(mDataNetworkUT), + eq(DataCallResponse.LINK_STATUS_DORMANT)); + + // RIL crash + mDataNetworkUT.sendMessage(4 /*EVENT_RADIO_NOT_AVAILABLE*/); + processAllMessages(); + + // verify link status sent on disconnected + verify(mDataNetworkCallback).onDisconnected(eq(mDataNetworkUT), + eq(DataFailCause.RADIO_NOT_AVAILABLE), eq(DataNetwork.TEAR_DOWN_REASON_NONE)); + verify(mDataNetworkCallback).onLinkStatusChanged(eq(mDataNetworkUT), + eq(DataCallResponse.LINK_STATUS_INACTIVE)); + } } -- GitLab From 863038a242ea878d1db66c50254f567aa11c850e Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Fri, 28 Apr 2023 09:39:59 -0700 Subject: [PATCH 636/656] Add unit test framework and some tests for SatelliteController Bug: 279929401 Test: Call/SMS/MMS with live network. atest SatelliteControllerTest Change-Id: I2f4cc9fffe350b409b8587e8b148249da7c769b4 --- .../satellite/DatagramController.java | 9 +- .../satellite/SatelliteController.java | 21 +- .../satellite/SatelliteModemInterface.java | 3 +- .../satellite/SatelliteSessionController.java | 3 +- .../satellite/SatelliteControllerTest.java | 770 ++++++++++++++++++ 5 files changed, 795 insertions(+), 11 deletions(-) create mode 100644 tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 2e6f9a3590..6ebb0b8b78 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -98,7 +98,7 @@ public class DatagramController { * @param pointingAppController PointingAppController is used to update PointingApp * about datagram transfer state changes. */ - @VisibleForTesting + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected DatagramController(@NonNull Context context, @NonNull Looper looper, @NonNull PointingAppController pointingAppController) { mContext = context; @@ -264,7 +264,8 @@ public class DatagramController { * Set variables for {@link DatagramDispatcher} and {@link DatagramReceiver} to run demo mode * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise. */ - void setDemoMode(boolean isDemoMode) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setDemoMode(boolean isDemoMode) { mIsDemoMode = isDemoMode; mDatagramDispatcher.setDemoMode(isDemoMode); mDatagramReceiver.setDemoMode(isDemoMode); @@ -275,7 +276,7 @@ public class DatagramController { } /** Get the last sent datagram for demo mode */ - @VisibleForTesting + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public SatelliteDatagram getDemoModeDatagram() { return mDemoModeDatagram; } @@ -285,7 +286,7 @@ public class DatagramController { * @param datagramType datagram type, only DATAGRAM_TYPE_SOS_MESSAGE will be saved * @param datagram datagram The last datagram saved when sendSatelliteDatagramForDemo is called */ - @VisibleForTesting + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected void setDemoModeDatagram(@SatelliteManager.DatagramType int datagramType, SatelliteDatagram datagram) { if (mIsDemoMode && datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 16efb27ab7..6fd13c8e71 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -283,7 +283,8 @@ public class SatelliteController extends Handler { } } - private void initializeSatelliteModeRadios() { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected void initializeSatelliteModeRadios() { UwbManager uwbManager = mContext.getSystemService(UwbManager.class); NfcManager nfcManager = mContext.getSystemService(NfcManager.class); NfcAdapter nfcAdapter = null; @@ -313,6 +314,10 @@ public class SatelliteController extends Handler { // Read satellite mode radios from settings String satelliteModeRadios = Settings.Global.getString(mContentResolver, Settings.Global.SATELLITE_MODE_RADIOS); + if (satelliteModeRadios == null) { + loge("initializeSatelliteModeRadios: satelliteModeRadios is null"); + return; + } logd("Radios To be checked when satellite is on: " + satelliteModeRadios); if (satelliteModeRadios.contains(Settings.Global.RADIO_BLUETOOTH) @@ -1146,7 +1151,7 @@ public class SatelliteController extends Handler { mSatelliteEnabledRequest = request; } else if (mSatelliteEnabledRequest.enableSatellite == request.enableSatellite) { logd("requestSatelliteEnabled enableSatellite: " + enableSatellite - + " is already in progress."); + + " is already in progress."); result.accept(SatelliteManager.SATELLITE_REQUEST_IN_PROGRESS); return; } else if (mSatelliteEnabledRequest.enableSatellite == false @@ -1756,6 +1761,8 @@ public class SatelliteController extends Handler { boolean result = mSatelliteModemInterface.setSatelliteServicePackageName( servicePackageName); if (result) { + logd("setSatelliteServicePackageName: Resetting cached states"); + // Cached states need to be cleared whenever switching satellite vendor services. synchronized (mIsSatelliteSupportedLock) { mIsSatelliteSupported = null; @@ -1847,7 +1854,8 @@ public class SatelliteController extends Handler { * Because satellite vendor service might have just come back from a crash, we need to disable * the satellite modem so that resources will be cleaned up and internal states will be reset. */ - void onSatelliteServiceConnected() { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void onSatelliteServiceConnected() { if (mSatelliteModemInterface.isSatelliteServiceSupported()) { synchronized (mIsSatelliteSupportedLock) { if (mIsSatelliteSupported == null) { @@ -2186,13 +2194,16 @@ public class SatelliteController extends Handler { mDatagramController.onSatelliteModemStateChanged(state); } - private void setSettingsKeyForSatelliteMode(int val) { + + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected void setSettingsKeyForSatelliteMode(int val) { logd("setSettingsKeyForSatelliteMode val: " + val); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.SATELLITE_MODE_ENABLED, val); } - private boolean areAllRadiosDisabled() { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) + protected boolean areAllRadiosDisabled() { synchronized (mRadioStateLock) { if ((mDisableBTOnSatelliteEnabled && mBTStateEnabled) || (mDisableNFCOnSatelliteEnabled && mNfcStateEnabled) diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java index 4d5e75de81..80c67b315a 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java @@ -1015,7 +1015,8 @@ public class SatelliteModemInterface { * @return {@code true} if the satellite vendor service is set successfully, * {@code false} otherwise. */ - boolean setSatelliteServicePackageName(@Nullable String servicePackageName) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public boolean setSatelliteServicePackageName(@Nullable String servicePackageName) { if (!shouldAllowModifyingSatelliteServicePackageName()) { loge("setSatelliteServicePackageName: modifying satellite service package name " + "is not allowed"); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java index d33046d336..36ad2503d0 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteSessionController.java @@ -338,7 +338,8 @@ public class SatelliteSessionController extends StateMachine { * {@code false} : The listening timeout durations will be restored to * production mode */ - void setDemoMode(boolean isDemoMode) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setDemoMode(boolean isDemoMode) { mIsDemoMode = isDemoMode; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java new file mode 100644 index 0000000000..63eb656103 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2023 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 static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_ENABLED; +import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_PROVISIONED; +import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_SUPPORTED; +import static android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_EMTC_NTN; +import static android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_NR_NTN; +import static android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_PROPRIETARY; +import static android.telephony.satellite.SatelliteManager.SATELLITE_ERROR; +import static android.telephony.satellite.SatelliteManager.SATELLITE_ERROR_NONE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_ARGUMENTS; +import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_MODEM_STATE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_NOT_SUPPORTED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_REQUEST_IN_PROGRESS; +import static android.telephony.satellite.SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED; + +import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_MODE_ENABLED_FALSE; +import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_MODE_ENABLED_TRUE; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.AsyncResult; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ResultReceiver; +import android.telephony.Rlog; +import android.telephony.satellite.SatelliteCapabilities; +import android.telephony.satellite.SatelliteManager; +import android.telephony.satellite.SatelliteManager.SatelliteException; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.internal.telephony.IIntegerConsumer; +import com.android.internal.telephony.TelephonyTest; +import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; +import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class SatelliteControllerTest extends TelephonyTest { + private static final String TAG = "SatelliteControllerTest"; + private static final long TIMEOUT = 500; + private static final int SUB_ID = 0; + private static final int MAX_BYTES_PER_OUT_GOING_DATAGRAM = 339; + + private TestSatelliteController mSatelliteControllerUT; + private TestSharedPreferences mSharedPreferences; + + @Mock private DatagramController mMockDatagramController; + @Mock private SatelliteModemInterface mMockSatelliteModemInterface; + @Mock private SatelliteSessionController mMockSatelliteSessionController; + @Mock private PointingAppController mMockPointingAppController; + @Mock private ControllerMetricsStats mMockControllerMetricsStats; + @Mock private ProvisionMetricsStats mMockProvisionMetricsStats; + + private int mIIntegerConsumerResult = 0; + private Semaphore mIIntegerConsumerSemaphore = new Semaphore(0); + private IIntegerConsumer mIIntegerConsumer = new IIntegerConsumer.Stub() { + @Override + public void accept(int result) { + logd("mIIntegerConsumer: result=" + result); + mIIntegerConsumerResult = result; + try { + mIIntegerConsumerSemaphore.release(); + } catch (Exception ex) { + loge("mIIntegerConsumer: Got exception in releasing semaphore, ex=" + ex); + } + } + }; + + private boolean mIsSatelliteSupported = true; + private boolean mIsSatelliteServiceSupported = true; + private boolean mIsPointingRequired = true; + private Set mSupportedRadioTechnologies = new HashSet<>(Arrays.asList( + NT_RADIO_TECHNOLOGY_NR_NTN, + NT_RADIO_TECHNOLOGY_EMTC_NTN, + NT_RADIO_TECHNOLOGY_PROPRIETARY)); + private SatelliteCapabilities mSatelliteCapabilities = new SatelliteCapabilities( + mSupportedRadioTechnologies, mIsPointingRequired, MAX_BYTES_PER_OUT_GOING_DATAGRAM, + new HashMap<>()); + + private boolean mQueriedSatelliteSupported = false; + private int mQueriedSatelliteSupportedResultCode = SATELLITE_ERROR_NONE; + private Semaphore mSatelliteSupportSemaphore = new Semaphore(0); + private ResultReceiver mSatelliteSupportReceiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + mQueriedSatelliteSupportedResultCode = resultCode; + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) { + mQueriedSatelliteSupported = resultData.getBoolean(KEY_SATELLITE_SUPPORTED); + } else { + loge("KEY_SATELLITE_SUPPORTED does not exist."); + mQueriedSatelliteSupported = false; + } + } else { + logd("mSatelliteSupportReceiver: resultCode=" + resultCode); + mQueriedSatelliteSupported = false; + } + try { + mSatelliteSupportSemaphore.release(); + } catch (Exception ex) { + loge("mSatelliteSupportReceiver: Got exception in releasing semaphore, ex=" + ex); + } + } + }; + + private boolean mQueriedIsSatelliteEnabled = false; + private int mQueriedIsSatelliteEnabledResultCode = SATELLITE_ERROR_NONE; + private Semaphore mIsSatelliteEnabledSemaphore = new Semaphore(0); + private ResultReceiver mIsSatelliteEnabledReceiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + mQueriedIsSatelliteEnabledResultCode = resultCode; + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_ENABLED)) { + mQueriedIsSatelliteEnabled = resultData.getBoolean(KEY_SATELLITE_ENABLED); + } else { + loge("KEY_SATELLITE_ENABLED does not exist."); + mQueriedIsSatelliteEnabled = false; + } + } else { + logd("mIsSatelliteEnableReceiver: resultCode=" + resultCode); + mQueriedIsSatelliteEnabled = false; + } + try { + mIsSatelliteEnabledSemaphore.release(); + } catch (Exception ex) { + loge("mIsSatelliteEnableReceiver: Got exception in releasing semaphore, ex=" + ex); + } + } + }; + + private boolean mQueriedIsSatelliteProvisioned = false; + private int mQueriedIsSatelliteProvisionedResultCode = SATELLITE_ERROR_NONE; + private Semaphore mIsSatelliteProvisionedSemaphore = new Semaphore(0); + private ResultReceiver mIsSatelliteProvisionedReceiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + mQueriedIsSatelliteProvisionedResultCode = resultCode; + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) { + mQueriedIsSatelliteProvisioned = + resultData.getBoolean(KEY_SATELLITE_PROVISIONED); + } else { + loge("KEY_SATELLITE_PROVISIONED does not exist."); + mQueriedIsSatelliteProvisioned = false; + } + } else { + mQueriedIsSatelliteProvisioned = false; + } + try { + mIsSatelliteProvisionedSemaphore.release(); + } catch (Exception ex) { + loge("mIsSatelliteProvisionedReceiver: Got exception in releasing semaphore ex=" + + ex); + } + } + }; + + @Before + public void setUp() throws Exception { + super.setUp(getClass().getSimpleName()); + MockitoAnnotations.initMocks(this); + logd(TAG + " Setup!"); + + replaceInstance(DatagramController.class, "sInstance", null, + mMockDatagramController); + replaceInstance(SatelliteModemInterface.class, "sInstance", null, + mMockSatelliteModemInterface); + replaceInstance(SatelliteSessionController.class, "sInstance", null, + mMockSatelliteSessionController); + replaceInstance(PointingAppController.class, "sInstance", null, + mMockPointingAppController); + replaceInstance(ControllerMetricsStats.class, "sInstance", null, + mMockControllerMetricsStats); + replaceInstance(ProvisionMetricsStats.class, "sInstance", null, + mMockProvisionMetricsStats); + + mSharedPreferences = new TestSharedPreferences(); + when(mContext.getSharedPreferences(anyString(), anyInt())).thenReturn(mSharedPreferences); + doReturn(mIsSatelliteServiceSupported) + .when(mMockSatelliteModemInterface).isSatelliteServiceSupported(); + setUpResponseForRequestSatelliteCapabilities( + mSatelliteCapabilities, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); + doNothing().when(mMockDatagramController).setDemoMode(anyBoolean()); + doNothing().when(mMockSatelliteSessionController) + .onSatelliteEnabledStateChanged(anyBoolean()); + doNothing().when(mMockSatelliteSessionController).setDemoMode(anyBoolean()); + + mSatelliteControllerUT = new TestSatelliteController(mContext, Looper.myLooper()); + verify(mMockSatelliteModemInterface).registerForSatelliteProvisionStateChanged( + any(Handler.class), + eq(26) /* EVENT_SATELLITE_PROVISION_STATE_CHANGED */, + eq(null)); + verify(mMockSatelliteModemInterface).registerForPendingDatagrams( + any(Handler.class), + eq(27) /* EVENT_PENDING_DATAGRAMS */, + eq(null)); + verify(mMockSatelliteModemInterface).registerForSatelliteModemStateChanged( + any(Handler.class), + eq(28) /* EVENT_SATELLITE_MODEM_STATE_CHANGED */, + eq(null)); + } + + @After + public void tearDown() throws Exception { + logd(TAG + " tearDown"); + mSatelliteControllerUT = null; + super.tearDown(); + } + + @Test + public void testRequestSatelliteEnabled() { + mIsSatelliteEnabledSemaphore.drainPermits(); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mIIntegerConsumerResult); + + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_NOT_SUPPORTED, mIIntegerConsumerResult); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, mIIntegerConsumerResult); + + sendProvisionedStateChangedEvent(true, null); + processAllMessages(); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + + mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false; + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + setRadioPower(false); + processAllMessages(); + verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + assertTrue(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled); + assertEquals( + SATELLITE_MODE_ENABLED_FALSE, mSatelliteControllerUT.satelliteModeSettingValue); + verify(mMockSatelliteSessionController, times(1)).onSatelliteEnabledStateChanged(eq(false)); + verify(mMockSatelliteSessionController, times(1)).setDemoMode(eq(false)); + verify(mMockDatagramController, times(1)).setDemoMode(eq(false)); + + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + // Radio is not on, can not enable satellite + assertEquals(SATELLITE_INVALID_MODEM_STATE, mIIntegerConsumerResult); + + setRadioPower(true); + processAllMessages(); + verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + + mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false; + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + assertTrue(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled); + assertEquals(SATELLITE_MODE_ENABLED_TRUE, mSatelliteControllerUT.satelliteModeSettingValue); + verify(mMockPointingAppController).startPointingUI(eq(false)); + verify(mMockSatelliteSessionController, times(1)).onSatelliteEnabledStateChanged(eq(true)); + verify(mMockSatelliteSessionController, times(2)).setDemoMode(eq(false)); + verify(mMockDatagramController, times(2)).setDemoMode(eq(false)); + + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, true, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_ARGUMENTS, mIIntegerConsumerResult); + verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, true, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + + setUpNoResponseForRequestSatelliteEnabled(true, false); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertFalse(waitForIIntegerConsumerResult(1)); + + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_REQUEST_IN_PROGRESS, mIIntegerConsumerResult); + + resetSatelliteControllerUTToOffAndProvisionedState(); + resetSatelliteControllerUTToSupportedAndProvisionedState(); + setUpNoResponseForRequestSatelliteEnabled(false, false); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); + processAllMessages(); + assertFalse(waitForIIntegerConsumerResult(1)); + + // Disabling is in progress. Thus, a new request to enable satellite will be rejected. + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR, mIIntegerConsumerResult); + } + + @Test + public void testOnSatelliteServiceConnected() { + verifySatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); + verifySatelliteEnabled(false, SATELLITE_INVALID_TELEPHONY_STATE); + verifySatelliteProvisioned(false, SATELLITE_INVALID_TELEPHONY_STATE); + + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + + mSatelliteControllerUT.onSatelliteServiceConnected(); + processAllMessages(); + + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + } + + private void resetSatelliteControllerUT() { + logd("resetSatelliteControllerUT"); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); + doReturn(true).when(mMockSatelliteModemInterface) + .setSatelliteServicePackageName(anyString()); + // Reset all cached states + mSatelliteControllerUT.setSatelliteServicePackageName("TestSatelliteService"); + processAllMessages(); + } + + private void resetSatelliteControllerUTToSupportedAndProvisionedState() { + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + sendProvisionedStateChangedEvent(true, null); + processAllMessages(); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + } + + private void resetSatelliteControllerUTToOffAndProvisionedState() { + resetSatelliteControllerUTToSupportedAndProvisionedState(); + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + } + + private void resetSatelliteControllerUTToOnAndProvisionedState() { + resetSatelliteControllerUTToOffAndProvisionedState(); + setRadioPower(true); + processAllMessages(); + + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + } + + private void setUpResponseForRequestIsSatelliteSupported( + boolean isSatelliteSupported, @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, isSatelliteSupported, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).requestIsSatelliteSupported(any(Message.class)); + } + + private void setUpResponseForRequestIsSatelliteProvisioned( + boolean isSatelliteProvisioned, @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + int[] provisioned = new int[] {isSatelliteProvisioned ? 1 : 0}; + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, provisioned, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).requestIsSatelliteProvisioned(any(Message.class)); + } + + private void setUpResponseForRequestSatelliteEnabled( + boolean enabled, boolean demoMode, @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[2]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface) + .requestSatelliteEnabled(eq(enabled), eq(demoMode), any(Message.class)); + } + + private void setUpNoResponseForRequestSatelliteEnabled(boolean enabled, boolean demoMode) { + doNothing().when(mMockSatelliteModemInterface) + .requestSatelliteEnabled(eq(enabled), eq(demoMode), any(Message.class)); + } + + private void setUpResponseForRequestSatelliteCapabilities( + SatelliteCapabilities satelliteCapabilities, + @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, satelliteCapabilities, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).requestSatelliteCapabilities(any(Message.class)); + } + + private boolean waitForRequestIsSatelliteSupportedResult(int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mSatelliteSupportSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + loge("Timeout to receive requestIsSatelliteSupported() callback"); + return false; + } + } catch (Exception ex) { + loge("waitForRequestIsSatelliteSupportedResult: Got exception=" + ex); + return false; + } + } + return true; + } + + private boolean waitForRequestIsSatelliteEnabledResult(int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mIsSatelliteEnabledSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + loge("Timeout to receive requestIsSatelliteEnabled() callback"); + return false; + } + } catch (Exception ex) { + loge("waitForRequestIsSatelliteEnabledResult: Got exception=" + ex); + return false; + } + } + return true; + } + + private boolean waitForRequestIsSatelliteProvisionedResult(int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mIsSatelliteProvisionedSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + loge("Timeout to receive requestIsSatelliteProvisioned() callback"); + return false; + } + } catch (Exception ex) { + loge("waitForRequestIsSatelliteProvisionedResult: Got exception=" + ex); + return false; + } + } + return true; + } + + private boolean waitForIIntegerConsumerResult(int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mIIntegerConsumerSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + loge("Timeout to receive IIntegerConsumer() callback"); + return false; + } + } catch (Exception ex) { + loge("waitForIIntegerConsumerResult: Got exception=" + ex); + return false; + } + } + return true; + } + + private void verifySatelliteSupported(boolean supported, int expectedErrorCode) { + mSatelliteSupportSemaphore.drainPermits(); + mSatelliteControllerUT.requestIsSatelliteSupported(SUB_ID, mSatelliteSupportReceiver); + processAllMessages(); + assertTrue(waitForRequestIsSatelliteSupportedResult(1)); + assertEquals(expectedErrorCode, mQueriedSatelliteSupportedResultCode); + assertEquals(supported, mQueriedSatelliteSupported); + } + + private void verifySatelliteEnabled(boolean enabled, int expectedErrorCode) { + mIsSatelliteEnabledSemaphore.drainPermits(); + mSatelliteControllerUT.requestIsSatelliteEnabled(SUB_ID, mIsSatelliteEnabledReceiver); + processAllMessages(); + assertTrue(waitForRequestIsSatelliteEnabledResult(1)); + assertEquals(expectedErrorCode, mQueriedIsSatelliteEnabledResultCode); + assertEquals(enabled, mQueriedIsSatelliteEnabled); + } + + private void verifySatelliteProvisioned(boolean provisioned, int expectedErrorCode) { + mIsSatelliteProvisionedSemaphore.drainPermits(); + mSatelliteControllerUT.requestIsSatelliteProvisioned( + SUB_ID, mIsSatelliteProvisionedReceiver); + processAllMessages(); + assertTrue(waitForRequestIsSatelliteProvisionedResult(1)); + assertEquals(expectedErrorCode, mQueriedIsSatelliteProvisionedResultCode); + assertEquals(provisioned, mQueriedIsSatelliteProvisioned); + } + + private void sendProvisionedStateChangedEvent(boolean provisioned, Throwable exception) { + Message msg = mSatelliteControllerUT.obtainMessage( + 26 /* EVENT_SATELLITE_PROVISION_STATE_CHANGED */); + msg.obj = new AsyncResult(null, provisioned, exception); + msg.sendToTarget(); + } + + private void setRadioPower(boolean on) { + mSimulatedCommands.setRadioPower(on, false, false, null); + } + + private static void loge(String message) { + Rlog.e(TAG, message); + } + + private static class TestSharedPreferences + implements SharedPreferences, SharedPreferences.Editor { + private HashMap mValues = new HashMap(); + + public int getValueCount() { + return mValues.size(); + } + + @Override + public Editor edit() { + return this; + } + + @Override + public boolean contains(String key) { + return mValues.containsKey(key); + } + + @Override + public Map getAll() { + return new HashMap(mValues); + } + + @Override + public boolean getBoolean(String key, boolean defValue) { + if (mValues.containsKey(key)) { + return ((Boolean) mValues.get(key)).booleanValue(); + } + return defValue; + } + + @Override + public float getFloat(String key, float defValue) { + if (mValues.containsKey(key)) { + return ((Float) mValues.get(key)).floatValue(); + } + return defValue; + } + + @Override + public int getInt(String key, int defValue) { + if (mValues.containsKey(key)) { + return ((Integer) mValues.get(key)).intValue(); + } + return defValue; + } + + @Override + public long getLong(String key, long defValue) { + if (mValues.containsKey(key)) { + return ((Long) mValues.get(key)).longValue(); + } + return defValue; + } + + @Override + public String getString(String key, String defValue) { + if (mValues.containsKey(key)) return (String) mValues.get(key); + else return defValue; + } + + @SuppressWarnings("unchecked") + @Override + public Set getStringSet(String key, Set defValues) { + if (mValues.containsKey(key)) { + return (Set) mValues.get(key); + } + return defValues; + } + + @Override + public void registerOnSharedPreferenceChangeListener( + OnSharedPreferenceChangeListener listener) { + throw new UnsupportedOperationException(); + } + + @Override + public void unregisterOnSharedPreferenceChangeListener( + OnSharedPreferenceChangeListener listener) { + throw new UnsupportedOperationException(); + } + + @Override + public Editor putBoolean(String key, boolean value) { + mValues.put(key, Boolean.valueOf(value)); + return this; + } + + @Override + public Editor putFloat(String key, float value) { + mValues.put(key, value); + return this; + } + + @Override + public Editor putInt(String key, int value) { + mValues.put(key, value); + return this; + } + + @Override + public Editor putLong(String key, long value) { + mValues.put(key, value); + return this; + } + + @Override + public Editor putString(String key, String value) { + mValues.put(key, value); + return this; + } + + @Override + public Editor putStringSet(String key, Set values) { + mValues.put(key, values); + return this; + } + + @Override + public Editor remove(String key) { + mValues.remove(key); + return this; + } + + @Override + public Editor clear() { + mValues.clear(); + return this; + } + + @Override + public boolean commit() { + return true; + } + + @Override + public void apply() { + commit(); + } + } + + private static class TestSatelliteController extends SatelliteController { + public boolean setSettingsKeyForSatelliteModeCalled = false; + public boolean allRadiosDisabled = true; + public int satelliteModeSettingValue = SATELLITE_MODE_ENABLED_FALSE; + + TestSatelliteController(Context context, Looper looper) { + super(context, looper); + logd("Constructing TestSatelliteController"); + } + + @Override + protected void initializeSatelliteModeRadios() { + logd("initializeSatelliteModeRadios"); + } + + @Override + protected void setSettingsKeyForSatelliteMode(int val) { + logd("setSettingsKeyForSatelliteMode: val=" + val); + satelliteModeSettingValue = val; + setSettingsKeyForSatelliteModeCalled = true; + } + + @Override + protected boolean areAllRadiosDisabled() { + return allRadiosDisabled; + } + } +} -- GitLab From 00b0a8d0933663c152dfa4b0a96ff12bff2f359b Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Tue, 11 Apr 2023 19:17:41 +0000 Subject: [PATCH 637/656] Do not send and receive datagrams at the same time. The following changes are made in this CL: - DatagramDispatcher: -- send datagram only if modem is not receiving datagrams. - DatagramReceiver: -- Poll for pending datagrams only if modem is not sending datagrams. Bug: 275670811 Test: atest com.android.internal.telephony.satellite atest CtsTelephonyTestCases:android.telephony.satellite.cts Flashed build on raven-userdebug: calls and sms are working Change-Id: I6fcf6709453daa75b69731fb19decd6fe90f4c6d --- .../satellite/DatagramController.java | 97 +++++++++++++------ .../satellite/DatagramDispatcher.java | 68 ++++++++----- .../telephony/satellite/DatagramReceiver.java | 56 +++++++---- .../satellite/DatagramDispatcherTest.java | 19 ++++ .../satellite/DatagramReceiverTest.java | 22 ++++- 5 files changed, 191 insertions(+), 71 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 2e6f9a3590..d3516be53d 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -26,6 +26,7 @@ import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.concurrent.TimeUnit; @@ -49,17 +50,27 @@ public class DatagramController { private static final boolean DEBUG = !"user".equals(Build.TYPE); /** Variables used to update onSendDatagramStateChanged(). */ + private final Object mLock = new Object(); + @GuardedBy("mLock") private int mSendSubId; - private int mSendDatagramTransferState = - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN; + @GuardedBy("mLock") + private @SatelliteManager.SatelliteDatagramTransferState int mSendDatagramTransferState = + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; + @GuardedBy("mLock") private int mSendPendingCount = 0; + @GuardedBy("mLock") private int mSendErrorCode = SatelliteManager.SATELLITE_ERROR_NONE; /** Variables used to update onReceiveDatagramStateChanged(). */ + @GuardedBy("mLock") private int mReceiveSubId; - private int mReceiveDatagramTransferState = - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN; + @GuardedBy("mLock") + private @SatelliteManager.SatelliteDatagramTransferState int mReceiveDatagramTransferState = + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; + @GuardedBy("mLock") private int mReceivePendingCount = 0; + @GuardedBy("mLock") private int mReceiveErrorCode = SatelliteManager.SATELLITE_ERROR_NONE; + private SatelliteDatagram mDemoModeDatagram; private boolean mIsDemoMode = false; private long mAlignTimeoutDuration = SATELLITE_ALIGN_TIMEOUT; @@ -192,18 +203,21 @@ public class DatagramController { public void updateSendStatus(int subId, @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, int sendPendingCount, int errorCode) { - logd("updateSendStatus" - + " subId: " + subId - + " datagramTransferState: " + datagramTransferState - + " sendPendingCount: " + sendPendingCount + " errorCode: " + errorCode); - - mSendSubId = subId; - mSendDatagramTransferState = datagramTransferState; - mSendPendingCount = sendPendingCount; - mSendErrorCode = errorCode; - notifyDatagramTransferStateChangedToSessionController(); - mPointingAppController.updateSendDatagramTransferState(subId, datagramTransferState, - sendPendingCount, errorCode); + synchronized (mLock) { + logd("updateSendStatus" + + " subId: " + subId + + " datagramTransferState: " + datagramTransferState + + " sendPendingCount: " + sendPendingCount + " errorCode: " + errorCode); + + mSendSubId = subId; + mSendDatagramTransferState = datagramTransferState; + mSendPendingCount = sendPendingCount; + mSendErrorCode = errorCode; + + notifyDatagramTransferStateChangedToSessionController(); + mPointingAppController.updateSendDatagramTransferState(mSendSubId, + mSendDatagramTransferState, mSendPendingCount, mSendErrorCode); + } } /** @@ -217,18 +231,25 @@ public class DatagramController { public void updateReceiveStatus(int subId, @SatelliteManager.SatelliteDatagramTransferState int datagramTransferState, int receivePendingCount, int errorCode) { - logd("updateReceiveStatus" - + " subId: " + subId - + " datagramTransferState: " + datagramTransferState - + " receivePendingCount: " + receivePendingCount + " errorCode: " + errorCode); - - mReceiveSubId = subId; - mReceiveDatagramTransferState = datagramTransferState; - mReceivePendingCount = receivePendingCount; - mReceiveErrorCode = errorCode; - notifyDatagramTransferStateChangedToSessionController(); - mPointingAppController.updateReceiveDatagramTransferState(subId, datagramTransferState, - receivePendingCount, errorCode); + synchronized (mLock) { + logd("updateReceiveStatus" + + " subId: " + subId + + " datagramTransferState: " + datagramTransferState + + " receivePendingCount: " + receivePendingCount + " errorCode: " + errorCode); + + mReceiveSubId = subId; + mReceiveDatagramTransferState = datagramTransferState; + mReceivePendingCount = receivePendingCount; + mReceiveErrorCode = errorCode; + + notifyDatagramTransferStateChangedToSessionController(); + mPointingAppController.updateReceiveDatagramTransferState(mReceiveSubId, + mReceiveDatagramTransferState, mReceivePendingCount, mReceiveErrorCode); + } + + if (isPollingInIdleState()) { + mDatagramDispatcher.retrySendingDatagrams(); + } } /** @@ -256,8 +277,24 @@ public class DatagramController { } boolean isReceivingDatagrams() { - return (mReceiveDatagramTransferState - == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + synchronized (mLock) { + return (mReceiveDatagramTransferState + == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); + } + } + + public boolean isSendingInIdleState() { + synchronized (mLock) { + return mSendDatagramTransferState == + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; + } + } + + public boolean isPollingInIdleState() { + synchronized (mLock) { + return mReceiveDatagramTransferState == + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE; + } } /** diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java index 63731e2aa3..77b410db3d 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java @@ -343,13 +343,15 @@ public class DatagramDispatcher extends Handler { needFullScreenPointingUI, callback); synchronized (mLock) { + // Add datagram to pending datagram map if (datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE) { mPendingEmergencyDatagramsMap.put(datagramId, datagramArgs); } else { mPendingNonEmergencyDatagramsMap.put(datagramId, datagramArgs); } - if (!mSendingDatagramInProgress) { + // Modem can be busy receiving datagrams, so send datagram only when modem is not busy. + if (!mSendingDatagramInProgress && mDatagramController.isPollingInIdleState()) { mSendingDatagramInProgress = true; datagramArgs.setDatagramStartTime(); mDatagramController.updateSendStatus(subId, @@ -360,6 +362,12 @@ public class DatagramDispatcher extends Handler { } } + public void retrySendingDatagrams() { + synchronized (mLock) { + sendPendingDatagrams(); + } + } + /** Set demo mode * * @param isDemoMode {@code true} means demo mode is on, {@code false} otherwise. @@ -439,6 +447,17 @@ public class DatagramDispatcher extends Handler { @GuardedBy("mLock") private void sendPendingDatagrams() { logd("sendPendingDatagrams()"); + if (!mDatagramController.isPollingInIdleState()) { + // Datagram should be sent to satellite modem when modem is free. + logd("sendPendingDatagrams: modem is receiving datagrams"); + return; + } + + if (getPendingDatagramCount() <= 0) { + logd("sendPendingDatagrams: no pending datagrams to send"); + return; + } + Phone phone = SatelliteServiceUtils.getPhone(); Set> pendingDatagram = null; if (!mSendingDatagramInProgress && !mPendingEmergencyDatagramsMap.isEmpty()) { @@ -552,33 +571,36 @@ public class DatagramDispatcher extends Handler { * @param state Current satellite modem state. */ public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { - if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF - || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { - logd("onSatelliteModemStateChanged: cleaning up resources"); - cleanUpResources(); + synchronized (mLock) { + if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF + || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { + logd("onSatelliteModemStateChanged: cleaning up resources"); + cleanUpResources(); + } else if (state == SatelliteManager.SATELLITE_MODEM_STATE_IDLE) { + sendPendingDatagrams(); + } } } + @GuardedBy("mLock") private void cleanUpResources() { - synchronized (mLock) { - mSendingDatagramInProgress = false; - if (getPendingDatagramCount() > 0) { - mDatagramController.updateSendStatus( - SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, - getPendingDatagramCount(), SatelliteManager.SATELLITE_REQUEST_ABORTED); - } - mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, - 0, SatelliteManager.SATELLITE_ERROR_NONE); - abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - SatelliteManager.SATELLITE_REQUEST_ABORTED); - - stopSatelliteAlignedTimer(); - mIsDemoMode = false; - mSendSatelliteDatagramRequest = null; - mIsAligned = false; + mSendingDatagramInProgress = false; + if (getPendingDatagramCount() > 0) { + mDatagramController.updateSendStatus( + SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED, + getPendingDatagramCount(), SatelliteManager.SATELLITE_REQUEST_ABORTED); } + mDatagramController.updateSendStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, + 0, SatelliteManager.SATELLITE_ERROR_NONE); + abortSendingPendingDatagrams(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_REQUEST_ABORTED); + + stopSatelliteAlignedTimer(); + mIsDemoMode = false; + mSendSatelliteDatagramRequest = null; + mIsAligned = false; } private static void logd(@NonNull String log) { diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 1ae771c2e6..20afdfb0ee 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -42,6 +42,7 @@ import android.telephony.satellite.SatelliteManager; import android.util.Pair; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.IVoidConsumer; @@ -79,6 +80,7 @@ public class DatagramReceiver extends Handler { private long mDatagramTransferStartTime = 0; private boolean mIsDemoMode = false; + @GuardedBy("mLock") private boolean mIsAligned = false; private DatagramReceiverHandlerRequest mPollPendingSatelliteDatagramsRequest = null; private final Object mLock = new Object(); @@ -97,7 +99,6 @@ public class DatagramReceiver extends Handler { private final ConcurrentHashMap mPendingAckCountHashMap = new ConcurrentHashMap<>(); - /** * Create the DatagramReceiver singleton instance. * @param context The Context to use to create the DatagramReceiver. @@ -331,7 +332,7 @@ public class DatagramReceiver extends Handler { logd("Received EVENT_SATELLITE_DATAGRAM_RECEIVED for subId=" + mSubId + " pendingCount:" + pendingCount); - if (pendingCount == 0 && satelliteDatagram == null) { + if (pendingCount <= 0 && satelliteDatagram == null) { sInstance.mDatagramController.updateReceiveStatus(mSubId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE, pendingCount, SatelliteManager.SATELLITE_ERROR_NONE); @@ -372,7 +373,7 @@ public class DatagramReceiver extends Handler { }; Consumer callback = FunctionalUtils.ignoreRemoteException( internalCallback::accept); - sInstance.pollPendingSatelliteDatagrams(mSubId, callback); + sInstance.pollPendingSatelliteDatagramsInternal(mSubId, callback); } // Send the captured data about incoming datagram to metric @@ -583,6 +584,25 @@ public class DatagramReceiver extends Handler { * @param callback The callback to get {@link SatelliteManager.SatelliteError} of the request. */ public void pollPendingSatelliteDatagrams(int subId, @NonNull Consumer callback) { + if (!mDatagramController.isPollingInIdleState()) { + // Poll request should be sent to satellite modem only when it is free. + logd("pollPendingSatelliteDatagrams: satellite modem is busy receiving datagrams."); + callback.accept(SatelliteManager.SATELLITE_MODEM_BUSY); + return; + } + + pollPendingSatelliteDatagramsInternal(subId, callback); + } + + private void pollPendingSatelliteDatagramsInternal(int subId, + @NonNull Consumer callback) { + if (!mDatagramController.isSendingInIdleState()) { + // Poll request should be sent to satellite modem only when it is free. + logd("pollPendingSatelliteDatagrams: satellite modem is busy sending datagrams."); + callback.accept(SatelliteManager.SATELLITE_MODEM_BUSY); + return; + } + mDatagramController.updateReceiveStatus(subId, SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING, mDatagramController.getReceivePendingCount(), @@ -615,13 +635,16 @@ public class DatagramReceiver extends Handler { * @param state Current satellite modem state. */ public void onSatelliteModemStateChanged(@SatelliteManager.SatelliteModemState int state) { - if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF - || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { - logd("onSatelliteModemStateChanged: cleaning up resources"); - cleanUpResources(); + synchronized (mLock) { + if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF + || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { + logd("onSatelliteModemStateChanged: cleaning up resources"); + cleanUpResources(); + } } } + @GuardedBy("mLock") private void cleanupDemoModeResources() { if (isSatelliteAlignedTimerStarted()) { stopSatelliteAlignedTimer(); @@ -639,19 +662,18 @@ public class DatagramReceiver extends Handler { mIsAligned = false; } + @GuardedBy("mLock") private void cleanUpResources() { - synchronized (mLock) { - if (mDatagramController.isReceivingDatagrams()) { - mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, - mDatagramController.getReceivePendingCount(), - SatelliteManager.SATELLITE_REQUEST_ABORTED); - } + if (mDatagramController.isReceivingDatagrams()) { mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, - SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0, - SatelliteManager.SATELLITE_ERROR_NONE); - cleanupDemoModeResources(); + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED, + mDatagramController.getReceivePendingCount(), + SatelliteManager.SATELLITE_REQUEST_ABORTED); } + mDatagramController.updateReceiveStatus(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE, 0, + SatelliteManager.SATELLITE_ERROR_NONE); + cleanupDemoModeResources(); } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java index a86eb6466d..bf02bb0182 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.Context; @@ -101,6 +102,7 @@ public class DatagramDispatcherTest extends TelephonyTest { mResultListener = new LinkedBlockingQueue<>(1); mDatagram = new SatelliteDatagram(TEST_MESSAGE.getBytes()); mInOrder = inOrder(mMockDatagramController); + when(mMockDatagramController.isPollingInIdleState()).thenReturn(true); } @After @@ -133,6 +135,7 @@ public class DatagramDispatcherTest extends TelephonyTest { processAllMessages(); + mInOrder.verify(mMockDatagramController).isPollingInIdleState(); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), @@ -170,6 +173,7 @@ public class DatagramDispatcherTest extends TelephonyTest { processAllMessages(); + mInOrder.verify(mMockDatagramController).isPollingInIdleState(); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), @@ -197,6 +201,7 @@ public class DatagramDispatcherTest extends TelephonyTest { processAllMessages(); + mInOrder.verify(mMockDatagramController).isPollingInIdleState(); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), @@ -234,6 +239,7 @@ public class DatagramDispatcherTest extends TelephonyTest { processAllMessages(); + mInOrder.verify(mMockDatagramController).isPollingInIdleState(); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), @@ -272,6 +278,7 @@ public class DatagramDispatcherTest extends TelephonyTest { processAllMessages(); + mInOrder.verify(mMockDatagramController).isPollingInIdleState(); mInOrder.verify(mMockDatagramController) .updateSendStatus(eq(SUB_ID), eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SENDING), eq(1), @@ -409,6 +416,18 @@ public class DatagramDispatcherTest extends TelephonyTest { mTestDemoModeDatagramDispatcher.onDeviceAlignedWithSatellite(false); } + @Test + public void testSatelliteModemBusy_modemPollingDatagram_sendingDelayed() { + when(mMockDatagramController.isPollingInIdleState()).thenReturn(false); + + mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + true, mResultListener::offer); + processAllMessages(); + // As modem is busy receiving datagrams, sending datagram did not proceed further. + mInOrder.verify(mMockDatagramController).isPollingInIdleState(); + verifyNoMoreInteractions(mMockDatagramController); + } + private static class TestDatagramDispatcher extends DatagramDispatcher { private long mLong = SATELLITE_ALIGN_TIMEOUT; diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java index f6239c4c87..709764610a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java @@ -38,7 +38,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; - import android.os.AsyncResult; import android.os.Looper; import android.os.Message; @@ -116,6 +115,8 @@ public class DatagramReceiverTest extends TelephonyTest { mDatagram = new SatelliteDatagram(TEST_MESSAGE.getBytes()); mInOrder = inOrder(mMockDatagramController); + when(mMockDatagramController.isSendingInIdleState()).thenReturn(true); + when(mMockDatagramController.isPollingInIdleState()).thenReturn(true); processAllMessages(); } @@ -386,6 +387,25 @@ public class DatagramReceiverTest extends TelephonyTest { mTestDemoModeDatagramReceiver.setDuration(previousTimer); } + @Test + public void testSatelliteModemBusy_modemSendingDatagram_pollingFailure() { + when(mMockDatagramController.isSendingInIdleState()).thenReturn(false); + + mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); + processAllMessages(); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_MODEM_BUSY); + } + + @Test + public void testSatelliteModemBusy_modemPollingDatagrams_pollingFailure() { + when(mMockDatagramController.isSendingInIdleState()).thenReturn(false); + when(mMockDatagramController.isPollingInIdleState()).thenReturn(true); + + mDatagramReceiverUT.pollPendingSatelliteDatagrams(SUB_ID, mResultListener::offer); + processAllMessages(); + assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_MODEM_BUSY); + } + private static class TestDatagramReceiver extends DatagramReceiver { private long mLong = SATELLITE_ALIGN_TIMEOUT; -- GitLab From f8a38f6f601a3539c72dc3ca90b457b4a6595385 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 4 May 2023 18:29:03 +0000 Subject: [PATCH 638/656] Revert "Enhance IMS/RCS graceful tear down" This reverts commit 46de4f8d19330daa0a3ee81e0ec71a7477f06529. Reason for revert: The APM+wifi on is punt on UDC. Reverting this CL because it caused other side effect b/278496217, b/277168789, and b/276837807. Change-Id: I782ef4df3c0629106b3a344026d2c17bf5e2bb03 --- .../telephony/data/DataNetworkController.java | 83 +++++++------------ .../data/DataNetworkControllerTest.java | 66 +++++---------- 2 files changed, 52 insertions(+), 97 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index b18ba3323b..ddd90c441e 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -77,7 +77,6 @@ import android.util.IndentingPrintWriter; import android.util.LocalLog; import android.util.SparseArray; import android.util.SparseBooleanArray; -import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.Phone; @@ -326,11 +325,8 @@ public class DataNetworkController extends Handler { */ private final @NonNull SparseArray mImsStateCallbacks = new SparseArray<>(); - /** - * The transport on which IMS features are registered. Key is the IMS feature, value is the - * transport. Unregistered IMS features are removed from the set. - */ - private final @NonNull SparseIntArray mRegisteredImsFeaturesTransport = new SparseIntArray(2); + /** Registered IMS features. Unregistered IMS features are removed from the set. */ + private final @NonNull Set mRegisteredImsFeatures = new ArraySet<>(); /** IMS feature package names. Key is the IMS feature, value is the package name. */ private final @NonNull SparseArray mImsFeaturePackageName = new SparseArray<>(); @@ -2195,18 +2191,17 @@ public class DataNetworkController extends Handler { RegistrationManager.RegistrationCallback callback = new RegistrationManager.RegistrationCallback() { @Override - public void onRegistered(@NonNull ImsRegistrationAttributes attributes) { + public void onRegistered(ImsRegistrationAttributes attributes) { log("IMS " + DataUtils.imsFeatureToString(imsFeature) + " registered. Attributes=" + attributes); - mRegisteredImsFeaturesTransport.put( - imsFeature, attributes.getTransportType()); + mRegisteredImsFeatures.add(imsFeature); } @Override public void onUnregistered(ImsReasonInfo info) { log("IMS " + DataUtils.imsFeatureToString(imsFeature) + " deregistered. Info=" + info); - mRegisteredImsFeaturesTransport.delete(imsFeature); + mRegisteredImsFeatures.remove(imsFeature); evaluatePendingImsDeregDataNetworks(); } }; @@ -2891,16 +2886,6 @@ public class DataNetworkController extends Handler { mImsDataNetworkState = TelephonyManager.DATA_DISCONNECTED; } - if (!mPendingTearDownAllNetworks) { - // Immediately reestablish on target transport if network was torn down due to policy - long delayMillis = tearDownReason == DataNetwork.TEAR_DOWN_REASON_HANDOVER_NOT_ALLOWED - ? 0 : mDataConfigManager.getRetrySetupAfterDisconnectMillis(); - // Sometimes network was unsolicitedly reported lost for reasons. We should re-evaluate - // and see if data network can be re-established again. - sendMessageDelayed(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, - DataEvaluationReason.RETRY_AFTER_DISCONNECTED), delayMillis); - } - if (mAnyDataNetworkExisting && mDataNetworkList.isEmpty()) { log("All data networks disconnected now."); mPendingTearDownAllNetworks = false; @@ -2908,6 +2893,14 @@ public class DataNetworkController extends Handler { mDataNetworkControllerCallbacks.forEach(callback -> callback.invokeFromExecutor( () -> callback.onAnyDataNetworkExistingChanged(mAnyDataNetworkExisting))); } + + // Immediately reestablish on target transport if network was torn down due to policy + long delayMillis = tearDownReason == DataNetwork.TEAR_DOWN_REASON_HANDOVER_NOT_ALLOWED + ? 0 : mDataConfigManager.getRetrySetupAfterDisconnectMillis(); + // Sometimes network was unsolicitedly reported lost for reasons. We should re-evaluate + // and see if data network can be re-established again. + sendMessageDelayed(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, + DataEvaluationReason.RETRY_AFTER_DISCONNECTED), delayMillis); } /** @@ -3627,23 +3620,22 @@ public class DataNetworkController extends Handler { } /** - * Check if the data network is safe to tear down at this moment. A network is considered safe - * to tear down if No IMS/RCS registration is relying on it. We infer a network is Not safe to - * tear down if 1) the network is on the transport where the IMS/RCS feature registration - * took place, and 2) the network has requests originated from the IMS/RCS service. + * Check if the data network is safe to tear down at this moment. * * @param dataNetwork The data network. - * @return {@code true} if the data network is safe to tear down; {@code false} otherwise. + * @return {@code true} if the data network is safe to tear down. {@code false} indicates this + * data network has requests originated from the IMS/RCS service and IMS/RCS is not + * de-registered yet. */ private boolean isSafeToTearDown(@NonNull DataNetwork dataNetwork) { for (int imsFeature : SUPPORTED_IMS_FEATURES) { - int registeredOnTransport = mRegisteredImsFeaturesTransport.get(imsFeature, - AccessNetworkConstants.TRANSPORT_TYPE_INVALID); - if (dataNetwork.getTransport() == registeredOnTransport) { - String imsFeaturePackage = mImsFeaturePackageName.get(imsFeature); - if (imsFeaturePackage != null && dataNetwork.getAttachedNetworkRequestList() + String imsFeaturePackage = mImsFeaturePackageName.get(imsFeature); + if (imsFeaturePackage != null) { + if (dataNetwork.getAttachedNetworkRequestList() .hasNetworkRequestsFromPackage(imsFeaturePackage)) { - return false; + if (mRegisteredImsFeatures.contains(imsFeature)) { + return false; + } } } } @@ -3667,19 +3659,13 @@ public class DataNetworkController extends Handler { private void tearDownGracefully(@NonNull DataNetwork dataNetwork, @TearDownReason int reason) { long deregDelay = mDataConfigManager.getImsDeregistrationDelay(); if (isImsGracefulTearDownSupported() && !isSafeToTearDown(dataNetwork)) { - int mmtelTransport = mRegisteredImsFeaturesTransport.get(ImsFeature.FEATURE_MMTEL, - AccessNetworkConstants.TRANSPORT_TYPE_INVALID); - int rcsTransport = mRegisteredImsFeaturesTransport.get(ImsFeature.FEATURE_RCS, - AccessNetworkConstants.TRANSPORT_TYPE_INVALID); log("tearDownGracefully: Not safe to tear down " + dataNetwork + " at this point. Wait for IMS de-registration or timeout. MMTEL=" - + (mmtelTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID - ? "registered on " + AccessNetworkConstants.transportTypeToString( - mmtelTransport) : "not registered") + + (mRegisteredImsFeatures.contains(ImsFeature.FEATURE_MMTEL) + ? "registered" : "not registered") + ", RCS=" - + (rcsTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID - ? "registered on " + AccessNetworkConstants.transportTypeToString( - rcsTransport) : "not registered") + + (mRegisteredImsFeatures.contains(ImsFeature.FEATURE_RCS) + ? "registered" : "not registered") ); Runnable runnable = dataNetwork.tearDownWhenConditionMet(reason, deregDelay); if (runnable != null) { @@ -3792,18 +3778,13 @@ public class DataNetworkController extends Handler { pw.println(networkRequest); } pw.decreaseIndent(); - int mmtelTransport = mRegisteredImsFeaturesTransport.get(ImsFeature.FEATURE_MMTEL, - AccessNetworkConstants.TRANSPORT_TYPE_INVALID); - int rcsTransport = mRegisteredImsFeaturesTransport.get(ImsFeature.FEATURE_RCS, - AccessNetworkConstants.TRANSPORT_TYPE_INVALID); + pw.println("IMS features registration state: MMTEL=" - + (mmtelTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID - ? "registered on " + AccessNetworkConstants.transportTypeToString( - mmtelTransport) : "not registered") + + (mRegisteredImsFeatures.contains(ImsFeature.FEATURE_MMTEL) + ? "registered" : "not registered") + ", RCS=" - + (rcsTransport != AccessNetworkConstants.TRANSPORT_TYPE_INVALID - ? "registered on " + AccessNetworkConstants.transportTypeToString( - rcsTransport) : "not registered")); + + (mRegisteredImsFeatures.contains(ImsFeature.FEATURE_RCS) + ? "registered" : "not registered")); pw.println("mServiceState=" + mServiceState); pw.println("mPsRestricted=" + mPsRestricted); pw.println("mAnyDataNetworkExisting=" + mAnyDataNetworkExisting); 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 0dded1247a..de1056392f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -480,14 +480,13 @@ public class DataNetworkControllerTest extends TelephonyTest { processAllMessages(); } - private void setImsRegistered(boolean registered, - @ImsRegistrationImplBase.ImsRegistrationTech int regTech) { + private void setImsRegistered(boolean registered) { if (registered) { final ArraySet features = new ArraySet<>(); features.add("feature1"); features.add("feature2"); - ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(regTech) - .setFeatureTags(features).build(); + ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder( + ImsRegistrationImplBase.REGISTRATION_TECH_LTE).setFeatureTags(features).build(); mMmtelRegCallback.onRegistered(attr); } else { @@ -496,14 +495,13 @@ public class DataNetworkControllerTest extends TelephonyTest { } } - private void setRcsRegistered(boolean registered, - @ImsRegistrationImplBase.ImsRegistrationTech int regTech) { + private void setRcsRegistered(boolean registered) { if (registered) { final ArraySet features = new ArraySet<>(); features.add("feature1"); features.add("feature2"); - ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder(regTech) - .setFeatureTags(features).build(); + ImsRegistrationAttributes attr = new ImsRegistrationAttributes.Builder( + ImsRegistrationImplBase.REGISTRATION_TECH_LTE).setFeatureTags(features).build(); mRcsRegCallback.onRegistered(attr); } else { @@ -3461,14 +3459,9 @@ public class DataNetworkControllerTest extends TelephonyTest { @Test public void testImsGracefulTearDown() throws Exception { - setImsRegistered(true, ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); - setRcsRegistered(true, ImsRegistrationImplBase.REGISTRATION_TECH_LTE); + setImsRegistered(true); + setRcsRegistered(true); - // IMS preferred on Wifi - updateTransport(NetworkCapabilities.NET_CAPABILITY_IMS, - AccessNetworkConstants.TRANSPORT_TYPE_WLAN); - - // IMS service requests an IMS network, expects the network on IWLAN. NetworkCapabilities netCaps = new NetworkCapabilities(); netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); netCaps.setRequestorPackageName(FAKE_MMTEL_PACKAGE); @@ -3478,53 +3471,34 @@ public class DataNetworkControllerTest extends TelephonyTest { TelephonyNetworkRequest networkRequest = new TelephonyNetworkRequest( nativeNetworkRequest, mPhone); - mDataNetworkControllerUT.addNetworkRequest(networkRequest); - setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 2/*cid*/); - - // IMS service requests an internet network, expects the network on WWAN. - netCaps = new NetworkCapabilities(); - netCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - netCaps.setRequestorPackageName(FAKE_MMTEL_PACKAGE); - - nativeNetworkRequest = new NetworkRequest(netCaps, - ConnectivityManager.TYPE_MOBILE, ++mNetworkRequestId, NetworkRequest.Type.REQUEST); - networkRequest = new TelephonyNetworkRequest( - nativeNetworkRequest, mPhone); - mDataNetworkControllerUT.addNetworkRequest(networkRequest); processAllMessages(); Mockito.clearInvocations(mPhone); - List networks = getDataNetworks(); - assertEquals(2, networks.size()); - - // Turn on APM mode. - mDataNetworkControllerUT.onTearDownAllDataNetworks(DataNetwork - .TEAR_DOWN_REASON_AIRPLANE_MODE_ON); + // SIM removal + mDataNetworkControllerUT.obtainMessage(9/*EVENT_SIM_STATE_CHANGED*/, + TelephonyManager.SIM_STATE_ABSENT, 0).sendToTarget(); processAllMessages(); - // Expect the network on WWAN immediately disconnected because IMS registration is on IWLAN. - assertEquals(1, networks.size()); - DataNetwork network = networks.get(0); - // Expect the network on IWLAN enters disconnecting state as part of waiting for dereg. - assertTrue(network.getNetworkCapabilities().hasCapability(NetworkCapabilities - .NET_CAPABILITY_IMS)); - assertTrue(network.isDisconnecting()); + // Make sure data network enters disconnecting state + ArgumentCaptor pdcsCaptor = + ArgumentCaptor.forClass(PreciseDataConnectionState.class); + verify(mPhone).notifyDataConnection(pdcsCaptor.capture()); + PreciseDataConnectionState pdcs = pdcsCaptor.getValue(); + assertThat(pdcs.getState()).isEqualTo(TelephonyManager.DATA_DISCONNECTING); // IMS de-registered. Now data network is safe to be torn down. Mockito.clearInvocations(mPhone); - setImsRegistered(false, ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); - setRcsRegistered(false, ImsRegistrationImplBase.REGISTRATION_TECH_LTE); + setImsRegistered(false); + setRcsRegistered(false); processAllMessages(); // All data should be disconnected. verifyAllDataDisconnected(); verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_IMS); - ArgumentCaptor pdcsCaptor = - ArgumentCaptor.forClass(PreciseDataConnectionState.class); verify(mPhone).notifyDataConnection(pdcsCaptor.capture()); - PreciseDataConnectionState pdcs = pdcsCaptor.getValue(); + pdcs = pdcsCaptor.getValue(); assertThat(pdcs.getState()).isEqualTo(TelephonyManager.DATA_DISCONNECTED); } -- GitLab From e5cdf7b0bfd38c5135f7e221d0ce5375a71e3e60 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Mon, 8 May 2023 19:38:45 +0000 Subject: [PATCH 639/656] Return true from checkSubscriptionAssociatedWithUser if subId is not present on the device. Bug: 277184941 Test: atest CtsTelephonyTestCases atest MmsTest#testSendMmsMessageWithInactiveSubscriptionId Flashed build on raven-userdebug: call/SMS/MMS are working fine. Change-Id: Ic1a5abdb42ea184925c41210b3f4b628df5f94ec --- .../telephony/subscription/SubscriptionManagerService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index ff2f7bda48..8ea94c6e6b 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -3602,6 +3602,13 @@ public class SubscriptionManagerService extends ISub.Stub { return true; } + List subIdList = subInfoList.stream().map(SubscriptionInfo::getSubscriptionId) + .collect(Collectors.toList()); + if (!subIdList.contains(subscriptionId)) { + // Return true as this subscription is not available on the device. + return true; + } + // Get list of subscriptions associated with this user. List associatedSubscriptionsList = getSubscriptionInfoListAssociatedWithUser(userHandle); -- GitLab From ceeca2946eec8d5cf9064345d5ef95233b13a7f3 Mon Sep 17 00:00:00 2001 From: arunvoddu Date: Wed, 19 Apr 2023 18:10:30 +0000 Subject: [PATCH 640/656] The CL moves the FDN fetching logic from SimRecords to IccRecord base class Bug: 277880312 Test: atest frameworks/opt/telephony/tests/telephonytests/src/com/android/internal/telephony/uicc. Also manually verified with CSIM and performed sanity with In Airtel and Jio and found no crash and problems. Change-Id: If67f749bccab36583af7631a75ad304a38514ea8 --- .../internal/telephony/uicc/IccRecords.java | 19 +++++++++++++++++++ .../internal/telephony/uicc/SIMRecords.java | 19 ------------------- .../telephony/uicc/UiccCardApplication.java | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java index fa00b16ca8..f80369675a 100644 --- a/src/java/com/android/internal/telephony/uicc/IccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java @@ -257,6 +257,8 @@ public abstract class IccRecords extends Handler implements IccConstants { // call back received on this upon EF_SMSS record update. public static final int EVENT_SET_SMSS_RECORD_DONE = 201; + private static final int EVENT_GET_FDN_DONE = 202; + /** * There are two purposes for this class. First, each instance of AuthAsyncResponse acts as a * lock to for calling thead to wait in getIccSimChallengeResponse(). Second, pass the IMS @@ -999,6 +1001,15 @@ public abstract class IccRecords extends Handler implements IccConstants { } break; + case EVENT_GET_FDN_DONE: + ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + loge("Failed to read USIM EF_FDN field error=" + ar.exception); + } else { + log("EF_FDN read successfully"); + } + break; + default: super.handleMessage(msg); } @@ -1674,4 +1685,12 @@ public abstract class IccRecords extends Handler implements IccConstants { return mMsg; } } + + public void loadFdnRecords() { + if (mParentApp != null) { + log("Loading FdnRecords"); + mAdnCache.requestLoadAllAdnLike(IccConstants.EF_FDN, EF_EXT2, + obtainMessage(EVENT_GET_FDN_DONE)); + } + } } diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index daf7842a9e..a97b00bdae 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -191,7 +191,6 @@ public class SIMRecords extends IccRecords { private static final int EVENT_SET_FPLMN_DONE = 43 + SIM_RECORD_EVENT_BASE; protected static final int EVENT_GET_SMSS_RECORD_DONE = 46 + SIM_RECORD_EVENT_BASE; protected static final int EVENT_GET_PSISMSC_DONE = 47 + SIM_RECORD_EVENT_BASE; - protected static final int EVENT_GET_FDN_DONE = 48 + SIM_RECORD_EVENT_BASE; // ***** Constructor @@ -1360,15 +1359,6 @@ public class SIMRecords extends IccRecords { } break; - case EVENT_GET_FDN_DONE: - ar = (AsyncResult) msg.obj; - if (ar.exception != null) { - loge("Failed to read USIM EF_FDN field error=" + ar.exception); - } else { - log("EF_FDN read successfully"); - } - break; - default: super.handleMessage(msg); // IccRecords handles generic record load responses } @@ -2194,15 +2184,6 @@ public class SIMRecords extends IccRecords { log("[CSP] Value Added Service Group (0xC0), not found!"); } - public void loadFdnRecords() { - if (mParentApp != null && mParentApp.getIccFdnEnabled() - && mParentApp.getIccFdnAvailable()) { - log("Loading FdnRecords"); - mAdnCache.requestLoadAllAdnLike(IccConstants.EF_FDN, getExtFromEf(IccConstants.EF_FDN), - obtainMessage(EVENT_GET_FDN_DONE)); - } - } - @VisibleForTesting public void setMailboxIndex(int mailboxIndex) { mMailboxIndex = mailboxIndex; diff --git a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java index 4eaf7a6e83..fe19e991cb 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java +++ b/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java @@ -271,7 +271,7 @@ public class UiccCardApplication { loge("Bogus facility lock response"); } if (mIccFdnEnabled && mIccFdnAvailable) { - ((SIMRecords) mIccRecords).loadFdnRecords(); + mIccRecords.loadFdnRecords(); } } } -- GitLab From b6eb89685f2b562b2e7ad6f1fbc35d5860292593 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Thu, 4 May 2023 13:42:55 -0700 Subject: [PATCH 641/656] Add more unit tests for SatelliteController - Add more unit tests for SatelliteControlle - Clean up resources when satellite modem crashes. Bug: 279929401 Test: Call/SMS/MMS with live nework. atest SatelliteControllerTest atest SatelliteManagerTestOnMockService Change-Id: I87a7f7c7820a6af36b82b1a6129e55cd7102f2e6 --- .../telephony/satellite/DatagramReceiver.java | 1 + .../satellite/SatelliteController.java | 20 +- .../satellite/SatelliteControllerTest.java | 414 ++++++++++++++++-- 3 files changed, 400 insertions(+), 35 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java index 20afdfb0ee..06eede122a 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java @@ -404,6 +404,7 @@ public class DatagramReceiver extends Handler { deleteDatagram(argument.datagramId); sInstance.mPendingAckCountHashMap.remove(argument.datagramId); } + break; } default: diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 6fd13c8e71..0ca6f8eef6 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -671,7 +671,6 @@ public class SatelliteController extends Handler { if (mNeedsSatellitePointing) { mPointingAppController.startPointingUI(false); } - evaluateToSendSatelliteEnabledSuccess(); } else { synchronized (mSatelliteEnabledRequestLock) { @@ -687,9 +686,12 @@ public class SatelliteController extends Handler { resetSatelliteEnabledRequest(); setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_FALSE); + setDemoModeEnabled(argument.enableDemoMode); + synchronized (mIsSatelliteEnabledLock) { + mIsSatelliteEnabled = argument.enableSatellite; + } // If satellite is disabled, send success to callback immediately argument.callback.accept(error); - setIsDemoModeEnabled(argument.enableDemoMode); updateSatelliteEnabledState( argument.enableSatellite, "EVENT_SET_SATELLITE_ENABLED_DONE"); } @@ -2187,6 +2189,8 @@ public class SatelliteController extends Handler { logd("handleEventSatelliteModemStateChanged: state=" + state); if (state == SatelliteManager.SATELLITE_MODEM_STATE_OFF || state == SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE) { + setSettingsKeyForSatelliteMode(SATELLITE_MODE_ENABLED_FALSE); + setDemoModeEnabled(false); updateSatelliteEnabledState( false, "handleEventSatelliteModemStateChanged"); cleanUpResources(state); @@ -2223,10 +2227,14 @@ public class SatelliteController extends Handler { if (areAllRadiosDisabled() && (mSatelliteEnabledRequest != null) && mWaitingForRadioDisabled) { logd("Sending success to callback that sent enable satellite request"); - setIsDemoModeEnabled(mSatelliteEnabledRequest.enableDemoMode); - updateSatelliteEnabledState(mSatelliteEnabledRequest.enableSatellite, - "EVENT_SET_SATELLITE_ENABLED_DONE"); + setDemoModeEnabled(mSatelliteEnabledRequest.enableDemoMode); + synchronized (mIsSatelliteEnabledLock) { + mIsSatelliteEnabled = mSatelliteEnabledRequest.enableSatellite; + } mSatelliteEnabledRequest.callback.accept(SatelliteManager.SATELLITE_ERROR_NONE); + updateSatelliteEnabledState( + mSatelliteEnabledRequest.enableSatellite, + "EVENT_SET_SATELLITE_ENABLED_DONE"); mSatelliteEnabledRequest = null; mWaitingForRadioDisabled = false; } @@ -2254,7 +2262,7 @@ public class SatelliteController extends Handler { } } - private void setIsDemoModeEnabled(boolean enabled) { + private void setDemoModeEnabled(boolean enabled) { mIsDemoModeEnabled = enabled; mDatagramController.setDemoMode(mIsDemoModeEnabled); } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java index 63eb656103..180ea8337a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java @@ -27,7 +27,10 @@ import static android.telephony.satellite.SatelliteManager.SATELLITE_ERROR_NONE; import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_ARGUMENTS; import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_MODEM_STATE; import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; import static android.telephony.satellite.SatelliteManager.SATELLITE_NOT_SUPPORTED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_NO_RESOURCES; import static android.telephony.satellite.SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE; import static android.telephony.satellite.SatelliteManager.SATELLITE_REQUEST_IN_PROGRESS; import static android.telephony.satellite.SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED; @@ -46,10 +49,12 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.NonNull; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncResult; @@ -59,16 +64,22 @@ import android.os.Looper; import android.os.Message; import android.os.ResultReceiver; import android.telephony.Rlog; +import android.telephony.satellite.ISatelliteDatagramCallback; +import android.telephony.satellite.ISatelliteProvisionStateCallback; +import android.telephony.satellite.ISatelliteStateCallback; import android.telephony.satellite.SatelliteCapabilities; +import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.telephony.satellite.SatelliteManager.SatelliteException; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import com.android.internal.telephony.IIntegerConsumer; +import com.android.internal.telephony.IVoidConsumer; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; +import com.android.internal.telephony.satellite.metrics.SessionMetricsStats; import org.junit.After; import org.junit.Before; @@ -77,9 +88,11 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Semaphore; @@ -102,14 +115,15 @@ public class SatelliteControllerTest extends TelephonyTest { @Mock private PointingAppController mMockPointingAppController; @Mock private ControllerMetricsStats mMockControllerMetricsStats; @Mock private ProvisionMetricsStats mMockProvisionMetricsStats; + @Mock private SessionMetricsStats mMockSessionMetricsStats; - private int mIIntegerConsumerResult = 0; + private List mIIntegerConsumerResults = new ArrayList<>(); private Semaphore mIIntegerConsumerSemaphore = new Semaphore(0); private IIntegerConsumer mIIntegerConsumer = new IIntegerConsumer.Stub() { @Override public void accept(int result) { logd("mIIntegerConsumer: result=" + result); - mIIntegerConsumerResult = result; + mIIntegerConsumerResults.add(result); try { mIIntegerConsumerSemaphore.release(); } catch (Exception ex) { @@ -118,7 +132,6 @@ public class SatelliteControllerTest extends TelephonyTest { } }; - private boolean mIsSatelliteSupported = true; private boolean mIsSatelliteServiceSupported = true; private boolean mIsPointingRequired = true; private Set mSupportedRadioTechnologies = new HashSet<>(Arrays.asList( @@ -226,6 +239,8 @@ public class SatelliteControllerTest extends TelephonyTest { mMockControllerMetricsStats); replaceInstance(ProvisionMetricsStats.class, "sInstance", null, mMockProvisionMetricsStats); + replaceInstance(SessionMetricsStats.class, "sInstance", null, + mMockSessionMetricsStats); mSharedPreferences = new TestSharedPreferences(); when(mContext.getSharedPreferences(anyString(), anyInt())).thenReturn(mSharedPreferences); @@ -238,6 +253,14 @@ public class SatelliteControllerTest extends TelephonyTest { doNothing().when(mMockSatelliteSessionController) .onSatelliteEnabledStateChanged(anyBoolean()); doNothing().when(mMockSatelliteSessionController).setDemoMode(anyBoolean()); + doNothing().when(mMockControllerMetricsStats).onSatelliteEnabled(); + doNothing().when(mMockControllerMetricsStats).reportServiceEnablementSuccessCount(); + doNothing().when(mMockControllerMetricsStats).reportServiceEnablementFailCount(); + doReturn(mMockSessionMetricsStats) + .when(mMockSessionMetricsStats).setInitializationResult(anyInt()); + doReturn(mMockSessionMetricsStats) + .when(mMockSessionMetricsStats).setRadioTechnology(anyInt()); + doNothing().when(mMockSessionMetricsStats).reportSessionMetrics(); mSatelliteControllerUT = new TestSatelliteController(mContext, Looper.myLooper()); verify(mMockSatelliteModemInterface).registerForSatelliteProvisionStateChanged( @@ -264,19 +287,29 @@ public class SatelliteControllerTest extends TelephonyTest { @Test public void testRequestSatelliteEnabled() { mIsSatelliteEnabledSemaphore.drainPermits(); + + // Fail to enable satellite when SatelliteController is not fully loaded yet. + mIIntegerConsumerResults.clear(); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mIIntegerConsumerResult); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + // Fail to enable satellite when the device does not support satellite. + mIIntegerConsumerResults.clear(); setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); verifySatelliteSupported(false, SATELLITE_ERROR_NONE); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_NOT_SUPPORTED, mIIntegerConsumerResult); + assertEquals(SATELLITE_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); + // Fail to enable satellite when the device is not provisioned yet. + mIIntegerConsumerResults.clear(); resetSatelliteControllerUT(); + verify(mMockSatelliteSessionController, times(1)).onSatelliteEnabledStateChanged(eq(false)); + verify(mMockSatelliteSessionController, times(1)).setDemoMode(eq(false)); + verify(mMockDatagramController, times(1)).setDemoMode(eq(false)); setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); verifySatelliteSupported(true, SATELLITE_ERROR_NONE); setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); @@ -284,12 +317,13 @@ public class SatelliteControllerTest extends TelephonyTest { mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, mIIntegerConsumerResult); + assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, (long) mIIntegerConsumerResults.get(0)); sendProvisionedStateChangedEvent(true, null); processAllMessages(); verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + // Successfully disable satellite when radio is turned off. mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false; setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); setRadioPower(false); @@ -298,87 +332,174 @@ public class SatelliteControllerTest extends TelephonyTest { assertTrue(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled); assertEquals( SATELLITE_MODE_ENABLED_FALSE, mSatelliteControllerUT.satelliteModeSettingValue); - verify(mMockSatelliteSessionController, times(1)).onSatelliteEnabledStateChanged(eq(false)); - verify(mMockSatelliteSessionController, times(1)).setDemoMode(eq(false)); - verify(mMockDatagramController, times(1)).setDemoMode(eq(false)); + verify(mMockSatelliteSessionController, times(2)).onSatelliteEnabledStateChanged(eq(false)); + verify(mMockSatelliteSessionController, times(2)).setDemoMode(eq(false)); + verify(mMockDatagramController, times(2)).setDemoMode(eq(false)); + verify(mMockControllerMetricsStats, times(1)).onSatelliteDisabled(); + // Fail to enable satellite when radio is off. + mIIntegerConsumerResults.clear(); setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); // Radio is not on, can not enable satellite - assertEquals(SATELLITE_INVALID_MODEM_STATE, mIIntegerConsumerResult); + assertEquals(SATELLITE_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); setRadioPower(true); processAllMessages(); verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + // Fail to enable satellite with an error response from modem when radio is on. + mIIntegerConsumerResults.clear(); + mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false; + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_INVALID_MODEM_STATE); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); + verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + verify(mMockPointingAppController, never()).startPointingUI(anyBoolean()); + assertFalse(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled); + verify(mMockControllerMetricsStats, times(1)).reportServiceEnablementFailCount(); + + // Successfully enable satellite when radio is on. + mIIntegerConsumerResults.clear(); mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled = false; + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); assertTrue(mSatelliteControllerUT.setSettingsKeyForSatelliteModeCalled); assertEquals(SATELLITE_MODE_ENABLED_TRUE, mSatelliteControllerUT.satelliteModeSettingValue); verify(mMockPointingAppController).startPointingUI(eq(false)); verify(mMockSatelliteSessionController, times(1)).onSatelliteEnabledStateChanged(eq(true)); - verify(mMockSatelliteSessionController, times(2)).setDemoMode(eq(false)); - verify(mMockDatagramController, times(2)).setDemoMode(eq(false)); - + verify(mMockSatelliteSessionController, times(3)).setDemoMode(eq(false)); + verify(mMockDatagramController, times(3)).setDemoMode(eq(false)); + verify(mMockControllerMetricsStats, times(1)).onSatelliteEnabled(); + verify(mMockControllerMetricsStats, times(1)).reportServiceEnablementSuccessCount(); + verify(mMockSessionMetricsStats, times(2)).setInitializationResult(anyInt()); + verify(mMockSessionMetricsStats, times(2)).setRadioTechnology(anyInt()); + verify(mMockSessionMetricsStats, times(2)).reportSessionMetrics(); + + // Successfully enable satellite when it is already enabled. + mIIntegerConsumerResults.clear(); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + // Fail to enable satellite with a different demo mode when it is already enabled. + mIIntegerConsumerResults.clear(); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, true, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_INVALID_ARGUMENTS, mIIntegerConsumerResult); + assertEquals(SATELLITE_INVALID_ARGUMENTS, (long) mIIntegerConsumerResults.get(0)); verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); + // Disable satellite. + mIIntegerConsumerResults.clear(); setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + // Disable satellite when satellite is already disabled. + mIIntegerConsumerResults.clear(); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + // Disable satellite with a different demo mode when satellite is already disabled. + mIIntegerConsumerResults.clear(); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, true, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + // Send a second request while the first request in progress + mIIntegerConsumerResults.clear(); setUpNoResponseForRequestSatelliteEnabled(true, false); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertFalse(waitForIIntegerConsumerResult(1)); - mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_REQUEST_IN_PROGRESS, mIIntegerConsumerResult); + assertEquals(SATELLITE_REQUEST_IN_PROGRESS, (long) mIIntegerConsumerResults.get(0)); - resetSatelliteControllerUTToOffAndProvisionedState(); + mIIntegerConsumerResults.clear(); resetSatelliteControllerUTToSupportedAndProvisionedState(); + // Should receive callback for the above request when satellite modem is turned off. + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); + + // Move to satellite-disabling in progress. setUpNoResponseForRequestSatelliteEnabled(false, false); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); processAllMessages(); assertFalse(waitForIIntegerConsumerResult(1)); - // Disabling is in progress. Thus, a new request to enable satellite will be rejected. + // Disable is in progress. Thus, a new request to enable satellite will be rejected. + mIIntegerConsumerResults.clear(); mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR, mIIntegerConsumerResult); + assertEquals(SATELLITE_ERROR, (long) mIIntegerConsumerResults.get(0)); + + mIIntegerConsumerResults.clear(); + resetSatelliteControllerUTToOffAndProvisionedState(); + // Should receive callback for the above request when satellite modem is turned off. + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); + + /** + * Make areAllRadiosDisabled return false and move mWaitingForRadioDisabled to true, which + * will lead to no response for requestSatelliteEnabled. + */ + mSatelliteControllerUT.allRadiosDisabled = false; + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertFalse(waitForIIntegerConsumerResult(1)); + + resetSatelliteControllerUTEnabledState(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); + processAllMessages(); + // We should receive 2 callbacks for the above 2 requests. + assertTrue(waitForIIntegerConsumerResult(2)); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(1)); + + resetSatelliteControllerUTToOffAndProvisionedState(); + + // Repeat the same test as above but with error response from modem for the second request + mSatelliteControllerUT.allRadiosDisabled = false; + setUpResponseForRequestSatelliteEnabled(true, false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); + processAllMessages(); + assertFalse(waitForIIntegerConsumerResult(1)); + + resetSatelliteControllerUTEnabledState(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_NO_RESOURCES); + mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); + processAllMessages(); + // We should receive 2 callbacks for the above 2 requests. + assertTrue(waitForIIntegerConsumerResult(2)); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + assertEquals(SATELLITE_NO_RESOURCES, (long) mIIntegerConsumerResults.get(1)); + mSatelliteControllerUT.allRadiosDisabled = true; } @Test @@ -399,12 +520,226 @@ public class SatelliteControllerTest extends TelephonyTest { verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); } + @Test + public void testRegisterForSatelliteModemStateChanged() { + ISatelliteStateCallback callback = new ISatelliteStateCallback.Stub() { + @Override + public void onSatelliteModemStateChanged(int state) { + logd("onSatelliteModemStateChanged: state=" + state); + } + }; + int errorCode = mSatelliteControllerUT.registerForSatelliteModemStateChanged( + SUB_ID, callback); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, errorCode); + verify(mMockSatelliteSessionController, never()) + .registerForSatelliteModemStateChanged(callback); + + resetSatelliteControllerUTToSupportedAndProvisionedState(); + + errorCode = mSatelliteControllerUT.registerForSatelliteModemStateChanged( + SUB_ID, callback); + assertEquals(SATELLITE_ERROR_NONE, errorCode); + verify(mMockSatelliteSessionController).registerForSatelliteModemStateChanged(callback); + } + + @Test + public void testUnregisterForSatelliteModemStateChanged() { + ISatelliteStateCallback callback = new ISatelliteStateCallback.Stub() { + @Override + public void onSatelliteModemStateChanged(int state) { + logd("onSatelliteModemStateChanged: state=" + state); + } + }; + mSatelliteControllerUT.unregisterForSatelliteModemStateChanged(SUB_ID, callback); + verify(mMockSatelliteSessionController, never()) + .unregisterForSatelliteModemStateChanged(callback); + + resetSatelliteControllerUTToSupportedAndProvisionedState(); + + mSatelliteControllerUT.unregisterForSatelliteModemStateChanged(SUB_ID, callback); + verify(mMockSatelliteSessionController).unregisterForSatelliteModemStateChanged(callback); + } + + @Test + public void testRegisterForSatelliteProvisionStateChanged() { + Semaphore semaphore = new Semaphore(0); + ISatelliteProvisionStateCallback callback = + new ISatelliteProvisionStateCallback.Stub() { + @Override + public void onSatelliteProvisionStateChanged(boolean provisioned) { + logd("onSatelliteProvisionStateChanged: provisioned=" + provisioned); + try { + semaphore.release(); + } catch (Exception ex) { + loge("onSatelliteProvisionStateChanged: Got exception in releasing " + + "semaphore, ex=" + ex); + } + } + }; + int errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( + SUB_ID, callback); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, errorCode); + + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( + SUB_ID, callback); + assertEquals(SATELLITE_NOT_SUPPORTED, errorCode); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( + SUB_ID, callback); + assertEquals(SATELLITE_ERROR_NONE, errorCode); + + sendProvisionedStateChangedEvent(true, null); + processAllMessages(); + assertTrue(waitForForEvents( + semaphore, 1, "testRegisterForSatelliteProvisionStateChanged")); + + mSatelliteControllerUT.unregisterForSatelliteProvisionStateChanged(SUB_ID, callback); + sendProvisionedStateChangedEvent(true, null); + processAllMessages(); + assertFalse(waitForForEvents( + semaphore, 1, "testRegisterForSatelliteProvisionStateChanged")); + } + + @Test + public void testRegisterForSatelliteDatagram() { + ISatelliteDatagramCallback callback = + new ISatelliteDatagramCallback.Stub() { + @Override + public void onSatelliteDatagramReceived(long datagramId, + @NonNull SatelliteDatagram datagram, int pendingCount, + @NonNull IVoidConsumer internalAck) { + logd("onSatelliteDatagramReceived"); + } + }; + when(mMockDatagramController.registerForSatelliteDatagram(eq(SUB_ID), eq(callback))) + .thenReturn(SATELLITE_ERROR_NONE); + int errorCode = mSatelliteControllerUT.registerForSatelliteDatagram(SUB_ID, callback); + assertEquals(SATELLITE_ERROR_NONE, errorCode); + verify(mMockDatagramController).registerForSatelliteDatagram(eq(SUB_ID), eq(callback)); + } + + @Test + public void testUnregisterForSatelliteDatagram() { + ISatelliteDatagramCallback callback = + new ISatelliteDatagramCallback.Stub() { + @Override + public void onSatelliteDatagramReceived(long datagramId, + @NonNull SatelliteDatagram datagram, int pendingCount, + @NonNull IVoidConsumer internalAck) { + logd("onSatelliteDatagramReceived"); + } + }; + doNothing().when(mMockDatagramController) + .unregisterForSatelliteDatagram(eq(SUB_ID), eq(callback)); + mSatelliteControllerUT.unregisterForSatelliteDatagram(SUB_ID, callback); + verify(mMockDatagramController).unregisterForSatelliteDatagram(eq(SUB_ID), eq(callback)); + } + + @Test + public void testSendSatelliteDatagram() { + String mText = "This is a test datagram message from user"; + SatelliteDatagram datagram = new SatelliteDatagram(mText.getBytes()); + + mIIntegerConsumerResults.clear(); + mSatelliteControllerUT.sendSatelliteDatagram(SUB_ID, + SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, datagram, true, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + verify(mMockDatagramController, never()).sendSatelliteDatagram(anyInt(), + eq(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE), eq(datagram), eq(true), + any()); + + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + sendProvisionedStateChangedEvent(false, null); + processAllMessages(); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.sendSatelliteDatagram(SUB_ID, + SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, datagram, true, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, (long) mIIntegerConsumerResults.get(0)); + verify(mMockDatagramController, never()).sendSatelliteDatagram(anyInt(), + eq(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE), eq(datagram), eq(true), + any()); + + mIIntegerConsumerResults.clear(); + sendProvisionedStateChangedEvent(true, null); + processAllMessages(); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.sendSatelliteDatagram(SUB_ID, + SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE, datagram, true, mIIntegerConsumer); + processAllMessages(); + assertFalse(waitForIIntegerConsumerResult(1)); + verify(mMockDatagramController, times(1)).sendSatelliteDatagram(anyInt(), + eq(SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE), eq(datagram), eq(true), + any()); + verify(mMockPointingAppController, times(1)).startPointingUI(eq(true)); + } + + @Test + public void testPollPendingSatelliteDatagrams() { + mIIntegerConsumerResults.clear(); + mSatelliteControllerUT.pollPendingSatelliteDatagrams(SUB_ID, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + verify(mMockDatagramController, never()).pollPendingSatelliteDatagrams(anyInt(), any()); + + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + sendProvisionedStateChangedEvent(false, null); + processAllMessages(); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.pollPendingSatelliteDatagrams(SUB_ID, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, (long) mIIntegerConsumerResults.get(0)); + verify(mMockDatagramController, never()).pollPendingSatelliteDatagrams(anyInt(), any()); + + mIIntegerConsumerResults.clear(); + sendProvisionedStateChangedEvent(true, null); + processAllMessages(); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.pollPendingSatelliteDatagrams(SUB_ID, mIIntegerConsumer); + processAllMessages(); + assertFalse(waitForIIntegerConsumerResult(1)); + verify(mMockDatagramController, times(1)).pollPendingSatelliteDatagrams(anyInt(), any()); + } + + private void resetSatelliteControllerUTEnabledState() { + logd("resetSatelliteControllerUTEnabledState"); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); + doReturn(true).when(mMockSatelliteModemInterface) + .setSatelliteServicePackageName(anyString()); + mSatelliteControllerUT.setSatelliteServicePackageName("TestSatelliteService"); + processAllMessages(); + + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + sendProvisionedStateChangedEvent(true, null); + processAllMessages(); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + } + private void resetSatelliteControllerUT() { logd("resetSatelliteControllerUT"); + // Trigger cleanUpResources + sendSatelliteModemStateChangedEvent(SATELLITE_MODEM_STATE_UNAVAILABLE, null); + processAllMessages(); + + // Reset all cached states setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); doReturn(true).when(mMockSatelliteModemInterface) .setSatelliteServicePackageName(anyString()); - // Reset all cached states mSatelliteControllerUT.setSatelliteServicePackageName("TestSatelliteService"); processAllMessages(); } @@ -420,10 +755,8 @@ public class SatelliteControllerTest extends TelephonyTest { private void resetSatelliteControllerUTToOffAndProvisionedState() { resetSatelliteControllerUTToSupportedAndProvisionedState(); - setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); - mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, false, false, mIIntegerConsumer); + sendSatelliteModemStateChangedEvent(SATELLITE_MODEM_STATE_OFF, null); processAllMessages(); - assertTrue(waitForIIntegerConsumerResult(1)); verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); } @@ -436,7 +769,7 @@ public class SatelliteControllerTest extends TelephonyTest { mSatelliteControllerUT.requestSatelliteEnabled(SUB_ID, true, false, mIIntegerConsumer); processAllMessages(); assertTrue(waitForIIntegerConsumerResult(1)); - assertEquals(SATELLITE_ERROR_NONE, mIIntegerConsumerResult); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); } @@ -496,6 +829,22 @@ public class SatelliteControllerTest extends TelephonyTest { }).when(mMockSatelliteModemInterface).requestSatelliteCapabilities(any(Message.class)); } + private boolean waitForForEvents( + Semaphore semaphore, int expectedNumberOfEvents, String caller) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!semaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + loge(caller + ": Timeout to receive the expected event"); + return false; + } + } catch (Exception ex) { + loge(caller + ": Got exception=" + ex); + return false; + } + } + return true; + } + private boolean waitForRequestIsSatelliteSupportedResult(int expectedNumberOfEvents) { for (int i = 0; i < expectedNumberOfEvents; i++) { try { @@ -591,6 +940,13 @@ public class SatelliteControllerTest extends TelephonyTest { msg.sendToTarget(); } + private void sendSatelliteModemStateChangedEvent(int state, Throwable exception) { + Message msg = mSatelliteControllerUT.obtainMessage( + 28 /* EVENT_SATELLITE_MODEM_STATE_CHANGED */); + msg.obj = new AsyncResult(null, state, exception); + msg.sendToTarget(); + } + private void setRadioPower(boolean on) { mSimulatedCommands.setRadioPower(on, false, false, null); } -- GitLab From 7a008f2a6c750c73b098362a4c3ea9f6160e3a18 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 10 May 2023 12:19:05 -0700 Subject: [PATCH 642/656] Moved debug message into verbose channel Fix: 281871313 Test: Boot up and basic phone functionality tests Change-Id: I009f5e36e84be094fcdfd0bca9eec700619c3808 --- .../subscription/SubscriptionManagerService.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index ff2f7bda48..7bab8afe9a 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -3565,7 +3565,7 @@ public class SubscriptionManagerService extends ISub.Stub { } UserHandle userHandle = UserHandle.of(subInfo.getUserId()); - log("getSubscriptionUserHandle subId = " + subId + " userHandle = " + userHandle); + logv("getSubscriptionUserHandle subId = " + subId + " userHandle = " + userHandle); if (userHandle.getIdentifier() == UserHandle.USER_NULL) { return null; } @@ -3928,6 +3928,15 @@ public class SubscriptionManagerService extends ISub.Stub { mLocalLog.log(s); } + /** + * Log verbose messages. + * + * @param s verbose messages + */ + private void logv(@NonNull String s) { + Rlog.v(LOG_TAG, s); + } + /** * Dump the state of {@link SubscriptionManagerService}. * -- GitLab From 53d1bd0f504d47c74bc547d6a4beebd52088cfd5 Mon Sep 17 00:00:00 2001 From: Sarah Chin Date: Thu, 11 May 2023 00:10:40 -0700 Subject: [PATCH 643/656] ServiceStateTracker consider config for combined bandwidth When we are calculating bandwidths from the physical channel config list, make sure to use the config KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL. Test: atest ServiceStateTrackerTest Test: manual verify no visible regressions for icon Bug: 281300377 Change-Id: Id918aeb5c1182c54d7bb3027afe80e9018980cfb --- .../telephony/ServiceStateTracker.java | 24 +++++++++---------- .../telephony/ServiceStateTrackerTest.java | 10 ++++---- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 9fb7d439eb..29b1acae28 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -1695,16 +1695,9 @@ public class ServiceStateTracker extends Handler { .findFirst() .orElse(PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN); } - boolean includeLte = mCarrierConfig.getBoolean(CarrierConfigManager - .KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); int[] bandwidths = new int[0]; if (list != null) { - bandwidths = list.stream() - .filter(config -> includeLte || config.getNetworkType() - == TelephonyManager.NETWORK_TYPE_NR) - .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) - .mapToInt(Integer::intValue) - .toArray(); + bandwidths = getBandwidthsFromLastPhysicalChannelConfigs(); } if (anchorNrCellId == mLastAnchorNrCellId && anchorNrCellId != PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN) { @@ -1712,7 +1705,8 @@ public class ServiceStateTracker extends Handler { hasChanged |= RatRatcheter.updateBandwidths(bandwidths, mSS); } else { log("Do not ratchet bandwidths since anchor NR cell is different (" - + mLastAnchorNrCellId + "->" + anchorNrCellId + ")."); + + mLastAnchorNrCellId + " -> " + anchorNrCellId + + "). New bandwidths are " + Arrays.toString(bandwidths)); mLastAnchorNrCellId = anchorNrCellId; hasChanged |= !Arrays.equals(mSS.getCellBandwidths(), bandwidths); mSS.setCellBandwidths(bandwidths); @@ -1796,8 +1790,12 @@ public class ServiceStateTracker extends Handler { return simAbsent; } - private static int[] getBandwidthsFromConfigs(List list) { - return list.stream() + private int[] getBandwidthsFromLastPhysicalChannelConfigs() { + boolean includeLte = mCarrierConfig.getBoolean( + CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); + return mLastPhysicalChannelConfigList.stream() + .filter(config -> includeLte + || config.getNetworkType() == TelephonyManager.NETWORK_TYPE_NR) .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) .mapToInt(Integer::intValue) .toArray(); @@ -2557,7 +2555,7 @@ public class ServiceStateTracker extends Handler { // Prioritize the PhysicalChannelConfig list because we might already be in carrier // aggregation by the time poll state is performed. if (primaryPcc != null) { - bandwidths = getBandwidthsFromConfigs(mLastPhysicalChannelConfigList); + bandwidths = getBandwidthsFromLastPhysicalChannelConfigs(); for (int bw : bandwidths) { if (!isValidLteBandwidthKhz(bw)) { loge("Invalid LTE Bandwidth in RegistrationState, " + bw); @@ -2593,7 +2591,7 @@ public class ServiceStateTracker extends Handler { // Prioritize the PhysicalChannelConfig list because we might already be in carrier // aggregation by the time poll state is performed. if (primaryPcc != null) { - bandwidths = getBandwidthsFromConfigs(mLastPhysicalChannelConfigList); + bandwidths = getBandwidthsFromLastPhysicalChannelConfigs(); for (int bw : bandwidths) { if (!isValidNrBandwidthKhz(bw)) { loge("Invalid NR Bandwidth in RegistrationState, " + bw); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 280fbcc177..379117cad0 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -374,6 +374,9 @@ public class ServiceStateTrackerTest extends TelephonyTest { 15, /* SIGNAL_STRENGTH_GOOD */ 30 /* SIGNAL_STRENGTH_GREAT */ }); + mBundle.putBoolean( + CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, + true); sendCarrierConfigUpdate(PHONE_ID); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); @@ -2282,10 +2285,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test public void testPhyChanBandwidthRatchetedOnPhyChanBandwidth() { - mBundle.putBoolean( - CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, - true); - // LTE Cell with bandwidth = 10000 CellIdentityLte cellIdentity10 = new CellIdentityLte(1, 1, 1, 1, new int[] {1, 2}, 10000, "1", "1", "test", @@ -2370,6 +2369,9 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test public void testPhyChanBandwidthForNr() { + mBundle.putBoolean( + CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, + false); // NR Cell with bandwidth = 10000 CellIdentityNr nrCi = new CellIdentityNr( 0, 0, 0, new int[]{10000}, "", "", 5, "", "", Collections.emptyList()); -- GitLab From 7fcf5f958b7e848a9ac994abf77c17292c2e786a Mon Sep 17 00:00:00 2001 From: Rafael Higuera Silva Date: Tue, 25 Apr 2023 20:08:02 +0000 Subject: [PATCH 644/656] Add fold state to service state Bug: 276772849 Test: make, atest com.android.internal.telephony.metrics and manual test Change-Id: I62ff6fb1be3aef6ac9044990b78094025da1da73 Merged-In: I62ff6fb1be3aef6ac9044990b78094025da1da73 --- proto/src/persist_atoms.proto | 2 + .../telephony/metrics/DeviceStateHelper.java | 77 +++++++++++++++++++ .../telephony/metrics/MetricsCollector.java | 18 +++-- .../metrics/PersistAtomsStorage.java | 5 +- .../telephony/metrics/ServiceStateStats.java | 24 ++++++ .../internal/telephony/TelephonyTest.java | 10 +++ .../metrics/MetricsCollectorTest.java | 4 +- .../metrics/ServiceStateStatsTest.java | 43 +++++++++++ 8 files changed, 174 insertions(+), 9 deletions(-) create mode 100644 src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index aa784dd5c1..fc3f0d0e9c 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -274,6 +274,7 @@ message VoiceCallSession { optional bool is_multiparty = 31; optional int32 call_duration = 32; optional int32 last_known_rat = 33; + // Internal use only optional int64 setup_begin_millis = 10001; } @@ -375,6 +376,7 @@ message CellularServiceState { optional int64 total_time_millis = 9; // Duration needs to be rounded when pulled optional bool is_emergency_only = 10; optional bool is_internet_pdn_up = 11; + optional int32 fold_state = 12; // Internal use only optional int64 last_used_millis = 10001; diff --git a/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java b/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java new file mode 100644 index 0000000000..29729c8092 --- /dev/null +++ b/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 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 com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_FLIPPED; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_HALF_OPENED; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_OPENED; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN; + +import android.content.Context; +import android.hardware.devicestate.DeviceStateManager; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.HandlerThread; + +import com.android.internal.telephony.Phone; + +/** Device state information like the fold state. */ +public class DeviceStateHelper { + private int mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN; + + public DeviceStateHelper(Context context) { + HandlerThread mHandlerThread = new HandlerThread("DeviceStateHelperThread"); + mHandlerThread.start(); + context.getSystemService(DeviceStateManager.class) + .registerCallback( + new HandlerExecutor(new Handler(mHandlerThread.getLooper())), + state -> { + updateFoldState(state); + }); + } + + private void updateFoldState(int posture) { + switch (posture) { + case 0: + mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED; + break; + case 1: + mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_HALF_OPENED; + break; + case 2: + mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_OPENED; + break; + case 4: + mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_FLIPPED; + break; + default: + mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN; + } + updateServiceStateStats(); + } + + private void updateServiceStateStats() { + for (Phone phone : MetricsCollector.getPhonesIfAny()) { + phone.getServiceStateTracker().getServiceStateStats().onFoldStateChanged(mFoldState); + } + } + + public int getFoldState() { + return mFoldState; + } +} diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index 7546124697..aab55e6d39 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -145,20 +145,22 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { DBG ? 2L * MILLIS_PER_SECOND : 5L * MILLIS_PER_MINUTE; private final PersistAtomsStorage mStorage; + private final DeviceStateHelper mDeviceStateHelper; private final StatsManager mStatsManager; private final AirplaneModeStats mAirplaneModeStats; private final Set mOngoingDataCallStats = ConcurrentHashMap.newKeySet(); private static final Random sRandom = new Random(); public MetricsCollector(Context context) { - this(context, new PersistAtomsStorage(context)); + this(context, new PersistAtomsStorage(context), new DeviceStateHelper(context)); } /** Allows dependency injection. Used during unit tests. */ @VisibleForTesting - public MetricsCollector(Context context, - PersistAtomsStorage storage) { + public MetricsCollector( + Context context, PersistAtomsStorage storage, DeviceStateHelper deviceStateHelper) { mStorage = storage; + mDeviceStateHelper = deviceStateHelper; mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER); if (mStatsManager != null) { // Most (but not all) of these are subject to cooldown specified by MIN_COOLDOWN_MILLIS. @@ -299,6 +301,11 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return mStorage; } + /** Returns the {@link DeviceStateHelper}. */ + public DeviceStateHelper getDeviceStateHelper() { + return mDeviceStateHelper; + } + /** Updates duration segments and calls {@link PersistAtomsStorage#flushAtoms()}. */ public void flushAtomsStorage() { concludeAll(); @@ -915,7 +922,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { state.carrierId, roundAndConvertMillisToSeconds(state.totalTimeMillis), state.isEmergencyOnly, - state.isInternetPdnUp); + state.isInternetPdnUp, + state.foldState); } private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) { @@ -1316,7 +1324,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } /** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */ - private static Phone[] getPhonesIfAny() { + static Phone[] getPhonesIfAny() { try { return PhoneFactory.getPhones(); } catch (IllegalStateException e) { diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java index 13ba91b269..5a21bafd49 100644 --- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java +++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java @@ -1708,7 +1708,8 @@ public class PersistAtomsStorage { && state.isMultiSim == key.isMultiSim && state.carrierId == key.carrierId && state.isEmergencyOnly == key.isEmergencyOnly - && state.isInternetPdnUp == key.isInternetPdnUp) { + && state.isInternetPdnUp == key.isInternetPdnUp + && state.foldState == key.foldState) { return state; } } @@ -2334,4 +2335,4 @@ public class PersistAtomsStorage { // Epoch time in UTC, preserved across reboots, but can be adjusted e.g. by the user or NTP return System.currentTimeMillis(); } -} \ No newline at end of file +} diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java index 7c63dec3a3..b830cd00d2 100644 --- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java +++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java @@ -54,11 +54,13 @@ public class ServiceStateStats extends DataNetworkControllerCallback { new AtomicReference<>(new TimestampedServiceState(null, 0L)); private final Phone mPhone; private final PersistAtomsStorage mStorage; + private final DeviceStateHelper mDeviceStateHelper; public ServiceStateStats(Phone phone) { super(Runnable::run); mPhone = phone; mStorage = PhoneFactory.getMetricsCollector().getAtomsStorage(); + mDeviceStateHelper = PhoneFactory.getMetricsCollector().getDeviceStateHelper(); } /** Finalizes the durations of the current service state segment. */ @@ -120,6 +122,7 @@ public class ServiceStateStats extends DataNetworkControllerCallback { newState.carrierId = mPhone.getCarrierId(); newState.isEmergencyOnly = isEmergencyOnly(serviceState); newState.isInternetPdnUp = isInternetPdnUp(mPhone); + newState.foldState = mDeviceStateHelper.getFoldState(); TimestampedServiceState prevState = mLastState.getAndSet(new TimestampedServiceState(newState, now)); addServiceStateAndSwitch( @@ -127,6 +130,26 @@ public class ServiceStateStats extends DataNetworkControllerCallback { } } + /** Updates the fold state of the device for the current service state. */ + public void onFoldStateChanged(int foldState) { + final long now = getTimeMillis(); + CellularServiceState lastServiceState = mLastState.get().mServiceState; + if (lastServiceState == null || lastServiceState.foldState == foldState) { + // Not need to update the fold state if modem is off or if is the + // same fold state + return; + } else { + TimestampedServiceState lastState = + mLastState.getAndUpdate( + state -> { + CellularServiceState newServiceState = copyOf(state.mServiceState); + newServiceState.foldState = foldState; + return new TimestampedServiceState(newServiceState, now); + }); + addServiceState(lastState, now); + } + } + private void addServiceState(TimestampedServiceState prevState, long now) { addServiceStateAndSwitch(prevState, now, null); } @@ -247,6 +270,7 @@ public class ServiceStateStats extends DataNetworkControllerCallback { copy.totalTimeMillis = state.totalTimeMillis; copy.isEmergencyOnly = state.isEmergencyOnly; copy.isInternetPdnUp = state.isInternetPdnUp; + copy.foldState = state.foldState; return copy; } diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 2f56f2ad90..b044814765 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN; + import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyString; @@ -109,6 +111,7 @@ import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsNrSaModeHandler; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; +import com.android.internal.telephony.metrics.DeviceStateHelper; import com.android.internal.telephony.metrics.ImsStats; import com.android.internal.telephony.metrics.MetricsCollector; import com.android.internal.telephony.metrics.PersistAtomsStorage; @@ -269,6 +272,7 @@ public abstract class TelephonyTest { protected DataServiceManager mMockedWlanDataServiceManager; protected ServiceStateStats mServiceStateStats; protected SatelliteController mSatelliteController; + protected DeviceStateHelper mDeviceStateHelper; // Initialized classes protected ActivityManager mActivityManager; @@ -504,6 +508,7 @@ public abstract class TelephonyTest { mMockedWlanDataServiceManager = Mockito.mock(DataServiceManager.class); mServiceStateStats = Mockito.mock(ServiceStateStats.class); mSatelliteController = Mockito.mock(SatelliteController.class); + mDeviceStateHelper = Mockito.mock(DeviceStateHelper.class); TelephonyManager.disableServiceHandleCaching(); PropertyInvalidatedCache.disableForTestMode(); @@ -828,6 +833,11 @@ public abstract class TelephonyTest { doReturn(null).when(mContext).getFileStreamPath(anyString()); doReturn(mPersistAtomsStorage).when(mMetricsCollector).getAtomsStorage(); doReturn(mWifiManager).when(mContext).getSystemService(eq(Context.WIFI_SERVICE)); + doReturn(mDeviceStateHelper).when(mMetricsCollector).getDeviceStateHelper(); + doReturn(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN) + .when(mDeviceStateHelper) + .getFoldState(); + doReturn(null).when(mContext).getSystemService(eq(Context.DEVICE_STATE_SERVICE)); //Use reflection to mock singletons replaceInstance(CallManager.class, "INSTANCE", null, mCallManager); 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 58864229e7..d4e1b86cda 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java @@ -104,7 +104,7 @@ public class MetricsCollectorTest extends TelephonyTest { mActivePort = mock(UiccPort.class); mServiceStateStats = mock(ServiceStateStats.class); mMetricsCollector = - new MetricsCollector(mContext, mPersistAtomsStorage); + new MetricsCollector(mContext, mPersistAtomsStorage, mDeviceStateHelper); doReturn(mSST).when(mSecondPhone).getServiceStateTracker(); doReturn(mServiceStateStats).when(mSST).getServiceStateStats(); } @@ -455,4 +455,4 @@ public class MetricsCollectorTest extends TelephonyTest { assertThat(actualAtoms).hasSize(4); assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS); } -} \ No newline at end of file +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java index 8885aa4f59..7b66a52e40 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java @@ -19,6 +19,8 @@ package com.android.internal.telephony.metrics; import static android.telephony.TelephonyManager.DATA_CONNECTED; import static android.telephony.TelephonyManager.DATA_UNKNOWN; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED; +import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN; 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; @@ -993,6 +995,47 @@ public class ServiceStateStatsTest extends TelephonyTest { mPhone, mServiceState, VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_UNKNOWN)); } + @Test + @SmallTest + public void onFoldStateChanged_modemOff() throws Exception { + doReturn(ServiceState.STATE_POWER_OFF).when(mServiceState).getVoiceRegState(); + doReturn(ServiceState.STATE_POWER_OFF).when(mServiceState).getDataRegState(); + doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getVoiceNetworkType(); + doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getDataNetworkType(); + mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN); + doReturn(-1).when(mPhone).getCarrierId(); + mServiceStateStats.onServiceStateChanged(mServiceState); + mServiceStateStats.incTimeMillis(100L); + + mServiceStateStats.onFoldStateChanged(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + + @Test + @SmallTest + public void onFoldStateChanged_LTEMode() throws Exception { + // Using default service state for LTE with fold state unknown + mServiceStateStats.onServiceStateChanged(mServiceState); + mServiceStateStats.incTimeMillis(100L); + mServiceStateStats.onFoldStateChanged(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED); + mServiceStateStats.incTimeMillis(1000L); + // Same fold state as before should not generate a new atom + mServiceStateStats.onFoldStateChanged(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED); + mServiceStateStats.incTimeMillis(1000L); + + // There should be 2 service state updates + mServiceStateStats.conclude(); + ArgumentCaptor captor = + ArgumentCaptor.forClass(CellularServiceState.class); + verify(mPersistAtomsStorage, times(2)) + .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null)); + CellularServiceState state = captor.getAllValues().get(0); + assertEquals(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN, state.foldState); + state = captor.getAllValues().get(1); + assertEquals(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED, state.foldState); + verifyNoMoreInteractions(mPersistAtomsStorage); + } + private void mockWwanPsRat(@NetworkType int rat) { mockWwanRat( NetworkRegistrationInfo.DOMAIN_PS, -- GitLab From d4a88433adfaf0e477599720f9c8873012b83fc6 Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Sat, 6 May 2023 06:28:28 +0000 Subject: [PATCH 645/656] Add Unit Tests for SatelliteController Bug: b/281206333 Test: Call/SMS/MMS with live network. atest SatelliteControllerTest Change-Id: Ifddee2fad20ab8a6b58e2861c8f00164973344e6 --- .../satellite/SatelliteControllerTest.java | 1029 +++++++++++++++-- 1 file changed, 964 insertions(+), 65 deletions(-) diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java index 180ea8337a..f6ed2e24df 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java @@ -16,7 +16,11 @@ package com.android.internal.telephony.satellite; +import static android.telephony.satellite.SatelliteManager.KEY_DEMO_MODE_ENABLED; +import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_CAPABILITIES; +import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED; import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_ENABLED; +import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_NEXT_VISIBILITY; import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_PROVISIONED; import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_SUPPORTED; import static android.telephony.satellite.SatelliteManager.NT_RADIO_TECHNOLOGY_EMTC_NTN; @@ -29,17 +33,21 @@ import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_MOD import static android.telephony.satellite.SatelliteManager.SATELLITE_INVALID_TELEPHONY_STATE; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF; import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE; +import static android.telephony.satellite.SatelliteManager.SATELLITE_NOT_AUTHORIZED; import static android.telephony.satellite.SatelliteManager.SATELLITE_NOT_SUPPORTED; import static android.telephony.satellite.SatelliteManager.SATELLITE_NO_RESOURCES; import static android.telephony.satellite.SatelliteManager.SATELLITE_RADIO_NOT_AVAILABLE; import static android.telephony.satellite.SatelliteManager.SATELLITE_REQUEST_IN_PROGRESS; import static android.telephony.satellite.SatelliteManager.SATELLITE_SERVICE_NOT_PROVISIONED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_SERVICE_PROVISION_IN_PROGRESS; import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_MODE_ENABLED_FALSE; import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_MODE_ENABLED_TRUE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -59,7 +67,9 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncResult; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Handler; +import android.os.ICancellationSignal; import android.os.Looper; import android.os.Message; import android.os.ResultReceiver; @@ -67,6 +77,7 @@ import android.telephony.Rlog; import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.ISatelliteProvisionStateCallback; import android.telephony.satellite.ISatelliteStateCallback; +import android.telephony.satellite.ISatelliteTransmissionUpdateCallback; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; @@ -76,6 +87,7 @@ import android.testing.TestableLooper; import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.IVoidConsumer; +import com.android.internal.telephony.Phone; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats; @@ -105,6 +117,8 @@ public class SatelliteControllerTest extends TelephonyTest { private static final long TIMEOUT = 500; private static final int SUB_ID = 0; private static final int MAX_BYTES_PER_OUT_GOING_DATAGRAM = 339; + private static final String TEST_SATELLITE_TOKEN = "TEST_SATELLITE_TOKEN"; + private static final String TEST_NEXT_SATELLITE_TOKEN = "TEST_NEXT_SATELLITE_TOKEN"; private TestSatelliteController mSatelliteControllerUT; private TestSharedPreferences mSharedPreferences; @@ -116,8 +130,9 @@ public class SatelliteControllerTest extends TelephonyTest { @Mock private ControllerMetricsStats mMockControllerMetricsStats; @Mock private ProvisionMetricsStats mMockProvisionMetricsStats; @Mock private SessionMetricsStats mMockSessionMetricsStats; - private List mIIntegerConsumerResults = new ArrayList<>(); + @Mock private ISatelliteTransmissionUpdateCallback mStartTransmissionUpdateCallback; + @Mock private ISatelliteTransmissionUpdateCallback mStopTransmissionUpdateCallback; private Semaphore mIIntegerConsumerSemaphore = new Semaphore(0); private IIntegerConsumer mIIntegerConsumer = new IIntegerConsumer.Stub() { @Override @@ -141,6 +156,32 @@ public class SatelliteControllerTest extends TelephonyTest { private SatelliteCapabilities mSatelliteCapabilities = new SatelliteCapabilities( mSupportedRadioTechnologies, mIsPointingRequired, MAX_BYTES_PER_OUT_GOING_DATAGRAM, new HashMap<>()); + private Semaphore mSatelliteCapabilitiesSemaphore = new Semaphore(0); + private SatelliteCapabilities mQueriedSatelliteCapabilities = null; + private int mQueriedSatelliteCapabilitiesResultCode = SATELLITE_ERROR_NONE; + private ResultReceiver mSatelliteCapabilitiesReceiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + mQueriedSatelliteCapabilitiesResultCode = resultCode; + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_CAPABILITIES)) { + mQueriedSatelliteCapabilities = resultData.getParcelable( + KEY_SATELLITE_CAPABILITIES, SatelliteCapabilities.class); + } else { + loge("KEY_SATELLITE_SUPPORTED does not exist."); + mQueriedSatelliteCapabilities = null; + } + } else { + logd("mSatelliteSupportReceiver: resultCode=" + resultCode); + mQueriedSatelliteCapabilities = null; + } + try { + mSatelliteCapabilitiesSemaphore.release(); + } catch (Exception ex) { + loge("mSatelliteSupportReceiver: Got exception in releasing semaphore, ex=" + ex); + } + } + }; private boolean mQueriedSatelliteSupported = false; private int mQueriedSatelliteSupportedResultCode = SATELLITE_ERROR_NONE; @@ -194,6 +235,32 @@ public class SatelliteControllerTest extends TelephonyTest { } }; + private boolean mQueriedIsDemoModeEnabled = false; + private int mQueriedIsDemoModeEnabledResultCode = SATELLITE_ERROR_NONE; + private Semaphore mIsDemoModeEnabledSemaphore = new Semaphore(0); + private ResultReceiver mIsDemoModeEnabledReceiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + mQueriedIsDemoModeEnabledResultCode = resultCode; + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_DEMO_MODE_ENABLED)) { + mQueriedIsDemoModeEnabled = resultData.getBoolean(KEY_DEMO_MODE_ENABLED); + } else { + loge("KEY_DEMO_MODE_ENABLED does not exist."); + mQueriedIsDemoModeEnabled = false; + } + } else { + logd("mIsSatelliteEnableReceiver: resultCode=" + resultCode); + mQueriedIsDemoModeEnabled = false; + } + try { + mIsDemoModeEnabledSemaphore.release(); + } catch (Exception ex) { + loge("mIsDemoModeEnabledReceiver: Got exception in releasing semaphore, ex=" + ex); + } + } + }; + private boolean mQueriedIsSatelliteProvisioned = false; private int mQueriedIsSatelliteProvisionedResultCode = SATELLITE_ERROR_NONE; private Semaphore mIsSatelliteProvisionedSemaphore = new Semaphore(0); @@ -221,6 +288,62 @@ public class SatelliteControllerTest extends TelephonyTest { } }; + private boolean mQueriedSatelliteAllowed = false; + private int mQueriedSatelliteAllowedResultCode = SATELLITE_ERROR_NONE; + private Semaphore mSatelliteAllowedSemaphore = new Semaphore(0); + private ResultReceiver mSatelliteAllowedReceiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + mQueriedSatelliteAllowedResultCode = resultCode; + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) { + mQueriedSatelliteAllowed = resultData.getBoolean( + KEY_SATELLITE_COMMUNICATION_ALLOWED); + } else { + loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist."); + mQueriedSatelliteAllowed = false; + } + } else { + logd("mSatelliteSupportReceiver: resultCode=" + resultCode); + mQueriedSatelliteAllowed = false; + } + try { + mSatelliteAllowedSemaphore.release(); + } catch (Exception ex) { + loge("mSatelliteAllowedReceiver: Got exception in releasing semaphore, ex=" + ex); + } + } + }; + + private int mQueriedSatelliteVisibilityTime = -1; + private int mSatelliteNextVisibilityTime = 3600; + private int mQueriedSatelliteVisibilityTimeResultCode = SATELLITE_ERROR_NONE; + private Semaphore mSatelliteVisibilityTimeSemaphore = new Semaphore(0); + private ResultReceiver mSatelliteVisibilityTimeReceiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + mQueriedSatelliteVisibilityTimeResultCode = resultCode; + if (resultCode == SATELLITE_ERROR_NONE) { + if (resultData.containsKey(KEY_SATELLITE_NEXT_VISIBILITY)) { + mQueriedSatelliteVisibilityTime = resultData.getInt( + KEY_SATELLITE_NEXT_VISIBILITY); + } else { + loge("KEY_SATELLITE_NEXT_VISIBILITY does not exist."); + mQueriedSatelliteVisibilityTime = -1; + } + } else { + logd("mSatelliteSupportReceiver: resultCode=" + resultCode); + mQueriedSatelliteVisibilityTime = -1; + } + try { + mSatelliteVisibilityTimeSemaphore.release(); + } catch (Exception ex) { + loge("mSatelliteAllowedReceiver: Got exception in releasing semaphore, ex=" + ex); + } + } + }; + + @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); @@ -262,6 +385,12 @@ public class SatelliteControllerTest extends TelephonyTest { .when(mMockSessionMetricsStats).setRadioTechnology(anyInt()); doNothing().when(mMockSessionMetricsStats).reportSessionMetrics(); + doReturn(mMockProvisionMetricsStats).when(mMockProvisionMetricsStats) + .setResultCode(anyInt()); + doReturn(mMockProvisionMetricsStats).when(mMockProvisionMetricsStats) + .setIsProvisionRequest(eq(false)); + doNothing().when(mMockProvisionMetricsStats).reportProvisionMetrics(); + doNothing().when(mMockControllerMetricsStats).reportDeprovisionCount(anyInt()); mSatelliteControllerUT = new TestSatelliteController(mContext, Looper.myLooper()); verify(mMockSatelliteModemInterface).registerForSatelliteProvisionStateChanged( any(Handler.class), @@ -284,6 +413,140 @@ public class SatelliteControllerTest extends TelephonyTest { super.tearDown(); } + @Test + public void testRequestIsSatelliteCommunicationAllowedForCurrentLocation() { + mSatelliteAllowedSemaphore.drainPermits(); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID, + mSatelliteAllowedReceiver); + processAllMessages(); + assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1)); + assertEquals(SATELLITE_NOT_SUPPORTED, mQueriedSatelliteAllowedResultCode); + + resetSatelliteControllerUT(); + mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID, + mSatelliteAllowedReceiver); + processAllMessages(); + assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteAllowedResultCode); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteAllowedForCurrentLocation(true, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID, + mSatelliteAllowedReceiver); + processAllMessages(); + assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1)); + assertEquals(SATELLITE_ERROR_NONE, mQueriedSatelliteAllowedResultCode); + assertTrue(mQueriedSatelliteAllowed); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpNullResponseForRequestIsSatelliteAllowedForCurrentLocation(SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID, + mSatelliteAllowedReceiver); + processAllMessages(); + assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteAllowedResultCode); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpNullResponseForRequestIsSatelliteAllowedForCurrentLocation( + SATELLITE_INVALID_MODEM_STATE); + mSatelliteControllerUT.requestIsSatelliteCommunicationAllowedForCurrentLocation(SUB_ID, + mSatelliteAllowedReceiver); + processAllMessages(); + assertTrue(waitForRequestIsSatelliteAllowedForCurrentLocationResult(1)); + assertEquals(SATELLITE_INVALID_MODEM_STATE, mQueriedSatelliteAllowedResultCode); + } + + @Test + public void testRequestTimeForNextSatelliteVisibility() { + mSatelliteVisibilityTimeSemaphore.drainPermits(); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, + mSatelliteVisibilityTimeReceiver); + processAllMessages(); + assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); + assertEquals(SATELLITE_NOT_SUPPORTED, mQueriedSatelliteVisibilityTimeResultCode); + + resetSatelliteControllerUT(); + mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, + mSatelliteVisibilityTimeReceiver); + processAllMessages(); + assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteVisibilityTimeResultCode); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestTimeForNextSatelliteVisibility(mSatelliteNextVisibilityTime, + SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, + mSatelliteVisibilityTimeReceiver); + processAllMessages(); + assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteVisibilityTimeResultCode); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForRequestTimeForNextSatelliteVisibility(mSatelliteNextVisibilityTime, + SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, + mSatelliteVisibilityTimeReceiver); + processAllMessages(); + assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); + assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, mQueriedSatelliteVisibilityTimeResultCode); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestTimeForNextSatelliteVisibility(mSatelliteNextVisibilityTime, + SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, + mSatelliteVisibilityTimeReceiver); + processAllMessages(); + assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); + assertEquals(SATELLITE_ERROR_NONE, mQueriedSatelliteVisibilityTimeResultCode); + assertEquals(mSatelliteNextVisibilityTime, mQueriedSatelliteVisibilityTime); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpNullResponseForRequestTimeForNextSatelliteVisibility( + SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, + mSatelliteVisibilityTimeReceiver); + processAllMessages(); + assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteVisibilityTimeResultCode); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpNullResponseForRequestTimeForNextSatelliteVisibility( + SATELLITE_INVALID_MODEM_STATE); + mSatelliteControllerUT.requestTimeForNextSatelliteVisibility(SUB_ID, + mSatelliteVisibilityTimeReceiver); + processAllMessages(); + assertTrue(waitForRequestTimeForNextSatelliteVisibilityResult(1)); + assertEquals(SATELLITE_INVALID_MODEM_STATE, mQueriedSatelliteVisibilityTimeResultCode); + } + @Test public void testRequestSatelliteEnabled() { mIsSatelliteEnabledSemaphore.drainPermits(); @@ -503,94 +766,346 @@ public class SatelliteControllerTest extends TelephonyTest { } @Test - public void testOnSatelliteServiceConnected() { - verifySatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); - verifySatelliteEnabled(false, SATELLITE_INVALID_TELEPHONY_STATE); - verifySatelliteProvisioned(false, SATELLITE_INVALID_TELEPHONY_STATE); + public void testRequestSatelliteCapabilities() { + mSatelliteCapabilitiesSemaphore.drainPermits(); + mSatelliteControllerUT.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); + processAllMessages(); + assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteCapabilitiesResultCode); + + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); + processAllMessages(); + assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); + assertEquals(SATELLITE_NOT_SUPPORTED, mQueriedSatelliteCapabilitiesResultCode); + resetSatelliteControllerUT(); setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); - setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteCapabilities(mSatelliteCapabilities, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); + processAllMessages(); + assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); + assertEquals(SATELLITE_ERROR_NONE, mQueriedSatelliteCapabilitiesResultCode); + assertEquals(mSatelliteCapabilities, mQueriedSatelliteCapabilities); - mSatelliteControllerUT.onSatelliteServiceConnected(); + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpNullResponseForRequestSatelliteCapabilities(SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); processAllMessages(); + assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedSatelliteCapabilitiesResultCode); + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpNullResponseForRequestSatelliteCapabilities(SATELLITE_INVALID_MODEM_STATE); verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); - verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestSatelliteCapabilities(SUB_ID, mSatelliteCapabilitiesReceiver); + processAllMessages(); + assertTrue(waitForRequestSatelliteCapabilitiesResult(1)); + assertEquals(SATELLITE_INVALID_MODEM_STATE, mQueriedSatelliteCapabilitiesResultCode); } @Test - public void testRegisterForSatelliteModemStateChanged() { - ISatelliteStateCallback callback = new ISatelliteStateCallback.Stub() { - @Override - public void onSatelliteModemStateChanged(int state) { - logd("onSatelliteModemStateChanged: state=" + state); - } - }; - int errorCode = mSatelliteControllerUT.registerForSatelliteModemStateChanged( - SUB_ID, callback); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, errorCode); - verify(mMockSatelliteSessionController, never()) - .registerForSatelliteModemStateChanged(callback); + public void testStartSatelliteTransmissionUpdates() { + mIIntegerConsumerSemaphore.drainPermits(); + mIIntegerConsumerResults.clear(); + mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStartTransmissionUpdateCallback); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); - resetSatelliteControllerUTToSupportedAndProvisionedState(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStartTransmissionUpdateCallback); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); - errorCode = mSatelliteControllerUT.registerForSatelliteModemStateChanged( - SUB_ID, callback); - assertEquals(SATELLITE_ERROR_NONE, errorCode); - verify(mMockSatelliteSessionController).registerForSatelliteModemStateChanged(callback); - } + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStartTransmissionUpdateCallback); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); - @Test - public void testUnregisterForSatelliteModemStateChanged() { - ISatelliteStateCallback callback = new ISatelliteStateCallback.Stub() { - @Override - public void onSatelliteModemStateChanged(int state) { - logd("onSatelliteModemStateChanged: state=" + state); - } - }; - mSatelliteControllerUT.unregisterForSatelliteModemStateChanged(SUB_ID, callback); - verify(mMockSatelliteSessionController, never()) - .unregisterForSatelliteModemStateChanged(callback); + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForStartSatelliteTransmissionUpdates(SATELLITE_ERROR_NONE); + mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStartTransmissionUpdateCallback); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, (long) mIIntegerConsumerResults.get(0)); - resetSatelliteControllerUTToSupportedAndProvisionedState(); + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForStartSatelliteTransmissionUpdates(SATELLITE_ERROR_NONE); + mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStartTransmissionUpdateCallback); + verify(mMockPointingAppController).registerForSatelliteTransmissionUpdates(anyInt(), + eq(mStartTransmissionUpdateCallback), any()); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + verify(mMockPointingAppController).startSatelliteTransmissionUpdates(any(Message.class), + any(Phone.class)); + verify(mMockPointingAppController).setStartedSatelliteTransmissionUpdates(eq(true)); - mSatelliteControllerUT.unregisterForSatelliteModemStateChanged(SUB_ID, callback); - verify(mMockSatelliteSessionController).unregisterForSatelliteModemStateChanged(callback); + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForStartSatelliteTransmissionUpdates(SATELLITE_INVALID_TELEPHONY_STATE); + mSatelliteControllerUT.startSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStartTransmissionUpdateCallback); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + verify(mMockPointingAppController).unregisterForSatelliteTransmissionUpdates(anyInt(), + any(), eq(mStartTransmissionUpdateCallback), any(Phone.class)); + verify(mMockPointingAppController).setStartedSatelliteTransmissionUpdates(eq(false)); } @Test - public void testRegisterForSatelliteProvisionStateChanged() { - Semaphore semaphore = new Semaphore(0); - ISatelliteProvisionStateCallback callback = - new ISatelliteProvisionStateCallback.Stub() { - @Override - public void onSatelliteProvisionStateChanged(boolean provisioned) { - logd("onSatelliteProvisionStateChanged: provisioned=" + provisioned); - try { - semaphore.release(); - } catch (Exception ex) { - loge("onSatelliteProvisionStateChanged: Got exception in releasing " - + "semaphore, ex=" + ex); - } - } - }; - int errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( - SUB_ID, callback); - assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, errorCode); + public void testStopSatelliteTransmissionUpdates() { + mIIntegerConsumerSemaphore.drainPermits(); + mIIntegerConsumerResults.clear(); + mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStopTransmissionUpdateCallback); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + mIIntegerConsumerResults.clear(); setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); verifySatelliteSupported(false, SATELLITE_ERROR_NONE); - errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( - SUB_ID, callback); - assertEquals(SATELLITE_NOT_SUPPORTED, errorCode); + mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStopTransmissionUpdateCallback); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); verifySatelliteSupported(true, SATELLITE_ERROR_NONE); - errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( - SUB_ID, callback); + mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStopTransmissionUpdateCallback); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForStopSatelliteTransmissionUpdates(SATELLITE_ERROR_NONE); + mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStopTransmissionUpdateCallback); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, (long) mIIntegerConsumerResults.get(0)); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForStopSatelliteTransmissionUpdates(SATELLITE_ERROR_NONE); + mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStopTransmissionUpdateCallback); + verify(mMockPointingAppController).unregisterForSatelliteTransmissionUpdates(anyInt(), + any(), eq(mStopTransmissionUpdateCallback), any(Phone.class)); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + verify(mMockPointingAppController).stopSatelliteTransmissionUpdates(any(Message.class), + any(Phone.class)); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForStopSatelliteTransmissionUpdates(SATELLITE_INVALID_TELEPHONY_STATE); + mSatelliteControllerUT.stopSatelliteTransmissionUpdates(SUB_ID, mIIntegerConsumer, + mStopTransmissionUpdateCallback); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + } + + @Test + public void testRequestIsDemoModeEnabled() { + mIsDemoModeEnabledSemaphore.drainPermits(); + resetSatelliteControllerUT(); + mSatelliteControllerUT.requestIsDemoModeEnabled(SUB_ID, mIsDemoModeEnabledReceiver); + assertTrue(waitForRequestIsDemoModeEnabledResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedIsDemoModeEnabledResultCode); + assertFalse(mQueriedIsDemoModeEnabled); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestIsDemoModeEnabled(SUB_ID, mIsDemoModeEnabledReceiver); + assertTrue(waitForRequestIsDemoModeEnabledResult(1)); + assertEquals(SATELLITE_NOT_SUPPORTED, mQueriedIsDemoModeEnabledResultCode); + assertFalse(mQueriedIsDemoModeEnabled); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestIsDemoModeEnabled(SUB_ID, mIsDemoModeEnabledReceiver); + assertTrue(waitForRequestIsDemoModeEnabledResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, mQueriedIsDemoModeEnabledResultCode); + assertFalse(mQueriedIsDemoModeEnabled); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestIsDemoModeEnabled(SUB_ID, mIsDemoModeEnabledReceiver); + assertTrue(waitForRequestIsDemoModeEnabledResult(1)); + assertEquals(SATELLITE_SERVICE_NOT_PROVISIONED, mQueriedIsDemoModeEnabledResultCode); + assertFalse(mQueriedIsDemoModeEnabled); + + resetSatelliteControllerUT(); + boolean isDemoModeEnabled = mSatelliteControllerUT.isDemoModeEnabled(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.requestIsDemoModeEnabled(SUB_ID, mIsDemoModeEnabledReceiver); + assertTrue(waitForRequestIsDemoModeEnabledResult(1)); + assertEquals(SATELLITE_ERROR_NONE, mQueriedIsDemoModeEnabledResultCode); + assertEquals(isDemoModeEnabled, mQueriedIsDemoModeEnabled); + } + + @Test + public void testIsSatelliteEnabled() { + assertFalse(mSatelliteControllerUT.isSatelliteEnabled()); + setUpResponseForRequestIsSatelliteEnabled(true, SATELLITE_ERROR_NONE); + mIsSatelliteEnabledSemaphore.drainPermits(); + mSatelliteControllerUT.requestIsSatelliteEnabled(SUB_ID, mIsSatelliteEnabledReceiver); + processAllMessages(); + assertTrue(waitForRequestIsSatelliteEnabledResult(1)); + assertEquals(mSatelliteControllerUT.isSatelliteEnabled(), mQueriedIsSatelliteEnabled); + } + + @Test + public void testOnSatelliteServiceConnected() { + verifySatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); + verifySatelliteEnabled(false, SATELLITE_INVALID_TELEPHONY_STATE); + verifySatelliteProvisioned(false, SATELLITE_INVALID_TELEPHONY_STATE); + + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestSatelliteEnabled(false, false, SATELLITE_ERROR_NONE); + + mSatelliteControllerUT.onSatelliteServiceConnected(); + processAllMessages(); + + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteEnabled(false, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + } + + @Test + public void testRegisterForSatelliteModemStateChanged() { + ISatelliteStateCallback callback = new ISatelliteStateCallback.Stub() { + @Override + public void onSatelliteModemStateChanged(int state) { + logd("onSatelliteModemStateChanged: state=" + state); + } + }; + int errorCode = mSatelliteControllerUT.registerForSatelliteModemStateChanged( + SUB_ID, callback); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, errorCode); + verify(mMockSatelliteSessionController, never()) + .registerForSatelliteModemStateChanged(callback); + + resetSatelliteControllerUTToSupportedAndProvisionedState(); + + errorCode = mSatelliteControllerUT.registerForSatelliteModemStateChanged( + SUB_ID, callback); + assertEquals(SATELLITE_ERROR_NONE, errorCode); + verify(mMockSatelliteSessionController).registerForSatelliteModemStateChanged(callback); + } + + @Test + public void testUnregisterForSatelliteModemStateChanged() { + ISatelliteStateCallback callback = new ISatelliteStateCallback.Stub() { + @Override + public void onSatelliteModemStateChanged(int state) { + logd("onSatelliteModemStateChanged: state=" + state); + } + }; + mSatelliteControllerUT.unregisterForSatelliteModemStateChanged(SUB_ID, callback); + verify(mMockSatelliteSessionController, never()) + .unregisterForSatelliteModemStateChanged(callback); + + resetSatelliteControllerUTToSupportedAndProvisionedState(); + + mSatelliteControllerUT.unregisterForSatelliteModemStateChanged(SUB_ID, callback); + verify(mMockSatelliteSessionController).unregisterForSatelliteModemStateChanged(callback); + } + + @Test + public void testRegisterForSatelliteProvisionStateChanged() { + Semaphore semaphore = new Semaphore(0); + ISatelliteProvisionStateCallback callback = + new ISatelliteProvisionStateCallback.Stub() { + @Override + public void onSatelliteProvisionStateChanged(boolean provisioned) { + logd("onSatelliteProvisionStateChanged: provisioned=" + provisioned); + try { + semaphore.release(); + } catch (Exception ex) { + loge("onSatelliteProvisionStateChanged: Got exception in releasing " + + "semaphore, ex=" + ex); + } + } + }; + int errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( + SUB_ID, callback); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, errorCode); + + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( + SUB_ID, callback); + assertEquals(SATELLITE_NOT_SUPPORTED, errorCode); + + resetSatelliteControllerUT(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + errorCode = mSatelliteControllerUT.registerForSatelliteProvisionStateChanged( + SUB_ID, callback); assertEquals(SATELLITE_ERROR_NONE, errorCode); sendProvisionedStateChangedEvent(true, null); @@ -715,6 +1230,191 @@ public class SatelliteControllerTest extends TelephonyTest { verify(mMockDatagramController, times(1)).pollPendingSatelliteDatagrams(anyInt(), any()); } + @Test + public void testProvisionSatelliteService() { + String mText = "This is test provision data."; + byte[] testProvisionData = mText.getBytes(); + CancellationSignal cancellationSignal = new CancellationSignal(); + ICancellationSignal cancelRemote = null; + mIIntegerConsumerResults.clear(); + cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, + testProvisionData, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + assertNull(cancelRemote); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, + testProvisionData, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); + assertNull(cancelRemote); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, + testProvisionData, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + assertNull(cancelRemote); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForProvisionSatelliteService(TEST_SATELLITE_TOKEN, testProvisionData, + SATELLITE_ERROR_NONE); + cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, + testProvisionData, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + assertNotNull(cancelRemote); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForProvisionSatelliteService(TEST_SATELLITE_TOKEN, testProvisionData, + SATELLITE_NOT_AUTHORIZED); + cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, + testProvisionData, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_NOT_AUTHORIZED, (long) mIIntegerConsumerResults.get(0)); + assertNotNull(cancelRemote); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForProvisionSatelliteService(TEST_NEXT_SATELLITE_TOKEN, testProvisionData, + SATELLITE_ERROR_NONE); + cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, + TEST_NEXT_SATELLITE_TOKEN, testProvisionData, mIIntegerConsumer); + cancellationSignal.setRemote(cancelRemote); + cancellationSignal.cancel(); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + verify(mMockSatelliteModemInterface).deprovisionSatelliteService( + eq(TEST_NEXT_SATELLITE_TOKEN), any(Message.class)); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpNoResponseForProvisionSatelliteService(TEST_SATELLITE_TOKEN); + setUpResponseForProvisionSatelliteService(TEST_NEXT_SATELLITE_TOKEN, testProvisionData, + SATELLITE_ERROR_NONE); + cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, + testProvisionData, mIIntegerConsumer); + cancelRemote = mSatelliteControllerUT.provisionSatelliteService(SUB_ID, + TEST_NEXT_SATELLITE_TOKEN, + testProvisionData, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_SERVICE_PROVISION_IN_PROGRESS, + (long) mIIntegerConsumerResults.get(0)); + } + + @Test + public void testDeprovisionSatelliteService() { + mIIntegerConsumerSemaphore.drainPermits(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(false, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_NOT_SUPPORTED, (long) mIIntegerConsumerResults.get(0)); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_TELEPHONY_STATE, (long) mIIntegerConsumerResults.get(0)); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(false, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(false, SATELLITE_ERROR_NONE); + setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, SATELLITE_ERROR_NONE); + mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_ERROR_NONE, (long) mIIntegerConsumerResults.get(0)); + + resetSatelliteControllerUT(); + mIIntegerConsumerResults.clear(); + setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_ERROR_NONE); + setUpResponseForRequestIsSatelliteProvisioned(true, SATELLITE_ERROR_NONE); + verifySatelliteSupported(true, SATELLITE_ERROR_NONE); + verifySatelliteProvisioned(true, SATELLITE_ERROR_NONE); + setUpResponseForDeprovisionSatelliteService(TEST_SATELLITE_TOKEN, + SATELLITE_INVALID_MODEM_STATE); + mSatelliteControllerUT.deprovisionSatelliteService(SUB_ID, + TEST_SATELLITE_TOKEN, mIIntegerConsumer); + processAllMessages(); + assertTrue(waitForIIntegerConsumerResult(1)); + assertEquals(SATELLITE_INVALID_MODEM_STATE, (long) mIIntegerConsumerResults.get(0)); + + } + private void resetSatelliteControllerUTEnabledState() { logd("resetSatelliteControllerUTEnabledState"); setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RADIO_NOT_AVAILABLE); @@ -773,6 +1473,18 @@ public class SatelliteControllerTest extends TelephonyTest { verifySatelliteEnabled(true, SATELLITE_ERROR_NONE); } + private void setUpResponseForRequestIsSatelliteEnabled(boolean isSatelliteEnabled, + @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, isSatelliteEnabled, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).requestIsSatelliteEnabled(any(Message.class)); + } + private void setUpResponseForRequestIsSatelliteSupported( boolean isSatelliteSupported, @SatelliteManager.SatelliteError int error) { SatelliteException exception = (error == SATELLITE_ERROR_NONE) @@ -785,6 +1497,59 @@ public class SatelliteControllerTest extends TelephonyTest { }).when(mMockSatelliteModemInterface).requestIsSatelliteSupported(any(Message.class)); } + private void setUpResponseForRequestIsSatelliteAllowedForCurrentLocation( + boolean isSatelliteAllowed, @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, isSatelliteAllowed, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface) + .requestIsSatelliteCommunicationAllowedForCurrentLocation(any(Message.class)); + } + + private void setUpNullResponseForRequestIsSatelliteAllowedForCurrentLocation( + @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface) + .requestIsSatelliteCommunicationAllowedForCurrentLocation(any(Message.class)); + } + + private void setUpResponseForRequestTimeForNextSatelliteVisibility( + int satelliteVisibilityTime, @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + int[] visibilityTime = new int[] {satelliteVisibilityTime}; + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, visibilityTime, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface) + .requestTimeForNextSatelliteVisibility(any(Message.class)); + } + + private void setUpNullResponseForRequestTimeForNextSatelliteVisibility( + @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface) + .requestTimeForNextSatelliteVisibility(any(Message.class)); + } + private void setUpResponseForRequestIsSatelliteProvisioned( boolean isSatelliteProvisioned, @SatelliteManager.SatelliteError int error) { SatelliteException exception = (error == SATELLITE_ERROR_NONE) @@ -816,6 +1581,37 @@ public class SatelliteControllerTest extends TelephonyTest { .requestSatelliteEnabled(eq(enabled), eq(demoMode), any(Message.class)); } + private void setUpResponseForProvisionSatelliteService( + String token, byte[] provisionData, @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[2]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface) + .provisionSatelliteService(eq(token), any(byte[].class), any(Message.class)); + } + + private void setUpNoResponseForProvisionSatelliteService(String token) { + doNothing().when(mMockSatelliteModemInterface) + .provisionSatelliteService(eq(token), any(), any(Message.class)); + } + + private void setUpResponseForDeprovisionSatelliteService(String token, + @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[1]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface) + .deprovisionSatelliteService(eq(token), any(Message.class)); + } + private void setUpResponseForRequestSatelliteCapabilities( SatelliteCapabilities satelliteCapabilities, @SatelliteManager.SatelliteError int error) { @@ -845,6 +1641,44 @@ public class SatelliteControllerTest extends TelephonyTest { return true; } + private void setUpNullResponseForRequestSatelliteCapabilities( + @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockSatelliteModemInterface).requestSatelliteCapabilities(any(Message.class)); + } + + private void setUpResponseForStartSatelliteTransmissionUpdates( + @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockPointingAppController).startSatelliteTransmissionUpdates(any(Message.class), + any()); + } + + private void setUpResponseForStopSatelliteTransmissionUpdates( + @SatelliteManager.SatelliteError int error) { + SatelliteException exception = (error == SATELLITE_ERROR_NONE) + ? null : new SatelliteException(error); + doAnswer(invocation -> { + Message message = (Message) invocation.getArguments()[0]; + AsyncResult.forMessage(message, null, exception); + message.sendToTarget(); + return null; + }).when(mMockPointingAppController).stopSatelliteTransmissionUpdates(any(Message.class), + any()); + } + private boolean waitForRequestIsSatelliteSupportedResult(int expectedNumberOfEvents) { for (int i = 0; i < expectedNumberOfEvents; i++) { try { @@ -860,6 +1694,41 @@ public class SatelliteControllerTest extends TelephonyTest { return true; } + private boolean waitForRequestIsSatelliteAllowedForCurrentLocationResult( + int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mSatelliteAllowedSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + loge("Timeout to receive " + + "requestIsSatelliteCommunicationAllowedForCurrentLocation()" + + " callback"); + return false; + } + } catch (Exception ex) { + loge("waitForRequestIsSatelliteSupportedResult: Got exception=" + ex); + return false; + } + } + return true; + } + + private boolean waitForRequestTimeForNextSatelliteVisibilityResult( + int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mSatelliteVisibilityTimeSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + loge("Timeout to receive " + + "requestTimeForNextSatelliteVisibility() callback"); + return false; + } + } catch (Exception ex) { + loge("waitForRequestTimeForNextSatelliteVisibilityResult: Got exception=" + ex); + return false; + } + } + return true; + } + private boolean waitForRequestIsSatelliteEnabledResult(int expectedNumberOfEvents) { for (int i = 0; i < expectedNumberOfEvents; i++) { try { @@ -890,6 +1759,36 @@ public class SatelliteControllerTest extends TelephonyTest { return true; } + private boolean waitForRequestSatelliteCapabilitiesResult(int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mSatelliteCapabilitiesSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + loge("Timeout to receive requestSatelliteCapabilities() callback"); + return false; + } + } catch (Exception ex) { + loge("waitForRequestSatelliteCapabilitiesResult: Got exception=" + ex); + return false; + } + } + return true; + } + + private boolean waitForRequestIsDemoModeEnabledResult(int expectedNumberOfEvents) { + for (int i = 0; i < expectedNumberOfEvents; i++) { + try { + if (!mIsDemoModeEnabledSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) { + loge("Timeout to receive requestIsDemoModeEnabled() callback"); + return false; + } + } catch (Exception ex) { + loge("waitForRequestIsDemoModeEnabled: Got exception=" + ex); + return false; + } + } + return true; + } + private boolean waitForIIntegerConsumerResult(int expectedNumberOfEvents) { for (int i = 0; i < expectedNumberOfEvents; i++) { try { -- GitLab From 38ac9f2abd97df7c2c160a7b9ba9b443fafba60d Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Mon, 8 May 2023 21:09:23 +0000 Subject: [PATCH 646/656] Cleanup testSatelliteModeRadios Bug: 280883393 Test: atest SatelliteManagerTestOnMockService Flashed build on raven-userdebug: calls/SMS/MMS are working fine Change-Id: I3ca610b302ac86d33a7c25c3736ca0806a5e54a4 --- .../satellite/DatagramController.java | 3 +- .../satellite/SatelliteController.java | 71 ++++++++++--------- .../satellite/DatagramDispatcherTest.java | 41 +++++++++++ .../satellite/DatagramReceiverTest.java | 71 +++++++++++++++++++ 4 files changed, 151 insertions(+), 35 deletions(-) diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java index 1b7333456e..e7f09c23ed 100644 --- a/src/java/com/android/internal/telephony/satellite/DatagramController.java +++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java @@ -276,7 +276,8 @@ public class DatagramController { mDatagramReceiver.onDeviceAlignedWithSatellite(isAligned); } - boolean isReceivingDatagrams() { + @VisibleForTesting + public boolean isReceivingDatagrams() { synchronized (mLock) { return (mReceiveDatagramTransferState == SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVING); diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java index 0ca6f8eef6..5cd84446c7 100644 --- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java +++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java @@ -285,15 +285,6 @@ public class SatelliteController extends Handler { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) protected void initializeSatelliteModeRadios() { - UwbManager uwbManager = mContext.getSystemService(UwbManager.class); - NfcManager nfcManager = mContext.getSystemService(NfcManager.class); - NfcAdapter nfcAdapter = null; - if (nfcManager != null) { - nfcAdapter = nfcManager.getDefaultAdapter(); - } - BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - WifiManager wifiManager = mContext.getSystemService(WifiManager.class); - if (mContentResolver != null) { BTWifiNFCStateReceiver bTWifiNFCSateReceiver = new BTWifiNFCStateReceiver(); UwbAdapterStateCallback uwbAdapterStateCallback = new UwbAdapterStateCallback(); @@ -320,38 +311,50 @@ public class SatelliteController extends Handler { } logd("Radios To be checked when satellite is on: " + satelliteModeRadios); - if (satelliteModeRadios.contains(Settings.Global.RADIO_BLUETOOTH) - && bluetoothAdapter != null) { - mDisableBTOnSatelliteEnabled = true; - mBTStateEnabled = bluetoothAdapter.isEnabled(); - radioStateIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); + if (satelliteModeRadios.contains(Settings.Global.RADIO_BLUETOOTH)) { + BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (bluetoothAdapter != null) { + mDisableBTOnSatelliteEnabled = true; + mBTStateEnabled = bluetoothAdapter.isEnabled(); + radioStateIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); + } } - if (satelliteModeRadios.contains(Settings.Global.RADIO_NFC) - && nfcAdapter != null) { - mDisableNFCOnSatelliteEnabled = true; - mNfcStateEnabled = nfcAdapter.isEnabled(); - radioStateIntentFilter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); + if (satelliteModeRadios.contains(Settings.Global.RADIO_NFC)) { + Context applicationContext = mContext.getApplicationContext(); + NfcAdapter nfcAdapter = null; + if (applicationContext != null) { + nfcAdapter = NfcAdapter.getDefaultAdapter(mContext.getApplicationContext()); + } + if (nfcAdapter != null) { + mDisableNFCOnSatelliteEnabled = true; + mNfcStateEnabled = nfcAdapter.isEnabled(); + radioStateIntentFilter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED); + } } - if (satelliteModeRadios.contains(Settings.Global.RADIO_WIFI) - && wifiManager != null) { - mDisableWifiOnSatelliteEnabled = true; - mWifiStateEnabled = wifiManager.isWifiEnabled(); - radioStateIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + if (satelliteModeRadios.contains(Settings.Global.RADIO_WIFI)) { + WifiManager wifiManager = mContext.getSystemService(WifiManager.class); + if (wifiManager != null) { + mDisableWifiOnSatelliteEnabled = true; + mWifiStateEnabled = wifiManager.isWifiEnabled(); + radioStateIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + } } mContext.registerReceiver(bTWifiNFCSateReceiver, radioStateIntentFilter); - if (satelliteModeRadios.contains(Settings.Global.RADIO_UWB) - && uwbManager != null) { - mDisableUWBOnSatelliteEnabled = true; - mUwbStateEnabled = uwbManager.isUwbEnabled(); - final long identity = Binder.clearCallingIdentity(); - try { - uwbManager.registerAdapterStateCallback(mContext.getMainExecutor(), - uwbAdapterStateCallback); - } finally { - Binder.restoreCallingIdentity(identity); + if (satelliteModeRadios.contains(Settings.Global.RADIO_UWB)) { + UwbManager uwbManager = mContext.getSystemService(UwbManager.class); + if (uwbManager != null) { + mDisableUWBOnSatelliteEnabled = true; + mUwbStateEnabled = uwbManager.isUwbEnabled(); + final long identity = Binder.clearCallingIdentity(); + try { + uwbManager.registerAdapterStateCallback(mContext.getMainExecutor(), + uwbAdapterStateCallback); + } finally { + Binder.restoreCallingIdentity(identity); + } } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java index bf02bb0182..bc1d7674ad 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java @@ -428,6 +428,47 @@ public class DatagramDispatcherTest extends TelephonyTest { verifyNoMoreInteractions(mMockDatagramController); } + @Test + public void testOnSatelliteModemStateChanged_modemStateListening() { + mDatagramDispatcherUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_LISTENING); + processAllMessages(); + verifyNoMoreInteractions(mMockDatagramController); + } + + @Test + public void testOnSatelliteModemStateChanged_modemStateOff_modemSendingDatagrams() { + mDatagramDispatcherUT.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram, + true, mResultListener::offer); + + mDatagramDispatcherUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_OFF); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(anyInt(), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED), + eq(1), eq(SatelliteManager.SATELLITE_REQUEST_ABORTED)); + mInOrder.verify(mMockDatagramController) + .updateSendStatus(anyInt(), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), + eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + } + + @Test + public void testOnSatelliteModemStateChanged_modemStateOff_modemNotSendingDatagrams() { + mDatagramDispatcherUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_OFF); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateSendStatus(anyInt(), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), + eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + } + private static class TestDatagramDispatcher extends DatagramDispatcher { private long mLong = SATELLITE_ALIGN_TIMEOUT; diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java index 709764610a..1c3777dc30 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java @@ -21,6 +21,7 @@ import static com.android.internal.telephony.satellite.DatagramController.SATELL import android.annotation.NonNull; import android.content.Context; import android.provider.Telephony; +import android.telephony.satellite.ISatelliteDatagramCallback; import android.test.mock.MockContentResolver; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -36,15 +37,19 @@ import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.os.AsyncResult; import android.os.Looper; import android.os.Message; +import android.os.IBinder; +import android.os.RemoteException; import android.telephony.satellite.SatelliteDatagram; import android.telephony.satellite.SatelliteManager; import android.util.Pair; +import com.android.internal.telephony.IVoidConsumer; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.TelephonyTest; @@ -73,6 +78,7 @@ public class DatagramReceiverTest extends TelephonyTest { private DatagramReceiver.SatelliteDatagramListenerHandler mSatelliteDatagramListenerHandler; private TestDatagramReceiver mTestDemoModeDatagramReceiver; + @Mock private SatelliteController mMockSatelliteController; @Mock private DatagramController mMockDatagramController; @Mock private SatelliteModemInterface mMockSatelliteModemInterface; @Mock private ControllerMetricsStats mMockControllerMetricsStats; @@ -97,6 +103,7 @@ public class DatagramReceiverTest extends TelephonyTest { Telephony.SatelliteDatagrams.PROVIDER_NAME, mFakeSatelliteProvider); doReturn(mMockContentResolver).when(mContext).getContentResolver(); + replaceInstance(SatelliteController.class, "sInstance", null, mMockSatelliteController); replaceInstance(DatagramController.class, "sInstance", null, mMockDatagramController); replaceInstance(SatelliteModemInterface.class, "sInstance", null, @@ -406,6 +413,70 @@ public class DatagramReceiverTest extends TelephonyTest { assertThat(mResultListener.peek()).isEqualTo(SatelliteManager.SATELLITE_MODEM_BUSY); } + @Test + public void testOnSatelliteModemStateChanged_modemStateIdle() { + mDatagramReceiverUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_IDLE); + processAllMessages(); + verifyNoMoreInteractions(mMockDatagramController); + } + + @Test + public void testOnSatelliteModemStateChanged_modemStateOff_modemReceivingDatagrams() { + when(mMockDatagramController.isReceivingDatagrams()).thenReturn(true); + when(mMockDatagramController.getReceivePendingCount()).thenReturn(10); + + mDatagramReceiverUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_OFF); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(anyInt(), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED), + eq(10), eq(SatelliteManager.SATELLITE_REQUEST_ABORTED)); + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(anyInt(), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), + eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + } + + @Test + public void testOnSatelliteModemStateChanged_modemStateOff_modemNotReceivingDatagrams() { + when(mMockDatagramController.isReceivingDatagrams()).thenReturn(false); + + mDatagramReceiverUT.onSatelliteModemStateChanged( + SatelliteManager.SATELLITE_MODEM_STATE_OFF); + + processAllMessages(); + + mInOrder.verify(mMockDatagramController) + .updateReceiveStatus(anyInt(), + eq(SatelliteManager.SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE), + eq(0), eq(SatelliteManager.SATELLITE_ERROR_NONE)); + } + + @Test + public void testRegisterForSatelliteDatagram_satelliteNotSupported() { + when(mMockSatelliteController.isSatelliteSupported()).thenReturn(false); + + ISatelliteDatagramCallback callback = new ISatelliteDatagramCallback() { + @Override + public void onSatelliteDatagramReceived(long datagramId, SatelliteDatagram datagram, + int pendingCount, IVoidConsumer callback) throws RemoteException { + logd("onSatelliteDatagramReceived"); + } + + @Override + public IBinder asBinder() { + return null; + } + }; + + assertThat(mDatagramReceiverUT.registerForSatelliteDatagram(SUB_ID, callback)) + .isEqualTo(SatelliteManager.SATELLITE_NOT_SUPPORTED); + } + private static class TestDatagramReceiver extends DatagramReceiver { private long mLong = SATELLITE_ALIGN_TIMEOUT; -- GitLab From 65debc1e8e2da2f8b861e77fca02bc0a42207054 Mon Sep 17 00:00:00 2001 From: Rafael Higuera Silva Date: Fri, 12 May 2023 04:25:38 +0000 Subject: [PATCH 647/656] Add fold state to voice call session Bug: 276772849 Test: make, atest com.android.internal.telephony.metrics and manual test Change-Id: I5d7236a9acbb89a759f0cb8727cd6626e7a91f83 Merged-In: I5d7236a9acbb89a759f0cb8727cd6626e7a91f83 --- proto/src/persist_atoms.proto | 1 + .../android/internal/telephony/metrics/MetricsCollector.java | 3 ++- .../internal/telephony/metrics/VoiceCallSessionStats.java | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto index fc3f0d0e9c..61e44a3c8f 100644 --- a/proto/src/persist_atoms.proto +++ b/proto/src/persist_atoms.proto @@ -274,6 +274,7 @@ message VoiceCallSession { optional bool is_multiparty = 31; optional int32 call_duration = 32; optional int32 last_known_rat = 33; + optional int32 fold_state = 34; // Internal use only optional int64 setup_begin_millis = 10001; diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java index aab55e6d39..5e00987911 100644 --- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java +++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java @@ -974,7 +974,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { session.ratAtConnected, session.isMultiparty, session.callDuration, - session.lastKnownRat); + session.lastKnownRat, + session.foldState); } private static StatsEvent buildStatsEvent(IncomingSms sms) { diff --git a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java index 91588e6402..ba07fa035a 100644 --- a/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java +++ b/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java @@ -157,6 +157,8 @@ public class VoiceCallSessionStats { private final PersistAtomsStorage mAtomsStorage = PhoneFactory.getMetricsCollector().getAtomsStorage(); private final UiccController mUiccController = UiccController.getInstance(); + private final DeviceStateHelper mDeviceStateHelper = + PhoneFactory.getMetricsCollector().getDeviceStateHelper(); public VoiceCallSessionStats(int phoneId, Phone phone) { mPhoneId = phoneId; @@ -514,6 +516,9 @@ public class VoiceCallSessionStats { // Update end RAT updateRatAtEnd(proto, getVoiceRatWithVoNRFix(mPhone, getServiceState(), proto.bearerAtEnd)); + // Set device fold state + proto.foldState = mDeviceStateHelper.getFoldState(); + mAtomsStorage.addVoiceCallSession(proto); // merge RAT usages to PersistPullers when the call session ends (i.e. no more active calls) -- GitLab From b8c1607bf48be81ee138fe790e2baf1eda953cf2 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 12 May 2023 22:31:21 -0700 Subject: [PATCH 648/656] Corretly handle SIM not ready state If SIM not ready is a final state, always mark subscription as inactive. Test: Basic phone funcationality tests Test: atest SubscriptionManagerServiceTests Test: Fi eSIM download/deactivate/activate tests on Pixel 5/6/7 Fix: 278920650 Change-Id: I1696a5b7f786772f4c7f64559ba76e8cc8318a72 --- .../subscription/SubscriptionManagerService.java | 5 +---- .../SubscriptionManagerServiceTest.java | 13 +++++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index d898bb3b39..f9720df6f1 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -46,7 +46,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.TelephonyServiceManager; import android.os.UserHandle; -import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Telephony.SimInfo; import android.service.carrier.CarrierIdentifier; @@ -1311,9 +1310,7 @@ public class SubscriptionManagerService extends ISub.Stub { log("updateSubscription: SIM_STATE_NOT_READY is not a final state. Will update " + "subscription later."); return; - } - - if (!areUiccAppsEnabledOnCard(phoneId)) { + } else { logl("updateSubscription: UICC app disabled on slot " + phoneId); markSubscriptionsInactive(phoneId); } 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 c52c6cc401..38b495aaca 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -2235,6 +2235,19 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty(); } + @Test + public void testSimNotReadyBySimDeactivate() { + insertSubscription(FAKE_SUBSCRIPTION_INFO1); + + mContextFixture.addCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + mSubscriptionManagerServiceUT.updateSimState( + 0, TelephonyManager.SIM_STATE_NOT_READY, null, null); + doReturn(true).when(mUiccProfile).isEmptyProfile(); + processAllMessages(); + + assertThat(mSubscriptionManagerServiceUT.getActiveSubIdList(false)).isEmpty(); + } + @Test public void testInactiveSimRemoval() { insertSubscription(FAKE_SUBSCRIPTION_INFO2); -- GitLab From 0acfea8d14a3959844736f30bb08c973fd926b36 Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Wed, 17 May 2023 14:53:51 -0700 Subject: [PATCH 649/656] update fallback logic to use cached country Existing code only falls back to cached location when service state is POWER_OFF. There can be race conditions when LocaleTracker updates country iso to NULL, but service state tracker still has not updated its state to POWER_OFF. This change is to always fallback to cached locale if current locale is not available. Bug: 282712991 Test: atest and b2b calls Change-Id: I5168a1e118768bb315601591ee31a5e799ff240d --- .../emergency/EmergencyNumberTracker.java | 2 +- .../emergency/EmergencyNumberTrackerTest.java | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java index a83569b275..9b44001785 100644 --- a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java +++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java @@ -684,7 +684,7 @@ public class EmergencyNumberTracker extends Handler { + countryIso); updateEmergencyCountryIso(countryIso.toLowerCase(Locale.ROOT)); // Use cached country iso in APM to load emergency number database. - if (TextUtils.isEmpty(countryIso) && isAirplaneModeEnabled()) { + if (TextUtils.isEmpty(countryIso)) { countryIso = getCountryIsoForCachingDatabase(); logd("updateEmergencyNumberListDatabaseAndNotify(): using cached APM country " + countryIso); diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java index f7ea4b66f9..c47eb3beae 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java @@ -40,6 +40,7 @@ import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; +import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.emergency.EmergencyNumber; @@ -50,6 +51,7 @@ import androidx.test.InstrumentationRegistry; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneFactory; +import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyTest; import com.google.i18n.phonenumbers.ShortNumberInfo; @@ -368,8 +370,31 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { IntentFilter ifilter = intentCaptor.getValue(); assertTrue(ifilter.hasAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED)); } + + @Test + public void testUpdateEmergencyCountryIso_whenStatePowerOff() throws Exception { + testUpdateEmergencyCountryIso(ServiceState.STATE_POWER_OFF); + } + + @Test + public void testUpdateEmergencyCountryIso_whenStateInService() throws Exception { + testUpdateEmergencyCountryIso(ServiceState.STATE_IN_SERVICE); + } + @Test - public void testUpdateEmergencyCountryIso() throws Exception { + public void testUpdateEmergencyCountryIso_whenStateOos() throws Exception { + testUpdateEmergencyCountryIso(ServiceState.STATE_OUT_OF_SERVICE); + } + + @Test + public void testUpdateEmergencyCountryIso_whenStateEmergencyOnly() throws Exception { + testUpdateEmergencyCountryIso(ServiceState.STATE_EMERGENCY_ONLY); + } + + private void testUpdateEmergencyCountryIso(int ss) throws Exception { + doReturn(mLocaleTracker).when(mSST).getLocaleTracker(); + doReturn("us").when(mLocaleTracker).getLastKnownCountryIso(); + sendEmergencyNumberPrefix(mEmergencyNumberTrackerMock); mEmergencyNumberTrackerMock.updateEmergencyNumberDatabaseCountryChange("us"); @@ -377,10 +402,14 @@ public class EmergencyNumberTrackerTest extends TelephonyTest { assertTrue(mEmergencyNumberTrackerMock.getEmergencyCountryIso().equals("us")); assertTrue(mEmergencyNumberTrackerMock.getLastKnownEmergencyCountryIso().equals("us")); + doReturn(ss).when(mServiceState).getState(); mEmergencyNumberTrackerMock.updateEmergencyNumberDatabaseCountryChange(""); processAllMessages(); assertTrue(mEmergencyNumberTrackerMock.getEmergencyCountryIso().equals("")); assertTrue(mEmergencyNumberTrackerMock.getLastKnownEmergencyCountryIso().equals("us")); + + //make sure we look up cached location whenever current iso is null + verify(mLocaleTracker).getLastKnownCountryIso(); } @Test -- GitLab From a6def0c9be0e25ddb9e06e48f26aab1732101a11 Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Wed, 24 May 2023 17:27:34 +0000 Subject: [PATCH 650/656] Remap CODE_SIP_BAD_REQUEST to SERVER_ERROR for outgoing calls. The vendor IMS stack can report a number of disconnect causes for incoming calls which were rejected on the device by the lower levels and as a consequence become "auto missed calls". CODE_SIP_BAD_REQUEST is one of the codes that can be reported which we will attribute as an "auto missed call". However, it is ALSO possible for an outgoing call to return that same disconnect code, which we should not remap to the auto rejected cause. Added a check to ensure that if the call state is dialing or alerting we will remap to SERVER_ERROR rather than the auto-missed disconnect code. This ensures failed outgoing calls don't get treated as missed incomign calls. Fixes: 281320323 Test: Added unit test for disconnect cause remapping. Change-Id: Ib272858cca7f6bd1694183e7f090fe1cdbe45b27 --- .../imsphone/ImsPhoneCallTracker.java | 7 ++++ .../imsphone/ImsPhoneCallTrackerTest.java | 37 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index 7a9c56f87c..c3ee0f6060 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -3389,6 +3389,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { break; case ImsReasonInfo.CODE_SIP_BAD_REQUEST: + // Auto-missed/rejected calls can sometimes use this reason cause, but if we see it + // for outgoing calls it is just a server error. + if (callState == Call.State.DIALING || callState == Call.State.ALERTING) { + return DisconnectCause.SERVER_ERROR; + } else { + return DisconnectCause.INCOMING_AUTO_REJECTED; + } case ImsReasonInfo.CODE_REJECT_CALL_ON_OTHER_SUB: case ImsReasonInfo.CODE_REJECT_ONGOING_E911_CALL: case ImsReasonInfo.CODE_REJECT_ONGOING_CALL_SETUP: diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java index 857b6a43e1..d0a20949bb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java @@ -1423,6 +1423,43 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest { new ImsReasonInfo(ImsReasonInfo.CODE_LOW_BATTERY, 0), Call.State.ACTIVE)); } + @Test + @SmallTest + public void testAutoRejectedCauses() { + assertEquals(DisconnectCause.INCOMING_AUTO_REJECTED, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_REJECT_CALL_ON_OTHER_SUB, 0), + Call.State.INCOMING)); + assertEquals(DisconnectCause.INCOMING_AUTO_REJECTED, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_REJECT_ONGOING_E911_CALL, 0), + Call.State.INCOMING)); + assertEquals(DisconnectCause.INCOMING_AUTO_REJECTED, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_REJECT_ONGOING_CALL_SETUP, 0), + Call.State.INCOMING)); + assertEquals(DisconnectCause.INCOMING_AUTO_REJECTED, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_REJECT_MAX_CALL_LIMIT_REACHED, 0), + Call.State.INCOMING)); + assertEquals(DisconnectCause.INCOMING_AUTO_REJECTED, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_REJECT_ONGOING_CALL_TRANSFER, 0), + Call.State.INCOMING)); + assertEquals(DisconnectCause.INCOMING_AUTO_REJECTED, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_REJECT_ONGOING_CONFERENCE_CALL, 0), + Call.State.INCOMING)); + assertEquals(DisconnectCause.INCOMING_AUTO_REJECTED, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_REJECT_ONGOING_HANDOVER, 0), + Call.State.INCOMING)); + assertEquals(DisconnectCause.INCOMING_AUTO_REJECTED, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_REJECT_ONGOING_CALL_UPGRADE, 0), + Call.State.INCOMING)); + assertEquals(DisconnectCause.INCOMING_AUTO_REJECTED, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_SIP_BAD_REQUEST, 0), Call.State.INCOMING)); + assertEquals(DisconnectCause.INCOMING_AUTO_REJECTED, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_SIP_BAD_REQUEST, 0), Call.State.WAITING)); + assertEquals(DisconnectCause.SERVER_ERROR, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_SIP_BAD_REQUEST, 0), Call.State.DIALING)); + assertEquals(DisconnectCause.SERVER_ERROR, mCTUT.getDisconnectCauseFromReasonInfo( + new ImsReasonInfo(ImsReasonInfo.CODE_SIP_BAD_REQUEST, 0), Call.State.ALERTING)); + } + @Test @SmallTest public void testImsAlternateEmergencyDisconnect() { -- GitLab From 1f515af2b9a187b8d86976a6af8dc95fead907b2 Mon Sep 17 00:00:00 2001 From: Sarah Kim Date: Fri, 2 Jun 2023 21:03:01 +0000 Subject: [PATCH 651/656] Revert "RIL handle AIDL binder died for all services at the same time" This reverts commit c588593f75620018cffd26f29a01ac42a32f0fd9. Reason for revert: b/260768727 Change-Id: I8043a9d6e63e1c3c6df34a3fd11ded8932de8d51 Merged-In: I6c2cbc9e6b51109cf0050a32cfc691fbd9cb61e3 --- .../com/android/internal/telephony/RIL.java | 50 ++++++------------- 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index c6820c146c..5ecdfcbbd4 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -385,15 +385,12 @@ public class RIL extends BaseCommands implements CommandsInterface { 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()) { - riljLog("handleMessage: EVENT_AIDL_PROXY_DEAD cookie = " + msgCookie - + ", service = " + serviceToString(aidlService) + ", cookie = " - + mServiceCookies.get(aidlService)); mIsRadioProxyInitialized = false; resetProxyAndRequestList(aidlService); - } else { - riljLog("Ignore stale EVENT_AIDL_PROXY_DEAD for service " - + serviceToString(aidlService)); } break; } @@ -438,7 +435,7 @@ public class RIL extends BaseCommands implements CommandsInterface { public void serviceDied(long cookie) { // Deal with service going away riljLog("serviceDied"); - mRilHandler.sendMessageAtFrontOfQueue(mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD, + mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD, HAL_SERVICE_RADIO, 0 /* ignored arg2 */, cookie)); } } @@ -471,14 +468,8 @@ public class RIL extends BaseCommands implements CommandsInterface { @Override public void binderDied() { riljLog("Service " + serviceToString(mService) + " has died."); - if (!mRilHandler.hasMessages(EVENT_AIDL_PROXY_DEAD)) { - mRilHandler.sendMessageAtFrontOfQueue(mRilHandler.obtainMessage( - EVENT_AIDL_PROXY_DEAD, mService, 0 /* ignored arg2 */, - mServiceCookies.get(mService).get())); - } else { - riljLog("Not sending redundant EVENT_AIDL_PROXY_DEAD for service " - + serviceToString(mService)); - } + mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_AIDL_PROXY_DEAD, mService, + 0 /* ignored arg2 */, mServiceCookies.get(mService).get())); unlinkToDeath(); } } @@ -487,19 +478,14 @@ public class RIL extends BaseCommands implements CommandsInterface { if (service == HAL_SERVICE_RADIO) { mRadioProxy = null; } else { - 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(); - } + mServiceProxies.get(service).clear(); } + // 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(); @@ -509,15 +495,7 @@ public class RIL extends BaseCommands implements CommandsInterface { if (service == HAL_SERVICE_RADIO) { getRadioProxy(null); } else { - 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, null); - } + getRadioServiceProxy(service, null); } } @@ -1804,7 +1782,7 @@ public class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = obtainRequest(RIL_REQUEST_GET_IMSI, result, mRILDefaultWorkSource); if (RILJ_LOGD) { - riljLog(rr.serialString() + ">" + RILUtils.requestToString(rr.mRequest) + riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + " aid = " + aid); } try { -- GitLab From 6ccd6680cc8c638a7ffea232e343daf9a61f6539 Mon Sep 17 00:00:00 2001 From: Sarah Kim Date: Wed, 21 Jun 2023 21:58:50 +0000 Subject: [PATCH 652/656] Revert "ServiceStateTracker consider config for combined bandwidth" This reverts commit 53d1bd0f504d47c74bc547d6a4beebd52088cfd5. Reason for revert: b/286594668 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:fde282c9dca22c2d9bb9ec60002a5ac991a53fed) Merged-In: I12e1a8e04d3ee4d58cdd24a5fe03bc0de6f4de78 Change-Id: I12e1a8e04d3ee4d58cdd24a5fe03bc0de6f4de78 --- .../telephony/ServiceStateTracker.java | 24 ++++++++++--------- .../telephony/ServiceStateTrackerTest.java | 10 ++++---- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 29b1acae28..9fb7d439eb 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -1695,9 +1695,16 @@ public class ServiceStateTracker extends Handler { .findFirst() .orElse(PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN); } + boolean includeLte = mCarrierConfig.getBoolean(CarrierConfigManager + .KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); int[] bandwidths = new int[0]; if (list != null) { - bandwidths = getBandwidthsFromLastPhysicalChannelConfigs(); + bandwidths = list.stream() + .filter(config -> includeLte || config.getNetworkType() + == TelephonyManager.NETWORK_TYPE_NR) + .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) + .mapToInt(Integer::intValue) + .toArray(); } if (anchorNrCellId == mLastAnchorNrCellId && anchorNrCellId != PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN) { @@ -1705,8 +1712,7 @@ public class ServiceStateTracker extends Handler { hasChanged |= RatRatcheter.updateBandwidths(bandwidths, mSS); } else { log("Do not ratchet bandwidths since anchor NR cell is different (" - + mLastAnchorNrCellId + " -> " + anchorNrCellId - + "). New bandwidths are " + Arrays.toString(bandwidths)); + + mLastAnchorNrCellId + "->" + anchorNrCellId + ")."); mLastAnchorNrCellId = anchorNrCellId; hasChanged |= !Arrays.equals(mSS.getCellBandwidths(), bandwidths); mSS.setCellBandwidths(bandwidths); @@ -1790,12 +1796,8 @@ public class ServiceStateTracker extends Handler { return simAbsent; } - private int[] getBandwidthsFromLastPhysicalChannelConfigs() { - boolean includeLte = mCarrierConfig.getBoolean( - CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); - return mLastPhysicalChannelConfigList.stream() - .filter(config -> includeLte - || config.getNetworkType() == TelephonyManager.NETWORK_TYPE_NR) + private static int[] getBandwidthsFromConfigs(List list) { + return list.stream() .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) .mapToInt(Integer::intValue) .toArray(); @@ -2555,7 +2557,7 @@ public class ServiceStateTracker extends Handler { // Prioritize the PhysicalChannelConfig list because we might already be in carrier // aggregation by the time poll state is performed. if (primaryPcc != null) { - bandwidths = getBandwidthsFromLastPhysicalChannelConfigs(); + bandwidths = getBandwidthsFromConfigs(mLastPhysicalChannelConfigList); for (int bw : bandwidths) { if (!isValidLteBandwidthKhz(bw)) { loge("Invalid LTE Bandwidth in RegistrationState, " + bw); @@ -2591,7 +2593,7 @@ public class ServiceStateTracker extends Handler { // Prioritize the PhysicalChannelConfig list because we might already be in carrier // aggregation by the time poll state is performed. if (primaryPcc != null) { - bandwidths = getBandwidthsFromLastPhysicalChannelConfigs(); + bandwidths = getBandwidthsFromConfigs(mLastPhysicalChannelConfigList); for (int bw : bandwidths) { if (!isValidNrBandwidthKhz(bw)) { loge("Invalid NR Bandwidth in RegistrationState, " + bw); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 379117cad0..280fbcc177 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -374,9 +374,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { 15, /* SIGNAL_STRENGTH_GOOD */ 30 /* SIGNAL_STRENGTH_GREAT */ }); - mBundle.putBoolean( - CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, - true); sendCarrierConfigUpdate(PHONE_ID); waitForLastHandlerAction(mSSTTestHandler.getThreadHandler()); @@ -2285,6 +2282,10 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test public void testPhyChanBandwidthRatchetedOnPhyChanBandwidth() { + mBundle.putBoolean( + CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, + true); + // LTE Cell with bandwidth = 10000 CellIdentityLte cellIdentity10 = new CellIdentityLte(1, 1, 1, 1, new int[] {1, 2}, 10000, "1", "1", "test", @@ -2369,9 +2370,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test public void testPhyChanBandwidthForNr() { - mBundle.putBoolean( - CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, - false); // NR Cell with bandwidth = 10000 CellIdentityNr nrCi = new CellIdentityNr( 0, 0, 0, new int[]{10000}, "", "", 5, "", "", Collections.emptyList()); -- GitLab From a3555fa56062bee91d47254bc3c0b4dfa5e770b4 Mon Sep 17 00:00:00 2001 From: Sarah Kim Date: Wed, 21 Jun 2023 21:59:11 +0000 Subject: [PATCH 653/656] Revert "Ratchet PCC bandwidths only if anchor cell is the same and ignore empty" This reverts commit b6a79f5bf395ee1839d0107ee0b0ebe476fc07b7. Reason for revert: b/286594668 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:542f8e399ce10bd6d34c724b00f6f1a5b8f5daae) Merged-In: I67d9a186cd67e495cc64f60cc0fdf838335ceeeb Change-Id: I67d9a186cd67e495cc64f60cc0fdf838335ceeeb --- .../telephony/NetworkTypeController.java | 18 +++++-- .../telephony/ServiceStateTracker.java | 49 +------------------ .../telephony/NetworkTypeControllerTest.java | 34 ++++++++++++- .../telephony/ServiceStateTrackerTest.java | 24 ++------- 4 files changed, 53 insertions(+), 72 deletions(-) diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index f94ff26bb8..beebf2206e 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -162,6 +162,7 @@ public class NetworkTypeController extends StateMachine { private boolean mIsTimerResetEnabledForLegacyStateRrcIdle; private int mLtePlusThresholdBandwidth; private int mNrAdvancedThresholdBandwidth; + private boolean mIncludeLteForNrAdvancedThresholdBandwidth; private @NonNull int[] mAdditionalNrAdvancedBandsList; private @NonNull String mPrimaryTimerState; private @NonNull String mSecondaryTimerState; @@ -290,6 +291,8 @@ public class NetworkTypeController extends StateMachine { CarrierConfigManager.KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT); mNrAdvancedThresholdBandwidth = config.getInt( CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT); + mIncludeLteForNrAdvancedThresholdBandwidth = config.getBoolean( + CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); mEnableNrAdvancedWhileRoaming = config.getBoolean( CarrierConfigManager.KEY_ENABLE_NR_ADVANCED_WHILE_ROAMING_BOOL); mAdditionalNrAdvancedBandsList = config.getIntArray( @@ -1281,11 +1284,20 @@ public class NetworkTypeController extends StateMachine { return false; } + int bandwidths = 0; + if (mPhone.getServiceStateTracker().getPhysicalChannelConfigList() != null) { + bandwidths = mPhone.getServiceStateTracker().getPhysicalChannelConfigList() + .stream() + .filter(config -> mIncludeLteForNrAdvancedThresholdBandwidth + || config.getNetworkType() == TelephonyManager.NETWORK_TYPE_NR) + .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) + .mapToInt(Integer::intValue) + .sum(); + } + // Check if meeting minimum bandwidth requirement. For most carriers, there is no minimum // bandwidth requirement and mNrAdvancedThresholdBandwidth is 0. - if (mNrAdvancedThresholdBandwidth > 0 - && IntStream.of(mPhone.getServiceState().getCellBandwidths()).sum() - < mNrAdvancedThresholdBandwidth) { + if (mNrAdvancedThresholdBandwidth > 0 && bandwidths < mNrAdvancedThresholdBandwidth) { return false; } diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 9fb7d439eb..50eea7f695 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -180,7 +180,6 @@ public class ServiceStateTracker extends Handler { private long mLastCellInfoReqTime; private List mLastCellInfoList = null; private List mLastPhysicalChannelConfigList = null; - private int mLastAnchorNrCellId = PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN; private final Set mRadioPowerOffReasons = new HashSet(); @@ -1661,18 +1660,6 @@ public class ServiceStateTracker extends Handler { log("EVENT_PHYSICAL_CHANNEL_CONFIG: list=" + list + (list == null ? "" : ", list.size()=" + list.size())); } - if ((list == null || list.isEmpty()) - && mLastAnchorNrCellId != PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN - && mPhone.getContext().getSystemService(TelephonyManager.class) - .isRadioInterfaceCapabilitySupported(TelephonyManager - .CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED) - && !mCarrierConfig.getBoolean(CarrierConfigManager - .KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL) - && mCarrierConfig.getBoolean(CarrierConfigManager - .KEY_RATCHET_NR_ADVANCED_BANDWIDTH_IF_RRC_IDLE_BOOL)) { - log("Ignore empty PCC list when RRC idle."); - break; - } mLastPhysicalChannelConfigList = list; boolean hasChanged = false; if (updateNrStateFromPhysicalChannelConfigs(list, mSS)) { @@ -1683,40 +1670,8 @@ public class ServiceStateTracker extends Handler { mNrFrequencyChangedRegistrants.notifyRegistrants(); hasChanged = true; } - int anchorNrCellId = PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN; - if (list != null) { - anchorNrCellId = list - .stream() - .filter(config -> config.getNetworkType() - == TelephonyManager.NETWORK_TYPE_NR - && config.getConnectionStatus() - == PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING) - .map(PhysicalChannelConfig::getPhysicalCellId) - .findFirst() - .orElse(PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN); - } - boolean includeLte = mCarrierConfig.getBoolean(CarrierConfigManager - .KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL); - int[] bandwidths = new int[0]; - if (list != null) { - bandwidths = list.stream() - .filter(config -> includeLte || config.getNetworkType() - == TelephonyManager.NETWORK_TYPE_NR) - .map(PhysicalChannelConfig::getCellBandwidthDownlinkKhz) - .mapToInt(Integer::intValue) - .toArray(); - } - if (anchorNrCellId == mLastAnchorNrCellId - && anchorNrCellId != PhysicalChannelConfig.PHYSICAL_CELL_ID_UNKNOWN) { - log("Ratchet bandwidths since anchor NR cell is the same."); - hasChanged |= RatRatcheter.updateBandwidths(bandwidths, mSS); - } else { - log("Do not ratchet bandwidths since anchor NR cell is different (" - + mLastAnchorNrCellId + "->" + anchorNrCellId + ")."); - mLastAnchorNrCellId = anchorNrCellId; - hasChanged |= !Arrays.equals(mSS.getCellBandwidths(), bandwidths); - mSS.setCellBandwidths(bandwidths); - } + hasChanged |= RatRatcheter + .updateBandwidths(getBandwidthsFromConfigs(list), mSS); mPhone.notifyPhysicalChannelConfig(list); // Notify NR frequency, NR connection status or bandwidths changed. diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index ff696fc0a3..0c57e829df 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -1274,7 +1274,12 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("DefaultState", getCurrentState().getName()); doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); - doReturn(new int[] {20001}).when(mServiceState).getCellBandwidths(); + List lastPhysicalChannelConfigList = new ArrayList<>(); + lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() + .setNetworkType(TelephonyManager.NETWORK_TYPE_NR) + .setCellBandwidthDownlinkKhz(20001) + .build()); + doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); sendCarrierConfigChanged(); @@ -1283,6 +1288,33 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertEquals("connected_mmwave", getCurrentState().getName()); } + @Test + public void testTransitionToCurrentStateNrConnectedWithHighBandwidthIncludingLte() + throws Exception { + assertEquals("DefaultState", getCurrentState().getName()); + doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); + doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange(); + List lastPhysicalChannelConfigList = new ArrayList<>(); + lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() + .setNetworkType(TelephonyManager.NETWORK_TYPE_NR) + .setCellBandwidthDownlinkKhz(20000) + .build()); + lastPhysicalChannelConfigList.add(new PhysicalChannelConfig.Builder() + .setNetworkType(TelephonyManager.NETWORK_TYPE_LTE) + .setCellBandwidthDownlinkKhz(10000) + .build()); + doReturn(lastPhysicalChannelConfigList).when(mSST).getPhysicalChannelConfigList(); + mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); + mBundle.putBoolean( + CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, + true); + sendCarrierConfigChanged(); + + mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE); + processAllMessages(); + assertEquals("connected_mmwave", getCurrentState().getName()); + } + @Test public void testNrAdvancedDisabledWhileRoaming() throws Exception { assertEquals("DefaultState", getCurrentState().getName()); diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java index 280fbcc177..846b48e3f7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java @@ -278,15 +278,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { // UMTS < GPRS < EDGE new String[]{"3,1,2"}); - mBundle.putBoolean(CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL, - false); - - mBundle.putBoolean(CarrierConfigManager.KEY_RATCHET_NR_ADVANCED_BANDWIDTH_IF_RRC_IDLE_BOOL, - true); - - doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported( - TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); - mSimulatedCommands.setVoiceRegState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME); mSimulatedCommands.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_HSPA); mSimulatedCommands.setDataRegState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME); @@ -2282,10 +2273,6 @@ public class ServiceStateTrackerTest extends TelephonyTest { @Test public void testPhyChanBandwidthRatchetedOnPhyChanBandwidth() { - mBundle.putBoolean( - CarrierConfigManager.KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, - true); - // LTE Cell with bandwidth = 10000 CellIdentityLte cellIdentity10 = new CellIdentityLte(1, 1, 1, 1, new int[] {1, 2}, 10000, "1", "1", "test", @@ -2372,16 +2359,11 @@ public class ServiceStateTrackerTest extends TelephonyTest { public void testPhyChanBandwidthForNr() { // NR Cell with bandwidth = 10000 CellIdentityNr nrCi = new CellIdentityNr( - 0, 0, 0, new int[]{10000}, "", "", 5, "", "", Collections.emptyList()); + 0, 0, 0, new int[] {}, "", "", 5, "", "", Collections.emptyList()); - sendRegStateUpdateForNrCellId(nrCi); - // should ratchet for NR sendPhyChanConfigChange(new int[] {10000, 5000}, TelephonyManager.NETWORK_TYPE_NR, 0); - assertArrayEquals(new int[]{10000, 5000}, sst.mSS.getCellBandwidths()); - - // should not ratchet for LTE - sendPhyChanConfigChange(new int[] {100}, TelephonyManager.NETWORK_TYPE_LTE, 0); - assertArrayEquals(new int[]{}, sst.mSS.getCellBandwidths()); + sendRegStateUpdateForNrCellId(nrCi); + assertArrayEquals(new int[] {10000, 5000}, sst.mSS.getCellBandwidths()); } /** -- GitLab From c34ea1b7dc343683409e6ae5b389ba683c06b92e Mon Sep 17 00:00:00 2001 From: Aishwarya Mallampati Date: Wed, 28 Jun 2023 17:22:31 +0000 Subject: [PATCH 654/656] Return only subscriptions associted with user for work profile. Bug: 289197367 Test: Flashed build on raven-userdebug: calls and sms are working fine. atest SubscriptionManagerServiceTest, atest com.android.providers.telephony.SmsProviderTest, atest com.android.providers.telephony.MmsProviderTest, atest com.android.providers.telephony.ProviderUtilTest, atest CtsTelephonyProviderTestCases, atest CtsTelephonyTestCases (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:79728a9bb1acf16043365fcf58ad6d1c117917b9) Merged-In: Ia143f9c8de146be0de09973cb15c5a949b988937 Change-Id: Ia143f9c8de146be0de09973cb15c5a949b988937 --- .../subscription/SubscriptionManagerService.java | 10 ++++++++++ .../subscription/SubscriptionManagerServiceTest.java | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java index f9720df6f1..8e773c072d 100644 --- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java +++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java @@ -46,6 +46,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.TelephonyServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.provider.Telephony.SimInfo; import android.service.carrier.CarrierIdentifier; @@ -3665,6 +3666,15 @@ public class SubscriptionManagerService extends ISub.Stub { } } + UserManager userManager = mContext.getSystemService(UserManager.class); + if ((userManager != null) + && (userManager.isManagedProfile(userHandle.getIdentifier()))) { + // For work profile, return subscriptions associated only with work profile + return subscriptionsAssociatedWithUser; + } + + // For all other profiles, if subscriptionsAssociatedWithUser is empty return all the + // subscriptionsWithNoAssociation. return subscriptionsAssociatedWithUser.isEmpty() ? subscriptionsWithNoAssociation : subscriptionsAssociatedWithUser; } finally { 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 38b495aaca..3abfac79e8 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/subscription/SubscriptionManagerServiceTest.java @@ -146,6 +146,8 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { private static final UserHandle FAKE_USER_HANDLE = new UserHandle(12); + private static final UserHandle FAKE_MANAGED_PROFILE_USER_HANDLE = new UserHandle(13); + // mocked private SubscriptionManagerServiceCallback mMockedSubscriptionManagerServiceCallback; private EuiccController mEuiccController; @@ -212,6 +214,9 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { setIdentifierAccess(false); setPhoneNumberAccess(PackageManager.PERMISSION_DENIED); + doReturn(true).when(mUserManager) + .isManagedProfile(eq(FAKE_MANAGED_PROFILE_USER_HANDLE.getIdentifier())); + logd("SubscriptionManagerServiceTest -Setup!"); } @@ -1081,6 +1086,13 @@ public class SubscriptionManagerServiceTest extends TelephonyTest { assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, FAKE_USER_HANDLE)).isEqualTo(true); + + // Work profile is not associated with any subscription + associatedSubInfoList = mSubscriptionManagerServiceUT + .getSubscriptionInfoListAssociatedWithUser(FAKE_MANAGED_PROFILE_USER_HANDLE); + assertThat(associatedSubInfoList.size()).isEqualTo(0); + assertThat(mSubscriptionManagerServiceUT.isSubscriptionAssociatedWithUser(1, + FAKE_MANAGED_PROFILE_USER_HANDLE)).isEqualTo(false); } @Test -- GitLab From 06a11f275bc6295c547593f97a9456618e15a0a1 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallamapti Date: Thu, 27 Jul 2023 18:53:54 +0000 Subject: [PATCH 655/656] Check mAdnCache is not null before loading FDN. Bug: 292467876 Test: Manual Verification: - Enable FDN - reboot device - After reboot, no crashes were observed - Performed basic functionality tests after reboot such as making calls and sending sms using the sim card. - QA verified and informed that fix is working: b/292467876#comment18 (cherry picked from commit 886684aa255b8564bb132a4b83202c6bcb5981ed) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:fd39f04d492aeac056028d6f0d0626cdfc3aa647) Merged-In: Id4909881f9f6ac509c60889557652632f00a8523 Change-Id: Id4909881f9f6ac509c60889557652632f00a8523 --- src/java/com/android/internal/telephony/uicc/IccRecords.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java index f80369675a..ae93b09283 100644 --- a/src/java/com/android/internal/telephony/uicc/IccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java @@ -1687,7 +1687,7 @@ public abstract class IccRecords extends Handler implements IccConstants { } public void loadFdnRecords() { - if (mParentApp != null) { + if (mParentApp != null && mAdnCache != null) { log("Loading FdnRecords"); mAdnCache.requestLoadAllAdnLike(IccConstants.EF_FDN, EF_EXT2, obtainMessage(EVENT_GET_FDN_DONE)); -- GitLab From df23e5e5af80a273ee411b745f81d07a83d57ff1 Mon Sep 17 00:00:00 2001 From: Aishwarya Mallamapti Date: Thu, 27 Jul 2023 18:53:54 +0000 Subject: [PATCH 656/656] Check mAdnCache is not null before loading FDN. Bug: 292467876 Test: Manual Verification: - Enable FDN - reboot device - After reboot, no crashes were observed - Performed basic functionality tests after reboot such as making calls and sending sms using the sim card. - QA verified and informed that fix is working: b/292467876#comment18 (cherry picked from commit 886684aa255b8564bb132a4b83202c6bcb5981ed) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:fd39f04d492aeac056028d6f0d0626cdfc3aa647) Merged-In: Id4909881f9f6ac509c60889557652632f00a8523 Change-Id: Id4909881f9f6ac509c60889557652632f00a8523 --- src/java/com/android/internal/telephony/uicc/IccRecords.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java index f80369675a..ae93b09283 100644 --- a/src/java/com/android/internal/telephony/uicc/IccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java @@ -1687,7 +1687,7 @@ public abstract class IccRecords extends Handler implements IccConstants { } public void loadFdnRecords() { - if (mParentApp != null) { + if (mParentApp != null && mAdnCache != null) { log("Loading FdnRecords"); mAdnCache.requestLoadAllAdnLike(IccConstants.EF_FDN, EF_EXT2, obtainMessage(EVENT_GET_FDN_DONE)); -- GitLab